aboutsummaryrefslogtreecommitdiff
path: root/lib/libc
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libc')
-rw-r--r--lib/libc/Makefile209
-rw-r--r--lib/libc/Makefile.depend18
-rw-r--r--lib/libc/Versions.def42
-rw-r--r--lib/libc/aarch64/Makefile.inc9
-rw-r--r--lib/libc/aarch64/SYS.h63
-rw-r--r--lib/libc/aarch64/Symbol.map38
-rw-r--r--lib/libc/aarch64/_fpmath.h58
-rw-r--r--lib/libc/aarch64/arith.h19
-rw-r--r--lib/libc/aarch64/gd_qnan.h21
-rw-r--r--lib/libc/aarch64/gen/Makefile.inc17
-rw-r--r--lib/libc/aarch64/gen/_ctx_start.S38
-rw-r--r--lib/libc/aarch64/gen/_set_tp.c43
-rw-r--r--lib/libc/aarch64/gen/_setjmp.S105
-rw-r--r--lib/libc/aarch64/gen/fabs.S33
-rw-r--r--lib/libc/aarch64/gen/flt_rounds.c49
-rw-r--r--lib/libc/aarch64/gen/fpgetmask.c47
-rw-r--r--lib/libc/aarch64/gen/fpsetmask.c52
-rw-r--r--lib/libc/aarch64/gen/infinity.c14
-rw-r--r--lib/libc/aarch64/gen/makecontext.c86
-rw-r--r--lib/libc/aarch64/gen/setjmp.S123
-rw-r--r--lib/libc/aarch64/gen/sigsetjmp.S53
-rw-r--r--lib/libc/aarch64/string/Makefile.inc19
-rw-r--r--lib/libc/aarch64/sys/Makefile.inc15
-rw-r--r--lib/libc/aarch64/sys/__vdso_gettc.c76
-rw-r--r--lib/libc/aarch64/sys/cerror.S42
-rw-r--r--lib/libc/aarch64/sys/shmat.S35
-rw-r--r--lib/libc/aarch64/sys/sigreturn.S35
-rw-r--r--lib/libc/aarch64/sys/syscall.S35
-rw-r--r--lib/libc/aarch64/sys/vfork.S42
-rw-r--r--lib/libc/amd64/Makefile.inc9
-rw-r--r--lib/libc/amd64/SYS.h52
-rw-r--r--lib/libc/amd64/Symbol.map70
-rw-r--r--lib/libc/amd64/_fpmath.h55
-rw-r--r--lib/libc/amd64/arith.h19
-rw-r--r--lib/libc/amd64/gd_qnan.h21
-rw-r--r--lib/libc/amd64/gen/Makefile.inc8
-rw-r--r--lib/libc/amd64/gen/_set_tp.c39
-rw-r--r--lib/libc/amd64/gen/_setjmp.S95
-rw-r--r--lib/libc/amd64/gen/fabs.S46
-rw-r--r--lib/libc/amd64/gen/flt_rounds.c26
-rw-r--r--lib/libc/amd64/gen/fpgetmask.c8
-rw-r--r--lib/libc/amd64/gen/fpgetprec.c8
-rw-r--r--lib/libc/amd64/gen/fpgetround.c8
-rw-r--r--lib/libc/amd64/gen/fpgetsticky.c8
-rw-r--r--lib/libc/amd64/gen/fpsetmask.c8
-rw-r--r--lib/libc/amd64/gen/fpsetprec.c8
-rw-r--r--lib/libc/amd64/gen/fpsetround.c8
-rw-r--r--lib/libc/amd64/gen/getcontextx.c111
-rw-r--r--lib/libc/amd64/gen/infinity.c14
-rw-r--r--lib/libc/amd64/gen/makecontext.c107
-rw-r--r--lib/libc/amd64/gen/rfork_thread.S99
-rw-r--r--lib/libc/amd64/gen/setjmp.S116
-rw-r--r--lib/libc/amd64/gen/signalcontext.c106
-rw-r--r--lib/libc/amd64/gen/sigsetjmp.S116
-rw-r--r--lib/libc/amd64/stdlib/Makefile.inc4
-rw-r--r--lib/libc/amd64/stdlib/div.S20
-rw-r--r--lib/libc/amd64/stdlib/ldiv.S18
-rw-r--r--lib/libc/amd64/stdlib/lldiv.S18
-rw-r--r--lib/libc/amd64/string/Makefile.inc4
-rw-r--r--lib/libc/amd64/string/bcmp.S27
-rw-r--r--lib/libc/amd64/string/bcopy.S99
-rw-r--r--lib/libc/amd64/string/bzero.S46
-rw-r--r--lib/libc/amd64/string/memcmp.S44
-rw-r--r--lib/libc/amd64/string/memcpy.S5
-rw-r--r--lib/libc/amd64/string/memmove.S5
-rw-r--r--lib/libc/amd64/string/memset.S63
-rw-r--r--lib/libc/amd64/string/stpcpy.S116
-rw-r--r--lib/libc/amd64/string/strcat.S168
-rw-r--r--lib/libc/amd64/string/strcmp.S76
-rw-r--r--lib/libc/amd64/string/strcpy.c38
-rw-r--r--lib/libc/amd64/sys/Makefile.inc11
-rw-r--r--lib/libc/amd64/sys/amd64_get_fsbase.c37
-rw-r--r--lib/libc/amd64/sys/amd64_get_gsbase.c37
-rw-r--r--lib/libc/amd64/sys/amd64_set_fsbase.c37
-rw-r--r--lib/libc/amd64/sys/amd64_set_gsbase.c37
-rw-r--r--lib/libc/amd64/sys/brk.S82
-rw-r--r--lib/libc/amd64/sys/cerror.S60
-rw-r--r--lib/libc/amd64/sys/exect.S53
-rw-r--r--lib/libc/amd64/sys/getcontext.S48
-rw-r--r--lib/libc/amd64/sys/sbrk.S85
-rw-r--r--lib/libc/amd64/sys/setlogin.S53
-rw-r--r--lib/libc/amd64/sys/sigreturn.S48
-rw-r--r--lib/libc/amd64/sys/vfork.S54
-rw-r--r--lib/libc/arm/Makefile.inc17
-rw-r--r--lib/libc/arm/SYS.h80
-rw-r--r--lib/libc/arm/Symbol.map83
-rw-r--r--lib/libc/arm/Symbol_vfp.map10
-rw-r--r--lib/libc/arm/_fpmath.h67
-rw-r--r--lib/libc/arm/aeabi/Makefile.inc32
-rw-r--r--lib/libc/arm/aeabi/Symbol.map72
-rw-r--r--lib/libc/arm/aeabi/aeabi_asm_double.S121
-rw-r--r--lib/libc/arm/aeabi/aeabi_asm_float.S112
-rw-r--r--lib/libc/arm/aeabi/aeabi_atexit.c38
-rw-r--r--lib/libc/arm/aeabi/aeabi_double.c101
-rw-r--r--lib/libc/arm/aeabi/aeabi_float.c101
-rw-r--r--lib/libc/arm/aeabi/aeabi_unwind_cpp.c61
-rw-r--r--lib/libc/arm/aeabi/aeabi_unwind_exidx.c104
-rw-r--r--lib/libc/arm/aeabi/aeabi_vfp.h131
-rw-r--r--lib/libc/arm/aeabi/aeabi_vfp_double.S204
-rw-r--r--lib/libc/arm/aeabi/aeabi_vfp_float.S191
-rw-r--r--lib/libc/arm/arith.h21
-rw-r--r--lib/libc/arm/gd_qnan.h23
-rw-r--r--lib/libc/arm/gen/Makefile.inc13
-rw-r--r--lib/libc/arm/gen/__aeabi_read_tp.S48
-rw-r--r--lib/libc/arm/gen/_ctx_start.S12
-rw-r--r--lib/libc/arm/gen/_set_tp.c44
-rw-r--r--lib/libc/arm/gen/_setjmp.S161
-rw-r--r--lib/libc/arm/gen/alloca.S48
-rw-r--r--lib/libc/arm/gen/arm_initfini.c78
-rw-r--r--lib/libc/arm/gen/divsi3.S393
-rw-r--r--lib/libc/arm/gen/fabs.c46
-rw-r--r--lib/libc/arm/gen/flt_rounds.c69
-rw-r--r--lib/libc/arm/gen/fpgetmask_vfp.c49
-rw-r--r--lib/libc/arm/gen/fpgetround_vfp.c47
-rw-r--r--lib/libc/arm/gen/fpgetsticky_vfp.c49
-rw-r--r--lib/libc/arm/gen/fpsetmask_vfp.c52
-rw-r--r--lib/libc/arm/gen/fpsetround_vfp.c50
-rw-r--r--lib/libc/arm/gen/fpsetsticky_vfp.c52
-rw-r--r--lib/libc/arm/gen/infinity.c26
-rw-r--r--lib/libc/arm/gen/makecontext.c89
-rw-r--r--lib/libc/arm/gen/setjmp.S162
-rw-r--r--lib/libc/arm/gen/signalcontext.c78
-rw-r--r--lib/libc/arm/gen/sigsetjmp.S70
-rw-r--r--lib/libc/arm/softfloat/arm-gcc.h101
-rw-r--r--lib/libc/arm/softfloat/milieu.h49
-rw-r--r--lib/libc/arm/softfloat/softfloat.h315
-rw-r--r--lib/libc/arm/string/Makefile.inc6
-rw-r--r--lib/libc/arm/string/bcopy.S6
-rw-r--r--lib/libc/arm/string/bzero.S37
-rw-r--r--lib/libc/arm/string/ffs.S88
-rw-r--r--lib/libc/arm/string/memcmp.S185
-rw-r--r--lib/libc/arm/string/memcpy.S9
-rw-r--r--lib/libc/arm/string/memcpy_arm.S338
-rw-r--r--lib/libc/arm/string/memcpy_xscale.S1788
-rw-r--r--lib/libc/arm/string/memmove.S613
-rw-r--r--lib/libc/arm/string/memset.S267
-rw-r--r--lib/libc/arm/string/strcmp.S47
-rw-r--r--lib/libc/arm/string/strlen.S87
-rw-r--r--lib/libc/arm/string/strncmp.S60
-rw-r--r--lib/libc/arm/sys/Makefile.inc8
-rw-r--r--lib/libc/arm/sys/Ovfork.S57
-rw-r--r--lib/libc/arm/sys/__vdso_gettc.c89
-rw-r--r--lib/libc/arm/sys/brk.S95
-rw-r--r--lib/libc/arm/sys/cerror.S51
-rw-r--r--lib/libc/arm/sys/sbrk.S82
-rw-r--r--lib/libc/arm/sys/shmat.S9
-rw-r--r--lib/libc/arm/sys/sigreturn.S44
-rw-r--r--lib/libc/arm/sys/syscall.S40
-rw-r--r--lib/libc/capability/Makefile.inc18
-rw-r--r--lib/libc/capability/Symbol.map14
-rw-r--r--lib/libc/capability/cap_rights_init.3241
-rw-r--r--lib/libc/compat-43/Makefile.inc24
-rw-r--r--lib/libc/compat-43/Symbol.map31
-rw-r--r--lib/libc/compat-43/creat.262
-rw-r--r--lib/libc/compat-43/creat.c55
-rw-r--r--lib/libc/compat-43/gethostid.380
-rw-r--r--lib/libc/compat-43/gethostid.c54
-rw-r--r--lib/libc/compat-43/getwd.c51
-rw-r--r--lib/libc/compat-43/killpg.292
-rw-r--r--lib/libc/compat-43/killpg.c51
-rw-r--r--lib/libc/compat-43/sethostid.c49
-rw-r--r--lib/libc/compat-43/setpgrp.c43
-rw-r--r--lib/libc/compat-43/setrgid.c43
-rw-r--r--lib/libc/compat-43/setruid.380
-rw-r--r--lib/libc/compat-43/setruid.c43
-rw-r--r--lib/libc/compat-43/sigcompat.c185
-rw-r--r--lib/libc/compat-43/sigpause.2243
-rw-r--r--lib/libc/compat-43/sigsetmask.2103
-rw-r--r--lib/libc/compat-43/sigvec.2342
-rw-r--r--lib/libc/db/Makefile.inc13
-rw-r--r--lib/libc/db/README34
-rw-r--r--lib/libc/db/Symbol.map36
-rw-r--r--lib/libc/db/btree/Makefile.inc8
-rw-r--r--lib/libc/db/btree/bt_close.c179
-rw-r--r--lib/libc/db/btree/bt_conv.c212
-rw-r--r--lib/libc/db/btree/bt_debug.c316
-rw-r--r--lib/libc/db/btree/bt_delete.c635
-rw-r--r--lib/libc/db/btree/bt_get.c99
-rw-r--r--lib/libc/db/btree/bt_open.c449
-rw-r--r--lib/libc/db/btree/bt_overflow.c216
-rw-r--r--lib/libc/db/btree/bt_page.c94
-rw-r--r--lib/libc/db/btree/bt_put.c315
-rw-r--r--lib/libc/db/btree/bt_search.c200
-rw-r--r--lib/libc/db/btree/bt_seq.c441
-rw-r--r--lib/libc/db/btree/bt_split.c802
-rw-r--r--lib/libc/db/btree/bt_utils.c246
-rw-r--r--lib/libc/db/btree/btree.h380
-rw-r--r--lib/libc/db/btree/extern.h67
-rw-r--r--lib/libc/db/changelog103
-rw-r--r--lib/libc/db/db/Makefile.inc6
-rw-r--r--lib/libc/db/db/db.c98
-rw-r--r--lib/libc/db/docs/hash.usenix.ps12209
-rw-r--r--lib/libc/db/docs/libtp.usenix.ps12340
-rw-r--r--lib/libc/db/hash/Makefile.inc7
-rw-r--r--lib/libc/db/hash/README69
-rw-r--r--lib/libc/db/hash/extern.h62
-rw-r--r--lib/libc/db/hash/hash.c967
-rw-r--r--lib/libc/db/hash/hash.h290
-rw-r--r--lib/libc/db/hash/hash_bigkey.c646
-rw-r--r--lib/libc/db/hash/hash_buf.c358
-rw-r--r--lib/libc/db/hash/hash_func.c190
-rw-r--r--lib/libc/db/hash/hash_log2.c52
-rw-r--r--lib/libc/db/hash/hash_page.c940
-rw-r--r--lib/libc/db/hash/ndbm.c212
-rw-r--r--lib/libc/db/hash/page.h89
-rw-r--r--lib/libc/db/man/Makefile.inc18
-rw-r--r--lib/libc/db/man/btree.3271
-rw-r--r--lib/libc/db/man/dbm.3226
-rw-r--r--lib/libc/db/man/dbopen.3546
-rw-r--r--lib/libc/db/man/hash.3196
-rw-r--r--lib/libc/db/man/mpool.3254
-rw-r--r--lib/libc/db/man/recno.3228
-rw-r--r--lib/libc/db/mpool/Makefile.inc9
-rw-r--r--lib/libc/db/mpool/README7
-rw-r--r--lib/libc/db/mpool/mpool-compat.c43
-rw-r--r--lib/libc/db/mpool/mpool.c493
-rw-r--r--lib/libc/db/mpool/mpool.libtp746
-rw-r--r--lib/libc/db/recno/Makefile.inc7
-rw-r--r--lib/libc/db/recno/extern.h51
-rw-r--r--lib/libc/db/recno/rec_close.c182
-rw-r--r--lib/libc/db/recno/rec_delete.c187
-rw-r--r--lib/libc/db/recno/rec_get.c291
-rw-r--r--lib/libc/db/recno/rec_open.c238
-rw-r--r--lib/libc/db/recno/rec_put.c274
-rw-r--r--lib/libc/db/recno/rec_search.c121
-rw-r--r--lib/libc/db/recno/rec_seq.c127
-rw-r--r--lib/libc/db/recno/rec_utils.c112
-rw-r--r--lib/libc/db/recno/recno.h36
-rw-r--r--lib/libc/db/test/Makefile24
-rw-r--r--lib/libc/db/test/README74
-rw-r--r--lib/libc/db/test/btree.tests/main.c763
-rw-r--r--lib/libc/db/test/dbtest.c738
-rw-r--r--lib/libc/db/test/hash.tests/driver2.c112
-rw-r--r--lib/libc/db/test/hash.tests/makedb.sh13
-rw-r--r--lib/libc/db/test/hash.tests/tcreat3.c103
-rw-r--r--lib/libc/db/test/hash.tests/tdel.c120
-rw-r--r--lib/libc/db/test/hash.tests/testit147
-rw-r--r--lib/libc/db/test/hash.tests/thash4.c130
-rw-r--r--lib/libc/db/test/hash.tests/tread2.c103
-rw-r--r--lib/libc/db/test/hash.tests/tseq.c86
-rw-r--r--lib/libc/db/test/hash.tests/tverify.c105
-rw-r--r--lib/libc/db/test/run.test705
-rw-r--r--lib/libc/gdtoa/Makefile.inc20
-rw-r--r--lib/libc/gdtoa/Symbol.map19
-rw-r--r--lib/libc/gdtoa/_hdtoa.c144
-rw-r--r--lib/libc/gdtoa/_hldtoa.c177
-rw-r--r--lib/libc/gdtoa/_ldtoa.c108
-rw-r--r--lib/libc/gdtoa/glue.c13
-rw-r--r--lib/libc/gdtoa/machdep_ldisQ.c52
-rw-r--r--lib/libc/gdtoa/machdep_ldisd.c49
-rw-r--r--lib/libc/gdtoa/machdep_ldisx.c53
-rw-r--r--lib/libc/gen/Makefile.inc524
-rw-r--r--lib/libc/gen/Symbol.map547
-rw-r--r--lib/libc/gen/__getosreldate.c68
-rw-r--r--lib/libc/gen/__pthread_mutex_init_calloc_cb_stub.c45
-rw-r--r--lib/libc/gen/__xuname.c146
-rw-r--r--lib/libc/gen/_once_stub.c64
-rw-r--r--lib/libc/gen/_pthread_stubs.c327
-rw-r--r--lib/libc/gen/_rand48.c49
-rw-r--r--lib/libc/gen/_spinlock_stub.c80
-rw-r--r--lib/libc/gen/_thread_init.c44
-rw-r--r--lib/libc/gen/alarm.393
-rw-r--r--lib/libc/gen/alarm.c56
-rw-r--r--lib/libc/gen/arc4random.3127
-rw-r--r--lib/libc/gen/arc4random.c302
-rw-r--r--lib/libc/gen/assert.c53
-rw-r--r--lib/libc/gen/auxv.c186
-rw-r--r--lib/libc/gen/basename.388
-rw-r--r--lib/libc/gen/basename.c54
-rw-r--r--lib/libc/gen/basename_compat.c81
-rw-r--r--lib/libc/gen/cap_rights_get.3119
-rw-r--r--lib/libc/gen/cap_sandboxed.371
-rw-r--r--lib/libc/gen/cap_sandboxed.c50
-rw-r--r--lib/libc/gen/check_utility_compat.389
-rw-r--r--lib/libc/gen/check_utility_compat.c71
-rw-r--r--lib/libc/gen/clock.376
-rw-r--r--lib/libc/gen/clock.c55
-rw-r--r--lib/libc/gen/clock_getcpuclockid.397
-rw-r--r--lib/libc/gen/clock_getcpuclockid.c41
-rw-r--r--lib/libc/gen/closedir.c76
-rw-r--r--lib/libc/gen/confstr.3129
-rw-r--r--lib/libc/gen/confstr.c121
-rw-r--r--lib/libc/gen/crypt.c88
-rw-r--r--lib/libc/gen/ctermid.3108
-rw-r--r--lib/libc/gen/ctermid.c70
-rw-r--r--lib/libc/gen/daemon.3112
-rw-r--r--lib/libc/gen/daemon.c95
-rw-r--r--lib/libc/gen/devname.3115
-rw-r--r--lib/libc/gen/devname.c75
-rw-r--r--lib/libc/gen/directory.3308
-rw-r--r--lib/libc/gen/dirfd.c45
-rw-r--r--lib/libc/gen/dirname.385
-rw-r--r--lib/libc/gen/dirname.c73
-rw-r--r--lib/libc/gen/dirname_compat.c79
-rw-r--r--lib/libc/gen/disklabel.c166
-rw-r--r--lib/libc/gen/dl_iterate_phdr.3115
-rw-r--r--lib/libc/gen/dladdr.3133
-rw-r--r--lib/libc/gen/dlfcn.c241
-rw-r--r--lib/libc/gen/dlinfo.3279
-rw-r--r--lib/libc/gen/dllockinit.3127
-rw-r--r--lib/libc/gen/dlopen.3408
-rw-r--r--lib/libc/gen/drand48.c25
-rw-r--r--lib/libc/gen/dup3.3116
-rw-r--r--lib/libc/gen/dup3.c61
-rw-r--r--lib/libc/gen/elf_utils.c84
-rw-r--r--lib/libc/gen/erand48.c26
-rw-r--r--lib/libc/gen/err.3245
-rw-r--r--lib/libc/gen/err.c192
-rw-r--r--lib/libc/gen/errlst.c164
-rw-r--r--lib/libc/gen/errno.c30
-rw-r--r--lib/libc/gen/exec.3321
-rw-r--r--lib/libc/gen/exec.c281
-rw-r--r--lib/libc/gen/fdevname.c55
-rw-r--r--lib/libc/gen/feature_present.372
-rw-r--r--lib/libc/gen/feature_present.c63
-rw-r--r--lib/libc/gen/fmtcheck.3108
-rw-r--r--lib/libc/gen/fmtcheck.c326
-rw-r--r--lib/libc/gen/fmtmsg.3260
-rw-r--r--lib/libc/gen/fmtmsg.c220
-rw-r--r--lib/libc/gen/fnmatch.3151
-rw-r--r--lib/libc/gen/fnmatch.c309
-rw-r--r--lib/libc/gen/fpclassify.3133
-rw-r--r--lib/libc/gen/fpclassify.c103
-rw-r--r--lib/libc/gen/frexp.394
-rw-r--r--lib/libc/gen/frexp.c57
-rw-r--r--lib/libc/gen/fstab.c302
-rw-r--r--lib/libc/gen/ftok.383
-rw-r--r--lib/libc/gen/ftok.c44
-rw-r--r--lib/libc/gen/fts-compat.c1214
-rw-r--r--lib/libc/gen/fts-compat.h128
-rw-r--r--lib/libc/gen/fts.3803
-rw-r--r--lib/libc/gen/fts.c1182
-rw-r--r--lib/libc/gen/ftw.3218
-rw-r--r--lib/libc/gen/ftw.c91
-rw-r--r--lib/libc/gen/gen-private.h58
-rw-r--r--lib/libc/gen/getbootfile.369
-rw-r--r--lib/libc/gen/getbootfile.c53
-rw-r--r--lib/libc/gen/getbsize.394
-rw-r--r--lib/libc/gen/getbsize.c104
-rw-r--r--lib/libc/gen/getcap.3569
-rw-r--r--lib/libc/gen/getcap.c1055
-rw-r--r--lib/libc/gen/getcontext.3150
-rw-r--r--lib/libc/gen/getcwd.3162
-rw-r--r--lib/libc/gen/getcwd.c230
-rw-r--r--lib/libc/gen/getdiskbyname.363
-rw-r--r--lib/libc/gen/getdomainname.3100
-rw-r--r--lib/libc/gen/getdomainname.c53
-rw-r--r--lib/libc/gen/getfsent.3185
-rw-r--r--lib/libc/gen/getgrent.3286
-rw-r--r--lib/libc/gen/getgrent.c1552
-rw-r--r--lib/libc/gen/getgrouplist.382
-rw-r--r--lib/libc/gen/getgrouplist.c52
-rw-r--r--lib/libc/gen/gethostname.3131
-rw-r--r--lib/libc/gen/gethostname.c55
-rw-r--r--lib/libc/gen/getloadavg.365
-rw-r--r--lib/libc/gen/getloadavg.c67
-rw-r--r--lib/libc/gen/getlogin.c106
-rw-r--r--lib/libc/gen/getmntinfo.3109
-rw-r--r--lib/libc/gen/getmntinfo.c66
-rw-r--r--lib/libc/gen/getnetgrent.3133
-rw-r--r--lib/libc/gen/getnetgrent.c1016
-rw-r--r--lib/libc/gen/getosreldate.386
-rw-r--r--lib/libc/gen/getosreldate.c61
-rw-r--r--lib/libc/gen/getpagesize.361
-rw-r--r--lib/libc/gen/getpagesize.c75
-rw-r--r--lib/libc/gen/getpagesizes.399
-rw-r--r--lib/libc/gen/getpagesizes.c85
-rw-r--r--lib/libc/gen/getpass.393
-rw-r--r--lib/libc/gen/getpeereid.3137
-rw-r--r--lib/libc/gen/getpeereid.c56
-rw-r--r--lib/libc/gen/getprogname.394
-rw-r--r--lib/libc/gen/getprogname.c17
-rw-r--r--lib/libc/gen/getpwent.3315
-rw-r--r--lib/libc/gen/getpwent.c2010
-rw-r--r--lib/libc/gen/getttyent.3208
-rw-r--r--lib/libc/gen/getttyent.c292
-rw-r--r--lib/libc/gen/getusershell.399
-rw-r--r--lib/libc/gen/getusershell.c260
-rw-r--r--lib/libc/gen/getutxent.3478
-rw-r--r--lib/libc/gen/getutxent.c246
-rw-r--r--lib/libc/gen/getvfsbyname.3117
-rw-r--r--lib/libc/gen/getvfsbyname.c74
-rw-r--r--lib/libc/gen/glob.3457
-rw-r--r--lib/libc/gen/glob.c1105
-rw-r--r--lib/libc/gen/initgroups.382
-rw-r--r--lib/libc/gen/initgroups.c66
-rw-r--r--lib/libc/gen/isatty.c47
-rw-r--r--lib/libc/gen/isgreater.3102
-rw-r--r--lib/libc/gen/isinf.c72
-rw-r--r--lib/libc/gen/isnan.c64
-rw-r--r--lib/libc/gen/jrand48.c27
-rw-r--r--lib/libc/gen/lcong48.c33
-rw-r--r--lib/libc/gen/ldexp.377
-rw-r--r--lib/libc/gen/ldexp.c123
-rw-r--r--lib/libc/gen/libc_dlopen.c61
-rw-r--r--lib/libc/gen/lockf.3266
-rw-r--r--lib/libc/gen/lockf.c84
-rw-r--r--lib/libc/gen/lrand48.c26
-rw-r--r--lib/libc/gen/makecontext.3120
-rw-r--r--lib/libc/gen/modf.381
-rw-r--r--lib/libc/gen/modf.c138
-rw-r--r--lib/libc/gen/mrand48.c30
-rw-r--r--lib/libc/gen/nftw.c109
-rw-r--r--lib/libc/gen/nice.397
-rw-r--r--lib/libc/gen/nice.c62
-rw-r--r--lib/libc/gen/nlist.377
-rw-r--r--lib/libc/gen/nlist.c404
-rw-r--r--lib/libc/gen/nrand48.c24
-rw-r--r--lib/libc/gen/opendir.c360
-rw-r--r--lib/libc/gen/pause.382
-rw-r--r--lib/libc/gen/pause.c57
-rw-r--r--lib/libc/gen/pmadvise.c26
-rw-r--r--lib/libc/gen/popen.3202
-rw-r--r--lib/libc/gen/popen.c229
-rw-r--r--lib/libc/gen/posix_spawn.3460
-rw-r--r--lib/libc/gen/posix_spawn.c481
-rw-r--r--lib/libc/gen/posix_spawn_file_actions_addopen.3203
-rw-r--r--lib/libc/gen/posix_spawn_file_actions_init.3104
-rw-r--r--lib/libc/gen/posix_spawnattr_getflags.3111
-rw-r--r--lib/libc/gen/posix_spawnattr_getpgroup.396
-rw-r--r--lib/libc/gen/posix_spawnattr_getschedparam.3100
-rw-r--r--lib/libc/gen/posix_spawnattr_getschedpolicy.398
-rw-r--r--lib/libc/gen/posix_spawnattr_getsigdefault.398
-rw-r--r--lib/libc/gen/posix_spawnattr_getsigmask.398
-rw-r--r--lib/libc/gen/posix_spawnattr_init.3123
-rw-r--r--lib/libc/gen/psignal.3109
-rw-r--r--lib/libc/gen/psignal.c61
-rw-r--r--lib/libc/gen/pututxline.c335
-rw-r--r--lib/libc/gen/pw_scan.c212
-rw-r--r--lib/libc/gen/pw_scan.h36
-rw-r--r--lib/libc/gen/raise.373
-rw-r--r--lib/libc/gen/raise.c53
-rw-r--r--lib/libc/gen/rand48.3190
-rw-r--r--lib/libc/gen/rand48.h32
-rw-r--r--lib/libc/gen/readdir.c135
-rw-r--r--lib/libc/gen/readpassphrase.3181
-rw-r--r--lib/libc/gen/readpassphrase.c203
-rw-r--r--lib/libc/gen/recvmmsg.c97
-rw-r--r--lib/libc/gen/rewinddir.c64
-rw-r--r--lib/libc/gen/rfork_thread.387
-rw-r--r--lib/libc/gen/scandir.3117
-rw-r--r--lib/libc/gen/scandir.c166
-rw-r--r--lib/libc/gen/scandir_b.c29
-rw-r--r--lib/libc/gen/seed48.c39
-rw-r--r--lib/libc/gen/seekdir.c58
-rw-r--r--lib/libc/gen/sem.c464
-rw-r--r--lib/libc/gen/sem_destroy.387
-rw-r--r--lib/libc/gen/sem_getvalue.380
-rw-r--r--lib/libc/gen/sem_init.3101
-rw-r--r--lib/libc/gen/sem_new.c452
-rw-r--r--lib/libc/gen/sem_open.3224
-rw-r--r--lib/libc/gen/sem_post.380
-rw-r--r--lib/libc/gen/sem_timedwait.3119
-rw-r--r--lib/libc/gen/sem_wait.3102
-rw-r--r--lib/libc/gen/semctl.c90
-rw-r--r--lib/libc/gen/sendmmsg.c64
-rw-r--r--lib/libc/gen/setdomainname.c51
-rw-r--r--lib/libc/gen/sethostname.c51
-rw-r--r--lib/libc/gen/setjmp.3172
-rw-r--r--lib/libc/gen/setjmperr.c53
-rw-r--r--lib/libc/gen/setmode.3127
-rw-r--r--lib/libc/gen/setmode.c485
-rw-r--r--lib/libc/gen/setproctitle.3121
-rw-r--r--lib/libc/gen/setproctitle.c170
-rw-r--r--lib/libc/gen/setprogname.c19
-rw-r--r--lib/libc/gen/siginterrupt.3119
-rw-r--r--lib/libc/gen/siginterrupt.c62
-rw-r--r--lib/libc/gen/siglist.c107
-rw-r--r--lib/libc/gen/signal.3272
-rw-r--r--lib/libc/gen/signal.c59
-rw-r--r--lib/libc/gen/sigsetops.3117
-rw-r--r--lib/libc/gen/sigsetops.c94
-rw-r--r--lib/libc/gen/sleep.383
-rw-r--r--lib/libc/gen/sleep.c73
-rw-r--r--lib/libc/gen/srand48.c30
-rw-r--r--lib/libc/gen/statvfs.3187
-rw-r--r--lib/libc/gen/statvfs.c160
-rw-r--r--lib/libc/gen/stringlist.3127
-rw-r--r--lib/libc/gen/stringlist.c114
-rw-r--r--lib/libc/gen/strtofflags.395
-rw-r--r--lib/libc/gen/strtofflags.c169
-rw-r--r--lib/libc/gen/sysconf.3276
-rw-r--r--lib/libc/gen/sysconf.c624
-rw-r--r--lib/libc/gen/sysctl.3862
-rw-r--r--lib/libc/gen/sysctl.c195
-rw-r--r--lib/libc/gen/sysctlbyname.c28
-rw-r--r--lib/libc/gen/sysctlnametomib.c55
-rw-r--r--lib/libc/gen/syslog.3295
-rw-r--r--lib/libc/gen/syslog.c457
-rw-r--r--lib/libc/gen/tcgetpgrp.378
-rw-r--r--lib/libc/gen/tcgetsid.372
-rw-r--r--lib/libc/gen/tcsendbreak.3180
-rw-r--r--lib/libc/gen/tcsetattr.3340
-rw-r--r--lib/libc/gen/tcsetpgrp.395
-rw-r--r--lib/libc/gen/tcsetsid.392
-rw-r--r--lib/libc/gen/telldir.c164
-rw-r--r--lib/libc/gen/telldir.h69
-rw-r--r--lib/libc/gen/termios.c277
-rw-r--r--lib/libc/gen/time.3101
-rw-r--r--lib/libc/gen/time.c52
-rw-r--r--lib/libc/gen/times.3145
-rw-r--r--lib/libc/gen/times.c67
-rw-r--r--lib/libc/gen/timezone.369
-rw-r--r--lib/libc/gen/timezone.c129
-rw-r--r--lib/libc/gen/tls.c326
-rw-r--r--lib/libc/gen/trivial-getcontextx.c76
-rw-r--r--lib/libc/gen/ttyname.3140
-rw-r--r--lib/libc/gen/ttyname.c110
-rw-r--r--lib/libc/gen/ttyslot.c45
-rw-r--r--lib/libc/gen/tzset.3338
-rw-r--r--lib/libc/gen/ualarm.397
-rw-r--r--lib/libc/gen/ualarm.c61
-rw-r--r--lib/libc/gen/ucontext.3111
-rw-r--r--lib/libc/gen/ulimit.398
-rw-r--r--lib/libc/gen/ulimit.c70
-rw-r--r--lib/libc/gen/uname.3117
-rw-r--r--lib/libc/gen/uname.c49
-rw-r--r--lib/libc/gen/unvis-compat.c48
-rw-r--r--lib/libc/gen/usleep.380
-rw-r--r--lib/libc/gen/usleep.c57
-rw-r--r--lib/libc/gen/utime.394
-rw-r--r--lib/libc/gen/utime.c53
-rw-r--r--lib/libc/gen/utxdb.c179
-rw-r--r--lib/libc/gen/utxdb.h61
-rw-r--r--lib/libc/gen/valloc.375
-rw-r--r--lib/libc/gen/valloc.c48
-rw-r--r--lib/libc/gen/wait.c56
-rw-r--r--lib/libc/gen/wait3.c55
-rw-r--r--lib/libc/gen/waitid.c70
-rw-r--r--lib/libc/gen/waitpid.c56
-rw-r--r--lib/libc/gen/wordexp.3210
-rw-r--r--lib/libc/gen/wordexp.c410
-rw-r--r--lib/libc/gmon/Makefile.inc17
-rw-r--r--lib/libc/gmon/Symbol.map14
-rw-r--r--lib/libc/gmon/gmon.c246
-rw-r--r--lib/libc/gmon/mcount.c321
-rw-r--r--lib/libc/gmon/moncontrol.3117
-rw-r--r--lib/libc/i386/Makefile.inc6
-rw-r--r--lib/libc/i386/SYS.h56
-rw-r--r--lib/libc/i386/Symbol.map67
-rw-r--r--lib/libc/i386/_fpmath.h54
-rw-r--r--lib/libc/i386/arith.h15
-rw-r--r--lib/libc/i386/gd_qnan.h21
-rw-r--r--lib/libc/i386/gen/Makefile.inc6
-rw-r--r--lib/libc/i386/gen/_ctx_start.S54
-rw-r--r--lib/libc/i386/gen/_set_tp.c40
-rw-r--r--lib/libc/i386/gen/_setjmp.S81
-rw-r--r--lib/libc/i386/gen/fabs.S45
-rw-r--r--lib/libc/i386/gen/flt_rounds.c25
-rw-r--r--lib/libc/i386/gen/getcontextx.c143
-rw-r--r--lib/libc/i386/gen/infinity.c14
-rw-r--r--lib/libc/i386/gen/makecontext.c163
-rw-r--r--lib/libc/i386/gen/rfork_thread.S119
-rw-r--r--lib/libc/i386/gen/setjmp.S97
-rw-r--r--lib/libc/i386/gen/signalcontext.c79
-rw-r--r--lib/libc/i386/gen/sigsetjmp.S108
-rw-r--r--lib/libc/i386/stdlib/Makefile.inc4
-rw-r--r--lib/libc/i386/stdlib/div.S39
-rw-r--r--lib/libc/i386/stdlib/ldiv.S42
-rw-r--r--lib/libc/i386/string/Makefile.inc6
-rw-r--r--lib/libc/i386/string/bcmp.S66
-rw-r--r--lib/libc/i386/string/bcopy.S110
-rw-r--r--lib/libc/i386/string/bzero.S84
-rw-r--r--lib/libc/i386/string/ffs.S56
-rw-r--r--lib/libc/i386/string/memchr.S61
-rw-r--r--lib/libc/i386/string/memcmp.S78
-rw-r--r--lib/libc/i386/string/memcpy.S5
-rw-r--r--lib/libc/i386/string/memmove.S5
-rw-r--r--lib/libc/i386/string/memset.S92
-rw-r--r--lib/libc/i386/string/strcat.S103
-rw-r--r--lib/libc/i386/string/strchr.S68
-rw-r--r--lib/libc/i386/string/strcmp.S122
-rw-r--r--lib/libc/i386/string/strcpy.S92
-rw-r--r--lib/libc/i386/string/strncmp.S169
-rw-r--r--lib/libc/i386/string/strrchr.S69
-rw-r--r--lib/libc/i386/string/swab.S102
-rw-r--r--lib/libc/i386/string/wcschr.S79
-rw-r--r--lib/libc/i386/string/wcscmp.S82
-rw-r--r--lib/libc/i386/string/wcslen.S71
-rw-r--r--lib/libc/i386/string/wmemchr.S108
-rw-r--r--lib/libc/i386/sys/Makefile.inc20
-rw-r--r--lib/libc/i386/sys/Ovfork.S54
-rw-r--r--lib/libc/i386/sys/brk.S85
-rw-r--r--lib/libc/i386/sys/cerror.S68
-rw-r--r--lib/libc/i386/sys/exect.S53
-rw-r--r--lib/libc/i386/sys/getcontext.S48
-rw-r--r--lib/libc/i386/sys/i386_clr_watch.c46
-rw-r--r--lib/libc/i386/sys/i386_get_fsbase.c37
-rw-r--r--lib/libc/i386/sys/i386_get_gsbase.c37
-rw-r--r--lib/libc/i386/sys/i386_get_ioperm.287
-rw-r--r--lib/libc/i386/sys/i386_get_ioperm.c48
-rw-r--r--lib/libc/i386/sys/i386_get_ldt.2139
-rw-r--r--lib/libc/i386/sys/i386_get_ldt.c46
-rw-r--r--lib/libc/i386/sys/i386_set_fsbase.c37
-rw-r--r--lib/libc/i386/sys/i386_set_gsbase.c37
-rw-r--r--lib/libc/i386/sys/i386_set_ioperm.c42
-rw-r--r--lib/libc/i386/sys/i386_set_ldt.c46
-rw-r--r--lib/libc/i386/sys/i386_set_watch.3118
-rw-r--r--lib/libc/i386/sys/i386_set_watch.c84
-rw-r--r--lib/libc/i386/sys/i386_vm86.2141
-rw-r--r--lib/libc/i386/sys/i386_vm86.c41
-rw-r--r--lib/libc/i386/sys/sbrk.S88
-rw-r--r--lib/libc/i386/sys/setlogin.S50
-rw-r--r--lib/libc/i386/sys/sigreturn.S48
-rw-r--r--lib/libc/i386/sys/syscall.S52
-rw-r--r--lib/libc/iconv/Makefile.inc26
-rw-r--r--lib/libc/iconv/Symbol.map104
-rw-r--r--lib/libc/iconv/__iconv.c38
-rw-r--r--lib/libc/iconv/__iconv_free_list.c37
-rw-r--r--lib/libc/iconv/__iconv_get_list.395
-rw-r--r--lib/libc/iconv/__iconv_get_list.c37
-rw-r--r--lib/libc/iconv/_strtol.h167
-rw-r--r--lib/libc/iconv/_strtoul.h126
-rw-r--r--lib/libc/iconv/bsd_iconv.c325
-rw-r--r--lib/libc/iconv/citrus_aliasname_local.h49
-rw-r--r--lib/libc/iconv/citrus_bcs.c168
-rw-r--r--lib/libc/iconv/citrus_bcs.h102
-rw-r--r--lib/libc/iconv/citrus_bcs_strtol.c57
-rw-r--r--lib/libc/iconv/citrus_bcs_strtoul.c57
-rw-r--r--lib/libc/iconv/citrus_csmapper.c386
-rw-r--r--lib/libc/iconv/citrus_csmapper.h48
-rw-r--r--lib/libc/iconv/citrus_db.c331
-rw-r--r--lib/libc/iconv/citrus_db.h70
-rw-r--r--lib/libc/iconv/citrus_db_factory.c337
-rw-r--r--lib/libc/iconv/citrus_db_factory.h57
-rw-r--r--lib/libc/iconv/citrus_db_file.h85
-rw-r--r--lib/libc/iconv/citrus_db_hash.c64
-rw-r--r--lib/libc/iconv/citrus_db_hash.h37
-rw-r--r--lib/libc/iconv/citrus_esdb.c368
-rw-r--r--lib/libc/iconv/citrus_esdb.h58
-rw-r--r--lib/libc/iconv/citrus_esdb_file.h45
-rw-r--r--lib/libc/iconv/citrus_fix_grouping.h53
-rw-r--r--lib/libc/iconv/citrus_hash.c51
-rw-r--r--lib/libc/iconv/citrus_hash.h59
-rw-r--r--lib/libc/iconv/citrus_iconv.c359
-rw-r--r--lib/libc/iconv/citrus_iconv.h64
-rw-r--r--lib/libc/iconv/citrus_iconv_local.h110
-rw-r--r--lib/libc/iconv/citrus_lock.h33
-rw-r--r--lib/libc/iconv/citrus_lookup.c362
-rw-r--r--lib/libc/iconv/citrus_lookup.h64
-rw-r--r--lib/libc/iconv/citrus_lookup_factory.c121
-rw-r--r--lib/libc/iconv/citrus_lookup_factory.h37
-rw-r--r--lib/libc/iconv/citrus_lookup_file.h35
-rw-r--r--lib/libc/iconv/citrus_mapper.c405
-rw-r--r--lib/libc/iconv/citrus_mapper.h131
-rw-r--r--lib/libc/iconv/citrus_mapper_local.h97
-rw-r--r--lib/libc/iconv/citrus_memstream.c147
-rw-r--r--lib/libc/iconv/citrus_memstream.h226
-rw-r--r--lib/libc/iconv/citrus_mmap.c95
-rw-r--r--lib/libc/iconv/citrus_mmap.h40
-rw-r--r--lib/libc/iconv/citrus_module.c315
-rw-r--r--lib/libc/iconv/citrus_module.h54
-rw-r--r--lib/libc/iconv/citrus_namespace.h241
-rw-r--r--lib/libc/iconv/citrus_none.c237
-rw-r--r--lib/libc/iconv/citrus_none.h36
-rw-r--r--lib/libc/iconv/citrus_pivot_factory.c225
-rw-r--r--lib/libc/iconv/citrus_pivot_factory.h37
-rw-r--r--lib/libc/iconv/citrus_pivot_file.h36
-rw-r--r--lib/libc/iconv/citrus_prop.c445
-rw-r--r--lib/libc/iconv/citrus_prop.h92
-rw-r--r--lib/libc/iconv/citrus_region.h113
-rw-r--r--lib/libc/iconv/citrus_stdenc.c147
-rw-r--r--lib/libc/iconv/citrus_stdenc.h124
-rw-r--r--lib/libc/iconv/citrus_stdenc_local.h162
-rw-r--r--lib/libc/iconv/citrus_stdenc_template.h211
-rw-r--r--lib/libc/iconv/citrus_types.h40
-rw-r--r--lib/libc/iconv/iconv-internal.h45
-rw-r--r--lib/libc/iconv/iconv.3309
-rw-r--r--lib/libc/iconv/iconv.c39
-rw-r--r--lib/libc/iconv/iconv_canonicalize.374
-rw-r--r--lib/libc/iconv/iconv_canonicalize.c37
-rw-r--r--lib/libc/iconv/iconv_close.c37
-rw-r--r--lib/libc/iconv/iconv_compat.c121
-rw-r--r--lib/libc/iconv/iconv_open.c37
-rw-r--r--lib/libc/iconv/iconv_open_into.c37
-rw-r--r--lib/libc/iconv/iconv_set_relocation_prefix.c37
-rw-r--r--lib/libc/iconv/iconvctl.3189
-rw-r--r--lib/libc/iconv/iconvctl.c37
-rw-r--r--lib/libc/iconv/iconvlist.393
-rw-r--r--lib/libc/iconv/iconvlist.c37
-rw-r--r--lib/libc/include/block_abi.h63
-rw-r--r--lib/libc/include/compat.h57
-rw-r--r--lib/libc/include/errlst.h43
-rw-r--r--lib/libc/include/fpmath.h75
-rw-r--r--lib/libc/include/isc/eventlib.h206
-rw-r--r--lib/libc/include/isc/list.h125
-rw-r--r--lib/libc/include/isc/platform.h37
-rw-r--r--lib/libc/include/libc_private.h404
-rw-r--r--lib/libc/include/namespace.h268
-rw-r--r--lib/libc/include/nscache.h197
-rw-r--r--lib/libc/include/nscachedcli.h107
-rw-r--r--lib/libc/include/nss_tls.h80
-rw-r--r--lib/libc/include/port_after.h11
-rw-r--r--lib/libc/include/port_before.h23
-rw-r--r--lib/libc/include/reentrant.h128
-rw-r--r--lib/libc/include/resolv_mt.h47
-rw-r--r--lib/libc/include/spinlock.h70
-rw-r--r--lib/libc/include/un-namespace.h258
-rw-r--r--lib/libc/inet/Makefile.inc11
-rw-r--r--lib/libc/inet/Symbol.map38
-rw-r--r--lib/libc/inet/inet_addr.c214
-rw-r--r--lib/libc/inet/inet_cidr_ntop.c265
-rw-r--r--lib/libc/inet/inet_cidr_pton.c279
-rw-r--r--lib/libc/inet/inet_lnaof.c69
-rw-r--r--lib/libc/inet/inet_makeaddr.c72
-rw-r--r--lib/libc/inet/inet_net_ntop.c279
-rw-r--r--lib/libc/inet/inet_net_pton.c416
-rw-r--r--lib/libc/inet/inet_neta.c95
-rw-r--r--lib/libc/inet/inet_netof.c68
-rw-r--r--lib/libc/inet/inet_network.c110
-rw-r--r--lib/libc/inet/inet_ntoa.c78
-rw-r--r--lib/libc/inet/inet_ntop.c204
-rw-r--r--lib/libc/inet/inet_pton.c224
-rw-r--r--lib/libc/inet/nsap_addr.c121
-rw-r--r--lib/libc/isc/Makefile.inc6
-rw-r--r--lib/libc/isc/ev_streams.c318
-rw-r--r--lib/libc/isc/ev_timers.c515
-rw-r--r--lib/libc/isc/eventlib_p.h289
-rw-r--r--lib/libc/libc.ldscript2
-rw-r--r--lib/libc/libc_nossp.ldscript2
-rw-r--r--lib/libc/locale/DESIGN.xlocale159
-rw-r--r--lib/libc/locale/Makefile.inc90
-rw-r--r--lib/libc/locale/Symbol.map217
-rw-r--r--lib/libc/locale/ascii.c194
-rw-r--r--lib/libc/locale/big5.551
-rw-r--r--lib/libc/locale/big5.c200
-rw-r--r--lib/libc/locale/btowc.388
-rw-r--r--lib/libc/locale/btowc.c64
-rw-r--r--lib/libc/locale/c16rtomb.c81
-rw-r--r--lib/libc/locale/c16rtomb_iconv.c8
-rw-r--r--lib/libc/locale/c32rtomb.c59
-rw-r--r--lib/libc/locale/c32rtomb_iconv.c8
-rw-r--r--lib/libc/locale/cXXrtomb_iconv.h115
-rw-r--r--lib/libc/locale/collate.c709
-rw-r--r--lib/libc/locale/collate.h139
-rw-r--r--lib/libc/locale/collcmp.c63
-rw-r--r--lib/libc/locale/ctype.3151
-rw-r--r--lib/libc/locale/ctype.c33
-rw-r--r--lib/libc/locale/ctype_l.3151
-rw-r--r--lib/libc/locale/digittoint.368
-rw-r--r--lib/libc/locale/duplocale.379
-rw-r--r--lib/libc/locale/endian.h52
-rw-r--r--lib/libc/locale/euc.5134
-rw-r--r--lib/libc/locale/euc.c455
-rw-r--r--lib/libc/locale/fix_grouping.c86
-rw-r--r--lib/libc/locale/freelocale.359
-rw-r--r--lib/libc/locale/gb18030.578
-rw-r--r--lib/libc/locale/gb18030.c252
-rw-r--r--lib/libc/locale/gb2312.557
-rw-r--r--lib/libc/locale/gb2312.c187
-rw-r--r--lib/libc/locale/gbk.563
-rw-r--r--lib/libc/locale/gbk.c197
-rw-r--r--lib/libc/locale/isalnum.3115
-rw-r--r--lib/libc/locale/isalpha.3113
-rw-r--r--lib/libc/locale/isascii.353
-rw-r--r--lib/libc/locale/isblank.396
-rw-r--r--lib/libc/locale/iscntrl.3103
-rw-r--r--lib/libc/locale/isctype.c206
-rw-r--r--lib/libc/locale/isdigit.3113
-rw-r--r--lib/libc/locale/isgraph.3119
-rw-r--r--lib/libc/locale/isideogram.357
-rw-r--r--lib/libc/locale/islower.3103
-rw-r--r--lib/libc/locale/isphonogram.357
-rw-r--r--lib/libc/locale/isprint.3103
-rw-r--r--lib/libc/locale/ispunct.3109
-rw-r--r--lib/libc/locale/isrune.363
-rw-r--r--lib/libc/locale/isspace.3101
-rw-r--r--lib/libc/locale/isspecial.356
-rw-r--r--lib/libc/locale/isupper.390
-rw-r--r--lib/libc/locale/iswalnum.3158
-rw-r--r--lib/libc/locale/iswalnum_l.3168
-rw-r--r--lib/libc/locale/iswctype.c189
-rw-r--r--lib/libc/locale/isxdigit.3101
-rw-r--r--lib/libc/locale/ldpart.c166
-rw-r--r--lib/libc/locale/ldpart.h39
-rw-r--r--lib/libc/locale/lmessages.c126
-rw-r--r--lib/libc/locale/lmessages.h49
-rw-r--r--lib/libc/locale/lmonetary.c225
-rw-r--r--lib/libc/locale/lmonetary.h70
-rw-r--r--lib/libc/locale/lnumeric.c127
-rw-r--r--lib/libc/locale/lnumeric.h52
-rw-r--r--lib/libc/locale/localeconv.3237
-rw-r--r--lib/libc/locale/localeconv.c117
-rw-r--r--lib/libc/locale/mblen.3106
-rw-r--r--lib/libc/locale/mblen.c61
-rw-r--r--lib/libc/locale/mblocal.h90
-rw-r--r--lib/libc/locale/mbrlen.3145
-rw-r--r--lib/libc/locale/mbrlen.c51
-rw-r--r--lib/libc/locale/mbrtoc16.c89
-rw-r--r--lib/libc/locale/mbrtoc16_iconv.c8
-rw-r--r--lib/libc/locale/mbrtoc32.c53
-rw-r--r--lib/libc/locale/mbrtoc32_iconv.c8
-rw-r--r--lib/libc/locale/mbrtocXX_iconv.h158
-rw-r--r--lib/libc/locale/mbrtowc.3179
-rw-r--r--lib/libc/locale/mbrtowc.c53
-rw-r--r--lib/libc/locale/mbsinit.367
-rw-r--r--lib/libc/locale/mbsinit.c48
-rw-r--r--lib/libc/locale/mbsnrtowcs.c104
-rw-r--r--lib/libc/locale/mbsrtowcs.3135
-rw-r--r--lib/libc/locale/mbsrtowcs.c55
-rw-r--r--lib/libc/locale/mbstowcs.387
-rw-r--r--lib/libc/locale/mbstowcs.c56
-rw-r--r--lib/libc/locale/mbtowc.3114
-rw-r--r--lib/libc/locale/mbtowc.c67
-rw-r--r--lib/libc/locale/mskanji.570
-rw-r--r--lib/libc/locale/mskanji.c191
-rw-r--r--lib/libc/locale/multibyte.3142
-rw-r--r--lib/libc/locale/newlocale.3112
-rw-r--r--lib/libc/locale/nextwctype.367
-rw-r--r--lib/libc/locale/nextwctype.c103
-rw-r--r--lib/libc/locale/nl_langinfo.3102
-rw-r--r--lib/libc/locale/nl_langinfo.c207
-rw-r--r--lib/libc/locale/nomacros.c18
-rw-r--r--lib/libc/locale/none.c215
-rw-r--r--lib/libc/locale/querylocale.354
-rw-r--r--lib/libc/locale/rpmatch.366
-rw-r--r--lib/libc/locale/rpmatch.c55
-rw-r--r--lib/libc/locale/rune.c252
-rw-r--r--lib/libc/locale/runefile.h61
-rw-r--r--lib/libc/locale/runetype.c89
-rw-r--r--lib/libc/locale/setlocale.3173
-rw-r--r--lib/libc/locale/setlocale.c329
-rw-r--r--lib/libc/locale/setlocale.h40
-rw-r--r--lib/libc/locale/setrunelocale.c213
-rw-r--r--lib/libc/locale/table.c263
-rw-r--r--lib/libc/locale/toascii.369
-rw-r--r--lib/libc/locale/tolower.379
-rw-r--r--lib/libc/locale/tolower.c76
-rw-r--r--lib/libc/locale/toupper.379
-rw-r--r--lib/libc/locale/toupper.c78
-rw-r--r--lib/libc/locale/towlower.366
-rw-r--r--lib/libc/locale/towupper.366
-rw-r--r--lib/libc/locale/uselocale.360
-rw-r--r--lib/libc/locale/utf8.5102
-rw-r--r--lib/libc/locale/utf8.c424
-rw-r--r--lib/libc/locale/wcrtomb.3123
-rw-r--r--lib/libc/locale/wcrtomb.c52
-rw-r--r--lib/libc/locale/wcsftime.366
-rw-r--r--lib/libc/locale/wcsftime.c122
-rw-r--r--lib/libc/locale/wcsnrtombs.c125
-rw-r--r--lib/libc/locale/wcsrtombs.3134
-rw-r--r--lib/libc/locale/wcsrtombs.c56
-rw-r--r--lib/libc/locale/wcstod.373
-rw-r--r--lib/libc/locale/wcstod.c116
-rw-r--r--lib/libc/locale/wcstof.c93
-rw-r--r--lib/libc/locale/wcstoimax.c137
-rw-r--r--lib/libc/locale/wcstol.394
-rw-r--r--lib/libc/locale/wcstol.c130
-rw-r--r--lib/libc/locale/wcstold.c93
-rw-r--r--lib/libc/locale/wcstoll.c136
-rw-r--r--lib/libc/locale/wcstombs.390
-rw-r--r--lib/libc/locale/wcstombs.c58
-rw-r--r--lib/libc/locale/wcstoul.c128
-rw-r--r--lib/libc/locale/wcstoull.c135
-rw-r--r--lib/libc/locale/wcstoumax.c135
-rw-r--r--lib/libc/locale/wctob.c56
-rw-r--r--lib/libc/locale/wctomb.3108
-rw-r--r--lib/libc/locale/wctomb.c59
-rw-r--r--lib/libc/locale/wctrans.3122
-rw-r--r--lib/libc/locale/wctrans.c101
-rw-r--r--lib/libc/locale/wctype.3119
-rw-r--r--lib/libc/locale/wctype.c115
-rw-r--r--lib/libc/locale/wcwidth.387
-rw-r--r--lib/libc/locale/wcwidth.c61
-rw-r--r--lib/libc/locale/xlocale.3280
-rw-r--r--lib/libc/locale/xlocale.c367
-rw-r--r--lib/libc/locale/xlocale_private.h231
-rw-r--r--lib/libc/md/Makefile.inc5
-rw-r--r--lib/libc/mips/Makefile.inc9
-rw-r--r--lib/libc/mips/SYS.h151
-rw-r--r--lib/libc/mips/Symbol.map78
-rw-r--r--lib/libc/mips/_fpmath.h56
-rw-r--r--lib/libc/mips/arith.h26
-rw-r--r--lib/libc/mips/gd_qnan.h48
-rw-r--r--lib/libc/mips/gdtoa/Makefile.inc4
-rw-r--r--lib/libc/mips/gdtoa/arith.h10
-rw-r--r--lib/libc/mips/gen/Makefile.inc11
-rw-r--r--lib/libc/mips/gen/_ctx_start.S41
-rw-r--r--lib/libc/mips/gen/_set_tp.c40
-rw-r--r--lib/libc/mips/gen/_setjmp.S201
-rw-r--r--lib/libc/mips/gen/fabs.S58
-rw-r--r--lib/libc/mips/gen/fabs.c46
-rw-r--r--lib/libc/mips/gen/flt_rounds.c42
-rw-r--r--lib/libc/mips/gen/hardfloat/fpgetmask.c29
-rw-r--r--lib/libc/mips/gen/hardfloat/fpgetround.c29
-rw-r--r--lib/libc/mips/gen/hardfloat/fpgetsticky.c29
-rw-r--r--lib/libc/mips/gen/hardfloat/fpsetmask.c38
-rw-r--r--lib/libc/mips/gen/hardfloat/fpsetround.c37
-rw-r--r--lib/libc/mips/gen/hardfloat/fpsetsticky.c38
-rw-r--r--lib/libc/mips/gen/infinity.c26
-rw-r--r--lib/libc/mips/gen/ldexp.S219
-rw-r--r--lib/libc/mips/gen/longjmp.c103
-rw-r--r--lib/libc/mips/gen/makecontext.c123
-rw-r--r--lib/libc/mips/gen/setjmp.S238
-rw-r--r--lib/libc/mips/gen/signalcontext.c53
-rw-r--r--lib/libc/mips/gen/sigsetjmp.S77
-rw-r--r--lib/libc/mips/net/Makefile.inc4
-rw-r--r--lib/libc/mips/net/htonl.S51
-rw-r--r--lib/libc/mips/net/htons.S47
-rw-r--r--lib/libc/mips/net/ntohl.S51
-rw-r--r--lib/libc/mips/net/ntohs.S46
-rw-r--r--lib/libc/mips/softfloat/milieu.h48
-rw-r--r--lib/libc/mips/softfloat/mips-gcc.h91
-rw-r--r--lib/libc/mips/softfloat/softfloat.h315
-rw-r--r--lib/libc/mips/string/Makefile.inc8
-rw-r--r--lib/libc/mips/string/bcmp.S130
-rw-r--r--lib/libc/mips/string/bcopy.S297
-rw-r--r--lib/libc/mips/string/bzero.S83
-rw-r--r--lib/libc/mips/string/ffs.S59
-rw-r--r--lib/libc/mips/string/memcpy.S7
-rw-r--r--lib/libc/mips/string/memmove.S7
-rw-r--r--lib/libc/mips/string/strchr.S66
-rw-r--r--lib/libc/mips/string/strcmp.S68
-rw-r--r--lib/libc/mips/string/strlen.S55
-rw-r--r--lib/libc/mips/string/strrchr.S64
-rw-r--r--lib/libc/mips/sys/Makefile.inc9
-rw-r--r--lib/libc/mips/sys/Ovfork.S64
-rw-r--r--lib/libc/mips/sys/brk.S71
-rw-r--r--lib/libc/mips/sys/cerror.S72
-rw-r--r--lib/libc/mips/sys/exect.S51
-rw-r--r--lib/libc/mips/sys/sbrk.S73
-rw-r--r--lib/libc/mips/sys/shmat.S7
-rw-r--r--lib/libc/mips/sys/syscall.S44
-rw-r--r--lib/libc/nameser/Makefile.inc8
-rw-r--r--lib/libc/nameser/Symbol.map52
-rw-r--r--lib/libc/nameser/ns_name.c1156
-rw-r--r--lib/libc/nameser/ns_netint.c60
-rw-r--r--lib/libc/nameser/ns_parse.c277
-rw-r--r--lib/libc/nameser/ns_print.c1254
-rw-r--r--lib/libc/nameser/ns_samedomain.c211
-rw-r--r--lib/libc/nameser/ns_ttl.c164
-rw-r--r--lib/libc/net/Makefile.inc125
-rw-r--r--lib/libc/net/Symbol.map174
-rw-r--r--lib/libc/net/base64.c319
-rw-r--r--lib/libc/net/byteorder.386
-rw-r--r--lib/libc/net/ether_addr.c231
-rw-r--r--lib/libc/net/ethers.3233
-rw-r--r--lib/libc/net/eui64.3223
-rw-r--r--lib/libc/net/eui64.c311
-rw-r--r--lib/libc/net/gai_strerror.392
-rw-r--r--lib/libc/net/gai_strerror.c119
-rw-r--r--lib/libc/net/getaddrinfo.3509
-rw-r--r--lib/libc/net/getaddrinfo.c3033
-rw-r--r--lib/libc/net/gethostbydns.c775
-rw-r--r--lib/libc/net/gethostbyht.c339
-rw-r--r--lib/libc/net/gethostbyname.3375
-rw-r--r--lib/libc/net/gethostbynis.c297
-rw-r--r--lib/libc/net/gethostnamadr.c727
-rw-r--r--lib/libc/net/getifaddrs.3163
-rw-r--r--lib/libc/net/getifaddrs.c344
-rw-r--r--lib/libc/net/getifmaddrs.3114
-rw-r--r--lib/libc/net/getifmaddrs.c197
-rw-r--r--lib/libc/net/getipnodebyname.3474
-rw-r--r--lib/libc/net/getnameinfo.3298
-rw-r--r--lib/libc/net/getnameinfo.c529
-rw-r--r--lib/libc/net/getnetbydns.c465
-rw-r--r--lib/libc/net/getnetbyht.c288
-rw-r--r--lib/libc/net/getnetbynis.c259
-rw-r--r--lib/libc/net/getnetent.3170
-rw-r--r--lib/libc/net/getnetnamadr.c451
-rw-r--r--lib/libc/net/getproto.c137
-rw-r--r--lib/libc/net/getprotoent.3144
-rw-r--r--lib/libc/net/getprotoent.c553
-rw-r--r--lib/libc/net/getprotoname.c151
-rw-r--r--lib/libc/net/getservent.3154
-rw-r--r--lib/libc/net/getservent.c1372
-rw-r--r--lib/libc/net/hesiod.3176
-rw-r--r--lib/libc/net/hesiod.c583
-rw-r--r--lib/libc/net/if_indextoname.3152
-rw-r--r--lib/libc/net/if_indextoname.c88
-rw-r--r--lib/libc/net/if_nameindex.c147
-rw-r--r--lib/libc/net/if_nametoindex.c100
-rw-r--r--lib/libc/net/inet.3305
-rw-r--r--lib/libc/net/inet6_opt_init.3337
-rw-r--r--lib/libc/net/inet6_option_space.354
-rw-r--r--lib/libc/net/inet6_rth_space.3225
-rw-r--r--lib/libc/net/inet6_rthdr_space.357
-rw-r--r--lib/libc/net/inet_net.3161
-rw-r--r--lib/libc/net/ip6opt.c599
-rw-r--r--lib/libc/net/linkaddr.3134
-rw-r--r--lib/libc/net/linkaddr.c169
-rw-r--r--lib/libc/net/map_v4v6.c111
-rw-r--r--lib/libc/net/name6.c1131
-rw-r--r--lib/libc/net/netdb_private.h162
-rw-r--r--lib/libc/net/nscache.c439
-rw-r--r--lib/libc/net/nscachedcli.c577
-rw-r--r--lib/libc/net/nsdispatch.3257
-rw-r--r--lib/libc/net/nsdispatch.c763
-rw-r--r--lib/libc/net/nslexer.l111
-rw-r--r--lib/libc/net/nsparser.y177
-rw-r--r--lib/libc/net/nss_backends.h43
-rw-r--r--lib/libc/net/nss_compat.c288
-rw-r--r--lib/libc/net/ntoh.c60
-rw-r--r--lib/libc/net/rcmd.3306
-rw-r--r--lib/libc/net/rcmd.c733
-rw-r--r--lib/libc/net/rcmdsh.3116
-rw-r--r--lib/libc/net/rcmdsh.c167
-rw-r--r--lib/libc/net/recv.c53
-rw-r--r--lib/libc/net/res_config.h6
-rw-r--r--lib/libc/net/resolver.3461
-rw-r--r--lib/libc/net/rthdr.c434
-rw-r--r--lib/libc/net/sctp_bindx.3110
-rw-r--r--lib/libc/net/sctp_connectx.3102
-rw-r--r--lib/libc/net/sctp_freepaddrs.364
-rw-r--r--lib/libc/net/sctp_getaddrlen.383
-rw-r--r--lib/libc/net/sctp_getassocid.370
-rw-r--r--lib/libc/net/sctp_getpaddrs.396
-rw-r--r--lib/libc/net/sctp_opt_info.3140
-rw-r--r--lib/libc/net/sctp_recvmsg.3294
-rw-r--r--lib/libc/net/sctp_send.3350
-rw-r--r--lib/libc/net/sctp_sendmsg.3329
-rw-r--r--lib/libc/net/sctp_sys_calls.c1203
-rw-r--r--lib/libc/net/send.c53
-rw-r--r--lib/libc/net/sockatmark.3123
-rw-r--r--lib/libc/net/sockatmark.c39
-rw-r--r--lib/libc/net/sourcefilter.3239
-rw-r--r--lib/libc/net/sourcefilter.c402
-rw-r--r--lib/libc/net/vars.c45
-rw-r--r--lib/libc/nls/C.msg301
-rw-r--r--lib/libc/nls/Makefile.inc41
-rw-r--r--lib/libc/nls/Symbol.map9
-rw-r--r--lib/libc/nls/be_BY.UTF-8.msg249
-rw-r--r--lib/libc/nls/ca_ES.ISO8859-1.msg267
-rw-r--r--lib/libc/nls/catclose.364
-rw-r--r--lib/libc/nls/catgets.382
-rw-r--r--lib/libc/nls/catopen.3157
-rw-r--r--lib/libc/nls/de_DE.ISO8859-1.msg249
-rw-r--r--lib/libc/nls/el_GR.ISO8859-7.msg249
-rw-r--r--lib/libc/nls/es_ES.ISO8859-1.msg295
-rw-r--r--lib/libc/nls/fi_FI.ISO8859-1.msg233
-rw-r--r--lib/libc/nls/fr_FR.ISO8859-1.msg249
-rw-r--r--lib/libc/nls/gl_ES.ISO8859-1.msg295
-rw-r--r--lib/libc/nls/hu_HU.ISO8859-2.msg295
-rw-r--r--lib/libc/nls/it_IT.ISO8859-15.msg231
-rw-r--r--lib/libc/nls/ja_JP.UTF-8.msg295
-rw-r--r--lib/libc/nls/ja_JP.eucJP.msg295
-rw-r--r--lib/libc/nls/ko_KR.UTF-8.msg295
-rw-r--r--lib/libc/nls/ko_KR.eucKR.msg295
-rw-r--r--lib/libc/nls/mn_MN.UTF-8.msg249
-rw-r--r--lib/libc/nls/msgcat.c457
-rw-r--r--lib/libc/nls/nl_NL.ISO8859-1.msg294
-rw-r--r--lib/libc/nls/no_NO.ISO8859-1.msg231
-rw-r--r--lib/libc/nls/pl_PL.ISO8859-2.msg249
-rw-r--r--lib/libc/nls/pt_BR.ISO8859-1.msg249
-rw-r--r--lib/libc/nls/ru_RU.KOI8-R.msg266
-rw-r--r--lib/libc/nls/sk_SK.ISO8859-2.msg267
-rw-r--r--lib/libc/nls/sv_SE.ISO8859-1.msg233
-rw-r--r--lib/libc/nls/uk_UA.UTF-8.msg259
-rw-r--r--lib/libc/nls/zh_CN.GB18030.msg297
-rw-r--r--lib/libc/nls/zh_CN.GB2312.msg297
-rw-r--r--lib/libc/nls/zh_CN.UTF-8.msg295
-rw-r--r--lib/libc/posix1e/Makefile.inc126
-rw-r--r--lib/libc/posix1e/Symbol.map86
-rw-r--r--lib/libc/posix1e/acl.3307
-rw-r--r--lib/libc/posix1e/acl_add_flag_np.398
-rw-r--r--lib/libc/posix1e/acl_add_perm.3129
-rw-r--r--lib/libc/posix1e/acl_branding.c169
-rw-r--r--lib/libc/posix1e/acl_calc_mask.398
-rw-r--r--lib/libc/posix1e/acl_calc_mask.c129
-rw-r--r--lib/libc/posix1e/acl_clear_flags_np.379
-rw-r--r--lib/libc/posix1e/acl_clear_perms.379
-rw-r--r--lib/libc/posix1e/acl_compat.c63
-rw-r--r--lib/libc/posix1e/acl_copy.c86
-rw-r--r--lib/libc/posix1e/acl_copy_entry.385
-rw-r--r--lib/libc/posix1e/acl_create_entry.398
-rw-r--r--lib/libc/posix1e/acl_delete.3140
-rw-r--r--lib/libc/posix1e/acl_delete.c79
-rw-r--r--lib/libc/posix1e/acl_delete_entry.3101
-rw-r--r--lib/libc/posix1e/acl_delete_entry.c162
-rw-r--r--lib/libc/posix1e/acl_delete_flag_np.384
-rw-r--r--lib/libc/posix1e/acl_delete_perm.384
-rw-r--r--lib/libc/posix1e/acl_dup.3110
-rw-r--r--lib/libc/posix1e/acl_entry.c146
-rw-r--r--lib/libc/posix1e/acl_flag.c155
-rw-r--r--lib/libc/posix1e/acl_free.389
-rw-r--r--lib/libc/posix1e/acl_free.c54
-rw-r--r--lib/libc/posix1e/acl_from_text.3130
-rw-r--r--lib/libc/posix1e/acl_from_text.c313
-rw-r--r--lib/libc/posix1e/acl_from_text_nfs4.c283
-rw-r--r--lib/libc/posix1e/acl_get.3168
-rw-r--r--lib/libc/posix1e/acl_get.c216
-rw-r--r--lib/libc/posix1e/acl_get_brand_np.386
-rw-r--r--lib/libc/posix1e/acl_get_entry.3145
-rw-r--r--lib/libc/posix1e/acl_get_entry_type_np.380
-rw-r--r--lib/libc/posix1e/acl_get_flag_np.394
-rw-r--r--lib/libc/posix1e/acl_get_flagset_np.383
-rw-r--r--lib/libc/posix1e/acl_get_perm_np.394
-rw-r--r--lib/libc/posix1e/acl_get_permset.383
-rw-r--r--lib/libc/posix1e/acl_get_qualifier.3140
-rw-r--r--lib/libc/posix1e/acl_get_tag_type.385
-rw-r--r--lib/libc/posix1e/acl_id_to_name.c100
-rw-r--r--lib/libc/posix1e/acl_init.3111
-rw-r--r--lib/libc/posix1e/acl_init.c95
-rw-r--r--lib/libc/posix1e/acl_is_trivial_np.385
-rw-r--r--lib/libc/posix1e/acl_perm.c128
-rw-r--r--lib/libc/posix1e/acl_set.3157
-rw-r--r--lib/libc/posix1e/acl_set.c253
-rw-r--r--lib/libc/posix1e/acl_set_entry_type_np.394
-rw-r--r--lib/libc/posix1e/acl_set_flagset_np.385
-rw-r--r--lib/libc/posix1e/acl_set_permset.381
-rw-r--r--lib/libc/posix1e/acl_set_qualifier.391
-rw-r--r--lib/libc/posix1e/acl_set_tag_type.3102
-rw-r--r--lib/libc/posix1e/acl_strip.c233
-rw-r--r--lib/libc/posix1e/acl_strip_np.3109
-rw-r--r--lib/libc/posix1e/acl_support.c418
-rw-r--r--lib/libc/posix1e/acl_support.h68
-rw-r--r--lib/libc/posix1e/acl_support_nfs4.c261
-rw-r--r--lib/libc/posix1e/acl_to_text.3158
-rw-r--r--lib/libc/posix1e/acl_to_text.c261
-rw-r--r--lib/libc/posix1e/acl_to_text_nfs4.c264
-rw-r--r--lib/libc/posix1e/acl_valid.3170
-rw-r--r--lib/libc/posix1e/acl_valid.c124
-rw-r--r--lib/libc/posix1e/extattr.3100
-rw-r--r--lib/libc/posix1e/extattr.c77
-rw-r--r--lib/libc/posix1e/mac.3165
-rw-r--r--lib/libc/posix1e/mac.c449
-rw-r--r--lib/libc/posix1e/mac.conf.5112
-rw-r--r--lib/libc/posix1e/mac_exec.c46
-rw-r--r--lib/libc/posix1e/mac_free.399
-rw-r--r--lib/libc/posix1e/mac_get.3152
-rw-r--r--lib/libc/posix1e/mac_get.c87
-rw-r--r--lib/libc/posix1e/mac_is_present.387
-rw-r--r--lib/libc/posix1e/mac_prepare.3126
-rw-r--r--lib/libc/posix1e/mac_set.3149
-rw-r--r--lib/libc/posix1e/mac_set.c69
-rw-r--r--lib/libc/posix1e/mac_text.3117
-rw-r--r--lib/libc/posix1e/posix1e.3118
-rw-r--r--lib/libc/powerpc/Makefile.inc7
-rw-r--r--lib/libc/powerpc/SYS.h70
-rw-r--r--lib/libc/powerpc/Symbol.map59
-rw-r--r--lib/libc/powerpc/_fpmath.h56
-rw-r--r--lib/libc/powerpc/arith.h16
-rw-r--r--lib/libc/powerpc/gd_qnan.h21
-rw-r--r--lib/libc/powerpc/gen/Makefile.common6
-rw-r--r--lib/libc/powerpc/gen/Makefile.inc7
-rw-r--r--lib/libc/powerpc/gen/_ctx_start.S46
-rw-r--r--lib/libc/powerpc/gen/_set_tp.c35
-rw-r--r--lib/libc/powerpc/gen/_setjmp.S116
-rw-r--r--lib/libc/powerpc/gen/eabi.S34
-rw-r--r--lib/libc/powerpc/gen/fabs.S38
-rw-r--r--lib/libc/powerpc/gen/flt_rounds.c56
-rw-r--r--lib/libc/powerpc/gen/fpgetmask.c48
-rw-r--r--lib/libc/powerpc/gen/fpgetround.c48
-rw-r--r--lib/libc/powerpc/gen/fpgetsticky.c54
-rw-r--r--lib/libc/powerpc/gen/fpsetmask.c52
-rw-r--r--lib/libc/powerpc/gen/fpsetround.c52
-rw-r--r--lib/libc/powerpc/gen/infinity.c30
-rw-r--r--lib/libc/powerpc/gen/makecontext.c120
-rw-r--r--lib/libc/powerpc/gen/setjmp.S134
-rw-r--r--lib/libc/powerpc/gen/signalcontext.c103
-rw-r--r--lib/libc/powerpc/gen/sigsetjmp.S142
-rw-r--r--lib/libc/powerpc/gen/syncicache.c103
-rw-r--r--lib/libc/powerpc/softfloat/milieu.h49
-rw-r--r--lib/libc/powerpc/softfloat/powerpc-gcc.h92
-rw-r--r--lib/libc/powerpc/softfloat/softfloat.h307
-rw-r--r--lib/libc/powerpc/sys/Makefile.inc3
-rw-r--r--lib/libc/powerpc/sys/brk.S76
-rw-r--r--lib/libc/powerpc/sys/cerror.S57
-rw-r--r--lib/libc/powerpc/sys/exect.S42
-rw-r--r--lib/libc/powerpc/sys/sbrk.S73
-rw-r--r--lib/libc/powerpc/sys/setlogin.S51
-rw-r--r--lib/libc/powerpc64/Makefile.inc7
-rw-r--r--lib/libc/powerpc64/SYS.h94
-rw-r--r--lib/libc/powerpc64/Symbol.map55
-rw-r--r--lib/libc/powerpc64/_fpmath.h56
-rw-r--r--lib/libc/powerpc64/arith.h16
-rw-r--r--lib/libc/powerpc64/gd_qnan.h21
-rw-r--r--lib/libc/powerpc64/gen/Makefile.inc10
-rw-r--r--lib/libc/powerpc64/gen/_ctx_start.S51
-rw-r--r--lib/libc/powerpc64/gen/_set_tp.c35
-rw-r--r--lib/libc/powerpc64/gen/_setjmp.S155
-rw-r--r--lib/libc/powerpc64/gen/fabs.S38
-rw-r--r--lib/libc/powerpc64/gen/flt_rounds.c56
-rw-r--r--lib/libc/powerpc64/gen/fpgetmask.c48
-rw-r--r--lib/libc/powerpc64/gen/fpgetround.c48
-rw-r--r--lib/libc/powerpc64/gen/fpgetsticky.c54
-rw-r--r--lib/libc/powerpc64/gen/fpsetmask.c52
-rw-r--r--lib/libc/powerpc64/gen/fpsetround.c52
-rw-r--r--lib/libc/powerpc64/gen/infinity.c30
-rw-r--r--lib/libc/powerpc64/gen/makecontext.c118
-rw-r--r--lib/libc/powerpc64/gen/setjmp.S176
-rw-r--r--lib/libc/powerpc64/gen/signalcontext.c103
-rw-r--r--lib/libc/powerpc64/gen/sigsetjmp.S183
-rw-r--r--lib/libc/powerpc64/gen/syncicache.c103
-rw-r--r--lib/libc/powerpc64/softfloat/milieu.h49
-rw-r--r--lib/libc/powerpc64/softfloat/powerpc-gcc.h92
-rw-r--r--lib/libc/powerpc64/softfloat/softfloat.h307
-rw-r--r--lib/libc/powerpc64/sys/Makefile.inc3
-rw-r--r--lib/libc/powerpc64/sys/brk.S74
-rw-r--r--lib/libc/powerpc64/sys/cerror.S60
-rw-r--r--lib/libc/powerpc64/sys/exect.S50
-rw-r--r--lib/libc/powerpc64/sys/sbrk.S69
-rw-r--r--lib/libc/powerpc64/sys/setlogin.S41
-rw-r--r--lib/libc/powerpcspe/Makefile.inc8
-rw-r--r--lib/libc/powerpcspe/gen/Makefile.inc7
-rw-r--r--lib/libc/powerpcspe/gen/_setjmp.S117
-rw-r--r--lib/libc/powerpcspe/gen/fabs.S38
-rw-r--r--lib/libc/powerpcspe/gen/flt_rounds.c57
-rw-r--r--lib/libc/powerpcspe/gen/fpgetmask.c49
-rw-r--r--lib/libc/powerpcspe/gen/fpgetround.c49
-rw-r--r--lib/libc/powerpcspe/gen/fpgetsticky.c55
-rw-r--r--lib/libc/powerpcspe/gen/fpsetmask.c53
-rw-r--r--lib/libc/powerpcspe/gen/fpsetround.c53
-rw-r--r--lib/libc/powerpcspe/gen/setjmp.S138
-rw-r--r--lib/libc/powerpcspe/gen/sigsetjmp.S150
-rw-r--r--lib/libc/powerpcspe/softfloat/milieu.h49
-rw-r--r--lib/libc/powerpcspe/softfloat/powerpc-gcc.h92
-rw-r--r--lib/libc/powerpcspe/softfloat/softfloat.h307
-rw-r--r--lib/libc/powerpcspe/sys/Makefile.inc4
-rw-r--r--lib/libc/quad/Makefile.inc25
-rw-r--r--lib/libc/quad/Symbol.map38
-rw-r--r--lib/libc/quad/TESTS/Makefile11
-rw-r--r--lib/libc/quad/TESTS/divrem.c76
-rw-r--r--lib/libc/quad/TESTS/mul.c72
-rw-r--r--lib/libc/quad/adddi3.c58
-rw-r--r--lib/libc/quad/anddi3.c56
-rw-r--r--lib/libc/quad/ashldi3.c64
-rw-r--r--lib/libc/quad/ashrdi3.c73
-rw-r--r--lib/libc/quad/cmpdi2.c57
-rw-r--r--lib/libc/quad/divdi3.c63
-rw-r--r--lib/libc/quad/fixdfdi.c60
-rw-r--r--lib/libc/quad/fixsfdi.c61
-rw-r--r--lib/libc/quad/fixunsdfdi.c94
-rw-r--r--lib/libc/quad/fixunssfdi.c98
-rw-r--r--lib/libc/quad/floatdidf.c72
-rw-r--r--lib/libc/quad/floatdisf.c74
-rw-r--r--lib/libc/quad/floatunsdidf.c57
-rw-r--r--lib/libc/quad/iordi3.c56
-rw-r--r--lib/libc/quad/lshldi3.c64
-rw-r--r--lib/libc/quad/lshrdi3.c63
-rw-r--r--lib/libc/quad/moddi3.c65
-rw-r--r--lib/libc/quad/muldi3.c244
-rw-r--r--lib/libc/quad/negdi2.c55
-rw-r--r--lib/libc/quad/notdi2.c56
-rw-r--r--lib/libc/quad/qdivrem.c277
-rw-r--r--lib/libc/quad/quad.h103
-rw-r--r--lib/libc/quad/subdi3.c57
-rw-r--r--lib/libc/quad/ucmpdi2.c56
-rw-r--r--lib/libc/quad/udivdi3.c51
-rw-r--r--lib/libc/quad/umoddi3.c53
-rw-r--r--lib/libc/quad/xordi3.c56
-rw-r--r--lib/libc/regex/COPYRIGHT56
-rw-r--r--lib/libc/regex/Makefile.inc17
-rw-r--r--lib/libc/regex/Symbol.map10
-rw-r--r--lib/libc/regex/WHATSNEW94
-rw-r--r--lib/libc/regex/cname.h138
-rw-r--r--lib/libc/regex/engine.c1183
-rw-r--r--lib/libc/regex/grot/Makefile99
-rw-r--r--lib/libc/regex/grot/debug.c212
-rw-r--r--lib/libc/regex/grot/main.c494
-rwxr-xr-xlib/libc/regex/grot/mkh77
-rw-r--r--lib/libc/regex/grot/split.c316
-rw-r--r--lib/libc/regex/grot/tests477
-rw-r--r--lib/libc/regex/re_format.7492
-rw-r--r--lib/libc/regex/regcomp.c1817
-rw-r--r--lib/libc/regex/regerror.c174
-rw-r--r--lib/libc/regex/regex.3755
-rw-r--r--lib/libc/regex/regex2.h192
-rw-r--r--lib/libc/regex/regexec.c233
-rw-r--r--lib/libc/regex/regfree.c89
-rw-r--r--lib/libc/regex/utils.h54
-rw-r--r--lib/libc/resolv/Makefile.inc12
-rw-r--r--lib/libc/resolv/Symbol.map112
-rw-r--r--lib/libc/resolv/h_errno.c49
-rw-r--r--lib/libc/resolv/herror.c125
-rw-r--r--lib/libc/resolv/mtctxres.c138
-rw-r--r--lib/libc/resolv/res_comp.c276
-rw-r--r--lib/libc/resolv/res_data.c335
-rw-r--r--lib/libc/resolv/res_debug.c1239
-rw-r--r--lib/libc/resolv/res_debug.h35
-rw-r--r--lib/libc/resolv/res_findzonecut.c727
-rw-r--r--lib/libc/resolv/res_init.c948
-rw-r--r--lib/libc/resolv/res_mkquery.c305
-rw-r--r--lib/libc/resolv/res_mkupdate.c1198
-rw-r--r--lib/libc/resolv/res_private.h27
-rw-r--r--lib/libc/resolv/res_query.c490
-rw-r--r--lib/libc/resolv/res_send.c1178
-rw-r--r--lib/libc/resolv/res_state.c122
-rw-r--r--lib/libc/resolv/res_update.c222
-rw-r--r--lib/libc/riscv/Makefile.inc13
-rw-r--r--lib/libc/riscv/SYS.h68
-rw-r--r--lib/libc/riscv/Symbol.map56
-rw-r--r--lib/libc/riscv/_fpmath.h71
-rw-r--r--lib/libc/riscv/arith.h19
-rw-r--r--lib/libc/riscv/gd_qnan.h21
-rw-r--r--lib/libc/riscv/gen/Makefile.inc13
-rw-r--r--lib/libc/riscv/gen/_ctx_start.S43
-rw-r--r--lib/libc/riscv/gen/_set_tp.c50
-rw-r--r--lib/libc/riscv/gen/_setjmp.S145
-rw-r--r--lib/libc/riscv/gen/fabs.S41
-rw-r--r--lib/libc/riscv/gen/flt_rounds.c72
-rw-r--r--lib/libc/riscv/gen/infinity.c14
-rw-r--r--lib/libc/riscv/gen/makecontext.c91
-rw-r--r--lib/libc/riscv/gen/setjmp.S171
-rw-r--r--lib/libc/riscv/gen/sigsetjmp.S57
-rw-r--r--lib/libc/riscv/softfloat/milieu.h48
-rw-r--r--lib/libc/riscv/softfloat/riscv-gcc.h86
-rw-r--r--lib/libc/riscv/softfloat/softfloat.h315
-rw-r--r--lib/libc/riscv/sys/Makefile.inc13
-rw-r--r--lib/libc/riscv/sys/cerror.S50
-rw-r--r--lib/libc/riscv/sys/shmat.S40
-rw-r--r--lib/libc/riscv/sys/sigreturn.S40
-rw-r--r--lib/libc/riscv/sys/syscall.S40
-rw-r--r--lib/libc/riscv/sys/vfork.S51
-rw-r--r--lib/libc/rpc/DISCLAIMER60
-rw-r--r--lib/libc/rpc/Makefile.inc179
-rw-r--r--lib/libc/rpc/README176
-rw-r--r--lib/libc/rpc/Symbol.map247
-rw-r--r--lib/libc/rpc/auth_des.c497
-rw-r--r--lib/libc/rpc/auth_none.c175
-rw-r--r--lib/libc/rpc/auth_time.c502
-rw-r--r--lib/libc/rpc/auth_unix.c370
-rw-r--r--lib/libc/rpc/authdes_prot.c89
-rw-r--r--lib/libc/rpc/authunix_prot.c76
-rw-r--r--lib/libc/rpc/bindresvport.3103
-rw-r--r--lib/libc/rpc/bindresvport.c156
-rw-r--r--lib/libc/rpc/clnt_bcast.c679
-rw-r--r--lib/libc/rpc/clnt_dg.c851
-rw-r--r--lib/libc/rpc/clnt_generic.c448
-rw-r--r--lib/libc/rpc/clnt_perror.c323
-rw-r--r--lib/libc/rpc/clnt_raw.c296
-rw-r--r--lib/libc/rpc/clnt_simple.c207
-rw-r--r--lib/libc/rpc/clnt_vc.c847
-rw-r--r--lib/libc/rpc/crypt_client.c99
-rw-r--r--lib/libc/rpc/des_crypt.3130
-rw-r--r--lib/libc/rpc/des_crypt.c140
-rw-r--r--lib/libc/rpc/des_soft.c69
-rw-r--r--lib/libc/rpc/getnetconfig.3222
-rw-r--r--lib/libc/rpc/getnetconfig.c734
-rw-r--r--lib/libc/rpc/getnetpath.3170
-rw-r--r--lib/libc/rpc/getnetpath.c271
-rw-r--r--lib/libc/rpc/getpublickey.c171
-rw-r--r--lib/libc/rpc/getrpcent.3109
-rw-r--r--lib/libc/rpc/getrpcent.c1047
-rw-r--r--lib/libc/rpc/getrpcport.336
-rw-r--r--lib/libc/rpc/getrpcport.c75
-rw-r--r--lib/libc/rpc/key_call.c459
-rw-r--r--lib/libc/rpc/key_prot_xdr.c177
-rw-r--r--lib/libc/rpc/mt_misc.c116
-rw-r--r--lib/libc/rpc/mt_misc.h65
-rw-r--r--lib/libc/rpc/netconfig.5132
-rw-r--r--lib/libc/rpc/netname.c141
-rw-r--r--lib/libc/rpc/netnamer.c323
-rw-r--r--lib/libc/rpc/pmap_clnt.c119
-rw-r--r--lib/libc/rpc/pmap_getmaps.c98
-rw-r--r--lib/libc/rpc/pmap_getport.c100
-rw-r--r--lib/libc/rpc/pmap_prot.c66
-rw-r--r--lib/libc/rpc/pmap_prot2.c138
-rw-r--r--lib/libc/rpc/pmap_rmt.c166
-rw-r--r--lib/libc/rpc/publickey.353
-rw-r--r--lib/libc/rpc/publickey.542
-rw-r--r--lib/libc/rpc/rpc.3517
-rw-r--r--lib/libc/rpc/rpc.559
-rw-r--r--lib/libc/rpc/rpc_callmsg.c204
-rw-r--r--lib/libc/rpc/rpc_clnt_auth.396
-rw-r--r--lib/libc/rpc/rpc_clnt_calls.3316
-rw-r--r--lib/libc/rpc/rpc_clnt_create.3514
-rw-r--r--lib/libc/rpc/rpc_com.h94
-rw-r--r--lib/libc/rpc/rpc_commondata.c47
-rw-r--r--lib/libc/rpc/rpc_dtablesize.c66
-rw-r--r--lib/libc/rpc/rpc_generic.c836
-rw-r--r--lib/libc/rpc/rpc_prot.c353
-rw-r--r--lib/libc/rpc/rpc_secure.3287
-rw-r--r--lib/libc/rpc/rpc_soc.31721
-rw-r--r--lib/libc/rpc/rpc_soc.c533
-rw-r--r--lib/libc/rpc/rpc_svc_calls.3267
-rw-r--r--lib/libc/rpc/rpc_svc_create.3337
-rw-r--r--lib/libc/rpc/rpc_svc_err.397
-rw-r--r--lib/libc/rpc/rpc_svc_reg.3183
-rw-r--r--lib/libc/rpc/rpc_xdr.3101
-rw-r--r--lib/libc/rpc/rpcb_clnt.c1303
-rw-r--r--lib/libc/rpc/rpcb_prot.c315
-rw-r--r--lib/libc/rpc/rpcb_st_xdr.c260
-rw-r--r--lib/libc/rpc/rpcbind.3194
-rw-r--r--lib/libc/rpc/rpcdname.c79
-rw-r--r--lib/libc/rpc/rpcsec_gss_stub.c48
-rw-r--r--lib/libc/rpc/rtime.350
-rw-r--r--lib/libc/rpc/rtime.c156
-rw-r--r--lib/libc/rpc/svc.c759
-rw-r--r--lib/libc/rpc/svc_auth.c224
-rw-r--r--lib/libc/rpc/svc_auth_des.c526
-rw-r--r--lib/libc/rpc/svc_auth_unix.c151
-rw-r--r--lib/libc/rpc/svc_dg.c710
-rw-r--r--lib/libc/rpc/svc_generic.c316
-rw-r--r--lib/libc/rpc/svc_raw.c269
-rw-r--r--lib/libc/rpc/svc_run.c97
-rw-r--r--lib/libc/rpc/svc_simple.c310
-rw-r--r--lib/libc/rpc/svc_vc.c782
-rw-r--r--lib/libc/secure/Makefile.inc13
-rw-r--r--lib/libc/secure/Symbol.map9
-rw-r--r--lib/libc/secure/stack_protector.c116
-rw-r--r--lib/libc/secure/stack_protector_compat.c20
-rw-r--r--lib/libc/softfloat/Makefile.inc35
-rw-r--r--lib/libc/softfloat/README.NetBSD9
-rw-r--r--lib/libc/softfloat/README.txt40
-rw-r--r--lib/libc/softfloat/Symbol.map41
-rw-r--r--lib/libc/softfloat/bits32/softfloat-macros649
-rw-r--r--lib/libc/softfloat/bits32/softfloat.c2347
-rw-r--r--lib/libc/softfloat/bits64/softfloat-macros746
-rw-r--r--lib/libc/softfloat/bits64/softfloat.c5599
-rw-r--r--lib/libc/softfloat/eqdf2.c22
-rw-r--r--lib/libc/softfloat/eqsf2.c22
-rw-r--r--lib/libc/softfloat/eqtf2.c24
-rw-r--r--lib/libc/softfloat/fpgetmask.c53
-rw-r--r--lib/libc/softfloat/fpgetround.c53
-rw-r--r--lib/libc/softfloat/fpgetsticky.c53
-rw-r--r--lib/libc/softfloat/fpsetmask.c56
-rw-r--r--lib/libc/softfloat/fpsetround.c56
-rw-r--r--lib/libc/softfloat/fpsetsticky.c56
-rw-r--r--lib/libc/softfloat/gedf2.c22
-rw-r--r--lib/libc/softfloat/gesf2.c22
-rw-r--r--lib/libc/softfloat/getf2.c26
-rw-r--r--lib/libc/softfloat/gexf2.c25
-rw-r--r--lib/libc/softfloat/gtdf2.c22
-rw-r--r--lib/libc/softfloat/gtsf2.c22
-rw-r--r--lib/libc/softfloat/gttf2.c26
-rw-r--r--lib/libc/softfloat/gtxf2.c25
-rw-r--r--lib/libc/softfloat/ledf2.c22
-rw-r--r--lib/libc/softfloat/lesf2.c22
-rw-r--r--lib/libc/softfloat/letf2.c26
-rw-r--r--lib/libc/softfloat/ltdf2.c22
-rw-r--r--lib/libc/softfloat/ltsf2.c22
-rw-r--r--lib/libc/softfloat/lttf2.c26
-rw-r--r--lib/libc/softfloat/nedf2.c22
-rw-r--r--lib/libc/softfloat/negdf2.c22
-rw-r--r--lib/libc/softfloat/negsf2.c22
-rw-r--r--lib/libc/softfloat/negtf2.c27
-rw-r--r--lib/libc/softfloat/negxf2.c25
-rw-r--r--lib/libc/softfloat/nesf2.c22
-rw-r--r--lib/libc/softfloat/netf2.c26
-rw-r--r--lib/libc/softfloat/nexf2.c25
-rw-r--r--lib/libc/softfloat/softfloat-for-gcc.h169
-rw-r--r--lib/libc/softfloat/softfloat-history.txt53
-rw-r--r--lib/libc/softfloat/softfloat-source.txt384
-rw-r--r--lib/libc/softfloat/softfloat-specialize521
-rw-r--r--lib/libc/softfloat/softfloat.txt373
-rw-r--r--lib/libc/softfloat/templates/milieu.h49
-rw-r--r--lib/libc/softfloat/templates/softfloat-specialize465
-rw-r--r--lib/libc/softfloat/templates/softfloat.h291
-rw-r--r--lib/libc/softfloat/timesoftfloat.c2639
-rw-r--r--lib/libc/softfloat/timesoftfloat.txt150
-rw-r--r--lib/libc/softfloat/unorddf2.c26
-rw-r--r--lib/libc/softfloat/unordsf2.c26
-rw-r--r--lib/libc/sparc64/Makefile.inc13
-rw-r--r--lib/libc/sparc64/SYS.h85
-rw-r--r--lib/libc/sparc64/Symbol.map95
-rw-r--r--lib/libc/sparc64/_fpmath.h57
-rw-r--r--lib/libc/sparc64/arith.h19
-rw-r--r--lib/libc/sparc64/fpu/Makefile.inc8
-rw-r--r--lib/libc/sparc64/fpu/fpu.c461
-rw-r--r--lib/libc/sparc64/fpu/fpu_add.c214
-rw-r--r--lib/libc/sparc64/fpu/fpu_arith.h87
-rw-r--r--lib/libc/sparc64/fpu/fpu_compare.c177
-rw-r--r--lib/libc/sparc64/fpu/fpu_div.c270
-rw-r--r--lib/libc/sparc64/fpu/fpu_emu.h177
-rw-r--r--lib/libc/sparc64/fpu/fpu_explode.c324
-rw-r--r--lib/libc/sparc64/fpu/fpu_extern.h85
-rw-r--r--lib/libc/sparc64/fpu/fpu_implode.c542
-rw-r--r--lib/libc/sparc64/fpu/fpu_mul.c224
-rw-r--r--lib/libc/sparc64/fpu/fpu_qp.c163
-rw-r--r--lib/libc/sparc64/fpu/fpu_reg.S194
-rw-r--r--lib/libc/sparc64/fpu/fpu_reg.h88
-rw-r--r--lib/libc/sparc64/fpu/fpu_sqrt.c397
-rw-r--r--lib/libc/sparc64/fpu/fpu_subr.c221
-rw-r--r--lib/libc/sparc64/gd_qnan.h21
-rw-r--r--lib/libc/sparc64/gen/Makefile.inc7
-rw-r--r--lib/libc/sparc64/gen/_ctx_start.S36
-rw-r--r--lib/libc/sparc64/gen/_set_tp.c35
-rw-r--r--lib/libc/sparc64/gen/_setjmp.S79
-rw-r--r--lib/libc/sparc64/gen/assym.s18
-rw-r--r--lib/libc/sparc64/gen/fabs.S35
-rw-r--r--lib/libc/sparc64/gen/fixunsdfsi.S93
-rw-r--r--lib/libc/sparc64/gen/flt_rounds.c26
-rw-r--r--lib/libc/sparc64/gen/fpgetmask.c22
-rw-r--r--lib/libc/sparc64/gen/fpgetround.c21
-rw-r--r--lib/libc/sparc64/gen/fpgetsticky.c21
-rw-r--r--lib/libc/sparc64/gen/fpsetmask.c28
-rw-r--r--lib/libc/sparc64/gen/fpsetround.c30
-rw-r--r--lib/libc/sparc64/gen/infinity.c17
-rw-r--r--lib/libc/sparc64/gen/makecontext.c89
-rw-r--r--lib/libc/sparc64/gen/setjmp.S88
-rw-r--r--lib/libc/sparc64/gen/signalcontext.c77
-rw-r--r--lib/libc/sparc64/gen/sigsetjmp.S56
-rw-r--r--lib/libc/sparc64/string/Makefile.inc1
-rw-r--r--lib/libc/sparc64/sys/Makefile.inc15
-rw-r--r--lib/libc/sparc64/sys/__sparc_sigtramp_setup.c46
-rw-r--r--lib/libc/sparc64/sys/__sparc_utrap.c141
-rw-r--r--lib/libc/sparc64/sys/__sparc_utrap_align.c117
-rw-r--r--lib/libc/sparc64/sys/__sparc_utrap_emul.c155
-rw-r--r--lib/libc/sparc64/sys/__sparc_utrap_fp_disabled.S36
-rw-r--r--lib/libc/sparc64/sys/__sparc_utrap_gen.S107
-rw-r--r--lib/libc/sparc64/sys/__sparc_utrap_install.c49
-rw-r--r--lib/libc/sparc64/sys/__sparc_utrap_private.h66
-rw-r--r--lib/libc/sparc64/sys/__sparc_utrap_setup.c58
-rw-r--r--lib/libc/sparc64/sys/assym.s39
-rw-r--r--lib/libc/sparc64/sys/brk.S65
-rw-r--r--lib/libc/sparc64/sys/cerror.S59
-rw-r--r--lib/libc/sparc64/sys/exect.S51
-rw-r--r--lib/libc/sparc64/sys/sbrk.S71
-rw-r--r--lib/libc/sparc64/sys/setlogin.S55
-rw-r--r--lib/libc/sparc64/sys/sigaction1.S50
-rw-r--r--lib/libc/sparc64/sys/sigcode.S40
-rw-r--r--lib/libc/stdio/Makefile.inc87
-rw-r--r--lib/libc/stdio/Symbol.map208
-rw-r--r--lib/libc/stdio/_flock_stub.c139
-rw-r--r--lib/libc/stdio/asprintf.c67
-rw-r--r--lib/libc/stdio/clrerr.c60
-rw-r--r--lib/libc/stdio/dprintf.c45
-rw-r--r--lib/libc/stdio/fclose.3161
-rw-r--r--lib/libc/stdio/fclose.c138
-rw-r--r--lib/libc/stdio/fcloseall.c39
-rw-r--r--lib/libc/stdio/fdopen.c105
-rw-r--r--lib/libc/stdio/feof.c63
-rw-r--r--lib/libc/stdio/ferror.3131
-rw-r--r--lib/libc/stdio/ferror.c63
-rw-r--r--lib/libc/stdio/fflush.3111
-rw-r--r--lib/libc/stdio/fflush.c150
-rw-r--r--lib/libc/stdio/fgetc.c55
-rw-r--r--lib/libc/stdio/fgetln.3128
-rw-r--r--lib/libc/stdio/fgetln.c174
-rw-r--r--lib/libc/stdio/fgetpos.c51
-rw-r--r--lib/libc/stdio/fgets.3156
-rw-r--r--lib/libc/stdio/fgets.c115
-rw-r--r--lib/libc/stdio/fgetwc.c109
-rw-r--r--lib/libc/stdio/fgetwln.3116
-rw-r--r--lib/libc/stdio/fgetwln.c94
-rw-r--r--lib/libc/stdio/fgetws.3121
-rw-r--r--lib/libc/stdio/fgetws.c128
-rw-r--r--lib/libc/stdio/fileno.c64
-rw-r--r--lib/libc/stdio/findfp.c219
-rw-r--r--lib/libc/stdio/flags.c117
-rw-r--r--lib/libc/stdio/floatio.h54
-rw-r--r--lib/libc/stdio/flockfile.3104
-rw-r--r--lib/libc/stdio/fmemopen.c262
-rw-r--r--lib/libc/stdio/fopen.3353
-rw-r--r--lib/libc/stdio/fopen.c99
-rw-r--r--lib/libc/stdio/fopencookie.3156
-rw-r--r--lib/libc/stdio/fopencookie.c168
-rw-r--r--lib/libc/stdio/fprintf.c70
-rw-r--r--lib/libc/stdio/fpurge.c69
-rw-r--r--lib/libc/stdio/fputc.c55
-rw-r--r--lib/libc/stdio/fputs.3104
-rw-r--r--lib/libc/stdio/fputs.c69
-rw-r--r--lib/libc/stdio/fputwc.c88
-rw-r--r--lib/libc/stdio/fputws.388
-rw-r--r--lib/libc/stdio/fputws.c86
-rw-r--r--lib/libc/stdio/fread.3105
-rw-r--r--lib/libc/stdio/fread.c115
-rw-r--r--lib/libc/stdio/freopen.c250
-rw-r--r--lib/libc/stdio/fscanf.c78
-rw-r--r--lib/libc/stdio/fseek.3269
-rw-r--r--lib/libc/stdio/fseek.c301
-rw-r--r--lib/libc/stdio/fsetpos.c49
-rw-r--r--lib/libc/stdio/ftell.c141
-rw-r--r--lib/libc/stdio/funopen.3177
-rw-r--r--lib/libc/stdio/funopen.c76
-rw-r--r--lib/libc/stdio/fvwrite.c205
-rw-r--r--lib/libc/stdio/fvwrite.h49
-rw-r--r--lib/libc/stdio/fwalk.c65
-rw-r--r--lib/libc/stdio/fwide.397
-rw-r--r--lib/libc/stdio/fwide.c51
-rw-r--r--lib/libc/stdio/fwprintf.c63
-rw-r--r--lib/libc/stdio/fwrite.c96
-rw-r--r--lib/libc/stdio/fwscanf.c63
-rw-r--r--lib/libc/stdio/getc.3169
-rw-r--r--lib/libc/stdio/getc.c65
-rw-r--r--lib/libc/stdio/getchar.c68
-rw-r--r--lib/libc/stdio/getdelim.c160
-rw-r--r--lib/libc/stdio/getline.3137
-rw-r--r--lib/libc/stdio/getline.c38
-rw-r--r--lib/libc/stdio/gets.c76
-rw-r--r--lib/libc/stdio/getw.c47
-rw-r--r--lib/libc/stdio/getwc.3114
-rw-r--r--lib/libc/stdio/getwc.c60
-rw-r--r--lib/libc/stdio/getwchar.c57
-rw-r--r--lib/libc/stdio/glue.h45
-rw-r--r--lib/libc/stdio/local.h140
-rw-r--r--lib/libc/stdio/makebuf.c116
-rw-r--r--lib/libc/stdio/mktemp.3326
-rw-r--r--lib/libc/stdio/mktemp.c210
-rw-r--r--lib/libc/stdio/open_memstream.3155
-rw-r--r--lib/libc/stdio/open_memstream.c212
-rw-r--r--lib/libc/stdio/open_wmemstream.c274
-rw-r--r--lib/libc/stdio/perror.c75
-rw-r--r--lib/libc/stdio/printf-pos.c773
-rw-r--r--lib/libc/stdio/printf.3891
-rw-r--r--lib/libc/stdio/printf.c69
-rw-r--r--lib/libc/stdio/printf_l.381
-rw-r--r--lib/libc/stdio/printfcommon.h307
-rw-r--r--lib/libc/stdio/printflocal.h94
-rw-r--r--lib/libc/stdio/putc.3165
-rw-r--r--lib/libc/stdio/putc.c65
-rw-r--r--lib/libc/stdio/putchar.c70
-rw-r--r--lib/libc/stdio/puts.c70
-rw-r--r--lib/libc/stdio/putw.c60
-rw-r--r--lib/libc/stdio/putwc.3103
-rw-r--r--lib/libc/stdio/putwc.c59
-rw-r--r--lib/libc/stdio/putwchar.c58
-rw-r--r--lib/libc/stdio/refill.c146
-rw-r--r--lib/libc/stdio/remove.383
-rw-r--r--lib/libc/stdio/remove.c54
-rw-r--r--lib/libc/stdio/rewind.c60
-rw-r--r--lib/libc/stdio/rget.c55
-rw-r--r--lib/libc/stdio/scanf.3513
-rw-r--r--lib/libc/stdio/scanf.c78
-rw-r--r--lib/libc/stdio/scanf_l.371
-rw-r--r--lib/libc/stdio/setbuf.3200
-rw-r--r--lib/libc/stdio/setbuf.c46
-rw-r--r--lib/libc/stdio/setbuffer.c56
-rw-r--r--lib/libc/stdio/setvbuf.c161
-rw-r--r--lib/libc/stdio/snprintf.c105
-rw-r--r--lib/libc/stdio/sprintf.c73
-rw-r--r--lib/libc/stdio/sscanf.c72
-rw-r--r--lib/libc/stdio/stdio.3333
-rw-r--r--lib/libc/stdio/stdio.c168
-rw-r--r--lib/libc/stdio/swprintf.c64
-rw-r--r--lib/libc/stdio/swscanf.c64
-rw-r--r--lib/libc/stdio/tempnam.c89
-rw-r--r--lib/libc/stdio/tmpfile.c93
-rw-r--r--lib/libc/stdio/tmpnam.3246
-rw-r--r--lib/libc/stdio/tmpnam.c60
-rw-r--r--lib/libc/stdio/ungetc.398
-rw-r--r--lib/libc/stdio/ungetc.c168
-rw-r--r--lib/libc/stdio/ungetwc.395
-rw-r--r--lib/libc/stdio/ungetwc.c90
-rw-r--r--lib/libc/stdio/vasprintf.c74
-rw-r--r--lib/libc/stdio/vdprintf.c70
-rw-r--r--lib/libc/stdio/vfprintf.c1045
-rw-r--r--lib/libc/stdio/vfscanf.c1092
-rw-r--r--lib/libc/stdio/vfwprintf.c1109
-rw-r--r--lib/libc/stdio/vfwscanf.c948
-rw-r--r--lib/libc/stdio/vprintf.c56
-rw-r--r--lib/libc/stdio/vscanf.c66
-rw-r--r--lib/libc/stdio/vsnprintf.c88
-rw-r--r--lib/libc/stdio/vsprintf.c68
-rw-r--r--lib/libc/stdio/vsscanf.c78
-rw-r--r--lib/libc/stdio/vswprintf.c114
-rw-r--r--lib/libc/stdio/vswscanf.c104
-rw-r--r--lib/libc/stdio/vwprintf.c49
-rw-r--r--lib/libc/stdio/vwscanf.c49
-rw-r--r--lib/libc/stdio/wbuf.c92
-rw-r--r--lib/libc/stdio/wprintf.3618
-rw-r--r--lib/libc/stdio/wprintf.c63
-rw-r--r--lib/libc/stdio/wscanf.3479
-rw-r--r--lib/libc/stdio/wscanf.c63
-rw-r--r--lib/libc/stdio/wsetup.c92
-rw-r--r--lib/libc/stdio/xprintf.c690
-rw-r--r--lib/libc/stdio/xprintf_errno.c66
-rw-r--r--lib/libc/stdio/xprintf_float.c422
-rw-r--r--lib/libc/stdio/xprintf_hexdump.c97
-rw-r--r--lib/libc/stdio/xprintf_int.c471
-rw-r--r--lib/libc/stdio/xprintf_quote.c98
-rw-r--r--lib/libc/stdio/xprintf_str.c187
-rw-r--r--lib/libc/stdio/xprintf_time.c122
-rw-r--r--lib/libc/stdio/xprintf_vis.c78
-rw-r--r--lib/libc/stdlib/Makefile.inc62
-rw-r--r--lib/libc/stdlib/Symbol.map129
-rw-r--r--lib/libc/stdlib/_Exit.c22
-rw-r--r--lib/libc/stdlib/a64l.3187
-rw-r--r--lib/libc/stdlib/a64l.c46
-rw-r--r--lib/libc/stdlib/abort.379
-rw-r--r--lib/libc/stdlib/abort.c79
-rw-r--r--lib/libc/stdlib/abs.375
-rw-r--r--lib/libc/stdlib/abs.c42
-rw-r--r--lib/libc/stdlib/alloca.388
-rw-r--r--lib/libc/stdlib/at_quick_exit.362
-rw-r--r--lib/libc/stdlib/atexit.3103
-rw-r--r--lib/libc/stdlib/atexit.c247
-rw-r--r--lib/libc/stdlib/atexit.h36
-rw-r--r--lib/libc/stdlib/atof.395
-rw-r--r--lib/libc/stdlib/atof.c54
-rw-r--r--lib/libc/stdlib/atoi.387
-rw-r--r--lib/libc/stdlib/atoi.c54
-rw-r--r--lib/libc/stdlib/atol.3135
-rw-r--r--lib/libc/stdlib/atol.c54
-rw-r--r--lib/libc/stdlib/atoll.c51
-rw-r--r--lib/libc/stdlib/bsearch.395
-rw-r--r--lib/libc/stdlib/bsearch.c88
-rw-r--r--lib/libc/stdlib/bsearch_b.c29
-rw-r--r--lib/libc/stdlib/cxa_thread_atexit.c40
-rw-r--r--lib/libc/stdlib/cxa_thread_atexit_impl.c153
-rw-r--r--lib/libc/stdlib/div.368
-rw-r--r--lib/libc/stdlib/div.c79
-rw-r--r--lib/libc/stdlib/exit.3132
-rw-r--r--lib/libc/stdlib/exit.c76
-rw-r--r--lib/libc/stdlib/getenv.3230
-rw-r--r--lib/libc/stdlib/getenv.c691
-rw-r--r--lib/libc/stdlib/getopt.3317
-rw-r--r--lib/libc/stdlib/getopt.c138
-rw-r--r--lib/libc/stdlib/getopt_long.3507
-rw-r--r--lib/libc/stdlib/getopt_long.c612
-rw-r--r--lib/libc/stdlib/getsubopt.3147
-rw-r--r--lib/libc/stdlib/getsubopt.c95
-rw-r--r--lib/libc/stdlib/hcreate.3325
-rw-r--r--lib/libc/stdlib/hcreate.c73
-rw-r--r--lib/libc/stdlib/hcreate_r.c63
-rw-r--r--lib/libc/stdlib/hdestroy_r.c43
-rw-r--r--lib/libc/stdlib/heapsort.c200
-rw-r--r--lib/libc/stdlib/heapsort_b.c29
-rw-r--r--lib/libc/stdlib/hsearch.h40
-rw-r--r--lib/libc/stdlib/hsearch_r.c150
-rw-r--r--lib/libc/stdlib/imaxabs.362
-rw-r--r--lib/libc/stdlib/imaxabs.c36
-rw-r--r--lib/libc/stdlib/imaxdiv.373
-rw-r--r--lib/libc/stdlib/imaxdiv.c47
-rw-r--r--lib/libc/stdlib/insque.361
-rw-r--r--lib/libc/stdlib/insque.c47
-rw-r--r--lib/libc/stdlib/jemalloc/Makefile.inc49
-rw-r--r--lib/libc/stdlib/jemalloc/Symbol.map69
-rw-r--r--lib/libc/stdlib/l64a.c44
-rw-r--r--lib/libc/stdlib/labs.367
-rw-r--r--lib/libc/stdlib/labs.c42
-rw-r--r--lib/libc/stdlib/ldiv.371
-rw-r--r--lib/libc/stdlib/ldiv.c58
-rw-r--r--lib/libc/stdlib/llabs.362
-rw-r--r--lib/libc/stdlib/llabs.c36
-rw-r--r--lib/libc/stdlib/lldiv.373
-rw-r--r--lib/libc/stdlib/lldiv.c47
-rw-r--r--lib/libc/stdlib/lsearch.3146
-rw-r--r--lib/libc/stdlib/lsearch.c60
-rw-r--r--lib/libc/stdlib/memory.377
-rw-r--r--lib/libc/stdlib/merge.c359
-rw-r--r--lib/libc/stdlib/mergesort_b.c29
-rw-r--r--lib/libc/stdlib/ptsname.3161
-rw-r--r--lib/libc/stdlib/ptsname.c91
-rw-r--r--lib/libc/stdlib/qsort.3366
-rw-r--r--lib/libc/stdlib/qsort.c202
-rw-r--r--lib/libc/stdlib/qsort_r.c19
-rw-r--r--lib/libc/stdlib/quick_exit.358
-rw-r--r--lib/libc/stdlib/quick_exit.c80
-rw-r--r--lib/libc/stdlib/radixsort.3160
-rw-r--r--lib/libc/stdlib/radixsort.c311
-rw-r--r--lib/libc/stdlib/rand.3125
-rw-r--r--lib/libc/stdlib/rand.c151
-rw-r--r--lib/libc/stdlib/random.3197
-rw-r--r--lib/libc/stdlib/random.c453
-rw-r--r--lib/libc/stdlib/reallocarray.3142
-rw-r--r--lib/libc/stdlib/reallocarray.c42
-rw-r--r--lib/libc/stdlib/reallocf.382
-rw-r--r--lib/libc/stdlib/reallocf.c48
-rw-r--r--lib/libc/stdlib/realpath.3135
-rw-r--r--lib/libc/stdlib/realpath.c235
-rw-r--r--lib/libc/stdlib/remque.c30
-rw-r--r--lib/libc/stdlib/strfmon.3184
-rw-r--r--lib/libc/stdlib/strfmon.c641
-rw-r--r--lib/libc/stdlib/strtod.3198
-rw-r--r--lib/libc/stdlib/strtoimax.c153
-rw-r--r--lib/libc/stdlib/strtol.3222
-rw-r--r--lib/libc/stdlib/strtol.c158
-rw-r--r--lib/libc/stdlib/strtoll.c153
-rw-r--r--lib/libc/stdlib/strtonum.3155
-rw-r--r--lib/libc/stdlib/strtonum.c68
-rw-r--r--lib/libc/stdlib/strtoq.c48
-rw-r--r--lib/libc/stdlib/strtoul.3224
-rw-r--r--lib/libc/stdlib/strtoul.c130
-rw-r--r--lib/libc/stdlib/strtoull.c131
-rw-r--r--lib/libc/stdlib/strtoumax.c131
-rw-r--r--lib/libc/stdlib/strtouq.c48
-rw-r--r--lib/libc/stdlib/system.3111
-rw-r--r--lib/libc/stdlib/system.c112
-rw-r--r--lib/libc/stdlib/tdelete.c208
-rw-r--r--lib/libc/stdlib/tfind.c48
-rw-r--r--lib/libc/stdlib/tsearch.3151
-rw-r--r--lib/libc/stdlib/tsearch.c197
-rw-r--r--lib/libc/stdlib/tsearch_path.h97
-rw-r--r--lib/libc/stdlib/twalk.c50
-rw-r--r--lib/libc/stdtime/Makefile.inc24
-rw-r--r--lib/libc/stdtime/Symbol.map35
-rw-r--r--lib/libc/stdtime/strftime.3289
-rw-r--r--lib/libc/stdtime/strftime.c642
-rw-r--r--lib/libc/stdtime/strptime.3182
-rw-r--r--lib/libc/stdtime/strptime.c707
-rw-r--r--lib/libc/stdtime/time32.c100
-rw-r--r--lib/libc/stdtime/timelocal.c154
-rw-r--r--lib/libc/stdtime/timelocal.h61
-rw-r--r--lib/libc/string/Makefile.inc102
-rw-r--r--lib/libc/string/Symbol.map114
-rw-r--r--lib/libc/string/bcmp.378
-rw-r--r--lib/libc/string/bcmp.c55
-rw-r--r--lib/libc/string/bcopy.398
-rw-r--r--lib/libc/string/bcopy.c137
-rw-r--r--lib/libc/string/bstring.3108
-rw-r--r--lib/libc/string/bzero.398
-rw-r--r--lib/libc/string/bzero.c5
-rw-r--r--lib/libc/string/ffs.3111
-rw-r--r--lib/libc/string/ffs.c51
-rw-r--r--lib/libc/string/ffsl.c48
-rw-r--r--lib/libc/string/ffsll.c48
-rw-r--r--lib/libc/string/fls.c48
-rw-r--r--lib/libc/string/flsl.c48
-rw-r--r--lib/libc/string/flsll.c48
-rw-r--r--lib/libc/string/index.3115
-rw-r--r--lib/libc/string/memccpy.374
-rw-r--r--lib/libc/string/memccpy.c52
-rw-r--r--lib/libc/string/memchr.3106
-rw-r--r--lib/libc/string/memchr.c53
-rw-r--r--lib/libc/string/memcmp.385
-rw-r--r--lib/libc/string/memcmp.c56
-rw-r--r--lib/libc/string/memcpy.388
-rw-r--r--lib/libc/string/memcpy.c5
-rw-r--r--lib/libc/string/memmem.392
-rw-r--r--lib/libc/string/memmem.c65
-rw-r--r--lib/libc/string/memmove.375
-rw-r--r--lib/libc/string/memmove.c5
-rw-r--r--lib/libc/string/memrchr.c40
-rw-r--r--lib/libc/string/memset.372
-rw-r--r--lib/libc/string/memset.c128
-rw-r--r--lib/libc/string/stpcpy.c46
-rw-r--r--lib/libc/string/stpncpy.c45
-rw-r--r--lib/libc/string/strcasecmp.3118
-rw-r--r--lib/libc/string/strcasecmp.c87
-rw-r--r--lib/libc/string/strcasestr.c72
-rw-r--r--lib/libc/string/strcat.3155
-rw-r--r--lib/libc/string/strcat.c46
-rw-r--r--lib/libc/string/strchr.3125
-rw-r--r--lib/libc/string/strchr.c54
-rw-r--r--lib/libc/string/strchrnul.c50
-rw-r--r--lib/libc/string/strcmp.3101
-rw-r--r--lib/libc/string/strcmp.c51
-rw-r--r--lib/libc/string/strcoll.383
-rw-r--r--lib/libc/string/strcoll.c118
-rw-r--r--lib/libc/string/strcpy.3212
-rw-r--r--lib/libc/string/strcpy.c45
-rw-r--r--lib/libc/string/strcspn.c72
-rw-r--r--lib/libc/string/strdup.384
-rw-r--r--lib/libc/string/strdup.c51
-rw-r--r--lib/libc/string/strerror.3190
-rw-r--r--lib/libc/string/strerror.c128
-rw-r--r--lib/libc/string/string.3157
-rw-r--r--lib/libc/string/strlcat.c58
-rw-r--r--lib/libc/string/strlcpy.3200
-rw-r--r--lib/libc/string/strlcpy.c53
-rw-r--r--lib/libc/string/strlen.392
-rw-r--r--lib/libc/string/strlen.c130
-rw-r--r--lib/libc/string/strmode.3142
-rw-r--r--lib/libc/string/strmode.c148
-rw-r--r--lib/libc/string/strncat.c62
-rw-r--r--lib/libc/string/strncmp.c52
-rw-r--r--lib/libc/string/strncpy.c62
-rw-r--r--lib/libc/string/strndup.c40
-rw-r--r--lib/libc/string/strnlen.c42
-rw-r--r--lib/libc/string/strnstr.c65
-rw-r--r--lib/libc/string/strpbrk.377
-rw-r--r--lib/libc/string/strpbrk.c53
-rw-r--r--lib/libc/string/strrchr.c55
-rw-r--r--lib/libc/string/strsep.3135
-rw-r--r--lib/libc/string/strsep.c75
-rw-r--r--lib/libc/string/strsignal.c152
-rw-r--r--lib/libc/string/strspn.3111
-rw-r--r--lib/libc/string/strspn.c71
-rw-r--r--lib/libc/string/strstr.3155
-rw-r--r--lib/libc/string/strstr.c61
-rw-r--r--lib/libc/string/strtok.3176
-rw-r--r--lib/libc/string/strtok.c136
-rw-r--r--lib/libc/string/strxfrm.3108
-rw-r--r--lib/libc/string/strxfrm.c103
-rw-r--r--lib/libc/string/swab.367
-rw-r--r--lib/libc/string/swab.c61
-rw-r--r--lib/libc/string/timingsafe_bcmp.392
-rw-r--r--lib/libc/string/timingsafe_bcmp.c36
-rw-r--r--lib/libc/string/timingsafe_memcmp.c53
-rw-r--r--lib/libc/string/wcpcpy.c46
-rw-r--r--lib/libc/string/wcpncpy.c45
-rw-r--r--lib/libc/string/wcscasecmp.c45
-rw-r--r--lib/libc/string/wcscat.c51
-rw-r--r--lib/libc/string/wcschr.c41
-rw-r--r--lib/libc/string/wcscmp.c56
-rw-r--r--lib/libc/string/wcscoll.3108
-rw-r--r--lib/libc/string/wcscoll.c223
-rw-r--r--lib/libc/string/wcscpy.c49
-rw-r--r--lib/libc/string/wcscspn.c58
-rw-r--r--lib/libc/string/wcsdup.c43
-rw-r--r--lib/libc/string/wcslcat.c74
-rw-r--r--lib/libc/string/wcslcpy.c70
-rw-r--r--lib/libc/string/wcslen.c49
-rw-r--r--lib/libc/string/wcsncasecmp.c49
-rw-r--r--lib/libc/string/wcsncat.c57
-rw-r--r--lib/libc/string/wcsncmp.c57
-rw-r--r--lib/libc/string/wcsncpy.c64
-rw-r--r--lib/libc/string/wcsnlen.c42
-rw-r--r--lib/libc/string/wcspbrk.c58
-rw-r--r--lib/libc/string/wcsrchr.c47
-rw-r--r--lib/libc/string/wcsspn.c60
-rw-r--r--lib/libc/string/wcsstr.c63
-rw-r--r--lib/libc/string/wcstok.3133
-rw-r--r--lib/libc/string/wcstok.c86
-rw-r--r--lib/libc/string/wcswidth.362
-rw-r--r--lib/libc/string/wcswidth.c69
-rw-r--r--lib/libc/string/wcsxfrm.3122
-rw-r--r--lib/libc/string/wcsxfrm.c85
-rw-r--r--lib/libc/string/wmemchr.3174
-rw-r--r--lib/libc/string/wmemchr.c52
-rw-r--r--lib/libc/string/wmemcmp.c53
-rw-r--r--lib/libc/string/wmemcpy.c44
-rw-r--r--lib/libc/string/wmemmove.c44
-rw-r--r--lib/libc/string/wmemset.c51
-rw-r--r--lib/libc/sys/Makefile.inc486
-rw-r--r--lib/libc/sys/Symbol.map1047
-rw-r--r--lib/libc/sys/__error.c58
-rw-r--r--lib/libc/sys/__vdso_gettimeofday.c156
-rw-r--r--lib/libc/sys/_exit.2125
-rw-r--r--lib/libc/sys/_umtx_op.21427
-rw-r--r--lib/libc/sys/abort2.2113
-rw-r--r--lib/libc/sys/accept.2239
-rw-r--r--lib/libc/sys/accept.c50
-rw-r--r--lib/libc/sys/accept4.c50
-rw-r--r--lib/libc/sys/access.2243
-rw-r--r--lib/libc/sys/acct.2131
-rw-r--r--lib/libc/sys/adjtime.2111
-rw-r--r--lib/libc/sys/aio_cancel.2117
-rw-r--r--lib/libc/sys/aio_error.2101
-rw-r--r--lib/libc/sys/aio_fsync.2178
-rw-r--r--lib/libc/sys/aio_mlock.2138
-rw-r--r--lib/libc/sys/aio_read.2222
-rw-r--r--lib/libc/sys/aio_return.2102
-rw-r--r--lib/libc/sys/aio_suspend.2117
-rw-r--r--lib/libc/sys/aio_suspend.c51
-rw-r--r--lib/libc/sys/aio_waitcomplete.2137
-rw-r--r--lib/libc/sys/aio_write.2217
-rw-r--r--lib/libc/sys/bind.2139
-rw-r--r--lib/libc/sys/bindat.2109
-rw-r--r--lib/libc/sys/brk.2170
-rw-r--r--lib/libc/sys/cap_enter.2160
-rw-r--r--lib/libc/sys/cap_fcntls_limit.2126
-rw-r--r--lib/libc/sys/cap_ioctls_limit.2159
-rw-r--r--lib/libc/sys/cap_rights_limit.2157
-rw-r--r--lib/libc/sys/chdir.2132
-rw-r--r--lib/libc/sys/chflags.2326
-rw-r--r--lib/libc/sys/chmod.2327
-rw-r--r--lib/libc/sys/chown.2268
-rw-r--r--lib/libc/sys/chroot.2156
-rw-r--r--lib/libc/sys/clock_gettime.2166
-rw-r--r--lib/libc/sys/clock_gettime.c52
-rw-r--r--lib/libc/sys/close.2144
-rw-r--r--lib/libc/sys/close.c49
-rw-r--r--lib/libc/sys/closefrom.253
-rw-r--r--lib/libc/sys/connect.2185
-rw-r--r--lib/libc/sys/connect.c50
-rw-r--r--lib/libc/sys/connectat.2109
-rw-r--r--lib/libc/sys/cpuset.2230
-rw-r--r--lib/libc/sys/cpuset_getaffinity.2166
-rw-r--r--lib/libc/sys/dup.2169
-rw-r--r--lib/libc/sys/execve.2377
-rw-r--r--lib/libc/sys/extattr_get_file.2276
-rw-r--r--lib/libc/sys/fcntl.2679
-rw-r--r--lib/libc/sys/fcntl.c56
-rw-r--r--lib/libc/sys/fdatasync.c46
-rw-r--r--lib/libc/sys/ffclock.2177
-rw-r--r--lib/libc/sys/fhopen.2147
-rw-r--r--lib/libc/sys/flock.2173
-rw-r--r--lib/libc/sys/fork.2148
-rw-r--r--lib/libc/sys/fork.c48
-rw-r--r--lib/libc/sys/fsync.2130
-rw-r--r--lib/libc/sys/fsync.c48
-rw-r--r--lib/libc/sys/futimens.c100
-rw-r--r--lib/libc/sys/getdirentries.2186
-rw-r--r--lib/libc/sys/getdtablesize.262
-rw-r--r--lib/libc/sys/getfh.2115
-rw-r--r--lib/libc/sys/getfsstat.2130
-rw-r--r--lib/libc/sys/getgid.280
-rw-r--r--lib/libc/sys/getgroups.2107
-rw-r--r--lib/libc/sys/getitimer.2180
-rw-r--r--lib/libc/sys/getlogin.2204
-rw-r--r--lib/libc/sys/getloginclass.2100
-rw-r--r--lib/libc/sys/getpeername.298
-rw-r--r--lib/libc/sys/getpgrp.2142
-rw-r--r--lib/libc/sys/getpid.290
-rw-r--r--lib/libc/sys/getpriority.2150
-rw-r--r--lib/libc/sys/getrlimit.2238
-rw-r--r--lib/libc/sys/getrusage.2186
-rw-r--r--lib/libc/sys/getsid.282
-rw-r--r--lib/libc/sys/getsockname.298
-rw-r--r--lib/libc/sys/getsockopt.2576
-rw-r--r--lib/libc/sys/gettimeofday.2132
-rw-r--r--lib/libc/sys/gettimeofday.c48
-rw-r--r--lib/libc/sys/getuid.289
-rw-r--r--lib/libc/sys/interposing_table.c91
-rw-r--r--lib/libc/sys/intro.2754
-rw-r--r--lib/libc/sys/ioctl.2155
-rw-r--r--lib/libc/sys/issetugid.298
-rw-r--r--lib/libc/sys/jail.2411
-rw-r--r--lib/libc/sys/kenv.2179
-rw-r--r--lib/libc/sys/kevent.c53
-rw-r--r--lib/libc/sys/kill.2156
-rw-r--r--lib/libc/sys/kldfind.286
-rw-r--r--lib/libc/sys/kldfirstmod.276
-rw-r--r--lib/libc/sys/kldload.296
-rw-r--r--lib/libc/sys/kldnext.289
-rw-r--r--lib/libc/sys/kldstat.2133
-rw-r--r--lib/libc/sys/kldsym.2121
-rw-r--r--lib/libc/sys/kldunload.294
-rw-r--r--lib/libc/sys/kqueue.2771
-rw-r--r--lib/libc/sys/ktrace.2204
-rw-r--r--lib/libc/sys/link.2288
-rw-r--r--lib/libc/sys/lio_listio.2218
-rw-r--r--lib/libc/sys/listen.2186
-rw-r--r--lib/libc/sys/lseek.2217
-rw-r--r--lib/libc/sys/madvise.2186
-rw-r--r--lib/libc/sys/mincore.2115
-rw-r--r--lib/libc/sys/minherit.2139
-rw-r--r--lib/libc/sys/mkdir.2176
-rw-r--r--lib/libc/sys/mkfifo.2185
-rw-r--r--lib/libc/sys/mknod.2182
-rw-r--r--lib/libc/sys/mlock.2183
-rw-r--r--lib/libc/sys/mlockall.2146
-rw-r--r--lib/libc/sys/mmap.2452
-rw-r--r--lib/libc/sys/modfind.286
-rw-r--r--lib/libc/sys/modnext.297
-rw-r--r--lib/libc/sys/modstat.2127
-rw-r--r--lib/libc/sys/mount.2378
-rw-r--r--lib/libc/sys/mprotect.297
-rw-r--r--lib/libc/sys/mq_close.2105
-rw-r--r--lib/libc/sys/mq_getattr.2127
-rw-r--r--lib/libc/sys/mq_notify.2165
-rw-r--r--lib/libc/sys/mq_open.2329
-rw-r--r--lib/libc/sys/mq_receive.2217
-rw-r--r--lib/libc/sys/mq_send.2236
-rw-r--r--lib/libc/sys/mq_setattr.2123
-rw-r--r--lib/libc/sys/msgctl.2210
-rw-r--r--lib/libc/sys/msgget.2141
-rw-r--r--lib/libc/sys/msgrcv.2222
-rw-r--r--lib/libc/sys/msgsnd.2184
-rw-r--r--lib/libc/sys/msync.2126
-rw-r--r--lib/libc/sys/msync.c50
-rw-r--r--lib/libc/sys/munmap.278
-rw-r--r--lib/libc/sys/nanosleep.2111
-rw-r--r--lib/libc/sys/nanosleep.c49
-rw-r--r--lib/libc/sys/nfssvc.2258
-rw-r--r--lib/libc/sys/ntp_adjtime.2315
-rw-r--r--lib/libc/sys/numa_getaffinity.2197
-rw-r--r--lib/libc/sys/open.2532
-rw-r--r--lib/libc/sys/open.c59
-rw-r--r--lib/libc/sys/openat.c62
-rw-r--r--lib/libc/sys/pathconf.2261
-rw-r--r--lib/libc/sys/pdfork.2202
-rw-r--r--lib/libc/sys/pipe.2178
-rw-r--r--lib/libc/sys/pipe.c47
-rw-r--r--lib/libc/sys/poll.2273
-rw-r--r--lib/libc/sys/poll.c49
-rw-r--r--lib/libc/sys/posix_fadvise.2139
-rw-r--r--lib/libc/sys/posix_fallocate.2144
-rw-r--r--lib/libc/sys/posix_openpt.2140
-rw-r--r--lib/libc/sys/ppoll.c51
-rw-r--r--lib/libc/sys/procctl.2505
-rw-r--r--lib/libc/sys/profil.2122
-rw-r--r--lib/libc/sys/pselect.2123
-rw-r--r--lib/libc/sys/pselect.c51
-rw-r--r--lib/libc/sys/ptrace.21066
-rw-r--r--lib/libc/sys/ptrace.c49
-rw-r--r--lib/libc/sys/quotactl.2261
-rw-r--r--lib/libc/sys/rctl_add_rule.2220
-rw-r--r--lib/libc/sys/read.2284
-rw-r--r--lib/libc/sys/read.c50
-rw-r--r--lib/libc/sys/readlink.2158
-rw-r--r--lib/libc/sys/readv.c51
-rw-r--r--lib/libc/sys/reboot.2168
-rw-r--r--lib/libc/sys/recv.2423
-rw-r--r--lib/libc/sys/recvfrom.c53
-rw-r--r--lib/libc/sys/recvmsg.c50
-rw-r--r--lib/libc/sys/rename.2308
-rw-r--r--lib/libc/sys/revoke.2110
-rw-r--r--lib/libc/sys/rfork.2192
-rw-r--r--lib/libc/sys/rmdir.2118
-rw-r--r--lib/libc/sys/rtprio.2199
-rw-r--r--lib/libc/sys/sched_get_priority_max.2123
-rw-r--r--lib/libc/sys/sched_setparam.2174
-rw-r--r--lib/libc/sys/sched_setscheduler.2166
-rw-r--r--lib/libc/sys/sched_yield.258
-rw-r--r--lib/libc/sys/sctp_generic_recvmsg.274
-rw-r--r--lib/libc/sys/sctp_generic_sendmsg.286
-rw-r--r--lib/libc/sys/sctp_peeloff.276
-rw-r--r--lib/libc/sys/select.2227
-rw-r--r--lib/libc/sys/select.c49
-rw-r--r--lib/libc/sys/semctl.2200
-rw-r--r--lib/libc/sys/semget.2159
-rw-r--r--lib/libc/sys/semop.2289
-rw-r--r--lib/libc/sys/send.2269
-rw-r--r--lib/libc/sys/sendfile.2399
-rw-r--r--lib/libc/sys/sendmsg.c50
-rw-r--r--lib/libc/sys/sendto.c53
-rw-r--r--lib/libc/sys/setcontext.c52
-rw-r--r--lib/libc/sys/setfib.2107
-rw-r--r--lib/libc/sys/setgroups.287
-rw-r--r--lib/libc/sys/setpgid.2110
-rw-r--r--lib/libc/sys/setregid.290
-rw-r--r--lib/libc/sys/setresuid.294
-rw-r--r--lib/libc/sys/setreuid.290
-rw-r--r--lib/libc/sys/setsid.281
-rw-r--r--lib/libc/sys/setuid.2187
-rw-r--r--lib/libc/sys/shm_open.2313
-rw-r--r--lib/libc/sys/shmat.2122
-rw-r--r--lib/libc/sys/shmctl.2141
-rw-r--r--lib/libc/sys/shmget.2146
-rw-r--r--lib/libc/sys/shutdown.2171
-rw-r--r--lib/libc/sys/sigaction.2791
-rw-r--r--lib/libc/sys/sigaction.c50
-rw-r--r--lib/libc/sys/sigaltstack.2162
-rw-r--r--lib/libc/sys/sigpending.277
-rw-r--r--lib/libc/sys/sigprocmask.2131
-rw-r--r--lib/libc/sys/sigprocmask.c50
-rw-r--r--lib/libc/sys/sigqueue.2149
-rw-r--r--lib/libc/sys/sigreturn.289
-rw-r--r--lib/libc/sys/sigstack.250
-rw-r--r--lib/libc/sys/sigsuspend.285
-rw-r--r--lib/libc/sys/sigsuspend.c50
-rw-r--r--lib/libc/sys/sigtimedwait.c51
-rw-r--r--lib/libc/sys/sigwait.2124
-rw-r--r--lib/libc/sys/sigwait.c54
-rw-r--r--lib/libc/sys/sigwaitinfo.2206
-rw-r--r--lib/libc/sys/sigwaitinfo.c49
-rw-r--r--lib/libc/sys/socket.2350
-rw-r--r--lib/libc/sys/socketpair.2100
-rw-r--r--lib/libc/sys/stat.2436
-rw-r--r--lib/libc/sys/statfs.2235
-rw-r--r--lib/libc/sys/swapcontext.c53
-rw-r--r--lib/libc/sys/swapon.2143
-rw-r--r--lib/libc/sys/symlink.2206
-rw-r--r--lib/libc/sys/sync.277
-rw-r--r--lib/libc/sys/sysarch.281
-rw-r--r--lib/libc/sys/syscall.277
-rw-r--r--lib/libc/sys/thr_exit.290
-rw-r--r--lib/libc/sys/thr_kill.2133
-rw-r--r--lib/libc/sys/thr_new.2245
-rw-r--r--lib/libc/sys/thr_self.290
-rw-r--r--lib/libc/sys/thr_set_name.294
-rw-r--r--lib/libc/sys/thr_suspend.2130
-rw-r--r--lib/libc/sys/thr_wake.2112
-rw-r--r--lib/libc/sys/timer_create.2200
-rw-r--r--lib/libc/sys/timer_delete.280
-rw-r--r--lib/libc/sys/timer_settime.2265
-rw-r--r--lib/libc/sys/trivial-vdso_tc.c48
-rw-r--r--lib/libc/sys/truncate.2165
-rw-r--r--lib/libc/sys/umask.288
-rw-r--r--lib/libc/sys/undelete.2105
-rw-r--r--lib/libc/sys/unlink.2228
-rw-r--r--lib/libc/sys/utimensat.2295
-rw-r--r--lib/libc/sys/utimensat.c112
-rw-r--r--lib/libc/sys/utimes.2262
-rw-r--r--lib/libc/sys/utrace.280
-rw-r--r--lib/libc/sys/uuidgen.2142
-rw-r--r--lib/libc/sys/vfork.2145
-rw-r--r--lib/libc/sys/wait.2680
-rw-r--r--lib/libc/sys/wait4.c49
-rw-r--r--lib/libc/sys/wait6.c52
-rw-r--r--lib/libc/sys/write.2285
-rw-r--r--lib/libc/sys/write.c50
-rw-r--r--lib/libc/sys/writev.c51
-rw-r--r--lib/libc/tests/Makefile40
-rw-r--r--lib/libc/tests/Makefile.depend11
-rw-r--r--lib/libc/tests/Makefile.netbsd-tests9
-rw-r--r--lib/libc/tests/c063/Makefile25
-rw-r--r--lib/libc/tests/c063/Makefile.depend20
-rw-r--r--lib/libc/tests/db/Makefile20
-rw-r--r--lib/libc/tests/db/Makefile.depend18
-rw-r--r--lib/libc/tests/gen/Makefile89
-rw-r--r--lib/libc/tests/gen/Makefile.depend23
-rw-r--r--lib/libc/tests/gen/arc4random_test.c89
-rw-r--r--lib/libc/tests/gen/dlopen_empty_test.c97
-rw-r--r--lib/libc/tests/gen/execve/Makefile9
-rw-r--r--lib/libc/tests/gen/execve/Makefile.depend20
-rw-r--r--lib/libc/tests/gen/fmtcheck_test.c105
-rw-r--r--lib/libc/tests/gen/fmtmsg_test.c252
-rw-r--r--lib/libc/tests/gen/fnmatch_test.c188
-rw-r--r--lib/libc/tests/gen/fnmatch_testcases.h176
-rw-r--r--lib/libc/tests/gen/fpclassify2_test.c72
-rw-r--r--lib/libc/tests/gen/ftw_test.c127
-rw-r--r--lib/libc/tests/gen/popen_test.c251
-rw-r--r--lib/libc/tests/gen/posix_spawn/Makefile30
-rw-r--r--lib/libc/tests/gen/posix_spawn/Makefile.depend20
-rw-r--r--lib/libc/tests/gen/posix_spawn_test.c103
-rw-r--r--lib/libc/tests/gen/test-fnmatch.c102
-rw-r--r--lib/libc/tests/gen/wordexp_test.c360
-rw-r--r--lib/libc/tests/hash/Makefile40
-rw-r--r--lib/libc/tests/hash/Makefile.depend22
-rw-r--r--lib/libc/tests/iconv/Makefile7
-rw-r--r--lib/libc/tests/iconv/iconvctl_test.c69
-rw-r--r--lib/libc/tests/inet/Makefile10
-rw-r--r--lib/libc/tests/inet/Makefile.depend21
-rw-r--r--lib/libc/tests/locale/Makefile44
-rw-r--r--lib/libc/tests/locale/Makefile.depend21
-rw-r--r--lib/libc/tests/locale/btowc_test.c71
-rw-r--r--lib/libc/tests/locale/c16rtomb_test.c166
-rw-r--r--lib/libc/tests/locale/iswctype_test.c122
-rw-r--r--lib/libc/tests/locale/mblen_test.c116
-rw-r--r--lib/libc/tests/locale/mbrlen_test.c126
-rw-r--r--lib/libc/tests/locale/mbrtoc16_test.c214
-rw-r--r--lib/libc/tests/locale/mbrtowc_test.c165
-rw-r--r--lib/libc/tests/locale/mbsnrtowcs_test.c195
-rw-r--r--lib/libc/tests/locale/mbsrtowcs_test.c153
-rw-r--r--lib/libc/tests/locale/mbstowcs_test.c111
-rw-r--r--lib/libc/tests/locale/mbtowc_test.c122
-rw-r--r--lib/libc/tests/locale/towctrans_test.c90
-rw-r--r--lib/libc/tests/locale/wcrtomb_test.c135
-rw-r--r--lib/libc/tests/locale/wcsnrtombs_test.c195
-rw-r--r--lib/libc/tests/locale/wcsrtombs_test.c156
-rw-r--r--lib/libc/tests/locale/wcstombs_test.c130
-rw-r--r--lib/libc/tests/locale/wctomb_test.c113
-rw-r--r--lib/libc/tests/net/Makefile41
-rw-r--r--lib/libc/tests/net/Makefile.depend21
-rw-r--r--lib/libc/tests/net/ether_test.c192
-rw-r--r--lib/libc/tests/net/eui64_aton_test.c104
-rw-r--r--lib/libc/tests/net/eui64_ntoa_test.c64
-rw-r--r--lib/libc/tests/net/getaddrinfo/Makefile32
-rw-r--r--lib/libc/tests/net/test-eui64.h55
-rw-r--r--lib/libc/tests/nss/Makefile25
-rw-r--r--lib/libc/tests/nss/Makefile.depend21
-rw-r--r--lib/libc/tests/nss/getaddrinfo_test.c556
-rw-r--r--lib/libc/tests/nss/getgr_test.c546
-rw-r--r--lib/libc/tests/nss/gethostby_test.c1506
-rw-r--r--lib/libc/tests/nss/getproto_test.c556
-rw-r--r--lib/libc/tests/nss/getpw_test.c530
-rw-r--r--lib/libc/tests/nss/getrpc_test.c560
-rw-r--r--lib/libc/tests/nss/getserv_test.c570
-rw-r--r--lib/libc/tests/nss/getusershell_test.c225
-rw-r--r--lib/libc/tests/nss/testutil.h330
-rw-r--r--lib/libc/tests/regex/Makefile62
-rw-r--r--lib/libc/tests/regex/Makefile.depend21
-rw-r--r--lib/libc/tests/resolv/Makefile15
-rw-r--r--lib/libc/tests/resolv/Makefile.depend20
-rw-r--r--lib/libc/tests/resolv/mach46
-rw-r--r--lib/libc/tests/resolv/resolv_test.c331
-rw-r--r--lib/libc/tests/rpc/Makefile25
-rw-r--r--lib/libc/tests/rpc/Makefile.depend23
-rw-r--r--lib/libc/tests/setjmp/Makefile12
-rw-r--r--lib/libc/tests/setjmp/Makefile.depend20
-rw-r--r--lib/libc/tests/ssp/Makefile70
-rw-r--r--lib/libc/tests/ssp/Makefile.depend21
-rw-r--r--lib/libc/tests/stdio/Makefile43
-rw-r--r--lib/libc/tests/stdio/Makefile.depend21
-rw-r--r--lib/libc/tests/stdio/fdopen_test.c225
-rw-r--r--lib/libc/tests/stdio/fmemopen2_test.c288
-rw-r--r--lib/libc/tests/stdio/fopen_test.c205
-rw-r--r--lib/libc/tests/stdio/freopen_test.c223
-rw-r--r--lib/libc/tests/stdio/getdelim_test.c235
-rw-r--r--lib/libc/tests/stdio/mkostemp_test.c185
-rw-r--r--lib/libc/tests/stdio/open_memstream2_test.c201
-rw-r--r--lib/libc/tests/stdio/open_wmemstream_test.c201
-rw-r--r--lib/libc/tests/stdio/perror_test.c107
-rw-r--r--lib/libc/tests/stdio/print_positional_test.c157
-rw-r--r--lib/libc/tests/stdio/printbasic_test.c160
-rw-r--r--lib/libc/tests/stdio/printfloat_test.c392
-rw-r--r--lib/libc/tests/stdio/scanfloat_test.c316
-rw-r--r--lib/libc/tests/stdlib/Makefile63
-rw-r--r--lib/libc/tests/stdlib/Makefile.depend26
-rw-r--r--lib/libc/tests/stdlib/cxa_thread_atexit_nothr_test.cc102
-rw-r--r--lib/libc/tests/stdlib/cxa_thread_atexit_test.cc180
-rw-r--r--lib/libc/tests/stdlib/heapsort_test.c71
-rw-r--r--lib/libc/tests/stdlib/mergesort_test.c71
-rw-r--r--lib/libc/tests/stdlib/qsort_test.c71
-rw-r--r--lib/libc/tests/stdlib/test-sort.h273
-rw-r--r--lib/libc/tests/stdlib/tsearch_test.c131
-rw-r--r--lib/libc/tests/string/Makefile36
-rw-r--r--lib/libc/tests/string/Makefile.depend21
-rw-r--r--lib/libc/tests/string/memcmp_test.c124
-rw-r--r--lib/libc/tests/string/stpncpy_test.c110
-rw-r--r--lib/libc/tests/string/strerror_test.c206
-rw-r--r--lib/libc/tests/string/strxfrm_test.c51
-rw-r--r--lib/libc/tests/string/wcscasecmp_test.c128
-rw-r--r--lib/libc/tests/string/wcscoll_test.c63
-rw-r--r--lib/libc/tests/string/wcsnlen_test.c104
-rw-r--r--lib/libc/tests/sys/Makefile97
-rw-r--r--lib/libc/tests/sys/Makefile.depend24
-rw-r--r--lib/libc/tests/sys/mlock_helper.c114
-rw-r--r--lib/libc/tests/sys/queue_test.c237
-rw-r--r--lib/libc/tests/termios/Makefile9
-rw-r--r--lib/libc/tests/termios/Makefile.depend20
-rw-r--r--lib/libc/tests/time/Makefile10
-rw-r--r--lib/libc/tests/time/Makefile.depend20
-rw-r--r--lib/libc/tests/tls/Makefile33
-rw-r--r--lib/libc/tests/tls/Makefile.depend22
-rw-r--r--lib/libc/tests/tls/dso/Makefile16
-rw-r--r--lib/libc/tests/tls_dso/Makefile20
-rw-r--r--lib/libc/tests/tls_dso/Makefile.depend17
-rw-r--r--lib/libc/tests/ttyio/Makefile12
-rw-r--r--lib/libc/tests/ttyio/Makefile.depend21
-rw-r--r--lib/libc/uuid/Makefile.inc24
-rw-r--r--lib/libc/uuid/Symbol.map21
-rw-r--r--lib/libc/uuid/uuid.3136
-rw-r--r--lib/libc/uuid/uuid_compare.c76
-rw-r--r--lib/libc/uuid/uuid_create.c45
-rw-r--r--lib/libc/uuid/uuid_create_nil.c46
-rw-r--r--lib/libc/uuid/uuid_equal.c55
-rw-r--r--lib/libc/uuid/uuid_from_string.c92
-rw-r--r--lib/libc/uuid/uuid_hash.c49
-rw-r--r--lib/libc/uuid/uuid_is_nil.c54
-rw-r--r--lib/libc/uuid/uuid_stream.c113
-rw-r--r--lib/libc/uuid/uuid_to_string.c67
-rw-r--r--lib/libc/x86/sys/Makefile.inc10
-rw-r--r--lib/libc/x86/sys/__vdso_gettc.c268
-rw-r--r--lib/libc/xdr/Makefile.inc52
-rw-r--r--lib/libc/xdr/Symbol.map56
-rw-r--r--lib/libc/xdr/xdr.3847
-rw-r--r--lib/libc/xdr/xdr.c907
-rw-r--r--lib/libc/xdr/xdr_array.c160
-rw-r--r--lib/libc/xdr/xdr_float.c295
-rw-r--r--lib/libc/xdr/xdr_mem.c234
-rw-r--r--lib/libc/xdr/xdr_rec.c761
-rw-r--r--lib/libc/xdr/xdr_reference.c141
-rw-r--r--lib/libc/xdr/xdr_sizeof.c155
-rw-r--r--lib/libc/xdr/xdr_stdio.c177
-rw-r--r--lib/libc/yp/Makefile.inc19
-rw-r--r--lib/libc/yp/Symbol.map25
-rw-r--r--lib/libc/yp/xdryp.c125
-rw-r--r--lib/libc/yp/yplib.c1242
2304 files changed, 383150 insertions, 0 deletions
diff --git a/lib/libc/Makefile b/lib/libc/Makefile
new file mode 100644
index 000000000000..97739713cb07
--- /dev/null
+++ b/lib/libc/Makefile
@@ -0,0 +1,209 @@
+# @(#)Makefile 8.2 (Berkeley) 2/3/94
+# $FreeBSD$
+
+PACKAGE= clibs
+SHLIBDIR?= /lib
+
+.include <src.opts.mk>
+
+# Force building of libc_pic.a
+MK_TOOLCHAIN= yes
+
+LIBC_SRCTOP?= ${.CURDIR}
+
+# Pick the current architecture directory for libc. In general, this is
+# named MACHINE_CPUARCH, but some ABIs are different enough to require
+# their own libc, so allow a directory named MACHINE_ARCH to override this.
+
+.if exists(${LIBC_SRCTOP}/${MACHINE_ARCH})
+LIBC_ARCH=${MACHINE_ARCH}
+.else
+LIBC_ARCH=${MACHINE_CPUARCH}
+.endif
+
+# All library objects contain FreeBSD revision strings by default; they may be
+# excluded as a space-saving measure. To produce a library that does
+# not contain these strings, add -DSTRIP_FBSDID (see <sys/cdefs.h>) to CFLAGS
+# below. Note: there are no IDs for syscall stubs whose sources are generated.
+# To include legacy CSRG sccsid strings, add -DLIBC_SCCS and -DSYSLIBC_SCCS
+# to CFLAGS below. -DSYSLIBC_SCCS affects just the system call stubs.
+LIB=c
+SHLIB_MAJOR= 7
+.if ${MK_SSP} != "no"
+SHLIB_LDSCRIPT=libc.ldscript
+.else
+SHLIB_LDSCRIPT=libc_nossp.ldscript
+.endif
+SHLIB_LDSCRIPT_LINKS=libxnet.so
+WARNS?= 2
+CFLAGS+=-I${LIBC_SRCTOP}/include -I${SRCTOP}/include
+CFLAGS+=-I${LIBC_SRCTOP}/${LIBC_ARCH}
+.if ${MK_NLS} != "no"
+CFLAGS+=-DNLS
+.endif
+CLEANFILES+=tags
+INSTALL_PIC_ARCHIVE=
+PRECIOUSLIB=
+
+.ifndef NO_THREAD_STACK_UNWIND
+CANCELPOINTS_CFLAGS=-fexceptions
+CFLAGS+=${CANCELPOINTS_CFLAGS}
+.endif
+
+#
+# Link with static libcompiler_rt.a.
+#
+LDFLAGS+= -nodefaultlibs
+LIBADD+= compiler_rt
+
+.if ${MK_SSP} != "no"
+LIBADD+= ssp_nonshared
+.endif
+
+# Extras that live in either libc.a or libc_nonshared.a
+LIBC_NONSHARED_SRCS=
+
+# Define (empty) variables so that make doesn't give substitution
+# errors if the included makefiles don't change these:
+MDSRCS=
+MISRCS=
+MDASM=
+MIASM=
+NOASM=
+
+.include "${LIBC_SRCTOP}/${LIBC_ARCH}/Makefile.inc"
+.include "${LIBC_SRCTOP}/db/Makefile.inc"
+.include "${LIBC_SRCTOP}/compat-43/Makefile.inc"
+.include "${LIBC_SRCTOP}/gdtoa/Makefile.inc"
+.include "${LIBC_SRCTOP}/gen/Makefile.inc"
+.include "${LIBC_SRCTOP}/gmon/Makefile.inc"
+.if ${MK_ICONV} != "no"
+.include "${LIBC_SRCTOP}/iconv/Makefile.inc"
+.endif
+.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"
+.include "${LIBC_SRCTOP}/posix1e/Makefile.inc"
+.if ${LIBC_ARCH} != "aarch64" && \
+ ${LIBC_ARCH} != "amd64" && \
+ ${LIBC_ARCH} != "powerpc64" && \
+ ${LIBC_ARCH} != "riscv" && \
+ ${LIBC_ARCH} != "sparc64" && \
+ ${MACHINE_ARCH:Mmipsn32*} == "" && \
+ ${MACHINE_ARCH:Mmips64*} == ""
+.include "${LIBC_SRCTOP}/quad/Makefile.inc"
+.endif
+.include "${LIBC_SRCTOP}/regex/Makefile.inc"
+.include "${LIBC_SRCTOP}/resolv/Makefile.inc"
+.include "${LIBC_SRCTOP}/stdio/Makefile.inc"
+.include "${LIBC_SRCTOP}/stdlib/Makefile.inc"
+.include "${LIBC_SRCTOP}/stdlib/jemalloc/Makefile.inc"
+.include "${LIBC_SRCTOP}/stdtime/Makefile.inc"
+.include "${LIBC_SRCTOP}/string/Makefile.inc"
+.include "${LIBC_SRCTOP}/sys/Makefile.inc"
+.include "${LIBC_SRCTOP}/secure/Makefile.inc"
+.include "${LIBC_SRCTOP}/rpc/Makefile.inc"
+.include "${LIBC_SRCTOP}/uuid/Makefile.inc"
+.include "${LIBC_SRCTOP}/xdr/Makefile.inc"
+.if (${LIBC_ARCH} == "arm" && \
+ (${MACHINE_ARCH:Marmv6*} == "" || (defined(CPUTYPE) && ${CPUTYPE:M*soft*}))) || \
+ (${LIBC_ARCH} == "mips" && ${MACHINE_ARCH:Mmips*hf} == "") || \
+ (${LIBC_ARCH} == "riscv" && ${MACHINE_ARCH:Mriscv*sf} != "")
+.include "${LIBC_SRCTOP}/softfloat/Makefile.inc"
+.endif
+.if ${LIBC_ARCH} == "i386" || ${LIBC_ARCH} == "amd64"
+.include "${LIBC_SRCTOP}/x86/sys/Makefile.inc"
+.endif
+.if ${MK_NIS} != "no"
+CFLAGS+= -DYP
+.include "${LIBC_SRCTOP}/yp/Makefile.inc"
+.endif
+.include "${LIBC_SRCTOP}/capability/Makefile.inc"
+.if ${MK_HESIOD} != "no"
+CFLAGS+= -DHESIOD
+.endif
+.if ${MK_FP_LIBC} == "no"
+CFLAGS+= -DNO_FLOATING_POINT
+.endif
+.if ${MK_NS_CACHING} != "no"
+CFLAGS+= -DNS_CACHING
+.endif
+.if defined(_FREEFALL_CONFIG)
+CFLAGS+=-D_FREEFALL_CONFIG
+.endif
+
+STATICOBJS+=${LIBC_NONSHARED_SRCS:S/.c$/.o/}
+
+VERSION_DEF=${LIBC_SRCTOP}/Versions.def
+SYMBOL_MAPS=${SYM_MAPS}
+CFLAGS+= -DSYMBOL_VERSIONING
+
+# If there are no machine dependent sources, append all the
+# machine-independent sources:
+.if empty(MDSRCS)
+SRCS+= ${MISRCS}
+.else
+# Append machine-dependent sources, then append machine-independent sources
+# for which there is no machine-dependent variant.
+SRCS+= ${MDSRCS}
+.for _src in ${MISRCS}
+.if ${MDSRCS:R:M${_src:R}} == ""
+SRCS+= ${_src}
+.endif
+.endfor
+.endif
+
+KQSRCS= adddi3.c anddi3.c ashldi3.c ashrdi3.c cmpdi2.c divdi3.c iordi3.c \
+ lshldi3.c lshrdi3.c moddi3.c muldi3.c negdi2.c notdi2.c qdivrem.c \
+ subdi3.c ucmpdi2.c udivdi3.c umoddi3.c xordi3.c
+KSRCS= bcmp.c ffs.c ffsl.c fls.c flsl.c mcount.c strcat.c strchr.c \
+ strcmp.c strcpy.c strlen.c strncpy.c strrchr.c
+
+libkern: libkern.gen libkern.${LIBC_ARCH}
+
+libkern.gen: ${KQSRCS} ${KSRCS}
+ ${CP} ${LIBC_SRCTOP}/quad/quad.h ${.ALLSRC} ${DESTDIR}/sys/libkern
+
+libkern.${LIBC_ARCH}:: ${KMSRCS}
+.if defined(KMSRCS) && !empty(KMSRCS)
+ ${CP} ${.ALLSRC} ${DESTDIR}/sys/libkern/${LIBC_ARCH}
+.endif
+
+.if ${MK_TESTS} != "no"
+SUBDIR+= tests
+.endif
+
+.include <bsd.lib.mk>
+
+.if !defined(_SKIP_BUILD)
+# We need libutil.h, get it directly to avoid
+# recording a build dependency
+CFLAGS+= -I${SRCTOP}/lib/libutil
+# Same issue with libm
+MSUN_ARCH_SUBDIR != ${MAKE} -B -C ${SRCTOP}/lib/msun -V ARCH_SUBDIR
+# unfortunately msun/src contains both private and public headers
+CFLAGS+= -I${SRCTOP}/lib/msun/${MSUN_ARCH_SUBDIR}
+.if ${MACHINE_CPUARCH} == "i386" || ${MACHINE_CPUARCH} == "amd64"
+CFLAGS+= -I${SRCTOP}/lib/msun/x86
+.endif
+CFLAGS+= -I${SRCTOP}/lib/msun/src
+# and we do not want to record a dependency on msun
+.if ${.MAKE.LEVEL} > 0
+GENDIRDEPS_FILTER+= N${RELDIR:H}/msun
+.endif
+.endif
+
+# Disable warnings in contributed sources.
+CWARNFLAGS:= ${.IMPSRC:Ngdtoa_*.c:C/^.+$/${CWARNFLAGS}/:C/^$/-w/}
+# XXX For now, we don't allow libc to be compiled with
+# -fstack-protector-all because it breaks rtld. We may want to make a librtld
+# in the future to circumvent this.
+SSP_CFLAGS:= ${SSP_CFLAGS:S/^-fstack-protector-all$/-fstack-protector/}
+# Disable stack protection for SSP symbols.
+SSP_CFLAGS:= ${.IMPSRC:N*/stack_protector.c:C/^.+$/${SSP_CFLAGS}/}
+# Generate stack unwinding tables for cancellation points
+CANCELPOINTS_CFLAGS:= ${.IMPSRC:Mcancelpoints_*:C/^.+$/${CANCELPOINTS_CFLAGS}/:C/^$//}
diff --git a/lib/libc/Makefile.depend b/lib/libc/Makefile.depend
new file mode 100644
index 000000000000..c38d79a7bea4
--- /dev/null
+++ b/lib/libc/Makefile.depend
@@ -0,0 +1,18 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ gnu/lib/csu \
+ include \
+ include/rpc \
+ include/rpcsvc \
+ lib/${CSU_DIR} \
+ lib/libcompiler_rt \
+ usr.bin/yacc.host \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/lib/libc/Versions.def b/lib/libc/Versions.def
new file mode 100644
index 000000000000..e348308a7906
--- /dev/null
+++ b/lib/libc/Versions.def
@@ -0,0 +1,42 @@
+# $FreeBSD$
+
+#
+# Note: Whenever bumping the FBSD version, always make
+# FBSDprivate_1.0 depend on the new FBSD version.
+# This will keep it at the end of the dependency chain.
+#
+
+# This is our first version; it depends on no other.
+# This version was first added to 7.0-current.
+FBSD_1.0 {
+};
+
+# This version was first added to 8.0-current.
+FBSD_1.1 {
+} FBSD_1.0;
+
+# This version was first added to 9.0-current.
+FBSD_1.2 {
+} FBSD_1.1;
+
+# This version was first added to 10.0-current.
+FBSD_1.3 {
+} FBSD_1.2;
+
+# This version was first added to 11.0-current.
+FBSD_1.4 {
+} FBSD_1.3;
+
+# This version was first added to 12.0-current.
+FBSD_1.5 {
+} FBSD_1.4;
+
+
+# This is our private namespace. Any global interfaces that are
+# strictly for use only by other FreeBSD applications and libraries
+# are listed here. We use a separate namespace so we can write
+# simple ABI-checking tools.
+#
+# Please do NOT increment the version of this namespace.
+FBSDprivate_1.0 {
+} FBSD_1.5;
diff --git a/lib/libc/aarch64/Makefile.inc b/lib/libc/aarch64/Makefile.inc
new file mode 100644
index 000000000000..5f172008e4c0
--- /dev/null
+++ b/lib/libc/aarch64/Makefile.inc
@@ -0,0 +1,9 @@
+# $FreeBSD$
+#
+# Machine dependent definitions for the arm 64-bit architecture.
+#
+
+# Long double is quad precision
+GDTOASRCS+=strtorQ.c
+MDSRCS+=machdep_ldisQ.c
+SYM_MAPS+=${LIBC_SRCTOP}/aarch64/Symbol.map
diff --git a/lib/libc/aarch64/SYS.h b/lib/libc/aarch64/SYS.h
new file mode 100644
index 000000000000..e0be59d3cddb
--- /dev/null
+++ b/lib/libc/aarch64/SYS.h
@@ -0,0 +1,63 @@
+/*-
+ * Copyright (c) 2014 Andrew Turner
+ * Copyright (c) 2015 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Andrew Turner under
+ * sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/syscall.h>
+#include <machine/asm.h>
+
+#define _SYSCALL(name) \
+ mov x8, SYS_ ## name; \
+ svc 0
+
+#define SYSCALL(name) \
+ENTRY(__sys_##name); \
+ WEAK_REFERENCE(__sys_##name, name); \
+ WEAK_REFERENCE(__sys_##name, _##name); \
+ _SYSCALL(name); \
+ ret; \
+END(__sys_##name)
+
+#define PSEUDO(name) \
+ENTRY(__sys_##name); \
+ WEAK_REFERENCE(__sys_##name, _##name); \
+ _SYSCALL(name); \
+ b.cs cerror; \
+ ret; \
+END(__sys_##name)
+
+#define RSYSCALL(name) \
+ENTRY(__sys_##name); \
+ WEAK_REFERENCE(__sys_##name, name); \
+ WEAK_REFERENCE(__sys_##name, _##name); \
+ _SYSCALL(name); \
+ b.cs cerror; \
+ ret; \
+END(__sys_##name)
diff --git a/lib/libc/aarch64/Symbol.map b/lib/libc/aarch64/Symbol.map
new file mode 100644
index 000000000000..669dad37983f
--- /dev/null
+++ b/lib/libc/aarch64/Symbol.map
@@ -0,0 +1,38 @@
+/*
+ * $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, ...).
+ */
+FBSD_1.0 {
+ /* PSEUDO syscalls */
+ _exit;
+
+ _setjmp;
+ _longjmp;
+ fabs;
+ __flt_rounds;
+ fpgetmask;
+ fpsetmask;
+ __infinity;
+ __nan;
+ setjmp;
+ longjmp;
+ sigsetjmp;
+ siglongjmp;
+ htonl;
+ htons;
+ ntohl;
+ ntohs;
+ vfork;
+ makecontext;
+};
+
+FBSDprivate_1.0 {
+ _set_tp;
+ _end;
+ __makecontext;
+};
diff --git a/lib/libc/aarch64/_fpmath.h b/lib/libc/aarch64/_fpmath.h
new file mode 100644
index 000000000000..71d0a715233f
--- /dev/null
+++ b/lib/libc/aarch64/_fpmath.h
@@ -0,0 +1,58 @@
+/*-
+ * Copyright (c) 2002, 2003 David Schultz <das@FreeBSD.ORG>
+ * Copyright (2) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+union IEEEl2bits {
+ long double e;
+ struct {
+ unsigned long manl :64;
+ unsigned long manh :48;
+ unsigned int exp :15;
+ unsigned int sign :1;
+ } bits;
+ /* TODO andrew: Check the packing here */
+ struct {
+ unsigned long manl :64;
+ unsigned long manh :48;
+ unsigned int expsign :16;
+ } xbits;
+};
+
+#define LDBL_NBIT 0
+#define LDBL_IMPLICIT_NBIT
+#define mask_nbit_l(u) ((void)0)
+
+#define LDBL_MANH_SIZE 48
+#define LDBL_MANL_SIZE 64
+
+#define LDBL_TO_ARRAY32(u, a) do { \
+ (a)[0] = (uint32_t)(u).bits.manl; \
+ (a)[1] = (uint32_t)((u).bits.manl >> 32); \
+ (a)[2] = (uint32_t)(u).bits.manh; \
+ (a)[3] = (uint32_t)((u).bits.manh >> 32); \
+} while(0)
diff --git a/lib/libc/aarch64/arith.h b/lib/libc/aarch64/arith.h
new file mode 100644
index 000000000000..ecb1a33fccb0
--- /dev/null
+++ b/lib/libc/aarch64/arith.h
@@ -0,0 +1,19 @@
+/*
+ * MD header for contrib/gdtoa
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * NOTE: The definitions in this file must be correct or strtod(3) and
+ * floating point formats in printf(3) will break! The file can be
+ * generated by running contrib/gdtoa/arithchk.c on the target
+ * architecture. See contrib/gdtoa/gdtoaimp.h for details.
+ */
+
+#define IEEE_8087
+#define Arith_Kind_ASL 1
+#define Long int
+#define Intcast (int)(long)
+#define Double_Align
+#define X64_bit_pointers
diff --git a/lib/libc/aarch64/gd_qnan.h b/lib/libc/aarch64/gd_qnan.h
new file mode 100644
index 000000000000..27e8d5811b7e
--- /dev/null
+++ b/lib/libc/aarch64/gd_qnan.h
@@ -0,0 +1,21 @@
+/*
+ * MD header for contrib/gdtoa
+ *
+ * This file can be generated by compiling and running contrib/gdtoa/qnan.c
+ * on the target architecture after arith.h has been generated.
+ *
+ * $FreeBSD$
+ */
+
+#define f_QNAN 0x7fc00000
+#define d_QNAN0 0x0
+#define d_QNAN1 0x7ff80000
+#define ld_QNAN0 0x0
+#define ld_QNAN1 0x0
+#define ld_QNAN2 0x0
+#define ld_QNAN3 0x7fff8000
+#define ldus_QNAN0 0x0
+#define ldus_QNAN1 0x0
+#define ldus_QNAN2 0x0
+#define ldus_QNAN3 0x0
+#define ldus_QNAN4 0x0
diff --git a/lib/libc/aarch64/gen/Makefile.inc b/lib/libc/aarch64/gen/Makefile.inc
new file mode 100644
index 000000000000..fe39136f5b41
--- /dev/null
+++ b/lib/libc/aarch64/gen/Makefile.inc
@@ -0,0 +1,17 @@
+# $FreeBSD$
+
+CFLAGS+= -DNO_COMPAT7
+
+SRCS+= _ctx_start.S \
+ fabs.S \
+ flt_rounds.c \
+ fpgetmask.c \
+ fpsetmask.c \
+ infinity.c \
+ ldexp.c \
+ makecontext.c \
+ _setjmp.S \
+ _set_tp.c \
+ setjmp.S \
+ sigsetjmp.S \
+ trivial-getcontextx.c
diff --git a/lib/libc/aarch64/gen/_ctx_start.S b/lib/libc/aarch64/gen/_ctx_start.S
new file mode 100644
index 000000000000..8664f69667c3
--- /dev/null
+++ b/lib/libc/aarch64/gen/_ctx_start.S
@@ -0,0 +1,38 @@
+/*-
+ * Copyright (c) 2015 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Andrew Turner under
+ * sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+ENTRY(_ctx_start)
+ blr x19 /* Call func from makecontext */
+ mov x0, x20 /* Load ucp saved in makecontext */
+ bl _C_LABEL(ctx_done)
+ bl _C_LABEL(abort)
+END(_ctx_start)
diff --git a/lib/libc/aarch64/gen/_set_tp.c b/lib/libc/aarch64/gen/_set_tp.c
new file mode 100644
index 000000000000..871acb3001a3
--- /dev/null
+++ b/lib/libc/aarch64/gen/_set_tp.c
@@ -0,0 +1,43 @@
+/*-
+ * Copyright (c) 2014 Andrew Turner
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <string.h>
+#include <sys/types.h>
+
+#include <machine/sysarch.h>
+
+#include <stdlib.h>
+#include "libc_private.h"
+
+void
+_set_tp(void *tp)
+{
+
+ asm volatile("msr tpidr_el0, %0" : : "r"(tp));
+}
diff --git a/lib/libc/aarch64/gen/_setjmp.S b/lib/libc/aarch64/gen/_setjmp.S
new file mode 100644
index 000000000000..ae00195d3ff7
--- /dev/null
+++ b/lib/libc/aarch64/gen/_setjmp.S
@@ -0,0 +1,105 @@
+/*-
+ * Copyright (c) 2014 Andrew Turner
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Andrew Turner
+ * under sponsorship from the FreeBSD Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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$");
+
+#include <machine/setjmp.h>
+
+ENTRY(_setjmp)
+ /* Store the magic value and stack pointer */
+ ldr x8, .Lmagic
+ mov x9, sp
+ stp x8, x9, [x0], #16
+
+ /* Store the general purpose registers and lr */
+ stp x19, x20, [x0], #16
+ stp x21, x22, [x0], #16
+ stp x23, x24, [x0], #16
+ stp x25, x26, [x0], #16
+ stp x27, x28, [x0], #16
+ stp x29, lr, [x0], #16
+
+#ifndef _STANDALONE
+ /* Store the vfp registers */
+ stp d8, d9, [x0], #16
+ stp d10, d11, [x0], #16
+ stp d12, d13, [x0], #16
+ stp d14, d15, [x0]
+#endif
+
+ /* Return value */
+ mov x0, #0
+ ret
+ .align 3
+.Lmagic:
+ .quad _JB_MAGIC__SETJMP
+END(_setjmp)
+
+ENTRY(_longjmp)
+ /* Check the magic value */
+ ldr x8, [x0], #8
+ ldr x9, .Lmagic
+ cmp x8, x9
+ b.ne botch
+
+ /* Restore the stack pointer */
+ ldr x8, [x0], #8
+ mov sp, x8
+
+ /* Restore the general purpose registers and lr */
+ ldp x19, x20, [x0], #16
+ ldp x21, x22, [x0], #16
+ ldp x23, x24, [x0], #16
+ ldp x25, x26, [x0], #16
+ ldp x27, x28, [x0], #16
+ ldp x29, lr, [x0], #16
+
+#ifndef _STANDALONE
+ /* Restore the vfp registers */
+ ldp d8, d9, [x0], #16
+ ldp d10, d11, [x0], #16
+ ldp d12, d13, [x0], #16
+ ldp d14, d15, [x0]
+#endif
+
+ /* Load the return value */
+ mov x0, x1
+ ret
+
+botch:
+#ifdef _STANDALONE
+ b botch
+#else
+ bl _C_LABEL(longjmperror)
+ bl _C_LABEL(abort)
+#endif
+END(_longjmp)
diff --git a/lib/libc/aarch64/gen/fabs.S b/lib/libc/aarch64/gen/fabs.S
new file mode 100644
index 000000000000..2f5fd06dec6c
--- /dev/null
+++ b/lib/libc/aarch64/gen/fabs.S
@@ -0,0 +1,33 @@
+/*-
+ * Copyright (c) 2015 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+ENTRY(fabs)
+ fabs d0, d0
+ ret
+END(fabs)
diff --git a/lib/libc/aarch64/gen/flt_rounds.c b/lib/libc/aarch64/gen/flt_rounds.c
new file mode 100644
index 000000000000..6f8eeebbad80
--- /dev/null
+++ b/lib/libc/aarch64/gen/flt_rounds.c
@@ -0,0 +1,49 @@
+/*-
+ * Copyright (c) 2012 Ian Lepore <freebsd@damnhippie.dyndns.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+#include <fenv.h>
+#include <float.h>
+
+static int map[] = {
+ 1, /* round to nearest */
+ 2, /* round to positive infinity */
+ 3, /* round to negative infinity */
+ 0 /* round to zero */
+};
+
+int
+__flt_rounds(void)
+{
+ uint64_t fpcr;
+
+ asm volatile("mrs %0, fpcr" : "=r" (fpcr));
+ return map[(fpcr >> 22) & 3];
+}
diff --git a/lib/libc/aarch64/gen/fpgetmask.c b/lib/libc/aarch64/gen/fpgetmask.c
new file mode 100644
index 000000000000..afc05b479a44
--- /dev/null
+++ b/lib/libc/aarch64/gen/fpgetmask.c
@@ -0,0 +1,47 @@
+/*-
+ * Copyright (c) 2015 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Andrew Turner under
+ * sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <ieeefp.h>
+
+#define FP_X_MASK (FP_X_INV | FP_X_DZ | FP_X_OFL | FP_X_UFL | FP_X_IMP)
+
+fp_except_t
+fpgetmask(void)
+{
+ uint64_t mask;
+
+ /* Read the current mask */
+ __asm __volatile("mrs %0, fpcr" : "=&r"(mask));
+
+ return (mask & FP_X_MASK);
+}
diff --git a/lib/libc/aarch64/gen/fpsetmask.c b/lib/libc/aarch64/gen/fpsetmask.c
new file mode 100644
index 000000000000..de9ac043b472
--- /dev/null
+++ b/lib/libc/aarch64/gen/fpsetmask.c
@@ -0,0 +1,52 @@
+/*-
+ * Copyright (c) 2015 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Andrew Turner under
+ * sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <ieeefp.h>
+
+#define FP_X_MASK (FP_X_INV | FP_X_DZ | FP_X_OFL | FP_X_UFL | FP_X_IMP)
+
+fp_except_t
+fpsetmask(fp_except_t mask)
+{
+ uint64_t old, new;
+
+ mask &= FP_X_MASK;
+
+ /* Read the current mask */
+ __asm __volatile("mrs %0, fpcr" : "=&r"(old));
+ new = old & ~FP_X_MASK;
+ new |= mask;
+ __asm __volatile("msr fpcr, %0" :: "r"(new));
+
+ return ((fp_except_t)old);
+}
diff --git a/lib/libc/aarch64/gen/infinity.c b/lib/libc/aarch64/gen/infinity.c
new file mode 100644
index 000000000000..c96045e581b6
--- /dev/null
+++ b/lib/libc/aarch64/gen/infinity.c
@@ -0,0 +1,14 @@
+/*
+ * infinity.c
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <math.h>
+
+/* bytes for +Infinity on aarch64 */
+const union __infinity_un __infinity = { { 0, 0, 0, 0, 0, 0, 0xf0, 0x7f } };
+
+/* bytes for NaN */
+const union __nan_un __nan = { { 0, 0, 0xc0, 0xff } };
diff --git a/lib/libc/aarch64/gen/makecontext.c b/lib/libc/aarch64/gen/makecontext.c
new file mode 100644
index 000000000000..747d2c53b198
--- /dev/null
+++ b/lib/libc/aarch64/gen/makecontext.c
@@ -0,0 +1,86 @@
+/*-
+ * Copyright (c) 2015 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Andrew Turner under
+ * sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+
+#include <machine/armreg.h>
+
+#include <inttypes.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <ucontext.h>
+
+void _ctx_start(void);
+
+void
+ctx_done(ucontext_t *ucp)
+{
+
+ if (ucp->uc_link == NULL) {
+ exit(0);
+ } else {
+ setcontext((const ucontext_t *)ucp->uc_link);
+ abort();
+ }
+}
+
+__weak_reference(__makecontext, makecontext);
+
+void
+__makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...)
+{
+ struct gpregs *gp;
+ va_list ap;
+ int i;
+
+ /* A valid context is required. */
+ if (ucp == NULL)
+ return;
+
+ if ((argc < 0) || (argc > 8))
+ return;
+
+ gp = &ucp->uc_mcontext.mc_gpregs;
+
+ va_start(ap, argc);
+ /* Pass up to eight arguments in x0-7. */
+ for (i = 0; i < argc && i < 8; i++)
+ gp->gp_x[i] = va_arg(ap, uint64_t);
+ va_end(ap);
+
+ /* Set the stack */
+ gp->gp_sp = STACKALIGN(ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size);
+ /* Arrange for return via the trampoline code. */
+ gp->gp_elr = (__register_t)_ctx_start;
+ gp->gp_x[19] = (__register_t)func;
+ gp->gp_x[20] = (__register_t)ucp;
+}
diff --git a/lib/libc/aarch64/gen/setjmp.S b/lib/libc/aarch64/gen/setjmp.S
new file mode 100644
index 000000000000..a30ed6a3082a
--- /dev/null
+++ b/lib/libc/aarch64/gen/setjmp.S
@@ -0,0 +1,123 @@
+/*-
+ * Copyright (c) 2014 Andrew Turner
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Andrew Turner
+ * under sponsorship from the FreeBSD Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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$");
+
+#include <machine/setjmp.h>
+
+ENTRY(setjmp)
+ sub sp, sp, #16
+ stp x0, lr, [sp]
+
+ /* Store the signal mask */
+ add x2, x0, #(_JB_SIGMASK * 8) /* oset */
+ mov x1, #0 /* set */
+ mov x0, #1 /* SIG_BLOCK */
+ bl sigprocmask
+
+ ldp x0, lr, [sp]
+ add sp, sp, #16
+
+ /* Store the magic value and stack pointer */
+ ldr x8, .Lmagic
+ mov x9, sp
+ stp x8, x9, [x0], #16
+
+ /* Store the general purpose registers and lr */
+ stp x19, x20, [x0], #16
+ stp x21, x22, [x0], #16
+ stp x23, x24, [x0], #16
+ stp x25, x26, [x0], #16
+ stp x27, x28, [x0], #16
+ stp x29, lr, [x0], #16
+
+ /* Store the vfp registers */
+ stp d8, d9, [x0], #16
+ stp d10, d11, [x0], #16
+ stp d12, d13, [x0], #16
+ stp d14, d15, [x0]
+
+ /* Return value */
+ mov x0, #0
+ ret
+ .align 3
+.Lmagic:
+ .quad _JB_MAGIC_SETJMP
+END(setjmp)
+
+ENTRY(longjmp)
+ sub sp, sp, #32
+ stp x0, lr, [sp]
+ str x1, [sp, #16]
+
+ /* Restore the signal mask */
+ mov x2, #0 /* oset */
+ add x1, x0, #(_JB_SIGMASK * 8) /* set */
+ mov x0, #3 /* SIG_BLOCK */
+ bl sigprocmask
+
+ ldr x1, [sp, #16]
+ ldp x0, lr, [sp]
+ add sp, sp, #32
+
+ /* Check the magic value */
+ ldr x8, [x0], #8
+ ldr x9, .Lmagic
+ cmp x8, x9
+ b.ne botch
+
+ /* Restore the stack pointer */
+ ldr x8, [x0], #8
+ mov sp, x8
+
+ /* Restore the general purpose registers and lr */
+ ldp x19, x20, [x0], #16
+ ldp x21, x22, [x0], #16
+ ldp x23, x24, [x0], #16
+ ldp x25, x26, [x0], #16
+ ldp x27, x28, [x0], #16
+ ldp x29, lr, [x0], #16
+
+ /* Restore the vfp registers */
+ ldp d8, d9, [x0], #16
+ ldp d10, d11, [x0], #16
+ ldp d12, d13, [x0], #16
+ ldp d14, d15, [x0]
+
+ /* Load the return value */
+ mov x0, x1
+ ret
+
+botch:
+ bl _C_LABEL(longjmperror)
+ bl _C_LABEL(abort)
+END(longjmp)
diff --git a/lib/libc/aarch64/gen/sigsetjmp.S b/lib/libc/aarch64/gen/sigsetjmp.S
new file mode 100644
index 000000000000..be49f5343871
--- /dev/null
+++ b/lib/libc/aarch64/gen/sigsetjmp.S
@@ -0,0 +1,53 @@
+/*-
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Andrew Turner under
+ * sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include <machine/setjmp.h>
+
+ENTRY(sigsetjmp)
+ cmp x1, #0
+ b.eq _C_LABEL(_setjmp)
+ b _C_LABEL(setjmp)
+END(sigsetjmp)
+
+ENTRY(siglongjmp)
+ /* Load the _setjmp magic */
+ ldr x2, .Lmagic
+ ldr x3, [x0]
+
+ /* Check the magic */
+ cmp x2, x3
+ b.eq _C_LABEL(_longjmp)
+ b _C_LABEL(longjmp)
+ .align 3
+.Lmagic:
+ .quad _JB_MAGIC__SETJMP
+END(siglongjmp)
diff --git a/lib/libc/aarch64/string/Makefile.inc b/lib/libc/aarch64/string/Makefile.inc
new file mode 100644
index 000000000000..b247c1c28d9c
--- /dev/null
+++ b/lib/libc/aarch64/string/Makefile.inc
@@ -0,0 +1,19 @@
+# $FreeBSD$
+#
+# String handling from the Cortex Strings library
+# https://git.linaro.org/toolchain/cortex-strings.git
+#
+
+.PATH: ${SRCTOP}/contrib/cortex-strings/src/aarch64
+
+MDSRCS+=memchr.S \
+ memcmp.S \
+ memcpy.S \
+ memmove.S \
+ memset.S \
+ strchr.S \
+ strcmp.S \
+ strcpy.S \
+ strlen.S \
+ strncmp.S \
+ strnlen.S
diff --git a/lib/libc/aarch64/sys/Makefile.inc b/lib/libc/aarch64/sys/Makefile.inc
new file mode 100644
index 000000000000..60f9a98eea5c
--- /dev/null
+++ b/lib/libc/aarch64/sys/Makefile.inc
@@ -0,0 +1,15 @@
+# $FreeBSD$
+
+MIASM:= ${MIASM:Nfreebsd[467]_*}
+
+SRCS+= __vdso_gettc.c
+
+MDASM= cerror.S \
+ shmat.S \
+ sigreturn.S \
+ syscall.S \
+ vfork.S
+
+# Don't generate default code for these syscalls:
+NOASM+= sbrk.o \
+ vfork.o
diff --git a/lib/libc/aarch64/sys/__vdso_gettc.c b/lib/libc/aarch64/sys/__vdso_gettc.c
new file mode 100644
index 000000000000..85e1b2e23cd3
--- /dev/null
+++ b/lib/libc/aarch64/sys/__vdso_gettc.c
@@ -0,0 +1,76 @@
+/*-
+ * Copyright (c) 2015 The FreeBSD Foundation
+ *
+ * This software was developed by Konstantin Belousov
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/elf.h>
+#include <sys/time.h>
+#include <sys/vdso.h>
+#include <machine/cpufunc.h>
+#include <errno.h>
+#include "libc_private.h"
+
+static inline uint64_t
+cp15_cntvct_get(void)
+{
+ uint64_t reg;
+
+ __asm __volatile("mrs %0, cntvct_el0" : "=r" (reg));
+ return (reg);
+}
+
+static inline uint64_t
+cp15_cntpct_get(void)
+{
+ uint64_t reg;
+
+ __asm __volatile("mrs %0, cntpct_el0" : "=r" (reg));
+ return (reg);
+}
+
+#pragma weak __vdso_gettc
+int
+__vdso_gettc(const struct vdso_timehands *th, u_int *tc)
+{
+
+ if (th->th_algo != VDSO_TH_ALGO_ARM_GENTIM)
+ return (ENOSYS);
+ __asm __volatile("isb" : : : "memory");
+ *tc = th->th_physical == 0 ? cp15_cntvct_get() : cp15_cntpct_get();
+ return (0);
+}
+
+#pragma weak __vdso_gettimekeep
+int
+__vdso_gettimekeep(struct vdso_timekeep **tk)
+{
+
+ return (_elf_aux_info(AT_TIMEKEEP, tk, sizeof(*tk)));
+}
diff --git a/lib/libc/aarch64/sys/cerror.S b/lib/libc/aarch64/sys/cerror.S
new file mode 100644
index 000000000000..7e1627dc8ab8
--- /dev/null
+++ b/lib/libc/aarch64/sys/cerror.S
@@ -0,0 +1,42 @@
+/*-
+ * 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$");
+
+ENTRY(cerror)
+ .hidden cerror
+ sub sp, sp, #16
+ stp x0, lr, [sp]
+ bl _C_LABEL(__error)
+ ldp x1, lr, [sp]
+ str w1, [x0]
+ movn x0, #0
+ movn x1, #0
+ add sp, sp, #16
+ ret
+END(cerror)
diff --git a/lib/libc/aarch64/sys/shmat.S b/lib/libc/aarch64/sys/shmat.S
new file mode 100644
index 000000000000..c0fb34f74c8f
--- /dev/null
+++ b/lib/libc/aarch64/sys/shmat.S
@@ -0,0 +1,35 @@
+/*-
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Andrew Turner under
+ * sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+RSYSCALL(shmat)
diff --git a/lib/libc/aarch64/sys/sigreturn.S b/lib/libc/aarch64/sys/sigreturn.S
new file mode 100644
index 000000000000..21ec1e456f5a
--- /dev/null
+++ b/lib/libc/aarch64/sys/sigreturn.S
@@ -0,0 +1,35 @@
+/*-
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Andrew Turner under
+ * sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+RSYSCALL(sigreturn)
diff --git a/lib/libc/aarch64/sys/syscall.S b/lib/libc/aarch64/sys/syscall.S
new file mode 100644
index 000000000000..63148357d567
--- /dev/null
+++ b/lib/libc/aarch64/sys/syscall.S
@@ -0,0 +1,35 @@
+/*-
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Andrew Turner under
+ * sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+RSYSCALL(syscall)
diff --git a/lib/libc/aarch64/sys/vfork.S b/lib/libc/aarch64/sys/vfork.S
new file mode 100644
index 000000000000..daecd1f04a33
--- /dev/null
+++ b/lib/libc/aarch64/sys/vfork.S
@@ -0,0 +1,42 @@
+/*-
+ * 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$");
+#include "SYS.h"
+
+ENTRY(__sys_vfork)
+ WEAK_REFERENCE(__sys_vfork, vfork)
+ WEAK_REFERENCE(__sys_vfork, _vfork)
+ mov x2, lr
+ _SYSCALL(vfork)
+ b.cs cerror
+ sub x1, x1, #1
+ and x0, x0, x1
+ mov lr, x2
+ ret
+END(__sys_vfork)
diff --git a/lib/libc/amd64/Makefile.inc b/lib/libc/amd64/Makefile.inc
new file mode 100644
index 000000000000..95fddefab933
--- /dev/null
+++ b/lib/libc/amd64/Makefile.inc
@@ -0,0 +1,9 @@
+# $FreeBSD$
+#
+# Machine dependent definitions for the amd64 architecture.
+#
+
+# Long double is 80 bits
+GDTOASRCS+=strtorx.c
+MDSRCS+=machdep_ldisx.c
+SYM_MAPS+=${LIBC_SRCTOP}/amd64/Symbol.map
diff --git a/lib/libc/amd64/SYS.h b/lib/libc/amd64/SYS.h
new file mode 100644
index 000000000000..3d9108e062af
--- /dev/null
+++ b/lib/libc/amd64/SYS.h
@@ -0,0 +1,52 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)SYS.h 5.5 (Berkeley) 5/7/91
+ * $FreeBSD$
+ */
+
+#include <sys/syscall.h>
+#include <machine/asm.h>
+
+#define RSYSCALL(name) ENTRY(__sys_##name); \
+ WEAK_REFERENCE(__sys_##name, name); \
+ WEAK_REFERENCE(__sys_##name, _##name); \
+ mov $SYS_##name,%eax; KERNCALL; \
+ jb HIDENAME(cerror); ret; \
+ END(__sys_##name)
+
+#define PSEUDO(name) ENTRY(__sys_##name); \
+ WEAK_REFERENCE(__sys_##name, _##name); \
+ mov $SYS_##name,%eax; KERNCALL; \
+ jb HIDENAME(cerror); ret; \
+ END(__sys_##name)
+
+#define KERNCALL movq %rcx, %r10; syscall
diff --git a/lib/libc/amd64/Symbol.map b/lib/libc/amd64/Symbol.map
new file mode 100644
index 000000000000..5354d66bcc38
--- /dev/null
+++ b/lib/libc/amd64/Symbol.map
@@ -0,0 +1,70 @@
+/*
+ * $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, ...).
+ */
+FBSD_1.0 {
+ /* PSEUDO syscalls */
+ _exit;
+
+ .mcount;
+ _setjmp;
+ _longjmp;
+ fabs;
+ __flt_rounds;
+ fpgetmask;
+ fpgetprec;
+ fpgetround;
+ fpgetsticky;
+ fpsetmask;
+ fpsetprec;
+ fpsetround;
+ __infinity;
+ __nan;
+ makecontext;
+ rfork_thread;
+ setjmp;
+ longjmp;
+ sigsetjmp;
+ siglongjmp;
+ htonl;
+ htons;
+ ntohl;
+ ntohs;
+ amd64_get_fsbase;
+ amd64_get_gsbase;
+ amd64_set_fsbase;
+ amd64_set_gsbase;
+ brk;
+ exect;
+ sbrk;
+ vfork;
+};
+
+/*
+ *
+ * FreeBSD private ABI
+ *
+ */
+FBSDprivate_1.0 {
+ /* PSEUDO syscalls */
+ __sys_getlogin;
+ _getlogin;
+ __sys_exit;
+
+ _set_tp;
+ ___longjmp;
+ __makecontext;
+ __longjmp;
+ __signalcontext;
+ signalcontext;
+ __siglongjmp;
+ _brk;
+ _end;
+ __sys_vfork;
+ _vfork;
+};
diff --git a/lib/libc/amd64/_fpmath.h b/lib/libc/amd64/_fpmath.h
new file mode 100644
index 000000000000..c2a73848d6a1
--- /dev/null
+++ b/lib/libc/amd64/_fpmath.h
@@ -0,0 +1,55 @@
+/*-
+ * Copyright (c) 2002, 2003 David Schultz <das@FreeBSD.ORG>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+union IEEEl2bits {
+ long double e;
+ struct {
+ unsigned int manl :32;
+ unsigned int manh :32;
+ unsigned int exp :15;
+ unsigned int sign :1;
+ unsigned int junkl :16;
+ unsigned int junkh :32;
+ } bits;
+ struct {
+ unsigned long man :64;
+ unsigned int expsign :16;
+ unsigned long junk :48;
+ } xbits;
+};
+
+#define LDBL_NBIT 0x80000000
+#define mask_nbit_l(u) ((u).bits.manh &= ~LDBL_NBIT)
+
+#define LDBL_MANH_SIZE 32
+#define LDBL_MANL_SIZE 32
+
+#define LDBL_TO_ARRAY32(u, a) do { \
+ (a)[0] = (uint32_t)(u).bits.manl; \
+ (a)[1] = (uint32_t)(u).bits.manh; \
+} while (0)
diff --git a/lib/libc/amd64/arith.h b/lib/libc/amd64/arith.h
new file mode 100644
index 000000000000..ecb1a33fccb0
--- /dev/null
+++ b/lib/libc/amd64/arith.h
@@ -0,0 +1,19 @@
+/*
+ * MD header for contrib/gdtoa
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * NOTE: The definitions in this file must be correct or strtod(3) and
+ * floating point formats in printf(3) will break! The file can be
+ * generated by running contrib/gdtoa/arithchk.c on the target
+ * architecture. See contrib/gdtoa/gdtoaimp.h for details.
+ */
+
+#define IEEE_8087
+#define Arith_Kind_ASL 1
+#define Long int
+#define Intcast (int)(long)
+#define Double_Align
+#define X64_bit_pointers
diff --git a/lib/libc/amd64/gd_qnan.h b/lib/libc/amd64/gd_qnan.h
new file mode 100644
index 000000000000..39923860db07
--- /dev/null
+++ b/lib/libc/amd64/gd_qnan.h
@@ -0,0 +1,21 @@
+/*
+ * MD header for contrib/gdtoa
+ *
+ * This file can be generated by compiling and running contrib/gdtoa/qnan.c
+ * on the target architecture after arith.h has been generated.
+ *
+ * $FreeBSD$
+ */
+
+#define f_QNAN 0x7fc00000
+#define d_QNAN0 0x0
+#define d_QNAN1 0x7ff80000
+#define ld_QNAN0 0x0
+#define ld_QNAN1 0xc0000000
+#define ld_QNAN2 0x7fff
+#define ld_QNAN3 0x0
+#define ldus_QNAN0 0x0
+#define ldus_QNAN1 0x0
+#define ldus_QNAN2 0x0
+#define ldus_QNAN3 0xc000
+#define ldus_QNAN4 0x7fff
diff --git a/lib/libc/amd64/gen/Makefile.inc b/lib/libc/amd64/gen/Makefile.inc
new file mode 100644
index 000000000000..fb4f7f4d30f0
--- /dev/null
+++ b/lib/libc/amd64/gen/Makefile.inc
@@ -0,0 +1,8 @@
+# @(#)Makefile.inc 8.1 (Berkeley) 6/4/93
+# $FreeBSD$
+
+SRCS+= _setjmp.S _set_tp.c rfork_thread.S setjmp.S sigsetjmp.S \
+ fabs.S getcontextx.c \
+ infinity.c ldexp.c makecontext.c signalcontext.c \
+ flt_rounds.c fpgetmask.c fpsetmask.c fpgetprec.c fpsetprec.c \
+ fpgetround.c fpsetround.c fpgetsticky.c
diff --git a/lib/libc/amd64/gen/_set_tp.c b/lib/libc/amd64/gen/_set_tp.c
new file mode 100644
index 000000000000..d5526fa51c01
--- /dev/null
+++ b/lib/libc/amd64/gen/_set_tp.c
@@ -0,0 +1,39 @@
+/*-
+ * Copyright (c) 2004 Doug Rabson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <string.h>
+#include <stdint.h>
+#include <machine/sysarch.h>
+#include "libc_private.h"
+
+void
+_set_tp(void *tp)
+{
+
+ amd64_set_fsbase(tp);
+}
diff --git a/lib/libc/amd64/gen/_setjmp.S b/lib/libc/amd64/gen/_setjmp.S
new file mode 100644
index 000000000000..57079a1d4d86
--- /dev/null
+++ b/lib/libc/amd64/gen/_setjmp.S
@@ -0,0 +1,95 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+ .asciz "@(#)_setjmp.s 5.1 (Berkeley) 4/23/90"
+#endif /* LIBC_SCCS and not lint */
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * C library -- _setjmp, _longjmp
+ *
+ * _longjmp(a,v)
+ * will generate a "return(v)" from the last call to
+ * _setjmp(a)
+ * by restoring registers from the environment 'a'.
+ * The previous signal state is NOT restored.
+ */
+
+ENTRY(_setjmp)
+ movq %rdi,%rax
+ movq 0(%rsp),%rdx /* retval */
+ movq %rdx, 0(%rax) /* 0; retval */
+ movq %rbx, 8(%rax) /* 1; rbx */
+ movq %rsp,16(%rax) /* 2; rsp */
+ movq %rbp,24(%rax) /* 3; rbp */
+ movq %r12,32(%rax) /* 4; r12 */
+ movq %r13,40(%rax) /* 5; r13 */
+ movq %r14,48(%rax) /* 6; r14 */
+ movq %r15,56(%rax) /* 7; r15 */
+ fnstcw 64(%rax) /* 8; fpu cw */
+ stmxcsr 68(%rax) /* and mxcsr */
+ xorq %rax,%rax
+ ret
+END(_setjmp)
+
+ WEAK_REFERENCE(___longjmp, _longjmp)
+ENTRY(___longjmp)
+ movq %rdi,%rdx
+ /* Restore the mxcsr, but leave exception flags intact. */
+ stmxcsr -4(%rsp)
+ movl 68(%rdx),%eax
+ andl $0xffffffc0,%eax
+ movl -4(%rsp),%edi
+ andl $0x3f,%edi
+ xorl %eax,%edi
+ movl %edi,-4(%rsp)
+ ldmxcsr -4(%rsp)
+ movq %rsi,%rax /* retval */
+ movq 0(%rdx),%rcx
+ movq 8(%rdx),%rbx
+ movq 16(%rdx),%rsp
+ movq 24(%rdx),%rbp
+ movq 32(%rdx),%r12
+ movq 40(%rdx),%r13
+ movq 48(%rdx),%r14
+ movq 56(%rdx),%r15
+ fldcw 64(%rdx)
+ testq %rax,%rax
+ jnz 1f
+ incq %rax
+1: movq %rcx,0(%rsp)
+ ret
+END(___longjmp)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/amd64/gen/fabs.S b/lib/libc/amd64/gen/fabs.S
new file mode 100644
index 000000000000..2ace0f9fb926
--- /dev/null
+++ b/lib/libc/amd64/gen/fabs.S
@@ -0,0 +1,46 @@
+/*-
+ * Copyright (c) 2004 Peter Wemm
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Return floating point absolute value of a double.
+ */
+
+ .text
+ENTRY(fabs)
+ movsd %xmm0, %xmm1
+ movsd signbit(%rip), %xmm0
+ andnpd %xmm1, %xmm0
+ ret
+END(fabs)
+
+ .data
+signbit:
+ .quad 0x8000000000000000
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/amd64/gen/flt_rounds.c b/lib/libc/amd64/gen/flt_rounds.c
new file mode 100644
index 000000000000..c0ce81f6dfa9
--- /dev/null
+++ b/lib/libc/amd64/gen/flt_rounds.c
@@ -0,0 +1,26 @@
+/*
+ * Written by J.T. Conklin, Apr 10, 1995
+ * Public domain.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <float.h>
+
+static const int map[] = {
+ 1, /* round to nearest */
+ 3, /* round to zero */
+ 2, /* round to negative infinity */
+ 0 /* round to positive infinity */
+};
+
+int
+__flt_rounds(void)
+{
+ int x;
+
+ /* Assume that the x87 and the SSE unit agree on the rounding mode. */
+ __asm("fnstcw %0" : "=m" (x));
+ return (map[(x >> 10) & 0x03]);
+}
diff --git a/lib/libc/amd64/gen/fpgetmask.c b/lib/libc/amd64/gen/fpgetmask.c
new file mode 100644
index 000000000000..03bb2741ef6a
--- /dev/null
+++ b/lib/libc/amd64/gen/fpgetmask.c
@@ -0,0 +1,8 @@
+/* $FreeBSD$ */
+#define __IEEEFP_NOINLINES__ 1
+#include <ieeefp.h>
+
+fp_except_t fpgetmask(void)
+{
+ return __fpgetmask();
+}
diff --git a/lib/libc/amd64/gen/fpgetprec.c b/lib/libc/amd64/gen/fpgetprec.c
new file mode 100644
index 000000000000..22d21480566a
--- /dev/null
+++ b/lib/libc/amd64/gen/fpgetprec.c
@@ -0,0 +1,8 @@
+/* $FreeBSD$ */
+#define __IEEEFP_NOINLINES__ 1
+#include <ieeefp.h>
+
+fp_prec_t fpgetprec(void)
+{
+ return __fpgetprec();
+}
diff --git a/lib/libc/amd64/gen/fpgetround.c b/lib/libc/amd64/gen/fpgetround.c
new file mode 100644
index 000000000000..9c066b149ca2
--- /dev/null
+++ b/lib/libc/amd64/gen/fpgetround.c
@@ -0,0 +1,8 @@
+/* $FreeBSD$ */
+#define __IEEEFP_NOINLINES__ 1
+#include <ieeefp.h>
+
+fp_rnd_t fpgetround(void)
+{
+ return __fpgetround();
+}
diff --git a/lib/libc/amd64/gen/fpgetsticky.c b/lib/libc/amd64/gen/fpgetsticky.c
new file mode 100644
index 000000000000..c3acb91d63e5
--- /dev/null
+++ b/lib/libc/amd64/gen/fpgetsticky.c
@@ -0,0 +1,8 @@
+/* $FreeBSD$ */
+#define __IEEEFP_NOINLINES__ 1
+#include <ieeefp.h>
+
+fp_except_t fpgetsticky(void)
+{
+ return __fpgetsticky();
+}
diff --git a/lib/libc/amd64/gen/fpsetmask.c b/lib/libc/amd64/gen/fpsetmask.c
new file mode 100644
index 000000000000..996e167ac1d9
--- /dev/null
+++ b/lib/libc/amd64/gen/fpsetmask.c
@@ -0,0 +1,8 @@
+/* $FreeBSD$ */
+#define __IEEEFP_NOINLINES__ 1
+#include <ieeefp.h>
+
+fp_except_t fpsetmask(fp_except_t m)
+{
+ return (__fpsetmask(m));
+}
diff --git a/lib/libc/amd64/gen/fpsetprec.c b/lib/libc/amd64/gen/fpsetprec.c
new file mode 100644
index 000000000000..5898de7e0e82
--- /dev/null
+++ b/lib/libc/amd64/gen/fpsetprec.c
@@ -0,0 +1,8 @@
+/* $FreeBSD$ */
+#define __IEEEFP_NOINLINES__ 1
+#include <ieeefp.h>
+
+fp_prec_t fpsetprec(fp_prec_t m)
+{
+ return (__fpsetprec(m));
+}
diff --git a/lib/libc/amd64/gen/fpsetround.c b/lib/libc/amd64/gen/fpsetround.c
new file mode 100644
index 000000000000..6f13367510d6
--- /dev/null
+++ b/lib/libc/amd64/gen/fpsetround.c
@@ -0,0 +1,8 @@
+/* $FreeBSD$ */
+#define __IEEEFP_NOINLINES__ 1
+#include <ieeefp.h>
+
+fp_rnd_t fpsetround(fp_rnd_t m)
+{
+ return (__fpsetround(m));
+}
diff --git a/lib/libc/amd64/gen/getcontextx.c b/lib/libc/amd64/gen/getcontextx.c
new file mode 100644
index 000000000000..749bfbda0c51
--- /dev/null
+++ b/lib/libc/amd64/gen/getcontextx.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2011 Konstantin Belousov <kib@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/ucontext.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <machine/cpufunc.h>
+#include <machine/fpu.h>
+#include <machine/specialreg.h>
+#include <machine/sysarch.h>
+
+static int xstate_sz = -1;
+
+int
+__getcontextx_size(void)
+{
+ u_int p[4];
+
+ if (xstate_sz == -1) {
+ do_cpuid(1, p);
+ if ((p[2] & CPUID2_OSXSAVE) != 0) {
+ cpuid_count(0xd, 0x0, p);
+ xstate_sz = p[1] - sizeof(struct savefpu);
+ } else
+ xstate_sz = 0;
+ }
+
+ return (sizeof(ucontext_t) + xstate_sz);
+}
+
+int
+__fillcontextx2(char *ctx)
+{
+ struct amd64_get_xfpustate xfpu;
+ ucontext_t *ucp;
+
+ ucp = (ucontext_t *)ctx;
+ if (xstate_sz != 0) {
+ xfpu.addr = (char *)(ucp + 1);
+ xfpu.len = xstate_sz;
+ if (sysarch(AMD64_GET_XFPUSTATE, &xfpu) == -1)
+ return (-1);
+ ucp->uc_mcontext.mc_xfpustate = (__register_t)xfpu.addr;
+ ucp->uc_mcontext.mc_xfpustate_len = xstate_sz;
+ ucp->uc_mcontext.mc_flags |= _MC_HASFPXSTATE;
+ } else {
+ ucp->uc_mcontext.mc_xfpustate = 0;
+ ucp->uc_mcontext.mc_xfpustate_len = 0;
+ }
+ return (0);
+}
+
+int
+__fillcontextx(char *ctx)
+{
+ ucontext_t *ucp;
+
+ ucp = (ucontext_t *)ctx;
+ if (getcontext(ucp) == -1)
+ return (-1);
+ __fillcontextx2(ctx);
+ return (0);
+}
+
+__weak_reference(__getcontextx, getcontextx);
+
+ucontext_t *
+__getcontextx(void)
+{
+ char *ctx;
+ int error;
+
+ ctx = malloc(__getcontextx_size());
+ if (ctx == NULL)
+ return (NULL);
+ if (__fillcontextx(ctx) == -1) {
+ error = errno;
+ free(ctx);
+ errno = error;
+ return (NULL);
+ }
+ return ((ucontext_t *)ctx);
+}
diff --git a/lib/libc/amd64/gen/infinity.c b/lib/libc/amd64/gen/infinity.c
new file mode 100644
index 000000000000..464b4029b35a
--- /dev/null
+++ b/lib/libc/amd64/gen/infinity.c
@@ -0,0 +1,14 @@
+/*
+ * infinity.c
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <math.h>
+
+/* bytes for +Infinity on a 387 */
+const union __infinity_un __infinity = { { 0, 0, 0, 0, 0, 0, 0xf0, 0x7f } };
+
+/* bytes for NaN */
+const union __nan_un __nan = { { 0, 0, 0xc0, 0xff } };
diff --git a/lib/libc/amd64/gen/makecontext.c b/lib/libc/amd64/gen/makecontext.c
new file mode 100644
index 000000000000..15f10b50ded4
--- /dev/null
+++ b/lib/libc/amd64/gen/makecontext.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2003 Marcel Moolenaar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/ucontext.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+typedef void (*func_t)(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t,
+ uint64_t);
+
+/* Prototypes */
+static void makectx_wrapper(ucontext_t *ucp, func_t func, uint64_t *args);
+
+__weak_reference(__makecontext, makecontext);
+
+void
+__makecontext(ucontext_t *ucp, void (*start)(void), int argc, ...)
+{
+ uint64_t *args;
+ uint64_t *sp;
+ va_list ap;
+ int i;
+
+ /* A valid context is required. */
+ if ((ucp == NULL) || (ucp->uc_mcontext.mc_len != sizeof(mcontext_t)))
+ return;
+ else if ((argc < 0) || (argc > 6) || (ucp->uc_stack.ss_sp == NULL) ||
+ (ucp->uc_stack.ss_size < MINSIGSTKSZ)) {
+ /*
+ * This should really return -1 with errno set to ENOMEM
+ * or something, but the spec says that makecontext is
+ * a void function. At least make sure that the context
+ * isn't valid so it can't be used without an error.
+ */
+ ucp->uc_mcontext.mc_len = 0;
+ return;
+ }
+
+ /* Align the stack to 16 bytes. */
+ sp = (uint64_t *)(ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size);
+ sp = (uint64_t *)((uint64_t)sp & ~15UL);
+
+ /* Allocate space for a maximum of 6 arguments on the stack. */
+ args = sp - 6;
+
+ /*
+ * Account for arguments on stack and do the funky C entry alignment.
+ * This means that we need an 8-byte-odd alignment since the ABI expects
+ * the return address to be pushed, thus breaking the 16 byte alignment.
+ */
+ sp -= 7;
+
+ /* Add the arguments: */
+ va_start(ap, argc);
+ for (i = 0; i < argc; i++)
+ args[i] = va_arg(ap, uint64_t);
+ va_end(ap);
+ for (i = argc; i < 6; i++)
+ args[i] = 0;
+
+ ucp->uc_mcontext.mc_rdi = (register_t)ucp;
+ ucp->uc_mcontext.mc_rsi = (register_t)start;
+ ucp->uc_mcontext.mc_rdx = (register_t)args;
+ ucp->uc_mcontext.mc_rbp = 0;
+ ucp->uc_mcontext.mc_rbx = (register_t)sp;
+ ucp->uc_mcontext.mc_rsp = (register_t)sp;
+ ucp->uc_mcontext.mc_rip = (register_t)makectx_wrapper;
+}
+
+static void
+makectx_wrapper(ucontext_t *ucp, func_t func, uint64_t *args)
+{
+ (*func)(args[0], args[1], args[2], args[3], args[4], args[5]);
+ if (ucp->uc_link == NULL)
+ exit(0);
+ setcontext((const ucontext_t *)ucp->uc_link);
+ /* should never get here */
+ abort();
+ /* NOTREACHED */
+}
diff --git a/lib/libc/amd64/gen/rfork_thread.S b/lib/libc/amd64/gen/rfork_thread.S
new file mode 100644
index 000000000000..5e764db831f5
--- /dev/null
+++ b/lib/libc/amd64/gen/rfork_thread.S
@@ -0,0 +1,99 @@
+/*-
+ * Copyright (c) 2000 Peter Wemm <peter@FreeBSD.org>
+ * Copyright (c) 2003 Alan L. Cox <alc@cs.rice.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * With thanks to John Dyson for the original version of this.
+ */
+
+#include <SYS.h>
+
+/*
+ * %edi %rsi %rdx %rcx
+ * rfork_thread(flags, stack_addr, start_fnc, start_arg);
+ *
+ * flags: Flags to rfork system call. See rfork(2).
+ * stack_addr: Top of stack for thread.
+ * start_fnc: Address of thread function to call in child.
+ * start_arg: Argument to pass to the thread function in child.
+ */
+
+ENTRY(rfork_thread)
+ pushq %rbx
+ pushq %r12
+ movq %rdx, %rbx
+ movq %rcx, %r12
+
+ /*
+ * Prepare and execute the thread creation syscall
+ */
+ movq $SYS_rfork, %rax
+ KERNCALL
+ jb 2f
+
+ /*
+ * Check to see if we are in the parent or child
+ */
+ cmpl $0, %edx
+ jnz 1f
+ popq %r12
+ popq %rbx
+ ret
+
+ /*
+ * If we are in the child (new thread), then
+ * set-up the call to the internal subroutine. If it
+ * returns, then call __exit.
+ */
+1:
+ movq %rsi, %rsp
+ movq %r12, %rdi
+ call *%rbx
+ movl %eax, %edi
+
+ /*
+ * Exit system call
+ */
+#ifdef SYS_exit
+ movq $SYS_exit, %rax
+#else
+ movq $SYS_sys_exit, %rax
+#endif
+ KERNCALL
+
+ /*
+ * Branch here if the thread creation fails:
+ */
+2:
+ popq %r12
+ popq %rbx
+ jmp HIDENAME(cerror)
+END(rfork_thread)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/amd64/gen/setjmp.S b/lib/libc/amd64/gen/setjmp.S
new file mode 100644
index 000000000000..826220e8bb55
--- /dev/null
+++ b/lib/libc/amd64/gen/setjmp.S
@@ -0,0 +1,116 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+ .asciz "@(#)setjmp.s 5.1 (Berkeley) 4/23/90"
+#endif /* LIBC_SCCS and not lint */
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * C library -- _setjmp, _longjmp
+ *
+ * longjmp(a,v)
+ * will generate a "return(v)" from the last call to
+ * setjmp(a)
+ * by restoring registers from the environment 'a'.
+ * The previous signal state is restored.
+ */
+
+#include "SYS.h"
+
+ENTRY(setjmp)
+ pushq %rdi
+ movq %rdi,%rcx
+ movq $1,%rdi /* SIG_BLOCK */
+ movq $0,%rsi /* (sigset_t*)set */
+ leaq 72(%rcx),%rdx /* 9,10; (sigset_t*)oset */
+ /* stack is 16-byte aligned */
+ call __libc_sigprocmask
+ popq %rdi
+ movq %rdi,%rcx
+ movq 0(%rsp),%rdx /* retval */
+ movq %rdx, 0(%rcx) /* 0; retval */
+ movq %rbx, 8(%rcx) /* 1; rbx */
+ movq %rsp,16(%rcx) /* 2; rsp */
+ movq %rbp,24(%rcx) /* 3; rbp */
+ movq %r12,32(%rcx) /* 4; r12 */
+ movq %r13,40(%rcx) /* 5; r13 */
+ movq %r14,48(%rcx) /* 6; r14 */
+ movq %r15,56(%rcx) /* 7; r15 */
+ fnstcw 64(%rcx) /* 8; fpu cw */
+ stmxcsr 68(%rcx) /* and mxcsr */
+ xorq %rax,%rax
+ ret
+END(setjmp)
+
+ WEAK_REFERENCE(__longjmp, longjmp)
+ENTRY(__longjmp)
+ pushq %rdi
+ pushq %rsi
+ movq %rdi,%rdx
+ movq $3,%rdi /* SIG_SETMASK */
+ leaq 72(%rdx),%rsi /* (sigset_t*)set */
+ movq $0,%rdx /* (sigset_t*)oset */
+ subq $0x8,%rsp /* make the stack 16-byte aligned */
+ call __libc_sigprocmask
+ addq $0x8,%rsp
+ popq %rsi
+ popq %rdi /* jmpbuf */
+ movq %rdi,%rdx
+ /* Restore the mxcsr, but leave exception flags intact. */
+ stmxcsr -4(%rsp)
+ movl 68(%rdx),%eax
+ andl $0xffffffc0,%eax
+ movl -4(%rsp),%edi
+ andl $0x3f,%edi
+ xorl %eax,%edi
+ movl %edi,-4(%rsp)
+ ldmxcsr -4(%rsp)
+ movq %rsi,%rax /* retval */
+ movq 0(%rdx),%rcx
+ movq 8(%rdx),%rbx
+ movq 16(%rdx),%rsp
+ movq 24(%rdx),%rbp
+ movq 32(%rdx),%r12
+ movq 40(%rdx),%r13
+ movq 48(%rdx),%r14
+ movq 56(%rdx),%r15
+ fldcw 64(%rdx)
+ testq %rax,%rax
+ jnz 1f
+ incq %rax
+1: movq %rcx,0(%rsp)
+ ret
+END(__longjmp)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/amd64/gen/signalcontext.c b/lib/libc/amd64/gen/signalcontext.c
new file mode 100644
index 000000000000..1a2621aa7229
--- /dev/null
+++ b/lib/libc/amd64/gen/signalcontext.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2003 Marcel Moolenaar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/ucontext.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <strings.h>
+
+typedef void (*handler_t)(uint64_t, uint64_t, uint64_t);
+
+/* Prototypes */
+static void sigctx_wrapper(ucontext_t *ucp, handler_t func, uint64_t *args);
+
+__weak_reference(__signalcontext, signalcontext);
+
+int
+__signalcontext(ucontext_t *ucp, int sig, __sighandler_t *func)
+{
+ uint64_t *args;
+ siginfo_t *sig_si;
+ ucontext_t *sig_uc;
+ uint64_t sp;
+
+ /* Bail out if we don't have a valid ucontext pointer. */
+ if (ucp == NULL)
+ abort();
+
+ /*
+ * Build a signal frame and copy the arguments of signal handler
+ * 'func' onto the stack and do the funky stack alignment.
+ * This means that we need an 8-byte-odd alignment since the ABI expects
+ * the return address to be pushed, thus breaking the 16 byte alignment.
+ */
+ sp = (ucp->uc_mcontext.mc_rsp - 128 - sizeof(ucontext_t)) & ~15UL;
+ sig_uc = (ucontext_t *)sp;
+ bcopy(ucp, sig_uc, sizeof(*sig_uc));
+ sp = (sp - sizeof(siginfo_t)) & ~15UL;
+ sig_si = (siginfo_t *)sp;
+ bzero(sig_si, sizeof(*sig_si));
+ sig_si->si_signo = sig;
+ sp -= 3 * sizeof(uint64_t);
+ args = (uint64_t *)sp;
+ args[0] = sig;
+ args[1] = (intptr_t)sig_si;
+ args[2] = (intptr_t)sig_uc;
+ sp -= 16;
+
+ /*
+ * Setup the ucontext of the signal handler.
+ */
+ bzero(&ucp->uc_mcontext, sizeof(ucp->uc_mcontext));
+ ucp->uc_mcontext.mc_fpformat = _MC_FPFMT_NODEV;
+ ucp->uc_mcontext.mc_ownedfp = _MC_FPOWNED_NONE;
+ ucp->uc_link = sig_uc;
+ sigdelset(&ucp->uc_sigmask, sig);
+
+ ucp->uc_mcontext.mc_len = sizeof(mcontext_t);
+ ucp->uc_mcontext.mc_rdi = (register_t)ucp;
+ ucp->uc_mcontext.mc_rsi = (register_t)func;
+ ucp->uc_mcontext.mc_rdx = (register_t)args;
+ ucp->uc_mcontext.mc_rbp = (register_t)sp;
+ ucp->uc_mcontext.mc_rbx = (register_t)sp;
+ ucp->uc_mcontext.mc_rsp = (register_t)sp;
+ ucp->uc_mcontext.mc_rip = (register_t)sigctx_wrapper;
+ return (0);
+}
+
+static void
+sigctx_wrapper(ucontext_t *ucp, handler_t func, uint64_t *args)
+{
+
+ (*func)(args[0], args[1], args[2]);
+ if (ucp->uc_link == NULL)
+ exit(0);
+ setcontext((const ucontext_t *)ucp->uc_link);
+ /* should never get here */
+ abort();
+ /* NOTREACHED */
+}
diff --git a/lib/libc/amd64/gen/sigsetjmp.S b/lib/libc/amd64/gen/sigsetjmp.S
new file mode 100644
index 000000000000..1e8e77cbde3b
--- /dev/null
+++ b/lib/libc/amd64/gen/sigsetjmp.S
@@ -0,0 +1,116 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)setjmp.s 5.1 (Berkeley) 4/23/90"
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+ .text
+ .asciz "$Id: sigsetjmp.S,v 1.1 1993/12/05 13:01:05 ats Exp $"
+#endif /* LIBC_SCCS and not lint */
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+/*-
+ * TODO:
+ * Rename sigsetjmp to __sigsetjmp and siglongjmp to __siglongjmp,
+ * remove the other *jmp functions and define everything in terms
+ * of the renamed functions. This requires compiler support for
+ * the renamed functions (introduced in gcc-2.5.3; previous versions
+ * only supported *jmp with 0 or 1 leading underscores).
+ *
+ * Restore _all_ the registers and the signal mask atomically. Can
+ * use sigreturn() if sigreturn() works.
+ */
+
+ENTRY(sigsetjmp)
+ movl %esi,88(%rdi) /* 11; savemask */
+ testl %esi,%esi
+ jz 2f
+ pushq %rdi
+ movq %rdi,%rcx
+ movq $1,%rdi /* SIG_BLOCK */
+ movq $0,%rsi /* (sigset_t*)set */
+ leaq 72(%rcx),%rdx /* 9,10 (sigset_t*)oset */
+ /* stack is 16-byte aligned */
+ call __libc_sigprocmask
+ popq %rdi
+2: movq %rdi,%rcx
+ movq 0(%rsp),%rdx /* retval */
+ movq %rdx, 0(%rcx) /* 0; retval */
+ movq %rbx, 8(%rcx) /* 1; rbx */
+ movq %rsp,16(%rcx) /* 2; rsp */
+ movq %rbp,24(%rcx) /* 3; rbp */
+ movq %r12,32(%rcx) /* 4; r12 */
+ movq %r13,40(%rcx) /* 5; r13 */
+ movq %r14,48(%rcx) /* 6; r14 */
+ movq %r15,56(%rcx) /* 7; r15 */
+ fnstcw 64(%rcx) /* 8; fpu cw */
+ xorq %rax,%rax
+ ret
+END(sigsetjmp)
+
+ WEAK_REFERENCE(__siglongjmp, siglongjmp)
+ENTRY(__siglongjmp)
+ cmpl $0,88(%rdi)
+ jz 2f
+ movq %rdi,%rdx
+ pushq %rdi
+ pushq %rsi
+ movq $3,%rdi /* SIG_SETMASK */
+ leaq 72(%rdx),%rsi /* (sigset_t*)set */
+ movq $0,%rdx /* (sigset_t*)oset */
+ subq $0x8,%rsp /* make the stack 16-byte aligned */
+ call __libc_sigprocmask
+ addq $0x8,%rsp
+ popq %rsi
+ popq %rdi /* jmpbuf */
+2: movq %rdi,%rdx
+ movq %rsi,%rax /* retval */
+ movq 0(%rdx),%rcx
+ movq 8(%rdx),%rbx
+ movq 16(%rdx),%rsp
+ movq 24(%rdx),%rbp
+ movq 32(%rdx),%r12
+ movq 40(%rdx),%r13
+ movq 48(%rdx),%r14
+ movq 56(%rdx),%r15
+ fldcw 64(%rdx)
+ testq %rax,%rax
+ jnz 1f
+ incq %rax
+1: movq %rcx,0(%rsp)
+ ret
+END(__siglongjmp)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/amd64/stdlib/Makefile.inc b/lib/libc/amd64/stdlib/Makefile.inc
new file mode 100644
index 000000000000..5b7e675ede0d
--- /dev/null
+++ b/lib/libc/amd64/stdlib/Makefile.inc
@@ -0,0 +1,4 @@
+# @(#)Makefile.inc 8.1 (Berkeley) 6/4/93
+# $FreeBSD$
+
+MDSRCS+=div.S ldiv.S lldiv.S
diff --git a/lib/libc/amd64/stdlib/div.S b/lib/libc/amd64/stdlib/div.S
new file mode 100644
index 000000000000..366010c3d208
--- /dev/null
+++ b/lib/libc/amd64/stdlib/div.S
@@ -0,0 +1,20 @@
+/* $NetBSD: div.S,v 1.1 2001/06/19 00:25:04 fvdl Exp $ */
+
+/*-
+ * Written by Frank van der Linden (fvdl@wasabisystems.com)
+ * Public domain.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+ENTRY(div)
+ movl %edi,%eax
+ cltd
+ idivl %esi
+ salq $32,%rdx
+ orq %rdx,%rax
+ ret
+END(div)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/amd64/stdlib/ldiv.S b/lib/libc/amd64/stdlib/ldiv.S
new file mode 100644
index 000000000000..f11472c671dc
--- /dev/null
+++ b/lib/libc/amd64/stdlib/ldiv.S
@@ -0,0 +1,18 @@
+/* $NetBSD: ldiv.S,v 1.1 2001/06/19 00:25:04 fvdl Exp $ */
+
+/*-
+ * Written by gcc 3.0.
+ * Copy/pasted by Frank van der Linden (fvdl@wasabisystems.com)
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+ENTRY(ldiv)
+ movq %rdi,%rax
+ cqto
+ idivq %rsi
+ ret
+END(ldiv)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/amd64/stdlib/lldiv.S b/lib/libc/amd64/stdlib/lldiv.S
new file mode 100644
index 000000000000..4dab0fdd5278
--- /dev/null
+++ b/lib/libc/amd64/stdlib/lldiv.S
@@ -0,0 +1,18 @@
+/* $NetBSD: ldiv.S,v 1.1 2001/06/19 00:25:04 fvdl Exp $ */
+
+/*-
+ * Written by gcc 3.0.
+ * Copy/pasted by Frank van der Linden (fvdl@wasabisystems.com)
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+ENTRY(lldiv)
+ movq %rdi,%rax
+ cqto
+ idivq %rsi
+ ret
+END(lldiv)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/amd64/string/Makefile.inc b/lib/libc/amd64/string/Makefile.inc
new file mode 100644
index 000000000000..46571ab0766e
--- /dev/null
+++ b/lib/libc/amd64/string/Makefile.inc
@@ -0,0 +1,4 @@
+# $FreeBSD$
+
+MDSRCS+= bcmp.S bcopy.S bzero.S memcmp.S memcpy.S memmove.S memset.S \
+ strcat.S strcmp.S stpcpy.S strcpy.c
diff --git a/lib/libc/amd64/string/bcmp.S b/lib/libc/amd64/string/bcmp.S
new file mode 100644
index 000000000000..d01b76bc10e5
--- /dev/null
+++ b/lib/libc/amd64/string/bcmp.S
@@ -0,0 +1,27 @@
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#if 0
+ RCSID("$NetBSD: bcmp.S,v 1.1 2001/06/19 00:25:04 fvdl Exp $")
+#endif
+
+ENTRY(bcmp)
+ cld /* set compare direction forward */
+
+ movq %rdx,%rcx /* compare by words */
+ shrq $3,%rcx
+ repe
+ cmpsq
+ jne L1
+
+ movq %rdx,%rcx /* compare remainder by bytes */
+ andq $7,%rcx
+ repe
+ cmpsb
+L1:
+ setne %al
+ movsbl %al,%eax
+ ret
+END(bcmp)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/amd64/string/bcopy.S b/lib/libc/amd64/string/bcopy.S
new file mode 100644
index 000000000000..cc38f4755254
--- /dev/null
+++ b/lib/libc/amd64/string/bcopy.S
@@ -0,0 +1,99 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from locore.s.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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$");
+
+#if 0
+ RCSID("$NetBSD: bcopy.S,v 1.2 2003/08/07 16:42:36 agc Exp $")
+#endif
+
+ /*
+ * (ov)bcopy (src,dst,cnt)
+ * ws@tools.de (Wolfgang Solfrank, TooLs GmbH) +49-228-985800
+ */
+
+#ifdef MEMCOPY
+ENTRY(memcpy)
+#else
+#ifdef MEMMOVE
+ENTRY(memmove)
+#else
+ENTRY(bcopy)
+#endif
+#endif
+#if defined(MEMCOPY) || defined(MEMMOVE)
+ movq %rdi,%rax /* return dst */
+#else
+ xchgq %rdi,%rsi
+#endif
+ movq %rdx,%rcx
+ movq %rdi,%r8
+ subq %rsi,%r8
+ cmpq %rcx,%r8 /* overlapping? */
+ jb 1f
+ cld /* nope, copy forwards. */
+ shrq $3,%rcx /* copy by words */
+ rep
+ movsq
+ movq %rdx,%rcx
+ andq $7,%rcx /* any bytes left? */
+ rep
+ movsb
+ ret
+1:
+ addq %rcx,%rdi /* copy backwards. */
+ addq %rcx,%rsi
+ std
+ andq $7,%rcx /* any fractional bytes? */
+ decq %rdi
+ decq %rsi
+ rep
+ movsb
+ movq %rdx,%rcx /* copy remainder by words */
+ shrq $3,%rcx
+ subq $7,%rsi
+ subq $7,%rdi
+ rep
+ movsq
+ cld
+ ret
+#ifdef MEMCOPY
+END(memcpy)
+#else
+#ifdef MEMMOVE
+END(memmove)
+#else
+END(bcopy)
+#endif
+#endif
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/amd64/string/bzero.S b/lib/libc/amd64/string/bzero.S
new file mode 100644
index 000000000000..cf46a2a317b7
--- /dev/null
+++ b/lib/libc/amd64/string/bzero.S
@@ -0,0 +1,46 @@
+/*
+ * Written by J.T. Conklin <jtc@NetBSD.org>.
+ * Public domain.
+ * Adapted for NetBSD/x86_64 by Frank van der Linden <fvdl@wasabisystems.com>
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#if 0
+ RCSID("$NetBSD: bzero.S,v 1.2 2003/07/26 19:24:38 salo Exp $")
+#endif
+
+ENTRY(bzero)
+ cld /* set fill direction forward */
+ xorq %rax,%rax /* set fill data to 0 */
+
+ /*
+ * if the string is too short, it's really not worth the overhead
+ * of aligning to word boundries, etc. So we jump to a plain
+ * unaligned set.
+ */
+ cmpq $16,%rsi
+ jb L1
+
+ movq %rdi,%rcx /* compute misalignment */
+ negq %rcx
+ andq $7,%rcx
+ subq %rcx,%rsi
+ rep /* zero until word aligned */
+ stosb
+
+ movq %rsi,%rcx /* zero by words */
+ shrq $3,%rcx
+ andq $7,%rsi
+ rep
+ stosq
+
+L1: movq %rsi,%rcx /* zero remainder by bytes */
+ rep
+ stosb
+
+ ret
+END(bzero)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/amd64/string/memcmp.S b/lib/libc/amd64/string/memcmp.S
new file mode 100644
index 000000000000..66d64a0b5a48
--- /dev/null
+++ b/lib/libc/amd64/string/memcmp.S
@@ -0,0 +1,44 @@
+/*
+ * Written by J.T. Conklin <jtc@NetBSD.org>.
+ * Public domain.
+ * Adapted for NetBSD/x86_64 by Frank van der Linden <fvdl@wasabisystems.com>
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#if 0
+ RCSID("$NetBSD: memcmp.S,v 1.2 2003/07/26 19:24:39 salo Exp $")
+#endif
+
+ENTRY(memcmp)
+ cld /* set compare direction forward */
+ movq %rdx,%rcx /* compare by longs */
+ shrq $3,%rcx
+ repe
+ cmpsq
+ jne L5 /* do we match so far? */
+
+ movq %rdx,%rcx /* compare remainder by bytes */
+ andq $7,%rcx
+ repe
+ cmpsb
+ jne L6 /* do we match? */
+
+ xorl %eax,%eax /* we match, return zero */
+ ret
+
+L5: movl $8,%ecx /* We know that one of the next */
+ subq %rcx,%rdi /* eight pairs of bytes do not */
+ subq %rcx,%rsi /* match. */
+ repe
+ cmpsb
+L6: xorl %eax,%eax /* Perform unsigned comparison */
+ movb -1(%rdi),%al
+ xorl %edx,%edx
+ movb -1(%rsi),%dl
+ subl %edx,%eax
+ ret
+END(memcmp)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/amd64/string/memcpy.S b/lib/libc/amd64/string/memcpy.S
new file mode 100644
index 000000000000..bd1e8422ad84
--- /dev/null
+++ b/lib/libc/amd64/string/memcpy.S
@@ -0,0 +1,5 @@
+/* $NetBSD: memcpy.S,v 1.1 2001/06/19 00:25:05 fvdl Exp $ */
+/* $FreeBSD$ */
+
+#define MEMCOPY
+#include "bcopy.S"
diff --git a/lib/libc/amd64/string/memmove.S b/lib/libc/amd64/string/memmove.S
new file mode 100644
index 000000000000..85beb262f8d9
--- /dev/null
+++ b/lib/libc/amd64/string/memmove.S
@@ -0,0 +1,5 @@
+/* $NetBSD: memmove.S,v 1.1 2001/06/19 00:25:05 fvdl Exp $ */
+/* $FreeBSD$ */
+
+#define MEMMOVE
+#include "bcopy.S"
diff --git a/lib/libc/amd64/string/memset.S b/lib/libc/amd64/string/memset.S
new file mode 100644
index 000000000000..84d15628766a
--- /dev/null
+++ b/lib/libc/amd64/string/memset.S
@@ -0,0 +1,63 @@
+/*
+ * Written by J.T. Conklin <jtc@NetBSD.org>.
+ * Public domain.
+ * Adapted for NetBSD/x86_64 by Frank van der Linden <fvdl@wasabisystems.com>
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#if 0
+ RCSID("$NetBSD: memset.S,v 1.3 2004/02/26 20:50:06 drochner Exp $")
+#endif
+
+ENTRY(memset)
+ movq %rsi,%rax
+ andq $0xff,%rax
+ movq %rdx,%rcx
+ movq %rdi,%r11
+
+ cld /* set fill direction forward */
+
+ /*
+ * if the string is too short, it's really not worth the overhead
+ * of aligning to word boundries, etc. So we jump to a plain
+ * unaligned set.
+ */
+ cmpq $0x0f,%rcx
+ jle L1
+
+ movb %al,%ah /* copy char to all bytes in word */
+ movl %eax,%edx
+ sall $16,%eax
+ orl %edx,%eax
+
+ movl %eax,%edx
+ salq $32,%rax
+ orq %rdx,%rax
+
+ movq %rdi,%rdx /* compute misalignment */
+ negq %rdx
+ andq $7,%rdx
+ movq %rcx,%r8
+ subq %rdx,%r8
+
+ movq %rdx,%rcx /* set until word aligned */
+ rep
+ stosb
+
+ movq %r8,%rcx
+ shrq $3,%rcx /* set by words */
+ rep
+ stosq
+
+ movq %r8,%rcx /* set remainder by bytes */
+ andq $7,%rcx
+L1: rep
+ stosb
+ movq %r11,%rax
+
+ ret
+END(memset)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/amd64/string/stpcpy.S b/lib/libc/amd64/string/stpcpy.S
new file mode 100644
index 000000000000..52ac69c5f7e2
--- /dev/null
+++ b/lib/libc/amd64/string/stpcpy.S
@@ -0,0 +1,116 @@
+/*
+ * Adapted by Guillaume Morin <guillaume@morinfr.org> from strcpy.S
+ * written by J.T. Conklin <jtc@acorntoolworks.com>
+ * Public domain.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * This stpcpy implementation copies a byte at a time until the
+ * source pointer is aligned to a word boundary, it then copies by
+ * words until it finds a word containing a zero byte, and finally
+ * copies by bytes until the end of the string is reached.
+ *
+ * While this may result in unaligned stores if the source and
+ * destination pointers are unaligned with respect to each other,
+ * it is still faster than either byte copies or the overhead of
+ * an implementation suitable for machines with strict alignment
+ * requirements.
+ */
+
+ .globl stpcpy,__stpcpy
+ENTRY(stpcpy)
+__stpcpy:
+ movabsq $0x0101010101010101,%r8
+ movabsq $0x8080808080808080,%r9
+
+ /*
+ * Align source to a word boundary.
+ * Consider unrolling loop?
+ */
+.Lalign:
+ testb $7,%sil
+ je .Lword_aligned
+ movb (%rsi),%dl
+ incq %rsi
+ movb %dl,(%rdi)
+ incq %rdi
+ testb %dl,%dl
+ jne .Lalign
+ movq %rdi,%rax
+ dec %rax
+ ret
+
+ .p2align 4
+.Lloop:
+ movq %rdx,(%rdi)
+ addq $8,%rdi
+.Lword_aligned:
+ movq (%rsi),%rdx
+ movq %rdx,%rcx
+ addq $8,%rsi
+ subq %r8,%rcx
+ testq %r9,%rcx
+ je .Lloop
+
+ /*
+ * In rare cases, the above loop may exit prematurely. We must
+ * return to the loop if none of the bytes in the word equal 0.
+ */
+
+ movb %dl,(%rdi)
+ testb %dl,%dl /* 1st byte == 0? */
+ je .Ldone
+ incq %rdi
+
+ shrq $8,%rdx
+ movb %dl,(%rdi)
+ testb %dl,%dl /* 2nd byte == 0? */
+ je .Ldone
+ incq %rdi
+
+ shrq $8,%rdx
+ movb %dl,(%rdi)
+ testb %dl,%dl /* 3rd byte == 0? */
+ je .Ldone
+ incq %rdi
+
+ shrq $8,%rdx
+ movb %dl,(%rdi)
+ testb %dl,%dl /* 4th byte == 0? */
+ je .Ldone
+ incq %rdi
+
+ shrq $8,%rdx
+ movb %dl,(%rdi)
+ testb %dl,%dl /* 5th byte == 0? */
+ je .Ldone
+ incq %rdi
+
+ shrq $8,%rdx
+ movb %dl,(%rdi)
+ testb %dl,%dl /* 6th byte == 0? */
+ je .Ldone
+ incq %rdi
+
+ shrq $8,%rdx
+ movb %dl,(%rdi)
+ testb %dl,%dl /* 7th byte == 0? */
+ je .Ldone
+ incq %rdi
+
+ shrq $8,%rdx
+ movb %dl,(%rdi)
+ incq %rdi
+ testb %dl,%dl /* 8th byte == 0? */
+ jne .Lword_aligned
+ decq %rdi
+
+.Ldone:
+ movq %rdi,%rax
+ ret
+END(stpcpy)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/amd64/string/strcat.S b/lib/libc/amd64/string/strcat.S
new file mode 100644
index 000000000000..7b5a1dd39cd3
--- /dev/null
+++ b/lib/libc/amd64/string/strcat.S
@@ -0,0 +1,168 @@
+/*
+ * Written by J.T. Conklin <jtc@acorntoolworks.com>
+ * Public domain.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#if 0
+ RCSID("$NetBSD: strcat.S,v 1.4 2004/07/26 18:51:21 drochner Exp $")
+#endif
+
+ENTRY(strcat)
+ movq %rdi,%rax
+ movabsq $0x0101010101010101,%r8
+ movabsq $0x8080808080808080,%r9
+
+ /*
+ * Align destination to word boundary.
+ * Consider unrolling loop?
+ */
+.Lscan:
+.Lscan_align:
+ testb $7,%dil
+ je .Lscan_aligned
+ cmpb $0,(%rdi)
+ je .Lcopy
+ incq %rdi
+ jmp .Lscan_align
+
+ .align 4
+.Lscan_aligned:
+.Lscan_loop:
+ movq (%rdi),%rdx
+ addq $8,%rdi
+ subq %r8,%rdx
+ testq %r9,%rdx
+ je .Lscan_loop
+
+ /*
+ * In rare cases, the above loop may exit prematurely. We must
+ * return to the loop if none of the bytes in the word equal 0.
+ */
+
+ cmpb $0,-8(%rdi) /* 1st byte == 0? */
+ jne 1f
+ subq $8,%rdi
+ jmp .Lcopy
+
+1: cmpb $0,-7(%rdi) /* 2nd byte == 0? */
+ jne 1f
+ subq $7,%rdi
+ jmp .Lcopy
+
+1: cmpb $0,-6(%rdi) /* 3rd byte == 0? */
+ jne 1f
+ subq $6,%rdi
+ jmp .Lcopy
+
+1: cmpb $0,-5(%rdi) /* 4th byte == 0? */
+ jne 1f
+ subq $5,%rdi
+ jmp .Lcopy
+
+1: cmpb $0,-4(%rdi) /* 5th byte == 0? */
+ jne 1f
+ subq $4,%rdi
+ jmp .Lcopy
+
+1: cmpb $0,-3(%rdi) /* 6th byte == 0? */
+ jne 1f
+ subq $3,%rdi
+ jmp .Lcopy
+
+1: cmpb $0,-2(%rdi) /* 7th byte == 0? */
+ jne 1f
+ subq $2,%rdi
+ jmp .Lcopy
+
+1: cmpb $0,-1(%rdi) /* 8th byte == 0? */
+ jne .Lscan_loop
+ subq $1,%rdi
+
+ /*
+ * Align source to a word boundary.
+ * Consider unrolling loop?
+ */
+.Lcopy:
+.Lcopy_align:
+ testb $7,%sil
+ je .Lcopy_aligned
+ movb (%rsi),%dl
+ incq %rsi
+ movb %dl,(%rdi)
+ incq %rdi
+ testb %dl,%dl
+ jne .Lcopy_align
+ ret
+
+ .align 4
+.Lcopy_loop:
+ movq %rdx,(%rdi)
+ addq $8,%rdi
+.Lcopy_aligned:
+ movq (%rsi),%rdx
+ movq %rdx,%rcx
+ addq $8,%rsi
+ subq %r8,%rcx
+ testq %r9,%rcx
+ je .Lcopy_loop
+
+ /*
+ * In rare cases, the above loop may exit prematurely. We must
+ * return to the loop if none of the bytes in the word equal 0.
+ */
+
+ movb %dl,(%rdi)
+ incq %rdi
+ testb %dl,%dl /* 1st byte == 0? */
+ je .Ldone
+
+ shrq $8,%rdx
+ movb %dl,(%rdi)
+ incq %rdi
+ testb %dl,%dl /* 2nd byte == 0? */
+ je .Ldone
+
+ shrq $8,%rdx
+ movb %dl,(%rdi)
+ incq %rdi
+ testb %dl,%dl /* 3rd byte == 0? */
+ je .Ldone
+
+ shrq $8,%rdx
+ movb %dl,(%rdi)
+ incq %rdi
+ testb %dl,%dl /* 4th byte == 0? */
+ je .Ldone
+
+ shrq $8,%rdx
+ movb %dl,(%rdi)
+ incq %rdi
+ testb %dl,%dl /* 5th byte == 0? */
+ je .Ldone
+
+ shrq $8,%rdx
+ movb %dl,(%rdi)
+ incq %rdi
+ testb %dl,%dl /* 6th byte == 0? */
+ je .Ldone
+
+ shrq $8,%rdx
+ movb %dl,(%rdi)
+ incq %rdi
+ testb %dl,%dl /* 7th byte == 0? */
+ je .Ldone
+
+ shrq $8,%rdx
+ movb %dl,(%rdi)
+ incq %rdi
+ testb %dl,%dl /* 8th byte == 0? */
+ jne .Lcopy_aligned
+
+.Ldone:
+ ret
+END(strcat)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/amd64/string/strcmp.S b/lib/libc/amd64/string/strcmp.S
new file mode 100644
index 000000000000..787e1e07b1b0
--- /dev/null
+++ b/lib/libc/amd64/string/strcmp.S
@@ -0,0 +1,76 @@
+/*
+ * Written by J.T. Conklin <jtc@acorntoolworks.com>
+ * Public domain.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#if 0
+ RCSID("$NetBSD: strcmp.S,v 1.3 2004/07/19 20:04:41 drochner Exp $")
+#endif
+
+ENTRY(strcmp)
+ /*
+ * Align s1 to word boundary.
+ * Consider unrolling loop?
+ */
+.Ls1align:
+ testb $7,%dil
+ je .Ls1aligned
+ movb (%rdi),%al
+ incq %rdi
+ movb (%rsi),%dl
+ incq %rsi
+ testb %al,%al
+ je .Ldone
+ cmpb %al,%dl
+ je .Ls1align
+ jmp .Ldone
+
+ /*
+ * Check whether s2 is aligned to a word boundary. If it is, we
+ * can compare by words. Otherwise we have to compare by bytes.
+ */
+.Ls1aligned:
+ testb $7,%sil
+ jne .Lbyte_loop
+
+ movabsq $0x0101010101010101,%r8
+ subq $8,%rdi
+ movabsq $0x8080808080808080,%r9
+ subq $8,%rsi
+
+ .align 4
+.Lword_loop:
+ movq 8(%rdi),%rax
+ addq $8,%rdi
+ movq 8(%rsi),%rdx
+ addq $8,%rsi
+ cmpq %rax,%rdx
+ jne .Lbyte_loop
+ subq %r8,%rdx
+ notq %rax
+ andq %rax,%rdx
+ testq %r9,%rdx
+ je .Lword_loop
+
+ .align 4
+.Lbyte_loop:
+ movb (%rdi),%al
+ incq %rdi
+ movb (%rsi),%dl
+ incq %rsi
+ testb %al,%al
+ je .Ldone
+ cmpb %al,%dl
+ je .Lbyte_loop
+
+.Ldone:
+ movzbq %al,%rax
+ movzbq %dl,%rdx
+ subq %rdx,%rax
+ ret
+END(strcmp)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/amd64/string/strcpy.c b/lib/libc/amd64/string/strcpy.c
new file mode 100644
index 000000000000..11a24eb2cf3a
--- /dev/null
+++ b/lib/libc/amd64/string/strcpy.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2011 George V. Neville-Neil. All rights reserved.
+ *
+ * The compilation of software known as FreeBSD is distributed under the
+ * following terms:
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+char *__stpcpy(char * __restrict, const char * __restrict);
+
+char *
+strcpy(char * __restrict to, const char * __restrict from)
+{
+ __stpcpy(to, from);
+ return(to);
+}
diff --git a/lib/libc/amd64/sys/Makefile.inc b/lib/libc/amd64/sys/Makefile.inc
new file mode 100644
index 000000000000..d208f0fcc111
--- /dev/null
+++ b/lib/libc/amd64/sys/Makefile.inc
@@ -0,0 +1,11 @@
+# from: Makefile.inc,v 1.1 1993/09/03 19:04:23 jtc Exp
+# $FreeBSD$
+
+SRCS+= amd64_get_fsbase.c amd64_get_gsbase.c amd64_set_fsbase.c \
+ amd64_set_gsbase.c
+
+MDASM= vfork.S brk.S cerror.S exect.S getcontext.S \
+ sbrk.S setlogin.S sigreturn.S
+
+# Don't generate default code for these syscalls:
+NOASM+= vfork.o
diff --git a/lib/libc/amd64/sys/amd64_get_fsbase.c b/lib/libc/amd64/sys/amd64_get_fsbase.c
new file mode 100644
index 000000000000..ff5eb8f305ae
--- /dev/null
+++ b/lib/libc/amd64/sys/amd64_get_fsbase.c
@@ -0,0 +1,37 @@
+/*-
+ * Copyright (c) 2003 Peter Wemm
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <machine/sysarch.h>
+
+int
+amd64_get_fsbase(void **addr)
+{
+
+ return (sysarch(AMD64_GET_FSBASE, addr));
+}
diff --git a/lib/libc/amd64/sys/amd64_get_gsbase.c b/lib/libc/amd64/sys/amd64_get_gsbase.c
new file mode 100644
index 000000000000..ddbf977f5dd1
--- /dev/null
+++ b/lib/libc/amd64/sys/amd64_get_gsbase.c
@@ -0,0 +1,37 @@
+/*-
+ * Copyright (c) 2003 Peter Wemm
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <machine/sysarch.h>
+
+int
+amd64_get_gsbase(void **addr)
+{
+
+ return (sysarch(AMD64_GET_GSBASE, addr));
+}
diff --git a/lib/libc/amd64/sys/amd64_set_fsbase.c b/lib/libc/amd64/sys/amd64_set_fsbase.c
new file mode 100644
index 000000000000..e0914859a1ae
--- /dev/null
+++ b/lib/libc/amd64/sys/amd64_set_fsbase.c
@@ -0,0 +1,37 @@
+/*-
+ * Copyright (c) 2003 Peter Wemm
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <machine/sysarch.h>
+
+int
+amd64_set_fsbase(void *addr)
+{
+
+ return (sysarch(AMD64_SET_FSBASE, &addr));
+}
diff --git a/lib/libc/amd64/sys/amd64_set_gsbase.c b/lib/libc/amd64/sys/amd64_set_gsbase.c
new file mode 100644
index 000000000000..f8963288ac07
--- /dev/null
+++ b/lib/libc/amd64/sys/amd64_set_gsbase.c
@@ -0,0 +1,37 @@
+/*-
+ * Copyright (c) 2003 Peter Wemm
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <machine/sysarch.h>
+
+int
+amd64_set_gsbase(void *addr)
+{
+
+ return (sysarch(AMD64_SET_GSBASE, &addr));
+}
diff --git a/lib/libc/amd64/sys/brk.S b/lib/libc/amd64/sys/brk.S
new file mode 100644
index 000000000000..4048ae60a890
--- /dev/null
+++ b/lib/libc/amd64/sys/brk.S
@@ -0,0 +1,82 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(SYSLIBC_SCCS) && !defined(lint)
+ .asciz "@(#)brk.s 5.2 (Berkeley) 12/17/90"
+#endif /* SYSLIBC_SCCS and not lint */
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+ .globl HIDENAME(curbrk)
+ .globl HIDENAME(minbrk)
+ENTRY(_brk)
+ pushq %rdi
+ jmp ok
+END(_brk)
+
+ENTRY(brk)
+ pushq %rdi
+ movq %rdi,%rax
+#ifdef PIC
+ movq PIC_GOT(HIDENAME(minbrk)),%rdx
+ cmpq %rax,(%rdx)
+#else
+ cmpq %rax,HIDENAME(minbrk)(%rip)
+#endif
+ jbe ok
+#ifdef PIC
+ movq (%rdx),%rdi
+#else
+ movq HIDENAME(minbrk)(%rip),%rdi
+#endif
+ok:
+ movq $SYS_break,%rax
+ KERNCALL
+ jb err
+ movq 0(%rsp),%rax
+#ifdef PIC
+ movq PIC_GOT(HIDENAME(curbrk)),%rdx
+ movq %rax,(%rdx)
+#else
+ movq %rax,HIDENAME(curbrk)(%rip)
+#endif
+ movq $0,%rax
+ popq %rdi
+ ret
+err:
+ addq $8, %rsp
+ jmp HIDENAME(cerror)
+END(brk)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/amd64/sys/cerror.S b/lib/libc/amd64/sys/cerror.S
new file mode 100644
index 000000000000..d28a13998b4b
--- /dev/null
+++ b/lib/libc/amd64/sys/cerror.S
@@ -0,0 +1,60 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(SYSLIBC_SCCS) && !defined(lint)
+ .asciz "@(#)cerror.s 5.1 (Berkeley) 4/23/90"
+#endif /* SYSLIBC_SCCS and not lint */
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+ .globl HIDENAME(cerror)
+ .hidden HIDENAME(cerror)
+
+ /*
+ * The __error() function is thread aware. For non-threaded
+ * programs and the initial threaded in threaded programs,
+ * it returns a pointer to the global errno variable.
+ */
+ .globl CNAME(__error)
+ .type CNAME(__error),@function
+HIDENAME(cerror):
+ pushq %rax
+ call PIC_PLT(CNAME(__error))
+ popq %rcx
+ movl %ecx,(%rax)
+ movq $-1,%rax
+ movq $-1,%rdx
+ ret
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/amd64/sys/exect.S b/lib/libc/amd64/sys/exect.S
new file mode 100644
index 000000000000..04a97ed8f5a2
--- /dev/null
+++ b/lib/libc/amd64/sys/exect.S
@@ -0,0 +1,53 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(SYSLIBC_SCCS) && !defined(lint)
+ .asciz "@(#)exect.s 5.1 (Berkeley) 4/23/90"
+#endif /* SYSLIBC_SCCS and not lint */
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+#include <machine/psl.h>
+
+ENTRY(exect)
+ movq $SYS_execve,%rax
+ pushfq
+ popq %r8
+ orq $PSL_T,%r8
+ pushq %r8
+ popfq
+ KERNCALL
+ jmp HIDENAME(cerror)
+END(exect)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/amd64/sys/getcontext.S b/lib/libc/amd64/sys/getcontext.S
new file mode 100644
index 000000000000..b11e65caf580
--- /dev/null
+++ b/lib/libc/amd64/sys/getcontext.S
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 2003 Peter Wemm <peter@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include <SYS.h>
+
+/*
+ * This has to be magic to handle the multiple returns.
+ * Otherwise, the setcontext() syscall will return here and we'll
+ * pop off the return address and go to the *setcontext* call.
+ */
+ WEAK_REFERENCE(__sys_getcontext, _getcontext)
+ WEAK_REFERENCE(__sys_getcontext, getcontext)
+ENTRY(__sys_getcontext)
+ movq (%rsp),%rsi /* save getcontext return address */
+ mov $SYS_getcontext,%rax
+ KERNCALL
+ jb HIDENAME(cerror)
+ addq $8,%rsp /* remove stale (setcontext) return address */
+ jmp *%rsi /* restore return address */
+END(__sys_getcontext)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/amd64/sys/sbrk.S b/lib/libc/amd64/sys/sbrk.S
new file mode 100644
index 000000000000..0332aaed6528
--- /dev/null
+++ b/lib/libc/amd64/sys/sbrk.S
@@ -0,0 +1,85 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(SYSLIBC_SCCS) && !defined(lint)
+ .asciz "@(#)sbrk.s 5.1 (Berkeley) 4/23/90"
+#endif /* SYSLIBC_SCCS and not lint */
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+ .globl CNAME(_end)
+ .globl HIDENAME(minbrk)
+ .globl HIDENAME(curbrk)
+
+ .data
+HIDENAME(minbrk): .quad CNAME(_end)
+HIDENAME(curbrk): .quad CNAME(_end)
+ .text
+
+ENTRY(sbrk)
+ pushq %rdi
+ movq %rdi,%rcx
+#ifdef PIC
+ movq PIC_GOT(HIDENAME(curbrk)),%rdx
+ movq (%rdx),%rax
+#else
+ movq HIDENAME(curbrk)(%rip),%rax
+#endif
+ testq %rcx,%rcx
+ jz back
+ addq %rax,%rdi
+ mov $SYS_break,%eax
+ KERNCALL
+ jb err
+#ifdef PIC
+ movq PIC_GOT(HIDENAME(curbrk)),%rdx
+ movq (%rdx),%rax
+#else
+ movq HIDENAME(curbrk)(%rip),%rax
+#endif
+ movq 0(%rsp), %rcx
+#ifdef PIC
+ addq %rcx,(%rdx)
+#else
+ addq %rcx,HIDENAME(curbrk)(%rip)
+#endif
+back:
+ addq $8, %rsp
+ ret
+err:
+ addq $8, %rsp
+ jmp HIDENAME(cerror)
+END(sbrk)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/amd64/sys/setlogin.S b/lib/libc/amd64/sys/setlogin.S
new file mode 100644
index 000000000000..a0d127de85c2
--- /dev/null
+++ b/lib/libc/amd64/sys/setlogin.S
@@ -0,0 +1,53 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+ .asciz "@(#)setlogin.s 5.2 (Berkeley) 4/12/91"
+#endif /* LIBC_SCCS and not lint */
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+.globl CNAME(_logname_valid) /* in _getlogin() */
+
+ WEAK_REFERENCE(__sys_setlogin, _setlogin)
+ WEAK_REFERENCE(__sys_setlogin, setlogin)
+ENTRY(__sys_setlogin)
+ mov $SYS_setlogin,%rax
+ KERNCALL
+ jb HIDENAME(cerror)
+ movl $0,CNAME(_logname_valid)(%rip)
+ ret /* setlogin(name) */
+END(__sys_setlogin)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/amd64/sys/sigreturn.S b/lib/libc/amd64/sys/sigreturn.S
new file mode 100644
index 000000000000..f91816edd443
--- /dev/null
+++ b/lib/libc/amd64/sys/sigreturn.S
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(SYSLIBC_SCCS) && !defined(lint)
+ .asciz "@(#)sigreturn.s 5.2 (Berkeley) 12/17/90"
+#endif /* SYSLIBC_SCCS and not lint */
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+/*
+ * NOTE: If the profiling ENTRY() code ever changes any registers, they
+ * must be saved. On FreeBSD, this is not the case.
+ */
+
+RSYSCALL(sigreturn)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/amd64/sys/vfork.S b/lib/libc/amd64/sys/vfork.S
new file mode 100644
index 000000000000..62dc71e83f3e
--- /dev/null
+++ b/lib/libc/amd64/sys/vfork.S
@@ -0,0 +1,54 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(SYSLIBC_SCCS) && !defined(lint)
+ .asciz "@(#)Ovfork.s 5.1 (Berkeley) 4/23/90"
+#endif /* SYSLIBC_SCCS and not lint */
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+ WEAK_REFERENCE(__sys_vfork, _vfork)
+ WEAK_REFERENCE(__sys_vfork, vfork)
+ENTRY(__sys_vfork)
+ popq %rsi /* fetch return address (%rsi preserved) */
+ mov $SYS_vfork,%rax
+ KERNCALL
+ jb 1f
+ jmp *%rsi
+1:
+ pushq %rsi
+ jmp HIDENAME(cerror)
+END(__sys_vfork)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/arm/Makefile.inc b/lib/libc/arm/Makefile.inc
new file mode 100644
index 000000000000..c263ae715e29
--- /dev/null
+++ b/lib/libc/arm/Makefile.inc
@@ -0,0 +1,17 @@
+# $FreeBSD$
+#
+# Machine dependent definitions for the arm architecture.
+#
+
+SOFTFLOAT_BITS=32
+
+# Long double is just double precision.
+MDSRCS+=machdep_ldisd.c
+SYM_MAPS+=${LIBC_SRCTOP}/arm/Symbol.map
+
+.include "${LIBC_SRCTOP}/arm/aeabi/Makefile.inc"
+
+.if ${MACHINE_ARCH:Marmv6*} && (!defined(CPUTYPE) || ${CPUTYPE:M*soft*} == "")
+SYM_MAPS+=${LIBC_SRCTOP}/arm/Symbol_vfp.map
+.endif
+
diff --git a/lib/libc/arm/SYS.h b/lib/libc/arm/SYS.h
new file mode 100644
index 000000000000..117308786ff3
--- /dev/null
+++ b/lib/libc/arm/SYS.h
@@ -0,0 +1,80 @@
+/* $NetBSD: SYS.h,v 1.8 2003/08/07 16:42:02 agc Exp $ */
+
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)SYS.h 5.5 (Berkeley) 5/7/91
+ * $FreeBSD$
+ */
+
+#include <machine/asm.h>
+#include <sys/syscall.h>
+#include <machine/swi.h>
+
+#define SYSTRAP(x) \
+ mov ip, r7; \
+ ldr r7, =SYS_ ## x; \
+ swi 0; \
+ mov r7, ip
+
+#define CERROR _C_LABEL(cerror)
+#define CURBRK _C_LABEL(curbrk)
+
+#define _SYSCALL_NOERROR(x) \
+ ENTRY(__CONCAT(__sys_, x)); \
+ .weak _C_LABEL(x); \
+ .set _C_LABEL(x), _C_LABEL(__CONCAT(__sys_,x)); \
+ .weak _C_LABEL(__CONCAT(_,x)); \
+ .set _C_LABEL(__CONCAT(_,x)),_C_LABEL(__CONCAT(__sys_,x)); \
+ SYSTRAP(x)
+
+#define _SYSCALL(x) \
+ _SYSCALL_NOERROR(x); \
+ it cs; \
+ bcs PIC_SYM(CERROR, PLT)
+
+#define SYSCALL(x) \
+ _SYSCALL(x)
+
+#define PSEUDO(x) \
+ ENTRY(__CONCAT(__sys_, x)); \
+ .weak _C_LABEL(__CONCAT(_,x)); \
+ .set _C_LABEL(__CONCAT(_,x)),_C_LABEL(__CONCAT(__sys_,x)); \
+ SYSTRAP(x); \
+ it cs; \
+ bcs PIC_SYM(CERROR, PLT); \
+ RET
+
+#define RSYSCALL(x) \
+ _SYSCALL(x); \
+ RET
+
+ .globl CERROR
diff --git a/lib/libc/arm/Symbol.map b/lib/libc/arm/Symbol.map
new file mode 100644
index 000000000000..3c5c80f1a74e
--- /dev/null
+++ b/lib/libc/arm/Symbol.map
@@ -0,0 +1,83 @@
+/*
+ * $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, ...).
+ */
+FBSD_1.0 {
+ /* PSEUDO syscalls */
+ _exit;
+
+ __mcount;
+ _setjmp;
+ _longjmp;
+ alloca;
+ fabs;
+ __infinity;
+ __nan;
+ makecontext;
+ setjmp;
+ longjmp;
+ sigsetjmp;
+ siglongjmp;
+ htonl;
+ htons;
+ ntohl;
+ ntohs;
+ vfork;
+ brk;
+ sbrk;
+};
+
+FBSD_1.3 {
+ __flt_rounds;
+};
+
+FBSD_1.4 {
+ __gnu_Unwind_Find_exidx;
+ dl_unwind_find_exidx;
+};
+
+FBSDprivate_1.0 {
+ /* PSEUDO syscalls */
+ __sys_getlogin;
+ _getlogin;
+ __sys_exit;
+
+ _set_tp;
+ __aeabi_read_tp;
+ ___longjmp;
+ __makecontext;
+ __longjmp;
+ signalcontext;
+ _signalcontext;
+ __siglongjmp;
+ __sys_vfork;
+ _vfork;
+ _brk;
+ _end;
+ _sbrk;
+
+ /* softfloat */
+ __addsf3;
+ __adddf3;
+ __subsf3;
+ __subdf3;
+ __mulsf3;
+ __muldf3;
+ __divsf3;
+ __divdf3;
+ __floatsisf;
+ __floatsidf;
+ __fixsfsi;
+ __fixdfsi;
+ __fixunssfsi;
+ __fixunsdfsi;
+ __extendsfdf2;
+ __truncdfsf2;
+
+ _libc_arm_fpu_present;
+};
diff --git a/lib/libc/arm/Symbol_vfp.map b/lib/libc/arm/Symbol_vfp.map
new file mode 100644
index 000000000000..82cfcfb574f5
--- /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/_fpmath.h b/lib/libc/arm/_fpmath.h
new file mode 100644
index 000000000000..28bcb4b4ffde
--- /dev/null
+++ b/lib/libc/arm/_fpmath.h
@@ -0,0 +1,67 @@
+/*-
+ * Copyright (c) 2002, 2003 David Schultz <das@FreeBSD.ORG>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#if defined(__VFP_FP__) || defined(__ARM_EABI__)
+#define _IEEE_WORD_ORDER _BYTE_ORDER
+#else
+#define _IEEE_WORD_ORDER _BIG_ENDIAN
+#endif
+
+union IEEEl2bits {
+ long double e;
+ struct {
+#if _BYTE_ORDER == _LITTLE_ENDIAN
+#if _IEEE_WORD_ORDER == _LITTLE_ENDIAN
+ unsigned int manl :32;
+#endif
+ unsigned int manh :20;
+ unsigned int exp :11;
+ unsigned int sign :1;
+#if _IEEE_WORD_ORDER == _BIG_ENDIAN
+ unsigned int manl :32;
+#endif
+#else /* _BYTE_ORDER == _LITTLE_ENDIAN */
+ unsigned int sign :1;
+ unsigned int exp :11;
+ unsigned int manh :20;
+ unsigned int manl :32;
+#endif
+ } bits;
+};
+
+#define LDBL_NBIT 0
+#define LDBL_IMPLICIT_NBIT
+#define mask_nbit_l(u) ((void)0)
+
+#define LDBL_MANH_SIZE 20
+#define LDBL_MANL_SIZE 32
+
+#define LDBL_TO_ARRAY32(u, a) do { \
+ (a)[0] = (uint32_t)(u).bits.manl; \
+ (a)[1] = (uint32_t)(u).bits.manh; \
+} while(0)
diff --git a/lib/libc/arm/aeabi/Makefile.inc b/lib/libc/arm/aeabi/Makefile.inc
new file mode 100644
index 000000000000..44ed2c696f4f
--- /dev/null
+++ b/lib/libc/arm/aeabi/Makefile.inc
@@ -0,0 +1,32 @@
+# $FreeBSD$
+
+.PATH: ${LIBC_SRCTOP}/arm/aeabi
+
+SRCS+= aeabi_atexit.c \
+ aeabi_unwind_cpp.c \
+ aeabi_unwind_exidx.c
+.if (${MACHINE_ARCH:Marmv6*} && defined(CPUTYPE) && ${CPUTYPE:M*soft*} != "") || \
+ ${MACHINE_ARCH:Marmv6*} == ""
+SRCS+= aeabi_asm_double.S \
+ aeabi_asm_float.S \
+ aeabi_double.c \
+ aeabi_float.c
+.endif
+.if ${MACHINE_ARCH:Marmv6*} && (!defined(CPUTYPE) || ${CPUTYPE:M*soft*} == "")
+SRCS+= aeabi_vfp_double.S \
+ aeabi_vfp_float.S
+.endif
+
+# Add the aeabi_mem* functions. While they live in compiler-rt they call into
+# libc. This causes issues when other parts of libc call these functions.
+# We work around this by including these functions in libc but mark them as
+# hidden so users of libc will not pick up these versions.
+.PATH: ${SRCTOP}/contrib/compiler-rt/lib/builtins/arm
+
+SRCS+= aeabi_memcmp.S \
+ aeabi_memcpy.S \
+ aeabi_memmove.S \
+ aeabi_memset.S
+
+SYM_MAPS+=${LIBC_SRCTOP}/arm/aeabi/Symbol.map
+
diff --git a/lib/libc/arm/aeabi/Symbol.map b/lib/libc/arm/aeabi/Symbol.map
new file mode 100644
index 000000000000..1aff92912434
--- /dev/null
+++ b/lib/libc/arm/aeabi/Symbol.map
@@ -0,0 +1,72 @@
+/*
+ * $FreeBSD$
+ */
+
+/*
+ * This only needs to contain AEABI 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, ...).
+ */
+FBSDprivate_1.0 {
+ __aeabi_atexit;
+
+ __aeabi_dcmpeq;
+ __aeabi_dcmplt;
+ __aeabi_dcmple;
+ __aeabi_dcmpge;
+ __aeabi_dcmpgt;
+ __aeabi_dcmpun;
+
+ __aeabi_cdcmpeq;
+ __aeabi_cdcmple;
+ __aeabi_cdrcmple;
+
+ __aeabi_d2iz;
+ __aeabi_d2f;
+
+ __aeabi_dadd;
+ __aeabi_ddiv;
+ __aeabi_dmul;
+ __aeabi_dsub;
+
+
+ __aeabi_fcmpeq;
+ __aeabi_fcmplt;
+ __aeabi_fcmple;
+ __aeabi_fcmpge;
+ __aeabi_fcmpgt;
+ __aeabi_fcmpun;
+
+ __aeabi_cfcmpeq;
+ __aeabi_cfcmple;
+ __aeabi_cfrcmple;
+
+ __aeabi_f2iz;
+ __aeabi_f2d;
+
+ __aeabi_fadd;
+ __aeabi_fdiv;
+ __aeabi_fmul;
+ __aeabi_fsub;
+
+
+ __aeabi_i2d;
+ __aeabi_i2f;
+
+
+ __aeabi_memclr;
+ __aeabi_memclr4;
+ __aeabi_memclr8;
+ __aeabi_memcmp;
+ __aeabi_memcmp4;
+ __aeabi_memcmp8;
+ __aeabi_memcpy;
+ __aeabi_memcpy4;
+ __aeabi_memcpy8;
+ __aeabi_memmove;
+ __aeabi_memmove4;
+ __aeabi_memmove8;
+ __aeabi_memset;
+ __aeabi_memset4;
+ __aeabi_memset8;
+};
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 000000000000..ced4d78b6cbf
--- /dev/null
+++ b/lib/libc/arm/aeabi/aeabi_asm_double.S
@@ -0,0 +1,121 @@
+/*
+ * 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 */
+ mov ip, #(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 */
+ mov ip, #(PCR_Z | PCR_C)
+ b 99f
+
+2:
+ /* Not less than or equal, set C and clear Z */
+ mov ip, #(PCR_C)
+
+99:
+ msr cpsr_c, ip
+ 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:
+ mov ip, #(PCR_C)
+ msr cpsr_c, ip
+ RET
+END(__aeabi_cdcmpeq)
+
+ .section .note.GNU-stack,"",%progbits
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 000000000000..de6b1c88f4f2
--- /dev/null
+++ b/lib/libc/arm/aeabi/aeabi_asm_float.S
@@ -0,0 +1,112 @@
+/*
+ * 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 */
+ mov ip, #(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 */
+ mov ip, #(PCR_Z | PCR_C)
+ b 99f
+
+2:
+ /* Not less than or equal, set C and clear Z */
+ mov ip, #(PCR_C)
+
+99:
+ msr cpsr_c, ip
+ 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:
+ mov ip, #(PCR_C)
+ msr cpsr_c, ip
+ RET
+END(__aeabi_cfcmpeq)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/arm/aeabi/aeabi_atexit.c b/lib/libc/arm/aeabi/aeabi_atexit.c
new file mode 100644
index 000000000000..8502595385df
--- /dev/null
+++ b/lib/libc/arm/aeabi/aeabi_atexit.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2012 Andrew Turner
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+int __cxa_atexit(void (*)(void *), void *, void *);
+
+int
+__aeabi_atexit(void *object, void (*func)(void*), void *dso)
+{
+ return __cxa_atexit(func, object, dso);
+}
+
diff --git a/lib/libc/arm/aeabi/aeabi_double.c b/lib/libc/arm/aeabi/aeabi_double.c
new file mode 100644
index 000000000000..a69e8a74b3cc
--- /dev/null
+++ b/lib/libc/arm/aeabi/aeabi_double.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2012 Andrew Turner
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "softfloat-for-gcc.h"
+#include "milieu.h"
+#include "softfloat.h"
+
+#include "aeabi_vfp.h"
+
+extern int _libc_arm_fpu_present;
+
+flag __unorddf2(float64, float64);
+
+/* These are written in asm and are only called from this file */
+int __aeabi_dcmpeq_vfp(float64, float64);
+int __aeabi_dcmplt_vfp(float64, float64);
+int __aeabi_dcmple_vfp(float64, float64);
+int __aeabi_dcmpgt_vfp(float64, float64);
+int __aeabi_dcmpge_vfp(float64, float64);
+int __aeabi_dcmpun_vfp(float64, float64);
+int __aeabi_d2iz_vfp(float64);
+float32 __aeabi_d2f_vfp(float64);
+float64 __aeabi_i2d_vfp(int);
+float64 __aeabi_dadd_vfp(float64, float64);
+float64 __aeabi_ddiv_vfp(float64, float64);
+float64 __aeabi_dmul_vfp(float64, float64);
+float64 __aeabi_dsub_vfp(float64, float64);
+
+/*
+ * Depending on the target these will:
+ * On armv6 with a vfp call the above function, or
+ * Call the softfloat function in the 3rd argument.
+ */
+int AEABI_FUNC2(dcmpeq, float64, float64_eq)
+int AEABI_FUNC2(dcmplt, float64, float64_lt)
+int AEABI_FUNC2(dcmple, float64, float64_le)
+int AEABI_FUNC2_REV(dcmpge, float64, float64_le)
+int AEABI_FUNC2_REV(dcmpgt, float64, float64_lt)
+int AEABI_FUNC2(dcmpun, float64, __unorddf2)
+
+int AEABI_FUNC(d2iz, float64, float64_to_int32_round_to_zero)
+float32 AEABI_FUNC(d2f, float64, float64_to_float32)
+float64 AEABI_FUNC(i2d, int, int32_to_float64)
+
+float64 AEABI_FUNC2(dadd, float64, float64_add)
+float64 AEABI_FUNC2(ddiv, float64, float64_div)
+float64 AEABI_FUNC2(dmul, float64, float64_mul)
+float64 AEABI_FUNC2(dsub, float64, float64_sub)
+
+int
+__aeabi_cdcmpeq_helper(float64 a, float64 b)
+{
+ int quiet = 0;
+
+ /* Check if a is a NaN */
+ if ((a << 1) > 0xffe0000000000000ull) {
+ /* If it's a signalling NaN we will always signal */
+ if ((a & 0x0008000000000000ull) == 0)
+ return (0);
+
+ quiet = 1;
+ }
+
+ /* Check if b is a NaN */
+ if ((b << 1) > 0xffe0000000000000ull) {
+ /* If it's a signalling NaN we will always signal */
+ if ((b & 0x0008000000000000ull) == 0)
+ return (0);
+
+ quiet = 1;
+ }
+
+ return (quiet);
+}
diff --git a/lib/libc/arm/aeabi/aeabi_float.c b/lib/libc/arm/aeabi/aeabi_float.c
new file mode 100644
index 000000000000..2e93594c2105
--- /dev/null
+++ b/lib/libc/arm/aeabi/aeabi_float.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2012 Andrew Turner
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "softfloat-for-gcc.h"
+#include "milieu.h"
+#include "softfloat.h"
+
+#include "aeabi_vfp.h"
+
+extern int _libc_arm_fpu_present;
+
+flag __unordsf2(float32, float32);
+
+/* These are written in asm and are only called from this file */
+int __aeabi_fcmpeq_vfp(float32, float32);
+int __aeabi_fcmplt_vfp(float32, float32);
+int __aeabi_fcmple_vfp(float32, float32);
+int __aeabi_fcmpgt_vfp(float32, float32);
+int __aeabi_fcmpge_vfp(float32, float32);
+int __aeabi_fcmpun_vfp(float32, float32);
+int __aeabi_f2iz_vfp(float32);
+float64 __aeabi_f2d_vfp(float32);
+float32 __aeabi_i2f_vfp(int);
+float32 __aeabi_fadd_vfp(float32, float32);
+float32 __aeabi_fdiv_vfp(float32, float32);
+float32 __aeabi_fmul_vfp(float32, float32);
+float32 __aeabi_fsub_vfp(float32, float32);
+
+/*
+ * Depending on the target these will:
+ * On armv6 with a vfp call the above function, or
+ * Call the softfloat function in the 3rd argument.
+ */
+int AEABI_FUNC2(fcmpeq, float32, float32_eq)
+int AEABI_FUNC2(fcmplt, float32, float32_lt)
+int AEABI_FUNC2(fcmple, float32, float32_le)
+int AEABI_FUNC2_REV(fcmpge, float32, float32_le)
+int AEABI_FUNC2_REV(fcmpgt, float32, float32_lt)
+int AEABI_FUNC2(fcmpun, float32, __unordsf2)
+
+int AEABI_FUNC(f2iz, float32, float32_to_int32_round_to_zero)
+float64 AEABI_FUNC(f2d, float32, float32_to_float64)
+float32 AEABI_FUNC(i2f, int, int32_to_float32)
+
+float32 AEABI_FUNC2(fadd, float32, float32_add)
+float32 AEABI_FUNC2(fdiv, float32, float32_div)
+float32 AEABI_FUNC2(fmul, float32, float32_mul)
+float32 AEABI_FUNC2(fsub, float32, float32_sub)
+
+int
+__aeabi_cfcmpeq_helper(float32 a, float32 b)
+{
+ int quiet = 0;
+
+ /* Check if a is a NaN */
+ if ((a << 1) > 0xff000000u) {
+ /* If it's a signalling NaN we will always signal */
+ if ((a & 0x00400000u) == 0)
+ return (0);
+
+ quiet = 1;
+ }
+
+ /* Check if b is a NaN */
+ if ((b << 1) > 0xff000000u) {
+ /* If it's a signalling NaN we will always signal */
+ if ((b & 0x00400000u) == 0)
+ return (0);
+
+ quiet = 1;
+ }
+
+ return (quiet);
+}
diff --git a/lib/libc/arm/aeabi/aeabi_unwind_cpp.c b/lib/libc/arm/aeabi/aeabi_unwind_cpp.c
new file mode 100644
index 000000000000..c07cbbde275b
--- /dev/null
+++ b/lib/libc/arm/aeabi/aeabi_unwind_cpp.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2011 Andrew Turner
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/*
+ * Provide an implementation of __aeabi_unwind_cpp_pr{0,1,2}. These are
+ * required by libc but are implemented in libgcc_eh.a which we don't link
+ * against. The libgcc_eh.a version will be called so we call abort to
+ * check this.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdlib.h>
+
+void __aeabi_unwind_cpp_pr0(void) __hidden;
+void __aeabi_unwind_cpp_pr1(void) __hidden;
+void __aeabi_unwind_cpp_pr2(void) __hidden;
+
+void
+__aeabi_unwind_cpp_pr0(void)
+{
+ abort();
+}
+
+void
+__aeabi_unwind_cpp_pr1(void)
+{
+ abort();
+}
+
+void
+__aeabi_unwind_cpp_pr2(void)
+{
+ abort();
+}
+
diff --git a/lib/libc/arm/aeabi/aeabi_unwind_exidx.c b/lib/libc/arm/aeabi/aeabi_unwind_exidx.c
new file mode 100644
index 000000000000..d5af8b3fc6e0
--- /dev/null
+++ b/lib/libc/arm/aeabi/aeabi_unwind_exidx.c
@@ -0,0 +1,104 @@
+/*-
+ * Copyright (c) 2014 Ian Lepore <ian@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <machine/elf.h>
+#include <link.h>
+#include <stddef.h>
+
+/*
+ * ARM EABI unwind helper.
+ *
+ * This finds the exidx section address and size associated with a given code
+ * address. There are separate implementations for static and dynamic code.
+ *
+ * GCC expects this function to exist as __gnu_Unwind_Find_exidx(), clang and
+ * BSD tools expect it to be dl_unwind_find_exidx(). Both have the same API, so
+ * we set up an alias for GCC.
+ */
+__strong_reference(dl_unwind_find_exidx, __gnu_Unwind_Find_exidx);
+
+/*
+ * Each entry in the exidx section is a pair of 32-bit words. We don't
+ * interpret the contents of the entries here; this typedef is just a local
+ * convenience for using sizeof() and doing pointer math.
+ */
+typedef struct exidx_entry {
+ uint32_t data[2];
+} exidx_entry;
+
+#ifdef __PIC__
+
+/*
+ * Unwind helper for dynamically linked code.
+ *
+ * This finds the shared object that contains the given address, and returns the
+ * address of the exidx section in that shared object along with the number of
+ * entries in that section, or NULL if it wasn't found.
+ */
+void *
+dl_unwind_find_exidx(const void *pc, int *pcount)
+{
+ const Elf_Phdr *hdr;
+ struct dl_phdr_info info;
+ int i;
+
+ if (_rtld_addr_phdr(pc, &info)) {
+ hdr = info.dlpi_phdr;
+ for (i = 0; i < info.dlpi_phnum; i++, hdr++) {
+ if (hdr->p_type == PT_ARM_EXIDX) {
+ *pcount = hdr->p_memsz / sizeof(exidx_entry);
+ return ((void *)(info.dlpi_addr + hdr->p_vaddr));
+ }
+ }
+ }
+ return (NULL);
+}
+
+#else /* !__PIC__ */
+
+/*
+ * Unwind helper for statically linked code.
+ *
+ * In a statically linked program, the linker populates a pair of symbols with
+ * the addresses of the start and end of the exidx table, so returning the
+ * address and count of elements is pretty straighforward.
+ */
+void *
+dl_unwind_find_exidx(const void *pc, int *pcount)
+{
+ extern struct exidx_entry __exidx_start;
+ extern struct exidx_entry __exidx_end;
+
+ *pcount = (int)(&__exidx_end - &__exidx_start);
+ return (&__exidx_start);
+}
+
+#endif /* __PIC__ */
+
diff --git a/lib/libc/arm/aeabi/aeabi_vfp.h b/lib/libc/arm/aeabi/aeabi_vfp.h
new file mode 100644
index 000000000000..927652f193ca
--- /dev/null
+++ b/lib/libc/arm/aeabi/aeabi_vfp.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2013 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.
+ *
+ * $FreeBSD$
+ *
+ */
+
+#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.
+ */
+
+/* Allow the name of the function to be changed depending on the ABI */
+#ifndef __ARM_PCS_VFP
+#define AEABI_ENTRY(x) ENTRY(__aeabi_ ## x ## _vfp)
+#define AEABI_END(x) END(__aeabi_ ## x ## _vfp)
+#else
+#define AEABI_ENTRY(x) ENTRY(__aeabi_ ## x)
+#define AEABI_END(x) END(__aeabi_ ## x)
+#endif
+
+/*
+ * These should be used when a function either takes, or returns a floating
+ * point falue. They will load the data from an ARM to a VFP register(s),
+ * or from a VFP to an ARM register
+ */
+#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
+#define LOAD_DREG(vreg, reg0, reg1) vmov vreg, reg0, reg1
+#define UNLOAD_DREG(reg0, reg1, vreg) vmov reg0, reg1, vreg
+#endif
+
+#define LOAD_SREGS(vreg0, vreg1, reg0, reg1) vmov vreg0, vreg1, reg0, reg1
+#define LOAD_SREG(vreg, reg) vmov vreg, reg
+#define UNLOAD_SREG(reg, vreg) vmov reg, vreg
+
+/*
+ * C Helper macros
+ */
+
+#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
+ * will take a single argument of the type given by in_type.
+ */
+#define AEABI_FUNC(name, in_type, soft_func) \
+__aeabi_ ## name(in_type a) \
+{ \
+ if (_libc_arm_fpu_present) \
+ return __aeabi_ ## name ## _vfp(a); \
+ else \
+ return soft_func (a); \
+}
+
+/* As above, but takes two arguments of the same type */
+#define AEABI_FUNC2(name, in_type, soft_func) \
+__aeabi_ ## name(in_type a, in_type b) \
+{ \
+ if (_libc_arm_fpu_present) \
+ return __aeabi_ ## name ## _vfp(a, b); \
+ else \
+ return soft_func (a, b); \
+}
+
+/* As above, but with the soft float arguments reversed */
+#define AEABI_FUNC2_REV(name, in_type, soft_func) \
+__aeabi_ ## name(in_type a, in_type b) \
+{ \
+ if (_libc_arm_fpu_present) \
+ return __aeabi_ ## name ## _vfp(a, b); \
+ else \
+ return soft_func (b, a); \
+}
+#else
+/*
+ * Helper macros for when we are only able to use the softfloat
+ * version of these functions, i.e. on arm before armv6.
+ */
+#define AEABI_FUNC(name, in_type, soft_func) \
+__aeabi_ ## name(in_type a) \
+{ \
+ return soft_func (a); \
+}
+
+/* As above, but takes two arguments of the same type */
+#define AEABI_FUNC2(name, in_type, soft_func) \
+__aeabi_ ## name(in_type a, in_type b) \
+{ \
+ return soft_func (a, b); \
+}
+
+/* As above, but with the soft float arguments reversed */
+#define AEABI_FUNC2_REV(name, in_type, soft_func) \
+__aeabi_ ## name(in_type a, in_type b) \
+{ \
+ return soft_func (b, a); \
+}
+#endif
+
+#endif
+
diff --git a/lib/libc/arm/aeabi/aeabi_vfp_double.S b/lib/libc/arm/aeabi/aeabi_vfp_double.S
new file mode 100644
index 000000000000..be4309dd6efc
--- /dev/null
+++ b/lib/libc/arm/aeabi/aeabi_vfp_double.S
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2013 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$");
+
+#include "aeabi_vfp.h"
+
+.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)
+ LOAD_DREG(d1, r2, r3)
+ vcmp.f64 d0, d1
+ vmrs APSR_nzcv, fpscr
+ ite ne
+ movne r0, #0
+ moveq r0, #1
+ RET
+AEABI_END(dcmpeq)
+
+/* int __aeabi_dcmplt(double, double) */
+AEABI_ENTRY(dcmplt)
+ LOAD_DREG(d0, r0, r1)
+ LOAD_DREG(d1, r2, r3)
+ vcmp.f64 d0, d1
+ vmrs APSR_nzcv, fpscr
+ ite cs
+ movcs r0, #0
+ movcc r0, #1
+ RET
+AEABI_END(dcmplt)
+
+/* int __aeabi_dcmple(double, double) */
+AEABI_ENTRY(dcmple)
+ LOAD_DREG(d0, r0, r1)
+ LOAD_DREG(d1, r2, r3)
+ vcmp.f64 d0, d1
+ vmrs APSR_nzcv, fpscr
+ ite hi
+ movhi r0, #0
+ movls r0, #1
+ RET
+AEABI_END(dcmple)
+
+/* int __aeabi_dcmpge(double, double) */
+AEABI_ENTRY(dcmpge)
+ LOAD_DREG(d0, r0, r1)
+ LOAD_DREG(d1, r2, r3)
+ vcmp.f64 d0, d1
+ vmrs APSR_nzcv, fpscr
+ ite lt
+ movlt r0, #0
+ movge r0, #1
+ RET
+AEABI_END(dcmpge)
+
+/* int __aeabi_dcmpgt(double, double) */
+AEABI_ENTRY(dcmpgt)
+ LOAD_DREG(d0, r0, r1)
+ LOAD_DREG(d1, r2, r3)
+ vcmp.f64 d0, d1
+ vmrs APSR_nzcv, fpscr
+ ite le
+ movle r0, #0
+ movgt r0, #1
+ RET
+AEABI_END(dcmpgt)
+
+/* int __aeabi_dcmpun(double, double) */
+AEABI_ENTRY(dcmpun)
+ LOAD_DREG(d0, r0, r1)
+ LOAD_DREG(d1, r2, r3)
+ vcmp.f64 d0, d1
+ vmrs APSR_nzcv, fpscr
+ ite vc
+ movvc r0, #0
+ movvs r0, #1
+ RET
+AEABI_END(dcmpun)
+
+/* int __aeabi_d2iz(double) */
+AEABI_ENTRY(d2iz)
+ LOAD_DREG(d0, r0, r1)
+#if 0
+ /*
+ * This should be the correct instruction, but binutils incorrectly
+ * encodes it as the version that used FPSCR to determine the rounding.
+ * When binutils is fixed we can use this again.
+ */
+ vcvt.s32.f64 s0, d0
+#else
+ ftosizd s0, d0
+#endif
+ vmov r0, s0
+ RET
+AEABI_END(d2iz)
+
+/* float __aeabi_d2f(double) */
+AEABI_ENTRY(d2f)
+ LOAD_DREG(d0, r0, r1)
+ vcvt.f32.f64 s0, d0
+ UNLOAD_SREG(r0, s0)
+ RET
+AEABI_END(d2f)
+
+/* double __aeabi_i2d(int) */
+AEABI_ENTRY(i2d)
+ vmov s0, r0
+ vcvt.f64.s32 d0, s0
+ UNLOAD_DREG(r0, r1, d0)
+ RET
+AEABI_END(i2d)
+
+/* double __aeabi_dadd(double, double) */
+AEABI_ENTRY(dadd)
+ LOAD_DREG(d0, r0, r1)
+ LOAD_DREG(d1, r2, r3)
+ vadd.f64 d0, d0, d1
+ UNLOAD_DREG(r0, r1, d0)
+ RET
+AEABI_END(dadd)
+
+/* double __aeabi_ddiv(double, double) */
+AEABI_ENTRY(ddiv)
+ LOAD_DREG(d0, r0, r1)
+ LOAD_DREG(d1, r2, r3)
+ vdiv.f64 d0, d0, d1
+ UNLOAD_DREG(r0, r1, d0)
+ RET
+AEABI_END(ddiv)
+
+/* double __aeabi_dmul(double, double) */
+AEABI_ENTRY(dmul)
+ LOAD_DREG(d0, r0, r1)
+ LOAD_DREG(d1, r2, r3)
+ vmul.f64 d0, d0, d1
+ UNLOAD_DREG(r0, r1, d0)
+ RET
+AEABI_END(dmul)
+
+/* double __aeabi_dsub(double, double) */
+AEABI_ENTRY(dsub)
+ LOAD_DREG(d0, r0, r1)
+ LOAD_DREG(d1, r2, r3)
+ vsub.f64 d0, d0, d1
+ UNLOAD_DREG(r0, r1, d0)
+ RET
+AEABI_END(dsub)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/arm/aeabi/aeabi_vfp_float.S b/lib/libc/arm/aeabi/aeabi_vfp_float.S
new file mode 100644
index 000000000000..c9df41cf4b2e
--- /dev/null
+++ b/lib/libc/arm/aeabi/aeabi_vfp_float.S
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2013 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$");
+
+#include "aeabi_vfp.h"
+
+.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)
+ vcmp.f32 s0, s1
+ vmrs APSR_nzcv, fpscr
+ ite ne
+ movne r0, #0
+ moveq r0, #1
+ RET
+AEABI_END(fcmpeq)
+
+/* int __aeabi_fcmplt(float, float) */
+AEABI_ENTRY(fcmplt)
+ LOAD_SREGS(s0, s1, r0, r1)
+ vcmp.f32 s0, s1
+ vmrs APSR_nzcv, fpscr
+ ite cs
+ movcs r0, #0
+ movcc r0, #1
+ RET
+AEABI_END(fcmplt)
+
+/* int __aeabi_fcmple(float, float) */
+AEABI_ENTRY(fcmple)
+ LOAD_SREGS(s0, s1, r0, r1)
+ vcmp.f32 s0, s1
+ vmrs APSR_nzcv, fpscr
+ ite hi
+ movhi r0, #0
+ movls r0, #1
+ RET
+AEABI_END(fcmple)
+
+/* int __aeabi_fcmpge(float, float) */
+AEABI_ENTRY(fcmpge)
+ LOAD_SREGS(s0, s1, r0, r1)
+ vcmp.f32 s0, s1
+ vmrs APSR_nzcv, fpscr
+ ite lt
+ movlt r0, #0
+ movge r0, #1
+ RET
+AEABI_END(fcmpge)
+
+/* int __aeabi_fcmpgt(float, float) */
+AEABI_ENTRY(fcmpgt)
+ LOAD_SREGS(s0, s1, r0, r1)
+ vcmp.f32 s0, s1
+ vmrs APSR_nzcv, fpscr
+ ite le
+ movle r0, #0
+ movgt r0, #1
+ RET
+AEABI_END(fcmpgt)
+
+/* int __aeabi_fcmpun(float, float) */
+AEABI_ENTRY(fcmpun)
+ LOAD_SREGS(s0, s1, r0, r1)
+ vcmp.f32 s0, s1
+ vmrs APSR_nzcv, fpscr
+ ite vc
+ movvc r0, #0
+ movvs r0, #1
+ RET
+AEABI_END(fcmpun)
+
+/* int __aeabi_f2iz(float) */
+AEABI_ENTRY(f2iz)
+ LOAD_SREG(s0, r0)
+#if 0
+ /*
+ * This should be the correct instruction, but binutils incorrectly
+ * encodes it as the version that used FPSCR to determine the rounding.
+ * When binutils is fixed we can use this again.
+ */
+ vcvt.s32.f32 s0, s0
+#else
+ ftosizs s0, s0
+#endif
+ vmov r0, s0
+ RET
+AEABI_END(f2iz)
+
+/* double __aeabi_f2d(float) */
+AEABI_ENTRY(f2d)
+ LOAD_SREG(s0, r0)
+ vcvt.f64.f32 d0, s0
+ UNLOAD_DREG(r0, r1, d0)
+ RET
+AEABI_END(f2d)
+
+/* float __aeabi_i2f(int) */
+AEABI_ENTRY(i2f)
+ vmov s0, r0
+ vcvt.f32.s32 s0, s0
+ UNLOAD_SREG(r0, s0)
+ RET
+AEABI_END(i2f)
+
+/* float __aeabi_fadd(float, float) */
+AEABI_ENTRY(fadd)
+ LOAD_SREGS(s0, s1, r0, r1)
+ vadd.f32 s0, s0, s1
+ UNLOAD_SREG(r0, s0)
+ RET
+AEABI_END(fadd)
+
+/* float __aeabi_fmul(float, float) */
+AEABI_ENTRY(fdiv)
+ LOAD_SREGS(s0, s1, r0, r1)
+ vdiv.f32 s0, s0, s1
+ UNLOAD_SREG(r0, s0)
+ RET
+AEABI_END(fdiv)
+
+/* float __aeabi_fmul(float, float) */
+AEABI_ENTRY(fmul)
+ LOAD_SREGS(s0, s1, r0, r1)
+ vmul.f32 s0, s0, s1
+ UNLOAD_SREG(r0, s0)
+ RET
+AEABI_END(fmul)
+
+/* float __aeabi_fsub(float, float) */
+AEABI_ENTRY(fsub)
+ LOAD_SREGS(s0, s1, r0, r1)
+ vsub.f32 s0, s0, s1
+ UNLOAD_SREG(r0, s0)
+ RET
+AEABI_END(fsub)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/arm/arith.h b/lib/libc/arm/arith.h
new file mode 100644
index 000000000000..5e2e3891dd91
--- /dev/null
+++ b/lib/libc/arm/arith.h
@@ -0,0 +1,21 @@
+/*
+ * MD header for contrib/gdtoa
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * NOTE: The definitions in this file must be correct or strtod(3) and
+ * floating point formats in printf(3) will break! The file can be
+ * generated by running contrib/gdtoa/arithchk.c on the target
+ * architecture. See contrib/gdtoa/gdtoaimp.h for details.
+ */
+
+#if !defined(__ARMEB__) && (defined(__VFP_FP__) || defined(__ARM_EABI__))
+#define IEEE_8087
+#define Arith_Kind_ASL 1
+#define Sudden_Underflow
+#else
+#define IEEE_MC68k
+#define Arith_Kind_ASL 2
+#endif
diff --git a/lib/libc/arm/gd_qnan.h b/lib/libc/arm/gd_qnan.h
new file mode 100644
index 000000000000..8fa9edd83415
--- /dev/null
+++ b/lib/libc/arm/gd_qnan.h
@@ -0,0 +1,23 @@
+/*
+ * MD header for contrib/gdtoa
+ *
+ * This file can be generated by compiling and running contrib/gdtoa/qnan.c
+ * on the target architecture after arith.h has been generated.
+ *
+ * XXX I don't have ARM hardware, so I just guessed. --das
+ *
+ * $FreeBSD$
+ */
+
+#define f_QNAN 0x7fc00000
+#define d_QNAN0 0x0
+#define d_QNAN1 0x7ff80000
+#define ld_QNAN0 0x0
+#define ld_QNAN1 0xc0000000
+#define ld_QNAN2 0x7fff
+#define ld_QNAN3 0x0
+#define ldus_QNAN0 0x0
+#define ldus_QNAN1 0x0
+#define ldus_QNAN2 0x0
+#define ldus_QNAN3 0xc000
+#define ldus_QNAN4 0x7fff
diff --git a/lib/libc/arm/gen/Makefile.inc b/lib/libc/arm/gen/Makefile.inc
new file mode 100644
index 000000000000..615ee17dc449
--- /dev/null
+++ b/lib/libc/arm/gen/Makefile.inc
@@ -0,0 +1,13 @@
+# @(#)Makefile.inc 8.1 (Berkeley) 6/4/93
+# $FreeBSD$
+
+SRCS+= _ctx_start.S _setjmp.S _set_tp.c alloca.S fabs.c \
+ infinity.c ldexp.c makecontext.c \
+ __aeabi_read_tp.S setjmp.S signalcontext.c sigsetjmp.S flt_rounds.c \
+ arm_initfini.c \
+ trivial-getcontextx.c
+
+.if ${MACHINE_ARCH:Marmv6*} && (!defined(CPUTYPE) || ${CPUTYPE:M*soft*} == "")
+SRCS+= fpgetmask_vfp.c fpgetround_vfp.c fpgetsticky_vfp.c fpsetmask_vfp.c \
+ fpsetround_vfp.c fpsetsticky_vfp.c
+.endif
diff --git a/lib/libc/arm/gen/__aeabi_read_tp.S b/lib/libc/arm/gen/__aeabi_read_tp.S
new file mode 100644
index 000000000000..224d6a632185
--- /dev/null
+++ b/lib/libc/arm/gen/__aeabi_read_tp.S
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 2012 Oleksandr Tymoshenko
+ * Copyright (c) 2012 Andrew Turner
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include <machine/sysarch.h>
+
+ENTRY(__aeabi_read_tp)
+#ifdef ARM_TP_ADDRESS
+ ldr r0, .Larm_tp_address
+ ldr r0, [r0]
+#else
+ mrc p15, 0, r0, c13, c0, 3
+#endif
+ RET
+END(__aeabi_read_tp)
+
+#ifdef ARM_TP_ADDRESS
+.Larm_tp_address:
+ .word ARM_TP_ADDRESS
+#endif
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/arm/gen/_ctx_start.S b/lib/libc/arm/gen/_ctx_start.S
new file mode 100644
index 000000000000..faedfb5c6443
--- /dev/null
+++ b/lib/libc/arm/gen/_ctx_start.S
@@ -0,0 +1,12 @@
+#include <machine/asm.h>
+
+.ident "$FreeBSD$"
+ENTRY(_ctx_start)
+ mov lr, pc
+ mov pc, r4
+ mov r0, r5
+ bl _C_LABEL(ctx_done)
+ bl _C_LABEL(abort)
+END(_ctx_start)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/arm/gen/_set_tp.c b/lib/libc/arm/gen/_set_tp.c
new file mode 100644
index 000000000000..2332f599a919
--- /dev/null
+++ b/lib/libc/arm/gen/_set_tp.c
@@ -0,0 +1,44 @@
+/*-
+ * Copyright (c) 2004 Doug Rabson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <string.h>
+#include <sys/types.h>
+
+#include <machine/sysarch.h>
+#include "libc_private.h"
+
+void
+_set_tp(void *tp)
+{
+
+#ifdef ARM_TP_ADDRESS
+ *((struct tcb **)ARM_TP_ADDRESS) = tp;
+#else
+ sysarch(ARM_SET_TP, tp);
+#endif
+}
diff --git a/lib/libc/arm/gen/_setjmp.S b/lib/libc/arm/gen/_setjmp.S
new file mode 100644
index 000000000000..e3c67fa7b9bb
--- /dev/null
+++ b/lib/libc/arm/gen/_setjmp.S
@@ -0,0 +1,161 @@
+/* $NetBSD: _setjmp.S,v 1.12 2013/04/19 13:45:45 matt Exp $ */
+
+/*
+ * Copyright (c) 1997 Mark Brinicombe
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Mark Brinicombe
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if !defined(__SOFTFP__) && !defined(__VFP_FP__) && !defined(__ARM_PCS)
+#error FPA is not supported anymore
+#endif
+
+#if !defined(_STANDALONE)
+ .fpu vfp
+#endif
+
+#include <machine/asm.h>
+#include <machine/setjmp.h>
+
+__FBSDID("$FreeBSD$");
+
+/*
+ * C library -- _setjmp, _longjmp
+ *
+ * _longjmp(a,v)
+ * will generate a "return(v)" from the last call to
+ * _setjmp(a)
+ * by restoring registers from the stack.
+ * The previous signal state is NOT restored.
+ *
+ * Note: r0 is the return value
+ * r1-r3,ip are scratch registers in functions
+ */
+
+ENTRY(_setjmp)
+ ldr r1, .L_setjmp_magic
+
+#if !defined(_STANDALONE)
+ ldr r2, .Lfpu_present
+#ifdef PIC
+ GOT_INIT(r3, .L_setjmp_got, .L_setjmp_gotinit)
+ ldr r2, [r2, r3]
+#else
+ ldr r2, [r2]
+#endif
+ teq r2, #0 /* do we have a FPU? */
+ beq 1f /* no, don't save VFP registers */
+
+ orr r1, r1, #(_JB_MAGIC__SETJMP ^ _JB_MAGIC__SETJMP_VFP)
+ /* change magic to VFP magic */
+ add r2, r0, #(_JB_REG_D8 * 4)
+ vstmia r2, {d8-d15}
+ vmrs r2, fpscr
+ str r2, [r0, #(_JB_REG_FPSCR * 4)]
+1:
+#endif /* !_STANDALONE */
+
+ str r1, [r0]
+
+ add r0, r0, #(_JB_REG_R4 * 4)
+ /* Store integer registers */
+#ifndef __thumb__
+ stmia r0, {r4-r14}
+#else
+ stmia r0, {r4-r12}
+ str r13, [r0, #((_JB_REG_R13 - _JB_REG_R4) * 4)]
+ str r14, [r0, #((_JB_REG_R14 - _JB_REG_R4) * 4)]
+#endif
+
+ mov r0, #0x00000000
+ RET
+END(_setjmp)
+
+.L_setjmp_magic:
+ .word _JB_MAGIC__SETJMP
+#if !defined(_STANDALONE)
+ GOT_INITSYM(.L_setjmp_got, .L_setjmp_gotinit)
+.Lfpu_present:
+ .word PIC_SYM(_libc_arm_fpu_present, GOTOFF)
+#endif /* !_STANDALONE */
+
+WEAK_ALIAS(___longjmp, _longjmp)
+ENTRY(_longjmp)
+ ldr r2, [r0] /* get magic from jmp_buf */
+ bic r3, r2, #(_JB_MAGIC__SETJMP ^ _JB_MAGIC__SETJMP_VFP)
+ /* ignore VFP-ness of magic */
+ ldr ip, .L_setjmp_magic /* load magic */
+ teq ip, r3 /* magic correct? */
+ bne botch /* no, botch */
+
+#if !defined(_STANDALONE)
+ teq r3, r2 /* did magic change? */
+ beq 1f /* no, don't restore VFP */
+ add ip, r0, #(_JB_REG_D8 * 4)
+ vldmia ip, {d8-d15}
+ ldr ip, [r0, #(_JB_REG_FPSCR * 4)]
+ vmsr fpscr, ip
+1:
+#endif /* !_STANDALONE */
+
+ add r0, r0, #(_JB_REG_R4 * 4)
+ /* Restore integer registers */
+#ifndef __thumb__
+ ldmia r0, {r4-r14}
+#else
+ ldmia r0, {r4-r12}
+ ldr r13, [r0, #((_JB_REG_R13 - _JB_REG_R4) * 4)]
+ ldr r14, [r0, #((_JB_REG_R14 - _JB_REG_R4) * 4)]
+#endif
+
+ /* Validate sp and r14 */
+ teq sp, #0
+ it ne
+ teqne r14, #0
+ it eq
+ beq botch
+
+ /* Set return value */
+ movs r0, r1
+ it eq
+ moveq r0, #0x00000001
+ RET
+
+ /* validation failed, die die die. */
+botch:
+#if !defined(_STANDALONE)
+ bl PIC_SYM(_C_LABEL(longjmperror), PLT)
+ bl PIC_SYM(_C_LABEL(abort), PLT)
+1: b 1b /* Cannot get here */
+#else
+ b .
+#endif
+END(_longjmp)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/arm/gen/alloca.S b/lib/libc/arm/gen/alloca.S
new file mode 100644
index 000000000000..2539b7a80c97
--- /dev/null
+++ b/lib/libc/arm/gen/alloca.S
@@ -0,0 +1,48 @@
+/* $NetBSD: alloca.S,v 1.3 2003/04/05 23:08:51 bjh21 Exp $ */
+
+/*
+ * Copyright (c) 1995 Mark Brinicombe
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Mark Brinicombe
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* like alloc, but automatic automatic free in return */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+ENTRY(alloca)
+ add r0, r0, #0x00000007 /* round up to next 8 byte alignment */
+ bic r0, r0, #0x00000007
+ sub sp, sp, r0 /* Adjust the stack pointer */
+ mov r0, sp /* r0 = base of new space */
+ RET
+END(alloca)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/arm/gen/arm_initfini.c b/lib/libc/arm/gen/arm_initfini.c
new file mode 100644
index 000000000000..9def8c8dfbcb
--- /dev/null
+++ b/lib/libc/arm/gen/arm_initfini.c
@@ -0,0 +1,78 @@
+/*-
+ * Copyright (c) 2013 The NetBSD Foundation, Inc.
+ * Copyright (c) 2013 Andrew Turner
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Matt Thomas of 3am Software Foundry.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Bases on NetBSD lib/libc/arch/arm/misc/arm_initfini.c
+ * $NetBSD: arm_initfini.c,v 1.2 2013/01/31 06:47:55 matt Exp $
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * To properly implement setjmp/longjmp for the ARM AAPCS ABI, it has to be
+ * aware of whether there is a FPU is present or not. Regardless of whether
+ * the hard-float ABI is being used, setjmp needs to save D8-D15. But it can
+ * only do this if those instructions won't cause an exception.
+ */
+
+#include <sys/param.h>
+#include <sys/sysctl.h>
+
+#include <stdbool.h>
+#include <stddef.h>
+
+extern int __sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
+ void *newp, size_t newlen);
+
+int _libc_arm_fpu_present;
+static bool _libc_aapcs_initialized;
+
+void _libc_aapcs_init(void) __attribute__((__constructor__, __used__));
+
+void
+_libc_aapcs_init(void)
+{
+ int mib[2];
+ size_t len;
+
+ if (_libc_aapcs_initialized)
+ return;
+
+ mib[0] = CTL_HW;
+ mib[1] = HW_FLOATINGPT;
+
+ len = sizeof(_libc_arm_fpu_present);
+ if (__sysctl(mib, 2, &_libc_arm_fpu_present, &len, NULL, 0) == -1 ||
+ len != sizeof(_libc_arm_fpu_present)) {
+ /* sysctl failed, assume no vfp */
+ _libc_arm_fpu_present = 0;
+ }
+
+ _libc_aapcs_initialized = true;
+}
diff --git a/lib/libc/arm/gen/divsi3.S b/lib/libc/arm/gen/divsi3.S
new file mode 100644
index 000000000000..fac0663cdb2a
--- /dev/null
+++ b/lib/libc/arm/gen/divsi3.S
@@ -0,0 +1,393 @@
+/* $NetBSD: divsi3.S,v 1.4 2003/04/05 23:27:15 bjh21 Exp $ */
+
+/*
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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$");
+
+/*
+ * stack is aligned as there's a possibility of branching to L_overflow
+ * which makes a C call
+ */
+
+ENTRY(__umodsi3)
+ stmfd sp!, {lr}
+ sub sp, sp, #4 /* align stack */
+ bl .L_udivide
+ add sp, sp, #4 /* unalign stack */
+ mov r0, r1
+ ldmfd sp!, {pc}
+END(__umodsi3)
+
+ENTRY(__modsi3)
+ stmfd sp!, {lr}
+ sub sp, sp, #4 /* align stack */
+ bl .L_divide
+ add sp, sp, #4 /* unalign stack */
+ mov r0, r1
+ ldmfd sp!, {pc}
+
+.L_overflow:
+#if !defined(_KERNEL) && !defined(_STANDALONE)
+ mov r0, #8 /* SIGFPE */
+ bl PIC_SYM(_C_LABEL(raise), PLT) /* raise it */
+ mov r0, #0
+#else
+ /* XXX should cause a fatal error */
+ mvn r0, #0
+#endif
+ RET
+END(__modsi3)
+
+ENTRY(__udivsi3)
+.L_udivide: /* r0 = r0 / r1; r1 = r0 % r1 */
+ eor r0, r1, r0
+ eor r1, r0, r1
+ eor r0, r1, r0
+ /* r0 = r1 / r0; r1 = r1 % r0 */
+ cmp r0, #1
+ bcc .L_overflow
+ beq .L_divide_l0
+ mov ip, #0
+ movs r1, r1
+ bpl .L_divide_l1
+ orr ip, ip, #0x20000000 /* ip bit 0x20000000 = -ve r1 */
+ movs r1, r1, lsr #1
+ orrcs ip, ip, #0x10000000 /* ip bit 0x10000000 = bit 0 of r1 */
+ b .L_divide_l1
+
+.L_divide_l0: /* r0 == 1 */
+ mov r0, r1
+ mov r1, #0
+ RET
+END(__udivsi3)
+
+ENTRY(__divsi3)
+.L_divide: /* r0 = r0 / r1; r1 = r0 % r1 */
+ eor r0, r1, r0
+ eor r1, r0, r1
+ eor r0, r1, r0
+ /* r0 = r1 / r0; r1 = r1 % r0 */
+ cmp r0, #1
+ bcc .L_overflow
+ beq .L_divide_l0
+ ands ip, r0, #0x80000000
+ rsbmi r0, r0, #0
+ ands r2, r1, #0x80000000
+ eor ip, ip, r2
+ rsbmi r1, r1, #0
+ orr ip, r2, ip, lsr #1 /* ip bit 0x40000000 = -ve division */
+ /* ip bit 0x80000000 = -ve remainder */
+
+.L_divide_l1:
+ mov r2, #1
+ mov r3, #0
+
+ /*
+ * If the highest bit of the dividend is set, we have to be
+ * careful when shifting the divisor. Test this.
+ */
+ movs r1,r1
+ bpl .L_old_code
+
+ /*
+ * At this point, the highest bit of r1 is known to be set.
+ * We abuse this below in the tst instructions.
+ */
+ tst r1, r0 /*, lsl #0 */
+ bmi .L_divide_b1
+ tst r1, r0, lsl #1
+ bmi .L_divide_b2
+ tst r1, r0, lsl #2
+ bmi .L_divide_b3
+ tst r1, r0, lsl #3
+ bmi .L_divide_b4
+ tst r1, r0, lsl #4
+ bmi .L_divide_b5
+ tst r1, r0, lsl #5
+ bmi .L_divide_b6
+ tst r1, r0, lsl #6
+ bmi .L_divide_b7
+ tst r1, r0, lsl #7
+ bmi .L_divide_b8
+ tst r1, r0, lsl #8
+ bmi .L_divide_b9
+ tst r1, r0, lsl #9
+ bmi .L_divide_b10
+ tst r1, r0, lsl #10
+ bmi .L_divide_b11
+ tst r1, r0, lsl #11
+ bmi .L_divide_b12
+ tst r1, r0, lsl #12
+ bmi .L_divide_b13
+ tst r1, r0, lsl #13
+ bmi .L_divide_b14
+ tst r1, r0, lsl #14
+ bmi .L_divide_b15
+ tst r1, r0, lsl #15
+ bmi .L_divide_b16
+ tst r1, r0, lsl #16
+ bmi .L_divide_b17
+ tst r1, r0, lsl #17
+ bmi .L_divide_b18
+ tst r1, r0, lsl #18
+ bmi .L_divide_b19
+ tst r1, r0, lsl #19
+ bmi .L_divide_b20
+ tst r1, r0, lsl #20
+ bmi .L_divide_b21
+ tst r1, r0, lsl #21
+ bmi .L_divide_b22
+ tst r1, r0, lsl #22
+ bmi .L_divide_b23
+ tst r1, r0, lsl #23
+ bmi .L_divide_b24
+ tst r1, r0, lsl #24
+ bmi .L_divide_b25
+ tst r1, r0, lsl #25
+ bmi .L_divide_b26
+ tst r1, r0, lsl #26
+ bmi .L_divide_b27
+ tst r1, r0, lsl #27
+ bmi .L_divide_b28
+ tst r1, r0, lsl #28
+ bmi .L_divide_b29
+ tst r1, r0, lsl #29
+ bmi .L_divide_b30
+ tst r1, r0, lsl #30
+ bmi .L_divide_b31
+/*
+ * instead of:
+ * tst r1, r0, lsl #31
+ * bmi .L_divide_b32
+ */
+ b .L_divide_b32
+
+.L_old_code:
+ cmp r1, r0
+ bcc .L_divide_b0
+ cmp r1, r0, lsl #1
+ bcc .L_divide_b1
+ cmp r1, r0, lsl #2
+ bcc .L_divide_b2
+ cmp r1, r0, lsl #3
+ bcc .L_divide_b3
+ cmp r1, r0, lsl #4
+ bcc .L_divide_b4
+ cmp r1, r0, lsl #5
+ bcc .L_divide_b5
+ cmp r1, r0, lsl #6
+ bcc .L_divide_b6
+ cmp r1, r0, lsl #7
+ bcc .L_divide_b7
+ cmp r1, r0, lsl #8
+ bcc .L_divide_b8
+ cmp r1, r0, lsl #9
+ bcc .L_divide_b9
+ cmp r1, r0, lsl #10
+ bcc .L_divide_b10
+ cmp r1, r0, lsl #11
+ bcc .L_divide_b11
+ cmp r1, r0, lsl #12
+ bcc .L_divide_b12
+ cmp r1, r0, lsl #13
+ bcc .L_divide_b13
+ cmp r1, r0, lsl #14
+ bcc .L_divide_b14
+ cmp r1, r0, lsl #15
+ bcc .L_divide_b15
+ cmp r1, r0, lsl #16
+ bcc .L_divide_b16
+ cmp r1, r0, lsl #17
+ bcc .L_divide_b17
+ cmp r1, r0, lsl #18
+ bcc .L_divide_b18
+ cmp r1, r0, lsl #19
+ bcc .L_divide_b19
+ cmp r1, r0, lsl #20
+ bcc .L_divide_b20
+ cmp r1, r0, lsl #21
+ bcc .L_divide_b21
+ cmp r1, r0, lsl #22
+ bcc .L_divide_b22
+ cmp r1, r0, lsl #23
+ bcc .L_divide_b23
+ cmp r1, r0, lsl #24
+ bcc .L_divide_b24
+ cmp r1, r0, lsl #25
+ bcc .L_divide_b25
+ cmp r1, r0, lsl #26
+ bcc .L_divide_b26
+ cmp r1, r0, lsl #27
+ bcc .L_divide_b27
+ cmp r1, r0, lsl #28
+ bcc .L_divide_b28
+ cmp r1, r0, lsl #29
+ bcc .L_divide_b29
+ cmp r1, r0, lsl #30
+ bcc .L_divide_b30
+.L_divide_b32:
+ cmp r1, r0, lsl #31
+ subhs r1, r1,r0, lsl #31
+ addhs r3, r3,r2, lsl #31
+.L_divide_b31:
+ cmp r1, r0, lsl #30
+ subhs r1, r1,r0, lsl #30
+ addhs r3, r3,r2, lsl #30
+.L_divide_b30:
+ cmp r1, r0, lsl #29
+ subhs r1, r1,r0, lsl #29
+ addhs r3, r3,r2, lsl #29
+.L_divide_b29:
+ cmp r1, r0, lsl #28
+ subhs r1, r1,r0, lsl #28
+ addhs r3, r3,r2, lsl #28
+.L_divide_b28:
+ cmp r1, r0, lsl #27
+ subhs r1, r1,r0, lsl #27
+ addhs r3, r3,r2, lsl #27
+.L_divide_b27:
+ cmp r1, r0, lsl #26
+ subhs r1, r1,r0, lsl #26
+ addhs r3, r3,r2, lsl #26
+.L_divide_b26:
+ cmp r1, r0, lsl #25
+ subhs r1, r1,r0, lsl #25
+ addhs r3, r3,r2, lsl #25
+.L_divide_b25:
+ cmp r1, r0, lsl #24
+ subhs r1, r1,r0, lsl #24
+ addhs r3, r3,r2, lsl #24
+.L_divide_b24:
+ cmp r1, r0, lsl #23
+ subhs r1, r1,r0, lsl #23
+ addhs r3, r3,r2, lsl #23
+.L_divide_b23:
+ cmp r1, r0, lsl #22
+ subhs r1, r1,r0, lsl #22
+ addhs r3, r3,r2, lsl #22
+.L_divide_b22:
+ cmp r1, r0, lsl #21
+ subhs r1, r1,r0, lsl #21
+ addhs r3, r3,r2, lsl #21
+.L_divide_b21:
+ cmp r1, r0, lsl #20
+ subhs r1, r1,r0, lsl #20
+ addhs r3, r3,r2, lsl #20
+.L_divide_b20:
+ cmp r1, r0, lsl #19
+ subhs r1, r1,r0, lsl #19
+ addhs r3, r3,r2, lsl #19
+.L_divide_b19:
+ cmp r1, r0, lsl #18
+ subhs r1, r1,r0, lsl #18
+ addhs r3, r3,r2, lsl #18
+.L_divide_b18:
+ cmp r1, r0, lsl #17
+ subhs r1, r1,r0, lsl #17
+ addhs r3, r3,r2, lsl #17
+.L_divide_b17:
+ cmp r1, r0, lsl #16
+ subhs r1, r1,r0, lsl #16
+ addhs r3, r3,r2, lsl #16
+.L_divide_b16:
+ cmp r1, r0, lsl #15
+ subhs r1, r1,r0, lsl #15
+ addhs r3, r3,r2, lsl #15
+.L_divide_b15:
+ cmp r1, r0, lsl #14
+ subhs r1, r1,r0, lsl #14
+ addhs r3, r3,r2, lsl #14
+.L_divide_b14:
+ cmp r1, r0, lsl #13
+ subhs r1, r1,r0, lsl #13
+ addhs r3, r3,r2, lsl #13
+.L_divide_b13:
+ cmp r1, r0, lsl #12
+ subhs r1, r1,r0, lsl #12
+ addhs r3, r3,r2, lsl #12
+.L_divide_b12:
+ cmp r1, r0, lsl #11
+ subhs r1, r1,r0, lsl #11
+ addhs r3, r3,r2, lsl #11
+.L_divide_b11:
+ cmp r1, r0, lsl #10
+ subhs r1, r1,r0, lsl #10
+ addhs r3, r3,r2, lsl #10
+.L_divide_b10:
+ cmp r1, r0, lsl #9
+ subhs r1, r1,r0, lsl #9
+ addhs r3, r3,r2, lsl #9
+.L_divide_b9:
+ cmp r1, r0, lsl #8
+ subhs r1, r1,r0, lsl #8
+ addhs r3, r3,r2, lsl #8
+.L_divide_b8:
+ cmp r1, r0, lsl #7
+ subhs r1, r1,r0, lsl #7
+ addhs r3, r3,r2, lsl #7
+.L_divide_b7:
+ cmp r1, r0, lsl #6
+ subhs r1, r1,r0, lsl #6
+ addhs r3, r3,r2, lsl #6
+.L_divide_b6:
+ cmp r1, r0, lsl #5
+ subhs r1, r1,r0, lsl #5
+ addhs r3, r3,r2, lsl #5
+.L_divide_b5:
+ cmp r1, r0, lsl #4
+ subhs r1, r1,r0, lsl #4
+ addhs r3, r3,r2, lsl #4
+.L_divide_b4:
+ cmp r1, r0, lsl #3
+ subhs r1, r1,r0, lsl #3
+ addhs r3, r3,r2, lsl #3
+.L_divide_b3:
+ cmp r1, r0, lsl #2
+ subhs r1, r1,r0, lsl #2
+ addhs r3, r3,r2, lsl #2
+.L_divide_b2:
+ cmp r1, r0, lsl #1
+ subhs r1, r1,r0, lsl #1
+ addhs r3, r3,r2, lsl #1
+.L_divide_b1:
+ cmp r1, r0
+ subhs r1, r1, r0
+ addhs r3, r3, r2
+.L_divide_b0:
+
+ tst ip, #0x20000000
+ bne .L_udivide_l1
+ mov r0, r3
+ cmp ip, #0
+ rsbmi r1, r1, #0
+ movs ip, ip, lsl #1
+ bicmi r0, r0, #0x80000000 /* Fix incase we divided 0x80000000 */
+ rsbmi r0, r0, #0
+ RET
+
+.L_udivide_l1:
+ tst ip, #0x10000000
+ mov r1, r1, lsl #1
+ orrne r1, r1, #1
+ mov r3, r3, lsl #1
+ cmp r1, r0
+ subhs r1, r1, r0
+ addhs r3, r3, r2
+ mov r0, r3
+ RET
+END(__divsi3)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/arm/gen/fabs.c b/lib/libc/arm/gen/fabs.c
new file mode 100644
index 000000000000..8bb15025aead
--- /dev/null
+++ b/lib/libc/arm/gen/fabs.c
@@ -0,0 +1,46 @@
+/* $NetBSD: fabs.c,v 1.2 2002/05/26 11:48:01 wiz Exp $ */
+
+/*
+ * Copyright (c) 1996 Mark Brinicombe
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Mark Brinicombe
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * fabs(x) returns the absolute value of x.
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+double
+fabs(double x)
+{
+ if (x < 0)
+ x = -x;
+ return(x);
+}
diff --git a/lib/libc/arm/gen/flt_rounds.c b/lib/libc/arm/gen/flt_rounds.c
new file mode 100644
index 000000000000..86509d233231
--- /dev/null
+++ b/lib/libc/arm/gen/flt_rounds.c
@@ -0,0 +1,69 @@
+/*-
+ * Copyright (c) 2012 Ian Lepore <freebsd@damnhippie.dyndns.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <fenv.h>
+#include <float.h>
+
+#ifndef __ARM_PCS_VFP
+#include "softfloat-for-gcc.h"
+#include "milieu.h"
+#include "softfloat.h"
+#endif
+
+int
+__flt_rounds(void)
+{
+ int mode;
+
+#ifndef __ARM_PCS_VFP
+ /*
+ * Translate our rounding modes to the unnamed
+ * manifest constants required by C99 et. al.
+ */
+ mode = __softfloat_float_rounding_mode;
+#else /* __ARM_PCS_VFP */
+ /*
+ * Read the floating-point status and control register
+ */
+ __asm __volatile("vmrs %0, fpscr" : "=&r"(mode));
+ mode &= _ROUND_MASK;
+#endif /* __ARM_PCS_VFP */
+
+ switch (mode) {
+ case FE_TOWARDZERO:
+ return (0);
+ case FE_TONEAREST:
+ return (1);
+ case FE_UPWARD:
+ return (2);
+ case FE_DOWNWARD:
+ return (3);
+ }
+ return (-1);
+}
diff --git a/lib/libc/arm/gen/fpgetmask_vfp.c b/lib/libc/arm/gen/fpgetmask_vfp.c
new file mode 100644
index 000000000000..7c4d76fc403d
--- /dev/null
+++ b/lib/libc/arm/gen/fpgetmask_vfp.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2014 Andrew Turner
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <ieeefp.h>
+
+#ifdef __weak_alias
+__weak_alias(fpgetmask,_fpgetmask)
+#endif
+
+#define FP_X_MASK (FP_X_INV | FP_X_DZ | FP_X_OFL | FP_X_UFL | FP_X_IMP)
+
+fp_except_t
+fpgetmask(void)
+{
+ fp_except mask;
+
+ __asm __volatile("vmrs %0, fpscr" : "=&r"(mask));
+
+ return ((mask >> 8) & FP_X_MASK);
+}
+
diff --git a/lib/libc/arm/gen/fpgetround_vfp.c b/lib/libc/arm/gen/fpgetround_vfp.c
new file mode 100644
index 000000000000..ed9438865649
--- /dev/null
+++ b/lib/libc/arm/gen/fpgetround_vfp.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2014 Andrew Turner
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <ieeefp.h>
+
+#ifdef __weak_alias
+__weak_alias(fpgetround,_fpgetround)
+#endif
+
+fp_rnd_t
+fpgetround(void)
+{
+ uint32_t fpscr;
+
+ __asm __volatile("vmrs %0, fpscr" : "=&r"(fpscr));
+
+ return ((fpscr >> 22) & 3);
+}
+
diff --git a/lib/libc/arm/gen/fpgetsticky_vfp.c b/lib/libc/arm/gen/fpgetsticky_vfp.c
new file mode 100644
index 000000000000..f1e0ba5bfdb2
--- /dev/null
+++ b/lib/libc/arm/gen/fpgetsticky_vfp.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2014 Andrew Turner
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <ieeefp.h>
+
+#ifdef __weak_alias
+__weak_alias(fpgetsticky,_fpgetsticky)
+#endif
+
+#define FP_X_MASK (FP_X_INV | FP_X_DZ | FP_X_OFL | FP_X_UFL | FP_X_IMP)
+
+fp_except
+fpgetsticky(void)
+{
+ fp_except old;
+
+ __asm __volatile("vmrs %0, fpscr" : "=&r"(old));
+
+ return (old & FP_X_MASK);
+}
+
diff --git a/lib/libc/arm/gen/fpsetmask_vfp.c b/lib/libc/arm/gen/fpsetmask_vfp.c
new file mode 100644
index 000000000000..170e06d74fa9
--- /dev/null
+++ b/lib/libc/arm/gen/fpsetmask_vfp.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2014 Andrew Turner
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <ieeefp.h>
+
+#ifdef __weak_alias
+__weak_alias(fpsetmask,_fpsetmask)
+#endif
+
+#define FP_X_MASK (FP_X_INV | FP_X_DZ | FP_X_OFL | FP_X_UFL | FP_X_IMP)
+
+fp_except_t
+fpsetmask(fp_except_t mask)
+{
+ fp_except old, new;
+
+ __asm __volatile("vmrs %0, fpscr" : "=&r"(old));
+ mask = (mask & FP_X_MASK) << 8;
+ new = (old & ~(FP_X_MASK << 8)) | mask;
+ __asm __volatile("vmsr fpscr, %0" : : "r"(new));
+
+ return ((old >> 8) & FP_X_MASK);
+}
+
diff --git a/lib/libc/arm/gen/fpsetround_vfp.c b/lib/libc/arm/gen/fpsetround_vfp.c
new file mode 100644
index 000000000000..dc65a2e10057
--- /dev/null
+++ b/lib/libc/arm/gen/fpsetround_vfp.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2014 Andrew Turner
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <ieeefp.h>
+
+#ifdef __weak_alias
+__weak_alias(fpsetround,_fpsetround)
+#endif
+
+fp_rnd_t
+fpsetround(fp_rnd_t rnd_dir)
+{
+ uint32_t old, new;
+
+ __asm __volatile("vmrs %0, fpscr" : "=&r"(old));
+ new = old & ~(3 << 22);
+ new |= rnd_dir << 22;
+ __asm __volatile("vmsr fpscr, %0" : : "r"(new));
+
+ return ((old >> 22) & 3);
+}
+
diff --git a/lib/libc/arm/gen/fpsetsticky_vfp.c b/lib/libc/arm/gen/fpsetsticky_vfp.c
new file mode 100644
index 000000000000..ddc15938417c
--- /dev/null
+++ b/lib/libc/arm/gen/fpsetsticky_vfp.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2014 Andrew Turner
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <ieeefp.h>
+
+#ifdef __weak_alias
+__weak_alias(fpsetsticky,_fpsetsticky)
+#endif
+
+#define FP_X_MASK (FP_X_INV | FP_X_DZ | FP_X_OFL | FP_X_UFL | FP_X_IMP)
+
+fp_except
+fpsetsticky(fp_except except)
+{
+ fp_except old, new;
+
+ __asm __volatile("vmrs %0, fpscr" : "=&r"(old));
+ new = old & ~(FP_X_MASK);
+ new &= ~except;
+ __asm __volatile("vmsr fpscr, %0" : : "r"(new));
+
+ return (old & except);
+}
+
diff --git a/lib/libc/arm/gen/infinity.c b/lib/libc/arm/gen/infinity.c
new file mode 100644
index 000000000000..60faf42a7ea3
--- /dev/null
+++ b/lib/libc/arm/gen/infinity.c
@@ -0,0 +1,26 @@
+/*
+ * infinity.c
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <math.h>
+
+/* bytes for +Infinity on a 387 */
+const union __infinity_un __infinity = {
+#if BYTE_ORDER == BIG_ENDIAN
+ { 0x7f, 0xf0, 0, 0, 0, 0, 0, 0 }
+#else
+ { 0, 0, 0, 0, 0, 0, 0xf0, 0x7f }
+#endif
+};
+
+/* bytes for NaN */
+const union __nan_un __nan = {
+#if BYTE_ORDER == BIG_ENDIAN
+ {0xff, 0xc0, 0, 0}
+#else
+ { 0, 0, 0xc0, 0xff }
+#endif
+};
diff --git a/lib/libc/arm/gen/makecontext.c b/lib/libc/arm/gen/makecontext.c
new file mode 100644
index 000000000000..4b0f92d78f77
--- /dev/null
+++ b/lib/libc/arm/gen/makecontext.c
@@ -0,0 +1,89 @@
+/* $NetBSD: makecontext.c,v 1.2 2003/01/18 11:06:24 thorpej Exp $ */
+
+/*-
+ * Copyright (c) 2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Klaus Klein.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <inttypes.h>
+#include <ucontext.h>
+
+#include <stdarg.h>
+
+extern void _ctx_start(void);
+
+void
+ctx_done(ucontext_t *ucp)
+{
+
+ if (ucp->uc_link == NULL)
+ exit(0);
+ else {
+ setcontext((const ucontext_t *)ucp->uc_link);
+ abort();
+ }
+}
+
+__weak_reference(__makecontext, makecontext);
+
+void
+__makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...)
+{
+ __greg_t *gr = ucp->uc_mcontext.__gregs;
+ int i;
+ unsigned int *sp;
+ va_list ap;
+
+ /* Compute and align stack pointer. */
+ sp = (unsigned int *)
+ (((uintptr_t)ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size -
+ sizeof(double)) & ~7);
+ /* Allocate necessary stack space for arguments exceeding r0-3. */
+ if (argc > 4)
+ sp -= argc - 4;
+ gr[_REG_SP] = (__greg_t)sp;
+ /* Wipe out frame pointer. */
+ gr[_REG_FP] = 0;
+ /* Arrange for return via the trampoline code. */
+ gr[_REG_PC] = (__greg_t)_ctx_start;
+ gr[_REG_R4] = (__greg_t)func;
+ gr[_REG_R5] = (__greg_t)ucp;
+
+ va_start(ap, argc);
+ /* Pass up to four arguments in r0-3. */
+ for (i = 0; i < argc && i < 4; i++)
+ gr[_REG_R0 + i] = va_arg(ap, int);
+ /* Pass any additional arguments on the stack. */
+ for (argc -= i; argc > 0; argc--)
+ *sp++ = va_arg(ap, int);
+ va_end(ap);
+}
diff --git a/lib/libc/arm/gen/setjmp.S b/lib/libc/arm/gen/setjmp.S
new file mode 100644
index 000000000000..4e3850d136c2
--- /dev/null
+++ b/lib/libc/arm/gen/setjmp.S
@@ -0,0 +1,162 @@
+/* $NetBSD: setjmp.S,v 1.14 2013/04/19 13:45:45 matt Exp $ */
+
+/*
+ * Copyright (c) 1997 Mark Brinicombe
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Mark Brinicombe
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if !defined(__SOFTFP__) && !defined(__VFP_FP__) && !defined(__ARM_PCS)
+#error FPA is not supported anymore
+#endif
+
+ .fpu vfp
+
+#include <machine/asm.h>
+#include <machine/setjmp.h>
+
+__FBSDID("$FreeBSD$");
+
+/*
+ * C library -- setjmp, longjmp
+ *
+ * longjmp(a,v)
+ * will generate a "return(v)" from the last call to
+ * setjmp(a)
+ * by restoring registers from the stack.
+ * The previous signal state is restored.
+ */
+
+ENTRY(setjmp)
+ /* Block all signals and retrieve the old signal mask */
+ stmfd sp!, {r0, r14}
+ add r2, r0, #(_JB_SIGMASK * 4) /* oset */
+ mov r1, #0x00000000 /* set */
+ mov r0, #0x00000001 /* SIG_BLOCK */
+ bl PIC_SYM(_C_LABEL(sigprocmask), PLT)
+ ldmfd sp!, {r0, r14}
+
+ ldr r1, .Lsetjmp_magic
+
+ ldr r2, .Lfpu_present
+#ifdef PIC
+ GOT_INIT(r3, .Lsetjmp_got, .Lsetjmp_gotinit)
+ ldr r2, [r2, r3]
+#else
+ ldr r2, [r2]
+#endif
+ teq r2, #0 /* do we have a FPU? */
+ beq 1f /* no, don't save VFP registers */
+
+ orr r1, r1, #(_JB_MAGIC_SETJMP ^ _JB_MAGIC_SETJMP_VFP)
+ /* change magic to VFP magic */
+ add r2, r0, #(_JB_REG_D8 * 4)
+ vstmia r2, {d8-d15}
+ vmrs r2, fpscr
+ str r2, [r0, #(_JB_REG_FPSCR * 4)]
+1:
+
+ str r1, [r0] /* store magic */
+
+ /* Store integer registers */
+ add r0, r0, #(_JB_REG_R4 * 4)
+#ifndef __thumb__
+ stmia r0, {r4-r14}
+#else
+ stmia r0, {r4-r12}
+ str r13, [r0, #((_JB_REG_R13 - _JB_REG_R4) * 4)]
+ str r14, [r0, #((_JB_REG_R14 - _JB_REG_R4) * 4)]
+#endif
+ mov r0, #0x00000000
+ RET
+
+.Lsetjmp_magic:
+ .word _JB_MAGIC_SETJMP
+ GOT_INITSYM(.Lsetjmp_got, .Lsetjmp_gotinit)
+.Lfpu_present:
+ .word PIC_SYM(_libc_arm_fpu_present, GOTOFF)
+END(setjmp)
+
+.weak _C_LABEL(longjmp)
+.set _C_LABEL(longjmp), _C_LABEL(__longjmp)
+ENTRY(__longjmp)
+ ldr r2, [r0]
+ ldr ip, .Lsetjmp_magic
+ bic r3, r2, #(_JB_MAGIC_SETJMP ^ _JB_MAGIC_SETJMP_VFP)
+ teq r3, ip
+ bne .Lbotch
+
+ /* Restore the signal mask. */
+ stmfd sp!, {r0-r2, r14}
+ mov r2, #0x00000000
+ add r1, r0, #(_JB_SIGMASK * 4) /* Signal mask */
+ mov r0, #3 /* SIG_SETMASK */
+ bl PIC_SYM(_C_LABEL(sigprocmask), PLT)
+ ldmfd sp!, {r0-r2, r14}
+
+ tst r2, #(_JB_MAGIC_SETJMP ^ _JB_MAGIC_SETJMP_VFP)
+ /* is this a VFP magic? */
+ beq 1f /* no, don't restore VFP */
+ add ip, r0, #(_JB_REG_D8 * 4)
+ vldmia ip, {d8-d15}
+ ldr ip, [r0, #(_JB_REG_FPSCR * 4)]
+ vmsr fpscr, ip
+1:
+
+ add r0, r0, #(_JB_REG_R4 * 4)
+ /* Restore integer registers */
+#ifndef __thumb__
+ ldmia r0, {r4-r14}
+#else
+ ldmia r0, {r4-r12}
+ ldr r13, [r0, #((_JB_REG_R13 - _JB_REG_R4) * 4)]
+ ldr r14, [r0, #((_JB_REG_R14 - _JB_REG_R4) * 4)]
+#endif
+
+ /* Validate sp and r14 */
+ teq sp, #0
+ it ne
+ teqne r14, #0
+ it eq
+ beq .Lbotch
+
+ /* Set return value */
+ movs r0, r1
+ it eq
+ moveq r0, #0x00000001
+ RET
+
+ /* validation failed, die die die. */
+.Lbotch:
+ bl PIC_SYM(_C_LABEL(longjmperror), PLT)
+ bl PIC_SYM(_C_LABEL(abort), PLT)
+1: b 1b /* Cannot get here */
+END(__longjmp)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/arm/gen/signalcontext.c b/lib/libc/arm/gen/signalcontext.c
new file mode 100644
index 000000000000..bb9a54dbe115
--- /dev/null
+++ b/lib/libc/arm/gen/signalcontext.c
@@ -0,0 +1,78 @@
+/*-
+ * Copyright (c) 2004 Olivier Houchard
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/signal.h>
+#include <sys/ucontext.h>
+
+#include <machine/frame.h>
+#include <machine/sigframe.h>
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <strings.h>
+#include <signal.h>
+
+__weak_reference(__signalcontext, signalcontext);
+
+extern void _ctx_start(void);
+
+int
+__signalcontext(ucontext_t *ucp, int sig, __sighandler_t *func)
+{
+ struct sigframe *sfp;
+ __greg_t *gr = ucp->uc_mcontext.__gregs;
+ unsigned int *sp;
+
+ sp = (unsigned int *)gr[_REG_SP];
+
+ sfp = (struct sigframe *)sp - 1;
+
+ bzero(sfp, sizeof(*sfp));
+ bcopy(ucp, &sfp->sf_uc, sizeof(*ucp));
+ sfp->sf_si.si_signo = sig;
+
+ gr[_REG_SP] = (__greg_t)sfp;
+ /* Wipe out frame pointer. */
+ gr[_REG_FP] = 0;
+ /* Arrange for return via the trampoline code. */
+ gr[_REG_PC] = (__greg_t)_ctx_start;
+ gr[_REG_R4] = (__greg_t)func;
+ gr[_REG_R5] = (__greg_t)ucp;
+ gr[_REG_R0] = (__greg_t)sig;
+ gr[_REG_R1] = (__greg_t)&sfp->sf_si;
+ gr[_REG_R2] = (__greg_t)&sfp->sf_uc;
+
+ ucp->uc_link = &sfp->sf_uc;
+ sigdelset(&ucp->uc_sigmask, sig);
+
+ return (0);
+}
diff --git a/lib/libc/arm/gen/sigsetjmp.S b/lib/libc/arm/gen/sigsetjmp.S
new file mode 100644
index 000000000000..236f5310a7f3
--- /dev/null
+++ b/lib/libc/arm/gen/sigsetjmp.S
@@ -0,0 +1,70 @@
+/* $NetBSD: sigsetjmp.S,v 1.6 2013/04/19 16:50:22 matt Exp $ */
+
+/*
+ * Copyright (c) 1997 Mark Brinicombe
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Mark Brinicombe
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include <machine/setjmp.h>
+
+/*
+ * C library -- sigsetjmp, siglongjmp
+ *
+ * longjmp(a,v)
+ * will generate a "return(v)" from the last call to
+ * setjmp(a, m)
+ * by restoring registers from the stack.
+ * The previous signal state is restored.
+ */
+
+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
+WEAK_ALIAS(__siglongjmp, siglongjmp)
+
+ENTRY(siglongjmp)
+ ldr r2, .L_setjmp_magic /* load magic */
+ ldr r3, [r0] /* get magic from jmp_buf */
+ bic r3, r3, #(_JB_MAGIC__SETJMP ^ _JB_MAGIC__SETJMP_VFP)
+ /* ignore VFP-ness of magic */
+ teq r2, r3 /* magic correct? */
+ beq PIC_SYM(_C_LABEL(_longjmp), PLT)
+ b PIC_SYM(_C_LABEL(longjmp), PLT)
+END(siglongjmp)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/arm/softfloat/arm-gcc.h b/lib/libc/arm/softfloat/arm-gcc.h
new file mode 100644
index 000000000000..0e20ef91f059
--- /dev/null
+++ b/lib/libc/arm/softfloat/arm-gcc.h
@@ -0,0 +1,101 @@
+/* $NetBSD: arm-gcc.h,v 1.2 2001/02/21 18:09:25 bjh21 Exp $ */
+/* $FreeBSD$ */
+
+/*
+-------------------------------------------------------------------------------
+One of the macros `BIGENDIAN' or `LITTLEENDIAN' must be defined.
+-------------------------------------------------------------------------------
+*/
+#ifdef __ARMEB__
+#define BIGENDIAN
+#else
+#define LITTLEENDIAN
+#endif
+
+/*
+-------------------------------------------------------------------------------
+The macro `BITS64' can be defined to indicate that 64-bit integer types are
+supported by the compiler.
+-------------------------------------------------------------------------------
+*/
+#define BITS64
+
+/*
+-------------------------------------------------------------------------------
+Each of the following `typedef's defines the most convenient type that holds
+integers of at least as many bits as specified. For example, `uint8' should
+be the most convenient type that can hold unsigned integers of as many as
+8 bits. The `flag' type must be able to hold either a 0 or 1. For most
+implementations of C, `flag', `uint8', and `int8' should all be `typedef'ed
+to the same as `int'.
+-------------------------------------------------------------------------------
+*/
+typedef int flag;
+typedef int uint8;
+typedef int int8;
+typedef int uint16;
+typedef int int16;
+typedef unsigned int uint32;
+typedef signed int int32;
+#ifdef BITS64
+typedef unsigned long long int uint64;
+typedef signed long long int int64;
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Each of the following `typedef's defines a type that holds integers
+of _exactly_ the number of bits specified. For instance, for most
+implementation of C, `bits16' and `sbits16' should be `typedef'ed to
+`unsigned short int' and `signed short int' (or `short int'), respectively.
+-------------------------------------------------------------------------------
+*/
+typedef unsigned char bits8;
+typedef signed char sbits8;
+typedef unsigned short int bits16;
+typedef signed short int sbits16;
+typedef unsigned int bits32;
+typedef signed int sbits32;
+#ifdef BITS64
+typedef unsigned long long int bits64;
+typedef signed long long int sbits64;
+#endif
+
+#ifdef BITS64
+/*
+-------------------------------------------------------------------------------
+The `LIT64' macro takes as its argument a textual integer literal and
+if necessary ``marks'' the literal as having a 64-bit integer type.
+For example, the GNU C Compiler (`gcc') requires that 64-bit literals be
+appended with the letters `LL' standing for `long long', which is `gcc's
+name for the 64-bit integer type. Some compilers may allow `LIT64' to be
+defined as the identity macro: `#define LIT64( a ) a'.
+-------------------------------------------------------------------------------
+*/
+#define LIT64( a ) a##LL
+#endif
+
+/*
+-------------------------------------------------------------------------------
+The macro `INLINE' can be used before functions that should be inlined. If
+a compiler does not support explicit inlining, this macro should be defined
+to be `static'.
+-------------------------------------------------------------------------------
+*/
+#define INLINE static __inline
+
+/*
+-------------------------------------------------------------------------------
+The ARM FPA is odd in that it stores doubles high-order word first, no matter
+what the endianness of the CPU. VFP is sane.
+-------------------------------------------------------------------------------
+*/
+#if defined(SOFTFLOAT_FOR_GCC)
+#if defined (__ARM_EABI__) || defined(__VFP_FP__) || defined(__ARMEB__)
+#define FLOAT64_DEMANGLE(a) (a)
+#define FLOAT64_MANGLE(a) (a)
+#else
+#define FLOAT64_DEMANGLE(a) ((((a) & 0xfffffffful) << 32) | ((a) >> 32))
+#define FLOAT64_MANGLE(a) FLOAT64_DEMANGLE(a)
+#endif
+#endif
diff --git a/lib/libc/arm/softfloat/milieu.h b/lib/libc/arm/softfloat/milieu.h
new file mode 100644
index 000000000000..54775c768b91
--- /dev/null
+++ b/lib/libc/arm/softfloat/milieu.h
@@ -0,0 +1,49 @@
+/* $NetBSD: milieu.h,v 1.1 2000/12/29 20:13:54 bjh21 Exp $ */
+/* $FreeBSD$ */
+
+/*
+===============================================================================
+
+This C header file is part of the SoftFloat IEC/IEEE Floating-point
+Arithmetic Package, Release 2a.
+
+Written by John R. Hauser. This work was made possible in part by the
+International Computer Science Institute, located at Suite 600, 1947 Center
+Street, Berkeley, California 94704. Funding was partially provided by the
+National Science Foundation under grant MIP-9311980. The original version
+of this code was written as part of a project to build a fixed-point vector
+processor in collaboration with the University of California at Berkeley,
+overseen by Profs. Nelson Morgan and John Wawrzynek. More information
+is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
+arithmetic/SoftFloat.html'.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
+has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
+TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
+PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
+AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
+
+Derivative works are acceptable, even for commercial purposes, so long as
+(1) they include prominent notice that the work is derivative, and (2) they
+include prominent notice akin to these four paragraphs for those parts of
+this code that are retained.
+
+===============================================================================
+*/
+
+/*
+-------------------------------------------------------------------------------
+Include common integer types and flags.
+-------------------------------------------------------------------------------
+*/
+#include "arm-gcc.h"
+
+/*
+-------------------------------------------------------------------------------
+Symbolic Boolean literals.
+-------------------------------------------------------------------------------
+*/
+enum {
+ FALSE = 0,
+ TRUE = 1
+};
diff --git a/lib/libc/arm/softfloat/softfloat.h b/lib/libc/arm/softfloat/softfloat.h
new file mode 100644
index 000000000000..6aef49975a38
--- /dev/null
+++ b/lib/libc/arm/softfloat/softfloat.h
@@ -0,0 +1,315 @@
+/* $NetBSD: softfloat.h,v 1.6 2002/05/12 13:12:46 bjh21 Exp $ */
+/* $FreeBSD$ */
+
+/* This is a derivative work. */
+
+/*
+===============================================================================
+
+This C header file is part of the SoftFloat IEC/IEEE Floating-point
+Arithmetic Package, Release 2a.
+
+Written by John R. Hauser. This work was made possible in part by the
+International Computer Science Institute, located at Suite 600, 1947 Center
+Street, Berkeley, California 94704. Funding was partially provided by the
+National Science Foundation under grant MIP-9311980. The original version
+of this code was written as part of a project to build a fixed-point vector
+processor in collaboration with the University of California at Berkeley,
+overseen by Profs. Nelson Morgan and John Wawrzynek. More information
+is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
+arithmetic/SoftFloat.html'.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
+has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
+TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
+PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
+AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
+
+Derivative works are acceptable, even for commercial purposes, so long as
+(1) they include prominent notice that the work is derivative, and (2) they
+include prominent notice akin to these four paragraphs for those parts of
+this code that are retained.
+
+===============================================================================
+*/
+
+/*
+-------------------------------------------------------------------------------
+The macro `FLOATX80' must be defined to enable the extended double-precision
+floating-point format `floatx80'. If this macro is not defined, the
+`floatx80' type will not be defined, and none of the functions that either
+input or output the `floatx80' type will be defined. The same applies to
+the `FLOAT128' macro and the quadruple-precision format `float128'.
+-------------------------------------------------------------------------------
+*/
+/* #define FLOATX80 */
+/* #define FLOAT128 */
+
+#include <fenv.h>
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE floating-point types.
+-------------------------------------------------------------------------------
+*/
+typedef unsigned int float32;
+typedef unsigned long long float64;
+#ifdef FLOATX80
+typedef struct {
+ unsigned short high;
+ unsigned long long low;
+} floatx80;
+#endif
+#ifdef FLOAT128
+typedef struct {
+ unsigned long long high, low;
+} float128;
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE floating-point underflow tininess-detection mode.
+-------------------------------------------------------------------------------
+*/
+#ifndef SOFTFLOAT_FOR_GCC
+extern int float_detect_tininess;
+#endif
+enum {
+ float_tininess_after_rounding = 0,
+ float_tininess_before_rounding = 1
+};
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE floating-point rounding mode.
+-------------------------------------------------------------------------------
+*/
+extern int float_rounding_mode;
+enum {
+ float_round_nearest_even = FE_TONEAREST,
+ float_round_to_zero = FE_TOWARDZERO,
+ float_round_down = FE_DOWNWARD,
+ float_round_up = FE_UPWARD
+};
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE floating-point exception flags.
+-------------------------------------------------------------------------------
+*/
+extern int float_exception_flags;
+extern int float_exception_mask;
+enum {
+ float_flag_inexact = FE_INEXACT,
+ float_flag_underflow = FE_UNDERFLOW,
+ float_flag_overflow = FE_OVERFLOW,
+ float_flag_divbyzero = FE_DIVBYZERO,
+ float_flag_invalid = FE_INVALID
+};
+
+/*
+-------------------------------------------------------------------------------
+Routine to raise any or all of the software IEC/IEEE floating-point
+exception flags.
+-------------------------------------------------------------------------------
+*/
+void float_raise( int );
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE integer-to-floating-point conversion routines.
+-------------------------------------------------------------------------------
+*/
+float32 int32_to_float32( int );
+float64 int32_to_float64( int );
+#ifdef FLOATX80
+floatx80 int32_to_floatx80( int );
+#endif
+#ifdef FLOAT128
+float128 int32_to_float128( int );
+#endif
+#ifndef SOFTFLOAT_FOR_GCC /* __floatdi?f is in libgcc2.c */
+float32 int64_to_float32( long long );
+float64 int64_to_float64( long long );
+#ifdef FLOATX80
+floatx80 int64_to_floatx80( long long );
+#endif
+#ifdef FLOAT128
+float128 int64_to_float128( long long );
+#endif
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE single-precision conversion routines.
+-------------------------------------------------------------------------------
+*/
+int float32_to_int32( float32 );
+int float32_to_int32_round_to_zero( float32 );
+#if defined(SOFTFLOAT_FOR_GCC) && defined(SOFTFLOAT_NEED_FIXUNS)
+unsigned int float32_to_uint32_round_to_zero( float32 );
+#endif
+#ifndef SOFTFLOAT_FOR_GCC /* __fix?fdi provided by libgcc2.c */
+long long float32_to_int64( float32 );
+long long float32_to_int64_round_to_zero( float32 );
+#endif
+float64 float32_to_float64( float32 );
+#ifdef FLOATX80
+floatx80 float32_to_floatx80( float32 );
+#endif
+#ifdef FLOAT128
+float128 float32_to_float128( float32 );
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE single-precision operations.
+-------------------------------------------------------------------------------
+*/
+float32 float32_round_to_int( float32 );
+float32 float32_add( float32, float32 );
+float32 float32_sub( float32, float32 );
+float32 float32_mul( float32, float32 );
+float32 float32_div( float32, float32 );
+float32 float32_rem( float32, float32 );
+float32 float32_sqrt( float32 );
+int float32_eq( float32, float32 );
+int float32_le( float32, float32 );
+int float32_lt( float32, float32 );
+int float32_eq_signaling( float32, float32 );
+int float32_le_quiet( float32, float32 );
+int float32_lt_quiet( float32, float32 );
+#ifndef SOFTFLOAT_FOR_GCC
+int float32_is_signaling_nan( float32 );
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE double-precision conversion routines.
+-------------------------------------------------------------------------------
+*/
+int float64_to_int32( float64 );
+int float64_to_int32_round_to_zero( float64 );
+#if defined(SOFTFLOAT_FOR_GCC) && defined(SOFTFLOAT_NEED_FIXUNS)
+unsigned int float64_to_uint32_round_to_zero( float64 );
+#endif
+#ifndef SOFTFLOAT_FOR_GCC /* __fix?fdi provided by libgcc2.c */
+long long float64_to_int64( float64 );
+long long float64_to_int64_round_to_zero( float64 );
+#endif
+float32 float64_to_float32( float64 );
+#ifdef FLOATX80
+floatx80 float64_to_floatx80( float64 );
+#endif
+#ifdef FLOAT128
+float128 float64_to_float128( float64 );
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE double-precision operations.
+-------------------------------------------------------------------------------
+*/
+float64 float64_round_to_int( float64 );
+float64 float64_add( float64, float64 );
+float64 float64_sub( float64, float64 );
+float64 float64_mul( float64, float64 );
+float64 float64_div( float64, float64 );
+float64 float64_rem( float64, float64 );
+float64 float64_sqrt( float64 );
+int float64_eq( float64, float64 );
+int float64_le( float64, float64 );
+int float64_lt( float64, float64 );
+int float64_eq_signaling( float64, float64 );
+int float64_le_quiet( float64, float64 );
+int float64_lt_quiet( float64, float64 );
+#ifndef SOFTFLOAT_FOR_GCC
+int float64_is_signaling_nan( float64 );
+#endif
+
+#ifdef FLOATX80
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE extended double-precision conversion routines.
+-------------------------------------------------------------------------------
+*/
+int floatx80_to_int32( floatx80 );
+int floatx80_to_int32_round_to_zero( floatx80 );
+long long floatx80_to_int64( floatx80 );
+long long floatx80_to_int64_round_to_zero( floatx80 );
+float32 floatx80_to_float32( floatx80 );
+float64 floatx80_to_float64( floatx80 );
+#ifdef FLOAT128
+float128 floatx80_to_float128( floatx80 );
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE extended double-precision rounding precision. Valid
+values are 32, 64, and 80.
+-------------------------------------------------------------------------------
+*/
+extern int floatx80_rounding_precision;
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE extended double-precision operations.
+-------------------------------------------------------------------------------
+*/
+floatx80 floatx80_round_to_int( floatx80 );
+floatx80 floatx80_add( floatx80, floatx80 );
+floatx80 floatx80_sub( floatx80, floatx80 );
+floatx80 floatx80_mul( floatx80, floatx80 );
+floatx80 floatx80_div( floatx80, floatx80 );
+floatx80 floatx80_rem( floatx80, floatx80 );
+floatx80 floatx80_sqrt( floatx80 );
+int floatx80_eq( floatx80, floatx80 );
+int floatx80_le( floatx80, floatx80 );
+int floatx80_lt( floatx80, floatx80 );
+int floatx80_eq_signaling( floatx80, floatx80 );
+int floatx80_le_quiet( floatx80, floatx80 );
+int floatx80_lt_quiet( floatx80, floatx80 );
+int floatx80_is_signaling_nan( floatx80 );
+
+#endif
+
+#ifdef FLOAT128
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE quadruple-precision conversion routines.
+-------------------------------------------------------------------------------
+*/
+int float128_to_int32( float128 );
+int float128_to_int32_round_to_zero( float128 );
+long long float128_to_int64( float128 );
+long long float128_to_int64_round_to_zero( float128 );
+float32 float128_to_float32( float128 );
+float64 float128_to_float64( float128 );
+#ifdef FLOATX80
+floatx80 float128_to_floatx80( float128 );
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE quadruple-precision operations.
+-------------------------------------------------------------------------------
+*/
+float128 float128_round_to_int( float128 );
+float128 float128_add( float128, float128 );
+float128 float128_sub( float128, float128 );
+float128 float128_mul( float128, float128 );
+float128 float128_div( float128, float128 );
+float128 float128_rem( float128, float128 );
+float128 float128_sqrt( float128 );
+int float128_eq( float128, float128 );
+int float128_le( float128, float128 );
+int float128_lt( float128, float128 );
+int float128_eq_signaling( float128, float128 );
+int float128_le_quiet( float128, float128 );
+int float128_lt_quiet( float128, float128 );
+int float128_is_signaling_nan( float128 );
+
+#endif
+
diff --git a/lib/libc/arm/string/Makefile.inc b/lib/libc/arm/string/Makefile.inc
new file mode 100644
index 000000000000..0ba43e6c7399
--- /dev/null
+++ b/lib/libc/arm/string/Makefile.inc
@@ -0,0 +1,6 @@
+# @(#)Makefile.inc 8.1 (Berkeley) 6/4/93
+# $FreeBSD$
+
+MDSRCS+=bcmp.c bcopy.S bzero.S ffs.S memchr.c memcmp.S memcpy.S \
+ memmove.S memset.S strcat.c strchr.c strcmp.S strcpy.c strlen.S \
+ strncmp.S strrchr.c swab.c wcschr.c wcscmp.c wcslen.c wmemchr.c
diff --git a/lib/libc/arm/string/bcopy.S b/lib/libc/arm/string/bcopy.S
new file mode 100644
index 000000000000..f2583fc7ffc8
--- /dev/null
+++ b/lib/libc/arm/string/bcopy.S
@@ -0,0 +1,6 @@
+/* $NetBSD: bcopy.S,v 1.3 2003/10/14 07:51:45 scw Exp $ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+#define _BCOPY
+#include "memmove.S"
diff --git a/lib/libc/arm/string/bzero.S b/lib/libc/arm/string/bzero.S
new file mode 100644
index 000000000000..b31358d6d928
--- /dev/null
+++ b/lib/libc/arm/string/bzero.S
@@ -0,0 +1,37 @@
+/* $NetBSD: bzero.S,v 1.3 2003/10/14 07:51:45 scw Exp $ */
+
+/*-
+ * Copyright (c) 1997 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Neil A. Carson and Mark Brinicombe
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+
+__FBSDID("$FreeBSD$");
+
+#define _BZERO
+#include "memset.S"
diff --git a/lib/libc/arm/string/ffs.S b/lib/libc/arm/string/ffs.S
new file mode 100644
index 000000000000..0ed815244755
--- /dev/null
+++ b/lib/libc/arm/string/ffs.S
@@ -0,0 +1,88 @@
+/* $NetBSD: ffs.S,v 1.5 2003/04/05 23:08:52 bjh21 Exp $ */
+/*
+ * Copyright (c) 2001 Christopher Gilbert
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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$");
+
+.syntax unified
+
+/*
+ * ffs - find first set bit, this algorithm isolates the first set
+ * bit, then multiplies the number by 0x0450fbaf which leaves the top
+ * 6 bits as an index into the table. This algorithm should be a win
+ * over the checking each bit in turn as per the C compiled version.
+ *
+ * under ARMv5 there's an instruction called CLZ (count leading Zero's) that
+ * could be used
+ *
+ * This is the ffs algorithm devised by d.seal and posted to comp.sys.arm on
+ * 16 Feb 1994.
+ */
+
+ENTRY(ffs)
+ /* Standard trick to isolate bottom bit in r0 or 0 if r0 = 0 on entry */
+ rsb r1, r0, #0
+ ands r0, r0, r1
+#ifndef _ARM_ARCH_5
+ /*
+ * now r0 has at most one set bit, call this X
+ * if X = 0, all further instructions are skipped
+ */
+ adrne r2, .L_ffs_table
+ orrne r0, r0, r0, lsl #4 /* r0 = X * 0x11 */
+ orrne r0, r0, r0, lsl #6 /* r0 = X * 0x451 */
+ rsbne r0, r0, r0, lsl #16 /* r0 = X * 0x0450fbaf */
+
+ /* now lookup in table indexed on top 6 bits of r0 */
+ ldrbne r0, [ r2, r0, lsr #26 ]
+
+ RET
+.text;
+.type .L_ffs_table, _ASM_TYPE_OBJECT;
+.L_ffs_table:
+/* 0 1 2 3 4 5 6 7 */
+ .byte 0, 1, 2, 13, 3, 7, 0, 14 /* 0- 7 */
+ .byte 4, 0, 8, 0, 0, 0, 0, 15 /* 8-15 */
+ .byte 11, 5, 0, 0, 9, 0, 0, 26 /* 16-23 */
+ .byte 0, 0, 0, 0, 0, 22, 28, 16 /* 24-31 */
+ .byte 32, 12, 6, 0, 0, 0, 0, 0 /* 32-39 */
+ .byte 10, 0, 0, 25, 0, 0, 21, 27 /* 40-47 */
+ .byte 31, 0, 0, 0, 0, 24, 0, 20 /* 48-55 */
+ .byte 30, 0, 23, 19, 29, 18, 17, 0 /* 56-63 */
+#else
+ itt ne
+ clzne r0, r0
+ rsbne r0, r0, #32
+ RET
+#endif
+END(ffs)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/arm/string/memcmp.S b/lib/libc/arm/string/memcmp.S
new file mode 100644
index 000000000000..33a11b7c4c49
--- /dev/null
+++ b/lib/libc/arm/string/memcmp.S
@@ -0,0 +1,185 @@
+/* $NetBSD: memcmp.S,v 1.3 2003/10/14 07:51:45 scw Exp $ */
+
+/*
+ * Copyright 2003 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Steve C. Woodford for Wasabi Systems, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the NetBSD Project by
+ * Wasabi Systems, Inc.
+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 2002 ARM Ltd
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the company may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ARM LTD ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL ARM LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * 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$");
+
+.syntax unified
+
+ENTRY(memcmp)
+ mov ip, r0
+#if defined(_KERNEL) && !defined(_STANDALONE)
+ cmp r2, #0x06
+ beq .Lmemcmp_6bytes
+#endif
+ mov r0, #0x00
+
+ /* Are both addresses aligned the same way? */
+ cmp r2, #0x00
+ eorsne r3, ip, r1
+ RETeq /* len == 0, or same addresses! */
+ tst r3, #0x03
+ subne r2, r2, #0x01
+ bne .Lmemcmp_bytewise2 /* Badly aligned. Do it the slow way */
+
+ /* Word-align the addresses, if necessary */
+ sub r3, r1, #0x05
+ ands r3, r3, #0x03
+ add r3, r3, r3, lsl #1
+ addne pc, pc, r3, lsl #3
+ nop
+
+ /* Compare up to 3 bytes */
+ ldrb r0, [ip], #0x01
+ ldrb r3, [r1], #0x01
+ subs r0, r0, r3
+ RETne
+ subs r2, r2, #0x01
+ RETeq
+
+ /* Compare up to 2 bytes */
+ ldrb r0, [ip], #0x01
+ ldrb r3, [r1], #0x01
+ subs r0, r0, r3
+ RETne
+ subs r2, r2, #0x01
+ RETeq
+
+ /* Compare 1 byte */
+ ldrb r0, [ip], #0x01
+ ldrb r3, [r1], #0x01
+ subs r0, r0, r3
+ RETne
+ subs r2, r2, #0x01
+ RETeq
+
+ /* Compare 4 bytes at a time, if possible */
+ subs r2, r2, #0x04
+ bcc .Lmemcmp_bytewise
+.Lmemcmp_word_aligned:
+ ldr r0, [ip], #0x04
+ ldr r3, [r1], #0x04
+ subs r2, r2, #0x04
+ cmpcs r0, r3
+ beq .Lmemcmp_word_aligned
+ sub r0, r0, r3
+
+ /* Correct for extra subtraction, and check if done */
+ adds r2, r2, #0x04
+ cmpeq r0, #0x00 /* If done, did all bytes match? */
+ RETeq /* Yup. Just return */
+
+ /* Re-do the final word byte-wise */
+ sub ip, ip, #0x04
+ sub r1, r1, #0x04
+
+.Lmemcmp_bytewise:
+ add r2, r2, #0x03
+.Lmemcmp_bytewise2:
+ ldrb r0, [ip], #0x01
+ ldrb r3, [r1], #0x01
+ subs r2, r2, #0x01
+ cmpcs r0, r3
+ beq .Lmemcmp_bytewise2
+ sub r0, r0, r3
+ RET
+
+#if defined(_KERNEL) && !defined(_STANDALONE)
+ /*
+ * 6 byte compares are very common, thanks to the network stack.
+ * This code is hand-scheduled to reduce the number of stalls for
+ * load results. Everything else being equal, this will be ~32%
+ * faster than a byte-wise memcmp.
+ */
+ .align 5
+.Lmemcmp_6bytes:
+ ldrb r3, [r1, #0x00] /* r3 = b2#0 */
+ ldrb r0, [ip, #0x00] /* r0 = b1#0 */
+ ldrb r2, [r1, #0x01] /* r2 = b2#1 */
+ subs r0, r0, r3 /* r0 = b1#0 - b2#0 */
+ ldreqb r3, [ip, #0x01] /* r3 = b1#1 */
+ RETne /* Return if mismatch on #0 */
+ subs r0, r3, r2 /* r0 = b1#1 - b2#1 */
+ ldreqb r3, [r1, #0x02] /* r3 = b2#2 */
+ ldreqb r0, [ip, #0x02] /* r0 = b1#2 */
+ RETne /* Return if mismatch on #1 */
+ ldrb r2, [r1, #0x03] /* r2 = b2#3 */
+ subs r0, r0, r3 /* r0 = b1#2 - b2#2 */
+ ldreqb r3, [ip, #0x03] /* r3 = b1#3 */
+ RETne /* Return if mismatch on #2 */
+ subs r0, r3, r2 /* r0 = b1#3 - b2#3 */
+ ldreqb r3, [r1, #0x04] /* r3 = b2#4 */
+ ldreqb r0, [ip, #0x04] /* r0 = b1#4 */
+ RETne /* Return if mismatch on #3 */
+ ldrb r2, [r1, #0x05] /* r2 = b2#5 */
+ subs r0, r0, r3 /* r0 = b1#4 - b2#4 */
+ ldreqb r3, [ip, #0x05] /* r3 = b1#5 */
+ RETne /* Return if mismatch on #4 */
+ sub r0, r3, r2 /* r0 = b1#5 - b2#5 */
+ RET
+#endif
+END(memcmp)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/arm/string/memcpy.S b/lib/libc/arm/string/memcpy.S
new file mode 100644
index 000000000000..3628652681e0
--- /dev/null
+++ b/lib/libc/arm/string/memcpy.S
@@ -0,0 +1,9 @@
+/* $NetBSD: memcpy.S,v 1.4 2003/10/14 07:51:45 scw Exp $ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+#if !defined(_ARM_ARCH_5E) || defined(_STANDALONE)
+#include "memcpy_arm.S"
+#else
+#include "memcpy_xscale.S"
+#endif
diff --git a/lib/libc/arm/string/memcpy_arm.S b/lib/libc/arm/string/memcpy_arm.S
new file mode 100644
index 000000000000..57b0449e5099
--- /dev/null
+++ b/lib/libc/arm/string/memcpy_arm.S
@@ -0,0 +1,338 @@
+/* $NetBSD: memcpy_arm.S,v 1.1 2003/10/14 07:51:45 scw Exp $ */
+
+/*-
+ * Copyright (c) 1997 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Neil A. Carson and Mark Brinicombe
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+.syntax unified
+
+/*
+ * This is one fun bit of code ...
+ * Some easy listening music is suggested while trying to understand this
+ * code e.g. Iron Maiden
+ *
+ * For anyone attempting to understand it :
+ *
+ * The core code is implemented here with simple stubs for memcpy().
+ *
+ * All local labels are prefixed with Lmemcpy_
+ * Following the prefix a label starting f is used in the forward copy code
+ * while a label using b is used in the backwards copy code
+ * The source and destination addresses determine whether a forward or
+ * backward copy is performed.
+ * Separate bits of code are used to deal with the following situations
+ * for both the forward and backwards copy.
+ * unaligned source address
+ * unaligned destination address
+ * Separate copy routines are used to produce an optimised result for each
+ * of these cases.
+ * The copy code will use LDM/STM instructions to copy up to 32 bytes at
+ * a time where possible.
+ *
+ * Note: r12 (aka ip) can be trashed during the function along with
+ * r0-r3 although r0-r2 have defined uses i.e. src, dest, len through out.
+ * Additional registers are preserved prior to use i.e. r4, r5 & lr
+ *
+ * Apologies for the state of the comments ;-)
+ */
+/* LINTSTUB: Func: void *memcpy(void *dst, const void *src, size_t len) */
+ENTRY(memcpy)
+ /* save leaf functions having to store this away */
+ stmdb sp!, {r0, lr} /* memcpy() returns dest addr */
+
+ subs r2, r2, #4
+ blt .Lmemcpy_l4 /* less than 4 bytes */
+ ands r12, r0, #3
+ bne .Lmemcpy_destul /* oh unaligned destination addr */
+ ands r12, r1, #3
+ bne .Lmemcpy_srcul /* oh unaligned source addr */
+
+.Lmemcpy_t8:
+ /* We have aligned source and destination */
+ subs r2, r2, #8
+ blt .Lmemcpy_l12 /* less than 12 bytes (4 from above) */
+ subs r2, r2, #0x14
+ blt .Lmemcpy_l32 /* less than 32 bytes (12 from above) */
+ stmdb sp!, {r4} /* borrow r4 */
+
+ /* blat 32 bytes at a time */
+ /* XXX for really big copies perhaps we should use more registers */
+.Lmemcpy_loop32:
+ ldmia r1!, {r3, r4, r12, lr}
+ stmia r0!, {r3, r4, r12, lr}
+ ldmia r1!, {r3, r4, r12, lr}
+ stmia r0!, {r3, r4, r12, lr}
+ subs r2, r2, #0x20
+ bge .Lmemcpy_loop32
+
+ cmn r2, #0x10
+ ldmiage r1!, {r3, r4, r12, lr} /* blat a remaining 16 bytes */
+ stmiage r0!, {r3, r4, r12, lr}
+ subge r2, r2, #0x10
+ ldmia sp!, {r4} /* return r4 */
+
+.Lmemcpy_l32:
+ adds r2, r2, #0x14
+
+ /* blat 12 bytes at a time */
+.Lmemcpy_loop12:
+ ldmiage r1!, {r3, r12, lr}
+ stmiage r0!, {r3, r12, lr}
+ subsge r2, r2, #0x0c
+ bge .Lmemcpy_loop12
+
+.Lmemcpy_l12:
+ adds r2, r2, #8
+ blt .Lmemcpy_l4
+
+ subs r2, r2, #4
+ ldrlt r3, [r1], #4
+ strlt r3, [r0], #4
+ ldmiage r1!, {r3, r12}
+ stmiage r0!, {r3, r12}
+ subge r2, r2, #4
+
+.Lmemcpy_l4:
+ /* less than 4 bytes to go */
+ adds r2, r2, #4
+#ifdef __APCS_26_
+ ldmiaeq sp!, {r0, pc}^ /* done */
+#else
+ ldmiaeq sp!, {r0, pc} /* done */
+#endif
+ /* copy the crud byte at a time */
+ cmp r2, #2
+ ldrb r3, [r1], #1
+ strb r3, [r0], #1
+ ldrbge r3, [r1], #1
+ strbge r3, [r0], #1
+ ldrbgt r3, [r1], #1
+ strbgt r3, [r0], #1
+ ldmia sp!, {r0, pc}
+
+ /* erg - unaligned destination */
+.Lmemcpy_destul:
+ rsb r12, r12, #4
+ cmp r12, #2
+
+ /* align destination with byte copies */
+ ldrb r3, [r1], #1
+ strb r3, [r0], #1
+ ldrbge r3, [r1], #1
+ strbge r3, [r0], #1
+ ldrbgt r3, [r1], #1
+ strbgt r3, [r0], #1
+ subs r2, r2, r12
+ blt .Lmemcpy_l4 /* less the 4 bytes */
+
+ ands r12, r1, #3
+ beq .Lmemcpy_t8 /* we have an aligned source */
+
+ /* erg - unaligned source */
+ /* This is where it gets nasty ... */
+.Lmemcpy_srcul:
+ bic r1, r1, #3
+ ldr lr, [r1], #4
+ cmp r12, #2
+ bgt .Lmemcpy_srcul3
+ beq .Lmemcpy_srcul2
+ cmp r2, #0x0c
+ blt .Lmemcpy_srcul1loop4
+ sub r2, r2, #0x0c
+ stmdb sp!, {r4, r5}
+
+.Lmemcpy_srcul1loop16:
+#ifdef __ARMEB__
+ mov r3, lr, lsl #8
+#else
+ mov r3, lr, lsr #8
+#endif
+ ldmia r1!, {r4, r5, r12, lr}
+#ifdef __ARMEB__
+ orr r3, r3, r4, lsr #24
+ mov r4, r4, lsl #8
+ orr r4, r4, r5, lsr #24
+ mov r5, r5, lsl #8
+ orr r5, r5, r12, lsr #24
+ mov r12, r12, lsl #8
+ orr r12, r12, lr, lsr #24
+#else
+ orr r3, r3, r4, lsl #24
+ mov r4, r4, lsr #8
+ orr r4, r4, r5, lsl #24
+ mov r5, r5, lsr #8
+ orr r5, r5, r12, lsl #24
+ mov r12, r12, lsr #8
+ orr r12, r12, lr, lsl #24
+#endif
+ stmia r0!, {r3-r5, r12}
+ subs r2, r2, #0x10
+ bge .Lmemcpy_srcul1loop16
+ ldmia sp!, {r4, r5}
+ adds r2, r2, #0x0c
+ blt .Lmemcpy_srcul1l4
+
+.Lmemcpy_srcul1loop4:
+#ifdef __ARMEB__
+ mov r12, lr, lsl #8
+#else
+ mov r12, lr, lsr #8
+#endif
+ ldr lr, [r1], #4
+#ifdef __ARMEB__
+ orr r12, r12, lr, lsr #24
+#else
+ orr r12, r12, lr, lsl #24
+#endif
+ str r12, [r0], #4
+ subs r2, r2, #4
+ bge .Lmemcpy_srcul1loop4
+
+.Lmemcpy_srcul1l4:
+ sub r1, r1, #3
+ b .Lmemcpy_l4
+
+.Lmemcpy_srcul2:
+ cmp r2, #0x0c
+ blt .Lmemcpy_srcul2loop4
+ sub r2, r2, #0x0c
+ stmdb sp!, {r4, r5}
+
+.Lmemcpy_srcul2loop16:
+#ifdef __ARMEB__
+ mov r3, lr, lsl #16
+#else
+ mov r3, lr, lsr #16
+#endif
+ ldmia r1!, {r4, r5, r12, lr}
+#ifdef __ARMEB__
+ orr r3, r3, r4, lsr #16
+ mov r4, r4, lsl #16
+ orr r4, r4, r5, lsr #16
+ mov r5, r5, lsl #16
+ orr r5, r5, r12, lsr #16
+ mov r12, r12, lsl #16
+ orr r12, r12, lr, lsr #16
+#else
+ orr r3, r3, r4, lsl #16
+ mov r4, r4, lsr #16
+ orr r4, r4, r5, lsl #16
+ mov r5, r5, lsr #16
+ orr r5, r5, r12, lsl #16
+ mov r12, r12, lsr #16
+ orr r12, r12, lr, lsl #16
+#endif
+ stmia r0!, {r3-r5, r12}
+ subs r2, r2, #0x10
+ bge .Lmemcpy_srcul2loop16
+ ldmia sp!, {r4, r5}
+ adds r2, r2, #0x0c
+ blt .Lmemcpy_srcul2l4
+
+.Lmemcpy_srcul2loop4:
+#ifdef __ARMEB__
+ mov r12, lr, lsl #16
+#else
+ mov r12, lr, lsr #16
+#endif
+ ldr lr, [r1], #4
+#ifdef __ARMEB__
+ orr r12, r12, lr, lsr #16
+#else
+ orr r12, r12, lr, lsl #16
+#endif
+ str r12, [r0], #4
+ subs r2, r2, #4
+ bge .Lmemcpy_srcul2loop4
+
+.Lmemcpy_srcul2l4:
+ sub r1, r1, #2
+ b .Lmemcpy_l4
+
+.Lmemcpy_srcul3:
+ cmp r2, #0x0c
+ blt .Lmemcpy_srcul3loop4
+ sub r2, r2, #0x0c
+ stmdb sp!, {r4, r5}
+
+.Lmemcpy_srcul3loop16:
+#ifdef __ARMEB__
+ mov r3, lr, lsl #24
+#else
+ mov r3, lr, lsr #24
+#endif
+ ldmia r1!, {r4, r5, r12, lr}
+#ifdef __ARMEB__
+ orr r3, r3, r4, lsr #8
+ mov r4, r4, lsl #24
+ orr r4, r4, r5, lsr #8
+ mov r5, r5, lsl #24
+ orr r5, r5, r12, lsr #8
+ mov r12, r12, lsl #24
+ orr r12, r12, lr, lsr #8
+#else
+ orr r3, r3, r4, lsl #8
+ mov r4, r4, lsr #24
+ orr r4, r4, r5, lsl #8
+ mov r5, r5, lsr #24
+ orr r5, r5, r12, lsl #8
+ mov r12, r12, lsr #24
+ orr r12, r12, lr, lsl #8
+#endif
+ stmia r0!, {r3-r5, r12}
+ subs r2, r2, #0x10
+ bge .Lmemcpy_srcul3loop16
+ ldmia sp!, {r4, r5}
+ adds r2, r2, #0x0c
+ blt .Lmemcpy_srcul3l4
+
+.Lmemcpy_srcul3loop4:
+#ifdef __ARMEB__
+ mov r12, lr, lsl #24
+#else
+ mov r12, lr, lsr #24
+#endif
+ ldr lr, [r1], #4
+#ifdef __ARMEB__
+ orr r12, r12, lr, lsr #8
+#else
+ orr r12, r12, lr, lsl #8
+#endif
+ str r12, [r0], #4
+ subs r2, r2, #4
+ bge .Lmemcpy_srcul3loop4
+
+.Lmemcpy_srcul3l4:
+ sub r1, r1, #1
+ b .Lmemcpy_l4
+END(memcpy)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/arm/string/memcpy_xscale.S b/lib/libc/arm/string/memcpy_xscale.S
new file mode 100644
index 000000000000..ab01544fc176
--- /dev/null
+++ b/lib/libc/arm/string/memcpy_xscale.S
@@ -0,0 +1,1788 @@
+/* $NetBSD: memcpy_xscale.S,v 1.1 2003/10/14 07:51:45 scw Exp $ */
+
+/*
+ * Copyright 2003 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Steve C. Woodford for Wasabi Systems, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the NetBSD Project by
+ * Wasabi Systems, Inc.
+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+.syntax unified
+
+/* LINTSTUB: Func: void *memcpy(void *dst, const void *src, size_t len) */
+ENTRY(memcpy)
+ pld [r1]
+ cmp r2, #0x0c
+ ble .Lmemcpy_short /* <= 12 bytes */
+ mov r3, r0 /* We must not clobber r0 */
+
+ /* Word-align the destination buffer */
+ ands ip, r3, #0x03 /* Already word aligned? */
+ beq .Lmemcpy_wordaligned /* Yup */
+ cmp ip, #0x02
+ ldrb ip, [r1], #0x01
+ sub r2, r2, #0x01
+ strb ip, [r3], #0x01
+ ldrble ip, [r1], #0x01
+ suble r2, r2, #0x01
+ strble ip, [r3], #0x01
+ ldrblt ip, [r1], #0x01
+ sublt r2, r2, #0x01
+ strblt ip, [r3], #0x01
+
+ /* Destination buffer is now word aligned */
+.Lmemcpy_wordaligned:
+ ands ip, r1, #0x03 /* Is src also word-aligned? */
+ bne .Lmemcpy_bad_align /* Nope. Things just got bad */
+
+ /* Quad-align the destination buffer */
+ tst r3, #0x07 /* Already quad aligned? */
+ ldrne ip, [r1], #0x04
+ stmfd sp!, {r4-r9} /* Free up some registers */
+ subne r2, r2, #0x04
+ strne ip, [r3], #0x04
+
+ /* Destination buffer quad aligned, source is at least word aligned */
+ subs r2, r2, #0x80
+ blt .Lmemcpy_w_lessthan128
+
+ /* Copy 128 bytes at a time */
+.Lmemcpy_w_loop128:
+ ldr r4, [r1], #0x04 /* LD:00-03 */
+ ldr r5, [r1], #0x04 /* LD:04-07 */
+ pld [r1, #0x18] /* Prefetch 0x20 */
+ ldr r6, [r1], #0x04 /* LD:08-0b */
+ ldr r7, [r1], #0x04 /* LD:0c-0f */
+ ldr r8, [r1], #0x04 /* LD:10-13 */
+ ldr r9, [r1], #0x04 /* LD:14-17 */
+ strd r4, [r3], #0x08 /* ST:00-07 */
+ ldr r4, [r1], #0x04 /* LD:18-1b */
+ ldr r5, [r1], #0x04 /* LD:1c-1f */
+ strd r6, [r3], #0x08 /* ST:08-0f */
+ ldr r6, [r1], #0x04 /* LD:20-23 */
+ ldr r7, [r1], #0x04 /* LD:24-27 */
+ pld [r1, #0x18] /* Prefetch 0x40 */
+ strd r8, [r3], #0x08 /* ST:10-17 */
+ ldr r8, [r1], #0x04 /* LD:28-2b */
+ ldr r9, [r1], #0x04 /* LD:2c-2f */
+ strd r4, [r3], #0x08 /* ST:18-1f */
+ ldr r4, [r1], #0x04 /* LD:30-33 */
+ ldr r5, [r1], #0x04 /* LD:34-37 */
+ strd r6, [r3], #0x08 /* ST:20-27 */
+ ldr r6, [r1], #0x04 /* LD:38-3b */
+ ldr r7, [r1], #0x04 /* LD:3c-3f */
+ strd r8, [r3], #0x08 /* ST:28-2f */
+ ldr r8, [r1], #0x04 /* LD:40-43 */
+ ldr r9, [r1], #0x04 /* LD:44-47 */
+ pld [r1, #0x18] /* Prefetch 0x60 */
+ strd r4, [r3], #0x08 /* ST:30-37 */
+ ldr r4, [r1], #0x04 /* LD:48-4b */
+ ldr r5, [r1], #0x04 /* LD:4c-4f */
+ strd r6, [r3], #0x08 /* ST:38-3f */
+ ldr r6, [r1], #0x04 /* LD:50-53 */
+ ldr r7, [r1], #0x04 /* LD:54-57 */
+ strd r8, [r3], #0x08 /* ST:40-47 */
+ ldr r8, [r1], #0x04 /* LD:58-5b */
+ ldr r9, [r1], #0x04 /* LD:5c-5f */
+ strd r4, [r3], #0x08 /* ST:48-4f */
+ ldr r4, [r1], #0x04 /* LD:60-63 */
+ ldr r5, [r1], #0x04 /* LD:64-67 */
+ pld [r1, #0x18] /* Prefetch 0x80 */
+ strd r6, [r3], #0x08 /* ST:50-57 */
+ ldr r6, [r1], #0x04 /* LD:68-6b */
+ ldr r7, [r1], #0x04 /* LD:6c-6f */
+ strd r8, [r3], #0x08 /* ST:58-5f */
+ ldr r8, [r1], #0x04 /* LD:70-73 */
+ ldr r9, [r1], #0x04 /* LD:74-77 */
+ strd r4, [r3], #0x08 /* ST:60-67 */
+ ldr r4, [r1], #0x04 /* LD:78-7b */
+ ldr r5, [r1], #0x04 /* LD:7c-7f */
+ strd r6, [r3], #0x08 /* ST:68-6f */
+ strd r8, [r3], #0x08 /* ST:70-77 */
+ subs r2, r2, #0x80
+ strd r4, [r3], #0x08 /* ST:78-7f */
+ bge .Lmemcpy_w_loop128
+
+.Lmemcpy_w_lessthan128:
+ adds r2, r2, #0x80 /* Adjust for extra sub */
+ ldmfdeq sp!, {r4-r9}
+ bxeq lr /* Return now if done */
+ subs r2, r2, #0x20
+ blt .Lmemcpy_w_lessthan32
+
+ /* Copy 32 bytes at a time */
+.Lmemcpy_w_loop32:
+ ldr r4, [r1], #0x04
+ ldr r5, [r1], #0x04
+ pld [r1, #0x18]
+ ldr r6, [r1], #0x04
+ ldr r7, [r1], #0x04
+ ldr r8, [r1], #0x04
+ ldr r9, [r1], #0x04
+ strd r4, [r3], #0x08
+ ldr r4, [r1], #0x04
+ ldr r5, [r1], #0x04
+ strd r6, [r3], #0x08
+ strd r8, [r3], #0x08
+ subs r2, r2, #0x20
+ strd r4, [r3], #0x08
+ bge .Lmemcpy_w_loop32
+
+.Lmemcpy_w_lessthan32:
+ adds r2, r2, #0x20 /* Adjust for extra sub */
+ ldmfdeq sp!, {r4-r9}
+ bxeq lr /* Return now if done */
+
+ and r4, r2, #0x18
+ rsbs r4, r4, #0x18
+ addne pc, pc, r4, lsl #1
+ nop
+
+ /* At least 24 bytes remaining */
+ ldr r4, [r1], #0x04
+ ldr r5, [r1], #0x04
+ sub r2, r2, #0x08
+ strd r4, [r3], #0x08
+
+ /* At least 16 bytes remaining */
+ ldr r4, [r1], #0x04
+ ldr r5, [r1], #0x04
+ sub r2, r2, #0x08
+ strd r4, [r3], #0x08
+
+ /* At least 8 bytes remaining */
+ ldr r4, [r1], #0x04
+ ldr r5, [r1], #0x04
+ subs r2, r2, #0x08
+ strd r4, [r3], #0x08
+
+ /* Less than 8 bytes remaining */
+ ldmfd sp!, {r4-r9}
+ bxeq lr /* Return now if done */
+ subs r2, r2, #0x04
+ ldrge ip, [r1], #0x04
+ strge ip, [r3], #0x04
+ bxeq lr /* Return now if done */
+ addlt r2, r2, #0x04
+ ldrb ip, [r1], #0x01
+ cmp r2, #0x02
+ ldrbge r2, [r1], #0x01
+ strb ip, [r3], #0x01
+ ldrbgt ip, [r1]
+ strbge r2, [r3], #0x01
+ strbgt ip, [r3]
+ bx lr
+
+
+/*
+ * At this point, it has not been possible to word align both buffers.
+ * The destination buffer is word aligned, but the source buffer is not.
+ */
+.Lmemcpy_bad_align:
+ stmfd sp!, {r4-r7}
+ bic r1, r1, #0x03
+ cmp ip, #2
+ ldr ip, [r1], #0x04
+ bgt .Lmemcpy_bad3
+ beq .Lmemcpy_bad2
+ b .Lmemcpy_bad1
+
+.Lmemcpy_bad1_loop16:
+#ifdef __ARMEB__
+ mov r4, ip, lsl #8
+#else
+ mov r4, ip, lsr #8
+#endif
+ ldr r5, [r1], #0x04
+ pld [r1, #0x018]
+ ldr r6, [r1], #0x04
+ ldr r7, [r1], #0x04
+ ldr ip, [r1], #0x04
+#ifdef __ARMEB__
+ orr r4, r4, r5, lsr #24
+ mov r5, r5, lsl #8
+ orr r5, r5, r6, lsr #24
+ mov r6, r6, lsl #8
+ orr r6, r6, r7, lsr #24
+ mov r7, r7, lsl #8
+ orr r7, r7, ip, lsr #24
+#else
+ orr r4, r4, r5, lsl #24
+ mov r5, r5, lsr #8
+ orr r5, r5, r6, lsl #24
+ mov r6, r6, lsr #8
+ orr r6, r6, r7, lsl #24
+ mov r7, r7, lsr #8
+ orr r7, r7, ip, lsl #24
+#endif
+ str r4, [r3], #0x04
+ str r5, [r3], #0x04
+ str r6, [r3], #0x04
+ str r7, [r3], #0x04
+.Lmemcpy_bad1:
+ subs r2, r2, #0x10
+ bge .Lmemcpy_bad1_loop16
+
+ adds r2, r2, #0x10
+ ldmfdeq sp!, {r4-r7}
+ bxeq lr /* Return now if done */
+ subs r2, r2, #0x04
+ sublt r1, r1, #0x03
+ blt .Lmemcpy_bad_done
+
+.Lmemcpy_bad1_loop4:
+#ifdef __ARMEB__
+ mov r4, ip, lsl #8
+#else
+ mov r4, ip, lsr #8
+#endif
+ ldr ip, [r1], #0x04
+ subs r2, r2, #0x04
+#ifdef __ARMEB__
+ orr r4, r4, ip, lsr #24
+#else
+ orr r4, r4, ip, lsl #24
+#endif
+ str r4, [r3], #0x04
+ bge .Lmemcpy_bad1_loop4
+ sub r1, r1, #0x03
+ b .Lmemcpy_bad_done
+
+.Lmemcpy_bad2_loop16:
+#ifdef __ARMEB__
+ mov r4, ip, lsl #16
+#else
+ mov r4, ip, lsr #16
+#endif
+ ldr r5, [r1], #0x04
+ pld [r1, #0x018]
+ ldr r6, [r1], #0x04
+ ldr r7, [r1], #0x04
+ ldr ip, [r1], #0x04
+#ifdef __ARMEB__
+ orr r4, r4, r5, lsr #16
+ mov r5, r5, lsl #16
+ orr r5, r5, r6, lsr #16
+ mov r6, r6, lsl #16
+ orr r6, r6, r7, lsr #16
+ mov r7, r7, lsl #16
+ orr r7, r7, ip, lsr #16
+#else
+ orr r4, r4, r5, lsl #16
+ mov r5, r5, lsr #16
+ orr r5, r5, r6, lsl #16
+ mov r6, r6, lsr #16
+ orr r6, r6, r7, lsl #16
+ mov r7, r7, lsr #16
+ orr r7, r7, ip, lsl #16
+#endif
+ str r4, [r3], #0x04
+ str r5, [r3], #0x04
+ str r6, [r3], #0x04
+ str r7, [r3], #0x04
+.Lmemcpy_bad2:
+ subs r2, r2, #0x10
+ bge .Lmemcpy_bad2_loop16
+
+ adds r2, r2, #0x10
+ ldmfdeq sp!, {r4-r7}
+ bxeq lr /* Return now if done */
+ subs r2, r2, #0x04
+ sublt r1, r1, #0x02
+ blt .Lmemcpy_bad_done
+
+.Lmemcpy_bad2_loop4:
+#ifdef __ARMEB__
+ mov r4, ip, lsl #16
+#else
+ mov r4, ip, lsr #16
+#endif
+ ldr ip, [r1], #0x04
+ subs r2, r2, #0x04
+#ifdef __ARMEB__
+ orr r4, r4, ip, lsr #16
+#else
+ orr r4, r4, ip, lsl #16
+#endif
+ str r4, [r3], #0x04
+ bge .Lmemcpy_bad2_loop4
+ sub r1, r1, #0x02
+ b .Lmemcpy_bad_done
+
+.Lmemcpy_bad3_loop16:
+#ifdef __ARMEB__
+ mov r4, ip, lsl #24
+#else
+ mov r4, ip, lsr #24
+#endif
+ ldr r5, [r1], #0x04
+ pld [r1, #0x018]
+ ldr r6, [r1], #0x04
+ ldr r7, [r1], #0x04
+ ldr ip, [r1], #0x04
+#ifdef __ARMEB__
+ orr r4, r4, r5, lsr #8
+ mov r5, r5, lsl #24
+ orr r5, r5, r6, lsr #8
+ mov r6, r6, lsl #24
+ orr r6, r6, r7, lsr #8
+ mov r7, r7, lsl #24
+ orr r7, r7, ip, lsr #8
+#else
+ orr r4, r4, r5, lsl #8
+ mov r5, r5, lsr #24
+ orr r5, r5, r6, lsl #8
+ mov r6, r6, lsr #24
+ orr r6, r6, r7, lsl #8
+ mov r7, r7, lsr #24
+ orr r7, r7, ip, lsl #8
+#endif
+ str r4, [r3], #0x04
+ str r5, [r3], #0x04
+ str r6, [r3], #0x04
+ str r7, [r3], #0x04
+.Lmemcpy_bad3:
+ subs r2, r2, #0x10
+ bge .Lmemcpy_bad3_loop16
+
+ adds r2, r2, #0x10
+ ldmfdeq sp!, {r4-r7}
+ bxeq lr /* Return now if done */
+ subs r2, r2, #0x04
+ sublt r1, r1, #0x01
+ blt .Lmemcpy_bad_done
+
+.Lmemcpy_bad3_loop4:
+#ifdef __ARMEB__
+ mov r4, ip, lsl #24
+#else
+ mov r4, ip, lsr #24
+#endif
+ ldr ip, [r1], #0x04
+ subs r2, r2, #0x04
+#ifdef __ARMEB__
+ orr r4, r4, ip, lsr #8
+#else
+ orr r4, r4, ip, lsl #8
+#endif
+ str r4, [r3], #0x04
+ bge .Lmemcpy_bad3_loop4
+ sub r1, r1, #0x01
+
+.Lmemcpy_bad_done:
+ ldmfd sp!, {r4-r7}
+ adds r2, r2, #0x04
+ bxeq lr
+ ldrb ip, [r1], #0x01
+ cmp r2, #0x02
+ ldrbge r2, [r1], #0x01
+ strb ip, [r3], #0x01
+ ldrbgt ip, [r1]
+ strbge r2, [r3], #0x01
+ strbgt ip, [r3]
+ bx lr
+
+
+/*
+ * Handle short copies (less than 16 bytes), possibly misaligned.
+ * Some of these are *very* common, thanks to the network stack,
+ * and so are handled specially.
+ */
+.Lmemcpy_short:
+#ifndef _STANDALONE
+ add pc, pc, r2, lsl #2
+ nop
+ bx lr /* 0x00 */
+ b .Lmemcpy_bytewise /* 0x01 */
+ b .Lmemcpy_bytewise /* 0x02 */
+ b .Lmemcpy_bytewise /* 0x03 */
+ b .Lmemcpy_4 /* 0x04 */
+ b .Lmemcpy_bytewise /* 0x05 */
+ b .Lmemcpy_6 /* 0x06 */
+ b .Lmemcpy_bytewise /* 0x07 */
+ b .Lmemcpy_8 /* 0x08 */
+ b .Lmemcpy_bytewise /* 0x09 */
+ b .Lmemcpy_bytewise /* 0x0a */
+ b .Lmemcpy_bytewise /* 0x0b */
+ b .Lmemcpy_c /* 0x0c */
+#endif
+.Lmemcpy_bytewise:
+ mov r3, r0 /* We must not clobber r0 */
+ ldrb ip, [r1], #0x01
+1: subs r2, r2, #0x01
+ strb ip, [r3], #0x01
+ ldrbne ip, [r1], #0x01
+ bne 1b
+ bx lr
+
+#ifndef _STANDALONE
+/******************************************************************************
+ * Special case for 4 byte copies
+ */
+#define LMEMCPY_4_LOG2 6 /* 64 bytes */
+#define LMEMCPY_4_PAD .align LMEMCPY_4_LOG2
+ LMEMCPY_4_PAD
+.Lmemcpy_4:
+ and r2, r1, #0x03
+ orr r2, r2, r0, lsl #2
+ ands r2, r2, #0x0f
+ sub r3, pc, #0x14
+ addne pc, r3, r2, lsl #LMEMCPY_4_LOG2
+
+/*
+ * 0000: dst is 32-bit aligned, src is 32-bit aligned
+ */
+ ldr r2, [r1]
+ str r2, [r0]
+ bx lr
+ LMEMCPY_4_PAD
+
+/*
+ * 0001: dst is 32-bit aligned, src is 8-bit aligned
+ */
+ ldr r3, [r1, #-1] /* BE:r3 = x012 LE:r3 = 210x */
+ ldr r2, [r1, #3] /* BE:r2 = 3xxx LE:r2 = xxx3 */
+#ifdef __ARMEB__
+ mov r3, r3, lsl #8 /* r3 = 012. */
+ orr r3, r3, r2, lsr #24 /* r3 = 0123 */
+#else
+ mov r3, r3, lsr #8 /* r3 = .210 */
+ orr r3, r3, r2, lsl #24 /* r3 = 3210 */
+#endif
+ str r3, [r0]
+ bx lr
+ LMEMCPY_4_PAD
+
+/*
+ * 0010: dst is 32-bit aligned, src is 16-bit aligned
+ */
+#ifdef __ARMEB__
+ ldrh r3, [r1]
+ ldrh r2, [r1, #0x02]
+#else
+ ldrh r3, [r1, #0x02]
+ ldrh r2, [r1]
+#endif
+ orr r3, r2, r3, lsl #16
+ str r3, [r0]
+ bx lr
+ LMEMCPY_4_PAD
+
+/*
+ * 0011: dst is 32-bit aligned, src is 8-bit aligned
+ */
+ ldr r3, [r1, #-3] /* BE:r3 = xxx0 LE:r3 = 0xxx */
+ ldr r2, [r1, #1] /* BE:r2 = 123x LE:r2 = x321 */
+#ifdef __ARMEB__
+ mov r3, r3, lsl #24 /* r3 = 0... */
+ orr r3, r3, r2, lsr #8 /* r3 = 0123 */
+#else
+ mov r3, r3, lsr #24 /* r3 = ...0 */
+ orr r3, r3, r2, lsl #8 /* r3 = 3210 */
+#endif
+ str r3, [r0]
+ bx lr
+ LMEMCPY_4_PAD
+
+/*
+ * 0100: dst is 8-bit aligned, src is 32-bit aligned
+ */
+ ldr r2, [r1]
+#ifdef __ARMEB__
+ strb r2, [r0, #0x03]
+ mov r3, r2, lsr #8
+ mov r1, r2, lsr #24
+ strb r1, [r0]
+#else
+ strb r2, [r0]
+ mov r3, r2, lsr #8
+ mov r1, r2, lsr #24
+ strb r1, [r0, #0x03]
+#endif
+ strh r3, [r0, #0x01]
+ bx lr
+ LMEMCPY_4_PAD
+
+/*
+ * 0101: dst is 8-bit aligned, src is 8-bit aligned
+ */
+ ldrb r2, [r1]
+ ldrh r3, [r1, #0x01]
+ ldrb r1, [r1, #0x03]
+ strb r2, [r0]
+ strh r3, [r0, #0x01]
+ strb r1, [r0, #0x03]
+ bx lr
+ LMEMCPY_4_PAD
+
+/*
+ * 0110: dst is 8-bit aligned, src is 16-bit aligned
+ */
+ ldrh r2, [r1] /* BE:r2 = ..01 LE:r2 = ..10 */
+ ldrh r3, [r1, #0x02] /* LE:r3 = ..23 LE:r3 = ..32 */
+#ifdef __ARMEB__
+ mov r1, r2, lsr #8 /* r1 = ...0 */
+ strb r1, [r0]
+ mov r2, r2, lsl #8 /* r2 = .01. */
+ orr r2, r2, r3, lsr #8 /* r2 = .012 */
+#else
+ strb r2, [r0]
+ mov r2, r2, lsr #8 /* r2 = ...1 */
+ orr r2, r2, r3, lsl #8 /* r2 = .321 */
+ mov r3, r3, lsr #8 /* r3 = ...3 */
+#endif
+ strh r2, [r0, #0x01]
+ strb r3, [r0, #0x03]
+ bx lr
+ LMEMCPY_4_PAD
+
+/*
+ * 0111: dst is 8-bit aligned, src is 8-bit aligned
+ */
+ ldrb r2, [r1]
+ ldrh r3, [r1, #0x01]
+ ldrb r1, [r1, #0x03]
+ strb r2, [r0]
+ strh r3, [r0, #0x01]
+ strb r1, [r0, #0x03]
+ bx lr
+ LMEMCPY_4_PAD
+
+/*
+ * 1000: dst is 16-bit aligned, src is 32-bit aligned
+ */
+ ldr r2, [r1]
+#ifdef __ARMEB__
+ strh r2, [r0, #0x02]
+ mov r3, r2, lsr #16
+ strh r3, [r0]
+#else
+ strh r2, [r0]
+ mov r3, r2, lsr #16
+ strh r3, [r0, #0x02]
+#endif
+ bx lr
+ LMEMCPY_4_PAD
+
+/*
+ * 1001: dst is 16-bit aligned, src is 8-bit aligned
+ */
+ ldr r2, [r1, #-1] /* BE:r2 = x012 LE:r2 = 210x */
+ ldr r3, [r1, #3] /* BE:r3 = 3xxx LE:r3 = xxx3 */
+ mov r1, r2, lsr #8 /* BE:r1 = .x01 LE:r1 = .210 */
+ strh r1, [r0]
+#ifdef __ARMEB__
+ mov r2, r2, lsl #8 /* r2 = 012. */
+ orr r2, r2, r3, lsr #24 /* r2 = 0123 */
+#else
+ mov r2, r2, lsr #24 /* r2 = ...2 */
+ orr r2, r2, r3, lsl #8 /* r2 = xx32 */
+#endif
+ strh r2, [r0, #0x02]
+ bx lr
+ LMEMCPY_4_PAD
+
+/*
+ * 1010: dst is 16-bit aligned, src is 16-bit aligned
+ */
+ ldrh r2, [r1]
+ ldrh r3, [r1, #0x02]
+ strh r2, [r0]
+ strh r3, [r0, #0x02]
+ bx lr
+ LMEMCPY_4_PAD
+
+/*
+ * 1011: dst is 16-bit aligned, src is 8-bit aligned
+ */
+ ldr r3, [r1, #1] /* BE:r3 = 123x LE:r3 = x321 */
+ ldr r2, [r1, #-3] /* BE:r2 = xxx0 LE:r2 = 0xxx */
+ mov r1, r3, lsr #8 /* BE:r1 = .123 LE:r1 = .x32 */
+ strh r1, [r0, #0x02]
+#ifdef __ARMEB__
+ mov r3, r3, lsr #24 /* r3 = ...1 */
+ orr r3, r3, r2, lsl #8 /* r3 = xx01 */
+#else
+ mov r3, r3, lsl #8 /* r3 = 321. */
+ orr r3, r3, r2, lsr #24 /* r3 = 3210 */
+#endif
+ strh r3, [r0]
+ bx lr
+ LMEMCPY_4_PAD
+
+/*
+ * 1100: dst is 8-bit aligned, src is 32-bit aligned
+ */
+ ldr r2, [r1] /* BE:r2 = 0123 LE:r2 = 3210 */
+#ifdef __ARMEB__
+ strb r2, [r0, #0x03]
+ mov r3, r2, lsr #8
+ mov r1, r2, lsr #24
+ strh r3, [r0, #0x01]
+ strb r1, [r0]
+#else
+ strb r2, [r0]
+ mov r3, r2, lsr #8
+ mov r1, r2, lsr #24
+ strh r3, [r0, #0x01]
+ strb r1, [r0, #0x03]
+#endif
+ bx lr
+ LMEMCPY_4_PAD
+
+/*
+ * 1101: dst is 8-bit aligned, src is 8-bit aligned
+ */
+ ldrb r2, [r1]
+ ldrh r3, [r1, #0x01]
+ ldrb r1, [r1, #0x03]
+ strb r2, [r0]
+ strh r3, [r0, #0x01]
+ strb r1, [r0, #0x03]
+ bx lr
+ LMEMCPY_4_PAD
+
+/*
+ * 1110: dst is 8-bit aligned, src is 16-bit aligned
+ */
+#ifdef __ARMEB__
+ ldrh r3, [r1, #0x02] /* BE:r3 = ..23 LE:r3 = ..32 */
+ ldrh r2, [r1] /* BE:r2 = ..01 LE:r2 = ..10 */
+ strb r3, [r0, #0x03]
+ mov r3, r3, lsr #8 /* r3 = ...2 */
+ orr r3, r3, r2, lsl #8 /* r3 = ..12 */
+ strh r3, [r0, #0x01]
+ mov r2, r2, lsr #8 /* r2 = ...0 */
+ strb r2, [r0]
+#else
+ ldrh r2, [r1] /* BE:r2 = ..01 LE:r2 = ..10 */
+ ldrh r3, [r1, #0x02] /* BE:r3 = ..23 LE:r3 = ..32 */
+ strb r2, [r0]
+ mov r2, r2, lsr #8 /* r2 = ...1 */
+ orr r2, r2, r3, lsl #8 /* r2 = .321 */
+ strh r2, [r0, #0x01]
+ mov r3, r3, lsr #8 /* r3 = ...3 */
+ strb r3, [r0, #0x03]
+#endif
+ bx lr
+ LMEMCPY_4_PAD
+
+/*
+ * 1111: dst is 8-bit aligned, src is 8-bit aligned
+ */
+ ldrb r2, [r1]
+ ldrh r3, [r1, #0x01]
+ ldrb r1, [r1, #0x03]
+ strb r2, [r0]
+ strh r3, [r0, #0x01]
+ strb r1, [r0, #0x03]
+ bx lr
+ LMEMCPY_4_PAD
+
+
+/******************************************************************************
+ * Special case for 6 byte copies
+ */
+#define LMEMCPY_6_LOG2 6 /* 64 bytes */
+#define LMEMCPY_6_PAD .align LMEMCPY_6_LOG2
+ LMEMCPY_6_PAD
+.Lmemcpy_6:
+ and r2, r1, #0x03
+ orr r2, r2, r0, lsl #2
+ ands r2, r2, #0x0f
+ sub r3, pc, #0x14
+ addne pc, r3, r2, lsl #LMEMCPY_6_LOG2
+
+/*
+ * 0000: dst is 32-bit aligned, src is 32-bit aligned
+ */
+ ldr r2, [r1]
+ ldrh r3, [r1, #0x04]
+ str r2, [r0]
+ strh r3, [r0, #0x04]
+ bx lr
+ LMEMCPY_6_PAD
+
+/*
+ * 0001: dst is 32-bit aligned, src is 8-bit aligned
+ */
+ ldr r2, [r1, #-1] /* BE:r2 = x012 LE:r2 = 210x */
+ ldr r3, [r1, #0x03] /* BE:r3 = 345x LE:r3 = x543 */
+#ifdef __ARMEB__
+ mov r2, r2, lsl #8 /* r2 = 012. */
+ orr r2, r2, r3, lsr #24 /* r2 = 0123 */
+#else
+ mov r2, r2, lsr #8 /* r2 = .210 */
+ orr r2, r2, r3, lsl #24 /* r2 = 3210 */
+#endif
+ mov r3, r3, lsr #8 /* BE:r3 = .345 LE:r3 = .x54 */
+ str r2, [r0]
+ strh r3, [r0, #0x04]
+ bx lr
+ LMEMCPY_6_PAD
+
+/*
+ * 0010: dst is 32-bit aligned, src is 16-bit aligned
+ */
+ ldr r3, [r1, #0x02] /* BE:r3 = 2345 LE:r3 = 5432 */
+ ldrh r2, [r1] /* BE:r2 = ..01 LE:r2 = ..10 */
+#ifdef __ARMEB__
+ mov r1, r3, lsr #16 /* r1 = ..23 */
+ orr r1, r1, r2, lsl #16 /* r1 = 0123 */
+ str r1, [r0]
+ strh r3, [r0, #0x04]
+#else
+ mov r1, r3, lsr #16 /* r1 = ..54 */
+ orr r2, r2, r3, lsl #16 /* r2 = 3210 */
+ str r2, [r0]
+ strh r1, [r0, #0x04]
+#endif
+ bx lr
+ LMEMCPY_6_PAD
+
+/*
+ * 0011: dst is 32-bit aligned, src is 8-bit aligned
+ */
+ ldr r2, [r1, #-3] /* BE:r2 = xxx0 LE:r2 = 0xxx */
+ ldr r3, [r1, #1] /* BE:r3 = 1234 LE:r3 = 4321 */
+ ldr r1, [r1, #5] /* BE:r1 = 5xxx LE:r3 = xxx5 */
+#ifdef __ARMEB__
+ mov r2, r2, lsl #24 /* r2 = 0... */
+ orr r2, r2, r3, lsr #8 /* r2 = 0123 */
+ mov r3, r3, lsl #8 /* r3 = 234. */
+ orr r1, r3, r1, lsr #24 /* r1 = 2345 */
+#else
+ mov r2, r2, lsr #24 /* r2 = ...0 */
+ orr r2, r2, r3, lsl #8 /* r2 = 3210 */
+ mov r1, r1, lsl #8 /* r1 = xx5. */
+ orr r1, r1, r3, lsr #24 /* r1 = xx54 */
+#endif
+ str r2, [r0]
+ strh r1, [r0, #0x04]
+ bx lr
+ LMEMCPY_6_PAD
+
+/*
+ * 0100: dst is 8-bit aligned, src is 32-bit aligned
+ */
+ ldr r3, [r1] /* BE:r3 = 0123 LE:r3 = 3210 */
+ ldrh r2, [r1, #0x04] /* BE:r2 = ..45 LE:r2 = ..54 */
+ mov r1, r3, lsr #8 /* BE:r1 = .012 LE:r1 = .321 */
+ strh r1, [r0, #0x01]
+#ifdef __ARMEB__
+ mov r1, r3, lsr #24 /* r1 = ...0 */
+ strb r1, [r0]
+ mov r3, r3, lsl #8 /* r3 = 123. */
+ orr r3, r3, r2, lsr #8 /* r3 = 1234 */
+#else
+ strb r3, [r0]
+ mov r3, r3, lsr #24 /* r3 = ...3 */
+ orr r3, r3, r2, lsl #8 /* r3 = .543 */
+ mov r2, r2, lsr #8 /* r2 = ...5 */
+#endif
+ strh r3, [r0, #0x03]
+ strb r2, [r0, #0x05]
+ bx lr
+ LMEMCPY_6_PAD
+
+/*
+ * 0101: dst is 8-bit aligned, src is 8-bit aligned
+ */
+ ldrb r2, [r1]
+ ldrh r3, [r1, #0x01]
+ ldrh ip, [r1, #0x03]
+ ldrb r1, [r1, #0x05]
+ strb r2, [r0]
+ strh r3, [r0, #0x01]
+ strh ip, [r0, #0x03]
+ strb r1, [r0, #0x05]
+ bx lr
+ LMEMCPY_6_PAD
+
+/*
+ * 0110: dst is 8-bit aligned, src is 16-bit aligned
+ */
+ ldrh r2, [r1] /* BE:r2 = ..01 LE:r2 = ..10 */
+ ldr r1, [r1, #0x02] /* BE:r1 = 2345 LE:r1 = 5432 */
+#ifdef __ARMEB__
+ mov r3, r2, lsr #8 /* r3 = ...0 */
+ strb r3, [r0]
+ strb r1, [r0, #0x05]
+ mov r3, r1, lsr #8 /* r3 = .234 */
+ strh r3, [r0, #0x03]
+ mov r3, r2, lsl #8 /* r3 = .01. */
+ orr r3, r3, r1, lsr #24 /* r3 = .012 */
+ strh r3, [r0, #0x01]
+#else
+ strb r2, [r0]
+ mov r3, r1, lsr #24
+ strb r3, [r0, #0x05]
+ mov r3, r1, lsr #8 /* r3 = .543 */
+ strh r3, [r0, #0x03]
+ mov r3, r2, lsr #8 /* r3 = ...1 */
+ orr r3, r3, r1, lsl #8 /* r3 = 4321 */
+ strh r3, [r0, #0x01]
+#endif
+ bx lr
+ LMEMCPY_6_PAD
+
+/*
+ * 0111: dst is 8-bit aligned, src is 8-bit aligned
+ */
+ ldrb r2, [r1]
+ ldrh r3, [r1, #0x01]
+ ldrh ip, [r1, #0x03]
+ ldrb r1, [r1, #0x05]
+ strb r2, [r0]
+ strh r3, [r0, #0x01]
+ strh ip, [r0, #0x03]
+ strb r1, [r0, #0x05]
+ bx lr
+ LMEMCPY_6_PAD
+
+/*
+ * 1000: dst is 16-bit aligned, src is 32-bit aligned
+ */
+#ifdef __ARMEB__
+ ldr r2, [r1] /* r2 = 0123 */
+ ldrh r3, [r1, #0x04] /* r3 = ..45 */
+ mov r1, r2, lsr #16 /* r1 = ..01 */
+ orr r3, r3, r2, lsl#16 /* r3 = 2345 */
+ strh r1, [r0]
+ str r3, [r0, #0x02]
+#else
+ ldrh r2, [r1, #0x04] /* r2 = ..54 */
+ ldr r3, [r1] /* r3 = 3210 */
+ mov r2, r2, lsl #16 /* r2 = 54.. */
+ orr r2, r2, r3, lsr #16 /* r2 = 5432 */
+ strh r3, [r0]
+ str r2, [r0, #0x02]
+#endif
+ bx lr
+ LMEMCPY_6_PAD
+
+/*
+ * 1001: dst is 16-bit aligned, src is 8-bit aligned
+ */
+ ldr r3, [r1, #-1] /* BE:r3 = x012 LE:r3 = 210x */
+ ldr r2, [r1, #3] /* BE:r2 = 345x LE:r2 = x543 */
+ mov r1, r3, lsr #8 /* BE:r1 = .x01 LE:r1 = .210 */
+#ifdef __ARMEB__
+ mov r2, r2, lsr #8 /* r2 = .345 */
+ orr r2, r2, r3, lsl #24 /* r2 = 2345 */
+#else
+ mov r2, r2, lsl #8 /* r2 = 543. */
+ orr r2, r2, r3, lsr #24 /* r2 = 5432 */
+#endif
+ strh r1, [r0]
+ str r2, [r0, #0x02]
+ bx lr
+ LMEMCPY_6_PAD
+
+/*
+ * 1010: dst is 16-bit aligned, src is 16-bit aligned
+ */
+ ldrh r2, [r1]
+ ldr r3, [r1, #0x02]
+ strh r2, [r0]
+ str r3, [r0, #0x02]
+ bx lr
+ LMEMCPY_6_PAD
+
+/*
+ * 1011: dst is 16-bit aligned, src is 8-bit aligned
+ */
+ ldrb r3, [r1] /* r3 = ...0 */
+ ldr r2, [r1, #0x01] /* BE:r2 = 1234 LE:r2 = 4321 */
+ ldrb r1, [r1, #0x05] /* r1 = ...5 */
+#ifdef __ARMEB__
+ mov r3, r3, lsl #8 /* r3 = ..0. */
+ orr r3, r3, r2, lsr #24 /* r3 = ..01 */
+ orr r1, r1, r2, lsl #8 /* r1 = 2345 */
+#else
+ orr r3, r3, r2, lsl #8 /* r3 = 3210 */
+ mov r1, r1, lsl #24 /* r1 = 5... */
+ orr r1, r1, r2, lsr #8 /* r1 = 5432 */
+#endif
+ strh r3, [r0]
+ str r1, [r0, #0x02]
+ bx lr
+ LMEMCPY_6_PAD
+
+/*
+ * 1100: dst is 8-bit aligned, src is 32-bit aligned
+ */
+ ldr r2, [r1] /* BE:r2 = 0123 LE:r2 = 3210 */
+ ldrh r1, [r1, #0x04] /* BE:r1 = ..45 LE:r1 = ..54 */
+#ifdef __ARMEB__
+ mov r3, r2, lsr #24 /* r3 = ...0 */
+ strb r3, [r0]
+ mov r2, r2, lsl #8 /* r2 = 123. */
+ orr r2, r2, r1, lsr #8 /* r2 = 1234 */
+#else
+ strb r2, [r0]
+ mov r2, r2, lsr #8 /* r2 = .321 */
+ orr r2, r2, r1, lsl #24 /* r2 = 4321 */
+ mov r1, r1, lsr #8 /* r1 = ...5 */
+#endif
+ str r2, [r0, #0x01]
+ strb r1, [r0, #0x05]
+ bx lr
+ LMEMCPY_6_PAD
+
+/*
+ * 1101: dst is 8-bit aligned, src is 8-bit aligned
+ */
+ ldrb r2, [r1]
+ ldrh r3, [r1, #0x01]
+ ldrh ip, [r1, #0x03]
+ ldrb r1, [r1, #0x05]
+ strb r2, [r0]
+ strh r3, [r0, #0x01]
+ strh ip, [r0, #0x03]
+ strb r1, [r0, #0x05]
+ bx lr
+ LMEMCPY_6_PAD
+
+/*
+ * 1110: dst is 8-bit aligned, src is 16-bit aligned
+ */
+ ldrh r2, [r1] /* BE:r2 = ..01 LE:r2 = ..10 */
+ ldr r1, [r1, #0x02] /* BE:r1 = 2345 LE:r1 = 5432 */
+#ifdef __ARMEB__
+ mov r3, r2, lsr #8 /* r3 = ...0 */
+ strb r3, [r0]
+ mov r2, r2, lsl #24 /* r2 = 1... */
+ orr r2, r2, r1, lsr #8 /* r2 = 1234 */
+#else
+ strb r2, [r0]
+ mov r2, r2, lsr #8 /* r2 = ...1 */
+ orr r2, r2, r1, lsl #8 /* r2 = 4321 */
+ mov r1, r1, lsr #24 /* r1 = ...5 */
+#endif
+ str r2, [r0, #0x01]
+ strb r1, [r0, #0x05]
+ bx lr
+ LMEMCPY_6_PAD
+
+/*
+ * 1111: dst is 8-bit aligned, src is 8-bit aligned
+ */
+ ldrb r2, [r1]
+ ldr r3, [r1, #0x01]
+ ldrb r1, [r1, #0x05]
+ strb r2, [r0]
+ str r3, [r0, #0x01]
+ strb r1, [r0, #0x05]
+ bx lr
+ LMEMCPY_6_PAD
+
+
+/******************************************************************************
+ * Special case for 8 byte copies
+ */
+#define LMEMCPY_8_LOG2 6 /* 64 bytes */
+#define LMEMCPY_8_PAD .align LMEMCPY_8_LOG2
+ LMEMCPY_8_PAD
+.Lmemcpy_8:
+ and r2, r1, #0x03
+ orr r2, r2, r0, lsl #2
+ ands r2, r2, #0x0f
+ sub r3, pc, #0x14
+ addne pc, r3, r2, lsl #LMEMCPY_8_LOG2
+
+/*
+ * 0000: dst is 32-bit aligned, src is 32-bit aligned
+ */
+ ldr r2, [r1]
+ ldr r3, [r1, #0x04]
+ str r2, [r0]
+ str r3, [r0, #0x04]
+ bx lr
+ LMEMCPY_8_PAD
+
+/*
+ * 0001: dst is 32-bit aligned, src is 8-bit aligned
+ */
+ ldr r3, [r1, #-1] /* BE:r3 = x012 LE:r3 = 210x */
+ ldr r2, [r1, #0x03] /* BE:r2 = 3456 LE:r2 = 6543 */
+ ldrb r1, [r1, #0x07] /* r1 = ...7 */
+#ifdef __ARMEB__
+ mov r3, r3, lsl #8 /* r3 = 012. */
+ orr r3, r3, r2, lsr #24 /* r3 = 0123 */
+ orr r2, r1, r2, lsl #8 /* r2 = 4567 */
+#else
+ mov r3, r3, lsr #8 /* r3 = .210 */
+ orr r3, r3, r2, lsl #24 /* r3 = 3210 */
+ mov r1, r1, lsl #24 /* r1 = 7... */
+ orr r2, r1, r2, lsr #8 /* r2 = 7654 */
+#endif
+ str r3, [r0]
+ str r2, [r0, #0x04]
+ bx lr
+ LMEMCPY_8_PAD
+
+/*
+ * 0010: dst is 32-bit aligned, src is 16-bit aligned
+ */
+ ldrh r2, [r1] /* BE:r2 = ..01 LE:r2 = ..10 */
+ ldr r3, [r1, #0x02] /* BE:r3 = 2345 LE:r3 = 5432 */
+ ldrh r1, [r1, #0x06] /* BE:r1 = ..67 LE:r1 = ..76 */
+#ifdef __ARMEB__
+ mov r2, r2, lsl #16 /* r2 = 01.. */
+ orr r2, r2, r3, lsr #16 /* r2 = 0123 */
+ orr r3, r1, r3, lsl #16 /* r3 = 4567 */
+#else
+ orr r2, r2, r3, lsl #16 /* r2 = 3210 */
+ mov r3, r3, lsr #16 /* r3 = ..54 */
+ orr r3, r3, r1, lsl #16 /* r3 = 7654 */
+#endif
+ str r2, [r0]
+ str r3, [r0, #0x04]
+ bx lr
+ LMEMCPY_8_PAD
+
+/*
+ * 0011: dst is 32-bit aligned, src is 8-bit aligned
+ */
+ ldrb r3, [r1] /* r3 = ...0 */
+ ldr r2, [r1, #0x01] /* BE:r2 = 1234 LE:r2 = 4321 */
+ ldr r1, [r1, #0x05] /* BE:r1 = 567x LE:r1 = x765 */
+#ifdef __ARMEB__
+ mov r3, r3, lsl #24 /* r3 = 0... */
+ orr r3, r3, r2, lsr #8 /* r3 = 0123 */
+ mov r2, r2, lsl #24 /* r2 = 4... */
+ orr r2, r2, r1, lsr #8 /* r2 = 4567 */
+#else
+ orr r3, r3, r2, lsl #8 /* r3 = 3210 */
+ mov r2, r2, lsr #24 /* r2 = ...4 */
+ orr r2, r2, r1, lsl #8 /* r2 = 7654 */
+#endif
+ str r3, [r0]
+ str r2, [r0, #0x04]
+ bx lr
+ LMEMCPY_8_PAD
+
+/*
+ * 0100: dst is 8-bit aligned, src is 32-bit aligned
+ */
+ ldr r3, [r1] /* BE:r3 = 0123 LE:r3 = 3210 */
+ ldr r2, [r1, #0x04] /* BE:r2 = 4567 LE:r2 = 7654 */
+#ifdef __ARMEB__
+ mov r1, r3, lsr #24 /* r1 = ...0 */
+ strb r1, [r0]
+ mov r1, r3, lsr #8 /* r1 = .012 */
+ strb r2, [r0, #0x07]
+ mov r3, r3, lsl #24 /* r3 = 3... */
+ orr r3, r3, r2, lsr #8 /* r3 = 3456 */
+#else
+ strb r3, [r0]
+ mov r1, r2, lsr #24 /* r1 = ...7 */
+ strb r1, [r0, #0x07]
+ mov r1, r3, lsr #8 /* r1 = .321 */
+ mov r3, r3, lsr #24 /* r3 = ...3 */
+ orr r3, r3, r2, lsl #8 /* r3 = 6543 */
+#endif
+ strh r1, [r0, #0x01]
+ str r3, [r0, #0x03]
+ bx lr
+ LMEMCPY_8_PAD
+
+/*
+ * 0101: dst is 8-bit aligned, src is 8-bit aligned
+ */
+ ldrb r2, [r1]
+ ldrh r3, [r1, #0x01]
+ ldr ip, [r1, #0x03]
+ ldrb r1, [r1, #0x07]
+ strb r2, [r0]
+ strh r3, [r0, #0x01]
+ str ip, [r0, #0x03]
+ strb r1, [r0, #0x07]
+ bx lr
+ LMEMCPY_8_PAD
+
+/*
+ * 0110: dst is 8-bit aligned, src is 16-bit aligned
+ */
+ ldrh r2, [r1] /* BE:r2 = ..01 LE:r2 = ..10 */
+ ldr r3, [r1, #0x02] /* BE:r3 = 2345 LE:r3 = 5432 */
+ ldrh r1, [r1, #0x06] /* BE:r1 = ..67 LE:r1 = ..76 */
+#ifdef __ARMEB__
+ mov ip, r2, lsr #8 /* ip = ...0 */
+ strb ip, [r0]
+ mov ip, r2, lsl #8 /* ip = .01. */
+ orr ip, ip, r3, lsr #24 /* ip = .012 */
+ strb r1, [r0, #0x07]
+ mov r3, r3, lsl #8 /* r3 = 345. */
+ orr r3, r3, r1, lsr #8 /* r3 = 3456 */
+#else
+ strb r2, [r0] /* 0 */
+ mov ip, r1, lsr #8 /* ip = ...7 */
+ strb ip, [r0, #0x07] /* 7 */
+ mov ip, r2, lsr #8 /* ip = ...1 */
+ orr ip, ip, r3, lsl #8 /* ip = 4321 */
+ mov r3, r3, lsr #8 /* r3 = .543 */
+ orr r3, r3, r1, lsl #24 /* r3 = 6543 */
+#endif
+ strh ip, [r0, #0x01]
+ str r3, [r0, #0x03]
+ bx lr
+ LMEMCPY_8_PAD
+
+/*
+ * 0111: dst is 8-bit aligned, src is 8-bit aligned
+ */
+ ldrb r3, [r1] /* r3 = ...0 */
+ ldr ip, [r1, #0x01] /* BE:ip = 1234 LE:ip = 4321 */
+ ldrh r2, [r1, #0x05] /* BE:r2 = ..56 LE:r2 = ..65 */
+ ldrb r1, [r1, #0x07] /* r1 = ...7 */
+ strb r3, [r0]
+ mov r3, ip, lsr #16 /* BE:r3 = ..12 LE:r3 = ..43 */
+#ifdef __ARMEB__
+ strh r3, [r0, #0x01]
+ orr r2, r2, ip, lsl #16 /* r2 = 3456 */
+#else
+ strh ip, [r0, #0x01]
+ orr r2, r3, r2, lsl #16 /* r2 = 6543 */
+#endif
+ str r2, [r0, #0x03]
+ strb r1, [r0, #0x07]
+ bx lr
+ LMEMCPY_8_PAD
+
+/*
+ * 1000: dst is 16-bit aligned, src is 32-bit aligned
+ */
+ ldr r2, [r1] /* BE:r2 = 0123 LE:r2 = 3210 */
+ ldr r3, [r1, #0x04] /* BE:r3 = 4567 LE:r3 = 7654 */
+ mov r1, r2, lsr #16 /* BE:r1 = ..01 LE:r1 = ..32 */
+#ifdef __ARMEB__
+ strh r1, [r0]
+ mov r1, r3, lsr #16 /* r1 = ..45 */
+ orr r2, r1 ,r2, lsl #16 /* r2 = 2345 */
+#else
+ strh r2, [r0]
+ orr r2, r1, r3, lsl #16 /* r2 = 5432 */
+ mov r3, r3, lsr #16 /* r3 = ..76 */
+#endif
+ str r2, [r0, #0x02]
+ strh r3, [r0, #0x06]
+ bx lr
+ LMEMCPY_8_PAD
+
+/*
+ * 1001: dst is 16-bit aligned, src is 8-bit aligned
+ */
+ ldr r2, [r1, #-1] /* BE:r2 = x012 LE:r2 = 210x */
+ ldr r3, [r1, #0x03] /* BE:r3 = 3456 LE:r3 = 6543 */
+ ldrb ip, [r1, #0x07] /* ip = ...7 */
+ mov r1, r2, lsr #8 /* BE:r1 = .x01 LE:r1 = .210 */
+ strh r1, [r0]
+#ifdef __ARMEB__
+ mov r1, r2, lsl #24 /* r1 = 2... */
+ orr r1, r1, r3, lsr #8 /* r1 = 2345 */
+ orr r3, ip, r3, lsl #8 /* r3 = 4567 */
+#else
+ mov r1, r2, lsr #24 /* r1 = ...2 */
+ orr r1, r1, r3, lsl #8 /* r1 = 5432 */
+ mov r3, r3, lsr #24 /* r3 = ...6 */
+ orr r3, r3, ip, lsl #8 /* r3 = ..76 */
+#endif
+ str r1, [r0, #0x02]
+ strh r3, [r0, #0x06]
+ bx lr
+ LMEMCPY_8_PAD
+
+/*
+ * 1010: dst is 16-bit aligned, src is 16-bit aligned
+ */
+ ldrh r2, [r1]
+ ldr ip, [r1, #0x02]
+ ldrh r3, [r1, #0x06]
+ strh r2, [r0]
+ str ip, [r0, #0x02]
+ strh r3, [r0, #0x06]
+ bx lr
+ LMEMCPY_8_PAD
+
+/*
+ * 1011: dst is 16-bit aligned, src is 8-bit aligned
+ */
+ ldr r3, [r1, #0x05] /* BE:r3 = 567x LE:r3 = x765 */
+ ldr r2, [r1, #0x01] /* BE:r2 = 1234 LE:r2 = 4321 */
+ ldrb ip, [r1] /* ip = ...0 */
+ mov r1, r3, lsr #8 /* BE:r1 = .567 LE:r1 = .x76 */
+ strh r1, [r0, #0x06]
+#ifdef __ARMEB__
+ mov r3, r3, lsr #24 /* r3 = ...5 */
+ orr r3, r3, r2, lsl #8 /* r3 = 2345 */
+ mov r2, r2, lsr #24 /* r2 = ...1 */
+ orr r2, r2, ip, lsl #8 /* r2 = ..01 */
+#else
+ mov r3, r3, lsl #24 /* r3 = 5... */
+ orr r3, r3, r2, lsr #8 /* r3 = 5432 */
+ orr r2, ip, r2, lsl #8 /* r2 = 3210 */
+#endif
+ str r3, [r0, #0x02]
+ strh r2, [r0]
+ bx lr
+ LMEMCPY_8_PAD
+
+/*
+ * 1100: dst is 8-bit aligned, src is 32-bit aligned
+ */
+ ldr r3, [r1, #0x04] /* BE:r3 = 4567 LE:r3 = 7654 */
+ ldr r2, [r1] /* BE:r2 = 0123 LE:r2 = 3210 */
+ mov r1, r3, lsr #8 /* BE:r1 = .456 LE:r1 = .765 */
+ strh r1, [r0, #0x05]
+#ifdef __ARMEB__
+ strb r3, [r0, #0x07]
+ mov r1, r2, lsr #24 /* r1 = ...0 */
+ strb r1, [r0]
+ mov r2, r2, lsl #8 /* r2 = 123. */
+ orr r2, r2, r3, lsr #24 /* r2 = 1234 */
+ str r2, [r0, #0x01]
+#else
+ strb r2, [r0]
+ mov r1, r3, lsr #24 /* r1 = ...7 */
+ strb r1, [r0, #0x07]
+ mov r2, r2, lsr #8 /* r2 = .321 */
+ orr r2, r2, r3, lsl #24 /* r2 = 4321 */
+ str r2, [r0, #0x01]
+#endif
+ bx lr
+ LMEMCPY_8_PAD
+
+/*
+ * 1101: dst is 8-bit aligned, src is 8-bit aligned
+ */
+ ldrb r3, [r1] /* r3 = ...0 */
+ ldrh r2, [r1, #0x01] /* BE:r2 = ..12 LE:r2 = ..21 */
+ ldr ip, [r1, #0x03] /* BE:ip = 3456 LE:ip = 6543 */
+ ldrb r1, [r1, #0x07] /* r1 = ...7 */
+ strb r3, [r0]
+ mov r3, ip, lsr #16 /* BE:r3 = ..34 LE:r3 = ..65 */
+#ifdef __ARMEB__
+ strh ip, [r0, #0x05]
+ orr r2, r3, r2, lsl #16 /* r2 = 1234 */
+#else
+ strh r3, [r0, #0x05]
+ orr r2, r2, ip, lsl #16 /* r2 = 4321 */
+#endif
+ str r2, [r0, #0x01]
+ strb r1, [r0, #0x07]
+ bx lr
+ LMEMCPY_8_PAD
+
+/*
+ * 1110: dst is 8-bit aligned, src is 16-bit aligned
+ */
+ ldrh r2, [r1] /* BE:r2 = ..01 LE:r2 = ..10 */
+ ldr r3, [r1, #0x02] /* BE:r3 = 2345 LE:r3 = 5432 */
+ ldrh r1, [r1, #0x06] /* BE:r1 = ..67 LE:r1 = ..76 */
+#ifdef __ARMEB__
+ mov ip, r2, lsr #8 /* ip = ...0 */
+ strb ip, [r0]
+ mov ip, r2, lsl #24 /* ip = 1... */
+ orr ip, ip, r3, lsr #8 /* ip = 1234 */
+ strb r1, [r0, #0x07]
+ mov r1, r1, lsr #8 /* r1 = ...6 */
+ orr r1, r1, r3, lsl #8 /* r1 = 3456 */
+#else
+ strb r2, [r0]
+ mov ip, r2, lsr #8 /* ip = ...1 */
+ orr ip, ip, r3, lsl #8 /* ip = 4321 */
+ mov r2, r1, lsr #8 /* r2 = ...7 */
+ strb r2, [r0, #0x07]
+ mov r1, r1, lsl #8 /* r1 = .76. */
+ orr r1, r1, r3, lsr #24 /* r1 = .765 */
+#endif
+ str ip, [r0, #0x01]
+ strh r1, [r0, #0x05]
+ bx lr
+ LMEMCPY_8_PAD
+
+/*
+ * 1111: dst is 8-bit aligned, src is 8-bit aligned
+ */
+ ldrb r2, [r1]
+ ldr ip, [r1, #0x01]
+ ldrh r3, [r1, #0x05]
+ ldrb r1, [r1, #0x07]
+ strb r2, [r0]
+ str ip, [r0, #0x01]
+ strh r3, [r0, #0x05]
+ strb r1, [r0, #0x07]
+ bx lr
+ LMEMCPY_8_PAD
+
+/******************************************************************************
+ * Special case for 12 byte copies
+ */
+#define LMEMCPY_C_LOG2 7 /* 128 bytes */
+#define LMEMCPY_C_PAD .align LMEMCPY_C_LOG2
+ LMEMCPY_C_PAD
+.Lmemcpy_c:
+ and r2, r1, #0x03
+ orr r2, r2, r0, lsl #2
+ ands r2, r2, #0x0f
+ sub r3, pc, #0x14
+ addne pc, r3, r2, lsl #LMEMCPY_C_LOG2
+
+/*
+ * 0000: dst is 32-bit aligned, src is 32-bit aligned
+ */
+ ldr r2, [r1]
+ ldr r3, [r1, #0x04]
+ ldr r1, [r1, #0x08]
+ str r2, [r0]
+ str r3, [r0, #0x04]
+ str r1, [r0, #0x08]
+ bx lr
+ LMEMCPY_C_PAD
+
+/*
+ * 0001: dst is 32-bit aligned, src is 8-bit aligned
+ */
+ ldrb r2, [r1, #0xb] /* r2 = ...B */
+ ldr ip, [r1, #0x07] /* BE:ip = 789A LE:ip = A987 */
+ ldr r3, [r1, #0x03] /* BE:r3 = 3456 LE:r3 = 6543 */
+ ldr r1, [r1, #-1] /* BE:r1 = x012 LE:r1 = 210x */
+#ifdef __ARMEB__
+ orr r2, r2, ip, lsl #8 /* r2 = 89AB */
+ str r2, [r0, #0x08]
+ mov r2, ip, lsr #24 /* r2 = ...7 */
+ orr r2, r2, r3, lsl #8 /* r2 = 4567 */
+ mov r1, r1, lsl #8 /* r1 = 012. */
+ orr r1, r1, r3, lsr #24 /* r1 = 0123 */
+#else
+ mov r2, r2, lsl #24 /* r2 = B... */
+ orr r2, r2, ip, lsr #8 /* r2 = BA98 */
+ str r2, [r0, #0x08]
+ mov r2, ip, lsl #24 /* r2 = 7... */
+ orr r2, r2, r3, lsr #8 /* r2 = 7654 */
+ mov r1, r1, lsr #8 /* r1 = .210 */
+ orr r1, r1, r3, lsl #24 /* r1 = 3210 */
+#endif
+ str r2, [r0, #0x04]
+ str r1, [r0]
+ bx lr
+ LMEMCPY_C_PAD
+
+/*
+ * 0010: dst is 32-bit aligned, src is 16-bit aligned
+ */
+ ldrh r2, [r1] /* BE:r2 = ..01 LE:r2 = ..10 */
+ ldr r3, [r1, #0x02] /* BE:r3 = 2345 LE:r3 = 5432 */
+ ldr ip, [r1, #0x06] /* BE:ip = 6789 LE:ip = 9876 */
+ ldrh r1, [r1, #0x0a] /* BE:r1 = ..AB LE:r1 = ..BA */
+#ifdef __ARMEB__
+ mov r2, r2, lsl #16 /* r2 = 01.. */
+ orr r2, r2, r3, lsr #16 /* r2 = 0123 */
+ str r2, [r0]
+ mov r3, r3, lsl #16 /* r3 = 45.. */
+ orr r3, r3, ip, lsr #16 /* r3 = 4567 */
+ orr r1, r1, ip, lsl #16 /* r1 = 89AB */
+#else
+ orr r2, r2, r3, lsl #16 /* r2 = 3210 */
+ str r2, [r0]
+ mov r3, r3, lsr #16 /* r3 = ..54 */
+ orr r3, r3, ip, lsl #16 /* r3 = 7654 */
+ mov r1, r1, lsl #16 /* r1 = BA.. */
+ orr r1, r1, ip, lsr #16 /* r1 = BA98 */
+#endif
+ str r3, [r0, #0x04]
+ str r1, [r0, #0x08]
+ bx lr
+ LMEMCPY_C_PAD
+
+/*
+ * 0011: dst is 32-bit aligned, src is 8-bit aligned
+ */
+ ldrb r2, [r1] /* r2 = ...0 */
+ ldr r3, [r1, #0x01] /* BE:r3 = 1234 LE:r3 = 4321 */
+ ldr ip, [r1, #0x05] /* BE:ip = 5678 LE:ip = 8765 */
+ ldr r1, [r1, #0x09] /* BE:r1 = 9ABx LE:r1 = xBA9 */
+#ifdef __ARMEB__
+ mov r2, r2, lsl #24 /* r2 = 0... */
+ orr r2, r2, r3, lsr #8 /* r2 = 0123 */
+ str r2, [r0]
+ mov r3, r3, lsl #24 /* r3 = 4... */
+ orr r3, r3, ip, lsr #8 /* r3 = 4567 */
+ mov r1, r1, lsr #8 /* r1 = .9AB */
+ orr r1, r1, ip, lsl #24 /* r1 = 89AB */
+#else
+ orr r2, r2, r3, lsl #8 /* r2 = 3210 */
+ str r2, [r0]
+ mov r3, r3, lsr #24 /* r3 = ...4 */
+ orr r3, r3, ip, lsl #8 /* r3 = 7654 */
+ mov r1, r1, lsl #8 /* r1 = BA9. */
+ orr r1, r1, ip, lsr #24 /* r1 = BA98 */
+#endif
+ str r3, [r0, #0x04]
+ str r1, [r0, #0x08]
+ bx lr
+ LMEMCPY_C_PAD
+
+/*
+ * 0100: dst is 8-bit aligned (byte 1), src is 32-bit aligned
+ */
+ ldr r2, [r1] /* BE:r2 = 0123 LE:r2 = 3210 */
+ ldr r3, [r1, #0x04] /* BE:r3 = 4567 LE:r3 = 7654 */
+ ldr ip, [r1, #0x08] /* BE:ip = 89AB LE:ip = BA98 */
+ mov r1, r2, lsr #8 /* BE:r1 = .012 LE:r1 = .321 */
+ strh r1, [r0, #0x01]
+#ifdef __ARMEB__
+ mov r1, r2, lsr #24 /* r1 = ...0 */
+ strb r1, [r0]
+ mov r1, r2, lsl #24 /* r1 = 3... */
+ orr r2, r1, r3, lsr #8 /* r1 = 3456 */
+ mov r1, r3, lsl #24 /* r1 = 7... */
+ orr r1, r1, ip, lsr #8 /* r1 = 789A */
+#else
+ strb r2, [r0]
+ mov r1, r2, lsr #24 /* r1 = ...3 */
+ orr r2, r1, r3, lsl #8 /* r1 = 6543 */
+ mov r1, r3, lsr #24 /* r1 = ...7 */
+ orr r1, r1, ip, lsl #8 /* r1 = A987 */
+ mov ip, ip, lsr #24 /* ip = ...B */
+#endif
+ str r2, [r0, #0x03]
+ str r1, [r0, #0x07]
+ strb ip, [r0, #0x0b]
+ bx lr
+ LMEMCPY_C_PAD
+
+/*
+ * 0101: dst is 8-bit aligned (byte 1), src is 8-bit aligned (byte 1)
+ */
+ ldrb r2, [r1]
+ ldrh r3, [r1, #0x01]
+ ldr ip, [r1, #0x03]
+ strb r2, [r0]
+ ldr r2, [r1, #0x07]
+ ldrb r1, [r1, #0x0b]
+ strh r3, [r0, #0x01]
+ str ip, [r0, #0x03]
+ str r2, [r0, #0x07]
+ strb r1, [r0, #0x0b]
+ bx lr
+ LMEMCPY_C_PAD
+
+/*
+ * 0110: dst is 8-bit aligned (byte 1), src is 16-bit aligned
+ */
+ ldrh r2, [r1] /* BE:r2 = ..01 LE:r2 = ..10 */
+ ldr r3, [r1, #0x02] /* BE:r3 = 2345 LE:r3 = 5432 */
+ ldr ip, [r1, #0x06] /* BE:ip = 6789 LE:ip = 9876 */
+ ldrh r1, [r1, #0x0a] /* BE:r1 = ..AB LE:r1 = ..BA */
+#ifdef __ARMEB__
+ mov r2, r2, ror #8 /* r2 = 1..0 */
+ strb r2, [r0]
+ mov r2, r2, lsr #16 /* r2 = ..1. */
+ orr r2, r2, r3, lsr #24 /* r2 = ..12 */
+ strh r2, [r0, #0x01]
+ mov r2, r3, lsl #8 /* r2 = 345. */
+ orr r3, r2, ip, lsr #24 /* r3 = 3456 */
+ mov r2, ip, lsl #8 /* r2 = 789. */
+ orr r2, r2, r1, lsr #8 /* r2 = 789A */
+#else
+ strb r2, [r0]
+ mov r2, r2, lsr #8 /* r2 = ...1 */
+ orr r2, r2, r3, lsl #8 /* r2 = 4321 */
+ strh r2, [r0, #0x01]
+ mov r2, r3, lsr #8 /* r2 = .543 */
+ orr r3, r2, ip, lsl #24 /* r3 = 6543 */
+ mov r2, ip, lsr #8 /* r2 = .987 */
+ orr r2, r2, r1, lsl #24 /* r2 = A987 */
+ mov r1, r1, lsr #8 /* r1 = ...B */
+#endif
+ str r3, [r0, #0x03]
+ str r2, [r0, #0x07]
+ strb r1, [r0, #0x0b]
+ bx lr
+ LMEMCPY_C_PAD
+
+/*
+ * 0111: dst is 8-bit aligned (byte 1), src is 8-bit aligned (byte 3)
+ */
+ ldrb r2, [r1]
+ ldr r3, [r1, #0x01] /* BE:r3 = 1234 LE:r3 = 4321 */
+ ldr ip, [r1, #0x05] /* BE:ip = 5678 LE:ip = 8765 */
+ ldr r1, [r1, #0x09] /* BE:r1 = 9ABx LE:r1 = xBA9 */
+ strb r2, [r0]
+#ifdef __ARMEB__
+ mov r2, r3, lsr #16 /* r2 = ..12 */
+ strh r2, [r0, #0x01]
+ mov r3, r3, lsl #16 /* r3 = 34.. */
+ orr r3, r3, ip, lsr #16 /* r3 = 3456 */
+ mov ip, ip, lsl #16 /* ip = 78.. */
+ orr ip, ip, r1, lsr #16 /* ip = 789A */
+ mov r1, r1, lsr #8 /* r1 = .9AB */
+#else
+ strh r3, [r0, #0x01]
+ mov r3, r3, lsr #16 /* r3 = ..43 */
+ orr r3, r3, ip, lsl #16 /* r3 = 6543 */
+ mov ip, ip, lsr #16 /* ip = ..87 */
+ orr ip, ip, r1, lsl #16 /* ip = A987 */
+ mov r1, r1, lsr #16 /* r1 = ..xB */
+#endif
+ str r3, [r0, #0x03]
+ str ip, [r0, #0x07]
+ strb r1, [r0, #0x0b]
+ bx lr
+ LMEMCPY_C_PAD
+
+/*
+ * 1000: dst is 16-bit aligned, src is 32-bit aligned
+ */
+ ldr ip, [r1] /* BE:ip = 0123 LE:ip = 3210 */
+ ldr r3, [r1, #0x04] /* BE:r3 = 4567 LE:r3 = 7654 */
+ ldr r2, [r1, #0x08] /* BE:r2 = 89AB LE:r2 = BA98 */
+ mov r1, ip, lsr #16 /* BE:r1 = ..01 LE:r1 = ..32 */
+#ifdef __ARMEB__
+ strh r1, [r0]
+ mov r1, ip, lsl #16 /* r1 = 23.. */
+ orr r1, r1, r3, lsr #16 /* r1 = 2345 */
+ mov r3, r3, lsl #16 /* r3 = 67.. */
+ orr r3, r3, r2, lsr #16 /* r3 = 6789 */
+#else
+ strh ip, [r0]
+ orr r1, r1, r3, lsl #16 /* r1 = 5432 */
+ mov r3, r3, lsr #16 /* r3 = ..76 */
+ orr r3, r3, r2, lsl #16 /* r3 = 9876 */
+ mov r2, r2, lsr #16 /* r2 = ..BA */
+#endif
+ str r1, [r0, #0x02]
+ str r3, [r0, #0x06]
+ strh r2, [r0, #0x0a]
+ bx lr
+ LMEMCPY_C_PAD
+
+/*
+ * 1001: dst is 16-bit aligned, src is 8-bit aligned (byte 1)
+ */
+ ldr r2, [r1, #-1] /* BE:r2 = x012 LE:r2 = 210x */
+ ldr r3, [r1, #0x03] /* BE:r3 = 3456 LE:r3 = 6543 */
+ mov ip, r2, lsr #8 /* BE:ip = .x01 LE:ip = .210 */
+ strh ip, [r0]
+ ldr ip, [r1, #0x07] /* BE:ip = 789A LE:ip = A987 */
+ ldrb r1, [r1, #0x0b] /* r1 = ...B */
+#ifdef __ARMEB__
+ mov r2, r2, lsl #24 /* r2 = 2... */
+ orr r2, r2, r3, lsr #8 /* r2 = 2345 */
+ mov r3, r3, lsl #24 /* r3 = 6... */
+ orr r3, r3, ip, lsr #8 /* r3 = 6789 */
+ orr r1, r1, ip, lsl #8 /* r1 = 89AB */
+#else
+ mov r2, r2, lsr #24 /* r2 = ...2 */
+ orr r2, r2, r3, lsl #8 /* r2 = 5432 */
+ mov r3, r3, lsr #24 /* r3 = ...6 */
+ orr r3, r3, ip, lsl #8 /* r3 = 9876 */
+ mov r1, r1, lsl #8 /* r1 = ..B. */
+ orr r1, r1, ip, lsr #24 /* r1 = ..BA */
+#endif
+ str r2, [r0, #0x02]
+ str r3, [r0, #0x06]
+ strh r1, [r0, #0x0a]
+ bx lr
+ LMEMCPY_C_PAD
+
+/*
+ * 1010: dst is 16-bit aligned, src is 16-bit aligned
+ */
+ ldrh r2, [r1]
+ ldr r3, [r1, #0x02]
+ ldr ip, [r1, #0x06]
+ ldrh r1, [r1, #0x0a]
+ strh r2, [r0]
+ str r3, [r0, #0x02]
+ str ip, [r0, #0x06]
+ strh r1, [r0, #0x0a]
+ bx lr
+ LMEMCPY_C_PAD
+
+/*
+ * 1011: dst is 16-bit aligned, src is 8-bit aligned (byte 3)
+ */
+ ldr r2, [r1, #0x09] /* BE:r2 = 9ABx LE:r2 = xBA9 */
+ ldr r3, [r1, #0x05] /* BE:r3 = 5678 LE:r3 = 8765 */
+ mov ip, r2, lsr #8 /* BE:ip = .9AB LE:ip = .xBA */
+ strh ip, [r0, #0x0a]
+ ldr ip, [r1, #0x01] /* BE:ip = 1234 LE:ip = 4321 */
+ ldrb r1, [r1] /* r1 = ...0 */
+#ifdef __ARMEB__
+ mov r2, r2, lsr #24 /* r2 = ...9 */
+ orr r2, r2, r3, lsl #8 /* r2 = 6789 */
+ mov r3, r3, lsr #24 /* r3 = ...5 */
+ orr r3, r3, ip, lsl #8 /* r3 = 2345 */
+ mov r1, r1, lsl #8 /* r1 = ..0. */
+ orr r1, r1, ip, lsr #24 /* r1 = ..01 */
+#else
+ mov r2, r2, lsl #24 /* r2 = 9... */
+ orr r2, r2, r3, lsr #8 /* r2 = 9876 */
+ mov r3, r3, lsl #24 /* r3 = 5... */
+ orr r3, r3, ip, lsr #8 /* r3 = 5432 */
+ orr r1, r1, ip, lsl #8 /* r1 = 3210 */
+#endif
+ str r2, [r0, #0x06]
+ str r3, [r0, #0x02]
+ strh r1, [r0]
+ bx lr
+ LMEMCPY_C_PAD
+
+/*
+ * 1100: dst is 8-bit aligned (byte 3), src is 32-bit aligned
+ */
+ ldr r2, [r1] /* BE:r2 = 0123 LE:r2 = 3210 */
+ ldr ip, [r1, #0x04] /* BE:ip = 4567 LE:ip = 7654 */
+ ldr r1, [r1, #0x08] /* BE:r1 = 89AB LE:r1 = BA98 */
+#ifdef __ARMEB__
+ mov r3, r2, lsr #24 /* r3 = ...0 */
+ strb r3, [r0]
+ mov r2, r2, lsl #8 /* r2 = 123. */
+ orr r2, r2, ip, lsr #24 /* r2 = 1234 */
+ str r2, [r0, #0x01]
+ mov r2, ip, lsl #8 /* r2 = 567. */
+ orr r2, r2, r1, lsr #24 /* r2 = 5678 */
+ str r2, [r0, #0x05]
+ mov r2, r1, lsr #8 /* r2 = ..9A */
+ strh r2, [r0, #0x09]
+ strb r1, [r0, #0x0b]
+#else
+ strb r2, [r0]
+ mov r3, r2, lsr #8 /* r3 = .321 */
+ orr r3, r3, ip, lsl #24 /* r3 = 4321 */
+ str r3, [r0, #0x01]
+ mov r3, ip, lsr #8 /* r3 = .765 */
+ orr r3, r3, r1, lsl #24 /* r3 = 8765 */
+ str r3, [r0, #0x05]
+ mov r1, r1, lsr #8 /* r1 = .BA9 */
+ strh r1, [r0, #0x09]
+ mov r1, r1, lsr #16 /* r1 = ...B */
+ strb r1, [r0, #0x0b]
+#endif
+ bx lr
+ LMEMCPY_C_PAD
+
+/*
+ * 1101: dst is 8-bit aligned (byte 3), src is 8-bit aligned (byte 1)
+ */
+ ldrb r2, [r1, #0x0b] /* r2 = ...B */
+ ldr r3, [r1, #0x07] /* BE:r3 = 789A LE:r3 = A987 */
+ ldr ip, [r1, #0x03] /* BE:ip = 3456 LE:ip = 6543 */
+ ldr r1, [r1, #-1] /* BE:r1 = x012 LE:r1 = 210x */
+ strb r2, [r0, #0x0b]
+#ifdef __ARMEB__
+ strh r3, [r0, #0x09]
+ mov r3, r3, lsr #16 /* r3 = ..78 */
+ orr r3, r3, ip, lsl #16 /* r3 = 5678 */
+ mov ip, ip, lsr #16 /* ip = ..34 */
+ orr ip, ip, r1, lsl #16 /* ip = 1234 */
+ mov r1, r1, lsr #16 /* r1 = ..x0 */
+#else
+ mov r2, r3, lsr #16 /* r2 = ..A9 */
+ strh r2, [r0, #0x09]
+ mov r3, r3, lsl #16 /* r3 = 87.. */
+ orr r3, r3, ip, lsr #16 /* r3 = 8765 */
+ mov ip, ip, lsl #16 /* ip = 43.. */
+ orr ip, ip, r1, lsr #16 /* ip = 4321 */
+ mov r1, r1, lsr #8 /* r1 = .210 */
+#endif
+ str r3, [r0, #0x05]
+ str ip, [r0, #0x01]
+ strb r1, [r0]
+ bx lr
+ LMEMCPY_C_PAD
+
+/*
+ * 1110: dst is 8-bit aligned (byte 3), src is 16-bit aligned
+ */
+#ifdef __ARMEB__
+ ldrh r2, [r1, #0x0a] /* r2 = ..AB */
+ ldr ip, [r1, #0x06] /* ip = 6789 */
+ ldr r3, [r1, #0x02] /* r3 = 2345 */
+ ldrh r1, [r1] /* r1 = ..01 */
+ strb r2, [r0, #0x0b]
+ mov r2, r2, lsr #8 /* r2 = ...A */
+ orr r2, r2, ip, lsl #8 /* r2 = 789A */
+ mov ip, ip, lsr #8 /* ip = .678 */
+ orr ip, ip, r3, lsl #24 /* ip = 5678 */
+ mov r3, r3, lsr #8 /* r3 = .234 */
+ orr r3, r3, r1, lsl #24 /* r3 = 1234 */
+ mov r1, r1, lsr #8 /* r1 = ...0 */
+ strb r1, [r0]
+ str r3, [r0, #0x01]
+ str ip, [r0, #0x05]
+ strh r2, [r0, #0x09]
+#else
+ ldrh r2, [r1] /* r2 = ..10 */
+ ldr r3, [r1, #0x02] /* r3 = 5432 */
+ ldr ip, [r1, #0x06] /* ip = 9876 */
+ ldrh r1, [r1, #0x0a] /* r1 = ..BA */
+ strb r2, [r0]
+ mov r2, r2, lsr #8 /* r2 = ...1 */
+ orr r2, r2, r3, lsl #8 /* r2 = 4321 */
+ mov r3, r3, lsr #24 /* r3 = ...5 */
+ orr r3, r3, ip, lsl #8 /* r3 = 8765 */
+ mov ip, ip, lsr #24 /* ip = ...9 */
+ orr ip, ip, r1, lsl #8 /* ip = .BA9 */
+ mov r1, r1, lsr #8 /* r1 = ...B */
+ str r2, [r0, #0x01]
+ str r3, [r0, #0x05]
+ strh ip, [r0, #0x09]
+ strb r1, [r0, #0x0b]
+#endif
+ bx lr
+ LMEMCPY_C_PAD
+
+/*
+ * 1111: dst is 8-bit aligned (byte 3), src is 8-bit aligned (byte 3)
+ */
+ ldrb r2, [r1]
+ ldr r3, [r1, #0x01]
+ ldr ip, [r1, #0x05]
+ strb r2, [r0]
+ ldrh r2, [r1, #0x09]
+ ldrb r1, [r1, #0x0b]
+ str r3, [r0, #0x01]
+ str ip, [r0, #0x05]
+ strh r2, [r0, #0x09]
+ strb r1, [r0, #0x0b]
+ bx lr
+#endif /* !_STANDALONE */
+END(memcpy)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/arm/string/memmove.S b/lib/libc/arm/string/memmove.S
new file mode 100644
index 000000000000..8f961470076c
--- /dev/null
+++ b/lib/libc/arm/string/memmove.S
@@ -0,0 +1,613 @@
+/* $NetBSD: memmove.S,v 1.4 2003/10/14 07:51:45 scw Exp $ */
+
+/*-
+ * Copyright (c) 1997 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Neil A. Carson and Mark Brinicombe
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+.syntax unified
+
+#ifndef _BCOPY
+/* LINTSTUB: Func: void *memmove(void *, const void *, size_t) */
+ENTRY(memmove)
+#else
+/* bcopy = memcpy/memmove with arguments reversed. */
+/* LINTSTUB: Func: void bcopy(void *, void *, size_t) */
+ENTRY(bcopy)
+ /* switch the source and destination registers */
+ eor r0, r1, r0
+ eor r1, r0, r1
+ eor r0, r1, r0
+#endif
+ /* Do the buffers overlap? */
+ cmp r0, r1
+ it eq
+ RETeq /* Bail now if src/dst are the same */
+ ite cc
+ subcc r3, r0, r1 /* if (dst > src) r3 = dst - src */
+ subcs r3, r1, r0 /* if (src > dsr) r3 = src - dst */
+ cmp r3, r2 /* if (r3 < len) we have an overlap */
+ bcc PIC_SYM(_C_LABEL(memcpy), PLT)
+
+ /* Determine copy direction */
+ cmp r1, r0
+ it cc
+ bcc .Lmemmove_backwards
+
+ itt eq
+ moveq r0, #0 /* Quick abort for len=0 */
+ RETeq
+
+ stmdb sp!, {r0, lr} /* memmove() returns dest addr */
+ subs r2, r2, #4
+ blt .Lmemmove_fl4 /* less than 4 bytes */
+ ands r12, r0, #3
+ bne .Lmemmove_fdestul /* oh unaligned destination addr */
+ ands r12, r1, #3
+ bne .Lmemmove_fsrcul /* oh unaligned source addr */
+
+.Lmemmove_ft8:
+ /* We have aligned source and destination */
+ subs r2, r2, #8
+ blt .Lmemmove_fl12 /* less than 12 bytes (4 from above) */
+ subs r2, r2, #0x14
+ blt .Lmemmove_fl32 /* less than 32 bytes (12 from above) */
+ stmdb sp!, {r4} /* borrow r4 */
+
+ /* blat 32 bytes at a time */
+ /* XXX for really big copies perhaps we should use more registers */
+.Lmemmove_floop32:
+ ldmia r1!, {r3, r4, r12, lr}
+ stmia r0!, {r3, r4, r12, lr}
+ ldmia r1!, {r3, r4, r12, lr}
+ stmia r0!, {r3, r4, r12, lr}
+ subs r2, r2, #0x20
+ bge .Lmemmove_floop32
+
+ cmn r2, #0x10
+ ittt ge
+ ldmiage r1!, {r3, r4, r12, lr} /* blat a remaining 16 bytes */
+ stmiage r0!, {r3, r4, r12, lr}
+ subge r2, r2, #0x10
+ ldmia sp!, {r4} /* return r4 */
+
+.Lmemmove_fl32:
+ adds r2, r2, #0x14
+
+ /* blat 12 bytes at a time */
+.Lmemmove_floop12:
+ ittt ge
+ ldmiage r1!, {r3, r12, lr}
+ stmiage r0!, {r3, r12, lr}
+ subsge r2, r2, #0x0c
+ bge .Lmemmove_floop12
+
+.Lmemmove_fl12:
+ adds r2, r2, #8
+ blt .Lmemmove_fl4
+
+ subs r2, r2, #4
+ itt lt
+ ldrlt r3, [r1], #4
+ strlt r3, [r0], #4
+ ittt ge
+ ldmiage r1!, {r3, r12}
+ stmiage r0!, {r3, r12}
+ subge r2, r2, #4
+
+.Lmemmove_fl4:
+ /* less than 4 bytes to go */
+ adds r2, r2, #4
+ it eq
+ ldmiaeq sp!, {r0, pc} /* done */
+
+ /* copy the crud byte at a time */
+ cmp r2, #2
+ ldrb r3, [r1], #1
+ strb r3, [r0], #1
+ itt ge
+ ldrbge r3, [r1], #1
+ strbge r3, [r0], #1
+ itt gt
+ ldrbgt r3, [r1], #1
+ strbgt r3, [r0], #1
+ ldmia sp!, {r0, pc}
+
+ /* erg - unaligned destination */
+.Lmemmove_fdestul:
+ rsb r12, r12, #4
+ cmp r12, #2
+
+ /* align destination with byte copies */
+ ldrb r3, [r1], #1
+ strb r3, [r0], #1
+ itt ge
+ ldrbge r3, [r1], #1
+ strbge r3, [r0], #1
+ itt gt
+ ldrbgt r3, [r1], #1
+ strbgt r3, [r0], #1
+ subs r2, r2, r12
+ blt .Lmemmove_fl4 /* less the 4 bytes */
+
+ ands r12, r1, #3
+ beq .Lmemmove_ft8 /* we have an aligned source */
+
+ /* erg - unaligned source */
+ /* This is where it gets nasty ... */
+.Lmemmove_fsrcul:
+ bic r1, r1, #3
+ ldr lr, [r1], #4
+ cmp r12, #2
+ bgt .Lmemmove_fsrcul3
+ beq .Lmemmove_fsrcul2
+ cmp r2, #0x0c
+ blt .Lmemmove_fsrcul1loop4
+ sub r2, r2, #0x0c
+ stmdb sp!, {r4, r5}
+
+.Lmemmove_fsrcul1loop16:
+#ifdef __ARMEB__
+ mov r3, lr, lsl #8
+#else
+ mov r3, lr, lsr #8
+#endif
+ ldmia r1!, {r4, r5, r12, lr}
+#ifdef __ARMEB__
+ orr r3, r3, r4, lsr #24
+ mov r4, r4, lsl #8
+ orr r4, r4, r5, lsr #24
+ mov r5, r5, lsl #8
+ orr r5, r5, r12, lsr #24
+ mov r12, r12, lsl #8
+ orr r12, r12, lr, lsr #24
+#else
+ orr r3, r3, r4, lsl #24
+ mov r4, r4, lsr #8
+ orr r4, r4, r5, lsl #24
+ mov r5, r5, lsr #8
+ orr r5, r5, r12, lsl #24
+ mov r12, r12, lsr #8
+ orr r12, r12, lr, lsl #24
+#endif
+ stmia r0!, {r3-r5, r12}
+ subs r2, r2, #0x10
+ bge .Lmemmove_fsrcul1loop16
+ ldmia sp!, {r4, r5}
+ adds r2, r2, #0x0c
+ blt .Lmemmove_fsrcul1l4
+
+.Lmemmove_fsrcul1loop4:
+#ifdef __ARMEB__
+ mov r12, lr, lsl #8
+#else
+ mov r12, lr, lsr #8
+#endif
+ ldr lr, [r1], #4
+#ifdef __ARMEB__
+ orr r12, r12, lr, lsr #24
+#else
+ orr r12, r12, lr, lsl #24
+#endif
+ str r12, [r0], #4
+ subs r2, r2, #4
+ bge .Lmemmove_fsrcul1loop4
+
+.Lmemmove_fsrcul1l4:
+ sub r1, r1, #3
+ b .Lmemmove_fl4
+
+.Lmemmove_fsrcul2:
+ cmp r2, #0x0c
+ blt .Lmemmove_fsrcul2loop4
+ sub r2, r2, #0x0c
+ stmdb sp!, {r4, r5}
+
+.Lmemmove_fsrcul2loop16:
+#ifdef __ARMEB__
+ mov r3, lr, lsl #16
+#else
+ mov r3, lr, lsr #16
+#endif
+ ldmia r1!, {r4, r5, r12, lr}
+#ifdef __ARMEB__
+ orr r3, r3, r4, lsr #16
+ mov r4, r4, lsl #16
+ orr r4, r4, r5, lsr #16
+ mov r5, r5, lsl #16
+ orr r5, r5, r12, lsr #16
+ mov r12, r12, lsl #16
+ orr r12, r12, lr, lsr #16
+#else
+ orr r3, r3, r4, lsl #16
+ mov r4, r4, lsr #16
+ orr r4, r4, r5, lsl #16
+ mov r5, r5, lsr #16
+ orr r5, r5, r12, lsl #16
+ mov r12, r12, lsr #16
+ orr r12, r12, lr, lsl #16
+#endif
+ stmia r0!, {r3-r5, r12}
+ subs r2, r2, #0x10
+ bge .Lmemmove_fsrcul2loop16
+ ldmia sp!, {r4, r5}
+ adds r2, r2, #0x0c
+ blt .Lmemmove_fsrcul2l4
+
+.Lmemmove_fsrcul2loop4:
+#ifdef __ARMEB__
+ mov r12, lr, lsl #16
+#else
+ mov r12, lr, lsr #16
+#endif
+ ldr lr, [r1], #4
+#ifdef __ARMEB__
+ orr r12, r12, lr, lsr #16
+#else
+ orr r12, r12, lr, lsl #16
+#endif
+ str r12, [r0], #4
+ subs r2, r2, #4
+ bge .Lmemmove_fsrcul2loop4
+
+.Lmemmove_fsrcul2l4:
+ sub r1, r1, #2
+ b .Lmemmove_fl4
+
+.Lmemmove_fsrcul3:
+ cmp r2, #0x0c
+ blt .Lmemmove_fsrcul3loop4
+ sub r2, r2, #0x0c
+ stmdb sp!, {r4, r5}
+
+.Lmemmove_fsrcul3loop16:
+#ifdef __ARMEB__
+ mov r3, lr, lsl #24
+#else
+ mov r3, lr, lsr #24
+#endif
+ ldmia r1!, {r4, r5, r12, lr}
+#ifdef __ARMEB__
+ orr r3, r3, r4, lsr #8
+ mov r4, r4, lsl #24
+ orr r4, r4, r5, lsr #8
+ mov r5, r5, lsl #24
+ orr r5, r5, r12, lsr #8
+ mov r12, r12, lsl #24
+ orr r12, r12, lr, lsr #8
+#else
+ orr r3, r3, r4, lsl #8
+ mov r4, r4, lsr #24
+ orr r4, r4, r5, lsl #8
+ mov r5, r5, lsr #24
+ orr r5, r5, r12, lsl #8
+ mov r12, r12, lsr #24
+ orr r12, r12, lr, lsl #8
+#endif
+ stmia r0!, {r3-r5, r12}
+ subs r2, r2, #0x10
+ bge .Lmemmove_fsrcul3loop16
+ ldmia sp!, {r4, r5}
+ adds r2, r2, #0x0c
+ blt .Lmemmove_fsrcul3l4
+
+.Lmemmove_fsrcul3loop4:
+#ifdef __ARMEB__
+ mov r12, lr, lsl #24
+#else
+ mov r12, lr, lsr #24
+#endif
+ ldr lr, [r1], #4
+#ifdef __ARMEB__
+ orr r12, r12, lr, lsr #8
+#else
+ orr r12, r12, lr, lsl #8
+#endif
+ str r12, [r0], #4
+ subs r2, r2, #4
+ bge .Lmemmove_fsrcul3loop4
+
+.Lmemmove_fsrcul3l4:
+ sub r1, r1, #1
+ b .Lmemmove_fl4
+
+.Lmemmove_backwards:
+ add r1, r1, r2
+ add r0, r0, r2
+ subs r2, r2, #4
+ blt .Lmemmove_bl4 /* less than 4 bytes */
+ ands r12, r0, #3
+ bne .Lmemmove_bdestul /* oh unaligned destination addr */
+ ands r12, r1, #3
+ bne .Lmemmove_bsrcul /* oh unaligned source addr */
+
+.Lmemmove_bt8:
+ /* We have aligned source and destination */
+ subs r2, r2, #8
+ blt .Lmemmove_bl12 /* less than 12 bytes (4 from above) */
+ stmdb sp!, {r4, lr}
+ subs r2, r2, #0x14 /* less than 32 bytes (12 from above) */
+ blt .Lmemmove_bl32
+
+ /* blat 32 bytes at a time */
+ /* XXX for really big copies perhaps we should use more registers */
+.Lmemmove_bloop32:
+ ldmdb r1!, {r3, r4, r12, lr}
+ stmdb r0!, {r3, r4, r12, lr}
+ ldmdb r1!, {r3, r4, r12, lr}
+ stmdb r0!, {r3, r4, r12, lr}
+ subs r2, r2, #0x20
+ bge .Lmemmove_bloop32
+
+.Lmemmove_bl32:
+ cmn r2, #0x10
+ ittt ge
+ ldmdbge r1!, {r3, r4, r12, lr} /* blat a remaining 16 bytes */
+ stmdbge r0!, {r3, r4, r12, lr}
+ subge r2, r2, #0x10
+ adds r2, r2, #0x14
+ ittt ge
+ ldmdbge r1!, {r3, r12, lr} /* blat a remaining 12 bytes */
+ stmdbge r0!, {r3, r12, lr}
+ subge r2, r2, #0x0c
+ ldmia sp!, {r4, lr}
+
+.Lmemmove_bl12:
+ adds r2, r2, #8
+ blt .Lmemmove_bl4
+ subs r2, r2, #4
+ itt lt
+ ldrlt r3, [r1, #-4]!
+ strlt r3, [r0, #-4]!
+ ittt ge
+ ldmdbge r1!, {r3, r12}
+ stmdbge r0!, {r3, r12}
+ subge r2, r2, #4
+
+.Lmemmove_bl4:
+ /* less than 4 bytes to go */
+ adds r2, r2, #4
+ it eq
+ RETeq /* done */
+
+ /* copy the crud byte at a time */
+ cmp r2, #2
+ ldrb r3, [r1, #-1]!
+ strb r3, [r0, #-1]!
+ itt ge
+ ldrbge r3, [r1, #-1]!
+ strbge r3, [r0, #-1]!
+ itt gt
+ ldrbgt r3, [r1, #-1]!
+ strbgt r3, [r0, #-1]!
+ RET
+
+ /* erg - unaligned destination */
+.Lmemmove_bdestul:
+ cmp r12, #2
+
+ /* align destination with byte copies */
+ ldrb r3, [r1, #-1]!
+ strb r3, [r0, #-1]!
+ itt ge
+ ldrbge r3, [r1, #-1]!
+ strbge r3, [r0, #-1]!
+ itt gt
+ ldrbgt r3, [r1, #-1]!
+ strbgt r3, [r0, #-1]!
+ subs r2, r2, r12
+ blt .Lmemmove_bl4 /* less than 4 bytes to go */
+ ands r12, r1, #3
+ beq .Lmemmove_bt8 /* we have an aligned source */
+
+ /* erg - unaligned source */
+ /* This is where it gets nasty ... */
+.Lmemmove_bsrcul:
+ bic r1, r1, #3
+ ldr r3, [r1, #0]
+ cmp r12, #2
+ blt .Lmemmove_bsrcul1
+ beq .Lmemmove_bsrcul2
+ cmp r2, #0x0c
+ blt .Lmemmove_bsrcul3loop4
+ sub r2, r2, #0x0c
+ stmdb sp!, {r4, r5, lr}
+
+.Lmemmove_bsrcul3loop16:
+#ifdef __ARMEB__
+ mov lr, r3, lsr #8
+#else
+ mov lr, r3, lsl #8
+#endif
+ ldmdb r1!, {r3-r5, r12}
+#ifdef __ARMEB__
+ orr lr, lr, r12, lsl #24
+ mov r12, r12, lsr #8
+ orr r12, r12, r5, lsl #24
+ mov r5, r5, lsr #8
+ orr r5, r5, r4, lsl #24
+ mov r4, r4, lsr #8
+ orr r4, r4, r3, lsl #24
+#else
+ orr lr, lr, r12, lsr #24
+ mov r12, r12, lsl #8
+ orr r12, r12, r5, lsr #24
+ mov r5, r5, lsl #8
+ orr r5, r5, r4, lsr #24
+ mov r4, r4, lsl #8
+ orr r4, r4, r3, lsr #24
+#endif
+ stmdb r0!, {r4, r5, r12, lr}
+ subs r2, r2, #0x10
+ bge .Lmemmove_bsrcul3loop16
+ ldmia sp!, {r4, r5, lr}
+ adds r2, r2, #0x0c
+ blt .Lmemmove_bsrcul3l4
+
+.Lmemmove_bsrcul3loop4:
+#ifdef __ARMEB__
+ mov r12, r3, lsr #8
+#else
+ mov r12, r3, lsl #8
+#endif
+ ldr r3, [r1, #-4]!
+#ifdef __ARMEB__
+ orr r12, r12, r3, lsl #24
+#else
+ orr r12, r12, r3, lsr #24
+#endif
+ str r12, [r0, #-4]!
+ subs r2, r2, #4
+ bge .Lmemmove_bsrcul3loop4
+
+.Lmemmove_bsrcul3l4:
+ add r1, r1, #3
+ b .Lmemmove_bl4
+
+.Lmemmove_bsrcul2:
+ cmp r2, #0x0c
+ blt .Lmemmove_bsrcul2loop4
+ sub r2, r2, #0x0c
+ stmdb sp!, {r4, r5, lr}
+
+.Lmemmove_bsrcul2loop16:
+#ifdef __ARMEB__
+ mov lr, r3, lsr #16
+#else
+ mov lr, r3, lsl #16
+#endif
+ ldmdb r1!, {r3-r5, r12}
+#ifdef __ARMEB__
+ orr lr, lr, r12, lsl #16
+ mov r12, r12, lsr #16
+ orr r12, r12, r5, lsl #16
+ mov r5, r5, lsr #16
+ orr r5, r5, r4, lsl #16
+ mov r4, r4, lsr #16
+ orr r4, r4, r3, lsl #16
+#else
+ orr lr, lr, r12, lsr #16
+ mov r12, r12, lsl #16
+ orr r12, r12, r5, lsr #16
+ mov r5, r5, lsl #16
+ orr r5, r5, r4, lsr #16
+ mov r4, r4, lsl #16
+ orr r4, r4, r3, lsr #16
+#endif
+ stmdb r0!, {r4, r5, r12, lr}
+ subs r2, r2, #0x10
+ bge .Lmemmove_bsrcul2loop16
+ ldmia sp!, {r4, r5, lr}
+ adds r2, r2, #0x0c
+ blt .Lmemmove_bsrcul2l4
+
+.Lmemmove_bsrcul2loop4:
+#ifdef __ARMEB__
+ mov r12, r3, lsr #16
+#else
+ mov r12, r3, lsl #16
+#endif
+ ldr r3, [r1, #-4]!
+#ifdef __ARMEB__
+ orr r12, r12, r3, lsl #16
+#else
+ orr r12, r12, r3, lsr #16
+#endif
+ str r12, [r0, #-4]!
+ subs r2, r2, #4
+ bge .Lmemmove_bsrcul2loop4
+
+.Lmemmove_bsrcul2l4:
+ add r1, r1, #2
+ b .Lmemmove_bl4
+
+.Lmemmove_bsrcul1:
+ cmp r2, #0x0c
+ blt .Lmemmove_bsrcul1loop4
+ sub r2, r2, #0x0c
+ stmdb sp!, {r4, r5, lr}
+
+.Lmemmove_bsrcul1loop32:
+#ifdef __ARMEB__
+ mov lr, r3, lsr #24
+#else
+ mov lr, r3, lsl #24
+#endif
+ ldmdb r1!, {r3-r5, r12}
+#ifdef __ARMEB__
+ orr lr, lr, r12, lsl #8
+ mov r12, r12, lsr #24
+ orr r12, r12, r5, lsl #8
+ mov r5, r5, lsr #24
+ orr r5, r5, r4, lsl #8
+ mov r4, r4, lsr #24
+ orr r4, r4, r3, lsl #8
+#else
+ orr lr, lr, r12, lsr #8
+ mov r12, r12, lsl #24
+ orr r12, r12, r5, lsr #8
+ mov r5, r5, lsl #24
+ orr r5, r5, r4, lsr #8
+ mov r4, r4, lsl #24
+ orr r4, r4, r3, lsr #8
+#endif
+ stmdb r0!, {r4, r5, r12, lr}
+ subs r2, r2, #0x10
+ bge .Lmemmove_bsrcul1loop32
+ ldmia sp!, {r4, r5, lr}
+ adds r2, r2, #0x0c
+ blt .Lmemmove_bsrcul1l4
+
+.Lmemmove_bsrcul1loop4:
+#ifdef __ARMEB__
+ mov r12, r3, lsr #24
+#else
+ mov r12, r3, lsl #24
+#endif
+ ldr r3, [r1, #-4]!
+#ifdef __ARMEB__
+ orr r12, r12, r3, lsl #8
+#else
+ orr r12, r12, r3, lsr #8
+#endif
+ str r12, [r0, #-4]!
+ subs r2, r2, #4
+ bge .Lmemmove_bsrcul1loop4
+
+.Lmemmove_bsrcul1l4:
+ add r1, r1, #1
+ b .Lmemmove_bl4
+#ifndef _BCOPY
+END(memmove)
+#else
+END(bcopy)
+#endif
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/arm/string/memset.S b/lib/libc/arm/string/memset.S
new file mode 100644
index 000000000000..96d2f93183c4
--- /dev/null
+++ b/lib/libc/arm/string/memset.S
@@ -0,0 +1,267 @@
+/* $NetBSD: memset.S,v 1.4 2003/10/14 07:51:45 scw Exp $ */
+
+/*
+ * Copyright 2003 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Steve C. Woodford for Wasabi Systems, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the NetBSD Project by
+ * Wasabi Systems, Inc.
+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 1995 Mark Brinicombe.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Mark Brinicombe.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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$");
+
+.syntax unified
+
+/*
+ * memset: Sets a block of memory to the specified value
+ *
+ * On entry:
+ * r0 - dest address
+ * r1 - byte to write
+ * r2 - number of bytes to write
+ *
+ * On exit:
+ * r0 - dest address
+ */
+#ifdef _BZERO
+/* LINTSTUB: Func: void bzero(void *, size_t) */
+ENTRY(bzero)
+ mov r3, #0x00
+#else
+/* LINTSTUB: Func: void *memset(void *, int, size_t) */
+ENTRY(memset)
+ and r3, r1, #0xff /* We deal with bytes */
+ mov r1, r2
+#endif
+ cmp r1, #0x04 /* Do we have less than 4 bytes */
+ mov ip, r0
+ blt .Lmemset_lessthanfour
+
+ /* Ok first we will word align the address */
+ ands r2, ip, #0x03 /* Get the bottom two bits */
+ bne .Lmemset_wordunaligned /* The address is not word aligned */
+
+ /* We are now word aligned */
+.Lmemset_wordaligned:
+#ifndef _BZERO
+ orr r3, r3, r3, lsl #8 /* Extend value to 16-bits */
+#endif
+#ifdef _ARM_ARCH_5E
+ tst ip, #0x04 /* Quad-align for armv5e */
+#else
+ cmp r1, #0x10
+#endif
+#ifndef _BZERO
+ orr r3, r3, r3, lsl #16 /* Extend value to 32-bits */
+#endif
+#ifdef _ARM_ARCH_5E
+ itt ne
+ subne r1, r1, #0x04 /* Quad-align if necessary */
+ strne r3, [ip], #0x04
+ cmp r1, #0x10
+#endif
+ blt .Lmemset_loop4 /* If less than 16 then use words */
+ mov r2, r3 /* Duplicate data */
+ cmp r1, #0x80 /* If < 128 then skip the big loop */
+ blt .Lmemset_loop32
+
+ /* Do 128 bytes at a time */
+.Lmemset_loop128:
+ subs r1, r1, #0x80
+#ifdef _ARM_ARCH_5E
+ itttt ge
+ strdge r2, [ip], #0x08
+ strdge r2, [ip], #0x08
+ strdge r2, [ip], #0x08
+ strdge r2, [ip], #0x08
+ itttt ge
+ strdge r2, [ip], #0x08
+ strdge r2, [ip], #0x08
+ strdge r2, [ip], #0x08
+ strdge r2, [ip], #0x08
+ itttt ge
+ strdge r2, [ip], #0x08
+ strdge r2, [ip], #0x08
+ strdge r2, [ip], #0x08
+ strdge r2, [ip], #0x08
+ itttt ge
+ strdge r2, [ip], #0x08
+ strdge r2, [ip], #0x08
+ strdge r2, [ip], #0x08
+ strdge r2, [ip], #0x08
+#else
+ stmiage ip!, {r2-r3}
+ stmiage ip!, {r2-r3}
+ stmiage ip!, {r2-r3}
+ stmiage ip!, {r2-r3}
+ stmiage ip!, {r2-r3}
+ stmiage ip!, {r2-r3}
+ stmiage ip!, {r2-r3}
+ stmiage ip!, {r2-r3}
+ stmiage ip!, {r2-r3}
+ stmiage ip!, {r2-r3}
+ stmiage ip!, {r2-r3}
+ stmiage ip!, {r2-r3}
+ stmiage ip!, {r2-r3}
+ stmiage ip!, {r2-r3}
+ stmiage ip!, {r2-r3}
+ stmiage ip!, {r2-r3}
+#endif
+ bgt .Lmemset_loop128
+ it eq
+ RETeq /* Zero length so just exit */
+
+ add r1, r1, #0x80 /* Adjust for extra sub */
+
+ /* Do 32 bytes at a time */
+.Lmemset_loop32:
+ subs r1, r1, #0x20
+ itttt ge
+#ifdef _ARM_ARCH_5E
+ strdge r2, [ip], #0x08
+ strdge r2, [ip], #0x08
+ strdge r2, [ip], #0x08
+ strdge r2, [ip], #0x08
+#else
+ stmiage ip!, {r2-r3}
+ stmiage ip!, {r2-r3}
+ stmiage ip!, {r2-r3}
+ stmiage ip!, {r2-r3}
+#endif
+ bgt .Lmemset_loop32
+ it eq
+ RETeq /* Zero length so just exit */
+
+ adds r1, r1, #0x10 /* Partially adjust for extra sub */
+
+ /* Deal with 16 bytes or more */
+ itt ge
+#ifdef _ARM_ARCH_5E
+ strdge r2, [ip], #0x08
+ strdge r2, [ip], #0x08
+#else
+ stmiage ip!, {r2-r3}
+ stmiage ip!, {r2-r3}
+#endif
+ it eq
+ RETeq /* Zero length so just exit */
+
+ it lt
+ addlt r1, r1, #0x10 /* Possibly adjust for extra sub */
+
+ /* We have at least 4 bytes so copy as words */
+.Lmemset_loop4:
+ subs r1, r1, #0x04
+ it ge
+ strge r3, [ip], #0x04
+ bgt .Lmemset_loop4
+ it eq
+ RETeq /* Zero length so just exit */
+
+#ifdef _ARM_ARCH_5E
+ /* Compensate for 64-bit alignment check */
+ adds r1, r1, #0x04
+ it eq
+ RETeq
+ cmp r1, #2
+#else
+ cmp r1, #-2
+#endif
+
+ strb r3, [ip], #0x01 /* Set 1 byte */
+ it ge
+ strbge r3, [ip], #0x01 /* Set another byte */
+ it gt
+ strbgt r3, [ip] /* and a third */
+ RET /* Exit */
+
+.Lmemset_wordunaligned:
+ rsb r2, r2, #0x004
+ strb r3, [ip], #0x01 /* Set 1 byte */
+ cmp r2, #0x02
+ it ge
+ strbge r3, [ip], #0x01 /* Set another byte */
+ sub r1, r1, r2
+ it gt
+ strbgt r3, [ip], #0x01 /* and a third */
+ cmp r1, #0x04 /* More than 4 bytes left? */
+ it ge
+ bge .Lmemset_wordaligned /* Yup */
+
+.Lmemset_lessthanfour:
+ cmp r1, #0x00
+ it eq
+ RETeq /* Zero length so exit */
+ strb r3, [ip], #0x01 /* Set 1 byte */
+ cmp r1, #0x02
+ it ge
+ strbge r3, [ip], #0x01 /* Set another byte */
+ it gt
+ strbgt r3, [ip] /* and a third */
+ RET /* Exit */
+#ifdef _BZERO
+END(bzero)
+#else
+END(memset)
+#endif
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/arm/string/strcmp.S b/lib/libc/arm/string/strcmp.S
new file mode 100644
index 000000000000..1cdce8bcbab9
--- /dev/null
+++ b/lib/libc/arm/string/strcmp.S
@@ -0,0 +1,47 @@
+/* $NetBSD: strcmp.S,v 1.3 2003/04/05 23:08:52 bjh21 Exp $ */
+
+/*
+ * Copyright (c) 2002 ARM Ltd
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the company may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ARM LTD ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL ARM LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * 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$");
+
+ENTRY(strcmp)
+1:
+ ldrb r2, [r0], #1
+ ldrb r3, [r1], #1
+ cmp r2, #1
+ it cs
+ cmpcs r2, r3
+ beq 1b
+ sub r0, r2, r3
+ RET
+END(strcmp)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/arm/string/strlen.S b/lib/libc/arm/string/strlen.S
new file mode 100644
index 000000000000..240fa7d9e85f
--- /dev/null
+++ b/lib/libc/arm/string/strlen.S
@@ -0,0 +1,87 @@
+/*-
+ * Copyright (c) 2005 Olivier Houchard
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+.syntax unified
+
+ENTRY(strlen)
+ mov r1, #0
+ /* Check that the pointer is aligned on 32 bits. */
+ ands r3, r0, #3
+ beq .Loop
+ sub r0, r0, r3
+ ldr r2, [r0]
+ add r0, r0, #4
+ cmp r3, #2
+ blt .Ldo_3
+ bgt .Ldo_1
+ /* So that the N bit is set. */
+ cmp r3, #0
+ b .Ldo_2
+
+.Loop:
+ ldr r2, [r0]
+ add r0, r0, #4
+#ifndef __ARMEB__
+ ands r3, r2, #0x000000ff
+#else
+ ands r3, r2, #0xff000000
+#endif
+ it ne
+ addne r1, r1, #1
+.Ldo_3:
+ itt ne
+#ifndef __ARMEB__
+ andsne r3, r2, #0x0000ff00
+#else
+ andsne r3, r2, #0x00ff0000
+#endif
+ addne r1, r1, #1
+.Ldo_2:
+ itt ne
+#ifndef __ARMEB__
+ andsne r3, r2, #0x00ff0000
+#else
+ andsne r3, r2, #0x0000ff00
+#endif
+ addne r1, r1, #1
+.Ldo_1:
+ ittt ne
+#ifndef __ARMEB__
+ andsne r3, r2, #0xff000000
+#else
+ andsne r3, r2, #0x000000ff
+#endif
+ addne r1, r1, #1
+ bne .Loop
+.Lexit:
+ mov r0, r1
+ RET
+END(strlen)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/arm/string/strncmp.S b/lib/libc/arm/string/strncmp.S
new file mode 100644
index 000000000000..affcaa0537b2
--- /dev/null
+++ b/lib/libc/arm/string/strncmp.S
@@ -0,0 +1,60 @@
+/* $NetBSD: strncmp.S,v 1.2 2003/04/05 23:08:52 bjh21 Exp $ */
+
+/*
+ * Copyright (c) 2002 ARM Ltd
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the company may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ARM LTD ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL ARM LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * 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$");
+
+ENTRY(strncmp)
+/* if (len == 0) return 0 */
+ cmp r2, #0
+ itt eq
+ moveq r0, #0
+ moveq pc, lr
+
+/* ip == last src address to compare */
+ adds ip, r0, r2
+/* Use last possible address on overflow. */
+ it cs
+ movcs ip, #0
+ sub ip, ip, #1
+1:
+ ldrb r2, [r0], #1
+ ldrb r3, [r1], #1
+ cmp ip, r0
+ itt cs
+ cmpcs r2, #1
+ cmpcs r2, r3
+ beq 1b
+ sub r0, r2, r3
+ RET
+END(strncmp)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/arm/sys/Makefile.inc b/lib/libc/arm/sys/Makefile.inc
new file mode 100644
index 000000000000..9b53030dd3c6
--- /dev/null
+++ b/lib/libc/arm/sys/Makefile.inc
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+SRCS+= __vdso_gettc.c
+
+MDASM= Ovfork.S brk.S cerror.S sbrk.S shmat.S sigreturn.S syscall.S
+
+# Don't generate default code for these syscalls:
+NOASM+= vfork.o
diff --git a/lib/libc/arm/sys/Ovfork.S b/lib/libc/arm/sys/Ovfork.S
new file mode 100644
index 000000000000..73c619e3609d
--- /dev/null
+++ b/lib/libc/arm/sys/Ovfork.S
@@ -0,0 +1,57 @@
+/* $NetBSD: Ovfork.S,v 1.6 2003/08/07 16:42:03 agc Exp $ */
+
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)Ovfork.s 5.1 (Berkeley) 4/23/90
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+#include "SYS.h"
+
+/*
+ * pid = vfork();
+ *
+ * On return from the SWI:
+ * r1 == 0 in parent process, r1 == 1 in child process.
+ * r0 == pid of child in parent, r0 == pid of parent in child.
+ */
+ .text
+ .align 0
+
+ENTRY(vfork)
+ mov r2, r14
+ SYSTRAP(vfork)
+ bcs PIC_SYM(CERROR, PLT)
+ 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)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/arm/sys/__vdso_gettc.c b/lib/libc/arm/sys/__vdso_gettc.c
new file mode 100644
index 000000000000..9f8631df5806
--- /dev/null
+++ b/lib/libc/arm/sys/__vdso_gettc.c
@@ -0,0 +1,89 @@
+/*-
+ * Copyright (c) 2015 The FreeBSD Foundation
+ *
+ * This software was developed by Konstantin Belousov
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/elf.h>
+#include <sys/time.h>
+#include <sys/vdso.h>
+#include <machine/cpufunc.h>
+#include <machine/acle-compat.h>
+#include <errno.h>
+#include "libc_private.h"
+
+#if __ARM_ARCH >= 6
+static inline uint64_t
+cp15_cntvct_get(void)
+{
+ uint64_t reg;
+
+ __asm __volatile("mrrc\tp15, 1, %Q0, %R0, c14" : "=r" (reg));
+ return (reg);
+}
+
+static inline uint64_t
+cp15_cntpct_get(void)
+{
+ uint64_t reg;
+
+ __asm __volatile("mrrc\tp15, 0, %Q0, %R0, c14" : "=r" (reg));
+ return (reg);
+}
+#endif
+
+#pragma weak __vdso_gettc
+int
+__vdso_gettc(const struct vdso_timehands *th, u_int *tc)
+{
+
+ if (th->th_algo != VDSO_TH_ALGO_ARM_GENTIM)
+ return (ENOSYS);
+#if __ARM_ARCH >= 6
+ /*
+ * Userspace gettimeofday() is only enabled on ARMv7 CPUs, but
+ * libc is compiled for ARMv6. Due to clang issues, .arch
+ * armv7-a directive does not work.
+ */
+ __asm __volatile(".word\t0xf57ff06f" : : : "memory"); /* isb */
+ *tc = th->th_physical == 0 ? cp15_cntvct_get() : cp15_cntpct_get();
+ return (0);
+#else
+ *tc = 0;
+ return (ENOSYS);
+#endif
+}
+
+#pragma weak __vdso_gettimekeep
+int
+__vdso_gettimekeep(struct vdso_timekeep **tk)
+{
+
+ return (_elf_aux_info(AT_TIMEKEEP, tk, sizeof(*tk)));
+}
diff --git a/lib/libc/arm/sys/brk.S b/lib/libc/arm/sys/brk.S
new file mode 100644
index 000000000000..bf1b4fb61d7b
--- /dev/null
+++ b/lib/libc/arm/sys/brk.S
@@ -0,0 +1,95 @@
+/* $NetBSD: brk.S,v 1.6 2003/08/07 16:42:04 agc Exp $ */
+
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)brk.s 5.2 (Berkeley) 12/17/90
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+#include "SYS.h"
+
+ .globl _C_LABEL(_end)
+ .globl CURBRK
+
+#ifdef WEAK_ALIAS
+WEAK_ALIAS(brk, _brk)
+#endif
+
+ .data
+ .align 0
+ .globl _C_LABEL(minbrk)
+ .type _C_LABEL(minbrk),#object
+_C_LABEL(minbrk):
+ .word _C_LABEL(_end)
+
+/*
+ * Change the data segment size
+ */
+ENTRY(_brk)
+ /* Setup the GOT */
+ GOT_INIT(r3, .Lgot, .L1)
+ GOT_GET(r1, r3, .Lminbrk)
+
+ /* Get the minimum allowable brk address */
+ ldr r1, [r1]
+
+ /*
+ * Valid the address specified and set to the minimum
+ * if the address is below minbrk.
+ */
+ cmp r0, r1
+ it lt
+ movlt r0, r1
+ mov r2, r0
+ SYSTRAP(break)
+ bcs PIC_SYM(CERROR, PLT)
+
+#ifdef PIC
+ ldr r1, .Lcurbrk
+ ldr r1, [r3, r1]
+#else
+ ldr r1, .Lcurbrk
+#endif
+ /* Store the new address in curbrk */
+ str r2, [r1]
+
+ /* Return 0 for success */
+ mov r0, #0x00000000
+ RET
+
+ .align 2
+ GOT_INITSYM(.Lgot, .L1)
+.Lminbrk:
+ .word PIC_SYM(_C_LABEL(minbrk), GOT)
+.Lcurbrk:
+ .word PIC_SYM(CURBRK, GOT)
+END(_brk)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/arm/sys/cerror.S b/lib/libc/arm/sys/cerror.S
new file mode 100644
index 000000000000..5fad698caf11
--- /dev/null
+++ b/lib/libc/arm/sys/cerror.S
@@ -0,0 +1,51 @@
+/* $NetBSD: cerror.S,v 1.5 2003/08/07 16:42:04 agc Exp $ */
+
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)cerror.s 5.1 (Berkeley) 4/23/90
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+#include "SYS.h"
+
+.globl _C_LABEL(__error)
+.type _C_LABEL(__error),%function
+
+ASENTRY(CERROR)
+ stmfd sp!, {r4, lr}
+ mov r4, r0
+ bl PIC_SYM(_C_LABEL(__error), PLT)
+ str r4, [r0]
+ mvn r0, #0x00000000
+ mvn r1, #0x00000000
+ ldmfd sp!, {r4, pc}
+END(CERROR)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/arm/sys/sbrk.S b/lib/libc/arm/sys/sbrk.S
new file mode 100644
index 000000000000..25622c4a809b
--- /dev/null
+++ b/lib/libc/arm/sys/sbrk.S
@@ -0,0 +1,82 @@
+/* $NetBSD: sbrk.S,v 1.7 2003/08/07 16:42:05 agc Exp $ */
+
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)sbrk.s 5.1 (Berkeley) 4/23/90
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+#include "SYS.h"
+
+ .globl _C_LABEL(_end)
+
+#ifdef WEAK_ALIAS
+WEAK_ALIAS(sbrk, _sbrk)
+#endif
+
+ .data
+ .align 0
+ .globl CURBRK
+ .type CURBRK,#object
+CURBRK:
+ .word _C_LABEL(_end)
+
+/*
+ * Change the data segment size
+ */
+ENTRY(_sbrk)
+ /* Setup the GOT */
+ GOT_INIT(r3, .Lgot, .L1)
+ GOT_GET(r2, r3, .Lcurbrk)
+
+ /* Get the current brk address */
+ ldr r1, [r2]
+
+ /* Calculate new value */
+ mov r3, r0
+ add r0, r0, r1
+ SYSTRAP(break)
+ bcs PIC_SYM(CERROR, PLT)
+
+ /* Store new curbrk value */
+ ldr r0, [r2]
+ add r1, r0, r3
+ str r1, [r2]
+
+ /* Return old curbrk value */
+ RET
+
+ .align 0
+ GOT_INITSYM(.Lgot, .L1)
+.Lcurbrk:
+ .word PIC_SYM(CURBRK, GOT)
+END(_sbrk)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/arm/sys/shmat.S b/lib/libc/arm/sys/shmat.S
new file mode 100644
index 000000000000..3574b1d4f4e4
--- /dev/null
+++ b/lib/libc/arm/sys/shmat.S
@@ -0,0 +1,9 @@
+/* $NetBSD: shmat.S,v 1.1 2000/12/29 20:14:04 bjh21 Exp $ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+#include "SYS.h"
+
+RSYSCALL(shmat)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/arm/sys/sigreturn.S b/lib/libc/arm/sys/sigreturn.S
new file mode 100644
index 000000000000..c377e4a296e4
--- /dev/null
+++ b/lib/libc/arm/sys/sigreturn.S
@@ -0,0 +1,44 @@
+/* $NetBSD: __sigreturn14.S,v 1.3 2003/08/07 16:42:03 agc Exp $ */
+
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)sigreturn.s 5.2 (Berkeley) 12/17/90"
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+#include "SYS.h"
+
+/*
+ * We must preserve the state of the registers as the user has set them up.
+ */
+
+RSYSCALL(sigreturn)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/arm/sys/syscall.S b/lib/libc/arm/sys/syscall.S
new file mode 100644
index 000000000000..c88d1aeb4b65
--- /dev/null
+++ b/lib/libc/arm/sys/syscall.S
@@ -0,0 +1,40 @@
+/* $NetBSD: syscall.S,v 1.4 2003/08/07 16:42:05 agc Exp $ */
+
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)syscall.s 5.1 (Berkeley) 4/23/90
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+#include "SYS.h"
+
+RSYSCALL(syscall)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/capability/Makefile.inc b/lib/libc/capability/Makefile.inc
new file mode 100644
index 000000000000..a53ba1f23049
--- /dev/null
+++ b/lib/libc/capability/Makefile.inc
@@ -0,0 +1,18 @@
+# $FreeBSD$
+
+# capability sources
+.PATH: ${SRCTOP}/sys/kern ${LIBC_SRCTOP}/capability
+
+SRCS+= subr_capability.c
+
+SYM_MAPS+= ${LIBC_SRCTOP}/capability/Symbol.map
+
+MAN+= cap_rights_init.3
+
+MLINKS+=cap_rights_init.3 cap_rights_set.3
+MLINKS+=cap_rights_init.3 cap_rights_clear.3
+MLINKS+=cap_rights_init.3 cap_rights_is_set.3
+MLINKS+=cap_rights_init.3 cap_rights_is_valid.3
+MLINKS+=cap_rights_init.3 cap_rights_merge.3
+MLINKS+=cap_rights_init.3 cap_rights_remove.3
+MLINKS+=cap_rights_init.3 cap_rights_contains.3
diff --git a/lib/libc/capability/Symbol.map b/lib/libc/capability/Symbol.map
new file mode 100644
index 000000000000..c5c18c2f5315
--- /dev/null
+++ b/lib/libc/capability/Symbol.map
@@ -0,0 +1,14 @@
+/*
+ * $FreeBSD$
+ */
+
+FBSD_1.3 {
+ __cap_rights_clear;
+ cap_rights_contains;
+ __cap_rights_init;
+ __cap_rights_is_set;
+ cap_rights_is_valid;
+ cap_rights_merge;
+ cap_rights_remove;
+ __cap_rights_set;
+};
diff --git a/lib/libc/capability/cap_rights_init.3 b/lib/libc/capability/cap_rights_init.3
new file mode 100644
index 000000000000..5615de1a6804
--- /dev/null
+++ b/lib/libc/capability/cap_rights_init.3
@@ -0,0 +1,241 @@
+.\"
+.\" Copyright (c) 2013 The FreeBSD Foundation
+.\" All rights reserved.
+.\"
+.\" This documentation was written 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 March 27, 2014
+.Dt CAP_RIGHTS_INIT 3
+.Os
+.Sh NAME
+.Nm cap_rights_init ,
+.Nm cap_rights_set ,
+.Nm cap_rights_clear ,
+.Nm cap_rights_is_set ,
+.Nm cap_rights_is_valid ,
+.Nm cap_rights_merge ,
+.Nm cap_rights_remove ,
+.Nm cap_rights_contains
+.Nd manage cap_rights_t structure
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/capsicum.h
+.Ft cap_rights_t *
+.Fn cap_rights_init "cap_rights_t *rights" "..."
+.Ft cap_rights_t *
+.Fn cap_rights_set "cap_rights_t *rights" "..."
+.Ft cap_rights_t *
+.Fn cap_rights_clear "cap_rights_t *rights" "..."
+.Ft bool
+.Fn cap_rights_is_set "const cap_rights_t *rights" "..."
+.Ft bool
+.Fn cap_rights_is_valid "const cap_rights_t *rights"
+.Ft cap_rights_t *
+.Fn cap_rights_merge "cap_rights_t *dst" "const cap_rights_t *src"
+.Ft cap_rights_t *
+.Fn cap_rights_remove "cap_rights_t *dst" "const cap_rights_t *src"
+.Ft bool
+.Fn cap_rights_contains "const cap_rights_t *big" "const cap_rights_t *little"
+.Sh DESCRIPTION
+The functions documented here allow to manage the
+.Vt cap_rights_t
+structure.
+.Pp
+Capability rights should be separated with comma when passed to the
+.Fn cap_rights_init ,
+.Fn cap_rights_set ,
+.Fn cap_rights_clear
+and
+.Fn cap_rights_is_set
+functions.
+For example:
+.Bd -literal
+cap_rights_set(&rights, CAP_READ, CAP_WRITE, CAP_FSTAT, CAP_SEEK);
+.Ed
+.Pp
+The complete list of the capability rights can be found in the
+.Xr rights 4
+manual page.
+.Pp
+The
+.Fn cap_rights_init
+function initialize provided
+.Vt cap_rights_t
+structure.
+Only properly initialized structure can be passed to the remaining functions.
+For convenience the structure can be filled with capability rights instead of
+calling the
+.Fn cap_rights_set
+function later.
+For even more convenience pointer to the given structure is returned, so it can
+be directly passed to
+.Xr cap_rights_limit 2 :
+.Bd -literal
+cap_rights_t rights;
+
+if (cap_rights_limit(fd, cap_rights_init(&rights, CAP_READ, CAP_WRITE)) < 0)
+ err(1, "Unable to limit capability rights");
+.Ed
+.Pp
+The
+.Fn cap_rights_set
+function adds the given capability rights to the given
+.Vt cap_rights_t
+structure.
+.Pp
+The
+.Fn cap_rights_clear
+function removes the given capability rights from the given
+.Vt cap_rights_t
+structure.
+.Pp
+The
+.Fn cap_rights_is_set
+function checks if all the given capability rights are set for the given
+.Vt cap_rights_t
+structure.
+.Pp
+The
+.Fn cap_rights_is_valid
+function verifies if the given
+.Vt cap_rights_t
+structure is valid.
+.Pp
+The
+.Fn cap_rights_merge
+function merges all capability rights present in the
+.Fa src
+structure into the
+.Fa dst
+structure.
+.Pp
+The
+.Fn cap_rights_remove
+function removes all capability rights present in the
+.Fa src
+structure from the
+.Fa dst
+structure.
+.Pp
+The
+.Fn cap_rights_contains
+function checks if the
+.Fa big
+structure contains all capability rights present in the
+.Fa little
+structure.
+.Sh RETURN VALUES
+The functions never fail.
+In case an invalid capability right or an invalid
+.Vt cap_rights_t
+structure is given as an argument, the program will be aborted.
+.Pp
+The
+.Fn cap_rights_init ,
+.Fn cap_rights_set
+and
+.Fn cap_rights_clear
+functions return pointer to the
+.Vt cap_rights_t
+structure given in the
+.Fa rights
+argument.
+.Pp
+The
+.Fn cap_rights_merge
+and
+.Fn cap_rights_remove
+functions return pointer to the
+.Vt cap_rights_t
+structure given in the
+.Fa dst
+argument.
+.Pp
+The
+.Fn cap_rights_is_set
+returns
+.Va true
+if all the given capability rights are set in the
+.Fa rights
+argument.
+.Pp
+The
+.Fn cap_rights_is_valid
+function performs various checks to see if the given
+.Vt cap_rights_t
+structure is valid and returns
+.Va true
+if it is.
+.Pp
+The
+.Fn cap_rights_contains
+function returns
+.Va true
+if all capability rights set in the
+.Fa little
+structure are also present in the
+.Fa big
+structure.
+.Sh EXAMPLES
+The following example demonstrates how to prepare a
+.Vt cap_rights_t
+structure to be passed to the
+.Xr cap_rights_limit 2
+system call.
+.Bd -literal
+cap_rights_t rights;
+int fd;
+
+fd = open("/tmp/foo", O_RDWR);
+if (fd < 0)
+ err(1, "open() failed");
+
+cap_rights_init(&rights, CAP_FSTAT, CAP_READ);
+
+if (allow_write_and_seek)
+ cap_rights_set(&rights, CAP_WRITE, CAP_SEEK);
+
+if (dont_allow_seek)
+ cap_rights_clear(&rights, CAP_SEEK);
+
+if (cap_rights_limit(fd, &rights) < 0 && errno != ENOSYS)
+ err(1, "cap_rights_limit() failed");
+.Ed
+.Sh SEE ALSO
+.Xr cap_rights_limit 2 ,
+.Xr open 2 ,
+.Xr capsicum 4 ,
+.Xr rights 4
+.Sh HISTORY
+Support for capabilities and capabilities mode was developed as part of the
+.Tn TrustedBSD
+Project.
+.Sh AUTHORS
+This family of functions was created by
+.An Pawel Jakub Dawidek Aq Mt pawel@dawidek.net
+under sponsorship from the FreeBSD Foundation.
diff --git a/lib/libc/compat-43/Makefile.inc b/lib/libc/compat-43/Makefile.inc
new file mode 100644
index 000000000000..597a0f8fd51e
--- /dev/null
+++ b/lib/libc/compat-43/Makefile.inc
@@ -0,0 +1,24 @@
+# @(#)Makefile.inc 8.1 (Berkeley) 6/2/93
+# $FreeBSD$
+
+# compat-43 sources
+.PATH: ${LIBC_SRCTOP}/${LIBC_ARCH}/compat-43 ${LIBC_SRCTOP}/compat-43
+
+SRCS+= creat.c gethostid.c getwd.c killpg.c sethostid.c setpgrp.c \
+ setrgid.c setruid.c sigcompat.c
+
+SYM_MAPS+=${LIBC_SRCTOP}/compat-43/Symbol.map
+
+MAN+= creat.2 killpg.2 sigpause.2 sigsetmask.2 sigvec.2
+MAN+= gethostid.3 setruid.3
+
+MLINKS+=gethostid.3 sethostid.3
+MLINKS+=sigpause.2 sighold.2
+MLINKS+=sigpause.2 sigignore.2
+MLINKS+=sigpause.2 sigrelse.2
+MLINKS+=sigpause.2 sigset.2
+MLINKS+=sigpause.2 xsi_sigpause.2
+MLINKS+=setruid.3 setrgid.3
+
+MLINKS+=sigsetmask.2 sigblock.2
+MLINKS+=sigsetmask.2 sigmask.2
diff --git a/lib/libc/compat-43/Symbol.map b/lib/libc/compat-43/Symbol.map
new file mode 100644
index 000000000000..bd49f99e2df6
--- /dev/null
+++ b/lib/libc/compat-43/Symbol.map
@@ -0,0 +1,31 @@
+/*
+ * $FreeBSD$
+ */
+
+FBSD_1.0 {
+ creat;
+ gethostid;
+ getwd;
+ killpg;
+ sethostid;
+ setpgrp;
+ setrgid;
+ setruid;
+ sigblock;
+ sigpause;
+ sigsetmask;
+ sigvec;
+};
+
+FBSD_1.2 {
+ sighold;
+ sigignore;
+ sigrelse;
+ sigset;
+ xsi_sigpause;
+};
+
+FBSDprivate_1.0 {
+ __creat;
+ _creat;
+};
diff --git a/lib/libc/compat-43/creat.2 b/lib/libc/compat-43/creat.2
new file mode 100644
index 000000000000..3b1d03b31f86
--- /dev/null
+++ b/lib/libc/compat-43/creat.2
@@ -0,0 +1,62 @@
+.\" Copyright (c) 1989, 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.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)creat.2 8.1 (Berkeley) 6/2/93
+.\" $FreeBSD$
+.\"
+.Dd June 2, 1993
+.Dt CREAT 2
+.Os
+.Sh NAME
+.Nm creat
+.Nd create a new file
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In fcntl.h
+.Ft int
+.Fn creat "const char *path" "mode_t mode"
+.Sh DESCRIPTION
+.Bf -symbolic
+This interface is made obsolete by:
+.Ef
+.Xr open 2 .
+.Pp
+The
+.Fn creat
+function
+is the same as:
+.Bd -literal -offset indent
+open(path, O_CREAT | O_TRUNC | O_WRONLY, mode);
+.Ed
+.Sh SEE ALSO
+.Xr open 2
+.Sh HISTORY
+The
+.Fn creat
+function appeared in
+.At v6 .
diff --git a/lib/libc/compat-43/creat.c b/lib/libc/compat-43/creat.c
new file mode 100644
index 000000000000..983ff928bc0b
--- /dev/null
+++ b/lib/libc/compat-43/creat.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)creat.c 8.1 (Berkeley) 6/2/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <fcntl.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+
+__weak_reference(__creat, creat);
+__weak_reference(__creat, _creat);
+
+int __creat(const char *path, mode_t mode);
+
+#pragma weak creat
+int
+__creat(const char *path, mode_t mode)
+{
+
+ return (((int (*)(int, const char *, int, ...))
+ __libc_interposing[INTERPOS_openat])(AT_FDCWD, path, O_WRONLY |
+ O_CREAT | O_TRUNC, mode));
+}
+
diff --git a/lib/libc/compat-43/gethostid.3 b/lib/libc/compat-43/gethostid.3
new file mode 100644
index 000000000000..faaee563a8ff
--- /dev/null
+++ b/lib/libc/compat-43/gethostid.3
@@ -0,0 +1,80 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)gethostid.3 8.1 (Berkeley) 6/2/93
+.\" $FreeBSD$
+.\"
+.Dd June 2, 1993
+.Dt GETHOSTID 3
+.Os
+.Sh NAME
+.Nm gethostid ,
+.Nm sethostid
+.Nd get/set unique identifier of current host
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft long
+.Fn gethostid void
+.Ft void
+.Fn sethostid "long hostid"
+.Sh DESCRIPTION
+The
+.Fn sethostid
+function
+establishes a 32-bit identifier for the
+current processor that is intended to be unique among all
+UNIX systems in existence.
+This is normally a DARPA Internet
+address for the local machine.
+This call is allowed only to the
+super-user and is normally performed at boot time.
+.Pp
+The
+.Fn gethostid
+function
+returns the 32-bit identifier for the current processor.
+.Pp
+This function has been deprecated.
+The hostid should be set or retrieved by use of
+.Xr sysctl 3 .
+.Sh SEE ALSO
+.Xr gethostname 3 ,
+.Xr sysctl 3 ,
+.Xr sysctl 8
+.Sh HISTORY
+The
+.Fn gethostid
+and
+.Fn sethostid
+syscalls appeared in
+.Bx 4.2
+and were dropped in
+.Bx 4.4 .
+.Sh BUGS
+32 bits for the identifier is too small.
diff --git a/lib/libc/compat-43/gethostid.c b/lib/libc/compat-43/gethostid.c
new file mode 100644
index 000000000000..6c33850014de
--- /dev/null
+++ b/lib/libc/compat-43/gethostid.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)gethostid.c 8.1 (Berkeley) 6/2/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/sysctl.h>
+
+#include <unistd.h>
+
+long
+gethostid(void)
+{
+ int mib[2];
+ size_t size;
+ long value;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_HOSTID;
+ size = sizeof value;
+ if (sysctl(mib, 2, &value, &size, NULL, 0) == -1)
+ return (-1);
+ return (value);
+}
diff --git a/lib/libc/compat-43/getwd.c b/lib/libc/compat-43/getwd.c
new file mode 100644
index 000000000000..98fceaff2a48
--- /dev/null
+++ b/lib/libc/compat-43/getwd.c
@@ -0,0 +1,51 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)getwd.c 8.1 (Berkeley) 6/2/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+char *
+getwd(char *buf)
+{
+ char *p;
+
+ if ( (p = getcwd(buf, MAXPATHLEN)) )
+ return(p);
+ (void)strerror_r(errno, buf, MAXPATHLEN);
+ return((char *)NULL);
+}
diff --git a/lib/libc/compat-43/killpg.2 b/lib/libc/compat-43/killpg.2
new file mode 100644
index 000000000000..a1d52a4824ed
--- /dev/null
+++ b/lib/libc/compat-43/killpg.2
@@ -0,0 +1,92 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)killpg.2 8.1 (Berkeley) 6/2/93
+.\" $FreeBSD$
+.\"
+.Dd March 15, 2012
+.Dt KILLPG 2
+.Os
+.Sh NAME
+.Nm killpg
+.Nd send signal to a process group
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In signal.h
+.Ft int
+.Fn killpg "pid_t pgrp" "int sig"
+.Sh DESCRIPTION
+The
+.Fn killpg
+function
+sends the signal
+.Fa sig
+to the process group
+.Fa pgrp .
+See
+.Xr sigaction 2
+for a list of signals.
+If
+.Fa pgrp
+is 0,
+.Fn killpg
+sends the signal to the sending process's process group.
+.Pp
+The sending process must be able to
+.Fn kill
+at least one process in the receiving process group.
+.Sh RETURN VALUES
+.Rv -std killpg
+.Sh ERRORS
+The
+.Fn killpg
+function
+will fail and no signal will be sent if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa sig
+argument
+is not a valid signal number.
+.It Bq Er ESRCH
+No process can be found in the process group specified by
+.Fa pgrp .
+.It Bq Er EPERM
+.Fn kill
+returns EPERM for all processes in the process group.
+.El
+.Sh SEE ALSO
+.Xr getpgrp 2 ,
+.Xr kill 2 ,
+.Xr sigaction 2
+.Sh HISTORY
+The
+.Fn killpg
+function appeared in
+.Bx 4.0 .
diff --git a/lib/libc/compat-43/killpg.c b/lib/libc/compat-43/killpg.c
new file mode 100644
index 000000000000..a8e36ae2b795
--- /dev/null
+++ b/lib/libc/compat-43/killpg.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)killpg.c 8.1 (Berkeley) 6/2/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <signal.h>
+#include <errno.h>
+
+/*
+ * Backwards-compatible killpg().
+ */
+int
+killpg(pid_t pgid, int sig)
+{
+ if (pgid == 1) {
+ errno = ESRCH;
+ return (-1);
+ }
+ return (kill(-pgid, sig));
+}
diff --git a/lib/libc/compat-43/sethostid.c b/lib/libc/compat-43/sethostid.c
new file mode 100644
index 000000000000..95c833343ba9
--- /dev/null
+++ b/lib/libc/compat-43/sethostid.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)sethostid.c 8.1 (Berkeley) 6/2/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/sysctl.h>
+
+#include <unistd.h>
+
+void
+sethostid(long hostid)
+{
+ int mib[2];
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_HOSTID;
+ sysctl(mib, 2, NULL, NULL, &hostid, sizeof hostid);
+}
diff --git a/lib/libc/compat-43/setpgrp.c b/lib/libc/compat-43/setpgrp.c
new file mode 100644
index 000000000000..39713d2966eb
--- /dev/null
+++ b/lib/libc/compat-43/setpgrp.c
@@ -0,0 +1,43 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)setpgrp.c 8.1 (Berkeley) 6/2/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <unistd.h>
+
+int
+setpgrp(pid_t pid, pid_t pgid)
+{
+ return(setpgid(pid, pgid));
+}
diff --git a/lib/libc/compat-43/setrgid.c b/lib/libc/compat-43/setrgid.c
new file mode 100644
index 000000000000..f006c76b6993
--- /dev/null
+++ b/lib/libc/compat-43/setrgid.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)setrgid.c 8.1 (Berkeley) 6/2/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <unistd.h>
+
+int
+setrgid(gid_t rgid)
+{
+
+ return (setregid(rgid, -1));
+}
diff --git a/lib/libc/compat-43/setruid.3 b/lib/libc/compat-43/setruid.3
new file mode 100644
index 000000000000..22584cf0293a
--- /dev/null
+++ b/lib/libc/compat-43/setruid.3
@@ -0,0 +1,80 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)setruid.3 8.1 (Berkeley) 6/2/93
+.\" $FreeBSD$
+.\"
+.Dd June 2, 1993
+.Dt SETRUID 3
+.Os
+.Sh NAME
+.Nm setruid ,
+.Nm setrgid
+.Nd set user and group ID
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft int
+.Fn setruid "uid_t ruid"
+.Ft int
+.Fn setrgid "gid_t rgid"
+.Sh DESCRIPTION
+The
+.Fn setruid
+function
+.Pq Fn setrgid
+sets the real user ID (group ID) of the
+current process.
+.Sh RETURN VALUES
+.Rv -std
+.Sh COMPATIBILITY
+The use of these calls is not portable.
+Their use is discouraged; they will be removed in the future.
+.Sh ERRORS
+The functions fail if:
+.Bl -tag -width Er
+.It Bq Er EPERM
+The user is not the super user and the ID
+specified is not the real or effective ID.
+.El
+.Sh SEE ALSO
+.Xr getgid 2 ,
+.Xr getuid 2 ,
+.Xr setegid 2 ,
+.Xr seteuid 2 ,
+.Xr setgid 2 ,
+.Xr setuid 2
+.Sh HISTORY
+The
+.Fn setruid
+and
+.Fn setrgid
+syscalls appeared in
+.Bx 4.2
+and were dropped in
+.Bx 4.4 .
diff --git a/lib/libc/compat-43/setruid.c b/lib/libc/compat-43/setruid.c
new file mode 100644
index 000000000000..33c9db13da34
--- /dev/null
+++ b/lib/libc/compat-43/setruid.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)setruid.c 8.1 (Berkeley) 6/2/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <unistd.h>
+
+int
+setruid(uid_t ruid)
+{
+
+ return (setreuid(ruid, -1));
+}
diff --git a/lib/libc/compat-43/sigcompat.c b/lib/libc/compat-43/sigcompat.c
new file mode 100644
index 000000000000..08484765397f
--- /dev/null
+++ b/lib/libc/compat-43/sigcompat.c
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)sigcompat.c 8.1 (Berkeley) 6/2/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+
+int
+sigvec(int signo, struct sigvec *sv, struct sigvec *osv)
+{
+ struct sigaction sa, osa;
+ struct sigaction *sap, *osap;
+ int ret;
+
+ if (sv != NULL) {
+ sa.sa_handler = sv->sv_handler;
+ sa.sa_flags = sv->sv_flags ^ SV_INTERRUPT;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_mask.__bits[0] = sv->sv_mask;
+ sap = &sa;
+ } else
+ sap = NULL;
+ osap = osv != NULL ? &osa : NULL;
+ ret = __libc_sigaction(signo, sap, osap);
+ if (ret == 0 && osv != NULL) {
+ osv->sv_handler = osa.sa_handler;
+ osv->sv_flags = osa.sa_flags ^ SV_INTERRUPT;
+ osv->sv_mask = osa.sa_mask.__bits[0];
+ }
+ return (ret);
+}
+
+int
+sigsetmask(int mask)
+{
+ sigset_t set, oset;
+ int n;
+
+ sigemptyset(&set);
+ set.__bits[0] = mask;
+ n = __libc_sigprocmask(SIG_SETMASK, &set, &oset);
+ if (n)
+ return (n);
+ return (oset.__bits[0]);
+}
+
+int
+sigblock(int mask)
+{
+ sigset_t set, oset;
+ int n;
+
+ sigemptyset(&set);
+ set.__bits[0] = mask;
+ n = __libc_sigprocmask(SIG_BLOCK, &set, &oset);
+ if (n)
+ return (n);
+ return (oset.__bits[0]);
+}
+
+int
+sigpause(int mask)
+{
+ sigset_t set;
+
+ sigemptyset(&set);
+ set.__bits[0] = mask;
+ return (__libc_sigsuspend(&set));
+}
+
+int
+xsi_sigpause(int sig)
+{
+ sigset_t set;
+
+ if (__libc_sigprocmask(SIG_BLOCK, NULL, &set) == -1)
+ return (-1);
+ if (sigdelset(&set, sig) == -1)
+ return (-1);
+ return (__libc_sigsuspend(&set));
+}
+
+int
+sighold(int sig)
+{
+ sigset_t set;
+
+ sigemptyset(&set);
+ if (sigaddset(&set, sig) == -1)
+ return (-1);
+ return (__libc_sigprocmask(SIG_BLOCK, &set, NULL));
+}
+
+int
+sigignore(int sig)
+{
+ struct sigaction sa;
+
+ bzero(&sa, sizeof(sa));
+ sa.sa_handler = SIG_IGN;
+ return (__libc_sigaction(sig, &sa, NULL));
+}
+
+int
+sigrelse(int sig)
+{
+ sigset_t set;
+
+ sigemptyset(&set);
+ if (sigaddset(&set, sig) == -1)
+ return (-1);
+ return (__libc_sigprocmask(SIG_UNBLOCK, &set, NULL));
+}
+
+void
+(*sigset(int sig, void (*disp)(int)))(int)
+{
+ sigset_t set, pset;
+ struct sigaction sa, psa;
+
+ sigemptyset(&set);
+ if (sigaddset(&set, sig) == -1)
+ return (SIG_ERR);
+ if (__libc_sigprocmask(SIG_BLOCK, NULL, &pset) == -1)
+ return (SIG_ERR);
+ if ((__sighandler_t *)disp == SIG_HOLD) {
+ if (__libc_sigprocmask(SIG_BLOCK, &set, &pset) == -1)
+ return (SIG_ERR);
+ if (sigismember(&pset, sig))
+ return (SIG_HOLD);
+ else {
+ if (__libc_sigaction(sig, NULL, &psa) == -1)
+ return (SIG_ERR);
+ return (psa.sa_handler);
+ }
+ } else {
+ if (__libc_sigprocmask(SIG_UNBLOCK, &set, &pset) == -1)
+ return (SIG_ERR);
+ }
+
+ bzero(&sa, sizeof(sa));
+ sa.sa_handler = disp;
+ if (__libc_sigaction(sig, &sa, &psa) == -1)
+ return (SIG_ERR);
+ if (sigismember(&pset, sig))
+ return (SIG_HOLD);
+ else
+ return (psa.sa_handler);
+}
diff --git a/lib/libc/compat-43/sigpause.2 b/lib/libc/compat-43/sigpause.2
new file mode 100644
index 000000000000..4c24ab7c4c2c
--- /dev/null
+++ b/lib/libc/compat-43/sigpause.2
@@ -0,0 +1,243 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)sigpause.2 8.1 (Berkeley) 6/2/93
+.\" $FreeBSD$
+.\"
+.\" Part of the content of the man page was derived from
+.\" The Open Group Base Specifications Issue 7
+.\" IEEE Std 1003.1-2008
+.\"
+.Dd June 2, 1993
+.Dt SIGPAUSE 2
+.Os
+.Sh NAME
+.Nm sighold ,
+.Nm sigignore ,
+.Nm sigpause ,
+.Nm sigrelse ,
+.Nm sigset
+.Nd legacy interface for signal management
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In signal.h
+.Ft int
+.Fn sighold "int sig"
+.Ft int
+.Fn sigignore "int sig"
+.Ft int
+.Fn xsi_sigpause "int sigmask"
+.Ft int
+.Fn sigrelse "int sig"
+.Ft void (*)(int)
+.Fn sigset "int" "void (*disp)(int)"
+.Ft int
+.Fn sigpause "int sigmask"
+.Sh DESCRIPTION
+.Sy This interface is made obsolete by
+.Xr sigsuspend 2
+.Sy and
+.Xr sigaction 2 .
+.Pp
+The
+.Fn sigset
+function modifies signal dispositions.
+The
+.Fa sig
+argument specifies the signal, which may be any signal except
+.Dv SIGKILL
+and
+.Dv SIGSTOP .
+The
+.Fa disp
+argument specifies the signal's disposition,
+which may be
+.Dv SIG_DFL ,
+.Dv SIG_IGN ,
+or the address of a signal handler.
+If
+.Fn sigset
+is used, and
+.Fa disp
+is the address of a signal handler, the
+system adds
+.Fa sig
+to the signal mask of the calling process before executing the signal
+handler; when the signal handler returns, the system restores the
+signal mask of the calling process to its state prior to the delivery
+of the signal.
+In addition, if
+.Fn sigset
+is used, and
+.Fa disp
+is equal to
+.Dv SIG_HOLD ,
+.Fa sig
+is added to the signal
+mask of the calling process and
+.Fa sig 's
+disposition remains unchanged.
+If
+.Fn sigset
+is used, and
+.Fa disp
+is not equal to
+.Dv SIG_HOLD ,
+.Fa sig
+is removed from the signal mask of the calling process.
+.Pp
+The
+.Fn sighold
+function adds
+.Fa sig
+to the signal mask of the calling process.
+.Pp
+The
+.Fn sigrelse
+function removes
+.Fa sig
+from the signal mask of the calling process.
+.Pp
+The
+.Fn sigignore
+function sets the disposition of
+.Fa sig
+to
+.Dv SIG_IGN .
+.Pp
+The
+.Fn xsi_sigpause
+function removes
+.Fa sig
+from the signal mask of the calling process and suspend the calling process
+until a signal is received.
+The
+.Fn xsi_sigpause
+function restores the signal mask of the process to its original state before
+returning.
+.Pp
+The
+.Fn sigpause
+function
+assigns
+.Fa sigmask
+to the set of masked signals
+and then waits for a signal to arrive;
+on return the set of masked signals is restored.
+The
+.Fa sigmask
+argument
+is usually 0 to indicate that no
+signals are to be blocked.
+.Sh RETURN VALUES
+The
+.Fn sigpause
+and
+.Fn xsi_sigpause
+functions
+always terminate by being interrupted, returning -1 with
+.Va errno
+set to
+.Er EINTR .
+.Pp
+Upon successful completion,
+.Fn sigset
+returns
+.Dv SIG_HOLD
+if the signal had been blocked and the signal's previous disposition if
+it had not been blocked.
+Otherwise,
+.Dv SIG_ERR
+is returned and
+.Va errno
+set to indicate the error.
+.Pp
+For all other functions, upon successful completion, 0 is returned.
+Otherwise, -1 is returned and
+.Va errno
+is set to indicate the error:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa sig
+argument
+is not a valid signal number.
+.It Bq Er EINVAL
+For
+.Fn sigset
+and
+.Fn sigignore
+functions, an attempt was made to catch or ignore
+.Dv SIGKILL
+or
+.Dv SIGSTOP .
+.El
+.Sh SEE ALSO
+.Xr kill 2 ,
+.Xr sigaction 2 ,
+.Xr sigblock 2 ,
+.Xr sigprocmask 2 ,
+.Xr sigsuspend 2 ,
+.Xr sigvec 2
+.Sh STANDARDS
+The
+.Fn sigpause
+function is implemented for compatibility with historic
+.Bx 4.3
+applications.
+An incompatible interface by the same name, which used a single signal number
+rather than a mask, was present in
+.At V ,
+and was copied from there into the
+.Sy X/Open System Interfaces
+.Pq Tn XSI
+option of
+.St -p1003.1-2001 .
+.Fx
+implements it under the name
+.Fn xsi_sigpause .
+The
+.Fn sighold ,
+.Fn sigignore ,
+.Fn sigrelse
+and
+.Fn sigset
+functions are implemented for compatibility with
+.Sy System V
+and
+.Sy XSI
+interfaces.
+.Sh HISTORY
+The
+.Fn sigpause
+function appeared in
+.Bx 4.2
+and has been deprecated.
+All other functions appeared in
+.Fx 8.1
+and were deprecated before being implemented.
diff --git a/lib/libc/compat-43/sigsetmask.2 b/lib/libc/compat-43/sigsetmask.2
new file mode 100644
index 000000000000..8894a1e57092
--- /dev/null
+++ b/lib/libc/compat-43/sigsetmask.2
@@ -0,0 +1,103 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)sigsetmask.2 8.1 (Berkeley) 6/2/93
+.\" $FreeBSD$
+.\"
+.Dd June 2, 1993
+.Dt SIGSETMASK 2
+.Os
+.Sh NAME
+.Nm sigsetmask ,
+.Nm sigblock
+.Nd manipulate current signal mask
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In signal.h
+.Ft int
+.Fn sigsetmask "int mask"
+.Ft int
+.Fn sigblock "int mask"
+.Ft int
+.Fn sigmask "int signum"
+.Sh DESCRIPTION
+.Bf -symbolic
+This interface is made obsolete by:
+.Ef
+.Xr sigprocmask 2 .
+.Pp
+The
+.Fn sigsetmask
+function
+sets the current signal mask to the specified
+.Fa mask .
+Signals are blocked from delivery if the corresponding bit in
+.Fa mask
+is a 1.
+The
+.Fn sigblock
+function
+adds the signals in the specified
+.Fa mask
+to the current signal mask,
+rather than overwriting it as
+.Fn sigsetmask
+does.
+The macro
+.Fn sigmask
+is provided to construct the mask for a given
+.Fa signum .
+.Pp
+The system
+quietly disallows
+.Dv SIGKILL
+or
+.Dv SIGSTOP
+to be blocked.
+.Sh RETURN VALUES
+The
+.Fn sigblock
+and
+.Fn sigsetmask
+functions
+return the previous set of masked signals.
+.Sh SEE ALSO
+.Xr kill 2 ,
+.Xr sigaction 2 ,
+.Xr sigprocmask 2 ,
+.Xr sigsuspend 2 ,
+.Xr sigvec 2 ,
+.Xr sigsetops 3
+.Sh HISTORY
+The
+.Fn sigsetmask
+and
+.Fn sigblock
+functions first appeared in
+.Bx 4.2
+and have been deprecated.
diff --git a/lib/libc/compat-43/sigvec.2 b/lib/libc/compat-43/sigvec.2
new file mode 100644
index 000000000000..d15c0237d611
--- /dev/null
+++ b/lib/libc/compat-43/sigvec.2
@@ -0,0 +1,342 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)sigvec.2 8.2 (Berkeley) 4/19/94
+.\" $FreeBSD$
+.\"
+.Dd April 19, 1994
+.Dt SIGVEC 2
+.Os
+.Sh NAME
+.Nm sigvec
+.Nd software signal facilities
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In signal.h
+.Bd -literal
+struct sigvec {
+ void (*sv_handler)();
+ int sv_mask;
+ int sv_flags;
+};
+.Ed
+.Ft int
+.Fn sigvec "int sig" "struct sigvec *vec" "struct sigvec *ovec"
+.Sh DESCRIPTION
+.Bf -symbolic
+This interface is made obsolete by
+.Xr sigaction 2 .
+.Ef
+.Pp
+The system defines a set of signals that may be delivered to a process.
+Signal delivery resembles the occurrence of a hardware interrupt:
+the signal is blocked from further occurrence, the current process
+context is saved, and a new one is built.
+A process may specify a
+.Em handler
+to which a signal is delivered, or specify that a signal is to be
+.Em blocked
+or
+.Em ignored .
+A process may also specify that a default action is to be taken
+by the system when a signal occurs.
+Normally, signal handlers execute on the current stack
+of the process.
+This may be changed, on a per-handler basis,
+so that signals are taken on a special
+.Em "signal stack" .
+.Pp
+All signals have the same
+.Em priority .
+Signal routines execute with the signal that caused their
+invocation
+.Em blocked ,
+but other signals may yet occur.
+A global
+.Em "signal mask"
+defines the set of signals currently blocked from delivery
+to a process.
+The signal mask for a process is initialized
+from that of its parent (normally 0).
+It
+may be changed with a
+.Xr sigblock 2
+or
+.Xr sigsetmask 2
+call, or when a signal is delivered to the process.
+.Pp
+When a signal
+condition arises for a process, the signal is added to a set of
+signals pending for the process.
+If the signal is not currently
+.Em blocked
+by the process then it is delivered to the process.
+When a signal
+is delivered, the current state of the process is saved,
+a new signal mask is calculated (as described below),
+and the signal handler is invoked.
+The call to the handler
+is arranged so that if the signal handling routine returns
+normally the process will resume execution in the context
+from before the signal's delivery.
+If the process wishes to resume in a different context, then it
+must arrange to restore the previous context itself.
+.Pp
+When a signal is delivered to a process a new signal mask is
+installed for the duration of the process' signal handler
+(or until a
+.Xr sigblock 2
+or
+.Xr sigsetmask 2
+call is made).
+This mask is formed by taking the current signal mask,
+adding the signal to be delivered, and
+.Em or Ns 'ing
+in the signal mask associated with the handler to be invoked.
+.Pp
+The
+.Fn sigvec
+function
+assigns a handler for a specific signal.
+If
+.Fa vec
+is non-zero, it
+specifies a handler routine and mask
+to be used when delivering the specified signal.
+Further, if the
+.Dv SV_ONSTACK
+bit is set in
+.Fa sv_flags ,
+the system will deliver the signal to the process on a
+.Em "signal stack" ,
+specified with
+.Xr sigaltstack 2 .
+If
+.Fa ovec
+is non-zero, the previous handling information for the signal
+is returned to the user.
+.Pp
+The following is a list of all signals
+with names as in the include file
+.In signal.h :
+.Bl -column SIGVTALARMXX "create core imagexxx"
+.It Sy "NAME Default Action Description"
+.It Dv SIGHUP No " terminate process" " terminal line hangup"
+.It Dv SIGINT No " terminate process" " interrupt program"
+.It Dv SIGQUIT No " create core image" " quit program"
+.It Dv SIGILL No " create core image" " illegal instruction"
+.It Dv SIGTRAP No " create core image" " trace trap"
+.It Dv SIGABRT No " create core image" Ta Xr abort 3
+call (formerly
+.Dv SIGIOT )
+.It Dv SIGEMT No " create core image" " emulate instruction executed"
+.It Dv SIGFPE No " create core image" " floating-point exception"
+.It Dv SIGKILL No " terminate process" " kill program"
+.It Dv SIGBUS No " create core image" " bus error"
+.It Dv SIGSEGV No " create core image" " segmentation violation"
+.It Dv SIGSYS No " create core image" " non-existent system call invoked"
+.It Dv SIGPIPE No " terminate process" " write on a pipe with no reader"
+.It Dv SIGALRM No " terminate process" " real-time timer expired"
+.It Dv SIGTERM No " terminate process" " software termination signal"
+.It Dv SIGURG No " discard signal" " urgent condition present on socket"
+.It Dv SIGSTOP No " stop process" " stop (cannot be caught or ignored)"
+.It Dv SIGTSTP No " stop process" " stop signal generated from keyboard"
+.It Dv SIGCONT No " discard signal" " continue after stop"
+.It Dv SIGCHLD No " discard signal" " child status has changed"
+.It Dv SIGTTIN No " stop process" " background read attempted from control terminal"
+.It Dv SIGTTOU No " stop process" " background write attempted to control terminal"
+.It Dv SIGIO No " discard signal" Tn " I/O"
+is possible on a descriptor (see
+.Xr fcntl 2 )
+.It Dv SIGXCPU No " terminate process" " cpu time limit exceeded (see"
+.Xr setrlimit 2 )
+.It Dv SIGXFSZ No " terminate process" " file size limit exceeded (see"
+.Xr setrlimit 2 )
+.It Dv SIGVTALRM No " terminate process" " virtual time alarm (see"
+.Xr setitimer 2 )
+.It Dv SIGPROF No " terminate process" " profiling timer alarm (see"
+.Xr setitimer 2 )
+.It Dv SIGWINCH No " discard signal" " Window size change"
+.It Dv SIGINFO No " discard signal" " status request from keyboard"
+.It Dv SIGUSR1 No " terminate process" " User defined signal 1"
+.It Dv SIGUSR2 No " terminate process" " User defined signal 2"
+.El
+.Pp
+Once a signal handler is installed, it remains installed
+until another
+.Fn sigvec
+call is made, or an
+.Xr execve 2
+is performed.
+A signal-specific default action may be reset by
+setting
+.Fa sv_handler
+to
+.Dv SIG_DFL .
+The defaults are process termination, possibly with core dump;
+no action; stopping the process; or continuing the process.
+See the above signal list for each signal's default action.
+If
+.Fa sv_handler
+is
+.Dv SIG_IGN
+current and pending instances
+of the signal are ignored and discarded.
+.Pp
+If a signal is caught during the system calls listed below,
+the call is normally restarted.
+The call can be forced to terminate prematurely with an
+.Er EINTR
+error return by setting the
+.Dv SV_INTERRUPT
+bit in
+.Fa sv_flags .
+The affected system calls include
+.Xr read 2 ,
+.Xr write 2 ,
+.Xr sendto 2 ,
+.Xr recvfrom 2 ,
+.Xr sendmsg 2
+and
+.Xr recvmsg 2
+on a communications channel or a slow device (such as a terminal,
+but not a regular file)
+and during a
+.Xr wait 2
+or
+.Xr ioctl 2 .
+However, calls that have already committed are not restarted,
+but instead return a partial success (for example, a short read count).
+.Pp
+After a
+.Xr fork 2
+or
+.Xr vfork 2
+all signals, the signal mask, the signal stack,
+and the restart/interrupt flags are inherited by the child.
+.Pp
+The
+.Xr execve 2
+system call reinstates the default
+action for all signals which were caught and
+resets all signals to be caught on the user stack.
+Ignored signals remain ignored;
+the signal mask remains the same;
+signals that interrupt system calls continue to do so.
+.Sh NOTES
+The mask specified in
+.Fa vec
+is not allowed to block
+.Dv SIGKILL
+or
+.Dv SIGSTOP .
+This is done silently by the system.
+.Pp
+The
+.Dv SV_INTERRUPT
+flag is not available in
+.Bx 4.2 ,
+hence it should not be used if backward compatibility is needed.
+.Sh RETURN VALUES
+.Rv -std sigvec
+.Sh EXAMPLES
+On the
+.Tn VAX\-11
+The handler routine can be declared:
+.Bd -literal -offset indent
+void handler(sig, code, scp)
+int sig, code;
+struct sigcontext *scp;
+.Ed
+.Pp
+Here
+.Fa sig
+is the signal number, into which the hardware faults and traps are
+mapped as defined below.
+The
+.Fa code
+argument
+is either a constant
+as given below or, for compatibility mode faults, the code provided by
+the hardware (Compatibility mode faults are distinguished from the
+other
+.Dv SIGILL
+traps by having
+.Dv PSL_CM
+set in the psl).
+The
+.Fa scp
+argument
+is a pointer to the
+.Fa sigcontext
+structure (defined in
+.In signal.h ) ,
+used to restore the context from before the signal.
+.Sh ERRORS
+The
+.Fn sigvec
+function
+will fail and no new signal handler will be installed if one
+of the following occurs:
+.Bl -tag -width Er
+.It Bq Er EFAULT
+Either
+.Fa vec
+or
+.Fa ovec
+points to memory that is not a valid part of the process
+address space.
+.It Bq Er EINVAL
+The
+.Fa sig
+argument
+is not a valid signal number.
+.It Bq Er EINVAL
+An attempt is made to ignore or supply a handler for
+.Dv SIGKILL
+or
+.Dv SIGSTOP .
+.El
+.Sh SEE ALSO
+.Xr kill 1 ,
+.Xr kill 2 ,
+.Xr ptrace 2 ,
+.Xr sigaction 2 ,
+.Xr sigaltstack 2 ,
+.Xr sigblock 2 ,
+.Xr sigpause 2 ,
+.Xr sigprocmask 2 ,
+.Xr sigsetmask 2 ,
+.Xr sigsuspend 2 ,
+.Xr setjmp 3 ,
+.Xr siginterrupt 3 ,
+.Xr signal 3 ,
+.Xr sigsetops 3 ,
+.Xr tty 4
+.Sh BUGS
+This manual page is still confusing.
diff --git a/lib/libc/db/Makefile.inc b/lib/libc/db/Makefile.inc
new file mode 100644
index 000000000000..a8905ef02997
--- /dev/null
+++ b/lib/libc/db/Makefile.inc
@@ -0,0 +1,13 @@
+# from @(#)Makefile.inc 8.2 (Berkeley) 2/21/94
+# $FreeBSD$
+#
+CFLAGS+=-D__DBINTERFACE_PRIVATE
+
+.include "${LIBC_SRCTOP}/db/btree/Makefile.inc"
+.include "${LIBC_SRCTOP}/db/db/Makefile.inc"
+.include "${LIBC_SRCTOP}/db/hash/Makefile.inc"
+.include "${LIBC_SRCTOP}/db/man/Makefile.inc"
+.include "${LIBC_SRCTOP}/db/mpool/Makefile.inc"
+.include "${LIBC_SRCTOP}/db/recno/Makefile.inc"
+
+SYM_MAPS+=${LIBC_SRCTOP}/db/Symbol.map
diff --git a/lib/libc/db/README b/lib/libc/db/README
new file mode 100644
index 000000000000..1f9ae7240658
--- /dev/null
+++ b/lib/libc/db/README
@@ -0,0 +1,34 @@
+# @(#)README 8.27 (Berkeley) 9/1/94
+# $FreeBSD$
+
+This is version 1.85 of the Berkeley DB code.
+
+For information on compiling and installing this software, see the file
+PORT/README.
+
+Newer versions of this software will periodically be made available by
+anonymous ftp from ftp.cs.berkeley.edu. An archive in compressed format
+is in ucb/4bsd/db.tar.Z, or in gzip format in ucb/4bsd/db.tar.gz. If
+you'd like to receive announcements of future releases of this software,
+send email to the contact address below.
+
+Email questions may be addressed to Keith Bostic at bostic@cs.berkeley.edu.
+
+============================================
+Distribution contents:
+
+Makefile.inc Ignore this, it's the 4.4BSD subsystem Makefile.
+PORT The per OS/architecture directories to use to build
+ libdb.a, if you're not running 4.4BSD. See the file
+ PORT/README for more information.
+README This file.
+btree The B+tree routines.
+changelog List of changes, per version.
+db The dbopen(3) interface routine.
+docs Various USENIX papers, and the formatted manual pages.
+hash The extended linear hashing routines.
+man The unformatted manual pages.
+mpool The memory pool routines.
+recno The fixed/variable length record routines.
+test Test package.
+
diff --git a/lib/libc/db/Symbol.map b/lib/libc/db/Symbol.map
new file mode 100644
index 000000000000..225fd401cb57
--- /dev/null
+++ b/lib/libc/db/Symbol.map
@@ -0,0 +1,36 @@
+/*
+ * $FreeBSD$
+ */
+
+FBSD_1.0 {
+ dbopen;
+ dbm_open;
+ dbm_close;
+ dbm_fetch;
+ dbm_firstkey;
+ dbm_nextkey;
+ dbm_delete;
+ dbm_store;
+ dbm_error;
+ dbm_clearerr;
+ dbm_dirfno;
+ mpool_open;
+ mpool_filter;
+ mpool_get;
+ mpool_put;
+ mpool_close;
+ mpool_sync;
+ mpool_stat;
+};
+
+FBSD_1.1 {
+ mpool_new;
+ mpool_delete;
+};
+
+FBSDprivate_1.0 {
+ __bt_open;
+ __dbpanic;
+ __hash_open;
+ __rec_open;
+};
diff --git a/lib/libc/db/btree/Makefile.inc b/lib/libc/db/btree/Makefile.inc
new file mode 100644
index 000000000000..b6305738d9fd
--- /dev/null
+++ b/lib/libc/db/btree/Makefile.inc
@@ -0,0 +1,8 @@
+# from @(#)Makefile.inc 8.2 (Berkeley) 7/14/94
+# $FreeBSD$
+
+.PATH: ${LIBC_SRCTOP}/db/btree
+
+SRCS+= bt_close.c bt_conv.c bt_debug.c bt_delete.c bt_get.c bt_open.c \
+ bt_overflow.c bt_page.c bt_put.c bt_search.c bt_seq.c bt_split.c \
+ bt_utils.c
diff --git a/lib/libc/db/btree/bt_close.c b/lib/libc/db/btree/bt_close.c
new file mode 100644
index 000000000000..f1e7c8ddef06
--- /dev/null
+++ b/lib/libc/db/btree/bt_close.c
@@ -0,0 +1,179 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Mike Olson.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)bt_close.c 8.7 (Berkeley) 8/17/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/param.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+#include <db.h>
+#include "btree.h"
+
+static int bt_meta(BTREE *);
+
+/*
+ * BT_CLOSE -- Close a btree.
+ *
+ * Parameters:
+ * dbp: pointer to access method
+ *
+ * Returns:
+ * RET_ERROR, RET_SUCCESS
+ */
+int
+__bt_close(DB *dbp)
+{
+ BTREE *t;
+ int fd;
+
+ t = dbp->internal;
+
+ /* Toss any page pinned across calls. */
+ if (t->bt_pinned != NULL) {
+ mpool_put(t->bt_mp, t->bt_pinned, 0);
+ t->bt_pinned = NULL;
+ }
+
+ /* Sync the tree. */
+ if (__bt_sync(dbp, 0) == RET_ERROR)
+ return (RET_ERROR);
+
+ /* Close the memory pool. */
+ if (mpool_close(t->bt_mp) == RET_ERROR)
+ return (RET_ERROR);
+
+ /* Free random memory. */
+ if (t->bt_cursor.key.data != NULL) {
+ free(t->bt_cursor.key.data);
+ t->bt_cursor.key.size = 0;
+ t->bt_cursor.key.data = NULL;
+ }
+ if (t->bt_rkey.data) {
+ free(t->bt_rkey.data);
+ t->bt_rkey.size = 0;
+ t->bt_rkey.data = NULL;
+ }
+ if (t->bt_rdata.data) {
+ free(t->bt_rdata.data);
+ t->bt_rdata.size = 0;
+ t->bt_rdata.data = NULL;
+ }
+
+ fd = t->bt_fd;
+ free(t);
+ free(dbp);
+ return (_close(fd) ? RET_ERROR : RET_SUCCESS);
+}
+
+/*
+ * BT_SYNC -- sync the btree to disk.
+ *
+ * Parameters:
+ * dbp: pointer to access method
+ *
+ * Returns:
+ * RET_SUCCESS, RET_ERROR.
+ */
+int
+__bt_sync(const DB *dbp, u_int flags)
+{
+ BTREE *t;
+ int status;
+
+ t = dbp->internal;
+
+ /* Toss any page pinned across calls. */
+ if (t->bt_pinned != NULL) {
+ mpool_put(t->bt_mp, t->bt_pinned, 0);
+ t->bt_pinned = NULL;
+ }
+
+ /* Sync doesn't currently take any flags. */
+ if (flags != 0) {
+ errno = EINVAL;
+ return (RET_ERROR);
+ }
+
+ if (F_ISSET(t, B_INMEM | B_RDONLY) ||
+ !F_ISSET(t, B_MODIFIED | B_METADIRTY))
+ return (RET_SUCCESS);
+
+ if (F_ISSET(t, B_METADIRTY) && bt_meta(t) == RET_ERROR)
+ return (RET_ERROR);
+
+ if ((status = mpool_sync(t->bt_mp)) == RET_SUCCESS)
+ F_CLR(t, B_MODIFIED);
+
+ return (status);
+}
+
+/*
+ * BT_META -- write the tree meta data to disk.
+ *
+ * Parameters:
+ * t: tree
+ *
+ * Returns:
+ * RET_ERROR, RET_SUCCESS
+ */
+static int
+bt_meta(BTREE *t)
+{
+ BTMETA m;
+ void *p;
+
+ if ((p = mpool_get(t->bt_mp, P_META, 0)) == NULL)
+ return (RET_ERROR);
+
+ /* Fill in metadata. */
+ m.magic = BTREEMAGIC;
+ m.version = BTREEVERSION;
+ m.psize = t->bt_psize;
+ m.free = t->bt_free;
+ m.nrecs = t->bt_nrecs;
+ m.flags = F_ISSET(t, SAVEMETA);
+
+ memmove(p, &m, sizeof(BTMETA));
+ mpool_put(t->bt_mp, p, MPOOL_DIRTY);
+ return (RET_SUCCESS);
+}
diff --git a/lib/libc/db/btree/bt_conv.c b/lib/libc/db/btree/bt_conv.c
new file mode 100644
index 000000000000..ba4a38bf853c
--- /dev/null
+++ b/lib/libc/db/btree/bt_conv.c
@@ -0,0 +1,212 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Mike Olson.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)bt_conv.c 8.5 (Berkeley) 8/17/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+
+#include <stdio.h>
+
+#include <db.h>
+#include "btree.h"
+
+static void mswap(PAGE *);
+
+/*
+ * __BT_BPGIN, __BT_BPGOUT --
+ * Convert host-specific number layout to/from the host-independent
+ * format stored on disk.
+ *
+ * Parameters:
+ * t: tree
+ * pg: page number
+ * h: page to convert
+ */
+void
+__bt_pgin(void *t, pgno_t pg, void *pp)
+{
+ PAGE *h;
+ indx_t i, top;
+ u_char flags;
+ char *p;
+
+ if (!F_ISSET(((BTREE *)t), B_NEEDSWAP))
+ return;
+ if (pg == P_META) {
+ mswap(pp);
+ return;
+ }
+
+ h = pp;
+ M_32_SWAP(h->pgno);
+ M_32_SWAP(h->prevpg);
+ M_32_SWAP(h->nextpg);
+ M_32_SWAP(h->flags);
+ M_16_SWAP(h->lower);
+ M_16_SWAP(h->upper);
+
+ top = NEXTINDEX(h);
+ if ((h->flags & P_TYPE) == P_BINTERNAL)
+ for (i = 0; i < top; i++) {
+ M_16_SWAP(h->linp[i]);
+ p = (char *)GETBINTERNAL(h, i);
+ P_32_SWAP(p);
+ p += sizeof(u_int32_t);
+ P_32_SWAP(p);
+ p += sizeof(pgno_t);
+ if (*(u_char *)p & P_BIGKEY) {
+ p += sizeof(u_char);
+ P_32_SWAP(p);
+ p += sizeof(pgno_t);
+ P_32_SWAP(p);
+ }
+ }
+ else if ((h->flags & P_TYPE) == P_BLEAF)
+ for (i = 0; i < top; i++) {
+ M_16_SWAP(h->linp[i]);
+ p = (char *)GETBLEAF(h, i);
+ P_32_SWAP(p);
+ p += sizeof(u_int32_t);
+ P_32_SWAP(p);
+ p += sizeof(u_int32_t);
+ flags = *(u_char *)p;
+ if (flags & (P_BIGKEY | P_BIGDATA)) {
+ p += sizeof(u_char);
+ if (flags & P_BIGKEY) {
+ P_32_SWAP(p);
+ p += sizeof(pgno_t);
+ P_32_SWAP(p);
+ }
+ if (flags & P_BIGDATA) {
+ p += sizeof(u_int32_t);
+ P_32_SWAP(p);
+ p += sizeof(pgno_t);
+ P_32_SWAP(p);
+ }
+ }
+ }
+}
+
+void
+__bt_pgout(void *t, pgno_t pg, void *pp)
+{
+ PAGE *h;
+ indx_t i, top;
+ u_char flags;
+ char *p;
+
+ if (!F_ISSET(((BTREE *)t), B_NEEDSWAP))
+ return;
+ if (pg == P_META) {
+ mswap(pp);
+ return;
+ }
+
+ h = pp;
+ top = NEXTINDEX(h);
+ if ((h->flags & P_TYPE) == P_BINTERNAL)
+ for (i = 0; i < top; i++) {
+ p = (char *)GETBINTERNAL(h, i);
+ P_32_SWAP(p);
+ p += sizeof(u_int32_t);
+ P_32_SWAP(p);
+ p += sizeof(pgno_t);
+ if (*(u_char *)p & P_BIGKEY) {
+ p += sizeof(u_char);
+ P_32_SWAP(p);
+ p += sizeof(pgno_t);
+ P_32_SWAP(p);
+ }
+ M_16_SWAP(h->linp[i]);
+ }
+ else if ((h->flags & P_TYPE) == P_BLEAF)
+ for (i = 0; i < top; i++) {
+ p = (char *)GETBLEAF(h, i);
+ P_32_SWAP(p);
+ p += sizeof(u_int32_t);
+ P_32_SWAP(p);
+ p += sizeof(u_int32_t);
+ flags = *(u_char *)p;
+ if (flags & (P_BIGKEY | P_BIGDATA)) {
+ p += sizeof(u_char);
+ if (flags & P_BIGKEY) {
+ P_32_SWAP(p);
+ p += sizeof(pgno_t);
+ P_32_SWAP(p);
+ }
+ if (flags & P_BIGDATA) {
+ p += sizeof(u_int32_t);
+ P_32_SWAP(p);
+ p += sizeof(pgno_t);
+ P_32_SWAP(p);
+ }
+ }
+ M_16_SWAP(h->linp[i]);
+ }
+
+ M_32_SWAP(h->pgno);
+ M_32_SWAP(h->prevpg);
+ M_32_SWAP(h->nextpg);
+ M_32_SWAP(h->flags);
+ M_16_SWAP(h->lower);
+ M_16_SWAP(h->upper);
+}
+
+/*
+ * MSWAP -- Actually swap the bytes on the meta page.
+ *
+ * Parameters:
+ * p: page to convert
+ */
+static void
+mswap(PAGE *pg)
+{
+ char *p;
+
+ p = (char *)pg;
+ P_32_SWAP(p); /* magic */
+ p += sizeof(u_int32_t);
+ P_32_SWAP(p); /* version */
+ p += sizeof(u_int32_t);
+ P_32_SWAP(p); /* psize */
+ p += sizeof(u_int32_t);
+ P_32_SWAP(p); /* free */
+ p += sizeof(u_int32_t);
+ P_32_SWAP(p); /* nrecs */
+ p += sizeof(u_int32_t);
+ P_32_SWAP(p); /* flags */
+ p += sizeof(u_int32_t);
+}
diff --git a/lib/libc/db/btree/bt_debug.c b/lib/libc/db/btree/bt_debug.c
new file mode 100644
index 000000000000..dc8b83dbefa4
--- /dev/null
+++ b/lib/libc/db/btree/bt_debug.c
@@ -0,0 +1,316 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Mike Olson.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)bt_debug.c 8.5 (Berkeley) 8/17/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <db.h>
+#include "btree.h"
+
+#ifdef DEBUG
+/*
+ * BT_DUMP -- Dump the tree
+ *
+ * Parameters:
+ * dbp: pointer to the DB
+ */
+void
+__bt_dump(DB *dbp)
+{
+ BTREE *t;
+ PAGE *h;
+ pgno_t i;
+ char *sep;
+
+ t = dbp->internal;
+ (void)fprintf(stderr, "%s: pgsz %u",
+ F_ISSET(t, B_INMEM) ? "memory" : "disk", t->bt_psize);
+ if (F_ISSET(t, R_RECNO))
+ (void)fprintf(stderr, " keys %u", t->bt_nrecs);
+#undef X
+#define X(flag, name) \
+ if (F_ISSET(t, flag)) { \
+ (void)fprintf(stderr, "%s%s", sep, name); \
+ sep = ", "; \
+ }
+ if (t->flags != 0) {
+ sep = " flags (";
+ X(R_FIXLEN, "FIXLEN");
+ X(B_INMEM, "INMEM");
+ X(B_NODUPS, "NODUPS");
+ X(B_RDONLY, "RDONLY");
+ X(R_RECNO, "RECNO");
+ X(B_METADIRTY,"METADIRTY");
+ (void)fprintf(stderr, ")\n");
+ }
+#undef X
+
+ for (i = P_ROOT;
+ (h = mpool_get(t->bt_mp, i, MPOOL_IGNOREPIN)) != NULL; ++i)
+ __bt_dpage(h);
+}
+
+/*
+ * BT_DMPAGE -- Dump the meta page
+ *
+ * Parameters:
+ * h: pointer to the PAGE
+ */
+void
+__bt_dmpage(PAGE *h)
+{
+ BTMETA *m;
+ char *sep;
+
+ m = (BTMETA *)h;
+ (void)fprintf(stderr, "magic %x\n", m->magic);
+ (void)fprintf(stderr, "version %u\n", m->version);
+ (void)fprintf(stderr, "psize %u\n", m->psize);
+ (void)fprintf(stderr, "free %u\n", m->free);
+ (void)fprintf(stderr, "nrecs %u\n", m->nrecs);
+ (void)fprintf(stderr, "flags %u", m->flags);
+#undef X
+#define X(flag, name) \
+ if (m->flags & flag) { \
+ (void)fprintf(stderr, "%s%s", sep, name); \
+ sep = ", "; \
+ }
+ if (m->flags) {
+ sep = " (";
+ X(B_NODUPS, "NODUPS");
+ X(R_RECNO, "RECNO");
+ (void)fprintf(stderr, ")");
+ }
+}
+
+/*
+ * BT_DNPAGE -- Dump the page
+ *
+ * Parameters:
+ * n: page number to dump.
+ */
+void
+__bt_dnpage(DB *dbp, pgno_t pgno)
+{
+ BTREE *t;
+ PAGE *h;
+
+ t = dbp->internal;
+ if ((h = mpool_get(t->bt_mp, pgno, MPOOL_IGNOREPIN)) != NULL)
+ __bt_dpage(h);
+}
+
+/*
+ * BT_DPAGE -- Dump the page
+ *
+ * Parameters:
+ * h: pointer to the PAGE
+ */
+void
+__bt_dpage(PAGE *h)
+{
+ BINTERNAL *bi;
+ BLEAF *bl;
+ RINTERNAL *ri;
+ RLEAF *rl;
+ indx_t cur, top;
+ char *sep;
+
+ (void)fprintf(stderr, " page %u: (", h->pgno);
+#undef X
+#define X(flag, name) \
+ if (h->flags & flag) { \
+ (void)fprintf(stderr, "%s%s", sep, name); \
+ sep = ", "; \
+ }
+ sep = "";
+ X(P_BINTERNAL, "BINTERNAL") /* types */
+ X(P_BLEAF, "BLEAF")
+ X(P_RINTERNAL, "RINTERNAL") /* types */
+ X(P_RLEAF, "RLEAF")
+ X(P_OVERFLOW, "OVERFLOW")
+ X(P_PRESERVE, "PRESERVE");
+ (void)fprintf(stderr, ")\n");
+#undef X
+
+ (void)fprintf(stderr, "\tprev %2u next %2u", h->prevpg, h->nextpg);
+ if (h->flags & P_OVERFLOW)
+ return;
+
+ top = NEXTINDEX(h);
+ (void)fprintf(stderr, " lower %3d upper %3d nextind %d\n",
+ h->lower, h->upper, top);
+ for (cur = 0; cur < top; cur++) {
+ (void)fprintf(stderr, "\t[%03d] %4d ", cur, h->linp[cur]);
+ switch (h->flags & P_TYPE) {
+ case P_BINTERNAL:
+ bi = GETBINTERNAL(h, cur);
+ (void)fprintf(stderr,
+ "size %03d pgno %03d", bi->ksize, bi->pgno);
+ if (bi->flags & P_BIGKEY)
+ (void)fprintf(stderr, " (indirect)");
+ else if (bi->ksize)
+ (void)fprintf(stderr,
+ " {%.*s}", (int)bi->ksize, bi->bytes);
+ break;
+ case P_RINTERNAL:
+ ri = GETRINTERNAL(h, cur);
+ (void)fprintf(stderr, "entries %03d pgno %03d",
+ ri->nrecs, ri->pgno);
+ break;
+ case P_BLEAF:
+ bl = GETBLEAF(h, cur);
+ if (bl->flags & P_BIGKEY)
+ (void)fprintf(stderr,
+ "big key page %u size %u/",
+ *(pgno_t *)bl->bytes,
+ *(u_int32_t *)(bl->bytes + sizeof(pgno_t)));
+ else if (bl->ksize)
+ (void)fprintf(stderr, "%.*s/",
+ bl->ksize, bl->bytes);
+ if (bl->flags & P_BIGDATA)
+ (void)fprintf(stderr,
+ "big data page %u size %u",
+ *(pgno_t *)(bl->bytes + bl->ksize),
+ *(u_int32_t *)(bl->bytes + bl->ksize +
+ sizeof(pgno_t)));
+ else if (bl->dsize)
+ (void)fprintf(stderr, "%.*s",
+ (int)bl->dsize, bl->bytes + bl->ksize);
+ break;
+ case P_RLEAF:
+ rl = GETRLEAF(h, cur);
+ if (rl->flags & P_BIGDATA)
+ (void)fprintf(stderr,
+ "big data page %u size %u",
+ *(pgno_t *)rl->bytes,
+ *(u_int32_t *)(rl->bytes + sizeof(pgno_t)));
+ else if (rl->dsize)
+ (void)fprintf(stderr,
+ "%.*s", (int)rl->dsize, rl->bytes);
+ break;
+ }
+ (void)fprintf(stderr, "\n");
+ }
+}
+#endif
+
+#ifdef STATISTICS
+/*
+ * BT_STAT -- Gather/print the tree statistics
+ *
+ * Parameters:
+ * dbp: pointer to the DB
+ */
+void
+__bt_stat(DB *dbp)
+{
+ extern u_long bt_cache_hit, bt_cache_miss, bt_pfxsaved, bt_rootsplit;
+ extern u_long bt_sortsplit, bt_split;
+ BTREE *t;
+ PAGE *h;
+ pgno_t i, pcont, pinternal, pleaf;
+ u_long ifree, lfree, nkeys;
+ int levels;
+
+ t = dbp->internal;
+ pcont = pinternal = pleaf = 0;
+ nkeys = ifree = lfree = 0;
+ for (i = P_ROOT;
+ (h = mpool_get(t->bt_mp, i, MPOOL_IGNOREPIN)) != NULL; ++i)
+ switch (h->flags & P_TYPE) {
+ case P_BINTERNAL:
+ case P_RINTERNAL:
+ ++pinternal;
+ ifree += h->upper - h->lower;
+ break;
+ case P_BLEAF:
+ case P_RLEAF:
+ ++pleaf;
+ lfree += h->upper - h->lower;
+ nkeys += NEXTINDEX(h);
+ break;
+ case P_OVERFLOW:
+ ++pcont;
+ break;
+ }
+
+ /* Count the levels of the tree. */
+ for (i = P_ROOT, levels = 0 ;; ++levels) {
+ h = mpool_get(t->bt_mp, i, MPOOL_IGNOREPIN);
+ if (h->flags & (P_BLEAF|P_RLEAF)) {
+ if (levels == 0)
+ levels = 1;
+ break;
+ }
+ i = F_ISSET(t, R_RECNO) ?
+ GETRINTERNAL(h, 0)->pgno :
+ GETBINTERNAL(h, 0)->pgno;
+ }
+
+ (void)fprintf(stderr, "%d level%s with %lu keys",
+ levels, levels == 1 ? "" : "s", nkeys);
+ if (F_ISSET(t, R_RECNO))
+ (void)fprintf(stderr, " (%u header count)", t->bt_nrecs);
+ (void)fprintf(stderr,
+ "\n%u pages (leaf %u, internal %u, overflow %u)\n",
+ pinternal + pleaf + pcont, pleaf, pinternal, pcont);
+ (void)fprintf(stderr, "%lu cache hits, %lu cache misses\n",
+ bt_cache_hit, bt_cache_miss);
+ (void)fprintf(stderr, "%lu splits (%lu root splits, %lu sort splits)\n",
+ bt_split, bt_rootsplit, bt_sortsplit);
+ pleaf *= t->bt_psize - BTDATAOFF;
+ if (pleaf)
+ (void)fprintf(stderr,
+ "%.0f%% leaf fill (%lu bytes used, %lu bytes free)\n",
+ ((double)(pleaf - lfree) / pleaf) * 100,
+ pleaf - lfree, lfree);
+ pinternal *= t->bt_psize - BTDATAOFF;
+ if (pinternal)
+ (void)fprintf(stderr,
+ "%.0f%% internal fill (%lu bytes used, %lu bytes free\n",
+ ((double)(pinternal - ifree) / pinternal) * 100,
+ pinternal - ifree, ifree);
+ if (bt_pfxsaved)
+ (void)fprintf(stderr, "prefix checking removed %lu bytes.\n",
+ bt_pfxsaved);
+}
+#endif
diff --git a/lib/libc/db/btree/bt_delete.c b/lib/libc/db/btree/bt_delete.c
new file mode 100644
index 000000000000..aa191b692291
--- /dev/null
+++ b/lib/libc/db/btree/bt_delete.c
@@ -0,0 +1,635 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Mike Olson.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)bt_delete.c 8.13 (Berkeley) 7/28/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <db.h>
+#include "btree.h"
+
+static int __bt_bdelete(BTREE *, const DBT *);
+static int __bt_curdel(BTREE *, const DBT *, PAGE *, u_int);
+static int __bt_pdelete(BTREE *, PAGE *);
+static int __bt_relink(BTREE *, PAGE *);
+static int __bt_stkacq(BTREE *, PAGE **, CURSOR *);
+
+/*
+ * __bt_delete
+ * Delete the item(s) referenced by a key.
+ *
+ * Return RET_SPECIAL if the key is not found.
+ */
+int
+__bt_delete(const DB *dbp, const DBT *key, u_int flags)
+{
+ BTREE *t;
+ CURSOR *c;
+ PAGE *h;
+ int status;
+
+ t = dbp->internal;
+
+ /* Toss any page pinned across calls. */
+ if (t->bt_pinned != NULL) {
+ mpool_put(t->bt_mp, t->bt_pinned, 0);
+ t->bt_pinned = NULL;
+ }
+
+ /* Check for change to a read-only tree. */
+ if (F_ISSET(t, B_RDONLY)) {
+ errno = EPERM;
+ return (RET_ERROR);
+ }
+
+ switch (flags) {
+ case 0:
+ status = __bt_bdelete(t, key);
+ break;
+ case R_CURSOR:
+ /*
+ * If flags is R_CURSOR, delete the cursor. Must already
+ * have started a scan and not have already deleted it.
+ */
+ c = &t->bt_cursor;
+ if (F_ISSET(c, CURS_INIT)) {
+ if (F_ISSET(c, CURS_ACQUIRE | CURS_AFTER | CURS_BEFORE))
+ return (RET_SPECIAL);
+ if ((h = mpool_get(t->bt_mp, c->pg.pgno, 0)) == NULL)
+ return (RET_ERROR);
+
+ /*
+ * If the page is about to be emptied, we'll need to
+ * delete it, which means we have to acquire a stack.
+ */
+ if (NEXTINDEX(h) == 1)
+ if (__bt_stkacq(t, &h, &t->bt_cursor))
+ return (RET_ERROR);
+
+ status = __bt_dleaf(t, NULL, h, c->pg.index);
+
+ if (NEXTINDEX(h) == 0 && status == RET_SUCCESS) {
+ if (__bt_pdelete(t, h))
+ return (RET_ERROR);
+ } else
+ mpool_put(t->bt_mp,
+ h, status == RET_SUCCESS ? MPOOL_DIRTY : 0);
+ break;
+ }
+ /* FALLTHROUGH */
+ default:
+ errno = EINVAL;
+ return (RET_ERROR);
+ }
+ if (status == RET_SUCCESS)
+ F_SET(t, B_MODIFIED);
+ return (status);
+}
+
+/*
+ * __bt_stkacq --
+ * Acquire a stack so we can delete a cursor entry.
+ *
+ * Parameters:
+ * t: tree
+ * hp: pointer to current, pinned PAGE pointer
+ * c: pointer to the cursor
+ *
+ * Returns:
+ * 0 on success, 1 on failure
+ */
+static int
+__bt_stkacq(BTREE *t, PAGE **hp, CURSOR *c)
+{
+ BINTERNAL *bi;
+ EPG *e;
+ EPGNO *parent;
+ PAGE *h;
+ indx_t idx;
+ pgno_t pgno;
+ recno_t nextpg, prevpg;
+ int exact, level;
+
+ /*
+ * Find the first occurrence of the key in the tree. Toss the
+ * currently locked page so we don't hit an already-locked page.
+ */
+ h = *hp;
+ mpool_put(t->bt_mp, h, 0);
+ if ((e = __bt_search(t, &c->key, &exact)) == NULL)
+ return (1);
+ h = e->page;
+
+ /* See if we got it in one shot. */
+ if (h->pgno == c->pg.pgno)
+ goto ret;
+
+ /*
+ * Move right, looking for the page. At each move we have to move
+ * up the stack until we don't have to move to the next page. If
+ * we have to change pages at an internal level, we have to fix the
+ * stack back up.
+ */
+ while (h->pgno != c->pg.pgno) {
+ if ((nextpg = h->nextpg) == P_INVALID)
+ break;
+ mpool_put(t->bt_mp, h, 0);
+
+ /* Move up the stack. */
+ for (level = 0; (parent = BT_POP(t)) != NULL; ++level) {
+ /* Get the parent page. */
+ if ((h = mpool_get(t->bt_mp, parent->pgno, 0)) == NULL)
+ return (1);
+
+ /* Move to the next index. */
+ if (parent->index != NEXTINDEX(h) - 1) {
+ idx = parent->index + 1;
+ BT_PUSH(t, h->pgno, idx);
+ break;
+ }
+ mpool_put(t->bt_mp, h, 0);
+ }
+
+ /* Restore the stack. */
+ while (level--) {
+ /* Push the next level down onto the stack. */
+ bi = GETBINTERNAL(h, idx);
+ pgno = bi->pgno;
+ BT_PUSH(t, pgno, 0);
+
+ /* Lose the currently pinned page. */
+ mpool_put(t->bt_mp, h, 0);
+
+ /* Get the next level down. */
+ if ((h = mpool_get(t->bt_mp, pgno, 0)) == NULL)
+ return (1);
+ idx = 0;
+ }
+ mpool_put(t->bt_mp, h, 0);
+ if ((h = mpool_get(t->bt_mp, nextpg, 0)) == NULL)
+ return (1);
+ }
+
+ if (h->pgno == c->pg.pgno)
+ goto ret;
+
+ /* Reacquire the original stack. */
+ mpool_put(t->bt_mp, h, 0);
+ if ((e = __bt_search(t, &c->key, &exact)) == NULL)
+ return (1);
+ h = e->page;
+
+ /*
+ * Move left, looking for the page. At each move we have to move
+ * up the stack until we don't have to change pages to move to the
+ * next page. If we have to change pages at an internal level, we
+ * have to fix the stack back up.
+ */
+ while (h->pgno != c->pg.pgno) {
+ if ((prevpg = h->prevpg) == P_INVALID)
+ break;
+ mpool_put(t->bt_mp, h, 0);
+
+ /* Move up the stack. */
+ for (level = 0; (parent = BT_POP(t)) != NULL; ++level) {
+ /* Get the parent page. */
+ if ((h = mpool_get(t->bt_mp, parent->pgno, 0)) == NULL)
+ return (1);
+
+ /* Move to the next index. */
+ if (parent->index != 0) {
+ idx = parent->index - 1;
+ BT_PUSH(t, h->pgno, idx);
+ break;
+ }
+ mpool_put(t->bt_mp, h, 0);
+ }
+
+ /* Restore the stack. */
+ while (level--) {
+ /* Push the next level down onto the stack. */
+ bi = GETBINTERNAL(h, idx);
+ pgno = bi->pgno;
+
+ /* Lose the currently pinned page. */
+ mpool_put(t->bt_mp, h, 0);
+
+ /* Get the next level down. */
+ if ((h = mpool_get(t->bt_mp, pgno, 0)) == NULL)
+ return (1);
+
+ idx = NEXTINDEX(h) - 1;
+ BT_PUSH(t, pgno, idx);
+ }
+ mpool_put(t->bt_mp, h, 0);
+ if ((h = mpool_get(t->bt_mp, prevpg, 0)) == NULL)
+ return (1);
+ }
+
+
+ret: mpool_put(t->bt_mp, h, 0);
+ return ((*hp = mpool_get(t->bt_mp, c->pg.pgno, 0)) == NULL);
+}
+
+/*
+ * __bt_bdelete --
+ * Delete all key/data pairs matching the specified key.
+ *
+ * Parameters:
+ * t: tree
+ * key: key to delete
+ *
+ * Returns:
+ * RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key not found.
+ */
+static int
+__bt_bdelete(BTREE *t, const DBT *key)
+{
+ EPG *e;
+ PAGE *h;
+ int deleted, exact, redo;
+
+ deleted = 0;
+
+ /* Find any matching record; __bt_search pins the page. */
+loop: if ((e = __bt_search(t, key, &exact)) == NULL)
+ return (deleted ? RET_SUCCESS : RET_ERROR);
+ if (!exact) {
+ mpool_put(t->bt_mp, e->page, 0);
+ return (deleted ? RET_SUCCESS : RET_SPECIAL);
+ }
+
+ /*
+ * Delete forward, then delete backward, from the found key. If
+ * there are duplicates and we reach either side of the page, do
+ * the key search again, so that we get them all.
+ */
+ redo = 0;
+ h = e->page;
+ do {
+ if (__bt_dleaf(t, key, h, e->index)) {
+ mpool_put(t->bt_mp, h, 0);
+ return (RET_ERROR);
+ }
+ if (F_ISSET(t, B_NODUPS)) {
+ if (NEXTINDEX(h) == 0) {
+ if (__bt_pdelete(t, h))
+ return (RET_ERROR);
+ } else
+ mpool_put(t->bt_mp, h, MPOOL_DIRTY);
+ return (RET_SUCCESS);
+ }
+ deleted = 1;
+ } while (e->index < NEXTINDEX(h) && __bt_cmp(t, key, e) == 0);
+
+ /* Check for right-hand edge of the page. */
+ if (e->index == NEXTINDEX(h))
+ redo = 1;
+
+ /* Delete from the key to the beginning of the page. */
+ while (e->index-- > 0) {
+ if (__bt_cmp(t, key, e) != 0)
+ break;
+ if (__bt_dleaf(t, key, h, e->index) == RET_ERROR) {
+ mpool_put(t->bt_mp, h, 0);
+ return (RET_ERROR);
+ }
+ if (e->index == 0)
+ redo = 1;
+ }
+
+ /* Check for an empty page. */
+ if (NEXTINDEX(h) == 0) {
+ if (__bt_pdelete(t, h))
+ return (RET_ERROR);
+ goto loop;
+ }
+
+ /* Put the page. */
+ mpool_put(t->bt_mp, h, MPOOL_DIRTY);
+
+ if (redo)
+ goto loop;
+ return (RET_SUCCESS);
+}
+
+/*
+ * __bt_pdelete --
+ * Delete a single page from the tree.
+ *
+ * Parameters:
+ * t: tree
+ * h: leaf page
+ *
+ * Returns:
+ * RET_SUCCESS, RET_ERROR.
+ *
+ * Side-effects:
+ * mpool_put's the page
+ */
+static int
+__bt_pdelete(BTREE *t, PAGE *h)
+{
+ BINTERNAL *bi;
+ PAGE *pg;
+ EPGNO *parent;
+ indx_t cnt, idx, *ip, offset;
+ u_int32_t nksize;
+ char *from;
+
+ /*
+ * Walk the parent page stack -- a LIFO stack of the pages that were
+ * traversed when we searched for the page where the delete occurred.
+ * Each stack entry is a page number and a page index offset. The
+ * offset is for the page traversed on the search. We've just deleted
+ * a page, so we have to delete the key from the parent page.
+ *
+ * If the delete from the parent page makes it empty, this process may
+ * continue all the way up the tree. We stop if we reach the root page
+ * (which is never deleted, it's just not worth the effort) or if the
+ * delete does not empty the page.
+ */
+ while ((parent = BT_POP(t)) != NULL) {
+ /* Get the parent page. */
+ if ((pg = mpool_get(t->bt_mp, parent->pgno, 0)) == NULL)
+ return (RET_ERROR);
+
+ idx = parent->index;
+ bi = GETBINTERNAL(pg, idx);
+
+ /* Free any overflow pages. */
+ if (bi->flags & P_BIGKEY &&
+ __ovfl_delete(t, bi->bytes) == RET_ERROR) {
+ mpool_put(t->bt_mp, pg, 0);
+ return (RET_ERROR);
+ }
+
+ /*
+ * Free the parent if it has only the one key and it's not the
+ * root page. If it's the rootpage, turn it back into an empty
+ * leaf page.
+ */
+ if (NEXTINDEX(pg) == 1) {
+ if (pg->pgno == P_ROOT) {
+ pg->lower = BTDATAOFF;
+ pg->upper = t->bt_psize;
+ pg->flags = P_BLEAF;
+ } else {
+ if (__bt_relink(t, pg) || __bt_free(t, pg))
+ return (RET_ERROR);
+ continue;
+ }
+ } else {
+ /* Pack remaining key items at the end of the page. */
+ nksize = NBINTERNAL(bi->ksize);
+ from = (char *)pg + pg->upper;
+ memmove(from + nksize, from, (char *)bi - from);
+ pg->upper += nksize;
+
+ /* Adjust indices' offsets, shift the indices down. */
+ offset = pg->linp[idx];
+ for (cnt = idx, ip = &pg->linp[0]; cnt--; ++ip)
+ if (ip[0] < offset)
+ ip[0] += nksize;
+ for (cnt = NEXTINDEX(pg) - idx; --cnt; ++ip)
+ ip[0] = ip[1] < offset ? ip[1] + nksize : ip[1];
+ pg->lower -= sizeof(indx_t);
+ }
+
+ mpool_put(t->bt_mp, pg, MPOOL_DIRTY);
+ break;
+ }
+
+ /* Free the leaf page, as long as it wasn't the root. */
+ if (h->pgno == P_ROOT) {
+ mpool_put(t->bt_mp, h, MPOOL_DIRTY);
+ return (RET_SUCCESS);
+ }
+ return (__bt_relink(t, h) || __bt_free(t, h));
+}
+
+/*
+ * __bt_dleaf --
+ * Delete a single record from a leaf page.
+ *
+ * Parameters:
+ * t: tree
+ * key: referenced key
+ * h: page
+ * idx: index on page to delete
+ *
+ * Returns:
+ * RET_SUCCESS, RET_ERROR.
+ */
+int
+__bt_dleaf(BTREE *t, const DBT *key, PAGE *h, u_int idx)
+{
+ BLEAF *bl;
+ indx_t cnt, *ip, offset;
+ u_int32_t nbytes;
+ void *to;
+ char *from;
+
+ /* If this record is referenced by the cursor, delete the cursor. */
+ if (F_ISSET(&t->bt_cursor, CURS_INIT) &&
+ !F_ISSET(&t->bt_cursor, CURS_ACQUIRE) &&
+ t->bt_cursor.pg.pgno == h->pgno && t->bt_cursor.pg.index == idx &&
+ __bt_curdel(t, key, h, idx))
+ return (RET_ERROR);
+
+ /* If the entry uses overflow pages, make them available for reuse. */
+ to = bl = GETBLEAF(h, idx);
+ if (bl->flags & P_BIGKEY && __ovfl_delete(t, bl->bytes) == RET_ERROR)
+ return (RET_ERROR);
+ if (bl->flags & P_BIGDATA &&
+ __ovfl_delete(t, bl->bytes + bl->ksize) == RET_ERROR)
+ return (RET_ERROR);
+
+ /* Pack the remaining key/data items at the end of the page. */
+ nbytes = NBLEAF(bl);
+ from = (char *)h + h->upper;
+ memmove(from + nbytes, from, (char *)to - from);
+ h->upper += nbytes;
+
+ /* Adjust the indices' offsets, shift the indices down. */
+ offset = h->linp[idx];
+ for (cnt = idx, ip = &h->linp[0]; cnt--; ++ip)
+ if (ip[0] < offset)
+ ip[0] += nbytes;
+ for (cnt = NEXTINDEX(h) - idx; --cnt; ++ip)
+ ip[0] = ip[1] < offset ? ip[1] + nbytes : ip[1];
+ h->lower -= sizeof(indx_t);
+
+ /* If the cursor is on this page, adjust it as necessary. */
+ if (F_ISSET(&t->bt_cursor, CURS_INIT) &&
+ !F_ISSET(&t->bt_cursor, CURS_ACQUIRE) &&
+ t->bt_cursor.pg.pgno == h->pgno && t->bt_cursor.pg.index > idx)
+ --t->bt_cursor.pg.index;
+
+ return (RET_SUCCESS);
+}
+
+/*
+ * __bt_curdel --
+ * Delete the cursor.
+ *
+ * Parameters:
+ * t: tree
+ * key: referenced key (or NULL)
+ * h: page
+ * idx: index on page to delete
+ *
+ * Returns:
+ * RET_SUCCESS, RET_ERROR.
+ */
+static int
+__bt_curdel(BTREE *t, const DBT *key, PAGE *h, u_int idx)
+{
+ CURSOR *c;
+ EPG e;
+ PAGE *pg;
+ int curcopy, status;
+
+ /*
+ * If there are duplicates, move forward or backward to one.
+ * Otherwise, copy the key into the cursor area.
+ */
+ c = &t->bt_cursor;
+ F_CLR(c, CURS_AFTER | CURS_BEFORE | CURS_ACQUIRE);
+
+ curcopy = 0;
+ if (!F_ISSET(t, B_NODUPS)) {
+ /*
+ * We're going to have to do comparisons. If we weren't
+ * provided a copy of the key, i.e. the user is deleting
+ * the current cursor position, get one.
+ */
+ if (key == NULL) {
+ e.page = h;
+ e.index = idx;
+ if ((status = __bt_ret(t, &e,
+ &c->key, &c->key, NULL, NULL, 1)) != RET_SUCCESS)
+ return (status);
+ curcopy = 1;
+ key = &c->key;
+ }
+ /* Check previous key, if not at the beginning of the page. */
+ if (idx > 0) {
+ e.page = h;
+ e.index = idx - 1;
+ if (__bt_cmp(t, key, &e) == 0) {
+ F_SET(c, CURS_BEFORE);
+ goto dup2;
+ }
+ }
+ /* Check next key, if not at the end of the page. */
+ if (idx < NEXTINDEX(h) - 1) {
+ e.page = h;
+ e.index = idx + 1;
+ if (__bt_cmp(t, key, &e) == 0) {
+ F_SET(c, CURS_AFTER);
+ goto dup2;
+ }
+ }
+ /* Check previous key if at the beginning of the page. */
+ if (idx == 0 && h->prevpg != P_INVALID) {
+ if ((pg = mpool_get(t->bt_mp, h->prevpg, 0)) == NULL)
+ return (RET_ERROR);
+ e.page = pg;
+ e.index = NEXTINDEX(pg) - 1;
+ if (__bt_cmp(t, key, &e) == 0) {
+ F_SET(c, CURS_BEFORE);
+ goto dup1;
+ }
+ mpool_put(t->bt_mp, pg, 0);
+ }
+ /* Check next key if at the end of the page. */
+ if (idx == NEXTINDEX(h) - 1 && h->nextpg != P_INVALID) {
+ if ((pg = mpool_get(t->bt_mp, h->nextpg, 0)) == NULL)
+ return (RET_ERROR);
+ e.page = pg;
+ e.index = 0;
+ if (__bt_cmp(t, key, &e) == 0) {
+ F_SET(c, CURS_AFTER);
+dup1: mpool_put(t->bt_mp, pg, 0);
+dup2: c->pg.pgno = e.page->pgno;
+ c->pg.index = e.index;
+ return (RET_SUCCESS);
+ }
+ mpool_put(t->bt_mp, pg, 0);
+ }
+ }
+ e.page = h;
+ e.index = idx;
+ if (curcopy || (status =
+ __bt_ret(t, &e, &c->key, &c->key, NULL, NULL, 1)) == RET_SUCCESS) {
+ F_SET(c, CURS_ACQUIRE);
+ return (RET_SUCCESS);
+ }
+ return (status);
+}
+
+/*
+ * __bt_relink --
+ * Link around a deleted page.
+ *
+ * Parameters:
+ * t: tree
+ * h: page to be deleted
+ */
+static int
+__bt_relink(BTREE *t, PAGE *h)
+{
+ PAGE *pg;
+
+ if (h->nextpg != P_INVALID) {
+ if ((pg = mpool_get(t->bt_mp, h->nextpg, 0)) == NULL)
+ return (RET_ERROR);
+ pg->prevpg = h->prevpg;
+ mpool_put(t->bt_mp, pg, MPOOL_DIRTY);
+ }
+ if (h->prevpg != P_INVALID) {
+ if ((pg = mpool_get(t->bt_mp, h->prevpg, 0)) == NULL)
+ return (RET_ERROR);
+ pg->nextpg = h->nextpg;
+ mpool_put(t->bt_mp, pg, MPOOL_DIRTY);
+ }
+ return (0);
+}
diff --git a/lib/libc/db/btree/bt_get.c b/lib/libc/db/btree/bt_get.c
new file mode 100644
index 000000000000..77fae309ae66
--- /dev/null
+++ b/lib/libc/db/btree/bt_get.c
@@ -0,0 +1,99 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Mike Olson.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)bt_get.c 8.6 (Berkeley) 7/20/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdio.h>
+
+#include <db.h>
+#include "btree.h"
+
+/*
+ * __BT_GET -- Get a record from the btree.
+ *
+ * Parameters:
+ * dbp: pointer to access method
+ * key: key to find
+ * data: data to return
+ * flag: currently unused
+ *
+ * Returns:
+ * RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key not found.
+ */
+int
+__bt_get(const DB *dbp, const DBT *key, DBT *data, u_int flags)
+{
+ BTREE *t;
+ EPG *e;
+ int exact, status;
+
+ t = dbp->internal;
+
+ /* Toss any page pinned across calls. */
+ if (t->bt_pinned != NULL) {
+ mpool_put(t->bt_mp, t->bt_pinned, 0);
+ t->bt_pinned = NULL;
+ }
+
+ /* Get currently doesn't take any flags. */
+ if (flags) {
+ errno = EINVAL;
+ return (RET_ERROR);
+ }
+
+ if ((e = __bt_search(t, key, &exact)) == NULL)
+ return (RET_ERROR);
+ if (!exact) {
+ mpool_put(t->bt_mp, e->page, 0);
+ return (RET_SPECIAL);
+ }
+
+ status = __bt_ret(t, e, NULL, NULL, data, &t->bt_rdata, 0);
+
+ /*
+ * If the user is doing concurrent access, we copied the
+ * key/data, toss the page.
+ */
+ if (F_ISSET(t, B_DB_LOCK))
+ mpool_put(t->bt_mp, e->page, 0);
+ else
+ t->bt_pinned = e->page;
+ return (status);
+}
diff --git a/lib/libc/db/btree/bt_open.c b/lib/libc/db/btree/bt_open.c
new file mode 100644
index 000000000000..640a6699a4d8
--- /dev/null
+++ b/lib/libc/db/btree/bt_open.c
@@ -0,0 +1,449 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Mike Olson.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)bt_open.c 8.10 (Berkeley) 8/17/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Implementation of btree access method for 4.4BSD.
+ *
+ * The design here was originally based on that of the btree access method
+ * used in the Postgres database system at UC Berkeley. This implementation
+ * is wholly independent of the Postgres code.
+ */
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+
+#include <db.h>
+#include "btree.h"
+
+#ifdef DEBUG
+#undef MINPSIZE
+#define MINPSIZE 128
+#endif
+
+static int byteorder(void);
+static int nroot(BTREE *);
+static int tmp(void);
+
+/*
+ * __BT_OPEN -- Open a btree.
+ *
+ * Creates and fills a DB struct, and calls the routine that actually
+ * opens the btree.
+ *
+ * Parameters:
+ * fname: filename (NULL for in-memory trees)
+ * flags: open flag bits
+ * mode: open permission bits
+ * b: BTREEINFO pointer
+ *
+ * Returns:
+ * NULL on failure, pointer to DB on success.
+ *
+ */
+DB *
+__bt_open(const char *fname, int flags, int mode, const BTREEINFO *openinfo, int dflags)
+{
+ struct stat sb;
+ BTMETA m;
+ BTREE *t;
+ BTREEINFO b;
+ DB *dbp;
+ pgno_t ncache;
+ ssize_t nr;
+ int machine_lorder, saved_errno;
+
+ t = NULL;
+
+ /*
+ * Intention is to make sure all of the user's selections are okay
+ * here and then use them without checking. Can't be complete, since
+ * we don't know the right page size, lorder or flags until the backing
+ * file is opened. Also, the file's page size can cause the cachesize
+ * to change.
+ */
+ machine_lorder = byteorder();
+ if (openinfo) {
+ b = *openinfo;
+
+ /* Flags: R_DUP. */
+ if (b.flags & ~(R_DUP))
+ goto einval;
+
+ /*
+ * Page size must be indx_t aligned and >= MINPSIZE. Default
+ * page size is set farther on, based on the underlying file
+ * transfer size.
+ */
+ if (b.psize &&
+ (b.psize < MINPSIZE || b.psize > MAX_PAGE_OFFSET + 1 ||
+ b.psize & (sizeof(indx_t) - 1) ))
+ goto einval;
+
+ /* Minimum number of keys per page; absolute minimum is 2. */
+ if (b.minkeypage) {
+ if (b.minkeypage < 2)
+ goto einval;
+ } else
+ b.minkeypage = DEFMINKEYPAGE;
+
+ /* If no comparison, use default comparison and prefix. */
+ if (b.compare == NULL) {
+ b.compare = __bt_defcmp;
+ if (b.prefix == NULL)
+ b.prefix = __bt_defpfx;
+ }
+
+ if (b.lorder == 0)
+ b.lorder = machine_lorder;
+ } else {
+ b.compare = __bt_defcmp;
+ b.cachesize = 0;
+ b.flags = 0;
+ b.lorder = machine_lorder;
+ b.minkeypage = DEFMINKEYPAGE;
+ b.prefix = __bt_defpfx;
+ b.psize = 0;
+ }
+
+ /* Check for the ubiquitous PDP-11. */
+ if (b.lorder != BIG_ENDIAN && b.lorder != LITTLE_ENDIAN)
+ goto einval;
+
+ /* Allocate and initialize DB and BTREE structures. */
+ if ((t = (BTREE *)calloc(1, sizeof(BTREE))) == NULL)
+ goto err;
+ t->bt_fd = -1; /* Don't close unopened fd on error. */
+ t->bt_lorder = b.lorder;
+ t->bt_order = NOT;
+ t->bt_cmp = b.compare;
+ t->bt_pfx = b.prefix;
+ t->bt_rfd = -1;
+
+ if ((t->bt_dbp = dbp = (DB *)calloc(1, sizeof(DB))) == NULL)
+ goto err;
+ if (t->bt_lorder != machine_lorder)
+ F_SET(t, B_NEEDSWAP);
+
+ dbp->type = DB_BTREE;
+ dbp->internal = t;
+ dbp->close = __bt_close;
+ dbp->del = __bt_delete;
+ dbp->fd = __bt_fd;
+ dbp->get = __bt_get;
+ dbp->put = __bt_put;
+ dbp->seq = __bt_seq;
+ dbp->sync = __bt_sync;
+
+ /*
+ * If no file name was supplied, this is an in-memory btree and we
+ * open a backing temporary file. Otherwise, it's a disk-based tree.
+ */
+ if (fname) {
+ switch (flags & O_ACCMODE) {
+ case O_RDONLY:
+ F_SET(t, B_RDONLY);
+ break;
+ case O_RDWR:
+ break;
+ case O_WRONLY:
+ default:
+ goto einval;
+ }
+
+ if ((t->bt_fd = _open(fname, flags | O_CLOEXEC, mode)) < 0)
+ goto err;
+
+ } else {
+ if ((flags & O_ACCMODE) != O_RDWR)
+ goto einval;
+ if ((t->bt_fd = tmp()) == -1)
+ goto err;
+ F_SET(t, B_INMEM);
+ }
+
+ if (_fstat(t->bt_fd, &sb))
+ goto err;
+ if (sb.st_size) {
+ if ((nr = _read(t->bt_fd, &m, sizeof(BTMETA))) < 0)
+ goto err;
+ if (nr != sizeof(BTMETA))
+ goto eftype;
+
+ /*
+ * Read in the meta-data. This can change the notion of what
+ * the lorder, page size and flags are, and, when the page size
+ * changes, the cachesize value can change too. If the user
+ * specified the wrong byte order for an existing database, we
+ * don't bother to return an error, we just clear the NEEDSWAP
+ * bit.
+ */
+ if (m.magic == BTREEMAGIC)
+ F_CLR(t, B_NEEDSWAP);
+ else {
+ F_SET(t, B_NEEDSWAP);
+ M_32_SWAP(m.magic);
+ M_32_SWAP(m.version);
+ M_32_SWAP(m.psize);
+ M_32_SWAP(m.free);
+ M_32_SWAP(m.nrecs);
+ M_32_SWAP(m.flags);
+ }
+ if (m.magic != BTREEMAGIC || m.version != BTREEVERSION)
+ goto eftype;
+ if (m.psize < MINPSIZE || m.psize > MAX_PAGE_OFFSET + 1 ||
+ m.psize & (sizeof(indx_t) - 1) )
+ goto eftype;
+ if (m.flags & ~SAVEMETA)
+ goto eftype;
+ b.psize = m.psize;
+ F_SET(t, m.flags);
+ t->bt_free = m.free;
+ t->bt_nrecs = m.nrecs;
+ } else {
+ /*
+ * Set the page size to the best value for I/O to this file.
+ * Don't overflow the page offset type.
+ */
+ if (b.psize == 0) {
+ b.psize = sb.st_blksize;
+ if (b.psize < MINPSIZE)
+ b.psize = MINPSIZE;
+ if (b.psize > MAX_PAGE_OFFSET + 1)
+ b.psize = MAX_PAGE_OFFSET + 1;
+ }
+
+ /* Set flag if duplicates permitted. */
+ if (!(b.flags & R_DUP))
+ F_SET(t, B_NODUPS);
+
+ t->bt_free = P_INVALID;
+ t->bt_nrecs = 0;
+ F_SET(t, B_METADIRTY);
+ }
+
+ t->bt_psize = b.psize;
+
+ /* Set the cache size; must be a multiple of the page size. */
+ if (b.cachesize && b.cachesize & (b.psize - 1) )
+ b.cachesize += (~b.cachesize & (b.psize - 1) ) + 1;
+ if (b.cachesize < b.psize * MINCACHE)
+ b.cachesize = b.psize * MINCACHE;
+
+ /* Calculate number of pages to cache. */
+ ncache = howmany(b.cachesize, t->bt_psize);
+
+ /*
+ * The btree data structure requires that at least two keys can fit on
+ * a page, but other than that there's no fixed requirement. The user
+ * specified a minimum number per page, and we translated that into the
+ * number of bytes a key/data pair can use before being placed on an
+ * overflow page. This calculation includes the page header, the size
+ * of the index referencing the leaf item and the size of the leaf item
+ * structure. Also, don't let the user specify a minkeypage such that
+ * a key/data pair won't fit even if both key and data are on overflow
+ * pages.
+ */
+ t->bt_ovflsize = (t->bt_psize - BTDATAOFF) / b.minkeypage -
+ (sizeof(indx_t) + NBLEAFDBT(0, 0));
+ if (t->bt_ovflsize < NBLEAFDBT(NOVFLSIZE, NOVFLSIZE) + sizeof(indx_t))
+ t->bt_ovflsize =
+ NBLEAFDBT(NOVFLSIZE, NOVFLSIZE) + sizeof(indx_t);
+
+ /* Initialize the buffer pool. */
+ if ((t->bt_mp =
+ mpool_open(NULL, t->bt_fd, t->bt_psize, ncache)) == NULL)
+ goto err;
+ if (!F_ISSET(t, B_INMEM))
+ mpool_filter(t->bt_mp, __bt_pgin, __bt_pgout, t);
+
+ /* Create a root page if new tree. */
+ if (nroot(t) == RET_ERROR)
+ goto err;
+
+ /* Global flags. */
+ if (dflags & DB_LOCK)
+ F_SET(t, B_DB_LOCK);
+ if (dflags & DB_SHMEM)
+ F_SET(t, B_DB_SHMEM);
+ if (dflags & DB_TXN)
+ F_SET(t, B_DB_TXN);
+
+ return (dbp);
+
+einval: errno = EINVAL;
+ goto err;
+
+eftype: errno = EFTYPE;
+ goto err;
+
+err: saved_errno = errno;
+ if (t) {
+ if (t->bt_dbp)
+ free(t->bt_dbp);
+ if (t->bt_fd != -1)
+ (void)_close(t->bt_fd);
+ free(t);
+ }
+ errno = saved_errno;
+ return (NULL);
+}
+
+/*
+ * NROOT -- Create the root of a new tree.
+ *
+ * Parameters:
+ * t: tree
+ *
+ * Returns:
+ * RET_ERROR, RET_SUCCESS
+ */
+static int
+nroot(BTREE *t)
+{
+ PAGE *meta, *root;
+ pgno_t npg;
+
+ if ((root = mpool_get(t->bt_mp, 1, 0)) != NULL) {
+ if (root->lower == 0 &&
+ root->pgno == 0 &&
+ root->linp[0] == 0) {
+ mpool_delete(t->bt_mp, root);
+ errno = EINVAL;
+ } else {
+ mpool_put(t->bt_mp, root, 0);
+ return (RET_SUCCESS);
+ }
+ }
+ if (errno != EINVAL) /* It's OK to not exist. */
+ return (RET_ERROR);
+ errno = 0;
+
+ if ((meta = mpool_new(t->bt_mp, &npg, MPOOL_PAGE_NEXT)) == NULL)
+ return (RET_ERROR);
+
+ if ((root = mpool_new(t->bt_mp, &npg, MPOOL_PAGE_NEXT)) == NULL)
+ return (RET_ERROR);
+
+ if (npg != P_ROOT)
+ return (RET_ERROR);
+ root->pgno = npg;
+ root->prevpg = root->nextpg = P_INVALID;
+ root->lower = BTDATAOFF;
+ root->upper = t->bt_psize;
+ root->flags = P_BLEAF;
+ memset(meta, 0, t->bt_psize);
+ mpool_put(t->bt_mp, meta, MPOOL_DIRTY);
+ mpool_put(t->bt_mp, root, MPOOL_DIRTY);
+ return (RET_SUCCESS);
+}
+
+static int
+tmp(void)
+{
+ sigset_t set, oset;
+ int fd, len;
+ char *envtmp = NULL;
+ char path[MAXPATHLEN];
+
+ if (issetugid() == 0)
+ envtmp = getenv("TMPDIR");
+ len = snprintf(path,
+ sizeof(path), "%s/bt.XXXXXXXXXX", envtmp ? envtmp : "/tmp");
+ if (len < 0 || len >= (int)sizeof(path)) {
+ errno = ENAMETOOLONG;
+ return(-1);
+ }
+
+ (void)sigfillset(&set);
+ (void)__libc_sigprocmask(SIG_BLOCK, &set, &oset);
+ if ((fd = mkostemp(path, O_CLOEXEC)) != -1)
+ (void)unlink(path);
+ (void)__libc_sigprocmask(SIG_SETMASK, &oset, NULL);
+ return(fd);
+}
+
+static int
+byteorder(void)
+{
+ u_int32_t x;
+ u_char *p;
+
+ x = 0x01020304;
+ p = (u_char *)&x;
+ switch (*p) {
+ case 1:
+ return (BIG_ENDIAN);
+ case 4:
+ return (LITTLE_ENDIAN);
+ default:
+ return (0);
+ }
+}
+
+int
+__bt_fd(const DB *dbp)
+{
+ BTREE *t;
+
+ t = dbp->internal;
+
+ /* Toss any page pinned across calls. */
+ if (t->bt_pinned != NULL) {
+ mpool_put(t->bt_mp, t->bt_pinned, 0);
+ t->bt_pinned = NULL;
+ }
+
+ /* In-memory database can't have a file descriptor. */
+ if (F_ISSET(t, B_INMEM)) {
+ errno = ENOENT;
+ return (-1);
+ }
+ return (t->bt_fd);
+}
diff --git a/lib/libc/db/btree/bt_overflow.c b/lib/libc/db/btree/bt_overflow.c
new file mode 100644
index 000000000000..266d59990cac
--- /dev/null
+++ b/lib/libc/db/btree/bt_overflow.c
@@ -0,0 +1,216 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Mike Olson.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)bt_overflow.c 8.5 (Berkeley) 7/16/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <db.h>
+#include "btree.h"
+
+/*
+ * Big key/data code.
+ *
+ * Big key and data entries are stored on linked lists of pages. The initial
+ * reference is byte string stored with the key or data and is the page number
+ * and size. The actual record is stored in a chain of pages linked by the
+ * nextpg field of the PAGE header.
+ *
+ * The first page of the chain has a special property. If the record is used
+ * by an internal page, it cannot be deleted and the P_PRESERVE bit will be set
+ * in the header.
+ *
+ * XXX
+ * A single DBT is written to each chain, so a lot of space on the last page
+ * is wasted. This is a fairly major bug for some data sets.
+ */
+
+/*
+ * __OVFL_GET -- Get an overflow key/data item.
+ *
+ * Parameters:
+ * t: tree
+ * p: pointer to { pgno_t, u_int32_t }
+ * buf: storage address
+ * bufsz: storage size
+ *
+ * Returns:
+ * RET_ERROR, RET_SUCCESS
+ */
+int
+__ovfl_get(BTREE *t, void *p, size_t *ssz, void **buf, size_t *bufsz)
+{
+ PAGE *h;
+ pgno_t pg;
+ size_t nb, plen;
+ u_int32_t sz;
+
+ memmove(&pg, p, sizeof(pgno_t));
+ memmove(&sz, (char *)p + sizeof(pgno_t), sizeof(u_int32_t));
+ *ssz = sz;
+
+#ifdef DEBUG
+ if (pg == P_INVALID || sz == 0)
+ abort();
+#endif
+ /* Make the buffer bigger as necessary. */
+ if (*bufsz < sz) {
+ *buf = reallocf(*buf, sz);
+ if (*buf == NULL)
+ return (RET_ERROR);
+ *bufsz = sz;
+ }
+
+ /*
+ * Step through the linked list of pages, copying the data on each one
+ * into the buffer. Never copy more than the data's length.
+ */
+ plen = t->bt_psize - BTDATAOFF;
+ for (p = *buf;; p = (char *)p + nb, pg = h->nextpg) {
+ if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
+ return (RET_ERROR);
+
+ nb = MIN(sz, plen);
+ memmove(p, (char *)h + BTDATAOFF, nb);
+ mpool_put(t->bt_mp, h, 0);
+
+ if ((sz -= nb) == 0)
+ break;
+ }
+ return (RET_SUCCESS);
+}
+
+/*
+ * __OVFL_PUT -- Store an overflow key/data item.
+ *
+ * Parameters:
+ * t: tree
+ * data: DBT to store
+ * pgno: storage page number
+ *
+ * Returns:
+ * RET_ERROR, RET_SUCCESS
+ */
+int
+__ovfl_put(BTREE *t, const DBT *dbt, pgno_t *pg)
+{
+ PAGE *h, *last;
+ void *p;
+ pgno_t npg;
+ size_t nb, plen;
+ u_int32_t sz;
+
+ /*
+ * Allocate pages and copy the key/data record into them. Store the
+ * number of the first page in the chain.
+ */
+ plen = t->bt_psize - BTDATAOFF;
+ for (last = NULL, p = dbt->data, sz = dbt->size;;
+ p = (char *)p + plen, last = h) {
+ if ((h = __bt_new(t, &npg)) == NULL)
+ return (RET_ERROR);
+
+ h->pgno = npg;
+ h->nextpg = h->prevpg = P_INVALID;
+ h->flags = P_OVERFLOW;
+ h->lower = h->upper = 0;
+
+ nb = MIN(sz, plen);
+ memmove((char *)h + BTDATAOFF, p, nb);
+
+ if (last) {
+ last->nextpg = h->pgno;
+ mpool_put(t->bt_mp, last, MPOOL_DIRTY);
+ } else
+ *pg = h->pgno;
+
+ if ((sz -= nb) == 0) {
+ mpool_put(t->bt_mp, h, MPOOL_DIRTY);
+ break;
+ }
+ }
+ return (RET_SUCCESS);
+}
+
+/*
+ * __OVFL_DELETE -- Delete an overflow chain.
+ *
+ * Parameters:
+ * t: tree
+ * p: pointer to { pgno_t, u_int32_t }
+ *
+ * Returns:
+ * RET_ERROR, RET_SUCCESS
+ */
+int
+__ovfl_delete(BTREE *t, void *p)
+{
+ PAGE *h;
+ pgno_t pg;
+ size_t plen;
+ u_int32_t sz;
+
+ memmove(&pg, p, sizeof(pgno_t));
+ memmove(&sz, (char *)p + sizeof(pgno_t), sizeof(u_int32_t));
+
+#ifdef DEBUG
+ if (pg == P_INVALID || sz == 0)
+ abort();
+#endif
+ if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
+ return (RET_ERROR);
+
+ /* Don't delete chains used by internal pages. */
+ if (h->flags & P_PRESERVE) {
+ mpool_put(t->bt_mp, h, 0);
+ return (RET_SUCCESS);
+ }
+
+ /* Step through the chain, calling the free routine for each page. */
+ for (plen = t->bt_psize - BTDATAOFF;; sz -= plen) {
+ pg = h->nextpg;
+ __bt_free(t, h);
+ if (sz <= plen)
+ break;
+ if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
+ return (RET_ERROR);
+ }
+ return (RET_SUCCESS);
+}
diff --git a/lib/libc/db/btree/bt_page.c b/lib/libc/db/btree/bt_page.c
new file mode 100644
index 000000000000..ab5e359742ca
--- /dev/null
+++ b/lib/libc/db/btree/bt_page.c
@@ -0,0 +1,94 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)bt_page.c 8.3 (Berkeley) 7/14/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+#include <stdio.h>
+
+#include <db.h>
+#include "btree.h"
+
+/*
+ * __bt_free --
+ * Put a page on the freelist.
+ *
+ * Parameters:
+ * t: tree
+ * h: page to free
+ *
+ * Returns:
+ * RET_ERROR, RET_SUCCESS
+ *
+ * Side-effect:
+ * mpool_put's the page.
+ */
+int
+__bt_free(BTREE *t, PAGE *h)
+{
+ /* Insert the page at the head of the free list. */
+ h->prevpg = P_INVALID;
+ h->nextpg = t->bt_free;
+ t->bt_free = h->pgno;
+ F_SET(t, B_METADIRTY);
+
+ /* Make sure the page gets written back. */
+ return (mpool_put(t->bt_mp, h, MPOOL_DIRTY));
+}
+
+/*
+ * __bt_new --
+ * Get a new page, preferably from the freelist.
+ *
+ * Parameters:
+ * t: tree
+ * npg: storage for page number.
+ *
+ * Returns:
+ * Pointer to a page, NULL on error.
+ */
+PAGE *
+__bt_new(BTREE *t, pgno_t *npg)
+{
+ PAGE *h;
+
+ if (t->bt_free != P_INVALID &&
+ (h = mpool_get(t->bt_mp, t->bt_free, 0)) != NULL) {
+ *npg = t->bt_free;
+ t->bt_free = h->nextpg;
+ F_SET(t, B_METADIRTY);
+ return (h);
+ }
+ return (mpool_new(t->bt_mp, npg, MPOOL_PAGE_NEXT));
+}
diff --git a/lib/libc/db/btree/bt_put.c b/lib/libc/db/btree/bt_put.c
new file mode 100644
index 000000000000..d4bc3aa3b09d
--- /dev/null
+++ b/lib/libc/db/btree/bt_put.c
@@ -0,0 +1,315 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Mike Olson.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)bt_put.c 8.8 (Berkeley) 7/26/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <db.h>
+#include "btree.h"
+
+static EPG *bt_fast(BTREE *, const DBT *, const DBT *, int *);
+
+/*
+ * __BT_PUT -- Add a btree item to the tree.
+ *
+ * Parameters:
+ * dbp: pointer to access method
+ * key: key
+ * data: data
+ * flag: R_NOOVERWRITE, R_SETCURSOR, R_CURSOR
+ *
+ * Returns:
+ * RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key is already in the
+ * tree and R_NOOVERWRITE specified.
+ */
+int
+__bt_put(const DB *dbp, DBT *key, const DBT *data, u_int flags)
+{
+ BTREE *t;
+ DBT tkey, tdata;
+ EPG *e;
+ PAGE *h;
+ indx_t idx, nxtindex;
+ pgno_t pg;
+ u_int32_t nbytes, tmp;
+ int dflags, exact, status;
+ char *dest, db[NOVFLSIZE], kb[NOVFLSIZE];
+
+ t = dbp->internal;
+
+ /* Toss any page pinned across calls. */
+ if (t->bt_pinned != NULL) {
+ mpool_put(t->bt_mp, t->bt_pinned, 0);
+ t->bt_pinned = NULL;
+ }
+
+ /* Check for change to a read-only tree. */
+ if (F_ISSET(t, B_RDONLY)) {
+ errno = EPERM;
+ return (RET_ERROR);
+ }
+
+ switch (flags) {
+ case 0:
+ case R_NOOVERWRITE:
+ case R_SETCURSOR:
+ break;
+ case R_CURSOR:
+ /*
+ * If flags is R_CURSOR, put the cursor. Must already
+ * have started a scan and not have already deleted it.
+ */
+ if (F_ISSET(&t->bt_cursor, CURS_INIT) &&
+ !F_ISSET(&t->bt_cursor,
+ CURS_ACQUIRE | CURS_AFTER | CURS_BEFORE))
+ break;
+ /* FALLTHROUGH */
+ default:
+ errno = EINVAL;
+ return (RET_ERROR);
+ }
+
+ /*
+ * If the key/data pair won't fit on a page, store it on overflow
+ * pages. Only put the key on the overflow page if the pair are
+ * still too big after moving the data to an overflow page.
+ *
+ * XXX
+ * If the insert fails later on, the overflow pages aren't recovered.
+ */
+ dflags = 0;
+ if (key->size + data->size > t->bt_ovflsize) {
+ if (key->size > t->bt_ovflsize) {
+storekey: if (__ovfl_put(t, key, &pg) == RET_ERROR)
+ return (RET_ERROR);
+ tkey.data = kb;
+ tkey.size = NOVFLSIZE;
+ memmove(kb, &pg, sizeof(pgno_t));
+ tmp = key->size;
+ memmove(kb + sizeof(pgno_t),
+ &tmp, sizeof(u_int32_t));
+ dflags |= P_BIGKEY;
+ key = &tkey;
+ }
+ if (key->size + data->size > t->bt_ovflsize) {
+ if (__ovfl_put(t, data, &pg) == RET_ERROR)
+ return (RET_ERROR);
+ tdata.data = db;
+ tdata.size = NOVFLSIZE;
+ memmove(db, &pg, sizeof(pgno_t));
+ tmp = data->size;
+ memmove(db + sizeof(pgno_t),
+ &tmp, sizeof(u_int32_t));
+ dflags |= P_BIGDATA;
+ data = &tdata;
+ }
+ if (key->size + data->size > t->bt_ovflsize)
+ goto storekey;
+ }
+
+ /* Replace the cursor. */
+ if (flags == R_CURSOR) {
+ if ((h = mpool_get(t->bt_mp, t->bt_cursor.pg.pgno, 0)) == NULL)
+ return (RET_ERROR);
+ idx = t->bt_cursor.pg.index;
+ goto delete;
+ }
+
+ /*
+ * Find the key to delete, or, the location at which to insert.
+ * Bt_fast and __bt_search both pin the returned page.
+ */
+ if (t->bt_order == NOT || (e = bt_fast(t, key, data, &exact)) == NULL)
+ if ((e = __bt_search(t, key, &exact)) == NULL)
+ return (RET_ERROR);
+ h = e->page;
+ idx = e->index;
+
+ /*
+ * Add the key/data pair to the tree. If an identical key is already
+ * in the tree, and R_NOOVERWRITE is set, an error is returned. If
+ * R_NOOVERWRITE is not set, the key is either added (if duplicates are
+ * permitted) or an error is returned.
+ */
+ switch (flags) {
+ case R_NOOVERWRITE:
+ if (!exact)
+ break;
+ mpool_put(t->bt_mp, h, 0);
+ return (RET_SPECIAL);
+ default:
+ if (!exact || !F_ISSET(t, B_NODUPS))
+ break;
+ /*
+ * !!!
+ * Note, the delete may empty the page, so we need to put a
+ * new entry into the page immediately.
+ */
+delete: if (__bt_dleaf(t, key, h, idx) == RET_ERROR) {
+ mpool_put(t->bt_mp, h, 0);
+ return (RET_ERROR);
+ }
+ break;
+ }
+
+ /*
+ * If not enough room, or the user has put a ceiling on the number of
+ * keys permitted in the page, split the page. The split code will
+ * insert the key and data and unpin the current page. If inserting
+ * into the offset array, shift the pointers up.
+ */
+ nbytes = NBLEAFDBT(key->size, data->size);
+ if ((u_int32_t)(h->upper - h->lower) < nbytes + sizeof(indx_t)) {
+ if ((status = __bt_split(t, h, key,
+ data, dflags, nbytes, idx)) != RET_SUCCESS)
+ return (status);
+ goto success;
+ }
+
+ if (idx < (nxtindex = NEXTINDEX(h)))
+ memmove(h->linp + idx + 1, h->linp + idx,
+ (nxtindex - idx) * sizeof(indx_t));
+ h->lower += sizeof(indx_t);
+
+ h->linp[idx] = h->upper -= nbytes;
+ dest = (char *)h + h->upper;
+ WR_BLEAF(dest, key, data, dflags);
+
+ /* If the cursor is on this page, adjust it as necessary. */
+ if (F_ISSET(&t->bt_cursor, CURS_INIT) &&
+ !F_ISSET(&t->bt_cursor, CURS_ACQUIRE) &&
+ t->bt_cursor.pg.pgno == h->pgno && t->bt_cursor.pg.index >= idx)
+ ++t->bt_cursor.pg.index;
+
+ if (t->bt_order == NOT) {
+ if (h->nextpg == P_INVALID) {
+ if (idx == NEXTINDEX(h) - 1) {
+ t->bt_order = FORWARD;
+ t->bt_last.index = idx;
+ t->bt_last.pgno = h->pgno;
+ }
+ } else if (h->prevpg == P_INVALID) {
+ if (idx == 0) {
+ t->bt_order = BACK;
+ t->bt_last.index = 0;
+ t->bt_last.pgno = h->pgno;
+ }
+ }
+ }
+
+ mpool_put(t->bt_mp, h, MPOOL_DIRTY);
+
+success:
+ if (flags == R_SETCURSOR)
+ __bt_setcur(t, e->page->pgno, e->index);
+
+ F_SET(t, B_MODIFIED);
+ return (RET_SUCCESS);
+}
+
+#ifdef STATISTICS
+u_long bt_cache_hit, bt_cache_miss;
+#endif
+
+/*
+ * BT_FAST -- Do a quick check for sorted data.
+ *
+ * Parameters:
+ * t: tree
+ * key: key to insert
+ *
+ * Returns:
+ * EPG for new record or NULL if not found.
+ */
+static EPG *
+bt_fast(BTREE *t, const DBT *key, const DBT *data, int *exactp)
+{
+ PAGE *h;
+ u_int32_t nbytes;
+ int cmp;
+
+ if ((h = mpool_get(t->bt_mp, t->bt_last.pgno, 0)) == NULL) {
+ t->bt_order = NOT;
+ return (NULL);
+ }
+ t->bt_cur.page = h;
+ t->bt_cur.index = t->bt_last.index;
+
+ /*
+ * If won't fit in this page or have too many keys in this page,
+ * have to search to get split stack.
+ */
+ nbytes = NBLEAFDBT(key->size, data->size);
+ if ((u_int32_t)(h->upper - h->lower) < nbytes + sizeof(indx_t))
+ goto miss;
+
+ if (t->bt_order == FORWARD) {
+ if (t->bt_cur.page->nextpg != P_INVALID)
+ goto miss;
+ if (t->bt_cur.index != NEXTINDEX(h) - 1)
+ goto miss;
+ if ((cmp = __bt_cmp(t, key, &t->bt_cur)) < 0)
+ goto miss;
+ t->bt_last.index = cmp ? ++t->bt_cur.index : t->bt_cur.index;
+ } else {
+ if (t->bt_cur.page->prevpg != P_INVALID)
+ goto miss;
+ if (t->bt_cur.index != 0)
+ goto miss;
+ if ((cmp = __bt_cmp(t, key, &t->bt_cur)) > 0)
+ goto miss;
+ t->bt_last.index = 0;
+ }
+ *exactp = cmp == 0;
+#ifdef STATISTICS
+ ++bt_cache_hit;
+#endif
+ return (&t->bt_cur);
+
+miss:
+#ifdef STATISTICS
+ ++bt_cache_miss;
+#endif
+ t->bt_order = NOT;
+ mpool_put(t->bt_mp, h, 0);
+ return (NULL);
+}
diff --git a/lib/libc/db/btree/bt_search.c b/lib/libc/db/btree/bt_search.c
new file mode 100644
index 000000000000..15ef1fa81af2
--- /dev/null
+++ b/lib/libc/db/btree/bt_search.c
@@ -0,0 +1,200 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Mike Olson.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)bt_search.c 8.8 (Berkeley) 7/31/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+#include <stdio.h>
+
+#include <db.h>
+#include "btree.h"
+
+static int __bt_snext(BTREE *, PAGE *, const DBT *, int *);
+static int __bt_sprev(BTREE *, PAGE *, const DBT *, int *);
+
+/*
+ * __bt_search --
+ * Search a btree for a key.
+ *
+ * Parameters:
+ * t: tree to search
+ * key: key to find
+ * exactp: pointer to exact match flag
+ *
+ * Returns:
+ * The EPG for matching record, if any, or the EPG for the location
+ * of the key, if it were inserted into the tree, is entered into
+ * the bt_cur field of the tree. A pointer to the field is returned.
+ */
+EPG *
+__bt_search(BTREE *t, const DBT *key, int *exactp)
+{
+ PAGE *h;
+ indx_t base, idx, lim;
+ pgno_t pg;
+ int cmp;
+
+ BT_CLR(t);
+ for (pg = P_ROOT;;) {
+ if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
+ return (NULL);
+
+ /* Do a binary search on the current page. */
+ t->bt_cur.page = h;
+ for (base = 0, lim = NEXTINDEX(h); lim; lim >>= 1) {
+ t->bt_cur.index = idx = base + (lim >> 1);
+ if ((cmp = __bt_cmp(t, key, &t->bt_cur)) == 0) {
+ if (h->flags & P_BLEAF) {
+ *exactp = 1;
+ return (&t->bt_cur);
+ }
+ goto next;
+ }
+ if (cmp > 0) {
+ base = idx + 1;
+ --lim;
+ }
+ }
+
+ /*
+ * If it's a leaf page, we're almost done. If no duplicates
+ * are allowed, or we have an exact match, we're done. Else,
+ * it's possible that there were matching keys on this page,
+ * which later deleted, and we're on a page with no matches
+ * while there are matches on other pages. If at the start or
+ * end of a page, check the adjacent page.
+ */
+ if (h->flags & P_BLEAF) {
+ if (!F_ISSET(t, B_NODUPS)) {
+ if (base == 0 &&
+ h->prevpg != P_INVALID &&
+ __bt_sprev(t, h, key, exactp))
+ return (&t->bt_cur);
+ if (base == NEXTINDEX(h) &&
+ h->nextpg != P_INVALID &&
+ __bt_snext(t, h, key, exactp))
+ return (&t->bt_cur);
+ }
+ *exactp = 0;
+ t->bt_cur.index = base;
+ return (&t->bt_cur);
+ }
+
+ /*
+ * No match found. Base is the smallest index greater than
+ * key and may be zero or a last + 1 index. If it's non-zero,
+ * decrement by one, and record the internal page which should
+ * be a parent page for the key. If a split later occurs, the
+ * inserted page will be to the right of the saved page.
+ */
+ idx = base ? base - 1 : base;
+
+next: BT_PUSH(t, h->pgno, idx);
+ pg = GETBINTERNAL(h, idx)->pgno;
+ mpool_put(t->bt_mp, h, 0);
+ }
+}
+
+/*
+ * __bt_snext --
+ * Check for an exact match after the key.
+ *
+ * Parameters:
+ * t: tree
+ * h: current page
+ * key: key
+ * exactp: pointer to exact match flag
+ *
+ * Returns:
+ * If an exact match found.
+ */
+static int
+__bt_snext(BTREE *t, PAGE *h, const DBT *key, int *exactp)
+{
+ EPG e;
+
+ /*
+ * Get the next page. The key is either an exact
+ * match, or not as good as the one we already have.
+ */
+ if ((e.page = mpool_get(t->bt_mp, h->nextpg, 0)) == NULL)
+ return (0);
+ e.index = 0;
+ if (__bt_cmp(t, key, &e) == 0) {
+ mpool_put(t->bt_mp, h, 0);
+ t->bt_cur = e;
+ *exactp = 1;
+ return (1);
+ }
+ mpool_put(t->bt_mp, e.page, 0);
+ return (0);
+}
+
+/*
+ * __bt_sprev --
+ * Check for an exact match before the key.
+ *
+ * Parameters:
+ * t: tree
+ * h: current page
+ * key: key
+ * exactp: pointer to exact match flag
+ *
+ * Returns:
+ * If an exact match found.
+ */
+static int
+__bt_sprev(BTREE *t, PAGE *h, const DBT *key, int *exactp)
+{
+ EPG e;
+
+ /*
+ * Get the previous page. The key is either an exact
+ * match, or not as good as the one we already have.
+ */
+ if ((e.page = mpool_get(t->bt_mp, h->prevpg, 0)) == NULL)
+ return (0);
+ e.index = NEXTINDEX(e.page) - 1;
+ if (__bt_cmp(t, key, &e) == 0) {
+ mpool_put(t->bt_mp, h, 0);
+ t->bt_cur = e;
+ *exactp = 1;
+ return (1);
+ }
+ mpool_put(t->bt_mp, e.page, 0);
+ return (0);
+}
diff --git a/lib/libc/db/btree/bt_seq.c b/lib/libc/db/btree/bt_seq.c
new file mode 100644
index 000000000000..19289512a3cb
--- /dev/null
+++ b/lib/libc/db/btree/bt_seq.c
@@ -0,0 +1,441 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Mike Olson.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)bt_seq.c 8.7 (Berkeley) 7/20/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <db.h>
+#include "btree.h"
+
+static int __bt_first(BTREE *, const DBT *, EPG *, int *);
+static int __bt_seqadv(BTREE *, EPG *, int);
+static int __bt_seqset(BTREE *, EPG *, DBT *, int);
+
+/*
+ * Sequential scan support.
+ *
+ * The tree can be scanned sequentially, starting from either end of the
+ * tree or from any specific key. A scan request before any scanning is
+ * done is initialized as starting from the least node.
+ */
+
+/*
+ * __bt_seq --
+ * Btree sequential scan interface.
+ *
+ * Parameters:
+ * dbp: pointer to access method
+ * key: key for positioning and return value
+ * data: data return value
+ * flags: R_CURSOR, R_FIRST, R_LAST, R_NEXT, R_PREV.
+ *
+ * Returns:
+ * RET_ERROR, RET_SUCCESS or RET_SPECIAL if there's no next key.
+ */
+int
+__bt_seq(const DB *dbp, DBT *key, DBT *data, u_int flags)
+{
+ BTREE *t;
+ EPG e;
+ int status;
+
+ t = dbp->internal;
+
+ /* Toss any page pinned across calls. */
+ if (t->bt_pinned != NULL) {
+ mpool_put(t->bt_mp, t->bt_pinned, 0);
+ t->bt_pinned = NULL;
+ }
+
+ /*
+ * If scan unitialized as yet, or starting at a specific record, set
+ * the scan to a specific key. Both __bt_seqset and __bt_seqadv pin
+ * the page the cursor references if they're successful.
+ */
+ switch (flags) {
+ case R_NEXT:
+ case R_PREV:
+ if (F_ISSET(&t->bt_cursor, CURS_INIT)) {
+ status = __bt_seqadv(t, &e, flags);
+ break;
+ }
+ /* FALLTHROUGH */
+ case R_FIRST:
+ case R_LAST:
+ case R_CURSOR:
+ status = __bt_seqset(t, &e, key, flags);
+ break;
+ default:
+ errno = EINVAL;
+ return (RET_ERROR);
+ }
+
+ if (status == RET_SUCCESS) {
+ __bt_setcur(t, e.page->pgno, e.index);
+
+ status =
+ __bt_ret(t, &e, key, &t->bt_rkey, data, &t->bt_rdata, 0);
+
+ /*
+ * If the user is doing concurrent access, we copied the
+ * key/data, toss the page.
+ */
+ if (F_ISSET(t, B_DB_LOCK))
+ mpool_put(t->bt_mp, e.page, 0);
+ else
+ t->bt_pinned = e.page;
+ }
+ return (status);
+}
+
+/*
+ * __bt_seqset --
+ * Set the sequential scan to a specific key.
+ *
+ * Parameters:
+ * t: tree
+ * ep: storage for returned key
+ * key: key for initial scan position
+ * flags: R_CURSOR, R_FIRST, R_LAST, R_NEXT, R_PREV
+ *
+ * Side effects:
+ * Pins the page the cursor references.
+ *
+ * Returns:
+ * RET_ERROR, RET_SUCCESS or RET_SPECIAL if there's no next key.
+ */
+static int
+__bt_seqset(BTREE *t, EPG *ep, DBT *key, int flags)
+{
+ PAGE *h;
+ pgno_t pg;
+ int exact;
+
+ /*
+ * Find the first, last or specific key in the tree and point the
+ * cursor at it. The cursor may not be moved until a new key has
+ * been found.
+ */
+ switch (flags) {
+ case R_CURSOR: /* Keyed scan. */
+ /*
+ * Find the first instance of the key or the smallest key
+ * which is greater than or equal to the specified key.
+ */
+ if (key->data == NULL || key->size == 0) {
+ errno = EINVAL;
+ return (RET_ERROR);
+ }
+ return (__bt_first(t, key, ep, &exact));
+ case R_FIRST: /* First record. */
+ case R_NEXT:
+ /* Walk down the left-hand side of the tree. */
+ for (pg = P_ROOT;;) {
+ if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
+ return (RET_ERROR);
+
+ /* Check for an empty tree. */
+ if (NEXTINDEX(h) == 0) {
+ mpool_put(t->bt_mp, h, 0);
+ return (RET_SPECIAL);
+ }
+
+ if (h->flags & (P_BLEAF | P_RLEAF))
+ break;
+ pg = GETBINTERNAL(h, 0)->pgno;
+ mpool_put(t->bt_mp, h, 0);
+ }
+ ep->page = h;
+ ep->index = 0;
+ break;
+ case R_LAST: /* Last record. */
+ case R_PREV:
+ /* Walk down the right-hand side of the tree. */
+ for (pg = P_ROOT;;) {
+ if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
+ return (RET_ERROR);
+
+ /* Check for an empty tree. */
+ if (NEXTINDEX(h) == 0) {
+ mpool_put(t->bt_mp, h, 0);
+ return (RET_SPECIAL);
+ }
+
+ if (h->flags & (P_BLEAF | P_RLEAF))
+ break;
+ pg = GETBINTERNAL(h, NEXTINDEX(h) - 1)->pgno;
+ mpool_put(t->bt_mp, h, 0);
+ }
+
+ ep->page = h;
+ ep->index = NEXTINDEX(h) - 1;
+ break;
+ }
+ return (RET_SUCCESS);
+}
+
+/*
+ * __bt_seqadvance --
+ * Advance the sequential scan.
+ *
+ * Parameters:
+ * t: tree
+ * flags: R_NEXT, R_PREV
+ *
+ * Side effects:
+ * Pins the page the new key/data record is on.
+ *
+ * Returns:
+ * RET_ERROR, RET_SUCCESS or RET_SPECIAL if there's no next key.
+ */
+static int
+__bt_seqadv(BTREE *t, EPG *ep, int flags)
+{
+ CURSOR *c;
+ PAGE *h;
+ indx_t idx;
+ pgno_t pg;
+ int exact;
+
+ /*
+ * There are a couple of states that we can be in. The cursor has
+ * been initialized by the time we get here, but that's all we know.
+ */
+ c = &t->bt_cursor;
+
+ /*
+ * The cursor was deleted where there weren't any duplicate records,
+ * so the key was saved. Find out where that key would go in the
+ * current tree. It doesn't matter if the returned key is an exact
+ * match or not -- if it's an exact match, the record was added after
+ * the delete so we can just return it. If not, as long as there's
+ * a record there, return it.
+ */
+ if (F_ISSET(c, CURS_ACQUIRE))
+ return (__bt_first(t, &c->key, ep, &exact));
+
+ /* Get the page referenced by the cursor. */
+ if ((h = mpool_get(t->bt_mp, c->pg.pgno, 0)) == NULL)
+ return (RET_ERROR);
+
+ /*
+ * Find the next/previous record in the tree and point the cursor at
+ * it. The cursor may not be moved until a new key has been found.
+ */
+ switch (flags) {
+ case R_NEXT: /* Next record. */
+ /*
+ * The cursor was deleted in duplicate records, and moved
+ * forward to a record that has yet to be returned. Clear
+ * that flag, and return the record.
+ */
+ if (F_ISSET(c, CURS_AFTER))
+ goto usecurrent;
+ idx = c->pg.index;
+ if (++idx == NEXTINDEX(h)) {
+ pg = h->nextpg;
+ mpool_put(t->bt_mp, h, 0);
+ if (pg == P_INVALID)
+ return (RET_SPECIAL);
+ if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
+ return (RET_ERROR);
+ idx = 0;
+ }
+ break;
+ case R_PREV: /* Previous record. */
+ /*
+ * The cursor was deleted in duplicate records, and moved
+ * backward to a record that has yet to be returned. Clear
+ * that flag, and return the record.
+ */
+ if (F_ISSET(c, CURS_BEFORE)) {
+usecurrent: F_CLR(c, CURS_AFTER | CURS_BEFORE);
+ ep->page = h;
+ ep->index = c->pg.index;
+ return (RET_SUCCESS);
+ }
+ idx = c->pg.index;
+ if (idx == 0) {
+ pg = h->prevpg;
+ mpool_put(t->bt_mp, h, 0);
+ if (pg == P_INVALID)
+ return (RET_SPECIAL);
+ if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
+ return (RET_ERROR);
+ idx = NEXTINDEX(h) - 1;
+ } else
+ --idx;
+ break;
+ }
+
+ ep->page = h;
+ ep->index = idx;
+ return (RET_SUCCESS);
+}
+
+/*
+ * __bt_first --
+ * Find the first entry.
+ *
+ * Parameters:
+ * t: the tree
+ * key: the key
+ * erval: return EPG
+ * exactp: pointer to exact match flag
+ *
+ * Returns:
+ * The first entry in the tree greater than or equal to key,
+ * or RET_SPECIAL if no such key exists.
+ */
+static int
+__bt_first(BTREE *t, const DBT *key, EPG *erval, int *exactp)
+{
+ PAGE *h;
+ EPG *ep, save;
+ pgno_t pg;
+
+ /*
+ * Find any matching record; __bt_search pins the page.
+ *
+ * If it's an exact match and duplicates are possible, walk backwards
+ * in the tree until we find the first one. Otherwise, make sure it's
+ * a valid key (__bt_search may return an index just past the end of a
+ * page) and return it.
+ */
+ if ((ep = __bt_search(t, key, exactp)) == NULL)
+ return (0);
+ if (*exactp) {
+ if (F_ISSET(t, B_NODUPS)) {
+ *erval = *ep;
+ return (RET_SUCCESS);
+ }
+
+ /*
+ * Walk backwards, as long as the entry matches and there are
+ * keys left in the tree. Save a copy of each match in case
+ * we go too far.
+ */
+ save = *ep;
+ h = ep->page;
+ do {
+ if (save.page->pgno != ep->page->pgno) {
+ mpool_put(t->bt_mp, save.page, 0);
+ save = *ep;
+ } else
+ save.index = ep->index;
+
+ /*
+ * Don't unpin the page the last (or original) match
+ * was on, but make sure it's unpinned if an error
+ * occurs.
+ */
+ if (ep->index == 0) {
+ if (h->prevpg == P_INVALID)
+ break;
+ if (h->pgno != save.page->pgno)
+ mpool_put(t->bt_mp, h, 0);
+ if ((h = mpool_get(t->bt_mp,
+ h->prevpg, 0)) == NULL) {
+ if (h->pgno == save.page->pgno)
+ mpool_put(t->bt_mp,
+ save.page, 0);
+ return (RET_ERROR);
+ }
+ ep->page = h;
+ ep->index = NEXTINDEX(h);
+ }
+ --ep->index;
+ } while (__bt_cmp(t, key, ep) == 0);
+
+ /*
+ * Reach here with the last page that was looked at pinned,
+ * which may or may not be the same as the last (or original)
+ * match page. If it's not useful, release it.
+ */
+ if (h->pgno != save.page->pgno)
+ mpool_put(t->bt_mp, h, 0);
+
+ *erval = save;
+ return (RET_SUCCESS);
+ }
+
+ /* If at the end of a page, find the next entry. */
+ if (ep->index == NEXTINDEX(ep->page)) {
+ h = ep->page;
+ pg = h->nextpg;
+ mpool_put(t->bt_mp, h, 0);
+ if (pg == P_INVALID)
+ return (RET_SPECIAL);
+ if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
+ return (RET_ERROR);
+ ep->index = 0;
+ ep->page = h;
+ }
+ *erval = *ep;
+ return (RET_SUCCESS);
+}
+
+/*
+ * __bt_setcur --
+ * Set the cursor to an entry in the tree.
+ *
+ * Parameters:
+ * t: the tree
+ * pgno: page number
+ * idx: page index
+ */
+void
+__bt_setcur(BTREE *t, pgno_t pgno, u_int idx)
+{
+ /* Lose any already deleted key. */
+ if (t->bt_cursor.key.data != NULL) {
+ free(t->bt_cursor.key.data);
+ t->bt_cursor.key.size = 0;
+ t->bt_cursor.key.data = NULL;
+ }
+ F_CLR(&t->bt_cursor, CURS_ACQUIRE | CURS_AFTER | CURS_BEFORE);
+
+ /* Update the cursor. */
+ t->bt_cursor.pg.pgno = pgno;
+ t->bt_cursor.pg.index = idx;
+ F_SET(&t->bt_cursor, CURS_INIT);
+}
diff --git a/lib/libc/db/btree/bt_split.c b/lib/libc/db/btree/bt_split.c
new file mode 100644
index 000000000000..fc7ddedac0df
--- /dev/null
+++ b/lib/libc/db/btree/bt_split.c
@@ -0,0 +1,802 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Mike Olson.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)bt_split.c 8.10 (Berkeley) 1/9/95";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <db.h>
+#include "btree.h"
+
+static int bt_broot(BTREE *, PAGE *, PAGE *, PAGE *);
+static PAGE *bt_page(BTREE *, PAGE *, PAGE **, PAGE **, indx_t *, size_t);
+static int bt_preserve(BTREE *, pgno_t);
+static PAGE *bt_psplit(BTREE *, PAGE *, PAGE *, PAGE *, indx_t *, size_t);
+static PAGE *bt_root(BTREE *, PAGE *, PAGE **, PAGE **, indx_t *, size_t);
+static int bt_rroot(BTREE *, PAGE *, PAGE *, PAGE *);
+static recno_t rec_total(PAGE *);
+
+#ifdef STATISTICS
+u_long bt_rootsplit, bt_split, bt_sortsplit, bt_pfxsaved;
+#endif
+
+/*
+ * __BT_SPLIT -- Split the tree.
+ *
+ * Parameters:
+ * t: tree
+ * sp: page to split
+ * key: key to insert
+ * data: data to insert
+ * flags: BIGKEY/BIGDATA flags
+ * ilen: insert length
+ * skip: index to leave open
+ *
+ * Returns:
+ * RET_ERROR, RET_SUCCESS
+ */
+int
+__bt_split(BTREE *t, PAGE *sp, const DBT *key, const DBT *data, int flags,
+ size_t ilen, u_int32_t argskip)
+{
+ BINTERNAL *bi;
+ BLEAF *bl, *tbl;
+ DBT a, b;
+ EPGNO *parent;
+ PAGE *h, *l, *r, *lchild, *rchild;
+ indx_t nxtindex;
+ u_int16_t skip;
+ u_int32_t n, nbytes, nksize;
+ int parentsplit;
+ char *dest;
+
+ /*
+ * Split the page into two pages, l and r. The split routines return
+ * a pointer to the page into which the key should be inserted and with
+ * skip set to the offset which should be used. Additionally, l and r
+ * are pinned.
+ */
+ skip = argskip;
+ h = sp->pgno == P_ROOT ?
+ bt_root(t, sp, &l, &r, &skip, ilen) :
+ bt_page(t, sp, &l, &r, &skip, ilen);
+ if (h == NULL)
+ return (RET_ERROR);
+
+ /*
+ * Insert the new key/data pair into the leaf page. (Key inserts
+ * always cause a leaf page to split first.)
+ */
+ h->linp[skip] = h->upper -= ilen;
+ dest = (char *)h + h->upper;
+ if (F_ISSET(t, R_RECNO))
+ WR_RLEAF(dest, data, flags)
+ else
+ WR_BLEAF(dest, key, data, flags)
+
+ /* If the root page was split, make it look right. */
+ if (sp->pgno == P_ROOT &&
+ (F_ISSET(t, R_RECNO) ?
+ bt_rroot(t, sp, l, r) : bt_broot(t, sp, l, r)) == RET_ERROR)
+ goto err2;
+
+ /*
+ * Now we walk the parent page stack -- a LIFO stack of the pages that
+ * were traversed when we searched for the page that split. Each stack
+ * entry is a page number and a page index offset. The offset is for
+ * the page traversed on the search. We've just split a page, so we
+ * have to insert a new key into the parent page.
+ *
+ * If the insert into the parent page causes it to split, may have to
+ * continue splitting all the way up the tree. We stop if the root
+ * splits or the page inserted into didn't have to split to hold the
+ * new key. Some algorithms replace the key for the old page as well
+ * as the new page. We don't, as there's no reason to believe that the
+ * first key on the old page is any better than the key we have, and,
+ * in the case of a key being placed at index 0 causing the split, the
+ * key is unavailable.
+ *
+ * There are a maximum of 5 pages pinned at any time. We keep the left
+ * and right pages pinned while working on the parent. The 5 are the
+ * two children, left parent and right parent (when the parent splits)
+ * and the root page or the overflow key page when calling bt_preserve.
+ * This code must make sure that all pins are released other than the
+ * root page or overflow page which is unlocked elsewhere.
+ */
+ while ((parent = BT_POP(t)) != NULL) {
+ lchild = l;
+ rchild = r;
+
+ /* Get the parent page. */
+ if ((h = mpool_get(t->bt_mp, parent->pgno, 0)) == NULL)
+ goto err2;
+
+ /*
+ * The new key goes ONE AFTER the index, because the split
+ * was to the right.
+ */
+ skip = parent->index + 1;
+
+ /*
+ * Calculate the space needed on the parent page.
+ *
+ * Prefix trees: space hack when inserting into BINTERNAL
+ * pages. Retain only what's needed to distinguish between
+ * the new entry and the LAST entry on the page to its left.
+ * If the keys compare equal, retain the entire key. Note,
+ * we don't touch overflow keys, and the entire key must be
+ * retained for the next-to-left most key on the leftmost
+ * page of each level, or the search will fail. Applicable
+ * ONLY to internal pages that have leaf pages as children.
+ * Further reduction of the key between pairs of internal
+ * pages loses too much information.
+ */
+ switch (rchild->flags & P_TYPE) {
+ case P_BINTERNAL:
+ bi = GETBINTERNAL(rchild, 0);
+ nbytes = NBINTERNAL(bi->ksize);
+ break;
+ case P_BLEAF:
+ bl = GETBLEAF(rchild, 0);
+ nbytes = NBINTERNAL(bl->ksize);
+ if (t->bt_pfx && !(bl->flags & P_BIGKEY) &&
+ (h->prevpg != P_INVALID || skip > 1)) {
+ tbl = GETBLEAF(lchild, NEXTINDEX(lchild) - 1);
+ a.size = tbl->ksize;
+ a.data = tbl->bytes;
+ b.size = bl->ksize;
+ b.data = bl->bytes;
+ nksize = t->bt_pfx(&a, &b);
+ n = NBINTERNAL(nksize);
+ if (n < nbytes) {
+#ifdef STATISTICS
+ bt_pfxsaved += nbytes - n;
+#endif
+ nbytes = n;
+ } else
+ nksize = 0;
+ } else
+ nksize = 0;
+ break;
+ case P_RINTERNAL:
+ case P_RLEAF:
+ nbytes = NRINTERNAL;
+ break;
+ default:
+ abort();
+ }
+
+ /* Split the parent page if necessary or shift the indices. */
+ if ((u_int32_t)(h->upper - h->lower) < nbytes + sizeof(indx_t)) {
+ sp = h;
+ h = h->pgno == P_ROOT ?
+ bt_root(t, h, &l, &r, &skip, nbytes) :
+ bt_page(t, h, &l, &r, &skip, nbytes);
+ if (h == NULL)
+ goto err1;
+ parentsplit = 1;
+ } else {
+ if (skip < (nxtindex = NEXTINDEX(h)))
+ memmove(h->linp + skip + 1, h->linp + skip,
+ (nxtindex - skip) * sizeof(indx_t));
+ h->lower += sizeof(indx_t);
+ parentsplit = 0;
+ }
+
+ /* Insert the key into the parent page. */
+ switch (rchild->flags & P_TYPE) {
+ case P_BINTERNAL:
+ h->linp[skip] = h->upper -= nbytes;
+ dest = (char *)h + h->linp[skip];
+ memmove(dest, bi, nbytes);
+ ((BINTERNAL *)dest)->pgno = rchild->pgno;
+ break;
+ case P_BLEAF:
+ h->linp[skip] = h->upper -= nbytes;
+ dest = (char *)h + h->linp[skip];
+ WR_BINTERNAL(dest, nksize ? nksize : bl->ksize,
+ rchild->pgno, bl->flags & P_BIGKEY);
+ memmove(dest, bl->bytes, nksize ? nksize : bl->ksize);
+ if (bl->flags & P_BIGKEY) {
+ pgno_t pgno;
+ memcpy(&pgno, bl->bytes, sizeof(pgno));
+ if (bt_preserve(t, pgno) == RET_ERROR)
+ goto err1;
+ }
+ break;
+ case P_RINTERNAL:
+ /*
+ * Update the left page count. If split
+ * added at index 0, fix the correct page.
+ */
+ if (skip > 0)
+ dest = (char *)h + h->linp[skip - 1];
+ else
+ dest = (char *)l + l->linp[NEXTINDEX(l) - 1];
+ ((RINTERNAL *)dest)->nrecs = rec_total(lchild);
+ ((RINTERNAL *)dest)->pgno = lchild->pgno;
+
+ /* Update the right page count. */
+ h->linp[skip] = h->upper -= nbytes;
+ dest = (char *)h + h->linp[skip];
+ ((RINTERNAL *)dest)->nrecs = rec_total(rchild);
+ ((RINTERNAL *)dest)->pgno = rchild->pgno;
+ break;
+ case P_RLEAF:
+ /*
+ * Update the left page count. If split
+ * added at index 0, fix the correct page.
+ */
+ if (skip > 0)
+ dest = (char *)h + h->linp[skip - 1];
+ else
+ dest = (char *)l + l->linp[NEXTINDEX(l) - 1];
+ ((RINTERNAL *)dest)->nrecs = NEXTINDEX(lchild);
+ ((RINTERNAL *)dest)->pgno = lchild->pgno;
+
+ /* Update the right page count. */
+ h->linp[skip] = h->upper -= nbytes;
+ dest = (char *)h + h->linp[skip];
+ ((RINTERNAL *)dest)->nrecs = NEXTINDEX(rchild);
+ ((RINTERNAL *)dest)->pgno = rchild->pgno;
+ break;
+ default:
+ abort();
+ }
+
+ /* Unpin the held pages. */
+ if (!parentsplit) {
+ mpool_put(t->bt_mp, h, MPOOL_DIRTY);
+ break;
+ }
+
+ /* If the root page was split, make it look right. */
+ if (sp->pgno == P_ROOT &&
+ (F_ISSET(t, R_RECNO) ?
+ bt_rroot(t, sp, l, r) : bt_broot(t, sp, l, r)) == RET_ERROR)
+ goto err1;
+
+ mpool_put(t->bt_mp, lchild, MPOOL_DIRTY);
+ mpool_put(t->bt_mp, rchild, MPOOL_DIRTY);
+ }
+
+ /* Unpin the held pages. */
+ mpool_put(t->bt_mp, l, MPOOL_DIRTY);
+ mpool_put(t->bt_mp, r, MPOOL_DIRTY);
+
+ /* Clear any pages left on the stack. */
+ return (RET_SUCCESS);
+
+ /*
+ * If something fails in the above loop we were already walking back
+ * up the tree and the tree is now inconsistent. Nothing much we can
+ * do about it but release any memory we're holding.
+ */
+err1: mpool_put(t->bt_mp, lchild, MPOOL_DIRTY);
+ mpool_put(t->bt_mp, rchild, MPOOL_DIRTY);
+
+err2: mpool_put(t->bt_mp, l, 0);
+ mpool_put(t->bt_mp, r, 0);
+ __dbpanic(t->bt_dbp);
+ return (RET_ERROR);
+}
+
+/*
+ * BT_PAGE -- Split a non-root page of a btree.
+ *
+ * Parameters:
+ * t: tree
+ * h: root page
+ * lp: pointer to left page pointer
+ * rp: pointer to right page pointer
+ * skip: pointer to index to leave open
+ * ilen: insert length
+ *
+ * Returns:
+ * Pointer to page in which to insert or NULL on error.
+ */
+static PAGE *
+bt_page(BTREE *t, PAGE *h, PAGE **lp, PAGE **rp, indx_t *skip, size_t ilen)
+{
+ PAGE *l, *r, *tp;
+ pgno_t npg;
+
+#ifdef STATISTICS
+ ++bt_split;
+#endif
+ /* Put the new right page for the split into place. */
+ if ((r = __bt_new(t, &npg)) == NULL)
+ return (NULL);
+ r->pgno = npg;
+ r->lower = BTDATAOFF;
+ r->upper = t->bt_psize;
+ r->nextpg = h->nextpg;
+ r->prevpg = h->pgno;
+ r->flags = h->flags & P_TYPE;
+
+ /*
+ * If we're splitting the last page on a level because we're appending
+ * a key to it (skip is NEXTINDEX()), it's likely that the data is
+ * sorted. Adding an empty page on the side of the level is less work
+ * and can push the fill factor much higher than normal. If we're
+ * wrong it's no big deal, we'll just do the split the right way next
+ * time. It may look like it's equally easy to do a similar hack for
+ * reverse sorted data, that is, split the tree left, but it's not.
+ * Don't even try.
+ */
+ if (h->nextpg == P_INVALID && *skip == NEXTINDEX(h)) {
+#ifdef STATISTICS
+ ++bt_sortsplit;
+#endif
+ h->nextpg = r->pgno;
+ r->lower = BTDATAOFF + sizeof(indx_t);
+ *skip = 0;
+ *lp = h;
+ *rp = r;
+ return (r);
+ }
+
+ /* Put the new left page for the split into place. */
+ if ((l = (PAGE *)calloc(1, t->bt_psize)) == NULL) {
+ mpool_put(t->bt_mp, r, 0);
+ return (NULL);
+ }
+ l->pgno = h->pgno;
+ l->nextpg = r->pgno;
+ l->prevpg = h->prevpg;
+ l->lower = BTDATAOFF;
+ l->upper = t->bt_psize;
+ l->flags = h->flags & P_TYPE;
+
+ /* Fix up the previous pointer of the page after the split page. */
+ if (h->nextpg != P_INVALID) {
+ if ((tp = mpool_get(t->bt_mp, h->nextpg, 0)) == NULL) {
+ free(l);
+ /* XXX mpool_free(t->bt_mp, r->pgno); */
+ return (NULL);
+ }
+ tp->prevpg = r->pgno;
+ mpool_put(t->bt_mp, tp, MPOOL_DIRTY);
+ }
+
+ /*
+ * Split right. The key/data pairs aren't sorted in the btree page so
+ * it's simpler to copy the data from the split page onto two new pages
+ * instead of copying half the data to the right page and compacting
+ * the left page in place. Since the left page can't change, we have
+ * to swap the original and the allocated left page after the split.
+ */
+ tp = bt_psplit(t, h, l, r, skip, ilen);
+
+ /* Move the new left page onto the old left page. */
+ memmove(h, l, t->bt_psize);
+ if (tp == l)
+ tp = h;
+ free(l);
+
+ *lp = h;
+ *rp = r;
+ return (tp);
+}
+
+/*
+ * BT_ROOT -- Split the root page of a btree.
+ *
+ * Parameters:
+ * t: tree
+ * h: root page
+ * lp: pointer to left page pointer
+ * rp: pointer to right page pointer
+ * skip: pointer to index to leave open
+ * ilen: insert length
+ *
+ * Returns:
+ * Pointer to page in which to insert or NULL on error.
+ */
+static PAGE *
+bt_root(BTREE *t, PAGE *h, PAGE **lp, PAGE **rp, indx_t *skip, size_t ilen)
+{
+ PAGE *l, *r, *tp;
+ pgno_t lnpg, rnpg;
+
+#ifdef STATISTICS
+ ++bt_split;
+ ++bt_rootsplit;
+#endif
+ /* Put the new left and right pages for the split into place. */
+ if ((l = __bt_new(t, &lnpg)) == NULL ||
+ (r = __bt_new(t, &rnpg)) == NULL)
+ return (NULL);
+ l->pgno = lnpg;
+ r->pgno = rnpg;
+ l->nextpg = r->pgno;
+ r->prevpg = l->pgno;
+ l->prevpg = r->nextpg = P_INVALID;
+ l->lower = r->lower = BTDATAOFF;
+ l->upper = r->upper = t->bt_psize;
+ l->flags = r->flags = h->flags & P_TYPE;
+
+ /* Split the root page. */
+ tp = bt_psplit(t, h, l, r, skip, ilen);
+
+ *lp = l;
+ *rp = r;
+ return (tp);
+}
+
+/*
+ * BT_RROOT -- Fix up the recno root page after it has been split.
+ *
+ * Parameters:
+ * t: tree
+ * h: root page
+ * l: left page
+ * r: right page
+ *
+ * Returns:
+ * RET_ERROR, RET_SUCCESS
+ */
+static int
+bt_rroot(BTREE *t, PAGE *h, PAGE *l, PAGE *r)
+{
+ char *dest;
+
+ /* Insert the left and right keys, set the header information. */
+ h->linp[0] = h->upper = t->bt_psize - NRINTERNAL;
+ dest = (char *)h + h->upper;
+ WR_RINTERNAL(dest,
+ l->flags & P_RLEAF ? NEXTINDEX(l) : rec_total(l), l->pgno);
+
+ __PAST_END(h->linp, 1) = h->upper -= NRINTERNAL;
+ dest = (char *)h + h->upper;
+ WR_RINTERNAL(dest,
+ r->flags & P_RLEAF ? NEXTINDEX(r) : rec_total(r), r->pgno);
+
+ h->lower = BTDATAOFF + 2 * sizeof(indx_t);
+
+ /* Unpin the root page, set to recno internal page. */
+ h->flags &= ~P_TYPE;
+ h->flags |= P_RINTERNAL;
+ mpool_put(t->bt_mp, h, MPOOL_DIRTY);
+
+ return (RET_SUCCESS);
+}
+
+/*
+ * BT_BROOT -- Fix up the btree root page after it has been split.
+ *
+ * Parameters:
+ * t: tree
+ * h: root page
+ * l: left page
+ * r: right page
+ *
+ * Returns:
+ * RET_ERROR, RET_SUCCESS
+ */
+static int
+bt_broot(BTREE *t, PAGE *h, PAGE *l, PAGE *r)
+{
+ BINTERNAL *bi;
+ BLEAF *bl;
+ u_int32_t nbytes;
+ char *dest;
+
+ /*
+ * If the root page was a leaf page, change it into an internal page.
+ * We copy the key we split on (but not the key's data, in the case of
+ * a leaf page) to the new root page.
+ *
+ * The btree comparison code guarantees that the left-most key on any
+ * level of the tree is never used, so it doesn't need to be filled in.
+ */
+ nbytes = NBINTERNAL(0);
+ h->linp[0] = h->upper = t->bt_psize - nbytes;
+ dest = (char *)h + h->upper;
+ WR_BINTERNAL(dest, 0, l->pgno, 0);
+
+ switch (h->flags & P_TYPE) {
+ case P_BLEAF:
+ bl = GETBLEAF(r, 0);
+ nbytes = NBINTERNAL(bl->ksize);
+ __PAST_END(h->linp, 1) = h->upper -= nbytes;
+ dest = (char *)h + h->upper;
+ WR_BINTERNAL(dest, bl->ksize, r->pgno, 0);
+ memmove(dest, bl->bytes, bl->ksize);
+
+ /*
+ * If the key is on an overflow page, mark the overflow chain
+ * so it isn't deleted when the leaf copy of the key is deleted.
+ */
+ if (bl->flags & P_BIGKEY) {
+ pgno_t pgno;
+ memcpy(&pgno, bl->bytes, sizeof(pgno));
+ if (bt_preserve(t, pgno) == RET_ERROR)
+ return (RET_ERROR);
+ }
+ break;
+ case P_BINTERNAL:
+ bi = GETBINTERNAL(r, 0);
+ nbytes = NBINTERNAL(bi->ksize);
+ __PAST_END(h->linp, 1) = h->upper -= nbytes;
+ dest = (char *)h + h->upper;
+ memmove(dest, bi, nbytes);
+ ((BINTERNAL *)dest)->pgno = r->pgno;
+ break;
+ default:
+ abort();
+ }
+
+ /* There are two keys on the page. */
+ h->lower = BTDATAOFF + 2 * sizeof(indx_t);
+
+ /* Unpin the root page, set to btree internal page. */
+ h->flags &= ~P_TYPE;
+ h->flags |= P_BINTERNAL;
+ mpool_put(t->bt_mp, h, MPOOL_DIRTY);
+
+ return (RET_SUCCESS);
+}
+
+/*
+ * BT_PSPLIT -- Do the real work of splitting the page.
+ *
+ * Parameters:
+ * t: tree
+ * h: page to be split
+ * l: page to put lower half of data
+ * r: page to put upper half of data
+ * pskip: pointer to index to leave open
+ * ilen: insert length
+ *
+ * Returns:
+ * Pointer to page in which to insert.
+ */
+static PAGE *
+bt_psplit(BTREE *t, PAGE *h, PAGE *l, PAGE *r, indx_t *pskip, size_t ilen)
+{
+ BINTERNAL *bi;
+ BLEAF *bl;
+ CURSOR *c;
+ RLEAF *rl;
+ PAGE *rval;
+ void *src;
+ indx_t full, half, nxt, off, skip, top, used;
+ u_int32_t nbytes;
+ int bigkeycnt, isbigkey;
+
+ /*
+ * Split the data to the left and right pages. Leave the skip index
+ * open. Additionally, make some effort not to split on an overflow
+ * key. This makes internal page processing faster and can save
+ * space as overflow keys used by internal pages are never deleted.
+ */
+ bigkeycnt = 0;
+ skip = *pskip;
+ full = t->bt_psize - BTDATAOFF;
+ half = full / 2;
+ used = 0;
+ for (nxt = off = 0, top = NEXTINDEX(h); nxt < top; ++off) {
+ if (skip == off) {
+ nbytes = ilen;
+ isbigkey = 0; /* XXX: not really known. */
+ } else
+ switch (h->flags & P_TYPE) {
+ case P_BINTERNAL:
+ src = bi = GETBINTERNAL(h, nxt);
+ nbytes = NBINTERNAL(bi->ksize);
+ isbigkey = bi->flags & P_BIGKEY;
+ break;
+ case P_BLEAF:
+ src = bl = GETBLEAF(h, nxt);
+ nbytes = NBLEAF(bl);
+ isbigkey = bl->flags & P_BIGKEY;
+ break;
+ case P_RINTERNAL:
+ src = GETRINTERNAL(h, nxt);
+ nbytes = NRINTERNAL;
+ isbigkey = 0;
+ break;
+ case P_RLEAF:
+ src = rl = GETRLEAF(h, nxt);
+ nbytes = NRLEAF(rl);
+ isbigkey = 0;
+ break;
+ default:
+ abort();
+ }
+
+ /*
+ * If the key/data pairs are substantial fractions of the max
+ * possible size for the page, it's possible to get situations
+ * where we decide to try and copy too much onto the left page.
+ * Make sure that doesn't happen.
+ */
+ if ((skip <= off && used + nbytes + sizeof(indx_t) >= full) ||
+ nxt == top - 1) {
+ --off;
+ break;
+ }
+
+ /* Copy the key/data pair, if not the skipped index. */
+ if (skip != off) {
+ ++nxt;
+
+ l->linp[off] = l->upper -= nbytes;
+ memmove((char *)l + l->upper, src, nbytes);
+ }
+
+ used += nbytes + sizeof(indx_t);
+ if (used >= half) {
+ if (!isbigkey || bigkeycnt == 3)
+ break;
+ else
+ ++bigkeycnt;
+ }
+ }
+
+ /*
+ * Off is the last offset that's valid for the left page.
+ * Nxt is the first offset to be placed on the right page.
+ */
+ l->lower += (off + 1) * sizeof(indx_t);
+
+ /*
+ * If splitting the page that the cursor was on, the cursor has to be
+ * adjusted to point to the same record as before the split. If the
+ * cursor is at or past the skipped slot, the cursor is incremented by
+ * one. If the cursor is on the right page, it is decremented by the
+ * number of records split to the left page.
+ */
+ c = &t->bt_cursor;
+ if (F_ISSET(c, CURS_INIT) && c->pg.pgno == h->pgno) {
+ if (c->pg.index >= skip)
+ ++c->pg.index;
+ if (c->pg.index < nxt) /* Left page. */
+ c->pg.pgno = l->pgno;
+ else { /* Right page. */
+ c->pg.pgno = r->pgno;
+ c->pg.index -= nxt;
+ }
+ }
+
+ /*
+ * If the skipped index was on the left page, just return that page.
+ * Otherwise, adjust the skip index to reflect the new position on
+ * the right page.
+ */
+ if (skip <= off) {
+ skip = MAX_PAGE_OFFSET;
+ rval = l;
+ } else {
+ rval = r;
+ *pskip -= nxt;
+ }
+
+ for (off = 0; nxt < top; ++off) {
+ if (skip == nxt) {
+ ++off;
+ skip = MAX_PAGE_OFFSET;
+ }
+ switch (h->flags & P_TYPE) {
+ case P_BINTERNAL:
+ src = bi = GETBINTERNAL(h, nxt);
+ nbytes = NBINTERNAL(bi->ksize);
+ break;
+ case P_BLEAF:
+ src = bl = GETBLEAF(h, nxt);
+ nbytes = NBLEAF(bl);
+ break;
+ case P_RINTERNAL:
+ src = GETRINTERNAL(h, nxt);
+ nbytes = NRINTERNAL;
+ break;
+ case P_RLEAF:
+ src = rl = GETRLEAF(h, nxt);
+ nbytes = NRLEAF(rl);
+ break;
+ default:
+ abort();
+ }
+ ++nxt;
+ r->linp[off] = r->upper -= nbytes;
+ memmove((char *)r + r->upper, src, nbytes);
+ }
+ r->lower += off * sizeof(indx_t);
+
+ /* If the key is being appended to the page, adjust the index. */
+ if (skip == top)
+ r->lower += sizeof(indx_t);
+
+ return (rval);
+}
+
+/*
+ * BT_PRESERVE -- Mark a chain of pages as used by an internal node.
+ *
+ * Chains of indirect blocks pointed to by leaf nodes get reclaimed when the
+ * record that references them gets deleted. Chains pointed to by internal
+ * pages never get deleted. This routine marks a chain as pointed to by an
+ * internal page.
+ *
+ * Parameters:
+ * t: tree
+ * pg: page number of first page in the chain.
+ *
+ * Returns:
+ * RET_SUCCESS, RET_ERROR.
+ */
+static int
+bt_preserve(BTREE *t, pgno_t pg)
+{
+ PAGE *h;
+
+ if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
+ return (RET_ERROR);
+ h->flags |= P_PRESERVE;
+ mpool_put(t->bt_mp, h, MPOOL_DIRTY);
+ return (RET_SUCCESS);
+}
+
+/*
+ * REC_TOTAL -- Return the number of recno entries below a page.
+ *
+ * Parameters:
+ * h: page
+ *
+ * Returns:
+ * The number of recno entries below a page.
+ *
+ * XXX
+ * These values could be set by the bt_psplit routine. The problem is that the
+ * entry has to be popped off of the stack etc. or the values have to be passed
+ * all the way back to bt_split/bt_rroot and it's not very clean.
+ */
+static recno_t
+rec_total(PAGE *h)
+{
+ recno_t recs;
+ indx_t nxt, top;
+
+ for (recs = 0, nxt = 0, top = NEXTINDEX(h); nxt < top; ++nxt)
+ recs += GETRINTERNAL(h, nxt)->nrecs;
+ return (recs);
+}
diff --git a/lib/libc/db/btree/bt_utils.c b/lib/libc/db/btree/bt_utils.c
new file mode 100644
index 000000000000..92b76baa30f4
--- /dev/null
+++ b/lib/libc/db/btree/bt_utils.c
@@ -0,0 +1,246 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Mike Olson.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)bt_utils.c 8.8 (Berkeley) 7/20/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <db.h>
+#include "btree.h"
+
+/*
+ * __bt_ret --
+ * Build return key/data pair.
+ *
+ * Parameters:
+ * t: tree
+ * e: key/data pair to be returned
+ * key: user's key structure (NULL if not to be filled in)
+ * rkey: memory area to hold key
+ * data: user's data structure (NULL if not to be filled in)
+ * rdata: memory area to hold data
+ * copy: always copy the key/data item
+ *
+ * Returns:
+ * RET_SUCCESS, RET_ERROR.
+ */
+int
+__bt_ret(BTREE *t, EPG *e, DBT *key, DBT *rkey, DBT *data, DBT *rdata, int copy)
+{
+ BLEAF *bl;
+ void *p;
+
+ bl = GETBLEAF(e->page, e->index);
+
+ /*
+ * We must copy big keys/data to make them contigous. Otherwise,
+ * leave the page pinned and don't copy unless the user specified
+ * concurrent access.
+ */
+ if (key == NULL)
+ goto dataonly;
+
+ if (bl->flags & P_BIGKEY) {
+ if (__ovfl_get(t, bl->bytes,
+ &key->size, &rkey->data, &rkey->size))
+ return (RET_ERROR);
+ key->data = rkey->data;
+ } else if (copy || F_ISSET(t, B_DB_LOCK)) {
+ if (bl->ksize > rkey->size) {
+ p = realloc(rkey->data, bl->ksize);
+ if (p == NULL)
+ return (RET_ERROR);
+ rkey->data = p;
+ rkey->size = bl->ksize;
+ }
+ memmove(rkey->data, bl->bytes, bl->ksize);
+ key->size = bl->ksize;
+ key->data = rkey->data;
+ } else {
+ key->size = bl->ksize;
+ key->data = bl->bytes;
+ }
+
+dataonly:
+ if (data == NULL)
+ return (RET_SUCCESS);
+
+ if (bl->flags & P_BIGDATA) {
+ if (__ovfl_get(t, bl->bytes + bl->ksize,
+ &data->size, &rdata->data, &rdata->size))
+ return (RET_ERROR);
+ data->data = rdata->data;
+ } else if (copy || F_ISSET(t, B_DB_LOCK)) {
+ /* Use +1 in case the first record retrieved is 0 length. */
+ if (bl->dsize + 1 > rdata->size) {
+ p = realloc(rdata->data, bl->dsize + 1);
+ if (p == NULL)
+ return (RET_ERROR);
+ rdata->data = p;
+ rdata->size = bl->dsize + 1;
+ }
+ memmove(rdata->data, bl->bytes + bl->ksize, bl->dsize);
+ data->size = bl->dsize;
+ data->data = rdata->data;
+ } else {
+ data->size = bl->dsize;
+ data->data = bl->bytes + bl->ksize;
+ }
+
+ return (RET_SUCCESS);
+}
+
+/*
+ * __BT_CMP -- Compare a key to a given record.
+ *
+ * Parameters:
+ * t: tree
+ * k1: DBT pointer of first arg to comparison
+ * e: pointer to EPG for comparison
+ *
+ * Returns:
+ * < 0 if k1 is < record
+ * = 0 if k1 is = record
+ * > 0 if k1 is > record
+ */
+int
+__bt_cmp(BTREE *t, const DBT *k1, EPG *e)
+{
+ BINTERNAL *bi;
+ BLEAF *bl;
+ DBT k2;
+ PAGE *h;
+ void *bigkey;
+
+ /*
+ * The left-most key on internal pages, at any level of the tree, is
+ * guaranteed by the following code to be less than any user key.
+ * This saves us from having to update the leftmost key on an internal
+ * page when the user inserts a new key in the tree smaller than
+ * anything we've yet seen.
+ */
+ h = e->page;
+ if (e->index == 0 && h->prevpg == P_INVALID && !(h->flags & P_BLEAF))
+ return (1);
+
+ bigkey = NULL;
+ if (h->flags & P_BLEAF) {
+ bl = GETBLEAF(h, e->index);
+ if (bl->flags & P_BIGKEY)
+ bigkey = bl->bytes;
+ else {
+ k2.data = bl->bytes;
+ k2.size = bl->ksize;
+ }
+ } else {
+ bi = GETBINTERNAL(h, e->index);
+ if (bi->flags & P_BIGKEY)
+ bigkey = bi->bytes;
+ else {
+ k2.data = bi->bytes;
+ k2.size = bi->ksize;
+ }
+ }
+
+ if (bigkey) {
+ if (__ovfl_get(t, bigkey,
+ &k2.size, &t->bt_rdata.data, &t->bt_rdata.size))
+ return (RET_ERROR);
+ k2.data = t->bt_rdata.data;
+ }
+ return ((*t->bt_cmp)(k1, &k2));
+}
+
+/*
+ * __BT_DEFCMP -- Default comparison routine.
+ *
+ * Parameters:
+ * a: DBT #1
+ * b: DBT #2
+ *
+ * Returns:
+ * < 0 if a is < b
+ * = 0 if a is = b
+ * > 0 if a is > b
+ */
+int
+__bt_defcmp(const DBT *a, const DBT *b)
+{
+ size_t len;
+ u_char *p1, *p2;
+
+ /*
+ * XXX
+ * If a size_t doesn't fit in an int, this routine can lose.
+ * What we need is an integral type which is guaranteed to be
+ * larger than a size_t, and there is no such thing.
+ */
+ len = MIN(a->size, b->size);
+ for (p1 = a->data, p2 = b->data; len--; ++p1, ++p2)
+ if (*p1 != *p2)
+ return ((int)*p1 - (int)*p2);
+ return ((int)a->size - (int)b->size);
+}
+
+/*
+ * __BT_DEFPFX -- Default prefix routine.
+ *
+ * Parameters:
+ * a: DBT #1
+ * b: DBT #2
+ *
+ * Returns:
+ * Number of bytes needed to distinguish b from a.
+ */
+size_t
+__bt_defpfx(const DBT *a, const DBT *b)
+{
+ u_char *p1, *p2;
+ size_t cnt, len;
+
+ cnt = 1;
+ len = MIN(a->size, b->size);
+ for (p1 = a->data, p2 = b->data; len--; ++p1, ++p2, ++cnt)
+ if (*p1 != *p2)
+ return (cnt);
+
+ /* a->size must be <= b->size, or they wouldn't be in this order. */
+ return (a->size < b->size ? a->size + 1 : a->size);
+}
diff --git a/lib/libc/db/btree/btree.h b/lib/libc/db/btree/btree.h
new file mode 100644
index 000000000000..a1766dc3dce4
--- /dev/null
+++ b/lib/libc/db/btree/btree.h
@@ -0,0 +1,380 @@
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Mike Olson.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)btree.h 8.11 (Berkeley) 8/17/94
+ * $FreeBSD$
+ */
+
+/* Macros to set/clear/test flags. */
+#define F_SET(p, f) (p)->flags |= (f)
+#define F_CLR(p, f) (p)->flags &= ~(f)
+#define F_ISSET(p, f) ((p)->flags & (f))
+
+#include <mpool.h>
+
+#define DEFMINKEYPAGE (2) /* Minimum keys per page */
+#define MINCACHE (5) /* Minimum cached pages */
+#define MINPSIZE (512) /* Minimum page size */
+
+/*
+ * Page 0 of a btree file contains a copy of the meta-data. This page is also
+ * used as an out-of-band page, i.e. page pointers that point to nowhere point
+ * to page 0. Page 1 is the root of the btree.
+ */
+#define P_INVALID 0 /* Invalid tree page number. */
+#define P_META 0 /* Tree metadata page number. */
+#define P_ROOT 1 /* Tree root page number. */
+
+/*
+ * There are five page layouts in the btree: btree internal pages (BINTERNAL),
+ * btree leaf pages (BLEAF), recno internal pages (RINTERNAL), recno leaf pages
+ * (RLEAF) and overflow pages. All five page types have a page header (PAGE).
+ * This implementation requires that values within structures NOT be padded.
+ * (ANSI C permits random padding.) If your compiler pads randomly you'll have
+ * to do some work to get this package to run.
+ */
+typedef struct _page {
+ pgno_t pgno; /* this page's page number */
+ pgno_t prevpg; /* left sibling */
+ pgno_t nextpg; /* right sibling */
+
+#define P_BINTERNAL 0x01 /* btree internal page */
+#define P_BLEAF 0x02 /* leaf page */
+#define P_OVERFLOW 0x04 /* overflow page */
+#define P_RINTERNAL 0x08 /* recno internal page */
+#define P_RLEAF 0x10 /* leaf page */
+#define P_TYPE 0x1f /* type mask */
+#define P_PRESERVE 0x20 /* never delete this chain of pages */
+ u_int32_t flags;
+
+ indx_t lower; /* lower bound of free space on page */
+ indx_t upper; /* upper bound of free space on page */
+ indx_t linp[1]; /* indx_t-aligned VAR. LENGTH DATA */
+} PAGE;
+
+/* First and next index. */
+#define BTDATAOFF \
+ (sizeof(pgno_t) + sizeof(pgno_t) + sizeof(pgno_t) + \
+ sizeof(u_int32_t) + sizeof(indx_t) + sizeof(indx_t))
+#define NEXTINDEX(p) (((p)->lower - BTDATAOFF) / sizeof(indx_t))
+
+/*
+ * For pages other than overflow pages, there is an array of offsets into the
+ * rest of the page immediately following the page header. Each offset is to
+ * an item which is unique to the type of page. The h_lower offset is just
+ * past the last filled-in index. The h_upper offset is the first item on the
+ * page. Offsets are from the beginning of the page.
+ *
+ * If an item is too big to store on a single page, a flag is set and the item
+ * is a { page, size } pair such that the page is the first page of an overflow
+ * chain with size bytes of item. Overflow pages are simply bytes without any
+ * external structure.
+ *
+ * The page number and size fields in the items are pgno_t-aligned so they can
+ * be manipulated without copying. (This presumes that 32 bit items can be
+ * manipulated on this system.)
+ */
+#define LALIGN(n) (((n) + sizeof(pgno_t) - 1) & ~(sizeof(pgno_t) - 1))
+#define NOVFLSIZE (sizeof(pgno_t) + sizeof(u_int32_t))
+
+/*
+ * For the btree internal pages, the item is a key. BINTERNALs are {key, pgno}
+ * pairs, such that the key compares less than or equal to all of the records
+ * on that page. For a tree without duplicate keys, an internal page with two
+ * consecutive keys, a and b, will have all records greater than or equal to a
+ * and less than b stored on the page associated with a. Duplicate keys are
+ * somewhat special and can cause duplicate internal and leaf page records and
+ * some minor modifications of the above rule.
+ */
+typedef struct _binternal {
+ u_int32_t ksize; /* key size */
+ pgno_t pgno; /* page number stored on */
+#define P_BIGDATA 0x01 /* overflow data */
+#define P_BIGKEY 0x02 /* overflow key */
+ u_char flags;
+ char bytes[1]; /* data */
+} BINTERNAL;
+
+/* Get the page's BINTERNAL structure at index indx. */
+#define GETBINTERNAL(pg, indx) \
+ ((BINTERNAL *)((char *)(pg) + (pg)->linp[indx]))
+
+/* Get the number of bytes in the entry. */
+#define NBINTERNAL(len) \
+ LALIGN(sizeof(u_int32_t) + sizeof(pgno_t) + sizeof(u_char) + (len))
+
+/* Copy a BINTERNAL entry to the page. */
+#define WR_BINTERNAL(p, size, pgno, flags) { \
+ *(u_int32_t *)p = size; \
+ p += sizeof(u_int32_t); \
+ *(pgno_t *)p = pgno; \
+ p += sizeof(pgno_t); \
+ *(u_char *)p = flags; \
+ p += sizeof(u_char); \
+}
+
+/*
+ * For the recno internal pages, the item is a page number with the number of
+ * keys found on that page and below.
+ */
+typedef struct _rinternal {
+ recno_t nrecs; /* number of records */
+ pgno_t pgno; /* page number stored below */
+} RINTERNAL;
+
+/* Get the page's RINTERNAL structure at index indx. */
+#define GETRINTERNAL(pg, indx) \
+ ((RINTERNAL *)((char *)(pg) + (pg)->linp[indx]))
+
+/* Get the number of bytes in the entry. */
+#define NRINTERNAL \
+ LALIGN(sizeof(recno_t) + sizeof(pgno_t))
+
+/* Copy a RINTERAL entry to the page. */
+#define WR_RINTERNAL(p, nrecs, pgno) { \
+ *(recno_t *)p = nrecs; \
+ p += sizeof(recno_t); \
+ *(pgno_t *)p = pgno; \
+}
+
+/* For the btree leaf pages, the item is a key and data pair. */
+typedef struct _bleaf {
+ u_int32_t ksize; /* size of key */
+ u_int32_t dsize; /* size of data */
+ u_char flags; /* P_BIGDATA, P_BIGKEY */
+ char bytes[1]; /* data */
+} BLEAF;
+
+/* Get the page's BLEAF structure at index indx. */
+#define GETBLEAF(pg, indx) \
+ ((BLEAF *)((char *)(pg) + (pg)->linp[indx]))
+
+/* Get the number of bytes in the entry. */
+#define NBLEAF(p) NBLEAFDBT((p)->ksize, (p)->dsize)
+
+/* Get the number of bytes in the user's key/data pair. */
+#define NBLEAFDBT(ksize, dsize) \
+ LALIGN(sizeof(u_int32_t) + sizeof(u_int32_t) + sizeof(u_char) + \
+ (ksize) + (dsize))
+
+/* Copy a BLEAF entry to the page. */
+#define WR_BLEAF(p, key, data, flags) { \
+ *(u_int32_t *)p = key->size; \
+ p += sizeof(u_int32_t); \
+ *(u_int32_t *)p = data->size; \
+ p += sizeof(u_int32_t); \
+ *(u_char *)p = flags; \
+ p += sizeof(u_char); \
+ memmove(p, key->data, key->size); \
+ p += key->size; \
+ memmove(p, data->data, data->size); \
+}
+
+/* For the recno leaf pages, the item is a data entry. */
+typedef struct _rleaf {
+ u_int32_t dsize; /* size of data */
+ u_char flags; /* P_BIGDATA */
+ char bytes[1];
+} RLEAF;
+
+/* Get the page's RLEAF structure at index indx. */
+#define GETRLEAF(pg, indx) \
+ ((RLEAF *)((char *)(pg) + (pg)->linp[indx]))
+
+/* Get the number of bytes in the entry. */
+#define NRLEAF(p) NRLEAFDBT((p)->dsize)
+
+/* Get the number of bytes from the user's data. */
+#define NRLEAFDBT(dsize) \
+ LALIGN(sizeof(u_int32_t) + sizeof(u_char) + (dsize))
+
+/* Copy a RLEAF entry to the page. */
+#define WR_RLEAF(p, data, flags) { \
+ *(u_int32_t *)p = data->size; \
+ p += sizeof(u_int32_t); \
+ *(u_char *)p = flags; \
+ p += sizeof(u_char); \
+ memmove(p, data->data, data->size); \
+}
+
+/*
+ * A record in the tree is either a pointer to a page and an index in the page
+ * or a page number and an index. These structures are used as a cursor, stack
+ * entry and search returns as well as to pass records to other routines.
+ *
+ * One comment about searches. Internal page searches must find the largest
+ * record less than key in the tree so that descents work. Leaf page searches
+ * must find the smallest record greater than key so that the returned index
+ * is the record's correct position for insertion.
+ */
+typedef struct _epgno {
+ pgno_t pgno; /* the page number */
+ indx_t index; /* the index on the page */
+} EPGNO;
+
+typedef struct _epg {
+ PAGE *page; /* the (pinned) page */
+ indx_t index; /* the index on the page */
+} EPG;
+
+/*
+ * About cursors. The cursor (and the page that contained the key/data pair
+ * that it referenced) can be deleted, which makes things a bit tricky. If
+ * there are no duplicates of the cursor key in the tree (i.e. B_NODUPS is set
+ * or there simply aren't any duplicates of the key) we copy the key that it
+ * referenced when it's deleted, and reacquire a new cursor key if the cursor
+ * is used again. If there are duplicates keys, we move to the next/previous
+ * key, and set a flag so that we know what happened. NOTE: if duplicate (to
+ * the cursor) keys are added to the tree during this process, it is undefined
+ * if they will be returned or not in a cursor scan.
+ *
+ * The flags determine the possible states of the cursor:
+ *
+ * CURS_INIT The cursor references *something*.
+ * CURS_ACQUIRE The cursor was deleted, and a key has been saved so that
+ * we can reacquire the right position in the tree.
+ * CURS_AFTER, CURS_BEFORE
+ * The cursor was deleted, and now references a key/data pair
+ * that has not yet been returned, either before or after the
+ * deleted key/data pair.
+ * XXX
+ * This structure is broken out so that we can eventually offer multiple
+ * cursors as part of the DB interface.
+ */
+typedef struct _cursor {
+ EPGNO pg; /* B: Saved tree reference. */
+ DBT key; /* B: Saved key, or key.data == NULL. */
+ recno_t rcursor; /* R: recno cursor (1-based) */
+
+#define CURS_ACQUIRE 0x01 /* B: Cursor needs to be reacquired. */
+#define CURS_AFTER 0x02 /* B: Unreturned cursor after key. */
+#define CURS_BEFORE 0x04 /* B: Unreturned cursor before key. */
+#define CURS_INIT 0x08 /* RB: Cursor initialized. */
+ u_int8_t flags;
+} CURSOR;
+
+/*
+ * The metadata of the tree. The nrecs field is used only by the RECNO code.
+ * This is because the btree doesn't really need it and it requires that every
+ * put or delete call modify the metadata.
+ */
+typedef struct _btmeta {
+ u_int32_t magic; /* magic number */
+ u_int32_t version; /* version */
+ u_int32_t psize; /* page size */
+ u_int32_t free; /* page number of first free page */
+ u_int32_t nrecs; /* R: number of records */
+
+#define SAVEMETA (B_NODUPS | R_RECNO)
+ u_int32_t flags; /* bt_flags & SAVEMETA */
+} BTMETA;
+
+/* The in-memory btree/recno data structure. */
+typedef struct _btree {
+ MPOOL *bt_mp; /* memory pool cookie */
+
+ DB *bt_dbp; /* pointer to enclosing DB */
+
+ EPG bt_cur; /* current (pinned) page */
+ PAGE *bt_pinned; /* page pinned across calls */
+
+ CURSOR bt_cursor; /* cursor */
+
+#define BT_PUSH(t, p, i) { \
+ t->bt_sp->pgno = p; \
+ t->bt_sp->index = i; \
+ ++t->bt_sp; \
+}
+#define BT_POP(t) (t->bt_sp == t->bt_stack ? NULL : --t->bt_sp)
+#define BT_CLR(t) (t->bt_sp = t->bt_stack)
+ EPGNO bt_stack[50]; /* stack of parent pages */
+ EPGNO *bt_sp; /* current stack pointer */
+
+ DBT bt_rkey; /* returned key */
+ DBT bt_rdata; /* returned data */
+
+ int bt_fd; /* tree file descriptor */
+
+ pgno_t bt_free; /* next free page */
+ u_int32_t bt_psize; /* page size */
+ indx_t bt_ovflsize; /* cut-off for key/data overflow */
+ int bt_lorder; /* byte order */
+ /* sorted order */
+ enum { NOT, BACK, FORWARD } bt_order;
+ EPGNO bt_last; /* last insert */
+
+ /* B: key comparison function */
+ int (*bt_cmp)(const DBT *, const DBT *);
+ /* B: prefix comparison function */
+ size_t (*bt_pfx)(const DBT *, const DBT *);
+ /* R: recno input function */
+ int (*bt_irec)(struct _btree *, recno_t);
+
+ FILE *bt_rfp; /* R: record FILE pointer */
+ int bt_rfd; /* R: record file descriptor */
+
+ caddr_t bt_cmap; /* R: current point in mapped space */
+ caddr_t bt_smap; /* R: start of mapped space */
+ caddr_t bt_emap; /* R: end of mapped space */
+ size_t bt_msize; /* R: size of mapped region. */
+
+ recno_t bt_nrecs; /* R: number of records */
+ size_t bt_reclen; /* R: fixed record length */
+ u_char bt_bval; /* R: delimiting byte/pad character */
+
+/*
+ * NB:
+ * B_NODUPS and R_RECNO are stored on disk, and may not be changed.
+ */
+#define B_INMEM 0x00001 /* in-memory tree */
+#define B_METADIRTY 0x00002 /* need to write metadata */
+#define B_MODIFIED 0x00004 /* tree modified */
+#define B_NEEDSWAP 0x00008 /* if byte order requires swapping */
+#define B_RDONLY 0x00010 /* read-only tree */
+
+#define B_NODUPS 0x00020 /* no duplicate keys permitted */
+#define R_RECNO 0x00080 /* record oriented tree */
+
+#define R_CLOSEFP 0x00040 /* opened a file pointer */
+#define R_EOF 0x00100 /* end of input file reached. */
+#define R_FIXLEN 0x00200 /* fixed length records */
+#define R_MEMMAPPED 0x00400 /* memory mapped file. */
+#define R_INMEM 0x00800 /* in-memory file */
+#define R_MODIFIED 0x01000 /* modified file */
+#define R_RDONLY 0x02000 /* read-only file */
+
+#define B_DB_LOCK 0x04000 /* DB_LOCK specified. */
+#define B_DB_SHMEM 0x08000 /* DB_SHMEM specified. */
+#define B_DB_TXN 0x10000 /* DB_TXN specified. */
+ u_int32_t flags;
+} BTREE;
+
+#include "extern.h"
diff --git a/lib/libc/db/btree/extern.h b/lib/libc/db/btree/extern.h
new file mode 100644
index 000000000000..0abd594cacc8
--- /dev/null
+++ b/lib/libc/db/btree/extern.h
@@ -0,0 +1,67 @@
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)extern.h 8.10 (Berkeley) 7/20/94
+ * $FreeBSD$
+ */
+
+int __bt_close(DB *);
+int __bt_cmp(BTREE *, const DBT *, EPG *);
+int __bt_crsrdel(BTREE *, EPGNO *);
+int __bt_defcmp(const DBT *, const DBT *);
+size_t __bt_defpfx(const DBT *, const DBT *);
+int __bt_delete(const DB *, const DBT *, u_int);
+int __bt_dleaf(BTREE *, const DBT *, PAGE *, u_int);
+int __bt_fd(const DB *);
+int __bt_free(BTREE *, PAGE *);
+int __bt_get(const DB *, const DBT *, DBT *, u_int);
+PAGE *__bt_new(BTREE *, pgno_t *);
+void __bt_pgin(void *, pgno_t, void *);
+void __bt_pgout(void *, pgno_t, void *);
+int __bt_push(BTREE *, pgno_t, int);
+int __bt_put(const DB *dbp, DBT *, const DBT *, u_int);
+int __bt_ret(BTREE *, EPG *, DBT *, DBT *, DBT *, DBT *, int);
+EPG *__bt_search(BTREE *, const DBT *, int *);
+int __bt_seq(const DB *, DBT *, DBT *, u_int);
+void __bt_setcur(BTREE *, pgno_t, u_int);
+int __bt_split(BTREE *, PAGE *,
+ const DBT *, const DBT *, int, size_t, u_int32_t);
+int __bt_sync(const DB *, u_int);
+
+int __ovfl_delete(BTREE *, void *);
+int __ovfl_get(BTREE *, void *, size_t *, void **, size_t *);
+int __ovfl_put(BTREE *, const DBT *, pgno_t *);
+
+#ifdef DEBUG
+void __bt_dnpage(DB *, pgno_t);
+void __bt_dpage(PAGE *);
+void __bt_dump(DB *);
+#endif
+#ifdef STATISTICS
+void __bt_stat(DB *);
+#endif
diff --git a/lib/libc/db/changelog b/lib/libc/db/changelog
new file mode 100644
index 000000000000..1540ca8e0034
--- /dev/null
+++ b/lib/libc/db/changelog
@@ -0,0 +1,103 @@
+1.84 -> 1.85
+ recno: #ifdef out use of mmap, it's not portable enough.
+
+1.83 -> 1.84 Thu Aug 18 15:46:07 EDT 1994
+ recno: Rework fixed-length records so that closing and reopening
+ the file now works. Pad short records on input. Never do
+ signed comparison in recno input reading functions.
+
+1.82 -> 1.83 Tue Jul 26 15:33:44 EDT 1994
+ btree: Rework cursor deletion code yet again; bugs with
+ deleting empty pages that only contained the cursor
+ record.
+
+1.81 -> 1.82 Sat Jul 16 11:01:50 EDT 1994
+ btree: Fix bugs introduced by new cursor/deletion code.
+ Replace return kbuf/dbuf with real DBT's.
+
+1.80 -> 1.81
+ btree: Fix bugs introduced by new cursor/deletion code.
+ all: Add #defines for Purify.
+
+1.79 -> 1.80 Wed Jul 13 22:41:54 EDT 1994
+ btree Change deletion to coalesce empty pages. This is a major
+ change, cursors and duplicate pages all had to be reworked.
+ Return to a fixed stack.
+ recno: Affected by cursor changes. New cursor structures should
+ permit multiple cursors in the future.
+
+1.78 -> 1.79 Mon Jun 20 17:36:47 EDT 1994
+ all: Minor cleanups of 1.78 for porting reasons; only
+ major change was inlining check of NULL pointer
+ so that __fix_realloc goes away.
+
+1.77 -> 1.78 Thu Jun 16 19:06:43 EDT 1994
+ all: Move "standard" size typedef's into db.h.
+
+1.76 -> 1.77 Thu Jun 16 16:48:38 EDT 1994
+ hash: Delete __init_ routine, has special meaning to OSF 2.0.
+
+1.74 -> 1.76
+ all: Finish up the port to the Alpha.
+
+1.73 -> 1.74
+ recno: Don't put the record if rec_search fails, in rec_rdelete.
+ Create fixed-length intermediate records past "end" of DB
+ correctly.
+ Realloc bug when reading in fixed records.
+ all: First cut at port to Alpha (64-bit architecture) using
+ 4.4BSD basic integral types typedef's.
+ Cast allocation pointers to shut up old compilers.
+ Rework PORT directory into OS/machine directories.
+
+1.72 -> 1.73
+ btree: If enough duplicate records were inserted and then deleted
+ that internal pages had references to empty pages of the
+ duplicate keys, the search function ended up on the wrong
+ page.
+
+1.7 -> 1.72 12 Oct 1993
+ hash: Support NET/2 hash formats.
+
+1.7 -> 1.71 16 Sep 1993
+ btree/recno:
+ Fix bug in internal search routines that caused
+ return of invalid pointers.
+
+1.6 -> 1.7 07 Sep 1993
+ hash: Fixed big key overflow bugs.
+ test: Portability hacks, rewrite test script, Makefile.
+ btree/recno:
+ Stop copying non-overflow key/data pairs.
+ PORT: Break PORT directory up into per architecture/OS
+ subdirectories.
+
+1.5 -> 1.6 06 Jun 1993
+ hash: In PAIRFITS, the first comparison should look at (P)[2].
+ The hash_realloc function was walking off the end of memory.
+ The overflow page number was wrong when bumping splitpoint.
+
+1.4 -> 1.5 23 May 1993
+ hash: Set hash default fill factor dynamically.
+ recno: Fixed bug in sorted page splits.
+ Add page size parameter support.
+ Allow recno to specify the name of the underlying btree;
+ used for vi recovery.
+ btree/recno:
+ Support 64K pages.
+ btree/hash/recno:
+ Provide access to an underlying file descriptor.
+ Change sync routines to take a flag argument, recno
+ uses this to sync out the underlying btree.
+
+1.3 -> 1.4 10 May 1993
+ recno: Delete the R_CURSORLOG flag from the recno interface.
+ Zero-length record fix for non-mmap reads.
+ Try and make SIZE_T_MAX test in open portable.
+
+1.2 -> 1.3 01 May 1993
+ btree: Ignore user byte-order setting when reading already
+ existing database. Fixes to byte-order conversions.
+
+1.1 -> 1.2 15 Apr 1993
+ No bug fixes, only compatibility hacks.
diff --git a/lib/libc/db/db/Makefile.inc b/lib/libc/db/db/Makefile.inc
new file mode 100644
index 000000000000..8dcf9fe5c753
--- /dev/null
+++ b/lib/libc/db/db/Makefile.inc
@@ -0,0 +1,6 @@
+# from @(#)Makefile.inc 8.1 (Berkeley) 6/4/93
+# $FreeBSD$
+
+.PATH: ${LIBC_SRCTOP}/db/db
+
+SRCS+= db.c
diff --git a/lib/libc/db/db/db.c b/lib/libc/db/db/db.c
new file mode 100644
index 000000000000..b01ae08f37fd
--- /dev/null
+++ b/lib/libc/db/db/db.c
@@ -0,0 +1,98 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)db.c 8.4 (Berkeley) 2/21/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <stdio.h>
+
+#include <db.h>
+
+static int __dberr(void);
+
+#ifndef O_CLOEXEC
+#define O_CLOEXEC 0
+#endif
+
+DB *
+dbopen(const char *fname, int flags, int mode, DBTYPE type, const void *openinfo)
+{
+
+#define DB_FLAGS (DB_LOCK | DB_SHMEM | DB_TXN)
+#define USE_OPEN_FLAGS \
+ (O_CREAT | O_EXCL | O_EXLOCK | O_NOFOLLOW | O_NONBLOCK | \
+ O_RDONLY | O_RDWR | O_SHLOCK | O_SYNC | O_TRUNC | O_CLOEXEC)
+
+ if ((flags & ~(USE_OPEN_FLAGS | DB_FLAGS)) == 0)
+ switch (type) {
+ case DB_BTREE:
+ return (__bt_open(fname, flags & USE_OPEN_FLAGS,
+ mode, openinfo, flags & DB_FLAGS));
+ case DB_HASH:
+ return (__hash_open(fname, flags & USE_OPEN_FLAGS,
+ mode, openinfo, flags & DB_FLAGS));
+ case DB_RECNO:
+ return (__rec_open(fname, flags & USE_OPEN_FLAGS,
+ mode, openinfo, flags & DB_FLAGS));
+ }
+ errno = EINVAL;
+ return (NULL);
+}
+
+static int
+__dberr(void)
+{
+ return (RET_ERROR);
+}
+
+/*
+ * __DBPANIC -- Stop.
+ *
+ * Parameters:
+ * dbp: pointer to the DB structure.
+ */
+void
+__dbpanic(DB *dbp)
+{
+ /* The only thing that can succeed is a close. */
+ dbp->del = (int (*)(const struct __db *, const DBT*, u_int))__dberr;
+ dbp->fd = (int (*)(const struct __db *))__dberr;
+ dbp->get = (int (*)(const struct __db *, const DBT*, DBT *, u_int))__dberr;
+ dbp->put = (int (*)(const struct __db *, DBT *, const DBT *, u_int))__dberr;
+ dbp->seq = (int (*)(const struct __db *, DBT *, DBT *, u_int))__dberr;
+ dbp->sync = (int (*)(const struct __db *, u_int))__dberr;
+}
diff --git a/lib/libc/db/docs/hash.usenix.ps b/lib/libc/db/docs/hash.usenix.ps
new file mode 100644
index 000000000000..3a0cf444b1ac
--- /dev/null
+++ b/lib/libc/db/docs/hash.usenix.ps
@@ -0,0 +1,12209 @@
+%!PS-Adobe-1.0
+%%Creator: utopia:margo (& Seltzer,608-13E,8072,)
+%%Title: stdin (ditroff)
+%%CreationDate: Tue Dec 11 15:06:45 1990
+%%EndComments
+% @(#)psdit.pro 1.3 4/15/88
+% lib/psdit.pro -- prolog for psdit (ditroff) files
+% Copyright (c) 1984, 1985 Adobe Systems Incorporated. All Rights Reserved.
+% last edit: shore Sat Nov 23 20:28:03 1985
+% RCSID: $FreeBSD$
+
+% Changed by Edward Wang (edward@ucbarpa.berkeley.edu) to handle graphics,
+% 17 Feb, 87.
+
+/$DITroff 140 dict def $DITroff begin
+/fontnum 1 def /fontsize 10 def /fontheight 10 def /fontslant 0 def
+/xi{0 72 11 mul translate 72 resolution div dup neg scale 0 0 moveto
+ /fontnum 1 def /fontsize 10 def /fontheight 10 def /fontslant 0 def F
+ /pagesave save def}def
+/PB{save /psv exch def currentpoint translate
+ resolution 72 div dup neg scale 0 0 moveto}def
+/PE{psv restore}def
+/arctoobig 90 def /arctoosmall .05 def
+/m1 matrix def /m2 matrix def /m3 matrix def /oldmat matrix def
+/tan{dup sin exch cos div}def
+/point{resolution 72 div mul}def
+/dround {transform round exch round exch itransform}def
+/xT{/devname exch def}def
+/xr{/mh exch def /my exch def /resolution exch def}def
+/xp{}def
+/xs{docsave restore end}def
+/xt{}def
+/xf{/fontname exch def /slotno exch def fontnames slotno get fontname eq not
+ {fonts slotno fontname findfont put fontnames slotno fontname put}if}def
+/xH{/fontheight exch def F}def
+/xS{/fontslant exch def F}def
+/s{/fontsize exch def /fontheight fontsize def F}def
+/f{/fontnum exch def F}def
+/F{fontheight 0 le{/fontheight fontsize def}if
+ fonts fontnum get fontsize point 0 0 fontheight point neg 0 0 m1 astore
+ fontslant 0 ne{1 0 fontslant tan 1 0 0 m2 astore m3 concatmatrix}if
+ makefont setfont .04 fontsize point mul 0 dround pop setlinewidth}def
+/X{exch currentpoint exch pop moveto show}def
+/N{3 1 roll moveto show}def
+/Y{exch currentpoint pop exch moveto show}def
+/S{show}def
+/ditpush{}def/ditpop{}def
+/AX{3 -1 roll currentpoint exch pop moveto 0 exch ashow}def
+/AN{4 2 roll moveto 0 exch ashow}def
+/AY{3 -1 roll currentpoint pop exch moveto 0 exch ashow}def
+/AS{0 exch ashow}def
+/MX{currentpoint exch pop moveto}def
+/MY{currentpoint pop exch moveto}def
+/MXY{moveto}def
+/cb{pop}def % action on unknown char -- nothing for now
+/n{}def/w{}def
+/p{pop showpage pagesave restore /pagesave save def}def
+/Dt{/Dlinewidth exch def}def 1 Dt
+/Ds{/Ddash exch def}def -1 Ds
+/Di{/Dstipple exch def}def 1 Di
+/Dsetlinewidth{2 Dlinewidth mul setlinewidth}def
+/Dsetdash{Ddash 4 eq{[8 12]}{Ddash 16 eq{[32 36]}
+ {Ddash 20 eq{[32 12 8 12]}{[]}ifelse}ifelse}ifelse 0 setdash}def
+/Dstroke{gsave Dsetlinewidth Dsetdash 1 setlinecap stroke grestore
+ currentpoint newpath moveto}def
+/Dl{rlineto Dstroke}def
+/arcellipse{/diamv exch def /diamh exch def oldmat currentmatrix pop
+ currentpoint translate 1 diamv diamh div scale /rad diamh 2 div def
+ currentpoint exch rad add exch rad -180 180 arc oldmat setmatrix}def
+/Dc{dup arcellipse Dstroke}def
+/De{arcellipse Dstroke}def
+/Da{/endv exch def /endh exch def /centerv exch def /centerh exch def
+ /cradius centerv centerv mul centerh centerh mul add sqrt def
+ /eradius endv endv mul endh endh mul add sqrt def
+ /endang endv endh atan def
+ /startang centerv neg centerh neg atan def
+ /sweep startang endang sub dup 0 lt{360 add}if def
+ sweep arctoobig gt
+ {/midang startang sweep 2 div sub def /midrad cradius eradius add 2 div def
+ /midh midang cos midrad mul def /midv midang sin midrad mul def
+ midh neg midv neg endh endv centerh centerv midh midv Da
+ Da}
+ {sweep arctoosmall ge
+ {/controldelt 1 sweep 2 div cos sub 3 sweep 2 div sin mul div 4 mul def
+ centerv neg controldelt mul centerh controldelt mul
+ endv neg controldelt mul centerh add endh add
+ endh controldelt mul centerv add endv add
+ centerh endh add centerv endv add rcurveto Dstroke}
+ {centerh endh add centerv endv add rlineto Dstroke}
+ ifelse}
+ ifelse}def
+/Dpatterns[
+[%cf[widthbits]
+[8<0000000000000010>]
+[8<0411040040114000>]
+[8<0204081020408001>]
+[8<0000103810000000>]
+[8<6699996666999966>]
+[8<0000800100001008>]
+[8<81c36666c3810000>]
+[8<0f0e0c0800000000>]
+[8<0000000000000010>]
+[8<0411040040114000>]
+[8<0204081020408001>]
+[8<0000001038100000>]
+[8<6699996666999966>]
+[8<0000800100001008>]
+[8<81c36666c3810000>]
+[8<0f0e0c0800000000>]
+[8<0042660000246600>]
+[8<0000990000990000>]
+[8<0804020180402010>]
+[8<2418814242811824>]
+[8<6699996666999966>]
+[8<8000000008000000>]
+[8<00001c3e363e1c00>]
+[8<0000000000000000>]
+[32<00000040000000c00000004000000040000000e0000000000000000000000000>]
+[32<00000000000060000000900000002000000040000000f0000000000000000000>]
+[32<000000000000000000e0000000100000006000000010000000e0000000000000>]
+[32<00000000000000002000000060000000a0000000f00000002000000000000000>]
+[32<0000000e0000000000000000000000000000000f000000080000000e00000001>]
+[32<0000090000000600000000000000000000000000000007000000080000000e00>]
+[32<00010000000200000004000000040000000000000000000000000000000f0000>]
+[32<0900000006000000090000000600000000000000000000000000000006000000>]]
+[%ug
+[8<0000020000000000>]
+[8<0000020000002000>]
+[8<0004020000002000>]
+[8<0004020000402000>]
+[8<0004060000402000>]
+[8<0004060000406000>]
+[8<0006060000406000>]
+[8<0006060000606000>]
+[8<00060e0000606000>]
+[8<00060e000060e000>]
+[8<00070e000060e000>]
+[8<00070e000070e000>]
+[8<00070e020070e000>]
+[8<00070e020070e020>]
+[8<04070e020070e020>]
+[8<04070e024070e020>]
+[8<04070e064070e020>]
+[8<04070e064070e060>]
+[8<06070e064070e060>]
+[8<06070e066070e060>]
+[8<06070f066070e060>]
+[8<06070f066070f060>]
+[8<060f0f066070f060>]
+[8<060f0f0660f0f060>]
+[8<060f0f0760f0f060>]
+[8<060f0f0760f0f070>]
+[8<0e0f0f0760f0f070>]
+[8<0e0f0f07e0f0f070>]
+[8<0e0f0f0fe0f0f070>]
+[8<0e0f0f0fe0f0f0f0>]
+[8<0f0f0f0fe0f0f0f0>]
+[8<0f0f0f0ff0f0f0f0>]
+[8<1f0f0f0ff0f0f0f0>]
+[8<1f0f0f0ff1f0f0f0>]
+[8<1f0f0f8ff1f0f0f0>]
+[8<1f0f0f8ff1f0f0f8>]
+[8<9f0f0f8ff1f0f0f8>]
+[8<9f0f0f8ff9f0f0f8>]
+[8<9f0f0f9ff9f0f0f8>]
+[8<9f0f0f9ff9f0f0f9>]
+[8<9f8f0f9ff9f0f0f9>]
+[8<9f8f0f9ff9f8f0f9>]
+[8<9f8f1f9ff9f8f0f9>]
+[8<9f8f1f9ff9f8f1f9>]
+[8<bf8f1f9ff9f8f1f9>]
+[8<bf8f1f9ffbf8f1f9>]
+[8<bf8f1fdffbf8f1f9>]
+[8<bf8f1fdffbf8f1fd>]
+[8<ff8f1fdffbf8f1fd>]
+[8<ff8f1fdffff8f1fd>]
+[8<ff8f1ffffff8f1fd>]
+[8<ff8f1ffffff8f1ff>]
+[8<ff9f1ffffff8f1ff>]
+[8<ff9f1ffffff9f1ff>]
+[8<ff9f9ffffff9f1ff>]
+[8<ff9f9ffffff9f9ff>]
+[8<ffbf9ffffff9f9ff>]
+[8<ffbf9ffffffbf9ff>]
+[8<ffbfdffffffbf9ff>]
+[8<ffbfdffffffbfdff>]
+[8<ffffdffffffbfdff>]
+[8<ffffdffffffffdff>]
+[8<fffffffffffffdff>]
+[8<ffffffffffffffff>]]
+[%mg
+[8<8000000000000000>]
+[8<0822080080228000>]
+[8<0204081020408001>]
+[8<40e0400000000000>]
+[8<66999966>]
+[8<8001000010080000>]
+[8<81c36666c3810000>]
+[8<f0e0c08000000000>]
+[16<07c00f801f003e007c00f800f001e003c007800f001f003e007c00f801f003e0>]
+[16<1f000f8007c003e001f000f8007c003e001f800fc007e003f001f8007c003e00>]
+[8<c3c300000000c3c3>]
+[16<0040008001000200040008001000200040008000000100020004000800100020>]
+[16<0040002000100008000400020001800040002000100008000400020001000080>]
+[16<1fc03fe07df0f8f8f07de03fc01f800fc01fe03ff07df8f87df03fe01fc00f80>]
+[8<80>]
+[8<8040201000000000>]
+[8<84cc000048cc0000>]
+[8<9900009900000000>]
+[8<08040201804020100800020180002010>]
+[8<2418814242811824>]
+[8<66999966>]
+[8<8000000008000000>]
+[8<70f8d8f870000000>]
+[8<0814224180402010>]
+[8<aa00440a11a04400>]
+[8<018245aa45820100>]
+[8<221c224180808041>]
+[8<88000000>]
+[8<0855800080550800>]
+[8<2844004482440044>]
+[8<0810204080412214>]
+[8<00>]]]def
+/Dfill{
+ transform /maxy exch def /maxx exch def
+ transform /miny exch def /minx exch def
+ minx maxx gt{/minx maxx /maxx minx def def}if
+ miny maxy gt{/miny maxy /maxy miny def def}if
+ Dpatterns Dstipple 1 sub get exch 1 sub get
+ aload pop /stip exch def /stipw exch def /stiph 128 def
+ /imatrix[stipw 0 0 stiph 0 0]def
+ /tmatrix[stipw 0 0 stiph 0 0]def
+ /minx minx cvi stiph idiv stiph mul def
+ /miny miny cvi stipw idiv stipw mul def
+ gsave eoclip 0 setgray
+ miny stiph maxy{
+ tmatrix exch 5 exch put
+ minx stipw maxx{
+ tmatrix exch 4 exch put tmatrix setmatrix
+ stipw stiph true imatrix {stip} imagemask
+ }for
+ }for
+ grestore
+}def
+/Dp{Dfill Dstroke}def
+/DP{Dfill currentpoint newpath moveto}def
+end
+
+/ditstart{$DITroff begin
+ /nfonts 60 def % NFONTS makedev/ditroff dependent!
+ /fonts[nfonts{0}repeat]def
+ /fontnames[nfonts{()}repeat]def
+/docsave save def
+}def
+
+% character outcalls
+/oc{
+ /pswid exch def /cc exch def /name exch def
+ /ditwid pswid fontsize mul resolution mul 72000 div def
+ /ditsiz fontsize resolution mul 72 div def
+ ocprocs name known{ocprocs name get exec}{name cb}ifelse
+}def
+/fractm [.65 0 0 .6 0 0] def
+/fraction{
+ /fden exch def /fnum exch def gsave /cf currentfont def
+ cf fractm makefont setfont 0 .3 dm 2 copy neg rmoveto
+ fnum show rmoveto currentfont cf setfont(\244)show setfont fden show
+ grestore ditwid 0 rmoveto
+}def
+/oce{grestore ditwid 0 rmoveto}def
+/dm{ditsiz mul}def
+/ocprocs 50 dict def ocprocs begin
+(14){(1)(4)fraction}def
+(12){(1)(2)fraction}def
+(34){(3)(4)fraction}def
+(13){(1)(3)fraction}def
+(23){(2)(3)fraction}def
+(18){(1)(8)fraction}def
+(38){(3)(8)fraction}def
+(58){(5)(8)fraction}def
+(78){(7)(8)fraction}def
+(sr){gsave 0 .06 dm rmoveto(\326)show oce}def
+(is){gsave 0 .15 dm rmoveto(\362)show oce}def
+(->){gsave 0 .02 dm rmoveto(\256)show oce}def
+(<-){gsave 0 .02 dm rmoveto(\254)show oce}def
+(==){gsave 0 .05 dm rmoveto(\272)show oce}def
+(uc){gsave currentpoint 400 .009 dm mul add translate
+ 8 -8 scale ucseal oce}def
+end
+
+% an attempt at a PostScript FONT to implement ditroff special chars
+% this will enable us to
+% cache the little buggers
+% generate faster, more compact PS out of psdit
+% confuse everyone (including myself)!
+50 dict dup begin
+/FontType 3 def
+/FontName /DIThacks def
+/FontMatrix [.001 0 0 .001 0 0] def
+/FontBBox [-260 -260 900 900] def% a lie but ...
+/Encoding 256 array def
+0 1 255{Encoding exch /.notdef put}for
+Encoding
+ dup 8#040/space put %space
+ dup 8#110/rc put %right ceil
+ dup 8#111/lt put %left top curl
+ dup 8#112/bv put %bold vert
+ dup 8#113/lk put %left mid curl
+ dup 8#114/lb put %left bot curl
+ dup 8#115/rt put %right top curl
+ dup 8#116/rk put %right mid curl
+ dup 8#117/rb put %right bot curl
+ dup 8#120/rf put %right floor
+ dup 8#121/lf put %left floor
+ dup 8#122/lc put %left ceil
+ dup 8#140/sq put %square
+ dup 8#141/bx put %box
+ dup 8#142/ci put %circle
+ dup 8#143/br put %box rule
+ dup 8#144/rn put %root extender
+ dup 8#145/vr put %vertical rule
+ dup 8#146/ob put %outline bullet
+ dup 8#147/bu put %bullet
+ dup 8#150/ru put %rule
+ dup 8#151/ul put %underline
+ pop
+/DITfd 100 dict def
+/BuildChar{0 begin
+ /cc exch def /fd exch def
+ /charname fd /Encoding get cc get def
+ /charwid fd /Metrics get charname get def
+ /charproc fd /CharProcs get charname get def
+ charwid 0 fd /FontBBox get aload pop setcachedevice
+ 2 setlinejoin 40 setlinewidth
+ newpath 0 0 moveto gsave charproc grestore
+ end}def
+/BuildChar load 0 DITfd put
+/CharProcs 50 dict def
+CharProcs begin
+/space{}def
+/.notdef{}def
+/ru{500 0 rls}def
+/rn{0 840 moveto 500 0 rls}def
+/vr{0 800 moveto 0 -770 rls}def
+/bv{0 800 moveto 0 -1000 rls}def
+/br{0 840 moveto 0 -1000 rls}def
+/ul{0 -140 moveto 500 0 rls}def
+/ob{200 250 rmoveto currentpoint newpath 200 0 360 arc closepath stroke}def
+/bu{200 250 rmoveto currentpoint newpath 200 0 360 arc closepath fill}def
+/sq{80 0 rmoveto currentpoint dround newpath moveto
+ 640 0 rlineto 0 640 rlineto -640 0 rlineto closepath stroke}def
+/bx{80 0 rmoveto currentpoint dround newpath moveto
+ 640 0 rlineto 0 640 rlineto -640 0 rlineto closepath fill}def
+/ci{500 360 rmoveto currentpoint newpath 333 0 360 arc
+ 50 setlinewidth stroke}def
+
+/lt{0 -200 moveto 0 550 rlineto currx 800 2cx s4 add exch s4 a4p stroke}def
+/lb{0 800 moveto 0 -550 rlineto currx -200 2cx s4 add exch s4 a4p stroke}def
+/rt{0 -200 moveto 0 550 rlineto currx 800 2cx s4 sub exch s4 a4p stroke}def
+/rb{0 800 moveto 0 -500 rlineto currx -200 2cx s4 sub exch s4 a4p stroke}def
+/lk{0 800 moveto 0 300 -300 300 s4 arcto pop pop 1000 sub
+ 0 300 4 2 roll s4 a4p 0 -200 lineto stroke}def
+/rk{0 800 moveto 0 300 s2 300 s4 arcto pop pop 1000 sub
+ 0 300 4 2 roll s4 a4p 0 -200 lineto stroke}def
+/lf{0 800 moveto 0 -1000 rlineto s4 0 rls}def
+/rf{0 800 moveto 0 -1000 rlineto s4 neg 0 rls}def
+/lc{0 -200 moveto 0 1000 rlineto s4 0 rls}def
+/rc{0 -200 moveto 0 1000 rlineto s4 neg 0 rls}def
+end
+
+/Metrics 50 dict def Metrics begin
+/.notdef 0 def
+/space 500 def
+/ru 500 def
+/br 0 def
+/lt 416 def
+/lb 416 def
+/rt 416 def
+/rb 416 def
+/lk 416 def
+/rk 416 def
+/rc 416 def
+/lc 416 def
+/rf 416 def
+/lf 416 def
+/bv 416 def
+/ob 350 def
+/bu 350 def
+/ci 750 def
+/bx 750 def
+/sq 750 def
+/rn 500 def
+/ul 500 def
+/vr 0 def
+end
+
+DITfd begin
+/s2 500 def /s4 250 def /s3 333 def
+/a4p{arcto pop pop pop pop}def
+/2cx{2 copy exch}def
+/rls{rlineto stroke}def
+/currx{currentpoint pop}def
+/dround{transform round exch round exch itransform} def
+end
+end
+/DIThacks exch definefont pop
+ditstart
+(psc)xT
+576 1 1 xr
+1(Times-Roman)xf 1 f
+2(Times-Italic)xf 2 f
+3(Times-Bold)xf 3 f
+4(Times-BoldItalic)xf 4 f
+5(Helvetica)xf 5 f
+6(Helvetica-Bold)xf 6 f
+7(Courier)xf 7 f
+8(Courier-Bold)xf 8 f
+9(Symbol)xf 9 f
+10(DIThacks)xf 10 f
+10 s
+1 f
+xi
+%%EndProlog
+
+%%Page: 1 1
+10 s 10 xH 0 xS 1 f
+3 f
+22 s
+1249 626(A)N
+1420(N)X
+1547(ew)X
+1796(H)X
+1933(ashing)X
+2467(P)X
+2574(ackage)X
+3136(for)X
+3405(U)X
+3532(N)X
+3659(IX)X
+2 f
+20 s
+3855 562(1)N
+1 f
+12 s
+1607 779(Margo)N
+1887(Seltzer)X
+9 f
+2179(-)X
+1 f
+2256(University)X
+2686(of)X
+2790(California,)X
+3229(Berkeley)X
+2015 875(Ozan)N
+2242(Yigit)X
+9 f
+2464(-)X
+1 f
+2541(York)X
+2762(University)X
+3 f
+2331 1086(ABSTRACT)N
+1 f
+10 s
+1152 1222(UNIX)N
+1385(support)X
+1657(of)X
+1756(disk)X
+1921(oriented)X
+2216(hashing)X
+2497(was)X
+2654(originally)X
+2997(provided)X
+3314(by)X
+2 f
+3426(dbm)X
+1 f
+3595([ATT79])X
+3916(and)X
+1152 1310(subsequently)N
+1595(improved)X
+1927(upon)X
+2112(in)X
+2 f
+2199(ndbm)X
+1 f
+2402([BSD86].)X
+2735(In)X
+2826(AT&T)X
+3068(System)X
+3327(V,)X
+3429(in-memory)X
+3809(hashed)X
+1152 1398(storage)N
+1420(and)X
+1572(access)X
+1814(support)X
+2090(was)X
+2251(added)X
+2479(in)X
+2577(the)X
+2 f
+2711(hsearch)X
+1 f
+3000(library)X
+3249(routines)X
+3542([ATT85].)X
+3907(The)X
+1152 1486(result)N
+1367(is)X
+1457(a)X
+1530(system)X
+1789(with)X
+1968(two)X
+2125(incompatible)X
+2580(hashing)X
+2865(schemes,)X
+3193(each)X
+3377(with)X
+3555(its)X
+3666(own)X
+3840(set)X
+3965(of)X
+1152 1574(shortcomings.)N
+1152 1688(This)N
+1316(paper)X
+1517(presents)X
+1802(the)X
+1922(design)X
+2152(and)X
+2289(performance)X
+2717(characteristics)X
+3198(of)X
+3286(a)X
+3343(new)X
+3498(hashing)X
+3768(package)X
+1152 1776(providing)N
+1483(a)X
+1539(superset)X
+1822(of)X
+1909(the)X
+2027(functionality)X
+2456(provided)X
+2761(by)X
+2 f
+2861(dbm)X
+1 f
+3019(and)X
+2 f
+3155(hsearch)X
+1 f
+3409(.)X
+3469(The)X
+3614(new)X
+3768(package)X
+1152 1864(uses)N
+1322(linear)X
+1537(hashing)X
+1818(to)X
+1912(provide)X
+2189(ef\256cient)X
+2484(support)X
+2755(of)X
+2853(both)X
+3026(memory)X
+3324(based)X
+3538(and)X
+3685(disk)X
+3849(based)X
+1152 1952(hash)N
+1319(tables)X
+1526(with)X
+1688(performance)X
+2115(superior)X
+2398(to)X
+2480(both)X
+2 f
+2642(dbm)X
+1 f
+2800(and)X
+2 f
+2936(hsearch)X
+1 f
+3210(under)X
+3413(most)X
+3588(conditions.)X
+3 f
+1380 2128(Introduction)N
+1 f
+892 2260(Current)N
+1196(UNIX)X
+1456(systems)X
+1768(offer)X
+1984(two)X
+2163(forms)X
+2409(of)X
+720 2348(hashed)N
+973(data)X
+1137(access.)X
+2 f
+1413(Dbm)X
+1 f
+1599(and)X
+1745(its)X
+1850(derivatives)X
+2231(provide)X
+720 2436(keyed)N
+939(access)X
+1171(to)X
+1259(disk)X
+1418(resident)X
+1698(data)X
+1858(while)X
+2 f
+2062(hsearch)X
+1 f
+2342(pro-)X
+720 2524(vides)N
+929(access)X
+1175(for)X
+1309(memory)X
+1616(resident)X
+1910(data.)X
+2124(These)X
+2356(two)X
+720 2612(access)N
+979(methods)X
+1302(are)X
+1453(incompatible)X
+1923(in)X
+2037(that)X
+2209(memory)X
+720 2700(resident)N
+1011(hash)X
+1195(tables)X
+1419(may)X
+1593(not)X
+1731(be)X
+1843(stored)X
+2075(on)X
+2191(disk)X
+2360(and)X
+720 2788(disk)N
+884(resident)X
+1169(tables)X
+1387(cannot)X
+1632(be)X
+1739(read)X
+1909(into)X
+2063(memory)X
+2360(and)X
+720 2876(accessed)N
+1022(using)X
+1215(the)X
+1333(in-memory)X
+1709(routines.)X
+2 f
+892 2990(Dbm)N
+1 f
+1091(has)X
+1241(several)X
+1512(shortcomings.)X
+2026(Since)X
+2247(data)X
+2423(is)X
+720 3078(assumed)N
+1032(to)X
+1130(be)X
+1242(disk)X
+1411(resident,)X
+1721(each)X
+1905(access)X
+2146(requires)X
+2440(a)X
+720 3166(system)N
+963(call,)X
+1120(and)X
+1257(almost)X
+1491(certainly,)X
+1813(a)X
+1869(disk)X
+2022(operation.)X
+2365(For)X
+720 3254(extremely)N
+1072(large)X
+1264(databases,)X
+1623(where)X
+1851(caching)X
+2131(is)X
+2214(unlikely)X
+720 3342(to)N
+810(be)X
+914(effective,)X
+1244(this)X
+1386(is)X
+1466(acceptable,)X
+1853(however,)X
+2177(when)X
+2378(the)X
+720 3430(database)N
+1022(is)X
+1100(small)X
+1298(\(i.e.)X
+1447(the)X
+1569(password)X
+1896(\256le\),)X
+2069(performance)X
+720 3518(improvements)N
+1204(can)X
+1342(be)X
+1443(obtained)X
+1744(through)X
+2018(caching)X
+2293(pages)X
+720 3606(of)N
+818(the)X
+947(database)X
+1255(in)X
+1348(memory.)X
+1685(In)X
+1782(addition,)X
+2 f
+2094(dbm)X
+1 f
+2262(cannot)X
+720 3694(store)N
+902(data)X
+1062(items)X
+1261(whose)X
+1492(total)X
+1660(key)X
+1802(and)X
+1943(data)X
+2102(size)X
+2252(exceed)X
+720 3782(the)N
+850(page)X
+1034(size)X
+1191(of)X
+1290(the)X
+1420(hash)X
+1599(table.)X
+1827(Similarly,)X
+2176(if)X
+2257(two)X
+2409(or)X
+720 3870(more)N
+907(keys)X
+1076(produce)X
+1357(the)X
+1477(same)X
+1664(hash)X
+1833(value)X
+2029(and)X
+2166(their)X
+2334(total)X
+720 3958(size)N
+876(exceeds)X
+1162(the)X
+1291(page)X
+1474(size,)X
+1650(the)X
+1779(table)X
+1966(cannot)X
+2210(store)X
+2396(all)X
+720 4046(the)N
+838(colliding)X
+1142(keys.)X
+892 4160(The)N
+1050(in-memory)X
+2 f
+1439(hsearch)X
+1 f
+1725(routines)X
+2015(have)X
+2199(different)X
+720 4248(shortcomings.)N
+1219(First,)X
+1413(the)X
+1539(notion)X
+1771(of)X
+1865(a)X
+1928(single)X
+2146(hash)X
+2320(table)X
+720 4336(is)N
+807(embedded)X
+1171(in)X
+1266(the)X
+1397(interface,)X
+1732(preventing)X
+2108(an)X
+2217(applica-)X
+720 4424(tion)N
+902(from)X
+1116(accessing)X
+1482(multiple)X
+1806(tables)X
+2050(concurrently.)X
+720 4512(Secondly,)N
+1063(the)X
+1186(routine)X
+1438(to)X
+1525(create)X
+1743(a)X
+1804(hash)X
+1976(table)X
+2157(requires)X
+2440(a)X
+720 4600(parameter)N
+1066(which)X
+1286(declares)X
+1573(the)X
+1694(size)X
+1842(of)X
+1932(the)X
+2053(hash)X
+2223(table.)X
+2422(If)X
+720 4688(this)N
+856(size)X
+1001(is)X
+1074(set)X
+1183(too)X
+1305(low,)X
+1465(performance)X
+1892(degradation)X
+2291(or)X
+2378(the)X
+720 4776(inability)N
+1008(to)X
+1092(add)X
+1230(items)X
+1425(to)X
+1509(the)X
+1628(table)X
+1805(may)X
+1964(result.)X
+2223(In)X
+2311(addi-)X
+720 4864(tion,)N
+2 f
+910(hsearch)X
+1 f
+1210(requires)X
+1515(that)X
+1681(the)X
+1825(application)X
+2226(allocate)X
+720 4952(memory)N
+1037(for)X
+1181(the)X
+1329(key)X
+1495(and)X
+1661(data)X
+1845(items.)X
+2108(Lastly,)X
+2378(the)X
+2 f
+720 5040(hsearch)N
+1 f
+1013(routines)X
+1310(provide)X
+1594(no)X
+1713(interface)X
+2034(to)X
+2135(store)X
+2329(hash)X
+720 5128(tables)N
+927(on)X
+1027(disk.)X
+16 s
+720 5593 MXY
+864 0 Dl
+2 f
+8 s
+760 5648(1)N
+1 f
+9 s
+5673(UNIX)Y
+990(is)X
+1056(a)X
+1106(registered)X
+1408(trademark)X
+1718(of)X
+1796(AT&T.)X
+10 s
+2878 2128(The)N
+3032(goal)X
+3199(of)X
+3295(our)X
+3431(work)X
+3625(was)X
+3779(to)X
+3870(design)X
+4108(and)X
+4253(imple-)X
+2706 2216(ment)N
+2900(a)X
+2970(new)X
+3138(package)X
+3436(that)X
+3590(provides)X
+3899(a)X
+3968(superset)X
+4264(of)X
+4364(the)X
+2706 2304(functionality)N
+3144(of)X
+3240(both)X
+2 f
+3411(dbm)X
+1 f
+3578(and)X
+2 f
+3723(hsearch)X
+1 f
+3977(.)X
+4045(The)X
+4198(package)X
+2706 2392(had)N
+2871(to)X
+2982(overcome)X
+3348(the)X
+3495(interface)X
+3826(shortcomings)X
+4306(cited)X
+2706 2480(above)N
+2930(and)X
+3078(its)X
+3185(implementation)X
+3719(had)X
+3867(to)X
+3961(provide)X
+4238(perfor-)X
+2706 2568(mance)N
+2942(equal)X
+3142(or)X
+3235(superior)X
+3524(to)X
+3612(that)X
+3758(of)X
+3851(the)X
+3975(existing)X
+4253(imple-)X
+2706 2656(mentations.)N
+3152(In)X
+3274(order)X
+3498(to)X
+3614(provide)X
+3913(a)X
+4003(compact)X
+4329(disk)X
+2706 2744(representation,)N
+3224(graceful)X
+3531(table)X
+3729(growth,)X
+4018(and)X
+4176(expected)X
+2706 2832(constant)N
+3033(time)X
+3234(performance,)X
+3720(we)X
+3873(selected)X
+4191(Litwin's)X
+2706 2920(linear)N
+2923(hashing)X
+3206(algorithm)X
+3551([LAR88,)X
+3872(LIT80].)X
+4178(We)X
+4324(then)X
+2706 3008(enhanced)N
+3037(the)X
+3161(algorithm)X
+3498(to)X
+3586(handle)X
+3826(page)X
+4004(over\257ows)X
+4346(and)X
+2706 3096(large)N
+2900(key)X
+3049(handling)X
+3362(with)X
+3537(a)X
+3606(single)X
+3830(mechanism,)X
+4248(named)X
+2706 3184(buddy-in-waiting.)N
+3 f
+2975 3338(Existing)N
+3274(UNIX)X
+3499(Hashing)X
+3802(Techniques)X
+1 f
+2878 3470(Over)N
+3076(the)X
+3210(last)X
+3357(decade,)X
+3637(several)X
+3901(dynamic)X
+4213(hashing)X
+2706 3558(schemes)N
+3000(have)X
+3174(been)X
+3348(developed)X
+3700(for)X
+3816(the)X
+3936(UNIX)X
+4159(timeshar-)X
+2706 3646(ing)N
+2856(system,)X
+3146(starting)X
+3433(with)X
+3622(the)X
+3767(inclusion)X
+4107(of)X
+2 f
+4221(dbm)X
+1 f
+4359(,)X
+4426(a)X
+2706 3734(minimal)N
+3008(database)X
+3321(library)X
+3571(written)X
+3834(by)X
+3950(Ken)X
+4120(Thompson)X
+2706 3822([THOM90],)N
+3141(in)X
+3248(the)X
+3391(Seventh)X
+3694(Edition)X
+3974(UNIX)X
+4220(system.)X
+2706 3910(Since)N
+2916(then,)X
+3106(an)X
+3214(extended)X
+3536(version)X
+3804(of)X
+3903(the)X
+4032(same)X
+4228(library,)X
+2 f
+2706 3998(ndbm)N
+1 f
+2884(,)X
+2933(and)X
+3078(a)X
+3142(public-domain)X
+3637(clone)X
+3839(of)X
+3934(the)X
+4060(latter,)X
+2 f
+4273(sdbm)X
+1 f
+4442(,)X
+2706 4086(have)N
+2902(been)X
+3098(developed.)X
+3491(Another)X
+3797 0.1645(interface-compatible)AX
+2706 4174(library)N
+2 f
+2950(gdbm)X
+1 f
+3128(,)X
+3178(was)X
+3333(recently)X
+3622(made)X
+3826(available)X
+4145(as)X
+4241(part)X
+4395(of)X
+2706 4262(the)N
+2829(Free)X
+2997(Software)X
+3312(Foundation's)X
+3759(\(FSF\))X
+3970(software)X
+4271(distri-)X
+2706 4350(bution.)N
+2878 4464(All)N
+3017(of)X
+3121(these)X
+3323(implementations)X
+3893(are)X
+4029(based)X
+4248(on)X
+4364(the)X
+2706 4552(idea)N
+2871(of)X
+2969(revealing)X
+3299(just)X
+3445(enough)X
+3711(bits)X
+3856(of)X
+3953(a)X
+4019(hash)X
+4196(value)X
+4400(to)X
+2706 4640(locate)N
+2920(a)X
+2978(page)X
+3151(in)X
+3234(a)X
+3291(single)X
+3503(access.)X
+3770(While)X
+2 f
+3987(dbm/ndbm)X
+1 f
+4346(and)X
+2 f
+2706 4728(sdbm)N
+1 f
+2908(map)X
+3079(the)X
+3210(hash)X
+3390(value)X
+3597(directly)X
+3874(to)X
+3968(a)X
+4036(disk)X
+4201(address,)X
+2 f
+2706 4816(gdbm)N
+1 f
+2921(uses)X
+3096(the)X
+3231(hash)X
+3414(value)X
+3624(to)X
+3722(index)X
+3936(into)X
+4096(a)X
+2 f
+4168(directory)X
+1 f
+2706 4904([ENB88])N
+3020(containing)X
+3378(disk)X
+3531(addresses.)X
+2878 5018(The)N
+2 f
+3033(hsearch)X
+1 f
+3317(routines)X
+3605(in)X
+3697(System)X
+3962(V)X
+4049(are)X
+4177(designed)X
+2706 5106(to)N
+2804(provide)X
+3085(memory-resident)X
+3669(hash)X
+3852(tables.)X
+4115(Since)X
+4328(data)X
+2706 5194(access)N
+2948(does)X
+3131(not)X
+3269(require)X
+3533(disk)X
+3702(access,)X
+3964(simple)X
+4213(hashing)X
+2706 5282(schemes)N
+3010(which)X
+3238(may)X
+3408(require)X
+3667(multiple)X
+3964(probes)X
+4209(into)X
+4364(the)X
+2706 5370(table)N
+2889(are)X
+3015(used.)X
+3209(A)X
+3294(more)X
+3486(interesting)X
+3851(version)X
+4114(of)X
+2 f
+4208(hsearch)X
+1 f
+2706 5458(is)N
+2784(a)X
+2845(public)X
+3070(domain)X
+3335(library,)X
+2 f
+3594(dynahash)X
+1 f
+3901(,)X
+3945(that)X
+4089(implements)X
+2706 5546(Larson's)N
+3036(in-memory)X
+3440(adaptation)X
+3822([LAR88])X
+4164(of)X
+4279(linear)X
+2706 5634(hashing)N
+2975([LIT80].)X
+3 f
+720 5960(USENIX)N
+9 f
+1042(-)X
+3 f
+1106(Winter)X
+1371('91)X
+9 f
+1498(-)X
+3 f
+1562(Dallas,)X
+1815(TX)X
+1 f
+4424(1)X
+
+2 p
+%%Page: 2 2
+10 s 10 xH 0 xS 1 f
+3 f
+432 258(A)N
+510(New)X
+682(Hashing)X
+985(Package)X
+1290(for)X
+1413(UNIX)X
+3663(Seltzer)X
+3920(&)X
+4007(Yigit)X
+2 f
+1074 538(dbm)N
+1 f
+1232(and)X
+2 f
+1368(ndbm)X
+1 f
+604 670(The)N
+2 f
+760(dbm)X
+1 f
+928(and)X
+2 f
+1074(ndbm)X
+1 f
+1282(library)X
+1526(implementations)X
+2089(are)X
+432 758(based)N
+667(on)X
+799(the)X
+949(same)X
+1166(algorithm)X
+1529(by)X
+1661(Ken)X
+1846(Thompson)X
+432 846([THOM90,)N
+824(TOR88,)X
+1113(WAL84],)X
+1452(but)X
+1582(differ)X
+1789(in)X
+1879(their)X
+2054(pro-)X
+432 934(grammatic)N
+801(interfaces.)X
+1160(The)X
+1311(latter)X
+1502(is)X
+1581(a)X
+1643(modi\256ed)X
+1952(version)X
+432 1022(of)N
+533(the)X
+665(former)X
+918(which)X
+1148(adds)X
+1328(support)X
+1601(for)X
+1728(multiple)X
+2027(data-)X
+432 1110(bases)N
+634(to)X
+724(be)X
+828(open)X
+1011(concurrently.)X
+1484(The)X
+1636(discussion)X
+1996(of)X
+2090(the)X
+432 1198(algorithm)N
+774(that)X
+925(follows)X
+1196(is)X
+1280(applicable)X
+1640(to)X
+1732(both)X
+2 f
+1904(dbm)X
+1 f
+2072(and)X
+2 f
+432 1286(ndbm)N
+1 f
+610(.)X
+604 1400(The)N
+760(basic)X
+956(structure)X
+1268(of)X
+2 f
+1366(dbm)X
+1 f
+1535(calls)X
+1712(for)X
+1836(\256xed-sized)X
+432 1488(disk)N
+612(blocks)X
+868(\(buckets\))X
+1214(and)X
+1377(an)X
+2 f
+1499(access)X
+1 f
+1755(function)X
+2068(that)X
+432 1576(maps)N
+623(a)X
+681(key)X
+819(to)X
+902(a)X
+959(bucket.)X
+1234(The)X
+1380(interface)X
+1683(routines)X
+1962(use)X
+2090(the)X
+2 f
+432 1664(access)N
+1 f
+673(function)X
+970(to)X
+1062(obtain)X
+1292(the)X
+1420(appropriate)X
+1816(bucket)X
+2060(in)X
+2152(a)X
+432 1752(single)N
+643(disk)X
+796(access.)X
+604 1866(Within)N
+869(the)X
+2 f
+1010(access)X
+1 f
+1263(function,)X
+1593(a)X
+1672(bit-randomizing)X
+432 1954(hash)N
+610(function)X
+2 f
+8 s
+877 1929(2)N
+1 f
+10 s
+940 1954(is)N
+1024(used)X
+1202(to)X
+1294(convert)X
+1565(a)X
+1631(key)X
+1777(into)X
+1931(a)X
+1997(32-bit)X
+432 2042(hash)N
+605(value.)X
+825(Out)X
+971(of)X
+1064(these)X
+1254(32)X
+1359(bits,)X
+1519(only)X
+1686(as)X
+1778(many)X
+1981(bits)X
+2121(as)X
+432 2130(necessary)N
+773(are)X
+900(used)X
+1075(to)X
+1165(determine)X
+1514(the)X
+1639(particular)X
+1974(bucket)X
+432 2218(on)N
+533(which)X
+750(a)X
+807(key)X
+944(resides.)X
+1228(An)X
+1347(in-memory)X
+1724(bitmap)X
+1967(is)X
+2041(used)X
+432 2306(to)N
+533(determine)X
+893(how)X
+1070(many)X
+1287(bits)X
+1441(are)X
+1579(required.)X
+1905(Each)X
+2104(bit)X
+432 2394(indicates)N
+746(whether)X
+1033(its)X
+1136(associated)X
+1494(bucket)X
+1736(has)X
+1871(been)X
+2051(split)X
+432 2482(yet)N
+562(\(a)X
+657(0)X
+728(indicating)X
+1079(that)X
+1230(the)X
+1359(bucket)X
+1604(has)X
+1742(not)X
+1875(yet)X
+2004(split\).)X
+432 2570(The)N
+590(use)X
+730(of)X
+830(the)X
+961(hash)X
+1141(function)X
+1441(and)X
+1590(the)X
+1720(bitmap)X
+1974(is)X
+2059(best)X
+432 2658(described)N
+769(by)X
+878(stepping)X
+1177(through)X
+1454(database)X
+1759(creation)X
+2046(with)X
+432 2746(multiple)N
+718(invocations)X
+1107(of)X
+1194(a)X
+2 f
+1250(store)X
+1 f
+1430(operation.)X
+604 2860(Initially,)N
+906(the)X
+1033(hash)X
+1209(table)X
+1394(contains)X
+1690(a)X
+1755(single)X
+1974(bucket)X
+432 2948(\(bucket)N
+711(0\),)X
+836(the)X
+972(bit)X
+1094(map)X
+1270(contains)X
+1575(a)X
+1649(single)X
+1878(bit)X
+2000(\(bit)X
+2148(0)X
+432 3036(corresponding)N
+913(to)X
+997(bucket)X
+1233(0\),)X
+1342(and)X
+1480(0)X
+1542(bits)X
+1699(of)X
+1788(a)X
+1846(hash)X
+2014(value)X
+432 3124(are)N
+560(examined)X
+901(to)X
+992(determine)X
+1342(where)X
+1568(a)X
+1633(key)X
+1778(is)X
+1860(placed)X
+2099(\(in)X
+432 3212(bucket)N
+670(0\).)X
+801(When)X
+1017(bucket)X
+1255(0)X
+1319(is)X
+1396(full,)X
+1551(its)X
+1650(bit)X
+1758(in)X
+1844(the)X
+1966(bitmap)X
+432 3300(\(bit)N
+564(0\))X
+652(is)X
+726(set,)X
+856(and)X
+993(its)X
+1089(contents)X
+1377(are)X
+1497(split)X
+1655(between)X
+1943(buckets)X
+432 3388(0)N
+499(and)X
+641(1,)X
+727(by)X
+833(considering)X
+1233(the)X
+1357(0)X
+2 f
+7 s
+3356(th)Y
+10 s
+1 f
+1480 3388(bit)N
+1590(\(the)X
+1741(lowest)X
+1976(bit)X
+2086(not)X
+432 3476(previously)N
+800(examined\))X
+1169(of)X
+1266(the)X
+1393(hash)X
+1569(value)X
+1772(for)X
+1895(each)X
+2072(key)X
+432 3564(within)N
+668(the)X
+798(bucket.)X
+1064(Given)X
+1292(a)X
+1359(well-designed)X
+1840(hash)X
+2018(func-)X
+432 3652(tion,)N
+613(approximately)X
+1112(half)X
+1273(of)X
+1376(the)X
+1510(keys)X
+1693(will)X
+1853(have)X
+2041(hash)X
+432 3740(values)N
+666(with)X
+837(the)X
+964(0)X
+2 f
+7 s
+3708(th)Y
+10 s
+1 f
+1090 3740(bit)N
+1203(set.)X
+1341(All)X
+1471(such)X
+1646(keys)X
+1821(and)X
+1965(associ-)X
+432 3828(ated)N
+586(data)X
+740(are)X
+859(moved)X
+1097(to)X
+1179(bucket)X
+1413(1,)X
+1493(and)X
+1629(the)X
+1747(rest)X
+1883(remain)X
+2126(in)X
+432 3916(bucket)N
+666(0.)X
+604 4030(After)N
+804(this)X
+949(split,)X
+1135(the)X
+1262(\256le)X
+1393(now)X
+1560(contains)X
+1856(two)X
+2005(buck-)X
+432 4118(ets,)N
+562(and)X
+699(the)X
+818(bitmap)X
+1061(contains)X
+1349(three)X
+1530(bits:)X
+1687(the)X
+1805(0)X
+2 f
+7 s
+4086(th)Y
+10 s
+1 f
+1922 4118(bit)N
+2026(is)X
+2099(set)X
+432 4206(to)N
+525(indicate)X
+810(a)X
+876(bucket)X
+1120(0)X
+1190(split)X
+1357(when)X
+1561(no)X
+1671(bits)X
+1816(of)X
+1913(the)X
+2041(hash)X
+432 4294(value)N
+648(are)X
+789(considered,)X
+1199(and)X
+1357(two)X
+1519(more)X
+1726(unset)X
+1937(bits)X
+2094(for)X
+432 4382(buckets)N
+706(0)X
+775(and)X
+920(1.)X
+1029(The)X
+1183(placement)X
+1542(of)X
+1638(an)X
+1742(incoming)X
+2072(key)X
+432 4470(now)N
+604(requires)X
+897(examination)X
+1327(of)X
+1428(the)X
+1560(0)X
+2 f
+7 s
+4438(th)Y
+10 s
+1 f
+1691 4470(bit)N
+1809(of)X
+1910(the)X
+2041(hash)X
+432 4558(value,)N
+667(and)X
+824(the)X
+963(key)X
+1119(is)X
+1212(placed)X
+1462(either)X
+1685(in)X
+1787(bucket)X
+2041(0)X
+2121(or)X
+432 4646(bucket)N
+674(1.)X
+782(If)X
+864(either)X
+1075(bucket)X
+1317(0)X
+1385(or)X
+1480(bucket)X
+1722(1)X
+1790(\256lls)X
+1937(up,)X
+2064(it)X
+2135(is)X
+432 4734(split)N
+598(as)X
+693(before,)X
+947(its)X
+1050(bit)X
+1162(is)X
+1243(set)X
+1360(in)X
+1450(the)X
+1576(bitmap,)X
+1846(and)X
+1990(a)X
+2054(new)X
+432 4822(set)N
+541(of)X
+628(unset)X
+817(bits)X
+952(are)X
+1071(added)X
+1283(to)X
+1365(the)X
+1483(bitmap.)X
+604 4936(Each)N
+791(time)X
+959(we)X
+1079(consider)X
+1376(a)X
+1437(new)X
+1596(bit)X
+1705(\(bit)X
+1841(n\),)X
+1953(we)X
+2072(add)X
+432 5024(2)N
+2 f
+7 s
+4992(n)Y
+9 f
+509(+)X
+1 f
+540(1)X
+10 s
+595 5024(bits)N
+737(to)X
+826(the)X
+951(bitmap)X
+1199(and)X
+1341(obtain)X
+1567(2)X
+2 f
+7 s
+4992(n)Y
+9 f
+1644(+)X
+1 f
+1675(1)X
+10 s
+1729 5024(more)N
+1920(address-)X
+432 5112(able)N
+595(buckets)X
+869(in)X
+960(the)X
+1087(\256le.)X
+1258(As)X
+1376(a)X
+1441(result,)X
+1668(the)X
+1795(bitmap)X
+2045(con-)X
+432 5200(tains)N
+618(the)X
+751(previous)X
+1062(2)X
+2 f
+7 s
+5168(n)Y
+9 f
+1139(+)X
+1 f
+1170(1)X
+2 f
+10 s
+9 f
+5200(-)Y
+1 f
+1242(1)X
+1317(bits)X
+1467(\(1)X
+2 f
+9 f
+1534(+)X
+1 f
+1578(2)X
+2 f
+9 f
+(+)S
+1 f
+1662(4)X
+2 f
+9 f
+(+)S
+1 f
+1746(...)X
+2 f
+9 f
+(+)S
+1 f
+1850(2)X
+2 f
+7 s
+5168(n)Y
+10 s
+1 f
+1931 5200(\))N
+1992(which)X
+432 5288(trace)N
+649(the)X
+807(entire)X
+2 f
+1050(split)X
+1247(history)X
+1 f
+1529(of)X
+1656(the)X
+1813(addressable)X
+16 s
+432 5433 MXY
+864 0 Dl
+2 f
+8 s
+472 5488(2)N
+1 f
+9 s
+523 5513(This)N
+670(bit-randomizing)X
+1153(property)X
+1416(is)X
+1482(important)X
+1780(to)X
+1854(obtain)X
+2052(radi-)X
+432 5593(cally)N
+599(different)X
+874(hash)X
+1033(values)X
+1244(for)X
+1355(nearly)X
+1562(identical)X
+1836(keys,)X
+2012(which)X
+432 5673(in)N
+506(turn)X
+640(avoids)X
+846(clustering)X
+1148(of)X
+1226(such)X
+1376(keys)X
+1526(in)X
+1600(a)X
+1650(single)X
+1840(bucket.)X
+10 s
+2418 538(buckets.)N
+2590 652(Given)N
+2809(a)X
+2868(key)X
+3007(and)X
+3146(the)X
+3267(bitmap)X
+3512(created)X
+3768(by)X
+3871(this)X
+4009(algo-)X
+2418 740(rithm,)N
+2638(we)X
+2759(\256rst)X
+2910(examine)X
+3209(bit)X
+3320(0)X
+3386(of)X
+3479(the)X
+3603(bitmap)X
+3851(\(the)X
+4002(bit)X
+4112(to)X
+2418 828(consult)N
+2673(when)X
+2871(0)X
+2934(bits)X
+3072(of)X
+3162(the)X
+3283(hash)X
+3453(value)X
+3650(are)X
+3772(being)X
+3973(exam-)X
+2418 916(ined\).)N
+2631(If)X
+2713(it)X
+2785(is)X
+2866(set)X
+2982(\(indicating)X
+3356(that)X
+3503(the)X
+3628(bucket)X
+3869(split\),)X
+4080(we)X
+2418 1004(begin)N
+2617(considering)X
+3012(the)X
+3131(bits)X
+3267(of)X
+3355(the)X
+3473(32-bit)X
+3684(hash)X
+3851(value.)X
+4085(As)X
+2418 1092(bit)N
+2525(n)X
+2587(is)X
+2662(revealed,)X
+2977(a)X
+3035(mask)X
+3226(equal)X
+3422(to)X
+3506(2)X
+2 f
+7 s
+1060(n)Y
+9 f
+3583(+)X
+1 f
+3614(1)X
+2 f
+10 s
+9 f
+1092(-)Y
+1 f
+3686(1)X
+3748(will)X
+3894(yield)X
+4076(the)X
+2418 1180(current)N
+2675(bucket)X
+2918(address.)X
+3228(Adding)X
+3496(2)X
+2 f
+7 s
+1148(n)Y
+9 f
+3573(+)X
+1 f
+3604(1)X
+2 f
+10 s
+9 f
+1180(-)Y
+1 f
+3676(1)X
+3744(to)X
+3834(the)X
+3960(bucket)X
+2418 1268(address)N
+2701(identi\256es)X
+3035(which)X
+3272(bit)X
+3397(in)X
+3500(the)X
+3639(bitmap)X
+3902(must)X
+4098(be)X
+2418 1356(checked.)N
+2743(We)X
+2876(continue)X
+3173(revealing)X
+3493(bits)X
+3628(of)X
+3715(the)X
+3833(hash)X
+4000(value)X
+2418 1444(until)N
+2591(all)X
+2698(set)X
+2814(bits)X
+2955(in)X
+3043(the)X
+3167(bitmap)X
+3415(are)X
+3540(exhausted.)X
+3907(The)X
+4058(fol-)X
+2418 1532(lowing)N
+2682(algorithm,)X
+3055(a)X
+3133(simpli\256cation)X
+3614(of)X
+3723(the)X
+3863(algorithm)X
+2418 1620(due)N
+2565(to)X
+2658(Ken)X
+2823(Thompson)X
+3196([THOM90,)X
+3590(TOR88],)X
+3908(uses)X
+4076(the)X
+2418 1708(hash)N
+2625(value)X
+2839(and)X
+2995(the)X
+3133(bitmap)X
+3395(to)X
+3497(calculate)X
+3823(the)X
+3960(bucket)X
+2418 1796(address)N
+2679(as)X
+2766(discussed)X
+3093(above.)X
+0(Courier)xf 0 f
+1 f
+0 f
+8 s
+2418 2095(hash)N
+2608(=)X
+2684 -0.4038(calchash\(key\);)AX
+2418 2183(mask)N
+2608(=)X
+2684(0;)X
+2418 2271(while)N
+2646 -0.4018(\(isbitset\(\(hash)AX
+3254(&)X
+3330(mask\))X
+3558(+)X
+3634(mask\)\))X
+2706 2359(mask)N
+2896(=)X
+2972(\(mask)X
+3200(<<)X
+3314(1\))X
+3428(+)X
+3504(1;)X
+2418 2447(bucket)N
+2684(=)X
+2760(hash)X
+2950(&)X
+3026(mask;)X
+2 f
+10 s
+3211 2812(sdbm)N
+1 f
+2590 2944(The)N
+2 f
+2738(sdbm)X
+1 f
+2930(library)X
+3167(is)X
+3243(a)X
+3302(public-domain)X
+3791(clone)X
+3987(of)X
+4076(the)X
+2 f
+2418 3032(ndbm)N
+1 f
+2638(library,)X
+2914(developed)X
+3286(by)X
+3408(Ozan)X
+3620(Yigit)X
+3826(to)X
+3929(provide)X
+2 f
+2418 3120(ndbm)N
+1 f
+2596('s)X
+2692(functionality)X
+3139(under)X
+3359(some)X
+3565(versions)X
+3869(of)X
+3973(UNIX)X
+2418 3208(that)N
+2559(exclude)X
+2830(it)X
+2894(for)X
+3008(licensing)X
+3317(reasons)X
+3578([YIG89].)X
+3895(The)X
+4040(pro-)X
+2418 3296(grammer)N
+2735(interface,)X
+3064(and)X
+3207(the)X
+3332(basic)X
+3524(structure)X
+3832(of)X
+2 f
+3926(sdbm)X
+1 f
+4121(is)X
+2418 3384(identical)N
+2733(to)X
+2 f
+2834(ndbm)X
+1 f
+3051(but)X
+3192(internal)X
+3476(details)X
+3723(of)X
+3828(the)X
+2 f
+3964(access)X
+1 f
+2418 3472(function,)N
+2726(such)X
+2894(as)X
+2982(the)X
+3101(calculation)X
+3474(of)X
+3561(the)X
+3679(bucket)X
+3913(address,)X
+2418 3560(and)N
+2563(the)X
+2690(use)X
+2825(of)X
+2920(different)X
+3225(hash)X
+3400(functions)X
+3726(make)X
+3928(the)X
+4054(two)X
+2418 3648(incompatible)N
+2856(at)X
+2934(the)X
+3052(database)X
+3349(level.)X
+2590 3762(The)N
+2 f
+2740(sdbm)X
+1 f
+2934(library)X
+3173(is)X
+3251(based)X
+3458(on)X
+3562(a)X
+3622(simpli\256ed)X
+3965(imple-)X
+2418 3850(mentation)N
+2778(of)X
+2885(Larson's)X
+3206(1978)X
+2 f
+3406(dynamic)X
+3717(hashing)X
+1 f
+4009(algo-)X
+2418 3938(rithm)N
+2616(including)X
+2943(the)X
+2 f
+3066(re\256nements)X
+3461(and)X
+3605(variations)X
+1 f
+3953(of)X
+4044(sec-)X
+2418 4026(tion)N
+2562(5)X
+2622([LAR78].)X
+2956(Larson's)X
+3257(original)X
+3526(algorithm)X
+3857(calls)X
+4024(for)X
+4138(a)X
+2418 4114(forest)N
+2635(of)X
+2736(binary)X
+2975(hash)X
+3156(trees)X
+3341(that)X
+3494(are)X
+3626(accessed)X
+3941(by)X
+4054(two)X
+2418 4202(hash)N
+2586(functions.)X
+2925(The)X
+3071(\256rst)X
+3216(hash)X
+3384(function)X
+3672(selects)X
+3907(a)X
+3964(partic-)X
+2418 4290(ular)N
+2571(tree)X
+2720(within)X
+2952(the)X
+3078(forest.)X
+3309(The)X
+3462(second)X
+3713(hash)X
+3887(function,)X
+2418 4378(which)N
+2659(is)X
+2757(required)X
+3070(to)X
+3177(be)X
+3297(a)X
+3377(boolean)X
+3675(pseudo-random)X
+2418 4466(number)N
+2687(generator)X
+3015(that)X
+3159(is)X
+3236(seeded)X
+3479(by)X
+3583(the)X
+3705(key,)X
+3865(is)X
+3942(used)X
+4112(to)X
+2418 4554(traverse)N
+2733(the)X
+2890(tree)X
+3070(until)X
+3275(internal)X
+3579(\(split\))X
+3829(nodes)X
+4075(are)X
+2418 4642(exhausted)N
+2763(and)X
+2903(an)X
+3003(external)X
+3286(\(non-split\))X
+3648(node)X
+3827(is)X
+3903(reached.)X
+2418 4730(The)N
+2571(bucket)X
+2813(addresses)X
+3149(are)X
+3276(stored)X
+3500(directly)X
+3772(in)X
+3861(the)X
+3986(exter-)X
+2418 4818(nal)N
+2536(nodes.)X
+2590 4932(Larson's)N
+2903(re\256nements)X
+3309(are)X
+3440(based)X
+3655(on)X
+3767(the)X
+3897(observa-)X
+2418 5020(tion)N
+2570(that)X
+2718(the)X
+2844(nodes)X
+3059(can)X
+3199(be)X
+3303(represented)X
+3702(by)X
+3809(a)X
+3872(single)X
+4090(bit)X
+2418 5108(that)N
+2569(is)X
+2653(set)X
+2773(for)X
+2898(internal)X
+3174(nodes)X
+3392(and)X
+3539(not)X
+3672(set)X
+3791(for)X
+3915(external)X
+2418 5196(nodes,)N
+2652(resulting)X
+2959(in)X
+3048(a)X
+3111(radix)X
+3303(search)X
+3536(trie.)X
+3709(Figure)X
+3944(1)X
+4010(illus-)X
+2418 5284(trates)N
+2621(this.)X
+2804(Nodes)X
+3037(A)X
+3123(and)X
+3267(B)X
+3348(are)X
+3475(internal)X
+3748(\(split\))X
+3967(nodes,)X
+2418 5372(thus)N
+2573(having)X
+2813(no)X
+2915(bucket)X
+3151(addresses)X
+3480(associated)X
+3831(with)X
+3994(them.)X
+2418 5460(Instead,)N
+2693(the)X
+2814(external)X
+3096(nodes)X
+3306(\(C,)X
+3429(D,)X
+3530(and)X
+3669(E\))X
+3768(each)X
+3938(need)X
+4112(to)X
+2418 5548(refer)N
+2594(to)X
+2679(a)X
+2738(bucket)X
+2975(address.)X
+3279(These)X
+3494(bucket)X
+3731(addresses)X
+4062(can)X
+2418 5636(be)N
+2529(stored)X
+2760(in)X
+2857(the)X
+2990(trie)X
+3132(itself)X
+3327(where)X
+3559(the)X
+3691(subtries)X
+3974(would)X
+3 f
+432 5960(2)N
+2970(USENIX)X
+9 f
+3292(-)X
+3 f
+3356(Winter)X
+3621('91)X
+9 f
+3748(-)X
+3 f
+3812(Dallas,)X
+4065(TX)X
+
+3 p
+%%Page: 3 3
+0(Courier)xf 0 f
+10 s 10 xH 0 xS 0 f
+3 f
+720 258(Seltzer)N
+977(&)X
+1064(Yigit)X
+3278(A)X
+3356(New)X
+3528(Hashing)X
+3831(Package)X
+4136(for)X
+4259(UNIX)X
+1 f
+720 538(live)N
+862(if)X
+933(they)X
+1092(existed)X
+1340([KNU68].)X
+1709(For)X
+1841(example,)X
+2154(if)X
+2224(nodes)X
+2432(F)X
+720 626(and)N
+858(G)X
+938(were)X
+1117(the)X
+1237(children)X
+1522(of)X
+1610(node)X
+1787(C,)X
+1881(the)X
+2000(bucket)X
+2235(address)X
+720 714(L00)N
+886(could)X
+1101(reside)X
+1330(in)X
+1429(the)X
+1563(bits)X
+1714(that)X
+1870(will)X
+2030(eventually)X
+2400(be)X
+720 802(used)N
+887(to)X
+969(store)X
+1145(nodes)X
+1352(F)X
+1416(and)X
+1552(G)X
+1630(and)X
+1766(all)X
+1866(their)X
+2033(children.)X
+10 f
+720 890 -0.0930(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)AN
+3 f
+1894 2247(L1)N
+784 1925(A)N
+1431(E)X
+1106 2247(D)N
+1428 1281(C)N
+1109 1603(B)N
+1884 1930(L01)N
+1879 1286(L00)N
+1221 1814(1)N
+903 2131(1)N
+1221 1402(0)N
+903 1714(0)N
+1 Dt
+1397 1821 MXY
+-8 -32 Dl
+-5 19 Dl
+-20 6 Dl
+33 7 Dl
+-187 -182 Dl
+1397 1322 MXY
+-33 7 Dl
+20 6 Dl
+5 19 Dl
+8 -32 Dl
+-187 182 Dl
+1069 1639 MXY
+-32 7 Dl
+20 6 Dl
+5 19 Dl
+7 -32 Dl
+-186 182 Dl
+1374 1891 MXY
+185 Dc
+1779 2133 MXY
+0 161 Dl
+322 0 Dl
+0 -161 Dl
+-322 0 Dl
+1811 MY
+0 161 Dl
+322 0 Dl
+0 -161 Dl
+-322 0 Dl
+1166 MY
+0 161 Dl
+322 0 Dl
+0 -161 Dl
+-322 0 Dl
+1052 2213 MXY
+185 Dc
+1569 MY
+185 Dc
+720 1881 MXY
+185 Dc
+1779 2213 MXY
+-28 -17 Dl
+10 17 Dl
+-10 18 Dl
+28 -18 Dl
+-543 0 Dl
+1769 1891 MXY
+-28 -18 Dl
+10 18 Dl
+-10 18 Dl
+28 -18 Dl
+-201 0 Dl
+1364 1247 MXY
+185 Dc
+1769 MX
+-28 -18 Dl
+10 18 Dl
+-10 18 Dl
+28 -18 Dl
+-201 0 Dl
+1064 2143 MXY
+-7 -32 Dl
+-5 19 Dl
+-20 6 Dl
+32 7 Dl
+-181 -181 Dl
+3 Dt
+-1 Ds
+8 s
+720 2482(Figure)N
+925(1:)X
+1 f
+1002(Radix)X
+1179(search)X
+1365(trie)X
+1474(with)X
+1612(internal)X
+1831(nodes)X
+2004(A)X
+2074(and)X
+2189(B,)X
+2271(external)X
+720 2570(nodes)N
+891(C,)X
+972(D,)X
+1056(and)X
+1170(E,)X
+1247(and)X
+1361(bucket)X
+1553(addresses)X
+1819(stored)X
+1997(in)X
+2069(the)X
+2168(unused)X
+2370(por-)X
+720 2658(tion)N
+836(of)X
+905(the)X
+999(trie.)X
+10 s
+10 f
+720 2922 -0.0930(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)AN
+1 f
+892 3124(Further)N
+1153(simpli\256cations)X
+1647(of)X
+1738(the)X
+1860(above)X
+2076([YIG89])X
+2377(are)X
+720 3212(possible.)N
+1038(Using)X
+1265(a)X
+1337(single)X
+1564(radix)X
+1765(trie)X
+1908(to)X
+2006(avoid)X
+2219(the)X
+2352(\256rst)X
+720 3300(hash)N
+904(function,)X
+1227(replacing)X
+1562(the)X
+1696(pseudo-random)X
+2231(number)X
+720 3388(generator)N
+1052(with)X
+1222(a)X
+1286(well)X
+1452(designed,)X
+1785(bit-randomizing)X
+2329(hash)X
+720 3476(function,)N
+1053(and)X
+1215(using)X
+1434(the)X
+1578(portion)X
+1855(of)X
+1967(the)X
+2110(hash)X
+2302(value)X
+720 3564(exposed)N
+1021(during)X
+1268(the)X
+1404(trie)X
+1549(traversal)X
+1864(as)X
+1969(a)X
+2042(direct)X
+2262(bucket)X
+720 3652(address)N
+990(results)X
+1228(in)X
+1319(an)X
+2 f
+1424(access)X
+1 f
+1663(function)X
+1959(that)X
+2108(works)X
+2333(very)X
+720 3740(similar)N
+974(to)X
+1068(Thompson's)X
+1499(algorithm)X
+1841(above.)X
+2084(The)X
+2240(follow-)X
+720 3828(ing)N
+847(algorithm)X
+1183(uses)X
+1346(the)X
+1469(hash)X
+1641(value)X
+1840(to)X
+1927(traverse)X
+2206(a)X
+2266(linear-)X
+720 3916(ized)N
+874(radix)X
+1059(trie)X
+2 f
+8 s
+1166 3891(3)N
+1 f
+10 s
+1218 3916(starting)N
+1478(at)X
+1556(the)X
+1674(0)X
+2 f
+7 s
+3884(th)Y
+10 s
+1 f
+1791 3916(bit.)N
+0 f
+8 s
+720 4215(tbit)N
+910(=)X
+986(0;)X
+1296(/*)X
+1410(radix)X
+1638(trie)X
+1828(index)X
+2056(*/)X
+720 4303(hbit)N
+910(=)X
+986(0;)X
+1296(/*)X
+1410(hash)X
+1600(bit)X
+1752(index)X
+2056(*/)X
+720 4391(mask)N
+910(=)X
+986(0;)X
+720 4479(hash)N
+910(=)X
+986 -0.4038(calchash\(key\);)AX
+720 4655(for)N
+872(\(mask)X
+1100(=)X
+1176(0;)X
+910 4743 -0.4018(isbitset\(tbit\);)AN
+910 4831(mask)N
+1100(=)X
+1176(\(mask)X
+1404(<<)X
+1518(1\))X
+1632(+)X
+1708(1\))X
+1008 4919(if)N
+1122(\(hash)X
+1350(&)X
+1426(\(1)X
+1540(<<)X
+1654 -0.4219(hbit++\)\)\))AX
+1160 5007(/*)N
+1274(right)X
+1502(son)X
+1692(*/)X
+1160 5095(tbit)N
+1350(=)X
+1426(2)X
+1502(*)X
+1578(tbit)X
+1768(+)X
+1844(2;)X
+1008 5183(else)N
+1 f
+16 s
+720 5353 MXY
+864 0 Dl
+2 f
+8 s
+760 5408(3)N
+1 f
+9 s
+818 5433(A)N
+896(linearized)X
+1206(radix)X
+1380(trie)X
+1502(is)X
+1576(merely)X
+1802(an)X
+1895(array)X
+2068(representation)X
+720 5513(of)N
+800(the)X
+908(radix)X
+1076(search)X
+1280(trie)X
+1396(described)X
+1692(above.)X
+1920(The)X
+2052(children)X
+2308(of)X
+2388(the)X
+720 5593(node)N
+885(with)X
+1038(index)X
+1223(i)X
+1267(can)X
+1391(be)X
+1483(found)X
+1675(at)X
+1751(the)X
+1863(nodes)X
+2055(indexed)X
+2307(2*i+1)X
+720 5673(and)N
+842(2*i+2.)X
+0 f
+8 s
+3146 538(/*)N
+3260(left)X
+3450(son)X
+3678(*/)X
+3146 626(tbit)N
+3336(=)X
+3412(2)X
+3488(*)X
+3564(tbit)X
+3754(+)X
+3830(1;)X
+2706 802(bucket)N
+2972(=)X
+3048(hash)X
+3238(&)X
+3314(mask;)X
+2 f
+10 s
+3495 1167(gdbm)N
+1 f
+2878 1299(The)N
+3027(gdbm)X
+3233(\(GNU)X
+3458(data)X
+3616(base)X
+3783(manager\))X
+4111(library)X
+4349(is)X
+4426(a)X
+2706 1387(UNIX)N
+2933(database)X
+3236(manager)X
+3539(written)X
+3792(by)X
+3897(Philip)X
+4112(A.)X
+4215(Nelson,)X
+2706 1475(and)N
+2848(made)X
+3048(available)X
+3364(as)X
+3457(a)X
+3518(part)X
+3668(of)X
+3760(the)X
+3883(FSF)X
+4040(software)X
+4342(dis-)X
+2706 1563(tribution.)N
+3052(The)X
+3207(gdbm)X
+3419(library)X
+3663(provides)X
+3969(the)X
+4097(same)X
+4292(func-)X
+2706 1651(tionality)N
+3028(of)X
+3151(the)X
+2 f
+3304(dbm)X
+1 f
+3442(/)X
+2 f
+3464(ndbm)X
+1 f
+3697(libraries)X
+4015([NEL90])X
+4360(but)X
+2706 1739(attempts)N
+3018(to)X
+3121(avoid)X
+3340(some)X
+3550(of)X
+3658(their)X
+3846(shortcomings.)X
+4337(The)X
+2706 1827(gdbm)N
+2918(library)X
+3162(allows)X
+3401(for)X
+3525(arbitrary-length)X
+4059(data,)X
+4242(and)X
+4387(its)X
+2706 1915(database)N
+3027(is)X
+3124(a)X
+3203(singular,)X
+3524(non-sparse)X
+2 f
+8 s
+3872 1890(4)N
+1 f
+10 s
+3947 1915(\256le.)N
+4112(The)X
+4280(gdbm)X
+2706 2003(library)N
+2947(also)X
+3103(includes)X
+2 f
+3396(dbm)X
+1 f
+3560(and)X
+2 f
+3702(ndbm)X
+1 f
+3906(compatible)X
+4288(inter-)X
+2706 2091(faces.)N
+2878 2205(The)N
+3025(gdbm)X
+3229(library)X
+3465(is)X
+3540(based)X
+3745(on)X
+2 f
+3847(extensible)X
+4189(hashing)X
+1 f
+4442(,)X
+2706 2293(a)N
+2766(dynamic)X
+3066(hashing)X
+3339(algorithm)X
+3674(by)X
+3778(Fagin)X
+3984(et)X
+4066(al)X
+4148([FAG79].)X
+2706 2381(This)N
+2881(algorithm)X
+3225(differs)X
+3467(from)X
+3655(the)X
+3785(previously)X
+4155(discussed)X
+2706 2469(algorithms)N
+3069(in)X
+3152(that)X
+3293(it)X
+3358(uses)X
+3517(a)X
+2 f
+3574(directory)X
+1 f
+3889(that)X
+4030(is)X
+4103(a)X
+4159(collapsed)X
+2706 2557(representation)N
+3192([ENB88])X
+3517(of)X
+3615(the)X
+3744(radix)X
+3940(search)X
+4177(trie)X
+4315(used)X
+2706 2645(by)N
+2 f
+2806(sdbm)X
+1 f
+2975(.)X
+10 f
+2706 2733 -0.0930(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)AN
+3 f
+7 s
+3572 3761(L1)N
+1 Dt
+3485 3738 MXY
+-20 -13 Dl
+7 13 Dl
+-7 13 Dl
+20 -13 Dl
+-400 0 Dl
+3180 3027 MXY
+136 Dc
+2706 3494 MXY
+136 Dc
+2950 3264 MXY
+136 Dc
+3738 MY
+136 Dc
+3485 2968 MXY
+0 118 Dl
+238 0 Dl
+0 -118 Dl
+-238 0 Dl
+3442 MY
+0 119 Dl
+238 0 Dl
+0 -119 Dl
+-238 0 Dl
+3679 MY
+0 119 Dl
+238 0 Dl
+0 -119 Dl
+-238 0 Dl
+3187 3501 MXY
+136 Dc
+2963 3316 MXY
+-24 5 Dl
+15 4 Dl
+4 15 Dl
+5 -24 Dl
+-137 134 Dl
+3204 3083 MXY
+-24 5 Dl
+15 4 Dl
+3 14 Dl
+6 -23 Dl
+-137 133 Dl
+3204 3450 MXY
+-6 -24 Dl
+-3 14 Dl
+-15 5 Dl
+24 5 Dl
+-137 -134 Dl
+2842 3369(0)N
+3075 3139(0)N
+2842 3676(1)N
+3075 3443(1)N
+3562 3054(L00)N
+3565 3528(L01)N
+4197 2968 MXY
+0 118 Dl
+237 0 Dl
+0 -118 Dl
+-237 0 Dl
+3205 MY
+0 119 Dl
+237 0 Dl
+0 -119 Dl
+-237 0 Dl
+3561 MY
+0 118 Dl
+237 0 Dl
+0 -118 Dl
+-237 0 Dl
+3960 2909 MXY
+0 237 Dl
+118 0 Dl
+0 -237 Dl
+-118 0 Dl
+3146 MY
+0 237 Dl
+118 0 Dl
+0 -237 Dl
+-118 0 Dl
+3383 MY
+0 237 Dl
+118 0 Dl
+0 -237 Dl
+-118 0 Dl
+3620 MY
+0 237 Dl
+118 0 Dl
+0 -237 Dl
+-118 0 Dl
+4197 3027 MXY
+-21 -13 Dl
+8 13 Dl
+-8 13 Dl
+21 -13 Dl
+-119 0 Dl
+4197 3264 MXY
+-21 -13 Dl
+8 13 Dl
+-8 13 Dl
+21 -13 Dl
+-119 0 Dl
+3501 MY
+59 0 Dl
+0 89 Dl
+4078 3738 MXY
+59 0 Dl
+0 -88 Dl
+4197 3590 MXY
+-21 -13 Dl
+8 13 Dl
+-8 13 Dl
+21 -13 Dl
+-60 0 Dl
+4197 3650 MXY
+-21 -13 Dl
+8 13 Dl
+-8 13 Dl
+21 -13 Dl
+-60 0 Dl
+3991 3050(00)N
+3991 3287(01)N
+3991 3524(10)N
+3991 3761(11)N
+4269 3050(L00)N
+4269 3287(L01)N
+4283 3643(L1)N
+3485 3501 MXY
+-20 -13 Dl
+7 13 Dl
+-7 13 Dl
+20 -13 Dl
+-155 0 Dl
+3485 3027 MXY
+-20 -13 Dl
+7 13 Dl
+-7 13 Dl
+20 -13 Dl
+-163 0 Dl
+2967 3687 MXY
+-5 -24 Dl
+-4 14 Dl
+-15 4 Dl
+24 6 Dl
+-141 -141 Dl
+3 Dt
+-1 Ds
+8 s
+2706 4033(Figure)N
+2903(2:)X
+1 f
+2972(A)X
+3034(radix)X
+3181(search)X
+3359(trie)X
+3460(and)X
+3568(a)X
+3612(directory)X
+3858(representing)X
+4189(the)X
+4283(trie.)X
+10 s
+10 f
+2706 4209 -0.0930(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)AN
+1 f
+2878 4411(In)N
+2968(this)X
+3106(algorithm,)X
+3460(a)X
+3519(directory)X
+3832(consists)X
+4108(of)X
+4198(a)X
+4256(search)X
+2706 4499(trie)N
+2847(of)X
+2947(depth)X
+2 f
+3158(n)X
+1 f
+3211(,)X
+3264(containing)X
+3635(2)X
+2 f
+7 s
+4467(n)Y
+10 s
+1 f
+3749 4499(bucket)N
+3996(addresses)X
+4337(\(i.e.)X
+2706 4587(each)N
+2897(element)X
+3194(of)X
+3304(the)X
+3445(trie)X
+3594(is)X
+3689(a)X
+3767(bucket)X
+4023(address\).)X
+4373(To)X
+2706 4675(access)N
+2935(the)X
+3056(hash)X
+3226(table,)X
+3425(a)X
+3483(32-bit)X
+3696(hash)X
+3865(value)X
+4061(is)X
+4136(calculated)X
+2706 4763(and)N
+2 f
+2861(n)X
+1 f
+2953(bits)X
+3107(of)X
+3213(the)X
+3350(value)X
+3563(are)X
+3701(used)X
+3886(to)X
+3986(index)X
+4202(into)X
+4364(the)X
+2706 4851(directory)N
+3018(to)X
+3102(obtain)X
+3324(a)X
+3382(bucket)X
+3618(address.)X
+3921(It)X
+3992(is)X
+4067(important)X
+4400(to)X
+2706 4939(note)N
+2866(that)X
+3008(multiple)X
+3296(entries)X
+3532(of)X
+3620(this)X
+3756(directory)X
+4067(may)X
+4226(contain)X
+2706 5027(the)N
+2833(same)X
+3026(bucket)X
+3268(address)X
+3537(as)X
+3632(a)X
+3696(result)X
+3902(of)X
+3997(directory)X
+4315(dou-)X
+2706 5115(bling)N
+2903(during)X
+3145(bucket)X
+3392(splitting.)X
+3706(Figure)X
+3948(2)X
+4021(illustrates)X
+4364(the)X
+2706 5203(relationship)N
+3126(between)X
+3436(a)X
+3513(typical)X
+3772(\(skewed\))X
+4108(search)X
+4355(trie)X
+2706 5291(and)N
+2850(its)X
+2953(directory)X
+3271(representation.)X
+3774(The)X
+3927(formation)X
+4270(of)X
+4364(the)X
+2706 5379(directory)N
+3016(shown)X
+3245(in)X
+3327(the)X
+3445(\256gure)X
+3652(is)X
+3725(as)X
+3812(follows.)X
+16 s
+2706 5593 MXY
+864 0 Dl
+2 f
+8 s
+2746 5648(4)N
+1 f
+9 s
+2796 5673(It)N
+2858(does)X
+3008(not)X
+3118(contain)X
+3348(holes.)X
+3 f
+10 s
+720 5960(USENIX)N
+9 f
+1042(-)X
+3 f
+1106(Winter)X
+1371('91)X
+9 f
+1498(-)X
+3 f
+1562(Dallas,)X
+1815(TX)X
+4424(3)X
+
+4 p
+%%Page: 4 4
+0(Courier)xf 0 f
+10 s 10 xH 0 xS 0 f
+3 f
+432 258(A)N
+510(New)X
+682(Hashing)X
+985(Package)X
+1290(for)X
+1413(UNIX)X
+3663(Seltzer)X
+3920(&)X
+4007(Yigit)X
+1 f
+604 538(Initially,)N
+937(there)X
+1158(is)X
+1271(one)X
+1446(slot)X
+1620(in)X
+1741(the)X
+1898(directory)X
+432 626(addressing)N
+802(a)X
+865(single)X
+1083(bucket.)X
+1364(The)X
+1515(depth)X
+1719(of)X
+1812(the)X
+1936(trie)X
+2069(is)X
+2148(0)X
+432 714(and)N
+577(0)X
+646(bits)X
+790(of)X
+886(each)X
+1063(hash)X
+1239(value)X
+1442(are)X
+1570(examined)X
+1910(to)X
+2000(deter-)X
+432 802(mine)N
+624(in)X
+718(which)X
+946(bucket)X
+1192(to)X
+1286(place)X
+1488(a)X
+1556(key;)X
+1726(all)X
+1837(keys)X
+2015(go)X
+2126(in)X
+432 890(bucket)N
+682(0.)X
+797(When)X
+1024(this)X
+1174(bucket)X
+1423(is)X
+1511(full,)X
+1677(its)X
+1787(contents)X
+2089(are)X
+432 978(divided)N
+698(between)X
+992(L0)X
+1107(and)X
+1249(L1)X
+1363(as)X
+1455(was)X
+1605(done)X
+1786(in)X
+1873(the)X
+1996(previ-)X
+432 1066(ously)N
+664(discussed)X
+1030(algorithms.)X
+1471(After)X
+1700(this)X
+1874(split,)X
+2090(the)X
+432 1154(address)N
+710(of)X
+814(the)X
+948(second)X
+1207(bucket)X
+1457(must)X
+1648(be)X
+1760(stored)X
+1992(in)X
+2090(the)X
+432 1242(directory.)N
+796(To)X
+939(accommodate)X
+1438(the)X
+1589(new)X
+1776(address,)X
+2090(the)X
+432 1330(directory)N
+752(is)X
+835(split)X
+2 f
+8 s
+972 1305(5)N
+1 f
+10 s
+1330(,)Y
+1054(by)X
+1163(doubling)X
+1476(it,)X
+1569(thus)X
+1731(increasing)X
+2090(the)X
+432 1418(depth)N
+630(of)X
+717(the)X
+835(directory)X
+1145(by)X
+1245(one.)X
+604 1532(After)N
+813(this)X
+967(split,)X
+1163(a)X
+1237(single)X
+1466(bit)X
+1588(of)X
+1693(the)X
+1829(hash)X
+2014(value)X
+432 1620(needs)N
+663(to)X
+773(be)X
+896(examined)X
+1255(to)X
+1364(decide)X
+1621(whether)X
+1927(the)X
+2072(key)X
+432 1708(belongs)N
+711(to)X
+803(L0)X
+922(or)X
+1019(L1.)X
+1158(Once)X
+1358(one)X
+1504(of)X
+1601(these)X
+1795(buckets)X
+2069(\256lls)X
+432 1796(\(L0)N
+578(for)X
+702(example\),)X
+1051(it)X
+1125(is)X
+1208(split)X
+1375(as)X
+1472(before,)X
+1728(and)X
+1873(the)X
+2000(direc-)X
+432 1884(tory)N
+585(is)X
+662(split)X
+823(again)X
+1021(to)X
+1107(make)X
+1305(room)X
+1498(for)X
+1615(the)X
+1736(address)X
+2000(of)X
+2090(the)X
+432 1972(third)N
+618(bucket.)X
+927(This)X
+1104(splitting)X
+1400(causes)X
+1645(the)X
+1778(addresses)X
+2121(of)X
+432 2060(the)N
+567(non-splitting)X
+1012(bucket)X
+1263(\(L1\))X
+1443(to)X
+1541(be)X
+1653(duplicated.)X
+2063(The)X
+432 2148(directory)N
+766(now)X
+948(has)X
+1099(four)X
+1277(entries,)X
+1555(a)X
+1635(depth)X
+1857(of)X
+1968(2,)X
+2072(and)X
+432 2236(indexes)N
+700(the)X
+821(buckets)X
+1089(L00,)X
+1261(L01)X
+1413(and)X
+1552(L1,)X
+1684(as)X
+1774(shown)X
+2006(in)X
+2090(the)X
+432 2324(Figure)N
+661(2.)X
+604 2438(The)N
+756(crucial)X
+1002(part)X
+1154(of)X
+1247(the)X
+1371(algorithm)X
+1708(is)X
+1787(the)X
+1911(observa-)X
+432 2526(tion)N
+580(that)X
+724(L1)X
+837(is)X
+914(addressed)X
+1255(twice)X
+1453(in)X
+1539(the)X
+1661(directory.)X
+1995(If)X
+2073(this)X
+432 2614(bucket)N
+679(were)X
+869(to)X
+964(split)X
+1134(now,)X
+1324(the)X
+1454(directory)X
+1776(already)X
+2045(con-)X
+432 2702(tains)N
+611(room)X
+808(to)X
+898(hold)X
+1067(the)X
+1192(address)X
+1460(of)X
+1554(the)X
+1679(new)X
+1840(bucket.)X
+2121(In)X
+432 2790(general,)N
+711(the)X
+831(relationship)X
+1231(between)X
+1521(the)X
+1641(directory)X
+1953(and)X
+2090(the)X
+432 2878(number)N
+704(of)X
+798(bucket)X
+1039(addresses)X
+1374(contained)X
+1713(therein)X
+1962(is)X
+2041(used)X
+432 2966(to)N
+517(decide)X
+750(when)X
+947(to)X
+1031(split)X
+1190(the)X
+1310(directory.)X
+1662(Each)X
+1845(bucket)X
+2081(has)X
+432 3054(a)N
+505(depth,)X
+740(\()X
+2 f
+767(n)X
+7 s
+3070(b)Y
+10 s
+1 f
+848 3054(\),)N
+932(associated)X
+1299(with)X
+1478(it)X
+1558(and)X
+1710(appears)X
+1992(in)X
+2090(the)X
+432 3142(directory)N
+744(exactly)X
+998(2)X
+2 f
+7 s
+3106(n)Y
+9 f
+1075(-)X
+2 f
+1106(n)X
+4 s
+3110(b)Y
+7 s
+1 f
+10 s
+1181 3142(times.)N
+1396(When)X
+1610(a)X
+1668(bucket)X
+1904(splits,)X
+2113(its)X
+432 3230(depth)N
+638(increases)X
+961(by)X
+1069(one.)X
+1253(The)X
+1406(directory)X
+1724(must)X
+1907(split)X
+2072(any)X
+432 3318(time)N
+602(a)X
+665(bucket's)X
+964(depth)X
+1169(exceeds)X
+1451(the)X
+1576(depth)X
+1781(of)X
+1875(the)X
+2000(direc-)X
+432 3406(tory.)N
+630(The)X
+784(following)X
+1123(code)X
+1303(fragment)X
+1621(helps)X
+1818(to)X
+1908(illustrate)X
+432 3494(the)N
+554(extendible)X
+912(hashing)X
+1185(algorithm)X
+1520([FAG79])X
+1838(for)X
+1955(access-)X
+432 3582(ing)N
+554(individual)X
+898(buckets)X
+1163(and)X
+1299(maintaining)X
+1701(the)X
+1819(directory.)X
+0 f
+8 s
+432 3881(hash)N
+622(=)X
+698 -0.4038(calchash\(key\);)AX
+432 3969(mask)N
+622(=)X
+698 -0.4018(maskvec[depth];)AX
+432 4145(bucket)N
+698(=)X
+774 -0.4038(directory[hash)AX
+1344(&)X
+1420(mask];)X
+432 4321(/*)N
+546(Key)X
+698 -0.4219(Insertion)AX
+1078(*/)X
+432 4409(if)N
+546 -0.4038(\(store\(bucket,)AX
+1116(key,)X
+1306(data\))X
+1534(==)X
+1648(FAIL\))X
+1876({)X
+720 4497(newbl)N
+948(=)X
+1024 -0.4167(getpage\(\);)AX
+720 4585 -0.4000(bucket->depth++;)AN
+720 4673 -0.4091(newbl->depth)AN
+1214(=)X
+1290 -0.4038(bucket->depth;)AX
+720 4761(if)N
+834 -0.4038(\(bucket->depth)AX
+1404(>)X
+1480(depth\))X
+1746({)X
+1008 4849(/*)N
+1122(double)X
+1388 -0.4219(directory)AX
+1768(*/)X
+1008 4937(depth++;)N
+1 f
+16 s
+432 5033 MXY
+864 0 Dl
+2 f
+8 s
+472 5088(5)N
+1 f
+9 s
+534 5113(This)N
+692(decision)X
+962(to)X
+1048(split)X
+1202(the)X
+1319(directory)X
+1608(is)X
+1685(based)X
+1878(on)X
+1979(a)X
+2040(com-)X
+432 5193(parison)N
+666(of)X
+748(the)X
+858(depth)X
+1040(of)X
+1121(the)X
+1230(page)X
+1387(being)X
+1568(split)X
+1713(and)X
+1838(the)X
+1947(depth)X
+2128(of)X
+432 5273(the)N
+543(trie.)X
+698(In)X
+781(Figure)X
+992(2,)X
+1069(the)X
+1180(depths)X
+1390(of)X
+1472(both)X
+1622(L00)X
+1760(and)X
+1886(L01)X
+2024(are)X
+2134(2,)X
+432 5353(whereas)N
+689(the)X
+798(depth)X
+979(of)X
+1060(L1)X
+1161(is)X
+1230(1.)X
+1323(Therefore,)X
+1646(if)X
+1710(L1)X
+1810(were)X
+1970(to)X
+2046(split,)X
+432 5433(the)N
+543(directory)X
+826(would)X
+1029(not)X
+1144(need)X
+1303(to)X
+1382(split.)X
+1565(In)X
+1648(reality,)X
+1872(a)X
+1926(bucket)X
+2140(is)X
+432 5513(allocated)N
+727(for)X
+846(the)X
+969(directory)X
+1264(at)X
+1351(the)X
+1474(time)X
+1637(of)X
+1732(\256le)X
+1858(creation)X
+2124(so)X
+432 5593(although)N
+707(the)X
+818(directory)X
+1100(splits)X
+1274(logically,)X
+1566(physical)X
+1828(splits)X
+2002(do)X
+2096(not)X
+432 5673(occur)N
+610(until)X
+760(the)X
+866(\256le)X
+976(becomes)X
+1246(quite)X
+1408(large.)X
+0 f
+8 s
+2994 538 -0.4219(directory)AN
+3374(=)X
+3450 -0.3971(double\(directory\);)AX
+2706 626(})N
+2706 714 -0.3958(splitbucket\(bucket,)AN
+3466(newbl\))X
+2706 802(...)N
+2418 890(})N
+2 f
+10 s
+3169 1255(hsearch)N
+1 f
+2590 1387(Since)N
+2 f
+2807(hsearch)X
+1 f
+3100(does)X
+3286(not)X
+3427(have)X
+3617(to)X
+3717(translate)X
+4027(hash)X
+2418 1475(values)N
+2659(into)X
+2819(disk)X
+2988(addresses,)X
+3352(it)X
+3432(can)X
+3579(use)X
+3721(much)X
+3934(simpler)X
+2418 1563(algorithms)N
+2808(than)X
+2994(those)X
+3211(de\256ned)X
+3495(above.)X
+3775(System)X
+4058(V's)X
+2 f
+2418 1651(hsearch)N
+1 f
+2708(constructs)X
+3069(a)X
+3141(\256xed-size)X
+3489(hash)X
+3671(table)X
+3862(\(speci\256ed)X
+2418 1739(by)N
+2519(the)X
+2637(user)X
+2791(at)X
+2869(table)X
+3045(creation\).)X
+3391(By)X
+3504(default,)X
+3767(a)X
+3823(multiplica-)X
+2418 1827(tive)N
+2570(hash)X
+2748(function)X
+3046(based)X
+3260(on)X
+3371(that)X
+3522(described)X
+3861(in)X
+3954(Knuth,)X
+2418 1915(Volume)N
+2710(3,)X
+2804(section)X
+3065(6.4)X
+3199([KNU68])X
+3541(is)X
+3628(used)X
+3809(to)X
+3905(obtain)X
+4138(a)X
+2418 2003(primary)N
+2694(bucket)X
+2930(address.)X
+3233(If)X
+3309(this)X
+3446(bucket)X
+3681(is)X
+3755(full,)X
+3907(a)X
+3964(secon-)X
+2418 2091(dary)N
+2593(multiplicative)X
+3069(hash)X
+3248(value)X
+3454(is)X
+3538(computed)X
+3885(to)X
+3978(de\256ne)X
+2418 2179(the)N
+2542(probe)X
+2751(interval.)X
+3062(The)X
+3213(probe)X
+3422(interval)X
+3693(is)X
+3772(added)X
+3989(to)X
+4076(the)X
+2418 2267(original)N
+2712(bucket)X
+2971(address)X
+3257(\(modulo)X
+3573(the)X
+3716(table)X
+3916(size\))X
+4112(to)X
+2418 2355(obtain)N
+2658(a)X
+2734(new)X
+2908(bucket)X
+3162(address.)X
+3483(This)X
+3665(process)X
+3946(repeats)X
+2418 2443(until)N
+2588(an)X
+2688(empty)X
+2911(bucket)X
+3148(is)X
+3224(found.)X
+3474(If)X
+3551(no)X
+3654(bucket)X
+3891(is)X
+3967(found,)X
+2418 2531(an)N
+2514(insertion)X
+2814(fails)X
+2972(with)X
+3134(a)X
+3190(``table)X
+3420(full'')X
+3605(condition.)X
+2590 2645(The)N
+2768(basic)X
+2986(algorithm)X
+3350(may)X
+3541(be)X
+3670(modi\256ed)X
+4006(by)X
+4138(a)X
+2418 2733(number)N
+2705(of)X
+2813(compile)X
+3112(time)X
+3295(options)X
+3571(available)X
+3902(to)X
+4005(those)X
+2418 2821(users)N
+2604(with)X
+2767(AT&T)X
+3006(source)X
+3237(code.)X
+3450(First,)X
+3637(the)X
+3756(package)X
+4040(pro-)X
+2418 2909(vides)N
+2638(two)X
+2809(options)X
+3094(for)X
+3238(hash)X
+3435(functions.)X
+3803(Users)X
+4036(may)X
+2418 2997(specify)N
+2690(their)X
+2877(own)X
+3055(hash)X
+3242(function)X
+3549(by)X
+3669(compiling)X
+4032(with)X
+2418 3085(``USCR'')N
+2757(de\256ned)X
+3016(and)X
+3155(declaring)X
+3477(and)X
+3616(de\256ning)X
+3901(the)X
+4022(vari-)X
+2418 3173(able)N
+2 f
+2578(hcompar)X
+1 f
+2863(,)X
+2909(a)X
+2971(function)X
+3263(taking)X
+3488(two)X
+3633(string)X
+3840(arguments)X
+2418 3261(and)N
+2560(returning)X
+2880(an)X
+2982(integer.)X
+3271(Users)X
+3480(may)X
+3643(also)X
+3797(request)X
+4054(that)X
+2418 3349(hash)N
+2587(values)X
+2814(be)X
+2912(computed)X
+3250(simply)X
+3489(by)X
+3590(taking)X
+3811(the)X
+3930(modulo)X
+2418 3437(of)N
+2521(key)X
+2673(\(using)X
+2909(division)X
+3201(rather)X
+3424(than)X
+3597(multiplication)X
+4080(for)X
+2418 3525(hash)N
+2589(value)X
+2787(calculation\).)X
+3230(If)X
+3308(this)X
+3447(technique)X
+3783(is)X
+3859(used,)X
+4049(col-)X
+2418 3613(lisions)N
+2651(are)X
+2775(resolved)X
+3072(by)X
+3176(scanning)X
+3485(sequentially)X
+3896(from)X
+4076(the)X
+2418 3701(selected)N
+2702(bucket)X
+2941(\(linear)X
+3176(probing\).)X
+3517(This)X
+3684(option)X
+3913(is)X
+3991(avail-)X
+2418 3789(able)N
+2572(by)X
+2672(de\256ning)X
+2954(the)X
+3072(variable)X
+3351(``DIV'')X
+3622(at)X
+3700(compile)X
+3978(time.)X
+2590 3903(A)N
+2720(second)X
+3015(option,)X
+3311(based)X
+3565(on)X
+3716(an)X
+3863(algorithm)X
+2418 3991(discovered)N
+2787(by)X
+2888(Richard)X
+3163(P.)X
+3248(Brent,)X
+3466(rearranges)X
+3822(the)X
+3940(table)X
+4116(at)X
+2418 4079(the)N
+2549(time)X
+2724(of)X
+2824(insertion)X
+3137(in)X
+3232(order)X
+3434(to)X
+3528(speed)X
+3743(up)X
+3855(retrievals.)X
+2418 4167(The)N
+2571(basic)X
+2764(idea)X
+2926(is)X
+3007(to)X
+3097(shorten)X
+3361(long)X
+3531(probe)X
+3741(sequences)X
+4094(by)X
+2418 4255(lengthening)N
+2833(short)X
+3030(probe)X
+3249(sequences.)X
+3651(Once)X
+3857(the)X
+3991(probe)X
+2418 4343(chain)N
+2613(has)X
+2741(exceeded)X
+3062(some)X
+3252(threshold)X
+3571(\(Brent)X
+3796(suggests)X
+4087(2\),)X
+2418 4431(we)N
+2541(attempt)X
+2809(to)X
+2899(shuf\257e)X
+3145(any)X
+3289(colliding)X
+3601(keys)X
+3776(\(keys)X
+3978(which)X
+2418 4519(appeared)N
+2734(in)X
+2821(the)X
+2944(probe)X
+3152(sequence)X
+3471(of)X
+3562(the)X
+3684(new)X
+3842(key\).)X
+4049(The)X
+2418 4607(details)N
+2652(of)X
+2744(this)X
+2884(key)X
+3025(shuf\257ing)X
+3333(can)X
+3469(be)X
+3569(found)X
+3780(in)X
+3866([KNU68])X
+2418 4695(and)N
+2576([BRE73].)X
+2946(This)X
+3129(algorithm)X
+3481(may)X
+3660(be)X
+3777(obtained)X
+4094(by)X
+2418 4783(de\256ning)N
+2700(the)X
+2818(variable)X
+3097(``BRENT'')X
+3487(at)X
+3565(compile)X
+3843(time.)X
+2590 4897(A)N
+2698(third)X
+2899(set)X
+3038(of)X
+3154(options,)X
+3458(obtained)X
+3783(by)X
+3912(de\256ning)X
+2418 4985(``CHAINED'',)N
+2943(use)X
+3086(linked)X
+3321(lists)X
+3484(to)X
+3581(resolve)X
+3848(collisions.)X
+2418 5073(Either)N
+2647(of)X
+2747(the)X
+2878(primary)X
+3164(hash)X
+3343(function)X
+3642(described)X
+3982(above)X
+2418 5161(may)N
+2584(be)X
+2688(used,)X
+2882(but)X
+3011(all)X
+3118(collisions)X
+3451(are)X
+3577(resolved)X
+3876(by)X
+3983(build-)X
+2418 5249(ing)N
+2554(a)X
+2623(linked)X
+2856(list)X
+2986(of)X
+3086(entries)X
+3333(from)X
+3522(the)X
+3653(primary)X
+3940(bucket.)X
+2418 5337(By)N
+2542(default,)X
+2816(new)X
+2981(entries)X
+3226(will)X
+3381(be)X
+3488(added)X
+3711(to)X
+3804(a)X
+3871(bucket)X
+4116(at)X
+2418 5425(the)N
+2541(beginning)X
+2886(of)X
+2978(the)X
+3101(bucket)X
+3339(chain.)X
+3577(However,)X
+3916(compile)X
+2418 5513(options)N
+2706(``SORTUP'')X
+3173(or)X
+3293(``SORTDOWN'')X
+3908(may)X
+4098(be)X
+2418 5601(speci\256ed)N
+2723(to)X
+2805(order)X
+2995(the)X
+3113(hash)X
+3280(chains)X
+3505(within)X
+3729(each)X
+3897(bucket.)X
+3 f
+432 5960(4)N
+2970(USENIX)X
+9 f
+3292(-)X
+3 f
+3356(Winter)X
+3621('91)X
+9 f
+3748(-)X
+3 f
+3812(Dallas,)X
+4065(TX)X
+
+5 p
+%%Page: 5 5
+0(Courier)xf 0 f
+10 s 10 xH 0 xS 0 f
+3 f
+720 258(Seltzer)N
+977(&)X
+1064(Yigit)X
+3278(A)X
+3356(New)X
+3528(Hashing)X
+3831(Package)X
+4136(for)X
+4259(UNIX)X
+2 f
+1444 538(dynahash)N
+1 f
+892 670(The)N
+2 f
+1054(dynahash)X
+1 f
+1398(library,)X
+1669(written)X
+1932(by)X
+2048(Esmond)X
+2346(Pitt,)X
+720 758(implements)N
+1183(Larson's)X
+1554(linear)X
+1827(hashing)X
+2165(algorithm)X
+720 846([LAR88])N
+1097(with)X
+1302(an)X
+2 f
+1440(hsearch)X
+1 f
+1756(compatible)X
+2174(interface.)X
+720 934(Intuitively,)N
+1099(a)X
+1161(hash)X
+1334(table)X
+1516(begins)X
+1751(as)X
+1844(a)X
+1905(single)X
+2121(bucket)X
+2360(and)X
+720 1022(grows)N
+941(in)X
+1028(generations,)X
+1443(where)X
+1665(a)X
+1725(generation)X
+2088(corresponds)X
+720 1110(to)N
+815(a)X
+884(doubling)X
+1201(in)X
+1296(the)X
+1427(size)X
+1585(of)X
+1685(the)X
+1815(hash)X
+1994(table.)X
+2222(The)X
+2379(0)X
+2 f
+7 s
+1078(th)Y
+10 s
+1 f
+720 1198(generation)N
+1085(occurs)X
+1321(as)X
+1414(the)X
+1538(table)X
+1719(grows)X
+1940(from)X
+2121(one)X
+2262(bucket)X
+720 1286(to)N
+814(two.)X
+1006(In)X
+1105(the)X
+1235(next)X
+1405(generation)X
+1776(the)X
+1906(table)X
+2093(grows)X
+2320(from)X
+720 1374(two)N
+862(to)X
+946(four.)X
+1122(During)X
+1371(each)X
+1541(generation,)X
+1921(every)X
+2121(bucket)X
+2356(that)X
+720 1462(existed)N
+967(at)X
+1045(the)X
+1163(beginning)X
+1503(of)X
+1590(the)X
+1708(generation)X
+2067(is)X
+2140(split.)X
+892 1576(The)N
+1041(table)X
+1221(starts)X
+1414(as)X
+1505(a)X
+1565(single)X
+1780(bucket)X
+2018(\(numbered)X
+2389(0\),)X
+720 1664(the)N
+839(current)X
+1088(split)X
+1245(bucket)X
+1479(is)X
+1552(set)X
+1661(to)X
+1743(bucket)X
+1977(0,)X
+2057(and)X
+2193(the)X
+2311(max-)X
+720 1752(imum)N
+933(split)X
+1097(point)X
+1288(is)X
+1368(set)X
+1483(to)X
+1571(twice)X
+1771(the)X
+1895(current)X
+2149(split)X
+2312(point)X
+720 1840(\(0\).)N
+863(When)X
+1084(it)X
+1157(is)X
+1239(time)X
+1410(for)X
+1532(a)X
+1596(bucket)X
+1838(to)X
+1928(split,)X
+2113(the)X
+2239(keys)X
+2414(in)X
+720 1928(the)N
+872(current)X
+1154(split)X
+1345(bucket)X
+1612(are)X
+1764(divided)X
+2057(between)X
+2378(the)X
+720 2016(current)N
+981(split)X
+1151(bucket)X
+1397(and)X
+1545(a)X
+1613(new)X
+1779(bucket)X
+2025(whose)X
+2262(bucket)X
+720 2104(number)N
+1000(is)X
+1088(equal)X
+1297(to)X
+1394(1)X
+1469(+)X
+1549(current)X
+1812(split)X
+1984(bucket)X
+2232(+)X
+2311(max-)X
+720 2192(imum)N
+927(split)X
+1085(point.)X
+1310(We)X
+1442(can)X
+1574(determine)X
+1915(which)X
+2131(keys)X
+2298(move)X
+720 2280(to)N
+807(the)X
+929(new)X
+1087(bucket)X
+1325(by)X
+1429(examining)X
+1791(the)X
+2 f
+1913(n)X
+7 s
+1962 2248(th)N
+10 s
+1 f
+2043 2280(bit)N
+2151(of)X
+2242(a)X
+2302(key's)X
+720 2368(hash)N
+899(value)X
+1105(where)X
+1334(n)X
+1406(is)X
+1491(the)X
+1620(generation)X
+1990(number.)X
+2306(After)X
+720 2456(the)N
+846(bucket)X
+1088(at)X
+1174(the)X
+1300(maximum)X
+1651(split)X
+1815(point)X
+2006(has)X
+2140(been)X
+2319(split,)X
+720 2544(the)N
+839(generation)X
+1198(number)X
+1463(is)X
+1536(incremented,)X
+1973(the)X
+2091(current)X
+2339(split)X
+720 2632(point)N
+908(is)X
+985(set)X
+1098(back)X
+1274(to)X
+1360(zero,)X
+1543(and)X
+1683(the)X
+1805(maximum)X
+2152(split)X
+2312(point)X
+720 2720(is)N
+815(set)X
+946(to)X
+1050(the)X
+1190(number)X
+1477(of)X
+1586(the)X
+1725(last)X
+1877(bucket)X
+2132(in)X
+2235(the)X
+2374(\256le)X
+720 2808(\(which)N
+971(is)X
+1052(equal)X
+1253(to)X
+1342(twice)X
+1543(the)X
+1668(old)X
+1797(maximum)X
+2148(split)X
+2312(point)X
+720 2896(plus)N
+873(1\).)X
+892 3010(To)N
+1031(facilitate)X
+1361(locating)X
+1668(keys,)X
+1884(we)X
+2027(maintain)X
+2356(two)X
+720 3098(masks.)N
+989(The)X
+1143(low)X
+1291(mask)X
+1488(is)X
+1569(equal)X
+1771(to)X
+1861(the)X
+1987(maximum)X
+2339(split)X
+720 3186(bucket)N
+967(and)X
+1116(the)X
+1247(high)X
+1422(mask)X
+1624(is)X
+1710(equal)X
+1917(to)X
+2011(the)X
+2141(next)X
+2311(max-)X
+720 3274(imum)N
+931(split)X
+1093(bucket.)X
+1372(To)X
+1486(locate)X
+1703(a)X
+1764(speci\256c)X
+2033(key,)X
+2193(we)X
+2311(com-)X
+720 3362(pute)N
+881(a)X
+940(32-bit)X
+1154(hash)X
+1324(value)X
+1520(using)X
+1715(a)X
+1773(bit-randomizing)X
+2311(algo-)X
+720 3450(rithm)N
+932(such)X
+1118(as)X
+1224(the)X
+1361(one)X
+1516(described)X
+1862(in)X
+1962([LAR88].)X
+2334(This)X
+720 3538(hash)N
+893(value)X
+1093(is)X
+1172(then)X
+1336(masked)X
+1607(with)X
+1775(the)X
+1898(high)X
+2065(mask.)X
+2299(If)X
+2378(the)X
+720 3626(resulting)N
+1026(number)X
+1297(is)X
+1376(greater)X
+1626(than)X
+1790(the)X
+1913(maximum)X
+2262(bucket)X
+720 3714(in)N
+823(the)X
+962(table)X
+1159(\(current)X
+1455(split)X
+1633(bucket)X
+1888(+)X
+1974(maximum)X
+2339(split)X
+720 3802(point\),)N
+962(the)X
+1091(hash)X
+1269(value)X
+1474(is)X
+1558(masked)X
+1834(with)X
+2007(the)X
+2136(low)X
+2287(mask.)X
+720 3890(In)N
+825(either)X
+1046(case,)X
+1242(the)X
+1377(result)X
+1592(of)X
+1696(the)X
+1831(mask)X
+2037(is)X
+2127(the)X
+2262(bucket)X
+720 3978(number)N
+989(for)X
+1107(the)X
+1229(given)X
+1431(key.)X
+1611(The)X
+1759(algorithm)X
+2093(below)X
+2312(illus-)X
+720 4066(trates)N
+914(this)X
+1049(process.)X
+0 f
+8 s
+720 4365(h)N
+796(=)X
+872 -0.4038(calchash\(key\);)AX
+720 4453(bucket)N
+986(=)X
+1062(h)X
+1138(&)X
+1214 -0.4167(high_mask;)AX
+720 4541(if)N
+834(\()X
+910(bucket)X
+1176(>)X
+1252 -0.4167(max_bucket)AX
+1670(\))X
+1008 4629(bucket)N
+1274(=)X
+1350(h)X
+1426(&)X
+1502 -0.4219(low_mask;)AX
+720 4717 -0.4018(return\(bucket\);)AN
+1 f
+10 s
+892 5042(In)N
+1013(order)X
+1237(to)X
+1353(decide)X
+1617(when)X
+1845(to)X
+1961(split)X
+2152(a)X
+2242(bucket,)X
+2 f
+720 5130(dynahash)N
+1 f
+1050(uses)X
+2 f
+1210(controlled)X
+1561(splitting)X
+1 f
+1822(.)X
+1884(A)X
+1964(hash)X
+2133(table)X
+2311(has)X
+2440(a)X
+720 5218(\256ll)N
+837(factor)X
+1054(which)X
+1279(is)X
+1361(expressed)X
+1707(in)X
+1798(terms)X
+2004(of)X
+2099(the)X
+2225(average)X
+720 5306(number)N
+990(of)X
+1082(keys)X
+1253(in)X
+1339(each)X
+1511(bucket.)X
+1789(Each)X
+1974(time)X
+2140(the)X
+2262(table's)X
+720 5394(total)N
+885(number)X
+1153(of)X
+1243(keys)X
+1413(divided)X
+1676(by)X
+1778(its)X
+1875(number)X
+2142(of)X
+2231(buckets)X
+720 5482(exceeds)N
+995(this)X
+1130(\256ll)X
+1238(factor,)X
+1466(a)X
+1522(bucket)X
+1756(is)X
+1829(split.)X
+2878 538(Since)N
+3079(the)X
+2 f
+3200(hsearch)X
+1 f
+3477(create)X
+3693(interface)X
+3998(\()X
+2 f
+4025(hcreate)X
+1 f
+4266(\))X
+4315(calls)X
+2706 626(for)N
+2842(an)X
+2960(estimate)X
+3269(of)X
+3378(the)X
+3518(\256nal)X
+3702(size)X
+3869(of)X
+3978(the)X
+4118(hash)X
+4306(table)X
+2706 714(\()N
+2 f
+2733(nelem)X
+1 f
+2925(\),)X
+2 f
+3007(dynahash)X
+1 f
+3349(uses)X
+3522(this)X
+3672(information)X
+4085(to)X
+4182(initialize)X
+2706 802(the)N
+2848(table.)X
+3088(The)X
+3257(initial)X
+3486(number)X
+3774(of)X
+3884(buckets)X
+4172(is)X
+4268(set)X
+4400(to)X
+2 f
+2706 890(nelem)N
+1 f
+2926(rounded)X
+3217(to)X
+3306(the)X
+3431(next)X
+3596(higher)X
+3828(power)X
+4056(of)X
+4150(two.)X
+4337(The)X
+2706 978(current)N
+2958(split)X
+3118(point)X
+3305(is)X
+3381(set)X
+3493(to)X
+3578(0)X
+3641(and)X
+3780(the)X
+3901(maximum)X
+4248(bucket)X
+2706 1066(and)N
+2842(maximum)X
+3186(split)X
+3343(point)X
+3527(are)X
+3646(set)X
+3755(to)X
+3837(this)X
+3972(rounded)X
+4255(value.)X
+3 f
+3148 1220(The)N
+3301(New)X
+3473(Implementation)X
+1 f
+2878 1352(Our)N
+3042(implementation)X
+3583(is)X
+3675(also)X
+3842(based)X
+4063(on)X
+4181(Larson's)X
+2706 1440(linear)N
+2939(hashing)X
+3238([LAR88])X
+3582(algorithm)X
+3943(as)X
+4060(well)X
+4248(as)X
+4364(the)X
+2 f
+2706 1528(dynahash)N
+1 f
+3047(implementation.)X
+3623(The)X
+2 f
+3782(dbm)X
+1 f
+3954(family)X
+4197(of)X
+4297(algo-)X
+2706 1616(rithms)N
+2942(decide)X
+3184(dynamically)X
+3612(which)X
+3840(bucket)X
+4085(to)X
+4178(split)X
+4346(and)X
+2706 1704(when)N
+2914(to)X
+3010(split)X
+3180(it)X
+3257(\(when)X
+3491(it)X
+3568(over\257ows\))X
+3944(while)X
+2 f
+4155(dynahash)X
+1 f
+2706 1792(splits)N
+2933(in)X
+3054(a)X
+3149(prede\256ned)X
+3547(order)X
+3776(\(linearly\))X
+4134(and)X
+4309(at)X
+4426(a)X
+2706 1880(prede\256ned)N
+3116(time)X
+3328(\(when)X
+3599(the)X
+3767(table)X
+3993(\256ll)X
+4151(factor)X
+4409(is)X
+2706 1968(exceeded\).)N
+3121(We)X
+3280(use)X
+3434(a)X
+3517(hybrid)X
+3773(of)X
+3887(these)X
+4099(techniques.)X
+2706 2056(Splits)N
+2913(occur)X
+3118(in)X
+3206(the)X
+3330(prede\256ned)X
+3695(order)X
+3891(of)X
+3984(linear)X
+4193(hashing,)X
+2706 2144(but)N
+2845(the)X
+2980(time)X
+3159(at)X
+3253(which)X
+3485(pages)X
+3704(are)X
+3839(split)X
+4012(is)X
+4101(determined)X
+2706 2232(both)N
+2869(by)X
+2970(page)X
+3143(over\257ows)X
+3480(\()X
+2 f
+3507(uncontrolled)X
+3937(splitting)X
+1 f
+4198(\))X
+4246(and)X
+4382(by)X
+2706 2320(exceeding)N
+3052(the)X
+3170(\256ll)X
+3278(factor)X
+3486(\()X
+2 f
+3513(controlled)X
+3862(splitting)X
+1 f
+4123(\))X
+2878 2434(A)N
+2962(hash)X
+3135(table)X
+3317(is)X
+3395(parameterized)X
+3876(by)X
+3981(both)X
+4148(its)X
+4248(bucket)X
+2706 2522(size)N
+2904(\()X
+2 f
+2931(bsize)X
+1 f
+(\))S
+3191(and)X
+3380(\256ll)X
+3541(factor)X
+3801(\()X
+2 f
+3828(ffactor)X
+1 f
+4041(\).)X
+4180(Whereas)X
+2 f
+2706 2610(dynahash's)N
+1 f
+3095(buckets)X
+3364(can)X
+3500(be)X
+3599(represented)X
+3993(as)X
+4083(a)X
+4142(linked)X
+4365(list)X
+2706 2698(of)N
+2798(elements)X
+3108(in)X
+3195(memory,)X
+3507(our)X
+3639(package)X
+3928(needs)X
+4136(to)X
+4222(support)X
+2706 2786(disk)N
+2874(access,)X
+3135(and)X
+3286(must)X
+3476(represent)X
+3806(buckets)X
+4086(in)X
+4183(terms)X
+4395(of)X
+2706 2874(pages.)N
+2955(The)X
+2 f
+3106(bsize)X
+1 f
+3291(is)X
+3369(the)X
+3492(size)X
+3642(\(in)X
+3756(bytes\))X
+3977(of)X
+4069(these)X
+4259(pages.)X
+2706 2962(As)N
+2833(in)X
+2933(linear)X
+3154(hashing,)X
+3461(the)X
+3597(number)X
+3879(of)X
+3983(buckets)X
+4265(in)X
+4364(the)X
+2706 3050(table)N
+2906(is)X
+3003(equal)X
+3221(to)X
+3327(the)X
+3469(number)X
+3758(of)X
+3869(keys)X
+4060(in)X
+4165(the)X
+4306(table)X
+2706 3138(divided)N
+2988(by)X
+2 f
+3110(ffactor)X
+1 f
+3323(.)X
+2 f
+8 s
+3113(6)Y
+1 f
+10 s
+3417 3138(The)N
+3584(controlled)X
+3950(splitting)X
+4252(occurs)X
+2706 3226(each)N
+2878(time)X
+3044(the)X
+3166(number)X
+3435(of)X
+3526(keys)X
+3697(in)X
+3783(the)X
+3905(table)X
+4085(exceeds)X
+4364(the)X
+2706 3314(\256ll)N
+2814(factor)X
+3022(multiplied)X
+3370(by)X
+3470(the)X
+3588(number)X
+3853(of)X
+3940(buckets.)X
+2878 3428(Inserting)N
+3187(keys)X
+3358(and)X
+3498(splitting)X
+3783(buckets)X
+4051(is)X
+4127(performed)X
+2706 3516(precisely)N
+3018(as)X
+3107(described)X
+3437(previously)X
+3796(for)X
+2 f
+3911(dynahash)X
+1 f
+4218(.)X
+4279(How-)X
+2706 3604(ever,)N
+2897(since)X
+3094(buckets)X
+3371(are)X
+3502(now)X
+3671(comprised)X
+4036(of)X
+4134(pages,)X
+4368(we)X
+2706 3692(must)N
+2883(be)X
+2981(prepared)X
+3284(to)X
+3367(handle)X
+3602(cases)X
+3793(where)X
+4011(the)X
+4130(size)X
+4276(of)X
+4364(the)X
+2706 3780(keys)N
+2873(and)X
+3009(data)X
+3163(in)X
+3245(a)X
+3301(bucket)X
+3535(exceed)X
+3779(the)X
+3897(bucket)X
+4131(size.)X
+3 f
+3318 3934(Over\257ow)N
+3654(Pages)X
+1 f
+2878 4066(There)N
+3095(are)X
+3223(two)X
+3372(cases)X
+3571(where)X
+3797(a)X
+3862(key)X
+4007(may)X
+4174(not)X
+4305(\256t)X
+4400(in)X
+2706 4154(its)N
+2802(designated)X
+3166(bucket.)X
+3441(In)X
+3529(the)X
+3647(\256rst)X
+3791(case,)X
+3970(the)X
+4088(total)X
+4250(size)X
+4395(of)X
+2706 4242(the)N
+2833(key)X
+2978(and)X
+3123(data)X
+3286(may)X
+3453(exceed)X
+3706(the)X
+3833(bucket)X
+4076(size.)X
+4269(In)X
+4364(the)X
+2706 4330(second,)N
+3008(addition)X
+3328(of)X
+3453(a)X
+3547(new)X
+3739(key)X
+3913(could)X
+4149(cause)X
+4386(an)X
+2706 4418(over\257ow,)N
+3068(but)X
+3227(the)X
+3382(bucket)X
+3652(in)X
+3770(question)X
+4097(is)X
+4206(not)X
+4364(yet)X
+2706 4506(scheduled)N
+3049(to)X
+3133(be)X
+3230(split.)X
+3428(In)X
+3516(existing)X
+3790(implementations,)X
+4364(the)X
+2706 4594(second)N
+2953(case)X
+3115(never)X
+3317(arises)X
+3523(\(since)X
+3738(buckets)X
+4006(are)X
+4128(split)X
+4288(when)X
+2706 4682(they)N
+2871(over\257ow\))X
+3210(and)X
+3352(the)X
+3476(\256rst)X
+3626(case)X
+3791(is)X
+3870(not)X
+3998(handled)X
+4278(at)X
+4362(all.)X
+2706 4770(Although)N
+3036(large)X
+3225(key/data)X
+3525(pair)X
+3678(handling)X
+3986(is)X
+4066(dif\256cult)X
+4346(and)X
+2706 4858(expensive,)N
+3083(it)X
+3163(is)X
+3252(essential.)X
+3604(In)X
+3706(a)X
+3777(linear)X
+3995(hashed)X
+4253(imple-)X
+2706 4946(mentation,)N
+3087(over\257ow)X
+3413(pages)X
+3636(are)X
+3775(required)X
+4083(for)X
+4217(buckets)X
+2706 5034(which)N
+2935(over\257ow)X
+3253(before)X
+3492(they)X
+3662(are)X
+3793(split,)X
+3982(so)X
+4085(we)X
+4211(can)X
+4355(use)X
+2706 5122(the)N
+2833(same)X
+3027(mechanism)X
+3421(for)X
+3544(large)X
+3734(key/data)X
+4035(pairs)X
+4220(that)X
+4368(we)X
+2706 5210(use)N
+2837(for)X
+2955(over\257ow)X
+3264(pages.)X
+3511(Logically,)X
+3862(we)X
+3980(chain)X
+4177(over\257ow)X
+16 s
+2706 5353 MXY
+864 0 Dl
+2 f
+8 s
+2746 5408(6)N
+1 f
+9 s
+2801 5433(This)N
+2952(is)X
+3023(not)X
+3138(strictly)X
+3361(true.)X
+3532(The)X
+3667(\256le)X
+3782(does)X
+3937(not)X
+4052(contract)X
+4306(when)X
+2706 5513(keys)N
+2861(are)X
+2972(deleted,)X
+3221(so)X
+3308(the)X
+3419(number)X
+3662(of)X
+3744(buckets)X
+3986(is)X
+4056(actually)X
+4306(equal)X
+2706 5593(to)N
+2782(the)X
+2890(maximum)X
+3202(number)X
+3441(of)X
+3520(keys)X
+3671(ever)X
+3814(present)X
+4041(in)X
+4116(the)X
+4223(table)X
+4382(di-)X
+2706 5673(vided)N
+2884(by)X
+2974(the)X
+3080(\256ll)X
+3178(factor.)X
+3 f
+10 s
+720 5960(USENIX)N
+9 f
+1042(-)X
+3 f
+1106(Winter)X
+1371('91)X
+9 f
+1498(-)X
+3 f
+1562(Dallas,)X
+1815(TX)X
+4424(5)X
+
+6 p
+%%Page: 6 6
+0(Courier)xf 0 f
+10 s 10 xH 0 xS 0 f
+3 f
+432 258(A)N
+510(New)X
+682(Hashing)X
+985(Package)X
+1290(for)X
+1413(UNIX)X
+3663(Seltzer)X
+3920(&)X
+4007(Yigit)X
+1 f
+432 538(pages)N
+639(to)X
+725(the)X
+847(buckets)X
+1116(\(also)X
+1296(called)X
+1512(primary)X
+1789(pages\).)X
+2062(In)X
+2152(a)X
+432 626(memory)N
+730(based)X
+943(representation,)X
+1448(over\257ow)X
+1763(pages)X
+1976(do)X
+2086(not)X
+432 714(pose)N
+628(any)X
+792(special)X
+1063(problems)X
+1409(because)X
+1712(we)X
+1854(can)X
+2014(chain)X
+432 802(over\257ow)N
+776(pages)X
+1017(to)X
+1137(primary)X
+1449(pages)X
+1690(using)X
+1921(memory)X
+432 890(pointers.)N
+776(However,)X
+1137(mapping)X
+1463(these)X
+1674(over\257ow)X
+2005(pages)X
+432 978(into)N
+584(a)X
+648(disk)X
+809(\256le)X
+939(is)X
+1019(more)X
+1211(of)X
+1305(a)X
+1368(challenge,)X
+1723(since)X
+1915(we)X
+2036(need)X
+432 1066(to)N
+547(be)X
+675(able)X
+861(to)X
+975(address)X
+1268(both)X
+1462(bucket)X
+1728(pages,)X
+1983(whose)X
+432 1154(numbers)N
+729(are)X
+849(growing)X
+1137(linearly,)X
+1422(and)X
+1558(some)X
+1747(indeterminate)X
+432 1242(number)N
+715(of)X
+820(over\257ow)X
+1143(pages)X
+1364(without)X
+1646(reorganizing)X
+2090(the)X
+432 1330(\256le.)N
+604 1444(One)N
+789(simple)X
+1053(solution)X
+1361(would)X
+1612(be)X
+1739(to)X
+1852(allocate)X
+2152(a)X
+432 1532(separate)N
+737(\256le)X
+880(for)X
+1015(over\257ow)X
+1341(pages.)X
+1604(The)X
+1769(disadvantage)X
+432 1620(with)N
+605(such)X
+783(a)X
+850(technique)X
+1193(is)X
+1276(that)X
+1426(it)X
+1500(requires)X
+1789(an)X
+1895(extra)X
+2086(\256le)X
+432 1708(descriptor,)N
+794(an)X
+891(extra)X
+1073(system)X
+1316(call)X
+1453(on)X
+1554(open)X
+1731(and)X
+1867(close,)X
+2072(and)X
+432 1796(logically)N
+739(associating)X
+1122(two)X
+1269(independent)X
+1687(\256les.)X
+1886(For)X
+2023(these)X
+432 1884(reasons,)N
+728(we)X
+857(wanted)X
+1123(to)X
+1219(map)X
+1391(both)X
+1567(primary)X
+1855(pages)X
+2072(and)X
+432 1972(over\257ow)N
+737(pages)X
+940(into)X
+1084(the)X
+1202(same)X
+1387(\256le)X
+1509(space.)X
+604 2086(The)N
+799(buddy-in-waiting)X
+1425(algorithm)X
+1806(provides)X
+2152(a)X
+432 2174(mechanism)N
+851(to)X
+966(support)X
+1259(multiple)X
+1578(pages)X
+1814(per)X
+1970(logical)X
+432 2262(bucket)N
+685(while)X
+902(retaining)X
+1226(the)X
+1362(simple)X
+1613(split)X
+1788(sequence)X
+2121(of)X
+432 2350(linear)N
+681(hashing.)X
+1015(Over\257ow)X
+1383(pages)X
+1631(are)X
+1795(preallocated)X
+432 2438(between)N
+781(generations)X
+1232(of)X
+1379(primary)X
+1713(pages.)X
+1996(These)X
+432 2526(over\257ow)N
+759(pages)X
+984(are)X
+1125(used)X
+1314(by)X
+1436(any)X
+1594(bucket)X
+1850(containing)X
+432 2614(more)N
+646(keys)X
+842(than)X
+1029(\256t)X
+1144(on)X
+1273(the)X
+1420(primary)X
+1723(page)X
+1924(and)X
+2089(are)X
+432 2702(reclaimed,)N
+808(if)X
+896(possible,)X
+1217(when)X
+1430(the)X
+1567(bucket)X
+1819(later)X
+2000(splits.)X
+432 2790(Figure)N
+687(3)X
+773(depicts)X
+1045(the)X
+1188(layout)X
+1433(of)X
+1545(primary)X
+1844(pages)X
+2072(and)X
+432 2878(over\257ow)N
+752(pages)X
+970(within)X
+1209(the)X
+1342(same)X
+1542(\256le.)X
+1699(Over\257ow)X
+2036(page)X
+432 2966(use)N
+586(information)X
+1011(is)X
+1111(recorded)X
+1440(in)X
+1548(bitmaps)X
+1847(which)X
+2089(are)X
+432 3054(themselves)N
+819(stored)X
+1046(on)X
+1157(over\257ow)X
+1472(pages.)X
+1725(The)X
+1880(addresses)X
+432 3142(of)N
+520(the)X
+639(bitmap)X
+882(pages)X
+1086(and)X
+1223(the)X
+1342(number)X
+1608(of)X
+1695(pages)X
+1898(allocated)X
+432 3230(at)N
+515(each)X
+688(split)X
+850(point)X
+1039(are)X
+1163(stored)X
+1384(in)X
+1470(the)X
+1592(\256le)X
+1718(header.)X
+1997(Using)X
+432 3318(this)N
+577(information,)X
+1005(both)X
+1177(over\257ow)X
+1492(addresses)X
+1829(and)X
+1974(bucket)X
+432 3406(addresses)N
+764(can)X
+900(be)X
+999(mapped)X
+1276(to)X
+1361(disk)X
+1517(addresses)X
+1848(by)X
+1951(the)X
+2072(fol-)X
+432 3494(lowing)N
+674(calculation:)X
+0 f
+8 s
+432 3793(int)N
+736(bucket;)X
+1192(/*)X
+1306(bucket)X
+1572(address)X
+1876(*/)X
+432 3881(u_short)N
+736(oaddr;)X
+1192(/*)X
+1306(OVERFLOW)X
+1648(address)X
+1952(*/)X
+432 3969(int)N
+736 -0.4125(nhdr_pages;)AX
+1192(/*)X
+1306(npages)X
+1572(in)X
+1686 -112.4062(\256le)AX
+1838(header)X
+2104(*/)X
+432 4057(int)N
+736 -0.4125(spares[32];)AX
+1192(/*)X
+1306(npages)X
+1572(at)X
+1686(each)X
+1876(split)X
+2104(*/)X
+432 4145(int)N
+736(log2\(\);)X
+1198(/*)X
+1312(ceil\(log)X
+1654(base)X
+1844(2\))X
+1958(*/)X
+432 4321(#DEFINE)N
+736 -0.3929(BUCKET_TO_PAGE\(bucket\))AX
+1610(\\)X
+584 4409(bucket)N
+850(+)X
+926 -0.4167(nhdr_pages)AX
+1344(+)X
+1420(\\)X
+584 4497 -0.3894(\(bucket?spares[logs2\(bucket)AN
+1648(+)X
+1724(1\)-1]:0\))X
+432 4673(#DEFINE)N
+736 -0.3947(OADDR_TO_PAGE\(oaddr\))AX
+1534(\\)X
+584 4761 -0.3984(BUCKET_TO_PAGE\(\(1)AN
+1268(<<)X
+1382 -0.4091(\(oaddr>>11\)\))AX
+1876(-)X
+1952(1\))X
+2066(+)X
+2142(\\)X
+584 4849(oaddr)N
+812(&)X
+888(0x7ff;)X
+1 f
+10 s
+604 5262(An)N
+728(over\257ow)X
+1039(page)X
+1217(is)X
+1295(addressed)X
+1637(by)X
+1742(its)X
+1842(split)X
+2004(point,)X
+432 5350(identifying)N
+858(the)X
+1031(generations)X
+1476(between)X
+1819(which)X
+2090(the)X
+432 5438(over\257ow)N
+740(page)X
+915(is)X
+991(allocated,)X
+1324(and)X
+1463(its)X
+1561(page)X
+1736(number,)X
+2023(iden-)X
+432 5526(tifying)N
+665(the)X
+783(particular)X
+1111(page)X
+1283(within)X
+1507(the)X
+1625(split)X
+1782(point.)X
+1986(In)X
+2073(this)X
+432 5614(implementation,)N
+983(offsets)X
+1225(within)X
+1457(pages)X
+1668(are)X
+1795(16)X
+1903(bits)X
+2046(long)X
+432 5702(\(limiting)N
+732(the)X
+851(maximum)X
+1196(page)X
+1368(size)X
+1513(to)X
+1595(32K\),)X
+1800(so)X
+1891(we)X
+2005(select)X
+2418 538(an)N
+2535(over\257ow)X
+2860(page)X
+3052(addressing)X
+3435(algorithm)X
+3786(that)X
+3946(can)X
+4098(be)X
+2418 626(expressed)N
+2760(in)X
+2847(16)X
+2952(bits)X
+3091(and)X
+3231(which)X
+3451(allows)X
+3684(quick)X
+3886(retrieval.)X
+2418 714(The)N
+2568(top)X
+2695(\256ve)X
+2840(bits)X
+2980(indicate)X
+3258(the)X
+3380(split)X
+3541(point)X
+3729(and)X
+3869(the)X
+3991(lower)X
+2418 802(eleven)N
+2650(indicate)X
+2926(the)X
+3046(page)X
+3220(number)X
+3487(within)X
+3713(the)X
+3832(split)X
+3990(point.)X
+2418 890(Since)N
+2633(\256ve)X
+2789(bits)X
+2940(are)X
+3075(reserved)X
+3384(for)X
+3514(the)X
+3648(split)X
+3821(point,)X
+4041(\256les)X
+2418 978(may)N
+2578(split)X
+2737(32)X
+2839(times)X
+3034(yielding)X
+3318(a)X
+3376(maximum)X
+3721(\256le)X
+3844(size)X
+3990(of)X
+4078(2)X
+7 s
+946(32)Y
+10 s
+2418 1066(buckets)N
+2698(and)X
+2849(32)X
+2 f
+(*)S
+1 f
+2982(2)X
+7 s
+1034(11)Y
+10 s
+3113 1066(over\257ow)N
+3433(pages.)X
+3691(The)X
+3850(maximum)X
+2418 1154(page)N
+2597(size)X
+2749(is)X
+2829(2)X
+7 s
+1122(15)Y
+10 s
+1154(,)Y
+2971(yielding)X
+3259(a)X
+3321(maximum)X
+3671(\256le)X
+3799(size)X
+3950(greater)X
+2418 1242(than)N
+2601(131,000)X
+2906(GB)X
+3061(\(on)X
+3212(\256le)X
+3358(systems)X
+3655(supporting)X
+4041(\256les)X
+2418 1330(larger)N
+2626(than)X
+2784(4GB\).)X
+10 f
+2418 1418 -0.0930(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)AN
+1 Dt
+4014 2275 MXY
+0 133 Dl
+3881 2275 MXY
+0 133 Dl
+3748 2275 MXY
+0 133 Dl
+3083 2275 MXY
+0 133 Dl
+5 s
+1 f
+3523 2475(2/3)N
+3390(2/2)X
+3257(2/1)X
+2859(1/2)X
+2726(1/1)X
+5 Dt
+3814 1743 MXY
+0 133 Dl
+3282 1743 MXY
+0 133 Dl
+3017 1743 MXY
+0 133 Dl
+2884 1743 MXY
+0 133 Dl
+1 Dt
+3681 1743 MXY
+0 133 Dl
+133 0 Dl
+0 -133 Dl
+-133 0 Dl
+3548 MX
+0 133 Dl
+133 0 Dl
+0 -133 Dl
+-133 0 Dl
+3415 MX
+0 133 Dl
+133 0 Dl
+0 -133 Dl
+-133 0 Dl
+3282 MX
+0 133 Dl
+133 0 Dl
+0 -133 Dl
+-133 0 Dl
+3150 MX
+0 133 Dl
+132 0 Dl
+0 -133 Dl
+-132 0 Dl
+3017 MX
+0 133 Dl
+133 0 Dl
+0 -133 Dl
+-133 0 Dl
+2884 MX
+0 133 Dl
+133 0 Dl
+0 -133 Dl
+-133 0 Dl
+3 f
+8 s
+3017 2601(Over\257ow)N
+3285(Addresses)X
+3515 2833(Over\257ow)N
+3783(Pages)X
+2850(Buckets)X
+1 Di
+3349 2740 MXY
+ 3349 2740 lineto
+ 3482 2740 lineto
+ 3482 2873 lineto
+ 3349 2873 lineto
+ 3349 2740 lineto
+closepath 3 3349 2740 3482 2873 Dp
+2684 MX
+0 133 Dl
+133 0 Dl
+0 -133 Dl
+-133 0 Dl
+5 Dt
+4146 2275 MXY
+0 133 Dl
+3216 2275 MXY
+0 133 Dl
+2684 2275 MXY
+0 133 Dl
+2551 2275 MXY
+0 133 Dl
+1 f
+3798 1963(3)N
+3266 1980(2)N
+3001(1)X
+2868(0)X
+1 Dt
+2751 1743 MXY
+0 133 Dl
+133 0 Dl
+0 -133 Dl
+-133 0 Dl
+3548 2275 MXY
+-15 -22 Dl
+2 16 Dl
+-13 11 Dl
+26 -5 Dl
+-282 -117 Dl
+3432 2275 MXY
+-10 -25 Dl
+-2 16 Dl
+-15 8 Dl
+27 1 Dl
+-166 -117 Dl
+3282 2275 MXY
+12 -25 Dl
+-14 10 Dl
+-15 -6 Dl
+17 21 Dl
+-16 -117 Dl
+2884 2275 MXY
+26 7 Dl
+-12 -12 Dl
+3 -16 Dl
+-17 21 Dl
+382 -117 Dl
+2751 2275 MXY
+25 9 Dl
+-11 -12 Dl
+5 -17 Dl
+-19 20 Dl
+515 -117 Dl
+3 f
+3070 2152(Over\257ow)N
+3338(Pages)X
+3482 2275 MXY
+ 3482 2275 lineto
+ 3615 2275 lineto
+ 3615 2408 lineto
+ 3482 2408 lineto
+ 3482 2275 lineto
+closepath 3 3482 2275 3615 2408 Dp
+3349 MX
+ 3349 2275 lineto
+ 3482 2275 lineto
+ 3482 2408 lineto
+ 3349 2408 lineto
+ 3349 2275 lineto
+closepath 3 3349 2275 3482 2408 Dp
+3216 MX
+ 3216 2275 lineto
+ 3349 2275 lineto
+ 3349 2408 lineto
+ 3216 2408 lineto
+ 3216 2275 lineto
+closepath 3 3216 2275 3349 2408 Dp
+2817 MX
+ 2817 2275 lineto
+ 2950 2275 lineto
+ 2950 2408 lineto
+ 2817 2408 lineto
+ 2817 2275 lineto
+closepath 3 2817 2275 2950 2408 Dp
+2684 MX
+ 2684 2275 lineto
+ 2817 2275 lineto
+ 2817 2408 lineto
+ 2684 2408 lineto
+ 2684 2275 lineto
+closepath 3 2684 2275 2817 2408 Dp
+3615 MX
+0 133 Dl
+531 0 Dl
+0 -133 Dl
+-531 0 Dl
+2950 MX
+0 133 Dl
+266 0 Dl
+0 -133 Dl
+-266 0 Dl
+2551 MX
+0 133 Dl
+133 0 Dl
+0 -133 Dl
+-133 0 Dl
+3798 1726 MXY
+-21 -18 Dl
+6 16 Dl
+-10 13 Dl
+25 -11 Dl
+-599 -99 Dl
+3266 1726 MXY
+-1 -27 Dl
+-7 15 Dl
+-17 1 Dl
+25 11 Dl
+-67 -99 Dl
+3033 1726 MXY
+27 1 Dl
+-14 -8 Dl
+-1 -17 Dl
+-12 24 Dl
+166 -99 Dl
+2900 1726 MXY
+27 7 Dl
+-13 -11 Dl
+3 -17 Dl
+-17 21 Dl
+299 -99 Dl
+3058 1621(Split)N
+3203(Points)X
+2418 2275 MXY
+0 133 Dl
+133 0 Dl
+0 -133 Dl
+-133 0 Dl
+3 Dt
+-1 Ds
+3137(Figure)Y
+2619(3:)X
+1 f
+2691(Split)X
+2832(points)X
+3008(occur)X
+3168(between)X
+3399(generations)X
+3712(and)X
+3823(are)X
+3919(numbered)X
+2418 3225(from)N
+2560(0.)X
+2642(In)X
+2713(this)X
+2824(\256gure)X
+2991(there)X
+3136(are)X
+3231(two)X
+3345(over\257ow)X
+3590(pages)X
+3753(allocated)X
+4000(at)X
+4063(split)X
+2418 3313(point)N
+2566(1)X
+2614(and)X
+2722(three)X
+2865(allocated)X
+3111(at)X
+3173(split)X
+3300(point)X
+3448(2.)X
+10 s
+10 f
+2418 3489 -0.0930(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)AN
+3 f
+2949 3731(Buffer)N
+3192(Management)X
+1 f
+2590 3863(The)N
+2744(hash)X
+2920(table)X
+3105(is)X
+3187(stored)X
+3412(in)X
+3502(memory)X
+3797(as)X
+3892(a)X
+3956(logical)X
+2418 3951(array)N
+2633(of)X
+2749(bucket)X
+3012(pointers.)X
+3359(Physically,)X
+3761(the)X
+3907(array)X
+4121(is)X
+2418 4039(arranged)N
+2728(in)X
+2818(segments)X
+3144(of)X
+3239(256)X
+3387(pointers.)X
+3713(Initially,)X
+4013(there)X
+2418 4127(is)N
+2530(space)X
+2767(to)X
+2887(allocate)X
+3195(256)X
+3373(segments.)X
+3769(Reallocation)X
+2418 4215(occurs)N
+2651(when)X
+2847(the)X
+2967(number)X
+3234(of)X
+3323(buckets)X
+3590(exceeds)X
+3867(32K)X
+4027(\(256)X
+2418 4303(*)N
+2508(256\).)X
+2745(Primary)X
+3053(pages)X
+3286(may)X
+3473(be)X
+3598(accessed)X
+3929(directly)X
+2418 4391(through)N
+2711(the)X
+2853(array)X
+3062(by)X
+3185(bucket)X
+3442(number)X
+3730(and)X
+3889(over\257ow)X
+2418 4479(pages)N
+2628(are)X
+2754 0.4028(referenced)AX
+3122(logically)X
+3429(by)X
+3536(their)X
+3710(over\257ow)X
+4022(page)X
+2418 4567(address.)N
+2726(For)X
+2864(small)X
+3063(hash)X
+3236(tables,)X
+3469(it)X
+3539(is)X
+3618(desirable)X
+3934(to)X
+4022(keep)X
+2418 4655(all)N
+2525(pages)X
+2735(in)X
+2823(main)X
+3009(memory)X
+3302(while)X
+3506(on)X
+3612(larger)X
+3826(tables,)X
+4059(this)X
+2418 4743(is)N
+2523(probably)X
+2860(impossible.)X
+3298(To)X
+3438(satisfy)X
+3698(both)X
+3891(of)X
+4009(these)X
+2418 4831(requirements,)N
+2900(the)X
+3041(package)X
+3348(includes)X
+3658(buffer)X
+3897(manage-)X
+2418 4919(ment)N
+2598(with)X
+2760(LRU)X
+2940(\(least)X
+3134(recently)X
+3413(used\))X
+3607(replacement.)X
+2590 5033(By)N
+2730(default,)X
+3020(the)X
+3165(package)X
+3475(allocates)X
+3802(up)X
+3928(to)X
+4036(64K)X
+2418 5121(bytes)N
+2616(of)X
+2712(buffered)X
+3014(pages.)X
+3246(All)X
+3377(pages)X
+3589(in)X
+3680(the)X
+3807(buffer)X
+4032(pool)X
+2418 5209(are)N
+2542(linked)X
+2766(in)X
+2852(LRU)X
+3036(order)X
+3230(to)X
+3316(facilitate)X
+3621(fast)X
+3761(replacement.)X
+2418 5297(Whereas)N
+2724(ef\256cient)X
+3011(access)X
+3241(to)X
+3327(primary)X
+3605(pages)X
+3812(is)X
+3889(provided)X
+2418 5385(by)N
+2521(the)X
+2642(bucket)X
+2879(array,)X
+3087(ef\256cient)X
+3372(access)X
+3600(to)X
+3684(over\257ow)X
+3991(pages)X
+2418 5473(is)N
+2501(provided)X
+2816(by)X
+2926(linking)X
+3182(over\257ow)X
+3497(page)X
+3679(buffers)X
+3936(to)X
+4027(their)X
+2418 5561(predecessor)N
+2827(page)X
+3008(\(either)X
+3247(the)X
+3374(primary)X
+3657(page)X
+3838(or)X
+3933(another)X
+2418 5649(over\257ow)N
+2742(page\).)X
+3000(This)X
+3181(means)X
+3425(that)X
+3584(an)X
+3699(over\257ow)X
+4022(page)X
+3 f
+432 5960(6)N
+2970(USENIX)X
+9 f
+3292(-)X
+3 f
+3356(Winter)X
+3621('91)X
+9 f
+3748(-)X
+3 f
+3812(Dallas,)X
+4065(TX)X
+
+7 p
+%%Page: 7 7
+0(Courier)xf 0 f
+10 s 10 xH 0 xS 0 f
+3 f
+720 258(Seltzer)N
+977(&)X
+1064(Yigit)X
+3278(A)X
+3356(New)X
+3528(Hashing)X
+3831(Package)X
+4136(for)X
+4259(UNIX)X
+1 f
+720 538(cannot)N
+955(be)X
+1052(present)X
+1305(in)X
+1388(the)X
+1507(buffer)X
+1724(pool)X
+1886(if)X
+1955(its)X
+2050(primary)X
+2324(page)X
+720 626(is)N
+804(not)X
+937(present.)X
+1240(This)X
+1413(does)X
+1591(not)X
+1724(impact)X
+1972(performance)X
+2409(or)X
+720 714(functionality,)N
+1209(because)X
+1524(an)X
+1660(over\257ow)X
+2005(page)X
+2217(will)X
+2400(be)X
+720 802(accessed)N
+1048(only)X
+1236(after)X
+1430(its)X
+1550(predecessor)X
+1975(page)X
+2172(has)X
+2324(been)X
+720 890(accessed.)N
+1068(Figure)X
+1303(4)X
+1369(depicts)X
+1622(the)X
+1746(data)X
+1905(structures)X
+2242(used)X
+2414(to)X
+720 978(manage)N
+990(the)X
+1108(buffer)X
+1325(pool.)X
+892 1092(The)N
+1040(in-memory)X
+1419(bucket)X
+1656(array)X
+1845(contains)X
+2134(pointers)X
+2414(to)X
+720 1180(buffer)N
+975(header)X
+1248(structures)X
+1617(which)X
+1870(represent)X
+2222(primary)X
+720 1268(pages.)N
+968(Buffer)X
+1203(headers)X
+1474(contain)X
+1735(modi\256ed)X
+2043(bits,)X
+2202(the)X
+2324(page)X
+720 1356(address)N
+995(of)X
+1096(the)X
+1228(buffer,)X
+1479(a)X
+1548(pointer)X
+1808(to)X
+1903(the)X
+2034(actual)X
+2259(buffer,)X
+720 1444(and)N
+875(a)X
+950(pointer)X
+1216(to)X
+1317(the)X
+1454(buffer)X
+1690(header)X
+1944(for)X
+2077(an)X
+2191(over\257ow)X
+720 1532(page)N
+901(if)X
+979(it)X
+1052(exists,)X
+1283(in)X
+1374(addition)X
+1665(to)X
+1756(the)X
+1883(LRU)X
+2072(links.)X
+2296(If)X
+2378(the)X
+720 1620(buffer)N
+950(corresponding)X
+1442(to)X
+1537(a)X
+1606(particular)X
+1947(bucket)X
+2194(is)X
+2280(not)X
+2414(in)X
+720 1708(memory,)N
+1048(its)X
+1164(pointer)X
+1432(is)X
+1526(NULL.)X
+1801(In)X
+1909(effect,)X
+2154(pages)X
+2377(are)X
+720 1796(linked)N
+950(in)X
+1042(three)X
+1233(ways.)X
+1468(Using)X
+1689(the)X
+1817(buffer)X
+2043(headers,)X
+2338(they)X
+720 1884(are)N
+851(linked)X
+1083(physically)X
+1444(through)X
+1725(the)X
+1854(LRU)X
+2045(links)X
+2231(and)X
+2378(the)X
+720 1972(over\257ow)N
+1036(links.)X
+1241(Using)X
+1462(the)X
+1590(pages)X
+1803(themselves,)X
+2209(they)X
+2377(are)X
+720 2060(linked)N
+943(logically)X
+1246(through)X
+1518(the)X
+1639(over\257ow)X
+1946(addresses)X
+2276(on)X
+2378(the)X
+720 2148(page.)N
+948(Since)X
+1162(over\257ow)X
+1482(pages)X
+1700(are)X
+1834(accessed)X
+2151(only)X
+2328(after)X
+720 2236(their)N
+904(predecessor)X
+1321(pages,)X
+1560(they)X
+1734(are)X
+1869(removed)X
+2186(from)X
+2378(the)X
+720 2324(buffer)N
+937(pool)X
+1099(when)X
+1293(their)X
+1460(primary)X
+1734(is)X
+1807(removed.)X
+10 f
+720 2412 -0.0930(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)AN
+1 Dt
+2309 3177 MXY
+24 15 Dl
+-8 -15 Dl
+8 -15 Dl
+-24 15 Dl
+52 0 Dl
+789 3160 MXY
+-35 0 Dl
+0 -156 Dl
+1607 0 Dl
+0 173 Dl
+789 3091 MXY
+-24 -15 Dl
+9 15 Dl
+-9 15 Dl
+24 -15 Dl
+-69 0 Dl
+2309 3125 MXY
+104 0 Dl
+0 -155 Dl
+-1693 0 Dl
+0 121 Dl
+927 3160 MXY
+24 15 Dl
+-9 -15 Dl
+9 -15 Dl
+-24 15 Dl
+553 0 Dl
+1618 3177 MXY
+8 27 Dl
+4 -17 Dl
+16 -6 Dl
+-28 -4 Dl
+138 121 Dl
+1895 3315 MXY
+28 3 Dl
+-15 -9 Dl
+1 -18 Dl
+-14 24 Dl
+276 -138 Dl
+3108 MY
+-28 -3 Dl
+15 10 Dl
+-1 17 Dl
+14 -24 Dl
+-276 138 Dl
+1756 3229 MXY
+-8 -27 Dl
+-3 17 Dl
+-16 6 Dl
+27 4 Dl
+-138 -121 Dl
+1480 MX
+-24 -15 Dl
+9 15 Dl
+-9 15 Dl
+24 -15 Dl
+-553 0 Dl
+3 f
+5 s
+1083 3073(LRU)N
+1178(chain)X
+4 Ds
+1402 3851 MXY
+ 1402 3851 lineto
+ 1471 3851 lineto
+ 1471 3920 lineto
+ 1402 3920 lineto
+ 1402 3851 lineto
+closepath 19 1402 3851 1471 3920 Dp
+1445 3747(Over\257ow)N
+1613(Address)X
+1549 3609 MXY
+0 69 Dl
+1756 MX
+-23 -15 Dl
+8 15 Dl
+-8 15 Dl
+23 -15 Dl
+-207 0 Dl
+-1 Ds
+3 Dt
+1756 3419 MXY
+-6 -28 Dl
+-4 17 Dl
+-17 5 Dl
+27 6 Dl
+-138 -138 Dl
+2240 3471 MXY
+15 -24 Dl
+-15 9 Dl
+-15 -9 Dl
+15 24 Dl
+0 -138 Dl
+1826 3609 MXY
+15 -24 Dl
+-15 9 Dl
+-16 -9 Dl
+16 24 Dl
+0 -138 Dl
+1549 MX
+15 -24 Dl
+-15 9 Dl
+-15 -9 Dl
+15 24 Dl
+0 -138 Dl
+858 3471 MXY
+15 -24 Dl
+-15 9 Dl
+-15 -9 Dl
+15 24 Dl
+0 -138 Dl
+2240 3056 MXY
+15 -24 Dl
+-15 9 Dl
+-15 -9 Dl
+15 24 Dl
+0 -138 Dl
+1549 3056 MXY
+15 -24 Dl
+-15 9 Dl
+-15 -9 Dl
+15 24 Dl
+0 -138 Dl
+858 3056 MXY
+15 -24 Dl
+-15 9 Dl
+-15 -9 Dl
+15 24 Dl
+0 -138 Dl
+1 Dt
+2171 3471 MXY
+ 2171 3471 lineto
+ 2448 3471 lineto
+ 2448 3609 lineto
+ 2171 3609 lineto
+ 2171 3471 lineto
+closepath 19 2171 3471 2448 3609 Dp
+1756 3609 MXY
+ 1756 3609 lineto
+ 2033 3609 lineto
+ 2033 3747 lineto
+ 1756 3747 lineto
+ 1756 3609 lineto
+closepath 3 1756 3609 2033 3747 Dp
+1480 3471 MXY
+ 1480 3471 lineto
+ 1756 3471 lineto
+ 1756 3609 lineto
+ 1480 3609 lineto
+ 1480 3471 lineto
+closepath 19 1480 3471 1756 3609 Dp
+789 MX
+ 789 3471 lineto
+ 1065 3471 lineto
+ 1065 3609 lineto
+ 789 3609 lineto
+ 789 3471 lineto
+closepath 19 789 3471 1065 3609 Dp
+962 3903(Buffer)N
+1083(Header)X
+849 3851 MXY
+ 849 3851 lineto
+ 918 3851 lineto
+ 918 3920 lineto
+ 849 3920 lineto
+ 849 3851 lineto
+closepath 14 849 3851 918 3920 Dp
+1756 3194 MXY
+ 1756 3194 lineto
+ 1895 3194 lineto
+ 1895 3471 lineto
+ 1756 3471 lineto
+ 1756 3194 lineto
+closepath 14 1756 3194 1895 3471 Dp
+2171 3056 MXY
+ 2171 3056 lineto
+ 2309 3056 lineto
+ 2309 3333 lineto
+ 2171 3333 lineto
+ 2171 3056 lineto
+closepath 14 2171 3056 2309 3333 Dp
+1480 MX
+ 1480 3056 lineto
+ 1618 3056 lineto
+ 1618 3333 lineto
+ 1480 3333 lineto
+ 1480 3056 lineto
+closepath 14 1480 3056 1618 3333 Dp
+789 MX
+ 789 3056 lineto
+ 927 3056 lineto
+ 927 3333 lineto
+ 789 3333 lineto
+ 789 3056 lineto
+closepath 14 789 3056 927 3333 Dp
+2780 MY
+0 138 Dl
+138 0 Dl
+0 -138 Dl
+-138 0 Dl
+927 MX
+0 138 Dl
+138 0 Dl
+0 -138 Dl
+-138 0 Dl
+1065 MX
+0 138 Dl
+138 0 Dl
+0 -138 Dl
+-138 0 Dl
+1203 MX
+0 138 Dl
+139 0 Dl
+0 -138 Dl
+-139 0 Dl
+1342 MX
+0 138 Dl
+138 0 Dl
+0 -138 Dl
+-138 0 Dl
+1480 MX
+0 138 Dl
+138 0 Dl
+0 -138 Dl
+-138 0 Dl
+1618 MX
+0 138 Dl
+138 0 Dl
+0 -138 Dl
+-138 0 Dl
+1756 MX
+0 138 Dl
+139 0 Dl
+0 -138 Dl
+-139 0 Dl
+1895 MX
+0 138 Dl
+138 0 Dl
+0 -138 Dl
+-138 0 Dl
+2033 MX
+0 138 Dl
+138 0 Dl
+0 -138 Dl
+-138 0 Dl
+2171 MX
+0 138 Dl
+138 0 Dl
+0 -138 Dl
+-138 0 Dl
+2309 MX
+0 138 Dl
+139 0 Dl
+0 -138 Dl
+-139 0 Dl
+13 s
+1048 2720(In)N
+1173(Memory)X
+1580(Bucket)X
+1918(Array)X
+867 3584(B0)N
+1558(B5)X
+2223(B10)X
+1788 3722(O1/1)N
+5 s
+1515 3903(Primay)N
+1651(Buffer)X
+4 Ds
+1990 3851 MXY
+ 1990 3851 lineto
+ 2059 3851 lineto
+ 2059 3920 lineto
+ 1990 3920 lineto
+ 1990 3851 lineto
+closepath 3 1990 3851 2059 3920 Dp
+2102 3903(Over\257ow)N
+2270(Buffer)X
+3 Dt
+-1 Ds
+8 s
+720 4184(Figure)N
+922(4:)X
+1 f
+996(Three)X
+1164(primary)X
+1386(pages)X
+1551(\(B0,)X
+1683(B5,)X
+1794(B10\))X
+1942(are)X
+2039(accessed)X
+2281(directly)X
+720 4272(from)N
+862(the)X
+958(bucket)X
+1146(array.)X
+1326(The)X
+1443(one)X
+1553(over\257ow)X
+1798(page)X
+1935(\(O1/1\))X
+2122(is)X
+2182(linked)X
+2359(phy-)X
+720 4360(sically)N
+915(from)X
+1067(its)X
+1155(primary)X
+1384(page's)X
+1577(buffer)X
+1759(header)X
+1955(as)X
+2035(well)X
+2172(as)X
+2252(logically)X
+720 4448(from)N
+860(its)X
+937(predecessor)X
+1253(page)X
+1389(buffer)X
+1560(\(B5\).)X
+10 s
+10 f
+720 4624 -0.0930(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)AN
+3 f
+1191 4954(Table)N
+1406(Parameterization)X
+1 f
+892 5086(When)N
+1107(a)X
+1166(hash)X
+1336(table)X
+1515(is)X
+1590(created,)X
+1865(the)X
+1985(bucket)X
+2221(size,)X
+2388(\256ll)X
+720 5174(factor,)N
+953(initial)X
+1164(number)X
+1434(of)X
+1526(elements,)X
+1856(number)X
+2125(of)X
+2216(bytes)X
+2409(of)X
+720 5262(main)N
+919(memory)X
+1225(used)X
+1411(for)X
+1543(caching,)X
+1851(and)X
+2005(a)X
+2079(user-de\256ned)X
+720 5350(hash)N
+892(function)X
+1184(may)X
+1347(be)X
+1448(speci\256ed.)X
+1797(The)X
+1946(bucket)X
+2184(size)X
+2333(\(and)X
+720 5438(page)N
+906(size)X
+1064(for)X
+1191(over\257ow)X
+1509(pages\))X
+1752(defaults)X
+2039(to)X
+2134(256)X
+2287(bytes.)X
+720 5526(For)N
+858(tables)X
+1072(with)X
+1241(large)X
+1429(data)X
+1590(items,)X
+1810(it)X
+1881(may)X
+2046(be)X
+2149(preferable)X
+720 5614(to)N
+803(increase)X
+1088(the)X
+1207(page)X
+1380(size,)X
+1545(and,)X
+1701(conversely,)X
+2089(applications)X
+720 5702(storing)N
+1002(small)X
+1235(items)X
+1467(exclusively)X
+1891(in)X
+2012(memory)X
+2338(may)X
+2706 538(bene\256t)N
+2966(from)X
+3164(a)X
+3242(smaller)X
+3520(bucket)X
+3776(size.)X
+3983(A)X
+4082(bucket)X
+4337(size)X
+2706 626(smaller)N
+2962(than)X
+3120(64)X
+3220(bytes)X
+3409(is)X
+3482(not)X
+3604(recommended.)X
+2878 740(The)N
+3031(\256ll)X
+3147(factor)X
+3363(indicates)X
+3676(a)X
+3740(desired)X
+4000(density)X
+4258(within)X
+2706 828(the)N
+2833(hash)X
+3009(table.)X
+3234(It)X
+3312(is)X
+3394(an)X
+3499(approximation)X
+3995(of)X
+4091(the)X
+4217(number)X
+2706 916(of)N
+2815(keys)X
+3004(allowed)X
+3300(to)X
+3404(accumulate)X
+3811(in)X
+3914(any)X
+4071(one)X
+4228(bucket,)X
+2706 1004(determining)N
+3119(when)X
+3319(the)X
+3442(hash)X
+3614(table)X
+3795(grows.)X
+4056(Its)X
+4161(default)X
+4409(is)X
+2706 1092(eight.)N
+2953(If)X
+3054(the)X
+3199(user)X
+3380(knows)X
+3636(the)X
+3781(average)X
+4079(size)X
+4251(of)X
+4364(the)X
+2706 1180(key/data)N
+3008(pairs)X
+3194(being)X
+3402(stored)X
+3627(in)X
+3718(the)X
+3845(table,)X
+4050(near)X
+4218(optimal)X
+2706 1268(bucket)N
+2943(sizes)X
+3122(and)X
+3261(\256ll)X
+3372(factors)X
+3614(may)X
+3775(be)X
+3874(selected)X
+4155(by)X
+4257(apply-)X
+2706 1356(ing)N
+2828(the)X
+2946(equation:)X
+0 f
+8 s
+2706 1655(\(1\))N
+2994 -0.3938(\(\(average_pair_length)AX
+3830(+)X
+3906(4\))X
+4020(*)X
+3032 1743(ffactor\))N
+3374(>=)X
+3488(bsize)X
+1 f
+10 s
+2706 2042(For)N
+2859(highly)X
+3104(time)X
+3287(critical)X
+3551(applications,)X
+3999(experimenting)X
+2706 2130(with)N
+2919(different)X
+3266(bucket)X
+3550(sizes)X
+3776(and)X
+3962(\256ll)X
+4120(factors)X
+4409(is)X
+2706 2218(encouraged.)N
+2878 2332(Figures)N
+3144(5a,b,)X
+3326(and)X
+3468(c)X
+3530(illustrate)X
+3836(the)X
+3960(effects)X
+4200(of)X
+4292(vary-)X
+2706 2420(ing)N
+2841(page)X
+3026(sizes)X
+3215(and)X
+3363(\256ll)X
+3483(factors)X
+3734(for)X
+3860(the)X
+3990(same)X
+4187(data)X
+4353(set.)X
+2706 2508(The)N
+2864(data)X
+3031(set)X
+3152(consisted)X
+3482(of)X
+3581(24474)X
+3813(keys)X
+3992(taken)X
+4198(from)X
+4386(an)X
+2706 2596(online)N
+2931(dictionary.)X
+3301(The)X
+3451(data)X
+3609(value)X
+3807(for)X
+3925(each)X
+4097(key)X
+4237(was)X
+4386(an)X
+2706 2684(ASCII)N
+2938(string)X
+3143(for)X
+3260(an)X
+3359(integer)X
+3605(from)X
+3784(1)X
+3847(to)X
+3931(24474)X
+4153(inclusive.)X
+2706 2772(The)N
+2867(test)X
+3013(run)X
+3155(consisted)X
+3488(of)X
+3590(creating)X
+3884(a)X
+3955(new)X
+4124(hash)X
+4306(table)X
+2706 2860(\(where)N
+2966(the)X
+3100(ultimate)X
+3398(size)X
+3559(of)X
+3662(the)X
+3796(table)X
+3987(was)X
+4147(known)X
+4400(in)X
+2706 2948(advance\),)N
+3054(entering)X
+3354(each)X
+3539(key/data)X
+3848(pair)X
+4010(into)X
+4171(the)X
+4306(table)X
+2706 3036(and)N
+2849(then)X
+3014(retrieving)X
+3353(each)X
+3528(key/data)X
+3827(pair)X
+3979(from)X
+4162(the)X
+4286(table.)X
+2706 3124(Each)N
+2898(of)X
+2996(the)X
+3125(graphs)X
+3369(shows)X
+3599(the)X
+3727(timings)X
+3996(resulting)X
+4306(from)X
+2706 3212(varying)N
+2973(the)X
+3093(pagesize)X
+3392(from)X
+3570(128)X
+3712(bytes)X
+3903(to)X
+3986(1M)X
+4118(and)X
+4255(the)X
+4374(\256ll)X
+2706 3300(factor)N
+2929(from)X
+3120(1)X
+3195(to)X
+3292(128.)X
+3486(For)X
+3631(each)X
+3813(run,)X
+3974(the)X
+4106(buffer)X
+4337(size)X
+2706 3388(was)N
+2874(set)X
+3006(at)X
+3106(1M.)X
+3299(The)X
+3466(tests)X
+3650(were)X
+3849(all)X
+3971(run)X
+4120(on)X
+4242(an)X
+4360(HP)X
+2706 3476(9000/370)N
+3077(\(33.3)X
+3312(Mhz)X
+3527(MC68030\),)X
+3966(with)X
+4176(16M)X
+4395(of)X
+2706 3564(memory,)N
+3042(64K)X
+3228(physically)X
+3605(addressed)X
+3970(cache,)X
+4222(and)X
+4386(an)X
+2706 3652(HP7959S)N
+3055(disk)X
+3231(drive,)X
+3459(running)X
+3751(4.3BSD-Reno)X
+4244(single-)X
+2706 3740(user.)N
+2878 3854(Both)N
+3066(system)X
+3321(time)X
+3496(\(Figure)X
+3764(5a\))X
+3899(and)X
+4047(elapsed)X
+4320(time)X
+2706 3942(\(Figure)N
+2966(5b\))X
+3097(show)X
+3290(that)X
+3434(for)X
+3552(all)X
+3655(bucket)X
+3892(sizes,)X
+4091(the)X
+4212(greatest)X
+2706 4030(performance)N
+3137(gains)X
+3329(are)X
+3451(made)X
+3648(by)X
+3751(increasing)X
+4104(the)X
+4225(\256ll)X
+4336(fac-)X
+2706 4118(tor)N
+2822(until)X
+2995(equation)X
+3298(1)X
+3365(is)X
+3445(satis\256ed.)X
+3774(The)X
+3925(user)X
+4085(time)X
+4253(shown)X
+2706 4206(in)N
+2791(Figure)X
+3023(5c)X
+3122(gives)X
+3314(a)X
+3373(more)X
+3561(detailed)X
+3838(picture)X
+4083(of)X
+4172(how)X
+4332(per-)X
+2706 4294(formance)N
+3054(varies.)X
+3330(The)X
+3499(smaller)X
+3778(bucket)X
+4035(sizes)X
+4234(require)X
+2706 4382(fewer)N
+2921(keys)X
+3099(per)X
+3233(page)X
+3416(to)X
+3509(satisfy)X
+3749(equation)X
+4056(1)X
+4127(and)X
+4274(there-)X
+2706 4470(fore)N
+2860(incur)X
+3049(fewer)X
+3257(collisions.)X
+3607(However,)X
+3946(when)X
+4144(the)X
+4265(buffer)X
+2706 4558(pool)N
+2884(size)X
+3045(is)X
+3134(\256xed,)X
+3349(smaller)X
+3620(pages)X
+3838(imply)X
+4059(more)X
+4259(pages.)X
+2706 4646(An)N
+2830(increased)X
+3160(number)X
+3430(of)X
+3522(pages)X
+3730(means)X
+3960(more)X
+2 f
+4150(malloc\(3\))X
+1 f
+2706 4734(calls)N
+2879(and)X
+3021(more)X
+3212(overhead)X
+3533(in)X
+3621(the)X
+3745(hash)X
+3918(package's)X
+4265(buffer)X
+2706 4822(manager)N
+3003(to)X
+3085(manage)X
+3355(the)X
+3473(additional)X
+3813(pages.)X
+2878 4936(The)N
+3028(tradeoff)X
+3308(works)X
+3529(out)X
+3655(most)X
+3834(favorably)X
+4166(when)X
+4364(the)X
+2706 5024(page)N
+2886(size)X
+3039(is)X
+3120(256)X
+3268(and)X
+3412(the)X
+3538(\256ll)X
+3654(factor)X
+3870(is)X
+3950(8.)X
+4057(Similar)X
+4319(con-)X
+2706 5112(clusions)N
+3009(were)X
+3207(obtained)X
+3524(if)X
+3614(the)X
+3753(test)X
+3905(was)X
+4071(run)X
+4218(without)X
+2706 5200(knowing)N
+3007(the)X
+3126(\256nal)X
+3289(table)X
+3466(size)X
+3612(in)X
+3695(advance.)X
+4020(If)X
+4095(the)X
+4214(\256le)X
+4337(was)X
+2706 5288(closed)N
+2942(and)X
+3088(written)X
+3345(to)X
+3437(disk,)X
+3620(the)X
+3748(conclusions)X
+4156(were)X
+4343(still)X
+2706 5376(the)N
+2832(same.)X
+3065(However,)X
+3408(rereading)X
+3740(the)X
+3865(\256le)X
+3994(from)X
+4177(disk)X
+4337(was)X
+2706 5464(slightly)N
+2983(faster)X
+3199(if)X
+3285(a)X
+3358(larger)X
+3583(bucket)X
+3834(size)X
+3996(and)X
+4149(\256ll)X
+4274(factor)X
+2706 5552(were)N
+2898(used)X
+3079(\(1K)X
+3238(bucket)X
+3486(size)X
+3645(and)X
+3795(32)X
+3909(\256ll)X
+4031(factor\).)X
+4320(This)X
+2706 5640(follows)N
+2987(intuitively)X
+3356(from)X
+3553(the)X
+3691(improved)X
+4038(ef\256ciency)X
+4395(of)X
+3 f
+720 5960(USENIX)N
+9 f
+1042(-)X
+3 f
+1106(Winter)X
+1371('91)X
+9 f
+1498(-)X
+3 f
+1562(Dallas,)X
+1815(TX)X
+4424(7)X
+
+8 p
+%%Page: 8 8
+0(Courier)xf 0 f
+10 s 10 xH 0 xS 0 f
+3 f
+432 258(A)N
+510(New)X
+682(Hashing)X
+985(Package)X
+1290(for)X
+1413(UNIX)X
+3663(Seltzer)X
+3920(&)X
+4007(Yigit)X
+1 f
+432 538(performing)N
+830(1K)X
+965(reads)X
+1172(from)X
+1365(the)X
+1500(disk)X
+1670(rather)X
+1894(than)X
+2068(256)X
+432 626(byte)N
+609(reads.)X
+857(In)X
+962(general,)X
+1257(performance)X
+1702(for)X
+1834(disk)X
+2005(based)X
+432 714(tables)N
+639(is)X
+712(best)X
+861(when)X
+1055(the)X
+1173(page)X
+1345(size)X
+1490(is)X
+1563(approximately)X
+2046(1K.)X
+10 f
+432 802 -0.0930(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)AN
+619 2380 MXY
+-12 24 Dl
+24 0 Dl
+-12 -24 Dl
+629 2437 MXY
+-12 24 Dl
+24 0 Dl
+-12 -24 Dl
+648 2504 MXY
+-12 25 Dl
+24 0 Dl
+-12 -25 Dl
+686 2515 MXY
+-12 24 Dl
+24 0 Dl
+-12 -24 Dl
+762 2516 MXY
+-12 24 Dl
+25 0 Dl
+-13 -24 Dl
+916 2515 MXY
+-13 24 Dl
+25 0 Dl
+-12 -24 Dl
+1222 2516 MXY
+-12 24 Dl
+24 0 Dl
+-12 -24 Dl
+1834 2515 MXY
+-12 24 Dl
+24 0 Dl
+-12 -24 Dl
+1 Dt
+619 2392 MXY
+10 57 Dl
+19 67 Dl
+38 11 Dl
+76 1 Dl
+154 -1 Dl
+306 1 Dl
+612 -1 Dl
+8 s
+1 f
+1628 2522(128)N
+3 Dt
+607 2245 MXY
+24 Dc
+617 2375 MXY
+23 Dc
+635 2442 MXY
+24 Dc
+674 2525 MXY
+23 Dc
+750 2529 MXY
+24 Dc
+904 2527 MXY
+23 Dc
+1210 MX
+23 Dc
+1822 2528 MXY
+23 Dc
+20 Ds
+1 Dt
+619 2245 MXY
+10 130 Dl
+19 67 Dl
+38 83 Dl
+76 4 Dl
+154 -2 Dl
+306 0 Dl
+612 1 Dl
+678 2482(256)N
+-1 Ds
+3 Dt
+619 2127 MXY
+0 24 Dl
+0 -12 Dl
+12 0 Dl
+-24 0 Dl
+629 2191 MXY
+0 25 Dl
+0 -12 Dl
+12 0 Dl
+-24 0 Dl
+648 2334 MXY
+0 24 Dl
+0 -12 Dl
+12 0 Dl
+-24 0 Dl
+686 2409 MXY
+0 25 Dl
+0 -13 Dl
+12 0 Dl
+-24 0 Dl
+762 2516 MXY
+0 25 Dl
+0 -12 Dl
+13 0 Dl
+-25 0 Dl
+916 2516 MXY
+0 24 Dl
+0 -12 Dl
+12 0 Dl
+-25 0 Dl
+1222 2515 MXY
+0 24 Dl
+0 -12 Dl
+12 0 Dl
+-24 0 Dl
+1834 2515 MXY
+0 24 Dl
+0 -12 Dl
+12 0 Dl
+-24 0 Dl
+5 Dt
+619 2139 MXY
+10 65 Dl
+19 142 Dl
+38 75 Dl
+76 108 Dl
+154 -1 Dl
+306 -1 Dl
+612 0 Dl
+694 2401(512)N
+3 Dt
+631 2064 MXY
+-24 24 Dl
+12 -12 Dl
+-12 -12 Dl
+24 24 Dl
+641 2077 MXY
+-24 25 Dl
+12 -12 Dl
+-12 -13 Dl
+24 25 Dl
+660 2132 MXY
+-24 24 Dl
+12 -12 Dl
+-12 -12 Dl
+24 24 Dl
+698 2292 MXY
+-24 24 Dl
+12 -12 Dl
+-12 -12 Dl
+24 24 Dl
+775 2382 MXY
+-25 24 Dl
+12 -12 Dl
+-12 -12 Dl
+25 24 Dl
+928 2516 MXY
+-25 24 Dl
+13 -12 Dl
+-13 -12 Dl
+25 24 Dl
+1234 2516 MXY
+-24 25 Dl
+12 -12 Dl
+-12 -13 Dl
+24 25 Dl
+1846 2516 MXY
+-24 24 Dl
+12 -12 Dl
+-12 -12 Dl
+24 24 Dl
+16 Ds
+1 Dt
+619 2076 MXY
+10 14 Dl
+19 54 Dl
+38 160 Dl
+76 90 Dl
+154 134 Dl
+306 1 Dl
+612 -1 Dl
+694 2257(1024)N
+-1 Ds
+3 Dt
+619 1877 MXY
+12 -24 Dl
+-24 0 Dl
+12 24 Dl
+629 1855 MXY
+12 -24 Dl
+-24 0 Dl
+12 24 Dl
+648 1838 MXY
+12 -24 Dl
+-24 0 Dl
+12 24 Dl
+686 1860 MXY
+12 -25 Dl
+-24 0 Dl
+12 25 Dl
+762 1923 MXY
+13 -24 Dl
+-25 0 Dl
+12 24 Dl
+916 2087 MXY
+12 -24 Dl
+-25 0 Dl
+13 24 Dl
+1222 2256 MXY
+12 -24 Dl
+-24 0 Dl
+12 24 Dl
+1834 2541 MXY
+12 -25 Dl
+-24 0 Dl
+12 25 Dl
+619 1865 MXY
+10 -22 Dl
+19 -17 Dl
+38 21 Dl
+76 64 Dl
+154 164 Dl
+306 169 Dl
+612 285 Dl
+1645 2427(4096)N
+619 1243 MXY
+0 24 Dl
+0 -12 Dl
+12 0 Dl
+-24 0 Dl
+629 1196 MXY
+0 24 Dl
+0 -12 Dl
+12 0 Dl
+-24 0 Dl
+648 1146 MXY
+0 24 Dl
+0 -12 Dl
+12 0 Dl
+-24 0 Dl
+686 1174 MXY
+0 25 Dl
+0 -13 Dl
+12 0 Dl
+-24 0 Dl
+762 1249 MXY
+0 24 Dl
+0 -12 Dl
+13 0 Dl
+-25 0 Dl
+916 1371 MXY
+0 24 Dl
+0 -12 Dl
+12 0 Dl
+-25 0 Dl
+1222 1680 MXY
+0 24 Dl
+0 -12 Dl
+12 0 Dl
+-24 0 Dl
+1834 1999 MXY
+0 24 Dl
+0 -12 Dl
+12 0 Dl
+-24 0 Dl
+619 1255 MXY
+10 -47 Dl
+19 -50 Dl
+38 28 Dl
+76 75 Dl
+154 122 Dl
+306 309 Dl
+612 319 Dl
+1741 1934(8192)N
+5 Dt
+609 2531 MXY
+1225 0 Dl
+609 MX
+0 -1553 Dl
+2531 MY
+0 16 Dl
+4 Ds
+1 Dt
+2531 MY
+0 -1553 Dl
+593 2625(0)N
+-1 Ds
+5 Dt
+916 2531 MXY
+0 16 Dl
+4 Ds
+1 Dt
+2531 MY
+0 -1553 Dl
+884 2625(32)N
+-1 Ds
+5 Dt
+1222 2531 MXY
+0 16 Dl
+4 Ds
+1 Dt
+2531 MY
+0 -1553 Dl
+1190 2625(64)N
+-1 Ds
+5 Dt
+1528 2531 MXY
+0 16 Dl
+4 Ds
+1 Dt
+2531 MY
+0 -1553 Dl
+1496 2625(96)N
+-1 Ds
+5 Dt
+1834 2531 MXY
+0 16 Dl
+4 Ds
+1 Dt
+2531 MY
+0 -1553 Dl
+1786 2625(128)N
+-1 Ds
+5 Dt
+609 2531 MXY
+-16 0 Dl
+4 Ds
+1 Dt
+609 MX
+1225 0 Dl
+545 2558(0)N
+-1 Ds
+5 Dt
+609 2013 MXY
+-16 0 Dl
+4 Ds
+1 Dt
+609 MX
+1225 0 Dl
+481 2040(100)N
+-1 Ds
+5 Dt
+609 1496 MXY
+-16 0 Dl
+4 Ds
+1 Dt
+609 MX
+1225 0 Dl
+481 1523(200)N
+-1 Ds
+5 Dt
+609 978 MXY
+-16 0 Dl
+4 Ds
+1 Dt
+609 MX
+1225 0 Dl
+481 1005(300)N
+1088 2724(Fill)N
+1194(Factor)X
+422 1611(S)N
+426 1667(e)N
+426 1724(c)N
+424 1780(o)N
+424 1837(n)N
+424 1893(d)N
+428 1949(s)N
+3 Dt
+-1 Ds
+3 f
+432 2882(Figure)N
+636(5a:)X
+1 f
+744(System)X
+956(Time)X
+1113(for)X
+1209(dictionary)X
+1490(data)X
+1618(set)X
+1711(with)X
+1847(1M)X
+1958(of)X
+2033(buffer)X
+432 2970(space)N
+594(and)X
+707(varying)X
+923(bucket)X
+1114(sizes)X
+1259(and)X
+1372(\256ll)X
+1465(factors.)X
+1675(Each)X
+1823(line)X
+1940(is)X
+2004(labeled)X
+432 3058(with)N
+562(its)X
+639(bucket)X
+825(size.)X
+10 s
+10 f
+432 3234 -0.0930(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)AN
+8 s
+1 f
+428 4381(s)N
+424 4325(d)N
+424 4269(n)N
+424 4212(o)N
+426 4156(c)N
+426 4099(e)N
+422 4043(S)N
+1116 5156(Fill)N
+1222(Factor)X
+506 3437(3200)N
+4 Ds
+1 Dt
+666 3410 MXY
+1168 0 Dl
+-1 Ds
+5 Dt
+666 MX
+-16 0 Dl
+506 3825(2400)N
+4 Ds
+1 Dt
+666 3799 MXY
+1168 0 Dl
+-1 Ds
+5 Dt
+666 MX
+-16 0 Dl
+506 4214(1600)N
+4 Ds
+1 Dt
+666 4186 MXY
+1168 0 Dl
+-1 Ds
+5 Dt
+666 MX
+-16 0 Dl
+538 4602(800)N
+4 Ds
+1 Dt
+666 4575 MXY
+1168 0 Dl
+-1 Ds
+5 Dt
+666 MX
+-16 0 Dl
+602 4990(0)N
+4 Ds
+1 Dt
+666 4963 MXY
+1168 0 Dl
+-1 Ds
+5 Dt
+666 MX
+-16 0 Dl
+1786 5057(128)N
+4 Ds
+1 Dt
+1834 4963 MXY
+0 -1553 Dl
+-1 Ds
+5 Dt
+4963 MY
+0 16 Dl
+1510 5057(96)N
+4 Ds
+1 Dt
+1542 4963 MXY
+0 -1553 Dl
+-1 Ds
+5 Dt
+4963 MY
+0 16 Dl
+1218 5057(64)N
+4 Ds
+1 Dt
+1250 4963 MXY
+0 -1553 Dl
+-1 Ds
+5 Dt
+4963 MY
+0 16 Dl
+926 5057(32)N
+4 Ds
+1 Dt
+958 4963 MXY
+0 -1553 Dl
+-1 Ds
+5 Dt
+4963 MY
+0 16 Dl
+650 5057(0)N
+4 Ds
+1 Dt
+666 4963 MXY
+0 -1553 Dl
+-1 Ds
+5 Dt
+4963 MY
+0 16 Dl
+4963 MY
+0 -1553 Dl
+4963 MY
+1168 0 Dl
+1741 4752(8192)N
+3 Dt
+675 3732 MXY
+9 -172 Dl
+18 -118 Dl
+37 128 Dl
+73 -121 Dl
+146 623 Dl
+292 497 Dl
+584 245 Dl
+4802 MY
+0 24 Dl
+0 -12 Dl
+12 0 Dl
+-24 0 Dl
+1250 4557 MXY
+0 25 Dl
+0 -13 Dl
+12 0 Dl
+-24 0 Dl
+958 4060 MXY
+0 24 Dl
+0 -12 Dl
+12 0 Dl
+-24 0 Dl
+812 3437 MXY
+0 24 Dl
+0 -12 Dl
+12 0 Dl
+-24 0 Dl
+739 3558 MXY
+0 24 Dl
+0 -12 Dl
+12 0 Dl
+-24 0 Dl
+702 3430 MXY
+0 25 Dl
+0 -13 Dl
+13 0 Dl
+-25 0 Dl
+684 3548 MXY
+0 24 Dl
+0 -12 Dl
+12 0 Dl
+-24 0 Dl
+675 3720 MXY
+0 24 Dl
+0 -12 Dl
+12 0 Dl
+-24 0 Dl
+1637 4912(4096)N
+675 4307 MXY
+9 -58 Dl
+18 30 Dl
+37 89 Dl
+73 144 Dl
+146 235 Dl
+292 122 Dl
+584 89 Dl
+4970 MY
+12 -24 Dl
+-24 0 Dl
+12 24 Dl
+1250 4881 MXY
+12 -24 Dl
+-24 0 Dl
+12 24 Dl
+958 4759 MXY
+12 -24 Dl
+-24 0 Dl
+12 24 Dl
+812 4524 MXY
+12 -24 Dl
+-24 0 Dl
+12 24 Dl
+739 4380 MXY
+12 -24 Dl
+-24 0 Dl
+12 24 Dl
+702 4291 MXY
+13 -24 Dl
+-25 0 Dl
+12 24 Dl
+684 4261 MXY
+12 -24 Dl
+-24 0 Dl
+12 24 Dl
+675 4319 MXY
+12 -24 Dl
+-24 0 Dl
+12 24 Dl
+734 4662(1024)N
+16 Ds
+1 Dt
+675 4352 MXY
+9 60 Dl
+18 134 Dl
+37 266 Dl
+73 117 Dl
+146 30 Dl
+292 0 Dl
+584 -1 Dl
+-1 Ds
+3 Dt
+1846 4946 MXY
+-24 24 Dl
+12 -12 Dl
+-12 -12 Dl
+24 24 Dl
+1262 4946 MXY
+-24 25 Dl
+12 -12 Dl
+-12 -13 Dl
+24 25 Dl
+970 4947 MXY
+-24 24 Dl
+12 -12 Dl
+-12 -12 Dl
+24 24 Dl
+824 4917 MXY
+-24 24 Dl
+12 -12 Dl
+-12 -12 Dl
+24 24 Dl
+751 4800 MXY
+-24 24 Dl
+12 -12 Dl
+-12 -12 Dl
+24 24 Dl
+715 4534 MXY
+-25 25 Dl
+12 -13 Dl
+-12 -12 Dl
+25 25 Dl
+696 4400 MXY
+-24 24 Dl
+12 -12 Dl
+-12 -12 Dl
+24 24 Dl
+687 4339 MXY
+-24 25 Dl
+12 -12 Dl
+-12 -13 Dl
+24 25 Dl
+718 4792(512)N
+5 Dt
+675 4422 MXY
+9 137 Dl
+18 278 Dl
+37 105 Dl
+73 18 Dl
+146 -1 Dl
+292 0 Dl
+584 -1 Dl
+3 Dt
+4946 MY
+0 24 Dl
+0 -12 Dl
+12 0 Dl
+-24 0 Dl
+1250 4946 MXY
+0 25 Dl
+0 -12 Dl
+12 0 Dl
+-24 0 Dl
+958 4947 MXY
+0 24 Dl
+0 -12 Dl
+12 0 Dl
+-24 0 Dl
+812 4948 MXY
+0 24 Dl
+0 -12 Dl
+12 0 Dl
+-24 0 Dl
+739 4930 MXY
+0 24 Dl
+0 -12 Dl
+12 0 Dl
+-24 0 Dl
+702 4824 MXY
+0 25 Dl
+0 -12 Dl
+13 0 Dl
+-25 0 Dl
+684 4547 MXY
+0 24 Dl
+0 -12 Dl
+12 0 Dl
+-24 0 Dl
+675 4410 MXY
+0 25 Dl
+0 -13 Dl
+12 0 Dl
+-24 0 Dl
+750 4921(256)N
+20 Ds
+1 Dt
+675 4597 MXY
+9 246 Dl
+18 106 Dl
+37 10 Dl
+73 0 Dl
+146 0 Dl
+292 0 Dl
+584 -1 Dl
+-1 Ds
+3 Dt
+1822 MX
+23 Dc
+1238 4959 MXY
+23 Dc
+946 MX
+23 Dc
+800 MX
+23 Dc
+727 MX
+23 Dc
+691 4949 MXY
+23 Dc
+672 4843 MXY
+24 Dc
+663 4597 MXY
+24 Dc
+1395 4961(128)N
+1 Dt
+675 4855 MXY
+9 93 Dl
+18 10 Dl
+37 1 Dl
+73 0 Dl
+146 -1 Dl
+292 0 Dl
+584 0 Dl
+3 Dt
+4946 MY
+-12 24 Dl
+24 0 Dl
+-12 -24 Dl
+1250 MX
+-12 24 Dl
+24 0 Dl
+-12 -24 Dl
+958 MX
+-12 24 Dl
+24 0 Dl
+-12 -24 Dl
+812 MX
+-12 25 Dl
+24 0 Dl
+-12 -25 Dl
+739 4947 MXY
+-12 24 Dl
+24 0 Dl
+-12 -24 Dl
+702 4946 MXY
+-12 24 Dl
+25 0 Dl
+-13 -24 Dl
+684 4936 MXY
+-12 24 Dl
+24 0 Dl
+-12 -24 Dl
+675 4843 MXY
+-12 24 Dl
+24 0 Dl
+-12 -24 Dl
+3 Dt
+-1 Ds
+3 f
+432 5314(Figure)N
+634(5b:)X
+1 f
+744(Elapsed)X
+967(Time)X
+1123(for)X
+1218(dictionary)X
+1498(data)X
+1625(set)X
+1717(with)X
+1851(1M)X
+1960(of)X
+2033(buffer)X
+432 5402(space)N
+593(and)X
+705(varying)X
+920(bucket)X
+1110(sizes)X
+1254(and)X
+1366(\256ll)X
+1457(factors.)X
+1681(Each)X
+1827(line)X
+1942(is)X
+2004(labeled)X
+432 5490(with)N
+562(its)X
+639(bucket)X
+825(size.)X
+10 s
+2590 538(If)N
+2677(an)X
+2785(approximation)X
+3284(of)X
+3383(the)X
+3513(number)X
+3790(of)X
+3889(elements)X
+2418 626(ultimately)N
+2773(to)X
+2866(be)X
+2973(stored)X
+3200(in)X
+3293(the)X
+3422(hash)X
+3599(table)X
+3785(is)X
+3868(known)X
+4116(at)X
+2418 714(the)N
+2564(time)X
+2754(of)X
+2869(creation,)X
+3196(the)X
+3342(hash)X
+3536(package)X
+3847(takes)X
+4059(this)X
+2418 802(number)N
+2688(as)X
+2779(a)X
+2839(parameter)X
+3185(and)X
+3325(uses)X
+3487(it)X
+3555(to)X
+3641(hash)X
+3812(entries)X
+4050(into)X
+2418 890(the)N
+2541(full)X
+2677(sized)X
+2867(table)X
+3048(rather)X
+3261(than)X
+3424(growing)X
+3716(the)X
+3838(table)X
+4018(from)X
+2418 978(a)N
+2477(single)X
+2691(bucket.)X
+2968(If)X
+3044(this)X
+3181(number)X
+3448(is)X
+3523(not)X
+3647(known,)X
+3907(the)X
+4027(hash)X
+2418 1066(table)N
+2632(starts)X
+2859(with)X
+3059(a)X
+3153(single)X
+3402(bucket)X
+3674(and)X
+3848(gracefully)X
+2418 1154(expands)N
+2707(as)X
+2800(elements)X
+3111(are)X
+3236(added,)X
+3474(although)X
+3780(a)X
+3842(slight)X
+4044(per-)X
+2418 1242(formance)N
+2747(degradation)X
+3151(may)X
+3313(be)X
+3413(noticed.)X
+3713(Figure)X
+3946(6)X
+4010(illus-)X
+2418 1330(trates)N
+2625(the)X
+2756(difference)X
+3116(in)X
+3211(performance)X
+3651(between)X
+3952(storing)X
+2418 1418(keys)N
+2588(in)X
+2673(a)X
+2732(\256le)X
+2857(when)X
+3054(the)X
+3174(ultimate)X
+3458(size)X
+3605(is)X
+3680(known)X
+3920(\(the)X
+4067(left)X
+2418 1506(bars)N
+2581(in)X
+2672(each)X
+2849(set\),)X
+3014(compared)X
+3360(to)X
+3450(building)X
+3744(the)X
+3870(\256le)X
+4000(when)X
+2418 1594(the)N
+2550(ultimate)X
+2846(size)X
+3005(is)X
+3091(unknown)X
+3422(\(the)X
+3580(right)X
+3764(bars)X
+3931(in)X
+4026(each)X
+2418 1682(set\).)N
+2609(Once)X
+2814(the)X
+2947(\256ll)X
+3069(factor)X
+3291(is)X
+3378(suf\256ciently)X
+3772(high)X
+3948(for)X
+4076(the)X
+2418 1770(page)N
+2596(size)X
+2747(\(8\),)X
+2887(growing)X
+3180(the)X
+3304(table)X
+3486(dynamically)X
+3908(does)X
+4081(lit-)X
+2418 1858(tle)N
+2518(to)X
+2600(degrade)X
+2875(performance.)X
+10 f
+2418 1946 -0.0930(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)AN
+9 s
+1 f
+2413 3238(s)N
+2409 3173(d)N
+2409 3108(n)N
+2409 3043(o)N
+2411 2979(c)N
+2411 2914(e)N
+2407 2849(S)N
+3143 4129(Fill)N
+3261(Factor)X
+2448 2152(15)N
+4 Ds
+1 Dt
+2557 2122 MXY
+1473 0 Dl
+-1 Ds
+5 Dt
+2557 MX
+-19 0 Dl
+2448 2747(10)N
+4 Ds
+1 Dt
+2557 2717 MXY
+1473 0 Dl
+-1 Ds
+5 Dt
+2557 MX
+-19 0 Dl
+2484 3343(5)N
+4 Ds
+1 Dt
+2557 3313 MXY
+1473 0 Dl
+-1 Ds
+5 Dt
+2557 MX
+-19 0 Dl
+2484 3938(0)N
+4 Ds
+1 Dt
+2557 3908 MXY
+1473 0 Dl
+-1 Ds
+5 Dt
+2557 MX
+-19 0 Dl
+3976 4015(128)N
+4 Ds
+1 Dt
+4030 3908 MXY
+0 -1786 Dl
+-1 Ds
+5 Dt
+3908 MY
+0 19 Dl
+3626 4015(96)N
+4 Ds
+1 Dt
+3662 3908 MXY
+0 -1786 Dl
+-1 Ds
+5 Dt
+3908 MY
+0 19 Dl
+3258 4015(64)N
+4 Ds
+1 Dt
+3294 3908 MXY
+0 -1786 Dl
+-1 Ds
+5 Dt
+3908 MY
+0 19 Dl
+2889 4015(32)N
+4 Ds
+1 Dt
+2925 3908 MXY
+0 -1786 Dl
+-1 Ds
+5 Dt
+3908 MY
+0 19 Dl
+2539 4015(0)N
+4 Ds
+1 Dt
+2557 3908 MXY
+0 -1786 Dl
+-1 Ds
+5 Dt
+3908 MY
+0 19 Dl
+3908 MY
+0 -1786 Dl
+3908 MY
+1473 0 Dl
+4053 2378(8192)N
+3 Dt
+2569 2277 MXY
+11 0 Dl
+23 48 Dl
+46 -167 Dl
+92 35 Dl
+184 12 Dl
+369 143 Dl
+736 0 Dl
+2334 MY
+0 28 Dl
+0 -14 Dl
+14 0 Dl
+-28 0 Dl
+3294 2334 MXY
+0 28 Dl
+0 -14 Dl
+13 0 Dl
+-27 0 Dl
+2925 2192 MXY
+0 27 Dl
+0 -14 Dl
+14 0 Dl
+-28 0 Dl
+2741 2180 MXY
+0 27 Dl
+0 -14 Dl
+14 0 Dl
+-28 0 Dl
+2649 2144 MXY
+0 28 Dl
+0 -14 Dl
+14 0 Dl
+-28 0 Dl
+2603 2311 MXY
+0 27 Dl
+0 -13 Dl
+14 0 Dl
+-28 0 Dl
+2580 2263 MXY
+0 28 Dl
+0 -14 Dl
+14 0 Dl
+-28 0 Dl
+2569 2263 MXY
+0 28 Dl
+0 -14 Dl
+13 0 Dl
+-27 0 Dl
+4053 2591(4096)N
+2569 2348 MXY
+11 -11 Dl
+23 -96 Dl
+46 71 Dl
+92 72 Dl
+184 226 Dl
+369 48 Dl
+736 -60 Dl
+2612 MY
+14 -28 Dl
+-28 0 Dl
+14 28 Dl
+3294 2672 MXY
+13 -28 Dl
+-27 0 Dl
+14 28 Dl
+2925 2624 MXY
+14 -28 Dl
+-28 0 Dl
+14 28 Dl
+2741 2398 MXY
+14 -28 Dl
+-28 0 Dl
+14 28 Dl
+2649 2326 MXY
+14 -27 Dl
+-28 0 Dl
+14 27 Dl
+2603 2255 MXY
+14 -28 Dl
+-28 0 Dl
+14 28 Dl
+2580 2350 MXY
+14 -27 Dl
+-28 0 Dl
+14 27 Dl
+2569 2362 MXY
+13 -28 Dl
+-27 0 Dl
+14 28 Dl
+4053 2681(1024)N
+16 Ds
+1 Dt
+2569 2300 MXY
+11 48 Dl
+23 96 Dl
+46 95 Dl
+92 274 Dl
+184 202 Dl
+369 -155 Dl
+736 -190 Dl
+-1 Ds
+3 Dt
+4044 2656 MXY
+-28 28 Dl
+14 -14 Dl
+-14 -14 Dl
+28 28 Dl
+3307 2846 MXY
+-27 28 Dl
+14 -14 Dl
+-14 -14 Dl
+27 28 Dl
+2939 3001 MXY
+-28 28 Dl
+14 -14 Dl
+-14 -14 Dl
+28 28 Dl
+2755 2799 MXY
+-28 28 Dl
+14 -14 Dl
+-14 -14 Dl
+28 28 Dl
+2663 2525 MXY
+-28 28 Dl
+14 -14 Dl
+-14 -14 Dl
+28 28 Dl
+2617 2430 MXY
+-28 28 Dl
+14 -14 Dl
+-14 -14 Dl
+28 28 Dl
+2594 2334 MXY
+-28 28 Dl
+14 -14 Dl
+-14 -14 Dl
+28 28 Dl
+2582 2287 MXY
+-27 27 Dl
+14 -14 Dl
+-14 -13 Dl
+27 27 Dl
+4053 2851(512)N
+5 Dt
+2569 2372 MXY
+11 -24 Dl
+23 405 Dl
+46 83 Dl
+92 227 Dl
+184 -72 Dl
+369 -119 Dl
+736 -107 Dl
+3 Dt
+2751 MY
+0 28 Dl
+0 -14 Dl
+14 0 Dl
+-28 0 Dl
+3294 2858 MXY
+0 28 Dl
+0 -14 Dl
+13 0 Dl
+-27 0 Dl
+2925 2977 MXY
+0 28 Dl
+0 -14 Dl
+14 0 Dl
+-28 0 Dl
+2741 3049 MXY
+0 27 Dl
+0 -13 Dl
+14 0 Dl
+-28 0 Dl
+2649 2823 MXY
+0 27 Dl
+0 -14 Dl
+14 0 Dl
+-28 0 Dl
+2603 2739 MXY
+0 28 Dl
+0 -14 Dl
+14 0 Dl
+-28 0 Dl
+2580 2334 MXY
+0 28 Dl
+0 -14 Dl
+14 0 Dl
+-28 0 Dl
+2569 2358 MXY
+0 28 Dl
+0 -14 Dl
+13 0 Dl
+-27 0 Dl
+4053 2795(256)N
+20 Ds
+1 Dt
+2569 2456 MXY
+11 285 Dl
+23 95 Dl
+46 251 Dl
+92 -60 Dl
+184 -84 Dl
+369 -107 Dl
+736 -71 Dl
+-1 Ds
+3 Dt
+4016 MX
+27 Dc
+3280 2836 MXY
+27 Dc
+2912 2943 MXY
+27 Dc
+2728 3027 MXY
+27 Dc
+2635 3087 MXY
+28 Dc
+2589 2836 MXY
+28 Dc
+2566 2741 MXY
+27 Dc
+2554 2456 MXY
+28 Dc
+4053 2741(128)N
+1 Dt
+2569 2729 MXY
+11 203 Dl
+23 131 Dl
+46 -60 Dl
+92 -119 Dl
+184 -60 Dl
+369 -83 Dl
+736 -12 Dl
+3 Dt
+2716 MY
+-14 27 Dl
+28 0 Dl
+-14 -27 Dl
+3294 2727 MXY
+-14 28 Dl
+27 0 Dl
+-13 -28 Dl
+2925 2811 MXY
+-14 27 Dl
+28 0 Dl
+-14 -27 Dl
+2741 2870 MXY
+-14 28 Dl
+28 0 Dl
+-14 -28 Dl
+2649 2989 MXY
+-14 28 Dl
+28 0 Dl
+-14 -28 Dl
+2603 3049 MXY
+-14 27 Dl
+28 0 Dl
+-14 -27 Dl
+2580 2918 MXY
+-14 28 Dl
+28 0 Dl
+-14 -28 Dl
+2569 2716 MXY
+-14 27 Dl
+27 0 Dl
+-13 -27 Dl
+3 Dt
+-1 Ds
+3 f
+8 s
+2418 4286(Figure)N
+2628(5c:)X
+1 f
+2738(User)X
+2887(Time)X
+3051(for)X
+3154(dictionary)X
+3442(data)X
+3577(set)X
+3677(with)X
+3820(1M)X
+3938(of)X
+4019(buffer)X
+2418 4374(space)N
+2579(and)X
+2691(varying)X
+2906(bucket)X
+3096(sizes)X
+3240(and)X
+3352(\256ll)X
+3443(factors.)X
+3667(Each)X
+3813(line)X
+3928(is)X
+3990(labeled)X
+2418 4462(with)N
+2548(its)X
+2625(bucket)X
+2811(size.)X
+10 s
+10 f
+2418 4638 -0.0930(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)AN
+1 f
+2590 4840(Since)N
+2796(no)X
+2904(known)X
+3150(hash)X
+3325(function)X
+3620(performs)X
+3938(equally)X
+2418 4928(well)N
+2589(on)X
+2702(all)X
+2815(possible)X
+3110(data,)X
+3297(the)X
+3428(user)X
+3595(may)X
+3766(\256nd)X
+3923(that)X
+4076(the)X
+2418 5016(built-in)N
+2678(hash)X
+2849(function)X
+3140(does)X
+3311(poorly)X
+3544(on)X
+3648(a)X
+3708(particular)X
+4040(data)X
+2418 5104(set.)N
+2548(In)X
+2636(this)X
+2771(case,)X
+2950(a)X
+3006(hash)X
+3173(function,)X
+3480(taking)X
+3700(two)X
+3840(arguments)X
+2418 5192(\(a)N
+2507(pointer)X
+2760(to)X
+2848(a)X
+2910(byte)X
+3074(string)X
+3282(and)X
+3424(a)X
+3486(length\))X
+3739(and)X
+3880(returning)X
+2418 5280(an)N
+2517(unsigned)X
+2829(long)X
+2993(to)X
+3077(be)X
+3175(used)X
+3344(as)X
+3433(the)X
+3553(hash)X
+3722(value,)X
+3938(may)X
+4098(be)X
+2418 5368(speci\256ed)N
+2731(at)X
+2817(hash)X
+2992(table)X
+3176(creation)X
+3463(time.)X
+3673(When)X
+3893(an)X
+3996(exist-)X
+2418 5456(ing)N
+2570(hash)X
+2767(table)X
+2973(is)X
+3076(opened)X
+3358(and)X
+3524(a)X
+3609(hash)X
+3805(function)X
+4121(is)X
+2418 5544(speci\256ed,)N
+2752(the)X
+2879(hash)X
+3054(package)X
+3346(will)X
+3498(try)X
+3615(to)X
+3705(determine)X
+4054(that)X
+2418 5632(the)N
+2546(hash)X
+2723(function)X
+3020(supplied)X
+3321(is)X
+3404(the)X
+3532(one)X
+3678(with)X
+3850(which)X
+4076(the)X
+2418 5720(table)N
+2630(was)X
+2811(created.)X
+3139(There)X
+3382(are)X
+3536(a)X
+3627(variety)X
+3905(of)X
+4027(hash)X
+3 f
+432 5960(8)N
+2970(USENIX)X
+9 f
+3292(-)X
+3 f
+3356(Winter)X
+3621('91)X
+9 f
+3748(-)X
+3 f
+3812(Dallas,)X
+4065(TX)X
+
+9 p
+%%Page: 9 9
+0(Courier)xf 0 f
+10 s 10 xH 0 xS 0 f
+3 f
+720 258(Seltzer)N
+977(&)X
+1064(Yigit)X
+3278(A)X
+3356(New)X
+3528(Hashing)X
+3831(Package)X
+4136(for)X
+4259(UNIX)X
+1 f
+720 538(functions)N
+1065(provided)X
+1397(with)X
+1586(the)X
+1731(package.)X
+2082(The)X
+2253(default)X
+720 626(function)N
+1014(for)X
+1135(the)X
+1260(package)X
+1551(is)X
+1631(the)X
+1755(one)X
+1897(which)X
+2119(offered)X
+2378(the)X
+720 714(best)N
+875(performance)X
+1308(in)X
+1396(terms)X
+1600(of)X
+1693(cycles)X
+1920(executed)X
+2232(per)X
+2360(call)X
+720 802(\(it)N
+827(did)X
+965(not)X
+1103(produce)X
+1398(the)X
+1531(fewest)X
+1776(collisions)X
+2117(although)X
+2432(it)X
+720 890(was)N
+866(within)X
+1091(a)X
+1148(small)X
+1341(percentage)X
+1710(of)X
+1797(the)X
+1915(function)X
+2202(that)X
+2342(pro-)X
+720 978(duced)N
+947(the)X
+1080(fewest)X
+1324(collisions\).)X
+1731(Again,)X
+1981(in)X
+2077(time)X
+2253(critical)X
+720 1066(applications,)N
+1152(users)X
+1342(are)X
+1466(encouraged)X
+1862(to)X
+1949(experiment)X
+2334(with)X
+720 1154(a)N
+783(variety)X
+1032(of)X
+1125(hash)X
+1298(functions)X
+1622(to)X
+1710(achieve)X
+1982(optimal)X
+2252(perfor-)X
+720 1242(mance.)N
+10 f
+720 1330 -0.0930(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)AN
+3 f
+7 s
+1038 2925(Full)N
+1149(size)X
+1251(table)X
+1384(\(left\))X
+1547 2718(Fill)N
+1643(Factor)X
+2268 2662(64)N
+1964(32)X
+1674(16)X
+1384(8)X
+1093(4)X
+4 Ds
+1 Dt
+900 2280 MXY
+1548 0 Dl
+900 1879 MXY
+1548 0 Dl
+900 1506 MXY
+1548 0 Dl
+1563 2902 MXY
+111 0 Dl
+-1 Ds
+900 MX
+110 0 Dl
+1425 2828(System)N
+983(User)X
+1895 2778 MXY
+ 1895 2778 lineto
+ 1950 2778 lineto
+ 1950 2833 lineto
+ 1895 2833 lineto
+ 1895 2778 lineto
+closepath 21 1895 2778 1950 2833 Dp
+1342 MX
+ 1342 2778 lineto
+ 1397 2778 lineto
+ 1397 2833 lineto
+ 1342 2833 lineto
+ 1342 2778 lineto
+closepath 14 1342 2778 1397 2833 Dp
+900 MX
+ 900 2778 lineto
+ 955 2778 lineto
+ 955 2833 lineto
+ 900 2833 lineto
+ 900 2778 lineto
+closepath 3 900 2778 955 2833 Dp
+5 Dt
+2283 2211 MXY
+96 0 Dl
+1992 MX
+97 0 Dl
+1702 MX
+97 0 Dl
+1411 2252 MXY
+97 0 Dl
+4 Ds
+1 Dt
+2283 2211 MXY
+ 2283 2211 lineto
+ 2379 2211 lineto
+ 2379 2252 lineto
+ 2283 2252 lineto
+ 2283 2211 lineto
+closepath 14 2283 2211 2379 2252 Dp
+1992 MX
+ 1992 2211 lineto
+ 2089 2211 lineto
+ 2089 2252 lineto
+ 1992 2252 lineto
+ 1992 2211 lineto
+closepath 14 1992 2211 2089 2252 Dp
+1702 MX
+ 1702 2211 lineto
+ 1799 2211 lineto
+ 1799 2252 lineto
+ 1702 2252 lineto
+ 1702 2211 lineto
+closepath 14 1702 2211 1799 2252 Dp
+1411 2252 MXY
+ 1411 2252 lineto
+ 1508 2252 lineto
+ 1508 2294 lineto
+ 1411 2294 lineto
+ 1411 2252 lineto
+closepath 14 1411 2252 1508 2294 Dp
+2283 MX
+ 2283 2252 lineto
+ 2379 2252 lineto
+ 2379 2612 lineto
+ 2283 2612 lineto
+ 2283 2252 lineto
+closepath 3 2283 2252 2379 2612 Dp
+1992 MX
+ 1992 2252 lineto
+ 2089 2252 lineto
+ 2089 2612 lineto
+ 1992 2612 lineto
+ 1992 2252 lineto
+closepath 3 1992 2252 2089 2612 Dp
+1702 MX
+ 1702 2252 lineto
+ 1799 2252 lineto
+ 1799 2612 lineto
+ 1702 2612 lineto
+ 1702 2252 lineto
+closepath 3 1702 2252 1799 2612 Dp
+1411 2294 MXY
+ 1411 2294 lineto
+ 1508 2294 lineto
+ 1508 2612 lineto
+ 1411 2612 lineto
+ 1411 2294 lineto
+closepath 3 1411 2294 1508 2612 Dp
+-1 Ds
+2158 2238 MXY
+ 2158 2238 lineto
+ 2255 2238 lineto
+ 2255 2252 lineto
+ 2158 2252 lineto
+ 2158 2238 lineto
+closepath 21 2158 2238 2255 2252 Dp
+1868 MX
+ 1868 2238 lineto
+ 1965 2238 lineto
+ 1965 2280 lineto
+ 1868 2280 lineto
+ 1868 2238 lineto
+closepath 21 1868 2238 1965 2280 Dp
+1577 MX
+ 1577 2238 lineto
+ 1674 2238 lineto
+ 1674 2308 lineto
+ 1577 2308 lineto
+ 1577 2238 lineto
+closepath 21 1577 2238 1674 2308 Dp
+1287 2308 MXY
+ 1287 2308 lineto
+ 1287 2280 lineto
+ 1384 2280 lineto
+ 1384 2308 lineto
+ 1287 2308 lineto
+closepath 21 1287 2280 1384 2308 Dp
+2158 2280 MXY
+ 2158 2280 lineto
+ 2158 2252 lineto
+ 2255 2252 lineto
+ 2255 2280 lineto
+ 2158 2280 lineto
+closepath 14 2158 2252 2255 2280 Dp
+1868 2308 MXY
+ 1868 2308 lineto
+ 1868 2280 lineto
+ 1965 2280 lineto
+ 1965 2308 lineto
+ 1868 2308 lineto
+closepath 14 1868 2280 1965 2308 Dp
+1577 2335 MXY
+ 1577 2335 lineto
+ 1577 2308 lineto
+ 1674 2308 lineto
+ 1674 2335 lineto
+ 1577 2335 lineto
+closepath 14 1577 2308 1674 2335 Dp
+1287 2363 MXY
+ 1287 2363 lineto
+ 1287 2308 lineto
+ 1384 2308 lineto
+ 1384 2363 lineto
+ 1287 2363 lineto
+closepath 14 1287 2308 1384 2363 Dp
+2158 2280 MXY
+ 2158 2280 lineto
+ 2255 2280 lineto
+ 2255 2612 lineto
+ 2158 2612 lineto
+ 2158 2280 lineto
+closepath 3 2158 2280 2255 2612 Dp
+1868 2308 MXY
+ 1868 2308 lineto
+ 1965 2308 lineto
+ 1965 2612 lineto
+ 1868 2612 lineto
+ 1868 2308 lineto
+closepath 3 1868 2308 1965 2612 Dp
+1577 2335 MXY
+ 1577 2335 lineto
+ 1674 2335 lineto
+ 1674 2612 lineto
+ 1577 2612 lineto
+ 1577 2335 lineto
+closepath 3 1577 2335 1674 2612 Dp
+1287 2363 MXY
+ 1287 2363 lineto
+ 1384 2363 lineto
+ 1384 2612 lineto
+ 1287 2612 lineto
+ 1287 2363 lineto
+closepath 3 1287 2363 1384 2612 Dp
+4 Ds
+1121 2066 MXY
+ 1121 2066 lineto
+ 1218 2066 lineto
+ 1224 2080 lineto
+ 1127 2080 lineto
+ 1121 2066 lineto
+closepath 21 1121 2066 1224 2080 Dp
+2080 MY
+ 1121 2080 lineto
+ 1218 2080 lineto
+ 1218 2273 lineto
+ 1121 2273 lineto
+ 1121 2080 lineto
+closepath 14 1121 2080 1218 2273 Dp
+2273 MY
+ 1121 2273 lineto
+ 1218 2273 lineto
+ 1218 2612 lineto
+ 1121 2612 lineto
+ 1121 2273 lineto
+closepath 3 1121 2273 1218 2612 Dp
+-1 Ds
+997 1589 MXY
+ 997 1589 lineto
+ 1093 1589 lineto
+ 1093 1644 lineto
+ 997 1644 lineto
+ 997 1589 lineto
+closepath 21 997 1589 1093 1644 Dp
+1644 MY
+ 997 1644 lineto
+ 1093 1644 lineto
+ 1093 2280 lineto
+ 997 2280 lineto
+ 997 1644 lineto
+closepath 14 997 1644 1093 2280 Dp
+2280 MY
+ 997 2280 lineto
+ 1093 2280 lineto
+ 1093 2612 lineto
+ 997 2612 lineto
+ 997 2280 lineto
+closepath 3 997 2280 1093 2612 Dp
+10 s
+719 2093(s)N
+712 2037(d)N
+712 1982(n)N
+714 1927(o)N
+716 1872(c)N
+716 1816(e)N
+712 1761(S)N
+804 2286(10)N
+804 1899(20)N
+804 1540(30)N
+3 Dt
+900 1506 MXY
+0 1106 Dl
+1548 0 Dl
+7 s
+1978 2828(Elapsed)N
+1701 2925(Dynamically)N
+2018(grown)X
+2184(table)X
+2317(\(right\))X
+3 Dt
+-1 Ds
+8 s
+720 3180(Figure)N
+934(6:)X
+1 f
+1020(The)X
+1152(total)X
+1299(regions)X
+1520(indicate)X
+1755(the)X
+1865(difference)X
+2154(between)X
+2398(the)X
+720 3268(elapsed)N
+931(time)X
+1065(and)X
+1177(the)X
+1275(sum)X
+1402(of)X
+1475(the)X
+1573(system)X
+1771(and)X
+1883(user)X
+2008(time.)X
+2173(The)X
+2291(left)X
+2395(bar)X
+720 3356(of)N
+798(each)X
+939(set)X
+1035(depicts)X
+1241(the)X
+1344(timing)X
+1537(of)X
+1615(the)X
+1718(test)X
+1831(run)X
+1940(when)X
+2102(the)X
+2204(number)X
+2423(of)X
+720 3444(entries)N
+910(is)X
+973(known)X
+1167(in)X
+1237(advance.)X
+1496(The)X
+1614(right)X
+1754(bars)X
+1879(depict)X
+2054(the)X
+2151(timing)X
+2338(when)X
+720 3532(the)N
+814(\256le)X
+912(is)X
+971(grown)X
+1150(from)X
+1290(a)X
+1334(single)X
+1503(bucket.)X
+10 s
+10 f
+720 3708 -0.0930(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)AN
+1 f
+892 3910(Since)N
+1131(this)X
+1307(hashing)X
+1617(package)X
+1942(provides)X
+2279(buffer)X
+720 3998(management,)N
+1188(the)X
+1323(amount)X
+1600(of)X
+1704(space)X
+1920(allocated)X
+2247(for)X
+2378(the)X
+720 4086(buffer)N
+948(pool)X
+1121(may)X
+1290(be)X
+1397(speci\256ed)X
+1713(by)X
+1824(the)X
+1953(user.)X
+2157(Using)X
+2378(the)X
+720 4174(same)N
+910(data)X
+1069(set)X
+1183(and)X
+1324(test)X
+1459(procedure)X
+1805(as)X
+1896(used)X
+2067(to)X
+2153(derive)X
+2378(the)X
+720 4262(graphs)N
+962(in)X
+1052(Figures)X
+1320(5a-c,)X
+1507(Figure)X
+1744(7)X
+1812(shows)X
+2039(the)X
+2164(impact)X
+2409(of)X
+720 4350(varying)N
+997(the)X
+1126(size)X
+1282(of)X
+1380(the)X
+1509(buffer)X
+1737(pool.)X
+1950(The)X
+2106(bucket)X
+2351(size)X
+720 4438(was)N
+873(set)X
+989(to)X
+1078(256)X
+1225(bytes)X
+1421(and)X
+1564(the)X
+1689(\256ll)X
+1804(factor)X
+2019(was)X
+2171(set)X
+2287(to)X
+2376(16.)X
+720 4526(The)N
+869(buffer)X
+1090(pool)X
+1256(size)X
+1404(was)X
+1552(varied)X
+1776(from)X
+1955(0)X
+2018(\(the)X
+2166(minimum)X
+720 4614(number)N
+986(of)X
+1074(pages)X
+1277(required)X
+1565(to)X
+1647(be)X
+1743(buffered\))X
+2063(to)X
+2145(1M.)X
+2316(With)X
+720 4702(1M)N
+854(of)X
+944(buffer)X
+1164(space,)X
+1386(the)X
+1507(package)X
+1794(performed)X
+2151(no)X
+2253(I/O)X
+2382(for)X
+720 4790(this)N
+871(data)X
+1040(set.)X
+1204(As)X
+1328(Figure)X
+1572(7)X
+1647(illustrates,)X
+2013(increasing)X
+2378(the)X
+720 4878(buffer)N
+944(pool)X
+1113(size)X
+1265(can)X
+1404(have)X
+1583(a)X
+1646(dramatic)X
+1954(affect)X
+2165(on)X
+2271(result-)X
+720 4966(ing)N
+842(performance.)X
+2 f
+8 s
+1269 4941(7)N
+1 f
+16 s
+720 5353 MXY
+864 0 Dl
+2 f
+8 s
+760 5408(7)N
+1 f
+9 s
+826 5433(Some)N
+1024(allocators)X
+1338(are)X
+1460(extremely)X
+1782(inef\256cient)X
+2107(at)X
+2192(allocating)X
+720 5513(memory.)N
+1029(If)X
+1110(you)X
+1251(\256nd)X
+1396(that)X
+1536(applications)X
+1916(are)X
+2036(running)X
+2292(out)X
+2416(of)X
+720 5593(memory)N
+1005(before)X
+1234(you)X
+1386(think)X
+1578(they)X
+1746(should,)X
+2000(try)X
+2124(varying)X
+2388(the)X
+720 5673(pagesize)N
+986(to)X
+1060(get)X
+1166(better)X
+1348(utilization)X
+1658(from)X
+1816(the)X
+1922(memory)X
+2180(allocator.)X
+10 s
+2830 1975 MXY
+0 -28 Dl
+28 0 Dl
+0 28 Dl
+-28 0 Dl
+2853 2004 MXY
+0 -27 Dl
+28 0 Dl
+0 27 Dl
+-28 0 Dl
+2876 2016 MXY
+0 -27 Dl
+27 0 Dl
+0 27 Dl
+-27 0 Dl
+2922 1998 MXY
+0 -27 Dl
+27 0 Dl
+0 27 Dl
+-27 0 Dl
+2967 2025 MXY
+0 -28 Dl
+28 0 Dl
+0 28 Dl
+-28 0 Dl
+3013 2031 MXY
+0 -28 Dl
+28 0 Dl
+0 28 Dl
+-28 0 Dl
+3059 MX
+0 -28 Dl
+27 0 Dl
+0 28 Dl
+-27 0 Dl
+3196 2052 MXY
+0 -28 Dl
+27 0 Dl
+0 28 Dl
+-27 0 Dl
+3561 2102 MXY
+0 -28 Dl
+28 0 Dl
+0 28 Dl
+-28 0 Dl
+4292 2105 MXY
+0 -28 Dl
+27 0 Dl
+0 28 Dl
+-27 0 Dl
+4 Ds
+1 Dt
+2844 1961 MXY
+23 30 Dl
+23 12 Dl
+45 -18 Dl
+46 26 Dl
+46 6 Dl
+45 0 Dl
+137 21 Dl
+366 50 Dl
+730 3 Dl
+9 s
+4227 2158(User)N
+-1 Ds
+3 Dt
+2830 1211 MXY
+27 Dc
+2853 1261 MXY
+27 Dc
+2876 1267 MXY
+27 Dc
+2921 1341 MXY
+27 Dc
+2967 1385 MXY
+27 Dc
+3013 1450 MXY
+27 Dc
+3059 1497 MXY
+27 Dc
+3196 1686 MXY
+27 Dc
+3561 2109 MXY
+27 Dc
+4292 2295 MXY
+27 Dc
+20 Ds
+1 Dt
+2844 1211 MXY
+23 50 Dl
+23 6 Dl
+45 74 Dl
+46 44 Dl
+46 65 Dl
+45 47 Dl
+137 189 Dl
+366 423 Dl
+730 186 Dl
+4181 2270(System)N
+-1 Ds
+3 Dt
+2844 583 MXY
+0 28 Dl
+0 -14 Dl
+14 0 Dl
+-28 0 Dl
+2867 672 MXY
+0 27 Dl
+0 -14 Dl
+14 0 Dl
+-28 0 Dl
+2890 701 MXY
+0 28 Dl
+0 -14 Dl
+13 0 Dl
+-27 0 Dl
+2935 819 MXY
+0 28 Dl
+0 -14 Dl
+14 0 Dl
+-27 0 Dl
+2981 849 MXY
+0 28 Dl
+0 -14 Dl
+14 0 Dl
+-28 0 Dl
+3027 908 MXY
+0 27 Dl
+0 -13 Dl
+14 0 Dl
+-28 0 Dl
+3072 1026 MXY
+0 27 Dl
+0 -13 Dl
+14 0 Dl
+-27 0 Dl
+3209 1292 MXY
+0 27 Dl
+0 -14 Dl
+14 0 Dl
+-27 0 Dl
+3575 1823 MXY
+0 28 Dl
+0 -14 Dl
+14 0 Dl
+-28 0 Dl
+4305 2059 MXY
+0 28 Dl
+0 -14 Dl
+14 0 Dl
+-27 0 Dl
+5 Dt
+2844 597 MXY
+23 88 Dl
+23 30 Dl
+45 118 Dl
+46 30 Dl
+46 59 Dl
+45 118 Dl
+137 265 Dl
+366 532 Dl
+730 236 Dl
+4328 2103(Total)N
+2844 2310 MXY
+1461 0 Dl
+2844 MX
+0 -1772 Dl
+2310 MY
+0 18 Dl
+4 Ds
+1 Dt
+2310 MY
+0 -1772 Dl
+2826 2416(0)N
+-1 Ds
+5 Dt
+3209 2310 MXY
+0 18 Dl
+4 Ds
+1 Dt
+2310 MY
+0 -1772 Dl
+3155 2416(256)N
+-1 Ds
+5 Dt
+3575 2310 MXY
+0 18 Dl
+4 Ds
+1 Dt
+2310 MY
+0 -1772 Dl
+3521 2416(512)N
+-1 Ds
+5 Dt
+3940 2310 MXY
+0 18 Dl
+4 Ds
+1 Dt
+2310 MY
+0 -1772 Dl
+3886 2416(768)N
+-1 Ds
+5 Dt
+4305 2310 MXY
+0 18 Dl
+4 Ds
+1 Dt
+2310 MY
+0 -1772 Dl
+4233 2416(1024)N
+-1 Ds
+5 Dt
+2844 2310 MXY
+-18 0 Dl
+4 Ds
+1 Dt
+2844 MX
+1461 0 Dl
+2771 2340(0)N
+-1 Ds
+5 Dt
+2844 2014 MXY
+-18 0 Dl
+2844 1719 MXY
+-18 0 Dl
+4 Ds
+1 Dt
+2844 MX
+1461 0 Dl
+2735 1749(20)N
+-1 Ds
+5 Dt
+2844 1423 MXY
+-18 0 Dl
+2844 1128 MXY
+-18 0 Dl
+4 Ds
+1 Dt
+2844 MX
+1461 0 Dl
+2735 1158(40)N
+-1 Ds
+5 Dt
+2844 833 MXY
+-18 0 Dl
+2844 538 MXY
+-18 0 Dl
+4 Ds
+1 Dt
+2844 MX
+1461 0 Dl
+2735 568(60)N
+3239 2529(Buffer)N
+3445(Pool)X
+3595(Size)X
+3737(\(in)X
+3835(K\))X
+2695 1259(S)N
+2699 1324(e)N
+2699 1388(c)N
+2697 1452(o)N
+2697 1517(n)N
+2697 1581(d)N
+2701 1645(s)N
+3 Dt
+-1 Ds
+3 f
+8 s
+2706 2773(Figure)N
+2908(7:)X
+1 f
+2982(User)X
+3123(time)X
+3258(is)X
+3322(virtually)X
+3560(insensitive)X
+3854(to)X
+3924(the)X
+4022(amount)X
+4234(of)X
+4307(buffer)X
+2706 2861(pool)N
+2852(available,)X
+3130(however,)X
+3396(both)X
+3541(system)X
+3750(time)X
+3895(and)X
+4018(elapsed)X
+4240(time)X
+4385(are)X
+2706 2949(inversely)N
+2960(proportional)X
+3296(to)X
+3366(the)X
+3464(size)X
+3583(of)X
+3656(the)X
+3753(buffer)X
+3927(pool.)X
+4092(Even)X
+4242(for)X
+4335(large)X
+2706 3037(data)N
+2831(sets)X
+2946(where)X
+3120(one)X
+3230(expects)X
+3439(few)X
+3552(collisions,)X
+3832(specifying)X
+4116(a)X
+4162(large)X
+4307(buffer)X
+2706 3125(pool)N
+2836(dramatically)X
+3171(improves)X
+3425(performance.)X
+10 s
+10 f
+2706 3301 -0.0930(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)AN
+3 f
+3175 3543(Enhanced)N
+3536(Functionality)X
+1 f
+2878 3675(This)N
+3046(hashing)X
+3320(package)X
+3609(provides)X
+3910(a)X
+3971(set)X
+4085(of)X
+4177(compati-)X
+2706 3763(bility)N
+2895(routines)X
+3174(to)X
+3257(implement)X
+3620(the)X
+2 f
+3739(ndbm)X
+1 f
+3937(interface.)X
+4279(How-)X
+2706 3851(ever,)N
+2893(when)X
+3095(the)X
+3220(native)X
+3443(interface)X
+3752(is)X
+3832(used,)X
+4026(the)X
+4151(following)X
+2706 3939(additional)N
+3046(functionality)X
+3475(is)X
+3548(provided:)X
+10 f
+2798 4071(g)N
+1 f
+2946(Inserts)X
+3197(never)X
+3413(fail)X
+3556(because)X
+3847(too)X
+3985(many)X
+4199(keys)X
+2946 4159(hash)N
+3113(to)X
+3195(the)X
+3313(same)X
+3498(value.)X
+10 f
+2798 4247(g)N
+1 f
+2946(Inserts)X
+3187(never)X
+3393(fail)X
+3527(because)X
+3808(key)X
+3950(and/or)X
+4181(asso-)X
+2946 4335(ciated)N
+3158(data)X
+3312(is)X
+3385(too)X
+3507(large)X
+10 f
+2798 4423(g)N
+1 f
+2946(Hash)X
+3131(functions)X
+3449(may)X
+3607(be)X
+3703(user-speci\256ed.)X
+10 f
+2798 4511(g)N
+1 f
+2946(Multiple)X
+3268(pages)X
+3498(may)X
+3683(be)X
+3806(cached)X
+4077(in)X
+4186(main)X
+2946 4599(memory.)N
+2706 4731(It)N
+2801(also)X
+2976(provides)X
+3298(a)X
+3380(set)X
+3514(of)X
+3626(compatibility)X
+4097(routines)X
+4400(to)X
+2706 4819(implement)N
+3087(the)X
+2 f
+3224(hsearch)X
+1 f
+3516(interface.)X
+3876(Again,)X
+4130(the)X
+4266(native)X
+2706 4907(interface)N
+3008(offers)X
+3216(enhanced)X
+3540(functionality:)X
+10 f
+2798 5039(g)N
+1 f
+2946(Files)X
+3121(may)X
+3279(grow)X
+3464(beyond)X
+2 f
+3720(nelem)X
+1 f
+3932(elements.)X
+10 f
+2798 5127(g)N
+1 f
+2946(Multiple)X
+3247(hash)X
+3420(tables)X
+3632(may)X
+3795(be)X
+3896(accessed)X
+4203(con-)X
+2946 5215(currently.)N
+10 f
+2798 5303(g)N
+1 f
+2946(Hash)X
+3134(tables)X
+3344(may)X
+3505(be)X
+3604(stored)X
+3823(and)X
+3962(accessed)X
+4266(on)X
+2946 5391(disk.)N
+10 f
+2798 5479(g)N
+1 f
+2946(Hash)X
+3155(functions)X
+3497(may)X
+3679(be)X
+3799(user-speci\256ed)X
+4288(at)X
+2946 5567(runtime.)N
+3 f
+720 5960(USENIX)N
+9 f
+1042(-)X
+3 f
+1106(Winter)X
+1371('91)X
+9 f
+1498(-)X
+3 f
+1562(Dallas,)X
+1815(TX)X
+4424(9)X
+
+10 p
+%%Page: 10 10
+0(Courier)xf 0 f
+10 s 10 xH 0 xS 0 f
+3 f
+432 258(A)N
+510(New)X
+682(Hashing)X
+985(Package)X
+1290(for)X
+1413(UNIX)X
+3663(Seltzer)X
+3920(&)X
+4007(Yigit)X
+459 538(Relative)N
+760(Performance)X
+1227(of)X
+1314(the)X
+1441(New)X
+1613(Implementation)X
+1 f
+604 670(The)N
+761(performance)X
+1200(testing)X
+1445(of)X
+1544(the)X
+1674(new)X
+1840(package)X
+2135(is)X
+432 758(divided)N
+711(into)X
+874(two)X
+1033(test)X
+1183(suites.)X
+1424(The)X
+1588(\256rst)X
+1751(suite)X
+1941(of)X
+2046(tests)X
+432 846(requires)N
+727(that)X
+882(the)X
+1015(tables)X
+1237(be)X
+1348(read)X
+1522(from)X
+1713(and)X
+1864(written)X
+2126(to)X
+432 934(disk.)N
+640(In)X
+742(these)X
+942(tests,)X
+1139(the)X
+1272(basis)X
+1467(for)X
+1595(comparison)X
+2003(is)X
+2090(the)X
+432 1022(4.3BSD-Reno)N
+908(version)X
+1169(of)X
+2 f
+1260(ndbm)X
+1 f
+1438(.)X
+1502(Based)X
+1722(on)X
+1826(the)X
+1948(designs)X
+432 1110(of)N
+2 f
+521(sdbm)X
+1 f
+712(and)X
+2 f
+850(gdbm)X
+1 f
+1028(,)X
+1070(they)X
+1230(are)X
+1351(expected)X
+1659(to)X
+1743(perform)X
+2024(simi-)X
+432 1198(larly)N
+605(to)X
+2 f
+693(ndbm)X
+1 f
+871(,)X
+917(and)X
+1059(we)X
+1179(do)X
+1285(not)X
+1413(show)X
+1608(their)X
+1781(performance)X
+432 1286(numbers.)N
+800(The)X
+977(second)X
+1252(suite)X
+1454(contains)X
+1772(the)X
+1921(memory)X
+432 1374(resident)N
+712(test)X
+849(which)X
+1071(does)X
+1243(not)X
+1370(require)X
+1623(that)X
+1768(the)X
+1891(\256les)X
+2049(ever)X
+432 1462(be)N
+533(written)X
+784(to)X
+870(disk,)X
+1047(only)X
+1213(that)X
+1357(hash)X
+1528(tables)X
+1739(may)X
+1901(be)X
+2001(mani-)X
+432 1550(pulated)N
+692(in)X
+778(main)X
+961(memory.)X
+1291(In)X
+1381(this)X
+1519(test,)X
+1673(we)X
+1790(compare)X
+2090(the)X
+432 1638(performance)N
+859(to)X
+941(that)X
+1081(of)X
+1168(the)X
+2 f
+1286(hsearch)X
+1 f
+1560(routines.)X
+604 1752(For)N
+760(both)X
+947(suites,)X
+1194(two)X
+1358(different)X
+1679(databases)X
+2031(were)X
+432 1840(used.)N
+656(The)X
+818(\256rst)X
+979(is)X
+1069(the)X
+1204(dictionary)X
+1566(database)X
+1880(described)X
+432 1928(previously.)N
+836(The)X
+987(second)X
+1236(was)X
+1386(constructed)X
+1781(from)X
+1962(a)X
+2023(pass-)X
+432 2016(word)N
+647(\256le)X
+799(with)X
+990(approximately)X
+1502(300)X
+1671(accounts.)X
+2041(Two)X
+432 2104(records)N
+700(were)X
+887(constructed)X
+1287(for)X
+1411(each)X
+1589(account.)X
+1909(The)X
+2064(\256rst)X
+432 2192(used)N
+604(the)X
+727(logname)X
+1028(as)X
+1120(the)X
+1243(key)X
+1384(and)X
+1525(the)X
+1648(remainder)X
+1999(of)X
+2090(the)X
+432 2280(password)N
+768(entry)X
+965(for)X
+1091(the)X
+1221(data.)X
+1427(The)X
+1584(second)X
+1839(was)X
+1996(keyed)X
+432 2368(by)N
+541(uid)X
+672(and)X
+817(contained)X
+1157(the)X
+1283(entire)X
+1494(password)X
+1825(entry)X
+2018(as)X
+2113(its)X
+432 2456(data)N
+589(\256eld.)X
+794(The)X
+942(tests)X
+1107(were)X
+1287(all)X
+1389(run)X
+1518(on)X
+1620(the)X
+1740(HP)X
+1864(9000)X
+2046(with)X
+432 2544(the)N
+574(same)X
+783(con\256guration)X
+1254(previously)X
+1636(described.)X
+2027(Each)X
+432 2632(test)N
+576(was)X
+734(run)X
+874(\256ve)X
+1027(times)X
+1232(and)X
+1380(the)X
+1510(timing)X
+1750(results)X
+1991(of)X
+2090(the)X
+432 2720(runs)N
+602(were)X
+791(averaged.)X
+1154(The)X
+1311(variance)X
+1616(across)X
+1849(the)X
+1979(5)X
+2050(runs)X
+432 2808(was)N
+591(approximately)X
+1088(1%)X
+1229(of)X
+1330(the)X
+1462(average)X
+1746(yielding)X
+2041(95%)X
+432 2896(con\256dence)N
+800(intervals)X
+1096(of)X
+1183(approximately)X
+1666(2%.)X
+3 f
+1021 3050(Disk)N
+1196(Based)X
+1420(Tests)X
+1 f
+604 3182(In)N
+693(these)X
+880(tests,)X
+1064(we)X
+1180(use)X
+1308(a)X
+1365(bucket)X
+1600(size)X
+1746(of)X
+1834(1024)X
+2015(and)X
+2152(a)X
+432 3270(\256ll)N
+540(factor)X
+748(of)X
+835(32.)X
+3 f
+432 3384(create)N
+663(test)X
+1 f
+547 3498(The)N
+703(keys)X
+881(are)X
+1011(entered)X
+1279(into)X
+1433(the)X
+1561(hash)X
+1738(table,)X
+1944(and)X
+2090(the)X
+547 3586(\256le)N
+669(is)X
+742(\257ushed)X
+993(to)X
+1075(disk.)X
+3 f
+432 3700(read)N
+608(test)X
+1 f
+547 3814(A)N
+640(lookup)X
+897(is)X
+984(performed)X
+1353(for)X
+1481(each)X
+1663(key)X
+1813(in)X
+1909(the)X
+2041(hash)X
+547 3902(table.)N
+3 f
+432 4016(verify)N
+653(test)X
+1 f
+547 4130(A)N
+640(lookup)X
+897(is)X
+984(performed)X
+1353(for)X
+1481(each)X
+1663(key)X
+1813(in)X
+1909(the)X
+2041(hash)X
+547 4218(table,)N
+759(and)X
+911(the)X
+1045(data)X
+1215(returned)X
+1519(is)X
+1608(compared)X
+1961(against)X
+547 4306(that)N
+687(originally)X
+1018(stored)X
+1234(in)X
+1316(the)X
+1434(hash)X
+1601(table.)X
+3 f
+432 4420(sequential)N
+798(retrieve)X
+1 f
+547 4534(All)N
+674(keys)X
+846(are)X
+970(retrieved)X
+1281(in)X
+1367(sequential)X
+1716(order)X
+1910(from)X
+2090(the)X
+547 4622(hash)N
+724(table.)X
+950(The)X
+2 f
+1105(ndbm)X
+1 f
+1313(interface)X
+1625(allows)X
+1863(sequential)X
+547 4710(retrieval)N
+848(of)X
+948(the)X
+1079(keys)X
+1259(from)X
+1448(the)X
+1578(database,)X
+1907(but)X
+2041(does)X
+547 4798(not)N
+701(return)X
+945(the)X
+1094(data)X
+1279(associated)X
+1660(with)X
+1853(each)X
+2052(key.)X
+547 4886(Therefore,)N
+929(we)X
+1067(compare)X
+1388(the)X
+1530(performance)X
+1980(of)X
+2090(the)X
+547 4974(new)N
+703(package)X
+989(to)X
+1073(two)X
+1215(different)X
+1514(runs)X
+1674(of)X
+2 f
+1763(ndbm)X
+1 f
+1941(.)X
+2002(In)X
+2090(the)X
+547 5062(\256rst)N
+697(case,)X
+2 f
+882(ndbm)X
+1 f
+1086(returns)X
+1335(only)X
+1503(the)X
+1627(keys)X
+1800(while)X
+2003(in)X
+2090(the)X
+547 5150(second,)N
+2 f
+823(ndbm)X
+1 f
+1034(returns)X
+1290(both)X
+1465(the)X
+1596(keys)X
+1776(and)X
+1924(the)X
+2054(data)X
+547 5238(\(requiring)N
+894(a)X
+956(second)X
+1204(call)X
+1345(to)X
+1432(the)X
+1555(library\).)X
+1861(There)X
+2074(is)X
+2152(a)X
+547 5326(single)N
+764(run)X
+897(for)X
+1017(the)X
+1141(new)X
+1300(library)X
+1539(since)X
+1729(it)X
+1798(returns)X
+2046(both)X
+547 5414(the)N
+665(key)X
+801(and)X
+937(the)X
+1055(data.)X
+3 f
+3014 538(In-Memory)N
+3431(Test)X
+1 f
+2590 670(This)N
+2757(test)X
+2892(uses)X
+3054(a)X
+3114(bucket)X
+3352(size)X
+3501(of)X
+3592(256)X
+3736(and)X
+3876(a)X
+3936(\256ll)X
+4048(fac-)X
+2418 758(tor)N
+2527(of)X
+2614(8.)X
+3 f
+2418 872(create/read)N
+2827(test)X
+1 f
+2533 986(In)N
+2627(this)X
+2769(test,)X
+2927(a)X
+2989(hash)X
+3162(table)X
+3344(is)X
+3423(created)X
+3682(by)X
+3788(inserting)X
+4094(all)X
+2533 1074(the)N
+2660(key/data)X
+2961(pairs.)X
+3186(Then)X
+3380(a)X
+3445(keyed)X
+3666(retrieval)X
+3963(is)X
+4044(per-)X
+2533 1162(formed)N
+2801(for)X
+2931(each)X
+3115(pair,)X
+3295(and)X
+3446(the)X
+3579(hash)X
+3761(table)X
+3952(is)X
+4040(des-)X
+2533 1250(troyed.)N
+3 f
+2938 1404(Performance)N
+3405(Results)X
+1 f
+2590 1536(Figures)N
+2866(8a)X
+2978(and)X
+3130(8b)X
+3246(show)X
+3451(the)X
+3585(user)X
+3755(time,)X
+3952(system)X
+2418 1624(time,)N
+2608(and)X
+2752(elapsed)X
+3021(time)X
+3191(for)X
+3312(each)X
+3487(test)X
+3625(for)X
+3746(both)X
+3915(the)X
+4040(new)X
+2418 1712(implementation)N
+2951(and)X
+3098(the)X
+3227(old)X
+3360(implementation)X
+3893(\()X
+2 f
+3920(hsearch)X
+1 f
+2418 1800(or)N
+2 f
+2528(ndbm)X
+1 f
+2706(,)X
+2769(whichever)X
+3147(is)X
+3243(appropriate\))X
+3678(as)X
+3787(well)X
+3967(as)X
+4076(the)X
+2418 1888(improvement.)N
+2929(The)X
+3098(improvement)X
+3569(is)X
+3666(expressed)X
+4027(as)X
+4138(a)X
+2418 1976(percentage)N
+2787(of)X
+2874(the)X
+2992(old)X
+3114(running)X
+3383(time:)X
+0 f
+8 s
+2418 2275(%)N
+2494(=)X
+2570(100)X
+2722(*)X
+2798 -0.4219(\(old_time)AX
+3178(-)X
+3254 -0.4219(new_time\))AX
+3634(/)X
+3710(old_time)X
+1 f
+10 s
+2590 2600(In)N
+2700(nearly)X
+2944(all)X
+3067(cases,)X
+3299(the)X
+3439(new)X
+3615(routines)X
+3915(perform)X
+2418 2688(better)N
+2628(than)X
+2793(the)X
+2918(old)X
+3047(routines)X
+3332(\(both)X
+2 f
+3527(hsearch)X
+1 f
+3807(and)X
+2 f
+3949(ndbm)X
+1 f
+4127(\).)X
+2418 2776(Although)N
+2755(the)X
+3 f
+2888(create)X
+1 f
+3134(tests)X
+3311(exhibit)X
+3567(superior)X
+3864(user)X
+4032(time)X
+2418 2864(performance,)N
+2869(the)X
+2991(test)X
+3126(time)X
+3292(is)X
+3369(dominated)X
+3731(by)X
+3834(the)X
+3955(cost)X
+4107(of)X
+2418 2952(writing)N
+2677(the)X
+2803(actual)X
+3023(\256le)X
+3153(to)X
+3243(disk.)X
+3444(For)X
+3583(the)X
+3709(large)X
+3897(database)X
+2418 3040(\(the)N
+2564(dictionary\),)X
+2957(this)X
+3093(completely)X
+3470(overwhelmed)X
+3927(the)X
+4045(sys-)X
+2418 3128(tem)N
+2570(time.)X
+2783(However,)X
+3129(for)X
+3254(the)X
+3383(small)X
+3587(data)X
+3752(base,)X
+3946(we)X
+4071(see)X
+2418 3216(that)N
+2569(differences)X
+2958(in)X
+3051(both)X
+3224(user)X
+3389(and)X
+3536(system)X
+3788(time)X
+3960(contri-)X
+2418 3304(bute)N
+2576(to)X
+2658(the)X
+2776(superior)X
+3059(performance)X
+3486(of)X
+3573(the)X
+3691(new)X
+3845(package.)X
+2590 3418(The)N
+3 f
+2764(read)X
+1 f
+2920(,)X
+3 f
+2989(verify)X
+1 f
+3190(,)X
+3259(and)X
+3 f
+3424(sequential)X
+1 f
+3818(results)X
+4075(are)X
+2418 3506(deceptive)N
+2758(for)X
+2883(the)X
+3012(small)X
+3216(database)X
+3524(since)X
+3720(the)X
+3849(entire)X
+4063(test)X
+2418 3594(ran)N
+2551(in)X
+2643(under)X
+2856(a)X
+2922(second.)X
+3215(However,)X
+3560(on)X
+3669(the)X
+3796(larger)X
+4013(data-)X
+2418 3682(base)N
+2590(the)X
+3 f
+2716(read)X
+1 f
+2900(and)X
+3 f
+3044(verify)X
+1 f
+3273(tests)X
+3443(bene\256t)X
+3689(from)X
+3873(the)X
+3999(cach-)X
+2418 3770(ing)N
+2546(of)X
+2639(buckets)X
+2910(in)X
+2998(the)X
+3122(new)X
+3282(package)X
+3571(to)X
+3658(improve)X
+3950(perfor-)X
+2418 3858(mance)N
+2666(by)X
+2784(over)X
+2965(80%.)X
+3169(Since)X
+3384(the)X
+3519(\256rst)X
+3 f
+3680(sequential)X
+1 f
+4063(test)X
+2418 3946(does)N
+2598(not)X
+2733(require)X
+2 f
+2994(ndbm)X
+1 f
+3205(to)X
+3299(return)X
+3523(the)X
+3653(data)X
+3819(values,)X
+4076(the)X
+2418 4034(user)N
+2573(time)X
+2735(is)X
+2808(lower)X
+3011(than)X
+3169(for)X
+3283(the)X
+3401(new)X
+3555(package.)X
+3879(However)X
+2418 4122(when)N
+2613(we)X
+2728(require)X
+2977(both)X
+3139(packages)X
+3454(to)X
+3536(return)X
+3748(data,)X
+3922(the)X
+4040(new)X
+2418 4210(package)N
+2702(excels)X
+2923(in)X
+3005(all)X
+3105(three)X
+3286(timings.)X
+2590 4324(The)N
+2773(small)X
+3003(database)X
+3337(runs)X
+3532(so)X
+3660(quickly)X
+3957(in)X
+4076(the)X
+2418 4412(memory-resident)N
+3000(case)X
+3173(that)X
+3326(the)X
+3457(results)X
+3699(are)X
+3831(uninterest-)X
+2418 4500(ing.)N
+2589(However,)X
+2933(for)X
+3056(the)X
+3183(larger)X
+3400(database)X
+3706(the)X
+3833(new)X
+3995(pack-)X
+2418 4588(age)N
+2567(pays)X
+2751(a)X
+2824(small)X
+3033(penalty)X
+3305(in)X
+3403(system)X
+3661(time)X
+3839(because)X
+4130(it)X
+2418 4676(limits)N
+2636(its)X
+2748(main)X
+2944(memory)X
+3247(utilization)X
+3607(and)X
+3759(swaps)X
+3991(pages)X
+2418 4764(out)N
+2550(to)X
+2642(temporary)X
+3002(storage)X
+3264(in)X
+3356(the)X
+3484(\256le)X
+3616(system)X
+3868(while)X
+4076(the)X
+2 f
+2418 4852(hsearch)N
+1 f
+2698(package)X
+2988(requires)X
+3273(that)X
+3419(the)X
+3543(application)X
+3924(allocate)X
+2418 4940(enough)N
+2692(space)X
+2909(for)X
+3041(all)X
+3159(key/data)X
+3468(pair.)X
+3670(However,)X
+4022(even)X
+2418 5028(with)N
+2600(the)X
+2738(system)X
+3000(time)X
+3182(penalty,)X
+3477(the)X
+3614(resulting)X
+3933(elapsed)X
+2418 5116(time)N
+2580(improves)X
+2898(by)X
+2998(over)X
+3161(50%.)X
+3 f
+432 5960(10)N
+2970(USENIX)X
+9 f
+3292(-)X
+3 f
+3356(Winter)X
+3621('91)X
+9 f
+3748(-)X
+3 f
+3812(Dallas,)X
+4065(TX)X
+
+11 p
+%%Page: 11 11
+0(Courier)xf 0 f
+10 s 10 xH 0 xS 0 f
+3 f
+720 258(Seltzer)N
+977(&)X
+1064(Yigit)X
+3278(A)X
+3356(New)X
+3528(Hashing)X
+3831(Package)X
+4136(for)X
+4259(UNIX)X
+1 f
+10 f
+908 454(i)N
+927(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+2 f
+1379 546(hash)N
+1652(ndbm)X
+1950(%change)X
+1 f
+10 f
+908 550(i)N
+927(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+948 642(CREATE)N
+10 f
+908 646(i)N
+927(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+1125 738(user)N
+1424(6.4)X
+1671(12.2)X
+2073(48)X
+1157 826(sys)N
+1384(32.5)X
+1671(34.7)X
+2113(6)X
+3 f
+1006 914(elapsed)N
+10 f
+1310 922(c)N
+890(c)Y
+810(c)Y
+730(c)Y
+3 f
+1384 914(90.4)N
+10 f
+1581 922(c)N
+890(c)Y
+810(c)Y
+730(c)Y
+3 f
+1671 914(99.6)N
+10 f
+1883 922(c)N
+890(c)Y
+810(c)Y
+730(c)Y
+3 f
+2113 914(9)N
+1 f
+10 f
+908 910(i)N
+927(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+908 926(i)N
+927(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+948 1010(READ)N
+10 f
+908 1014(i)N
+927(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+1125 1106(user)N
+1424(3.4)X
+1711(6.1)X
+2073(44)X
+1157 1194(sys)N
+1424(1.2)X
+1671(15.3)X
+2073(92)X
+3 f
+1006 1282(elapsed)N
+10 f
+1310 1290(c)N
+1258(c)Y
+1178(c)Y
+1098(c)Y
+3 f
+1424 1282(4.0)N
+10 f
+1581 1290(c)N
+1258(c)Y
+1178(c)Y
+1098(c)Y
+3 f
+1671 1282(21.2)N
+10 f
+1883 1290(c)N
+1258(c)Y
+1178(c)Y
+1098(c)Y
+3 f
+2073 1282(81)N
+1 f
+10 f
+908 1278(i)N
+927(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+908 1294(i)N
+927(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+948 1378(VERIFY)N
+10 f
+908 1382(i)N
+927(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+1125 1474(user)N
+1424(3.5)X
+1711(6.3)X
+2073(44)X
+1157 1562(sys)N
+1424(1.2)X
+1671(15.3)X
+2073(92)X
+3 f
+1006 1650(elapsed)N
+10 f
+1310 1658(c)N
+1626(c)Y
+1546(c)Y
+1466(c)Y
+3 f
+1424 1650(4.0)N
+10 f
+1581 1658(c)N
+1626(c)Y
+1546(c)Y
+1466(c)Y
+3 f
+1671 1650(21.2)N
+10 f
+1883 1658(c)N
+1626(c)Y
+1546(c)Y
+1466(c)Y
+3 f
+2073 1650(81)N
+1 f
+10 f
+908 1646(i)N
+927(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+908 1662(i)N
+927(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+948 1746(SEQUENTIAL)N
+10 f
+908 1750(i)N
+927(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+1125 1842(user)N
+1424(2.7)X
+1711(1.9)X
+2046(-42)X
+1157 1930(sys)N
+1424(0.7)X
+1711(3.9)X
+2073(82)X
+3 f
+1006 2018(elapsed)N
+10 f
+1310 2026(c)N
+1994(c)Y
+1914(c)Y
+1834(c)Y
+3 f
+1424 2018(3.0)N
+10 f
+1581 2026(c)N
+1994(c)Y
+1914(c)Y
+1834(c)Y
+3 f
+1711 2018(5.0)N
+10 f
+1883 2026(c)N
+1994(c)Y
+1914(c)Y
+1834(c)Y
+3 f
+2073 2018(40)N
+1 f
+10 f
+908 2014(i)N
+927(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+908 2030(i)N
+927(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+948 2114(SEQUENTIAL)N
+1467(\(with)X
+1656(data)X
+1810(retrieval\))X
+10 f
+908 2118(i)N
+927(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+1125 2210(user)N
+1424(2.7)X
+1711(8.2)X
+2073(67)X
+1157 2298(sys)N
+1424(0.7)X
+1711(4.3)X
+2073(84)X
+3 f
+1006 2386(elapsed)N
+1424(3.0)X
+1671(12.0)X
+2073(75)X
+1 f
+10 f
+908 2390(i)N
+927(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+899 2394(c)N
+2378(c)Y
+2298(c)Y
+2218(c)Y
+2138(c)Y
+2058(c)Y
+1978(c)Y
+1898(c)Y
+1818(c)Y
+1738(c)Y
+1658(c)Y
+1578(c)Y
+1498(c)Y
+1418(c)Y
+1338(c)Y
+1258(c)Y
+1178(c)Y
+1098(c)Y
+1018(c)Y
+938(c)Y
+858(c)Y
+778(c)Y
+698(c)Y
+618(c)Y
+538(c)Y
+1310 2394(c)N
+2362(c)Y
+2282(c)Y
+2202(c)Y
+1581 2394(c)N
+2362(c)Y
+2282(c)Y
+2202(c)Y
+1883 2394(c)N
+2362(c)Y
+2282(c)Y
+2202(c)Y
+2278 2394(c)N
+2378(c)Y
+2298(c)Y
+2218(c)Y
+2138(c)Y
+2058(c)Y
+1978(c)Y
+1898(c)Y
+1818(c)Y
+1738(c)Y
+1658(c)Y
+1578(c)Y
+1498(c)Y
+1418(c)Y
+1338(c)Y
+1258(c)Y
+1178(c)Y
+1098(c)Y
+1018(c)Y
+938(c)Y
+858(c)Y
+778(c)Y
+698(c)Y
+618(c)Y
+538(c)Y
+905 2574(i)N
+930(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+2 f
+1318 2666(hash)N
+1585(hsearch)X
+1953(%change)X
+1 f
+10 f
+905 2670(i)N
+930(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+945 2762(CREATE/READ)N
+10 f
+905 2766(i)N
+930(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+1064 2858(user)N
+1343(6.6)X
+1642(17.2)X
+2096(62)X
+1096 2946(sys)N
+1343(1.1)X
+1682(0.3)X
+2029(-266)X
+3 f
+945 3034(elapsed)N
+1343(7.8)X
+1642(17.0)X
+2096(54)X
+1 f
+10 f
+905 3038(i)N
+930(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+896 3050(c)N
+2978(c)Y
+2898(c)Y
+2818(c)Y
+2738(c)Y
+2658(c)Y
+1249 3034(c)N
+3010(c)Y
+2930(c)Y
+2850(c)Y
+1520 3034(c)N
+3010(c)Y
+2930(c)Y
+2850(c)Y
+1886 3034(c)N
+3010(c)Y
+2930(c)Y
+2850(c)Y
+2281 3050(c)N
+2978(c)Y
+2898(c)Y
+2818(c)Y
+2738(c)Y
+2658(c)Y
+3 f
+720 3174(Figure)N
+967(8a:)X
+1 f
+1094(Timing)X
+1349(results)X
+1578(for)X
+1692(the)X
+1810(dictionary)X
+2155(database.)X
+10 f
+720 3262 -0.0930(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)AN
+3 f
+1407 3504(Conclusion)N
+1 f
+892 3636(This)N
+1063(paper)X
+1271(has)X
+1407(presented)X
+1744(the)X
+1871(design,)X
+2129(implemen-)X
+720 3724(tation)N
+928(and)X
+1070(performance)X
+1503(of)X
+1596(a)X
+1658(new)X
+1818(hashing)X
+2093(package)X
+2382(for)X
+720 3812(UNIX.)N
+993(The)X
+1150(new)X
+1316(package)X
+1612(provides)X
+1919(a)X
+1986(superset)X
+2280(of)X
+2378(the)X
+720 3900(functionality)N
+1159(of)X
+1255(existing)X
+1537(hashing)X
+1815(packages)X
+2139(and)X
+2284(incor-)X
+720 3988(porates)N
+975(additional)X
+1318(features)X
+1596(such)X
+1766(as)X
+1855(large)X
+2038(key)X
+2176(handling,)X
+720 4076(user)N
+876(de\256ned)X
+1134(hash)X
+1302(functions,)X
+1641(multiple)X
+1928(hash)X
+2096(tables,)X
+2324(vari-)X
+720 4164(able)N
+894(sized)X
+1099(pages,)X
+1342(and)X
+1498(linear)X
+1721(hashing.)X
+2050(In)X
+2156(nearly)X
+2396(all)X
+720 4252(cases,)N
+954(the)X
+1096(new)X
+1274(package)X
+1582(provides)X
+1902(improved)X
+2252(perfor-)X
+720 4340(mance)N
+974(on)X
+1098(the)X
+1240(order)X
+1454(of)X
+1565(50-80%)X
+1863(for)X
+2001(the)X
+2142(workloads)X
+720 4428(shown.)N
+990(Applications)X
+1420(such)X
+1588(as)X
+1676(the)X
+1794(loader,)X
+2035(compiler,)X
+2360(and)X
+720 4516(mail,)N
+921(which)X
+1156(currently)X
+1485(implement)X
+1866(their)X
+2051(own)X
+2227(hashing)X
+720 4604(routines,)N
+1032(should)X
+1279(be)X
+1389(modi\256ed)X
+1706(to)X
+1801(use)X
+1941(the)X
+2072(generic)X
+2342(rou-)X
+720 4692(tines.)N
+892 4806(This)N
+1087(hashing)X
+1389(package)X
+1705(is)X
+1810(one)X
+1978(access)X
+2236(method)X
+720 4894(which)N
+953(is)X
+1043(part)X
+1205(of)X
+1309(a)X
+1382(generic)X
+1656(database)X
+1970(access)X
+2212(package)X
+720 4982(being)N
+955(developed)X
+1342(at)X
+1457(the)X
+1612(University)X
+2007(of)X
+2131(California,)X
+720 5070(Berkeley.)N
+1089(It)X
+1177(will)X
+1340(include)X
+1614(a)X
+1688(btree)X
+1887(access)X
+2131(method)X
+2409(as)X
+720 5158(well)N
+916(as)X
+1041(\256xed)X
+1259(and)X
+1433(variable)X
+1750(length)X
+2007(record)X
+2270(access)X
+720 5246(methods)N
+1024(in)X
+1119(addition)X
+1414(to)X
+1509(the)X
+1640(hashed)X
+1896(support)X
+2168(presented)X
+720 5334(here.)N
+948(All)X
+1099(of)X
+1215(the)X
+1361(access)X
+1615(methods)X
+1934(are)X
+2081(based)X
+2312(on)X
+2440(a)X
+720 5422(key/data)N
+1037(pair)X
+1207(interface)X
+1533(and)X
+1693(appear)X
+1952(identical)X
+2272(to)X
+2378(the)X
+720 5510(application)N
+1121(layer,)X
+1347(allowing)X
+1671(application)X
+2071(implementa-)X
+720 5598(tions)N
+906(to)X
+999(be)X
+1106(largely)X
+1360(independent)X
+1783(of)X
+1881(the)X
+2010(database)X
+2318(type.)X
+720 5686(The)N
+873(package)X
+1165(is)X
+1246(expected)X
+1560(to)X
+1650(be)X
+1754(an)X
+1858(integral)X
+2131(part)X
+2284(of)X
+2378(the)X
+2706 538(4.4BSD)N
+3006(system,)X
+3293(with)X
+3479(various)X
+3759(standard)X
+4075(applications)X
+2706 626(such)N
+2879(as)X
+2972(more\(1\),)X
+3277(sort\(1\))X
+3517(and)X
+3659(vi\(1\))X
+3841(based)X
+4050(on)X
+4156(it.)X
+4266(While)X
+2706 714(the)N
+2833(current)X
+3089(design)X
+3326(does)X
+3501(not)X
+3631(support)X
+3899(multi-user)X
+4256(access)X
+2706 802(or)N
+2804(transactions,)X
+3238(they)X
+3407(could)X
+3616(be)X
+3723(incorporated)X
+4159(relatively)X
+2706 890(easily.)N
+10 f
+2894 938(i)N
+2913(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+2 f
+3365 1030(hash)N
+3638(ndbm)X
+3936(%change)X
+1 f
+10 f
+2894 1034(i)N
+2913(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+2934 1126(CREATE)N
+10 f
+2894 1130(i)N
+2913(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+3111 1222(user)N
+3390(0.2)X
+3677(0.4)X
+4079(50)X
+3143 1310(sys)N
+3390(0.1)X
+3677(1.0)X
+4079(90)X
+3 f
+2992 1398(elapsed)N
+10 f
+3296 1406(c)N
+1374(c)Y
+1294(c)Y
+1214(c)Y
+3 f
+3390 1398(0)N
+10 f
+3567 1406(c)N
+1374(c)Y
+1294(c)Y
+1214(c)Y
+3 f
+3677 1398(3.2)N
+10 f
+3869 1406(c)N
+1374(c)Y
+1294(c)Y
+1214(c)Y
+3 f
+4039 1398(100)N
+1 f
+10 f
+2894 1394(i)N
+2913(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+2894 1410(i)N
+2913(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+2934 1494(READ)N
+10 f
+2894 1498(i)N
+2913(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+3111 1590(user)N
+3390(0.1)X
+3677(0.1)X
+4119(0)X
+3143 1678(sys)N
+3390(0.1)X
+3677(0.4)X
+4079(75)X
+3 f
+2992 1766(elapsed)N
+10 f
+3296 1774(c)N
+1742(c)Y
+1662(c)Y
+1582(c)Y
+3 f
+3390 1766(0.0)N
+10 f
+3567 1774(c)N
+1742(c)Y
+1662(c)Y
+1582(c)Y
+3 f
+3677 1766(0.0)N
+10 f
+3869 1774(c)N
+1742(c)Y
+1662(c)Y
+1582(c)Y
+3 f
+4119 1766(0)N
+1 f
+10 f
+2894 1762(i)N
+2913(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+2894 1778(i)N
+2913(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+2934 1862(VERIFY)N
+10 f
+2894 1866(i)N
+2913(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+3111 1958(user)N
+3390(0.1)X
+3677(0.2)X
+4079(50)X
+3143 2046(sys)N
+3390(0.1)X
+3677(0.3)X
+4079(67)X
+3 f
+2992 2134(elapsed)N
+10 f
+3296 2142(c)N
+2110(c)Y
+2030(c)Y
+1950(c)Y
+3 f
+3390 2134(0.0)N
+10 f
+3567 2142(c)N
+2110(c)Y
+2030(c)Y
+1950(c)Y
+3 f
+3677 2134(0.0)N
+10 f
+3869 2142(c)N
+2110(c)Y
+2030(c)Y
+1950(c)Y
+3 f
+4119 2134(0)N
+1 f
+10 f
+2894 2130(i)N
+2913(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+2894 2146(i)N
+2913(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+2934 2230(SEQUENTIAL)N
+10 f
+2894 2234(i)N
+2913(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+3111 2326(user)N
+3390(0.1)X
+3677(0.0)X
+4012(-100)X
+3143 2414(sys)N
+3390(0.1)X
+3677(0.1)X
+4119(0)X
+3 f
+2992 2502(elapsed)N
+10 f
+3296 2510(c)N
+2478(c)Y
+2398(c)Y
+2318(c)Y
+3 f
+3390 2502(0.0)N
+10 f
+3567 2510(c)N
+2478(c)Y
+2398(c)Y
+2318(c)Y
+3 f
+3677 2502(0.0)N
+10 f
+3869 2510(c)N
+2478(c)Y
+2398(c)Y
+2318(c)Y
+3 f
+4119 2502(0)N
+1 f
+10 f
+2894 2498(i)N
+2913(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+2894 2514(i)N
+2913(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+2934 2598(SEQUENTIAL)N
+3453(\(with)X
+3642(data)X
+3796(retrieval\))X
+10 f
+2894 2602(i)N
+2913(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+3111 2694(user)N
+3390(0.1)X
+3677(0.1)X
+4119(0)X
+3143 2782(sys)N
+3390(0.1)X
+3677(0.1)X
+4119(0)X
+3 f
+2992 2870(elapsed)N
+3390(0.0)X
+3677(0.0)X
+4119(0)X
+1 f
+10 f
+2894 2874(i)N
+2913(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+2885 2878(c)N
+2862(c)Y
+2782(c)Y
+2702(c)Y
+2622(c)Y
+2542(c)Y
+2462(c)Y
+2382(c)Y
+2302(c)Y
+2222(c)Y
+2142(c)Y
+2062(c)Y
+1982(c)Y
+1902(c)Y
+1822(c)Y
+1742(c)Y
+1662(c)Y
+1582(c)Y
+1502(c)Y
+1422(c)Y
+1342(c)Y
+1262(c)Y
+1182(c)Y
+1102(c)Y
+1022(c)Y
+3296 2878(c)N
+2846(c)Y
+2766(c)Y
+2686(c)Y
+3567 2878(c)N
+2846(c)Y
+2766(c)Y
+2686(c)Y
+3869 2878(c)N
+2846(c)Y
+2766(c)Y
+2686(c)Y
+4264 2878(c)N
+2862(c)Y
+2782(c)Y
+2702(c)Y
+2622(c)Y
+2542(c)Y
+2462(c)Y
+2382(c)Y
+2302(c)Y
+2222(c)Y
+2142(c)Y
+2062(c)Y
+1982(c)Y
+1902(c)Y
+1822(c)Y
+1742(c)Y
+1662(c)Y
+1582(c)Y
+1502(c)Y
+1422(c)Y
+1342(c)Y
+1262(c)Y
+1182(c)Y
+1102(c)Y
+1022(c)Y
+2891 3058(i)N
+2916(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+2 f
+3304 3150(hash)N
+3571(hsearch)X
+3939(%change)X
+1 f
+10 f
+2891 3154(i)N
+2916(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+2931 3246(CREATE/READ)N
+10 f
+2891 3250(i)N
+2916(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+3050 3342(user)N
+3329(0.3)X
+3648(0.4)X
+4048(25)X
+3082 3430(sys)N
+3329(0.0)X
+3648(0.0)X
+4088(0)X
+3 f
+2931 3518(elapsed)N
+3329(0.0)X
+3648(0.0)X
+4088(0)X
+1 f
+10 f
+2891 3522(i)N
+2916(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+2882 3534(c)N
+3462(c)Y
+3382(c)Y
+3302(c)Y
+3222(c)Y
+3142(c)Y
+3235 3518(c)N
+3494(c)Y
+3414(c)Y
+3334(c)Y
+3506 3518(c)N
+3494(c)Y
+3414(c)Y
+3334(c)Y
+3872 3518(c)N
+3494(c)Y
+3414(c)Y
+3334(c)Y
+4267 3534(c)N
+3462(c)Y
+3382(c)Y
+3302(c)Y
+3222(c)Y
+3142(c)Y
+3 f
+2706 3658(Figure)N
+2953(8b:)X
+1 f
+3084(Timing)X
+3339(results)X
+3568(for)X
+3682(the)X
+3800(password)X
+4123(database.)X
+10 f
+2706 3746 -0.0930(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)AN
+3 f
+3396 3988(References)N
+1 f
+2706 4120([ATT79])N
+3058(AT&T,)X
+3358(DBM\(3X\),)X
+2 f
+3773(Unix)X
+3990(Programmer's)X
+2878 4208(Manual,)N
+3194(Seventh)X
+3491(Edition,)X
+3793(Volume)X
+4085(1)X
+1 f
+(,)S
+4192(January,)X
+2878 4296(1979.)N
+2706 4472([ATT85])N
+3027(AT&T,)X
+3296(HSEARCH\(BA_LIB\),)X
+2 f
+4053(Unix)X
+4239(System)X
+2878 4560(User's)N
+3112(Manual,)X
+3401(System)X
+3644(V.3)X
+1 f
+3753(,)X
+3793(pp.)X
+3913(506-508,)X
+4220(1985.)X
+2706 4736([BRE73])N
+3025(Brent,)X
+3253(Richard)X
+3537(P.,)X
+3651(``Reducing)X
+4041(the)X
+4168(Retrieval)X
+2878 4824(Time)N
+3071(of)X
+3162(Scatter)X
+3409(Storage)X
+3678(Techniques'',)X
+2 f
+4146(Commun-)X
+2878 4912(ications)N
+3175(of)X
+3281(the)X
+3422(ACM)X
+1 f
+3591(,)X
+3654(Volume)X
+3955(16,)X
+4098(No.)X
+4259(2,)X
+4362(pp.)X
+2878 5000(105-109,)N
+3185(February,)X
+3515(1973.)X
+2706 5176([BSD86])N
+3055(NDBM\(3\),)X
+2 f
+3469(4.3BSD)X
+3775(Unix)X
+3990(Programmer's)X
+2878 5264(Manual)N
+3155(Reference)X
+3505(Guide)X
+1 f
+3701(,)X
+3749(University)X
+4114(of)X
+4208(Califor-)X
+2878 5352(nia,)N
+3016(Berkeley,)X
+3346(1986.)X
+2706 5528([ENB88])N
+3025(Enbody,)X
+3319(R.)X
+3417(J.,)X
+3533(Du,)X
+3676(H.)X
+3779(C.,)X
+3897(``Dynamic)X
+4270(Hash-)X
+2878 5616(ing)N
+3034(Schemes'',)X
+2 f
+3427(ACM)X
+3630(Computing)X
+4019(Surveys)X
+1 f
+4269(,)X
+4322(Vol.)X
+2878 5704(20,)N
+2998(No.)X
+3136(2,)X
+3216(pp.)X
+3336(85-113,)X
+3603(June)X
+3770(1988.)X
+3 f
+720 5960(USENIX)N
+9 f
+1042(-)X
+3 f
+1106(Winter)X
+1371('91)X
+9 f
+1498(-)X
+3 f
+1562(Dallas,)X
+1815(TX)X
+4384(11)X
+
+12 p
+%%Page: 12 12
+0(Courier)xf 0 f
+10 s 10 xH 0 xS 0 f
+3 f
+432 258(A)N
+510(New)X
+682(Hashing)X
+985(Package)X
+1290(for)X
+1413(UNIX)X
+3663(Seltzer)X
+3920(&)X
+4007(Yigit)X
+1 f
+432 538([FAG79])N
+776(Ronald)X
+1057(Fagin,)X
+1308(Jurg)X
+1495(Nievergelt,)X
+1903(Nicholas)X
+604 626(Pippenger,)N
+1003(H.)X
+1135(Raymond)X
+1500(Strong,)X
+1787(``Extendible)X
+604 714(Hashing)N
+901(--)X
+985(A)X
+1073(Fast)X
+1236(Access)X
+1493(Method)X
+1771(for)X
+1894(Dynamic)X
+604 802(Files'',)N
+2 f
+855(ACM)X
+1046(Transactions)X
+1485(on)X
+1586(Database)X
+1914(Systems)X
+1 f
+2168(,)X
+604 890(Volume)N
+882(4,)X
+962(No.)X
+1100(3.,)X
+1200(September)X
+1563(1979,)X
+1763(pp)X
+1863(315-34)X
+432 1066([KNU68],)N
+802(Knuth,)X
+1064(D.E.,)X
+2 f
+1273(The)X
+1434(Art)X
+1577(of)X
+1680(Computer)X
+2041(Pro-)X
+604 1154(gramming)N
+971(Vol.)X
+1140(3:)X
+1245(Sorting)X
+1518(and)X
+1676(Searching)X
+1 f
+2001(,)X
+2058(sec-)X
+604 1242(tions)N
+779(6.3-6.4,)X
+1046(pp)X
+1146(481-550.)X
+432 1418([LAR78])N
+747(Larson,)X
+1011(Per-Ake,)X
+1319(``Dynamic)X
+1687(Hashing'',)X
+2 f
+2048(BIT)X
+1 f
+(,)S
+604 1506(Vol.)N
+764(18,)X
+884(1978,)X
+1084(pp.)X
+1204(184-201.)X
+432 1682([LAR88])N
+752(Larson,)X
+1021(Per-Ake,)X
+1335(``Dynamic)X
+1709(Hash)X
+1900(Tables'',)X
+2 f
+604 1770(Communications)N
+1183(of)X
+1281(the)X
+1415(ACM)X
+1 f
+1584(,)X
+1640(Volume)X
+1934(31,)X
+2070(No.)X
+604 1858(4.,)N
+704(April)X
+893(1988,)X
+1093(pp)X
+1193(446-457.)X
+432 2034([LIT80])N
+731(Witold,)X
+1013(Litwin,)X
+1286(``Linear)X
+1590(Hashing:)X
+1939(A)X
+2036(New)X
+604 2122(Tool)N
+786(for)X
+911(File)X
+1065(and)X
+1211(Table)X
+1424(Addressing'',)X
+2 f
+1893(Proceed-)X
+604 2210(ings)N
+761(of)X
+847(the)X
+969(6th)X
+1095(International)X
+1540(Conference)X
+1933(on)X
+2036(Very)X
+604 2298(Large)N
+815(Databases)X
+1 f
+1153(,)X
+1193(1980.)X
+432 2474([NEL90])N
+743(Nelson,)X
+1011(Philip)X
+1222(A.,)X
+2 f
+1341(Gdbm)X
+1558(1.4)X
+1679(source)X
+1913(distribu-)X
+604 2562(tion)N
+748(and)X
+888(README)X
+1 f
+1209(,)X
+1249(August)X
+1500(1990.)X
+432 2738([THOM90])N
+840(Ken)X
+1011(Thompson,)X
+1410(private)X
+1670(communication,)X
+604 2826(Nov.)N
+782(1990.)X
+432 3002([TOR87])N
+790(Torek,)X
+1066(C.,)X
+1222(``Re:)X
+1470(dbm.a)X
+1751(and)X
+1950(ndbm.a)X
+604 3090(archives'',)N
+2 f
+966(USENET)X
+1279(newsgroup)X
+1650(comp.unix)X
+1 f
+2002(1987.)X
+432 3266([TOR88])N
+760(Torek,)X
+1006(C.,)X
+1133(``Re:)X
+1351(questions)X
+1686(regarding)X
+2027(data-)X
+604 3354(bases)N
+826(created)X
+1106(with)X
+1295(dbm)X
+1484(and)X
+1647(ndbm)X
+1876(routines'')X
+2 f
+604 3442(USENET)N
+937(newsgroup)X
+1328(comp.unix.questions)X
+1 f
+1982(,)X
+2041(June)X
+604 3530(1988.)N
+432 3706([WAL84])N
+773(Wales,)X
+1018(R.,)X
+1135(``Discussion)X
+1564(of)X
+1655("dbm")X
+1887(data)X
+2045(base)X
+604 3794(system'',)N
+2 f
+973(USENET)X
+1339(newsgroup)X
+1762(unix.wizards)X
+1 f
+2168(,)X
+604 3882(January,)N
+894(1984.)X
+432 4058([YIG89])N
+751(Ozan)X
+963(S.)X
+1069(Yigit,)X
+1294(``How)X
+1545(to)X
+1648(Roll)X
+1826(Your)X
+2032(Own)X
+604 4146(Dbm/Ndbm'',)N
+2 f
+1087(unpublished)X
+1504(manuscript)X
+1 f
+(,)S
+1910(Toronto,)X
+604 4234(July,)N
+777(1989)X
+3 f
+432 5960(12)N
+2970(USENIX)X
+9 f
+3292(-)X
+3 f
+3356(Winter)X
+3621('91)X
+9 f
+3748(-)X
+3 f
+3812(Dallas,)X
+4065(TX)X
+
+13 p
+%%Page: 13 13
+0(Courier)xf 0 f
+10 s 10 xH 0 xS 0 f
+3 f
+720 258(Seltzer)N
+977(&)X
+1064(Yigit)X
+3278(A)X
+3356(New)X
+3528(Hashing)X
+3831(Package)X
+4136(for)X
+4259(UNIX)X
+1 f
+720 538(Margo)N
+960(I.)X
+1033(Seltzer)X
+1282(is)X
+1361(a)X
+1423(Ph.D.)X
+1631(student)X
+1887(in)X
+1974(the)X
+2097(Department)X
+720 626(of)N
+823(Electrical)X
+1167(Engineering)X
+1595(and)X
+1747(Computer)X
+2102(Sciences)X
+2418(at)X
+720 714(the)N
+850(University)X
+1220(of)X
+1318(California,)X
+1694(Berkeley.)X
+2055(Her)X
+2207(research)X
+720 802(interests)N
+1017(include)X
+1283(\256le)X
+1415(systems,)X
+1718(databases,)X
+2076(and)X
+2221(transac-)X
+720 890(tion)N
+896(processing)X
+1291(systems.)X
+1636(She)X
+1807(spent)X
+2027(several)X
+2306(years)X
+720 978(working)N
+1026(at)X
+1123(startup)X
+1380(companies)X
+1762(designing)X
+2112(and)X
+2267(imple-)X
+720 1066(menting)N
+1048(\256le)X
+1216(systems)X
+1535(and)X
+1716(transaction)X
+2133(processing)X
+720 1154(software)N
+1026(and)X
+1170(designing)X
+1509(microprocessors.)X
+2103(Ms.)X
+2253(Seltzer)X
+720 1242(received)N
+1057(her)X
+1223(AB)X
+1397(in)X
+1522(Applied)X
+1843(Mathematics)X
+2320(from)X
+720 1330 0.1953(Harvard/Radcliffe)AN
+1325(College)X
+1594(in)X
+1676(1983.)X
+720 1444(In)N
+810(her)X
+936(spare)X
+1129(time,)X
+1313(Margo)X
+1549(can)X
+1683(usually)X
+1936(be)X
+2034(found)X
+2243(prepar-)X
+720 1532(ing)N
+868(massive)X
+1171(quantities)X
+1527(of)X
+1639(food)X
+1831(for)X
+1970(hungry)X
+2242(hoards,)X
+720 1620(studying)N
+1022(Japanese,)X
+1355(or)X
+1449(playing)X
+1716(soccer)X
+1948(with)X
+2116(an)X
+2218(exciting)X
+720 1708(Bay)N
+912(Area)X
+1132(Women's)X
+1507(Soccer)X
+1788(team,)X
+2026(the)X
+2186(Berkeley)X
+720 1796(Bruisers.)N
+720 1910(Ozan)N
+915(\()X
+3 f
+942(Oz)X
+1 f
+1040(\))X
+1092(Yigit)X
+1281(is)X
+1358(currently)X
+1672(a)X
+1732(software)X
+2033(engineer)X
+2334(with)X
+720 1998(the)N
+886(Communications)X
+1499(Research)X
+1861(and)X
+2044(Development)X
+720 2086(group,)N
+948(Computing)X
+1328(Services,)X
+1641(York)X
+1826(University.)X
+2224(His)X
+2355(for-)X
+720 2174(mative)N
+967(years)X
+1166(were)X
+1352(also)X
+1510(spent)X
+1708(at)X
+1795(York,)X
+2009(where)X
+2234(he)X
+2338(held)X
+720 2262(system)N
+985(programmer)X
+1425(and)X
+1583(administrator)X
+2052(positions)X
+2382(for)X
+720 2350(various)N
+995(mixtures)X
+1314(of)X
+1420(of)X
+1526(UNIX)X
+1765(systems)X
+2056(starting)X
+2334(with)X
+720 2438(Berkeley)N
+1031(4.1)X
+1151(in)X
+1233(1982,)X
+1433(while)X
+1631(at)X
+1709(the)X
+1827(same)X
+2012(time)X
+2174(obtaining)X
+720 2526(a)N
+776(degree)X
+1011(in)X
+1093(Computer)X
+1433(Science.)X
+720 2640(In)N
+813(his)X
+931(copious)X
+1205(free)X
+1356(time,)X
+1543(Oz)X
+1662(enjoys)X
+1896(working)X
+2188(on)X
+2293(what-)X
+720 2728(ever)N
+890(software)X
+1197(looks)X
+1400(interesting,)X
+1788(which)X
+2014(often)X
+2209(includes)X
+720 2816(language)N
+1044(interpreters,)X
+1464(preprocessors,)X
+1960(and)X
+2110(lately,)X
+2342(pro-)X
+720 2904(gram)N
+905(generators)X
+1260(and)X
+1396(expert)X
+1617(systems.)X
+720 3018(Oz)N
+836(has)X
+964(authored)X
+1266(several)X
+1515(public-domain)X
+2003(software)X
+2301(tools,)X
+720 3106(including)N
+1069(an)X
+1191(nroff-like)X
+1545(text)X
+1711(formatter)X
+2 f
+2056(proff)X
+1 f
+2257(that)X
+2423(is)X
+720 3194(apparently)N
+1083(still)X
+1226(used)X
+1397(in)X
+1483(some)X
+1676(basement)X
+2002(PCs.)X
+2173(His)X
+2307(latest)X
+720 3282(obsessions)N
+1143(include)X
+1460(the)X
+1639(incredible)X
+2040(programming)X
+720 3370(language)N
+1030(Scheme,)X
+1324(and)X
+1460(Chinese)X
+1738(Brush)X
+1949(painting.)X
+3 f
+720 5960(USENIX)N
+9 f
+1042(-)X
+3 f
+1106(Winter)X
+1371('91)X
+9 f
+1498(-)X
+3 f
+1562(Dallas,)X
+1815(TX)X
+4384(13)X
+
+14 p
+%%Page: 14 14
+0(Courier)xf 0 f
+10 s 10 xH 0 xS 0 f
+3 f
+432 5960(14)N
+2970(USENIX)X
+9 f
+3292(-)X
+3 f
+3356(Winter)X
+3621('91)X
+9 f
+3748(-)X
+3 f
+3812(Dallas,)X
+4065(TX)X
+
+14 p
+%%Trailer
+xt
+
+xs
diff --git a/lib/libc/db/docs/libtp.usenix.ps b/lib/libc/db/docs/libtp.usenix.ps
new file mode 100644
index 000000000000..b7e441a5755e
--- /dev/null
+++ b/lib/libc/db/docs/libtp.usenix.ps
@@ -0,0 +1,12340 @@
+%!PS-Adobe-1.0
+%%Creator: utopia:margo (& Seltzer,608-13E,8072,)
+%%Title: stdin (ditroff)
+%%CreationDate: Thu Dec 12 15:32:11 1991
+%%EndComments
+% @(#)psdit.pro 1.3 4/15/88
+% lib/psdit.pro -- prolog for psdit (ditroff) files
+% Copyright (c) 1984, 1985 Adobe Systems Incorporated. All Rights Reserved.
+% last edit: shore Sat Nov 23 20:28:03 1985
+% RCSID: $FreeBSD$
+
+% Changed by Edward Wang (edward@ucbarpa.berkeley.edu) to handle graphics,
+% 17 Feb, 87.
+
+/$DITroff 140 dict def $DITroff begin
+/fontnum 1 def /fontsize 10 def /fontheight 10 def /fontslant 0 def
+/xi{0 72 11 mul translate 72 resolution div dup neg scale 0 0 moveto
+ /fontnum 1 def /fontsize 10 def /fontheight 10 def /fontslant 0 def F
+ /pagesave save def}def
+/PB{save /psv exch def currentpoint translate
+ resolution 72 div dup neg scale 0 0 moveto}def
+/PE{psv restore}def
+/arctoobig 90 def /arctoosmall .05 def
+/m1 matrix def /m2 matrix def /m3 matrix def /oldmat matrix def
+/tan{dup sin exch cos div}def
+/point{resolution 72 div mul}def
+/dround {transform round exch round exch itransform}def
+/xT{/devname exch def}def
+/xr{/mh exch def /my exch def /resolution exch def}def
+/xp{}def
+/xs{docsave restore end}def
+/xt{}def
+/xf{/fontname exch def /slotno exch def fontnames slotno get fontname eq not
+ {fonts slotno fontname findfont put fontnames slotno fontname put}if}def
+/xH{/fontheight exch def F}def
+/xS{/fontslant exch def F}def
+/s{/fontsize exch def /fontheight fontsize def F}def
+/f{/fontnum exch def F}def
+/F{fontheight 0 le{/fontheight fontsize def}if
+ fonts fontnum get fontsize point 0 0 fontheight point neg 0 0 m1 astore
+ fontslant 0 ne{1 0 fontslant tan 1 0 0 m2 astore m3 concatmatrix}if
+ makefont setfont .04 fontsize point mul 0 dround pop setlinewidth}def
+/X{exch currentpoint exch pop moveto show}def
+/N{3 1 roll moveto show}def
+/Y{exch currentpoint pop exch moveto show}def
+/S{show}def
+/ditpush{}def/ditpop{}def
+/AX{3 -1 roll currentpoint exch pop moveto 0 exch ashow}def
+/AN{4 2 roll moveto 0 exch ashow}def
+/AY{3 -1 roll currentpoint pop exch moveto 0 exch ashow}def
+/AS{0 exch ashow}def
+/MX{currentpoint exch pop moveto}def
+/MY{currentpoint pop exch moveto}def
+/MXY{moveto}def
+/cb{pop}def % action on unknown char -- nothing for now
+/n{}def/w{}def
+/p{pop showpage pagesave restore /pagesave save def}def
+/Dt{/Dlinewidth exch def}def 1 Dt
+/Ds{/Ddash exch def}def -1 Ds
+/Di{/Dstipple exch def}def 1 Di
+/Dsetlinewidth{2 Dlinewidth mul setlinewidth}def
+/Dsetdash{Ddash 4 eq{[8 12]}{Ddash 16 eq{[32 36]}
+ {Ddash 20 eq{[32 12 8 12]}{[]}ifelse}ifelse}ifelse 0 setdash}def
+/Dstroke{gsave Dsetlinewidth Dsetdash 1 setlinecap stroke grestore
+ currentpoint newpath moveto}def
+/Dl{rlineto Dstroke}def
+/arcellipse{/diamv exch def /diamh exch def oldmat currentmatrix pop
+ currentpoint translate 1 diamv diamh div scale /rad diamh 2 div def
+ currentpoint exch rad add exch rad -180 180 arc oldmat setmatrix}def
+/Dc{dup arcellipse Dstroke}def
+/De{arcellipse Dstroke}def
+/Da{/endv exch def /endh exch def /centerv exch def /centerh exch def
+ /cradius centerv centerv mul centerh centerh mul add sqrt def
+ /eradius endv endv mul endh endh mul add sqrt def
+ /endang endv endh atan def
+ /startang centerv neg centerh neg atan def
+ /sweep startang endang sub dup 0 lt{360 add}if def
+ sweep arctoobig gt
+ {/midang startang sweep 2 div sub def /midrad cradius eradius add 2 div def
+ /midh midang cos midrad mul def /midv midang sin midrad mul def
+ midh neg midv neg endh endv centerh centerv midh midv Da
+ Da}
+ {sweep arctoosmall ge
+ {/controldelt 1 sweep 2 div cos sub 3 sweep 2 div sin mul div 4 mul def
+ centerv neg controldelt mul centerh controldelt mul
+ endv neg controldelt mul centerh add endh add
+ endh controldelt mul centerv add endv add
+ centerh endh add centerv endv add rcurveto Dstroke}
+ {centerh endh add centerv endv add rlineto Dstroke}
+ ifelse}
+ ifelse}def
+/Dpatterns[
+[%cf[widthbits]
+[8<0000000000000010>]
+[8<0411040040114000>]
+[8<0204081020408001>]
+[8<0000103810000000>]
+[8<6699996666999966>]
+[8<0000800100001008>]
+[8<81c36666c3810000>]
+[8<0f0e0c0800000000>]
+[8<0000000000000010>]
+[8<0411040040114000>]
+[8<0204081020408001>]
+[8<0000001038100000>]
+[8<6699996666999966>]
+[8<0000800100001008>]
+[8<81c36666c3810000>]
+[8<0f0e0c0800000000>]
+[8<0042660000246600>]
+[8<0000990000990000>]
+[8<0804020180402010>]
+[8<2418814242811824>]
+[8<6699996666999966>]
+[8<8000000008000000>]
+[8<00001c3e363e1c00>]
+[8<0000000000000000>]
+[32<00000040000000c00000004000000040000000e0000000000000000000000000>]
+[32<00000000000060000000900000002000000040000000f0000000000000000000>]
+[32<000000000000000000e0000000100000006000000010000000e0000000000000>]
+[32<00000000000000002000000060000000a0000000f00000002000000000000000>]
+[32<0000000e0000000000000000000000000000000f000000080000000e00000001>]
+[32<0000090000000600000000000000000000000000000007000000080000000e00>]
+[32<00010000000200000004000000040000000000000000000000000000000f0000>]
+[32<0900000006000000090000000600000000000000000000000000000006000000>]]
+[%ug
+[8<0000020000000000>]
+[8<0000020000002000>]
+[8<0004020000002000>]
+[8<0004020000402000>]
+[8<0004060000402000>]
+[8<0004060000406000>]
+[8<0006060000406000>]
+[8<0006060000606000>]
+[8<00060e0000606000>]
+[8<00060e000060e000>]
+[8<00070e000060e000>]
+[8<00070e000070e000>]
+[8<00070e020070e000>]
+[8<00070e020070e020>]
+[8<04070e020070e020>]
+[8<04070e024070e020>]
+[8<04070e064070e020>]
+[8<04070e064070e060>]
+[8<06070e064070e060>]
+[8<06070e066070e060>]
+[8<06070f066070e060>]
+[8<06070f066070f060>]
+[8<060f0f066070f060>]
+[8<060f0f0660f0f060>]
+[8<060f0f0760f0f060>]
+[8<060f0f0760f0f070>]
+[8<0e0f0f0760f0f070>]
+[8<0e0f0f07e0f0f070>]
+[8<0e0f0f0fe0f0f070>]
+[8<0e0f0f0fe0f0f0f0>]
+[8<0f0f0f0fe0f0f0f0>]
+[8<0f0f0f0ff0f0f0f0>]
+[8<1f0f0f0ff0f0f0f0>]
+[8<1f0f0f0ff1f0f0f0>]
+[8<1f0f0f8ff1f0f0f0>]
+[8<1f0f0f8ff1f0f0f8>]
+[8<9f0f0f8ff1f0f0f8>]
+[8<9f0f0f8ff9f0f0f8>]
+[8<9f0f0f9ff9f0f0f8>]
+[8<9f0f0f9ff9f0f0f9>]
+[8<9f8f0f9ff9f0f0f9>]
+[8<9f8f0f9ff9f8f0f9>]
+[8<9f8f1f9ff9f8f0f9>]
+[8<9f8f1f9ff9f8f1f9>]
+[8<bf8f1f9ff9f8f1f9>]
+[8<bf8f1f9ffbf8f1f9>]
+[8<bf8f1fdffbf8f1f9>]
+[8<bf8f1fdffbf8f1fd>]
+[8<ff8f1fdffbf8f1fd>]
+[8<ff8f1fdffff8f1fd>]
+[8<ff8f1ffffff8f1fd>]
+[8<ff8f1ffffff8f1ff>]
+[8<ff9f1ffffff8f1ff>]
+[8<ff9f1ffffff9f1ff>]
+[8<ff9f9ffffff9f1ff>]
+[8<ff9f9ffffff9f9ff>]
+[8<ffbf9ffffff9f9ff>]
+[8<ffbf9ffffffbf9ff>]
+[8<ffbfdffffffbf9ff>]
+[8<ffbfdffffffbfdff>]
+[8<ffffdffffffbfdff>]
+[8<ffffdffffffffdff>]
+[8<fffffffffffffdff>]
+[8<ffffffffffffffff>]]
+[%mg
+[8<8000000000000000>]
+[8<0822080080228000>]
+[8<0204081020408001>]
+[8<40e0400000000000>]
+[8<66999966>]
+[8<8001000010080000>]
+[8<81c36666c3810000>]
+[8<f0e0c08000000000>]
+[16<07c00f801f003e007c00f800f001e003c007800f001f003e007c00f801f003e0>]
+[16<1f000f8007c003e001f000f8007c003e001f800fc007e003f001f8007c003e00>]
+[8<c3c300000000c3c3>]
+[16<0040008001000200040008001000200040008000000100020004000800100020>]
+[16<0040002000100008000400020001800040002000100008000400020001000080>]
+[16<1fc03fe07df0f8f8f07de03fc01f800fc01fe03ff07df8f87df03fe01fc00f80>]
+[8<80>]
+[8<8040201000000000>]
+[8<84cc000048cc0000>]
+[8<9900009900000000>]
+[8<08040201804020100800020180002010>]
+[8<2418814242811824>]
+[8<66999966>]
+[8<8000000008000000>]
+[8<70f8d8f870000000>]
+[8<0814224180402010>]
+[8<aa00440a11a04400>]
+[8<018245aa45820100>]
+[8<221c224180808041>]
+[8<88000000>]
+[8<0855800080550800>]
+[8<2844004482440044>]
+[8<0810204080412214>]
+[8<00>]]]def
+/Dfill{
+ transform /maxy exch def /maxx exch def
+ transform /miny exch def /minx exch def
+ minx maxx gt{/minx maxx /maxx minx def def}if
+ miny maxy gt{/miny maxy /maxy miny def def}if
+ Dpatterns Dstipple 1 sub get exch 1 sub get
+ aload pop /stip exch def /stipw exch def /stiph 128 def
+ /imatrix[stipw 0 0 stiph 0 0]def
+ /tmatrix[stipw 0 0 stiph 0 0]def
+ /minx minx cvi stiph idiv stiph mul def
+ /miny miny cvi stipw idiv stipw mul def
+ gsave eoclip 0 setgray
+ miny stiph maxy{
+ tmatrix exch 5 exch put
+ minx stipw maxx{
+ tmatrix exch 4 exch put tmatrix setmatrix
+ stipw stiph true imatrix {stip} imagemask
+ }for
+ }for
+ grestore
+}def
+/Dp{Dfill Dstroke}def
+/DP{Dfill currentpoint newpath moveto}def
+end
+
+/ditstart{$DITroff begin
+ /nfonts 60 def % NFONTS makedev/ditroff dependent!
+ /fonts[nfonts{0}repeat]def
+ /fontnames[nfonts{()}repeat]def
+/docsave save def
+}def
+
+% character outcalls
+/oc{
+ /pswid exch def /cc exch def /name exch def
+ /ditwid pswid fontsize mul resolution mul 72000 div def
+ /ditsiz fontsize resolution mul 72 div def
+ ocprocs name known{ocprocs name get exec}{name cb}ifelse
+}def
+/fractm [.65 0 0 .6 0 0] def
+/fraction{
+ /fden exch def /fnum exch def gsave /cf currentfont def
+ cf fractm makefont setfont 0 .3 dm 2 copy neg rmoveto
+ fnum show rmoveto currentfont cf setfont(\244)show setfont fden show
+ grestore ditwid 0 rmoveto
+}def
+/oce{grestore ditwid 0 rmoveto}def
+/dm{ditsiz mul}def
+/ocprocs 50 dict def ocprocs begin
+(14){(1)(4)fraction}def
+(12){(1)(2)fraction}def
+(34){(3)(4)fraction}def
+(13){(1)(3)fraction}def
+(23){(2)(3)fraction}def
+(18){(1)(8)fraction}def
+(38){(3)(8)fraction}def
+(58){(5)(8)fraction}def
+(78){(7)(8)fraction}def
+(sr){gsave 0 .06 dm rmoveto(\326)show oce}def
+(is){gsave 0 .15 dm rmoveto(\362)show oce}def
+(->){gsave 0 .02 dm rmoveto(\256)show oce}def
+(<-){gsave 0 .02 dm rmoveto(\254)show oce}def
+(==){gsave 0 .05 dm rmoveto(\272)show oce}def
+(uc){gsave currentpoint 400 .009 dm mul add translate
+ 8 -8 scale ucseal oce}def
+end
+
+% an attempt at a PostScript FONT to implement ditroff special chars
+% this will enable us to
+% cache the little buggers
+% generate faster, more compact PS out of psdit
+% confuse everyone (including myself)!
+50 dict dup begin
+/FontType 3 def
+/FontName /DIThacks def
+/FontMatrix [.001 0 0 .001 0 0] def
+/FontBBox [-260 -260 900 900] def% a lie but ...
+/Encoding 256 array def
+0 1 255{Encoding exch /.notdef put}for
+Encoding
+ dup 8#040/space put %space
+ dup 8#110/rc put %right ceil
+ dup 8#111/lt put %left top curl
+ dup 8#112/bv put %bold vert
+ dup 8#113/lk put %left mid curl
+ dup 8#114/lb put %left bot curl
+ dup 8#115/rt put %right top curl
+ dup 8#116/rk put %right mid curl
+ dup 8#117/rb put %right bot curl
+ dup 8#120/rf put %right floor
+ dup 8#121/lf put %left floor
+ dup 8#122/lc put %left ceil
+ dup 8#140/sq put %square
+ dup 8#141/bx put %box
+ dup 8#142/ci put %circle
+ dup 8#143/br put %box rule
+ dup 8#144/rn put %root extender
+ dup 8#145/vr put %vertical rule
+ dup 8#146/ob put %outline bullet
+ dup 8#147/bu put %bullet
+ dup 8#150/ru put %rule
+ dup 8#151/ul put %underline
+ pop
+/DITfd 100 dict def
+/BuildChar{0 begin
+ /cc exch def /fd exch def
+ /charname fd /Encoding get cc get def
+ /charwid fd /Metrics get charname get def
+ /charproc fd /CharProcs get charname get def
+ charwid 0 fd /FontBBox get aload pop setcachedevice
+ 2 setlinejoin 40 setlinewidth
+ newpath 0 0 moveto gsave charproc grestore
+ end}def
+/BuildChar load 0 DITfd put
+/CharProcs 50 dict def
+CharProcs begin
+/space{}def
+/.notdef{}def
+/ru{500 0 rls}def
+/rn{0 840 moveto 500 0 rls}def
+/vr{0 800 moveto 0 -770 rls}def
+/bv{0 800 moveto 0 -1000 rls}def
+/br{0 840 moveto 0 -1000 rls}def
+/ul{0 -140 moveto 500 0 rls}def
+/ob{200 250 rmoveto currentpoint newpath 200 0 360 arc closepath stroke}def
+/bu{200 250 rmoveto currentpoint newpath 200 0 360 arc closepath fill}def
+/sq{80 0 rmoveto currentpoint dround newpath moveto
+ 640 0 rlineto 0 640 rlineto -640 0 rlineto closepath stroke}def
+/bx{80 0 rmoveto currentpoint dround newpath moveto
+ 640 0 rlineto 0 640 rlineto -640 0 rlineto closepath fill}def
+/ci{500 360 rmoveto currentpoint newpath 333 0 360 arc
+ 50 setlinewidth stroke}def
+
+/lt{0 -200 moveto 0 550 rlineto currx 800 2cx s4 add exch s4 a4p stroke}def
+/lb{0 800 moveto 0 -550 rlineto currx -200 2cx s4 add exch s4 a4p stroke}def
+/rt{0 -200 moveto 0 550 rlineto currx 800 2cx s4 sub exch s4 a4p stroke}def
+/rb{0 800 moveto 0 -500 rlineto currx -200 2cx s4 sub exch s4 a4p stroke}def
+/lk{0 800 moveto 0 300 -300 300 s4 arcto pop pop 1000 sub
+ 0 300 4 2 roll s4 a4p 0 -200 lineto stroke}def
+/rk{0 800 moveto 0 300 s2 300 s4 arcto pop pop 1000 sub
+ 0 300 4 2 roll s4 a4p 0 -200 lineto stroke}def
+/lf{0 800 moveto 0 -1000 rlineto s4 0 rls}def
+/rf{0 800 moveto 0 -1000 rlineto s4 neg 0 rls}def
+/lc{0 -200 moveto 0 1000 rlineto s4 0 rls}def
+/rc{0 -200 moveto 0 1000 rlineto s4 neg 0 rls}def
+end
+
+/Metrics 50 dict def Metrics begin
+/.notdef 0 def
+/space 500 def
+/ru 500 def
+/br 0 def
+/lt 416 def
+/lb 416 def
+/rt 416 def
+/rb 416 def
+/lk 416 def
+/rk 416 def
+/rc 416 def
+/lc 416 def
+/rf 416 def
+/lf 416 def
+/bv 416 def
+/ob 350 def
+/bu 350 def
+/ci 750 def
+/bx 750 def
+/sq 750 def
+/rn 500 def
+/ul 500 def
+/vr 0 def
+end
+
+DITfd begin
+/s2 500 def /s4 250 def /s3 333 def
+/a4p{arcto pop pop pop pop}def
+/2cx{2 copy exch}def
+/rls{rlineto stroke}def
+/currx{currentpoint pop}def
+/dround{transform round exch round exch itransform} def
+end
+end
+/DIThacks exch definefont pop
+ditstart
+(psc)xT
+576 1 1 xr
+1(Times-Roman)xf 1 f
+2(Times-Italic)xf 2 f
+3(Times-Bold)xf 3 f
+4(Times-BoldItalic)xf 4 f
+5(Helvetica)xf 5 f
+6(Helvetica-Bold)xf 6 f
+7(Courier)xf 7 f
+8(Courier-Bold)xf 8 f
+9(Symbol)xf 9 f
+10(DIThacks)xf 10 f
+10 s
+1 f
+xi
+%%EndProlog
+
+%%Page: 1 1
+10 s 10 xH 0 xS 1 f
+3 f
+14 s
+1205 1206(LIBTP:)N
+1633(Portable,)X
+2100(M)X
+2206(odular)X
+2551(Transactions)X
+3202(for)X
+3374(UNIX)X
+1 f
+11 s
+3661 1162(1)N
+2 f
+12 s
+2182 1398(Margo)N
+2467(Seltzer)X
+2171 1494(Michael)N
+2511(Olson)X
+1800 1590(University)N
+2225(of)X
+2324(California,)X
+2773(Berkeley)X
+3 f
+2277 1878(Abstract)N
+1 f
+10 s
+755 2001(Transactions)N
+1198(provide)X
+1475(a)X
+1543(useful)X
+1771(programming)X
+2239(paradigm)X
+2574(for)X
+2700(maintaining)X
+3114(logical)X
+3364(consistency,)X
+3790(arbitrating)X
+4156(con-)X
+555 2091(current)N
+808(access,)X
+1059(and)X
+1200(managing)X
+1540(recovery.)X
+1886(In)X
+1977(traditional)X
+2330(UNIX)X
+2555(systems,)X
+2852(the)X
+2974(only)X
+3140(easy)X
+3307(way)X
+3465(of)X
+3556(using)X
+3753(transactions)X
+4160(is)X
+4237(to)X
+555 2181(purchase)N
+876(a)X
+947(database)X
+1258(system.)X
+1554(Such)X
+1748(systems)X
+2035(are)X
+2168(often)X
+2367(slow,)X
+2572(costly,)X
+2817(and)X
+2967(may)X
+3139(not)X
+3275(provide)X
+3554(the)X
+3686(exact)X
+3890(functionality)X
+555 2271(desired.)N
+848(This)X
+1011(paper)X
+1210(presents)X
+1493(the)X
+1611(design,)X
+1860(implementation,)X
+2402(and)X
+2538(performance)X
+2965(of)X
+3052(LIBTP,)X
+3314(a)X
+3370(simple,)X
+3623(non-proprietary)X
+4147(tran-)X
+555 2361(saction)N
+809(library)X
+1050(using)X
+1249(the)X
+1373(4.4BSD)X
+1654(database)X
+1957(access)X
+2189(routines)X
+2473(\()X
+3 f
+2500(db)X
+1 f
+2588(\(3\)\).)X
+2775(On)X
+2899(a)X
+2961(conventional)X
+3401(transaction)X
+3779(processing)X
+4148(style)X
+555 2451(benchmark,)N
+959(its)X
+1061(performance)X
+1495(is)X
+1575(approximately)X
+2065(85%)X
+2239(that)X
+2386(of)X
+2480(the)X
+2604(database)X
+2907(access)X
+3139(routines)X
+3423(without)X
+3693(transaction)X
+4071(protec-)X
+555 2541(tion,)N
+725(200%)X
+938(that)X
+1084(of)X
+1177(using)X
+3 f
+1376(fsync)X
+1 f
+1554(\(2\))X
+1674(to)X
+1761(commit)X
+2030(modi\256cations)X
+2490(to)X
+2577(disk,)X
+2755(and)X
+2896(125%)X
+3108(that)X
+3253(of)X
+3345(a)X
+3406(commercial)X
+3810(relational)X
+4138(data-)X
+555 2631(base)N
+718(system.)X
+3 f
+555 2817(1.)N
+655(Introduction)X
+1 f
+755 2940(Transactions)N
+1186(are)X
+1306(used)X
+1474(in)X
+1557(database)X
+1855(systems)X
+2129(to)X
+2212(enable)X
+2443(concurrent)X
+2807(users)X
+2992(to)X
+3074(apply)X
+3272(multi-operation)X
+3790(updates)X
+4055(without)X
+555 3030(violating)N
+863(the)X
+985(integrity)X
+1280(of)X
+1371(the)X
+1493(database.)X
+1814(They)X
+2003(provide)X
+2271(the)X
+2392(properties)X
+2736(of)X
+2826(atomicity,)X
+3171(consistency,)X
+3588(isolation,)X
+3906(and)X
+4045(durabil-)X
+555 3120(ity.)N
+701(By)X
+816(atomicity,)X
+1160(we)X
+1276(mean)X
+1472(that)X
+1614(the)X
+1734(set)X
+1845(of)X
+1934(updates)X
+2200(comprising)X
+2581(a)X
+2638(transaction)X
+3011(must)X
+3187(be)X
+3284(applied)X
+3541(as)X
+3629(a)X
+3686(single)X
+3898(unit;)X
+4085(that)X
+4226(is,)X
+555 3210(they)N
+714(must)X
+890(either)X
+1094(all)X
+1195(be)X
+1292(applied)X
+1549(to)X
+1632(the)X
+1751(database)X
+2049(or)X
+2137(all)X
+2238(be)X
+2335(absent.)X
+2601(Consistency)X
+3013(requires)X
+3293(that)X
+3434(a)X
+3491(transaction)X
+3864(take)X
+4019(the)X
+4138(data-)X
+555 3300(base)N
+725(from)X
+908(one)X
+1051(logically)X
+1358(consistent)X
+1704(state)X
+1877(to)X
+1965(another.)X
+2272(The)X
+2423(property)X
+2721(of)X
+2814(isolation)X
+3115(requires)X
+3400(that)X
+3546(concurrent)X
+3916(transactions)X
+555 3390(yield)N
+750(results)X
+994(which)X
+1225(are)X
+1358(indistinguishable)X
+1938(from)X
+2128(the)X
+2260(results)X
+2503(which)X
+2733(would)X
+2967(be)X
+3077(obtained)X
+3387(by)X
+3501(running)X
+3784(the)X
+3916(transactions)X
+555 3480(sequentially.)N
+1002(Finally,)X
+1268(durability)X
+1599(requires)X
+1878(that)X
+2018(once)X
+2190(transactions)X
+2593(have)X
+2765(been)X
+2937(committed,)X
+3319(their)X
+3486(results)X
+3715(must)X
+3890(be)X
+3986(preserved)X
+555 3570(across)N
+776(system)X
+1018(failures)X
+1279([TPCB90].)X
+755 3693(Although)N
+1080(these)X
+1268(properties)X
+1612(are)X
+1734(most)X
+1912(frequently)X
+2265(discussed)X
+2595(in)X
+2680(the)X
+2801(context)X
+3060(of)X
+3150(databases,)X
+3501(they)X
+3661(are)X
+3782(useful)X
+4000(program-)X
+555 3783(ming)N
+750(paradigms)X
+1114(for)X
+1238(more)X
+1433(general)X
+1700(purpose)X
+1984(applications.)X
+2441(There)X
+2659(are)X
+2788(several)X
+3046(different)X
+3353(situations)X
+3689(where)X
+3916(transactions)X
+555 3873(can)N
+687(be)X
+783(used)X
+950(to)X
+1032(replace)X
+1285(current)X
+1533(ad-hoc)X
+1772(mechanisms.)X
+755 3996(One)N
+910(situation)X
+1206(is)X
+1280(when)X
+1475(multiple)X
+1762(\256les)X
+1916(or)X
+2004(parts)X
+2181(of)X
+2269(\256les)X
+2422(need)X
+2594(to)X
+2676(be)X
+2772(updated)X
+3046(in)X
+3128(an)X
+3224(atomic)X
+3462(fashion.)X
+3758(For)X
+3889(example,)X
+4201(the)X
+555 4086(traditional)N
+907(UNIX)X
+1131(\256le)X
+1256(system)X
+1501(uses)X
+1661(ordering)X
+1955(constraints)X
+2324(to)X
+2408(achieve)X
+2676(recoverability)X
+3144(in)X
+3228(the)X
+3348(face)X
+3505(of)X
+3594(crashes.)X
+3893(When)X
+4107(a)X
+4165(new)X
+555 4176(\256le)N
+678(is)X
+752(created,)X
+1026(its)X
+1122(inode)X
+1321(is)X
+1395(written)X
+1642(to)X
+1724(disk)X
+1877(before)X
+2103(the)X
+2221(new)X
+2375(\256le)X
+2497(is)X
+2570(added)X
+2782(to)X
+2864(the)X
+2982(directory)X
+3292(structure.)X
+3633(This)X
+3795(guarantees)X
+4159(that,)X
+555 4266(if)N
+627(the)X
+748(system)X
+993(crashes)X
+1253(between)X
+1544(the)X
+1665(two)X
+1808(I/O's,)X
+2016(the)X
+2137(directory)X
+2450(does)X
+2620(not)X
+2744(contain)X
+3002(a)X
+3060 0.4531(reference)AX
+3383(to)X
+3467(an)X
+3565(invalid)X
+3809(inode.)X
+4049(In)X
+4138(actu-)X
+555 4356(ality,)N
+741(the)X
+863(desired)X
+1119(effect)X
+1326(is)X
+1402(that)X
+1545(these)X
+1733(two)X
+1876(updates)X
+2144(have)X
+2319(the)X
+2440(transactional)X
+2873(property)X
+3168(of)X
+3258(atomicity)X
+3583(\(either)X
+3816(both)X
+3981(writes)X
+4200(are)X
+555 4446(visible)N
+790(or)X
+879(neither)X
+1124(is\).)X
+1266(Rather)X
+1501(than)X
+1660(building)X
+1947(special)X
+2191(purpose)X
+2466(recovery)X
+2769(mechanisms)X
+3186(into)X
+3331(the)X
+3450(\256le)X
+3573(system)X
+3816(or)X
+3904(related)X
+4144(tools)X
+555 4536(\()N
+2 f
+582(e.g.)X
+3 f
+726(fsck)X
+1 f
+864(\(8\)\),)X
+1033(one)X
+1177(could)X
+1383(use)X
+1518(general)X
+1783(purpose)X
+2064(transaction)X
+2443(recovery)X
+2752(protocols)X
+3077(after)X
+3252(system)X
+3501(failure.)X
+3778(Any)X
+3943(application)X
+555 4626(that)N
+705(needs)X
+918(to)X
+1010(keep)X
+1192(multiple,)X
+1508(related)X
+1757(\256les)X
+1920(\(or)X
+2044(directories\))X
+2440(consistent)X
+2790(should)X
+3032(do)X
+3141(so)X
+3241(using)X
+3443(transactions.)X
+3895(Source)X
+4147(code)X
+555 4716(control)N
+805(systems,)X
+1101(such)X
+1271(as)X
+1361(RCS)X
+1534(and)X
+1673(SCCS,)X
+1910(should)X
+2146(use)X
+2276(transaction)X
+2651(semantics)X
+2990(to)X
+3075(allow)X
+3276(the)X
+3397(``checking)X
+3764(in'')X
+3903(of)X
+3992(groups)X
+4232(of)X
+555 4806(related)N
+801(\256les.)X
+1001(In)X
+1095(this)X
+1237(way,)X
+1418(if)X
+1493(the)X
+1617 0.2841(``check-in'')AX
+2028(fails,)X
+2212(the)X
+2336(transaction)X
+2714(may)X
+2878(be)X
+2980(aborted,)X
+3267(backing)X
+3547(out)X
+3675(the)X
+3799(partial)X
+4030(``check-)X
+555 4896(in'')N
+691(leaving)X
+947(the)X
+1065(source)X
+1295(repository)X
+1640(in)X
+1722(a)X
+1778(consistent)X
+2118(state.)X
+755 5019(A)N
+842(second)X
+1094(situation)X
+1398(where)X
+1624(transactions)X
+2036(can)X
+2177(be)X
+2282(used)X
+2458(to)X
+2549(replace)X
+2811(current)X
+3068(ad-hoc)X
+3316(mechanisms)X
+3741(is)X
+3822(in)X
+3912(applications)X
+555 5109(where)N
+776(concurrent)X
+1144(updates)X
+1413(to)X
+1499(a)X
+1559(shared)X
+1793(\256le)X
+1919(are)X
+2042(desired,)X
+2318(but)X
+2444(there)X
+2629(is)X
+2706(logical)X
+2948(consistency)X
+3345(of)X
+3435(the)X
+3556(data)X
+3713(which)X
+3932(needs)X
+4138(to)X
+4223(be)X
+555 5199(preserved.)N
+928(For)X
+1059(example,)X
+1371(when)X
+1565(the)X
+1683(password)X
+2006(\256le)X
+2128(is)X
+2201(updated,)X
+2495(\256le)X
+2617(locking)X
+2877(is)X
+2950(used)X
+3117(to)X
+3199(disallow)X
+3490(concurrent)X
+3854(access.)X
+4120(Tran-)X
+555 5289(saction)N
+804(semantics)X
+1142(on)X
+1244(the)X
+1364(password)X
+1689(\256les)X
+1844(would)X
+2066(allow)X
+2266(concurrent)X
+2632(updates,)X
+2919(while)X
+3119(preserving)X
+3479(the)X
+3598(logical)X
+3837(consistency)X
+4232(of)X
+555 5379(the)N
+681(password)X
+1012(database.)X
+1357(Similarly,)X
+1702(UNIX)X
+1930(utilities)X
+2196(which)X
+2419(rewrite)X
+2674(\256les)X
+2834(face)X
+2996(a)X
+3059(potential)X
+3366(race)X
+3528(condition)X
+3857(between)X
+4152(their)X
+555 5469(rewriting)N
+871(a)X
+929(\256le)X
+1053(and)X
+1191(another)X
+1453(process)X
+1715(reading)X
+1977(the)X
+2096(\256le.)X
+2259(For)X
+2391(example,)X
+2704(the)X
+2823(compiler)X
+3129(\(more)X
+3342(precisely,)X
+3673(the)X
+3792(assembler\))X
+4161(may)X
+8 s
+10 f
+555 5541(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)N
+5 s
+1 f
+727 5619(1)N
+8 s
+763 5644(To)N
+850(appear)X
+1035(in)X
+1101(the)X
+2 f
+1195(Proceedings)X
+1530(of)X
+1596(the)X
+1690(1992)X
+1834(Winter)X
+2024(Usenix)X
+1 f
+2201(,)X
+2233(San)X
+2345(Francisco,)X
+2625(CA,)X
+2746(January)X
+2960(1992.)X
+
+2 p
+%%Page: 2 2
+8 s 8 xH 0 xS 1 f
+10 s
+3 f
+1 f
+555 630(have)N
+737(to)X
+829(rewrite)X
+1087(a)X
+1152(\256le)X
+1283(to)X
+1374(which)X
+1599(it)X
+1672(has)X
+1808(write)X
+2002(permission)X
+2382(in)X
+2473(a)X
+2538(directory)X
+2857(to)X
+2948(which)X
+3173(it)X
+3246(does)X
+3422(not)X
+3553(have)X
+3734(write)X
+3928(permission.)X
+555 720(While)N
+779(the)X
+904(``.o'')X
+1099(\256le)X
+1228(is)X
+1308(being)X
+1513(written,)X
+1787(another)X
+2055(utility)X
+2272(such)X
+2446(as)X
+3 f
+2540(nm)X
+1 f
+2651(\(1\))X
+2772(or)X
+3 f
+2866(ar)X
+1 f
+2942(\(1\))X
+3063(may)X
+3228(read)X
+3394(the)X
+3519(\256le)X
+3648(and)X
+3791(produce)X
+4077(invalid)X
+555 810(results)N
+790(since)X
+981(the)X
+1105(\256le)X
+1233(has)X
+1366(not)X
+1494(been)X
+1672(completely)X
+2054(written.)X
+2347(Currently,)X
+2700(some)X
+2895(utilities)X
+3160(use)X
+3293(special)X
+3542(purpose)X
+3821(code)X
+3998(to)X
+4085(handle)X
+555 900(such)N
+722(cases)X
+912(while)X
+1110(others)X
+1326(ignore)X
+1551(the)X
+1669(problem)X
+1956(and)X
+2092(force)X
+2278(users)X
+2463(to)X
+2545(live)X
+2685(with)X
+2847(the)X
+2965(consequences.)X
+755 1023(In)N
+845(this)X
+983(paper,)X
+1205(we)X
+1322(present)X
+1577(a)X
+1635(simple)X
+1870(library)X
+2106(which)X
+2324(provides)X
+2622(transaction)X
+2996(semantics)X
+3334(\(atomicity,)X
+3705(consistency,)X
+4121(isola-)X
+555 1113(tion,)N
+720(and)X
+857(durability\).)X
+1236(The)X
+1382(4.4BSD)X
+1658(database)X
+1956(access)X
+2182(methods)X
+2473(have)X
+2645(been)X
+2817(modi\256ed)X
+3121(to)X
+3203(use)X
+3330(this)X
+3465(library,)X
+3719(optionally)X
+4063(provid-)X
+555 1203(ing)N
+682(shared)X
+917(buffer)X
+1139(management)X
+1574(between)X
+1867(applications,)X
+2298(locking,)X
+2582(and)X
+2722(transaction)X
+3098(semantics.)X
+3478(Any)X
+3640(UNIX)X
+3865(program)X
+4161(may)X
+555 1293(transaction)N
+930(protect)X
+1176(its)X
+1274(data)X
+1430(by)X
+1532(requesting)X
+1888(transaction)X
+2262(protection)X
+2609(with)X
+2773(the)X
+3 f
+2893(db)X
+1 f
+2981(\(3\))X
+3097(library)X
+3333(or)X
+3422(by)X
+3524(adding)X
+3764(appropriate)X
+4152(calls)X
+555 1383(to)N
+646(the)X
+773(transaction)X
+1154(manager,)X
+1480(buffer)X
+1706(manager,)X
+2032(lock)X
+2199(manager,)X
+2525(and)X
+2670(log)X
+2801(manager.)X
+3147(The)X
+3301(library)X
+3543(routines)X
+3829(may)X
+3995(be)X
+4099(linked)X
+555 1473(into)N
+708(the)X
+834(host)X
+995(application)X
+1379(and)X
+1523(called)X
+1743(by)X
+1851(subroutine)X
+2217(interface,)X
+2547(or)X
+2642(they)X
+2808(may)X
+2974(reside)X
+3194(in)X
+3284(a)X
+3348(separate)X
+3640(server)X
+3865(process.)X
+4174(The)X
+555 1563(server)N
+772(architecture)X
+1172(provides)X
+1468(for)X
+1582(network)X
+1865(access)X
+2091(and)X
+2227(better)X
+2430(protection)X
+2775(mechanisms.)X
+3 f
+555 1749(2.)N
+655(Related)X
+938(Work)X
+1 f
+755 1872(There)N
+1000(has)X
+1164(been)X
+1373(much)X
+1608(discussion)X
+1998(in)X
+2117(recent)X
+2371(years)X
+2597(about)X
+2831(new)X
+3021(transaction)X
+3429(models)X
+3716(and)X
+3888(architectures)X
+555 1962 0.1172([SPEC88][NODI90][CHEN91][MOHA91].)AN
+2009(Much)X
+2220(of)X
+2310(this)X
+2448(work)X
+2636(focuses)X
+2900(on)X
+3003(new)X
+3160(ways)X
+3348(to)X
+3433(model)X
+3656(transactions)X
+4062(and)X
+4201(the)X
+555 2052(interactions)N
+953(between)X
+1245(them,)X
+1449(while)X
+1651(the)X
+1772(work)X
+1960(presented)X
+2291(here)X
+2453(focuses)X
+2717(on)X
+2820(the)X
+2941(implementation)X
+3466(and)X
+3605(performance)X
+4035(of)X
+4125(tradi-)X
+555 2142(tional)N
+757(transaction)X
+1129(techniques)X
+1492(\(write-ahead)X
+1919(logging)X
+2183(and)X
+2319(two-phase)X
+2669(locking\))X
+2956(on)X
+3056(a)X
+3112(standard)X
+3404(operating)X
+3727(system)X
+3969(\(UNIX\).)X
+755 2265(Such)N
+947(traditional)X
+1308(operating)X
+1643(systems)X
+1928(are)X
+2059(often)X
+2256(criticized)X
+2587(for)X
+2713(their)X
+2892(inability)X
+3190(to)X
+3283(perform)X
+3573(transaction)X
+3956(processing)X
+555 2355(adequately.)N
+971([STON81])X
+1342(cites)X
+1517(three)X
+1706(main)X
+1894(areas)X
+2088(of)X
+2183(inadequate)X
+2559(support:)X
+2849(buffer)X
+3074(management,)X
+3532(the)X
+3658(\256le)X
+3788(system,)X
+4058(and)X
+4201(the)X
+555 2445(process)N
+823(structure.)X
+1191(These)X
+1410(arguments)X
+1771(are)X
+1897(summarized)X
+2316(in)X
+2405(table)X
+2587(one.)X
+2769(Fortunately,)X
+3184(much)X
+3388(has)X
+3521(changed)X
+3815(since)X
+4006(1981.)X
+4232(In)X
+555 2535(the)N
+683(area)X
+848(of)X
+945(buffer)X
+1172(management,)X
+1632(most)X
+1817(UNIX)X
+2048(systems)X
+2331(provide)X
+2606(the)X
+2734(ability)X
+2968(to)X
+3060(memory)X
+3357(map)X
+3525(\256les,)X
+3708(thus)X
+3870(obviating)X
+4201(the)X
+555 2625(need)N
+734(for)X
+855(a)X
+918(copy)X
+1101(between)X
+1396(kernel)X
+1624(and)X
+1766(user)X
+1926(space.)X
+2171(If)X
+2251(a)X
+2313(database)X
+2616(system)X
+2864(is)X
+2943(going)X
+3151(to)X
+3239(use)X
+3372(the)X
+3496(\256le)X
+3624(system)X
+3872(buffer)X
+4095(cache,)X
+555 2715(then)N
+719(a)X
+781(system)X
+1029(call)X
+1171(is)X
+1250(required.)X
+1584(However,)X
+1924(if)X
+1998(buffering)X
+2322(is)X
+2400(provided)X
+2710(at)X
+2793(user)X
+2952(level)X
+3133(using)X
+3331(shared)X
+3566(memory,)X
+3878(as)X
+3970(in)X
+4057(LIBTP,)X
+555 2805(buffer)N
+776(management)X
+1210(is)X
+1287(only)X
+1452(as)X
+1542(slow)X
+1716(as)X
+1806(access)X
+2035(to)X
+2120(shared)X
+2353(memory)X
+2643(and)X
+2782(any)X
+2921(replacement)X
+3337(algorithm)X
+3671(may)X
+3832(be)X
+3931(used.)X
+4121(Since)X
+555 2895(multiple)N
+849(processes)X
+1185(can)X
+1325(access)X
+1559(the)X
+1685(shared)X
+1923(data,)X
+2105(prefetching)X
+2499(may)X
+2665(be)X
+2769(accomplished)X
+3238(by)X
+3346(separate)X
+3638(processes)X
+3973(or)X
+4067(threads)X
+555 2985(whose)N
+782(sole)X
+932(purpose)X
+1207(is)X
+1281(to)X
+1364(prefetch)X
+1649(pages)X
+1853(and)X
+1990(wait)X
+2149(on)X
+2250(them.)X
+2471(There)X
+2680(is)X
+2754(still)X
+2894(no)X
+2995(way)X
+3150(to)X
+3233(enforce)X
+3496(write)X
+3682(ordering)X
+3975(other)X
+4161(than)X
+555 3075(keeping)N
+829(pages)X
+1032(in)X
+1114(user)X
+1268(memory)X
+1555(and)X
+1691(using)X
+1884(the)X
+3 f
+2002(fsync)X
+1 f
+2180(\(3\))X
+2294(system)X
+2536(call)X
+2672(to)X
+2754(perform)X
+3033(synchronous)X
+3458(writes.)X
+755 3198(In)N
+845(the)X
+966(area)X
+1124(of)X
+1214(\256le)X
+1339(systems,)X
+1635(the)X
+1756(fast)X
+1895(\256le)X
+2020(system)X
+2265(\(FFS\))X
+2474([MCKU84])X
+2871(allows)X
+3103(allocation)X
+3442(in)X
+3527(units)X
+3704(up)X
+3806(to)X
+3890(64KBytes)X
+4232(as)X
+555 3288(opposed)N
+846(to)X
+932(the)X
+1054(4KByte)X
+1327(and)X
+1466(8KByte)X
+1738(\256gures)X
+1979(quoted)X
+2220(in)X
+2305([STON81].)X
+2711(The)X
+2859(measurements)X
+3341(in)X
+3426(this)X
+3564(paper)X
+3766(were)X
+3946(taken)X
+4143(from)X
+555 3378(an)N
+655(8KByte)X
+928(FFS,)X
+1104(but)X
+1230(as)X
+1320(LIBTP)X
+1565(runs)X
+1726(exclusively)X
+2114(in)X
+2199(user)X
+2356(space,)X
+2578(there)X
+2762(is)X
+2838(nothing)X
+3105(to)X
+3190(prevent)X
+3454(it)X
+3521(from)X
+3700(being)X
+3901(run)X
+4031(on)X
+4134(other)X
+555 3468(UNIX)N
+776(compatible)X
+1152(\256le)X
+1274(systems)X
+1547(\(e.g.)X
+1710(log-structured)X
+2180([ROSE91],)X
+2558(extent-based,)X
+3004(or)X
+3091(multi-block)X
+3484([SELT91]\).)X
+755 3591(Finally,)N
+1029(with)X
+1199(regard)X
+1433(to)X
+1523(the)X
+1648(process)X
+1916(structure,)X
+2244(neither)X
+2494(context)X
+2757(switch)X
+2993(time)X
+3162(nor)X
+3296(scheduling)X
+3670(around)X
+3920(semaphores)X
+555 3681(seems)N
+785(to)X
+881(affect)X
+1099(the)X
+1231(system)X
+1487(performance.)X
+1968(However,)X
+2317(the)X
+2449(implementation)X
+2984(of)X
+3084(semaphores)X
+3496(can)X
+3641(impact)X
+3892(performance)X
+555 3771(tremendously.)N
+1051(This)X
+1213(is)X
+1286(discussed)X
+1613(in)X
+1695(more)X
+1880(detail)X
+2078(in)X
+2160(section)X
+2407(4.3.)X
+755 3894(The)N
+908(Tuxedo)X
+1181(system)X
+1431(from)X
+1615(AT&T)X
+1861(is)X
+1941(a)X
+2004(transaction)X
+2383(manager)X
+2687(which)X
+2910(coordinates)X
+3307(distributed)X
+3676(transaction)X
+4055(commit)X
+555 3984(from)N
+738(a)X
+801(variety)X
+1051(of)X
+1145(different)X
+1449(local)X
+1632(transaction)X
+2011(managers.)X
+2386(At)X
+2493(this)X
+2634(time,)X
+2822(LIBTP)X
+3070(does)X
+3243(not)X
+3371(have)X
+3549(its)X
+3650(own)X
+3814(mechanism)X
+4205(for)X
+555 4074(distributed)N
+942(commit)X
+1231(processing,)X
+1639(but)X
+1786(could)X
+2009(be)X
+2130(used)X
+2322(as)X
+2434(a)X
+2515(local)X
+2716(transaction)X
+3113(agent)X
+3331(by)X
+3455(systems)X
+3752(such)X
+3943(as)X
+4054(Tuxedo)X
+555 4164([ANDR89].)N
+10 f
+863 4393(i)N
+870(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+903 4483(Buffer)N
+1133(Management)X
+10 f
+1672(g)X
+1 f
+1720(Data)X
+1892(must)X
+2067(be)X
+2163(copied)X
+2397(between)X
+2685(kernel)X
+2906(space)X
+3105(and)X
+3241(user)X
+3395(space.)X
+10 f
+1672 4573(g)N
+1 f
+1720(Buffer)X
+1950(pool)X
+2112(access)X
+2338(is)X
+2411(too)X
+2533(slow.)X
+10 f
+1672 4663(g)N
+1 f
+1720(There)X
+1928(is)X
+2001(no)X
+2101(way)X
+2255(to)X
+2337(request)X
+2589(prefetch.)X
+10 f
+1672 4753(g)N
+1 f
+1720(Replacement)X
+2159(is)X
+2232(usually)X
+2483(LRU)X
+2663(which)X
+2879(may)X
+3037(be)X
+3133(suboptimal)X
+3508(for)X
+3622(databases.)X
+10 f
+1672 4843(g)N
+1 f
+1720(There)X
+1928(is)X
+2001(no)X
+2101(way)X
+2255(to)X
+2337(guarantee)X
+2670(write)X
+2855(ordering.)X
+10 f
+863 4853(i)N
+870(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+903 4943(File)N
+1047(System)X
+10 f
+1672(g)X
+1 f
+1720(Allocation)X
+2078(is)X
+2151(done)X
+2327(in)X
+2409(small)X
+2602(blocks)X
+2831(\(usually)X
+3109(4K)X
+3227(or)X
+3314(8K\).)X
+10 f
+1672 5033(g)N
+1 f
+1720(Logical)X
+1985(organization)X
+2406(of)X
+2493(\256les)X
+2646(is)X
+2719(redundantly)X
+3122(expressed.)X
+10 f
+863 5043(i)N
+870(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+903 5133(Process)N
+1168(Structure)X
+10 f
+1672(g)X
+1 f
+1720(Context)X
+1993(switching)X
+2324(and)X
+2460(message)X
+2752(passing)X
+3012(are)X
+3131(too)X
+3253(slow.)X
+10 f
+1672 5223(g)N
+1 f
+1720(A)X
+1798(process)X
+2059(may)X
+2217(be)X
+2313(descheduled)X
+2730(while)X
+2928(holding)X
+3192(a)X
+3248(semaphore.)X
+10 f
+863 5233(i)N
+870(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+863(c)X
+5193(c)Y
+5113(c)Y
+5033(c)Y
+4953(c)Y
+4873(c)Y
+4793(c)Y
+4713(c)Y
+4633(c)Y
+4553(c)Y
+4473(c)Y
+3990 5233(c)N
+5193(c)Y
+5113(c)Y
+5033(c)Y
+4953(c)Y
+4873(c)Y
+4793(c)Y
+4713(c)Y
+4633(c)Y
+4553(c)Y
+4473(c)Y
+3 f
+1156 5446(Table)N
+1371(One:)X
+1560(Shortcomings)X
+2051(of)X
+2138(UNIX)X
+2363(transaction)X
+2770(support)X
+3056(cited)X
+3241(in)X
+3327([STON81].)X
+
+3 p
+%%Page: 3 3
+10 s 10 xH 0 xS 3 f
+1 f
+755 630(The)N
+901(transaction)X
+1274(architecture)X
+1675(presented)X
+2004(in)X
+2087([YOUN91])X
+2474(is)X
+2548(very)X
+2712(similar)X
+2955(to)X
+3038(that)X
+3179(implemented)X
+3618(in)X
+3701(the)X
+3820(LIBTP.)X
+4103(While)X
+555 720([YOUN91])N
+947(presents)X
+1236(a)X
+1298(model)X
+1524(for)X
+1644(providing)X
+1981(transaction)X
+2359(services,)X
+2663(this)X
+2803(paper)X
+3007(focuses)X
+3273(on)X
+3378(the)X
+3501(implementation)X
+4028(and)X
+4169(per-)X
+555 810(formance)N
+881(of)X
+970(a)X
+1028(particular)X
+1358(system.)X
+1642(In)X
+1731(addition,)X
+2034(we)X
+2149(provide)X
+2415(detailed)X
+2690(comparisons)X
+3116(with)X
+3279(alternative)X
+3639(solutions:)X
+3970(traditional)X
+555 900(UNIX)N
+776(services)X
+1055(and)X
+1191(commercial)X
+1590(database)X
+1887(management)X
+2317(systems.)X
+3 f
+555 1086(3.)N
+655(Architecture)X
+1 f
+755 1209(The)N
+906(library)X
+1146(is)X
+1224(designed)X
+1534(to)X
+1621(provide)X
+1891(well)X
+2054(de\256ned)X
+2315(interfaces)X
+2653(to)X
+2740(the)X
+2863(services)X
+3147(required)X
+3440(for)X
+3559(transaction)X
+3936(processing.)X
+555 1299(These)N
+777(services)X
+1066(are)X
+1195(recovery,)X
+1527(concurrency)X
+1955(control,)X
+2232(and)X
+2378(the)X
+2506(management)X
+2946(of)X
+3043(shared)X
+3283(data.)X
+3487(First)X
+3663(we)X
+3787(will)X
+3941(discuss)X
+4201(the)X
+555 1389(design)N
+795(tradeoffs)X
+1112(in)X
+1205(the)X
+1334(selection)X
+1650(of)X
+1748(recovery,)X
+2081(concurrency)X
+2510(control,)X
+2787(and)X
+2933(buffer)X
+3160(management)X
+3600(implementations,)X
+4183(and)X
+555 1479(then)N
+713(we)X
+827(will)X
+971(present)X
+1223(the)X
+1341(overall)X
+1584(library)X
+1818(architecture)X
+2218(and)X
+2354(module)X
+2614(descriptions.)X
+3 f
+555 1665(3.1.)N
+715(Design)X
+966(Tradeoffs)X
+1 f
+3 f
+555 1851(3.1.1.)N
+775(Crash)X
+1004(Recovery)X
+1 f
+755 1974(The)N
+909(recovery)X
+1220(protocol)X
+1516(is)X
+1598(responsible)X
+1992(for)X
+2115(providing)X
+2455(the)X
+2582(transaction)X
+2963(semantics)X
+3308(discussed)X
+3644(earlier.)X
+3919(There)X
+4136(are)X
+4263(a)X
+555 2064(wide)N
+739(range)X
+946(of)X
+1041(recovery)X
+1351(protocols)X
+1677(available)X
+1995([HAER83],)X
+2395(but)X
+2525(we)X
+2647(can)X
+2786(crudely)X
+3054(divide)X
+3281(them)X
+3468(into)X
+3619(two)X
+3766(main)X
+3953(categories.)X
+555 2154(The)N
+706(\256rst)X
+856(category)X
+1159(records)X
+1422(all)X
+1528(modi\256cations)X
+1989(to)X
+2077(the)X
+2201(database)X
+2504(in)X
+2592(a)X
+2653(separate)X
+2942(\256le,)X
+3089(and)X
+3230(uses)X
+3393(this)X
+3533(\256le)X
+3660(\(log\))X
+3841(to)X
+3928(back)X
+4105(out)X
+4232(or)X
+555 2244(reapply)N
+825(these)X
+1019(modi\256cations)X
+1483(if)X
+1561(a)X
+1626(transaction)X
+2007(aborts)X
+2232(or)X
+2328(the)X
+2455(system)X
+2706(crashes.)X
+3012(We)X
+3153(call)X
+3298(this)X
+3442(set)X
+3560(the)X
+3 f
+3687(logging)X
+3963(protocols)X
+1 f
+4279(.)X
+555 2334(The)N
+703(second)X
+949(category)X
+1249(avoids)X
+1481(the)X
+1602(use)X
+1732(of)X
+1822(a)X
+1881(log)X
+2006(by)X
+2109(carefully)X
+2418(controlling)X
+2792(when)X
+2989(data)X
+3146(are)X
+3268(written)X
+3518(to)X
+3603(disk.)X
+3799(We)X
+3934(call)X
+4073(this)X
+4210(set)X
+555 2424(the)N
+3 f
+673(non-logging)X
+1096(protocols)X
+1 f
+1412(.)X
+755 2547(Non-logging)N
+1185(protocols)X
+1504(hold)X
+1666(dirty)X
+1837(buffers)X
+2085(in)X
+2167(main)X
+2347(memory)X
+2634(or)X
+2721(temporary)X
+3071(\256les)X
+3224(until)X
+3390(commit)X
+3654(and)X
+3790(then)X
+3948(force)X
+4134(these)X
+555 2637(pages)N
+769(to)X
+862(disk)X
+1026(at)X
+1115(transaction)X
+1498(commit.)X
+1813(While)X
+2040(we)X
+2165(can)X
+2308(use)X
+2446(temporary)X
+2807(\256les)X
+2971(to)X
+3064(hold)X
+3237(dirty)X
+3418(pages)X
+3631(that)X
+3781(may)X
+3949(need)X
+4131(to)X
+4223(be)X
+555 2727(evicted)N
+810(from)X
+988(memory)X
+1277(during)X
+1508(a)X
+1566(long-running)X
+2006(transaction,)X
+2400(the)X
+2520(only)X
+2684(user-level)X
+3023(mechanism)X
+3410(to)X
+3494(force)X
+3682(pages)X
+3887(to)X
+3971(disk)X
+4126(is)X
+4201(the)X
+3 f
+555 2817(fsync)N
+1 f
+733(\(2\))X
+850(system)X
+1095(call.)X
+1274(Unfortunately,)X
+3 f
+1767(fsync)X
+1 f
+1945(\(2\))X
+2062(is)X
+2138(an)X
+2237(expensive)X
+2581(system)X
+2826(call)X
+2965(in)X
+3050(that)X
+3193(it)X
+3260(forces)X
+3480(all)X
+3583(pages)X
+3789(of)X
+3879(a)X
+3938(\256le)X
+4062(to)X
+4146(disk,)X
+555 2907(and)N
+691(transactions)X
+1094(that)X
+1234(manage)X
+1504(more)X
+1689(than)X
+1847(one)X
+1983(\256le)X
+2105(must)X
+2280(issue)X
+2460(one)X
+2596(call)X
+2732(per)X
+2855(\256le.)X
+755 3030(In)N
+853(addition,)X
+3 f
+1166(fsync)X
+1 f
+1344(\(2\))X
+1469(provides)X
+1776(no)X
+1887(way)X
+2051(to)X
+2143(control)X
+2400(the)X
+2528(order)X
+2728(in)X
+2820(which)X
+3046(dirty)X
+3227(pages)X
+3440(are)X
+3569(written)X
+3826(to)X
+3918(disk.)X
+4121(Since)X
+555 3120(non-logging)N
+976(protocols)X
+1304(must)X
+1489(sometimes)X
+1861(order)X
+2061(writes)X
+2287(carefully)X
+2603([SULL92],)X
+2987(they)X
+3155(are)X
+3284(dif\256cult)X
+3567(to)X
+3659(implement)X
+4030(on)X
+4139(Unix)X
+555 3210(systems.)N
+868(As)X
+977(a)X
+1033(result,)X
+1251(we)X
+1365(have)X
+1537(chosen)X
+1780(to)X
+1862(implement)X
+2224(a)X
+2280(logging)X
+2544(protocol.)X
+755 3333(Logging)N
+1050(protocols)X
+1372(may)X
+1534(be)X
+1634(categorized)X
+2029(based)X
+2236(on)X
+2340(how)X
+2502(information)X
+2904(is)X
+2981(logged)X
+3223(\(physically)X
+3602(or)X
+3692(logically\))X
+4022(and)X
+4161(how)X
+555 3423(much)N
+767(is)X
+854(logged)X
+1106(\(before)X
+1373(images,)X
+1654(after)X
+1836(images)X
+2097(or)X
+2198(both\).)X
+2441(In)X
+3 f
+2542(physical)X
+2855(logging)X
+1 f
+3103(,)X
+3157(images)X
+3417(of)X
+3517(complete)X
+3844(physical)X
+4144(units)X
+555 3513(\(pages)N
+786(or)X
+874(buffers\))X
+1150(are)X
+1270(recorded,)X
+1593(while)X
+1792(in)X
+3 f
+1875(logical)X
+2118(logging)X
+1 f
+2387(a)X
+2444(description)X
+2820(of)X
+2907(the)X
+3025(operation)X
+3348(is)X
+3421(recorded.)X
+3763(Therefore,)X
+4121(while)X
+555 3603(we)N
+675(may)X
+839(record)X
+1071(entire)X
+1280(pages)X
+1489(in)X
+1577(a)X
+1639(physical)X
+1932(log,)X
+2080(we)X
+2200(need)X
+2378(only)X
+2546(record)X
+2777(the)X
+2900(records)X
+3162(being)X
+3365(modi\256ed)X
+3674(in)X
+3761(a)X
+3822(logical)X
+4065(log.)X
+4232(In)X
+555 3693(fact,)N
+718(physical)X
+1006(logging)X
+1271(can)X
+1404(be)X
+1501(thought)X
+1766(of)X
+1854(as)X
+1942(a)X
+1999(special)X
+2243(case)X
+2403(of)X
+2491(logical)X
+2730(logging,)X
+3015(since)X
+3201(the)X
+3320 0.3125(``records'')AX
+3686(that)X
+3827(we)X
+3942(log)X
+4065(in)X
+4148(logi-)X
+555 3783(cal)N
+673(logging)X
+941(might)X
+1151(be)X
+1251(physical)X
+1542(pages.)X
+1789(Since)X
+1991(logical)X
+2233(logging)X
+2501(is)X
+2578(both)X
+2743(more)X
+2931(space-ef\256cient)X
+3423(and)X
+3562(more)X
+3750(general,)X
+4030(we)X
+4147(have)X
+555 3873(chosen)N
+798(it)X
+862(for)X
+976(our)X
+1103(logging)X
+1367(protocol.)X
+755 3996(In)N
+3 f
+843(before-image)X
+1315(logging)X
+1 f
+1563(,)X
+1604(we)X
+1719(log)X
+1842(a)X
+1899(copy)X
+2076(of)X
+2164(the)X
+2283(data)X
+2438(before)X
+2665(the)X
+2784(update,)X
+3039(while)X
+3238(in)X
+3 f
+3321(after-image)X
+3739(logging)X
+1 f
+3987(,)X
+4027(we)X
+4141(log)X
+4263(a)X
+555 4086(copy)N
+740(of)X
+836(the)X
+963(data)X
+1126(after)X
+1303(the)X
+1429(update.)X
+1711(If)X
+1793(we)X
+1915(log)X
+2045(only)X
+2215(before-images,)X
+2723(then)X
+2889(there)X
+3078(is)X
+3159(suf\256cient)X
+3485(information)X
+3891(in)X
+3981(the)X
+4107(log)X
+4237(to)X
+555 4176(allow)N
+761(us)X
+860(to)X
+3 f
+950(undo)X
+1 f
+1150(the)X
+1276(transaction)X
+1656(\(go)X
+1791(back)X
+1971(to)X
+2061(the)X
+2187(state)X
+2361(represented)X
+2759(by)X
+2866(the)X
+2991(before-image\).)X
+3514(However,)X
+3876(if)X
+3952(the)X
+4077(system)X
+555 4266(crashes)N
+814(and)X
+952(a)X
+1010(committed)X
+1374(transaction's)X
+1806(changes)X
+2087(have)X
+2261(not)X
+2385(reached)X
+2658(the)X
+2778(disk,)X
+2953(we)X
+3068(have)X
+3241(no)X
+3342(means)X
+3568(to)X
+3 f
+3651(redo)X
+1 f
+3828(the)X
+3947(transaction)X
+555 4356(\(reapply)N
+849(the)X
+973(updates\).)X
+1311(Therefore,)X
+1675(logging)X
+1945(only)X
+2113(before-images)X
+2599(necessitates)X
+3004(forcing)X
+3262(dirty)X
+3439(pages)X
+3648(at)X
+3732(commit)X
+4002(time.)X
+4210(As)X
+555 4446(mentioned)N
+913(above,)X
+1145(forcing)X
+1397(pages)X
+1600(at)X
+1678(commit)X
+1942(is)X
+2015(considered)X
+2383(too)X
+2505(costly.)X
+755 4569(If)N
+834(we)X
+953(log)X
+1080(only)X
+1247(after-images,)X
+1694(then)X
+1857(there)X
+2043(is)X
+2121(suf\256cient)X
+2444(information)X
+2847(in)X
+2934(the)X
+3057(log)X
+3184(to)X
+3271(allow)X
+3474(us)X
+3570(to)X
+3657(redo)X
+3825(the)X
+3947(transaction)X
+555 4659(\(go)N
+687(forward)X
+967(to)X
+1054(the)X
+1177(state)X
+1348(represented)X
+1743(by)X
+1847(the)X
+1969(after-image\),)X
+2411(but)X
+2537(we)X
+2655(do)X
+2759(not)X
+2885(have)X
+3061(the)X
+3183(information)X
+3585(required)X
+3877(to)X
+3963(undo)X
+4147(tran-)X
+555 4749(sactions)N
+845(which)X
+1073(aborted)X
+1346(after)X
+1526(dirty)X
+1709(pages)X
+1924(were)X
+2113(written)X
+2372(to)X
+2466(disk.)X
+2670(Therefore,)X
+3039(logging)X
+3314(only)X
+3487(after-images)X
+3920(necessitates)X
+555 4839(holding)N
+819(all)X
+919(dirty)X
+1090(buffers)X
+1338(in)X
+1420(main)X
+1600(memory)X
+1887(until)X
+2053(commit)X
+2317(or)X
+2404(writing)X
+2655(them)X
+2835(to)X
+2917(a)X
+2973(temporary)X
+3323(\256le.)X
+755 4962(Since)N
+956(neither)X
+1202(constraint)X
+1541(\(forcing)X
+1823(pages)X
+2029(on)X
+2132(commit)X
+2399(or)X
+2489(buffering)X
+2811(pages)X
+3016(until)X
+3184(commit\))X
+3477(was)X
+3624(feasible,)X
+3916(we)X
+4032(chose)X
+4237(to)X
+555 5052(log)N
+683(both)X
+851(before)X
+1083(and)X
+1225(after)X
+1399(images.)X
+1672(The)X
+1823(only)X
+1991(remaining)X
+2342(consideration)X
+2800(is)X
+2879(when)X
+3079(changes)X
+3363(get)X
+3486(written)X
+3738(to)X
+3825(disk.)X
+4023(Changes)X
+555 5142(affect)N
+764(both)X
+931(data)X
+1090(pages)X
+1298(and)X
+1438(the)X
+1560(log.)X
+1726(If)X
+1804(the)X
+1926(changed)X
+2218(data)X
+2376(page)X
+2552(is)X
+2629(written)X
+2880(before)X
+3110(the)X
+3232(log)X
+3358(page,)X
+3554(and)X
+3694(the)X
+3816(system)X
+4062(crashes)X
+555 5232(before)N
+787(the)X
+911(log)X
+1039(page)X
+1217(is)X
+1296(written,)X
+1569(the)X
+1693(log)X
+1820(will)X
+1969(contain)X
+2230(insuf\256cient)X
+2615(information)X
+3018(to)X
+3105(undo)X
+3290(the)X
+3413(change.)X
+3706(This)X
+3873(violates)X
+4147(tran-)X
+555 5322(saction)N
+803(semantics,)X
+1160(since)X
+1346(some)X
+1536(changed)X
+1825(data)X
+1980(pages)X
+2184(may)X
+2343(not)X
+2466(have)X
+2638(been)X
+2810(written,)X
+3077(and)X
+3213(the)X
+3331(database)X
+3628(cannot)X
+3862(be)X
+3958(restored)X
+4237(to)X
+555 5412(its)N
+650(pre-transaction)X
+1152(state.)X
+755 5535(The)N
+914(log)X
+1050(record)X
+1290(describing)X
+1658(an)X
+1768(update)X
+2016(must)X
+2205(be)X
+2315(written)X
+2576(to)X
+2672(stable)X
+2893(storage)X
+3159(before)X
+3398(the)X
+3529(modi\256ed)X
+3846(page.)X
+4071(This)X
+4246(is)X
+3 f
+555 5625(write-ahead)N
+992(logging)X
+1 f
+1240(.)X
+1307(If)X
+1388(log)X
+1517(records)X
+1781(are)X
+1907(safely)X
+2126(written)X
+2380(to)X
+2469(disk,)X
+2649(data)X
+2810(pages)X
+3020(may)X
+3185(be)X
+3288(written)X
+3542(at)X
+3627(any)X
+3770(time)X
+3939(afterwards.)X
+555 5715(This)N
+721(means)X
+950(that)X
+1094(the)X
+1216(only)X
+1382(\256le)X
+1508(that)X
+1652(ever)X
+1815(needs)X
+2022(to)X
+2108(be)X
+2208(forced)X
+2438(to)X
+2524(disk)X
+2681(is)X
+2758(the)X
+2880(log.)X
+3046(Since)X
+3248(the)X
+3370(log)X
+3495(is)X
+3571(append-only,)X
+4015(modi\256ed)X
+
+4 p
+%%Page: 4 4
+10 s 10 xH 0 xS 1 f
+3 f
+1 f
+555 630(pages)N
+760(always)X
+1005(appear)X
+1242(at)X
+1322(the)X
+1442(end)X
+1580(and)X
+1718(may)X
+1878(be)X
+1976(written)X
+2224(to)X
+2307(disk)X
+2461(ef\256ciently)X
+2807(in)X
+2890(any)X
+3027(\256le)X
+3150(system)X
+3393(that)X
+3534(favors)X
+3756(sequential)X
+4102(order-)X
+555 720(ing)N
+677(\()X
+2 f
+704(e.g.)X
+1 f
+820(,)X
+860(FFS,)X
+1032(log-structured)X
+1502(\256le)X
+1624(system,)X
+1886(or)X
+1973(an)X
+2069(extent-based)X
+2495(system\).)X
+3 f
+555 906(3.1.2.)N
+775(Concurrency)X
+1245(Control)X
+1 f
+755 1029(The)N
+918(concurrency)X
+1354(control)X
+1619(protocol)X
+1923(is)X
+2013(responsible)X
+2415(for)X
+2546(maintaining)X
+2965(consistency)X
+3376(in)X
+3475(the)X
+3610(presence)X
+3929(of)X
+4033(multiple)X
+555 1119(accesses.)N
+897(There)X
+1114(are)X
+1242(several)X
+1499(alternative)X
+1867(solutions)X
+2183(such)X
+2358(as)X
+2453(locking,)X
+2741(optimistic)X
+3088(concurrency)X
+3514(control)X
+3769([KUNG81],)X
+4183(and)X
+555 1209(timestamp)N
+912(ordering)X
+1208([BERN80].)X
+1619(Since)X
+1821(optimistic)X
+2164(methods)X
+2459(and)X
+2599(timestamp)X
+2956(ordering)X
+3252(are)X
+3374(generally)X
+3696(more)X
+3884(complex)X
+4183(and)X
+555 1299(restrict)N
+804(concurrency)X
+1228(without)X
+1498(eliminating)X
+1888(starvation)X
+2230(or)X
+2323(deadlocks,)X
+2690(we)X
+2810(chose)X
+3018(two-phase)X
+3373(locking)X
+3638(\(2PL\).)X
+3890(Strict)X
+4088(2PL)X
+4246(is)X
+555 1389(suboptimal)N
+935(for)X
+1054(certain)X
+1297(data)X
+1455(structures)X
+1791(such)X
+1962(as)X
+2053(B-trees)X
+2309(because)X
+2588(it)X
+2656(can)X
+2792(limit)X
+2966(concurrency,)X
+3408(so)X
+3503(we)X
+3621(use)X
+3752(a)X
+3812(special)X
+4059(locking)X
+555 1479(protocol)N
+842(based)X
+1045(on)X
+1145(one)X
+1281(described)X
+1609(in)X
+1691([LEHM81].)X
+755 1602(The)N
+901(B-tree)X
+1123(locking)X
+1384(protocol)X
+1672(we)X
+1787(implemented)X
+2226(releases)X
+2502(locks)X
+2691(at)X
+2769(internal)X
+3034(nodes)X
+3241(in)X
+3323(the)X
+3441(tree)X
+3582(as)X
+3669(it)X
+3733(descends.)X
+4083(A)X
+4161(lock)X
+555 1692(on)N
+658(an)X
+757(internal)X
+1025(page)X
+1200(is)X
+1276(always)X
+1522(released)X
+1808(before)X
+2036(a)X
+2094(lock)X
+2254(on)X
+2356(its)X
+2453(child)X
+2635(is)X
+2710(obtained)X
+3008(\(that)X
+3177(is,)X
+3272(locks)X
+3463(are)X
+3584(not)X
+3 f
+3708(coupled)X
+1 f
+3996([BAY77])X
+555 1782(during)N
+786(descent\).)X
+1116(When)X
+1330(a)X
+1388(leaf)X
+1531(\(or)X
+1647(internal\))X
+1941(page)X
+2115(is)X
+2190(split,)X
+2369(a)X
+2427(write)X
+2614(lock)X
+2774(is)X
+2849(acquired)X
+3148(on)X
+3250(the)X
+3370(parent)X
+3593(before)X
+3821(the)X
+3941(lock)X
+4100(on)X
+4201(the)X
+555 1872(just-split)N
+855(page)X
+1028(is)X
+1102(released)X
+1387(\(locks)X
+1604(are)X
+3 f
+1724(coupled)X
+1 f
+2011(during)X
+2241(ascent\).)X
+2530(Write)X
+2734(locks)X
+2924(on)X
+3025(internal)X
+3291(pages)X
+3495(are)X
+3615(released)X
+3899(immediately)X
+555 1962(after)N
+723(the)X
+841(page)X
+1013(is)X
+1086(updated,)X
+1380(but)X
+1502(locks)X
+1691(on)X
+1791(leaf)X
+1932(pages)X
+2135(are)X
+2254(held)X
+2412(until)X
+2578(the)X
+2696(end)X
+2832(of)X
+2919(the)X
+3037(transaction.)X
+755 2085(Since)N
+964(locks)X
+1164(are)X
+1294(released)X
+1589(during)X
+1828(descent,)X
+2119(the)X
+2247(structure)X
+2558(of)X
+2655(the)X
+2783(tree)X
+2934(may)X
+3102(change)X
+3360(above)X
+3582(a)X
+3648(node)X
+3834(being)X
+4042(used)X
+4219(by)X
+555 2175(some)N
+752(process.)X
+1061(If)X
+1143(that)X
+1291(process)X
+1560(must)X
+1743(later)X
+1914(ascend)X
+2161(the)X
+2287(tree)X
+2435(because)X
+2717(of)X
+2811(a)X
+2874(page)X
+3053(split,)X
+3237(any)X
+3380(such)X
+3554(change)X
+3809(must)X
+3991(not)X
+4120(cause)X
+555 2265(confusion.)N
+938(We)X
+1077(use)X
+1211(the)X
+1336(technique)X
+1675(described)X
+2010(in)X
+2099([LEHM81])X
+2487(which)X
+2710(exploits)X
+2989(the)X
+3113(ordering)X
+3411(of)X
+3504(data)X
+3664(on)X
+3770(a)X
+3832(B-tree)X
+4059(page)X
+4237(to)X
+555 2355(guarantee)N
+888(that)X
+1028(no)X
+1128(process)X
+1389(ever)X
+1548(gets)X
+1697(lost)X
+1832(as)X
+1919(a)X
+1975(result)X
+2173(of)X
+2260(internal)X
+2525(page)X
+2697(updates)X
+2962(made)X
+3156(by)X
+3256(other)X
+3441(processes.)X
+755 2478(If)N
+836(a)X
+899(transaction)X
+1278(that)X
+1425(updates)X
+1697(a)X
+1760(B-tree)X
+1988(aborts,)X
+2231(the)X
+2356(user-visible)X
+2757(changes)X
+3043(to)X
+3131(the)X
+3255(tree)X
+3402(must)X
+3583(be)X
+3685(rolled)X
+3898(back.)X
+4116(How-)X
+555 2568(ever,)N
+735(changes)X
+1015(to)X
+1097(the)X
+1215(internal)X
+1480(nodes)X
+1687(of)X
+1774(the)X
+1892(tree)X
+2033(need)X
+2205(not)X
+2327(be)X
+2423(rolled)X
+2630(back,)X
+2822(since)X
+3007(these)X
+3192(pages)X
+3395(contain)X
+3651(no)X
+3751(user-visible)X
+4145(data.)X
+555 2658(When)N
+771(rolling)X
+1008(back)X
+1184(a)X
+1244(transaction,)X
+1640(we)X
+1758(roll)X
+1893(back)X
+2069(all)X
+2173(leaf)X
+2318(page)X
+2494(updates,)X
+2783(but)X
+2909(no)X
+3013(internal)X
+3281(insertions)X
+3615(or)X
+3705(page)X
+3880(splits.)X
+4111(In)X
+4201(the)X
+555 2748(worst)N
+759(case,)X
+944(this)X
+1085(will)X
+1235(leave)X
+1431(a)X
+1493(leaf)X
+1640(page)X
+1818(less)X
+1964(than)X
+2128(half)X
+2279(full.)X
+2456(This)X
+2624(may)X
+2788(cause)X
+2993(poor)X
+3166(space)X
+3371(utilization,)X
+3741(but)X
+3869(does)X
+4042(not)X
+4170(lose)X
+555 2838(user)N
+709(data.)X
+755 2961(Holding)N
+1038(locks)X
+1228(on)X
+1329(leaf)X
+1471(pages)X
+1675(until)X
+1842(transaction)X
+2215(commit)X
+2480(guarantees)X
+2845(that)X
+2986(no)X
+3087(other)X
+3273(process)X
+3535(can)X
+3668(insert)X
+3866(or)X
+3953(delete)X
+4165(data)X
+555 3051(that)N
+711(has)X
+854(been)X
+1042(touched)X
+1332(by)X
+1448(this)X
+1598(process.)X
+1914(Rolling)X
+2188(back)X
+2375(insertions)X
+2721(and)X
+2872(deletions)X
+3196(on)X
+3311(leaf)X
+3467(pages)X
+3685(guarantees)X
+4064(that)X
+4219(no)X
+555 3141(aborted)N
+819(updates)X
+1087(are)X
+1209(ever)X
+1371(visible)X
+1607(to)X
+1692(other)X
+1880(transactions.)X
+2326(Leaving)X
+2612(page)X
+2787(splits)X
+2978(intact)X
+3179(permits)X
+3442(us)X
+3536(to)X
+3621(release)X
+3867(internal)X
+4134(write)X
+555 3231(locks)N
+744(early.)X
+965(Thus)X
+1145(transaction)X
+1517(semantics)X
+1853(are)X
+1972(preserved,)X
+2325(and)X
+2461(locks)X
+2650(are)X
+2769(held)X
+2927(for)X
+3041(shorter)X
+3284(periods.)X
+755 3354(The)N
+901(extra)X
+1083(complexity)X
+1464(introduced)X
+1828(by)X
+1929(this)X
+2065(locking)X
+2326(protocol)X
+2614(appears)X
+2881(substantial,)X
+3264(but)X
+3387(it)X
+3452(is)X
+3525(important)X
+3856(for)X
+3970(multi-user)X
+555 3444(execution.)N
+950(The)X
+1118(bene\256ts)X
+1410(of)X
+1520(non-two-phase)X
+2040(locking)X
+2323(on)X
+2446(B-trees)X
+2721(are)X
+2863(well)X
+3044(established)X
+3443(in)X
+3548(the)X
+3689(database)X
+4009(literature)X
+555 3534([BAY77],)N
+899([LEHM81].)X
+1320(If)X
+1394(a)X
+1450(process)X
+1711(held)X
+1869(locks)X
+2058(until)X
+2224(it)X
+2288(committed,)X
+2670(then)X
+2828(a)X
+2884(long-running)X
+3322(update)X
+3556(could)X
+3754(lock)X
+3912(out)X
+4034(all)X
+4134(other)X
+555 3624(transactions)N
+967(by)X
+1076(preventing)X
+1448(any)X
+1593(other)X
+1787(process)X
+2057(from)X
+2241(locking)X
+2509(the)X
+2635(root)X
+2792(page)X
+2972(of)X
+3067(the)X
+3193(tree.)X
+3382(The)X
+3535(B-tree)X
+3764(locking)X
+4032(protocol)X
+555 3714(described)N
+884(above)X
+1096(guarantees)X
+1460(that)X
+1600(locks)X
+1789(on)X
+1889(internal)X
+2154(pages)X
+2357(are)X
+2476(held)X
+2634(for)X
+2748(extremely)X
+3089(short)X
+3269(periods,)X
+3545(thereby)X
+3806(increasing)X
+4156(con-)X
+555 3804(currency.)N
+3 f
+555 3990(3.1.3.)N
+775(Management)X
+1245(of)X
+1332(Shared)X
+1596(Data)X
+1 f
+755 4113(Database)N
+1075(systems)X
+1353(permit)X
+1587(many)X
+1790(users)X
+1980(to)X
+2067(examine)X
+2364(and)X
+2505(update)X
+2744(the)X
+2866(same)X
+3055(data)X
+3213(concurrently.)X
+3683(In)X
+3774(order)X
+3968(to)X
+4054(provide)X
+555 4203(this)N
+702(concurrent)X
+1078(access)X
+1316(and)X
+1464(enforce)X
+1738(the)X
+1868(write-ahead)X
+2280(logging)X
+2556(protocol)X
+2855(described)X
+3195(in)X
+3289(section)X
+3548(3.1.1,)X
+3759(we)X
+3884(use)X
+4022(a)X
+4089(shared)X
+555 4293(memory)N
+848(buffer)X
+1071(manager.)X
+1414(Not)X
+1559(only)X
+1726(does)X
+1898(this)X
+2038(provide)X
+2308(the)X
+2431(guarantees)X
+2800(we)X
+2919(require,)X
+3192(but)X
+3319(a)X
+3380(user-level)X
+3722(buffer)X
+3944(manager)X
+4246(is)X
+555 4383(frequently)N
+916(faster)X
+1126(than)X
+1295(using)X
+1498(the)X
+1626(\256le)X
+1758(system)X
+2010(buffer)X
+2237(cache.)X
+2491(Reads)X
+2717(or)X
+2814(writes)X
+3040(involving)X
+3376(the)X
+3504(\256le)X
+3636(system)X
+3888(buffer)X
+4115(cache)X
+555 4473(often)N
+746(require)X
+1000(copying)X
+1284(data)X
+1444(between)X
+1738(user)X
+1898(and)X
+2040(kernel)X
+2266(space)X
+2470(while)X
+2673(a)X
+2734(user-level)X
+3076(buffer)X
+3298(manager)X
+3600(can)X
+3737(return)X
+3954(pointers)X
+4237(to)X
+555 4563(data)N
+709(pages)X
+912(directly.)X
+1217(Additionally,)X
+1661(if)X
+1730(more)X
+1915(than)X
+2073(one)X
+2209(process)X
+2470(uses)X
+2628(the)X
+2746(same)X
+2931(page,)X
+3123(then)X
+3281(fewer)X
+3485(copies)X
+3710(may)X
+3868(be)X
+3964(required.)X
+3 f
+555 4749(3.2.)N
+715(Module)X
+997(Architecture)X
+1 f
+755 4872(The)N
+913(preceding)X
+1262(sections)X
+1552(described)X
+1892(modules)X
+2195(for)X
+2321(managing)X
+2669(the)X
+2799(transaction)X
+3183(log,)X
+3337(locks,)X
+3558(and)X
+3706(a)X
+3774(cache)X
+3990(of)X
+4089(shared)X
+555 4962(buffers.)N
+847(In)X
+938(addition,)X
+1244(we)X
+1362(need)X
+1538(to)X
+1624(provide)X
+1893(functionality)X
+2326(for)X
+2444(transaction)X
+2 f
+2819(begin)X
+1 f
+2997(,)X
+2 f
+3040(commit)X
+1 f
+3276(,)X
+3319(and)X
+2 f
+3458(abort)X
+1 f
+3654(processing,)X
+4040(necessi-)X
+555 5052(tating)N
+769(a)X
+837(transaction)X
+1221(manager.)X
+1570(In)X
+1669(order)X
+1871(to)X
+1965(arbitrate)X
+2265(concurrent)X
+2641(access)X
+2879(to)X
+2973(locks)X
+3173(and)X
+3320(buffers,)X
+3599(we)X
+3724(include)X
+3991(a)X
+4058(process)X
+555 5142(management)N
+995(module)X
+1264(which)X
+1489(manages)X
+1799(a)X
+1864(collection)X
+2209(of)X
+2305(semaphores)X
+2713(used)X
+2889(to)X
+2980(block)X
+3187(and)X
+3332(release)X
+3585(processes.)X
+3962(Finally,)X
+4237(in)X
+555 5232(order)N
+752(to)X
+841(provide)X
+1113(a)X
+1176(simple,)X
+1436(standard)X
+1735(interface)X
+2044(we)X
+2165(have)X
+2344(modi\256ed)X
+2655(the)X
+2780(database)X
+3084(access)X
+3317(routines)X
+3602(\()X
+3 f
+3629(db)X
+1 f
+3717(\(3\)\).)X
+3904(For)X
+4041(the)X
+4165(pur-)X
+555 5322(poses)N
+758(of)X
+850(this)X
+990(paper)X
+1194(we)X
+1313(call)X
+1453(the)X
+1575(modi\256ed)X
+1883(package)X
+2171(the)X
+3 f
+2293(Record)X
+2567(Manager)X
+1 f
+2879(.)X
+2943(Figure)X
+3176(one)X
+3316(shows)X
+3540(the)X
+3662(main)X
+3846(interfaces)X
+4183(and)X
+555 5412(architecture)N
+955(of)X
+1042(LIBTP.)X
+
+5 p
+%%Page: 5 5
+10 s 10 xH 0 xS 1 f
+3 f
+1 f
+11 s
+1851 1520(log_commit)N
+2764 2077(buf_unpin)N
+2764 1987(buf_get)N
+3633 1408(buf_unpin)N
+3633 1319(buf_pin)N
+3633 1230(buf_get)N
+3 f
+17 s
+1163 960(Txn)N
+1430(M)X
+1559(anager)X
+2582(Record)X
+3040(M)X
+3169(anager)X
+1 Dt
+2363 726 MXY
+0 355 Dl
+1426 0 Dl
+0 -355 Dl
+-1426 0 Dl
+3255 1616 MXY
+0 535 Dl
+534 0 Dl
+0 -535 Dl
+-534 0 Dl
+2185 MX
+0 535 Dl
+535 0 Dl
+0 -535 Dl
+-535 0 Dl
+1116 MX
+0 535 Dl
+534 0 Dl
+0 -535 Dl
+-534 0 Dl
+726 MY
+0 355 Dl
+891 0 Dl
+0 -355 Dl
+-891 0 Dl
+1 f
+11 s
+2207 1297(lock)N
+2564 1386(log)N
+865(unlock_all)X
+1851 1609(log_unroll)N
+1650 2508 MXY
+0 178 Dl
+1605 0 Dl
+0 -178 Dl
+-1605 0 Dl
+1294 1616 MXY
+19 -30 Dl
+-19 11 Dl
+-20 -11 Dl
+20 30 Dl
+0 -535 Dl
+2319 2508 MXY
+-22 -30 Dl
+4 23 Dl
+-18 14 Dl
+36 -7 Dl
+-936 -357 Dl
+3277 2455(sleep_on)N
+1405 1616 MXY
+36 4 Dl
+-18 -13 Dl
+1 -22 Dl
+-19 31 Dl
+1070 -535 Dl
+2631 2508 MXY
+36 6 Dl
+-18 -14 Dl
+3 -22 Dl
+-21 30 Dl
+891 -357 Dl
+1426 2455(sleep_on)N
+3255 1884 MXY
+-31 -20 Dl
+11 20 Dl
+-11 19 Dl
+31 -19 Dl
+-535 0 Dl
+1554 2366(wake)N
+3277(wake)X
+2185 1884 MXY
+-31 -20 Dl
+12 20 Dl
+-12 19 Dl
+31 -19 Dl
+-356 0 Dl
+0 -803 Dl
+3 f
+17 s
+1236 1851(Lock)N
+1118 2030(M)N
+1247(anager)X
+2339 1851(Log)N
+2187 2030(M)N
+2316(anager)X
+3333 1851(Buffer)N
+3257 2030(M)N
+3386(anager)X
+3522 1616 MXY
+20 -30 Dl
+-20 11 Dl
+-20 -11 Dl
+20 30 Dl
+0 -535 Dl
+1950 2654(Process)N
+2424(M)X
+2553(anager)X
+2542 1616 MXY
+19 -30 Dl
+-19 11 Dl
+-20 -11 Dl
+20 30 Dl
+0 -535 Dl
+1 f
+11 s
+2207 1364(unlock)N
+2452 2508 MXY
+20 -31 Dl
+-20 11 Dl
+-19 -11 Dl
+19 31 Dl
+0 -357 Dl
+2497 2322(sleep_on)N
+2497 2233(wake)N
+3 Dt
+-1 Ds
+3 f
+10 s
+1790 2830(Figure)N
+2037(1:)X
+2144(Library)X
+2435(module)X
+2708(interfaces.)X
+1 f
+10 f
+555 3010(h)N
+579(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)X
+3 f
+555 3286(3.2.1.)N
+775(The)X
+928(Log)X
+1081(Manager)X
+1 f
+755 3409(The)N
+3 f
+907(Log)X
+1067(Manager)X
+1 f
+1406(enforces)X
+1706(the)X
+1831(write-ahead)X
+2238(logging)X
+2509(protocol.)X
+2843(Its)X
+2949(primitive)X
+3268(operations)X
+3628(are)X
+2 f
+3753(log)X
+1 f
+3855(,)X
+2 f
+3901(log_commit)X
+1 f
+4279(,)X
+2 f
+555 3499(log_read)N
+1 f
+844(,)X
+2 f
+889(log_roll)X
+1 f
+1171(and)X
+2 f
+1312(log_unroll)X
+1 f
+1649(.)X
+1714(The)X
+2 f
+1864(log)X
+1 f
+1991(call)X
+2132(performs)X
+2447(a)X
+2508(buffered)X
+2806(write)X
+2996(of)X
+3088(the)X
+3211(speci\256ed)X
+3520(log)X
+3646(record)X
+3876(and)X
+4016(returns)X
+4263(a)X
+555 3589(unique)N
+809(log)X
+947(sequence)X
+1278(number)X
+1559(\(LSN\).)X
+1840(This)X
+2017(LSN)X
+2203(may)X
+2376(then)X
+2549(be)X
+2660(used)X
+2842(to)X
+2939(retrieve)X
+3220(a)X
+3291(record)X
+3532(from)X
+3723(the)X
+3856(log)X
+3993(using)X
+4201(the)X
+2 f
+555 3679(log_read)N
+1 f
+865(call.)X
+1042(The)X
+2 f
+1188(log)X
+1 f
+1311(interface)X
+1614(knows)X
+1844(very)X
+2008(little)X
+2175(about)X
+2374(the)X
+2493(internal)X
+2759(format)X
+2993(of)X
+3080(the)X
+3198(log)X
+3320(records)X
+3577(it)X
+3641(receives.)X
+3965(Rather,)X
+4219(all)X
+555 3769(log)N
+681(records)X
+942(are)X
+1065 0.4028(referenced)AX
+1430(by)X
+1534(a)X
+1594(header)X
+1833(structure,)X
+2158(a)X
+2218(log)X
+2344(record)X
+2574(type,)X
+2756(and)X
+2896(a)X
+2956(character)X
+3276(buffer)X
+3497(containing)X
+3859(the)X
+3981(data)X
+4138(to)X
+4223(be)X
+555 3859(logged.)N
+834(The)X
+980(log)X
+1103(record)X
+1330(type)X
+1489(is)X
+1563(used)X
+1731(to)X
+1814(call)X
+1951(the)X
+2070(appropriate)X
+2457(redo)X
+2621(and)X
+2758(undo)X
+2939(routines)X
+3217(during)X
+2 f
+3446(abort)X
+1 f
+3639(and)X
+2 f
+3775(commit)X
+1 f
+4031(process-)X
+555 3949(ing.)N
+721(While)X
+941(we)X
+1059(have)X
+1235(used)X
+1406(the)X
+3 f
+1528(Log)X
+1684(Manager)X
+1 f
+2019(to)X
+2104(provide)X
+2372(before)X
+2601(and)X
+2740(after)X
+2911(image)X
+3130(logging,)X
+3417(it)X
+3484(may)X
+3645(also)X
+3797(be)X
+3896(used)X
+4066(for)X
+4183(any)X
+555 4039(of)N
+642(the)X
+760(logging)X
+1024(algorithms)X
+1386(discussed.)X
+755 4162(The)N
+2 f
+905(log_commit)X
+1 f
+1308(operation)X
+1636(behaves)X
+1920(exactly)X
+2177(like)X
+2322(the)X
+2 f
+2445(log)X
+1 f
+2572(operation)X
+2900(but)X
+3026(guarantees)X
+3394(that)X
+3538(the)X
+3660(log)X
+3786(has)X
+3917(been)X
+4093(forced)X
+555 4252(to)N
+643(disk)X
+802(before)X
+1034(returning.)X
+1394(A)X
+1478(discussion)X
+1837(of)X
+1930(our)X
+2063(commit)X
+2333(strategy)X
+2613(appears)X
+2884(in)X
+2971(the)X
+3094(implementation)X
+3621(section)X
+3873(\(section)X
+4152(4.2\).)X
+2 f
+555 4342(Log_unroll)N
+1 f
+935(reads)X
+1126(log)X
+1249(records)X
+1507(from)X
+1684(the)X
+1803(log,)X
+1946(following)X
+2278(backward)X
+2611(transaction)X
+2983(pointers)X
+3261(and)X
+3397(calling)X
+3635(the)X
+3753(appropriate)X
+4139(undo)X
+555 4432(routines)N
+839(to)X
+927(implement)X
+1295(transaction)X
+1673(abort.)X
+1904(In)X
+1997(a)X
+2059(similar)X
+2307(manner,)X
+2 f
+2594(log_roll)X
+1 f
+2877(reads)X
+3073(log)X
+3201(records)X
+3464(sequentially)X
+3877(forward,)X
+4178(cal-)X
+555 4522(ling)N
+699(the)X
+817(appropriate)X
+1203(redo)X
+1366(routines)X
+1644(to)X
+1726(recover)X
+1988(committed)X
+2350(transactions)X
+2753(after)X
+2921(a)X
+2977(system)X
+3219(crash.)X
+3 f
+555 4708(3.2.2.)N
+775(The)X
+928(Buffer)X
+1171(Manager)X
+1 f
+755 4831(The)N
+3 f
+912(Buffer)X
+1167(Manager)X
+1 f
+1511(uses)X
+1681(a)X
+1749(pool)X
+1923(of)X
+2022(shared)X
+2264(memory)X
+2563(to)X
+2657(provide)X
+2934(a)X
+3002(least-recently-used)X
+3641(\(LRU\))X
+3886(block)X
+4095(cache.)X
+555 4921(Although)N
+886(the)X
+1013(current)X
+1270(library)X
+1513(provides)X
+1818(an)X
+1923(LRU)X
+2112(cache,)X
+2345(it)X
+2418(would)X
+2647(be)X
+2752(simple)X
+2994(to)X
+3085(add)X
+3229(alternate)X
+3534(replacement)X
+3955(policies)X
+4232(as)X
+555 5011(suggested)N
+903(by)X
+1015([CHOU85])X
+1408(or)X
+1507(to)X
+1601(provide)X
+1878(multiple)X
+2176(buffer)X
+2405(pools)X
+2610(with)X
+2784(different)X
+3092(policies.)X
+3412(Transactions)X
+3853(request)X
+4116(pages)X
+555 5101(from)N
+736(the)X
+859(buffer)X
+1081(manager)X
+1383(and)X
+1524(keep)X
+1701(them)X
+3 f
+1886(pinned)X
+1 f
+2145(to)X
+2232(ensure)X
+2466(that)X
+2610(they)X
+2772(are)X
+2895(not)X
+3021(written)X
+3272(to)X
+3358(disk)X
+3515(while)X
+3717(they)X
+3879(are)X
+4002(in)X
+4088(a)X
+4148(logi-)X
+555 5191(cally)N
+732(inconsistent)X
+1135(state.)X
+1343(When)X
+1556(page)X
+1729(replacement)X
+2143(is)X
+2217(necessary,)X
+2571(the)X
+3 f
+2689(Buffer)X
+2932(Manager)X
+1 f
+3264(\256nds)X
+3439(an)X
+3535(unpinned)X
+3853(page)X
+4025(and)X
+4161(then)X
+555 5281(checks)N
+794(with)X
+956(the)X
+3 f
+1074(Log)X
+1227(Manager)X
+1 f
+1559(to)X
+1641(ensure)X
+1871(that)X
+2011(the)X
+2129(write-ahead)X
+2529(protocol)X
+2816(is)X
+2889(enforced.)X
+3 f
+555 5467(3.2.3.)N
+775(The)X
+928(Lock)X
+1121(Manager)X
+1 f
+755 5590(The)N
+3 f
+901(Lock)X
+1095(Manager)X
+1 f
+1428(supports)X
+1720(general)X
+1978(purpose)X
+2253(locking)X
+2514(\(single)X
+2753(writer,)X
+2986(multiple)X
+3273(readers\))X
+3553(which)X
+3769(is)X
+3842(currently)X
+4152(used)X
+555 5680(to)N
+638(provide)X
+904(two-phase)X
+1254(locking)X
+1514(and)X
+1650(high)X
+1812(concurrency)X
+2230(B-tree)X
+2451(locking.)X
+2751(However,)X
+3086(the)X
+3204(general)X
+3461(purpose)X
+3735(nature)X
+3956(of)X
+4043(the)X
+4161(lock)X
+
+6 p
+%%Page: 6 6
+10 s 10 xH 0 xS 1 f
+3 f
+1 f
+555 630(manager)N
+857(provides)X
+1158(the)X
+1281(ability)X
+1510(to)X
+1597(support)X
+1862(a)X
+1923(variety)X
+2171(of)X
+2263(locking)X
+2528(protocols.)X
+2890(Currently,)X
+3241(all)X
+3345(locks)X
+3538(are)X
+3661(issued)X
+3885(at)X
+3967(the)X
+4089(granu-)X
+555 720(larity)N
+747(of)X
+837(a)X
+896(page)X
+1071(\(the)X
+1219(size)X
+1367(of)X
+1457(a)X
+1516(buffer)X
+1736(in)X
+1821(the)X
+1942(buffer)X
+2161(pool\))X
+2352(which)X
+2570(is)X
+2645(identi\256ed)X
+2969(by)X
+3071(two)X
+3213(4-byte)X
+3440(integers)X
+3716(\(a)X
+3801(\256le)X
+3925(id)X
+4009(and)X
+4147(page)X
+555 810(number\).)N
+898(This)X
+1071(provides)X
+1378(the)X
+1507(necessary)X
+1851(information)X
+2259(to)X
+2351(extend)X
+2595(the)X
+3 f
+2723(Lock)X
+2926(Manager)X
+1 f
+3268(to)X
+3360(perform)X
+3649(hierarchical)X
+4059(locking)X
+555 900([GRAY76].)N
+982(The)X
+1133(current)X
+1387(implementation)X
+1915(does)X
+2088(not)X
+2216(support)X
+2482(locks)X
+2677(at)X
+2760(other)X
+2950(granularities)X
+3376(and)X
+3517(does)X
+3689(not)X
+3816(promote)X
+4108(locks;)X
+555 990(these)N
+740(are)X
+859(obvious)X
+1132(future)X
+1344(additions)X
+1657(to)X
+1739(the)X
+1857(system.)X
+755 1113(If)N
+831(an)X
+929(incoming)X
+1253(lock)X
+1413(request)X
+1667(cannot)X
+1903(be)X
+2001(granted,)X
+2284(the)X
+2404(requesting)X
+2760(process)X
+3023(is)X
+3098(queued)X
+3352(for)X
+3467(the)X
+3586(lock)X
+3745(and)X
+3882(descheduled.)X
+555 1203(When)N
+769(a)X
+827(lock)X
+987(is)X
+1062(released,)X
+1368(the)X
+1488(wait)X
+1647(queue)X
+1860(is)X
+1934(traversed)X
+2250(and)X
+2387(any)X
+2524(newly)X
+2741(compatible)X
+3118(locks)X
+3308(are)X
+3428(granted.)X
+3730(Locks)X
+3947(are)X
+4067(located)X
+555 1293(via)N
+680(a)X
+743(\256le)X
+872(and)X
+1015(page)X
+1194(hash)X
+1368(table)X
+1551(and)X
+1694(are)X
+1820(chained)X
+2097(both)X
+2266(by)X
+2373(object)X
+2595(and)X
+2737(by)X
+2843(transaction,)X
+3241(facilitating)X
+3614(rapid)X
+3805(traversal)X
+4108(of)X
+4201(the)X
+555 1383(lock)N
+713(table)X
+889(during)X
+1118(transaction)X
+1490(commit)X
+1754(and)X
+1890(abort.)X
+755 1506(The)N
+907(primary)X
+1188(interfaces)X
+1528(to)X
+1617(the)X
+1742(lock)X
+1907(manager)X
+2211(are)X
+2 f
+2337(lock)X
+1 f
+2471(,)X
+2 f
+2518(unlock)X
+1 f
+2732(,)X
+2779(and)X
+2 f
+2922(lock_unlock_all)X
+1 f
+3434(.)X
+2 f
+3500(Lock)X
+1 f
+3682(obtains)X
+3939(a)X
+4001(new)X
+4161(lock)X
+555 1596(for)N
+680(a)X
+747(speci\256c)X
+1023(object.)X
+1290(There)X
+1509(are)X
+1638(also)X
+1797(two)X
+1947(variants)X
+2231(of)X
+2328(the)X
+2 f
+2456(lock)X
+1 f
+2620(request,)X
+2 f
+2902(lock_upgrade)X
+1 f
+3373(and)X
+2 f
+3519(lock_downgrade)X
+1 f
+4053(,)X
+4103(which)X
+555 1686(allow)N
+755(the)X
+875(caller)X
+1076(to)X
+1160(atomically)X
+1519(trade)X
+1701(a)X
+1758(lock)X
+1917(of)X
+2005(one)X
+2142(type)X
+2301(for)X
+2416(a)X
+2473(lock)X
+2632(of)X
+2720(another.)X
+2 f
+3022(Unlock)X
+1 f
+3275(releases)X
+3551(a)X
+3608(speci\256c)X
+3874(mode)X
+4073(of)X
+4161(lock)X
+555 1776(on)N
+655(a)X
+711(speci\256c)X
+976(object.)X
+2 f
+1232(Lock_unlock_all)X
+1 f
+1786(releases)X
+2061(all)X
+2161(the)X
+2279(locks)X
+2468(associated)X
+2818(with)X
+2980(a)X
+3036(speci\256c)X
+3301(transaction.)X
+3 f
+555 1962(3.2.4.)N
+775(The)X
+928(Process)X
+1207(Manager)X
+1 f
+755 2085(The)N
+3 f
+900(Process)X
+1179(Manager)X
+1 f
+1511(acts)X
+1656(as)X
+1743(a)X
+1799(user-level)X
+2136(scheduler)X
+2464(to)X
+2546(make)X
+2740(processes)X
+3068(wait)X
+3226(on)X
+3326(unavailable)X
+3716(locks)X
+3905(and)X
+4041(pending)X
+555 2175(buffer)N
+778(cache)X
+988(I/O.)X
+1161(For)X
+1297(each)X
+1470(process,)X
+1756(a)X
+1817(semaphore)X
+2190(is)X
+2268(maintained)X
+2649(upon)X
+2834(which)X
+3055(that)X
+3200(process)X
+3466(waits)X
+3660(when)X
+3859(it)X
+3928(needs)X
+4136(to)X
+4223(be)X
+555 2265(descheduled.)N
+1014(When)X
+1228(a)X
+1286(process)X
+1549(needs)X
+1754(to)X
+1838(be)X
+1936(run,)X
+2084(its)X
+2180(semaphore)X
+2549(is)X
+2623(cleared,)X
+2897(and)X
+3034(the)X
+3153(operating)X
+3477(system)X
+3720(reschedules)X
+4116(it.)X
+4201(No)X
+555 2355(sophisticated)N
+1002(scheduling)X
+1378(algorithm)X
+1718(is)X
+1799(applied;)X
+2085(if)X
+2162(the)X
+2288(lock)X
+2454(for)X
+2576(which)X
+2800(a)X
+2864(process)X
+3133(was)X
+3286(waiting)X
+3554(becomes)X
+3863(available,)X
+4201(the)X
+555 2445(process)N
+824(is)X
+905(made)X
+1107(runnable.)X
+1456(It)X
+1533(would)X
+1761(have)X
+1941(been)X
+2121(possible)X
+2411(to)X
+2501(change)X
+2757(the)X
+2883(kernel's)X
+3170(process)X
+3439(scheduler)X
+3775(to)X
+3865(interact)X
+4134(more)X
+555 2535(ef\256ciently)N
+900(with)X
+1062(the)X
+1180(lock)X
+1338(manager,)X
+1655(but)X
+1777(doing)X
+1979(so)X
+2070(would)X
+2290(have)X
+2462(compromised)X
+2918(our)X
+3045(commitment)X
+3469(to)X
+3551(a)X
+3607(user-level)X
+3944(package.)X
+3 f
+555 2721(3.2.5.)N
+775(The)X
+928(Transaction)X
+1361(Manager)X
+1 f
+755 2844(The)N
+3 f
+901(Transaction)X
+1335(Manager)X
+1 f
+1668(provides)X
+1965(the)X
+2084(standard)X
+2377(interface)X
+2680(of)X
+2 f
+2768(txn_begin)X
+1 f
+3084(,)X
+2 f
+3125(txn_commit)X
+1 f
+3499(,)X
+3540(and)X
+2 f
+3676(txn_abort)X
+1 f
+3987(.)X
+4047(It)X
+4116(keeps)X
+555 2934(track)N
+742(of)X
+835(all)X
+941(active)X
+1159(transactions,)X
+1588(assigns)X
+1845(unique)X
+2089(transaction)X
+2467(identi\256ers,)X
+2833(and)X
+2974(directs)X
+3213(the)X
+3336(abort)X
+3526(and)X
+3667(commit)X
+3936(processing.)X
+555 3024(When)N
+772(a)X
+2 f
+833(txn_begin)X
+1 f
+1174(is)X
+1252(issued,)X
+1497(the)X
+3 f
+1620(Transaction)X
+2058(Manager)X
+1 f
+2395(assigns)X
+2651(the)X
+2773(next)X
+2935(available)X
+3249(transaction)X
+3625(identi\256er,)X
+3958(allocates)X
+4263(a)X
+555 3114(per-process)N
+948(transaction)X
+1322(structure)X
+1625(in)X
+1709(shared)X
+1941(memory,)X
+2249(increments)X
+2622(the)X
+2741(count)X
+2940(of)X
+3028(active)X
+3241(transactions,)X
+3665(and)X
+3802(returns)X
+4046(the)X
+4165(new)X
+555 3204(transaction)N
+937(identi\256er)X
+1256(to)X
+1348(the)X
+1476(calling)X
+1724(process.)X
+2034(The)X
+2188(in-memory)X
+2573(transaction)X
+2954(structure)X
+3264(contains)X
+3560(a)X
+3625(pointer)X
+3881(into)X
+4034(the)X
+4161(lock)X
+555 3294(table)N
+734(for)X
+851(locks)X
+1043(held)X
+1204(by)X
+1307(this)X
+1445(transaction,)X
+1840(the)X
+1961(last)X
+2095(log)X
+2220(sequence)X
+2538(number,)X
+2826(a)X
+2885(transaction)X
+3260(state)X
+3430(\()X
+2 f
+3457(idle)X
+1 f
+(,)S
+2 f
+3620(running)X
+1 f
+3873(,)X
+2 f
+3915(aborting)X
+1 f
+4190(,)X
+4232(or)X
+2 f
+555 3384(committing\))N
+1 f
+942(,)X
+982(an)X
+1078(error)X
+1255(code,)X
+1447(and)X
+1583(a)X
+1639(semaphore)X
+2007(identi\256er.)X
+755 3507(At)N
+859(commit,)X
+1147(the)X
+3 f
+1269(Transaction)X
+1706(Manager)X
+1 f
+2042(calls)X
+2 f
+2213(log_commit)X
+1 f
+2615(to)X
+2700(record)X
+2929(the)X
+3050(end)X
+3189(of)X
+3279(transaction)X
+3654(and)X
+3793(to)X
+3878(\257ush)X
+4056(the)X
+4177(log.)X
+555 3597(Then)N
+743(it)X
+810(directs)X
+1047(the)X
+3 f
+1168(Lock)X
+1364(Manager)X
+1 f
+1699(to)X
+1784(release)X
+2031(all)X
+2134(locks)X
+2325(associated)X
+2677(with)X
+2841(the)X
+2961(given)X
+3161(transaction.)X
+3575(If)X
+3651(a)X
+3709(transaction)X
+4083(aborts,)X
+555 3687(the)N
+3 f
+680(Transaction)X
+1120(Manager)X
+1 f
+1459(calls)X
+1633(on)X
+2 f
+1739(log_unroll)X
+1 f
+2102(to)X
+2190(read)X
+2355(the)X
+2479(transaction's)X
+2915(log)X
+3043(records)X
+3306(and)X
+3448(undo)X
+3634(any)X
+3776(modi\256cations)X
+4237(to)X
+555 3777(the)N
+673(database.)X
+1010(As)X
+1119(in)X
+1201(the)X
+1319(commit)X
+1583(case,)X
+1762(it)X
+1826(then)X
+1984(calls)X
+2 f
+2151(lock_unlock_all)X
+1 f
+2683(to)X
+2765(release)X
+3009(the)X
+3127(transaction's)X
+3557(locks.)X
+3 f
+555 3963(3.2.6.)N
+775(The)X
+928(Record)X
+1198(Manager)X
+1 f
+755 4086(The)N
+3 f
+919(Record)X
+1208(Manager)X
+1 f
+1559(supports)X
+1869(the)X
+2006(abstraction)X
+2397(of)X
+2503(reading)X
+2783(and)X
+2938(writing)X
+3208(records)X
+3484(to)X
+3585(a)X
+3660(database.)X
+3996(We)X
+4147(have)X
+555 4176(modi\256ed)N
+861(the)X
+981(the)X
+1101(database)X
+1399(access)X
+1626(routines)X
+3 f
+1905(db)X
+1 f
+1993(\(3\))X
+2108([BSD91])X
+2418(to)X
+2501(call)X
+2638(the)X
+2757(log,)X
+2900(lock,)X
+3079(and)X
+3216(buffer)X
+3434(managers.)X
+3803(In)X
+3891(order)X
+4082(to)X
+4165(pro-)X
+555 4266(vide)N
+718(functionality)X
+1152(to)X
+1239(perform)X
+1523(undo)X
+1708(and)X
+1849(redo,)X
+2037(the)X
+3 f
+2160(Record)X
+2434(Manager)X
+1 f
+2770(de\256nes)X
+3021(a)X
+3081(collection)X
+3421(of)X
+3512(log)X
+3638(record)X
+3868(types)X
+4061(and)X
+4201(the)X
+555 4356(associated)N
+920(undo)X
+1115(and)X
+1266(redo)X
+1444(routines.)X
+1777(The)X
+3 f
+1937(Log)X
+2105(Manager)X
+1 f
+2452(performs)X
+2777(a)X
+2848(table)X
+3039(lookup)X
+3296(on)X
+3411(the)X
+3543(record)X
+3783(type)X
+3955(to)X
+4051(call)X
+4201(the)X
+555 4446(appropriate)N
+951(routines.)X
+1299(For)X
+1440(example,)X
+1762(the)X
+1890(B-tree)X
+2121(access)X
+2356(method)X
+2625(requires)X
+2913(two)X
+3062(log)X
+3193(record)X
+3428(types:)X
+3648(insert)X
+3855(and)X
+4000(delete.)X
+4241(A)X
+555 4536(replace)N
+808(operation)X
+1131(is)X
+1204(implemented)X
+1642(as)X
+1729(a)X
+1785(delete)X
+1997(followed)X
+2302(by)X
+2402(an)X
+2498(insert)X
+2696(and)X
+2832(is)X
+2905(logged)X
+3143(accordingly.)X
+3 f
+555 4722(3.3.)N
+715(Application)X
+1134(Architectures)X
+1 f
+755 4845(The)N
+907(structure)X
+1215(of)X
+1309(LIBTP)X
+1558(allows)X
+1794(application)X
+2177(designers)X
+2507(to)X
+2596(trade)X
+2784(off)X
+2905(performance)X
+3339(and)X
+3481(protection.)X
+3872(Since)X
+4076(a)X
+4138(large)X
+555 4935(portion)N
+810(of)X
+901(LIBTP's)X
+1205(functionality)X
+1638(is)X
+1715(provided)X
+2024(by)X
+2128(managing)X
+2468(structures)X
+2804(in)X
+2889(shared)X
+3122(memory,)X
+3432(its)X
+3530(structures)X
+3865(are)X
+3987(subject)X
+4237(to)X
+555 5025(corruption)N
+926(by)X
+1043(applications)X
+1467(when)X
+1678(the)X
+1813(library)X
+2064(is)X
+2154(linked)X
+2391(directly)X
+2673(with)X
+2852(the)X
+2987(application.)X
+3420(For)X
+3568(this)X
+3720(reason,)X
+3987(LIBTP)X
+4246(is)X
+555 5115(designed)N
+864(to)X
+950(allow)X
+1152(compilation)X
+1558(into)X
+1706(a)X
+1766(separate)X
+2053(server)X
+2273(process)X
+2537(which)X
+2756(may)X
+2917(be)X
+3016(accessed)X
+3321(via)X
+3442(a)X
+3501(socket)X
+3729(interface.)X
+4094(In)X
+4184(this)X
+555 5205(way)N
+712(LIBTP's)X
+1015(data)X
+1172(structures)X
+1507(are)X
+1629(protected)X
+1951(from)X
+2130(application)X
+2509(code,)X
+2704(but)X
+2829(communication)X
+3349(overhead)X
+3666(is)X
+3741(increased.)X
+4107(When)X
+555 5295(applications)N
+975(are)X
+1107(trusted,)X
+1377(LIBTP)X
+1631(may)X
+1801(be)X
+1909(compiled)X
+2239(directly)X
+2516(into)X
+2672(the)X
+2802(application)X
+3190(providing)X
+3533(improved)X
+3872(performance.)X
+555 5385(Figures)N
+815(two)X
+955(and)X
+1091(three)X
+1272(show)X
+1461(the)X
+1579(two)X
+1719(alternate)X
+2016(application)X
+2392(architectures.)X
+755 5508(There)N
+964(are)X
+1084(potentially)X
+1447(two)X
+1588(modes)X
+1818(in)X
+1901(which)X
+2118(one)X
+2255(might)X
+2462(use)X
+2590(LIBTP)X
+2833(in)X
+2916(a)X
+2972(server)X
+3189(based)X
+3392(architecture.)X
+3832(In)X
+3919(the)X
+4037(\256rst,)X
+4201(the)X
+555 5598(server)N
+778(would)X
+1004(provide)X
+1275(the)X
+1399(capability)X
+1741(to)X
+1829(respond)X
+2109(to)X
+2197(requests)X
+2486(to)X
+2574(each)X
+2747(of)X
+2839(the)X
+2962(low)X
+3107(level)X
+3288(modules)X
+3584(\(lock,)X
+3794(log,)X
+3941(buffer,)X
+4183(and)X
+555 5688(transaction)N
+944(managers\).)X
+1356(Unfortunately,)X
+1863(the)X
+1998(performance)X
+2442(of)X
+2546(such)X
+2730(a)X
+2803(system)X
+3062(is)X
+3152(likely)X
+3371(to)X
+3470(be)X
+3583(blindingly)X
+3947(slow)X
+4134(since)X
+
+7 p
+%%Page: 7 7
+10 s 10 xH 0 xS 1 f
+3 f
+1 f
+1 Dt
+1864 1125 MXY
+15 -26 Dl
+-15 10 Dl
+-14 -10 Dl
+14 26 Dl
+0 -266 Dl
+1315 1125 MXY
+15 -26 Dl
+-15 10 Dl
+-14 -10 Dl
+14 26 Dl
+0 -266 Dl
+3 Dt
+1133 1125 MXY
+0 798 Dl
+931 0 Dl
+0 -798 Dl
+-931 0 Dl
+1 Dt
+1266 1257 MXY
+0 133 Dl
+665 0 Dl
+0 -133 Dl
+-665 0 Dl
+3 f
+8 s
+1513 1351(driver)N
+1502 1617(LIBTP)N
+1266 1390 MXY
+0 400 Dl
+665 0 Dl
+0 -400 Dl
+-665 0 Dl
+3 Dt
+1133 726 MXY
+0 133 Dl
+931 0 Dl
+0 -133 Dl
+-931 0 Dl
+1 f
+1029 1098(txn_abort)N
+964 1015(txn_commit)N
+1018 932(txn_begin)N
+1910 1015(db_ops)N
+3 f
+1308 820(Application)N
+1645(Program)X
+1398 1218(Server)N
+1594(Process)X
+1 f
+1390 986(socket)N
+1569(interface)X
+1 Dt
+1848 967 MXY
+-23 -14 Dl
+8 14 Dl
+-8 15 Dl
+23 -15 Dl
+-50 0 Dl
+1324 MX
+23 15 Dl
+-9 -15 Dl
+9 -14 Dl
+-23 14 Dl
+50 0 Dl
+3 Dt
+2862 859 MXY
+0 1064 Dl
+932 0 Dl
+0 -1064 Dl
+-932 0 Dl
+1 Dt
+3178 1390 MXY
+24 -12 Dl
+-17 0 Dl
+-8 -15 Dl
+1 27 Dl
+150 -265 Dl
+3494 1390 MXY
+0 -27 Dl
+-8 15 Dl
+-16 1 Dl
+24 11 Dl
+-166 -265 Dl
+3 f
+3232 1617(LIBTP)N
+2995 1390 MXY
+0 400 Dl
+666 0 Dl
+0 -400 Dl
+-666 0 Dl
+992 MY
+0 133 Dl
+666 0 Dl
+0 -133 Dl
+-666 0 Dl
+3168 1086(Application)N
+1 f
+2939 1201(txn_begin)N
+2885 1284(txn_commit)N
+2950 1368(txn_abort)N
+3465 1284(db_ops)N
+3 f
+3155 766(Single)N
+3339(Process)X
+3 Dt
+-1 Ds
+811 2100(Figure)N
+1023(2:)X
+1107(Server)X
+1318(Architecture.)X
+1 f
+1727(In)X
+1811(this)X
+1934(con\256guration,)X
+811 2190(the)N
+916(library)X
+1113(is)X
+1183(loaded)X
+1380(into)X
+1507(a)X
+1562(server)X
+1744(process)X
+1962(which)X
+2145(is)X
+2214(ac-)X
+811 2280(cessed)N
+993(via)X
+1087(a)X
+1131(socket)X
+1310(interface.)X
+3 f
+2563 2100(Figure)N
+2803(3:)X
+2914(Single)X
+3140(Process)X
+3403(Architecture.)X
+1 f
+3839(In)X
+3950(this)X
+2563 2190(con\256guration,)N
+2948(the)X
+3053(library)X
+3250(routines)X
+3483(are)X
+3587(loaded)X
+3784(as)X
+3864(part)X
+3990(of)X
+2563 2280(the)N
+2657(application)X
+2957(and)X
+3065(accessed)X
+3303(via)X
+3397(a)X
+3441(subroutine)X
+3727(interface.)X
+10 s
+10 f
+555 2403(h)N
+579(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)X
+1 f
+555 2679(modifying)N
+909(a)X
+966(piece)X
+1157(of)X
+1245(data)X
+1400(would)X
+1621(require)X
+1870(three)X
+2051(or)X
+2138(possibly)X
+2424(four)X
+2578(separate)X
+2862(communications:)X
+3433(one)X
+3569(to)X
+3651(lock)X
+3809(the)X
+3927(data,)X
+4101(one)X
+4237(to)X
+555 2769(obtain)N
+781(the)X
+905(data,)X
+1085(one)X
+1227(to)X
+1315(log)X
+1443(the)X
+1567(modi\256cation,)X
+2017(and)X
+2159(possibly)X
+2451(one)X
+2593(to)X
+2681(transmit)X
+2969(the)X
+3093(modi\256ed)X
+3403(data.)X
+3583(Figure)X
+3817(four)X
+3976(shows)X
+4201(the)X
+555 2859(relative)N
+826(performance)X
+1263(for)X
+1387(retrieving)X
+1728(a)X
+1793(single)X
+2013(record)X
+2248(using)X
+2450(the)X
+2577(record)X
+2812(level)X
+2997(call)X
+3142(versus)X
+3376(using)X
+3578(the)X
+3705(lower)X
+3917(level)X
+4102(buffer)X
+555 2949(management)N
+987(and)X
+1125(locking)X
+1387(calls.)X
+1616(The)X
+1763(2:1)X
+1887(ratio)X
+2056(observed)X
+2367(in)X
+2450(the)X
+2569(single)X
+2781(process)X
+3043(case)X
+3203(re\257ects)X
+3456(the)X
+3575(additional)X
+3916(overhead)X
+4232(of)X
+555 3039(parsing)N
+819(eight)X
+1006(commands)X
+1380(rather)X
+1595(than)X
+1760(one)X
+1903(while)X
+2108(the)X
+2233(3:1)X
+2362(ratio)X
+2536(observed)X
+2853(in)X
+2942(the)X
+3067(client/server)X
+3491(architecture)X
+3898(re\257ects)X
+4157(both)X
+555 3129(the)N
+679(parsing)X
+941(and)X
+1083(the)X
+1207(communication)X
+1731(overheard.)X
+2118(Although)X
+2445(there)X
+2631(may)X
+2794(be)X
+2895(applications)X
+3307(which)X
+3528(could)X
+3731(tolerate)X
+3997(such)X
+4169(per-)X
+555 3219(formance,)N
+904(it)X
+973(seems)X
+1194(far)X
+1309(more)X
+1499(feasible)X
+1774(to)X
+1861(support)X
+2126(a)X
+2187(higher)X
+2417(level)X
+2597(interface,)X
+2923(such)X
+3094(as)X
+3185(that)X
+3329(provided)X
+3638(by)X
+3742(a)X
+3802(query)X
+4009(language)X
+555 3309(\()N
+2 f
+582(e.g.)X
+1 f
+718(SQL)X
+889([SQL86]\).)X
+755 3432(Although)N
+1081(LIBTP)X
+1327(does)X
+1498(not)X
+1624(have)X
+1800(an)X
+1900(SQL)X
+2075(parser,)X
+2316(we)X
+2433(have)X
+2608(built)X
+2777(a)X
+2836(server)X
+3056(application)X
+3435(using)X
+3631(the)X
+3752(toolkit)X
+3983(command)X
+555 3522(language)N
+882(\(TCL\))X
+1124([OUST90].)X
+1544(The)X
+1706(server)X
+1940(supports)X
+2248(a)X
+2321(command)X
+2674(line)X
+2831(interface)X
+3150(similar)X
+3409(to)X
+3508(the)X
+3643(subroutine)X
+4017(interface)X
+555 3612(de\256ned)N
+811(in)X
+3 f
+893(db)X
+1 f
+981(\(3\).)X
+1135(Since)X
+1333(it)X
+1397(is)X
+1470(based)X
+1673(on)X
+1773(TCL,)X
+1964(it)X
+2028(provides)X
+2324(control)X
+2571(structures)X
+2903(as)X
+2990(well.)X
+3 f
+555 3798(4.)N
+655(Implementation)X
+1 f
+3 f
+555 3984(4.1.)N
+715(Locking)X
+1014(and)X
+1162(Deadlock)X
+1502(Detection)X
+1 f
+755 4107(LIBTP)N
+1007(uses)X
+1175(two-phase)X
+1535(locking)X
+1805(for)X
+1929(user)X
+2093(data.)X
+2297(Strictly)X
+2562(speaking,)X
+2897(the)X
+3024(two)X
+3173(phases)X
+3416(in)X
+3507(two-phase)X
+3866(locking)X
+4135(are)X
+4263(a)X
+3 f
+555 4197(grow)N
+1 f
+756(phase,)X
+986(during)X
+1221(which)X
+1443(locks)X
+1638(are)X
+1763(acquired,)X
+2086(and)X
+2228(a)X
+3 f
+2290(shrink)X
+1 f
+2537(phase,)X
+2766(during)X
+3001(which)X
+3223(locks)X
+3418(are)X
+3543(released.)X
+3873(No)X
+3997(lock)X
+4161(may)X
+555 4287(ever)N
+720(be)X
+822(acquired)X
+1124(during)X
+1358(the)X
+1481(shrink)X
+1706(phase.)X
+1954(The)X
+2104(grow)X
+2294(phase)X
+2502(lasts)X
+2669(until)X
+2840(the)X
+2963(\256rst)X
+3112(release,)X
+3381(which)X
+3602(marks)X
+3823(the)X
+3946(start)X
+4109(of)X
+4201(the)X
+555 4377(shrink)N
+780(phase.)X
+1028(In)X
+1120(practice,)X
+1420(the)X
+1543(grow)X
+1733(phase)X
+1941(lasts)X
+2108(for)X
+2227(the)X
+2350(duration)X
+2642(of)X
+2734(a)X
+2795(transaction)X
+3172(in)X
+3259(LIBTP)X
+3506(and)X
+3647(in)X
+3734(commercial)X
+4138(data-)X
+555 4467(base)N
+721(systems.)X
+1037(The)X
+1184(shrink)X
+1406(phase)X
+1611(takes)X
+1798(place)X
+1990(during)X
+2221(transaction)X
+2595(commit)X
+2861(or)X
+2950(abort.)X
+3177(This)X
+3341(means)X
+3568(that)X
+3710(locks)X
+3901(are)X
+4022(acquired)X
+555 4557(on)N
+655(demand)X
+929(during)X
+1158(the)X
+1276(lifetime)X
+1545(of)X
+1632(a)X
+1688(transaction,)X
+2080(and)X
+2216(held)X
+2374(until)X
+2540(commit)X
+2804(time,)X
+2986(at)X
+3064(which)X
+3280(point)X
+3464(all)X
+3564(locks)X
+3753(are)X
+3872(released.)X
+755 4680(If)N
+832(multiple)X
+1121(transactions)X
+1527(are)X
+1649(active)X
+1864(concurrently,)X
+2313(deadlocks)X
+2657(can)X
+2792(occur)X
+2994(and)X
+3133(must)X
+3311(be)X
+3410(detected)X
+3701(and)X
+3840(resolved.)X
+4174(The)X
+555 4770(lock)N
+715(table)X
+893(can)X
+1027(be)X
+1125(thought)X
+1391(of)X
+1480(as)X
+1569(a)X
+1627(representation)X
+2104(of)X
+2193(a)X
+2251(directed)X
+2532(graph.)X
+2777(The)X
+2924(nodes)X
+3133(in)X
+3216(the)X
+3335(graph)X
+3539(are)X
+3659(transactions.)X
+4103(Edges)X
+555 4860(represent)N
+878(the)X
+3 f
+1004(waits-for)X
+1 f
+1340(relation)X
+1613(between)X
+1909(transactions;)X
+2342(if)X
+2419(transaction)X
+2 f
+2799(A)X
+1 f
+2876(is)X
+2957(waiting)X
+3225(for)X
+3347(a)X
+3411(lock)X
+3577(held)X
+3743(by)X
+3851(transaction)X
+2 f
+4230(B)X
+1 f
+4279(,)X
+555 4950(then)N
+716(a)X
+775(directed)X
+1057(edge)X
+1232(exists)X
+1437(from)X
+2 f
+1616(A)X
+1 f
+1687(to)X
+2 f
+1771(B)X
+1 f
+1842(in)X
+1926(the)X
+2046(graph.)X
+2291(A)X
+2371(deadlock)X
+2683(exists)X
+2887(if)X
+2958(a)X
+3016(cycle)X
+3208(appears)X
+3476(in)X
+3560(the)X
+3680(graph.)X
+3925(By)X
+4040(conven-)X
+555 5040(tion,)N
+719(no)X
+819(transaction)X
+1191(ever)X
+1350(waits)X
+1539(for)X
+1653(a)X
+1709(lock)X
+1867(it)X
+1931(already)X
+2188(holds,)X
+2401(so)X
+2492(re\257exive)X
+2793(edges)X
+2996(are)X
+3115(impossible.)X
+755 5163(A)N
+836(distinguished)X
+1285(process)X
+1549(monitors)X
+1856(the)X
+1977(lock)X
+2138(table,)X
+2337(searching)X
+2668(for)X
+2785(cycles.)X
+3048(The)X
+3195(frequency)X
+3539(with)X
+3703(which)X
+3921(this)X
+4058(process)X
+555 5253(runs)N
+716(is)X
+792(user-settable;)X
+1243(for)X
+1360(the)X
+1481(multi-user)X
+1833(tests)X
+1998(discussed)X
+2328(in)X
+2413(section)X
+2663(5.1.2,)X
+2866(it)X
+2933(has)X
+3063(been)X
+3238(set)X
+3350(to)X
+3435(wake)X
+3628(up)X
+3731(every)X
+3932(second,)X
+4197(but)X
+555 5343(more)N
+742(sophisticated)X
+1182(schedules)X
+1516(are)X
+1636(certainly)X
+1938(possible.)X
+2261(When)X
+2474(a)X
+2531(cycle)X
+2722(is)X
+2796(detected,)X
+3105(one)X
+3242(of)X
+3330(the)X
+3449(transactions)X
+3853(in)X
+3936(the)X
+4055(cycle)X
+4246(is)X
+555 5433(nominated)N
+917(and)X
+1057(aborted.)X
+1362(When)X
+1578(the)X
+1700(transaction)X
+2076(aborts,)X
+2315(it)X
+2382(rolls)X
+2547(back)X
+2722(its)X
+2820(changes)X
+3102(and)X
+3241(releases)X
+3519(its)X
+3617(locks,)X
+3829(thereby)X
+4093(break-)X
+555 5523(ing)N
+677(the)X
+795(cycle)X
+985(in)X
+1067(the)X
+1185(graph.)X
+
+8 p
+%%Page: 8 8
+10 s 10 xH 0 xS 1 f
+3 f
+1 f
+4 Ds
+1 Dt
+1866 865 MXY
+1338 0 Dl
+1866 1031 MXY
+1338 0 Dl
+1866 1199 MXY
+1338 0 Dl
+1866 1366 MXY
+1338 0 Dl
+1866 1533 MXY
+1338 0 Dl
+1866 1701 MXY
+1338 0 Dl
+-1 Ds
+5 Dt
+1866 1868 MXY
+1338 0 Dl
+1 Dt
+1 Di
+2981 MX
+ 2981 1868 lineto
+ 2981 1575 lineto
+ 3092 1575 lineto
+ 3092 1868 lineto
+ 2981 1868 lineto
+closepath 21 2981 1575 3092 1868 Dp
+2646 MX
+ 2646 1868 lineto
+ 2646 949 lineto
+ 2758 949 lineto
+ 2758 1868 lineto
+ 2646 1868 lineto
+closepath 14 2646 949 2758 1868 Dp
+2312 MX
+ 2312 1868 lineto
+ 2312 1701 lineto
+ 2423 1701 lineto
+ 2423 1868 lineto
+ 2312 1868 lineto
+closepath 3 2312 1701 2423 1868 Dp
+1977 MX
+ 1977 1868 lineto
+ 1977 1512 lineto
+ 2089 1512 lineto
+ 2089 1868 lineto
+ 1977 1868 lineto
+closepath 19 1977 1512 2089 1868 Dp
+3 f
+2640 2047(Client/Server)N
+1957(Single)X
+2185(Process)X
+7 s
+2957 1957(record)N
+2570(component)X
+2289(record)X
+1890(components)X
+1733 1724(.1)N
+1733 1556(.2)N
+1733 1389(.3)N
+1733 1222(.4)N
+1733 1055(.5)N
+1733 889(.6)N
+1590 726(Elapsed)N
+1794(Time)X
+1613 782(\(in)N
+1693(seconds\))X
+3 Dt
+-1 Ds
+8 s
+555 2255(Figure)N
+756(4:)X
+829(Comparison)X
+1187(of)X
+1260(High)X
+1416(and)X
+1540(Low)X
+1681(Level)X
+1850(Interfaces.)X
+1 f
+2174(Elapsed)X
+2395(time)X
+2528(in)X
+2597(seconds)X
+2818(to)X
+2887(perform)X
+3111(a)X
+3158(single)X
+3330(record)X
+3511(retrieval)X
+3742(from)X
+3885(a)X
+3932(command)X
+4203(line)X
+555 2345(\(rather)N
+751(than)X
+888(a)X
+943(procedural)X
+1241(interface\))X
+1510(is)X
+1579(shown)X
+1772(on)X
+1862(the)X
+1966(y)X
+2024(axis.)X
+2185(The)X
+2310(``component'')X
+2704(numbers)X
+2950(re\257ect)X
+3135(the)X
+3239(timings)X
+3458(when)X
+3622(the)X
+3726(record)X
+3914(is)X
+3983(retrieved)X
+4235(by)X
+555 2435(separate)N
+785(calls)X
+924(to)X
+996(the)X
+1096(lock)X
+1228(manager)X
+1469(and)X
+1583(buffer)X
+1760(manager)X
+2001(while)X
+2165(the)X
+2264(``record'')X
+2531(timings)X
+2745(were)X
+2889(obtained)X
+3130(by)X
+3215(using)X
+3375(a)X
+3424(single)X
+3598(call)X
+3711(to)X
+3782(the)X
+3881(record)X
+4064(manager.)X
+555 2525(The)N
+674(2:1)X
+776(ratio)X
+913(observed)X
+1163(for)X
+1257(the)X
+1355(single)X
+1528(process)X
+1739(case)X
+1868(is)X
+1930(a)X
+1977(re\257ection)X
+2237(of)X
+2309(the)X
+2406(parsing)X
+2613(overhead)X
+2865(for)X
+2958(executing)X
+3225(eight)X
+3372(separate)X
+3599(commands)X
+3895(rather)X
+4062(than)X
+4191(one.)X
+555 2615(The)N
+673(additional)X
+948(factor)X
+1115(of)X
+1187(one)X
+1298(re\257ected)X
+1536(in)X
+1605(the)X
+1702(3:1)X
+1803(ratio)X
+1939(for)X
+2031(the)X
+2127(client/server)X
+2460(architecture)X
+2794(is)X
+2855(due)X
+2965(to)X
+3033(the)X
+3129(communication)X
+3545(overhead.)X
+3828(The)X
+3945(true)X
+4062(ratios)X
+4222(are)X
+555 2705(actually)N
+775(worse)X
+945(since)X
+1094(the)X
+1190(component)X
+1492(timings)X
+1703(do)X
+1785(not)X
+1884(re\257ect)X
+2060(the)X
+2155(search)X
+2334(times)X
+2490(within)X
+2671(each)X
+2804(page)X
+2941(or)X
+3011(the)X
+3106(time)X
+3237(required)X
+3466(to)X
+3533(transmit)X
+3760(the)X
+3855(page)X
+3992(between)X
+4221(the)X
+555 2795(two)N
+667(processes.)X
+10 s
+10 f
+555 2885(h)N
+579(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)X
+3 f
+555 3161(4.2.)N
+715(Group)X
+961(Commit)X
+1 f
+755 3284(Since)N
+959(the)X
+1083(log)X
+1211(must)X
+1392(be)X
+1494(\257ushed)X
+1751(to)X
+1839(disk)X
+1997(at)X
+2080(commit)X
+2349(time,)X
+2536(disk)X
+2694(bandwidth)X
+3057(fundamentally)X
+3545(limits)X
+3751(the)X
+3874(rate)X
+4020(at)X
+4103(which)X
+555 3374(transactions)N
+959(complete.)X
+1314(Since)X
+1513(most)X
+1688(transactions)X
+2091(write)X
+2276(only)X
+2438(a)X
+2494(few)X
+2635(small)X
+2828(records)X
+3085(to)X
+3167(the)X
+3285(log,)X
+3427(the)X
+3545(last)X
+3676(page)X
+3848(of)X
+3935(the)X
+4053(log)X
+4175(will)X
+555 3464(be)N
+658(\257ushed)X
+916(once)X
+1095(by)X
+1202(every)X
+1408(transaction)X
+1787(which)X
+2010(writes)X
+2233(to)X
+2322(it.)X
+2433(In)X
+2527(the)X
+2652(naive)X
+2853(implementation,)X
+3402(these)X
+3593(\257ushes)X
+3841(would)X
+4067(happen)X
+555 3554(serially.)N
+755 3677(LIBTP)N
+1008(uses)X
+3 f
+1177(group)X
+1412(commit)X
+1 f
+1702([DEWI84])X
+2077(in)X
+2170(order)X
+2371(to)X
+2464(amortize)X
+2775(the)X
+2903(cost)X
+3062(of)X
+3159(one)X
+3305(synchronous)X
+3740(disk)X
+3903(write)X
+4098(across)X
+555 3767(multiple)N
+851(transactions.)X
+1304(Group)X
+1539(commit)X
+1812(provides)X
+2117(a)X
+2182(way)X
+2345(for)X
+2468(a)X
+2533(group)X
+2749(of)X
+2845(transactions)X
+3257(to)X
+3348(commit)X
+3621(simultaneously.)X
+4174(The)X
+555 3857(\256rst)N
+709(several)X
+967(transactions)X
+1380(to)X
+1472(commit)X
+1745(write)X
+1939(their)X
+2115(changes)X
+2403(to)X
+2494(the)X
+2621(in-memory)X
+3006(log)X
+3137(page,)X
+3338(then)X
+3505(sleep)X
+3699(on)X
+3808(a)X
+3873(distinguished)X
+555 3947(semaphore.)N
+966(Later,)X
+1179(a)X
+1238(committing)X
+1629(transaction)X
+2004(\257ushes)X
+2249(the)X
+2370(page)X
+2545(to)X
+2630(disk,)X
+2805(and)X
+2943(wakes)X
+3166(up)X
+3268(all)X
+3370(its)X
+3467(sleeping)X
+3756(peers.)X
+3988(The)X
+4135(point)X
+555 4037(at)N
+635(which)X
+853(changes)X
+1134(are)X
+1255(actually)X
+1531(written)X
+1780(is)X
+1855(determined)X
+2238(by)X
+2340(three)X
+2523(thresholds.)X
+2914(The)X
+3061(\256rst)X
+3207(is)X
+3281(the)X
+2 f
+3400(group)X
+3612(threshold)X
+1 f
+3935(and)X
+4072(de\256nes)X
+555 4127(the)N
+674(minimum)X
+1005(number)X
+1271(of)X
+1359(transactions)X
+1763(which)X
+1979(must)X
+2154(be)X
+2250(active)X
+2462(in)X
+2544(the)X
+2662(system)X
+2904(before)X
+3130(transactions)X
+3533(are)X
+3652(forced)X
+3878(to)X
+3960(participate)X
+555 4217(in)N
+646(a)X
+711(group)X
+927(commit.)X
+1240(The)X
+1394(second)X
+1646(is)X
+1728(the)X
+2 f
+1855(wait)X
+2021(threshold)X
+1 f
+2352(which)X
+2577(is)X
+2658(expressed)X
+3003(as)X
+3098(the)X
+3224(percentage)X
+3601(of)X
+3696(active)X
+3916(transactions)X
+555 4307(waiting)N
+826(to)X
+919(be)X
+1026(committed.)X
+1439(The)X
+1595(last)X
+1737(is)X
+1821(the)X
+2 f
+1950(logdelay)X
+2257(threshold)X
+1 f
+2590(which)X
+2816(indicates)X
+3131(how)X
+3299(much)X
+3507(un\257ushed)X
+3848(log)X
+3980(should)X
+4223(be)X
+555 4397(allowed)N
+829(to)X
+911(accumulate)X
+1297(before)X
+1523(a)X
+1579(waiting)X
+1839(transaction's)X
+2289(commit)X
+2553(record)X
+2779(is)X
+2852(\257ushed.)X
+755 4520(Group)N
+981(commit)X
+1246(can)X
+1379(substantially)X
+1803(improve)X
+2090(performance)X
+2517(for)X
+2631(high-concurrency)X
+3218(environments.)X
+3714(If)X
+3788(only)X
+3950(a)X
+4006(few)X
+4147(tran-)X
+555 4610(sactions)N
+836(are)X
+957(running,)X
+1248(it)X
+1314(is)X
+1389(unlikely)X
+1673(to)X
+1757(improve)X
+2046(things)X
+2263(at)X
+2343(all.)X
+2485(The)X
+2632(crossover)X
+2962(point)X
+3148(is)X
+3223(the)X
+3343(point)X
+3529(at)X
+3609(which)X
+3827(the)X
+3947(transaction)X
+555 4700(commit)N
+823(rate)X
+968(is)X
+1045(limited)X
+1295(by)X
+1399(the)X
+1521(bandwidth)X
+1883(of)X
+1974(the)X
+2096(device)X
+2330(on)X
+2434(which)X
+2654(the)X
+2776(log)X
+2902(resides.)X
+3189(If)X
+3267(processes)X
+3599(are)X
+3722(trying)X
+3937(to)X
+4023(\257ush)X
+4201(the)X
+555 4790(log)N
+677(faster)X
+876(than)X
+1034(the)X
+1152(log)X
+1274(disk)X
+1427(can)X
+1559(accept)X
+1785(data,)X
+1959(then)X
+2117(group)X
+2324(commit)X
+2588(will)X
+2732(increase)X
+3016(the)X
+3134(commit)X
+3398(rate.)X
+3 f
+555 4976(4.3.)N
+715(Kernel)X
+971(Intervention)X
+1418(for)X
+1541(Synchronization)X
+1 f
+755 5099(Since)N
+954(LIBTP)X
+1197(uses)X
+1356(data)X
+1511(in)X
+1594(shared)X
+1825(memory)X
+2113(\()X
+2 f
+2140(e.g.)X
+1 f
+2277(the)X
+2395(lock)X
+2553(table)X
+2729(and)X
+2865(buffer)X
+3082(pool\))X
+3271(it)X
+3335(must)X
+3510(be)X
+3606(possible)X
+3888(for)X
+4002(a)X
+4058(process)X
+555 5189(to)N
+640(acquire)X
+900(exclusive)X
+1226(access)X
+1454(to)X
+1538(shared)X
+1770(data)X
+1926(in)X
+2010(order)X
+2202(to)X
+2286(prevent)X
+2549(corruption.)X
+2945(In)X
+3034(addition,)X
+3338(the)X
+3458(process)X
+3721(manager)X
+4020(must)X
+4197(put)X
+555 5279(processes)N
+886(to)X
+971(sleep)X
+1159(when)X
+1356(the)X
+1477(lock)X
+1638(or)X
+1728(buffer)X
+1948(they)X
+2109(request)X
+2364(is)X
+2440(in)X
+2525(use)X
+2655(by)X
+2758(some)X
+2950(other)X
+3138(process.)X
+3441(In)X
+3530(the)X
+3650(LIBTP)X
+3894(implementa-)X
+555 5385(tion)N
+705(under)X
+914(Ultrix)X
+1131(4.0)X
+7 s
+5353(2)Y
+10 s
+5385(,)Y
+1305(we)X
+1424(use)X
+1556(System)X
+1816(V)X
+1899(semaphores)X
+2303(to)X
+2390(provide)X
+2660(this)X
+2800(synchronization.)X
+3377(Semaphores)X
+3794(implemented)X
+4237(in)X
+555 5475(this)N
+701(fashion)X
+968(turn)X
+1128(out)X
+1261(to)X
+1354(be)X
+1461(an)X
+1568(expensive)X
+1920(choice)X
+2161(for)X
+2285(synchronization,)X
+2847(because)X
+3132(each)X
+3310(access)X
+3546(traps)X
+3732(to)X
+3824(the)X
+3952(kernel)X
+4183(and)X
+8 s
+10 f
+555 5547(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)N
+5 s
+1 f
+727 5625(2)N
+8 s
+763 5650(Ultrix)N
+932(and)X
+1040(DEC)X
+1184(are)X
+1277(trademarks)X
+1576(of)X
+1645(Digital)X
+1839(Equipment)X
+2136(Corporation.)X
+
+9 p
+%%Page: 9 9
+8 s 8 xH 0 xS 1 f
+10 s
+3 f
+1 f
+555 630(executes)N
+852(atomically)X
+1210(there.)X
+755 753(On)N
+878(architectures)X
+1314(that)X
+1459(support)X
+1724(atomic)X
+1967(test-and-set,)X
+2382(a)X
+2443(much)X
+2646(better)X
+2854(choice)X
+3089(would)X
+3314(be)X
+3415(to)X
+3502(attempt)X
+3767(to)X
+3854(obtain)X
+4079(a)X
+4139(spin-)X
+555 843(lock)N
+714(with)X
+877(a)X
+934(test-and-set,)X
+1345(and)X
+1482(issue)X
+1663(a)X
+1720(system)X
+1963(call)X
+2100(only)X
+2263(if)X
+2333(the)X
+2452(spinlock)X
+2744(is)X
+2818(unavailable.)X
+3249(Since)X
+3447(virtually)X
+3738(all)X
+3838(semaphores)X
+4237(in)X
+555 933(LIBTP)N
+801(are)X
+924(uncontested)X
+1330(and)X
+1469(are)X
+1591(held)X
+1752(for)X
+1869(very)X
+2035(short)X
+2218(periods)X
+2477(of)X
+2567(time,)X
+2752(this)X
+2890(would)X
+3113(improve)X
+3403(performance.)X
+3873(For)X
+4007(example,)X
+555 1023(processes)N
+885(must)X
+1062(acquire)X
+1321(exclusive)X
+1646(access)X
+1874(to)X
+1958(buffer)X
+2177(pool)X
+2341(metadata)X
+2653(in)X
+2737(order)X
+2929(to)X
+3013(\256nd)X
+3159(and)X
+3297(pin)X
+3421(a)X
+3479(buffer)X
+3698(in)X
+3781(shared)X
+4012(memory.)X
+555 1113(This)N
+721(semaphore)X
+1093(is)X
+1170(requested)X
+1502(most)X
+1681(frequently)X
+2034(in)X
+2119(LIBTP.)X
+2404(However,)X
+2742(once)X
+2917(it)X
+2984(is)X
+3060(acquired,)X
+3380(only)X
+3545(a)X
+3604(few)X
+3748(instructions)X
+4144(must)X
+555 1203(be)N
+656(executed)X
+966(before)X
+1196(it)X
+1264(is)X
+1341(released.)X
+1669(On)X
+1791(one)X
+1931(architecture)X
+2335(for)X
+2453(which)X
+2673(we)X
+2791(were)X
+2972(able)X
+3130(to)X
+3216(gather)X
+3441(detailed)X
+3719(pro\256ling)X
+4018(informa-)X
+555 1293(tion,)N
+729(the)X
+857(cost)X
+1015(of)X
+1111(the)X
+1238(semaphore)X
+1615(calls)X
+1791(accounted)X
+2146(for)X
+2269(25%)X
+2445(of)X
+2541(the)X
+2668(total)X
+2839(time)X
+3010(spent)X
+3208(updating)X
+3517(the)X
+3644(metadata.)X
+4003(This)X
+4174(was)X
+555 1383(fairly)N
+749(consistent)X
+1089(across)X
+1310(most)X
+1485(of)X
+1572(the)X
+1690(critical)X
+1933(sections.)X
+755 1506(In)N
+848(an)X
+950(attempt)X
+1216(to)X
+1304(quantify)X
+1597(the)X
+1720(overhead)X
+2040(of)X
+2132(kernel)X
+2358(synchronization,)X
+2915(we)X
+3034(ran)X
+3162(tests)X
+3329(on)X
+3434(a)X
+3495(version)X
+3756(of)X
+3848(4.3BSD-Reno)X
+555 1596(which)N
+786(had)X
+937(been)X
+1123(modi\256ed)X
+1441(to)X
+1537(support)X
+1811(binary)X
+2050(semaphore)X
+2432(facilities)X
+2742(similar)X
+2998(to)X
+3094(those)X
+3297(described)X
+3639(in)X
+3735([POSIX91].)X
+4174(The)X
+555 1686(hardware)N
+880(platform)X
+1181(consisted)X
+1504(of)X
+1595(an)X
+1695(HP300)X
+1941(\(33MHz)X
+2237(MC68030\))X
+2612(workstation)X
+3014(with)X
+3180(16MBytes)X
+3537(of)X
+3628(main)X
+3812(memory,)X
+4123(and)X
+4263(a)X
+555 1776(600MByte)N
+920(HP7959)X
+1205(SCSI)X
+1396(disk)X
+1552(\(17)X
+1682(ms)X
+1798(average)X
+2072(seek)X
+2237(time\).)X
+2468(We)X
+2602(ran)X
+2727(three)X
+2910(sets)X
+3052(of)X
+3141(comparisons)X
+3568(which)X
+3786(are)X
+3907(summarized)X
+555 1866(in)N
+645(\256gure)X
+860(\256ve.)X
+1028(In)X
+1123(each)X
+1299(comparison)X
+1701(we)X
+1823(ran)X
+1954(two)X
+2102(tests,)X
+2292(one)X
+2436(using)X
+2637(hardware)X
+2965(spinlocks)X
+3295(and)X
+3438(the)X
+3563(other)X
+3755(using)X
+3955(kernel)X
+4183(call)X
+555 1956(synchronization.)N
+1135(Since)X
+1341(the)X
+1467(test)X
+1606(was)X
+1758(run)X
+1892(single-user,)X
+2291(none)X
+2474(of)X
+2568(the)X
+2693(the)X
+2818(locks)X
+3014(were)X
+3198(contested.)X
+3568(In)X
+3662(the)X
+3787(\256rst)X
+3938(two)X
+4085(sets)X
+4232(of)X
+555 2046(tests,)N
+743(we)X
+863(ran)X
+992(the)X
+1116(full)X
+1253(transaction)X
+1631(processing)X
+2000(benchmark)X
+2383(described)X
+2717(in)X
+2805(section)X
+3058(5.1.)X
+3223(In)X
+3315(one)X
+3456(case)X
+3620(we)X
+3739(ran)X
+3867(with)X
+4034(both)X
+4201(the)X
+555 2136(database)N
+854(and)X
+992(log)X
+1116(on)X
+1218(the)X
+1338(same)X
+1525(disk)X
+1680(\(1)X
+1769(Disk\))X
+1969(and)X
+2107(in)X
+2191(the)X
+2311(second,)X
+2576(we)X
+2692(ran)X
+2817(with)X
+2981(the)X
+3101(database)X
+3400(and)X
+3538(log)X
+3661(on)X
+3762(separate)X
+4047(disks)X
+4232(\(2)X
+555 2226(Disk\).)N
+800(In)X
+894(the)X
+1019(last)X
+1157(test,)X
+1315(we)X
+1436(wanted)X
+1695(to)X
+1784(create)X
+2004(a)X
+2067(CPU)X
+2249(bound)X
+2476(environment,)X
+2928(so)X
+3026(we)X
+3146(used)X
+3319(a)X
+3381(database)X
+3684(small)X
+3883(enough)X
+4145(to)X
+4233(\256t)X
+555 2316(completely)N
+941(in)X
+1033(the)X
+1161(cache)X
+1375(and)X
+1521(issued)X
+1751(read-only)X
+2089(transactions.)X
+2541(The)X
+2695(results)X
+2933(in)X
+3024(\256gure)X
+3240(\256ve)X
+3389(express)X
+3659(the)X
+3786(kernel)X
+4016(call)X
+4161(syn-)X
+555 2406(chronization)N
+980(performance)X
+1411(as)X
+1502(a)X
+1562(percentage)X
+1935(of)X
+2026(the)X
+2148(spinlock)X
+2443(performance.)X
+2914(For)X
+3049(example,)X
+3365(in)X
+3451(the)X
+3573(1)X
+3637(disk)X
+3794(case,)X
+3977(the)X
+4098(kernel)X
+555 2496(call)N
+697(implementation)X
+1225(achieved)X
+1537(4.4)X
+1662(TPS)X
+1824(\(transactions)X
+2259(per)X
+2387(second\))X
+2662(while)X
+2865(the)X
+2988(semaphore)X
+3361(implementation)X
+3888(achieved)X
+4199(4.6)X
+555 2586(TPS,)N
+735(and)X
+874(the)X
+995(relative)X
+1259(performance)X
+1689(of)X
+1779(the)X
+1900(kernel)X
+2123(synchronization)X
+2657(is)X
+2732(96%)X
+2901(that)X
+3043(of)X
+3132(the)X
+3252(spinlock)X
+3545(\(100)X
+3714(*)X
+3776(4.4)X
+3898(/)X
+3942(4.6\).)X
+4111(There)X
+555 2676(are)N
+674(two)X
+814(striking)X
+1078(observations)X
+1503(from)X
+1679(these)X
+1864(results:)X
+10 f
+635 2799(g)N
+1 f
+755(even)X
+927(when)X
+1121(the)X
+1239(system)X
+1481(is)X
+1554(disk)X
+1707(bound,)X
+1947(the)X
+2065(CPU)X
+2240(cost)X
+2389(of)X
+2476(synchronization)X
+3008(is)X
+3081(noticeable,)X
+3451(and)X
+10 f
+635 2922(g)N
+1 f
+755(when)X
+949(we)X
+1063(are)X
+1182(CPU)X
+1357(bound,)X
+1597(the)X
+1715(difference)X
+2062(is)X
+2135(dramatic)X
+2436(\(67%\).)X
+3 f
+555 3108(4.4.)N
+715(Transaction)X
+1148(Protected)X
+1499(Access)X
+1747(Methods)X
+1 f
+755 3231(The)N
+903(B-tree)X
+1127(and)X
+1266(\256xed)X
+1449(length)X
+1671(recno)X
+1872(\(record)X
+2127(number\))X
+2421(access)X
+2649(methods)X
+2942(have)X
+3116(been)X
+3290(modi\256ed)X
+3596(to)X
+3680(provide)X
+3947(transaction)X
+555 3321(protection.)N
+941(Whereas)X
+1244(the)X
+1363(previously)X
+1722(published)X
+2054(interface)X
+2357(to)X
+2440(the)X
+2559(access)X
+2786(routines)X
+3065(had)X
+3202(separate)X
+3487(open)X
+3664(calls)X
+3832(for)X
+3946(each)X
+4114(of)X
+4201(the)X
+10 f
+555 3507(h)N
+579(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)X
+1 Dt
+2978 5036 MXY
+ 2978 5036 lineto
+ 2978 4662 lineto
+ 3093 4662 lineto
+ 3093 5036 lineto
+ 2978 5036 lineto
+closepath 21 2978 4662 3093 5036 Dp
+2518 MX
+ 2518 5036 lineto
+ 2518 3960 lineto
+ 2633 3960 lineto
+ 2633 5036 lineto
+ 2518 5036 lineto
+closepath 3 2518 3960 2633 5036 Dp
+2059 MX
+ 2059 5036 lineto
+ 2059 3946 lineto
+ 2174 3946 lineto
+ 2174 5036 lineto
+ 2059 5036 lineto
+closepath 1 2059 3946 2174 5036 Dp
+3 f
+7 s
+2912 5141(Read-only)N
+1426 3767(of)N
+1487(Spinlock)X
+1710(Throughput)X
+1480 3710(Throughput)N
+1786(as)X
+1850(a)X
+1892(%)X
+11 s
+1670 4843(20)N
+1670 4614(40)N
+1670 4384(60)N
+1670 4155(80)N
+1648 3925(100)N
+7 s
+2041 5141(1)N
+2083(Disk)X
+2490(2)X
+2532(Disks)X
+5 Dt
+1829 5036 MXY
+1494 0 Dl
+4 Ds
+1 Dt
+1829 4806 MXY
+1494 0 Dl
+1829 4577 MXY
+1494 0 Dl
+1829 4347 MXY
+1494 0 Dl
+1829 4118 MXY
+1494 0 Dl
+1829 3888 MXY
+1494 0 Dl
+3 Dt
+-1 Ds
+8 s
+555 5360(Figure)N
+753(5:)X
+823(Kernel)X
+1028(Overhead)X
+1315(for)X
+1413(System)X
+1625(Call)X
+1756(Synchronization.)X
+1 f
+2254(The)X
+2370(performance)X
+2708(of)X
+2778(the)X
+2873(kernel)X
+3049(call)X
+3158(synchronization)X
+3583(is)X
+3643(expressed)X
+3911(as)X
+3980(a)X
+4024(percentage)X
+555 5450(of)N
+625(the)X
+720(spinlock)X
+954(synchronization)X
+1379(performance.)X
+1749(In)X
+1819(disk)X
+1943(bound)X
+2120(cases)X
+2271(\(1)X
+2341(Disk)X
+2479(and)X
+2588(2)X
+2637(Disks\),)X
+2837(we)X
+2928(see)X
+3026(that)X
+3139(4-6%)X
+3294(of)X
+3364(the)X
+3459(performance)X
+3797(is)X
+3857(lost)X
+3966(due)X
+4074(to)X
+4140(kernel)X
+555 5540(calls)N
+688(while)X
+846(in)X
+912(the)X
+1006(CPU)X
+1147(bound)X
+1323(case,)X
+1464(we)X
+1554(have)X
+1690(lost)X
+1799(67%)X
+1932(of)X
+2001(the)X
+2095(performance)X
+2432(due)X
+2540(to)X
+2606(kernel)X
+2781(calls.)X
+
+10 p
+%%Page: 10 10
+8 s 8 xH 0 xS 1 f
+10 s
+3 f
+1 f
+555 630(access)N
+781(methods,)X
+1092(we)X
+1206(now)X
+1364(have)X
+1536(an)X
+1632(integrated)X
+1973(open)X
+2149(call)X
+2285(with)X
+2447(the)X
+2565(following)X
+2896(calling)X
+3134(conventions:)X
+7 f
+715 753(DB)N
+859(*dbopen)X
+1243(\(const)X
+1579(char)X
+1819(*file,)X
+2155(int)X
+2347(flags,)X
+2683(int)X
+2875(mode,)X
+3163(DBTYPE)X
+3499(type,)X
+1291 843(int)N
+1483(dbflags,)X
+1915(const)X
+2203(void)X
+2443(*openinfo\))X
+1 f
+555 966(where)N
+2 f
+774(\256le)X
+1 f
+894(is)X
+969(the)X
+1089(name)X
+1285(of)X
+1374(the)X
+1494(\256le)X
+1618(being)X
+1818(opened,)X
+2 f
+2092(\257ags)X
+1 f
+2265(and)X
+2 f
+2402(mode)X
+1 f
+2597(are)X
+2717(the)X
+2836(standard)X
+3129(arguments)X
+3484(to)X
+3 f
+3567(open)X
+1 f
+3731(\(2\),)X
+2 f
+3866(type)X
+1 f
+4021(is)X
+4095(one)X
+4232(of)X
+555 1056(the)N
+680(access)X
+913(method)X
+1180(types,)X
+2 f
+1396(db\257ags)X
+1 f
+1654(indicates)X
+1966(the)X
+2091(mode)X
+2296(of)X
+2390(the)X
+2515(buffer)X
+2739(pool)X
+2907(and)X
+3049(transaction)X
+3427(protection,)X
+3798(and)X
+2 f
+3940(openinfo)X
+1 f
+4246(is)X
+555 1146(the)N
+681(access)X
+915(method)X
+1183(speci\256c)X
+1456(information.)X
+1902(Currently,)X
+2257(the)X
+2383(possible)X
+2673(values)X
+2906(for)X
+2 f
+3028(db\257ags)X
+1 f
+3287(are)X
+3414(DB_SHARED)X
+3912(and)X
+4055(DB_TP)X
+555 1236(indicating)N
+895(that)X
+1035(buffers)X
+1283(should)X
+1516(be)X
+1612(kept)X
+1770(in)X
+1852(a)X
+1908(shared)X
+2138(buffer)X
+2355(pool)X
+2517(and)X
+2653(that)X
+2793(the)X
+2911(\256le)X
+3033(should)X
+3266(be)X
+3362(transaction)X
+3734(protected.)X
+755 1359(The)N
+900(modi\256cations)X
+1355(required)X
+1643(to)X
+1725(add)X
+1861(transaction)X
+2233(protection)X
+2578(to)X
+2660(an)X
+2756(access)X
+2982(method)X
+3242(are)X
+3361(quite)X
+3541(simple)X
+3774(and)X
+3910(localized.)X
+715 1482(1.)N
+795(Replace)X
+1074(\256le)X
+2 f
+1196(open)X
+1 f
+1372(with)X
+2 f
+1534(buf_open)X
+1 f
+1832(.)X
+715 1572(2.)N
+795(Replace)X
+1074(\256le)X
+2 f
+1196(read)X
+1 f
+1363(and)X
+2 f
+1499(write)X
+1 f
+1683(calls)X
+1850(with)X
+2012(buffer)X
+2229(manager)X
+2526(calls)X
+2693(\()X
+2 f
+2720(buf_get)X
+1 f
+(,)S
+2 f
+3000(buf_unpin)X
+1 f
+3324(\).)X
+715 1662(3.)N
+795(Precede)X
+1070(buffer)X
+1287(manager)X
+1584(calls)X
+1751(with)X
+1913(an)X
+2009(appropriate)X
+2395(\(read)X
+2581(or)X
+2668(write\))X
+2880(lock)X
+3038(call.)X
+715 1752(4.)N
+795(Before)X
+1034(updates,)X
+1319(issue)X
+1499(a)X
+1555(logging)X
+1819(operation.)X
+715 1842(5.)N
+795(After)X
+985(data)X
+1139(have)X
+1311(been)X
+1483(accessed,)X
+1805(release)X
+2049(the)X
+2167(buffer)X
+2384(manager)X
+2681(pin.)X
+715 1932(6.)N
+795(Provide)X
+1064(undo/redo)X
+1409(code)X
+1581(for)X
+1695(each)X
+1863(type)X
+2021(of)X
+2108(log)X
+2230(record)X
+2456(de\256ned.)X
+555 2071(The)N
+702(following)X
+1035(code)X
+1209(fragments)X
+1552(show)X
+1743(how)X
+1903(to)X
+1987(transaction)X
+2361(protect)X
+2606(several)X
+2856(updates)X
+3123(to)X
+3206(a)X
+3263(B-tree.)X
+7 s
+3484 2039(3)N
+10 s
+3533 2071(In)N
+3621(the)X
+3740(unprotected)X
+4140(case,)X
+555 2161(an)N
+652(open)X
+829(call)X
+966(is)X
+1040(followed)X
+1346(by)X
+1447(a)X
+1504(read)X
+1664(call)X
+1801(to)X
+1884(obtain)X
+2105(the)X
+2224(meta-data)X
+2562(for)X
+2677(the)X
+2796(B-tree.)X
+3058(Instead,)X
+3331(we)X
+3446(issue)X
+3627(an)X
+3724(open)X
+3901(to)X
+3984(the)X
+4102(buffer)X
+555 2251(manager)N
+852(to)X
+934(obtain)X
+1154(a)X
+1210(\256le)X
+1332(id)X
+1414(and)X
+1550(a)X
+1606(buffer)X
+1823(request)X
+2075(to)X
+2157(obtain)X
+2377(the)X
+2495(meta-data)X
+2832(as)X
+2919(shown)X
+3148(below.)X
+7 f
+715 2374(char)N
+955(*path;)X
+715 2464(int)N
+907(fid,)X
+1147(flags,)X
+1483(len,)X
+1723(mode;)X
+715 2644(/*)N
+859(Obtain)X
+1195(a)X
+1291(file)X
+1531(id)X
+1675(with)X
+1915(which)X
+2203(to)X
+2347(access)X
+2683(the)X
+2875(buffer)X
+3211(pool)X
+3451(*/)X
+715 2734(fid)N
+907(=)X
+1003(buf_open\(path,)X
+1723(flags,)X
+2059(mode\);)X
+715 2914(/*)N
+859(Read)X
+1099(the)X
+1291(meta)X
+1531(data)X
+1771(\(page)X
+2059(0\))X
+2203(for)X
+2395(the)X
+2587(B-tree)X
+2923(*/)X
+715 3004(if)N
+859(\(tp_lock\(fid,)X
+1531(0,)X
+1675(READ_LOCK\)\))X
+1003 3094(return)N
+1339(error;)X
+715 3184(meta_data_ptr)N
+1387(=)X
+1483(buf_get\(fid,)X
+2107(0,)X
+2251(BF_PIN,)X
+2635(&len\);)X
+1 f
+555 3307(The)N
+714(BF_PIN)X
+1014(argument)X
+1350(to)X
+2 f
+1445(buf_get)X
+1 f
+1718(indicates)X
+2036(that)X
+2189(we)X
+2316(wish)X
+2500(to)X
+2595(leave)X
+2798(this)X
+2946(page)X
+3131(pinned)X
+3382(in)X
+3477(memory)X
+3777(so)X
+3881(that)X
+4034(it)X
+4111(is)X
+4197(not)X
+555 3397(swapped)N
+862(out)X
+990(while)X
+1194(we)X
+1314(are)X
+1439(accessing)X
+1772(it.)X
+1881(The)X
+2031(last)X
+2167(argument)X
+2495(to)X
+2 f
+2582(buf_get)X
+1 f
+2847(returns)X
+3095(the)X
+3218(number)X
+3488(of)X
+3580(bytes)X
+3774(on)X
+3879(the)X
+4002(page)X
+4179(that)X
+555 3487(were)N
+732(valid)X
+912(so)X
+1003(that)X
+1143(the)X
+1261(access)X
+1487(method)X
+1747(may)X
+1905(initialize)X
+2205(the)X
+2323(page)X
+2495(if)X
+2564(necessary.)X
+755 3610(Next,)N
+955(consider)X
+1251(inserting)X
+1555(a)X
+1615(record)X
+1845(on)X
+1949(a)X
+2009(particular)X
+2341(page)X
+2517(of)X
+2608(a)X
+2668(B-tree.)X
+2932(In)X
+3022(the)X
+3143(unprotected)X
+3545(case,)X
+3727(we)X
+3844(read)X
+4006(the)X
+4127(page,)X
+555 3700(call)N
+2 f
+693(_bt_insertat)X
+1 f
+1079(,)X
+1121(and)X
+1258(write)X
+1444(the)X
+1563(page.)X
+1776(Instead,)X
+2049(we)X
+2164(lock)X
+2323(the)X
+2442(page,)X
+2635(request)X
+2888(the)X
+3007(buffer,)X
+3245(log)X
+3368(the)X
+3487(change,)X
+3756(modify)X
+4008(the)X
+4127(page,)X
+555 3790(and)N
+691(release)X
+935(the)X
+1053(buffer.)X
+7 f
+715 3913(int)N
+907(fid,)X
+1147(len,)X
+1387(pageno;)X
+1867(/*)X
+2011(Identifies)X
+2539(the)X
+2731(buffer)X
+3067(*/)X
+715 4003(int)N
+907(index;)X
+1867(/*)X
+2011(Location)X
+2443(at)X
+2587(which)X
+2875(to)X
+3019(insert)X
+3355(the)X
+3547(new)X
+3739(pair)X
+3979(*/)X
+715 4093(DBT)N
+907(*keyp,)X
+1243(*datap;)X
+1867(/*)X
+2011(Key/Data)X
+2443(pair)X
+2683(to)X
+2827(be)X
+2971(inserted)X
+3403(*/)X
+715 4183(DATUM)N
+1003(*d;)X
+1867(/*)X
+2011(Key/data)X
+2443(structure)X
+2923(to)X
+3067(insert)X
+3403(*/)X
+715 4363(/*)N
+859(Lock)X
+1099(and)X
+1291(request)X
+1675(the)X
+1867(buffer)X
+2203(*/)X
+715 4453(if)N
+859(\(tp_lock\(fid,)X
+1531(pageno,)X
+1915(WRITE_LOCK\)\))X
+1003 4543(return)N
+1339(error;)X
+715 4633(buffer_ptr)N
+1243(=)X
+1339(buf_get\(fid,)X
+1963(pageno,)X
+2347(BF_PIN,)X
+2731(&len\);)X
+715 4813(/*)N
+859(Log)X
+1051(and)X
+1243(perform)X
+1627(the)X
+1819(update)X
+2155(*/)X
+715 4903(log_insdel\(BTREE_INSERT,)N
+1915(fid,)X
+2155(pageno,)X
+2539(keyp,)X
+2827(datap\);)X
+715 4993(_bt_insertat\(buffer_ptr,)N
+1915(d,)X
+2059(index\);)X
+715 5083(buf_unpin\(buffer_ptr\);)N
+1 f
+555 5206(Succinctly,)N
+942(the)X
+1068(algorithm)X
+1407(for)X
+1529(turning)X
+1788(unprotected)X
+2195(code)X
+2375(into)X
+2527(protected)X
+2854(code)X
+3034(is)X
+3115(to)X
+3205(replace)X
+3466(read)X
+3633(operations)X
+3995(with)X
+2 f
+4165(lock)X
+1 f
+555 5296(and)N
+2 f
+691(buf_get)X
+1 f
+951(operations)X
+1305(and)X
+1441(write)X
+1626(operations)X
+1980(with)X
+2 f
+2142(log)X
+1 f
+2264(and)X
+2 f
+2400(buf_unpin)X
+1 f
+2744(operations.)X
+8 s
+10 f
+555 5458(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)N
+5 s
+1 f
+727 5536(3)N
+8 s
+766 5561(The)N
+884(following)X
+1152(code)X
+1291(fragments)X
+1565(are)X
+1661(examples,)X
+1937(but)X
+2038(do)X
+2120(not)X
+2220(de\256ne)X
+2394(the)X
+2490(\256nal)X
+2622(interface.)X
+2894(The)X
+3011(\256nal)X
+3143(interface)X
+3383(will)X
+3501(be)X
+3579(determined)X
+3884(after)X
+4018(LIBTP)X
+4214(has)X
+555 5633(been)N
+691(fully)X
+828(integrated)X
+1099(with)X
+1229(the)X
+1323(most)X
+1464(recent)X
+3 f
+1635(db)X
+1 f
+1707(\(3\))X
+1797(release)X
+1989(from)X
+2129(the)X
+2223(Computer)X
+2495(Systems)X
+2725(Research)X
+2974(Group)X
+3153(at)X
+3215(University)X
+3501(of)X
+3570(California,)X
+3861(Berkeley.)X
+
+11 p
+%%Page: 11 11
+8 s 8 xH 0 xS 1 f
+10 s
+3 f
+555 630(5.)N
+655(Performance)X
+1 f
+755 753(In)N
+845(this)X
+983(section,)X
+1253(we)X
+1370(present)X
+1625(the)X
+1746(results)X
+1978(of)X
+2067(two)X
+2209(very)X
+2374(different)X
+2673(benchmarks.)X
+3103(The)X
+3250(\256rst)X
+3396(is)X
+3471(an)X
+3569(online)X
+3791(transaction)X
+4165(pro-)X
+555 843(cessing)N
+824(benchmark,)X
+1234(similar)X
+1489(to)X
+1584(the)X
+1715(standard)X
+2020(TPCB,)X
+2272(but)X
+2407(has)X
+2547(been)X
+2732(adapted)X
+3015(to)X
+3110(run)X
+3250(in)X
+3345(a)X
+3414(desktop)X
+3696(environment.)X
+4174(The)X
+555 933(second)N
+798(emulates)X
+1103(a)X
+1159(computer-aided)X
+1683(design)X
+1912(environment)X
+2337(and)X
+2473(provides)X
+2769(more)X
+2954(complex)X
+3250(query)X
+3453(processing.)X
+3 f
+555 1119(5.1.)N
+715(Transaction)X
+1148(Processing)X
+1533(Benchmark)X
+1 f
+755 1242(For)N
+887(this)X
+1023(section,)X
+1291(all)X
+1392(performance)X
+1820(numbers)X
+2117(shown)X
+2346(except)X
+2576(for)X
+2690(the)X
+2808(commercial)X
+3207(database)X
+3504(system)X
+3746(were)X
+3923(obtained)X
+4219(on)X
+555 1332(a)N
+614(DECstation)X
+1009(5000/200)X
+1333(with)X
+1497(32MBytes)X
+1852(of)X
+1941(memory)X
+2230(running)X
+2501(Ultrix)X
+2714(V4.0,)X
+2914(accessing)X
+3244(a)X
+3302(DEC)X
+3484(RZ57)X
+3688(1GByte)X
+3959(disk)X
+4114(drive.)X
+555 1422(The)N
+720(commercial)X
+1139(relational)X
+1482(database)X
+1799(system)X
+2061(tests)X
+2242(were)X
+2438(run)X
+2584(on)X
+2703(a)X
+2778(comparable)X
+3192(machine,)X
+3523(a)X
+3598(Sparcstation)X
+4033(1+)X
+4157(with)X
+555 1512(32MBytes)N
+915(memory)X
+1209(and)X
+1352(a)X
+1415(1GByte)X
+1691(external)X
+1976(disk)X
+2135(drive.)X
+2366(The)X
+2517(database,)X
+2840(binaries)X
+3120(and)X
+3262(log)X
+3390(resided)X
+3648(on)X
+3754(the)X
+3878(same)X
+4069(device.)X
+555 1602(Reported)N
+869(times)X
+1062(are)X
+1181(the)X
+1299(means)X
+1524(of)X
+1611(\256ve)X
+1751(tests)X
+1913(and)X
+2049(have)X
+2221(standard)X
+2513(deviations)X
+2862(within)X
+3086(two)X
+3226(percent)X
+3483(of)X
+3570(the)X
+3688(mean.)X
+755 1725(The)N
+905(test)X
+1041(database)X
+1343(was)X
+1493(con\256gured)X
+1861(according)X
+2203(to)X
+2290(the)X
+2413(TPCB)X
+2637(scaling)X
+2889(rules)X
+3070(for)X
+3189(a)X
+3250(10)X
+3355(transaction)X
+3732(per)X
+3860(second)X
+4108(\(TPS\))X
+555 1815(system)N
+817(with)X
+999(1,000,000)X
+1359(account)X
+1649(records,)X
+1946(100)X
+2106(teller)X
+2311(records,)X
+2607(and)X
+2762(10)X
+2881(branch)X
+3139(records.)X
+3455(Where)X
+3709(TPS)X
+3885(numbers)X
+4200(are)X
+555 1905(reported,)N
+865(we)X
+981(are)X
+1102(running)X
+1373(a)X
+1431(modi\256ed)X
+1737(version)X
+1995(of)X
+2084(the)X
+2203(industry)X
+2486(standard)X
+2779(transaction)X
+3152(processing)X
+3516(benchmark,)X
+3914(TPCB.)X
+4174(The)X
+555 1995(TPCB)N
+780(benchmark)X
+1163(simulates)X
+1491(a)X
+1553(withdrawal)X
+1940(performed)X
+2301(by)X
+2407(a)X
+2469(hypothetical)X
+2891(teller)X
+3082(at)X
+3166(a)X
+3228(hypothetical)X
+3650(bank.)X
+3872(The)X
+4022(database)X
+555 2085(consists)N
+831(of)X
+921(relations)X
+1220(\(\256les\))X
+1430(for)X
+1547(accounts,)X
+1871(branches,)X
+2200(tellers,)X
+2439(and)X
+2578(history.)X
+2863(For)X
+2997(each)X
+3168(transaction,)X
+3563(the)X
+3684(account,)X
+3976(teller,)X
+4183(and)X
+555 2175(branch)N
+795(balances)X
+1093(must)X
+1269(be)X
+1366(updated)X
+1641(to)X
+1724(re\257ect)X
+1946(the)X
+2065(withdrawal)X
+2447(and)X
+2584(a)X
+2640(history)X
+2882(record)X
+3108(is)X
+3181(written)X
+3428(which)X
+3644(contains)X
+3931(the)X
+4049(account)X
+555 2265(id,)N
+657(branch)X
+896(id,)X
+998(teller)X
+1183(id,)X
+1285(and)X
+1421(the)X
+1539(amount)X
+1799(of)X
+1886(the)X
+2004(withdrawal)X
+2385([TPCB90].)X
+755 2388(Our)N
+914(implementation)X
+1450(of)X
+1551(the)X
+1683(benchmark)X
+2074(differs)X
+2317(from)X
+2506(the)X
+2637(speci\256cation)X
+3075(in)X
+3170(several)X
+3431(aspects.)X
+3736(The)X
+3894(speci\256cation)X
+555 2478(requires)N
+840(that)X
+985(the)X
+1108(database)X
+1410(keep)X
+1587(redundant)X
+1933(logs)X
+2091(on)X
+2196(different)X
+2498(devices,)X
+2784(but)X
+2911(we)X
+3030(use)X
+3162(a)X
+3223(single)X
+3439(log.)X
+3606(Furthermore,)X
+4052(all)X
+4157(tests)X
+555 2568(were)N
+734(run)X
+863(on)X
+965(a)X
+1023(single,)X
+1256(centralized)X
+1631(system)X
+1875(so)X
+1968(there)X
+2151(is)X
+2226(no)X
+2328(notion)X
+2553(of)X
+2641(remote)X
+2885(accesses.)X
+3219(Finally,)X
+3486(we)X
+3601(calculated)X
+3948(throughput)X
+555 2658(by)N
+662(dividing)X
+955(the)X
+1080(total)X
+1249(elapsed)X
+1517(time)X
+1686(by)X
+1793(the)X
+1918(number)X
+2190(of)X
+2284(transactions)X
+2694(processed)X
+3038(rather)X
+3253(than)X
+3418(by)X
+3525(computing)X
+3894(the)X
+4018(response)X
+555 2748(time)N
+717(for)X
+831(each)X
+999(transaction.)X
+755 2871(The)N
+912(performance)X
+1351(comparisons)X
+1788(focus)X
+1993(on)X
+2104(traditional)X
+2464(Unix)X
+2655(techniques)X
+3029(\(unprotected,)X
+3486(using)X
+3 f
+3690(\257ock)X
+1 f
+3854(\(2\))X
+3979(and)X
+4126(using)X
+3 f
+555 2961(fsync)N
+1 f
+733(\(2\)\))X
+884(and)X
+1030(a)X
+1096(commercial)X
+1504(relational)X
+1836(database)X
+2142(system.)X
+2433(Well-behaved)X
+2913(applications)X
+3329(using)X
+3 f
+3531(\257ock)X
+1 f
+3695(\(2\))X
+3818(are)X
+3946(guaranteed)X
+555 3051(that)N
+704(concurrent)X
+1077(processes')X
+1441(updates)X
+1715(do)X
+1824(not)X
+1955(interact)X
+2225(with)X
+2396(one)X
+2541(another,)X
+2831(but)X
+2962(no)X
+3070(guarantees)X
+3442(about)X
+3648(atomicity)X
+3978(are)X
+4105(made.)X
+555 3141(That)N
+731(is,)X
+833(if)X
+911(the)X
+1038(system)X
+1289(crashes)X
+1555(in)X
+1646(mid-transaction,)X
+2198(only)X
+2369(parts)X
+2554(of)X
+2649(that)X
+2797(transaction)X
+3177(will)X
+3329(be)X
+3433(re\257ected)X
+3738(in)X
+3828(the)X
+3954 0.3125(after-crash)AX
+555 3231(state)N
+725(of)X
+815(the)X
+936(database.)X
+1276(The)X
+1424(use)X
+1554(of)X
+3 f
+1643(fsync)X
+1 f
+1821(\(2\))X
+1937(at)X
+2017(transaction)X
+2391(commit)X
+2657(time)X
+2821(provides)X
+3119(guarantees)X
+3485(of)X
+3574(durability)X
+3907(after)X
+4077(system)X
+555 3321(failure.)N
+825(However,)X
+1160(there)X
+1341(is)X
+1414(no)X
+1514(mechanism)X
+1899(to)X
+1981(perform)X
+2260(transaction)X
+2632(abort.)X
+3 f
+555 3507(5.1.1.)N
+775(Single-User)X
+1191(Tests)X
+1 f
+755 3630(These)N
+978(tests)X
+1151(compare)X
+1459(LIBTP)X
+1712(in)X
+1804(a)X
+1870(variety)X
+2123(of)X
+2220(con\256gurations)X
+2708(to)X
+2800(traditional)X
+3159(UNIX)X
+3390(solutions)X
+3708(and)X
+3854(a)X
+3920(commercial)X
+555 3720(relational)N
+884(database)X
+1187(system)X
+1435(\(RDBMS\).)X
+1814(To)X
+1929(demonstrate)X
+2347(the)X
+2471(server)X
+2694(architecture)X
+3100(we)X
+3220(built)X
+3392(a)X
+3454(front)X
+3636(end)X
+3777(test)X
+3913(process)X
+4179(that)X
+555 3810(uses)N
+732(TCL)X
+922([OUST90])X
+1304(to)X
+1405(parse)X
+1614(database)X
+1930(access)X
+2175(commands)X
+2561(and)X
+2716(call)X
+2870(the)X
+3006(database)X
+3321(access)X
+3565(routines.)X
+3901(In)X
+4006(one)X
+4160(case)X
+555 3900(\(SERVER\),)N
+956(frontend)X
+1249(and)X
+1386(backend)X
+1675(processes)X
+2004(were)X
+2181(created)X
+2434(which)X
+2650(communicated)X
+3142(via)X
+3260(an)X
+3356(IP)X
+3447(socket.)X
+3712(In)X
+3799(the)X
+3917(second)X
+4160(case)X
+555 3990(\(TCL\),)N
+802(a)X
+860(single)X
+1073(process)X
+1336(read)X
+1497(queries)X
+1751(from)X
+1929(standard)X
+2223(input,)X
+2429(parsed)X
+2660(them,)X
+2861(and)X
+2998(called)X
+3211(the)X
+3330(database)X
+3628(access)X
+3855(routines.)X
+4174(The)X
+555 4080(performance)N
+987(difference)X
+1338(between)X
+1630(the)X
+1752(TCL)X
+1927(and)X
+2067(SERVER)X
+2397(tests)X
+2563(quanti\256es)X
+2898(the)X
+3020(communication)X
+3542(overhead)X
+3861(of)X
+3952(the)X
+4074(socket.)X
+555 4170(The)N
+732(RDBMS)X
+1063(implementation)X
+1617(used)X
+1816(embedded)X
+2198(SQL)X
+2401(in)X
+2515(C)X
+2620(with)X
+2814(stored)X
+3062(database)X
+3391(procedures.)X
+3835(Therefore,)X
+4224(its)X
+555 4260(con\256guration)N
+1003(is)X
+1076(a)X
+1132(hybrid)X
+1361(of)X
+1448(the)X
+1566(single)X
+1777(process)X
+2038(architecture)X
+2438(and)X
+2574(the)X
+2692(server)X
+2909(architecture.)X
+3349(The)X
+3494(graph)X
+3697(in)X
+3779(\256gure)X
+3986(six)X
+4099(shows)X
+555 4350(a)N
+611(comparison)X
+1005(of)X
+1092(the)X
+1210(following)X
+1541(six)X
+1654(con\256gurations:)X
+1126 4506(LIBTP)N
+1552(Uses)X
+1728(the)X
+1846(LIBTP)X
+2088(library)X
+2322(in)X
+2404(a)X
+2460(single)X
+2671(application.)X
+1126 4596(TCL)N
+1552(Uses)X
+1728(the)X
+1846(LIBTP)X
+2088(library)X
+2322(in)X
+2404(a)X
+2460(single)X
+2671(application,)X
+3067(requires)X
+3346(query)X
+3549(parsing.)X
+1126 4686(SERVER)N
+1552(Uses)X
+1728(the)X
+1846(LIBTP)X
+2088(library)X
+2322(in)X
+2404(a)X
+2460(server)X
+2677(con\256guration,)X
+3144(requires)X
+3423(query)X
+3626(parsing.)X
+1126 4776(NOTP)N
+1552(Uses)X
+1728(no)X
+1828(locking,)X
+2108(logging,)X
+2392(or)X
+2479(concurrency)X
+2897(control.)X
+1126 4866(FLOCK)N
+1552(Uses)X
+3 f
+1728(\257ock)X
+1 f
+1892(\(2\))X
+2006(for)X
+2120(concurrency)X
+2538(control)X
+2785(and)X
+2921(nothing)X
+3185(for)X
+3299(durability.)X
+1126 4956(FSYNC)N
+1552(Uses)X
+3 f
+1728(fsync)X
+1 f
+1906(\(2\))X
+2020(for)X
+2134(durability)X
+2465(and)X
+2601(nothing)X
+2865(for)X
+2979(concurrency)X
+3397(control.)X
+1126 5046(RDBMS)N
+1552(Uses)X
+1728(a)X
+1784(commercial)X
+2183(relational)X
+2506(database)X
+2803(system.)X
+755 5235(The)N
+902(results)X
+1133(show)X
+1324(that)X
+1466(LIBTP,)X
+1730(both)X
+1894(in)X
+1978(the)X
+2098(procedural)X
+2464(and)X
+2602(parsed)X
+2834(environments,)X
+3312(is)X
+3387(competitive)X
+3787(with)X
+3951(a)X
+4009(commer-)X
+555 5325(cial)N
+692(system)X
+935(\(comparing)X
+1326(LIBTP,)X
+1589(TCL,)X
+1781(and)X
+1917(RDBMS\).)X
+2263(Compared)X
+2617(to)X
+2699(existing)X
+2972(UNIX)X
+3193(solutions,)X
+3521(LIBTP)X
+3763(is)X
+3836(approximately)X
+555 5415(15%)N
+738(slower)X
+988(than)X
+1162(using)X
+3 f
+1371(\257ock)X
+1 f
+1535(\(2\))X
+1665(or)X
+1768(no)X
+1884(protection)X
+2245(but)X
+2383(over)X
+2562(80%)X
+2745(better)X
+2964(than)X
+3137(using)X
+3 f
+3345(fsync)X
+1 f
+3523(\(2\))X
+3652(\(comparing)X
+4057(LIBTP,)X
+555 5505(FLOCK,)N
+857(NOTP,)X
+1106(and)X
+1242(FSYNC\).)X
+
+12 p
+%%Page: 12 12
+10 s 10 xH 0 xS 1 f
+3 f
+8 s
+3500 2184(RDBMS)N
+1 Dt
+3553 2085 MXY
+ 3553 2085 lineto
+ 3676 2085 lineto
+ 3676 1351 lineto
+ 3553 1351 lineto
+ 3553 2085 lineto
+closepath 16 3553 1351 3676 2085 Dp
+2018 2184(SERVER)N
+1720 1168 MXY
+0 917 Dl
+122 0 Dl
+0 -917 Dl
+-122 0 Dl
+1715 2184(TCL)N
+2087 1534 MXY
+ 2087 1534 lineto
+ 2209 1534 lineto
+ 2209 2085 lineto
+ 2087 2085 lineto
+ 2087 1534 lineto
+closepath 12 2087 1534 2209 2085 Dp
+3187 MX
+ 3187 1534 lineto
+ 3309 1534 lineto
+ 3309 2085 lineto
+ 3187 2085 lineto
+ 3187 1534 lineto
+closepath 19 3187 1534 3309 2085 Dp
+3142 2184(FSYNC)N
+2425(NOTP)X
+2453 955 MXY
+ 2453 955 lineto
+ 2576 955 lineto
+ 2576 2085 lineto
+ 2453 2085 lineto
+ 2453 955 lineto
+closepath 21 2453 955 2576 2085 Dp
+2820 1000 MXY
+ 2820 1000 lineto
+ 2942 1000 lineto
+ 2942 2085 lineto
+ 2820 2085 lineto
+ 2820 1000 lineto
+closepath 14 2820 1000 2942 2085 Dp
+5 Dt
+1231 2085 MXY
+2567 0 Dl
+4 Ds
+1 Dt
+1231 1840 MXY
+2567 0 Dl
+1231 1596 MXY
+2567 0 Dl
+1231 1351 MXY
+2567 0 Dl
+1231 1108 MXY
+2567 0 Dl
+1231 863 MXY
+2567 0 Dl
+11 s
+1087 1877(2)N
+1087 1633(4)N
+1087 1388(6)N
+1087 1145(8)N
+1065 900(10)N
+1028 763(TPS)N
+-1 Ds
+1353 2085 MXY
+ 1353 2085 lineto
+ 1353 1151 lineto
+ 1476 1151 lineto
+ 1476 2085 lineto
+ 1353 2085 lineto
+closepath 3 1353 1151 1476 2085 Dp
+8 s
+1318 2184(LIBTP)N
+2767(FLOCK)X
+3 Dt
+-1 Ds
+10 s
+1597 2399(Figure)N
+1844(6:)X
+1931(Single-User)X
+2347(Performance)X
+2814(Comparison.)X
+1 f
+10 f
+555 2579(h)N
+579(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)X
+3 f
+555 2855(5.1.2.)N
+775(Multi-User)X
+1174(Tests)X
+1 f
+755 2978(While)N
+975(the)X
+1097(single-user)X
+1473(tests)X
+1639(form)X
+1819(a)X
+1878(basis)X
+2061(for)X
+2178(comparing)X
+2544(LIBTP)X
+2789(to)X
+2874(other)X
+3062(systems,)X
+3358(our)X
+3488(goal)X
+3649(in)X
+3734(multi-user)X
+4086(testing)X
+555 3068(was)N
+714(to)X
+810(analyze)X
+1089(its)X
+1197(scalability.)X
+1579(To)X
+1701(this)X
+1849(end,)X
+2018(we)X
+2145(have)X
+2330(run)X
+2470(the)X
+2601(benchmark)X
+2991(in)X
+3086(three)X
+3280(modes,)X
+3542(the)X
+3673(normal)X
+3933(disk)X
+4099(bound)X
+555 3158(con\256guration)N
+1010(\(\256gure)X
+1252(seven\),)X
+1510(a)X
+1573(CPU)X
+1755(bound)X
+1982(con\256guration)X
+2436(\(\256gure)X
+2677(eight,)X
+2884(READ-ONLY\),)X
+3426(and)X
+3569(lock)X
+3734(contention)X
+4099(bound)X
+555 3248(\(\256gure)N
+796(eight,)X
+1003(NO_FSYNC\).)X
+1510(Since)X
+1715(the)X
+1840(normal)X
+2094(con\256guration)X
+2548(is)X
+2628(completely)X
+3011(disk)X
+3171(bound)X
+3398(\(each)X
+3600(transaction)X
+3978(requires)X
+4263(a)X
+555 3354(random)N
+823(read,)X
+1005(a)X
+1064(random)X
+1332(write,)X
+1540(and)X
+1679(a)X
+1738(sequential)X
+2086(write)X
+7 s
+2251 3322(4)N
+10 s
+3354(\))Y
+2329(we)X
+2446(expect)X
+2679(to)X
+2764(see)X
+2890(little)X
+3059(performance)X
+3489(improvement)X
+3939(as)X
+4028(the)X
+4148(mul-)X
+555 3444(tiprogramming)N
+1064(level)X
+1249(increases.)X
+1613(In)X
+1709(fact,)X
+1879(\256gure)X
+2095(seven)X
+2307(reveals)X
+2564(that)X
+2713(we)X
+2836(are)X
+2964(able)X
+3127(to)X
+3218(overlap)X
+3487(CPU)X
+3670(and)X
+3814(disk)X
+3975(utilization)X
+555 3534(slightly)N
+825(producing)X
+1181(approximately)X
+1674(a)X
+1740(10%)X
+1917(performance)X
+2354(improvement)X
+2811(with)X
+2983(two)X
+3133(processes.)X
+3511(After)X
+3711(that)X
+3861(point,)X
+4075(perfor-)X
+555 3624(mance)N
+785(drops)X
+983(off,)X
+1117(and)X
+1253(at)X
+1331(a)X
+1387(multi-programming)X
+2038(level)X
+2214(of)X
+2301(4,)X
+2381(we)X
+2495(are)X
+2614(performing)X
+2995(worse)X
+3207(than)X
+3365(in)X
+3447(the)X
+3565(single)X
+3776(process)X
+4037(case.)X
+755 3747(Similar)N
+1021(behavior)X
+1333(was)X
+1489(reported)X
+1787(on)X
+1897(the)X
+2025(commercial)X
+2434(relational)X
+2767(database)X
+3074(system)X
+3326(using)X
+3529(the)X
+3657(same)X
+3852(con\256guration.)X
+555 3837(The)N
+707(important)X
+1045(conclusion)X
+1419(to)X
+1508(draw)X
+1696(from)X
+1879(this)X
+2021(is)X
+2101(that)X
+2248(you)X
+2395(cannot)X
+2636(attain)X
+2841(good)X
+3028(multi-user)X
+3384(scaling)X
+3638(on)X
+3745(a)X
+3808(badly)X
+4013(balanced)X
+555 3927(system.)N
+839(If)X
+915(multi-user)X
+1266(performance)X
+1695(on)X
+1797(applications)X
+2205(of)X
+2293(this)X
+2429(sort)X
+2570(is)X
+2644(important,)X
+2996(one)X
+3133(must)X
+3309(have)X
+3482(a)X
+3539(separate)X
+3824(logging)X
+4089(device)X
+555 4017(and)N
+697(horizontally)X
+1110(partition)X
+1407(the)X
+1531(database)X
+1834(to)X
+1921(allow)X
+2124(a)X
+2185(suf\256ciently)X
+2570(high)X
+2737(degree)X
+2977(of)X
+3069(multiprogramming)X
+3698(that)X
+3843(group)X
+4055(commit)X
+555 4107(can)N
+687(amortize)X
+988(the)X
+1106(cost)X
+1255(of)X
+1342(log)X
+1464(\257ushing.)X
+755 4230(By)N
+871(using)X
+1067(a)X
+1126(very)X
+1292(small)X
+1488(database)X
+1788(\(one)X
+1954(that)X
+2097(can)X
+2232(be)X
+2331(entirely)X
+2599(cached)X
+2846(in)X
+2930(main)X
+3112(memory\))X
+3428(and)X
+3566(read-only)X
+3896(transactions,)X
+555 4320(we)N
+670(generated)X
+1004(a)X
+1061(CPU)X
+1236(bound)X
+1456(environment.)X
+1921(By)X
+2034(using)X
+2227(the)X
+2345(same)X
+2530(small)X
+2723(database,)X
+3040(the)X
+3158(complete)X
+3472(TPCB)X
+3691(transaction,)X
+4083(and)X
+4219(no)X
+3 f
+555 4410(fsync)N
+1 f
+733(\(2\))X
+862(on)X
+977(the)X
+1110(log)X
+1247(at)X
+1340(commit,)X
+1639(we)X
+1768(created)X
+2036(a)X
+2107(lock)X
+2280(contention)X
+2652(bound)X
+2886(environment.)X
+3365(The)X
+3524(small)X
+3731(database)X
+4042(used)X
+4223(an)X
+555 4500(account)N
+828(\256le)X
+953(containing)X
+1314(only)X
+1479(1000)X
+1662(records)X
+1922(rather)X
+2133(than)X
+2294(the)X
+2415(full)X
+2549(1,000,000)X
+2891(records)X
+3150(and)X
+3288(ran)X
+3413(enough)X
+3671(transactions)X
+4076(to)X
+4160(read)X
+555 4590(the)N
+677(entire)X
+883(database)X
+1183(into)X
+1330(the)X
+1451(buffer)X
+1671(pool)X
+1836(\(2000\))X
+2073(before)X
+2302(beginning)X
+2645(measurements.)X
+3147(The)X
+3295(read-only)X
+3626(transaction)X
+4001(consisted)X
+555 4680(of)N
+646(three)X
+831(database)X
+1132(reads)X
+1326(\(from)X
+1533(the)X
+1655(1000)X
+1839(record)X
+2069(account)X
+2343(\256le,)X
+2489(the)X
+2611(100)X
+2754(record)X
+2983(teller)X
+3171(\256le,)X
+3316(and)X
+3455(the)X
+3576(10)X
+3679(record)X
+3908(branch)X
+4150(\256le\).)X
+555 4770(Since)N
+759(no)X
+865(data)X
+1025(were)X
+1208(modi\256ed)X
+1518(and)X
+1660(no)X
+1766(history)X
+2014(records)X
+2277(were)X
+2460(written,)X
+2733(no)X
+2839(log)X
+2966(records)X
+3228(were)X
+3410(written.)X
+3702(For)X
+3838(the)X
+3961(contention)X
+555 4860(bound)N
+780(con\256guration,)X
+1252(we)X
+1371(used)X
+1543(the)X
+1666(normal)X
+1918(TPCB)X
+2142(transaction)X
+2519(\(against)X
+2798(the)X
+2920(small)X
+3117(database\))X
+3445(and)X
+3585(disabled)X
+3876(the)X
+3998(log)X
+4124(\257ush.)X
+555 4950(Figure)N
+784(eight)X
+964(shows)X
+1184(both)X
+1346(of)X
+1433(these)X
+1618(results.)X
+755 5073(The)N
+902(read-only)X
+1231(test)X
+1363(indicates)X
+1669(that)X
+1810(we)X
+1925(barely)X
+2147(scale)X
+2329(at)X
+2408(all)X
+2509(in)X
+2592(the)X
+2711(CPU)X
+2887(bound)X
+3108(case.)X
+3308(The)X
+3454(explanation)X
+3849(for)X
+3964(that)X
+4105(is)X
+4179(that)X
+555 5163(even)N
+735(with)X
+905(a)X
+969(single)X
+1188(process,)X
+1477(we)X
+1599(are)X
+1726(able)X
+1888(to)X
+1978(drive)X
+2171(the)X
+2297(CPU)X
+2480(utilization)X
+2832(to)X
+2922(96%.)X
+3137(As)X
+3254(a)X
+3317(result,)X
+3542(that)X
+3689(gives)X
+3885(us)X
+3983(very)X
+4153(little)X
+555 5253(room)N
+753(for)X
+876(improvement,)X
+1352(and)X
+1497(it)X
+1570(takes)X
+1764(a)X
+1829(multiprogramming)X
+2462(level)X
+2647(of)X
+2743(four)X
+2906(to)X
+2997(approach)X
+3321(100%)X
+3537(CPU)X
+3721(saturation.)X
+4106(In)X
+4201(the)X
+555 5343(case)N
+718(where)X
+939(we)X
+1057(do)X
+1161(perform)X
+1444(writes,)X
+1684(we)X
+1802(are)X
+1925(interested)X
+2261(in)X
+2347(detecting)X
+2665(when)X
+2863(lock)X
+3025(contention)X
+3387(becomes)X
+3691(a)X
+3750(dominant)X
+4075(perfor-)X
+555 5433(mance)N
+787(factor.)X
+1037(Contention)X
+1414(will)X
+1560(cause)X
+1761(two)X
+1903(phenomena;)X
+2317(we)X
+2433(will)X
+2579(see)X
+2704(transactions)X
+3109(queueing)X
+3425(behind)X
+3665(frequently)X
+4017(accessed)X
+555 5523(data,)N
+731(and)X
+869(we)X
+985(will)X
+1131(see)X
+1256(transaction)X
+1629(abort)X
+1815(rates)X
+1988(increasing)X
+2339(due)X
+2476(to)X
+2559(deadlock.)X
+2910(Given)X
+3127(that)X
+3268(the)X
+3387(branch)X
+3627(\256le)X
+3750(contains)X
+4038(only)X
+4201(ten)X
+8 s
+10 f
+555 5595(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)N
+5 s
+1 f
+727 5673(4)N
+8 s
+763 5698(Although)N
+1021(the)X
+1115(log)X
+1213(is)X
+1272(written)X
+1469(sequentially,)X
+1810(we)X
+1900(do)X
+1980(not)X
+2078(get)X
+2172(the)X
+2266(bene\256t)X
+2456(of)X
+2525(sequentiality)X
+2868(since)X
+3015(the)X
+3109(log)X
+3207(and)X
+3315(database)X
+3550(reside)X
+3718(on)X
+3798(the)X
+3892(same)X
+4039(disk.)X
+
+13 p
+%%Page: 13 13
+8 s 8 xH 0 xS 1 f
+10 s
+3 f
+1 f
+3187 2051 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+3286 2028 MXY
+0 17 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+3384 1926 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+3483 1910 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+3581 1910 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+3680 1832 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+3778 1909 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+3877 1883 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+3975 1679 MXY
+0 17 Dl
+0 -8 Dl
+9 0 Dl
+-18 0 Dl
+4074 1487 MXY
+0 17 Dl
+0 -8 Dl
+9 0 Dl
+-18 0 Dl
+5 Dt
+3187 2060 MXY
+99 -24 Dl
+98 -101 Dl
+99 -16 Dl
+98 0 Dl
+99 -78 Dl
+98 77 Dl
+99 -26 Dl
+98 -204 Dl
+99 -192 Dl
+3 f
+6 s
+4088 1516(SMALL)N
+3 Dt
+3187 2051 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+3286 2051 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+3384 2041 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+3483 1990 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+3581 1843 MXY
+0 17 Dl
+0 -8 Dl
+9 0 Dl
+-18 0 Dl
+3680 1578 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+3778 1496 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+3877 1430 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+3975 1269 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+4074 1070 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+1 Dt
+3187 2060 MXY
+99 0 Dl
+98 -10 Dl
+99 -51 Dl
+98 -147 Dl
+99 -265 Dl
+98 -82 Dl
+99 -66 Dl
+98 -161 Dl
+99 -199 Dl
+4088 1099(LARGE)N
+5 Dt
+3089 2060 MXY
+985 0 Dl
+3089 MX
+0 -1174 Dl
+4 Ds
+1 Dt
+3581 2060 MXY
+0 -1174 Dl
+4074 2060 MXY
+0 -1174 Dl
+3089 1825 MXY
+985 0 Dl
+9 s
+2993 1855(25)N
+3089 1591 MXY
+985 0 Dl
+2993 1621(50)N
+3089 1356 MXY
+985 0 Dl
+2993 1386(75)N
+3089 1121 MXY
+985 0 Dl
+2957 1151(100)N
+3089 886 MXY
+985 0 Dl
+2957 916(125)N
+3281 2199(Multiprogramming)N
+3071 2152(0)N
+3569(5)X
+4038(10)X
+2859 787(Aborts)N
+3089(per)X
+3211(500)X
+2901 847(transactions)N
+-1 Ds
+3 Dt
+2037 1342 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+2125 1358 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+2213 1341 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+2301 1191 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+2388 1124 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-17 0 Dl
+2476 1157 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+2564 1157 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+2652 1161 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+2740 1153 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+2828 1150 MXY
+0 18 Dl
+0 -9 Dl
+8 0 Dl
+-17 0 Dl
+5 Dt
+2037 1351 MXY
+88 16 Dl
+88 -17 Dl
+88 -150 Dl
+87 -67 Dl
+88 33 Dl
+88 0 Dl
+88 4 Dl
+88 -8 Dl
+88 -3 Dl
+6 s
+2685 1234(READ-ONLY)N
+3 Dt
+2037 1464 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+2125 1640 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+2213 1854 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+2301 1872 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+2388 1871 MXY
+0 17 Dl
+0 -9 Dl
+9 0 Dl
+-17 0 Dl
+2476 1933 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+2564 1914 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+2652 1903 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+2740 1980 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+2828 2004 MXY
+0 18 Dl
+0 -9 Dl
+8 0 Dl
+-17 0 Dl
+1 Dt
+2037 1473 MXY
+88 176 Dl
+88 214 Dl
+88 18 Dl
+87 -2 Dl
+88 63 Dl
+88 -19 Dl
+88 -11 Dl
+88 77 Dl
+88 24 Dl
+2759 1997(NO-FSYNC)N
+5 Dt
+1949 2060 MXY
+879 0 Dl
+1949 MX
+0 -1174 Dl
+4 Ds
+1 Dt
+2388 2060 MXY
+0 -1174 Dl
+2828 2060 MXY
+0 -1174 Dl
+1949 1825 MXY
+879 0 Dl
+9 s
+1842 1855(40)N
+1949 1591 MXY
+879 0 Dl
+1842 1621(80)N
+1949 1356 MXY
+879 0 Dl
+1806 1386(120)N
+1949 1121 MXY
+879 0 Dl
+1806 1151(160)N
+1949 886 MXY
+879 0 Dl
+1806 916(200)N
+2088 2199(Multiprogramming)N
+1844 863(in)N
+1922(TPS)X
+1761 792(Throughput)N
+1931 2121(0)N
+2370 2133(5)N
+2792(10)X
+6 s
+1679 1833(LIBTP)N
+-1 Ds
+3 Dt
+837 1019 MXY
+0 17 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+929 878 MXY
+0 17 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+1021 939 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+1113 1043 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+1205 1314 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+1297 1567 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+1389 1665 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+1481 1699 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+1573 1828 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+1665 1804 MXY
+0 18 Dl
+0 -9 Dl
+8 0 Dl
+-17 0 Dl
+5 Dt
+837 1027 MXY
+92 -141 Dl
+92 62 Dl
+92 104 Dl
+92 271 Dl
+92 253 Dl
+92 98 Dl
+92 34 Dl
+92 129 Dl
+92 -24 Dl
+745 2060 MXY
+920 0 Dl
+745 MX
+0 -1174 Dl
+4 Ds
+1 Dt
+1205 2060 MXY
+0 -1174 Dl
+1665 2060 MXY
+0 -1174 Dl
+745 1766 MXY
+920 0 Dl
+9 s
+673 1796(3)N
+745 1473 MXY
+920 0 Dl
+673 1503(5)N
+745 1180 MXY
+920 0 Dl
+673 1210(8)N
+745 886 MXY
+920 0 Dl
+637 916(10)N
+905 2199(Multiprogramming)N
+622 851(in)N
+700(TPS)X
+575 792(Throughput)N
+733 2152(0)N
+1196(5)X
+1629(10)X
+3 Dt
+-1 Ds
+8 s
+655 2441(Figure)N
+872(7:)X
+960(Multi-user)X
+1286(Performance.)X
+1 f
+655 2531(Since)N
+825(the)X
+931(con\256guration)X
+1300(is)X
+1371(completely)X
+655 2621(disk)N
+790(bound,)X
+994(we)X
+1096(see)X
+1204(only)X
+1345(a)X
+1400(small)X
+1566(im-)X
+655 2711(provement)N
+964(by)X
+1064(adding)X
+1274(a)X
+1337(second)X
+1549(pro-)X
+655 2801(cess.)N
+849(Adding)X
+1081(any)X
+1213(more)X
+1383(concurrent)X
+655 2891(processes)N
+935(causes)X
+1137(performance)X
+1493(degra-)X
+655 2981(dation.)N
+3 f
+1927 2441(Figure)N
+2149(8:)X
+2243(Multi-user)X
+2574(Performance)X
+1927 2531(on)N
+2021(a)X
+2079(small)X
+2251(database.)X
+1 f
+2551(With)X
+2704(one)X
+2821(pro-)X
+1927 2621(cess,)N
+2075(we)X
+2174(are)X
+2276(driving)X
+2486(the)X
+2589(CPU)X
+2739(at)X
+2810(96%)X
+1927 2711(utilization)N
+2215(leaving)X
+2430(little)X
+2575(room)X
+2737(for)X
+2838(im-)X
+1927 2801(provement)N
+2238(as)X
+2328(the)X
+2443(multiprogramming)X
+1927 2891(level)N
+2091(increases.)X
+2396(In)X
+2489(the)X
+2607(NO-FSYNC)X
+1927 2981(case,)N
+2076(lock)X
+2209(contention)X
+2502(degrades)X
+2751(perfor-)X
+1927 3071(mance)N
+2117(as)X
+2194(soon)X
+2339(as)X
+2416(a)X
+2468(second)X
+2669(process)X
+2884(is)X
+1927 3161(added.)N
+3 f
+3199 2441(Figure)N
+3405(9:)X
+3482(Abort)X
+3669(rates)X
+3827(on)X
+3919(the)X
+4028(TPCB)X
+3199 2531(Benchmark.)N
+1 f
+3589(The)X
+3726(abort)X
+3895(rate)X
+4028(climbs)X
+3199 2621(more)N
+3366(quickly)X
+3594(for)X
+3704(the)X
+3818(large)X
+3980(database)X
+3199 2711(test)N
+3324(since)X
+3491(processes)X
+3771(are)X
+3884(descheduled)X
+3199 2801(more)N
+3409(frequently,)X
+3766(allowing)X
+4068(more)X
+3199 2891(processes)N
+3459(to)X
+3525(vie)X
+3619(for)X
+3709(the)X
+3803(same)X
+3950(locks.)X
+10 s
+10 f
+555 3284(h)N
+579(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)X
+1 f
+555 3560(records,)N
+835(we)X
+952(expect)X
+1185(contention)X
+1546(to)X
+1631(become)X
+1904(a)X
+1963(factor)X
+2174(quickly)X
+2437(and)X
+2576(the)X
+2697(NO-FSYNC)X
+3120(line)X
+3263(in)X
+3348(\256gure)X
+3557(eight)X
+3739(demonstrates)X
+4184(this)X
+555 3650(dramatically.)N
+1022(Each)X
+1209(additional)X
+1555(process)X
+1822(causes)X
+2058(both)X
+2226(more)X
+2417(waiting)X
+2682(and)X
+2823(more)X
+3013(deadlocking.)X
+3470(Figure)X
+3704(nine)X
+3867(shows)X
+4092(that)X
+4237(in)X
+555 3740(the)N
+681(small)X
+882(database)X
+1187(case)X
+1353(\(SMALL\),)X
+1725(waiting)X
+1992(is)X
+2072(the)X
+2197(dominant)X
+2526(cause)X
+2732(of)X
+2826(declining)X
+3151(performance)X
+3585(\(the)X
+3737(number)X
+4009(of)X
+4103(aborts)X
+555 3830(increases)N
+878(less)X
+1026(steeply)X
+1281(than)X
+1447(the)X
+1573(performance)X
+2008(drops)X
+2214(off)X
+2336(in)X
+2426(\256gure)X
+2641(eight\),)X
+2876(while)X
+3082(in)X
+3172(the)X
+3298(large)X
+3487(database)X
+3792(case)X
+3958(\(LARGE\),)X
+555 3920(deadlocking)N
+967(contributes)X
+1343(more)X
+1528(to)X
+1610(the)X
+1728(declining)X
+2046(performance.)X
+755 4043(Deadlocks)N
+1116(are)X
+1237(more)X
+1424(likely)X
+1628(to)X
+1712(occur)X
+1913(in)X
+1997(the)X
+2116(LARGE)X
+2404(test)X
+2536(than)X
+2695(in)X
+2778(the)X
+2897(SMALL)X
+3189(test)X
+3321(because)X
+3597(there)X
+3779(are)X
+3899(more)X
+4085(oppor-)X
+555 4133(tunities)N
+814(to)X
+900(wait.)X
+1082(In)X
+1173(the)X
+1295(SMALL)X
+1590(case,)X
+1773(processes)X
+2105(never)X
+2307(do)X
+2410(I/O)X
+2540(and)X
+2679(are)X
+2801(less)X
+2944(likely)X
+3149(to)X
+3234(be)X
+3333(descheduled)X
+3753(during)X
+3985(a)X
+4044(transac-)X
+555 4223(tion.)N
+740(In)X
+828(the)X
+947(LARGE)X
+1235(case,)X
+1415(processes)X
+1744(will)X
+1889(frequently)X
+2240(be)X
+2337(descheduled)X
+2755(since)X
+2941(they)X
+3100(have)X
+3273(to)X
+3356(perform)X
+3636(I/O.)X
+3804(This)X
+3967(provides)X
+4263(a)X
+555 4313(window)N
+837(where)X
+1058(a)X
+1118(second)X
+1365(process)X
+1630(can)X
+1766(request)X
+2022(locks)X
+2215(on)X
+2318(already)X
+2578(locked)X
+2815(pages,)X
+3041(thus)X
+3197(increasing)X
+3550(the)X
+3671(likelihood)X
+4018(of)X
+4108(build-)X
+555 4403(ing)N
+677(up)X
+777(long)X
+939(chains)X
+1164(of)X
+1251(waiting)X
+1511(processes.)X
+1879(Eventually,)X
+2266(this)X
+2401(leads)X
+2586(to)X
+2668(deadlock.)X
+3 f
+555 4589(5.2.)N
+715(The)X
+868(OO1)X
+1052(Benchmark)X
+1 f
+755 4712(The)N
+903(TPCB)X
+1125(benchmark)X
+1505(described)X
+1836(in)X
+1921(the)X
+2042(previous)X
+2341(section)X
+2591(measures)X
+2913(performance)X
+3343(under)X
+3549(a)X
+3608(conventional)X
+4044(transac-)X
+555 4802(tion)N
+706(processing)X
+1076(workload.)X
+1446(Other)X
+1656(application)X
+2039(domains,)X
+2357(such)X
+2531(as)X
+2625(computer-aided)X
+3156(design,)X
+3412(have)X
+3591(substantially)X
+4022(different)X
+555 4892(access)N
+786(patterns.)X
+1105(In)X
+1197(order)X
+1392(to)X
+1479(measure)X
+1772(the)X
+1895(performance)X
+2327(of)X
+2418(LIBTP)X
+2664(under)X
+2871(workloads)X
+3229(of)X
+3320(this)X
+3459(type,)X
+3641(we)X
+3759(implemented)X
+4201(the)X
+555 4982(OO1)N
+731(benchmark)X
+1108(described)X
+1436(in)X
+1518([CATT91].)X
+755 5105(The)N
+908(database)X
+1213(models)X
+1472(a)X
+1535(set)X
+1651(of)X
+1745(electronics)X
+2120(components)X
+2534(with)X
+2703(connections)X
+3113(among)X
+3358(them.)X
+3585(One)X
+3746(table)X
+3929(stores)X
+4143(parts)X
+555 5195(and)N
+696(another)X
+962(stores)X
+1174(connections.)X
+1622(There)X
+1835(are)X
+1959(three)X
+2145(connections)X
+2552(originating)X
+2927(at)X
+3009(any)X
+3149(given)X
+3351(part.)X
+3540(Ninety)X
+3782(percent)X
+4043(of)X
+4134(these)X
+555 5285(connections)N
+960(are)X
+1081(to)X
+1165(nearby)X
+1406(parts)X
+1584(\(those)X
+1802(with)X
+1966(nearby)X
+2 f
+2207(ids)X
+1 f
+2300(\))X
+2348(to)X
+2431(model)X
+2652(the)X
+2771(spatial)X
+3001(locality)X
+3262(often)X
+3448(exhibited)X
+3767(in)X
+3850(CAD)X
+4040(applica-)X
+555 5375(tions.)N
+779(Ten)X
+933(percent)X
+1198(of)X
+1293(the)X
+1419(connections)X
+1830(are)X
+1957(randomly)X
+2292(distributed)X
+2662(among)X
+2908(all)X
+3016(other)X
+3209(parts)X
+3393(in)X
+3483(the)X
+3609(database.)X
+3954(Every)X
+4174(part)X
+555 5465(appears)N
+829(exactly)X
+1089(three)X
+1278(times)X
+1479(in)X
+1569(the)X
+2 f
+1695(from)X
+1 f
+1874(\256eld)X
+2043(of)X
+2137(a)X
+2200(connection)X
+2579(record,)X
+2832(and)X
+2975(zero)X
+3141(or)X
+3235(more)X
+3427(times)X
+3627(in)X
+3716(the)X
+2 f
+3841(to)X
+1 f
+3930(\256eld.)X
+4139(Parts)X
+555 5555(have)N
+2 f
+727(x)X
+1 f
+783(and)X
+2 f
+919(y)X
+1 f
+975(locations)X
+1284(set)X
+1393(randomly)X
+1720(in)X
+1802(an)X
+1898(appropriate)X
+2284(range.)X
+
+14 p
+%%Page: 14 14
+10 s 10 xH 0 xS 1 f
+3 f
+1 f
+755 630(The)N
+900(intent)X
+1102(of)X
+1189(OO1)X
+1365(is)X
+1438(to)X
+1520(measure)X
+1808(the)X
+1926(overall)X
+2169(cost)X
+2318(of)X
+2405(a)X
+2461(query)X
+2664(mix)X
+2808(characteristic)X
+3257(of)X
+3344(engineering)X
+3743(database)X
+4040(applica-)X
+555 720(tions.)N
+770(There)X
+978(are)X
+1097(three)X
+1278(tests:)X
+10 f
+635 843(g)N
+2 f
+755(Lookup)X
+1 f
+1022(generates)X
+1353(1,000)X
+1560(random)X
+1832(part)X
+2 f
+1984(ids)X
+1 f
+2077(,)X
+2124(fetches)X
+2378(the)X
+2502(corresponding)X
+2987(parts)X
+3169(from)X
+3351(the)X
+3475(database,)X
+3798(and)X
+3940(calls)X
+4113(a)X
+4175(null)X
+755 933(procedure)N
+1097(in)X
+1179(the)X
+1297(host)X
+1450(programming)X
+1906(language)X
+2216(with)X
+2378(the)X
+2496(parts')X
+2 f
+2699(x)X
+1 f
+2755(and)X
+2 f
+2891(y)X
+1 f
+2947(positions.)X
+10 f
+635 1056(g)N
+2 f
+755(Traverse)X
+1 f
+1067(retrieves)X
+1371(a)X
+1434(random)X
+1706(part)X
+1858(from)X
+2041(the)X
+2166(database)X
+2470(and)X
+2613(follows)X
+2880(connections)X
+3290(from)X
+3473(it)X
+3544(to)X
+3632(other)X
+3823(parts.)X
+4045(Each)X
+4232(of)X
+755 1146(those)N
+947(parts)X
+1126(is)X
+1202(retrieved,)X
+1531(and)X
+1670(all)X
+1773(connections)X
+2179(from)X
+2358(it)X
+2424(followed.)X
+2771(This)X
+2935(procedure)X
+3279(is)X
+3354(repeated)X
+3649(depth-\256rst)X
+4000(for)X
+4116(seven)X
+755 1236(hops)N
+930(from)X
+1110(the)X
+1232(original)X
+1505(part,)X
+1674(for)X
+1792(a)X
+1852(total)X
+2018(of)X
+2109(3280)X
+2293(parts.)X
+2513(Backward)X
+2862(traversal)X
+3162(also)X
+3314(exists,)X
+3539(and)X
+3678(follows)X
+3941(all)X
+4044(connec-)X
+755 1326(tions)N
+930(into)X
+1074(a)X
+1130(given)X
+1328(part)X
+1473(to)X
+1555(their)X
+1722(origin.)X
+10 f
+635 1449(g)N
+2 f
+755(Insert)X
+1 f
+962(adds)X
+1129(100)X
+1269(new)X
+1423(parts)X
+1599(and)X
+1735(their)X
+1902(connections.)X
+755 1572(The)N
+913(benchmark)X
+1303(is)X
+1389(single-user,)X
+1794(but)X
+1929(multi-user)X
+2291(access)X
+2530(controls)X
+2821(\(locking)X
+3120(and)X
+3268(transaction)X
+3652(protection\))X
+4036(must)X
+4223(be)X
+555 1662(enforced.)N
+898(It)X
+968(is)X
+1042(designed)X
+1348(to)X
+1431(be)X
+1528(run)X
+1656(on)X
+1757(a)X
+1814(database)X
+2112(with)X
+2275(20,000)X
+2516(parts,)X
+2713(and)X
+2850(on)X
+2951(one)X
+3087(with)X
+3249(200,000)X
+3529(parts.)X
+3745(Because)X
+4033(we)X
+4147(have)X
+555 1752(insuf\256cient)N
+935(disk)X
+1088(space)X
+1287(for)X
+1401(the)X
+1519(larger)X
+1727(database,)X
+2044(we)X
+2158(report)X
+2370(results)X
+2599(only)X
+2761(for)X
+2875(the)X
+2993(20,000)X
+3233(part)X
+3378(database.)X
+3 f
+555 1938(5.2.1.)N
+775(Implementation)X
+1 f
+755 2061(The)N
+920(LIBTP)X
+1182(implementation)X
+1724(of)X
+1831(OO1)X
+2027(uses)X
+2205(the)X
+2342(TCL)X
+2532([OUST90])X
+2914(interface)X
+3235(described)X
+3582(earlier.)X
+3867(The)X
+4031(backend)X
+555 2151(accepts)N
+813(commands)X
+1181(over)X
+1345(an)X
+1442(IP)X
+1534(socket)X
+1760(and)X
+1897(performs)X
+2208(the)X
+2327(requested)X
+2656(database)X
+2954(actions.)X
+3242(The)X
+3387(frontend)X
+3679(opens)X
+3886(and)X
+4022(executes)X
+555 2241(a)N
+618(TCL)X
+796(script.)X
+1041(This)X
+1210(script)X
+1415(contains)X
+1709(database)X
+2013(accesses)X
+2313(interleaved)X
+2697(with)X
+2866(ordinary)X
+3165(program)X
+3463(control)X
+3716(statements.)X
+4120(Data-)X
+555 2331(base)N
+718(commands)X
+1085(are)X
+1204(submitted)X
+1539(to)X
+1621(the)X
+1739(backend)X
+2027(and)X
+2163(results)X
+2392(are)X
+2511(bound)X
+2731(to)X
+2813(program)X
+3105(variables.)X
+755 2454(The)N
+903(parts)X
+1082(table)X
+1261(was)X
+1409(stored)X
+1628(as)X
+1718(a)X
+1776(B-tree)X
+1999(indexed)X
+2275(by)X
+2 f
+2377(id)X
+1 f
+2439(.)X
+2501(The)X
+2648(connection)X
+3022(table)X
+3200(was)X
+3347(stored)X
+3565(as)X
+3654(a)X
+3712(set)X
+3823(of)X
+3912(\256xed-length)X
+555 2544(records)N
+824(using)X
+1029(the)X
+1159(4.4BSD)X
+1446(recno)X
+1657(access)X
+1895(method.)X
+2207(In)X
+2306(addition,)X
+2620(two)X
+2771(B-tree)X
+3003(indices)X
+3261(were)X
+3449(maintained)X
+3836(on)X
+3947(connection)X
+555 2634(table)N
+732(entries.)X
+1007(One)X
+1162(index)X
+1360(mapped)X
+1634(the)X
+2 f
+1752(from)X
+1 f
+1923(\256eld)X
+2085(to)X
+2167(a)X
+2223(connection)X
+2595(record)X
+2821(number,)X
+3106(and)X
+3242(the)X
+3360(other)X
+3545(mapped)X
+3819(the)X
+2 f
+3937(to)X
+1 f
+4019(\256eld)X
+4181(to)X
+4263(a)X
+555 2724(connection)N
+932(record)X
+1163(number.)X
+1473(These)X
+1690(indices)X
+1941(support)X
+2205(fast)X
+2345(lookups)X
+2622(on)X
+2726(connections)X
+3133(in)X
+3219(both)X
+3385(directions.)X
+3765(For)X
+3900(the)X
+4022(traversal)X
+555 2814(tests,)N
+743(the)X
+867(frontend)X
+1165(does)X
+1338(an)X
+1439(index)X
+1642(lookup)X
+1889(to)X
+1976(discover)X
+2273(the)X
+2396(connected)X
+2747(part's)X
+2 f
+2955(id)X
+1 f
+3017(,)X
+3062(and)X
+3203(then)X
+3366(does)X
+3538(another)X
+3804(lookup)X
+4051(to)X
+4138(fetch)X
+555 2904(the)N
+673(part)X
+818(itself.)X
+3 f
+555 3090(5.2.2.)N
+775(Performance)X
+1242(Measurements)X
+1766(for)X
+1889(OO1)X
+1 f
+755 3213(We)N
+888(compare)X
+1186(LIBTP's)X
+1487(OO1)X
+1664(performance)X
+2092(to)X
+2174(that)X
+2314(reported)X
+2602(in)X
+2684([CATT91].)X
+3087(Those)X
+3303(results)X
+3532(were)X
+3709(collected)X
+4019(on)X
+4119(a)X
+4175(Sun)X
+555 3303(3/280)N
+759(\(25)X
+888(MHz)X
+1075(MC68020\))X
+1448(with)X
+1612(16)X
+1714(MBytes)X
+1989(of)X
+2078(memory)X
+2367(and)X
+2505(two)X
+2647(Hitachi)X
+2904(892MByte)X
+3267(disks)X
+3452(\(15)X
+3580(ms)X
+3694(average)X
+3966(seek)X
+4130(time\))X
+555 3393(behind)N
+793(an)X
+889(SMD-4)X
+1149(controller.)X
+1521(Frontends)X
+1861(ran)X
+1984(on)X
+2084(an)X
+2180(8MByte)X
+2462(Sun)X
+2606(3/260.)X
+755 3516(In)N
+844(order)X
+1036(to)X
+1120(measure)X
+1410(performance)X
+1839(on)X
+1941(a)X
+1999(machine)X
+2293(of)X
+2382(roughly)X
+2653(equivalent)X
+3009(processor)X
+3339(power,)X
+3582(we)X
+3698(ran)X
+3822(one)X
+3959(set)X
+4069(of)X
+4157(tests)X
+555 3606(on)N
+666(a)X
+733(standalone)X
+1107(MC68030-based)X
+1671(HP300)X
+1923(\(33MHz)X
+2225(MC68030\).)X
+2646(The)X
+2801(database)X
+3108(was)X
+3263(stored)X
+3489(on)X
+3599(a)X
+3665(300MByte)X
+4037(HP7959)X
+555 3696(SCSI)N
+744(disk)X
+898(\(17)X
+1026(ms)X
+1139(average)X
+1410(seek)X
+1573(time\).)X
+1802(Since)X
+2000(this)X
+2135(machine)X
+2427(is)X
+2500(not)X
+2622(connected)X
+2968(to)X
+3050(a)X
+3106(network,)X
+3409(we)X
+3523(ran)X
+3646(local)X
+3822(tests)X
+3984(where)X
+4201(the)X
+555 3786(frontend)N
+855(and)X
+999(backend)X
+1295(run)X
+1430(on)X
+1538(the)X
+1664(same)X
+1856(machine.)X
+2195(We)X
+2334(compare)X
+2638(these)X
+2830(measurements)X
+3316(with)X
+3485(Cattell's)X
+3783(local)X
+3966(Sun)X
+4117(3/280)X
+555 3876(numbers.)N
+755 3999(Because)N
+1051(the)X
+1177(benchmark)X
+1562(requires)X
+1849(remote)X
+2100(access,)X
+2354(we)X
+2476(ran)X
+2607(another)X
+2876(set)X
+2993(of)X
+3088(tests)X
+3258(on)X
+3365(a)X
+3428(DECstation)X
+3828(5000/200)X
+4157(with)X
+555 4089(32M)N
+732(of)X
+825(memory)X
+1118(running)X
+1393(Ultrix)X
+1610(V4.0)X
+1794(and)X
+1936(a)X
+1998(DEC)X
+2184(1GByte)X
+2459(RZ57)X
+2666(SCSI)X
+2859(disk.)X
+3057(We)X
+3194(compare)X
+3496(the)X
+3619(local)X
+3800(performance)X
+4232(of)X
+555 4179(OO1)N
+734(on)X
+837(the)X
+958(DECstation)X
+1354(to)X
+1439(its)X
+1536(remote)X
+1781(performance.)X
+2250(For)X
+2383(the)X
+2503(remote)X
+2748(case,)X
+2929(we)X
+3045(ran)X
+3170(the)X
+3290(frontend)X
+3584(on)X
+3686(a)X
+3744(DECstation)X
+4139(3100)X
+555 4269(with)N
+717(16)X
+817(MBytes)X
+1090(of)X
+1177(main)X
+1357(memory.)X
+755 4392(The)N
+900(databases)X
+1228(tested)X
+1435(in)X
+1517([CATT91])X
+1880(are)X
+10 f
+635 4515(g)N
+1 f
+755(INDEX,)X
+1045(a)X
+1101(highly-optimized)X
+1672(access)X
+1898(method)X
+2158(package)X
+2442(developed)X
+2792(at)X
+2870(Sun)X
+3014(Microsystems.)X
+10 f
+635 4638(g)N
+1 f
+755(OODBMS,)X
+1137(a)X
+1193(beta)X
+1347(release)X
+1591(of)X
+1678(a)X
+1734(commercial)X
+2133(object-oriented)X
+2639(database)X
+2936(management)X
+3366(system.)X
+10 f
+635 4761(g)N
+1 f
+755(RDBMS,)X
+1076(a)X
+1133(UNIX-based)X
+1565(commercial)X
+1965(relational)X
+2289(data)X
+2444(manager)X
+2742(at)X
+2821(production)X
+3189(release.)X
+3474(The)X
+3620(OO1)X
+3797(implementation)X
+755 4851(used)N
+922(embedded)X
+1272(SQL)X
+1443(in)X
+1525(C.)X
+1638(Stored)X
+1867(procedures)X
+2240(were)X
+2417(de\256ned)X
+2673(to)X
+2755(reduce)X
+2990(client-server)X
+3412(traf\256c.)X
+755 4974(Table)N
+974(two)X
+1130(shows)X
+1366(the)X
+1500(measurements)X
+1995(from)X
+2187([CATT91])X
+2566(and)X
+2718(LIBTP)X
+2976(for)X
+3106(a)X
+3178(local)X
+3370(test)X
+3517(on)X
+3632(the)X
+3765(MC680x0-based)X
+555 5064(hardware.)N
+915(All)X
+1037(caches)X
+1272(are)X
+1391(cleared)X
+1644(before)X
+1870(each)X
+2038(test.)X
+2209(All)X
+2331(times)X
+2524(are)X
+2643(in)X
+2725(seconds.)X
+755 5187(Table)N
+960(two)X
+1102(shows)X
+1324(that)X
+1466(LIBTP)X
+1710(outperforms)X
+2123(the)X
+2242(commercial)X
+2642(relational)X
+2966(system,)X
+3229(but)X
+3352(is)X
+3426(slower)X
+3661(than)X
+3820(OODBMS)X
+4183(and)X
+555 5277(INDEX.)N
+872(Since)X
+1077(the)X
+1202(caches)X
+1444(were)X
+1628(cleared)X
+1888(at)X
+1973(the)X
+2098(start)X
+2263(of)X
+2356(each)X
+2530(test,)X
+2687(disk)X
+2846(throughput)X
+3223(is)X
+3302(critical)X
+3551(in)X
+3639(this)X
+3780(test.)X
+3957(The)X
+4108(single)X
+555 5367(SCSI)N
+749(HP)X
+877(drive)X
+1068(used)X
+1241(by)X
+1347(LIBTP)X
+1595(is)X
+1674(approximately)X
+2163(13%)X
+2336(slower)X
+2576(than)X
+2739(the)X
+2862(disks)X
+3051(used)X
+3223(in)X
+3310([CATT91])X
+3678(which)X
+3899(accounts)X
+4205(for)X
+555 5457(part)N
+700(of)X
+787(the)X
+905(difference.)X
+755 5580(OODBMS)N
+1118(and)X
+1255(INDEX)X
+1525(outperform)X
+1906(LIBTP)X
+2148(most)X
+2323(dramatically)X
+2744(on)X
+2844(traversal.)X
+3181(This)X
+3343(is)X
+3416(because)X
+3691(we)X
+3805(use)X
+3932(index)X
+4130(look-)X
+555 5670(ups)N
+689(to)X
+774(\256nd)X
+921(connections,)X
+1347(whereas)X
+1634(the)X
+1755(other)X
+1942(two)X
+2084(systems)X
+2359(use)X
+2488(a)X
+2546(link)X
+2692(access)X
+2920(method.)X
+3222(The)X
+3369(index)X
+3569(requires)X
+3850(us)X
+3943(to)X
+4027(examine)X
+
+15 p
+%%Page: 15 15
+10 s 10 xH 0 xS 1 f
+3 f
+1 f
+10 f
+555 679(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)N
+2 f
+606 769(Measure)N
+1 f
+1019(INDEX)X
+1389(OODBMS)X
+1851(RDBMS)X
+2250(LIBTP)X
+10 f
+555 771(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)N
+555 787(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)N
+1 f
+595 869(Lookup)N
+1114(5.4)X
+1490(12.9)X
+1950(27)X
+2291(27.2)X
+595 959(Traversal)N
+1074(13)X
+1530(9.8)X
+1950(90)X
+2291(47.3)X
+595 1049(Insert)N
+1114(7.4)X
+1530(1.5)X
+1950(22)X
+2331(9.7)X
+10 f
+555 1059(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)N
+555(c)X
+999(c)Y
+919(c)Y
+839(c)Y
+759(c)Y
+959 1059(c)N
+999(c)Y
+919(c)Y
+839(c)Y
+759(c)Y
+1329 1059(c)N
+999(c)Y
+919(c)Y
+839(c)Y
+759(c)Y
+1791 1059(c)N
+999(c)Y
+919(c)Y
+839(c)Y
+759(c)Y
+2190 1059(c)N
+999(c)Y
+919(c)Y
+839(c)Y
+759(c)Y
+2512 1059(c)N
+999(c)Y
+919(c)Y
+839(c)Y
+759(c)Y
+2618 679(i)N
+2629(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+2 f
+2829 769(Measure)N
+3401(Cache)X
+3726(Local)X
+4028(Remote)X
+1 f
+10 f
+2618 771(i)N
+2629(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+2618 787(i)N
+2629(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+2658 869(Lookup)N
+3401(cold)X
+3747(15.7)X
+4078(20.6)X
+3401 959(warm)N
+3787(7.8)X
+4078(12.4)X
+10 f
+2618 969(i)N
+2629(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+2658 1059(Forward)N
+2950(traversal)X
+3401(cold)X
+3747(28.4)X
+4078(52.6)X
+3401 1149(warm)N
+3747(23.5)X
+4078(47.4)X
+10 f
+2618 1159(i)N
+2629(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+2658 1249(Backward)N
+3004(traversal)X
+3401(cold)X
+3747(24.2)X
+4078(47.4)X
+3401 1339(warm)N
+3747(24.3)X
+4078(47.6)X
+10 f
+2618 1349(i)N
+2629(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+2658 1439(Insert)N
+3401(cold)X
+3787(7.5)X
+4078(10.3)X
+3401 1529(warm)N
+3787(6.7)X
+4078(10.9)X
+10 f
+2618 1539(i)N
+2629(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+2618(c)X
+1479(c)Y
+1399(c)Y
+1319(c)Y
+1239(c)Y
+1159(c)Y
+1079(c)Y
+999(c)Y
+919(c)Y
+839(c)Y
+759(c)Y
+3341 1539(c)N
+1479(c)Y
+1399(c)Y
+1319(c)Y
+1239(c)Y
+1159(c)Y
+1079(c)Y
+999(c)Y
+919(c)Y
+839(c)Y
+759(c)Y
+3666 1539(c)N
+1479(c)Y
+1399(c)Y
+1319(c)Y
+1239(c)Y
+1159(c)Y
+1079(c)Y
+999(c)Y
+919(c)Y
+839(c)Y
+759(c)Y
+3968 1539(c)N
+1479(c)Y
+1399(c)Y
+1319(c)Y
+1239(c)Y
+1159(c)Y
+1079(c)Y
+999(c)Y
+919(c)Y
+839(c)Y
+759(c)Y
+4309 1539(c)N
+1479(c)Y
+1399(c)Y
+1319(c)Y
+1239(c)Y
+1159(c)Y
+1079(c)Y
+999(c)Y
+919(c)Y
+839(c)Y
+759(c)Y
+3 f
+587 1785(Table)N
+823(2:)X
+931(Local)X
+1163(MC680x0)X
+1538(Performance)X
+2026(of)X
+2133(Several)X
+587 1875(Systems)N
+883(on)X
+987(OO1.)X
+2667 1785(Table)N
+2909(3:)X
+3023(Local)X
+3260(vs.)X
+3397(Remote)X
+3707(Performance)X
+4200(of)X
+2667 1875(LIBTP)N
+2926(on)X
+3030(OO1.)X
+1 f
+10 f
+555 1998(h)N
+579(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)X
+1 f
+555 2274(two)N
+696(disk)X
+850(pages,)X
+1074(but)X
+1197(the)X
+1316(links)X
+1492(require)X
+1741(only)X
+1904(one,)X
+2061(regardless)X
+2408(of)X
+2496(database)X
+2794(size.)X
+2980(Cattell)X
+3214(reports)X
+3458(that)X
+3599(lookups)X
+3873(using)X
+4067(B-trees)X
+555 2364(instead)N
+808(of)X
+901(links)X
+1082(makes)X
+1313(traversal)X
+1616(take)X
+1776(twice)X
+1976(as)X
+2069(long)X
+2237(in)X
+2325(INDEX.)X
+2641(Adding)X
+2907(a)X
+2969(link)X
+3119(access)X
+3351(method)X
+3617(to)X
+3 f
+3704(db)X
+1 f
+3792(\(3\))X
+3911(or)X
+4003(using)X
+4201(the)X
+555 2454(existing)N
+828(hash)X
+995(method)X
+1255(would)X
+1475(apparently)X
+1834(be)X
+1930(a)X
+1986(good)X
+2166(idea.)X
+755 2577(Both)N
+936(OODBMS)X
+1304(and)X
+1446(INDEX)X
+1722(issue)X
+1908 0.1944(coarser-granularity)AX
+2545(locks)X
+2739(than)X
+2902(LIBTP.)X
+3189(This)X
+3356(limits)X
+3562(concurrency)X
+3985(for)X
+4104(multi-)X
+555 2667(user)N
+711(applications,)X
+1140(but)X
+1264(helps)X
+1455(single-user)X
+1829(applications.)X
+2278(In)X
+2367(addition,)X
+2671(the)X
+2791(fact)X
+2934(that)X
+3076(LIBTP)X
+3319(releases)X
+3595(B-tree)X
+3817(locks)X
+4007(early)X
+4189(is)X
+4263(a)X
+555 2757(drawback)N
+896(in)X
+986(OO1.)X
+1210(Since)X
+1416(there)X
+1605(is)X
+1686(no)X
+1793(concurrency)X
+2218(in)X
+2307(the)X
+2432(benchmark,)X
+2836(high-concurrency)X
+3430(strategies)X
+3760(only)X
+3929(show)X
+4125(up)X
+4232(as)X
+555 2847(increased)N
+882(locking)X
+1145(overhead.)X
+1503(Finally,)X
+1772(the)X
+1892(architecture)X
+2294(of)X
+2383(the)X
+2503(LIBTP)X
+2747(implementation)X
+3271(was)X
+3418(substantially)X
+3844(different)X
+4143(from)X
+555 2937(that)N
+702(of)X
+796(either)X
+1006(OODBMS)X
+1375(or)X
+1469(INDEX.)X
+1786(Both)X
+1968(of)X
+2062(those)X
+2258(systems)X
+2538(do)X
+2645(the)X
+2770(searches)X
+3070(in)X
+3159(the)X
+3284(user's)X
+3503(address)X
+3771(space,)X
+3997(and)X
+4139(issue)X
+555 3027(requests)N
+844(for)X
+964(pages)X
+1173(to)X
+1260(the)X
+1383(server)X
+1605(process.)X
+1911(Pages)X
+2123(are)X
+2247(cached)X
+2496(in)X
+2583(the)X
+2706(client,)X
+2929(and)X
+3070(many)X
+3273(queries)X
+3530(can)X
+3667(be)X
+3768(satis\256ed)X
+4055(without)X
+555 3117(contacting)N
+910(the)X
+1029(server)X
+1247(at)X
+1326(all.)X
+1467(LIBTP)X
+1710(submits)X
+1979(all)X
+2080(the)X
+2199(queries)X
+2452(to)X
+2535(the)X
+2653(server)X
+2870(process,)X
+3151(and)X
+3287(receives)X
+3571(database)X
+3868(records)X
+4125(back;)X
+555 3207(it)N
+619(does)X
+786(no)X
+886(client)X
+1084(caching.)X
+755 3330(The)N
+911(RDBMS)X
+1221(architecture)X
+1632(is)X
+1716(much)X
+1925(closer)X
+2148(to)X
+2241(that)X
+2392(of)X
+2490(LIBTP.)X
+2783(A)X
+2872(server)X
+3100(process)X
+3372(receives)X
+3667(queries)X
+3930(and)X
+4076(returns)X
+555 3420(results)N
+786(to)X
+870(a)X
+928(client.)X
+1168(The)X
+1315(timing)X
+1545(results)X
+1776(in)X
+1860(table)X
+2038(two)X
+2180(clearly)X
+2421(show)X
+2612(that)X
+2754(the)X
+2874(conventional)X
+3309(database)X
+3607(client/server)X
+4025(model)X
+4246(is)X
+555 3510(expensive.)N
+941(LIBTP)X
+1188(outperforms)X
+1605(the)X
+1728(RDBMS)X
+2032(on)X
+2136(traversal)X
+2437(and)X
+2577(insertion.)X
+2921(We)X
+3057(speculate)X
+3380(that)X
+3524(this)X
+3663(is)X
+3740(due)X
+3880(in)X
+3966(part)X
+4115(to)X
+4201(the)X
+555 3600(overhead)N
+870(of)X
+957(query)X
+1160(parsing,)X
+1436(optimization,)X
+1880(and)X
+2016(repeated)X
+2309(interpretation)X
+2761(of)X
+2848(the)X
+2966(plan)X
+3124(tree)X
+3265(in)X
+3347(the)X
+3465(RDBMS')X
+3791(query)X
+3994(executor.)X
+755 3723(Table)N
+962(three)X
+1147(shows)X
+1371(the)X
+1492(differences)X
+1873(between)X
+2164(local)X
+2343(and)X
+2482(remote)X
+2728(execution)X
+3063(of)X
+3153(LIBTP's)X
+3456(OO1)X
+3635(implementation)X
+4160(on)X
+4263(a)X
+555 3813(DECstation.)N
+989(We)X
+1122(measured)X
+1451(performance)X
+1879(with)X
+2042(a)X
+2099(populated)X
+2436(\(warm\))X
+2694(cache)X
+2899(and)X
+3036(an)X
+3133(empty)X
+3354(\(cold\))X
+3567(cache.)X
+3812(Reported)X
+4126(times)X
+555 3903(are)N
+681(the)X
+806(means)X
+1037(of)X
+1130(twenty)X
+1374(tests,)X
+1562(and)X
+1704(are)X
+1829(in)X
+1917(seconds.)X
+2237(Standard)X
+2548(deviations)X
+2903(were)X
+3086(within)X
+3316(seven)X
+3525(percent)X
+3788(of)X
+3881(the)X
+4005(mean)X
+4205(for)X
+555 3993(remote,)N
+818(and)X
+954(two)X
+1094(percent)X
+1351(of)X
+1438(the)X
+1556(mean)X
+1750(for)X
+1864(local.)X
+755 4116(The)N
+914(20ms)X
+1121(overhead)X
+1450(of)X
+1551(TCP/IP)X
+1824(on)X
+1938(an)X
+2048(Ethernet)X
+2354(entirely)X
+2633(accounts)X
+2948(for)X
+3076(the)X
+3207(difference)X
+3567(in)X
+3662(speed.)X
+3918(The)X
+4076(remote)X
+555 4206(traversal)N
+857(times)X
+1055(are)X
+1179(nearly)X
+1405(double)X
+1648(the)X
+1771(local)X
+1952(times)X
+2150(because)X
+2430(we)X
+2549(do)X
+2653(index)X
+2855(lookups)X
+3132(and)X
+3272(part)X
+3421(fetches)X
+3673(in)X
+3759(separate)X
+4047(queries.)X
+555 4296(It)N
+629(would)X
+854(make)X
+1053(sense)X
+1252(to)X
+1339(do)X
+1444(indexed)X
+1723(searches)X
+2021(on)X
+2126(the)X
+2248(server,)X
+2489(but)X
+2615(we)X
+2733(were)X
+2914(unwilling)X
+3244(to)X
+3330(hard-code)X
+3676(knowledge)X
+4052(of)X
+4143(OO1)X
+555 4386(indices)N
+803(into)X
+948(our)X
+1075(LIBTP)X
+1317(TCL)X
+1488(server.)X
+1745(Cold)X
+1920(and)X
+2056(warm)X
+2259(insertion)X
+2559(times)X
+2752(are)X
+2871(identical)X
+3167(since)X
+3352(insertions)X
+3683(do)X
+3783(not)X
+3905(bene\256t)X
+4143(from)X
+555 4476(caching.)N
+755 4599(One)N
+915(interesting)X
+1279(difference)X
+1632(shown)X
+1867(by)X
+1973(table)X
+2155(three)X
+2342(is)X
+2421(the)X
+2545(cost)X
+2700(of)X
+2793(forward)X
+3074(versus)X
+3305(backward)X
+3644(traversal.)X
+3987(When)X
+4205(we)X
+555 4689(built)N
+725(the)X
+847(database,)X
+1168(we)X
+1285(inserted)X
+1562(parts)X
+1741(in)X
+1826(part)X
+2 f
+1974(id)X
+1 f
+2059(order.)X
+2292(We)X
+2427(built)X
+2596(the)X
+2717(indices)X
+2967(at)X
+3048(the)X
+3169(same)X
+3357(time.)X
+3562(Therefore,)X
+3923(the)X
+4044(forward)X
+555 4779(index)N
+757(had)X
+897(keys)X
+1068(inserted)X
+1346(in)X
+1432(order,)X
+1646(while)X
+1848(the)X
+1970(backward)X
+2307(index)X
+2509(had)X
+2649(keys)X
+2820(inserted)X
+3098(more)X
+3286(randomly.)X
+3656(In-order)X
+3943(insertion)X
+4246(is)X
+555 4885(pessimal)N
+858(for)X
+975(B-tree)X
+1199(indices,)X
+1469(so)X
+1563(the)X
+1684(forward)X
+1962(index)X
+2163(is)X
+2239(much)X
+2440(larger)X
+2651(than)X
+2812(the)X
+2933(backward)X
+3269(one)X
+7 s
+3385 4853(5)N
+10 s
+4885(.)Y
+3476(This)X
+3640(larger)X
+3850(size)X
+3997(shows)X
+4219(up)X
+555 4975(as)N
+642(extra)X
+823(disk)X
+976(reads)X
+1166(in)X
+1248(the)X
+1366(cold)X
+1524(benchmark.)X
+3 f
+555 5161(6.)N
+655(Conclusions)X
+1 f
+755 5284(LIBTP)N
+1006(provides)X
+1311(the)X
+1438(basic)X
+1632(building)X
+1927(blocks)X
+2165(to)X
+2256(support)X
+2525(transaction)X
+2906(protection.)X
+3300(In)X
+3396(comparison)X
+3799(with)X
+3970(traditional)X
+555 5374(Unix)N
+746(libraries)X
+1040(and)X
+1187(commercial)X
+1597(systems,)X
+1900(it)X
+1974(offers)X
+2192(a)X
+2258(variety)X
+2511(of)X
+2608(tradeoffs.)X
+2964(Using)X
+3185(complete)X
+3509(transaction)X
+3891(protection)X
+4246(is)X
+555 5464(more)N
+747(complicated)X
+1166(than)X
+1331(simply)X
+1575(adding)X
+3 f
+1820(fsync)X
+1 f
+1998(\(2\))X
+2119(and)X
+3 f
+2262(\257ock)X
+1 f
+2426(\(2\))X
+2547(calls)X
+2721(to)X
+2810(code,)X
+3008(but)X
+3136(it)X
+3206(is)X
+3285(faster)X
+3490(in)X
+3578(some)X
+3773(cases)X
+3969(and)X
+4111(offers)X
+8 s
+10 f
+555 5536(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)N
+5 s
+1 f
+727 5614(5)N
+8 s
+763 5639(The)N
+878(next)X
+1004(release)X
+1196(of)X
+1265(the)X
+1359(4.4BSD)X
+1580(access)X
+1758(method)X
+1966(will)X
+2082(automatically)X
+2446(detect)X
+2614(and)X
+2722(compensate)X
+3039(for)X
+3129(in-order)X
+3350(insertion,)X
+3606(eliminating)X
+3914(this)X
+4023(problem.)X
+
+16 p
+%%Page: 16 16
+8 s 8 xH 0 xS 1 f
+10 s
+3 f
+1 f
+555 630(stricter)N
+801(guarantees)X
+1168(\(atomicity,)X
+1540(consistency,)X
+1957(isolation,)X
+2275(and)X
+2414(durability\).)X
+2815(If)X
+2892(the)X
+3013(data)X
+3170(to)X
+3255(be)X
+3354(protected)X
+3676(are)X
+3798(already)X
+4058(format-)X
+555 720(ted)N
+675(\()X
+2 f
+702(i.e.)X
+1 f
+821(use)X
+949(one)X
+1086(of)X
+1174(the)X
+1293(database)X
+1591(access)X
+1818(methods\),)X
+2157(then)X
+2316(adding)X
+2555(transaction)X
+2928(protection)X
+3274(requires)X
+3554(no)X
+3655(additional)X
+3996(complex-)X
+555 810(ity,)N
+679(but)X
+801(incurs)X
+1017(a)X
+1073(performance)X
+1500(penalty)X
+1756(of)X
+1843(approximately)X
+2326(15%.)X
+755 933(In)N
+844(comparison)X
+1240(with)X
+1404(commercial)X
+1805(database)X
+2104(systems,)X
+2399(the)X
+2519(tradeoffs)X
+2827(are)X
+2948(more)X
+3135(complex.)X
+3473(LIBTP)X
+3717(does)X
+3886(not)X
+4009(currently)X
+555 1023(support)N
+825(a)X
+891(standard)X
+1193(query)X
+1406(language.)X
+1766(The)X
+1921(TCL-based)X
+2312(server)X
+2539(process)X
+2810(allows)X
+3049(a)X
+3115(certain)X
+3364(ease)X
+3533(of)X
+3630(use)X
+3767(which)X
+3993(would)X
+4223(be)X
+555 1113(enhanced)N
+882(with)X
+1047(a)X
+1106(more)X
+1294(user-friendly)X
+1732(interface)X
+2037(\()X
+2 f
+2064(e.g.)X
+1 f
+2203(a)X
+2261(windows)X
+2572(based)X
+2777(query-by-form)X
+3272(application\),)X
+3697(for)X
+3813(which)X
+4031(we)X
+4147(have)X
+555 1203(a)N
+620(working)X
+916(prototype.)X
+1292(When)X
+1513(accesses)X
+1815(do)X
+1924(not)X
+2055(require)X
+2312(sophisticated)X
+2758(query)X
+2969(processing,)X
+3360(the)X
+3486(TCL)X
+3665(interface)X
+3975(is)X
+4056(an)X
+4160(ade-)X
+555 1293(quate)N
+756(solution.)X
+1080(What)X
+1281(LIBTP)X
+1529(fails)X
+1693(to)X
+1781(provide)X
+2052(in)X
+2140(functionality,)X
+2595(it)X
+2665(makes)X
+2896(up)X
+3002(for)X
+3122(in)X
+3210(performance)X
+3643(and)X
+3785(\257exibility.)X
+4161(Any)X
+555 1383(application)N
+931(may)X
+1089(make)X
+1283(use)X
+1410(of)X
+1497(its)X
+1592(record)X
+1818(interface)X
+2120(or)X
+2207(the)X
+2325(more)X
+2510(primitive)X
+2823(log,)X
+2965(lock,)X
+3143(and)X
+3279(buffer)X
+3496(calls.)X
+755 1506(Future)N
+987(work)X
+1175(will)X
+1322(focus)X
+1519(on)X
+1621(overcoming)X
+2026(some)X
+2217(of)X
+2306(the)X
+2426(areas)X
+2614(in)X
+2698(which)X
+2916(LIBTP)X
+3160(is)X
+3235(currently)X
+3547(de\256cient)X
+3845(and)X
+3983(extending)X
+555 1596(its)N
+652(transaction)X
+1026(model.)X
+1288(The)X
+1435(addition)X
+1719(of)X
+1808(an)X
+1905(SQL)X
+2077(parser)X
+2295(and)X
+2432(forms)X
+2640(front)X
+2817(end)X
+2954(will)X
+3099(improve)X
+3387(the)X
+3506(system's)X
+3807(ease)X
+3967(of)X
+4055(use)X
+4183(and)X
+555 1686(make)N
+750(it)X
+815(more)X
+1001(competitive)X
+1400(with)X
+1563(commercial)X
+1963(systems.)X
+2277(In)X
+2365(the)X
+2484(long)X
+2647(term,)X
+2835(we)X
+2950(would)X
+3170(like)X
+3310(to)X
+3392(add)X
+3528(generalized)X
+3919(hierarchical)X
+555 1776(locking,)N
+836(nested)X
+1062(transactions,)X
+1486(parallel)X
+1748(transactions,)X
+2171(passing)X
+2431(of)X
+2518(transactions)X
+2921(between)X
+3209(processes,)X
+3557(and)X
+3693(distributed)X
+4055(commit)X
+555 1866(handling.)N
+900(In)X
+992(the)X
+1115(short)X
+1300(term,)X
+1492(the)X
+1614(next)X
+1776(step)X
+1929(is)X
+2006(to)X
+2092(integrate)X
+2397(LIBTP)X
+2643(with)X
+2809(the)X
+2931(most)X
+3110(recent)X
+3331(release)X
+3579(of)X
+3670(the)X
+3792(database)X
+4093(access)X
+555 1956(routines)N
+833(and)X
+969(make)X
+1163(it)X
+1227(freely)X
+1435(available)X
+1745(via)X
+1863(anonymous)X
+2252(ftp.)X
+3 f
+555 2142(7.)N
+655(Acknowledgements)X
+1 f
+755 2265(We)N
+888(would)X
+1109(like)X
+1250(to)X
+1332(thank)X
+1530(John)X
+1701(Wilkes)X
+1948(and)X
+2084(Carl)X
+2242(Staelin)X
+2484(of)X
+2571(Hewlett-Packard)X
+3131(Laboratories)X
+3557(and)X
+3693(Jon)X
+3824(Krueger.)X
+4148(John)X
+555 2355(and)N
+694(Carl)X
+855(provided)X
+1162(us)X
+1255(with)X
+1419(an)X
+1517(extra)X
+1700(disk)X
+1855(for)X
+1971(the)X
+2091(HP)X
+2215(testbed)X
+2464(less)X
+2606(than)X
+2766(24)X
+2868(hours)X
+3068(after)X
+3238(we)X
+3354(requested)X
+3684(it.)X
+3770(Jon)X
+3903(spent)X
+4094(count-)X
+555 2445(less)N
+699(hours)X
+901(helping)X
+1164(us)X
+1258(understand)X
+1633(the)X
+1754(intricacies)X
+2107(of)X
+2197(commercial)X
+2599(database)X
+2899(products)X
+3198(and)X
+3337(their)X
+3507(behavior)X
+3811(under)X
+4017(a)X
+4076(variety)X
+555 2535(of)N
+642(system)X
+884(con\256gurations.)X
+3 f
+555 2721(8.)N
+655(References)X
+1 f
+555 2901([ANDR89])N
+942(Andrade,)X
+1265(J.,)X
+1361(Carges,)X
+1629(M.,)X
+1765(Kovach,)X
+2060(K.,)X
+2183(``Building)X
+2541(an)X
+2642(On-Line)X
+2939(Transaction)X
+3343(Processing)X
+3715(System)X
+3975(On)X
+4098(UNIX)X
+727 2991(System)N
+982(V'',)X
+2 f
+1134(CommUNIXations)X
+1 f
+1725(,)X
+1765 0.2188(November/December)AX
+2477(1989.)X
+555 3171([BAY77])N
+878(Bayer,)X
+1110(R.,)X
+1223(Schkolnick,)X
+1623(M.,)X
+1754(``Concurrency)X
+2243(of)X
+2330(Operations)X
+2702(on)X
+2802(B-Trees'',)X
+2 f
+3155(Acta)X
+3322(Informatica)X
+1 f
+3700(,)X
+3740(1977.)X
+555 3351([BERN80])N
+936(Bernstein,)X
+1297(P.,)X
+1415(Goodman,)X
+1785(N.,)X
+1917(``Timestamp)X
+2365(Based)X
+2595(Algorithms)X
+2992(for)X
+3119(Concurrency)X
+3567(Control)X
+3844(in)X
+3939(Distributed)X
+727 3441(Database)N
+1042(Systems'',)X
+2 f
+1402(Proceedings)X
+1823(6th)X
+1945(International)X
+2387(Conference)X
+2777(on)X
+2877(Very)X
+3049(Large)X
+3260(Data)X
+3440(Bases)X
+1 f
+3627(,)X
+3667(October)X
+3946(1980.)X
+555 3621([BSD91])N
+864(DB\(3\),)X
+2 f
+1109(4.4BSD)X
+1376(Unix)X
+1552(Programmer's)X
+2044(Manual)X
+2313(Reference)X
+2655(Guide)X
+1 f
+2851(,)X
+2891(University)X
+3249(of)X
+3336(California,)X
+3701(Berkeley,)X
+4031(1991.)X
+555 3801([CATT91])N
+923(Cattell,)X
+1181(R.G.G.,)X
+1455(``An)X
+1632(Engineering)X
+2049(Database)X
+2369(Benchmark'',)X
+2 f
+2838(The)X
+2983(Benchmark)X
+3373(Handbook)X
+3731(for)X
+3848(Database)X
+4179(and)X
+727 3891(Transaction)N
+1133(Processing)X
+1509(Systems)X
+1 f
+1763(,)X
+1803(J.)X
+1874(Gray,)X
+2075(editor,)X
+2302(Morgan)X
+2576(Kaufman)X
+2895(1991.)X
+555 4071([CHEN91])N
+929(Cheng,)X
+1180(E.,)X
+1291(Chang,)X
+1542(E.,)X
+1653(Klein,)X
+1872(J.,)X
+1964(Lee,)X
+2126(D.,)X
+2245(Lu,)X
+2375(E.,)X
+2485(Lutgardo,)X
+2820(A.,)X
+2939(Obermarck,)X
+3342(R.,)X
+3456(``An)X
+3629(Open)X
+3824(and)X
+3961(Extensible)X
+727 4161(Event-Based)N
+1157(Transaction)X
+1556(Manager'',)X
+2 f
+1936(Proceedings)X
+2357(1991)X
+2537(Summer)X
+2820(Usenix)X
+1 f
+3043(,)X
+3083(Nashville,)X
+3430(TN,)X
+3577(June)X
+3744(1991.)X
+555 4341([CHOU85])N
+943(Chou,)X
+1163(H.,)X
+1288(DeWitt,)X
+1570(D.,)X
+1694(``An)X
+1872(Evaluation)X
+2245(of)X
+2338(Buffer)X
+2574(Management)X
+3019(Strategies)X
+3361(for)X
+3481(Relational)X
+3836(Database)X
+4157(Sys-)X
+727 4431(tems'',)N
+2 f
+972(Proceedings)X
+1393(of)X
+1475(the)X
+1593(11th)X
+1755(International)X
+2197(Conference)X
+2587(on)X
+2687(Very)X
+2859(Large)X
+3070(Databases)X
+1 f
+3408(,)X
+3448(1985.)X
+555 4611([DEWI84])N
+925(DeWitt,)X
+1207(D.,)X
+1331(Katz,)X
+1529(R.,)X
+1648(Olken,)X
+1890(F.,)X
+2000(Shapiro,)X
+2295(L.,)X
+2410(Stonebraker,)X
+2843(M.,)X
+2979(Wood,)X
+3220(D.,)X
+3343(``Implementation)X
+3929(Techniques)X
+727 4701(for)N
+841(Main)X
+1030(Memory)X
+1326(Database)X
+1641(Systems'',)X
+2 f
+2001(Proceedings)X
+2422(of)X
+2504(SIGMOD)X
+1 f
+2812(,)X
+2852(pp.)X
+2972(1-8,)X
+3119(June)X
+3286(1984.)X
+555 4881([GRAY76])N
+944(Gray,)X
+1153(J.,)X
+1252(Lorie,)X
+1474(R.,)X
+1595(Putzolu,)X
+1887(F.,)X
+1999(and)X
+2143(Traiger,)X
+2428(I.,)X
+2522(``Granularity)X
+2973(of)X
+3067(locks)X
+3263(and)X
+3406(degrees)X
+3679(of)X
+3773(consistency)X
+4174(in)X
+4263(a)X
+727 4971(large)N
+909(shared)X
+1140(data)X
+1295(base'',)X
+2 f
+1533(Modeling)X
+1861(in)X
+1944(Data)X
+2125(Base)X
+2301(Management)X
+2740(Systems)X
+1 f
+2994(,)X
+3034(Elsevier)X
+3317(North)X
+3524(Holland,)X
+3822(New)X
+3994(York,)X
+4199(pp.)X
+727 5061(365-394.)N
+555 5241([HAER83])N
+931(Haerder,)X
+1235(T.)X
+1348(Reuter,)X
+1606(A.)X
+1728(``Principles)X
+2126(of)X
+2217(Transaction-Oriented)X
+2928(Database)X
+3246(Recovery'',)X
+2 f
+3651(Computing)X
+4029(Surveys)X
+1 f
+4279(,)X
+727 5331(15\(4\);)N
+943(237-318,)X
+1250(1983.)X
+555 5511([KUNG81])N
+943(Kung,)X
+1162(H.)X
+1261(T.,)X
+1371(Richardson,)X
+1777(J.,)X
+1869(``On)X
+2042(Optimistic)X
+2400(Methods)X
+2701(for)X
+2816(Concurrency)X
+3252(Control'',)X
+2 f
+3591(ACM)X
+3781(Transactions)X
+4219(on)X
+727 5601(Database)N
+1054(Systems)X
+1 f
+1328(6\(2\);)X
+1504(213-226,)X
+1811(1981.)X
+
+17 p
+%%Page: 17 17
+10 s 10 xH 0 xS 1 f
+3 f
+1 f
+555 630([LEHM81])N
+939(Lehman,)X
+1245(P.,)X
+1352(Yao,)X
+1529(S.,)X
+1636(``Ef\256cient)X
+1989(Locking)X
+2279(for)X
+2396(Concurrent)X
+2780(Operations)X
+3155(on)X
+3258(B-trees'',)X
+2 f
+3587(ACM)X
+3779(Transactions)X
+4219(on)X
+727 720(Database)N
+1054(Systems)X
+1 f
+1308(,)X
+1348(6\(4\),)X
+1522(December)X
+1873(1981.)X
+555 900([MOHA91])N
+964(Mohan,)X
+1241(C.,)X
+1364(Pirahesh,)X
+1690(H.,)X
+1818(``ARIES-RRH:)X
+2366(Restricted)X
+2721(Repeating)X
+3076(of)X
+3173(History)X
+3442(in)X
+3533(the)X
+3660(ARIES)X
+3920(Transaction)X
+727 990(Recovery)N
+1055(Method'',)X
+2 f
+1398(Proceedings)X
+1819(7th)X
+1941(International)X
+2383(Conference)X
+2773(on)X
+2873(Data)X
+3053(Engineering)X
+1 f
+3449(,)X
+3489(Kobe,)X
+3703(Japan,)X
+3926(April)X
+4115(1991.)X
+555 1170([NODI90])N
+914(Nodine,)X
+1194(M.,)X
+1328(Zdonik,)X
+1602(S.,)X
+1709(``Cooperative)X
+2178(Transaction)X
+2580(Hierarchies:)X
+2996(A)X
+3077(Transaction)X
+3479(Model)X
+3711(to)X
+3796(Support)X
+4072(Design)X
+727 1260(Applications'',)N
+2 f
+1242(Proceedings)X
+1675(16th)X
+1849(International)X
+2303(Conference)X
+2704(on)X
+2815(Very)X
+2998(Large)X
+3220(Data)X
+3411(Bases)X
+1 f
+3598(,)X
+3649(Brisbane,)X
+3985(Australia,)X
+727 1350(August)N
+978(1990.)X
+555 1530([OUST90])N
+923(Ousterhout,)X
+1324(J.,)X
+1420(``Tcl:)X
+1648(An)X
+1771(Embeddable)X
+2197(Command)X
+2555(Language'',)X
+2 f
+2971(Proceedings)X
+3396(1990)X
+3580(Winter)X
+3822(Usenix)X
+1 f
+4045(,)X
+4089(Wash-)X
+727 1620(ington,)N
+971(D.C.,)X
+1162(January)X
+1432(1990.)X
+555 1800([POSIX91])N
+955(``Unapproved)X
+1441(Draft)X
+1645(for)X
+1773(Realtime)X
+2096(Extension)X
+2450(for)X
+2578(Portable)X
+2879(Operating)X
+3234(Systems'',)X
+3608(Draft)X
+3812(11,)X
+3946(October)X
+4239(7,)X
+727 1890(1991,)N
+927(IEEE)X
+1121(Computer)X
+1461(Society.)X
+555 2070([ROSE91])N
+925(Rosenblum,)X
+1341(M.,)X
+1484(Ousterhout,)X
+1892(J.,)X
+1995(``The)X
+2206(Design)X
+2464(and)X
+2611(Implementation)X
+3149(of)X
+3247(a)X
+3314(Log-Structured)X
+3835(File)X
+3990(System'',)X
+2 f
+727 2160(Proceedings)N
+1148(of)X
+1230(the)X
+1348(13th)X
+1510(Symposium)X
+1895(on)X
+1995(Operating)X
+2344(Systems)X
+2618(Principles)X
+1 f
+2947(,)X
+2987(1991.)X
+555 2340([SELT91])N
+904(Seltzer,)X
+1171(M.,)X
+1306(Stonebraker,)X
+1738(M.,)X
+1873(``Read)X
+2116(Optimized)X
+2478(File)X
+2626(Systems:)X
+2938(A)X
+3020(Performance)X
+3454(Evaluation'',)X
+2 f
+3898(Proceedings)X
+727 2430(7th)N
+849(Annual)X
+1100(International)X
+1542(Conference)X
+1932(on)X
+2032(Data)X
+2212(Engineering)X
+1 f
+2608(,)X
+2648(Kobe,)X
+2862(Japan,)X
+3085(April)X
+3274(1991.)X
+555 2610([SPEC88])N
+907(Spector,)X
+1200(Rausch,)X
+1484(Bruell,)X
+1732(``Camelot:)X
+2107(A)X
+2192(Flexible,)X
+2501(Distributed)X
+2888(Transaction)X
+3294(Processing)X
+3668(System'',)X
+2 f
+4004(Proceed-)X
+727 2700(ings)N
+880(of)X
+962(Spring)X
+1195(COMPCON)X
+1606(1988)X
+1 f
+(,)S
+1806(February)X
+2116(1988.)X
+555 2880([SQL86])N
+862(American)X
+1201(National)X
+1499(Standards)X
+1836(Institute,)X
+2139(``Database)X
+2509(Language)X
+2847(SQL'',)X
+3093(ANSI)X
+3301(X3.135-1986)X
+3747(\(ISO)X
+3924(9075\),)X
+4152(May)X
+727 2970(1986.)N
+555 3150([STON81])N
+919(Stonebraker,)X
+1348(M.,)X
+1480(``Operating)X
+1876(System)X
+2132(Support)X
+2406(for)X
+2520(Database)X
+2835(Management'',)X
+2 f
+3348(Communications)X
+3910(of)X
+3992(the)X
+4110(ACM)X
+1 f
+4279(,)X
+727 3240(1981.)N
+555 3420([SULL92])N
+925(Sullivan,)X
+1247(M.,)X
+1394(Olson,)X
+1641(M.,)X
+1788(``An)X
+1976(Index)X
+2195(Implementation)X
+2737(Supporting)X
+3127(Fast)X
+3295(Recovery)X
+3638(for)X
+3767(the)X
+3900(POSTGRES)X
+727 3510(Storage)N
+1014(System'',)X
+1365(to)X
+1469(appear)X
+1726(in)X
+2 f
+1830(Proceedings)X
+2272(8th)X
+2415(Annual)X
+2687(International)X
+3150(Conference)X
+3561(on)X
+3682(Data)X
+3883(Engineering)X
+1 f
+4279(,)X
+727 3600(Tempe,)N
+990(Arizona,)X
+1289(February)X
+1599(1992.)X
+555 3780([TPCB90])N
+914(Transaction)X
+1319(Processing)X
+1692(Performance)X
+2129(Council,)X
+2428(``TPC)X
+2653(Benchmark)X
+3048(B'',)X
+3200(Standard)X
+3510(Speci\256cation,)X
+3973(Waterside)X
+727 3870(Associates,)N
+1110(Fremont,)X
+1421(CA.,)X
+1592(1990.)X
+555 4050([YOUN91])N
+947(Young,)X
+1211(M.)X
+1328(W.,)X
+1470(Thompson,)X
+1858(D.)X
+1962(S.,)X
+2072(Jaffe,)X
+2274(E.,)X
+2388(``A)X
+2525(Modular)X
+2826(Architecture)X
+3253(for)X
+3372(Distributed)X
+3757(Transaction)X
+4161(Pro-)X
+727 4140(cessing'',)N
+2 f
+1057(Proceedings)X
+1478(1991)X
+1658(Winter)X
+1896(Usenix)X
+1 f
+2119(,)X
+2159(Dallas,)X
+2404(TX,)X
+2551(January)X
+2821(1991.)X
+3 f
+755 4263(Margo)N
+1008(I.)X
+1080(Seltzer)X
+1 f
+1338(is)X
+1411(a)X
+1467(Ph.D.)X
+1669(student)X
+1920(in)X
+2002(the)X
+2120(Department)X
+2519(of)X
+2606(Electrical)X
+2934(Engineering)X
+3346(and)X
+3482(Computer)X
+3822(Sciences)X
+4123(at)X
+4201(the)X
+555 4353(University)N
+919(of)X
+1012(California,)X
+1383(Berkeley.)X
+1739(Her)X
+1886(research)X
+2181(interests)X
+2474(include)X
+2735(\256le)X
+2862(systems,)X
+3160(databases,)X
+3513(and)X
+3654(transaction)X
+4031(process-)X
+555 4443(ing)N
+686(systems.)X
+1008(She)X
+1157(spent)X
+1355(several)X
+1612(years)X
+1811(working)X
+2107(at)X
+2194(startup)X
+2441(companies)X
+2813(designing)X
+3153(and)X
+3298(implementing)X
+3771(\256le)X
+3902(systems)X
+4183(and)X
+555 4533(transaction)N
+929(processing)X
+1294(software)X
+1592(and)X
+1729(designing)X
+2061(microprocessors.)X
+2648(Ms.)X
+2791(Seltzer)X
+3035(received)X
+3329(her)X
+3453(AB)X
+3585(in)X
+3668(Applied)X
+3947(Mathemat-)X
+555 4623(ics)N
+664(from)X
+840 0.1953(Harvard/Radcliffe)AX
+1445(College)X
+1714(in)X
+1796(1983.)X
+755 4746(In)N
+845(her)X
+971(spare)X
+1163(time,)X
+1347(Margo)X
+1583(can)X
+1717(usually)X
+1970(be)X
+2068(found)X
+2277(preparing)X
+2607(massive)X
+2887(quantities)X
+3220(of)X
+3309(food)X
+3478(for)X
+3594(hungry)X
+3843(hordes,)X
+4099(study-)X
+555 4836(ing)N
+677(Japanese,)X
+1003(or)X
+1090(playing)X
+1350(soccer)X
+1576(with)X
+1738(an)X
+1834(exciting)X
+2112(Bay)X
+2261(Area)X
+2438(Women's)X
+2770(Soccer)X
+3009(team,)X
+3205(the)X
+3323(Berkeley)X
+3633(Bruisers.)X
+3 f
+755 5049(Michael)N
+1056(A.)X
+1159(Olson)X
+1 f
+1383(is)X
+1461(a)X
+1522(Master's)X
+1828(student)X
+2084(in)X
+2170(the)X
+2292(Department)X
+2695(of)X
+2786(Electrical)X
+3118(Engineering)X
+3534(and)X
+3674(Computer)X
+4018(Sciences)X
+555 5139(at)N
+645(the)X
+774(University)X
+1143(of)X
+1241(California,)X
+1617(Berkeley.)X
+1978(His)X
+2120(primary)X
+2405(interests)X
+2703(are)X
+2833(database)X
+3141(systems)X
+3425(and)X
+3572(mass)X
+3763(storage)X
+4026(systems.)X
+555 5229(Mike)N
+759(spent)X
+963(two)X
+1118(years)X
+1323(working)X
+1625(for)X
+1754(a)X
+1825(commercial)X
+2239(database)X
+2551(system)X
+2808(vendor)X
+3066(before)X
+3307(joining)X
+3567(the)X
+3699(Postgres)X
+4004(Research)X
+555 5319(Group)N
+780(at)X
+858(Berkeley)X
+1168(in)X
+1250(1988.)X
+1470(He)X
+1584(received)X
+1877(his)X
+1990(B.A.)X
+2161(in)X
+2243(Computer)X
+2583(Science)X
+2853(from)X
+3029(Berkeley)X
+3339(in)X
+3421(May)X
+3588(1991.)X
+755 5442(Mike)N
+945(only)X
+1108(recently)X
+1388(transferred)X
+1758(into)X
+1903(Sin)X
+2030(City,)X
+2208(but)X
+2330(is)X
+2403(rapidly)X
+2650(adopting)X
+2950(local)X
+3126(customs)X
+3408(and)X
+3544(coloration.)X
+3929(In)X
+4016(his)X
+4129(spare)X
+555 5532(time,)N
+742(he)X
+843(organizes)X
+1176(informal)X
+1477(Friday)X
+1711(afternoon)X
+2043(study)X
+2240(groups)X
+2482(to)X
+2568(discuss)X
+2823(recent)X
+3044(technical)X
+3358(and)X
+3498(economic)X
+3834(developments.)X
+555 5622(Among)N
+815(his)X
+928(hobbies)X
+1197(are)X
+1316(Charles)X
+1581(Dickens,)X
+1884(Red)X
+2033(Rock,)X
+2242(and)X
+2378(speaking)X
+2683(Dutch)X
+2899(to)X
+2981(anyone)X
+3233(who)X
+3391(will)X
+3535(permit)X
+3764(it.)X
+
+17 p
+%%Trailer
+xt
+
+xs
+
diff --git a/lib/libc/db/hash/Makefile.inc b/lib/libc/db/hash/Makefile.inc
new file mode 100644
index 000000000000..e1be7a565a2c
--- /dev/null
+++ b/lib/libc/db/hash/Makefile.inc
@@ -0,0 +1,7 @@
+# from @(#)Makefile.inc 8.1 (Berkeley) 6/4/93
+# $FreeBSD$
+
+.PATH: ${LIBC_SRCTOP}/db/hash
+
+SRCS+= hash.c hash_bigkey.c hash_buf.c hash_func.c hash_log2.c \
+ hash_page.c ndbm.c
diff --git a/lib/libc/db/hash/README b/lib/libc/db/hash/README
new file mode 100644
index 000000000000..80d674396c0a
--- /dev/null
+++ b/lib/libc/db/hash/README
@@ -0,0 +1,69 @@
+# @(#)README 8.1 (Berkeley) 6/4/93
+# $FreeBSD$
+
+This package implements a superset of the hsearch and dbm/ndbm libraries.
+
+Test Programs:
+ All test programs which need key/data pairs expect them entered
+ with key and data on separate lines
+
+ tcreat3.c
+ Takes
+ bucketsize (bsize),
+ fill factor (ffactor), and
+ initial number of elements (nelem).
+ Creates a hash table named hashtest containing the
+ keys/data pairs entered from standard in.
+ thash4.c
+ Takes
+ bucketsize (bsize),
+ fill factor (ffactor),
+ initial number of elements (nelem)
+ bytes of cache (ncached), and
+ file from which to read data (fname)
+ Creates a table from the key/data pairs on standard in and
+ then does a read of each key/data in fname
+ tdel.c
+ Takes
+ bucketsize (bsize), and
+ fill factor (ffactor).
+ file from which to read data (fname)
+ Reads each key/data pair from fname and deletes the
+ key from the hash table hashtest
+ tseq.c
+ Reads the key/data pairs in the file hashtest and writes them
+ to standard out.
+ tread2.c
+ Takes
+ butes of cache (ncached).
+ Reads key/data pairs from standard in and looks them up
+ in the file hashtest.
+ tverify.c
+ Reads key/data pairs from standard in, looks them up
+ in the file hashtest, and verifies that the data is
+ correct.
+
+NOTES:
+
+The man page ../man/db.3 explains the interface to the hashing system.
+The file hash.ps is a postscript copy of a paper explaining
+the history, implementation, and performance of the hash package.
+
+"bugs" or idiosyncracies
+
+If you have a lot of overflows, it is possible to run out of overflow
+pages. Currently, this will cause a message to be printed on stderr.
+Eventually, this will be indicated by a return error code.
+
+If you are using the ndbm interface and exit without flushing or closing the
+file, you may lose updates since the package buffers all writes. Also,
+the db interface only creates a single database file. To avoid overwriting
+the user's original file, the suffix ".db" is appended to the file name
+passed to dbm_open. Additionally, if your code "knows" about the historic
+.dir and .pag files, it will break.
+
+There is a fundamental difference between this package and the old hsearch.
+Hsearch requires the user to maintain the keys and data in the application's
+allocated memory while hash takes care of all storage management. The down
+side is that the byte strings passed in the ENTRY structure must be null
+terminated (both the keys and the data).
diff --git a/lib/libc/db/hash/extern.h b/lib/libc/db/hash/extern.h
new file mode 100644
index 000000000000..c75c0ac66fc4
--- /dev/null
+++ b/lib/libc/db/hash/extern.h
@@ -0,0 +1,62 @@
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)extern.h 8.4 (Berkeley) 6/16/94
+ * $FreeBSD$
+ */
+
+BUFHEAD *__add_ovflpage(HTAB *, BUFHEAD *);
+int __addel(HTAB *, BUFHEAD *, const DBT *, const DBT *);
+int __big_delete(HTAB *, BUFHEAD *);
+int __big_insert(HTAB *, BUFHEAD *, const DBT *, const DBT *);
+int __big_keydata(HTAB *, BUFHEAD *, DBT *, DBT *, int);
+int __big_return(HTAB *, BUFHEAD *, int, DBT *, int);
+int __big_split(HTAB *, BUFHEAD *, BUFHEAD *, BUFHEAD *,
+ int, u_int32_t, SPLIT_RETURN *);
+int __buf_free(HTAB *, int, int);
+void __buf_init(HTAB *, int);
+u_int32_t __call_hash(HTAB *, char *, int);
+int __delpair(HTAB *, BUFHEAD *, int);
+int __expand_table(HTAB *);
+int __find_bigpair(HTAB *, BUFHEAD *, int, char *, int);
+u_int16_t __find_last_page(HTAB *, BUFHEAD **);
+void __free_ovflpage(HTAB *, BUFHEAD *);
+BUFHEAD *__get_buf(HTAB *, u_int32_t, BUFHEAD *, int);
+int __get_page(HTAB *, char *, u_int32_t, int, int, int);
+int __ibitmap(HTAB *, int, int, int);
+u_int32_t __log2(u_int32_t);
+int __put_page(HTAB *, char *, u_int32_t, int, int);
+void __reclaim_buf(HTAB *, BUFHEAD *);
+int __split_page(HTAB *, u_int32_t, u_int32_t);
+
+/* Default hash routine. */
+extern u_int32_t (*__default_hash)(const void *, size_t);
+
+#ifdef HASH_STATISTICS
+extern int hash_accesses, hash_collisions, hash_expansions, hash_overflows;
+#endif
diff --git a/lib/libc/db/hash/hash.c b/lib/libc/db/hash/hash.c
new file mode 100644
index 000000000000..c7dc4e78b595
--- /dev/null
+++ b/lib/libc/db/hash/hash.c
@@ -0,0 +1,967 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Margo Seltzer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)hash.c 8.9 (Berkeley) 6/16/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#ifdef DEBUG
+#include <assert.h>
+#endif
+#include "un-namespace.h"
+
+#include <db.h>
+#include "hash.h"
+#include "page.h"
+#include "extern.h"
+
+static int alloc_segs(HTAB *, int);
+static int flush_meta(HTAB *);
+static int hash_access(HTAB *, ACTION, DBT *, DBT *);
+static int hash_close(DB *);
+static int hash_delete(const DB *, const DBT *, u_int32_t);
+static int hash_fd(const DB *);
+static int hash_get(const DB *, const DBT *, DBT *, u_int32_t);
+static int hash_put(const DB *, DBT *, const DBT *, u_int32_t);
+static void *hash_realloc(SEGMENT **, int, int);
+static int hash_seq(const DB *, DBT *, DBT *, u_int32_t);
+static int hash_sync(const DB *, u_int32_t);
+static int hdestroy(HTAB *);
+static HTAB *init_hash(HTAB *, const char *, const HASHINFO *);
+static int init_htab(HTAB *, int);
+#if BYTE_ORDER == LITTLE_ENDIAN
+static void swap_header(HTAB *);
+static void swap_header_copy(HASHHDR *, HASHHDR *);
+#endif
+
+/* Fast arithmetic, relying on powers of 2, */
+#define MOD(x, y) ((x) & ((y) - 1))
+
+#define RETURN_ERROR(ERR, LOC) { save_errno = ERR; goto LOC; }
+
+/* Return values */
+#define SUCCESS (0)
+#define ERROR (-1)
+#define ABNORMAL (1)
+
+#ifdef HASH_STATISTICS
+int hash_accesses, hash_collisions, hash_expansions, hash_overflows;
+#endif
+
+/************************** INTERFACE ROUTINES ***************************/
+/* OPEN/CLOSE */
+
+/* ARGSUSED */
+DB *
+__hash_open(const char *file, int flags, int mode,
+ const HASHINFO *info, /* Special directives for create */
+ int dflags)
+{
+ HTAB *hashp;
+ struct stat statbuf;
+ DB *dbp;
+ int bpages, hdrsize, new_table, nsegs, save_errno;
+
+ if ((flags & O_ACCMODE) == O_WRONLY) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ if (!(hashp = (HTAB *)calloc(1, sizeof(HTAB))))
+ return (NULL);
+ hashp->fp = -1;
+
+ /*
+ * Even if user wants write only, we need to be able to read
+ * the actual file, so we need to open it read/write. But, the
+ * field in the hashp structure needs to be accurate so that
+ * we can check accesses.
+ */
+ hashp->flags = flags;
+
+ if (file) {
+ if ((hashp->fp = _open(file, flags | O_CLOEXEC, mode)) == -1)
+ RETURN_ERROR(errno, error0);
+ new_table = _fstat(hashp->fp, &statbuf) == 0 &&
+ statbuf.st_size == 0 && (flags & O_ACCMODE) != O_RDONLY;
+ } else
+ new_table = 1;
+
+ if (new_table) {
+ if (!(hashp = init_hash(hashp, file, info)))
+ RETURN_ERROR(errno, error1);
+ } else {
+ /* Table already exists */
+ if (info && info->hash)
+ hashp->hash = info->hash;
+ else
+ hashp->hash = __default_hash;
+
+ hdrsize = _read(hashp->fp, &hashp->hdr, sizeof(HASHHDR));
+#if BYTE_ORDER == LITTLE_ENDIAN
+ swap_header(hashp);
+#endif
+ if (hdrsize == -1)
+ RETURN_ERROR(errno, error1);
+ if (hdrsize != sizeof(HASHHDR))
+ RETURN_ERROR(EFTYPE, error1);
+ /* Verify file type, versions and hash function */
+ if (hashp->MAGIC != HASHMAGIC)
+ RETURN_ERROR(EFTYPE, error1);
+#define OLDHASHVERSION 1
+ if (hashp->VERSION != HASHVERSION &&
+ hashp->VERSION != OLDHASHVERSION)
+ RETURN_ERROR(EFTYPE, error1);
+ if ((int32_t)hashp->hash(CHARKEY, sizeof(CHARKEY)) != hashp->H_CHARKEY)
+ RETURN_ERROR(EFTYPE, error1);
+ /*
+ * Figure out how many segments we need. Max_Bucket is the
+ * maximum bucket number, so the number of buckets is
+ * max_bucket + 1.
+ */
+ nsegs = howmany(hashp->MAX_BUCKET + 1, hashp->SGSIZE);
+ if (alloc_segs(hashp, nsegs))
+ /*
+ * If alloc_segs fails, table will have been destroyed
+ * and errno will have been set.
+ */
+ return (NULL);
+ /* Read in bitmaps */
+ bpages = (hashp->SPARES[hashp->OVFL_POINT] +
+ (hashp->BSIZE << BYTE_SHIFT) - 1) >>
+ (hashp->BSHIFT + BYTE_SHIFT);
+
+ hashp->nmaps = bpages;
+ (void)memset(&hashp->mapp[0], 0, bpages * sizeof(u_int32_t *));
+ }
+
+ /* Initialize Buffer Manager */
+ if (info && info->cachesize)
+ __buf_init(hashp, info->cachesize);
+ else
+ __buf_init(hashp, DEF_BUFSIZE);
+
+ hashp->new_file = new_table;
+ hashp->save_file = file && (hashp->flags & O_RDWR);
+ hashp->cbucket = -1;
+ if (!(dbp = (DB *)malloc(sizeof(DB)))) {
+ save_errno = errno;
+ hdestroy(hashp);
+ errno = save_errno;
+ return (NULL);
+ }
+ dbp->internal = hashp;
+ dbp->close = hash_close;
+ dbp->del = hash_delete;
+ dbp->fd = hash_fd;
+ dbp->get = hash_get;
+ dbp->put = hash_put;
+ dbp->seq = hash_seq;
+ dbp->sync = hash_sync;
+ dbp->type = DB_HASH;
+
+#ifdef DEBUG
+ (void)fprintf(stderr,
+"%s\n%s%p\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%x\n%s%x\n%s%d\n%s%d\n",
+ "init_htab:",
+ "TABLE POINTER ", hashp,
+ "BUCKET SIZE ", hashp->BSIZE,
+ "BUCKET SHIFT ", hashp->BSHIFT,
+ "DIRECTORY SIZE ", hashp->DSIZE,
+ "SEGMENT SIZE ", hashp->SGSIZE,
+ "SEGMENT SHIFT ", hashp->SSHIFT,
+ "FILL FACTOR ", hashp->FFACTOR,
+ "MAX BUCKET ", hashp->MAX_BUCKET,
+ "OVFL POINT ", hashp->OVFL_POINT,
+ "LAST FREED ", hashp->LAST_FREED,
+ "HIGH MASK ", hashp->HIGH_MASK,
+ "LOW MASK ", hashp->LOW_MASK,
+ "NSEGS ", hashp->nsegs,
+ "NKEYS ", hashp->NKEYS);
+#endif
+#ifdef HASH_STATISTICS
+ hash_overflows = hash_accesses = hash_collisions = hash_expansions = 0;
+#endif
+ return (dbp);
+
+error1:
+ if (hashp != NULL)
+ (void)_close(hashp->fp);
+
+error0:
+ free(hashp);
+ errno = save_errno;
+ return (NULL);
+}
+
+static int
+hash_close(DB *dbp)
+{
+ HTAB *hashp;
+ int retval;
+
+ if (!dbp)
+ return (ERROR);
+
+ hashp = (HTAB *)dbp->internal;
+ retval = hdestroy(hashp);
+ free(dbp);
+ return (retval);
+}
+
+static int
+hash_fd(const DB *dbp)
+{
+ HTAB *hashp;
+
+ if (!dbp)
+ return (ERROR);
+
+ hashp = (HTAB *)dbp->internal;
+ if (hashp->fp == -1) {
+ errno = ENOENT;
+ return (-1);
+ }
+ return (hashp->fp);
+}
+
+/************************** LOCAL CREATION ROUTINES **********************/
+static HTAB *
+init_hash(HTAB *hashp, const char *file, const HASHINFO *info)
+{
+ struct stat statbuf;
+ int nelem;
+
+ nelem = 1;
+ hashp->NKEYS = 0;
+ hashp->LORDER = BYTE_ORDER;
+ hashp->BSIZE = DEF_BUCKET_SIZE;
+ hashp->BSHIFT = DEF_BUCKET_SHIFT;
+ hashp->SGSIZE = DEF_SEGSIZE;
+ hashp->SSHIFT = DEF_SEGSIZE_SHIFT;
+ hashp->DSIZE = DEF_DIRSIZE;
+ hashp->FFACTOR = DEF_FFACTOR;
+ hashp->hash = __default_hash;
+ memset(hashp->SPARES, 0, sizeof(hashp->SPARES));
+ memset(hashp->BITMAPS, 0, sizeof (hashp->BITMAPS));
+
+ /* Fix bucket size to be optimal for file system */
+ if (file != NULL) {
+ if (stat(file, &statbuf))
+ return (NULL);
+ hashp->BSIZE = statbuf.st_blksize;
+ if (hashp->BSIZE > MAX_BSIZE)
+ hashp->BSIZE = MAX_BSIZE;
+ hashp->BSHIFT = __log2(hashp->BSIZE);
+ }
+
+ if (info) {
+ if (info->bsize) {
+ /* Round pagesize up to power of 2 */
+ hashp->BSHIFT = __log2(info->bsize);
+ hashp->BSIZE = 1 << hashp->BSHIFT;
+ if (hashp->BSIZE > MAX_BSIZE) {
+ errno = EINVAL;
+ return (NULL);
+ }
+ }
+ if (info->ffactor)
+ hashp->FFACTOR = info->ffactor;
+ if (info->hash)
+ hashp->hash = info->hash;
+ if (info->nelem)
+ nelem = info->nelem;
+ if (info->lorder) {
+ if (info->lorder != BIG_ENDIAN &&
+ info->lorder != LITTLE_ENDIAN) {
+ errno = EINVAL;
+ return (NULL);
+ }
+ hashp->LORDER = info->lorder;
+ }
+ }
+ /* init_htab should destroy the table and set errno if it fails */
+ if (init_htab(hashp, nelem))
+ return (NULL);
+ else
+ return (hashp);
+}
+/*
+ * This calls alloc_segs which may run out of memory. Alloc_segs will destroy
+ * the table and set errno, so we just pass the error information along.
+ *
+ * Returns 0 on No Error
+ */
+static int
+init_htab(HTAB *hashp, int nelem)
+{
+ int nbuckets, nsegs, l2;
+
+ /*
+ * Divide number of elements by the fill factor and determine a
+ * desired number of buckets. Allocate space for the next greater
+ * power of two number of buckets.
+ */
+ nelem = (nelem - 1) / hashp->FFACTOR + 1;
+
+ l2 = __log2(MAX(nelem, 2));
+ nbuckets = 1 << l2;
+
+ hashp->SPARES[l2] = l2 + 1;
+ hashp->SPARES[l2 + 1] = l2 + 1;
+ hashp->OVFL_POINT = l2;
+ hashp->LAST_FREED = 2;
+
+ /* First bitmap page is at: splitpoint l2 page offset 1 */
+ if (__ibitmap(hashp, OADDR_OF(l2, 1), l2 + 1, 0))
+ return (-1);
+
+ hashp->MAX_BUCKET = hashp->LOW_MASK = nbuckets - 1;
+ hashp->HIGH_MASK = (nbuckets << 1) - 1;
+ hashp->HDRPAGES = ((MAX(sizeof(HASHHDR), MINHDRSIZE) - 1) >>
+ hashp->BSHIFT) + 1;
+
+ nsegs = (nbuckets - 1) / hashp->SGSIZE + 1;
+ nsegs = 1 << __log2(nsegs);
+
+ if (nsegs > hashp->DSIZE)
+ hashp->DSIZE = nsegs;
+ return (alloc_segs(hashp, nsegs));
+}
+
+/********************** DESTROY/CLOSE ROUTINES ************************/
+
+/*
+ * Flushes any changes to the file if necessary and destroys the hashp
+ * structure, freeing all allocated space.
+ */
+static int
+hdestroy(HTAB *hashp)
+{
+ int i, save_errno;
+
+ save_errno = 0;
+
+#ifdef HASH_STATISTICS
+ (void)fprintf(stderr, "hdestroy: accesses %ld collisions %ld\n",
+ hash_accesses, hash_collisions);
+ (void)fprintf(stderr, "hdestroy: expansions %ld\n",
+ hash_expansions);
+ (void)fprintf(stderr, "hdestroy: overflows %ld\n",
+ hash_overflows);
+ (void)fprintf(stderr, "keys %ld maxp %d segmentcount %d\n",
+ hashp->NKEYS, hashp->MAX_BUCKET, hashp->nsegs);
+
+ for (i = 0; i < NCACHED; i++)
+ (void)fprintf(stderr,
+ "spares[%d] = %d\n", i, hashp->SPARES[i]);
+#endif
+ /*
+ * Call on buffer manager to free buffers, and if required,
+ * write them to disk.
+ */
+ if (__buf_free(hashp, 1, hashp->save_file))
+ save_errno = errno;
+ if (hashp->dir) {
+ free(*hashp->dir); /* Free initial segments */
+ /* Free extra segments */
+ while (hashp->exsegs--)
+ free(hashp->dir[--hashp->nsegs]);
+ free(hashp->dir);
+ }
+ if (flush_meta(hashp) && !save_errno)
+ save_errno = errno;
+ /* Free Bigmaps */
+ for (i = 0; i < hashp->nmaps; i++)
+ if (hashp->mapp[i])
+ free(hashp->mapp[i]);
+ if (hashp->tmp_key)
+ free(hashp->tmp_key);
+ if (hashp->tmp_buf)
+ free(hashp->tmp_buf);
+
+ if (hashp->fp != -1) {
+ if (hashp->save_file)
+ (void)_fsync(hashp->fp);
+ (void)_close(hashp->fp);
+ }
+
+ free(hashp);
+
+ if (save_errno) {
+ errno = save_errno;
+ return (ERROR);
+ }
+ return (SUCCESS);
+}
+/*
+ * Write modified pages to disk
+ *
+ * Returns:
+ * 0 == OK
+ * -1 ERROR
+ */
+static int
+hash_sync(const DB *dbp, u_int32_t flags)
+{
+ HTAB *hashp;
+
+ if (flags != 0) {
+ errno = EINVAL;
+ return (ERROR);
+ }
+
+ if (!dbp)
+ return (ERROR);
+
+ hashp = (HTAB *)dbp->internal;
+ if (!hashp->save_file)
+ return (0);
+ if (__buf_free(hashp, 0, 1) || flush_meta(hashp))
+ return (ERROR);
+ if (hashp->fp != -1 && _fsync(hashp->fp) != 0)
+ return (ERROR);
+ hashp->new_file = 0;
+ return (0);
+}
+
+/*
+ * Returns:
+ * 0 == OK
+ * -1 indicates that errno should be set
+ */
+static int
+flush_meta(HTAB *hashp)
+{
+ HASHHDR *whdrp;
+#if BYTE_ORDER == LITTLE_ENDIAN
+ HASHHDR whdr;
+#endif
+ int fp, i, wsize;
+
+ if (!hashp->save_file)
+ return (0);
+ hashp->MAGIC = HASHMAGIC;
+ hashp->VERSION = HASHVERSION;
+ hashp->H_CHARKEY = hashp->hash(CHARKEY, sizeof(CHARKEY));
+
+ fp = hashp->fp;
+ whdrp = &hashp->hdr;
+#if BYTE_ORDER == LITTLE_ENDIAN
+ whdrp = &whdr;
+ swap_header_copy(&hashp->hdr, whdrp);
+#endif
+ if ((wsize = pwrite(fp, whdrp, sizeof(HASHHDR), (off_t)0)) == -1)
+ return (-1);
+ else
+ if (wsize != sizeof(HASHHDR)) {
+ errno = EFTYPE;
+ hashp->error = errno;
+ return (-1);
+ }
+ for (i = 0; i < NCACHED; i++)
+ if (hashp->mapp[i])
+ if (__put_page(hashp, (char *)hashp->mapp[i],
+ hashp->BITMAPS[i], 0, 1))
+ return (-1);
+ return (0);
+}
+
+/*******************************SEARCH ROUTINES *****************************/
+/*
+ * All the access routines return
+ *
+ * Returns:
+ * 0 on SUCCESS
+ * 1 to indicate an external ERROR (i.e. key not found, etc)
+ * -1 to indicate an internal ERROR (i.e. out of memory, etc)
+ */
+static int
+hash_get(const DB *dbp, const DBT *key, DBT *data, u_int32_t flag)
+{
+ HTAB *hashp;
+
+ hashp = (HTAB *)dbp->internal;
+ if (flag) {
+ hashp->error = errno = EINVAL;
+ return (ERROR);
+ }
+ return (hash_access(hashp, HASH_GET, (DBT *)key, data));
+}
+
+static int
+hash_put(const DB *dbp, DBT *key, const DBT *data, u_int32_t flag)
+{
+ HTAB *hashp;
+
+ hashp = (HTAB *)dbp->internal;
+ if (flag && flag != R_NOOVERWRITE) {
+ hashp->error = errno = EINVAL;
+ return (ERROR);
+ }
+ if ((hashp->flags & O_ACCMODE) == O_RDONLY) {
+ hashp->error = errno = EPERM;
+ return (ERROR);
+ }
+ return (hash_access(hashp, flag == R_NOOVERWRITE ?
+ HASH_PUTNEW : HASH_PUT, (DBT *)key, (DBT *)data));
+}
+
+static int
+hash_delete(const DB *dbp, const DBT *key,
+ u_int32_t flag) /* Ignored */
+{
+ HTAB *hashp;
+
+ hashp = (HTAB *)dbp->internal;
+ if (flag && flag != R_CURSOR) {
+ hashp->error = errno = EINVAL;
+ return (ERROR);
+ }
+ if ((hashp->flags & O_ACCMODE) == O_RDONLY) {
+ hashp->error = errno = EPERM;
+ return (ERROR);
+ }
+ return (hash_access(hashp, HASH_DELETE, (DBT *)key, NULL));
+}
+
+/*
+ * Assume that hashp has been set in wrapper routine.
+ */
+static int
+hash_access(HTAB *hashp, ACTION action, DBT *key, DBT *val)
+{
+ BUFHEAD *rbufp;
+ BUFHEAD *bufp, *save_bufp;
+ u_int16_t *bp;
+ int n, ndx, off, size;
+ char *kp;
+ u_int16_t pageno;
+
+#ifdef HASH_STATISTICS
+ hash_accesses++;
+#endif
+
+ off = hashp->BSIZE;
+ size = key->size;
+ kp = (char *)key->data;
+ rbufp = __get_buf(hashp, __call_hash(hashp, kp, size), NULL, 0);
+ if (!rbufp)
+ return (ERROR);
+ save_bufp = rbufp;
+
+ /* Pin the bucket chain */
+ rbufp->flags |= BUF_PIN;
+ for (bp = (u_int16_t *)rbufp->page, n = *bp++, ndx = 1; ndx < n;)
+ if (bp[1] >= REAL_KEY) {
+ /* Real key/data pair */
+ if (size == off - *bp &&
+ memcmp(kp, rbufp->page + *bp, size) == 0)
+ goto found;
+ off = bp[1];
+#ifdef HASH_STATISTICS
+ hash_collisions++;
+#endif
+ bp += 2;
+ ndx += 2;
+ } else if (bp[1] == OVFLPAGE) {
+ rbufp = __get_buf(hashp, *bp, rbufp, 0);
+ if (!rbufp) {
+ save_bufp->flags &= ~BUF_PIN;
+ return (ERROR);
+ }
+ /* FOR LOOP INIT */
+ bp = (u_int16_t *)rbufp->page;
+ n = *bp++;
+ ndx = 1;
+ off = hashp->BSIZE;
+ } else if (bp[1] < REAL_KEY) {
+ if ((ndx =
+ __find_bigpair(hashp, rbufp, ndx, kp, size)) > 0)
+ goto found;
+ if (ndx == -2) {
+ bufp = rbufp;
+ if (!(pageno =
+ __find_last_page(hashp, &bufp))) {
+ ndx = 0;
+ rbufp = bufp;
+ break; /* FOR */
+ }
+ rbufp = __get_buf(hashp, pageno, bufp, 0);
+ if (!rbufp) {
+ save_bufp->flags &= ~BUF_PIN;
+ return (ERROR);
+ }
+ /* FOR LOOP INIT */
+ bp = (u_int16_t *)rbufp->page;
+ n = *bp++;
+ ndx = 1;
+ off = hashp->BSIZE;
+ } else {
+ save_bufp->flags &= ~BUF_PIN;
+ return (ERROR);
+ }
+ }
+
+ /* Not found */
+ switch (action) {
+ case HASH_PUT:
+ case HASH_PUTNEW:
+ if (__addel(hashp, rbufp, key, val)) {
+ save_bufp->flags &= ~BUF_PIN;
+ return (ERROR);
+ } else {
+ save_bufp->flags &= ~BUF_PIN;
+ return (SUCCESS);
+ }
+ case HASH_GET:
+ case HASH_DELETE:
+ default:
+ save_bufp->flags &= ~BUF_PIN;
+ return (ABNORMAL);
+ }
+
+found:
+ switch (action) {
+ case HASH_PUTNEW:
+ save_bufp->flags &= ~BUF_PIN;
+ return (ABNORMAL);
+ case HASH_GET:
+ bp = (u_int16_t *)rbufp->page;
+ if (bp[ndx + 1] < REAL_KEY) {
+ if (__big_return(hashp, rbufp, ndx, val, 0))
+ return (ERROR);
+ } else {
+ val->data = (u_char *)rbufp->page + (int)bp[ndx + 1];
+ val->size = bp[ndx] - bp[ndx + 1];
+ }
+ break;
+ case HASH_PUT:
+ if ((__delpair(hashp, rbufp, ndx)) ||
+ (__addel(hashp, rbufp, key, val))) {
+ save_bufp->flags &= ~BUF_PIN;
+ return (ERROR);
+ }
+ break;
+ case HASH_DELETE:
+ if (__delpair(hashp, rbufp, ndx))
+ return (ERROR);
+ break;
+ default:
+ abort();
+ }
+ save_bufp->flags &= ~BUF_PIN;
+ return (SUCCESS);
+}
+
+static int
+hash_seq(const DB *dbp, DBT *key, DBT *data, u_int32_t flag)
+{
+ u_int32_t bucket;
+ BUFHEAD *bufp;
+ HTAB *hashp;
+ u_int16_t *bp, ndx;
+
+ hashp = (HTAB *)dbp->internal;
+ if (flag && flag != R_FIRST && flag != R_NEXT) {
+ hashp->error = errno = EINVAL;
+ return (ERROR);
+ }
+#ifdef HASH_STATISTICS
+ hash_accesses++;
+#endif
+ if ((hashp->cbucket < 0) || (flag == R_FIRST)) {
+ hashp->cbucket = 0;
+ hashp->cndx = 1;
+ hashp->cpage = NULL;
+ }
+next_bucket:
+ for (bp = NULL; !bp || !bp[0]; ) {
+ if (!(bufp = hashp->cpage)) {
+ for (bucket = hashp->cbucket;
+ bucket <= hashp->MAX_BUCKET;
+ bucket++, hashp->cndx = 1) {
+ bufp = __get_buf(hashp, bucket, NULL, 0);
+ if (!bufp)
+ return (ERROR);
+ hashp->cpage = bufp;
+ bp = (u_int16_t *)bufp->page;
+ if (bp[0])
+ break;
+ }
+ hashp->cbucket = bucket;
+ if ((u_int32_t)hashp->cbucket > hashp->MAX_BUCKET) {
+ hashp->cbucket = -1;
+ return (ABNORMAL);
+ }
+ } else {
+ bp = (u_int16_t *)hashp->cpage->page;
+ if (flag == R_NEXT || flag == 0) {
+ hashp->cndx += 2;
+ if (hashp->cndx > bp[0]) {
+ hashp->cpage = NULL;
+ hashp->cbucket++;
+ hashp->cndx = 1;
+ goto next_bucket;
+ }
+ }
+ }
+
+#ifdef DEBUG
+ assert(bp);
+ assert(bufp);
+#endif
+ while (bp[hashp->cndx + 1] == OVFLPAGE) {
+ bufp = hashp->cpage =
+ __get_buf(hashp, bp[hashp->cndx], bufp, 0);
+ if (!bufp)
+ return (ERROR);
+ bp = (u_int16_t *)(bufp->page);
+ hashp->cndx = 1;
+ }
+ if (!bp[0]) {
+ hashp->cpage = NULL;
+ ++hashp->cbucket;
+ }
+ }
+ ndx = hashp->cndx;
+ if (bp[ndx + 1] < REAL_KEY) {
+ if (__big_keydata(hashp, bufp, key, data, 1))
+ return (ERROR);
+ } else {
+ if (hashp->cpage == NULL)
+ return (ERROR);
+ key->data = (u_char *)hashp->cpage->page + bp[ndx];
+ key->size = (ndx > 1 ? bp[ndx - 1] : hashp->BSIZE) - bp[ndx];
+ data->data = (u_char *)hashp->cpage->page + bp[ndx + 1];
+ data->size = bp[ndx] - bp[ndx + 1];
+ }
+ return (SUCCESS);
+}
+
+/********************************* UTILITIES ************************/
+
+/*
+ * Returns:
+ * 0 ==> OK
+ * -1 ==> Error
+ */
+int
+__expand_table(HTAB *hashp)
+{
+ u_int32_t old_bucket, new_bucket;
+ int dirsize, new_segnum, spare_ndx;
+
+#ifdef HASH_STATISTICS
+ hash_expansions++;
+#endif
+ new_bucket = ++hashp->MAX_BUCKET;
+ old_bucket = (hashp->MAX_BUCKET & hashp->LOW_MASK);
+
+ new_segnum = new_bucket >> hashp->SSHIFT;
+
+ /* Check if we need a new segment */
+ if (new_segnum >= hashp->nsegs) {
+ /* Check if we need to expand directory */
+ if (new_segnum >= hashp->DSIZE) {
+ /* Reallocate directory */
+ dirsize = hashp->DSIZE * sizeof(SEGMENT *);
+ if (!hash_realloc(&hashp->dir, dirsize, dirsize << 1))
+ return (-1);
+ hashp->DSIZE = dirsize << 1;
+ }
+ if ((hashp->dir[new_segnum] =
+ calloc(hashp->SGSIZE, sizeof(SEGMENT))) == NULL)
+ return (-1);
+ hashp->exsegs++;
+ hashp->nsegs++;
+ }
+ /*
+ * If the split point is increasing (MAX_BUCKET's log base 2
+ * * increases), we need to copy the current contents of the spare
+ * split bucket to the next bucket.
+ */
+ spare_ndx = __log2(hashp->MAX_BUCKET + 1);
+ if (spare_ndx > hashp->OVFL_POINT) {
+ hashp->SPARES[spare_ndx] = hashp->SPARES[hashp->OVFL_POINT];
+ hashp->OVFL_POINT = spare_ndx;
+ }
+
+ if (new_bucket > hashp->HIGH_MASK) {
+ /* Starting a new doubling */
+ hashp->LOW_MASK = hashp->HIGH_MASK;
+ hashp->HIGH_MASK = new_bucket | hashp->LOW_MASK;
+ }
+ /* Relocate records to the new bucket */
+ return (__split_page(hashp, old_bucket, new_bucket));
+}
+
+/*
+ * If realloc guarantees that the pointer is not destroyed if the realloc
+ * fails, then this routine can go away.
+ */
+static void *
+hash_realloc(SEGMENT **p_ptr, int oldsize, int newsize)
+{
+ void *p;
+
+ if ( (p = malloc(newsize)) ) {
+ memmove(p, *p_ptr, oldsize);
+ memset((char *)p + oldsize, 0, newsize - oldsize);
+ free(*p_ptr);
+ *p_ptr = p;
+ }
+ return (p);
+}
+
+u_int32_t
+__call_hash(HTAB *hashp, char *k, int len)
+{
+ unsigned int n, bucket;
+
+ n = hashp->hash(k, len);
+ bucket = n & hashp->HIGH_MASK;
+ if (bucket > hashp->MAX_BUCKET)
+ bucket = bucket & hashp->LOW_MASK;
+ return (bucket);
+}
+
+/*
+ * Allocate segment table. On error, destroy the table and set errno.
+ *
+ * Returns 0 on success
+ */
+static int
+alloc_segs(HTAB *hashp, int nsegs)
+{
+ int i;
+ SEGMENT store;
+
+ int save_errno;
+
+ if ((hashp->dir =
+ calloc(hashp->DSIZE, sizeof(SEGMENT *))) == NULL) {
+ save_errno = errno;
+ (void)hdestroy(hashp);
+ errno = save_errno;
+ return (-1);
+ }
+ hashp->nsegs = nsegs;
+ if (nsegs == 0)
+ return (0);
+ /* Allocate segments */
+ if ((store = calloc(nsegs << hashp->SSHIFT, sizeof(SEGMENT))) == NULL) {
+ save_errno = errno;
+ (void)hdestroy(hashp);
+ errno = save_errno;
+ return (-1);
+ }
+ for (i = 0; i < nsegs; i++)
+ hashp->dir[i] = &store[i << hashp->SSHIFT];
+ return (0);
+}
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+/*
+ * Hashp->hdr needs to be byteswapped.
+ */
+static void
+swap_header_copy(HASHHDR *srcp, HASHHDR *destp)
+{
+ int i;
+
+ P_32_COPY(srcp->magic, destp->magic);
+ P_32_COPY(srcp->version, destp->version);
+ P_32_COPY(srcp->lorder, destp->lorder);
+ P_32_COPY(srcp->bsize, destp->bsize);
+ P_32_COPY(srcp->bshift, destp->bshift);
+ P_32_COPY(srcp->dsize, destp->dsize);
+ P_32_COPY(srcp->ssize, destp->ssize);
+ P_32_COPY(srcp->sshift, destp->sshift);
+ P_32_COPY(srcp->ovfl_point, destp->ovfl_point);
+ P_32_COPY(srcp->last_freed, destp->last_freed);
+ P_32_COPY(srcp->max_bucket, destp->max_bucket);
+ P_32_COPY(srcp->high_mask, destp->high_mask);
+ P_32_COPY(srcp->low_mask, destp->low_mask);
+ P_32_COPY(srcp->ffactor, destp->ffactor);
+ P_32_COPY(srcp->nkeys, destp->nkeys);
+ P_32_COPY(srcp->hdrpages, destp->hdrpages);
+ P_32_COPY(srcp->h_charkey, destp->h_charkey);
+ for (i = 0; i < NCACHED; i++) {
+ P_32_COPY(srcp->spares[i], destp->spares[i]);
+ P_16_COPY(srcp->bitmaps[i], destp->bitmaps[i]);
+ }
+}
+
+static void
+swap_header(HTAB *hashp)
+{
+ HASHHDR *hdrp;
+ int i;
+
+ hdrp = &hashp->hdr;
+
+ M_32_SWAP(hdrp->magic);
+ M_32_SWAP(hdrp->version);
+ M_32_SWAP(hdrp->lorder);
+ M_32_SWAP(hdrp->bsize);
+ M_32_SWAP(hdrp->bshift);
+ M_32_SWAP(hdrp->dsize);
+ M_32_SWAP(hdrp->ssize);
+ M_32_SWAP(hdrp->sshift);
+ M_32_SWAP(hdrp->ovfl_point);
+ M_32_SWAP(hdrp->last_freed);
+ M_32_SWAP(hdrp->max_bucket);
+ M_32_SWAP(hdrp->high_mask);
+ M_32_SWAP(hdrp->low_mask);
+ M_32_SWAP(hdrp->ffactor);
+ M_32_SWAP(hdrp->nkeys);
+ M_32_SWAP(hdrp->hdrpages);
+ M_32_SWAP(hdrp->h_charkey);
+ for (i = 0; i < NCACHED; i++) {
+ M_32_SWAP(hdrp->spares[i]);
+ M_16_SWAP(hdrp->bitmaps[i]);
+ }
+}
+#endif
diff --git a/lib/libc/db/hash/hash.h b/lib/libc/db/hash/hash.h
new file mode 100644
index 000000000000..663ecdd10f8f
--- /dev/null
+++ b/lib/libc/db/hash/hash.h
@@ -0,0 +1,290 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Margo Seltzer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)hash.h 8.3 (Berkeley) 5/31/94
+ * $FreeBSD$
+ */
+
+/* Operations */
+typedef enum {
+ HASH_GET, HASH_PUT, HASH_PUTNEW, HASH_DELETE, HASH_FIRST, HASH_NEXT
+} ACTION;
+
+/* Buffer Management structures */
+typedef struct _bufhead BUFHEAD;
+
+struct _bufhead {
+ BUFHEAD *prev; /* LRU links */
+ BUFHEAD *next; /* LRU links */
+ BUFHEAD *ovfl; /* Overflow page buffer header */
+ u_int32_t addr; /* Address of this page */
+ char *page; /* Actual page data */
+ char flags;
+#define BUF_MOD 0x0001
+#define BUF_DISK 0x0002
+#define BUF_BUCKET 0x0004
+#define BUF_PIN 0x0008
+};
+
+#define IS_BUCKET(X) ((X) & BUF_BUCKET)
+
+typedef BUFHEAD **SEGMENT;
+
+/* Hash Table Information */
+typedef struct hashhdr { /* Disk resident portion */
+ int32_t magic; /* Magic NO for hash tables */
+ int32_t version; /* Version ID */
+ u_int32_t lorder; /* Byte Order */
+ int32_t bsize; /* Bucket/Page Size */
+ int32_t bshift; /* Bucket shift */
+ int32_t dsize; /* Directory Size */
+ int32_t ssize; /* Segment Size */
+ int32_t sshift; /* Segment shift */
+ int32_t ovfl_point; /* Where overflow pages are being
+ * allocated */
+ int32_t last_freed; /* Last overflow page freed */
+ u_int32_t max_bucket; /* ID of Maximum bucket in use */
+ u_int32_t high_mask; /* Mask to modulo into entire table */
+ u_int32_t low_mask; /* Mask to modulo into lower half of
+ * table */
+ u_int32_t ffactor; /* Fill factor */
+ int32_t nkeys; /* Number of keys in hash table */
+ int32_t hdrpages; /* Size of table header */
+ int32_t h_charkey; /* value of hash(CHARKEY) */
+#define NCACHED 32 /* number of bit maps and spare
+ * points */
+ int32_t spares[NCACHED];/* spare pages for overflow */
+ u_int16_t bitmaps[NCACHED]; /* address of overflow page
+ * bitmaps */
+} HASHHDR;
+
+typedef struct htab { /* Memory resident data structure */
+ HASHHDR hdr; /* Header */
+ int nsegs; /* Number of allocated segments */
+ int exsegs; /* Number of extra allocated
+ * segments */
+ u_int32_t /* Hash function */
+ (*hash)(const void *, size_t);
+ int flags; /* Flag values */
+ int fp; /* File pointer */
+ char *tmp_buf; /* Temporary Buffer for BIG data */
+ char *tmp_key; /* Temporary Buffer for BIG keys */
+ BUFHEAD *cpage; /* Current page */
+ int cbucket; /* Current bucket */
+ int cndx; /* Index of next item on cpage */
+ int error; /* Error Number -- for DBM
+ * compatibility */
+ int new_file; /* Indicates if fd is backing store
+ * or no */
+ int save_file; /* Indicates whether we need to flush
+ * file at
+ * exit */
+ u_int32_t *mapp[NCACHED]; /* Pointers to page maps */
+ int nmaps; /* Initial number of bitmaps */
+ int nbufs; /* Number of buffers left to
+ * allocate */
+ BUFHEAD bufhead; /* Header of buffer lru list */
+ SEGMENT *dir; /* Hash Bucket directory */
+} HTAB;
+
+/*
+ * Constants
+ */
+#define MAX_BSIZE 32768 /* 2^15 but should be 65536 */
+#define MIN_BUFFERS 6
+#define MINHDRSIZE 512
+#define DEF_BUFSIZE 65536 /* 64 K */
+#define DEF_BUCKET_SIZE 4096
+#define DEF_BUCKET_SHIFT 12 /* log2(BUCKET) */
+#define DEF_SEGSIZE 256
+#define DEF_SEGSIZE_SHIFT 8 /* log2(SEGSIZE) */
+#define DEF_DIRSIZE 256
+#define DEF_FFACTOR 65536
+#define MIN_FFACTOR 4
+#define SPLTMAX 8
+#define CHARKEY "%$sniglet^&"
+#define NUMKEY 1038583
+#define BYTE_SHIFT 3
+#define INT_TO_BYTE 2
+#define INT_BYTE_SHIFT 5
+#define ALL_SET ((u_int32_t)0xFFFFFFFF)
+#define ALL_CLEAR 0
+
+#define PTROF(X) ((BUFHEAD *)((intptr_t)(X)&~0x3))
+#define ISMOD(X) ((u_int32_t)(intptr_t)(X)&0x1)
+#define DOMOD(X) ((X) = (char *)((intptr_t)(X)|0x1))
+#define ISDISK(X) ((u_int32_t)(intptr_t)(X)&0x2)
+#define DODISK(X) ((X) = (char *)((intptr_t)(X)|0x2))
+
+#define BITS_PER_MAP 32
+
+/* Given the address of the beginning of a big map, clear/set the nth bit */
+#define CLRBIT(A, N) ((A)[(N)/BITS_PER_MAP] &= ~(1<<((N)%BITS_PER_MAP)))
+#define SETBIT(A, N) ((A)[(N)/BITS_PER_MAP] |= (1<<((N)%BITS_PER_MAP)))
+#define ISSET(A, N) ((A)[(N)/BITS_PER_MAP] & (1<<((N)%BITS_PER_MAP)))
+
+/* Overflow management */
+/*
+ * Overflow page numbers are allocated per split point. At each doubling of
+ * the table, we can allocate extra pages. So, an overflow page number has
+ * the top 5 bits indicate which split point and the lower 11 bits indicate
+ * which page at that split point is indicated (pages within split points are
+ * numberered starting with 1).
+ */
+
+#define SPLITSHIFT 11
+#define SPLITMASK 0x7FF
+#define SPLITNUM(N) (((u_int32_t)(N)) >> SPLITSHIFT)
+#define OPAGENUM(N) ((N) & SPLITMASK)
+#define OADDR_OF(S,O) ((u_int32_t)((u_int32_t)(S) << SPLITSHIFT) + (O))
+
+#define BUCKET_TO_PAGE(B) \
+ (B) + hashp->HDRPAGES + ((B) ? hashp->SPARES[__log2((B)+1)-1] : 0)
+#define OADDR_TO_PAGE(B) \
+ BUCKET_TO_PAGE ( (1 << SPLITNUM((B))) -1 ) + OPAGENUM((B));
+
+/*
+ * page.h contains a detailed description of the page format.
+ *
+ * Normally, keys and data are accessed from offset tables in the top of
+ * each page which point to the beginning of the key and data. There are
+ * four flag values which may be stored in these offset tables which indicate
+ * the following:
+ *
+ *
+ * OVFLPAGE Rather than a key data pair, this pair contains
+ * the address of an overflow page. The format of
+ * the pair is:
+ * OVERFLOW_PAGE_NUMBER OVFLPAGE
+ *
+ * PARTIAL_KEY This must be the first key/data pair on a page
+ * and implies that page contains only a partial key.
+ * That is, the key is too big to fit on a single page
+ * so it starts on this page and continues on the next.
+ * The format of the page is:
+ * KEY_OFF PARTIAL_KEY OVFL_PAGENO OVFLPAGE
+ *
+ * KEY_OFF -- offset of the beginning of the key
+ * PARTIAL_KEY -- 1
+ * OVFL_PAGENO - page number of the next overflow page
+ * OVFLPAGE -- 0
+ *
+ * FULL_KEY This must be the first key/data pair on the page. It
+ * is used in two cases.
+ *
+ * Case 1:
+ * There is a complete key on the page but no data
+ * (because it wouldn't fit). The next page contains
+ * the data.
+ *
+ * Page format it:
+ * KEY_OFF FULL_KEY OVFL_PAGENO OVFL_PAGE
+ *
+ * KEY_OFF -- offset of the beginning of the key
+ * FULL_KEY -- 2
+ * OVFL_PAGENO - page number of the next overflow page
+ * OVFLPAGE -- 0
+ *
+ * Case 2:
+ * This page contains no key, but part of a large
+ * data field, which is continued on the next page.
+ *
+ * Page format it:
+ * DATA_OFF FULL_KEY OVFL_PAGENO OVFL_PAGE
+ *
+ * KEY_OFF -- offset of the beginning of the data on
+ * this page
+ * FULL_KEY -- 2
+ * OVFL_PAGENO - page number of the next overflow page
+ * OVFLPAGE -- 0
+ *
+ * FULL_KEY_DATA
+ * This must be the first key/data pair on the page.
+ * There are two cases:
+ *
+ * Case 1:
+ * This page contains a key and the beginning of the
+ * data field, but the data field is continued on the
+ * next page.
+ *
+ * Page format is:
+ * KEY_OFF FULL_KEY_DATA OVFL_PAGENO DATA_OFF
+ *
+ * KEY_OFF -- offset of the beginning of the key
+ * FULL_KEY_DATA -- 3
+ * OVFL_PAGENO - page number of the next overflow page
+ * DATA_OFF -- offset of the beginning of the data
+ *
+ * Case 2:
+ * This page contains the last page of a big data pair.
+ * There is no key, only the tail end of the data
+ * on this page.
+ *
+ * Page format is:
+ * DATA_OFF FULL_KEY_DATA <OVFL_PAGENO> <OVFLPAGE>
+ *
+ * DATA_OFF -- offset of the beginning of the data on
+ * this page
+ * FULL_KEY_DATA -- 3
+ * OVFL_PAGENO - page number of the next overflow page
+ * OVFLPAGE -- 0
+ *
+ * OVFL_PAGENO and OVFLPAGE are optional (they are
+ * not present if there is no next page).
+ */
+
+#define OVFLPAGE 0
+#define PARTIAL_KEY 1
+#define FULL_KEY 2
+#define FULL_KEY_DATA 3
+#define REAL_KEY 4
+
+/* Short hands for accessing structure */
+#define BSIZE hdr.bsize
+#define BSHIFT hdr.bshift
+#define DSIZE hdr.dsize
+#define SGSIZE hdr.ssize
+#define SSHIFT hdr.sshift
+#define LORDER hdr.lorder
+#define OVFL_POINT hdr.ovfl_point
+#define LAST_FREED hdr.last_freed
+#define MAX_BUCKET hdr.max_bucket
+#define FFACTOR hdr.ffactor
+#define HIGH_MASK hdr.high_mask
+#define LOW_MASK hdr.low_mask
+#define NKEYS hdr.nkeys
+#define HDRPAGES hdr.hdrpages
+#define SPARES hdr.spares
+#define BITMAPS hdr.bitmaps
+#define VERSION hdr.version
+#define MAGIC hdr.magic
+#define NEXT_FREE hdr.next_free
+#define H_CHARKEY hdr.h_charkey
diff --git a/lib/libc/db/hash/hash_bigkey.c b/lib/libc/db/hash/hash_bigkey.c
new file mode 100644
index 000000000000..c1914a521833
--- /dev/null
+++ b/lib/libc/db/hash/hash_bigkey.c
@@ -0,0 +1,646 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Margo Seltzer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)hash_bigkey.c 8.3 (Berkeley) 5/31/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * PACKAGE: hash
+ * DESCRIPTION:
+ * Big key/data handling for the hashing package.
+ *
+ * ROUTINES:
+ * External
+ * __big_keydata
+ * __big_split
+ * __big_insert
+ * __big_return
+ * __big_delete
+ * __find_last_page
+ * Internal
+ * collect_key
+ * collect_data
+ */
+
+#include <sys/param.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef DEBUG
+#include <assert.h>
+#endif
+
+#include <db.h>
+#include "hash.h"
+#include "page.h"
+#include "extern.h"
+
+static int collect_key(HTAB *, BUFHEAD *, int, DBT *, int);
+static int collect_data(HTAB *, BUFHEAD *, int, int);
+
+/*
+ * Big_insert
+ *
+ * You need to do an insert and the key/data pair is too big
+ *
+ * Returns:
+ * 0 ==> OK
+ *-1 ==> ERROR
+ */
+int
+__big_insert(HTAB *hashp, BUFHEAD *bufp, const DBT *key, const DBT *val)
+{
+ u_int16_t *p;
+ int key_size, n;
+ unsigned int val_size;
+ u_int16_t space, move_bytes, off;
+ char *cp, *key_data, *val_data;
+
+ cp = bufp->page; /* Character pointer of p. */
+ p = (u_int16_t *)cp;
+
+ key_data = (char *)key->data;
+ key_size = key->size;
+ val_data = (char *)val->data;
+ val_size = val->size;
+
+ /* First move the Key */
+ for (space = FREESPACE(p) - BIGOVERHEAD; key_size;
+ space = FREESPACE(p) - BIGOVERHEAD) {
+ move_bytes = MIN(space, key_size);
+ off = OFFSET(p) - move_bytes;
+ memmove(cp + off, key_data, move_bytes);
+ key_size -= move_bytes;
+ key_data += move_bytes;
+ n = p[0];
+ p[++n] = off;
+ p[0] = ++n;
+ FREESPACE(p) = off - PAGE_META(n);
+ OFFSET(p) = off;
+ p[n] = PARTIAL_KEY;
+ bufp = __add_ovflpage(hashp, bufp);
+ if (!bufp)
+ return (-1);
+ n = p[0];
+ if (!key_size) {
+ space = FREESPACE(p);
+ if (space) {
+ move_bytes = MIN(space, val_size);
+ /*
+ * If the data would fit exactly in the
+ * remaining space, we must overflow it to the
+ * next page; otherwise the invariant that the
+ * data must end on a page with FREESPACE
+ * non-zero would fail.
+ */
+ if (space == val_size && val_size == val->size)
+ goto toolarge;
+ off = OFFSET(p) - move_bytes;
+ memmove(cp + off, val_data, move_bytes);
+ val_data += move_bytes;
+ val_size -= move_bytes;
+ p[n] = off;
+ p[n - 2] = FULL_KEY_DATA;
+ FREESPACE(p) = FREESPACE(p) - move_bytes;
+ OFFSET(p) = off;
+ } else {
+ toolarge:
+ p[n - 2] = FULL_KEY;
+ }
+ }
+ p = (u_int16_t *)bufp->page;
+ cp = bufp->page;
+ bufp->flags |= BUF_MOD;
+ }
+
+ /* Now move the data */
+ for (space = FREESPACE(p) - BIGOVERHEAD; val_size;
+ space = FREESPACE(p) - BIGOVERHEAD) {
+ move_bytes = MIN(space, val_size);
+ /*
+ * Here's the hack to make sure that if the data ends on the
+ * same page as the key ends, FREESPACE is at least one.
+ */
+ if (space == val_size && val_size == val->size)
+ move_bytes--;
+ off = OFFSET(p) - move_bytes;
+ memmove(cp + off, val_data, move_bytes);
+ val_size -= move_bytes;
+ val_data += move_bytes;
+ n = p[0];
+ p[++n] = off;
+ p[0] = ++n;
+ FREESPACE(p) = off - PAGE_META(n);
+ OFFSET(p) = off;
+ if (val_size) {
+ p[n] = FULL_KEY;
+ bufp = __add_ovflpage(hashp, bufp);
+ if (!bufp)
+ return (-1);
+ cp = bufp->page;
+ p = (u_int16_t *)cp;
+ } else
+ p[n] = FULL_KEY_DATA;
+ bufp->flags |= BUF_MOD;
+ }
+ return (0);
+}
+
+/*
+ * Called when bufp's page contains a partial key (index should be 1)
+ *
+ * All pages in the big key/data pair except bufp are freed. We cannot
+ * free bufp because the page pointing to it is lost and we can't get rid
+ * of its pointer.
+ *
+ * Returns:
+ * 0 => OK
+ *-1 => ERROR
+ */
+int
+__big_delete(HTAB *hashp, BUFHEAD *bufp)
+{
+ BUFHEAD *last_bfp, *rbufp;
+ u_int16_t *bp, pageno;
+ int key_done, n;
+
+ rbufp = bufp;
+ last_bfp = NULL;
+ bp = (u_int16_t *)bufp->page;
+ pageno = 0;
+ key_done = 0;
+
+ while (!key_done || (bp[2] != FULL_KEY_DATA)) {
+ if (bp[2] == FULL_KEY || bp[2] == FULL_KEY_DATA)
+ key_done = 1;
+
+ /*
+ * If there is freespace left on a FULL_KEY_DATA page, then
+ * the data is short and fits entirely on this page, and this
+ * is the last page.
+ */
+ if (bp[2] == FULL_KEY_DATA && FREESPACE(bp))
+ break;
+ pageno = bp[bp[0] - 1];
+ rbufp->flags |= BUF_MOD;
+ rbufp = __get_buf(hashp, pageno, rbufp, 0);
+ if (last_bfp)
+ __free_ovflpage(hashp, last_bfp);
+ last_bfp = rbufp;
+ if (!rbufp)
+ return (-1); /* Error. */
+ bp = (u_int16_t *)rbufp->page;
+ }
+
+ /*
+ * If we get here then rbufp points to the last page of the big
+ * key/data pair. Bufp points to the first one -- it should now be
+ * empty pointing to the next page after this pair. Can't free it
+ * because we don't have the page pointing to it.
+ */
+
+ /* This is information from the last page of the pair. */
+ n = bp[0];
+ pageno = bp[n - 1];
+
+ /* Now, bp is the first page of the pair. */
+ bp = (u_int16_t *)bufp->page;
+ if (n > 2) {
+ /* There is an overflow page. */
+ bp[1] = pageno;
+ bp[2] = OVFLPAGE;
+ bufp->ovfl = rbufp->ovfl;
+ } else
+ /* This is the last page. */
+ bufp->ovfl = NULL;
+ n -= 2;
+ bp[0] = n;
+ FREESPACE(bp) = hashp->BSIZE - PAGE_META(n);
+ OFFSET(bp) = hashp->BSIZE;
+
+ bufp->flags |= BUF_MOD;
+ if (rbufp)
+ __free_ovflpage(hashp, rbufp);
+ if (last_bfp && last_bfp != rbufp)
+ __free_ovflpage(hashp, last_bfp);
+
+ hashp->NKEYS--;
+ return (0);
+}
+/*
+ * Returns:
+ * 0 = key not found
+ * -1 = get next overflow page
+ * -2 means key not found and this is big key/data
+ * -3 error
+ */
+int
+__find_bigpair(HTAB *hashp, BUFHEAD *bufp, int ndx, char *key, int size)
+{
+ u_int16_t *bp;
+ char *p;
+ int ksize;
+ u_int16_t bytes;
+ char *kkey;
+
+ bp = (u_int16_t *)bufp->page;
+ p = bufp->page;
+ ksize = size;
+ kkey = key;
+
+ for (bytes = hashp->BSIZE - bp[ndx];
+ bytes <= size && bp[ndx + 1] == PARTIAL_KEY;
+ bytes = hashp->BSIZE - bp[ndx]) {
+ if (memcmp(p + bp[ndx], kkey, bytes))
+ return (-2);
+ kkey += bytes;
+ ksize -= bytes;
+ bufp = __get_buf(hashp, bp[ndx + 2], bufp, 0);
+ if (!bufp)
+ return (-3);
+ p = bufp->page;
+ bp = (u_int16_t *)p;
+ ndx = 1;
+ }
+
+ if (bytes != ksize || memcmp(p + bp[ndx], kkey, bytes)) {
+#ifdef HASH_STATISTICS
+ ++hash_collisions;
+#endif
+ return (-2);
+ } else
+ return (ndx);
+}
+
+/*
+ * Given the buffer pointer of the first overflow page of a big pair,
+ * find the end of the big pair
+ *
+ * This will set bpp to the buffer header of the last page of the big pair.
+ * It will return the pageno of the overflow page following the last page
+ * of the pair; 0 if there isn't any (i.e. big pair is the last key in the
+ * bucket)
+ */
+u_int16_t
+__find_last_page(HTAB *hashp, BUFHEAD **bpp)
+{
+ BUFHEAD *bufp;
+ u_int16_t *bp, pageno;
+ int n;
+
+ bufp = *bpp;
+ bp = (u_int16_t *)bufp->page;
+ for (;;) {
+ n = bp[0];
+
+ /*
+ * This is the last page if: the tag is FULL_KEY_DATA and
+ * either only 2 entries OVFLPAGE marker is explicit there
+ * is freespace on the page.
+ */
+ if (bp[2] == FULL_KEY_DATA &&
+ ((n == 2) || (bp[n] == OVFLPAGE) || (FREESPACE(bp))))
+ break;
+
+ pageno = bp[n - 1];
+ bufp = __get_buf(hashp, pageno, bufp, 0);
+ if (!bufp)
+ return (0); /* Need to indicate an error! */
+ bp = (u_int16_t *)bufp->page;
+ }
+
+ *bpp = bufp;
+ if (bp[0] > 2)
+ return (bp[3]);
+ else
+ return (0);
+}
+
+/*
+ * Return the data for the key/data pair that begins on this page at this
+ * index (index should always be 1).
+ */
+int
+__big_return(HTAB *hashp, BUFHEAD *bufp, int ndx, DBT *val, int set_current)
+{
+ BUFHEAD *save_p;
+ u_int16_t *bp, len, off, save_addr;
+ char *tp;
+
+ bp = (u_int16_t *)bufp->page;
+ while (bp[ndx + 1] == PARTIAL_KEY) {
+ bufp = __get_buf(hashp, bp[bp[0] - 1], bufp, 0);
+ if (!bufp)
+ return (-1);
+ bp = (u_int16_t *)bufp->page;
+ ndx = 1;
+ }
+
+ if (bp[ndx + 1] == FULL_KEY) {
+ bufp = __get_buf(hashp, bp[bp[0] - 1], bufp, 0);
+ if (!bufp)
+ return (-1);
+ bp = (u_int16_t *)bufp->page;
+ save_p = bufp;
+ save_addr = save_p->addr;
+ off = bp[1];
+ len = 0;
+ } else
+ if (!FREESPACE(bp)) {
+ /*
+ * This is a hack. We can't distinguish between
+ * FULL_KEY_DATA that contains complete data or
+ * incomplete data, so we require that if the data
+ * is complete, there is at least 1 byte of free
+ * space left.
+ */
+ off = bp[bp[0]];
+ len = bp[1] - off;
+ save_p = bufp;
+ save_addr = bufp->addr;
+ bufp = __get_buf(hashp, bp[bp[0] - 1], bufp, 0);
+ if (!bufp)
+ return (-1);
+ bp = (u_int16_t *)bufp->page;
+ } else {
+ /* The data is all on one page. */
+ tp = (char *)bp;
+ off = bp[bp[0]];
+ val->data = (u_char *)tp + off;
+ val->size = bp[1] - off;
+ if (set_current) {
+ if (bp[0] == 2) { /* No more buckets in
+ * chain */
+ hashp->cpage = NULL;
+ hashp->cbucket++;
+ hashp->cndx = 1;
+ } else {
+ hashp->cpage = __get_buf(hashp,
+ bp[bp[0] - 1], bufp, 0);
+ if (!hashp->cpage)
+ return (-1);
+ hashp->cndx = 1;
+ if (!((u_int16_t *)
+ hashp->cpage->page)[0]) {
+ hashp->cbucket++;
+ hashp->cpage = NULL;
+ }
+ }
+ }
+ return (0);
+ }
+
+ val->size = (size_t)collect_data(hashp, bufp, (int)len, set_current);
+ if (val->size == (size_t)-1)
+ return (-1);
+ if (save_p->addr != save_addr) {
+ /* We are pretty short on buffers. */
+ errno = EINVAL; /* OUT OF BUFFERS */
+ return (-1);
+ }
+ memmove(hashp->tmp_buf, (save_p->page) + off, len);
+ val->data = (u_char *)hashp->tmp_buf;
+ return (0);
+}
+/*
+ * Count how big the total datasize is by recursing through the pages. Then
+ * allocate a buffer and copy the data as you recurse up.
+ */
+static int
+collect_data(HTAB *hashp, BUFHEAD *bufp, int len, int set)
+{
+ u_int16_t *bp;
+ char *p;
+ BUFHEAD *xbp;
+ u_int16_t save_addr;
+ int mylen, totlen;
+
+ p = bufp->page;
+ bp = (u_int16_t *)p;
+ mylen = hashp->BSIZE - bp[1];
+ save_addr = bufp->addr;
+
+ if (bp[2] == FULL_KEY_DATA) { /* End of Data */
+ totlen = len + mylen;
+ if (hashp->tmp_buf)
+ free(hashp->tmp_buf);
+ if ((hashp->tmp_buf = (char *)malloc(totlen)) == NULL)
+ return (-1);
+ if (set) {
+ hashp->cndx = 1;
+ if (bp[0] == 2) { /* No more buckets in chain */
+ hashp->cpage = NULL;
+ hashp->cbucket++;
+ } else {
+ hashp->cpage =
+ __get_buf(hashp, bp[bp[0] - 1], bufp, 0);
+ if (!hashp->cpage)
+ return (-1);
+ else if (!((u_int16_t *)hashp->cpage->page)[0]) {
+ hashp->cbucket++;
+ hashp->cpage = NULL;
+ }
+ }
+ }
+ } else {
+ xbp = __get_buf(hashp, bp[bp[0] - 1], bufp, 0);
+ if (!xbp || ((totlen =
+ collect_data(hashp, xbp, len + mylen, set)) < 1))
+ return (-1);
+ }
+ if (bufp->addr != save_addr) {
+ errno = EINVAL; /* Out of buffers. */
+ return (-1);
+ }
+ memmove(&hashp->tmp_buf[len], (bufp->page) + bp[1], mylen);
+ return (totlen);
+}
+
+/*
+ * Fill in the key and data for this big pair.
+ */
+int
+__big_keydata(HTAB *hashp, BUFHEAD *bufp, DBT *key, DBT *val, int set)
+{
+ key->size = (size_t)collect_key(hashp, bufp, 0, val, set);
+ if (key->size == (size_t)-1)
+ return (-1);
+ key->data = (u_char *)hashp->tmp_key;
+ return (0);
+}
+
+/*
+ * Count how big the total key size is by recursing through the pages. Then
+ * collect the data, allocate a buffer and copy the key as you recurse up.
+ */
+static int
+collect_key(HTAB *hashp, BUFHEAD *bufp, int len, DBT *val, int set)
+{
+ BUFHEAD *xbp;
+ char *p;
+ int mylen, totlen;
+ u_int16_t *bp, save_addr;
+
+ p = bufp->page;
+ bp = (u_int16_t *)p;
+ mylen = hashp->BSIZE - bp[1];
+
+ save_addr = bufp->addr;
+ totlen = len + mylen;
+ if (bp[2] == FULL_KEY || bp[2] == FULL_KEY_DATA) { /* End of Key. */
+ if (hashp->tmp_key != NULL)
+ free(hashp->tmp_key);
+ if ((hashp->tmp_key = (char *)malloc(totlen)) == NULL)
+ return (-1);
+ if (__big_return(hashp, bufp, 1, val, set))
+ return (-1);
+ } else {
+ xbp = __get_buf(hashp, bp[bp[0] - 1], bufp, 0);
+ if (!xbp || ((totlen =
+ collect_key(hashp, xbp, totlen, val, set)) < 1))
+ return (-1);
+ }
+ if (bufp->addr != save_addr) {
+ errno = EINVAL; /* MIS -- OUT OF BUFFERS */
+ return (-1);
+ }
+ memmove(&hashp->tmp_key[len], (bufp->page) + bp[1], mylen);
+ return (totlen);
+}
+
+/*
+ * Returns:
+ * 0 => OK
+ * -1 => error
+ */
+int
+__big_split(HTAB *hashp,
+ BUFHEAD *op, /* Pointer to where to put keys that go in old bucket */
+ BUFHEAD *np, /* Pointer to new bucket page */
+ BUFHEAD *big_keyp, /* Pointer to first page containing the big key/data */
+ int addr, /* Address of big_keyp */
+ u_int32_t obucket, /* Old Bucket */
+ SPLIT_RETURN *ret)
+{
+ BUFHEAD *bp, *tmpp;
+ DBT key, val;
+ u_int32_t change;
+ u_int16_t free_space, n, off, *tp;
+
+ bp = big_keyp;
+
+ /* Now figure out where the big key/data goes */
+ if (__big_keydata(hashp, big_keyp, &key, &val, 0))
+ return (-1);
+ change = (__call_hash(hashp, key.data, key.size) != obucket);
+
+ if ( (ret->next_addr = __find_last_page(hashp, &big_keyp)) ) {
+ if (!(ret->nextp =
+ __get_buf(hashp, ret->next_addr, big_keyp, 0)))
+ return (-1);
+ } else
+ ret->nextp = NULL;
+
+ /* Now make one of np/op point to the big key/data pair */
+#ifdef DEBUG
+ assert(np->ovfl == NULL);
+#endif
+ if (change)
+ tmpp = np;
+ else
+ tmpp = op;
+
+ tmpp->flags |= BUF_MOD;
+#ifdef DEBUG1
+ (void)fprintf(stderr,
+ "BIG_SPLIT: %d->ovfl was %d is now %d\n", tmpp->addr,
+ (tmpp->ovfl ? tmpp->ovfl->addr : 0), (bp ? bp->addr : 0));
+#endif
+ tmpp->ovfl = bp; /* one of op/np point to big_keyp */
+ tp = (u_int16_t *)tmpp->page;
+#ifdef DEBUG
+ assert(FREESPACE(tp) >= OVFLSIZE);
+#endif
+ n = tp[0];
+ off = OFFSET(tp);
+ free_space = FREESPACE(tp);
+ tp[++n] = (u_int16_t)addr;
+ tp[++n] = OVFLPAGE;
+ tp[0] = n;
+ OFFSET(tp) = off;
+ FREESPACE(tp) = free_space - OVFLSIZE;
+
+ /*
+ * Finally, set the new and old return values. BIG_KEYP contains a
+ * pointer to the last page of the big key_data pair. Make sure that
+ * big_keyp has no following page (2 elements) or create an empty
+ * following page.
+ */
+
+ ret->newp = np;
+ ret->oldp = op;
+
+ tp = (u_int16_t *)big_keyp->page;
+ big_keyp->flags |= BUF_MOD;
+ if (tp[0] > 2) {
+ /*
+ * There may be either one or two offsets on this page. If
+ * there is one, then the overflow page is linked on normally
+ * and tp[4] is OVFLPAGE. If there are two, tp[4] contains
+ * the second offset and needs to get stuffed in after the
+ * next overflow page is added.
+ */
+ n = tp[4];
+ free_space = FREESPACE(tp);
+ off = OFFSET(tp);
+ tp[0] -= 2;
+ FREESPACE(tp) = free_space + OVFLSIZE;
+ OFFSET(tp) = off;
+ tmpp = __add_ovflpage(hashp, big_keyp);
+ if (!tmpp)
+ return (-1);
+ tp[4] = n;
+ } else
+ tmpp = big_keyp;
+
+ if (change)
+ ret->newp = tmpp;
+ else
+ ret->oldp = tmpp;
+ return (0);
+}
diff --git a/lib/libc/db/hash/hash_buf.c b/lib/libc/db/hash/hash_buf.c
new file mode 100644
index 000000000000..5c62a2c36eaf
--- /dev/null
+++ b/lib/libc/db/hash/hash_buf.c
@@ -0,0 +1,358 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Margo Seltzer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)hash_buf.c 8.5 (Berkeley) 7/15/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * PACKAGE: hash
+ *
+ * DESCRIPTION:
+ * Contains buffer management
+ *
+ * ROUTINES:
+ * External
+ * __buf_init
+ * __get_buf
+ * __buf_free
+ * __reclaim_buf
+ * Internal
+ * newbuf
+ */
+
+#include <sys/param.h>
+
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef DEBUG
+#include <assert.h>
+#endif
+
+#include <db.h>
+#include "hash.h"
+#include "page.h"
+#include "extern.h"
+
+static BUFHEAD *newbuf(HTAB *, u_int32_t, BUFHEAD *);
+
+/* Unlink B from its place in the lru */
+#define BUF_REMOVE(B) { \
+ (B)->prev->next = (B)->next; \
+ (B)->next->prev = (B)->prev; \
+}
+
+/* Insert B after P */
+#define BUF_INSERT(B, P) { \
+ (B)->next = (P)->next; \
+ (B)->prev = (P); \
+ (P)->next = (B); \
+ (B)->next->prev = (B); \
+}
+
+#define MRU hashp->bufhead.next
+#define LRU hashp->bufhead.prev
+
+#define MRU_INSERT(B) BUF_INSERT((B), &hashp->bufhead)
+#define LRU_INSERT(B) BUF_INSERT((B), LRU)
+
+/*
+ * We are looking for a buffer with address "addr". If prev_bp is NULL, then
+ * address is a bucket index. If prev_bp is not NULL, then it points to the
+ * page previous to an overflow page that we are trying to find.
+ *
+ * CAVEAT: The buffer header accessed via prev_bp's ovfl field may no longer
+ * be valid. Therefore, you must always verify that its address matches the
+ * address you are seeking.
+ */
+BUFHEAD *
+__get_buf(HTAB *hashp, u_int32_t addr,
+ BUFHEAD *prev_bp, /* If prev_bp set, indicates a new overflow page. */
+ int newpage)
+{
+ BUFHEAD *bp;
+ u_int32_t is_disk_mask;
+ int is_disk, segment_ndx;
+ SEGMENT segp;
+
+ is_disk = 0;
+ is_disk_mask = 0;
+ if (prev_bp) {
+ bp = prev_bp->ovfl;
+ if (!bp || (bp->addr != addr))
+ bp = NULL;
+ if (!newpage)
+ is_disk = BUF_DISK;
+ } else {
+ /* Grab buffer out of directory */
+ segment_ndx = addr & (hashp->SGSIZE - 1);
+
+ /* valid segment ensured by __call_hash() */
+ segp = hashp->dir[addr >> hashp->SSHIFT];
+#ifdef DEBUG
+ assert(segp != NULL);
+#endif
+ bp = PTROF(segp[segment_ndx]);
+ is_disk_mask = ISDISK(segp[segment_ndx]);
+ is_disk = is_disk_mask || !hashp->new_file;
+ }
+
+ if (!bp) {
+ bp = newbuf(hashp, addr, prev_bp);
+ if (!bp ||
+ __get_page(hashp, bp->page, addr, !prev_bp, is_disk, 0))
+ return (NULL);
+ if (!prev_bp)
+ segp[segment_ndx] =
+ (BUFHEAD *)((intptr_t)bp | is_disk_mask);
+ } else {
+ BUF_REMOVE(bp);
+ MRU_INSERT(bp);
+ }
+ return (bp);
+}
+
+/*
+ * We need a buffer for this page. Either allocate one, or evict a resident
+ * one (if we have as many buffers as we're allowed) and put this one in.
+ *
+ * If newbuf finds an error (returning NULL), it also sets errno.
+ */
+static BUFHEAD *
+newbuf(HTAB *hashp, u_int32_t addr, BUFHEAD *prev_bp)
+{
+ BUFHEAD *bp; /* The buffer we're going to use */
+ BUFHEAD *xbp; /* Temp pointer */
+ BUFHEAD *next_xbp;
+ SEGMENT segp;
+ int segment_ndx;
+ u_int16_t oaddr, *shortp;
+
+ oaddr = 0;
+ bp = LRU;
+
+ /* It is bad to overwrite the page under the cursor. */
+ if (bp == hashp->cpage) {
+ BUF_REMOVE(bp);
+ MRU_INSERT(bp);
+ bp = LRU;
+ }
+
+ /* If prev_bp is part of bp overflow, create a new buffer. */
+ if (hashp->nbufs == 0 && prev_bp && bp->ovfl) {
+ BUFHEAD *ovfl;
+
+ for (ovfl = bp->ovfl; ovfl ; ovfl = ovfl->ovfl) {
+ if (ovfl == prev_bp) {
+ hashp->nbufs++;
+ break;
+ }
+ }
+ }
+
+ /*
+ * If LRU buffer is pinned, the buffer pool is too small. We need to
+ * allocate more buffers.
+ */
+ if (hashp->nbufs || (bp->flags & BUF_PIN) || bp == hashp->cpage) {
+ /* Allocate a new one */
+ if ((bp = (BUFHEAD *)calloc(1, sizeof(BUFHEAD))) == NULL)
+ return (NULL);
+ if ((bp->page = (char *)calloc(1, hashp->BSIZE)) == NULL) {
+ free(bp);
+ return (NULL);
+ }
+ if (hashp->nbufs)
+ hashp->nbufs--;
+ } else {
+ /* Kick someone out */
+ BUF_REMOVE(bp);
+ /*
+ * If this is an overflow page with addr 0, it's already been
+ * flushed back in an overflow chain and initialized.
+ */
+ if ((bp->addr != 0) || (bp->flags & BUF_BUCKET)) {
+ /*
+ * Set oaddr before __put_page so that you get it
+ * before bytes are swapped.
+ */
+ shortp = (u_int16_t *)bp->page;
+ if (shortp[0])
+ oaddr = shortp[shortp[0] - 1];
+ if ((bp->flags & BUF_MOD) && __put_page(hashp, bp->page,
+ bp->addr, (int)IS_BUCKET(bp->flags), 0))
+ return (NULL);
+ /*
+ * Update the pointer to this page (i.e. invalidate it).
+ *
+ * If this is a new file (i.e. we created it at open
+ * time), make sure that we mark pages which have been
+ * written to disk so we retrieve them from disk later,
+ * rather than allocating new pages.
+ */
+ if (IS_BUCKET(bp->flags)) {
+ segment_ndx = bp->addr & (hashp->SGSIZE - 1);
+ segp = hashp->dir[bp->addr >> hashp->SSHIFT];
+#ifdef DEBUG
+ assert(segp != NULL);
+#endif
+
+ if (hashp->new_file &&
+ ((bp->flags & BUF_MOD) ||
+ ISDISK(segp[segment_ndx])))
+ segp[segment_ndx] = (BUFHEAD *)BUF_DISK;
+ else
+ segp[segment_ndx] = NULL;
+ }
+ /*
+ * Since overflow pages can only be access by means of
+ * their bucket, free overflow pages associated with
+ * this bucket.
+ */
+ for (xbp = bp; xbp->ovfl;) {
+ next_xbp = xbp->ovfl;
+ xbp->ovfl = NULL;
+ xbp = next_xbp;
+
+ /* Check that ovfl pointer is up date. */
+ if (IS_BUCKET(xbp->flags) ||
+ (oaddr != xbp->addr))
+ break;
+
+ shortp = (u_int16_t *)xbp->page;
+ if (shortp[0])
+ /* set before __put_page */
+ oaddr = shortp[shortp[0] - 1];
+ if ((xbp->flags & BUF_MOD) && __put_page(hashp,
+ xbp->page, xbp->addr, 0, 0))
+ return (NULL);
+ xbp->addr = 0;
+ xbp->flags = 0;
+ BUF_REMOVE(xbp);
+ LRU_INSERT(xbp);
+ }
+ }
+ }
+
+ /* Now assign this buffer */
+ bp->addr = addr;
+#ifdef DEBUG1
+ (void)fprintf(stderr, "NEWBUF1: %d->ovfl was %d is now %d\n",
+ bp->addr, (bp->ovfl ? bp->ovfl->addr : 0), 0);
+#endif
+ bp->ovfl = NULL;
+ if (prev_bp) {
+ /*
+ * If prev_bp is set, this is an overflow page, hook it in to
+ * the buffer overflow links.
+ */
+#ifdef DEBUG1
+ (void)fprintf(stderr, "NEWBUF2: %d->ovfl was %d is now %d\n",
+ prev_bp->addr, (prev_bp->ovfl ? prev_bp->ovfl->addr : 0),
+ (bp ? bp->addr : 0));
+#endif
+ prev_bp->ovfl = bp;
+ bp->flags = 0;
+ } else
+ bp->flags = BUF_BUCKET;
+ MRU_INSERT(bp);
+ return (bp);
+}
+
+void
+__buf_init(HTAB *hashp, int nbytes)
+{
+ BUFHEAD *bfp;
+ int npages;
+
+ bfp = &(hashp->bufhead);
+ npages = (nbytes + hashp->BSIZE - 1) >> hashp->BSHIFT;
+ npages = MAX(npages, MIN_BUFFERS);
+
+ hashp->nbufs = npages;
+ bfp->next = bfp;
+ bfp->prev = bfp;
+ /*
+ * This space is calloc'd so these are already null.
+ *
+ * bfp->ovfl = NULL;
+ * bfp->flags = 0;
+ * bfp->page = NULL;
+ * bfp->addr = 0;
+ */
+}
+
+int
+__buf_free(HTAB *hashp, int do_free, int to_disk)
+{
+ BUFHEAD *bp;
+
+ /* Need to make sure that buffer manager has been initialized */
+ if (!LRU)
+ return (0);
+ for (bp = LRU; bp != &hashp->bufhead;) {
+ /* Check that the buffer is valid */
+ if (bp->addr || IS_BUCKET(bp->flags)) {
+ if (to_disk && (bp->flags & BUF_MOD) &&
+ __put_page(hashp, bp->page,
+ bp->addr, IS_BUCKET(bp->flags), 0))
+ return (-1);
+ }
+ /* Check if we are freeing stuff */
+ if (do_free) {
+ if (bp->page) {
+ (void)memset(bp->page, 0, hashp->BSIZE);
+ free(bp->page);
+ }
+ BUF_REMOVE(bp);
+ free(bp);
+ bp = LRU;
+ } else
+ bp = bp->prev;
+ }
+ return (0);
+}
+
+void
+__reclaim_buf(HTAB *hashp, BUFHEAD *bp)
+{
+ bp->ovfl = NULL;
+ bp->addr = 0;
+ bp->flags = 0;
+ BUF_REMOVE(bp);
+ LRU_INSERT(bp);
+}
diff --git a/lib/libc/db/hash/hash_func.c b/lib/libc/db/hash/hash_func.c
new file mode 100644
index 000000000000..db32a75b7286
--- /dev/null
+++ b/lib/libc/db/hash/hash_func.c
@@ -0,0 +1,190 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Margo Seltzer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)hash_func.c 8.2 (Berkeley) 2/21/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+#include <db.h>
+#include "hash.h"
+#include "page.h"
+#include "extern.h"
+
+#ifdef notdef
+static u_int32_t hash1(const void *, size_t) __unused;
+static u_int32_t hash2(const void *, size_t) __unused;
+static u_int32_t hash3(const void *, size_t) __unused;
+#endif
+static u_int32_t hash4(const void *, size_t);
+
+/* Default hash function. */
+u_int32_t (*__default_hash)(const void *, size_t) = hash4;
+
+#ifdef notdef
+/*
+ * Assume that we've already split the bucket to which this key hashes,
+ * calculate that bucket, and check that in fact we did already split it.
+ *
+ * EJB's original hsearch hash.
+ */
+#define PRIME1 37
+#define PRIME2 1048583
+
+u_int32_t
+hash1(const void *key, size_t len)
+{
+ u_int32_t h;
+ u_int8_t *k;
+
+ h = 0;
+ k = (u_int8_t *)key;
+ /* Convert string to integer */
+ while (len--)
+ h = h * PRIME1 ^ (*k++ - ' ');
+ h %= PRIME2;
+ return (h);
+}
+
+/*
+ * Phong Vo's linear congruential hash
+ */
+#define dcharhash(h, c) ((h) = 0x63c63cd9*(h) + 0x9c39c33d + (c))
+
+u_int32_t
+hash2(const void *key, size_t len)
+{
+ u_int32_t h;
+ u_int8_t *e, c, *k;
+
+ k = (u_int8_t *)key;
+ e = k + len;
+ for (h = 0; k != e;) {
+ c = *k++;
+ if (!c && k > e)
+ break;
+ dcharhash(h, c);
+ }
+ return (h);
+}
+
+/*
+ * This is INCREDIBLY ugly, but fast. We break the string up into 8 byte
+ * units. On the first time through the loop we get the "leftover bytes"
+ * (strlen % 8). On every other iteration, we perform 8 HASHC's so we handle
+ * all 8 bytes. Essentially, this saves us 7 cmp & branch instructions. If
+ * this routine is heavily used enough, it's worth the ugly coding.
+ *
+ * Ozan Yigit's original sdbm hash.
+ */
+u_int32_t
+hash3(const void *key, size_t len)
+{
+ u_int32_t n, loop;
+ u_int8_t *k;
+
+#define HASHC n = *k++ + 65599 * n
+
+ n = 0;
+ k = (u_int8_t *)key;
+ if (len > 0) {
+ loop = (len + 8 - 1) >> 3;
+
+ switch (len & (8 - 1)) {
+ case 0:
+ do { /* All fall throughs */
+ HASHC;
+ case 7:
+ HASHC;
+ case 6:
+ HASHC;
+ case 5:
+ HASHC;
+ case 4:
+ HASHC;
+ case 3:
+ HASHC;
+ case 2:
+ HASHC;
+ case 1:
+ HASHC;
+ } while (--loop);
+ }
+
+ }
+ return (n);
+}
+#endif /* notdef */
+
+/* Chris Torek's hash function. */
+u_int32_t
+hash4(const void *key, size_t len)
+{
+ u_int32_t h, loop;
+ const u_int8_t *k;
+
+#define HASH4a h = (h << 5) - h + *k++;
+#define HASH4b h = (h << 5) + h + *k++;
+#define HASH4 HASH4b
+
+ h = 0;
+ k = key;
+ if (len > 0) {
+ loop = (len + 8 - 1) >> 3;
+
+ switch (len & (8 - 1)) {
+ case 0:
+ do { /* All fall throughs */
+ HASH4;
+ case 7:
+ HASH4;
+ case 6:
+ HASH4;
+ case 5:
+ HASH4;
+ case 4:
+ HASH4;
+ case 3:
+ HASH4;
+ case 2:
+ HASH4;
+ case 1:
+ HASH4;
+ } while (--loop);
+ }
+
+ }
+ return (h);
+}
diff --git a/lib/libc/db/hash/hash_log2.c b/lib/libc/db/hash/hash_log2.c
new file mode 100644
index 000000000000..0586aa728ec3
--- /dev/null
+++ b/lib/libc/db/hash/hash_log2.c
@@ -0,0 +1,52 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Margo Seltzer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)hash_log2.c 8.2 (Berkeley) 5/31/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <db.h>
+#include "hash.h"
+#include "page.h"
+#include "extern.h"
+
+u_int32_t
+__log2(u_int32_t num)
+{
+ u_int32_t i, limit;
+
+ limit = 1;
+ for (i = 0; limit < num; limit = limit << 1, i++);
+ return (i);
+}
diff --git a/lib/libc/db/hash/hash_page.c b/lib/libc/db/hash/hash_page.c
new file mode 100644
index 000000000000..ec2d184fe23b
--- /dev/null
+++ b/lib/libc/db/hash/hash_page.c
@@ -0,0 +1,940 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Margo Seltzer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)hash_page.c 8.7 (Berkeley) 8/16/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * PACKAGE: hashing
+ *
+ * DESCRIPTION:
+ * Page manipulation for hashing package.
+ *
+ * ROUTINES:
+ *
+ * External
+ * __get_page
+ * __add_ovflpage
+ * Internal
+ * overflow_page
+ * open_temp
+ */
+
+#include "namespace.h"
+#include <sys/param.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#ifdef DEBUG
+#include <assert.h>
+#endif
+#include "un-namespace.h"
+#include "libc_private.h"
+
+#include <db.h>
+#include "hash.h"
+#include "page.h"
+#include "extern.h"
+
+static u_int32_t *fetch_bitmap(HTAB *, int);
+static u_int32_t first_free(u_int32_t);
+static int open_temp(HTAB *);
+static u_int16_t overflow_page(HTAB *);
+static void putpair(char *, const DBT *, const DBT *);
+static void squeeze_key(u_int16_t *, const DBT *, const DBT *);
+static int ugly_split(HTAB *, u_int32_t, BUFHEAD *, BUFHEAD *, int, int);
+
+#define PAGE_INIT(P) { \
+ ((u_int16_t *)(P))[0] = 0; \
+ ((u_int16_t *)(P))[1] = hashp->BSIZE - 3 * sizeof(u_int16_t); \
+ ((u_int16_t *)(P))[2] = hashp->BSIZE; \
+}
+
+/*
+ * This is called AFTER we have verified that there is room on the page for
+ * the pair (PAIRFITS has returned true) so we go right ahead and start moving
+ * stuff on.
+ */
+static void
+putpair(char *p, const DBT *key, const DBT *val)
+{
+ u_int16_t *bp, n, off;
+
+ bp = (u_int16_t *)p;
+
+ /* Enter the key first. */
+ n = bp[0];
+
+ off = OFFSET(bp) - key->size;
+ memmove(p + off, key->data, key->size);
+ bp[++n] = off;
+
+ /* Now the data. */
+ off -= val->size;
+ memmove(p + off, val->data, val->size);
+ bp[++n] = off;
+
+ /* Adjust page info. */
+ bp[0] = n;
+ bp[n + 1] = off - ((n + 3) * sizeof(u_int16_t));
+ bp[n + 2] = off;
+}
+
+/*
+ * Returns:
+ * 0 OK
+ * -1 error
+ */
+int
+__delpair(HTAB *hashp, BUFHEAD *bufp, int ndx)
+{
+ u_int16_t *bp, newoff, pairlen;
+ int n;
+
+ bp = (u_int16_t *)bufp->page;
+ n = bp[0];
+
+ if (bp[ndx + 1] < REAL_KEY)
+ return (__big_delete(hashp, bufp));
+ if (ndx != 1)
+ newoff = bp[ndx - 1];
+ else
+ newoff = hashp->BSIZE;
+ pairlen = newoff - bp[ndx + 1];
+
+ if (ndx != (n - 1)) {
+ /* Hard Case -- need to shuffle keys */
+ int i;
+ char *src = bufp->page + (int)OFFSET(bp);
+ char *dst = src + (int)pairlen;
+ memmove(dst, src, bp[ndx + 1] - OFFSET(bp));
+
+ /* Now adjust the pointers */
+ for (i = ndx + 2; i <= n; i += 2) {
+ if (bp[i + 1] == OVFLPAGE) {
+ bp[i - 2] = bp[i];
+ bp[i - 1] = bp[i + 1];
+ } else {
+ bp[i - 2] = bp[i] + pairlen;
+ bp[i - 1] = bp[i + 1] + pairlen;
+ }
+ }
+ if (ndx == hashp->cndx) {
+ /*
+ * We just removed pair we were "pointing" to.
+ * By moving back the cndx we ensure subsequent
+ * hash_seq() calls won't skip over any entries.
+ */
+ hashp->cndx -= 2;
+ }
+ }
+ /* Finally adjust the page data */
+ bp[n] = OFFSET(bp) + pairlen;
+ bp[n - 1] = bp[n + 1] + pairlen + 2 * sizeof(u_int16_t);
+ bp[0] = n - 2;
+ hashp->NKEYS--;
+
+ bufp->flags |= BUF_MOD;
+ return (0);
+}
+/*
+ * Returns:
+ * 0 ==> OK
+ * -1 ==> Error
+ */
+int
+__split_page(HTAB *hashp, u_int32_t obucket, u_int32_t nbucket)
+{
+ BUFHEAD *new_bufp, *old_bufp;
+ u_int16_t *ino;
+ char *np;
+ DBT key, val;
+ int n, ndx, retval;
+ u_int16_t copyto, diff, off, moved;
+ char *op;
+
+ copyto = (u_int16_t)hashp->BSIZE;
+ off = (u_int16_t)hashp->BSIZE;
+ old_bufp = __get_buf(hashp, obucket, NULL, 0);
+ if (old_bufp == NULL)
+ return (-1);
+ new_bufp = __get_buf(hashp, nbucket, NULL, 0);
+ if (new_bufp == NULL)
+ return (-1);
+
+ old_bufp->flags |= (BUF_MOD | BUF_PIN);
+ new_bufp->flags |= (BUF_MOD | BUF_PIN);
+
+ ino = (u_int16_t *)(op = old_bufp->page);
+ np = new_bufp->page;
+
+ moved = 0;
+
+ for (n = 1, ndx = 1; n < ino[0]; n += 2) {
+ if (ino[n + 1] < REAL_KEY) {
+ retval = ugly_split(hashp, obucket, old_bufp, new_bufp,
+ (int)copyto, (int)moved);
+ old_bufp->flags &= ~BUF_PIN;
+ new_bufp->flags &= ~BUF_PIN;
+ return (retval);
+
+ }
+ key.data = (u_char *)op + ino[n];
+ key.size = off - ino[n];
+
+ if (__call_hash(hashp, key.data, key.size) == obucket) {
+ /* Don't switch page */
+ diff = copyto - off;
+ if (diff) {
+ copyto = ino[n + 1] + diff;
+ memmove(op + copyto, op + ino[n + 1],
+ off - ino[n + 1]);
+ ino[ndx] = copyto + ino[n] - ino[n + 1];
+ ino[ndx + 1] = copyto;
+ } else
+ copyto = ino[n + 1];
+ ndx += 2;
+ } else {
+ /* Switch page */
+ val.data = (u_char *)op + ino[n + 1];
+ val.size = ino[n] - ino[n + 1];
+ putpair(np, &key, &val);
+ moved += 2;
+ }
+
+ off = ino[n + 1];
+ }
+
+ /* Now clean up the page */
+ ino[0] -= moved;
+ FREESPACE(ino) = copyto - sizeof(u_int16_t) * (ino[0] + 3);
+ OFFSET(ino) = copyto;
+
+#ifdef DEBUG3
+ (void)fprintf(stderr, "split %d/%d\n",
+ ((u_int16_t *)np)[0] / 2,
+ ((u_int16_t *)op)[0] / 2);
+#endif
+ /* unpin both pages */
+ old_bufp->flags &= ~BUF_PIN;
+ new_bufp->flags &= ~BUF_PIN;
+ return (0);
+}
+
+/*
+ * Called when we encounter an overflow or big key/data page during split
+ * handling. This is special cased since we have to begin checking whether
+ * the key/data pairs fit on their respective pages and because we may need
+ * overflow pages for both the old and new pages.
+ *
+ * The first page might be a page with regular key/data pairs in which case
+ * we have a regular overflow condition and just need to go on to the next
+ * page or it might be a big key/data pair in which case we need to fix the
+ * big key/data pair.
+ *
+ * Returns:
+ * 0 ==> success
+ * -1 ==> failure
+ */
+static int
+ugly_split(HTAB *hashp,
+ u_int32_t obucket, /* Same as __split_page. */
+ BUFHEAD *old_bufp,
+ BUFHEAD *new_bufp,
+ int copyto, /* First byte on page which contains key/data values. */
+ int moved) /* Number of pairs moved to new page. */
+{
+ BUFHEAD *bufp; /* Buffer header for ino */
+ u_int16_t *ino; /* Page keys come off of */
+ u_int16_t *np; /* New page */
+ u_int16_t *op; /* Page keys go on to if they aren't moving */
+
+ BUFHEAD *last_bfp; /* Last buf header OVFL needing to be freed */
+ DBT key, val;
+ SPLIT_RETURN ret;
+ u_int16_t n, off, ov_addr, scopyto;
+ char *cino; /* Character value of ino */
+
+ bufp = old_bufp;
+ ino = (u_int16_t *)old_bufp->page;
+ np = (u_int16_t *)new_bufp->page;
+ op = (u_int16_t *)old_bufp->page;
+ last_bfp = NULL;
+ scopyto = (u_int16_t)copyto; /* ANSI */
+
+ n = ino[0] - 1;
+ while (n < ino[0]) {
+ if (ino[2] < REAL_KEY && ino[2] != OVFLPAGE) {
+ if (__big_split(hashp, old_bufp,
+ new_bufp, bufp, bufp->addr, obucket, &ret))
+ return (-1);
+ old_bufp = ret.oldp;
+ if (!old_bufp)
+ return (-1);
+ op = (u_int16_t *)old_bufp->page;
+ new_bufp = ret.newp;
+ if (!new_bufp)
+ return (-1);
+ np = (u_int16_t *)new_bufp->page;
+ bufp = ret.nextp;
+ if (!bufp)
+ return (0);
+ cino = (char *)bufp->page;
+ ino = (u_int16_t *)cino;
+ last_bfp = ret.nextp;
+ } else if (ino[n + 1] == OVFLPAGE) {
+ ov_addr = ino[n];
+ /*
+ * Fix up the old page -- the extra 2 are the fields
+ * which contained the overflow information.
+ */
+ ino[0] -= (moved + 2);
+ FREESPACE(ino) =
+ scopyto - sizeof(u_int16_t) * (ino[0] + 3);
+ OFFSET(ino) = scopyto;
+
+ bufp = __get_buf(hashp, ov_addr, bufp, 0);
+ if (!bufp)
+ return (-1);
+
+ ino = (u_int16_t *)bufp->page;
+ n = 1;
+ scopyto = hashp->BSIZE;
+ moved = 0;
+
+ if (last_bfp)
+ __free_ovflpage(hashp, last_bfp);
+ last_bfp = bufp;
+ }
+ /* Move regular sized pairs of there are any */
+ off = hashp->BSIZE;
+ for (n = 1; (n < ino[0]) && (ino[n + 1] >= REAL_KEY); n += 2) {
+ cino = (char *)ino;
+ key.data = (u_char *)cino + ino[n];
+ key.size = off - ino[n];
+ val.data = (u_char *)cino + ino[n + 1];
+ val.size = ino[n] - ino[n + 1];
+ off = ino[n + 1];
+
+ if (__call_hash(hashp, key.data, key.size) == obucket) {
+ /* Keep on old page */
+ if (PAIRFITS(op, (&key), (&val)))
+ putpair((char *)op, &key, &val);
+ else {
+ old_bufp =
+ __add_ovflpage(hashp, old_bufp);
+ if (!old_bufp)
+ return (-1);
+ op = (u_int16_t *)old_bufp->page;
+ putpair((char *)op, &key, &val);
+ }
+ old_bufp->flags |= BUF_MOD;
+ } else {
+ /* Move to new page */
+ if (PAIRFITS(np, (&key), (&val)))
+ putpair((char *)np, &key, &val);
+ else {
+ new_bufp =
+ __add_ovflpage(hashp, new_bufp);
+ if (!new_bufp)
+ return (-1);
+ np = (u_int16_t *)new_bufp->page;
+ putpair((char *)np, &key, &val);
+ }
+ new_bufp->flags |= BUF_MOD;
+ }
+ }
+ }
+ if (last_bfp)
+ __free_ovflpage(hashp, last_bfp);
+ return (0);
+}
+
+/*
+ * Add the given pair to the page
+ *
+ * Returns:
+ * 0 ==> OK
+ * 1 ==> failure
+ */
+int
+__addel(HTAB *hashp, BUFHEAD *bufp, const DBT *key, const DBT *val)
+{
+ u_int16_t *bp, *sop;
+ int do_expand;
+
+ bp = (u_int16_t *)bufp->page;
+ do_expand = 0;
+ while (bp[0] && (bp[2] < REAL_KEY || bp[bp[0]] < REAL_KEY))
+ /* Exception case */
+ if (bp[2] == FULL_KEY_DATA && bp[0] == 2)
+ /* This is the last page of a big key/data pair
+ and we need to add another page */
+ break;
+ else if (bp[2] < REAL_KEY && bp[bp[0]] != OVFLPAGE) {
+ bufp = __get_buf(hashp, bp[bp[0] - 1], bufp, 0);
+ if (!bufp)
+ return (-1);
+ bp = (u_int16_t *)bufp->page;
+ } else if (bp[bp[0]] != OVFLPAGE) {
+ /* Short key/data pairs, no more pages */
+ break;
+ } else {
+ /* Try to squeeze key on this page */
+ if (bp[2] >= REAL_KEY &&
+ FREESPACE(bp) >= PAIRSIZE(key, val)) {
+ squeeze_key(bp, key, val);
+ goto stats;
+ } else {
+ bufp = __get_buf(hashp, bp[bp[0] - 1], bufp, 0);
+ if (!bufp)
+ return (-1);
+ bp = (u_int16_t *)bufp->page;
+ }
+ }
+
+ if (PAIRFITS(bp, key, val))
+ putpair(bufp->page, key, val);
+ else {
+ do_expand = 1;
+ bufp = __add_ovflpage(hashp, bufp);
+ if (!bufp)
+ return (-1);
+ sop = (u_int16_t *)bufp->page;
+
+ if (PAIRFITS(sop, key, val))
+ putpair((char *)sop, key, val);
+ else
+ if (__big_insert(hashp, bufp, key, val))
+ return (-1);
+ }
+stats:
+ bufp->flags |= BUF_MOD;
+ /*
+ * If the average number of keys per bucket exceeds the fill factor,
+ * expand the table.
+ */
+ hashp->NKEYS++;
+ if (do_expand ||
+ (hashp->NKEYS / (hashp->MAX_BUCKET + 1) > hashp->FFACTOR))
+ return (__expand_table(hashp));
+ return (0);
+}
+
+/*
+ *
+ * Returns:
+ * pointer on success
+ * NULL on error
+ */
+BUFHEAD *
+__add_ovflpage(HTAB *hashp, BUFHEAD *bufp)
+{
+ u_int16_t *sp, ndx, ovfl_num;
+#ifdef DEBUG1
+ int tmp1, tmp2;
+#endif
+ sp = (u_int16_t *)bufp->page;
+
+ /* Check if we are dynamically determining the fill factor */
+ if (hashp->FFACTOR == DEF_FFACTOR) {
+ hashp->FFACTOR = sp[0] >> 1;
+ if (hashp->FFACTOR < MIN_FFACTOR)
+ hashp->FFACTOR = MIN_FFACTOR;
+ }
+ bufp->flags |= BUF_MOD;
+ ovfl_num = overflow_page(hashp);
+#ifdef DEBUG1
+ tmp1 = bufp->addr;
+ tmp2 = bufp->ovfl ? bufp->ovfl->addr : 0;
+#endif
+ if (!ovfl_num || !(bufp->ovfl = __get_buf(hashp, ovfl_num, bufp, 1)))
+ return (NULL);
+ bufp->ovfl->flags |= BUF_MOD;
+#ifdef DEBUG1
+ (void)fprintf(stderr, "ADDOVFLPAGE: %d->ovfl was %d is now %d\n",
+ tmp1, tmp2, bufp->ovfl->addr);
+#endif
+ ndx = sp[0];
+ /*
+ * Since a pair is allocated on a page only if there's room to add
+ * an overflow page, we know that the OVFL information will fit on
+ * the page.
+ */
+ sp[ndx + 4] = OFFSET(sp);
+ sp[ndx + 3] = FREESPACE(sp) - OVFLSIZE;
+ sp[ndx + 1] = ovfl_num;
+ sp[ndx + 2] = OVFLPAGE;
+ sp[0] = ndx + 2;
+#ifdef HASH_STATISTICS
+ hash_overflows++;
+#endif
+ return (bufp->ovfl);
+}
+
+/*
+ * Returns:
+ * 0 indicates SUCCESS
+ * -1 indicates FAILURE
+ */
+int
+__get_page(HTAB *hashp, char *p, u_int32_t bucket, int is_bucket, int is_disk,
+ int is_bitmap)
+{
+ int fd, page, size, rsize;
+ u_int16_t *bp;
+
+ fd = hashp->fp;
+ size = hashp->BSIZE;
+
+ if ((fd == -1) || !is_disk) {
+ PAGE_INIT(p);
+ return (0);
+ }
+ if (is_bucket)
+ page = BUCKET_TO_PAGE(bucket);
+ else
+ page = OADDR_TO_PAGE(bucket);
+ if ((rsize = pread(fd, p, size, (off_t)page << hashp->BSHIFT)) == -1)
+ return (-1);
+ bp = (u_int16_t *)p;
+ if (!rsize)
+ bp[0] = 0; /* We hit the EOF, so initialize a new page */
+ else
+ if (rsize != size) {
+ errno = EFTYPE;
+ return (-1);
+ }
+ if (!is_bitmap && !bp[0]) {
+ PAGE_INIT(p);
+ } else
+ if (hashp->LORDER != BYTE_ORDER) {
+ int i, max;
+
+ if (is_bitmap) {
+ max = hashp->BSIZE >> 2; /* divide by 4 */
+ for (i = 0; i < max; i++)
+ M_32_SWAP(((int *)p)[i]);
+ } else {
+ M_16_SWAP(bp[0]);
+ max = bp[0] + 2;
+ for (i = 1; i <= max; i++)
+ M_16_SWAP(bp[i]);
+ }
+ }
+ return (0);
+}
+
+/*
+ * Write page p to disk
+ *
+ * Returns:
+ * 0 ==> OK
+ * -1 ==>failure
+ */
+int
+__put_page(HTAB *hashp, char *p, u_int32_t bucket, int is_bucket, int is_bitmap)
+{
+ int fd, page, size;
+ ssize_t wsize;
+ char pbuf[MAX_BSIZE];
+
+ size = hashp->BSIZE;
+ if ((hashp->fp == -1) && open_temp(hashp))
+ return (-1);
+ fd = hashp->fp;
+
+ if (hashp->LORDER != BYTE_ORDER) {
+ int i, max;
+
+ memcpy(pbuf, p, size);
+ if (is_bitmap) {
+ max = hashp->BSIZE >> 2; /* divide by 4 */
+ for (i = 0; i < max; i++)
+ M_32_SWAP(((int *)pbuf)[i]);
+ } else {
+ uint16_t *bp = (uint16_t *)(void *)pbuf;
+ max = bp[0] + 2;
+ for (i = 0; i <= max; i++)
+ M_16_SWAP(bp[i]);
+ }
+ p = pbuf;
+ }
+ if (is_bucket)
+ page = BUCKET_TO_PAGE(bucket);
+ else
+ page = OADDR_TO_PAGE(bucket);
+ if ((wsize = pwrite(fd, p, size, (off_t)page << hashp->BSHIFT)) == -1)
+ /* Errno is set */
+ return (-1);
+ if (wsize != size) {
+ errno = EFTYPE;
+ return (-1);
+ }
+ return (0);
+}
+
+#define BYTE_MASK ((1 << INT_BYTE_SHIFT) -1)
+/*
+ * Initialize a new bitmap page. Bitmap pages are left in memory
+ * once they are read in.
+ */
+int
+__ibitmap(HTAB *hashp, int pnum, int nbits, int ndx)
+{
+ u_int32_t *ip;
+ int clearbytes, clearints;
+
+ if ((ip = (u_int32_t *)malloc(hashp->BSIZE)) == NULL)
+ return (1);
+ hashp->nmaps++;
+ clearints = ((nbits - 1) >> INT_BYTE_SHIFT) + 1;
+ clearbytes = clearints << INT_TO_BYTE;
+ (void)memset((char *)ip, 0, clearbytes);
+ (void)memset(((char *)ip) + clearbytes, 0xFF,
+ hashp->BSIZE - clearbytes);
+ ip[clearints - 1] = ALL_SET << (nbits & BYTE_MASK);
+ SETBIT(ip, 0);
+ hashp->BITMAPS[ndx] = (u_int16_t)pnum;
+ hashp->mapp[ndx] = ip;
+ return (0);
+}
+
+static u_int32_t
+first_free(u_int32_t map)
+{
+ u_int32_t i, mask;
+
+ mask = 0x1;
+ for (i = 0; i < BITS_PER_MAP; i++) {
+ if (!(mask & map))
+ return (i);
+ mask = mask << 1;
+ }
+ return (i);
+}
+
+static u_int16_t
+overflow_page(HTAB *hashp)
+{
+ u_int32_t *freep;
+ int max_free, offset, splitnum;
+ u_int16_t addr;
+ int bit, first_page, free_bit, free_page, i, in_use_bits, j;
+#ifdef DEBUG2
+ int tmp1, tmp2;
+#endif
+ splitnum = hashp->OVFL_POINT;
+ max_free = hashp->SPARES[splitnum];
+
+ free_page = (max_free - 1) >> (hashp->BSHIFT + BYTE_SHIFT);
+ free_bit = (max_free - 1) & ((hashp->BSIZE << BYTE_SHIFT) - 1);
+
+ /* Look through all the free maps to find the first free block */
+ first_page = hashp->LAST_FREED >>(hashp->BSHIFT + BYTE_SHIFT);
+ for ( i = first_page; i <= free_page; i++ ) {
+ if (!(freep = (u_int32_t *)hashp->mapp[i]) &&
+ !(freep = fetch_bitmap(hashp, i)))
+ return (0);
+ if (i == free_page)
+ in_use_bits = free_bit;
+ else
+ in_use_bits = (hashp->BSIZE << BYTE_SHIFT) - 1;
+
+ if (i == first_page) {
+ bit = hashp->LAST_FREED &
+ ((hashp->BSIZE << BYTE_SHIFT) - 1);
+ j = bit / BITS_PER_MAP;
+ bit = rounddown2(bit, BITS_PER_MAP);
+ } else {
+ bit = 0;
+ j = 0;
+ }
+ for (; bit <= in_use_bits; j++, bit += BITS_PER_MAP)
+ if (freep[j] != ALL_SET)
+ goto found;
+ }
+
+ /* No Free Page Found */
+ hashp->LAST_FREED = hashp->SPARES[splitnum];
+ hashp->SPARES[splitnum]++;
+ offset = hashp->SPARES[splitnum] -
+ (splitnum ? hashp->SPARES[splitnum - 1] : 0);
+
+#define OVMSG "HASH: Out of overflow pages. Increase page size\n"
+ if (offset > SPLITMASK) {
+ if (++splitnum >= NCACHED) {
+ (void)_write(STDERR_FILENO, OVMSG, sizeof(OVMSG) - 1);
+ errno = EFBIG;
+ return (0);
+ }
+ hashp->OVFL_POINT = splitnum;
+ hashp->SPARES[splitnum] = hashp->SPARES[splitnum-1];
+ hashp->SPARES[splitnum-1]--;
+ offset = 1;
+ }
+
+ /* Check if we need to allocate a new bitmap page */
+ if (free_bit == (hashp->BSIZE << BYTE_SHIFT) - 1) {
+ free_page++;
+ if (free_page >= NCACHED) {
+ (void)_write(STDERR_FILENO, OVMSG, sizeof(OVMSG) - 1);
+ errno = EFBIG;
+ return (0);
+ }
+ /*
+ * This is tricky. The 1 indicates that you want the new page
+ * allocated with 1 clear bit. Actually, you are going to
+ * allocate 2 pages from this map. The first is going to be
+ * the map page, the second is the overflow page we were
+ * looking for. The init_bitmap routine automatically, sets
+ * the first bit of itself to indicate that the bitmap itself
+ * is in use. We would explicitly set the second bit, but
+ * don't have to if we tell init_bitmap not to leave it clear
+ * in the first place.
+ */
+ if (__ibitmap(hashp,
+ (int)OADDR_OF(splitnum, offset), 1, free_page))
+ return (0);
+ hashp->SPARES[splitnum]++;
+#ifdef DEBUG2
+ free_bit = 2;
+#endif
+ offset++;
+ if (offset > SPLITMASK) {
+ if (++splitnum >= NCACHED) {
+ (void)_write(STDERR_FILENO, OVMSG,
+ sizeof(OVMSG) - 1);
+ errno = EFBIG;
+ return (0);
+ }
+ hashp->OVFL_POINT = splitnum;
+ hashp->SPARES[splitnum] = hashp->SPARES[splitnum-1];
+ hashp->SPARES[splitnum-1]--;
+ offset = 0;
+ }
+ } else {
+ /*
+ * Free_bit addresses the last used bit. Bump it to address
+ * the first available bit.
+ */
+ free_bit++;
+ SETBIT(freep, free_bit);
+ }
+
+ /* Calculate address of the new overflow page */
+ addr = OADDR_OF(splitnum, offset);
+#ifdef DEBUG2
+ (void)fprintf(stderr, "OVERFLOW_PAGE: ADDR: %d BIT: %d PAGE %d\n",
+ addr, free_bit, free_page);
+#endif
+ return (addr);
+
+found:
+ bit = bit + first_free(freep[j]);
+ SETBIT(freep, bit);
+#ifdef DEBUG2
+ tmp1 = bit;
+ tmp2 = i;
+#endif
+ /*
+ * Bits are addressed starting with 0, but overflow pages are addressed
+ * beginning at 1. Bit is a bit addressnumber, so we need to increment
+ * it to convert it to a page number.
+ */
+ bit = 1 + bit + (i * (hashp->BSIZE << BYTE_SHIFT));
+ if (bit >= hashp->LAST_FREED)
+ hashp->LAST_FREED = bit - 1;
+
+ /* Calculate the split number for this page */
+ for (i = 0; (i < splitnum) && (bit > hashp->SPARES[i]); i++);
+ offset = (i ? bit - hashp->SPARES[i - 1] : bit);
+ if (offset >= SPLITMASK) {
+ (void)_write(STDERR_FILENO, OVMSG, sizeof(OVMSG) - 1);
+ errno = EFBIG;
+ return (0); /* Out of overflow pages */
+ }
+ addr = OADDR_OF(i, offset);
+#ifdef DEBUG2
+ (void)fprintf(stderr, "OVERFLOW_PAGE: ADDR: %d BIT: %d PAGE %d\n",
+ addr, tmp1, tmp2);
+#endif
+
+ /* Allocate and return the overflow page */
+ return (addr);
+}
+
+/*
+ * Mark this overflow page as free.
+ */
+void
+__free_ovflpage(HTAB *hashp, BUFHEAD *obufp)
+{
+ u_int16_t addr;
+ u_int32_t *freep;
+ int bit_address, free_page, free_bit;
+ u_int16_t ndx;
+
+ addr = obufp->addr;
+#ifdef DEBUG1
+ (void)fprintf(stderr, "Freeing %d\n", addr);
+#endif
+ ndx = (((u_int16_t)addr) >> SPLITSHIFT);
+ bit_address =
+ (ndx ? hashp->SPARES[ndx - 1] : 0) + (addr & SPLITMASK) - 1;
+ if (bit_address < hashp->LAST_FREED)
+ hashp->LAST_FREED = bit_address;
+ free_page = (bit_address >> (hashp->BSHIFT + BYTE_SHIFT));
+ free_bit = bit_address & ((hashp->BSIZE << BYTE_SHIFT) - 1);
+
+ if (!(freep = hashp->mapp[free_page]))
+ freep = fetch_bitmap(hashp, free_page);
+#ifdef DEBUG
+ /*
+ * This had better never happen. It means we tried to read a bitmap
+ * that has already had overflow pages allocated off it, and we
+ * failed to read it from the file.
+ */
+ if (!freep)
+ assert(0);
+#endif
+ CLRBIT(freep, free_bit);
+#ifdef DEBUG2
+ (void)fprintf(stderr, "FREE_OVFLPAGE: ADDR: %d BIT: %d PAGE %d\n",
+ obufp->addr, free_bit, free_page);
+#endif
+ __reclaim_buf(hashp, obufp);
+}
+
+/*
+ * Returns:
+ * 0 success
+ * -1 failure
+ */
+static int
+open_temp(HTAB *hashp)
+{
+ sigset_t set, oset;
+ int len;
+ char *envtmp = NULL;
+ char path[MAXPATHLEN];
+
+ if (issetugid() == 0)
+ envtmp = getenv("TMPDIR");
+ len = snprintf(path,
+ sizeof(path), "%s/_hash.XXXXXX", envtmp ? envtmp : "/tmp");
+ if (len < 0 || len >= (int)sizeof(path)) {
+ errno = ENAMETOOLONG;
+ return (-1);
+ }
+
+ /* Block signals; make sure file goes away at process exit. */
+ (void)sigfillset(&set);
+ (void)__libc_sigprocmask(SIG_BLOCK, &set, &oset);
+ if ((hashp->fp = mkostemp(path, O_CLOEXEC)) != -1)
+ (void)unlink(path);
+ (void)__libc_sigprocmask(SIG_SETMASK, &oset, (sigset_t *)NULL);
+ return (hashp->fp != -1 ? 0 : -1);
+}
+
+/*
+ * We have to know that the key will fit, but the last entry on the page is
+ * an overflow pair, so we need to shift things.
+ */
+static void
+squeeze_key(u_int16_t *sp, const DBT *key, const DBT *val)
+{
+ char *p;
+ u_int16_t free_space, n, off, pageno;
+
+ p = (char *)sp;
+ n = sp[0];
+ free_space = FREESPACE(sp);
+ off = OFFSET(sp);
+
+ pageno = sp[n - 1];
+ off -= key->size;
+ sp[n - 1] = off;
+ memmove(p + off, key->data, key->size);
+ off -= val->size;
+ sp[n] = off;
+ memmove(p + off, val->data, val->size);
+ sp[0] = n + 2;
+ sp[n + 1] = pageno;
+ sp[n + 2] = OVFLPAGE;
+ FREESPACE(sp) = free_space - PAIRSIZE(key, val);
+ OFFSET(sp) = off;
+}
+
+static u_int32_t *
+fetch_bitmap(HTAB *hashp, int ndx)
+{
+ if (ndx >= hashp->nmaps)
+ return (NULL);
+ if ((hashp->mapp[ndx] = (u_int32_t *)malloc(hashp->BSIZE)) == NULL)
+ return (NULL);
+ if (__get_page(hashp,
+ (char *)hashp->mapp[ndx], hashp->BITMAPS[ndx], 0, 1, 1)) {
+ free(hashp->mapp[ndx]);
+ return (NULL);
+ }
+ return (hashp->mapp[ndx]);
+}
+
+#ifdef DEBUG4
+int
+print_chain(int addr)
+{
+ BUFHEAD *bufp;
+ short *bp, oaddr;
+
+ (void)fprintf(stderr, "%d ", addr);
+ bufp = __get_buf(hashp, addr, NULL, 0);
+ bp = (short *)bufp->page;
+ while (bp[0] && ((bp[bp[0]] == OVFLPAGE) ||
+ ((bp[0] > 2) && bp[2] < REAL_KEY))) {
+ oaddr = bp[bp[0] - 1];
+ (void)fprintf(stderr, "%d ", (int)oaddr);
+ bufp = __get_buf(hashp, (int)oaddr, bufp, 0);
+ bp = (short *)bufp->page;
+ }
+ (void)fprintf(stderr, "\n");
+}
+#endif
diff --git a/lib/libc/db/hash/ndbm.c b/lib/libc/db/hash/ndbm.c
new file mode 100644
index 000000000000..1a02d005e8c3
--- /dev/null
+++ b/lib/libc/db/hash/ndbm.c
@@ -0,0 +1,212 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Margo Seltzer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)ndbm.c 8.4 (Berkeley) 7/21/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * This package provides a dbm compatible interface to the new hashing
+ * package described in db(3).
+ */
+
+#include <sys/param.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <ndbm.h>
+#include "hash.h"
+
+/*
+ * Returns:
+ * *DBM on success
+ * NULL on failure
+ */
+extern DBM *
+dbm_open(const char *file, int flags, mode_t mode)
+{
+ HASHINFO info;
+ char path[MAXPATHLEN];
+
+ info.bsize = 4096;
+ info.ffactor = 40;
+ info.nelem = 1;
+ info.cachesize = 0;
+ info.hash = NULL;
+ info.lorder = 0;
+
+ if( strlen(file) >= sizeof(path) - strlen(DBM_SUFFIX)) {
+ errno = ENAMETOOLONG;
+ return(NULL);
+ }
+ (void)strcpy(path, file);
+ (void)strcat(path, DBM_SUFFIX);
+ return ((DBM *)__hash_open(path, flags, mode, &info, 0));
+}
+
+extern void
+dbm_close(DBM *db)
+{
+ (void)(db->close)(db);
+}
+
+/*
+ * Returns:
+ * DATUM on success
+ * NULL on failure
+ */
+extern datum
+dbm_fetch(DBM *db, datum key)
+{
+ datum retdata;
+ int status;
+ DBT dbtkey, dbtretdata;
+
+ dbtkey.data = key.dptr;
+ dbtkey.size = key.dsize;
+ status = (db->get)(db, &dbtkey, &dbtretdata, 0);
+ if (status) {
+ dbtretdata.data = NULL;
+ dbtretdata.size = 0;
+ }
+ retdata.dptr = dbtretdata.data;
+ retdata.dsize = dbtretdata.size;
+ return (retdata);
+}
+
+/*
+ * Returns:
+ * DATUM on success
+ * NULL on failure
+ */
+extern datum
+dbm_firstkey(DBM *db)
+{
+ int status;
+ datum retkey;
+ DBT dbtretkey, dbtretdata;
+
+ status = (db->seq)(db, &dbtretkey, &dbtretdata, R_FIRST);
+ if (status)
+ dbtretkey.data = NULL;
+ retkey.dptr = dbtretkey.data;
+ retkey.dsize = dbtretkey.size;
+ return (retkey);
+}
+
+/*
+ * Returns:
+ * DATUM on success
+ * NULL on failure
+ */
+extern datum
+dbm_nextkey(DBM *db)
+{
+ int status;
+ datum retkey;
+ DBT dbtretkey, dbtretdata;
+
+ status = (db->seq)(db, &dbtretkey, &dbtretdata, R_NEXT);
+ if (status)
+ dbtretkey.data = NULL;
+ retkey.dptr = dbtretkey.data;
+ retkey.dsize = dbtretkey.size;
+ return (retkey);
+}
+
+/*
+ * Returns:
+ * 0 on success
+ * <0 failure
+ */
+extern int
+dbm_delete(DBM *db, datum key)
+{
+ int status;
+ DBT dbtkey;
+
+ dbtkey.data = key.dptr;
+ dbtkey.size = key.dsize;
+ status = (db->del)(db, &dbtkey, 0);
+ if (status)
+ return (-1);
+ else
+ return (0);
+}
+
+/*
+ * Returns:
+ * 0 on success
+ * <0 failure
+ * 1 if DBM_INSERT and entry exists
+ */
+extern int
+dbm_store(DBM *db, datum key, datum data, int flags)
+{
+ DBT dbtkey, dbtdata;
+
+ dbtkey.data = key.dptr;
+ dbtkey.size = key.dsize;
+ dbtdata.data = data.dptr;
+ dbtdata.size = data.dsize;
+ return ((db->put)(db, &dbtkey, &dbtdata,
+ (flags == DBM_INSERT) ? R_NOOVERWRITE : 0));
+}
+
+extern int
+dbm_error(DBM *db)
+{
+ HTAB *hp;
+
+ hp = (HTAB *)db->internal;
+ return (hp->error);
+}
+
+extern int
+dbm_clearerr(DBM *db)
+{
+ HTAB *hp;
+
+ hp = (HTAB *)db->internal;
+ hp->error = 0;
+ return (0);
+}
+
+extern int
+dbm_dirfno(DBM *db)
+{
+ return(((HTAB *)db->internal)->fp);
+}
diff --git a/lib/libc/db/hash/page.h b/lib/libc/db/hash/page.h
new file mode 100644
index 000000000000..6959fe87eeb7
--- /dev/null
+++ b/lib/libc/db/hash/page.h
@@ -0,0 +1,89 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Margo Seltzer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)page.h 8.2 (Berkeley) 5/31/94
+ * $FreeBSD$
+ */
+
+/*
+ * Definitions for hashing page file format.
+ */
+
+/*
+ * routines dealing with a data page
+ *
+ * page format:
+ * +------------------------------+
+ * p | n | keyoff | datoff | keyoff |
+ * +------------+--------+--------+
+ * | datoff | free | ptr | --> |
+ * +--------+---------------------+
+ * | F R E E A R E A |
+ * +--------------+---------------+
+ * | <---- - - - | data |
+ * +--------+-----+----+----------+
+ * | key | data | key |
+ * +--------+----------+----------+
+ *
+ * Pointer to the free space is always: p[p[0] + 2]
+ * Amount of free space on the page is: p[p[0] + 1]
+ */
+
+/*
+ * How many bytes required for this pair?
+ * 2 shorts in the table at the top of the page + room for the
+ * key and room for the data
+ *
+ * We prohibit entering a pair on a page unless there is also room to append
+ * an overflow page. The reason for this it that you can get in a situation
+ * where a single key/data pair fits on a page, but you can't append an
+ * overflow page and later you'd have to split the key/data and handle like
+ * a big pair.
+ * You might as well do this up front.
+ */
+
+#define PAIRSIZE(K,D) (2*sizeof(u_int16_t) + (K)->size + (D)->size)
+#define BIGOVERHEAD (4*sizeof(u_int16_t))
+#define KEYSIZE(K) (4*sizeof(u_int16_t) + (K)->size);
+#define OVFLSIZE (2*sizeof(u_int16_t))
+#define FREESPACE(P) ((P)[(P)[0]+1])
+#define OFFSET(P) ((P)[(P)[0]+2])
+#define PAIRFITS(P,K,D) \
+ (((P)[2] >= REAL_KEY) && \
+ (PAIRSIZE((K),(D)) + OVFLSIZE) <= FREESPACE((P)))
+#define PAGE_META(N) (((N)+3) * sizeof(u_int16_t))
+
+typedef struct {
+ BUFHEAD *newp;
+ BUFHEAD *oldp;
+ BUFHEAD *nextp;
+ u_int16_t next_addr;
+} SPLIT_RETURN;
diff --git a/lib/libc/db/man/Makefile.inc b/lib/libc/db/man/Makefile.inc
new file mode 100644
index 000000000000..7c2db8bf5ea4
--- /dev/null
+++ b/lib/libc/db/man/Makefile.inc
@@ -0,0 +1,18 @@
+# from @(#)Makefile.inc 8.1 (Berkeley) 6/4/93
+# $FreeBSD$
+
+.PATH: ${LIBC_SRCTOP}/db/man
+
+MAN+= btree.3 dbm.3 dbopen.3 hash.3 mpool.3 recno.3
+
+MLINKS+= dbm.3 dbm_clearerr.3
+MLINKS+= dbm.3 dbm_close.3
+MLINKS+= dbm.3 dbm_delete.3
+MLINKS+= dbm.3 dbm_dirnfo.3
+MLINKS+= dbm.3 dbm_error.3
+MLINKS+= dbm.3 dbm_fetch.3
+MLINKS+= dbm.3 dbm_firstkey.3
+MLINKS+= dbm.3 dbm_nextkey.3
+MLINKS+= dbm.3 dbm_open.3
+MLINKS+= dbm.3 dbm_store.3
+MLINKS+= dbopen.3 db.3
diff --git a/lib/libc/db/man/btree.3 b/lib/libc/db/man/btree.3
new file mode 100644
index 000000000000..42fc254dd615
--- /dev/null
+++ b/lib/libc/db/man/btree.3
@@ -0,0 +1,271 @@
+.\" Copyright (c) 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)btree.3 8.4 (Berkeley) 8/18/94
+.\" $FreeBSD$
+.\"
+.Dd August 18, 1994
+.Dt BTREE 3
+.Os
+.Sh NAME
+.Nm btree
+.Nd "btree database access method"
+.Sh SYNOPSIS
+.In sys/types.h
+.In db.h
+.Sh DESCRIPTION
+The routine
+.Fn dbopen
+is the library interface to database files.
+One of the supported file formats is
+.Nm
+files.
+The general description of the database access methods is in
+.Xr dbopen 3 ,
+this manual page describes only the
+.Nm
+specific information.
+.Pp
+The
+.Nm
+data structure is a sorted, balanced tree structure storing
+associated key/data pairs.
+.Pp
+The
+.Nm
+access method specific data structure provided to
+.Fn dbopen
+is defined in the
+.In db.h
+include file as follows:
+.Bd -literal
+typedef struct {
+ u_long flags;
+ u_int cachesize;
+ int maxkeypage;
+ int minkeypage;
+ u_int psize;
+ int (*compare)(const DBT *key1, const DBT *key2);
+ size_t (*prefix)(const DBT *key1, const DBT *key2);
+ int lorder;
+} BTREEINFO;
+.Ed
+.Pp
+The elements of this structure are as follows:
+.Bl -tag -width indent
+.It Va flags
+The flag value is specified by
+.Em or Ns 'ing
+any of the following values:
+.Bl -tag -width indent
+.It Dv R_DUP
+Permit duplicate keys in the tree, i.e., permit insertion if the key to be
+inserted already exists in the tree.
+The default behavior, as described in
+.Xr dbopen 3 ,
+is to overwrite a matching key when inserting a new key or to fail if
+the
+.Dv R_NOOVERWRITE
+flag is specified.
+The
+.Dv R_DUP
+flag is overridden by the
+.Dv R_NOOVERWRITE
+flag, and if the
+.Dv R_NOOVERWRITE
+flag is specified, attempts to insert duplicate keys into
+the tree will fail.
+.Pp
+If the database contains duplicate keys, the order of retrieval of
+key/data pairs is undefined if the
+.Va get
+routine is used, however,
+.Va seq
+routine calls with the
+.Dv R_CURSOR
+flag set will always return the logical
+.Dq first
+of any group of duplicate keys.
+.El
+.It Va cachesize
+A suggested maximum size (in bytes) of the memory cache.
+This value is
+.Em only
+advisory, and the access method will allocate more memory rather than fail.
+Since every search examines the root page of the tree, caching the most
+recently used pages substantially improves access time.
+In addition, physical writes are delayed as long as possible, so a moderate
+cache can reduce the number of I/O operations significantly.
+Obviously, using a cache increases (but only increases) the likelihood of
+corruption or lost data if the system crashes while a tree is being modified.
+If
+.Va cachesize
+is 0 (no size is specified) a default cache is used.
+.It Va maxkeypage
+The maximum number of keys which will be stored on any single page.
+Not currently implemented.
+.\" The maximum number of keys which will be stored on any single page.
+.\" Because of the way the
+.\" .Nm
+.\" data structure works,
+.\" .Va maxkeypage
+.\" must always be greater than or equal to 2.
+.\" If
+.\" .Va maxkeypage
+.\" is 0 (no maximum number of keys is specified) the page fill factor is
+.\" made as large as possible (which is almost invariably what is wanted).
+.It Va minkeypage
+The minimum number of keys which will be stored on any single page.
+This value is used to determine which keys will be stored on overflow
+pages, i.e., if a key or data item is longer than the pagesize divided
+by the minkeypage value, it will be stored on overflow pages instead
+of in the page itself.
+If
+.Va minkeypage
+is 0 (no minimum number of keys is specified) a value of 2 is used.
+.It Va psize
+Page size is the size (in bytes) of the pages used for nodes in the tree.
+The minimum page size is 512 bytes and the maximum page size is 64K.
+If
+.Va psize
+is 0 (no page size is specified) a page size is chosen based on the
+underlying file system I/O block size.
+.It Va compare
+Compare is the key comparison function.
+It must return an integer less than, equal to, or greater than zero if the
+first key argument is considered to be respectively less than, equal to,
+or greater than the second key argument.
+The same comparison function must be used on a given tree every time it
+is opened.
+If
+.Va compare
+is
+.Dv NULL
+(no comparison function is specified), the keys are compared
+lexically, with shorter keys considered less than longer keys.
+.It Va prefix
+The
+.Va prefix
+element
+is the prefix comparison function.
+If specified, this routine must return the number of bytes of the second key
+argument which are necessary to determine that it is greater than the first
+key argument.
+If the keys are equal, the key length should be returned.
+Note, the usefulness of this routine is very data dependent, but, in some
+data sets can produce significantly reduced tree sizes and search times.
+If
+.Va prefix
+is
+.Dv NULL
+(no prefix function is specified),
+.Em and
+no comparison function is specified, a default lexical comparison routine
+is used.
+If
+.Va prefix
+is
+.Dv NULL
+and a comparison routine is specified, no prefix comparison is
+done.
+.It Va lorder
+The byte order for integers in the stored database metadata.
+The number should represent the order as an integer; for example,
+big endian order would be the number 4,321.
+If
+.Va lorder
+is 0 (no order is specified) the current host order is used.
+.El
+.Pp
+If the file already exists (and the
+.Dv O_TRUNC
+flag is not specified), the
+values specified for the
+.Va flags , lorder
+and
+.Va psize
+arguments
+are ignored
+in favor of the values used when the tree was created.
+.Pp
+Forward sequential scans of a tree are from the least key to the greatest.
+.Pp
+Space freed up by deleting key/data pairs from the tree is never reclaimed,
+although it is normally made available for reuse.
+This means that the
+.Nm
+storage structure is grow-only.
+The only solutions are to avoid excessive deletions, or to create a fresh
+tree periodically from a scan of an existing one.
+.Pp
+Searches, insertions, and deletions in a
+.Nm
+will all complete in
+O lg base N where base is the average fill factor.
+Often, inserting ordered data into
+.Nm Ns s
+results in a low fill factor.
+This implementation has been modified to make ordered insertion the best
+case, resulting in a much better than normal page fill factor.
+.Sh ERRORS
+The
+.Nm
+access method routines may fail and set
+.Va errno
+for any of the errors specified for the library routine
+.Xr dbopen 3 .
+.Sh SEE ALSO
+.Xr dbopen 3 ,
+.Xr hash 3 ,
+.Xr mpool 3 ,
+.Xr recno 3
+.Rs
+.%T "The Ubiquitous B-tree"
+.%A Douglas Comer
+.%J "ACM Comput. Surv. 11"
+.%N 2
+.%D June 1979
+.%P 121-138
+.Re
+.Rs
+.%A Bayer
+.%A Unterauer
+.%T "Prefix B-trees"
+.%J "ACM Transactions on Database Systems"
+.%N 1
+.%V Vol. 2
+.%D March 1977
+.%P 11-26
+.Re
+.Rs
+.%B "The Art of Computer Programming Vol. 3: Sorting and Searching"
+.%A D. E. Knuth
+.%D 1968
+.%P 471-480
+.Re
+.Sh BUGS
+Only big and little endian byte order is supported.
diff --git a/lib/libc/db/man/dbm.3 b/lib/libc/db/man/dbm.3
new file mode 100644
index 000000000000..4fe5d82d6902
--- /dev/null
+++ b/lib/libc/db/man/dbm.3
@@ -0,0 +1,226 @@
+.\" Copyright (c) 1999 Tim Singletary
+.\" No copyright is claimed.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 May 30, 2016
+.Dt DBM 3
+.Os
+.Sh NAME
+.Nm dbm_clearerr ,
+.Nm dbm_close ,
+.Nm dbm_delete ,
+.Nm dbm_dirfno ,
+.Nm dbm_error ,
+.Nm dbm_fetch ,
+.Nm dbm_firstkey ,
+.Nm dbm_nextkey ,
+.Nm dbm_open ,
+.Nm dbm_store
+.Nd database access functions
+.Sh SYNOPSIS
+.In fcntl.h
+.In ndbm.h
+.Ft DBM *
+.Fn dbm_open "const char *base" "int flags" "mode_t mode"
+.Ft void
+.Fn dbm_close "DBM *db"
+.Ft int
+.Fn dbm_store "DBM *db" "datum key" "datum data" "int flags"
+.Ft datum
+.Fn dbm_fetch "DBM *db" "datum key"
+.Ft int
+.Fn dbm_delete "DBM *db" "datum key"
+.Ft datum
+.Fn dbm_firstkey "DBM *db"
+.Ft datum
+.Fn dbm_nextkey "DBM *db"
+.Ft int
+.Fn dbm_error "DBM *db"
+.Ft int
+.Fn dbm_clearerr "DBM *db"
+.Ft int
+.Fn dbm_dirfno "DBM *db"
+.Sh DESCRIPTION
+Database access functions.
+These functions are implemented using
+.Xr dbopen 3
+with a
+.Xr hash 3
+database.
+.Pp
+.Vt datum
+is declared in
+.In ndbm.h :
+.Bd -literal
+typedef struct {
+ void *dptr;
+ int dsize;
+} datum;
+.Ed
+.Pp
+The
+.Fn dbm_open base flags mode
+function
+opens or creates a database.
+The
+.Fa base
+argument
+is the basename of the file containing
+the database; the actual database has a
+.Pa .db
+suffix.
+I.e., if
+.Fa base
+is
+.Qq Li /home/me/mystuff
+then the actual database is in the file
+.Pa /home/me/mystuff.db .
+The
+.Fa flags
+and
+.Fa mode
+arguments
+are passed to
+.Xr open 2 .
+.Pq Dv O_RDWR | O_CREAT
+is a typical value for
+.Fa flags ;
+.Li 0660
+is a typical value for
+.Fa mode .
+.Dv O_WRONLY
+is not allowed in
+.Fa flags .
+The pointer returned by
+.Fn dbm_open
+identifies the database and is the
+.Fa db
+argument to the other functions.
+The
+.Fn dbm_open
+function
+returns
+.Dv NULL
+and sets
+.Va errno
+if there were any errors.
+.Pp
+The
+.Fn dbm_close db
+function
+closes the database.
+.Pp
+The
+.Fn dbm_store db key data flags
+function
+inserts or replaces an entry in the database.
+The
+.Fa flags
+argument
+is either
+.Dv DBM_INSERT
+or
+.Dv DBM_REPLACE .
+If
+.Fa flags
+is
+.Dv DBM_INSERT
+and the database already contains an entry for
+.Fa key ,
+that entry is not replaced.
+Otherwise the entry is replaced or inserted.
+The
+.Fn dbm_store
+function
+normally returns zero but returns 1 if the entry could not be
+inserted (because
+.Fa flags
+is
+.Dv DBM_INSERT ,
+and an entry with
+.Fa key
+already exists) or returns -1 and sets
+.Va errno
+if there were any errors.
+.Pp
+The
+.Fn dbm_fetch db key
+function
+returns
+.Dv NULL
+or the
+.Fa data
+corresponding to
+.Fa key .
+.Pp
+The
+.Fn dbm_delete db key
+function
+deletes the entry for
+.Fa key .
+The
+.Fn dbm_delete
+function
+normally returns zero or returns -1 and sets
+.Va errno
+if there were any errors.
+.Pp
+The
+.Fn dbm_firstkey db
+function
+returns the first key in the database.
+The
+.Fn dbm_nextkey db
+function
+returns subsequent keys.
+The
+.Fn db_firstkey
+function
+must be called before
+.Fn dbm_nextkey .
+The order in which keys are returned is unspecified and may appear
+random.
+The
+.Fn dbm_nextkey
+function
+returns
+.Dv NULL
+after all keys have been returned.
+.Pp
+The
+.Fn dbm_error db
+function
+returns the
+.Va errno
+value of the most recent error.
+The
+.Fn dbm_clearerr db
+function
+resets this value to 0 and returns 0.
+.Pp
+The
+.Fn dbm_dirfno db
+function
+returns the file descriptor to the database.
+.Sh SEE ALSO
+.Xr open 2 ,
+.Xr dbopen 3 ,
+.Xr hash 3
+.Sh STANDARDS
+These functions (except
+.Fn dbm_dirfno )
+are included in the
+.St -susv2 .
diff --git a/lib/libc/db/man/dbopen.3 b/lib/libc/db/man/dbopen.3
new file mode 100644
index 000000000000..13481dd7eccc
--- /dev/null
+++ b/lib/libc/db/man/dbopen.3
@@ -0,0 +1,546 @@
+.\" Copyright (c) 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)dbopen.3 8.5 (Berkeley) 1/2/94
+.\" $FreeBSD$
+.\"
+.Dd September 10, 2010
+.Dt DBOPEN 3
+.Os
+.Sh NAME
+.Nm dbopen
+.Nd "database access methods"
+.Sh SYNOPSIS
+.In sys/types.h
+.In db.h
+.In fcntl.h
+.In limits.h
+.Ft DB *
+.Fn dbopen "const char *file" "int flags" "int mode" "DBTYPE type" "const void *openinfo"
+.Sh DESCRIPTION
+The
+.Fn dbopen
+function
+is the library interface to database files.
+The supported file formats are btree, hashed and UNIX file oriented.
+The btree format is a representation of a sorted, balanced tree structure.
+The hashed format is an extensible, dynamic hashing scheme.
+The flat-file format is a byte stream file with fixed or variable length
+records.
+The formats and file format specific information are described in detail
+in their respective manual pages
+.Xr btree 3 ,
+.Xr hash 3
+and
+.Xr recno 3 .
+.Pp
+The
+.Fn dbopen
+function
+opens
+.Fa file
+for reading and/or writing.
+Files never intended to be preserved on disk may be created by setting
+the
+.Fa file
+argument to
+.Dv NULL .
+.Pp
+The
+.Fa flags
+and
+.Fa mode
+arguments
+are as specified to the
+.Xr open 2
+routine, however, only the
+.Dv O_CREAT , O_EXCL , O_EXLOCK , O_NOFOLLOW , O_NONBLOCK ,
+.Dv O_RDONLY , O_RDWR , O_SHLOCK , O_SYNC
+and
+.Dv O_TRUNC
+flags are meaningful.
+(Note, opening a database file
+.Dv O_WRONLY
+is not possible.)
+.\"Three additional options may be specified by
+.\".Em or Ns 'ing
+.\"them into the
+.\".Fa flags
+.\"argument.
+.\".Bl -tag -width indent
+.\".It Dv DB_LOCK
+.\"Do the necessary locking in the database to support concurrent access.
+.\"If concurrent access is not needed or the database is read-only this
+.\"flag should not be set, as it tends to have an associated performance
+.\"penalty.
+.\".It Dv DB_SHMEM
+.\"Place the underlying memory pool used by the database in shared
+.\"memory.
+.\"Necessary for concurrent access.
+.\".It Dv DB_TXN
+.\"Support transactions in the database.
+.\"The
+.\".Dv DB_LOCK
+.\"and
+.\".Dv DB_SHMEM
+.\"flags must be set as well.
+.\".El
+.Pp
+The
+.Fa type
+argument is of type
+.Ft DBTYPE
+(as defined in the
+.In db.h
+include file) and
+may be set to
+.Dv DB_BTREE , DB_HASH
+or
+.Dv DB_RECNO .
+.Pp
+The
+.Fa openinfo
+argument is a pointer to an access method specific structure described
+in the access method's manual page.
+If
+.Fa openinfo
+is
+.Dv NULL ,
+each access method will use defaults appropriate for the system
+and the access method.
+.Pp
+The
+.Fn dbopen
+function
+returns a pointer to a
+.Ft DB
+structure on success and
+.Dv NULL
+on error.
+The
+.Ft DB
+structure is defined in the
+.In db.h
+include file, and contains at
+least the following fields:
+.Bd -literal
+typedef struct {
+ DBTYPE type;
+ int (*close)(DB *db);
+ int (*del)(const DB *db, const DBT *key, u_int flags);
+ int (*fd)(const DB *db);
+ int (*get)(const DB *db, const DBT *key, DBT *data, u_int flags);
+ int (*put)(const DB *db, DBT *key, const DBT *data,
+ u_int flags);
+ int (*sync)(const DB *db, u_int flags);
+ int (*seq)(const DB *db, DBT *key, DBT *data, u_int flags);
+} DB;
+.Ed
+.Pp
+These elements describe a database type and a set of functions performing
+various actions.
+These functions take a pointer to a structure as returned by
+.Fn dbopen ,
+and sometimes one or more pointers to key/data structures and a flag value.
+.Bl -tag -width indent
+.It Va type
+The type of the underlying access method (and file format).
+.It Va close
+A pointer to a routine to flush any cached information to disk, free any
+allocated resources, and close the underlying file(s).
+Since key/data pairs may be cached in memory, failing to sync the file
+with a
+.Va close
+or
+.Va sync
+function may result in inconsistent or lost information.
+.Va close
+routines return -1 on error (setting
+.Va errno )
+and 0 on success.
+.It Va del
+A pointer to a routine to remove key/data pairs from the database.
+.Pp
+The
+.Fa flags
+argument
+may be set to the following value:
+.Bl -tag -width indent
+.It Dv R_CURSOR
+Delete the record referenced by the cursor.
+The cursor must have previously been initialized.
+.El
+.Pp
+.Va delete
+routines return -1 on error (setting
+.Va errno ) ,
+0 on success, and 1 if the specified
+.Fa key
+was not in the file.
+.It Va fd
+A pointer to a routine which returns a file descriptor representative
+of the underlying database.
+A file descriptor referencing the same file will be returned to all
+processes which call
+.Fn dbopen
+with the same
+.Fa file
+name.
+This file descriptor may be safely used as an argument to the
+.Xr fcntl 2
+and
+.Xr flock 2
+locking functions.
+The file descriptor is not necessarily associated with any of the
+underlying files used by the access method.
+No file descriptor is available for in memory databases.
+.Va \&Fd
+routines return -1 on error (setting
+.Va errno ) ,
+and the file descriptor on success.
+.It Va get
+A pointer to a routine which is the interface for keyed retrieval from
+the database.
+The address and length of the data associated with the specified
+.Fa key
+are returned in the structure referenced by
+.Fa data .
+.Va get
+routines return -1 on error (setting
+.Va errno ) ,
+0 on success, and 1 if the
+.Fa key
+was not in the file.
+.It Va put
+A pointer to a routine to store key/data pairs in the database.
+.Pp
+The
+.Fa flags
+argument
+may be set to one of the following values:
+.Bl -tag -width indent
+.It Dv R_CURSOR
+Replace the key/data pair referenced by the cursor.
+The cursor must have previously been initialized.
+.It Dv R_IAFTER
+Append the data immediately after the data referenced by
+.Fa key ,
+creating a new key/data pair.
+The record number of the appended key/data pair is returned in the
+.Fa key
+structure.
+(Applicable only to the
+.Dv DB_RECNO
+access method.)
+.It Dv R_IBEFORE
+Insert the data immediately before the data referenced by
+.Fa key ,
+creating a new key/data pair.
+The record number of the inserted key/data pair is returned in the
+.Fa key
+structure.
+(Applicable only to the
+.Dv DB_RECNO
+access method.)
+.It Dv R_NOOVERWRITE
+Enter the new key/data pair only if the key does not previously exist.
+.It Dv R_SETCURSOR
+Store the key/data pair, setting or initializing the position of the
+cursor to reference it.
+(Applicable only to the
+.Dv DB_BTREE
+and
+.Dv DB_RECNO
+access methods.)
+.El
+.Pp
+.Dv R_SETCURSOR
+is available only for the
+.Dv DB_BTREE
+and
+.Dv DB_RECNO
+access
+methods because it implies that the keys have an inherent order
+which does not change.
+.Pp
+.Dv R_IAFTER
+and
+.Dv R_IBEFORE
+are available only for the
+.Dv DB_RECNO
+access method because they each imply that the access method is able to
+create new keys.
+This is only true if the keys are ordered and independent, record numbers
+for example.
+.Pp
+The default behavior of the
+.Va put
+routines is to enter the new key/data pair, replacing any previously
+existing key.
+.Pp
+.Va put
+routines return -1 on error (setting
+.Va errno ) ,
+0 on success, and 1 if the
+.Dv R_NOOVERWRITE
+flag
+was set and the key already exists in the file.
+.It Va seq
+A pointer to a routine which is the interface for sequential
+retrieval from the database.
+The address and length of the key are returned in the structure
+referenced by
+.Fa key ,
+and the address and length of the data are returned in the
+structure referenced
+by
+.Fa data .
+.Pp
+Sequential key/data pair retrieval may begin at any time, and the
+position of the
+.Dq cursor
+is not affected by calls to the
+.Va del ,
+.Va get ,
+.Va put ,
+or
+.Va sync
+routines.
+Modifications to the database during a sequential scan will be reflected
+in the scan, i.e., records inserted behind the cursor will not be returned
+while records inserted in front of the cursor will be returned.
+.Pp
+The
+.Fa flags
+argument
+.Em must
+be set to one of the following values:
+.Bl -tag -width indent
+.It Dv R_CURSOR
+The data associated with the specified key is returned.
+This differs from the
+.Va get
+routines in that it sets or initializes the cursor to the location of
+the key as well.
+(Note, for the
+.Dv DB_BTREE
+access method, the returned key is not necessarily an
+exact match for the specified key.
+The returned key is the smallest key greater than or equal to the specified
+key, permitting partial key matches and range searches.)
+.It Dv R_FIRST
+The first key/data pair of the database is returned, and the cursor
+is set or initialized to reference it.
+.It Dv R_LAST
+The last key/data pair of the database is returned, and the cursor
+is set or initialized to reference it.
+(Applicable only to the
+.Dv DB_BTREE
+and
+.Dv DB_RECNO
+access methods.)
+.It Dv R_NEXT
+Retrieve the key/data pair immediately after the cursor.
+If the cursor is not yet set, this is the same as the
+.Dv R_FIRST
+flag.
+.It Dv R_PREV
+Retrieve the key/data pair immediately before the cursor.
+If the cursor is not yet set, this is the same as the
+.Dv R_LAST
+flag.
+(Applicable only to the
+.Dv DB_BTREE
+and
+.Dv DB_RECNO
+access methods.)
+.El
+.Pp
+.Dv R_LAST
+and
+.Dv R_PREV
+are available only for the
+.Dv DB_BTREE
+and
+.Dv DB_RECNO
+access methods because they each imply that the keys have an inherent
+order which does not change.
+.Pp
+.Va seq
+routines return -1 on error (setting
+.Va errno ) ,
+0 on success and 1 if there are no key/data pairs less than or greater
+than the specified or current key.
+If the
+.Dv DB_RECNO
+access method is being used, and if the database file
+is a character special file and no complete key/data pairs are currently
+available, the
+.Va seq
+routines return 2.
+.It Va sync
+A pointer to a routine to flush any cached information to disk.
+If the database is in memory only, the
+.Va sync
+routine has no effect and will always succeed.
+.Pp
+The
+.Fa flags
+argument may be set to the following value:
+.Bl -tag -width indent
+.It Dv R_RECNOSYNC
+If the
+.Dv DB_RECNO
+access method is being used, this flag causes
+the
+.Va sync
+routine to apply to the btree file which underlies the
+recno file, not the recno file itself.
+(See the
+.Va bfname
+field of the
+.Xr recno 3
+manual page for more information.)
+.El
+.Pp
+.Va sync
+routines return -1 on error (setting
+.Va errno )
+and 0 on success.
+.El
+.Sh "KEY/DATA PAIRS"
+Access to all file types is based on key/data pairs.
+Both keys and data are represented by the following data structure:
+.Bd -literal
+typedef struct {
+ void *data;
+ size_t size;
+} DBT;
+.Ed
+.Pp
+The elements of the
+.Ft DBT
+structure are defined as follows:
+.Bl -tag -width "data"
+.It Va data
+A pointer to a byte string.
+.It Va size
+The length of the byte string.
+.El
+.Pp
+Key and data byte strings may reference strings of essentially unlimited
+length although any two of them must fit into available memory at the same
+time.
+It should be noted that the access methods provide no guarantees about
+byte string alignment.
+.Sh ERRORS
+The
+.Fn dbopen
+routine may fail and set
+.Va errno
+for any of the errors specified for the library routines
+.Xr open 2
+and
+.Xr malloc 3
+or the following:
+.Bl -tag -width Er
+.It Bq Er EFTYPE
+A file is incorrectly formatted.
+.It Bq Er EINVAL
+An argument has been specified (hash function, pad byte etc.) that is
+incompatible with the current file specification or which is not
+meaningful for the function (for example, use of the cursor without
+prior initialization) or there is a mismatch between the version
+number of file and the software.
+.El
+.Pp
+The
+.Va close
+routines may fail and set
+.Va errno
+for any of the errors specified for the library routines
+.Xr close 2 ,
+.Xr read 2 ,
+.Xr write 2 ,
+.Xr free 3 ,
+or
+.Xr fsync 2 .
+.Pp
+The
+.Va del ,
+.Va get ,
+.Va put
+and
+.Va seq
+routines may fail and set
+.Va errno
+for any of the errors specified for the library routines
+.Xr read 2 ,
+.Xr write 2 ,
+.Xr free 3
+or
+.Xr malloc 3 .
+.Pp
+The
+.Va fd
+routines will fail and set
+.Va errno
+to
+.Er ENOENT
+for in memory databases.
+.Pp
+The
+.Va sync
+routines may fail and set
+.Va errno
+for any of the errors specified for the library routine
+.Xr fsync 2 .
+.Sh SEE ALSO
+.Xr btree 3 ,
+.Xr hash 3 ,
+.Xr mpool 3 ,
+.Xr recno 3
+.Rs
+.%T "LIBTP: Portable, Modular Transactions for UNIX"
+.%A Margo Seltzer
+.%A Michael Olson
+.%R "USENIX proceedings"
+.%D Winter 1992
+.Re
+.Sh BUGS
+The typedef
+.Ft DBT
+is a mnemonic for
+.Dq "data base thang" ,
+and was used
+because noone could think of a reasonable name that was not already used.
+.Pp
+The file descriptor interface is a kluge and will be deleted in a
+future version of the interface.
+.Pp
+None of the access methods provide any form of concurrent access,
+locking, or transactions.
diff --git a/lib/libc/db/man/hash.3 b/lib/libc/db/man/hash.3
new file mode 100644
index 000000000000..a2a8bca65c14
--- /dev/null
+++ b/lib/libc/db/man/hash.3
@@ -0,0 +1,196 @@
+.\" Copyright (c) 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)hash.3 8.6 (Berkeley) 8/18/94
+.\" $FreeBSD$
+.\"
+.Dd August 18, 1994
+.Dt HASH 3
+.Os
+.Sh NAME
+.Nm hash
+.Nd "hash database access method"
+.Sh SYNOPSIS
+.In sys/types.h
+.In db.h
+.Sh DESCRIPTION
+The routine
+.Fn dbopen
+is the library interface to database files.
+One of the supported file formats is
+.Nm
+files.
+The general description of the database access methods is in
+.Xr dbopen 3 ,
+this manual page describes only the
+.Nm
+specific information.
+.Pp
+The
+.Nm
+data structure is an extensible, dynamic hashing scheme.
+.Pp
+The access method specific data structure provided to
+.Fn dbopen
+is defined in the
+.In db.h
+include file as follows:
+.Bd -literal
+typedef struct {
+ u_int bsize;
+ u_int ffactor;
+ u_int nelem;
+ u_int cachesize;
+ uint32_t (*hash)(const void *, size_t);
+ int lorder;
+} HASHINFO;
+.Ed
+.Pp
+The elements of this structure are as follows:
+.Bl -tag -width indent
+.It Va bsize
+The
+.Va bsize
+element
+defines the
+.Nm
+table bucket size, and is, by default, 4096 bytes.
+It may be preferable to increase the page size for disk-resident tables
+and tables with large data items.
+.It Va ffactor
+The
+.Va ffactor
+element
+indicates a desired density within the
+.Nm
+table.
+It is an approximation of the number of keys allowed to accumulate in any
+one bucket, determining when the
+.Nm
+table grows or shrinks.
+The default value is 8.
+.It Va nelem
+The
+.Va nelem
+element
+is an estimate of the final size of the
+.Nm
+table.
+If not set or set too low,
+.Nm
+tables will expand gracefully as keys
+are entered, although a slight performance degradation may be noticed.
+The default value is 1.
+.It Va cachesize
+A suggested maximum size, in bytes, of the memory cache.
+This value is
+.Em only
+advisory, and the access method will allocate more memory rather
+than fail.
+.It Va hash
+The
+.Va hash
+element
+is a user defined
+.Nm
+function.
+Since no
+.Nm
+function performs equally well on all possible data, the
+user may find that the built-in
+.Nm
+function does poorly on a particular
+data set.
+User specified
+.Nm
+functions must take two arguments (a pointer to a byte
+string and a length) and return a 32-bit quantity to be used as the
+.Nm
+value.
+.It Va lorder
+The byte order for integers in the stored database metadata.
+The number should represent the order as an integer; for example,
+big endian order would be the number 4,321.
+If
+.Va lorder
+is 0 (no order is specified) the current host order is used.
+If the file already exists, the specified value is ignored and the
+value specified when the tree was created is used.
+.El
+.Pp
+If the file already exists (and the
+.Dv O_TRUNC
+flag is not specified), the
+values specified for the
+.Va bsize , ffactor , lorder
+and
+.Va nelem
+arguments
+are
+ignored and the values specified when the tree was created are used.
+.Pp
+If a
+.Nm
+function is specified,
+.Fn hash_open
+will attempt to determine if the
+.Nm
+function specified is the same as
+the one with which the database was created, and will fail if it is not.
+.Pp
+Backward compatible interfaces to the older
+.Em dbm
+and
+.Em ndbm
+routines are provided, however these interfaces are not compatible with
+previous file formats.
+.Sh ERRORS
+The
+.Nm
+access method routines may fail and set
+.Va errno
+for any of the errors specified for the library routine
+.Xr dbopen 3 .
+.Sh SEE ALSO
+.Xr btree 3 ,
+.Xr dbopen 3 ,
+.Xr mpool 3 ,
+.Xr recno 3
+.Rs
+.%T "Dynamic Hash Tables"
+.%A Per-Ake Larson
+.%R "Communications of the ACM"
+.%D April 1988
+.Re
+.Rs
+.%T "A New Hash Package for UNIX"
+.%A Margo Seltzer
+.%R "USENIX Proceedings"
+.%D Winter 1991
+.Re
+.Sh BUGS
+Only big and little endian byte order is supported.
diff --git a/lib/libc/db/man/mpool.3 b/lib/libc/db/man/mpool.3
new file mode 100644
index 000000000000..5af7d2736fda
--- /dev/null
+++ b/lib/libc/db/man/mpool.3
@@ -0,0 +1,254 @@
+.\" Copyright (c) 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)mpool.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 17, 2011
+.Dt MPOOL 3
+.Os
+.Sh NAME
+.Nm mpool
+.Nd "shared memory buffer pool"
+.Sh SYNOPSIS
+.In db.h
+.In mpool.h
+.Ft MPOOL *
+.Fn mpool_open "void *key" "int fd" "pgno_t pagesize" "pgno_t maxcache"
+.Ft void
+.Fo mpool_filter
+.Fa "MPOOL *mp"
+.Fa "void (*pgin)(void *, pgno_t, void *)"
+.Fa "void (*pgout)(void *, pgno_t, void *)"
+.Fa "void *pgcookie"
+.Fc
+.Ft void *
+.Fn mpool_new "MPOOL *mp" "pgno_t *pgnoaddr" "u_int flags"
+.Ft int
+.Fn mpool_delete "MPOOL *mp" "void *page"
+.Ft void *
+.Fn mpool_get "MPOOL *mp" "pgno_t pgno" "u_int flags"
+.Ft int
+.Fn mpool_put "MPOOL *mp" "void *pgaddr" "u_int flags"
+.Ft int
+.Fn mpool_sync "MPOOL *mp"
+.Ft int
+.Fn mpool_close "MPOOL *mp"
+.Sh DESCRIPTION
+The
+.Nm mpool
+library interface is intended to provide page oriented buffer management
+of files.
+.Pp
+The
+.Fn mpool_open
+function initializes a memory pool.
+The
+.Fa key
+argument is currently ignored.
+The
+.Fa fd
+argument is a file descriptor for the underlying file, which must be seekable.
+.Pp
+The
+.Fa pagesize
+argument is the size, in bytes, of the pages into which the file is broken up.
+The
+.Fa maxcache
+argument is the maximum number of pages from the underlying file to cache
+at any one time.
+This value is not relative to the number of processes which share a file's
+buffers, but will be the largest value specified by any of the processes
+sharing the file.
+.Pp
+The
+.Fn mpool_filter
+function is intended to make transparent input and output processing of the
+pages possible.
+If the
+.Fa pgin
+function is specified, it is called each time a buffer is read into the memory
+pool from the backing file.
+If the
+.Fa pgout
+function is specified, it is called each time a buffer is written into the
+backing file.
+Both functions are called with the
+.Fa pgcookie
+pointer, the page number and a pointer to the page to being read or written.
+.Pp
+The function
+.Fn mpool_new
+takes an
+.Dv MPOOL
+pointer, an address, and a set of flags as arguments.
+If a new page can be allocated, a pointer to the page is returned and
+the page number is stored into the
+.Fa pgnoaddr
+address.
+Otherwise,
+.Dv NULL
+is returned and
+.Va errno
+is set.
+The flags value is formed by
+.Tn OR Ns 'ing
+the following values:
+.Bl -tag -width Ds
+.It Dv MPOOL_PAGE_REQUEST
+Allocate a new page with a specific page number.
+.It Dv MPOOL_PAGE_NEXT
+Allocate a new page with the next page number.
+.El
+.Pp
+The function
+.Fn mpool_delete
+deletes the specified page from a pool and frees the page.
+It takes an
+.Dv MPOOL
+pointer and a page as arguments.
+The page must have been generated by
+.Fn mpool_new .
+.Pp
+The
+.Fn mpool_get
+function takes a
+.Ft MPOOL
+pointer and a page number as arguments.
+If the page exists, a pointer to the page is returned.
+Otherwise,
+.Dv NULL
+is returned and
+.Va errno
+is set.
+The
+.Fa flags
+argument is specified by
+.Em or Ns 'ing
+any of the following values:
+.Bl -tag -width indent
+.It Dv MPOOL_IGNOREPIN
+The page returned is not pinned;
+page will otherwise be pinned on return.
+.El
+.Pp
+The
+.Fn mpool_put
+function unpins the page referenced by
+.Fa pgaddr .
+The
+.Fa pgaddr
+argument
+must be an address previously returned by
+.Fn mpool_get
+or
+.Fn mpool_new .
+The
+.Fa flags
+argument is specified by
+.Em or Ns 'ing
+any of the following values:
+.Bl -tag -width indent
+.It Dv MPOOL_DIRTY
+The page has been modified and needs to be written to the backing file.
+.El
+.Pp
+The
+.Fn mpool_put
+function
+returns 0 on success and -1 if an error occurs.
+.Pp
+The
+.Fn mpool_sync
+function writes all modified pages associated with the
+.Ft MPOOL
+pointer to the
+backing file.
+The
+.Fn mpool_sync
+function
+returns 0 on success and -1 if an error occurs.
+.Pp
+The
+.Fn mpool_close
+function free's up any allocated memory associated with the memory pool
+cookie.
+Modified pages are
+.Em not
+written to the backing file.
+The
+.Fn mpool_close
+function
+returns 0 on success and -1 if an error occurs.
+.Sh ERRORS
+The
+.Fn mpool_open
+function may fail and set
+.Va errno
+for any of the errors specified for the library routine
+.Xr malloc 3 .
+.Pp
+The
+.Fn mpool_get
+function may fail and set
+.Va errno
+for the following:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The requested record does not exist.
+.El
+.Pp
+The
+.Fn mpool_new
+and
+.Fn mpool_get
+functions may fail and set
+.Va errno
+for any of the errors specified for the library routines
+.Xr read 2 ,
+.Xr write 2 ,
+and
+.Xr malloc 3 .
+.Pp
+The
+.Fn mpool_sync
+function may fail and set
+.Va errno
+for any of the errors specified for the library routine
+.Xr write 2 .
+.Pp
+The
+.Fn mpool_close
+function may fail and set
+.Va errno
+for any of the errors specified for the library routine
+.Xr free 3 .
+.Sh SEE ALSO
+.Xr btree 3 ,
+.Xr dbopen 3 ,
+.Xr hash 3 ,
+.Xr recno 3
diff --git a/lib/libc/db/man/recno.3 b/lib/libc/db/man/recno.3
new file mode 100644
index 000000000000..22d5567a7a9b
--- /dev/null
+++ b/lib/libc/db/man/recno.3
@@ -0,0 +1,228 @@
+.\" Copyright (c) 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)recno.3 8.5 (Berkeley) 8/18/94
+.\" $FreeBSD$
+.\"
+.Dd August 18, 1994
+.Dt RECNO 3
+.Os
+.Sh NAME
+.Nm recno
+.Nd "record number database access method"
+.Sh SYNOPSIS
+.In sys/types.h
+.In db.h
+.Sh DESCRIPTION
+The routine
+.Fn dbopen
+is the library interface to database files.
+One of the supported file formats is record number files.
+The general description of the database access methods is in
+.Xr dbopen 3 ,
+this manual page describes only the
+.Nm
+specific information.
+.Pp
+The record number data structure is either variable or fixed-length
+records stored in a flat-file format, accessed by the logical record
+number.
+The existence of record number five implies the existence of records
+one through four, and the deletion of record number one causes
+record number five to be renumbered to record number four, as well
+as the cursor, if positioned after record number one, to shift down
+one record.
+.Pp
+The
+.Nm
+access method specific data structure provided to
+.Fn dbopen
+is defined in the
+.In db.h
+include file as follows:
+.Bd -literal
+typedef struct {
+ u_long flags;
+ u_int cachesize;
+ u_int psize;
+ int lorder;
+ size_t reclen;
+ u_char bval;
+ char *bfname;
+} RECNOINFO;
+.Ed
+.Pp
+The elements of this structure are defined as follows:
+.Bl -tag -width indent
+.It Va flags
+The flag value is specified by
+.Em or Ns 'ing
+any of the following values:
+.Bl -tag -width indent
+.It Dv R_FIXEDLEN
+The records are fixed-length, not byte delimited.
+The structure element
+.Va reclen
+specifies the length of the record, and the structure element
+.Va bval
+is used as the pad character.
+Any records, inserted into the database, that are less than
+.Va reclen
+bytes long are automatically padded.
+.It Dv R_NOKEY
+In the interface specified by
+.Fn dbopen ,
+the sequential record retrieval fills in both the caller's key and
+data structures.
+If the
+.Dv R_NOKEY
+flag is specified, the
+.Em cursor
+routines are not required to fill in the key structure.
+This permits applications to retrieve records at the end of files without
+reading all of the intervening records.
+.It Dv R_SNAPSHOT
+This flag requires that a snapshot of the file be taken when
+.Fn dbopen
+is called, instead of permitting any unmodified records to be read from
+the original file.
+.El
+.It Va cachesize
+A suggested maximum size, in bytes, of the memory cache.
+This value is
+.Em only
+advisory, and the access method will allocate more memory rather than fail.
+If
+.Va cachesize
+is 0 (no size is specified) a default cache is used.
+.It Va psize
+The
+.Nm
+access method stores the in-memory copies of its records
+in a btree.
+This value is the size (in bytes) of the pages used for nodes in that tree.
+If
+.Va psize
+is 0 (no page size is specified) a page size is chosen based on the
+underlying file system I/O block size.
+See
+.Xr btree 3
+for more information.
+.It Va lorder
+The byte order for integers in the stored database metadata.
+The number should represent the order as an integer; for example,
+big endian order would be the number 4,321.
+If
+.Va lorder
+is 0 (no order is specified) the current host order is used.
+.It Va reclen
+The length of a fixed-length record.
+.It Va bval
+The delimiting byte to be used to mark the end of a record for
+variable-length records, and the pad character for fixed-length
+records.
+If no value is specified, newlines
+.Pq Dq \en
+are used to mark the end
+of variable-length records and fixed-length records are padded with
+spaces.
+.It Va bfname
+The
+.Nm
+access method stores the in-memory copies of its records
+in a btree.
+If
+.Va bfname
+is
+.No non\- Ns Dv NULL ,
+it specifies the name of the btree file,
+as if specified as the file name for a
+.Fn dbopen
+of a btree file.
+.El
+.Pp
+The data part of the key/data pair used by the
+.Nm
+access method
+is the same as other access methods.
+The key is different.
+The
+.Va data
+field of the key should be a pointer to a memory location of type
+.Ft recno_t ,
+as defined in the
+.In db.h
+include file.
+This type is normally the largest unsigned integral type available to
+the implementation.
+The
+.Va size
+field of the key should be the size of that type.
+.Pp
+Because there can be no meta-data associated with the underlying
+.Nm
+access method files, any changes made to the default values
+(e.g.\& fixed record length or byte separator value) must be explicitly
+specified each time the file is opened.
+.Pp
+In the interface specified by
+.Fn dbopen ,
+using the
+.Va put
+interface to create a new record will cause the creation of multiple,
+empty records if the record number is more than one greater than the
+largest record currently in the database.
+.Sh ERRORS
+The
+.Nm
+access method routines may fail and set
+.Va errno
+for any of the errors specified for the library routine
+.Xr dbopen 3
+or the following:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+An attempt was made to add a record to a fixed-length database that
+was too large to fit.
+.El
+.Sh SEE ALSO
+.Xr btree 3 ,
+.Xr dbopen 3 ,
+.Xr hash 3 ,
+.Xr mpool 3
+.Rs
+.%T "Document Processing in a Relational Database System"
+.%A Michael Stonebraker
+.%A Heidi Stettner
+.%A Joseph Kalash
+.%A Antonin Guttman
+.%A Nadene Lynn
+.%R "Memorandum No. UCB/ERL M82/32"
+.%D May 1982
+.Re
+.Sh BUGS
+Only big and little endian byte order is supported.
diff --git a/lib/libc/db/mpool/Makefile.inc b/lib/libc/db/mpool/Makefile.inc
new file mode 100644
index 000000000000..76ec0ebe5cd2
--- /dev/null
+++ b/lib/libc/db/mpool/Makefile.inc
@@ -0,0 +1,9 @@
+# from @(#)Makefile.inc 8.1 (Berkeley) 6/4/93
+# $FreeBSD$
+
+.PATH: ${LIBC_SRCTOP}/db/mpool
+
+SRCS+= mpool.c
+.if ${MK_SYMVER} == yes
+SRCS+= mpool-compat.c
+.endif
diff --git a/lib/libc/db/mpool/README b/lib/libc/db/mpool/README
new file mode 100644
index 000000000000..0f01fbcdb449
--- /dev/null
+++ b/lib/libc/db/mpool/README
@@ -0,0 +1,7 @@
+# @(#)README 8.1 (Berkeley) 6/4/93
+
+These are the current memory pool routines.
+They aren't ready for prime time, yet, and
+the interface is expected to change.
+
+--keith
diff --git a/lib/libc/db/mpool/mpool-compat.c b/lib/libc/db/mpool/mpool-compat.c
new file mode 100644
index 000000000000..9df76ff0b5d2
--- /dev/null
+++ b/lib/libc/db/mpool/mpool-compat.c
@@ -0,0 +1,43 @@
+/*-
+ * Copyright (c) 2009 Xin LI <delphij@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 <db.h>
+#include <mpool.h>
+
+void *__mpool_new__44bsd(MPOOL *, pgno_t *);
+
+void *
+__mpool_new__44bsd(MPOOL *mp, pgno_t *pgnoaddr)
+{
+
+ return (mpool_new(mp, pgnoaddr, MPOOL_PAGE_NEXT));
+}
+
+__sym_compat(mpool_new, __mpool_new_44bsd, FBSD_1.0);
diff --git a/lib/libc/db/mpool/mpool.c b/lib/libc/db/mpool/mpool.c
new file mode 100644
index 000000000000..c3a19e06a636
--- /dev/null
+++ b/lib/libc/db/mpool/mpool.c
@@ -0,0 +1,493 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)mpool.c 8.7 (Berkeley) 11/2/95";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+#include <db.h>
+
+#define __MPOOLINTERFACE_PRIVATE
+#include <mpool.h>
+
+static BKT *mpool_bkt(MPOOL *);
+static BKT *mpool_look(MPOOL *, pgno_t);
+static int mpool_write(MPOOL *, BKT *);
+
+/*
+ * mpool_open --
+ * Initialize a memory pool.
+ */
+/* ARGSUSED */
+MPOOL *
+mpool_open(void *key, int fd, pgno_t pagesize, pgno_t maxcache)
+{
+ struct stat sb;
+ MPOOL *mp;
+ int entry;
+
+ /*
+ * Get information about the file.
+ *
+ * XXX
+ * We don't currently handle pipes, although we should.
+ */
+ if (_fstat(fd, &sb))
+ return (NULL);
+ if (!S_ISREG(sb.st_mode)) {
+ errno = ESPIPE;
+ return (NULL);
+ }
+
+ /* Allocate and initialize the MPOOL cookie. */
+ if ((mp = (MPOOL *)calloc(1, sizeof(MPOOL))) == NULL)
+ return (NULL);
+ TAILQ_INIT(&mp->lqh);
+ for (entry = 0; entry < HASHSIZE; ++entry)
+ TAILQ_INIT(&mp->hqh[entry]);
+ mp->maxcache = maxcache;
+ mp->npages = sb.st_size / pagesize;
+ mp->pagesize = pagesize;
+ mp->fd = fd;
+ return (mp);
+}
+
+/*
+ * mpool_filter --
+ * Initialize input/output filters.
+ */
+void
+mpool_filter(MPOOL *mp, void (*pgin) (void *, pgno_t, void *),
+ void (*pgout) (void *, pgno_t, void *), void *pgcookie)
+{
+ mp->pgin = pgin;
+ mp->pgout = pgout;
+ mp->pgcookie = pgcookie;
+}
+
+/*
+ * mpool_new --
+ * Get a new page of memory.
+ */
+void *
+mpool_new(MPOOL *mp, pgno_t *pgnoaddr, u_int flags)
+{
+ struct _hqh *head;
+ BKT *bp;
+
+ if (mp->npages == MAX_PAGE_NUMBER) {
+ (void)fprintf(stderr, "mpool_new: page allocation overflow.\n");
+ abort();
+ }
+#ifdef STATISTICS
+ ++mp->pagenew;
+#endif
+ /*
+ * Get a BKT from the cache. Assign a new page number, attach
+ * it to the head of the hash chain, the tail of the lru chain,
+ * and return.
+ */
+ if ((bp = mpool_bkt(mp)) == NULL)
+ return (NULL);
+ if (flags == MPOOL_PAGE_REQUEST) {
+ mp->npages++;
+ bp->pgno = *pgnoaddr;
+ } else
+ bp->pgno = *pgnoaddr = mp->npages++;
+
+ bp->flags = MPOOL_PINNED | MPOOL_INUSE;
+
+ head = &mp->hqh[HASHKEY(bp->pgno)];
+ TAILQ_INSERT_HEAD(head, bp, hq);
+ TAILQ_INSERT_TAIL(&mp->lqh, bp, q);
+ return (bp->page);
+}
+
+int
+mpool_delete(MPOOL *mp, void *page)
+{
+ struct _hqh *head;
+ BKT *bp;
+
+ bp = (BKT *)((char *)page - sizeof(BKT));
+
+#ifdef DEBUG
+ if (!(bp->flags & MPOOL_PINNED)) {
+ (void)fprintf(stderr,
+ "mpool_delete: page %d not pinned\n", bp->pgno);
+ abort();
+ }
+#endif
+
+ /* Remove from the hash and lru queues. */
+ head = &mp->hqh[HASHKEY(bp->pgno)];
+ TAILQ_REMOVE(head, bp, hq);
+ TAILQ_REMOVE(&mp->lqh, bp, q);
+
+ free(bp);
+ mp->curcache--;
+ return (RET_SUCCESS);
+}
+
+/*
+ * mpool_get
+ * Get a page.
+ */
+/* ARGSUSED */
+void *
+mpool_get(MPOOL *mp, pgno_t pgno,
+ u_int flags) /* XXX not used? */
+{
+ struct _hqh *head;
+ BKT *bp;
+ off_t off;
+ int nr;
+
+#ifdef STATISTICS
+ ++mp->pageget;
+#endif
+
+ /* Check for a page that is cached. */
+ if ((bp = mpool_look(mp, pgno)) != NULL) {
+#ifdef DEBUG
+ if (!(flags & MPOOL_IGNOREPIN) && bp->flags & MPOOL_PINNED) {
+ (void)fprintf(stderr,
+ "mpool_get: page %d already pinned\n", bp->pgno);
+ abort();
+ }
+#endif
+ /*
+ * Move the page to the head of the hash chain and the tail
+ * of the lru chain.
+ */
+ head = &mp->hqh[HASHKEY(bp->pgno)];
+ TAILQ_REMOVE(head, bp, hq);
+ TAILQ_INSERT_HEAD(head, bp, hq);
+ TAILQ_REMOVE(&mp->lqh, bp, q);
+ TAILQ_INSERT_TAIL(&mp->lqh, bp, q);
+
+ /* Return a pinned page. */
+ bp->flags |= MPOOL_PINNED;
+ return (bp->page);
+ }
+
+ /* Get a page from the cache. */
+ if ((bp = mpool_bkt(mp)) == NULL)
+ return (NULL);
+
+ /* Read in the contents. */
+ off = mp->pagesize * pgno;
+ if ((nr = pread(mp->fd, bp->page, mp->pagesize, off)) != (ssize_t)mp->pagesize) {
+ switch (nr) {
+ case -1:
+ /* errno is set for us by pread(). */
+ free(bp);
+ mp->curcache--;
+ return (NULL);
+ case 0:
+ /*
+ * A zero-length read means you need to create a
+ * new page.
+ */
+ memset(bp->page, 0, mp->pagesize);
+ break;
+ default:
+ /* A partial read is definitely bad. */
+ free(bp);
+ mp->curcache--;
+ errno = EINVAL;
+ return (NULL);
+ }
+ }
+#ifdef STATISTICS
+ ++mp->pageread;
+#endif
+
+ /* Set the page number, pin the page. */
+ bp->pgno = pgno;
+ if (!(flags & MPOOL_IGNOREPIN))
+ bp->flags = MPOOL_PINNED;
+ bp->flags |= MPOOL_INUSE;
+
+ /*
+ * Add the page to the head of the hash chain and the tail
+ * of the lru chain.
+ */
+ head = &mp->hqh[HASHKEY(bp->pgno)];
+ TAILQ_INSERT_HEAD(head, bp, hq);
+ TAILQ_INSERT_TAIL(&mp->lqh, bp, q);
+
+ /* Run through the user's filter. */
+ if (mp->pgin != NULL)
+ (mp->pgin)(mp->pgcookie, bp->pgno, bp->page);
+
+ return (bp->page);
+}
+
+/*
+ * mpool_put
+ * Return a page.
+ */
+/* ARGSUSED */
+int
+mpool_put(MPOOL *mp, void *page, u_int flags)
+{
+ BKT *bp;
+
+#ifdef STATISTICS
+ ++mp->pageput;
+#endif
+ bp = (BKT *)((char *)page - sizeof(BKT));
+#ifdef DEBUG
+ if (!(bp->flags & MPOOL_PINNED)) {
+ (void)fprintf(stderr,
+ "mpool_put: page %d not pinned\n", bp->pgno);
+ abort();
+ }
+#endif
+ bp->flags &= ~MPOOL_PINNED;
+ if (flags & MPOOL_DIRTY)
+ bp->flags |= flags & MPOOL_DIRTY;
+ return (RET_SUCCESS);
+}
+
+/*
+ * mpool_close
+ * Close the buffer pool.
+ */
+int
+mpool_close(MPOOL *mp)
+{
+ BKT *bp;
+
+ /* Free up any space allocated to the lru pages. */
+ while (!TAILQ_EMPTY(&mp->lqh)) {
+ bp = TAILQ_FIRST(&mp->lqh);
+ TAILQ_REMOVE(&mp->lqh, bp, q);
+ free(bp);
+ }
+
+ /* Free the MPOOL cookie. */
+ free(mp);
+ return (RET_SUCCESS);
+}
+
+/*
+ * mpool_sync
+ * Sync the pool to disk.
+ */
+int
+mpool_sync(MPOOL *mp)
+{
+ BKT *bp;
+
+ /* Walk the lru chain, flushing any dirty pages to disk. */
+ TAILQ_FOREACH(bp, &mp->lqh, q)
+ if (bp->flags & MPOOL_DIRTY &&
+ mpool_write(mp, bp) == RET_ERROR)
+ return (RET_ERROR);
+
+ /* Sync the file descriptor. */
+ return (_fsync(mp->fd) ? RET_ERROR : RET_SUCCESS);
+}
+
+/*
+ * mpool_bkt
+ * Get a page from the cache (or create one).
+ */
+static BKT *
+mpool_bkt(MPOOL *mp)
+{
+ struct _hqh *head;
+ BKT *bp;
+
+ /* If under the max cached, always create a new page. */
+ if (mp->curcache < mp->maxcache)
+ goto new;
+
+ /*
+ * If the cache is max'd out, walk the lru list for a buffer we
+ * can flush. If we find one, write it (if necessary) and take it
+ * off any lists. If we don't find anything we grow the cache anyway.
+ * The cache never shrinks.
+ */
+ TAILQ_FOREACH(bp, &mp->lqh, q)
+ if (!(bp->flags & MPOOL_PINNED)) {
+ /* Flush if dirty. */
+ if (bp->flags & MPOOL_DIRTY &&
+ mpool_write(mp, bp) == RET_ERROR)
+ return (NULL);
+#ifdef STATISTICS
+ ++mp->pageflush;
+#endif
+ /* Remove from the hash and lru queues. */
+ head = &mp->hqh[HASHKEY(bp->pgno)];
+ TAILQ_REMOVE(head, bp, hq);
+ TAILQ_REMOVE(&mp->lqh, bp, q);
+#ifdef DEBUG
+ { void *spage;
+ spage = bp->page;
+ memset(bp, 0xff, sizeof(BKT) + mp->pagesize);
+ bp->page = spage;
+ }
+#endif
+ bp->flags = 0;
+ return (bp);
+ }
+
+new: if ((bp = (BKT *)calloc(1, sizeof(BKT) + mp->pagesize)) == NULL)
+ return (NULL);
+#ifdef STATISTICS
+ ++mp->pagealloc;
+#endif
+ bp->page = (char *)bp + sizeof(BKT);
+ bp->flags = 0;
+ ++mp->curcache;
+ return (bp);
+}
+
+/*
+ * mpool_write
+ * Write a page to disk.
+ */
+static int
+mpool_write(MPOOL *mp, BKT *bp)
+{
+ off_t off;
+
+#ifdef STATISTICS
+ ++mp->pagewrite;
+#endif
+
+ /* Run through the user's filter. */
+ if (mp->pgout)
+ (mp->pgout)(mp->pgcookie, bp->pgno, bp->page);
+
+ off = mp->pagesize * bp->pgno;
+ if (pwrite(mp->fd, bp->page, mp->pagesize, off) != (ssize_t)mp->pagesize)
+ return (RET_ERROR);
+
+ /*
+ * Re-run through the input filter since this page may soon be
+ * accessed via the cache, and whatever the user's output filter
+ * did may screw things up if we don't let the input filter
+ * restore the in-core copy.
+ */
+ if (mp->pgin)
+ (mp->pgin)(mp->pgcookie, bp->pgno, bp->page);
+
+ bp->flags &= ~MPOOL_DIRTY;
+ return (RET_SUCCESS);
+}
+
+/*
+ * mpool_look
+ * Lookup a page in the cache.
+ */
+static BKT *
+mpool_look(MPOOL *mp, pgno_t pgno)
+{
+ struct _hqh *head;
+ BKT *bp;
+
+ head = &mp->hqh[HASHKEY(pgno)];
+ TAILQ_FOREACH(bp, head, hq)
+ if ((bp->pgno == pgno) &&
+ ((bp->flags & MPOOL_INUSE) == MPOOL_INUSE)) {
+#ifdef STATISTICS
+ ++mp->cachehit;
+#endif
+ return (bp);
+ }
+#ifdef STATISTICS
+ ++mp->cachemiss;
+#endif
+ return (NULL);
+}
+
+#ifdef STATISTICS
+/*
+ * mpool_stat
+ * Print out cache statistics.
+ */
+void
+mpool_stat(MPOOL *mp)
+{
+ BKT *bp;
+ int cnt;
+ char *sep;
+
+ (void)fprintf(stderr, "%lu pages in the file\n", mp->npages);
+ (void)fprintf(stderr,
+ "page size %lu, cacheing %lu pages of %lu page max cache\n",
+ mp->pagesize, mp->curcache, mp->maxcache);
+ (void)fprintf(stderr, "%lu page puts, %lu page gets, %lu page new\n",
+ mp->pageput, mp->pageget, mp->pagenew);
+ (void)fprintf(stderr, "%lu page allocs, %lu page flushes\n",
+ mp->pagealloc, mp->pageflush);
+ if (mp->cachehit + mp->cachemiss)
+ (void)fprintf(stderr,
+ "%.0f%% cache hit rate (%lu hits, %lu misses)\n",
+ ((double)mp->cachehit / (mp->cachehit + mp->cachemiss))
+ * 100, mp->cachehit, mp->cachemiss);
+ (void)fprintf(stderr, "%lu page reads, %lu page writes\n",
+ mp->pageread, mp->pagewrite);
+
+ sep = "";
+ cnt = 0;
+ TAILQ_FOREACH(bp, &mp->lqh, q) {
+ (void)fprintf(stderr, "%s%d", sep, bp->pgno);
+ if (bp->flags & MPOOL_DIRTY)
+ (void)fprintf(stderr, "d");
+ if (bp->flags & MPOOL_PINNED)
+ (void)fprintf(stderr, "P");
+ if (++cnt == 10) {
+ sep = "\n";
+ cnt = 0;
+ } else
+ sep = ", ";
+
+ }
+ (void)fprintf(stderr, "\n");
+}
+#endif
diff --git a/lib/libc/db/mpool/mpool.libtp b/lib/libc/db/mpool/mpool.libtp
new file mode 100644
index 000000000000..bcd827dce29d
--- /dev/null
+++ b/lib/libc/db/mpool/mpool.libtp
@@ -0,0 +1,746 @@
+/******************************************************************************
+
+VERSION $FreeBSD$
+PACKAGE: User Level Shared Memory Manager
+
+DESCRIPTION:
+ This package provides a buffer pool interface implemented as
+ a collection of file pages mapped into shared memory.
+
+ Based on Mark's buffer manager
+
+ROUTINES:
+ External
+ buf_alloc
+ buf_flags
+ buf_get
+ buf_init
+ buf_last
+ buf_open
+ buf_pin
+ buf_sync
+ buf_unpin
+ Internal
+ bf_assign_buf
+ bf_fid_to_fd
+ bf_newbuf
+ bf_put_page
+
+
+******************************************************************************/
+#include <sys/types.h>
+#include <assert.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <errno.h>
+#include "list.h"
+#include "user.h"
+#include "txn_sys.h"
+#include "buf.h"
+#include "semkeys.h"
+#include "error.h"
+
+/*
+ we need to translate between some type of file id that the user
+ process passes and a file descriptor. For now, it's a nop.
+*/
+#define GET_MASTER get_sem ( buf_spinlock )
+#define RELEASE_MASTER release_sem ( buf_spinlock )
+
+#define LRUID *buf_lru
+#define LRUP (bufhdr_table+*buf_lru)
+#define MRU bufhdr_table[*buf_lru].lru.prev
+
+/* Global indicator that you have started reusing buffers */
+int do_statistics = 0;
+/*
+ Process Statics (pointers into shared memory)
+*/
+static BUF_T *buf_table = 0;
+static BUFHDR_T *bufhdr_table;
+static int *buf_hash_table;
+static int *buf_lru; /* LRU is the free list */
+static int buf_spinlock;
+static FINFO_T *buf_fids;
+static int *buf_sp; /* Pointer to string free space */
+static char *buf_strings;
+
+/* Process Local FID->FD table */
+static int fds[NUM_FILE_ENTRIES];
+
+/* Static routines */
+static BUFHDR_T *bf_assign_buf();
+static int bf_fid_to_fd();
+static BUFHDR_T *bf_newbuf();
+static int bf_put_page();
+
+/*
+ Return 0 on success
+ 1 on failure
+*/
+extern int
+buf_init ( )
+{
+ ADDR_T buf_region;
+ BUFHDR_T *bhp;
+ int i;
+ int ref_count;
+ int *spinlockp;
+
+ /*
+ Initialize Process local structures
+ */
+ for ( i = 0; i < NUM_FILE_ENTRIES; i++ ) {
+ fds[i] = -1;
+ }
+
+ buf_region = attach_region ( BUF_REGION_NAME, BUF_REGION_NUM,
+ BUF_REGION_SIZE, &ref_count );
+ if ( !buf_region ) {
+ return (1);
+ }
+ error_log3 ( "Buf Region: ADDR: %d ID: %d SIZE: %d\n", buf_region,
+ BUF_REGION_NUM, BUF_REGION_SIZE );
+
+ buf_table = (BUF_T *)buf_region;
+ bufhdr_table = (BUFHDR_T *)(buf_table + NUM_BUFS);
+ buf_hash_table = (int *)(bufhdr_table + NUM_BUFS);
+ buf_lru = buf_hash_table + NUMTABLE_ENTRIES;
+ spinlockp = buf_lru + 1;
+ buf_fids = (FINFO_T *)(spinlockp+1);
+ buf_sp = (int *)(buf_fids + NUM_FILE_ENTRIES);
+ buf_strings = (char *)(buf_sp + 1);
+
+ /* Create locking spinlock (gets creating holding the lock) */
+ buf_spinlock = create_sem ( BUF_SPIN_NAME, BUF_SPIN_NUM, ref_count <= 1 );
+ if ( buf_spinlock < 0 ) {
+ return(1);
+ }
+ if ( ref_count <= 1 ) {
+ *spinlockp = buf_spinlock;
+
+ /* Now initialize the buffer manager */
+
+ /* 1. Free list */
+ *buf_lru = 0;
+
+ /* 2. Buffer headers */
+ for ( i = 0, bhp = bufhdr_table; i < NUM_BUFS; bhp++, i++ ) {
+ bhp->lru.next = i+1;
+ bhp->lru.prev = i-1;
+ bhp->flags = 0; /* All Flags off */
+ bhp->refcount = 0;
+ bhp->wait_proc = -1; /* No sleepers */
+ LISTPE_INIT ( hash, bhp, i ); /* Hash chains */
+ }
+ bufhdr_table[0].lru.prev = NUM_BUFS-1;
+ bufhdr_table[NUM_BUFS-1].lru.next = 0;
+
+ /* 3. Hash Table */
+ for ( i = 0; i < NUMTABLE_ENTRIES; i++ ) {
+ buf_hash_table[i] = NUM_BUFS;
+ }
+
+ /* 4. File ID Table */
+ for ( i = 0; i < NUM_FILE_ENTRIES; i++ ) {
+ buf_fids[i].offset = -1;
+ buf_fids[i].npages = -1;
+ buf_fids[i].refcount = 0;
+ }
+
+ /* 5. Free String Pointer */
+ *buf_sp = (FILE_NAME_LEN*NUM_FILE_ENTRIES);
+ if (RELEASE_MASTER) {
+ return(1);
+ }
+ error_log0 ( "Initialized buffer region\n" );
+ }
+ return (0);
+}
+
+extern void
+buf_exit()
+{
+ int ref;
+ int i;
+
+ /* Flush Buffer Pool on Exit */
+ for ( i = 0; i < NUM_FILE_ENTRIES; i++ ) {
+ if ( fds[i] != -1 ) {
+ close ( fds[i] );
+ }
+ }
+ if ( buf_table ) {
+ detach_region ( buf_table, BUF_REGION_NUM, BUF_REGION_SIZE, &ref );
+ }
+ return;
+}
+
+/*
+ We need an empty buffer. Find the LRU unpinned NON-Dirty page.
+*/
+static BUFHDR_T *
+bf_newbuf()
+{
+ int fd;
+ int lruid;
+ int nbytes;
+ int ndx;
+ BUFHDR_T *bhp;
+
+ lruid = LRUID;
+ for ( bhp = LRUP;
+ bhp->flags & (BUF_PINNED|BUF_IO_IN_PROGRESS);
+ bhp = LISTP_NEXTP (bufhdr_table, lru, bhp ) ) {
+
+ if ( bhp->lru.next == lruid ) {
+ /* OUT OF BUFFERS */
+ error_log1 ( "All buffers are pinned. %s\n",
+ "Unable to grant buffer request" );
+ return(NULL);
+ }
+ }
+ /* BHP can be used */
+ if ( bhp->flags & BUF_DIRTY ) {
+ do_statistics = 1;
+ /*
+ MIS Check for log flushed appropriately
+ */
+ fd = bf_fid_to_fd(bhp->id.file_id);
+ if ( fd == -1 ) {
+ error_log1 ("Invalid fid %d\n", bhp->id.file_id);
+ return(NULL);
+ }
+ if ( bf_put_page(fd, bhp) < 0 ) {
+ return(NULL);
+ }
+ }
+ /* Update Hash Pointers */
+ ndx = BUF_HASH ( bhp->id.file_id, bhp->id.obj_id );
+ LISTP_REMOVE(bufhdr_table, hash, bhp);
+ if ( buf_hash_table[ndx] == (bhp-bufhdr_table) ) {
+ if ( bhp->hash.next != (bhp-bufhdr_table) ) {
+ buf_hash_table[ndx] = bhp->hash.next;
+ } else {
+ buf_hash_table[ndx] = NUM_BUFS;
+ }
+ }
+ INIT_BUF(bhp);
+
+ return(bhp);
+}
+/*
+ buf_alloc
+
+ Add a page to a file and return a buffer for it.
+
+*/
+ADDR_T
+buf_alloc ( fid, new_pageno )
+int fid;
+int *new_pageno;
+{
+ BUFHDR_T *bhp;
+ int fd;
+ int len;
+ int ndx;
+ OBJ_T fobj;
+
+ if (GET_MASTER) {
+ return(NULL);
+ }
+ if ( buf_fids[fid].npages == -1 ) {
+ /* initialize npages field */
+ fd = bf_fid_to_fd ( fid );
+ }
+ assert (fid < NUM_FILE_ENTRIES);
+
+ *new_pageno = buf_fids[fid].npages;
+ if ( *new_pageno == -1 ) {
+ RELEASE_MASTER;
+ return ( NULL );
+ }
+ buf_fids[fid].npages++;
+ ndx = BUF_HASH ( fid, *new_pageno );
+ fobj.file_id = fid;
+ fobj.obj_id = *new_pageno;
+ bhp = bf_assign_buf ( ndx, &fobj, BF_PIN|BF_DIRTY|BF_EMPTY, &len );
+ if ( RELEASE_MASTER ) {
+ /* Memory leak */
+ return(NULL);
+ }
+ if ( bhp ) {
+ return ((ADDR_T)(buf_table+(bhp-bufhdr_table)));
+ } else {
+ return ( NULL );
+ }
+}
+
+
+/*
+ Buffer Flags
+ BF_DIRTY Mark page as dirty
+ BF_EMPTY Don't initialize page, just get buffer
+ BF_PIN Retrieve with pin
+
+MIS
+Might want to add a flag that sets an LSN for this buffer is the
+DIRTY flag is set
+
+Eventually, you may want a flag that indicates the I/O and lock
+request should be shipped off together, but not for now.
+*/
+extern ADDR_T
+buf_get ( file_id, page_id, flags, len )
+int file_id;
+int page_id;
+u_long flags;
+int *len; /* Number of bytes read into buffer */
+{
+ BUFHDR_T *bhp;
+ int bufid;
+ int fd;
+ int ndx;
+ int next_bufid;
+ int stat;
+ OBJ_T fobj;
+
+ ndx = BUF_HASH ( file_id, page_id );
+ fobj.file_id = (long) file_id;
+ fobj.obj_id = (long) page_id;
+ if ( GET_MASTER ) {
+ return(NULL);
+ }
+ /*
+ This could be a for loop, but we lose speed
+ by making all the cases general purpose so we
+ optimize for the no-collision case.
+ */
+ bufid = buf_hash_table[ndx];
+ if ( bufid < NUM_BUFS ) {
+ for ( bhp = bufhdr_table+bufid;
+ !OBJ_EQ (bhp->id, fobj) || !(bhp->flags & BUF_VALID);
+ bhp = LISTP_NEXTP ( bufhdr_table, hash, bhp ) ) {
+
+ if ( bhp->hash.next == bufid ) {
+ goto not_found;
+ }
+ }
+/* found */
+ if ( flags & BF_PIN ) {
+ bhp->flags |= BUF_PINNED;
+ bhp->refcount++;
+#ifdef PIN_DEBUG
+ fprintf(stderr, "buf_get: %X PINNED (%d)\n",
+ buf_table + (bhp-bufhdr_table), bhp->refcount);
+#endif
+ }
+ if ( flags & BF_DIRTY ) {
+ bhp->flags |= BUF_DIRTY;
+ }
+
+ while ( bhp->flags & BUF_IO_IN_PROGRESS ) {
+ /* MIS -- eventually err check here */
+#ifdef DEBUG
+ printf("About to sleep on %d (me: %d\n)\n", bhp->wait_proc,
+ my_txnp - txn_table);
+#endif
+#ifdef WAIT_STATS
+ buf_waits++;
+#endif
+ stat = proc_sleep_on ( &(bhp->wait_proc), buf_spinlock );
+ if ( stat ) {
+ /* Memory leak */
+ return(NULL);
+ }
+ if (!( bhp->flags & BUF_IO_IN_PROGRESS) &&
+ (!OBJ_EQ (bhp->id, fobj) || !(bhp->flags & BUF_VALID))) {
+ if (RELEASE_MASTER)
+ return(NULL);
+ return(buf_get ( file_id, page_id, flags, len ));
+ }
+ }
+ MAKE_MRU( bhp );
+ *len = BUFSIZE;
+ } else {
+not_found:
+ /* If you get here, the page isn't in the hash table */
+ bhp = bf_assign_buf ( ndx, &fobj, flags, len );
+ }
+ /* Common code between found and not found */
+
+ if ( bhp && bhp->flags & BUF_NEWPAGE ) {
+ *len = 0;
+ }
+ if (RELEASE_MASTER){
+ /* Memory leak */
+ return(NULL);
+ }
+ if ( bhp ) {
+ return ((ADDR_T)(buf_table+(bhp-bufhdr_table)));
+ } else {
+ return ( NULL );
+ }
+}
+
+/*
+ MIS - do I want to add file links to buffer pool?
+*/
+extern int
+buf_sync ( fid, close )
+int fid;
+int close; /* should we dec refcount and possibly
+ invalidate all the buffers */
+{
+ int i;
+ int fd;
+ int invalidate;
+ BUFHDR_T *bhp;
+
+ if ( (fd = bf_fid_to_fd ( fid )) < 0 ) {
+ return(1);
+ }
+ if (GET_MASTER) {
+ return(1);
+ }
+ invalidate = (buf_fids[fid].refcount == 1 && close);
+ if ( invalidate )
+ for ( bhp = bufhdr_table, i = 0; i < NUM_BUFS; bhp++, i++ ) {
+ if (bhp->id.file_id == fid) {
+ if ((bhp->flags & BF_DIRTY) && (bf_put_page( fd, bhp ) < 0)) {
+ return(1);
+ }
+ bhp->id.file_id = -1;
+ }
+ }
+ if (invalidate || close)
+ buf_fids[fid].refcount--;
+
+ if (RELEASE_MASTER) {
+ return(1);
+ }
+ return(0);
+
+
+}
+
+extern int
+buf_flags ( addr, set_flags, unset_flags )
+ADDR_T addr;
+u_long set_flags;
+u_long unset_flags;
+{
+ int bufid;
+ BUFHDR_T *bhp;
+
+#ifdef PIN_DEBUG
+ fprintf(stderr, "buf_flags: %X setting %s%s%s%s%s releasing %s%s%s%s%s\n",
+ addr,
+ set_flags&BUF_DIRTY ? "DIRTY " : "",
+ set_flags&BUF_VALID ? "VALID " : "",
+ set_flags&BUF_PINNED ? "PINNED " : "",
+ set_flags&BUF_IO_ERROR ? "IO_ERROR " : "",
+ set_flags&BUF_IO_IN_PROGRESS ? "IO_IN_PROG " : "",
+ set_flags&BUF_NEWPAGE ? "NEWPAGE " : "",
+ unset_flags&BUF_DIRTY ? "DIRTY " : "",
+ unset_flags&BUF_VALID ? "VALID " : "",
+ unset_flags&BUF_PINNED ? "PINNED " : "",
+ unset_flags&BUF_IO_ERROR ? "IO_ERROR " : "",
+ unset_flags&BUF_IO_IN_PROGRESS ? "IO_IN_PROG " : "",
+ unset_flags&BUF_NEWPAGE ? "NEWPAGE " : "" );
+#endif
+ if (!ADDR_OK(addr)) {
+ error_log1 ( "buf_pin: Invalid Buffer Address %x\n", addr );
+ return(1);
+ }
+ bufid = ((BUF_T *)addr) - buf_table;
+ assert ( bufid < NUM_BUFS);
+ bhp = &bufhdr_table[bufid];
+ if (GET_MASTER) {
+ return(1);
+ }
+ bhp->flags |= set_flags;
+ if ( set_flags & BUF_PINNED ) {
+ bhp->refcount++;
+ }
+ if ( set_flags & BUF_DIRTY ) {
+ unset_flags |= BUF_NEWPAGE;
+ }
+
+ if ( unset_flags & BUF_PINNED ) {
+ bhp->refcount--;
+ if ( bhp->refcount ) {
+ /* Turn off pin bit so it doesn't get unset */
+ unset_flags &= ~BUF_PINNED;
+ }
+ }
+ bhp->flags &= ~unset_flags;
+ MAKE_MRU(bhp);
+ if (RELEASE_MASTER) {
+ return(1);
+ }
+ return(0);
+}
+
+/*
+ Take a string name and produce an fid.
+
+ returns -1 on error
+
+ MIS -- this is a potential problem -- you keep actual names
+ here -- what if people run from different directories?
+*/
+extern int
+buf_name_lookup ( fname )
+char *fname;
+{
+ int i;
+ int fid;
+ int ndx;
+
+ fid = -1;
+ if (GET_MASTER) {
+ return(-1);
+ }
+ for ( i = 0; i < NUM_FILE_ENTRIES; i++ ) {
+ if ( buf_fids[i].offset == -1 ) {
+ fid = i;
+ } else {
+ if (!strcmp (fname, buf_strings+buf_fids[i].offset)) {
+ if (RELEASE_MASTER) {
+ return(-1);
+ }
+ buf_fids[i].refcount++;
+ return(i);
+ }
+ }
+ }
+ if ( fid == -1 ) {
+ error_log0 ( "No more file ID's\n" );
+ } else {
+ ndx = *buf_sp - strlen(fname) - 1;
+ if ( ndx < 0 ) {
+ error_log0 ( "Out of string space\n" );
+ fid = -1;
+ } else {
+ *buf_sp = ndx;
+ strcpy ( buf_strings+ndx, fname );
+ buf_fids[fid].offset = ndx;
+ }
+ buf_fids[fid].refcount = 1;
+ }
+ if (RELEASE_MASTER) {
+ return(-1);
+ }
+ return(fid);
+}
+
+static int
+bf_fid_to_fd ( fid )
+int fid;
+{
+ struct stat sbuf;
+
+ assert ( (fid < NUM_FILE_ENTRIES) && (buf_fids[fid].offset != -1) );
+ if ( fds[fid] != -1 ) {
+ return(fds[fid]);
+
+ }
+ fds[fid] = open ( buf_strings+buf_fids[fid].offset, O_RDWR|O_CREAT,
+ 0666 );
+ if ( fds[fid] < 0 ) {
+ error_log3 ( "Error Opening File %s FID: %d FD: %d. Errno = %d\n",
+ buf_strings+buf_fids[fid].offset, fid, fds[fid],
+ errno );
+ return(-1);
+ }
+ error_log3 ( "Opening File %s FID: %d FD: %d\n",
+ buf_strings+buf_fids[fid].offset, fid, fds[fid] );
+ if ( buf_fids[fid].npages == -1 ) {
+ /* Initialize the npages field */
+ if ( fstat ( fds[fid], &sbuf ) ) {
+ error_log3 ( "Error Fstating %s FID: %d. Errno = %d\n",
+ buf_strings+buf_fids[fid].offset, fid, errno );
+ } else {
+ buf_fids[fid].npages = ( sbuf.st_size / BUFSIZE );
+ }
+ }
+
+ return ( fds[fid] );
+}
+
+static int
+bf_put_page ( fd, bhp )
+int fd;
+BUFHDR_T *bhp;
+{
+ int nbytes;
+
+ assert ( (bhp-bufhdr_table) < NUM_BUFS );
+ if ( lseek ( fd, bhp->id.obj_id << BUFSHIFT, L_SET ) < 0 ) {
+ return(-1);
+ }
+ bhp->flags |= BUF_IO_IN_PROGRESS;
+ if (RELEASE_MASTER) {
+ return(-1);
+ }
+ nbytes = write(fd, buf_table[bhp-bufhdr_table], BUFSIZE);
+ if (GET_MASTER) {
+ return(-2);
+ }
+ if ( nbytes < 0 ) {
+ error_log1 ("Write failed with error code %d\n", errno);
+ return(-1);
+ } else if ( nbytes != BUFSIZE ) {
+ error_log1 ("Short write: %d bytes of %d\n", nbytes, BUFSIZE );
+ }
+ bhp->flags &= ~(BUF_DIRTY|BUF_IO_IN_PROGRESS);
+ return (0);
+}
+
+static BUFHDR_T *
+bf_assign_buf ( ndx, obj, flags, len )
+int ndx;
+OBJ_T *obj;
+u_long flags;
+int *len; /* Number of bytes read */
+{
+ BUFHDR_T *bhp;
+ int fd;
+
+ assert ( obj->file_id < NUM_FILE_ENTRIES );
+ bhp = bf_newbuf();
+ if ( !bhp ) {
+ return(NULL);
+ }
+ OBJ_ASSIGN ( (*obj), bhp->id );
+ if ( buf_hash_table[ndx] >= NUM_BUFS ) {
+ buf_hash_table[ndx] = bhp-bufhdr_table;
+ } else {
+ LISTPE_INSERT ( bufhdr_table, hash, bhp, buf_hash_table[ndx] );
+ }
+
+ bhp->flags |= BUF_VALID;
+ if ( flags & BF_PIN ) {
+ bhp->flags |= BUF_PINNED;
+ bhp->refcount++;
+#ifdef PIN_DEBUG
+ fprintf(stderr, "bf_assign_buf: %X PINNED (%d)\n",
+ buf_table + (bhp-bufhdr_table), bhp->refcount);
+#endif
+ }
+ fd = bf_fid_to_fd(obj->file_id);
+ if ( fd == -1 ) {
+ error_log1 ("Invalid fid %d\n", obj->file_id);
+ bhp->flags |= ~BUF_IO_ERROR;
+ return(NULL);
+ }
+ if ( obj->obj_id >= buf_fids[obj->file_id].npages) {
+ buf_fids[obj->file_id].npages = obj->obj_id+1;
+ *len = 0;
+ } else if ( flags & BF_EMPTY ) {
+ *len = 0;
+ } else {
+ bhp->flags |= BUF_IO_IN_PROGRESS;
+ if (RELEASE_MASTER) {
+ return(NULL);
+ }
+ if ( lseek ( fd, obj->obj_id << BUFSHIFT, L_SET ) < -1 ) {
+ error_log2 ("Unable to perform seek on file: %d to page %d",
+ obj->file_id, obj->obj_id );
+ bhp->flags &= ~BUF_IO_IN_PROGRESS;
+ bhp->flags |= ~BUF_IO_ERROR;
+ return(NULL);
+ }
+ *len = read(fd, buf_table[bhp-bufhdr_table], BUFSIZE);
+ if ( *len < 0 ) {
+ error_log2 ("Unable to perform read on file: %d to page %d",
+ obj->file_id, obj->obj_id );
+ bhp->flags &= ~BUF_IO_IN_PROGRESS;
+ bhp->flags |= ~BUF_IO_ERROR;
+ return(NULL);
+ }
+ if (GET_MASTER) {
+ return(NULL);
+ }
+ bhp->flags &= ~BUF_IO_IN_PROGRESS;
+ if ( bhp->wait_proc != -1 ) {
+ /* wake up waiter and anyone waiting on it */
+#ifdef DEBUG
+ printf("Waking transaction %d due to completed I/O\n",
+ bhp->wait_proc);
+#endif
+ proc_wake_id ( bhp->wait_proc );
+ bhp->wait_proc = -1;
+ }
+ MAKE_MRU(bhp);
+ }
+
+ if ( flags & BF_DIRTY ) {
+ bhp->flags |= BUF_DIRTY;
+ } else if ( *len < BUFSIZE ) {
+ bhp->flags |= BUF_NEWPAGE;
+ }
+ return ( bhp );
+}
+
+int
+buf_last ( fid )
+int fid;
+{
+ int val;
+
+ if (GET_MASTER) {
+ return(-1);
+ }
+ assert ( fid < NUM_FILE_ENTRIES );
+ if ( buf_fids[fid].npages == -1 ) {
+ /* initialize npages field */
+ (void) bf_fid_to_fd ( fid );
+ }
+ val = buf_fids[fid].npages;
+ if ( val ) {
+ val--; /* Convert to page number */
+ }
+ if (RELEASE_MASTER) {
+ return(-1);
+ }
+ return(val);
+}
+
+#ifdef DEBUG
+extern void
+buf_dump ( id, all )
+int id;
+int all;
+{
+ int i;
+ BUFHDR_T *bhp;
+
+ printf ( "LRU + %d\n", *buf_lru );
+ if ( all ) {
+ printf("ID\tFID\tPID\tLNEXT\tLPREV\tHNEXT\tHPREV\tSLEEP\tFLAG\tREFS\n");
+ for ( bhp = bufhdr_table, i = 0; i < NUM_BUFS; bhp++, i++ ) {
+ printf ( "%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%x\t%d\n", i,
+ bhp->id.file_id, bhp->id.obj_id,
+ bhp->lru.next, bhp->lru.prev,
+ bhp->hash.next, bhp->hash.prev,
+ bhp->wait_proc, bhp->flags, bhp->refcount );
+ }
+ } else {
+ if ( id >= NUM_BUFS ) {
+ printf ( "Buffer ID (%d) too high\n", id );
+ return;
+ }
+ bhp = bufhdr_table+id;
+ printf ( "%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%x\t%d\n", i,
+ bhp->id.file_id, bhp->id.obj_id,
+ bhp->lru.next, bhp->lru.prev,
+ bhp->hash.next, bhp->hash.prev,
+ bhp->wait_proc, bhp->flags, bhp->refcount );
+ }
+ return;
+}
+#endif
+
diff --git a/lib/libc/db/recno/Makefile.inc b/lib/libc/db/recno/Makefile.inc
new file mode 100644
index 000000000000..744109f46d83
--- /dev/null
+++ b/lib/libc/db/recno/Makefile.inc
@@ -0,0 +1,7 @@
+# from @(#)Makefile.inc 8.1 (Berkeley) 6/4/93
+# $FreeBSD$
+
+.PATH: ${LIBC_SRCTOP}/db/recno
+
+SRCS+= rec_close.c rec_delete.c rec_get.c rec_open.c rec_put.c rec_search.c \
+ rec_seq.c rec_utils.c
diff --git a/lib/libc/db/recno/extern.h b/lib/libc/db/recno/extern.h
new file mode 100644
index 000000000000..53916bd4861a
--- /dev/null
+++ b/lib/libc/db/recno/extern.h
@@ -0,0 +1,51 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)extern.h 8.3 (Berkeley) 6/4/94
+ * $FreeBSD$
+ */
+
+#include "../btree/extern.h"
+
+int __rec_close(DB *);
+int __rec_delete(const DB *, const DBT *, u_int);
+int __rec_dleaf(BTREE *, PAGE *, u_int32_t);
+int __rec_fd(const DB *);
+int __rec_fmap(BTREE *, recno_t);
+int __rec_fout(BTREE *);
+int __rec_fpipe(BTREE *, recno_t);
+int __rec_get(const DB *, const DBT *, DBT *, u_int);
+int __rec_iput(BTREE *, recno_t, const DBT *, u_int);
+int __rec_put(const DB *dbp, DBT *, const DBT *, u_int);
+int __rec_ret(BTREE *, EPG *, recno_t, DBT *, DBT *);
+EPG *__rec_search(BTREE *, recno_t, enum SRCHOP);
+int __rec_seq(const DB *, DBT *, DBT *, u_int);
+int __rec_sync(const DB *, u_int);
+int __rec_vmap(BTREE *, recno_t);
+int __rec_vout(BTREE *);
+int __rec_vpipe(BTREE *, recno_t);
diff --git a/lib/libc/db/recno/rec_close.c b/lib/libc/db/recno/rec_close.c
new file mode 100644
index 000000000000..2d1ff846c4b0
--- /dev/null
+++ b/lib/libc/db/recno/rec_close.c
@@ -0,0 +1,182 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)rec_close.c 8.6 (Berkeley) 8/18/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/mman.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+#include <db.h>
+#include "recno.h"
+
+/*
+ * __REC_CLOSE -- Close a recno tree.
+ *
+ * Parameters:
+ * dbp: pointer to access method
+ *
+ * Returns:
+ * RET_ERROR, RET_SUCCESS
+ */
+int
+__rec_close(DB *dbp)
+{
+ BTREE *t;
+ int status;
+
+ t = dbp->internal;
+
+ /* Toss any page pinned across calls. */
+ if (t->bt_pinned != NULL) {
+ mpool_put(t->bt_mp, t->bt_pinned, 0);
+ t->bt_pinned = NULL;
+ }
+
+ if (__rec_sync(dbp, 0) == RET_ERROR)
+ return (RET_ERROR);
+
+ /* Committed to closing. */
+ status = RET_SUCCESS;
+ if (F_ISSET(t, R_MEMMAPPED) && munmap(t->bt_smap, t->bt_msize))
+ status = RET_ERROR;
+
+ if (!F_ISSET(t, R_INMEM)) {
+ if (F_ISSET(t, R_CLOSEFP)) {
+ if (fclose(t->bt_rfp))
+ status = RET_ERROR;
+ } else {
+ if (_close(t->bt_rfd))
+ status = RET_ERROR;
+ }
+ }
+
+ if (__bt_close(dbp) == RET_ERROR)
+ status = RET_ERROR;
+
+ return (status);
+}
+
+/*
+ * __REC_SYNC -- sync the recno tree to disk.
+ *
+ * Parameters:
+ * dbp: pointer to access method
+ *
+ * Returns:
+ * RET_SUCCESS, RET_ERROR.
+ */
+int
+__rec_sync(const DB *dbp, u_int flags)
+{
+ struct iovec iov[2];
+ BTREE *t;
+ DBT data, key;
+ off_t off;
+ recno_t scursor, trec;
+ int status;
+
+ t = dbp->internal;
+
+ /* Toss any page pinned across calls. */
+ if (t->bt_pinned != NULL) {
+ mpool_put(t->bt_mp, t->bt_pinned, 0);
+ t->bt_pinned = NULL;
+ }
+
+ if (flags == R_RECNOSYNC)
+ return (__bt_sync(dbp, 0));
+
+ if (F_ISSET(t, R_RDONLY | R_INMEM) || !F_ISSET(t, R_MODIFIED))
+ return (RET_SUCCESS);
+
+ /* Read any remaining records into the tree. */
+ if (!F_ISSET(t, R_EOF) && t->bt_irec(t, MAX_REC_NUMBER) == RET_ERROR)
+ return (RET_ERROR);
+
+ /* Rewind the file descriptor. */
+ if (lseek(t->bt_rfd, (off_t)0, SEEK_SET) != 0)
+ return (RET_ERROR);
+
+ /* Save the cursor. */
+ scursor = t->bt_cursor.rcursor;
+
+ key.size = sizeof(recno_t);
+ key.data = &trec;
+
+ if (F_ISSET(t, R_FIXLEN)) {
+ /*
+ * We assume that fixed length records are all fixed length.
+ * Any that aren't are either EINVAL'd or corrected by the
+ * record put code.
+ */
+ status = (dbp->seq)(dbp, &key, &data, R_FIRST);
+ while (status == RET_SUCCESS) {
+ if (_write(t->bt_rfd, data.data, data.size) !=
+ (ssize_t)data.size)
+ return (RET_ERROR);
+ status = (dbp->seq)(dbp, &key, &data, R_NEXT);
+ }
+ } else {
+ iov[1].iov_base = &t->bt_bval;
+ iov[1].iov_len = 1;
+
+ status = (dbp->seq)(dbp, &key, &data, R_FIRST);
+ while (status == RET_SUCCESS) {
+ iov[0].iov_base = data.data;
+ iov[0].iov_len = data.size;
+ if (_writev(t->bt_rfd, iov, 2) != (ssize_t)(data.size + 1))
+ return (RET_ERROR);
+ status = (dbp->seq)(dbp, &key, &data, R_NEXT);
+ }
+ }
+
+ /* Restore the cursor. */
+ t->bt_cursor.rcursor = scursor;
+
+ if (status == RET_ERROR)
+ return (RET_ERROR);
+ if ((off = lseek(t->bt_rfd, (off_t)0, SEEK_CUR)) == -1)
+ return (RET_ERROR);
+ if (ftruncate(t->bt_rfd, off))
+ return (RET_ERROR);
+ F_CLR(t, R_MODIFIED);
+ return (RET_SUCCESS);
+}
diff --git a/lib/libc/db/recno/rec_delete.c b/lib/libc/db/recno/rec_delete.c
new file mode 100644
index 000000000000..d799da282ceb
--- /dev/null
+++ b/lib/libc/db/recno/rec_delete.c
@@ -0,0 +1,187 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Mike Olson.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)rec_delete.c 8.7 (Berkeley) 7/14/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <db.h>
+#include "recno.h"
+
+static int rec_rdelete(BTREE *, recno_t);
+
+/*
+ * __REC_DELETE -- Delete the item(s) referenced by a key.
+ *
+ * Parameters:
+ * dbp: pointer to access method
+ * key: key to delete
+ * flags: R_CURSOR if deleting what the cursor references
+ *
+ * Returns:
+ * RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key not found.
+ */
+int
+__rec_delete(const DB *dbp, const DBT *key, u_int flags)
+{
+ BTREE *t;
+ recno_t nrec;
+ int status;
+
+ t = dbp->internal;
+
+ /* Toss any page pinned across calls. */
+ if (t->bt_pinned != NULL) {
+ mpool_put(t->bt_mp, t->bt_pinned, 0);
+ t->bt_pinned = NULL;
+ }
+
+ switch(flags) {
+ case 0:
+ if ((nrec = *(recno_t *)key->data) == 0)
+ goto einval;
+ if (nrec > t->bt_nrecs)
+ return (RET_SPECIAL);
+ --nrec;
+ status = rec_rdelete(t, nrec);
+ break;
+ case R_CURSOR:
+ if (!F_ISSET(&t->bt_cursor, CURS_INIT))
+ goto einval;
+ if (t->bt_nrecs == 0)
+ return (RET_SPECIAL);
+ status = rec_rdelete(t, t->bt_cursor.rcursor - 1);
+ if (status == RET_SUCCESS)
+ --t->bt_cursor.rcursor;
+ break;
+ default:
+einval: errno = EINVAL;
+ return (RET_ERROR);
+ }
+
+ if (status == RET_SUCCESS)
+ F_SET(t, B_MODIFIED | R_MODIFIED);
+ return (status);
+}
+
+/*
+ * REC_RDELETE -- Delete the data matching the specified key.
+ *
+ * Parameters:
+ * tree: tree
+ * nrec: record to delete
+ *
+ * Returns:
+ * RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key not found.
+ */
+static int
+rec_rdelete(BTREE *t, recno_t nrec)
+{
+ EPG *e;
+ PAGE *h;
+ int status;
+
+ /* Find the record; __rec_search pins the page. */
+ if ((e = __rec_search(t, nrec, SDELETE)) == NULL)
+ return (RET_ERROR);
+
+ /* Delete the record. */
+ h = e->page;
+ status = __rec_dleaf(t, h, e->index);
+ if (status != RET_SUCCESS) {
+ mpool_put(t->bt_mp, h, 0);
+ return (status);
+ }
+ mpool_put(t->bt_mp, h, MPOOL_DIRTY);
+ return (RET_SUCCESS);
+}
+
+/*
+ * __REC_DLEAF -- Delete a single record from a recno leaf page.
+ *
+ * Parameters:
+ * t: tree
+ * idx: index on current page to delete
+ *
+ * Returns:
+ * RET_SUCCESS, RET_ERROR.
+ */
+int
+__rec_dleaf(BTREE *t, PAGE *h, u_int32_t idx)
+{
+ RLEAF *rl;
+ indx_t *ip, cnt, offset;
+ u_int32_t nbytes;
+ char *from;
+ void *to;
+
+ /*
+ * Delete a record from a recno leaf page. Internal records are never
+ * deleted from internal pages, regardless of the records that caused
+ * them to be added being deleted. Pages made empty by deletion are
+ * not reclaimed. They are, however, made available for reuse.
+ *
+ * Pack the remaining entries at the end of the page, shift the indices
+ * down, overwriting the deleted record and its index. If the record
+ * uses overflow pages, make them available for reuse.
+ */
+ to = rl = GETRLEAF(h, idx);
+ if (rl->flags & P_BIGDATA && __ovfl_delete(t, rl->bytes) == RET_ERROR)
+ return (RET_ERROR);
+ nbytes = NRLEAF(rl);
+
+ /*
+ * Compress the key/data pairs. Compress and adjust the [BR]LEAF
+ * offsets. Reset the headers.
+ */
+ from = (char *)h + h->upper;
+ memmove(from + nbytes, from, (char *)to - from);
+ h->upper += nbytes;
+
+ offset = h->linp[idx];
+ for (cnt = &h->linp[idx] - (ip = &h->linp[0]); cnt--; ++ip)
+ if (ip[0] < offset)
+ ip[0] += nbytes;
+ for (cnt = &h->linp[NEXTINDEX(h)] - ip; --cnt; ++ip)
+ ip[0] = ip[1] < offset ? ip[1] + nbytes : ip[1];
+ h->lower -= sizeof(indx_t);
+ --t->bt_nrecs;
+ return (RET_SUCCESS);
+}
diff --git a/lib/libc/db/recno/rec_get.c b/lib/libc/db/recno/rec_get.c
new file mode 100644
index 000000000000..b543d478b8f0
--- /dev/null
+++ b/lib/libc/db/recno/rec_get.c
@@ -0,0 +1,291 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)rec_get.c 8.9 (Berkeley) 8/18/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <db.h>
+#include "recno.h"
+
+/*
+ * __REC_GET -- Get a record from the btree.
+ *
+ * Parameters:
+ * dbp: pointer to access method
+ * key: key to find
+ * data: data to return
+ * flag: currently unused
+ *
+ * Returns:
+ * RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key not found.
+ */
+int
+__rec_get(const DB *dbp, const DBT *key, DBT *data, u_int flags)
+{
+ BTREE *t;
+ EPG *e;
+ recno_t nrec;
+ int status;
+
+ t = dbp->internal;
+
+ /* Toss any page pinned across calls. */
+ if (t->bt_pinned != NULL) {
+ mpool_put(t->bt_mp, t->bt_pinned, 0);
+ t->bt_pinned = NULL;
+ }
+
+ /* Get currently doesn't take any flags, and keys of 0 are illegal. */
+ if (flags || (nrec = *(recno_t *)key->data) == 0) {
+ errno = EINVAL;
+ return (RET_ERROR);
+ }
+
+ /*
+ * If we haven't seen this record yet, try to find it in the
+ * original file.
+ */
+ if (nrec > t->bt_nrecs) {
+ if (F_ISSET(t, R_EOF | R_INMEM))
+ return (RET_SPECIAL);
+ if ((status = t->bt_irec(t, nrec)) != RET_SUCCESS)
+ return (status);
+ }
+
+ --nrec;
+ if ((e = __rec_search(t, nrec, SEARCH)) == NULL)
+ return (RET_ERROR);
+
+ status = __rec_ret(t, e, 0, NULL, data);
+ if (F_ISSET(t, B_DB_LOCK))
+ mpool_put(t->bt_mp, e->page, 0);
+ else
+ t->bt_pinned = e->page;
+ return (status);
+}
+
+/*
+ * __REC_FPIPE -- Get fixed length records from a pipe.
+ *
+ * Parameters:
+ * t: tree
+ * cnt: records to read
+ *
+ * Returns:
+ * RET_ERROR, RET_SUCCESS
+ */
+int
+__rec_fpipe(BTREE *t, recno_t top)
+{
+ DBT data;
+ recno_t nrec;
+ size_t len;
+ int ch;
+ u_char *p;
+
+ if (t->bt_rdata.size < t->bt_reclen) {
+ t->bt_rdata.data = reallocf(t->bt_rdata.data, t->bt_reclen);
+ if (t->bt_rdata.data == NULL)
+ return (RET_ERROR);
+ t->bt_rdata.size = t->bt_reclen;
+ }
+ data.data = t->bt_rdata.data;
+ data.size = t->bt_reclen;
+
+ for (nrec = t->bt_nrecs; nrec < top;) {
+ len = t->bt_reclen;
+ for (p = t->bt_rdata.data;; *p++ = ch)
+ if ((ch = getc(t->bt_rfp)) == EOF || !--len) {
+ if (ch != EOF)
+ *p = ch;
+ if (len != 0)
+ memset(p, t->bt_bval, len);
+ if (__rec_iput(t,
+ nrec, &data, 0) != RET_SUCCESS)
+ return (RET_ERROR);
+ ++nrec;
+ break;
+ }
+ if (ch == EOF)
+ break;
+ }
+ if (nrec < top) {
+ F_SET(t, R_EOF);
+ return (RET_SPECIAL);
+ }
+ return (RET_SUCCESS);
+}
+
+/*
+ * __REC_VPIPE -- Get variable length records from a pipe.
+ *
+ * Parameters:
+ * t: tree
+ * cnt: records to read
+ *
+ * Returns:
+ * RET_ERROR, RET_SUCCESS
+ */
+int
+__rec_vpipe(BTREE *t, recno_t top)
+{
+ DBT data;
+ recno_t nrec;
+ size_t len;
+ size_t sz;
+ int bval, ch;
+ u_char *p;
+
+ bval = t->bt_bval;
+ for (nrec = t->bt_nrecs; nrec < top; ++nrec) {
+ for (p = t->bt_rdata.data,
+ sz = t->bt_rdata.size;; *p++ = ch, --sz) {
+ if ((ch = getc(t->bt_rfp)) == EOF || ch == bval) {
+ data.data = t->bt_rdata.data;
+ data.size = p - (u_char *)t->bt_rdata.data;
+ if (ch == EOF && data.size == 0)
+ break;
+ if (__rec_iput(t, nrec, &data, 0)
+ != RET_SUCCESS)
+ return (RET_ERROR);
+ break;
+ }
+ if (sz == 0) {
+ len = p - (u_char *)t->bt_rdata.data;
+ t->bt_rdata.size += (sz = 256);
+ t->bt_rdata.data = reallocf(t->bt_rdata.data, t->bt_rdata.size);
+ if (t->bt_rdata.data == NULL)
+ return (RET_ERROR);
+ p = (u_char *)t->bt_rdata.data + len;
+ }
+ }
+ if (ch == EOF)
+ break;
+ }
+ if (nrec < top) {
+ F_SET(t, R_EOF);
+ return (RET_SPECIAL);
+ }
+ return (RET_SUCCESS);
+}
+
+/*
+ * __REC_FMAP -- Get fixed length records from a file.
+ *
+ * Parameters:
+ * t: tree
+ * cnt: records to read
+ *
+ * Returns:
+ * RET_ERROR, RET_SUCCESS
+ */
+int
+__rec_fmap(BTREE *t, recno_t top)
+{
+ DBT data;
+ recno_t nrec;
+ u_char *sp, *ep, *p;
+ size_t len;
+
+ if (t->bt_rdata.size < t->bt_reclen) {
+ t->bt_rdata.data = reallocf(t->bt_rdata.data, t->bt_reclen);
+ if (t->bt_rdata.data == NULL)
+ return (RET_ERROR);
+ t->bt_rdata.size = t->bt_reclen;
+ }
+ data.data = t->bt_rdata.data;
+ data.size = t->bt_reclen;
+
+ sp = (u_char *)t->bt_cmap;
+ ep = (u_char *)t->bt_emap;
+ for (nrec = t->bt_nrecs; nrec < top; ++nrec) {
+ if (sp >= ep) {
+ F_SET(t, R_EOF);
+ return (RET_SPECIAL);
+ }
+ len = t->bt_reclen;
+ for (p = t->bt_rdata.data;
+ sp < ep && len > 0; *p++ = *sp++, --len);
+ if (len != 0)
+ memset(p, t->bt_bval, len);
+ if (__rec_iput(t, nrec, &data, 0) != RET_SUCCESS)
+ return (RET_ERROR);
+ }
+ t->bt_cmap = (caddr_t)sp;
+ return (RET_SUCCESS);
+}
+
+/*
+ * __REC_VMAP -- Get variable length records from a file.
+ *
+ * Parameters:
+ * t: tree
+ * cnt: records to read
+ *
+ * Returns:
+ * RET_ERROR, RET_SUCCESS
+ */
+int
+__rec_vmap(BTREE *t, recno_t top)
+{
+ DBT data;
+ u_char *sp, *ep;
+ recno_t nrec;
+ int bval;
+
+ sp = (u_char *)t->bt_cmap;
+ ep = (u_char *)t->bt_emap;
+ bval = t->bt_bval;
+
+ for (nrec = t->bt_nrecs; nrec < top; ++nrec) {
+ if (sp >= ep) {
+ F_SET(t, R_EOF);
+ return (RET_SPECIAL);
+ }
+ for (data.data = sp; sp < ep && *sp != bval; ++sp);
+ data.size = sp - (u_char *)data.data;
+ if (__rec_iput(t, nrec, &data, 0) != RET_SUCCESS)
+ return (RET_ERROR);
+ ++sp;
+ }
+ t->bt_cmap = (caddr_t)sp;
+ return (RET_SUCCESS);
+}
diff --git a/lib/libc/db/recno/rec_open.c b/lib/libc/db/recno/rec_open.c
new file mode 100644
index 000000000000..8fce730f2799
--- /dev/null
+++ b/lib/libc/db/recno/rec_open.c
@@ -0,0 +1,238 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Mike Olson.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)rec_open.c 8.10 (Berkeley) 9/1/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+#include <db.h>
+#include "recno.h"
+
+DB *
+__rec_open(const char *fname, int flags, int mode, const RECNOINFO *openinfo,
+ int dflags)
+{
+ BTREE *t;
+ BTREEINFO btopeninfo;
+ DB *dbp;
+ PAGE *h;
+ struct stat sb;
+ int rfd, sverrno;
+
+ /* Open the user's file -- if this fails, we're done. */
+ if (fname != NULL && (rfd = _open(fname, flags | O_CLOEXEC, mode)) < 0)
+ return (NULL);
+
+ /* Create a btree in memory (backed by disk). */
+ dbp = NULL;
+ if (openinfo) {
+ if (openinfo->flags & ~(R_FIXEDLEN | R_NOKEY | R_SNAPSHOT))
+ goto einval;
+ btopeninfo.flags = 0;
+ btopeninfo.cachesize = openinfo->cachesize;
+ btopeninfo.maxkeypage = 0;
+ btopeninfo.minkeypage = 0;
+ btopeninfo.psize = openinfo->psize;
+ btopeninfo.compare = NULL;
+ btopeninfo.prefix = NULL;
+ btopeninfo.lorder = openinfo->lorder;
+ dbp = __bt_open(openinfo->bfname,
+ O_RDWR, S_IRUSR | S_IWUSR, &btopeninfo, dflags);
+ } else
+ dbp = __bt_open(NULL, O_RDWR, S_IRUSR | S_IWUSR, NULL, dflags);
+ if (dbp == NULL)
+ goto err;
+
+ /*
+ * Some fields in the tree structure are recno specific. Fill them
+ * in and make the btree structure look like a recno structure. We
+ * don't change the bt_ovflsize value, it's close enough and slightly
+ * bigger.
+ */
+ t = dbp->internal;
+ if (openinfo) {
+ if (openinfo->flags & R_FIXEDLEN) {
+ F_SET(t, R_FIXLEN);
+ t->bt_reclen = openinfo->reclen;
+ if (t->bt_reclen == 0)
+ goto einval;
+ }
+ t->bt_bval = openinfo->bval;
+ } else
+ t->bt_bval = '\n';
+
+ F_SET(t, R_RECNO);
+ if (fname == NULL)
+ F_SET(t, R_EOF | R_INMEM);
+ else
+ t->bt_rfd = rfd;
+
+ if (fname != NULL) {
+ /*
+ * In 4.4BSD, stat(2) returns true for ISSOCK on pipes.
+ * Unfortunately, that's not portable, so we use lseek
+ * and check the errno values.
+ */
+ errno = 0;
+ if (lseek(rfd, (off_t)0, SEEK_CUR) == -1 && errno == ESPIPE) {
+ switch (flags & O_ACCMODE) {
+ case O_RDONLY:
+ F_SET(t, R_RDONLY);
+ break;
+ default:
+ goto einval;
+ }
+slow: if ((t->bt_rfp = fdopen(rfd, "r")) == NULL)
+ goto err;
+ F_SET(t, R_CLOSEFP);
+ t->bt_irec =
+ F_ISSET(t, R_FIXLEN) ? __rec_fpipe : __rec_vpipe;
+ } else {
+ switch (flags & O_ACCMODE) {
+ case O_RDONLY:
+ F_SET(t, R_RDONLY);
+ break;
+ case O_RDWR:
+ break;
+ default:
+ goto einval;
+ }
+
+ if (_fstat(rfd, &sb))
+ goto err;
+ /*
+ * Kluge -- we'd like to test to see if the file is too
+ * big to mmap. Since, we don't know what size or type
+ * off_t's or size_t's are, what the largest unsigned
+ * integral type is, or what random insanity the local
+ * C compiler will perpetrate, doing the comparison in
+ * a portable way is flatly impossible. Hope that mmap
+ * fails if the file is too large.
+ */
+ if (sb.st_size == 0)
+ F_SET(t, R_EOF);
+ else {
+#ifdef MMAP_NOT_AVAILABLE
+ /*
+ * XXX
+ * Mmap doesn't work correctly on many current
+ * systems. In particular, it can fail subtly,
+ * with cache coherency problems. Don't use it
+ * for now.
+ */
+ t->bt_msize = sb.st_size;
+ if ((t->bt_smap = mmap(NULL, t->bt_msize,
+ PROT_READ, MAP_PRIVATE, rfd,
+ (off_t)0)) == MAP_FAILED)
+ goto slow;
+ t->bt_cmap = t->bt_smap;
+ t->bt_emap = t->bt_smap + sb.st_size;
+ t->bt_irec = F_ISSET(t, R_FIXLEN) ?
+ __rec_fmap : __rec_vmap;
+ F_SET(t, R_MEMMAPPED);
+#else
+ goto slow;
+#endif
+ }
+ }
+ }
+
+ /* Use the recno routines. */
+ dbp->close = __rec_close;
+ dbp->del = __rec_delete;
+ dbp->fd = __rec_fd;
+ dbp->get = __rec_get;
+ dbp->put = __rec_put;
+ dbp->seq = __rec_seq;
+ dbp->sync = __rec_sync;
+
+ /* If the root page was created, reset the flags. */
+ if ((h = mpool_get(t->bt_mp, P_ROOT, 0)) == NULL)
+ goto err;
+ if ((h->flags & P_TYPE) == P_BLEAF) {
+ F_CLR(h, P_TYPE);
+ F_SET(h, P_RLEAF);
+ mpool_put(t->bt_mp, h, MPOOL_DIRTY);
+ } else
+ mpool_put(t->bt_mp, h, 0);
+
+ if (openinfo && openinfo->flags & R_SNAPSHOT &&
+ !F_ISSET(t, R_EOF | R_INMEM) &&
+ t->bt_irec(t, MAX_REC_NUMBER) == RET_ERROR)
+ goto err;
+ return (dbp);
+
+einval: errno = EINVAL;
+err: sverrno = errno;
+ if (dbp != NULL)
+ (void)__bt_close(dbp);
+ if (fname != NULL)
+ (void)_close(rfd);
+ errno = sverrno;
+ return (NULL);
+}
+
+int
+__rec_fd(const DB *dbp)
+{
+ BTREE *t;
+
+ t = dbp->internal;
+
+ /* Toss any page pinned across calls. */
+ if (t->bt_pinned != NULL) {
+ mpool_put(t->bt_mp, t->bt_pinned, 0);
+ t->bt_pinned = NULL;
+ }
+
+ /* In-memory database can't have a file descriptor. */
+ if (F_ISSET(t, R_INMEM)) {
+ errno = ENOENT;
+ return (-1);
+ }
+ return (t->bt_rfd);
+}
diff --git a/lib/libc/db/recno/rec_put.c b/lib/libc/db/recno/rec_put.c
new file mode 100644
index 000000000000..68e6e854521b
--- /dev/null
+++ b/lib/libc/db/recno/rec_put.c
@@ -0,0 +1,274 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)rec_put.c 8.7 (Berkeley) 8/18/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <db.h>
+#include "recno.h"
+
+/*
+ * __REC_PUT -- Add a recno item to the tree.
+ *
+ * Parameters:
+ * dbp: pointer to access method
+ * key: key
+ * data: data
+ * flag: R_CURSOR, R_IAFTER, R_IBEFORE, R_NOOVERWRITE
+ *
+ * Returns:
+ * RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key is
+ * already in the tree and R_NOOVERWRITE specified.
+ */
+int
+__rec_put(const DB *dbp, DBT *key, const DBT *data, u_int flags)
+{
+ BTREE *t;
+ DBT fdata, tdata;
+ recno_t nrec;
+ int status;
+
+ t = dbp->internal;
+
+ /* Toss any page pinned across calls. */
+ if (t->bt_pinned != NULL) {
+ mpool_put(t->bt_mp, t->bt_pinned, 0);
+ t->bt_pinned = NULL;
+ }
+
+ /*
+ * If using fixed-length records, and the record is long, return
+ * EINVAL. If it's short, pad it out. Use the record data return
+ * memory, it's only short-term.
+ */
+ if (F_ISSET(t, R_FIXLEN) && data->size != t->bt_reclen) {
+ if (data->size > t->bt_reclen)
+ goto einval;
+
+ if (t->bt_rdata.size < t->bt_reclen) {
+ t->bt_rdata.data =
+ reallocf(t->bt_rdata.data, t->bt_reclen);
+ if (t->bt_rdata.data == NULL)
+ return (RET_ERROR);
+ t->bt_rdata.size = t->bt_reclen;
+ }
+ memmove(t->bt_rdata.data, data->data, data->size);
+ memset((char *)t->bt_rdata.data + data->size,
+ t->bt_bval, t->bt_reclen - data->size);
+ fdata.data = t->bt_rdata.data;
+ fdata.size = t->bt_reclen;
+ } else {
+ fdata.data = data->data;
+ fdata.size = data->size;
+ }
+
+ switch (flags) {
+ case R_CURSOR:
+ if (!F_ISSET(&t->bt_cursor, CURS_INIT))
+ goto einval;
+ nrec = t->bt_cursor.rcursor;
+ break;
+ case R_SETCURSOR:
+ if ((nrec = *(recno_t *)key->data) == 0)
+ goto einval;
+ break;
+ case R_IAFTER:
+ if ((nrec = *(recno_t *)key->data) == 0) {
+ nrec = 1;
+ flags = R_IBEFORE;
+ }
+ break;
+ case 0:
+ case R_IBEFORE:
+ if ((nrec = *(recno_t *)key->data) == 0)
+ goto einval;
+ break;
+ case R_NOOVERWRITE:
+ if ((nrec = *(recno_t *)key->data) == 0)
+ goto einval;
+ if (nrec <= t->bt_nrecs)
+ return (RET_SPECIAL);
+ break;
+ default:
+einval: errno = EINVAL;
+ return (RET_ERROR);
+ }
+
+ /*
+ * Make sure that records up to and including the put record are
+ * already in the database. If skipping records, create empty ones.
+ */
+ if (nrec > t->bt_nrecs) {
+ if (!F_ISSET(t, R_EOF | R_INMEM) &&
+ t->bt_irec(t, nrec) == RET_ERROR)
+ return (RET_ERROR);
+ if (nrec > t->bt_nrecs + 1) {
+ if (F_ISSET(t, R_FIXLEN)) {
+ if ((tdata.data = malloc(t->bt_reclen)) == NULL)
+ return (RET_ERROR);
+ tdata.size = t->bt_reclen;
+ memset(tdata.data, t->bt_bval, tdata.size);
+ } else {
+ tdata.data = NULL;
+ tdata.size = 0;
+ }
+ while (nrec > t->bt_nrecs + 1)
+ if (__rec_iput(t,
+ t->bt_nrecs, &tdata, 0) != RET_SUCCESS)
+ return (RET_ERROR);
+ if (F_ISSET(t, R_FIXLEN))
+ free(tdata.data);
+ }
+ }
+
+ if ((status = __rec_iput(t, nrec - 1, &fdata, flags)) != RET_SUCCESS)
+ return (status);
+
+ switch (flags) {
+ case R_IAFTER:
+ nrec++;
+ break;
+ case R_SETCURSOR:
+ t->bt_cursor.rcursor = nrec;
+ break;
+ }
+
+ F_SET(t, R_MODIFIED);
+ return (__rec_ret(t, NULL, nrec, key, NULL));
+}
+
+/*
+ * __REC_IPUT -- Add a recno item to the tree.
+ *
+ * Parameters:
+ * t: tree
+ * nrec: record number
+ * data: data
+ *
+ * Returns:
+ * RET_ERROR, RET_SUCCESS
+ */
+int
+__rec_iput(BTREE *t, recno_t nrec, const DBT *data, u_int flags)
+{
+ DBT tdata;
+ EPG *e;
+ PAGE *h;
+ indx_t idx, nxtindex;
+ pgno_t pg;
+ u_int32_t nbytes;
+ int dflags, status;
+ char *dest, db[NOVFLSIZE];
+
+ /*
+ * If the data won't fit on a page, store it on indirect pages.
+ *
+ * XXX
+ * If the insert fails later on, these pages aren't recovered.
+ */
+ if (data->size > t->bt_ovflsize) {
+ if (__ovfl_put(t, data, &pg) == RET_ERROR)
+ return (RET_ERROR);
+ tdata.data = db;
+ tdata.size = NOVFLSIZE;
+ memcpy(db, &pg, sizeof(pg));
+ *(u_int32_t *)(db + sizeof(pgno_t)) = data->size;
+ dflags = P_BIGDATA;
+ data = &tdata;
+ } else
+ dflags = 0;
+
+ /* __rec_search pins the returned page. */
+ if ((e = __rec_search(t, nrec,
+ nrec > t->bt_nrecs || flags == R_IAFTER || flags == R_IBEFORE ?
+ SINSERT : SEARCH)) == NULL)
+ return (RET_ERROR);
+
+ h = e->page;
+ idx = e->index;
+
+ /*
+ * Add the specified key/data pair to the tree. The R_IAFTER and
+ * R_IBEFORE flags insert the key after/before the specified key.
+ *
+ * Pages are split as required.
+ */
+ switch (flags) {
+ case R_IAFTER:
+ ++idx;
+ break;
+ case R_IBEFORE:
+ break;
+ default:
+ if (nrec < t->bt_nrecs &&
+ __rec_dleaf(t, h, idx) == RET_ERROR) {
+ mpool_put(t->bt_mp, h, 0);
+ return (RET_ERROR);
+ }
+ break;
+ }
+
+ /*
+ * If not enough room, split the page. The split code will insert
+ * the key and data and unpin the current page. If inserting into
+ * the offset array, shift the pointers up.
+ */
+ nbytes = NRLEAFDBT(data->size);
+ if ((u_int32_t)(h->upper - h->lower) < nbytes + sizeof(indx_t)) {
+ status = __bt_split(t, h, NULL, data, dflags, nbytes, idx);
+ if (status == RET_SUCCESS)
+ ++t->bt_nrecs;
+ return (status);
+ }
+
+ if (idx < (nxtindex = NEXTINDEX(h)))
+ memmove(h->linp + idx + 1, h->linp + idx,
+ (nxtindex - idx) * sizeof(indx_t));
+ h->lower += sizeof(indx_t);
+
+ h->linp[idx] = h->upper -= nbytes;
+ dest = (char *)h + h->upper;
+ WR_RLEAF(dest, data, dflags);
+
+ ++t->bt_nrecs;
+ F_SET(t, B_MODIFIED);
+ mpool_put(t->bt_mp, h, MPOOL_DIRTY);
+
+ return (RET_SUCCESS);
+}
diff --git a/lib/libc/db/recno/rec_search.c b/lib/libc/db/recno/rec_search.c
new file mode 100644
index 000000000000..8115e0f7db27
--- /dev/null
+++ b/lib/libc/db/recno/rec_search.c
@@ -0,0 +1,121 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)rec_search.c 8.4 (Berkeley) 7/14/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+#include <errno.h>
+#include <stdio.h>
+
+#include <db.h>
+#include "recno.h"
+
+/*
+ * __REC_SEARCH -- Search a btree for a key.
+ *
+ * Parameters:
+ * t: tree to search
+ * recno: key to find
+ * op: search operation
+ *
+ * Returns:
+ * EPG for matching record, if any, or the EPG for the location of the
+ * key, if it were inserted into the tree.
+ *
+ * Returns:
+ * The EPG for matching record, if any, or the EPG for the location
+ * of the key, if it were inserted into the tree, is entered into
+ * the bt_cur field of the tree. A pointer to the field is returned.
+ */
+EPG *
+__rec_search(BTREE *t, recno_t recno, enum SRCHOP op)
+{
+ indx_t idx;
+ PAGE *h;
+ EPGNO *parent;
+ RINTERNAL *r;
+ pgno_t pg;
+ indx_t top;
+ recno_t total;
+ int sverrno;
+
+ BT_CLR(t);
+ for (pg = P_ROOT, total = 0;;) {
+ if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
+ goto err;
+ if (h->flags & P_RLEAF) {
+ t->bt_cur.page = h;
+ t->bt_cur.index = recno - total;
+ return (&t->bt_cur);
+ }
+ for (idx = 0, top = NEXTINDEX(h);;) {
+ r = GETRINTERNAL(h, idx);
+ if (++idx == top || total + r->nrecs > recno)
+ break;
+ total += r->nrecs;
+ }
+
+ BT_PUSH(t, pg, idx - 1);
+
+ pg = r->pgno;
+ switch (op) {
+ case SDELETE:
+ --GETRINTERNAL(h, (idx - 1))->nrecs;
+ mpool_put(t->bt_mp, h, MPOOL_DIRTY);
+ break;
+ case SINSERT:
+ ++GETRINTERNAL(h, (idx - 1))->nrecs;
+ mpool_put(t->bt_mp, h, MPOOL_DIRTY);
+ break;
+ case SEARCH:
+ mpool_put(t->bt_mp, h, 0);
+ break;
+ }
+
+ }
+ /* Try and recover the tree. */
+err: sverrno = errno;
+ if (op != SEARCH)
+ while ((parent = BT_POP(t)) != NULL) {
+ if ((h = mpool_get(t->bt_mp, parent->pgno, 0)) == NULL)
+ break;
+ if (op == SINSERT)
+ --GETRINTERNAL(h, parent->index)->nrecs;
+ else
+ ++GETRINTERNAL(h, parent->index)->nrecs;
+ mpool_put(t->bt_mp, h, MPOOL_DIRTY);
+ }
+ errno = sverrno;
+ return (NULL);
+}
diff --git a/lib/libc/db/recno/rec_seq.c b/lib/libc/db/recno/rec_seq.c
new file mode 100644
index 000000000000..42d98d7bbe50
--- /dev/null
+++ b/lib/libc/db/recno/rec_seq.c
@@ -0,0 +1,127 @@
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+/* XXX use __SCCSID */
+static char sccsid[] __unused = "@(#)rec_seq.c 8.3 (Berkeley) 7/14/94";
+#endif /* not lint */
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <db.h>
+#include "recno.h"
+
+/*
+ * __REC_SEQ -- Recno sequential scan interface.
+ *
+ * Parameters:
+ * dbp: pointer to access method
+ * key: key for positioning and return value
+ * data: data return value
+ * flags: R_CURSOR, R_FIRST, R_LAST, R_NEXT, R_PREV.
+ *
+ * Returns:
+ * RET_ERROR, RET_SUCCESS or RET_SPECIAL if there's no next key.
+ */
+int
+__rec_seq(const DB *dbp, DBT *key, DBT *data, u_int flags)
+{
+ BTREE *t;
+ EPG *e;
+ recno_t nrec;
+ int status;
+
+ t = dbp->internal;
+
+ /* Toss any page pinned across calls. */
+ if (t->bt_pinned != NULL) {
+ mpool_put(t->bt_mp, t->bt_pinned, 0);
+ t->bt_pinned = NULL;
+ }
+
+ switch(flags) {
+ case R_CURSOR:
+ if ((nrec = *(recno_t *)key->data) == 0)
+ goto einval;
+ break;
+ case R_NEXT:
+ if (F_ISSET(&t->bt_cursor, CURS_INIT)) {
+ nrec = t->bt_cursor.rcursor + 1;
+ break;
+ }
+ /* FALLTHROUGH */
+ case R_FIRST:
+ nrec = 1;
+ break;
+ case R_PREV:
+ if (F_ISSET(&t->bt_cursor, CURS_INIT)) {
+ if ((nrec = t->bt_cursor.rcursor - 1) == 0)
+ return (RET_SPECIAL);
+ break;
+ }
+ /* FALLTHROUGH */
+ case R_LAST:
+ if (!F_ISSET(t, R_EOF | R_INMEM) &&
+ t->bt_irec(t, MAX_REC_NUMBER) == RET_ERROR)
+ return (RET_ERROR);
+ nrec = t->bt_nrecs;
+ break;
+ default:
+einval: errno = EINVAL;
+ return (RET_ERROR);
+ }
+
+ if (t->bt_nrecs == 0 || nrec > t->bt_nrecs) {
+ if (!F_ISSET(t, R_EOF | R_INMEM) &&
+ (status = t->bt_irec(t, nrec)) != RET_SUCCESS)
+ return (status);
+ if (t->bt_nrecs == 0 || nrec > t->bt_nrecs)
+ return (RET_SPECIAL);
+ }
+
+ if ((e = __rec_search(t, nrec - 1, SEARCH)) == NULL)
+ return (RET_ERROR);
+
+ F_SET(&t->bt_cursor, CURS_INIT);
+ t->bt_cursor.rcursor = nrec;
+
+ status = __rec_ret(t, e, nrec, key, data);
+ if (F_ISSET(t, B_DB_LOCK))
+ mpool_put(t->bt_mp, e->page, 0);
+ else
+ t->bt_pinned = e->page;
+ return (status);
+}
diff --git a/lib/libc/db/recno/rec_utils.c b/lib/libc/db/recno/rec_utils.c
new file mode 100644
index 000000000000..39285a545a51
--- /dev/null
+++ b/lib/libc/db/recno/rec_utils.c
@@ -0,0 +1,112 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)rec_utils.c 8.6 (Berkeley) 7/16/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <db.h>
+#include "recno.h"
+
+/*
+ * __rec_ret --
+ * Build return data.
+ *
+ * Parameters:
+ * t: tree
+ * e: key/data pair to be returned
+ * nrec: record number
+ * key: user's key structure
+ * data: user's data structure
+ *
+ * Returns:
+ * RET_SUCCESS, RET_ERROR.
+ */
+int
+__rec_ret(BTREE *t, EPG *e, recno_t nrec, DBT *key, DBT *data)
+{
+ RLEAF *rl;
+ void *p;
+
+ if (key == NULL)
+ goto dataonly;
+
+ /* We have to copy the key, it's not on the page. */
+ if (sizeof(recno_t) > t->bt_rkey.size) {
+ p = realloc(t->bt_rkey.data, sizeof(recno_t));
+ if (p == NULL)
+ return (RET_ERROR);
+ t->bt_rkey.data = p;
+ t->bt_rkey.size = sizeof(recno_t);
+ }
+ memmove(t->bt_rkey.data, &nrec, sizeof(recno_t));
+ key->size = sizeof(recno_t);
+ key->data = t->bt_rkey.data;
+
+dataonly:
+ if (data == NULL)
+ return (RET_SUCCESS);
+
+ /*
+ * We must copy big keys/data to make them contigous. Otherwise,
+ * leave the page pinned and don't copy unless the user specified
+ * concurrent access.
+ */
+ rl = GETRLEAF(e->page, e->index);
+ if (rl->flags & P_BIGDATA) {
+ if (__ovfl_get(t, rl->bytes,
+ &data->size, &t->bt_rdata.data, &t->bt_rdata.size))
+ return (RET_ERROR);
+ data->data = t->bt_rdata.data;
+ } else if (F_ISSET(t, B_DB_LOCK)) {
+ /* Use +1 in case the first record retrieved is 0 length. */
+ if (rl->dsize + 1 > t->bt_rdata.size) {
+ p = realloc(t->bt_rdata.data, rl->dsize + 1);
+ if (p == NULL)
+ return (RET_ERROR);
+ t->bt_rdata.data = p;
+ t->bt_rdata.size = rl->dsize + 1;
+ }
+ memmove(t->bt_rdata.data, rl->bytes, rl->dsize);
+ data->size = rl->dsize;
+ data->data = t->bt_rdata.data;
+ } else {
+ data->size = rl->dsize;
+ data->data = rl->bytes;
+ }
+ return (RET_SUCCESS);
+}
diff --git a/lib/libc/db/recno/recno.h b/lib/libc/db/recno/recno.h
new file mode 100644
index 000000000000..5c561703637a
--- /dev/null
+++ b/lib/libc/db/recno/recno.h
@@ -0,0 +1,36 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)recno.h 8.1 (Berkeley) 6/4/93
+ * $FreeBSD$
+ */
+
+enum SRCHOP { SDELETE, SINSERT, SEARCH}; /* Rec_search operation. */
+
+#include "../btree/btree.h"
+#include "extern.h"
diff --git a/lib/libc/db/test/Makefile b/lib/libc/db/test/Makefile
new file mode 100644
index 000000000000..712ad6258376
--- /dev/null
+++ b/lib/libc/db/test/Makefile
@@ -0,0 +1,24 @@
+# @(#)Makefile 8.15 (Berkeley) 7/28/94
+# $FreeBSD$
+
+PROG= dbtest
+OBJS= dbtest.o strerror.o
+
+# Uncomment the STAT line get hash and btree statistical use info. This
+# also forces ld to load the btree debug functions for use by gdb, which
+# is useful. The db library has to be compiled with -DSTATISTICS as well.
+INC= -I${PORTDIR}/include -I${PORTDIR}
+OORG= -g
+#STAT= -DSTATISTICS
+CFLAGS+=-D__DBINTERFACE_PRIVATE -DDEBUG ${STAT} ${OORG} ${INC}
+
+dbtest: ${OBJS} ${PORTDIR}/libdb.a
+ ${CC} -o ${.TARGET} ${OBJS} ${PORTDIR}/libdb.a
+
+strerror.o: ${PORTDIR}/clib/strerror.c
+ ${CC} -c ${PORTDIR}/clib/strerror.c
+
+clean:
+ rm -f dbtest.core gmon.out ${OBJS} ${PROG} t1 t2 t3
+
+${OBJS}: Makefile
diff --git a/lib/libc/db/test/README b/lib/libc/db/test/README
new file mode 100644
index 000000000000..0c0cd13d8fa0
--- /dev/null
+++ b/lib/libc/db/test/README
@@ -0,0 +1,74 @@
+# @(#)README 8.8 (Berkeley) 7/31/94
+
+To build this portably, try something like:
+
+ make PORTDIR="../PORT/MACH"
+
+where MACH is the machine, i.e. "sunos.4.1.1".
+
+To run the tests, enter "sh run.test". If your system dictionary isn't
+in /usr/share/dict/words, edit run.test to reflect the correct place.
+
+Fairly large files (the command files) are built in this directory during
+the test runs, and even larger files (the database files) are created in
+"/var/tmp". If the latter directory doesn't exist, set the environmental
+variable TMPDIR to a directory where the files can be built.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+The script file consists of lines with an initial character which is
+the command for that line, or an initial character indicating a key
+or data entry for a previous command.
+
+Legal command characters are as follows:
+
+c: compare a record
+ + must be followed by [kK][dD]; the data value in the database
+ associated with the specified key is compared to the specified
+ data value.
+e: echo a string
+ + writes out the rest of the line into the output file; if the
+ last character is not a carriage-return, a newline is appended.
+f: set the flags for the next command
+ + no value zero's the flags
+g: do a get command
+ + must be followed by [kK]
+ + writes out the retrieved data DBT.
+o [r]: dump [reverse]
+ + dump the database out, if 'r' is set, in reverse order.
+p: do a put command
+ + must be followed by [kK][dD]
+r: do a del command
+ + must be followed by [kK] unless R_CURSOR flag set.
+S: sync the database
+s: do a seq command
+ + must be followed by [kK] if R_CURSOR flag set.
+ + writes out the retrieved data DBT.
+
+Legal key/data characters are as follows:
+
+D [file]: data file
+ + set the current data value to the contents of the file
+d [data]:
+ + set the current key value to the contents of the line.
+K [file]: key file
+ + set the current key value to the contents of the file
+k [data]:
+ + set the current key value to the contents of the line.
+
+Blank lines, lines with leading white space, and lines with leading
+hash marks (#) are ignored.
+
+Options to dbtest are as follows:
+
+ -d: Set the DB_LOCK flag.
+ -f: Use the file argument as the database file.
+ -i: Use the rest of the argument to set elements in the info
+ structure. If the type is btree, then "-i cachesize=10240"
+ will set BTREEINFO.cachesize to 10240.
+ -o: The rest of the argument is the output file instead of
+ using stdout.
+ -s: Don't delete the database file before opening it, i.e.
+ use the database file from a previous run.
+
+Dbtest requires two arguments, the type of access "hash", "recno"
+or "btree", and the script name or "-" to indicate stdin.
diff --git a/lib/libc/db/test/btree.tests/main.c b/lib/libc/db/test/btree.tests/main.c
new file mode 100644
index 000000000000..ec17b580d169
--- /dev/null
+++ b/lib/libc/db/test/btree.tests/main.c
@@ -0,0 +1,763 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Mike Olson.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <fcntl.h>
+#include <db.h>
+#include <errno.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include "btree.h"
+
+typedef struct cmd_table {
+ char *cmd;
+ int nargs;
+ int rconv;
+ void (*func)(DB *, char **);
+ char *usage, *descrip;
+} cmd_table;
+
+int stopstop;
+DB *globaldb;
+
+void append(DB *, char **);
+void bstat(DB *, char **);
+void cursor(DB *, char **);
+void delcur(DB *, char **);
+void delete(DB *, char **);
+void dump(DB *, char **);
+void first(DB *, char **);
+void get(DB *, char **);
+void help(DB *, char **);
+void iafter(DB *, char **);
+void ibefore(DB *, char **);
+void icursor(DB *, char **);
+void insert(DB *, char **);
+void keydata(DBT *, DBT *);
+void last(DB *, char **);
+void list(DB *, char **);
+void load(DB *, char **);
+void mstat(DB *, char **);
+void next(DB *, char **);
+int parse(char *, char **, int);
+void previous(DB *, char **);
+void show(DB *, char **);
+void usage(void);
+void user(DB *);
+
+cmd_table commands[] = {
+ "?", 0, 0, help, "help", NULL,
+ "a", 2, 1, append, "append key def", "append key with data def",
+ "b", 0, 0, bstat, "bstat", "stat btree",
+ "c", 1, 1, cursor, "cursor word", "move cursor to word",
+ "delc", 0, 0, delcur, "delcur", "delete key the cursor references",
+ "dele", 1, 1, delete, "delete word", "delete word",
+ "d", 0, 0, dump, "dump", "dump database",
+ "f", 0, 0, first, "first", "move cursor to first record",
+ "g", 1, 1, get, "get key", "locate key",
+ "h", 0, 0, help, "help", "print command summary",
+ "ia", 2, 1, iafter, "iafter key data", "insert data after key",
+ "ib", 2, 1, ibefore, "ibefore key data", "insert data before key",
+ "ic", 2, 1, icursor, "icursor key data", "replace cursor",
+ "in", 2, 1, insert, "insert key def", "insert key with data def",
+ "la", 0, 0, last, "last", "move cursor to last record",
+ "li", 1, 1, list, "list file", "list to a file",
+ "loa", 1, 0, load, "load file", NULL,
+ "loc", 1, 1, get, "get key", NULL,
+ "m", 0, 0, mstat, "mstat", "stat memory pool",
+ "n", 0, 0, next, "next", "move cursor forward one record",
+ "p", 0, 0, previous, "previous", "move cursor back one record",
+ "q", 0, 0, NULL, "quit", "quit",
+ "sh", 1, 0, show, "show page", "dump a page",
+ { NULL },
+};
+
+int recno; /* use record numbers */
+char *dict = "words"; /* default dictionary */
+char *progname;
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int c;
+ DB *db;
+ BTREEINFO b;
+
+ progname = *argv;
+
+ b.flags = 0;
+ b.cachesize = 0;
+ b.maxkeypage = 0;
+ b.minkeypage = 0;
+ b.psize = 0;
+ b.compare = NULL;
+ b.prefix = NULL;
+ b.lorder = 0;
+
+ while ((c = getopt(argc, argv, "bc:di:lp:ru")) != -1) {
+ switch (c) {
+ case 'b':
+ b.lorder = BIG_ENDIAN;
+ break;
+ case 'c':
+ b.cachesize = atoi(optarg);
+ break;
+ case 'd':
+ b.flags |= R_DUP;
+ break;
+ case 'i':
+ dict = optarg;
+ break;
+ case 'l':
+ b.lorder = LITTLE_ENDIAN;
+ break;
+ case 'p':
+ b.psize = atoi(optarg);
+ break;
+ case 'r':
+ recno = 1;
+ break;
+ case 'u':
+ b.flags = 0;
+ break;
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (recno)
+ db = dbopen(*argv == NULL ? NULL : *argv, O_RDWR,
+ 0, DB_RECNO, NULL);
+ else
+ db = dbopen(*argv == NULL ? NULL : *argv, O_CREAT|O_RDWR,
+ 0600, DB_BTREE, &b);
+
+ if (db == NULL) {
+ (void)fprintf(stderr, "dbopen: %s\n", strerror(errno));
+ exit(1);
+ }
+ globaldb = db;
+ user(db);
+ exit(0);
+ /* NOTREACHED */
+}
+
+void
+user(db)
+ DB *db;
+{
+ FILE *ifp;
+ int argc, i, last;
+ char *lbuf, *argv[4], buf[512];
+
+ if ((ifp = fopen("/dev/tty", "r")) == NULL) {
+ (void)fprintf(stderr,
+ "/dev/tty: %s\n", strerror(errno));
+ exit(1);
+ }
+ for (last = 0;;) {
+ (void)printf("> ");
+ (void)fflush(stdout);
+ if ((lbuf = fgets(&buf[0], 512, ifp)) == NULL)
+ break;
+ if (lbuf[0] == '\n') {
+ i = last;
+ goto uselast;
+ }
+ lbuf[strlen(lbuf) - 1] = '\0';
+
+ if (lbuf[0] == 'q')
+ break;
+
+ argc = parse(lbuf, &argv[0], 3);
+ if (argc == 0)
+ continue;
+
+ for (i = 0; commands[i].cmd != NULL; i++)
+ if (strncmp(commands[i].cmd, argv[0],
+ strlen(commands[i].cmd)) == 0)
+ break;
+
+ if (commands[i].cmd == NULL) {
+ (void)fprintf(stderr,
+ "%s: command unknown ('help' for help)\n", lbuf);
+ continue;
+ }
+
+ if (commands[i].nargs != argc - 1) {
+ (void)fprintf(stderr, "usage: %s\n", commands[i].usage);
+ continue;
+ }
+
+ if (recno && commands[i].rconv) {
+ static recno_t nlong;
+ nlong = atoi(argv[1]);
+ argv[1] = (char *)&nlong;
+ }
+uselast: last = i;
+ (*commands[i].func)(db, argv);
+ }
+ if ((db->sync)(db) == RET_ERROR)
+ perror("dbsync");
+ else if ((db->close)(db) == RET_ERROR)
+ perror("dbclose");
+}
+
+int
+parse(lbuf, argv, maxargc)
+ char *lbuf, **argv;
+ int maxargc;
+{
+ int argc = 0;
+ char *c;
+
+ c = lbuf;
+ while (isspace(*c))
+ c++;
+ while (*c != '\0' && argc < maxargc) {
+ *argv++ = c;
+ argc++;
+ while (!isspace(*c) && *c != '\0') {
+ c++;
+ }
+ while (isspace(*c))
+ *c++ = '\0';
+ }
+ return (argc);
+}
+
+void
+append(db, argv)
+ DB *db;
+ char **argv;
+{
+ DBT key, data;
+ int status;
+
+ if (!recno) {
+ (void)fprintf(stderr,
+ "append only available for recno db's.\n");
+ return;
+ }
+ key.data = argv[1];
+ key.size = sizeof(recno_t);
+ data.data = argv[2];
+ data.size = strlen(data.data);
+ status = (db->put)(db, &key, &data, R_APPEND);
+ switch (status) {
+ case RET_ERROR:
+ perror("append/put");
+ break;
+ case RET_SPECIAL:
+ (void)printf("%s (duplicate key)\n", argv[1]);
+ break;
+ case RET_SUCCESS:
+ break;
+ }
+}
+
+void
+cursor(db, argv)
+ DB *db;
+ char **argv;
+{
+ DBT data, key;
+ int status;
+
+ key.data = argv[1];
+ if (recno)
+ key.size = sizeof(recno_t);
+ else
+ key.size = strlen(argv[1]) + 1;
+ status = (*db->seq)(db, &key, &data, R_CURSOR);
+ switch (status) {
+ case RET_ERROR:
+ perror("cursor/seq");
+ break;
+ case RET_SPECIAL:
+ (void)printf("key not found\n");
+ break;
+ case RET_SUCCESS:
+ keydata(&key, &data);
+ break;
+ }
+}
+
+void
+delcur(db, argv)
+ DB *db;
+ char **argv;
+{
+ int status;
+
+ status = (*db->del)(db, NULL, R_CURSOR);
+
+ if (status == RET_ERROR)
+ perror("delcur/del");
+}
+
+void
+delete(db, argv)
+ DB *db;
+ char **argv;
+{
+ DBT key;
+ int status;
+
+ key.data = argv[1];
+ if (recno)
+ key.size = sizeof(recno_t);
+ else
+ key.size = strlen(argv[1]) + 1;
+
+ status = (*db->del)(db, &key, 0);
+ switch (status) {
+ case RET_ERROR:
+ perror("delete/del");
+ break;
+ case RET_SPECIAL:
+ (void)printf("key not found\n");
+ break;
+ case RET_SUCCESS:
+ break;
+ }
+}
+
+void
+dump(db, argv)
+ DB *db;
+ char **argv;
+{
+ __bt_dump(db);
+}
+
+void
+first(db, argv)
+ DB *db;
+ char **argv;
+{
+ DBT data, key;
+ int status;
+
+ status = (*db->seq)(db, &key, &data, R_FIRST);
+
+ switch (status) {
+ case RET_ERROR:
+ perror("first/seq");
+ break;
+ case RET_SPECIAL:
+ (void)printf("no more keys\n");
+ break;
+ case RET_SUCCESS:
+ keydata(&key, &data);
+ break;
+ }
+}
+
+void
+get(db, argv)
+ DB *db;
+ char **argv;
+{
+ DBT data, key;
+ int status;
+
+ key.data = argv[1];
+ if (recno)
+ key.size = sizeof(recno_t);
+ else
+ key.size = strlen(argv[1]) + 1;
+
+ status = (*db->get)(db, &key, &data, 0);
+
+ switch (status) {
+ case RET_ERROR:
+ perror("get/get");
+ break;
+ case RET_SPECIAL:
+ (void)printf("key not found\n");
+ break;
+ case RET_SUCCESS:
+ keydata(&key, &data);
+ break;
+ }
+}
+
+void
+help(db, argv)
+ DB *db;
+ char **argv;
+{
+ int i;
+
+ for (i = 0; commands[i].cmd; i++)
+ if (commands[i].descrip)
+ (void)printf("%s: %s\n",
+ commands[i].usage, commands[i].descrip);
+}
+
+void
+iafter(db, argv)
+ DB *db;
+ char **argv;
+{
+ DBT key, data;
+ int status;
+
+ if (!recno) {
+ (void)fprintf(stderr,
+ "iafter only available for recno db's.\n");
+ return;
+ }
+ key.data = argv[1];
+ key.size = sizeof(recno_t);
+ data.data = argv[2];
+ data.size = strlen(data.data);
+ status = (db->put)(db, &key, &data, R_IAFTER);
+ switch (status) {
+ case RET_ERROR:
+ perror("iafter/put");
+ break;
+ case RET_SPECIAL:
+ (void)printf("%s (duplicate key)\n", argv[1]);
+ break;
+ case RET_SUCCESS:
+ break;
+ }
+}
+
+void
+ibefore(db, argv)
+ DB *db;
+ char **argv;
+{
+ DBT key, data;
+ int status;
+
+ if (!recno) {
+ (void)fprintf(stderr,
+ "ibefore only available for recno db's.\n");
+ return;
+ }
+ key.data = argv[1];
+ key.size = sizeof(recno_t);
+ data.data = argv[2];
+ data.size = strlen(data.data);
+ status = (db->put)(db, &key, &data, R_IBEFORE);
+ switch (status) {
+ case RET_ERROR:
+ perror("ibefore/put");
+ break;
+ case RET_SPECIAL:
+ (void)printf("%s (duplicate key)\n", argv[1]);
+ break;
+ case RET_SUCCESS:
+ break;
+ }
+}
+
+void
+icursor(db, argv)
+ DB *db;
+ char **argv;
+{
+ int status;
+ DBT data, key;
+
+ key.data = argv[1];
+ if (recno)
+ key.size = sizeof(recno_t);
+ else
+ key.size = strlen(argv[1]) + 1;
+ data.data = argv[2];
+ data.size = strlen(argv[2]) + 1;
+
+ status = (*db->put)(db, &key, &data, R_CURSOR);
+ switch (status) {
+ case RET_ERROR:
+ perror("icursor/put");
+ break;
+ case RET_SPECIAL:
+ (void)printf("%s (duplicate key)\n", argv[1]);
+ break;
+ case RET_SUCCESS:
+ break;
+ }
+}
+
+void
+insert(db, argv)
+ DB *db;
+ char **argv;
+{
+ int status;
+ DBT data, key;
+
+ key.data = argv[1];
+ if (recno)
+ key.size = sizeof(recno_t);
+ else
+ key.size = strlen(argv[1]) + 1;
+ data.data = argv[2];
+ data.size = strlen(argv[2]) + 1;
+
+ status = (*db->put)(db, &key, &data, R_NOOVERWRITE);
+ switch (status) {
+ case RET_ERROR:
+ perror("insert/put");
+ break;
+ case RET_SPECIAL:
+ (void)printf("%s (duplicate key)\n", argv[1]);
+ break;
+ case RET_SUCCESS:
+ break;
+ }
+}
+
+void
+last(db, argv)
+ DB *db;
+ char **argv;
+{
+ DBT data, key;
+ int status;
+
+ status = (*db->seq)(db, &key, &data, R_LAST);
+
+ switch (status) {
+ case RET_ERROR:
+ perror("last/seq");
+ break;
+ case RET_SPECIAL:
+ (void)printf("no more keys\n");
+ break;
+ case RET_SUCCESS:
+ keydata(&key, &data);
+ break;
+ }
+}
+
+void
+list(db, argv)
+ DB *db;
+ char **argv;
+{
+ DBT data, key;
+ FILE *fp;
+ int status;
+
+ if ((fp = fopen(argv[1], "w")) == NULL) {
+ (void)fprintf(stderr, "%s: %s\n", argv[1], strerror(errno));
+ return;
+ }
+ status = (*db->seq)(db, &key, &data, R_FIRST);
+ while (status == RET_SUCCESS) {
+ (void)fprintf(fp, "%s\n", key.data);
+ status = (*db->seq)(db, &key, &data, R_NEXT);
+ }
+ if (status == RET_ERROR)
+ perror("list/seq");
+}
+
+DB *BUGdb;
+void
+load(db, argv)
+ DB *db;
+ char **argv;
+{
+ char *p, *t;
+ FILE *fp;
+ DBT data, key;
+ recno_t cnt;
+ size_t len;
+ int status;
+ char *lp, buf[16 * 1024];
+
+ BUGdb = db;
+ if ((fp = fopen(argv[1], "r")) == NULL) {
+ (void)fprintf(stderr, "%s: %s\n", argv[1], strerror(errno));
+ return;
+ }
+ (void)printf("loading %s...\n", argv[1]);
+
+ for (cnt = 1; (lp = fgetline(fp, &len)) != NULL; ++cnt) {
+ if (recno) {
+ key.data = &cnt;
+ key.size = sizeof(recno_t);
+ data.data = lp;
+ data.size = len + 1;
+ } else {
+ key.data = lp;
+ key.size = len + 1;
+ for (p = lp + len - 1, t = buf; p >= lp; *t++ = *p--);
+ *t = '\0';
+ data.data = buf;
+ data.size = len + 1;
+ }
+
+ status = (*db->put)(db, &key, &data, R_NOOVERWRITE);
+ switch (status) {
+ case RET_ERROR:
+ perror("load/put");
+ exit(1);
+ case RET_SPECIAL:
+ if (recno)
+ (void)fprintf(stderr,
+ "duplicate: %ld {%s}\n", cnt, data.data);
+ else
+ (void)fprintf(stderr,
+ "duplicate: %ld {%s}\n", cnt, key.data);
+ exit(1);
+ case RET_SUCCESS:
+ break;
+ }
+ }
+ (void)fclose(fp);
+}
+
+void
+next(db, argv)
+ DB *db;
+ char **argv;
+{
+ DBT data, key;
+ int status;
+
+ status = (*db->seq)(db, &key, &data, R_NEXT);
+
+ switch (status) {
+ case RET_ERROR:
+ perror("next/seq");
+ break;
+ case RET_SPECIAL:
+ (void)printf("no more keys\n");
+ break;
+ case RET_SUCCESS:
+ keydata(&key, &data);
+ break;
+ }
+}
+
+void
+previous(db, argv)
+ DB *db;
+ char **argv;
+{
+ DBT data, key;
+ int status;
+
+ status = (*db->seq)(db, &key, &data, R_PREV);
+
+ switch (status) {
+ case RET_ERROR:
+ perror("previous/seq");
+ break;
+ case RET_SPECIAL:
+ (void)printf("no more keys\n");
+ break;
+ case RET_SUCCESS:
+ keydata(&key, &data);
+ break;
+ }
+}
+
+void
+show(db, argv)
+ DB *db;
+ char **argv;
+{
+ BTREE *t;
+ PAGE *h;
+ pgno_t pg;
+
+ pg = atoi(argv[1]);
+ t = db->internal;
+ if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL) {
+ (void)printf("getpage of %ld failed\n", pg);
+ return;
+ }
+ if (pg == 0)
+ __bt_dmpage(h);
+ else
+ __bt_dpage(h);
+ mpool_put(t->bt_mp, h, 0);
+}
+
+void
+bstat(db, argv)
+ DB *db;
+ char **argv;
+{
+ (void)printf("BTREE\n");
+ __bt_stat(db);
+}
+
+void
+mstat(db, argv)
+ DB *db;
+ char **argv;
+{
+ (void)printf("MPOOL\n");
+ mpool_stat(((BTREE *)db->internal)->bt_mp);
+}
+
+void
+keydata(key, data)
+ DBT *key, *data;
+{
+ if (!recno && key->size > 0)
+ (void)printf("%s/", key->data);
+ if (data->size > 0)
+ (void)printf("%s", data->data);
+ (void)printf("\n");
+}
+
+void
+usage()
+{
+ (void)fprintf(stderr,
+ "usage: %s [-bdlu] [-c cache] [-i file] [-p page] [file]\n",
+ progname);
+ exit (1);
+}
diff --git a/lib/libc/db/test/dbtest.c b/lib/libc/db/test/dbtest.c
new file mode 100644
index 000000000000..7de3a5c6de80
--- /dev/null
+++ b/lib/libc/db/test/dbtest.c
@@ -0,0 +1,738 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1992, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)dbtest.c 8.17 (Berkeley) 9/1/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <db.h>
+
+enum S { COMMAND, COMPARE, GET, PUT, REMOVE, SEQ, SEQFLAG, KEY, DATA };
+
+void compare(DBT *, DBT *);
+DBTYPE dbtype(char *);
+void dump(DB *, int);
+void err(const char *, ...) __printflike(1, 2);
+void get(DB *, DBT *);
+void getdata(DB *, DBT *, DBT *);
+void put(DB *, DBT *, DBT *);
+void rem(DB *, DBT *);
+char *sflags(int);
+void synk(DB *);
+void *rfile(char *, size_t *);
+void seq(DB *, DBT *);
+u_int setflags(char *);
+void *setinfo(DBTYPE, char *);
+void usage(void);
+void *xmalloc(char *, size_t);
+
+DBTYPE type; /* Database type. */
+void *infop; /* Iflags. */
+u_long lineno; /* Current line in test script. */
+u_int flags; /* Current DB flags. */
+int ofd = STDOUT_FILENO; /* Standard output fd. */
+
+DB *XXdbp; /* Global for gdb. */
+int XXlineno; /* Fast breakpoint for gdb. */
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ extern int optind;
+ extern char *optarg;
+ enum S command, state;
+ DB *dbp;
+ DBT data, key, keydata;
+ size_t len;
+ int ch, oflags, sflag;
+ char *fname, *infoarg, *p, *t, buf[8 * 1024];
+
+ infoarg = NULL;
+ fname = NULL;
+ oflags = O_CREAT | O_RDWR;
+ sflag = 0;
+ while ((ch = getopt(argc, argv, "f:i:lo:s")) != -1)
+ switch (ch) {
+ case 'f':
+ fname = optarg;
+ break;
+ case 'i':
+ infoarg = optarg;
+ break;
+ case 'l':
+ oflags |= DB_LOCK;
+ break;
+ case 'o':
+ if ((ofd = open(optarg,
+ O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
+ err("%s: %s", optarg, strerror(errno));
+ break;
+ case 's':
+ sflag = 1;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc != 2)
+ usage();
+
+ /* Set the type. */
+ type = dbtype(*argv++);
+
+ /* Open the descriptor file. */
+ if (strcmp(*argv, "-") && freopen(*argv, "r", stdin) == NULL)
+ err("%s: %s", *argv, strerror(errno));
+
+ /* Set up the db structure as necessary. */
+ if (infoarg == NULL)
+ infop = NULL;
+ else
+ for (p = strtok(infoarg, ",\t "); p != NULL;
+ p = strtok(0, ",\t "))
+ if (*p != '\0')
+ infop = setinfo(type, p);
+
+ /*
+ * Open the DB. Delete any preexisting copy, you almost never
+ * want it around, and it often screws up tests.
+ */
+ if (fname == NULL) {
+ p = getenv("TMPDIR");
+ if (p == NULL)
+ p = "/var/tmp";
+ (void)snprintf(buf, sizeof(buf), "%s/__dbtest", p);
+ fname = buf;
+ (void)unlink(buf);
+ } else if (!sflag)
+ (void)unlink(fname);
+
+ if ((dbp = dbopen(fname,
+ oflags, S_IRUSR | S_IWUSR, type, infop)) == NULL)
+ err("dbopen: %s", strerror(errno));
+ XXdbp = dbp;
+
+ state = COMMAND;
+ for (lineno = 1;
+ (p = fgets(buf, sizeof(buf), stdin)) != NULL; ++lineno) {
+ /* Delete the newline, displaying the key/data is easier. */
+ if (ofd == STDOUT_FILENO && (t = strchr(p, '\n')) != NULL)
+ *t = '\0';
+ if ((len = strlen(buf)) == 0 || isspace(*p) || *p == '#')
+ continue;
+
+ /* Convenient gdb break point. */
+ if (XXlineno == lineno)
+ XXlineno = 1;
+ switch (*p) {
+ case 'c': /* compare */
+ if (state != COMMAND)
+ err("line %lu: not expecting command", lineno);
+ state = KEY;
+ command = COMPARE;
+ break;
+ case 'e': /* echo */
+ if (state != COMMAND)
+ err("line %lu: not expecting command", lineno);
+ /* Don't display the newline, if CR at EOL. */
+ if (p[len - 2] == '\r')
+ --len;
+ if (write(ofd, p + 1, len - 1) != len - 1 ||
+ write(ofd, "\n", 1) != 1)
+ err("write: %s", strerror(errno));
+ break;
+ case 'g': /* get */
+ if (state != COMMAND)
+ err("line %lu: not expecting command", lineno);
+ state = KEY;
+ command = GET;
+ break;
+ case 'p': /* put */
+ if (state != COMMAND)
+ err("line %lu: not expecting command", lineno);
+ state = KEY;
+ command = PUT;
+ break;
+ case 'r': /* remove */
+ if (state != COMMAND)
+ err("line %lu: not expecting command", lineno);
+ if (flags == R_CURSOR) {
+ rem(dbp, &key);
+ state = COMMAND;
+ } else {
+ state = KEY;
+ command = REMOVE;
+ }
+ break;
+ case 'S': /* sync */
+ if (state != COMMAND)
+ err("line %lu: not expecting command", lineno);
+ synk(dbp);
+ state = COMMAND;
+ break;
+ case 's': /* seq */
+ if (state != COMMAND)
+ err("line %lu: not expecting command", lineno);
+ if (flags == R_CURSOR) {
+ state = KEY;
+ command = SEQ;
+ } else
+ seq(dbp, &key);
+ break;
+ case 'f':
+ flags = setflags(p + 1);
+ break;
+ case 'D': /* data file */
+ if (state != DATA)
+ err("line %lu: not expecting data", lineno);
+ data.data = rfile(p + 1, &data.size);
+ goto ldata;
+ case 'd': /* data */
+ if (state != DATA)
+ err("line %lu: not expecting data", lineno);
+ data.data = xmalloc(p + 1, len - 1);
+ data.size = len - 1;
+ldata: switch (command) {
+ case COMPARE:
+ compare(&keydata, &data);
+ break;
+ case PUT:
+ put(dbp, &key, &data);
+ break;
+ default:
+ err("line %lu: command doesn't take data",
+ lineno);
+ }
+ if (type != DB_RECNO)
+ free(key.data);
+ free(data.data);
+ state = COMMAND;
+ break;
+ case 'K': /* key file */
+ if (state != KEY)
+ err("line %lu: not expecting a key", lineno);
+ if (type == DB_RECNO)
+ err("line %lu: 'K' not available for recno",
+ lineno);
+ key.data = rfile(p + 1, &key.size);
+ goto lkey;
+ case 'k': /* key */
+ if (state != KEY)
+ err("line %lu: not expecting a key", lineno);
+ if (type == DB_RECNO) {
+ static recno_t recno;
+ recno = atoi(p + 1);
+ key.data = &recno;
+ key.size = sizeof(recno);
+ } else {
+ key.data = xmalloc(p + 1, len - 1);
+ key.size = len - 1;
+ }
+lkey: switch (command) {
+ case COMPARE:
+ getdata(dbp, &key, &keydata);
+ state = DATA;
+ break;
+ case GET:
+ get(dbp, &key);
+ if (type != DB_RECNO)
+ free(key.data);
+ state = COMMAND;
+ break;
+ case PUT:
+ state = DATA;
+ break;
+ case REMOVE:
+ rem(dbp, &key);
+ if ((type != DB_RECNO) && (flags != R_CURSOR))
+ free(key.data);
+ state = COMMAND;
+ break;
+ case SEQ:
+ seq(dbp, &key);
+ if ((type != DB_RECNO) && (flags != R_CURSOR))
+ free(key.data);
+ state = COMMAND;
+ break;
+ default:
+ err("line %lu: command doesn't take a key",
+ lineno);
+ }
+ break;
+ case 'o':
+ dump(dbp, p[1] == 'r');
+ break;
+ default:
+ err("line %lu: %s: unknown command character",
+ lineno, p);
+ }
+ }
+#ifdef STATISTICS
+ /*
+ * -l must be used (DB_LOCK must be set) for this to be
+ * used, otherwise a page will be locked and it will fail.
+ */
+ if (type == DB_BTREE && oflags & DB_LOCK)
+ __bt_stat(dbp);
+#endif
+ if (dbp->close(dbp))
+ err("db->close: %s", strerror(errno));
+ (void)close(ofd);
+ exit(0);
+}
+
+#define NOOVERWRITE "put failed, would overwrite key\n"
+
+void
+compare(db1, db2)
+ DBT *db1, *db2;
+{
+ size_t len;
+ u_char *p1, *p2;
+
+ if (db1->size != db2->size)
+ printf("compare failed: key->data len %lu != data len %lu\n",
+ db1->size, db2->size);
+
+ len = MIN(db1->size, db2->size);
+ for (p1 = db1->data, p2 = db2->data; len--;)
+ if (*p1++ != *p2++) {
+ printf("compare failed at offset %d\n",
+ p1 - (u_char *)db1->data);
+ break;
+ }
+}
+
+void
+get(dbp, kp)
+ DB *dbp;
+ DBT *kp;
+{
+ DBT data;
+
+ switch (dbp->get(dbp, kp, &data, flags)) {
+ case 0:
+ (void)write(ofd, data.data, data.size);
+ if (ofd == STDOUT_FILENO)
+ (void)write(ofd, "\n", 1);
+ break;
+ case -1:
+ err("line %lu: get: %s", lineno, strerror(errno));
+ /* NOTREACHED */
+ case 1:
+#define NOSUCHKEY "get failed, no such key\n"
+ if (ofd != STDOUT_FILENO)
+ (void)write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1);
+ else
+ (void)fprintf(stderr, "%d: %.*s: %s",
+ lineno, MIN(kp->size, 20), kp->data, NOSUCHKEY);
+#undef NOSUCHKEY
+ break;
+ }
+}
+
+void
+getdata(dbp, kp, dp)
+ DB *dbp;
+ DBT *kp, *dp;
+{
+ switch (dbp->get(dbp, kp, dp, flags)) {
+ case 0:
+ return;
+ case -1:
+ err("line %lu: getdata: %s", lineno, strerror(errno));
+ /* NOTREACHED */
+ case 1:
+ err("line %lu: getdata failed, no such key", lineno);
+ /* NOTREACHED */
+ }
+}
+
+void
+put(dbp, kp, dp)
+ DB *dbp;
+ DBT *kp, *dp;
+{
+ switch (dbp->put(dbp, kp, dp, flags)) {
+ case 0:
+ break;
+ case -1:
+ err("line %lu: put: %s", lineno, strerror(errno));
+ /* NOTREACHED */
+ case 1:
+ (void)write(ofd, NOOVERWRITE, sizeof(NOOVERWRITE) - 1);
+ break;
+ }
+}
+
+void
+rem(dbp, kp)
+ DB *dbp;
+ DBT *kp;
+{
+ switch (dbp->del(dbp, kp, flags)) {
+ case 0:
+ break;
+ case -1:
+ err("line %lu: rem: %s", lineno, strerror(errno));
+ /* NOTREACHED */
+ case 1:
+#define NOSUCHKEY "rem failed, no such key\n"
+ if (ofd != STDOUT_FILENO)
+ (void)write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1);
+ else if (flags != R_CURSOR)
+ (void)fprintf(stderr, "%d: %.*s: %s",
+ lineno, MIN(kp->size, 20), kp->data, NOSUCHKEY);
+ else
+ (void)fprintf(stderr,
+ "%d: rem of cursor failed\n", lineno);
+#undef NOSUCHKEY
+ break;
+ }
+}
+
+void
+synk(dbp)
+ DB *dbp;
+{
+ switch (dbp->sync(dbp, flags)) {
+ case 0:
+ break;
+ case -1:
+ err("line %lu: synk: %s", lineno, strerror(errno));
+ /* NOTREACHED */
+ }
+}
+
+void
+seq(dbp, kp)
+ DB *dbp;
+ DBT *kp;
+{
+ DBT data;
+
+ switch (dbp->seq(dbp, kp, &data, flags)) {
+ case 0:
+ (void)write(ofd, data.data, data.size);
+ if (ofd == STDOUT_FILENO)
+ (void)write(ofd, "\n", 1);
+ break;
+ case -1:
+ err("line %lu: seq: %s", lineno, strerror(errno));
+ /* NOTREACHED */
+ case 1:
+#define NOSUCHKEY "seq failed, no such key\n"
+ if (ofd != STDOUT_FILENO)
+ (void)write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1);
+ else if (flags == R_CURSOR)
+ (void)fprintf(stderr, "%d: %.*s: %s",
+ lineno, MIN(kp->size, 20), kp->data, NOSUCHKEY);
+ else
+ (void)fprintf(stderr,
+ "%d: seq (%s) failed\n", lineno, sflags(flags));
+#undef NOSUCHKEY
+ break;
+ }
+}
+
+void
+dump(dbp, rev)
+ DB *dbp;
+ int rev;
+{
+ DBT key, data;
+ int flags, nflags;
+
+ if (rev) {
+ flags = R_LAST;
+ nflags = R_PREV;
+ } else {
+ flags = R_FIRST;
+ nflags = R_NEXT;
+ }
+ for (;; flags = nflags)
+ switch (dbp->seq(dbp, &key, &data, flags)) {
+ case 0:
+ (void)write(ofd, data.data, data.size);
+ if (ofd == STDOUT_FILENO)
+ (void)write(ofd, "\n", 1);
+ break;
+ case 1:
+ goto done;
+ case -1:
+ err("line %lu: (dump) seq: %s",
+ lineno, strerror(errno));
+ /* NOTREACHED */
+ }
+done: return;
+}
+
+u_int
+setflags(s)
+ char *s;
+{
+ char *p, *index();
+
+ for (; isspace(*s); ++s);
+ if (*s == '\n' || *s == '\0')
+ return (0);
+ if ((p = index(s, '\n')) != NULL)
+ *p = '\0';
+ if (!strcmp(s, "R_CURSOR")) return (R_CURSOR);
+ if (!strcmp(s, "R_FIRST")) return (R_FIRST);
+ if (!strcmp(s, "R_IAFTER")) return (R_IAFTER);
+ if (!strcmp(s, "R_IBEFORE")) return (R_IBEFORE);
+ if (!strcmp(s, "R_LAST")) return (R_LAST);
+ if (!strcmp(s, "R_NEXT")) return (R_NEXT);
+ if (!strcmp(s, "R_NOOVERWRITE")) return (R_NOOVERWRITE);
+ if (!strcmp(s, "R_PREV")) return (R_PREV);
+ if (!strcmp(s, "R_SETCURSOR")) return (R_SETCURSOR);
+
+ err("line %lu: %s: unknown flag", lineno, s);
+ /* NOTREACHED */
+}
+
+char *
+sflags(flags)
+ int flags;
+{
+ switch (flags) {
+ case R_CURSOR: return ("R_CURSOR");
+ case R_FIRST: return ("R_FIRST");
+ case R_IAFTER: return ("R_IAFTER");
+ case R_IBEFORE: return ("R_IBEFORE");
+ case R_LAST: return ("R_LAST");
+ case R_NEXT: return ("R_NEXT");
+ case R_NOOVERWRITE: return ("R_NOOVERWRITE");
+ case R_PREV: return ("R_PREV");
+ case R_SETCURSOR: return ("R_SETCURSOR");
+ }
+
+ return ("UNKNOWN!");
+}
+
+DBTYPE
+dbtype(s)
+ char *s;
+{
+ if (!strcmp(s, "btree"))
+ return (DB_BTREE);
+ if (!strcmp(s, "hash"))
+ return (DB_HASH);
+ if (!strcmp(s, "recno"))
+ return (DB_RECNO);
+ err("%s: unknown type (use btree, hash or recno)", s);
+ /* NOTREACHED */
+}
+
+void *
+setinfo(type, s)
+ DBTYPE type;
+ char *s;
+{
+ static BTREEINFO ib;
+ static HASHINFO ih;
+ static RECNOINFO rh;
+ char *eq, *index();
+
+ if ((eq = index(s, '=')) == NULL)
+ err("%s: illegal structure set statement", s);
+ *eq++ = '\0';
+ if (!isdigit(*eq))
+ err("%s: structure set statement must be a number", s);
+
+ switch (type) {
+ case DB_BTREE:
+ if (!strcmp("flags", s)) {
+ ib.flags = atoi(eq);
+ return (&ib);
+ }
+ if (!strcmp("cachesize", s)) {
+ ib.cachesize = atoi(eq);
+ return (&ib);
+ }
+ if (!strcmp("maxkeypage", s)) {
+ ib.maxkeypage = atoi(eq);
+ return (&ib);
+ }
+ if (!strcmp("minkeypage", s)) {
+ ib.minkeypage = atoi(eq);
+ return (&ib);
+ }
+ if (!strcmp("lorder", s)) {
+ ib.lorder = atoi(eq);
+ return (&ib);
+ }
+ if (!strcmp("psize", s)) {
+ ib.psize = atoi(eq);
+ return (&ib);
+ }
+ break;
+ case DB_HASH:
+ if (!strcmp("bsize", s)) {
+ ih.bsize = atoi(eq);
+ return (&ih);
+ }
+ if (!strcmp("ffactor", s)) {
+ ih.ffactor = atoi(eq);
+ return (&ih);
+ }
+ if (!strcmp("nelem", s)) {
+ ih.nelem = atoi(eq);
+ return (&ih);
+ }
+ if (!strcmp("cachesize", s)) {
+ ih.cachesize = atoi(eq);
+ return (&ih);
+ }
+ if (!strcmp("lorder", s)) {
+ ih.lorder = atoi(eq);
+ return (&ih);
+ }
+ break;
+ case DB_RECNO:
+ if (!strcmp("flags", s)) {
+ rh.flags = atoi(eq);
+ return (&rh);
+ }
+ if (!strcmp("cachesize", s)) {
+ rh.cachesize = atoi(eq);
+ return (&rh);
+ }
+ if (!strcmp("lorder", s)) {
+ rh.lorder = atoi(eq);
+ return (&rh);
+ }
+ if (!strcmp("reclen", s)) {
+ rh.reclen = atoi(eq);
+ return (&rh);
+ }
+ if (!strcmp("bval", s)) {
+ rh.bval = atoi(eq);
+ return (&rh);
+ }
+ if (!strcmp("psize", s)) {
+ rh.psize = atoi(eq);
+ return (&rh);
+ }
+ break;
+ }
+ err("%s: unknown structure value", s);
+ /* NOTREACHED */
+}
+
+void *
+rfile(name, lenp)
+ char *name;
+ size_t *lenp;
+{
+ struct stat sb;
+ void *p;
+ int fd;
+ char *np, *index();
+
+ for (; isspace(*name); ++name);
+ if ((np = index(name, '\n')) != NULL)
+ *np = '\0';
+ if ((fd = open(name, O_RDONLY, 0)) < 0 ||
+ fstat(fd, &sb))
+ err("%s: %s\n", name, strerror(errno));
+#ifdef NOT_PORTABLE
+ if (sb.st_size > (off_t)SIZE_T_MAX)
+ err("%s: %s\n", name, strerror(E2BIG));
+#endif
+ if ((p = (void *)malloc((u_int)sb.st_size)) == NULL)
+ err("%s", strerror(errno));
+ (void)read(fd, p, (int)sb.st_size);
+ *lenp = sb.st_size;
+ (void)close(fd);
+ return (p);
+}
+
+void *
+xmalloc(text, len)
+ char *text;
+ size_t len;
+{
+ void *p;
+
+ if ((p = (void *)malloc(len)) == NULL)
+ err("%s", strerror(errno));
+ memmove(p, text, len);
+ return (p);
+}
+
+void
+usage()
+{
+ (void)fprintf(stderr,
+ "usage: dbtest [-l] [-f file] [-i info] [-o file] type script\n");
+ exit(1);
+}
+
+#include <stdarg.h>
+
+void
+err(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ (void)fprintf(stderr, "dbtest: ");
+ (void)vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ (void)fprintf(stderr, "\n");
+ exit(1);
+ /* NOTREACHED */
+}
diff --git a/lib/libc/db/test/hash.tests/driver2.c b/lib/libc/db/test/hash.tests/driver2.c
new file mode 100644
index 000000000000..1c5a13093c74
--- /dev/null
+++ b/lib/libc/db/test/hash.tests/driver2.c
@@ -0,0 +1,112 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Margo Seltzer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1991, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)driver2.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Test driver, to try to tackle the large ugly-split problem.
+ */
+
+#include <sys/file.h>
+#include <stdio.h>
+#include "ndbm.h"
+
+int my_hash(key, len)
+ char *key;
+ int len;
+{
+ return(17); /* So I'm cruel... */
+}
+
+main(argc, argv)
+ int argc;
+{
+ DB *db;
+ DBT key, content;
+ char keybuf[2049];
+ char contentbuf[2049];
+ char buf[256];
+ int i;
+ HASHINFO info;
+
+ info.bsize = 1024;
+ info.ffactor = 5;
+ info.nelem = 1;
+ info.cachesize = NULL;
+#ifdef HASH_ID_PROGRAM_SPECIFIED
+ info.hash_id = HASH_ID_PROGRAM_SPECIFIED;
+ info.hash_func = my_hash;
+#else
+ info.hash = my_hash;
+#endif
+ info.lorder = 0;
+ if (!(db = dbopen("bigtest", O_RDWR | O_CREAT, 0644, DB_HASH, &info))) {
+ sprintf(buf, "dbopen: failed on file bigtest");
+ perror(buf);
+ exit(1);
+ }
+ srandom(17);
+ key.data = keybuf;
+ content.data = contentbuf;
+ bzero(keybuf, sizeof(keybuf));
+ bzero(contentbuf, sizeof(contentbuf));
+ for (i=1; i <= 500; i++) {
+ key.size = 128 + (random()&1023);
+ content.size = 128 + (random()&1023);
+/* printf("%d: Key size %d, data size %d\n", i, key.size,
+ content.size); */
+ sprintf(keybuf, "Key #%d", i);
+ sprintf(contentbuf, "Contents #%d", i);
+ if ((db->put)(db, &key, &content, R_NOOVERWRITE)) {
+ sprintf(buf, "dbm_store #%d", i);
+ perror(buf);
+ }
+ }
+ if ((db->close)(db)) {
+ perror("closing hash file");
+ exit(1);
+ }
+ exit(0);
+}
+
+
+
diff --git a/lib/libc/db/test/hash.tests/makedb.sh b/lib/libc/db/test/hash.tests/makedb.sh
new file mode 100644
index 000000000000..f28e281fd19c
--- /dev/null
+++ b/lib/libc/db/test/hash.tests/makedb.sh
@@ -0,0 +1,13 @@
+#!/bin/sh
+#
+# @(#)makedb.sh 8.1 (Berkeley) 6/4/93
+
+awk '{i++; print $0; print i;}' /usr/share/dict/words > WORDS
+ls /bin /usr/bin /usr/ucb /etc | egrep '^(...|....|.....|......)$' | \
+sort | uniq | \
+awk '{
+ printf "%s\n", $0
+ for (i = 0; i < 1000; i++)
+ printf "%s+", $0
+ printf "\n"
+}' > LONG.DATA
diff --git a/lib/libc/db/test/hash.tests/tcreat3.c b/lib/libc/db/test/hash.tests/tcreat3.c
new file mode 100644
index 000000000000..6ba3c07a8aa5
--- /dev/null
+++ b/lib/libc/db/test/hash.tests/tcreat3.c
@@ -0,0 +1,103 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Margo Seltzer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1991, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)tcreat3.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/file.h>
+#include <stdio.h>
+#include <db.h>
+
+#define INITIAL 25000
+#define MAXWORDS 25000 /* # of elements in search table */
+
+char wp1[8192];
+char wp2[8192];
+main(argc, argv)
+char **argv;
+{
+ DBT item, key;
+ DB *dbp;
+ HASHINFO ctl;
+ FILE *fp;
+ int trash;
+
+ int i = 0;
+
+ argv++;
+ ctl.hash = NULL;
+ ctl.bsize = atoi(*argv++);
+ ctl.ffactor = atoi(*argv++);
+ ctl.nelem = atoi(*argv++);
+ ctl.lorder = 0;
+ if (!(dbp = dbopen( "hashtest",
+ O_CREAT|O_TRUNC|O_RDWR, 0600, DB_HASH, &ctl))){
+ /* create table */
+ fprintf(stderr, "cannot create: hash table (size %d)\n",
+ INITIAL);
+ exit(1);
+ }
+
+ key.data = wp1;
+ item.data = wp2;
+ while ( fgets(wp1, 8192, stdin) &&
+ fgets(wp2, 8192, stdin) &&
+ i++ < MAXWORDS) {
+/*
+* put info in structure, and structure in the item
+*/
+ key.size = strlen(wp1);
+ item.size = strlen(wp2);
+
+/*
+ * enter key/data pair into the table
+ */
+ if ((dbp->put)(dbp, &key, &item, R_NOOVERWRITE) != NULL) {
+ fprintf(stderr, "cannot enter: key %s\n",
+ item.data);
+ exit(1);
+ }
+ }
+
+ (dbp->close)(dbp);
+ exit(0);
+}
diff --git a/lib/libc/db/test/hash.tests/tdel.c b/lib/libc/db/test/hash.tests/tdel.c
new file mode 100644
index 000000000000..1d7e424f7acc
--- /dev/null
+++ b/lib/libc/db/test/hash.tests/tdel.c
@@ -0,0 +1,120 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Margo Seltzer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1991, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)tdel.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/file.h>
+#include <db.h>
+#include <stdio.h>
+
+#define INITIAL 25000
+#define MAXWORDS 25000 /* # of elements in search table */
+
+/* Usage: thash pagesize fillfactor file */
+char wp1[8192];
+char wp2[8192];
+main(argc, argv)
+char **argv;
+{
+ DBT item, key;
+ DB *dbp;
+ HASHINFO ctl;
+ FILE *fp;
+ int stat;
+
+ int i = 0;
+
+ argv++;
+ ctl.nelem = INITIAL;
+ ctl.hash = NULL;
+ ctl.bsize = atoi(*argv++);
+ ctl.ffactor = atoi(*argv++);
+ ctl.cachesize = 1024 * 1024; /* 1 MEG */
+ ctl.lorder = 0;
+ argc -= 2;
+ if (!(dbp = dbopen( NULL, O_CREAT|O_RDWR, 0400, DB_HASH, &ctl))) {
+ /* create table */
+ fprintf(stderr, "cannot create: hash table size %d)\n",
+ INITIAL);
+ exit(1);
+ }
+
+ key.data = wp1;
+ item.data = wp2;
+ while ( fgets(wp1, 8192, stdin) &&
+ fgets(wp2, 8192, stdin) &&
+ i++ < MAXWORDS) {
+/*
+* put info in structure, and structure in the item
+*/
+ key.size = strlen(wp1);
+ item.size = strlen(wp2);
+
+/*
+ * enter key/data pair into the table
+ */
+ if ((dbp->put)(dbp, &key, &item, R_NOOVERWRITE) != NULL) {
+ fprintf(stderr, "cannot enter: key %s\n",
+ item.data);
+ exit(1);
+ }
+ }
+
+ if ( --argc ) {
+ fp = fopen ( argv[0], "r");
+ i = 0;
+ while ( fgets(wp1, 8192, fp) &&
+ fgets(wp2, 8192, fp) &&
+ i++ < MAXWORDS) {
+ key.size = strlen(wp1);
+ stat = (dbp->del)(dbp, &key, 0);
+ if (stat) {
+ fprintf ( stderr, "Error retrieving %s\n", key.data );
+ exit(1);
+ }
+ }
+ fclose(fp);
+ }
+ (dbp->close)(dbp);
+ exit(0);
+}
diff --git a/lib/libc/db/test/hash.tests/testit b/lib/libc/db/test/hash.tests/testit
new file mode 100644
index 000000000000..039457a9c4e4
--- /dev/null
+++ b/lib/libc/db/test/hash.tests/testit
@@ -0,0 +1,147 @@
+#!/bin/csh -f
+#
+# @(#)testit 8.1 (Berkeley) 6/4/93
+#
+
+echo ""
+echo "PAGE FILL "
+set name=WORDS
+ set i = 256
+ foreach j ( 11 14 21 )
+ thash4 $i $j 25000 65536 $name < $name
+ end
+ set i = 512
+ foreach j ( 21 28 43 )
+ thash4 $i $j 25000 65536 $name < $name
+ end
+ set i = 1024
+ foreach j ( 43 57 85 )
+ thash4 $i $j 25000 65536 $name < $name
+ end
+ set i = 2048
+ foreach j ( 85 114 171 )
+ thash4 $i $j 25000 65536 $name < $name
+ end
+ set i = 4096
+ foreach j ( 171 228 341 )
+ thash4 $i $j 25000 65536 $name < $name
+ end
+ set i = 8192
+ foreach j ( 341 455 683 )
+ thash4 $i $j 25000 65536 $name < $name
+ end
+ echo "PAGE FILL "
+ set i = 256
+ foreach j ( 11 14 21 )
+ echo "$i"_"$j"
+ tcreat3 $i $j 25000 $name < $name
+ tread2 65536 < $name
+ tverify $name < $name
+ tseq > /dev/null
+ tdel $i $j $name < $name
+ end
+ set i = 512
+ foreach j ( 21 28 43 )
+ echo "$i"_"$j"
+ tcreat3 $i $j 25000 $name < $name
+ tread2 65536 < $name
+ tverify $name < $name
+ tseq > /dev/null
+ tdel $i $j $name < $name
+ end
+ set i = 1024
+ foreach j ( 43 57 85 )
+ echo "$i"_"$j"
+ tcreat3 $i $j 25000 $name < $name
+ tread2 65536 < $name
+ tverify $name < $name
+ tseq > /dev/null
+ tdel $i $j $name < $name
+ end
+ set i = 2048
+ foreach j ( 85 114 171 )
+ echo "$i"_"$j"
+ tcreat3 $i $j 25000 $name < $name
+ tread2 65536 < $name
+ tverify $name < $name
+ tseq > /dev/null
+ tdel $i $j $name < $name
+ end
+ set i = 4096
+ foreach j ( 171 228 341 )
+ echo "$i"_"$j"
+ tcreat3 $i $j 25000 $name < $name
+ tread2 65536 < $name
+ tverify $name < $name
+ tseq > /dev/null
+ tdel $i $j $name < $name
+ end
+ set i = 8192
+ foreach j ( 341 455 683 )
+ echo "$i"_"$j"
+ tcreat3 $i $j 25000 $name < $name
+ tread2 65536 < $name
+ tverify $name < $name
+ tseq > /dev/null
+ tdel $i $j $name < $name
+ end
+set name=LONG.DATA
+ set i = 1024
+ foreach j ( 1 2 4 )
+ echo thash4 $i $j 600 65536 $name
+ thash4 $i $j 600 65536 $name < $name
+ end
+
+ set i = 2048
+ foreach j ( 1 2 4 )
+ echo thash4 $i $j 600 65536 $name
+ thash4 $i $j 600 65536 $name < $name
+ end
+ set i = 4096
+ foreach j ( 1 2 4 )
+ echo thash4 $i $j 600 65536 $name
+ thash4 $i $j 600 65536 $name < $name
+ end
+ set i = 8192
+ foreach j ( 2 4 8 )
+ echo thash4 $i $j 600 65536 $name
+ thash4 $i $j 600 65536 $name < $name
+ end
+ echo "PAGE FILL "
+ set i = 1024
+ foreach j ( 1 2 4 )
+ echo "$i"_"$j"
+ tcreat3 $i $j 600 $name < $name
+ tread2 65536 < $name
+ tverify $name < $name
+ tseq > /dev/null
+ tdel $i $j $name < $name
+ end
+ set i = 2048
+ foreach j ( 1 2 4 )
+ echo "$i"_"$j"
+ tcreat3 $i $j 600 $name < $name
+ tread2 65536 < $name
+ tverify $name < $name
+ tseq > /dev/null
+ tdel $i $j $name < $name
+ end
+ set i = 4096
+ foreach j ( 1 2 4 )
+ echo "$i"_"$j"
+ tcreat3 $i $j 600 $name < $name
+ tread2 65536 < $name
+ tverify $name < $name
+ tseq > /dev/null
+ tdel $i $j $name < $name
+ end
+ set i = 8192
+ foreach j ( 2 4 8 )
+ echo "$i"_"$j"
+ tcreat3 $i $j 600 $name < $name
+ tread2 65536 < $name
+ tverify $name < $name
+ tseq > /dev/null
+ tdel $i $j $name < $name
+ end
+driver2
diff --git a/lib/libc/db/test/hash.tests/thash4.c b/lib/libc/db/test/hash.tests/thash4.c
new file mode 100644
index 000000000000..02f6832ba423
--- /dev/null
+++ b/lib/libc/db/test/hash.tests/thash4.c
@@ -0,0 +1,130 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Margo Seltzer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1991, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)thash4.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/timeb.h>
+#include <stdio.h>
+#include <errno.h>
+#include <db.h>
+
+#define INITIAL 25000
+#define MAXWORDS 25000 /* # of elements in search table */
+
+/* Usage: thash pagesize fillfactor file */
+char wp1[8192];
+char wp2[8192];
+main(argc, argv)
+char **argv;
+{
+ DBT item, key, res;
+ DB *dbp;
+ HASHINFO ctl;
+ FILE *fp;
+ int stat;
+ time_t t;
+
+ int i = 0;
+
+ argv++;
+ ctl.hash = NULL;
+ ctl.bsize = atoi(*argv++);
+ ctl.ffactor = atoi(*argv++);
+ ctl.nelem = atoi(*argv++);
+ ctl.cachesize = atoi(*argv++);
+ ctl.lorder = 0;
+ if (!(dbp = dbopen( NULL, O_CREAT|O_RDWR, 0400, DB_HASH, &ctl))) {
+ /* create table */
+ fprintf(stderr, "cannot create: hash table size %d)\n",
+ INITIAL);
+ fprintf(stderr, "\terrno: %d\n", errno);
+ exit(1);
+ }
+
+ key.data = wp1;
+ item.data = wp2;
+ while ( fgets(wp1, 8192, stdin) &&
+ fgets(wp2, 8192, stdin) &&
+ i++ < MAXWORDS) {
+/*
+* put info in structure, and structure in the item
+*/
+ key.size = strlen(wp1);
+ item.size = strlen(wp2);
+
+/*
+ * enter key/data pair into the table
+ */
+ if ((dbp->put)(dbp, &key, &item, R_NOOVERWRITE) != NULL) {
+ fprintf(stderr, "cannot enter: key %s\n",
+ item.data);
+ fprintf(stderr, "\terrno: %d\n", errno);
+ exit(1);
+ }
+ }
+
+ if ( --argc ) {
+ fp = fopen ( argv[0], "r");
+ i = 0;
+ while ( fgets(wp1, 256, fp) &&
+ fgets(wp2, 8192, fp) &&
+ i++ < MAXWORDS) {
+
+ key.size = strlen(wp1);
+ stat = (dbp->get)(dbp, &key, &res, 0);
+ if (stat < 0 ) {
+ fprintf ( stderr, "Error retrieving %s\n", key.data );
+ fprintf(stderr, "\terrno: %d\n", errno);
+ exit(1);
+ } else if ( stat > 0 ) {
+ fprintf ( stderr, "%s not found\n", key.data );
+ fprintf(stderr, "\terrno: %d\n", errno);
+ exit(1);
+ }
+ }
+ fclose(fp);
+ }
+ dbp->close(dbp);
+ exit(0);
+}
diff --git a/lib/libc/db/test/hash.tests/tread2.c b/lib/libc/db/test/hash.tests/tread2.c
new file mode 100644
index 000000000000..fdcaab3100d1
--- /dev/null
+++ b/lib/libc/db/test/hash.tests/tread2.c
@@ -0,0 +1,103 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Margo Seltzer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1991, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)tread2.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/file.h>
+#include <stdio.h>
+#include <db.h>
+
+#define INITIAL 25000
+#define MAXWORDS 25000 /* # of elements in search table */
+
+typedef struct { /* info to be stored */
+ int num, siz;
+} info;
+
+char wp1[8192];
+char wp2[8192];
+main(argc, argv)
+char **argv;
+{
+ DBT item, key, res;
+ DB *dbp;
+ HASHINFO ctl;
+ int stat;
+
+ int i = 0;
+
+ ctl.nelem = INITIAL;
+ ctl.hash = NULL;
+ ctl.bsize = 64;
+ ctl.ffactor = 1;
+ ctl.cachesize = atoi(*argv++);
+ ctl.lorder = 0;
+ if (!(dbp = dbopen( "hashtest", O_RDONLY, 0400, DB_HASH, &ctl))) {
+ /* create table */
+ fprintf(stderr, "cannot open: hash table\n" );
+ exit(1);
+ }
+
+ key.data = wp1;
+ item.data = wp2;
+ while ( fgets(wp1, 8192, stdin) &&
+ fgets(wp2, 8192, stdin) &&
+ i++ < MAXWORDS) {
+/*
+* put info in structure, and structure in the item
+*/
+ key.size = strlen(wp1);
+ item.size = strlen(wp2);
+
+ stat = (dbp->get)(dbp, &key, &res,0);
+ if (stat < 0) {
+ fprintf ( stderr, "Error retrieving %s\n", key.data );
+ exit(1);
+ } else if ( stat > 0 ) {
+ fprintf ( stderr, "%s not found\n", key.data );
+ exit(1);
+ }
+ }
+ (dbp->close)(dbp);
+ exit(0);
+}
diff --git a/lib/libc/db/test/hash.tests/tseq.c b/lib/libc/db/test/hash.tests/tseq.c
new file mode 100644
index 000000000000..3aac7d57488b
--- /dev/null
+++ b/lib/libc/db/test/hash.tests/tseq.c
@@ -0,0 +1,86 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Margo Seltzer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1991, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)tseq.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/file.h>
+#include <stdio.h>
+#include <db.h>
+
+#define INITIAL 25000
+#define MAXWORDS 25000 /* # of elements in search table */
+
+
+char wp[8192];
+char cp[8192];
+main(argc, argv)
+char **argv;
+{
+ DBT item, key, res;
+ DB *dbp;
+ FILE *fp;
+ int stat;
+
+ if (!(dbp = dbopen( "hashtest", O_RDONLY, 0400, DB_HASH, NULL))) {
+ /* create table */
+ fprintf(stderr, "cannot open: hash table\n" );
+ exit(1);
+ }
+
+/*
+* put info in structure, and structure in the item
+*/
+ for ( stat = (dbp->seq) (dbp, &res, &item, 1 );
+ stat == 0;
+ stat = (dbp->seq) (dbp, &res, &item, 0 ) ) {
+
+ bcopy ( res.data, wp, res.size );
+ wp[res.size] = 0;
+ bcopy ( item.data, cp, item.size );
+ cp[item.size] = 0;
+
+ printf ( "%s %s\n", wp, cp );
+ }
+ (dbp->close)(dbp);
+ exit(0);
+}
diff --git a/lib/libc/db/test/hash.tests/tverify.c b/lib/libc/db/test/hash.tests/tverify.c
new file mode 100644
index 000000000000..fb8ee3328e06
--- /dev/null
+++ b/lib/libc/db/test/hash.tests/tverify.c
@@ -0,0 +1,105 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Margo Seltzer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1991, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)tverify.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/file.h>
+#include <stdio.h>
+#include <db.h>
+
+#define INITIAL 25000
+#define MAXWORDS 25000 /* # of elements in search table */
+
+typedef struct { /* info to be stored */
+ int num, siz;
+} info;
+
+char wp1[8192];
+char wp2[8192];
+main(argc, argv)
+char **argv;
+{
+ DBT key, res;
+ DB *dbp;
+ HASHINFO ctl;
+ int trash;
+ int stat;
+
+ int i = 0;
+
+ ctl.nelem = INITIAL;
+ ctl.hash = NULL;
+ ctl.bsize = 64;
+ ctl.ffactor = 1;
+ ctl.cachesize = 1024 * 1024; /* 1 MEG */
+ ctl.lorder = 0;
+ if (!(dbp = dbopen( "hashtest", O_RDONLY, 0400, DB_HASH, &ctl))) {
+ /* create table */
+ fprintf(stderr, "cannot open: hash table\n" );
+ exit(1);
+ }
+
+ key.data = wp1;
+ while ( fgets(wp1, 8192, stdin) &&
+ fgets(wp2, 8192, stdin) &&
+ i++ < MAXWORDS) {
+/*
+* put info in structure, and structure in the item
+*/
+ key.size = strlen(wp1);
+
+ stat = (dbp->get)(dbp, &key, &res,0);
+ if (stat < 0) {
+ fprintf ( stderr, "Error retrieving %s\n", key.data );
+ exit(1);
+ } else if ( stat > 0 ) {
+ fprintf ( stderr, "%s not found\n", key.data );
+ exit(1);
+ }
+ if ( memcmp ( res.data, wp2, res.size ) ) {
+ fprintf ( stderr, "data for %s is incorrect. Data was %s. Should have been %s\n", key.data, res.data, wp2 );
+ }
+ }
+ (dbp->close)(dbp);
+ exit(0);
+}
diff --git a/lib/libc/db/test/run.test b/lib/libc/db/test/run.test
new file mode 100644
index 000000000000..52b74c316199
--- /dev/null
+++ b/lib/libc/db/test/run.test
@@ -0,0 +1,705 @@
+#!/bin/sh -
+#
+# @(#)run.test 8.10 (Berkeley) 7/26/94
+#
+
+# db regression tests
+main()
+{
+
+ PROG=./dbtest
+ TMP1=t1
+ TMP2=t2
+ TMP3=t3
+
+ if [ -f /usr/share/dict/words ]; then
+ DICT=/usr/share/dict/words
+ elif [ -f /usr/dict/words ]; then
+ DICT=/usr/dict/words
+ else
+ echo 'run.test: no dictionary'
+ exit 1
+ fi
+
+ if [ $# -eq 0 ]; then
+ for t in 1 2 3 4 5 6 7 8 9 10 11 12 13 20; do
+ test$t
+ done
+ else
+ while [ $# -gt 0 ]
+ do case "$1" in
+ test*)
+ $1;;
+ [0-9]*)
+ test$1;;
+ btree)
+ for t in 1 2 3 7 8 9 10 12 13; do
+ test$t
+ done;;
+ hash)
+ for t in 1 2 3 8 13 20; do
+ test$t
+ done;;
+ recno)
+ for t in 1 2 3 4 5 6 7 10 11; do
+ test$t
+ done;;
+ *)
+ echo "run.test: unknown test $1"
+ echo "usage: run.test test# | type"
+ exit 1
+ esac
+ shift
+ done
+ fi
+ rm -f $TMP1 $TMP2 $TMP3
+ exit 0
+}
+
+# Take the first hundred entries in the dictionary, and make them
+# be key/data pairs.
+test1()
+{
+ echo "Test 1: btree, hash: small key, small data pairs"
+ sed 200q $DICT > $TMP1
+ for type in btree hash; do
+ rm -f $TMP2 $TMP3
+ for i in `sed 200q $DICT`; do
+ echo p
+ echo k$i
+ echo d$i
+ echo g
+ echo k$i
+ done > $TMP2
+ $PROG -o $TMP3 $type $TMP2
+ if (cmp -s $TMP1 $TMP3) ; then :
+ else
+ echo "test1: type $type: failed"
+ exit 1
+ fi
+ done
+ echo "Test 1: recno: small key, small data pairs"
+ rm -f $TMP2 $TMP3
+ sed 200q $DICT |
+ awk '{
+ ++i;
+ printf("p\nk%d\nd%s\ng\nk%d\n", i, $0, i);
+ }' > $TMP2
+ $PROG -o $TMP3 recno $TMP2
+ if (cmp -s $TMP1 $TMP3) ; then :
+ else
+ echo "test1: type recno: failed"
+ exit 1
+ fi
+}
+
+# Take the first 200 entries in the dictionary, and give them
+# each a medium size data entry.
+test2()
+{
+ echo "Test 2: btree, hash: small key, medium data pairs"
+ mdata=abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz
+ echo $mdata |
+ awk '{ for (i = 1; i < 201; ++i) print $0 }' > $TMP1
+ for type in hash btree; do
+ rm -f $TMP2 $TMP3
+ for i in `sed 200q $DICT`; do
+ echo p
+ echo k$i
+ echo d$mdata
+ echo g
+ echo k$i
+ done > $TMP2
+ $PROG -o $TMP3 $type $TMP2
+ if (cmp -s $TMP1 $TMP3) ; then :
+ else
+ echo "test2: type $type: failed"
+ exit 1
+ fi
+ done
+ echo "Test 2: recno: small key, medium data pairs"
+ rm -f $TMP2 $TMP3
+ echo $mdata |
+ awk '{ for (i = 1; i < 201; ++i)
+ printf("p\nk%d\nd%s\ng\nk%d\n", i, $0, i);
+ }' > $TMP2
+ $PROG -o $TMP3 recno $TMP2
+ if (cmp -s $TMP1 $TMP3) ; then :
+ else
+ echo "test2: type recno: failed"
+ exit 1
+ fi
+}
+
+# Insert the programs in /bin with their paths as their keys.
+test3()
+{
+ echo "Test 3: hash: small key, big data pairs"
+ rm -f $TMP1
+ (find /bin -type f -print | xargs cat) > $TMP1
+ for type in hash; do
+ rm -f $TMP2 $TMP3
+ for i in `find /bin -type f -print`; do
+ echo p
+ echo k$i
+ echo D$i
+ echo g
+ echo k$i
+ done > $TMP2
+ $PROG -o $TMP3 $type $TMP2
+ if (cmp -s $TMP1 $TMP3) ; then :
+ else
+ echo "test3: $type: failed"
+ exit 1
+ fi
+ done
+ echo "Test 3: btree: small key, big data pairs"
+ for psize in 512 16384 65536; do
+ echo " page size $psize"
+ for type in btree; do
+ rm -f $TMP2 $TMP3
+ for i in `find /bin -type f -print`; do
+ echo p
+ echo k$i
+ echo D$i
+ echo g
+ echo k$i
+ done > $TMP2
+ $PROG -i psize=$psize -o $TMP3 $type $TMP2
+ if (cmp -s $TMP1 $TMP3) ; then :
+ else
+ echo "test3: $type: page size $psize: failed"
+ exit 1
+ fi
+ done
+ done
+ echo "Test 3: recno: big data pairs"
+ rm -f $TMP2 $TMP3
+ find /bin -type f -print |
+ awk '{
+ ++i;
+ printf("p\nk%d\nD%s\ng\nk%d\n", i, $0, i);
+ }' > $TMP2
+ for psize in 512 16384 65536; do
+ echo " page size $psize"
+ $PROG -i psize=$psize -o $TMP3 recno $TMP2
+ if (cmp -s $TMP1 $TMP3) ; then :
+ else
+ echo "test3: recno: page size $psize: failed"
+ exit 1
+ fi
+ done
+}
+
+# Do random recno entries.
+test4()
+{
+ echo "Test 4: recno: random entries"
+ echo "abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg" |
+ awk '{
+ for (i = 37; i <= 37 + 88 * 17; i += 17) {
+ if (i % 41)
+ s = substr($0, 1, i % 41);
+ else
+ s = substr($0, 1);
+ printf("input key %d: %s\n", i, s);
+ }
+ for (i = 1; i <= 15; ++i) {
+ if (i % 41)
+ s = substr($0, 1, i % 41);
+ else
+ s = substr($0, 1);
+ printf("input key %d: %s\n", i, s);
+ }
+ for (i = 19234; i <= 19234 + 61 * 27; i += 27) {
+ if (i % 41)
+ s = substr($0, 1, i % 41);
+ else
+ s = substr($0, 1);
+ printf("input key %d: %s\n", i, s);
+ }
+ exit
+ }' > $TMP1
+ rm -f $TMP2 $TMP3
+ cat $TMP1 |
+ awk 'BEGIN {
+ i = 37;
+ incr = 17;
+ }
+ {
+ printf("p\nk%d\nd%s\n", i, $0);
+ if (i == 19234 + 61 * 27)
+ exit;
+ if (i == 37 + 88 * 17) {
+ i = 1;
+ incr = 1;
+ } else if (i == 15) {
+ i = 19234;
+ incr = 27;
+ } else
+ i += incr;
+ }
+ END {
+ for (i = 37; i <= 37 + 88 * 17; i += 17)
+ printf("g\nk%d\n", i);
+ for (i = 1; i <= 15; ++i)
+ printf("g\nk%d\n", i);
+ for (i = 19234; i <= 19234 + 61 * 27; i += 27)
+ printf("g\nk%d\n", i);
+ }' > $TMP2
+ $PROG -o $TMP3 recno $TMP2
+ if (cmp -s $TMP1 $TMP3) ; then :
+ else
+ echo "test4: type recno: failed"
+ exit 1
+ fi
+}
+
+# Do reverse order recno entries.
+test5()
+{
+ echo "Test 5: recno: reverse order entries"
+ echo "abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg" |
+ awk ' {
+ for (i = 1500; i; --i) {
+ if (i % 34)
+ s = substr($0, 1, i % 34);
+ else
+ s = substr($0, 1);
+ printf("input key %d: %s\n", i, s);
+ }
+ exit;
+ }' > $TMP1
+ rm -f $TMP2 $TMP3
+ cat $TMP1 |
+ awk 'BEGIN {
+ i = 1500;
+ }
+ {
+ printf("p\nk%d\nd%s\n", i, $0);
+ --i;
+ }
+ END {
+ for (i = 1500; i; --i)
+ printf("g\nk%d\n", i);
+ }' > $TMP2
+ $PROG -o $TMP3 recno $TMP2
+ if (cmp -s $TMP1 $TMP3) ; then :
+ else
+ echo "test5: type recno: failed"
+ exit 1
+ fi
+}
+
+# Do alternating order recno entries.
+test6()
+{
+ echo "Test 6: recno: alternating order entries"
+ echo "abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg" |
+ awk ' {
+ for (i = 1; i < 1200; i += 2) {
+ if (i % 34)
+ s = substr($0, 1, i % 34);
+ else
+ s = substr($0, 1);
+ printf("input key %d: %s\n", i, s);
+ }
+ for (i = 2; i < 1200; i += 2) {
+ if (i % 34)
+ s = substr($0, 1, i % 34);
+ else
+ s = substr($0, 1);
+ printf("input key %d: %s\n", i, s);
+ }
+ exit;
+ }' > $TMP1
+ rm -f $TMP2 $TMP3
+ cat $TMP1 |
+ awk 'BEGIN {
+ i = 1;
+ even = 0;
+ }
+ {
+ printf("p\nk%d\nd%s\n", i, $0);
+ i += 2;
+ if (i >= 1200) {
+ if (even == 1)
+ exit;
+ even = 1;
+ i = 2;
+ }
+ }
+ END {
+ for (i = 1; i < 1200; ++i)
+ printf("g\nk%d\n", i);
+ }' > $TMP2
+ $PROG -o $TMP3 recno $TMP2
+ sort -o $TMP1 $TMP1
+ sort -o $TMP3 $TMP3
+ if (cmp -s $TMP1 $TMP3) ; then :
+ else
+ echo "test6: type recno: failed"
+ exit 1
+ fi
+}
+
+# Delete cursor record
+test7()
+{
+ echo "Test 7: btree, recno: delete cursor record"
+ echo "abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg" |
+ awk '{
+ for (i = 1; i <= 120; ++i)
+ printf("%05d: input key %d: %s\n", i, i, $0);
+ printf("%05d: input key %d: %s\n", 120, 120, $0);
+ printf("seq failed, no such key\n");
+ printf("%05d: input key %d: %s\n", 1, 1, $0);
+ printf("%05d: input key %d: %s\n", 2, 2, $0);
+ exit;
+ }' > $TMP1
+ rm -f $TMP2 $TMP3
+
+ for type in btree recno; do
+ cat $TMP1 |
+ awk '{
+ if (i == 120)
+ exit;
+ printf("p\nk%d\nd%s\n", ++i, $0);
+ }
+ END {
+ printf("fR_NEXT\n");
+ for (i = 1; i <= 120; ++i)
+ printf("s\n");
+ printf("fR_CURSOR\ns\nk120\n");
+ printf("r\n");
+ printf("fR_NEXT\ns\n");
+ printf("fR_CURSOR\ns\nk1\n");
+ printf("r\n");
+ printf("fR_FIRST\ns\n");
+ }' > $TMP2
+ $PROG -o $TMP3 recno $TMP2
+ if (cmp -s $TMP1 $TMP3) ; then :
+ else
+ echo "test7: type $type: failed"
+ exit 1
+ fi
+ done
+}
+
+# Make sure that overflow pages are reused.
+test8()
+{
+ echo "Test 8: btree, hash: repeated small key, big data pairs"
+ rm -f $TMP1
+ echo "" |
+ awk 'BEGIN {
+ for (i = 1; i <= 10; ++i) {
+ printf("p\nkkey1\nD/bin/sh\n");
+ printf("p\nkkey2\nD/bin/csh\n");
+ if (i % 8 == 0) {
+ printf("c\nkkey2\nD/bin/csh\n");
+ printf("c\nkkey1\nD/bin/sh\n");
+ printf("e\t%d of 10 (comparison)\n", i);
+ } else
+ printf("e\t%d of 10 \n", i);
+ printf("r\nkkey1\nr\nkkey2\n");
+ }
+ }' > $TMP1
+ $PROG btree $TMP1
+# $PROG hash $TMP1
+ # No explicit test for success.
+}
+
+# Test btree duplicate keys
+test9()
+{
+ echo "Test 9: btree: duplicate keys"
+ echo "abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg" |
+ awk '{
+ for (i = 1; i <= 543; ++i)
+ printf("%05d: input key %d: %s\n", i, i, $0);
+ exit;
+ }' > $TMP1
+ rm -f $TMP2 $TMP3
+
+ for type in btree; do
+ cat $TMP1 |
+ awk '{
+ if (i++ % 2)
+ printf("p\nkduplicatekey\nd%s\n", $0);
+ else
+ printf("p\nkunique%dkey\nd%s\n", i, $0);
+ }
+ END {
+ printf("o\n");
+ }' > $TMP2
+ $PROG -iflags=1 -o $TMP3 $type $TMP2
+ sort -o $TMP3 $TMP3
+ if (cmp -s $TMP1 $TMP3) ; then :
+ else
+ echo "test9: type $type: failed"
+ exit 1
+ fi
+ done
+}
+
+# Test use of cursor flags without initialization
+test10()
+{
+ echo "Test 10: btree, recno: test cursor flag use"
+ echo "abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg" |
+ awk '{
+ for (i = 1; i <= 20; ++i)
+ printf("%05d: input key %d: %s\n", i, i, $0);
+ exit;
+ }' > $TMP1
+ rm -f $TMP2 $TMP3
+
+ # Test that R_CURSOR doesn't succeed before cursor initialized
+ for type in btree recno; do
+ cat $TMP1 |
+ awk '{
+ if (i == 10)
+ exit;
+ printf("p\nk%d\nd%s\n", ++i, $0);
+ }
+ END {
+ printf("fR_CURSOR\nr\n");
+ printf("eR_CURSOR SHOULD HAVE FAILED\n");
+ }' > $TMP2
+ $PROG -o $TMP3 $type $TMP2 > /dev/null 2>&1
+ if [ -s $TMP3 ] ; then
+ echo "Test 10: delete: R_CURSOR SHOULD HAVE FAILED"
+ exit 1
+ fi
+ done
+ for type in btree recno; do
+ cat $TMP1 |
+ awk '{
+ if (i == 10)
+ exit;
+ printf("p\nk%d\nd%s\n", ++i, $0);
+ }
+ END {
+ printf("fR_CURSOR\np\nk1\ndsome data\n");
+ printf("eR_CURSOR SHOULD HAVE FAILED\n");
+ }' > $TMP2
+ $PROG -o $TMP3 $type $TMP2 > /dev/null 2>&1
+ if [ -s $TMP3 ] ; then
+ echo "Test 10: put: R_CURSOR SHOULD HAVE FAILED"
+ exit 1
+ fi
+ done
+}
+
+# Test insert in reverse order.
+test11()
+{
+ echo "Test 11: recno: reverse order insert"
+ echo "abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg" |
+ awk '{
+ for (i = 1; i <= 779; ++i)
+ printf("%05d: input key %d: %s\n", i, i, $0);
+ exit;
+ }' > $TMP1
+ rm -f $TMP2 $TMP3
+
+ for type in recno; do
+ cat $TMP1 |
+ awk '{
+ if (i == 0) {
+ i = 1;
+ printf("p\nk1\nd%s\n", $0);
+ printf("%s\n", "fR_IBEFORE");
+ } else
+ printf("p\nk1\nd%s\n", $0);
+ }
+ END {
+ printf("or\n");
+ }' > $TMP2
+ $PROG -o $TMP3 $type $TMP2
+ if (cmp -s $TMP1 $TMP3) ; then :
+ else
+ echo "test11: type $type: failed"
+ exit 1
+ fi
+ done
+}
+
+# Take the first 20000 entries in the dictionary, reverse them, and give
+# them each a small size data entry. Use a small page size to make sure
+# the btree split code gets hammered.
+test12()
+{
+ echo "Test 12: btree: lots of keys, small page size"
+ mdata=abcdefghijklmnopqrstuvwxy
+ echo $mdata |
+ awk '{ for (i = 1; i < 20001; ++i) print $0 }' > $TMP1
+ for type in btree; do
+ rm -f $TMP2 $TMP3
+ for i in `sed 20000q $DICT | rev`; do
+ echo p
+ echo k$i
+ echo d$mdata
+ echo g
+ echo k$i
+ done > $TMP2
+ $PROG -i psize=512 -o $TMP3 $type $TMP2
+ if (cmp -s $TMP1 $TMP3) ; then :
+ else
+ echo "test12: type $type: failed"
+ exit 1
+ fi
+ done
+}
+
+# Test different byte orders.
+test13()
+{
+ echo "Test 13: btree, hash: differing byte orders"
+ sed 50q $DICT > $TMP1
+ for order in 1234 4321; do
+ for type in btree hash; do
+ rm -f byte.file $TMP2 $TMP3
+ for i in `sed 50q $DICT`; do
+ echo p
+ echo k$i
+ echo d$i
+ echo g
+ echo k$i
+ done > $TMP2
+ $PROG -ilorder=$order -f byte.file -o $TMP3 $type $TMP2
+ if (cmp -s $TMP1 $TMP3) ; then :
+ else
+ echo "test13: $type/$order put failed"
+ exit 1
+ fi
+ for i in `sed 50q $DICT`; do
+ echo g
+ echo k$i
+ done > $TMP2
+ $PROG -s \
+ -ilorder=$order -f byte.file -o $TMP3 $type $TMP2
+ if (cmp -s $TMP1 $TMP3) ; then :
+ else
+ echo "test13: $type/$order get failed"
+ exit 1
+ fi
+ done
+ done
+ rm -f byte.file
+}
+
+# Try a variety of bucketsizes and fill factors for hashing
+test20()
+{
+ echo\
+ "Test 20: hash: bucketsize, fill factor; nelem 25000 cachesize 65536"
+ echo "abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg" |
+ awk '{
+ for (i = 1; i <= 10000; ++i) {
+ if (i % 34)
+ s = substr($0, 1, i % 34);
+ else
+ s = substr($0, 1);
+ printf("%s\n", s);
+ }
+ exit;
+ }' > $TMP1
+ sed 10000q $DICT |
+ awk 'BEGIN {
+ ds="abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg"
+ }
+ {
+ if (++i % 34)
+ s = substr(ds, 1, i % 34);
+ else
+ s = substr(ds, 1);
+ printf("p\nk%s\nd%s\n", $0, s);
+ }' > $TMP2
+ sed 10000q $DICT |
+ awk '{
+ ++i;
+ printf("g\nk%s\n", $0);
+ }' >> $TMP2
+ bsize=256
+ for ffactor in 11 14 21; do
+ echo " bucketsize $bsize, fill factor $ffactor"
+ $PROG -o$TMP3 \
+ -ibsize=$bsize,ffactor=$ffactor,nelem=25000,cachesize=65536\
+ hash $TMP2
+ if (cmp -s $TMP1 $TMP3) ; then :
+ else
+ echo "test20: type hash:\
+bsize=$bsize ffactor=$ffactor nelem=25000 cachesize=65536 failed"
+ exit 1
+ fi
+ done
+ bsize=512
+ for ffactor in 21 28 43; do
+ echo " bucketsize $bsize, fill factor $ffactor"
+ $PROG -o$TMP3 \
+ -ibsize=$bsize,ffactor=$ffactor,nelem=25000,cachesize=65536\
+ hash $TMP2
+ if (cmp -s $TMP1 $TMP3) ; then :
+ else
+ echo "test20: type hash:\
+bsize=$bsize ffactor=$ffactor nelem=25000 cachesize=65536 failed"
+ exit 1
+ fi
+ done
+ bsize=1024
+ for ffactor in 43 57 85; do
+ echo " bucketsize $bsize, fill factor $ffactor"
+ $PROG -o$TMP3 \
+ -ibsize=$bsize,ffactor=$ffactor,nelem=25000,cachesize=65536\
+ hash $TMP2
+ if (cmp -s $TMP1 $TMP3) ; then :
+ else
+ echo "test20: type hash:\
+bsize=$bsize ffactor=$ffactor nelem=25000 cachesize=65536 failed"
+ exit 1
+ fi
+ done
+ bsize=2048
+ for ffactor in 85 114 171; do
+ echo " bucketsize $bsize, fill factor $ffactor"
+ $PROG -o$TMP3 \
+ -ibsize=$bsize,ffactor=$ffactor,nelem=25000,cachesize=65536\
+ hash $TMP2
+ if (cmp -s $TMP1 $TMP3) ; then :
+ else
+ echo "test20: type hash:\
+bsize=$bsize ffactor=$ffactor nelem=25000 cachesize=65536 failed"
+ exit 1
+ fi
+ done
+ bsize=4096
+ for ffactor in 171 228 341; do
+ echo " bucketsize $bsize, fill factor $ffactor"
+ $PROG -o$TMP3 \
+ -ibsize=$bsize,ffactor=$ffactor,nelem=25000,cachesize=65536\
+ hash $TMP2
+ if (cmp -s $TMP1 $TMP3) ; then :
+ else
+ echo "test20: type hash:\
+bsize=$bsize ffactor=$ffactor nelem=25000 cachesize=65536 failed"
+ exit 1
+ fi
+ done
+ bsize=8192
+ for ffactor in 341 455 683; do
+ echo " bucketsize $bsize, fill factor $ffactor"
+ $PROG -o$TMP3 \
+ -ibsize=$bsize,ffactor=$ffactor,nelem=25000,cachesize=65536\
+ hash $TMP2
+ if (cmp -s $TMP1 $TMP3) ; then :
+ else
+ echo "test20: type hash:\
+bsize=$bsize ffactor=$ffactor nelem=25000 cachesize=65536 failed"
+ exit 1
+ fi
+ done
+}
+
+main $*
diff --git a/lib/libc/gdtoa/Makefile.inc b/lib/libc/gdtoa/Makefile.inc
new file mode 100644
index 000000000000..61dbf34adbae
--- /dev/null
+++ b/lib/libc/gdtoa/Makefile.inc
@@ -0,0 +1,20 @@
+# $FreeBSD$
+
+# netlib gdtoa sources
+.PATH: ${LIBC_SRCTOP}/gdtoa
+
+MISRCS+=_hdtoa.c _hldtoa.c _ldtoa.c glue.c
+GDTOASRCS+=dmisc.c dtoa.c gdtoa.c gethex.c gmisc.c \
+ hd_init.c hexnan.c misc.c smisc.c \
+ strtod.c strtodg.c strtof.c strtord.c sum.c ulp.c
+
+SYM_MAPS+=${LIBC_SRCTOP}/gdtoa/Symbol.map
+
+CFLAGS+=-I${SRCTOP}/contrib/gdtoa
+
+.for src in ${GDTOASRCS}
+MISRCS+=gdtoa_${src}
+CLEANFILES+=gdtoa_${src}
+gdtoa_${src}: ${SRCTOP}/contrib/gdtoa/${src} .NOMETA
+ ln -sf ${.ALLSRC} ${.TARGET}
+.endfor
diff --git a/lib/libc/gdtoa/Symbol.map b/lib/libc/gdtoa/Symbol.map
new file mode 100644
index 000000000000..4483e9a3adff
--- /dev/null
+++ b/lib/libc/gdtoa/Symbol.map
@@ -0,0 +1,19 @@
+/*
+ * $FreeBSD$
+ */
+
+FBSD_1.0 {
+ /*
+ * Standard functions from contrib/gdtoa
+ */
+ strtod;
+ strtof;
+
+ /* FreeBSD additions */
+ strtold;
+};
+
+FBSDprivate_1.0 {
+ /* used in libm */
+ __hexnan_D2A;
+};
diff --git a/lib/libc/gdtoa/_hdtoa.c b/lib/libc/gdtoa/_hdtoa.c
new file mode 100644
index 000000000000..6f8ccacda373
--- /dev/null
+++ b/lib/libc/gdtoa/_hdtoa.c
@@ -0,0 +1,144 @@
+/*-
+ * Copyright (c) 2004-2008 David Schultz <das@FreeBSD.ORG>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <float.h>
+#include <limits.h>
+#include <math.h>
+
+#include "../stdio/floatio.h"
+#include "fpmath.h"
+#include "gdtoaimp.h"
+
+/* Strings values used by dtoa() */
+#define INFSTR "Infinity"
+#define NANSTR "NaN"
+
+#define DBL_ADJ (DBL_MAX_EXP - 2)
+#define SIGFIGS ((DBL_MANT_DIG + 3) / 4 + 1)
+
+static const float one[] = { 1.0f, -1.0f };
+
+/*
+ * This procedure converts a double-precision number in IEEE format
+ * into a string of hexadecimal digits and an exponent of 2. Its
+ * behavior is bug-for-bug compatible with dtoa() in mode 2, with the
+ * following exceptions:
+ *
+ * - An ndigits < 0 causes it to use as many digits as necessary to
+ * represent the number exactly.
+ * - The additional xdigs argument should point to either the string
+ * "0123456789ABCDEF" or the string "0123456789abcdef", depending on
+ * which case is desired.
+ * - This routine does not repeat dtoa's mistake of setting decpt
+ * to 9999 in the case of an infinity or NaN. INT_MAX is used
+ * for this purpose instead.
+ *
+ * Note that the C99 standard does not specify what the leading digit
+ * should be for non-zero numbers. For instance, 0x1.3p3 is the same
+ * as 0x2.6p2 is the same as 0x4.cp3. This implementation always makes
+ * the leading digit a 1. This ensures that the exponent printed is the
+ * actual base-2 exponent, i.e., ilogb(d).
+ *
+ * Inputs: d, xdigs, ndigits
+ * Outputs: decpt, sign, rve
+ */
+char *
+__hdtoa(double d, const char *xdigs, int ndigits, int *decpt, int *sign,
+ char **rve)
+{
+ union IEEEd2bits u;
+ char *s, *s0;
+ int bufsize;
+ uint32_t manh, manl;
+
+ u.d = d;
+ *sign = u.bits.sign;
+
+ switch (fpclassify(d)) {
+ case FP_NORMAL:
+ *decpt = u.bits.exp - DBL_ADJ;
+ break;
+ case FP_ZERO:
+ *decpt = 1;
+ return (nrv_alloc("0", rve, 1));
+ case FP_SUBNORMAL:
+ u.d *= 0x1p514;
+ *decpt = u.bits.exp - (514 + DBL_ADJ);
+ break;
+ case FP_INFINITE:
+ *decpt = INT_MAX;
+ return (nrv_alloc(INFSTR, rve, sizeof(INFSTR) - 1));
+ default: /* FP_NAN or unrecognized */
+ *decpt = INT_MAX;
+ return (nrv_alloc(NANSTR, rve, sizeof(NANSTR) - 1));
+ }
+
+ /* FP_NORMAL or FP_SUBNORMAL */
+
+ if (ndigits == 0) /* dtoa() compatibility */
+ ndigits = 1;
+
+ /*
+ * If ndigits < 0, we are expected to auto-size, so we allocate
+ * enough space for all the digits.
+ */
+ bufsize = (ndigits > 0) ? ndigits : SIGFIGS;
+ s0 = rv_alloc(bufsize);
+
+ /* Round to the desired number of digits. */
+ if (SIGFIGS > ndigits && ndigits > 0) {
+ float redux = one[u.bits.sign];
+ int offset = 4 * ndigits + DBL_MAX_EXP - 4 - DBL_MANT_DIG;
+ u.bits.exp = offset;
+ u.d += redux;
+ u.d -= redux;
+ *decpt += u.bits.exp - offset;
+ }
+
+ manh = u.bits.manh;
+ manl = u.bits.manl;
+ *s0 = '1';
+ for (s = s0 + 1; s < s0 + bufsize; s++) {
+ *s = xdigs[(manh >> (DBL_MANH_SIZE - 4)) & 0xf];
+ manh = (manh << 4) | (manl >> (DBL_MANL_SIZE - 4));
+ manl <<= 4;
+ }
+
+ /* If ndigits < 0, we are expected to auto-size the precision. */
+ if (ndigits < 0) {
+ for (ndigits = SIGFIGS; s0[ndigits - 1] == '0'; ndigits--)
+ ;
+ }
+
+ s = s0 + ndigits;
+ *s = '\0';
+ if (rve != NULL)
+ *rve = s;
+ return (s0);
+}
diff --git a/lib/libc/gdtoa/_hldtoa.c b/lib/libc/gdtoa/_hldtoa.c
new file mode 100644
index 000000000000..97394eaa30c1
--- /dev/null
+++ b/lib/libc/gdtoa/_hldtoa.c
@@ -0,0 +1,177 @@
+/*-
+ * Copyright (c) 2004-2008 David Schultz <das@FreeBSD.ORG>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <float.h>
+#include <limits.h>
+#include <math.h>
+#include <stdint.h>
+
+#ifdef __i386__
+#include <ieeefp.h>
+#endif
+
+#include "../stdio/floatio.h"
+#include "fpmath.h"
+#include "gdtoaimp.h"
+
+#if (LDBL_MANT_DIG > DBL_MANT_DIG)
+
+/* Strings values used by dtoa() */
+#define INFSTR "Infinity"
+#define NANSTR "NaN"
+
+#ifdef LDBL_IMPLICIT_NBIT
+#define MANH_SIZE LDBL_MANH_SIZE
+#else
+#define MANH_SIZE (LDBL_MANH_SIZE - 1)
+#endif
+
+#if MANH_SIZE > 32
+typedef uint64_t manh_t;
+#else
+typedef uint32_t manh_t;
+#endif
+
+#if LDBL_MANL_SIZE > 32
+typedef uint64_t manl_t;
+#else
+typedef uint32_t manl_t;
+#endif
+
+#define LDBL_ADJ (LDBL_MAX_EXP - 2)
+#define SIGFIGS ((LDBL_MANT_DIG + 3) / 4 + 1)
+
+static const float one[] = { 1.0f, -1.0f };
+
+/*
+ * This is the long double version of __hdtoa().
+ */
+char *
+__hldtoa(long double e, const char *xdigs, int ndigits, int *decpt, int *sign,
+ char **rve)
+{
+ union IEEEl2bits u;
+ char *s, *s0;
+ manh_t manh;
+ manl_t manl;
+ int bufsize;
+#ifdef __i386__
+ fp_prec_t oldprec;
+#endif
+
+ u.e = e;
+ *sign = u.bits.sign;
+
+ switch (fpclassify(e)) {
+ case FP_NORMAL:
+ *decpt = u.bits.exp - LDBL_ADJ;
+ break;
+ case FP_ZERO:
+ *decpt = 1;
+ return (nrv_alloc("0", rve, 1));
+ case FP_SUBNORMAL:
+#ifdef __i386__
+ oldprec = fpsetprec(FP_PE);
+#endif
+ u.e *= 0x1p514L;
+ *decpt = u.bits.exp - (514 + LDBL_ADJ);
+#ifdef __i386__
+ fpsetprec(oldprec);
+#endif
+ break;
+ case FP_INFINITE:
+ *decpt = INT_MAX;
+ return (nrv_alloc(INFSTR, rve, sizeof(INFSTR) - 1));
+ default: /* FP_NAN or unrecognized */
+ *decpt = INT_MAX;
+ return (nrv_alloc(NANSTR, rve, sizeof(NANSTR) - 1));
+ }
+
+ /* FP_NORMAL or FP_SUBNORMAL */
+
+ if (ndigits == 0) /* dtoa() compatibility */
+ ndigits = 1;
+
+ /*
+ * If ndigits < 0, we are expected to auto-size, so we allocate
+ * enough space for all the digits.
+ */
+ bufsize = (ndigits > 0) ? ndigits : SIGFIGS;
+ s0 = rv_alloc(bufsize);
+
+ /* Round to the desired number of digits. */
+ if (SIGFIGS > ndigits && ndigits > 0) {
+ float redux = one[u.bits.sign];
+ int offset = 4 * ndigits + LDBL_MAX_EXP - 4 - LDBL_MANT_DIG;
+#ifdef __i386__
+ oldprec = fpsetprec(FP_PE);
+#endif
+ u.bits.exp = offset;
+ u.e += redux;
+ u.e -= redux;
+ *decpt += u.bits.exp - offset;
+#ifdef __i386__
+ fpsetprec(oldprec);
+#endif
+ }
+
+ mask_nbit_l(u);
+ manh = u.bits.manh;
+ manl = u.bits.manl;
+ *s0 = '1';
+ for (s = s0 + 1; s < s0 + bufsize; s++) {
+ *s = xdigs[(manh >> (MANH_SIZE - 4)) & 0xf];
+ manh = (manh << 4) | (manl >> (LDBL_MANL_SIZE - 4));
+ manl <<= 4;
+ }
+
+ /* If ndigits < 0, we are expected to auto-size the precision. */
+ if (ndigits < 0) {
+ for (ndigits = SIGFIGS; s0[ndigits - 1] == '0'; ndigits--)
+ ;
+ }
+
+ s = s0 + ndigits;
+ *s = '\0';
+ if (rve != NULL)
+ *rve = s;
+ return (s0);
+}
+
+#else /* (LDBL_MANT_DIG == DBL_MANT_DIG) */
+
+char *
+__hldtoa(long double e, const char *xdigs, int ndigits, int *decpt, int *sign,
+ char **rve)
+{
+
+ return (__hdtoa((double)e, xdigs, ndigits, decpt, sign, rve));
+}
+
+#endif /* (LDBL_MANT_DIG == DBL_MANT_DIG) */
diff --git a/lib/libc/gdtoa/_ldtoa.c b/lib/libc/gdtoa/_ldtoa.c
new file mode 100644
index 000000000000..00d76013f887
--- /dev/null
+++ b/lib/libc/gdtoa/_ldtoa.c
@@ -0,0 +1,108 @@
+/*-
+ * Copyright (c) 2003 David Schultz <das@FreeBSD.ORG>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <float.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <math.h>
+#include <stdlib.h>
+#include "../stdio/floatio.h"
+#include "fpmath.h"
+#include "gdtoaimp.h"
+
+/*
+ * ldtoa() is a wrapper for gdtoa() that makes it smell like dtoa(),
+ * except that the floating point argument is passed by reference.
+ * When dtoa() is passed a NaN or infinity, it sets expt to 9999.
+ * However, a long double could have a valid exponent of 9999, so we
+ * use INT_MAX in ldtoa() instead.
+ */
+char *
+__ldtoa(long double *ld, int mode, int ndigits, int *decpt, int *sign,
+ char **rve)
+{
+ FPI fpi = {
+ LDBL_MANT_DIG, /* nbits */
+ LDBL_MIN_EXP - LDBL_MANT_DIG, /* emin */
+ LDBL_MAX_EXP - LDBL_MANT_DIG, /* emax */
+ FLT_ROUNDS, /* rounding */
+#ifdef Sudden_Underflow /* unused, but correct anyway */
+ 1
+#else
+ 0
+#endif
+ };
+ int be, kind;
+ char *ret;
+ union IEEEl2bits u;
+ uint32_t bits[(LDBL_MANT_DIG + 31) / 32];
+ void *vbits = bits;
+
+ u.e = *ld;
+
+ /*
+ * gdtoa doesn't know anything about the sign of the number, so
+ * if the number is negative, we need to swap rounding modes of
+ * 2 (upwards) and 3 (downwards).
+ */
+ *sign = u.bits.sign;
+ fpi.rounding ^= (fpi.rounding >> 1) & u.bits.sign;
+
+ be = u.bits.exp - (LDBL_MAX_EXP - 1) - (LDBL_MANT_DIG - 1);
+ LDBL_TO_ARRAY32(u, bits);
+
+ switch (fpclassify(u.e)) {
+ case FP_NORMAL:
+ kind = STRTOG_Normal;
+#ifdef LDBL_IMPLICIT_NBIT
+ bits[LDBL_MANT_DIG / 32] |= 1 << ((LDBL_MANT_DIG - 1) % 32);
+#endif /* LDBL_IMPLICIT_NBIT */
+ break;
+ case FP_ZERO:
+ kind = STRTOG_Zero;
+ break;
+ case FP_SUBNORMAL:
+ kind = STRTOG_Denormal;
+ be++;
+ break;
+ case FP_INFINITE:
+ kind = STRTOG_Infinite;
+ break;
+ case FP_NAN:
+ kind = STRTOG_NaN;
+ break;
+ default:
+ abort();
+ }
+
+ ret = gdtoa(&fpi, be, vbits, &kind, mode, ndigits, decpt, rve);
+ if (*decpt == -32768)
+ *decpt = INT_MAX;
+ return ret;
+}
diff --git a/lib/libc/gdtoa/glue.c b/lib/libc/gdtoa/glue.c
new file mode 100644
index 000000000000..39e491a7a277
--- /dev/null
+++ b/lib/libc/gdtoa/glue.c
@@ -0,0 +1,13 @@
+/*
+ * Machine-independent glue to integrate David Gay's gdtoa
+ * package into libc.
+ *
+ * $FreeBSD$
+ */
+
+#include <pthread.h>
+
+pthread_mutex_t __gdtoa_locks[] = {
+ PTHREAD_MUTEX_INITIALIZER,
+ PTHREAD_MUTEX_INITIALIZER
+};
diff --git a/lib/libc/gdtoa/machdep_ldisQ.c b/lib/libc/gdtoa/machdep_ldisQ.c
new file mode 100644
index 000000000000..7b5c7afbc108
--- /dev/null
+++ b/lib/libc/gdtoa/machdep_ldisQ.c
@@ -0,0 +1,52 @@
+/*-
+ * Copyright (c) 2003 David Schultz <das@FreeBSD.ORG>
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Machine-dependent glue to integrate David Gay's gdtoa
+ * package into libc for architectures where a long double
+ * uses quad precision, such as sparc64.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <float.h>
+
+#include "gdtoaimp.h"
+
+long double
+strtold_l(const char * __restrict s, char ** __restrict sp, locale_t locale)
+{
+ long double result;
+
+ strtorQ_l(s, sp, FLT_ROUNDS, &result, locale);
+ return result;
+}
diff --git a/lib/libc/gdtoa/machdep_ldisd.c b/lib/libc/gdtoa/machdep_ldisd.c
new file mode 100644
index 000000000000..d5c732998023
--- /dev/null
+++ b/lib/libc/gdtoa/machdep_ldisd.c
@@ -0,0 +1,49 @@
+/*-
+ * Copyright (c) 2003 David Schultz <das@FreeBSD.ORG>
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Machine-dependent glue to integrate David Gay's gdtoa
+ * package into libc for architectures where a long double
+ * is the same as a double, such as the Alpha.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "gdtoaimp.h"
+#undef strtold_l
+
+long double
+strtold_l(const char * __restrict s, char ** __restrict sp, locale_t locale)
+{
+
+ return strtod_l(s, sp, locale);
+}
diff --git a/lib/libc/gdtoa/machdep_ldisx.c b/lib/libc/gdtoa/machdep_ldisx.c
new file mode 100644
index 000000000000..b8e2a05790cc
--- /dev/null
+++ b/lib/libc/gdtoa/machdep_ldisx.c
@@ -0,0 +1,53 @@
+/*-
+ * Copyright (c) 2003 David Schultz <das@FreeBSD.ORG>
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Machine-dependent glue to integrate David Gay's gdtoa
+ * package into libc for architectures where a long double
+ * is an IEEE extended precision number.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <float.h>
+
+#include "gdtoaimp.h"
+
+long double
+strtold_l(const char * __restrict s, char ** __restrict sp, locale_t locale)
+{
+ long double result;
+ FIX_LOCALE(locale);
+
+ strtorx_l(s, sp, FLT_ROUNDS, &result, locale);
+ return result;
+}
diff --git a/lib/libc/gen/Makefile.inc b/lib/libc/gen/Makefile.inc
new file mode 100644
index 000000000000..460d09a9c4e2
--- /dev/null
+++ b/lib/libc/gen/Makefile.inc
@@ -0,0 +1,524 @@
+# @(#)Makefile.inc 8.6 (Berkeley) 5/4/95
+# $FreeBSD$
+
+# machine-independent gen sources
+.PATH: ${LIBC_SRCTOP}/${LIBC_ARCH}/gen ${LIBC_SRCTOP}/gen
+
+SRCS+= __getosreldate.c \
+ __pthread_mutex_init_calloc_cb_stub.c \
+ __xuname.c \
+ _once_stub.c \
+ _pthread_stubs.c \
+ _rand48.c \
+ _spinlock_stub.c \
+ _thread_init.c \
+ alarm.c \
+ arc4random.c \
+ assert.c \
+ auxv.c \
+ basename.c \
+ basename_compat.c \
+ cap_sandboxed.c \
+ check_utility_compat.c \
+ clock.c \
+ clock_getcpuclockid.c \
+ closedir.c \
+ confstr.c \
+ crypt.c \
+ ctermid.c \
+ daemon.c \
+ devname.c \
+ dirfd.c \
+ dirname.c \
+ dirname_compat.c \
+ disklabel.c \
+ dlfcn.c \
+ drand48.c \
+ dup3.c \
+ elf_utils.c \
+ erand48.c \
+ err.c \
+ errlst.c \
+ errno.c \
+ exec.c \
+ fdevname.c \
+ feature_present.c \
+ fmtcheck.c \
+ fmtmsg.c \
+ fnmatch.c \
+ fpclassify.c \
+ frexp.c \
+ fstab.c \
+ ftok.c \
+ fts.c \
+ ftw.c \
+ getbootfile.c \
+ getbsize.c \
+ getcap.c \
+ getcwd.c \
+ getdomainname.c \
+ getgrent.c \
+ getgrouplist.c \
+ gethostname.c \
+ getloadavg.c \
+ getlogin.c \
+ getmntinfo.c \
+ getnetgrent.c \
+ getosreldate.c \
+ getpagesize.c \
+ getpagesizes.c \
+ getpeereid.c \
+ getprogname.c \
+ getpwent.c \
+ getttyent.c \
+ getusershell.c \
+ getutxent.c \
+ getvfsbyname.c \
+ glob.c \
+ initgroups.c \
+ isatty.c \
+ isinf.c \
+ isnan.c \
+ jrand48.c \
+ lcong48.c \
+ libc_dlopen.c \
+ lockf.c \
+ lrand48.c \
+ mrand48.c \
+ nftw.c \
+ nice.c \
+ nlist.c \
+ nrand48.c \
+ opendir.c \
+ pause.c \
+ pmadvise.c \
+ popen.c \
+ posix_spawn.c \
+ psignal.c \
+ pututxline.c \
+ pw_scan.c \
+ raise.c \
+ readdir.c \
+ readpassphrase.c \
+ recvmmsg.c \
+ rewinddir.c \
+ scandir.c \
+ seed48.c \
+ seekdir.c \
+ semctl.c \
+ sendmmsg.c \
+ setdomainname.c \
+ sethostname.c \
+ setjmperr.c \
+ setmode.c \
+ setproctitle.c \
+ setprogname.c \
+ siginterrupt.c \
+ siglist.c \
+ signal.c \
+ sigsetops.c \
+ sleep.c \
+ srand48.c \
+ statvfs.c \
+ stringlist.c \
+ strtofflags.c \
+ sysconf.c \
+ sysctl.c \
+ sysctlbyname.c \
+ sysctlnametomib.c \
+ syslog.c \
+ telldir.c \
+ termios.c \
+ time.c \
+ times.c \
+ timezone.c \
+ tls.c \
+ ttyname.c \
+ ttyslot.c \
+ ualarm.c \
+ ulimit.c \
+ uname.c \
+ usleep.c \
+ utime.c \
+ utxdb.c \
+ valloc.c \
+ wait.c \
+ wait3.c \
+ waitpid.c \
+ waitid.c \
+ wordexp.c
+.if ${MK_SYMVER} == yes
+SRCS+= fts-compat.c \
+ unvis-compat.c
+.endif
+
+.PATH: ${SRCTOP}/contrib/libc-pwcache
+SRCS+= pwcache.c pwcache.h
+
+.PATH: ${SRCTOP}/contrib/libc-vis
+CFLAGS+= -I${SRCTOP}/contrib/libc-vis
+SRCS+= unvis.c vis.c
+
+MISRCS+=modf.c
+
+CANCELPOINTS_SRCS=sem.c sem_new.c
+.for src in ${CANCELPOINTS_SRCS}
+SRCS+=cancelpoints_${src}
+CLEANFILES+=cancelpoints_${src}
+cancelpoints_${src}: ${LIBC_SRCTOP}/gen/${src} .NOMETA
+ ln -sf ${.ALLSRC} ${.TARGET}
+.endfor
+
+SYM_MAPS+=${LIBC_SRCTOP}/gen/Symbol.map
+
+# machine-dependent gen sources
+.sinclude "${LIBC_SRCTOP}/${LIBC_ARCH}/gen/Makefile.inc"
+
+MAN+= alarm.3 \
+ arc4random.3 \
+ basename.3 \
+ cap_rights_get.3 \
+ cap_sandboxed.3 \
+ check_utility_compat.3 \
+ clock.3 \
+ clock_getcpuclockid.3 \
+ confstr.3 \
+ ctermid.3 \
+ daemon.3 \
+ devname.3 \
+ directory.3 \
+ dirname.3 \
+ dl_iterate_phdr.3 \
+ dladdr.3 \
+ dlinfo.3 \
+ dllockinit.3 \
+ dlopen.3 \
+ dup3.3 \
+ err.3 \
+ exec.3 \
+ feature_present.3 \
+ fmtcheck.3 \
+ fmtmsg.3 \
+ fnmatch.3 \
+ fpclassify.3 \
+ frexp.3 \
+ ftok.3 \
+ fts.3 \
+ ftw.3 \
+ getbootfile.3 \
+ getbsize.3 \
+ getcap.3 \
+ getcontext.3 \
+ getcwd.3 \
+ getdiskbyname.3 \
+ getdomainname.3 \
+ getfsent.3 \
+ getgrent.3 \
+ getgrouplist.3 \
+ gethostname.3 \
+ getloadavg.3 \
+ getmntinfo.3 \
+ getnetgrent.3 \
+ getosreldate.3 \
+ getpagesize.3 \
+ getpagesizes.3 \
+ getpass.3 \
+ getpeereid.3 \
+ getprogname.3 \
+ getpwent.3 \
+ getttyent.3 \
+ getusershell.3 \
+ getutxent.3 \
+ getvfsbyname.3 \
+ glob.3 \
+ initgroups.3 \
+ isgreater.3 \
+ ldexp.3 \
+ lockf.3 \
+ makecontext.3 \
+ modf.3 \
+ nice.3 \
+ nlist.3 \
+ pause.3 \
+ popen.3 \
+ posix_spawn.3 \
+ posix_spawn_file_actions_addopen.3 \
+ posix_spawn_file_actions_init.3 \
+ posix_spawnattr_getflags.3 \
+ posix_spawnattr_getpgroup.3 \
+ posix_spawnattr_getschedparam.3 \
+ posix_spawnattr_getschedpolicy.3 \
+ posix_spawnattr_init.3 \
+ posix_spawnattr_getsigdefault.3 \
+ posix_spawnattr_getsigmask.3 \
+ psignal.3 \
+ pwcache.3 \
+ raise.3 \
+ rand48.3 \
+ readpassphrase.3 \
+ rfork_thread.3 \
+ scandir.3 \
+ sem_destroy.3 \
+ sem_getvalue.3 \
+ sem_init.3 \
+ sem_open.3 \
+ sem_post.3 \
+ sem_timedwait.3 \
+ sem_wait.3 \
+ setjmp.3 \
+ setmode.3 \
+ setproctitle.3 \
+ siginterrupt.3 \
+ signal.3 \
+ sigsetops.3 \
+ sleep.3 \
+ statvfs.3 \
+ stringlist.3 \
+ strtofflags.3 \
+ sysconf.3 \
+ sysctl.3 \
+ syslog.3 \
+ tcgetpgrp.3 \
+ tcgetsid.3 \
+ tcsendbreak.3 \
+ tcsetattr.3 \
+ tcsetpgrp.3 \
+ tcsetsid.3 \
+ time.3 \
+ times.3 \
+ timezone.3 \
+ ttyname.3 \
+ tzset.3 \
+ ualarm.3 \
+ ucontext.3 \
+ ulimit.3 \
+ uname.3 \
+ unvis.3 \
+ usleep.3 \
+ utime.3 \
+ valloc.3 \
+ vis.3 \
+ wordexp.3
+
+MLINKS+=arc4random.3 arc4random_addrandom.3 \
+ arc4random.3 arc4random_stir.3 \
+ arc4random.3 arc4random_buf.3 \
+ arc4random.3 arc4random_uniform.3
+MLINKS+=basename.3 basename_r.3
+MLINKS+=ctermid.3 ctermid_r.3
+MLINKS+=devname.3 devname_r.3
+MLINKS+=devname.3 fdevname.3
+MLINKS+=devname.3 fdevname_r.3
+MLINKS+=directory.3 closedir.3 \
+ directory.3 dirfd.3 \
+ directory.3 fdclosedir.3 \
+ directory.3 fdopendir.3 \
+ directory.3 opendir.3 \
+ directory.3 readdir.3 \
+ directory.3 readdir_r.3 \
+ directory.3 rewinddir.3 \
+ directory.3 seekdir.3 \
+ directory.3 telldir.3
+MLINKS+=dlopen.3 fdlopen.3 \
+ dlopen.3 dlclose.3 \
+ dlopen.3 dlerror.3 \
+ dlopen.3 dlfunc.3 \
+ dlopen.3 dlsym.3
+MLINKS+=err.3 err_set_exit.3 \
+ err.3 err_set_file.3 \
+ err.3 errc.3 \
+ err.3 errx.3 \
+ err.3 verr.3 \
+ err.3 verrc.3 \
+ err.3 verrx.3 \
+ err.3 vwarn.3 \
+ err.3 vwarnc.3 \
+ err.3 vwarnx.3 \
+ err.3 warnc.3 \
+ err.3 warn.3 \
+ err.3 warnx.3
+MLINKS+=exec.3 execl.3 \
+ exec.3 execle.3 \
+ exec.3 execlp.3 \
+ exec.3 exect.3 \
+ exec.3 execv.3 \
+ exec.3 execvP.3 \
+ exec.3 execvp.3
+MLINKS+=fpclassify.3 finite.3 \
+ fpclassify.3 finitef.3 \
+ fpclassify.3 isfinite.3 \
+ fpclassify.3 isinf.3 \
+ fpclassify.3 isnan.3 \
+ fpclassify.3 isnormal.3
+MLINKS+=frexp.3 frexpf.3 \
+ frexp.3 frexpl.3
+MLINKS+=fts.3 fts_children.3 \
+ fts.3 fts_close.3 \
+ fts.3 fts_open.3 \
+ fts.3 fts_read.3 \
+ fts.3 fts_set.3 \
+ fts.3 fts_set_clientptr.3 \
+ fts.3 fts_get_clientptr.3 \
+ fts.3 fts_get_stream.3
+MLINKS+=ftw.3 nftw.3
+MLINKS+=getcap.3 cgetcap.3 \
+ getcap.3 cgetclose.3 \
+ getcap.3 cgetent.3 \
+ getcap.3 cgetfirst.3 \
+ getcap.3 cgetmatch.3 \
+ getcap.3 cgetnext.3 \
+ getcap.3 cgetnum.3 \
+ getcap.3 cgetset.3 \
+ getcap.3 cgetstr.3 \
+ getcap.3 cgetustr.3
+MLINKS+=getcwd.3 getwd.3
+MLINKS+=getcontext.3 getcontextx.3
+MLINKS+=getcontext.3 setcontext.3
+MLINKS+=getdomainname.3 setdomainname.3
+MLINKS+=getfsent.3 endfsent.3 \
+ getfsent.3 getfsfile.3 \
+ getfsent.3 getfsspec.3 \
+ getfsent.3 getfstype.3 \
+ getfsent.3 setfsent.3 \
+ getfsent.3 setfstab.3 \
+ getfsent.3 getfstab.3
+MLINKS+=getgrent.3 endgrent.3 \
+ getgrent.3 getgrgid.3 \
+ getgrent.3 getgrnam.3 \
+ getgrent.3 setgrent.3 \
+ getgrent.3 setgroupent.3 \
+ getgrent.3 getgrent_r.3 \
+ getgrent.3 getgrnam_r.3 \
+ getgrent.3 getgrgid_r.3
+MLINKS+=gethostname.3 sethostname.3
+MLINKS+=getnetgrent.3 endnetgrent.3 \
+ getnetgrent.3 getnetgrent_r.3 \
+ getnetgrent.3 innetgr.3 \
+ getnetgrent.3 setnetgrent.3
+MLINKS+=getprogname.3 setprogname.3
+MLINKS+=getpwent.3 endpwent.3 \
+ getpwent.3 getpwnam.3 \
+ getpwent.3 getpwuid.3 \
+ getpwent.3 setpassent.3 \
+ getpwent.3 setpwent.3 \
+ getpwent.3 setpwfile.3 \
+ getpwent.3 getpwent_r.3 \
+ getpwent.3 getpwnam_r.3 \
+ getpwent.3 getpwuid_r.3
+MLINKS+=getttyent.3 endttyent.3 \
+ getttyent.3 getttynam.3 \
+ getttyent.3 isdialuptty.3 \
+ getttyent.3 isnettty.3 \
+ getttyent.3 setttyent.3
+MLINKS+=getusershell.3 endusershell.3 \
+ getusershell.3 setusershell.3
+MLINKS+=getutxent.3 endutxent.3 \
+ getutxent.3 getutxid.3 \
+ getutxent.3 getutxline.3 \
+ getutxent.3 getutxuser.3 \
+ getutxent.3 pututxline.3 \
+ getutxent.3 setutxdb.3 \
+ getutxent.3 setutxent.3 \
+ getutxent.3 utmpx.3
+MLINKS+=glob.3 globfree.3
+MLINKS+=isgreater.3 isgreaterequal.3 \
+ isgreater.3 isless.3 \
+ isgreater.3 islessequal.3 \
+ isgreater.3 islessgreater.3 \
+ isgreater.3 isunordered.3
+MLINKS+=ldexp.3 ldexpf.3 \
+ ldexp.3 ldexpl.3
+MLINKS+=makecontext.3 swapcontext.3
+MLINKS+=modf.3 modff.3 \
+ modf.3 modfl.3
+MLINKS+=popen.3 pclose.3
+MLINKS+=posix_spawn.3 posix_spawnp.3 \
+ posix_spawn_file_actions_addopen.3 posix_spawn_file_actions_addclose.3 \
+ posix_spawn_file_actions_addopen.3 posix_spawn_file_actions_adddup2.3 \
+ posix_spawn_file_actions_init.3 posix_spawn_file_actions_destroy.3 \
+ posix_spawnattr_getflags.3 posix_spawnattr_setflags.3 \
+ posix_spawnattr_getpgroup.3 posix_spawnattr_setpgroup.3 \
+ posix_spawnattr_getschedparam.3 posix_spawnattr_setschedparam.3 \
+ posix_spawnattr_getschedpolicy.3 posix_spawnattr_setschedpolicy.3 \
+ posix_spawnattr_getsigdefault.3 posix_spawnattr_setsigdefault.3 \
+ posix_spawnattr_getsigmask.3 posix_spawnattr_setsigmask.3 \
+ posix_spawnattr_init.3 posix_spawnattr_destroy.3
+MLINKS+=psignal.3 strsignal.3 \
+ psignal.3 sys_siglist.3 \
+ psignal.3 sys_signame.3
+MLINKS+=pwcache.3 group_from_gid.3 \
+ pwcache.3 user_from_uid.3
+MLINKS+=rand48.3 _rand48.3 \
+ rand48.3 drand48.3 \
+ rand48.3 erand48.3 \
+ rand48.3 jrand48.3 \
+ rand48.3 lcong48.3 \
+ rand48.3 lrand48.3 \
+ rand48.3 mrand48.3 \
+ rand48.3 nrand48.3 \
+ rand48.3 seed48.3 \
+ rand48.3 srand48.3
+MLINKS+=recv.2 recvmmsg.2
+MLINKS+=scandir.3 alphasort.3
+MLINKS+=sem_open.3 sem_close.3 \
+ sem_open.3 sem_unlink.3
+MLINKS+=sem_wait.3 sem_trywait.3
+MLINKS+=send.2 sendmmsg.2
+MLINKS+=setjmp.3 _longjmp.3 \
+ setjmp.3 _setjmp.3 \
+ setjmp.3 longjmp.3 \
+ setjmp.3 longjmperr.3 \
+ setjmp.3 longjmperror.3 \
+ setjmp.3 siglongjmp.3 \
+ setjmp.3 sigsetjmp.3
+MLINKS+=setmode.3 getmode.3
+MLINKS+=sigsetops.3 sigaddset.3 \
+ sigsetops.3 sigdelset.3 \
+ sigsetops.3 sigemptyset.3 \
+ sigsetops.3 sigfillset.3 \
+ sigsetops.3 sigismember.3
+MLINKS+=statvfs.3 fstatvfs.3
+MLINKS+=stringlist.3 sl_add.3 \
+ stringlist.3 sl_find.3 \
+ stringlist.3 sl_free.3 \
+ stringlist.3 sl_init.3
+MLINKS+=strtofflags.3 fflagstostr.3
+MLINKS+=sysctl.3 sysctlbyname.3 \
+ sysctl.3 sysctlnametomib.3
+MLINKS+=syslog.3 closelog.3 \
+ syslog.3 openlog.3 \
+ syslog.3 setlogmask.3 \
+ syslog.3 vsyslog.3
+MLINKS+=tcsendbreak.3 tcdrain.3 \
+ tcsendbreak.3 tcflow.3 \
+ tcsendbreak.3 tcflush.3
+MLINKS+=tcsetattr.3 cfgetispeed.3 \
+ tcsetattr.3 cfgetospeed.3 \
+ tcsetattr.3 cfmakeraw.3 \
+ tcsetattr.3 cfmakesane.3 \
+ tcsetattr.3 cfsetispeed.3 \
+ tcsetattr.3 cfsetospeed.3 \
+ tcsetattr.3 cfsetspeed.3 \
+ tcsetattr.3 tcgetattr.3
+MLINKS+=ttyname.3 isatty.3 \
+ ttyname.3 ttyname_r.3
+MLINKS+=tzset.3 tzsetwall.3
+MLINKS+=unvis.3 strunvis.3 \
+ unvis.3 strunvisx.3
+MLINKS+=vis.3 nvis.3 \
+ vis.3 snvis.3 \
+ vis.3 strenvisx.3 \
+ vis.3 strnunvis.3 \
+ vis.3 strnunvisx.3 \
+ vis.3 strnvis.3 \
+ vis.3 strnvisx.3 \
+ vis.3 strsenvisx.3 \
+ vis.3 strsnvis.3 \
+ vis.3 strsnvisx.3 \
+ vis.3 strsvis.3 \
+ vis.3 strsvisx.3 \
+ vis.3 strvis.3 \
+ vis.3 strvisx.3 \
+ vis.3 svis.3
+
+MLINKS+=wordexp.3 wordfree.3
diff --git a/lib/libc/gen/Symbol.map b/lib/libc/gen/Symbol.map
new file mode 100644
index 000000000000..4b07a0067be9
--- /dev/null
+++ b/lib/libc/gen/Symbol.map
@@ -0,0 +1,547 @@
+/*
+ * $FreeBSD$
+ */
+
+FBSD_1.0 {
+ __xuname;
+ pthread_atfork;
+ pthread_attr_destroy;
+ pthread_attr_getdetachstate;
+ pthread_attr_getguardsize;
+ pthread_attr_getinheritsched;
+ pthread_attr_getschedparam;
+ pthread_attr_getschedpolicy;
+ pthread_attr_getscope;
+ pthread_attr_getstackaddr;
+ pthread_attr_getstacksize;
+ pthread_attr_init;
+ pthread_attr_setdetachstate;
+ pthread_attr_setguardsize;
+ pthread_attr_setinheritsched;
+ pthread_attr_setschedparam;
+ pthread_attr_setschedpolicy;
+ pthread_attr_setscope;
+ pthread_attr_setstackaddr;
+ pthread_attr_setstacksize;
+ pthread_cancel;
+ pthread_cleanup_pop;
+ pthread_cleanup_push;
+ pthread_cond_broadcast;
+ pthread_cond_destroy;
+ pthread_cond_init;
+ pthread_cond_signal;
+ pthread_cond_timedwait;
+ pthread_cond_wait;
+ pthread_detach;
+ pthread_equal;
+ pthread_exit;
+ pthread_getspecific;
+ pthread_join;
+ pthread_key_create;
+ pthread_key_delete;
+ pthread_kill;
+ pthread_main_np;
+ pthread_mutex_destroy;
+ pthread_mutex_init;
+ pthread_mutex_lock;
+ pthread_mutex_trylock;
+ pthread_mutex_unlock;
+ pthread_mutexattr_destroy;
+ pthread_mutexattr_init;
+ pthread_mutexattr_settype;
+ pthread_once;
+ pthread_rwlock_destroy;
+ pthread_rwlock_init;
+ pthread_rwlock_rdlock;
+ pthread_rwlock_tryrdlock;
+ pthread_rwlock_trywrlock;
+ pthread_rwlock_unlock;
+ pthread_rwlock_wrlock;
+ pthread_self;
+ pthread_setcancelstate;
+ pthread_setcanceltype;
+ pthread_setspecific;
+ pthread_sigmask;
+ pthread_testcancel;
+ alarm;
+ arc4random;
+ arc4random_addrandom;
+ arc4random_stir;
+ __assert;
+ check_utility_compat;
+ clock;
+ closedir;
+ confstr;
+ ctermid;
+ ctermid_r;
+ daemon;
+ devname;
+ devname_r;
+ getdiskbyname;
+ dladdr;
+ dlclose;
+ dlerror;
+ dlfunc;
+ dllockinit;
+ dlopen;
+ dlsym;
+ dlvsym;
+ dlinfo;
+ dl_iterate_phdr;
+ drand48;
+ erand48;
+ err_set_file;
+ err_set_exit;
+ err;
+ verr;
+ errc;
+ verrc;
+ errx;
+ verrx;
+ warn;
+ vwarn;
+ warnc;
+ vwarnc;
+ warnx;
+ vwarnx;
+ sys_errlist;
+ sys_nerr;
+ errno;
+ execl;
+ execle;
+ execlp;
+ execv;
+ execvp;
+ execvP;
+ fmtcheck;
+ fmtmsg;
+ fnmatch;
+ __fpclassifyf;
+ __fpclassifyd;
+ __fpclassifyl;
+ frexp;
+ setfstab;
+ getfstab;
+ getfsent;
+ getfsspec;
+ getfsfile;
+ setfsent;
+ endfsent;
+ ftok;
+ ftw;
+ glob;
+ globfree;
+ getbootfile;
+ getbsize;
+ cgetset;
+ cgetcap;
+ cgetent;
+ cgetmatch;
+ cgetfirst;
+ cgetclose;
+ cgetnext;
+ cgetstr;
+ cgetustr;
+ cgetnum;
+ getcwd;
+ getdomainname;
+ setgrent;
+ setgroupent;
+ endgrent;
+ getgrent_r;
+ getgrnam_r;
+ getgrgid_r;
+ getgrnam;
+ getgrgid;
+ getgrent;
+ /*
+ * Why are __gr_parse_entry() and __gr_match_entry() not static in
+ * gen/getgrent.c?
+ */
+ getgrouplist;
+ gethostname;
+ getloadavg;
+ getlogin;
+ getlogin_r;
+ getmntinfo;
+ setnetgrent;
+ getnetgrent;
+ endnetgrent;
+ innetgr;
+ getosreldate;
+ getpagesize;
+ getpeereid;
+ _getprogname;
+ getprogname;
+ setpwent;
+ setpassent;
+ endpwent;
+ getpwent_r;
+ getpwnam_r;
+ getpwuid_r;
+ getpwnam;
+ getpwuid;
+ getpwent;
+ getttynam;
+ getttyent;
+ setttyent;
+ endttyent;
+ isdialuptty;
+ isnettty;
+ getusershell;
+ endusershell;
+ setusershell;
+ getvfsbyname;
+ __isnan;
+ isnan;
+ __isnanf;
+ isnanf;
+ __isinf;
+ isinf;
+ __isinff;
+ __isinfl;
+ isatty;
+ initgroups;
+ jrand48;
+ lcong48;
+ ldexp;
+ lockf;
+ lrand48;
+ modf;
+ mrand48;
+ nftw;
+ nice;
+ nlist;
+ nrand48;
+ opendir;
+ pause;
+ posix_madvise;
+ popen;
+ pclose;
+ psignal;
+ raise;
+ readdir;
+ readdir_r;
+ readpassphrase;
+ getpass;
+ rewinddir;
+ scandir;
+ alphasort;
+ seed48;
+ seekdir;
+ user_from_uid;
+ group_from_gid;
+ setdomainname;
+ sethostname;
+ longjmperror;
+ getmode;
+ setmode;
+ setproctitle;
+ setprogname;
+ siginterrupt;
+ sys_signame;
+ sys_siglist;
+ sys_nsig;
+ signal;
+ sigaddset;
+ sigdelset;
+ sigemptyset;
+ sigfillset;
+ sigismember;
+ sleep;
+ srand48;
+ fstatvfs;
+ statvfs;
+ sl_init;
+ sl_add;
+ sl_free;
+ sl_find;
+ fflagstostr;
+ strtofflags;
+ sysconf;
+ sysctl;
+ sysctlbyname;
+ sysctlnametomib;
+ syslog;
+ vsyslog;
+ openlog;
+ closelog;
+ setlogmask;
+ ttyname_r;
+ ttyname;
+ timezone;
+ times;
+ time;
+ telldir;
+ tcgetattr;
+ tcsetattr;
+ tcsetpgrp;
+ tcgetpgrp;
+ cfgetospeed;
+ cfgetispeed;
+ cfsetospeed;
+ cfsetispeed;
+ cfsetspeed;
+ cfmakeraw;
+ tcsendbreak;
+ _init_tls;
+ __tls_get_addr;
+ tcdrain;
+ tcflush;
+ tcflow;
+ ualarm;
+ ulimit;
+ uname;
+ strunvis;
+ strunvisx;
+ usleep;
+ utime;
+ valloc;
+ vis;
+ strvis;
+ strvisx;
+ wait;
+ wait3;
+ waitpid;
+ wordexp;
+ wordfree;
+};
+
+FBSD_1.1 {
+ arc4random_buf;
+ arc4random_uniform;
+ fdevname;
+ fdevname_r;
+ fdopendir;
+ feature_present;
+ fts_children;
+ fts_close;
+ fts_get_clientptr;
+ fts_get_stream;
+ fts_open;
+ fts_read;
+ fts_set;
+ fts_set_clientptr;
+ posix_spawn;
+ posix_spawn_file_actions_addclose;
+ posix_spawn_file_actions_adddup2;
+ posix_spawn_file_actions_addopen;
+ posix_spawn_file_actions_destroy;
+ posix_spawn_file_actions_init;
+ posix_spawnattr_destroy;
+ posix_spawnattr_getflags;
+ posix_spawnattr_getpgroup;
+ posix_spawnattr_getschedparam;
+ posix_spawnattr_getschedpolicy;
+ posix_spawnattr_getsigdefault;
+ posix_spawnattr_getsigmask;
+ posix_spawnattr_init;
+ posix_spawnattr_setflags;
+ posix_spawnattr_setpgroup;
+ posix_spawnattr_setschedparam;
+ posix_spawnattr_setschedpolicy;
+ posix_spawnattr_setsigdefault;
+ posix_spawnattr_setsigmask;
+ posix_spawnp;
+ semctl;
+ tcgetsid;
+ tcsetsid;
+ __pthread_cleanup_pop_imp;
+ __pthread_cleanup_push_imp;
+};
+
+FBSD_1.2 {
+ basename_r;
+ cfmakesane;
+ endutxent;
+ getpagesizes;
+ getutxent;
+ getutxid;
+ getutxline;
+ getutxuser;
+ pututxline;
+ sem_close;
+ sem_destroy;
+ sem_getvalue;
+ sem_init;
+ sem_open;
+ sem_post;
+ sem_timedwait;
+ sem_trywait;
+ sem_unlink;
+ sem_wait;
+ setutxdb;
+ setutxent;
+};
+
+FBSD_1.3 {
+ clock_getcpuclockid;
+ dirfd;
+ dup3;
+ fdclosedir;
+ fdlopen;
+ __FreeBSD_libc_enter_restricted_mode;
+ getcontextx;
+ gid_from_group;
+ nvis;
+ pwcache_userdb;
+ pwcache_groupdb;
+ snvis;
+ strenvisx;
+ strnunvis;
+ strnunvisx;
+ strnvis;
+ strnvisx;
+ strsenvisx;
+ strsnvis;
+ strsnvisx;
+ strsvis;
+ strsvisx;
+ svis;
+ uid_from_user;
+ unvis;
+ waitid;
+};
+
+FBSD_1.4 {
+ getnetgrent_r;
+ pthread_mutex_consistent;
+ pthread_mutexattr_getrobust;
+ pthread_mutexattr_setrobust;
+ scandir_b;
+ stravis;
+};
+
+FBSD_1.5 {
+ basename;
+ dirname;
+};
+
+FBSDprivate_1.0 {
+ /* needed by thread libraries */
+ __thr_jtable;
+
+ _pthread_atfork;
+ _pthread_attr_destroy;
+ _pthread_attr_getdetachstate;
+ _pthread_attr_getguardsize;
+ _pthread_attr_getinheritsched;
+ _pthread_attr_getschedparam;
+ _pthread_attr_getschedpolicy;
+ _pthread_attr_getscope;
+ _pthread_attr_getstackaddr;
+ _pthread_attr_getstacksize;
+ _pthread_attr_init;
+ _pthread_attr_setdetachstate;
+ _pthread_attr_setguardsize;
+ _pthread_attr_setinheritsched;
+ _pthread_attr_setschedparam;
+ _pthread_attr_setschedpolicy;
+ _pthread_attr_setscope;
+ _pthread_attr_setstackaddr;
+ _pthread_attr_setstacksize;
+ _pthread_cancel;
+ _pthread_cancel_enter;
+ _pthread_cancel_leave;
+ _pthread_cleanup_pop;
+ _pthread_cleanup_push;
+ _pthread_cond_broadcast;
+ _pthread_cond_destroy;
+ _pthread_cond_init;
+ _pthread_cond_signal;
+ _pthread_cond_timedwait;
+ _pthread_cond_wait;
+ _pthread_detach;
+ _pthread_equal;
+ _pthread_exit;
+ _pthread_getspecific;
+ _pthread_join;
+ _pthread_key_create;
+ _pthread_key_delete;
+ _pthread_kill;
+ _pthread_main_np;
+ _pthread_mutex_destroy;
+ _pthread_mutex_init_calloc_cb;
+ _pthread_mutex_init;
+ _pthread_mutex_lock;
+ _pthread_mutex_trylock;
+ _pthread_mutex_unlock;
+ _pthread_mutexattr_destroy;
+ _pthread_mutexattr_init;
+ _pthread_mutexattr_settype;
+ _pthread_once;
+ _pthread_rwlock_destroy;
+ _pthread_rwlock_init;
+ _pthread_rwlock_rdlock;
+ _pthread_rwlock_tryrdlock;
+ _pthread_rwlock_trywrlock;
+ _pthread_rwlock_unlock;
+ _pthread_rwlock_wrlock;
+ _pthread_self;
+ _pthread_setcancelstate;
+ _pthread_setcanceltype;
+ _pthread_setspecific;
+ _pthread_sigmask;
+ _pthread_testcancel;
+ _spinlock;
+ _spinlock_debug;
+ _spinunlock;
+ _rtld_addr_phdr;
+ _rtld_atfork_pre;
+ _rtld_atfork_post;
+ _rtld_error; /* for private use */
+ _rtld_get_stack_prot;
+ _rtld_is_dlopened;
+ _rtld_thread_init; /* for private use */
+ __elf_phdr_match_addr;
+ _err;
+ _warn;
+ __fmtcheck;
+ /* __pw_match_entry; */
+ /* __pw_parse_entry; */
+ __fdnlist; /* used by libkvm */
+ /* __aout_fdnlist; */
+ /* __elf_is_okay__; */
+ /* __elf_fdnlist; */
+ __opendir2;
+ __pause;
+ _pause;
+ __pw_scan; /* Used by (at least) libutil */
+ __raise;
+ _raise;
+ __sleep;
+ _sleep;
+ _rtld_allocate_tls;
+ _rtld_free_tls;
+#if defined(i386)
+ ___libc_tls_get_addr; /* x86 only */
+#endif
+ __libc_tls_get_addr;
+ __tcdrain;
+ _tcdrain;
+ __usleep;
+ _usleep;
+ __wait;
+ _wait;
+ __waitpid;
+ _waitpid;
+
+ _libc_sem_init_compat;
+ _libc_sem_destroy_compat;
+ _libc_sem_open_compat;
+ _libc_sem_close_compat;
+ _libc_sem_unlink_compat;
+ _libc_sem_wait_compat;
+ _libc_sem_trywait_compat;
+ _libc_sem_timedwait_compat;
+ _libc_sem_post_compat;
+ _libc_sem_getvalue_compat;
+
+ __libc_tcdrain;
+
+ __elf_aux_vector;
+ __pthread_map_stacks_exec;
+ __fillcontextx;
+ __fillcontextx2;
+ __getcontextx_size;
+};
diff --git a/lib/libc/gen/__getosreldate.c b/lib/libc/gen/__getosreldate.c
new file mode 100644
index 000000000000..377eadbb8926
--- /dev/null
+++ b/lib/libc/gen/__getosreldate.c
@@ -0,0 +1,68 @@
+/*-
+ * Copyright (c) 2007 Peter Wemm
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <errno.h>
+#include <link.h>
+#include "libc_private.h"
+
+/*
+ * This is private to libc. It is intended for wrapping syscall stubs in order
+ * to avoid having to put SIGSYS signal handlers in place to test for presence
+ * of new syscalls. This caches the result in order to be as quick as possible.
+ *
+ * Use getosreldate(3) for public use as it respects the $OSVERSION environment
+ * variable.
+ */
+
+int
+__getosreldate(void)
+{
+ static int osreldate;
+ size_t len;
+ int oid[2];
+ int error, osrel;
+
+ if (osreldate != 0)
+ return (osreldate);
+
+ error = _elf_aux_info(AT_OSRELDATE, &osreldate, sizeof(osreldate));
+ if (error == 0 && osreldate != 0)
+ return (osreldate);
+
+ oid[0] = CTL_KERN;
+ oid[1] = KERN_OSRELDATE;
+ osrel = 0;
+ len = sizeof(osrel);
+ error = sysctl(oid, 2, &osrel, &len, NULL, 0);
+ if (error == 0 && osrel > 0 && len == sizeof(osrel))
+ osreldate = osrel;
+ return (osreldate);
+}
diff --git a/lib/libc/gen/__pthread_mutex_init_calloc_cb_stub.c b/lib/libc/gen/__pthread_mutex_init_calloc_cb_stub.c
new file mode 100644
index 000000000000..1c566ecf4809
--- /dev/null
+++ b/lib/libc/gen/__pthread_mutex_init_calloc_cb_stub.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2014 The FreeBSD Foundation.
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Konstantin Belousov
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice(s), this list of conditions and the following disclaimer as
+ * the first lines of this file unmodified other than the possible
+ * addition of one or more copyright notices.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice(s), this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <pthread.h>
+#include "libc_private.h"
+
+int
+_pthread_mutex_init_calloc_cb_stub(pthread_mutex_t *mutex,
+ void *(calloc_cb)(size_t, size_t))
+{
+
+ return (0);
+}
diff --git a/lib/libc/gen/__xuname.c b/lib/libc/gen/__xuname.c
new file mode 100644
index 000000000000..6f7d92a1708a
--- /dev/null
+++ b/lib/libc/gen/__xuname.c
@@ -0,0 +1,146 @@
+/*-
+ * Copyright (c) 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char sccsid[] = "From: @(#)uname.c 8.1 (Berkeley) 1/4/94";*/
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <sys/utsname.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+int
+__xuname(int namesize, void *namebuf)
+{
+ int mib[2], rval;
+ size_t len;
+ char *p, *q;
+ int oerrno;
+
+ rval = 0;
+ q = (char *)namebuf;
+
+ mib[0] = CTL_KERN;
+
+ if ((p = getenv("UNAME_s")))
+ strlcpy(q, p, namesize);
+ else {
+ mib[1] = KERN_OSTYPE;
+ len = namesize;
+ oerrno = errno;
+ if (sysctl(mib, 2, q, &len, NULL, 0) == -1) {
+ if (errno == ENOMEM)
+ errno = oerrno;
+ else
+ rval = -1;
+ }
+ q[namesize - 1] = '\0';
+ }
+ q += namesize;
+
+ mib[1] = KERN_HOSTNAME;
+ len = namesize;
+ oerrno = errno;
+ if (sysctl(mib, 2, q, &len, NULL, 0) == -1) {
+ if (errno == ENOMEM)
+ errno = oerrno;
+ else
+ rval = -1;
+ }
+ q[namesize - 1] = '\0';
+ q += namesize;
+
+ if ((p = getenv("UNAME_r")))
+ strlcpy(q, p, namesize);
+ else {
+ mib[1] = KERN_OSRELEASE;
+ len = namesize;
+ oerrno = errno;
+ if (sysctl(mib, 2, q, &len, NULL, 0) == -1) {
+ if (errno == ENOMEM)
+ errno = oerrno;
+ else
+ rval = -1;
+ }
+ q[namesize - 1] = '\0';
+ }
+ q += namesize;
+
+ if ((p = getenv("UNAME_v")))
+ strlcpy(q, p, namesize);
+ else {
+
+ /*
+ * The version may have newlines in it, turn them into
+ * spaces.
+ */
+ mib[1] = KERN_VERSION;
+ len = namesize;
+ oerrno = errno;
+ if (sysctl(mib, 2, q, &len, NULL, 0) == -1) {
+ if (errno == ENOMEM)
+ errno = oerrno;
+ else
+ rval = -1;
+ }
+ q[namesize - 1] = '\0';
+ for (p = q; len--; ++p) {
+ if (*p == '\n' || *p == '\t') {
+ if (len > 1)
+ *p = ' ';
+ else
+ *p = '\0';
+ }
+ }
+ }
+ q += namesize;
+
+ if ((p = getenv("UNAME_m")))
+ strlcpy(q, p, namesize);
+ else {
+ mib[0] = CTL_HW;
+ mib[1] = HW_MACHINE;
+ len = namesize;
+ oerrno = errno;
+ if (sysctl(mib, 2, q, &len, NULL, 0) == -1) {
+ if (errno == ENOMEM)
+ errno = oerrno;
+ else
+ rval = -1;
+ }
+ q[namesize - 1] = '\0';
+ }
+
+ return (rval);
+}
diff --git a/lib/libc/gen/_once_stub.c b/lib/libc/gen/_once_stub.c
new file mode 100644
index 000000000000..c45565a79cbd
--- /dev/null
+++ b/lib/libc/gen/_once_stub.c
@@ -0,0 +1,64 @@
+/*-
+ * Copyright (c) 2009 Hudson River Trading LLC
+ * Written by: John H. Baldwin <jhb@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <pthread.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+
+/* This implements pthread_once() for the single-threaded case. */
+static int
+_libc_once(pthread_once_t *once_control, void (*init_routine)(void))
+{
+
+ if (once_control->state == PTHREAD_DONE_INIT)
+ return (0);
+ init_routine();
+ once_control->state = PTHREAD_DONE_INIT;
+ return (0);
+}
+
+/*
+ * This is the internal interface provided to libc. It will use
+ * pthread_once() from the threading library in a multi-threaded
+ * process and _libc_once() for a single-threaded library. Because
+ * _libc_once() uses the same ABI for the values in the pthread_once_t
+ * structure as the threading library, it is safe for a process to
+ * switch from _libc_once() to pthread_once() when threading is
+ * enabled.
+ */
+int
+_once(pthread_once_t *once_control, void (*init_routine)(void))
+{
+
+ if (__isthreaded)
+ return (_pthread_once(once_control, init_routine));
+ return (_libc_once(once_control, init_routine));
+}
diff --git a/lib/libc/gen/_pthread_stubs.c b/lib/libc/gen/_pthread_stubs.c
new file mode 100644
index 000000000000..18a23216d501
--- /dev/null
+++ b/lib/libc/gen/_pthread_stubs.c
@@ -0,0 +1,327 @@
+/*
+ * Copyright (c) 2001 Daniel Eischen <deischen@FreeBSD.org>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY DANIEL EISCHEN AND CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <signal.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "libc_private.h"
+
+/*
+ * Weak symbols: All libc internal usage of these functions should
+ * use the weak symbol versions (_pthread_XXX). If libpthread is
+ * linked, it will override these functions with (non-weak) routines.
+ * The _pthread_XXX functions are provided solely for internal libc
+ * usage to avoid unwanted cancellation points and to differentiate
+ * between application locks and libc locks (threads holding the
+ * latter can't be allowed to exit/terminate).
+ */
+
+/* Define a null pthread structure just to satisfy _pthread_self. */
+struct pthread {
+};
+
+static struct pthread main_thread;
+
+static int stub_main(void);
+static void *stub_null(void);
+static struct pthread *stub_self(void);
+static int stub_zero(void);
+static int stub_fail(void);
+static int stub_true(void);
+static void stub_exit(void);
+
+#define PJT_DUAL_ENTRY(entry) \
+ (pthread_func_t)entry, (pthread_func_t)entry
+
+pthread_func_entry_t __thr_jtable[PJT_MAX] = {
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_ATFORK */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_ATTR_DESTROY */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_ATTR_GETDETACHSTATE */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_ATTR_GETGUARDSIZE */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_ATTR_GETINHERITSCHED */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_ATTR_GETSCHEDPARAM */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_ATTR_GETSCHEDPOLICY */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_ATTR_GETSCOPE */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_ATTR_GETSTACKADDR */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_ATTR_GETSTACKSIZE */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_ATTR_INIT */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_ATTR_SETDETACHSTATE */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_ATTR_SETGUARDSIZE */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_ATTR_SETINHERITSCHED */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_ATTR_SETSCHEDPARAM */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_ATTR_SETSCHEDPOLICY */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_ATTR_SETSCOPE */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_ATTR_SETSTACKADDR */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_ATTR_SETSTACKSIZE */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_CANCEL */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_CLEANUP_POP */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_CLEANUP_PUSH */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_COND_BROADCAST */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_COND_DESTROY */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_COND_INIT */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_COND_SIGNAL */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_COND_TIMEDWAIT */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_COND_WAIT */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_DETACH */
+ {PJT_DUAL_ENTRY(stub_true)}, /* PJT_EQUAL */
+ {PJT_DUAL_ENTRY(stub_exit)}, /* PJT_EXIT */
+ {PJT_DUAL_ENTRY(stub_null)}, /* PJT_GETSPECIFIC */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_JOIN */
+ {PJT_DUAL_ENTRY(stub_fail)}, /* PJT_KEY_CREATE */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_KEY_DELETE */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_KILL */
+ {PJT_DUAL_ENTRY(stub_main)}, /* PJT_MAIN_NP */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_MUTEXATTR_DESTROY */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_MUTEXATTR_INIT */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_MUTEXATTR_SETTYPE */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_MUTEX_DESTROY */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_MUTEX_INIT */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_MUTEX_LOCK */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_MUTEX_TRYLOCK */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_MUTEX_UNLOCK */
+ {PJT_DUAL_ENTRY(stub_fail)}, /* PJT_ONCE */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_RWLOCK_DESTROY */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_RWLOCK_INIT */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_RWLOCK_RDLOCK */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_RWLOCK_TRYRDLOCK */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_RWLOCK_TRYWRLOCK */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_RWLOCK_UNLOCK */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_RWLOCK_WRLOCK */
+ {PJT_DUAL_ENTRY(stub_self)}, /* PJT_SELF */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_SETCANCELSTATE */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_SETCANCELTYPE */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_SETSPECIFIC */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_SIGMASK */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_TESTCANCEL */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_CLEANUP_POP_IMP */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_CLEANUP_PUSH_IMP */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_CANCEL_ENTER */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_CANCEL_LEAVE */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_MUTEX_CONSISTENT */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_MUTEXATTR_GETROBUST */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_MUTEXATTR_SETROBUST */
+};
+
+/*
+ * Weak aliases for exported (pthread_*) and internal (_pthread_*) routines.
+ */
+#define WEAK_REF(sym, alias) __weak_reference(sym, alias)
+
+#define FUNC_TYPE(name) __CONCAT(name, _func_t)
+#define FUNC_INT(name) __CONCAT(name, _int)
+#define FUNC_EXP(name) __CONCAT(name, _exp)
+
+#define STUB_FUNC(name, idx, ret) \
+ static ret FUNC_EXP(name)(void) __used; \
+ static ret FUNC_INT(name)(void) __used; \
+ WEAK_REF(FUNC_EXP(name), name); \
+ WEAK_REF(FUNC_INT(name), __CONCAT(_, name)); \
+ typedef ret (*FUNC_TYPE(name))(void); \
+ static ret FUNC_EXP(name)(void) \
+ { \
+ FUNC_TYPE(name) func; \
+ func = (FUNC_TYPE(name))__thr_jtable[idx][0]; \
+ return (func()); \
+ } \
+ static ret FUNC_INT(name)(void) \
+ { \
+ FUNC_TYPE(name) func; \
+ func = (FUNC_TYPE(name))__thr_jtable[idx][1]; \
+ return (func()); \
+ }
+
+#define STUB_FUNC1(name, idx, ret, p0_type) \
+ static ret FUNC_EXP(name)(p0_type) __used; \
+ static ret FUNC_INT(name)(p0_type) __used; \
+ WEAK_REF(FUNC_EXP(name), name); \
+ WEAK_REF(FUNC_INT(name), __CONCAT(_, name)); \
+ typedef ret (*FUNC_TYPE(name))(p0_type); \
+ static ret FUNC_EXP(name)(p0_type p0) \
+ { \
+ FUNC_TYPE(name) func; \
+ func = (FUNC_TYPE(name))__thr_jtable[idx][0]; \
+ return (func(p0)); \
+ } \
+ static ret FUNC_INT(name)(p0_type p0) \
+ { \
+ FUNC_TYPE(name) func; \
+ func = (FUNC_TYPE(name))__thr_jtable[idx][1]; \
+ return (func(p0)); \
+ }
+
+#define STUB_FUNC2(name, idx, ret, p0_type, p1_type) \
+ static ret FUNC_EXP(name)(p0_type, p1_type) __used; \
+ static ret FUNC_INT(name)(p0_type, p1_type) __used; \
+ WEAK_REF(FUNC_EXP(name), name); \
+ WEAK_REF(FUNC_INT(name), __CONCAT(_, name)); \
+ typedef ret (*FUNC_TYPE(name))(p0_type, p1_type); \
+ static ret FUNC_EXP(name)(p0_type p0, p1_type p1) \
+ { \
+ FUNC_TYPE(name) func; \
+ func = (FUNC_TYPE(name))__thr_jtable[idx][0]; \
+ return (func(p0, p1)); \
+ } \
+ static ret FUNC_INT(name)(p0_type p0, p1_type p1) \
+ { \
+ FUNC_TYPE(name) func; \
+ func = (FUNC_TYPE(name))__thr_jtable[idx][1]; \
+ return (func(p0, p1)); \
+ }
+
+#define STUB_FUNC3(name, idx, ret, p0_type, p1_type, p2_type) \
+ static ret FUNC_EXP(name)(p0_type, p1_type, p2_type) __used; \
+ static ret FUNC_INT(name)(p0_type, p1_type, p2_type) __used; \
+ WEAK_REF(FUNC_EXP(name), name); \
+ WEAK_REF(FUNC_INT(name), __CONCAT(_, name)); \
+ typedef ret (*FUNC_TYPE(name))(p0_type, p1_type, p2_type); \
+ static ret FUNC_EXP(name)(p0_type p0, p1_type p1, p2_type p2) \
+ { \
+ FUNC_TYPE(name) func; \
+ func = (FUNC_TYPE(name))__thr_jtable[idx][0]; \
+ return (func(p0, p1, p2)); \
+ } \
+ static ret FUNC_INT(name)(p0_type p0, p1_type p1, p2_type p2) \
+ { \
+ FUNC_TYPE(name) func; \
+ func = (FUNC_TYPE(name))__thr_jtable[idx][1]; \
+ return (func(p0, p1, p2)); \
+ }
+
+STUB_FUNC1(pthread_cond_broadcast, PJT_COND_BROADCAST, int, void *)
+STUB_FUNC1(pthread_cond_destroy, PJT_COND_DESTROY, int, void *)
+STUB_FUNC2(pthread_cond_init, PJT_COND_INIT, int, void *, void *)
+STUB_FUNC1(pthread_cond_signal, PJT_COND_SIGNAL, int, void *)
+STUB_FUNC2(pthread_cond_wait, PJT_COND_WAIT, int, void *, void *)
+STUB_FUNC1(pthread_getspecific, PJT_GETSPECIFIC, void *, pthread_key_t)
+STUB_FUNC2(pthread_key_create, PJT_KEY_CREATE, int, void *, void *)
+STUB_FUNC1(pthread_key_delete, PJT_KEY_DELETE, int, pthread_key_t)
+STUB_FUNC(pthread_main_np, PJT_MAIN_NP, int)
+STUB_FUNC1(pthread_mutex_destroy, PJT_MUTEX_DESTROY, int, void *)
+STUB_FUNC2(pthread_mutex_init, PJT_MUTEX_INIT, int, void *, void *)
+STUB_FUNC1(pthread_mutex_lock, PJT_MUTEX_LOCK, int, void *)
+STUB_FUNC1(pthread_mutex_trylock, PJT_MUTEX_TRYLOCK, int, void *)
+STUB_FUNC1(pthread_mutex_unlock, PJT_MUTEX_UNLOCK, int, void *)
+STUB_FUNC1(pthread_mutex_consistent, PJT_MUTEX_CONSISTENT, int, void *)
+STUB_FUNC1(pthread_mutexattr_destroy, PJT_MUTEXATTR_DESTROY, int, void *)
+STUB_FUNC1(pthread_mutexattr_init, PJT_MUTEXATTR_INIT, int, void *)
+STUB_FUNC2(pthread_mutexattr_settype, PJT_MUTEXATTR_SETTYPE, int, void *, int)
+STUB_FUNC2(pthread_mutexattr_getrobust, PJT_MUTEXATTR_GETROBUST, int, void *,
+ int *)
+STUB_FUNC2(pthread_mutexattr_setrobust, PJT_MUTEXATTR_SETROBUST, int, void *,
+ int)
+STUB_FUNC2(pthread_once, PJT_ONCE, int, void *, void *)
+STUB_FUNC1(pthread_rwlock_destroy, PJT_RWLOCK_DESTROY, int, void *)
+STUB_FUNC2(pthread_rwlock_init, PJT_RWLOCK_INIT, int, void *, void *)
+STUB_FUNC1(pthread_rwlock_rdlock, PJT_RWLOCK_RDLOCK, int, void *)
+STUB_FUNC1(pthread_rwlock_tryrdlock, PJT_RWLOCK_TRYRDLOCK, int, void *)
+STUB_FUNC1(pthread_rwlock_trywrlock, PJT_RWLOCK_TRYWRLOCK, int, void *)
+STUB_FUNC1(pthread_rwlock_unlock, PJT_RWLOCK_UNLOCK, int, void *)
+STUB_FUNC1(pthread_rwlock_wrlock, PJT_RWLOCK_WRLOCK, int, void *)
+STUB_FUNC(pthread_self, PJT_SELF, pthread_t)
+STUB_FUNC2(pthread_setspecific, PJT_SETSPECIFIC, int, pthread_key_t, void *)
+STUB_FUNC3(pthread_sigmask, PJT_SIGMASK, int, int, void *, void *)
+STUB_FUNC3(pthread_atfork, PJT_ATFORK, int, void *, void *, void*)
+STUB_FUNC1(pthread_attr_destroy, PJT_ATTR_DESTROY, int, void *);
+STUB_FUNC2(pthread_attr_getdetachstate, PJT_ATTR_GETDETACHSTATE, int, void *, void *)
+STUB_FUNC2(pthread_attr_getguardsize, PJT_ATTR_GETGUARDSIZE, int, void *, void *)
+STUB_FUNC2(pthread_attr_getstackaddr, PJT_ATTR_GETSTACKADDR, int, void *, void *)
+STUB_FUNC2(pthread_attr_getstacksize, PJT_ATTR_GETSTACKSIZE, int, void *, void *)
+STUB_FUNC2(pthread_attr_getinheritsched, PJT_ATTR_GETINHERITSCHED, int, void *, void *)
+STUB_FUNC2(pthread_attr_getschedparam, PJT_ATTR_GETSCHEDPARAM, int, void *, void *)
+STUB_FUNC2(pthread_attr_getschedpolicy, PJT_ATTR_GETSCHEDPOLICY, int, void *, void *)
+STUB_FUNC2(pthread_attr_getscope, PJT_ATTR_GETSCOPE, int, void *, void *)
+STUB_FUNC1(pthread_attr_init, PJT_ATTR_INIT, int, void *)
+STUB_FUNC2(pthread_attr_setdetachstate, PJT_ATTR_SETDETACHSTATE, int, void *, int)
+STUB_FUNC2(pthread_attr_setguardsize, PJT_ATTR_SETGUARDSIZE, int, void *, size_t)
+STUB_FUNC2(pthread_attr_setstackaddr, PJT_ATTR_SETSTACKADDR, int, void *, void *)
+STUB_FUNC2(pthread_attr_setstacksize, PJT_ATTR_SETSTACKSIZE, int, void *, size_t)
+STUB_FUNC2(pthread_attr_setinheritsched, PJT_ATTR_SETINHERITSCHED, int, void *, int)
+STUB_FUNC2(pthread_attr_setschedparam, PJT_ATTR_SETSCHEDPARAM, int, void *, void *)
+STUB_FUNC2(pthread_attr_setschedpolicy, PJT_ATTR_SETSCHEDPOLICY, int, void *, int)
+STUB_FUNC2(pthread_attr_setscope, PJT_ATTR_SETSCOPE, int, void *, int)
+STUB_FUNC1(pthread_cancel, PJT_CANCEL, int, void *)
+STUB_FUNC1(pthread_cleanup_pop, PJT_CLEANUP_POP, int, int)
+STUB_FUNC2(pthread_cleanup_push, PJT_CLEANUP_PUSH, void, void *, void *)
+STUB_FUNC3(pthread_cond_timedwait, PJT_COND_TIMEDWAIT, int, void *, void *, void *)
+STUB_FUNC1(pthread_detach, PJT_DETACH, int, void *)
+STUB_FUNC2(pthread_equal, PJT_EQUAL, int, void *, void *)
+STUB_FUNC1(pthread_exit, PJT_EXIT, void, void *)
+STUB_FUNC2(pthread_join, PJT_JOIN, int, void *, void *)
+STUB_FUNC2(pthread_kill, PJT_KILL, int, void *, int)
+STUB_FUNC2(pthread_setcancelstate, PJT_SETCANCELSTATE, int, int, void *)
+STUB_FUNC2(pthread_setcanceltype, PJT_SETCANCELTYPE, int, int, void *)
+STUB_FUNC(pthread_testcancel, PJT_TESTCANCEL, void)
+STUB_FUNC1(__pthread_cleanup_pop_imp, PJT_CLEANUP_POP_IMP, int, int)
+STUB_FUNC2(__pthread_cleanup_push_imp, PJT_CLEANUP_PUSH_IMP, void, void*, void *);
+STUB_FUNC1(_pthread_cancel_enter, PJT_CANCEL_ENTER, int, int)
+STUB_FUNC1(_pthread_cancel_leave, PJT_CANCEL_LEAVE, int, int)
+
+static int
+stub_zero(void)
+{
+ return (0);
+}
+
+static void *
+stub_null(void)
+{
+ return (NULL);
+}
+
+static struct pthread *
+stub_self(void)
+{
+ return (&main_thread);
+}
+
+static int
+stub_fail(void)
+{
+ return (ENOSYS);
+}
+
+static int
+stub_main(void)
+{
+ return (-1);
+}
+
+static int
+stub_true(void)
+{
+ return (1);
+}
+
+static void
+stub_exit(void)
+{
+ exit(0);
+}
diff --git a/lib/libc/gen/_rand48.c b/lib/libc/gen/_rand48.c
new file mode 100644
index 000000000000..279bbc362394
--- /dev/null
+++ b/lib/libc/gen/_rand48.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 1993 Martin Birgmeier
+ * All rights reserved.
+ *
+ * You may redistribute unmodified or modified versions of this source
+ * code provided that the above copyright notice and this and the
+ * following conditions are retained.
+ *
+ * This software is provided ``as is'', and comes with no warranties
+ * of any kind. I shall in no event be liable for anything that happens
+ * to anyone/anything when using this software.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "rand48.h"
+
+unsigned short _rand48_seed[3] = {
+ RAND48_SEED_0,
+ RAND48_SEED_1,
+ RAND48_SEED_2
+};
+unsigned short _rand48_mult[3] = {
+ RAND48_MULT_0,
+ RAND48_MULT_1,
+ RAND48_MULT_2
+};
+unsigned short _rand48_add = RAND48_ADD;
+
+void
+_dorand48(unsigned short xseed[3])
+{
+ unsigned long accu;
+ unsigned short temp[2];
+
+ accu = (unsigned long) _rand48_mult[0] * (unsigned long) xseed[0] +
+ (unsigned long) _rand48_add;
+ temp[0] = (unsigned short) accu; /* lower 16 bits */
+ accu >>= sizeof(unsigned short) * 8;
+ accu += (unsigned long) _rand48_mult[0] * (unsigned long) xseed[1] +
+ (unsigned long) _rand48_mult[1] * (unsigned long) xseed[0];
+ temp[1] = (unsigned short) accu; /* middle 16 bits */
+ accu >>= sizeof(unsigned short) * 8;
+ accu += _rand48_mult[0] * xseed[2] + _rand48_mult[1] * xseed[1] + _rand48_mult[2] * xseed[0];
+ xseed[0] = temp[0];
+ xseed[1] = temp[1];
+ xseed[2] = (unsigned short) accu;
+}
diff --git a/lib/libc/gen/_spinlock_stub.c b/lib/libc/gen/_spinlock_stub.c
new file mode 100644
index 000000000000..3decf8a0a565
--- /dev/null
+++ b/lib/libc/gen/_spinlock_stub.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 1998 John Birrell <jb@cimlogic.com.au>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+
+#include "spinlock.h"
+#include "libc_private.h"
+
+long _atomic_lock_stub(volatile long *);
+void _spinlock_stub(spinlock_t *);
+void _spinunlock_stub(spinlock_t *);
+void _spinlock_debug_stub(spinlock_t *, char *, int);
+
+__weak_reference(_atomic_lock_stub, _atomic_lock);
+
+long
+_atomic_lock_stub(volatile long *lck __unused)
+{
+ return (0L);
+}
+
+__weak_reference(_spinlock, _spinlock_debug);
+#pragma weak _spinlock
+void
+_spinlock(spinlock_t *lck)
+{
+
+ ((void (*)(spinlock_t *lck))__libc_interposing[INTERPOS_spinlock])
+ (lck);
+
+}
+
+#pragma weak _spinunlock
+void
+_spinunlock(spinlock_t *lck)
+{
+
+ ((void (*)(spinlock_t *lck))__libc_interposing[INTERPOS_spinunlock])
+ (lck);
+
+}
+
+void
+__libc_spinlock_stub(spinlock_t *lck __unused)
+{
+}
+
+void
+__libc_spinunlock_stub(spinlock_t *lck __unused)
+{
+}
diff --git a/lib/libc/gen/_thread_init.c b/lib/libc/gen/_thread_init.c
new file mode 100644
index 000000000000..c0b6aded38bf
--- /dev/null
+++ b/lib/libc/gen/_thread_init.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2001 Daniel Eischen <deischen@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY DANIEL EISCHEN AND CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+void _thread_init_stub(void);
+
+__weak_reference(_thread_init_stub, _thread_init);
+__weak_reference(_thread_autoinit_dummy_decl_stub,
+ _thread_autoinit_dummy_decl);
+
+int _thread_autoinit_dummy_decl_stub = 0;
+
+void
+_thread_init_stub(void)
+{
+ /* This is just a stub; there is nothing to do. */
+}
diff --git a/lib/libc/gen/alarm.3 b/lib/libc/gen/alarm.3
new file mode 100644
index 000000000000..92817b8fce28
--- /dev/null
+++ b/lib/libc/gen/alarm.3
@@ -0,0 +1,93 @@
+.\" Copyright (c) 1980, 1991, 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)alarm.3 8.2 (Berkeley) 4/19/94
+.\" $FreeBSD$
+.\"
+.Dd April 19, 1994
+.Dt ALARM 3
+.Os
+.Sh NAME
+.Nm alarm
+.Nd set signal timer alarm
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft unsigned int
+.Fn alarm "unsigned int seconds"
+.Sh DESCRIPTION
+.Bf -symbolic
+This interface is made obsolete by
+.Xr setitimer 2 .
+.Ef
+.Pp
+The
+.Fn alarm
+function sets a timer to deliver the signal
+.Dv SIGALRM
+to the calling process after the specified number of
+.Fa seconds .
+If an alarm has already been set with
+.Fn alarm
+but has not been delivered, another call to
+.Fn alarm
+will supersede the prior call.
+The request
+.Fn alarm "0"
+voids the current
+alarm and the signal SIGALRM will not be delivered.
+.Pp
+Due to
+.Xr setitimer 2
+restriction the maximum number of
+.Fa seconds
+allowed is 100000000.
+.Sh RETURN VALUES
+The return value of
+.Fn alarm
+is the amount of time left on the timer from a previous call to
+.Fn alarm .
+If no alarm is currently set, the return value is 0.
+.Sh SEE ALSO
+.Xr setitimer 2 ,
+.Xr sigaction 2 ,
+.Xr sigsuspend 2 ,
+.Xr signal 3 ,
+.Xr sleep 3 ,
+.Xr ualarm 3 ,
+.Xr usleep 3
+.\" .Sh STANDARDS
+.\" The
+.\" .Fn alarm
+.\" function conforms to
+.\" .St -p1003.1-90 .
+.Sh HISTORY
+An
+.Fn alarm
+function appeared in
+.At v7 .
diff --git a/lib/libc/gen/alarm.c b/lib/libc/gen/alarm.c
new file mode 100644
index 000000000000..439a9e138e87
--- /dev/null
+++ b/lib/libc/gen/alarm.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)alarm.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Backwards compatible alarm.
+ */
+#include <sys/time.h>
+#include <unistd.h>
+
+unsigned int
+alarm(unsigned int secs)
+{
+ struct itimerval it, oitv;
+ struct itimerval *itp = &it;
+
+ timerclear(&itp->it_interval);
+ itp->it_value.tv_sec = secs;
+ itp->it_value.tv_usec = 0;
+ if (setitimer(ITIMER_REAL, itp, &oitv) < 0)
+ return (-1);
+ if (oitv.it_value.tv_usec)
+ oitv.it_value.tv_sec++;
+ return (oitv.it_value.tv_sec);
+}
diff --git a/lib/libc/gen/arc4random.3 b/lib/libc/gen/arc4random.3
new file mode 100644
index 000000000000..e1124c622e77
--- /dev/null
+++ b/lib/libc/gen/arc4random.3
@@ -0,0 +1,127 @@
+.\" $OpenBSD: arc4random.3,v 1.2 1997/04/27 22:40:25 angelos Exp $
+.\" Copyright 1997 Niels Provos <provos@physnet.uni-hamburg.de>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by Niels Provos.
+.\" 4. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" Manual page, using -mandoc macros
+.\" $FreeBSD$
+.\"
+.Dd April 15, 1997
+.Dt ARC4RANDOM 3
+.Os
+.Sh NAME
+.Nm arc4random ,
+.Nm arc4random_buf ,
+.Nm arc4random_uniform ,
+.Nm arc4random_stir ,
+.Nm arc4random_addrandom
+.Nd arc4 random number generator
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft uint32_t
+.Fn arc4random "void"
+.Ft void
+.Fn arc4random_buf "void *buf" "size_t nbytes"
+.Ft uint32_t
+.Fn arc4random_uniform "uint32_t upper_bound"
+.Ft void
+.Fn arc4random_stir "void"
+.Ft void
+.Fn arc4random_addrandom "unsigned char *dat" "int datlen"
+.Sh DESCRIPTION
+The
+.Fn arc4random
+function uses the key stream generator employed by the
+arc4 cipher, which uses 8*8 8 bit S-Boxes.
+The S-Boxes
+can be in about
+.if t 2\u\s71700\s10\d
+.if n (2**1700)
+states.
+The
+.Fn arc4random
+function returns pseudo-random numbers in the range of 0 to
+.if t 2\u\s731\s10\d\(mi1,
+.if n (2**32)\(mi1,
+and therefore has twice the range of
+.Xr rand 3
+and
+.Xr random 3 .
+.Pp
+.Fn arc4random_buf
+function fills the region
+.Fa buf
+of length
+.Fa nbytes
+with ARC4-derived random data.
+.Pp
+.Fn arc4random_uniform
+will return a uniformly distributed random number less than
+.Fa upper_bound .
+.Fn arc4random_uniform
+is recommended over constructions like
+.Dq Li arc4random() % upper_bound
+as it avoids "modulo bias" when the upper bound is not a power of two.
+.Pp
+The
+.Fn arc4random_stir
+function reads data from
+.Pa /dev/urandom
+and uses it to permute the S-Boxes via
+.Fn arc4random_addrandom .
+.Pp
+There is no need to call
+.Fn arc4random_stir
+before using
+.Fn arc4random
+functions family, since
+they automatically initialize themselves.
+.Sh EXAMPLES
+The following produces a drop-in replacement for the traditional
+.Fn rand
+and
+.Fn random
+functions using
+.Fn arc4random :
+.Pp
+.Dl "#define foo4random() (arc4random() % ((unsigned)RAND_MAX + 1))"
+.Sh SEE ALSO
+.Xr rand 3 ,
+.Xr random 3 ,
+.Xr srandomdev 3
+.Sh HISTORY
+.Pa RC4
+has been designed by RSA Data Security, Inc.
+It was posted anonymously
+to the USENET and was confirmed to be equivalent by several sources who
+had access to the original cipher.
+Since
+.Pa RC4
+used to be a trade secret, the cipher is now referred to as
+.Pa ARC4 .
diff --git a/lib/libc/gen/arc4random.c b/lib/libc/gen/arc4random.c
new file mode 100644
index 000000000000..becc17bc2711
--- /dev/null
+++ b/lib/libc/gen/arc4random.c
@@ -0,0 +1,302 @@
+/* $OpenBSD: arc4random.c,v 1.24 2013/06/11 16:59:50 deraadt Exp $ */
+
+/*
+ * Copyright (c) 1996, David Mazieres <dm@uun.org>
+ * Copyright (c) 2008, Damien Miller <djm@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.
+ */
+
+/*
+ * Arc4 random number generator for OpenBSD.
+ *
+ * This code is derived from section 17.1 of Applied Cryptography,
+ * second edition, which describes a stream cipher allegedly
+ * compatible with RSA Labs "RC4" cipher (the actual description of
+ * which is a trade secret). The same algorithm is used as a stream
+ * cipher called "arcfour" in Tatu Ylonen's ssh package.
+ *
+ * RC4 is a registered trademark of RSA Laboratories.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <fcntl.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <sys/time.h>
+#include <pthread.h>
+
+#include "libc_private.h"
+#include "un-namespace.h"
+
+#ifdef __GNUC__
+#define inline __inline
+#else /* !__GNUC__ */
+#define inline
+#endif /* !__GNUC__ */
+
+struct arc4_stream {
+ u_int8_t i;
+ u_int8_t j;
+ u_int8_t s[256];
+};
+
+static pthread_mutex_t arc4random_mtx = PTHREAD_MUTEX_INITIALIZER;
+
+#define RANDOMDEV "/dev/random"
+#define KEYSIZE 128
+#define _ARC4_LOCK() \
+ do { \
+ if (__isthreaded) \
+ _pthread_mutex_lock(&arc4random_mtx); \
+ } while (0)
+
+#define _ARC4_UNLOCK() \
+ do { \
+ if (__isthreaded) \
+ _pthread_mutex_unlock(&arc4random_mtx); \
+ } while (0)
+
+static int rs_initialized;
+static struct arc4_stream rs;
+static pid_t arc4_stir_pid;
+static int arc4_count;
+
+extern int __sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
+ void *newp, size_t newlen);
+
+static inline u_int8_t arc4_getbyte(void);
+static void arc4_stir(void);
+
+static inline void
+arc4_init(void)
+{
+ int n;
+
+ for (n = 0; n < 256; n++)
+ rs.s[n] = n;
+ rs.i = 0;
+ rs.j = 0;
+}
+
+static inline void
+arc4_addrandom(u_char *dat, int datlen)
+{
+ int n;
+ u_int8_t si;
+
+ rs.i--;
+ for (n = 0; n < 256; n++) {
+ rs.i = (rs.i + 1);
+ si = rs.s[rs.i];
+ rs.j = (rs.j + si + dat[n % datlen]);
+ rs.s[rs.i] = rs.s[rs.j];
+ rs.s[rs.j] = si;
+ }
+ rs.j = rs.i;
+}
+
+static size_t
+arc4_sysctl(u_char *buf, size_t size)
+{
+ int mib[2];
+ size_t len, done;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_ARND;
+ done = 0;
+
+ do {
+ len = size;
+ if (__sysctl(mib, 2, buf, &len, NULL, 0) == -1)
+ return (done);
+ done += len;
+ buf += len;
+ size -= len;
+ } while (size > 0);
+
+ return (done);
+}
+
+static void
+arc4_stir(void)
+{
+ u_char rdat[KEYSIZE];
+ int i;
+
+ if (!rs_initialized) {
+ arc4_init();
+ rs_initialized = 1;
+ }
+ if (arc4_sysctl(rdat, KEYSIZE) != KEYSIZE) {
+ /*
+ * The sysctl cannot fail. If it does fail on some FreeBSD
+ * derivative or after some future change, just abort so that
+ * the problem will be found and fixed. abort is not normally
+ * suitable for a library but makes sense here.
+ */
+ abort();
+ }
+
+ arc4_addrandom(rdat, KEYSIZE);
+
+ /*
+ * Discard early keystream, as per recommendations in:
+ * "(Not So) Random Shuffles of RC4" by Ilya Mironov.
+ */
+ for (i = 0; i < 1024; i++)
+ (void)arc4_getbyte();
+ arc4_count = 1600000;
+}
+
+static void
+arc4_stir_if_needed(void)
+{
+ pid_t pid = getpid();
+
+ if (arc4_count <= 0 || !rs_initialized || arc4_stir_pid != pid) {
+ arc4_stir_pid = pid;
+ arc4_stir();
+ }
+}
+
+static inline u_int8_t
+arc4_getbyte(void)
+{
+ u_int8_t si, sj;
+
+ rs.i = (rs.i + 1);
+ si = rs.s[rs.i];
+ rs.j = (rs.j + si);
+ sj = rs.s[rs.j];
+ rs.s[rs.i] = sj;
+ rs.s[rs.j] = si;
+ return (rs.s[(si + sj) & 0xff]);
+}
+
+static inline u_int32_t
+arc4_getword(void)
+{
+ u_int32_t val;
+ val = arc4_getbyte() << 24;
+ val |= arc4_getbyte() << 16;
+ val |= arc4_getbyte() << 8;
+ val |= arc4_getbyte();
+ return val;
+}
+
+void
+arc4random_stir(void)
+{
+ _ARC4_LOCK();
+ arc4_stir();
+ _ARC4_UNLOCK();
+}
+
+void
+arc4random_addrandom(u_char *dat, int datlen)
+{
+ _ARC4_LOCK();
+ if (!rs_initialized)
+ arc4_stir();
+ arc4_addrandom(dat, datlen);
+ _ARC4_UNLOCK();
+}
+
+u_int32_t
+arc4random(void)
+{
+ u_int32_t val;
+ _ARC4_LOCK();
+ arc4_count -= 4;
+ arc4_stir_if_needed();
+ val = arc4_getword();
+ _ARC4_UNLOCK();
+ return val;
+}
+
+void
+arc4random_buf(void *_buf, size_t n)
+{
+ u_char *buf = (u_char *)_buf;
+ _ARC4_LOCK();
+ arc4_stir_if_needed();
+ while (n--) {
+ if (--arc4_count <= 0)
+ arc4_stir();
+ buf[n] = arc4_getbyte();
+ }
+ _ARC4_UNLOCK();
+}
+
+/*
+ * Calculate a uniformly distributed random number less than upper_bound
+ * avoiding "modulo bias".
+ *
+ * Uniformity is achieved by generating new random numbers until the one
+ * returned is outside the range [0, 2**32 % upper_bound). This
+ * guarantees the selected random number will be inside
+ * [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound)
+ * after reduction modulo upper_bound.
+ */
+u_int32_t
+arc4random_uniform(u_int32_t upper_bound)
+{
+ u_int32_t r, min;
+
+ if (upper_bound < 2)
+ return 0;
+
+ /* 2**32 % x == (2**32 - x) % x */
+ min = -upper_bound % upper_bound;
+ /*
+ * This could theoretically loop forever but each retry has
+ * p > 0.5 (worst case, usually far better) of selecting a
+ * number inside the range we need, so it should rarely need
+ * to re-roll.
+ */
+ for (;;) {
+ r = arc4random();
+ if (r >= min)
+ break;
+ }
+
+ return r % upper_bound;
+}
+
+#if 0
+/*-------- Test code for i386 --------*/
+#include <stdio.h>
+#include <machine/pctr.h>
+int
+main(int argc, char **argv)
+{
+ const int iter = 1000000;
+ int i;
+ pctrval v;
+
+ v = rdtsc();
+ for (i = 0; i < iter; i++)
+ arc4random();
+ v = rdtsc() - v;
+ v /= iter;
+
+ printf("%qd cycles\n", v);
+}
+#endif
diff --git a/lib/libc/gen/assert.c b/lib/libc/gen/assert.c
new file mode 100644
index 000000000000..ccbc7a4bd0d6
--- /dev/null
+++ b/lib/libc/gen/assert.c
@@ -0,0 +1,53 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)assert.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+void
+__assert(const char *func, const char *file, int line, const char *failedexpr)
+{
+ if (func == NULL)
+ (void)fprintf(stderr,
+ "Assertion failed: (%s), file %s, line %d.\n", failedexpr,
+ file, line);
+ else
+ (void)fprintf(stderr,
+ "Assertion failed: (%s), function %s, file %s, line %d.\n",
+ failedexpr, func, file, line);
+ abort();
+ /* NOTREACHED */
+}
diff --git a/lib/libc/gen/auxv.c b/lib/libc/gen/auxv.c
new file mode 100644
index 000000000000..3767ac0a263c
--- /dev/null
+++ b/lib/libc/gen/auxv.c
@@ -0,0 +1,186 @@
+/*-
+ * Copyright 2010, 2012 Konstantin Belousov <kib@FreeBSD.ORG>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <elf.h>
+#include <errno.h>
+#include <link.h>
+#include <pthread.h>
+#include <string.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+
+extern char **environ;
+extern int _DYNAMIC;
+#pragma weak _DYNAMIC
+
+void *__elf_aux_vector;
+static pthread_once_t aux_vector_once = PTHREAD_ONCE_INIT;
+
+static void
+init_aux_vector_once(void)
+{
+ Elf_Addr *sp;
+
+ sp = (Elf_Addr *)environ;
+ while (*sp++ != 0)
+ ;
+ __elf_aux_vector = (Elf_Auxinfo *)sp;
+}
+
+void
+__init_elf_aux_vector(void)
+{
+
+ if (&_DYNAMIC != NULL)
+ return;
+ _once(&aux_vector_once, init_aux_vector_once);
+}
+
+static pthread_once_t aux_once = PTHREAD_ONCE_INIT;
+static int pagesize, osreldate, canary_len, ncpus, pagesizes_len;
+static char *canary, *pagesizes;
+static void *timekeep;
+
+static void
+init_aux(void)
+{
+ Elf_Auxinfo *aux;
+
+ for (aux = __elf_aux_vector; aux->a_type != AT_NULL; aux++) {
+ switch (aux->a_type) {
+ case AT_CANARY:
+ canary = (char *)(aux->a_un.a_ptr);
+ break;
+
+ case AT_CANARYLEN:
+ canary_len = aux->a_un.a_val;
+ break;
+
+ case AT_PAGESIZES:
+ pagesizes = (char *)(aux->a_un.a_ptr);
+ break;
+
+ case AT_PAGESIZESLEN:
+ pagesizes_len = aux->a_un.a_val;
+ break;
+
+ case AT_PAGESZ:
+ pagesize = aux->a_un.a_val;
+ break;
+
+ case AT_OSRELDATE:
+ osreldate = aux->a_un.a_val;
+ break;
+
+ case AT_NCPUS:
+ ncpus = aux->a_un.a_val;
+ break;
+
+ case AT_TIMEKEEP:
+ timekeep = aux->a_un.a_ptr;
+ break;
+ }
+ }
+}
+
+int
+_elf_aux_info(int aux, void *buf, int buflen)
+{
+ int res;
+
+ __init_elf_aux_vector();
+ if (__elf_aux_vector == NULL)
+ return (ENOSYS);
+ _once(&aux_once, init_aux);
+
+ switch (aux) {
+ case AT_CANARY:
+ if (canary != NULL && canary_len >= buflen) {
+ memcpy(buf, canary, buflen);
+ memset(canary, 0, canary_len);
+ canary = NULL;
+ res = 0;
+ } else
+ res = ENOENT;
+ break;
+ case AT_PAGESIZES:
+ if (pagesizes != NULL && pagesizes_len >= buflen) {
+ memcpy(buf, pagesizes, buflen);
+ res = 0;
+ } else
+ res = ENOENT;
+ break;
+
+ case AT_PAGESZ:
+ if (buflen == sizeof(int)) {
+ if (pagesize != 0) {
+ *(int *)buf = pagesize;
+ res = 0;
+ } else
+ res = ENOENT;
+ } else
+ res = EINVAL;
+ break;
+ case AT_OSRELDATE:
+ if (buflen == sizeof(int)) {
+ if (osreldate != 0) {
+ *(int *)buf = osreldate;
+ res = 0;
+ } else
+ res = ENOENT;
+ } else
+ res = EINVAL;
+ break;
+ case AT_NCPUS:
+ if (buflen == sizeof(int)) {
+ if (ncpus != 0) {
+ *(int *)buf = ncpus;
+ res = 0;
+ } else
+ res = ENOENT;
+ } else
+ res = EINVAL;
+ break;
+ case AT_TIMEKEEP:
+ if (buflen == sizeof(void *)) {
+ if (timekeep != NULL) {
+ *(void **)buf = timekeep;
+ res = 0;
+ } else
+ res = ENOENT;
+ } else
+ res = EINVAL;
+ break;
+ default:
+ res = ENOENT;
+ break;
+ }
+ return (res);
+}
diff --git a/lib/libc/gen/basename.3 b/lib/libc/gen/basename.3
new file mode 100644
index 000000000000..51a90e404746
--- /dev/null
+++ b/lib/libc/gen/basename.3
@@ -0,0 +1,88 @@
+.\" $OpenBSD: basename.3,v 1.20 2007/05/31 19:19:28 jmc Exp $
+.\"
+.\" Copyright (c) 1997 Todd C. Miller <Todd.Miller@courtesan.com>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd October 29, 2016
+.Dt BASENAME 3
+.Os
+.Sh NAME
+.Nm basename
+.Nd extract the base portion of a pathname
+.Sh SYNOPSIS
+.In libgen.h
+.Ft char *
+.Fn basename "char *path"
+.Sh DESCRIPTION
+The
+.Fn basename
+function returns the last component from the pathname pointed to by
+.Fa path ,
+deleting any trailing
+.Sq \&/
+characters.
+.Sh RETURN VALUES
+If
+.Fa path
+consists entirely of
+.Sq \&/
+characters, a pointer to the string
+.Qq \&/
+is returned.
+If
+.Fa path
+is a null pointer or the empty string, a pointer to the string
+.Qq \&.
+is returned.
+Otherwise,
+it returns a pointer to the last component of
+.Fa path .
+.Sh IMPLEMENTATION NOTES
+This implementation of
+.Fn basename
+uses the buffer provided by the caller to store the resulting pathname
+component.
+Other vendor implementations may return a pointer to internal storage
+space instead.
+The advantage of the former approach is that it ensures thread-safety,
+while also placing no upper limit on the supported length of the
+pathname.
+.Sh SEE ALSO
+.Xr basename 1 ,
+.Xr dirname 1 ,
+.Xr dirname 3
+.Sh STANDARDS
+The
+.Fn basename
+function conforms to
+.St -xpg4.2 .
+.Sh HISTORY
+The
+.Fn basename
+function first appeared in
+.Ox 2.2
+and
+.Fx 4.2 .
+.Pp
+In
+.Fx 12.0 ,
+this function was reimplemented to store its result in the provided
+input buffer.
+There is no longer any need to use the
+.Fn basename_r
+function.
+.Sh AUTHORS
+.An Nuxi, the Netherlands
diff --git a/lib/libc/gen/basename.c b/lib/libc/gen/basename.c
new file mode 100644
index 000000000000..7569ab9c3029
--- /dev/null
+++ b/lib/libc/gen/basename.c
@@ -0,0 +1,54 @@
+/*-
+ * Copyright (c) 2015-2016 Nuxi, https://nuxi.nl/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <libgen.h>
+#include <string.h>
+
+char *
+(basename)(char *path)
+{
+ char *ptr;
+
+ /*
+ * If path is a null pointer or points to an empty string,
+ * basename() shall return a pointer to the string ".".
+ */
+ if (path == NULL || *path == '\0')
+ return (__DECONST(char *, "."));
+
+ /* Find end of last pathname component and null terminate it. */
+ ptr = path + strlen(path);
+ while (ptr > path + 1 && *(ptr - 1) == '/')
+ --ptr;
+ *ptr-- = '\0';
+
+ /* Find beginning of last pathname component. */
+ while (ptr > path && *(ptr - 1) != '/')
+ --ptr;
+ return (ptr);
+}
diff --git a/lib/libc/gen/basename_compat.c b/lib/libc/gen/basename_compat.c
new file mode 100644
index 000000000000..f6ce7f9a1f43
--- /dev/null
+++ b/lib/libc/gen/basename_compat.c
@@ -0,0 +1,81 @@
+/* $OpenBSD: basename.c,v 1.14 2005/08/08 08:05:33 espie Exp $ */
+
+/*
+ * Copyright (c) 1997, 2004 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <libgen.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/param.h>
+
+char *
+basename_r(const char *path, char *bname)
+{
+ const char *endp, *startp;
+ size_t len;
+
+ /* Empty or NULL string gets treated as "." */
+ if (path == NULL || *path == '\0') {
+ bname[0] = '.';
+ bname[1] = '\0';
+ return (bname);
+ }
+
+ /* Strip any trailing slashes */
+ endp = path + strlen(path) - 1;
+ while (endp > path && *endp == '/')
+ endp--;
+
+ /* All slashes becomes "/" */
+ if (endp == path && *endp == '/') {
+ bname[0] = '/';
+ bname[1] = '\0';
+ return (bname);
+ }
+
+ /* Find the start of the base */
+ startp = endp;
+ while (startp > path && *(startp - 1) != '/')
+ startp--;
+
+ len = endp - startp + 1;
+ if (len >= MAXPATHLEN) {
+ errno = ENAMETOOLONG;
+ return (NULL);
+ }
+ memcpy(bname, startp, len);
+ bname[len] = '\0';
+ return (bname);
+}
+
+char *
+__freebsd11_basename(char *path)
+{
+ static char *bname = NULL;
+
+ if (bname == NULL) {
+ bname = (char *)malloc(MAXPATHLEN);
+ if (bname == NULL)
+ return (NULL);
+ }
+ return (basename_r(path, bname));
+}
+
+__sym_compat(basename, __freebsd11_basename, FBSD_1.0);
diff --git a/lib/libc/gen/cap_rights_get.3 b/lib/libc/gen/cap_rights_get.3
new file mode 100644
index 000000000000..a665465e5339
--- /dev/null
+++ b/lib/libc/gen/cap_rights_get.3
@@ -0,0 +1,119 @@
+.\"
+.\" Copyright (c) 2013 The FreeBSD Foundation
+.\" All rights reserved.
+.\"
+.\" This documentation was written 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 March 27, 2014
+.Dt CAP_RIGHTS_GET 3
+.Os
+.Sh NAME
+.Nm cap_rights_get
+.Nd obtain capability rights
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/capsicum.h
+.Ft int
+.Fn cap_rights_get "int fd" "cap_rights_t *rights"
+.Sh DESCRIPTION
+The
+.Nm cap_rights_get
+function allows to obtain current capability rights for the given descriptor.
+The function will fill the
+.Fa rights
+argument with all capability rights if they were not limited or capability
+rights configured during the last successful call of
+.Xr cap_rights_limit 2
+on the given descriptor.
+.Pp
+The
+.Fa rights
+argument can be inspected using
+.Xr cap_rights_init 3
+family of functions.
+.Pp
+The complete list of the capability rights can be found in the
+.Xr rights 4
+manual page.
+.Sh RETURN VALUES
+.Rv -std
+.Sh EXAMPLES
+The following example demonstrates how to limit file descriptor capability
+rights and how to obtain them.
+.Bd -literal
+cap_rights_t setrights, getrights;
+int fd;
+
+memset(&setrights, 0, sizeof(setrights));
+memset(&getrights, 0, sizeof(getrights));
+
+fd = open("/tmp/foo", O_RDONLY);
+if (fd < 0)
+ err(1, "open() failed");
+
+cap_rights_init(&setrights, CAP_FSTAT, CAP_READ);
+if (cap_rights_limit(fd, &setrights) < 0 && errno != ENOSYS)
+ err(1, "cap_rights_limit() failed");
+
+if (cap_rights_get(fd, &getrights) < 0 && errno != ENOSYS)
+ err(1, "cap_rights_get() failed");
+
+assert(memcmp(&setrights, &getrights, sizeof(setrights)) == 0);
+.Ed
+.Sh ERRORS
+.Fn cap_rights_get
+succeeds unless:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa fd
+argument is not a valid active descriptor.
+.It Bq Er EFAULT
+The
+.Fa rights
+argument points at an invalid address.
+.El
+.Sh SEE ALSO
+.Xr cap_rights_limit 2 ,
+.Xr errno 2 ,
+.Xr open 2 ,
+.Xr assert 3 ,
+.Xr cap_rights_init 3 ,
+.Xr err 3 ,
+.Xr memcmp 3 ,
+.Xr memset 3 ,
+.Xr capsicum 4 ,
+.Xr rights 4
+.Sh HISTORY
+Support for capabilities and capabilities mode was developed as part of the
+.Tn TrustedBSD
+Project.
+.Sh AUTHORS
+This function was created by
+.An Pawel Jakub Dawidek Aq Mt pawel@dawidek.net
+under sponsorship of the FreeBSD Foundation.
diff --git a/lib/libc/gen/cap_sandboxed.3 b/lib/libc/gen/cap_sandboxed.3
new file mode 100644
index 000000000000..5882ff002789
--- /dev/null
+++ b/lib/libc/gen/cap_sandboxed.3
@@ -0,0 +1,71 @@
+.\"
+.\" Copyright (c) 2012 The FreeBSD Foundation
+.\" All rights reserved.
+.\"
+.\" This documentation was written 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 March 27, 2014
+.Dt CAP_SANDBOXED 3
+.Os
+.Sh NAME
+.Nm cap_sandboxed
+.Nd Check if in a capability mode sandbox
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/capsicum.h
+.In stdbool.h
+.Ft bool
+.Fn cap_sandboxed "void"
+.Sh DESCRIPTION
+.Fn cap_sandboxed
+returns
+.Va true
+if the process is in a capability mode sandbox or
+.Va false
+if it is not.
+This function is a more handy alternative to the
+.Xr cap_getmode 2
+system call as it always succeeds, so there is no need for error checking.
+If the support for capability mode is not compiled into the kernel,
+.Fn cap_sandboxed
+will always return
+.Va false .
+.Sh RETURN VALUES
+Function
+.Fn cap_sandboxed
+is always successful and will return either
+.Va true
+or
+.Va false .
+.Sh SEE ALSO
+.Xr cap_enter 2 ,
+.Xr capsicum 4
+.Sh AUTHORS
+This function was implemented and manual page was written by
+.An Pawel Jakub Dawidek Aq Mt pawel@dawidek.net
+under sponsorship of the FreeBSD Foundation.
diff --git a/lib/libc/gen/cap_sandboxed.c b/lib/libc/gen/cap_sandboxed.c
new file mode 100644
index 000000000000..ec2d4db334a7
--- /dev/null
+++ b/lib/libc/gen/cap_sandboxed.c
@@ -0,0 +1,50 @@
+/*-
+ * Copyright (c) 2012 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/capsicum.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+
+bool
+cap_sandboxed(void)
+{
+ u_int mode;
+
+ if (cap_getmode(&mode) != 0) {
+ assert(errno == ENOSYS);
+ return (false);
+ }
+ assert(mode == 0 || mode == 1);
+ return (mode == 1);
+}
diff --git a/lib/libc/gen/check_utility_compat.3 b/lib/libc/gen/check_utility_compat.3
new file mode 100644
index 000000000000..89449a4064bb
--- /dev/null
+++ b/lib/libc/gen/check_utility_compat.3
@@ -0,0 +1,89 @@
+.\"
+.\" Copyright 2002 Massachusetts Institute of Technology
+.\"
+.\" Permission to use, copy, modify, and distribute this software and
+.\" its documentation for any purpose and without fee is hereby
+.\" granted, provided that both the above copyright notice and this
+.\" permission notice appear in all copies, that both the above
+.\" copyright notice and this permission notice appear in all
+.\" supporting documentation, and that the name of M.I.T. not be used
+.\" in advertising or publicity pertaining to distribution of the
+.\" software without specific, written prior permission. M.I.T. makes
+.\" no representations about the suitability of this software for any
+.\" purpose. It is provided "as is" without express or implied
+.\" warranty.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
+.\" ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
+.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
+.\" SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+.\" USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+.\" ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+.\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+.\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd October 27, 2002
+.Dt CHECK_UTILITY_COMPAT 3
+.Os
+.Sh NAME
+.Nm check_utility_compat
+.Nd "determine whether a utility should be compatible"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft int
+.Fn check_utility_compat "const char *utility"
+.Sh DESCRIPTION
+The
+.Fn check_utility_compat
+function checks whether
+.Fa utility
+should behave in a traditional
+.Pq Fx 4.7 Ns -compatible
+manner, or in accordance with
+.St -p1003.1-2001 .
+The configuration is given as a comma-separated list of utility names;
+if the list is present but empty, all supported utilities assume their
+most compatible mode.
+The
+.Fn check_utility_compat
+function first checks for an environment variable named
+.Ev _COMPAT_FreeBSD_4 .
+If that environment variable does not exist, then
+.Fn check_utility_compat
+will attempt to read the contents of a symbolic link named
+.Pa /etc/compat-FreeBSD-4-util .
+If no configuration is found, compatibility mode is disabled.
+.Sh RETURN VALUES
+The
+.Fn check_utility_compat
+function returns zero if
+.Fa utility
+should implement strict
+.St -p1003.1-2001
+behavior, and nonzero otherwise.
+.Sh FILES
+.Bl -tag -width ".Pa /etc/compat-FreeBSD-4-util"
+.It Pa /etc/compat-FreeBSD-4-util
+If present, a symbolic link whose expansion gives system-wide default settings
+for the
+.Fn check_utility_compat
+function.
+.El
+.Sh ERRORS
+No errors are detected.
+.Sh HISTORY
+The
+.Fn check_utility_compat
+function first appeared in
+.Fx 5.0 .
+.Sh AUTHORS
+This manual page was written by
+.An Garrett Wollman Aq Mt wollman@FreeBSD.org .
diff --git a/lib/libc/gen/check_utility_compat.c b/lib/libc/gen/check_utility_compat.c
new file mode 100644
index 000000000000..04c594b52665
--- /dev/null
+++ b/lib/libc/gen/check_utility_compat.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2002 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that both the above copyright notice and this
+ * permission notice appear in all copies, that both the above
+ * copyright notice and this permission notice appear in all
+ * supporting documentation, and that the name of M.I.T. not be used
+ * in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission. M.I.T. makes
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied
+ * warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
+ * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
+ * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * I din't use "namespace.h" here because none of the relevant utilities
+ * are threaded, so I'm not concerned about cancellation points or other
+ * niceties.
+ */
+#include <sys/limits.h>
+
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define _PATH_UTIL_COMPAT "/etc/compat-FreeBSD-4-util"
+#define _ENV_UTIL_COMPAT "_COMPAT_FreeBSD_4"
+
+int
+check_utility_compat(const char *utility)
+{
+ char buf[PATH_MAX];
+ char *p, *bp;
+ int len;
+
+ if ((p = getenv(_ENV_UTIL_COMPAT)) != NULL) {
+ strlcpy(buf, p, sizeof buf);
+ } else {
+ if ((len = readlink(_PATH_UTIL_COMPAT, buf, sizeof(buf) - 1)) < 0)
+ return 0;
+ buf[len] = '\0';
+ }
+ if (buf[0] == '\0')
+ return 1;
+
+ bp = buf;
+ while ((p = strsep(&bp, ",")) != NULL) {
+ if (strcmp(p, utility) == 0)
+ return 1;
+ }
+ return 0;
+}
diff --git a/lib/libc/gen/clock.3 b/lib/libc/gen/clock.3
new file mode 100644
index 000000000000..6a585e57df7e
--- /dev/null
+++ b/lib/libc/gen/clock.3
@@ -0,0 +1,76 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)clock.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt CLOCK 3
+.Os
+.Sh NAME
+.Nm clock
+.Nd determine processor time used
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In time.h
+.Ft clock_t
+.Fn clock void
+.Sh DESCRIPTION
+The
+.Fn clock
+function
+determines the amount of processor time used since the invocation of the
+calling process, measured in
+.Dv CLOCKS_PER_SEC Ns s
+of a second.
+.Sh RETURN VALUES
+The
+.Fn clock
+function returns the amount of time used unless an error occurs, in which
+case the return value is \-1.
+.Sh SEE ALSO
+.Xr getrusage 2 ,
+.Xr clocks 7
+.Sh STANDARDS
+The
+.Fn clock
+function conforms to
+.St -isoC .
+However,
+.St -susv2
+requires
+.Dv CLOCKS_PER_SEC
+to be defined as one million.
+.Fx
+does not conform to this requirement;
+changing the value would introduce binary incompatibility
+and one million is still inadequate on modern processors.
diff --git a/lib/libc/gen/clock.c b/lib/libc/gen/clock.c
new file mode 100644
index 000000000000..435e0f827432
--- /dev/null
+++ b/lib/libc/gen/clock.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)clock.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+/*
+ * Convert usec to clock ticks; could do (usec * CLOCKS_PER_SEC) / 1000000,
+ * but this would overflow if we switch to nanosec.
+ */
+#define CONVTCK(r) ((r).tv_sec * CLOCKS_PER_SEC \
+ + (r).tv_usec / (1000000 / CLOCKS_PER_SEC))
+
+clock_t
+clock(void)
+{
+ struct rusage ru;
+
+ if (getrusage(RUSAGE_SELF, &ru))
+ return ((clock_t) -1);
+ return((clock_t)((CONVTCK(ru.ru_utime) + CONVTCK(ru.ru_stime))));
+}
diff --git a/lib/libc/gen/clock_getcpuclockid.3 b/lib/libc/gen/clock_getcpuclockid.3
new file mode 100644
index 000000000000..7a476846f51e
--- /dev/null
+++ b/lib/libc/gen/clock_getcpuclockid.3
@@ -0,0 +1,97 @@
+.\" Copyright (c) 2012 David Xu <davidxu@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" Portions of this text are reprinted and reproduced in electronic form
+.\" from IEEE Std 1003.1, 2004 Edition, Standard for Information Technology --
+.\" Portable Operating System Interface (POSIX), The Open Group Base
+.\" Specifications Issue 6, Copyright (C) 2001-2004 by the Institute of
+.\" Electrical and Electronics Engineers, Inc and The Open Group. In the
+.\" event of any discrepancy between this version and the original IEEE and
+.\" The Open Group Standard, the original IEEE and The Open Group Standard is
+.\" the referee document. The original Standard can be obtained online at
+.\" http://www.opengroup.org/unix/online.html.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd August 21, 2012
+.Dt CLOCK_GETCPUCLOCKID 3
+.Os
+.Sh NAME
+.Nm clock_getcpuclockid
+.Nd access a process CPU-time clock
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In time.h
+.Ft int
+.Fn clock_getcpuclockid "pid_t pid" "clockid_t *clock_id"
+.Sh DESCRIPTION
+The
+.Fn clock_getcpuclockid
+returns the clock ID of the CPU-time clock of the process specified by
+.Fa pid .
+If the process described by
+.Fa pid
+exists and the calling process has permission, the clock ID of this
+clock will be returned in
+.Fa clock_id .
+.Pp
+If
+.Fa pid
+is zero, the
+.Fn clock_getcpuclockid
+function returns the clock ID of the CPU-time clock of the process
+making the call, in
+.Fa clock_id .
+.Sh RETURN VALUES
+Upon successful completion,
+.Fn clock_getcpuclockid
+returns zero; otherwise, an error number is returned to indicate the
+error.
+.Sh ERRORS
+The
+.Fn clock_getcpuclockid
+function will fail if:
+.Bl -tag -width Er
+.It Bq Er EPERM
+The requesting process does not have permission to access the CPU-time
+clock for the process.
+.It Bq Er ESRCH
+No process can be found corresponding to the process specified by
+.Fa pid .
+.El
+.Sh SEE ALSO
+.Xr clock_gettime 2
+.Sh STANDARDS
+The
+.Fn clock_getcpuclockid
+function conforms to
+.St -p1003.1-2001 .
+.Sh HISTORY
+The
+.Fn clock_getcpuclockid
+function first appeared in
+.Fx 10.0 .
+.Sh AUTHORS
+.An David Xu Aq Mt davidxu@FreeBSD.org
diff --git a/lib/libc/gen/clock_getcpuclockid.c b/lib/libc/gen/clock_getcpuclockid.c
new file mode 100644
index 000000000000..f26035f421fa
--- /dev/null
+++ b/lib/libc/gen/clock_getcpuclockid.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2012 David Xu <davidxu@FreeBSD.org>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY DANIEL EISCHEN AND CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/time.h>
+
+int
+clock_getcpuclockid(pid_t pid, clockid_t *clock_id)
+{
+ if (clock_getcpuclockid2(pid, CPUCLOCK_WHICH_PID, clock_id))
+ return (errno);
+ return (0);
+}
diff --git a/lib/libc/gen/closedir.c b/lib/libc/gen/closedir.c
new file mode 100644
index 000000000000..88ded37be51f
--- /dev/null
+++ b/lib/libc/gen/closedir.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 1983, 1993
+ * Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)closedir.c 8.1 (Berkeley) 6/10/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <dirent.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+#include "libc_private.h"
+#include "gen-private.h"
+#include "telldir.h"
+
+/*
+ * close a directory.
+ */
+int
+fdclosedir(DIR *dirp)
+{
+ int fd;
+
+ if (__isthreaded)
+ _pthread_mutex_lock(&dirp->dd_lock);
+ fd = dirp->dd_fd;
+ dirp->dd_fd = -1;
+ dirp->dd_loc = 0;
+ free((void *)dirp->dd_buf);
+ _reclaim_telldir(dirp);
+ if (__isthreaded) {
+ _pthread_mutex_unlock(&dirp->dd_lock);
+ _pthread_mutex_destroy(&dirp->dd_lock);
+ }
+ free((void *)dirp);
+ return (fd);
+}
+
+int
+closedir(DIR *dirp)
+{
+
+ return (_close(fdclosedir(dirp)));
+}
diff --git a/lib/libc/gen/confstr.3 b/lib/libc/gen/confstr.3
new file mode 100644
index 000000000000..9ca4250aa350
--- /dev/null
+++ b/lib/libc/gen/confstr.3
@@ -0,0 +1,129 @@
+.\" Copyright (c) 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)confstr.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd December 3, 2006
+.Dt CONFSTR 3
+.Os
+.Sh NAME
+.Nm confstr
+.Nd get string-valued configurable variables
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft size_t
+.Fn confstr "int name" "char *buf" "size_t len"
+.Sh DESCRIPTION
+This interface is specified by
+.St -p1003.1-2001 .
+A more flexible (but non-portable) interface is provided by
+.Xr sysctl 3 .
+.Pp
+The
+.Fn confstr
+function provides a method for applications to get configuration
+defined string values.
+Shell programmers needing access to these parameters should use the
+.Xr getconf 1
+utility.
+.Pp
+The
+.Fa name
+argument specifies the system variable to be queried.
+Symbolic constants for each name value are found in the include file
+.In unistd.h .
+The
+.Fa len
+argument specifies the size of the buffer referenced by the
+argument
+.Fa buf .
+If
+.Fa len
+is non-zero,
+.Fa buf
+is a non-null pointer, and
+.Fa name
+has a value, up to
+.Fa len
+\- 1 bytes of the value are copied into the buffer
+.Fa buf .
+The copied value is always null terminated.
+.Pp
+The available values are as follows:
+.Bl -tag -width 6n
+.It Li _CS_PATH
+Return a value for the
+.Ev PATH
+environment variable that finds all the standard utilities.
+.El
+.Sh RETURN VALUES
+If the call to
+.Fn confstr
+is not successful, 0 is returned and
+.Va errno
+is set appropriately.
+Otherwise, if the variable does not have a configuration defined value,
+0 is returned and
+.Va errno
+is not modified.
+Otherwise, the buffer size needed to hold the entire configuration-defined
+value is returned.
+If this size is greater than the argument
+.Fa len ,
+the string in
+.Fa buf
+was truncated.
+.Sh ERRORS
+The
+.Fn confstr
+function may fail and set
+.Va errno
+for any of the errors specified for the library functions
+.Xr malloc 3
+and
+.Xr sysctl 3 .
+.Pp
+In addition, the following errors may be reported:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The value of the
+.Fa name
+argument is invalid.
+.El
+.Sh SEE ALSO
+.Xr getconf 1 ,
+.Xr pathconf 2 ,
+.Xr sysconf 3 ,
+.Xr sysctl 3
+.Sh HISTORY
+The
+.Fn confstr
+function first appeared in
+.Bx 4.4 .
diff --git a/lib/libc/gen/confstr.c b/lib/libc/gen/confstr.c
new file mode 100644
index 000000000000..2f9a061696c8
--- /dev/null
+++ b/lib/libc/gen/confstr.c
@@ -0,0 +1,121 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)confstr.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <paths.h>
+#include <string.h>
+#include <unistd.h>
+
+
+size_t
+confstr(int name, char *buf, size_t len)
+{
+ const char *p;
+ const char UPE[] = "unsupported programming environment";
+
+ switch (name) {
+ case _CS_PATH:
+ p = _PATH_STDPATH;
+ goto docopy;
+
+ /*
+ * POSIX/SUS ``Programming Environments'' stuff
+ *
+ * We don't support more than one programming environment
+ * on any platform (yet), so we just return the empty
+ * string for the environment we are compiled for,
+ * and the string "unsupported programming environment"
+ * for anything else. (The Standard says that if these
+ * values are used on a system which does not support
+ * this environment -- determined via sysconf() -- then
+ * the value we return is unspecified. So, we return
+ * something which will cause obvious breakage.)
+ */
+ case _CS_POSIX_V6_ILP32_OFF32_CFLAGS:
+ case _CS_POSIX_V6_ILP32_OFF32_LDFLAGS:
+ case _CS_POSIX_V6_ILP32_OFF32_LIBS:
+ case _CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS:
+ case _CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS:
+ case _CS_POSIX_V6_LPBIG_OFFBIG_LIBS:
+ /*
+ * These two environments are never supported.
+ */
+ p = UPE;
+ goto docopy;
+
+ case _CS_POSIX_V6_ILP32_OFFBIG_CFLAGS:
+ case _CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS:
+ case _CS_POSIX_V6_ILP32_OFFBIG_LIBS:
+ if (sizeof(long) * CHAR_BIT == 32 &&
+ sizeof(off_t) > sizeof(long))
+ p = "";
+ else
+ p = UPE;
+ goto docopy;
+
+ case _CS_POSIX_V6_LP64_OFF64_CFLAGS:
+ case _CS_POSIX_V6_LP64_OFF64_LDFLAGS:
+ case _CS_POSIX_V6_LP64_OFF64_LIBS:
+ if (sizeof(long) * CHAR_BIT >= 64 &&
+ sizeof(void *) * CHAR_BIT >= 64 &&
+ sizeof(int) * CHAR_BIT >= 32 &&
+ sizeof(off_t) >= sizeof(long))
+ p = "";
+ else
+ p = UPE;
+ goto docopy;
+
+ case _CS_POSIX_V6_WIDTH_RESTRICTED_ENVS:
+ /* XXX - should have more complete coverage */
+ if (sizeof(long) * CHAR_BIT >= 64)
+ p = "_POSIX_V6_LP64_OFF64";
+ else
+ p = "_POSIX_V6_ILP32_OFFBIG";
+ goto docopy;
+
+docopy:
+ if (len != 0 && buf != NULL)
+ strlcpy(buf, p, len);
+ return (strlen(p) + 1);
+
+ default:
+ errno = EINVAL;
+ return (0);
+ }
+ /* NOTREACHED */
+}
diff --git a/lib/libc/gen/crypt.c b/lib/libc/gen/crypt.c
new file mode 100644
index 000000000000..d8e45cd21fa7
--- /dev/null
+++ b/lib/libc/gen/crypt.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Tom Truscott.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/* from static char sccsid[] = "@(#)crypt.c 5.11 (Berkeley) 6/25/91"; */
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+/*
+ * UNIX password, and DES, encryption.
+ *
+ * since this is non-exportable, this is just a dummy. if you want real
+ * encryption, make sure you've got libcrypt.a around.
+ */
+
+/* ARGSUSED */
+int
+__freebsd11_des_setkey(const char *key __unused)
+{
+ fprintf(stderr, "WARNING! des_setkey(3) not present in the system!\n");
+ return (0);
+}
+
+/* ARGSUSED */
+int
+__freebsd11_des_cipher(const char *in, char *out, long salt __unused,
+ int num_iter __unused)
+{
+ fprintf(stderr, "WARNING! des_cipher(3) not present in the system!\n");
+ bcopy(in, out, 8);
+ return (0);
+}
+
+/* ARGSUSED */
+int
+__freebsd11_setkey(const char *key __unused)
+{
+ fprintf(stderr, "WARNING! setkey(3) not present in the system!\n");
+ return (0);
+}
+
+/* ARGSUSED */
+int
+__freebsd11_encrypt(char *block __unused, int flag __unused)
+{
+ fprintf(stderr, "WARNING! encrypt(3) not present in the system!\n");
+ return (0);
+}
+
+__sym_compat(des_setkey, __freebsd11_des_setkey, FBSD_1.0);
+__sym_compat(des_cipher, __freebsd11_des_cipher, FBSD_1.0);
+__sym_compat(setkey, __freebsd11_setkey, FBSD_1.0);
+__sym_compat(encrypt, __freebsd11_encrypt, FBSD_1.0);
diff --git a/lib/libc/gen/ctermid.3 b/lib/libc/gen/ctermid.3
new file mode 100644
index 000000000000..d737e5e0d3a1
--- /dev/null
+++ b/lib/libc/gen/ctermid.3
@@ -0,0 +1,108 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)ctermid.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd October 1, 2011
+.Dt CTERMID 3
+.Os
+.Sh NAME
+.Nm ctermid
+.Nd generate terminal pathname
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdio.h
+.Ft char *
+.Fn ctermid "char *buf"
+.Ft char *
+.Fn ctermid_r "char *buf"
+.Sh DESCRIPTION
+The
+.Fn ctermid
+function generates a string, that, when used as a pathname, refers to
+the current controlling terminal of the calling process.
+.Pp
+If
+.Fa buf
+is the
+.Dv NULL
+pointer, a pointer to a static area is returned.
+Otherwise, the pathname is copied into the memory referenced by
+.Fa buf .
+The argument
+.Fa buf
+is assumed to be at least
+.Dv L_ctermid
+(as defined in the include
+file
+.In stdio.h )
+bytes long.
+.Pp
+The
+.Fn ctermid_r
+function
+provides the same functionality as
+.Fn ctermid
+except that if
+.Fa buf
+is a
+.Dv NULL
+pointer,
+.Dv NULL
+is returned.
+.Pp
+If no suitable lookup of the controlling terminal name can be performed,
+this implementation returns
+.Ql /dev/tty .
+.Sh RETURN VALUES
+Upon successful completion, a
+.Pf non- Dv NULL
+pointer is returned.
+Otherwise, a
+.Dv NULL
+pointer is returned and the global variable
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+The current implementation detects no error conditions.
+.Sh SEE ALSO
+.Xr ttyname 3
+.Sh STANDARDS
+The
+.Fn ctermid
+function conforms to
+.St -p1003.1-88 .
+.Sh BUGS
+By default the
+.Fn ctermid
+function
+writes all information to an internal static object.
+Subsequent calls to
+.Fn ctermid
+will modify the same object.
diff --git a/lib/libc/gen/ctermid.c b/lib/libc/gen/ctermid.c
new file mode 100644
index 000000000000..8af1cb2f3d30
--- /dev/null
+++ b/lib/libc/gen/ctermid.c
@@ -0,0 +1,70 @@
+/*-
+ * Copyright (c) 2011 Ed Schouten <ed@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+
+#include <errno.h>
+#include <paths.h>
+#include <stdio.h>
+#include <string.h>
+
+#define LEN_PATH_DEV (sizeof(_PATH_DEV) - 1)
+
+char *
+ctermid(char *s)
+{
+ static char def[sizeof(_PATH_DEV) + SPECNAMELEN];
+ struct stat sb;
+ size_t dlen;
+ int sverrno;
+
+ if (s == NULL) {
+ s = def;
+ dlen = sizeof(def) - LEN_PATH_DEV;
+ } else
+ dlen = L_ctermid - LEN_PATH_DEV;
+ strcpy(s, _PATH_TTY);
+
+ /* Attempt to perform a lookup of the actual TTY pathname. */
+ sverrno = errno;
+ if (stat(_PATH_TTY, &sb) == 0 && S_ISCHR(sb.st_mode))
+ (void)sysctlbyname("kern.devname", s + LEN_PATH_DEV,
+ &dlen, &sb.st_rdev, sizeof(sb.st_rdev));
+ errno = sverrno;
+ return (s);
+}
+
+char *
+ctermid_r(char *s)
+{
+
+ return (s != NULL ? ctermid(s) : NULL);
+}
diff --git a/lib/libc/gen/daemon.3 b/lib/libc/gen/daemon.3
new file mode 100644
index 000000000000..34db96603839
--- /dev/null
+++ b/lib/libc/gen/daemon.3
@@ -0,0 +1,112 @@
+.\" Copyright (c) 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)daemon.3 8.1 (Berkeley) 6/9/93
+.\" $FreeBSD$
+.\"
+.Dd June 9, 1993
+.Dt DAEMON 3
+.Os
+.Sh NAME
+.Nm daemon
+.Nd run in the background
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft int
+.Fn daemon "int nochdir" "int noclose"
+.Sh DESCRIPTION
+The
+.Fn daemon
+function is for programs wishing to detach themselves from the
+controlling terminal and run in the background as system daemons.
+.Pp
+Unless the argument
+.Fa nochdir
+is non-zero,
+.Fn daemon
+changes the current working directory to the root
+.Pq Pa / .
+.Pp
+Unless the argument
+.Fa noclose
+is non-zero,
+.Fn daemon
+will redirect standard input, standard output, and standard error to
+.Pa /dev/null .
+.Sh RETURN VALUES
+.Rv -std daemon
+.Sh ERRORS
+The
+.Fn daemon
+function may fail and set
+.Va errno
+for any of the errors specified for the library functions
+.Xr fork 2
+and
+.Xr setsid 2 .
+.Sh SEE ALSO
+.Xr fork 2 ,
+.Xr setsid 2 ,
+.Xr sigaction 2
+.Sh HISTORY
+The
+.Fn daemon
+function first appeared in
+.Bx 4.4 .
+.Sh CAVEATS
+Unless the
+.Fa noclose
+argument is non-zero,
+.Fn daemon
+will close the first three file descriptors and redirect them to
+.Pa /dev/null .
+Normally, these correspond to standard input, standard output, and
+standard error.
+However, if any of those file descriptors refer to something else, they
+will still be closed, resulting in incorrect behavior of the calling program.
+This can happen if any of standard input, standard output, or standard
+error have been closed before the program was run.
+Programs using
+.Fn daemon
+should therefore either call
+.Fn daemon
+before opening any files or sockets, or verify that any file
+descriptors obtained have values greater than 2.
+.Pp
+The
+.Fn daemon
+function temporarily ignores
+.Dv SIGHUP
+while calling
+.Xr setsid 2
+to prevent a parent session group leader's calls to
+.Xr fork 2
+and then
+.Xr _exit 2
+from prematurely terminating the child process.
diff --git a/lib/libc/gen/daemon.c b/lib/libc/gen/daemon.c
new file mode 100644
index 000000000000..15c6f4af7583
--- /dev/null
+++ b/lib/libc/gen/daemon.c
@@ -0,0 +1,95 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)daemon.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+
+int
+daemon(int nochdir, int noclose)
+{
+ struct sigaction osa, sa;
+ int fd;
+ pid_t newgrp;
+ int oerrno;
+ int osa_ok;
+
+ /* A SIGHUP may be thrown when the parent exits below. */
+ sigemptyset(&sa.sa_mask);
+ sa.sa_handler = SIG_IGN;
+ sa.sa_flags = 0;
+ osa_ok = __libc_sigaction(SIGHUP, &sa, &osa);
+
+ switch (fork()) {
+ case -1:
+ return (-1);
+ case 0:
+ break;
+ default:
+ /*
+ * A fine point: _exit(0), not exit(0), to avoid triggering
+ * atexit(3) processing
+ */
+ _exit(0);
+ }
+
+ newgrp = setsid();
+ oerrno = errno;
+ if (osa_ok != -1)
+ __libc_sigaction(SIGHUP, &osa, NULL);
+
+ if (newgrp == -1) {
+ errno = oerrno;
+ return (-1);
+ }
+
+ if (!nochdir)
+ (void)chdir("/");
+
+ if (!noclose && (fd = _open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
+ (void)_dup2(fd, STDIN_FILENO);
+ (void)_dup2(fd, STDOUT_FILENO);
+ (void)_dup2(fd, STDERR_FILENO);
+ if (fd > 2)
+ (void)_close(fd);
+ }
+ return (0);
+}
diff --git a/lib/libc/gen/devname.3 b/lib/libc/gen/devname.3
new file mode 100644
index 000000000000..7ff31c720653
--- /dev/null
+++ b/lib/libc/gen/devname.3
@@ -0,0 +1,115 @@
+.\" Copyright (c) 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)devname.3 8.2 (Berkeley) 4/29/95
+.\" $FreeBSD$
+.\"
+.Dd February 22, 2005
+.Dt DEVNAME 3
+.Os
+.Sh NAME
+.Nm devname
+.Nd "get device name"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/stat.h
+.In stdlib.h
+.Ft char *
+.Fn devname "dev_t dev" "mode_t type"
+.Ft char *
+.Fn devname_r "dev_t dev" "mode_t type" "char *buf" "int len"
+.Ft char *
+.Fn fdevname "int fd"
+.Ft char *
+.Fn fdevname_r "int fd" "char *buf" "int len"
+.Sh DESCRIPTION
+The
+.Fn devname
+function returns a pointer to the name of the block or character
+device in
+.Pa /dev
+with a device number of
+.Fa dev ,
+and a file type matching the one encoded in
+.Fa type
+which must be one of
+.Dv S_IFBLK
+or
+.Dv S_IFCHR .
+To find the right name,
+.Fn devname
+asks the kernel via the
+.Va kern.devname
+sysctl.
+If it is unable to come up with a suitable name,
+it will format the information encapsulated in
+.Fa dev
+and
+.Fa type
+in a human-readable format.
+.Pp
+The
+.Fn fdevname
+and
+.Fn fdevname_r
+function obtains the device name directly from a file descriptor
+pointing to a character device.
+If it is unable to come up with a suitable name, these functions will
+return a NULL pointer.
+.Pp
+.Fn devname
+and
+.Fn fdevname
+return the name stored in a static buffer which will be overwritten
+on subsequent calls.
+.Fn devname_r
+and
+.Fn fdevname_r
+take a buffer and length as argument to avoid this problem.
+.Sh EXAMPLES
+.Bd -literal -compact
+int fd;
+struct stat buf;
+char *name;
+
+ fd = open("/dev/tun");
+ fstat(fd, &buf);
+ printf("devname is /dev/%s\en", devname(buf.st_rdev, S_IFCHR));
+ printf("fdevname is /dev/%s\en", fdevname(fd));
+.Ed
+.Sh SEE ALSO
+.Xr stat 2
+.Sh HISTORY
+The
+.Fn devname
+function appeared in
+.Bx 4.4 .
+The
+.Fn fdevname
+function appeared in
+.Fx 8.0 .
diff --git a/lib/libc/gen/devname.c b/lib/libc/gen/devname.c
new file mode 100644
index 000000000000..120c284449cd
--- /dev/null
+++ b/lib/libc/gen/devname.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)devname.c 8.2 (Berkeley) 4/29/95";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/sysctl.h>
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+char *
+devname_r(dev_t dev, mode_t type, char *buf, int len)
+{
+ int i;
+ size_t j;
+
+ if (dev == NODEV || !(S_ISCHR(type) || S_ISBLK(dev))) {
+ strlcpy(buf, "#NODEV", len);
+ return (buf);
+ }
+
+ if (S_ISCHR(type)) {
+ j = len;
+ i = sysctlbyname("kern.devname", buf, &j, &dev, sizeof (dev));
+ if (i == 0)
+ return (buf);
+ }
+
+ /* Finally just format it */
+ snprintf(buf, len, "#%c:%#jx",
+ S_ISCHR(type) ? 'C' : 'B', (uintmax_t)dev);
+ return (buf);
+}
+
+char *
+devname(dev_t dev, mode_t type)
+{
+ static char buf[SPECNAMELEN + 1];
+
+ return (devname_r(dev, type, buf, sizeof(buf)));
+}
diff --git a/lib/libc/gen/directory.3 b/lib/libc/gen/directory.3
new file mode 100644
index 000000000000..4b6d0a1f2372
--- /dev/null
+++ b/lib/libc/gen/directory.3
@@ -0,0 +1,308 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)directory.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd August 31, 2016
+.Dt DIRECTORY 3
+.Os
+.Sh NAME
+.Nm opendir ,
+.Nm fdopendir ,
+.Nm readdir ,
+.Nm readdir_r ,
+.Nm telldir ,
+.Nm seekdir ,
+.Nm rewinddir ,
+.Nm closedir ,
+.Nm fdclosedir ,
+.Nm dirfd
+.Nd directory operations
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In dirent.h
+.Ft DIR *
+.Fn opendir "const char *filename"
+.Ft DIR *
+.Fn fdopendir "int fd"
+.Ft struct dirent *
+.Fn readdir "DIR *dirp"
+.Ft int
+.Fn readdir_r "DIR *dirp" "struct dirent *entry" "struct dirent **result"
+.Ft long
+.Fn telldir "DIR *dirp"
+.Ft void
+.Fn seekdir "DIR *dirp" "long loc"
+.Ft void
+.Fn rewinddir "DIR *dirp"
+.Ft int
+.Fn closedir "DIR *dirp"
+.Ft int
+.Fn fdclosedir "DIR *dirp"
+.Ft int
+.Fn dirfd "DIR *dirp"
+.Sh DESCRIPTION
+.Bf -symbolic
+The
+.Fn readdir_r
+interface is deprecated
+because it cannot be used correctly unless
+.Brq Va NAME_MAX
+is a fixed value.
+.Ef
+.Pp
+The
+.Fn opendir
+function
+opens the directory named by
+.Fa filename ,
+associates a
+.Em directory stream
+with it
+and
+returns a pointer to be used to identify the
+.Em directory stream
+in subsequent operations.
+The pointer
+.Dv NULL
+is returned if
+.Fa filename
+cannot be accessed, or if it cannot
+.Xr malloc 3
+enough memory to hold the whole thing.
+.Pp
+The
+.Fn fdopendir
+function is equivalent to the
+.Fn opendir
+function except that the directory is specified by a file descriptor
+.Fa fd
+rather than by a name.
+The file offset associated with the file descriptor at the time of the call
+determines which entries are returned.
+.Pp
+Upon successful return from
+.Fn fdopendir ,
+the file descriptor is under the control of the system,
+and if any attempt is made to close the file descriptor,
+or to modify the state of the associated description other than by means
+of
+.Fn closedir ,
+.Fn readdir ,
+.Fn readdir_r ,
+or
+.Fn rewinddir ,
+the behavior is undefined.
+Upon calling
+.Fn closedir
+the file descriptor is closed.
+The
+.Dv FD_CLOEXEC
+flag is set on the file descriptor by a successful call to
+.Fn fdopendir .
+.Pp
+The
+.Fn readdir
+function
+returns a pointer to the next directory entry.
+The directory entry remains valid until the next call to
+.Fn readdir
+or
+.Fn closedir
+on the same
+.Em directory stream .
+The function returns
+.Dv NULL
+upon reaching the end of the directory or on error.
+In the event of an error,
+.Va errno
+may be set to any of the values documented for the
+.Xr getdirentries 2
+system call.
+.Pp
+The
+.Fn readdir_r
+function
+provides the same functionality as
+.Fn readdir ,
+but the caller must provide a directory
+.Fa entry
+buffer to store the results in.
+The buffer must be large enough for a
+.Vt struct dirent
+with a
+.Va d_name
+array with
+.Brq Va NAME_MAX
++ 1 elements.
+If the read succeeds,
+.Fa result
+is pointed at the
+.Fa entry ;
+upon reaching the end of the directory
+.Fa result
+is set to
+.Dv NULL .
+The
+.Fn readdir_r
+function
+returns 0 on success or an error number to indicate failure.
+.Pp
+The
+.Fn telldir
+function
+returns a token representing the current location associated with the named
+.Em directory stream .
+Values returned by
+.Fn telldir
+are good only for the lifetime of the
+.Dv DIR
+pointer,
+.Fa dirp ,
+from which they are derived.
+If the directory is closed and then
+reopened, prior values returned by
+.Fn telldir
+will no longer be valid.
+Values returned by
+.Fn telldir
+are also invalidated by a call to
+.Fn rewinddir .
+.Pp
+The
+.Fn seekdir
+function
+sets the position of the next
+.Fn readdir
+operation on the
+.Em directory stream .
+The new position reverts to the one associated with the
+.Em directory stream
+when the
+.Fn telldir
+operation was performed.
+.Pp
+The
+.Fn rewinddir
+function
+resets the position of the named
+.Em directory stream
+to the beginning of the directory.
+.Pp
+The
+.Fn closedir
+function
+closes the named
+.Em directory stream
+and frees the structure associated with the
+.Fa dirp
+pointer,
+returning 0 on success.
+On failure, \-1 is returned and the global variable
+.Va errno
+is set to indicate the error.
+.Pp
+The
+.Fn fdclosedir
+function is equivalent to the
+.Fn closedir
+function except that this function returns directory file descriptor instead of
+closing it.
+.Pp
+The
+.Fn dirfd
+function
+returns the integer file descriptor associated with the named
+.Em directory stream ,
+see
+.Xr open 2 .
+.Pp
+Sample code which searches a directory for entry ``name'' is:
+.Bd -literal -offset indent
+dirp = opendir(".");
+if (dirp == NULL)
+ return (ERROR);
+len = strlen(name);
+while ((dp = readdir(dirp)) != NULL) {
+ if (dp->d_namlen == len && strcmp(dp->d_name, name) == 0) {
+ (void)closedir(dirp);
+ return (FOUND);
+ }
+}
+(void)closedir(dirp);
+return (NOT_FOUND);
+.Ed
+.Sh SEE ALSO
+.Xr close 2 ,
+.Xr lseek 2 ,
+.Xr open 2 ,
+.Xr read 2 ,
+.Xr dir 5
+.Sh HISTORY
+The
+.Fn opendir ,
+.Fn readdir ,
+.Fn telldir ,
+.Fn seekdir ,
+.Fn rewinddir ,
+.Fn closedir ,
+and
+.Fn dirfd
+functions appeared in
+.Bx 4.2 .
+The
+.Fn fdopendir
+function appeared in
+.Fx 8.0 .
+.Fn fdclosedir
+function appeared in
+.Fx 10.0 .
+.Sh BUGS
+The behaviour of
+.Fn telldir
+and
+.Fn seekdir
+is likely to be wrong if there are parallel unlinks happening
+and the directory is larger than one page.
+There is code to ensure that a
+.Fn seekdir
+to the location given by a
+.Fn telldir
+immediately before the last
+.Fn readdir
+will always set the correct location to return the same value as that last
+.Fn readdir
+performed.
+This is enough for some applications which want to "push back the last entry read" E.g. Samba.
+Seeks back to any other location,
+other than the beginning of the directory,
+may result in unexpected behaviour if deletes are present.
+It is hoped that this situation will be resolved with changes to
+.Fn getdirentries
+and the VFS.
diff --git a/lib/libc/gen/dirfd.c b/lib/libc/gen/dirfd.c
new file mode 100644
index 000000000000..e29bfdccb7e3
--- /dev/null
+++ b/lib/libc/gen/dirfd.c
@@ -0,0 +1,45 @@
+/*-
+ * Copyright (c) 2011 Gleb Kurtsou <gleb@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/param.h>
+
+#include <dirent.h>
+#include "un-namespace.h"
+
+#include "gen-private.h"
+
+int
+dirfd(DIR *dirp)
+{
+
+ return (_dirfd(dirp));
+}
diff --git a/lib/libc/gen/dirname.3 b/lib/libc/gen/dirname.3
new file mode 100644
index 000000000000..60f44e298614
--- /dev/null
+++ b/lib/libc/gen/dirname.3
@@ -0,0 +1,85 @@
+.\" $OpenBSD: dirname.3,v 1.17 2007/05/31 19:19:28 jmc Exp $
+.\"
+.\" Copyright (c) 1997 Todd C. Miller <Todd.Miller@courtesan.com>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd September 5, 2016
+.Dt DIRNAME 3
+.Os
+.Sh NAME
+.Nm dirname
+.Nd extract the directory part of a pathname
+.Sh SYNOPSIS
+.In libgen.h
+.Ft char *
+.Fn dirname "char *path"
+.Sh DESCRIPTION
+The
+.Fn dirname
+function is the converse of
+.Xr basename 3 ;
+it returns a pointer to the parent directory of the pathname pointed to by
+.Fa path .
+Any trailing
+.Sq \&/
+characters are not counted as part of the directory
+name.
+.Sh RETURN VALUES
+If
+.Fa path
+is a null pointer, the empty string, or contains no
+.Sq \&/
+characters,
+.Fn dirname
+returns a pointer to the string
+.Qq \&. ,
+signifying the current directory.
+Otherwise,
+it returns a pointer to the parent directory of
+.Fa path .
+.Sh IMPLEMENTATION NOTES
+This implementation of
+.Fn dirname
+uses the buffer provided by the caller to store the resulting parent
+directory.
+Other vendor implementations may return a pointer to internal storage
+space instead.
+The advantage of the former approach is that it ensures thread-safety,
+while also placing no upper limit on the supported length of the
+pathname.
+.Sh SEE ALSO
+.Xr basename 1 ,
+.Xr dirname 1 ,
+.Xr basename 3
+.Sh STANDARDS
+The
+.Fn dirname
+function conforms to
+.St -xpg4.2 .
+.Sh HISTORY
+The
+.Fn dirname
+function first appeared in
+.Ox 2.2
+and
+.Fx 4.2 .
+.Pp
+In
+.Fx 12.0 ,
+this function was reimplemented to store its result in the provided
+input buffer.
+.Sh AUTHORS
+.An Nuxi, the Netherlands
diff --git a/lib/libc/gen/dirname.c b/lib/libc/gen/dirname.c
new file mode 100644
index 000000000000..ae7b928d54eb
--- /dev/null
+++ b/lib/libc/gen/dirname.c
@@ -0,0 +1,73 @@
+/*-
+ * Copyright (c) 2015-2016 Nuxi, https://nuxi.nl/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <libgen.h>
+#include <string.h>
+
+char *
+(dirname)(char *path)
+{
+ char *end;
+
+ /*
+ * If path is a null pointer or points to an empty string,
+ * dirname() shall return a pointer to the string ".".
+ */
+ if (path == NULL || *path == '\0')
+ return (__DECONST(char *, "."));
+
+ /* Find end of last pathname component. */
+ end = path + strlen(path);
+ while (end > path + 1 && *(end - 1) == '/')
+ --end;
+
+ /* Strip off the last pathname component. */
+ while (end > path && *(end - 1) != '/')
+ --end;
+
+ /*
+ * If path does not contain a '/', then dirname() shall return a
+ * pointer to the string ".".
+ */
+ if (end == path) {
+ path[0] = '.';
+ path[1] = '\0';
+ return (path);
+ }
+
+ /*
+ * Remove trailing slashes from the resulting directory name. Ensure
+ * that at least one character remains.
+ */
+ while (end > path + 1 && *(end - 1) == '/')
+ --end;
+
+ /* Null terminate directory name and return it. */
+ *end = '\0';
+ return (path);
+}
diff --git a/lib/libc/gen/dirname_compat.c b/lib/libc/gen/dirname_compat.c
new file mode 100644
index 000000000000..48ad32c8d70a
--- /dev/null
+++ b/lib/libc/gen/dirname_compat.c
@@ -0,0 +1,79 @@
+/* $OpenBSD: dirname.c,v 1.13 2005/08/08 08:05:33 espie Exp $ */
+
+/*
+ * Copyright (c) 1997, 2004 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <libgen.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/param.h>
+
+char *
+__freebsd11_dirname(char *path)
+{
+ static char *dname = NULL;
+ size_t len;
+ const char *endp;
+
+ if (dname == NULL) {
+ dname = (char *)malloc(MAXPATHLEN);
+ if (dname == NULL)
+ return(NULL);
+ }
+
+ /* Empty or NULL string gets treated as "." */
+ if (path == NULL || *path == '\0') {
+ dname[0] = '.';
+ dname[1] = '\0';
+ return (dname);
+ }
+
+ /* Strip any trailing slashes */
+ endp = path + strlen(path) - 1;
+ while (endp > path && *endp == '/')
+ endp--;
+
+ /* Find the start of the dir */
+ while (endp > path && *endp != '/')
+ endp--;
+
+ /* Either the dir is "/" or there are no slashes */
+ if (endp == path) {
+ dname[0] = *endp == '/' ? '/' : '.';
+ dname[1] = '\0';
+ return (dname);
+ } else {
+ /* Move forward past the separating slashes */
+ do {
+ endp--;
+ } while (endp > path && *endp == '/');
+ }
+
+ len = endp - path + 1;
+ if (len >= MAXPATHLEN) {
+ errno = ENAMETOOLONG;
+ return (NULL);
+ }
+ memcpy(dname, path, len);
+ dname[len] = '\0';
+ return (dname);
+}
+
+__sym_compat(dirname, __freebsd11_dirname, FBSD_1.0);
diff --git a/lib/libc/gen/disklabel.c b/lib/libc/gen/disklabel.c
new file mode 100644
index 000000000000..8780573d1c5d
--- /dev/null
+++ b/lib/libc/gen/disklabel.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 1983, 1987, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)disklabel.c 8.2 (Berkeley) 5/3/95";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#define DKTYPENAMES
+#define FSTYPENAMES
+#include <sys/disklabel.h>
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+
+static int
+gettype(char *t, const char **names)
+{
+ const char **nm;
+
+ for (nm = names; *nm; nm++)
+ if (strcasecmp(t, *nm) == 0)
+ return (nm - names);
+ if (isdigit((unsigned char)*t))
+ return (atoi(t));
+ return (0);
+}
+
+struct disklabel *
+getdiskbyname(const char *name)
+{
+ static struct disklabel disk;
+ struct disklabel *dp = &disk;
+ struct partition *pp;
+ char *buf;
+ char *db_array[2] = { _PATH_DISKTAB, 0 };
+ char *cp, *cq; /* can't be register */
+ char p, max, psize[3], pbsize[3],
+ pfsize[3], poffset[3], ptype[3];
+ u_int32_t *dx;
+
+ if (cgetent(&buf, db_array, (char *) name) < 0)
+ return NULL;
+
+ bzero((char *)&disk, sizeof(disk));
+ /*
+ * typename
+ */
+ cq = dp->d_typename;
+ cp = buf;
+ while (cq < dp->d_typename + sizeof(dp->d_typename) - 1 &&
+ (*cq = *cp) && *cq != '|' && *cq != ':')
+ cq++, cp++;
+ *cq = '\0';
+
+ if (cgetstr(buf, "ty", &cq) > 0) {
+ if (strcmp(cq, "removable") == 0)
+ dp->d_flags |= D_REMOVABLE;
+ else if (cq && strcmp(cq, "simulated") == 0)
+ dp->d_flags |= D_RAMDISK;
+ free(cq);
+ }
+ if (cgetcap(buf, "sf", ':') != NULL)
+ dp->d_flags |= D_BADSECT;
+
+#define getnumdflt(field, dname, dflt) \
+ { long f; (field) = (cgetnum(buf, dname, &f) == -1) ? (dflt) : f; }
+
+ getnumdflt(dp->d_secsize, "se", DEV_BSIZE);
+ getnumdflt(dp->d_ntracks, "nt", 0);
+ getnumdflt(dp->d_nsectors, "ns", 0);
+ getnumdflt(dp->d_ncylinders, "nc", 0);
+
+ if (cgetstr(buf, "dt", &cq) > 0) {
+ dp->d_type = gettype(cq, dktypenames);
+ free(cq);
+ } else
+ getnumdflt(dp->d_type, "dt", 0);
+ getnumdflt(dp->d_secpercyl, "sc", dp->d_nsectors * dp->d_ntracks);
+ getnumdflt(dp->d_secperunit, "su", dp->d_secpercyl * dp->d_ncylinders);
+ getnumdflt(dp->d_rpm, "rm", 3600);
+ getnumdflt(dp->d_interleave, "il", 1);
+ getnumdflt(dp->d_trackskew, "sk", 0);
+ getnumdflt(dp->d_cylskew, "cs", 0);
+ getnumdflt(dp->d_headswitch, "hs", 0);
+ getnumdflt(dp->d_trkseek, "ts", 0);
+ getnumdflt(dp->d_bbsize, "bs", BBSIZE);
+ getnumdflt(dp->d_sbsize, "sb", 0);
+ strcpy(psize, "px");
+ strcpy(pbsize, "bx");
+ strcpy(pfsize, "fx");
+ strcpy(poffset, "ox");
+ strcpy(ptype, "tx");
+ max = 'a' - 1;
+ pp = &dp->d_partitions[0];
+ for (p = 'a'; p < 'a' + MAXPARTITIONS; p++, pp++) {
+ long l;
+ psize[1] = pbsize[1] = pfsize[1] = poffset[1] = ptype[1] = p;
+ if (cgetnum(buf, psize, &l) == -1)
+ pp->p_size = 0;
+ else {
+ pp->p_size = l;
+ cgetnum(buf, poffset, &l);
+ pp->p_offset = l;
+ getnumdflt(pp->p_fsize, pfsize, 0);
+ if (pp->p_fsize) {
+ long bsize;
+
+ if (cgetnum(buf, pbsize, &bsize) == 0)
+ pp->p_frag = bsize / pp->p_fsize;
+ else
+ pp->p_frag = 8;
+ }
+ getnumdflt(pp->p_fstype, ptype, 0);
+ if (pp->p_fstype == 0)
+ if (cgetstr(buf, ptype, &cq) >= 0) {
+ pp->p_fstype = gettype(cq, fstypenames);
+ free(cq);
+ }
+ max = p;
+ }
+ }
+ dp->d_npartitions = max + 1 - 'a';
+ (void)strcpy(psize, "dx");
+ dx = dp->d_drivedata;
+ for (p = '0'; p < '0' + NDDATA; p++, dx++) {
+ psize[1] = p;
+ getnumdflt(*dx, psize, 0);
+ }
+ dp->d_magic = DISKMAGIC;
+ dp->d_magic2 = DISKMAGIC;
+ free(buf);
+ return (dp);
+}
diff --git a/lib/libc/gen/dl_iterate_phdr.3 b/lib/libc/gen/dl_iterate_phdr.3
new file mode 100644
index 000000000000..6e952dc13b57
--- /dev/null
+++ b/lib/libc/gen/dl_iterate_phdr.3
@@ -0,0 +1,115 @@
+.\" Copyright (c) 2005 Mark Kettenis
+.\" Copyright (c) 2012 Konstantin Belousov <kib@FreeBSD.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.
+.\"
+.\" $OpenBSD: dl_iterate_phdr.3,v 1.3 2007/05/31 19:19:48 jmc Exp $
+.\" $FreeBSD$
+.Dd October 9, 2014
+.Dt DL_ITERATE_PHDR 3
+.Os
+.Sh NAME
+.Nm dl_iterate_phdr
+.Nd iterate over program headers
+.Sh LIBRARY
+For the dynamically linked binaries, the service is provided by
+.Xr ld-elf.so.1 1
+dynamic linker.
+Statically linked programs use an implementation of
+.Fn dl_iterate_phdr
+from libc.
+.Sh SYNOPSIS
+.In link.h
+.Ft int
+.Fn dl_iterate_phdr "int (*callback)(struct dl_phdr_info *, size_t, void *)" "void *data"
+.Sh DESCRIPTION
+The
+.Fn dl_iterate_phdr
+function iterates over all ELF objects loaded into a process's
+address space, calling
+.Fa callback
+for each object, passing it information about the object's
+program headers and the
+.Fa data
+argument.
+The iteration is aborted when all objects are passed, or when the next
+.Fa callback
+call returns non-zero value.
+The information about the program headers is passed in a structure
+that is defined as:
+.Bd -literal
+struct dl_phdr_info {
+ Elf_Addr dlpi_addr;
+ const char *dlpi_name;
+ const Elf_Phdr *dlpi_phdr;
+ Elf_Half dlpi_phnum;
+ unsigned long long int dlpi_adds;
+ unsigned long long int dlpi_subs;
+ size_t dlpi_tls_modid;
+ void *dlpi_tls_data;
+};
+.Ed
+.Pp
+The members of
+.Li struct dl_phdr_info
+have the following meaning:
+.Bl -tag -width dlpi_tls_modid
+.It Fa dlpi_addr
+The base address at which the object is mapped into the address
+space of the calling process.
+.It Fa dlpi_name
+The pathname of the ELF object.
+.It Fa dlpi_phdr
+A pointer to the object's program headers.
+.It Fa dlpi_phnum
+The number of program headers in the object.
+.It Fa dlpi_adds
+The counter of the object loads performed by the dynamic linker.
+.It Fa dlpi_subs
+The counter of the object unloads performed by the dynamic linker.
+.It Fa dlpi_tls_modid
+The TLS index of the object.
+.It Fa dlpi_tls_data
+A pointer to the initialization data for the object TLS segment.
+.El
+.Pp
+Future versions of
+.Fx
+might add more members to this structure.
+To make it possible for programs to check whether any new members have
+been added, the size of the structure is passed as an second argument to
+.Fa callback .
+.Pp
+The third argument to callback is the
+.Fa data
+value passed to the call to
+.Fn dl_iterate_phdr ,
+allowing the
+.Fa callback
+to have a context.
+.Sh RETURN VALUES
+The
+.Fn dl_iterate_phdr
+returns the value returned by the last
+.Fa callback
+call executed.
+.Sh SEE ALSO
+.Xr ld 1 ,
+.Xr ld-elf.so.1 1 ,
+.Xr dlopen 3 ,
+.Xr elf 5
+.Sh HISTORY
+The
+.Nm
+function first appeared in
+.Fx 7.0 .
diff --git a/lib/libc/gen/dladdr.3 b/lib/libc/gen/dladdr.3
new file mode 100644
index 000000000000..65662793b59d
--- /dev/null
+++ b/lib/libc/gen/dladdr.3
@@ -0,0 +1,133 @@
+.\"
+.\" Copyright (c) 1998 John D. Polstra
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd February 5, 1998
+.Dt DLADDR 3
+.Os
+.Sh NAME
+.Nm dladdr
+.Nd find the shared object containing a given address
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In dlfcn.h
+.Ft int
+.Fn dladdr "const void *addr" "Dl_info *info"
+.Sh DESCRIPTION
+The
+.Fn dladdr
+function
+queries the dynamic linker for information about the shared object
+containing the address
+.Fa addr .
+The information is returned in the structure specified by
+.Fa info .
+The structure contains at least the following members:
+.Bl -tag -width "XXXconst char *dli_fname"
+.It Li "const char *dli_fname"
+The pathname of the shared object containing the address.
+.It Li "void *dli_fbase"
+The base address at which the shared object is mapped into the
+address space of the calling process.
+.It Li "const char *dli_sname"
+The name of the nearest run-time symbol with a value less than or
+equal to
+.Fa addr .
+When possible, the symbol name is returned as it would appear in C
+source code.
+.Pp
+If no symbol with a suitable value is found, both this field and
+.Va dli_saddr
+are set to
+.Dv NULL .
+.It Li "void *dli_saddr"
+The value of the symbol returned in
+.Li dli_sname .
+.El
+.Pp
+The
+.Fn dladdr
+function
+is available only in dynamically linked programs.
+.Sh ERRORS
+If a mapped shared object containing
+.Fa addr
+cannot be found,
+.Fn dladdr
+returns 0.
+In that case, a message detailing the failure can be retrieved by
+calling
+.Fn dlerror .
+.Pp
+On success, a non-zero value is returned.
+.Sh SEE ALSO
+.Xr rtld 1 ,
+.Xr dlopen 3
+.Sh HISTORY
+The
+.Fn dladdr
+function first appeared in the Solaris operating system.
+.Sh BUGS
+This implementation is bug-compatible with the Solaris
+implementation.
+In particular, the following bugs are present:
+.Bl -bullet
+.It
+If
+.Fa addr
+lies in the main executable rather than in a shared library, the
+pathname returned in
+.Va dli_fname
+may not be correct.
+The pathname is taken directly from
+.Va argv[0]
+of the calling process.
+When executing a program specified by its
+full pathname, most shells set
+.Va argv[0]
+to the pathname.
+But this is not required of shells or guaranteed
+by the operating system.
+.It
+If
+.Fa addr
+is of the form
+.Va &func ,
+where
+.Va func
+is a global function, its value may be an unpleasant surprise.
+In
+dynamically linked programs, the address of a global function is
+considered to point to its program linkage table entry, rather than to
+the entry point of the function itself.
+This causes most global
+functions to appear to be defined within the main executable, rather
+than in the shared libraries where the actual code resides.
+.It
+Returning 0 as an indication of failure goes against long-standing
+Unix tradition.
+.El
diff --git a/lib/libc/gen/dlfcn.c b/lib/libc/gen/dlfcn.c
new file mode 100644
index 000000000000..53c9d67ab9e2
--- /dev/null
+++ b/lib/libc/gen/dlfcn.c
@@ -0,0 +1,241 @@
+/*-
+ * Copyright (c) 1998 John D. Polstra
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Linkage to services provided by the dynamic linker.
+ */
+#include <sys/mman.h>
+#include <dlfcn.h>
+#include <link.h>
+#include <stddef.h>
+#include "namespace.h"
+#include <pthread.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+
+static char sorry[] = "Service unavailable";
+
+void _rtld_thread_init(void *);
+void _rtld_atfork_pre(int *);
+void _rtld_atfork_post(int *);
+
+/*
+ * For ELF, the dynamic linker directly resolves references to its
+ * services to functions inside the dynamic linker itself. These
+ * weak-symbol stubs are necessary so that "ld" won't complain about
+ * undefined symbols. The stubs are executed only when the program is
+ * linked statically, or when a given service isn't implemented in the
+ * dynamic linker. They must return an error if called, and they must
+ * be weak symbols so that the dynamic linker can override them.
+ */
+
+#pragma weak _rtld_error
+void
+_rtld_error(const char *fmt, ...)
+{
+}
+
+#pragma weak dladdr
+int
+dladdr(const void *addr, Dl_info *dlip)
+{
+ _rtld_error(sorry);
+ return 0;
+}
+
+#pragma weak dlclose
+int
+dlclose(void *handle)
+{
+ _rtld_error(sorry);
+ return -1;
+}
+
+#pragma weak dlerror
+char *
+dlerror(void)
+{
+ return sorry;
+}
+
+#pragma weak dllockinit
+void
+dllockinit(void *context,
+ void *(*lock_create)(void *context),
+ void (*rlock_acquire)(void *lock),
+ void (*wlock_acquire)(void *lock),
+ void (*lock_release)(void *lock),
+ void (*lock_destroy)(void *lock),
+ void (*context_destroy)(void *context))
+{
+ if (context_destroy != NULL)
+ context_destroy(context);
+}
+
+#pragma weak dlopen
+void *
+dlopen(const char *name, int mode)
+{
+ _rtld_error(sorry);
+ return NULL;
+}
+
+#pragma weak dlsym
+void *
+dlsym(void * __restrict handle, const char * __restrict name)
+{
+ _rtld_error(sorry);
+ return NULL;
+}
+
+#pragma weak dlfunc
+dlfunc_t
+dlfunc(void * __restrict handle, const char * __restrict name)
+{
+ _rtld_error(sorry);
+ return NULL;
+}
+
+#pragma weak dlvsym
+void *
+dlvsym(void * __restrict handle, const char * __restrict name,
+ const char * __restrict version)
+{
+ _rtld_error(sorry);
+ return NULL;
+}
+
+#pragma weak dlinfo
+int
+dlinfo(void * __restrict handle, int request, void * __restrict p)
+{
+ _rtld_error(sorry);
+ return 0;
+}
+
+#pragma weak _rtld_thread_init
+void
+_rtld_thread_init(void * li)
+{
+ _rtld_error(sorry);
+}
+
+static pthread_once_t dl_phdr_info_once = PTHREAD_ONCE_INIT;
+static struct dl_phdr_info phdr_info;
+
+static void
+dl_init_phdr_info(void)
+{
+ Elf_Auxinfo *auxp;
+ unsigned int i;
+
+ for (auxp = __elf_aux_vector; auxp->a_type != AT_NULL; auxp++) {
+ switch (auxp->a_type) {
+ case AT_BASE:
+ phdr_info.dlpi_addr = (Elf_Addr)auxp->a_un.a_ptr;
+ break;
+ case AT_EXECPATH:
+ phdr_info.dlpi_name = (const char *)auxp->a_un.a_ptr;
+ break;
+ case AT_PHDR:
+ phdr_info.dlpi_phdr =
+ (const Elf_Phdr *)auxp->a_un.a_ptr;
+ break;
+ case AT_PHNUM:
+ phdr_info.dlpi_phnum = (Elf_Half)auxp->a_un.a_val;
+ break;
+ }
+ }
+ for (i = 0; i < phdr_info.dlpi_phnum; i++) {
+ if (phdr_info.dlpi_phdr[i].p_type == PT_TLS) {
+ phdr_info.dlpi_tls_modid = 1;
+ phdr_info.dlpi_tls_data =
+ (void*)phdr_info.dlpi_phdr[i].p_vaddr;
+ }
+ }
+ phdr_info.dlpi_adds = 1;
+}
+
+#pragma weak dl_iterate_phdr
+int
+dl_iterate_phdr(int (*callback)(struct dl_phdr_info *, size_t, void *),
+ void *data)
+{
+
+ __init_elf_aux_vector();
+ if (__elf_aux_vector == NULL)
+ return (1);
+ _once(&dl_phdr_info_once, dl_init_phdr_info);
+ return (callback(&phdr_info, sizeof(phdr_info), data));
+}
+
+#pragma weak fdlopen
+void *
+fdlopen(int fd, int mode)
+{
+
+ _rtld_error(sorry);
+ return NULL;
+}
+
+#pragma weak _rtld_atfork_pre
+void
+_rtld_atfork_pre(int *locks)
+{
+}
+
+#pragma weak _rtld_atfork_post
+void
+_rtld_atfork_post(int *locks)
+{
+}
+
+#pragma weak _rtld_addr_phdr
+int
+_rtld_addr_phdr(const void *addr, struct dl_phdr_info *phdr_info)
+{
+
+ return (0);
+}
+
+#pragma weak _rtld_get_stack_prot
+int
+_rtld_get_stack_prot(void)
+{
+
+ return (PROT_EXEC | PROT_READ | PROT_WRITE);
+}
+
+#pragma weak _rtld_is_dlopened
+int
+_rtld_is_dlopened(void *arg)
+{
+
+ return (0);
+}
diff --git a/lib/libc/gen/dlinfo.3 b/lib/libc/gen/dlinfo.3
new file mode 100644
index 000000000000..3fc568e0fcc6
--- /dev/null
+++ b/lib/libc/gen/dlinfo.3
@@ -0,0 +1,279 @@
+.\"
+.\" Copyright (c) 2003 Alexey Zelkin <phantom@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd February 14, 2003
+.Dt DLINFO 3
+.Os
+.Sh NAME
+.Nm dlinfo
+.Nd information about dynamically loaded object
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In link.h
+.In dlfcn.h
+.Ft int
+.Fn dlinfo "void * restrict handle" "int request" "void * restrict p"
+.Sh DESCRIPTION
+The
+.Fn dlinfo
+function provides information about dynamically loaded object.
+The action taken by
+.Fn dlinfo
+and exact meaning and type of
+.Fa p
+argument depend on value of the
+.Fa request
+argument provided by caller.
+.Pp
+The
+.Fa handle
+argument is either the value returned from the
+.Xr dlopen 3
+function call or special handle
+.Dv RTLD_SELF .
+If
+.Fa handle
+is the value returned from
+.Xr dlopen 3 ,
+the information returned by the
+.Fn dlinfo
+function pertains to the specified object.
+If handle is the special handle
+.Dv RTLD_SELF ,
+the information returned pertains to the caller itself.
+.Pp
+Possible values for the
+.Fa request
+argument are:
+.Bl -tag -width indent
+.It Dv RTLD_DI_LINKMAP
+Retrieve the
+.Vt Link_map
+.Pq Vt "struct link_map"
+structure pointer for the specified
+.Fa handle .
+On successful return, the
+.Fa p
+argument is filled with the pointer to the
+.Vt Link_map
+structure
+.Pq Fa "Link_map **p"
+describing a shared object specified by the
+.Fa handle
+argument.
+The
+.Vt Link_map
+structures are maintained as a doubly linked list by
+.Xr ld.so 1 ,
+in the same order as
+.Xr dlopen 3
+and
+.Xr dlclose 3
+are called.
+See
+.Sx EXAMPLES ,
+example 1.
+.Pp
+The
+.Vt Link_map
+structure is defined in
+.In link.h
+and has the following members:
+.Bd -literal -offset indent
+caddr_t l_addr; /* Base Address of library */
+const char *l_name; /* Absolute Path to Library */
+const void *l_ld; /* Pointer to .dynamic in memory */
+struct link_map *l_next, /* linked list of mapped libs */
+ *l_prev;
+.Ed
+.Bl -tag -width ".Va l_addr"
+.It Va l_addr
+The base address of the object loaded into memory.
+.It Va l_name
+The full name of the loaded shared object.
+.It Va l_ld
+The address of the dynamic linking information segment
+.Pq Dv PT_DYNAMIC
+loaded into memory.
+.It Va l_next
+The next
+.Vt Link_map
+structure on the link-map list.
+.It Va l_prev
+The previous
+.Vt Link_map
+structure on the link-map list.
+.El
+.It Dv RTLD_DI_SERINFO
+Retrieve the library search paths associated with the given
+.Fa handle
+argument.
+The
+.Fa p
+argument should point to
+.Vt Dl_serinfo
+structure buffer
+.Pq Fa "Dl_serinfo *p" .
+The
+.Vt Dl_serinfo
+structure must be initialized first with the
+.Dv RTLD_DI_SERINFOSIZE
+request.
+.Pp
+The returned
+.Vt Dl_serinfo
+structure contains
+.Va dls_cnt
+.Vt Dl_serpath
+entries.
+Each entry's
+.Va dlp_name
+field points to the search path.
+The corresponding
+.Va dlp_info
+field contains one of more flags indicating the origin of the path (see the
+.Dv LA_SER_*
+flags defined in the
+.In link.h
+header file).
+See
+.Sx EXAMPLES ,
+example 2, for a usage example.
+.It Dv RTLD_DI_SERINFOSIZE
+Initialize a
+.Vt Dl_serinfo
+structure for use in a
+.Dv RTLD_DI_SERINFO
+request.
+Both the
+.Va dls_cnt
+and
+.Va dls_size
+fields are returned to indicate the number of search paths applicable
+to the handle, and the total size of a
+.Vt Dl_serinfo
+buffer required to hold
+.Va dls_cnt
+.Vt Dl_serpath
+entries and the associated search path strings.
+See
+.Sx EXAMPLES ,
+example 2, for a usage example.
+.It Va RTLD_DI_ORIGIN
+Retrieve the origin of the dynamic object associated with the handle.
+On successful return,
+.Fa p
+argument is filled with the
+.Vt char
+pointer
+.Pq Fa "char *p" .
+.El
+.Sh RETURN VALUES
+The
+.Fn dlinfo
+function returns 0 on success, or \-1 if an error occurred.
+Whenever an error has been detected, a message detailing it can
+be retrieved via a call to
+.Xr dlerror 3 .
+.Sh EXAMPLES
+Example 1: Using
+.Fn dlinfo
+to retrieve
+.Vt Link_map
+structure.
+.Pp
+The following example shows how dynamic library can detect the list
+of shared libraries loaded after caller's one.
+For simplicity, error checking has been omitted.
+.Bd -literal -offset indent
+Link_map *map;
+
+dlinfo(RTLD_SELF, RTLD_DI_LINKMAP, &map);
+
+while (map != NULL) {
+ printf("%p: %s\\n", map->l_addr, map->l_name);
+ map = map->l_next;
+}
+.Ed
+.Pp
+Example 2: Using
+.Fn dlinfo
+to retrieve the library search paths.
+.Pp
+The following example shows how a dynamic object can inspect the library
+search paths that would be used to locate a simple filename with
+.Xr dlopen 3 .
+For simplicity, error checking has been omitted.
+.Bd -literal -offset indent
+Dl_serinfo _info, *info = &_info;
+Dl_serpath *path;
+unsigned int cnt;
+
+/* determine search path count and required buffer size */
+dlinfo(RTLD_SELF, RTLD_DI_SERINFOSIZE, (void *)info);
+
+/* allocate new buffer and initialize */
+info = malloc(_info.dls_size);
+info->dls_size = _info.dls_size;
+info->dls_cnt = _info.dls_cnt;
+
+/* obtain sarch path information */
+dlinfo(RTLD_SELF, RTLD_DI_SERINFO, (void *)info);
+
+path = &info->dls_serpath[0];
+
+for (cnt = 1; cnt <= info->dls_cnt; cnt++, path++) {
+ (void) printf("%2d: %s\\n", cnt, path->dls_name);
+}
+.Ed
+.Sh SEE ALSO
+.Xr rtld 1 ,
+.Xr dladdr 3 ,
+.Xr dlopen 3 ,
+.Xr dlsym 3
+.Sh HISTORY
+The
+.Fn dlinfo
+function first appeared in the Solaris operating system.
+In
+.Fx ,
+it first appeared in
+.Fx 4.8 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Fx
+implementation of the
+.Fn dlinfo
+function was originally written by
+.An Alexey Zelkin Aq Mt phantom@FreeBSD.org
+and later extended and improved by
+.An Alexander Kabaev Aq Mt kan@FreeBSD.org .
+.Pp
+The manual page for this function was written by
+.An Alexey Zelkin Aq Mt phantom@FreeBSD.org .
diff --git a/lib/libc/gen/dllockinit.3 b/lib/libc/gen/dllockinit.3
new file mode 100644
index 000000000000..be3e2cab87f7
--- /dev/null
+++ b/lib/libc/gen/dllockinit.3
@@ -0,0 +1,127 @@
+.\"
+.\" Copyright (c) 1999, 2000 John D. Polstra
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd July 5, 2000
+.Dt DLLOCKINIT 3
+.Os
+.Sh NAME
+.Nm dllockinit
+.Nd register thread locking methods with the dynamic linker
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In dlfcn.h
+.Ft void
+.Fn dllockinit "void *context" "void *(*lock_create)(void *context)" "void (*rlock_acquire)(void *lock)" "void (*wlock_acquire)(void *lock)" "void (*lock_release)(void *lock)" "void (*lock_destroy)(void *lock)" "void (*context_destroy)(void *context)"
+.Sh DESCRIPTION
+.Bf Sy
+Due to enhancements in the dynamic linker, this interface is no longer
+needed.
+It is deprecated and will be removed from future releases.
+In current releases it still exists, but only as a stub which does nothing.
+.Ef
+.Pp
+Threads packages can call
+.Fn dllockinit
+at initialization time to register locking functions for the dynamic
+linker to use.
+This enables the dynamic linker to prevent multiple
+threads from entering its critical sections simultaneously.
+.Pp
+The
+.Fa context
+argument specifies an opaque context for creating locks.
+The
+dynamic linker will pass it to the
+.Fa lock_create
+function when creating the locks it needs.
+When the dynamic linker
+is permanently finished using the locking functions (e.g., if the
+program makes a subsequent call to
+.Fn dllockinit
+to register new locking functions) it will call
+.Fa context_destroy
+to destroy the context.
+.Pp
+The
+.Fa lock_create
+argument specifies a function for creating a read/write lock.
+It
+must return a pointer to the new lock.
+.Pp
+The
+.Fa rlock_acquire
+and
+.Fa wlock_acquire
+arguments specify functions which lock a lock for reading or
+writing, respectively.
+The
+.Fa lock_release
+argument specifies a function which unlocks a lock.
+Each of these
+functions is passed a pointer to the lock.
+.Pp
+The
+.Fa lock_destroy
+argument specifies a function to destroy a lock.
+It may be
+.Dv NULL
+if locks do not need to be destroyed.
+The
+.Fa context_destroy
+argument specifies a function to destroy the context.
+It may be
+.Dv NULL
+if the context does not need to be destroyed.
+.Pp
+Until
+.Fn dllockinit
+is called, the dynamic linker protects its critical sections using
+a default locking mechanism which works by blocking the
+.Dv SIGVTALRM ,
+.Dv SIGPROF ,
+and
+.Dv SIGALRM
+signals.
+This is sufficient for many application level threads
+packages, which typically use one of these signals to implement
+preemption.
+An application which has registered its own locking
+methods with
+.Fn dllockinit
+can restore the default locking by calling
+.Fn dllockinit
+with all arguments
+.Dv NULL .
+.Sh SEE ALSO
+.Xr rtld 1 ,
+.Xr signal 3
+.Sh HISTORY
+The
+.Fn dllockinit
+function first appeared in
+.Fx 4.0 .
diff --git a/lib/libc/gen/dlopen.3 b/lib/libc/gen/dlopen.3
new file mode 100644
index 000000000000..1963528b54bf
--- /dev/null
+++ b/lib/libc/gen/dlopen.3
@@ -0,0 +1,408 @@
+.\" This source code is a product of Sun Microsystems, Inc. and is provided
+.\" for unrestricted use provided that this legend is included on all tape
+.\" media and as a part of the software program in whole or part. Users
+.\" may copy or modify this source code without charge, but are not authorized
+.\" to license or distribute it to anyone else except as part of a product or
+.\" program developed by the user.
+.\"
+.\" THIS PROGRAM CONTAINS SOURCE CODE COPYRIGHTED BY SUN MICROSYSTEMS, INC.
+.\" SUN MICROSYSTEMS, INC., MAKES NO REPRESENTATIONS ABOUT THE SUITABLITY
+.\" OF SUCH SOURCE CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT
+.\" EXPRESS OR IMPLIED WARRANTY OF ANY KIND. SUN MICROSYSTEMS, INC. DISCLAIMS
+.\" ALL WARRANTIES WITH REGARD TO SUCH SOURCE CODE, INCLUDING ALL IMPLIED
+.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN
+.\" NO EVENT SHALL SUN MICROSYSTEMS, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT,
+.\" INCIDENTAL, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+.\" FROM USE OF SUCH SOURCE CODE, REGARDLESS OF THE THEORY OF LIABILITY.
+.\"
+.\" This source code is provided with no support and without any obligation on
+.\" the part of Sun Microsystems, Inc. to assist in its use, correction,
+.\" modification or enhancement.
+.\"
+.\" SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+.\" INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS
+.\" SOURCE CODE OR ANY PART THEREOF.
+.\"
+.\" Sun Microsystems, Inc.
+.\" 2550 Garcia Avenue
+.\" Mountain View, California 94043
+.\"
+.\" Copyright (c) 1991 Sun Microsystems, Inc.
+.\"
+.\" @(#) dlopen.3 1.6 90/01/31 SMI
+.\" $FreeBSD$
+.\"
+.Dd February 14, 2015
+.Dt DLOPEN 3
+.Os
+.Sh NAME
+.Nm dlopen ,
+.Nm fdlopen ,
+.Nm dlsym ,
+.Nm dlfunc ,
+.Nm dlerror ,
+.Nm dlclose
+.Nd programmatic interface to the dynamic linker
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In dlfcn.h
+.Ft void *
+.Fn dlopen "const char *path" "int mode"
+.Ft void *
+.Fn fdlopen "int fd" "int mode"
+.Ft void *
+.Fn dlsym "void * restrict handle" "const char * restrict symbol"
+.Ft dlfunc_t
+.Fn dlfunc "void * restrict handle" "const char * restrict symbol"
+.Ft char *
+.Fn dlerror "void"
+.Ft int
+.Fn dlclose "void *handle"
+.Sh DESCRIPTION
+These functions provide a simple programmatic interface to the services of the
+dynamic linker.
+Operations are provided to add new shared objects to a
+program's address space, to obtain the address bindings of symbols
+defined by such
+objects, and to remove such objects when their use is no longer required.
+.Pp
+The
+.Fn dlopen
+function
+provides access to the shared object in
+.Fa path ,
+returning a descriptor that can be used for later
+references to the object in calls to
+.Fn dlsym
+and
+.Fn dlclose .
+If
+.Fa path
+was not in the address space prior to the call to
+.Fn dlopen ,
+it is placed in the address space.
+When an object is first loaded into the address space in this way, its
+function
+.Fn _init ,
+if any, is called by the dynamic linker.
+If
+.Fa path
+has already been placed in the address space in a previous call to
+.Fn dlopen ,
+it is not added a second time, although a reference count of
+.Fn dlopen
+operations on
+.Fa path
+is maintained.
+A null pointer supplied for
+.Fa path
+is interpreted as a reference to the main
+executable of the process.
+The
+.Fa mode
+argument
+controls the way in which external function references from the
+loaded object are bound to their referents.
+It must contain one of the following values, possibly ORed with
+additional flags which will be described subsequently:
+.Bl -tag -width RTLD_LAZYX
+.It Dv RTLD_LAZY
+Each external function reference is resolved when the function is first
+called.
+.It Dv RTLD_NOW
+All external function references are bound immediately by
+.Fn dlopen .
+.El
+.Pp
+.Dv RTLD_LAZY
+is normally preferred, for reasons of efficiency.
+However,
+.Dv RTLD_NOW
+is useful to ensure that any undefined symbols are discovered during the
+call to
+.Fn dlopen .
+.Pp
+One of the following flags may be ORed into the
+.Fa mode
+argument:
+.Bl -tag -width RTLD_NODELETE
+.It Dv RTLD_GLOBAL
+Symbols from this shared object and its directed acyclic graph (DAG)
+of needed objects will be available for resolving undefined references
+from all other shared objects.
+.It Dv RTLD_LOCAL
+Symbols in this shared object and its DAG of needed objects will be
+available for resolving undefined references only from other objects
+in the same DAG.
+This is the default, but it may be specified
+explicitly with this flag.
+.It Dv RTLD_TRACE
+When set, causes dynamic linker to exit after loading all objects
+needed by this shared object and printing a summary which includes
+the absolute pathnames of all objects, to standard output.
+With this flag
+.Fn dlopen
+will return to the caller only in the case of error.
+.It Dv RTLD_NODELETE
+Prevents unload of the loaded object on
+.Fn dlclose .
+The same behaviour may be requested by
+.Fl "z nodelete"
+option of the static linker
+.Xr ld 1 .
+.It Dv RTLD_NOLOAD
+Only return valid handle for the object if it is already loaded in
+the process address space, otherwise
+.Dv NULL
+is returned.
+Other mode flags may be specified, which will be applied for promotion
+for the found object.
+.El
+.Pp
+If
+.Fn dlopen
+fails, it returns a null pointer, and sets an error condition which may
+be interrogated with
+.Fn dlerror .
+.Pp
+The
+.Fn fdlopen
+function is similar to
+.Fn dlopen ,
+but it takes the file descriptor argument
+.Fa fd ,
+which is used for the file operations needed to load an object
+into the address space.
+The file descriptor
+.Fa fd
+is not closed by the function regardless a result of execution,
+but a duplicate of the file descriptor is.
+This may be important if a
+.Xr lockf 3
+lock is held on the passed descriptor.
+The
+.Fa fd
+argument -1 is interpreted as a reference to the main
+executable of the process, similar to
+.Va NULL
+value for the
+.Fa name
+argument to
+.Fn dlopen .
+The
+.Fn fdlopen
+function can be used by the code that needs to perform
+additional checks on the loaded objects, to prevent races with
+symlinking or renames.
+.Pp
+The
+.Fn dlsym
+function
+returns the address binding of the symbol described in the null-terminated
+character string
+.Fa symbol ,
+as it occurs in the shared object identified by
+.Fa handle .
+The symbols exported by objects added to the address space by
+.Fn dlopen
+can be accessed only through calls to
+.Fn dlsym .
+Such symbols do not supersede any definition of those symbols already present
+in the address space when the object is loaded, nor are they available to
+satisfy normal dynamic linking references.
+.Pp
+If
+.Fn dlsym
+is called with the special
+.Fa handle
+.Dv NULL ,
+it is interpreted as a reference to the executable or shared object
+from which the call
+is being made.
+Thus a shared object can reference its own symbols.
+.Pp
+If
+.Fn dlsym
+is called with the special
+.Fa handle
+.Dv RTLD_DEFAULT ,
+the search for the symbol follows the algorithm used for resolving
+undefined symbols when objects are loaded.
+The objects searched are
+as follows, in the given order:
+.Bl -enum
+.It
+The referencing object itself (or the object from which the call to
+.Fn dlsym
+is made), if that object was linked using the
+.Fl Bsymbolic
+option to
+.Xr ld 1 .
+.It
+All objects loaded at program start-up.
+.It
+All objects loaded via
+.Fn dlopen
+with the
+.Dv RTLD_GLOBAL
+flag set in the
+.Fa mode
+argument.
+.It
+All objects loaded via
+.Fn dlopen
+which are in needed-object DAGs that also contain the referencing object.
+.El
+.Pp
+If
+.Fn dlsym
+is called with the special
+.Fa handle
+.Dv RTLD_NEXT ,
+then the search for the symbol is limited to the shared objects
+which were loaded after the one issuing the call to
+.Fn dlsym .
+Thus, if the function is called from the main program, all
+the shared libraries are searched.
+If it is called from a shared library, all subsequent shared
+libraries are searched.
+.Dv RTLD_NEXT
+is useful for implementing wrappers around library functions.
+For example, a wrapper function
+.Fn getpid
+could access the
+.Dq real
+.Fn getpid
+with
+.Li dlsym(RTLD_NEXT, \&"getpid\&") .
+(Actually, the
+.Fn dlfunc
+interface, below, should be used, since
+.Fn getpid
+is a function and not a data object.)
+.Pp
+If
+.Fn dlsym
+is called with the special
+.Fa handle
+.Dv RTLD_SELF ,
+then the search for the symbol is limited to the shared object
+issuing the call to
+.Fn dlsym
+and those shared objects which were loaded after it.
+.Pp
+The
+.Fn dlsym
+function
+returns a null pointer if the symbol cannot be found, and sets an error
+condition which may be queried with
+.Fn dlerror .
+.Pp
+The
+.Fn dlfunc
+function
+implements all of the behavior of
+.Fn dlsym ,
+but has a return type which can be cast to a function pointer without
+triggering compiler diagnostics.
+(The
+.Fn dlsym
+function
+returns a data pointer; in the C standard, conversions between
+data and function pointer types are undefined.
+Some compilers and
+.Xr lint 1
+utilities warn about such casts.)
+The precise return type of
+.Fn dlfunc
+is unspecified; applications must cast it to an appropriate function pointer
+type.
+.Pp
+The
+.Fn dlerror
+function
+returns a null-terminated character string describing the last error that
+occurred during a call to
+.Fn dlopen ,
+.Fn dladdr ,
+.Fn dlinfo ,
+.Fn dlsym ,
+.Fn dlfunc ,
+or
+.Fn dlclose .
+If no such error has occurred,
+.Fn dlerror
+returns a null pointer.
+At each call to
+.Fn dlerror ,
+the error indication is reset.
+Thus in the case of two calls
+to
+.Fn dlerror ,
+where the second call follows the first immediately, the second call
+will always return a null pointer.
+.Pp
+The
+.Fn dlclose
+function
+deletes a reference to the shared object referenced by
+.Fa handle .
+If the reference count drops to 0, the object is removed from the
+address space, and
+.Fa handle
+is rendered invalid.
+Just before removing a shared object in this way, the dynamic linker
+calls the object's
+.Fn _fini
+function, if such a function is defined by the object.
+If
+.Fn dlclose
+is successful, it returns a value of 0.
+Otherwise it returns -1, and sets an error condition that can be
+interrogated with
+.Fn dlerror .
+.Pp
+The object-intrinsic functions
+.Fn _init
+and
+.Fn _fini
+are called with no arguments, and are not expected to return values.
+.Sh NOTES
+ELF executables need to be linked
+using the
+.Fl export-dynamic
+option to
+.Xr ld 1
+for symbols defined in the executable to become visible to
+.Fn dlsym .
+.Pp
+In previous implementations, it was necessary to prepend an underscore
+to all external symbols in order to gain symbol
+compatibility with object code compiled from the C language.
+This is
+still the case when using the (obsolete)
+.Fl aout
+option to the C language compiler.
+.Sh ERRORS
+The
+.Fn dlopen ,
+.Fn fdlopen ,
+.Fn dlsym ,
+and
+.Fn dlfunc
+functions
+return a null pointer in the event of errors.
+The
+.Fn dlclose
+function
+returns 0 on success, or -1 if an error occurred.
+Whenever an error has been detected, a message detailing it can be
+retrieved via a call to
+.Fn dlerror .
+.Sh SEE ALSO
+.Xr ld 1 ,
+.Xr rtld 1 ,
+.Xr dladdr 3 ,
+.Xr dlinfo 3 ,
+.Xr link 5
diff --git a/lib/libc/gen/drand48.c b/lib/libc/gen/drand48.c
new file mode 100644
index 000000000000..672b5eef6b19
--- /dev/null
+++ b/lib/libc/gen/drand48.c
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 1993 Martin Birgmeier
+ * All rights reserved.
+ *
+ * You may redistribute unmodified or modified versions of this source
+ * code provided that the above copyright notice and this and the
+ * following conditions are retained.
+ *
+ * This software is provided ``as is'', and comes with no warranties
+ * of any kind. I shall in no event be liable for anything that happens
+ * to anyone/anything when using this software.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "rand48.h"
+
+extern unsigned short _rand48_seed[3];
+
+double
+drand48(void)
+{
+ return erand48(_rand48_seed);
+}
diff --git a/lib/libc/gen/dup3.3 b/lib/libc/gen/dup3.3
new file mode 100644
index 000000000000..d3bb116189b7
--- /dev/null
+++ b/lib/libc/gen/dup3.3
@@ -0,0 +1,116 @@
+.\" Copyright (c) 2013 Jilles Tjoelker
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd August 16, 2013
+.Dt DUP3 3
+.Os
+.Sh NAME
+.Nm dup3
+.Nd duplicate an existing file descriptor
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In fcntl.h
+.In unistd.h
+.Ft int
+.Fn dup3 "int oldd" "int newd" "int flags"
+.Sh DESCRIPTION
+The
+.Fn dup3
+function
+duplicates an existing object descriptor
+while allowing the value of the new descriptor to be specified.
+.Pp
+The close-on-exec flag on the new file descriptor is determined by the
+.Dv O_CLOEXEC
+bit in
+.Fa flags .
+.Pp
+If
+.Fa oldd
+\*(Ne
+.Fa newd
+and
+.Fa flags
+== 0,
+the behavior is identical to
+.Li dup2(oldd, newd) .
+.Pp
+If
+.Fa oldd
+==
+.Fa newd ,
+then
+.Fn dup3
+fails, unlike
+.Xr dup2 2 .
+.Sh RETURN VALUES
+The value -1 is returned if an error occurs.
+The external variable
+.Va errno
+indicates the cause of the error.
+.Sh ERRORS
+The
+.Fn dup3
+function fails if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa oldd
+argument is not a valid active descriptor or the
+.Fa newd
+argument is negative or exceeds the maximum allowable descriptor number
+.It Bq Er EINVAL
+The
+.Fa oldd
+argument is equal to the
+.Fa newd
+argument.
+.It Bq Er EINVAL
+The
+.Fa flags
+argument has bits set other than
+.Dv O_CLOEXEC .
+.El
+.Sh SEE ALSO
+.Xr accept 2 ,
+.Xr close 2 ,
+.Xr dup2 2 ,
+.Xr fcntl 2 ,
+.Xr getdtablesize 2 ,
+.Xr open 2 ,
+.Xr pipe 2 ,
+.Xr socket 2 ,
+.Xr socketpair 2
+.Sh STANDARDS
+The
+.Fn dup3
+function does not conform to any standard.
+.Sh HISTORY
+The
+.Fn dup3
+function appeared in
+.Fx 10.0 .
diff --git a/lib/libc/gen/dup3.c b/lib/libc/gen/dup3.c
new file mode 100644
index 000000000000..ff3431af461b
--- /dev/null
+++ b/lib/libc/gen/dup3.c
@@ -0,0 +1,61 @@
+/*-
+ * Copyright (c) 2012 Jukka A. Ukkonen
+ * All rights reserved.
+ *
+ * This software was developed by Jukka Ukkonen for FreeBSD.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include "un-namespace.h"
+
+int __dup3(int, int, int);
+
+int
+__dup3(int oldfd, int newfd, int flags)
+{
+ int how;
+
+ if (oldfd == newfd) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (flags & ~O_CLOEXEC) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ how = (flags & O_CLOEXEC) ? F_DUP2FD_CLOEXEC : F_DUP2FD;
+
+ return (_fcntl(oldfd, how, newfd));
+}
+
+__weak_reference(__dup3, dup3);
+__weak_reference(__dup3, _dup3);
diff --git a/lib/libc/gen/elf_utils.c b/lib/libc/gen/elf_utils.c
new file mode 100644
index 000000000000..80ab013849b7
--- /dev/null
+++ b/lib/libc/gen/elf_utils.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2010 Konstantin Belousov <kib@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/resource.h>
+#include <sys/sysctl.h>
+#include <link.h>
+#include <stddef.h>
+#include "libc_private.h"
+
+int __elf_phdr_match_addr(struct dl_phdr_info *, void *);
+void __pthread_map_stacks_exec(void);
+
+int
+__elf_phdr_match_addr(struct dl_phdr_info *phdr_info, void *addr)
+{
+ const Elf_Phdr *ph;
+ int i;
+
+ for (i = 0; i < phdr_info->dlpi_phnum; i++) {
+ ph = &phdr_info->dlpi_phdr[i];
+ if (ph->p_type != PT_LOAD || (ph->p_flags & PF_X) == 0)
+ continue;
+ if (phdr_info->dlpi_addr + ph->p_vaddr <= (uintptr_t)addr &&
+ (uintptr_t)addr + sizeof(addr) < phdr_info->dlpi_addr +
+ ph->p_vaddr + ph->p_memsz)
+ break;
+ }
+ return (i != phdr_info->dlpi_phnum);
+}
+
+void
+__libc_map_stacks_exec(void)
+{
+ int mib[2];
+ struct rlimit rlim;
+ u_long usrstack;
+ size_t len;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_USRSTACK;
+ len = sizeof(usrstack);
+ if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), &usrstack, &len, NULL, 0)
+ == -1)
+ return;
+ if (getrlimit(RLIMIT_STACK, &rlim) == -1)
+ return;
+ mprotect((void *)(uintptr_t)(usrstack - rlim.rlim_cur),
+ rlim.rlim_cur, _rtld_get_stack_prot());
+}
+
+#pragma weak __pthread_map_stacks_exec
+void
+__pthread_map_stacks_exec(void)
+{
+
+ ((void (*)(void))__libc_interposing[INTERPOS_map_stacks_exec])();
+}
diff --git a/lib/libc/gen/erand48.c b/lib/libc/gen/erand48.c
new file mode 100644
index 000000000000..cdb3ec85052b
--- /dev/null
+++ b/lib/libc/gen/erand48.c
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 1993 Martin Birgmeier
+ * All rights reserved.
+ *
+ * You may redistribute unmodified or modified versions of this source
+ * code provided that the above copyright notice and this and the
+ * following conditions are retained.
+ *
+ * This software is provided ``as is'', and comes with no warranties
+ * of any kind. I shall in no event be liable for anything that happens
+ * to anyone/anything when using this software.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "rand48.h"
+
+double
+erand48(unsigned short xseed[3])
+{
+ _dorand48(xseed);
+ return ldexp((double) xseed[0], -48) +
+ ldexp((double) xseed[1], -32) +
+ ldexp((double) xseed[2], -16);
+}
diff --git a/lib/libc/gen/err.3 b/lib/libc/gen/err.3
new file mode 100644
index 000000000000..8bd31c360e11
--- /dev/null
+++ b/lib/libc/gen/err.3
@@ -0,0 +1,245 @@
+.\" Copyright (c) 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" From: @(#)err.3 8.1 (Berkeley) 6/9/93
+.\" $FreeBSD$
+.\"
+.Dd March 29, 2012
+.Dt ERR 3
+.Os
+.Sh NAME
+.Nm err ,
+.Nm verr ,
+.Nm errc ,
+.Nm verrc ,
+.Nm errx ,
+.Nm verrx ,
+.Nm warn ,
+.Nm vwarn ,
+.Nm warnc ,
+.Nm vwarnc ,
+.Nm warnx ,
+.Nm vwarnx ,
+.Nm err_set_exit ,
+.Nm err_set_file
+.Nd formatted error messages
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In err.h
+.Ft void
+.Fn err "int eval" "const char *fmt" "..."
+.Ft void
+.Fn err_set_exit "void (*exitf)(int)"
+.Ft void
+.Fn err_set_file "void *vfp"
+.Ft void
+.Fn errc "int eval" "int code" "const char *fmt" "..."
+.Ft void
+.Fn errx "int eval" "const char *fmt" "..."
+.Ft void
+.Fn warn "const char *fmt" "..."
+.Ft void
+.Fn warnc "int code" "const char *fmt" "..."
+.Ft void
+.Fn warnx "const char *fmt" "..."
+.In stdarg.h
+.Ft void
+.Fn verr "int eval" "const char *fmt" "va_list args"
+.Ft void
+.Fn verrc "int eval" "int code" "const char *fmt" "va_list args"
+.Ft void
+.Fn verrx "int eval" "const char *fmt" "va_list args"
+.Ft void
+.Fn vwarn "const char *fmt" "va_list args"
+.Ft void
+.Fn vwarnc "int code" "const char *fmt" "va_list args"
+.Ft void
+.Fn vwarnx "const char *fmt" "va_list args"
+.Sh DESCRIPTION
+The
+.Fn err
+and
+.Fn warn
+family of functions display a formatted error message on the standard
+error output, or on another file specified using the
+.Fn err_set_file
+function.
+In all cases, the last component of the program name, a colon character,
+and a space are output.
+If the
+.Fa fmt
+argument is not NULL, the
+.Xr printf 3 Ns
+-like formatted error message is output.
+The output is terminated by a newline character.
+.Pp
+The
+.Fn err ,
+.Fn errc ,
+.Fn verr ,
+.Fn verrc ,
+.Fn warn ,
+.Fn warnc ,
+.Fn vwarn ,
+and
+.Fn vwarnc
+functions append an error message obtained from
+.Xr strerror 3
+based on a supplied error code value or the global variable
+.Va errno ,
+preceded by another colon and space unless the
+.Fa fmt
+argument is
+.Dv NULL .
+.Pp
+In the case of the
+.Fn errc ,
+.Fn verrc ,
+.Fn warnc ,
+and
+.Fn vwarnc
+functions,
+the
+.Fa code
+argument is used to look up the error message.
+.Pp
+The
+.Fn err ,
+.Fn verr ,
+.Fn warn ,
+and
+.Fn vwarn
+functions use the global variable
+.Va errno
+to look up the error message.
+.Pp
+The
+.Fn errx
+and
+.Fn warnx
+functions do not append an error message.
+.Pp
+The
+.Fn err ,
+.Fn verr ,
+.Fn errc ,
+.Fn verrc ,
+.Fn errx ,
+and
+.Fn verrx
+functions do not return, but exit with the value of the argument
+.Fa eval .
+It is recommended that the standard values defined in
+.Xr sysexits 3
+be used for the value of
+.Fa eval .
+The
+.Fn err_set_exit
+function can be used to specify a function which is called before
+.Xr exit 3
+to perform any necessary cleanup; passing a null function pointer for
+.Va exitf
+resets the hook to do nothing.
+The
+.Fn err_set_file
+function sets the output stream used by the other functions.
+Its
+.Fa vfp
+argument must be either a pointer to an open stream
+(possibly already converted to void *)
+or a null pointer
+(in which case the output stream is set to standard error).
+.Sh EXAMPLES
+Display the current errno information string and exit:
+.Bd -literal -offset indent
+if ((p = malloc(size)) == NULL)
+ err(EX_OSERR, NULL);
+if ((fd = open(file_name, O_RDONLY, 0)) == -1)
+ err(EX_NOINPUT, "%s", file_name);
+.Ed
+.Pp
+Display an error message and exit:
+.Bd -literal -offset indent
+if (tm.tm_hour < START_TIME)
+ errx(EX_DATAERR, "too early, wait until %s",
+ start_time_string);
+.Ed
+.Pp
+Warn of an error:
+.Bd -literal -offset indent
+if ((fd = open(raw_device, O_RDONLY, 0)) == -1)
+ warnx("%s: %s: trying the block device",
+ raw_device, strerror(errno));
+if ((fd = open(block_device, O_RDONLY, 0)) == -1)
+ err(EX_OSFILE, "%s", block_device);
+.Ed
+.Pp
+Warn of an error without using the global variable
+.Va errno :
+.Bd -literal -offset indent
+error = my_function(); /* returns a value from <errno.h> */
+if (error != 0)
+ warnc(error, "my_function");
+.Ed
+.Sh SEE ALSO
+.Xr exit 3 ,
+.Xr fmtmsg 3 ,
+.Xr printf 3 ,
+.Xr strerror 3 ,
+.Xr sysexits 3
+.Sh STANDARDS
+The
+.Fn err
+and
+.Fn warn
+families of functions are
+.Bx
+extensions.
+As such they should not be used in truly portable code.
+Use
+.Fn strerror
+or similar functions instead.
+.Sh HISTORY
+The
+.Fn err
+and
+.Fn warn
+functions first appeared in
+.Bx 4.4 .
+The
+.Fn err_set_exit
+and
+.Fn err_set_file
+functions first appeared in
+.Fx 2.1 .
+The
+.Fn errc
+and
+.Fn warnc
+functions first appeared in
+.Fx 3.0 .
diff --git a/lib/libc/gen/err.c b/lib/libc/gen/err.c
new file mode 100644
index 000000000000..3b32c3d61528
--- /dev/null
+++ b/lib/libc/gen/err.c
@@ -0,0 +1,192 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)err.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <err.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "un-namespace.h"
+
+#include "libc_private.h"
+
+static FILE *err_file; /* file to use for error output */
+static void (*err_exit)(int);
+
+/*
+ * This is declared to take a `void *' so that the caller is not required
+ * to include <stdio.h> first. However, it is really a `FILE *', and the
+ * manual page documents it as such.
+ */
+void
+err_set_file(void *fp)
+{
+ if (fp)
+ err_file = fp;
+ else
+ err_file = stderr;
+}
+
+void
+err_set_exit(void (*ef)(int))
+{
+ err_exit = ef;
+}
+
+__weak_reference(_err, err);
+
+void
+_err(int eval, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ verrc(eval, errno, fmt, ap);
+ va_end(ap);
+}
+
+void
+verr(int eval, const char *fmt, va_list ap)
+{
+ verrc(eval, errno, fmt, ap);
+}
+
+void
+errc(int eval, int code, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ verrc(eval, code, fmt, ap);
+ va_end(ap);
+}
+
+void
+verrc(int eval, int code, const char *fmt, va_list ap)
+{
+ if (err_file == NULL)
+ err_set_file((FILE *)0);
+ fprintf(err_file, "%s: ", _getprogname());
+ if (fmt != NULL) {
+ vfprintf(err_file, fmt, ap);
+ fprintf(err_file, ": ");
+ }
+ fprintf(err_file, "%s\n", strerror(code));
+ if (err_exit)
+ err_exit(eval);
+ exit(eval);
+}
+
+void
+errx(int eval, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ verrx(eval, fmt, ap);
+ va_end(ap);
+}
+
+void
+verrx(int eval, const char *fmt, va_list ap)
+{
+ if (err_file == NULL)
+ err_set_file((FILE *)0);
+ fprintf(err_file, "%s: ", _getprogname());
+ if (fmt != NULL)
+ vfprintf(err_file, fmt, ap);
+ fprintf(err_file, "\n");
+ if (err_exit)
+ err_exit(eval);
+ exit(eval);
+}
+
+__weak_reference(_warn, warn);
+
+void
+_warn(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vwarnc(errno, fmt, ap);
+ va_end(ap);
+}
+
+void
+vwarn(const char *fmt, va_list ap)
+{
+ vwarnc(errno, fmt, ap);
+}
+
+void
+warnc(int code, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vwarnc(code, fmt, ap);
+ va_end(ap);
+}
+
+void
+vwarnc(int code, const char *fmt, va_list ap)
+{
+ if (err_file == NULL)
+ err_set_file((FILE *)0);
+ fprintf(err_file, "%s: ", _getprogname());
+ if (fmt != NULL) {
+ vfprintf(err_file, fmt, ap);
+ fprintf(err_file, ": ");
+ }
+ fprintf(err_file, "%s\n", strerror(code));
+}
+
+void
+warnx(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vwarnx(fmt, ap);
+ va_end(ap);
+}
+
+void
+vwarnx(const char *fmt, va_list ap)
+{
+ if (err_file == NULL)
+ err_set_file((FILE *)0);
+ fprintf(err_file, "%s: ", _getprogname());
+ if (fmt != NULL)
+ vfprintf(err_file, fmt, ap);
+ fprintf(err_file, "\n");
+}
diff --git a/lib/libc/gen/errlst.c b/lib/libc/gen/errlst.c
new file mode 100644
index 000000000000..f8fe9684a26a
--- /dev/null
+++ b/lib/libc/gen/errlst.c
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 1982, 1985, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)errlst.c 8.2 (Berkeley) 11/16/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include "errlst.h"
+
+const char *const sys_errlist[] = {
+ "No error: 0", /* 0 - ENOERROR */
+ "Operation not permitted", /* 1 - EPERM */
+ "No such file or directory", /* 2 - ENOENT */
+ "No such process", /* 3 - ESRCH */
+ "Interrupted system call", /* 4 - EINTR */
+ "Input/output error", /* 5 - EIO */
+ "Device not configured", /* 6 - ENXIO */
+ "Argument list too long", /* 7 - E2BIG */
+ "Exec format error", /* 8 - ENOEXEC */
+ "Bad file descriptor", /* 9 - EBADF */
+ "No child processes", /* 10 - ECHILD */
+ "Resource deadlock avoided", /* 11 - EDEADLK */
+ "Cannot allocate memory", /* 12 - ENOMEM */
+ "Permission denied", /* 13 - EACCES */
+ "Bad address", /* 14 - EFAULT */
+ "Block device required", /* 15 - ENOTBLK */
+ "Device busy", /* 16 - EBUSY */
+ "File exists", /* 17 - EEXIST */
+ "Cross-device link", /* 18 - EXDEV */
+ "Operation not supported by device", /* 19 - ENODEV */
+ "Not a directory", /* 20 - ENOTDIR */
+ "Is a directory", /* 21 - EISDIR */
+ "Invalid argument", /* 22 - EINVAL */
+ "Too many open files in system", /* 23 - ENFILE */
+ "Too many open files", /* 24 - EMFILE */
+ "Inappropriate ioctl for device", /* 25 - ENOTTY */
+ "Text file busy", /* 26 - ETXTBSY */
+ "File too large", /* 27 - EFBIG */
+ "No space left on device", /* 28 - ENOSPC */
+ "Illegal seek", /* 29 - ESPIPE */
+ "Read-only file system", /* 30 - EROFS */
+ "Too many links", /* 31 - EMLINK */
+ "Broken pipe", /* 32 - EPIPE */
+
+/* math software */
+ "Numerical argument out of domain", /* 33 - EDOM */
+ "Result too large", /* 34 - ERANGE */
+
+/* non-blocking and interrupt i/o */
+ "Resource temporarily unavailable", /* 35 - EAGAIN */
+ /* 35 - EWOULDBLOCK */
+ "Operation now in progress", /* 36 - EINPROGRESS */
+ "Operation already in progress", /* 37 - EALREADY */
+
+/* ipc/network software -- argument errors */
+ "Socket operation on non-socket", /* 38 - ENOTSOCK */
+ "Destination address required", /* 39 - EDESTADDRREQ */
+ "Message too long", /* 40 - EMSGSIZE */
+ "Protocol wrong type for socket", /* 41 - EPROTOTYPE */
+ "Protocol not available", /* 42 - ENOPROTOOPT */
+ "Protocol not supported", /* 43 - EPROTONOSUPPORT */
+ "Socket type not supported", /* 44 - ESOCKTNOSUPPORT */
+ "Operation not supported", /* 45 - EOPNOTSUPP */
+ "Protocol family not supported", /* 46 - EPFNOSUPPORT */
+ /* 47 - EAFNOSUPPORT */
+ "Address family not supported by protocol family",
+ "Address already in use", /* 48 - EADDRINUSE */
+ "Can't assign requested address", /* 49 - EADDRNOTAVAIL */
+
+/* ipc/network software -- operational errors */
+ "Network is down", /* 50 - ENETDOWN */
+ "Network is unreachable", /* 51 - ENETUNREACH */
+ "Network dropped connection on reset", /* 52 - ENETRESET */
+ "Software caused connection abort", /* 53 - ECONNABORTED */
+ "Connection reset by peer", /* 54 - ECONNRESET */
+ "No buffer space available", /* 55 - ENOBUFS */
+ "Socket is already connected", /* 56 - EISCONN */
+ "Socket is not connected", /* 57 - ENOTCONN */
+ "Can't send after socket shutdown", /* 58 - ESHUTDOWN */
+ "Too many references: can't splice", /* 59 - ETOOMANYREFS */
+ "Operation timed out", /* 60 - ETIMEDOUT */
+ "Connection refused", /* 61 - ECONNREFUSED */
+
+ "Too many levels of symbolic links", /* 62 - ELOOP */
+ "File name too long", /* 63 - ENAMETOOLONG */
+
+/* should be rearranged */
+ "Host is down", /* 64 - EHOSTDOWN */
+ "No route to host", /* 65 - EHOSTUNREACH */
+ "Directory not empty", /* 66 - ENOTEMPTY */
+
+/* quotas & mush */
+ "Too many processes", /* 67 - EPROCLIM */
+ "Too many users", /* 68 - EUSERS */
+ "Disc quota exceeded", /* 69 - EDQUOT */
+
+/* Network File System */
+ "Stale NFS file handle", /* 70 - ESTALE */
+ "Too many levels of remote in path", /* 71 - EREMOTE */
+ "RPC struct is bad", /* 72 - EBADRPC */
+ "RPC version wrong", /* 73 - ERPCMISMATCH */
+ "RPC prog. not avail", /* 74 - EPROGUNAVAIL */
+ "Program version wrong", /* 75 - EPROGMISMATCH */
+ "Bad procedure for program", /* 76 - EPROCUNAVAIL */
+
+ "No locks available", /* 77 - ENOLCK */
+ "Function not implemented", /* 78 - ENOSYS */
+ "Inappropriate file type or format", /* 79 - EFTYPE */
+ "Authentication error", /* 80 - EAUTH */
+ "Need authenticator", /* 81 - ENEEDAUTH */
+ "Identifier removed", /* 82 - EIDRM */
+ "No message of desired type", /* 83 - ENOMSG */
+ "Value too large to be stored in data type", /* 84 - EOVERFLOW */
+ "Operation canceled", /* 85 - ECANCELED */
+ "Illegal byte sequence", /* 86 - EILSEQ */
+ "Attribute not found", /* 87 - ENOATTR */
+
+/* General */
+ "Programming error", /* 88 - EDOOFUS */
+
+ "Bad message", /* 89 - EBADMSG */
+ "Multihop attempted", /* 90 - EMULTIHOP */
+ "Link has been severed", /* 91 - ENOLINK */
+ "Protocol error", /* 92 - EPROTO */
+ "Capabilities insufficient", /* 93 - ENOTCAPABLE */
+ "Not permitted in capability mode", /* 94 - ECAPMODE */
+ "State not recoverable", /* 95 - ENOTRECOVERABLE */
+ "Previous owner died", /* 96 - EOWNERDEAD */
+};
+const int sys_nerr = sizeof(sys_errlist) / sizeof(sys_errlist[0]);
+
+#ifdef PIC
+__strong_reference(sys_errlist, __hidden_sys_errlist);
+__strong_reference(sys_nerr, __hidden_sys_nerr);
+#endif
diff --git a/lib/libc/gen/errno.c b/lib/libc/gen/errno.c
new file mode 100644
index 000000000000..02e0351badc2
--- /dev/null
+++ b/lib/libc/gen/errno.c
@@ -0,0 +1,30 @@
+/*-
+ * Copyright (c) 2002 Peter Wemm <peter@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+int errno;
diff --git a/lib/libc/gen/exec.3 b/lib/libc/gen/exec.3
new file mode 100644
index 000000000000..0805c62d6463
--- /dev/null
+++ b/lib/libc/gen/exec.3
@@ -0,0 +1,321 @@
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)exec.3 8.3 (Berkeley) 1/24/94
+.\" $FreeBSD$
+.\"
+.Dd January 5, 2016
+.Dt EXEC 3
+.Os
+.Sh NAME
+.Nm execl ,
+.Nm execlp ,
+.Nm execle ,
+.Nm exect ,
+.Nm execv ,
+.Nm execvp ,
+.Nm execvP
+.Nd execute a file
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Vt extern char **environ ;
+.Ft int
+.Fn execl "const char *path" "const char *arg" ... /* "(char *)0" */
+.Ft int
+.Fn execlp "const char *file" "const char *arg" ... /* "(char *)0" */
+.Ft int
+.Fo execle
+.Fa "const char *path" "const char *arg" ...
+.Fa /*
+.Bk -words
+.Fa "(char *)0" "char *const envp[]" */
+.Ek
+.Fc
+.Ft int
+.Fn exect "const char *path" "char *const argv[]" "char *const envp[]"
+.Ft int
+.Fn execv "const char *path" "char *const argv[]"
+.Ft int
+.Fn execvp "const char *file" "char *const argv[]"
+.Ft int
+.Fn execvP "const char *file" "const char *search_path" "char *const argv[]"
+.Sh DESCRIPTION
+The
+.Nm exec
+family of functions replaces the current process image with a
+new process image.
+The functions described in this manual page are front-ends for the function
+.Xr execve 2 .
+(See the manual page for
+.Xr execve 2
+for detailed information about the replacement of the current process.)
+.Pp
+The initial argument for these functions is the pathname of a file which
+is to be executed.
+.Pp
+The
+.Fa "const char *arg"
+and subsequent ellipses in the
+.Fn execl ,
+.Fn execlp ,
+and
+.Fn execle
+functions can be thought of as
+.Em arg0 ,
+.Em arg1 ,
+\&...,
+.Em argn .
+Together they describe a list of one or more pointers to null-terminated
+strings that represent the argument list available to the executed program.
+The first argument, by convention, should point to the file name associated
+with the file being executed.
+The list of arguments
+.Em must
+be terminated by a
+.Dv NULL
+pointer.
+.Pp
+The
+.Fn exect ,
+.Fn execv ,
+.Fn execvp ,
+and
+.Fn execvP
+functions provide an array of pointers to null-terminated strings that
+represent the argument list available to the new program.
+The first argument, by convention, should point to the file name associated
+with the file being executed.
+The array of pointers
+.Sy must
+be terminated by a
+.Dv NULL
+pointer.
+.Pp
+The
+.Fn execle
+and
+.Fn exect
+functions also specify the environment of the executed process by following
+the
+.Dv NULL
+pointer that terminates the list of arguments in the argument list
+or the pointer to the argv array with an additional argument.
+This additional argument is an array of pointers to null-terminated strings
+and
+.Em must
+be terminated by a
+.Dv NULL
+pointer.
+The other functions take the environment for the new process image from the
+external variable
+.Va environ
+in the current process.
+.Pp
+Some of these functions have special semantics.
+.Pp
+The functions
+.Fn execlp ,
+.Fn execvp ,
+and
+.Fn execvP
+will duplicate the actions of the shell in searching for an executable file
+if the specified file name does not contain a slash
+.Dq Li /
+character.
+For
+.Fn execlp
+and
+.Fn execvp ,
+search path is the path specified in the environment by
+.Dq Ev PATH
+variable.
+If this variable is not specified,
+the default path is set according to the
+.Dv _PATH_DEFPATH
+definition in
+.In paths.h ,
+which is set to
+.Dq Ev /sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin .
+For
+.Fn execvP ,
+the search path is specified as an argument to the function.
+In addition, certain errors are treated specially.
+.Pp
+If an error is ambiguous (for simplicity, we shall consider all
+errors except
+.Er ENOEXEC
+as being ambiguous here, although only the critical error
+.Er EACCES
+is really ambiguous),
+then these functions will act as if they stat the file to determine
+whether the file exists and has suitable execute permissions.
+If it does, they will return immediately with the global variable
+.Va errno
+restored to the value set by
+.Fn execve .
+Otherwise, the search will be continued.
+If the search completes without performing a successful
+.Fn execve
+or terminating due to an error,
+these functions will return with the global variable
+.Va errno
+set to
+.Er EACCES
+or
+.Er ENOENT
+according to whether at least one file with suitable execute permissions
+was found.
+.Pp
+If the header of a file is not recognized (the attempted
+.Fn execve
+returned
+.Er ENOEXEC ) ,
+these functions will execute the shell with the path of
+the file as its first argument.
+(If this attempt fails, no further searching is done.)
+.Pp
+The function
+.Fn exect
+executes a file with the program tracing facilities enabled (see
+.Xr ptrace 2 ) .
+.Sh RETURN VALUES
+If any of the
+.Fn exec
+functions returns, an error will have occurred.
+The return value is \-1, and the global variable
+.Va errno
+will be set to indicate the error.
+.Sh FILES
+.Bl -tag -width /bin/sh -compact
+.It Pa /bin/sh
+The shell.
+.El
+.Sh COMPATIBILITY
+Historically, the default path for the
+.Fn execlp
+and
+.Fn execvp
+functions was
+.Dq Pa :/bin:/usr/bin .
+This was changed to remove the current directory to enhance system
+security.
+.Pp
+The behavior of
+.Fn execlp
+and
+.Fn execvp
+when errors occur while attempting to execute the file is not quite historic
+practice, and has not traditionally been documented and is not specified
+by the
+.Tn POSIX
+standard.
+.Pp
+Traditionally, the functions
+.Fn execlp
+and
+.Fn execvp
+ignored all errors except for the ones described above and
+.Er ETXTBSY ,
+upon which they retried after sleeping for several seconds, and
+.Er ENOMEM
+and
+.Er E2BIG ,
+upon which they returned.
+They now return for
+.Er ETXTBSY ,
+and determine existence and executability more carefully.
+In particular,
+.Er EACCES
+for inaccessible directories in the path prefix is no longer
+confused with
+.Er EACCES
+for files with unsuitable execute permissions.
+In
+.Bx 4.4 ,
+they returned upon all errors except
+.Er EACCES ,
+.Er ENOENT ,
+.Er ENOEXEC
+and
+.Er ETXTBSY .
+This was inferior to the traditional error handling,
+since it breaks the ignoring of errors for path prefixes
+and only improves the handling of the unusual ambiguous error
+.Er EFAULT
+and the unusual error
+.Er EIO .
+The behaviour was changed to match the behaviour of
+.Xr sh 1 .
+.Sh ERRORS
+The
+.Fn execl ,
+.Fn execle ,
+.Fn execlp ,
+.Fn execvp
+and
+.Fn execvP
+functions
+may fail and set
+.Va errno
+for any of the errors specified for the library functions
+.Xr execve 2
+and
+.Xr malloc 3 .
+.Pp
+The
+.Fn exect
+and
+.Fn execv
+functions
+may fail and set
+.Va errno
+for any of the errors specified for the library function
+.Xr execve 2 .
+.Sh SEE ALSO
+.Xr sh 1 ,
+.Xr execve 2 ,
+.Xr fork 2 ,
+.Xr ktrace 2 ,
+.Xr ptrace 2 ,
+.Xr environ 7
+.Sh STANDARDS
+The
+.Fn execl ,
+.Fn execv ,
+.Fn execle ,
+.Fn execlp
+and
+.Fn execvp
+functions
+conform to
+.St -p1003.1-88 .
+The
+.Fn execvP
+function first appeared in
+.Fx 5.2 .
diff --git a/lib/libc/gen/exec.c b/lib/libc/gen/exec.c
new file mode 100644
index 000000000000..e20ff42d3c90
--- /dev/null
+++ b/lib/libc/gen/exec.c
@@ -0,0 +1,281 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)exec.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <paths.h>
+
+#include <stdarg.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+
+extern char **environ;
+
+int
+execl(const char *name, const char *arg, ...)
+{
+ va_list ap;
+ const char **argv;
+ int n;
+
+ va_start(ap, arg);
+ n = 1;
+ while (va_arg(ap, char *) != NULL)
+ n++;
+ va_end(ap);
+ argv = alloca((n + 1) * sizeof(*argv));
+ if (argv == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ va_start(ap, arg);
+ n = 1;
+ argv[0] = arg;
+ while ((argv[n] = va_arg(ap, char *)) != NULL)
+ n++;
+ va_end(ap);
+ return (_execve(name, __DECONST(char **, argv), environ));
+}
+
+int
+execle(const char *name, const char *arg, ...)
+{
+ va_list ap;
+ const char **argv;
+ char **envp;
+ int n;
+
+ va_start(ap, arg);
+ n = 1;
+ while (va_arg(ap, char *) != NULL)
+ n++;
+ va_end(ap);
+ argv = alloca((n + 1) * sizeof(*argv));
+ if (argv == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ va_start(ap, arg);
+ n = 1;
+ argv[0] = arg;
+ while ((argv[n] = va_arg(ap, char *)) != NULL)
+ n++;
+ envp = va_arg(ap, char **);
+ va_end(ap);
+ return (_execve(name, __DECONST(char **, argv), envp));
+}
+
+int
+execlp(const char *name, const char *arg, ...)
+{
+ va_list ap;
+ const char **argv;
+ int n;
+
+ va_start(ap, arg);
+ n = 1;
+ while (va_arg(ap, char *) != NULL)
+ n++;
+ va_end(ap);
+ argv = alloca((n + 1) * sizeof(*argv));
+ if (argv == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ va_start(ap, arg);
+ n = 1;
+ argv[0] = arg;
+ while ((argv[n] = va_arg(ap, char *)) != NULL)
+ n++;
+ va_end(ap);
+ return (execvp(name, __DECONST(char **, argv)));
+}
+
+int
+execv(const char *name, char * const *argv)
+{
+ (void)_execve(name, argv, environ);
+ return (-1);
+}
+
+int
+execvp(const char *name, char * const *argv)
+{
+ return (_execvpe(name, argv, environ));
+}
+
+static int
+execvPe(const char *name, const char *path, char * const *argv,
+ char * const *envp)
+{
+ const char **memp;
+ size_t cnt, lp, ln;
+ int eacces, save_errno;
+ char *cur, buf[MAXPATHLEN];
+ const char *p, *bp;
+ struct stat sb;
+
+ eacces = 0;
+
+ /* If it's an absolute or relative path name, it's easy. */
+ if (strchr(name, '/')) {
+ bp = name;
+ cur = NULL;
+ goto retry;
+ }
+ bp = buf;
+
+ /* If it's an empty path name, fail in the usual POSIX way. */
+ if (*name == '\0') {
+ errno = ENOENT;
+ return (-1);
+ }
+
+ cur = alloca(strlen(path) + 1);
+ if (cur == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ strcpy(cur, path);
+ while ((p = strsep(&cur, ":")) != NULL) {
+ /*
+ * It's a SHELL path -- double, leading and trailing colons
+ * mean the current directory.
+ */
+ if (*p == '\0') {
+ p = ".";
+ lp = 1;
+ } else
+ lp = strlen(p);
+ ln = strlen(name);
+
+ /*
+ * If the path is too long complain. This is a possible
+ * security issue; given a way to make the path too long
+ * the user may execute the wrong program.
+ */
+ if (lp + ln + 2 > sizeof(buf)) {
+ (void)_write(STDERR_FILENO, "execvP: ", 8);
+ (void)_write(STDERR_FILENO, p, lp);
+ (void)_write(STDERR_FILENO, ": path too long\n",
+ 16);
+ continue;
+ }
+ bcopy(p, buf, lp);
+ buf[lp] = '/';
+ bcopy(name, buf + lp + 1, ln);
+ buf[lp + ln + 1] = '\0';
+
+retry: (void)_execve(bp, argv, envp);
+ switch (errno) {
+ case E2BIG:
+ goto done;
+ case ELOOP:
+ case ENAMETOOLONG:
+ case ENOENT:
+ break;
+ case ENOEXEC:
+ for (cnt = 0; argv[cnt]; ++cnt)
+ ;
+ memp = alloca((cnt + 2) * sizeof(char *));
+ if (memp == NULL) {
+ /* errno = ENOMEM; XXX override ENOEXEC? */
+ goto done;
+ }
+ memp[0] = "sh";
+ memp[1] = bp;
+ bcopy(argv + 1, memp + 2, cnt * sizeof(char *));
+ (void)_execve(_PATH_BSHELL,
+ __DECONST(char **, memp), envp);
+ goto done;
+ case ENOMEM:
+ goto done;
+ case ENOTDIR:
+ break;
+ case ETXTBSY:
+ /*
+ * We used to retry here, but sh(1) doesn't.
+ */
+ goto done;
+ default:
+ /*
+ * EACCES may be for an inaccessible directory or
+ * a non-executable file. Call stat() to decide
+ * which. This also handles ambiguities for EFAULT
+ * and EIO, and undocumented errors like ESTALE.
+ * We hope that the race for a stat() is unimportant.
+ */
+ save_errno = errno;
+ if (stat(bp, &sb) != 0)
+ break;
+ if (save_errno == EACCES) {
+ eacces = 1;
+ continue;
+ }
+ errno = save_errno;
+ goto done;
+ }
+ }
+ if (eacces)
+ errno = EACCES;
+ else
+ errno = ENOENT;
+done:
+ return (-1);
+}
+
+int
+execvP(const char *name, const char *path, char * const argv[])
+{
+ return execvPe(name, path, argv, environ);
+}
+
+int
+_execvpe(const char *name, char * const argv[], char * const envp[])
+{
+ const char *path;
+
+ /* Get the path we're searching. */
+ if ((path = getenv("PATH")) == NULL)
+ path = _PATH_DEFPATH;
+
+ return (execvPe(name, path, argv, envp));
+}
diff --git a/lib/libc/gen/fdevname.c b/lib/libc/gen/fdevname.c
new file mode 100644
index 000000000000..d60da70d84e6
--- /dev/null
+++ b/lib/libc/gen/fdevname.c
@@ -0,0 +1,55 @@
+/*-
+ * Copyright (c) 2009 Ed Schouten <ed@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <stdlib.h>
+#include "un-namespace.h"
+
+char *
+fdevname_r(int fd, char *buf, int len)
+{
+ struct fiodgname_arg fgn;
+
+ fgn.buf = buf;
+ fgn.len = len;
+
+ if (_ioctl(fd, FIODGNAME, &fgn) == -1)
+ return (NULL);
+ return (buf);
+}
+
+char *
+fdevname(int fd)
+{
+ static char buf[SPECNAMELEN + 1];
+
+ return (fdevname_r(fd, buf, sizeof(buf)));
+}
diff --git a/lib/libc/gen/feature_present.3 b/lib/libc/gen/feature_present.3
new file mode 100644
index 000000000000..3a702d441df2
--- /dev/null
+++ b/lib/libc/gen/feature_present.3
@@ -0,0 +1,72 @@
+.\" Copyright (c) 2008 Yahoo!, Inc.
+.\" All rights reserved.
+.\" Written by: John Baldwin <jhb@FreeBSD.org>
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the author nor the names of any co-contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd January 8, 2008
+.Dt FEATURE_PRESENT 3
+.Os
+.Sh NAME
+.Nm feature_present
+.Nd query presence of a kernel feature
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft int
+.Fn feature_present "const char *feature"
+.Sh DESCRIPTION
+The
+.Fn feature_present
+function provides a method for an application to determine if a specific
+kernel feature is present in the currently running kernel.
+The
+.Fa feature
+argument specifies the name of the feature to check.
+The
+.Fn feature_present
+function will return 1 if the specified feature is present,
+otherwise it will return 0.
+If the
+.Fn feature_present
+function is not able to determine the presence of
+.Fa feature
+due to an internal error it will return 0.
+.Sh RETURN VALUES
+If
+.Fa feature
+is present then 1 is returned;
+otherwise 0 is returned.
+.Sh SEE ALSO
+.Xr sysconf 3 ,
+.Xr sysctl 3
+.Sh HISTORY
+The
+.Fn feature_present
+function first appeared in
+.Fx 8.0 .
diff --git a/lib/libc/gen/feature_present.c b/lib/libc/gen/feature_present.c
new file mode 100644
index 000000000000..a230c8a8be03
--- /dev/null
+++ b/lib/libc/gen/feature_present.c
@@ -0,0 +1,63 @@
+/*-
+ * Copyright (c) 2008 Yahoo!, Inc.
+ * All rights reserved.
+ * Written by: John Baldwin <jhb@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+/*
+ * Returns true if the named feature is present in the currently
+ * running kernel. A feature's presence is indicated by an integer
+ * sysctl node called kern.feature.<feature> that is non-zero.
+ */
+int
+feature_present(const char *feature)
+{
+ char *mib;
+ size_t len;
+ int i;
+
+ if (asprintf(&mib, "kern.features.%s", feature) < 0)
+ return (0);
+ len = sizeof(i);
+ if (sysctlbyname(mib, &i, &len, NULL, 0) < 0) {
+ free(mib);
+ return (0);
+ }
+ free(mib);
+ if (len != sizeof(i))
+ return (0);
+ return (i != 0);
+}
diff --git a/lib/libc/gen/fmtcheck.3 b/lib/libc/gen/fmtcheck.3
new file mode 100644
index 000000000000..0bd429982ead
--- /dev/null
+++ b/lib/libc/gen/fmtcheck.3
@@ -0,0 +1,108 @@
+.\" Copyright (c) 2000 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This file was contributed to The NetBSD Foundation by Allen Briggs.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.Dd October 16, 2002
+.Dt FMTCHECK 3
+.Os
+.Sh NAME
+.Nm fmtcheck
+.Nd sanitizes user-supplied
+.Xr printf 3 Ns -style
+format string
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdio.h
+.Ft const char *
+.Fn fmtcheck "const char *fmt_suspect" "const char *fmt_default"
+.Sh DESCRIPTION
+The
+.Fn fmtcheck
+scans
+.Fa fmt_suspect
+and
+.Fa fmt_default
+to determine if
+.Fa fmt_suspect
+will consume the same argument types as
+.Fa fmt_default
+and to ensure that
+.Fa fmt_suspect
+is a valid format string.
+.Pp
+The
+.Xr printf 3
+family of functions cannot verify the types of arguments that they are
+passed at run-time.
+In some cases, like
+.Xr catgets 3 ,
+it is useful or necessary to use a user-supplied format string with no
+guarantee that the format string matches the specified arguments.
+.Pp
+The
+.Fn fmtcheck
+was designed to be used in these cases, as in:
+.Bd -literal -offset indent
+printf(fmtcheck(user_format, standard_format), arg1, arg2);
+.Ed
+.Pp
+In the check, field widths, fillers, precisions, etc.\& are ignored (unless
+the field width or precision is an asterisk
+.Ql *
+instead of a digit string).
+Also, any text other than the format specifiers
+is completely ignored.
+.Sh RETURN VALUES
+If
+.Fa fmt_suspect
+is a valid format and consumes the same argument types as
+.Fa fmt_default ,
+then the
+.Fn fmtcheck
+will return
+.Fa fmt_suspect .
+Otherwise, it will return
+.Fa fmt_default .
+.Sh SEE ALSO
+.Xr printf 3
+.Sh BUGS
+The
+.Fn fmtcheck
+function does not recognize positional parameters.
+.Sh SECURITY CONSIDERATIONS
+Note that the formats may be quite different as long as they accept the
+same arguments.
+For example,
+.Qq Li "%p %o %30s %#llx %-10.*e %n"
+is compatible with
+.Qq Li "This number %lu %d%% and string %s has %qd numbers and %.*g floats (%n)" .
+However,
+.Qq Li %o
+is not equivalent to
+.Qq Li %lx
+because
+the first requires an integer and the second requires a long.
diff --git a/lib/libc/gen/fmtcheck.c b/lib/libc/gen/fmtcheck.c
new file mode 100644
index 000000000000..7929f1f4b231
--- /dev/null
+++ b/lib/libc/gen/fmtcheck.c
@@ -0,0 +1,326 @@
+/* $NetBSD: fmtcheck.c,v 1.8 2008/04/28 20:22:59 martin Exp $ */
+
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code was contributed to The NetBSD Foundation by Allen Briggs.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+__weak_reference(__fmtcheck, fmtcheck);
+const char * __fmtcheck(const char *, const char *);
+
+enum __e_fmtcheck_types {
+ FMTCHECK_START,
+ FMTCHECK_SHORT,
+ FMTCHECK_INT,
+ FMTCHECK_WINTT,
+ FMTCHECK_LONG,
+ FMTCHECK_QUAD,
+ FMTCHECK_INTMAXT,
+ FMTCHECK_PTRDIFFT,
+ FMTCHECK_SIZET,
+ FMTCHECK_CHARPOINTER,
+ FMTCHECK_SHORTPOINTER,
+ FMTCHECK_INTPOINTER,
+ FMTCHECK_LONGPOINTER,
+ FMTCHECK_QUADPOINTER,
+ FMTCHECK_INTMAXTPOINTER,
+ FMTCHECK_PTRDIFFTPOINTER,
+ FMTCHECK_SIZETPOINTER,
+#ifndef NO_FLOATING_POINT
+ FMTCHECK_DOUBLE,
+ FMTCHECK_LONGDOUBLE,
+#endif
+ FMTCHECK_STRING,
+ FMTCHECK_WSTRING,
+ FMTCHECK_WIDTH,
+ FMTCHECK_PRECISION,
+ FMTCHECK_DONE,
+ FMTCHECK_UNKNOWN
+};
+typedef enum __e_fmtcheck_types EFT;
+
+enum e_modifier {
+ MOD_NONE,
+ MOD_CHAR,
+ MOD_SHORT,
+ MOD_LONG,
+ MOD_QUAD,
+ MOD_INTMAXT,
+ MOD_LONGDOUBLE,
+ MOD_PTRDIFFT,
+ MOD_SIZET,
+};
+
+#define RETURN(pf,f,r) do { \
+ *(pf) = (f); \
+ return r; \
+ } /*NOTREACHED*/ /*CONSTCOND*/ while (0)
+
+static EFT
+get_next_format_from_precision(const char **pf)
+{
+ enum e_modifier modifier;
+ const char *f;
+
+ f = *pf;
+ switch (*f) {
+ case 'h':
+ f++;
+ if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
+ if (*f == 'h') {
+ f++;
+ modifier = MOD_CHAR;
+ } else {
+ modifier = MOD_SHORT;
+ }
+ break;
+ case 'j':
+ f++;
+ modifier = MOD_INTMAXT;
+ break;
+ case 'l':
+ f++;
+ if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
+ if (*f == 'l') {
+ f++;
+ modifier = MOD_QUAD;
+ } else {
+ modifier = MOD_LONG;
+ }
+ break;
+ case 'q':
+ f++;
+ modifier = MOD_QUAD;
+ break;
+ case 't':
+ f++;
+ modifier = MOD_PTRDIFFT;
+ break;
+ case 'z':
+ f++;
+ modifier = MOD_SIZET;
+ break;
+ case 'L':
+ f++;
+ modifier = MOD_LONGDOUBLE;
+ break;
+ default:
+ modifier = MOD_NONE;
+ break;
+ }
+ if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
+ if (strchr("diouxX", *f)) {
+ switch (modifier) {
+ case MOD_LONG:
+ RETURN(pf,f,FMTCHECK_LONG);
+ case MOD_QUAD:
+ RETURN(pf,f,FMTCHECK_QUAD);
+ case MOD_INTMAXT:
+ RETURN(pf,f,FMTCHECK_INTMAXT);
+ case MOD_PTRDIFFT:
+ RETURN(pf,f,FMTCHECK_PTRDIFFT);
+ case MOD_SIZET:
+ RETURN(pf,f,FMTCHECK_SIZET);
+ case MOD_CHAR:
+ case MOD_SHORT:
+ case MOD_NONE:
+ RETURN(pf,f,FMTCHECK_INT);
+ default:
+ RETURN(pf,f,FMTCHECK_UNKNOWN);
+ }
+ }
+ if (*f == 'n') {
+ switch (modifier) {
+ case MOD_CHAR:
+ RETURN(pf,f,FMTCHECK_CHARPOINTER);
+ case MOD_SHORT:
+ RETURN(pf,f,FMTCHECK_SHORTPOINTER);
+ case MOD_LONG:
+ RETURN(pf,f,FMTCHECK_LONGPOINTER);
+ case MOD_QUAD:
+ RETURN(pf,f,FMTCHECK_QUADPOINTER);
+ case MOD_INTMAXT:
+ RETURN(pf,f,FMTCHECK_INTMAXTPOINTER);
+ case MOD_PTRDIFFT:
+ RETURN(pf,f,FMTCHECK_PTRDIFFTPOINTER);
+ case MOD_SIZET:
+ RETURN(pf,f,FMTCHECK_SIZETPOINTER);
+ case MOD_NONE:
+ RETURN(pf,f,FMTCHECK_INTPOINTER);
+ default:
+ RETURN(pf,f,FMTCHECK_UNKNOWN);
+ }
+ }
+ if (strchr("DOU", *f)) {
+ if (modifier != MOD_NONE)
+ RETURN(pf,f,FMTCHECK_UNKNOWN);
+ RETURN(pf,f,FMTCHECK_LONG);
+ }
+#ifndef NO_FLOATING_POINT
+ if (strchr("aAeEfFgG", *f)) {
+ switch (modifier) {
+ case MOD_LONGDOUBLE:
+ RETURN(pf,f,FMTCHECK_LONGDOUBLE);
+ case MOD_LONG:
+ case MOD_NONE:
+ RETURN(pf,f,FMTCHECK_DOUBLE);
+ default:
+ RETURN(pf,f,FMTCHECK_UNKNOWN);
+ }
+ }
+#endif
+ if (*f == 'c') {
+ switch (modifier) {
+ case MOD_LONG:
+ RETURN(pf,f,FMTCHECK_WINTT);
+ case MOD_NONE:
+ RETURN(pf,f,FMTCHECK_INT);
+ default:
+ RETURN(pf,f,FMTCHECK_UNKNOWN);
+ }
+ }
+ if (*f == 'C') {
+ if (modifier != MOD_NONE)
+ RETURN(pf,f,FMTCHECK_UNKNOWN);
+ RETURN(pf,f,FMTCHECK_WINTT);
+ }
+ if (*f == 's') {
+ switch (modifier) {
+ case MOD_LONG:
+ RETURN(pf,f,FMTCHECK_WSTRING);
+ case MOD_NONE:
+ RETURN(pf,f,FMTCHECK_STRING);
+ default:
+ RETURN(pf,f,FMTCHECK_UNKNOWN);
+ }
+ }
+ if (*f == 'S') {
+ if (modifier != MOD_NONE)
+ RETURN(pf,f,FMTCHECK_UNKNOWN);
+ RETURN(pf,f,FMTCHECK_WSTRING);
+ }
+ if (*f == 'p') {
+ if (modifier != MOD_NONE)
+ RETURN(pf,f,FMTCHECK_UNKNOWN);
+ RETURN(pf,f,FMTCHECK_LONG);
+ }
+ RETURN(pf,f,FMTCHECK_UNKNOWN);
+ /*NOTREACHED*/
+}
+
+static EFT
+get_next_format_from_width(const char **pf)
+{
+ const char *f;
+
+ f = *pf;
+ if (*f == '.') {
+ f++;
+ if (*f == '*') {
+ RETURN(pf,f,FMTCHECK_PRECISION);
+ }
+ /* eat any precision (empty is allowed) */
+ while (isdigit(*f)) f++;
+ if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
+ }
+ RETURN(pf,f,get_next_format_from_precision(pf));
+ /*NOTREACHED*/
+}
+
+static EFT
+get_next_format(const char **pf, EFT eft)
+{
+ int infmt;
+ const char *f;
+
+ if (eft == FMTCHECK_WIDTH) {
+ (*pf)++;
+ return get_next_format_from_width(pf);
+ } else if (eft == FMTCHECK_PRECISION) {
+ (*pf)++;
+ return get_next_format_from_precision(pf);
+ }
+
+ f = *pf;
+ infmt = 0;
+ while (!infmt) {
+ f = strchr(f, '%');
+ if (f == NULL)
+ RETURN(pf,f,FMTCHECK_DONE);
+ f++;
+ if (!*f)
+ RETURN(pf,f,FMTCHECK_UNKNOWN);
+ if (*f != '%')
+ infmt = 1;
+ else
+ f++;
+ }
+
+ /* Eat any of the flags */
+ while (*f && (strchr("#'0- +", *f)))
+ f++;
+
+ if (*f == '*') {
+ RETURN(pf,f,FMTCHECK_WIDTH);
+ }
+ /* eat any width */
+ while (isdigit(*f)) f++;
+ if (!*f) {
+ RETURN(pf,f,FMTCHECK_UNKNOWN);
+ }
+
+ RETURN(pf,f,get_next_format_from_width(pf));
+ /*NOTREACHED*/
+}
+
+const char *
+__fmtcheck(const char *f1, const char *f2)
+{
+ const char *f1p, *f2p;
+ EFT f1t, f2t;
+
+ if (!f1) return f2;
+
+ f1p = f1;
+ f1t = FMTCHECK_START;
+ f2p = f2;
+ f2t = FMTCHECK_START;
+ while ((f1t = get_next_format(&f1p, f1t)) != FMTCHECK_DONE) {
+ if (f1t == FMTCHECK_UNKNOWN)
+ return f2;
+ f2t = get_next_format(&f2p, f2t);
+ if (f1t != f2t)
+ return f2;
+ }
+ return f1;
+}
diff --git a/lib/libc/gen/fmtmsg.3 b/lib/libc/gen/fmtmsg.3
new file mode 100644
index 000000000000..7995d7bd31c5
--- /dev/null
+++ b/lib/libc/gen/fmtmsg.3
@@ -0,0 +1,260 @@
+.\"
+.\" Copyright (c) 2002 Mike Barcroft <mike@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd August 5, 2002
+.Dt FMTMSG 3
+.Os
+.Sh NAME
+.Nm fmtmsg
+.Nd display a detailed diagnostic message
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In fmtmsg.h
+.Ft int
+.Fo fmtmsg
+.Fa "long classification" "const char *label" "int severity"
+.Fa "const char *text" "const char *action" "const char *tag"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn fmtmsg
+function displays a detailed diagnostic message, based on
+the supplied arguments, to
+.Dv stderr
+and/or the system console.
+.Pp
+The
+.Fa classification
+argument is the bitwise inclusive
+.Tn OR
+of zero or one of the manifest constants from
+each of the classification groups below.
+The Output classification group is an exception since both
+.Dv MM_PRINT
+and
+.Dv MM_CONSOLE
+may be specified.
+.Bl -tag -width indent
+.It Output
+.Bl -tag -width ".Dv MM_CONSOLE"
+.It Dv MM_PRINT
+Output should take place on
+.Dv stderr .
+.It Dv MM_CONSOLE
+Output should take place on the system console.
+.El
+.It "Source of Condition (Major)"
+.Bl -tag -width ".Dv MM_CONSOLE"
+.It Dv MM_HARD
+The source of the condition is hardware related.
+.It Dv MM_SOFT
+The source of the condition is software related.
+.It Dv MM_FIRM
+The source of the condition is firmware related.
+.El
+.It "Source of Condition (Minor)"
+.Bl -tag -width ".Dv MM_CONSOLE"
+.It Dv MM_APPL
+The condition was detected at the application level.
+.It Dv MM_UTIL
+The condition was detected at the utility level.
+.It Dv MM_OPSYS
+The condition was detected at the operating system level.
+.El
+.It Status
+.Bl -tag -width ".Dv MM_CONSOLE"
+.It Dv MM_RECOVER
+The application can recover from the condition.
+.It Dv MM_NRECOV
+The application is unable to recover from the condition.
+.El
+.El
+.Pp
+Alternatively, the
+.Dv MM_NULLMC
+manifest constant may be used to specify no classification.
+.Pp
+The
+.Fa label
+argument indicates the source of the message.
+It is made up of two fields separated by a colon
+.Pq Ql \&: .
+The first field can be up to 10 bytes,
+and the second field can be up to 14 bytes.
+The
+.Dv MM_NULLLBL
+manifest constant may be used to specify no label.
+.Pp
+The
+.Fa severity
+argument identifies the importance of the condition.
+One of the following manifest constants should be used for this argument.
+.Bl -tag -offset indent -width ".Dv MM_WARNING"
+.It Dv MM_HALT
+The application has confronted a serious fault and is halting.
+.It Dv MM_ERROR
+The application has detected a fault.
+.It Dv MM_WARNING
+The application has detected an unusual condition,
+that could be indicative of a problem.
+.It Dv MM_INFO
+The application is providing information about a non-error condition.
+.It Dv MM_NOSEV
+No severity level supplied.
+.El
+.Pp
+The
+.Fa text
+argument details the error condition that caused the message.
+There is no limit on the size of this character string.
+The
+.Dv MM_NULLTXT
+manifest constant may be used to specify no text.
+.Pp
+The
+.Fa action
+argument details how the error-recovery process should begin.
+Upon output,
+.Fn fmtmsg
+will prefix
+.Qq Li "TO FIX:"
+to the beginning of the
+.Fa action
+argument.
+The
+.Dv MM_NULLACT
+manifest constant may be used to specify no action.
+.Pp
+The
+.Fa tag
+argument should reference online documentation for the message.
+This usually includes the
+.Fa label
+and a unique identifying number.
+An example tag is
+.Qq Li BSD:ls:168 .
+The
+.Dv MM_NULLTAG
+manifest constant may be used to specify no tag.
+.Sh RETURN VALUES
+The
+.Fn fmtmsg
+function returns
+.Dv MM_OK
+upon success,
+.Dv MM_NOMSG
+to indicate output to
+.Dv stderr
+failed,
+.Dv MM_NOCON
+to indicate output to the system console failed, or
+.Dv MM_NOTOK
+to indicate output to
+.Dv stderr
+and the system console failed.
+.Sh ENVIRONMENT
+The
+.Ev MSGVERB
+(message verbosity)
+environment variable specifies which arguments to
+.Fn fmtmsg
+will be output to
+.Dv stderr ,
+and in which order.
+.Ev MSGVERB
+should be a colon
+.Pq Ql \&:
+separated list of identifiers.
+Valid identifiers include:
+.Li label , severity , text , action ,
+and
+.Li tag .
+If invalid identifiers are specified or incorrectly separated,
+the default message verbosity and ordering will be used.
+The default ordering is equivalent to a
+.Ev MSGVERB
+with a value of
+.Qq Li label:severity:text:action:tag .
+.Sh EXAMPLES
+The code:
+.Bd -literal -offset indent
+fmtmsg(MM_UTIL | MM_PRINT, "BSD:ls", MM_ERROR,
+ "illegal option -- z", "refer to manual", "BSD:ls:001");
+.Ed
+.Pp
+will output:
+.Bd -literal -offset indent
+BSD:ls: ERROR: illegal option -- z
+TO FIX: refer to manual BSD:ls:001
+.Ed
+.Pp
+to
+.Dv stderr .
+.Pp
+The same code, with
+.Ev MSGVERB
+set to
+.Qq Li "text:severity:action:tag" ,
+produces:
+.Bd -literal -offset indent
+illegal option -- z: ERROR
+TO FIX: refer to manual BSD:ls:001
+.Ed
+.Sh SEE ALSO
+.Xr err 3 ,
+.Xr exit 3 ,
+.Xr strerror 3
+.Sh STANDARDS
+The
+.Fn fmtmsg
+function conforms to
+.St -p1003.1-2001 .
+.Sh HISTORY
+The
+.Fn fmtmsg
+function first appeared in
+.Fx 5.0 .
+.Sh BUGS
+Specifying
+.Dv MM_NULLMC
+for the
+.Fa classification
+argument makes little sense, since without an output specified,
+.Fn fmtmsg
+is unable to do anything useful.
+.Pp
+In order for
+.Fn fmtmsg
+to output to the system console, the effective
+user must have appropriate permission to write to
+.Pa /dev/console .
+This means that on most systems
+.Fn fmtmsg
+will return
+.Dv MM_NOCON
+unless the effective user is root.
diff --git a/lib/libc/gen/fmtmsg.c b/lib/libc/gen/fmtmsg.c
new file mode 100644
index 000000000000..d2c67a6cb014
--- /dev/null
+++ b/lib/libc/gen/fmtmsg.c
@@ -0,0 +1,220 @@
+/*-
+ * Copyright (c) 2002 Mike Barcroft <mike@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <fmtmsg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Default value for MSGVERB. */
+#define DFLT_MSGVERB "label:severity:text:action:tag"
+
+/* Maximum valid size for a MSGVERB. */
+#define MAX_MSGVERB sizeof(DFLT_MSGVERB)
+
+static char *printfmt(char *, long, const char *, int, const char *,
+ const char *, const char *);
+static char *nextcomp(const char *);
+static const char
+ *sevinfo(int);
+static int validmsgverb(const char *);
+
+int
+fmtmsg(long class, const char *label, int sev, const char *text,
+ const char *action, const char *tag)
+{
+ FILE *fp;
+ char *env, *msgverb, *output;
+
+ if (class & MM_PRINT) {
+ if ((env = getenv("MSGVERB")) != NULL && *env != '\0' &&
+ strlen(env) <= strlen(DFLT_MSGVERB)) {
+ if ((msgverb = strdup(env)) == NULL)
+ return (MM_NOTOK);
+ else if (validmsgverb(msgverb) == 0) {
+ free(msgverb);
+ goto def;
+ }
+ } else {
+def:
+ if ((msgverb = strdup(DFLT_MSGVERB)) == NULL)
+ return (MM_NOTOK);
+ }
+ output = printfmt(msgverb, class, label, sev, text, action,
+ tag);
+ if (output == NULL) {
+ free(msgverb);
+ return (MM_NOTOK);
+ }
+ if (*output != '\0')
+ fprintf(stderr, "%s", output);
+ free(msgverb);
+ free(output);
+ }
+ if (class & MM_CONSOLE) {
+ output = printfmt(DFLT_MSGVERB, class, label, sev, text,
+ action, tag);
+ if (output == NULL)
+ return (MM_NOCON);
+ if (*output != '\0') {
+ if ((fp = fopen("/dev/console", "ae")) == NULL) {
+ free(output);
+ return (MM_NOCON);
+ }
+ fprintf(fp, "%s", output);
+ fclose(fp);
+ }
+ free(output);
+ }
+ return (MM_OK);
+}
+
+#define INSERT_COLON \
+ if (*output != '\0') \
+ strlcat(output, ": ", size)
+#define INSERT_NEWLINE \
+ if (*output != '\0') \
+ strlcat(output, "\n", size)
+#define INSERT_SPACE \
+ if (*output != '\0') \
+ strlcat(output, " ", size)
+
+/*
+ * Returns NULL on memory allocation failure, otherwise returns a pointer to
+ * a newly malloc()'d output buffer.
+ */
+static char *
+printfmt(char *msgverb, long class, const char *label, int sev,
+ const char *text, const char *act, const char *tag)
+{
+ size_t size;
+ char *comp, *output;
+ const char *sevname;
+
+ size = 32;
+ if (label != MM_NULLLBL)
+ size += strlen(label);
+ if ((sevname = sevinfo(sev)) != NULL)
+ size += strlen(sevname);
+ if (text != MM_NULLTXT)
+ size += strlen(text);
+ if (act != MM_NULLACT)
+ size += strlen(act);
+ if (tag != MM_NULLTAG)
+ size += strlen(tag);
+
+ if ((output = malloc(size)) == NULL)
+ return (NULL);
+ *output = '\0';
+ while ((comp = nextcomp(msgverb)) != NULL) {
+ if (strcmp(comp, "label") == 0 && label != MM_NULLLBL) {
+ INSERT_COLON;
+ strlcat(output, label, size);
+ } else if (strcmp(comp, "severity") == 0 && sevname != NULL) {
+ INSERT_COLON;
+ strlcat(output, sevinfo(sev), size);
+ } else if (strcmp(comp, "text") == 0 && text != MM_NULLTXT) {
+ INSERT_COLON;
+ strlcat(output, text, size);
+ } else if (strcmp(comp, "action") == 0 && act != MM_NULLACT) {
+ INSERT_NEWLINE;
+ strlcat(output, "TO FIX: ", size);
+ strlcat(output, act, size);
+ } else if (strcmp(comp, "tag") == 0 && tag != MM_NULLTAG) {
+ INSERT_SPACE;
+ strlcat(output, tag, size);
+ }
+ }
+ INSERT_NEWLINE;
+ return (output);
+}
+
+/*
+ * Returns a component of a colon delimited string. NULL is returned to
+ * indicate that there are no remaining components. This function must be
+ * called until it returns NULL in order for the local state to be cleared.
+ */
+static char *
+nextcomp(const char *msgverb)
+{
+ static char lmsgverb[MAX_MSGVERB], *state;
+ char *retval;
+
+ if (*lmsgverb == '\0') {
+ strlcpy(lmsgverb, msgverb, sizeof(lmsgverb));
+ retval = strtok_r(lmsgverb, ":", &state);
+ } else {
+ retval = strtok_r(NULL, ":", &state);
+ }
+ if (retval == NULL)
+ *lmsgverb = '\0';
+ return (retval);
+}
+
+static const char *
+sevinfo(int sev)
+{
+
+ switch (sev) {
+ case MM_HALT:
+ return ("HALT");
+ case MM_ERROR:
+ return ("ERROR");
+ case MM_WARNING:
+ return ("WARNING");
+ case MM_INFO:
+ return ("INFO");
+ default:
+ return (NULL);
+ }
+}
+
+/*
+ * Returns 1 if the msgverb list is valid, otherwise 0.
+ */
+static int
+validmsgverb(const char *msgverb)
+{
+ const char *validlist = "label\0severity\0text\0action\0tag\0";
+ char *msgcomp;
+ size_t len1, len2;
+ const char *p;
+ int equality;
+
+ equality = 0;
+ while ((msgcomp = nextcomp(msgverb)) != NULL) {
+ equality--;
+ len1 = strlen(msgcomp);
+ for (p = validlist; (len2 = strlen(p)) != 0; p += len2 + 1) {
+ if (len1 == len2 && memcmp(msgcomp, p, len1) == 0)
+ equality++;
+ }
+ }
+ return (!equality);
+}
diff --git a/lib/libc/gen/fnmatch.3 b/lib/libc/gen/fnmatch.3
new file mode 100644
index 000000000000..489b2a80c5d9
--- /dev/null
+++ b/lib/libc/gen/fnmatch.3
@@ -0,0 +1,151 @@
+.\" Copyright (c) 1989, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Guido van Rossum.
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)fnmatch.3 8.3 (Berkeley) 4/28/95
+.\" $FreeBSD$
+.\"
+.Dd July 18, 2004
+.Dt FNMATCH 3
+.Os
+.Sh NAME
+.Nm fnmatch
+.Nd test whether a filename or pathname matches a shell-style pattern
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In fnmatch.h
+.Ft int
+.Fn fnmatch "const char *pattern" "const char *string" "int flags"
+.Sh DESCRIPTION
+The
+.Fn fnmatch
+function
+matches patterns according to the rules used by the shell.
+It checks the string specified by the
+.Fa string
+argument to see if it matches the pattern specified by the
+.Fa pattern
+argument.
+.Pp
+The
+.Fa flags
+argument modifies the interpretation of
+.Fa pattern
+and
+.Fa string .
+The value of
+.Fa flags
+is the bitwise inclusive
+.Tn OR
+of any of the following
+constants, which are defined in the include file
+.In fnmatch.h .
+.Bl -tag -width FNM_PATHNAME
+.It Dv FNM_NOESCAPE
+Normally, every occurrence of a backslash
+.Pq Ql \e
+followed by a character in
+.Fa pattern
+is replaced by that character.
+This is done to negate any special meaning for the character.
+If the
+.Dv FNM_NOESCAPE
+flag is set, a backslash character is treated as an ordinary character.
+.It Dv FNM_PATHNAME
+Slash characters in
+.Fa string
+must be explicitly matched by slashes in
+.Fa pattern .
+If this flag is not set, then slashes are treated as regular characters.
+.It Dv FNM_PERIOD
+Leading periods in
+.Fa string
+must be explicitly matched by periods in
+.Fa pattern .
+If this flag is not set, then leading periods are treated as regular
+characters.
+The definition of
+.Dq leading
+is related to the specification of
+.Dv FNM_PATHNAME .
+A period is always
+.Dq leading
+if it is the first character in
+.Fa string .
+Additionally, if
+.Dv FNM_PATHNAME
+is set,
+a period is
+leading
+if it immediately follows a slash.
+.It Dv FNM_LEADING_DIR
+Ignore
+.Dq Li /*
+rest after successful
+.Fa pattern
+matching.
+.It Dv FNM_CASEFOLD
+Ignore case distinctions in both the
+.Fa pattern
+and the
+.Fa string .
+.El
+.Sh RETURN VALUES
+The
+.Fn fnmatch
+function returns zero if
+.Fa string
+matches the pattern specified by
+.Fa pattern ,
+otherwise, it returns the value
+.Dv FNM_NOMATCH .
+.Sh SEE ALSO
+.Xr sh 1 ,
+.Xr glob 3 ,
+.Xr regex 3
+.Sh STANDARDS
+The current implementation of the
+.Fn fnmatch
+function
+.Em does not
+conform to
+.St -p1003.2 .
+Collating symbol expressions, equivalence class expressions and
+character class expressions are not supported.
+.Sh HISTORY
+The
+.Fn fnmatch
+function first appeared in
+.Bx 4.4 .
+.Sh BUGS
+The pattern
+.Ql *
+matches the empty string, even if
+.Dv FNM_PATHNAME
+is specified.
diff --git a/lib/libc/gen/fnmatch.c b/lib/libc/gen/fnmatch.c
new file mode 100644
index 000000000000..65efe20727b6
--- /dev/null
+++ b/lib/libc/gen/fnmatch.c
@@ -0,0 +1,309 @@
+/*
+ * Copyright (c) 1989, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Guido van Rossum.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)fnmatch.c 8.2 (Berkeley) 4/16/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6.
+ * Compares a filename or pathname to a pattern.
+ */
+
+/*
+ * Some notes on multibyte character support:
+ * 1. Patterns with illegal byte sequences match nothing.
+ * 2. Illegal byte sequences in the "string" argument are handled by treating
+ * them as single-byte characters with a value of the first byte of the
+ * sequence cast to wchar_t.
+ * 3. Multibyte conversion state objects (mbstate_t) are passed around and
+ * used for most, but not all, conversions. Further work will be required
+ * to support state-dependent encodings.
+ */
+
+#include <fnmatch.h>
+#include <limits.h>
+#include <string.h>
+#include <wchar.h>
+#include <wctype.h>
+
+#include "collate.h"
+
+#define EOS '\0'
+
+#define RANGE_MATCH 1
+#define RANGE_NOMATCH 0
+#define RANGE_ERROR (-1)
+
+static int rangematch(const char *, wchar_t, int, char **, mbstate_t *);
+static int fnmatch1(const char *, const char *, const char *, int, mbstate_t,
+ mbstate_t);
+
+int
+fnmatch(const char *pattern, const char *string, int flags)
+{
+ static const mbstate_t initial;
+
+ return (fnmatch1(pattern, string, string, flags, initial, initial));
+}
+
+static int
+fnmatch1(const char *pattern, const char *string, const char *stringstart,
+ int flags, mbstate_t patmbs, mbstate_t strmbs)
+{
+ const char *bt_pattern, *bt_string;
+ mbstate_t bt_patmbs, bt_strmbs;
+ char *newp;
+ char c;
+ wchar_t pc, sc;
+ size_t pclen, sclen;
+
+ bt_pattern = bt_string = NULL;
+ for (;;) {
+ pclen = mbrtowc(&pc, pattern, MB_LEN_MAX, &patmbs);
+ if (pclen == (size_t)-1 || pclen == (size_t)-2)
+ return (FNM_NOMATCH);
+ pattern += pclen;
+ sclen = mbrtowc(&sc, string, MB_LEN_MAX, &strmbs);
+ if (sclen == (size_t)-1 || sclen == (size_t)-2) {
+ sc = (unsigned char)*string;
+ sclen = 1;
+ memset(&strmbs, 0, sizeof(strmbs));
+ }
+ switch (pc) {
+ case EOS:
+ if ((flags & FNM_LEADING_DIR) && sc == '/')
+ return (0);
+ if (sc == EOS)
+ return (0);
+ goto backtrack;
+ case '?':
+ if (sc == EOS)
+ return (FNM_NOMATCH);
+ if (sc == '/' && (flags & FNM_PATHNAME))
+ goto backtrack;
+ if (sc == '.' && (flags & FNM_PERIOD) &&
+ (string == stringstart ||
+ ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
+ goto backtrack;
+ string += sclen;
+ break;
+ case '*':
+ c = *pattern;
+ /* Collapse multiple stars. */
+ while (c == '*')
+ c = *++pattern;
+
+ if (sc == '.' && (flags & FNM_PERIOD) &&
+ (string == stringstart ||
+ ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
+ goto backtrack;
+
+ /* Optimize for pattern with * at end or before /. */
+ if (c == EOS)
+ if (flags & FNM_PATHNAME)
+ return ((flags & FNM_LEADING_DIR) ||
+ strchr(string, '/') == NULL ?
+ 0 : FNM_NOMATCH);
+ else
+ return (0);
+ else if (c == '/' && flags & FNM_PATHNAME) {
+ if ((string = strchr(string, '/')) == NULL)
+ return (FNM_NOMATCH);
+ break;
+ }
+
+ /*
+ * First try the shortest match for the '*' that
+ * could work. We can forget any earlier '*' since
+ * there is no way having it match more characters
+ * can help us, given that we are already here.
+ */
+ bt_pattern = pattern, bt_patmbs = patmbs;
+ bt_string = string, bt_strmbs = strmbs;
+ break;
+ case '[':
+ if (sc == EOS)
+ return (FNM_NOMATCH);
+ if (sc == '/' && (flags & FNM_PATHNAME))
+ goto backtrack;
+ if (sc == '.' && (flags & FNM_PERIOD) &&
+ (string == stringstart ||
+ ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
+ goto backtrack;
+
+ switch (rangematch(pattern, sc, flags, &newp,
+ &patmbs)) {
+ case RANGE_ERROR:
+ goto norm;
+ case RANGE_MATCH:
+ pattern = newp;
+ break;
+ case RANGE_NOMATCH:
+ goto backtrack;
+ }
+ string += sclen;
+ break;
+ case '\\':
+ if (!(flags & FNM_NOESCAPE)) {
+ pclen = mbrtowc(&pc, pattern, MB_LEN_MAX,
+ &patmbs);
+ if (pclen == (size_t)-1 || pclen == (size_t)-2)
+ return (FNM_NOMATCH);
+ pattern += pclen;
+ }
+ /* FALLTHROUGH */
+ default:
+ norm:
+ string += sclen;
+ if (pc == sc)
+ ;
+ else if ((flags & FNM_CASEFOLD) &&
+ (towlower(pc) == towlower(sc)))
+ ;
+ else {
+ backtrack:
+ /*
+ * If we have a mismatch (other than hitting
+ * the end of the string), go back to the last
+ * '*' seen and have it match one additional
+ * character.
+ */
+ if (bt_pattern == NULL)
+ return (FNM_NOMATCH);
+ sclen = mbrtowc(&sc, bt_string, MB_LEN_MAX,
+ &bt_strmbs);
+ if (sclen == (size_t)-1 ||
+ sclen == (size_t)-2) {
+ sc = (unsigned char)*bt_string;
+ sclen = 1;
+ memset(&bt_strmbs, 0,
+ sizeof(bt_strmbs));
+ }
+ if (sc == EOS)
+ return (FNM_NOMATCH);
+ if (sc == '/' && flags & FNM_PATHNAME)
+ return (FNM_NOMATCH);
+ bt_string += sclen;
+ pattern = bt_pattern, patmbs = bt_patmbs;
+ string = bt_string, strmbs = bt_strmbs;
+ }
+ break;
+ }
+ }
+ /* NOTREACHED */
+}
+
+static int
+rangematch(const char *pattern, wchar_t test, int flags, char **newp,
+ mbstate_t *patmbs)
+{
+ int negate, ok;
+ wchar_t c, c2;
+ size_t pclen;
+ const char *origpat;
+ struct xlocale_collate *table =
+ (struct xlocale_collate*)__get_locale()->components[XLC_COLLATE];
+
+ /*
+ * A bracket expression starting with an unquoted circumflex
+ * character produces unspecified results (IEEE 1003.2-1992,
+ * 3.13.2). This implementation treats it like '!', for
+ * consistency with the regular expression syntax.
+ * J.T. Conklin (conklin@ngai.kaleida.com)
+ */
+ if ( (negate = (*pattern == '!' || *pattern == '^')) )
+ ++pattern;
+
+ if (flags & FNM_CASEFOLD)
+ test = towlower(test);
+
+ /*
+ * A right bracket shall lose its special meaning and represent
+ * itself in a bracket expression if it occurs first in the list.
+ * -- POSIX.2 2.8.3.2
+ */
+ ok = 0;
+ origpat = pattern;
+ for (;;) {
+ if (*pattern == ']' && pattern > origpat) {
+ pattern++;
+ break;
+ } else if (*pattern == '\0') {
+ return (RANGE_ERROR);
+ } else if (*pattern == '/' && (flags & FNM_PATHNAME)) {
+ return (RANGE_NOMATCH);
+ } else if (*pattern == '\\' && !(flags & FNM_NOESCAPE))
+ pattern++;
+ pclen = mbrtowc(&c, pattern, MB_LEN_MAX, patmbs);
+ if (pclen == (size_t)-1 || pclen == (size_t)-2)
+ return (RANGE_NOMATCH);
+ pattern += pclen;
+
+ if (flags & FNM_CASEFOLD)
+ c = towlower(c);
+
+ if (*pattern == '-' && *(pattern + 1) != EOS &&
+ *(pattern + 1) != ']') {
+ if (*++pattern == '\\' && !(flags & FNM_NOESCAPE))
+ if (*pattern != EOS)
+ pattern++;
+ pclen = mbrtowc(&c2, pattern, MB_LEN_MAX, patmbs);
+ if (pclen == (size_t)-1 || pclen == (size_t)-2)
+ return (RANGE_NOMATCH);
+ pattern += pclen;
+ if (c2 == EOS)
+ return (RANGE_ERROR);
+
+ if (flags & FNM_CASEFOLD)
+ c2 = towlower(c2);
+
+ if (table->__collate_load_error ?
+ c <= test && test <= c2 :
+ __wcollate_range_cmp(c, test) <= 0
+ && __wcollate_range_cmp(test, c2) <= 0
+ )
+ ok = 1;
+ } else if (c == test)
+ ok = 1;
+ }
+
+ *newp = (char *)pattern;
+ return (ok == negate ? RANGE_NOMATCH : RANGE_MATCH);
+}
diff --git a/lib/libc/gen/fpclassify.3 b/lib/libc/gen/fpclassify.3
new file mode 100644
index 000000000000..a547eeb45466
--- /dev/null
+++ b/lib/libc/gen/fpclassify.3
@@ -0,0 +1,133 @@
+.\" 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$
+.\"
+.Dd January 26, 2005
+.Dt FPCLASSIFY 3
+.Os
+.Sh NAME
+.Nm fpclassify , isfinite , isinf , isnan , isnormal
+.Nd "classify a floating-point number"
+.Sh LIBRARY
+.Lb libm
+.Sh SYNOPSIS
+.In math.h
+.Ft int
+.Fn fpclassify "real-floating x"
+.Ft int
+.Fn isfinite "real-floating x"
+.Ft int
+.Fn isinf "real-floating x"
+.Ft int
+.Fn isnan "real-floating x"
+.Ft int
+.Fn isnormal "real-floating x"
+.Sh DESCRIPTION
+The
+.Fn fpclassify
+macro takes an argument of
+.Fa x
+and returns one of the following manifest constants.
+.Bl -tag -width ".Dv FP_SUBNORMAL"
+.It Dv FP_INFINITE
+Indicates that
+.Fa x
+is an infinite number.
+.It Dv FP_NAN
+Indicates that
+.Fa x
+is not a number (NaN).
+.It Dv FP_NORMAL
+Indicates that
+.Fa x
+is a normalized number.
+.It Dv FP_SUBNORMAL
+Indicates that
+.Fa x
+is a denormalized number.
+.It Dv FP_ZERO
+Indicates that
+.Fa x
+is zero (0 or \-0).
+.El
+.Pp
+The
+.Fn isfinite
+macro returns a non-zero value if and only if its argument has
+a finite (zero, subnormal, or normal) value.
+The
+.Fn isinf ,
+.Fn isnan ,
+and
+.Fn isnormal
+macros return non-zero if and only if
+.Fa x
+is an infinity, NaN,
+or a non-zero normalized number, respectively.
+.Pp
+The symbol
+.Fn isnanf
+is provided as an alias to
+.Fn isnan
+for compatibility, and its use is deprecated.
+Similarly,
+.Fn finite
+and
+.Fn finitef
+are deprecated versions of
+.Fn isfinite .
+.Sh SEE ALSO
+.Xr isgreater 3 ,
+.Xr math 3 ,
+.Xr signbit 3
+.Sh STANDARDS
+The
+.Fn fpclassify ,
+.Fn isfinite ,
+.Fn isinf ,
+.Fn isnan ,
+and
+.Fn isnormal
+macros conform to
+.St -isoC-99 .
+.Sh HISTORY
+The
+.Fn fpclassify ,
+.Fn isfinite ,
+.Fn isinf ,
+.Fn isnan ,
+and
+.Fn isnormal
+macros were added in
+.Fx 5.1 .
+.Bx 3
+introduced
+.Fn isinf
+and
+.Fn isnan
+functions, which accepted
+.Vt double
+arguments; these have been superseded by the macros
+described above.
diff --git a/lib/libc/gen/fpclassify.c b/lib/libc/gen/fpclassify.c
new file mode 100644
index 000000000000..444b5513ddf4
--- /dev/null
+++ b/lib/libc/gen/fpclassify.c
@@ -0,0 +1,103 @@
+/*-
+ * Copyright (c) 2003 Mike Barcroft <mike@FreeBSD.org>
+ * Copyright (c) 2002, 2003 David Schultz <das@FreeBSD.ORG>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/endian.h>
+
+#include <machine/float.h>
+
+#include <math.h>
+#include <stdint.h>
+
+#include "fpmath.h"
+
+int
+__fpclassifyf(float f)
+{
+ union IEEEf2bits u;
+
+ u.f = f;
+ if (u.bits.exp == 0) {
+ if (u.bits.man == 0)
+ return (FP_ZERO);
+ return (FP_SUBNORMAL);
+ }
+ if (u.bits.exp == 255) {
+ if (u.bits.man == 0)
+ return (FP_INFINITE);
+ return (FP_NAN);
+ }
+ return (FP_NORMAL);
+}
+
+int
+__fpclassifyd(double d)
+{
+ union IEEEd2bits u;
+
+ u.d = d;
+ if (u.bits.exp == 0) {
+ if ((u.bits.manl | u.bits.manh) == 0)
+ return (FP_ZERO);
+ return (FP_SUBNORMAL);
+ }
+ if (u.bits.exp == 2047) {
+ if ((u.bits.manl | u.bits.manh) == 0)
+ return (FP_INFINITE);
+ return (FP_NAN);
+ }
+ return (FP_NORMAL);
+}
+
+int
+__fpclassifyl(long double e)
+{
+ union IEEEl2bits u;
+
+ u.e = e;
+ if (u.bits.exp == 0) {
+ if ((u.bits.manl | u.bits.manh) == 0)
+ return (FP_ZERO);
+ return (FP_SUBNORMAL);
+ }
+ mask_nbit_l(u); /* Mask normalization bit if applicable. */
+#if LDBL_MANT_DIG == 53
+ if (u.bits.exp == 2047) {
+ if ((u.bits.manl | u.bits.manh) == 0)
+ return (FP_INFINITE);
+ return (FP_NAN);
+ }
+#else
+ if (u.bits.exp == 32767) {
+ if ((u.bits.manl | u.bits.manh) == 0)
+ return (FP_INFINITE);
+ return (FP_NAN);
+ }
+#endif
+ return (FP_NORMAL);
+}
diff --git a/lib/libc/gen/frexp.3 b/lib/libc/gen/frexp.3
new file mode 100644
index 000000000000..ba33d3dfeba9
--- /dev/null
+++ b/lib/libc/gen/frexp.3
@@ -0,0 +1,94 @@
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)frexp.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd March 4, 2005
+.Dt FREXP 3
+.Os
+.Sh NAME
+.Nm frexp ,
+.Nm frexpf ,
+.Nm frexpl
+.Nd convert floating-point number to fractional and integral components
+.Sh LIBRARY
+.Lb libm
+.Sh SYNOPSIS
+.In math.h
+.Ft double
+.Fn frexp "double value" "int *exp"
+.Ft float
+.Fn frexpf "float value" "int *exp"
+.Ft long double
+.Fn frexpl "long double value" "int *exp"
+.Sh DESCRIPTION
+The
+.Fn frexp ,
+.Fn frexpf
+and
+.Fn frexpl
+functions break a floating-point number into a normalized
+fraction and an integral power of 2.
+They store the integer in the
+.Vt int
+object pointed to by
+.Fa exp .
+.Sh RETURN VALUES
+These functions return the value
+.Va x ,
+such that
+.Va x
+is a
+.Vt double
+with magnitude in the interval
+.Eo [ 1/2 , 1 Ec )
+or zero, and
+.Fa value
+equals
+.Va x
+times 2 raised to the power
+.Fa *exp .
+If
+.Fa value
+is zero, both parts of the result are zero.
+.Sh SEE ALSO
+.Xr ldexp 3 ,
+.Xr math 3 ,
+.Xr modf 3
+.Sh STANDARDS
+The
+.Fn frexp ,
+.Fn frexpf ,
+and
+.Fn frexpl
+functions conform to
+.St -isoC-99 .
diff --git a/lib/libc/gen/frexp.c b/lib/libc/gen/frexp.c
new file mode 100644
index 000000000000..53483da88568
--- /dev/null
+++ b/lib/libc/gen/frexp.c
@@ -0,0 +1,57 @@
+/*-
+ * Copyright (c) 2004 David Schultz <das@FreeBSD.ORG>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <math.h>
+
+#include "fpmath.h"
+
+double
+frexp(double d, int *ex)
+{
+ union IEEEd2bits u;
+
+ u.d = d;
+ switch (u.bits.exp) {
+ case 0: /* 0 or subnormal */
+ if ((u.bits.manl | u.bits.manh) == 0) {
+ *ex = 0;
+ } else {
+ u.d *= 0x1.0p514;
+ *ex = u.bits.exp - 1536;
+ u.bits.exp = 1022;
+ }
+ break;
+ case 2047: /* infinity or NaN; value of *ex is unspecified */
+ break;
+ default: /* normal */
+ *ex = u.bits.exp - 1022;
+ u.bits.exp = 1022;
+ break;
+ }
+ return (u.d);
+}
diff --git a/lib/libc/gen/fstab.c b/lib/libc/gen/fstab.c
new file mode 100644
index 000000000000..c21ceb388904
--- /dev/null
+++ b/lib/libc/gen/fstab.c
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 1980, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)fstab.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <fstab.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <vis.h>
+#include "un-namespace.h"
+
+static FILE *_fs_fp;
+static struct fstab _fs_fstab;
+static int LineNo = 0;
+static char *path_fstab;
+static char fstab_path[PATH_MAX];
+static int fsp_set = 0;
+
+static void error(int);
+static void fixfsfile(void);
+static int fstabscan(void);
+
+void
+setfstab(const char *file)
+{
+
+ if (file == NULL) {
+ path_fstab = _PATH_FSTAB;
+ } else {
+ strncpy(fstab_path, file, PATH_MAX);
+ fstab_path[PATH_MAX - 1] = '\0';
+ path_fstab = fstab_path;
+ }
+ fsp_set = 1;
+
+ return;
+}
+
+const char *
+getfstab(void)
+{
+
+ if (fsp_set)
+ return (path_fstab);
+ else
+ return (_PATH_FSTAB);
+}
+
+static void
+fixfsfile(void)
+{
+ static char buf[sizeof(_PATH_DEV) + MNAMELEN];
+ struct stat sb;
+ struct statfs sf;
+
+ if (_fs_fstab.fs_file != NULL && strcmp(_fs_fstab.fs_file, "/") != 0)
+ return;
+ if (statfs("/", &sf) != 0)
+ return;
+ if (sf.f_mntfromname[0] == '/')
+ buf[0] = '\0';
+ else
+ strcpy(buf, _PATH_DEV);
+ strcat(buf, sf.f_mntfromname);
+ if (stat(buf, &sb) != 0 ||
+ (!S_ISBLK(sb.st_mode) && !S_ISCHR(sb.st_mode)))
+ return;
+ _fs_fstab.fs_spec = buf;
+}
+
+static int
+fstabscan(void)
+{
+ char *cp, *p;
+#define MAXLINELENGTH 1024
+ static char line[MAXLINELENGTH];
+ char subline[MAXLINELENGTH];
+ int typexx;
+
+ for (;;) {
+
+ if (!(p = fgets(line, sizeof(line), _fs_fp)))
+ return (0);
+/* OLD_STYLE_FSTAB */
+ ++LineNo;
+ if (*line == '#' || *line == '\n')
+ continue;
+ if (!strpbrk(p, " \t")) {
+ _fs_fstab.fs_spec = strsep(&p, ":\n");
+ _fs_fstab.fs_file = strsep(&p, ":\n");
+ fixfsfile();
+ _fs_fstab.fs_type = strsep(&p, ":\n");
+ if (_fs_fstab.fs_type) {
+ if (!strcmp(_fs_fstab.fs_type, FSTAB_XX))
+ continue;
+ _fs_fstab.fs_mntops = _fs_fstab.fs_type;
+ _fs_fstab.fs_vfstype =
+ strcmp(_fs_fstab.fs_type, FSTAB_SW) ?
+ "ufs" : "swap";
+ if ((cp = strsep(&p, ":\n")) != NULL) {
+ _fs_fstab.fs_freq = atoi(cp);
+ if ((cp = strsep(&p, ":\n")) != NULL) {
+ _fs_fstab.fs_passno = atoi(cp);
+ return (1);
+ }
+ }
+ }
+ goto bad;
+ }
+/* OLD_STYLE_FSTAB */
+ while ((cp = strsep(&p, " \t\n")) != NULL && *cp == '\0')
+ ;
+ _fs_fstab.fs_spec = cp;
+ if (_fs_fstab.fs_spec == NULL || *_fs_fstab.fs_spec == '#')
+ continue;
+ if (strunvis(_fs_fstab.fs_spec, _fs_fstab.fs_spec) < 0)
+ goto bad;
+ while ((cp = strsep(&p, " \t\n")) != NULL && *cp == '\0')
+ ;
+ _fs_fstab.fs_file = cp;
+ if (_fs_fstab.fs_file == NULL)
+ goto bad;
+ if (strunvis(_fs_fstab.fs_file, _fs_fstab.fs_file) < 0)
+ goto bad;
+ fixfsfile();
+ while ((cp = strsep(&p, " \t\n")) != NULL && *cp == '\0')
+ ;
+ _fs_fstab.fs_vfstype = cp;
+ while ((cp = strsep(&p, " \t\n")) != NULL && *cp == '\0')
+ ;
+ _fs_fstab.fs_mntops = cp;
+ if (_fs_fstab.fs_mntops == NULL)
+ goto bad;
+ _fs_fstab.fs_freq = 0;
+ _fs_fstab.fs_passno = 0;
+ while ((cp = strsep(&p, " \t\n")) != NULL && *cp == '\0')
+ ;
+ if (cp != NULL) {
+ _fs_fstab.fs_freq = atoi(cp);
+ while ((cp = strsep(&p, " \t\n")) != NULL && *cp == '\0')
+ ;
+ if (cp != NULL)
+ _fs_fstab.fs_passno = atoi(cp);
+ }
+ (void)strlcpy(subline, _fs_fstab.fs_mntops, sizeof(subline));
+ p = subline;
+ for (typexx = 0, cp = strsep(&p, ","); cp;
+ cp = strsep(&p, ",")) {
+ if (strlen(cp) != 2)
+ continue;
+ if (!strcmp(cp, FSTAB_RW)) {
+ _fs_fstab.fs_type = FSTAB_RW;
+ break;
+ }
+ if (!strcmp(cp, FSTAB_RQ)) {
+ _fs_fstab.fs_type = FSTAB_RQ;
+ break;
+ }
+ if (!strcmp(cp, FSTAB_RO)) {
+ _fs_fstab.fs_type = FSTAB_RO;
+ break;
+ }
+ if (!strcmp(cp, FSTAB_SW)) {
+ _fs_fstab.fs_type = FSTAB_SW;
+ break;
+ }
+ if (!strcmp(cp, FSTAB_XX)) {
+ _fs_fstab.fs_type = FSTAB_XX;
+ typexx++;
+ break;
+ }
+ }
+ if (typexx)
+ continue;
+ if (cp != NULL)
+ return (1);
+
+bad: /* no way to distinguish between EOF and syntax error */
+ error(EFTYPE);
+ }
+ /* NOTREACHED */
+}
+
+struct fstab *
+getfsent(void)
+{
+
+ if ((!_fs_fp && !setfsent()) || !fstabscan())
+ return (NULL);
+ return (&_fs_fstab);
+}
+
+struct fstab *
+getfsspec(const char *name)
+{
+
+ if (setfsent())
+ while (fstabscan())
+ if (!strcmp(_fs_fstab.fs_spec, name))
+ return (&_fs_fstab);
+ return (NULL);
+}
+
+struct fstab *
+getfsfile(const char *name)
+{
+
+ if (setfsent())
+ while (fstabscan())
+ if (!strcmp(_fs_fstab.fs_file, name))
+ return (&_fs_fstab);
+ return (NULL);
+}
+
+int
+setfsent(void)
+{
+ if (_fs_fp) {
+ rewind(_fs_fp);
+ LineNo = 0;
+ return (1);
+ }
+ if (fsp_set == 0) {
+ if (issetugid())
+ setfstab(NULL);
+ else
+ setfstab(getenv("PATH_FSTAB"));
+ }
+ if ((_fs_fp = fopen(path_fstab, "re")) != NULL) {
+ LineNo = 0;
+ return (1);
+ }
+ error(errno);
+ return (0);
+}
+
+void
+endfsent(void)
+{
+
+ if (_fs_fp) {
+ (void)fclose(_fs_fp);
+ _fs_fp = NULL;
+ }
+
+ fsp_set = 0;
+}
+
+static void
+error(int err)
+{
+ char *p;
+ char num[30];
+
+ (void)_write(STDERR_FILENO, "fstab: ", 7);
+ (void)_write(STDERR_FILENO, path_fstab, strlen(path_fstab));
+ (void)_write(STDERR_FILENO, ":", 1);
+ sprintf(num, "%d: ", LineNo);
+ (void)_write(STDERR_FILENO, num, strlen(num));
+ p = strerror(err);
+ (void)_write(STDERR_FILENO, p, strlen(p));
+ (void)_write(STDERR_FILENO, "\n", 1);
+}
diff --git a/lib/libc/gen/ftok.3 b/lib/libc/gen/ftok.3
new file mode 100644
index 000000000000..b819dbd185d4
--- /dev/null
+++ b/lib/libc/gen/ftok.3
@@ -0,0 +1,83 @@
+.\" Copyright (c) 1994 SigmaSoft, Th. Lockert <tholo@sigmasoft.com>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+.\" PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+.\" OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+.\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.Dd July 9, 2009
+.Dt FTOK 3
+.Os
+.Sh NAME
+.Nm ftok
+.Nd create IPC identifier from path name
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/ipc.h
+.Ft key_t
+.Fn ftok "const char *path" "int id"
+.Sh DESCRIPTION
+The
+.Fn ftok
+function attempts to create a unique key suitable for use with the
+.Xr msgget 2 ,
+.Xr semget 2
+and
+.Xr shmget 2
+functions given the
+.Fa path
+of an existing file and a user-selectable
+.Fa id .
+.Pp
+The specified
+.Fa path
+must specify an existing file that is accessible to the calling process
+or the call will fail.
+Also, note that links to files will return the
+same key, given the same
+.Fa id .
+.Sh RETURN VALUES
+The
+.Fn ftok
+function will return -1 if
+.Fa path
+does not exist or if it cannot be accessed by the calling process.
+.Sh SEE ALSO
+.Xr msgget 2 ,
+.Xr semget 2 ,
+.Xr shmget 2
+.Sh HISTORY
+The
+.Fn ftok
+function originates with System V and is typically used by programs
+that use the System V IPC routines.
+.Sh AUTHORS
+.An Thorsten Lockert Aq Mt tholo@sigmasoft.com
+.Sh BUGS
+The returned key is computed based on the device minor number and inode of the
+specified
+.Fa path
+in combination with the lower 8 bits of the given
+.Fa id .
+Thus it is quite possible for the routine to return duplicate keys.
diff --git a/lib/libc/gen/ftok.c b/lib/libc/gen/ftok.c
new file mode 100644
index 000000000000..2fad66e64ee1
--- /dev/null
+++ b/lib/libc/gen/ftok.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 1994 SigmaSoft, Th. Lockert <tholo@sigmasoft.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ipc.h>
+
+key_t
+ftok(const char *path, int id)
+{
+ struct stat st;
+
+ if (stat(path, &st) < 0)
+ return (key_t)-1;
+
+ return (key_t) (id << 24 | (st.st_dev & 0xff) << 16 | (st.st_ino & 0xffff));
+}
diff --git a/lib/libc/gen/fts-compat.c b/lib/libc/gen/fts-compat.c
new file mode 100644
index 000000000000..c34a281cfe3c
--- /dev/null
+++ b/lib/libc/gen/fts-compat.c
@@ -0,0 +1,1214 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $OpenBSD: fts.c,v 1.22 1999/10/03 19:22:22 millert Exp $
+ */
+
+#if 0
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)fts.c 8.6 (Berkeley) 8/14/94";
+#endif /* LIBC_SCCS and not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "fts-compat.h"
+#include "un-namespace.h"
+
+#include "gen-private.h"
+
+FTSENT *__fts_children_44bsd(FTS *, int);
+int __fts_close_44bsd(FTS *);
+void *__fts_get_clientptr_44bsd(FTS *);
+FTS *__fts_get_stream_44bsd(FTSENT *);
+FTS *__fts_open_44bsd(char * const *, int,
+ int (*)(const FTSENT * const *, const FTSENT * const *));
+FTSENT *__fts_read_44bsd(FTS *);
+int __fts_set_44bsd(FTS *, FTSENT *, int);
+void __fts_set_clientptr_44bsd(FTS *, void *);
+
+static FTSENT *fts_alloc(FTS *, char *, int);
+static FTSENT *fts_build(FTS *, int);
+static void fts_lfree(FTSENT *);
+static void fts_load(FTS *, FTSENT *);
+static size_t fts_maxarglen(char * const *);
+static void fts_padjust(FTS *, FTSENT *);
+static int fts_palloc(FTS *, size_t);
+static FTSENT *fts_sort(FTS *, FTSENT *, int);
+static u_short fts_stat(FTS *, FTSENT *, int);
+static int fts_safe_changedir(FTS *, FTSENT *, int, char *);
+static int fts_ufslinks(FTS *, const FTSENT *);
+
+#define ISDOT(a) (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2])))
+
+#define CLR(opt) (sp->fts_options &= ~(opt))
+#define ISSET(opt) (sp->fts_options & (opt))
+#define SET(opt) (sp->fts_options |= (opt))
+
+#define FCHDIR(sp, fd) (!ISSET(FTS_NOCHDIR) && fchdir(fd))
+
+/* fts_build flags */
+#define BCHILD 1 /* fts_children */
+#define BNAMES 2 /* fts_children, names only */
+#define BREAD 3 /* fts_read */
+
+/*
+ * Internal representation of an FTS, including extra implementation
+ * details. The FTS returned from fts_open points to this structure's
+ * ftsp_fts member (and can be cast to an _fts_private as required)
+ */
+struct _fts_private {
+ FTS ftsp_fts;
+ struct statfs ftsp_statfs;
+ dev_t ftsp_dev;
+ int ftsp_linksreliable;
+};
+
+/*
+ * The "FTS_NOSTAT" option can avoid a lot of calls to stat(2) if it
+ * knows that a directory could not possibly have subdirectories. This
+ * is decided by looking at the link count: a subdirectory would
+ * increment its parent's link count by virtue of its own ".." entry.
+ * This assumption only holds for UFS-like filesystems that implement
+ * links and directories this way, so we must punt for others.
+ */
+
+static const char *ufslike_filesystems[] = {
+ "ufs",
+ "zfs",
+ "nfs",
+ "ext2fs",
+ 0
+};
+
+FTS *
+__fts_open_44bsd(char * const *argv, int options,
+ int (*compar)(const FTSENT * const *, const FTSENT * const *))
+{
+ struct _fts_private *priv;
+ FTS *sp;
+ FTSENT *p, *root;
+ int nitems;
+ FTSENT *parent, *tmp;
+ int len;
+
+ /* Options check. */
+ if (options & ~FTS_OPTIONMASK) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ /* Allocate/initialize the stream. */
+ if ((priv = calloc(1, sizeof(*priv))) == NULL)
+ return (NULL);
+ sp = &priv->ftsp_fts;
+ sp->fts_compar = compar;
+ sp->fts_options = options;
+
+ /* Shush, GCC. */
+ tmp = NULL;
+
+ /* Logical walks turn on NOCHDIR; symbolic links are too hard. */
+ if (ISSET(FTS_LOGICAL))
+ SET(FTS_NOCHDIR);
+
+ /*
+ * Start out with 1K of path space, and enough, in any case,
+ * to hold the user's paths.
+ */
+ if (fts_palloc(sp, MAX(fts_maxarglen(argv), MAXPATHLEN)))
+ goto mem1;
+
+ /* Allocate/initialize root's parent. */
+ if ((parent = fts_alloc(sp, "", 0)) == NULL)
+ goto mem2;
+ parent->fts_level = FTS_ROOTPARENTLEVEL;
+
+ /* Allocate/initialize root(s). */
+ for (root = NULL, nitems = 0; *argv != NULL; ++argv, ++nitems) {
+ /* Don't allow zero-length paths. */
+ if ((len = strlen(*argv)) == 0) {
+ errno = ENOENT;
+ goto mem3;
+ }
+
+ p = fts_alloc(sp, *argv, len);
+ p->fts_level = FTS_ROOTLEVEL;
+ p->fts_parent = parent;
+ p->fts_accpath = p->fts_name;
+ p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW));
+
+ /* Command-line "." and ".." are real directories. */
+ if (p->fts_info == FTS_DOT)
+ p->fts_info = FTS_D;
+
+ /*
+ * If comparison routine supplied, traverse in sorted
+ * order; otherwise traverse in the order specified.
+ */
+ if (compar) {
+ p->fts_link = root;
+ root = p;
+ } else {
+ p->fts_link = NULL;
+ if (root == NULL)
+ tmp = root = p;
+ else {
+ tmp->fts_link = p;
+ tmp = p;
+ }
+ }
+ }
+ if (compar && nitems > 1)
+ root = fts_sort(sp, root, nitems);
+
+ /*
+ * Allocate a dummy pointer and make fts_read think that we've just
+ * finished the node before the root(s); set p->fts_info to FTS_INIT
+ * so that everything about the "current" node is ignored.
+ */
+ if ((sp->fts_cur = fts_alloc(sp, "", 0)) == NULL)
+ goto mem3;
+ sp->fts_cur->fts_link = root;
+ sp->fts_cur->fts_info = FTS_INIT;
+
+ /*
+ * If using chdir(2), grab a file descriptor pointing to dot to ensure
+ * that we can get back here; this could be avoided for some paths,
+ * but almost certainly not worth the effort. Slashes, symbolic links,
+ * and ".." are all fairly nasty problems. Note, if we can't get the
+ * descriptor we run anyway, just more slowly.
+ */
+ if (!ISSET(FTS_NOCHDIR) &&
+ (sp->fts_rfd = _open(".", O_RDONLY | O_CLOEXEC, 0)) < 0)
+ SET(FTS_NOCHDIR);
+
+ return (sp);
+
+mem3: fts_lfree(root);
+ free(parent);
+mem2: free(sp->fts_path);
+mem1: free(sp);
+ return (NULL);
+}
+
+static void
+fts_load(FTS *sp, FTSENT *p)
+{
+ int len;
+ char *cp;
+
+ /*
+ * Load the stream structure for the next traversal. Since we don't
+ * actually enter the directory until after the preorder visit, set
+ * the fts_accpath field specially so the chdir gets done to the right
+ * place and the user can access the first node. From fts_open it's
+ * known that the path will fit.
+ */
+ len = p->fts_pathlen = p->fts_namelen;
+ memmove(sp->fts_path, p->fts_name, len + 1);
+ if ((cp = strrchr(p->fts_name, '/')) && (cp != p->fts_name || cp[1])) {
+ len = strlen(++cp);
+ memmove(p->fts_name, cp, len + 1);
+ p->fts_namelen = len;
+ }
+ p->fts_accpath = p->fts_path = sp->fts_path;
+ sp->fts_dev = p->fts_dev;
+}
+
+int
+__fts_close_44bsd(FTS *sp)
+{
+ FTSENT *freep, *p;
+ int saved_errno;
+
+ /*
+ * This still works if we haven't read anything -- the dummy structure
+ * points to the root list, so we step through to the end of the root
+ * list which has a valid parent pointer.
+ */
+ if (sp->fts_cur) {
+ for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) {
+ freep = p;
+ p = p->fts_link != NULL ? p->fts_link : p->fts_parent;
+ free(freep);
+ }
+ free(p);
+ }
+
+ /* Free up child linked list, sort array, path buffer. */
+ if (sp->fts_child)
+ fts_lfree(sp->fts_child);
+ if (sp->fts_array)
+ free(sp->fts_array);
+ free(sp->fts_path);
+
+ /* Return to original directory, save errno if necessary. */
+ if (!ISSET(FTS_NOCHDIR)) {
+ saved_errno = fchdir(sp->fts_rfd) ? errno : 0;
+ (void)_close(sp->fts_rfd);
+
+ /* Set errno and return. */
+ if (saved_errno != 0) {
+ /* Free up the stream pointer. */
+ free(sp);
+ errno = saved_errno;
+ return (-1);
+ }
+ }
+
+ /* Free up the stream pointer. */
+ free(sp);
+ return (0);
+}
+
+/*
+ * Special case of "/" at the end of the path so that slashes aren't
+ * appended which would cause paths to be written as "....//foo".
+ */
+#define NAPPEND(p) \
+ (p->fts_path[p->fts_pathlen - 1] == '/' \
+ ? p->fts_pathlen - 1 : p->fts_pathlen)
+
+FTSENT *
+__fts_read_44bsd(FTS *sp)
+{
+ FTSENT *p, *tmp;
+ int instr;
+ char *t;
+ int saved_errno;
+
+ /* If finished or unrecoverable error, return NULL. */
+ if (sp->fts_cur == NULL || ISSET(FTS_STOP))
+ return (NULL);
+
+ /* Set current node pointer. */
+ p = sp->fts_cur;
+
+ /* Save and zero out user instructions. */
+ instr = p->fts_instr;
+ p->fts_instr = FTS_NOINSTR;
+
+ /* Any type of file may be re-visited; re-stat and re-turn. */
+ if (instr == FTS_AGAIN) {
+ p->fts_info = fts_stat(sp, p, 0);
+ return (p);
+ }
+
+ /*
+ * Following a symlink -- SLNONE test allows application to see
+ * SLNONE and recover. If indirecting through a symlink, have
+ * keep a pointer to current location. If unable to get that
+ * pointer, follow fails.
+ */
+ if (instr == FTS_FOLLOW &&
+ (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) {
+ p->fts_info = fts_stat(sp, p, 1);
+ if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
+ if ((p->fts_symfd = _open(".", O_RDONLY | O_CLOEXEC,
+ 0)) < 0) {
+ p->fts_errno = errno;
+ p->fts_info = FTS_ERR;
+ } else
+ p->fts_flags |= FTS_SYMFOLLOW;
+ }
+ return (p);
+ }
+
+ /* Directory in pre-order. */
+ if (p->fts_info == FTS_D) {
+ /* If skipped or crossed mount point, do post-order visit. */
+ if (instr == FTS_SKIP ||
+ (ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev)) {
+ if (p->fts_flags & FTS_SYMFOLLOW)
+ (void)_close(p->fts_symfd);
+ if (sp->fts_child) {
+ fts_lfree(sp->fts_child);
+ sp->fts_child = NULL;
+ }
+ p->fts_info = FTS_DP;
+ return (p);
+ }
+
+ /* Rebuild if only read the names and now traversing. */
+ if (sp->fts_child != NULL && ISSET(FTS_NAMEONLY)) {
+ CLR(FTS_NAMEONLY);
+ fts_lfree(sp->fts_child);
+ sp->fts_child = NULL;
+ }
+
+ /*
+ * Cd to the subdirectory.
+ *
+ * If have already read and now fail to chdir, whack the list
+ * to make the names come out right, and set the parent errno
+ * so the application will eventually get an error condition.
+ * Set the FTS_DONTCHDIR flag so that when we logically change
+ * directories back to the parent we don't do a chdir.
+ *
+ * If haven't read do so. If the read fails, fts_build sets
+ * FTS_STOP or the fts_info field of the node.
+ */
+ if (sp->fts_child != NULL) {
+ if (fts_safe_changedir(sp, p, -1, p->fts_accpath)) {
+ p->fts_errno = errno;
+ p->fts_flags |= FTS_DONTCHDIR;
+ for (p = sp->fts_child; p != NULL;
+ p = p->fts_link)
+ p->fts_accpath =
+ p->fts_parent->fts_accpath;
+ }
+ } else if ((sp->fts_child = fts_build(sp, BREAD)) == NULL) {
+ if (ISSET(FTS_STOP))
+ return (NULL);
+ return (p);
+ }
+ p = sp->fts_child;
+ sp->fts_child = NULL;
+ goto name;
+ }
+
+ /* Move to the next node on this level. */
+next: tmp = p;
+ if ((p = p->fts_link) != NULL) {
+ free(tmp);
+
+ /*
+ * If reached the top, return to the original directory (or
+ * the root of the tree), and load the paths for the next root.
+ */
+ if (p->fts_level == FTS_ROOTLEVEL) {
+ if (FCHDIR(sp, sp->fts_rfd)) {
+ SET(FTS_STOP);
+ return (NULL);
+ }
+ fts_load(sp, p);
+ return (sp->fts_cur = p);
+ }
+
+ /*
+ * User may have called fts_set on the node. If skipped,
+ * ignore. If followed, get a file descriptor so we can
+ * get back if necessary.
+ */
+ if (p->fts_instr == FTS_SKIP)
+ goto next;
+ if (p->fts_instr == FTS_FOLLOW) {
+ p->fts_info = fts_stat(sp, p, 1);
+ if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
+ if ((p->fts_symfd =
+ _open(".", O_RDONLY | O_CLOEXEC, 0)) < 0) {
+ p->fts_errno = errno;
+ p->fts_info = FTS_ERR;
+ } else
+ p->fts_flags |= FTS_SYMFOLLOW;
+ }
+ p->fts_instr = FTS_NOINSTR;
+ }
+
+name: t = sp->fts_path + NAPPEND(p->fts_parent);
+ *t++ = '/';
+ memmove(t, p->fts_name, p->fts_namelen + 1);
+ return (sp->fts_cur = p);
+ }
+
+ /* Move up to the parent node. */
+ p = tmp->fts_parent;
+ free(tmp);
+
+ if (p->fts_level == FTS_ROOTPARENTLEVEL) {
+ /*
+ * Done; free everything up and set errno to 0 so the user
+ * can distinguish between error and EOF.
+ */
+ free(p);
+ errno = 0;
+ return (sp->fts_cur = NULL);
+ }
+
+ /* NUL terminate the pathname. */
+ sp->fts_path[p->fts_pathlen] = '\0';
+
+ /*
+ * Return to the parent directory. If at a root node or came through
+ * a symlink, go back through the file descriptor. Otherwise, cd up
+ * one directory.
+ */
+ if (p->fts_level == FTS_ROOTLEVEL) {
+ if (FCHDIR(sp, sp->fts_rfd)) {
+ SET(FTS_STOP);
+ return (NULL);
+ }
+ } else if (p->fts_flags & FTS_SYMFOLLOW) {
+ if (FCHDIR(sp, p->fts_symfd)) {
+ saved_errno = errno;
+ (void)_close(p->fts_symfd);
+ errno = saved_errno;
+ SET(FTS_STOP);
+ return (NULL);
+ }
+ (void)_close(p->fts_symfd);
+ } else if (!(p->fts_flags & FTS_DONTCHDIR) &&
+ fts_safe_changedir(sp, p->fts_parent, -1, "..")) {
+ SET(FTS_STOP);
+ return (NULL);
+ }
+ p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP;
+ return (sp->fts_cur = p);
+}
+
+/*
+ * Fts_set takes the stream as an argument although it's not used in this
+ * implementation; it would be necessary if anyone wanted to add global
+ * semantics to fts using fts_set. An error return is allowed for similar
+ * reasons.
+ */
+/* ARGSUSED */
+int
+__fts_set_44bsd(FTS *sp, FTSENT *p, int instr)
+{
+ if (instr != 0 && instr != FTS_AGAIN && instr != FTS_FOLLOW &&
+ instr != FTS_NOINSTR && instr != FTS_SKIP) {
+ errno = EINVAL;
+ return (1);
+ }
+ p->fts_instr = instr;
+ return (0);
+}
+
+FTSENT *
+__fts_children_44bsd(FTS *sp, int instr)
+{
+ FTSENT *p;
+ int fd;
+
+ if (instr != 0 && instr != FTS_NAMEONLY) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ /* Set current node pointer. */
+ p = sp->fts_cur;
+
+ /*
+ * Errno set to 0 so user can distinguish empty directory from
+ * an error.
+ */
+ errno = 0;
+
+ /* Fatal errors stop here. */
+ if (ISSET(FTS_STOP))
+ return (NULL);
+
+ /* Return logical hierarchy of user's arguments. */
+ if (p->fts_info == FTS_INIT)
+ return (p->fts_link);
+
+ /*
+ * If not a directory being visited in pre-order, stop here. Could
+ * allow FTS_DNR, assuming the user has fixed the problem, but the
+ * same effect is available with FTS_AGAIN.
+ */
+ if (p->fts_info != FTS_D /* && p->fts_info != FTS_DNR */)
+ return (NULL);
+
+ /* Free up any previous child list. */
+ if (sp->fts_child != NULL)
+ fts_lfree(sp->fts_child);
+
+ if (instr == FTS_NAMEONLY) {
+ SET(FTS_NAMEONLY);
+ instr = BNAMES;
+ } else
+ instr = BCHILD;
+
+ /*
+ * If using chdir on a relative path and called BEFORE fts_read does
+ * its chdir to the root of a traversal, we can lose -- we need to
+ * chdir into the subdirectory, and we don't know where the current
+ * directory is, so we can't get back so that the upcoming chdir by
+ * fts_read will work.
+ */
+ if (p->fts_level != FTS_ROOTLEVEL || p->fts_accpath[0] == '/' ||
+ ISSET(FTS_NOCHDIR))
+ return (sp->fts_child = fts_build(sp, instr));
+
+ if ((fd = _open(".", O_RDONLY | O_CLOEXEC, 0)) < 0)
+ return (NULL);
+ sp->fts_child = fts_build(sp, instr);
+ if (fchdir(fd)) {
+ (void)_close(fd);
+ return (NULL);
+ }
+ (void)_close(fd);
+ return (sp->fts_child);
+}
+
+#ifndef fts_get_clientptr
+#error "fts_get_clientptr not defined"
+#endif
+
+void *
+(__fts_get_clientptr_44bsd)(FTS *sp)
+{
+
+ return (fts_get_clientptr(sp));
+}
+
+#ifndef fts_get_stream
+#error "fts_get_stream not defined"
+#endif
+
+FTS *
+(__fts_get_stream_44bsd)(FTSENT *p)
+{
+ return (fts_get_stream(p));
+}
+
+void
+__fts_set_clientptr_44bsd(FTS *sp, void *clientptr)
+{
+
+ sp->fts_clientptr = clientptr;
+}
+
+/*
+ * This is the tricky part -- do not casually change *anything* in here. The
+ * idea is to build the linked list of entries that are used by fts_children
+ * and fts_read. There are lots of special cases.
+ *
+ * The real slowdown in walking the tree is the stat calls. If FTS_NOSTAT is
+ * set and it's a physical walk (so that symbolic links can't be directories),
+ * we can do things quickly. First, if it's a 4.4BSD file system, the type
+ * of the file is in the directory entry. Otherwise, we assume that the number
+ * of subdirectories in a node is equal to the number of links to the parent.
+ * The former skips all stat calls. The latter skips stat calls in any leaf
+ * directories and for any files after the subdirectories in the directory have
+ * been found, cutting the stat calls by about 2/3.
+ */
+static FTSENT *
+fts_build(FTS *sp, int type)
+{
+ struct dirent *dp;
+ FTSENT *p, *head;
+ int nitems;
+ FTSENT *cur, *tail;
+ DIR *dirp;
+ void *oldaddr;
+ size_t dnamlen;
+ int cderrno, descend, len, level, maxlen, nlinks, oflag, saved_errno,
+ nostat, doadjust;
+ char *cp;
+
+ /* Set current node pointer. */
+ cur = sp->fts_cur;
+
+ /*
+ * Open the directory for reading. If this fails, we're done.
+ * If being called from fts_read, set the fts_info field.
+ */
+#ifdef FTS_WHITEOUT
+ if (ISSET(FTS_WHITEOUT))
+ oflag = DTF_NODUP | DTF_REWIND;
+ else
+ oflag = DTF_HIDEW | DTF_NODUP | DTF_REWIND;
+#else
+#define __opendir2(path, flag) opendir(path)
+#endif
+ if ((dirp = __opendir2(cur->fts_accpath, oflag)) == NULL) {
+ if (type == BREAD) {
+ cur->fts_info = FTS_DNR;
+ cur->fts_errno = errno;
+ }
+ return (NULL);
+ }
+
+ /*
+ * Nlinks is the number of possible entries of type directory in the
+ * directory if we're cheating on stat calls, 0 if we're not doing
+ * any stat calls at all, -1 if we're doing stats on everything.
+ */
+ if (type == BNAMES) {
+ nlinks = 0;
+ /* Be quiet about nostat, GCC. */
+ nostat = 0;
+ } else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL)) {
+ if (fts_ufslinks(sp, cur))
+ nlinks = cur->fts_nlink - (ISSET(FTS_SEEDOT) ? 0 : 2);
+ else
+ nlinks = -1;
+ nostat = 1;
+ } else {
+ nlinks = -1;
+ nostat = 0;
+ }
+
+#ifdef notdef
+ (void)printf("nlinks == %d (cur: %d)\n", nlinks, cur->fts_nlink);
+ (void)printf("NOSTAT %d PHYSICAL %d SEEDOT %d\n",
+ ISSET(FTS_NOSTAT), ISSET(FTS_PHYSICAL), ISSET(FTS_SEEDOT));
+#endif
+ /*
+ * If we're going to need to stat anything or we want to descend
+ * and stay in the directory, chdir. If this fails we keep going,
+ * but set a flag so we don't chdir after the post-order visit.
+ * We won't be able to stat anything, but we can still return the
+ * names themselves. Note, that since fts_read won't be able to
+ * chdir into the directory, it will have to return different path
+ * names than before, i.e. "a/b" instead of "b". Since the node
+ * has already been visited in pre-order, have to wait until the
+ * post-order visit to return the error. There is a special case
+ * here, if there was nothing to stat then it's not an error to
+ * not be able to stat. This is all fairly nasty. If a program
+ * needed sorted entries or stat information, they had better be
+ * checking FTS_NS on the returned nodes.
+ */
+ cderrno = 0;
+ if (nlinks || type == BREAD) {
+ if (fts_safe_changedir(sp, cur, _dirfd(dirp), NULL)) {
+ if (nlinks && type == BREAD)
+ cur->fts_errno = errno;
+ cur->fts_flags |= FTS_DONTCHDIR;
+ descend = 0;
+ cderrno = errno;
+ } else
+ descend = 1;
+ } else
+ descend = 0;
+
+ /*
+ * Figure out the max file name length that can be stored in the
+ * current path -- the inner loop allocates more path as necessary.
+ * We really wouldn't have to do the maxlen calculations here, we
+ * could do them in fts_read before returning the path, but it's a
+ * lot easier here since the length is part of the dirent structure.
+ *
+ * If not changing directories set a pointer so that can just append
+ * each new name into the path.
+ */
+ len = NAPPEND(cur);
+ if (ISSET(FTS_NOCHDIR)) {
+ cp = sp->fts_path + len;
+ *cp++ = '/';
+ } else {
+ /* GCC, you're too verbose. */
+ cp = NULL;
+ }
+ len++;
+ maxlen = sp->fts_pathlen - len;
+
+ level = cur->fts_level + 1;
+
+ /* Read the directory, attaching each entry to the `link' pointer. */
+ doadjust = 0;
+ for (head = tail = NULL, nitems = 0; dirp && (dp = readdir(dirp));) {
+ dnamlen = dp->d_namlen;
+ if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name))
+ continue;
+
+ if ((p = fts_alloc(sp, dp->d_name, (int)dnamlen)) == NULL)
+ goto mem1;
+ if (dnamlen >= maxlen) { /* include space for NUL */
+ oldaddr = sp->fts_path;
+ if (fts_palloc(sp, dnamlen + len + 1)) {
+ /*
+ * No more memory for path or structures. Save
+ * errno, free up the current structure and the
+ * structures already allocated.
+ */
+mem1: saved_errno = errno;
+ if (p)
+ free(p);
+ fts_lfree(head);
+ (void)closedir(dirp);
+ cur->fts_info = FTS_ERR;
+ SET(FTS_STOP);
+ errno = saved_errno;
+ return (NULL);
+ }
+ /* Did realloc() change the pointer? */
+ if (oldaddr != sp->fts_path) {
+ doadjust = 1;
+ if (ISSET(FTS_NOCHDIR))
+ cp = sp->fts_path + len;
+ }
+ maxlen = sp->fts_pathlen - len;
+ }
+
+ if (len + dnamlen >= USHRT_MAX) {
+ /*
+ * In an FTSENT, fts_pathlen is a u_short so it is
+ * possible to wraparound here. If we do, free up
+ * the current structure and the structures already
+ * allocated, then error out with ENAMETOOLONG.
+ */
+ free(p);
+ fts_lfree(head);
+ (void)closedir(dirp);
+ cur->fts_info = FTS_ERR;
+ SET(FTS_STOP);
+ errno = ENAMETOOLONG;
+ return (NULL);
+ }
+ p->fts_level = level;
+ p->fts_parent = sp->fts_cur;
+ p->fts_pathlen = len + dnamlen;
+
+#ifdef FTS_WHITEOUT
+ if (dp->d_type == DT_WHT)
+ p->fts_flags |= FTS_ISW;
+#endif
+
+ if (cderrno) {
+ if (nlinks) {
+ p->fts_info = FTS_NS;
+ p->fts_errno = cderrno;
+ } else
+ p->fts_info = FTS_NSOK;
+ p->fts_accpath = cur->fts_accpath;
+ } else if (nlinks == 0
+#ifdef DT_DIR
+ || (nostat &&
+ dp->d_type != DT_DIR && dp->d_type != DT_UNKNOWN)
+#endif
+ ) {
+ p->fts_accpath =
+ ISSET(FTS_NOCHDIR) ? p->fts_path : p->fts_name;
+ p->fts_info = FTS_NSOK;
+ } else {
+ /* Build a file name for fts_stat to stat. */
+ if (ISSET(FTS_NOCHDIR)) {
+ p->fts_accpath = p->fts_path;
+ memmove(cp, p->fts_name, p->fts_namelen + 1);
+ } else
+ p->fts_accpath = p->fts_name;
+ /* Stat it. */
+ p->fts_info = fts_stat(sp, p, 0);
+
+ /* Decrement link count if applicable. */
+ if (nlinks > 0 && (p->fts_info == FTS_D ||
+ p->fts_info == FTS_DC || p->fts_info == FTS_DOT))
+ --nlinks;
+ }
+
+ /* We walk in directory order so "ls -f" doesn't get upset. */
+ p->fts_link = NULL;
+ if (head == NULL)
+ head = tail = p;
+ else {
+ tail->fts_link = p;
+ tail = p;
+ }
+ ++nitems;
+ }
+ if (dirp)
+ (void)closedir(dirp);
+
+ /*
+ * If realloc() changed the address of the path, adjust the
+ * addresses for the rest of the tree and the dir list.
+ */
+ if (doadjust)
+ fts_padjust(sp, head);
+
+ /*
+ * If not changing directories, reset the path back to original
+ * state.
+ */
+ if (ISSET(FTS_NOCHDIR)) {
+ if (len == sp->fts_pathlen || nitems == 0)
+ --cp;
+ *cp = '\0';
+ }
+
+ /*
+ * If descended after called from fts_children or after called from
+ * fts_read and nothing found, get back. At the root level we use
+ * the saved fd; if one of fts_open()'s arguments is a relative path
+ * to an empty directory, we wind up here with no other way back. If
+ * can't get back, we're done.
+ */
+ if (descend && (type == BCHILD || !nitems) &&
+ (cur->fts_level == FTS_ROOTLEVEL ?
+ FCHDIR(sp, sp->fts_rfd) :
+ fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) {
+ cur->fts_info = FTS_ERR;
+ SET(FTS_STOP);
+ return (NULL);
+ }
+
+ /* If didn't find anything, return NULL. */
+ if (!nitems) {
+ if (type == BREAD)
+ cur->fts_info = FTS_DP;
+ return (NULL);
+ }
+
+ /* Sort the entries. */
+ if (sp->fts_compar && nitems > 1)
+ head = fts_sort(sp, head, nitems);
+ return (head);
+}
+
+static u_short
+fts_stat(FTS *sp, FTSENT *p, int follow)
+{
+ FTSENT *t;
+ dev_t dev;
+ ino_t ino;
+ struct stat *sbp, sb;
+ int saved_errno;
+
+ /* If user needs stat info, stat buffer already allocated. */
+ sbp = ISSET(FTS_NOSTAT) ? &sb : p->fts_statp;
+
+#ifdef FTS_WHITEOUT
+ /* Check for whiteout. */
+ if (p->fts_flags & FTS_ISW) {
+ if (sbp != &sb) {
+ memset(sbp, '\0', sizeof(*sbp));
+ sbp->st_mode = S_IFWHT;
+ }
+ return (FTS_W);
+ }
+#endif
+
+ /*
+ * If doing a logical walk, or application requested FTS_FOLLOW, do
+ * a stat(2). If that fails, check for a non-existent symlink. If
+ * fail, set the errno from the stat call.
+ */
+ if (ISSET(FTS_LOGICAL) || follow) {
+ if (stat(p->fts_accpath, sbp)) {
+ saved_errno = errno;
+ if (!lstat(p->fts_accpath, sbp)) {
+ errno = 0;
+ return (FTS_SLNONE);
+ }
+ p->fts_errno = saved_errno;
+ goto err;
+ }
+ } else if (lstat(p->fts_accpath, sbp)) {
+ p->fts_errno = errno;
+err: memset(sbp, 0, sizeof(struct stat));
+ return (FTS_NS);
+ }
+
+ if (S_ISDIR(sbp->st_mode)) {
+ /*
+ * Set the device/inode. Used to find cycles and check for
+ * crossing mount points. Also remember the link count, used
+ * in fts_build to limit the number of stat calls. It is
+ * understood that these fields are only referenced if fts_info
+ * is set to FTS_D.
+ */
+ dev = p->fts_dev = sbp->st_dev;
+ ino = p->fts_ino = sbp->st_ino;
+ p->fts_nlink = sbp->st_nlink;
+
+ if (ISDOT(p->fts_name))
+ return (FTS_DOT);
+
+ /*
+ * Cycle detection is done by brute force when the directory
+ * is first encountered. If the tree gets deep enough or the
+ * number of symbolic links to directories is high enough,
+ * something faster might be worthwhile.
+ */
+ for (t = p->fts_parent;
+ t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent)
+ if (ino == t->fts_ino && dev == t->fts_dev) {
+ p->fts_cycle = t;
+ return (FTS_DC);
+ }
+ return (FTS_D);
+ }
+ if (S_ISLNK(sbp->st_mode))
+ return (FTS_SL);
+ if (S_ISREG(sbp->st_mode))
+ return (FTS_F);
+ return (FTS_DEFAULT);
+}
+
+/*
+ * The comparison function takes pointers to pointers to FTSENT structures.
+ * Qsort wants a comparison function that takes pointers to void.
+ * (Both with appropriate levels of const-poisoning, of course!)
+ * Use a trampoline function to deal with the difference.
+ */
+static int
+fts_compar(const void *a, const void *b)
+{
+ FTS *parent;
+
+ parent = (*(const FTSENT * const *)a)->fts_fts;
+ return (*parent->fts_compar)(a, b);
+}
+
+static FTSENT *
+fts_sort(FTS *sp, FTSENT *head, int nitems)
+{
+ FTSENT **ap, *p;
+
+ /*
+ * Construct an array of pointers to the structures and call qsort(3).
+ * Reassemble the array in the order returned by qsort. If unable to
+ * sort for memory reasons, return the directory entries in their
+ * current order. Allocate enough space for the current needs plus
+ * 40 so don't realloc one entry at a time.
+ */
+ if (nitems > sp->fts_nitems) {
+ sp->fts_nitems = nitems + 40;
+ if ((sp->fts_array = reallocf(sp->fts_array,
+ sp->fts_nitems * sizeof(FTSENT *))) == NULL) {
+ sp->fts_nitems = 0;
+ return (head);
+ }
+ }
+ for (ap = sp->fts_array, p = head; p; p = p->fts_link)
+ *ap++ = p;
+ qsort(sp->fts_array, nitems, sizeof(FTSENT *), fts_compar);
+ for (head = *(ap = sp->fts_array); --nitems; ++ap)
+ ap[0]->fts_link = ap[1];
+ ap[0]->fts_link = NULL;
+ return (head);
+}
+
+static FTSENT *
+fts_alloc(FTS *sp, char *name, int namelen)
+{
+ FTSENT *p;
+ size_t len;
+
+ struct ftsent_withstat {
+ FTSENT ent;
+ struct stat statbuf;
+ };
+
+ /*
+ * The file name is a variable length array and no stat structure is
+ * necessary if the user has set the nostat bit. Allocate the FTSENT
+ * structure, the file name and the stat structure in one chunk, but
+ * be careful that the stat structure is reasonably aligned.
+ */
+ if (ISSET(FTS_NOSTAT))
+ len = sizeof(FTSENT) + namelen + 1;
+ else
+ len = sizeof(struct ftsent_withstat) + namelen + 1;
+
+ if ((p = malloc(len)) == NULL)
+ return (NULL);
+
+ if (ISSET(FTS_NOSTAT)) {
+ p->fts_name = (char *)(p + 1);
+ p->fts_statp = NULL;
+ } else {
+ p->fts_name = (char *)((struct ftsent_withstat *)p + 1);
+ p->fts_statp = &((struct ftsent_withstat *)p)->statbuf;
+ }
+
+ /* Copy the name and guarantee NUL termination. */
+ memcpy(p->fts_name, name, namelen);
+ p->fts_name[namelen] = '\0';
+ p->fts_namelen = namelen;
+ p->fts_path = sp->fts_path;
+ p->fts_errno = 0;
+ p->fts_flags = 0;
+ p->fts_instr = FTS_NOINSTR;
+ p->fts_number = 0;
+ p->fts_pointer = NULL;
+ p->fts_fts = sp;
+ return (p);
+}
+
+static void
+fts_lfree(FTSENT *head)
+{
+ FTSENT *p;
+
+ /* Free a linked list of structures. */
+ while ((p = head)) {
+ head = head->fts_link;
+ free(p);
+ }
+}
+
+/*
+ * Allow essentially unlimited paths; find, rm, ls should all work on any tree.
+ * Most systems will allow creation of paths much longer than MAXPATHLEN, even
+ * though the kernel won't resolve them. Add the size (not just what's needed)
+ * plus 256 bytes so don't realloc the path 2 bytes at a time.
+ */
+static int
+fts_palloc(FTS *sp, size_t more)
+{
+
+ sp->fts_pathlen += more + 256;
+ /*
+ * Check for possible wraparound. In an FTS, fts_pathlen is
+ * a signed int but in an FTSENT it is an unsigned short.
+ * We limit fts_pathlen to USHRT_MAX to be safe in both cases.
+ */
+ if (sp->fts_pathlen < 0 || sp->fts_pathlen >= USHRT_MAX) {
+ if (sp->fts_path)
+ free(sp->fts_path);
+ sp->fts_path = NULL;
+ errno = ENAMETOOLONG;
+ return (1);
+ }
+ sp->fts_path = reallocf(sp->fts_path, sp->fts_pathlen);
+ return (sp->fts_path == NULL);
+}
+
+/*
+ * When the path is realloc'd, have to fix all of the pointers in structures
+ * already returned.
+ */
+static void
+fts_padjust(FTS *sp, FTSENT *head)
+{
+ FTSENT *p;
+ char *addr = sp->fts_path;
+
+#define ADJUST(p) do { \
+ if ((p)->fts_accpath != (p)->fts_name) { \
+ (p)->fts_accpath = \
+ (char *)addr + ((p)->fts_accpath - (p)->fts_path); \
+ } \
+ (p)->fts_path = addr; \
+} while (0)
+ /* Adjust the current set of children. */
+ for (p = sp->fts_child; p; p = p->fts_link)
+ ADJUST(p);
+
+ /* Adjust the rest of the tree, including the current level. */
+ for (p = head; p->fts_level >= FTS_ROOTLEVEL;) {
+ ADJUST(p);
+ p = p->fts_link ? p->fts_link : p->fts_parent;
+ }
+}
+
+static size_t
+fts_maxarglen(char * const *argv)
+{
+ size_t len, max;
+
+ for (max = 0; *argv; ++argv)
+ if ((len = strlen(*argv)) > max)
+ max = len;
+ return (max + 1);
+}
+
+/*
+ * Change to dir specified by fd or p->fts_accpath without getting
+ * tricked by someone changing the world out from underneath us.
+ * Assumes p->fts_dev and p->fts_ino are filled in.
+ */
+static int
+fts_safe_changedir(FTS *sp, FTSENT *p, int fd, char *path)
+{
+ int ret, oerrno, newfd;
+ struct stat sb;
+
+ newfd = fd;
+ if (ISSET(FTS_NOCHDIR))
+ return (0);
+ if (fd < 0 && (newfd = _open(path, O_RDONLY | O_CLOEXEC, 0)) < 0)
+ return (-1);
+ if (_fstat(newfd, &sb)) {
+ ret = -1;
+ goto bail;
+ }
+ if (p->fts_dev != sb.st_dev || p->fts_ino != sb.st_ino) {
+ errno = ENOENT; /* disinformation */
+ ret = -1;
+ goto bail;
+ }
+ ret = fchdir(newfd);
+bail:
+ oerrno = errno;
+ if (fd < 0)
+ (void)_close(newfd);
+ errno = oerrno;
+ return (ret);
+}
+
+/*
+ * Check if the filesystem for "ent" has UFS-style links.
+ */
+static int
+fts_ufslinks(FTS *sp, const FTSENT *ent)
+{
+ struct _fts_private *priv;
+ const char **cpp;
+
+ priv = (struct _fts_private *)sp;
+ /*
+ * If this node's device is different from the previous, grab
+ * the filesystem information, and decide on the reliability
+ * of the link information from this filesystem for stat(2)
+ * avoidance.
+ */
+ if (priv->ftsp_dev != ent->fts_dev) {
+ if (statfs(ent->fts_path, &priv->ftsp_statfs) != -1) {
+ priv->ftsp_dev = ent->fts_dev;
+ priv->ftsp_linksreliable = 0;
+ for (cpp = ufslike_filesystems; *cpp; cpp++) {
+ if (strcmp(priv->ftsp_statfs.f_fstypename,
+ *cpp) == 0) {
+ priv->ftsp_linksreliable = 1;
+ break;
+ }
+ }
+ } else {
+ priv->ftsp_linksreliable = 0;
+ }
+ }
+ return (priv->ftsp_linksreliable);
+}
+
+__sym_compat(fts_open, __fts_open_44bsd, FBSD_1.0);
+__sym_compat(fts_close, __fts_close_44bsd, FBSD_1.0);
+__sym_compat(fts_read, __fts_read_44bsd, FBSD_1.0);
+__sym_compat(fts_set, __fts_set_44bsd, FBSD_1.0);
+__sym_compat(fts_children, __fts_children_44bsd, FBSD_1.0);
+__sym_compat(fts_get_clientptr, __fts_get_clientptr_44bsd, FBSD_1.0);
+__sym_compat(fts_get_stream, __fts_get_stream_44bsd, FBSD_1.0);
+__sym_compat(fts_set_clientptr, __fts_set_clientptr_44bsd, FBSD_1.0);
diff --git a/lib/libc/gen/fts-compat.h b/lib/libc/gen/fts-compat.h
new file mode 100644
index 000000000000..d8fe6895f11c
--- /dev/null
+++ b/lib/libc/gen/fts-compat.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)fts.h 8.3 (Berkeley) 8/14/94
+ * $FreeBSD$
+ */
+
+#ifndef _FTS_H_
+#define _FTS_H_
+
+typedef struct {
+ struct _ftsent *fts_cur; /* current node */
+ struct _ftsent *fts_child; /* linked list of children */
+ struct _ftsent **fts_array; /* sort array */
+ dev_t fts_dev; /* starting device # */
+ char *fts_path; /* path for this descent */
+ int fts_rfd; /* fd for root */
+ int fts_pathlen; /* sizeof(path) */
+ int fts_nitems; /* elements in the sort array */
+ int (*fts_compar) /* compare function */
+ (const struct _ftsent * const *, const struct _ftsent * const *);
+
+#define FTS_COMFOLLOW 0x001 /* follow command line symlinks */
+#define FTS_LOGICAL 0x002 /* logical walk */
+#define FTS_NOCHDIR 0x004 /* don't change directories */
+#define FTS_NOSTAT 0x008 /* don't get stat info */
+#define FTS_PHYSICAL 0x010 /* physical walk */
+#define FTS_SEEDOT 0x020 /* return dot and dot-dot */
+#define FTS_XDEV 0x040 /* don't cross devices */
+#define FTS_WHITEOUT 0x080 /* return whiteout information */
+#define FTS_OPTIONMASK 0x0ff /* valid user option mask */
+
+#define FTS_NAMEONLY 0x100 /* (private) child names only */
+#define FTS_STOP 0x200 /* (private) unrecoverable error */
+ int fts_options; /* fts_open options, global flags */
+ void *fts_clientptr; /* thunk for sort function */
+} FTS;
+
+typedef struct _ftsent {
+ struct _ftsent *fts_cycle; /* cycle node */
+ struct _ftsent *fts_parent; /* parent directory */
+ struct _ftsent *fts_link; /* next file in directory */
+ union {
+ struct {
+ long __fts_number; /* local numeric value */
+ void *__fts_pointer; /* local address value */
+ } __struct_ftsent;
+ int64_t __fts_bignum;
+ } __union_ftsent;
+#define fts_number __union_ftsent.__struct_ftsent.__fts_number
+#define fts_pointer __union_ftsent.__struct_ftsent.__fts_pointer
+#define fts_bignum __union_ftsent.__fts_bignum
+ char *fts_accpath; /* access path */
+ char *fts_path; /* root path */
+ int fts_errno; /* errno for this node */
+ int fts_symfd; /* fd for symlink */
+ u_short fts_pathlen; /* strlen(fts_path) */
+ u_short fts_namelen; /* strlen(fts_name) */
+
+ ino_t fts_ino; /* inode */
+ dev_t fts_dev; /* device */
+ nlink_t fts_nlink; /* link count */
+
+#define FTS_ROOTPARENTLEVEL -1
+#define FTS_ROOTLEVEL 0
+ short fts_level; /* depth (-1 to N) */
+
+#define FTS_D 1 /* preorder directory */
+#define FTS_DC 2 /* directory that causes cycles */
+#define FTS_DEFAULT 3 /* none of the above */
+#define FTS_DNR 4 /* unreadable directory */
+#define FTS_DOT 5 /* dot or dot-dot */
+#define FTS_DP 6 /* postorder directory */
+#define FTS_ERR 7 /* error; errno is set */
+#define FTS_F 8 /* regular file */
+#define FTS_INIT 9 /* initialized only */
+#define FTS_NS 10 /* stat(2) failed */
+#define FTS_NSOK 11 /* no stat(2) requested */
+#define FTS_SL 12 /* symbolic link */
+#define FTS_SLNONE 13 /* symbolic link without target */
+#define FTS_W 14 /* whiteout object */
+ u_short fts_info; /* user flags for FTSENT structure */
+
+#define FTS_DONTCHDIR 0x01 /* don't chdir .. to the parent */
+#define FTS_SYMFOLLOW 0x02 /* followed a symlink to get here */
+#define FTS_ISW 0x04 /* this is a whiteout object */
+ u_short fts_flags; /* private flags for FTSENT structure */
+
+#define FTS_AGAIN 1 /* read node again */
+#define FTS_FOLLOW 2 /* follow symbolic link */
+#define FTS_NOINSTR 3 /* no instructions */
+#define FTS_SKIP 4 /* discard node */
+ u_short fts_instr; /* fts_set() instructions */
+
+ struct stat *fts_statp; /* stat(2) information */
+ char *fts_name; /* file name */
+ FTS *fts_fts; /* back pointer to main FTS */
+} FTSENT;
+
+#define fts_get_clientptr(fts) ((fts)->fts_clientptr)
+#define fts_get_stream(ftsent) ((ftsent)->fts_fts)
+
+#endif /* !_FTS_H_ */
diff --git a/lib/libc/gen/fts.3 b/lib/libc/gen/fts.3
new file mode 100644
index 000000000000..2464d4102d81
--- /dev/null
+++ b/lib/libc/gen/fts.3
@@ -0,0 +1,803 @@
+.\" Copyright (c) 1989, 1991, 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)fts.3 8.5 (Berkeley) 4/16/94
+.\" $FreeBSD$
+.\"
+.Dd January 12, 2014
+.Dt FTS 3
+.Os
+.Sh NAME
+.Nm fts
+.Nd traverse a file hierarchy
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In fts.h
+.Ft FTS *
+.Fn fts_open "char * const *path_argv" "int options" "int (*compar)(const FTSENT * const *, const FTSENT * const *)"
+.Ft FTSENT *
+.Fn fts_read "FTS *ftsp"
+.Ft FTSENT *
+.Fn fts_children "FTS *ftsp" "int options"
+.Ft int
+.Fn fts_set "FTS *ftsp" "FTSENT *f" "int options"
+.Ft void
+.Fn fts_set_clientptr "FTS *ftsp" "void *clientdata"
+.Ft void *
+.Fn fts_get_clientptr "FTS *ftsp"
+.Ft FTS *
+.Fn fts_get_stream "FTSENT *f"
+.Ft int
+.Fn fts_close "FTS *ftsp"
+.Sh DESCRIPTION
+The
+.Nm
+functions are provided for traversing
+.Ux
+file hierarchies.
+A simple overview is that the
+.Fn fts_open
+function returns a
+.Dq handle
+on a file hierarchy, which is then supplied to
+the other
+.Nm
+functions.
+The function
+.Fn fts_read
+returns a pointer to a structure describing one of the files in the file
+hierarchy.
+The function
+.Fn fts_children
+returns a pointer to a linked list of structures, each of which describes
+one of the files contained in a directory in the hierarchy.
+In general, directories are visited two distinguishable times; in pre-order
+(before any of their descendants are visited) and in post-order (after all
+of their descendants have been visited).
+Files are visited once.
+It is possible to walk the hierarchy
+.Dq logically
+(ignoring symbolic links)
+or physically (visiting symbolic links), order the walk of the hierarchy or
+prune and/or re-visit portions of the hierarchy.
+.Pp
+Two structures are defined (and typedef'd) in the include file
+.In fts.h .
+The first is
+.Vt FTS ,
+the structure that represents the file hierarchy itself.
+The second is
+.Vt FTSENT ,
+the structure that represents a file in the file
+hierarchy.
+Normally, an
+.Vt FTSENT
+structure is returned for every file in the file
+hierarchy.
+In this manual page,
+.Dq file
+and
+.Dq Vt FTSENT No structure
+are generally
+interchangeable.
+.Pp
+The
+.Vt FTS
+structure contains space for a single pointer, which may be used to
+store application data or per-hierarchy state.
+The
+.Fn fts_set_clientptr
+and
+.Fn fts_get_clientptr
+functions may be used to set and retrieve this pointer.
+This is likely to be useful only when accessed from the sort
+comparison function, which can determine the original
+.Vt FTS
+stream of its arguments using the
+.Fn fts_get_stream
+function.
+The two
+.Li get
+functions are also available as macros of the same name.
+.Pp
+The
+.Vt FTSENT
+structure contains at least the following fields, which are
+described in greater detail below:
+.Bd -literal
+typedef struct _ftsent {
+ int fts_info; /* status for FTSENT structure */
+ char *fts_accpath; /* access path */
+ char *fts_path; /* root path */
+ size_t fts_pathlen; /* strlen(fts_path) */
+ char *fts_name; /* file name */
+ size_t fts_namelen; /* strlen(fts_name) */
+ long fts_level; /* depth (\-1 to N) */
+ int fts_errno; /* file errno */
+ long long fts_number; /* local numeric value */
+ void *fts_pointer; /* local address value */
+ struct ftsent *fts_parent; /* parent directory */
+ struct ftsent *fts_link; /* next file structure */
+ struct ftsent *fts_cycle; /* cycle structure */
+ struct stat *fts_statp; /* stat(2) information */
+} FTSENT;
+.Ed
+.Pp
+These fields are defined as follows:
+.Bl -tag -width "fts_namelen"
+.It Fa fts_info
+One of the following values describing the returned
+.Vt FTSENT
+structure and
+the file it represents.
+With the exception of directories without errors
+.Pq Dv FTS_D ,
+all of these
+entries are terminal, that is, they will not be revisited, nor will any
+of their descendants be visited.
+.Bl -tag -width FTS_DEFAULT
+.It Dv FTS_D
+A directory being visited in pre-order.
+.It Dv FTS_DC
+A directory that causes a cycle in the tree.
+(The
+.Fa fts_cycle
+field of the
+.Vt FTSENT
+structure will be filled in as well.)
+.It Dv FTS_DEFAULT
+Any
+.Vt FTSENT
+structure that represents a file type not explicitly described
+by one of the other
+.Fa fts_info
+values.
+.It Dv FTS_DNR
+A directory which cannot be read.
+This is an error return, and the
+.Fa fts_errno
+field will be set to indicate what caused the error.
+.It Dv FTS_DOT
+A file named
+.Ql .\&
+or
+.Ql ..\&
+which was not specified as a file name to
+.Fn fts_open
+(see
+.Dv FTS_SEEDOT ) .
+.It Dv FTS_DP
+A directory being visited in post-order.
+The contents of the
+.Vt FTSENT
+structure will be unchanged from when
+the directory was visited in pre-order, except for the
+.Fa fts_info
+field.
+.It Dv FTS_ERR
+This is an error return, and the
+.Fa fts_errno
+field will be set to indicate what caused the error.
+.It Dv FTS_F
+A regular file.
+.It Dv FTS_NS
+A file for which no
+.Xr stat 2
+information was available.
+The contents of the
+.Fa fts_statp
+field are undefined.
+This is an error return, and the
+.Fa fts_errno
+field will be set to indicate what caused the error.
+.It Dv FTS_NSOK
+A file for which no
+.Xr stat 2
+information was requested.
+The contents of the
+.Fa fts_statp
+field are undefined.
+.It Dv FTS_SL
+A symbolic link.
+.It Dv FTS_SLNONE
+A symbolic link with a non-existent target.
+The contents of the
+.Fa fts_statp
+field reference the file characteristic information for the symbolic link
+itself.
+.El
+.It Fa fts_accpath
+A path for accessing the file from the current directory.
+.It Fa fts_path
+The path for the file relative to the root of the traversal.
+This path contains the path specified to
+.Fn fts_open
+as a prefix.
+.It Fa fts_pathlen
+The length of the string referenced by
+.Fa fts_path .
+.It Fa fts_name
+The name of the file.
+.It Fa fts_namelen
+The length of the string referenced by
+.Fa fts_name .
+.It Fa fts_level
+The depth of the traversal, numbered from \-1 to N, where this file
+was found.
+The
+.Vt FTSENT
+structure representing the parent of the starting point (or root)
+of the traversal is numbered
+.Dv FTS_ROOTPARENTLEVEL
+(\-1), and the
+.Vt FTSENT
+structure for the root
+itself is numbered
+.Dv FTS_ROOTLEVEL
+(0).
+.It Fa fts_errno
+Upon return of a
+.Vt FTSENT
+structure from the
+.Fn fts_children
+or
+.Fn fts_read
+functions, with its
+.Fa fts_info
+field set to
+.Dv FTS_DNR ,
+.Dv FTS_ERR
+or
+.Dv FTS_NS ,
+the
+.Fa fts_errno
+field contains the value of the external variable
+.Va errno
+specifying the cause of the error.
+Otherwise, the contents of the
+.Fa fts_errno
+field are undefined.
+.It Fa fts_number
+This field is provided for the use of the application program and is
+not modified by the
+.Nm
+functions.
+It is initialized to 0.
+.It Fa fts_pointer
+This field is provided for the use of the application program and is
+not modified by the
+.Nm
+functions.
+It is initialized to
+.Dv NULL .
+.It Fa fts_parent
+A pointer to the
+.Vt FTSENT
+structure referencing the file in the hierarchy
+immediately above the current file, i.e., the directory of which this
+file is a member.
+A parent structure for the initial entry point is provided as well,
+however, only the
+.Fa fts_level ,
+.Fa fts_number
+and
+.Fa fts_pointer
+fields are guaranteed to be initialized.
+.It Fa fts_link
+Upon return from the
+.Fn fts_children
+function, the
+.Fa fts_link
+field points to the next structure in the NULL-terminated linked list of
+directory members.
+Otherwise, the contents of the
+.Fa fts_link
+field are undefined.
+.It Fa fts_cycle
+If a directory causes a cycle in the hierarchy (see
+.Dv FTS_DC ) ,
+either because
+of a hard link between two directories, or a symbolic link pointing to a
+directory, the
+.Fa fts_cycle
+field of the structure will point to the
+.Vt FTSENT
+structure in the hierarchy that references the same file as the current
+.Vt FTSENT
+structure.
+Otherwise, the contents of the
+.Fa fts_cycle
+field are undefined.
+.It Fa fts_statp
+A pointer to
+.Xr stat 2
+information for the file.
+.El
+.Pp
+A single buffer is used for all of the paths of all of the files in the
+file hierarchy.
+Therefore, the
+.Fa fts_path
+and
+.Fa fts_accpath
+fields are guaranteed to be
+.Dv NUL Ns -terminated
+.Em only
+for the file most recently returned by
+.Fn fts_read .
+To use these fields to reference any files represented by other
+.Vt FTSENT
+structures will require that the path buffer be modified using the
+information contained in that
+.Vt FTSENT
+structure's
+.Fa fts_pathlen
+field.
+Any such modifications should be undone before further calls to
+.Fn fts_read
+are attempted.
+The
+.Fa fts_name
+field is always
+.Dv NUL Ns -terminated .
+.Sh FTS_OPEN
+The
+.Fn fts_open
+function takes a pointer to an array of character pointers naming one
+or more paths which make up a logical file hierarchy to be traversed.
+The array must be terminated by a
+.Dv NULL
+pointer.
+.Pp
+There are
+a number of options, at least one of which (either
+.Dv FTS_LOGICAL
+or
+.Dv FTS_PHYSICAL )
+must be specified.
+The options are selected by
+.Em or Ns 'ing
+the following values:
+.Bl -tag -width "FTS_PHYSICAL"
+.It Dv FTS_COMFOLLOW
+This option causes any symbolic link specified as a root path to be
+followed immediately whether or not
+.Dv FTS_LOGICAL
+is also specified.
+.It Dv FTS_LOGICAL
+This option causes the
+.Nm
+routines to return
+.Vt FTSENT
+structures for the targets of symbolic links
+instead of the symbolic links themselves.
+If this option is set, the only symbolic links for which
+.Vt FTSENT
+structures
+are returned to the application are those referencing non-existent files.
+Either
+.Dv FTS_LOGICAL
+or
+.Dv FTS_PHYSICAL
+.Em must
+be provided to the
+.Fn fts_open
+function.
+.It Dv FTS_NOCHDIR
+To allow descending to arbitrary depths
+(independent of
+.Brq Dv PATH_MAX )
+and improve performance, the
+.Nm
+functions change directories as they walk the file hierarchy.
+This has the side-effect that an application cannot rely on being
+in any particular directory during the traversal.
+The
+.Dv FTS_NOCHDIR
+option turns off this feature, and the
+.Nm
+functions will not change the current directory.
+Note that applications should not themselves change their current directory
+and try to access files unless
+.Dv FTS_NOCHDIR
+is specified and absolute
+pathnames were provided as arguments to
+.Fn fts_open .
+.It Dv FTS_NOSTAT
+By default, returned
+.Vt FTSENT
+structures reference file characteristic information (the
+.Fa statp
+field) for each file visited.
+This option relaxes that requirement as a performance optimization,
+allowing the
+.Nm
+functions to set the
+.Fa fts_info
+field to
+.Dv FTS_NSOK
+and leave the contents of the
+.Fa statp
+field undefined.
+.It Dv FTS_PHYSICAL
+This option causes the
+.Nm
+routines to return
+.Vt FTSENT
+structures for symbolic links themselves instead
+of the target files they point to.
+If this option is set,
+.Vt FTSENT
+structures for all symbolic links in the
+hierarchy are returned to the application.
+Either
+.Dv FTS_LOGICAL
+or
+.Dv FTS_PHYSICAL
+.Em must
+be provided to the
+.Fn fts_open
+function.
+.It Dv FTS_SEEDOT
+By default, unless they are specified as path arguments to
+.Fn fts_open ,
+any files named
+.Ql .\&
+or
+.Ql ..\&
+encountered in the file hierarchy are ignored.
+This option causes the
+.Nm
+routines to return
+.Vt FTSENT
+structures for them.
+.It Dv FTS_XDEV
+This option prevents
+.Nm
+from descending into directories that have a different device number
+than the file from which the descent began.
+.El
+.Pp
+The argument
+.Fn compar
+specifies a user-defined function which may be used to order the traversal
+of the hierarchy.
+It
+takes two pointers to pointers to
+.Vt FTSENT
+structures as arguments and
+should return a negative value, zero, or a positive value to indicate
+if the file referenced by its first argument comes before, in any order
+with respect to, or after, the file referenced by its second argument.
+The
+.Fa fts_accpath ,
+.Fa fts_path
+and
+.Fa fts_pathlen
+fields of the
+.Vt FTSENT
+structures may
+.Em never
+be used in this comparison.
+If the
+.Fa fts_info
+field is set to
+.Dv FTS_NS
+or
+.Dv FTS_NSOK ,
+the
+.Fa fts_statp
+field may not either.
+If the
+.Fn compar
+argument is
+.Dv NULL ,
+the directory traversal order is in the order listed in
+.Fa path_argv
+for the root paths, and in the order listed in the directory for
+everything else.
+.Sh FTS_READ
+The
+.Fn fts_read
+function returns a pointer to an
+.Vt FTSENT
+structure describing a file in
+the hierarchy.
+Directories (that are readable and do not cause cycles) are visited at
+least twice, once in pre-order and once in post-order.
+All other files are visited at least once.
+(Hard links between directories that do not cause cycles or symbolic
+links to symbolic links may cause files to be visited more than once,
+or directories more than twice.)
+.Pp
+If all the members of the hierarchy have been returned,
+.Fn fts_read
+returns
+.Dv NULL
+and sets the external variable
+.Va errno
+to 0.
+If an error unrelated to a file in the hierarchy occurs,
+.Fn fts_read
+returns
+.Dv NULL
+and sets
+.Va errno
+appropriately.
+If an error related to a returned file occurs, a pointer to an
+.Vt FTSENT
+structure is returned, and
+.Va errno
+may or may not have been set (see
+.Fa fts_info ) .
+.Pp
+The
+.Vt FTSENT
+structures returned by
+.Fn fts_read
+may be overwritten after a call to
+.Fn fts_close
+on the same file hierarchy stream, or, after a call to
+.Fn fts_read
+on the same file hierarchy stream unless they represent a file of type
+directory, in which case they will not be overwritten until after a call to
+.Fn fts_read
+after the
+.Vt FTSENT
+structure has been returned by the function
+.Fn fts_read
+in post-order.
+.Sh FTS_CHILDREN
+The
+.Fn fts_children
+function returns a pointer to an
+.Vt FTSENT
+structure describing the first entry in a NULL-terminated linked list of
+the files in the directory represented by the
+.Vt FTSENT
+structure most recently returned by
+.Fn fts_read .
+The list is linked through the
+.Fa fts_link
+field of the
+.Vt FTSENT
+structure, and is ordered by the user-specified comparison function, if any.
+Repeated calls to
+.Fn fts_children
+will recreate this linked list.
+.Pp
+As a special case, if
+.Fn fts_read
+has not yet been called for a hierarchy,
+.Fn fts_children
+will return a pointer to the files in the logical directory specified to
+.Fn fts_open ,
+i.e., the arguments specified to
+.Fn fts_open .
+Otherwise, if the
+.Vt FTSENT
+structure most recently returned by
+.Fn fts_read
+is not a directory being visited in pre-order,
+or the directory does not contain any files,
+.Fn fts_children
+returns
+.Dv NULL
+and sets
+.Va errno
+to zero.
+If an error occurs,
+.Fn fts_children
+returns
+.Dv NULL
+and sets
+.Va errno
+appropriately.
+.Pp
+The
+.Vt FTSENT
+structures returned by
+.Fn fts_children
+may be overwritten after a call to
+.Fn fts_children ,
+.Fn fts_close
+or
+.Fn fts_read
+on the same file hierarchy stream.
+.Pp
+.Em Option
+may be set to the following value:
+.Bl -tag -width FTS_NAMEONLY
+.It Dv FTS_NAMEONLY
+Only the names of the files are needed.
+The contents of all the fields in the returned linked list of structures
+are undefined with the exception of the
+.Fa fts_name
+and
+.Fa fts_namelen
+fields.
+.El
+.Sh FTS_SET
+The function
+.Fn fts_set
+allows the user application to determine further processing for the
+file
+.Fa f
+of the stream
+.Fa ftsp .
+The
+.Fn fts_set
+function
+returns 0 on success, and \-1 if an error occurs.
+.Em Option
+must be set to one of the following values:
+.Bl -tag -width FTS_PHYSICAL
+.It Dv FTS_AGAIN
+Re-visit the file; any file type may be re-visited.
+The next call to
+.Fn fts_read
+will return the referenced file.
+The
+.Fa fts_stat
+and
+.Fa fts_info
+fields of the structure will be reinitialized at that time,
+but no other fields will have been changed.
+This option is meaningful only for the most recently returned
+file from
+.Fn fts_read .
+Normal use is for post-order directory visits, where it causes the
+directory to be re-visited (in both pre and post-order) as well as all
+of its descendants.
+.It Dv FTS_FOLLOW
+The referenced file must be a symbolic link.
+If the referenced file is the one most recently returned by
+.Fn fts_read ,
+the next call to
+.Fn fts_read
+returns the file with the
+.Fa fts_info
+and
+.Fa fts_statp
+fields reinitialized to reflect the target of the symbolic link instead
+of the symbolic link itself.
+If the file is one of those most recently returned by
+.Fn fts_children ,
+the
+.Fa fts_info
+and
+.Fa fts_statp
+fields of the structure, when returned by
+.Fn fts_read ,
+will reflect the target of the symbolic link instead of the symbolic link
+itself.
+In either case, if the target of the symbolic link does not exist the
+fields of the returned structure will be unchanged and the
+.Fa fts_info
+field will be set to
+.Dv FTS_SLNONE .
+.Pp
+If the target of the link is a directory, the pre-order return, followed
+by the return of all of its descendants, followed by a post-order return,
+is done.
+.It Dv FTS_SKIP
+No descendants of this file are visited.
+The file may be one of those most recently returned by either
+.Fn fts_children
+or
+.Fn fts_read .
+.El
+.Sh FTS_CLOSE
+The
+.Fn fts_close
+function closes a file hierarchy stream
+.Fa ftsp
+and restores the current directory to the directory from which
+.Fn fts_open
+was called to open
+.Fa ftsp .
+The
+.Fn fts_close
+function
+returns 0 on success, and \-1 if an error occurs.
+.Sh ERRORS
+The function
+.Fn fts_open
+may fail and set
+.Va errno
+for any of the errors specified for the library functions
+.Xr open 2
+and
+.Xr malloc 3 .
+.Pp
+The function
+.Fn fts_close
+may fail and set
+.Va errno
+for any of the errors specified for the library functions
+.Xr chdir 2
+and
+.Xr close 2 .
+.Pp
+The functions
+.Fn fts_read
+and
+.Fn fts_children
+may fail and set
+.Va errno
+for any of the errors specified for the library functions
+.Xr chdir 2 ,
+.Xr malloc 3 ,
+.Xr opendir 3 ,
+.Xr readdir 3
+and
+.Xr stat 2 .
+.Pp
+In addition,
+.Fn fts_children ,
+.Fn fts_open
+and
+.Fn fts_set
+may fail and set
+.Va errno
+as follows:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The options were invalid, or the list were empty.
+.El
+.Sh SEE ALSO
+.Xr find 1 ,
+.Xr chdir 2 ,
+.Xr stat 2 ,
+.Xr ftw 3 ,
+.Xr qsort 3
+.Sh HISTORY
+The
+.Nm
+interface was first introduced in
+.Bx 4.4 .
+The
+.Fn fts_get_clientptr ,
+.Fn fts_get_stream ,
+and
+.Fn fts_set_clientptr
+functions were introduced in
+.Fx 5.0 ,
+principally to provide for alternative interfaces to the
+.Nm
+functionality using different data structures.
+.Sh BUGS
+The
+.Fn fts_open
+function will automatically set the
+.Dv FTS_NOCHDIR
+option if the
+.Dv FTS_LOGICAL
+option is provided, or if it cannot
+.Xr open 2
+the current directory.
diff --git a/lib/libc/gen/fts.c b/lib/libc/gen/fts.c
new file mode 100644
index 000000000000..8f3dd6da27db
--- /dev/null
+++ b/lib/libc/gen/fts.c
@@ -0,0 +1,1182 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $OpenBSD: fts.c,v 1.22 1999/10/03 19:22:22 millert Exp $
+ */
+
+#if 0
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)fts.c 8.6 (Berkeley) 8/14/94";
+#endif /* LIBC_SCCS and not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <fts.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+#include "gen-private.h"
+
+static FTSENT *fts_alloc(FTS *, char *, size_t);
+static FTSENT *fts_build(FTS *, int);
+static void fts_lfree(FTSENT *);
+static void fts_load(FTS *, FTSENT *);
+static size_t fts_maxarglen(char * const *);
+static void fts_padjust(FTS *, FTSENT *);
+static int fts_palloc(FTS *, size_t);
+static FTSENT *fts_sort(FTS *, FTSENT *, size_t);
+static int fts_stat(FTS *, FTSENT *, int, int);
+static int fts_safe_changedir(FTS *, FTSENT *, int, char *);
+static int fts_ufslinks(FTS *, const FTSENT *);
+
+#define ISDOT(a) (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2])))
+
+#define CLR(opt) (sp->fts_options &= ~(opt))
+#define ISSET(opt) (sp->fts_options & (opt))
+#define SET(opt) (sp->fts_options |= (opt))
+
+#define FCHDIR(sp, fd) (!ISSET(FTS_NOCHDIR) && fchdir(fd))
+
+/* fts_build flags */
+#define BCHILD 1 /* fts_children */
+#define BNAMES 2 /* fts_children, names only */
+#define BREAD 3 /* fts_read */
+
+/*
+ * Internal representation of an FTS, including extra implementation
+ * details. The FTS returned from fts_open points to this structure's
+ * ftsp_fts member (and can be cast to an _fts_private as required)
+ */
+struct _fts_private {
+ FTS ftsp_fts;
+ struct statfs ftsp_statfs;
+ dev_t ftsp_dev;
+ int ftsp_linksreliable;
+};
+
+/*
+ * The "FTS_NOSTAT" option can avoid a lot of calls to stat(2) if it
+ * knows that a directory could not possibly have subdirectories. This
+ * is decided by looking at the link count: a subdirectory would
+ * increment its parent's link count by virtue of its own ".." entry.
+ * This assumption only holds for UFS-like filesystems that implement
+ * links and directories this way, so we must punt for others.
+ */
+
+static const char *ufslike_filesystems[] = {
+ "ufs",
+ "zfs",
+ "nfs",
+ "ext2fs",
+ 0
+};
+
+FTS *
+fts_open(char * const *argv, int options,
+ int (*compar)(const FTSENT * const *, const FTSENT * const *))
+{
+ struct _fts_private *priv;
+ FTS *sp;
+ FTSENT *p, *root;
+ FTSENT *parent, *tmp;
+ size_t len, nitems;
+
+ /* Options check. */
+ if (options & ~FTS_OPTIONMASK) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ /* fts_open() requires at least one path */
+ if (*argv == NULL) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ /* Allocate/initialize the stream. */
+ if ((priv = calloc(1, sizeof(*priv))) == NULL)
+ return (NULL);
+ sp = &priv->ftsp_fts;
+ sp->fts_compar = compar;
+ sp->fts_options = options;
+
+ /* Shush, GCC. */
+ tmp = NULL;
+
+ /* Logical walks turn on NOCHDIR; symbolic links are too hard. */
+ if (ISSET(FTS_LOGICAL))
+ SET(FTS_NOCHDIR);
+
+ /*
+ * Start out with 1K of path space, and enough, in any case,
+ * to hold the user's paths.
+ */
+ if (fts_palloc(sp, MAX(fts_maxarglen(argv), MAXPATHLEN)))
+ goto mem1;
+
+ /* Allocate/initialize root's parent. */
+ if ((parent = fts_alloc(sp, "", 0)) == NULL)
+ goto mem2;
+ parent->fts_level = FTS_ROOTPARENTLEVEL;
+
+ /* Allocate/initialize root(s). */
+ for (root = NULL, nitems = 0; *argv != NULL; ++argv, ++nitems) {
+ len = strlen(*argv);
+
+ p = fts_alloc(sp, *argv, len);
+ p->fts_level = FTS_ROOTLEVEL;
+ p->fts_parent = parent;
+ p->fts_accpath = p->fts_name;
+ p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW), -1);
+
+ /* Command-line "." and ".." are real directories. */
+ if (p->fts_info == FTS_DOT)
+ p->fts_info = FTS_D;
+
+ /*
+ * If comparison routine supplied, traverse in sorted
+ * order; otherwise traverse in the order specified.
+ */
+ if (compar) {
+ p->fts_link = root;
+ root = p;
+ } else {
+ p->fts_link = NULL;
+ if (root == NULL)
+ tmp = root = p;
+ else {
+ tmp->fts_link = p;
+ tmp = p;
+ }
+ }
+ }
+ if (compar && nitems > 1)
+ root = fts_sort(sp, root, nitems);
+
+ /*
+ * Allocate a dummy pointer and make fts_read think that we've just
+ * finished the node before the root(s); set p->fts_info to FTS_INIT
+ * so that everything about the "current" node is ignored.
+ */
+ if ((sp->fts_cur = fts_alloc(sp, "", 0)) == NULL)
+ goto mem3;
+ sp->fts_cur->fts_link = root;
+ sp->fts_cur->fts_info = FTS_INIT;
+
+ /*
+ * If using chdir(2), grab a file descriptor pointing to dot to ensure
+ * that we can get back here; this could be avoided for some paths,
+ * but almost certainly not worth the effort. Slashes, symbolic links,
+ * and ".." are all fairly nasty problems. Note, if we can't get the
+ * descriptor we run anyway, just more slowly.
+ */
+ if (!ISSET(FTS_NOCHDIR) &&
+ (sp->fts_rfd = _open(".", O_RDONLY | O_CLOEXEC, 0)) < 0)
+ SET(FTS_NOCHDIR);
+
+ return (sp);
+
+mem3: fts_lfree(root);
+ free(parent);
+mem2: free(sp->fts_path);
+mem1: free(sp);
+ return (NULL);
+}
+
+static void
+fts_load(FTS *sp, FTSENT *p)
+{
+ size_t len;
+ char *cp;
+
+ /*
+ * Load the stream structure for the next traversal. Since we don't
+ * actually enter the directory until after the preorder visit, set
+ * the fts_accpath field specially so the chdir gets done to the right
+ * place and the user can access the first node. From fts_open it's
+ * known that the path will fit.
+ */
+ len = p->fts_pathlen = p->fts_namelen;
+ memmove(sp->fts_path, p->fts_name, len + 1);
+ if ((cp = strrchr(p->fts_name, '/')) && (cp != p->fts_name || cp[1])) {
+ len = strlen(++cp);
+ memmove(p->fts_name, cp, len + 1);
+ p->fts_namelen = len;
+ }
+ p->fts_accpath = p->fts_path = sp->fts_path;
+ sp->fts_dev = p->fts_dev;
+}
+
+int
+fts_close(FTS *sp)
+{
+ FTSENT *freep, *p;
+ int saved_errno;
+
+ /*
+ * This still works if we haven't read anything -- the dummy structure
+ * points to the root list, so we step through to the end of the root
+ * list which has a valid parent pointer.
+ */
+ if (sp->fts_cur) {
+ for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) {
+ freep = p;
+ p = p->fts_link != NULL ? p->fts_link : p->fts_parent;
+ free(freep);
+ }
+ free(p);
+ }
+
+ /* Free up child linked list, sort array, path buffer. */
+ if (sp->fts_child)
+ fts_lfree(sp->fts_child);
+ if (sp->fts_array)
+ free(sp->fts_array);
+ free(sp->fts_path);
+
+ /* Return to original directory, save errno if necessary. */
+ if (!ISSET(FTS_NOCHDIR)) {
+ saved_errno = fchdir(sp->fts_rfd) ? errno : 0;
+ (void)_close(sp->fts_rfd);
+
+ /* Set errno and return. */
+ if (saved_errno != 0) {
+ /* Free up the stream pointer. */
+ free(sp);
+ errno = saved_errno;
+ return (-1);
+ }
+ }
+
+ /* Free up the stream pointer. */
+ free(sp);
+ return (0);
+}
+
+/*
+ * Special case of "/" at the end of the path so that slashes aren't
+ * appended which would cause paths to be written as "....//foo".
+ */
+#define NAPPEND(p) \
+ (p->fts_path[p->fts_pathlen - 1] == '/' \
+ ? p->fts_pathlen - 1 : p->fts_pathlen)
+
+FTSENT *
+fts_read(FTS *sp)
+{
+ FTSENT *p, *tmp;
+ int instr;
+ char *t;
+ int saved_errno;
+
+ /* If finished or unrecoverable error, return NULL. */
+ if (sp->fts_cur == NULL || ISSET(FTS_STOP))
+ return (NULL);
+
+ /* Set current node pointer. */
+ p = sp->fts_cur;
+
+ /* Save and zero out user instructions. */
+ instr = p->fts_instr;
+ p->fts_instr = FTS_NOINSTR;
+
+ /* Any type of file may be re-visited; re-stat and re-turn. */
+ if (instr == FTS_AGAIN) {
+ p->fts_info = fts_stat(sp, p, 0, -1);
+ return (p);
+ }
+
+ /*
+ * Following a symlink -- SLNONE test allows application to see
+ * SLNONE and recover. If indirecting through a symlink, have
+ * keep a pointer to current location. If unable to get that
+ * pointer, follow fails.
+ */
+ if (instr == FTS_FOLLOW &&
+ (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) {
+ p->fts_info = fts_stat(sp, p, 1, -1);
+ if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
+ if ((p->fts_symfd = _open(".", O_RDONLY | O_CLOEXEC,
+ 0)) < 0) {
+ p->fts_errno = errno;
+ p->fts_info = FTS_ERR;
+ } else
+ p->fts_flags |= FTS_SYMFOLLOW;
+ }
+ return (p);
+ }
+
+ /* Directory in pre-order. */
+ if (p->fts_info == FTS_D) {
+ /* If skipped or crossed mount point, do post-order visit. */
+ if (instr == FTS_SKIP ||
+ (ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev)) {
+ if (p->fts_flags & FTS_SYMFOLLOW)
+ (void)_close(p->fts_symfd);
+ if (sp->fts_child) {
+ fts_lfree(sp->fts_child);
+ sp->fts_child = NULL;
+ }
+ p->fts_info = FTS_DP;
+ return (p);
+ }
+
+ /* Rebuild if only read the names and now traversing. */
+ if (sp->fts_child != NULL && ISSET(FTS_NAMEONLY)) {
+ CLR(FTS_NAMEONLY);
+ fts_lfree(sp->fts_child);
+ sp->fts_child = NULL;
+ }
+
+ /*
+ * Cd to the subdirectory.
+ *
+ * If have already read and now fail to chdir, whack the list
+ * to make the names come out right, and set the parent errno
+ * so the application will eventually get an error condition.
+ * Set the FTS_DONTCHDIR flag so that when we logically change
+ * directories back to the parent we don't do a chdir.
+ *
+ * If haven't read do so. If the read fails, fts_build sets
+ * FTS_STOP or the fts_info field of the node.
+ */
+ if (sp->fts_child != NULL) {
+ if (fts_safe_changedir(sp, p, -1, p->fts_accpath)) {
+ p->fts_errno = errno;
+ p->fts_flags |= FTS_DONTCHDIR;
+ for (p = sp->fts_child; p != NULL;
+ p = p->fts_link)
+ p->fts_accpath =
+ p->fts_parent->fts_accpath;
+ }
+ } else if ((sp->fts_child = fts_build(sp, BREAD)) == NULL) {
+ if (ISSET(FTS_STOP))
+ return (NULL);
+ return (p);
+ }
+ p = sp->fts_child;
+ sp->fts_child = NULL;
+ goto name;
+ }
+
+ /* Move to the next node on this level. */
+next: tmp = p;
+ if ((p = p->fts_link) != NULL) {
+ /*
+ * If reached the top, return to the original directory (or
+ * the root of the tree), and load the paths for the next root.
+ */
+ if (p->fts_level == FTS_ROOTLEVEL) {
+ if (FCHDIR(sp, sp->fts_rfd)) {
+ SET(FTS_STOP);
+ return (NULL);
+ }
+ free(tmp);
+ fts_load(sp, p);
+ return (sp->fts_cur = p);
+ }
+
+ /*
+ * User may have called fts_set on the node. If skipped,
+ * ignore. If followed, get a file descriptor so we can
+ * get back if necessary.
+ */
+ if (p->fts_instr == FTS_SKIP) {
+ free(tmp);
+ goto next;
+ }
+ if (p->fts_instr == FTS_FOLLOW) {
+ p->fts_info = fts_stat(sp, p, 1, -1);
+ if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
+ if ((p->fts_symfd =
+ _open(".", O_RDONLY | O_CLOEXEC, 0)) < 0) {
+ p->fts_errno = errno;
+ p->fts_info = FTS_ERR;
+ } else
+ p->fts_flags |= FTS_SYMFOLLOW;
+ }
+ p->fts_instr = FTS_NOINSTR;
+ }
+
+ free(tmp);
+
+name: t = sp->fts_path + NAPPEND(p->fts_parent);
+ *t++ = '/';
+ memmove(t, p->fts_name, p->fts_namelen + 1);
+ return (sp->fts_cur = p);
+ }
+
+ /* Move up to the parent node. */
+ p = tmp->fts_parent;
+
+ if (p->fts_level == FTS_ROOTPARENTLEVEL) {
+ /*
+ * Done; free everything up and set errno to 0 so the user
+ * can distinguish between error and EOF.
+ */
+ free(tmp);
+ free(p);
+ errno = 0;
+ return (sp->fts_cur = NULL);
+ }
+
+ /* NUL terminate the pathname. */
+ sp->fts_path[p->fts_pathlen] = '\0';
+
+ /*
+ * Return to the parent directory. If at a root node or came through
+ * a symlink, go back through the file descriptor. Otherwise, cd up
+ * one directory.
+ */
+ if (p->fts_level == FTS_ROOTLEVEL) {
+ if (FCHDIR(sp, sp->fts_rfd)) {
+ SET(FTS_STOP);
+ return (NULL);
+ }
+ } else if (p->fts_flags & FTS_SYMFOLLOW) {
+ if (FCHDIR(sp, p->fts_symfd)) {
+ saved_errno = errno;
+ (void)_close(p->fts_symfd);
+ errno = saved_errno;
+ SET(FTS_STOP);
+ return (NULL);
+ }
+ (void)_close(p->fts_symfd);
+ } else if (!(p->fts_flags & FTS_DONTCHDIR) &&
+ fts_safe_changedir(sp, p->fts_parent, -1, "..")) {
+ SET(FTS_STOP);
+ return (NULL);
+ }
+ free(tmp);
+ p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP;
+ return (sp->fts_cur = p);
+}
+
+/*
+ * Fts_set takes the stream as an argument although it's not used in this
+ * implementation; it would be necessary if anyone wanted to add global
+ * semantics to fts using fts_set. An error return is allowed for similar
+ * reasons.
+ */
+/* ARGSUSED */
+int
+fts_set(FTS *sp, FTSENT *p, int instr)
+{
+ if (instr != 0 && instr != FTS_AGAIN && instr != FTS_FOLLOW &&
+ instr != FTS_NOINSTR && instr != FTS_SKIP) {
+ errno = EINVAL;
+ return (1);
+ }
+ p->fts_instr = instr;
+ return (0);
+}
+
+FTSENT *
+fts_children(FTS *sp, int instr)
+{
+ FTSENT *p;
+ int fd, rc, serrno;
+
+ if (instr != 0 && instr != FTS_NAMEONLY) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ /* Set current node pointer. */
+ p = sp->fts_cur;
+
+ /*
+ * Errno set to 0 so user can distinguish empty directory from
+ * an error.
+ */
+ errno = 0;
+
+ /* Fatal errors stop here. */
+ if (ISSET(FTS_STOP))
+ return (NULL);
+
+ /* Return logical hierarchy of user's arguments. */
+ if (p->fts_info == FTS_INIT)
+ return (p->fts_link);
+
+ /*
+ * If not a directory being visited in pre-order, stop here. Could
+ * allow FTS_DNR, assuming the user has fixed the problem, but the
+ * same effect is available with FTS_AGAIN.
+ */
+ if (p->fts_info != FTS_D /* && p->fts_info != FTS_DNR */)
+ return (NULL);
+
+ /* Free up any previous child list. */
+ if (sp->fts_child != NULL)
+ fts_lfree(sp->fts_child);
+
+ if (instr == FTS_NAMEONLY) {
+ SET(FTS_NAMEONLY);
+ instr = BNAMES;
+ } else
+ instr = BCHILD;
+
+ /*
+ * If using chdir on a relative path and called BEFORE fts_read does
+ * its chdir to the root of a traversal, we can lose -- we need to
+ * chdir into the subdirectory, and we don't know where the current
+ * directory is, so we can't get back so that the upcoming chdir by
+ * fts_read will work.
+ */
+ if (p->fts_level != FTS_ROOTLEVEL || p->fts_accpath[0] == '/' ||
+ ISSET(FTS_NOCHDIR))
+ return (sp->fts_child = fts_build(sp, instr));
+
+ if ((fd = _open(".", O_RDONLY | O_CLOEXEC, 0)) < 0)
+ return (NULL);
+ sp->fts_child = fts_build(sp, instr);
+ serrno = (sp->fts_child == NULL) ? errno : 0;
+ rc = fchdir(fd);
+ if (rc < 0 && serrno == 0)
+ serrno = errno;
+ (void)_close(fd);
+ errno = serrno;
+ if (rc < 0)
+ return (NULL);
+ return (sp->fts_child);
+}
+
+#ifndef fts_get_clientptr
+#error "fts_get_clientptr not defined"
+#endif
+
+void *
+(fts_get_clientptr)(FTS *sp)
+{
+
+ return (fts_get_clientptr(sp));
+}
+
+#ifndef fts_get_stream
+#error "fts_get_stream not defined"
+#endif
+
+FTS *
+(fts_get_stream)(FTSENT *p)
+{
+ return (fts_get_stream(p));
+}
+
+void
+fts_set_clientptr(FTS *sp, void *clientptr)
+{
+
+ sp->fts_clientptr = clientptr;
+}
+
+/*
+ * This is the tricky part -- do not casually change *anything* in here. The
+ * idea is to build the linked list of entries that are used by fts_children
+ * and fts_read. There are lots of special cases.
+ *
+ * The real slowdown in walking the tree is the stat calls. If FTS_NOSTAT is
+ * set and it's a physical walk (so that symbolic links can't be directories),
+ * we can do things quickly. First, if it's a 4.4BSD file system, the type
+ * of the file is in the directory entry. Otherwise, we assume that the number
+ * of subdirectories in a node is equal to the number of links to the parent.
+ * The former skips all stat calls. The latter skips stat calls in any leaf
+ * directories and for any files after the subdirectories in the directory have
+ * been found, cutting the stat calls by about 2/3.
+ */
+static FTSENT *
+fts_build(FTS *sp, int type)
+{
+ struct dirent *dp;
+ FTSENT *p, *head;
+ FTSENT *cur, *tail;
+ DIR *dirp;
+ void *oldaddr;
+ char *cp;
+ int cderrno, descend, oflag, saved_errno, nostat, doadjust;
+ long level;
+ long nlinks; /* has to be signed because -1 is a magic value */
+ size_t dnamlen, len, maxlen, nitems;
+
+ /* Set current node pointer. */
+ cur = sp->fts_cur;
+
+ /*
+ * Open the directory for reading. If this fails, we're done.
+ * If being called from fts_read, set the fts_info field.
+ */
+#ifdef FTS_WHITEOUT
+ if (ISSET(FTS_WHITEOUT))
+ oflag = DTF_NODUP | DTF_REWIND;
+ else
+ oflag = DTF_HIDEW | DTF_NODUP | DTF_REWIND;
+#else
+#define __opendir2(path, flag) opendir(path)
+#endif
+ if ((dirp = __opendir2(cur->fts_accpath, oflag)) == NULL) {
+ if (type == BREAD) {
+ cur->fts_info = FTS_DNR;
+ cur->fts_errno = errno;
+ }
+ return (NULL);
+ }
+
+ /*
+ * Nlinks is the number of possible entries of type directory in the
+ * directory if we're cheating on stat calls, 0 if we're not doing
+ * any stat calls at all, -1 if we're doing stats on everything.
+ */
+ if (type == BNAMES) {
+ nlinks = 0;
+ /* Be quiet about nostat, GCC. */
+ nostat = 0;
+ } else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL)) {
+ if (fts_ufslinks(sp, cur))
+ nlinks = cur->fts_nlink - (ISSET(FTS_SEEDOT) ? 0 : 2);
+ else
+ nlinks = -1;
+ nostat = 1;
+ } else {
+ nlinks = -1;
+ nostat = 0;
+ }
+
+#ifdef notdef
+ (void)printf("nlinks == %d (cur: %d)\n", nlinks, cur->fts_nlink);
+ (void)printf("NOSTAT %d PHYSICAL %d SEEDOT %d\n",
+ ISSET(FTS_NOSTAT), ISSET(FTS_PHYSICAL), ISSET(FTS_SEEDOT));
+#endif
+ /*
+ * If we're going to need to stat anything or we want to descend
+ * and stay in the directory, chdir. If this fails we keep going,
+ * but set a flag so we don't chdir after the post-order visit.
+ * We won't be able to stat anything, but we can still return the
+ * names themselves. Note, that since fts_read won't be able to
+ * chdir into the directory, it will have to return different path
+ * names than before, i.e. "a/b" instead of "b". Since the node
+ * has already been visited in pre-order, have to wait until the
+ * post-order visit to return the error. There is a special case
+ * here, if there was nothing to stat then it's not an error to
+ * not be able to stat. This is all fairly nasty. If a program
+ * needed sorted entries or stat information, they had better be
+ * checking FTS_NS on the returned nodes.
+ */
+ cderrno = 0;
+ if (nlinks || type == BREAD) {
+ if (fts_safe_changedir(sp, cur, _dirfd(dirp), NULL)) {
+ if (nlinks && type == BREAD)
+ cur->fts_errno = errno;
+ cur->fts_flags |= FTS_DONTCHDIR;
+ descend = 0;
+ cderrno = errno;
+ } else
+ descend = 1;
+ } else
+ descend = 0;
+
+ /*
+ * Figure out the max file name length that can be stored in the
+ * current path -- the inner loop allocates more path as necessary.
+ * We really wouldn't have to do the maxlen calculations here, we
+ * could do them in fts_read before returning the path, but it's a
+ * lot easier here since the length is part of the dirent structure.
+ *
+ * If not changing directories set a pointer so that can just append
+ * each new name into the path.
+ */
+ len = NAPPEND(cur);
+ if (ISSET(FTS_NOCHDIR)) {
+ cp = sp->fts_path + len;
+ *cp++ = '/';
+ } else {
+ /* GCC, you're too verbose. */
+ cp = NULL;
+ }
+ len++;
+ maxlen = sp->fts_pathlen - len;
+
+ level = cur->fts_level + 1;
+
+ /* Read the directory, attaching each entry to the `link' pointer. */
+ doadjust = 0;
+ for (head = tail = NULL, nitems = 0; dirp && (dp = readdir(dirp));) {
+ dnamlen = dp->d_namlen;
+ if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name))
+ continue;
+
+ if ((p = fts_alloc(sp, dp->d_name, dnamlen)) == NULL)
+ goto mem1;
+ if (dnamlen >= maxlen) { /* include space for NUL */
+ oldaddr = sp->fts_path;
+ if (fts_palloc(sp, dnamlen + len + 1)) {
+ /*
+ * No more memory for path or structures. Save
+ * errno, free up the current structure and the
+ * structures already allocated.
+ */
+mem1: saved_errno = errno;
+ if (p)
+ free(p);
+ fts_lfree(head);
+ (void)closedir(dirp);
+ cur->fts_info = FTS_ERR;
+ SET(FTS_STOP);
+ errno = saved_errno;
+ return (NULL);
+ }
+ /* Did realloc() change the pointer? */
+ if (oldaddr != sp->fts_path) {
+ doadjust = 1;
+ if (ISSET(FTS_NOCHDIR))
+ cp = sp->fts_path + len;
+ }
+ maxlen = sp->fts_pathlen - len;
+ }
+
+ p->fts_level = level;
+ p->fts_parent = sp->fts_cur;
+ p->fts_pathlen = len + dnamlen;
+
+#ifdef FTS_WHITEOUT
+ if (dp->d_type == DT_WHT)
+ p->fts_flags |= FTS_ISW;
+#endif
+
+ if (cderrno) {
+ if (nlinks) {
+ p->fts_info = FTS_NS;
+ p->fts_errno = cderrno;
+ } else
+ p->fts_info = FTS_NSOK;
+ p->fts_accpath = cur->fts_accpath;
+ } else if (nlinks == 0
+#ifdef DT_DIR
+ || (nostat &&
+ dp->d_type != DT_DIR && dp->d_type != DT_UNKNOWN)
+#endif
+ ) {
+ p->fts_accpath =
+ ISSET(FTS_NOCHDIR) ? p->fts_path : p->fts_name;
+ p->fts_info = FTS_NSOK;
+ } else {
+ /* Build a file name for fts_stat to stat. */
+ if (ISSET(FTS_NOCHDIR)) {
+ p->fts_accpath = p->fts_path;
+ memmove(cp, p->fts_name, p->fts_namelen + 1);
+ p->fts_info = fts_stat(sp, p, 0, _dirfd(dirp));
+ } else {
+ p->fts_accpath = p->fts_name;
+ p->fts_info = fts_stat(sp, p, 0, -1);
+ }
+
+ /* Decrement link count if applicable. */
+ if (nlinks > 0 && (p->fts_info == FTS_D ||
+ p->fts_info == FTS_DC || p->fts_info == FTS_DOT))
+ --nlinks;
+ }
+
+ /* We walk in directory order so "ls -f" doesn't get upset. */
+ p->fts_link = NULL;
+ if (head == NULL)
+ head = tail = p;
+ else {
+ tail->fts_link = p;
+ tail = p;
+ }
+ ++nitems;
+ }
+ if (dirp)
+ (void)closedir(dirp);
+
+ /*
+ * If realloc() changed the address of the path, adjust the
+ * addresses for the rest of the tree and the dir list.
+ */
+ if (doadjust)
+ fts_padjust(sp, head);
+
+ /*
+ * If not changing directories, reset the path back to original
+ * state.
+ */
+ if (ISSET(FTS_NOCHDIR))
+ sp->fts_path[cur->fts_pathlen] = '\0';
+
+ /*
+ * If descended after called from fts_children or after called from
+ * fts_read and nothing found, get back. At the root level we use
+ * the saved fd; if one of fts_open()'s arguments is a relative path
+ * to an empty directory, we wind up here with no other way back. If
+ * can't get back, we're done.
+ */
+ if (descend && (type == BCHILD || !nitems) &&
+ (cur->fts_level == FTS_ROOTLEVEL ?
+ FCHDIR(sp, sp->fts_rfd) :
+ fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) {
+ cur->fts_info = FTS_ERR;
+ SET(FTS_STOP);
+ return (NULL);
+ }
+
+ /* If didn't find anything, return NULL. */
+ if (!nitems) {
+ if (type == BREAD)
+ cur->fts_info = FTS_DP;
+ return (NULL);
+ }
+
+ /* Sort the entries. */
+ if (sp->fts_compar && nitems > 1)
+ head = fts_sort(sp, head, nitems);
+ return (head);
+}
+
+static int
+fts_stat(FTS *sp, FTSENT *p, int follow, int dfd)
+{
+ FTSENT *t;
+ dev_t dev;
+ ino_t ino;
+ struct stat *sbp, sb;
+ int saved_errno;
+ const char *path;
+
+ if (dfd == -1)
+ path = p->fts_accpath, dfd = AT_FDCWD;
+ else
+ path = p->fts_name;
+
+ /* If user needs stat info, stat buffer already allocated. */
+ sbp = ISSET(FTS_NOSTAT) ? &sb : p->fts_statp;
+
+#ifdef FTS_WHITEOUT
+ /* Check for whiteout. */
+ if (p->fts_flags & FTS_ISW) {
+ if (sbp != &sb) {
+ memset(sbp, '\0', sizeof(*sbp));
+ sbp->st_mode = S_IFWHT;
+ }
+ return (FTS_W);
+ }
+#endif
+
+ /*
+ * If doing a logical walk, or application requested FTS_FOLLOW, do
+ * a stat(2). If that fails, check for a non-existent symlink. If
+ * fail, set the errno from the stat call.
+ */
+ if (ISSET(FTS_LOGICAL) || follow) {
+ if (fstatat(dfd, path, sbp, 0)) {
+ saved_errno = errno;
+ if (fstatat(dfd, path, sbp, AT_SYMLINK_NOFOLLOW)) {
+ p->fts_errno = saved_errno;
+ goto err;
+ }
+ errno = 0;
+ if (S_ISLNK(sbp->st_mode))
+ return (FTS_SLNONE);
+ }
+ } else if (fstatat(dfd, path, sbp, AT_SYMLINK_NOFOLLOW)) {
+ p->fts_errno = errno;
+err: memset(sbp, 0, sizeof(struct stat));
+ return (FTS_NS);
+ }
+
+ if (S_ISDIR(sbp->st_mode)) {
+ /*
+ * Set the device/inode. Used to find cycles and check for
+ * crossing mount points. Also remember the link count, used
+ * in fts_build to limit the number of stat calls. It is
+ * understood that these fields are only referenced if fts_info
+ * is set to FTS_D.
+ */
+ dev = p->fts_dev = sbp->st_dev;
+ ino = p->fts_ino = sbp->st_ino;
+ p->fts_nlink = sbp->st_nlink;
+
+ if (ISDOT(p->fts_name))
+ return (FTS_DOT);
+
+ /*
+ * Cycle detection is done by brute force when the directory
+ * is first encountered. If the tree gets deep enough or the
+ * number of symbolic links to directories is high enough,
+ * something faster might be worthwhile.
+ */
+ for (t = p->fts_parent;
+ t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent)
+ if (ino == t->fts_ino && dev == t->fts_dev) {
+ p->fts_cycle = t;
+ return (FTS_DC);
+ }
+ return (FTS_D);
+ }
+ if (S_ISLNK(sbp->st_mode))
+ return (FTS_SL);
+ if (S_ISREG(sbp->st_mode))
+ return (FTS_F);
+ return (FTS_DEFAULT);
+}
+
+/*
+ * The comparison function takes pointers to pointers to FTSENT structures.
+ * Qsort wants a comparison function that takes pointers to void.
+ * (Both with appropriate levels of const-poisoning, of course!)
+ * Use a trampoline function to deal with the difference.
+ */
+static int
+fts_compar(const void *a, const void *b)
+{
+ FTS *parent;
+
+ parent = (*(const FTSENT * const *)a)->fts_fts;
+ return (*parent->fts_compar)(a, b);
+}
+
+static FTSENT *
+fts_sort(FTS *sp, FTSENT *head, size_t nitems)
+{
+ FTSENT **ap, *p;
+
+ /*
+ * Construct an array of pointers to the structures and call qsort(3).
+ * Reassemble the array in the order returned by qsort. If unable to
+ * sort for memory reasons, return the directory entries in their
+ * current order. Allocate enough space for the current needs plus
+ * 40 so don't realloc one entry at a time.
+ */
+ if (nitems > sp->fts_nitems) {
+ sp->fts_nitems = nitems + 40;
+ if ((sp->fts_array = reallocf(sp->fts_array,
+ sp->fts_nitems * sizeof(FTSENT *))) == NULL) {
+ sp->fts_nitems = 0;
+ return (head);
+ }
+ }
+ for (ap = sp->fts_array, p = head; p; p = p->fts_link)
+ *ap++ = p;
+ qsort(sp->fts_array, nitems, sizeof(FTSENT *), fts_compar);
+ for (head = *(ap = sp->fts_array); --nitems; ++ap)
+ ap[0]->fts_link = ap[1];
+ ap[0]->fts_link = NULL;
+ return (head);
+}
+
+static FTSENT *
+fts_alloc(FTS *sp, char *name, size_t namelen)
+{
+ FTSENT *p;
+ size_t len;
+
+ struct ftsent_withstat {
+ FTSENT ent;
+ struct stat statbuf;
+ };
+
+ /*
+ * The file name is a variable length array and no stat structure is
+ * necessary if the user has set the nostat bit. Allocate the FTSENT
+ * structure, the file name and the stat structure in one chunk, but
+ * be careful that the stat structure is reasonably aligned.
+ */
+ if (ISSET(FTS_NOSTAT))
+ len = sizeof(FTSENT) + namelen + 1;
+ else
+ len = sizeof(struct ftsent_withstat) + namelen + 1;
+
+ if ((p = malloc(len)) == NULL)
+ return (NULL);
+
+ if (ISSET(FTS_NOSTAT)) {
+ p->fts_name = (char *)(p + 1);
+ p->fts_statp = NULL;
+ } else {
+ p->fts_name = (char *)((struct ftsent_withstat *)p + 1);
+ p->fts_statp = &((struct ftsent_withstat *)p)->statbuf;
+ }
+
+ /* Copy the name and guarantee NUL termination. */
+ memcpy(p->fts_name, name, namelen);
+ p->fts_name[namelen] = '\0';
+ p->fts_namelen = namelen;
+ p->fts_path = sp->fts_path;
+ p->fts_errno = 0;
+ p->fts_flags = 0;
+ p->fts_instr = FTS_NOINSTR;
+ p->fts_number = 0;
+ p->fts_pointer = NULL;
+ p->fts_fts = sp;
+ return (p);
+}
+
+static void
+fts_lfree(FTSENT *head)
+{
+ FTSENT *p;
+
+ /* Free a linked list of structures. */
+ while ((p = head)) {
+ head = head->fts_link;
+ free(p);
+ }
+}
+
+/*
+ * Allow essentially unlimited paths; find, rm, ls should all work on any tree.
+ * Most systems will allow creation of paths much longer than MAXPATHLEN, even
+ * though the kernel won't resolve them. Add the size (not just what's needed)
+ * plus 256 bytes so don't realloc the path 2 bytes at a time.
+ */
+static int
+fts_palloc(FTS *sp, size_t more)
+{
+
+ sp->fts_pathlen += more + 256;
+ sp->fts_path = reallocf(sp->fts_path, sp->fts_pathlen);
+ return (sp->fts_path == NULL);
+}
+
+/*
+ * When the path is realloc'd, have to fix all of the pointers in structures
+ * already returned.
+ */
+static void
+fts_padjust(FTS *sp, FTSENT *head)
+{
+ FTSENT *p;
+ char *addr = sp->fts_path;
+
+#define ADJUST(p) do { \
+ if ((p)->fts_accpath != (p)->fts_name) { \
+ (p)->fts_accpath = \
+ (char *)addr + ((p)->fts_accpath - (p)->fts_path); \
+ } \
+ (p)->fts_path = addr; \
+} while (0)
+ /* Adjust the current set of children. */
+ for (p = sp->fts_child; p; p = p->fts_link)
+ ADJUST(p);
+
+ /* Adjust the rest of the tree, including the current level. */
+ for (p = head; p->fts_level >= FTS_ROOTLEVEL;) {
+ ADJUST(p);
+ p = p->fts_link ? p->fts_link : p->fts_parent;
+ }
+}
+
+static size_t
+fts_maxarglen(char * const *argv)
+{
+ size_t len, max;
+
+ for (max = 0; *argv; ++argv)
+ if ((len = strlen(*argv)) > max)
+ max = len;
+ return (max + 1);
+}
+
+/*
+ * Change to dir specified by fd or p->fts_accpath without getting
+ * tricked by someone changing the world out from underneath us.
+ * Assumes p->fts_dev and p->fts_ino are filled in.
+ */
+static int
+fts_safe_changedir(FTS *sp, FTSENT *p, int fd, char *path)
+{
+ int ret, oerrno, newfd;
+ struct stat sb;
+
+ newfd = fd;
+ if (ISSET(FTS_NOCHDIR))
+ return (0);
+ if (fd < 0 && (newfd = _open(path, O_RDONLY | O_DIRECTORY |
+ O_CLOEXEC, 0)) < 0)
+ return (-1);
+ if (_fstat(newfd, &sb)) {
+ ret = -1;
+ goto bail;
+ }
+ if (p->fts_dev != sb.st_dev || p->fts_ino != sb.st_ino) {
+ errno = ENOENT; /* disinformation */
+ ret = -1;
+ goto bail;
+ }
+ ret = fchdir(newfd);
+bail:
+ oerrno = errno;
+ if (fd < 0)
+ (void)_close(newfd);
+ errno = oerrno;
+ return (ret);
+}
+
+/*
+ * Check if the filesystem for "ent" has UFS-style links.
+ */
+static int
+fts_ufslinks(FTS *sp, const FTSENT *ent)
+{
+ struct _fts_private *priv;
+ const char **cpp;
+
+ priv = (struct _fts_private *)sp;
+ /*
+ * If this node's device is different from the previous, grab
+ * the filesystem information, and decide on the reliability
+ * of the link information from this filesystem for stat(2)
+ * avoidance.
+ */
+ if (priv->ftsp_dev != ent->fts_dev) {
+ if (statfs(ent->fts_path, &priv->ftsp_statfs) != -1) {
+ priv->ftsp_dev = ent->fts_dev;
+ priv->ftsp_linksreliable = 0;
+ for (cpp = ufslike_filesystems; *cpp; cpp++) {
+ if (strcmp(priv->ftsp_statfs.f_fstypename,
+ *cpp) == 0) {
+ priv->ftsp_linksreliable = 1;
+ break;
+ }
+ }
+ } else {
+ priv->ftsp_linksreliable = 0;
+ }
+ }
+ return (priv->ftsp_linksreliable);
+}
diff --git a/lib/libc/gen/ftw.3 b/lib/libc/gen/ftw.3
new file mode 100644
index 000000000000..df8abab031bd
--- /dev/null
+++ b/lib/libc/gen/ftw.3
@@ -0,0 +1,218 @@
+.\" $OpenBSD: ftw.3,v 1.5 2004/01/25 14:48:32 jmc Exp $
+.\"
+.\" Copyright (c) 2003 Todd C. Miller <Todd.Miller@courtesan.com>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.\" Sponsored in part by the Defense Advanced Research Projects
+.\" Agency (DARPA) and Air Force Research Laboratory, Air Force
+.\" Materiel Command, USAF, under agreement number F39502-99-1-0512.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd July 5, 2004
+.Dt FTW 3
+.Os
+.Sh NAME
+.Nm ftw , nftw
+.Nd traverse (walk) a file tree
+.Sh SYNOPSIS
+.In ftw.h
+.Ft int
+.Fo ftw
+.Fa "const char *path"
+.Fa "int \*[lp]*fn\*[rp]\*[lp]const char *, const struct stat *, int\*[rp]"
+.Fa "int maxfds"
+.Fc
+.Ft int
+.Fo nftw
+.Fa "const char *path"
+.Fa "int \*[lp]*fn\*[rp]\*[lp]const char *, const struct stat *, int, struct FTW *\*[rp]"
+.Fa "int maxfds"
+.Fa "int flags"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn ftw
+and
+.Fn nftw
+functions traverse (walk) the directory hierarchy rooted in
+.Fa path .
+For each object in the hierarchy, these functions call the function
+pointed to by
+.Fa fn .
+The
+.Fn ftw
+function passes this function a pointer to a
+.Dv NUL Ns
+-terminated string containing
+the name of the object, a pointer to a
+.Vt stat
+structure corresponding to the
+object, and an integer flag.
+The
+.Fn nftw
+function passes the aforementioned arguments plus a pointer to a
+.Vt FTW
+structure as defined by
+.In ftw.h
+(shown below):
+.Bd -literal
+struct FTW {
+ int base; /* offset of basename into pathname */
+ int level; /* directory depth relative to starting point */
+};
+.Ed
+.Pp
+Possible values for the flag passed to
+.Fa fn
+are:
+.Bl -tag -width ".Dv FTW_DNR"
+.It Dv FTW_F
+A regular file.
+.It Dv FTW_D
+A directory being visited in pre-order.
+.It Dv FTW_DNR
+A directory which cannot be read.
+The directory will not be descended into.
+.It Dv FTW_DP
+A directory being visited in post-order
+.Po Fn nftw
+only
+.Pc .
+.It Dv FTW_NS
+A file for which no
+.Xr stat 2
+information was available.
+The contents of the
+.Vt stat
+structure are undefined.
+.It Dv FTW_SL
+A symbolic link.
+.It Dv FTW_SLN
+A symbolic link with a non-existent target
+.Po Fn nftw
+only
+.Pc .
+.El
+.Pp
+The
+.Fn ftw
+function traverses the tree in pre-order.
+That is, it processes the directory before the directory's contents.
+.Pp
+The
+.Fa maxfds
+argument specifies the maximum number of file descriptors
+to keep open while traversing the tree.
+It has no effect in this implementation.
+.Pp
+The
+.Fn nftw
+function has an additional
+.Fa flags
+argument with the following possible values:
+.Bl -tag -width ".Dv FTW_MOUNT"
+.It Dv FTW_PHYS
+Physical walk, do not follow symbolic links.
+.It Dv FTW_MOUNT
+The walk will not cross a mount point.
+.It FTW_DEPTH
+Process directories in post-order.
+Contents of a directory are visited before the directory itself.
+By default,
+.Fn nftw
+traverses the tree in pre-order.
+.It FTW_CHDIR
+Change to a directory before reading it.
+By default,
+.Fn nftw
+will change its starting directory.
+The current working directory will be restored to its original value before
+.Fn nftw
+returns.
+.El
+.Sh RETURN VALUES
+If the tree was traversed successfully, the
+.Fn ftw
+and
+.Fn nftw
+functions return 0.
+If the function pointed to by
+.Fa fn
+returns a non-zero value,
+.Fn ftw
+and
+.Fn nftw
+will stop processing the tree and return the value from
+.Fa fn .
+Both functions return \-1 if an error is detected.
+.Sh ERRORS
+The
+.Fn ftw
+and
+.Fn nftw
+functions may fail and set
+.Va errno
+for any of the errors specified for the library functions
+.Xr close 2 ,
+.Xr open 2 ,
+.Xr stat 2 ,
+.Xr malloc 3 ,
+.Xr opendir 3
+and
+.Xr readdir 3 .
+If the
+.Dv FTW_CHDIR
+flag is set, the
+.Fn nftw
+function may fail and set
+.Va errno
+for any of the errors specified for
+.Xr chdir 2 .
+In addition, either function may fail and set
+.Va errno
+as follows:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa maxfds
+argument is less than 1.
+.El
+.Sh SEE ALSO
+.Xr chdir 2 ,
+.Xr close 2 ,
+.Xr open 2 ,
+.Xr stat 2 ,
+.Xr fts 3 ,
+.Xr malloc 3 ,
+.Xr opendir 3 ,
+.Xr readdir 3
+.Sh STANDARDS
+The
+.Fn ftw
+and
+.Fn nftw
+functions conform to
+.St -p1003.1-2001 .
+.Sh HISTORY
+These functions first appeared in
+.At V.3 .
+Their first
+.Fx
+appearance was in
+.Fx 5.3 .
+.Sh BUGS
+The
+.Fa maxfds
+argument is currently ignored.
diff --git a/lib/libc/gen/ftw.c b/lib/libc/gen/ftw.c
new file mode 100644
index 000000000000..253a29583f36
--- /dev/null
+++ b/lib/libc/gen/ftw.c
@@ -0,0 +1,91 @@
+/* $OpenBSD: ftw.c,v 1.5 2005/08/08 08:05:34 espie Exp $ */
+
+/*
+ * Copyright (c) 2003, 2004 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F39502-99-1-0512.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <fts.h>
+#include <ftw.h>
+
+int
+ftw(const char *path, int (*fn)(const char *, const struct stat *, int),
+ int nfds)
+{
+ char * const paths[2] = { (char *)path, NULL };
+ FTSENT *cur;
+ FTS *ftsp;
+ int error = 0, fnflag, sverrno;
+
+ /* XXX - nfds is currently unused */
+ if (nfds < 1) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ ftsp = fts_open(paths, FTS_LOGICAL | FTS_COMFOLLOW | FTS_NOCHDIR, NULL);
+ if (ftsp == NULL)
+ return (-1);
+ while ((cur = fts_read(ftsp)) != NULL) {
+ switch (cur->fts_info) {
+ case FTS_D:
+ fnflag = FTW_D;
+ break;
+ case FTS_DNR:
+ fnflag = FTW_DNR;
+ break;
+ case FTS_DP:
+ /* we only visit in preorder */
+ continue;
+ case FTS_F:
+ case FTS_DEFAULT:
+ fnflag = FTW_F;
+ break;
+ case FTS_NS:
+ case FTS_NSOK:
+ case FTS_SLNONE:
+ fnflag = FTW_NS;
+ break;
+ case FTS_SL:
+ fnflag = FTW_SL;
+ break;
+ case FTS_DC:
+ errno = ELOOP;
+ /* FALLTHROUGH */
+ default:
+ error = -1;
+ goto done;
+ }
+ error = fn(cur->fts_path, cur->fts_statp, fnflag);
+ if (error != 0)
+ break;
+ }
+done:
+ sverrno = errno;
+ if (fts_close(ftsp) != 0 && error == 0)
+ error = -1;
+ else
+ errno = sverrno;
+ return (error);
+}
diff --git a/lib/libc/gen/gen-private.h b/lib/libc/gen/gen-private.h
new file mode 100644
index 000000000000..d1fab5f31462
--- /dev/null
+++ b/lib/libc/gen/gen-private.h
@@ -0,0 +1,58 @@
+/*-
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _GEN_PRIVATE_H_
+#define _GEN_PRIVATE_H_
+
+struct _telldir; /* see telldir.h */
+struct pthread_mutex;
+
+/*
+ * Structure describing an open directory.
+ *
+ * NOTE. Change structure layout with care, at least dd_fd field has to
+ * remain unchanged to guarantee backward compatibility.
+ */
+struct _dirdesc {
+ int dd_fd; /* file descriptor associated with directory */
+ long dd_loc; /* offset in current buffer */
+ long dd_size; /* amount of data returned by getdirentries */
+ char *dd_buf; /* data buffer */
+ int dd_len; /* size of data buffer */
+ long dd_seek; /* magic cookie returned by getdirentries */
+ int dd_flags; /* flags for readdir */
+ struct pthread_mutex *dd_lock; /* lock */
+ struct _telldir *dd_td; /* telldir position recording */
+};
+
+#define _dirfd(dirp) ((dirp)->dd_fd)
+
+#endif /* !_GEN_PRIVATE_H_ */
diff --git a/lib/libc/gen/getbootfile.3 b/lib/libc/gen/getbootfile.3
new file mode 100644
index 000000000000..5130c64ba6b9
--- /dev/null
+++ b/lib/libc/gen/getbootfile.3
@@ -0,0 +1,69 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" From: @(#)gethostname.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd September 23, 1994
+.Dt GETBOOTFILE 3
+.Os
+.Sh NAME
+.Nm getbootfile
+.Nd get kernel boot file name
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In paths.h
+.Ft const char *
+.Fn getbootfile void
+.Sh DESCRIPTION
+The
+.Fn getbootfile
+function retrieves the full pathname of the file from which the
+current kernel was loaded, and returns a static pointer to the name.
+A read/write interface to this information is available via the
+.Xr sysctl 3
+MIB variable
+.Dq Li kern.bootfile .
+.Sh RETURN VALUES
+If the call succeeds a string giving the pathname is returned.
+If it
+fails, a null pointer is returned and an error code is
+placed in the global location
+.Va errno .
+.Sh SEE ALSO
+.Xr sysctl 3
+.Sh HISTORY
+The
+.Fn getbootfile
+function appeared in
+.Fx 2.0 .
+.Sh BUGS
+If the boot blocks have not been modified to pass this information into
+the kernel at boot time, the static string
+.Dq Pa /boot/kernel/kernel
+is returned instead of the real boot file.
diff --git a/lib/libc/gen/getbootfile.c b/lib/libc/gen/getbootfile.c
new file mode 100644
index 000000000000..aa23247f90b8
--- /dev/null
+++ b/lib/libc/gen/getbootfile.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "From: @(#)gethostname.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/sysctl.h>
+
+#include <paths.h>
+
+const char *
+getbootfile(void)
+{
+ static char name[MAXPATHLEN];
+ size_t size = sizeof name;
+ int mib[2];
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_BOOTFILE;
+ if (sysctl(mib, 2, name, &size, NULL, 0) == -1)
+ return ("/boot/kernel/kernel");
+ return (name);
+}
diff --git a/lib/libc/gen/getbsize.3 b/lib/libc/gen/getbsize.3
new file mode 100644
index 000000000000..2caf5fe1cb77
--- /dev/null
+++ b/lib/libc/gen/getbsize.3
@@ -0,0 +1,94 @@
+.\" Copyright (c) 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)getbsize.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd November 16, 2012
+.Dt GETBSIZE 3
+.Os
+.Sh NAME
+.Nm getbsize
+.Nd get preferred block size
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft char *
+.Fn getbsize "int *headerlenp" "long *blocksizep"
+.Sh DESCRIPTION
+The
+.Fn getbsize
+function returns a preferred block size for reporting by system utilities
+.Xr df 1 ,
+.Xr du 1 ,
+.Xr ls 1
+and
+.Xr systat 1 ,
+based on the value of the
+.Ev BLOCKSIZE
+environment variable.
+.Ev BLOCKSIZE
+may be specified directly in bytes, or in multiples of a kilobyte by
+specifying a number followed by ``K'' or ``k'', in multiples of a
+megabyte by specifying a number followed by ``M'' or ``m'' or in
+multiples of a gigabyte by specifying a number followed by ``G'' or
+``g''.
+Multiples must be integers.
+.Pp
+Valid values of
+.Ev BLOCKSIZE
+are 512 bytes to 1 gigabyte.
+Sizes less than 512 bytes are rounded up to 512 bytes, and sizes
+greater than 1 GB are rounded down to 1 GB.
+In each case
+.Fn getbsize
+produces a warning message.
+.Pp
+The
+.Fn getbsize
+function returns a pointer to a null-terminated string describing
+the block size, something like
+.Dq 1K-blocks .
+The memory referenced by
+.Fa headerlenp
+is filled in with the length of the string (not including the
+terminating null).
+The memory referenced by
+.Fa blocksizep
+is filled in with block size, in bytes.
+.Sh SEE ALSO
+.Xr df 1 ,
+.Xr du 1 ,
+.Xr ls 1 ,
+.Xr systat 1 ,
+.Xr environ 7
+.Sh HISTORY
+The
+.Fn getbsize
+function first appeared in
+.Bx 4.4 .
diff --git a/lib/libc/gen/getbsize.c b/lib/libc/gen/getbsize.c
new file mode 100644
index 000000000000..bbf5b1e89686
--- /dev/null
+++ b/lib/libc/gen/getbsize.c
@@ -0,0 +1,104 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)getbsize.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+char *
+getbsize(int *headerlenp, long *blocksizep)
+{
+ static char header[20];
+ long n, max, mul, blocksize;
+ char *ep, *p;
+ const char *form;
+
+#define KB (1024L)
+#define MB (1024L * 1024L)
+#define GB (1024L * 1024L * 1024L)
+#define MAXB GB /* No tera, peta, nor exa. */
+ form = "";
+ if ((p = getenv("BLOCKSIZE")) != NULL && *p != '\0') {
+ if ((n = strtol(p, &ep, 10)) < 0)
+ goto underflow;
+ if (n == 0)
+ n = 1;
+ if (*ep && ep[1])
+ goto fmterr;
+ switch (*ep) {
+ case 'G': case 'g':
+ form = "G";
+ max = MAXB / GB;
+ mul = GB;
+ break;
+ case 'K': case 'k':
+ form = "K";
+ max = MAXB / KB;
+ mul = KB;
+ break;
+ case 'M': case 'm':
+ form = "M";
+ max = MAXB / MB;
+ mul = MB;
+ break;
+ case '\0':
+ max = MAXB;
+ mul = 1;
+ break;
+ default:
+fmterr: warnx("%s: unknown blocksize", p);
+ n = 512;
+ max = MAXB;
+ mul = 1;
+ break;
+ }
+ if (n > max) {
+ warnx("maximum blocksize is %ldG", MAXB / GB);
+ n = max;
+ }
+ if ((blocksize = n * mul) < 512) {
+underflow: warnx("minimum blocksize is 512");
+ form = "";
+ blocksize = n = 512;
+ }
+ } else
+ blocksize = n = 512;
+
+ (void)snprintf(header, sizeof(header), "%ld%s-blocks", n, form);
+ *headerlenp = strlen(header);
+ *blocksizep = blocksize;
+ return (header);
+}
diff --git a/lib/libc/gen/getcap.3 b/lib/libc/gen/getcap.3
new file mode 100644
index 000000000000..c3a9ce87a032
--- /dev/null
+++ b/lib/libc/gen/getcap.3
@@ -0,0 +1,569 @@
+.\" Copyright (c) 1992, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Casey Leedom of Lawrence Livermore National Laboratory.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)getcap.3 8.4 (Berkeley) 5/13/94
+.\" $FreeBSD$
+.\"
+.Dd March 22, 2002
+.Dt GETCAP 3
+.Os
+.Sh NAME
+.Nm cgetent ,
+.Nm cgetset ,
+.Nm cgetmatch ,
+.Nm cgetcap ,
+.Nm cgetnum ,
+.Nm cgetstr ,
+.Nm cgetustr ,
+.Nm cgetfirst ,
+.Nm cgetnext ,
+.Nm cgetclose
+.Nd capability database access routines
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft int
+.Fn cgetent "char **buf" "char **db_array" "const char *name"
+.Ft int
+.Fn cgetset "const char *ent"
+.Ft int
+.Fn cgetmatch "const char *buf" "const char *name"
+.Ft char *
+.Fn cgetcap "char *buf" "const char *cap" "int type"
+.Ft int
+.Fn cgetnum "char *buf" "const char *cap" "long *num"
+.Ft int
+.Fn cgetstr "char *buf" "const char *cap" "char **str"
+.Ft int
+.Fn cgetustr "char *buf" "const char *cap" "char **str"
+.Ft int
+.Fn cgetfirst "char **buf" "char **db_array"
+.Ft int
+.Fn cgetnext "char **buf" "char **db_array"
+.Ft int
+.Fn cgetclose "void"
+.Sh DESCRIPTION
+The
+.Fn cgetent
+function extracts the capability
+.Fa name
+from the database specified by the
+.Dv NULL
+terminated file array
+.Fa db_array
+and returns a pointer to a
+.Xr malloc 3 Ns \&'d
+copy of it in
+.Fa buf .
+The
+.Fn cgetent
+function will first look for files ending in
+.Pa .db
+(see
+.Xr cap_mkdb 1 )
+before accessing the ASCII file.
+The
+.Fa buf
+argument
+must be retained through all subsequent calls to
+.Fn cgetmatch ,
+.Fn cgetcap ,
+.Fn cgetnum ,
+.Fn cgetstr ,
+and
+.Fn cgetustr ,
+but may then be
+.Xr free 3 Ns \&'d .
+On success 0 is returned, 1 if the returned
+record contains an unresolved
+.Ic tc
+expansion,
+\-1 if the requested record could not be found,
+\-2 if a system error was encountered (could not open/read a file, etc.) also
+setting
+.Va errno ,
+and \-3 if a potential reference loop is detected (see
+.Ic tc=
+comments below).
+.Pp
+The
+.Fn cgetset
+function enables the addition of a character buffer containing a single capability
+record entry
+to the capability database.
+Conceptually, the entry is added as the first ``file'' in the database, and
+is therefore searched first on the call to
+.Fn cgetent .
+The entry is passed in
+.Fa ent .
+If
+.Fa ent
+is
+.Dv NULL ,
+the current entry is removed from the database.
+A call to
+.Fn cgetset
+must precede the database traversal.
+It must be called before the
+.Fn cgetent
+call.
+If a sequential access is being performed (see below), it must be called
+before the first sequential access call
+.Po Fn cgetfirst
+or
+.Fn cgetnext
+.Pc ,
+or be directly preceded by a
+.Fn cgetclose
+call.
+On success 0 is returned and \-1 on failure.
+.Pp
+The
+.Fn cgetmatch
+function will return 0 if
+.Fa name
+is one of the names of the capability record
+.Fa buf ,
+\-1 if
+not.
+.Pp
+The
+.Fn cgetcap
+function searches the capability record
+.Fa buf
+for the capability
+.Fa cap
+with type
+.Fa type .
+A
+.Fa type
+is specified using any single character.
+If a colon (`:') is used, an
+untyped capability will be searched for (see below for explanation of
+types).
+A pointer to the value of
+.Fa cap
+in
+.Fa buf
+is returned on success,
+.Dv NULL
+if the requested capability could not be
+found.
+The end of the capability value is signaled by a `:' or
+.Tn ASCII
+.Dv NUL
+(see below for capability database syntax).
+.Pp
+The
+.Fn cgetnum
+function retrieves the value of the numeric capability
+.Fa cap
+from the capability record pointed to by
+.Fa buf .
+The numeric value is returned in the
+.Ft long
+pointed to by
+.Fa num .
+0 is returned on success, \-1 if the requested numeric capability could not
+be found.
+.Pp
+The
+.Fn cgetstr
+function retrieves the value of the string capability
+.Fa cap
+from the capability record pointed to by
+.Fa buf .
+A pointer to a decoded,
+.Dv NUL
+terminated,
+.Xr malloc 3 Ns \&'d
+copy of the string is returned in the
+.Ft char *
+pointed to by
+.Fa str .
+The number of characters in the decoded string not including the trailing
+.Dv NUL
+is returned on success, \-1 if the requested string capability could not
+be found, \-2 if a system error was encountered (storage allocation
+failure).
+.Pp
+The
+.Fn cgetustr
+function is identical to
+.Fn cgetstr
+except that it does not expand special characters, but rather returns each
+character of the capability string literally.
+.Pp
+The
+.Fn cgetfirst
+and
+.Fn cgetnext
+functions comprise a function group that provides for sequential
+access of the
+.Dv NULL
+pointer terminated array of file names,
+.Fa db_array .
+The
+.Fn cgetfirst
+function returns the first record in the database and resets the access
+to the first record.
+The
+.Fn cgetnext
+function returns the next record in the database with respect to the
+record returned by the previous
+.Fn cgetfirst
+or
+.Fn cgetnext
+call.
+If there is no such previous call, the first record in the database is
+returned.
+Each record is returned in a
+.Xr malloc 3 Ns \&'d
+copy pointed to by
+.Fa buf .
+.Ic Tc
+expansion is done (see
+.Ic tc=
+comments below).
+Upon completion of the database 0 is returned, 1 is returned upon successful
+return of record with possibly more remaining (we have not reached the end of
+the database yet), 2 is returned if the record contains an unresolved
+.Ic tc
+expansion, \-1 is returned if a system error occurred, and \-2
+is returned if a potential reference loop is detected (see
+.Ic tc=
+comments below).
+Upon completion of database (0 return) the database is closed.
+.Pp
+The
+.Fn cgetclose
+function closes the sequential access and frees any memory and file descriptors
+being used.
+Note that it does not erase the buffer pushed by a call to
+.Fn cgetset .
+.Sh CAPABILITY DATABASE SYNTAX
+Capability databases are normally
+.Tn ASCII
+and may be edited with standard
+text editors.
+Blank lines and lines beginning with a `#' are comments
+and are ignored.
+Lines ending with a `\|\e' indicate that the next line
+is a continuation of the current line; the `\|\e' and following newline
+are ignored.
+Long lines are usually continued onto several physical
+lines by ending each line except the last with a `\|\e'.
+.Pp
+Capability databases consist of a series of records, one per logical
+line.
+Each record contains a variable number of `:'-separated fields
+(capabilities).
+Empty fields consisting entirely of white space
+characters (spaces and tabs) are ignored.
+.Pp
+The first capability of each record specifies its names, separated by `|'
+characters.
+These names are used to reference records in the database.
+By convention, the last name is usually a comment and is not intended as
+a lookup tag.
+For example, the
+.Em vt100
+record from the
+.Xr termcap 5
+database begins:
+.Pp
+.Dl "d0\||\|vt100\||\|vt100-am\||\|vt100am\||\|dec vt100:"
+.Pp
+giving four names that can be used to access the record.
+.Pp
+The remaining non-empty capabilities describe a set of (name, value)
+bindings, consisting of a names optionally followed by a typed value:
+.Pp
+.Bl -tag -width "nameTvalue" -compact
+.It name
+typeless [boolean] capability
+.Em name No "is present [true]"
+.It name Ns Em \&T Ns value
+capability
+.Pq Em name , \&T
+has value
+.Em value
+.It name@
+no capability
+.Em name No exists
+.It name Ns Em T Ns \&@
+capability
+.Pq Em name , T
+does not exist
+.El
+.Pp
+Names consist of one or more characters.
+Names may contain any character
+except `:', but it is usually best to restrict them to the printable
+characters and avoid use of graphics like `#', `=', `%', `@', etc.
+Types
+are single characters used to separate capability names from their
+associated typed values.
+Types may be any character except a `:'.
+Typically, graphics like `#', `=', `%', etc.\& are used.
+Values may be any
+number of characters and may contain any character except `:'.
+.Sh CAPABILITY DATABASE SEMANTICS
+Capability records describe a set of (name, value) bindings.
+Names may
+have multiple values bound to them.
+Different values for a name are
+distinguished by their
+.Fa types .
+The
+.Fn cgetcap
+function will return a pointer to a value of a name given the capability
+name and the type of the value.
+.Pp
+The types `#' and `=' are conventionally used to denote numeric and
+string typed values, but no restriction on those types is enforced.
+The
+functions
+.Fn cgetnum
+and
+.Fn cgetstr
+can be used to implement the traditional syntax and semantics of `#'
+and `='.
+Typeless capabilities are typically used to denote boolean objects with
+presence or absence indicating truth and false values respectively.
+This interpretation is conveniently represented by:
+.Pp
+.Dl "(getcap(buf, name, ':') != NULL)"
+.Pp
+A special capability,
+.Ic tc= name ,
+is used to indicate that the record specified by
+.Fa name
+should be substituted for the
+.Ic tc
+capability.
+.Ic Tc
+capabilities may interpolate records which also contain
+.Ic tc
+capabilities and more than one
+.Ic tc
+capability may be used in a record.
+A
+.Ic tc
+expansion scope (i.e., where the argument is searched for) contains the
+file in which the
+.Ic tc
+is declared and all subsequent files in the file array.
+.Pp
+When a database is searched for a capability record, the first matching
+record in the search is returned.
+When a record is scanned for a
+capability, the first matching capability is returned; the capability
+.Ic :nameT@:
+will hide any following definition of a value of type
+.Em T
+for
+.Fa name ;
+and the capability
+.Ic :name@:
+will prevent any following values of
+.Fa name
+from being seen.
+.Pp
+These features combined with
+.Ic tc
+capabilities can be used to generate variations of other databases and
+records by either adding new capabilities, overriding definitions with new
+definitions, or hiding following definitions via `@' capabilities.
+.Sh EXAMPLES
+.Bd -unfilled -offset indent
+example\||\|an example of binding multiple values to names:\e
+ :foo%bar:foo^blah:foo@:\e
+ :abc%xyz:abc^frap:abc$@:\e
+ :tc=more:
+.Ed
+.Pp
+The capability foo has two values bound to it (bar of type `%' and blah of
+type `^') and any other value bindings are hidden.
+The capability abc
+also has two values bound but only a value of type `$' is prevented from
+being defined in the capability record more.
+.Bd -unfilled -offset indent
+file1:
+ new\||\|new_record\||\|a modification of "old":\e
+ :fript=bar:who-cares@:tc=old:blah:tc=extensions:
+file2:
+ old\||\|old_record\||\|an old database record:\e
+ :fript=foo:who-cares:glork#200:
+.Ed
+.Pp
+The records are extracted by calling
+.Fn cgetent
+with file1 preceding file2.
+In the capability record new in file1, fript=bar overrides the definition
+of fript=foo interpolated from the capability record old in file2,
+who-cares@ prevents the definition of any who-cares definitions in old
+from being seen, glork#200 is inherited from old, and blah and anything
+defined by the record extensions is added to those definitions in old.
+Note that the position of the fript=bar and who-cares@ definitions before
+tc=old is important here.
+If they were after, the definitions in old
+would take precedence.
+.Sh CGETNUM AND CGETSTR SYNTAX AND SEMANTICS
+Two types are predefined by
+.Fn cgetnum
+and
+.Fn cgetstr :
+.Pp
+.Bl -tag -width "nameXnumber" -compact
+.It Em name Ns \&# Ns Em number
+numeric capability
+.Em name
+has value
+.Em number
+.It Em name Ns = Ns Em string
+string capability
+.Em name
+has value
+.Em string
+.It Em name Ns \&#@
+the numeric capability
+.Em name
+does not exist
+.It Em name Ns \&=@
+the string capability
+.Em name
+does not exist
+.El
+.Pp
+Numeric capability values may be given in one of three numeric bases.
+If the number starts with either
+.Ql 0x
+or
+.Ql 0X
+it is interpreted as a hexadecimal number (both upper and lower case a-f
+may be used to denote the extended hexadecimal digits).
+Otherwise, if the number starts with a
+.Ql 0
+it is interpreted as an octal number.
+Otherwise the number is interpreted as a decimal number.
+.Pp
+String capability values may contain any character.
+Non-printable
+.Dv ASCII
+codes, new lines, and colons may be conveniently represented by the use
+of escape sequences:
+.Bl -column "\e\|X,X\e\|X" "(ASCII octal nnn)"
+^X ('X' & 037) control-X
+\e\|b, \e\|B (ASCII 010) backspace
+\e\|t, \e\|T (ASCII 011) tab
+\e\|n, \e\|N (ASCII 012) line feed (newline)
+\e\|f, \e\|F (ASCII 014) form feed
+\e\|r, \e\|R (ASCII 015) carriage return
+\e\|e, \e\|E (ASCII 027) escape
+\e\|c, \e\|C (:) colon
+\e\|\e (\e\|) back slash
+\e\|^ (^) caret
+\e\|nnn (ASCII octal nnn)
+.El
+.Pp
+A `\|\e' may be followed by up to three octal digits directly specifies
+the numeric code for a character.
+The use of
+.Tn ASCII
+.Dv NUL Ns s ,
+while easily
+encoded, causes all sorts of problems and must be used with care since
+.Dv NUL Ns s
+are typically used to denote the end of strings; many applications
+use `\e\|200' to represent a
+.Dv NUL .
+.Sh DIAGNOSTICS
+The
+.Fn cgetent ,
+.Fn cgetset ,
+.Fn cgetmatch ,
+.Fn cgetnum ,
+.Fn cgetstr ,
+.Fn cgetustr ,
+.Fn cgetfirst ,
+and
+.Fn cgetnext
+functions
+return a value greater than or equal to 0 on success and a value less
+than 0 on failure.
+The
+.Fn cgetcap
+function returns a character pointer on success and a
+.Dv NULL
+on failure.
+.Pp
+The
+.Fn cgetent ,
+and
+.Fn cgetset
+functions may fail and set
+.Va errno
+for any of the errors specified for the library functions:
+.Xr fopen 3 ,
+.Xr fclose 3 ,
+.Xr open 2 ,
+and
+.Xr close 2 .
+.Pp
+The
+.Fn cgetent ,
+.Fn cgetset ,
+.Fn cgetstr ,
+and
+.Fn cgetustr
+functions
+may fail and set
+.Va errno
+as follows:
+.Bl -tag -width Er
+.It Bq Er ENOMEM
+No memory to allocate.
+.El
+.Sh SEE ALSO
+.Xr cap_mkdb 1 ,
+.Xr malloc 3
+.Sh BUGS
+Colons (`:') cannot be used in names, types, or values.
+.Pp
+There are no checks for
+.Ic tc Ns = Ns Ic name
+loops in
+.Fn cgetent .
+.Pp
+The buffer added to the database by a call to
+.Fn cgetset
+is not unique to the database but is rather prepended to any database used.
diff --git a/lib/libc/gen/getcap.c b/lib/libc/gen/getcap.c
new file mode 100644
index 000000000000..f2f3777ab14e
--- /dev/null
+++ b/lib/libc/gen/getcap.c
@@ -0,0 +1,1055 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Casey Leedom of Lawrence Livermore National Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)getcap.c 8.3 (Berkeley) 3/25/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+#include <db.h>
+
+#define BFRAG 1024
+#define BSIZE 1024
+#define ESC ('[' & 037) /* ASCII ESC */
+#define MAX_RECURSION 32 /* maximum getent recursion */
+#define SFRAG 100 /* cgetstr mallocs in SFRAG chunks */
+
+#define RECOK (char)0
+#define TCERR (char)1
+#define SHADOW (char)2
+
+static size_t topreclen; /* toprec length */
+static char *toprec; /* Additional record specified by cgetset() */
+static int gottoprec; /* Flag indicating retrieval of toprecord */
+
+static int cdbget(DB *, char **, const char *);
+static int getent(char **, u_int *, char **, int, const char *, int, char *);
+static int nfcmp(char *, char *);
+
+/*
+ * Cgetset() allows the addition of a user specified buffer to be added
+ * to the database array, in effect "pushing" the buffer on top of the
+ * virtual database. 0 is returned on success, -1 on failure.
+ */
+int
+cgetset(const char *ent)
+{
+ if (ent == NULL) {
+ if (toprec)
+ free(toprec);
+ toprec = NULL;
+ topreclen = 0;
+ return (0);
+ }
+ topreclen = strlen(ent);
+ if ((toprec = malloc (topreclen + 1)) == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ gottoprec = 0;
+ (void)strcpy(toprec, ent);
+ return (0);
+}
+
+/*
+ * Cgetcap searches the capability record buf for the capability cap with
+ * type `type'. A pointer to the value of cap is returned on success, NULL
+ * if the requested capability couldn't be found.
+ *
+ * Specifying a type of ':' means that nothing should follow cap (:cap:).
+ * In this case a pointer to the terminating ':' or NUL will be returned if
+ * cap is found.
+ *
+ * If (cap, '@') or (cap, terminator, '@') is found before (cap, terminator)
+ * return NULL.
+ */
+char *
+cgetcap(char *buf, const char *cap, int type)
+{
+ char *bp;
+ const char *cp;
+
+ bp = buf;
+ for (;;) {
+ /*
+ * Skip past the current capability field - it's either the
+ * name field if this is the first time through the loop, or
+ * the remainder of a field whose name failed to match cap.
+ */
+ for (;;)
+ if (*bp == '\0')
+ return (NULL);
+ else
+ if (*bp++ == ':')
+ break;
+
+ /*
+ * Try to match (cap, type) in buf.
+ */
+ for (cp = cap; *cp == *bp && *bp != '\0'; cp++, bp++)
+ continue;
+ if (*cp != '\0')
+ continue;
+ if (*bp == '@')
+ return (NULL);
+ if (type == ':') {
+ if (*bp != '\0' && *bp != ':')
+ continue;
+ return(bp);
+ }
+ if (*bp != type)
+ continue;
+ bp++;
+ return (*bp == '@' ? NULL : bp);
+ }
+ /* NOTREACHED */
+}
+
+/*
+ * Cgetent extracts the capability record name from the NULL terminated file
+ * array db_array and returns a pointer to a malloc'd copy of it in buf.
+ * Buf must be retained through all subsequent calls to cgetcap, cgetnum,
+ * cgetflag, and cgetstr, but may then be free'd. 0 is returned on success,
+ * -1 if the requested record couldn't be found, -2 if a system error was
+ * encountered (couldn't open/read a file, etc.), and -3 if a potential
+ * reference loop is detected.
+ */
+int
+cgetent(char **buf, char **db_array, const char *name)
+{
+ u_int dummy;
+
+ return (getent(buf, &dummy, db_array, -1, name, 0, NULL));
+}
+
+/*
+ * Getent implements the functions of cgetent. If fd is non-negative,
+ * *db_array has already been opened and fd is the open file descriptor. We
+ * do this to save time and avoid using up file descriptors for tc=
+ * recursions.
+ *
+ * Getent returns the same success/failure codes as cgetent. On success, a
+ * pointer to a malloc'ed capability record with all tc= capabilities fully
+ * expanded and its length (not including trailing ASCII NUL) are left in
+ * *cap and *len.
+ *
+ * Basic algorithm:
+ * + Allocate memory incrementally as needed in chunks of size BFRAG
+ * for capability buffer.
+ * + Recurse for each tc=name and interpolate result. Stop when all
+ * names interpolated, a name can't be found, or depth exceeds
+ * MAX_RECURSION.
+ */
+static int
+getent(char **cap, u_int *len, char **db_array, int fd, const char *name,
+ int depth, char *nfield)
+{
+ DB *capdbp;
+ char *r_end, *rp, **db_p;
+ int myfd, eof, foundit, retval;
+ char *record, *cbuf;
+ int tc_not_resolved;
+ char pbuf[_POSIX_PATH_MAX];
+
+ /*
+ * Return with ``loop detected'' error if we've recursed more than
+ * MAX_RECURSION times.
+ */
+ if (depth > MAX_RECURSION)
+ return (-3);
+
+ /*
+ * Check if we have a top record from cgetset().
+ */
+ if (depth == 0 && toprec != NULL && cgetmatch(toprec, name) == 0) {
+ if ((record = malloc (topreclen + BFRAG)) == NULL) {
+ errno = ENOMEM;
+ return (-2);
+ }
+ (void)strcpy(record, toprec);
+ myfd = 0;
+ db_p = db_array;
+ rp = record + topreclen + 1;
+ r_end = rp + BFRAG;
+ goto tc_exp;
+ }
+ /*
+ * Allocate first chunk of memory.
+ */
+ if ((record = malloc(BFRAG)) == NULL) {
+ errno = ENOMEM;
+ return (-2);
+ }
+ r_end = record + BFRAG;
+ foundit = 0;
+ /*
+ * Loop through database array until finding the record.
+ */
+
+ for (db_p = db_array; *db_p != NULL; db_p++) {
+ eof = 0;
+
+ /*
+ * Open database if not already open.
+ */
+
+ if (fd >= 0) {
+ (void)lseek(fd, (off_t)0, SEEK_SET);
+ myfd = 0;
+ } else {
+ (void)snprintf(pbuf, sizeof(pbuf), "%s.db", *db_p);
+ if ((capdbp = dbopen(pbuf, O_RDONLY, 0, DB_HASH, 0))
+ != NULL) {
+ free(record);
+ retval = cdbget(capdbp, &record, name);
+ if (retval < 0) {
+ /* no record available */
+ (void)capdbp->close(capdbp);
+ return (retval);
+ }
+ /* save the data; close frees it */
+ cbuf = strdup(record);
+ if (capdbp->close(capdbp) < 0) {
+ free(cbuf);
+ return (-2);
+ }
+ if (cbuf == NULL) {
+ errno = ENOMEM;
+ return (-2);
+ }
+ *len = strlen(cbuf);
+ *cap = cbuf;
+ return (retval);
+ } else {
+ fd = _open(*db_p, O_RDONLY | O_CLOEXEC, 0);
+ if (fd < 0)
+ continue;
+ myfd = 1;
+ }
+ }
+ /*
+ * Find the requested capability record ...
+ */
+ {
+ char buf[BUFSIZ];
+ char *b_end, *bp;
+ int c;
+
+ /*
+ * Loop invariants:
+ * There is always room for one more character in record.
+ * R_end always points just past end of record.
+ * Rp always points just past last character in record.
+ * B_end always points just past last character in buf.
+ * Bp always points at next character in buf.
+ */
+ b_end = buf;
+ bp = buf;
+ for (;;) {
+
+ /*
+ * Read in a line implementing (\, newline)
+ * line continuation.
+ */
+ rp = record;
+ for (;;) {
+ if (bp >= b_end) {
+ int n;
+
+ n = _read(fd, buf, sizeof(buf));
+ if (n <= 0) {
+ if (myfd)
+ (void)_close(fd);
+ if (n < 0) {
+ free(record);
+ return (-2);
+ } else {
+ fd = -1;
+ eof = 1;
+ break;
+ }
+ }
+ b_end = buf+n;
+ bp = buf;
+ }
+
+ c = *bp++;
+ if (c == '\n') {
+ if (rp > record && *(rp-1) == '\\') {
+ rp--;
+ continue;
+ } else
+ break;
+ }
+ *rp++ = c;
+
+ /*
+ * Enforce loop invariant: if no room
+ * left in record buffer, try to get
+ * some more.
+ */
+ if (rp >= r_end) {
+ u_int pos;
+ size_t newsize;
+
+ pos = rp - record;
+ newsize = r_end - record + BFRAG;
+ record = reallocf(record, newsize);
+ if (record == NULL) {
+ errno = ENOMEM;
+ if (myfd)
+ (void)_close(fd);
+ return (-2);
+ }
+ r_end = record + newsize;
+ rp = record + pos;
+ }
+ }
+ /* loop invariant let's us do this */
+ *rp++ = '\0';
+
+ /*
+ * If encountered eof check next file.
+ */
+ if (eof)
+ break;
+
+ /*
+ * Toss blank lines and comments.
+ */
+ if (*record == '\0' || *record == '#')
+ continue;
+
+ /*
+ * See if this is the record we want ...
+ */
+ if (cgetmatch(record, name) == 0) {
+ if (nfield == NULL || !nfcmp(nfield, record)) {
+ foundit = 1;
+ break; /* found it! */
+ }
+ }
+ }
+ }
+ if (foundit)
+ break;
+ }
+
+ if (!foundit) {
+ free(record);
+ return (-1);
+ }
+
+ /*
+ * Got the capability record, but now we have to expand all tc=name
+ * references in it ...
+ */
+tc_exp: {
+ char *newicap, *s;
+ int newilen;
+ u_int ilen;
+ int diff, iret, tclen;
+ char *icap, *scan, *tc, *tcstart, *tcend;
+
+ /*
+ * Loop invariants:
+ * There is room for one more character in record.
+ * R_end points just past end of record.
+ * Rp points just past last character in record.
+ * Scan points at remainder of record that needs to be
+ * scanned for tc=name constructs.
+ */
+ scan = record;
+ tc_not_resolved = 0;
+ for (;;) {
+ if ((tc = cgetcap(scan, "tc", '=')) == NULL)
+ break;
+
+ /*
+ * Find end of tc=name and stomp on the trailing `:'
+ * (if present) so we can use it to call ourselves.
+ */
+ s = tc;
+ for (;;)
+ if (*s == '\0')
+ break;
+ else
+ if (*s++ == ':') {
+ *(s - 1) = '\0';
+ break;
+ }
+ tcstart = tc - 3;
+ tclen = s - tcstart;
+ tcend = s;
+
+ iret = getent(&icap, &ilen, db_p, fd, tc, depth+1,
+ NULL);
+ newicap = icap; /* Put into a register. */
+ newilen = ilen;
+ if (iret != 0) {
+ /* an error */
+ if (iret < -1) {
+ if (myfd)
+ (void)_close(fd);
+ free(record);
+ return (iret);
+ }
+ if (iret == 1)
+ tc_not_resolved = 1;
+ /* couldn't resolve tc */
+ if (iret == -1) {
+ *(s - 1) = ':';
+ scan = s - 1;
+ tc_not_resolved = 1;
+ continue;
+
+ }
+ }
+ /* not interested in name field of tc'ed record */
+ s = newicap;
+ for (;;)
+ if (*s == '\0')
+ break;
+ else
+ if (*s++ == ':')
+ break;
+ newilen -= s - newicap;
+ newicap = s;
+
+ /* make sure interpolated record is `:'-terminated */
+ s += newilen;
+ if (*(s-1) != ':') {
+ *s = ':'; /* overwrite NUL with : */
+ newilen++;
+ }
+
+ /*
+ * Make sure there's enough room to insert the
+ * new record.
+ */
+ diff = newilen - tclen;
+ if (diff >= r_end - rp) {
+ u_int pos, tcpos, tcposend;
+ size_t newsize;
+
+ pos = rp - record;
+ newsize = r_end - record + diff + BFRAG;
+ tcpos = tcstart - record;
+ tcposend = tcend - record;
+ record = reallocf(record, newsize);
+ if (record == NULL) {
+ errno = ENOMEM;
+ if (myfd)
+ (void)_close(fd);
+ free(icap);
+ return (-2);
+ }
+ r_end = record + newsize;
+ rp = record + pos;
+ tcstart = record + tcpos;
+ tcend = record + tcposend;
+ }
+
+ /*
+ * Insert tc'ed record into our record.
+ */
+ s = tcstart + newilen;
+ bcopy(tcend, s, rp - tcend);
+ bcopy(newicap, tcstart, newilen);
+ rp += diff;
+ free(icap);
+
+ /*
+ * Start scan on `:' so next cgetcap works properly
+ * (cgetcap always skips first field).
+ */
+ scan = s-1;
+ }
+
+ }
+ /*
+ * Close file (if we opened it), give back any extra memory, and
+ * return capability, length and success.
+ */
+ if (myfd)
+ (void)_close(fd);
+ *len = rp - record - 1; /* don't count NUL */
+ if (r_end > rp)
+ if ((record =
+ reallocf(record, (size_t)(rp - record))) == NULL) {
+ errno = ENOMEM;
+ return (-2);
+ }
+
+ *cap = record;
+ if (tc_not_resolved)
+ return (1);
+ return (0);
+}
+
+static int
+cdbget(DB *capdbp, char **bp, const char *name)
+{
+ DBT key, data;
+ char *namebuf;
+
+ namebuf = strdup(name);
+ if (namebuf == NULL)
+ return (-2);
+ key.data = namebuf;
+ key.size = strlen(namebuf);
+
+ for (;;) {
+ /* Get the reference. */
+ switch(capdbp->get(capdbp, &key, &data, 0)) {
+ case -1:
+ free(namebuf);
+ return (-2);
+ case 1:
+ free(namebuf);
+ return (-1);
+ }
+
+ /* If not an index to another record, leave. */
+ if (((char *)data.data)[0] != SHADOW)
+ break;
+
+ key.data = (char *)data.data + 1;
+ key.size = data.size - 1;
+ }
+
+ *bp = (char *)data.data + 1;
+ free(namebuf);
+ return (((char *)(data.data))[0] == TCERR ? 1 : 0);
+}
+
+/*
+ * Cgetmatch will return 0 if name is one of the names of the capability
+ * record buf, -1 if not.
+ */
+int
+cgetmatch(const char *buf, const char *name)
+{
+ const char *np, *bp;
+
+ if (name == NULL || *name == '\0')
+ return -1;
+
+ /*
+ * Start search at beginning of record.
+ */
+ bp = buf;
+ for (;;) {
+ /*
+ * Try to match a record name.
+ */
+ np = name;
+ for (;;)
+ if (*np == '\0')
+ if (*bp == '|' || *bp == ':' || *bp == '\0')
+ return (0);
+ else
+ break;
+ else
+ if (*bp++ != *np++)
+ break;
+
+ /*
+ * Match failed, skip to next name in record.
+ */
+ bp--; /* a '|' or ':' may have stopped the match */
+ for (;;)
+ if (*bp == '\0' || *bp == ':')
+ return (-1); /* match failed totally */
+ else
+ if (*bp++ == '|')
+ break; /* found next name */
+ }
+}
+
+
+
+
+
+int
+cgetfirst(char **buf, char **db_array)
+{
+ (void)cgetclose();
+ return (cgetnext(buf, db_array));
+}
+
+static FILE *pfp;
+static int slash;
+static char **dbp;
+
+int
+cgetclose(void)
+{
+ if (pfp != NULL) {
+ (void)fclose(pfp);
+ pfp = NULL;
+ }
+ dbp = NULL;
+ gottoprec = 0;
+ slash = 0;
+ return(0);
+}
+
+/*
+ * Cgetnext() gets either the first or next entry in the logical database
+ * specified by db_array. It returns 0 upon completion of the database, 1
+ * upon returning an entry with more remaining, and -1 if an error occurs.
+ */
+int
+cgetnext(char **bp, char **db_array)
+{
+ size_t len;
+ int done, hadreaderr, savederrno, status;
+ char *cp, *line, *rp, *np, buf[BSIZE], nbuf[BSIZE];
+ u_int dummy;
+
+ if (dbp == NULL)
+ dbp = db_array;
+
+ if (pfp == NULL && (pfp = fopen(*dbp, "re")) == NULL) {
+ (void)cgetclose();
+ return (-1);
+ }
+ for (;;) {
+ if (toprec && !gottoprec) {
+ gottoprec = 1;
+ line = toprec;
+ } else {
+ line = fgetln(pfp, &len);
+ if (line == NULL && pfp) {
+ hadreaderr = ferror(pfp);
+ if (hadreaderr)
+ savederrno = errno;
+ fclose(pfp);
+ pfp = NULL;
+ if (hadreaderr) {
+ cgetclose();
+ errno = savederrno;
+ return (-1);
+ } else {
+ if (*++dbp == NULL) {
+ (void)cgetclose();
+ return (0);
+ } else if ((pfp =
+ fopen(*dbp, "re")) == NULL) {
+ (void)cgetclose();
+ return (-1);
+ } else
+ continue;
+ }
+ } else
+ line[len - 1] = '\0';
+ if (len == 1) {
+ slash = 0;
+ continue;
+ }
+ if (isspace((unsigned char)*line) ||
+ *line == ':' || *line == '#' || slash) {
+ if (line[len - 2] == '\\')
+ slash = 1;
+ else
+ slash = 0;
+ continue;
+ }
+ if (line[len - 2] == '\\')
+ slash = 1;
+ else
+ slash = 0;
+ }
+
+
+ /*
+ * Line points to a name line.
+ */
+ done = 0;
+ np = nbuf;
+ for (;;) {
+ for (cp = line; *cp != '\0'; cp++) {
+ if (*cp == ':') {
+ *np++ = ':';
+ done = 1;
+ break;
+ }
+ if (*cp == '\\')
+ break;
+ *np++ = *cp;
+ }
+ if (done) {
+ *np = '\0';
+ break;
+ } else { /* name field extends beyond the line */
+ line = fgetln(pfp, &len);
+ if (line == NULL && pfp) {
+ /* Name extends beyond the EOF! */
+ hadreaderr = ferror(pfp);
+ if (hadreaderr)
+ savederrno = errno;
+ fclose(pfp);
+ pfp = NULL;
+ if (hadreaderr) {
+ cgetclose();
+ errno = savederrno;
+ return (-1);
+ } else {
+ cgetclose();
+ return (-1);
+ }
+ } else
+ line[len - 1] = '\0';
+ }
+ }
+ rp = buf;
+ for(cp = nbuf; *cp != '\0'; cp++)
+ if (*cp == '|' || *cp == ':')
+ break;
+ else
+ *rp++ = *cp;
+
+ *rp = '\0';
+ /*
+ * XXX
+ * Last argument of getent here should be nbuf if we want true
+ * sequential access in the case of duplicates.
+ * With NULL, getent will return the first entry found
+ * rather than the duplicate entry record. This is a
+ * matter of semantics that should be resolved.
+ */
+ status = getent(bp, &dummy, db_array, -1, buf, 0, NULL);
+ if (status == -2 || status == -3)
+ (void)cgetclose();
+
+ return (status + 1);
+ }
+ /* NOTREACHED */
+}
+
+/*
+ * Cgetstr retrieves the value of the string capability cap from the
+ * capability record pointed to by buf. A pointer to a decoded, NUL
+ * terminated, malloc'd copy of the string is returned in the char *
+ * pointed to by str. The length of the string not including the trailing
+ * NUL is returned on success, -1 if the requested string capability
+ * couldn't be found, -2 if a system error was encountered (storage
+ * allocation failure).
+ */
+int
+cgetstr(char *buf, const char *cap, char **str)
+{
+ u_int m_room;
+ char *bp, *mp;
+ int len;
+ char *mem;
+
+ /*
+ * Find string capability cap
+ */
+ bp = cgetcap(buf, cap, '=');
+ if (bp == NULL)
+ return (-1);
+
+ /*
+ * Conversion / storage allocation loop ... Allocate memory in
+ * chunks SFRAG in size.
+ */
+ if ((mem = malloc(SFRAG)) == NULL) {
+ errno = ENOMEM;
+ return (-2); /* couldn't even allocate the first fragment */
+ }
+ m_room = SFRAG;
+ mp = mem;
+
+ while (*bp != ':' && *bp != '\0') {
+ /*
+ * Loop invariants:
+ * There is always room for one more character in mem.
+ * Mp always points just past last character in mem.
+ * Bp always points at next character in buf.
+ */
+ if (*bp == '^') {
+ bp++;
+ if (*bp == ':' || *bp == '\0')
+ break; /* drop unfinished escape */
+ if (*bp == '?') {
+ *mp++ = '\177';
+ bp++;
+ } else
+ *mp++ = *bp++ & 037;
+ } else if (*bp == '\\') {
+ bp++;
+ if (*bp == ':' || *bp == '\0')
+ break; /* drop unfinished escape */
+ if ('0' <= *bp && *bp <= '7') {
+ int n, i;
+
+ n = 0;
+ i = 3; /* maximum of three octal digits */
+ do {
+ n = n * 8 + (*bp++ - '0');
+ } while (--i && '0' <= *bp && *bp <= '7');
+ *mp++ = n;
+ }
+ else switch (*bp++) {
+ case 'b': case 'B':
+ *mp++ = '\b';
+ break;
+ case 't': case 'T':
+ *mp++ = '\t';
+ break;
+ case 'n': case 'N':
+ *mp++ = '\n';
+ break;
+ case 'f': case 'F':
+ *mp++ = '\f';
+ break;
+ case 'r': case 'R':
+ *mp++ = '\r';
+ break;
+ case 'e': case 'E':
+ *mp++ = ESC;
+ break;
+ case 'c': case 'C':
+ *mp++ = ':';
+ break;
+ default:
+ /*
+ * Catches '\', '^', and
+ * everything else.
+ */
+ *mp++ = *(bp-1);
+ break;
+ }
+ } else
+ *mp++ = *bp++;
+ m_room--;
+
+ /*
+ * Enforce loop invariant: if no room left in current
+ * buffer, try to get some more.
+ */
+ if (m_room == 0) {
+ size_t size = mp - mem;
+
+ if ((mem = reallocf(mem, size + SFRAG)) == NULL)
+ return (-2);
+ m_room = SFRAG;
+ mp = mem + size;
+ }
+ }
+ *mp++ = '\0'; /* loop invariant let's us do this */
+ m_room--;
+ len = mp - mem - 1;
+
+ /*
+ * Give back any extra memory and return value and success.
+ */
+ if (m_room != 0)
+ if ((mem = reallocf(mem, (size_t)(mp - mem))) == NULL)
+ return (-2);
+ *str = mem;
+ return (len);
+}
+
+/*
+ * Cgetustr retrieves the value of the string capability cap from the
+ * capability record pointed to by buf. The difference between cgetustr()
+ * and cgetstr() is that cgetustr does not decode escapes but rather treats
+ * all characters literally. A pointer to a NUL terminated malloc'd
+ * copy of the string is returned in the char pointed to by str. The
+ * length of the string not including the trailing NUL is returned on success,
+ * -1 if the requested string capability couldn't be found, -2 if a system
+ * error was encountered (storage allocation failure).
+ */
+int
+cgetustr(char *buf, const char *cap, char **str)
+{
+ u_int m_room;
+ char *bp, *mp;
+ int len;
+ char *mem;
+
+ /*
+ * Find string capability cap
+ */
+ if ((bp = cgetcap(buf, cap, '=')) == NULL)
+ return (-1);
+
+ /*
+ * Conversion / storage allocation loop ... Allocate memory in
+ * chunks SFRAG in size.
+ */
+ if ((mem = malloc(SFRAG)) == NULL) {
+ errno = ENOMEM;
+ return (-2); /* couldn't even allocate the first fragment */
+ }
+ m_room = SFRAG;
+ mp = mem;
+
+ while (*bp != ':' && *bp != '\0') {
+ /*
+ * Loop invariants:
+ * There is always room for one more character in mem.
+ * Mp always points just past last character in mem.
+ * Bp always points at next character in buf.
+ */
+ *mp++ = *bp++;
+ m_room--;
+
+ /*
+ * Enforce loop invariant: if no room left in current
+ * buffer, try to get some more.
+ */
+ if (m_room == 0) {
+ size_t size = mp - mem;
+
+ if ((mem = reallocf(mem, size + SFRAG)) == NULL)
+ return (-2);
+ m_room = SFRAG;
+ mp = mem + size;
+ }
+ }
+ *mp++ = '\0'; /* loop invariant let's us do this */
+ m_room--;
+ len = mp - mem - 1;
+
+ /*
+ * Give back any extra memory and return value and success.
+ */
+ if (m_room != 0)
+ if ((mem = reallocf(mem, (size_t)(mp - mem))) == NULL)
+ return (-2);
+ *str = mem;
+ return (len);
+}
+
+/*
+ * Cgetnum retrieves the value of the numeric capability cap from the
+ * capability record pointed to by buf. The numeric value is returned in
+ * the long pointed to by num. 0 is returned on success, -1 if the requested
+ * numeric capability couldn't be found.
+ */
+int
+cgetnum(char *buf, const char *cap, long *num)
+{
+ long n;
+ int base, digit;
+ char *bp;
+
+ /*
+ * Find numeric capability cap
+ */
+ bp = cgetcap(buf, cap, '#');
+ if (bp == NULL)
+ return (-1);
+
+ /*
+ * Look at value and determine numeric base:
+ * 0x... or 0X... hexadecimal,
+ * else 0... octal,
+ * else decimal.
+ */
+ if (*bp == '0') {
+ bp++;
+ if (*bp == 'x' || *bp == 'X') {
+ bp++;
+ base = 16;
+ } else
+ base = 8;
+ } else
+ base = 10;
+
+ /*
+ * Conversion loop ...
+ */
+ n = 0;
+ for (;;) {
+ if ('0' <= *bp && *bp <= '9')
+ digit = *bp - '0';
+ else if ('a' <= *bp && *bp <= 'f')
+ digit = 10 + *bp - 'a';
+ else if ('A' <= *bp && *bp <= 'F')
+ digit = 10 + *bp - 'A';
+ else
+ break;
+
+ if (digit >= base)
+ break;
+
+ n = n * base + digit;
+ bp++;
+ }
+
+ /*
+ * Return value and success.
+ */
+ *num = n;
+ return (0);
+}
+
+
+/*
+ * Compare name field of record.
+ */
+static int
+nfcmp(char *nf, char *rec)
+{
+ char *cp, tmp;
+ int ret;
+
+ for (cp = rec; *cp != ':'; cp++)
+ ;
+
+ tmp = *(cp + 1);
+ *(cp + 1) = '\0';
+ ret = strcmp(nf, rec);
+ *(cp + 1) = tmp;
+
+ return (ret);
+}
diff --git a/lib/libc/gen/getcontext.3 b/lib/libc/gen/getcontext.3
new file mode 100644
index 000000000000..9e3e4fccb47b
--- /dev/null
+++ b/lib/libc/gen/getcontext.3
@@ -0,0 +1,150 @@
+.\" Copyright (c) 2002 Packet Design, LLC.
+.\" All rights reserved.
+.\"
+.\" Subject to the following obligations and disclaimer of warranty,
+.\" use and redistribution of this software, in source or object code
+.\" forms, with or without modifications are expressly permitted by
+.\" Packet Design; provided, however, that:
+.\"
+.\" (i) Any and all reproductions of the source or object code
+.\" must include the copyright notice above and the following
+.\" disclaimer of warranties; and
+.\" (ii) No rights are granted, in any manner or form, to use
+.\" Packet Design trademarks, including the mark "PACKET DESIGN"
+.\" on advertising, endorsements, or otherwise except as such
+.\" appears in the above copyright notice or in the software.
+.\"
+.\" THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND
+.\" TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO
+.\" REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING
+.\" THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED
+.\" WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
+.\" OR NON-INFRINGEMENT. PACKET DESIGN DOES NOT WARRANT, GUARANTEE,
+.\" OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS
+.\" OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY,
+.\" RELIABILITY OR OTHERWISE. IN NO EVENT SHALL PACKET DESIGN BE
+.\" LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE
+.\" OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT,
+.\" INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL
+.\" DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF
+.\" USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF
+.\" LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+.\" THE USE OF THIS SOFTWARE, EVEN IF PACKET DESIGN IS ADVISED OF
+.\" THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd March 13, 2013
+.Dt GETCONTEXT 3
+.Os
+.Sh NAME
+.Nm getcontext , getcontextx , setcontext
+.Nd get and set user thread context
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In ucontext.h
+.Ft int
+.Fn getcontext "ucontext_t *ucp"
+.Ft ucontext_t *
+.Fn getcontextx "void"
+.Ft int
+.Fn setcontext "const ucontext_t *ucp"
+.Sh DESCRIPTION
+The
+.Fn getcontext
+function
+saves the current thread's execution context in the structure pointed to by
+.Fa ucp .
+This saved context may then later be restored by calling
+.Fn setcontext .
+.Pp
+The
+.Fn getcontextx
+function saves the current execution context in the newly allocated structure
+.Vt ucontext_t ,
+which is returned on success.
+If architecture defines additional CPU states that can be stored in extended
+blocks referenced from the
+.Vt ucontext_t ,
+the memory for them may be allocated and their context also stored.
+Memory returned by
+.Fn getcontextx
+function shall be freed using
+.Fn free 3 .
+.Pp
+The
+.Fn setcontext
+function
+makes a previously saved thread context the current thread context, i.e.,
+the current context is lost and
+.Fn setcontext
+does not return.
+Instead, execution continues in the context specified by
+.Fa ucp ,
+which must have been previously initialized by a call to
+.Fn getcontext ,
+.Xr makecontext 3 ,
+or by being passed as an argument to a signal handler (see
+.Xr sigaction 2 ) .
+.Pp
+If
+.Fa ucp
+was initialized by
+.Fn getcontext ,
+then execution continues as if the original
+.Fn getcontext
+call had just returned (again).
+.Pp
+If
+.Fa ucp
+was initialized by
+.Xr makecontext 3 ,
+execution continues with the invocation of the function specified to
+.Xr makecontext 3 .
+When that function returns,
+.Fa "ucp->uc_link"
+determines what happens next:
+if
+.Fa "ucp->uc_link"
+is
+.Dv NULL ,
+the process exits;
+otherwise,
+.Fn setcontext "ucp->uc_link"
+is implicitly invoked.
+.Pp
+If
+.Fa ucp
+was initialized by the invocation of a signal handler, execution continues
+at the point the thread was interrupted by the signal.
+.Sh RETURN VALUES
+If successful,
+.Fn getcontext
+returns zero and
+.Fn setcontext
+does not return; otherwise \-1 is returned.
+The
+.Fn getcontextx
+returns pointer to the allocated and initialized context on success, and
+.Va NULL
+on failure.
+.Sh ERRORS
+No errors are defined for
+.Fn getcontext
+or
+.Fn setcontext .
+The
+.Fn getcontextx
+may return the following errors in
+.Va errno :
+.Bl -tag -width Er
+.It Bq Er ENOMEM
+No memory was available to allocate for the context or some extended state.
+.El
+.Sh SEE ALSO
+.Xr sigaction 2 ,
+.Xr sigaltstack 2 ,
+.Xr makecontext 3 ,
+.Xr ucontext 3
diff --git a/lib/libc/gen/getcwd.3 b/lib/libc/gen/getcwd.3
new file mode 100644
index 000000000000..88291c3e2ee2
--- /dev/null
+++ b/lib/libc/gen/getcwd.3
@@ -0,0 +1,162 @@
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)getcwd.3 8.2 (Berkeley) 12/11/93
+.\" $FreeBSD$
+.\"
+.Dd April 17, 2010
+.Dt GETCWD 3
+.Os
+.Sh NAME
+.Nm getcwd ,
+.Nm getwd
+.Nd get working directory pathname
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft char *
+.Fn getcwd "char *buf" "size_t size"
+.Ft char *
+.Fn getwd "char *buf"
+.Sh DESCRIPTION
+The
+.Fn getcwd
+function copies the absolute pathname of the current working directory
+into the memory referenced by
+.Fa buf
+and returns a pointer to
+.Fa buf .
+The
+.Fa size
+argument is the size, in bytes, of the array referenced by
+.Fa buf .
+.Pp
+If
+.Fa buf
+is
+.Dv NULL ,
+space is allocated as necessary to store the pathname.
+This space may later be
+.Xr free 3 Ns 'd .
+.Pp
+The function
+.Fn getwd
+is a compatibility routine which calls
+.Fn getcwd
+with its
+.Fa buf
+argument and a size of
+.Dv MAXPATHLEN
+(as defined in the include
+file
+.In sys/param.h ) .
+Obviously,
+.Fa buf
+should be at least
+.Dv MAXPATHLEN
+bytes in length.
+.Pp
+These routines have traditionally been used by programs to save the
+name of a working directory for the purpose of returning to it.
+A much faster and less error-prone method of accomplishing this is to
+open the current directory
+.Pq Ql .\&
+and use the
+.Xr fchdir 2
+function to return.
+.Sh RETURN VALUES
+Upon successful completion, a pointer to the pathname is returned.
+Otherwise a
+.Dv NULL
+pointer is returned and the global variable
+.Va errno
+is set to indicate the error.
+In addition,
+.Fn getwd
+copies the error message associated with
+.Va errno
+into the memory referenced by
+.Fa buf .
+.Sh ERRORS
+The
+.Fn getcwd
+function
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa size
+argument is zero.
+.It Bq Er ENOENT
+A component of the pathname no longer exists.
+.It Bq Er ENOMEM
+Insufficient memory is available.
+.It Bq Er ERANGE
+The
+.Fa size
+argument is greater than zero but smaller than the length of the pathname
+plus 1.
+.El
+.Pp
+The
+.Fn getcwd
+function
+may fail if:
+.Bl -tag -width Er
+.It Bq Er EACCES
+Read or search permission was denied for a component of the pathname.
+This is only checked in limited cases, depending on implementation details.
+.El
+.Sh SEE ALSO
+.Xr chdir 2 ,
+.Xr fchdir 2 ,
+.Xr malloc 3 ,
+.Xr strerror 3
+.Sh STANDARDS
+The
+.Fn getcwd
+function
+conforms to
+.St -p1003.1-90 .
+The ability to specify a
+.Dv NULL
+pointer and have
+.Fn getcwd
+allocate memory as necessary is an extension.
+.Sh HISTORY
+The
+.Fn getwd
+function appeared in
+.Bx 4.0 .
+.Sh BUGS
+The
+.Fn getwd
+function
+does not do sufficient error checking and is not able to return very
+long, but valid, paths.
+It is provided for compatibility.
diff --git a/lib/libc/gen/getcwd.c b/lib/libc/gen/getcwd.c
new file mode 100644
index 000000000000..6884897fe22c
--- /dev/null
+++ b/lib/libc/gen/getcwd.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 1989, 1991, 1993, 1995
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)getcwd.c 8.5 (Berkeley) 2/7/95";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+#include "gen-private.h"
+
+#define ISDOT(dp) \
+ (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' || \
+ (dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
+
+extern int __getcwd(char *, size_t);
+
+char *
+getcwd(char *pt, size_t size)
+{
+ struct dirent *dp;
+ DIR *dir = NULL;
+ dev_t dev;
+ ino_t ino;
+ int first;
+ char *bpt;
+ struct stat s;
+ dev_t root_dev;
+ ino_t root_ino;
+ size_t ptsize;
+ int save_errno;
+ char *ept, c;
+ int fd;
+
+ /*
+ * If no buffer specified by the user, allocate one as necessary.
+ * If a buffer is specified, the size has to be non-zero. The path
+ * is built from the end of the buffer backwards.
+ */
+ if (pt) {
+ ptsize = 0;
+ if (!size) {
+ errno = EINVAL;
+ return (NULL);
+ }
+ if (size == 1) {
+ errno = ERANGE;
+ return (NULL);
+ }
+ ept = pt + size;
+ } else {
+ if ((pt = malloc(ptsize = PATH_MAX)) == NULL)
+ return (NULL);
+ ept = pt + ptsize;
+ }
+ if (__getcwd(pt, ept - pt) == 0) {
+ if (*pt != '/') {
+ bpt = pt;
+ ept = pt + strlen(pt) - 1;
+ while (bpt < ept) {
+ c = *bpt;
+ *bpt++ = *ept;
+ *ept-- = c;
+ }
+ }
+ return (pt);
+ }
+ bpt = ept - 1;
+ *bpt = '\0';
+
+ /* Save root values, so know when to stop. */
+ if (stat("/", &s))
+ goto err;
+ root_dev = s.st_dev;
+ root_ino = s.st_ino;
+
+ errno = 0; /* XXX readdir has no error return. */
+
+ for (first = 1;; first = 0) {
+ /* Stat the current level. */
+ if (dir != NULL ? _fstat(_dirfd(dir), &s) : lstat(".", &s))
+ goto err;
+
+ /* Save current node values. */
+ ino = s.st_ino;
+ dev = s.st_dev;
+
+ /* Check for reaching root. */
+ if (root_dev == dev && root_ino == ino) {
+ *--bpt = '/';
+ /*
+ * It's unclear that it's a requirement to copy the
+ * path to the beginning of the buffer, but it's always
+ * been that way and stuff would probably break.
+ */
+ bcopy(bpt, pt, ept - bpt);
+ if (dir)
+ (void) closedir(dir);
+ return (pt);
+ }
+
+ /* Open and stat parent directory. */
+ fd = _openat(dir != NULL ? _dirfd(dir) : AT_FDCWD,
+ "..", O_RDONLY | O_CLOEXEC);
+ if (fd == -1)
+ goto err;
+ if (dir)
+ (void) closedir(dir);
+ if (!(dir = fdopendir(fd)) || _fstat(_dirfd(dir), &s)) {
+ _close(fd);
+ goto err;
+ }
+
+ /*
+ * If it's a mount point, have to stat each element because
+ * the inode number in the directory is for the entry in the
+ * parent directory, not the inode number of the mounted file.
+ */
+ save_errno = 0;
+ if (s.st_dev == dev) {
+ for (;;) {
+ if (!(dp = readdir(dir)))
+ goto notfound;
+ if (dp->d_fileno == ino)
+ break;
+ }
+ } else
+ for (;;) {
+ if (!(dp = readdir(dir)))
+ goto notfound;
+ if (ISDOT(dp))
+ continue;
+
+ /* Save the first error for later. */
+ if (fstatat(_dirfd(dir), dp->d_name, &s,
+ AT_SYMLINK_NOFOLLOW)) {
+ if (!save_errno)
+ save_errno = errno;
+ errno = 0;
+ continue;
+ }
+ if (s.st_dev == dev && s.st_ino == ino)
+ break;
+ }
+
+ /*
+ * Check for length of the current name, preceding slash,
+ * leading slash.
+ */
+ while (bpt - pt < dp->d_namlen + (first ? 1 : 2)) {
+ size_t len, off;
+
+ if (!ptsize) {
+ errno = ERANGE;
+ goto err;
+ }
+ off = bpt - pt;
+ len = ept - bpt;
+ if ((pt = reallocf(pt, ptsize *= 2)) == NULL)
+ goto err;
+ bpt = pt + off;
+ ept = pt + ptsize;
+ bcopy(bpt, ept - len, len);
+ bpt = ept - len;
+ }
+ if (!first)
+ *--bpt = '/';
+ bpt -= dp->d_namlen;
+ bcopy(dp->d_name, bpt, dp->d_namlen);
+ }
+
+notfound:
+ /*
+ * If readdir set errno, use it, not any saved error; otherwise,
+ * didn't find the current directory in its parent directory, set
+ * errno to ENOENT.
+ */
+ if (!errno)
+ errno = save_errno ? save_errno : ENOENT;
+ /* FALLTHROUGH */
+err:
+ save_errno = errno;
+
+ if (ptsize)
+ free(pt);
+ if (dir)
+ (void) closedir(dir);
+
+ errno = save_errno;
+ return (NULL);
+}
diff --git a/lib/libc/gen/getdiskbyname.3 b/lib/libc/gen/getdiskbyname.3
new file mode 100644
index 000000000000..440609604c1d
--- /dev/null
+++ b/lib/libc/gen/getdiskbyname.3
@@ -0,0 +1,63 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)getdiskbyname.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt GETDISKBYNAME 3
+.Os
+.Sh NAME
+.Nm getdiskbyname
+.Nd get generic disk description by its name
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/disklabel.h
+.Ft struct disklabel *
+.Fn getdiskbyname "const char *name"
+.Sh DESCRIPTION
+The
+.Fn getdiskbyname
+function
+takes a disk name (e.g.\&
+.Ql rm03 )
+and returns a prototype disk label
+describing its geometry information and the standard
+disk partition tables.
+All information is obtained from
+the
+.Xr disktab 5
+file.
+.Sh SEE ALSO
+.Xr disktab 5 ,
+.Xr disklabel 8
+.Sh HISTORY
+The
+.Fn getdiskbyname
+function appeared in
+.Bx 4.3 .
diff --git a/lib/libc/gen/getdomainname.3 b/lib/libc/gen/getdomainname.3
new file mode 100644
index 000000000000..480c746ae80f
--- /dev/null
+++ b/lib/libc/gen/getdomainname.3
@@ -0,0 +1,100 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)gethostname.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd May 6, 1994
+.Dt GETDOMAINNAME 3
+.Os
+.Sh NAME
+.Nm getdomainname ,
+.Nm setdomainname
+.Nd get/set the NIS domain name of current host
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft int
+.Fn getdomainname "char *name" "int namelen"
+.Ft int
+.Fn setdomainname "const char *name" "int namelen"
+.Sh DESCRIPTION
+The
+.Fn getdomainname
+function
+returns the standard NIS domain name for the current host, as
+previously set by
+.Fn setdomainname .
+The
+.Fa namelen
+argument
+specifies the size of the
+.Fa name
+array.
+The returned name is null-terminated unless insufficient
+space is provided.
+.Pp
+The
+.Fn setdomainname
+function
+sets the NIS domain name of the host machine to be
+.Fa name ,
+which has length
+.Fa namelen .
+This call is restricted to the super-user and
+is normally used only when the system is bootstrapped.
+.Sh RETURN VALUES
+.Rv -std
+.Sh ERRORS
+The following errors may be returned by these calls:
+.Bl -tag -width Er
+.It Bq Er EFAULT
+The
+.Fa name
+or
+.Fa namelen
+argument gave an
+invalid address.
+.It Bq Er EPERM
+The caller tried to set the hostname and was not the super-user.
+.El
+.Sh SEE ALSO
+.Xr gethostid 3 ,
+.Xr gethostname 3 ,
+.Xr sysctl 3
+.Sh HISTORY
+The
+.Fn getdomainname
+function appeared in
+.Bx 4.2 .
+.Sh BUGS
+Domain names are limited to
+.Dv MAXHOSTNAMELEN
+(from
+.In sys/param.h )
+characters, currently 256.
diff --git a/lib/libc/gen/getdomainname.c b/lib/libc/gen/getdomainname.c
new file mode 100644
index 000000000000..5a388576f142
--- /dev/null
+++ b/lib/libc/gen/getdomainname.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)gethostname.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/sysctl.h>
+
+#include <unistd.h>
+
+int
+getdomainname(char *name, int namelen)
+{
+ int mib[2];
+ size_t size;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_NISDOMAINNAME;
+ size = namelen;
+ if (sysctl(mib, 2, name, &size, NULL, 0) == -1)
+ return (-1);
+ return (0);
+}
diff --git a/lib/libc/gen/getfsent.3 b/lib/libc/gen/getfsent.3
new file mode 100644
index 000000000000..306db64135c3
--- /dev/null
+++ b/lib/libc/gen/getfsent.3
@@ -0,0 +1,185 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)getfsent.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd April 7, 2003
+.Dt GETFSENT 3
+.Os
+.Sh NAME
+.Nm getfsent ,
+.Nm getfsspec ,
+.Nm getfsfile ,
+.Nm setfsent ,
+.Nm endfsent
+.Nd get file system descriptor file entry
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In fstab.h
+.Ft "struct fstab *"
+.Fn getfsent void
+.Ft "struct fstab *"
+.Fn getfsspec "const char *spec"
+.Ft "struct fstab *"
+.Fn getfsfile "const char *file"
+.Ft int
+.Fn setfsent void
+.Ft void
+.Fn endfsent void
+.Ft void
+.Fn setfstab "const char *file"
+.Ft "const char *"
+.Fn getfstab void
+.Sh DESCRIPTION
+The
+.Fn getfsent ,
+.Fn getfsspec ,
+and
+.Fn getfsfile
+functions
+each return a pointer to an object with the following structure
+containing the broken-out fields of a line in the file system
+description file,
+.In fstab.h .
+.Bd -literal -offset indent
+struct fstab {
+ char *fs_spec; /* block special device name */
+ char *fs_file; /* file system path prefix */
+ char *fs_vfstype; /* File system type, ufs, nfs */
+ char *fs_mntops; /* Mount options ala -o */
+ char *fs_type; /* FSTAB_* from fs_mntops */
+ int fs_freq; /* dump frequency, in days */
+ int fs_passno; /* pass number on parallel fsck */
+};
+.Ed
+.Pp
+The fields have meanings described in
+.Xr fstab 5 .
+.Pp
+The
+.Fn setfsent
+function
+opens the file (closing any previously opened file) or rewinds it
+if it is already open.
+.Pp
+The
+.Fn endfsent
+function
+closes the file.
+.Pp
+The
+.Fn setfstab
+function sets the file to be used by subsequent operations.
+The value set by
+.Fn setfstab
+does not persist across calls to
+.Fn endfsent .
+.Pp
+The
+.Fn getfstab
+function returns the name of the file that will be used.
+.Pp
+The
+.Fn getfsspec
+and
+.Fn getfsfile
+functions
+search the entire file (opening it if necessary) for a matching special
+file name or file system file name.
+.Pp
+For programs wishing to read the entire database,
+.Fn getfsent
+reads the next entry (opening the file if necessary).
+.Pp
+All entries in the file with a type field equivalent to
+.Dv FSTAB_XX
+are ignored.
+.Sh RETURN VALUES
+The
+.Fn getfsent ,
+.Fn getfsspec ,
+and
+.Fn getfsfile
+functions
+return a
+.Dv NULL
+pointer on
+.Dv EOF
+or error.
+The
+.Fn setfsent
+function
+returns 0 on failure, 1 on success.
+The
+.Fn endfsent
+function
+returns nothing.
+.Sh ENVIRONMENT
+.Bl -tag -width ".Ev PATH_FSTAB"
+.It Ev PATH_FSTAB
+If the environment variable
+.Ev PATH_FSTAB
+is set, all operations are performed against the specified file.
+.Ev PATH_FSTAB
+will not be honored if the process environment or memory address space is
+considered
+.Dq tainted .
+(See
+.Xr issetugid 2
+for more information.)
+.El
+.Sh FILES
+.Bl -tag -width /etc/fstab -compact
+.It Pa /etc/fstab
+.El
+.Sh SEE ALSO
+.Xr fstab 5
+.Sh HISTORY
+The
+.Fn getfsent
+function appeared in
+.Bx 4.0 ;
+the
+.Fn endfsent ,
+.Fn getfsfile ,
+.Fn getfsspec ,
+and
+.Fn setfsent
+functions appeared in
+.Bx 4.3 ;
+the
+.Fn setfstab
+and
+.Fn getfstab
+functions appeared in
+.Fx 5.1 .
+.Sh BUGS
+These functions use static data storage;
+if the data is needed for future use, it should be
+copied before any subsequent calls overwrite it.
diff --git a/lib/libc/gen/getgrent.3 b/lib/libc/gen/getgrent.3
new file mode 100644
index 000000000000..18a52da6e520
--- /dev/null
+++ b/lib/libc/gen/getgrent.3
@@ -0,0 +1,286 @@
+.\" Copyright (c) 1989, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" From: @(#)getgrent.3 8.2 (Berkeley) 4/19/94
+.\" $FreeBSD$
+.\"
+.Dd July 31, 2016
+.Dt GETGRENT 3
+.Os
+.Sh NAME
+.Nm getgrent ,
+.Nm getgrent_r ,
+.Nm getgrnam ,
+.Nm getgrnam_r ,
+.Nm getgrgid ,
+.Nm getgrgid_r ,
+.Nm setgroupent ,
+.Nm setgrent ,
+.Nm endgrent
+.Nd group database operations
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In grp.h
+.Ft struct group *
+.Fn getgrent void
+.Ft int
+.Fn getgrent_r "struct group *grp" "char *buffer" "size_t bufsize" "struct group **result"
+.Ft struct group *
+.Fn getgrnam "const char *name"
+.Ft int
+.Fn getgrnam_r "const char *name" "struct group *grp" "char *buffer" "size_t bufsize" "struct group **result"
+.Ft struct group *
+.Fn getgrgid "gid_t gid"
+.Ft int
+.Fn getgrgid_r "gid_t gid" "struct group *grp" "char *buffer" "size_t bufsize" "struct group **result"
+.Ft int
+.Fn setgroupent "int stayopen"
+.Ft void
+.Fn setgrent void
+.Ft void
+.Fn endgrent void
+.Sh DESCRIPTION
+These functions operate on the group database file
+.Pa /etc/group
+which is described
+in
+.Xr group 5 .
+Each line of the database is defined by the structure
+.Vt group
+found in the include
+file
+.In grp.h :
+.Bd -literal -offset indent
+struct group {
+ char *gr_name; /* group name */
+ char *gr_passwd; /* group password */
+ gid_t gr_gid; /* group id */
+ char **gr_mem; /* group members */
+};
+.Ed
+.Pp
+The functions
+.Fn getgrnam
+and
+.Fn getgrgid
+search the group database for the given group name pointed to by
+.Fa name
+or the group id pointed to by
+.Fa gid ,
+respectively, returning the first one encountered.
+Identical group
+names or group gids may result in undefined behavior.
+.Pp
+The
+.Fn getgrent
+function
+sequentially reads the group database and is intended for programs
+that wish to step through the complete list of groups.
+.Pp
+The functions
+.Fn getgrent_r ,
+.Fn getgrnam_r ,
+and
+.Fn getgrgid_r
+are thread-safe versions of
+.Fn getgrent ,
+.Fn getgrnam ,
+and
+.Fn getgrgid ,
+respectively.
+The caller must provide storage for the results of the search in
+the
+.Fa grp ,
+.Fa buffer ,
+.Fa bufsize ,
+and
+.Fa result
+arguments.
+When these functions are successful, the
+.Fa grp
+argument will be filled-in, and a pointer to that argument will be
+stored in
+.Fa result .
+If an entry is not found or an error occurs,
+.Fa result
+will be set to
+.Dv NULL .
+.Pp
+These functions will open the group file for reading, if necessary.
+.Pp
+The
+.Fn setgroupent
+function
+opens the file, or rewinds it if it is already open.
+If
+.Fa stayopen
+is non-zero, file descriptors are left open, significantly speeding
+functions subsequent calls.
+This functionality is unnecessary for
+.Fn getgrent
+as it does not close its file descriptors by default.
+It should also
+be noted that it is dangerous for long-running programs to use this
+functionality as the group file may be updated.
+.Pp
+The
+.Fn setgrent
+function
+is identical to
+.Fn setgroupent
+with an argument of zero.
+.Pp
+The
+.Fn endgrent
+function
+closes any open files.
+.Sh RETURN VALUES
+The functions
+.Fn getgrent ,
+.Fn getgrnam ,
+and
+.Fn getgrgid ,
+return a pointer to a group structure on success or
+.Dv NULL
+if the entry is not found or if an error occurs.
+If an error does occur,
+.Va errno
+will be set.
+Note that programs must explicitly set
+.Va errno
+to zero before calling any of these functions if they need to
+distinguish between a non-existent entry and an error.
+The functions
+.Fn getgrent_r ,
+.Fn getgrnam_r ,
+and
+.Fn getgrgid_r
+return 0 if no error occurred, or an error number to indicate failure.
+It is not an error if a matching entry is not found.
+(Thus, if
+.Fa result
+is set to
+.Dv NULL
+and the return value is 0, no matching entry exists.)
+.Pp
+The function
+.Fn setgroupent
+returns the value 1 if successful, otherwise the value
+0 is returned.
+The functions
+.Fn endgrent ,
+.Fn setgrent
+and
+.Fn setgrfile
+have no return value.
+.Sh FILES
+.Bl -tag -width /etc/group -compact
+.It Pa /etc/group
+group database file
+.El
+.Sh COMPATIBILITY
+The historic function
+.Fn setgrfile ,
+which allowed the specification of alternate password databases, has
+been deprecated and is no longer available.
+.Sh SEE ALSO
+.Xr getpwent 3 ,
+.Xr group 5 ,
+.Xr nsswitch.conf 5 ,
+.Xr yp 8
+.Sh STANDARDS
+The
+.Fn getgrent ,
+.Fn getgrnam ,
+.Fn getgrnam_r ,
+.Fn getgrgid ,
+.Fn getgrgid_r
+and
+.Fn endgrent
+functions conform to
+.St -p1003.1-96 .
+The
+.Fn setgrent
+function differs from that standard in that its return type is
+.Vt int
+rather than
+.Vt void .
+.Sh HISTORY
+The functions
+.Fn endgrent ,
+.Fn getgrent ,
+.Fn getgrnam ,
+.Fn getgrgid ,
+and
+.Fn setgrent
+appeared in
+.At v7 .
+The functions
+.Fn setgrfile
+and
+.Fn setgroupent
+appeared in
+.Bx 4.3 Reno .
+The functions
+.Fn getgrent_r ,
+.Fn getgrnam_r ,
+and
+.Fn getgrgid_r
+appeared in
+.Fx 5.1 .
+.Sh BUGS
+The functions
+.Fn getgrent ,
+.Fn getgrnam ,
+.Fn getgrgid ,
+.Fn setgroupent
+and
+.Fn setgrent
+leave their results in an internal static object and return
+a pointer to that object.
+Subsequent calls to
+the same function
+will modify the same object.
+.Pp
+The functions
+.Fn getgrent ,
+.Fn getgrent_r ,
+.Fn endgrent ,
+.Fn setgroupent ,
+and
+.Fn setgrent
+are fairly useless in a networked environment and should be
+avoided, if possible.
+The
+.Fn getgrent
+and
+.Fn getgrent_r
+functions
+make no attempt to suppress duplicate information if multiple
+sources are specified in
+.Xr nsswitch.conf 5 .
diff --git a/lib/libc/gen/getgrent.c b/lib/libc/gen/getgrent.c
new file mode 100644
index 000000000000..dca5375faea4
--- /dev/null
+++ b/lib/libc/gen/getgrent.c
@@ -0,0 +1,1552 @@
+/*-
+ * Copyright (c) 2003 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project by
+ * Jacques A. Vidrine, Safeport Network Services, and Network
+ * Associates Laboratories, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+ * ("CBOSS"), as part of the DARPA CHATS research program.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/param.h>
+#ifdef YP
+#include <rpc/rpc.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+#endif
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#ifdef HESIOD
+#include <hesiod.h>
+#endif
+#include <grp.h>
+#include <nsswitch.h>
+#include <pthread.h>
+#include <pthread_np.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+#include "nss_tls.h"
+#ifdef NS_CACHING
+#include "nscache.h"
+#endif
+
+enum constants {
+ GRP_STORAGE_INITIAL = 1 << 10, /* 1 KByte */
+ GRP_STORAGE_MAX = 1 << 20, /* 1 MByte */
+ SETGRENT = 1,
+ ENDGRENT = 2,
+ HESIOD_NAME_MAX = 256,
+};
+
+static const ns_src defaultsrc[] = {
+ { NSSRC_COMPAT, NS_SUCCESS },
+ { NULL, 0 }
+};
+
+int __getgroupmembership(const char *, gid_t, gid_t *, int, int *);
+int __gr_match_entry(const char *, size_t, enum nss_lookup_type,
+ const char *, gid_t);
+int __gr_parse_entry(char *, size_t, struct group *, char *, size_t,
+ int *);
+
+static int is_comment_line(const char *, size_t);
+
+union key {
+ const char *name;
+ gid_t gid;
+};
+static struct group *getgr(int (*)(union key, struct group *, char *, size_t,
+ struct group **), union key);
+static int wrap_getgrnam_r(union key, struct group *, char *, size_t,
+ struct group **);
+static int wrap_getgrgid_r(union key, struct group *, char *, size_t,
+ struct group **);
+static int wrap_getgrent_r(union key, struct group *, char *, size_t,
+ struct group **);
+
+struct files_state {
+ FILE *fp;
+ int stayopen;
+};
+static void files_endstate(void *);
+NSS_TLS_HANDLING(files);
+static int files_setgrent(void *, void *, va_list);
+static int files_group(void *, void *, va_list);
+
+
+#ifdef HESIOD
+struct dns_state {
+ long counter;
+};
+static void dns_endstate(void *);
+NSS_TLS_HANDLING(dns);
+static int dns_setgrent(void *, void *, va_list);
+static int dns_group(void *, void *, va_list);
+#endif
+
+
+#ifdef YP
+struct nis_state {
+ char domain[MAXHOSTNAMELEN];
+ int done;
+ char *key;
+ int keylen;
+};
+static void nis_endstate(void *);
+NSS_TLS_HANDLING(nis);
+static int nis_setgrent(void *, void *, va_list);
+static int nis_group(void *, void *, va_list);
+#endif
+
+struct compat_state {
+ FILE *fp;
+ int stayopen;
+ char *name;
+ enum _compat {
+ COMPAT_MODE_OFF = 0,
+ COMPAT_MODE_ALL,
+ COMPAT_MODE_NAME
+ } compat;
+};
+static void compat_endstate(void *);
+NSS_TLS_HANDLING(compat);
+static int compat_setgrent(void *, void *, va_list);
+static int compat_group(void *, void *, va_list);
+
+static int gr_addgid(gid_t, gid_t *, int, int *);
+static int getgroupmembership_fallback(void *, void *, va_list);
+
+#ifdef NS_CACHING
+static int grp_id_func(char *, size_t *, va_list, void *);
+static int grp_marshal_func(char *, size_t *, void *, va_list, void *);
+static int grp_unmarshal_func(char *, size_t, void *, va_list, void *);
+
+static int
+grp_id_func(char *buffer, size_t *buffer_size, va_list ap, void *cache_mdata)
+{
+ char *name;
+ gid_t gid;
+
+ size_t desired_size, size;
+ int res = NS_UNAVAIL;
+ enum nss_lookup_type lookup_type;
+
+
+ lookup_type = (enum nss_lookup_type)cache_mdata;
+ switch (lookup_type) {
+ case nss_lt_name:
+ name = va_arg(ap, char *);
+ size = strlen(name);
+ desired_size = sizeof(enum nss_lookup_type) + size + 1;
+ if (desired_size > *buffer_size) {
+ res = NS_RETURN;
+ goto fin;
+ }
+
+ memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type));
+ memcpy(buffer + sizeof(enum nss_lookup_type), name, size + 1);
+
+ res = NS_SUCCESS;
+ break;
+ case nss_lt_id:
+ gid = va_arg(ap, gid_t);
+ desired_size = sizeof(enum nss_lookup_type) + sizeof(gid_t);
+ if (desired_size > *buffer_size) {
+ res = NS_RETURN;
+ goto fin;
+ }
+
+ memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type));
+ memcpy(buffer + sizeof(enum nss_lookup_type), &gid,
+ sizeof(gid_t));
+
+ res = NS_SUCCESS;
+ break;
+ default:
+ /* should be unreachable */
+ return (NS_UNAVAIL);
+ }
+
+fin:
+ *buffer_size = desired_size;
+ return (res);
+}
+
+static int
+grp_marshal_func(char *buffer, size_t *buffer_size, void *retval, va_list ap,
+ void *cache_mdata)
+{
+ char *name;
+ gid_t gid;
+ struct group *grp;
+ char *orig_buf;
+ size_t orig_buf_size;
+
+ struct group new_grp;
+ size_t desired_size, size, mem_size;
+ char *p, **mem;
+
+ switch ((enum nss_lookup_type)cache_mdata) {
+ case nss_lt_name:
+ name = va_arg(ap, char *);
+ break;
+ case nss_lt_id:
+ gid = va_arg(ap, gid_t);
+ break;
+ case nss_lt_all:
+ break;
+ default:
+ /* should be unreachable */
+ return (NS_UNAVAIL);
+ }
+
+ grp = va_arg(ap, struct group *);
+ orig_buf = va_arg(ap, char *);
+ orig_buf_size = va_arg(ap, size_t);
+
+ desired_size = _ALIGNBYTES + sizeof(struct group) + sizeof(char *);
+
+ if (grp->gr_name != NULL)
+ desired_size += strlen(grp->gr_name) + 1;
+ if (grp->gr_passwd != NULL)
+ desired_size += strlen(grp->gr_passwd) + 1;
+
+ if (grp->gr_mem != NULL) {
+ mem_size = 0;
+ for (mem = grp->gr_mem; *mem; ++mem) {
+ desired_size += strlen(*mem) + 1;
+ ++mem_size;
+ }
+
+ desired_size += _ALIGNBYTES + (mem_size + 1) * sizeof(char *);
+ }
+
+ if (desired_size > *buffer_size) {
+ /* this assignment is here for future use */
+ *buffer_size = desired_size;
+ return (NS_RETURN);
+ }
+
+ memcpy(&new_grp, grp, sizeof(struct group));
+ memset(buffer, 0, desired_size);
+
+ *buffer_size = desired_size;
+ p = buffer + sizeof(struct group) + sizeof(char *);
+ memcpy(buffer + sizeof(struct group), &p, sizeof(char *));
+ p = (char *)_ALIGN(p);
+
+ if (new_grp.gr_name != NULL) {
+ size = strlen(new_grp.gr_name);
+ memcpy(p, new_grp.gr_name, size);
+ new_grp.gr_name = p;
+ p += size + 1;
+ }
+
+ if (new_grp.gr_passwd != NULL) {
+ size = strlen(new_grp.gr_passwd);
+ memcpy(p, new_grp.gr_passwd, size);
+ new_grp.gr_passwd = p;
+ p += size + 1;
+ }
+
+ if (new_grp.gr_mem != NULL) {
+ p = (char *)_ALIGN(p);
+ memcpy(p, new_grp.gr_mem, sizeof(char *) * mem_size);
+ new_grp.gr_mem = (char **)p;
+ p += sizeof(char *) * (mem_size + 1);
+
+ for (mem = new_grp.gr_mem; *mem; ++mem) {
+ size = strlen(*mem);
+ memcpy(p, *mem, size);
+ *mem = p;
+ p += size + 1;
+ }
+ }
+
+ memcpy(buffer, &new_grp, sizeof(struct group));
+ return (NS_SUCCESS);
+}
+
+static int
+grp_unmarshal_func(char *buffer, size_t buffer_size, void *retval, va_list ap,
+ void *cache_mdata)
+{
+ char *name;
+ gid_t gid;
+ struct group *grp;
+ char *orig_buf;
+ size_t orig_buf_size;
+ int *ret_errno;
+
+ char *p;
+ char **mem;
+
+ switch ((enum nss_lookup_type)cache_mdata) {
+ case nss_lt_name:
+ name = va_arg(ap, char *);
+ break;
+ case nss_lt_id:
+ gid = va_arg(ap, gid_t);
+ break;
+ case nss_lt_all:
+ break;
+ default:
+ /* should be unreachable */
+ return (NS_UNAVAIL);
+ }
+
+ grp = va_arg(ap, struct group *);
+ orig_buf = va_arg(ap, char *);
+ orig_buf_size = va_arg(ap, size_t);
+ ret_errno = va_arg(ap, int *);
+
+ if (orig_buf_size <
+ buffer_size - sizeof(struct group) - sizeof(char *)) {
+ *ret_errno = ERANGE;
+ return (NS_RETURN);
+ }
+
+ memcpy(grp, buffer, sizeof(struct group));
+ memcpy(&p, buffer + sizeof(struct group), sizeof(char *));
+
+ orig_buf = (char *)_ALIGN(orig_buf);
+ memcpy(orig_buf, buffer + sizeof(struct group) + sizeof(char *) +
+ _ALIGN(p) - (size_t)p,
+ buffer_size - sizeof(struct group) - sizeof(char *) -
+ _ALIGN(p) + (size_t)p);
+ p = (char *)_ALIGN(p);
+
+ NS_APPLY_OFFSET(grp->gr_name, orig_buf, p, char *);
+ NS_APPLY_OFFSET(grp->gr_passwd, orig_buf, p, char *);
+ if (grp->gr_mem != NULL) {
+ NS_APPLY_OFFSET(grp->gr_mem, orig_buf, p, char **);
+
+ for (mem = grp->gr_mem; *mem; ++mem)
+ NS_APPLY_OFFSET(*mem, orig_buf, p, char *);
+ }
+
+ if (retval != NULL)
+ *((struct group **)retval) = grp;
+
+ return (NS_SUCCESS);
+}
+
+NSS_MP_CACHE_HANDLING(group);
+#endif /* NS_CACHING */
+
+#ifdef NS_CACHING
+static const nss_cache_info setgrent_cache_info = NS_MP_CACHE_INFO_INITIALIZER(
+ group, (void *)nss_lt_all,
+ NULL, NULL);
+#endif
+
+static const ns_dtab setgrent_dtab[] = {
+ { NSSRC_FILES, files_setgrent, (void *)SETGRENT },
+#ifdef HESIOD
+ { NSSRC_DNS, dns_setgrent, (void *)SETGRENT },
+#endif
+#ifdef YP
+ { NSSRC_NIS, nis_setgrent, (void *)SETGRENT },
+#endif
+ { NSSRC_COMPAT, compat_setgrent, (void *)SETGRENT },
+#ifdef NS_CACHING
+ NS_CACHE_CB(&setgrent_cache_info)
+#endif
+ { NULL, NULL, NULL }
+};
+
+#ifdef NS_CACHING
+static const nss_cache_info endgrent_cache_info = NS_MP_CACHE_INFO_INITIALIZER(
+ group, (void *)nss_lt_all,
+ NULL, NULL);
+#endif
+
+static const ns_dtab endgrent_dtab[] = {
+ { NSSRC_FILES, files_setgrent, (void *)ENDGRENT },
+#ifdef HESIOD
+ { NSSRC_DNS, dns_setgrent, (void *)ENDGRENT },
+#endif
+#ifdef YP
+ { NSSRC_NIS, nis_setgrent, (void *)ENDGRENT },
+#endif
+ { NSSRC_COMPAT, compat_setgrent, (void *)ENDGRENT },
+#ifdef NS_CACHING
+ NS_CACHE_CB(&endgrent_cache_info)
+#endif
+ { NULL, NULL, NULL }
+};
+
+#ifdef NS_CACHING
+static const nss_cache_info getgrent_r_cache_info = NS_MP_CACHE_INFO_INITIALIZER(
+ group, (void *)nss_lt_all,
+ grp_marshal_func, grp_unmarshal_func);
+#endif
+
+static const ns_dtab getgrent_r_dtab[] = {
+ { NSSRC_FILES, files_group, (void *)nss_lt_all },
+#ifdef HESIOD
+ { NSSRC_DNS, dns_group, (void *)nss_lt_all },
+#endif
+#ifdef YP
+ { NSSRC_NIS, nis_group, (void *)nss_lt_all },
+#endif
+ { NSSRC_COMPAT, compat_group, (void *)nss_lt_all },
+#ifdef NS_CACHING
+ NS_CACHE_CB(&getgrent_r_cache_info)
+#endif
+ { NULL, NULL, NULL }
+};
+
+static int
+gr_addgid(gid_t gid, gid_t *groups, int maxgrp, int *grpcnt)
+{
+ int ret, dupc;
+
+ for (dupc = 0; dupc < MIN(maxgrp, *grpcnt); dupc++) {
+ if (groups[dupc] == gid)
+ return 1;
+ }
+
+ ret = 1;
+ if (*grpcnt < maxgrp)
+ groups[*grpcnt] = gid;
+ else
+ ret = 0;
+
+ (*grpcnt)++;
+
+ return ret;
+}
+
+static int
+getgroupmembership_fallback(void *retval, void *mdata, va_list ap)
+{
+ const ns_src src[] = {
+ { mdata, NS_SUCCESS },
+ { NULL, 0}
+ };
+ struct group grp;
+ struct group *grp_p;
+ char *buf;
+ size_t bufsize;
+ const char *uname;
+ gid_t *groups;
+ gid_t agroup;
+ int maxgrp, *grpcnt;
+ int i, rv, ret_errno;
+
+ /*
+ * As this is a fallback method, only provided src
+ * list will be respected during methods search.
+ */
+ assert(src[0].name != NULL);
+
+ uname = va_arg(ap, const char *);
+ agroup = va_arg(ap, gid_t);
+ groups = va_arg(ap, gid_t *);
+ maxgrp = va_arg(ap, int);
+ grpcnt = va_arg(ap, int *);
+
+ rv = NS_UNAVAIL;
+
+ buf = malloc(GRP_STORAGE_INITIAL);
+ if (buf == NULL)
+ goto out;
+
+ bufsize = GRP_STORAGE_INITIAL;
+
+ gr_addgid(agroup, groups, maxgrp, grpcnt);
+
+ _nsdispatch(NULL, setgrent_dtab, NSDB_GROUP, "setgrent", src, 0);
+ for (;;) {
+ do {
+ ret_errno = 0;
+ grp_p = NULL;
+ rv = _nsdispatch(&grp_p, getgrent_r_dtab, NSDB_GROUP,
+ "getgrent_r", src, &grp, buf, bufsize, &ret_errno);
+
+ if (grp_p == NULL && ret_errno == ERANGE) {
+ free(buf);
+ if ((bufsize << 1) > GRP_STORAGE_MAX) {
+ buf = NULL;
+ errno = ERANGE;
+ goto out;
+ }
+
+ bufsize <<= 1;
+ buf = malloc(bufsize);
+ if (buf == NULL) {
+ goto out;
+ }
+ }
+ } while (grp_p == NULL && ret_errno == ERANGE);
+
+ if (ret_errno != 0) {
+ errno = ret_errno;
+ goto out;
+ }
+
+ if (grp_p == NULL)
+ break;
+
+ for (i = 0; grp.gr_mem[i]; i++) {
+ if (strcmp(grp.gr_mem[i], uname) == 0)
+ gr_addgid(grp.gr_gid, groups, maxgrp, grpcnt);
+ }
+ }
+
+ _nsdispatch(NULL, endgrent_dtab, NSDB_GROUP, "endgrent", src);
+out:
+ free(buf);
+ return (rv);
+}
+
+void
+setgrent(void)
+{
+ (void)_nsdispatch(NULL, setgrent_dtab, NSDB_GROUP, "setgrent", defaultsrc, 0);
+}
+
+
+int
+setgroupent(int stayopen)
+{
+ (void)_nsdispatch(NULL, setgrent_dtab, NSDB_GROUP, "setgrent", defaultsrc,
+ stayopen);
+ return (1);
+}
+
+
+void
+endgrent(void)
+{
+ (void)_nsdispatch(NULL, endgrent_dtab, NSDB_GROUP, "endgrent", defaultsrc);
+}
+
+
+int
+getgrent_r(struct group *grp, char *buffer, size_t bufsize,
+ struct group **result)
+{
+ int rv, ret_errno;
+
+ ret_errno = 0;
+ *result = NULL;
+ rv = _nsdispatch(result, getgrent_r_dtab, NSDB_GROUP, "getgrent_r", defaultsrc,
+ grp, buffer, bufsize, &ret_errno);
+ if (rv == NS_SUCCESS)
+ return (0);
+ else
+ return (ret_errno);
+}
+
+
+int
+getgrnam_r(const char *name, struct group *grp, char *buffer, size_t bufsize,
+ struct group **result)
+{
+#ifdef NS_CACHING
+ static const nss_cache_info cache_info =
+ NS_COMMON_CACHE_INFO_INITIALIZER(
+ group, (void *)nss_lt_name,
+ grp_id_func, grp_marshal_func, grp_unmarshal_func);
+#endif
+
+ static const ns_dtab dtab[] = {
+ { NSSRC_FILES, files_group, (void *)nss_lt_name },
+#ifdef HESIOD
+ { NSSRC_DNS, dns_group, (void *)nss_lt_name },
+#endif
+#ifdef YP
+ { NSSRC_NIS, nis_group, (void *)nss_lt_name },
+#endif
+ { NSSRC_COMPAT, compat_group, (void *)nss_lt_name },
+#ifdef NS_CACHING
+ NS_CACHE_CB(&cache_info)
+#endif
+ { NULL, NULL, NULL }
+ };
+ int rv, ret_errno;
+
+ ret_errno = 0;
+ *result = NULL;
+ rv = _nsdispatch(result, dtab, NSDB_GROUP, "getgrnam_r", defaultsrc,
+ name, grp, buffer, bufsize, &ret_errno);
+ if (rv == NS_SUCCESS)
+ return (0);
+ else
+ return (ret_errno);
+}
+
+
+int
+getgrgid_r(gid_t gid, struct group *grp, char *buffer, size_t bufsize,
+ struct group **result)
+{
+#ifdef NS_CACHING
+ static const nss_cache_info cache_info =
+ NS_COMMON_CACHE_INFO_INITIALIZER(
+ group, (void *)nss_lt_id,
+ grp_id_func, grp_marshal_func, grp_unmarshal_func);
+#endif
+
+ static const ns_dtab dtab[] = {
+ { NSSRC_FILES, files_group, (void *)nss_lt_id },
+#ifdef HESIOD
+ { NSSRC_DNS, dns_group, (void *)nss_lt_id },
+#endif
+#ifdef YP
+ { NSSRC_NIS, nis_group, (void *)nss_lt_id },
+#endif
+ { NSSRC_COMPAT, compat_group, (void *)nss_lt_id },
+#ifdef NS_CACHING
+ NS_CACHE_CB(&cache_info)
+#endif
+ { NULL, NULL, NULL }
+ };
+ int rv, ret_errno;
+
+ ret_errno = 0;
+ *result = NULL;
+ rv = _nsdispatch(result, dtab, NSDB_GROUP, "getgrgid_r", defaultsrc,
+ gid, grp, buffer, bufsize, &ret_errno);
+ if (rv == NS_SUCCESS)
+ return (0);
+ else
+ return (ret_errno);
+}
+
+
+
+int
+__getgroupmembership(const char *uname, gid_t agroup, gid_t *groups,
+ int maxgrp, int *grpcnt)
+{
+ static const ns_dtab dtab[] = {
+ NS_FALLBACK_CB(getgroupmembership_fallback)
+ { NULL, NULL, NULL }
+ };
+
+ assert(uname != NULL);
+ /* groups may be NULL if just sizing when invoked with maxgrp = 0 */
+ assert(grpcnt != NULL);
+
+ *grpcnt = 0;
+ (void)_nsdispatch(NULL, dtab, NSDB_GROUP, "getgroupmembership",
+ defaultsrc, uname, agroup, groups, maxgrp, grpcnt);
+
+ /* too many groups found? */
+ return (*grpcnt > maxgrp ? -1 : 0);
+}
+
+
+static struct group grp;
+static char *grp_storage;
+static size_t grp_storage_size;
+
+static struct group *
+getgr(int (*fn)(union key, struct group *, char *, size_t, struct group **),
+ union key key)
+{
+ int rv;
+ struct group *res;
+
+ if (grp_storage == NULL) {
+ grp_storage = malloc(GRP_STORAGE_INITIAL);
+ if (grp_storage == NULL)
+ return (NULL);
+ grp_storage_size = GRP_STORAGE_INITIAL;
+ }
+ do {
+ rv = fn(key, &grp, grp_storage, grp_storage_size, &res);
+ if (res == NULL && rv == ERANGE) {
+ free(grp_storage);
+ if ((grp_storage_size << 1) > GRP_STORAGE_MAX) {
+ grp_storage = NULL;
+ errno = ERANGE;
+ return (NULL);
+ }
+ grp_storage_size <<= 1;
+ grp_storage = malloc(grp_storage_size);
+ if (grp_storage == NULL)
+ return (NULL);
+ }
+ } while (res == NULL && rv == ERANGE);
+ if (rv != 0)
+ errno = rv;
+ return (res);
+}
+
+
+static int
+wrap_getgrnam_r(union key key, struct group *grp, char *buffer, size_t bufsize,
+ struct group **res)
+{
+ return (getgrnam_r(key.name, grp, buffer, bufsize, res));
+}
+
+
+static int
+wrap_getgrgid_r(union key key, struct group *grp, char *buffer, size_t bufsize,
+ struct group **res)
+{
+ return (getgrgid_r(key.gid, grp, buffer, bufsize, res));
+}
+
+
+static int
+wrap_getgrent_r(union key key __unused, struct group *grp, char *buffer,
+ size_t bufsize, struct group **res)
+{
+ return (getgrent_r(grp, buffer, bufsize, res));
+}
+
+
+struct group *
+getgrnam(const char *name)
+{
+ union key key;
+
+ key.name = name;
+ return (getgr(wrap_getgrnam_r, key));
+}
+
+
+struct group *
+getgrgid(gid_t gid)
+{
+ union key key;
+
+ key.gid = gid;
+ return (getgr(wrap_getgrgid_r, key));
+}
+
+
+struct group *
+getgrent(void)
+{
+ union key key;
+
+ key.gid = 0; /* not used */
+ return (getgr(wrap_getgrent_r, key));
+}
+
+
+static int
+is_comment_line(const char *s, size_t n)
+{
+ const char *eom;
+
+ eom = &s[n];
+
+ for (; s < eom; s++)
+ if (*s == '#' || !isspace((unsigned char)*s))
+ break;
+ return (*s == '#' || s == eom);
+}
+
+
+/*
+ * files backend
+ */
+static void
+files_endstate(void *p)
+{
+
+ if (p == NULL)
+ return;
+ if (((struct files_state *)p)->fp != NULL)
+ fclose(((struct files_state *)p)->fp);
+ free(p);
+}
+
+
+static int
+files_setgrent(void *retval, void *mdata, va_list ap)
+{
+ struct files_state *st;
+ int rv, stayopen;
+
+ rv = files_getstate(&st);
+ if (rv != 0)
+ return (NS_UNAVAIL);
+ switch ((enum constants)mdata) {
+ case SETGRENT:
+ stayopen = va_arg(ap, int);
+ if (st->fp != NULL)
+ rewind(st->fp);
+ else if (stayopen)
+ st->fp = fopen(_PATH_GROUP, "re");
+ break;
+ case ENDGRENT:
+ if (st->fp != NULL) {
+ fclose(st->fp);
+ st->fp = NULL;
+ }
+ break;
+ default:
+ break;
+ }
+ return (NS_UNAVAIL);
+}
+
+
+static int
+files_group(void *retval, void *mdata, va_list ap)
+{
+ struct files_state *st;
+ enum nss_lookup_type how;
+ const char *name, *line;
+ struct group *grp;
+ gid_t gid;
+ char *buffer;
+ size_t bufsize, linesize;
+ off_t pos;
+ int rv, stayopen, *errnop;
+
+ name = NULL;
+ gid = (gid_t)-1;
+ how = (enum nss_lookup_type)mdata;
+ switch (how) {
+ case nss_lt_name:
+ name = va_arg(ap, const char *);
+ break;
+ case nss_lt_id:
+ gid = va_arg(ap, gid_t);
+ break;
+ case nss_lt_all:
+ break;
+ default:
+ return (NS_NOTFOUND);
+ }
+ grp = va_arg(ap, struct group *);
+ buffer = va_arg(ap, char *);
+ bufsize = va_arg(ap, size_t);
+ errnop = va_arg(ap, int *);
+ *errnop = files_getstate(&st);
+ if (*errnop != 0)
+ return (NS_UNAVAIL);
+ if (st->fp == NULL &&
+ ((st->fp = fopen(_PATH_GROUP, "re")) == NULL)) {
+ *errnop = errno;
+ return (NS_UNAVAIL);
+ }
+ if (how == nss_lt_all)
+ stayopen = 1;
+ else {
+ rewind(st->fp);
+ stayopen = st->stayopen;
+ }
+ rv = NS_NOTFOUND;
+ pos = ftello(st->fp);
+ while ((line = fgetln(st->fp, &linesize)) != NULL) {
+ if (line[linesize-1] == '\n')
+ linesize--;
+ rv = __gr_match_entry(line, linesize, how, name, gid);
+ if (rv != NS_SUCCESS)
+ continue;
+ /* We need room at least for the line, a string NUL
+ * terminator, alignment padding, and one (char *)
+ * pointer for the member list terminator.
+ */
+ if (bufsize <= linesize + _ALIGNBYTES + sizeof(char *)) {
+ *errnop = ERANGE;
+ rv = NS_RETURN;
+ break;
+ }
+ memcpy(buffer, line, linesize);
+ buffer[linesize] = '\0';
+ rv = __gr_parse_entry(buffer, linesize, grp,
+ &buffer[linesize + 1], bufsize - linesize - 1, errnop);
+ if (rv & NS_TERMINATE)
+ break;
+ pos = ftello(st->fp);
+ }
+ if (st->fp != NULL && !stayopen) {
+ fclose(st->fp);
+ st->fp = NULL;
+ }
+ if (rv == NS_SUCCESS && retval != NULL)
+ *(struct group **)retval = grp;
+ else if (rv == NS_RETURN && *errnop == ERANGE && st->fp != NULL)
+ fseeko(st->fp, pos, SEEK_SET);
+ return (rv);
+}
+
+
+#ifdef HESIOD
+/*
+ * dns backend
+ */
+static void
+dns_endstate(void *p)
+{
+
+ free(p);
+}
+
+
+static int
+dns_setgrent(void *retval, void *cb_data, va_list ap)
+{
+ struct dns_state *st;
+ int rv;
+
+ rv = dns_getstate(&st);
+ if (rv != 0)
+ return (NS_UNAVAIL);
+ st->counter = 0;
+ return (NS_UNAVAIL);
+}
+
+
+static int
+dns_group(void *retval, void *mdata, va_list ap)
+{
+ char buf[HESIOD_NAME_MAX];
+ struct dns_state *st;
+ struct group *grp;
+ const char *name, *label;
+ void *ctx;
+ char *buffer, **hes;
+ size_t bufsize, adjsize, linesize;
+ gid_t gid;
+ enum nss_lookup_type how;
+ int rv, *errnop;
+
+ ctx = NULL;
+ hes = NULL;
+ name = NULL;
+ gid = (gid_t)-1;
+ how = (enum nss_lookup_type)mdata;
+ switch (how) {
+ case nss_lt_name:
+ name = va_arg(ap, const char *);
+ break;
+ case nss_lt_id:
+ gid = va_arg(ap, gid_t);
+ break;
+ case nss_lt_all:
+ break;
+ }
+ grp = va_arg(ap, struct group *);
+ buffer = va_arg(ap, char *);
+ bufsize = va_arg(ap, size_t);
+ errnop = va_arg(ap, int *);
+ *errnop = dns_getstate(&st);
+ if (*errnop != 0)
+ return (NS_UNAVAIL);
+ if (hesiod_init(&ctx) != 0) {
+ *errnop = errno;
+ rv = NS_UNAVAIL;
+ goto fin;
+ }
+ do {
+ rv = NS_NOTFOUND;
+ switch (how) {
+ case nss_lt_name:
+ label = name;
+ break;
+ case nss_lt_id:
+ if (snprintf(buf, sizeof(buf), "%lu",
+ (unsigned long)gid) >= sizeof(buf))
+ goto fin;
+ label = buf;
+ break;
+ case nss_lt_all:
+ if (st->counter < 0)
+ goto fin;
+ if (snprintf(buf, sizeof(buf), "group-%ld",
+ st->counter++) >= sizeof(buf))
+ goto fin;
+ label = buf;
+ break;
+ }
+ hes = hesiod_resolve(ctx, label,
+ how == nss_lt_id ? "gid" : "group");
+ if ((how == nss_lt_id && hes == NULL &&
+ (hes = hesiod_resolve(ctx, buf, "group")) == NULL) ||
+ hes == NULL) {
+ if (how == nss_lt_all)
+ st->counter = -1;
+ if (errno != ENOENT)
+ *errnop = errno;
+ goto fin;
+ }
+ rv = __gr_match_entry(hes[0], strlen(hes[0]), how, name, gid);
+ if (rv != NS_SUCCESS) {
+ hesiod_free_list(ctx, hes);
+ hes = NULL;
+ continue;
+ }
+ /* We need room at least for the line, a string NUL
+ * terminator, alignment padding, and one (char *)
+ * pointer for the member list terminator.
+ */
+ adjsize = bufsize - _ALIGNBYTES - sizeof(char *);
+ linesize = strlcpy(buffer, hes[0], adjsize);
+ if (linesize >= adjsize) {
+ *errnop = ERANGE;
+ rv = NS_RETURN;
+ goto fin;
+ }
+ hesiod_free_list(ctx, hes);
+ hes = NULL;
+ rv = __gr_parse_entry(buffer, linesize, grp,
+ &buffer[linesize + 1], bufsize - linesize - 1, errnop);
+ } while (how == nss_lt_all && !(rv & NS_TERMINATE));
+fin:
+ if (hes != NULL)
+ hesiod_free_list(ctx, hes);
+ if (ctx != NULL)
+ hesiod_end(ctx);
+ if (rv == NS_SUCCESS && retval != NULL)
+ *(struct group **)retval = grp;
+ return (rv);
+}
+#endif /* HESIOD */
+
+
+#ifdef YP
+/*
+ * nis backend
+ */
+static void
+nis_endstate(void *p)
+{
+
+ if (p == NULL)
+ return;
+ free(((struct nis_state *)p)->key);
+ free(p);
+}
+
+
+static int
+nis_setgrent(void *retval, void *cb_data, va_list ap)
+{
+ struct nis_state *st;
+ int rv;
+
+ rv = nis_getstate(&st);
+ if (rv != 0)
+ return (NS_UNAVAIL);
+ st->done = 0;
+ free(st->key);
+ st->key = NULL;
+ return (NS_UNAVAIL);
+}
+
+
+static int
+nis_group(void *retval, void *mdata, va_list ap)
+{
+ char *map;
+ struct nis_state *st;
+ struct group *grp;
+ const char *name;
+ char *buffer, *key, *result;
+ size_t bufsize;
+ gid_t gid;
+ enum nss_lookup_type how;
+ int *errnop, keylen, resultlen, rv;
+
+ name = NULL;
+ gid = (gid_t)-1;
+ how = (enum nss_lookup_type)mdata;
+ switch (how) {
+ case nss_lt_name:
+ name = va_arg(ap, const char *);
+ map = "group.byname";
+ break;
+ case nss_lt_id:
+ gid = va_arg(ap, gid_t);
+ map = "group.bygid";
+ break;
+ case nss_lt_all:
+ map = "group.byname";
+ break;
+ }
+ grp = va_arg(ap, struct group *);
+ buffer = va_arg(ap, char *);
+ bufsize = va_arg(ap, size_t);
+ errnop = va_arg(ap, int *);
+ *errnop = nis_getstate(&st);
+ if (*errnop != 0)
+ return (NS_UNAVAIL);
+ if (st->domain[0] == '\0') {
+ if (getdomainname(st->domain, sizeof(st->domain)) != 0) {
+ *errnop = errno;
+ return (NS_UNAVAIL);
+ }
+ }
+ result = NULL;
+ do {
+ rv = NS_NOTFOUND;
+ switch (how) {
+ case nss_lt_name:
+ if (strlcpy(buffer, name, bufsize) >= bufsize)
+ goto erange;
+ break;
+ case nss_lt_id:
+ if (snprintf(buffer, bufsize, "%lu",
+ (unsigned long)gid) >= bufsize)
+ goto erange;
+ break;
+ case nss_lt_all:
+ if (st->done)
+ goto fin;
+ break;
+ }
+ result = NULL;
+ if (how == nss_lt_all) {
+ if (st->key == NULL)
+ rv = yp_first(st->domain, map, &st->key,
+ &st->keylen, &result, &resultlen);
+ else {
+ key = st->key;
+ keylen = st->keylen;
+ st->key = NULL;
+ rv = yp_next(st->domain, map, key, keylen,
+ &st->key, &st->keylen, &result,
+ &resultlen);
+ free(key);
+ }
+ if (rv != 0) {
+ free(result);
+ free(st->key);
+ st->key = NULL;
+ if (rv == YPERR_NOMORE) {
+ st->done = 1;
+ rv = NS_NOTFOUND;
+ } else
+ rv = NS_UNAVAIL;
+ goto fin;
+ }
+ } else {
+ rv = yp_match(st->domain, map, buffer, strlen(buffer),
+ &result, &resultlen);
+ if (rv == YPERR_KEY) {
+ rv = NS_NOTFOUND;
+ continue;
+ } else if (rv != 0) {
+ free(result);
+ rv = NS_UNAVAIL;
+ continue;
+ }
+ }
+ /* We need room at least for the line, a string NUL
+ * terminator, alignment padding, and one (char *)
+ * pointer for the member list terminator.
+ */
+ if (resultlen >= bufsize - _ALIGNBYTES - sizeof(char *)) {
+ free(result);
+ goto erange;
+ }
+ memcpy(buffer, result, resultlen);
+ buffer[resultlen] = '\0';
+ free(result);
+ rv = __gr_match_entry(buffer, resultlen, how, name, gid);
+ if (rv == NS_SUCCESS)
+ rv = __gr_parse_entry(buffer, resultlen, grp,
+ &buffer[resultlen+1], bufsize - resultlen - 1,
+ errnop);
+ } while (how == nss_lt_all && !(rv & NS_TERMINATE));
+fin:
+ if (rv == NS_SUCCESS && retval != NULL)
+ *(struct group **)retval = grp;
+ return (rv);
+erange:
+ *errnop = ERANGE;
+ return (NS_RETURN);
+}
+#endif /* YP */
+
+
+
+/*
+ * compat backend
+ */
+static void
+compat_endstate(void *p)
+{
+ struct compat_state *st;
+
+ if (p == NULL)
+ return;
+ st = (struct compat_state *)p;
+ free(st->name);
+ if (st->fp != NULL)
+ fclose(st->fp);
+ free(p);
+}
+
+
+static int
+compat_setgrent(void *retval, void *mdata, va_list ap)
+{
+ static const ns_src compatsrc[] = {
+#ifdef YP
+ { NSSRC_NIS, NS_SUCCESS },
+#endif
+ { NULL, 0 }
+ };
+ ns_dtab dtab[] = {
+#ifdef HESIOD
+ { NSSRC_DNS, dns_setgrent, NULL },
+#endif
+#ifdef YP
+ { NSSRC_NIS, nis_setgrent, NULL },
+#endif
+ { NULL, NULL, NULL }
+ };
+ struct compat_state *st;
+ int rv, stayopen;
+
+#define set_setent(x, y) do { \
+ int i; \
+ for (i = 0; i < (int)(nitems(x) - 1); i++) \
+ x[i].mdata = (void *)y; \
+} while (0)
+
+ rv = compat_getstate(&st);
+ if (rv != 0)
+ return (NS_UNAVAIL);
+ switch ((enum constants)mdata) {
+ case SETGRENT:
+ stayopen = va_arg(ap, int);
+ if (st->fp != NULL)
+ rewind(st->fp);
+ else if (stayopen)
+ st->fp = fopen(_PATH_GROUP, "re");
+ set_setent(dtab, mdata);
+ (void)_nsdispatch(NULL, dtab, NSDB_GROUP_COMPAT, "setgrent",
+ compatsrc, 0);
+ break;
+ case ENDGRENT:
+ if (st->fp != NULL) {
+ fclose(st->fp);
+ st->fp = NULL;
+ }
+ set_setent(dtab, mdata);
+ (void)_nsdispatch(NULL, dtab, NSDB_GROUP_COMPAT, "endgrent",
+ compatsrc, 0);
+ break;
+ default:
+ break;
+ }
+ st->compat = COMPAT_MODE_OFF;
+ free(st->name);
+ st->name = NULL;
+ return (NS_UNAVAIL);
+#undef set_setent
+}
+
+
+static int
+compat_group(void *retval, void *mdata, va_list ap)
+{
+ static const ns_src compatsrc[] = {
+#ifdef YP
+ { NSSRC_NIS, NS_SUCCESS },
+#endif
+ { NULL, 0 }
+ };
+ ns_dtab dtab[] = {
+#ifdef YP
+ { NSSRC_NIS, nis_group, NULL },
+#endif
+#ifdef HESIOD
+ { NSSRC_DNS, dns_group, NULL },
+#endif
+ { NULL, NULL, NULL }
+ };
+ struct compat_state *st;
+ enum nss_lookup_type how;
+ const char *name, *line;
+ struct group *grp;
+ gid_t gid;
+ char *buffer, *p;
+ void *discard;
+ size_t bufsize, linesize;
+ off_t pos;
+ int rv, stayopen, *errnop;
+
+#define set_lookup_type(x, y) do { \
+ int i; \
+ for (i = 0; i < (int)(nitems(x) - 1); i++) \
+ x[i].mdata = (void *)y; \
+} while (0)
+
+ name = NULL;
+ gid = (gid_t)-1;
+ how = (enum nss_lookup_type)mdata;
+ switch (how) {
+ case nss_lt_name:
+ name = va_arg(ap, const char *);
+ break;
+ case nss_lt_id:
+ gid = va_arg(ap, gid_t);
+ break;
+ case nss_lt_all:
+ break;
+ default:
+ return (NS_NOTFOUND);
+ }
+ grp = va_arg(ap, struct group *);
+ buffer = va_arg(ap, char *);
+ bufsize = va_arg(ap, size_t);
+ errnop = va_arg(ap, int *);
+ *errnop = compat_getstate(&st);
+ if (*errnop != 0)
+ return (NS_UNAVAIL);
+ if (st->fp == NULL &&
+ ((st->fp = fopen(_PATH_GROUP, "re")) == NULL)) {
+ *errnop = errno;
+ rv = NS_UNAVAIL;
+ goto fin;
+ }
+ if (how == nss_lt_all)
+ stayopen = 1;
+ else {
+ rewind(st->fp);
+ stayopen = st->stayopen;
+ }
+docompat:
+ switch (st->compat) {
+ case COMPAT_MODE_ALL:
+ set_lookup_type(dtab, how);
+ switch (how) {
+ case nss_lt_all:
+ rv = _nsdispatch(&discard, dtab, NSDB_GROUP_COMPAT,
+ "getgrent_r", compatsrc, grp, buffer, bufsize,
+ errnop);
+ break;
+ case nss_lt_id:
+ rv = _nsdispatch(&discard, dtab, NSDB_GROUP_COMPAT,
+ "getgrgid_r", compatsrc, gid, grp, buffer, bufsize,
+ errnop);
+ break;
+ case nss_lt_name:
+ rv = _nsdispatch(&discard, dtab, NSDB_GROUP_COMPAT,
+ "getgrnam_r", compatsrc, name, grp, buffer,
+ bufsize, errnop);
+ break;
+ }
+ if (rv & NS_TERMINATE)
+ goto fin;
+ st->compat = COMPAT_MODE_OFF;
+ break;
+ case COMPAT_MODE_NAME:
+ set_lookup_type(dtab, nss_lt_name);
+ rv = _nsdispatch(&discard, dtab, NSDB_GROUP_COMPAT,
+ "getgrnam_r", compatsrc, st->name, grp, buffer, bufsize,
+ errnop);
+ switch (rv) {
+ case NS_SUCCESS:
+ switch (how) {
+ case nss_lt_name:
+ if (strcmp(name, grp->gr_name) != 0)
+ rv = NS_NOTFOUND;
+ break;
+ case nss_lt_id:
+ if (gid != grp->gr_gid)
+ rv = NS_NOTFOUND;
+ break;
+ default:
+ break;
+ }
+ break;
+ case NS_RETURN:
+ goto fin;
+ default:
+ break;
+ }
+ free(st->name);
+ st->name = NULL;
+ st->compat = COMPAT_MODE_OFF;
+ if (rv == NS_SUCCESS)
+ goto fin;
+ break;
+ default:
+ break;
+ }
+ rv = NS_NOTFOUND;
+ pos = ftello(st->fp);
+ while ((line = fgetln(st->fp, &linesize)) != NULL) {
+ if (line[linesize-1] == '\n')
+ linesize--;
+ if (linesize > 2 && line[0] == '+') {
+ p = memchr(&line[1], ':', linesize);
+ if (p == NULL || p == &line[1])
+ st->compat = COMPAT_MODE_ALL;
+ else {
+ st->name = malloc(p - line);
+ if (st->name == NULL) {
+ syslog(LOG_ERR,
+ "getgrent memory allocation failure");
+ *errnop = ENOMEM;
+ rv = NS_UNAVAIL;
+ break;
+ }
+ memcpy(st->name, &line[1], p - line - 1);
+ st->name[p - line - 1] = '\0';
+ st->compat = COMPAT_MODE_NAME;
+ }
+ goto docompat;
+ }
+ rv = __gr_match_entry(line, linesize, how, name, gid);
+ if (rv != NS_SUCCESS)
+ continue;
+ /* We need room at least for the line, a string NUL
+ * terminator, alignment padding, and one (char *)
+ * pointer for the member list terminator.
+ */
+ if (bufsize <= linesize + _ALIGNBYTES + sizeof(char *)) {
+ *errnop = ERANGE;
+ rv = NS_RETURN;
+ break;
+ }
+ memcpy(buffer, line, linesize);
+ buffer[linesize] = '\0';
+ rv = __gr_parse_entry(buffer, linesize, grp,
+ &buffer[linesize + 1], bufsize - linesize - 1, errnop);
+ if (rv & NS_TERMINATE)
+ break;
+ pos = ftello(st->fp);
+ }
+fin:
+ if (st->fp != NULL && !stayopen) {
+ fclose(st->fp);
+ st->fp = NULL;
+ }
+ if (rv == NS_SUCCESS && retval != NULL)
+ *(struct group **)retval = grp;
+ else if (rv == NS_RETURN && *errnop == ERANGE && st->fp != NULL)
+ fseeko(st->fp, pos, SEEK_SET);
+ return (rv);
+#undef set_lookup_type
+}
+
+
+/*
+ * common group line matching and parsing
+ */
+int
+__gr_match_entry(const char *line, size_t linesize, enum nss_lookup_type how,
+ const char *name, gid_t gid)
+{
+ size_t namesize;
+ const char *p, *eol;
+ char *q;
+ unsigned long n;
+ int i, needed;
+
+ if (linesize == 0 || is_comment_line(line, linesize))
+ return (NS_NOTFOUND);
+ switch (how) {
+ case nss_lt_name: needed = 1; break;
+ case nss_lt_id: needed = 2; break;
+ default: needed = 2; break;
+ }
+ eol = &line[linesize];
+ for (p = line, i = 0; i < needed && p < eol; p++)
+ if (*p == ':')
+ i++;
+ if (i < needed)
+ return (NS_NOTFOUND);
+ switch (how) {
+ case nss_lt_name:
+ namesize = strlen(name);
+ if (namesize + 1 == (size_t)(p - line) &&
+ memcmp(line, name, namesize) == 0)
+ return (NS_SUCCESS);
+ break;
+ case nss_lt_id:
+ n = strtoul(p, &q, 10);
+ if (q < eol && *q == ':' && gid == (gid_t)n)
+ return (NS_SUCCESS);
+ break;
+ case nss_lt_all:
+ return (NS_SUCCESS);
+ default:
+ break;
+ }
+ return (NS_NOTFOUND);
+}
+
+
+int
+__gr_parse_entry(char *line, size_t linesize, struct group *grp, char *membuf,
+ size_t membufsize, int *errnop)
+{
+ char *s_gid, *s_mem, *p, **members;
+ unsigned long n;
+ int maxmembers;
+
+ memset(grp, 0, sizeof(*grp));
+ members = (char **)_ALIGN(membuf);
+ membufsize -= (char *)members - membuf;
+ maxmembers = membufsize / sizeof(*members);
+ if (maxmembers <= 0 ||
+ (grp->gr_name = strsep(&line, ":")) == NULL ||
+ grp->gr_name[0] == '\0' ||
+ (grp->gr_passwd = strsep(&line, ":")) == NULL ||
+ (s_gid = strsep(&line, ":")) == NULL ||
+ s_gid[0] == '\0')
+ return (NS_NOTFOUND);
+ s_mem = line;
+ n = strtoul(s_gid, &s_gid, 10);
+ if (s_gid[0] != '\0')
+ return (NS_NOTFOUND);
+ grp->gr_gid = (gid_t)n;
+ grp->gr_mem = members;
+ while (maxmembers > 1 && s_mem != NULL) {
+ p = strsep(&s_mem, ",");
+ if (p != NULL && *p != '\0') {
+ *members++ = p;
+ maxmembers--;
+ }
+ }
+ *members = NULL;
+ if (s_mem == NULL)
+ return (NS_SUCCESS);
+ else {
+ *errnop = ERANGE;
+ return (NS_RETURN);
+ }
+}
+
+
diff --git a/lib/libc/gen/getgrouplist.3 b/lib/libc/gen/getgrouplist.3
new file mode 100644
index 000000000000..b0e116fa7453
--- /dev/null
+++ b/lib/libc/gen/getgrouplist.3
@@ -0,0 +1,82 @@
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)getgrouplist.3 8.1 (Berkeley) 6/9/93
+.\" $FreeBSD$
+.\"
+.Dd October 26, 2014
+.Dt GETGROUPLIST 3
+.Os
+.Sh NAME
+.Nm getgrouplist
+.Nd calculate group access list
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft int
+.Fn getgrouplist "const char *name" "gid_t basegid" "gid_t *groups" "int *ngroups"
+.Sh DESCRIPTION
+The
+.Fn getgrouplist
+function reads through the group file and calculates
+the group access list for the user specified in
+.Fa name .
+The
+.Fa basegid
+is automatically included in the groups list.
+Typically this value is given as
+the group number from the password file.
+.Pp
+The resulting group list is returned in the array pointed to by
+.Fa groups .
+The caller specifies the size of the
+.Fa groups
+array in the integer pointed to by
+.Fa ngroups ;
+the actual number of groups found is returned in
+.Fa ngroups .
+.Sh RETURN VALUES
+The
+.Fn getgrouplist
+function
+returns 0 on success and \-1 if the size of the group list is too small to
+hold all the user's groups.
+Here, the group array will be filled with as many groups as will fit.
+.Sh FILES
+.Bl -tag -width /etc/group -compact
+.It Pa /etc/group
+group membership list
+.El
+.Sh SEE ALSO
+.Xr setgroups 2 ,
+.Xr initgroups 3
+.Sh HISTORY
+The
+.Fn getgrouplist
+function first appeared in
+.Bx 4.4 .
diff --git a/lib/libc/gen/getgrouplist.c b/lib/libc/gen/getgrouplist.c
new file mode 100644
index 000000000000..9eb55f9865cf
--- /dev/null
+++ b/lib/libc/gen/getgrouplist.c
@@ -0,0 +1,52 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)getgrouplist.c 8.2 (Berkeley) 12/8/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * get credential
+ */
+#include <sys/types.h>
+
+#include <grp.h>
+#include <string.h>
+#include <unistd.h>
+
+extern int __getgroupmembership(const char *, gid_t, gid_t *, int, int *);
+
+int
+getgrouplist(const char *uname, gid_t agroup, gid_t *groups, int *grpcnt)
+{
+ return __getgroupmembership(uname, agroup, groups, *grpcnt, grpcnt);
+}
+
diff --git a/lib/libc/gen/gethostname.3 b/lib/libc/gen/gethostname.3
new file mode 100644
index 000000000000..00853ef1b32e
--- /dev/null
+++ b/lib/libc/gen/gethostname.3
@@ -0,0 +1,131 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)gethostname.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd August 18, 2003
+.Dt GETHOSTNAME 3
+.Os
+.Sh NAME
+.Nm gethostname ,
+.Nm sethostname
+.Nd get/set name of current host
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft int
+.Fn gethostname "char *name" "size_t namelen"
+.Ft int
+.Fn sethostname "const char *name" "int namelen"
+.Sh DESCRIPTION
+The
+.Fn gethostname
+function
+returns the standard host name for the current processor, as
+previously set by
+.Fn sethostname .
+The
+.Fa namelen
+argument
+specifies the size of the
+.Fa name
+array.
+The returned name is null-terminated unless insufficient space is provided.
+.Pp
+The
+.Fn sethostname
+function
+sets the name of the host machine to be
+.Fa name ,
+which has length
+.Fa namelen .
+This call is restricted to the super-user and
+is normally used only when the system is bootstrapped.
+.Pp
+Host names are limited to
+.Brq Dv HOST_NAME_MAX
+characters, not including the trailing null, currently 255.
+.Sh RETURN VALUES
+.Rv -std
+.Sh ERRORS
+The following errors may be returned by these calls:
+.Bl -tag -width Er
+.It Bq Er EFAULT
+The
+.Fa name
+or
+.Fa namelen
+argument gave an
+invalid address.
+.It Bq Er ENAMETOOLONG
+The current host name is longer than
+.Fa namelen .
+(For
+.Fn gethostname
+only.)
+.It Bq Er EPERM
+The caller tried to set the host name and was not the super-user.
+.El
+.Sh SEE ALSO
+.Xr sysconf 3 ,
+.Xr sysctl 3
+.Sh STANDARDS
+The
+.Fn gethostname
+function conforms to
+.St -p1003.1-2001 .
+Callers should be aware that
+.Brq Dv HOST_NAME_MAX
+may be variable or infinite, but is guaranteed to be no less than
+.Brq Dv _POSIX_HOST_NAME_MAX .
+On older systems, this limit was defined in the non-standard header
+.In sys/param.h
+as
+.Dv MAXHOSTNAMELEN ,
+and counted the terminating null.
+The
+.Fn sethostname
+function and the error returns for
+.Fn gethostname
+are not standardized.
+.Sh HISTORY
+The
+.Fn gethostname
+function appeared in
+.Bx 4.2 .
+The
+.Fa namelen
+argument to
+.Fn gethostname
+was changed to
+.Vt size_t
+in
+.Fx 5.2
+for alignment with
+.St -p1003.1-2001 .
diff --git a/lib/libc/gen/gethostname.c b/lib/libc/gen/gethostname.c
new file mode 100644
index 000000000000..dc2b372a8ea5
--- /dev/null
+++ b/lib/libc/gen/gethostname.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)gethostname.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/sysctl.h>
+
+#include <errno.h>
+#include <unistd.h>
+
+int
+gethostname(char *name, size_t namelen)
+{
+ int mib[2];
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_HOSTNAME;
+ if (sysctl(mib, 2, name, &namelen, NULL, 0) == -1) {
+ if (errno == ENOMEM)
+ errno = ENAMETOOLONG;
+ return (-1);
+ }
+ return (0);
+}
diff --git a/lib/libc/gen/getloadavg.3 b/lib/libc/gen/getloadavg.3
new file mode 100644
index 000000000000..5a77ecbd149e
--- /dev/null
+++ b/lib/libc/gen/getloadavg.3
@@ -0,0 +1,65 @@
+.\" Copyright (c) 1989, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)getloadavg.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt GETLOADAVG 3
+.Os
+.Sh NAME
+.Nm getloadavg
+.Nd get system load averages
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft int
+.Fn getloadavg "double loadavg[]" "int nelem"
+.Sh DESCRIPTION
+The
+.Fn getloadavg
+function returns the number of processes in the system run queue
+averaged over various periods of time.
+Up to
+.Fa nelem
+samples are retrieved and assigned to successive elements of
+.Fa loadavg Ns Bq .
+The system imposes a maximum of 3 samples, representing averages
+over the last 1, 5, and 15 minutes, respectively.
+.Sh DIAGNOSTICS
+If the load average was unobtainable, \-1 is returned; otherwise,
+the number of samples actually retrieved is returned.
+.Sh SEE ALSO
+.Xr uptime 1 ,
+.Xr kvm_getloadavg 3 ,
+.Xr sysctl 3
+.Sh HISTORY
+The
+.Fn getloadavg
+function appeared in
+.Bx 4.3 Reno .
diff --git a/lib/libc/gen/getloadavg.c b/lib/libc/gen/getloadavg.c
new file mode 100644
index 000000000000..9c06d0a4d986
--- /dev/null
+++ b/lib/libc/gen/getloadavg.c
@@ -0,0 +1,67 @@
+/*-
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)getloadavg.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/sysctl.h>
+#include <vm/vm_param.h>
+
+#include <stdlib.h>
+
+/*
+ * getloadavg() -- Get system load averages.
+ *
+ * Put `nelem' samples into `loadavg' array.
+ * Return number of samples retrieved, or -1 on error.
+ */
+int
+getloadavg(double loadavg[], int nelem)
+{
+ struct loadavg loadinfo;
+ int i, mib[2];
+ size_t size;
+
+ mib[0] = CTL_VM;
+ mib[1] = VM_LOADAVG;
+ size = sizeof(loadinfo);
+ if (sysctl(mib, 2, &loadinfo, &size, NULL, 0) < 0)
+ return (-1);
+
+ nelem = MIN(nelem, sizeof(loadinfo.ldavg) / sizeof(fixpt_t));
+ for (i = 0; i < nelem; i++)
+ loadavg[i] = (double) loadinfo.ldavg[i] / loadinfo.fscale;
+ return (nelem);
+}
diff --git a/lib/libc/gen/getlogin.c b/lib/libc/gen/getlogin.c
new file mode 100644
index 000000000000..7ab4cba88a48
--- /dev/null
+++ b/lib/libc/gen/getlogin.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)getlogin.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <errno.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include "namespace.h"
+#include <pthread.h>
+#include "un-namespace.h"
+
+#include "libc_private.h"
+
+#define THREAD_LOCK() if (__isthreaded) _pthread_mutex_lock(&logname_mutex)
+#define THREAD_UNLOCK() if (__isthreaded) _pthread_mutex_unlock(&logname_mutex)
+
+extern int _getlogin(char *, int);
+
+int _logname_valid __hidden; /* known to setlogin() */
+static pthread_mutex_t logname_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static char *
+getlogin_basic(int *status)
+{
+ static char logname[MAXLOGNAME];
+
+ if (_logname_valid == 0) {
+ if (_getlogin(logname, sizeof(logname)) < 0) {
+ *status = errno;
+ return (NULL);
+ }
+ _logname_valid = 1;
+ }
+ *status = 0;
+ return (*logname ? logname : NULL);
+}
+
+char *
+getlogin(void)
+{
+ char *result;
+ int status;
+
+ THREAD_LOCK();
+ result = getlogin_basic(&status);
+ THREAD_UNLOCK();
+ return (result);
+}
+
+int
+getlogin_r(char *logname, int namelen)
+{
+ char *result;
+ int len;
+ int status;
+
+ if (namelen < 1)
+ return (ERANGE);
+ logname[0] = '\0';
+
+ THREAD_LOCK();
+ result = getlogin_basic(&status);
+ if (status == 0 && result != NULL) {
+ len = strlen(result) + 1;
+ if (len > namelen)
+ status = ERANGE;
+ else
+ strncpy(logname, result, len);
+ }
+ THREAD_UNLOCK();
+ return (status);
+}
diff --git a/lib/libc/gen/getmntinfo.3 b/lib/libc/gen/getmntinfo.3
new file mode 100644
index 000000000000..0e9601c3ccd4
--- /dev/null
+++ b/lib/libc/gen/getmntinfo.3
@@ -0,0 +1,109 @@
+.\" Copyright (c) 1989, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)getmntinfo.3 8.1 (Berkeley) 6/9/93
+.\" $FreeBSD$
+.\"
+.Dd December 27, 2016
+.Dt GETMNTINFO 3
+.Os
+.Sh NAME
+.Nm getmntinfo
+.Nd get information about mounted file systems
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/param.h
+.In sys/ucred.h
+.In sys/mount.h
+.Ft int
+.Fn getmntinfo "struct statfs **mntbufp" "int mode"
+.Sh DESCRIPTION
+The
+.Fn getmntinfo
+function
+returns an array of
+.Fn statfs
+structures describing each currently mounted file system (see
+.Xr statfs 2 ) .
+.Pp
+The
+.Fn getmntinfo
+function
+passes its
+.Fa mode
+argument transparently to
+.Xr getfsstat 2 .
+.Sh RETURN VALUES
+On successful completion,
+.Fn getmntinfo
+returns a count of the number of elements in the array.
+The pointer to the array is stored into
+.Fa mntbufp .
+.Pp
+If an error occurs, zero is returned and the external variable
+.Va errno
+is set to indicate the error.
+Although the pointer
+.Fa mntbufp
+will be unmodified, any information previously returned by
+.Fn getmntinfo
+will be lost.
+.Sh ERRORS
+The
+.Fn getmntinfo
+function
+may fail and set errno for any of the errors specified for the library
+routines
+.Xr getfsstat 2
+or
+.Xr malloc 3 .
+.Sh SEE ALSO
+.Xr getfsstat 2 ,
+.Xr mount 2 ,
+.Xr statfs 2 ,
+.Xr mount 8
+.Sh HISTORY
+The
+.Fn getmntinfo
+function first appeared in
+.Bx 4.4 .
+.Sh BUGS
+The
+.Fn getmntinfo
+function writes the array of structures to an internal static object
+and returns
+a pointer to that object.
+Subsequent calls to
+.Fn getmntinfo
+will modify the same object.
+.Pp
+The memory allocated by
+.Fn getmntinfo
+cannot be
+.Xr free 3 Ns 'd
+by the application.
diff --git a/lib/libc/gen/getmntinfo.c b/lib/libc/gen/getmntinfo.c
new file mode 100644
index 000000000000..692d8f1de0bf
--- /dev/null
+++ b/lib/libc/gen/getmntinfo.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)getmntinfo.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/ucred.h>
+#include <sys/mount.h>
+#include <stdlib.h>
+
+/*
+ * Return information about mounted filesystems.
+ */
+int
+getmntinfo(struct statfs **mntbufp, int mode)
+{
+ static struct statfs *mntbuf;
+ static int mntsize;
+ static long bufsize;
+
+ if (mntsize <= 0 && (mntsize = getfsstat(0, 0, MNT_NOWAIT)) < 0)
+ return (0);
+ if (bufsize > 0 && (mntsize = getfsstat(mntbuf, bufsize, mode)) < 0)
+ return (0);
+ while (bufsize <= mntsize * sizeof(struct statfs)) {
+ if (mntbuf)
+ free(mntbuf);
+ bufsize = (mntsize + 1) * sizeof(struct statfs);
+ if ((mntbuf = malloc(bufsize)) == NULL)
+ return (0);
+ if ((mntsize = getfsstat(mntbuf, bufsize, mode)) < 0)
+ return (0);
+ }
+ *mntbufp = mntbuf;
+ return (mntsize);
+}
diff --git a/lib/libc/gen/getnetgrent.3 b/lib/libc/gen/getnetgrent.3
new file mode 100644
index 000000000000..8547e66cf443
--- /dev/null
+++ b/lib/libc/gen/getnetgrent.3
@@ -0,0 +1,133 @@
+.\" Copyright (c) 1992, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)getnetgrent.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 5, 2016
+.Dt GETNETGRENT 3
+.Os
+.Sh NAME
+.Nm getnetgrent ,
+.Nm innetgr ,
+.Nm setnetgrent ,
+.Nm endnetgrent
+.Nd netgroup database operations
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In netdb.h
+.Ft int
+.Fn getnetgrent "char **host" "char **user" "char **domain"
+.Ft int
+.Fn getnetgrent_r "char **host" "char **user" "char **domain" "char *buf" "size_t bufsize"
+.Ft int
+.Fn innetgr "const char *netgroup" "const char *host" "const char *user" "const char *domain"
+.Ft void
+.Fn setnetgrent "const char *netgroup"
+.Ft void
+.Fn endnetgrent void
+.Sh DESCRIPTION
+These functions operate on the netgroup database file
+.Pa /etc/netgroup
+which is described
+in
+.Xr netgroup 5 .
+The database defines a set of netgroups, each made up of one or more triples:
+.Bd -literal -offset indent
+(host, user, domain)
+.Ed
+that defines a combination of host, user and domain.
+Any of the three fields may be specified as ``wildcards'' that match any
+string.
+.Pp
+The function
+.Fn getnetgrent
+sets the three pointer arguments to the strings of the next member of the
+current netgroup.
+If any of the string pointers are
+.Dv NULL
+that field is considered a wildcard.
+.Pp
+The functions
+.Fn setnetgrent
+and
+.Fn endnetgrent
+set the current netgroup and terminate the current netgroup respectively.
+If
+.Fn setnetgrent
+is called with a different netgroup than the previous call, an implicit
+.Fn endnetgrent
+is implied.
+The
+.Fn setnetgrent
+function
+also sets the offset to the first member of the netgroup.
+.Pp
+The function
+.Fn innetgr
+searches for a match of all fields within the specified group.
+If any of the
+.Sy host ,
+.Sy user ,
+or
+.Sy domain
+arguments are
+.Dv NULL
+those fields will match any string value in the netgroup member.
+.Sh RETURN VALUES
+The function
+.Fn getnetgrent
+returns 0 for ``no more netgroup members'' and 1 otherwise.
+The function
+.Fn innetgr
+returns 1 for a successful match and 0 otherwise.
+The functions
+.Fn setnetgrent
+and
+.Fn endnetgrent
+have no return value.
+.Sh FILES
+.Bl -tag -width /etc/netgroup -compact
+.It Pa /etc/netgroup
+netgroup database file
+.El
+.Sh COMPATIBILITY
+The netgroup members have three string fields to maintain compatibility
+with other vendor implementations, however it is not obvious what use the
+.Sy domain
+string has within
+.Bx .
+.Sh SEE ALSO
+.Xr netgroup 5
+.Sh BUGS
+The function
+.Fn getnetgrent
+returns pointers to dynamically allocated data areas that are freed when
+the function
+.Fn endnetgrent
+is called.
diff --git a/lib/libc/gen/getnetgrent.c b/lib/libc/gen/getnetgrent.c
new file mode 100644
index 000000000000..d71928e5a189
--- /dev/null
+++ b/lib/libc/gen/getnetgrent.c
@@ -0,0 +1,1016 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Rick Macklem at The University of Guelph.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)getnetgrent.c 8.2 (Berkeley) 4/27/95";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+
+#include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+#include <nsswitch.h>
+#include <pthread.h>
+#include <pthread_np.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "nss_tls.h"
+
+#ifdef YP
+/*
+ * Notes:
+ * We want to be able to use NIS netgroups properly while retaining
+ * the ability to use a local /etc/netgroup file. Unfortunately, you
+ * can't really do both at the same time - at least, not efficiently.
+ * NetBSD deals with this problem by creating a netgroup database
+ * using Berkeley DB (just like the password database) that allows
+ * for lookups using netgroup, netgroup.byuser or netgroup.byhost
+ * searches. This is a neat idea, but I don't have time to implement
+ * something like that now. (I think ultimately it would be nice
+ * if we DB-fied the group and netgroup stuff all in one shot, but
+ * for now I'm satisfied just to have something that works well
+ * without requiring massive code changes.)
+ *
+ * Therefore, to still permit the use of the local file and maintain
+ * optimum NIS performance, we allow for the following conditions:
+ *
+ * - If /etc/netgroup does not exist and NIS is turned on, we use
+ * NIS netgroups only.
+ *
+ * - If /etc/netgroup exists but is empty, we use NIS netgroups
+ * only.
+ *
+ * - If /etc/netgroup exists and contains _only_ a '+', we use
+ * NIS netgroups only.
+ *
+ * - If /etc/netgroup exists, contains locally defined netgroups
+ * and a '+', we use a mixture of NIS and the local entries.
+ * This method should return the same NIS data as just using
+ * NIS alone, but it will be slower if the NIS netgroup database
+ * is large (innetgr() in particular will suffer since extra
+ * processing has to be done in order to determine memberships
+ * using just the raw netgroup data).
+ *
+ * - If /etc/netgroup exists and contains only locally defined
+ * netgroup entries, we use just those local entries and ignore
+ * NIS (this is the original, pre-NIS behavior).
+ */
+
+#include <rpc/rpc.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/errno.h>
+static char *_netgr_yp_domain;
+int _use_only_yp;
+static int _netgr_yp_enabled;
+static int _yp_innetgr;
+#endif
+
+#ifndef _PATH_NETGROUP
+#define _PATH_NETGROUP "/etc/netgroup"
+#endif
+
+enum constants {
+ NGRP_STORAGE_INITIAL = 1 << 10, /* 1 KByte */
+ NGRP_STORAGE_MAX = 1 << 20, /* 1 MByte */
+};
+
+static const ns_src defaultsrc[] = {
+ { NSSRC_COMPAT, NS_SUCCESS },
+ { NULL, 0 },
+};
+
+/*
+ * Static Variables and functions used by setnetgrent(), getnetgrent() and
+ * endnetgrent().
+ * There are two linked lists:
+ * - linelist is just used by setnetgrent() to parse the net group file via.
+ * parse_netgrp()
+ * - netgrp is the list of entries for the current netgroup
+ */
+struct linelist {
+ struct linelist *l_next; /* Chain ptr. */
+ int l_parsed; /* Flag for cycles */
+ char *l_groupname; /* Name of netgroup */
+ char *l_line; /* Netgroup entrie(s) to be parsed */
+};
+
+struct netgrp {
+ struct netgrp *ng_next; /* Chain ptr */
+ char *ng_str[3]; /* Field pointers, see below */
+};
+
+struct netgr_state {
+ FILE *st_netf;
+ struct linelist *st_linehead;
+ struct netgrp *st_nextgrp;
+ struct netgrp *st_gr;
+ char *st_grname;
+};
+
+#define NG_HOST 0 /* Host name */
+#define NG_USER 1 /* User name */
+#define NG_DOM 2 /* and Domain name */
+
+static void netgr_endstate(void *);
+NSS_TLS_HANDLING(netgr);
+
+static int files_endnetgrent(void *, void *, va_list);
+static int files_getnetgrent_r(void *, void *, va_list);
+static int files_setnetgrent(void *, void *, va_list);
+
+static int compat_endnetgrent(void *, void *, va_list);
+static int compat_innetgr(void *, void *, va_list);
+static int compat_getnetgrent_r(void *, void *, va_list);
+static int compat_setnetgrent(void *, void *, va_list);
+
+static void _compat_clearstate(void);
+static int _getnetgrent_r(char **, char **, char **, char *, size_t, int *,
+ struct netgr_state *);
+static int _innetgr_fallback(void *, void *, const char *, const char *,
+ const char *, const char *);
+static int innetgr_fallback(void *, void *, va_list);
+static int parse_netgrp(const char *, struct netgr_state *, int);
+static struct linelist *read_for_group(const char *, struct netgr_state *, int);
+
+#define LINSIZ 1024 /* Length of netgroup file line */
+
+static const ns_dtab getnetgrent_dtab[] = {
+ NS_FILES_CB(files_getnetgrent_r, NULL)
+ NS_COMPAT_CB(compat_getnetgrent_r, NULL)
+ { NULL, NULL, NULL },
+};
+
+static const ns_dtab setnetgrent_dtab[] = {
+ NS_FILES_CB(files_setnetgrent, NULL)
+ NS_COMPAT_CB(compat_setnetgrent, NULL)
+ { NULL, NULL, NULL },
+};
+
+static const ns_dtab endnetgrent_dtab[] = {
+ NS_FILES_CB(files_endnetgrent, NULL)
+ NS_COMPAT_CB(compat_endnetgrent, NULL)
+ { NULL, NULL, NULL },
+};
+
+static struct netgr_state compat_state;
+
+static void
+netgr_endstate(void *arg)
+{
+ struct linelist *lp, *olp;
+ struct netgrp *gp, *ogp;
+ struct netgr_state *st;
+
+ st = (struct netgr_state *)arg;
+ lp = st->st_linehead;
+ while (lp != NULL) {
+ olp = lp;
+ lp = lp->l_next;
+ free(olp->l_groupname);
+ free(olp->l_line);
+ free(olp);
+ }
+ st->st_linehead = NULL;
+ if (st->st_grname != NULL) {
+ free(st->st_grname);
+ st->st_grname = NULL;
+ }
+ gp = st->st_gr;
+ while (gp != NULL) {
+ ogp = gp;
+ gp = gp->ng_next;
+ free(ogp->ng_str[NG_HOST]);
+ free(ogp->ng_str[NG_USER]);
+ free(ogp->ng_str[NG_DOM]);
+ free(ogp);
+ }
+ st->st_gr = NULL;
+ st->st_nextgrp = NULL;
+}
+
+static int
+files_getnetgrent_r(void *retval, void *mdata, va_list ap)
+{
+ struct netgr_state *st;
+ char **hostp, **userp, **domp, *buf;
+ size_t bufsize;
+ int *errnop;
+
+ hostp = va_arg(ap, char **);
+ userp = va_arg(ap, char **);
+ domp = va_arg(ap, char **);
+ buf = va_arg(ap, char *);
+ bufsize = va_arg(ap, size_t);
+ errnop = va_arg(ap, int *);
+
+ if (netgr_getstate(&st) != 0)
+ return (NS_UNAVAIL);
+
+ return (_getnetgrent_r(hostp, userp, domp, buf, bufsize, errnop, st));
+}
+
+static int
+files_setnetgrent(void *retval, void *mdata, va_list ap)
+{
+ const ns_src src[] = {
+ { NSSRC_FILES, NS_SUCCESS },
+ { NULL, 0 },
+ };
+ struct netgr_state *st;
+ const char *group;
+ int rv;
+
+ group = va_arg(ap, const char *);
+
+ if (group == NULL || group[0] == '\0')
+ return (NS_RETURN);
+
+ rv = netgr_getstate(&st);
+ if (rv != 0)
+ return (NS_UNAVAIL);
+
+ if (st->st_gr == NULL || strcmp(group, st->st_grname) != 0) {
+ (void)_nsdispatch(NULL, endnetgrent_dtab, NSDB_NETGROUP,
+ "endnetgrent", src);
+ if ((st->st_netf = fopen(_PATH_NETGROUP, "re")) != NULL) {
+ if (parse_netgrp(group, st, 0) != 0)
+ (void)_nsdispatch(NULL, endnetgrent_dtab,
+ NSDB_NETGROUP, "endnetgrent", src);
+ else
+ st->st_grname = strdup(group);
+ (void)fclose(st->st_netf);
+ st->st_netf = NULL;
+ }
+ }
+ st->st_nextgrp = st->st_gr;
+ return (st->st_grname != NULL ? NS_SUCCESS : NS_NOTFOUND);
+}
+
+static int
+files_endnetgrent(void *retval, void *mdata, va_list ap)
+{
+ struct netgr_state *st;
+
+ if (netgr_getstate(&st) != 0)
+ return (NS_UNAVAIL);
+ netgr_endstate(st);
+ return (NS_SUCCESS);
+}
+
+static int
+compat_getnetgrent_r(void *retval, void *mdata, va_list ap)
+{
+ char **hostp, **userp, **domp, *buf;
+ size_t bufsize;
+ int *errnop;
+#ifdef YP
+ _yp_innetgr = 0;
+#endif
+
+ hostp = va_arg(ap, char **);
+ userp = va_arg(ap, char **);
+ domp = va_arg(ap, char **);
+ buf = va_arg(ap, char *);
+ bufsize = va_arg(ap, size_t);
+ errnop = va_arg(ap, int *);
+
+ return (_getnetgrent_r(hostp, userp, domp, buf, bufsize, errnop,
+ &compat_state));
+}
+
+/*
+ * compat_setnetgrent()
+ * Parse the netgroup file looking for the netgroup and build the list
+ * of netgrp structures. Let parse_netgrp() and read_for_group() do
+ * most of the work.
+ */
+static int
+compat_setnetgrent(void *retval, void *mdata, va_list ap)
+{
+ FILE *netf;
+ const char *group;
+#ifdef YP
+ struct stat _yp_statp;
+ char _yp_plus;
+#endif
+
+ group = va_arg(ap, const char *);
+
+ /* Sanity check */
+ if (group == NULL || !strlen(group))
+ return (NS_RETURN);
+
+ if (compat_state.st_gr == NULL ||
+ strcmp(group, compat_state.st_grname) != 0) {
+ _compat_clearstate();
+
+#ifdef YP
+ /* Presumed guilty until proven innocent. */
+ _use_only_yp = 0;
+ /*
+ * If /etc/netgroup doesn't exist or is empty,
+ * use NIS exclusively.
+ */
+ if (((stat(_PATH_NETGROUP, &_yp_statp) < 0) &&
+ errno == ENOENT) || _yp_statp.st_size == 0)
+ _use_only_yp = _netgr_yp_enabled = 1;
+ if ((netf = fopen(_PATH_NETGROUP,"re")) != NULL ||_use_only_yp){
+ compat_state.st_netf = netf;
+ /*
+ * Icky: grab the first character of the netgroup file
+ * and turn on NIS if it's a '+'. rewind the stream
+ * afterwards so we don't goof up read_for_group() later.
+ */
+ if (netf) {
+ fscanf(netf, "%c", &_yp_plus);
+ rewind(netf);
+ if (_yp_plus == '+')
+ _use_only_yp = _netgr_yp_enabled = 1;
+ }
+ /*
+ * If we were called specifically for an innetgr()
+ * lookup and we're in NIS-only mode, short-circuit
+ * parse_netgroup() and cut directly to the chase.
+ */
+ if (_use_only_yp && _yp_innetgr) {
+ /* dohw! */
+ if (netf != NULL)
+ fclose(netf);
+ return (NS_RETURN);
+ }
+#else
+ if ((netf = fopen(_PATH_NETGROUP, "re"))) {
+ compat_state.st_netf = netf;
+#endif
+ if (parse_netgrp(group, &compat_state, 1)) {
+ _compat_clearstate();
+ } else {
+ compat_state.st_grname = strdup(group);
+ }
+ if (netf)
+ fclose(netf);
+ }
+ }
+ compat_state.st_nextgrp = compat_state.st_gr;
+ return (NS_SUCCESS);
+}
+
+static void
+_compat_clearstate(void)
+{
+
+#ifdef YP
+ _netgr_yp_enabled = 0;
+#endif
+ netgr_endstate(&compat_state);
+}
+
+/*
+ * compat_endnetgrent() - cleanup
+ */
+static int
+compat_endnetgrent(void *retval, void *mdata, va_list ap)
+{
+
+ _compat_clearstate();
+ return (NS_SUCCESS);
+}
+
+int
+_getnetgrent_r(char **hostp, char **userp, char **domp, char *buf,
+ size_t bufsize, int *errnop, struct netgr_state *st)
+{
+ char *p, *src;
+ size_t len;
+ int rv;
+
+#define COPY_NG_ELEM(dstp, i) do { \
+ src = st->st_nextgrp->ng_str[(i)]; \
+ if (src == NULL) \
+ src = ""; \
+ len = strlcpy(p, src, bufsize); \
+ if (len >= bufsize) { \
+ *errnop = ERANGE; \
+ return (NS_RETURN); \
+ } \
+ *(dstp) = p; \
+ p += len + 1; \
+ bufsize -= len + 1; \
+} while (0)
+
+ p = buf;
+ if (st->st_nextgrp != NULL) {
+ COPY_NG_ELEM(hostp, NG_HOST);
+ COPY_NG_ELEM(userp, NG_USER);
+ COPY_NG_ELEM(domp, NG_DOM);
+ st->st_nextgrp = st->st_nextgrp->ng_next;
+ rv = NS_SUCCESS;
+ } else {
+ rv = NS_NOTFOUND;
+ }
+#undef COPY_NG_ELEM
+
+ return (rv);
+}
+
+#ifdef YP
+static int
+_listmatch(const char *list, const char *group, int len)
+{
+ const char *ptr = list;
+ const char *cptr;
+ int glen = strlen(group);
+
+ /* skip possible leading whitespace */
+ while (isspace((unsigned char)*ptr))
+ ptr++;
+
+ while (ptr < list + len) {
+ cptr = ptr;
+ while(*ptr != ',' && *ptr != '\0' && !isspace((unsigned char)*ptr))
+ ptr++;
+ if (strncmp(cptr, group, glen) == 0 && glen == (ptr - cptr))
+ return (1);
+ while (*ptr == ',' || isspace((unsigned char)*ptr))
+ ptr++;
+ }
+
+ return (0);
+}
+
+static int
+_revnetgr_lookup(char* lookupdom, char* map, const char* str,
+ const char* dom, const char* group)
+{
+ int y, rv, rot;
+ char key[MAXHOSTNAMELEN];
+ char *result;
+ int resultlen;
+
+ for (rot = 0; ; rot++) {
+ switch (rot) {
+ case 0:
+ snprintf(key, MAXHOSTNAMELEN, "%s.%s", str,
+ dom ? dom : lookupdom);
+ break;
+ case 1:
+ snprintf(key, MAXHOSTNAMELEN, "%s.*", str);
+ break;
+ case 2:
+ snprintf(key, MAXHOSTNAMELEN, "*.%s",
+ dom ? dom : lookupdom);
+ break;
+ case 3:
+ snprintf(key, MAXHOSTNAMELEN, "*.*");
+ break;
+ default:
+ return (0);
+ }
+ y = yp_match(lookupdom, map, key, strlen(key), &result,
+ &resultlen);
+ if (y == 0) {
+ rv = _listmatch(result, group, resultlen);
+ free(result);
+ if (rv)
+ return (1);
+ } else if (y != YPERR_KEY) {
+ /*
+ * If we get an error other than 'no
+ * such key in map' then something is
+ * wrong and we should stop the search.
+ */
+ return (-1);
+ }
+ }
+}
+#endif
+
+/*
+ * Search for a match in a netgroup.
+ */
+static int
+compat_innetgr(void *retval, void *mdata, va_list ap)
+{
+#ifdef YP
+ const ns_src src[] = {
+ { mdata, NS_SUCCESS },
+ { NULL, 0 },
+ };
+#endif
+ const char *group, *host, *user, *dom;
+
+ group = va_arg(ap, const char *);
+ host = va_arg(ap, const char *);
+ user = va_arg(ap, const char *);
+ dom = va_arg(ap, const char *);
+
+ if (group == NULL || !strlen(group))
+ return (NS_RETURN);
+
+#ifdef YP
+ _yp_innetgr = 1;
+ (void)_nsdispatch(NULL, setnetgrent_dtab, NSDB_NETGROUP, "setnetgrent",
+ src, group);
+ _yp_innetgr = 0;
+ /*
+ * If we're in NIS-only mode, do the search using
+ * NIS 'reverse netgroup' lookups.
+ *
+ * What happens with 'reverse netgroup' lookups:
+ *
+ * 1) try 'reverse netgroup' lookup
+ * 1.a) if host is specified and user is null:
+ * look in netgroup.byhost
+ * (try host.domain, host.*, *.domain or *.*)
+ * if found, return yes
+ * 1.b) if user is specified and host is null:
+ * look in netgroup.byuser
+ * (try host.domain, host.*, *.domain or *.*)
+ * if found, return yes
+ * 1.c) if both host and user are specified,
+ * don't do 'reverse netgroup' lookup. It won't work.
+ * 1.d) if neither host ane user are specified (why?!?)
+ * don't do 'reverse netgroup' lookup either.
+ * 2) if domain is specified and 'reverse lookup' is done:
+ * 'reverse lookup' was authoritative. bye bye.
+ * 3) otherwise, too bad, try it the slow way.
+ */
+ if (_use_only_yp && (host == NULL) != (user == NULL)) {
+ int ret;
+ if(yp_get_default_domain(&_netgr_yp_domain))
+ return (NS_NOTFOUND);
+ ret = _revnetgr_lookup(_netgr_yp_domain,
+ host?"netgroup.byhost":"netgroup.byuser",
+ host?host:user, dom, group);
+ if (ret == 1) {
+ *(int *)retval = 1;
+ return (NS_SUCCESS);
+ } else if (ret == 0 && dom != NULL) {
+ *(int *)retval = 0;
+ return (NS_SUCCESS);
+ }
+ }
+#endif /* YP */
+
+ return (_innetgr_fallback(retval, mdata, group, host, user, dom));
+}
+
+static int
+_innetgr_fallback(void *retval, void *mdata, const char *group, const char *host,
+ const char *user, const char *dom)
+{
+ const ns_src src[] = {
+ { mdata, NS_SUCCESS },
+ { NULL, 0 },
+ };
+ char *h, *u, *d;
+ char *buf;
+ size_t bufsize;
+ int rv, ret_errno;
+
+ if (group == NULL || group[0] == '\0')
+ return (NS_RETURN);
+
+ bufsize = NGRP_STORAGE_INITIAL;
+ buf = malloc(bufsize);
+ if (buf == NULL)
+ return (NS_UNAVAIL);
+
+ *(int *)retval = 0;
+
+ (void)_nsdispatch(NULL, setnetgrent_dtab, NSDB_NETGROUP, "setnetgrent",
+ src, group);
+
+ for (;;) {
+ do {
+ ret_errno = 0;
+ rv = _nsdispatch(NULL, getnetgrent_dtab, NSDB_NETGROUP,
+ "getnetgrent_r", src, &h, &u, &d, buf, bufsize,
+ &ret_errno);
+ if (rv != NS_SUCCESS && ret_errno == ERANGE) {
+ bufsize *= 2;
+ if (bufsize > NGRP_STORAGE_MAX ||
+ (buf = reallocf(buf, bufsize)) == NULL)
+ goto out;
+ }
+ } while (rv != NS_SUCCESS && ret_errno == ERANGE);
+
+ if (rv != NS_SUCCESS) {
+ if (rv == NS_NOTFOUND && ret_errno == 0)
+ rv = NS_SUCCESS;
+ break;
+ }
+
+ if ((host == NULL || h == NULL || strcmp(host, h) == 0) &&
+ (user == NULL || u == NULL || strcmp(user, u) == 0) &&
+ (dom == NULL || d == NULL || strcmp(dom, d) == 0)) {
+ *(int *)retval = 1;
+ break;
+ }
+ }
+
+out:
+ free(buf);
+ (void)_nsdispatch(NULL, endnetgrent_dtab, NSDB_NETGROUP, "endnetgrent",
+ src);
+ return (rv);
+}
+
+static int
+innetgr_fallback(void *retval, void *mdata, va_list ap)
+{
+ const char *group, *host, *user, *dom;
+
+ group = va_arg(ap, const char *);
+ host = va_arg(ap, const char *);
+ user = va_arg(ap, const char *);
+ dom = va_arg(ap, const char *);
+
+ return (_innetgr_fallback(retval, mdata, group, host, user, dom));
+}
+
+/*
+ * Parse the netgroup file setting up the linked lists.
+ */
+static int
+parse_netgrp(const char *group, struct netgr_state *st, int niscompat)
+{
+ struct netgrp *grp;
+ struct linelist *lp = st->st_linehead;
+ char **ng;
+ char *epos, *gpos, *pos, *spos;
+ int freepos, len, strpos;
+#ifdef DEBUG
+ int fields;
+#endif
+
+ /*
+ * First, see if the line has already been read in.
+ */
+ while (lp) {
+ if (!strcmp(group, lp->l_groupname))
+ break;
+ lp = lp->l_next;
+ }
+ if (lp == NULL && (lp = read_for_group(group, st, niscompat)) == NULL)
+ return (1);
+ if (lp->l_parsed) {
+#ifdef DEBUG
+ /*
+ * This error message is largely superflous since the
+ * code handles the error condition sucessfully, and
+ * spewing it out from inside libc can actually hose
+ * certain programs.
+ */
+ fprintf(stderr, "Cycle in netgroup %s\n", lp->l_groupname);
+#endif
+ return (1);
+ } else
+ lp->l_parsed = 1;
+ pos = lp->l_line;
+ /* Watch for null pointer dereferences, dammit! */
+ while (pos != NULL && *pos != '\0') {
+ if (*pos == '(') {
+ grp = malloc(sizeof(*grp));
+ if (grp == NULL)
+ return (1);
+ ng = grp->ng_str;
+ bzero(grp, sizeof(*grp));
+ pos++;
+ gpos = strsep(&pos, ")");
+#ifdef DEBUG
+ fields = 0;
+#endif
+ for (strpos = 0; strpos < 3; strpos++) {
+ if ((spos = strsep(&gpos, ",")) == NULL) {
+ /*
+ * All other systems I've tested
+ * return NULL for empty netgroup
+ * fields. It's up to user programs
+ * to handle the NULLs appropriately.
+ */
+ ng[strpos] = NULL;
+ continue;
+ }
+#ifdef DEBUG
+ fields++;
+#endif
+ while (*spos == ' ' || *spos == '\t')
+ spos++;
+ if ((epos = strpbrk(spos, " \t"))) {
+ *epos = '\0';
+ len = epos - spos;
+ } else
+ len = strlen(spos);
+ if (len <= 0)
+ continue;
+ ng[strpos] = malloc(len + 1);
+ if (ng[strpos] == NULL) {
+ for (freepos = 0; freepos < strpos;
+ freepos++)
+ free(ng[freepos]);
+ free(grp);
+ return (1);
+ }
+ bcopy(spos, ng[strpos], len + 1);
+ }
+ grp->ng_next = st->st_gr;
+ st->st_gr = grp;
+#ifdef DEBUG
+ /*
+ * Note: on other platforms, malformed netgroup
+ * entries are not normally flagged. While we
+ * can catch bad entries and report them, we should
+ * stay silent by default for compatibility's sake.
+ */
+ if (fields < 3) {
+ fprintf(stderr,
+ "Bad entry (%s%s%s%s%s) in netgroup \"%s\"\n",
+ ng[NG_HOST] == NULL ? "" : ng[NG_HOST],
+ ng[NG_USER] == NULL ? "" : ",",
+ ng[NG_USER] == NULL ? "" : ng[NG_USER],
+ ng[NG_DOM] == NULL ? "" : ",",
+ ng[NG_DOM] == NULL ? "" : ng[NG_DOM],
+ lp->l_groupname);
+ }
+#endif
+ } else {
+ spos = strsep(&pos, ", \t");
+ if (parse_netgrp(spos, st, niscompat))
+ continue;
+ }
+ if (pos == NULL)
+ break;
+ while (*pos == ' ' || *pos == ',' || *pos == '\t')
+ pos++;
+ }
+ return (0);
+}
+
+/*
+ * Read the netgroup file and save lines until the line for the netgroup
+ * is found. Return 1 if eof is encountered.
+ */
+static struct linelist *
+read_for_group(const char *group, struct netgr_state *st, int niscompat)
+{
+ char *linep, *olinep, *pos, *spos;
+ int len, olen;
+ int cont;
+ struct linelist *lp;
+ char line[LINSIZ + 2];
+ FILE *netf;
+#ifdef YP
+ char *result;
+ int resultlen;
+ linep = NULL;
+
+ netf = st->st_netf;
+ while ((_netgr_yp_enabled && niscompat) ||
+ fgets(line, LINSIZ, netf) != NULL) {
+ if (_netgr_yp_enabled) {
+ if(!_netgr_yp_domain)
+ if(yp_get_default_domain(&_netgr_yp_domain))
+ continue;
+ if (yp_match(_netgr_yp_domain, "netgroup", group,
+ strlen(group), &result, &resultlen)) {
+ free(result);
+ if (_use_only_yp)
+ return ((struct linelist *)0);
+ else {
+ _netgr_yp_enabled = 0;
+ continue;
+ }
+ }
+ if (strlen(result) == 0) {
+ free(result);
+ return (NULL);
+ }
+ snprintf(line, LINSIZ, "%s %s", group, result);
+ free(result);
+ }
+#else
+ linep = NULL;
+ while (fgets(line, LINSIZ, netf) != NULL) {
+#endif
+ pos = (char *)&line;
+#ifdef YP
+ if (niscompat && *pos == '+') {
+ _netgr_yp_enabled = 1;
+ continue;
+ }
+#endif
+ if (*pos == '#')
+ continue;
+ while (*pos == ' ' || *pos == '\t')
+ pos++;
+ spos = pos;
+ while (*pos != ' ' && *pos != '\t' && *pos != '\n' &&
+ *pos != '\0')
+ pos++;
+ len = pos - spos;
+ while (*pos == ' ' || *pos == '\t')
+ pos++;
+ if (*pos != '\n' && *pos != '\0') {
+ lp = malloc(sizeof (*lp));
+ if (lp == NULL)
+ return (NULL);
+ lp->l_parsed = 0;
+ lp->l_groupname = malloc(len + 1);
+ if (lp->l_groupname == NULL) {
+ free(lp);
+ return (NULL);
+ }
+ bcopy(spos, lp->l_groupname, len);
+ *(lp->l_groupname + len) = '\0';
+ len = strlen(pos);
+ olen = 0;
+
+ /*
+ * Loop around handling line continuations.
+ */
+ do {
+ if (*(pos + len - 1) == '\n')
+ len--;
+ if (*(pos + len - 1) == '\\') {
+ len--;
+ cont = 1;
+ } else
+ cont = 0;
+ if (len > 0) {
+ linep = malloc(olen + len + 1);
+ if (linep == NULL) {
+ free(lp->l_groupname);
+ free(lp);
+ if (olen > 0)
+ free(olinep);
+ return (NULL);
+ }
+ if (olen > 0) {
+ bcopy(olinep, linep, olen);
+ free(olinep);
+ }
+ bcopy(pos, linep + olen, len);
+ olen += len;
+ *(linep + olen) = '\0';
+ olinep = linep;
+ }
+ if (cont) {
+ if (fgets(line, LINSIZ, netf)) {
+ pos = line;
+ len = strlen(pos);
+ } else
+ cont = 0;
+ }
+ } while (cont);
+ lp->l_line = linep;
+ lp->l_next = st->st_linehead;
+ st->st_linehead = lp;
+
+ /*
+ * If this is the one we wanted, we are done.
+ */
+ if (!strcmp(lp->l_groupname, group))
+ return (lp);
+ }
+ }
+#ifdef YP
+ /*
+ * Yucky. The recursive nature of this whole mess might require
+ * us to make more than one pass through the netgroup file.
+ * This might be best left outside the #ifdef YP, but YP is
+ * defined by default anyway, so I'll leave it like this
+ * until I know better.
+ */
+ rewind(netf);
+#endif
+ return (NULL);
+}
+
+int
+getnetgrent_r(char **hostp, char **userp, char **domp, char *buf, size_t bufsize)
+{
+ int rv, ret_errno;
+
+ ret_errno = 0;
+ rv = _nsdispatch(NULL, getnetgrent_dtab, NSDB_NETGROUP, "getnetgrent_r",
+ defaultsrc, hostp, userp, domp, buf, bufsize, &ret_errno);
+ if (rv == NS_SUCCESS) {
+ return (1);
+ } else {
+ errno = ret_errno;
+ return (0);
+ }
+}
+
+int
+getnetgrent(char **hostp, char **userp, char **domp)
+{
+ static char *ngrp_storage;
+ static size_t ngrp_storage_size;
+ int ret_errno, rv;
+
+ if (ngrp_storage == NULL) {
+ ngrp_storage_size = NGRP_STORAGE_INITIAL;
+ ngrp_storage = malloc(ngrp_storage_size);
+ if (ngrp_storage == NULL)
+ return (0);
+ }
+
+ do {
+ ret_errno = 0;
+ rv = _nsdispatch(NULL, getnetgrent_dtab, NSDB_NETGROUP,
+ "getnetgrent_r", defaultsrc, hostp, userp, domp,
+ ngrp_storage, ngrp_storage_size, &ret_errno);
+ if (rv != NS_SUCCESS && ret_errno == ERANGE) {
+ ngrp_storage_size *= 2;
+ if (ngrp_storage_size > NGRP_STORAGE_MAX) {
+ free(ngrp_storage);
+ ngrp_storage = NULL;
+ errno = ERANGE;
+ return (0);
+ }
+ ngrp_storage = reallocf(ngrp_storage,
+ ngrp_storage_size);
+ if (ngrp_storage == NULL)
+ return (0);
+ }
+ } while (rv != NS_SUCCESS && ret_errno == ERANGE);
+
+ if (rv == NS_SUCCESS) {
+ return (1);
+ } else {
+ errno = ret_errno;
+ return (0);
+ }
+}
+
+void
+setnetgrent(const char *netgroup)
+{
+
+ (void)_nsdispatch(NULL, setnetgrent_dtab, NSDB_NETGROUP, "setnetgrent",
+ defaultsrc, netgroup);
+}
+
+void
+endnetgrent(void)
+{
+
+ (void)_nsdispatch(NULL, endnetgrent_dtab, NSDB_NETGROUP, "endnetgrent",
+ defaultsrc);
+}
+
+int
+innetgr(const char *netgroup, const char *host, const char *user,
+ const char *domain)
+{
+ static const ns_dtab dtab[] = {
+ NS_COMPAT_CB(compat_innetgr, NULL)
+ NS_FALLBACK_CB(innetgr_fallback)
+ { NULL, NULL, NULL },
+ };
+ int result, rv;
+
+ rv = _nsdispatch(&result, dtab, NSDB_NETGROUP, "innetgr", defaultsrc,
+ netgroup, host, user, domain);
+ return (rv == NS_SUCCESS ? result : 0);
+}
diff --git a/lib/libc/gen/getosreldate.3 b/lib/libc/gen/getosreldate.3
new file mode 100644
index 000000000000..95f63b56c7db
--- /dev/null
+++ b/lib/libc/gen/getosreldate.3
@@ -0,0 +1,86 @@
+.\" Copyright (c) 2002 The FreeBSD Project.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 September 30, 2008
+.Dt GETOSRELDATE 3
+.Os
+.Sh NAME
+.Nm getosreldate
+.Nd get the value of
+.Dv __FreeBSD_version
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft int
+.Fn getosreldate void
+.Sh DESCRIPTION
+The
+.Fn getosreldate
+function returns an integer showing the version of the
+currently running
+.Fx
+kernel.
+Definitions of the values can be found in
+.%B "The Porter's Handbook"
+which is usually installed at
+.Pa /usr/share/doc/en_US.ISO8859-1/books/porters-handbook/ .
+.Sh RETURN VALUES
+Upon successful completion,
+.Fn getosreldate
+returns the value requested;
+otherwise the value \-1 is returned and the global variable
+.Va errno
+is set to indicate the error.
+.Sh ENVIRONMENT
+.Bl -tag -width ".Ev OSVERSION"
+.It Ev OSVERSION
+If the environment variable
+.Ev OSVERSION
+is set, it will override the
+.Fn getosreldate
+return value.
+.El
+.Sh EXAMPLES
+An example can be found in
+.Pa /usr/share/examples/FreeBSD_version .
+.Sh ERRORS
+The
+.Fn getosreldate
+function may fail and set
+.Va errno
+for any of the errors specified for the library function
+.Xr sysctl 3 .
+.Sh SEE ALSO
+.Rs
+.%B "The Porter's Handbook"
+.%O /usr/share/doc/en_US.ISO8859-1/books/porters\-handbook/
+.Re
+.Sh HISTORY
+The
+.Fn getosreldate
+function appeared in
+.Fx 2.0 .
diff --git a/lib/libc/gen/getosreldate.c b/lib/libc/gen/getosreldate.c
new file mode 100644
index 000000000000..b4bf545ed31e
--- /dev/null
+++ b/lib/libc/gen/getosreldate.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)gethostid.c 8.1 (Berkeley) 6/2/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/sysctl.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+
+int
+getosreldate(void)
+{
+ int mib[2];
+ size_t size;
+ int value;
+ char *temp;
+
+ if ((temp = getenv("OSVERSION"))) {
+ value = atoi(temp);
+ return (value);
+ }
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_OSRELDATE;
+ size = sizeof value;
+ if (sysctl(mib, 2, &value, &size, NULL, 0) == -1)
+ return (-1);
+ return (value);
+}
diff --git a/lib/libc/gen/getpagesize.3 b/lib/libc/gen/getpagesize.3
new file mode 100644
index 000000000000..8369a854c434
--- /dev/null
+++ b/lib/libc/gen/getpagesize.3
@@ -0,0 +1,61 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)getpagesize.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt GETPAGESIZE 3
+.Os
+.Sh NAME
+.Nm getpagesize
+.Nd get system page size
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft int
+.Fn getpagesize void
+.Sh DESCRIPTION
+The
+.Fn getpagesize
+function
+returns the number of bytes in a page.
+Page granularity is the granularity of many of the memory
+management calls.
+.Pp
+The page size is a system
+page size and may not be the same as the underlying
+hardware page size.
+.Sh SEE ALSO
+.Xr pagesize 1 ,
+.Xr sbrk 2
+.Sh HISTORY
+The
+.Fn getpagesize
+function appeared in
+.Bx 4.2 .
diff --git a/lib/libc/gen/getpagesize.c b/lib/libc/gen/getpagesize.c
new file mode 100644
index 000000000000..ffd30851eb5a
--- /dev/null
+++ b/lib/libc/gen/getpagesize.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)getpagesize.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/sysctl.h>
+
+#include <errno.h>
+#include <link.h>
+#include <unistd.h>
+
+#include "libc_private.h"
+
+/*
+ * This is unlikely to change over the running time of any
+ * program, so we cache the result to save some syscalls.
+ *
+ * NB: This function may be called from malloc(3) at initialization
+ * NB: so must not result in a malloc(3) related call!
+ */
+
+int
+getpagesize(void)
+{
+ int mib[2];
+ static int value;
+ size_t size;
+ int error;
+
+ if (value != 0)
+ return (value);
+
+ error = _elf_aux_info(AT_PAGESZ, &value, sizeof(value));
+ if (error == 0 && value != 0)
+ return (value);
+
+ mib[0] = CTL_HW;
+ mib[1] = HW_PAGESIZE;
+ size = sizeof value;
+ if (sysctl(mib, nitems(mib), &value, &size, NULL, 0) == -1)
+ return (-1);
+
+ return (value);
+}
diff --git a/lib/libc/gen/getpagesizes.3 b/lib/libc/gen/getpagesizes.3
new file mode 100644
index 000000000000..52fa866821f2
--- /dev/null
+++ b/lib/libc/gen/getpagesizes.3
@@ -0,0 +1,99 @@
+.\" Copyright (c) 2009 Alan L. Cox <alc@cs.rice.edu>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd September 21, 2009
+.Dt GETPAGESIZES 3
+.Os
+.Sh NAME
+.Nm getpagesizes
+.Nd "get system page sizes"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/mman.h
+.Ft int
+.Fn getpagesizes "size_t pagesize[]" "int nelem"
+.Sh DESCRIPTION
+The
+.Fn getpagesizes
+function retrieves page size information from the system.
+When it is called with
+.Fa pagesize
+specified as
+.Dv NULL
+and
+.Fa nelem
+specified as 0, it returns the number of distinct page sizes that are
+supported by the system.
+Otherwise, it assigns up to
+.Fa nelem
+of the system-supported page sizes to consecutive elements of the
+array referenced by
+.Fa pagesize .
+These page sizes are expressed in bytes.
+In this case,
+.Fn getpagesizes
+returns the number of such page sizes that it assigned to the array.
+.Sh RETURN VALUES
+If successful, the
+.Fn getpagesizes
+function returns either the number of page sizes that are supported by
+the system or the number of supported page sizes that it assigned to
+the array referenced by
+.Fa pagesize .
+Otherwise, it returns the value\~\-1 and sets
+.Va errno
+to indicate the error.
+.Sh ERRORS
+The
+.Fn getpagesizes
+function will succeed unless:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa pagesize
+argument is
+.Dv NULL
+and the
+.Fa nelem
+argument is non-zero.
+.It Bq Er EINVAL
+The
+.Fa nelem
+argument is less than zero.
+.El
+.Sh SEE ALSO
+.Xr getpagesize 3
+.Sh HISTORY
+The
+.Fn getpagesizes
+function first appeared in Solaris 9.
+This manual page was written in conjunction with a new but compatible
+implementation that was first released in
+.Fx 7.3 .
+.Sh AUTHORS
+This manual page was written by
+.An Alan L. Cox Aq Mt alc@cs.rice.edu .
diff --git a/lib/libc/gen/getpagesizes.c b/lib/libc/gen/getpagesizes.c
new file mode 100644
index 000000000000..534fe9e1fefe
--- /dev/null
+++ b/lib/libc/gen/getpagesizes.c
@@ -0,0 +1,85 @@
+/*-
+ * Copyright (c) 2009 Alan L. Cox <alc@cs.rice.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/mman.h>
+#include <sys/sysctl.h>
+
+#include <errno.h>
+#include <link.h>
+
+#include "libc_private.h"
+
+/*
+ * Retrieves page size information from the system. Specifically, returns the
+ * number of distinct page sizes that are supported by the system, if
+ * "pagesize" is NULL and "nelem" is 0. Otherwise, assigns up to "nelem" of
+ * the system-supported page sizes to consecutive elements of the array
+ * referenced by "pagesize", and returns the number of such page sizes that it
+ * assigned to the array. These page sizes are expressed in bytes.
+ *
+ * The implementation of this function does not directly or indirectly call
+ * malloc(3) or any other dynamic memory allocator that may itself call this
+ * function.
+ */
+int
+getpagesizes(size_t pagesize[], int nelem)
+{
+ static u_long ps[MAXPAGESIZES];
+ static int nops;
+ size_t size;
+ int error, i;
+
+ if (nelem < 0 || (nelem > 0 && pagesize == NULL)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ /* Cache the result of the sysctl(2). */
+ if (nops == 0) {
+ error = _elf_aux_info(AT_PAGESIZES, ps, sizeof(ps));
+ size = sizeof(ps);
+ if (error != 0 || ps[0] == 0) {
+ if (sysctlbyname("hw.pagesizes", ps, &size, NULL, 0)
+ == -1)
+ return (-1);
+ }
+ /* Count the number of page sizes that are supported. */
+ nops = size / sizeof(ps[0]);
+ while (nops > 0 && ps[nops - 1] == 0)
+ nops--;
+ }
+ if (pagesize == NULL)
+ return (nops);
+ /* Return up to "nelem" page sizes from the cached result. */
+ if (nelem > nops)
+ nelem = nops;
+ for (i = 0; i < nelem; i++)
+ pagesize[i] = ps[i];
+ return (nelem);
+}
diff --git a/lib/libc/gen/getpass.3 b/lib/libc/gen/getpass.3
new file mode 100644
index 000000000000..85dcdced2fe7
--- /dev/null
+++ b/lib/libc/gen/getpass.3
@@ -0,0 +1,93 @@
+.\" Copyright (c) 1989, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)getpass.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt GETPASS 3
+.Os
+.Sh NAME
+.Nm getpass
+.Nd get a password
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In pwd.h
+.In unistd.h
+.Ft char *
+.Fn getpass "const char *prompt"
+.Sh DESCRIPTION
+The
+.Fn getpass
+function displays a prompt to, and reads in a password from,
+.Pa /dev/tty .
+If this file is not accessible,
+.Fn getpass
+displays the prompt on the standard error output and reads from the standard
+input.
+.Pp
+The password may be up to _PASSWORD_LEN (currently 128)
+characters in length.
+Any additional
+characters and the terminating newline character are discarded.
+.Pp
+The
+.Fn getpass
+function turns off character echoing while reading the password.
+.Sh RETURN VALUES
+The
+.Fn getpass
+function returns a pointer to the null terminated password.
+.Sh FILES
+.Bl -tag -width /dev/tty -compact
+.It Pa /dev/tty
+.El
+.Sh SEE ALSO
+.Xr crypt 3 ,
+.Xr readpassphrase 3
+.Sh HISTORY
+A
+.Fn getpass
+function appeared in
+.At v7 .
+.Sh BUGS
+The
+.Fn getpass
+function leaves its result in an internal static object and returns
+a pointer to that object.
+Subsequent calls to
+.Fn getpass
+will modify the same object.
+.Pp
+The calling process should zero the password as soon as possible to
+avoid leaving the cleartext password visible in the process's address
+space.
+.Pp
+Upon receipt of a SIGTSTP, the input buffer will be flushed, so any
+partially typed password must be retyped when the process
+continues.
diff --git a/lib/libc/gen/getpeereid.3 b/lib/libc/gen/getpeereid.3
new file mode 100644
index 000000000000..12999e501b09
--- /dev/null
+++ b/lib/libc/gen/getpeereid.3
@@ -0,0 +1,137 @@
+.\"
+.\" Copyright (c) 2001 Dima Dorfman.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd July 15, 2001
+.Dt GETPEEREID 3
+.Os
+.Sh NAME
+.Nm getpeereid
+.Nd get the effective credentials of a UNIX-domain peer
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In unistd.h
+.Ft int
+.Fn getpeereid "int s" "uid_t *euid" "gid_t *egid"
+.Sh DESCRIPTION
+The
+.Fn getpeereid
+function returns the effective user and group IDs of the
+peer connected to a
+.Ux Ns -domain
+socket.
+The argument
+.Fa s
+must be a
+.Ux Ns -domain
+socket
+.Pq Xr unix 4
+of type
+.Dv SOCK_STREAM
+on which either
+.Xr connect 2
+or
+.Xr listen 2
+have been called.
+The effective used ID is placed in
+.Fa euid ,
+and the effective group ID in
+.Fa egid .
+.Pp
+The credentials returned to the
+.Xr listen 2
+caller are those of its peer at the time it called
+.Xr connect 2 ;
+the credentials returned to the
+.Xr connect 2
+caller are those of its peer at the time it called
+.Xr listen 2 .
+This mechanism is reliable; there is no way for either side to influence
+the credentials returned to its peer except by calling the appropriate
+system call (i.e., either
+.Xr connect 2
+or
+.Xr listen 2 )
+under different effective credentials.
+.Pp
+One common use of this routine is for a
+.Ux Ns -domain
+server
+to verify the credentials of its client.
+Likewise, the client can verify the credentials of the server.
+.Sh IMPLEMENTATION NOTES
+On
+.Fx ,
+.Fn getpeereid
+is implemented in terms of the
+.Dv LOCAL_PEERCRED
+.Xr unix 4
+socket option.
+.Sh RETURN VALUES
+.Rv -std getpeereid
+.Sh ERRORS
+The
+.Fn getpeereid
+function
+fails if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The argument
+.Fa s
+is not a valid descriptor.
+.It Bq Er ENOTSOCK
+The argument
+.Fa s
+is a file, not a socket.
+.It Bq Er ENOTCONN
+The argument
+.Fa s
+does not refer to a socket on which
+.Xr connect 2
+or
+.Xr listen 2
+have been called.
+.It Bq Er EINVAL
+The argument
+.Fa s
+does not refer to a socket of type
+.Dv SOCK_STREAM ,
+or the kernel returned invalid data.
+.El
+.Sh SEE ALSO
+.Xr connect 2 ,
+.Xr getpeername 2 ,
+.Xr getsockname 2 ,
+.Xr getsockopt 2 ,
+.Xr listen 2 ,
+.Xr unix 4
+.Sh HISTORY
+The
+.Fn getpeereid
+function appeared in
+.Fx 4.6 .
diff --git a/lib/libc/gen/getpeereid.c b/lib/libc/gen/getpeereid.c
new file mode 100644
index 000000000000..cedaee656d48
--- /dev/null
+++ b/lib/libc/gen/getpeereid.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2001 Dima Dorfman.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/ucred.h>
+#include <sys/un.h>
+
+#include <errno.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+int
+getpeereid(int s, uid_t *euid, gid_t *egid)
+{
+ struct xucred xuc;
+ socklen_t xuclen;
+ int error;
+
+ xuclen = sizeof(xuc);
+ error = _getsockopt(s, 0, LOCAL_PEERCRED, &xuc, &xuclen);
+ if (error != 0)
+ return (error);
+ if (xuc.cr_version != XUCRED_VERSION)
+ return (EINVAL);
+ *euid = xuc.cr_uid;
+ *egid = xuc.cr_gid;
+ return (0);
+}
diff --git a/lib/libc/gen/getprogname.3 b/lib/libc/gen/getprogname.3
new file mode 100644
index 000000000000..53d39a60526b
--- /dev/null
+++ b/lib/libc/gen/getprogname.3
@@ -0,0 +1,94 @@
+.\"
+.\" Copyright (c) 2001 Christopher G. Demetriou
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed for the
+.\" NetBSD Project. See http://www.netbsd.org/ for
+.\" information about NetBSD.
+.\" 4. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd May 1, 2001
+.Dt GETPROGNAME 3
+.Os
+.Sh NAME
+.Nm getprogname ,
+.Nm setprogname
+.Nd get or set the program name
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft const char *
+.Fn getprogname "void"
+.Ft void
+.Fn setprogname "const char *progname"
+.Sh DESCRIPTION
+The
+.Fn getprogname
+and
+.Fn setprogname
+functions manipulate the name of the current program.
+They are used by error-reporting routines to produce
+consistent output.
+.Pp
+The
+.Fn getprogname
+function returns the name of the program.
+If the name has not been set yet, it will return
+.Dv NULL .
+.Pp
+The
+.Fn setprogname
+function sets the name of the program to be the last component of the
+.Fa progname
+argument.
+Since a pointer to the given string is kept as the program name,
+it should not be modified for the rest of the program's lifetime.
+.Pp
+In
+.Fx ,
+the name of the program is set by the start-up code that is run before
+.Fn main ;
+thus,
+running
+.Fn setprogname
+is not necessary.
+Programs that desire maximum portability should still call it;
+on another operating system,
+these functions may be implemented in a portability library.
+Calling
+.Fn setprogname
+allows the aforementioned library to learn the program name without
+modifications to the start-up code.
+.Sh SEE ALSO
+.Xr err 3 ,
+.Xr setproctitle 3
+.Sh HISTORY
+These functions first appeared in
+.Nx 1.6 ,
+and made their way into
+.Fx 4.4 .
diff --git a/lib/libc/gen/getprogname.c b/lib/libc/gen/getprogname.c
new file mode 100644
index 000000000000..fd51d1322517
--- /dev/null
+++ b/lib/libc/gen/getprogname.c
@@ -0,0 +1,17 @@
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <stdlib.h>
+#include "un-namespace.h"
+
+#include "libc_private.h"
+
+__weak_reference(_getprogname, getprogname);
+
+const char *
+_getprogname(void)
+{
+
+ return (__progname);
+}
diff --git a/lib/libc/gen/getpwent.3 b/lib/libc/gen/getpwent.3
new file mode 100644
index 000000000000..65092abab1fb
--- /dev/null
+++ b/lib/libc/gen/getpwent.3
@@ -0,0 +1,315 @@
+.\" Copyright (c) 1988, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" From: @(#)getpwent.3 8.2 (Berkeley) 12/11/93
+.\" $FreeBSD$
+.\"
+.Dd April 16, 2003
+.Dt GETPWENT 3
+.Os
+.Sh NAME
+.Nm getpwent ,
+.Nm getpwent_r ,
+.Nm getpwnam ,
+.Nm getpwnam_r ,
+.Nm getpwuid ,
+.Nm getpwuid_r ,
+.Nm setpassent ,
+.Nm setpwent ,
+.Nm endpwent
+.Nd password database operations
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In pwd.h
+.Ft struct passwd *
+.Fn getpwent void
+.Ft int
+.Fn getpwent_r "struct passwd *pwd" "char *buffer" "size_t bufsize" "struct passwd **result"
+.Ft struct passwd *
+.Fn getpwnam "const char *login"
+.Ft int
+.Fn getpwnam_r "const char *name" "struct passwd *pwd" "char *buffer" "size_t bufsize" "struct passwd **result"
+.Ft struct passwd *
+.Fn getpwuid "uid_t uid"
+.Ft int
+.Fn getpwuid_r "uid_t uid" "struct passwd *pwd" "char *buffer" "size_t bufsize" "struct passwd **result"
+.Ft int
+.Fn setpassent "int stayopen"
+.Ft void
+.Fn setpwent void
+.Ft void
+.Fn endpwent void
+.Sh DESCRIPTION
+These functions
+operate on the password database file
+which is described
+in
+.Xr passwd 5 .
+Each entry in the database is defined by the structure
+.Vt passwd
+found in the include
+file
+.In pwd.h :
+.Bd -literal -offset indent
+struct passwd {
+ char *pw_name; /* user name */
+ char *pw_passwd; /* encrypted password */
+ uid_t pw_uid; /* user uid */
+ gid_t pw_gid; /* user gid */
+ time_t pw_change; /* password change time */
+ char *pw_class; /* user access class */
+ char *pw_gecos; /* Honeywell login info */
+ char *pw_dir; /* home directory */
+ char *pw_shell; /* default shell */
+ time_t pw_expire; /* account expiration */
+ int pw_fields; /* internal: fields filled in */
+};
+.Ed
+.Pp
+The functions
+.Fn getpwnam
+and
+.Fn getpwuid
+search the password database for the given login name or user uid,
+respectively, always returning the first one encountered.
+.Pp
+The
+.Fn getpwent
+function
+sequentially reads the password database and is intended for programs
+that wish to process the complete list of users.
+.Pp
+The functions
+.Fn getpwent_r ,
+.Fn getpwnam_r ,
+and
+.Fn getpwuid_r
+are thread-safe versions of
+.Fn getpwent ,
+.Fn getpwnam ,
+and
+.Fn getpwuid ,
+respectively.
+The caller must provide storage for the results of the search in
+the
+.Fa pwd ,
+.Fa buffer ,
+.Fa bufsize ,
+and
+.Fa result
+arguments.
+When these functions are successful, the
+.Fa pwd
+argument will be filled-in, and a pointer to that argument will be
+stored in
+.Fa result .
+If an entry is not found or an error occurs,
+.Fa result
+will be set to
+.Dv NULL .
+.Pp
+The
+.Fn setpassent
+function
+accomplishes two purposes.
+First, it causes
+.Fn getpwent
+to ``rewind'' to the beginning of the database.
+Additionally, if
+.Fa stayopen
+is non-zero, file descriptors are left open, significantly speeding
+up subsequent accesses for all of the routines.
+(This latter functionality is unnecessary for
+.Fn getpwent
+as it does not close its file descriptors by default.)
+.Pp
+It is dangerous for long-running programs to keep the file descriptors
+open as the database will become out of date if it is updated while the
+program is running.
+.Pp
+The
+.Fn setpwent
+function
+is identical to
+.Fn setpassent
+with an argument of zero.
+.Pp
+The
+.Fn endpwent
+function
+closes any open files.
+.Pp
+These routines have been written to ``shadow'' the password file, e.g.\&
+allow only certain programs to have access to the encrypted password.
+If the process which calls them has an effective uid of 0, the encrypted
+password will be returned, otherwise, the password field of the returned
+structure will point to the string
+.Ql * .
+.Sh RETURN VALUES
+The functions
+.Fn getpwent ,
+.Fn getpwnam ,
+and
+.Fn getpwuid
+return a valid pointer to a passwd structure on success
+or
+.Dv NULL
+if the entry is not found or if an error occurs.
+If an error does occur,
+.Va errno
+will be set.
+Note that programs must explicitly set
+.Va errno
+to zero before calling any of these functions if they need to
+distinguish between a non-existent entry and an error.
+The functions
+.Fn getpwent_r ,
+.Fn getpwnam_r ,
+and
+.Fn getpwuid_r
+return 0 if no error occurred, or an error number to indicate failure.
+It is not an error if a matching entry is not found.
+(Thus, if
+.Fa result
+is
+.Dv NULL
+and the return value is 0, no matching entry exists.)
+.Pp
+The
+.Fn setpassent
+function returns 0 on failure and 1 on success.
+The
+.Fn endpwent
+and
+.Fn setpwent
+functions
+have no return value.
+.Sh FILES
+.Bl -tag -width /etc/master.passwd -compact
+.It Pa /etc/pwd.db
+The insecure password database file
+.It Pa /etc/spwd.db
+The secure password database file
+.It Pa /etc/master.passwd
+The current password file
+.It Pa /etc/passwd
+A Version 7 format password file
+.El
+.Sh COMPATIBILITY
+The historic function
+.Xr setpwfile 3 ,
+which allowed the specification of alternate password databases,
+has been deprecated and is no longer available.
+.Sh ERRORS
+These routines may fail for any of the errors specified in
+.Xr open 2 ,
+.Xr dbopen 3 ,
+.Xr socket 2 ,
+and
+.Xr connect 2 ,
+in addition to the following:
+.Bl -tag -width Er
+.It Bq Er ERANGE
+The buffer specified by the
+.Fa buffer
+and
+.Fa bufsize
+arguments was insufficiently sized to store the result.
+The caller should retry with a larger buffer.
+.El
+.Sh SEE ALSO
+.Xr getlogin 2 ,
+.Xr getgrent 3 ,
+.Xr nsswitch.conf 5 ,
+.Xr passwd 5 ,
+.Xr pwd_mkdb 8 ,
+.Xr vipw 8 ,
+.Xr yp 8
+.Sh STANDARDS
+The
+.Fn getpwent ,
+.Fn getpwnam ,
+.Fn getpwnam_r ,
+.Fn getpwuid ,
+.Fn getpwuid_r ,
+.Fn setpwent ,
+and
+.Fn endpwent
+functions conform to
+.St -p1003.1-96 .
+.Sh HISTORY
+The
+.Fn getpwent ,
+.Fn getpwnam ,
+.Fn getpwuid ,
+.Fn setpwent ,
+and
+.Fn endpwent
+functions appeared in
+.At v7 .
+The
+.Fn setpassent
+function appeared in
+.Bx 4.3 Reno .
+The
+.Fn getpwent_r ,
+.Fn getpwnam_r ,
+and
+.Fn getpwuid_r
+functions appeared in
+.Fx 5.1 .
+.Sh BUGS
+The functions
+.Fn getpwent ,
+.Fn getpwnam ,
+and
+.Fn getpwuid ,
+leave their results in an internal static object and return
+a pointer to that object.
+Subsequent calls to
+the same function
+will modify the same object.
+.Pp
+The functions
+.Fn getpwent ,
+.Fn getpwent_r ,
+.Fn endpwent ,
+.Fn setpassent ,
+and
+.Fn setpwent
+are fairly useless in a networked environment and should be
+avoided, if possible.
+The
+.Fn getpwent
+and
+.Fn getpwent_r
+functions
+make no attempt to suppress duplicate information if multiple
+sources are specified in
+.Xr nsswitch.conf 5 .
diff --git a/lib/libc/gen/getpwent.c b/lib/libc/gen/getpwent.c
new file mode 100644
index 000000000000..a35a28835004
--- /dev/null
+++ b/lib/libc/gen/getpwent.c
@@ -0,0 +1,2010 @@
+/*-
+ * Copyright (c) 2003 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project by
+ * Jacques A. Vidrine, Safeport Network Services, and Network
+ * Associates Laboratories, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+ * ("CBOSS"), as part of the DARPA CHATS research program.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/param.h>
+#ifdef YP
+#include <rpc/rpc.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+#endif
+#include <arpa/inet.h>
+#include <errno.h>
+#include <fcntl.h>
+#ifdef HESIOD
+#include <hesiod.h>
+#endif
+#include <netdb.h>
+#include <nsswitch.h>
+#include <pthread.h>
+#include <pthread_np.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include "un-namespace.h"
+#include <db.h>
+#include "libc_private.h"
+#include "pw_scan.h"
+#include "nss_tls.h"
+#ifdef NS_CACHING
+#include "nscache.h"
+#endif
+
+#ifndef CTASSERT
+#define CTASSERT(x) _CTASSERT(x, __LINE__)
+#define _CTASSERT(x, y) __CTASSERT(x, y)
+#define __CTASSERT(x, y) typedef char __assert_ ## y [(x) ? 1 : -1]
+#endif
+
+/* Counter as stored in /etc/pwd.db */
+typedef int pwkeynum;
+
+CTASSERT(MAXLOGNAME > sizeof(uid_t));
+CTASSERT(MAXLOGNAME > sizeof(pwkeynum));
+
+enum constants {
+ PWD_STORAGE_INITIAL = 1 << 10, /* 1 KByte */
+ PWD_STORAGE_MAX = 1 << 20, /* 1 MByte */
+ SETPWENT = 1,
+ ENDPWENT = 2,
+ HESIOD_NAME_MAX = 256
+};
+
+static const ns_src defaultsrc[] = {
+ { NSSRC_COMPAT, NS_SUCCESS },
+ { NULL, 0 }
+};
+
+int __pw_match_entry(const char *, size_t, enum nss_lookup_type,
+ const char *, uid_t);
+int __pw_parse_entry(char *, size_t, struct passwd *, int, int *errnop);
+
+static void pwd_init(struct passwd *);
+
+union key {
+ const char *name;
+ uid_t uid;
+};
+
+static struct passwd *getpw(int (*fn)(union key, struct passwd *, char *,
+ size_t, struct passwd **), union key);
+static int wrap_getpwnam_r(union key, struct passwd *, char *,
+ size_t, struct passwd **);
+static int wrap_getpwuid_r(union key, struct passwd *, char *, size_t,
+ struct passwd **);
+static int wrap_getpwent_r(union key, struct passwd *, char *, size_t,
+ struct passwd **);
+
+static int pwdb_match_entry_v3(char *, size_t, enum nss_lookup_type,
+ const char *, uid_t);
+static int pwdb_parse_entry_v3(char *, size_t, struct passwd *, int *);
+static int pwdb_match_entry_v4(char *, size_t, enum nss_lookup_type,
+ const char *, uid_t);
+static int pwdb_parse_entry_v4(char *, size_t, struct passwd *, int *);
+
+
+struct {
+ int (*match)(char *, size_t, enum nss_lookup_type, const char *,
+ uid_t);
+ int (*parse)(char *, size_t, struct passwd *, int *);
+} pwdb_versions[] = {
+ { NULL, NULL }, /* version 0 */
+ { NULL, NULL }, /* version 1 */
+ { NULL, NULL }, /* version 2 */
+ { pwdb_match_entry_v3, pwdb_parse_entry_v3 }, /* version 3 */
+ { pwdb_match_entry_v4, pwdb_parse_entry_v4 }, /* version 4 */
+};
+
+
+struct files_state {
+ DB *db;
+ pwkeynum keynum;
+ int stayopen;
+ int version;
+};
+static void files_endstate(void *);
+NSS_TLS_HANDLING(files);
+static DB *pwdbopen(int *);
+static void files_endstate(void *);
+static int files_setpwent(void *, void *, va_list);
+static int files_passwd(void *, void *, va_list);
+
+
+#ifdef HESIOD
+struct dns_state {
+ long counter;
+};
+static void dns_endstate(void *);
+NSS_TLS_HANDLING(dns);
+static int dns_setpwent(void *, void *, va_list);
+static int dns_passwd(void *, void *, va_list);
+#endif
+
+
+#ifdef YP
+struct nis_state {
+ char domain[MAXHOSTNAMELEN];
+ int done;
+ char *key;
+ int keylen;
+};
+static void nis_endstate(void *);
+NSS_TLS_HANDLING(nis);
+static int nis_setpwent(void *, void *, va_list);
+static int nis_passwd(void *, void *, va_list);
+static int nis_map(char *, enum nss_lookup_type, char *, size_t, int *);
+static int nis_adjunct(char *, const char *, char *, size_t);
+#endif
+
+
+struct compat_state {
+ DB *db;
+ pwkeynum keynum;
+ int stayopen;
+ int version;
+ DB *exclude;
+ struct passwd template;
+ char *name;
+ enum _compat {
+ COMPAT_MODE_OFF = 0,
+ COMPAT_MODE_ALL,
+ COMPAT_MODE_NAME,
+ COMPAT_MODE_NETGROUP
+ } compat;
+};
+static void compat_endstate(void *);
+NSS_TLS_HANDLING(compat);
+static int compat_setpwent(void *, void *, va_list);
+static int compat_passwd(void *, void *, va_list);
+static void compat_clear_template(struct passwd *);
+static int compat_set_template(struct passwd *, struct passwd *);
+static int compat_use_template(struct passwd *, struct passwd *, char *,
+ size_t);
+static int compat_redispatch(struct compat_state *, enum nss_lookup_type,
+ enum nss_lookup_type, const char *, const char *, uid_t,
+ struct passwd *, char *, size_t, int *);
+
+#ifdef NS_CACHING
+static int pwd_id_func(char *, size_t *, va_list ap, void *);
+static int pwd_marshal_func(char *, size_t *, void *, va_list, void *);
+static int pwd_unmarshal_func(char *, size_t, void *, va_list, void *);
+
+static int
+pwd_id_func(char *buffer, size_t *buffer_size, va_list ap, void *cache_mdata)
+{
+ char *name;
+ uid_t uid;
+ size_t size, desired_size;
+ int res = NS_UNAVAIL;
+ enum nss_lookup_type lookup_type;
+
+ lookup_type = (enum nss_lookup_type)cache_mdata;
+ switch (lookup_type) {
+ case nss_lt_name:
+ name = va_arg(ap, char *);
+ size = strlen(name);
+ desired_size = sizeof(enum nss_lookup_type) + size + 1;
+ if (desired_size > *buffer_size) {
+ res = NS_RETURN;
+ goto fin;
+ }
+
+ memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type));
+ memcpy(buffer + sizeof(enum nss_lookup_type), name, size + 1);
+
+ res = NS_SUCCESS;
+ break;
+ case nss_lt_id:
+ uid = va_arg(ap, uid_t);
+ desired_size = sizeof(enum nss_lookup_type) + sizeof(uid_t);
+ if (desired_size > *buffer_size) {
+ res = NS_RETURN;
+ goto fin;
+ }
+
+ memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type));
+ memcpy(buffer + sizeof(enum nss_lookup_type), &uid,
+ sizeof(uid_t));
+
+ res = NS_SUCCESS;
+ break;
+ default:
+ /* should be unreachable */
+ return (NS_UNAVAIL);
+ }
+
+fin:
+ *buffer_size = desired_size;
+ return (res);
+}
+
+static int
+pwd_marshal_func(char *buffer, size_t *buffer_size, void *retval, va_list ap,
+ void *cache_mdata)
+{
+ char *name;
+ uid_t uid;
+ struct passwd *pwd;
+ char *orig_buf;
+ size_t orig_buf_size;
+
+ struct passwd new_pwd;
+ size_t desired_size, size;
+ char *p;
+
+ switch ((enum nss_lookup_type)cache_mdata) {
+ case nss_lt_name:
+ name = va_arg(ap, char *);
+ break;
+ case nss_lt_id:
+ uid = va_arg(ap, uid_t);
+ break;
+ case nss_lt_all:
+ break;
+ default:
+ /* should be unreachable */
+ return (NS_UNAVAIL);
+ }
+
+ pwd = va_arg(ap, struct passwd *);
+ orig_buf = va_arg(ap, char *);
+ orig_buf_size = va_arg(ap, size_t);
+
+ desired_size = sizeof(struct passwd) + sizeof(char *) +
+ strlen(pwd->pw_name) + 1;
+ if (pwd->pw_passwd != NULL)
+ desired_size += strlen(pwd->pw_passwd) + 1;
+ if (pwd->pw_class != NULL)
+ desired_size += strlen(pwd->pw_class) + 1;
+ if (pwd->pw_gecos != NULL)
+ desired_size += strlen(pwd->pw_gecos) + 1;
+ if (pwd->pw_dir != NULL)
+ desired_size += strlen(pwd->pw_dir) + 1;
+ if (pwd->pw_shell != NULL)
+ desired_size += strlen(pwd->pw_shell) + 1;
+
+ if (*buffer_size < desired_size) {
+ /* this assignment is here for future use */
+ *buffer_size = desired_size;
+ return (NS_RETURN);
+ }
+
+ memcpy(&new_pwd, pwd, sizeof(struct passwd));
+ memset(buffer, 0, desired_size);
+
+ *buffer_size = desired_size;
+ p = buffer + sizeof(struct passwd) + sizeof(char *);
+ memcpy(buffer + sizeof(struct passwd), &p, sizeof(char *));
+
+ if (new_pwd.pw_name != NULL) {
+ size = strlen(new_pwd.pw_name);
+ memcpy(p, new_pwd.pw_name, size);
+ new_pwd.pw_name = p;
+ p += size + 1;
+ }
+
+ if (new_pwd.pw_passwd != NULL) {
+ size = strlen(new_pwd.pw_passwd);
+ memcpy(p, new_pwd.pw_passwd, size);
+ new_pwd.pw_passwd = p;
+ p += size + 1;
+ }
+
+ if (new_pwd.pw_class != NULL) {
+ size = strlen(new_pwd.pw_class);
+ memcpy(p, new_pwd.pw_class, size);
+ new_pwd.pw_class = p;
+ p += size + 1;
+ }
+
+ if (new_pwd.pw_gecos != NULL) {
+ size = strlen(new_pwd.pw_gecos);
+ memcpy(p, new_pwd.pw_gecos, size);
+ new_pwd.pw_gecos = p;
+ p += size + 1;
+ }
+
+ if (new_pwd.pw_dir != NULL) {
+ size = strlen(new_pwd.pw_dir);
+ memcpy(p, new_pwd.pw_dir, size);
+ new_pwd.pw_dir = p;
+ p += size + 1;
+ }
+
+ if (new_pwd.pw_shell != NULL) {
+ size = strlen(new_pwd.pw_shell);
+ memcpy(p, new_pwd.pw_shell, size);
+ new_pwd.pw_shell = p;
+ p += size + 1;
+ }
+
+ memcpy(buffer, &new_pwd, sizeof(struct passwd));
+ return (NS_SUCCESS);
+}
+
+static int
+pwd_unmarshal_func(char *buffer, size_t buffer_size, void *retval, va_list ap,
+ void *cache_mdata)
+{
+ char *name;
+ uid_t uid;
+ struct passwd *pwd;
+ char *orig_buf;
+ size_t orig_buf_size;
+ int *ret_errno;
+
+ char *p;
+
+ switch ((enum nss_lookup_type)cache_mdata) {
+ case nss_lt_name:
+ name = va_arg(ap, char *);
+ break;
+ case nss_lt_id:
+ uid = va_arg(ap, uid_t);
+ break;
+ case nss_lt_all:
+ break;
+ default:
+ /* should be unreachable */
+ return (NS_UNAVAIL);
+ }
+
+ pwd = va_arg(ap, struct passwd *);
+ orig_buf = va_arg(ap, char *);
+ orig_buf_size = va_arg(ap, size_t);
+ ret_errno = va_arg(ap, int *);
+
+ if (orig_buf_size <
+ buffer_size - sizeof(struct passwd) - sizeof(char *)) {
+ *ret_errno = ERANGE;
+ return (NS_RETURN);
+ }
+
+ memcpy(pwd, buffer, sizeof(struct passwd));
+ memcpy(&p, buffer + sizeof(struct passwd), sizeof(char *));
+ memcpy(orig_buf, buffer + sizeof(struct passwd) + sizeof(char *),
+ buffer_size - sizeof(struct passwd) - sizeof(char *));
+
+ NS_APPLY_OFFSET(pwd->pw_name, orig_buf, p, char *);
+ NS_APPLY_OFFSET(pwd->pw_passwd, orig_buf, p, char *);
+ NS_APPLY_OFFSET(pwd->pw_class, orig_buf, p, char *);
+ NS_APPLY_OFFSET(pwd->pw_gecos, orig_buf, p, char *);
+ NS_APPLY_OFFSET(pwd->pw_dir, orig_buf, p, char *);
+ NS_APPLY_OFFSET(pwd->pw_shell, orig_buf, p, char *);
+
+ if (retval != NULL)
+ *((struct passwd **)retval) = pwd;
+
+ return (NS_SUCCESS);
+}
+
+NSS_MP_CACHE_HANDLING(passwd);
+#endif /* NS_CACHING */
+
+void
+setpwent(void)
+{
+#ifdef NS_CACHING
+ static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
+ passwd, (void *)nss_lt_all,
+ NULL, NULL);
+#endif
+
+ static const ns_dtab dtab[] = {
+ { NSSRC_FILES, files_setpwent, (void *)SETPWENT },
+#ifdef HESIOD
+ { NSSRC_DNS, dns_setpwent, (void *)SETPWENT },
+#endif
+#ifdef YP
+ { NSSRC_NIS, nis_setpwent, (void *)SETPWENT },
+#endif
+ { NSSRC_COMPAT, compat_setpwent, (void *)SETPWENT },
+#ifdef NS_CACHING
+ NS_CACHE_CB(&cache_info)
+#endif
+ { NULL, NULL, NULL }
+ };
+ (void)_nsdispatch(NULL, dtab, NSDB_PASSWD, "setpwent", defaultsrc, 0);
+}
+
+
+int
+setpassent(int stayopen)
+{
+#ifdef NS_CACHING
+ static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
+ passwd, (void *)nss_lt_all,
+ NULL, NULL);
+#endif
+
+ static const ns_dtab dtab[] = {
+ { NSSRC_FILES, files_setpwent, (void *)SETPWENT },
+#ifdef HESIOD
+ { NSSRC_DNS, dns_setpwent, (void *)SETPWENT },
+#endif
+#ifdef YP
+ { NSSRC_NIS, nis_setpwent, (void *)SETPWENT },
+#endif
+ { NSSRC_COMPAT, compat_setpwent, (void *)SETPWENT },
+#ifdef NS_CACHING
+ NS_CACHE_CB(&cache_info)
+#endif
+ { NULL, NULL, NULL }
+ };
+ (void)_nsdispatch(NULL, dtab, NSDB_PASSWD, "setpwent", defaultsrc,
+ stayopen);
+ return (1);
+}
+
+
+void
+endpwent(void)
+{
+#ifdef NS_CACHING
+ static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
+ passwd, (void *)nss_lt_all,
+ NULL, NULL);
+#endif
+
+ static const ns_dtab dtab[] = {
+ { NSSRC_FILES, files_setpwent, (void *)ENDPWENT },
+#ifdef HESIOD
+ { NSSRC_DNS, dns_setpwent, (void *)ENDPWENT },
+#endif
+#ifdef YP
+ { NSSRC_NIS, nis_setpwent, (void *)ENDPWENT },
+#endif
+ { NSSRC_COMPAT, compat_setpwent, (void *)ENDPWENT },
+#ifdef NS_CACHING
+ NS_CACHE_CB(&cache_info)
+#endif
+ { NULL, NULL, NULL }
+ };
+ (void)_nsdispatch(NULL, dtab, NSDB_PASSWD, "endpwent", defaultsrc);
+}
+
+
+int
+getpwent_r(struct passwd *pwd, char *buffer, size_t bufsize,
+ struct passwd **result)
+{
+#ifdef NS_CACHING
+ static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
+ passwd, (void *)nss_lt_all,
+ pwd_marshal_func, pwd_unmarshal_func);
+#endif
+
+ static const ns_dtab dtab[] = {
+ { NSSRC_FILES, files_passwd, (void *)nss_lt_all },
+#ifdef HESIOD
+ { NSSRC_DNS, dns_passwd, (void *)nss_lt_all },
+#endif
+#ifdef YP
+ { NSSRC_NIS, nis_passwd, (void *)nss_lt_all },
+#endif
+ { NSSRC_COMPAT, compat_passwd, (void *)nss_lt_all },
+#ifdef NS_CACHING
+ NS_CACHE_CB(&cache_info)
+#endif
+ { NULL, NULL, NULL }
+ };
+ int rv, ret_errno;
+
+ pwd_init(pwd);
+ ret_errno = 0;
+ *result = NULL;
+ rv = _nsdispatch(result, dtab, NSDB_PASSWD, "getpwent_r", defaultsrc,
+ pwd, buffer, bufsize, &ret_errno);
+ if (rv == NS_SUCCESS)
+ return (0);
+ else
+ return (ret_errno);
+}
+
+
+int
+getpwnam_r(const char *name, struct passwd *pwd, char *buffer, size_t bufsize,
+ struct passwd **result)
+{
+#ifdef NS_CACHING
+ static const nss_cache_info cache_info =
+ NS_COMMON_CACHE_INFO_INITIALIZER(
+ passwd, (void *)nss_lt_name,
+ pwd_id_func, pwd_marshal_func, pwd_unmarshal_func);
+#endif
+
+ static const ns_dtab dtab[] = {
+ { NSSRC_FILES, files_passwd, (void *)nss_lt_name },
+#ifdef HESIOD
+ { NSSRC_DNS, dns_passwd, (void *)nss_lt_name },
+#endif
+#ifdef YP
+ { NSSRC_NIS, nis_passwd, (void *)nss_lt_name },
+#endif
+ { NSSRC_COMPAT, compat_passwd, (void *)nss_lt_name },
+#ifdef NS_CACHING
+ NS_CACHE_CB(&cache_info)
+#endif
+ { NULL, NULL, NULL }
+ };
+ int rv, ret_errno;
+
+ pwd_init(pwd);
+ ret_errno = 0;
+ *result = NULL;
+ rv = _nsdispatch(result, dtab, NSDB_PASSWD, "getpwnam_r", defaultsrc,
+ name, pwd, buffer, bufsize, &ret_errno);
+ if (rv == NS_SUCCESS)
+ return (0);
+ else
+ return (ret_errno);
+}
+
+
+int
+getpwuid_r(uid_t uid, struct passwd *pwd, char *buffer, size_t bufsize,
+ struct passwd **result)
+{
+#ifdef NS_CACHING
+ static const nss_cache_info cache_info =
+ NS_COMMON_CACHE_INFO_INITIALIZER(
+ passwd, (void *)nss_lt_id,
+ pwd_id_func, pwd_marshal_func, pwd_unmarshal_func);
+#endif
+
+ static const ns_dtab dtab[] = {
+ { NSSRC_FILES, files_passwd, (void *)nss_lt_id },
+#ifdef HESIOD
+ { NSSRC_DNS, dns_passwd, (void *)nss_lt_id },
+#endif
+#ifdef YP
+ { NSSRC_NIS, nis_passwd, (void *)nss_lt_id },
+#endif
+ { NSSRC_COMPAT, compat_passwd, (void *)nss_lt_id },
+#ifdef NS_CACHING
+ NS_CACHE_CB(&cache_info)
+#endif
+ { NULL, NULL, NULL }
+ };
+ int rv, ret_errno;
+
+ pwd_init(pwd);
+ ret_errno = 0;
+ *result = NULL;
+ rv = _nsdispatch(result, dtab, NSDB_PASSWD, "getpwuid_r", defaultsrc,
+ uid, pwd, buffer, bufsize, &ret_errno);
+ if (rv == NS_SUCCESS)
+ return (0);
+ else
+ return (ret_errno);
+}
+
+
+static void
+pwd_init(struct passwd *pwd)
+{
+ static char nul[] = "";
+
+ memset(pwd, 0, sizeof(*pwd));
+ pwd->pw_uid = (uid_t)-1; /* Considered least likely to lead to */
+ pwd->pw_gid = (gid_t)-1; /* a security issue. */
+ pwd->pw_name = nul;
+ pwd->pw_passwd = nul;
+ pwd->pw_class = nul;
+ pwd->pw_gecos = nul;
+ pwd->pw_dir = nul;
+ pwd->pw_shell = nul;
+}
+
+
+static struct passwd pwd;
+static char *pwd_storage;
+static size_t pwd_storage_size;
+
+
+static struct passwd *
+getpw(int (*fn)(union key, struct passwd *, char *, size_t, struct passwd **),
+ union key key)
+{
+ int rv;
+ struct passwd *res;
+
+ if (pwd_storage == NULL) {
+ pwd_storage = malloc(PWD_STORAGE_INITIAL);
+ if (pwd_storage == NULL)
+ return (NULL);
+ pwd_storage_size = PWD_STORAGE_INITIAL;
+ }
+ do {
+ rv = fn(key, &pwd, pwd_storage, pwd_storage_size, &res);
+ if (res == NULL && rv == ERANGE) {
+ free(pwd_storage);
+ if ((pwd_storage_size << 1) > PWD_STORAGE_MAX) {
+ pwd_storage = NULL;
+ errno = ERANGE;
+ return (NULL);
+ }
+ pwd_storage_size <<= 1;
+ pwd_storage = malloc(pwd_storage_size);
+ if (pwd_storage == NULL)
+ return (NULL);
+ }
+ } while (res == NULL && rv == ERANGE);
+ if (rv != 0)
+ errno = rv;
+ return (res);
+}
+
+
+static int
+wrap_getpwnam_r(union key key, struct passwd *pwd, char *buffer,
+ size_t bufsize, struct passwd **res)
+{
+ return (getpwnam_r(key.name, pwd, buffer, bufsize, res));
+}
+
+
+static int
+wrap_getpwuid_r(union key key, struct passwd *pwd, char *buffer,
+ size_t bufsize, struct passwd **res)
+{
+ return (getpwuid_r(key.uid, pwd, buffer, bufsize, res));
+}
+
+
+static int
+wrap_getpwent_r(union key key __unused, struct passwd *pwd, char *buffer,
+ size_t bufsize, struct passwd **res)
+{
+ return (getpwent_r(pwd, buffer, bufsize, res));
+}
+
+
+struct passwd *
+getpwnam(const char *name)
+{
+ union key key;
+
+ key.name = name;
+ return (getpw(wrap_getpwnam_r, key));
+}
+
+
+struct passwd *
+getpwuid(uid_t uid)
+{
+ union key key;
+
+ key.uid = uid;
+ return (getpw(wrap_getpwuid_r, key));
+}
+
+
+struct passwd *
+getpwent(void)
+{
+ union key key;
+
+ key.uid = 0; /* not used */
+ return (getpw(wrap_getpwent_r, key));
+}
+
+
+/*
+ * files backend
+ */
+static DB *
+pwdbopen(int *version)
+{
+ DB *res;
+ DBT key, entry;
+ int rv;
+
+ if (geteuid() != 0 ||
+ (res = dbopen(_PATH_SMP_DB, O_RDONLY, 0, DB_HASH, NULL)) == NULL)
+ res = dbopen(_PATH_MP_DB, O_RDONLY, 0, DB_HASH, NULL);
+ if (res == NULL)
+ return (NULL);
+ key.data = _PWD_VERSION_KEY;
+ key.size = strlen(_PWD_VERSION_KEY);
+ rv = res->get(res, &key, &entry, 0);
+ if (rv == 0)
+ *version = *(unsigned char *)entry.data;
+ else
+ *version = 3;
+ if (*version < 3 ||
+ *version >= nitems(pwdb_versions)) {
+ syslog(LOG_CRIT, "Unsupported password database version %d",
+ *version);
+ res->close(res);
+ res = NULL;
+ }
+ return (res);
+}
+
+
+static void
+files_endstate(void *p)
+{
+ DB *db;
+
+ if (p == NULL)
+ return;
+ db = ((struct files_state *)p)->db;
+ if (db != NULL)
+ db->close(db);
+ free(p);
+}
+
+
+static int
+files_setpwent(void *retval, void *mdata, va_list ap)
+{
+ struct files_state *st;
+ int rv, stayopen;
+
+ rv = files_getstate(&st);
+ if (rv != 0)
+ return (NS_UNAVAIL);
+ switch ((enum constants)mdata) {
+ case SETPWENT:
+ stayopen = va_arg(ap, int);
+ st->keynum = 0;
+ if (stayopen)
+ st->db = pwdbopen(&st->version);
+ st->stayopen = stayopen;
+ break;
+ case ENDPWENT:
+ if (st->db != NULL) {
+ (void)st->db->close(st->db);
+ st->db = NULL;
+ }
+ break;
+ default:
+ break;
+ }
+ return (NS_UNAVAIL);
+}
+
+
+static int
+files_passwd(void *retval, void *mdata, va_list ap)
+{
+ char keybuf[MAXLOGNAME + 1];
+ DBT key, entry;
+ struct files_state *st;
+ enum nss_lookup_type how;
+ const char *name;
+ struct passwd *pwd;
+ char *buffer;
+ size_t bufsize, namesize;
+ uid_t uid;
+ uint32_t store;
+ int rv, stayopen = 0, *errnop;
+
+ name = NULL;
+ uid = (uid_t)-1;
+ how = (enum nss_lookup_type)mdata;
+ switch (how) {
+ case nss_lt_name:
+ name = va_arg(ap, const char *);
+ keybuf[0] = _PW_KEYBYNAME;
+ break;
+ case nss_lt_id:
+ uid = va_arg(ap, uid_t);
+ keybuf[0] = _PW_KEYBYUID;
+ break;
+ case nss_lt_all:
+ keybuf[0] = _PW_KEYBYNUM;
+ break;
+ default:
+ rv = NS_NOTFOUND;
+ goto fin;
+ }
+ pwd = va_arg(ap, struct passwd *);
+ buffer = va_arg(ap, char *);
+ bufsize = va_arg(ap, size_t);
+ errnop = va_arg(ap, int *);
+ *errnop = files_getstate(&st);
+ if (*errnop != 0)
+ return (NS_UNAVAIL);
+ if (how == nss_lt_all && st->keynum < 0) {
+ rv = NS_NOTFOUND;
+ goto fin;
+ }
+ if (st->db == NULL &&
+ (st->db = pwdbopen(&st->version)) == NULL) {
+ *errnop = errno;
+ rv = NS_UNAVAIL;
+ goto fin;
+ }
+ if (how == nss_lt_all)
+ stayopen = 1;
+ else
+ stayopen = st->stayopen;
+ key.data = keybuf;
+ do {
+ switch (how) {
+ case nss_lt_name:
+ /* MAXLOGNAME includes NUL byte, but we do not
+ * include the NUL byte in the key.
+ */
+ namesize = strlcpy(&keybuf[1], name, sizeof(keybuf)-1);
+ if (namesize >= sizeof(keybuf)-1) {
+ *errnop = EINVAL;
+ rv = NS_NOTFOUND;
+ goto fin;
+ }
+ key.size = namesize + 1;
+ break;
+ case nss_lt_id:
+ if (st->version < _PWD_CURRENT_VERSION) {
+ memcpy(&keybuf[1], &uid, sizeof(uid));
+ key.size = sizeof(uid) + 1;
+ } else {
+ store = htonl(uid);
+ memcpy(&keybuf[1], &store, sizeof(store));
+ key.size = sizeof(store) + 1;
+ }
+ break;
+ case nss_lt_all:
+ st->keynum++;
+ if (st->version < _PWD_CURRENT_VERSION) {
+ memcpy(&keybuf[1], &st->keynum,
+ sizeof(st->keynum));
+ key.size = sizeof(st->keynum) + 1;
+ } else {
+ store = htonl(st->keynum);
+ memcpy(&keybuf[1], &store, sizeof(store));
+ key.size = sizeof(store) + 1;
+ }
+ break;
+ }
+ keybuf[0] = _PW_VERSIONED(keybuf[0], st->version);
+ rv = st->db->get(st->db, &key, &entry, 0);
+ if (rv < 0 || rv > 1) { /* should never return > 1 */
+ *errnop = errno;
+ rv = NS_UNAVAIL;
+ goto fin;
+ } else if (rv == 1) {
+ if (how == nss_lt_all)
+ st->keynum = -1;
+ rv = NS_NOTFOUND;
+ goto fin;
+ }
+ rv = pwdb_versions[st->version].match(entry.data, entry.size,
+ how, name, uid);
+ if (rv != NS_SUCCESS)
+ continue;
+ if (entry.size > bufsize) {
+ *errnop = ERANGE;
+ rv = NS_RETURN;
+ break;
+ }
+ memcpy(buffer, entry.data, entry.size);
+ rv = pwdb_versions[st->version].parse(buffer, entry.size, pwd,
+ errnop);
+ } while (how == nss_lt_all && !(rv & NS_TERMINATE));
+fin:
+ if (st->db != NULL && !stayopen) {
+ (void)st->db->close(st->db);
+ st->db = NULL;
+ }
+ if (rv == NS_SUCCESS) {
+ pwd->pw_fields &= ~_PWF_SOURCE;
+ pwd->pw_fields |= _PWF_FILES;
+ if (retval != NULL)
+ *(struct passwd **)retval = pwd;
+ }
+ return (rv);
+}
+
+
+static int
+pwdb_match_entry_v3(char *entry, size_t entrysize, enum nss_lookup_type how,
+ const char *name, uid_t uid)
+{
+ const char *p, *eom;
+ uid_t uid2;
+
+ eom = &entry[entrysize];
+ for (p = entry; p < eom; p++)
+ if (*p == '\0')
+ break;
+ if (*p != '\0')
+ return (NS_NOTFOUND);
+ if (how == nss_lt_all)
+ return (NS_SUCCESS);
+ if (how == nss_lt_name)
+ return (strcmp(name, entry) == 0 ? NS_SUCCESS : NS_NOTFOUND);
+ for (p++; p < eom; p++)
+ if (*p == '\0')
+ break;
+ if (*p != '\0' || (++p) + sizeof(uid) >= eom)
+ return (NS_NOTFOUND);
+ memcpy(&uid2, p, sizeof(uid2));
+ return (uid == uid2 ? NS_SUCCESS : NS_NOTFOUND);
+}
+
+
+static int
+pwdb_parse_entry_v3(char *buffer, size_t bufsize, struct passwd *pwd,
+ int *errnop)
+{
+ char *p, *eom;
+ int32_t pw_change, pw_expire;
+
+ /* THIS CODE MUST MATCH THAT IN pwd_mkdb. */
+ p = buffer;
+ eom = &buffer[bufsize];
+#define STRING(field) do { \
+ (field) = p; \
+ while (p < eom && *p != '\0') \
+ p++; \
+ if (p >= eom) \
+ return (NS_NOTFOUND); \
+ p++; \
+ } while (0)
+#define SCALAR(field) do { \
+ if (p + sizeof(field) > eom) \
+ return (NS_NOTFOUND); \
+ memcpy(&(field), p, sizeof(field)); \
+ p += sizeof(field); \
+ } while (0)
+ STRING(pwd->pw_name);
+ STRING(pwd->pw_passwd);
+ SCALAR(pwd->pw_uid);
+ SCALAR(pwd->pw_gid);
+ SCALAR(pw_change);
+ STRING(pwd->pw_class);
+ STRING(pwd->pw_gecos);
+ STRING(pwd->pw_dir);
+ STRING(pwd->pw_shell);
+ SCALAR(pw_expire);
+ SCALAR(pwd->pw_fields);
+#undef STRING
+#undef SCALAR
+ pwd->pw_change = pw_change;
+ pwd->pw_expire = pw_expire;
+ return (NS_SUCCESS);
+}
+
+
+static int
+pwdb_match_entry_v4(char *entry, size_t entrysize, enum nss_lookup_type how,
+ const char *name, uid_t uid)
+{
+ const char *p, *eom;
+ uint32_t uid2;
+
+ eom = &entry[entrysize];
+ for (p = entry; p < eom; p++)
+ if (*p == '\0')
+ break;
+ if (*p != '\0')
+ return (NS_NOTFOUND);
+ if (how == nss_lt_all)
+ return (NS_SUCCESS);
+ if (how == nss_lt_name)
+ return (strcmp(name, entry) == 0 ? NS_SUCCESS : NS_NOTFOUND);
+ for (p++; p < eom; p++)
+ if (*p == '\0')
+ break;
+ if (*p != '\0' || (++p) + sizeof(uid) >= eom)
+ return (NS_NOTFOUND);
+ memcpy(&uid2, p, sizeof(uid2));
+ uid2 = ntohl(uid2);
+ return (uid == (uid_t)uid2 ? NS_SUCCESS : NS_NOTFOUND);
+}
+
+
+static int
+pwdb_parse_entry_v4(char *buffer, size_t bufsize, struct passwd *pwd,
+ int *errnop)
+{
+ char *p, *eom;
+ uint32_t n;
+
+ /* THIS CODE MUST MATCH THAT IN pwd_mkdb. */
+ p = buffer;
+ eom = &buffer[bufsize];
+#define STRING(field) do { \
+ (field) = p; \
+ while (p < eom && *p != '\0') \
+ p++; \
+ if (p >= eom) \
+ return (NS_NOTFOUND); \
+ p++; \
+ } while (0)
+#define SCALAR(field) do { \
+ if (p + sizeof(n) > eom) \
+ return (NS_NOTFOUND); \
+ memcpy(&n, p, sizeof(n)); \
+ (field) = ntohl(n); \
+ p += sizeof(n); \
+ } while (0)
+ STRING(pwd->pw_name);
+ STRING(pwd->pw_passwd);
+ SCALAR(pwd->pw_uid);
+ SCALAR(pwd->pw_gid);
+ SCALAR(pwd->pw_change);
+ STRING(pwd->pw_class);
+ STRING(pwd->pw_gecos);
+ STRING(pwd->pw_dir);
+ STRING(pwd->pw_shell);
+ SCALAR(pwd->pw_expire);
+ SCALAR(pwd->pw_fields);
+#undef STRING
+#undef SCALAR
+ return (NS_SUCCESS);
+}
+
+
+#ifdef HESIOD
+/*
+ * dns backend
+ */
+static void
+dns_endstate(void *p)
+{
+ free(p);
+}
+
+
+static int
+dns_setpwent(void *retval, void *mdata, va_list ap)
+{
+ struct dns_state *st;
+ int rv;
+
+ rv = dns_getstate(&st);
+ if (rv != 0)
+ return (NS_UNAVAIL);
+ st->counter = 0;
+ return (NS_UNAVAIL);
+}
+
+
+static int
+dns_passwd(void *retval, void *mdata, va_list ap)
+{
+ char buf[HESIOD_NAME_MAX];
+ struct dns_state *st;
+ struct passwd *pwd;
+ const char *name, *label;
+ void *ctx;
+ char *buffer, **hes;
+ size_t bufsize, linesize;
+ uid_t uid;
+ enum nss_lookup_type how;
+ int rv, *errnop;
+
+ ctx = NULL;
+ hes = NULL;
+ name = NULL;
+ uid = (uid_t)-1;
+ how = (enum nss_lookup_type)mdata;
+ switch (how) {
+ case nss_lt_name:
+ name = va_arg(ap, const char *);
+ break;
+ case nss_lt_id:
+ uid = va_arg(ap, uid_t);
+ break;
+ case nss_lt_all:
+ break;
+ }
+ pwd = va_arg(ap, struct passwd *);
+ buffer = va_arg(ap, char *);
+ bufsize = va_arg(ap, size_t);
+ errnop = va_arg(ap, int *);
+ *errnop = dns_getstate(&st);
+ if (*errnop != 0)
+ return (NS_UNAVAIL);
+ if (hesiod_init(&ctx) != 0) {
+ *errnop = errno;
+ rv = NS_UNAVAIL;
+ goto fin;
+ }
+ do {
+ rv = NS_NOTFOUND;
+ switch (how) {
+ case nss_lt_name:
+ label = name;
+ break;
+ case nss_lt_id:
+ if (snprintf(buf, sizeof(buf), "%lu",
+ (unsigned long)uid) >= sizeof(buf))
+ goto fin;
+ label = buf;
+ break;
+ case nss_lt_all:
+ if (st->counter < 0)
+ goto fin;
+ if (snprintf(buf, sizeof(buf), "passwd-%ld",
+ st->counter++) >= sizeof(buf))
+ goto fin;
+ label = buf;
+ break;
+ }
+ hes = hesiod_resolve(ctx, label,
+ how == nss_lt_id ? "uid" : "passwd");
+ if (hes == NULL) {
+ if (how == nss_lt_all)
+ st->counter = -1;
+ if (errno != ENOENT)
+ *errnop = errno;
+ goto fin;
+ }
+ rv = __pw_match_entry(hes[0], strlen(hes[0]), how, name, uid);
+ if (rv != NS_SUCCESS) {
+ hesiod_free_list(ctx, hes);
+ hes = NULL;
+ continue;
+ }
+ linesize = strlcpy(buffer, hes[0], bufsize);
+ if (linesize >= bufsize) {
+ *errnop = ERANGE;
+ rv = NS_RETURN;
+ continue;
+ }
+ hesiod_free_list(ctx, hes);
+ hes = NULL;
+ rv = __pw_parse_entry(buffer, bufsize, pwd, 0, errnop);
+ } while (how == nss_lt_all && !(rv & NS_TERMINATE));
+fin:
+ if (hes != NULL)
+ hesiod_free_list(ctx, hes);
+ if (ctx != NULL)
+ hesiod_end(ctx);
+ if (rv == NS_SUCCESS) {
+ pwd->pw_fields &= ~_PWF_SOURCE;
+ pwd->pw_fields |= _PWF_HESIOD;
+ if (retval != NULL)
+ *(struct passwd **)retval = pwd;
+ }
+ return (rv);
+}
+#endif /* HESIOD */
+
+
+#ifdef YP
+/*
+ * nis backend
+ */
+static void
+nis_endstate(void *p)
+{
+ free(((struct nis_state *)p)->key);
+ free(p);
+}
+
+/*
+ * Test for the presence of special FreeBSD-specific master.passwd.by*
+ * maps. We do this using yp_order(). If it fails, then either the server
+ * doesn't have the map, or the YPPROC_ORDER procedure isn't supported by
+ * the server (Sun NIS+ servers in YP compat mode behave this way). If
+ * the master.passwd.by* maps don't exist, then let the lookup routine try
+ * the regular passwd.by* maps instead. If the lookup routine fails, it
+ * can return an error as needed.
+ */
+static int
+nis_map(char *domain, enum nss_lookup_type how, char *buffer, size_t bufsize,
+ int *master)
+{
+ int rv, order;
+
+ *master = 0;
+ if (geteuid() == 0) {
+ if (snprintf(buffer, bufsize, "master.passwd.by%s",
+ (how == nss_lt_id) ? "uid" : "name") >= bufsize)
+ return (NS_UNAVAIL);
+ rv = yp_order(domain, buffer, &order);
+ if (rv == 0) {
+ *master = 1;
+ return (NS_SUCCESS);
+ }
+ }
+
+ if (snprintf(buffer, bufsize, "passwd.by%s",
+ (how == nss_lt_id) ? "uid" : "name") >= bufsize)
+ return (NS_UNAVAIL);
+
+ return (NS_SUCCESS);
+}
+
+
+static int
+nis_adjunct(char *domain, const char *name, char *buffer, size_t bufsize)
+{
+ int rv;
+ char *result, *p, *q, *eor;
+ int resultlen;
+
+ result = NULL;
+ rv = yp_match(domain, "passwd.adjunct.byname", name, strlen(name),
+ &result, &resultlen);
+ if (rv != 0)
+ rv = 1;
+ else {
+ eor = &result[resultlen];
+ p = memchr(result, ':', eor - result);
+ if (p != NULL && ++p < eor &&
+ (q = memchr(p, ':', eor - p)) != NULL) {
+ if (q - p >= bufsize)
+ rv = -1;
+ else {
+ memcpy(buffer, p, q - p);
+ buffer[q - p] ='\0';
+ }
+ } else
+ rv = 1;
+ }
+ free(result);
+ return (rv);
+}
+
+
+static int
+nis_setpwent(void *retval, void *mdata, va_list ap)
+{
+ struct nis_state *st;
+ int rv;
+
+ rv = nis_getstate(&st);
+ if (rv != 0)
+ return (NS_UNAVAIL);
+ st->done = 0;
+ free(st->key);
+ st->key = NULL;
+ return (NS_UNAVAIL);
+}
+
+
+static int
+nis_passwd(void *retval, void *mdata, va_list ap)
+{
+ char map[YPMAXMAP];
+ struct nis_state *st;
+ struct passwd *pwd;
+ const char *name;
+ char *buffer, *key, *result;
+ size_t bufsize;
+ uid_t uid;
+ enum nss_lookup_type how;
+ int *errnop, keylen, resultlen, rv, master;
+
+ name = NULL;
+ uid = (uid_t)-1;
+ how = (enum nss_lookup_type)mdata;
+ switch (how) {
+ case nss_lt_name:
+ name = va_arg(ap, const char *);
+ break;
+ case nss_lt_id:
+ uid = va_arg(ap, uid_t);
+ break;
+ case nss_lt_all:
+ break;
+ }
+ pwd = va_arg(ap, struct passwd *);
+ buffer = va_arg(ap, char *);
+ bufsize = va_arg(ap, size_t);
+ errnop = va_arg(ap, int *);
+ *errnop = nis_getstate(&st);
+ if (*errnop != 0)
+ return (NS_UNAVAIL);
+ if (st->domain[0] == '\0') {
+ if (getdomainname(st->domain, sizeof(st->domain)) != 0) {
+ *errnop = errno;
+ return (NS_UNAVAIL);
+ }
+ }
+ rv = nis_map(st->domain, how, map, sizeof(map), &master);
+ if (rv != NS_SUCCESS)
+ return (rv);
+ result = NULL;
+ do {
+ rv = NS_NOTFOUND;
+ switch (how) {
+ case nss_lt_name:
+ if (strlcpy(buffer, name, bufsize) >= bufsize)
+ goto erange;
+ break;
+ case nss_lt_id:
+ if (snprintf(buffer, bufsize, "%lu",
+ (unsigned long)uid) >= bufsize)
+ goto erange;
+ break;
+ case nss_lt_all:
+ if (st->done)
+ goto fin;
+ break;
+ }
+ result = NULL;
+ if (how == nss_lt_all) {
+ if (st->key == NULL)
+ rv = yp_first(st->domain, map, &st->key,
+ &st->keylen, &result, &resultlen);
+ else {
+ key = st->key;
+ keylen = st->keylen;
+ st->key = NULL;
+ rv = yp_next(st->domain, map, key, keylen,
+ &st->key, &st->keylen, &result,
+ &resultlen);
+ free(key);
+ }
+ if (rv != 0) {
+ free(result);
+ free(st->key);
+ st->key = NULL;
+ if (rv == YPERR_NOMORE)
+ st->done = 1;
+ else
+ rv = NS_UNAVAIL;
+ goto fin;
+ }
+ } else {
+ rv = yp_match(st->domain, map, buffer, strlen(buffer),
+ &result, &resultlen);
+ if (rv == YPERR_KEY) {
+ rv = NS_NOTFOUND;
+ continue;
+ } else if (rv != 0) {
+ free(result);
+ rv = NS_UNAVAIL;
+ continue;
+ }
+ }
+ if (resultlen >= bufsize) {
+ free(result);
+ goto erange;
+ }
+ memcpy(buffer, result, resultlen);
+ buffer[resultlen] = '\0';
+ free(result);
+ rv = __pw_match_entry(buffer, resultlen, how, name, uid);
+ if (rv == NS_SUCCESS)
+ rv = __pw_parse_entry(buffer, resultlen, pwd, master,
+ errnop);
+ } while (how == nss_lt_all && !(rv & NS_TERMINATE));
+fin:
+ if (rv == NS_SUCCESS) {
+ if (strstr(pwd->pw_passwd, "##") != NULL) {
+ rv = nis_adjunct(st->domain, pwd->pw_name,
+ &buffer[resultlen+1], bufsize-resultlen-1);
+ if (rv < 0)
+ goto erange;
+ else if (rv == 0)
+ pwd->pw_passwd = &buffer[resultlen+1];
+ }
+ pwd->pw_fields &= ~_PWF_SOURCE;
+ pwd->pw_fields |= _PWF_NIS;
+ if (retval != NULL)
+ *(struct passwd **)retval = pwd;
+ rv = NS_SUCCESS;
+ }
+ return (rv);
+erange:
+ *errnop = ERANGE;
+ return (NS_RETURN);
+}
+#endif /* YP */
+
+
+/*
+ * compat backend
+ */
+static void
+compat_clear_template(struct passwd *template)
+{
+
+ free(template->pw_passwd);
+ free(template->pw_gecos);
+ free(template->pw_dir);
+ free(template->pw_shell);
+ memset(template, 0, sizeof(*template));
+}
+
+
+static int
+compat_set_template(struct passwd *src, struct passwd *template)
+{
+
+ compat_clear_template(template);
+#ifdef PW_OVERRIDE_PASSWD
+ if ((src->pw_fields & _PWF_PASSWD) &&
+ (template->pw_passwd = strdup(src->pw_passwd)) == NULL)
+ goto enomem;
+#endif
+ if (src->pw_fields & _PWF_UID)
+ template->pw_uid = src->pw_uid;
+ if (src->pw_fields & _PWF_GID)
+ template->pw_gid = src->pw_gid;
+ if ((src->pw_fields & _PWF_GECOS) &&
+ (template->pw_gecos = strdup(src->pw_gecos)) == NULL)
+ goto enomem;
+ if ((src->pw_fields & _PWF_DIR) &&
+ (template->pw_dir = strdup(src->pw_dir)) == NULL)
+ goto enomem;
+ if ((src->pw_fields & _PWF_SHELL) &&
+ (template->pw_shell = strdup(src->pw_shell)) == NULL)
+ goto enomem;
+ template->pw_fields = src->pw_fields;
+ return (0);
+enomem:
+ syslog(LOG_ERR, "getpwent memory allocation failure");
+ return (-1);
+}
+
+
+static int
+compat_use_template(struct passwd *pwd, struct passwd *template, char *buffer,
+ size_t bufsize)
+{
+ struct passwd hold;
+ char *copy, *p, *q, *eob;
+ size_t n;
+
+ /* We cannot know the layout of the password fields in `buffer',
+ * so we have to copy everything.
+ */
+ if (template->pw_fields == 0) /* nothing to fill-in */
+ return (0);
+ n = 0;
+ n += pwd->pw_name != NULL ? strlen(pwd->pw_name) + 1 : 0;
+ n += pwd->pw_passwd != NULL ? strlen(pwd->pw_passwd) + 1 : 0;
+ n += pwd->pw_class != NULL ? strlen(pwd->pw_class) + 1 : 0;
+ n += pwd->pw_gecos != NULL ? strlen(pwd->pw_gecos) + 1 : 0;
+ n += pwd->pw_dir != NULL ? strlen(pwd->pw_dir) + 1 : 0;
+ n += pwd->pw_shell != NULL ? strlen(pwd->pw_shell) + 1 : 0;
+ copy = malloc(n);
+ if (copy == NULL) {
+ syslog(LOG_ERR, "getpwent memory allocation failure");
+ return (ENOMEM);
+ }
+ p = copy;
+ eob = &copy[n];
+#define COPY(field) do { \
+ if (pwd->field == NULL) \
+ hold.field = NULL; \
+ else { \
+ hold.field = p; \
+ p += strlcpy(p, pwd->field, eob-p) + 1; \
+ } \
+} while (0)
+ COPY(pw_name);
+ COPY(pw_passwd);
+ COPY(pw_class);
+ COPY(pw_gecos);
+ COPY(pw_dir);
+ COPY(pw_shell);
+#undef COPY
+ p = buffer;
+ eob = &buffer[bufsize];
+#define COPY(field, flag) do { \
+ q = (template->pw_fields & flag) ? template->field : hold.field; \
+ if (q == NULL) \
+ pwd->field = NULL; \
+ else { \
+ pwd->field = p; \
+ if ((n = strlcpy(p, q, eob-p)) >= eob-p) { \
+ free(copy); \
+ return (ERANGE); \
+ } \
+ p += n + 1; \
+ } \
+} while (0)
+ COPY(pw_name, 0);
+#ifdef PW_OVERRIDE_PASSWD
+ COPY(pw_passwd, _PWF_PASSWD);
+#else
+ COPY(pw_passwd, 0);
+#endif
+ COPY(pw_class, 0);
+ COPY(pw_gecos, _PWF_GECOS);
+ COPY(pw_dir, _PWF_DIR);
+ COPY(pw_shell, _PWF_SHELL);
+#undef COPY
+#define COPY(field, flag) do { \
+ if (template->pw_fields & flag) \
+ pwd->field = template->field; \
+} while (0)
+ COPY(pw_uid, _PWF_UID);
+ COPY(pw_gid, _PWF_GID);
+#undef COPY
+ free(copy);
+ return (0);
+}
+
+
+static int
+compat_exclude(const char *name, DB **db)
+{
+ DBT key, data;
+
+ if (*db == NULL &&
+ (*db = dbopen(NULL, O_RDWR, 600, DB_HASH, 0)) == NULL)
+ return (errno);
+ key.size = strlen(name);
+ key.data = (char *)name;
+ data.size = 0;
+ data.data = NULL;
+
+ if ((*db)->put(*db, &key, &data, 0) == -1)
+ return (errno);
+ return (0);
+}
+
+
+static int
+compat_is_excluded(const char *name, DB *db)
+{
+ DBT key, data;
+
+ if (db == NULL)
+ return (0);
+ key.size = strlen(name);
+ key.data = (char *)name;
+ return (db->get(db, &key, &data, 0) == 0);
+}
+
+
+static int
+compat_redispatch(struct compat_state *st, enum nss_lookup_type how,
+ enum nss_lookup_type lookup_how, const char *name, const char *lookup_name,
+ uid_t uid, struct passwd *pwd, char *buffer, size_t bufsize, int *errnop)
+{
+ static const ns_src compatsrc[] = {
+#ifdef YP
+ { NSSRC_NIS, NS_SUCCESS },
+#endif
+ { NULL, 0 }
+ };
+ ns_dtab dtab[] = {
+#ifdef YP
+ { NSSRC_NIS, nis_passwd, NULL },
+#endif
+#ifdef HESIOD
+ { NSSRC_DNS, dns_passwd, NULL },
+#endif
+ { NULL, NULL, NULL }
+ };
+ void *discard;
+ int e, i, rv;
+
+ for (i = 0; i < (int)(nitems(dtab) - 1); i++)
+ dtab[i].mdata = (void *)lookup_how;
+more:
+ pwd_init(pwd);
+ switch (lookup_how) {
+ case nss_lt_all:
+ rv = _nsdispatch(&discard, dtab, NSDB_PASSWD_COMPAT,
+ "getpwent_r", compatsrc, pwd, buffer, bufsize,
+ errnop);
+ break;
+ case nss_lt_id:
+ rv = _nsdispatch(&discard, dtab, NSDB_PASSWD_COMPAT,
+ "getpwuid_r", compatsrc, uid, pwd, buffer,
+ bufsize, errnop);
+ break;
+ case nss_lt_name:
+ rv = _nsdispatch(&discard, dtab, NSDB_PASSWD_COMPAT,
+ "getpwnam_r", compatsrc, lookup_name, pwd, buffer,
+ bufsize, errnop);
+ break;
+ default:
+ return (NS_UNAVAIL);
+ }
+ if (rv != NS_SUCCESS)
+ return (rv);
+ if (compat_is_excluded(pwd->pw_name, st->exclude)) {
+ if (how == nss_lt_all)
+ goto more;
+ return (NS_NOTFOUND);
+ }
+ e = compat_use_template(pwd, &st->template, buffer, bufsize);
+ if (e != 0) {
+ *errnop = e;
+ if (e == ERANGE)
+ return (NS_RETURN);
+ else
+ return (NS_UNAVAIL);
+ }
+ switch (how) {
+ case nss_lt_name:
+ if (strcmp(name, pwd->pw_name) != 0)
+ return (NS_NOTFOUND);
+ break;
+ case nss_lt_id:
+ if (uid != pwd->pw_uid)
+ return (NS_NOTFOUND);
+ break;
+ default:
+ break;
+ }
+ return (NS_SUCCESS);
+}
+
+
+static void
+compat_endstate(void *p)
+{
+ struct compat_state *st;
+
+ if (p == NULL)
+ return;
+ st = (struct compat_state *)p;
+ if (st->db != NULL)
+ st->db->close(st->db);
+ if (st->exclude != NULL)
+ st->exclude->close(st->exclude);
+ compat_clear_template(&st->template);
+ free(p);
+}
+
+
+static int
+compat_setpwent(void *retval, void *mdata, va_list ap)
+{
+ static const ns_src compatsrc[] = {
+#ifdef YP
+ { NSSRC_NIS, NS_SUCCESS },
+#endif
+ { NULL, 0 }
+ };
+ ns_dtab dtab[] = {
+#ifdef YP
+ { NSSRC_NIS, nis_setpwent, NULL },
+#endif
+#ifdef HESIOD
+ { NSSRC_DNS, dns_setpwent, NULL },
+#endif
+ { NULL, NULL, NULL }
+ };
+ struct compat_state *st;
+ int rv, stayopen;
+
+#define set_setent(x, y) do { \
+ int i; \
+ for (i = 0; i < (int)(nitems(x) - 1); i++) \
+ x[i].mdata = (void *)y; \
+} while (0)
+
+ rv = compat_getstate(&st);
+ if (rv != 0)
+ return (NS_UNAVAIL);
+ switch ((enum constants)mdata) {
+ case SETPWENT:
+ stayopen = va_arg(ap, int);
+ st->keynum = 0;
+ if (stayopen)
+ st->db = pwdbopen(&st->version);
+ st->stayopen = stayopen;
+ set_setent(dtab, mdata);
+ (void)_nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, "setpwent",
+ compatsrc, 0);
+ break;
+ case ENDPWENT:
+ if (st->db != NULL) {
+ (void)st->db->close(st->db);
+ st->db = NULL;
+ }
+ set_setent(dtab, mdata);
+ (void)_nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, "endpwent",
+ compatsrc, 0);
+ break;
+ default:
+ break;
+ }
+ return (NS_UNAVAIL);
+#undef set_setent
+}
+
+
+static int
+compat_passwd(void *retval, void *mdata, va_list ap)
+{
+ char keybuf[MAXLOGNAME + 1];
+ DBT key, entry;
+ struct compat_state *st;
+ enum nss_lookup_type how;
+ const char *name;
+ struct passwd *pwd;
+ char *buffer, *pw_name;
+ char *host, *user, *domain;
+ size_t bufsize;
+ uid_t uid;
+ uint32_t store;
+ int rv, from_compat, stayopen, *errnop;
+
+ from_compat = 0;
+ name = NULL;
+ uid = (uid_t)-1;
+ how = (enum nss_lookup_type)mdata;
+ switch (how) {
+ case nss_lt_name:
+ name = va_arg(ap, const char *);
+ break;
+ case nss_lt_id:
+ uid = va_arg(ap, uid_t);
+ break;
+ case nss_lt_all:
+ break;
+ default:
+ rv = NS_NOTFOUND;
+ goto fin;
+ }
+ pwd = va_arg(ap, struct passwd *);
+ buffer = va_arg(ap, char *);
+ bufsize = va_arg(ap, size_t);
+ errnop = va_arg(ap, int *);
+ *errnop = compat_getstate(&st);
+ if (*errnop != 0)
+ return (NS_UNAVAIL);
+ if (how == nss_lt_all && st->keynum < 0) {
+ rv = NS_NOTFOUND;
+ goto fin;
+ }
+ if (st->db == NULL &&
+ (st->db = pwdbopen(&st->version)) == NULL) {
+ *errnop = errno;
+ rv = NS_UNAVAIL;
+ goto fin;
+ }
+ if (how == nss_lt_all) {
+ if (st->keynum < 0) {
+ rv = NS_NOTFOUND;
+ goto fin;
+ }
+ stayopen = 1;
+ } else {
+ st->keynum = 0;
+ stayopen = st->stayopen;
+ }
+docompat:
+ rv = NS_NOTFOUND;
+ switch (st->compat) {
+ case COMPAT_MODE_ALL:
+ rv = compat_redispatch(st, how, how, name, name, uid, pwd,
+ buffer, bufsize, errnop);
+ if (rv != NS_SUCCESS)
+ st->compat = COMPAT_MODE_OFF;
+ break;
+ case COMPAT_MODE_NETGROUP:
+ /* XXX getnetgrent is not thread-safe. */
+ do {
+ rv = getnetgrent(&host, &user, &domain);
+ if (rv == 0) {
+ endnetgrent();
+ st->compat = COMPAT_MODE_OFF;
+ rv = NS_NOTFOUND;
+ continue;
+ } else if (user == NULL || user[0] == '\0')
+ continue;
+ rv = compat_redispatch(st, how, nss_lt_name, name,
+ user, uid, pwd, buffer, bufsize, errnop);
+ } while (st->compat == COMPAT_MODE_NETGROUP &&
+ !(rv & NS_TERMINATE));
+ break;
+ case COMPAT_MODE_NAME:
+ rv = compat_redispatch(st, how, nss_lt_name, name, st->name,
+ uid, pwd, buffer, bufsize, errnop);
+ free(st->name);
+ st->name = NULL;
+ st->compat = COMPAT_MODE_OFF;
+ break;
+ default:
+ break;
+ }
+ if (rv & NS_TERMINATE) {
+ from_compat = 1;
+ goto fin;
+ }
+ key.data = keybuf;
+ rv = NS_NOTFOUND;
+ while (st->keynum >= 0) {
+ st->keynum++;
+ if (st->version < _PWD_CURRENT_VERSION) {
+ memcpy(&keybuf[1], &st->keynum, sizeof(st->keynum));
+ key.size = sizeof(st->keynum) + 1;
+ } else {
+ store = htonl(st->keynum);
+ memcpy(&keybuf[1], &store, sizeof(store));
+ key.size = sizeof(store) + 1;
+ }
+ keybuf[0] = _PW_VERSIONED(_PW_KEYBYNUM, st->version);
+ rv = st->db->get(st->db, &key, &entry, 0);
+ if (rv < 0 || rv > 1) { /* should never return > 1 */
+ *errnop = errno;
+ rv = NS_UNAVAIL;
+ goto fin;
+ } else if (rv == 1) {
+ st->keynum = -1;
+ rv = NS_NOTFOUND;
+ goto fin;
+ }
+ pw_name = (char *)entry.data;
+ switch (pw_name[0]) {
+ case '+':
+ switch (pw_name[1]) {
+ case '\0':
+ st->compat = COMPAT_MODE_ALL;
+ break;
+ case '@':
+ setnetgrent(&pw_name[2]);
+ st->compat = COMPAT_MODE_NETGROUP;
+ break;
+ default:
+ st->name = strdup(&pw_name[1]);
+ if (st->name == NULL) {
+ syslog(LOG_ERR,
+ "getpwent memory allocation failure");
+ *errnop = ENOMEM;
+ rv = NS_UNAVAIL;
+ break;
+ }
+ st->compat = COMPAT_MODE_NAME;
+ }
+ if (entry.size > bufsize) {
+ *errnop = ERANGE;
+ rv = NS_RETURN;
+ goto fin;
+ }
+ memcpy(buffer, entry.data, entry.size);
+ rv = pwdb_versions[st->version].parse(buffer,
+ entry.size, pwd, errnop);
+ if (rv != NS_SUCCESS)
+ ;
+ else if (compat_set_template(pwd, &st->template) < 0) {
+ *errnop = ENOMEM;
+ rv = NS_UNAVAIL;
+ goto fin;
+ }
+ goto docompat;
+ case '-':
+ switch (pw_name[1]) {
+ case '\0':
+ /* XXX Maybe syslog warning */
+ continue;
+ case '@':
+ setnetgrent(&pw_name[2]);
+ while (getnetgrent(&host, &user, &domain) !=
+ 0) {
+ if (user != NULL && user[0] != '\0')
+ compat_exclude(user,
+ &st->exclude);
+ }
+ endnetgrent();
+ continue;
+ default:
+ compat_exclude(&pw_name[1], &st->exclude);
+ continue;
+ }
+ break;
+ default:
+ break;
+ }
+ if (compat_is_excluded((char *)entry.data, st->exclude))
+ continue;
+ rv = pwdb_versions[st->version].match(entry.data, entry.size,
+ how, name, uid);
+ if (rv == NS_RETURN)
+ break;
+ else if (rv != NS_SUCCESS)
+ continue;
+ if (entry.size > bufsize) {
+ *errnop = ERANGE;
+ rv = NS_RETURN;
+ break;
+ }
+ memcpy(buffer, entry.data, entry.size);
+ rv = pwdb_versions[st->version].parse(buffer, entry.size, pwd,
+ errnop);
+ if (rv & NS_TERMINATE)
+ break;
+ }
+fin:
+ if (st->db != NULL && !stayopen) {
+ (void)st->db->close(st->db);
+ st->db = NULL;
+ }
+ if (rv == NS_SUCCESS) {
+ if (!from_compat) {
+ pwd->pw_fields &= ~_PWF_SOURCE;
+ pwd->pw_fields |= _PWF_FILES;
+ }
+ if (retval != NULL)
+ *(struct passwd **)retval = pwd;
+ }
+ return (rv);
+}
+
+
+/*
+ * common passwd line matching and parsing
+ */
+int
+__pw_match_entry(const char *entry, size_t entrysize, enum nss_lookup_type how,
+ const char *name, uid_t uid)
+{
+ const char *p, *eom;
+ char *q;
+ size_t len;
+ unsigned long m;
+
+ eom = entry + entrysize;
+ for (p = entry; p < eom; p++)
+ if (*p == ':')
+ break;
+ if (*p != ':')
+ return (NS_NOTFOUND);
+ if (how == nss_lt_all)
+ return (NS_SUCCESS);
+ if (how == nss_lt_name) {
+ len = strlen(name);
+ if (len == (p - entry) && memcmp(name, entry, len) == 0)
+ return (NS_SUCCESS);
+ else
+ return (NS_NOTFOUND);
+ }
+ for (p++; p < eom; p++)
+ if (*p == ':')
+ break;
+ if (*p != ':')
+ return (NS_NOTFOUND);
+ m = strtoul(++p, &q, 10);
+ if (q[0] != ':' || (uid_t)m != uid)
+ return (NS_NOTFOUND);
+ else
+ return (NS_SUCCESS);
+}
+
+
+/* XXX buffer must be NUL-terminated. errnop is not set correctly. */
+int
+__pw_parse_entry(char *buffer, size_t bufsize __unused, struct passwd *pwd,
+ int master, int *errnop __unused)
+{
+
+ if (__pw_scan(buffer, pwd, master ? _PWSCAN_MASTER : 0) == 0)
+ return (NS_NOTFOUND);
+ else
+ return (NS_SUCCESS);
+}
diff --git a/lib/libc/gen/getttyent.3 b/lib/libc/gen/getttyent.3
new file mode 100644
index 000000000000..18c3f07c1aad
--- /dev/null
+++ b/lib/libc/gen/getttyent.3
@@ -0,0 +1,208 @@
+.\" Copyright (c) 1989, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)getttyent.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd November 17, 1996
+.Dt GETTTYENT 3
+.Os
+.Sh NAME
+.Nm getttyent ,
+.Nm getttynam ,
+.Nm setttyent ,
+.Nm endttyent ,
+.Nm isdialuptty ,
+.Nm isnettty
+.Nd
+.Xr ttys 5
+file routines
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In ttyent.h
+.Ft struct ttyent *
+.Fn getttyent void
+.Ft struct ttyent *
+.Fn getttynam "const char *name"
+.Ft int
+.Fn setttyent void
+.Ft int
+.Fn endttyent void
+.Ft int
+.Fn isdialuptty "const char *name"
+.Ft int
+.Fn isnettty "const char *name"
+.Sh DESCRIPTION
+The
+.Fn getttyent ,
+and
+.Fn getttynam
+functions
+each return a pointer to an object, with the following structure,
+containing the broken-out fields of a line from the tty description
+file.
+.Bd -literal
+struct ttyent {
+ char *ty_name; /* terminal device name */
+ char *ty_getty; /* command to execute, usually getty */
+ char *ty_type; /* terminal type for termcap */
+#define TTY_ON 0x01 /* enable logins (start ty_getty program) */
+#define TTY_SECURE 0x02 /* allow uid of 0 to login */
+#define TTY_DIALUP 0x04 /* is a dialup tty */
+#define TTY_NETWORK 0x08 /* is a network tty */
+ int ty_status; /* status flags */
+ char *ty_window; /* command to start up window manager */
+ char *ty_comment; /* comment field */
+ char *ty_group; /* tty group name */
+};
+.Ed
+.Pp
+The fields are as follows:
+.Bl -tag -width ty_comment
+.It Fa ty_name
+The name of the character-special file.
+.It Fa ty_getty
+The name of the command invoked by
+.Xr init 8
+to initialize tty line characteristics.
+.It Fa ty_type
+The name of the default terminal type connected to this tty line.
+.It Fa ty_status
+A mask of bit fields which indicate various actions allowed on this
+tty line.
+The possible flags are as follows:
+.Bl -tag -width TTY_NETWORK
+.It Dv TTY_ON
+Enables logins (i.e.,
+.Xr init 8
+will start the command referenced by
+.Fa ty_getty
+on this entry).
+.It Dv TTY_SECURE
+Allow users with a uid of 0 to login on this terminal.
+.It Dv TTY_DIALUP
+Identifies a tty as a dialin line.
+If this flag is set, then
+.Fn isdialuptty
+will return a non-zero value.
+.It Dv TTY_NETWORK
+Identifies a tty used for network connections.
+If this flag is set, then
+.Fn isnettty
+will return a non-zero value.
+.El
+.It Fa ty_window
+The command to execute for a window system associated with the line.
+.It Fa ty_group
+A group name to which the tty belongs.
+If no group is specified in the ttys description file,
+then the tty is placed in an anonymous group called "none".
+.It Fa ty_comment
+Any trailing comment field, with any leading hash marks (``#'') or
+whitespace removed.
+.El
+.Pp
+If any of the fields pointing to character strings are unspecified,
+they are returned as null pointers.
+The field
+.Fa ty_status
+will be zero if no flag values are specified.
+.Pp
+See
+.Xr ttys 5
+for a more complete discussion of the meaning and usage of the
+fields.
+.Pp
+The
+.Fn getttyent
+function
+reads the next line from the ttys file, opening the file if necessary.
+The
+.Fn setttyent
+function
+rewinds the file if open, or opens the file if it is unopened.
+The
+.Fn endttyent
+function
+closes any open files.
+.Pp
+The
+.Fn getttynam
+function
+searches from the beginning of the file until a matching
+.Fa name
+is found
+(or until
+.Dv EOF
+is encountered).
+.Sh RETURN VALUES
+The routines
+.Fn getttyent
+and
+.Fn getttynam
+return a null pointer on
+.Dv EOF
+or error.
+The
+.Fn setttyent
+function
+and
+.Fn endttyent
+return 0 on failure and 1 on success.
+.Pp
+The routines
+.Fn isdialuptty
+and
+.Fn isnettty
+return non-zero if the dialup or network flag is set for the
+tty entry relating to the tty named by the argument, and
+zero otherwise.
+.Sh FILES
+.Bl -tag -width /etc/ttys -compact
+.It Pa /etc/ttys
+.El
+.Sh SEE ALSO
+.Xr login 1 ,
+.Xr gettytab 5 ,
+.Xr termcap 5 ,
+.Xr ttys 5 ,
+.Xr getty 8 ,
+.Xr init 8
+.Sh HISTORY
+The
+.Fn getttyent ,
+.Fn getttynam ,
+.Fn setttyent ,
+and
+.Fn endttyent
+functions appeared in
+.Bx 4.3 .
+.Sh BUGS
+These functions use static data storage;
+if the data is needed for future use, it should be
+copied before any subsequent calls overwrite it.
diff --git a/lib/libc/gen/getttyent.c b/lib/libc/gen/getttyent.c
new file mode 100644
index 000000000000..d10430524dac
--- /dev/null
+++ b/lib/libc/gen/getttyent.c
@@ -0,0 +1,292 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)getttyent.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <ttyent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <sys/sysctl.h>
+
+static char zapchar;
+static FILE *tf;
+static size_t lbsize;
+static char *line;
+
+#define MALLOCCHUNK 100
+
+static char *skip(char *);
+static char *value(char *);
+
+struct ttyent *
+getttynam(const char *tty)
+{
+ struct ttyent *t;
+
+ if (strncmp(tty, "/dev/", 5) == 0)
+ tty += 5;
+ setttyent();
+ while ( (t = getttyent()) )
+ if (!strcmp(tty, t->ty_name))
+ break;
+ endttyent();
+ return (t);
+}
+
+static int
+auto_tty_status(const char *ty_name)
+{
+ size_t len;
+ char *buf, *cons, *nextcons;
+
+ /* Check if this is an enabled kernel console line */
+ buf = NULL;
+ if (sysctlbyname("kern.console", NULL, &len, NULL, 0) == -1)
+ return (0); /* Errors mean don't enable */
+ buf = malloc(len);
+ if (sysctlbyname("kern.console", buf, &len, NULL, 0) == -1)
+ goto done;
+
+ if ((cons = strchr(buf, '/')) == NULL)
+ goto done;
+ *cons = '\0';
+ nextcons = buf;
+ while ((cons = strsep(&nextcons, ",")) != NULL && strlen(cons) != 0) {
+ if (strcmp(cons, ty_name) == 0) {
+ free(buf);
+ return (TTY_ON);
+ }
+ }
+
+done:
+ free(buf);
+ return (0);
+}
+
+struct ttyent *
+getttyent(void)
+{
+ static struct ttyent tty;
+ char *p;
+ int c;
+ size_t i;
+
+ if (!tf && !setttyent())
+ return (NULL);
+ for (;;) {
+ if (!fgets(p = line, lbsize, tf))
+ return (NULL);
+ /* extend buffer if line was too big, and retry */
+ while (!strchr(p, '\n') && !feof(tf)) {
+ i = strlen(p);
+ lbsize += MALLOCCHUNK;
+ if ((p = realloc(line, lbsize)) == NULL) {
+ (void)endttyent();
+ return (NULL);
+ }
+ line = p;
+ if (!fgets(&line[i], lbsize - i, tf))
+ return (NULL);
+ }
+ while (isspace((unsigned char)*p))
+ ++p;
+ if (*p && *p != '#')
+ break;
+ }
+
+#define scmp(e) !strncmp(p, e, sizeof(e) - 1) && isspace((unsigned char)p[sizeof(e) - 1])
+#define vcmp(e) !strncmp(p, e, sizeof(e) - 1) && p[sizeof(e) - 1] == '='
+
+ zapchar = 0;
+ tty.ty_name = p;
+ tty.ty_status = 0;
+ tty.ty_window = NULL;
+ tty.ty_group = _TTYS_NOGROUP;
+
+ p = skip(p);
+ if (!*(tty.ty_getty = p))
+ tty.ty_getty = tty.ty_type = NULL;
+ else {
+ p = skip(p);
+ if (!*(tty.ty_type = p))
+ tty.ty_type = NULL;
+ else {
+ /* compatibility kludge: handle network/dialup specially */
+ if (scmp(_TTYS_DIALUP))
+ tty.ty_status |= TTY_DIALUP;
+ else if (scmp(_TTYS_NETWORK))
+ tty.ty_status |= TTY_NETWORK;
+ p = skip(p);
+ }
+ }
+
+ for (; *p; p = skip(p)) {
+ if (scmp(_TTYS_OFF))
+ tty.ty_status &= ~TTY_ON;
+ else if (scmp(_TTYS_ON))
+ tty.ty_status |= TTY_ON;
+ else if (scmp(_TTYS_ONIFCONSOLE))
+ tty.ty_status |= auto_tty_status(tty.ty_name);
+ else if (scmp(_TTYS_SECURE))
+ tty.ty_status |= TTY_SECURE;
+ else if (scmp(_TTYS_INSECURE))
+ tty.ty_status &= ~TTY_SECURE;
+ else if (scmp(_TTYS_DIALUP))
+ tty.ty_status |= TTY_DIALUP;
+ else if (scmp(_TTYS_NETWORK))
+ tty.ty_status |= TTY_NETWORK;
+ else if (vcmp(_TTYS_WINDOW))
+ tty.ty_window = value(p);
+ else if (vcmp(_TTYS_GROUP))
+ tty.ty_group = value(p);
+ else
+ break;
+ }
+
+ if (zapchar == '#' || *p == '#')
+ while ((c = *++p) == ' ' || c == '\t')
+ ;
+ tty.ty_comment = p;
+ if (*p == 0)
+ tty.ty_comment = 0;
+ if ((p = strchr(p, '\n')))
+ *p = '\0';
+ return (&tty);
+}
+
+#define QUOTED 1
+
+/*
+ * Skip over the current field, removing quotes, and return a pointer to
+ * the next field.
+ */
+static char *
+skip(char *p)
+{
+ char *t;
+ int c, q;
+
+ for (q = 0, t = p; (c = *p) != '\0'; p++) {
+ if (c == '"') {
+ q ^= QUOTED; /* obscure, but nice */
+ continue;
+ }
+ if (q == QUOTED && *p == '\\' && *(p+1) == '"')
+ p++;
+ *t++ = *p;
+ if (q == QUOTED)
+ continue;
+ if (c == '#') {
+ zapchar = c;
+ *p = 0;
+ break;
+ }
+ if (c == '\t' || c == ' ' || c == '\n') {
+ zapchar = c;
+ *p++ = 0;
+ while ((c = *p) == '\t' || c == ' ' || c == '\n')
+ p++;
+ break;
+ }
+ }
+ *--t = '\0';
+ return (p);
+}
+
+static char *
+value(char *p)
+{
+
+ return ((p = strchr(p, '=')) ? ++p : NULL);
+}
+
+int
+setttyent(void)
+{
+
+ if (line == NULL) {
+ if ((line = malloc(MALLOCCHUNK)) == NULL)
+ return (0);
+ lbsize = MALLOCCHUNK;
+ }
+ if (tf) {
+ rewind(tf);
+ return (1);
+ } else if ( (tf = fopen(_PATH_TTYS, "re")) )
+ return (1);
+ return (0);
+}
+
+int
+endttyent(void)
+{
+ int rval;
+
+ /*
+ * NB: Don't free `line' because getttynam()
+ * may still be referencing it
+ */
+ if (tf) {
+ rval = (fclose(tf) != EOF);
+ tf = NULL;
+ return (rval);
+ }
+ return (1);
+}
+
+static int
+isttystat(const char *tty, int flag)
+{
+ struct ttyent *t;
+
+ return ((t = getttynam(tty)) == NULL) ? 0 : !!(t->ty_status & flag);
+}
+
+
+int
+isdialuptty(const char *tty)
+{
+
+ return isttystat(tty, TTY_DIALUP);
+}
+
+int
+isnettty(const char *tty)
+{
+
+ return isttystat(tty, TTY_NETWORK);
+}
diff --git a/lib/libc/gen/getusershell.3 b/lib/libc/gen/getusershell.3
new file mode 100644
index 000000000000..1559519c88f6
--- /dev/null
+++ b/lib/libc/gen/getusershell.3
@@ -0,0 +1,99 @@
+.\" $NetBSD: getusershell.3,v 1.6 1999/03/22 19:44:42 garbled Exp $
+.\"
+.\" Copyright (c) 1985, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)getusershell.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd January 16, 1999
+.Dt GETUSERSHELL 3
+.Os
+.Sh NAME
+.Nm getusershell ,
+.Nm setusershell ,
+.Nm endusershell
+.Nd get valid user shells
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft char *
+.Fn getusershell void
+.Ft void
+.Fn setusershell void
+.Ft void
+.Fn endusershell void
+.Sh DESCRIPTION
+The
+.Fn getusershell
+function
+returns a pointer to a valid user shell as defined by the
+system manager in the shells database as described in
+.Xr shells 5 .
+If the shells database is not available,
+.Fn getusershell
+behaves as if
+.Pa /bin/sh
+and
+.Pa /bin/csh
+were listed.
+.Pp
+The
+.Fn getusershell
+function
+reads the next
+line (opening the file if necessary);
+.Fn setusershell
+rewinds the file;
+.Fn endusershell
+closes it.
+.Sh FILES
+.Bl -tag -width /etc/shells -compact
+.It Pa /etc/shells
+.El
+.Sh DIAGNOSTICS
+The routine
+.Fn getusershell
+returns a null pointer (0) on
+.Dv EOF .
+.Sh SEE ALSO
+.Xr nsswitch.conf 5 ,
+.Xr shells 5
+.Sh HISTORY
+The
+.Fn getusershell
+function appeared in
+.Bx 4.3 .
+.Sh BUGS
+The
+.Fn getusershell
+function leaves its result in an internal static object and returns
+a pointer to that object.
+Subsequent calls to
+.Fn getusershell
+will modify the same object.
diff --git a/lib/libc/gen/getusershell.c b/lib/libc/gen/getusershell.c
new file mode 100644
index 000000000000..6e782865dfe3
--- /dev/null
+++ b/lib/libc/gen/getusershell.c
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 1985, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)getusershell.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+/* $NetBSD: getusershell.c,v 1.17 1999/01/25 01:09:34 lukem Exp $ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <sys/file.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <nsswitch.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stringlist.h>
+#include <unistd.h>
+
+#ifdef HESIOD
+#include <hesiod.h>
+#endif
+#ifdef YP
+#include <rpc/rpc.h>
+#include <rpcsvc/ypclnt.h>
+#include <rpcsvc/yp_prot.h>
+#endif
+#include "un-namespace.h"
+
+static const char *const *curshell;
+static StringList *sl;
+
+static const char *const *initshells(void);
+
+/*
+ * Get a list of shells from "shells" nsswitch database
+ */
+char *
+getusershell(void)
+{
+ char *ret;
+
+ if (curshell == NULL)
+ curshell = initshells();
+ /*LINTED*/
+ ret = (char *)*curshell;
+ if (ret != NULL)
+ curshell++;
+ return (ret);
+}
+
+void
+endusershell(void)
+{
+ if (sl) {
+ sl_free(sl, 1);
+ sl = NULL;
+ }
+ curshell = NULL;
+}
+
+void
+setusershell(void)
+{
+
+ curshell = initshells();
+}
+
+
+static int _local_initshells(void *, void *, va_list);
+
+/*ARGSUSED*/
+static int
+_local_initshells(void *rv, void *cb_data, va_list ap)
+{
+ char *sp, *cp;
+ FILE *fp;
+ char line[MAXPATHLEN + 2];
+
+ if (sl)
+ sl_free(sl, 1);
+ sl = sl_init();
+
+ if ((fp = fopen(_PATH_SHELLS, "re")) == NULL)
+ return NS_UNAVAIL;
+
+ cp = line;
+ while (fgets(cp, MAXPATHLEN + 1, fp) != NULL) {
+ while (*cp != '#' && *cp != '/' && *cp != '\0')
+ cp++;
+ if (*cp == '#' || *cp == '\0')
+ continue;
+ sp = cp;
+ while (!isspace(*cp) && *cp != '#' && *cp != '\0')
+ cp++;
+ *cp++ = '\0';
+ sl_add(sl, strdup(sp));
+ }
+ (void)fclose(fp);
+ return NS_SUCCESS;
+}
+
+#ifdef HESIOD
+static int _dns_initshells(void *, void *, va_list);
+
+/*ARGSUSED*/
+static int
+_dns_initshells(void *rv, void *cb_data, va_list ap)
+{
+ char shellname[] = "shells-XXXXX";
+ int hsindex, hpi, r;
+ char **hp;
+ void *context;
+
+ if (sl)
+ sl_free(sl, 1);
+ sl = sl_init();
+ r = NS_UNAVAIL;
+ if (hesiod_init(&context) == -1)
+ return (r);
+
+ for (hsindex = 0; ; hsindex++) {
+ snprintf(shellname, sizeof(shellname)-1, "shells-%d", hsindex);
+ hp = hesiod_resolve(context, shellname, "shells");
+ if (hp == NULL) {
+ if (errno == ENOENT) {
+ if (hsindex == 0)
+ r = NS_NOTFOUND;
+ else
+ r = NS_SUCCESS;
+ }
+ break;
+ } else {
+ for (hpi = 0; hp[hpi]; hpi++)
+ sl_add(sl, hp[hpi]);
+ free(hp);
+ }
+ }
+ hesiod_end(context);
+ return (r);
+}
+#endif /* HESIOD */
+
+#ifdef YP
+static int _nis_initshells(void *, void *, va_list);
+
+/*ARGSUSED*/
+static int
+_nis_initshells(void *rv, void *cb_data, va_list ap)
+{
+ static char *ypdomain;
+ char *key, *data;
+ char *lastkey;
+ int keylen, datalen;
+ int r;
+
+ if (sl)
+ sl_free(sl, 1);
+ sl = sl_init();
+
+ if (ypdomain == NULL) {
+ switch (yp_get_default_domain(&ypdomain)) {
+ case 0:
+ break;
+ case YPERR_RESRC:
+ return NS_TRYAGAIN;
+ default:
+ return NS_UNAVAIL;
+ }
+ }
+
+ /*
+ * `key' and `data' point to strings dynamically allocated by
+ * the yp_... functions.
+ * `data' is directly put into the stringlist of shells.
+ */
+ key = data = NULL;
+ if (yp_first(ypdomain, "shells", &key, &keylen, &data, &datalen))
+ return NS_UNAVAIL;
+ do {
+ data[datalen] = '\0'; /* clear trailing \n */
+ sl_add(sl, data);
+
+ lastkey = key;
+ r = yp_next(ypdomain, "shells", lastkey, keylen,
+ &key, &keylen, &data, &datalen);
+ free(lastkey);
+ } while (r == 0);
+
+ if (r == YPERR_NOMORE) {
+ /*
+ * `data' and `key' ought to be NULL - do not try to free them.
+ */
+ return NS_SUCCESS;
+ }
+
+ return NS_UNAVAIL;
+}
+#endif /* YP */
+
+static const char *const *
+initshells(void)
+{
+ static const ns_dtab dtab[] = {
+ NS_FILES_CB(_local_initshells, NULL)
+ NS_DNS_CB(_dns_initshells, NULL)
+ NS_NIS_CB(_nis_initshells, NULL)
+ { 0 }
+ };
+ if (sl)
+ sl_free(sl, 1);
+ sl = sl_init();
+
+ if (_nsdispatch(NULL, dtab, NSDB_SHELLS, "initshells", __nsdefaultsrc)
+ != NS_SUCCESS) {
+ if (sl)
+ sl_free(sl, 1);
+ sl = sl_init();
+ /*
+ * Local shells should NOT be added here. They should be
+ * added in /etc/shells.
+ */
+ sl_add(sl, strdup(_PATH_BSHELL));
+ sl_add(sl, strdup(_PATH_CSHELL));
+ }
+ sl_add(sl, NULL);
+
+ return (const char *const *)(sl->sl_str);
+}
diff --git a/lib/libc/gen/getutxent.3 b/lib/libc/gen/getutxent.3
new file mode 100644
index 000000000000..85c37b16e0fc
--- /dev/null
+++ b/lib/libc/gen/getutxent.3
@@ -0,0 +1,478 @@
+.\" Copyright (c) 2010 Ed Schouten <ed@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd October 27, 2011
+.Dt GETUTXENT 3
+.Os
+.Sh NAME
+.Nm endutxent ,
+.Nm getutxent ,
+.Nm getutxid ,
+.Nm getutxline ,
+.Nm getutxuser ,
+.Nm pututxline ,
+.Nm setutxdb ,
+.Nm setutxent
+.Nd user accounting database functions
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In utmpx.h
+.Ft void
+.Fn endutxent "void"
+.Ft struct utmpx *
+.Fn getutxent "void"
+.Ft struct utmpx *
+.Fn getutxid "const struct utmpx *id"
+.Ft struct utmpx *
+.Fn getutxline "const struct utmpx *line"
+.Ft struct utmpx *
+.Fn getutxuser "const char *user"
+.Ft struct utmpx *
+.Fn pututxline "const struct utmpx *utmpx"
+.Ft int
+.Fn setutxdb "int type" "const char *file"
+.Ft void
+.Fn setutxent "void"
+.Sh DESCRIPTION
+These functions operate on the user accounting database which stores
+records of various system activities, such as user login and logouts,
+but also system startups and shutdowns and modifications to the system's
+clock.
+The system stores these records in three databases, each having a
+different purpose:
+.Bl -tag -width indent
+.It Pa /var/run/utx.active
+Log of currently active user login sessions.
+This file is similar to the traditional
+.Pa utmp
+file.
+This file only contains process related entries, such as user login and
+logout records.
+.It Pa /var/log/utx.lastlogin
+Log of last user login entries per user.
+This file is similar to the traditional
+.Pa lastlog
+file.
+This file only contains user login records for users who have at least
+logged in once.
+.It Pa /var/log/utx.log
+Log of all entries, sorted by date of addition.
+This file is similar to the traditional
+.Pa wtmp
+file.
+This file may contain any type of record described below.
+.El
+.Pp
+Each entry in these databases is defined by the structure
+.Vt utmpx
+found in the include file
+.In utmpx.h :
+.Bd -literal -offset indent
+struct utmpx {
+ short ut_type; /* Type of entry. */
+ struct timeval ut_tv; /* Time entry was made. */
+ char ut_id[]; /* Record identifier. */
+ pid_t ut_pid; /* Process ID. */
+ char ut_user[]; /* User login name. */
+ char ut_line[]; /* Device name. */
+ char ut_host[]; /* Remote hostname. */
+};
+.Ed
+.Pp
+The
+.Fa ut_type
+field indicates the type of the log entry, which can have one of the
+following values:
+.Bl -tag -width LOGIN_PROCESS
+.It Dv EMPTY
+No valid user accounting information.
+.It Dv BOOT_TIME
+Identifies time of system boot.
+.It Dv SHUTDOWN_TIME
+Identifies time of system shutdown.
+.It Dv OLD_TIME
+Identifies time when system clock changed.
+.It Dv NEW_TIME
+Identifies time after system clock changed.
+.It Dv USER_PROCESS
+Identifies a process.
+.It Dv INIT_PROCESS
+Identifies a process spawned by the init process.
+.It Dv LOGIN_PROCESS
+Identifies the session leader of a logged-in user.
+.It Dv DEAD_PROCESS
+Identifies a session leader who has exited.
+.El
+.Pp
+Entries of type
+.Dv INIT_PROCESS
+and
+.Dv LOGIN_PROCESS
+are not processed by this implementation.
+.Pp
+Other fields inside the structure are:
+.Bl -tag -width ut_user
+.It Fa ut_tv
+The time the event occurred.
+This field is used for all types of entries, except
+.Dv EMPTY .
+.It Fa ut_id
+An identifier that is used to refer to the entry.
+This identifier can be used to remove or replace a login entry by
+writing a new entry to the database containing the same value for
+.Fa ut_id .
+This field is only applicable to entries of type
+.Dv USER_PROCESS ,
+.Dv INIT_PROCESS ,
+.Dv LOGIN_PROCESS
+and
+.Dv DEAD_PROCESS .
+.It Fa ut_pid
+The process identifier of the session leader of the login session.
+This field is only applicable to entries of type
+.Dv USER_PROCESS ,
+.Dv INIT_PROCESS ,
+.Dv LOGIN_PROCESS
+and
+.Dv DEAD_PROCESS .
+.It Fa ut_user
+The user login name corresponding with the login session.
+This field is only applicable to entries of type
+.Dv USER_PROCESS
+and
+.Dv INIT_PROCESS .
+For
+.Dv INIT_PROCESS
+entries this entry typically contains the name of the login process.
+.It Fa ut_line
+The name of the TTY character device, without the leading
+.Pa /dev/
+prefix, corresponding with the device used to facilitate the user login
+session.
+If no TTY character device is used, this field is left blank.
+This field is only applicable to entries of type
+.Dv USER_PROCESS
+and
+.Dv LOGIN_PROCESS .
+.It Fa ut_host
+The network hostname of the remote system, connecting to perform a user
+login.
+If the user login session is not performed across a network, this field
+is left blank.
+This field is only applicable to entries of type
+.Dv USER_PROCESS .
+.El
+.Pp
+This implementation guarantees all inapplicable fields are discarded.
+The
+.Fa ut_user ,
+.Fa ut_line
+and
+.Fa ut_host
+fields of the structure returned by the library functions are also
+guaranteed to be null-terminated in this implementation.
+.Pp
+The
+.Fn getutxent
+function can be used to read the next entry from the user accounting
+database.
+.Pp
+The
+.Fn getutxid
+function searches for the next entry in the database of which the
+behaviour is based on the
+.Fa ut_type
+field of
+.Fa id .
+If
+.Fa ut_type
+has a value of
+.Dv BOOT_TIME ,
+.Dv SHUTDOWN_TIME ,
+.Dv OLD_TIME
+or
+.Dv NEW_TIME ,
+it will return the next entry whose
+.Fa ut_type
+has an equal value.
+If
+.Fa ut_type
+has a value of
+.Dv USER_PROCESS ,
+.Dv INIT_PROCESS ,
+.Dv LOGIN_PROCESS
+or
+.Dv DEAD_PROCESS ,
+it will return the next entry whose
+.Fa ut_type
+has one of the previously mentioned values and whose
+.Fa ut_id
+is equal.
+.Pp
+The
+.Fn getutxline
+function searches for the next entry in the database whose
+.Fa ut_type
+has a value of
+.Dv USER_PROCESS
+or
+.Dv LOGIN_PROCESS
+and whose
+.Fa ut_line
+is equal to the same field in
+.Fa line .
+.Pp
+The
+.Fn getutxuser
+function searches for the next entry in the database whose
+.Fa ut_type
+has a value of
+.Dv USER_PROCESS
+and whose
+.Fa ut_user
+is equal to
+.Fa user .
+.Pp
+The previously mentioned functions will automatically try to open the
+user accounting database if not already done so.
+The
+.Fn setutxdb
+and
+.Fn setutxent
+functions allow the database to be opened manually, causing the offset
+within the user accounting database to be rewound.
+The
+.Fn endutxent
+function closes the database.
+.Pp
+The
+.Fn setutxent
+database always opens the active sessions database.
+The
+.Fn setutxdb
+function opens the database identified by
+.Fa type ,
+whose value is either
+.Dv UTXDB_ACTIVE ,
+.Dv UTXDB_LASTLOGIN
+or
+.Dv UTXDB_LOG .
+It will open a custom file with filename
+.Fa file
+instead of the system-default if
+.Fa file
+is not null.
+Care must be taken that when using a custom filename,
+.Fa type
+still has to match with the actual format, since each database may use
+its own file format.
+.Pp
+The
+.Fn pututxline
+function writes record
+.Fa utmpx
+to the system-default user accounting databases.
+The value of
+.Fa ut_type
+determines which databases are modified.
+.Pp
+Entries of type
+.Dv SHUTDOWN_TIME ,
+.Dv OLD_TIME
+and
+.Dv NEW_TIME
+will only be written to
+.Pa /var/log/utx.log .
+.Pp
+Entries of type
+.Dv USER_PROCESS
+will also be written to
+.Pa /var/run/utx.active
+and
+.Pa /var/log/utx.lastlogin .
+.Pp
+Entries of type
+.Dv DEAD_PROCESS
+will only be written to
+.Pa /var/log/utx.log
+and
+.Pa /var/run/utx.active
+if a corresponding
+.Dv USER_PROCESS ,
+.Dv INIT_PROCESS
+or
+.Dv LOGIN_PROCESS
+entry whose
+.Fa ut_id
+is equal has been found in the latter.
+.Pp
+In addition, entries of type
+.Dv BOOT_TIME
+and
+.Dv SHUTDOWN_TIME
+will cause all existing entries in
+.Pa /var/run/utx.active
+to be discarded.
+.Pp
+All entries whose type has not been mentioned previously, are discarded
+by this implementation of
+.Fn pututxline .
+This implementation also ignores the value of
+.Fa ut_tv .
+.Sh RETURN VALUES
+The
+.Fn getutxent ,
+.Fn getutxid ,
+.Fn getutxline ,
+and
+.Fn getutxuser
+functions return a pointer to an
+.Vt utmpx
+structure that matches the mentioned constraints on success or
+.Dv NULL
+when reaching the end-of-file or when an error occurs.
+.Pp
+The
+.Fn pututxline
+function returns a pointer to an
+.Vt utmpx
+structure containing a copy of the structure written to disk upon
+success.
+It returns
+.Dv NULL
+when the provided
+.Vt utmpx
+is invalid, or
+.Fa ut_type
+has a value of
+.Dv DEAD_PROCESS
+and an entry with an identifier with a value equal to the field
+.Fa ut_id
+was not found; the global variable
+.Va errno
+is set to indicate the error.
+.Pp
+The
+.Fn setutxdb
+function returns 0 if the user accounting database was opened
+successfully.
+Otherwise, -1 is returned and the global variable
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+In addition to the error conditions described in
+.Xr open 2 ,
+.Xr fdopen 3 ,
+.Xr fopen 3 ,
+.Xr fseek 3 ,
+the
+.Fn pututxline
+function can generate the following errors:
+.Bl -tag -width Er
+.It Bq Er ESRCH
+The value of
+.Fa ut_type
+is DEAD_PROCESS, and the process entry could not be found.
+.It Bq Er EINVAL
+The value of
+.Fa ut_type
+is not supported by this implementation.
+.El
+In addition to the error conditions described in
+.Xr fopen 3 ,
+the
+.Fn setutxdb
+function can generate the following errors:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa type
+argument contains a value not supported by this implementation.
+.It Bq Er EFTYPE
+The file format is invalid.
+.El
+.Sh SEE ALSO
+.Xr last 1 ,
+.Xr write 1 ,
+.Xr getpid 2 ,
+.Xr gettimeofday 2 ,
+.Xr tty 4 ,
+.Xr ac 8 ,
+.Xr newsyslog 8 ,
+.Xr utx 8
+.Sh STANDARDS
+The
+.Fn endutxent ,
+.Fn getutxent ,
+.Fn getutxid ,
+.Fn getutxline
+and
+.Fn setutxent
+functions are expected to conform to
+.St -p1003.1-2008 .
+.Pp
+The
+.Fn pututxline
+function deviates from the standard by writing its records to multiple
+database files, depending on its
+.Fa ut_type .
+This prevents the need for special utility functions to update the other
+databases, such as the
+.Fn updlastlogx
+and
+.Fn updwtmpx
+functions which are available in other implementations.
+It also tries to replace
+.Dv DEAD_PROCESS
+entries in the active sessions database when storing
+.Dv USER_PROCESS
+entries and no entry with the same value for
+.Fa ut_id
+has been found.
+The standard always requires a new entry to be allocated, which could
+cause an unbounded growth of the database.
+.Pp
+The
+.Fn getutxuser
+and
+.Fn setutxdb
+functions,
+the
+.Fa ut_host
+field of the
+.Vt utmpx
+structure and
+.Dv SHUTDOWN_TIME
+are extensions.
+.Sh HISTORY
+These functions appeared in
+.Fx 9.0 .
+They replaced the
+.In utmp.h
+interface.
+.Sh AUTHORS
+.An \&Ed Schouten Aq Mt ed@FreeBSD.org
diff --git a/lib/libc/gen/getutxent.c b/lib/libc/gen/getutxent.c
new file mode 100644
index 000000000000..1679aa43d097
--- /dev/null
+++ b/lib/libc/gen/getutxent.c
@@ -0,0 +1,246 @@
+/*-
+ * Copyright (c) 2010 Ed Schouten <ed@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/endian.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <utmpx.h>
+#include "utxdb.h"
+#include "un-namespace.h"
+
+#ifdef __NO_TLS
+static FILE *uf = NULL;
+static int udb;
+#else
+static _Thread_local FILE *uf = NULL;
+static _Thread_local int udb;
+#endif
+
+int
+setutxdb(int db, const char *file)
+{
+ struct stat sb;
+
+ switch (db) {
+ case UTXDB_ACTIVE:
+ if (file == NULL)
+ file = _PATH_UTX_ACTIVE;
+ break;
+ case UTXDB_LASTLOGIN:
+ if (file == NULL)
+ file = _PATH_UTX_LASTLOGIN;
+ break;
+ case UTXDB_LOG:
+ if (file == NULL)
+ file = _PATH_UTX_LOG;
+ break;
+ default:
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (uf != NULL)
+ fclose(uf);
+ uf = fopen(file, "re");
+ if (uf == NULL)
+ return (-1);
+
+ if (db != UTXDB_LOG) {
+ /* Safety check: never use broken files. */
+ if (_fstat(fileno(uf), &sb) != -1 &&
+ sb.st_size % sizeof(struct futx) != 0) {
+ fclose(uf);
+ uf = NULL;
+ errno = EFTYPE;
+ return (-1);
+ }
+ /* Prevent reading of partial records. */
+ (void)setvbuf(uf, NULL, _IOFBF,
+ rounddown(BUFSIZ, sizeof(struct futx)));
+ }
+
+ udb = db;
+ return (0);
+}
+
+void
+setutxent(void)
+{
+
+ setutxdb(UTXDB_ACTIVE, NULL);
+}
+
+void
+endutxent(void)
+{
+
+ if (uf != NULL) {
+ fclose(uf);
+ uf = NULL;
+ }
+}
+
+static int
+getfutxent(struct futx *fu)
+{
+
+ if (uf == NULL)
+ setutxent();
+ if (uf == NULL)
+ return (-1);
+
+ if (udb == UTXDB_LOG) {
+ uint16_t len;
+
+retry:
+ if (fread(&len, sizeof(len), 1, uf) != 1)
+ return (-1);
+ len = be16toh(len);
+ if (len == 0) {
+ /*
+ * XXX: Though zero-size records are valid in theory,
+ * they can never occur in practice. Zero-size records
+ * indicate file corruption. Seek one byte forward, to
+ * see if we can find a record there.
+ */
+ ungetc('\0', uf);
+ goto retry;
+ }
+ if (len > sizeof *fu) {
+ /* Forward compatibility. */
+ if (fread(fu, sizeof(*fu), 1, uf) != 1)
+ return (-1);
+ fseek(uf, len - sizeof(*fu), SEEK_CUR);
+ } else {
+ /* Partial record. */
+ memset(fu, 0, sizeof(*fu));
+ if (fread(fu, len, 1, uf) != 1)
+ return (-1);
+ }
+ } else {
+ if (fread(fu, sizeof(*fu), 1, uf) != 1)
+ return (-1);
+ }
+ return (0);
+}
+
+struct utmpx *
+getutxent(void)
+{
+ struct futx fu;
+
+ if (getfutxent(&fu) != 0)
+ return (NULL);
+ return (futx_to_utx(&fu));
+}
+
+struct utmpx *
+getutxid(const struct utmpx *id)
+{
+ struct futx fu;
+
+ for (;;) {
+ if (getfutxent(&fu) != 0)
+ return (NULL);
+
+ switch (fu.fu_type) {
+ case USER_PROCESS:
+ case INIT_PROCESS:
+ case LOGIN_PROCESS:
+ case DEAD_PROCESS:
+ switch (id->ut_type) {
+ case USER_PROCESS:
+ case INIT_PROCESS:
+ case LOGIN_PROCESS:
+ case DEAD_PROCESS:
+ if (memcmp(fu.fu_id, id->ut_id,
+ MIN(sizeof(fu.fu_id), sizeof(id->ut_id))) ==
+ 0)
+ goto found;
+ }
+ break;
+ default:
+ if (fu.fu_type == id->ut_type)
+ goto found;
+ break;
+ }
+ }
+
+found:
+ return (futx_to_utx(&fu));
+}
+
+struct utmpx *
+getutxline(const struct utmpx *line)
+{
+ struct futx fu;
+
+ for (;;) {
+ if (getfutxent(&fu) != 0)
+ return (NULL);
+
+ switch (fu.fu_type) {
+ case USER_PROCESS:
+ case LOGIN_PROCESS:
+ if (strncmp(fu.fu_line, line->ut_line,
+ MIN(sizeof(fu.fu_line), sizeof(line->ut_line))) ==
+ 0)
+ goto found;
+ break;
+ }
+ }
+
+found:
+ return (futx_to_utx(&fu));
+}
+
+struct utmpx *
+getutxuser(const char *user)
+{
+ struct futx fu;
+
+ for (;;) {
+ if (getfutxent(&fu) != 0)
+ return (NULL);
+
+ switch (fu.fu_type) {
+ case USER_PROCESS:
+ if (strncmp(fu.fu_user, user, sizeof(fu.fu_user)) == 0)
+ goto found;
+ break;
+ }
+ }
+
+found:
+ return (futx_to_utx(&fu));
+}
diff --git a/lib/libc/gen/getvfsbyname.3 b/lib/libc/gen/getvfsbyname.3
new file mode 100644
index 000000000000..a0fc843a0123
--- /dev/null
+++ b/lib/libc/gen/getvfsbyname.3
@@ -0,0 +1,117 @@
+.\" Copyright (c) 1995
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)kvm_getvfsbyname.3 8.3 (Berkeley) 5/4/95
+.\" $FreeBSD$
+.\"
+.Dd August 30, 2016
+.Dt GETVFSBYNAME 3
+.Os
+.Sh NAME
+.Nm getvfsbyname
+.Nd get information about a file system
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/param.h
+.In sys/mount.h
+.Ft int
+.Fn getvfsbyname "const char *name" "struct xvfsconf *vfc"
+.Sh DESCRIPTION
+The
+.Fn getvfsbyname
+function provides access to information about a
+file system module that is configured in the kernel.
+If successful,
+the requested file system
+.Fa xvfsconf
+is returned in the location pointed to by
+.Fa vfc .
+The fields in a
+.Dq Li struct xvfsconf
+are defined as follows:
+.Pp
+.Bl -tag -compact -width vfc_refcount
+.It vfc_name
+the name of the file system
+.It vfc_typenum
+the file system type number assigned by the kernel
+.It vfc_refcount
+the number of active mount points using the file system
+.It vfc_flags
+flag bits, as described below
+.El
+.Pp
+The flags are defined as follows:
+.Pp
+.Bl -tag -width VFCF_DELEGADMIN -compact
+.It Dv VFCF_STATIC
+statically compiled into kernel
+.It Dv VFCF_NETWORK
+may get data over the network
+.It Dv VFCF_READONLY
+writes are not implemented
+.It Dv VFCF_SYNTHETIC
+data does not represent real files
+.It Dv VFCF_LOOPBACK
+aliases some other mounted FS
+.It Dv VFCF_UNICODE
+stores file names as Unicode
+.It Dv VFCF_JAIL
+can be mounted from within a jail if
+.Va security.jail.mount_allowed
+sysctl is set to
+.Dv 1
+.It Dv VFCF_DELEGADMIN
+supports delegated administration if
+.Va vfs.usermount
+sysctl is set to
+.Dv 1
+.El
+.Sh RETURN VALUES
+.Rv -std getvfsbyname
+.Sh ERRORS
+The following errors may be reported:
+.Bl -tag -width Er
+.It Bq Er ENOENT
+The
+.Fa name
+argument
+specifies a file system that is unknown or not configured in the kernel.
+.El
+.Sh SEE ALSO
+.Xr jail 2 ,
+.Xr mount 2 ,
+.Xr sysctl 3 ,
+.Xr jail 8 ,
+.Xr mount 8 ,
+.Xr sysctl 8
+.Sh HISTORY
+A variant of the
+.Fn getvfsbyname
+function first appeared in
+.Fx 2.0 .
diff --git a/lib/libc/gen/getvfsbyname.c b/lib/libc/gen/getvfsbyname.c
new file mode 100644
index 000000000000..c90c5eeb8474
--- /dev/null
+++ b/lib/libc/gen/getvfsbyname.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 1995
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)kvm_getvfsbyname.c 8.1 (Berkeley) 4/3/95";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/mount.h>
+#include <sys/sysctl.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * Given a filesystem name, determine if it is resident in the kernel,
+ * and if it is resident, return its xvfsconf structure.
+ */
+int
+getvfsbyname(const char *fsname, struct xvfsconf *vfcp)
+{
+ struct xvfsconf *xvfsp;
+ size_t buflen;
+ int cnt, i;
+
+ if (sysctlbyname("vfs.conflist", NULL, &buflen, NULL, 0) < 0)
+ return (-1);
+ xvfsp = malloc(buflen);
+ if (xvfsp == NULL)
+ return (-1);
+ if (sysctlbyname("vfs.conflist", xvfsp, &buflen, NULL, 0) < 0) {
+ free(xvfsp);
+ return (-1);
+ }
+ cnt = buflen / sizeof(struct xvfsconf);
+ for (i = 0; i < cnt; i++) {
+ if (strcmp(fsname, xvfsp[i].vfc_name) == 0) {
+ memcpy(vfcp, xvfsp + i, sizeof(struct xvfsconf));
+ free(xvfsp);
+ return (0);
+ }
+ }
+ free(xvfsp);
+ errno = ENOENT;
+ return (-1);
+}
diff --git a/lib/libc/gen/glob.3 b/lib/libc/gen/glob.3
new file mode 100644
index 000000000000..ef7059d7624f
--- /dev/null
+++ b/lib/libc/gen/glob.3
@@ -0,0 +1,457 @@
+.\" Copyright (c) 1989, 1991, 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Guido van Rossum.
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)glob.3 8.3 (Berkeley) 4/16/94
+.\" $FreeBSD$
+.\"
+.Dd December 20, 2011
+.Dt GLOB 3
+.Os
+.Sh NAME
+.Nm glob ,
+.Nm globfree
+.Nd generate pathnames matching a pattern
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In glob.h
+.Ft int
+.Fn glob "const char * restrict pattern" "int flags" "int (*errfunc)(const char *, int)" "glob_t * restrict pglob"
+.Ft void
+.Fn globfree "glob_t *pglob"
+.Sh DESCRIPTION
+The
+.Fn glob
+function
+is a pathname generator that implements the rules for file name pattern
+matching used by the shell.
+.Pp
+The include file
+.In glob.h
+defines the structure type
+.Fa glob_t ,
+which contains at least the following fields:
+.Bd -literal
+typedef struct {
+ size_t gl_pathc; /* count of total paths so far */
+ size_t gl_matchc; /* count of paths matching pattern */
+ size_t gl_offs; /* reserved at beginning of gl_pathv */
+ int gl_flags; /* returned flags */
+ char **gl_pathv; /* list of paths matching pattern */
+} glob_t;
+.Ed
+.Pp
+The argument
+.Fa pattern
+is a pointer to a pathname pattern to be expanded.
+The
+.Fn glob
+argument
+matches all accessible pathnames against the pattern and creates
+a list of the pathnames that match.
+In order to have access to a pathname,
+.Fn glob
+requires search permission on every component of a path except the last
+and read permission on each directory of any filename component of
+.Fa pattern
+that contains any of the special characters
+.Ql * ,
+.Ql ?\&
+or
+.Ql \&[ .
+.Pp
+The
+.Fn glob
+argument
+stores the number of matched pathnames into the
+.Fa gl_pathc
+field, and a pointer to a list of pointers to pathnames into the
+.Fa gl_pathv
+field.
+The first pointer after the last pathname is
+.Dv NULL .
+If the pattern does not match any pathnames, the returned number of
+matched paths is set to zero.
+.Pp
+It is the caller's responsibility to create the structure pointed to by
+.Fa pglob .
+The
+.Fn glob
+function allocates other space as needed, including the memory pointed
+to by
+.Fa gl_pathv .
+.Pp
+The argument
+.Fa flags
+is used to modify the behavior of
+.Fn glob .
+The value of
+.Fa flags
+is the bitwise inclusive
+.Tn OR
+of any of the following
+values defined in
+.In glob.h :
+.Bl -tag -width GLOB_ALTDIRFUNC
+.It Dv GLOB_APPEND
+Append pathnames generated to the ones from a previous call (or calls)
+to
+.Fn glob .
+The value of
+.Fa gl_pathc
+will be the total matches found by this call and the previous call(s).
+The pathnames are appended to, not merged with the pathnames returned by
+the previous call(s).
+Between calls, the caller must not change the setting of the
+.Dv GLOB_DOOFFS
+flag, nor change the value of
+.Fa gl_offs
+when
+.Dv GLOB_DOOFFS
+is set, nor (obviously) call
+.Fn globfree
+for
+.Fa pglob .
+.It Dv GLOB_DOOFFS
+Make use of the
+.Fa gl_offs
+field.
+If this flag is set,
+.Fa gl_offs
+is used to specify how many
+.Dv NULL
+pointers to prepend to the beginning
+of the
+.Fa gl_pathv
+field.
+In other words,
+.Fa gl_pathv
+will point to
+.Fa gl_offs
+.Dv NULL
+pointers,
+followed by
+.Fa gl_pathc
+pathname pointers, followed by a
+.Dv NULL
+pointer.
+.It Dv GLOB_ERR
+Causes
+.Fn glob
+to return when it encounters a directory that it cannot open or read.
+Ordinarily,
+.Fn glob
+continues to find matches.
+.It Dv GLOB_MARK
+Each pathname that is a directory that matches
+.Fa pattern
+has a slash
+appended.
+.It Dv GLOB_NOCHECK
+If
+.Fa pattern
+does not match any pathname, then
+.Fn glob
+returns a list
+consisting of only
+.Fa pattern ,
+with the number of total pathnames set to 1, and the number of matched
+pathnames set to 0.
+The effect of backslash escaping is present in the pattern returned.
+.It Dv GLOB_NOESCAPE
+By default, a backslash
+.Pq Ql \e
+character is used to escape the following character in the pattern,
+avoiding any special interpretation of the character.
+If
+.Dv GLOB_NOESCAPE
+is set, backslash escaping is disabled.
+.It Dv GLOB_NOSORT
+By default, the pathnames are sorted in ascending
+collation
+order;
+this flag prevents that sorting (speeding up
+.Fn glob ) .
+.El
+.Pp
+The following values may also be included in
+.Fa flags ,
+however, they are non-standard extensions to
+.St -p1003.2 .
+.Bl -tag -width GLOB_ALTDIRFUNC
+.It Dv GLOB_ALTDIRFUNC
+The following additional fields in the pglob structure have been
+initialized with alternate functions for glob to use to open, read,
+and close directories and to get stat information on names found
+in those directories.
+.Bd -literal
+void *(*gl_opendir)(const char * name);
+struct dirent *(*gl_readdir)(void *);
+void (*gl_closedir)(void *);
+int (*gl_lstat)(const char *name, struct stat *st);
+int (*gl_stat)(const char *name, struct stat *st);
+.Ed
+.Pp
+This extension is provided to allow programs such as
+.Xr restore 8
+to provide globbing from directories stored on tape.
+.It Dv GLOB_BRACE
+Pre-process the pattern string to expand
+.Ql {pat,pat,...}
+strings like
+.Xr csh 1 .
+The pattern
+.Ql {}
+is left unexpanded for historical reasons (and
+.Xr csh 1
+does the same thing to
+ease typing
+of
+.Xr find 1
+patterns).
+.It Dv GLOB_MAGCHAR
+Set by the
+.Fn glob
+function if the pattern included globbing characters.
+See the description of the usage of the
+.Fa gl_matchc
+structure member for more details.
+.It Dv GLOB_NOMAGIC
+Is the same as
+.Dv GLOB_NOCHECK
+but it only appends the
+.Fa pattern
+if it does not contain any of the special characters ``*'', ``?'' or ``[''.
+.Dv GLOB_NOMAGIC
+is provided to simplify implementing the historic
+.Xr csh 1
+globbing behavior and should probably not be used anywhere else.
+.It Dv GLOB_TILDE
+Expand patterns that start with
+.Ql ~
+to user name home directories.
+.It Dv GLOB_LIMIT
+Limit the total number of returned pathnames to the value provided in
+.Fa gl_matchc
+(default
+.Dv ARG_MAX ) .
+This option should be set for programs
+that can be coerced into a denial of service attack
+via patterns that expand to a very large number of matches,
+such as a long string of
+.Ql */../*/.. .
+.El
+.Pp
+If, during the search, a directory is encountered that cannot be opened
+or read and
+.Fa errfunc
+is
+.Pf non- Dv NULL ,
+.Fn glob
+calls
+.Fa \*(lp*errfunc\*(rp Ns ( Fa path , errno ) ,
+however, the
+.Dv GLOB_ERR
+flag will cause an immediate
+return when this happens.
+.Pp
+If
+.Fa errfunc
+returns non-zero,
+.Fn glob
+stops the scan and returns
+.Dv GLOB_ABORTED
+after setting
+.Fa gl_pathc
+and
+.Fa gl_pathv
+to reflect any paths already matched.
+This also happens if an error is encountered and
+.Dv GLOB_ERR
+is set in
+.Fa flags ,
+regardless of the return value of
+.Fa errfunc ,
+if called.
+If
+.Dv GLOB_ERR
+is not set and either
+.Fa errfunc
+is
+.Dv NULL
+or
+.Fa errfunc
+returns zero, the error is ignored.
+.Pp
+The
+.Fn globfree
+function frees any space associated with
+.Fa pglob
+from a previous call(s) to
+.Fn glob .
+.Sh RETURN VALUES
+On successful completion,
+.Fn glob
+returns zero.
+In addition the fields of
+.Fa pglob
+contain the values described below:
+.Bl -tag -width GLOB_NOCHECK
+.It Fa gl_pathc
+contains the total number of matched pathnames so far.
+This includes other matches from previous invocations of
+.Fn glob
+if
+.Dv GLOB_APPEND
+was specified.
+.It Fa gl_matchc
+contains the number of matched pathnames in the current invocation of
+.Fn glob .
+.It Fa gl_flags
+contains a copy of the
+.Fa flags
+argument with the bit
+.Dv GLOB_MAGCHAR
+set if
+.Fa pattern
+contained any of the special characters ``*'', ``?'' or ``['', cleared
+if not.
+.It Fa gl_pathv
+contains a pointer to a
+.Dv NULL Ns -terminated
+list of matched pathnames.
+However, if
+.Fa gl_pathc
+is zero, the contents of
+.Fa gl_pathv
+are undefined.
+.El
+.Pp
+If
+.Fn glob
+terminates due to an error, it sets errno and returns one of the
+following non-zero constants, which are defined in the include
+file
+.In glob.h :
+.Bl -tag -width GLOB_NOCHECK
+.It Dv GLOB_NOSPACE
+An attempt to allocate memory failed, or if
+.Fa errno
+was E2BIG,
+.Dv GLOB_LIMIT
+was specified in the flags and
+.Fa pglob\->gl_matchc
+or more patterns were matched.
+.It Dv GLOB_ABORTED
+The scan was stopped because an error was encountered and either
+.Dv GLOB_ERR
+was set or
+.Fa \*(lp*errfunc\*(rp\*(lp\*(rp
+returned non-zero.
+.It Dv GLOB_NOMATCH
+The pattern did not match a pathname and
+.Dv GLOB_NOCHECK
+was not set.
+.El
+.Pp
+The arguments
+.Fa pglob\->gl_pathc
+and
+.Fa pglob\->gl_pathv
+are still set as specified above.
+.Sh EXAMPLES
+A rough equivalent of
+.Ql "ls -l *.c *.h"
+can be obtained with the
+following code:
+.Bd -literal -offset indent
+glob_t g;
+
+g.gl_offs = 2;
+glob("*.c", GLOB_DOOFFS, NULL, &g);
+glob("*.h", GLOB_DOOFFS | GLOB_APPEND, NULL, &g);
+g.gl_pathv[0] = "ls";
+g.gl_pathv[1] = "-l";
+execvp("ls", g.gl_pathv);
+.Ed
+.Sh SEE ALSO
+.Xr sh 1 ,
+.Xr fnmatch 3 ,
+.Xr regex 3
+.Sh STANDARDS
+The current implementation of the
+.Fn glob
+function
+.Em does not
+conform to
+.St -p1003.2 .
+Collating symbol expressions, equivalence class expressions and
+character class expressions are not supported.
+.Pp
+The flags
+.Dv GLOB_ALTDIRFUNC ,
+.Dv GLOB_BRACE ,
+.Dv GLOB_LIMIT ,
+.Dv GLOB_MAGCHAR ,
+.Dv GLOB_NOMAGIC ,
+and
+.Dv GLOB_TILDE ,
+and the fields
+.Fa gl_matchc
+and
+.Fa gl_flags
+are extensions to the
+.Tn POSIX
+standard and
+should not be used by applications striving for strict
+conformance.
+.Sh HISTORY
+The
+.Fn glob
+and
+.Fn globfree
+functions first appeared in
+.Bx 4.4 .
+.Sh BUGS
+Patterns longer than
+.Dv MAXPATHLEN
+may cause unchecked errors.
+.Pp
+The
+.Fn glob
+argument
+may fail and set errno for any of the errors specified for the
+library routines
+.Xr stat 2 ,
+.Xr closedir 3 ,
+.Xr opendir 3 ,
+.Xr readdir 3 ,
+.Xr malloc 3 ,
+and
+.Xr free 3 .
diff --git a/lib/libc/gen/glob.c b/lib/libc/gen/glob.c
new file mode 100644
index 000000000000..5df0b745b182
--- /dev/null
+++ b/lib/libc/gen/glob.c
@@ -0,0 +1,1105 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Guido van Rossum.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)glob.c 8.3 (Berkeley) 10/13/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * glob(3) -- a superset of the one defined in POSIX 1003.2.
+ *
+ * The [!...] convention to negate a range is supported (SysV, Posix, ksh).
+ *
+ * Optional extra services, controlled by flags not defined by POSIX:
+ *
+ * GLOB_QUOTE:
+ * Escaping convention: \ inhibits any special meaning the following
+ * character might have (except \ at end of string is retained).
+ * GLOB_MAGCHAR:
+ * Set in gl_flags if pattern contained a globbing character.
+ * GLOB_NOMAGIC:
+ * Same as GLOB_NOCHECK, but it will only append pattern if it did
+ * not contain any magic characters. [Used in csh style globbing]
+ * GLOB_ALTDIRFUNC:
+ * Use alternately specified directory access functions.
+ * GLOB_TILDE:
+ * expand ~user/foo to the /home/dir/of/user/foo
+ * GLOB_BRACE:
+ * expand {1,2}{a,b} to 1a 1b 2a 2b
+ * gl_matchc:
+ * Number of matches in the current invocation of glob.
+ */
+
+/*
+ * Some notes on multibyte character support:
+ * 1. Patterns with illegal byte sequences match nothing - even if
+ * GLOB_NOCHECK is specified.
+ * 2. Illegal byte sequences in filenames are handled by treating them as
+ * single-byte characters with a values of such bytes of the sequence
+ * cast to wchar_t.
+ * 3. State-dependent encodings are not currently supported.
+ */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <glob.h>
+#include <limits.h>
+#include <pwd.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <wchar.h>
+
+#include "collate.h"
+
+/*
+ * glob(3) expansion limits. Stop the expansion if any of these limits
+ * is reached. This caps the runtime in the face of DoS attacks. See
+ * also CVE-2010-2632
+ */
+#define GLOB_LIMIT_BRACE 128 /* number of brace calls */
+#define GLOB_LIMIT_PATH 65536 /* number of path elements */
+#define GLOB_LIMIT_READDIR 16384 /* number of readdirs */
+#define GLOB_LIMIT_STAT 1024 /* number of stat system calls */
+#define GLOB_LIMIT_STRING ARG_MAX /* maximum total size for paths */
+
+struct glob_limit {
+ size_t l_brace_cnt;
+ size_t l_path_lim;
+ size_t l_readdir_cnt;
+ size_t l_stat_cnt;
+ size_t l_string_cnt;
+};
+
+#define DOT L'.'
+#define EOS L'\0'
+#define LBRACKET L'['
+#define NOT L'!'
+#define QUESTION L'?'
+#define QUOTE L'\\'
+#define RANGE L'-'
+#define RBRACKET L']'
+#define SEP L'/'
+#define STAR L'*'
+#define TILDE L'~'
+#define LBRACE L'{'
+#define RBRACE L'}'
+#define COMMA L','
+
+#define M_QUOTE 0x8000000000ULL
+#define M_PROTECT 0x4000000000ULL
+#define M_MASK 0xffffffffffULL
+#define M_CHAR 0x00ffffffffULL
+
+typedef uint_fast64_t Char;
+
+#define CHAR(c) ((Char)((c)&M_CHAR))
+#define META(c) ((Char)((c)|M_QUOTE))
+#define UNPROT(c) ((c) & ~M_PROTECT)
+#define M_ALL META(L'*')
+#define M_END META(L']')
+#define M_NOT META(L'!')
+#define M_ONE META(L'?')
+#define M_RNG META(L'-')
+#define M_SET META(L'[')
+#define ismeta(c) (((c)&M_QUOTE) != 0)
+#ifdef DEBUG
+#define isprot(c) (((c)&M_PROTECT) != 0)
+#endif
+
+static int compare(const void *, const void *);
+static int g_Ctoc(const Char *, char *, size_t);
+static int g_lstat(Char *, struct stat *, glob_t *);
+static DIR *g_opendir(Char *, glob_t *);
+static const Char *g_strchr(const Char *, wchar_t);
+#ifdef notdef
+static Char *g_strcat(Char *, const Char *);
+#endif
+static int g_stat(Char *, struct stat *, glob_t *);
+static int glob0(const Char *, glob_t *, struct glob_limit *,
+ const char *);
+static int glob1(Char *, glob_t *, struct glob_limit *);
+static int glob2(Char *, Char *, Char *, Char *, glob_t *,
+ struct glob_limit *);
+static int glob3(Char *, Char *, Char *, Char *, Char *, glob_t *,
+ struct glob_limit *);
+static int globextend(const Char *, glob_t *, struct glob_limit *,
+ const char *);
+static const Char *
+ globtilde(const Char *, Char *, size_t, glob_t *);
+static int globexp0(const Char *, glob_t *, struct glob_limit *,
+ const char *);
+static int globexp1(const Char *, glob_t *, struct glob_limit *);
+static int globexp2(const Char *, const Char *, glob_t *,
+ struct glob_limit *);
+static int globfinal(glob_t *, struct glob_limit *, size_t,
+ const char *);
+static int match(Char *, Char *, Char *);
+static int err_nomatch(glob_t *, struct glob_limit *, const char *);
+static int err_aborted(glob_t *, int, char *);
+#ifdef DEBUG
+static void qprintf(const char *, Char *);
+#endif
+
+int
+glob(const char * __restrict pattern, int flags,
+ int (*errfunc)(const char *, int), glob_t * __restrict pglob)
+{
+ struct glob_limit limit = { 0, 0, 0, 0, 0 };
+ const char *patnext;
+ Char *bufnext, *bufend, patbuf[MAXPATHLEN], prot;
+ mbstate_t mbs;
+ wchar_t wc;
+ size_t clen;
+ int too_long;
+
+ patnext = pattern;
+ if (!(flags & GLOB_APPEND)) {
+ pglob->gl_pathc = 0;
+ pglob->gl_pathv = NULL;
+ if (!(flags & GLOB_DOOFFS))
+ pglob->gl_offs = 0;
+ }
+ if (flags & GLOB_LIMIT) {
+ limit.l_path_lim = pglob->gl_matchc;
+ if (limit.l_path_lim == 0)
+ limit.l_path_lim = GLOB_LIMIT_PATH;
+ }
+ pglob->gl_flags = flags & ~GLOB_MAGCHAR;
+ pglob->gl_errfunc = errfunc;
+ pglob->gl_matchc = 0;
+
+ bufnext = patbuf;
+ bufend = bufnext + MAXPATHLEN - 1;
+ too_long = 1;
+ if (flags & GLOB_NOESCAPE) {
+ memset(&mbs, 0, sizeof(mbs));
+ while (bufnext <= bufend) {
+ clen = mbrtowc(&wc, patnext, MB_LEN_MAX, &mbs);
+ if (clen == (size_t)-1 || clen == (size_t)-2)
+ return (err_nomatch(pglob, &limit, pattern));
+ else if (clen == 0) {
+ too_long = 0;
+ break;
+ }
+ *bufnext++ = wc;
+ patnext += clen;
+ }
+ } else {
+ /* Protect the quoted characters. */
+ memset(&mbs, 0, sizeof(mbs));
+ while (bufnext <= bufend) {
+ if (*patnext == '\\') {
+ if (*++patnext == '\0') {
+ *bufnext++ = QUOTE;
+ continue;
+ }
+ prot = M_PROTECT;
+ } else
+ prot = 0;
+ clen = mbrtowc(&wc, patnext, MB_LEN_MAX, &mbs);
+ if (clen == (size_t)-1 || clen == (size_t)-2)
+ return (err_nomatch(pglob, &limit, pattern));
+ else if (clen == 0) {
+ too_long = 0;
+ break;
+ }
+ *bufnext++ = wc | prot;
+ patnext += clen;
+ }
+ }
+ if (too_long)
+ return (err_nomatch(pglob, &limit, pattern));
+ *bufnext = EOS;
+
+ if (flags & GLOB_BRACE)
+ return (globexp0(patbuf, pglob, &limit, pattern));
+ else
+ return (glob0(patbuf, pglob, &limit, pattern));
+}
+
+static int
+globexp0(const Char *pattern, glob_t *pglob, struct glob_limit *limit,
+ const char *origpat) {
+ int rv;
+ size_t oldpathc;
+
+ /* Protect a single {}, for find(1), like csh */
+ if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS) {
+ if ((pglob->gl_flags & GLOB_LIMIT) &&
+ limit->l_brace_cnt++ >= GLOB_LIMIT_BRACE) {
+ errno = E2BIG;
+ return (GLOB_NOSPACE);
+ }
+ return (glob0(pattern, pglob, limit, origpat));
+ }
+
+ oldpathc = pglob->gl_pathc;
+
+ if ((rv = globexp1(pattern, pglob, limit)) != 0)
+ return rv;
+
+ return (globfinal(pglob, limit, oldpathc, origpat));
+}
+
+/*
+ * Expand recursively a glob {} pattern. When there is no more expansion
+ * invoke the standard globbing routine to glob the rest of the magic
+ * characters
+ */
+static int
+globexp1(const Char *pattern, glob_t *pglob, struct glob_limit *limit)
+{
+ const Char* ptr;
+
+ if ((ptr = g_strchr(pattern, LBRACE)) != NULL) {
+ if ((pglob->gl_flags & GLOB_LIMIT) &&
+ limit->l_brace_cnt++ >= GLOB_LIMIT_BRACE) {
+ errno = E2BIG;
+ return (GLOB_NOSPACE);
+ }
+ return (globexp2(ptr, pattern, pglob, limit));
+ }
+
+ return (glob0(pattern, pglob, limit, NULL));
+}
+
+
+/*
+ * Recursive brace globbing helper. Tries to expand a single brace.
+ * If it succeeds then it invokes globexp1 with the new pattern.
+ * If it fails then it tries to glob the rest of the pattern and returns.
+ */
+static int
+globexp2(const Char *ptr, const Char *pattern, glob_t *pglob,
+ struct glob_limit *limit)
+{
+ int i, rv;
+ Char *lm, *ls;
+ const Char *pe, *pm, *pm1, *pl;
+ Char patbuf[MAXPATHLEN];
+
+ /* copy part up to the brace */
+ for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++)
+ continue;
+ *lm = EOS;
+ ls = lm;
+
+ /* Find the balanced brace */
+ for (i = 0, pe = ++ptr; *pe != EOS; pe++)
+ if (*pe == LBRACKET) {
+ /* Ignore everything between [] */
+ for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++)
+ continue;
+ if (*pe == EOS) {
+ /*
+ * We could not find a matching RBRACKET.
+ * Ignore and just look for RBRACE
+ */
+ pe = pm;
+ }
+ }
+ else if (*pe == LBRACE)
+ i++;
+ else if (*pe == RBRACE) {
+ if (i == 0)
+ break;
+ i--;
+ }
+
+ /* Non matching braces; just glob the pattern */
+ if (i != 0 || *pe == EOS)
+ return (glob0(pattern, pglob, limit, NULL));
+
+ for (i = 0, pl = pm = ptr; pm <= pe; pm++)
+ switch (*pm) {
+ case LBRACKET:
+ /* Ignore everything between [] */
+ for (pm1 = pm++; *pm != RBRACKET && *pm != EOS; pm++)
+ continue;
+ if (*pm == EOS) {
+ /*
+ * We could not find a matching RBRACKET.
+ * Ignore and just look for RBRACE
+ */
+ pm = pm1;
+ }
+ break;
+
+ case LBRACE:
+ i++;
+ break;
+
+ case RBRACE:
+ if (i) {
+ i--;
+ break;
+ }
+ /* FALLTHROUGH */
+ case COMMA:
+ if (i && *pm == COMMA)
+ break;
+ else {
+ /* Append the current string */
+ for (lm = ls; (pl < pm); *lm++ = *pl++)
+ continue;
+ /*
+ * Append the rest of the pattern after the
+ * closing brace
+ */
+ for (pl = pe + 1; (*lm++ = *pl++) != EOS;)
+ continue;
+
+ /* Expand the current pattern */
+#ifdef DEBUG
+ qprintf("globexp2:", patbuf);
+#endif
+ rv = globexp1(patbuf, pglob, limit);
+ if (rv)
+ return (rv);
+
+ /* move after the comma, to the next string */
+ pl = pm + 1;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return (0);
+}
+
+
+
+/*
+ * expand tilde from the passwd file.
+ */
+static const Char *
+globtilde(const Char *pattern, Char *patbuf, size_t patbuf_len, glob_t *pglob)
+{
+ struct passwd *pwd;
+ char *h, *sc;
+ const Char *p;
+ Char *b, *eb;
+ wchar_t wc;
+ wchar_t wbuf[MAXPATHLEN];
+ wchar_t *wbufend, *dc;
+ size_t clen;
+ mbstate_t mbs;
+ int too_long;
+
+ if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE))
+ return (pattern);
+
+ /*
+ * Copy up to the end of the string or /
+ */
+ eb = &patbuf[patbuf_len - 1];
+ for (p = pattern + 1, b = patbuf;
+ b < eb && *p != EOS && UNPROT(*p) != SEP; *b++ = *p++)
+ continue;
+
+ if (*p != EOS && UNPROT(*p) != SEP)
+ return (NULL);
+
+ *b = EOS;
+ h = NULL;
+
+ if (patbuf[0] == EOS) {
+ /*
+ * handle a plain ~ or ~/ by expanding $HOME first (iff
+ * we're not running setuid or setgid) and then trying
+ * the password file
+ */
+ if (issetugid() != 0 ||
+ (h = getenv("HOME")) == NULL) {
+ if (((h = getlogin()) != NULL &&
+ (pwd = getpwnam(h)) != NULL) ||
+ (pwd = getpwuid(getuid())) != NULL)
+ h = pwd->pw_dir;
+ else
+ return (pattern);
+ }
+ }
+ else {
+ /*
+ * Expand a ~user
+ */
+ if (g_Ctoc(patbuf, (char *)wbuf, sizeof(wbuf)))
+ return (NULL);
+ if ((pwd = getpwnam((char *)wbuf)) == NULL)
+ return (pattern);
+ else
+ h = pwd->pw_dir;
+ }
+
+ /* Copy the home directory */
+ dc = wbuf;
+ sc = h;
+ wbufend = wbuf + MAXPATHLEN - 1;
+ too_long = 1;
+ memset(&mbs, 0, sizeof(mbs));
+ while (dc <= wbufend) {
+ clen = mbrtowc(&wc, sc, MB_LEN_MAX, &mbs);
+ if (clen == (size_t)-1 || clen == (size_t)-2) {
+ /* XXX See initial comment #2. */
+ wc = (unsigned char)*sc;
+ clen = 1;
+ memset(&mbs, 0, sizeof(mbs));
+ }
+ if ((*dc++ = wc) == EOS) {
+ too_long = 0;
+ break;
+ }
+ sc += clen;
+ }
+ if (too_long)
+ return (NULL);
+
+ dc = wbuf;
+ for (b = patbuf; b < eb && *dc != EOS; *b++ = *dc++ | M_PROTECT)
+ continue;
+ if (*dc != EOS)
+ return (NULL);
+
+ /* Append the rest of the pattern */
+ if (*p != EOS) {
+ too_long = 1;
+ while (b <= eb) {
+ if ((*b++ = *p++) == EOS) {
+ too_long = 0;
+ break;
+ }
+ }
+ if (too_long)
+ return (NULL);
+ } else
+ *b = EOS;
+
+ return (patbuf);
+}
+
+
+/*
+ * The main glob() routine: compiles the pattern (optionally processing
+ * quotes), calls glob1() to do the real pattern matching, and finally
+ * sorts the list (unless unsorted operation is requested). Returns 0
+ * if things went well, nonzero if errors occurred.
+ */
+static int
+glob0(const Char *pattern, glob_t *pglob, struct glob_limit *limit,
+ const char *origpat) {
+ const Char *qpatnext;
+ int err;
+ size_t oldpathc;
+ Char *bufnext, c, patbuf[MAXPATHLEN];
+
+ qpatnext = globtilde(pattern, patbuf, MAXPATHLEN, pglob);
+ if (qpatnext == NULL) {
+ errno = E2BIG;
+ return (GLOB_NOSPACE);
+ }
+ oldpathc = pglob->gl_pathc;
+ bufnext = patbuf;
+
+ /* We don't need to check for buffer overflow any more. */
+ while ((c = *qpatnext++) != EOS) {
+ switch (c) {
+ case LBRACKET:
+ c = *qpatnext;
+ if (c == NOT)
+ ++qpatnext;
+ if (*qpatnext == EOS ||
+ g_strchr(qpatnext+1, RBRACKET) == NULL) {
+ *bufnext++ = LBRACKET;
+ if (c == NOT)
+ --qpatnext;
+ break;
+ }
+ *bufnext++ = M_SET;
+ if (c == NOT)
+ *bufnext++ = M_NOT;
+ c = *qpatnext++;
+ do {
+ *bufnext++ = CHAR(c);
+ if (*qpatnext == RANGE &&
+ (c = qpatnext[1]) != RBRACKET) {
+ *bufnext++ = M_RNG;
+ *bufnext++ = CHAR(c);
+ qpatnext += 2;
+ }
+ } while ((c = *qpatnext++) != RBRACKET);
+ pglob->gl_flags |= GLOB_MAGCHAR;
+ *bufnext++ = M_END;
+ break;
+ case QUESTION:
+ pglob->gl_flags |= GLOB_MAGCHAR;
+ *bufnext++ = M_ONE;
+ break;
+ case STAR:
+ pglob->gl_flags |= GLOB_MAGCHAR;
+ /* collapse adjacent stars to one,
+ * to avoid exponential behavior
+ */
+ if (bufnext == patbuf || bufnext[-1] != M_ALL)
+ *bufnext++ = M_ALL;
+ break;
+ default:
+ *bufnext++ = CHAR(c);
+ break;
+ }
+ }
+ *bufnext = EOS;
+#ifdef DEBUG
+ qprintf("glob0:", patbuf);
+#endif
+
+ if ((err = glob1(patbuf, pglob, limit)) != 0)
+ return(err);
+
+ if (origpat != NULL)
+ return (globfinal(pglob, limit, oldpathc, origpat));
+
+ return (0);
+}
+
+static int
+globfinal(glob_t *pglob, struct glob_limit *limit, size_t oldpathc,
+ const char *origpat) {
+ if (pglob->gl_pathc == oldpathc)
+ return (err_nomatch(pglob, limit, origpat));
+
+ if (!(pglob->gl_flags & GLOB_NOSORT))
+ qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
+ pglob->gl_pathc - oldpathc, sizeof(char *), compare);
+
+ return (0);
+}
+
+static int
+compare(const void *p, const void *q)
+{
+ return (strcoll(*(char **)p, *(char **)q));
+}
+
+static int
+glob1(Char *pattern, glob_t *pglob, struct glob_limit *limit)
+{
+ Char pathbuf[MAXPATHLEN];
+
+ /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
+ if (*pattern == EOS)
+ return (0);
+ return (glob2(pathbuf, pathbuf, pathbuf + MAXPATHLEN - 1,
+ pattern, pglob, limit));
+}
+
+/*
+ * The functions glob2 and glob3 are mutually recursive; there is one level
+ * of recursion for each segment in the pattern that contains one or more
+ * meta characters.
+ */
+static int
+glob2(Char *pathbuf, Char *pathend, Char *pathend_last, Char *pattern,
+ glob_t *pglob, struct glob_limit *limit)
+{
+ struct stat sb;
+ Char *p, *q;
+ int anymeta;
+
+ /*
+ * Loop over pattern segments until end of pattern or until
+ * segment with meta character found.
+ */
+ for (anymeta = 0;;) {
+ if (*pattern == EOS) { /* End of pattern? */
+ *pathend = EOS;
+ if (g_lstat(pathbuf, &sb, pglob))
+ return (0);
+
+ if ((pglob->gl_flags & GLOB_LIMIT) &&
+ limit->l_stat_cnt++ >= GLOB_LIMIT_STAT) {
+ errno = E2BIG;
+ return (GLOB_NOSPACE);
+ }
+ if ((pglob->gl_flags & GLOB_MARK) &&
+ UNPROT(pathend[-1]) != SEP &&
+ (S_ISDIR(sb.st_mode) ||
+ (S_ISLNK(sb.st_mode) &&
+ g_stat(pathbuf, &sb, pglob) == 0 &&
+ S_ISDIR(sb.st_mode)))) {
+ if (pathend + 1 > pathend_last) {
+ errno = E2BIG;
+ return (GLOB_NOSPACE);
+ }
+ *pathend++ = SEP;
+ *pathend = EOS;
+ }
+ ++pglob->gl_matchc;
+ return (globextend(pathbuf, pglob, limit, NULL));
+ }
+
+ /* Find end of next segment, copy tentatively to pathend. */
+ q = pathend;
+ p = pattern;
+ while (*p != EOS && UNPROT(*p) != SEP) {
+ if (ismeta(*p))
+ anymeta = 1;
+ if (q + 1 > pathend_last) {
+ errno = E2BIG;
+ return (GLOB_NOSPACE);
+ }
+ *q++ = *p++;
+ }
+
+ if (!anymeta) { /* No expansion, do next segment. */
+ pathend = q;
+ pattern = p;
+ while (UNPROT(*pattern) == SEP) {
+ if (pathend + 1 > pathend_last) {
+ errno = E2BIG;
+ return (GLOB_NOSPACE);
+ }
+ *pathend++ = *pattern++;
+ }
+ } else /* Need expansion, recurse. */
+ return (glob3(pathbuf, pathend, pathend_last, pattern,
+ p, pglob, limit));
+ }
+ /* NOTREACHED */
+}
+
+static int
+glob3(Char *pathbuf, Char *pathend, Char *pathend_last,
+ Char *pattern, Char *restpattern,
+ glob_t *pglob, struct glob_limit *limit)
+{
+ struct dirent *dp;
+ DIR *dirp;
+ int err, too_long, saverrno, saverrno2;
+ char buf[MAXPATHLEN + MB_LEN_MAX - 1];
+
+ struct dirent *(*readdirfunc)(DIR *);
+
+ if (pathend > pathend_last) {
+ errno = E2BIG;
+ return (GLOB_NOSPACE);
+ }
+ *pathend = EOS;
+ if (pglob->gl_errfunc != NULL &&
+ g_Ctoc(pathbuf, buf, sizeof(buf))) {
+ errno = E2BIG;
+ return (GLOB_NOSPACE);
+ }
+
+ saverrno = errno;
+ errno = 0;
+ if ((dirp = g_opendir(pathbuf, pglob)) == NULL) {
+ if (errno == ENOENT || errno == ENOTDIR)
+ return (0);
+ err = err_aborted(pglob, errno, buf);
+ if (errno == 0)
+ errno = saverrno;
+ return (err);
+ }
+
+ err = 0;
+
+ /* pglob->gl_readdir takes a void *, fix this manually */
+ if (pglob->gl_flags & GLOB_ALTDIRFUNC)
+ readdirfunc = (struct dirent *(*)(DIR *))pglob->gl_readdir;
+ else
+ readdirfunc = readdir;
+
+ errno = 0;
+ /* Search directory for matching names. */
+ while ((dp = (*readdirfunc)(dirp)) != NULL) {
+ char *sc;
+ Char *dc;
+ wchar_t wc;
+ size_t clen;
+ mbstate_t mbs;
+
+ if ((pglob->gl_flags & GLOB_LIMIT) &&
+ limit->l_readdir_cnt++ >= GLOB_LIMIT_READDIR) {
+ errno = E2BIG;
+ err = GLOB_NOSPACE;
+ break;
+ }
+
+ /* Initial DOT must be matched literally. */
+ if (dp->d_name[0] == '.' && UNPROT(*pattern) != DOT) {
+ errno = 0;
+ continue;
+ }
+ memset(&mbs, 0, sizeof(mbs));
+ dc = pathend;
+ sc = dp->d_name;
+ too_long = 1;
+ while (dc <= pathend_last) {
+ clen = mbrtowc(&wc, sc, MB_LEN_MAX, &mbs);
+ if (clen == (size_t)-1 || clen == (size_t)-2) {
+ /* XXX See initial comment #2. */
+ wc = (unsigned char)*sc;
+ clen = 1;
+ memset(&mbs, 0, sizeof(mbs));
+ }
+ if ((*dc++ = wc) == EOS) {
+ too_long = 0;
+ break;
+ }
+ sc += clen;
+ }
+ if (too_long && (err = err_aborted(pglob, ENAMETOOLONG,
+ buf))) {
+ errno = ENAMETOOLONG;
+ break;
+ }
+ if (too_long || !match(pathend, pattern, restpattern)) {
+ *pathend = EOS;
+ errno = 0;
+ continue;
+ }
+ if (errno == 0)
+ errno = saverrno;
+ err = glob2(pathbuf, --dc, pathend_last, restpattern,
+ pglob, limit);
+ if (err)
+ break;
+ errno = 0;
+ }
+
+ saverrno2 = errno;
+ if (pglob->gl_flags & GLOB_ALTDIRFUNC)
+ (*pglob->gl_closedir)(dirp);
+ else
+ closedir(dirp);
+ errno = saverrno2;
+
+ if (err)
+ return (err);
+
+ if (dp == NULL && errno != 0 &&
+ (err = err_aborted(pglob, errno, buf)))
+ return (err);
+
+ if (errno == 0)
+ errno = saverrno;
+ return (0);
+}
+
+
+/*
+ * Extend the gl_pathv member of a glob_t structure to accommodate a new item,
+ * add the new item, and update gl_pathc.
+ *
+ * This assumes the BSD realloc, which only copies the block when its size
+ * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
+ * behavior.
+ *
+ * Return 0 if new item added, error code if memory couldn't be allocated.
+ *
+ * Invariant of the glob_t structure:
+ * Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
+ * gl_pathv points to (gl_offs + gl_pathc + 1) items.
+ */
+static int
+globextend(const Char *path, glob_t *pglob, struct glob_limit *limit,
+ const char *origpat)
+{
+ char **pathv;
+ size_t i, newsize, len;
+ char *copy;
+ const Char *p;
+
+ if ((pglob->gl_flags & GLOB_LIMIT) &&
+ pglob->gl_matchc > limit->l_path_lim) {
+ errno = E2BIG;
+ return (GLOB_NOSPACE);
+ }
+
+ newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs);
+ /* realloc(NULL, newsize) is equivalent to malloc(newsize). */
+ pathv = realloc((void *)pglob->gl_pathv, newsize);
+ if (pathv == NULL)
+ return (GLOB_NOSPACE);
+
+ if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
+ /* first time around -- clear initial gl_offs items */
+ pathv += pglob->gl_offs;
+ for (i = pglob->gl_offs + 1; --i > 0; )
+ *--pathv = NULL;
+ }
+ pglob->gl_pathv = pathv;
+
+ if (origpat != NULL)
+ copy = strdup(origpat);
+ else {
+ for (p = path; *p++ != EOS;)
+ continue;
+ len = MB_CUR_MAX * (size_t)(p - path); /* XXX overallocation */
+ if ((copy = malloc(len)) != NULL) {
+ if (g_Ctoc(path, copy, len)) {
+ free(copy);
+ errno = E2BIG;
+ return (GLOB_NOSPACE);
+ }
+ }
+ }
+ if (copy != NULL) {
+ limit->l_string_cnt += strlen(copy) + 1;
+ if ((pglob->gl_flags & GLOB_LIMIT) &&
+ limit->l_string_cnt >= GLOB_LIMIT_STRING) {
+ free(copy);
+ errno = E2BIG;
+ return (GLOB_NOSPACE);
+ }
+ pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
+ }
+ pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
+ return (copy == NULL ? GLOB_NOSPACE : 0);
+}
+
+/*
+ * pattern matching function for filenames. Each occurrence of the *
+ * pattern causes a recursion level.
+ */
+static int
+match(Char *name, Char *pat, Char *patend)
+{
+ int ok, negate_range;
+ Char c, k;
+ struct xlocale_collate *table =
+ (struct xlocale_collate*)__get_locale()->components[XLC_COLLATE];
+
+ while (pat < patend) {
+ c = *pat++;
+ switch (c & M_MASK) {
+ case M_ALL:
+ if (pat == patend)
+ return (1);
+ do
+ if (match(name, pat, patend))
+ return (1);
+ while (*name++ != EOS);
+ return (0);
+ case M_ONE:
+ if (*name++ == EOS)
+ return (0);
+ break;
+ case M_SET:
+ ok = 0;
+ if ((k = *name++) == EOS)
+ return (0);
+ if ((negate_range = ((*pat & M_MASK) == M_NOT)) != 0)
+ ++pat;
+ while (((c = *pat++) & M_MASK) != M_END)
+ if ((*pat & M_MASK) == M_RNG) {
+ if (table->__collate_load_error ?
+ CHAR(c) <= CHAR(k) &&
+ CHAR(k) <= CHAR(pat[1]) :
+ __wcollate_range_cmp(CHAR(c),
+ CHAR(k)) <= 0 &&
+ __wcollate_range_cmp(CHAR(k),
+ CHAR(pat[1])) <= 0)
+ ok = 1;
+ pat += 2;
+ } else if (c == k)
+ ok = 1;
+ if (ok == negate_range)
+ return (0);
+ break;
+ default:
+ if (*name++ != c)
+ return (0);
+ break;
+ }
+ }
+ return (*name == EOS);
+}
+
+/* Free allocated data belonging to a glob_t structure. */
+void
+globfree(glob_t *pglob)
+{
+ size_t i;
+ char **pp;
+
+ if (pglob->gl_pathv != NULL) {
+ pp = pglob->gl_pathv + pglob->gl_offs;
+ for (i = pglob->gl_pathc; i--; ++pp)
+ if (*pp)
+ free(*pp);
+ free(pglob->gl_pathv);
+ pglob->gl_pathv = NULL;
+ }
+}
+
+static DIR *
+g_opendir(Char *str, glob_t *pglob)
+{
+ char buf[MAXPATHLEN + MB_LEN_MAX - 1];
+
+ if (*str == EOS)
+ strcpy(buf, ".");
+ else {
+ if (g_Ctoc(str, buf, sizeof(buf))) {
+ errno = ENAMETOOLONG;
+ return (NULL);
+ }
+ }
+
+ if (pglob->gl_flags & GLOB_ALTDIRFUNC)
+ return ((*pglob->gl_opendir)(buf));
+
+ return (opendir(buf));
+}
+
+static int
+g_lstat(Char *fn, struct stat *sb, glob_t *pglob)
+{
+ char buf[MAXPATHLEN + MB_LEN_MAX - 1];
+
+ if (g_Ctoc(fn, buf, sizeof(buf))) {
+ errno = ENAMETOOLONG;
+ return (-1);
+ }
+ if (pglob->gl_flags & GLOB_ALTDIRFUNC)
+ return((*pglob->gl_lstat)(buf, sb));
+ return (lstat(buf, sb));
+}
+
+static int
+g_stat(Char *fn, struct stat *sb, glob_t *pglob)
+{
+ char buf[MAXPATHLEN + MB_LEN_MAX - 1];
+
+ if (g_Ctoc(fn, buf, sizeof(buf))) {
+ errno = ENAMETOOLONG;
+ return (-1);
+ }
+ if (pglob->gl_flags & GLOB_ALTDIRFUNC)
+ return ((*pglob->gl_stat)(buf, sb));
+ return (stat(buf, sb));
+}
+
+static const Char *
+g_strchr(const Char *str, wchar_t ch)
+{
+
+ do {
+ if (*str == ch)
+ return (str);
+ } while (*str++);
+ return (NULL);
+}
+
+static int
+g_Ctoc(const Char *str, char *buf, size_t len)
+{
+ mbstate_t mbs;
+ size_t clen;
+
+ memset(&mbs, 0, sizeof(mbs));
+ while (len >= MB_CUR_MAX) {
+ clen = wcrtomb(buf, CHAR(*str), &mbs);
+ if (clen == (size_t)-1) {
+ /* XXX See initial comment #2. */
+ *buf = (char)CHAR(*str);
+ clen = 1;
+ memset(&mbs, 0, sizeof(mbs));
+ }
+ if (CHAR(*str) == EOS)
+ return (0);
+ str++;
+ buf += clen;
+ len -= clen;
+ }
+ return (1);
+}
+
+static int
+err_nomatch(glob_t *pglob, struct glob_limit *limit, const char *origpat) {
+ /*
+ * If there was no match we are going to append the origpat
+ * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
+ * and the origpat did not contain any magic characters
+ * GLOB_NOMAGIC is there just for compatibility with csh.
+ */
+ if ((pglob->gl_flags & GLOB_NOCHECK) ||
+ ((pglob->gl_flags & GLOB_NOMAGIC) &&
+ !(pglob->gl_flags & GLOB_MAGCHAR)))
+ return (globextend(NULL, pglob, limit, origpat));
+ return (GLOB_NOMATCH);
+}
+
+static int
+err_aborted(glob_t *pglob, int err, char *buf) {
+ if ((pglob->gl_errfunc != NULL && pglob->gl_errfunc(buf, err)) ||
+ (pglob->gl_flags & GLOB_ERR))
+ return (GLOB_ABORTED);
+ return (0);
+}
+
+#ifdef DEBUG
+static void
+qprintf(const char *str, Char *s)
+{
+ Char *p;
+
+ (void)printf("%s\n", str);
+ if (s != NULL) {
+ for (p = s; *p != EOS; p++)
+ (void)printf("%c", (char)CHAR(*p));
+ (void)printf("\n");
+ for (p = s; *p != EOS; p++)
+ (void)printf("%c", (isprot(*p) ? '\\' : ' '));
+ (void)printf("\n");
+ for (p = s; *p != EOS; p++)
+ (void)printf("%c", (ismeta(*p) ? '_' : ' '));
+ (void)printf("\n");
+ }
+}
+#endif
diff --git a/lib/libc/gen/initgroups.3 b/lib/libc/gen/initgroups.3
new file mode 100644
index 000000000000..b0b68f2685b4
--- /dev/null
+++ b/lib/libc/gen/initgroups.3
@@ -0,0 +1,82 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)initgroups.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd October 26, 2014
+.Dt INITGROUPS 3
+.Os
+.Sh NAME
+.Nm initgroups
+.Nd initialize group access list
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft int
+.Fn initgroups "const char *name" "gid_t basegid"
+.Sh DESCRIPTION
+The
+.Fn initgroups
+function
+uses the
+.Xr getgrouplist 3
+function to calculate the group access list for the user
+specified in
+.Fa name .
+This group list is then setup for the current process using
+.Xr setgroups 2 .
+The
+.Fa basegid
+is automatically included in the groups list.
+Typically this value is given as
+the group number from the password file.
+.Sh RETURN VALUES
+.Rv -std initgroups
+.Sh ERRORS
+The
+.Fn initgroups
+function may fail and set
+.Va errno
+for any of the errors specified for the library function
+.Xr setgroups 2 .
+It may also return:
+.Bl -tag -width Er
+.It Bq Er ENOMEM
+The
+.Fn initgroups
+function was unable to allocate temporary storage.
+.El
+.Sh SEE ALSO
+.Xr setgroups 2 ,
+.Xr getgrouplist 3
+.Sh HISTORY
+The
+.Fn initgroups
+function appeared in
+.Bx 4.2 .
diff --git a/lib/libc/gen/initgroups.c b/lib/libc/gen/initgroups.c
new file mode 100644
index 000000000000..d6a644c2c004
--- /dev/null
+++ b/lib/libc/gen/initgroups.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)initgroups.c 8.1 (Berkeley) 6/4/93";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+
+#include "namespace.h"
+#include <err.h>
+#include "un-namespace.h"
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int
+initgroups(const char *uname, gid_t agroup)
+{
+ int ngroups, ret;
+ long ngroups_max;
+ gid_t *groups;
+
+ /*
+ * Provide space for one group more than possible to allow
+ * setgroups to fail and set errno.
+ */
+ ngroups_max = sysconf(_SC_NGROUPS_MAX) + 2;
+ if ((groups = malloc(sizeof(*groups) * ngroups_max)) == NULL)
+ return (ENOMEM);
+
+ ngroups = (int)ngroups_max;
+ getgrouplist(uname, agroup, groups, &ngroups);
+ ret = setgroups(ngroups, groups);
+ free(groups);
+ return (ret);
+}
diff --git a/lib/libc/gen/isatty.c b/lib/libc/gen/isatty.c
new file mode 100644
index 000000000000..02b0ffdfeeaa
--- /dev/null
+++ b/lib/libc/gen/isatty.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)isatty.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <termios.h>
+#include <unistd.h>
+
+int
+isatty(int fd)
+{
+ int retval;
+ struct termios t;
+
+ retval = (tcgetattr(fd, &t) != -1);
+ return(retval);
+}
diff --git a/lib/libc/gen/isgreater.3 b/lib/libc/gen/isgreater.3
new file mode 100644
index 000000000000..9a6d85cd50ca
--- /dev/null
+++ b/lib/libc/gen/isgreater.3
@@ -0,0 +1,102 @@
+.\" Copyright (c) 2003 David Schultz <das@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd February 12, 2003
+.Dt ISGREATER 3
+.Os
+.Sh NAME
+.Nm isgreater , isgreaterequal , isless , islessequal ,
+.Nm islessgreater , isunordered
+.Nd "compare two floating-point numbers"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In math.h
+.Ft int
+.Fn isgreater "real-floating x" "real-floating y"
+.Ft int
+.Fn isgreaterequal "real-floating x" "real-floating y"
+.Ft int
+.Fn isless "real-floating x" "real-floating y"
+.Ft int
+.Fn islessequal "real-floating x" "real-floating y"
+.Ft int
+.Fn islessgreater "real-floating x" "real-floating y"
+.Ft int
+.Fn isunordered "real-floating x" "real-floating y"
+.Sh DESCRIPTION
+Each of the macros
+.Fn isgreater ,
+.Fn isgreaterequal ,
+.Fn isless ,
+.Fn islessequal ,
+and
+.Fn islessgreater
+take arguments
+.Fa x
+and
+.Fa y
+and return a non-zero value if and only if its nominal
+relation on
+.Fa x
+and
+.Fa y
+is true.
+These macros always return zero if either
+argument is not a number (NaN), but unlike the corresponding C
+operators, they never raise a floating point exception.
+.Pp
+The
+.Fn isunordered
+macro takes arguments
+.Fa x
+and
+.Fa y
+and returns non-zero if and only if neither
+.Fa x
+nor
+.Fa y
+are NaNs.
+For any pair of floating-point values, one
+of the relationships (less, greater, equal, unordered) holds.
+.Sh SEE ALSO
+.Xr fpclassify 3 ,
+.Xr math 3 ,
+.Xr signbit 3
+.Sh STANDARDS
+The
+.Fn isgreater ,
+.Fn isgreaterequal ,
+.Fn isless ,
+.Fn islessequal ,
+.Fn islessgreater ,
+and
+.Fn isunordered
+macros conform to
+.St -isoC-99 .
+.Sh HISTORY
+The relational macros described above first appeared in
+.Fx 5.1 .
diff --git a/lib/libc/gen/isinf.c b/lib/libc/gen/isinf.c
new file mode 100644
index 000000000000..0eb8b9f13ccb
--- /dev/null
+++ b/lib/libc/gen/isinf.c
@@ -0,0 +1,72 @@
+/*-
+ * Copyright (c) 2004 David Schultz <das@FreeBSD.ORG>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <machine/float.h>
+
+#include <math.h>
+
+#include "fpmath.h"
+
+/*
+ * XXX These routines belong in libm, but they must remain in libc for
+ * binary compat until we can bump libm's major version number.
+ */
+
+__weak_reference(__isinf, isinf);
+
+int
+__isinf(double d)
+{
+ union IEEEd2bits u;
+
+ u.d = d;
+ return (u.bits.exp == 2047 && u.bits.manl == 0 && u.bits.manh == 0);
+}
+
+int
+__isinff(float f)
+{
+ union IEEEf2bits u;
+
+ u.f = f;
+ return (u.bits.exp == 255 && u.bits.man == 0);
+}
+
+int
+__isinfl(long double e)
+{
+ union IEEEl2bits u;
+
+ u.e = e;
+ mask_nbit_l(u);
+#if LDBL_MANT_DIG == 53
+ return (u.bits.exp == 2047 && u.bits.manl == 0 && u.bits.manh == 0);
+#else
+ return (u.bits.exp == 32767 && u.bits.manl == 0 && u.bits.manh == 0);
+#endif
+}
diff --git a/lib/libc/gen/isnan.c b/lib/libc/gen/isnan.c
new file mode 100644
index 000000000000..72c2868b5e90
--- /dev/null
+++ b/lib/libc/gen/isnan.c
@@ -0,0 +1,64 @@
+/*-
+ * Copyright (c) 2004 David Schultz <das@FreeBSD.ORG>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <math.h>
+
+#include "fpmath.h"
+
+/*
+ * XXX These routines belong in libm, but they must remain in libc for
+ * binary compat until we can bump libm's major version number.
+ *
+ * Note this only applies to the dynamic versions of libm and libc, so
+ * for the static and profiled versions we stub out the definitions.
+ * Otherwise you cannot link statically to libm and libc at the same
+ * time, when calling both functions.
+ */
+
+#ifdef PIC
+__weak_reference(__isnan, isnan);
+__weak_reference(__isnanf, isnanf);
+
+int
+__isnan(double d)
+{
+ union IEEEd2bits u;
+
+ u.d = d;
+ return (u.bits.exp == 2047 && (u.bits.manl != 0 || u.bits.manh != 0));
+}
+
+int
+__isnanf(float f)
+{
+ union IEEEf2bits u;
+
+ u.f = f;
+ return (u.bits.exp == 255 && u.bits.man != 0);
+}
+#endif /* PIC */
diff --git a/lib/libc/gen/jrand48.c b/lib/libc/gen/jrand48.c
new file mode 100644
index 000000000000..5aab1e1bec9e
--- /dev/null
+++ b/lib/libc/gen/jrand48.c
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 1993 Martin Birgmeier
+ * All rights reserved.
+ *
+ * You may redistribute unmodified or modified versions of this source
+ * code provided that the above copyright notice and this and the
+ * following conditions are retained.
+ *
+ * This software is provided ``as is'', and comes with no warranties
+ * of any kind. I shall in no event be liable for anything that happens
+ * to anyone/anything when using this software.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdint.h>
+
+#include "rand48.h"
+
+long
+jrand48(unsigned short xseed[3])
+{
+
+ _dorand48(xseed);
+ return ((int32_t)(((uint32_t)xseed[2] << 16) | (uint32_t)xseed[1]));
+}
diff --git a/lib/libc/gen/lcong48.c b/lib/libc/gen/lcong48.c
new file mode 100644
index 000000000000..ab0d1f762d80
--- /dev/null
+++ b/lib/libc/gen/lcong48.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 1993 Martin Birgmeier
+ * All rights reserved.
+ *
+ * You may redistribute unmodified or modified versions of this source
+ * code provided that the above copyright notice and this and the
+ * following conditions are retained.
+ *
+ * This software is provided ``as is'', and comes with no warranties
+ * of any kind. I shall in no event be liable for anything that happens
+ * to anyone/anything when using this software.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "rand48.h"
+
+extern unsigned short _rand48_seed[3];
+extern unsigned short _rand48_mult[3];
+extern unsigned short _rand48_add;
+
+void
+lcong48(unsigned short p[7])
+{
+ _rand48_seed[0] = p[0];
+ _rand48_seed[1] = p[1];
+ _rand48_seed[2] = p[2];
+ _rand48_mult[0] = p[3];
+ _rand48_mult[1] = p[4];
+ _rand48_mult[2] = p[5];
+ _rand48_add = p[6];
+}
diff --git a/lib/libc/gen/ldexp.3 b/lib/libc/gen/ldexp.3
new file mode 100644
index 000000000000..e8e4fbac5ebb
--- /dev/null
+++ b/lib/libc/gen/ldexp.3
@@ -0,0 +1,77 @@
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)ldexp.3 8.2 (Berkeley) 4/19/94
+.\" $FreeBSD$
+.\"
+.Dd March 4, 2005
+.Dt LDEXP 3
+.Os
+.Sh NAME
+.Nm ldexp ,
+.Nm ldexpf ,
+.Nm ldexpl
+.Nd multiply floating-point number by integral power of 2
+.Sh LIBRARY
+.Lb libm
+.Sh SYNOPSIS
+.In math.h
+.Ft double
+.Fn ldexp "double x" "int exp"
+.Ft float
+.Fn ldexpf "float x" "int exp"
+.Ft long double
+.Fn ldexpl "long double x" "int exp"
+.Sh DESCRIPTION
+The
+.Fn ldexp ,
+.Fn ldexpf ,
+and
+.Fn ldexpl
+functions multiply a floating-point number by an integral
+power of 2.
+.Sh RETURN VALUES
+These functions return the value of
+.Fa x
+times 2 raised to the power
+.Fa exp .
+.Sh SEE ALSO
+.Xr frexp 3 ,
+.Xr math 3 ,
+.Xr modf 3
+.Sh STANDARDS
+The
+.Fn ldexp ,
+.Fn ldexpf ,
+and
+.Fn ldexpl
+functions conform to
+.St -isoC-99 .
diff --git a/lib/libc/gen/ldexp.c b/lib/libc/gen/ldexp.c
new file mode 100644
index 000000000000..887f673ee9a5
--- /dev/null
+++ b/lib/libc/gen/ldexp.c
@@ -0,0 +1,123 @@
+/* @(#)s_scalbn.c 5.1 93/09/24 */
+/* @(#)fdlibm.h 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <machine/endian.h>
+#include <math.h>
+
+/* Bit fiddling routines copied from msun/src/math_private.h,v 1.15 */
+
+#if BYTE_ORDER == BIG_ENDIAN
+
+typedef union
+{
+ double value;
+ struct
+ {
+ u_int32_t msw;
+ u_int32_t lsw;
+ } parts;
+} ieee_double_shape_type;
+
+#endif
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+
+typedef union
+{
+ double value;
+ struct
+ {
+ u_int32_t lsw;
+ u_int32_t msw;
+ } parts;
+} ieee_double_shape_type;
+
+#endif
+
+/* Get two 32 bit ints from a double. */
+
+#define EXTRACT_WORDS(ix0,ix1,d) \
+do { \
+ ieee_double_shape_type ew_u; \
+ ew_u.value = (d); \
+ (ix0) = ew_u.parts.msw; \
+ (ix1) = ew_u.parts.lsw; \
+} while (0)
+
+/* Get the more significant 32 bit int from a double. */
+
+#define GET_HIGH_WORD(i,d) \
+do { \
+ ieee_double_shape_type gh_u; \
+ gh_u.value = (d); \
+ (i) = gh_u.parts.msw; \
+} while (0)
+
+/* Set the more significant 32 bits of a double from an int. */
+
+#define SET_HIGH_WORD(d,v) \
+do { \
+ ieee_double_shape_type sh_u; \
+ sh_u.value = (d); \
+ sh_u.parts.msw = (v); \
+ (d) = sh_u.value; \
+} while (0)
+
+
+static const double
+two54 = 1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */
+twom54 = 5.55111512312578270212e-17, /* 0x3C900000, 0x00000000 */
+huge = 1.0e+300,
+tiny = 1.0e-300;
+
+static double
+_copysign(double x, double y)
+{
+ u_int32_t hx,hy;
+ GET_HIGH_WORD(hx,x);
+ GET_HIGH_WORD(hy,y);
+ SET_HIGH_WORD(x,(hx&0x7fffffff)|(hy&0x80000000));
+ return x;
+}
+
+double
+ldexp(double x, int n)
+{
+ int32_t k,hx,lx;
+ EXTRACT_WORDS(hx,lx,x);
+ k = (hx&0x7ff00000)>>20; /* extract exponent */
+ if (k==0) { /* 0 or subnormal x */
+ if ((lx|(hx&0x7fffffff))==0) return x; /* +-0 */
+ x *= two54;
+ GET_HIGH_WORD(hx,x);
+ k = ((hx&0x7ff00000)>>20) - 54;
+ if (n< -50000) return tiny*x; /*underflow*/
+ }
+ if (k==0x7ff) return x+x; /* NaN or Inf */
+ k = k+n;
+ if (k > 0x7fe) return huge*_copysign(huge,x); /* overflow */
+ if (k > 0) /* normal result */
+ {SET_HIGH_WORD(x,(hx&0x800fffff)|(k<<20)); return x;}
+ if (k <= -54) {
+ if (n > 50000) /* in case integer overflow in n+k */
+ return huge*_copysign(huge,x); /*overflow*/
+ else return tiny*_copysign(tiny,x); /*underflow*/
+ }
+ k += 54; /* subnormal result */
+ SET_HIGH_WORD(x,(hx&0x800fffff)|(k<<20));
+ return x*twom54;
+}
diff --git a/lib/libc/gen/libc_dlopen.c b/lib/libc/gen/libc_dlopen.c
new file mode 100644
index 000000000000..2b1aa9e9d43d
--- /dev/null
+++ b/lib/libc/gen/libc_dlopen.c
@@ -0,0 +1,61 @@
+/*-
+ * Copyright (c) 2011 Xin Li <delphij@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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <dlfcn.h>
+#include <stddef.h>
+#include <unistd.h>
+
+#include "libc_private.h"
+
+/*
+ * Whether we want to restrict dlopen()s.
+ */
+static int __libc_restricted_mode = 0;
+
+void *
+libc_dlopen(const char *path, int mode)
+{
+
+ if (__libc_restricted_mode) {
+ _rtld_error("Service unavailable -- libc in restricted mode");
+ return (NULL);
+ } else
+ return (dlopen(path, mode));
+}
+
+void
+__FreeBSD_libc_enter_restricted_mode(void)
+{
+
+ __libc_restricted_mode = 1;
+ return;
+}
+
diff --git a/lib/libc/gen/lockf.3 b/lib/libc/gen/lockf.3
new file mode 100644
index 000000000000..a4adcfa6e2ab
--- /dev/null
+++ b/lib/libc/gen/lockf.3
@@ -0,0 +1,266 @@
+.\" $NetBSD: lockf.3,v 1.10 2008/04/30 13:10:50 martin Exp $
+.\"
+.\" Copyright (c) 1997 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Klaus Klein and S.P. Zeidler.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd September 11, 2013
+.Dt LOCKF 3
+.Os
+.Sh NAME
+.Nm lockf
+.Nd record locking on files
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft int
+.Fn lockf "int fd" "int function" "off_t size"
+.Sh DESCRIPTION
+The
+.Fn lockf
+function allows sections of a file to be locked with advisory-mode locks.
+Calls to
+.Fn lockf
+from other processes which attempt to lock the locked file section will
+either return an error value or block until the section becomes unlocked.
+All the locks for a process are removed when the process terminates.
+.Pp
+The argument
+.Fa fd
+is an open file descriptor.
+The file descriptor must have been opened either for write-only
+.Dv ( O_WRONLY )
+or read/write
+.Dv ( O_RDWR )
+operation.
+.Pp
+The
+.Fa function
+argument is a control value which specifies the action to be taken.
+The permissible values for
+.Fa function
+are as follows:
+.Bl -tag -width F_ULOCKXX -compact -offset indent
+.It Sy Function
+.Sy Description
+.It Dv F_ULOCK
+unlock locked sections
+.It Dv F_LOCK
+lock a section for exclusive use
+.It Dv F_TLOCK
+test and lock a section for exclusive use
+.It Dv F_TEST
+test a section for locks by other processes
+.El
+.Pp
+.Dv F_ULOCK
+removes locks from a section of the file;
+.Dv F_LOCK
+and
+.Dv F_TLOCK
+both lock a section of a file if the section is available;
+.Dv F_TEST
+detects if a lock by another process is present on the specified section.
+.Pp
+The
+.Fa size
+argument is the number of contiguous bytes to be locked or
+unlocked.
+The section to be locked or unlocked starts at the current
+offset in the file and extends forward for a positive size or backward
+for a negative size (the preceding bytes up to but not including the
+current offset).
+However, it is not permitted to lock a section that
+starts or extends before the beginning of the file.
+If
+.Fa size
+is 0, the section from the current offset through the largest possible
+file offset is locked (that is, from the current offset through the
+present or any future end-of-file).
+.Pp
+The sections locked with
+.Dv F_LOCK
+or
+.Dv F_TLOCK
+may, in whole or in part, contain or be contained by a previously
+locked section for the same process.
+When this occurs, or if adjacent
+locked sections would occur, the sections are combined into a single
+locked section.
+If the request would cause the number of locks to
+exceed a system-imposed limit, the request will fail.
+.Pp
+.Dv F_LOCK
+and
+.Dv F_TLOCK
+requests differ only by the action taken if the section is not
+available.
+.Dv F_LOCK
+blocks the calling process until the section is available.
+.Dv F_TLOCK
+makes the function fail if the section is already locked by another
+process.
+.Pp
+File locks are released on first close by the locking process of any
+file descriptor for the file.
+.Pp
+.Dv F_ULOCK
+requests release (wholly or in part) one or more locked sections
+controlled by the process.
+Locked sections will be unlocked starting
+at the current file offset through
+.Fa size
+bytes or to the end of file if size is 0.
+When all of a locked section
+is not released (that is, when the beginning or end of the area to be
+unlocked falls within a locked section), the remaining portions of
+that section are still locked by the process.
+Releasing the center
+portion of a locked section will cause the remaining locked beginning
+and end portions to become two separate locked sections.
+If the
+request would cause the number of locks in the system to exceed a
+system-imposed limit, the request will fail.
+.Pp
+An
+.Dv F_ULOCK
+request in which size is non-zero and the offset of the last byte of
+the requested section is the maximum value for an object of type
+off_t, when the process has an existing lock in which size is 0 and
+which includes the last byte of the requested section, will be treated
+as a request to unlock from the start of the requested section with a
+size equal to 0.
+Otherwise an
+.Dv F_ULOCK
+request will attempt to unlock only the requested section.
+.Pp
+A potential for deadlock occurs if a process controlling a locked
+region is put to sleep by attempting to lock the locked region of
+another process.
+This implementation detects that sleeping until a
+locked region is unlocked would cause a deadlock and fails with an
+.Er EDEADLK
+error.
+.Pp
+The
+.Fn lockf ,
+.Xr fcntl 2 ,
+and
+.Xr flock 2
+locks are compatible.
+Processes using different locking interfaces can cooperate
+over the same file safely.
+However, only one of such interfaces should be used within
+the same process.
+If a file is locked by a process through
+.Xr flock 2 ,
+any record within the file will be seen as locked
+from the viewpoint of another process using
+.Xr fcntl 2
+or
+.Fn lockf ,
+and vice versa.
+.Pp
+Blocking on a section is interrupted by any signal.
+.Sh RETURN VALUES
+.Rv -std lockf
+In the case of a failure, existing locks are not changed.
+.Sh ERRORS
+The
+.Fn lockf
+function
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EAGAIN
+The argument
+.Fa function
+is
+.Dv F_TLOCK
+or
+.Dv F_TEST
+and the section is already locked by another process.
+.It Bq Er EBADF
+The argument
+.Fa fd
+is not a valid open file descriptor.
+.Pp
+The argument
+.Fa function
+is
+.Dv F_LOCK
+or
+.Dv F_TLOCK ,
+and
+.Fa fd
+is not a valid file descriptor open for writing.
+.It Bq Er EDEADLK
+The argument
+.Fa function
+is
+.Dv F_LOCK
+and a deadlock is detected.
+.It Bq Er EINTR
+The argument
+.Fa function
+is F_LOCK
+and
+.Fn lockf
+was interrupted by the delivery of a signal.
+.It Bq Er EINVAL
+The argument
+.Fa function
+is not one of
+.Dv F_ULOCK ,
+.Dv F_LOCK ,
+.Dv F_TLOCK
+or
+.Dv F_TEST .
+.Pp
+The argument
+.Fa fd
+refers to a file that does not support locking.
+.It Bq Er ENOLCK
+The argument
+.Fa function
+is
+.Dv F_ULOCK ,
+.Dv F_LOCK
+or
+.Dv F_TLOCK ,
+and satisfying the lock or unlock request would result in the number
+of locked regions in the system exceeding a system-imposed limit.
+.El
+.Sh SEE ALSO
+.Xr fcntl 2 ,
+.Xr flock 2
+.Sh STANDARDS
+The
+.Fn lockf
+function conforms to
+.St -xpg4.2 .
diff --git a/lib/libc/gen/lockf.c b/lib/libc/gen/lockf.c
new file mode 100644
index 000000000000..c64a34747b5d
--- /dev/null
+++ b/lib/libc/gen/lockf.c
@@ -0,0 +1,84 @@
+/* $NetBSD: lockf.c,v 1.3 2008/04/28 20:22:59 martin Exp $ */
+/*-
+ * Copyright (c) 1997 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Klaus Klein.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+
+int
+lockf(int filedes, int function, off_t size)
+{
+ struct flock fl;
+ int cmd;
+
+ fl.l_start = 0;
+ fl.l_len = size;
+ fl.l_whence = SEEK_CUR;
+
+ switch (function) {
+ case F_ULOCK:
+ cmd = F_SETLK;
+ fl.l_type = F_UNLCK;
+ break;
+ case F_LOCK:
+ cmd = F_SETLKW;
+ fl.l_type = F_WRLCK;
+ break;
+ case F_TLOCK:
+ cmd = F_SETLK;
+ fl.l_type = F_WRLCK;
+ break;
+ case F_TEST:
+ fl.l_type = F_WRLCK;
+ if (((int (*)(int, int, ...))
+ __libc_interposing[INTERPOS_fcntl])(filedes, F_GETLK, &fl)
+ == -1)
+ return (-1);
+ if (fl.l_type == F_UNLCK || (fl.l_sysid == 0 &&
+ fl.l_pid == getpid()))
+ return (0);
+ errno = EAGAIN;
+ return (-1);
+ /* NOTREACHED */
+ default:
+ errno = EINVAL;
+ return (-1);
+ /* NOTREACHED */
+ }
+
+ return (((int (*)(int, int, ...))
+ __libc_interposing[INTERPOS_fcntl])(filedes, cmd, &fl));
+}
diff --git a/lib/libc/gen/lrand48.c b/lib/libc/gen/lrand48.c
new file mode 100644
index 000000000000..44a7f5d0e924
--- /dev/null
+++ b/lib/libc/gen/lrand48.c
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 1993 Martin Birgmeier
+ * All rights reserved.
+ *
+ * You may redistribute unmodified or modified versions of this source
+ * code provided that the above copyright notice and this and the
+ * following conditions are retained.
+ *
+ * This software is provided ``as is'', and comes with no warranties
+ * of any kind. I shall in no event be liable for anything that happens
+ * to anyone/anything when using this software.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "rand48.h"
+
+extern unsigned short _rand48_seed[3];
+
+long
+lrand48(void)
+{
+ _dorand48(_rand48_seed);
+ return ((long) _rand48_seed[2] << 15) + ((long) _rand48_seed[1] >> 1);
+}
diff --git a/lib/libc/gen/makecontext.3 b/lib/libc/gen/makecontext.3
new file mode 100644
index 000000000000..ad55e7abcb47
--- /dev/null
+++ b/lib/libc/gen/makecontext.3
@@ -0,0 +1,120 @@
+.\" Copyright (c) 2002 Packet Design, LLC.
+.\" All rights reserved.
+.\"
+.\" Subject to the following obligations and disclaimer of warranty,
+.\" use and redistribution of this software, in source or object code
+.\" forms, with or without modifications are expressly permitted by
+.\" Packet Design; provided, however, that:
+.\"
+.\" (i) Any and all reproductions of the source or object code
+.\" must include the copyright notice above and the following
+.\" disclaimer of warranties; and
+.\" (ii) No rights are granted, in any manner or form, to use
+.\" Packet Design trademarks, including the mark "PACKET DESIGN"
+.\" on advertising, endorsements, or otherwise except as such
+.\" appears in the above copyright notice or in the software.
+.\"
+.\" THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND
+.\" TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO
+.\" REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING
+.\" THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED
+.\" WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
+.\" OR NON-INFRINGEMENT. PACKET DESIGN DOES NOT WARRANT, GUARANTEE,
+.\" OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS
+.\" OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY,
+.\" RELIABILITY OR OTHERWISE. IN NO EVENT SHALL PACKET DESIGN BE
+.\" LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE
+.\" OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT,
+.\" INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL
+.\" DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF
+.\" USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF
+.\" LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+.\" THE USE OF THIS SOFTWARE, EVEN IF PACKET DESIGN IS ADVISED OF
+.\" THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd September 10, 2002
+.Dt MAKECONTEXT 3
+.Os
+.Sh NAME
+.Nm makecontext , swapcontext
+.Nd modify and exchange user thread contexts
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In ucontext.h
+.Ft void
+.Fo makecontext
+.Fa "ucontext_t *ucp"
+.Fa "void \*[lp]*func\*[rp]\*[lp]void\*[rp]"
+.Fa "int argc" ...
+.Fc
+.Ft int
+.Fn swapcontext "ucontext_t *oucp" "const ucontext_t *ucp"
+.Sh DESCRIPTION
+The
+.Fn makecontext
+function
+modifies the user thread context pointed to by
+.Fa ucp ,
+which must have previously been initialized by a call to
+.Xr getcontext 3
+and had a stack allocated for it.
+The context is modified so that it will continue execution by invoking
+.Fn func
+with the arguments provided.
+The
+.Fa argc
+argument
+must be equal to the number of additional arguments provided to
+.Fn makecontext
+and also equal to the number of arguments to
+.Fn func ,
+or else the behavior is undefined.
+.Pp
+The
+.Fa "ucp->uc_link"
+argument
+must be initialized before calling
+.Fn makecontext
+and determines the action to take when
+.Fn func
+returns:
+if equal to
+.Dv NULL ,
+the process exits;
+otherwise,
+.Fn setcontext "ucp->uc_link"
+is implicitly invoked.
+.Pp
+The
+.Fn swapcontext
+function
+saves the current thread context in
+.Fa "*oucp"
+and makes
+.Fa "*ucp"
+the currently active context.
+.Sh RETURN VALUES
+If successful,
+.Fn swapcontext
+returns zero;
+otherwise \-1 is returned and the global variable
+.Va errno
+is set appropriately.
+.Sh ERRORS
+The
+.Fn swapcontext
+function
+will fail if:
+.Bl -tag -width Er
+.It Bq Er ENOMEM
+There is not enough stack space in
+.Fa ucp
+to complete the operation.
+.El
+.Sh SEE ALSO
+.Xr setcontext 3 ,
+.Xr ucontext 3
diff --git a/lib/libc/gen/modf.3 b/lib/libc/gen/modf.3
new file mode 100644
index 000000000000..a3ee527faca6
--- /dev/null
+++ b/lib/libc/gen/modf.3
@@ -0,0 +1,81 @@
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)modf.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd March 29, 2008
+.Dt MODF 3
+.Os
+.Sh NAME
+.Nm modf ,
+.Nm modff ,
+.Nm modfl
+.Nd extract signed integral and fractional values from floating-point number
+.Sh LIBRARY
+.Lb libm
+.Sh SYNOPSIS
+.In math.h
+.Ft double
+.Fn modf "double value" "double *iptr"
+.Ft float
+.Fn modff "float value" "float *iptr"
+.Ft long double
+.Fn modfl "long double value" "long double *iptr"
+.Sh DESCRIPTION
+The
+.Fn modf ,
+.Fn modff ,
+and
+.Fn modfl
+functions break the argument
+.Fa value
+into integral and fractional parts, each of which has the
+same sign as the argument.
+It stores the integral part as a
+floating point number
+in the object pointed to by
+.Fa iptr .
+.Sh RETURN VALUES
+These functions return the signed fractional part of
+.Fa value .
+.Sh SEE ALSO
+.Xr frexp 3 ,
+.Xr ldexp 3 ,
+.Xr math 3
+.Sh STANDARDS
+The
+.Fn modf ,
+.Fn modff ,
+and
+.Fn modfl
+functions conform to
+.St -isoC-99 .
diff --git a/lib/libc/gen/modf.c b/lib/libc/gen/modf.c
new file mode 100644
index 000000000000..d67b44121aaa
--- /dev/null
+++ b/lib/libc/gen/modf.c
@@ -0,0 +1,138 @@
+/* @(#)s_modf.c 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * modf(double x, double *iptr)
+ * return fraction part of x, and return x's integral part in *iptr.
+ * Method:
+ * Bit twiddling.
+ *
+ * Exception:
+ * No exception.
+ */
+
+#include <sys/types.h>
+#include <machine/endian.h>
+#include <math.h>
+
+/* Bit fiddling routines copied from msun/src/math_private.h,v 1.15 */
+
+#if BYTE_ORDER == BIG_ENDIAN
+
+typedef union
+{
+ double value;
+ struct
+ {
+ u_int32_t msw;
+ u_int32_t lsw;
+ } parts;
+} ieee_double_shape_type;
+
+#endif
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+
+typedef union
+{
+ double value;
+ struct
+ {
+ u_int32_t lsw;
+ u_int32_t msw;
+ } parts;
+} ieee_double_shape_type;
+
+#endif
+
+/* Get two 32 bit ints from a double. */
+
+#define EXTRACT_WORDS(ix0,ix1,d) \
+do { \
+ ieee_double_shape_type ew_u; \
+ ew_u.value = (d); \
+ (ix0) = ew_u.parts.msw; \
+ (ix1) = ew_u.parts.lsw; \
+} while (0)
+
+/* Get the more significant 32 bit int from a double. */
+
+#define GET_HIGH_WORD(i,d) \
+do { \
+ ieee_double_shape_type gh_u; \
+ gh_u.value = (d); \
+ (i) = gh_u.parts.msw; \
+} while (0)
+
+/* Set a double from two 32 bit ints. */
+
+#define INSERT_WORDS(d,ix0,ix1) \
+do { \
+ ieee_double_shape_type iw_u; \
+ iw_u.parts.msw = (ix0); \
+ iw_u.parts.lsw = (ix1); \
+ (d) = iw_u.value; \
+} while (0)
+
+static const double one = 1.0;
+
+double
+modf(double x, double *iptr)
+{
+ int32_t i0,i1,j0;
+ u_int32_t i;
+ EXTRACT_WORDS(i0,i1,x);
+ j0 = ((i0>>20)&0x7ff)-0x3ff; /* exponent of x */
+ if(j0<20) { /* integer part in high x */
+ if(j0<0) { /* |x|<1 */
+ INSERT_WORDS(*iptr,i0&0x80000000,0); /* *iptr = +-0 */
+ return x;
+ } else {
+ i = (0x000fffff)>>j0;
+ if(((i0&i)|i1)==0) { /* x is integral */
+ u_int32_t high;
+ *iptr = x;
+ GET_HIGH_WORD(high,x);
+ INSERT_WORDS(x,high&0x80000000,0); /* return +-0 */
+ return x;
+ } else {
+ INSERT_WORDS(*iptr,i0&(~i),0);
+ return x - *iptr;
+ }
+ }
+ } else if (j0>51) { /* no fraction part */
+ u_int32_t high;
+ if (j0 == 0x400) { /* inf/NaN */
+ *iptr = x;
+ return 0.0 / x;
+ }
+ *iptr = x*one;
+ GET_HIGH_WORD(high,x);
+ INSERT_WORDS(x,high&0x80000000,0); /* return +-0 */
+ return x;
+ } else { /* fraction part in low x */
+ i = ((u_int32_t)(0xffffffff))>>(j0-20);
+ if((i1&i)==0) { /* x is integral */
+ u_int32_t high;
+ *iptr = x;
+ GET_HIGH_WORD(high,x);
+ INSERT_WORDS(x,high&0x80000000,0); /* return +-0 */
+ return x;
+ } else {
+ INSERT_WORDS(*iptr,i0,i1&(~i));
+ return x - *iptr;
+ }
+ }
+}
diff --git a/lib/libc/gen/mrand48.c b/lib/libc/gen/mrand48.c
new file mode 100644
index 000000000000..795a8585802d
--- /dev/null
+++ b/lib/libc/gen/mrand48.c
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 1993 Martin Birgmeier
+ * All rights reserved.
+ *
+ * You may redistribute unmodified or modified versions of this source
+ * code provided that the above copyright notice and this and the
+ * following conditions are retained.
+ *
+ * This software is provided ``as is'', and comes with no warranties
+ * of any kind. I shall in no event be liable for anything that happens
+ * to anyone/anything when using this software.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdint.h>
+
+#include "rand48.h"
+
+extern unsigned short _rand48_seed[3];
+
+long
+mrand48(void)
+{
+
+ _dorand48(_rand48_seed);
+ return ((int32_t)(((uint32_t)_rand48_seed[2] << 16) |
+ (uint32_t)_rand48_seed[1]));
+}
diff --git a/lib/libc/gen/nftw.c b/lib/libc/gen/nftw.c
new file mode 100644
index 000000000000..a338e5a34c84
--- /dev/null
+++ b/lib/libc/gen/nftw.c
@@ -0,0 +1,109 @@
+/* $OpenBSD: nftw.c,v 1.7 2006/03/31 19:41:44 millert Exp $ */
+
+/*
+ * Copyright (c) 2003, 2004 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F39502-99-1-0512.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <fts.h>
+#include <ftw.h>
+
+int
+nftw(const char *path, int (*fn)(const char *, const struct stat *, int,
+ struct FTW *), int nfds, int ftwflags)
+{
+ char * const paths[2] = { (char *)path, NULL };
+ struct FTW ftw;
+ FTSENT *cur;
+ FTS *ftsp;
+ int error = 0, ftsflags, fnflag, postorder, sverrno;
+
+ /* XXX - nfds is currently unused */
+ if (nfds < 1) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ ftsflags = FTS_COMFOLLOW;
+ if (!(ftwflags & FTW_CHDIR))
+ ftsflags |= FTS_NOCHDIR;
+ if (ftwflags & FTW_MOUNT)
+ ftsflags |= FTS_XDEV;
+ if (ftwflags & FTW_PHYS)
+ ftsflags |= FTS_PHYSICAL;
+ else
+ ftsflags |= FTS_LOGICAL;
+ postorder = (ftwflags & FTW_DEPTH) != 0;
+ ftsp = fts_open(paths, ftsflags, NULL);
+ if (ftsp == NULL)
+ return (-1);
+ while ((cur = fts_read(ftsp)) != NULL) {
+ switch (cur->fts_info) {
+ case FTS_D:
+ if (postorder)
+ continue;
+ fnflag = FTW_D;
+ break;
+ case FTS_DC:
+ continue;
+ case FTS_DNR:
+ fnflag = FTW_DNR;
+ break;
+ case FTS_DP:
+ if (!postorder)
+ continue;
+ fnflag = FTW_DP;
+ break;
+ case FTS_F:
+ case FTS_DEFAULT:
+ fnflag = FTW_F;
+ break;
+ case FTS_NS:
+ case FTS_NSOK:
+ fnflag = FTW_NS;
+ break;
+ case FTS_SL:
+ fnflag = FTW_SL;
+ break;
+ case FTS_SLNONE:
+ fnflag = FTW_SLN;
+ break;
+ default:
+ error = -1;
+ goto done;
+ }
+ ftw.base = cur->fts_pathlen - cur->fts_namelen;
+ ftw.level = cur->fts_level;
+ error = fn(cur->fts_path, cur->fts_statp, fnflag, &ftw);
+ if (error != 0)
+ break;
+ }
+done:
+ sverrno = errno;
+ if (fts_close(ftsp) != 0 && error == 0)
+ error = -1;
+ else
+ errno = sverrno;
+ return (error);
+}
diff --git a/lib/libc/gen/nice.3 b/lib/libc/gen/nice.3
new file mode 100644
index 000000000000..b04c8f4596b4
--- /dev/null
+++ b/lib/libc/gen/nice.3
@@ -0,0 +1,97 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)nice.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd February 28, 2015
+.Dt NICE 3
+.Os
+.Sh NAME
+.Nm nice
+.Nd set program scheduling priority
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft int
+.Fn nice "int incr"
+.Sh DESCRIPTION
+.Bf -symbolic
+This interface is obsoleted by
+.Xr setpriority 2 .
+.Ef
+.Pp
+The
+.Fn nice
+function adds
+.Fa incr
+to the scheduling priority of the process.
+The priority is a value in the range -20 to 20.
+The default priority is 0; lower priorities cause more favorable scheduling.
+Only the super-user may lower priorities.
+.Pp
+Children inherit the priority of their parent processes via
+.Xr fork 2 .
+.Sh RETURN VALUES
+Upon successful completion,
+.Fn nice
+returns 0, and
+.Va errno
+is unchanged.
+Otherwise, \-1 is returned, the process' nice value is not changed, and
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+The
+.Fn nice
+function will fail if:
+.Bl -tag -width Er
+.It Bq Er EPERM
+The
+.Fa incr
+argument is negative and the caller does not have appropriate privileges.
+.El
+.Sh SEE ALSO
+.Xr nice 1 ,
+.Xr fork 2 ,
+.Xr setpriority 2 ,
+.Xr renice 8
+.Sh STANDARDS
+The
+.Fn nice
+function conforms to
+.St -p1003.1-2008
+except for the return value.
+This implementation returns 0 upon successful completion but
+the standard requires returning the new nice value,
+which could be \-1.
+.Sh HISTORY
+A
+.Fn nice
+syscall appeared in
+.At v6 .
diff --git a/lib/libc/gen/nice.c b/lib/libc/gen/nice.c
new file mode 100644
index 000000000000..ba9524b5c6c0
--- /dev/null
+++ b/lib/libc/gen/nice.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)nice.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <errno.h>
+#include <unistd.h>
+
+/*
+ * Backwards compatible nice.
+ */
+int
+nice(int incr)
+{
+ int saverrno, prio;
+
+ saverrno = errno;
+ errno = 0;
+ prio = getpriority(PRIO_PROCESS, 0);
+ if (prio == -1 && errno != 0)
+ return (-1);
+ if (setpriority(PRIO_PROCESS, 0, prio + incr) == -1) {
+ if (errno == EACCES)
+ errno = EPERM;
+ return (-1);
+ }
+ errno = saverrno;
+ return (0);
+}
diff --git a/lib/libc/gen/nlist.3 b/lib/libc/gen/nlist.3
new file mode 100644
index 000000000000..5bcd72a0f97d
--- /dev/null
+++ b/lib/libc/gen/nlist.3
@@ -0,0 +1,77 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)nlist.3 8.3 (Berkeley) 4/19/94
+.\" $FreeBSD$
+.\"
+.Dd April 19, 1994
+.Dt NLIST 3
+.Os
+.Sh NAME
+.Nm nlist
+.Nd retrieve symbol table name list from an executable file
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In nlist.h
+.Ft int
+.Fn nlist "const char *filename" "struct nlist *nl"
+.Sh DESCRIPTION
+The
+.Fn nlist
+function
+retrieves name list entries from the symbol table of an
+executable file (see
+.Xr a.out 5 ) .
+The argument
+.Fa \&nl
+is set to reference the
+beginning of the list.
+The list is preened of binary and invalid data;
+if an entry in the
+name list is valid, the
+.Fa n_type
+and
+.Fa n_value
+for the entry are copied into the list
+referenced by
+.Fa \&nl .
+No other data is copied.
+The last entry in the list is always
+.Dv NULL .
+.Sh RETURN VALUES
+The number of invalid entries is returned if successful; otherwise,
+if the file
+.Fa filename
+does not exist or is not executable, the returned value is \-1.
+.Sh SEE ALSO
+.Xr a.out 5
+.Sh HISTORY
+A
+.Fn nlist
+function appeared in
+.At v6 .
diff --git a/lib/libc/gen/nlist.c b/lib/libc/gen/nlist.c
new file mode 100644
index 000000000000..f5631771de6b
--- /dev/null
+++ b/lib/libc/gen/nlist.c
@@ -0,0 +1,404 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)nlist.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <a.out.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+/* i386 is the only current FreeBSD architecture that used a.out format. */
+#ifdef __i386__
+#define _NLIST_DO_AOUT
+#endif
+#define _NLIST_DO_ELF
+
+#ifdef _NLIST_DO_ELF
+#include <machine/elf.h>
+#include <elf-hints.h>
+#endif
+
+int __fdnlist(int, struct nlist *);
+int __aout_fdnlist(int, struct nlist *);
+int __elf_fdnlist(int, struct nlist *);
+int __elf_is_okay__(Elf_Ehdr *);
+
+int
+nlist(const char *name, struct nlist *list)
+{
+ int fd, n;
+
+ fd = _open(name, O_RDONLY | O_CLOEXEC, 0);
+ if (fd < 0)
+ return (-1);
+ n = __fdnlist(fd, list);
+ (void)_close(fd);
+ return (n);
+}
+
+static struct nlist_handlers {
+ int (*fn)(int fd, struct nlist *list);
+} nlist_fn[] = {
+#ifdef _NLIST_DO_AOUT
+ { __aout_fdnlist },
+#endif
+#ifdef _NLIST_DO_ELF
+ { __elf_fdnlist },
+#endif
+};
+
+int
+__fdnlist(int fd, struct nlist *list)
+{
+ int n = -1;
+ unsigned int i;
+
+ for (i = 0; i < nitems(nlist_fn); i++) {
+ n = (nlist_fn[i].fn)(fd, list);
+ if (n != -1)
+ break;
+ }
+ return (n);
+}
+
+#define ISLAST(p) (p->n_un.n_name == 0 || p->n_un.n_name[0] == 0)
+
+#ifdef _NLIST_DO_AOUT
+int
+__aout_fdnlist(int fd, struct nlist *list)
+{
+ struct nlist *p, *symtab;
+ caddr_t strtab, a_out_mmap;
+ off_t stroff, symoff;
+ u_long symsize;
+ int nent;
+ struct exec * exec;
+ struct stat st;
+
+ /* check that file is at least as large as struct exec! */
+ if ((_fstat(fd, &st) < 0) || (st.st_size < sizeof(struct exec)))
+ return (-1);
+
+ /* Check for files too large to mmap. */
+ if (st.st_size > SIZE_T_MAX) {
+ errno = EFBIG;
+ return (-1);
+ }
+
+ /*
+ * Map the whole a.out file into our address space.
+ * We then find the string table withing this area.
+ * We do not just mmap the string table, as it probably
+ * does not start at a page boundary - we save ourselves a
+ * lot of nastiness by mmapping the whole file.
+ *
+ * This gives us an easy way to randomly access all the strings,
+ * without making the memory allocation permanent as with
+ * malloc/free (i.e., munmap will return it to the system).
+ */
+ a_out_mmap = mmap(NULL, (size_t)st.st_size, PROT_READ, MAP_PRIVATE, fd, (off_t)0);
+ if (a_out_mmap == MAP_FAILED)
+ return (-1);
+
+ exec = (struct exec *)a_out_mmap;
+ if (N_BADMAG(*exec)) {
+ munmap(a_out_mmap, (size_t)st.st_size);
+ return (-1);
+ }
+
+ symoff = N_SYMOFF(*exec);
+ symsize = exec->a_syms;
+ stroff = symoff + symsize;
+
+ /* find the string table in our mmapped area */
+ strtab = a_out_mmap + stroff;
+ symtab = (struct nlist *)(a_out_mmap + symoff);
+
+ /*
+ * clean out any left-over information for all valid entries.
+ * Type and value defined to be 0 if not found; historical
+ * versions cleared other and desc as well. Also figure out
+ * the largest string length so don't read any more of the
+ * string table than we have to.
+ *
+ * XXX clearing anything other than n_type and n_value violates
+ * the semantics given in the man page.
+ */
+ nent = 0;
+ for (p = list; !ISLAST(p); ++p) {
+ p->n_type = 0;
+ p->n_other = 0;
+ p->n_desc = 0;
+ p->n_value = 0;
+ ++nent;
+ }
+
+ while (symsize > 0) {
+ int soff;
+
+ symsize-= sizeof(struct nlist);
+ soff = symtab->n_un.n_strx;
+
+
+ if (soff != 0 && (symtab->n_type & N_STAB) == 0)
+ for (p = list; !ISLAST(p); p++)
+ if (!strcmp(&strtab[soff], p->n_un.n_name)) {
+ p->n_value = symtab->n_value;
+ p->n_type = symtab->n_type;
+ p->n_desc = symtab->n_desc;
+ p->n_other = symtab->n_other;
+ if (--nent <= 0)
+ break;
+ }
+ symtab++;
+ }
+ munmap(a_out_mmap, (size_t)st.st_size);
+ return (nent);
+}
+#endif
+
+#ifdef _NLIST_DO_ELF
+static void elf_sym_to_nlist(struct nlist *, Elf_Sym *, Elf_Shdr *, int);
+
+/*
+ * __elf_is_okay__ - Determine if ehdr really
+ * is ELF and valid for the target platform.
+ *
+ * WARNING: This is NOT an ELF ABI function and
+ * as such its use should be restricted.
+ */
+int
+__elf_is_okay__(Elf_Ehdr *ehdr)
+{
+ int retval = 0;
+ /*
+ * We need to check magic, class size, endianess,
+ * and version before we look at the rest of the
+ * Elf_Ehdr structure. These few elements are
+ * represented in a machine independant fashion.
+ */
+ if (IS_ELF(*ehdr) &&
+ ehdr->e_ident[EI_CLASS] == ELF_TARG_CLASS &&
+ ehdr->e_ident[EI_DATA] == ELF_TARG_DATA &&
+ ehdr->e_ident[EI_VERSION] == ELF_TARG_VER) {
+
+ /* Now check the machine dependant header */
+ if (ehdr->e_machine == ELF_TARG_MACH &&
+ ehdr->e_version == ELF_TARG_VER)
+ retval = 1;
+ }
+ return retval;
+}
+
+int
+__elf_fdnlist(int fd, struct nlist *list)
+{
+ struct nlist *p;
+ Elf_Off symoff = 0, symstroff = 0;
+ Elf_Size symsize = 0, symstrsize = 0;
+ Elf_Ssize cc, i;
+ int nent = -1;
+ int errsave;
+ Elf_Sym sbuf[1024];
+ Elf_Sym *s;
+ Elf_Ehdr ehdr;
+ char *strtab = NULL;
+ Elf_Shdr *shdr = NULL;
+ Elf_Size shdr_size;
+ void *base;
+ struct stat st;
+
+ /* Make sure obj is OK */
+ if (lseek(fd, (off_t)0, SEEK_SET) == -1 ||
+ _read(fd, &ehdr, sizeof(Elf_Ehdr)) != sizeof(Elf_Ehdr) ||
+ !__elf_is_okay__(&ehdr) ||
+ _fstat(fd, &st) < 0)
+ return (-1);
+
+ /* calculate section header table size */
+ shdr_size = ehdr.e_shentsize * ehdr.e_shnum;
+
+ /* Make sure it's not too big to mmap */
+ if (shdr_size > SIZE_T_MAX) {
+ errno = EFBIG;
+ return (-1);
+ }
+
+ /* mmap section header table */
+ base = mmap(NULL, (size_t)shdr_size, PROT_READ, MAP_PRIVATE, fd,
+ (off_t)ehdr.e_shoff);
+ if (base == MAP_FAILED)
+ return (-1);
+ shdr = (Elf_Shdr *)base;
+
+ /*
+ * Find the symbol table entry and it's corresponding
+ * string table entry. Version 1.1 of the ABI states
+ * that there is only one symbol table but that this
+ * could change in the future.
+ */
+ for (i = 0; i < ehdr.e_shnum; i++) {
+ if (shdr[i].sh_type == SHT_SYMTAB) {
+ symoff = shdr[i].sh_offset;
+ symsize = shdr[i].sh_size;
+ symstroff = shdr[shdr[i].sh_link].sh_offset;
+ symstrsize = shdr[shdr[i].sh_link].sh_size;
+ break;
+ }
+ }
+
+ /* Check for files too large to mmap. */
+ if (symstrsize > SIZE_T_MAX) {
+ errno = EFBIG;
+ goto done;
+ }
+ /*
+ * Map string table into our address space. This gives us
+ * an easy way to randomly access all the strings, without
+ * 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, MAP_PRIVATE, fd,
+ (off_t)symstroff);
+ if (base == MAP_FAILED)
+ goto done;
+ strtab = (char *)base;
+
+ /*
+ * clean out any left-over information for all valid entries.
+ * Type and value defined to be 0 if not found; historical
+ * versions cleared other and desc as well. Also figure out
+ * the largest string length so don't read any more of the
+ * string table than we have to.
+ *
+ * XXX clearing anything other than n_type and n_value violates
+ * the semantics given in the man page.
+ */
+ nent = 0;
+ for (p = list; !ISLAST(p); ++p) {
+ p->n_type = 0;
+ p->n_other = 0;
+ p->n_desc = 0;
+ p->n_value = 0;
+ ++nent;
+ }
+
+ /* Don't process any further if object is stripped. */
+ if (symoff == 0)
+ goto done;
+
+ if (lseek(fd, (off_t) symoff, SEEK_SET) == -1) {
+ nent = -1;
+ goto done;
+ }
+
+ while (symsize > 0 && nent > 0) {
+ cc = MIN(symsize, sizeof(sbuf));
+ if (_read(fd, sbuf, cc) != cc)
+ break;
+ symsize -= cc;
+ for (s = sbuf; cc > 0 && nent > 0; ++s, cc -= sizeof(*s)) {
+ char *name;
+ struct nlist *p;
+
+ name = strtab + s->st_name;
+ if (name[0] == '\0')
+ continue;
+ for (p = list; !ISLAST(p); p++) {
+ if ((p->n_un.n_name[0] == '_' &&
+ strcmp(name, p->n_un.n_name+1) == 0)
+ || strcmp(name, p->n_un.n_name) == 0) {
+ elf_sym_to_nlist(p, s, shdr,
+ ehdr.e_shnum);
+ if (--nent <= 0)
+ break;
+ }
+ }
+ }
+ }
+ done:
+ errsave = errno;
+ if (strtab != NULL)
+ munmap(strtab, symstrsize);
+ if (shdr != NULL)
+ munmap(shdr, shdr_size);
+ errno = errsave;
+ return (nent);
+}
+
+/*
+ * Convert an Elf_Sym into an nlist structure. This fills in only the
+ * n_value and n_type members.
+ */
+static void
+elf_sym_to_nlist(struct nlist *nl, Elf_Sym *s, Elf_Shdr *shdr, int shnum)
+{
+ nl->n_value = s->st_value;
+
+ switch (s->st_shndx) {
+ case SHN_UNDEF:
+ case SHN_COMMON:
+ nl->n_type = N_UNDF;
+ break;
+ case SHN_ABS:
+ nl->n_type = ELF_ST_TYPE(s->st_info) == STT_FILE ?
+ N_FN : N_ABS;
+ break;
+ default:
+ if (s->st_shndx >= shnum)
+ nl->n_type = N_UNDF;
+ else {
+ Elf_Shdr *sh = shdr + s->st_shndx;
+
+ nl->n_type = sh->sh_type == SHT_PROGBITS ?
+ (sh->sh_flags & SHF_WRITE ? N_DATA : N_TEXT) :
+ (sh->sh_type == SHT_NOBITS ? N_BSS : N_UNDF);
+ }
+ break;
+ }
+
+ if (ELF_ST_BIND(s->st_info) == STB_GLOBAL ||
+ ELF_ST_BIND(s->st_info) == STB_WEAK)
+ nl->n_type |= N_EXT;
+}
+#endif /* _NLIST_DO_ELF */
diff --git a/lib/libc/gen/nrand48.c b/lib/libc/gen/nrand48.c
new file mode 100644
index 000000000000..16c8ca111b5e
--- /dev/null
+++ b/lib/libc/gen/nrand48.c
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 1993 Martin Birgmeier
+ * All rights reserved.
+ *
+ * You may redistribute unmodified or modified versions of this source
+ * code provided that the above copyright notice and this and the
+ * following conditions are retained.
+ *
+ * This software is provided ``as is'', and comes with no warranties
+ * of any kind. I shall in no event be liable for anything that happens
+ * to anyone/anything when using this software.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "rand48.h"
+
+long
+nrand48(unsigned short xseed[3])
+{
+ _dorand48(xseed);
+ return ((long) xseed[2] << 15) + ((long) xseed[1] >> 1);
+}
diff --git a/lib/libc/gen/opendir.c b/lib/libc/gen/opendir.c
new file mode 100644
index 000000000000..bf4dea3ffc83
--- /dev/null
+++ b/lib/libc/gen/opendir.c
@@ -0,0 +1,360 @@
+/*-
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)opendir.c 8.8 (Berkeley) 5/1/95";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+#include "gen-private.h"
+#include "telldir.h"
+
+static DIR * __opendir_common(int, int, bool);
+
+/*
+ * Open a directory.
+ */
+DIR *
+opendir(const char *name)
+{
+
+ return (__opendir2(name, DTF_HIDEW|DTF_NODUP));
+}
+
+/*
+ * Open a directory with existing file descriptor.
+ */
+DIR *
+fdopendir(int fd)
+{
+
+ if (_fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
+ return (NULL);
+ return (__opendir_common(fd, DTF_HIDEW|DTF_NODUP, true));
+}
+
+DIR *
+__opendir2(const char *name, int flags)
+{
+ int fd;
+ DIR *dir;
+ int saved_errno;
+
+ if ((flags & (__DTF_READALL | __DTF_SKIPREAD)) != 0)
+ return (NULL);
+ if ((fd = _open(name,
+ O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC)) == -1)
+ return (NULL);
+
+ dir = __opendir_common(fd, flags, false);
+ if (dir == NULL) {
+ saved_errno = errno;
+ _close(fd);
+ errno = saved_errno;
+ }
+ return (dir);
+}
+
+static int
+opendir_compar(const void *p1, const void *p2)
+{
+
+ return (strcmp((*(const struct dirent **)p1)->d_name,
+ (*(const struct dirent **)p2)->d_name));
+}
+
+/*
+ * For a directory at the top of a unionfs stack, the entire directory's
+ * contents are read and cached locally until the next call to rewinddir().
+ * For the fdopendir() case, the initial seek position must be preserved.
+ * For rewinddir(), the full directory should always be re-read from the
+ * beginning.
+ *
+ * If an error occurs, the existing buffer and state of 'dirp' is left
+ * unchanged.
+ */
+bool
+_filldir(DIR *dirp, bool use_current_pos)
+{
+ struct dirent **dpv;
+ char *buf, *ddptr, *ddeptr;
+ off_t pos;
+ int fd2, incr, len, n, saved_errno, space;
+
+ len = 0;
+ space = 0;
+ buf = NULL;
+ ddptr = NULL;
+
+ /*
+ * Use the system page size if that is a multiple of DIRBLKSIZ.
+ * Hopefully this can be a big win someday by allowing page
+ * trades to user space to be done by _getdirentries().
+ */
+ incr = getpagesize();
+ if ((incr % DIRBLKSIZ) != 0)
+ incr = DIRBLKSIZ;
+
+ /*
+ * The strategy here is to read all the directory
+ * entries into a buffer, sort the buffer, and
+ * remove duplicate entries by setting the inode
+ * number to zero.
+ *
+ * We reopen the directory because _getdirentries()
+ * on a MNT_UNION mount modifies the open directory,
+ * making it refer to the lower directory after the
+ * upper directory's entries are exhausted.
+ * This would otherwise break software that uses
+ * the directory descriptor for fchdir or *at
+ * functions, such as fts.c.
+ */
+ if ((fd2 = _openat(dirp->dd_fd, ".", O_RDONLY | O_CLOEXEC)) == -1)
+ return (false);
+
+ if (use_current_pos) {
+ pos = lseek(dirp->dd_fd, 0, SEEK_CUR);
+ if (pos == -1 || lseek(fd2, pos, SEEK_SET) == -1) {
+ saved_errno = errno;
+ _close(fd2);
+ errno = saved_errno;
+ return (false);
+ }
+ }
+
+ do {
+ /*
+ * Always make at least DIRBLKSIZ bytes
+ * available to _getdirentries
+ */
+ if (space < DIRBLKSIZ) {
+ space += incr;
+ len += incr;
+ buf = reallocf(buf, len);
+ if (buf == NULL) {
+ saved_errno = errno;
+ _close(fd2);
+ errno = saved_errno;
+ return (false);
+ }
+ ddptr = buf + (len - space);
+ }
+
+ n = _getdirentries(fd2, ddptr, space, &dirp->dd_seek);
+ if (n > 0) {
+ ddptr += n;
+ space -= n;
+ }
+ if (n < 0) {
+ saved_errno = errno;
+ _close(fd2);
+ errno = saved_errno;
+ return (false);
+ }
+ } while (n > 0);
+ _close(fd2);
+
+ ddeptr = ddptr;
+
+ /*
+ * There is now a buffer full of (possibly) duplicate
+ * names.
+ */
+ dirp->dd_buf = buf;
+
+ /*
+ * Go round this loop twice...
+ *
+ * Scan through the buffer, counting entries.
+ * On the second pass, save pointers to each one.
+ * Then sort the pointers and remove duplicate names.
+ */
+ for (dpv = NULL;;) {
+ n = 0;
+ ddptr = buf;
+ while (ddptr < ddeptr) {
+ struct dirent *dp;
+
+ dp = (struct dirent *) ddptr;
+ if ((long)dp & 03L)
+ break;
+ if ((dp->d_reclen <= 0) ||
+ (dp->d_reclen > (ddeptr + 1 - ddptr)))
+ break;
+ ddptr += dp->d_reclen;
+ if (dp->d_fileno) {
+ if (dpv)
+ dpv[n] = dp;
+ n++;
+ }
+ }
+
+ if (dpv) {
+ struct dirent *xp;
+
+ /*
+ * This sort must be stable.
+ */
+ mergesort(dpv, n, sizeof(*dpv), opendir_compar);
+
+ dpv[n] = NULL;
+ xp = NULL;
+
+ /*
+ * Scan through the buffer in sort order,
+ * zapping the inode number of any
+ * duplicate names.
+ */
+ for (n = 0; dpv[n]; n++) {
+ struct dirent *dp = dpv[n];
+
+ if ((xp == NULL) ||
+ strcmp(dp->d_name, xp->d_name)) {
+ xp = dp;
+ } else {
+ dp->d_fileno = 0;
+ }
+ if (dp->d_type == DT_WHT &&
+ (dirp->dd_flags & DTF_HIDEW))
+ dp->d_fileno = 0;
+ }
+
+ free(dpv);
+ break;
+ } else {
+ dpv = malloc((n+1) * sizeof(struct dirent *));
+ if (dpv == NULL)
+ break;
+ }
+ }
+
+ dirp->dd_len = len;
+ dirp->dd_size = ddptr - dirp->dd_buf;
+ return (true);
+}
+
+
+/*
+ * Common routine for opendir(3), __opendir2(3) and fdopendir(3).
+ */
+static DIR *
+__opendir_common(int fd, int flags, bool use_current_pos)
+{
+ DIR *dirp;
+ int incr;
+ int saved_errno;
+ int unionstack;
+
+ if ((dirp = malloc(sizeof(DIR) + sizeof(struct _telldir))) == NULL)
+ return (NULL);
+
+ dirp->dd_buf = NULL;
+ dirp->dd_fd = fd;
+ dirp->dd_flags = flags;
+ dirp->dd_loc = 0;
+ dirp->dd_lock = NULL;
+ dirp->dd_td = (struct _telldir *)((char *)dirp + sizeof(DIR));
+ LIST_INIT(&dirp->dd_td->td_locq);
+ dirp->dd_td->td_loccnt = 0;
+
+ /*
+ * Use the system page size if that is a multiple of DIRBLKSIZ.
+ * Hopefully this can be a big win someday by allowing page
+ * trades to user space to be done by _getdirentries().
+ */
+ incr = getpagesize();
+ if ((incr % DIRBLKSIZ) != 0)
+ incr = DIRBLKSIZ;
+
+ /*
+ * Determine whether this directory is the top of a union stack.
+ */
+ if (flags & DTF_NODUP) {
+ struct statfs sfb;
+
+ if (_fstatfs(fd, &sfb) < 0)
+ goto fail;
+ unionstack = !strcmp(sfb.f_fstypename, "unionfs")
+ || (sfb.f_flags & MNT_UNION);
+ } else {
+ unionstack = 0;
+ }
+
+ if (unionstack) {
+ if (!_filldir(dirp, use_current_pos))
+ goto fail;
+ dirp->dd_flags |= __DTF_READALL;
+ } else {
+ dirp->dd_len = incr;
+ dirp->dd_buf = malloc(dirp->dd_len);
+ if (dirp->dd_buf == NULL)
+ goto fail;
+ if (use_current_pos) {
+ /*
+ * Read the first batch of directory entries
+ * to prime dd_seek. This also checks if the
+ * fd passed to fdopendir() is a directory.
+ */
+ dirp->dd_size = _getdirentries(dirp->dd_fd,
+ dirp->dd_buf, dirp->dd_len, &dirp->dd_seek);
+ if (dirp->dd_size < 0) {
+ if (errno == EINVAL)
+ errno = ENOTDIR;
+ goto fail;
+ }
+ dirp->dd_flags |= __DTF_SKIPREAD;
+ } else {
+ dirp->dd_size = 0;
+ dirp->dd_seek = 0;
+ }
+ }
+
+ return (dirp);
+
+fail:
+ saved_errno = errno;
+ free(dirp->dd_buf);
+ free(dirp);
+ errno = saved_errno;
+ return (NULL);
+}
diff --git a/lib/libc/gen/pause.3 b/lib/libc/gen/pause.3
new file mode 100644
index 000000000000..ce715d2b4cb1
--- /dev/null
+++ b/lib/libc/gen/pause.3
@@ -0,0 +1,82 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)pause.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt PAUSE 3
+.Os
+.Sh NAME
+.Nm pause
+.Nd stop until signal
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft int
+.Fn pause void
+.Sh DESCRIPTION
+.Sy Pause is made obsolete by
+.Xr sigsuspend 2 .
+.Pp
+The
+.Fn pause
+function
+forces a process to pause until
+a signal is received from either the
+.Xr kill 2
+function
+or an interval timer.
+(See
+.Xr setitimer 2 . )
+Upon termination of a signal handler started during a
+.Fn pause ,
+the
+.Fn pause
+call will return.
+.Sh RETURN VALUES
+Always returns \-1.
+.Sh ERRORS
+The
+.Fn pause
+function
+always returns:
+.Bl -tag -width Er
+.It Bq Er EINTR
+The call was interrupted.
+.El
+.Sh SEE ALSO
+.Xr kill 2 ,
+.Xr select 2 ,
+.Xr sigsuspend 2
+.Sh HISTORY
+A
+.Fn pause
+syscall
+appeared in
+.At v6 .
diff --git a/lib/libc/gen/pause.c b/lib/libc/gen/pause.c
new file mode 100644
index 000000000000..8e7a638783f4
--- /dev/null
+++ b/lib/libc/gen/pause.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)pause.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <signal.h>
+#include <unistd.h>
+
+#include "libc_private.h"
+
+int __pause(void);
+
+/*
+ * Backwards compatible pause.
+ */
+int
+__pause(void)
+{
+ sigset_t oset;
+
+ if (sigprocmask(SIG_BLOCK, NULL, &oset) == -1)
+ return (-1);
+ return (sigsuspend(&oset));
+}
+
+__weak_reference(__pause, pause);
+__weak_reference(__pause, _pause);
diff --git a/lib/libc/gen/pmadvise.c b/lib/libc/gen/pmadvise.c
new file mode 100644
index 000000000000..0dc77e3e992b
--- /dev/null
+++ b/lib/libc/gen/pmadvise.c
@@ -0,0 +1,26 @@
+/*
+ * The contents of this file are in the public domain.
+ * Written by Garrett A. Wollman, 2000-10-07.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/mman.h>
+#include <errno.h>
+
+int
+posix_madvise(void *address, size_t size, int how)
+{
+ int ret, saved_errno;
+
+ saved_errno = errno;
+ if (madvise(address, size, how) == -1) {
+ ret = errno;
+ errno = saved_errno;
+ } else {
+ ret = 0;
+ }
+ return (ret);
+}
diff --git a/lib/libc/gen/popen.3 b/lib/libc/gen/popen.3
new file mode 100644
index 000000000000..386a0bdf9857
--- /dev/null
+++ b/lib/libc/gen/popen.3
@@ -0,0 +1,202 @@
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)popen.3 8.2 (Berkeley) 5/3/95
+.\" $FreeBSD$
+.\"
+.Dd May 20, 2013
+.Dt POPEN 3
+.Os
+.Sh NAME
+.Nm popen ,
+.Nm pclose
+.Nd process
+.Tn I/O
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdio.h
+.Ft FILE *
+.Fn popen "const char *command" "const char *type"
+.Ft int
+.Fn pclose "FILE *stream"
+.Sh DESCRIPTION
+The
+.Fn popen
+function
+.Dq opens
+a process by creating a bidirectional pipe
+forking,
+and invoking the shell.
+Any streams opened by previous
+.Fn popen
+calls in the parent process are closed in the new child process.
+Historically,
+.Fn popen
+was implemented with a unidirectional pipe;
+hence many implementations of
+.Fn popen
+only allow the
+.Fa type
+argument to specify reading or writing, not both.
+Since
+.Fn popen
+is now implemented using a bidirectional pipe, the
+.Fa type
+argument may request a bidirectional data flow.
+The
+.Fa type
+argument is a pointer to a null-terminated string
+which must be
+.Ql r
+for reading,
+.Ql w
+for writing, or
+.Ql r+
+for reading and writing.
+.Pp
+A letter
+.Ql e
+may be appended to that to request that the underlying file descriptor
+be set close-on-exec.
+.Pp
+The
+.Fa command
+argument is a pointer to a null-terminated string
+containing a shell command line.
+This command is passed to
+.Pa /bin/sh
+using the
+.Fl c
+flag; interpretation, if any, is performed by the shell.
+.Pp
+The return value from
+.Fn popen
+is a normal standard
+.Tn I/O
+stream in all respects
+save that it must be closed with
+.Fn pclose
+rather than
+.Fn fclose .
+Writing to such a stream
+writes to the standard input of the command;
+the command's standard output is the same as that of the process that called
+.Fn popen ,
+unless this is altered by the command itself.
+Conversely, reading from a
+.Dq popened
+stream reads the command's standard output, and
+the command's standard input is the same as that of the process that called
+.Fn popen .
+.Pp
+Note that output
+.Fn popen
+streams are fully buffered by default.
+.Pp
+The
+.Fn pclose
+function waits for the associated process to terminate
+and returns the exit status of the command
+as returned by
+.Xr wait4 2 .
+.Sh RETURN VALUES
+The
+.Fn popen
+function returns
+.Dv NULL
+if the
+.Xr fork 2
+or
+.Xr pipe 2
+calls fail,
+or if it cannot allocate memory.
+.Pp
+The
+.Fn pclose
+function
+returns \-1 if
+.Fa stream
+is not associated with a
+.Dq popened
+command, if
+.Fa stream
+already
+.Dq pclosed ,
+or if
+.Xr wait4 2
+returns an error.
+.Sh ERRORS
+The
+.Fn popen
+function does not reliably set
+.Va errno .
+.Sh SEE ALSO
+.Xr sh 1 ,
+.Xr fork 2 ,
+.Xr pipe 2 ,
+.Xr wait4 2 ,
+.Xr fclose 3 ,
+.Xr fflush 3 ,
+.Xr fopen 3 ,
+.Xr stdio 3 ,
+.Xr system 3
+.Sh HISTORY
+A
+.Fn popen
+and a
+.Fn pclose
+function appeared in
+.At v7 .
+.Pp
+Bidirectional functionality was added in
+.Fx 2.2.6 .
+.Sh BUGS
+Since the standard input of a command opened for reading
+shares its seek offset with the process that called
+.Fn popen ,
+if the original process has done a buffered read,
+the command's input position may not be as expected.
+Similarly, the output from a command opened for writing
+may become intermingled with that of the original process.
+The latter can be avoided by calling
+.Xr fflush 3
+before
+.Fn popen .
+.Pp
+Failure to execute the shell
+is indistinguishable from the shell's failure to execute command,
+or an immediate exit of the command.
+The only hint is an exit status of 127.
+.Pp
+The
+.Fn popen
+function
+always calls
+.Xr sh 1 ,
+never calls
+.Xr csh 1 .
diff --git a/lib/libc/gen/popen.c b/lib/libc/gen/popen.c
new file mode 100644
index 000000000000..e469ab6f96c7
--- /dev/null
+++ b/lib/libc/gen/popen.c
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software written by Ken Arnold and
+ * published in UNIX Review, Vol. 6, No. 8.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)popen.c 8.3 (Berkeley) 5/3/95";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/wait.h>
+
+#include <signal.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <paths.h>
+#include <pthread.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+
+extern char **environ;
+
+struct pid {
+ SLIST_ENTRY(pid) next;
+ FILE *fp;
+ pid_t pid;
+};
+static SLIST_HEAD(, pid) pidlist = SLIST_HEAD_INITIALIZER(pidlist);
+static pthread_mutex_t pidlist_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+#define THREAD_LOCK() if (__isthreaded) _pthread_mutex_lock(&pidlist_mutex)
+#define THREAD_UNLOCK() if (__isthreaded) _pthread_mutex_unlock(&pidlist_mutex)
+
+FILE *
+popen(const char *command, const char *type)
+{
+ struct pid *cur;
+ FILE *iop;
+ int pdes[2], pid, twoway, cloexec;
+ int pdes_unused_in_parent;
+ char *argv[4];
+ struct pid *p;
+
+ cloexec = strchr(type, 'e') != NULL;
+ /*
+ * Lite2 introduced two-way popen() pipes using _socketpair().
+ * FreeBSD's pipe() is bidirectional, so we use that.
+ */
+ if (strchr(type, '+')) {
+ twoway = 1;
+ type = "r+";
+ } else {
+ twoway = 0;
+ if ((*type != 'r' && *type != 'w') ||
+ (type[1] && (type[1] != 'e' || type[2])))
+ return (NULL);
+ }
+ if (pipe2(pdes, O_CLOEXEC) < 0)
+ return (NULL);
+
+ if ((cur = malloc(sizeof(struct pid))) == NULL) {
+ (void)_close(pdes[0]);
+ (void)_close(pdes[1]);
+ return (NULL);
+ }
+
+ if (*type == 'r') {
+ iop = fdopen(pdes[0], type);
+ pdes_unused_in_parent = pdes[1];
+ } else {
+ iop = fdopen(pdes[1], type);
+ pdes_unused_in_parent = pdes[0];
+ }
+ if (iop == NULL) {
+ (void)_close(pdes[0]);
+ (void)_close(pdes[1]);
+ free(cur);
+ return (NULL);
+ }
+
+ argv[0] = "sh";
+ argv[1] = "-c";
+ argv[2] = (char *)command;
+ argv[3] = NULL;
+
+ THREAD_LOCK();
+ switch (pid = vfork()) {
+ case -1: /* Error. */
+ THREAD_UNLOCK();
+ /*
+ * The _close() closes the unused end of pdes[], while
+ * the fclose() closes the used end of pdes[], *and* cleans
+ * up iop.
+ */
+ (void)_close(pdes_unused_in_parent);
+ free(cur);
+ (void)fclose(iop);
+ return (NULL);
+ /* NOTREACHED */
+ case 0: /* Child. */
+ if (*type == 'r') {
+ /*
+ * The _dup2() to STDIN_FILENO is repeated to avoid
+ * writing to pdes[1], which might corrupt the
+ * parent's copy. This isn't good enough in
+ * general, since the _exit() is no return, so
+ * the compiler is free to corrupt all the local
+ * variables.
+ */
+ if (pdes[1] != STDOUT_FILENO) {
+ (void)_dup2(pdes[1], STDOUT_FILENO);
+ if (twoway)
+ (void)_dup2(STDOUT_FILENO, STDIN_FILENO);
+ } else if (twoway && (pdes[1] != STDIN_FILENO)) {
+ (void)_dup2(pdes[1], STDIN_FILENO);
+ (void)_fcntl(pdes[1], F_SETFD, 0);
+ } else
+ (void)_fcntl(pdes[1], F_SETFD, 0);
+ } else {
+ if (pdes[0] != STDIN_FILENO) {
+ (void)_dup2(pdes[0], STDIN_FILENO);
+ } else
+ (void)_fcntl(pdes[0], F_SETFD, 0);
+ }
+ SLIST_FOREACH(p, &pidlist, next)
+ (void)_close(fileno(p->fp));
+ _execve(_PATH_BSHELL, argv, environ);
+ _exit(127);
+ /* NOTREACHED */
+ }
+ THREAD_UNLOCK();
+
+ /* Parent. */
+ (void)_close(pdes_unused_in_parent);
+
+ /* Link into list of file descriptors. */
+ cur->fp = iop;
+ cur->pid = pid;
+ THREAD_LOCK();
+ SLIST_INSERT_HEAD(&pidlist, cur, next);
+ THREAD_UNLOCK();
+
+ /*
+ * To guard against undesired fd passing with concurrent calls,
+ * only clear the close-on-exec flag after linking the file into
+ * the list which will cause an explicit close.
+ */
+ if (!cloexec)
+ (void)_fcntl(*type == 'r' ? pdes[0] : pdes[1], F_SETFD, 0);
+
+ return (iop);
+}
+
+/*
+ * pclose --
+ * Pclose returns -1 if stream is not associated with a `popened' command,
+ * if already `pclosed', or waitpid returns an error.
+ */
+int
+pclose(FILE *iop)
+{
+ struct pid *cur, *last = NULL;
+ int pstat;
+ pid_t pid;
+
+ /*
+ * Find the appropriate file pointer and remove it from the list.
+ */
+ THREAD_LOCK();
+ SLIST_FOREACH(cur, &pidlist, next) {
+ if (cur->fp == iop)
+ break;
+ last = cur;
+ }
+ if (cur == NULL) {
+ THREAD_UNLOCK();
+ return (-1);
+ }
+ if (last == NULL)
+ SLIST_REMOVE_HEAD(&pidlist, next);
+ else
+ SLIST_REMOVE_AFTER(last, next);
+ THREAD_UNLOCK();
+
+ (void)fclose(iop);
+
+ do {
+ pid = _wait4(cur->pid, &pstat, 0, (struct rusage *)0);
+ } while (pid == -1 && errno == EINTR);
+
+ free(cur);
+
+ return (pid == -1 ? -1 : pstat);
+}
diff --git a/lib/libc/gen/posix_spawn.3 b/lib/libc/gen/posix_spawn.3
new file mode 100644
index 000000000000..ebbf05a4f25c
--- /dev/null
+++ b/lib/libc/gen/posix_spawn.3
@@ -0,0 +1,460 @@
+.\" Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" Portions of this text are reprinted and reproduced in electronic form
+.\" from IEEE Std 1003.1, 2004 Edition, Standard for Information Technology --
+.\" Portable Operating System Interface (POSIX), The Open Group Base
+.\" Specifications Issue 6, Copyright (C) 2001-2004 by the Institute of
+.\" Electrical and Electronics Engineers, Inc and The Open Group. In the
+.\" event of any discrepancy between this version and the original IEEE and
+.\" The Open Group Standard, the original IEEE and The Open Group Standard is
+.\" the referee document. The original Standard can be obtained online at
+.\" http://www.opengroup.org/unix/online.html.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd January 5, 2016
+.Dt POSIX_SPAWN 3
+.Os
+.Sh NAME
+.Nm posix_spawn ,
+.Nm posix_spawnp
+.Nd "spawn a process"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In spawn.h
+.Ft int
+.Fn posix_spawn "pid_t *restrict pid" "const char *restrict path" "const posix_spawn_file_actions_t *file_actions" "const posix_spawnattr_t *restrict attrp" "char *const argv[restrict]" "char *const envp[restrict]"
+.Ft int
+.Fn posix_spawnp "pid_t *restrict pid" "const char *restrict file" "const posix_spawn_file_actions_t *file_actions" "const posix_spawnattr_t *restrict attrp" "char *const argv[restrict]" "char *const envp[restrict]"
+.Sh DESCRIPTION
+The
+.Fn posix_spawn
+and
+.Fn posix_spawnp
+functions create a new process (child process) from the specified
+process image.
+The new process image is constructed from a regular executable
+file called the new process image file.
+.Pp
+When a C program is executed as the result of this call, it is
+entered as a C-language function call as follows:
+.Bd -literal -offset indent
+int main(int argc, char *argv[]);
+.Ed
+.Pp
+where
+.Fa argc
+is the argument count and
+.Fa argv
+is an array of character pointers to the arguments themselves.
+In addition, the variable:
+.Bd -literal -offset indent
+extern char **environ;
+.Ed
+.Pp
+points to an array of character pointers to
+the environment strings.
+.Pp
+The argument
+.Fa argv
+is an array of character pointers to null-terminated
+strings.
+The last member of this array is a null pointer and is not counted
+in
+.Fa argc .
+These strings constitute the argument list available to the new process
+image.
+The value in
+.Fa argv Ns [0]
+should point to
+a filename that is associated with the process image being started by
+the
+.Fn posix_spawn
+or
+.Fn posix_spawnp
+function.
+.Pp
+The argument
+.Fa envp
+is an array of character pointers to null-terminated strings.
+These strings constitute the environment for the new process image.
+The environment array is terminated by a null pointer.
+.Pp
+The
+.Fa path
+argument to
+.Fn posix_spawn
+is a pathname that identifies the new process image file to execute.
+.Pp
+The
+.Fa file
+parameter to
+.Fn posix_spawnp
+is used to construct a pathname that identifies the new process
+image file.
+If the file parameter contains a slash character, the file parameter
+is used as the pathname for the new process image file.
+Otherwise, the path prefix for this file is obtained by a search
+of the directories passed as the environment variable
+.Dq Ev PATH .
+If this variable is not specified,
+the default path is set according to the
+.Dv _PATH_DEFPATH
+definition in
+.In paths.h ,
+which is set to
+.Dq Ev /sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin .
+.Pp
+If
+.Fa file_actions
+is a null pointer, then file descriptors open in the
+calling process remain open in the child process, except for those
+whose close-on-exec flag
+.Dv FD_CLOEXEC
+is set (see
+.Fn fcntl ) .
+For those
+file descriptors that remain open, all attributes of the corresponding
+open file descriptions, including file locks (see
+.Fn fcntl ) ,
+remain unchanged.
+.Pp
+If
+.Fa file_actions
+is not NULL, then the file descriptors open in the child process are
+those open in the calling process as modified by the spawn file
+actions object pointed to by
+.Fa file_actions
+and the
+.Dv FD_CLOEXEC
+flag of each remaining open file descriptor after the spawn file actions
+have been processed.
+The effective order of processing the spawn file actions are:
+.Bl -enum
+.It
+The set of open file descriptors for the child process initially
+are the same set as is open for the calling process.
+All attributes of the corresponding open file descriptions, including
+file locks (see
+.Fn fcntl ) ,
+remain unchanged.
+.It
+The signal mask, signal default actions, and the effective user and
+group IDs for the child process are changed as specified in the
+attributes object referenced by
+.Fa attrp .
+.It
+The file actions specified by the spawn file actions object are
+performed in the order in which they were added to the spawn file
+actions object.
+.It
+Any file descriptor that has its
+.Dv FD_CLOEXEC
+flag set (see
+.Fn fcntl )
+is closed.
+.El
+.Pp
+The
+.Vt posix_spawnattr_t
+spawn attributes object type is defined in
+.In spawn.h .
+It contains the attributes defined below.
+.Pp
+If the
+.Dv POSIX_SPAWN_SETPGROUP
+flag is set in the spawn-flags attribute of the object referenced by
+.Fa attrp ,
+and the spawn-pgroup attribute of the same object is non-zero, then the
+child's process group is as specified in the spawn-pgroup
+attribute of the object referenced by
+.Fa attrp .
+.Pp
+As a special case, if the
+.Dv POSIX_SPAWN_SETPGROUP
+flag is set in the spawn-flags attribute of the object referenced by
+.Fa attrp ,
+and the spawn-pgroup attribute of the same object is set to zero, then
+the child is in a new process group with a process group ID equal
+to its process ID.
+.Pp
+If the
+.Dv POSIX_SPAWN_SETPGROUP
+flag is not set in the spawn-flags attribute of the object referenced by
+.Fa attrp ,
+the new child process inherits the parent's process group.
+.Pp
+If the
+.Dv POSIX_SPAWN_SETSCHEDPARAM
+flag is set in the spawn-flags attribute of the object referenced by
+.Fa attrp ,
+but
+.Dv POSIX_SPAWN_SETSCHEDULER
+is not set, the new process image initially has the scheduling
+policy of the calling process with the scheduling parameters specified
+in the spawn-schedparam attribute of the object referenced by
+.Fa attrp .
+.Pp
+If the
+.Dv POSIX_SPAWN_SETSCHEDULER
+flag is set in the spawn-flags attribute of the object referenced by
+.Fa attrp
+(regardless of the setting of the
+.Dv POSIX_SPAWN_SETSCHEDPARAM
+flag), the new process image initially has the scheduling policy
+specified in the spawn-schedpolicy attribute of the object referenced by
+.Fa attrp
+and the scheduling parameters specified in the spawn-schedparam
+attribute of the same object.
+.Pp
+The
+.Dv POSIX_SPAWN_RESETIDS
+flag in the spawn-flags attribute of the object referenced by
+.Fa attrp
+governs the effective user ID of the child process.
+If this flag is not set, the child process inherits the parent
+process' effective user ID.
+If this flag is set, the child process' effective user ID is reset
+to the parent's real user ID.
+In either case, if the set-user-ID mode bit of the new process image
+file is set, the effective user ID of the child process becomes
+that file's owner ID before the new process image begins execution.
+.Pp
+The
+.Dv POSIX_SPAWN_RESETIDS
+flag in the spawn-flags attribute of the object referenced by
+.Fa attrp
+also governs the effective group ID of the child process.
+If this flag is not set, the child process inherits the parent
+process' effective group ID.
+If this flag is set, the child process' effective group ID is
+reset to the parent's real group ID.
+In either case, if the set-group-ID mode bit of the new process image
+file is set, the effective group ID of the child process becomes
+that file's group ID before the new process image begins execution.
+.Pp
+If the
+.Dv POSIX_SPAWN_SETSIGMASK
+flag is set in the spawn-flags attribute of the object referenced by
+.Fa attrp ,
+the child process initially has the signal mask specified in the
+spawn-sigmask attribute of the object referenced by
+.Fa attrp .
+.Pp
+If the
+.Dv POSIX_SPAWN_SETSIGDEF
+flag is set in the spawn-flags attribute of the object referenced by
+.Fa attrp ,
+the signals specified in the spawn-sigdefault attribute of the same
+object is set to their default actions in the child process.
+Signals set to the default action in the parent process is set to
+the default action in the child process.
+.Pp
+Signals set to be caught by the calling process is set to the
+default action in the child process.
+.Pp
+Signals set to be ignored by the calling process image is set to
+be ignored by the child process, unless otherwise specified by the
+.Dv POSIX_SPAWN_SETSIGDEF
+flag being set in the spawn-flags attribute of the object referenced by
+.Fa attrp
+and the signals being indicated in the spawn-sigdefault attribute
+of the object referenced by
+.Fa attrp .
+.Pp
+If the value of the
+.Fa attrp
+pointer is NULL, then the default values are used.
+.Pp
+All process attributes, other than those influenced by the attributes
+set in the object referenced by
+.Fa attrp
+as specified above or by the file descriptor manipulations specified in
+.Fa file_actions ,
+appear in the new process image as though
+.Fn vfork
+had been called to create a child process and then
+.Fn execve
+had been called by the child process to execute the new process image.
+.Pp
+The implementation uses vfork(), thus the fork handlers are not run when
+.Fn posix_spawn
+or
+.Fn posix_spawnp
+is called.
+.Sh RETURN VALUES
+Upon successful completion,
+.Fn posix_spawn
+and
+.Fn posix_spawnp
+return the process ID of the child process to the parent process,
+in the variable pointed to by a non-NULL
+.Fa pid
+argument, and return zero as the function return value.
+Otherwise, no child process is created, no value is stored into
+the variable pointed to by
+.Fa pid ,
+and an error number is returned as the function return value to
+indicate the error.
+If the
+.Fa pid
+argument is a null pointer, the process ID of the child is not returned
+to the caller.
+.Sh ERRORS
+.Bl -enum
+.It
+If
+.Fn posix_spawn
+and
+.Fn posix_spawnp
+fail for any of the reasons that would cause
+.Fn vfork
+or one of the
+.Nm exec
+to fail, an error value is returned as described by
+.Fn vfork
+and
+.Nm exec ,
+respectively (or, if the error occurs after the calling process successfully
+returns, the child process exits with exit status 127).
+.It
+If
+.Nm POSIX_SPAWN_SETPGROUP
+is set in the spawn-flags attribute of the object referenced by attrp, and
+.Fn posix_spawn
+or
+.Fn posix_spawnp
+fails while changing the child's process group, an error value is returned as
+described by
+.Fn setpgid
+(or, if the error occurs after the calling process successfully returns,
+the child process exits with exit status 127).
+.It
+If
+.Nm POSIX_SPAWN_SETSCHEDPARAM
+is set and
+.Nm POSIX_SPAWN_SETSCHEDULER
+is not set in the spawn-flags attribute of the object referenced by attrp, then
+if
+.Fn posix_spawn
+or
+.Fn posix_spawnp
+fails for any of the reasons that would cause
+.Fn sched_setparam
+to fail, an error value is returned as described by
+.Fn sched_setparam
+(or, if the error occurs after the calling process successfully returns, the
+child process exits with exit status 127).
+.It
+If
+.Nm POSIX_SPAWN_SETSCHEDULER
+is set in the spawn-flags attribute of the object referenced by attrp, and if
+.Fn posix_spawn
+or
+.Fn posix_spawnp
+fails for any of the reasons that would cause
+.Fn sched_setscheduler
+to fail, an error value is returned as described by
+.Fn sched_setscheduler
+(or, if the error occurs after the calling process successfully returns,
+the child process exits with exit status 127).
+.It
+If the
+.Fa file_actions
+argument is not NULL, and specifies any dup2 or open actions to be
+performed, and if
+.Fn posix_spawn
+or
+.Fn posix_spawnp
+fails for any of the reasons that would cause
+.Fn dup2
+or
+.Fn open
+to fail, an error value is returned as described by
+.Fn dup2
+and
+.Fn open ,
+respectively (or, if the error occurs after the calling process successfully
+returns, the child process exits with exit status 127). An open file action
+may, by itself, result in any of the errors described by
+.Fn dup2 ,
+in addition to those described by
+.Fn open .
+This implementation ignores any errors from
+.Fn close ,
+including trying to close a descriptor that is not open.
+.El
+.Sh SEE ALSO
+.Xr close 2 ,
+.Xr dup2 2 ,
+.Xr execve 2 ,
+.Xr fcntl 2 ,
+.Xr open 2 ,
+.Xr sched_setparam 2 ,
+.Xr sched_setscheduler 2 ,
+.Xr setpgid 2 ,
+.Xr vfork 2 ,
+.Xr posix_spawn_file_actions_addclose 3 ,
+.Xr posix_spawn_file_actions_adddup2 3 ,
+.Xr posix_spawn_file_actions_addopen 3 ,
+.Xr posix_spawn_file_actions_destroy 3 ,
+.Xr posix_spawn_file_actions_init 3 ,
+.Xr posix_spawnattr_destroy 3 ,
+.Xr posix_spawnattr_getflags 3 ,
+.Xr posix_spawnattr_getpgroup 3 ,
+.Xr posix_spawnattr_getschedparam 3 ,
+.Xr posix_spawnattr_getschedpolicy 3 ,
+.Xr posix_spawnattr_getsigdefault 3 ,
+.Xr posix_spawnattr_getsigmask 3 ,
+.Xr posix_spawnattr_init 3 ,
+.Xr posix_spawnattr_setflags 3 ,
+.Xr posix_spawnattr_setpgroup 3 ,
+.Xr posix_spawnattr_setschedparam 3 ,
+.Xr posix_spawnattr_setschedpolicy 3 ,
+.Xr posix_spawnattr_setsigdefault 3 ,
+.Xr posix_spawnattr_setsigmask 3
+.Sh STANDARDS
+The
+.Fn posix_spawn
+and
+.Fn posix_spawnp
+functions conform to
+.St -p1003.1-2001 ,
+except that they ignore all errors from
+.Fn close .
+A future update of the Standard is expected to require that these functions
+not fail because a file descriptor to be closed (via
+.Fn posix_spawn_file_actions_addclose )
+is not open.
+.Sh HISTORY
+The
+.Fn posix_spawn
+and
+.Fn posix_spawnp
+functions first appeared in
+.Fx 8.0 .
+.Sh AUTHORS
+.An \&Ed Schouten Aq Mt ed@FreeBSD.org
diff --git a/lib/libc/gen/posix_spawn.c b/lib/libc/gen/posix_spawn.c
new file mode 100644
index 000000000000..2838c5c0aacd
--- /dev/null
+++ b/lib/libc/gen/posix_spawn.c
@@ -0,0 +1,481 @@
+/*-
+ * Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/queue.h>
+#include <sys/wait.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sched.h>
+#include <spawn.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+
+extern char **environ;
+
+struct __posix_spawnattr {
+ short sa_flags;
+ pid_t sa_pgroup;
+ struct sched_param sa_schedparam;
+ int sa_schedpolicy;
+ sigset_t sa_sigdefault;
+ sigset_t sa_sigmask;
+};
+
+struct __posix_spawn_file_actions {
+ STAILQ_HEAD(, __posix_spawn_file_actions_entry) fa_list;
+};
+
+typedef struct __posix_spawn_file_actions_entry {
+ STAILQ_ENTRY(__posix_spawn_file_actions_entry) fae_list;
+ enum { FAE_OPEN, FAE_DUP2, FAE_CLOSE } fae_action;
+
+ int fae_fildes;
+ union {
+ struct {
+ char *path;
+#define fae_path fae_data.open.path
+ int oflag;
+#define fae_oflag fae_data.open.oflag
+ mode_t mode;
+#define fae_mode fae_data.open.mode
+ } open;
+ struct {
+ int newfildes;
+#define fae_newfildes fae_data.dup2.newfildes
+ } dup2;
+ } fae_data;
+} posix_spawn_file_actions_entry_t;
+
+/*
+ * Spawn routines
+ */
+
+static int
+process_spawnattr(const posix_spawnattr_t sa)
+{
+ struct sigaction sigact = { .sa_flags = 0, .sa_handler = SIG_DFL };
+ int i;
+
+ /*
+ * POSIX doesn't really describe in which order everything
+ * should be set. We'll just set them in the order in which they
+ * are mentioned.
+ */
+
+ /* Set process group */
+ if (sa->sa_flags & POSIX_SPAWN_SETPGROUP) {
+ if (setpgid(0, sa->sa_pgroup) != 0)
+ return (errno);
+ }
+
+ /* Set scheduler policy */
+ if (sa->sa_flags & POSIX_SPAWN_SETSCHEDULER) {
+ if (sched_setscheduler(0, sa->sa_schedpolicy,
+ &sa->sa_schedparam) != 0)
+ return (errno);
+ } else if (sa->sa_flags & POSIX_SPAWN_SETSCHEDPARAM) {
+ if (sched_setparam(0, &sa->sa_schedparam) != 0)
+ return (errno);
+ }
+
+ /* Reset user ID's */
+ if (sa->sa_flags & POSIX_SPAWN_RESETIDS) {
+ if (setegid(getgid()) != 0)
+ return (errno);
+ if (seteuid(getuid()) != 0)
+ return (errno);
+ }
+
+ /*
+ * Set signal masks/defaults.
+ * Use unwrapped syscall, libthr is in undefined state after vfork().
+ */
+ if (sa->sa_flags & POSIX_SPAWN_SETSIGMASK) {
+ __sys_sigprocmask(SIG_SETMASK, &sa->sa_sigmask, NULL);
+ }
+
+ if (sa->sa_flags & POSIX_SPAWN_SETSIGDEF) {
+ for (i = 1; i <= _SIG_MAXSIG; i++) {
+ if (sigismember(&sa->sa_sigdefault, i))
+ if (__sys_sigaction(i, &sigact, NULL) != 0)
+ return (errno);
+ }
+ }
+
+ return (0);
+}
+
+static int
+process_file_actions_entry(posix_spawn_file_actions_entry_t *fae)
+{
+ int fd, saved_errno;
+
+ switch (fae->fae_action) {
+ case FAE_OPEN:
+ /* Perform an open(), make it use the right fd */
+ fd = _open(fae->fae_path, fae->fae_oflag, fae->fae_mode);
+ if (fd < 0)
+ return (errno);
+ if (fd != fae->fae_fildes) {
+ if (_dup2(fd, fae->fae_fildes) == -1) {
+ saved_errno = errno;
+ (void)_close(fd);
+ return (saved_errno);
+ }
+ if (_close(fd) != 0) {
+ if (errno == EBADF)
+ return (EBADF);
+ }
+ }
+ if (_fcntl(fae->fae_fildes, F_SETFD, 0) == -1)
+ return (errno);
+ break;
+ case FAE_DUP2:
+ /* Perform a dup2() */
+ if (_dup2(fae->fae_fildes, fae->fae_newfildes) == -1)
+ return (errno);
+ if (_fcntl(fae->fae_newfildes, F_SETFD, 0) == -1)
+ return (errno);
+ break;
+ case FAE_CLOSE:
+ /* Perform a close(), do not fail if already closed */
+ (void)_close(fae->fae_fildes);
+ break;
+ }
+ return (0);
+}
+
+static int
+process_file_actions(const posix_spawn_file_actions_t fa)
+{
+ posix_spawn_file_actions_entry_t *fae;
+ int error;
+
+ /* Replay all file descriptor modifications */
+ STAILQ_FOREACH(fae, &fa->fa_list, fae_list) {
+ error = process_file_actions_entry(fae);
+ if (error)
+ return (error);
+ }
+ return (0);
+}
+
+static int
+do_posix_spawn(pid_t *pid, const char *path,
+ const posix_spawn_file_actions_t *fa,
+ const posix_spawnattr_t *sa,
+ char * const argv[], char * const envp[], int use_env_path)
+{
+ pid_t p;
+ volatile int error = 0;
+
+ p = vfork();
+ switch (p) {
+ case -1:
+ return (errno);
+ case 0:
+ if (sa != NULL) {
+ error = process_spawnattr(*sa);
+ if (error)
+ _exit(127);
+ }
+ if (fa != NULL) {
+ error = process_file_actions(*fa);
+ if (error)
+ _exit(127);
+ }
+ if (use_env_path)
+ _execvpe(path, argv, envp != NULL ? envp : environ);
+ else
+ _execve(path, argv, envp != NULL ? envp : environ);
+ error = errno;
+ _exit(127);
+ default:
+ if (error != 0)
+ _waitpid(p, NULL, WNOHANG);
+ else if (pid != NULL)
+ *pid = p;
+ return (error);
+ }
+}
+
+int
+posix_spawn(pid_t *pid, const char *path,
+ const posix_spawn_file_actions_t *fa,
+ const posix_spawnattr_t *sa,
+ char * const argv[], char * const envp[])
+{
+ return do_posix_spawn(pid, path, fa, sa, argv, envp, 0);
+}
+
+int
+posix_spawnp(pid_t *pid, const char *path,
+ const posix_spawn_file_actions_t *fa,
+ const posix_spawnattr_t *sa,
+ char * const argv[], char * const envp[])
+{
+ return do_posix_spawn(pid, path, fa, sa, argv, envp, 1);
+}
+
+/*
+ * File descriptor actions
+ */
+
+int
+posix_spawn_file_actions_init(posix_spawn_file_actions_t *ret)
+{
+ posix_spawn_file_actions_t fa;
+
+ fa = malloc(sizeof(struct __posix_spawn_file_actions));
+ if (fa == NULL)
+ return (-1);
+
+ STAILQ_INIT(&fa->fa_list);
+ *ret = fa;
+ return (0);
+}
+
+int
+posix_spawn_file_actions_destroy(posix_spawn_file_actions_t *fa)
+{
+ posix_spawn_file_actions_entry_t *fae;
+
+ while ((fae = STAILQ_FIRST(&(*fa)->fa_list)) != NULL) {
+ /* Remove file action entry from the queue */
+ STAILQ_REMOVE_HEAD(&(*fa)->fa_list, fae_list);
+
+ /* Deallocate file action entry */
+ if (fae->fae_action == FAE_OPEN)
+ free(fae->fae_path);
+ free(fae);
+ }
+
+ free(*fa);
+ return (0);
+}
+
+int
+posix_spawn_file_actions_addopen(posix_spawn_file_actions_t * __restrict fa,
+ int fildes, const char * __restrict path, int oflag, mode_t mode)
+{
+ posix_spawn_file_actions_entry_t *fae;
+ int error;
+
+ if (fildes < 0)
+ return (EBADF);
+
+ /* Allocate object */
+ fae = malloc(sizeof(posix_spawn_file_actions_entry_t));
+ if (fae == NULL)
+ return (errno);
+
+ /* Set values and store in queue */
+ fae->fae_action = FAE_OPEN;
+ fae->fae_path = strdup(path);
+ if (fae->fae_path == NULL) {
+ error = errno;
+ free(fae);
+ return (error);
+ }
+ fae->fae_fildes = fildes;
+ fae->fae_oflag = oflag;
+ fae->fae_mode = mode;
+
+ STAILQ_INSERT_TAIL(&(*fa)->fa_list, fae, fae_list);
+ return (0);
+}
+
+int
+posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t *fa,
+ int fildes, int newfildes)
+{
+ posix_spawn_file_actions_entry_t *fae;
+
+ if (fildes < 0 || newfildes < 0)
+ return (EBADF);
+
+ /* Allocate object */
+ fae = malloc(sizeof(posix_spawn_file_actions_entry_t));
+ if (fae == NULL)
+ return (errno);
+
+ /* Set values and store in queue */
+ fae->fae_action = FAE_DUP2;
+ fae->fae_fildes = fildes;
+ fae->fae_newfildes = newfildes;
+
+ STAILQ_INSERT_TAIL(&(*fa)->fa_list, fae, fae_list);
+ return (0);
+}
+
+int
+posix_spawn_file_actions_addclose(posix_spawn_file_actions_t *fa,
+ int fildes)
+{
+ posix_spawn_file_actions_entry_t *fae;
+
+ if (fildes < 0)
+ return (EBADF);
+
+ /* Allocate object */
+ fae = malloc(sizeof(posix_spawn_file_actions_entry_t));
+ if (fae == NULL)
+ return (errno);
+
+ /* Set values and store in queue */
+ fae->fae_action = FAE_CLOSE;
+ fae->fae_fildes = fildes;
+
+ STAILQ_INSERT_TAIL(&(*fa)->fa_list, fae, fae_list);
+ return (0);
+}
+
+/*
+ * Spawn attributes
+ */
+
+int
+posix_spawnattr_init(posix_spawnattr_t *ret)
+{
+ posix_spawnattr_t sa;
+
+ sa = calloc(1, sizeof(struct __posix_spawnattr));
+ if (sa == NULL)
+ return (errno);
+
+ /* Set defaults as specified by POSIX, cleared above */
+ *ret = sa;
+ return (0);
+}
+
+int
+posix_spawnattr_destroy(posix_spawnattr_t *sa)
+{
+ free(*sa);
+ return (0);
+}
+
+int
+posix_spawnattr_getflags(const posix_spawnattr_t * __restrict sa,
+ short * __restrict flags)
+{
+ *flags = (*sa)->sa_flags;
+ return (0);
+}
+
+int
+posix_spawnattr_getpgroup(const posix_spawnattr_t * __restrict sa,
+ pid_t * __restrict pgroup)
+{
+ *pgroup = (*sa)->sa_pgroup;
+ return (0);
+}
+
+int
+posix_spawnattr_getschedparam(const posix_spawnattr_t * __restrict sa,
+ struct sched_param * __restrict schedparam)
+{
+ *schedparam = (*sa)->sa_schedparam;
+ return (0);
+}
+
+int
+posix_spawnattr_getschedpolicy(const posix_spawnattr_t * __restrict sa,
+ int * __restrict schedpolicy)
+{
+ *schedpolicy = (*sa)->sa_schedpolicy;
+ return (0);
+}
+
+int
+posix_spawnattr_getsigdefault(const posix_spawnattr_t * __restrict sa,
+ sigset_t * __restrict sigdefault)
+{
+ *sigdefault = (*sa)->sa_sigdefault;
+ return (0);
+}
+
+int
+posix_spawnattr_getsigmask(const posix_spawnattr_t * __restrict sa,
+ sigset_t * __restrict sigmask)
+{
+ *sigmask = (*sa)->sa_sigmask;
+ return (0);
+}
+
+int
+posix_spawnattr_setflags(posix_spawnattr_t *sa, short flags)
+{
+ (*sa)->sa_flags = flags;
+ return (0);
+}
+
+int
+posix_spawnattr_setpgroup(posix_spawnattr_t *sa, pid_t pgroup)
+{
+ (*sa)->sa_pgroup = pgroup;
+ return (0);
+}
+
+int
+posix_spawnattr_setschedparam(posix_spawnattr_t * __restrict sa,
+ const struct sched_param * __restrict schedparam)
+{
+ (*sa)->sa_schedparam = *schedparam;
+ return (0);
+}
+
+int
+posix_spawnattr_setschedpolicy(posix_spawnattr_t *sa, int schedpolicy)
+{
+ (*sa)->sa_schedpolicy = schedpolicy;
+ return (0);
+}
+
+int
+posix_spawnattr_setsigdefault(posix_spawnattr_t * __restrict sa,
+ const sigset_t * __restrict sigdefault)
+{
+ (*sa)->sa_sigdefault = *sigdefault;
+ return (0);
+}
+
+int
+posix_spawnattr_setsigmask(posix_spawnattr_t * __restrict sa,
+ const sigset_t * __restrict sigmask)
+{
+ (*sa)->sa_sigmask = *sigmask;
+ return (0);
+}
diff --git a/lib/libc/gen/posix_spawn_file_actions_addopen.3 b/lib/libc/gen/posix_spawn_file_actions_addopen.3
new file mode 100644
index 000000000000..0b57999bf4be
--- /dev/null
+++ b/lib/libc/gen/posix_spawn_file_actions_addopen.3
@@ -0,0 +1,203 @@
+.\" Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" Portions of this text are reprinted and reproduced in electronic form
+.\" from IEEE Std 1003.1, 2004 Edition, Standard for Information Technology --
+.\" Portable Operating System Interface (POSIX), The Open Group Base
+.\" Specifications Issue 6, Copyright (C) 2001-2004 by the Institute of
+.\" Electrical and Electronics Engineers, Inc and The Open Group. In the
+.\" event of any discrepancy between this version and the original IEEE and
+.\" The Open Group Standard, the original IEEE and The Open Group Standard is
+.\" the referee document. The original Standard can be obtained online at
+.\" http://www.opengroup.org/unix/online.html.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd May 9, 2013
+.Dt POSIX_SPAWN_FILE_ACTIONS_ADDOPEN 3
+.Os
+.Sh NAME
+.Nm posix_spawn_file_actions_addopen ,
+.Nm posix_spawn_file_actions_adddup2 ,
+.Nm posix_spawn_file_actions_addclose
+.Nd "add open, dup2 or close action to spawn file actions object"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In spawn.h
+.Ft int
+.Fn posix_spawn_file_actions_addopen "posix_spawn_file_actions_t * file_actions" "int fildes" "const char *restrict path" "int oflag" "mode_t mode"
+.Ft int
+.Fn posix_spawn_file_actions_adddup2 "posix_spawn_file_actions_t * file_actions" "int fildes" "int newfildes"
+.Ft int
+.Fn posix_spawn_file_actions_addclose "posix_spawn_file_actions_t * file_actions" "int fildes"
+.Sh DESCRIPTION
+These functions add an open, dup2 or close action to a spawn
+file actions object.
+.Pp
+A spawn file actions object is of type
+.Vt posix_spawn_file_actions_t
+(defined in
+.In spawn.h )
+and is used to specify a series of actions to be performed by a
+.Fn posix_spawn
+or
+.Fn posix_spawnp
+operation in order to arrive at the set of open file descriptors for the
+child process given the set of open file descriptors of the parent.
+.Pp
+A spawn file actions object, when passed to
+.Fn posix_spawn
+or
+.Fn posix_spawnp ,
+specify how the set of open file descriptors in the calling
+process is transformed into a set of potentially open file descriptors
+for the spawned process.
+This transformation is as if the specified sequence of actions was
+performed exactly once, in the context of the spawned process (prior to
+execution of the new process image), in the order in which the actions
+were added to the object; additionally, when the new process image is
+executed, any file descriptor (from this new set) which has its
+.Dv FD_CLOEXEC
+flag set is closed (see
+.Fn posix_spawn ) .
+.Pp
+The
+.Fn posix_spawn_file_actions_addopen
+function adds an open action to the object referenced by
+.Fa file_actions
+that causes the file named by
+.Fa path
+to be opened (as if
+.Bd -literal -offset indent
+open(path, oflag, mode)
+.Ed
+.Pp
+had been called, and the returned file descriptor, if not
+.Fa fildes ,
+had been changed to
+.Fa fildes )
+when a new process is spawned using this file actions object.
+If
+.Fa fildes
+was already an open file descriptor, it is closed before the new
+file is opened.
+.Pp
+The string described by
+.Fa path
+is copied by the
+.Fn posix_spawn_file_actions_addopen
+function.
+.Pp
+The
+.Fn posix_spawn_file_actions_adddup2
+function adds a dup2 action to the object referenced by
+.Fa file_actions
+that causes the file descriptor
+.Fa fildes
+to be duplicated as
+.Fa newfildes
+(as if
+.Bd -literal -offset indent
+dup2(fildes, newfildes)
+.Ed
+.Pp
+had been called) when a new process is spawned using this file actions object,
+except that the
+.Dv FD_CLOEXEC
+flag for
+.Fa newfildes
+is cleared even if
+.Fa fildes
+is equal to
+.Fa newfildes .
+The difference from
+.Fn dup2
+is useful for passing a particular file descriptor
+to a particular child process.
+.Pp
+The
+.Fn posix_spawn_file_actions_addclose
+function adds a close action to the object referenced by
+.Fa file_actions
+that causes the file descriptor
+.Fa fildes
+to be closed (as if
+.Bd -literal -offset indent
+close(fildes)
+.Ed
+.Pp
+had been called) when a new process is spawned using this file actions
+object.
+.Sh RETURN VALUES
+Upon successful completion, these functions return zero;
+otherwise, an error number is returned to indicate the error.
+.Sh ERRORS
+These
+functions fail if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The value specified by
+.Fa fildes
+or
+.Fa newfildes
+is negative.
+.It Bq Er ENOMEM
+Insufficient memory exists to add to the spawn file actions object.
+.El
+.Sh SEE ALSO
+.Xr close 2 ,
+.Xr dup2 2 ,
+.Xr open 2 ,
+.Xr posix_spawn 3 ,
+.Xr posix_spawn_file_actions_destroy 3 ,
+.Xr posix_spawn_file_actions_init 3 ,
+.Xr posix_spawnp 3
+.Sh STANDARDS
+The
+.Fn posix_spawn_file_actions_addopen ,
+.Fn posix_spawn_file_actions_adddup2
+and
+.Fn posix_spawn_file_actions_addclose
+functions conform to
+.St -p1003.1-2001 ,
+with the exception of the behavior of
+.Fn posix_spawn_file_actions_adddup2
+if
+.Fa fildes
+is equal to
+.Fa newfildes
+(clearing
+.Dv FD_CLOEXEC ) .
+A future update of the Standard is expected to require this behavior.
+.Sh HISTORY
+The
+.Fn posix_spawn_file_actions_addopen ,
+.Fn posix_spawn_file_actions_adddup2
+and
+.Fn posix_spawn_file_actions_addclose
+functions first appeared in
+.Fx 8.0 .
+.Sh AUTHORS
+.An \&Ed Schouten Aq Mt ed@FreeBSD.org
diff --git a/lib/libc/gen/posix_spawn_file_actions_init.3 b/lib/libc/gen/posix_spawn_file_actions_init.3
new file mode 100644
index 000000000000..380eed769003
--- /dev/null
+++ b/lib/libc/gen/posix_spawn_file_actions_init.3
@@ -0,0 +1,104 @@
+.\" Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" Portions of this text are reprinted and reproduced in electronic form
+.\" from IEEE Std 1003.1, 2004 Edition, Standard for Information Technology --
+.\" Portable Operating System Interface (POSIX), The Open Group Base
+.\" Specifications Issue 6, Copyright (C) 2001-2004 by the Institute of
+.\" Electrical and Electronics Engineers, Inc and The Open Group. In the
+.\" event of any discrepancy between this version and the original IEEE and
+.\" The Open Group Standard, the original IEEE and The Open Group Standard is
+.\" the referee document. The original Standard can be obtained online at
+.\" http://www.opengroup.org/unix/online.html.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd March 24, 2008
+.Dt POSIX_SPAWN_FILE_ACTIONS_INIT 3
+.Os
+.Sh NAME
+.Nm posix_spawn_file_actions_init ,
+.Nm posix_spawn_file_actions_destroy
+.Nd "initialize and destroy spawn file actions object"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In spawn.h
+.Ft int
+.Fn posix_spawn_file_actions_init "posix_spawn_file_actions_t * file_actions"
+.Ft int
+.Fn posix_spawn_file_actions_destroy "posix_spawn_file_actions_t * file_actions"
+.Sh DESCRIPTION
+The
+.Fn posix_spawn_file_actions_init
+function initialize the object referenced by
+.Fn file_actions
+to contain no file actions for
+.Fn posix_spawn
+or
+.Fn posix_spawnp .
+Initializing an already initialized spawn file actions object may cause
+memory to be leaked.
+.Pp
+The
+.Fn posix_spawn_file_actions_destroy
+function destroy the object referenced by
+.Fa file_actions ;
+the object becomes, in effect, uninitialized.
+A destroyed spawn file actions object can be reinitialized using
+.Fn posix_spawn_file_actions_init .
+The object should not be used after it has been destroyed.
+.Sh RETURN VALUES
+Upon successful completion, these functions return zero;
+otherwise, an error number is returned to indicate the error.
+.Sh ERRORS
+The
+.Fn posix_spawn_file_actions_init
+function will fail if:
+.Bl -tag -width Er
+.It Bq Er ENOMEM
+Insufficient memory exists to initialize the spawn file actions object.
+.El
+.Sh SEE ALSO
+.Xr posix_spawn 3 ,
+.Xr posix_spawn_file_actions_addclose 3 ,
+.Xr posix_spawn_file_actions_adddup2 3 ,
+.Xr posix_spawn_file_actions_addopen 3 ,
+.Xr posix_spawnp 3
+.Sh STANDARDS
+The
+.Fn posix_spawn_file_actions_init
+and
+.Fn posix_spawn_file_actions_destroy
+functions conform to
+.St -p1003.1-2001 .
+.Sh HISTORY
+The
+.Fn posix_spawn_file_actions_init
+and
+.Fn posix_spawn_file_actions_destroy
+functions first appeared in
+.Fx 8.0 .
+.Sh AUTHORS
+.An \&Ed Schouten Aq Mt ed@FreeBSD.org
diff --git a/lib/libc/gen/posix_spawnattr_getflags.3 b/lib/libc/gen/posix_spawnattr_getflags.3
new file mode 100644
index 000000000000..2571f4ab307c
--- /dev/null
+++ b/lib/libc/gen/posix_spawnattr_getflags.3
@@ -0,0 +1,111 @@
+.\" Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" Portions of this text are reprinted and reproduced in electronic form
+.\" from IEEE Std 1003.1, 2004 Edition, Standard for Information Technology --
+.\" Portable Operating System Interface (POSIX), The Open Group Base
+.\" Specifications Issue 6, Copyright (C) 2001-2004 by the Institute of
+.\" Electrical and Electronics Engineers, Inc and The Open Group. In the
+.\" event of any discrepancy between this version and the original IEEE and
+.\" The Open Group Standard, the original IEEE and The Open Group Standard is
+.\" the referee document. The original Standard can be obtained online at
+.\" http://www.opengroup.org/unix/online.html.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd March 24, 2008
+.Dt POSIX_SPAWNATTR_GETFLAGS 3
+.Os
+.Sh NAME
+.Nm posix_spawnattr_getflags ,
+.Nm posix_spawnattr_setflags
+.Nd "get and set the spawn-flags attribute of a spawn attributes object"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In spawn.h
+.Ft int
+.Fn posix_spawnattr_getflags "const posix_spawnattr_t *restrict attr" "short *restrict flags"
+.Ft int
+.Fn posix_spawnattr_setflags "posix_spawnattr_t *attr" "short flags"
+.Sh DESCRIPTION
+The
+.Fn posix_spawnattr_getflags
+function obtains the value of the spawn-flags attribute from the
+attributes object referenced by
+.Fa attr .
+.Pp
+The
+.Fn posix_spawnattr_setflags
+function sets the spawn-flags attribute in an initialized
+attributes object referenced by
+.Fa attr .
+.Pp
+The spawn-flags attribute is used to indicate which process attributes
+are to be changed in the new process image when invoking
+.Fn posix_spawn
+or
+.Fn posix_spawnp .
+It is the bitwise-inclusive OR of zero or more of the following flags
+(see
+.Fn posix_spawn ) :
+.Bl -tag -width "POSIX_SPAWN_SETSCHEDPARAM" -offset indent
+.It Dv POSIX_SPAWN_RESETIDS
+.It Dv POSIX_SPAWN_SETPGROUP
+.It Dv POSIX_SPAWN_SETSIGDEF
+.It Dv POSIX_SPAWN_SETSIGMASK
+.It Dv POSIX_SPAWN_SETSCHEDPARAM
+.It Dv POSIX_SPAWN_SETSCHEDULER
+.El
+.Pp
+These flags are defined in
+.In spawn.h .
+The default value of this attribute is as if no flags were set.
+.Sh RETURN VALUES
+The
+.Fn posix_spawnattr_getflags
+and
+.Fn posix_spawnattr_setflags
+functions return zero.
+.Sh SEE ALSO
+.Xr posix_spawn 3 ,
+.Xr posix_spawnattr_destroy 3 ,
+.Xr posix_spawnattr_init 3 ,
+.Xr posix_spawnp 3
+.Sh STANDARDS
+The
+.Fn posix_spawnattr_getflags
+and
+.Fn posix_spawnattr_setflags
+functions conform to
+.St -p1003.1-2001 .
+.Sh HISTORY
+The
+.Fn posix_spawnattr_getflags
+and
+.Fn posix_spawnattr_setflags
+functions first appeared in
+.Fx 8.0 .
+.Sh AUTHORS
+.An \&Ed Schouten Aq Mt ed@FreeBSD.org
diff --git a/lib/libc/gen/posix_spawnattr_getpgroup.3 b/lib/libc/gen/posix_spawnattr_getpgroup.3
new file mode 100644
index 000000000000..cfc1b54ab633
--- /dev/null
+++ b/lib/libc/gen/posix_spawnattr_getpgroup.3
@@ -0,0 +1,96 @@
+.\" Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" Portions of this text are reprinted and reproduced in electronic form
+.\" from IEEE Std 1003.1, 2004 Edition, Standard for Information Technology --
+.\" Portable Operating System Interface (POSIX), The Open Group Base
+.\" Specifications Issue 6, Copyright (C) 2001-2004 by the Institute of
+.\" Electrical and Electronics Engineers, Inc and The Open Group. In the
+.\" event of any discrepancy between this version and the original IEEE and
+.\" The Open Group Standard, the original IEEE and The Open Group Standard is
+.\" the referee document. The original Standard can be obtained online at
+.\" http://www.opengroup.org/unix/online.html.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd March 24, 2008
+.Dt POSIX_SPAWNATTR_GETPGROUP 3
+.Os
+.Sh NAME
+.Nm posix_spawnattr_getpgroup ,
+.Nm posix_spawnattr_setpgroup
+.Nd "get and set the spawn-pgroup attribute of a spawn attributes object"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In spawn.h
+.Ft int
+.Fn posix_spawnattr_getpgroup "const posix_spawnattr_t *restrict attr" "pid_t *restrict pgroup"
+.Ft int
+.Fn posix_spawnattr_setpgroup "posix_spawnattr_t *attr" "pid_t pgroup"
+.Sh DESCRIPTION
+The
+.Fn posix_spawnattr_getpgroup
+function obtains the value of the spawn-pgroup attribute from the
+attributes object referenced by
+.Fa attr .
+.Pp
+The
+.Fn posix_spawnattr_setpgroup
+function sets the spawn-pgroup attribute in an initialized
+attributes object referenced by
+.Fa attr .
+.Pp
+The spawn-pgroup attribute represents the process group to be joined by
+the new process image in a spawn operation (if
+.Dv POSIX_SPAWN_SETPGROUP
+is set in the spawn-flags attribute).
+The default value of this attribute is zero.
+.Sh RETURN VALUES
+The
+.Fn posix_spawnattr_getpgroup
+and
+.Fn posix_spawnattr_setpgroup
+functions return zero.
+.Sh SEE ALSO
+.Xr posix_spawn 3 ,
+.Xr posix_spawnattr_destroy 3 ,
+.Xr posix_spawnattr_init 3 ,
+.Xr posix_spawnp 3
+.Sh STANDARDS
+The
+.Fn posix_spawnattr_getpgroup
+and
+.Fn posix_spawnattr_setpgroup
+functions conform to
+.St -p1003.1-2001 .
+.Sh HISTORY
+The
+.Fn posix_spawnattr_getpgroup
+and
+.Fn posix_spawnattr_setpgroup
+functions first appeared in
+.Fx 8.0 .
+.Sh AUTHORS
+.An \&Ed Schouten Aq Mt ed@FreeBSD.org
diff --git a/lib/libc/gen/posix_spawnattr_getschedparam.3 b/lib/libc/gen/posix_spawnattr_getschedparam.3
new file mode 100644
index 000000000000..5eef96ea825d
--- /dev/null
+++ b/lib/libc/gen/posix_spawnattr_getschedparam.3
@@ -0,0 +1,100 @@
+.\" Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" Portions of this text are reprinted and reproduced in electronic form
+.\" from IEEE Std 1003.1, 2004 Edition, Standard for Information Technology --
+.\" Portable Operating System Interface (POSIX), The Open Group Base
+.\" Specifications Issue 6, Copyright (C) 2001-2004 by the Institute of
+.\" Electrical and Electronics Engineers, Inc and The Open Group. In the
+.\" event of any discrepancy between this version and the original IEEE and
+.\" The Open Group Standard, the original IEEE and The Open Group Standard is
+.\" the referee document. The original Standard can be obtained online at
+.\" http://www.opengroup.org/unix/online.html.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd March 24, 2008
+.Dt POSIX_SPAWNATTR_GETSCHEDPARAM 3
+.Os
+.Sh NAME
+.Nm posix_spawnattr_getschedparam ,
+.Nm posix_spawnattr_setschedparam
+.Nd "get and set the spawn-schedparam attribute of a spawn attributes object"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In spawn.h
+.Ft int
+.Fn posix_spawnattr_getschedparam "const posix_spawnattr_t *restrict attr" "struct sched_param *restrict schedparam"
+.Ft int
+.Fn posix_spawnattr_setschedparam "posix_spawnattr_t *attr" "const struct sched_param *restrict schedparam"
+.Sh DESCRIPTION
+The
+.Fn posix_spawnattr_getschedparam
+function obtains the value of the spawn-schedparam attribute from the
+attributes object referenced by
+.Fa attr .
+.Pp
+The
+.Fn posix_spawnattr_setschedparam
+function sets the spawn-schedparam attribute in an initialized attributes
+object referenced by
+.Fa attr .
+.Pp
+The spawn-schedparam attribute represents the scheduling parameters to
+be assigned to the new process image in a spawn operation (if
+.Dv POSIX_SPAWN_SETSCHEDULER
+or
+.Dv POSIX_SPAWN_SETSCHEDPARAM
+is set in the spawn-flags attribute).
+The default value of this attribute is unspecified.
+.Sh RETURN VALUES
+The
+.Fn posix_spawnattr_getschedparam
+and
+.Fn posix_spawnattr_setschedparam
+functions return zero.
+.Sh SEE ALSO
+.Xr posix_spawn 3 ,
+.Xr posix_spawnattr_destroy 3 ,
+.Xr posix_spawnattr_getschedpolicy 3 ,
+.Xr posix_spawnattr_init 3 ,
+.Xr posix_spawnattr_setschedpolicy 3 ,
+.Xr posix_spawnp 3
+.Sh STANDARDS
+The
+.Fn posix_spawnattr_getschedparam
+and
+.Fn posix_spawnattr_setschedparam
+functions conform to
+.St -p1003.1-2001 .
+.Sh HISTORY
+The
+.Fn posix_spawnattr_getschedparam
+and
+.Fn posix_spawnattr_setschedparam
+functions first appeared in
+.Fx 8.0 .
+.Sh AUTHORS
+.An \&Ed Schouten Aq Mt ed@FreeBSD.org
diff --git a/lib/libc/gen/posix_spawnattr_getschedpolicy.3 b/lib/libc/gen/posix_spawnattr_getschedpolicy.3
new file mode 100644
index 000000000000..5276de5a2f35
--- /dev/null
+++ b/lib/libc/gen/posix_spawnattr_getschedpolicy.3
@@ -0,0 +1,98 @@
+.\" Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" Portions of this text are reprinted and reproduced in electronic form
+.\" from IEEE Std 1003.1, 2004 Edition, Standard for Information Technology --
+.\" Portable Operating System Interface (POSIX), The Open Group Base
+.\" Specifications Issue 6, Copyright (C) 2001-2004 by the Institute of
+.\" Electrical and Electronics Engineers, Inc and The Open Group. In the
+.\" event of any discrepancy between this version and the original IEEE and
+.\" The Open Group Standard, the original IEEE and The Open Group Standard is
+.\" the referee document. The original Standard can be obtained online at
+.\" http://www.opengroup.org/unix/online.html.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd March 24, 2008
+.Dt POSIX_SPAWNATTR_GETSCHEDPOLICY 3
+.Os
+.Sh NAME
+.Nm posix_spawnattr_getschedpolicy ,
+.Nm posix_spawnattr_setschedpolicy
+.Nd "get and set the spawn-schedpolicy attribute of a spawn attributes object"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In spawn.h
+.Ft int
+.Fn posix_spawnattr_getschedpolicy "const posix_spawnattr_t *restrict attr" "int *restrict schedpolicy"
+.Ft int
+.Fn posix_spawnattr_setschedpolicy "posix_spawnattr_t *attr" "int schedpolicy"
+.Sh DESCRIPTION
+The
+.Fn posix_spawnattr_getschedpolicy
+function obtains the value of the spawn-schedpolicy attribute from the
+attributes object referenced by
+.Fa attr .
+.Pp
+The
+.Fn posix_spawnattr_setschedpolicy
+function sets the spawn-schedpolicy attribute in an initialized attributes
+object referenced by
+.Fa attr .
+.Pp
+The spawn-schedpolicy attribute represents the scheduling policy to
+be assigned to the new process image in a spawn operation (if
+.Dv POSIX_SPAWN_SETSCHEDULER
+is set in the spawn-flags attribute).
+The default value of this attribute is unspecified.
+.Sh RETURN VALUES
+The
+.Fn posix_spawnattr_getschedpolicy
+and
+.Fn posix_spawnattr_setschedpolicy
+functions return zero.
+.Sh SEE ALSO
+.Xr posix_spawn 3 ,
+.Xr posix_spawnattr_destroy 3 ,
+.Xr posix_spawnattr_getschedparam 3 ,
+.Xr posix_spawnattr_init 3 ,
+.Xr posix_spawnattr_setschedparam 3 ,
+.Xr posix_spawnp 3
+.Sh STANDARDS
+The
+.Fn posix_spawnattr_getschedpolicy
+and
+.Fn posix_spawnattr_setschedpolicy
+functions conform to
+.St -p1003.1-2001 .
+.Sh HISTORY
+The
+.Fn posix_spawnattr_getschedpolicy
+and
+.Fn posix_spawnattr_setschedpolicy
+functions first appeared in
+.Fx 8.0 .
+.Sh AUTHORS
+.An \&Ed Schouten Aq Mt ed@FreeBSD.org
diff --git a/lib/libc/gen/posix_spawnattr_getsigdefault.3 b/lib/libc/gen/posix_spawnattr_getsigdefault.3
new file mode 100644
index 000000000000..a81c71417449
--- /dev/null
+++ b/lib/libc/gen/posix_spawnattr_getsigdefault.3
@@ -0,0 +1,98 @@
+.\" Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" Portions of this text are reprinted and reproduced in electronic form
+.\" from IEEE Std 1003.1, 2004 Edition, Standard for Information Technology --
+.\" Portable Operating System Interface (POSIX), The Open Group Base
+.\" Specifications Issue 6, Copyright (C) 2001-2004 by the Institute of
+.\" Electrical and Electronics Engineers, Inc and The Open Group. In the
+.\" event of any discrepancy between this version and the original IEEE and
+.\" The Open Group Standard, the original IEEE and The Open Group Standard is
+.\" the referee document. The original Standard can be obtained online at
+.\" http://www.opengroup.org/unix/online.html.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd March 24, 2008
+.Dt POSIX_SPAWNATTR_GETSIGDEFAULT 3
+.Os
+.Sh NAME
+.Nm posix_spawnattr_getsigdefault ,
+.Nm posix_spawnattr_setsigdefault
+.Nd "get and set the spawn-sigdefault attribute of a spawn attributes object"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In spawn.h
+.Ft int
+.Fn posix_spawnattr_getsigdefault "const posix_spawnattr_t *restrict attr" "sigset_t *restrict sigdefault"
+.Ft int
+.Fn posix_spawnattr_setsigdefault "posix_spawnattr_t *attr" "const sigset_t *restrict sigdefault"
+.Sh DESCRIPTION
+The
+.Fn posix_spawnattr_getsigdefault
+function obtains the value of the spawn-sigdefault attribute from the
+attributes object referenced by
+.Fa attr .
+.Pp
+The
+.Fn posix_spawnattr_setsigdefault
+function sets the spawn-sigdefault attribute in an initialized attributes
+object referenced by
+.Fa attr .
+.Pp
+The spawn-sigdefault attribute represents the set of signals to be forced to
+default signal handling in the new process image (if
+.Dv POSIX_SPAWN_SETSIGDEF
+is set in the spawn-flags attribute) by a spawn operation.
+The default value of this attribute is an empty signal set.
+.Sh RETURN VALUES
+The
+.Fn posix_spawnattr_getsigdefault
+and
+.Fn posix_spawnattr_setsigdefault
+functions return zero.
+.Sh SEE ALSO
+.Xr posix_spawn 3 ,
+.Xr posix_spawnattr_destroy 3 ,
+.Xr posix_spawnattr_getsigmask 3 ,
+.Xr posix_spawnattr_init 3 ,
+.Xr posix_spawnattr_setsigmask 3 ,
+.Xr posix_spawnp 3
+.Sh STANDARDS
+The
+.Fn posix_spawnattr_getsigdefault
+and
+.Fn posix_spawnattr_setsigdefault
+functions conform to
+.St -p1003.1-2001 .
+.Sh HISTORY
+The
+.Fn posix_spawnattr_getsigdefault
+and
+.Fn posix_spawnattr_setsigdefault
+functions first appeared in
+.Fx 8.0 .
+.Sh AUTHORS
+.An \&Ed Schouten Aq Mt ed@FreeBSD.org
diff --git a/lib/libc/gen/posix_spawnattr_getsigmask.3 b/lib/libc/gen/posix_spawnattr_getsigmask.3
new file mode 100644
index 000000000000..be15d9d47d82
--- /dev/null
+++ b/lib/libc/gen/posix_spawnattr_getsigmask.3
@@ -0,0 +1,98 @@
+.\" Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" Portions of this text are reprinted and reproduced in electronic form
+.\" from IEEE Std 1003.1, 2004 Edition, Standard for Information Technology --
+.\" Portable Operating System Interface (POSIX), The Open Group Base
+.\" Specifications Issue 6, Copyright (C) 2001-2004 by the Institute of
+.\" Electrical and Electronics Engineers, Inc and The Open Group. In the
+.\" event of any discrepancy between this version and the original IEEE and
+.\" The Open Group Standard, the original IEEE and The Open Group Standard is
+.\" the referee document. The original Standard can be obtained online at
+.\" http://www.opengroup.org/unix/online.html.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd March 24, 2008
+.Dt POSIX_SPAWNATTR_GETSIGMASK 3
+.Os
+.Sh NAME
+.Nm posix_spawnattr_getsigmask ,
+.Nm posix_spawnattr_setsigmask
+.Nd "get and set the spawn-sigmask attribute of a spawn attributes object"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In spawn.h
+.Ft int
+.Fn posix_spawnattr_getsigmask "const posix_spawnattr_t *restrict attr" "sigset_t *restrict sigmask"
+.Ft int
+.Fn posix_spawnattr_setsigmask "posix_spawnattr_t *attr" "const sigset_t *restrict sigmask"
+.Sh DESCRIPTION
+The
+.Fn posix_spawnattr_getsigmask
+function obtains the value of the spawn-sigmask attribute from the
+attributes object referenced by
+.Fa attr .
+.Pp
+The
+.Fn posix_spawnattr_setsigmask
+function sets the spawn-sigmask attribute in an initialized attributes
+object referenced by
+.Fa attr .
+.Pp
+The spawn-sigmask attribute represents the signal mask in effect in the
+new process image of a spawn operation (if
+.Dv POSIX_SPAWN_SETSIGMASK
+is set in the spawn-flags attribute).
+The default value of this attribute is unspecified.
+.Sh RETURN VALUES
+The
+.Fn posix_spawnattr_getsigmask
+and
+.Fn posix_spawnattr_setsigmask
+functions return zero.
+.Sh SEE ALSO
+.Xr posix_spawn 3 ,
+.Xr posix_spawnattr_destroy 3 ,
+.Xr posix_spawnattr_getsigmask 3 ,
+.Xr posix_spawnattr_init 3 ,
+.Xr posix_spawnattr_setsigmask 3 ,
+.Xr posix_spawnp 3
+.Sh STANDARDS
+The
+.Fn posix_spawnattr_getsigmask
+and
+.Fn posix_spawnattr_setsigmask
+functions conform to
+.St -p1003.1-2001 .
+.Sh HISTORY
+The
+.Fn posix_spawnattr_getsigmask
+and
+.Fn posix_spawnattr_setsigmask
+functions first appeared in
+.Fx 8.0 .
+.Sh AUTHORS
+.An \&Ed Schouten Aq Mt ed@FreeBSD.org
diff --git a/lib/libc/gen/posix_spawnattr_init.3 b/lib/libc/gen/posix_spawnattr_init.3
new file mode 100644
index 000000000000..b4ec52c30e25
--- /dev/null
+++ b/lib/libc/gen/posix_spawnattr_init.3
@@ -0,0 +1,123 @@
+.\" Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" Portions of this text are reprinted and reproduced in electronic form
+.\" from IEEE Std 1003.1, 2004 Edition, Standard for Information Technology --
+.\" Portable Operating System Interface (POSIX), The Open Group Base
+.\" Specifications Issue 6, Copyright (C) 2001-2004 by the Institute of
+.\" Electrical and Electronics Engineers, Inc and The Open Group. In the
+.\" event of any discrepancy between this version and the original IEEE and
+.\" The Open Group Standard, the original IEEE and The Open Group Standard is
+.\" the referee document. The original Standard can be obtained online at
+.\" http://www.opengroup.org/unix/online.html.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd March 24, 2008
+.Dt POSIX_SPAWNATTR_INIT 3
+.Os
+.Sh NAME
+.Nm posix_spawnattr_init ,
+.Nm posix_spawnattr_destroy
+.Nd "initialize and destroy spawn attributes object"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In spawn.h
+.Ft int
+.Fn posix_spawnattr_init "posix_spawnattr_t * attr"
+.Ft int
+.Fn posix_spawnattr_destroy "posix_spawnattr_t * attr"
+.Sh DESCRIPTION
+The
+.Fn posix_spawnattr_init
+function initializes a spawn attributes object
+.Fa attr
+with the default value for all of the individual attributes used by the
+implementation.
+Initializing an already initialized spawn attributes object may cause
+memory to be leaked.
+.Pp
+The
+.Fn posix_spawnattr_destroy
+function destroys a spawn attributes object.
+A destroyed
+.Fa attr
+attributes object can be reinitialized using
+.Fn posix_spawnattr_init .
+The object should not be used after it has been destroyed.
+.Pp
+A spawn attributes object is of type
+.Vt posix_spawnattr_t
+(defined in
+.In spawn.h )
+and is used to specify the inheritance of process attributes across a
+spawn operation.
+.Pp
+The resulting spawn attributes object (possibly modified by setting
+individual attribute values), is used to modify the behavior of
+.Fn posix_spawn
+or
+.Fn posix_spawnp .
+After a spawn attributes object has been used to spawn a process by a
+call to a
+.Fn posix_spawn
+or
+.Fn posix_spawnp ,
+any function affecting the attributes object (including destruction)
+will not affect any process that has been spawned in this way.
+.Sh RETURN VALUES
+Upon successful completion,
+.Fn posix_spawnattr_init
+and
+.Fn posix_spawnattr_destroy
+return zero;
+otherwise, an error number is returned to indicate the error.
+.Sh ERRORS
+The
+.Fn posix_spawnattr_init
+function will fail if:
+.Bl -tag -width Er
+.It Bq Er ENOMEM
+Insufficient memory exists to initialize the spawn attributes object.
+.El
+.Sh SEE ALSO
+.Xr posix_spawn 3 ,
+.Xr posix_spawnp 3
+.Sh STANDARDS
+The
+.Fn posix_spawnattr_init
+and
+.Fn posix_spawnattr_destroy
+functions conform to
+.St -p1003.1-2001 .
+.Sh HISTORY
+The
+.Fn posix_spawnattr_init
+and
+.Fn posix_spawnattr_destroy
+functions first appeared in
+.Fx 8.0 .
+.Sh AUTHORS
+.An \&Ed Schouten Aq Mt ed@FreeBSD.org
diff --git a/lib/libc/gen/psignal.3 b/lib/libc/gen/psignal.3
new file mode 100644
index 000000000000..ed7023b7a3f1
--- /dev/null
+++ b/lib/libc/gen/psignal.3
@@ -0,0 +1,109 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)psignal.3 8.2 (Berkeley) 2/27/95
+.\" $FreeBSD$
+.\"
+.Dd May 30, 2016
+.Dt PSIGNAL 3
+.Os
+.Sh NAME
+.Nm psignal ,
+.Nm strsignal ,
+.Nm sys_siglist ,
+.Nm sys_signame
+.Nd system signal messages
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In signal.h
+.Ft void
+.Fn psignal "int sig" "const char *s"
+.Vt extern const char * const sys_siglist[] ;
+.Vt extern const char * const sys_signame[] ;
+.In string.h
+.Ft "char *"
+.Fn strsignal "int sig"
+.Sh DESCRIPTION
+The
+.Fn psignal
+and
+.Fn strsignal
+functions locate the descriptive message
+string for a signal number.
+.Pp
+The
+.Fn strsignal
+function accepts a signal number argument
+.Fa sig
+and returns a pointer to the corresponding message string.
+.Pp
+The
+.Fn psignal
+function accepts a signal number argument
+.Fa sig
+and writes it to the standard error.
+If the argument
+.Fa s
+is
+.Pf non- Dv NULL
+and does not point to the null character,
+.Fa s
+is written to the standard error file descriptor
+prior to the message string,
+immediately followed by a colon and a space.
+If the signal number is not recognized
+.Pq Xr sigaction 2 ,
+the string
+.Dq "Unknown signal"
+is produced.
+.Pp
+The message strings can be accessed directly
+through the external array
+.Va sys_siglist ,
+indexed by recognized signal numbers.
+The external array
+.Va sys_signame
+is used similarly and
+contains short, upper-case abbreviations for signals
+which are useful for recognizing signal names
+in user input.
+The defined variable
+.Dv NSIG
+contains a count of the strings in
+.Va sys_siglist
+and
+.Va sys_signame .
+.Sh SEE ALSO
+.Xr sigaction 2 ,
+.Xr perror 3 ,
+.Xr strerror 3
+.Sh HISTORY
+The
+.Fn psignal
+function appeared in
+.Bx 4.2 .
diff --git a/lib/libc/gen/psignal.c b/lib/libc/gen/psignal.c
new file mode 100644
index 000000000000..d1c70c600643
--- /dev/null
+++ b/lib/libc/gen/psignal.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)psignal.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Print the name of the signal indicated
+ * along with the supplied message.
+ */
+#include "namespace.h"
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+void
+psignal(int sig, const char *s)
+{
+ const char *c;
+
+ if (sig >= 0 && sig < NSIG)
+ c = sys_siglist[sig];
+ else
+ c = "Unknown signal";
+ if (s != NULL && *s != '\0') {
+ (void)_write(STDERR_FILENO, s, strlen(s));
+ (void)_write(STDERR_FILENO, ": ", 2);
+ }
+ (void)_write(STDERR_FILENO, c, strlen(c));
+ (void)_write(STDERR_FILENO, "\n", 1);
+}
diff --git a/lib/libc/gen/pututxline.c b/lib/libc/gen/pututxline.c
new file mode 100644
index 000000000000..4982c0276fbf
--- /dev/null
+++ b/lib/libc/gen/pututxline.c
@@ -0,0 +1,335 @@
+/*-
+ * Copyright (c) 2010 Ed Schouten <ed@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/endian.h>
+#include <sys/stat.h>
+#include <sys/uio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <utmpx.h>
+#include "utxdb.h"
+#include "un-namespace.h"
+
+static FILE *
+futx_open(const char *file)
+{
+ FILE *fp;
+ struct stat sb;
+ int fd;
+
+ fd = _open(file, O_CREAT|O_RDWR|O_EXLOCK|O_CLOEXEC, 0644);
+ if (fd < 0)
+ return (NULL);
+
+ /* Safety check: never use broken files. */
+ if (_fstat(fd, &sb) != -1 && sb.st_size % sizeof(struct futx) != 0) {
+ _close(fd);
+ errno = EFTYPE;
+ return (NULL);
+ }
+
+ fp = fdopen(fd, "r+");
+ if (fp == NULL) {
+ _close(fd);
+ return (NULL);
+ }
+ return (fp);
+}
+
+static int
+utx_active_add(const struct futx *fu)
+{
+ FILE *fp;
+ struct futx fe;
+ off_t partial;
+ int error, ret;
+
+ partial = -1;
+ ret = 0;
+
+ /*
+ * Register user login sessions. Overwrite entries of sessions
+ * that have already been terminated.
+ */
+ fp = futx_open(_PATH_UTX_ACTIVE);
+ if (fp == NULL)
+ return (-1);
+ while (fread(&fe, sizeof(fe), 1, fp) == 1) {
+ switch (fe.fu_type) {
+ case BOOT_TIME:
+ /* Leave these intact. */
+ break;
+ case USER_PROCESS:
+ case INIT_PROCESS:
+ case LOGIN_PROCESS:
+ case DEAD_PROCESS:
+ /* Overwrite when ut_id matches. */
+ if (memcmp(fu->fu_id, fe.fu_id, sizeof(fe.fu_id)) ==
+ 0) {
+ ret = fseeko(fp, -(off_t)sizeof(fe), SEEK_CUR);
+ goto exact;
+ }
+ if (fe.fu_type != DEAD_PROCESS)
+ break;
+ /* FALLTHROUGH */
+ default:
+ /* Allow us to overwrite unused records. */
+ if (partial == -1) {
+ partial = ftello(fp);
+ /*
+ * Distinguish errors from valid values so we
+ * don't overwrite good data by accident.
+ */
+ if (partial != -1)
+ partial -= (off_t)sizeof(fe);
+ }
+ break;
+ }
+ }
+
+ /*
+ * No exact match found. Use the partial match. If no partial
+ * match was found, just append a new record.
+ */
+ if (partial != -1)
+ ret = fseeko(fp, partial, SEEK_SET);
+exact:
+ if (ret == -1)
+ error = errno;
+ else if (fwrite(fu, sizeof(*fu), 1, fp) < 1)
+ error = errno;
+ else
+ error = 0;
+ fclose(fp);
+ if (error != 0)
+ errno = error;
+ return (error == 0 ? 0 : 1);
+}
+
+static int
+utx_active_remove(struct futx *fu)
+{
+ FILE *fp;
+ struct futx fe;
+ int error, ret;
+
+ /*
+ * Remove user login sessions, having the same ut_id.
+ */
+ fp = futx_open(_PATH_UTX_ACTIVE);
+ if (fp == NULL)
+ return (-1);
+ error = ESRCH;
+ ret = -1;
+ while (fread(&fe, sizeof(fe), 1, fp) == 1 && ret != 0)
+ switch (fe.fu_type) {
+ case USER_PROCESS:
+ case INIT_PROCESS:
+ case LOGIN_PROCESS:
+ if (memcmp(fu->fu_id, fe.fu_id, sizeof(fe.fu_id)) != 0)
+ continue;
+
+ /* Terminate session. */
+ if (fseeko(fp, -(off_t)sizeof(fe), SEEK_CUR) == -1)
+ error = errno;
+ else if (fwrite(fu, sizeof(*fu), 1, fp) < 1)
+ error = errno;
+ else
+ ret = 0;
+
+ }
+
+ fclose(fp);
+ if (ret != 0)
+ errno = error;
+ return (ret);
+}
+
+static void
+utx_active_init(const struct futx *fu)
+{
+ int fd;
+
+ /* Initialize utx.active with a single BOOT_TIME record. */
+ fd = _open(_PATH_UTX_ACTIVE, O_CREAT|O_RDWR|O_TRUNC, 0644);
+ if (fd < 0)
+ return;
+ _write(fd, fu, sizeof(*fu));
+ _close(fd);
+}
+
+static void
+utx_active_purge(void)
+{
+
+ truncate(_PATH_UTX_ACTIVE, 0);
+}
+
+static int
+utx_lastlogin_add(const struct futx *fu)
+{
+ struct futx fe;
+ FILE *fp;
+ int error, ret;
+
+ ret = 0;
+
+ /*
+ * Write an entry to lastlogin. Overwrite the entry if the
+ * current user already has an entry. If not, append a new
+ * entry.
+ */
+ fp = futx_open(_PATH_UTX_LASTLOGIN);
+ if (fp == NULL)
+ return (-1);
+ while (fread(&fe, sizeof fe, 1, fp) == 1) {
+ if (strncmp(fu->fu_user, fe.fu_user, sizeof fe.fu_user) != 0)
+ continue;
+
+ /* Found a previous lastlogin entry for this user. */
+ ret = fseeko(fp, -(off_t)sizeof fe, SEEK_CUR);
+ break;
+ }
+ if (ret == -1)
+ error = errno;
+ else if (fwrite(fu, sizeof *fu, 1, fp) < 1) {
+ error = errno;
+ ret = -1;
+ }
+ fclose(fp);
+ if (ret == -1)
+ errno = error;
+ return (ret);
+}
+
+static void
+utx_lastlogin_upgrade(void)
+{
+ struct stat sb;
+ int fd;
+
+ fd = _open(_PATH_UTX_LASTLOGIN, O_RDWR|O_CLOEXEC, 0644);
+ if (fd < 0)
+ return;
+
+ /*
+ * Truncate broken lastlogin files. In the future we should
+ * check for older versions of the file format here and try to
+ * upgrade it.
+ */
+ if (_fstat(fd, &sb) != -1 && sb.st_size % sizeof(struct futx) != 0)
+ ftruncate(fd, 0);
+ _close(fd);
+}
+
+static int
+utx_log_add(const struct futx *fu)
+{
+ struct iovec vec[2];
+ int error, fd;
+ uint16_t l;
+
+ /*
+ * Append an entry to the log file. We only need to append
+ * records to this file, so to conserve space, trim any trailing
+ * zero-bytes. Prepend a length field, indicating the length of
+ * the record, excluding the length field itself.
+ */
+ for (l = sizeof(*fu); l > 0 && ((const char *)fu)[l - 1] == '\0'; l--) ;
+ vec[0].iov_base = &l;
+ vec[0].iov_len = sizeof(l);
+ vec[1].iov_base = __DECONST(void *, fu);
+ vec[1].iov_len = l;
+ l = htobe16(l);
+
+ fd = _open(_PATH_UTX_LOG, O_CREAT|O_WRONLY|O_APPEND|O_CLOEXEC, 0644);
+ if (fd < 0)
+ return (-1);
+ if (_writev(fd, vec, 2) == -1)
+ error = errno;
+ else
+ error = 0;
+ _close(fd);
+ if (error != 0)
+ errno = error;
+ return (error == 0 ? 0 : 1);
+}
+
+struct utmpx *
+pututxline(const struct utmpx *utmpx)
+{
+ struct futx fu;
+ int bad;
+
+ bad = 0;
+
+ utx_to_futx(utmpx, &fu);
+
+ switch (fu.fu_type) {
+ case BOOT_TIME:
+ utx_active_init(&fu);
+ utx_lastlogin_upgrade();
+ break;
+ case SHUTDOWN_TIME:
+ utx_active_purge();
+ break;
+ case OLD_TIME:
+ case NEW_TIME:
+ break;
+ case USER_PROCESS:
+ bad |= utx_active_add(&fu);
+ bad |= utx_lastlogin_add(&fu);
+ break;
+#if 0 /* XXX: Are these records of any use to us? */
+ case INIT_PROCESS:
+ case LOGIN_PROCESS:
+ bad |= utx_active_add(&fu);
+ break;
+#endif
+ case DEAD_PROCESS:
+ /*
+ * In case writing a logout entry fails, never attempt
+ * to write it to utx.log. The logout entry's ut_id
+ * might be invalid.
+ */
+ if (utx_active_remove(&fu) != 0)
+ return (NULL);
+ break;
+ default:
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ bad |= utx_log_add(&fu);
+ return (bad ? NULL : futx_to_utx(&fu));
+}
diff --git a/lib/libc/gen/pw_scan.c b/lib/libc/gen/pw_scan.c
new file mode 100644
index 000000000000..24e822597bfd
--- /dev/null
+++ b/lib/libc/gen/pw_scan.c
@@ -0,0 +1,212 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)pw_scan.c 8.3 (Berkeley) 4/2/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * This module is used to "verify" password entries by chpass(1) and
+ * pwd_mkdb(8).
+ */
+
+#include <sys/param.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "pw_scan.h"
+
+/*
+ * Some software assumes that IDs are short. We should emit warnings
+ * for id's which cannot be stored in a short, but we are more liberal
+ * by default, warning for IDs greater than USHRT_MAX.
+ *
+ * If pw_big_ids_warning is -1 on entry to pw_scan(), it will be set based
+ * on the existence of PW_SCAN_BIG_IDS in the environment.
+ *
+ * It is believed all baseline system software that can not handle the
+ * normal ID sizes is now gone so pw_big_ids_warning is disabled for now.
+ * But the code has been left in place in case end-users want to re-enable
+ * it and/or for the next time the ID sizes get bigger but pieces of the
+ * system lag behind.
+ */
+static int pw_big_ids_warning = 0;
+
+int
+__pw_scan(char *bp, struct passwd *pw, int flags)
+{
+ uid_t id;
+ int root;
+ char *ep, *p, *sh;
+ unsigned long temp;
+
+ if (pw_big_ids_warning == -1)
+ pw_big_ids_warning = getenv("PW_SCAN_BIG_IDS") == NULL ? 1 : 0;
+
+ pw->pw_fields = 0;
+ if (!(pw->pw_name = strsep(&bp, ":"))) /* login */
+ goto fmt;
+ root = !strcmp(pw->pw_name, "root");
+ if (pw->pw_name[0] && (pw->pw_name[0] != '+' || pw->pw_name[1] == '\0'))
+ pw->pw_fields |= _PWF_NAME;
+
+ if (!(pw->pw_passwd = strsep(&bp, ":"))) /* passwd */
+ goto fmt;
+ if (pw->pw_passwd[0])
+ pw->pw_fields |= _PWF_PASSWD;
+
+ if (!(p = strsep(&bp, ":"))) /* uid */
+ goto fmt;
+ if (p[0])
+ pw->pw_fields |= _PWF_UID;
+ else {
+ if (pw->pw_name[0] != '+' && pw->pw_name[0] != '-') {
+ if (flags & _PWSCAN_WARN)
+ warnx("no uid for user %s", pw->pw_name);
+ return (0);
+ }
+ }
+ errno = 0;
+ temp = strtoul(p, &ep, 10);
+ if ((temp == ULONG_MAX && errno == ERANGE) || temp > UID_MAX) {
+ if (flags & _PWSCAN_WARN)
+ warnx("%s > max uid value (%u)", p, UID_MAX);
+ return (0);
+ }
+ id = temp;
+ if (*ep != '\0') {
+ if (flags & _PWSCAN_WARN)
+ warnx("%s uid is incorrect", p);
+ return (0);
+ }
+ if (root && id) {
+ if (flags & _PWSCAN_WARN)
+ warnx("root uid should be 0");
+ return (0);
+ }
+ if (flags & _PWSCAN_WARN && pw_big_ids_warning && id > USHRT_MAX) {
+ warnx("%s > recommended max uid value (%u)", p, USHRT_MAX);
+ /*return (0);*/ /* THIS SHOULD NOT BE FATAL! */
+ }
+ pw->pw_uid = id;
+
+ if (!(p = strsep(&bp, ":"))) /* gid */
+ goto fmt;
+ if (p[0])
+ pw->pw_fields |= _PWF_GID;
+ else {
+ if (pw->pw_name[0] != '+' && pw->pw_name[0] != '-') {
+ if (flags & _PWSCAN_WARN)
+ warnx("no gid for user %s", pw->pw_name);
+ return (0);
+ }
+ }
+ errno = 0;
+ temp = strtoul(p, &ep, 10);
+ if ((temp == ULONG_MAX && errno == ERANGE) || temp > GID_MAX) {
+ if (flags & _PWSCAN_WARN)
+ warnx("%s > max gid value (%u)", p, GID_MAX);
+ return (0);
+ }
+ id = temp;
+ if (*ep != '\0') {
+ if (flags & _PWSCAN_WARN)
+ warnx("%s gid is incorrect", p);
+ return (0);
+ }
+ if (flags & _PWSCAN_WARN && pw_big_ids_warning && id > USHRT_MAX) {
+ warnx("%s > recommended max gid value (%u)", p, USHRT_MAX);
+ /* return (0); This should not be fatal! */
+ }
+ pw->pw_gid = id;
+
+ if (flags & _PWSCAN_MASTER ) {
+ if (!(pw->pw_class = strsep(&bp, ":"))) /* class */
+ goto fmt;
+ if (pw->pw_class[0])
+ pw->pw_fields |= _PWF_CLASS;
+
+ if (!(p = strsep(&bp, ":"))) /* change */
+ goto fmt;
+ if (p[0])
+ pw->pw_fields |= _PWF_CHANGE;
+ pw->pw_change = atol(p);
+
+ if (!(p = strsep(&bp, ":"))) /* expire */
+ goto fmt;
+ if (p[0])
+ pw->pw_fields |= _PWF_EXPIRE;
+ pw->pw_expire = atol(p);
+ }
+ if (!(pw->pw_gecos = strsep(&bp, ":"))) /* gecos */
+ goto fmt;
+ if (pw->pw_gecos[0])
+ pw->pw_fields |= _PWF_GECOS;
+
+ if (!(pw->pw_dir = strsep(&bp, ":"))) /* directory */
+ goto fmt;
+ if (pw->pw_dir[0])
+ pw->pw_fields |= _PWF_DIR;
+
+ if (!(pw->pw_shell = strsep(&bp, ":"))) /* shell */
+ goto fmt;
+
+ p = pw->pw_shell;
+ if (root && *p) { /* empty == /bin/sh */
+ for (setusershell();;) {
+ if (!(sh = getusershell())) {
+ if (flags & _PWSCAN_WARN)
+ warnx("warning, unknown root shell");
+ break;
+ }
+ if (!strcmp(p, sh))
+ break;
+ }
+ endusershell();
+ }
+ if (p[0])
+ pw->pw_fields |= _PWF_SHELL;
+
+ if ((p = strsep(&bp, ":"))) { /* too many */
+fmt:
+ if (flags & _PWSCAN_WARN)
+ warnx("corrupted entry");
+ return (0);
+ }
+ return (1);
+}
diff --git a/lib/libc/gen/pw_scan.h b/lib/libc/gen/pw_scan.h
new file mode 100644
index 000000000000..468096c55e70
--- /dev/null
+++ b/lib/libc/gen/pw_scan.h
@@ -0,0 +1,36 @@
+/*-
+ * Copyright (c) 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)pw_scan.h 8.1 (Berkeley) 4/1/94
+ * $FreeBSD$
+ */
+
+#define _PWSCAN_MASTER 0x01
+#define _PWSCAN_WARN 0x02
+
+extern int __pw_scan(char *, struct passwd *, int);
diff --git a/lib/libc/gen/raise.3 b/lib/libc/gen/raise.3
new file mode 100644
index 000000000000..fe75268eb837
--- /dev/null
+++ b/lib/libc/gen/raise.3
@@ -0,0 +1,73 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)raise.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd May 7, 2010
+.Dt RAISE 3
+.Os
+.Sh NAME
+.Nm raise
+.Nd send a signal to the current thread
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In signal.h
+.Ft int
+.Fn raise "int sig"
+.Sh DESCRIPTION
+The
+.Fn raise
+function sends the signal
+.Fa sig
+to the current thread.
+.Sh RETURN VALUES
+.Rv -std raise
+.Sh ERRORS
+The
+.Fn raise
+function
+may fail and set
+.Va errno
+for any of the errors specified for the
+library functions
+.Xr getpid 2
+and
+.Xr kill 2 .
+.Sh SEE ALSO
+.Xr kill 2
+.Sh STANDARDS
+The
+.Fn raise
+function
+conforms to
+.St -isoC .
diff --git a/lib/libc/gen/raise.c b/lib/libc/gen/raise.c
new file mode 100644
index 000000000000..4bc895eb409a
--- /dev/null
+++ b/lib/libc/gen/raise.c
@@ -0,0 +1,53 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)raise.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <signal.h>
+#include <unistd.h>
+
+#include "libc_private.h"
+
+__weak_reference(__raise, raise);
+__weak_reference(__raise, _raise);
+int __raise(int);
+
+int
+__raise(int s)
+{
+ long id;
+
+ if (__sys_thr_self(&id) == -1)
+ return (-1);
+ return (__sys_thr_kill(id, s));
+}
diff --git a/lib/libc/gen/rand48.3 b/lib/libc/gen/rand48.3
new file mode 100644
index 000000000000..c70a8320c15b
--- /dev/null
+++ b/lib/libc/gen/rand48.3
@@ -0,0 +1,190 @@
+.\" Copyright (c) 1993 Martin Birgmeier
+.\" All rights reserved.
+.\"
+.\" You may redistribute unmodified or modified versions of this source
+.\" code provided that the above copyright notice and this and the
+.\" following conditions are retained.
+.\"
+.\" This software is provided ``as is'', and comes with no warranties
+.\" of any kind. I shall in no event be liable for anything that happens
+.\" to anyone/anything when using this software.
+.\"
+.\" @(#)rand48.3 V1.0 MB 8 Oct 1993
+.\" $FreeBSD$
+.\"
+.Dd September 4, 2012
+.Dt RAND48 3
+.Os
+.Sh NAME
+.Nm drand48 ,
+.Nm erand48 ,
+.Nm lrand48 ,
+.Nm nrand48 ,
+.Nm mrand48 ,
+.Nm jrand48 ,
+.Nm srand48 ,
+.Nm seed48 ,
+.Nm lcong48
+.Nd pseudo random number generators and initialization routines
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft double
+.Fn drand48 void
+.Ft double
+.Fn erand48 "unsigned short xseed[3]"
+.Ft long
+.Fn lrand48 void
+.Ft long
+.Fn nrand48 "unsigned short xseed[3]"
+.Ft long
+.Fn mrand48 void
+.Ft long
+.Fn jrand48 "unsigned short xseed[3]"
+.Ft void
+.Fn srand48 "long seed"
+.Ft "unsigned short *"
+.Fn seed48 "unsigned short xseed[3]"
+.Ft void
+.Fn lcong48 "unsigned short p[7]"
+.Sh DESCRIPTION
+.Bf -symbolic
+The functions described in this manual page are not cryptographically
+secure.
+Cryptographic applications should use
+.Xr arc4random 3
+instead.
+.Ef
+.Pp
+The
+.Fn rand48
+family of functions generates pseudo-random numbers using a linear
+congruential algorithm working on integers 48 bits in size.
+The
+particular formula employed is
+r(n+1) = (a * r(n) + c) mod m
+where the default values are
+for the multiplicand a = 0x5deece66d = 25214903917 and
+the addend c = 0xb = 11.
+The modulo is always fixed at m = 2 ** 48.
+r(n) is called the seed of the random number generator.
+.Pp
+For all the six generator routines described next, the first
+computational step is to perform a single iteration of the algorithm.
+.Pp
+The
+.Fn drand48
+and
+.Fn erand48
+functions
+return values of type double.
+The full 48 bits of r(n+1) are
+loaded into the mantissa of the returned value, with the exponent set
+such that the values produced lie in the interval [0.0, 1.0).
+.Pp
+The
+.Fn lrand48
+and
+.Fn nrand48
+functions
+return values of type long in the range
+[0, 2**31-1].
+The high-order (31) bits of
+r(n+1) are loaded into the lower bits of the returned value, with
+the topmost (sign) bit set to zero.
+.Pp
+The
+.Fn mrand48
+and
+.Fn jrand48
+functions
+return values of type long in the range
+[-2**31, 2**31-1].
+The high-order (32) bits of
+r(n+1) are loaded into the returned value.
+.Pp
+The
+.Fn drand48 ,
+.Fn lrand48 ,
+and
+.Fn mrand48
+functions
+use an internal buffer to store r(n).
+For these functions
+the initial value of r(0) = 0x1234abcd330e = 20017429951246.
+.Pp
+On the other hand,
+.Fn erand48 ,
+.Fn nrand48 ,
+and
+.Fn jrand48
+use a user-supplied buffer to store the seed r(n),
+which consists of an array of 3 shorts, where the zeroth member
+holds the least significant bits.
+.Pp
+All functions share the same multiplicand and addend.
+.Pp
+The
+.Fn srand48
+function
+is used to initialize the internal buffer r(n) of
+.Fn drand48 ,
+.Fn lrand48 ,
+and
+.Fn mrand48
+such that the 32 bits of the seed value are copied into the upper 32 bits
+of r(n), with the lower 16 bits of r(n) arbitrarily being set to 0x330e.
+Additionally, the constant multiplicand and addend of the algorithm are
+reset to the default values given above.
+.Pp
+The
+.Fn seed48
+function
+also initializes the internal buffer r(n) of
+.Fn drand48 ,
+.Fn lrand48 ,
+and
+.Fn mrand48 ,
+but here all 48 bits of the seed can be specified in an array of 3 shorts,
+where the zeroth member specifies the lowest bits.
+Again,
+the constant multiplicand and addend of the algorithm are
+reset to the default values given above.
+The
+.Fn seed48
+function
+returns a pointer to an array of 3 shorts which contains the old seed.
+This array is statically allocated, thus its contents are lost after
+each new call to
+.Fn seed48 .
+.Pp
+Finally,
+.Fn lcong48
+allows full control over the multiplicand and addend used in
+.Fn drand48 ,
+.Fn erand48 ,
+.Fn lrand48 ,
+.Fn nrand48 ,
+.Fn mrand48 ,
+and
+.Fn jrand48 ,
+and the seed used in
+.Fn drand48 ,
+.Fn lrand48 ,
+and
+.Fn mrand48 .
+An array of 7 shorts is passed as argument; the first three shorts are
+used to initialize the seed; the second three are used to initialize the
+multiplicand; and the last short is used to initialize the addend.
+It is thus not possible to use values greater than 0xffff as the addend.
+.Pp
+Note that all three methods of seeding the random number generator
+always also set the multiplicand and addend for any of the six
+generator calls.
+.Sh SEE ALSO
+.Xr arc4random 3 ,
+.Xr rand 3 ,
+.Xr random 3
+.Sh AUTHORS
+.An Martin Birgmeier
diff --git a/lib/libc/gen/rand48.h b/lib/libc/gen/rand48.h
new file mode 100644
index 000000000000..b6602dc5a9f7
--- /dev/null
+++ b/lib/libc/gen/rand48.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 1993 Martin Birgmeier
+ * All rights reserved.
+ *
+ * You may redistribute unmodified or modified versions of this source
+ * code provided that the above copyright notice and this and the
+ * following conditions are retained.
+ *
+ * This software is provided ``as is'', and comes with no warranties
+ * of any kind. I shall in no event be liable for anything that happens
+ * to anyone/anything when using this software.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _RAND48_H_
+#define _RAND48_H_
+
+#include <math.h>
+#include <stdlib.h>
+
+void _dorand48(unsigned short[3]);
+
+#define RAND48_SEED_0 (0x330e)
+#define RAND48_SEED_1 (0xabcd)
+#define RAND48_SEED_2 (0x1234)
+#define RAND48_MULT_0 (0xe66d)
+#define RAND48_MULT_1 (0xdeec)
+#define RAND48_MULT_2 (0x0005)
+#define RAND48_ADD (0x000b)
+
+#endif /* _RAND48_H_ */
diff --git a/lib/libc/gen/readdir.c b/lib/libc/gen/readdir.c
new file mode 100644
index 000000000000..b5162ed1e0e6
--- /dev/null
+++ b/lib/libc/gen/readdir.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)readdir.c 8.3 (Berkeley) 9/29/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <dirent.h>
+#include <errno.h>
+#include <string.h>
+#include <pthread.h>
+#include "un-namespace.h"
+
+#include "libc_private.h"
+#include "gen-private.h"
+#include "telldir.h"
+
+/*
+ * get next entry in a directory.
+ */
+struct dirent *
+_readdir_unlocked(DIR *dirp, int skip)
+{
+ struct dirent *dp;
+ long initial_seek;
+ long initial_loc = 0;
+
+ for (;;) {
+ if (dirp->dd_loc >= dirp->dd_size) {
+ if (dirp->dd_flags & __DTF_READALL)
+ return (NULL);
+ initial_loc = dirp->dd_loc;
+ dirp->dd_flags &= ~__DTF_SKIPREAD;
+ dirp->dd_loc = 0;
+ }
+ if (dirp->dd_loc == 0 &&
+ !(dirp->dd_flags & (__DTF_READALL | __DTF_SKIPREAD))) {
+ initial_seek = dirp->dd_seek;
+ dirp->dd_size = _getdirentries(dirp->dd_fd,
+ dirp->dd_buf, dirp->dd_len, &dirp->dd_seek);
+ if (dirp->dd_size <= 0)
+ return (NULL);
+ _fixtelldir(dirp, initial_seek, initial_loc);
+ }
+ dirp->dd_flags &= ~__DTF_SKIPREAD;
+ dp = (struct dirent *)(dirp->dd_buf + dirp->dd_loc);
+ if ((long)dp & 03L) /* bogus pointer check */
+ return (NULL);
+ if (dp->d_reclen <= 0 ||
+ dp->d_reclen > dirp->dd_len + 1 - dirp->dd_loc)
+ return (NULL);
+ dirp->dd_loc += dp->d_reclen;
+ if (dp->d_ino == 0 && skip)
+ continue;
+ if (dp->d_type == DT_WHT && (dirp->dd_flags & DTF_HIDEW))
+ continue;
+ return (dp);
+ }
+}
+
+struct dirent *
+readdir(DIR *dirp)
+{
+ struct dirent *dp;
+
+ if (__isthreaded) {
+ _pthread_mutex_lock(&dirp->dd_lock);
+ dp = _readdir_unlocked(dirp, 1);
+ _pthread_mutex_unlock(&dirp->dd_lock);
+ }
+ else
+ dp = _readdir_unlocked(dirp, 1);
+ return (dp);
+}
+
+int
+readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result)
+{
+ struct dirent *dp;
+ int saved_errno;
+
+ saved_errno = errno;
+ errno = 0;
+ if (__isthreaded) {
+ _pthread_mutex_lock(&dirp->dd_lock);
+ if ((dp = _readdir_unlocked(dirp, 1)) != NULL)
+ memcpy(entry, dp, _GENERIC_DIRSIZ(dp));
+ _pthread_mutex_unlock(&dirp->dd_lock);
+ }
+ else if ((dp = _readdir_unlocked(dirp, 1)) != NULL)
+ memcpy(entry, dp, _GENERIC_DIRSIZ(dp));
+
+ if (errno != 0) {
+ if (dp == NULL)
+ return (errno);
+ } else
+ errno = saved_errno;
+
+ if (dp != NULL)
+ *result = entry;
+ else
+ *result = NULL;
+
+ return (0);
+}
diff --git a/lib/libc/gen/readpassphrase.3 b/lib/libc/gen/readpassphrase.3
new file mode 100644
index 000000000000..3bcee6f5638d
--- /dev/null
+++ b/lib/libc/gen/readpassphrase.3
@@ -0,0 +1,181 @@
+.\" $OpenBSD: readpassphrase.3,v 1.17 2007/05/31 19:19:28 jmc Exp $
+.\"
+.\" Copyright (c) 2000, 2002 Todd C. Miller <Todd.Miller@courtesan.com>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.\" Sponsored in part by the Defense Advanced Research Projects
+.\" Agency (DARPA) and Air Force Research Laboratory, Air Force
+.\" Materiel Command, USAF, under agreement number F39502-99-1-0512.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd May 31, 2007
+.Dt READPASSPHRASE 3
+.Os
+.Sh NAME
+.Nm readpassphrase
+.Nd get a passphrase from the user
+.Sh SYNOPSIS
+.In readpassphrase.h
+.Ft "char *"
+.Fn readpassphrase "const char *prompt" "char *buf" "size_t bufsiz" "int flags"
+.Sh DESCRIPTION
+The
+.Fn readpassphrase
+function displays a prompt to, and reads in a passphrase from,
+.Pa /dev/tty .
+If this file is inaccessible
+and the
+.Dv RPP_REQUIRE_TTY
+flag is not set,
+.Fn readpassphrase
+displays the prompt on the standard error output and reads from the standard
+input.
+In this case it is generally not possible to turn off echo.
+.Pp
+Up to
+.Fa bufsiz
+\- 1 characters (one is for the
+.Dv NUL )
+are read into the provided buffer
+.Fa buf .
+Any additional
+characters and the terminating newline (or return) character are discarded.
+.Pp
+The
+.Fn readpassphrase
+function
+takes the following optional
+.Fa flags :
+.Pp
+.Bl -tag -width ".Dv RPP_REQUIRE_TTY" -compact
+.It Dv RPP_ECHO_OFF
+turn off echo (default behavior)
+.It Dv RPP_ECHO_ON
+leave echo on
+.It Dv RPP_REQUIRE_TTY
+fail if there is no tty
+.It Dv RPP_FORCELOWER
+force input to lower case
+.It Dv RPP_FORCEUPPER
+force input to upper case
+.It Dv RPP_SEVENBIT
+strip the high bit from input
+.It Dv RPP_STDIN
+force read of passphrase from stdin
+.El
+.Pp
+The calling process should zero the passphrase as soon as possible to
+avoid leaving the cleartext passphrase visible in the process's address
+space.
+.Sh RETURN VALUES
+Upon successful completion,
+.Fn readpassphrase
+returns a pointer to the NUL-terminated passphrase.
+If an error is encountered, the terminal state is restored and
+a
+.Dv NULL
+pointer is returned.
+.Sh FILES
+.Bl -tag -width ".Pa /dev/tty" -compact
+.It Pa /dev/tty
+.El
+.Sh EXAMPLES
+The following code fragment will read a passphrase from
+.Pa /dev/tty
+into the buffer
+.Fa passbuf .
+.Bd -literal -offset indent
+char passbuf[1024];
+
+\&...
+
+if (readpassphrase("Response: ", passbuf, sizeof(passbuf),
+ RPP_REQUIRE_TTY) == NULL)
+ errx(1, "unable to read passphrase");
+
+if (compare(transform(passbuf), epass) != 0)
+ errx(1, "bad passphrase");
+
+\&...
+
+memset(passbuf, 0, sizeof(passbuf));
+.Ed
+.Sh ERRORS
+.Bl -tag -width Er
+.It Bq Er EINTR
+The
+.Fn readpassphrase
+function was interrupted by a signal.
+.It Bq Er EINVAL
+The
+.Ar bufsiz
+argument was zero.
+.It Bq Er EIO
+The process is a member of a background process attempting to read
+from its controlling terminal, the process is ignoring or blocking
+the
+.Dv SIGTTIN
+signal, or the process group is orphaned.
+.It Bq Er EMFILE
+The process has already reached its limit for open file descriptors.
+.It Bq Er ENFILE
+The system file table is full.
+.It Bq Er ENOTTY
+There is no controlling terminal and the
+.Dv RPP_REQUIRE_TTY
+flag was specified.
+.El
+.Sh SIGNALS
+The
+.Fn readpassphrase
+function
+will catch the following signals:
+.Bd -literal -offset indent
+SIGALRM SIGHUP SIGINT
+SIGPIPE SIGQUIT SIGTERM
+SIGTSTP SIGTTIN SIGTTOU
+.Ed
+.Pp
+When one of the above signals is intercepted, terminal echo will
+be restored if it had previously been turned off.
+If a signal handler was installed for the signal when
+.Fn readpassphrase
+was called, that handler is then executed.
+If no handler was previously installed for the signal then the
+default action is taken as per
+.Xr sigaction 2 .
+.Pp
+The
+.Dv SIGTSTP , SIGTTIN
+and
+.Dv SIGTTOU
+signals (stop signals generated from keyboard or due to terminal I/O
+from a background process) are treated specially.
+When the process is resumed after it has been stopped,
+.Fn readpassphrase
+will reprint the prompt and the user may then enter a passphrase.
+.Sh SEE ALSO
+.Xr sigaction 2 ,
+.Xr getpass 3
+.Sh STANDARDS
+The
+.Fn readpassphrase
+function is an
+extension and should not be used if portability is desired.
+.Sh HISTORY
+The
+.Fn readpassphrase
+function first appeared in
+.Ox 2.9 .
diff --git a/lib/libc/gen/readpassphrase.c b/lib/libc/gen/readpassphrase.c
new file mode 100644
index 000000000000..0961fbb35a8b
--- /dev/null
+++ b/lib/libc/gen/readpassphrase.c
@@ -0,0 +1,203 @@
+/* $OpenBSD: readpassphrase.c,v 1.24 2013/11/24 23:51:29 deraadt Exp $ */
+
+/*
+ * Copyright (c) 2000-2002, 2007, 2010
+ * Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F39502-99-1-0512.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <pwd.h>
+#include <signal.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+#include <readpassphrase.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+
+static volatile sig_atomic_t signo[NSIG];
+
+static void handler(int);
+
+char *
+readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags)
+{
+ ssize_t nr;
+ int input, output, save_errno, i, need_restart, input_is_tty;
+ char ch, *p, *end;
+ struct termios term, oterm;
+ struct sigaction sa, savealrm, saveint, savehup, savequit, saveterm;
+ struct sigaction savetstp, savettin, savettou, savepipe;
+
+ /* I suppose we could alloc on demand in this case (XXX). */
+ if (bufsiz == 0) {
+ errno = EINVAL;
+ return(NULL);
+ }
+
+restart:
+ for (i = 0; i < NSIG; i++)
+ signo[i] = 0;
+ nr = -1;
+ save_errno = 0;
+ need_restart = 0;
+ /*
+ * Read and write to /dev/tty if available. If not, read from
+ * stdin and write to stderr unless a tty is required.
+ */
+ input_is_tty = 0;
+ if (!(flags & RPP_STDIN)) {
+ input = output = _open(_PATH_TTY, O_RDWR | O_CLOEXEC);
+ if (input == -1) {
+ if (flags & RPP_REQUIRE_TTY) {
+ errno = ENOTTY;
+ return(NULL);
+ }
+ input = STDIN_FILENO;
+ output = STDERR_FILENO;
+ } else {
+ input_is_tty = 1;
+ }
+ } else {
+ input = STDIN_FILENO;
+ output = STDERR_FILENO;
+ }
+
+ /*
+ * Turn off echo if possible.
+ * If we are using a tty but are not the foreground pgrp this will
+ * generate SIGTTOU, so do it *before* installing the signal handlers.
+ */
+ if (input_is_tty && tcgetattr(input, &oterm) == 0) {
+ memcpy(&term, &oterm, sizeof(term));
+ if (!(flags & RPP_ECHO_ON))
+ term.c_lflag &= ~(ECHO | ECHONL);
+ if (term.c_cc[VSTATUS] != _POSIX_VDISABLE)
+ term.c_cc[VSTATUS] = _POSIX_VDISABLE;
+ (void)tcsetattr(input, TCSAFLUSH|TCSASOFT, &term);
+ } else {
+ memset(&term, 0, sizeof(term));
+ term.c_lflag |= ECHO;
+ memset(&oterm, 0, sizeof(oterm));
+ oterm.c_lflag |= ECHO;
+ }
+
+ /*
+ * Catch signals that would otherwise cause the user to end
+ * up with echo turned off in the shell. Don't worry about
+ * things like SIGXCPU and SIGVTALRM for now.
+ */
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0; /* don't restart system calls */
+ sa.sa_handler = handler;
+ (void)__libc_sigaction(SIGALRM, &sa, &savealrm);
+ (void)__libc_sigaction(SIGHUP, &sa, &savehup);
+ (void)__libc_sigaction(SIGINT, &sa, &saveint);
+ (void)__libc_sigaction(SIGPIPE, &sa, &savepipe);
+ (void)__libc_sigaction(SIGQUIT, &sa, &savequit);
+ (void)__libc_sigaction(SIGTERM, &sa, &saveterm);
+ (void)__libc_sigaction(SIGTSTP, &sa, &savetstp);
+ (void)__libc_sigaction(SIGTTIN, &sa, &savettin);
+ (void)__libc_sigaction(SIGTTOU, &sa, &savettou);
+
+ if (!(flags & RPP_STDIN))
+ (void)_write(output, prompt, strlen(prompt));
+ end = buf + bufsiz - 1;
+ p = buf;
+ while ((nr = _read(input, &ch, 1)) == 1 && ch != '\n' && ch != '\r') {
+ if (p < end) {
+ if ((flags & RPP_SEVENBIT))
+ ch &= 0x7f;
+ if (isalpha((unsigned char)ch)) {
+ if ((flags & RPP_FORCELOWER))
+ ch = (char)tolower((unsigned char)ch);
+ if ((flags & RPP_FORCEUPPER))
+ ch = (char)toupper((unsigned char)ch);
+ }
+ *p++ = ch;
+ }
+ }
+ *p = '\0';
+ save_errno = errno;
+ if (!(term.c_lflag & ECHO))
+ (void)_write(output, "\n", 1);
+
+ /* Restore old terminal settings and signals. */
+ if (memcmp(&term, &oterm, sizeof(term)) != 0) {
+ while (tcsetattr(input, TCSAFLUSH|TCSASOFT, &oterm) == -1 &&
+ errno == EINTR && !signo[SIGTTOU])
+ continue;
+ }
+ (void)__libc_sigaction(SIGALRM, &savealrm, NULL);
+ (void)__libc_sigaction(SIGHUP, &savehup, NULL);
+ (void)__libc_sigaction(SIGINT, &saveint, NULL);
+ (void)__libc_sigaction(SIGQUIT, &savequit, NULL);
+ (void)__libc_sigaction(SIGPIPE, &savepipe, NULL);
+ (void)__libc_sigaction(SIGTERM, &saveterm, NULL);
+ (void)__libc_sigaction(SIGTSTP, &savetstp, NULL);
+ (void)__libc_sigaction(SIGTTIN, &savettin, NULL);
+ (void)__libc_sigaction(SIGTTOU, &savettou, NULL);
+ if (input_is_tty)
+ (void)_close(input);
+
+ /*
+ * If we were interrupted by a signal, resend it to ourselves
+ * now that we have restored the signal handlers.
+ */
+ for (i = 0; i < NSIG; i++) {
+ if (signo[i]) {
+ kill(getpid(), i);
+ switch (i) {
+ case SIGTSTP:
+ case SIGTTIN:
+ case SIGTTOU:
+ need_restart = 1;
+ }
+ }
+ }
+ if (need_restart)
+ goto restart;
+
+ if (save_errno)
+ errno = save_errno;
+ return(nr == -1 ? NULL : buf);
+}
+
+char *
+getpass(const char *prompt)
+{
+ static char buf[_PASSWORD_LEN + 1];
+
+ if (readpassphrase(prompt, buf, sizeof(buf), RPP_ECHO_OFF) == NULL)
+ buf[0] = '\0';
+ return(buf);
+}
+
+static void handler(int s)
+{
+
+ signo[s] = 1;
+}
diff --git a/lib/libc/gen/recvmmsg.c b/lib/libc/gen/recvmmsg.c
new file mode 100644
index 000000000000..7c5c289569ee
--- /dev/null
+++ b/lib/libc/gen/recvmmsg.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2016 Boris Astardzhiev, Smartcom-Bulgaria AD
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice(s), this list of conditions and the following disclaimer as
+ * the first lines of this file unmodified other than the possible
+ * addition of one or more copyright notices.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice(s), this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <poll.h>
+#include <stddef.h>
+#include "libc_private.h"
+
+ssize_t
+recvmmsg(int s, struct mmsghdr *__restrict msgvec, size_t vlen, int flags,
+ const struct timespec *__restrict timeout)
+{
+ struct pollfd pfd[1];
+ size_t i, rcvd;
+ ssize_t ret;
+ int res;
+ short ev;
+
+ if (timeout != NULL) {
+ pfd[0].fd = s;
+ pfd[0].revents = 0;
+ pfd[0].events = ev = POLLIN | POLLRDNORM | POLLRDBAND |
+ POLLPRI;
+ res = ppoll(&pfd[0], 1, timeout, NULL);
+ if (res == -1 || res == 0)
+ return (res);
+ if (pfd[0].revents & POLLNVAL) {
+ errno = EBADF;
+ return (-1);
+ }
+ if ((pfd[0].revents & ev) == 0) {
+ errno = ETIMEDOUT;
+ return (-1);
+ }
+ }
+
+ ret = __sys_recvmsg(s, &msgvec[0].msg_hdr, flags);
+ if (ret == -1)
+ return (ret);
+
+ msgvec[0].msg_len = ret;
+
+ /*
+ * Do non-blocking receive for second and later messages if
+ * WAITFORONE is set.
+ */
+ if (flags & MSG_WAITFORONE)
+ flags |= MSG_DONTWAIT;
+
+ rcvd = 1;
+ for (i = rcvd; i < vlen; i++, rcvd++) {
+ ret = __sys_recvmsg(s, &msgvec[i].msg_hdr, flags);
+ if (ret == -1) {
+ /* We have received messages. Let caller know
+ * about the data received, socket error is
+ * returned on next invocation.
+ */
+ return (rcvd);
+ }
+
+ /* Save received bytes. */
+ msgvec[i].msg_len = ret;
+ }
+
+ return (rcvd);
+}
diff --git a/lib/libc/gen/rewinddir.c b/lib/libc/gen/rewinddir.c
new file mode 100644
index 000000000000..2421c472541a
--- /dev/null
+++ b/lib/libc/gen/rewinddir.c
@@ -0,0 +1,64 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)rewinddir.c 8.1 (Berkeley) 6/8/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <dirent.h>
+#include <pthread.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+#include "libc_private.h"
+#include "gen-private.h"
+#include "telldir.h"
+
+void
+rewinddir(DIR *dirp)
+{
+
+ if (__isthreaded)
+ _pthread_mutex_lock(&dirp->dd_lock);
+ dirp->dd_flags &= ~__DTF_SKIPREAD; /* current contents are invalid */
+ if (dirp->dd_flags & __DTF_READALL)
+ _filldir(dirp, false);
+ else {
+ (void) lseek(dirp->dd_fd, 0, SEEK_SET);
+ dirp->dd_seek = 0;
+ }
+ dirp->dd_loc = 0;
+ _reclaim_telldir(dirp);
+ if (__isthreaded)
+ _pthread_mutex_unlock(&dirp->dd_lock);
+}
diff --git a/lib/libc/gen/rfork_thread.3 b/lib/libc/gen/rfork_thread.3
new file mode 100644
index 000000000000..dfd6fbcc3c68
--- /dev/null
+++ b/lib/libc/gen/rfork_thread.3
@@ -0,0 +1,87 @@
+.\"
+.\" Copyright (c) 2000 Peter Wemm <peter@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd February 6, 2011
+.Dt RFORK_THREAD 3
+.Os
+.Sh NAME
+.Nm rfork_thread
+.Nd create a rfork-based process thread
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft pid_t
+.Fn rfork_thread "int flags" "void *stack" "int (*func)(void *arg)" "void *arg"
+.Sh DESCRIPTION
+.Bf -symbolic
+The
+.Fn rfork_thread
+function has been deprecated in favor of
+.Xr pthread_create 3 .
+.Ef
+.Pp
+The
+.Fn rfork_thread
+function
+is a helper function for
+.Xr rfork 2 .
+It arranges for a new process to be created and the child process will
+call the specified function with the specified argument, while running on
+the supplied stack.
+.Pp
+Using this function should avoid the need to implement complex stack
+swap code.
+.Sh RETURN VALUES
+Upon successful completion,
+.Fn rfork_thread
+returns the process ID of the child process to the parent process.
+Otherwise, a value of -1 is returned
+to the parent process, no child process is created, and the global
+variable
+.Va errno
+is set to indicate the error.
+.Pp
+The child process context is not aware of a return from the
+.Fn rfork_thread
+function as it begins executing directly with the supplied function.
+.Sh ERRORS
+See
+.Xr rfork 2
+for error return codes.
+.Sh SEE ALSO
+.Xr fork 2 ,
+.Xr intro 2 ,
+.Xr minherit 2 ,
+.Xr rfork 2 ,
+.Xr vfork 2 ,
+.Xr pthread_create 3
+.Sh HISTORY
+The
+.Fn rfork_thread
+function first appeared in
+.Fx 4.3 .
diff --git a/lib/libc/gen/scandir.3 b/lib/libc/gen/scandir.3
new file mode 100644
index 000000000000..aa8dea030a75
--- /dev/null
+++ b/lib/libc/gen/scandir.3
@@ -0,0 +1,117 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)scandir.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd January 3, 2010
+.Dt SCANDIR 3
+.Os
+.Sh NAME
+.Nm scandir ,
+.Nm alphasort
+.Nd scan a directory
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In dirent.h
+.Ft int
+.Fn scandir "const char *dirname" "struct dirent ***namelist" "int \*(lp*select\*(rp\*(lpconst struct dirent *\*(rp" "int \*(lp*compar\*(rp\*(lpconst struct dirent **, const struct dirent **\*(rp"
+.Ft int
+.Fn scandir_b "const char *dirname" "struct dirent ***namelist" "int \*(lp*select\^(rp\*(lpconst struct dirent *\*(rp" "int \*(lp^compar\*(rp\*(lpconst struct dirent **, const struct dirent **\*(rp"
+.Ft int
+.Fn alphasort "const struct dirent **d1" "const struct dirent **d2"
+.Sh DESCRIPTION
+The
+.Fn scandir
+function
+reads the directory
+.Fa dirname
+and builds an array of pointers to directory
+entries using
+.Xr malloc 3 .
+It returns the number of entries in the array.
+A pointer to the array of directory entries is stored in the location
+referenced by
+.Fa namelist .
+.Pp
+The
+.Fa select
+argument is a pointer to a user supplied subroutine which is called by
+.Fn scandir
+to select which entries are to be included in the array.
+The select routine is passed a
+pointer to a directory entry and should return a non-zero
+value if the directory entry is to be included in the array.
+If
+.Fa select
+is null, then all the directory entries will be included.
+.Pp
+The
+.Fa compar
+argument is a pointer to a user supplied subroutine which is passed to
+.Xr qsort 3
+to sort the completed array.
+If this pointer is null, the array is not sorted.
+.Pp
+The
+.Fn alphasort
+function
+is a routine which can be used for the
+.Fa compar
+argument to sort the array alphabetically using
+.Xr strcoll 3 .
+.Pp
+The memory allocated for the array can be deallocated with
+.Xr free 3 ,
+by freeing each pointer in the array and then the array itself.
+.Pp
+The
+.Fn scandir_b
+function behaves in the same way as
+.Fn scandir ,
+but takes blocks as arguments instead of function pointers and calls
+.Fn qsort_b
+rather than
+.Fn qsort .
+.Sh DIAGNOSTICS
+Returns \-1 if the directory cannot be opened for reading or if
+.Xr malloc 3
+cannot allocate enough memory to hold all the data structures.
+.Sh SEE ALSO
+.Xr directory 3 ,
+.Xr malloc 3 ,
+.Xr qsort 3 ,
+.Xr strcoll 3 ,
+.Xr dir 5
+.Sh HISTORY
+The
+.Fn scandir
+and
+.Fn alphasort
+functions appeared in
+.Bx 4.2 .
diff --git a/lib/libc/gen/scandir.c b/lib/libc/gen/scandir.c
new file mode 100644
index 000000000000..d81acc8bfa64
--- /dev/null
+++ b/lib/libc/gen/scandir.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)scandir.c 8.3 (Berkeley) 1/2/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Scan the directory dirname calling select to make a list of selected
+ * directory entries then sort using qsort and compare routine dcomp.
+ * Returns the number of entries and a pointer to a list of pointers to
+ * struct dirent (through namelist). Returns -1 if there were any errors.
+ */
+
+#include "namespace.h"
+#include <dirent.h>
+#include <stdlib.h>
+#include <string.h>
+#include "un-namespace.h"
+
+#ifdef I_AM_SCANDIR_B
+#include "block_abi.h"
+#define SELECT(x) CALL_BLOCK(select, x)
+#ifndef __BLOCKS__
+void
+qsort_b(void *, size_t, size_t, void*);
+#endif
+#else
+#define SELECT(x) select(x)
+#endif
+
+static int alphasort_thunk(void *thunk, const void *p1, const void *p2);
+
+/*
+ * The DIRSIZ macro is the minimum record length which will hold the directory
+ * entry. This requires the amount of space in struct dirent without the
+ * d_name field, plus enough space for the name and a terminating nul byte
+ * (dp->d_namlen + 1), rounded up to a 4 byte boundary.
+ */
+#undef DIRSIZ
+#define DIRSIZ(dp) \
+ ((sizeof(struct dirent) - sizeof(dp)->d_name) + \
+ (((dp)->d_namlen + 1 + 3) &~ 3))
+
+int
+#ifdef I_AM_SCANDIR_B
+scandir_b(const char *dirname, struct dirent ***namelist,
+ DECLARE_BLOCK(int, select, const struct dirent *),
+ DECLARE_BLOCK(int, dcomp, const struct dirent **, const struct dirent **))
+#else
+scandir(const char *dirname, struct dirent ***namelist,
+ int (*select)(const struct dirent *), int (*dcomp)(const struct dirent **,
+ const struct dirent **))
+#endif
+{
+ struct dirent *d, *p, **names = NULL;
+ size_t nitems = 0;
+ long arraysz;
+ DIR *dirp;
+
+ if ((dirp = opendir(dirname)) == NULL)
+ return(-1);
+
+ arraysz = 32; /* initial estimate of the array size */
+ names = (struct dirent **)malloc(arraysz * sizeof(struct dirent *));
+ if (names == NULL)
+ goto fail;
+
+ while ((d = readdir(dirp)) != NULL) {
+ if (select != NULL && !SELECT(d))
+ continue; /* just selected names */
+ /*
+ * Make a minimum size copy of the data
+ */
+ p = (struct dirent *)malloc(DIRSIZ(d));
+ if (p == NULL)
+ goto fail;
+ p->d_fileno = d->d_fileno;
+ p->d_type = d->d_type;
+ p->d_reclen = d->d_reclen;
+ p->d_namlen = d->d_namlen;
+ bcopy(d->d_name, p->d_name, p->d_namlen + 1);
+ /*
+ * Check to make sure the array has space left and
+ * realloc the maximum size.
+ */
+ if (nitems >= arraysz) {
+ struct dirent **names2;
+
+ names2 = (struct dirent **)realloc((char *)names,
+ (arraysz * 2) * sizeof(struct dirent *));
+ if (names2 == NULL) {
+ free(p);
+ goto fail;
+ }
+ names = names2;
+ arraysz *= 2;
+ }
+ names[nitems++] = p;
+ }
+ closedir(dirp);
+ if (nitems && dcomp != NULL)
+#ifdef I_AM_SCANDIR_B
+ qsort_b(names, nitems, sizeof(struct dirent *), (void*)dcomp);
+#else
+ qsort_r(names, nitems, sizeof(struct dirent *),
+ &dcomp, alphasort_thunk);
+#endif
+ *namelist = names;
+ return (nitems);
+
+fail:
+ while (nitems > 0)
+ free(names[--nitems]);
+ free(names);
+ closedir(dirp);
+ return (-1);
+}
+
+/*
+ * Alphabetic order comparison routine for those who want it.
+ * POSIX 2008 requires that alphasort() uses strcoll().
+ */
+int
+alphasort(const struct dirent **d1, const struct dirent **d2)
+{
+
+ return (strcoll((*d1)->d_name, (*d2)->d_name));
+}
+
+static int
+alphasort_thunk(void *thunk, const void *p1, const void *p2)
+{
+ int (*dc)(const struct dirent **, const struct dirent **);
+
+ dc = *(int (**)(const struct dirent **, const struct dirent **))thunk;
+ return (dc((const struct dirent **)p1, (const struct dirent **)p2));
+}
diff --git a/lib/libc/gen/scandir_b.c b/lib/libc/gen/scandir_b.c
new file mode 100644
index 000000000000..6310a9110598
--- /dev/null
+++ b/lib/libc/gen/scandir_b.c
@@ -0,0 +1,29 @@
+/*-
+ * Copyright (c) 2014 David Chisnall
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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$
+ */
+#define I_AM_SCANDIR_B
+#include "scandir.c"
diff --git a/lib/libc/gen/seed48.c b/lib/libc/gen/seed48.c
new file mode 100644
index 000000000000..5339b8c0c4e9
--- /dev/null
+++ b/lib/libc/gen/seed48.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 1993 Martin Birgmeier
+ * All rights reserved.
+ *
+ * You may redistribute unmodified or modified versions of this source
+ * code provided that the above copyright notice and this and the
+ * following conditions are retained.
+ *
+ * This software is provided ``as is'', and comes with no warranties
+ * of any kind. I shall in no event be liable for anything that happens
+ * to anyone/anything when using this software.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "rand48.h"
+
+extern unsigned short _rand48_seed[3];
+extern unsigned short _rand48_mult[3];
+extern unsigned short _rand48_add;
+
+unsigned short *
+seed48(unsigned short xseed[3])
+{
+ static unsigned short sseed[3];
+
+ sseed[0] = _rand48_seed[0];
+ sseed[1] = _rand48_seed[1];
+ sseed[2] = _rand48_seed[2];
+ _rand48_seed[0] = xseed[0];
+ _rand48_seed[1] = xseed[1];
+ _rand48_seed[2] = xseed[2];
+ _rand48_mult[0] = RAND48_MULT_0;
+ _rand48_mult[1] = RAND48_MULT_1;
+ _rand48_mult[2] = RAND48_MULT_2;
+ _rand48_add = RAND48_ADD;
+ return sseed;
+}
diff --git a/lib/libc/gen/seekdir.c b/lib/libc/gen/seekdir.c
new file mode 100644
index 000000000000..699de4626c10
--- /dev/null
+++ b/lib/libc/gen/seekdir.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)seekdir.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <dirent.h>
+#include <pthread.h>
+#include "un-namespace.h"
+
+#include "libc_private.h"
+#include "gen-private.h"
+#include "telldir.h"
+
+/*
+ * Seek to an entry in a directory.
+ * _seekdir is in telldir.c so that it can share opaque data structures.
+ */
+void
+seekdir(DIR *dirp, long loc)
+{
+ if (__isthreaded)
+ _pthread_mutex_lock(&dirp->dd_lock);
+ _seekdir(dirp, loc);
+ if (__isthreaded)
+ _pthread_mutex_unlock(&dirp->dd_lock);
+}
diff --git a/lib/libc/gen/sem.c b/lib/libc/gen/sem.c
new file mode 100644
index 000000000000..71cd0517743d
--- /dev/null
+++ b/lib/libc/gen/sem.c
@@ -0,0 +1,464 @@
+/*
+ * Copyright (C) 2010 David Xu <davidxu@freebsd.org>.
+ * Copyright (C) 2000 Jason Evans <jasone@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(s), this list of conditions and the following disclaimer as
+ * the first lines of this file unmodified other than the possible
+ * addition of one or more copyright notices.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice(s), this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Some notes about this implementation.
+ *
+ * This is mostly a simple implementation of POSIX semaphores that
+ * does not need threading. Any semaphore created is a kernel-based
+ * semaphore regardless of the pshared attribute. This is necessary
+ * because libc's stub for pthread_cond_wait() doesn't really wait,
+ * and it is not worth the effort impose this behavior on libc.
+ *
+ * All functions here are designed to be thread-safe so that a
+ * threads library need not provide wrappers except to make
+ * sem_wait() and sem_timedwait() cancellation points or to
+ * provide a faster userland implementation for non-pshared
+ * semaphores.
+ *
+ * Also, this implementation of semaphores cannot really support
+ * real pshared semaphores. The sem_t is an allocated object
+ * and can't be seen by other processes when placed in shared
+ * memory. It should work across forks as long as the semaphore
+ * is created before any forks.
+ *
+ * The function sem_init() should be overridden by a threads
+ * library if it wants to provide a different userland version
+ * of semaphores. The functions sem_wait() and sem_timedwait()
+ * need to be wrapped to provide cancellation points. The function
+ * sem_post() may need to be wrapped to be signal-safe.
+ */
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <machine/atomic.h>
+#include <errno.h>
+#include <sys/umtx.h>
+#include <sys/_semaphore.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <time.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+
+/*
+ * Old semaphore definitions.
+ */
+struct sem {
+#define SEM_MAGIC ((u_int32_t) 0x09fa4012)
+ u_int32_t magic;
+ pthread_mutex_t lock;
+ pthread_cond_t gtzero;
+ u_int32_t count;
+ u_int32_t nwaiters;
+#define SEM_USER (NULL)
+ semid_t semid; /* semaphore id if kernel (shared) semaphore */
+ int syssem; /* 1 if kernel (shared) semaphore */
+ LIST_ENTRY(sem) entry;
+ struct sem **backpointer;
+};
+
+typedef struct sem* sem_t;
+
+#define SEM_FAILED ((sem_t *)0)
+#define SEM_VALUE_MAX __INT_MAX
+
+#define SYM_FB10(sym) __CONCAT(sym, _fb10)
+#define WEAK_REF(sym, alias) __weak_reference(sym, alias)
+#define SYM_COMPAT(sym, impl, ver) __sym_compat(sym, impl, ver)
+
+#define FB10_COMPAT(func, sym) \
+ WEAK_REF(func, SYM_FB10(sym)); \
+ SYM_COMPAT(sym, SYM_FB10(sym), FBSD_1.0)
+
+static sem_t sem_alloc(unsigned int value, semid_t semid, int system_sem);
+static void sem_free(sem_t sem);
+
+static LIST_HEAD(, sem) named_sems = LIST_HEAD_INITIALIZER(named_sems);
+static pthread_mutex_t named_sems_mtx = PTHREAD_MUTEX_INITIALIZER;
+
+FB10_COMPAT(_libc_sem_init_compat, sem_init);
+FB10_COMPAT(_libc_sem_destroy_compat, sem_destroy);
+FB10_COMPAT(_libc_sem_open_compat, sem_open);
+FB10_COMPAT(_libc_sem_close_compat, sem_close);
+FB10_COMPAT(_libc_sem_unlink_compat, sem_unlink);
+FB10_COMPAT(_libc_sem_wait_compat, sem_wait);
+FB10_COMPAT(_libc_sem_trywait_compat, sem_trywait);
+FB10_COMPAT(_libc_sem_timedwait_compat, sem_timedwait);
+FB10_COMPAT(_libc_sem_post_compat, sem_post);
+FB10_COMPAT(_libc_sem_getvalue_compat, sem_getvalue);
+
+static inline int
+sem_check_validity(sem_t *sem)
+{
+
+ if ((sem != NULL) && ((*sem)->magic == SEM_MAGIC))
+ return (0);
+ else {
+ errno = EINVAL;
+ return (-1);
+ }
+}
+
+static void
+sem_free(sem_t sem)
+{
+
+ sem->magic = 0;
+ free(sem);
+}
+
+static sem_t
+sem_alloc(unsigned int value, semid_t semid, int system_sem)
+{
+ sem_t sem;
+
+ if (value > SEM_VALUE_MAX) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ sem = (sem_t)malloc(sizeof(struct sem));
+ if (sem == NULL) {
+ errno = ENOSPC;
+ return (NULL);
+ }
+
+ sem->count = (u_int32_t)value;
+ sem->nwaiters = 0;
+ sem->magic = SEM_MAGIC;
+ sem->semid = semid;
+ sem->syssem = system_sem;
+ return (sem);
+}
+
+int
+_libc_sem_init_compat(sem_t *sem, int pshared, unsigned int value)
+{
+ semid_t semid;
+
+ /*
+ * We always have to create the kernel semaphore if the
+ * threads library isn't present since libc's version of
+ * pthread_cond_wait() is just a stub that doesn't really
+ * wait.
+ */
+ semid = (semid_t)SEM_USER;
+ if ((pshared != 0) && ksem_init(&semid, value) != 0)
+ return (-1);
+
+ *sem = sem_alloc(value, semid, pshared);
+ if ((*sem) == NULL) {
+ if (pshared != 0)
+ ksem_destroy(semid);
+ return (-1);
+ }
+ return (0);
+}
+
+int
+_libc_sem_destroy_compat(sem_t *sem)
+{
+ int retval;
+
+ if (sem_check_validity(sem) != 0)
+ return (-1);
+
+ /*
+ * If this is a system semaphore let the kernel track it otherwise
+ * make sure there are no waiters.
+ */
+ if ((*sem)->syssem != 0)
+ retval = ksem_destroy((*sem)->semid);
+ else if ((*sem)->nwaiters > 0) {
+ errno = EBUSY;
+ retval = -1;
+ }
+ else {
+ retval = 0;
+ (*sem)->magic = 0;
+ }
+
+ if (retval == 0)
+ sem_free(*sem);
+ return (retval);
+}
+
+sem_t *
+_libc_sem_open_compat(const char *name, int oflag, ...)
+{
+ sem_t *sem;
+ sem_t s;
+ semid_t semid;
+ mode_t mode;
+ unsigned int value;
+
+ mode = 0;
+ value = 0;
+
+ if ((oflag & O_CREAT) != 0) {
+ va_list ap;
+
+ va_start(ap, oflag);
+ mode = va_arg(ap, int);
+ value = va_arg(ap, unsigned int);
+ va_end(ap);
+ }
+ /*
+ * we can be lazy and let the kernel handle the "oflag",
+ * we'll just merge duplicate IDs into our list.
+ */
+ if (ksem_open(&semid, name, oflag, mode, value) == -1)
+ return (SEM_FAILED);
+ /*
+ * search for a duplicate ID, we must return the same sem_t *
+ * if we locate one.
+ */
+ _pthread_mutex_lock(&named_sems_mtx);
+ LIST_FOREACH(s, &named_sems, entry) {
+ if (s->semid == semid) {
+ sem = s->backpointer;
+ _pthread_mutex_unlock(&named_sems_mtx);
+ return (sem);
+ }
+ }
+ sem = (sem_t *)malloc(sizeof(*sem));
+ if (sem == NULL)
+ goto err;
+ *sem = sem_alloc(value, semid, 1);
+ if ((*sem) == NULL)
+ goto err;
+ LIST_INSERT_HEAD(&named_sems, *sem, entry);
+ (*sem)->backpointer = sem;
+ _pthread_mutex_unlock(&named_sems_mtx);
+ return (sem);
+err:
+ _pthread_mutex_unlock(&named_sems_mtx);
+ ksem_close(semid);
+ if (sem != NULL) {
+ if (*sem != NULL)
+ sem_free(*sem);
+ else
+ errno = ENOSPC;
+ free(sem);
+ } else {
+ errno = ENOSPC;
+ }
+ return (SEM_FAILED);
+}
+
+int
+_libc_sem_close_compat(sem_t *sem)
+{
+
+ if (sem_check_validity(sem) != 0)
+ return (-1);
+
+ if ((*sem)->syssem == 0) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ _pthread_mutex_lock(&named_sems_mtx);
+ if (ksem_close((*sem)->semid) != 0) {
+ _pthread_mutex_unlock(&named_sems_mtx);
+ return (-1);
+ }
+ LIST_REMOVE((*sem), entry);
+ _pthread_mutex_unlock(&named_sems_mtx);
+ sem_free(*sem);
+ *sem = NULL;
+ free(sem);
+ return (0);
+}
+
+int
+_libc_sem_unlink_compat(const char *name)
+{
+
+ return (ksem_unlink(name));
+}
+
+static int
+_umtx_wait_uint(volatile unsigned *mtx, unsigned id, const struct timespec *abstime)
+{
+ struct _umtx_time *tm_p, timeout;
+ size_t tm_size;
+
+ if (abstime == NULL) {
+ tm_p = NULL;
+ tm_size = 0;
+ } else {
+ timeout._clockid = CLOCK_REALTIME;
+ timeout._flags = UMTX_ABSTIME;
+ timeout._timeout = *abstime;
+ tm_p = &timeout;
+ tm_size = sizeof(timeout);
+ }
+ return _umtx_op(__DEVOLATILE(void *, mtx),
+ UMTX_OP_WAIT_UINT_PRIVATE, id,
+ (void *)tm_size, __DECONST(void*, tm_p));
+}
+
+static int
+_umtx_wake(volatile void *mtx)
+{
+ return _umtx_op(__DEVOLATILE(void *, mtx), UMTX_OP_WAKE_PRIVATE,
+ 1, NULL, NULL);
+}
+
+#define TIMESPEC_SUB(dst, src, val) \
+ do { \
+ (dst)->tv_sec = (src)->tv_sec - (val)->tv_sec; \
+ (dst)->tv_nsec = (src)->tv_nsec - (val)->tv_nsec; \
+ if ((dst)->tv_nsec < 0) { \
+ (dst)->tv_sec--; \
+ (dst)->tv_nsec += 1000000000; \
+ } \
+ } while (0)
+
+
+static void
+sem_cancel_handler(void *arg)
+{
+ sem_t *sem = arg;
+
+ atomic_add_int(&(*sem)->nwaiters, -1);
+ if ((*sem)->nwaiters && (*sem)->count)
+ _umtx_wake(&(*sem)->count);
+}
+
+int
+_libc_sem_timedwait_compat(sem_t * __restrict sem,
+ const struct timespec * __restrict abstime)
+{
+ int val, retval;
+
+ if (sem_check_validity(sem) != 0)
+ return (-1);
+
+ if ((*sem)->syssem != 0) {
+ _pthread_cancel_enter(1);
+ retval = ksem_wait((*sem)->semid); /* XXX no timeout */
+ _pthread_cancel_leave(retval == -1);
+ return (retval);
+ }
+
+ retval = 0;
+ _pthread_testcancel();
+ for (;;) {
+ while ((val = (*sem)->count) > 0) {
+ if (atomic_cmpset_acq_int(&(*sem)->count, val, val - 1))
+ return (0);
+ }
+ if (retval) {
+ _pthread_testcancel();
+ break;
+ }
+ if (abstime) {
+ if (abstime->tv_nsec >= 1000000000 || abstime->tv_nsec < 0) {
+ errno = EINVAL;
+ return (-1);
+ }
+ }
+ atomic_add_int(&(*sem)->nwaiters, 1);
+ pthread_cleanup_push(sem_cancel_handler, sem);
+ _pthread_cancel_enter(1);
+ retval = _umtx_wait_uint(&(*sem)->count, 0, abstime);
+ _pthread_cancel_leave(0);
+ pthread_cleanup_pop(0);
+ atomic_add_int(&(*sem)->nwaiters, -1);
+ }
+ return (retval);
+}
+
+int
+_libc_sem_wait_compat(sem_t *sem)
+{
+ return _libc_sem_timedwait_compat(sem, NULL);
+}
+
+int
+_libc_sem_trywait_compat(sem_t *sem)
+{
+ int val;
+
+ if (sem_check_validity(sem) != 0)
+ return (-1);
+
+ if ((*sem)->syssem != 0)
+ return ksem_trywait((*sem)->semid);
+
+ while ((val = (*sem)->count) > 0) {
+ if (atomic_cmpset_acq_int(&(*sem)->count, val, val - 1))
+ return (0);
+ }
+ errno = EAGAIN;
+ return (-1);
+}
+
+int
+_libc_sem_post_compat(sem_t *sem)
+{
+
+ if (sem_check_validity(sem) != 0)
+ return (-1);
+
+ if ((*sem)->syssem != 0)
+ return ksem_post((*sem)->semid);
+
+ atomic_add_rel_int(&(*sem)->count, 1);
+ rmb();
+ if ((*sem)->nwaiters)
+ return _umtx_wake(&(*sem)->count);
+ return (0);
+}
+
+int
+_libc_sem_getvalue_compat(sem_t * __restrict sem, int * __restrict sval)
+{
+ int retval;
+
+ if (sem_check_validity(sem) != 0)
+ return (-1);
+
+ if ((*sem)->syssem != 0)
+ retval = ksem_getvalue((*sem)->semid, sval);
+ else {
+ *sval = (int)(*sem)->count;
+ retval = 0;
+ }
+ return (retval);
+}
diff --git a/lib/libc/gen/sem_destroy.3 b/lib/libc/gen/sem_destroy.3
new file mode 100644
index 000000000000..b43742065620
--- /dev/null
+++ b/lib/libc/gen/sem_destroy.3
@@ -0,0 +1,87 @@
+.\" Copyright (C) 2000 Jason Evans <jasone@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(s), this list of conditions and the following disclaimer as
+.\" the first lines of this file unmodified other than the possible
+.\" addition of one or more copyright notices.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice(s), this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+.\" EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+.\" OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+.\" EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd February 15, 2000
+.Dt SEM_DESTROY 3
+.Os
+.Sh NAME
+.Nm sem_destroy
+.Nd destroy an unnamed semaphore
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In semaphore.h
+.Ft int
+.Fn sem_destroy "sem_t *sem"
+.Sh DESCRIPTION
+The
+.Fn sem_destroy
+function destroys the unnamed semaphore pointed to by
+.Fa sem .
+After a successful call to
+.Fn sem_destroy ,
+.Fa sem
+is unusable until re-initialized by another call to
+.Xr sem_init 3 .
+.Sh RETURN VALUES
+.Rv -std sem_destroy
+.Sh ERRORS
+The
+.Fn sem_destroy
+function will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa sem
+argument
+points to an invalid semaphore.
+.It Bq Er EBUSY
+There are currently threads blocked on the semaphore that
+.Fa sem
+points to.
+.El
+.Sh SEE ALSO
+.Xr sem_init 3
+.Sh STANDARDS
+The
+.Fn sem_destroy
+function conforms to
+.St -p1003.1-96 .
+.Pp
+.Tn POSIX
+does not define the behavior of
+.Fn sem_destroy
+if called while there are threads blocked on
+.Fa sem ,
+but this implementation is guaranteed to return \-1 and set
+.Va errno
+to
+.Er EBUSY
+if there are threads blocked on
+.Fa sem .
diff --git a/lib/libc/gen/sem_getvalue.3 b/lib/libc/gen/sem_getvalue.3
new file mode 100644
index 000000000000..d81c2b17eaaa
--- /dev/null
+++ b/lib/libc/gen/sem_getvalue.3
@@ -0,0 +1,80 @@
+.\" Copyright (C) 2000 Jason Evans <jasone@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(s), this list of conditions and the following disclaimer as
+.\" the first lines of this file unmodified other than the possible
+.\" addition of one or more copyright notices.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice(s), this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+.\" EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+.\" OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+.\" EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd February 15, 2000
+.Dt SEM_GETVALUE 3
+.Os
+.Sh NAME
+.Nm sem_getvalue
+.Nd get the value of a semaphore
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In semaphore.h
+.Ft int
+.Fn sem_getvalue "sem_t * restrict sem" "int * restrict sval"
+.Sh DESCRIPTION
+The
+.Fn sem_getvalue
+function sets the variable pointed to by
+.Fa sval
+to the current value of the semaphore pointed to by
+.Fa sem ,
+as of the time that the call to
+.Fn sem_getvalue
+is actually run.
+.Sh RETURN VALUES
+.Rv -std sem_getvalue
+.Sh ERRORS
+The
+.Fn sem_getvalue
+function will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa sem
+argument
+points to an invalid semaphore.
+.El
+.Sh SEE ALSO
+.Xr sem_post 3 ,
+.Xr sem_trywait 3 ,
+.Xr sem_wait 3
+.Sh STANDARDS
+The
+.Fn sem_getvalue
+function conforms to
+.St -p1003.1-96 .
+.Pp
+The value of the semaphore is never negative, even if there are threads blocked
+on the semaphore.
+.Tn POSIX
+is somewhat ambiguous in its wording with regard to
+what the value of the semaphore should be if there are blocked waiting threads,
+but this behavior is conformant, given the wording of the specification.
diff --git a/lib/libc/gen/sem_init.3 b/lib/libc/gen/sem_init.3
new file mode 100644
index 000000000000..a96749b0bad2
--- /dev/null
+++ b/lib/libc/gen/sem_init.3
@@ -0,0 +1,101 @@
+.\" Copyright (C) 2000 Jason Evans <jasone@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(s), this list of conditions and the following disclaimer as
+.\" the first lines of this file unmodified other than the possible
+.\" addition of one or more copyright notices.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice(s), this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+.\" EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+.\" OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+.\" EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd January 9, 2010
+.Dt SEM_INIT 3
+.Os
+.Sh NAME
+.Nm sem_init
+.Nd initialize an unnamed semaphore
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In semaphore.h
+.Ft int
+.Fn sem_init "sem_t *sem" "int pshared" "unsigned int value"
+.Sh DESCRIPTION
+The
+.Fn sem_init
+function initializes the unnamed semaphore pointed to by
+.Fa sem
+to have the value
+.Fa value .
+.Pp
+A non-zero value for
+.Fa pshared
+specifies a shared semaphore that can be used by multiple processes,
+the semaphore should be located in shared memory region (see
+.Xr mmap 2 ,
+.Xr shm_open 2 ,
+and
+.Xr shmget 2 ) ,
+any process having read and write access to address
+.Fa sem
+can perform semaphore operations on
+.Fa sem .
+.Pp
+Following a successful call to
+.Fn sem_init ,
+.Fa sem
+can be used as an argument in subsequent calls to
+.Xr sem_wait 3 ,
+.Xr sem_trywait 3 ,
+.Xr sem_post 3 ,
+and
+.Xr sem_destroy 3 .
+The
+.Fa sem
+argument is no longer valid after a successful call to
+.Xr sem_destroy 3 .
+.Sh RETURN VALUES
+.Rv -std sem_init
+.Sh ERRORS
+The
+.Fn sem_init
+function will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa value
+argument exceeds
+.Dv SEM_VALUE_MAX .
+.It Bq Er ENOSPC
+Memory allocation error.
+.El
+.Sh SEE ALSO
+.Xr sem_destroy 3 ,
+.Xr sem_getvalue 3 ,
+.Xr sem_post 3 ,
+.Xr sem_trywait 3 ,
+.Xr sem_wait 3
+.Sh STANDARDS
+The
+.Fn sem_init
+function conforms to
+.St -p1003.1-96 .
diff --git a/lib/libc/gen/sem_new.c b/lib/libc/gen/sem_new.c
new file mode 100644
index 000000000000..8fe027f12449
--- /dev/null
+++ b/lib/libc/gen/sem_new.c
@@ -0,0 +1,452 @@
+/*
+ * Copyright (C) 2010 David Xu <davidxu@freebsd.org>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice(s), this list of conditions and the following disclaimer as
+ * the first lines of this file unmodified other than the possible
+ * addition of one or more copyright notices.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice(s), this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <machine/atomic.h>
+#include <sys/umtx.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <semaphore.h>
+#include <unistd.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+
+__weak_reference(_sem_close, sem_close);
+__weak_reference(_sem_destroy, sem_destroy);
+__weak_reference(_sem_getvalue, sem_getvalue);
+__weak_reference(_sem_init, sem_init);
+__weak_reference(_sem_open, sem_open);
+__weak_reference(_sem_post, sem_post);
+__weak_reference(_sem_timedwait, sem_timedwait);
+__weak_reference(_sem_trywait, sem_trywait);
+__weak_reference(_sem_unlink, sem_unlink);
+__weak_reference(_sem_wait, sem_wait);
+
+#define SEM_PREFIX "/tmp/SEMD"
+#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;
+ char *name;
+ dev_t dev;
+ ino_t ino;
+ sem_t *sem;
+ LIST_ENTRY(sem_nameinfo) next;
+};
+
+static pthread_once_t once = PTHREAD_ONCE_INIT;
+static pthread_mutex_t sem_llock;
+static LIST_HEAD(,sem_nameinfo) sem_list = LIST_HEAD_INITIALIZER(sem_list);
+
+static void
+sem_prefork()
+{
+
+ _pthread_mutex_lock(&sem_llock);
+}
+
+static void
+sem_postfork()
+{
+ _pthread_mutex_unlock(&sem_llock);
+}
+
+static void
+sem_child_postfork()
+{
+ _pthread_mutex_unlock(&sem_llock);
+}
+
+static void
+sem_module_init(void)
+{
+ pthread_mutexattr_t ma;
+
+ _pthread_mutexattr_init(&ma);
+ _pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_RECURSIVE);
+ _pthread_mutex_init(&sem_llock, &ma);
+ _pthread_mutexattr_destroy(&ma);
+ _pthread_atfork(sem_prefork, sem_postfork, sem_child_postfork);
+}
+
+static inline int
+sem_check_validity(sem_t *sem)
+{
+
+ if (sem->_magic == SEM_MAGIC)
+ return (0);
+ else {
+ errno = EINVAL;
+ return (-1);
+ }
+}
+
+int
+_sem_init(sem_t *sem, int pshared, unsigned int value)
+{
+
+ if (value > SEM_VALUE_MAX) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ bzero(sem, sizeof(sem_t));
+ sem->_magic = SEM_MAGIC;
+ sem->_kern._count = (u_int32_t)value;
+ sem->_kern._flags = pshared ? USYNC_PROCESS_SHARED : 0;
+ return (0);
+}
+
+sem_t *
+_sem_open(const char *name, int flags, ...)
+{
+ char path[PATH_MAX];
+
+ struct stat sb;
+ va_list ap;
+ struct sem_nameinfo *ni = NULL;
+ sem_t *sem = NULL;
+ int fd = -1, mode, len, errsave;
+ int value = 0;
+
+ if (name[0] != '/') {
+ errno = EINVAL;
+ return (SEM_FAILED);
+ }
+ name++;
+ strcpy(path, SEM_PREFIX);
+ if (strlcat(path, name, sizeof(path)) >= sizeof(path)) {
+ errno = ENAMETOOLONG;
+ return (SEM_FAILED);
+ }
+ if (flags & ~(O_CREAT|O_EXCL)) {
+ errno = EINVAL;
+ return (SEM_FAILED);
+ }
+ if ((flags & O_CREAT) != 0) {
+ va_start(ap, flags);
+ mode = va_arg(ap, int);
+ value = va_arg(ap, int);
+ va_end(ap);
+ }
+ fd = -1;
+ _pthread_once(&once, sem_module_init);
+
+ _pthread_mutex_lock(&sem_llock);
+ LIST_FOREACH(ni, &sem_list, next) {
+ if (ni->name != NULL && strcmp(name, ni->name) == 0) {
+ fd = _open(path, flags | O_RDWR | O_CLOEXEC |
+ O_EXLOCK, mode);
+ if (fd == -1 || _fstat(fd, &sb) == -1) {
+ ni = NULL;
+ goto error;
+ }
+ if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT |
+ O_EXCL) || ni->dev != sb.st_dev ||
+ ni->ino != sb.st_ino) {
+ ni->name = NULL;
+ ni = NULL;
+ break;
+ }
+ ni->open_count++;
+ sem = ni->sem;
+ _pthread_mutex_unlock(&sem_llock);
+ _close(fd);
+ return (sem);
+ }
+ }
+
+ len = sizeof(*ni) + strlen(name) + 1;
+ ni = (struct sem_nameinfo *)malloc(len);
+ if (ni == NULL) {
+ errno = ENOSPC;
+ goto error;
+ }
+
+ ni->name = (char *)(ni+1);
+ strcpy(ni->name, name);
+
+ if (fd == -1) {
+ fd = _open(path, flags | O_RDWR | O_CLOEXEC | O_EXLOCK, mode);
+ if (fd == -1 || _fstat(fd, &sb) == -1)
+ goto error;
+ }
+ if (sb.st_size < sizeof(sem_t)) {
+ sem_t tmp;
+
+ tmp._magic = SEM_MAGIC;
+ tmp._kern._count = value;
+ tmp._kern._flags = USYNC_PROCESS_SHARED | SEM_NAMED;
+ if (_write(fd, &tmp, sizeof(tmp)) != sizeof(tmp))
+ goto error;
+ }
+ flock(fd, LOCK_UN);
+ sem = (sem_t *)mmap(NULL, sizeof(sem_t), PROT_READ|PROT_WRITE,
+ MAP_SHARED|MAP_NOSYNC, fd, 0);
+ if (sem == MAP_FAILED) {
+ sem = NULL;
+ if (errno == ENOMEM)
+ errno = ENOSPC;
+ goto error;
+ }
+ if (sem->_magic != SEM_MAGIC) {
+ errno = EINVAL;
+ goto error;
+ }
+ ni->open_count = 1;
+ ni->sem = sem;
+ ni->dev = sb.st_dev;
+ ni->ino = sb.st_ino;
+ LIST_INSERT_HEAD(&sem_list, ni, next);
+ _close(fd);
+ _pthread_mutex_unlock(&sem_llock);
+ return (sem);
+
+error:
+ errsave = errno;
+ if (fd != -1)
+ _close(fd);
+ if (sem != NULL)
+ munmap(sem, sizeof(sem_t));
+ free(ni);
+ _pthread_mutex_unlock(&sem_llock);
+ errno = errsave;
+ return (SEM_FAILED);
+}
+
+int
+_sem_close(sem_t *sem)
+{
+ struct sem_nameinfo *ni;
+
+ if (sem_check_validity(sem) != 0)
+ return (-1);
+
+ if (!(sem->_kern._flags & SEM_NAMED)) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ _pthread_once(&once, sem_module_init);
+
+ _pthread_mutex_lock(&sem_llock);
+ LIST_FOREACH(ni, &sem_list, next) {
+ if (sem == ni->sem) {
+ if (--ni->open_count > 0) {
+ _pthread_mutex_unlock(&sem_llock);
+ return (0);
+ }
+ else
+ break;
+ }
+ }
+
+ if (ni) {
+ LIST_REMOVE(ni, next);
+ _pthread_mutex_unlock(&sem_llock);
+ munmap(sem, sizeof(*sem));
+ free(ni);
+ return (0);
+ }
+ _pthread_mutex_unlock(&sem_llock);
+ errno = EINVAL;
+ return (-1);
+}
+
+int
+_sem_unlink(const char *name)
+{
+ char path[PATH_MAX];
+
+ if (name[0] != '/') {
+ errno = ENOENT;
+ return -1;
+ }
+ name++;
+ strcpy(path, SEM_PREFIX);
+ if (strlcat(path, name, sizeof(path)) >= sizeof(path)) {
+ errno = ENAMETOOLONG;
+ return (-1);
+ }
+
+ return (unlink(path));
+}
+
+int
+_sem_destroy(sem_t *sem)
+{
+
+ if (sem_check_validity(sem) != 0)
+ return (-1);
+
+ if (sem->_kern._flags & SEM_NAMED) {
+ errno = EINVAL;
+ return (-1);
+ }
+ sem->_magic = 0;
+ return (0);
+}
+
+int
+_sem_getvalue(sem_t * __restrict sem, int * __restrict sval)
+{
+
+ if (sem_check_validity(sem) != 0)
+ return (-1);
+
+ *sval = (int)USEM_COUNT(sem->_kern._count);
+ return (0);
+}
+
+static __inline int
+usem_wake(struct _usem2 *sem)
+{
+ return _umtx_op(sem, UMTX_OP_SEM2_WAKE, 0, NULL, NULL);
+}
+
+static __inline int
+usem_wait(struct _usem2 *sem, const struct timespec *abstime)
+{
+ struct _umtx_time *tm_p, timeout;
+ size_t tm_size;
+
+ if (abstime == NULL) {
+ tm_p = NULL;
+ tm_size = 0;
+ } else {
+ timeout._clockid = CLOCK_REALTIME;
+ timeout._flags = UMTX_ABSTIME;
+ timeout._timeout = *abstime;
+ tm_p = &timeout;
+ tm_size = sizeof(timeout);
+ }
+ return _umtx_op(sem, UMTX_OP_SEM2_WAIT, 0,
+ (void *)tm_size, __DECONST(void*, tm_p));
+}
+
+int
+_sem_trywait(sem_t *sem)
+{
+ int val;
+
+ if (sem_check_validity(sem) != 0)
+ return (-1);
+
+ while (USEM_COUNT(val = sem->_kern._count) > 0) {
+ if (atomic_cmpset_acq_int(&sem->_kern._count, val, val - 1))
+ return (0);
+ }
+ errno = EAGAIN;
+ return (-1);
+}
+
+int
+_sem_timedwait(sem_t * __restrict sem,
+ const struct timespec * __restrict abstime)
+{
+ int val, retval;
+
+ if (sem_check_validity(sem) != 0)
+ return (-1);
+
+ retval = 0;
+ _pthread_testcancel();
+ for (;;) {
+ while (USEM_COUNT(val = sem->_kern._count) > 0) {
+ if (atomic_cmpset_acq_int(&sem->_kern._count, val, val - 1))
+ return (0);
+ }
+
+ if (retval) {
+ _pthread_testcancel();
+ break;
+ }
+
+ /*
+ * The timeout argument is only supposed to
+ * be checked if the thread would have blocked.
+ */
+ if (abstime != NULL) {
+ if (abstime->tv_nsec >= 1000000000 || abstime->tv_nsec < 0) {
+ errno = EINVAL;
+ return (-1);
+ }
+ }
+ _pthread_cancel_enter(1);
+ retval = usem_wait(&sem->_kern, abstime);
+ _pthread_cancel_leave(0);
+ }
+ return (retval);
+}
+
+int
+_sem_wait(sem_t *sem)
+{
+ return _sem_timedwait(sem, NULL);
+}
+
+/*
+ * POSIX:
+ * The sem_post() interface is reentrant with respect to signals and may be
+ * invoked from a signal-catching function.
+ * The implementation does not use lock, so it should be safe.
+ */
+int
+_sem_post(sem_t *sem)
+{
+ unsigned int count;
+
+ if (sem_check_validity(sem) != 0)
+ return (-1);
+
+ do {
+ count = sem->_kern._count;
+ if (USEM_COUNT(count) + 1 > SEM_VALUE_MAX) {
+ errno = EOVERFLOW;
+ return (-1);
+ }
+ } 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
new file mode 100644
index 000000000000..2fdc01934172
--- /dev/null
+++ b/lib/libc/gen/sem_open.3
@@ -0,0 +1,224 @@
+.\" Copyright (C) 2000 Jason Evans <jasone@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(s), this list of conditions and the following disclaimer as
+.\" the first lines of this file unmodified other than the possible
+.\" addition of one or more copyright notices.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice(s), this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+.\" EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+.\" OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+.\" EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd January 9, 2010
+.Dt SEM_OPEN 3
+.Os
+.Sh NAME
+.Nm sem_open ,
+.Nm sem_close ,
+.Nm sem_unlink
+.Nd named semaphore operations
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In semaphore.h
+.Ft "sem_t *"
+.Fn sem_open "const char *name" "int oflag" ...
+.Ft int
+.Fn sem_close "sem_t *sem"
+.Ft int
+.Fn sem_unlink "const char *name"
+.Sh DESCRIPTION
+The
+.Fn sem_open
+function creates or opens the named semaphore specified by
+.Fa name .
+The returned semaphore may be used in subsequent calls to
+.Xr sem_getvalue 3 ,
+.Xr sem_wait 3 ,
+.Xr sem_trywait 3 ,
+.Xr sem_post 3 ,
+and
+.Fn sem_close .
+.Pp
+This implementation places strict requirements on the value of
+.Fa name :
+it must begin with a slash
+.Pq Ql /
+and contain no other slash characters.
+.Pp
+The following bits may be set in the
+.Fa oflag
+argument:
+.Bl -tag -width ".Dv O_CREAT"
+.It Dv O_CREAT
+Create the semaphore if it does not already exist.
+.Pp
+The third argument to the call to
+.Fn sem_open
+must be of type
+.Vt mode_t
+and specifies the mode for the semaphore.
+Only the
+.Dv S_IWUSR , S_IWGRP ,
+and
+.Dv S_IWOTH
+bits are examined;
+it is not possible to grant only
+.Dq read
+permission on a semaphore.
+The mode is modified according to the process's file creation
+mask; see
+.Xr umask 2 .
+.Pp
+The fourth argument must be an
+.Vt "unsigned int"
+and specifies the initial value for the semaphore,
+and must be no greater than
+.Dv SEM_VALUE_MAX .
+.It Dv O_EXCL
+Create the semaphore if it does not exist.
+If the semaphore already exists,
+.Fn sem_open
+will fail.
+This flag is ignored unless
+.Dv O_CREAT
+is also specified.
+.El
+.Pp
+The
+.Fn sem_close
+function closes a named semaphore that was opened by a call to
+.Fn sem_open .
+.Pp
+The
+.Fn sem_unlink
+function removes the semaphore named
+.Fa name .
+Resources allocated to the semaphore are only deallocated when all
+processes that have the semaphore open close it.
+.Sh RETURN VALUES
+If successful,
+the
+.Fn sem_open
+function returns the address of the opened semaphore.
+If the same
+.Fa name
+argument is given to multiple calls to
+.Fn sem_open
+by the same process without an intervening call to
+.Fn sem_close ,
+the same address is returned each time.
+If the semaphore cannot be opened,
+.Fn sem_open
+returns
+.Dv SEM_FAILED
+and the global variable
+.Va errno
+is set to indicate the error.
+.Pp
+.Rv -std sem_close sem_unlink
+.Sh ERRORS
+The
+.Fn sem_open
+function will fail if:
+.Bl -tag -width Er
+.It Bq Er EACCES
+The semaphore exists and the permissions specified by
+.Fa oflag
+at the time it was created deny access to this process.
+.It Bq Er EACCES
+The semaphore does not exist, but permission to create it is denied.
+.It Bq Er EEXIST
+.Dv O_CREAT
+and
+.Dv O_EXCL
+are set but the semaphore already exists.
+.It Bq Er EINTR
+The call was interrupted by a signal.
+.It Bq Er EINVAL
+The
+.Fn sem_open
+operation is not supported for the given
+.Fa name .
+.It Bq Er EINVAL
+The
+.Fa value
+argument is greater than
+.Dv SEM_VALUE_MAX .
+.\"FreeBSD never returns EMFILE
+.\".It Bq Er EMFILE
+.\"Too many semaphores are in use by this process.
+.It Bq Er ENAMETOOLONG
+The
+.Fa name
+argument is too long.
+.It Bq Er ENFILE
+The system limit on semaphores has been reached.
+.It Bq Er ENOENT
+.Dv O_CREAT
+is not set but the named semaphore does not exist.
+.It Bq Er ENOSPC
+There is not enough space to create the semaphore.
+.El
+.Pp
+The
+.Fn sem_close
+function will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa sem
+argument is not a valid semaphore.
+.El
+.Pp
+The
+.Fn sem_unlink
+function will fail if:
+.Bl -tag -width Er
+.It Bq Er EACCES
+Permission is denied to unlink the semaphore.
+.It Bq Er ENAMETOOLONG
+The specified
+.Fa name
+is too long.
+.It Bq Er ENOENT
+The named semaphore does not exist.
+.El
+.Sh SEE ALSO
+.Xr close 2 ,
+.Xr open 2 ,
+.Xr umask 2 ,
+.Xr unlink 2 ,
+.Xr sem_getvalue 3 ,
+.Xr sem_post 3 ,
+.Xr sem_trywait 3 ,
+.Xr sem_wait 3
+.Sh STANDARDS
+The
+.Fn sem_open ,
+.Fn sem_close ,
+and
+.Fn sem_unlink
+functions conform to
+.St -p1003.1-96 .
+.Sh HISTORY
+Support for named semaphores first appeared in
+.Fx 5.0 .
diff --git a/lib/libc/gen/sem_post.3 b/lib/libc/gen/sem_post.3
new file mode 100644
index 000000000000..dea8eb697169
--- /dev/null
+++ b/lib/libc/gen/sem_post.3
@@ -0,0 +1,80 @@
+.\" Copyright (C) 2000 Jason Evans <jasone@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(s), this list of conditions and the following disclaimer as
+.\" the first lines of this file unmodified other than the possible
+.\" addition of one or more copyright notices.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice(s), this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+.\" EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+.\" OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+.\" EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd January 28, 2015
+.Dt SEM_POST 3
+.Os
+.Sh NAME
+.Nm sem_post
+.Nd increment (unlock) a semaphore
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In semaphore.h
+.Ft int
+.Fn sem_post "sem_t *sem"
+.Sh DESCRIPTION
+The
+.Fn sem_post
+function increments (unlocks) the semaphore pointed to by
+.Fa sem .
+If there are threads blocked on the semaphore when
+.Fn sem_post
+is called, then the highest priority thread that has been blocked the longest on
+the semaphore will be allowed to return from
+.Fn sem_wait .
+.Pp
+The
+.Fn sem_post
+function is signal-reentrant and may be called within signal handlers.
+.Sh RETURN VALUES
+.Rv -std sem_post
+.Sh ERRORS
+The
+.Fn sem_post
+function will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa sem
+argument
+points to an invalid semaphore.
+.It Bq Er EOVERFLOW
+The semaphore value would exceed
+.Dv SEM_VALUE_MAX .
+.El
+.Sh SEE ALSO
+.Xr sem_getvalue 3 ,
+.Xr sem_trywait 3 ,
+.Xr sem_wait 3
+.Sh STANDARDS
+The
+.Fn sem_post
+function conforms to
+.St -p1003.1-96 .
diff --git a/lib/libc/gen/sem_timedwait.3 b/lib/libc/gen/sem_timedwait.3
new file mode 100644
index 000000000000..16d107369ea0
--- /dev/null
+++ b/lib/libc/gen/sem_timedwait.3
@@ -0,0 +1,119 @@
+.\" Copyright (c) 2008, David Xu <davidxu@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" Portions of this text are reprinted and reproduced in electronic form
+.\" from IEEE Std 1003.1, 2004 Edition, Standard for Information Technology --
+.\" Portable Operating System Interface (POSIX), The Open Group Base
+.\" Specifications Issue 6, Copyright (C) 2001-2004 by the Institute of
+.\" Electrical and Electronics Engineers, Inc and The Open Group. In the
+.\" event of any discrepancy between this version and the original IEEE and
+.\" The Open Group Standard, the original IEEE and The Open Group Standard is
+.\" the referee document. The original Standard can be obtained online at
+.\" http://www.opengroup.org/unix/online.html.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd August 17, 2016
+.Dt SEM_TIMEDWAIT 3
+.Os
+.Sh NAME
+.Nm sem_timedwait
+.Nd "lock a semaphore"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In semaphore.h
+.Ft int
+.Fn sem_timedwait "sem_t * restrict sem" "const struct timespec * restrict abs_timeout"
+.Sh DESCRIPTION
+The
+.Fn sem_timedwait
+function locks the semaphore referenced by
+.Fa sem ,
+as in the
+.Xr sem_wait 3
+function.
+However, if the semaphore cannot be locked without waiting for
+another process or thread to unlock the semaphore by performing
+a
+.Xr sem_post 3
+function, this wait will be terminated when the specified timeout expires.
+.Pp
+The timeout will expire when the absolute time specified by
+.Fa abs_timeout
+passes, as measured by the clock on which timeouts are based (that is,
+when the value of that clock equals or exceeds
+.Fa abs_timeout ) ,
+or if the
+absolute time specified by
+.Fa abs_timeout
+has already been passed at the time of the call.
+.Pp
+Note that the timeout is based on the
+.Dv CLOCK_REALTIME
+clock.
+.Pp
+The validity of the
+.Fa abs_timeout
+is not checked if the semaphore can be locked immediately.
+.Sh RETURN VALUES
+The
+.Fn sem_timedwait
+function returns zero if the calling process successfully performed the
+semaphore lock operation on the semaphore designated by
+.Fa sem .
+If the call was unsuccessful, the state of the semaphore is unchanged,
+and the function returns a value of \-1 and sets the global variable
+.Va errno
+to indicate the error.
+.Sh ERRORS
+The
+.Fn sem_timedwait
+function will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa sem
+argument does not refer to a valid semaphore, or the process or thread would
+have blocked, and the
+.Fa abs_timeout
+parameter specified a nanoseconds field value less than zero or greater than
+or equal to 1000 million.
+.It Bq Er ETIMEDOUT
+The semaphore could not be locked before the specified timeout expired.
+.It Bq Er EINTR
+A signal interrupted this function.
+.El
+.Sh SEE ALSO
+.Xr sem_post 3 ,
+.Xr sem_trywait 3 ,
+.Xr sem_wait 3
+.Sh STANDARDS
+The
+.Fn sem_timedwait
+function conforms to
+.St -p1003.1-2004 .
+.Sh HISTORY
+The function first appeared in
+.Fx 5.0 .
diff --git a/lib/libc/gen/sem_wait.3 b/lib/libc/gen/sem_wait.3
new file mode 100644
index 000000000000..cb5a2f68b782
--- /dev/null
+++ b/lib/libc/gen/sem_wait.3
@@ -0,0 +1,102 @@
+.\" Copyright (C) 2000 Jason Evans <jasone@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(s), this list of conditions and the following disclaimer as
+.\" the first lines of this file unmodified other than the possible
+.\" addition of one or more copyright notices.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice(s), this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+.\" EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+.\" OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+.\" EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd April 16, 2013
+.Dt SEM_WAIT 3
+.Os
+.Sh NAME
+.Nm sem_wait ,
+.Nm sem_trywait
+.Nd decrement (lock) a semaphore
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In semaphore.h
+.Ft int
+.Fn sem_wait "sem_t *sem"
+.Ft int
+.Fn sem_trywait "sem_t *sem"
+.Sh DESCRIPTION
+The
+.Fn sem_wait
+function decrements (locks) the semaphore pointed to by
+.Fa sem ,
+but blocks if the value of
+.Fa sem
+is zero, until the value is non-zero and the value can be decremented.
+.Pp
+The
+.Fn sem_trywait
+function decrements (locks) the semaphore pointed to by
+.Fa sem
+only if the value is non-zero.
+Otherwise, the semaphore is not decremented and
+an error is returned.
+.Sh RETURN VALUES
+.Rv -std
+.Sh ERRORS
+The
+.Fn sem_wait
+and
+.Fn sem_trywait
+functions will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa sem
+argument
+points to an invalid semaphore.
+.El
+.Pp
+Additionally,
+.Fn sem_wait
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EINTR
+A signal interrupted this function.
+.El
+.Pp
+Additionally,
+.Fn sem_trywait
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EAGAIN
+The semaphore value was zero, and thus could not be decremented.
+.El
+.Sh SEE ALSO
+.Xr sem_getvalue 3 ,
+.Xr sem_post 3 ,
+.Xr sem_timedwait 3
+.Sh STANDARDS
+The
+.Fn sem_wait
+and
+.Fn sem_trywait
+functions conform to
+.St -p1003.1-96 .
diff --git a/lib/libc/gen/semctl.c b/lib/libc/gen/semctl.c
new file mode 100644
index 000000000000..0e418f6d058e
--- /dev/null
+++ b/lib/libc/gen/semctl.c
@@ -0,0 +1,90 @@
+/*-
+ * Copyright (c) 2002 Doug Rabson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifndef NO_COMPAT7
+#define _WANT_SEMUN_OLD
+#endif
+
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/sem.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+int __semctl(int semid, int semnum, int cmd, union semun *arg);
+#ifndef NO_COMPAT7
+int freebsd7___semctl(int semid, int semnum, int cmd, union semun_old *arg);
+int freebsd7_semctl(int semid, int semnum, int cmd, ...);
+#endif
+
+int
+semctl(int semid, int semnum, int cmd, ...)
+{
+ va_list ap;
+ union semun semun;
+ union semun *semun_ptr;
+
+ va_start(ap, cmd);
+ if (cmd == IPC_SET || cmd == IPC_STAT || cmd == GETALL
+ || cmd == SETVAL || cmd == SETALL) {
+ semun = va_arg(ap, union semun);
+ semun_ptr = &semun;
+ } else {
+ semun_ptr = NULL;
+ }
+ va_end(ap);
+
+ return (__semctl(semid, semnum, cmd, semun_ptr));
+}
+
+#ifndef NO_COMPAT7
+int
+freebsd7_semctl(int semid, int semnum, int cmd, ...)
+{
+ va_list ap;
+ union semun_old semun;
+ union semun_old *semun_ptr;
+
+ va_start(ap, cmd);
+ if (cmd == IPC_SET || cmd == IPC_STAT || cmd == GETALL
+ || cmd == SETVAL || cmd == SETALL) {
+ semun = va_arg(ap, union semun_old);
+ semun_ptr = &semun;
+ } else {
+ semun_ptr = NULL;
+ }
+ va_end(ap);
+
+ return (freebsd7___semctl(semid, semnum, cmd, semun_ptr));
+}
+
+__sym_compat(semctl, freebsd7_semctl, FBSD_1.0);
+#endif
diff --git a/lib/libc/gen/sendmmsg.c b/lib/libc/gen/sendmmsg.c
new file mode 100644
index 000000000000..7b3e8f357613
--- /dev/null
+++ b/lib/libc/gen/sendmmsg.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2016 Boris Astardzhiev, Smartcom-Bulgaria AD
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice(s), this list of conditions and the following disclaimer as
+ * the first lines of this file unmodified other than the possible
+ * addition of one or more copyright notices.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice(s), this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "libc_private.h"
+
+ssize_t
+sendmmsg(int s, struct mmsghdr *__restrict msgvec, size_t vlen, int flags)
+{
+ size_t i, sent;
+ ssize_t ret;
+
+ sent = 0;
+ for (i = 0; i < vlen; i++, sent++) {
+ ret = __sys_sendmsg(s, &msgvec[i].msg_hdr, flags);
+ if (ret == -1) {
+ if (sent != 0) {
+ /*
+ * We have sent messages. Let caller
+ * know about the data sent, socket
+ * error is returned on next
+ * invocation.
+ */
+ return (sent);
+ }
+ return (ret);
+ }
+
+ /* Save sent bytes. */
+ msgvec[i].msg_len = ret;
+ }
+
+ return (sent);
+}
diff --git a/lib/libc/gen/setdomainname.c b/lib/libc/gen/setdomainname.c
new file mode 100644
index 000000000000..cba67a759a7d
--- /dev/null
+++ b/lib/libc/gen/setdomainname.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)sethostname.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/sysctl.h>
+
+#include <unistd.h>
+
+int
+setdomainname(const char *name, int namelen)
+{
+ int mib[2];
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_NISDOMAINNAME;
+ if (sysctl(mib, 2, NULL, NULL, (void *)name, namelen) == -1)
+ return (-1);
+ return (0);
+}
diff --git a/lib/libc/gen/sethostname.c b/lib/libc/gen/sethostname.c
new file mode 100644
index 000000000000..466ff577b29b
--- /dev/null
+++ b/lib/libc/gen/sethostname.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)sethostname.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/sysctl.h>
+
+#include <unistd.h>
+
+int
+sethostname(const char *name, int namelen)
+{
+ int mib[2];
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_HOSTNAME;
+ if (sysctl(mib, 2, NULL, NULL, (void *)name, namelen) == -1)
+ return (-1);
+ return (0);
+}
diff --git a/lib/libc/gen/setjmp.3 b/lib/libc/gen/setjmp.3
new file mode 100644
index 000000000000..5c995f0ae677
--- /dev/null
+++ b/lib/libc/gen/setjmp.3
@@ -0,0 +1,172 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)setjmp.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt SETJMP 3
+.Os
+.Sh NAME
+.Nm sigsetjmp ,
+.Nm siglongjmp ,
+.Nm setjmp ,
+.Nm longjmp ,
+.Nm _setjmp ,
+.Nm _longjmp ,
+.Nm longjmperror
+.Nd non-local jumps
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In setjmp.h
+.Ft int
+.Fn sigsetjmp "sigjmp_buf env" "int savemask"
+.Ft void
+.Fn siglongjmp "sigjmp_buf env" "int val"
+.Ft int
+.Fn setjmp "jmp_buf env"
+.Ft void
+.Fn longjmp "jmp_buf env" "int val"
+.Ft int
+.Fn _setjmp "jmp_buf env"
+.Ft void
+.Fn _longjmp "jmp_buf env" "int val"
+.Ft void
+.Fn longjmperror void
+.Sh DESCRIPTION
+The
+.Fn sigsetjmp ,
+.Fn setjmp ,
+and
+.Fn _setjmp
+functions save their calling environment in
+.Fa env .
+Each of these functions returns 0.
+.Pp
+The corresponding
+.Fn longjmp
+functions restore the environment saved by their most recent respective
+invocations
+of the
+.Fn setjmp
+function.
+They then return so that program execution continues as if the corresponding
+invocation of the
+.Fn setjmp
+call had just returned the value specified by
+.Fa val ,
+instead of 0.
+.Pp
+Pairs of calls may be intermixed, i.e., both
+.Fn sigsetjmp
+and
+.Fn siglongjmp
+and
+.Fn setjmp
+and
+.Fn longjmp
+combinations may be used in the same program, however, individual
+calls may not, e.g.\& the
+.Fa env
+argument to
+.Fn setjmp
+may not be passed to
+.Fn siglongjmp .
+.Pp
+The
+.Fn longjmp
+routines may not be called after the routine which called the
+.Fn setjmp
+routines returns.
+.Pp
+All accessible objects have values as of the time
+.Fn longjmp
+routine was called, except that the values of objects of automatic storage
+invocation duration that do not have the
+.Vt volatile
+type and have been changed between the
+.Fn setjmp
+invocation and
+.Fn longjmp
+call are indeterminate.
+.Pp
+The
+.Fn setjmp Ns / Ns Fn longjmp
+pairs save and restore the signal mask while
+.Fn _setjmp Ns / Ns Fn _longjmp
+pairs save and restore only the register set and the stack.
+(See
+.Fn sigprocmask 2 . )
+.Pp
+The
+.Fn sigsetjmp Ns / Ns Fn siglongjmp
+function
+pairs save and restore the signal mask if the argument
+.Fa savemask
+is non-zero, otherwise only the register set and the stack are saved.
+.Sh ERRORS
+If the contents of the
+.Fa env
+are corrupted, or correspond to an environment that has already returned,
+the
+.Fn longjmp
+routine calls the routine
+.Fn longjmperror 3 .
+If
+.Fn longjmperror
+returns the program is aborted (see
+.Xr abort 3 ) .
+The default version of
+.Fn longjmperror
+prints the message
+.Dq Li longjmp botch
+to standard error and returns.
+User programs wishing to exit more gracefully should write their own
+versions of
+.Fn longjmperror .
+.Sh SEE ALSO
+.Xr sigaction 2 ,
+.Xr sigaltstack 2 ,
+.Xr signal 3
+.Sh STANDARDS
+The
+.Fn setjmp
+and
+.Fn longjmp
+functions conform to
+.St -isoC .
+The
+.Fn sigsetjmp
+and
+.Fn siglongjmp
+functions conform to
+.St -p1003.1-88 .
diff --git a/lib/libc/gen/setjmperr.c b/lib/libc/gen/setjmperr.c
new file mode 100644
index 000000000000..90fa4aa45af0
--- /dev/null
+++ b/lib/libc/gen/setjmperr.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)setjmperr.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * This routine is called from longjmp() when an error occurs.
+ * Programs that wish to exit gracefully from this error may
+ * write their own versions.
+ * If this routine returns, the program is aborted.
+ */
+
+#include "namespace.h"
+#include <setjmp.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+void
+longjmperror(void)
+{
+#define ERRMSG "longjmp botch.\n"
+ (void)_write(STDERR_FILENO, ERRMSG, sizeof(ERRMSG) - 1);
+}
diff --git a/lib/libc/gen/setmode.3 b/lib/libc/gen/setmode.3
new file mode 100644
index 000000000000..684c2e1d2bbf
--- /dev/null
+++ b/lib/libc/gen/setmode.3
@@ -0,0 +1,127 @@
+.\" Copyright (c) 1989, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)setmode.3 8.2 (Berkeley) 4/28/95
+.\" $FreeBSD$
+.\"
+.Dd February 22, 2015
+.Dt SETMODE 3
+.Os
+.Sh NAME
+.Nm getmode ,
+.Nm setmode
+.Nd modify mode bits
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft mode_t
+.Fn getmode "const void *set" "mode_t mode"
+.Ft void *
+.Fn setmode "const char *mode_str"
+.Sh DESCRIPTION
+The
+.Fn getmode
+function
+returns a copy of the file permission bits
+.Fa mode
+as altered by the values pointed to by
+.Fa set .
+While only the mode bits are altered, other parts of the file mode
+may be examined.
+.Pp
+The
+.Fn setmode
+function
+takes an absolute (octal) or symbolic value, as described in
+.Xr chmod 1 ,
+as an argument
+and returns a pointer to mode values to be supplied to
+.Fn getmode .
+Because some of the symbolic values are relative to the file
+creation mask,
+.Fn setmode
+may call
+.Xr umask 2 .
+If this occurs, the file creation mask will be restored before
+.Fn setmode
+returns.
+If the calling program changes the value of its file creation mask
+after calling
+.Fn setmode ,
+.Fn setmode
+must be called again if
+.Fn getmode
+is to modify future file modes correctly.
+.Pp
+If the mode passed to
+.Fn setmode
+is invalid or if memory cannot be allocated for the return value,
+.Fn setmode
+returns
+.Dv NULL .
+.Pp
+The value returned from
+.Fn setmode
+is obtained from
+.Fn malloc
+and should be returned to the system with
+.Fn free
+when the program is done with it, generally after a call to
+.Fn getmode .
+.Sh ERRORS
+The
+.Fn setmode
+function
+may fail and set errno for any of the errors specified for the library
+routine
+.Xr malloc 3
+or
+.Xr strtol 3 .
+In addition,
+.Fn setmode
+will fail and set
+.Va errno
+to:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa mode
+argument does not represent a valid mode.
+.El
+.Sh SEE ALSO
+.Xr chmod 1 ,
+.Xr stat 2 ,
+.Xr umask 2 ,
+.Xr malloc 3
+.Sh HISTORY
+The
+.Fn getmode
+and
+.Fn setmode
+functions first appeared in
+.Bx 4.4 .
diff --git a/lib/libc/gen/setmode.c b/lib/libc/gen/setmode.c
new file mode 100644
index 000000000000..7525567bb792
--- /dev/null
+++ b/lib/libc/gen/setmode.c
@@ -0,0 +1,485 @@
+/*
+ * Copyright (c) 1989, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Dave Borman at Cray Research, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)setmode.c 8.2 (Berkeley) 3/25/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#ifdef SETMODE_DEBUG
+#include <stdio.h>
+#endif
+#include "un-namespace.h"
+#include "libc_private.h"
+
+#define SET_LEN 6 /* initial # of bitcmd struct to malloc */
+#define SET_LEN_INCR 4 /* # of bitcmd structs to add as needed */
+
+typedef struct bitcmd {
+ char cmd;
+ char cmd2;
+ mode_t bits;
+} BITCMD;
+
+#define CMD2_CLR 0x01
+#define CMD2_SET 0x02
+#define CMD2_GBITS 0x04
+#define CMD2_OBITS 0x08
+#define CMD2_UBITS 0x10
+
+static mode_t getumask(void);
+static BITCMD *addcmd(BITCMD *, mode_t, mode_t, mode_t, mode_t);
+static void compress_mode(BITCMD *);
+#ifdef SETMODE_DEBUG
+static void dumpmode(BITCMD *);
+#endif
+
+/*
+ * Given the old mode and an array of bitcmd structures, apply the operations
+ * described in the bitcmd structures to the old mode, and return the new mode.
+ * Note that there is no '=' command; a strict assignment is just a '-' (clear
+ * bits) followed by a '+' (set bits).
+ */
+mode_t
+getmode(const void *bbox, mode_t omode)
+{
+ const BITCMD *set;
+ mode_t clrval, newmode, value;
+
+ set = (const BITCMD *)bbox;
+ newmode = omode;
+ for (value = 0;; set++)
+ switch(set->cmd) {
+ /*
+ * When copying the user, group or other bits around, we "know"
+ * where the bits are in the mode so that we can do shifts to
+ * copy them around. If we don't use shifts, it gets real
+ * grundgy with lots of single bit checks and bit sets.
+ */
+ case 'u':
+ value = (newmode & S_IRWXU) >> 6;
+ goto common;
+
+ case 'g':
+ value = (newmode & S_IRWXG) >> 3;
+ goto common;
+
+ case 'o':
+ value = newmode & S_IRWXO;
+common: if (set->cmd2 & CMD2_CLR) {
+ clrval =
+ (set->cmd2 & CMD2_SET) ? S_IRWXO : value;
+ if (set->cmd2 & CMD2_UBITS)
+ newmode &= ~((clrval<<6) & set->bits);
+ if (set->cmd2 & CMD2_GBITS)
+ newmode &= ~((clrval<<3) & set->bits);
+ if (set->cmd2 & CMD2_OBITS)
+ newmode &= ~(clrval & set->bits);
+ }
+ if (set->cmd2 & CMD2_SET) {
+ if (set->cmd2 & CMD2_UBITS)
+ newmode |= (value<<6) & set->bits;
+ if (set->cmd2 & CMD2_GBITS)
+ newmode |= (value<<3) & set->bits;
+ if (set->cmd2 & CMD2_OBITS)
+ newmode |= value & set->bits;
+ }
+ break;
+
+ case '+':
+ newmode |= set->bits;
+ break;
+
+ case '-':
+ newmode &= ~set->bits;
+ break;
+
+ case 'X':
+ if (omode & (S_IFDIR|S_IXUSR|S_IXGRP|S_IXOTH))
+ newmode |= set->bits;
+ break;
+
+ case '\0':
+ default:
+#ifdef SETMODE_DEBUG
+ (void)printf("getmode:%04o -> %04o\n", omode, newmode);
+#endif
+ return (newmode);
+ }
+}
+
+#define ADDCMD(a, b, c, d) \
+ if (set >= endset) { \
+ BITCMD *newset; \
+ setlen += SET_LEN_INCR; \
+ newset = realloc(saveset, sizeof(BITCMD) * setlen); \
+ if (newset == NULL) \
+ goto out; \
+ set = newset + (set - saveset); \
+ saveset = newset; \
+ endset = newset + (setlen - 2); \
+ } \
+ set = addcmd(set, (mode_t)(a), (mode_t)(b), (mode_t)(c), (d))
+
+#define STANDARD_BITS (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
+
+void *
+setmode(const char *p)
+{
+ int serrno;
+ char op, *ep;
+ BITCMD *set, *saveset, *endset;
+ mode_t mask, perm, permXbits, who;
+ long perml;
+ int equalopdone;
+ int setlen;
+
+ if (!*p) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ /*
+ * Get a copy of the mask for the permissions that are mask relative.
+ * Flip the bits, we want what's not set.
+ */
+ mask = ~getumask();
+
+ setlen = SET_LEN + 2;
+
+ if ((set = malloc((u_int)(sizeof(BITCMD) * setlen))) == NULL)
+ return (NULL);
+ saveset = set;
+ endset = set + (setlen - 2);
+
+ /*
+ * If an absolute number, get it and return; disallow non-octal digits
+ * or illegal bits.
+ */
+ if (isdigit((unsigned char)*p)) {
+ errno = 0;
+ perml = strtol(p, &ep, 8);
+ if (*ep) {
+ errno = EINVAL;
+ goto out;
+ }
+ if (errno == ERANGE && (perml == LONG_MAX || perml == LONG_MIN))
+ goto out;
+ if (perml & ~(STANDARD_BITS|S_ISTXT)) {
+ errno = EINVAL;
+ goto out;
+ }
+ perm = (mode_t)perml;
+ ADDCMD('=', (STANDARD_BITS|S_ISTXT), perm, mask);
+ set->cmd = 0;
+ return (saveset);
+ }
+
+ /*
+ * Build list of structures to set/clear/copy bits as described by
+ * each clause of the symbolic mode.
+ */
+ equalopdone = 0;
+ for (;;) {
+ /* First, find out which bits might be modified. */
+ for (who = 0;; ++p) {
+ switch (*p) {
+ case 'a':
+ who |= STANDARD_BITS;
+ break;
+ case 'u':
+ who |= S_ISUID|S_IRWXU;
+ break;
+ case 'g':
+ who |= S_ISGID|S_IRWXG;
+ break;
+ case 'o':
+ who |= S_IRWXO;
+ break;
+ default:
+ goto getop;
+ }
+ }
+
+getop: if ((op = *p++) != '+' && op != '-' && op != '=') {
+ errno = EINVAL;
+ goto out;
+ }
+ if (op == '=')
+ equalopdone = 0;
+
+ who &= ~S_ISTXT;
+ for (perm = 0, permXbits = 0;; ++p) {
+ switch (*p) {
+ case 'r':
+ perm |= S_IRUSR|S_IRGRP|S_IROTH;
+ break;
+ case 's':
+ /* If only "other" bits ignore set-id. */
+ if (!who || who & ~S_IRWXO)
+ perm |= S_ISUID|S_ISGID;
+ break;
+ case 't':
+ /* If only "other" bits ignore sticky. */
+ if (!who || who & ~S_IRWXO) {
+ who |= S_ISTXT;
+ perm |= S_ISTXT;
+ }
+ break;
+ case 'w':
+ perm |= S_IWUSR|S_IWGRP|S_IWOTH;
+ break;
+ case 'X':
+ permXbits = S_IXUSR|S_IXGRP|S_IXOTH;
+ break;
+ case 'x':
+ perm |= S_IXUSR|S_IXGRP|S_IXOTH;
+ break;
+ case 'u':
+ case 'g':
+ case 'o':
+ /*
+ * When ever we hit 'u', 'g', or 'o', we have
+ * to flush out any partial mode that we have,
+ * and then do the copying of the mode bits.
+ */
+ if (perm) {
+ ADDCMD(op, who, perm, mask);
+ perm = 0;
+ }
+ if (op == '=')
+ equalopdone = 1;
+ if (op == '+' && permXbits) {
+ ADDCMD('X', who, permXbits, mask);
+ permXbits = 0;
+ }
+ ADDCMD(*p, who, op, mask);
+ break;
+
+ default:
+ /*
+ * Add any permissions that we haven't already
+ * done.
+ */
+ if (perm || (op == '=' && !equalopdone)) {
+ if (op == '=')
+ equalopdone = 1;
+ ADDCMD(op, who, perm, mask);
+ perm = 0;
+ }
+ if (permXbits) {
+ ADDCMD('X', who, permXbits, mask);
+ permXbits = 0;
+ }
+ goto apply;
+ }
+ }
+
+apply: if (!*p)
+ break;
+ if (*p != ',')
+ goto getop;
+ ++p;
+ }
+ set->cmd = 0;
+#ifdef SETMODE_DEBUG
+ (void)printf("Before compress_mode()\n");
+ dumpmode(saveset);
+#endif
+ compress_mode(saveset);
+#ifdef SETMODE_DEBUG
+ (void)printf("After compress_mode()\n");
+ dumpmode(saveset);
+#endif
+ return (saveset);
+out:
+ serrno = errno;
+ free(saveset);
+ errno = serrno;
+ return NULL;
+}
+
+static mode_t
+getumask(void)
+{
+ sigset_t sigset, sigoset;
+ size_t len;
+ mode_t mask;
+ u_short smask;
+
+ /*
+ * First try requesting the umask without temporarily modifying it.
+ * Note that this does not work if the sysctl
+ * security.bsd.unprivileged_proc_debug is set to 0.
+ */
+ len = sizeof(smask);
+ if (sysctl((int[4]){ CTL_KERN, KERN_PROC, KERN_PROC_UMASK, getpid() },
+ 4, &smask, &len, NULL, 0) == 0)
+ return (smask);
+
+ /*
+ * Since it's possible that the caller is opening files inside a signal
+ * handler, protect them as best we can.
+ */
+ sigfillset(&sigset);
+ (void)__libc_sigprocmask(SIG_BLOCK, &sigset, &sigoset);
+ (void)umask(mask = umask(0));
+ (void)__libc_sigprocmask(SIG_SETMASK, &sigoset, NULL);
+ return (mask);
+}
+
+static BITCMD *
+addcmd(BITCMD *set, mode_t op, mode_t who, mode_t oparg, mode_t mask)
+{
+ switch (op) {
+ case '=':
+ set->cmd = '-';
+ set->bits = who ? who : STANDARD_BITS;
+ set++;
+
+ op = '+';
+ /* FALLTHROUGH */
+ case '+':
+ case '-':
+ case 'X':
+ set->cmd = op;
+ set->bits = (who ? who : mask) & oparg;
+ break;
+
+ case 'u':
+ case 'g':
+ case 'o':
+ set->cmd = op;
+ if (who) {
+ set->cmd2 = ((who & S_IRUSR) ? CMD2_UBITS : 0) |
+ ((who & S_IRGRP) ? CMD2_GBITS : 0) |
+ ((who & S_IROTH) ? CMD2_OBITS : 0);
+ set->bits = (mode_t)~0;
+ } else {
+ set->cmd2 = CMD2_UBITS | CMD2_GBITS | CMD2_OBITS;
+ set->bits = mask;
+ }
+
+ if (oparg == '+')
+ set->cmd2 |= CMD2_SET;
+ else if (oparg == '-')
+ set->cmd2 |= CMD2_CLR;
+ else if (oparg == '=')
+ set->cmd2 |= CMD2_SET|CMD2_CLR;
+ break;
+ }
+ return (set + 1);
+}
+
+#ifdef SETMODE_DEBUG
+static void
+dumpmode(BITCMD *set)
+{
+ for (; set->cmd; ++set)
+ (void)printf("cmd: '%c' bits %04o%s%s%s%s%s%s\n",
+ set->cmd, set->bits, set->cmd2 ? " cmd2:" : "",
+ set->cmd2 & CMD2_CLR ? " CLR" : "",
+ set->cmd2 & CMD2_SET ? " SET" : "",
+ set->cmd2 & CMD2_UBITS ? " UBITS" : "",
+ set->cmd2 & CMD2_GBITS ? " GBITS" : "",
+ set->cmd2 & CMD2_OBITS ? " OBITS" : "");
+}
+#endif
+
+/*
+ * Given an array of bitcmd structures, compress by compacting consecutive
+ * '+', '-' and 'X' commands into at most 3 commands, one of each. The 'u',
+ * 'g' and 'o' commands continue to be separate. They could probably be
+ * compacted, but it's not worth the effort.
+ */
+static void
+compress_mode(BITCMD *set)
+{
+ BITCMD *nset;
+ int setbits, clrbits, Xbits, op;
+
+ for (nset = set;;) {
+ /* Copy over any 'u', 'g' and 'o' commands. */
+ while ((op = nset->cmd) != '+' && op != '-' && op != 'X') {
+ *set++ = *nset++;
+ if (!op)
+ return;
+ }
+
+ for (setbits = clrbits = Xbits = 0;; nset++) {
+ if ((op = nset->cmd) == '-') {
+ clrbits |= nset->bits;
+ setbits &= ~nset->bits;
+ Xbits &= ~nset->bits;
+ } else if (op == '+') {
+ setbits |= nset->bits;
+ clrbits &= ~nset->bits;
+ Xbits &= ~nset->bits;
+ } else if (op == 'X')
+ Xbits |= nset->bits & ~setbits;
+ else
+ break;
+ }
+ if (clrbits) {
+ set->cmd = '-';
+ set->cmd2 = 0;
+ set->bits = clrbits;
+ set++;
+ }
+ if (setbits) {
+ set->cmd = '+';
+ set->cmd2 = 0;
+ set->bits = setbits;
+ set++;
+ }
+ if (Xbits) {
+ set->cmd = 'X';
+ set->cmd2 = 0;
+ set->bits = Xbits;
+ set++;
+ }
+ }
+}
diff --git a/lib/libc/gen/setproctitle.3 b/lib/libc/gen/setproctitle.3
new file mode 100644
index 000000000000..955556e5b205
--- /dev/null
+++ b/lib/libc/gen/setproctitle.3
@@ -0,0 +1,121 @@
+.\" Copyright (c) 1995 Peter Wemm <peter@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, is permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice immediately at the beginning of the file, without modification,
+.\" this list of conditions, and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. This work was done expressly for inclusion into FreeBSD. Other use
+.\" is permitted provided this notation is included.
+.\" 4. Absolutely no warranty of function or purpose is made by the author
+.\" Peter Wemm.
+.\" 5. Modifications may be freely made to this file providing the above
+.\" conditions are met.
+.\"
+.\" $FreeBSD$
+.\"
+.\" The following requests are required for all man pages.
+.Dd December 16, 1995
+.Dt SETPROCTITLE 3
+.Os
+.Sh NAME
+.Nm setproctitle
+.Nd set process title
+.Sh SYNOPSIS
+.In sys/types.h
+.In unistd.h
+.Ft void
+.Fn setproctitle "const char *fmt" "..."
+.Sh DESCRIPTION
+The
+.Fn setproctitle
+library routine sets the process title that appears on the
+.Xr ps 1
+command.
+.Pp
+The title is set from the executable's name, followed by the
+result of a
+.Xr printf 3
+style expansion of the arguments as specified by the
+.Va fmt
+argument.
+If the
+.Va fmt
+argument begins with a
+.Dq -
+character, the executable's name is skipped.
+.Pp
+If
+.Va fmt
+is NULL, the process title is restored.
+.Sh EXAMPLES
+To set the title on a daemon to indicate its activity:
+.Bd -literal -offset indent
+setproctitle("talking to %s", inet_ntoa(addr));
+.Ed
+.Sh SEE ALSO
+.Xr ps 1 ,
+.Xr w 1 ,
+.Xr kvm 3 ,
+.Xr kvm_getargv 3 ,
+.Xr printf 3
+.Sh STANDARDS
+The
+.Fn setproctitle
+function
+is implicitly non-standard.
+Other methods of causing the
+.Xr ps 1
+command line to change, including copying over the argv[0] string are
+also implicitly non-portable.
+It is preferable to use an operating system
+supplied
+.Fn setproctitle
+if present.
+.Pp
+Unfortunately, it is possible that there are other calling conventions
+to other versions of
+.Fn setproctitle ,
+although none have been found by the author as yet.
+This is believed to be
+the predominant convention.
+.Pp
+It is thought that the implementation is compatible with other systems,
+including
+.Nx
+and
+.Bsx .
+.Sh HISTORY
+The
+.Fn setproctitle
+function
+first appeared in
+.Fx 2.2 .
+Other operating systems have
+similar functions.
+.Sh AUTHORS
+.An -nosplit
+.An Peter Wemm Aq Mt peter@FreeBSD.org
+stole the idea from the
+.Sy "Sendmail 8.7.3"
+source code by
+.An Eric Allman Aq Mt eric@sendmail.org .
+.Sh BUGS
+Never pass a string with user-supplied data as a format without using
+.Ql %s .
+An attacker can put format specifiers in the string to mangle your stack,
+leading to a possible security hole.
+This holds true even if the string was built using a function like
+.Fn snprintf ,
+as the resulting string may still contain user-supplied conversion specifiers
+for later interpolation by
+.Fn setproctitle .
+.Pp
+Always use the proper secure idiom:
+.Pp
+.Dl setproctitle("%s", string);
diff --git a/lib/libc/gen/setproctitle.c b/lib/libc/gen/setproctitle.c
new file mode 100644
index 000000000000..fd87c3507153
--- /dev/null
+++ b/lib/libc/gen/setproctitle.c
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 1995 Peter Wemm <peter@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, is permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * this list of conditions, and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Absolutely no warranty of function or purpose is made by the author
+ * Peter Wemm.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <sys/exec.h>
+#include <sys/sysctl.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+#include "libc_private.h"
+
+/*
+ * Older FreeBSD 2.0, 2.1 and 2.2 had different ps_strings structures and
+ * in different locations.
+ * 1: old_ps_strings at the very top of the stack.
+ * 2: old_ps_strings at SPARE_USRSPACE below the top of the stack.
+ * 3: ps_strings at the very top of the stack.
+ * We only support a kernel providing #3 style ps_strings.
+ *
+ * For historical purposes, a definition of the old ps_strings structure
+ * and location is preserved below:
+struct old_ps_strings {
+ char *old_ps_argvstr;
+ int old_ps_nargvstr;
+ char *old_ps_envstr;
+ int old_ps_nenvstr;
+};
+#define OLD_PS_STRINGS ((struct old_ps_strings *) \
+ (USRSTACK - SPARE_USRSPACE - sizeof(struct old_ps_strings)))
+ */
+
+#include <stdarg.h>
+
+#define SPT_BUFSIZE 2048 /* from other parts of sendmail */
+
+void
+setproctitle(const char *fmt, ...)
+{
+ static struct ps_strings *ps_strings;
+ static char *buf = NULL;
+ static char *obuf = NULL;
+ static char **oargv, *kbuf;
+ static int oargc = -1;
+ static char *nargv[2] = { NULL, NULL };
+ char **nargvp;
+ int nargc;
+ int i;
+ va_list ap;
+ size_t len;
+ unsigned long ul_ps_strings;
+ int oid[4];
+
+ if (buf == NULL) {
+ buf = malloc(SPT_BUFSIZE);
+ if (buf == NULL)
+ return;
+ nargv[0] = buf;
+ }
+
+ if (obuf == NULL ) {
+ obuf = malloc(SPT_BUFSIZE);
+ if (obuf == NULL)
+ return;
+ *obuf = '\0';
+ }
+
+ va_start(ap, fmt);
+
+ if (fmt) {
+ buf[SPT_BUFSIZE - 1] = '\0';
+
+ if (fmt[0] == '-') {
+ /* skip program name prefix */
+ fmt++;
+ len = 0;
+ } else {
+ /* print program name heading for grep */
+ (void)snprintf(buf, SPT_BUFSIZE, "%s: ", _getprogname());
+ len = strlen(buf);
+ }
+
+ /* print the argument string */
+ (void) vsnprintf(buf + len, SPT_BUFSIZE - len, fmt, ap);
+
+ nargvp = nargv;
+ nargc = 1;
+ kbuf = buf;
+ } else if (*obuf != '\0') {
+ /* Idea from NetBSD - reset the title on fmt == NULL */
+ nargvp = oargv;
+ nargc = oargc;
+ kbuf = obuf;
+ } else
+ /* Nothing to restore */
+ return;
+
+ va_end(ap);
+
+ /* Set the title into the kernel cached command line */
+ oid[0] = CTL_KERN;
+ oid[1] = KERN_PROC;
+ oid[2] = KERN_PROC_ARGS;
+ oid[3] = getpid();
+ sysctl(oid, 4, 0, 0, kbuf, strlen(kbuf) + 1);
+
+ if (ps_strings == NULL) {
+ len = sizeof(ul_ps_strings);
+ if (sysctlbyname("kern.ps_strings", &ul_ps_strings, &len, NULL,
+ 0) == -1)
+ return;
+ ps_strings = (struct ps_strings *)ul_ps_strings;
+ }
+
+ /*
+ * PS_STRINGS points to zeroed memory on a style #2 kernel.
+ * Should not happen.
+ */
+ if (ps_strings->ps_argvstr == NULL)
+ return;
+
+ /* style #3 */
+ if (oargc == -1) {
+ /* Record our original args */
+ oargc = ps_strings->ps_nargvstr;
+ oargv = ps_strings->ps_argvstr;
+ for (i = len = 0; i < oargc; i++) {
+ /*
+ * The program may have scribbled into its
+ * argv array, e.g., to remove some arguments.
+ * If that has happened, break out before
+ * trying to call strlen on a NULL pointer.
+ */
+ if (oargv[i] == NULL) {
+ oargc = i;
+ break;
+ }
+ snprintf(obuf + len, SPT_BUFSIZE - len, "%s%s",
+ len != 0 ? " " : "", oargv[i]);
+ if (len != 0)
+ len++;
+ len += strlen(oargv[i]);
+ if (len >= SPT_BUFSIZE)
+ break;
+ }
+ }
+ ps_strings->ps_nargvstr = nargc;
+ ps_strings->ps_argvstr = nargvp;
+}
diff --git a/lib/libc/gen/setprogname.c b/lib/libc/gen/setprogname.c
new file mode 100644
index 000000000000..29a6cd025ec8
--- /dev/null
+++ b/lib/libc/gen/setprogname.c
@@ -0,0 +1,19 @@
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "libc_private.h"
+
+void
+setprogname(const char *progname)
+{
+ const char *p;
+
+ p = strrchr(progname, '/');
+ if (p != NULL)
+ __progname = p + 1;
+ else
+ __progname = progname;
+}
diff --git a/lib/libc/gen/siginterrupt.3 b/lib/libc/gen/siginterrupt.3
new file mode 100644
index 000000000000..e790132b3703
--- /dev/null
+++ b/lib/libc/gen/siginterrupt.3
@@ -0,0 +1,119 @@
+.\" Copyright (c) 1985, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)siginterrupt.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt SIGINTERRUPT 3
+.Os
+.Sh NAME
+.Nm siginterrupt
+.Nd allow signals to interrupt system calls
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In signal.h
+.Ft int
+.Fn siginterrupt "int sig" "int flag"
+.Sh DESCRIPTION
+The
+.Fn siginterrupt
+function
+is used to change the system call restart
+behavior when a system call is interrupted by the specified signal.
+If the flag is false (0), then system calls will be restarted if
+they are interrupted by the specified signal
+and no data has been transferred yet.
+System call restart has been the default behavior since
+.Bx 4.2 ,
+and is the default behaviour for
+.Xr signal 3
+on
+.Fx .
+.Pp
+If the flag is true (1),
+then restarting of system calls is disabled.
+If a system call is interrupted by the specified signal
+and no data has been transferred,
+the system call will return \-1 with the global variable
+.Va errno
+set to
+.Er EINTR .
+Interrupted system calls that have started transferring
+data will return the amount of data actually transferred.
+System call interrupt is the signal behavior found on
+.Bx 4.1
+and
+.At V
+systems.
+.Pp
+Note that the new
+.Bx 4.2
+signal handling semantics are not
+altered in any other way.
+Most notably, signal handlers always remain installed until
+explicitly changed by a subsequent
+.Xr sigaction 2
+call, and the signal mask operates as documented in
+.Xr sigaction 2 .
+Programs may switch between restartable and interruptible
+system call operation as often as desired in the execution of a program.
+.Pp
+Issuing a
+.Fn siginterrupt 3
+call during the execution of a signal handler will cause
+the new action to take place on the next signal to be caught.
+.Sh NOTES
+This library routine uses an extension of the
+.Xr sigaction 2
+system call that is not available in
+.Bx 4.2 ,
+hence it should not be used if backward compatibility is needed.
+.Sh RETURN VALUES
+.Rv -std siginterrupt
+.Sh ERRORS
+The
+.Fn siginterrupt
+call fails if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa sig
+argument
+is not a valid signal number.
+.El
+.Sh SEE ALSO
+.Xr sigaction 2 ,
+.Xr sigprocmask 2 ,
+.Xr sigsuspend 2 ,
+.Xr signal 3
+.Sh HISTORY
+The
+.Fn siginterrupt
+function appeared in
+.Bx 4.3 .
diff --git a/lib/libc/gen/siginterrupt.c b/lib/libc/gen/siginterrupt.c
new file mode 100644
index 000000000000..d99b77233786
--- /dev/null
+++ b/lib/libc/gen/siginterrupt.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)siginterrupt.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <signal.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+
+/*
+ * Set signal state to prevent restart of system calls
+ * after an instance of the indicated signal.
+ */
+int
+siginterrupt(int sig, int flag)
+{
+ extern sigset_t _sigintr __hidden;
+ struct sigaction sa;
+ int ret;
+
+ if ((ret = __libc_sigaction(sig, (struct sigaction *)0, &sa)) < 0)
+ return (ret);
+ if (flag) {
+ sigaddset(&_sigintr, sig);
+ sa.sa_flags &= ~SA_RESTART;
+ } else {
+ sigdelset(&_sigintr, sig);
+ sa.sa_flags |= SA_RESTART;
+ }
+ return (__libc_sigaction(sig, &sa, (struct sigaction *)0));
+}
diff --git a/lib/libc/gen/siglist.c b/lib/libc/gen/siglist.c
new file mode 100644
index 000000000000..2a177bffcf1f
--- /dev/null
+++ b/lib/libc/gen/siglist.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)siglist.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <signal.h>
+
+const char *const sys_signame[NSIG] = {
+ [0] = "Signal 0",
+ [SIGHUP] = "HUP",
+ [SIGINT] = "INT",
+ [SIGQUIT] = "QUIT",
+ [SIGILL] = "ILL",
+ [SIGTRAP] = "TRAP",
+ [SIGABRT] = "ABRT",
+ [SIGEMT] = "EMT",
+ [SIGFPE] = "FPE",
+ [SIGKILL] = "KILL",
+ [SIGBUS] = "BUS",
+ [SIGSEGV] = "SEGV",
+ [SIGSYS] = "SYS",
+ [SIGPIPE] = "PIPE",
+ [SIGALRM] = "ALRM",
+ [SIGTERM] = "TERM",
+ [SIGURG] = "URG",
+ [SIGSTOP] = "STOP",
+ [SIGTSTP] = "TSTP",
+ [SIGCONT] = "CONT",
+ [SIGCHLD] = "CHLD",
+ [SIGTTIN] = "TTIN",
+ [SIGTTOU] = "TTOU",
+ [SIGIO] = "IO",
+ [SIGXCPU] = "XCPU",
+ [SIGXFSZ] = "XFSZ",
+ [SIGVTALRM] = "VTALRM",
+ [SIGPROF] = "PROF",
+ [SIGWINCH] = "WINCH",
+ [SIGINFO] = "INFO",
+ [SIGUSR1] = "USR1",
+ [SIGUSR2] = "USR2",
+};
+
+const char *const sys_siglist[NSIG] = {
+ [0] = "Signal 0",
+ [SIGHUP] = "Hangup",
+ [SIGINT] = "Interrupt",
+ [SIGQUIT] = "Quit",
+ [SIGILL] = "Illegal instruction",
+ [SIGTRAP] = "Trace/BPT trap",
+ [SIGABRT] = "Abort trap",
+ [SIGEMT] = "EMT trap",
+ [SIGFPE] = "Floating point exception",
+ [SIGKILL] = "Killed",
+ [SIGBUS] = "Bus error",
+ [SIGSEGV] = "Segmentation fault",
+ [SIGSYS] = "Bad system call",
+ [SIGPIPE] = "Broken pipe",
+ [SIGALRM] = "Alarm clock",
+ [SIGTERM] = "Terminated",
+ [SIGURG] = "Urgent I/O condition",
+ [SIGSTOP] = "Suspended (signal)",
+ [SIGTSTP] = "Suspended",
+ [SIGCONT] = "Continued",
+ [SIGCHLD] = "Child exited",
+ [SIGTTIN] = "Stopped (tty input)",
+ [SIGTTOU] = "Stopped (tty output)",
+ [SIGIO] = "I/O possible",
+ [SIGXCPU] = "Cputime limit exceeded",
+ [SIGXFSZ] = "Filesize limit exceeded",
+ [SIGVTALRM] = "Virtual timer expired",
+ [SIGPROF] = "Profiling timer expired",
+ [SIGWINCH] = "Window size changes",
+ [SIGINFO] = "Information request",
+ [SIGUSR1] = "User defined signal 1",
+ [SIGUSR2] = "User defined signal 2",
+};
+const int sys_nsig = sizeof(sys_siglist) / sizeof(sys_siglist[0]);
diff --git a/lib/libc/gen/signal.3 b/lib/libc/gen/signal.3
new file mode 100644
index 000000000000..ea6df4410b2c
--- /dev/null
+++ b/lib/libc/gen/signal.3
@@ -0,0 +1,272 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)signal.3 8.3 (Berkeley) 4/19/94
+.\" $FreeBSD$
+.\"
+.Dd June 7, 2004
+.Dt SIGNAL 3
+.Os
+.Sh NAME
+.Nm signal
+.Nd simplified software signal facilities
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In signal.h
+.\" The following is Quite Ugly, but syntactically correct.
+.\" Don't try to fix it.
+.Ft void
+.Fn \*(lp*signal "int sig" "void \*(lp*func\*(rp\*(lpint\*(rp\*(rp\*(rp\*(lpint"
+.Pp
+or in
+.Fx Ap s
+equivalent but easier to read typedef'd version:
+.Ft typedef "void \*(lp*sig_t\*(rp \*(lpint\*(rp" ;
+.Pp
+.Ft sig_t
+.Fn signal "int sig" "sig_t func"
+.Sh DESCRIPTION
+This
+.Fn signal
+facility
+is a simplified interface to the more general
+.Xr sigaction 2
+facility.
+.Pp
+Signals allow the manipulation of a process from outside its
+domain as well as allowing the process to manipulate itself or
+copies of itself (children).
+There are two general types of signals:
+those that cause termination of a process and those that do not.
+Signals which cause termination of a program might result from
+an irrecoverable error or might be the result of a user at a terminal
+typing the `interrupt' character.
+Signals are used when a process is stopped because it wishes to access
+its control terminal while in the background (see
+.Xr tty 4 ) .
+Signals are optionally generated
+when a process resumes after being stopped,
+when the status of child processes changes,
+or when input is ready at the control terminal.
+Most signals result in the termination of the process receiving them
+if no action
+is taken; some signals instead cause the process receiving them
+to be stopped, or are simply discarded if the process has not
+requested otherwise.
+Except for the
+.Dv SIGKILL
+and
+.Dv SIGSTOP
+signals, the
+.Fn signal
+function allows for a signal to be caught, to be ignored, or to generate
+an interrupt.
+These signals are defined in the file
+.In signal.h :
+.Bl -column No ".Dv SIGVTALRM" "create core image"
+.It Sy "Num" Ta Sy "Name" Ta Sy "Default Action" Ta Sy "Description"
+.It 1 Ta Dv SIGHUP Ta "terminate process" Ta "terminal line hangup"
+.It 2 Ta Dv SIGINT Ta "terminate process" Ta "interrupt program"
+.It 3 Ta Dv SIGQUIT Ta "create core image" Ta "quit program"
+.It 4 Ta Dv SIGILL Ta "create core image" Ta "illegal instruction"
+.It 5 Ta Dv SIGTRAP Ta "create core image" Ta "trace trap"
+.It 6 Ta Dv SIGABRT Ta "create core image" Ta "abort program"
+(formerly
+.Dv SIGIOT )
+.It 7 Ta Dv SIGEMT Ta "create core image" Ta "emulate instruction executed"
+.It 8 Ta Dv SIGFPE Ta "create core image" Ta "floating-point exception"
+.It 9 Ta Dv SIGKILL Ta "terminate process" Ta "kill program"
+.It 10 Ta Dv SIGBUS Ta "create core image" Ta "bus error"
+.It 11 Ta Dv SIGSEGV Ta "create core image" Ta "segmentation violation"
+.It 12 Ta Dv SIGSYS Ta "create core image" Ta "non-existent system call invoked"
+.It 13 Ta Dv SIGPIPE Ta "terminate process" Ta "write on a pipe with no reader"
+.It 14 Ta Dv SIGALRM Ta "terminate process" Ta "real-time timer expired"
+.It 15 Ta Dv SIGTERM Ta "terminate process" Ta "software termination signal"
+.It 16 Ta Dv SIGURG Ta "discard signal" Ta "urgent condition present on socket"
+.It 17 Ta Dv SIGSTOP Ta "stop process" Ta "stop (cannot be caught or ignored)"
+.It 18 Ta Dv SIGTSTP Ta "stop process" Ta "stop signal generated from keyboard"
+.It 19 Ta Dv SIGCONT Ta "discard signal" Ta "continue after stop"
+.It 20 Ta Dv SIGCHLD Ta "discard signal" Ta "child status has changed"
+.It 21 Ta Dv SIGTTIN Ta "stop process" Ta "background read attempted from"
+control terminal
+.It 22 Ta Dv SIGTTOU Ta "stop process" Ta "background write attempted to"
+control terminal
+.It 23 Ta Dv SIGIO Ta "discard signal" Ta Tn "I/O"
+is possible on a descriptor (see
+.Xr fcntl 2 )
+.It 24 Ta Dv SIGXCPU Ta "terminate process" Ta "cpu time limit exceeded (see"
+.Xr setrlimit 2 )
+.It 25 Ta Dv SIGXFSZ Ta "terminate process" Ta "file size limit exceeded (see"
+.Xr setrlimit 2 )
+.It 26 Ta Dv SIGVTALRM Ta "terminate process" Ta "virtual time alarm (see"
+.Xr setitimer 2 )
+.It 27 Ta Dv SIGPROF Ta "terminate process" Ta "profiling timer alarm (see"
+.Xr setitimer 2 )
+.It 28 Ta Dv SIGWINCH Ta "discard signal" Ta "Window size change"
+.It 29 Ta Dv SIGINFO Ta "discard signal" Ta "status request from keyboard"
+.It 30 Ta Dv SIGUSR1 Ta "terminate process" Ta "User defined signal 1"
+.It 31 Ta Dv SIGUSR2 Ta "terminate process" Ta "User defined signal 2"
+.It 32 Ta Dv SIGTHR Ta "terminate process" Ta "thread interrupt"
+.It 33 Ta Dv SIGLIBRT Ta "terminate process" Ta "real-time library interrupt"
+.El
+.Pp
+The
+.Fa sig
+argument specifies which signal was received.
+The
+.Fa func
+procedure allows a user to choose the action upon receipt of a signal.
+To set the default action of the signal to occur as listed above,
+.Fa func
+should be
+.Dv SIG_DFL .
+A
+.Dv SIG_DFL
+resets the default action.
+To ignore the signal
+.Fa func
+should be
+.Dv SIG_IGN .
+This will cause subsequent instances of the signal to be ignored
+and pending instances to be discarded.
+If
+.Dv SIG_IGN
+is not used,
+further occurrences of the signal are
+automatically blocked and
+.Fa func
+is called.
+.Pp
+The handled signal is unblocked when the
+function returns and
+the process continues from where it left off when the signal occurred.
+.Bf -symbolic
+Unlike previous signal facilities, the handler
+func() remains installed after a signal has been delivered.
+.Ef
+.Pp
+For some system calls, if a signal is caught while the call is
+executing and the call is prematurely terminated,
+the call is automatically restarted.
+Any handler installed with
+.Xr signal 3
+will have the
+.Dv SA_RESTART
+flag set, meaning that any restartable system call will not return on
+receipt of a signal.
+The affected system calls include
+.Xr read 2 ,
+.Xr write 2 ,
+.Xr sendto 2 ,
+.Xr recvfrom 2 ,
+.Xr sendmsg 2
+and
+.Xr recvmsg 2
+on a communications channel or a low speed device
+and during a
+.Xr ioctl 2
+or
+.Xr wait 2 .
+However, calls that have already committed are not restarted,
+but instead return a partial success (for example, a short read count).
+These semantics could be changed with
+.Xr siginterrupt 3 .
+.Pp
+When a process which has installed signal handlers forks,
+the child process inherits the signals.
+All caught signals may be reset to their default action by a call
+to the
+.Xr execve 2
+function;
+ignored signals remain ignored.
+.Pp
+If a process explicitly specifies
+.Dv SIG_IGN
+as the action for the signal
+.Dv SIGCHLD ,
+the system will not create zombie processes when children
+of the calling process exit.
+As a consequence, the system will discard the exit status
+from the child processes.
+If the calling process subsequently issues a call to
+.Xr wait 2
+or equivalent, it will block until all of the calling process's
+children terminate, and then return a value of \-1 with
+.Va errno
+set to
+.Er ECHILD .
+.Pp
+See
+.Xr sigaction 2
+for a list of functions
+that are considered safe for use in signal handlers.
+.Sh RETURN VALUES
+The previous action is returned on a successful call.
+Otherwise, SIG_ERR is returned and the global variable
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+The
+.Fn signal
+function
+will fail and no action will take place if one of the
+following occur:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa sig
+argument
+is not a valid signal number.
+.It Bq Er EINVAL
+An attempt is made to ignore or supply a handler for
+.Dv SIGKILL
+or
+.Dv SIGSTOP .
+.El
+.Sh SEE ALSO
+.Xr kill 1 ,
+.Xr kill 2 ,
+.Xr ptrace 2 ,
+.Xr sigaction 2 ,
+.Xr sigaltstack 2 ,
+.Xr sigprocmask 2 ,
+.Xr sigsuspend 2 ,
+.Xr wait 2 ,
+.Xr fpsetmask 3 ,
+.Xr setjmp 3 ,
+.Xr siginterrupt 3 ,
+.Xr tty 4
+.Sh HISTORY
+The
+.Nm
+facility appeared in
+.Bx 4.0 .
+The option to avoid the creation of child zombies through ignoring
+.Dv SIGCHLD
+appeared in
+.Fx 5.0 .
diff --git a/lib/libc/gen/signal.c b/lib/libc/gen/signal.c
new file mode 100644
index 000000000000..70e7f1712cea
--- /dev/null
+++ b/lib/libc/gen/signal.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 1985, 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)signal.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Almost backwards compatible signal.
+ */
+#include "namespace.h"
+#include <signal.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+
+sigset_t _sigintr __hidden; /* shared with siginterrupt */
+
+sig_t
+signal(int s, sig_t a)
+{
+ struct sigaction sa, osa;
+
+ sa.sa_handler = a;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0;
+ if (!sigismember(&_sigintr, s))
+ sa.sa_flags |= SA_RESTART;
+ if (__libc_sigaction(s, &sa, &osa) < 0)
+ return (SIG_ERR);
+ return (osa.sa_handler);
+}
diff --git a/lib/libc/gen/sigsetops.3 b/lib/libc/gen/sigsetops.3
new file mode 100644
index 000000000000..88affad61fdb
--- /dev/null
+++ b/lib/libc/gen/sigsetops.3
@@ -0,0 +1,117 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)sigsetops.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd December 16, 2004
+.Dt SIGSETOPS 3
+.Os
+.Sh NAME
+.Nm sigemptyset ,
+.Nm sigfillset ,
+.Nm sigaddset ,
+.Nm sigdelset ,
+.Nm sigismember
+.Nd manipulate signal sets
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In signal.h
+.Ft int
+.Fn sigemptyset "sigset_t *set"
+.Ft int
+.Fn sigfillset "sigset_t *set"
+.Ft int
+.Fn sigaddset "sigset_t *set" "int signo"
+.Ft int
+.Fn sigdelset "sigset_t *set" "int signo"
+.Ft int
+.Fn sigismember "const sigset_t *set" "int signo"
+.Sh DESCRIPTION
+These functions manipulate signal sets stored in a
+.Fa sigset_t .
+Either
+.Fn sigemptyset
+or
+.Fn sigfillset
+must be called for every object of type
+.Fa sigset_t
+before any other use of the object.
+.Pp
+The
+.Fn sigemptyset
+function initializes a signal set to be empty.
+.Pp
+The
+.Fn sigfillset
+function initializes a signal set to contain all signals.
+.Pp
+The
+.Fn sigaddset
+function adds the specified signal
+.Fa signo
+to the signal set.
+.Pp
+The
+.Fn sigdelset
+function deletes the specified signal
+.Fa signo
+from the signal set.
+.Pp
+The
+.Fn sigismember
+function returns whether a specified signal
+.Fa signo
+is contained in the signal set.
+.Sh RETURN VALUES
+The
+.Fn sigismember
+function returns 1
+if the signal is a member of the set,
+0 otherwise.
+The other functions return 0 upon success.
+A \-1 return value
+indicates an error occurred and the global variable
+.Va errno
+is set to indicate the reason.
+.Sh ERRORS
+These functions could fail if one of the following occurs:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+.Fa signo
+has an invalid value.
+.El
+.Sh SEE ALSO
+.Xr kill 2 ,
+.Xr sigaction 2 ,
+.Xr sigpending 2 ,
+.Xr sigprocmask 2 ,
+.Xr sigsuspend 2
+.Sh STANDARDS
+These functions are defined by
+.St -p1003.1-88 .
diff --git a/lib/libc/gen/sigsetops.c b/lib/libc/gen/sigsetops.c
new file mode 100644
index 000000000000..cbcbfec48720
--- /dev/null
+++ b/lib/libc/gen/sigsetops.c
@@ -0,0 +1,94 @@
+/*-
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)sigsetops.c 8.1 (Berkeley) 6/4/93
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)sigsetops.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <signal.h>
+
+int
+sigaddset(sigset_t *set, int signo)
+{
+
+ if (signo <= 0 || signo > _SIG_MAXSIG) {
+ errno = EINVAL;
+ return (-1);
+ }
+ set->__bits[_SIG_WORD(signo)] |= _SIG_BIT(signo);
+ return (0);
+}
+
+int
+sigdelset(sigset_t *set, int signo)
+{
+
+ if (signo <= 0 || signo > _SIG_MAXSIG) {
+ errno = EINVAL;
+ return (-1);
+ }
+ set->__bits[_SIG_WORD(signo)] &= ~_SIG_BIT(signo);
+ return (0);
+}
+
+int
+sigemptyset(sigset_t *set)
+{
+ int i;
+
+ for (i = 0; i < _SIG_WORDS; i++)
+ set->__bits[i] = 0;
+ return (0);
+}
+
+int
+sigfillset(sigset_t *set)
+{
+ int i;
+
+ for (i = 0; i < _SIG_WORDS; i++)
+ set->__bits[i] = ~0U;
+ return (0);
+}
+
+int
+sigismember(const sigset_t *set, int signo)
+{
+
+ if (signo <= 0 || signo > _SIG_MAXSIG) {
+ errno = EINVAL;
+ return (-1);
+ }
+ return ((set->__bits[_SIG_WORD(signo)] & _SIG_BIT(signo)) ? 1 : 0);
+}
diff --git a/lib/libc/gen/sleep.3 b/lib/libc/gen/sleep.3
new file mode 100644
index 000000000000..00e8f8d1daba
--- /dev/null
+++ b/lib/libc/gen/sleep.3
@@ -0,0 +1,83 @@
+.\" Copyright (c) 1986, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)sleep.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd February 13, 1998
+.Dt SLEEP 3
+.Os
+.Sh NAME
+.Nm sleep
+.Nd suspend thread execution for an interval measured in seconds
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft unsigned int
+.Fn sleep "unsigned int seconds"
+.Sh DESCRIPTION
+The
+.Fn sleep
+function suspends execution of the calling thread until either
+.Fa seconds
+seconds have elapsed or a signal is delivered to the thread and its
+action is to invoke a signal-catching function or to terminate the
+thread or process.
+System activity may lengthen the sleep by an indeterminate amount.
+.Pp
+This function is implemented using
+.Xr nanosleep 2
+by pausing for
+.Fa seconds
+seconds or until a signal occurs.
+Consequently, in this implementation,
+sleeping has no effect on the state of process timers,
+and there is no special handling for SIGALRM.
+.Sh RETURN VALUES
+If the
+.Fn sleep
+function returns because the requested time has elapsed, the value
+returned will be zero.
+If the
+.Fn sleep
+function returns due to the delivery of a signal, the value returned
+will be the unslept amount (the requested time minus the time actually
+slept) in seconds.
+.Sh SEE ALSO
+.Xr nanosleep 2 ,
+.Xr usleep 3
+.Sh STANDARDS
+The
+.Fn sleep
+function conforms to
+.St -p1003.1-90 .
+.Sh HISTORY
+A
+.Fn sleep
+function appeared in
+.At v7 .
diff --git a/lib/libc/gen/sleep.c b/lib/libc/gen/sleep.c
new file mode 100644
index 000000000000..6c33c3543a52
--- /dev/null
+++ b/lib/libc/gen/sleep.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)sleep.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <errno.h>
+#include <limits.h>
+#include <time.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+#include "libc_private.h"
+
+unsigned int __sleep(unsigned int);
+
+unsigned int
+__sleep(unsigned int seconds)
+{
+ struct timespec time_to_sleep;
+ struct timespec time_remaining;
+
+ /*
+ * Avoid overflow when `seconds' is huge. This assumes that
+ * the maximum value for a time_t is >= INT_MAX.
+ */
+ if (seconds > INT_MAX)
+ return (seconds - INT_MAX + __sleep(INT_MAX));
+
+ time_to_sleep.tv_sec = seconds;
+ time_to_sleep.tv_nsec = 0;
+ if (((int (*)(const struct timespec *, struct timespec *))
+ __libc_interposing[INTERPOS_nanosleep])(
+ &time_to_sleep, &time_remaining) != -1)
+ return (0);
+ if (errno != EINTR)
+ return (seconds); /* best guess */
+ return (time_remaining.tv_sec +
+ (time_remaining.tv_nsec != 0)); /* round up */
+}
+
+__weak_reference(__sleep, sleep);
+__weak_reference(__sleep, _sleep);
diff --git a/lib/libc/gen/srand48.c b/lib/libc/gen/srand48.c
new file mode 100644
index 000000000000..fd369a094c51
--- /dev/null
+++ b/lib/libc/gen/srand48.c
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 1993 Martin Birgmeier
+ * All rights reserved.
+ *
+ * You may redistribute unmodified or modified versions of this source
+ * code provided that the above copyright notice and this and the
+ * following conditions are retained.
+ *
+ * This software is provided ``as is'', and comes with no warranties
+ * of any kind. I shall in no event be liable for anything that happens
+ * to anyone/anything when using this software.
+ */
+
+#include "rand48.h"
+
+extern unsigned short _rand48_seed[3];
+extern unsigned short _rand48_mult[3];
+extern unsigned short _rand48_add;
+
+void
+srand48(long seed)
+{
+ _rand48_seed[0] = RAND48_SEED_0;
+ _rand48_seed[1] = (unsigned short) seed;
+ _rand48_seed[2] = (unsigned short) (seed >> 16);
+ _rand48_mult[0] = RAND48_MULT_0;
+ _rand48_mult[1] = RAND48_MULT_1;
+ _rand48_mult[2] = RAND48_MULT_2;
+ _rand48_add = RAND48_ADD;
+}
diff --git a/lib/libc/gen/statvfs.3 b/lib/libc/gen/statvfs.3
new file mode 100644
index 000000000000..73109bd98342
--- /dev/null
+++ b/lib/libc/gen/statvfs.3
@@ -0,0 +1,187 @@
+.\"
+.\" Copyright 2002 Massachusetts Institute of Technology
+.\"
+.\" Permission to use, copy, modify, and distribute this software and
+.\" its documentation for any purpose and without fee is hereby
+.\" granted, provided that both the above copyright notice and this
+.\" permission notice appear in all copies, that both the above
+.\" copyright notice and this permission notice appear in all
+.\" supporting documentation, and that the name of M.I.T. not be used
+.\" in advertising or publicity pertaining to distribution of the
+.\" software without specific, written prior permission. M.I.T. makes
+.\" no representations about the suitability of this software for any
+.\" purpose. It is provided "as is" without express or implied
+.\" warranty.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
+.\" ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
+.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
+.\" SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+.\" USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+.\" ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+.\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+.\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd July 13, 2002
+.Dt STATVFS 3
+.Os
+.Sh NAME
+.Nm statvfs ,
+.Nm fstatvfs
+.Nd retrieve file system information
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/statvfs.h
+.Ft int
+.Fn statvfs "const char * restrict path" "struct statvfs * restrict buf"
+.Ft int
+.Fn fstatvfs "int fd" "struct statvfs *buf"
+.Sh DESCRIPTION
+The
+.Fn statvfs
+and
+.Fn fstatvfs
+functions fill the structure pointed to by
+.Fa buf
+with garbage.
+This garbage will occasionally bear resemblance to file system
+statistics, but portable applications must not depend on this.
+Applications must pass a pathname or file descriptor which refers to a
+file on the file system in which they are interested.
+.Pp
+The
+.Vt statvfs
+structure contains the following members:
+.Bl -tag -offset indent -width ".Va f_namemax"
+.It Va f_namemax
+The maximum length in bytes of a file name on this file system.
+Applications should use
+.Xr pathconf 2
+instead.
+.It Va f_fsid
+Not meaningful in this implementation.
+.It Va f_frsize
+The size in bytes of the minimum unit of allocation on this
+file system.
+(This corresponds to the
+.Va f_bsize
+member of
+.Vt "struct statfs" . )
+.It Va f_bsize
+The preferred length of I/O requests for files on this file system.
+(Corresponds to the
+.Va f_iosize
+member of
+.Vt "struct statfs" . )
+.It Va f_flag
+Flags describing mount options for this file system; see below.
+.El
+.Pp
+In addition, there are three members of type
+.Vt fsfilcnt_t ,
+which represent counts of file serial numbers
+.Em ( i.e. ,
+inodes); these are named
+.Va f_files , f_favail ,
+and
+.Va f_ffree ,
+and represent the number of file serial numbers which exist in total,
+are available to unprivileged processes, and are available to
+privileged processes, respectively.
+Likewise, the members
+.Va f_blocks , f_bavail ,
+and
+.Va f_bfree
+(all of type
+.Vt fsblkcnt_t )
+represent the respective allocation-block counts.
+.Pp
+There are two flags defined for the
+.Va f_flag
+member:
+.Bl -tag -offset indent -width ".Dv ST_NOSUID"
+.It Dv ST_RDONLY
+The file system is mounted read-only.
+.It Dv ST_NOSUID
+The semantics of the
+.Dv S_ISUID
+and
+.Dv S_ISGID
+file mode bits
+are not supported by, or are disabled on, this file system.
+.El
+.Sh IMPLEMENTATION NOTES
+The
+.Fn statvfs
+and
+.Fn fstatvfs
+functions are implemented as wrappers around the
+.Fn statfs
+and
+.Fn fstatfs
+functions, respectively.
+Not all the information provided by those functions is made available
+through this interface.
+.Sh RETURN VALUES
+.Rv -std statvfs fstatvfs
+.Sh ERRORS
+The
+.Fn statvfs
+and
+.Fn fstatvfs
+functions may fail for any of the reasons documented for
+.Xr statfs 2
+or
+.Xr fstatfs 2
+and
+.Xr pathconf 2
+or
+.Xr fpathconf 2 ,
+respectively.
+In addition,
+.Fn statvfs
+and
+.Fn fstatvfs
+functions may also fail for the following reason:
+.Bl -tag -width Er
+.It Bq Er EOVERFLOW
+One or more of the file system statistics has a value which cannot be
+represented by the data types used in
+.Vt "struct statvfs" .
+.El
+.Sh SEE ALSO
+.Xr pathconf 2 ,
+.Xr statfs 2
+.Sh STANDARDS
+The
+.Fn statvfs
+and
+.Fn fstatvfs
+functions conform to
+.St -p1003.1-2001 .
+As standardized, portable applications cannot depend on these functions
+returning any valid information at all.
+This implementation attempts to provide as much useful information as
+is provided by the underlying file system, subject to the limitations
+of the specified data types.
+.Sh HISTORY
+The
+.Fn statvfs
+and
+.Fn fstatvfs
+functions first appeared in
+.Fx 5.0 .
+.Sh AUTHORS
+The
+.Fn statvfs
+and
+.Fn fstatvfs
+functions and this manual page were written by
+.An Garrett Wollman Aq Mt wollman@FreeBSD.org .
diff --git a/lib/libc/gen/statvfs.c b/lib/libc/gen/statvfs.c
new file mode 100644
index 000000000000..fe9462bd307b
--- /dev/null
+++ b/lib/libc/gen/statvfs.c
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2002 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that both the above copyright notice and this
+ * permission notice appear in all copies, that both the above
+ * copyright notice and this permission notice appear in all
+ * supporting documentation, and that the name of M.I.T. not be used
+ * in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission. M.I.T. makes
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied
+ * warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
+ * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
+ * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <sys/mount.h>
+#include <sys/statvfs.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+static int sfs2svfs(const struct statfs *from, struct statvfs *to);
+
+int
+fstatvfs(int fd, struct statvfs *result)
+{
+ struct statfs sfs;
+ int rv;
+ long pcval;
+
+ rv = _fstatfs(fd, &sfs);
+ if (rv != 0)
+ return (rv);
+
+ rv = sfs2svfs(&sfs, result);
+ if (rv != 0)
+ return (rv);
+
+ /*
+ * Whether pathconf's -1 return means error or unlimited does not
+ * make any difference in this best-effort implementation.
+ */
+ pcval = _fpathconf(fd, _PC_NAME_MAX);
+ if (pcval == -1)
+ result->f_namemax = ~0UL;
+ else
+ result->f_namemax = (unsigned long)pcval;
+ return (0);
+}
+
+int
+statvfs(const char * __restrict path, struct statvfs * __restrict result)
+{
+ struct statfs sfs;
+ int rv;
+ long pcval;
+
+ rv = statfs(path, &sfs);
+ if (rv != 0)
+ return (rv);
+
+ sfs2svfs(&sfs, result);
+
+ /*
+ * Whether pathconf's -1 return means error or unlimited does not
+ * make any difference in this best-effort implementation.
+ */
+ pcval = pathconf(path, _PC_NAME_MAX);
+ if (pcval == -1)
+ result->f_namemax = ~0UL;
+ else
+ result->f_namemax = (unsigned long)pcval;
+ return (0);
+}
+
+static int
+sfs2svfs(const struct statfs *from, struct statvfs *to)
+{
+ static const struct statvfs zvfs;
+
+ *to = zvfs;
+
+ if (from->f_flags & MNT_RDONLY)
+ to->f_flag |= ST_RDONLY;
+ if (from->f_flags & MNT_NOSUID)
+ to->f_flag |= ST_NOSUID;
+
+ /* XXX should we clamp negative values? */
+#define COPY(field) \
+ do { \
+ to->field = from->field; \
+ if (from->field != to->field) { \
+ errno = EOVERFLOW; \
+ return (-1); \
+ } \
+ } while(0)
+
+ COPY(f_bavail);
+ COPY(f_bfree);
+ COPY(f_blocks);
+ COPY(f_ffree);
+ COPY(f_files);
+ to->f_bsize = from->f_iosize;
+ to->f_frsize = from->f_bsize;
+ to->f_favail = to->f_ffree;
+ return (0);
+}
+
+#ifdef MAIN
+#include <err.h>
+#include <stdint.h>
+#include <stdio.h>
+
+int
+main(int argc, char **argv)
+{
+ struct statvfs buf;
+
+ if (statvfs(argv[1], &buf) < 0)
+ err(1, "statvfs");
+
+#define SHOW(field) \
+ printf(#field ": %ju\n", (uintmax_t)buf.field)
+
+ SHOW(f_bavail);
+ SHOW(f_bfree);
+ SHOW(f_blocks);
+ SHOW(f_favail);
+ SHOW(f_ffree);
+ SHOW(f_files);
+ SHOW(f_bsize);
+ SHOW(f_frsize);
+ SHOW(f_namemax);
+ printf("f_flag: %lx\n", (unsigned long)buf.f_flag);
+
+ return 0;
+}
+
+#endif /* MAIN */
diff --git a/lib/libc/gen/stringlist.3 b/lib/libc/gen/stringlist.3
new file mode 100644
index 000000000000..d4480beb0e2d
--- /dev/null
+++ b/lib/libc/gen/stringlist.3
@@ -0,0 +1,127 @@
+.\" $NetBSD: stringlist.3,v 1.5 1999/03/22 19:44:46 garbled Exp $
+.\"
+.\" Copyright (c) 1997, 1999 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This file was contributed to The NetBSD Foundation by Luke Mewburn.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (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 November 28, 1999
+.Dt STRINGLIST 3
+.Os
+.Sh NAME
+.Nm stringlist ,
+.Nm sl_init ,
+.Nm sl_add ,
+.Nm sl_free ,
+.Nm sl_find
+.Nd stringlist manipulation functions
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stringlist.h
+.Ft StringList *
+.Fn sl_init
+.Ft int
+.Fn sl_add "StringList *sl" "char *item"
+.Ft void
+.Fn sl_free "StringList *sl" "int freeall"
+.Ft char *
+.Fn sl_find "StringList *sl" "const char *item"
+.Sh DESCRIPTION
+The
+.Nm
+functions manipulate stringlists, which are lists of
+strings that extend automatically if necessary.
+.Pp
+The
+.Vt StringList
+structure has the following definition:
+.Bd -literal -offset indent
+typedef struct _stringlist {
+ char **sl_str;
+ size_t sl_max;
+ size_t sl_cur;
+} StringList;
+.Ed
+.Bl -tag -width "sl_str" -offset indent
+.It Va sl_str
+a pointer to the base of the array containing the list.
+.It Va sl_max
+the size of
+.Va sl_str .
+.It Va sl_cur
+the offset in
+.Va sl_str
+of the current element.
+.El
+.Pp
+The following stringlist manipulation functions are available:
+.Bl -tag -width "sl_init()"
+.It Fn sl_init
+Create a stringlist.
+Returns a pointer to a
+.Vt StringList ,
+or
+.Dv NULL
+in case of failure.
+.It Fn sl_free
+Releases memory occupied by
+.Fa sl
+and the
+.Fa sl->sl_str
+array.
+If
+.Fa freeall
+is non-zero, then each of the items within
+.Fa sl->sl_str
+is released as well.
+.It Fn sl_add
+Add
+.Fa item
+to
+.Fa sl->sl_str
+at
+.Fa sl->sl_cur ,
+extending the size of
+.Fa sl->sl_str .
+Returns zero upon success, \-1 upon failure.
+.It Fn sl_find
+Find
+.Fa item
+in
+.Fa sl ,
+returning NULL if it is not found.
+.El
+.Sh SEE ALSO
+.Xr free 3 ,
+.Xr malloc 3
+.Sh HISTORY
+The
+.Nm
+functions appeared in
+.Fx 2.2.6
+and
+.Nx 1.3 .
diff --git a/lib/libc/gen/stringlist.c b/lib/libc/gen/stringlist.c
new file mode 100644
index 000000000000..236af17516d6
--- /dev/null
+++ b/lib/libc/gen/stringlist.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 1994 Christos Zoulas
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *rcsid = "$NetBSD: stringlist.c,v 1.2 1997/01/17 07:26:20 lukem Exp $";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <stdio.h>
+#include <string.h>
+#include <err.h>
+#include <stdlib.h>
+#include <stringlist.h>
+#include "un-namespace.h"
+
+#define _SL_CHUNKSIZE 20
+
+/*
+ * sl_init(): Initialize a string list
+ */
+StringList *
+sl_init(void)
+{
+ StringList *sl;
+
+ sl = malloc(sizeof(StringList));
+ if (sl == NULL)
+ _err(1, "stringlist: %m");
+
+ sl->sl_cur = 0;
+ sl->sl_max = _SL_CHUNKSIZE;
+ sl->sl_str = malloc(sl->sl_max * sizeof(char *));
+ if (sl->sl_str == NULL)
+ _err(1, "stringlist: %m");
+ return sl;
+}
+
+
+/*
+ * sl_add(): Add an item to the string list
+ */
+int
+sl_add(StringList *sl, char *name)
+{
+ if (sl->sl_cur == sl->sl_max - 1) {
+ sl->sl_max += _SL_CHUNKSIZE;
+ sl->sl_str = reallocf(sl->sl_str, sl->sl_max * sizeof(char *));
+ if (sl->sl_str == NULL)
+ return (-1);
+ }
+ sl->sl_str[sl->sl_cur++] = name;
+ return (0);
+}
+
+
+/*
+ * sl_free(): Free a stringlist
+ */
+void
+sl_free(StringList *sl, int all)
+{
+ size_t i;
+
+ if (sl == NULL)
+ return;
+ if (sl->sl_str) {
+ if (all)
+ for (i = 0; i < sl->sl_cur; i++)
+ free(sl->sl_str[i]);
+ free(sl->sl_str);
+ }
+ free(sl);
+}
+
+
+/*
+ * sl_find(): Find a name in the string list
+ */
+char *
+sl_find(StringList *sl, const char *name)
+{
+ size_t i;
+
+ for (i = 0; i < sl->sl_cur; i++)
+ if (strcmp(sl->sl_str[i], name) == 0)
+ return sl->sl_str[i];
+
+ return NULL;
+}
diff --git a/lib/libc/gen/strtofflags.3 b/lib/libc/gen/strtofflags.3
new file mode 100644
index 000000000000..38c2ff5f93dc
--- /dev/null
+++ b/lib/libc/gen/strtofflags.3
@@ -0,0 +1,95 @@
+.\" Copyright (c) 1989, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)setmode.3 8.2 (Berkeley) 4/28/95
+.\" $FreeBSD$
+.\"
+.Dd January 1, 2000
+.Dt STRTOFFLAGS 3
+.Os
+.Sh NAME
+.Nm fflagstostr ,
+.Nm strtofflags
+.Nd convert between file flag bits and their string names
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft char *
+.Fn fflagstostr "u_long flags"
+.Ft int
+.Fn strtofflags "char **stringp" "u_long *setp" "u_long *clrp"
+.Sh DESCRIPTION
+The
+.Fn fflagstostr
+function returns a comma separated string of the file flags represented by
+.Fa flags .
+If no flags are set a zero length string is returned.
+.Pp
+If memory cannot be allocated for the return value,
+.Fn fflagstostr
+returns
+.Dv NULL .
+.Pp
+The value returned from
+.Fn fflagstostr
+is obtained from
+.Fn malloc
+and should be returned to the system with
+.Fn free
+when the program is done with it.
+.Pp
+The
+.Fn strtofflags
+function takes a string of file flags, as described in
+.Xr chflags 1 ,
+parses it, and returns the 'set' flags and 'clear' flags
+such as would be given as arguments to
+.Xr chflags 2 .
+On success
+.Fn strtofflags
+returns 0, otherwise it returns non-zero and
+.Fa stringp
+is left pointing to the offending token.
+.Sh ERRORS
+The
+.Fn fflagstostr
+function
+may fail and set errno for any of the errors specified for the library
+routine
+.Xr malloc 3 .
+.Sh SEE ALSO
+.Xr chflags 1 ,
+.Xr chflags 2 ,
+.Xr malloc 3
+.Sh HISTORY
+The
+.Fn fflagstostr
+and
+.Fn strtofflags
+functions first appeared in
+.Fx 4.0 .
diff --git a/lib/libc/gen/strtofflags.c b/lib/libc/gen/strtofflags.c
new file mode 100644
index 000000000000..dba9cd24fb65
--- /dev/null
+++ b/lib/libc/gen/strtofflags.c
@@ -0,0 +1,169 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)stat_flags.c 8.1 (Berkeley) 5/31/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define longestflaglen 12
+static struct {
+ char name[longestflaglen + 1];
+ char invert;
+ u_long flag;
+} const mapping[] = {
+ /* shorter names per flag first, all prefixed by "no" */
+ { "nosappnd", 0, SF_APPEND },
+ { "nosappend", 0, SF_APPEND },
+ { "noarch", 0, SF_ARCHIVED },
+ { "noarchived", 0, SF_ARCHIVED },
+ { "noschg", 0, SF_IMMUTABLE },
+ { "noschange", 0, SF_IMMUTABLE },
+ { "nosimmutable", 0, SF_IMMUTABLE },
+ { "nosunlnk", 0, SF_NOUNLINK },
+ { "nosunlink", 0, SF_NOUNLINK },
+#ifdef SF_SNAPSHOT
+ { "nosnapshot", 0, SF_SNAPSHOT },
+#endif
+ { "nouappnd", 0, UF_APPEND },
+ { "nouappend", 0, UF_APPEND },
+ { "nouarch", 0, UF_ARCHIVE },
+ { "nouarchive", 0, UF_ARCHIVE },
+ { "nohidden", 0, UF_HIDDEN },
+ { "nouhidden", 0, UF_HIDDEN },
+ { "nouchg", 0, UF_IMMUTABLE },
+ { "nouchange", 0, UF_IMMUTABLE },
+ { "nouimmutable", 0, UF_IMMUTABLE },
+ { "nodump", 1, UF_NODUMP },
+ { "nouunlnk", 0, UF_NOUNLINK },
+ { "nouunlink", 0, UF_NOUNLINK },
+ { "nooffline", 0, UF_OFFLINE },
+ { "nouoffline", 0, UF_OFFLINE },
+ { "noopaque", 0, UF_OPAQUE },
+ { "nordonly", 0, UF_READONLY },
+ { "nourdonly", 0, UF_READONLY },
+ { "noreadonly", 0, UF_READONLY },
+ { "noureadonly", 0, UF_READONLY },
+ { "noreparse", 0, UF_REPARSE },
+ { "noureparse", 0, UF_REPARSE },
+ { "nosparse", 0, UF_SPARSE },
+ { "nousparse", 0, UF_SPARSE },
+ { "nosystem", 0, UF_SYSTEM },
+ { "nousystem", 0, UF_SYSTEM }
+};
+#define nmappings (sizeof(mapping) / sizeof(mapping[0]))
+
+/*
+ * fflagstostr --
+ * Convert file flags to a comma-separated string. If no flags
+ * are set, return the empty string.
+ */
+char *
+fflagstostr(u_long flags)
+{
+ char *string;
+ const char *sp;
+ char *dp;
+ u_long setflags;
+ u_int i;
+
+ if ((string = (char *)malloc(nmappings * (longestflaglen + 1))) == NULL)
+ return (NULL);
+
+ setflags = flags;
+ dp = string;
+ for (i = 0; i < nmappings; i++) {
+ if (setflags & mapping[i].flag) {
+ if (dp > string)
+ *dp++ = ',';
+ for (sp = mapping[i].invert ? mapping[i].name :
+ mapping[i].name + 2; *sp; *dp++ = *sp++) ;
+ setflags &= ~mapping[i].flag;
+ }
+ }
+ *dp = '\0';
+ return (string);
+}
+
+/*
+ * strtofflags --
+ * Take string of arguments and return file flags. Return 0 on
+ * success, 1 on failure. On failure, stringp is set to point
+ * to the offending token.
+ */
+int
+strtofflags(char **stringp, u_long *setp, u_long *clrp)
+{
+ char *string, *p;
+ int i;
+
+ if (setp)
+ *setp = 0;
+ if (clrp)
+ *clrp = 0;
+ string = *stringp;
+ while ((p = strsep(&string, "\t ,")) != NULL) {
+ *stringp = p;
+ if (*p == '\0')
+ continue;
+ for (i = 0; i < nmappings; i++) {
+ if (strcmp(p, mapping[i].name + 2) == 0) {
+ if (mapping[i].invert) {
+ if (clrp)
+ *clrp |= mapping[i].flag;
+ } else {
+ if (setp)
+ *setp |= mapping[i].flag;
+ }
+ break;
+ } else if (strcmp(p, mapping[i].name) == 0) {
+ if (mapping[i].invert) {
+ if (setp)
+ *setp |= mapping[i].flag;
+ } else {
+ if (clrp)
+ *clrp |= mapping[i].flag;
+ }
+ break;
+ }
+ }
+ if (i == nmappings)
+ return 1;
+ }
+ return 0;
+}
diff --git a/lib/libc/gen/sysconf.3 b/lib/libc/gen/sysconf.3
new file mode 100644
index 000000000000..4631aeb6bf1b
--- /dev/null
+++ b/lib/libc/gen/sysconf.3
@@ -0,0 +1,276 @@
+.\" Copyright (c) 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)sysconf.3 8.3 (Berkeley) 4/19/94
+.\" $FreeBSD$
+.\"
+.Dd April 26, 2013
+.Dt SYSCONF 3
+.Os
+.Sh NAME
+.Nm sysconf
+.Nd get configurable system variables
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft long
+.Fn sysconf "int name"
+.Sh DESCRIPTION
+This interface is defined by
+.St -p1003.1-88 .
+A far more complete interface is available using
+.Xr sysctl 3 .
+.Pp
+The
+.Fn sysconf
+function provides a method for applications to determine the current
+value of a configurable system limit or option variable.
+The
+.Fa name
+argument specifies the system variable to be queried.
+Symbolic constants for each name value are found in the include file
+.In unistd.h .
+Shell programmers who need access to these parameters should use the
+.Xr getconf 1
+utility.
+.Pp
+The available values are as follows:
+.Bl -tag -width 6n
+.It Li _SC_ARG_MAX
+The maximum bytes of argument to
+.Xr execve 2 .
+.It Li _SC_CHILD_MAX
+The maximum number of simultaneous processes per user id.
+.It Li _SC_CLK_TCK
+The frequency of the statistics clock in ticks per second.
+.It Li _SC_IOV_MAX
+The maximum number of elements in the I/O vector used by
+.Xr readv 2 ,
+.Xr writev 2 ,
+.Xr recvmsg 2 ,
+and
+.Xr sendmsg 2 .
+.It Li _SC_NGROUPS_MAX
+The maximum number of supplemental groups.
+.It Li _SC_NPROCESSORS_CONF
+The number of processors configured.
+.It Li _SC_NPROCESSORS_ONLN
+The number of processors currently online.
+.It Li _SC_OPEN_MAX
+One more than the maximum value the system may assign to a new file descriptor.
+.It Li _SC_PAGESIZE
+The size of a system page in bytes.
+.It Li _SC_PAGE_SIZE
+Equivalent to
+.Li _SC_PAGESIZE .
+.It Li _SC_STREAM_MAX
+The minimum maximum number of streams that a process may have open
+at any one time.
+.It Li _SC_TZNAME_MAX
+The minimum maximum number of types supported for the name of a
+timezone.
+.It Li _SC_JOB_CONTROL
+Return 1 if job control is available on this system, otherwise \-1.
+.It Li _SC_SAVED_IDS
+Returns 1 if saved set-group and saved set-user ID is available,
+otherwise \-1.
+.It Li _SC_VERSION
+The version of
+.St -p1003.1
+with which the system
+attempts to comply.
+.It Li _SC_BC_BASE_MAX
+The maximum ibase/obase values in the
+.Xr bc 1
+utility.
+.It Li _SC_BC_DIM_MAX
+The maximum array size in the
+.Xr bc 1
+utility.
+.It Li _SC_BC_SCALE_MAX
+The maximum scale value in the
+.Xr bc 1
+utility.
+.It Li _SC_BC_STRING_MAX
+The maximum string length in the
+.Xr bc 1
+utility.
+.It Li _SC_COLL_WEIGHTS_MAX
+The maximum number of weights that can be assigned to any entry of
+the LC_COLLATE order keyword in the locale definition file.
+.It Li _SC_EXPR_NEST_MAX
+The maximum number of expressions that can be nested within
+parenthesis by the
+.Xr expr 1
+utility.
+.It Li _SC_LINE_MAX
+The maximum length in bytes of a text-processing utility's input
+line.
+.It Li _SC_RE_DUP_MAX
+The maximum number of repeated occurrences of a regular expression
+permitted when using interval notation.
+.It Li _SC_2_VERSION
+The version of
+.St -p1003.2
+with which the system attempts to comply.
+.It Li _SC_2_C_BIND
+Return 1 if the system's C-language development facilities support the
+C-Language Bindings Option, otherwise \-1.
+.It Li _SC_2_C_DEV
+Return 1 if the system supports the C-Language Development Utilities Option,
+otherwise \-1.
+.It Li _SC_2_CHAR_TERM
+Return 1 if the system supports at least one terminal type capable of
+all operations described in
+.St -p1003.2 ,
+otherwise \-1.
+.It Li _SC_2_FORT_DEV
+Return 1 if the system supports the FORTRAN Development Utilities Option,
+otherwise \-1.
+.It Li _SC_2_FORT_RUN
+Return 1 if the system supports the FORTRAN Runtime Utilities Option,
+otherwise \-1.
+.It Li _SC_2_LOCALEDEF
+Return 1 if the system supports the creation of locales, otherwise \-1.
+.It Li _SC_2_SW_DEV
+Return 1 if the system supports the Software Development Utilities Option,
+otherwise \-1.
+.It Li _SC_2_UPE
+Return 1 if the system supports the User Portability Utilities Option,
+otherwise \-1.
+.It Li _SC_AIO_LISTIO_MAX
+Maximum number of I/O operations in a single list I/O call supported.
+.It Li _SC_AIO_MAX
+Maximum number of outstanding asynchronous I/O operations supported.
+.It Li _SC_AIO_PRIO_DELTA_MAX
+The maximum amount by which a process can decrease its asynchronous I/O
+priority level from its own scheduling priority.
+.It Li _SC_DELAYTIMER_MAX
+Maximum number of timer expiration overruns.
+.It Li _SC_MQ_OPEN_MAX
+The maximum number of open message queue descriptors a process may hold.
+.It Li _SC_RTSIG_MAX
+Maximum number of realtime signals reserved for application use.
+.It Li _SC_SEM_NSEMS_MAX
+Maximum number of semaphores that a process may have.
+.It Li _SC_SEM_VALUE_MAX
+The maximum value a semaphore may have.
+.It Li _SC_SIGQUEUE_MAX
+Maximum number of queued signals that a process may send and have pending at
+the receiver(s) at any time.
+.It Li _SC_TIMER_MAX
+Maximum number of timers per process supported.
+.It Li _SC_GETGR_R_SIZE_MAX
+Suggested initial value for the size of the group entry buffer.
+.It Li _SC_GETPW_R_SIZE_MAX
+Suggested initial value for the size of the password entry buffer.
+.It Li _SC_HOST_NAME_MAX
+Maximum length of a host name (not including the terminating null) as
+returned from the
+.Fn gethostname
+function.
+.It Li _SC_LOGIN_NAME_MAX
+Maximum length of a login name.
+.It Li _SC_THREAD_STACK_MIN
+Minimum size in bytes of thread stack storage.
+.It Li _SC_THREAD_THREADS_MAX
+Maximum number of threads that can be created per process.
+.It Li _SC_TTY_NAME_MAX
+Maximum length of terminal device name.
+.It Li _SC_SYMLOOP_MAX
+Maximum number of symbolic links that can be reliably traversed in the
+resolution of a pathname in the absence of a loop.
+.It Li _SC_ATEXIT_MAX
+Maximum number of functions that may be registered with
+.Fn atexit .
+.It Li _SC_XOPEN_VERSION
+An integer value greater than or equal to 4,
+indicating the version of the X/Open Portability Guide to which this
+system conforms.
+.It Li _SC_XOPEN_XCU_VERSION
+An integer value indicating the version of the XCU Specification to which
+this system conforms.
+.El
+.Pp
+These values also exist, but may not be standard:
+.Bl -tag -width 6n
+.It Li _SC_CPUSET_SIZE
+Size of the kernel cpuset.
+.It Li _SC_PHYS_PAGES
+The number of pages of physical memory.
+Note that it is possible that the product of this value and the value of
+.Li _SC_PAGESIZE
+will overflow a
+.Vt long
+in some configurations on a 32bit machine.
+.El
+.Sh RETURN VALUES
+If the call to
+.Fn sysconf
+is not successful, \-1 is returned and
+.Va errno
+is set appropriately.
+Otherwise, if the variable is associated with functionality that is not
+supported, \-1 is returned and
+.Va errno
+is not modified.
+Otherwise, the current variable value is returned.
+.Sh ERRORS
+The
+.Fn sysconf
+function may fail and set
+.Va errno
+for any of the errors specified for the library function
+.Xr sysctl 3 .
+In addition, the following error may be reported:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The value of the
+.Fa name
+argument is invalid.
+.El
+.Sh SEE ALSO
+.Xr getconf 1 ,
+.Xr pathconf 2 ,
+.Xr confstr 3 ,
+.Xr sysctl 3
+.Sh STANDARDS
+Except for the fact that values returned by
+.Fn sysconf
+may change over the lifetime of the calling process,
+this function conforms to
+.St -p1003.1-88 .
+.Sh HISTORY
+The
+.Fn sysconf
+function first appeared in
+.Bx 4.4 .
+.Sh BUGS
+The value for _SC_STREAM_MAX is a minimum maximum, and required to be
+the same as ANSI C's FOPEN_MAX, so the returned value is a ridiculously
+small and misleading number.
diff --git a/lib/libc/gen/sysconf.c b/lib/libc/gen/sysconf.c
new file mode 100644
index 000000000000..71f232105d43
--- /dev/null
+++ b/lib/libc/gen/sysconf.c
@@ -0,0 +1,624 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Sean Eric Fagan of Cygnus Support.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)sysconf.c 8.2 (Berkeley) 3/20/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/sysctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+
+#include <elf.h>
+#include <errno.h>
+#include <limits.h>
+#include <paths.h>
+#include <pthread.h> /* we just need the limits */
+#include <time.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+#include "../stdlib/atexit.h"
+#include "tzfile.h" /* from ../../../contrib/tzcode/stdtime */
+#include "libc_private.h"
+
+#define _PATH_ZONEINFO TZDIR /* from tzfile.h */
+
+/*
+ * sysconf --
+ * get configurable system variables.
+ *
+ * XXX
+ * POSIX 1003.1 (ISO/IEC 9945-1, 4.8.1.3) states that the variable values
+ * not change during the lifetime of the calling process. This would seem
+ * to require that any change to system limits kill all running processes.
+ * A workaround might be to cache the values when they are first retrieved
+ * and then simply return the cached value on subsequent calls. This is
+ * less useful than returning up-to-date values, however.
+ */
+long
+sysconf(int name)
+{
+ struct rlimit rl;
+ size_t len;
+ int mib[2], sverrno, value;
+ long lvalue, defaultresult;
+ const char *path;
+
+ defaultresult = -1;
+
+ switch (name) {
+ case _SC_ARG_MAX:
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_ARGMAX;
+ break;
+ case _SC_CHILD_MAX:
+ if (getrlimit(RLIMIT_NPROC, &rl) != 0)
+ return (-1);
+ if (rl.rlim_cur == RLIM_INFINITY)
+ return (-1);
+ if (rl.rlim_cur > LONG_MAX) {
+ errno = EOVERFLOW;
+ return (-1);
+ }
+ return ((long)rl.rlim_cur);
+ case _SC_CLK_TCK:
+ return (CLK_TCK);
+ case _SC_NGROUPS_MAX:
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_NGROUPS;
+ break;
+ case _SC_OPEN_MAX:
+ if (getrlimit(RLIMIT_NOFILE, &rl) != 0)
+ return (-1);
+ if (rl.rlim_cur == RLIM_INFINITY)
+ return (-1);
+ if (rl.rlim_cur > LONG_MAX) {
+ errno = EOVERFLOW;
+ return (-1);
+ }
+ return ((long)rl.rlim_cur);
+ case _SC_STREAM_MAX:
+ if (getrlimit(RLIMIT_NOFILE, &rl) != 0)
+ return (-1);
+ if (rl.rlim_cur == RLIM_INFINITY)
+ return (-1);
+ if (rl.rlim_cur > LONG_MAX) {
+ errno = EOVERFLOW;
+ return (-1);
+ }
+ /*
+ * struct __sFILE currently has a limitation that
+ * file descriptors must fit in a signed short.
+ * This doesn't precisely capture the letter of POSIX
+ * but approximates the spirit.
+ */
+ if (rl.rlim_cur > SHRT_MAX)
+ return (SHRT_MAX);
+
+ return ((long)rl.rlim_cur);
+ case _SC_JOB_CONTROL:
+ return (_POSIX_JOB_CONTROL);
+ case _SC_SAVED_IDS:
+ /* XXX - must be 1 */
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_SAVED_IDS;
+ goto yesno;
+ case _SC_VERSION:
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_POSIX1;
+ break;
+ case _SC_BC_BASE_MAX:
+ return (BC_BASE_MAX);
+ case _SC_BC_DIM_MAX:
+ return (BC_DIM_MAX);
+ case _SC_BC_SCALE_MAX:
+ return (BC_SCALE_MAX);
+ case _SC_BC_STRING_MAX:
+ return (BC_STRING_MAX);
+ case _SC_COLL_WEIGHTS_MAX:
+ return (COLL_WEIGHTS_MAX);
+ case _SC_EXPR_NEST_MAX:
+ return (EXPR_NEST_MAX);
+ case _SC_LINE_MAX:
+ return (LINE_MAX);
+ case _SC_RE_DUP_MAX:
+ return (RE_DUP_MAX);
+ case _SC_2_VERSION:
+ /*
+ * This is something of a lie, but it would be silly at
+ * this point to try to deduce this from the contents
+ * of the filesystem.
+ */
+ return (_POSIX2_VERSION);
+ case _SC_2_C_BIND:
+ return (_POSIX2_C_BIND);
+ case _SC_2_C_DEV:
+ return (_POSIX2_C_DEV);
+ case _SC_2_CHAR_TERM:
+ return (_POSIX2_CHAR_TERM);
+ case _SC_2_FORT_DEV:
+ return (_POSIX2_FORT_DEV);
+ case _SC_2_FORT_RUN:
+ return (_POSIX2_FORT_RUN);
+ case _SC_2_LOCALEDEF:
+ return (_POSIX2_LOCALEDEF);
+ case _SC_2_SW_DEV:
+ return (_POSIX2_SW_DEV);
+ case _SC_2_UPE:
+ return (_POSIX2_UPE);
+ case _SC_TZNAME_MAX:
+ path = _PATH_ZONEINFO;
+do_NAME_MAX:
+ sverrno = errno;
+ errno = 0;
+ lvalue = pathconf(path, _PC_NAME_MAX);
+ if (lvalue == -1 && errno != 0)
+ return (-1);
+ errno = sverrno;
+ return (lvalue);
+
+ case _SC_ASYNCHRONOUS_IO:
+#if _POSIX_ASYNCHRONOUS_IO == 0
+ mib[0] = CTL_P1003_1B;
+ mib[1] = CTL_P1003_1B_ASYNCHRONOUS_IO;
+ break;
+#else
+ return (_POSIX_ASYNCHRONOUS_IO);
+#endif
+ case _SC_MAPPED_FILES:
+ return (_POSIX_MAPPED_FILES);
+ case _SC_MEMLOCK:
+ return (_POSIX_MEMLOCK);
+ case _SC_MEMLOCK_RANGE:
+ return (_POSIX_MEMLOCK_RANGE);
+ case _SC_MEMORY_PROTECTION:
+ return (_POSIX_MEMORY_PROTECTION);
+ case _SC_MESSAGE_PASSING:
+#if _POSIX_MESSAGE_PASSING == 0
+ mib[0] = CTL_P1003_1B;
+ mib[1] = CTL_P1003_1B_MESSAGE_PASSING;
+ goto yesno;
+#else
+ return (_POSIX_MESSAGE_PASSING);
+#endif
+ case _SC_PRIORITIZED_IO:
+#if _POSIX_PRIORITIZED_IO == 0
+ mib[0] = CTL_P1003_1B;
+ mib[1] = CTL_P1003_1B_PRIORITIZED_IO;
+ goto yesno;
+#else
+ return (_POSIX_PRIORITIZED_IO);
+#endif
+ case _SC_PRIORITY_SCHEDULING:
+#if _POSIX_PRIORITY_SCHEDULING == 0
+ mib[0] = CTL_P1003_1B;
+ mib[1] = CTL_P1003_1B_PRIORITY_SCHEDULING;
+ goto yesno;
+#else
+ return (_POSIX_PRIORITY_SCHEDULING);
+#endif
+ case _SC_REALTIME_SIGNALS:
+#if _POSIX_REALTIME_SIGNALS == 0
+ mib[0] = CTL_P1003_1B;
+ mib[1] = CTL_P1003_1B_REALTIME_SIGNALS;
+ goto yesno;
+#else
+ return (_POSIX_REALTIME_SIGNALS);
+#endif
+ case _SC_SEMAPHORES:
+#if _POSIX_SEMAPHORES == 0
+ mib[0] = CTL_P1003_1B;
+ mib[1] = CTL_P1003_1B_SEMAPHORES;
+ goto yesno;
+#else
+ return (_POSIX_SEMAPHORES);
+#endif
+ case _SC_FSYNC:
+ return (_POSIX_FSYNC);
+
+ case _SC_SHARED_MEMORY_OBJECTS:
+ return (_POSIX_SHARED_MEMORY_OBJECTS);
+ case _SC_SYNCHRONIZED_IO:
+#if _POSIX_SYNCHRONIZED_IO == 0
+ mib[0] = CTL_P1003_1B;
+ mib[1] = CTL_P1003_1B_SYNCHRONIZED_IO;
+ goto yesno;
+#else
+ return (_POSIX_SYNCHRONIZED_IO);
+#endif
+ case _SC_TIMERS:
+#if _POSIX_TIMERS == 0
+ mib[0] = CTL_P1003_1B;
+ mib[1] = CTL_P1003_1B_TIMERS;
+ goto yesno;
+#else
+ return (_POSIX_TIMERS);
+#endif
+ case _SC_AIO_LISTIO_MAX:
+ mib[0] = CTL_P1003_1B;
+ mib[1] = CTL_P1003_1B_AIO_LISTIO_MAX;
+ break;
+ case _SC_AIO_MAX:
+ mib[0] = CTL_P1003_1B;
+ mib[1] = CTL_P1003_1B_AIO_MAX;
+ break;
+ case _SC_AIO_PRIO_DELTA_MAX:
+ mib[0] = CTL_P1003_1B;
+ mib[1] = CTL_P1003_1B_AIO_PRIO_DELTA_MAX;
+ break;
+ case _SC_DELAYTIMER_MAX:
+ mib[0] = CTL_P1003_1B;
+ mib[1] = CTL_P1003_1B_DELAYTIMER_MAX;
+ goto yesno;
+ case _SC_MQ_OPEN_MAX:
+ mib[0] = CTL_P1003_1B;
+ mib[1] = CTL_P1003_1B_MQ_OPEN_MAX;
+ goto yesno;
+ case _SC_PAGESIZE:
+ defaultresult = getpagesize();
+ mib[0] = CTL_P1003_1B;
+ mib[1] = CTL_P1003_1B_PAGESIZE;
+ goto yesno;
+ case _SC_RTSIG_MAX:
+ mib[0] = CTL_P1003_1B;
+ mib[1] = CTL_P1003_1B_RTSIG_MAX;
+ goto yesno;
+ case _SC_SEM_NSEMS_MAX:
+ mib[0] = CTL_P1003_1B;
+ mib[1] = CTL_P1003_1B_SEM_NSEMS_MAX;
+ goto yesno;
+ case _SC_SEM_VALUE_MAX:
+ mib[0] = CTL_P1003_1B;
+ mib[1] = CTL_P1003_1B_SEM_VALUE_MAX;
+ goto yesno;
+ case _SC_SIGQUEUE_MAX:
+ mib[0] = CTL_P1003_1B;
+ mib[1] = CTL_P1003_1B_SIGQUEUE_MAX;
+ goto yesno;
+ case _SC_TIMER_MAX:
+ mib[0] = CTL_P1003_1B;
+ mib[1] = CTL_P1003_1B_TIMER_MAX;
+yesno:
+ len = sizeof(value);
+ if (sysctl(mib, 2, &value, &len, NULL, 0) == -1)
+ return (-1);
+ if (value == 0)
+ return (defaultresult);
+ return ((long)value);
+
+ case _SC_2_PBS:
+ case _SC_2_PBS_ACCOUNTING:
+ case _SC_2_PBS_CHECKPOINT:
+ case _SC_2_PBS_LOCATE:
+ case _SC_2_PBS_MESSAGE:
+ case _SC_2_PBS_TRACK:
+#if _POSIX2_PBS == 0
+#error "don't know how to determine _SC_2_PBS"
+ /*
+ * This probably requires digging through the filesystem
+ * to see if the appropriate package has been installed.
+ * Since we don't currently support this option at all,
+ * it's not worth the effort to write the code now.
+ * Figuring out which of the sub-options are supported
+ * would be even more difficult, so it's probably easier
+ * to always say ``no''.
+ */
+#else
+ return (_POSIX2_PBS);
+#endif
+ case _SC_ADVISORY_INFO:
+#if _POSIX_ADVISORY_INFO == 0
+#error "_POSIX_ADVISORY_INFO"
+#else
+ return (_POSIX_ADVISORY_INFO);
+#endif
+ case _SC_BARRIERS:
+#if _POSIX_BARRIERS == 0
+#error "_POSIX_BARRIERS"
+#else
+ return (_POSIX_BARRIERS);
+#endif
+ case _SC_CLOCK_SELECTION:
+#if _POSIX_CLOCK_SELECTION == 0
+#error "_POSIX_CLOCK_SELECTION"
+#else
+ return (_POSIX_CLOCK_SELECTION);
+#endif
+ case _SC_CPUTIME:
+ return (_POSIX_CPUTIME);
+#ifdef notdef
+ case _SC_FILE_LOCKING:
+ /*
+ * XXX - The standard doesn't tell us how to define
+ * _POSIX_FILE_LOCKING, so we can't answer this one.
+ */
+#endif
+
+ /*
+ * SUSv4tc1 says the following about _SC_GETGR_R_SIZE_MAX and
+ * _SC_GETPW_R_SIZE_MAX:
+ * Note that sysconf(_SC_GETGR_R_SIZE_MAX) may return -1 if
+ * there is no hard limit on the size of the buffer needed to
+ * store all the groups returned.
+ */
+ case _SC_GETGR_R_SIZE_MAX:
+ case _SC_GETPW_R_SIZE_MAX:
+ return (-1);
+ case _SC_HOST_NAME_MAX:
+ return (MAXHOSTNAMELEN - 1); /* does not include \0 */
+ case _SC_LOGIN_NAME_MAX:
+ return (MAXLOGNAME);
+ case _SC_MONOTONIC_CLOCK:
+#if _POSIX_MONOTONIC_CLOCK == 0
+#error "_POSIX_MONOTONIC_CLOCK"
+#else
+ return (_POSIX_MONOTONIC_CLOCK);
+#endif
+#if _POSIX_MESSAGE_PASSING > -1
+ case _SC_MQ_PRIO_MAX:
+ return (MQ_PRIO_MAX);
+#endif
+ case _SC_READER_WRITER_LOCKS:
+ return (_POSIX_READER_WRITER_LOCKS);
+ case _SC_REGEXP:
+ return (_POSIX_REGEXP);
+ case _SC_SHELL:
+ return (_POSIX_SHELL);
+ case _SC_SPAWN:
+ return (_POSIX_SPAWN);
+ case _SC_SPIN_LOCKS:
+ return (_POSIX_SPIN_LOCKS);
+ case _SC_SPORADIC_SERVER:
+#if _POSIX_SPORADIC_SERVER == 0
+#error "_POSIX_SPORADIC_SERVER"
+#else
+ return (_POSIX_SPORADIC_SERVER);
+#endif
+ case _SC_THREAD_ATTR_STACKADDR:
+ return (_POSIX_THREAD_ATTR_STACKADDR);
+ case _SC_THREAD_ATTR_STACKSIZE:
+ return (_POSIX_THREAD_ATTR_STACKSIZE);
+ case _SC_THREAD_CPUTIME:
+ return (_POSIX_THREAD_CPUTIME);
+ case _SC_THREAD_DESTRUCTOR_ITERATIONS:
+ return (PTHREAD_DESTRUCTOR_ITERATIONS);
+ case _SC_THREAD_KEYS_MAX:
+ return (PTHREAD_KEYS_MAX);
+ case _SC_THREAD_PRIO_INHERIT:
+ return (_POSIX_THREAD_PRIO_INHERIT);
+ case _SC_THREAD_PRIO_PROTECT:
+ return (_POSIX_THREAD_PRIO_PROTECT);
+ case _SC_THREAD_PRIORITY_SCHEDULING:
+ return (_POSIX_THREAD_PRIORITY_SCHEDULING);
+ case _SC_THREAD_PROCESS_SHARED:
+ return (_POSIX_THREAD_PROCESS_SHARED);
+ case _SC_THREAD_SAFE_FUNCTIONS:
+ return (_POSIX_THREAD_SAFE_FUNCTIONS);
+ case _SC_THREAD_STACK_MIN:
+ return (PTHREAD_STACK_MIN);
+ case _SC_THREAD_THREADS_MAX:
+ return (PTHREAD_THREADS_MAX); /* XXX wrong type! */
+ case _SC_TIMEOUTS:
+ return (_POSIX_TIMEOUTS);
+ case _SC_THREADS:
+ return (_POSIX_THREADS);
+ case _SC_TRACE:
+#if _POSIX_TRACE == 0
+#error "_POSIX_TRACE"
+ /* While you're implementing this, also do the ones below. */
+#else
+ return (_POSIX_TRACE);
+#endif
+#if _POSIX_TRACE > -1
+ case _SC_TRACE_EVENT_FILTER:
+ return (_POSIX_TRACE_EVENT_FILTER);
+ case _SC_TRACE_INHERIT:
+ return (_POSIX_TRACE_INHERIT);
+ case _SC_TRACE_LOG:
+ return (_POSIX_TRACE_LOG);
+#endif
+ case _SC_TTY_NAME_MAX:
+ path = _PATH_DEV;
+ goto do_NAME_MAX;
+ case _SC_TYPED_MEMORY_OBJECTS:
+#if _POSIX_TYPED_MEMORY_OBJECTS == 0
+#error "_POSIX_TYPED_MEMORY_OBJECTS"
+#else
+ return (_POSIX_TYPED_MEMORY_OBJECTS);
+#endif
+ case _SC_V6_ILP32_OFF32:
+#if _V6_ILP32_OFF32 == 0
+ if (sizeof(int) * CHAR_BIT == 32 &&
+ sizeof(int) == sizeof(long) &&
+ sizeof(long) == sizeof(void *) &&
+ sizeof(void *) == sizeof(off_t))
+ return 1;
+ else
+ return -1;
+#else
+ return (_V6_ILP32_OFF32);
+#endif
+ case _SC_V6_ILP32_OFFBIG:
+#if _V6_ILP32_OFFBIG == 0
+ if (sizeof(int) * CHAR_BIT == 32 &&
+ sizeof(int) == sizeof(long) &&
+ sizeof(long) == sizeof(void *) &&
+ sizeof(off_t) * CHAR_BIT >= 64)
+ return 1;
+ else
+ return -1;
+#else
+ return (_V6_ILP32_OFFBIG);
+#endif
+ case _SC_V6_LP64_OFF64:
+#if _V6_LP64_OFF64 == 0
+ if (sizeof(int) * CHAR_BIT == 32 &&
+ sizeof(long) * CHAR_BIT == 64 &&
+ sizeof(long) == sizeof(void *) &&
+ sizeof(void *) == sizeof(off_t))
+ return 1;
+ else
+ return -1;
+#else
+ return (_V6_LP64_OFF64);
+#endif
+ case _SC_V6_LPBIG_OFFBIG:
+#if _V6_LPBIG_OFFBIG == 0
+ if (sizeof(int) * CHAR_BIT >= 32 &&
+ sizeof(long) * CHAR_BIT >= 64 &&
+ sizeof(void *) * CHAR_BIT >= 64 &&
+ sizeof(off_t) * CHAR_BIT >= 64)
+ return 1;
+ else
+ return -1;
+#else
+ return (_V6_LPBIG_OFFBIG);
+#endif
+ case _SC_ATEXIT_MAX:
+ return (ATEXIT_SIZE);
+ case _SC_IOV_MAX:
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_IOV_MAX;
+ break;
+ case _SC_XOPEN_CRYPT:
+ return (_XOPEN_CRYPT);
+ case _SC_XOPEN_ENH_I18N:
+ return (_XOPEN_ENH_I18N);
+ case _SC_XOPEN_LEGACY:
+ return (_XOPEN_LEGACY);
+ case _SC_XOPEN_REALTIME:
+#if _XOPEN_REALTIME == 0
+ sverrno = errno;
+ value = sysconf(_SC_ASYNCHRONOUS_IO) > 0 &&
+ sysconf(_SC_MEMLOCK) > 0 &&
+ sysconf(_SC_MEMLOCK_RANGE) > 0 &&
+ sysconf(_SC_MESSAGE_PASSING) > 0 &&
+ sysconf(_SC_PRIORITY_SCHEDULING) > 0 &&
+ sysconf(_SC_REALTIME_SIGNALS) > 0 &&
+ sysconf(_SC_SEMAPHORES) > 0 &&
+ sysconf(_SC_SHARED_MEMORY_OBJECTS) > 0 &&
+ sysconf(_SC_SYNCHRONIZED_IO) > 0 &&
+ sysconf(_SC_TIMERS) > 0;
+ errno = sverrno;
+ if (value)
+ return (200112L);
+ else
+ return (-1);
+#else
+ return (_XOPEN_REALTIME);
+#endif
+ case _SC_XOPEN_REALTIME_THREADS:
+#if _XOPEN_REALTIME_THREADS == 0
+#error "_XOPEN_REALTIME_THREADS"
+#else
+ return (_XOPEN_REALTIME_THREADS);
+#endif
+ case _SC_XOPEN_SHM:
+ len = sizeof(lvalue);
+ sverrno = errno;
+ if (sysctlbyname("kern.ipc.shmmin", &lvalue, &len, NULL,
+ 0) == -1) {
+ errno = sverrno;
+ return (-1);
+ }
+ errno = sverrno;
+ return (1);
+ case _SC_XOPEN_STREAMS:
+ return (_XOPEN_STREAMS);
+ case _SC_XOPEN_UNIX:
+ return (_XOPEN_UNIX);
+#ifdef _XOPEN_VERSION
+ case _SC_XOPEN_VERSION:
+ return (_XOPEN_VERSION);
+#endif
+#ifdef _XOPEN_XCU_VERSION
+ case _SC_XOPEN_XCU_VERSION:
+ return (_XOPEN_XCU_VERSION);
+#endif
+ case _SC_SYMLOOP_MAX:
+ return (MAXSYMLINKS);
+ case _SC_RAW_SOCKETS:
+ return (_POSIX_RAW_SOCKETS);
+ case _SC_IPV6:
+#if _POSIX_IPV6 == 0
+ sverrno = errno;
+ value = _socket(PF_INET6, SOCK_DGRAM, 0);
+ errno = sverrno;
+ if (value >= 0) {
+ _close(value);
+ return (200112L);
+ } else
+ return (0);
+#else
+ return (_POSIX_IPV6);
+#endif
+
+ case _SC_NPROCESSORS_CONF:
+ case _SC_NPROCESSORS_ONLN:
+ if (_elf_aux_info(AT_NCPUS, &value, sizeof(value)) == 0)
+ return ((long)value);
+ mib[0] = CTL_HW;
+ mib[1] = HW_NCPU;
+ break;
+
+#ifdef _SC_PHYS_PAGES
+ case _SC_PHYS_PAGES:
+ len = sizeof(lvalue);
+ if (sysctlbyname("hw.availpages", &lvalue, &len, NULL, 0) == -1)
+ return (-1);
+ return (lvalue);
+#endif
+
+#ifdef _SC_CPUSET_SIZE
+ case _SC_CPUSET_SIZE:
+ len = sizeof(value);
+ if (sysctlbyname("kern.sched.cpusetsize", &value, &len, NULL,
+ 0) == -1)
+ return (-1);
+ return ((long)value);
+#endif
+
+ default:
+ errno = EINVAL;
+ return (-1);
+ }
+ len = sizeof(value);
+ if (sysctl(mib, 2, &value, &len, NULL, 0) == -1)
+ value = -1;
+ return ((long)value);
+}
diff --git a/lib/libc/gen/sysctl.3 b/lib/libc/gen/sysctl.3
new file mode 100644
index 000000000000..633f364b9f2a
--- /dev/null
+++ b/lib/libc/gen/sysctl.3
@@ -0,0 +1,862 @@
+.\" Copyright (c) 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)sysctl.3 8.4 (Berkeley) 5/9/95
+.\" $FreeBSD$
+.\"
+.Dd September 10, 2015
+.Dt SYSCTL 3
+.Os
+.Sh NAME
+.Nm sysctl ,
+.Nm sysctlbyname ,
+.Nm sysctlnametomib
+.Nd get or set system information
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/sysctl.h
+.Ft int
+.Fn sysctl "const int *name" "u_int namelen" "void *oldp" "size_t *oldlenp" "const void *newp" "size_t newlen"
+.Ft int
+.Fn sysctlbyname "const char *name" "void *oldp" "size_t *oldlenp" "const void *newp" "size_t newlen"
+.Ft int
+.Fn sysctlnametomib "const char *name" "int *mibp" "size_t *sizep"
+.Sh DESCRIPTION
+The
+.Fn sysctl
+function retrieves system information and allows processes with
+appropriate privileges to set system information.
+The information available from
+.Fn sysctl
+consists of integers, strings, and tables.
+Information may be retrieved and set from the command interface
+using the
+.Xr sysctl 8
+utility.
+.Pp
+Unless explicitly noted below,
+.Fn sysctl
+returns a consistent snapshot of the data requested.
+Consistency is obtained by locking the destination
+buffer into memory so that the data may be copied out without blocking.
+Calls to
+.Fn sysctl
+are serialized to avoid deadlock.
+.Pp
+The state is described using a ``Management Information Base'' (MIB)
+style name, listed in
+.Fa name ,
+which is a
+.Fa namelen
+length array of integers.
+.Pp
+The
+.Fn sysctlbyname
+function accepts an ASCII representation of the name and internally
+looks up the integer name vector.
+Apart from that, it behaves the same
+as the standard
+.Fn sysctl
+function.
+.Pp
+The information is copied into the buffer specified by
+.Fa oldp .
+The size of the buffer is given by the location specified by
+.Fa oldlenp
+before the call,
+and that location gives the amount of data copied after a successful call
+and after a call that returns with the error code
+.Er ENOMEM .
+If the amount of data available is greater
+than the size of the buffer supplied,
+the call supplies as much data as fits in the buffer provided
+and returns with the error code
+.Er ENOMEM .
+If the old value is not desired,
+.Fa oldp
+and
+.Fa oldlenp
+should be set to NULL.
+.Pp
+The size of the available data can be determined by calling
+.Fn sysctl
+with the
+.Dv NULL
+argument for
+.Fa oldp .
+The size of the available data will be returned in the location pointed to by
+.Fa oldlenp .
+For some operations, the amount of space may change often.
+For these operations,
+the system attempts to round up so that the returned size is
+large enough for a call to return the data shortly thereafter.
+.Pp
+To set a new value,
+.Fa newp
+is set to point to a buffer of length
+.Fa newlen
+from which the requested value is to be taken.
+If a new value is not to be set,
+.Fa newp
+should be set to NULL and
+.Fa newlen
+set to 0.
+.Pp
+The
+.Fn sysctlnametomib
+function accepts an ASCII representation of the name,
+looks up the integer name vector,
+and returns the numeric representation in the mib array pointed to by
+.Fa mibp .
+The number of elements in the mib array is given by the location specified by
+.Fa sizep
+before the call,
+and that location gives the number of entries copied after a successful call.
+The resulting
+.Fa mib
+and
+.Fa size
+may be used in subsequent
+.Fn sysctl
+calls to get the data associated with the requested ASCII name.
+This interface is intended for use by applications that want to
+repeatedly request the same variable (the
+.Fn sysctl
+function runs in about a third the time as the same request made via the
+.Fn sysctlbyname
+function).
+The
+.Fn sysctlnametomib
+function is also useful for fetching mib prefixes and then adding
+a final component.
+For example, to fetch process information
+for processes with pid's less than 100:
+.Pp
+.Bd -literal -offset indent -compact
+int i, mib[4];
+size_t len;
+struct kinfo_proc kp;
+
+/* Fill out the first three components of the mib */
+len = 4;
+sysctlnametomib("kern.proc.pid", mib, &len);
+
+/* Fetch and print entries for pid's < 100 */
+for (i = 0; i < 100; i++) {
+ mib[3] = i;
+ len = sizeof(kp);
+ if (sysctl(mib, 4, &kp, &len, NULL, 0) == -1)
+ perror("sysctl");
+ else if (len > 0)
+ printkproc(&kp);
+}
+.Ed
+.Pp
+The top level names are defined with a CTL_ prefix in
+.In sys/sysctl.h ,
+and are as follows.
+The next and subsequent levels down are found in the include files
+listed here, and described in separate sections below.
+.Bl -column CTLXMACHDEPXXX "Next Level NamesXXXXXX" -offset indent
+.It Sy Name Ta Sy Next Level Names Ta Sy Description
+.It Dv CTL_DEBUG Ta In sys/sysctl.h Ta Debugging
+.It Dv CTL_VFS Ta In sys/mount.h Ta File system
+.It Dv CTL_HW Ta In sys/sysctl.h Ta Generic CPU, I/O
+.It Dv CTL_KERN Ta In sys/sysctl.h Ta High kernel limits
+.It Dv CTL_MACHDEP Ta In sys/sysctl.h Ta Machine dependent
+.It Dv CTL_NET Ta In sys/socket.h Ta Networking
+.It Dv CTL_USER Ta In sys/sysctl.h Ta User-level
+.It Dv CTL_VM Ta In vm/vm_param.h Ta Virtual memory
+.El
+.Pp
+For example, the following retrieves the maximum number of processes allowed
+in the system:
+.Pp
+.Bd -literal -offset indent -compact
+int mib[2], maxproc;
+size_t len;
+
+mib[0] = CTL_KERN;
+mib[1] = KERN_MAXPROC;
+len = sizeof(maxproc);
+sysctl(mib, 2, &maxproc, &len, NULL, 0);
+.Ed
+.Pp
+To retrieve the standard search path for the system utilities:
+.Pp
+.Bd -literal -offset indent -compact
+int mib[2];
+size_t len;
+char *p;
+
+mib[0] = CTL_USER;
+mib[1] = USER_CS_PATH;
+sysctl(mib, 2, NULL, &len, NULL, 0);
+p = malloc(len);
+sysctl(mib, 2, p, &len, NULL, 0);
+.Ed
+.Ss CTL_DEBUG
+The debugging variables vary from system to system.
+A debugging variable may be added or deleted without need to recompile
+.Fn sysctl
+to know about it.
+Each time it runs,
+.Fn sysctl
+gets the list of debugging variables from the kernel and
+displays their current values.
+The system defines twenty
+.Pq Vt "struct ctldebug"
+variables named
+.Va debug0
+through
+.Va debug19 .
+They are declared as separate variables so that they can be
+individually initialized at the location of their associated variable.
+The loader prevents multiple use of the same variable by issuing errors
+if a variable is initialized in more than one place.
+For example, to export the variable
+.Va dospecialcheck
+as a debugging variable, the following declaration would be used:
+.Pp
+.Bd -literal -offset indent -compact
+int dospecialcheck = 1;
+struct ctldebug debug5 = { "dospecialcheck", &dospecialcheck };
+.Ed
+.Ss CTL_VFS
+A distinguished second level name, VFS_GENERIC,
+is used to get general information about all file systems.
+One of its third level identifiers is VFS_MAXTYPENUM
+that gives the highest valid file system type number.
+Its other third level identifier is VFS_CONF that
+returns configuration information about the file system
+type given as a fourth level identifier (see
+.Xr getvfsbyname 3
+as an example of its use).
+The remaining second level identifiers are the
+file system type number returned by a
+.Xr statfs 2
+call or from VFS_CONF.
+The third level identifiers available for each file system
+are given in the header file that defines the mount
+argument structure for that file system.
+.Ss CTL_HW
+The string and integer information available for the CTL_HW level
+is detailed below.
+The changeable column shows whether a process with appropriate
+privilege may change the value.
+.Bl -column "Second Level Name" integerXXX Changeable -offset indent
+.It Sy Second Level Name Ta Sy Type Ta Sy Changeable
+.It Dv HW_MACHINE Ta string Ta no
+.It Dv HW_MODEL Ta string Ta no
+.It Dv HW_NCPU Ta integer Ta no
+.It Dv HW_BYTEORDER Ta integer Ta no
+.It Dv HW_PHYSMEM Ta integer Ta no
+.It Dv HW_USERMEM Ta integer Ta no
+.It Dv HW_PAGESIZE Ta integer Ta no
+.\".It Dv HW_DISKNAMES Ta integer Ta no
+.\".It Dv HW_DISKSTATS Ta integer Ta no
+.It Dv HW_FLOATINGPT Ta integer Ta no
+.It Dv HW_MACHINE_ARCH Ta string Ta no
+.It Dv HW_REALMEM Ta integer Ta no
+.El
+.Bl -tag -width 6n
+.It Li HW_MACHINE
+The machine class.
+.It Li HW_MODEL
+The machine model
+.It Li HW_NCPU
+The number of cpus.
+.It Li HW_BYTEORDER
+The byteorder (4321 or 1234).
+.It Li HW_PHYSMEM
+The bytes of physical memory.
+.It Li HW_USERMEM
+The bytes of non-kernel memory.
+.It Li HW_PAGESIZE
+The software page size.
+.\".It Fa HW_DISKNAMES
+.\".It Fa HW_DISKSTATS
+.It Li HW_FLOATINGPT
+Nonzero if the floating point support is in hardware.
+.It Li HW_MACHINE_ARCH
+The machine dependent architecture type.
+.It Li HW_REALMEM
+The bytes of real memory.
+.El
+.Ss CTL_KERN
+The string and integer information available for the CTL_KERN level
+is detailed below.
+The changeable column shows whether a process with appropriate
+privilege may change the value.
+The types of data currently available are process information,
+system vnodes, the open file entries, routing table entries,
+virtual memory statistics, load average history, and clock rate
+information.
+.Bl -column "KERNXMAXFILESPERPROCXXX" "struct clockrateXXX" -offset indent
+.It Sy Second Level Name Ta Sy Type Ta Sy Changeable
+.It Dv KERN_ARGMAX Ta integer Ta no
+.It Dv KERN_BOOTFILE Ta string Ta yes
+.It Dv KERN_BOOTTIME Ta struct timeval Ta no
+.It Dv KERN_CLOCKRATE Ta struct clockinfo Ta no
+.It Dv KERN_FILE Ta struct xfile Ta no
+.It Dv KERN_HOSTID Ta integer Ta yes
+.It Dv KERN_HOSTUUID Ta string Ta yes
+.It Dv KERN_HOSTNAME Ta string Ta yes
+.It Dv KERN_JOB_CONTROL Ta integer Ta no
+.It Dv KERN_MAXFILES Ta integer Ta yes
+.It Dv KERN_MAXFILESPERPROC Ta integer Ta yes
+.It Dv KERN_MAXPROC Ta integer Ta no
+.It Dv KERN_MAXPROCPERUID Ta integer Ta yes
+.It Dv KERN_MAXVNODES Ta integer Ta yes
+.It Dv KERN_NGROUPS Ta integer Ta no
+.It Dv KERN_NISDOMAINNAME Ta string Ta yes
+.It Dv KERN_OSRELDATE Ta integer Ta no
+.It Dv KERN_OSRELEASE Ta string Ta no
+.It Dv KERN_OSREV Ta integer Ta no
+.It Dv KERN_OSTYPE Ta string Ta no
+.It Dv KERN_POSIX1 Ta integer Ta no
+.It Dv KERN_PROC Ta node Ta not applicable
+.It Dv KERN_PROF Ta node Ta not applicable
+.It Dv KERN_QUANTUM Ta integer Ta yes
+.It Dv KERN_SAVED_IDS Ta integer Ta no
+.It Dv KERN_SECURELVL Ta integer Ta raise only
+.It Dv KERN_UPDATEINTERVAL Ta integer Ta no
+.It Dv KERN_VERSION Ta string Ta no
+.It Dv KERN_VNODE Ta struct xvnode Ta no
+.El
+.Bl -tag -width 6n
+.It Li KERN_ARGMAX
+The maximum bytes of argument to
+.Xr execve 2 .
+.It Li KERN_BOOTFILE
+The full pathname of the file from which the kernel was loaded.
+.It Li KERN_BOOTTIME
+A
+.Va struct timeval
+structure is returned.
+This structure contains the time that the system was booted.
+.It Li KERN_CLOCKRATE
+A
+.Va struct clockinfo
+structure is returned.
+This structure contains the clock, statistics clock and profiling clock
+frequencies, the number of micro-seconds per hz tick and the skew rate.
+.It Li KERN_FILE
+Return the entire file table.
+The returned data consists of an array of
+.Va struct xfile ,
+whose size depends on the current number of such objects in the system.
+.It Li KERN_HOSTID
+Get or set the host ID.
+.It Li KERN_HOSTUUID
+Get or set the host's universally unique identifier (UUID).
+.It Li KERN_HOSTNAME
+Get or set the hostname.
+.It Li KERN_JOB_CONTROL
+Return 1 if job control is available on this system, otherwise 0.
+.It Li KERN_MAXFILES
+The maximum number of files that may be open in the system.
+.It Li KERN_MAXFILESPERPROC
+The maximum number of files that may be open for a single process.
+This limit only applies to processes with an effective uid of nonzero
+at the time of the open request.
+Files that have already been opened are not affected if the limit
+or the effective uid is changed.
+.It Li KERN_MAXPROC
+The maximum number of concurrent processes the system will allow.
+.It Li KERN_MAXPROCPERUID
+The maximum number of concurrent processes the system will allow
+for a single effective uid.
+This limit only applies to processes with an effective uid of nonzero
+at the time of a fork request.
+Processes that have already been started are not affected if the limit
+is changed.
+.It Li KERN_MAXVNODES
+The maximum number of vnodes available on the system.
+.It Li KERN_NGROUPS
+The maximum number of supplemental groups.
+.It Li KERN_NISDOMAINNAME
+The name of the current YP/NIS domain.
+.It Li KERN_OSRELDATE
+The kernel release version in the format
+.Ar M Ns Ar mm Ns Ar R Ns Ar xx ,
+where
+.Ar M
+is the major version,
+.Ar mm
+is the two digit minor version,
+.Ar R
+is 0 if release branch, otherwise 1,
+and
+.Ar xx
+is updated when the available APIs change.
+.Pp
+The userland release version is available from
+.In osreldate.h ;
+parse this file if you need to get the release version of
+the currently installed userland.
+.It Li KERN_OSRELEASE
+The system release string.
+.It Li KERN_OSREV
+The system revision string.
+.It Li KERN_OSTYPE
+The system type string.
+.It Li KERN_POSIX1
+The version of
+.St -p1003.1
+with which the system
+attempts to comply.
+.It Li KERN_PROC
+Return selected information about specific running processes.
+.Pp
+For the following names, an array of
+.Va struct kinfo_proc
+structures is returned,
+whose size depends on the current number of such objects in the system.
+.Bl -column "Third Level NameXXXXXX" "Fourth LevelXXXXXX" -offset indent
+.It Sy Third Level Name Ta Sy Fourth Level
+.It Dv KERN_PROC_ALL Ta None
+.It Dv KERN_PROC_PID Ta A process ID
+.It Dv KERN_PROC_PGRP Ta A process group
+.It Dv KERN_PROC_TTY Ta A tty device
+.It Dv KERN_PROC_UID Ta A user ID
+.It Dv KERN_PROC_RUID Ta A real user ID
+.El
+.Pp
+If the third level name is
+.Dv KERN_PROC_ARGS
+then the command line argument
+array is returned in a flattened form, i.e., zero-terminated arguments
+follow each other.
+The total size of array is returned.
+It is also possible for a process to set its own process title this way.
+If the third level name is
+.Dv KERN_PROC_PATHNAME ,
+the path of the
+process' text file is stored.
+For
+.Dv KERN_PROC_PATHNAME ,
+a process ID of
+.Li \-1
+implies the current process.
+.Bl -column "Third Level NameXXXXXX" "Fourth LevelXXXXXX" -offset indent
+.It Sy Third Level Name Ta Sy Fourth Level
+.It Dv KERN_PROC_ARGS Ta "A process ID"
+.It Dv KERN_PROC_PATHNAME Ta "A process ID"
+.El
+.It Li KERN_PROF
+Return profiling information about the kernel.
+If the kernel is not compiled for profiling,
+attempts to retrieve any of the KERN_PROF values will
+fail with
+.Er ENOENT .
+The third level names for the string and integer profiling information
+is detailed below.
+The changeable column shows whether a process with appropriate
+privilege may change the value.
+.Bl -column "GPROFXGMONPARAMXXX" "struct gmonparamXXX" -offset indent
+.It Sy Third Level Name Ta Sy Type Ta Sy Changeable
+.It Dv GPROF_STATE Ta integer Ta yes
+.It Dv GPROF_COUNT Ta u_short[\|] Ta yes
+.It Dv GPROF_FROMS Ta u_short[\|] Ta yes
+.It Dv GPROF_TOS Ta struct tostruct Ta yes
+.It Dv GPROF_GMONPARAM Ta struct gmonparam Ta no
+.El
+.Pp
+The variables are as follows:
+.Bl -tag -width 6n
+.It Li GPROF_STATE
+Returns GMON_PROF_ON or GMON_PROF_OFF to show that profiling
+is running or stopped.
+.It Li GPROF_COUNT
+Array of statistical program counter counts.
+.It Li GPROF_FROMS
+Array indexed by program counter of call-from points.
+.It Li GPROF_TOS
+Array of
+.Va struct tostruct
+describing destination of calls and their counts.
+.It Li GPROF_GMONPARAM
+Structure giving the sizes of the above arrays.
+.El
+.It Li KERN_QUANTUM
+The maximum period of time, in microseconds, for which a process is allowed
+to run without being preempted if other processes are in the run queue.
+.It Li KERN_SAVED_IDS
+Returns 1 if saved set-group and saved set-user ID is available.
+.It Li KERN_SECURELVL
+The system security level.
+This level may be raised by processes with appropriate privilege.
+It may not be lowered.
+.It Li KERN_VERSION
+The system version string.
+.It Li KERN_VNODE
+Return the entire vnode table.
+Note, the vnode table is not necessarily a consistent snapshot of
+the system.
+The returned data consists of an array whose size depends on the
+current number of such objects in the system.
+Each element of the array consists of a
+.Va struct xvnode .
+.El
+.Ss CTL_NET
+The string and integer information available for the CTL_NET level
+is detailed below.
+The changeable column shows whether a process with appropriate
+privilege may change the value.
+.Bl -column "Second Level NameXXXXXX" "routing messagesXXX" -offset indent
+.It Sy Second Level Name Ta Sy Type Ta Sy Changeable
+.It Dv PF_ROUTE Ta routing messages Ta no
+.It Dv PF_INET Ta IPv4 values Ta yes
+.It Dv PF_INET6 Ta IPv6 values Ta yes
+.El
+.Bl -tag -width 6n
+.It Li PF_ROUTE
+Return the entire routing table or a subset of it.
+The data is returned as a sequence of routing messages (see
+.Xr route 4
+for the header file, format and meaning).
+The length of each message is contained in the message header.
+.Pp
+The third level name is a protocol number, which is currently always 0.
+The fourth level name is an address family, which may be set to 0 to
+select all address families.
+The fifth, sixth, and seventh level names are as follows:
+.Bl -column -offset indent "Fifth Level" "Sixth Level" "Seventh Level"
+.It Sy Fifth level Ta Sy Sixth Level Ta Sy Seventh Level
+.It Dv NET_RT_FLAGS Ta rtflags Ta None
+.It Dv NET_RT_DUMP Ta None Ta None or fib number
+.It Dv NET_RT_IFLIST Ta 0 or if_index Ta None
+.It Dv NET_RT_IFMALIST Ta 0 or if_index Ta None
+.It Dv NET_RT_IFLISTL Ta 0 or if_index Ta None
+.El
+.Pp
+The
+.Dv NET_RT_IFMALIST
+name returns information about multicast group memberships on all interfaces
+if 0 is specified, or for the interface specified by
+.Va if_index .
+.Pp
+The
+.Dv NET_RT_IFLISTL
+is like
+.Dv NET_RT_IFLIST ,
+just returning message header structs with additional fields allowing the
+interface to be extended without breaking binary compatibility.
+The
+.Dv NET_RT_IFLISTL
+uses 'l' versions of the message header structures:
+.Va struct if_msghdrl
+and
+.Va struct ifa_msghdrl .
+.It Li PF_INET
+Get or set various global information about the IPv4
+(Internet Protocol version 4).
+The third level name is the protocol.
+The fourth level name is the variable name.
+The currently defined protocols and names are:
+.Bl -column ProtocolXX VariableXX TypeXX ChangeableXX
+.It Sy Protocol Ta Sy Variable Ta Sy Type Ta Sy Changeable
+.It icmp Ta bmcastecho Ta integer Ta yes
+.It icmp Ta maskrepl Ta integer Ta yes
+.It ip Ta forwarding Ta integer Ta yes
+.It ip Ta redirect Ta integer Ta yes
+.It ip Ta ttl Ta integer Ta yes
+.It udp Ta checksum Ta integer Ta yes
+.El
+.Pp
+The variables are as follows:
+.Bl -tag -width 6n
+.It Li icmp.bmcastecho
+Returns 1 if an ICMP echo request to a broadcast or multicast address is
+to be answered.
+.It Li icmp.maskrepl
+Returns 1 if ICMP network mask requests are to be answered.
+.It Li ip.forwarding
+Returns 1 when IP forwarding is enabled for the host,
+meaning that the host is acting as a router.
+.It Li ip.redirect
+Returns 1 when ICMP redirects may be sent by the host.
+This option is ignored unless the host is routing IP packets,
+and should normally be enabled on all systems.
+.It Li ip.ttl
+The maximum time-to-live (hop count) value for an IP packet sourced by
+the system.
+This value applies to normal transport protocols, not to ICMP.
+.It Li udp.checksum
+Returns 1 when UDP checksums are being computed and checked.
+Disabling UDP checksums is strongly discouraged.
+.Pp
+For variables net.inet.*.ipsec, please refer to
+.Xr ipsec 4 .
+.El
+.It Li PF_INET6
+Get or set various global information about the IPv6
+(Internet Protocol version 6).
+The third level name is the protocol.
+The fourth level name is the variable name.
+.Pp
+For variables net.inet6.* please refer to
+.Xr inet6 4 .
+For variables net.inet6.*.ipsec6, please refer to
+.Xr ipsec 4 .
+.El
+.Ss CTL_USER
+The string and integer information available for the CTL_USER level
+is detailed below.
+The changeable column shows whether a process with appropriate
+privilege may change the value.
+.Bl -column "USER_COLL_WEIGHTS_MAXXXX" "integerXXX" -offset indent
+.It Sy Second Level Name Ta Sy Type Ta Sy Changeable
+.It Dv USER_BC_BASE_MAX Ta integer Ta no
+.It Dv USER_BC_DIM_MAX Ta integer Ta no
+.It Dv USER_BC_SCALE_MAX Ta integer Ta no
+.It Dv USER_BC_STRING_MAX Ta integer Ta no
+.It Dv USER_COLL_WEIGHTS_MAX Ta integer Ta no
+.It Dv USER_CS_PATH Ta string Ta no
+.It Dv USER_EXPR_NEST_MAX Ta integer Ta no
+.It Dv USER_LINE_MAX Ta integer Ta no
+.It Dv USER_POSIX2_CHAR_TERM Ta integer Ta no
+.It Dv USER_POSIX2_C_BIND Ta integer Ta no
+.It Dv USER_POSIX2_C_DEV Ta integer Ta no
+.It Dv USER_POSIX2_FORT_DEV Ta integer Ta no
+.It Dv USER_POSIX2_FORT_RUN Ta integer Ta no
+.It Dv USER_POSIX2_LOCALEDEF Ta integer Ta no
+.It Dv USER_POSIX2_SW_DEV Ta integer Ta no
+.It Dv USER_POSIX2_UPE Ta integer Ta no
+.It Dv USER_POSIX2_VERSION Ta integer Ta no
+.It Dv USER_RE_DUP_MAX Ta integer Ta no
+.It Dv USER_STREAM_MAX Ta integer Ta no
+.It Dv USER_TZNAME_MAX Ta integer Ta no
+.El
+.Bl -tag -width 6n
+.It Li USER_BC_BASE_MAX
+The maximum ibase/obase values in the
+.Xr bc 1
+utility.
+.It Li USER_BC_DIM_MAX
+The maximum array size in the
+.Xr bc 1
+utility.
+.It Li USER_BC_SCALE_MAX
+The maximum scale value in the
+.Xr bc 1
+utility.
+.It Li USER_BC_STRING_MAX
+The maximum string length in the
+.Xr bc 1
+utility.
+.It Li USER_COLL_WEIGHTS_MAX
+The maximum number of weights that can be assigned to any entry of
+the LC_COLLATE order keyword in the locale definition file.
+.It Li USER_CS_PATH
+Return a value for the
+.Ev PATH
+environment variable that finds all the standard utilities.
+.It Li USER_EXPR_NEST_MAX
+The maximum number of expressions that can be nested within
+parenthesis by the
+.Xr expr 1
+utility.
+.It Li USER_LINE_MAX
+The maximum length in bytes of a text-processing utility's input
+line.
+.It Li USER_POSIX2_CHAR_TERM
+Return 1 if the system supports at least one terminal type capable of
+all operations described in
+.St -p1003.2 ,
+otherwise 0.
+.It Li USER_POSIX2_C_BIND
+Return 1 if the system's C-language development facilities support the
+C-Language Bindings Option, otherwise 0.
+.It Li USER_POSIX2_C_DEV
+Return 1 if the system supports the C-Language Development Utilities Option,
+otherwise 0.
+.It Li USER_POSIX2_FORT_DEV
+Return 1 if the system supports the FORTRAN Development Utilities Option,
+otherwise 0.
+.It Li USER_POSIX2_FORT_RUN
+Return 1 if the system supports the FORTRAN Runtime Utilities Option,
+otherwise 0.
+.It Li USER_POSIX2_LOCALEDEF
+Return 1 if the system supports the creation of locales, otherwise 0.
+.It Li USER_POSIX2_SW_DEV
+Return 1 if the system supports the Software Development Utilities Option,
+otherwise 0.
+.It Li USER_POSIX2_UPE
+Return 1 if the system supports the User Portability Utilities Option,
+otherwise 0.
+.It Li USER_POSIX2_VERSION
+The version of
+.St -p1003.2
+with which the system attempts to comply.
+.It Li USER_RE_DUP_MAX
+The maximum number of repeated occurrences of a regular expression
+permitted when using interval notation.
+.It Li USER_STREAM_MAX
+The minimum maximum number of streams that a process may have open
+at any one time.
+.It Li USER_TZNAME_MAX
+The minimum maximum number of types supported for the name of a
+timezone.
+.El
+.Ss CTL_VM
+The string and integer information available for the CTL_VM level
+is detailed below.
+The changeable column shows whether a process with appropriate
+privilege may change the value.
+.Bl -column "Second Level NameXXXXXX" "struct loadavgXXX" -offset indent
+.It Sy Second Level Name Ta Sy Type Ta Sy Changeable
+.It Dv VM_LOADAVG Ta struct loadavg Ta no
+.It Dv VM_TOTAL Ta struct vmtotal Ta no
+.It Dv VM_SWAPPING_ENABLED Ta integer Ta maybe
+.It Dv VM_V_FREE_MIN Ta integer Ta yes
+.It Dv VM_V_FREE_RESERVED Ta integer Ta yes
+.It Dv VM_V_FREE_TARGET Ta integer Ta yes
+.It Dv VM_V_INACTIVE_TARGET Ta integer Ta yes
+.It Dv VM_V_PAGEOUT_FREE_MIN Ta integer Ta yes
+.El
+.Bl -tag -width 6n
+.It Li VM_LOADAVG
+Return the load average history.
+The returned data consists of a
+.Va struct loadavg .
+.It Li VM_TOTAL
+Return the system wide virtual memory statistics.
+The returned data consists of a
+.Va struct vmtotal .
+.It Li VM_SWAPPING_ENABLED
+1 if process swapping is enabled or 0 if disabled.
+This variable is
+permanently set to 0 if the kernel was built with swapping disabled.
+.It Li VM_V_FREE_MIN
+Minimum amount of memory (cache memory plus free memory)
+required to be available before a process waiting on memory will be
+awakened.
+.It Li VM_V_FREE_RESERVED
+Processes will awaken the pageout daemon and wait for memory if the
+number of free and cached pages drops below this value.
+.It Li VM_V_FREE_TARGET
+The total amount of free memory (including cache memory) that the
+pageout daemon tries to maintain.
+.It Li VM_V_INACTIVE_TARGET
+The desired number of inactive pages that the pageout daemon should
+achieve when it runs.
+Inactive pages can be quickly inserted into
+process address space when needed.
+.It Li VM_V_PAGEOUT_FREE_MIN
+If the amount of free and cache memory falls below this value, the
+pageout daemon will enter "memory conserving mode" to avoid deadlock.
+.El
+.Sh RETURN VALUES
+.Rv -std
+.Sh FILES
+.Bl -tag -width <netinet/icmpXvar.h> -compact
+.It In sys/sysctl.h
+definitions for top level identifiers, second level kernel and hardware
+identifiers, and user level identifiers
+.It In sys/socket.h
+definitions for second level network identifiers
+.It In sys/gmon.h
+definitions for third level profiling identifiers
+.It In vm/vm_param.h
+definitions for second level virtual memory identifiers
+.It In netinet/in.h
+definitions for third level IPv4/IPv6 identifiers and
+fourth level IPv4/v6 identifiers
+.It In netinet/icmp_var.h
+definitions for fourth level ICMP identifiers
+.It In netinet/icmp6.h
+definitions for fourth level ICMPv6 identifiers
+.It In netinet/udp_var.h
+definitions for fourth level UDP identifiers
+.El
+.Sh ERRORS
+The following errors may be reported:
+.Bl -tag -width Er
+.It Bq Er EFAULT
+The buffer
+.Fa name ,
+.Fa oldp ,
+.Fa newp ,
+or length pointer
+.Fa oldlenp
+contains an invalid address.
+.It Bq Er EINVAL
+The
+.Fa name
+array is less than two or greater than CTL_MAXNAME.
+.It Bq Er EINVAL
+A non-null
+.Fa newp
+is given and its specified length in
+.Fa newlen
+is too large or too small.
+.It Bq Er ENOMEM
+The length pointed to by
+.Fa oldlenp
+is too short to hold the requested value.
+.It Bq Er ENOMEM
+The smaller of either the length pointed to by
+.Fa oldlenp
+or the estimated size of the returned data exceeds the
+system limit on locked memory.
+.It Bq Er ENOMEM
+Locking the buffer
+.Fa oldp ,
+or a portion of the buffer if the estimated size of the data
+to be returned is smaller,
+would cause the process to exceed its per-process locked memory limit.
+.It Bq Er ENOTDIR
+The
+.Fa name
+array specifies an intermediate rather than terminal name.
+.It Bq Er EISDIR
+The
+.Fa name
+array specifies a terminal name, but the actual name is not terminal.
+.It Bq Er ENOENT
+The
+.Fa name
+array specifies a value that is unknown.
+.It Bq Er EPERM
+An attempt is made to set a read-only value.
+.It Bq Er EPERM
+A process without appropriate privilege attempts to set a value.
+.El
+.Sh SEE ALSO
+.Xr confstr 3 ,
+.Xr kvm 3 ,
+.Xr sysconf 3 ,
+.Xr sysctl 8
+.Sh HISTORY
+The
+.Fn sysctl
+function first appeared in
+.Bx 4.4 .
diff --git a/lib/libc/gen/sysctl.c b/lib/libc/gen/sysctl.c
new file mode 100644
index 000000000000..b83b439f6501
--- /dev/null
+++ b/lib/libc/gen/sysctl.c
@@ -0,0 +1,195 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)sysctl.c 8.2 (Berkeley) 1/4/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/sysctl.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <paths.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+
+extern int __sysctl(const int *name, u_int namelen, void *oldp,
+ size_t *oldlenp, const void *newp, size_t newlen);
+
+int
+sysctl(const int *name, u_int namelen, void *oldp, size_t *oldlenp,
+ const void *newp, size_t newlen)
+{
+ int retval;
+ size_t orig_oldlen;
+
+ orig_oldlen = oldlenp ? *oldlenp : 0;
+ retval = __sysctl(name, namelen, oldp, oldlenp, newp, newlen);
+ /*
+ * All valid names under CTL_USER have a dummy entry in the sysctl
+ * tree (to support name lookups and enumerations) with an
+ * empty/zero value, and the true value is supplied by this routine.
+ * For all such names, __sysctl() is used solely to validate the
+ * name.
+ *
+ * Return here unless there was a successful lookup for a CTL_USER
+ * name.
+ */
+ if (retval || name[0] != CTL_USER)
+ return (retval);
+
+ if (newp != NULL) {
+ errno = EPERM;
+ return (-1);
+ }
+ if (namelen != 2) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ switch (name[1]) {
+ case USER_CS_PATH:
+ if (oldp && orig_oldlen < sizeof(_PATH_STDPATH)) {
+ errno = ENOMEM;
+ return -1;
+ }
+ *oldlenp = sizeof(_PATH_STDPATH);
+ if (oldp != NULL)
+ memmove(oldp, _PATH_STDPATH, sizeof(_PATH_STDPATH));
+ return (0);
+ }
+
+ if (oldp && *oldlenp < sizeof(int)) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ *oldlenp = sizeof(int);
+ if (oldp == NULL)
+ return (0);
+
+ switch (name[1]) {
+ case USER_BC_BASE_MAX:
+ *(int *)oldp = BC_BASE_MAX;
+ return (0);
+ case USER_BC_DIM_MAX:
+ *(int *)oldp = BC_DIM_MAX;
+ return (0);
+ case USER_BC_SCALE_MAX:
+ *(int *)oldp = BC_SCALE_MAX;
+ return (0);
+ case USER_BC_STRING_MAX:
+ *(int *)oldp = BC_STRING_MAX;
+ return (0);
+ case USER_COLL_WEIGHTS_MAX:
+ *(int *)oldp = COLL_WEIGHTS_MAX;
+ return (0);
+ case USER_EXPR_NEST_MAX:
+ *(int *)oldp = EXPR_NEST_MAX;
+ return (0);
+ case USER_LINE_MAX:
+ *(int *)oldp = LINE_MAX;
+ return (0);
+ case USER_RE_DUP_MAX:
+ *(int *)oldp = RE_DUP_MAX;
+ return (0);
+ case USER_POSIX2_VERSION:
+ *(int *)oldp = _POSIX2_VERSION;
+ return (0);
+ case USER_POSIX2_C_BIND:
+#ifdef POSIX2_C_BIND
+ *(int *)oldp = 1;
+#else
+ *(int *)oldp = 0;
+#endif
+ return (0);
+ case USER_POSIX2_C_DEV:
+#ifdef POSIX2_C_DEV
+ *(int *)oldp = 1;
+#else
+ *(int *)oldp = 0;
+#endif
+ return (0);
+ case USER_POSIX2_CHAR_TERM:
+#ifdef POSIX2_CHAR_TERM
+ *(int *)oldp = 1;
+#else
+ *(int *)oldp = 0;
+#endif
+ return (0);
+ case USER_POSIX2_FORT_DEV:
+#ifdef POSIX2_FORT_DEV
+ *(int *)oldp = 1;
+#else
+ *(int *)oldp = 0;
+#endif
+ return (0);
+ case USER_POSIX2_FORT_RUN:
+#ifdef POSIX2_FORT_RUN
+ *(int *)oldp = 1;
+#else
+ *(int *)oldp = 0;
+#endif
+ return (0);
+ case USER_POSIX2_LOCALEDEF:
+#ifdef POSIX2_LOCALEDEF
+ *(int *)oldp = 1;
+#else
+ *(int *)oldp = 0;
+#endif
+ return (0);
+ case USER_POSIX2_SW_DEV:
+#ifdef POSIX2_SW_DEV
+ *(int *)oldp = 1;
+#else
+ *(int *)oldp = 0;
+#endif
+ return (0);
+ case USER_POSIX2_UPE:
+#ifdef POSIX2_UPE
+ *(int *)oldp = 1;
+#else
+ *(int *)oldp = 0;
+#endif
+ return (0);
+ case USER_STREAM_MAX:
+ *(int *)oldp = FOPEN_MAX;
+ return (0);
+ case USER_TZNAME_MAX:
+ *(int *)oldp = NAME_MAX;
+ return (0);
+ default:
+ errno = EINVAL;
+ return (-1);
+ }
+ /* NOTREACHED */
+}
diff --git a/lib/libc/gen/sysctlbyname.c b/lib/libc/gen/sysctlbyname.c
new file mode 100644
index 000000000000..88b860d3e794
--- /dev/null
+++ b/lib/libc/gen/sysctlbyname.c
@@ -0,0 +1,28 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@FreeBSD.org> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+ * ----------------------------------------------------------------------------
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/sysctl.h>
+
+int
+sysctlbyname(const char *name, void *oldp, size_t *oldlenp,
+ const void *newp, size_t newlen)
+{
+ int real_oid[CTL_MAXNAME+2];
+ size_t oidlen;
+
+ oidlen = sizeof(real_oid) / sizeof(int);
+ if (sysctlnametomib(name, real_oid, &oidlen) < 0)
+ return (-1);
+ return (sysctl(real_oid, oidlen, oldp, oldlenp, newp, newlen));
+}
diff --git a/lib/libc/gen/sysctlnametomib.c b/lib/libc/gen/sysctlnametomib.c
new file mode 100644
index 000000000000..afca95dc3a6c
--- /dev/null
+++ b/lib/libc/gen/sysctlnametomib.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2001 The FreeBSD Project. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE FREEBSD PROJECT ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE FREEBSD PROJECT BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <string.h>
+
+/*
+ * This function uses a presently undocumented interface to the kernel
+ * to walk the tree and get the type so it can print the value.
+ * This interface is under work and consideration, and should probably
+ * be killed with a big axe by the first person who can find the time.
+ * (be aware though, that the proper interface isn't as obvious as it
+ * may seem, there are various conflicting requirements.
+ */
+int
+sysctlnametomib(const char *name, int *mibp, size_t *sizep)
+{
+ int oid[2];
+ int error;
+
+ oid[0] = 0;
+ oid[1] = 3;
+
+ *sizep *= sizeof(int);
+ error = sysctl(oid, 2, mibp, sizep, name, strlen(name));
+ *sizep /= sizeof(int);
+ return (error);
+}
diff --git a/lib/libc/gen/syslog.3 b/lib/libc/gen/syslog.3
new file mode 100644
index 000000000000..b513adcd6343
--- /dev/null
+++ b/lib/libc/gen/syslog.3
@@ -0,0 +1,295 @@
+.\" Copyright (c) 1985, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)syslog.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd July 21, 2015
+.Dt SYSLOG 3
+.Os
+.Sh NAME
+.Nm syslog ,
+.Nm vsyslog ,
+.Nm openlog ,
+.Nm closelog ,
+.Nm setlogmask
+.Nd control system log
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In syslog.h
+.In stdarg.h
+.Ft void
+.Fn syslog "int priority" "const char *message" "..."
+.Ft void
+.Fn vsyslog "int priority" "const char *message" "va_list args"
+.Ft void
+.Fn openlog "const char *ident" "int logopt" "int facility"
+.Ft void
+.Fn closelog void
+.Ft int
+.Fn setlogmask "int maskpri"
+.Sh DESCRIPTION
+The
+.Fn syslog
+function
+writes
+.Fa message
+to the system message logger.
+The message is then written to the system console, log files,
+logged-in users, or forwarded to other machines as appropriate.
+(See
+.Xr syslogd 8 . )
+.Pp
+The message is identical to a
+.Xr printf 3
+format string, except that
+.Ql %m
+is replaced by the current error
+message.
+(As denoted by the global variable
+.Va errno ;
+see
+.Xr strerror 3 . )
+A trailing newline is added if none is present.
+.Pp
+The
+.Fn vsyslog
+function
+is an alternate form in which the arguments have already been captured
+using the variable-length argument facilities of
+.Xr stdarg 3 .
+.Pp
+The message is tagged with
+.Fa priority .
+Priorities are encoded as a
+.Fa facility
+and a
+.Em level .
+The facility describes the part of the system
+generating the message.
+The level is selected from the following
+.Em ordered
+(high to low) list:
+.Bl -tag -width LOG_AUTHPRIV
+.It Dv LOG_EMERG
+A panic condition.
+This is normally broadcast to all users.
+.It Dv LOG_ALERT
+A condition that should be corrected immediately, such as a corrupted
+system database.
+.It Dv LOG_CRIT
+Critical conditions, e.g., hard device errors.
+.It Dv LOG_ERR
+Errors.
+.It Dv LOG_WARNING
+Warning messages.
+.It Dv LOG_NOTICE
+Conditions that are not error conditions,
+but should possibly be handled specially.
+.It Dv LOG_INFO
+Informational messages.
+.It Dv LOG_DEBUG
+Messages that contain information
+normally of use only when debugging a program.
+.El
+.Pp
+The
+.Fn openlog
+function
+provides for more specialized processing of the messages sent
+by
+.Fn syslog
+and
+.Fn vsyslog .
+The
+.Fa ident
+argument
+is a string that will be prepended to every message.
+The
+.Fa logopt
+argument
+is a bit field specifying logging options, which is formed by
+.Tn OR Ns 'ing
+one or more of the following values:
+.Bl -tag -width LOG_AUTHPRIV
+.It Dv LOG_CONS
+If
+.Fn syslog
+cannot pass the message to
+.Xr syslogd 8
+it will attempt to write the message to the console
+.Pq Dq Pa /dev/console .
+.It Dv LOG_NDELAY
+Open the connection to
+.Xr syslogd 8
+immediately.
+Normally the open is delayed until the first message is logged.
+Useful for programs that need to manage the order in which file
+descriptors are allocated.
+.It Dv LOG_PERROR
+Write the message to standard error output as well to the system log.
+.It Dv LOG_PID
+Log the process id with each message: useful for identifying
+instantiations of daemons.
+.El
+.Pp
+The
+.Fa facility
+argument encodes a default facility to be assigned to all messages
+that do not have an explicit facility encoded:
+.Bl -tag -width LOG_AUTHPRIV
+.It Dv LOG_AUTH
+The authorization system:
+.Xr login 1 ,
+.Xr su 1 ,
+.Xr getty 8 ,
+etc.
+.It Dv LOG_AUTHPRIV
+The same as
+.Dv LOG_AUTH ,
+but logged to a file readable only by
+selected individuals.
+.It Dv LOG_CONSOLE
+Messages written to
+.Pa /dev/console
+by the kernel console output driver.
+.It Dv LOG_CRON
+The cron daemon:
+.Xr cron 8 .
+.It Dv LOG_DAEMON
+System daemons, such as
+.Xr routed 8 ,
+that are not provided for explicitly by other facilities.
+.It Dv LOG_FTP
+The file transfer protocol daemons:
+.Xr ftpd 8 ,
+.Xr tftpd 8 .
+.It Dv LOG_KERN
+Messages generated by the kernel.
+These cannot be generated by any user processes.
+.It Dv LOG_LPR
+The line printer spooling system:
+.Xr lpr 1 ,
+.Xr lpc 8 ,
+.Xr lpd 8 ,
+etc.
+.It Dv LOG_MAIL
+The mail system.
+.It Dv LOG_NEWS
+The network news system.
+.It Dv LOG_NTP
+The network time protocol system.
+.It Dv LOG_SECURITY
+Security subsystems, such as
+.Xr ipfw 4 .
+.It Dv LOG_SYSLOG
+Messages generated internally by
+.Xr syslogd 8 .
+.It Dv LOG_USER
+Messages generated by random user processes.
+This is the default facility identifier if none is specified.
+.It Dv LOG_UUCP
+The uucp system.
+.It Dv LOG_LOCAL0
+Reserved for local use.
+Similarly for
+.Dv LOG_LOCAL1
+through
+.Dv LOG_LOCAL7 .
+.El
+.Pp
+The
+.Fn closelog
+function
+can be used to close the log file.
+.Pp
+The
+.Fn setlogmask
+function
+sets the log priority mask to
+.Fa maskpri
+and returns the previous mask.
+Calls to
+.Fn syslog
+with a priority not set in
+.Fa maskpri
+are rejected.
+The mask for an individual priority
+.Fa pri
+is calculated by the macro
+.Fn LOG_MASK pri ;
+the mask for all priorities up to and including
+.Fa toppri
+is given by the macro
+.Fn LOG_UPTO toppri ; .
+The default allows all priorities to be logged.
+.Sh RETURN VALUES
+The routines
+.Fn closelog ,
+.Fn openlog ,
+.Fn syslog
+and
+.Fn vsyslog
+return no value.
+.Pp
+The routine
+.Fn setlogmask
+always returns the previous log mask level.
+.Sh EXAMPLES
+.Bd -literal -offset indent -compact
+syslog(LOG_ALERT, "who: internal error 23");
+
+openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_FTP);
+
+setlogmask(LOG_UPTO(LOG_ERR));
+
+syslog(LOG_INFO, "Connection from host %d", CallingHost);
+
+syslog(LOG_INFO|LOG_LOCAL2, "foobar error: %m");
+.Ed
+.Sh SEE ALSO
+.Xr logger 1 ,
+.Xr syslogd 8
+.Sh HISTORY
+These
+functions appeared in
+.Bx 4.2 .
+.Sh BUGS
+Never pass a string with user-supplied data as a format without using
+.Ql %s .
+An attacker can put format specifiers in the string to mangle your stack,
+leading to a possible security hole.
+This holds true even if the string was built using a function like
+.Fn snprintf ,
+as the resulting string may still contain user-supplied conversion specifiers
+for later interpolation by
+.Fn syslog .
+.Pp
+Always use the proper secure idiom:
+.Pp
+.Dl syslog(priority, "%s", string);
diff --git a/lib/libc/gen/syslog.c b/lib/libc/gen/syslog.c
new file mode 100644
index 000000000000..003f24ddcaf6
--- /dev/null
+++ b/lib/libc/gen/syslog.c
@@ -0,0 +1,457 @@
+/*
+ * Copyright (c) 1983, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)syslog.c 8.5 (Berkeley) 4/29/95";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/syslog.h>
+#include <sys/uio.h>
+#include <sys/un.h>
+#include <netdb.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <stdarg.h>
+#include "un-namespace.h"
+
+#include "libc_private.h"
+
+static int LogFile = -1; /* fd for log */
+static int status; /* connection status */
+static int opened; /* have done openlog() */
+static int LogStat = 0; /* status bits, set by openlog() */
+static const char *LogTag = NULL; /* string to tag the entry with */
+static int LogFacility = LOG_USER; /* default facility code */
+static int LogMask = 0xff; /* mask of priorities to be logged */
+static pthread_mutex_t syslog_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+#define THREAD_LOCK() \
+ do { \
+ if (__isthreaded) _pthread_mutex_lock(&syslog_mutex); \
+ } while(0)
+#define THREAD_UNLOCK() \
+ do { \
+ if (__isthreaded) _pthread_mutex_unlock(&syslog_mutex); \
+ } while(0)
+
+static void disconnectlog(void); /* disconnect from syslogd */
+static void connectlog(void); /* (re)connect to syslogd */
+static void openlog_unlocked(const char *, int, int);
+
+enum {
+ NOCONN = 0,
+ CONNDEF,
+ CONNPRIV,
+};
+
+/*
+ * Format of the magic cookie passed through the stdio hook
+ */
+struct bufcookie {
+ char *base; /* start of buffer */
+ int left;
+};
+
+/*
+ * stdio write hook for writing to a static string buffer
+ * XXX: Maybe one day, dynamically allocate it so that the line length
+ * is `unlimited'.
+ */
+static int
+writehook(void *cookie, const char *buf, int len)
+{
+ struct bufcookie *h; /* private `handle' */
+
+ h = (struct bufcookie *)cookie;
+ if (len > h->left) {
+ /* clip in case of wraparound */
+ len = h->left;
+ }
+ if (len > 0) {
+ (void)memcpy(h->base, buf, len); /* `write' it. */
+ h->base += len;
+ h->left -= len;
+ }
+ return len;
+}
+
+/*
+ * syslog, vsyslog --
+ * print message on log file; output is intended for syslogd(8).
+ */
+void
+syslog(int pri, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vsyslog(pri, fmt, ap);
+ va_end(ap);
+}
+
+void
+vsyslog(int pri, const char *fmt, va_list ap)
+{
+ int cnt;
+ char ch, *p;
+ time_t now;
+ int fd, saved_errno;
+ char *stdp, tbuf[2048], fmt_cpy[1024], timbuf[26], errstr[64];
+ FILE *fp, *fmt_fp;
+ struct bufcookie tbuf_cookie;
+ struct bufcookie fmt_cookie;
+
+#define INTERNALLOG LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID
+ /* Check for invalid bits. */
+ if (pri & ~(LOG_PRIMASK|LOG_FACMASK)) {
+ syslog(INTERNALLOG,
+ "syslog: unknown facility/priority: %x", pri);
+ pri &= LOG_PRIMASK|LOG_FACMASK;
+ }
+
+ saved_errno = errno;
+
+ THREAD_LOCK();
+
+ /* Check priority against setlogmask values. */
+ if (!(LOG_MASK(LOG_PRI(pri)) & LogMask)) {
+ THREAD_UNLOCK();
+ return;
+ }
+
+ /* Set default facility if none specified. */
+ if ((pri & LOG_FACMASK) == 0)
+ pri |= LogFacility;
+
+ /* Create the primary stdio hook */
+ tbuf_cookie.base = tbuf;
+ tbuf_cookie.left = sizeof(tbuf);
+ fp = fwopen(&tbuf_cookie, writehook);
+ if (fp == NULL) {
+ THREAD_UNLOCK();
+ return;
+ }
+
+ /* Build the message. */
+ (void)time(&now);
+ (void)fprintf(fp, "<%d>", pri);
+ (void)fprintf(fp, "%.15s ", ctime_r(&now, timbuf) + 4);
+ if (LogStat & LOG_PERROR) {
+ /* Transfer to string buffer */
+ (void)fflush(fp);
+ stdp = tbuf + (sizeof(tbuf) - tbuf_cookie.left);
+ }
+ if (LogTag == NULL)
+ LogTag = _getprogname();
+ if (LogTag != NULL)
+ (void)fprintf(fp, "%s", LogTag);
+ if (LogStat & LOG_PID)
+ (void)fprintf(fp, "[%d]", getpid());
+ if (LogTag != NULL) {
+ (void)fprintf(fp, ": ");
+ }
+
+ /* Check to see if we can skip expanding the %m */
+ if (strstr(fmt, "%m")) {
+
+ /* Create the second stdio hook */
+ fmt_cookie.base = fmt_cpy;
+ fmt_cookie.left = sizeof(fmt_cpy) - 1;
+ fmt_fp = fwopen(&fmt_cookie, writehook);
+ if (fmt_fp == NULL) {
+ fclose(fp);
+ THREAD_UNLOCK();
+ return;
+ }
+
+ /*
+ * Substitute error message for %m. Be careful not to
+ * molest an escaped percent "%%m". We want to pass it
+ * on untouched as the format is later parsed by vfprintf.
+ */
+ for ( ; (ch = *fmt); ++fmt) {
+ if (ch == '%' && fmt[1] == 'm') {
+ ++fmt;
+ strerror_r(saved_errno, errstr, sizeof(errstr));
+ fputs(errstr, fmt_fp);
+ } else if (ch == '%' && fmt[1] == '%') {
+ ++fmt;
+ fputc(ch, fmt_fp);
+ fputc(ch, fmt_fp);
+ } else {
+ fputc(ch, fmt_fp);
+ }
+ }
+
+ /* Null terminate if room */
+ fputc(0, fmt_fp);
+ fclose(fmt_fp);
+
+ /* Guarantee null termination */
+ fmt_cpy[sizeof(fmt_cpy) - 1] = '\0';
+
+ fmt = fmt_cpy;
+ }
+
+ (void)vfprintf(fp, fmt, ap);
+ (void)fclose(fp);
+
+ cnt = sizeof(tbuf) - tbuf_cookie.left;
+
+ /* Remove a trailing newline */
+ if (tbuf[cnt - 1] == '\n')
+ cnt--;
+
+ /* Output to stderr if requested. */
+ if (LogStat & LOG_PERROR) {
+ struct iovec iov[2];
+ struct iovec *v = iov;
+
+ v->iov_base = stdp;
+ v->iov_len = cnt - (stdp - tbuf);
+ ++v;
+ v->iov_base = "\n";
+ v->iov_len = 1;
+ (void)_writev(STDERR_FILENO, iov, 2);
+ }
+
+ /* Get connected, output the message to the local logger. */
+ if (!opened)
+ openlog_unlocked(LogTag, LogStat | LOG_NDELAY, 0);
+ connectlog();
+
+ /*
+ * If the send() fails, there are two likely scenarios:
+ * 1) syslogd was restarted
+ * 2) /var/run/log is out of socket buffer space, which
+ * in most cases means local DoS.
+ * If the error does not indicate a full buffer, we address
+ * case #1 by attempting to reconnect to /var/run/log[priv]
+ * and resending the message once.
+ *
+ * If we are working with a privileged socket, the retry
+ * attempts end there, because we don't want to freeze a
+ * critical application like su(1) or sshd(8).
+ *
+ * Otherwise, we address case #2 by repeatedly retrying the
+ * send() to give syslogd a chance to empty its socket buffer.
+ */
+
+ if (send(LogFile, tbuf, cnt, 0) < 0) {
+ if (errno != ENOBUFS) {
+ /*
+ * Scenario 1: syslogd was restarted
+ * reconnect and resend once
+ */
+ disconnectlog();
+ connectlog();
+ if (send(LogFile, tbuf, cnt, 0) >= 0) {
+ THREAD_UNLOCK();
+ return;
+ }
+ /*
+ * if the resend failed, fall through to
+ * possible scenario 2
+ */
+ }
+ while (errno == ENOBUFS) {
+ /*
+ * Scenario 2: out of socket buffer space
+ * possible DoS, fail fast on a privileged
+ * socket
+ */
+ if (status == CONNPRIV)
+ break;
+ _usleep(1);
+ if (send(LogFile, tbuf, cnt, 0) >= 0) {
+ THREAD_UNLOCK();
+ return;
+ }
+ }
+ } else {
+ THREAD_UNLOCK();
+ return;
+ }
+
+ /*
+ * Output the message to the console; try not to block
+ * as a blocking console should not stop other processes.
+ * Make sure the error reported is the one from the syslogd failure.
+ */
+ if (LogStat & LOG_CONS &&
+ (fd = _open(_PATH_CONSOLE, O_WRONLY|O_NONBLOCK|O_CLOEXEC, 0)) >=
+ 0) {
+ struct iovec iov[2];
+ struct iovec *v = iov;
+
+ p = strchr(tbuf, '>') + 1;
+ v->iov_base = p;
+ v->iov_len = cnt - (p - tbuf);
+ ++v;
+ v->iov_base = "\r\n";
+ v->iov_len = 2;
+ (void)_writev(fd, iov, 2);
+ (void)_close(fd);
+ }
+
+ THREAD_UNLOCK();
+}
+
+/* Should be called with mutex acquired */
+static void
+disconnectlog(void)
+{
+ /*
+ * If the user closed the FD and opened another in the same slot,
+ * that's their problem. They should close it before calling on
+ * system services.
+ */
+ if (LogFile != -1) {
+ _close(LogFile);
+ LogFile = -1;
+ }
+ status = NOCONN; /* retry connect */
+}
+
+/* Should be called with mutex acquired */
+static void
+connectlog(void)
+{
+ struct sockaddr_un SyslogAddr; /* AF_UNIX address of local logger */
+
+ if (LogFile == -1) {
+ if ((LogFile = _socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC,
+ 0)) == -1)
+ return;
+ }
+ if (LogFile != -1 && status == NOCONN) {
+ SyslogAddr.sun_len = sizeof(SyslogAddr);
+ SyslogAddr.sun_family = AF_UNIX;
+
+ /*
+ * First try privileged socket. If no success,
+ * then try default socket.
+ */
+ (void)strncpy(SyslogAddr.sun_path, _PATH_LOG_PRIV,
+ sizeof SyslogAddr.sun_path);
+ if (_connect(LogFile, (struct sockaddr *)&SyslogAddr,
+ sizeof(SyslogAddr)) != -1)
+ status = CONNPRIV;
+
+ if (status == NOCONN) {
+ (void)strncpy(SyslogAddr.sun_path, _PATH_LOG,
+ sizeof SyslogAddr.sun_path);
+ if (_connect(LogFile, (struct sockaddr *)&SyslogAddr,
+ sizeof(SyslogAddr)) != -1)
+ status = CONNDEF;
+ }
+
+ if (status == NOCONN) {
+ /*
+ * Try the old "/dev/log" path, for backward
+ * compatibility.
+ */
+ (void)strncpy(SyslogAddr.sun_path, _PATH_OLDLOG,
+ sizeof SyslogAddr.sun_path);
+ if (_connect(LogFile, (struct sockaddr *)&SyslogAddr,
+ sizeof(SyslogAddr)) != -1)
+ status = CONNDEF;
+ }
+
+ if (status == NOCONN) {
+ (void)_close(LogFile);
+ LogFile = -1;
+ }
+ }
+}
+
+static void
+openlog_unlocked(const char *ident, int logstat, int logfac)
+{
+ if (ident != NULL)
+ LogTag = ident;
+ LogStat = logstat;
+ if (logfac != 0 && (logfac &~ LOG_FACMASK) == 0)
+ LogFacility = logfac;
+
+ if (LogStat & LOG_NDELAY) /* open immediately */
+ connectlog();
+
+ opened = 1; /* ident and facility has been set */
+}
+
+void
+openlog(const char *ident, int logstat, int logfac)
+{
+ THREAD_LOCK();
+ openlog_unlocked(ident, logstat, logfac);
+ THREAD_UNLOCK();
+}
+
+
+void
+closelog(void)
+{
+ THREAD_LOCK();
+ if (LogFile != -1) {
+ (void)_close(LogFile);
+ LogFile = -1;
+ }
+ LogTag = NULL;
+ status = NOCONN;
+ THREAD_UNLOCK();
+}
+
+/* setlogmask -- set the log mask level */
+int
+setlogmask(int pmask)
+{
+ int omask;
+
+ THREAD_LOCK();
+ omask = LogMask;
+ if (pmask != 0)
+ LogMask = pmask;
+ THREAD_UNLOCK();
+ return (omask);
+}
diff --git a/lib/libc/gen/tcgetpgrp.3 b/lib/libc/gen/tcgetpgrp.3
new file mode 100644
index 000000000000..ba4d08432dd0
--- /dev/null
+++ b/lib/libc/gen/tcgetpgrp.3
@@ -0,0 +1,78 @@
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)tcgetpgrp.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt TCGETPGRP 3
+.Os
+.Sh NAME
+.Nm tcgetpgrp
+.Nd get foreground process group ID
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In unistd.h
+.Ft pid_t
+.Fn tcgetpgrp "int fd"
+.Sh DESCRIPTION
+The
+.Fn tcgetpgrp
+function returns the value of the process group ID of the foreground
+process group associated with the terminal device.
+If there is no foreground process group,
+.Fn tcgetpgrp
+returns an invalid process ID.
+.Sh ERRORS
+If an error occurs,
+.Fn tcgetpgrp
+returns -1 and the global variable
+.Va errno
+is set to indicate the error, as follows:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa fd
+argument is not a valid file descriptor.
+.It Bq Er ENOTTY
+The calling process does not have a controlling terminal or the
+underlying terminal device represented by
+.Fa fd
+is not the controlling terminal.
+.El
+.Sh SEE ALSO
+.Xr setpgid 2 ,
+.Xr setsid 2 ,
+.Xr tcsetpgrp 3
+.Sh STANDARDS
+The
+.Fn tcgetpgrp
+function is expected to be compliant with the
+.St -p1003.1-88
+specification.
diff --git a/lib/libc/gen/tcgetsid.3 b/lib/libc/gen/tcgetsid.3
new file mode 100644
index 000000000000..60bff8d0b98a
--- /dev/null
+++ b/lib/libc/gen/tcgetsid.3
@@ -0,0 +1,72 @@
+.\" Copyright (c) 2008 David Xu <davidxu@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 April 15, 2008
+.Dt TCGETSID 3
+.Os
+.Sh NAME
+.Nm tcgetsid
+.Nd get session ID associated with a controlling terminal
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In termios.h
+.Ft pid_t
+.Fn tcgetsid "int fd"
+.Sh DESCRIPTION
+The
+.Fn tcgetsid
+function returns the process group ID of the session leader for a
+controlling terminal specified by
+.Fa fd .
+.Sh ERRORS
+If an error occurs,
+.Fn tcgetsid
+returns -1 and the global variable
+.Va errno
+is set to indicate the error, as follows:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa fd
+argument is not a valid file descriptor.
+.It Bq Er ENOTTY
+The calling process does not have a controlling terminal or the
+underlying terminal device represented by
+.Fa fd
+is not the controlling terminal.
+.El
+.Sh SEE ALSO
+.Xr getsid 2 ,
+.Xr setsid 2 ,
+.Xr tcgetpgrp 3 ,
+.Xr tcsetsid 3
+.Sh STANDARDS
+The
+.Fn tcgetsid
+function conforms to
+.St -xpg4.2 .
diff --git a/lib/libc/gen/tcsendbreak.3 b/lib/libc/gen/tcsendbreak.3
new file mode 100644
index 000000000000..dd43a298941e
--- /dev/null
+++ b/lib/libc/gen/tcsendbreak.3
@@ -0,0 +1,180 @@
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)tcsendbreak.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd January 11, 2017
+.Dt TCSENDBREAK 3
+.Os
+.Sh NAME
+.Nm tcsendbreak ,
+.Nm tcdrain ,
+.Nm tcflush ,
+.Nm tcflow
+.Nd line control functions
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In termios.h
+.Ft int
+.Fn tcdrain "int fd"
+.Ft int
+.Fn tcflow "int fd" "int action"
+.Ft int
+.Fn tcflush "int fd" "int action"
+.Ft int
+.Fn tcsendbreak "int fd" "int len"
+.Sh DESCRIPTION
+The
+.Fn tcdrain
+function waits until all output written to the terminal referenced by
+.Fa fd
+has been transmitted to the terminal.
+.Pp
+The
+.Fn tcflow
+function suspends transmission of data to or the reception of data from
+the terminal referenced by
+.Fa fd
+depending on the value of
+.Fa action .
+The value of
+.Fa action
+must be one of the following:
+.Bl -tag -width "TCIOFF"
+.It Fa TCOOFF
+Suspend output.
+.It Fa TCOON
+Restart suspended output.
+.It Fa TCIOFF
+Transmit a STOP character, which is intended to cause the terminal to stop
+transmitting data to the system.
+(See the description of IXOFF in the
+.Ql Input Modes
+section of
+.Xr termios 4 ) .
+.It Fa TCION
+Transmit a START character, which is intended to cause the terminal to start
+transmitting data to the system.
+(See the description of IXOFF in the
+.Ql Input Modes
+section of
+.Xr termios 4 ) .
+.El
+.Pp
+The
+.Fn tcflush
+function discards any data written to the terminal referenced by
+.Fa fd
+which has not been transmitted to the terminal, or any data received
+from the terminal but not yet read, depending on the value of
+.Fa action .
+The value of
+.Fa action
+must be one of the following:
+.Bl -tag -width "TCIOFLUSH"
+.It Fa TCIFLUSH
+Flush data received but not read.
+.It Fa TCOFLUSH
+Flush data written but not transmitted.
+.It Fa TCIOFLUSH
+Flush both data received but not read and data written but not transmitted.
+.El
+.Pp
+The
+.Fn tcsendbreak
+function transmits a continuous stream of zero-valued bits for four-tenths
+of a second to the terminal referenced by
+.Fa fd .
+The
+.Fa len
+argument is ignored in this implementation.
+.Sh RETURN VALUES
+Upon successful completion, all of these functions return a value of zero.
+.Sh ERRORS
+If any error occurs, a value of -1 is returned and the global variable
+.Va errno
+is set to indicate the error, as follows:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa fd
+argument is not a valid file descriptor.
+.It Bq Er EINVAL
+The
+.Fa action
+argument is not a proper value.
+.It Bq Er ENOTTY
+The file associated with
+.Fa fd
+is not a terminal.
+.It Bq Er EINTR
+A signal interrupted the
+.Fn tcdrain
+function.
+.It Bq Er EWOULDBLOCK
+The configured timeout expired before the
+.Fn tcdrain
+function could write all buffered output.
+.El
+.Sh SEE ALSO
+.Xr tcsetattr 3 ,
+.Xr termios 4 ,
+.Xr tty 4 ,
+.Xr comcontrol 8
+.Sh STANDARDS
+The
+.Fn tcsendbreak ,
+.Fn tcflush
+and
+.Fn tcflow
+functions are expected to be compliant with the
+.St -p1003.1-88
+specification.
+.Pp
+The
+.Fn tcdrain
+function is expected to be compliant with
+.St -p1003.1-88
+when the drain wait value is set to zero with
+.Xr comcontrol 8 ,
+or with
+.Xr ioctl 2
+.Va TIOCSDRAINWAIT ,
+or with
+.Xr sysctl 8
+.Va kern.tty_drainwait .
+A non-zero drain wait value can result in
+.Fn tcdrain
+returning
+.Va EWOULDBLOCK
+without writing all output.
+The default value for
+.Va kern.tty_drainwait
+is 300 seconds.
+
diff --git a/lib/libc/gen/tcsetattr.3 b/lib/libc/gen/tcsetattr.3
new file mode 100644
index 000000000000..9be012eda8b8
--- /dev/null
+++ b/lib/libc/gen/tcsetattr.3
@@ -0,0 +1,340 @@
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)tcsetattr.3 8.3 (Berkeley) 1/2/94
+.\" $FreeBSD$
+.\"
+.Dd January 2, 1994
+.Dt TCSETATTR 3
+.Os
+.Sh NAME
+.Nm cfgetispeed ,
+.Nm cfsetispeed ,
+.Nm cfgetospeed ,
+.Nm cfsetospeed ,
+.Nm cfsetspeed ,
+.Nm cfmakeraw ,
+.Nm cfmakesane ,
+.Nm tcgetattr ,
+.Nm tcsetattr
+.Nd manipulating the termios structure
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In termios.h
+.Ft speed_t
+.Fn cfgetispeed "const struct termios *t"
+.Ft int
+.Fn cfsetispeed "struct termios *t" "speed_t speed"
+.Ft speed_t
+.Fn cfgetospeed "const struct termios *t"
+.Ft int
+.Fn cfsetospeed "struct termios *t" "speed_t speed"
+.Ft int
+.Fn cfsetspeed "struct termios *t" "speed_t speed"
+.Ft void
+.Fn cfmakeraw "struct termios *t"
+.Ft void
+.Fn cfmakesane "struct termios *t"
+.Ft int
+.Fn tcgetattr "int fd" "struct termios *t"
+.Ft int
+.Fn tcsetattr "int fd" "int action" "const struct termios *t"
+.Sh DESCRIPTION
+The
+.Fn cfmakeraw ,
+.Fn cfmakesane ,
+.Fn tcgetattr
+and
+.Fn tcsetattr
+functions are provided for getting and setting the termios structure.
+.Pp
+The
+.Fn cfgetispeed ,
+.Fn cfsetispeed ,
+.Fn cfgetospeed ,
+.Fn cfsetospeed
+and
+.Fn cfsetspeed
+functions are provided for getting and setting the baud rate values in
+the termios structure.
+The effects of the functions on the terminal as described below
+do not become effective, nor are all errors detected, until the
+.Fn tcsetattr
+function is called.
+Certain values for baud rates set in the termios structure and passed to
+.Fn tcsetattr
+have special meanings.
+These are discussed in the portion of the manual page that describes the
+.Fn tcsetattr
+function.
+.Sh GETTING AND SETTING THE BAUD RATE
+The input and output baud rates are found in the termios structure.
+The unsigned integer
+.Li speed_t
+is typedef'd in the include file
+.In termios.h .
+The value of the integer corresponds directly to the baud rate being
+represented, however, the following symbolic values are defined.
+.Bd -literal
+#define B0 0
+#define B50 50
+#define B75 75
+#define B110 110
+#define B134 134
+#define B150 150
+#define B200 200
+#define B300 300
+#define B600 600
+#define B1200 1200
+#define B1800 1800
+#define B2400 2400
+#define B4800 4800
+#define B9600 9600
+#define B19200 19200
+#define B38400 38400
+#ifndef _POSIX_SOURCE
+#define EXTA 19200
+#define EXTB 38400
+#endif /*_POSIX_SOURCE */
+.Ed
+.Pp
+The
+.Fn cfgetispeed
+function returns the input baud rate in the termios structure referenced by
+.Fa tp .
+.Pp
+The
+.Fn cfsetispeed
+function sets the input baud rate in the termios structure referenced by
+.Fa tp
+to
+.Fa speed .
+.Pp
+The
+.Fn cfgetospeed
+function returns the output baud rate in the termios structure referenced by
+.Fa tp .
+.Pp
+The
+.Fn cfsetospeed
+function sets the output baud rate in the termios structure referenced by
+.Fa tp
+to
+.Fa speed .
+.Pp
+The
+.Fn cfsetspeed
+function sets both the input and output baud rate in the termios structure
+referenced by
+.Fa tp
+to
+.Fa speed .
+.Pp
+Upon successful completion, the functions
+.Fn cfsetispeed ,
+.Fn cfsetospeed ,
+and
+.Fn cfsetspeed
+return a value of 0.
+Otherwise, a value of -1 is returned and the global variable
+.Va errno
+is set to indicate the error.
+.Sh GETTING AND SETTING THE TERMIOS STATE
+This section describes the functions that are used to control the general
+terminal interface.
+Unless otherwise noted for a specific command, these functions are restricted
+from use by background processes.
+Attempts to perform these operations shall cause the process group to be sent
+a SIGTTOU signal.
+If the calling process is blocking or ignoring SIGTTOU signals, the process
+is allowed to perform the operation and the SIGTTOU signal is not sent.
+.Pp
+In all the functions, although
+.Fa fd
+is an open file descriptor, the functions affect the underlying terminal
+file, not just the open file description associated with the particular
+file descriptor.
+.Pp
+The
+.Fn cfmakeraw
+function sets the flags stored in the termios structure to a state disabling
+all input and output processing, giving a
+.Dq raw I/O path ,
+while the
+.Fn cfmakesane
+function sets them to a state similar to those of a newly created
+terminal device.
+It should be noted that there is no function to reverse this effect.
+This is because there are a variety of processing options that could be
+re-enabled and the correct method is for an application to snapshot the
+current terminal state using the function
+.Fn tcgetattr ,
+setting raw or sane mode with
+.Fn cfmakeraw
+or
+.Fn cfmakesane
+and the subsequent
+.Fn tcsetattr ,
+and then using another
+.Fn tcsetattr
+with the saved state to revert to the previous terminal state.
+.Pp
+The
+.Fn tcgetattr
+function copies the parameters associated with the terminal referenced
+by
+.Fa fd
+in the termios structure referenced by
+.Fa tp .
+This function is allowed from a background process, however, the terminal
+attributes may be subsequently changed by a foreground process.
+.Pp
+The
+.Fn tcsetattr
+function sets the parameters associated with the terminal from the
+termios structure referenced by
+.Fa tp .
+The
+.Fa action
+argument is created by
+.Em or Ns 'ing
+the following values, as specified in the include file
+.In termios.h .
+.Bl -tag -width "TCSADRAIN"
+.It Fa TCSANOW
+The change occurs immediately.
+.It Fa TCSADRAIN
+The change occurs after all output written to
+.Fa fd
+has been transmitted to the terminal.
+This value of
+.Fa action
+should be used when changing parameters that affect output.
+.It Fa TCSAFLUSH
+The change occurs after all output written to
+.Fa fd
+has been transmitted to the terminal.
+Additionally, any input that has been received but not read is discarded.
+.It Fa TCSASOFT
+If this value is
+.Em or Ns 'ed
+into the
+.Fa action
+value, the values of the
+.Va c_cflag ,
+.Va c_ispeed ,
+and
+.Va c_ospeed
+fields are ignored.
+.El
+.Pp
+The 0 baud rate is used to terminate the connection.
+If 0 is specified as the output speed to the function
+.Fn tcsetattr ,
+modem control will no longer be asserted on the terminal, disconnecting
+the terminal.
+.Pp
+If zero is specified as the input speed to the function
+.Fn tcsetattr ,
+the input baud rate will be set to the same value as that specified by
+the output baud rate.
+.Pp
+If
+.Fn tcsetattr
+is unable to make any of the requested changes, it returns -1 and
+sets errno.
+Otherwise, it makes all of the requested changes it can.
+If the specified input and output baud rates differ and are a combination
+that is not supported, neither baud rate is changed.
+.Pp
+Upon successful completion, the functions
+.Fn tcgetattr
+and
+.Fn tcsetattr
+return a value of 0.
+Otherwise, they
+return -1 and the global variable
+.Va errno
+is set to indicate the error, as follows:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa fd
+argument to
+.Fn tcgetattr
+or
+.Fn tcsetattr
+was not a valid file descriptor.
+.It Bq Er EINTR
+The
+.Fn tcsetattr
+function was interrupted by a signal.
+.It Bq Er EINVAL
+The
+.Fa action
+argument to the
+.Fn tcsetattr
+function was not valid, or an attempt was made to change an attribute
+represented in the termios structure to an unsupported value.
+.It Bq Er ENOTTY
+The file associated with the
+.Fa fd
+argument to
+.Fn tcgetattr
+or
+.Fn tcsetattr
+is not a terminal.
+.El
+.Sh SEE ALSO
+.Xr tcsendbreak 3 ,
+.Xr termios 4
+.Sh STANDARDS
+The
+.Fn cfgetispeed ,
+.Fn cfsetispeed ,
+.Fn cfgetospeed ,
+.Fn cfsetospeed ,
+.Fn tcgetattr
+and
+.Fn tcsetattr
+functions are expected to be compliant with the
+.St -p1003.1-88
+specification.
+The
+.Fn cfmakeraw ,
+.Fn cfmakesane
+and
+.Fn cfsetspeed
+functions,
+as well as the
+.Li TCSASOFT
+option to the
+.Fn tcsetattr
+function are extensions to the
+.St -p1003.1-88
+specification.
diff --git a/lib/libc/gen/tcsetpgrp.3 b/lib/libc/gen/tcsetpgrp.3
new file mode 100644
index 000000000000..494731c4cae5
--- /dev/null
+++ b/lib/libc/gen/tcsetpgrp.3
@@ -0,0 +1,95 @@
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)tcsetpgrp.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt TCSETPGRP 3
+.Os
+.Sh NAME
+.Nm tcsetpgrp
+.Nd set foreground process group ID
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In unistd.h
+.Ft int
+.Fn tcsetpgrp "int fd" "pid_t pgrp_id"
+.Sh DESCRIPTION
+If the process has a controlling terminal, the
+.Fn tcsetpgrp
+function sets the foreground process group ID associated with the
+terminal device to
+.Fa pgrp_id .
+The terminal device associated with
+.Fa fd
+must be the controlling terminal of the calling process and the
+controlling terminal must be currently associated with the session
+of the calling process.
+The value of
+.Fa pgrp_id
+must be the same as the process group ID of a process in the same
+session as the calling process.
+.Sh RETURN VALUES
+.Rv -std tcsetpgrp
+.Sh ERRORS
+The
+.Fn tcsetpgrp
+function will fail if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa fd
+argument is not a valid file descriptor.
+.It Bq Er EINVAL
+An invalid value of
+.Fa pgrp_id
+was specified.
+.It Bq Er ENOTTY
+The calling process does not have a controlling terminal, or the file
+represented by
+.Fa fd
+is not the controlling terminal, or the controlling terminal is no
+longer associated with the session of the calling process.
+.It Bq Er EPERM
+The
+.Fa pgrp_id
+argument does not match the process group ID of a process in the same
+session as the calling process.
+.El
+.Sh SEE ALSO
+.Xr setpgid 2 ,
+.Xr setsid 2 ,
+.Xr tcgetpgrp 3
+.Sh STANDARDS
+The
+.Fn tcsetpgrp
+function is expected to be compliant with the
+.St -p1003.1-88
+specification.
diff --git a/lib/libc/gen/tcsetsid.3 b/lib/libc/gen/tcsetsid.3
new file mode 100644
index 000000000000..d0f1d985753e
--- /dev/null
+++ b/lib/libc/gen/tcsetsid.3
@@ -0,0 +1,92 @@
+.\" Copyright (c) 2009 Ed Schouten <ed@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 May 4, 2009
+.Dt TCSETSID 3
+.Os
+.Sh NAME
+.Nm tcsetsid
+.Nd set session ID associated with a controlling terminal
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In termios.h
+.Ft int
+.Fn tcsetsid "int fd" "pid_t pid"
+.Sh DESCRIPTION
+The
+.Fn tcsetsid
+function sets associates a session identified by
+.Fa pid
+with a controlling terminal specified by
+.Fa fd .
+.Pp
+This implementation only allows the controlling terminal to be changed
+by the session leader itself.
+This implies that
+.Fa pid
+always has to be equal to the process ID.
+.Pp
+It is unsupported to associate with a terminal that already has an
+associated session.
+Conversely, it is also unsupported to associate to a terminal when
+the session is already associated with a different terminal.
+.Sh ERRORS
+If an error occurs,
+.Fn tcsetsid
+returns -1 and the global variable
+.Va errno
+is set to indicate the error, as follows:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa fd
+argument is not a valid file descriptor.
+.It Bq Er ENOTTY
+The file descriptor represented by
+.Fa fd
+is not a terminal.
+.It Bq Er EINVAL
+The
+.Fa pid
+argument is not equal to the session ID of the calling process.
+.It Bq Er EPERM
+The calling process is not a session leader.
+.It Bq Er EPERM
+The session already has an associated terminal or the terminal already
+has an associated session.
+.El
+.Sh SEE ALSO
+.Xr getsid 2 ,
+.Xr setsid 2 ,
+.Xr tcgetpgrp 3 ,
+.Xr tcgetsid 3
+.Sh HISTORY
+A
+.Fn tcsetsid
+function first appeared in QNX.
+It does not comply to any standard.
diff --git a/lib/libc/gen/telldir.c b/lib/libc/gen/telldir.c
new file mode 100644
index 000000000000..3e5678cf2eb1
--- /dev/null
+++ b/lib/libc/gen/telldir.c
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)telldir.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <dirent.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+#include "libc_private.h"
+#include "gen-private.h"
+#include "telldir.h"
+
+/*
+ * return a pointer into a directory
+ */
+long
+telldir(DIR *dirp)
+{
+ struct ddloc *lp;
+ long idx;
+
+ if (__isthreaded)
+ _pthread_mutex_lock(&dirp->dd_lock);
+ LIST_FOREACH(lp, &dirp->dd_td->td_locq, loc_lqe) {
+ if (lp->loc_seek == dirp->dd_seek &&
+ lp->loc_loc == dirp->dd_loc)
+ break;
+ }
+ if (lp == NULL) {
+ lp = malloc(sizeof(struct ddloc));
+ if (lp == NULL) {
+ if (__isthreaded)
+ _pthread_mutex_unlock(&dirp->dd_lock);
+ return (-1);
+ }
+ lp->loc_index = dirp->dd_td->td_loccnt++;
+ lp->loc_seek = dirp->dd_seek;
+ lp->loc_loc = dirp->dd_loc;
+ LIST_INSERT_HEAD(&dirp->dd_td->td_locq, lp, loc_lqe);
+ }
+ idx = lp->loc_index;
+ if (__isthreaded)
+ _pthread_mutex_unlock(&dirp->dd_lock);
+ return (idx);
+}
+
+/*
+ * seek to an entry in a directory.
+ * Only values returned by "telldir" should be passed to seekdir.
+ */
+void
+_seekdir(DIR *dirp, long loc)
+{
+ struct ddloc *lp;
+ struct dirent *dp;
+
+ LIST_FOREACH(lp, &dirp->dd_td->td_locq, loc_lqe) {
+ if (lp->loc_index == loc)
+ break;
+ }
+ if (lp == NULL)
+ return;
+ if (lp->loc_loc == dirp->dd_loc && lp->loc_seek == dirp->dd_seek)
+ return;
+
+ /* If it's within the same chunk of data, don't bother reloading. */
+ if (lp->loc_seek == dirp->dd_seek) {
+ /*
+ * If we go back to 0 don't make the next readdir
+ * trigger a call to getdirentries().
+ */
+ if (lp->loc_loc == 0)
+ dirp->dd_flags |= __DTF_SKIPREAD;
+ dirp->dd_loc = lp->loc_loc;
+ return;
+ }
+ (void) lseek(dirp->dd_fd, (off_t)lp->loc_seek, SEEK_SET);
+ dirp->dd_seek = lp->loc_seek;
+ dirp->dd_loc = 0;
+ dirp->dd_flags &= ~__DTF_SKIPREAD; /* current contents are invalid */
+ while (dirp->dd_loc < lp->loc_loc) {
+ dp = _readdir_unlocked(dirp, 0);
+ if (dp == NULL)
+ break;
+ }
+}
+
+/*
+ * After readdir returns the last entry in a block, a call to telldir
+ * returns a location that is after the end of that last entry.
+ * However, that location doesn't refer to a valid directory entry.
+ * Ideally, the call to telldir would return a location that refers to
+ * the first entry in the next block. That location is not known
+ * until the next block is read, so readdir calls this function after
+ * fetching a new block to fix any such telldir locations.
+ */
+void
+_fixtelldir(DIR *dirp, long oldseek, long oldloc)
+{
+ struct ddloc *lp;
+
+ lp = LIST_FIRST(&dirp->dd_td->td_locq);
+ if (lp != NULL) {
+ if (lp->loc_loc == oldloc &&
+ lp->loc_seek == oldseek) {
+ lp->loc_seek = dirp->dd_seek;
+ lp->loc_loc = dirp->dd_loc;
+ }
+ }
+}
+
+/*
+ * Reclaim memory for telldir cookies which weren't used.
+ */
+void
+_reclaim_telldir(DIR *dirp)
+{
+ struct ddloc *lp;
+ struct ddloc *templp;
+
+ lp = LIST_FIRST(&dirp->dd_td->td_locq);
+ while (lp != NULL) {
+ templp = lp;
+ lp = LIST_NEXT(lp, loc_lqe);
+ free(templp);
+ }
+ LIST_INIT(&dirp->dd_td->td_locq);
+}
diff --git a/lib/libc/gen/telldir.h b/lib/libc/gen/telldir.h
new file mode 100644
index 000000000000..bccabb1aea53
--- /dev/null
+++ b/lib/libc/gen/telldir.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Copyright (c) 2000
+ * Daniel Eischen. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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 _TELLDIR_H_
+#define _TELLDIR_H_
+
+#include <sys/queue.h>
+#include <stdbool.h>
+
+/*
+ * One of these structures is malloced to describe the current directory
+ * position each time telldir is called. It records the current magic
+ * cookie returned by getdirentries and the offset within the buffer
+ * associated with that return value.
+ */
+struct ddloc {
+ LIST_ENTRY(ddloc) loc_lqe; /* entry in list */
+ long loc_index; /* key associated with structure */
+ long loc_seek; /* magic cookie returned by getdirentries */
+ long loc_loc; /* offset of entry in buffer */
+};
+
+/*
+ * One of these structures is malloced for each DIR to record telldir
+ * positions.
+ */
+struct _telldir {
+ LIST_HEAD(, ddloc) td_locq; /* list of locations */
+ long td_loccnt; /* index of entry for sequential readdir's */
+};
+
+bool _filldir(DIR *, bool);
+struct dirent *_readdir_unlocked(DIR *, int);
+void _reclaim_telldir(DIR *);
+void _seekdir(DIR *, long);
+void _fixtelldir(DIR *dirp, long oldseek, long oldloc);
+
+#endif
diff --git a/lib/libc/gen/termios.c b/lib/libc/gen/termios.c
new file mode 100644
index 000000000000..f8b7354f3162
--- /dev/null
+++ b/lib/libc/gen/termios.c
@@ -0,0 +1,277 @@
+/*-
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)termios.c 8.2 (Berkeley) 2/21/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+
+#include <errno.h>
+#include <string.h>
+#define TTYDEFCHARS
+#include <termios.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+#include "libc_private.h"
+
+int
+tcgetattr(int fd, struct termios *t)
+{
+
+ return (_ioctl(fd, TIOCGETA, t));
+}
+
+int
+tcsetattr(int fd, int opt, const struct termios *t)
+{
+ struct termios localterm;
+
+ if (opt & TCSASOFT) {
+ localterm = *t;
+ localterm.c_cflag |= CIGNORE;
+ t = &localterm;
+ }
+ switch (opt & ~TCSASOFT) {
+ case TCSANOW:
+ return (_ioctl(fd, TIOCSETA, t));
+ case TCSADRAIN:
+ return (_ioctl(fd, TIOCSETAW, t));
+ case TCSAFLUSH:
+ return (_ioctl(fd, TIOCSETAF, t));
+ default:
+ errno = EINVAL;
+ return (-1);
+ }
+}
+
+int
+tcsetpgrp(int fd, pid_t pgrp)
+{
+ int s;
+
+ s = pgrp;
+ return (_ioctl(fd, TIOCSPGRP, &s));
+}
+
+pid_t
+tcgetpgrp(int fd)
+{
+ int s;
+
+ if (_ioctl(fd, TIOCGPGRP, &s) < 0)
+ return ((pid_t)-1);
+
+ return ((pid_t)s);
+}
+
+pid_t
+tcgetsid(int fd)
+{
+ int s;
+
+ if (_ioctl(fd, TIOCGSID, &s) < 0)
+ return ((pid_t)-1);
+
+ return ((pid_t)s);
+}
+
+int
+tcsetsid(int fd, pid_t pid)
+{
+
+ if (pid != getsid(0)) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ return (_ioctl(fd, TIOCSCTTY, NULL));
+}
+
+speed_t
+cfgetospeed(const struct termios *t)
+{
+
+ return (t->c_ospeed);
+}
+
+speed_t
+cfgetispeed(const struct termios *t)
+{
+
+ return (t->c_ispeed);
+}
+
+int
+cfsetospeed(struct termios *t, speed_t speed)
+{
+
+ t->c_ospeed = speed;
+ return (0);
+}
+
+int
+cfsetispeed(struct termios *t, speed_t speed)
+{
+
+ t->c_ispeed = speed;
+ return (0);
+}
+
+int
+cfsetspeed(struct termios *t, speed_t speed)
+{
+
+ t->c_ispeed = t->c_ospeed = speed;
+ return (0);
+}
+
+/*
+ * Make a pre-existing termios structure into "raw" mode: character-at-a-time
+ * mode with no characters interpreted, 8-bit data path.
+ */
+void
+cfmakeraw(struct termios *t)
+{
+
+ t->c_iflag &= ~(IMAXBEL|IXOFF|INPCK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON|IGNPAR);
+ t->c_iflag |= IGNBRK;
+ t->c_oflag &= ~OPOST;
+ t->c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|ICANON|ISIG|IEXTEN|NOFLSH|TOSTOP|PENDIN);
+ t->c_cflag &= ~(CSIZE|PARENB);
+ t->c_cflag |= CS8|CREAD;
+ t->c_cc[VMIN] = 1;
+ t->c_cc[VTIME] = 0;
+}
+
+/*
+ * Obtain a termios structure which is similar to the one provided by
+ * the kernel.
+ */
+void
+cfmakesane(struct termios *t)
+{
+
+ t->c_cflag = TTYDEF_CFLAG;
+ t->c_iflag = TTYDEF_IFLAG;
+ t->c_lflag = TTYDEF_LFLAG;
+ t->c_oflag = TTYDEF_OFLAG;
+ t->c_ispeed = TTYDEF_SPEED;
+ t->c_ospeed = TTYDEF_SPEED;
+ memcpy(&t->c_cc, ttydefchars, sizeof ttydefchars);
+}
+
+int
+tcsendbreak(int fd, int len __unused)
+{
+ struct timeval sleepytime;
+
+ sleepytime.tv_sec = 0;
+ sleepytime.tv_usec = 400000;
+ if (_ioctl(fd, TIOCSBRK, 0) == -1)
+ return (-1);
+ (void)_select(0, 0, 0, 0, &sleepytime);
+ if (_ioctl(fd, TIOCCBRK, 0) == -1)
+ return (-1);
+ return (0);
+}
+
+int
+__libc_tcdrain(int fd)
+{
+
+ return (_ioctl(fd, TIOCDRAIN, 0));
+}
+
+#pragma weak tcdrain
+int
+tcdrain(int fd)
+{
+
+ return (((int (*)(int))
+ __libc_interposing[INTERPOS_tcdrain])(fd));
+}
+
+__weak_reference(__libc_tcdrain, __tcdrain);
+__weak_reference(__libc_tcdrain, _tcdrain);
+
+int
+tcflush(int fd, int which)
+{
+ int com;
+
+ switch (which) {
+ case TCIFLUSH:
+ com = FREAD;
+ break;
+ case TCOFLUSH:
+ com = FWRITE;
+ break;
+ case TCIOFLUSH:
+ com = FREAD | FWRITE;
+ break;
+ default:
+ errno = EINVAL;
+ return (-1);
+ }
+ return (_ioctl(fd, TIOCFLUSH, &com));
+}
+
+int
+tcflow(int fd, int action)
+{
+ struct termios term;
+ u_char c;
+
+ switch (action) {
+ case TCOOFF:
+ return (_ioctl(fd, TIOCSTOP, 0));
+ case TCOON:
+ return (_ioctl(fd, TIOCSTART, 0));
+ case TCION:
+ case TCIOFF:
+ if (tcgetattr(fd, &term) == -1)
+ return (-1);
+ c = term.c_cc[action == TCIOFF ? VSTOP : VSTART];
+ if (c != _POSIX_VDISABLE && _write(fd, &c, sizeof(c)) == -1)
+ return (-1);
+ return (0);
+ default:
+ errno = EINVAL;
+ return (-1);
+ }
+ /* NOTREACHED */
+}
diff --git a/lib/libc/gen/time.3 b/lib/libc/gen/time.3
new file mode 100644
index 000000000000..d022e0611c47
--- /dev/null
+++ b/lib/libc/gen/time.3
@@ -0,0 +1,101 @@
+.\" Copyright (c) 1989, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)time.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd July 18, 2003
+.Dt TIME 3
+.Os
+.Sh NAME
+.Nm time
+.Nd get time of day
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In time.h
+.Ft time_t
+.Fn time "time_t *tloc"
+.Sh DESCRIPTION
+The
+.Fn time
+function
+returns the value of time in seconds since 0 hours, 0 minutes,
+0 seconds, January 1, 1970, Coordinated Universal Time.
+If an error occurs,
+.Fn time
+returns the value
+.Po Vt time_t Pc Ns \-1 .
+.Pp
+The return value is also stored in
+.No \&* Ns Va tloc ,
+provided that
+.Va tloc
+is non-null.
+.Sh ERRORS
+The
+.Fn time
+function may fail for any of the reasons described in
+.Xr gettimeofday 2 .
+.Sh SEE ALSO
+.Xr clock_gettime 2 ,
+.Xr gettimeofday 2 ,
+.Xr ctime 3
+.Sh STANDARDS
+The
+.Nm
+function conforms to
+.St -p1003.1-2001 .
+.Sh HISTORY
+A
+.Fn time
+function appeared in
+.At v6 .
+.Sh BUGS
+Neither
+.St -isoC-99
+nor
+.St -p1003.1-2001
+requires
+.Fn time
+to set
+.Va errno
+on failure; thus, it is impossible for an application to distinguish
+the valid time value \-1 (representing the last UTC second of 1969)
+from the error return value.
+.Pp
+Systems conforming to earlier versions of the C and
+.Tn POSIX
+standards (including older versions of
+.Fx )
+did not set
+.No \&* Ns Va tloc
+in the error case.
diff --git a/lib/libc/gen/time.c b/lib/libc/gen/time.c
new file mode 100644
index 000000000000..214dfce1bb8e
--- /dev/null
+++ b/lib/libc/gen/time.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)time.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/time.h>
+
+time_t
+time(time_t *t)
+{
+ struct timespec tt;
+ time_t retval;
+
+ if (clock_gettime(CLOCK_SECOND, &tt) < 0)
+ retval = -1;
+ else
+ retval = tt.tv_sec;
+ if (t != NULL)
+ *t = retval;
+ return (retval);
+}
diff --git a/lib/libc/gen/times.3 b/lib/libc/gen/times.3
new file mode 100644
index 000000000000..a77c69f227a0
--- /dev/null
+++ b/lib/libc/gen/times.3
@@ -0,0 +1,145 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)times.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd December 1, 2008
+.Dt TIMES 3
+.Os
+.Sh NAME
+.Nm times
+.Nd process times
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/times.h
+.Ft clock_t
+.Fn times "struct tms *tp"
+.Sh DESCRIPTION
+.Bf -symbolic
+This interface is obsoleted by
+.Xr getrusage 2
+and
+.Xr gettimeofday 2 .
+.Ef
+.Pp
+The
+.Fn times
+function returns the value of time in
+.Dv CLK_TCK Ns 's
+of a second since the system startup time.
+The current value of
+.Dv CLK_TCK ,
+the frequency of the statistics clock in ticks per second, may be
+obtained through the
+.Xr sysconf 3
+interface.
+.Pp
+It also fills in the structure pointed to by
+.Fa tp
+with time-accounting information.
+.Pp
+The
+.Vt tms
+structure is defined as follows:
+.Bd -literal -offset indent
+struct tms {
+ clock_t tms_utime;
+ clock_t tms_stime;
+ clock_t tms_cutime;
+ clock_t tms_cstime;
+};
+.Ed
+.Pp
+The elements of this structure are defined as follows:
+.Bl -tag -width ".Va tms_cutime"
+.It Va tms_utime
+The
+.Tn CPU
+time charged for the execution of user instructions.
+.It Va tms_stime
+The
+.Tn CPU
+time charged for execution by the system on behalf of
+the process.
+.It Va tms_cutime
+The sum of the
+.Va tms_utime Ns s
+and
+.Va tms_cutime Ns s
+of the child processes.
+.It Va tms_cstime
+The sum of the
+.Fa tms_stime Ns s
+and
+.Fa tms_cstime Ns s
+of the child processes.
+.El
+.Pp
+All times are in
+.Dv CLK_TCK Ns 's
+of a second.
+.Pp
+The times of a terminated child process are included in the
+.Va tms_cutime
+and
+.Va tms_cstime
+elements of the parent when one of the
+.Xr wait 2
+functions returns the process ID of the terminated child to the parent.
+If an error occurs,
+.Fn times
+returns the value
+.Pq Po Vt clock_t Pc Ns \-1 ,
+and sets
+.Va errno
+to indicate the error.
+.Sh ERRORS
+The
+.Fn times
+function
+may fail and set the global variable
+.Va errno
+for any of the errors specified for the library
+routines
+.Xr getrusage 2
+and
+.Xr gettimeofday 2 .
+.Sh SEE ALSO
+.Xr time 1 ,
+.Xr getrusage 2 ,
+.Xr gettimeofday 2 ,
+.Xr wait 2 ,
+.Xr sysconf 3 ,
+.Xr clocks 7
+.Sh STANDARDS
+The
+.Fn times
+function
+conforms to
+.St -p1003.1-88 .
diff --git a/lib/libc/gen/times.c b/lib/libc/gen/times.c
new file mode 100644
index 000000000000..936511e1e439
--- /dev/null
+++ b/lib/libc/gen/times.c
@@ -0,0 +1,67 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)times.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/times.h>
+#include <sys/resource.h>
+
+/*
+ * Convert usec to clock ticks; could do (usec * CLK_TCK) / 1000000,
+ * but this would overflow if we switch to nanosec.
+ */
+#define CONVTCK(r) (r.tv_sec * CLK_TCK + r.tv_usec / (1000000 / CLK_TCK))
+
+clock_t
+times(tp)
+ struct tms *tp;
+{
+ struct rusage ru;
+ struct timespec t;
+ clock_t c;
+
+ if (getrusage(RUSAGE_SELF, &ru) < 0)
+ return ((clock_t)-1);
+ tp->tms_utime = CONVTCK(ru.ru_utime);
+ tp->tms_stime = CONVTCK(ru.ru_stime);
+ if (getrusage(RUSAGE_CHILDREN, &ru) < 0)
+ return ((clock_t)-1);
+ tp->tms_cutime = CONVTCK(ru.ru_utime);
+ tp->tms_cstime = CONVTCK(ru.ru_stime);
+ if (clock_gettime(CLOCK_MONOTONIC, &t))
+ return ((clock_t)-1);
+ c = t.tv_sec * CLK_TCK + t.tv_nsec / (1000000000 / CLK_TCK);
+ return (c);
+}
diff --git a/lib/libc/gen/timezone.3 b/lib/libc/gen/timezone.3
new file mode 100644
index 000000000000..dcf2665aba0f
--- /dev/null
+++ b/lib/libc/gen/timezone.3
@@ -0,0 +1,69 @@
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)timezone.3 8.2 (Berkeley) 4/19/94
+.\" $FreeBSD$
+.\"
+.Dd April 19, 1994
+.Dt TIMEZONE 3
+.Os
+.Sh NAME
+.Nm timezone
+.Nd return the timezone abbreviation
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.Ft char *
+.Fn timezone "int zone" "int dst"
+.Sh DESCRIPTION
+.Bf Sy
+This interface is for compatibility only; it is impossible to reliably
+map timezone's arguments to a time zone abbreviation.
+See
+.Xr ctime 3 .
+.Ef
+.Pp
+The
+.Fn timezone
+function returns a pointer to a time zone abbreviation for the specified
+.Fa zone
+and
+.Fa dst
+values.
+The
+.Fa zone
+argument
+is the number of minutes west of GMT and
+.Fa dst
+is non-zero if daylight savings time is in effect.
+.Sh SEE ALSO
+.Xr ctime 3
+.Sh HISTORY
+A
+.Fn timezone
+function appeared in
+.At v7 .
diff --git a/lib/libc/gen/timezone.c b/lib/libc/gen/timezone.c
new file mode 100644
index 000000000000..9b50e79dea0c
--- /dev/null
+++ b/lib/libc/gen/timezone.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 1987, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)timezone.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#define TZ_MAX_CHARS 255
+
+char *_tztab(int, int);
+
+/*
+ * timezone --
+ * The arguments are the number of minutes of time you are westward
+ * from Greenwich and whether DST is in effect. It returns a string
+ * giving the name of the local timezone. Should be replaced, in the
+ * application code, by a call to localtime.
+ */
+
+static char czone[TZ_MAX_CHARS]; /* space for zone name */
+
+char *
+timezone(int zone, int dst)
+{
+ char *beg,
+ *end;
+
+ if ( (beg = getenv("TZNAME")) ) { /* set in environment */
+ if ((end = strchr(beg, ','))) { /* "PST,PDT" */
+ if (dst)
+ return(++end);
+ *end = '\0';
+ (void)strncpy(czone,beg,sizeof(czone) - 1);
+ czone[sizeof(czone) - 1] = '\0';
+ *end = ',';
+ return(czone);
+ }
+ return(beg);
+ }
+ return(_tztab(zone,dst)); /* default: table or created zone */
+}
+
+static struct zone {
+ int offset;
+ char *stdzone;
+ char *dlzone;
+} zonetab[] = {
+ {-1*60, "MET", "MET DST"}, /* Middle European */
+ {-2*60, "EET", "EET DST"}, /* Eastern European */
+ {4*60, "AST", "ADT"}, /* Atlantic */
+ {5*60, "EST", "EDT"}, /* Eastern */
+ {6*60, "CST", "CDT"}, /* Central */
+ {7*60, "MST", "MDT"}, /* Mountain */
+ {8*60, "PST", "PDT"}, /* Pacific */
+#ifdef notdef
+ /* there's no way to distinguish this from WET */
+ {0, "GMT", 0}, /* Greenwich */
+#endif
+ {0*60, "WET", "WET DST"}, /* Western European */
+ {-10*60,"EST", "EST"}, /* Aust: Eastern */
+ {-10*60+30,"CST", "CST"}, /* Aust: Central */
+ {-8*60, "WST", 0}, /* Aust: Western */
+ {-1}
+};
+
+/*
+ * _tztab --
+ * check static tables or create a new zone name; broken out so that
+ * we can make a guess as to what the zone is if the standard tables
+ * aren't in place in /etc. DO NOT USE THIS ROUTINE OUTSIDE OF THE
+ * STANDARD LIBRARY.
+ */
+char *
+_tztab(int zone, int dst)
+{
+ struct zone *zp;
+ char sign;
+
+ for (zp = zonetab; zp->offset != -1;++zp) /* static tables */
+ if (zp->offset == zone) {
+ if (dst && zp->dlzone)
+ return(zp->dlzone);
+ if (!dst && zp->stdzone)
+ return(zp->stdzone);
+ }
+
+ if (zone < 0) { /* create one */
+ zone = -zone;
+ sign = '+';
+ }
+ else
+ sign = '-';
+ (void)snprintf(czone, sizeof(czone),
+ "GMT%c%d:%02d",sign,zone / 60,zone % 60);
+ return(czone);
+}
diff --git a/lib/libc/gen/tls.c b/lib/libc/gen/tls.c
new file mode 100644
index 000000000000..6cba47fe3d33
--- /dev/null
+++ b/lib/libc/gen/tls.c
@@ -0,0 +1,326 @@
+/*-
+ * Copyright (c) 2004 Doug Rabson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Define stubs for TLS internals so that programs and libraries can
+ * link. These functions will be replaced by functional versions at
+ * runtime from ld-elf.so.1.
+ */
+
+#include <sys/cdefs.h>
+#include <sys/param.h>
+#include <stdlib.h>
+#include <string.h>
+#include <elf.h>
+
+#include "libc_private.h"
+
+/* Provided by jemalloc to avoid bootstrapping issues. */
+void *__je_bootstrap_malloc(size_t size);
+void *__je_bootstrap_calloc(size_t num, size_t size);
+void __je_bootstrap_free(void *ptr);
+
+__weak_reference(__libc_allocate_tls, _rtld_allocate_tls);
+__weak_reference(__libc_free_tls, _rtld_free_tls);
+
+#ifdef __i386__
+
+__weak_reference(___libc_tls_get_addr, ___tls_get_addr);
+__attribute__((__regparm__(1))) void * ___libc_tls_get_addr(void *);
+
+#endif
+
+void * __libc_tls_get_addr(void *);
+__weak_reference(__libc_tls_get_addr, __tls_get_addr);
+
+void *_rtld_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign);
+void _rtld_free_tls(void *tls, size_t tcbsize, size_t tcbalign);
+void *__libc_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign);
+void __libc_free_tls(void *tls, size_t tcbsize, size_t tcbalign);
+
+#if defined(__amd64__)
+#define TLS_TCB_ALIGN 16
+#elif defined(__aarch64__) || defined(__arm__) || defined(__i386__) || \
+ defined(__mips__) || defined(__powerpc__) || defined(__riscv__) || \
+ defined(__sparc64__)
+#define TLS_TCB_ALIGN sizeof(void *)
+#else
+#error TLS_TCB_ALIGN undefined for target architecture
+#endif
+
+#if defined(__aarch64__) || defined(__arm__) || defined(__mips__) || \
+ defined(__powerpc__) || defined(__riscv__)
+#define TLS_VARIANT_I
+#endif
+#if defined(__i386__) || defined(__amd64__) || defined(__sparc64__)
+#define TLS_VARIANT_II
+#endif
+
+#ifndef PIC
+
+static size_t tls_static_space;
+static size_t tls_init_size;
+static void *tls_init;
+#endif
+
+#ifdef __i386__
+
+/* GNU ABI */
+
+__attribute__((__regparm__(1)))
+void *
+___libc_tls_get_addr(void *ti __unused)
+{
+ return (0);
+}
+
+#endif
+
+void *
+__libc_tls_get_addr(void *ti __unused)
+{
+ return (0);
+}
+
+#ifndef PIC
+
+#ifdef TLS_VARIANT_I
+
+#define TLS_TCB_SIZE (2 * sizeof(void *))
+
+/*
+ * Free Static TLS using the Variant I method.
+ */
+void
+__libc_free_tls(void *tcb, size_t tcbsize, size_t tcbalign __unused)
+{
+ Elf_Addr *dtv;
+ Elf_Addr **tls;
+
+ tls = (Elf_Addr **)((Elf_Addr)tcb + tcbsize - TLS_TCB_SIZE);
+ dtv = tls[0];
+ __je_bootstrap_free(dtv);
+ __je_bootstrap_free(tcb);
+}
+
+/*
+ * Allocate Static TLS using the Variant I method.
+ */
+void *
+__libc_allocate_tls(void *oldtcb, size_t tcbsize, size_t tcbalign __unused)
+{
+ Elf_Addr *dtv;
+ Elf_Addr **tls;
+ char *tcb;
+
+ if (oldtcb != NULL && tcbsize == TLS_TCB_SIZE)
+ return (oldtcb);
+
+ tcb = __je_bootstrap_calloc(1, tls_static_space + tcbsize - TLS_TCB_SIZE);
+ tls = (Elf_Addr **)(tcb + tcbsize - TLS_TCB_SIZE);
+
+ if (oldtcb != NULL) {
+ memcpy(tls, oldtcb, tls_static_space);
+ __je_bootstrap_free(oldtcb);
+
+ /* Adjust the DTV. */
+ dtv = tls[0];
+ dtv[2] = (Elf_Addr)tls + TLS_TCB_SIZE;
+ } else {
+ dtv = __je_bootstrap_malloc(3 * sizeof(Elf_Addr));
+ tls[0] = dtv;
+ dtv[0] = 1;
+ dtv[1] = 1;
+ dtv[2] = (Elf_Addr)tls + TLS_TCB_SIZE;
+
+ if (tls_init_size > 0)
+ memcpy((void*)dtv[2], tls_init, tls_init_size);
+ if (tls_static_space > tls_init_size)
+ memset((void*)(dtv[2] + tls_init_size), 0,
+ tls_static_space - tls_init_size);
+ }
+
+ return(tcb);
+}
+
+#endif
+
+#ifdef TLS_VARIANT_II
+
+#define TLS_TCB_SIZE (3 * sizeof(Elf_Addr))
+
+/*
+ * Free Static TLS using the Variant II method.
+ */
+void
+__libc_free_tls(void *tcb, size_t tcbsize __unused, size_t tcbalign)
+{
+ size_t size;
+ Elf_Addr* dtv;
+ Elf_Addr tlsstart, tlsend;
+
+ /*
+ * Figure out the size of the initial TLS block so that we can
+ * find stuff which ___tls_get_addr() allocated dynamically.
+ */
+ size = roundup2(tls_static_space, tcbalign);
+
+ dtv = ((Elf_Addr**)tcb)[1];
+ tlsend = (Elf_Addr) tcb;
+ tlsstart = tlsend - size;
+ __je_bootstrap_free((void*) tlsstart);
+ __je_bootstrap_free(dtv);
+}
+
+/*
+ * Allocate Static TLS using the Variant II method.
+ */
+void *
+__libc_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign)
+{
+ size_t size;
+ char *tls;
+ Elf_Addr *dtv;
+ Elf_Addr segbase, oldsegbase;
+
+ size = roundup2(tls_static_space, tcbalign);
+
+ if (tcbsize < 2 * sizeof(Elf_Addr))
+ tcbsize = 2 * sizeof(Elf_Addr);
+ tls = __je_bootstrap_calloc(1, size + tcbsize);
+ dtv = __je_bootstrap_malloc(3 * sizeof(Elf_Addr));
+
+ segbase = (Elf_Addr)(tls + size);
+ ((Elf_Addr*)segbase)[0] = segbase;
+ ((Elf_Addr*)segbase)[1] = (Elf_Addr) dtv;
+
+ dtv[0] = 1;
+ dtv[1] = 1;
+ dtv[2] = segbase - tls_static_space;
+
+ if (oldtls) {
+ /*
+ * Copy the static TLS block over whole.
+ */
+ oldsegbase = (Elf_Addr) oldtls;
+ memcpy((void *)(segbase - tls_static_space),
+ (const void *)(oldsegbase - tls_static_space),
+ tls_static_space);
+
+ /*
+ * We assume that this block was the one we created with
+ * allocate_initial_tls().
+ */
+ _rtld_free_tls(oldtls, 2*sizeof(Elf_Addr), sizeof(Elf_Addr));
+ } else {
+ memcpy((void *)(segbase - tls_static_space),
+ tls_init, tls_init_size);
+ memset((void *)(segbase - tls_static_space + tls_init_size),
+ 0, tls_static_space - tls_init_size);
+ }
+
+ return (void*) segbase;
+}
+
+#endif /* TLS_VARIANT_II */
+
+#else
+
+void *
+__libc_allocate_tls(void *oldtls __unused, size_t tcbsize __unused,
+ size_t tcbalign __unused)
+{
+ return (0);
+}
+
+void
+__libc_free_tls(void *tcb __unused, size_t tcbsize __unused,
+ size_t tcbalign __unused)
+{
+}
+
+#endif /* PIC */
+
+extern char **environ;
+
+void
+_init_tls(void)
+{
+#ifndef PIC
+ Elf_Addr *sp;
+ Elf_Auxinfo *aux, *auxp;
+ Elf_Phdr *phdr;
+ size_t phent, phnum;
+ int i;
+ void *tls;
+
+ sp = (Elf_Addr *) environ;
+ while (*sp++ != 0)
+ ;
+ aux = (Elf_Auxinfo *) sp;
+ phdr = NULL;
+ phent = phnum = 0;
+ for (auxp = aux; auxp->a_type != AT_NULL; auxp++) {
+ switch (auxp->a_type) {
+ case AT_PHDR:
+ phdr = auxp->a_un.a_ptr;
+ break;
+
+ case AT_PHENT:
+ phent = auxp->a_un.a_val;
+ break;
+
+ case AT_PHNUM:
+ phnum = auxp->a_un.a_val;
+ break;
+ }
+ }
+ if (phdr == NULL || phent != sizeof(Elf_Phdr) || phnum == 0)
+ return;
+
+ for (i = 0; (unsigned) i < phnum; i++) {
+ if (phdr[i].p_type == PT_TLS) {
+ tls_static_space = roundup2(phdr[i].p_memsz,
+ phdr[i].p_align);
+ tls_init_size = phdr[i].p_filesz;
+ tls_init = (void*) phdr[i].p_vaddr;
+ }
+ }
+
+#ifdef TLS_VARIANT_I
+ /*
+ * tls_static_space should include space for TLS structure
+ */
+ tls_static_space += TLS_TCB_SIZE;
+#endif
+
+ tls = _rtld_allocate_tls(NULL, TLS_TCB_SIZE, TLS_TCB_ALIGN);
+
+ _set_tp(tls);
+#endif
+}
diff --git a/lib/libc/gen/trivial-getcontextx.c b/lib/libc/gen/trivial-getcontextx.c
new file mode 100644
index 000000000000..54f851384811
--- /dev/null
+++ b/lib/libc/gen/trivial-getcontextx.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2011 Konstantin Belousov <kib@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/ucontext.h>
+#include <errno.h>
+#include <stdlib.h>
+
+int
+__getcontextx_size(void)
+{
+
+ return (sizeof(ucontext_t));
+}
+
+int
+__fillcontextx2(char *ctx)
+{
+
+ return (0);
+}
+
+int
+__fillcontextx(char *ctx)
+{
+ ucontext_t *ucp;
+
+ ucp = (ucontext_t *)ctx;
+ return (getcontext(ucp));
+}
+
+__weak_reference(__getcontextx, getcontextx);
+
+ucontext_t *
+__getcontextx(void)
+{
+ char *ctx;
+ int error;
+
+ ctx = malloc(__getcontextx_size());
+ if (ctx == NULL)
+ return (NULL);
+ if (__fillcontextx(ctx) == -1) {
+ error = errno;
+ free(ctx);
+ errno = error;
+ return (NULL);
+ }
+ return ((ucontext_t *)ctx);
+}
diff --git a/lib/libc/gen/ttyname.3 b/lib/libc/gen/ttyname.3
new file mode 100644
index 000000000000..9e8a4f099598
--- /dev/null
+++ b/lib/libc/gen/ttyname.3
@@ -0,0 +1,140 @@
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)ttyname.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd July 18, 2014
+.Dt TTYNAME 3
+.Os
+.Sh NAME
+.Nm ttyname ,
+.Nm ttyname_r ,
+.Nm isatty
+.Nd get name of associated terminal (tty) from file descriptor
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft char *
+.Fn ttyname "int fd"
+.Ft int
+.Fn ttyname_r "int fd" "char *buf" "size_t len"
+.Ft int
+.Fn isatty "int fd"
+.Sh DESCRIPTION
+These functions operate on file descriptors for terminal type devices.
+.Pp
+The
+.Fn isatty
+function
+determines if the file descriptor
+.Fa fd
+refers to a valid
+terminal type device.
+.Pp
+The
+.Fn ttyname
+function
+gets the related device name of
+a file descriptor for which
+.Fn isatty
+is true.
+.Pp
+The
+.Fn ttyname
+function
+returns the name stored in a static buffer which will be overwritten
+on subsequent calls.
+The
+.Fn ttyname_r
+function
+takes a buffer and length as arguments to avoid this problem.
+.Sh RETURN VALUES
+The
+.Fn isatty
+function returns 1 if
+.Fa fd
+refers to a terminal type device;
+otherwise, it returns 0 and may set
+.Va errno
+to indicate the error.
+The
+.Fn ttyname
+function
+returns the null terminated name if the device is found and
+.Fn isatty
+is true; otherwise
+a
+.Dv NULL
+pointer is returned.
+The
+.Fn ttyname_r
+function returns 0 if successful.
+Otherwise an error number is returned.
+.Sh ERRORS
+These functions may fail if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa fd
+argument
+is not a valid file descriptor.
+.It Bq Er ENOTTY
+The file associated with
+.Fa fd
+is not a terminal.
+.El
+.Pp
+Additionally,
+.Fn ttyname_r
+may fail if:
+.Bl -tag -width Er
+.It Bq Er ERANGE
+The
+.Fa bufsize
+argument
+is smaller than the length of the string to be returned.
+.El
+.Sh SEE ALSO
+.Xr fdevname 3 ,
+.Xr ptsname 3 ,
+.Xr tcgetattr 3 ,
+.Xr tty 4
+.Sh HISTORY
+The
+.Fn isatty
+and
+.Fn ttyname
+functions
+appeared in
+.At v7 .
+The
+.Fn ttyname_r
+function
+appeared in
+.Fx 6.0 .
diff --git a/lib/libc/gen/ttyname.c b/lib/libc/gen/ttyname.c
new file mode 100644
index 000000000000..02aa1587e14d
--- /dev/null
+++ b/lib/libc/gen/ttyname.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)ttyname.c 8.2 (Berkeley) 1/27/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/filio.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <stdlib.h>
+#include <termios.h>
+#include <unistd.h>
+#include <string.h>
+#include <paths.h>
+#include <errno.h>
+#include "reentrant.h"
+#include "un-namespace.h"
+
+#include "libc_private.h"
+
+static char ttyname_buf[sizeof(_PATH_DEV) + MAXNAMLEN];
+
+static once_t ttyname_init_once = ONCE_INITIALIZER;
+static thread_key_t ttyname_key;
+static int ttyname_keycreated = 0;
+
+int
+ttyname_r(int fd, char *buf, size_t len)
+{
+ size_t used;
+
+ *buf = '\0';
+
+ /* Must be a terminal. */
+ if (!isatty(fd))
+ return (errno);
+ /* Must have enough room */
+ if (len <= sizeof(_PATH_DEV))
+ return (ERANGE);
+
+ strcpy(buf, _PATH_DEV);
+ used = strlen(buf);
+ if (fdevname_r(fd, buf + used, len - used) == NULL)
+ return (errno == EINVAL ? ERANGE : errno);
+ return (0);
+}
+
+static void
+ttyname_keycreate(void)
+{
+ ttyname_keycreated = (thr_keycreate(&ttyname_key, free) == 0);
+}
+
+char *
+ttyname(int fd)
+{
+ char *buf;
+
+ if (thr_main() != 0)
+ buf = ttyname_buf;
+ else {
+ if (thr_once(&ttyname_init_once, ttyname_keycreate) != 0 ||
+ !ttyname_keycreated)
+ return (NULL);
+ if ((buf = thr_getspecific(ttyname_key)) == NULL) {
+ if ((buf = malloc(sizeof ttyname_buf)) == NULL)
+ return (NULL);
+ if (thr_setspecific(ttyname_key, buf) != 0) {
+ free(buf);
+ return (NULL);
+ }
+ }
+ }
+
+ if (ttyname_r(fd, buf, sizeof ttyname_buf) != 0)
+ return (NULL);
+ return (buf);
+}
diff --git a/lib/libc/gen/ttyslot.c b/lib/libc/gen/ttyslot.c
new file mode 100644
index 000000000000..397e3ad466c4
--- /dev/null
+++ b/lib/libc/gen/ttyslot.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)ttyslot.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+int __ttyslot(void);
+
+int
+__ttyslot(void)
+{
+
+ return (0);
+}
+
+__sym_compat(ttyslot, __ttyslot, FBSD_1.0);
diff --git a/lib/libc/gen/tzset.3 b/lib/libc/gen/tzset.3
new file mode 100644
index 000000000000..8d37fcaf9db8
--- /dev/null
+++ b/lib/libc/gen/tzset.3
@@ -0,0 +1,338 @@
+.\" Copyright (c) 1989, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Arthur Olson.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)tzset.3 8.2 (Berkeley) 11/17/93
+.\" $FreeBSD$
+.\"
+.Dd November 17, 1993
+.Dt TZSET 3
+.Os
+.Sh NAME
+.Nm tzset ,
+.Nm tzsetwall
+.Nd initialize time conversion information
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In time.h
+.Ft void
+.Fn tzset void
+.Ft void
+.Fn tzsetwall void
+.Sh DESCRIPTION
+The
+.Fn tzset
+function
+initializes time conversion information used by the library routine
+.Xr localtime 3 .
+The environment variable
+.Ev TZ
+specifies how this is done.
+.Pp
+If
+.Ev TZ
+does not appear in the environment, the best available approximation to
+local wall clock time, as specified by the
+.Xr tzfile 5 Ns -format
+file
+.Pa /etc/localtime
+is used.
+.Pp
+If
+.Ev TZ
+appears in the environment but its value is a null string, Coordinated
+Universal Time
+.Pq Tn UTC
+is used (without leap second correction).
+.Pp
+If
+.Ev TZ
+appears in the environment and its value begins with a colon
+.Pq Ql \&: ,
+the rest of its value is used as a pathname of a
+.Xr tzfile 5 Ns -format
+file from which to read the time conversion information.
+If the first character of the pathname is a slash
+.Pq Ql /
+it is used as
+an absolute pathname; otherwise, it is used as a pathname relative to
+the system time conversion information directory.
+.Pp
+If its value does not begin with a colon, it is first used as the pathname
+of a file (as described above) from which to read the time conversion
+information.
+If that file cannot be read, the value is then interpreted as a direct
+specification (the format is described below) of the time conversion
+information.
+.Pp
+If the
+.Ev TZ
+environment variable does not specify a
+.Xr tzfile 5 Ns -format
+file and cannot be interpreted as a direct specification,
+.Tn UTC
+is used.
+.Pp
+The
+.Fn tzsetwall
+function
+sets things up so that
+.Xr localtime 3
+returns the best available approximation of local wall clock time.
+.Sh SPECIFICATION FORMAT
+When
+.Ev TZ
+is used directly as a specification of the time conversion information,
+it must have the following syntax (spaces inserted for clarity):
+.Bd -ragged -offset indent
+.Em std offset
+.Bo
+.Em dst
+.Bq Em offset
+.Bq , Em rule
+.Bc
+.Ed
+.Pp
+Where:
+.Bl -tag -width std_and_dst -offset indent
+.It Em std No and Em dst
+Three or more bytes that are the designation for the standard
+.Pq Em std
+or summer
+.Pq Em dst
+time zone.
+Only
+.Em std
+is required; if
+.Em dst
+is missing, then summer time does not apply in this locale.
+Upper and lowercase letters are explicitly allowed.
+Any characters
+except a leading colon
+.Pq Ql \&: ,
+digits, comma
+.Pq Ql \&, ,
+minus
+.Pq Ql \- ,
+plus
+.Pq Ql + ,
+and
+.Tn ASCII
+.Dv NUL
+are allowed.
+.It Em offset
+Indicates the value one must add to the local time to arrive at
+Coordinated Universal Time.
+The
+.Em offset
+has the form:
+.Bd -ragged -offset indent
+.Sm off
+.Em hh Bo
+.Em : mm
+.Bq Em : ss
+.Bc
+.Sm on
+.Ed
+.Pp
+The minutes
+.Pq Em mm
+and seconds
+.Pq Em ss
+are optional.
+The hour
+.Pq Em hh
+is required and may be a single digit.
+The
+.Em offset
+following
+.Em std
+is required.
+If no
+.Em offset
+follows
+.Em dst ,
+summer time is assumed to be one hour ahead of standard time.
+One or
+more digits may be used; the value is always interpreted as a decimal
+number.
+The hour must be between zero and 24, and the minutes (and
+seconds) \(em if present \(em between zero and 59.
+If preceded by a
+.Pq Ql \-
+the time zone shall be east of the Prime Meridian; otherwise it shall be
+west (which may be indicated by an optional preceding
+.Pq Ql + ) .
+.It Em rule
+Indicates when to change to and back from summer time.
+The
+.Em rule
+has the form:
+.Bd -ragged -offset indent
+.Em date/time,date/time
+.Ed
+.Pp
+where the first
+.Em date
+describes when the change from standard to summer time occurs and the
+second
+.Em date
+describes when the change back happens.
+Each
+.Em time
+field describes when, in current local time, the change to the other
+time is made.
+.Pp
+The format of
+.Em date
+is one of the following:
+.Bl -tag -width "M.m.n.d"
+.It Sy J Em n
+The Julian day
+.Em n
+(1 \*(Le
+.Em n
+\*(Le 365).
+Leap days are not counted; that is, in all years \(em including leap
+years \(em February 28 is day 59 and March 1 is day 60.
+It is
+impossible to explicitly refer to the occasional February 29.
+.It Em n
+The zero-based Julian day
+(0 \*(Le
+.Em n
+\*(Le 365 ) .
+Leap days are counted, and it is possible to refer to February 29.
+.It Sy M Em m.n.d
+The
+.Em d Ns 'th
+day (0 \*(Le
+.Em d
+\*(Le 6)
+of week
+.Em n
+of month
+.Em m
+of the year
+(1 \*(Le
+.Em n
+\*(Le 5),
+(1 \*(Le
+.Em m
+\*(Le 12),
+where week 5 means
+.Do
+the last
+.Em d
+day in month
+.Em m
+.Dc
+which may occur in either the fourth or the fifth week).
+Week 1 is the
+first week in which the
+.Em d Ns 'th
+day occurs.
+Day zero is Sunday.
+.Pp
+The
+.Em time
+has the same format as
+.Em offset
+except that no leading sign
+.Pq Ql \-
+or
+.Pq Ql +
+is allowed.
+The default, if
+.Em time
+is not given, is
+.Sy 02:00:00 .
+.El
+.Pp
+If no
+.Em rule
+is present in the
+.Ev TZ
+specification, the rules specified
+by the
+.Xr tzfile 5 Ns -format
+file
+.Em posixrules
+in the system time conversion information directory are used, with the
+standard and summer time offsets from
+.Tn UTC
+replaced by those specified by
+the
+.Em offset
+values in
+.Ev TZ .
+.El
+.Pp
+For compatibility with System V Release 3.1, a semicolon
+.Pq Ql \&;
+may be used to separate the
+.Em rule
+from the rest of the specification.
+.Sh FILES
+.Bl -tag -width /usr/share/zoneinfo/posixrules -compact
+.It Pa /etc/localtime
+local time zone file
+.It Pa /usr/share/zoneinfo
+time zone directory
+.It Pa /usr/share/zoneinfo/posixrules
+rules for
+.Tn POSIX Ns -style
+.Tn TZ Ns 's
+.It Pa /usr/share/zoneinfo/Etc/GMT
+for
+.Tn UTC
+leap seconds
+.El
+.Pp
+If the file
+.Pa /usr/share/zoneinfo/UTC
+does not exist,
+.Tn UTC
+leap seconds are loaded from
+.Pa /usr/share/zoneinfo/posixrules .
+.Sh SEE ALSO
+.Xr date 1 ,
+.Xr gettimeofday 2 ,
+.Xr ctime 3 ,
+.Xr getenv 3 ,
+.Xr time 3 ,
+.Xr tzfile 5
+.Sh HISTORY
+The
+.Fn tzset
+and
+.Fn tzsetwall
+functions first appeared in
+.Bx 4.4 .
diff --git a/lib/libc/gen/ualarm.3 b/lib/libc/gen/ualarm.3
new file mode 100644
index 000000000000..57198962800d
--- /dev/null
+++ b/lib/libc/gen/ualarm.3
@@ -0,0 +1,97 @@
+.\" Copyright (c) 1986, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" From: @(#)ualarm.3 8.2 (Berkeley) 4/19/94
+.\" $FreeBSD$
+.\"
+.Dd April 19, 1994
+.Dt UALARM 3
+.Os
+.Sh NAME
+.Nm ualarm
+.Nd schedule signal after specified time
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft useconds_t
+.Fn ualarm "useconds_t microseconds" "useconds_t interval"
+.Sh DESCRIPTION
+.Bf -symbolic
+This is a simplified interface to
+.Xr setitimer 2 .
+.Ef
+.Pp
+The
+.Fn ualarm
+function
+waits a count of
+.Fa microseconds
+before asserting the terminating signal
+.Dv SIGALRM .
+System activity or time used in processing the call may cause a slight
+delay.
+.Pp
+If the
+.Fa interval
+argument is non-zero, the
+.Dv SIGALRM
+signal will be sent
+to the process every
+.Fa interval
+microseconds after the timer expires (e.g.\& after
+.Fa microseconds
+number of microseconds have passed).
+.Pp
+Due to
+.Xr setitimer 2
+restriction the maximum number of
+.Fa microseconds
+and
+.Fa interval
+is limited to 100000000000000
+(in case this value fits in the unsigned integer).
+.Sh RETURN VALUES
+When the signal has successfully been caught,
+.Fn ualarm
+returns the amount of time left on the clock.
+.Sh NOTES
+A microsecond is 0.000001 seconds.
+.Sh SEE ALSO
+.Xr getitimer 2 ,
+.Xr setitimer 2 ,
+.Xr sigaction 2 ,
+.Xr sigsuspend 2 ,
+.Xr alarm 3 ,
+.Xr signal 3 ,
+.Xr sleep 3 ,
+.Xr usleep 3
+.Sh HISTORY
+The
+.Fn ualarm
+function appeared in
+.Bx 4.3 .
diff --git a/lib/libc/gen/ualarm.c b/lib/libc/gen/ualarm.c
new file mode 100644
index 000000000000..6a1dca791533
--- /dev/null
+++ b/lib/libc/gen/ualarm.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1985, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)ualarm.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/time.h>
+#include <unistd.h>
+
+#define USPS 1000000 /* # of microseconds in a second */
+
+/*
+ * Generate a SIGALRM signal in ``usecs'' microseconds.
+ * If ``reload'' is non-zero, keep generating SIGALRM
+ * every ``reload'' microseconds after the first signal.
+ */
+useconds_t
+ualarm(useconds_t usecs, useconds_t reload)
+{
+ struct itimerval new, old;
+
+ new.it_interval.tv_usec = reload % USPS;
+ new.it_interval.tv_sec = reload / USPS;
+
+ new.it_value.tv_usec = usecs % USPS;
+ new.it_value.tv_sec = usecs / USPS;
+
+ if (setitimer(ITIMER_REAL, &new, &old) == 0)
+ return (old.it_value.tv_sec * USPS + old.it_value.tv_usec);
+ /* else */
+ return (-1);
+}
diff --git a/lib/libc/gen/ucontext.3 b/lib/libc/gen/ucontext.3
new file mode 100644
index 000000000000..69ecbc1793e0
--- /dev/null
+++ b/lib/libc/gen/ucontext.3
@@ -0,0 +1,111 @@
+.\" Copyright (c) 2002 Packet Design, LLC.
+.\" All rights reserved.
+.\"
+.\" Subject to the following obligations and disclaimer of warranty,
+.\" use and redistribution of this software, in source or object code
+.\" forms, with or without modifications are expressly permitted by
+.\" Packet Design; provided, however, that:
+.\"
+.\" (i) Any and all reproductions of the source or object code
+.\" must include the copyright notice above and the following
+.\" disclaimer of warranties; and
+.\" (ii) No rights are granted, in any manner or form, to use
+.\" Packet Design trademarks, including the mark "PACKET DESIGN"
+.\" on advertising, endorsements, or otherwise except as such
+.\" appears in the above copyright notice or in the software.
+.\"
+.\" THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND
+.\" TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO
+.\" REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING
+.\" THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED
+.\" WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
+.\" OR NON-INFRINGEMENT. PACKET DESIGN DOES NOT WARRANT, GUARANTEE,
+.\" OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS
+.\" OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY,
+.\" RELIABILITY OR OTHERWISE. IN NO EVENT SHALL PACKET DESIGN BE
+.\" LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE
+.\" OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT,
+.\" INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL
+.\" DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF
+.\" USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF
+.\" LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+.\" THE USE OF THIS SOFTWARE, EVEN IF PACKET DESIGN IS ADVISED OF
+.\" THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd September 10, 2002
+.Dt UCONTEXT 3
+.Os
+.Sh NAME
+.Nm ucontext
+.Nd user thread context
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In ucontext.h
+.Sh DESCRIPTION
+The
+.Vt ucontext_t
+type is a structure type suitable for holding the context for a user
+thread of execution.
+A thread's context includes its stack, saved registers, and list of
+blocked signals.
+.Pp
+The
+.Vt ucontext_t
+structure contains at least these fields:
+.Pp
+.Bl -tag -width ".Va mcontext_t\ \ uc_mcontext" -offset 3n -compact
+.It Va "ucontext_t *uc_link"
+context to assume when this one returns
+.It Va "sigset_t uc_sigmask"
+signals being blocked
+.It Va "stack_t uc_stack"
+stack area
+.It Va "mcontext_t uc_mcontext"
+saved registers
+.El
+.Pp
+The
+.Va uc_link
+field points to the context to resume when this context's entry point
+function returns.
+If
+.Va uc_link
+is equal to
+.Dv NULL ,
+then the process exits when this context returns.
+.Pp
+The
+.Va uc_mcontext
+field is machine-dependent and should be treated as opaque by
+portable applications.
+.Pp
+The following functions are defined to manipulate
+.Vt ucontext_t
+structures:
+.Pp
+.Bl -item -offset 3n -compact
+.It
+.Ft int
+.Fn getcontext "ucontext_t *" ;
+.It
+.Ft "ucontext_t *"
+.Fn getcontextx "void" ;
+.It
+.Ft int
+.Fn setcontext "const ucontext_t *" ;
+.It
+.Ft void
+.Fn makecontext "ucontext_t *" "void \*[lp]*\*[rp]\*[lp]void\*[rp]" int ... ;
+.It
+.Ft int
+.Fn swapcontext "ucontext_t *" "const ucontext_t *" ;
+.El
+.Sh SEE ALSO
+.Xr sigaltstack 2 ,
+.Xr getcontext 3 ,
+.Xr getcontextx 3 ,
+.Xr makecontext 3
diff --git a/lib/libc/gen/ulimit.3 b/lib/libc/gen/ulimit.3
new file mode 100644
index 000000000000..e4c2d769323c
--- /dev/null
+++ b/lib/libc/gen/ulimit.3
@@ -0,0 +1,98 @@
+.\" Copyright (c) 2002 Kyle Martin. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 January 4, 2003
+.Dt ULIMIT 3
+.Os
+.Sh NAME
+.Nm ulimit
+.Nd get and set process limits
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In ulimit.h
+.Ft long
+.Fn ulimit "int cmd" "..."
+.Sh DESCRIPTION
+The
+.Fn ulimit
+function will get and set process limits.
+Currently this is limited to the maximum file size.
+The
+.Fa cmd
+argument is one of the following:
+.Bl -tag -width ".Dv UL_GETFSIZE"
+.It Dv UL_GETFSIZE
+will return the maximum file size in units of 512 blocks of
+the current process.
+.It Dv UL_SETFSIZE
+will attempt to set the maximum file size of the current
+process and its children with the second argument expressed as a long.
+.El
+.Sh RETURN VALUES
+Upon successful completion,
+.Fn ulimit
+returns the value requested;
+otherwise the value \-1 is returned and the global variable
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+The
+.Fn ulimit
+function will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The command specified was invalid.
+.It Bq Er EPERM
+The limit specified to
+.Fn ulimit
+would have raised the maximum limit value,
+and the caller is not the super-user.
+.El
+.Sh SEE ALSO
+.Xr getrlimit 2
+.Sh STANDARDS
+The
+.Fn ulimit
+function conforms to
+.St -p1003.1-2001 .
+.Sh HISTORY
+The
+.Fn ulimit
+function first appeared in
+.Fx 5.0 .
+.Sh BUGS
+The
+.Fn ulimit
+function provides limited precision for
+setting and retrieving process limits.
+If there is a need for greater precision than the
+type
+.Vt long
+provides, the
+.Xr getrlimit 2
+and
+.Xr setrlimit 2
+functions should be considered.
diff --git a/lib/libc/gen/ulimit.c b/lib/libc/gen/ulimit.c
new file mode 100644
index 000000000000..2c090c0a7ef3
--- /dev/null
+++ b/lib/libc/gen/ulimit.c
@@ -0,0 +1,70 @@
+/*-
+ * Copyright (c) 2002 Kyle Martin <mkm@ieee.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 <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <ulimit.h>
+
+long
+ulimit(int cmd, ...)
+{
+ struct rlimit limit;
+ va_list ap;
+ rlim_t arg;
+
+ if (cmd == UL_GETFSIZE) {
+ if (getrlimit(RLIMIT_FSIZE, &limit) == -1)
+ return (-1);
+ limit.rlim_cur /= 512;
+ if (limit.rlim_cur > LONG_MAX)
+ return (LONG_MAX);
+ return ((long)limit.rlim_cur);
+ } else if (cmd == UL_SETFSIZE) {
+ va_start(ap, cmd);
+ arg = va_arg(ap, long);
+ va_end(ap);
+ if (arg < 0)
+ arg = LONG_MAX;
+ if (arg > RLIM_INFINITY / 512)
+ arg = RLIM_INFINITY / 512;
+ limit.rlim_max = limit.rlim_cur = arg * 512;
+
+ /* The setrlimit() function sets errno to EPERM if needed. */
+ if (setrlimit(RLIMIT_FSIZE, &limit) == -1)
+ return (-1);
+ return ((long)arg);
+ } else {
+ errno = EINVAL;
+ return (-1);
+ }
+}
diff --git a/lib/libc/gen/uname.3 b/lib/libc/gen/uname.3
new file mode 100644
index 000000000000..a906e79d3489
--- /dev/null
+++ b/lib/libc/gen/uname.3
@@ -0,0 +1,117 @@
+.\" Copyright (c) 1994
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)uname.3 8.1 (Berkeley) 1/4/94
+.\" $FreeBSD$
+.\"
+.Dd December 2, 2005
+.Dt UNAME 3
+.Os
+.Sh NAME
+.Nm uname
+.Nd get system identification
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/utsname.h
+.Ft int
+.Fn uname "struct utsname *name"
+.Sh DESCRIPTION
+The
+.Fn uname
+function stores
+.Dv NUL Ns -terminated
+strings of information identifying
+the current system into the structure referenced by
+.Fa name .
+.Pp
+The
+.Vt utsname
+structure is defined in the
+.In sys/utsname.h
+header file, and contains the following members:
+.Bl -tag -width nodenameXXXX -offset indent
+.It sysname
+Name of the operating system implementation.
+.It nodename
+Network name of this machine.
+.It release
+Release level of the operating system.
+.It version
+Version level of the operating system.
+.It machine
+Machine hardware platform.
+.El
+.Sh RETURN VALUES
+.Rv -std uname
+.Sh ENVIRONMENT
+.Bl -tag -width ".Ev UNAME_s"
+.It Ev UNAME_s
+If the environment variable
+.Ev UNAME_s
+is set, it will override the
+.Va sysname
+member.
+.It Ev UNAME_r
+If the environment variable
+.Ev UNAME_r
+is set, it will override the
+.Va release
+member.
+.It Ev UNAME_v
+If the environment variable
+.Ev UNAME_v
+is set, it will override the
+.Va version
+member.
+.It Ev UNAME_m
+If the environment variable
+.Ev UNAME_m
+is set, it will override the
+.Va machine
+member.
+.El
+.Sh ERRORS
+The
+.Fn uname
+function may fail and set
+.Va errno
+for any of the errors specified for the library functions
+.Xr sysctl 3 .
+.Sh SEE ALSO
+.Xr uname 1 ,
+.Xr sysctl 3
+.Sh STANDARDS
+The
+.Fn uname
+function conforms to
+.St -p1003.1-88 .
+.Sh HISTORY
+The
+.Fn uname
+function first appeared in
+.Bx 4.4 .
diff --git a/lib/libc/gen/uname.c b/lib/libc/gen/uname.c
new file mode 100644
index 000000000000..499f761ae48b
--- /dev/null
+++ b/lib/libc/gen/uname.c
@@ -0,0 +1,49 @@
+/*-
+ * Copyright (c) 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "From: @(#)uname.c 8.1 (Berkeley) 1/4/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#define uname wrapped_uname
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <sys/utsname.h>
+#include <errno.h>
+#undef uname
+
+int uname(struct utsname *);
+
+int
+uname(struct utsname *name)
+{
+ return __xuname(32, name);
+}
diff --git a/lib/libc/gen/unvis-compat.c b/lib/libc/gen/unvis-compat.c
new file mode 100644
index 000000000000..5fa5ca9ee053
--- /dev/null
+++ b/lib/libc/gen/unvis-compat.c
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 2012 SRI International
+ * All rights reserved.
+ *
+ * This software was developed by SRI International and the University of
+ * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
+ * ("CTSRD"), as part of the DARPA CRASH research programme.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <vis.h>
+
+#define _UNVIS_END 1
+
+int __unvis_44bsd(char *, int, int *, int);
+
+int
+__unvis_44bsd(char *cp, int c, int *astate, int flag)
+{
+
+ if (flag & _UNVIS_END)
+ flag = (flag & ~_UNVIS_END) ^ UNVIS_END;
+ return unvis(cp, c, astate, flag);
+}
+
+__sym_compat(unvis, __vis_44bsd, FBSD_1.0);
diff --git a/lib/libc/gen/usleep.3 b/lib/libc/gen/usleep.3
new file mode 100644
index 000000000000..a17468b332e7
--- /dev/null
+++ b/lib/libc/gen/usleep.3
@@ -0,0 +1,80 @@
+.\" Copyright (c) 1986, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)usleep.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd February 13, 1998
+.Dt USLEEP 3
+.Os
+.Sh NAME
+.Nm usleep
+.Nd suspend process execution for an interval measured in microseconds
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft int
+.Fn usleep "useconds_t microseconds"
+.Sh DESCRIPTION
+The
+.Fn usleep
+function suspends execution of the calling process until either
+.Fa microseconds
+microseconds have elapsed or a signal is delivered to the process and its
+action is to invoke a signal-catching function or to terminate the
+process.
+System activity may lengthen the sleep by an indeterminate amount.
+.Pp
+This function is implemented using
+.Xr nanosleep 2
+by pausing for
+.Fa microseconds
+microseconds or until a signal occurs.
+Consequently, in this implementation,
+sleeping has no effect on the state of process timers,
+and there is no special handling for SIGALRM.
+.Sh RETURN VALUES
+.Rv -std usleep
+.Sh ERRORS
+The
+.Fn usleep
+function
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EINTR
+A signal was delivered to the process and its
+action was to invoke a signal-catching function.
+.El
+.Sh SEE ALSO
+.Xr nanosleep 2 ,
+.Xr sleep 3
+.Sh HISTORY
+The
+.Fn usleep
+function appeared in
+.Bx 4.3 .
diff --git a/lib/libc/gen/usleep.c b/lib/libc/gen/usleep.c
new file mode 100644
index 000000000000..90be6d455c91
--- /dev/null
+++ b/lib/libc/gen/usleep.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)usleep.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <time.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+#include "libc_private.h"
+
+int __usleep(useconds_t);
+
+int
+__usleep(useconds_t useconds)
+{
+ struct timespec time_to_sleep;
+
+ time_to_sleep.tv_nsec = (useconds % 1000000) * 1000;
+ time_to_sleep.tv_sec = useconds / 1000000;
+ return (((int (*)(const struct timespec *, struct timespec *))
+ __libc_interposing[INTERPOS_nanosleep])(&time_to_sleep, NULL));
+}
+
+__weak_reference(__usleep, usleep);
+__weak_reference(__usleep, _usleep);
diff --git a/lib/libc/gen/utime.3 b/lib/libc/gen/utime.3
new file mode 100644
index 000000000000..20c7916acbbb
--- /dev/null
+++ b/lib/libc/gen/utime.3
@@ -0,0 +1,94 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)utime.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 9, 2016
+.Dt UTIME 3
+.Os
+.Sh NAME
+.Nm utime
+.Nd set file times
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In utime.h
+.Ft int
+.Fn utime "const char *file" "const struct utimbuf *timep"
+.Sh DESCRIPTION
+.Bf -symbolic
+This interface is obsoleted by
+.Xr utimensat 2
+because it is not accurate to fractions of a second.
+.Ef
+.Pp
+The
+.Fn utime
+function sets the access and modification times of the named file from
+the
+.Va actime
+and
+.Va modtime
+fields of the
+.Vt "struct utimbuf"
+pointed at by
+.Fa timep .
+.Pp
+If the times are specified (the
+.Fa timep
+argument is
+.Pf non- Dv NULL )
+the caller must be the owner of the file or be the super-user.
+.Pp
+If the times are not specified (the
+.Fa timep
+argument is
+.Dv NULL )
+the caller must be the owner of the file, have permission to write
+the file, or be the super-user.
+.Sh ERRORS
+The
+.Fn utime
+function may fail and set
+.Va errno
+for any of the errors specified for the library function
+.Xr utimes 2 .
+.Sh SEE ALSO
+.Xr stat 2 ,
+.Xr utimensat 2 ,
+.Xr utimes 2
+.Sh STANDARDS
+The
+.Fn utime
+function conforms to
+.St -p1003.1-88 .
+.Sh HISTORY
+A
+.Fn utime
+function appeared in
+.At v7 .
diff --git a/lib/libc/gen/utime.c b/lib/libc/gen/utime.c
new file mode 100644
index 000000000000..0250a7ad8c33
--- /dev/null
+++ b/lib/libc/gen/utime.c
@@ -0,0 +1,53 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)utime.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/time.h>
+
+#include <utime.h>
+
+int
+utime(const char *path, const struct utimbuf *times)
+{
+ struct timeval tv[2], *tvp;
+
+ if (times) {
+ tv[0].tv_sec = times->actime;
+ tv[1].tv_sec = times->modtime;
+ tv[0].tv_usec = tv[1].tv_usec = 0;
+ tvp = tv;
+ } else
+ tvp = NULL;
+ return (utimes(path, tvp));
+}
diff --git a/lib/libc/gen/utxdb.c b/lib/libc/gen/utxdb.c
new file mode 100644
index 000000000000..66671290dc4b
--- /dev/null
+++ b/lib/libc/gen/utxdb.c
@@ -0,0 +1,179 @@
+/*-
+ * Copyright (c) 2010 Ed Schouten <ed@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/endian.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <stdlib.h>
+#include <string.h>
+#include <utmpx.h>
+#include "utxdb.h"
+#include "un-namespace.h"
+
+#define UTOF_STRING(ut, fu, field) do { \
+ strncpy((fu)->fu_ ## field, (ut)->ut_ ## field, \
+ MIN(sizeof (fu)->fu_ ## field, sizeof (ut)->ut_ ## field)); \
+} while (0)
+#define UTOF_ID(ut, fu) do { \
+ memcpy((fu)->fu_id, (ut)->ut_id, \
+ MIN(sizeof (fu)->fu_id, sizeof (ut)->ut_id)); \
+} while (0)
+#define UTOF_PID(ut, fu) do { \
+ (fu)->fu_pid = htobe32((ut)->ut_pid); \
+} while (0)
+#define UTOF_TYPE(ut, fu) do { \
+ (fu)->fu_type = (ut)->ut_type; \
+} while (0)
+#define UTOF_TV(fu) do { \
+ struct timeval tv; \
+ gettimeofday(&tv, NULL); \
+ (fu)->fu_tv = htobe64((uint64_t)tv.tv_sec * 1000000 + \
+ (uint64_t)tv.tv_usec); \
+} while (0)
+
+void
+utx_to_futx(const struct utmpx *ut, struct futx *fu)
+{
+
+ memset(fu, 0, sizeof *fu);
+
+ switch (ut->ut_type) {
+ case BOOT_TIME:
+ case OLD_TIME:
+ case NEW_TIME:
+ /* Extension: shutdown time. */
+ case SHUTDOWN_TIME:
+ break;
+ case USER_PROCESS:
+ UTOF_ID(ut, fu);
+ UTOF_STRING(ut, fu, user);
+ UTOF_STRING(ut, fu, line);
+ /* Extension: host name. */
+ UTOF_STRING(ut, fu, host);
+ UTOF_PID(ut, fu);
+ break;
+ case INIT_PROCESS:
+ UTOF_ID(ut, fu);
+ UTOF_PID(ut, fu);
+ break;
+ case LOGIN_PROCESS:
+ UTOF_ID(ut, fu);
+ UTOF_STRING(ut, fu, user);
+ UTOF_STRING(ut, fu, line);
+ UTOF_PID(ut, fu);
+ break;
+ case DEAD_PROCESS:
+ UTOF_ID(ut, fu);
+ UTOF_PID(ut, fu);
+ break;
+ default:
+ fu->fu_type = EMPTY;
+ return;
+ }
+
+ UTOF_TYPE(ut, fu);
+ UTOF_TV(fu);
+}
+
+#define FTOU_STRING(fu, ut, field) do { \
+ strncpy((ut)->ut_ ## field, (fu)->fu_ ## field, \
+ MIN(sizeof (ut)->ut_ ## field - 1, sizeof (fu)->fu_ ## field)); \
+} while (0)
+#define FTOU_ID(fu, ut) do { \
+ memcpy((ut)->ut_id, (fu)->fu_id, \
+ MIN(sizeof (ut)->ut_id, sizeof (fu)->fu_id)); \
+} while (0)
+#define FTOU_PID(fu, ut) do { \
+ (ut)->ut_pid = be32toh((fu)->fu_pid); \
+} while (0)
+#define FTOU_TYPE(fu, ut) do { \
+ (ut)->ut_type = (fu)->fu_type; \
+} while (0)
+#define FTOU_TV(fu, ut) do { \
+ uint64_t t; \
+ t = be64toh((fu)->fu_tv); \
+ (ut)->ut_tv.tv_sec = t / 1000000; \
+ (ut)->ut_tv.tv_usec = t % 1000000; \
+} while (0)
+
+struct utmpx *
+futx_to_utx(const struct futx *fu)
+{
+#ifdef __NO_TLS
+ static struct utmpx *ut;
+#else
+ static _Thread_local struct utmpx *ut;
+#endif
+
+ if (ut == NULL) {
+ ut = calloc(1, sizeof *ut);
+ if (ut == NULL)
+ return (NULL);
+ } else
+ memset(ut, 0, sizeof *ut);
+
+ switch (fu->fu_type) {
+ case BOOT_TIME:
+ case OLD_TIME:
+ case NEW_TIME:
+ /* Extension: shutdown time. */
+ case SHUTDOWN_TIME:
+ break;
+ case USER_PROCESS:
+ FTOU_ID(fu, ut);
+ FTOU_STRING(fu, ut, user);
+ FTOU_STRING(fu, ut, line);
+ /* Extension: host name. */
+ FTOU_STRING(fu, ut, host);
+ FTOU_PID(fu, ut);
+ break;
+ case INIT_PROCESS:
+ FTOU_ID(fu, ut);
+ FTOU_PID(fu, ut);
+ break;
+ case LOGIN_PROCESS:
+ FTOU_ID(fu, ut);
+ FTOU_STRING(fu, ut, user);
+ FTOU_STRING(fu, ut, line);
+ FTOU_PID(fu, ut);
+ break;
+ case DEAD_PROCESS:
+ FTOU_ID(fu, ut);
+ FTOU_PID(fu, ut);
+ break;
+ default:
+ ut->ut_type = EMPTY;
+ return (ut);
+ }
+
+ FTOU_TYPE(fu, ut);
+ FTOU_TV(fu, ut);
+ return (ut);
+}
diff --git a/lib/libc/gen/utxdb.h b/lib/libc/gen/utxdb.h
new file mode 100644
index 000000000000..d9ebc93e73f2
--- /dev/null
+++ b/lib/libc/gen/utxdb.h
@@ -0,0 +1,61 @@
+/*-
+ * Copyright (c) 2010 Ed Schouten <ed@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _UTXDB_H_
+#define _UTXDB_H_
+
+#include <stdint.h>
+
+#define _PATH_UTX_ACTIVE "/var/run/utx.active"
+#define _PATH_UTX_LASTLOGIN "/var/log/utx.lastlogin"
+#define _PATH_UTX_LOG "/var/log/utx.log"
+
+/*
+ * Entries in struct futx are ordered by how often they are used. In
+ * utx.log only entries will be written until the last non-zero byte,
+ * which means we want to put the hostname at the end. Most primitive
+ * records only store a ut_type and ut_tv, which means we want to store
+ * those at the front.
+ */
+
+struct utmpx;
+
+struct futx {
+ uint8_t fu_type;
+ uint64_t fu_tv;
+ char fu_id[8];
+ uint32_t fu_pid;
+ char fu_user[32];
+ char fu_line[16];
+ char fu_host[128];
+} __packed;
+
+void utx_to_futx(const struct utmpx *, struct futx *);
+struct utmpx *futx_to_utx(const struct futx *);
+
+#endif /* !_UTXDB_H_ */
diff --git a/lib/libc/gen/valloc.3 b/lib/libc/gen/valloc.3
new file mode 100644
index 000000000000..610ca1cd879b
--- /dev/null
+++ b/lib/libc/gen/valloc.3
@@ -0,0 +1,75 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)valloc.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd October 30, 2007
+.Dt VALLOC 3
+.Os
+.Sh NAME
+.Nm valloc
+.Nd aligned memory allocation function
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft void *
+.Fn valloc "size_t size"
+.Sh DESCRIPTION
+The
+.Fn valloc
+function is obsoleted by
+.Xr posix_memalign 3 ,
+which can be used to request page-aligned allocations.
+.Pp
+The
+.Fn valloc
+function
+allocates
+.Fa size
+bytes aligned on a page boundary.
+.Sh RETURN VALUES
+The
+.Fn valloc
+function returns
+a pointer to the allocated space if successful; otherwise
+a null pointer is returned.
+.Sh SEE ALSO
+.Xr posix_memalign 3
+.Sh HISTORY
+The
+.Fn valloc
+function appeared in
+.Bx 3.0 .
+.Pp
+The
+.Fn valloc
+function correctly allocated memory that could be deallocated via
+.Fn free
+starting in
+.Fx 7.0 .
diff --git a/lib/libc/gen/valloc.c b/lib/libc/gen/valloc.c
new file mode 100644
index 000000000000..a5b0f75eb694
--- /dev/null
+++ b/lib/libc/gen/valloc.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)valloc.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdlib.h>
+#include <unistd.h>
+
+void *
+valloc(size_t i)
+{
+ void *ret;
+
+ if (posix_memalign(&ret, getpagesize(), i) != 0)
+ ret = NULL;
+
+ return ret;
+}
diff --git a/lib/libc/gen/wait.c b/lib/libc/gen/wait.c
new file mode 100644
index 000000000000..7cede6e321b3
--- /dev/null
+++ b/lib/libc/gen/wait.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)wait.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <sys/resource.h>
+#include "un-namespace.h"
+
+#include "libc_private.h"
+
+pid_t __wait(int *);
+
+pid_t
+__wait(int *istat)
+{
+
+ return (((pid_t (*)(pid_t, int *, int, struct rusage *))
+ __libc_interposing[INTERPOS_wait4])(WAIT_ANY, istat, 0, NULL));
+}
+
+__weak_reference(__wait, wait);
+__weak_reference(__wait, _wait);
diff --git a/lib/libc/gen/wait3.c b/lib/libc/gen/wait3.c
new file mode 100644
index 000000000000..b50e3dd14b50
--- /dev/null
+++ b/lib/libc/gen/wait3.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)wait3.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <sys/resource.h>
+#include "un-namespace.h"
+
+#include "libc_private.h"
+
+pid_t __wait3(int *, int, struct rusage *);
+
+pid_t
+__wait3(int *istat, int options, struct rusage *rup)
+{
+
+ return (((pid_t (*)(pid_t, int *, int, struct rusage *))
+ __libc_interposing[INTERPOS_wait4])(WAIT_ANY, istat, options, rup));
+}
+
+__weak_reference(__wait3, wait3);
diff --git a/lib/libc/gen/waitid.c b/lib/libc/gen/waitid.c
new file mode 100644
index 000000000000..8bdd6521aa31
--- /dev/null
+++ b/lib/libc/gen/waitid.c
@@ -0,0 +1,70 @@
+/*-
+ * Copyright (c) 2012 Jukka A. Ukkonen
+ * All rights reserved.
+ *
+ * This software was developed by Jukka Ukkonen for FreeBSD.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <stddef.h>
+#include <string.h>
+#include <signal.h>
+#include <errno.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+
+int __waitid(idtype_t, id_t, siginfo_t *, int);
+
+int
+__waitid(idtype_t idtype, id_t id, siginfo_t *info, int flags)
+{
+ int status;
+ pid_t ret;
+
+ ret = ((pid_t (*)(idtype_t, id_t, int *, int, struct __wrusage *,
+ siginfo_t *))__libc_interposing[INTERPOS_wait6])(idtype, id,
+ &status, flags, NULL, info);
+
+ /*
+ * According to SUSv4, waitid() shall not return a PID when a
+ * process is found, but only 0. If a process was actually
+ * found, siginfo_t fields si_signo and si_pid will be
+ * non-zero. In case WNOHANG was set in the flags and no
+ * process was found those fields are set to zero using
+ * memset() below.
+ */
+ if (ret == 0 && info != NULL)
+ memset(info, 0, sizeof(*info));
+ else if (ret > 0)
+ ret = 0;
+ return (ret);
+}
+
+__weak_reference(__waitid, waitid);
+__weak_reference(__waitid, _waitid);
diff --git a/lib/libc/gen/waitpid.c b/lib/libc/gen/waitpid.c
new file mode 100644
index 000000000000..5dc4fa820ea2
--- /dev/null
+++ b/lib/libc/gen/waitpid.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)waitpid.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <sys/resource.h>
+#include "un-namespace.h"
+
+#include "libc_private.h"
+
+pid_t __waitpid(pid_t, int *, int);
+
+pid_t
+__waitpid(pid_t pid, int *istat, int options)
+{
+
+ return (((pid_t (*)(pid_t, int *, int, struct rusage *))
+ __libc_interposing[INTERPOS_wait4])(pid, istat, options, NULL));
+}
+
+__weak_reference(__waitpid, waitpid);
+__weak_reference(__waitpid, _waitpid);
diff --git a/lib/libc/gen/wordexp.3 b/lib/libc/gen/wordexp.3
new file mode 100644
index 000000000000..dd4605ffa6fd
--- /dev/null
+++ b/lib/libc/gen/wordexp.3
@@ -0,0 +1,210 @@
+.\"
+.\" Copyright (c) 2002 Tim J. Robbins
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd September 30, 2015
+.Dt WORDEXP 3
+.Os
+.Sh NAME
+.Nm wordexp
+.Nd "perform shell-style word expansions"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In wordexp.h
+.Ft int
+.Fn wordexp "const char * restrict words" "wordexp_t * restrict we" "int flags"
+.Ft void
+.Fn wordfree "wordexp_t *we"
+.Sh DESCRIPTION
+The
+.Fn wordexp
+function performs shell-style word expansion on
+.Fa words
+and places the list of words into the
+.Va we_wordv
+member of
+.Fa we ,
+and the number of words into
+.Va we_wordc .
+.Pp
+The
+.Fa flags
+argument is the bitwise inclusive OR of any of the following constants:
+.Bl -tag -width ".Dv WRDE_SHOWERR"
+.It Dv WRDE_APPEND
+Append the words to those generated by a previous call to
+.Fn wordexp .
+.It Dv WRDE_DOOFFS
+As many
+.Dv NULL
+pointers as are specified by the
+.Va we_offs
+member of
+.Fa we
+are added to the front of
+.Va we_wordv .
+.It Dv WRDE_NOCMD
+Disallow command substitution in
+.Fa words .
+See the note in
+.Sx BUGS
+before using this.
+.It Dv WRDE_REUSE
+The
+.Fa we
+argument was passed to a previous successful call to
+.Fn wordexp
+but has not been passed to
+.Fn wordfree .
+The implementation may reuse the space allocated to it.
+.It Dv WRDE_SHOWERR
+Do not redirect shell error messages to
+.Pa /dev/null .
+.It Dv WRDE_UNDEF
+Report error on an attempt to expand an undefined shell variable.
+.El
+.Pp
+The
+.Vt wordexp_t
+structure is defined in
+.In wordexp.h
+as:
+.Bd -literal -offset indent
+typedef struct {
+ size_t we_wordc; /* count of words matched */
+ char **we_wordv; /* pointer to list of words */
+ size_t we_offs; /* slots to reserve in we_wordv */
+} wordexp_t;
+.Ed
+.Pp
+The
+.Fn wordfree
+function frees the memory allocated by
+.Fn wordexp .
+.Sh IMPLEMENTATION NOTES
+The
+.Fn wordexp
+function is implemented using the undocumented
+.Ic freebsd_wordexp
+shell built-in command.
+.Sh RETURN VALUES
+The
+.Fn wordexp
+function returns zero if successful, otherwise it returns one of the following
+error codes:
+.Bl -tag -width ".Dv WRDE_NOSPACE"
+.It Dv WRDE_BADCHAR
+The
+.Fa words
+argument contains one of the following unquoted characters:
+.Aq newline ,
+.Ql | ,
+.Ql & ,
+.Ql \&; ,
+.Ql < ,
+.Ql > ,
+.Ql \&( ,
+.Ql \&) ,
+.Ql { ,
+.Ql } .
+.It Dv WRDE_BADVAL
+An error after successful parsing,
+such as an attempt to expand an undefined shell variable with
+.Dv WRDE_UNDEF
+set in
+.Fa flags .
+.It Dv WRDE_CMDSUB
+An attempt was made to use command substitution and
+.Dv WRDE_NOCMD
+is set in
+.Fa flags .
+.It Dv WRDE_NOSPACE
+Not enough memory to store the result or
+an error during
+.Xr fork 2 .
+.It Dv WRDE_SYNTAX
+Shell syntax error in
+.Fa words .
+.El
+.Pp
+The
+.Fn wordfree
+function returns no value.
+.Sh ENVIRONMENT
+.Bl -tag -width ".Ev IFS"
+.It Ev IFS
+Field separator.
+.El
+.Sh EXAMPLES
+Invoke the editor on all
+.Pa .c
+files in the current directory
+and
+.Pa /etc/motd
+(error checking omitted):
+.Bd -literal -offset indent
+wordexp_t we;
+
+wordexp("${EDITOR:-vi} *.c /etc/motd", &we, 0);
+execvp(we.we_wordv[0], we.we_wordv);
+.Ed
+.Sh DIAGNOSTICS
+Diagnostic messages from the shell are written to the standard error output
+if
+.Dv WRDE_SHOWERR
+is set in
+.Fa flags .
+.Sh SEE ALSO
+.Xr sh 1 ,
+.Xr fnmatch 3 ,
+.Xr glob 3 ,
+.Xr popen 3 ,
+.Xr system 3
+.Sh STANDARDS
+The
+.Fn wordexp
+and
+.Fn wordfree
+functions conform to
+.St -p1003.1-2001 .
+.Sh BUGS
+The current
+.Fn wordexp
+implementation does not recognize multibyte characters other than UTF-8, since
+the shell (which it invokes to perform expansions) does not.
+.Sh SECURITY CONSIDERATIONS
+Pathname generation may create output that is exponentially larger than the
+input size.
+.Pp
+Although this implementation detects command substitution reliably for
+.Dv WRDE_NOCMD ,
+the attack surface remains fairly large.
+Also, some other implementations
+(such as older versions of this one)
+may execute command substitutions even if
+.Dv WRDE_NOCMD
+is set.
diff --git a/lib/libc/gen/wordexp.c b/lib/libc/gen/wordexp.c
new file mode 100644
index 000000000000..3791e1e05b19
--- /dev/null
+++ b/lib/libc/gen/wordexp.c
@@ -0,0 +1,410 @@
+/*-
+ * Copyright (c) 2002 Tim J. Robbins.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "namespace.h"
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <wordexp.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+
+__FBSDID("$FreeBSD$");
+
+static int we_askshell(const char *, wordexp_t *, int);
+static int we_check(const char *);
+
+/*
+ * wordexp --
+ * Perform shell word expansion on `words' and place the resulting list
+ * of words in `we'. See wordexp(3).
+ *
+ * Specified by IEEE Std. 1003.1-2001.
+ */
+int
+wordexp(const char * __restrict words, wordexp_t * __restrict we, int flags)
+{
+ int error;
+
+ if (flags & WRDE_REUSE)
+ wordfree(we);
+ if ((flags & WRDE_APPEND) == 0) {
+ we->we_wordc = 0;
+ we->we_wordv = NULL;
+ we->we_strings = NULL;
+ we->we_nbytes = 0;
+ }
+ if ((error = we_check(words)) != 0) {
+ wordfree(we);
+ return (error);
+ }
+ if ((error = we_askshell(words, we, flags)) != 0) {
+ wordfree(we);
+ return (error);
+ }
+ return (0);
+}
+
+static size_t
+we_read_fully(int fd, char *buffer, size_t len)
+{
+ size_t done;
+ ssize_t nread;
+
+ done = 0;
+ do {
+ nread = _read(fd, buffer + done, len - done);
+ if (nread == -1 && errno == EINTR)
+ continue;
+ if (nread <= 0)
+ break;
+ done += nread;
+ } while (done != len);
+ return done;
+}
+
+static bool
+we_write_fully(int fd, const char *buffer, size_t len)
+{
+ size_t done;
+ ssize_t nwritten;
+
+ done = 0;
+ do {
+ nwritten = _write(fd, buffer + done, len - done);
+ if (nwritten == -1 && errno == EINTR)
+ continue;
+ if (nwritten <= 0)
+ return (false);
+ done += nwritten;
+ } while (done != len);
+ return (true);
+}
+
+/*
+ * we_askshell --
+ * Use the `freebsd_wordexp' /bin/sh builtin function to do most of the
+ * work in expanding the word string. This function is complicated by
+ * memory management.
+ */
+static int
+we_askshell(const char *words, wordexp_t *we, int flags)
+{
+ int pdesw[2]; /* Pipe for writing words */
+ int pdes[2]; /* Pipe for reading output */
+ char wfdstr[sizeof(int) * 3 + 1];
+ char buf[35]; /* Buffer for byte and word count */
+ long nwords, nbytes; /* Number of words, bytes from child */
+ long i; /* Handy integer */
+ size_t sofs; /* Offset into we->we_strings */
+ size_t vofs; /* Offset into we->we_wordv */
+ pid_t pid; /* Process ID of child */
+ pid_t wpid; /* waitpid return value */
+ int status; /* Child exit status */
+ int error; /* Our return value */
+ int serrno; /* errno to return */
+ char *np, *p; /* Handy pointers */
+ char *nstrings; /* Temporary for realloc() */
+ char **nwv; /* Temporary for realloc() */
+ sigset_t newsigblock, oldsigblock;
+ const char *ifs;
+
+ serrno = errno;
+ ifs = getenv("IFS");
+
+ if (pipe2(pdesw, O_CLOEXEC) < 0)
+ return (WRDE_NOSPACE); /* XXX */
+ snprintf(wfdstr, sizeof(wfdstr), "%d", pdesw[0]);
+ if (pipe2(pdes, O_CLOEXEC) < 0) {
+ _close(pdesw[0]);
+ _close(pdesw[1]);
+ return (WRDE_NOSPACE); /* XXX */
+ }
+ (void)sigemptyset(&newsigblock);
+ (void)sigaddset(&newsigblock, SIGCHLD);
+ (void)__libc_sigprocmask(SIG_BLOCK, &newsigblock, &oldsigblock);
+ if ((pid = fork()) < 0) {
+ serrno = errno;
+ _close(pdesw[0]);
+ _close(pdesw[1]);
+ _close(pdes[0]);
+ _close(pdes[1]);
+ (void)__libc_sigprocmask(SIG_SETMASK, &oldsigblock, NULL);
+ errno = serrno;
+ return (WRDE_NOSPACE); /* XXX */
+ }
+ else if (pid == 0) {
+ /*
+ * We are the child; make /bin/sh expand `words'.
+ */
+ (void)__libc_sigprocmask(SIG_SETMASK, &oldsigblock, NULL);
+ if ((pdes[1] != STDOUT_FILENO ?
+ _dup2(pdes[1], STDOUT_FILENO) :
+ _fcntl(pdes[1], F_SETFD, 0)) < 0)
+ _exit(1);
+ if (_fcntl(pdesw[0], F_SETFD, 0) < 0)
+ _exit(1);
+ execl(_PATH_BSHELL, "sh", flags & WRDE_UNDEF ? "-u" : "+u",
+ "-c", "IFS=$1;eval \"$2\";"
+ "freebsd_wordexp -f \"$3\" ${4:+\"$4\"}",
+ "",
+ ifs != NULL ? ifs : " \t\n",
+ flags & WRDE_SHOWERR ? "" : "exec 2>/dev/null",
+ wfdstr,
+ flags & WRDE_NOCMD ? "-p" : "",
+ (char *)NULL);
+ _exit(1);
+ }
+
+ /*
+ * We are the parent; write the words.
+ */
+ _close(pdes[1]);
+ _close(pdesw[0]);
+ if (!we_write_fully(pdesw[1], words, strlen(words))) {
+ _close(pdesw[1]);
+ error = WRDE_SYNTAX;
+ goto cleanup;
+ }
+ _close(pdesw[1]);
+ /*
+ * Read the output of the shell wordexp function,
+ * which is a byte indicating that the words were parsed successfully,
+ * a 64-bit hexadecimal word count, a dummy byte, a 64-bit hexadecimal
+ * byte count (not including terminating null bytes), followed by the
+ * expanded words separated by nulls.
+ */
+ switch (we_read_fully(pdes[0], buf, 34)) {
+ case 1:
+ error = buf[0] == 'C' ? WRDE_CMDSUB : WRDE_BADVAL;
+ serrno = errno;
+ goto cleanup;
+ case 34:
+ break;
+ default:
+ error = WRDE_SYNTAX;
+ serrno = errno;
+ goto cleanup;
+ }
+ buf[17] = '\0';
+ nwords = strtol(buf + 1, NULL, 16);
+ buf[34] = '\0';
+ nbytes = strtol(buf + 18, NULL, 16) + nwords;
+
+ /*
+ * Allocate or reallocate (when flags & WRDE_APPEND) the word vector
+ * and string storage buffers for the expanded words we're about to
+ * read from the child.
+ */
+ sofs = we->we_nbytes;
+ vofs = we->we_wordc;
+ if ((flags & (WRDE_DOOFFS|WRDE_APPEND)) == (WRDE_DOOFFS|WRDE_APPEND))
+ vofs += we->we_offs;
+ we->we_wordc += nwords;
+ we->we_nbytes += nbytes;
+ if ((nwv = realloc(we->we_wordv, (we->we_wordc + 1 +
+ (flags & WRDE_DOOFFS ? we->we_offs : 0)) *
+ sizeof(char *))) == NULL) {
+ error = WRDE_NOSPACE;
+ goto cleanup;
+ }
+ we->we_wordv = nwv;
+ if ((nstrings = realloc(we->we_strings, we->we_nbytes)) == NULL) {
+ error = WRDE_NOSPACE;
+ goto cleanup;
+ }
+ for (i = 0; i < vofs; i++)
+ if (we->we_wordv[i] != NULL)
+ we->we_wordv[i] += nstrings - we->we_strings;
+ we->we_strings = nstrings;
+
+ if (we_read_fully(pdes[0], we->we_strings + sofs, nbytes) != nbytes) {
+ error = WRDE_NOSPACE; /* abort for unknown reason */
+ serrno = errno;
+ goto cleanup;
+ }
+
+ error = 0;
+cleanup:
+ _close(pdes[0]);
+ do
+ wpid = _waitpid(pid, &status, 0);
+ while (wpid < 0 && errno == EINTR);
+ (void)__libc_sigprocmask(SIG_SETMASK, &oldsigblock, NULL);
+ if (error != 0) {
+ errno = serrno;
+ return (error);
+ }
+ if (wpid < 0 || !WIFEXITED(status) || WEXITSTATUS(status) != 0)
+ return (WRDE_NOSPACE); /* abort for unknown reason */
+
+ /*
+ * Break the null-terminated expanded word strings out into
+ * the vector.
+ */
+ if (vofs == 0 && flags & WRDE_DOOFFS)
+ while (vofs < we->we_offs)
+ we->we_wordv[vofs++] = NULL;
+ p = we->we_strings + sofs;
+ while (nwords-- != 0) {
+ we->we_wordv[vofs++] = p;
+ if ((np = memchr(p, '\0', nbytes)) == NULL)
+ return (WRDE_NOSPACE); /* XXX */
+ nbytes -= np - p + 1;
+ p = np + 1;
+ }
+ we->we_wordv[vofs] = NULL;
+
+ return (0);
+}
+
+/*
+ * we_check --
+ * Check that the string contains none of the following unquoted
+ * special characters: <newline> |&;<>(){}
+ * This mainly serves for {} which are normally legal in sh.
+ * It deliberately does not attempt to model full sh syntax.
+ */
+static int
+we_check(const char *words)
+{
+ char c;
+ /* Saw \ or $, possibly not special: */
+ bool quote = false, dollar = false;
+ /* Saw ', ", ${, ` or $(, possibly not special: */
+ bool have_sq = false, have_dq = false, have_par_begin = false;
+ bool have_cmd = false;
+ /* Definitely saw a ', ", ${, ` or $(, need a closing character: */
+ bool need_sq = false, need_dq = false, need_par_end = false;
+ bool need_cmd_old = false, need_cmd_new = false;
+
+ while ((c = *words++) != '\0') {
+ switch (c) {
+ case '\\':
+ quote = !quote;
+ continue;
+ case '$':
+ if (quote)
+ quote = false;
+ else
+ dollar = !dollar;
+ continue;
+ case '\'':
+ if (!quote && !have_sq && !have_dq)
+ need_sq = true;
+ else
+ need_sq = false;
+ have_sq = true;
+ break;
+ case '"':
+ if (!quote && !have_sq && !have_dq)
+ need_dq = true;
+ else
+ need_dq = false;
+ have_dq = true;
+ break;
+ case '`':
+ if (!quote && !have_sq && !have_cmd)
+ need_cmd_old = true;
+ else
+ need_cmd_old = false;
+ have_cmd = true;
+ break;
+ case '{':
+ if (!quote && !dollar && !have_sq && !have_dq &&
+ !have_cmd)
+ return (WRDE_BADCHAR);
+ if (dollar) {
+ if (!quote && !have_sq)
+ need_par_end = true;
+ have_par_begin = true;
+ }
+ break;
+ case '}':
+ if (!quote && !have_sq && !have_dq && !have_par_begin &&
+ !have_cmd)
+ return (WRDE_BADCHAR);
+ need_par_end = false;
+ break;
+ case '(':
+ if (!quote && !dollar && !have_sq && !have_dq &&
+ !have_cmd)
+ return (WRDE_BADCHAR);
+ if (dollar) {
+ if (!quote && !have_sq)
+ need_cmd_new = true;
+ have_cmd = true;
+ }
+ break;
+ case ')':
+ if (!quote && !have_sq && !have_dq && !have_cmd)
+ return (WRDE_BADCHAR);
+ need_cmd_new = false;
+ break;
+ case '|': case '&': case ';': case '<': case '>': case '\n':
+ if (!quote && !have_sq && !have_dq && !have_cmd)
+ return (WRDE_BADCHAR);
+ break;
+ default:
+ break;
+ }
+ quote = dollar = false;
+ }
+ if (quote || dollar || need_sq || need_dq || need_par_end ||
+ need_cmd_old || need_cmd_new)
+ return (WRDE_SYNTAX);
+
+ return (0);
+}
+
+/*
+ * wordfree --
+ * Free the result of wordexp(). See wordexp(3).
+ *
+ * Specified by IEEE Std. 1003.1-2001.
+ */
+void
+wordfree(wordexp_t *we)
+{
+
+ if (we == NULL)
+ return;
+ free(we->we_wordv);
+ free(we->we_strings);
+ we->we_wordv = NULL;
+ we->we_strings = NULL;
+ we->we_nbytes = 0;
+ we->we_wordc = 0;
+}
diff --git a/lib/libc/gmon/Makefile.inc b/lib/libc/gmon/Makefile.inc
new file mode 100644
index 000000000000..3e3dede8a45e
--- /dev/null
+++ b/lib/libc/gmon/Makefile.inc
@@ -0,0 +1,17 @@
+# from @(#)Makefile.inc 8.1 (Berkeley) 6/4/93
+# $FreeBSD$
+
+# gmon sources
+.PATH: ${LIBC_SRCTOP}/gmon
+
+SRCS+= gmon.c mcount.c
+
+SYM_MAPS+=${LIBC_SRCTOP}/gmon/Symbol.map
+
+MAN+= moncontrol.3
+
+MLINKS+=moncontrol.3 monstartup.3
+
+# mcount cannot be compiled with profiling
+mcount.po: mcount.o
+ cp mcount.o mcount.po
diff --git a/lib/libc/gmon/Symbol.map b/lib/libc/gmon/Symbol.map
new file mode 100644
index 000000000000..822789972ebf
--- /dev/null
+++ b/lib/libc/gmon/Symbol.map
@@ -0,0 +1,14 @@
+/*
+ * $FreeBSD$
+ */
+
+FBSD_1.0 {
+ _mcleanup;
+ monstartup;
+ moncontrol;
+ mexitcount;
+};
+
+FBSDprivate_1.0 {
+ _gmonparam;
+};
diff --git a/lib/libc/gmon/gmon.c b/lib/libc/gmon/gmon.c
new file mode 100644
index 000000000000..6ca8f79267b6
--- /dev/null
+++ b/lib/libc/gmon/gmon.c
@@ -0,0 +1,246 @@
+/*-
+ * Copyright (c) 1983, 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)gmon.c 8.1 (Berkeley) 6/4/93";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/gmon.h>
+#include <sys/mman.h>
+#include <sys/sysctl.h>
+
+#include <err.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+#include "libc_private.h"
+
+struct gmonparam _gmonparam = { GMON_PROF_OFF };
+
+static int s_scale;
+/* See profil(2) where this is described (incorrectly). */
+#define SCALE_SHIFT 16
+
+#define ERR(s) _write(2, s, sizeof(s))
+
+void moncontrol(int);
+static int hertz(void);
+void _mcleanup(void);
+
+void
+monstartup(u_long lowpc, u_long highpc)
+{
+ int o;
+ char *cp;
+ struct gmonparam *p = &_gmonparam;
+
+ /*
+ * round lowpc and highpc to multiples of the density we're using
+ * so the rest of the scaling (here and in gprof) stays in ints.
+ */
+ p->lowpc = ROUNDDOWN(lowpc, HISTFRACTION * sizeof(HISTCOUNTER));
+ p->highpc = ROUNDUP(highpc, HISTFRACTION * sizeof(HISTCOUNTER));
+ p->textsize = p->highpc - p->lowpc;
+ p->kcountsize = p->textsize / HISTFRACTION;
+ p->hashfraction = HASHFRACTION;
+ p->fromssize = p->textsize / HASHFRACTION;
+ p->tolimit = p->textsize * ARCDENSITY / 100;
+ if (p->tolimit < MINARCS)
+ p->tolimit = MINARCS;
+ else if (p->tolimit > MAXARCS)
+ p->tolimit = MAXARCS;
+ p->tossize = p->tolimit * sizeof(struct tostruct);
+
+ cp = mmap(NULL, p->kcountsize + p->fromssize + p->tossize,
+ PROT_READ | PROT_WRITE, MAP_ANON, -1, 0);
+ if (cp == MAP_FAILED) {
+ ERR("monstartup: out of memory\n");
+ return;
+ }
+#ifdef notdef
+ bzero(cp, p->kcountsize + p->fromssize + p->tossize);
+#endif
+ p->tos = (struct tostruct *)cp;
+ cp += p->tossize;
+ p->kcount = (u_short *)cp;
+ cp += p->kcountsize;
+ p->froms = (u_short *)cp;
+
+ p->tos[0].link = 0;
+
+ o = p->highpc - p->lowpc;
+ s_scale = (p->kcountsize < o) ?
+ ((uintmax_t)p->kcountsize << SCALE_SHIFT) / o : (1 << SCALE_SHIFT);
+ moncontrol(1);
+}
+
+void
+_mcleanup(void)
+{
+ int fd;
+ int fromindex;
+ int endfrom;
+ u_long frompc;
+ int toindex;
+ struct rawarc rawarc;
+ struct gmonparam *p = &_gmonparam;
+ struct gmonhdr gmonhdr, *hdr;
+ struct clockinfo clockinfo;
+ char outname[128];
+ int mib[2];
+ size_t size;
+#ifdef DEBUG
+ int log, len;
+ char buf[200];
+#endif
+
+ if (p->state == GMON_PROF_ERROR)
+ ERR("_mcleanup: tos overflow\n");
+
+ size = sizeof(clockinfo);
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_CLOCKRATE;
+ if (sysctl(mib, 2, &clockinfo, &size, NULL, 0) < 0) {
+ /*
+ * Best guess
+ */
+ clockinfo.profhz = hertz();
+ } else if (clockinfo.profhz == 0) {
+ if (clockinfo.hz != 0)
+ clockinfo.profhz = clockinfo.hz;
+ else
+ clockinfo.profhz = hertz();
+ }
+
+ moncontrol(0);
+ if (getenv("PROFIL_USE_PID"))
+ snprintf(outname, sizeof(outname), "%s.%d.gmon",
+ _getprogname(), getpid());
+ else
+ snprintf(outname, sizeof(outname), "%s.gmon", _getprogname());
+
+ fd = _open(outname, O_CREAT|O_TRUNC|O_WRONLY|O_CLOEXEC, 0666);
+ if (fd < 0) {
+ _warn("_mcleanup: %s", outname);
+ return;
+ }
+#ifdef DEBUG
+ log = _open("gmon.log", O_CREAT|O_TRUNC|O_WRONLY|O_CLOEXEC, 0664);
+ if (log < 0) {
+ _warn("_mcleanup: gmon.log");
+ return;
+ }
+ len = sprintf(buf, "[mcleanup1] kcount 0x%p ssiz %lu\n",
+ p->kcount, p->kcountsize);
+ _write(log, buf, len);
+#endif
+ hdr = (struct gmonhdr *)&gmonhdr;
+ bzero(hdr, sizeof(*hdr));
+ hdr->lpc = p->lowpc;
+ hdr->hpc = p->highpc;
+ hdr->ncnt = p->kcountsize + sizeof(gmonhdr);
+ hdr->version = GMONVERSION;
+ hdr->profrate = clockinfo.profhz;
+ _write(fd, (char *)hdr, sizeof *hdr);
+ _write(fd, p->kcount, p->kcountsize);
+ endfrom = p->fromssize / sizeof(*p->froms);
+ for (fromindex = 0; fromindex < endfrom; fromindex++) {
+ if (p->froms[fromindex] == 0)
+ continue;
+
+ frompc = p->lowpc;
+ frompc += fromindex * p->hashfraction * sizeof(*p->froms);
+ for (toindex = p->froms[fromindex]; toindex != 0;
+ toindex = p->tos[toindex].link) {
+#ifdef DEBUG
+ len = sprintf(buf,
+ "[mcleanup2] frompc 0x%lx selfpc 0x%lx count %lu\n" ,
+ frompc, p->tos[toindex].selfpc,
+ p->tos[toindex].count);
+ _write(log, buf, len);
+#endif
+ rawarc.raw_frompc = frompc;
+ rawarc.raw_selfpc = p->tos[toindex].selfpc;
+ rawarc.raw_count = p->tos[toindex].count;
+ _write(fd, &rawarc, sizeof rawarc);
+ }
+ }
+ _close(fd);
+}
+
+/*
+ * Control profiling
+ * profiling is what mcount checks to see if
+ * all the data structures are ready.
+ */
+void
+moncontrol(int mode)
+{
+ struct gmonparam *p = &_gmonparam;
+
+ if (mode) {
+ /* start */
+ profil((char *)p->kcount, p->kcountsize, p->lowpc, s_scale);
+ p->state = GMON_PROF_ON;
+ } else {
+ /* stop */
+ profil((char *)0, 0, 0, 0);
+ p->state = GMON_PROF_OFF;
+ }
+}
+
+/*
+ * discover the tick frequency of the machine
+ * if something goes wrong, we return 0, an impossible hertz.
+ */
+static int
+hertz(void)
+{
+ struct itimerval tim;
+
+ tim.it_interval.tv_sec = 0;
+ tim.it_interval.tv_usec = 1;
+ tim.it_value.tv_sec = 0;
+ tim.it_value.tv_usec = 0;
+ setitimer(ITIMER_REAL, &tim, 0);
+ setitimer(ITIMER_REAL, 0, &tim);
+ if (tim.it_interval.tv_usec < 2)
+ return(0);
+ return (1000000 / tim.it_interval.tv_usec);
+}
diff --git a/lib/libc/gmon/mcount.c b/lib/libc/gmon/mcount.c
new file mode 100644
index 000000000000..02f3efd84b3d
--- /dev/null
+++ b/lib/libc/gmon/mcount.c
@@ -0,0 +1,321 @@
+/*-
+ * Copyright (c) 1983, 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if !defined(_KERNEL) && defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)mcount.c 8.1 (Berkeley) 6/4/93";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/gmon.h>
+#ifdef _KERNEL
+#include <sys/systm.h>
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/pmap.h>
+void bintr(void);
+void btrap(void);
+void eintr(void);
+void user(void);
+#endif
+#include <machine/atomic.h>
+
+/*
+ * mcount is called on entry to each function compiled with the profiling
+ * switch set. _mcount(), which is declared in a machine-dependent way
+ * with _MCOUNT_DECL, does the actual work and is either inlined into a
+ * C routine or called by an assembly stub. In any case, this magic is
+ * taken care of by the MCOUNT definition in <machine/profile.h>.
+ *
+ * _mcount updates data structures that represent traversals of the
+ * program's call graph edges. frompc and selfpc are the return
+ * address and function address that represents the given call graph edge.
+ *
+ * Note: the original BSD code used the same variable (frompcindex) for
+ * both frompcindex and frompc. Any reasonable, modern compiler will
+ * perform this optimization.
+ */
+/* _mcount; may be static, inline, etc */
+_MCOUNT_DECL(uintfptr_t frompc, uintfptr_t selfpc)
+{
+#ifdef GUPROF
+ u_int delta;
+#endif
+ fptrdiff_t frompci;
+ u_short *frompcindex;
+ struct tostruct *top, *prevtop;
+ struct gmonparam *p;
+ long toindex;
+#ifdef _KERNEL
+ MCOUNT_DECL(s)
+#endif
+
+ p = &_gmonparam;
+#ifndef GUPROF /* XXX */
+ /*
+ * check that we are profiling
+ * and that we aren't recursively invoked.
+ */
+ if (p->state != GMON_PROF_ON)
+ return;
+#endif
+#ifdef _KERNEL
+ MCOUNT_ENTER(s);
+#else
+ if (!atomic_cmpset_acq_int(&p->state, GMON_PROF_ON, GMON_PROF_BUSY))
+ return;
+#endif
+ frompci = frompc - p->lowpc;
+
+#ifdef _KERNEL
+ /*
+ * When we are called from an exception handler, frompci may be
+ * for a user address. Convert such frompci's to the index of
+ * user() to merge all user counts.
+ */
+ if (frompci >= p->textsize) {
+ if (frompci + p->lowpc
+ >= (uintfptr_t)(VM_MAXUSER_ADDRESS + UPAGES * PAGE_SIZE))
+ goto done;
+ frompci = (uintfptr_t)user - p->lowpc;
+ if (frompci >= p->textsize)
+ goto done;
+ }
+#endif
+
+#ifdef GUPROF
+ if (p->state != GMON_PROF_HIRES)
+ goto skip_guprof_stuff;
+ /*
+ * Look at the clock and add the count of clock cycles since the
+ * clock was last looked at to a counter for frompc. This
+ * solidifies the count for the function containing frompc and
+ * effectively starts another clock for the current function.
+ * The count for the new clock will be solidified when another
+ * function call is made or the function returns.
+ *
+ * We use the usual sampling counters since they can be located
+ * efficiently. 4-byte counters are usually necessary.
+ *
+ * There are many complications for subtracting the profiling
+ * overheads from the counts for normal functions and adding
+ * them to the counts for mcount(), mexitcount() and cputime().
+ * We attempt to handle fractional cycles, but the overheads
+ * are usually underestimated because they are calibrated for
+ * a simpler than usual setup.
+ */
+ delta = cputime() - p->mcount_overhead;
+ p->cputime_overhead_resid += p->cputime_overhead_frac;
+ p->mcount_overhead_resid += p->mcount_overhead_frac;
+ if ((int)delta < 0)
+ *p->mcount_count += delta + p->mcount_overhead
+ - p->cputime_overhead;
+ else if (delta != 0) {
+ if (p->cputime_overhead_resid >= CALIB_SCALE) {
+ p->cputime_overhead_resid -= CALIB_SCALE;
+ ++*p->cputime_count;
+ --delta;
+ }
+ if (delta != 0) {
+ if (p->mcount_overhead_resid >= CALIB_SCALE) {
+ p->mcount_overhead_resid -= CALIB_SCALE;
+ ++*p->mcount_count;
+ --delta;
+ }
+ KCOUNT(p, frompci) += delta;
+ }
+ *p->mcount_count += p->mcount_overhead_sub;
+ }
+ *p->cputime_count += p->cputime_overhead;
+skip_guprof_stuff:
+#endif /* GUPROF */
+
+#ifdef _KERNEL
+ /*
+ * When we are called from an exception handler, frompc is faked
+ * to be for where the exception occurred. We've just solidified
+ * the count for there. Now convert frompci to the index of btrap()
+ * for trap handlers and bintr() for interrupt handlers to make
+ * exceptions appear in the call graph as calls from btrap() and
+ * bintr() instead of calls from all over.
+ */
+ if ((uintfptr_t)selfpc >= (uintfptr_t)btrap
+ && (uintfptr_t)selfpc < (uintfptr_t)eintr) {
+ if ((uintfptr_t)selfpc >= (uintfptr_t)bintr)
+ frompci = (uintfptr_t)bintr - p->lowpc;
+ else
+ frompci = (uintfptr_t)btrap - p->lowpc;
+ }
+#endif
+
+ /*
+ * check that frompc is a reasonable pc value.
+ * for example: signal catchers get called from the stack,
+ * not from text space. too bad.
+ */
+ if (frompci >= p->textsize)
+ goto done;
+
+ frompcindex = &p->froms[frompci / (p->hashfraction * sizeof(*p->froms))];
+ toindex = *frompcindex;
+ if (toindex == 0) {
+ /*
+ * first time traversing this arc
+ */
+ toindex = ++p->tos[0].link;
+ if (toindex >= p->tolimit)
+ /* halt further profiling */
+ goto overflow;
+
+ *frompcindex = toindex;
+ top = &p->tos[toindex];
+ top->selfpc = selfpc;
+ top->count = 1;
+ top->link = 0;
+ goto done;
+ }
+ top = &p->tos[toindex];
+ if (top->selfpc == selfpc) {
+ /*
+ * arc at front of chain; usual case.
+ */
+ top->count++;
+ goto done;
+ }
+ /*
+ * have to go looking down chain for it.
+ * top points to what we are looking at,
+ * prevtop points to previous top.
+ * we know it is not at the head of the chain.
+ */
+ for (; /* goto done */; ) {
+ if (top->link == 0) {
+ /*
+ * top is end of the chain and none of the chain
+ * had top->selfpc == selfpc.
+ * so we allocate a new tostruct
+ * and link it to the head of the chain.
+ */
+ toindex = ++p->tos[0].link;
+ if (toindex >= p->tolimit)
+ goto overflow;
+
+ top = &p->tos[toindex];
+ top->selfpc = selfpc;
+ top->count = 1;
+ top->link = *frompcindex;
+ *frompcindex = toindex;
+ goto done;
+ }
+ /*
+ * otherwise, check the next arc on the chain.
+ */
+ prevtop = top;
+ top = &p->tos[top->link];
+ if (top->selfpc == selfpc) {
+ /*
+ * there it is.
+ * increment its count
+ * move it to the head of the chain.
+ */
+ top->count++;
+ toindex = prevtop->link;
+ prevtop->link = top->link;
+ top->link = *frompcindex;
+ *frompcindex = toindex;
+ goto done;
+ }
+
+ }
+done:
+#ifdef _KERNEL
+ MCOUNT_EXIT(s);
+#else
+ atomic_store_rel_int(&p->state, GMON_PROF_ON);
+#endif
+ return;
+overflow:
+ atomic_store_rel_int(&p->state, GMON_PROF_ERROR);
+#ifdef _KERNEL
+ MCOUNT_EXIT(s);
+#endif
+ return;
+}
+
+/*
+ * Actual definition of mcount function. Defined in <machine/profile.h>,
+ * which is included by <sys/gmon.h>.
+ */
+MCOUNT
+
+#ifdef GUPROF
+void
+mexitcount(selfpc)
+ uintfptr_t selfpc;
+{
+ struct gmonparam *p;
+ uintfptr_t selfpcdiff;
+
+ p = &_gmonparam;
+ selfpcdiff = selfpc - (uintfptr_t)p->lowpc;
+ if (selfpcdiff < p->textsize) {
+ u_int delta;
+
+ /*
+ * Solidify the count for the current function.
+ */
+ delta = cputime() - p->mexitcount_overhead;
+ p->cputime_overhead_resid += p->cputime_overhead_frac;
+ p->mexitcount_overhead_resid += p->mexitcount_overhead_frac;
+ if ((int)delta < 0)
+ *p->mexitcount_count += delta + p->mexitcount_overhead
+ - p->cputime_overhead;
+ else if (delta != 0) {
+ if (p->cputime_overhead_resid >= CALIB_SCALE) {
+ p->cputime_overhead_resid -= CALIB_SCALE;
+ ++*p->cputime_count;
+ --delta;
+ }
+ if (delta != 0) {
+ if (p->mexitcount_overhead_resid
+ >= CALIB_SCALE) {
+ p->mexitcount_overhead_resid
+ -= CALIB_SCALE;
+ ++*p->mexitcount_count;
+ --delta;
+ }
+ KCOUNT(p, selfpcdiff) += delta;
+ }
+ *p->mexitcount_count += p->mexitcount_overhead_sub;
+ }
+ *p->cputime_count += p->cputime_overhead;
+ }
+}
+#endif /* GUPROF */
diff --git a/lib/libc/gmon/moncontrol.3 b/lib/libc/gmon/moncontrol.3
new file mode 100644
index 000000000000..d63035a83d1b
--- /dev/null
+++ b/lib/libc/gmon/moncontrol.3
@@ -0,0 +1,117 @@
+.\" Copyright (c) 1980, 1991, 1992, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)moncontrol.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 14, 2004
+.Dt MONCONTROL 3
+.Os
+.Sh NAME
+.Nm moncontrol ,
+.Nm monstartup
+.Nd control execution profile
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/gmon.h
+.Ft void
+.Fn moncontrol "int mode"
+.Ft void
+.Fn monstartup "u_long lowpc" "u_long highpc"
+.Sh DESCRIPTION
+An executable program compiled using the
+.Fl pg
+option to
+.Xr cc 1
+automatically includes calls to collect statistics for the
+.Xr gprof 1
+call-graph execution profiler.
+In typical operation, profiling begins at program startup
+and ends when the program calls exit.
+When the program exits, the profiling data are written to the file
+.Ar progname Ns Pa .gmon ,
+where progname is the name of the program, then
+.Xr gprof 1
+can be used to examine the results.
+.Pp
+The
+.Fn moncontrol
+function
+selectively controls profiling within a program.
+When the program starts, profiling begins.
+To stop the collection of histogram ticks and call counts use
+.Fn moncontrol 0 ;
+to resume the collection of histogram ticks and call counts use
+.Fn moncontrol 1 .
+This feature allows the cost of particular operations to be measured.
+Note that an output file will be produced on program exit
+regardless of the state of
+.Fn moncontrol .
+.Pp
+Programs that are not loaded with
+.Fl pg
+may selectively collect profiling statistics by calling
+.Fn monstartup
+with the range of addresses to be profiled.
+The
+.Fa lowpc
+and
+.Fa highpc
+arguments
+specify the address range that is to be sampled;
+the lowest address sampled is that of
+.Fa lowpc
+and the highest is just below
+.Fa highpc .
+Only functions in that range that have been compiled with the
+.Fl pg
+option to
+.Xr cc 1
+will appear in the call graph part of the output;
+however, all functions in that address range will
+have their execution time measured.
+Profiling begins on return from
+.Fn monstartup .
+.Sh ENVIRONMENT
+The following environment variables affect the execution of
+.Nm :
+.Bl -tag -width ".Ev PROFIL_USE_PID"
+.It PROFIL_USE_PID
+If set, the pid of the process is inserted into the filename.
+.El
+.Sh FILES
+.Bl -tag -width progname.gmon -compact
+.It Pa progname.gmon
+execution data file
+.El
+.Sh SEE ALSO
+.Xr cc 1 ,
+.Xr gprof 1 ,
+.Xr profil 2 ,
+.Xr clocks 7
diff --git a/lib/libc/i386/Makefile.inc b/lib/libc/i386/Makefile.inc
new file mode 100644
index 000000000000..627311cbe46a
--- /dev/null
+++ b/lib/libc/i386/Makefile.inc
@@ -0,0 +1,6 @@
+# $FreeBSD$
+
+# Long double is 80 bits
+GDTOASRCS+=strtorx.c
+MDSRCS+=machdep_ldisx.c
+SYM_MAPS+=${LIBC_SRCTOP}/i386/Symbol.map
diff --git a/lib/libc/i386/SYS.h b/lib/libc/i386/SYS.h
new file mode 100644
index 000000000000..9a4856a4d3e2
--- /dev/null
+++ b/lib/libc/i386/SYS.h
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)SYS.h 5.5 (Berkeley) 5/7/91
+ * $FreeBSD$
+ */
+
+#include <sys/syscall.h>
+#include <machine/asm.h>
+
+#define SYSCALL(name) ENTRY(__sys_##name); \
+ WEAK_REFERENCE(__sys_##name, name); \
+ WEAK_REFERENCE(__sys_##name, _##name); \
+ mov $SYS_##name,%eax; KERNCALL; \
+ jb HIDENAME(cerror)
+
+#define RSYSCALL(name) SYSCALL(name); ret; END(__sys_##name)
+
+#define PSEUDO(name) ENTRY(__sys_##name); \
+ WEAK_REFERENCE(__sys_##name, _##name); \
+ mov $SYS_##name,%eax; KERNCALL; \
+ jb HIDENAME(cerror); ret; \
+ END(__sys_##name)
+
+/* gas messes up offset -- although we don't currently need it, do for BCS */
+#define LCALL(x,y) .byte 0x9a ; .long y; .word x
+
+#define KERNCALL int $0x80
diff --git a/lib/libc/i386/Symbol.map b/lib/libc/i386/Symbol.map
new file mode 100644
index 000000000000..20dbc3e9cfcd
--- /dev/null
+++ b/lib/libc/i386/Symbol.map
@@ -0,0 +1,67 @@
+/*
+ * $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, ...).
+ */
+FBSD_1.0 {
+ /* PSEUDO syscalls */
+ _exit;
+
+ .mcount;
+ _setjmp;
+ _longjmp;
+ alloca;
+ fabs;
+ __flt_rounds;
+ __nan;
+ __infinity;
+ makecontext;
+ rfork_thread;
+ setjmp;
+ longjmp;
+ sigsetjmp;
+ siglongjmp;
+ htonl;
+ htons;
+ ntohl;
+ ntohs;
+ vfork;
+ brk;
+ exect;
+ i386_clr_watch;
+ i386_get_fsbase;
+ i386_get_gsbase;
+ i386_get_ioperm;
+ i386_get_ldt;
+ i386_set_fsbase;
+ i386_set_gsbase;
+ i386_set_ioperm;
+ i386_set_ldt;
+ i386_set_watch;
+ i386_vm86;
+ sbrk;
+ ___tls_get_addr;
+};
+
+FBSDprivate_1.0 {
+ /* PSEUDO syscalls */
+ __sys_getlogin;
+ _getlogin;
+ __sys_exit;
+
+ _set_tp;
+ ___longjmp;
+ __makecontext;
+ __longjmp;
+ __signalcontext;
+ signalcontext;
+ __siglongjmp;
+ __sys_vfork;
+ _vfork;
+ _end;
+ _brk;
+};
diff --git a/lib/libc/i386/_fpmath.h b/lib/libc/i386/_fpmath.h
new file mode 100644
index 000000000000..4f1f5f4a5a16
--- /dev/null
+++ b/lib/libc/i386/_fpmath.h
@@ -0,0 +1,54 @@
+/*-
+ * Copyright (c) 2002, 2003 David Schultz <das@FreeBSD.ORG>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+union IEEEl2bits {
+ long double e;
+ struct {
+ unsigned int manl :32;
+ unsigned int manh :32;
+ unsigned int exp :15;
+ unsigned int sign :1;
+ unsigned int junk :16;
+ } bits;
+ struct {
+ unsigned long long man :64;
+ unsigned int expsign :16;
+ unsigned int junk :16;
+ } xbits;
+};
+
+#define LDBL_NBIT 0x80000000
+#define mask_nbit_l(u) ((u).bits.manh &= ~LDBL_NBIT)
+
+#define LDBL_MANH_SIZE 32
+#define LDBL_MANL_SIZE 32
+
+#define LDBL_TO_ARRAY32(u, a) do { \
+ (a)[0] = (uint32_t)(u).bits.manl; \
+ (a)[1] = (uint32_t)(u).bits.manh; \
+} while (0)
diff --git a/lib/libc/i386/arith.h b/lib/libc/i386/arith.h
new file mode 100644
index 000000000000..2d65061e82a7
--- /dev/null
+++ b/lib/libc/i386/arith.h
@@ -0,0 +1,15 @@
+/*
+ * MD header for contrib/gdtoa
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * NOTE: The definitions in this file must be correct or strtod(3) and
+ * floating point formats in printf(3) will break! The file can be
+ * generated by running contrib/gdtoa/arithchk.c on the target
+ * architecture. See contrib/gdtoa/gdtoaimp.h for details.
+ */
+
+#define IEEE_8087
+#define Arith_Kind_ASL 1
diff --git a/lib/libc/i386/gd_qnan.h b/lib/libc/i386/gd_qnan.h
new file mode 100644
index 000000000000..39923860db07
--- /dev/null
+++ b/lib/libc/i386/gd_qnan.h
@@ -0,0 +1,21 @@
+/*
+ * MD header for contrib/gdtoa
+ *
+ * This file can be generated by compiling and running contrib/gdtoa/qnan.c
+ * on the target architecture after arith.h has been generated.
+ *
+ * $FreeBSD$
+ */
+
+#define f_QNAN 0x7fc00000
+#define d_QNAN0 0x0
+#define d_QNAN1 0x7ff80000
+#define ld_QNAN0 0x0
+#define ld_QNAN1 0xc0000000
+#define ld_QNAN2 0x7fff
+#define ld_QNAN3 0x0
+#define ldus_QNAN0 0x0
+#define ldus_QNAN1 0x0
+#define ldus_QNAN2 0x0
+#define ldus_QNAN3 0xc000
+#define ldus_QNAN4 0x7fff
diff --git a/lib/libc/i386/gen/Makefile.inc b/lib/libc/i386/gen/Makefile.inc
new file mode 100644
index 000000000000..73dcabbece53
--- /dev/null
+++ b/lib/libc/i386/gen/Makefile.inc
@@ -0,0 +1,6 @@
+# @(#)Makefile.inc 8.1 (Berkeley) 6/4/93
+# $FreeBSD$
+
+SRCS+= _ctx_start.S _setjmp.S _set_tp.c fabs.S \
+ flt_rounds.c getcontextx.c infinity.c ldexp.c makecontext.c \
+ rfork_thread.S setjmp.S signalcontext.c sigsetjmp.S
diff --git a/lib/libc/i386/gen/_ctx_start.S b/lib/libc/i386/gen/_ctx_start.S
new file mode 100644
index 000000000000..fdea3719815b
--- /dev/null
+++ b/lib/libc/i386/gen/_ctx_start.S
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2001 Daniel Eischen <deischen@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Neither the name of the author nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * _ctx_start((void *func)(int arg1, ..., argn),
+ * int arg1, ..., argn, ucontext_t *ucp)
+ *
+ * 0(%esp) - func
+ * 4(%esp) - arg1
+ * 8(%esp) - arg2
+ * ...
+ * (4*n)(%esp) - argn
+ * (4*(n + 1))(%esp) - ucp, %ebp setup to point here (base of stack)
+ */
+ENTRY(_ctx_start)
+ popl %eax /* get start function */
+ call *%eax /* call start function */
+ PIC_PROLOGUE
+ movl %esi, %esp /*
+ * setup stack for completion routine;
+ * ucp is now at top of stack
+ */
+ call PIC_PLT(_ctx_done) /* should never return */
+ call PIC_PLT(abort) /* fubar */
+ ret
+END(_ctx_start)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/i386/gen/_set_tp.c b/lib/libc/i386/gen/_set_tp.c
new file mode 100644
index 000000000000..8a6c9295f5f2
--- /dev/null
+++ b/lib/libc/i386/gen/_set_tp.c
@@ -0,0 +1,40 @@
+/*-
+ * Copyright (c) 2004 Doug Rabson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <string.h>
+#include <stdint.h>
+#include <machine/sysarch.h>
+
+#include "libc_private.h"
+
+void
+_set_tp(void *tp)
+{
+
+ i386_set_gsbase(tp);
+}
diff --git a/lib/libc/i386/gen/_setjmp.S b/lib/libc/i386/gen/_setjmp.S
new file mode 100644
index 000000000000..c5996c6029ca
--- /dev/null
+++ b/lib/libc/i386/gen/_setjmp.S
@@ -0,0 +1,81 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+ .asciz "@(#)_setjmp.s 5.1 (Berkeley) 4/23/90"
+#endif /* LIBC_SCCS and not lint */
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * C library -- _setjmp, _longjmp
+ *
+ * _longjmp(a,v)
+ * will generate a "return(v)" from the last call to
+ * _setjmp(a)
+ * by restoring registers from the environment 'a'.
+ * The previous signal state is NOT restored.
+ */
+
+ENTRY(_setjmp)
+ movl 4(%esp),%eax
+ movl 0(%esp),%edx
+ movl %edx, 0(%eax) /* rta */
+ movl %ebx, 4(%eax)
+ movl %esp, 8(%eax)
+ movl %ebp,12(%eax)
+ movl %esi,16(%eax)
+ movl %edi,20(%eax)
+ fnstcw 24(%eax)
+ xorl %eax,%eax
+ ret
+END(_setjmp)
+
+ WEAK_REFERENCE(___longjmp, _longjmp)
+ENTRY(___longjmp)
+ movl 4(%esp),%edx
+ movl 8(%esp),%eax
+ movl 0(%edx),%ecx
+ movl 4(%edx),%ebx
+ movl 8(%edx),%esp
+ movl 12(%edx),%ebp
+ movl 16(%edx),%esi
+ movl 20(%edx),%edi
+ fldcw 24(%edx)
+ testl %eax,%eax
+ jnz 1f
+ incl %eax
+1: movl %ecx,0(%esp)
+ ret
+END(___longjmp)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/i386/gen/fabs.S b/lib/libc/i386/gen/fabs.S
new file mode 100644
index 000000000000..7fb1531a9016
--- /dev/null
+++ b/lib/libc/i386/gen/fabs.S
@@ -0,0 +1,45 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+ .asciz "@(#)fabs.s 5.2 (Berkeley) 12/17/90"
+#endif /* LIBC_SCCS and not lint */
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+ENTRY(fabs)
+ fldl 4(%esp)
+ fabs
+ ret
+END(fabs)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/i386/gen/flt_rounds.c b/lib/libc/i386/gen/flt_rounds.c
new file mode 100644
index 000000000000..16417ffd46e2
--- /dev/null
+++ b/lib/libc/i386/gen/flt_rounds.c
@@ -0,0 +1,25 @@
+/*
+ * Written by J.T. Conklin, Apr 10, 1995
+ * Public domain.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <float.h>
+
+static const int map[] = {
+ 1, /* round to nearest */
+ 3, /* round to zero */
+ 2, /* round to negative infinity */
+ 0 /* round to positive infinity */
+};
+
+int
+__flt_rounds(void)
+{
+ int x;
+
+ __asm("fnstcw %0" : "=m" (x));
+ return (map[(x >> 10) & 0x03]);
+}
diff --git a/lib/libc/i386/gen/getcontextx.c b/lib/libc/i386/gen/getcontextx.c
new file mode 100644
index 000000000000..3c6dd33ef10f
--- /dev/null
+++ b/lib/libc/i386/gen/getcontextx.c
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2011 Konstantin Belousov <kib@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/ucontext.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <machine/npx.h>
+#include <machine/specialreg.h>
+#include <machine/sysarch.h>
+
+static int xstate_sz = -1;
+
+int
+__getcontextx_size(void)
+{
+ u_int p[4];
+ int cpuid_supported;
+
+ if (xstate_sz == -1) {
+ __asm __volatile(
+ " pushfl\n"
+ " popl %%eax\n"
+ " movl %%eax,%%ecx\n"
+ " xorl $0x200000,%%eax\n"
+ " pushl %%eax\n"
+ " popfl\n"
+ " pushfl\n"
+ " popl %%eax\n"
+ " xorl %%eax,%%ecx\n"
+ " je 1f\n"
+ " movl $1,%0\n"
+ " jmp 2f\n"
+ "1: movl $0,%0\n"
+ "2:\n"
+ : "=r" (cpuid_supported) : : "eax", "ecx");
+ if (cpuid_supported) {
+ __asm __volatile(
+ " pushl %%ebx\n"
+ " cpuid\n"
+ " movl %%ebx,%1\n"
+ " popl %%ebx\n"
+ : "=a" (p[0]), "=r" (p[1]), "=c" (p[2]), "=d" (p[3])
+ : "0" (0x1));
+ if ((p[2] & CPUID2_OSXSAVE) != 0) {
+ __asm __volatile(
+ " pushl %%ebx\n"
+ " cpuid\n"
+ " movl %%ebx,%1\n"
+ " popl %%ebx\n"
+ : "=a" (p[0]), "=r" (p[1]), "=c" (p[2]),
+ "=d" (p[3])
+ : "0" (0xd), "2" (0x0));
+ xstate_sz = p[1] - sizeof(struct savexmm);
+ } else
+ xstate_sz = 0;
+ } else
+ xstate_sz = 0;
+ }
+
+ return (sizeof(ucontext_t) + xstate_sz);
+}
+
+int
+__fillcontextx2(char *ctx)
+{
+ struct i386_get_xfpustate xfpu;
+ ucontext_t *ucp;
+
+ ucp = (ucontext_t *)ctx;
+ if (xstate_sz != 0) {
+ xfpu.addr = (char *)(ucp + 1);
+ xfpu.len = xstate_sz;
+ if (sysarch(I386_GET_XFPUSTATE, &xfpu) == -1)
+ return (-1);
+ ucp->uc_mcontext.mc_xfpustate = (__register_t)xfpu.addr;
+ ucp->uc_mcontext.mc_xfpustate_len = xstate_sz;
+ ucp->uc_mcontext.mc_flags |= _MC_HASFPXSTATE;
+ } else {
+ ucp->uc_mcontext.mc_xfpustate = 0;
+ ucp->uc_mcontext.mc_xfpustate_len = 0;
+ }
+ return (0);
+}
+
+int
+__fillcontextx(char *ctx)
+{
+ ucontext_t *ucp;
+
+ ucp = (ucontext_t *)ctx;
+ if (getcontext(ucp) == -1)
+ return (-1);
+ __fillcontextx2(ctx);
+ return (0);
+}
+
+__weak_reference(__getcontextx, getcontextx);
+
+ucontext_t *
+__getcontextx(void)
+{
+ char *ctx;
+ int error;
+
+ ctx = malloc(__getcontextx_size());
+ if (ctx == NULL)
+ return (NULL);
+ if (__fillcontextx(ctx) == -1) {
+ error = errno;
+ free(ctx);
+ errno = error;
+ return (NULL);
+ }
+ return ((ucontext_t *)ctx);
+}
diff --git a/lib/libc/i386/gen/infinity.c b/lib/libc/i386/gen/infinity.c
new file mode 100644
index 000000000000..464b4029b35a
--- /dev/null
+++ b/lib/libc/i386/gen/infinity.c
@@ -0,0 +1,14 @@
+/*
+ * infinity.c
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <math.h>
+
+/* bytes for +Infinity on a 387 */
+const union __infinity_un __infinity = { { 0, 0, 0, 0, 0, 0, 0xf0, 0x7f } };
+
+/* bytes for NaN */
+const union __nan_un __nan = { { 0, 0, 0xc0, 0xff } };
diff --git a/lib/libc/i386/gen/makecontext.c b/lib/libc/i386/gen/makecontext.c
new file mode 100644
index 000000000000..167cb12893dc
--- /dev/null
+++ b/lib/libc/i386/gen/makecontext.c
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2001 Daniel M. Eischen <deischen@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Neither the name of the author nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/signal.h>
+#include <sys/ucontext.h>
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+/* Prototypes */
+extern void _ctx_start(ucontext_t *, int argc, ...);
+
+
+__weak_reference(__makecontext, makecontext);
+
+void
+_ctx_done (ucontext_t *ucp)
+{
+ if (ucp->uc_link == NULL)
+ exit(0);
+ else {
+ /*
+ * Since this context has finished, don't allow it
+ * to be restarted without being reinitialized (via
+ * setcontext or swapcontext).
+ */
+ ucp->uc_mcontext.mc_len = 0;
+
+ /* Set context to next one in link */
+ /* XXX - what to do for error, abort? */
+ setcontext((const ucontext_t *)ucp->uc_link);
+ abort(); /* should never get here */
+ }
+}
+
+void
+__makecontext(ucontext_t *ucp, void (*start)(void), int argc, ...)
+{
+ va_list ap;
+ char *stack_top;
+ intptr_t *argp;
+ int i;
+
+ if (ucp == NULL)
+ return;
+ else if ((ucp->uc_stack.ss_sp == NULL) ||
+ (ucp->uc_stack.ss_size < MINSIGSTKSZ)) {
+ /*
+ * This should really return -1 with errno set to ENOMEM
+ * or something, but the spec says that makecontext is
+ * a void function. At least make sure that the context
+ * isn't valid so it can't be used without an error.
+ */
+ ucp->uc_mcontext.mc_len = 0;
+ }
+ /* XXX - Do we want to sanity check argc? */
+ else if ((argc < 0) || (argc > NCARGS)) {
+ ucp->uc_mcontext.mc_len = 0;
+ }
+ /* Make sure the context is valid. */
+ else if (ucp->uc_mcontext.mc_len == sizeof(mcontext_t)) {
+ /*
+ * Arrange the stack as follows:
+ *
+ * _ctx_start() - context start wrapper
+ * start() - user start routine
+ * arg1 - first argument, aligned(16)
+ * ...
+ * argn
+ * ucp - this context, %ebp points here
+ *
+ * When the context is started, control will return to
+ * the context start wrapper which will pop the user
+ * start routine from the top of the stack. After that,
+ * the top of the stack will be setup with all arguments
+ * necessary for calling the start routine. When the
+ * start routine returns, the context wrapper then sets
+ * the stack pointer to %ebp which was setup to point to
+ * the base of the stack (and where ucp is stored). It
+ * will then call _ctx_done() to swap in the next context
+ * (uc_link != 0) or exit the program (uc_link == 0).
+ */
+ stack_top = (char *)(ucp->uc_stack.ss_sp +
+ ucp->uc_stack.ss_size - sizeof(intptr_t));
+
+ /*
+ * Adjust top of stack to allow for 3 pointers (return
+ * address, _ctx_start, and ucp) and argc arguments.
+ * We allow the arguments to be pointers also. The first
+ * argument to the user function must be properly aligned.
+ */
+ stack_top = stack_top - (sizeof(intptr_t) * (1 + argc));
+ stack_top = (char *)((unsigned)stack_top & ~15);
+ stack_top = stack_top - (2 * sizeof(intptr_t));
+ argp = (intptr_t *)stack_top;
+
+ /*
+ * Setup the top of the stack with the user start routine
+ * followed by all of its aguments and the pointer to the
+ * ucontext. We need to leave a spare spot at the top of
+ * the stack because setcontext will move eip to the top
+ * of the stack before returning.
+ */
+ *argp = (intptr_t)_ctx_start; /* overwritten with same value */
+ argp++;
+ *argp = (intptr_t)start;
+ argp++;
+
+ /* Add all the arguments: */
+ va_start(ap, argc);
+ for (i = 0; i < argc; i++) {
+ *argp = va_arg(ap, intptr_t);
+ argp++;
+ }
+ va_end(ap);
+
+ /* The ucontext is placed at the bottom of the stack. */
+ *argp = (intptr_t)ucp;
+
+ /*
+ * Set the machine context to point to the top of the
+ * stack and the program counter to the context start
+ * wrapper. Note that setcontext() pushes the return
+ * address onto the top of the stack, so allow for this
+ * by adjusting the stack downward 1 slot. Also set
+ * %esi to point to the base of the stack where ucp
+ * is stored.
+ */
+ ucp->uc_mcontext.mc_esi = (int)argp;
+ ucp->uc_mcontext.mc_ebp = 0;
+ ucp->uc_mcontext.mc_esp = (int)stack_top + sizeof(caddr_t);
+ ucp->uc_mcontext.mc_eip = (int)_ctx_start;
+ }
+}
diff --git a/lib/libc/i386/gen/rfork_thread.S b/lib/libc/i386/gen/rfork_thread.S
new file mode 100644
index 000000000000..1f8181d0cfbc
--- /dev/null
+++ b/lib/libc/i386/gen/rfork_thread.S
@@ -0,0 +1,119 @@
+/*-
+ * Copyright (c) 2000 Peter Wemm <peter@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * With thanks to John Dyson for the original version of this.
+ */
+
+#include <SYS.h>
+
+/*
+ * 8 12 16 20
+ * rfork_thread(flags, stack_addr, start_fnc, start_arg);
+ *
+ * flags: Flags to rfork system call. See rfork(2).
+ * stack_addr: Top of stack for thread.
+ * start_fnc: Address of thread function to call in child.
+ * start_arg: Argument to pass to the thread function in child.
+ */
+
+ENTRY(rfork_thread)
+ pushl %ebp
+ movl %esp, %ebp
+ pushl %esi
+
+ /*
+ * Push thread info onto the new thread's stack
+ */
+ movl 12(%ebp), %esi # get stack addr
+
+ subl $4, %esi
+ movl 20(%ebp), %eax # get start argument
+ movl %eax, (%esi)
+
+ subl $4, %esi
+ movl 16(%ebp), %eax # get start thread address
+ movl %eax, (%esi)
+
+ /*
+ * Prepare and execute the thread creation syscall
+ */
+ pushl 8(%ebp)
+ pushl $0
+ movl $SYS_rfork, %eax
+ KERNCALL
+ jb 2f
+
+ /*
+ * Check to see if we are in the parent or child
+ */
+ cmpl $0, %edx
+ jnz 1f
+ addl $8, %esp
+ popl %esi
+ movl %ebp, %esp
+ popl %ebp
+ ret
+ .p2align 2
+
+ /*
+ * If we are in the child (new thread), then
+ * set-up the call to the internal subroutine. If it
+ * returns, then call __exit.
+ */
+1:
+ movl %esi,%esp
+ popl %eax
+ call *%eax
+ addl $4, %esp
+
+ /*
+ * Exit system call
+ */
+ pushl %eax
+ pushl $0
+#ifdef SYS_exit
+ movl $SYS_exit, %eax
+#else
+ movl $SYS_sys_exit, %eax
+#endif
+ KERNCALL
+
+ /*
+ * Branch here if the thread creation fails:
+ */
+2:
+ addl $8, %esp
+ popl %esi
+ movl %ebp, %esp
+ popl %ebp
+ jmp HIDENAME(cerror)
+END(rfork_thread)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/i386/gen/setjmp.S b/lib/libc/i386/gen/setjmp.S
new file mode 100644
index 000000000000..eb33e101ea86
--- /dev/null
+++ b/lib/libc/i386/gen/setjmp.S
@@ -0,0 +1,97 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+ .asciz "@(#)setjmp.s 5.1 (Berkeley) 4/23/90"
+#endif /* LIBC_SCCS and not lint */
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * C library -- _setjmp, _longjmp
+ *
+ * longjmp(a,v)
+ * will generate a "return(v)" from the last call to
+ * setjmp(a)
+ * by restoring registers from the environment 'a'.
+ * The previous signal state is restored.
+ */
+
+#include "SYS.h"
+
+ENTRY(setjmp)
+ movl 4(%esp),%ecx
+ leal 28(%ecx), %eax
+ pushl %eax /* (sigset_t*)oset */
+ pushl $0 /* (sigset_t*)set */
+ pushl $1 /* SIG_BLOCK */
+ call __libc_sigprocmask
+ addl $12,%esp
+ movl 4(%esp),%ecx
+ movl 0(%esp),%edx
+ movl %edx, 0(%ecx)
+ movl %ebx, 4(%ecx)
+ movl %esp, 8(%ecx)
+ movl %ebp,12(%ecx)
+ movl %esi,16(%ecx)
+ movl %edi,20(%ecx)
+ fnstcw 24(%ecx)
+ xorl %eax,%eax
+ ret
+END(setjmp)
+
+ WEAK_REFERENCE(__longjmp, longjmp)
+ENTRY(__longjmp)
+ movl 4(%esp),%edx
+ pushl $0 /* (sigset_t*)oset */
+ leal 28(%edx), %eax
+ pushl %eax /* (sigset_t*)set */
+ pushl $3 /* SIG_SETMASK */
+ call __libc_sigprocmask
+ addl $12,%esp
+ movl 4(%esp),%edx
+ movl 8(%esp),%eax
+ movl 0(%edx),%ecx
+ movl 4(%edx),%ebx
+ movl 8(%edx),%esp
+ movl 12(%edx),%ebp
+ movl 16(%edx),%esi
+ movl 20(%edx),%edi
+ fldcw 24(%edx)
+ testl %eax,%eax
+ jnz 1f
+ incl %eax
+1: movl %ecx,0(%esp)
+ ret
+END(__longjmp)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/i386/gen/signalcontext.c b/lib/libc/i386/gen/signalcontext.c
new file mode 100644
index 000000000000..877b6556a3f2
--- /dev/null
+++ b/lib/libc/i386/gen/signalcontext.c
@@ -0,0 +1,79 @@
+/*-
+ * Copyright (c) 2002 Jonathan Mini <mini@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/ucontext.h>
+#include <machine/psl.h>
+#include <machine/sigframe.h>
+#include <signal.h>
+#include <strings.h>
+
+__weak_reference(__signalcontext, signalcontext);
+
+extern void _ctx_start(ucontext_t *, int argc, ...);
+
+int
+__signalcontext(ucontext_t *ucp, int sig, __sighandler_t *func)
+{
+ register_t *p;
+ struct sigframe *sfp;
+
+ /*-
+ * Set up stack.
+ * (n = sizeof(int))
+ * 2n+sizeof(struct sigframe) ucp
+ * 2n struct sigframe
+ * 1n &func
+ * 0n &_ctx_start
+ */
+ p = (register_t *)(void *)(intptr_t)ucp->uc_mcontext.mc_esp;
+ *--p = (register_t)(intptr_t)ucp;
+ p = (register_t *)((u_register_t)p & ~0xF); /* Align to 16 bytes. */
+ p = (register_t *)((u_register_t)p - sizeof(struct sigframe));
+ sfp = (struct sigframe *)p;
+ bzero(sfp, sizeof(struct sigframe));
+ sfp->sf_signum = sig;
+ sfp->sf_siginfo = (register_t)(intptr_t)&sfp->sf_si;
+ sfp->sf_ucontext = (register_t)(intptr_t)&sfp->sf_uc;
+ sfp->sf_ahu.sf_action = (__siginfohandler_t *)func;
+ bcopy(ucp, &sfp->sf_uc, sizeof(ucontext_t));
+ sfp->sf_si.si_signo = sig;
+ *--p = (register_t)(intptr_t)func;
+
+ /*
+ * Set up ucontext_t.
+ */
+ ucp->uc_mcontext.mc_esi = ucp->uc_mcontext.mc_esp - sizeof(int);
+ ucp->uc_mcontext.mc_esp = (register_t)(intptr_t)p;
+ ucp->uc_mcontext.mc_eip = (register_t)(intptr_t)_ctx_start;
+ ucp->uc_mcontext.mc_eflags &= ~PSL_T;
+ ucp->uc_link = &sfp->sf_uc;
+ sigdelset(&ucp->uc_sigmask, sig);
+ return (0);
+}
diff --git a/lib/libc/i386/gen/sigsetjmp.S b/lib/libc/i386/gen/sigsetjmp.S
new file mode 100644
index 000000000000..7566d7246409
--- /dev/null
+++ b/lib/libc/i386/gen/sigsetjmp.S
@@ -0,0 +1,108 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)setjmp.s 5.1 (Berkeley) 4/23/90"
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+ .text
+ .asciz "$Id: sigsetjmp.S,v 1.1 1993/12/05 13:01:05 ats Exp $"
+#endif /* LIBC_SCCS and not lint */
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+/*-
+ * TODO:
+ * Rename sigsetjmp to __sigsetjmp and siglongjmp to __siglongjmp,
+ * remove the other *jmp functions and define everything in terms
+ * of the renamed functions. This requires compiler support for
+ * the renamed functions (introduced in gcc-2.5.3; previous versions
+ * only supported *jmp with 0 or 1 leading underscores).
+ *
+ * Restore _all_ the registers and the signal mask atomically. Can
+ * use sigreturn() if sigreturn() works.
+ */
+
+ENTRY(sigsetjmp)
+ movl 8(%esp),%eax
+ movl 4(%esp),%ecx
+ movl %eax,44(%ecx)
+ testl %eax,%eax
+ jz 2f
+ leal 28(%ecx), %eax
+ pushl %eax /* (sigset_t*)oset */
+ pushl $0 /* (sigset_t*)set */
+ pushl $1 /* SIG_BLOCK */
+ call __libc_sigprocmask
+ addl $12,%esp
+ movl 4(%esp),%ecx
+2: movl 0(%esp),%edx
+ movl %edx, 0(%ecx)
+ movl %ebx, 4(%ecx)
+ movl %esp, 8(%ecx)
+ movl %ebp,12(%ecx)
+ movl %esi,16(%ecx)
+ movl %edi,20(%ecx)
+ fnstcw 24(%ecx)
+ xorl %eax,%eax
+ ret
+END(sigsetjmp)
+
+ WEAK_REFERENCE(__siglongjmp, siglongjmp)
+ENTRY(__siglongjmp)
+ movl 4(%esp),%edx
+ cmpl $0,44(%edx)
+ jz 2f
+ pushl $0 /* (sigset_t*)oset */
+ leal 28(%edx), %eax
+ pushl %eax /* (sigset_t*)set */
+ pushl $3 /* SIG_SETMASK */
+ call __libc_sigprocmask
+ addl $12,%esp
+ movl 4(%esp),%edx
+2: movl 8(%esp),%eax
+ movl 0(%edx),%ecx
+ movl 4(%edx),%ebx
+ movl 8(%edx),%esp
+ movl 12(%edx),%ebp
+ movl 16(%edx),%esi
+ movl 20(%edx),%edi
+ fldcw 24(%edx)
+ testl %eax,%eax
+ jnz 1f
+ incl %eax
+1: movl %ecx,0(%esp)
+ ret
+END(__siglongjmp)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/i386/stdlib/Makefile.inc b/lib/libc/i386/stdlib/Makefile.inc
new file mode 100644
index 000000000000..e4197d80b022
--- /dev/null
+++ b/lib/libc/i386/stdlib/Makefile.inc
@@ -0,0 +1,4 @@
+# @(#)Makefile.inc 8.1 (Berkeley) 6/4/93
+# $FreeBSD$
+
+MDSRCS+=div.S ldiv.S
diff --git a/lib/libc/i386/stdlib/div.S b/lib/libc/i386/stdlib/div.S
new file mode 100644
index 000000000000..81d6e6e4aa52
--- /dev/null
+++ b/lib/libc/i386/stdlib/div.S
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 1993 Winning Strategies, 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.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+ENTRY(div)
+ movl 4(%esp),%eax
+ movl 8(%esp),%ecx
+ cdq
+ idiv %ecx
+ ret
+END(div)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/i386/stdlib/ldiv.S b/lib/libc/i386/stdlib/ldiv.S
new file mode 100644
index 000000000000..c40c6314fc03
--- /dev/null
+++ b/lib/libc/i386/stdlib/ldiv.S
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 1993 Winning Strategies, 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Winning Strategies, Inc.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+ENTRY(ldiv)
+ movl 4(%esp),%eax
+ movl 8(%esp),%ecx
+ cdq
+ idiv %ecx
+ ret
+END(ldiv)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/i386/string/Makefile.inc b/lib/libc/i386/string/Makefile.inc
new file mode 100644
index 000000000000..f574c8f25c8b
--- /dev/null
+++ b/lib/libc/i386/string/Makefile.inc
@@ -0,0 +1,6 @@
+# @(#)Makefile.inc 8.1 (Berkeley) 6/4/93
+# $FreeBSD$
+
+MDSRCS+=bcmp.S bcopy.S bzero.S ffs.S memchr.S memcmp.S memcpy.S memmove.S \
+ memset.S strcat.S strchr.S strcmp.S strcpy.S strncmp.S strrchr.S \
+ swab.S wcschr.S wcscmp.S wcslen.S wmemchr.S
diff --git a/lib/libc/i386/string/bcmp.S b/lib/libc/i386/string/bcmp.S
new file mode 100644
index 000000000000..b25ee6ef8dc1
--- /dev/null
+++ b/lib/libc/i386/string/bcmp.S
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 1993 Winning Strategies, 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Winning Strategies, Inc.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * bcmp (void *b1, void *b2, size_t len)
+ *
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+ENTRY(bcmp)
+ pushl %edi
+ pushl %esi
+ movl 12(%esp),%edi
+ movl 16(%esp),%esi
+ cld /* set compare direction forward */
+
+ movl 20(%esp),%ecx /* compare by words */
+ shrl $2,%ecx
+ repe
+ cmpsl
+ jne L1
+
+ movl 20(%esp),%ecx /* compare remainder by bytes */
+ andl $3,%ecx
+ repe
+ cmpsb
+L1:
+ setne %al
+ movsbl %al,%eax
+ popl %esi
+ popl %edi
+ ret
+END(bcmp)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/i386/string/bcopy.S b/lib/libc/i386/string/bcopy.S
new file mode 100644
index 000000000000..cab1de641a21
--- /dev/null
+++ b/lib/libc/i386/string/bcopy.S
@@ -0,0 +1,110 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from locore.s.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#if 0
+ RCSID("$NetBSD: bcopy.S,v 1.6 1996/11/12 00:50:06 jtc Exp $")
+#endif
+
+ /*
+ * (ov)bcopy (src,dst,cnt)
+ * ws@tools.de (Wolfgang Solfrank, TooLs GmbH) +49-228-985800
+ */
+
+#ifdef MEMCOPY
+ENTRY(memcpy)
+#else
+#ifdef MEMMOVE
+ENTRY(memmove)
+#else
+ENTRY(bcopy)
+#endif
+#endif
+ pushl %esi
+ pushl %edi
+#if defined(MEMCOPY) || defined(MEMMOVE)
+ movl 12(%esp),%edi
+ movl 16(%esp),%esi
+ movl %edi,%eax
+#else
+ movl 12(%esp),%esi
+ movl 16(%esp),%edi
+#endif
+ movl 20(%esp),%ecx
+ movl %edi,%edx
+ subl %esi,%edx
+ cmpl %ecx,%edx /* overlapping? */
+ jb 1f
+ cld /* nope, copy forwards. */
+ movl %ecx,%edx
+ shrl $2,%ecx /* copy by words */
+ rep
+ movsl
+ movl %edx,%ecx
+ andl $3,%ecx /* any bytes left? */
+ rep
+ movsb
+ popl %edi
+ popl %esi
+ ret
+1:
+ addl %ecx,%edi /* copy backwards. */
+ addl %ecx,%esi
+ std
+ movl %ecx,%edx
+ andl $3,%ecx /* any fractional bytes? */
+ decl %edi
+ decl %esi
+ rep
+ movsb
+ movl %edx,%ecx /* copy remainder by words */
+ shrl $2,%ecx
+ subl $3,%esi
+ subl $3,%edi
+ rep
+ movsl
+ popl %edi
+ popl %esi
+ cld
+ ret
+#ifdef MEMCOPY
+END(memcpy)
+#else
+#ifdef MEMMOVE
+END(memmove)
+#else
+END(bcopy)
+#endif
+#endif
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/i386/string/bzero.S b/lib/libc/i386/string/bzero.S
new file mode 100644
index 000000000000..c8d3776cf83f
--- /dev/null
+++ b/lib/libc/i386/string/bzero.S
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 1993 Winning Strategies, 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Winning Strategies, Inc.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * bzero (void *b, size_t len)
+ * write len zero bytes to the string b.
+ *
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+ENTRY(bzero)
+ pushl %edi
+ pushl %ebx
+ movl 12(%esp),%edi
+ movl 16(%esp),%ecx
+
+ cld /* set fill direction forward */
+ xorl %eax,%eax /* set fill data to 0 */
+
+ /*
+ * if the string is too short, it's really not worth the overhead
+ * of aligning to word boundries, etc. So we jump to a plain
+ * unaligned set.
+ */
+ cmpl $0x0f,%ecx
+ jle L1
+
+ movl %edi,%edx /* compute misalignment */
+ negl %edx
+ andl $3,%edx
+ movl %ecx,%ebx
+ subl %edx,%ebx
+
+ movl %edx,%ecx /* zero until word aligned */
+ rep
+ stosb
+
+ movl %ebx,%ecx /* zero by words */
+ shrl $2,%ecx
+ rep
+ stosl
+
+ movl %ebx,%ecx
+ andl $3,%ecx /* zero remainder by bytes */
+L1: rep
+ stosb
+
+ popl %ebx
+ popl %edi
+ ret
+END(bzero)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/i386/string/ffs.S b/lib/libc/i386/string/ffs.S
new file mode 100644
index 000000000000..3a0431c6a845
--- /dev/null
+++ b/lib/libc/i386/string/ffs.S
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 1993 Winning Strategies, 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Winning Strategies, Inc.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * ffs(value)
+ * finds the first bit set in value and returns the index of
+ * that bit. Bits are numbered starting from 1, starting at the
+ * rightmost bit. A return value of 0 means that the argument
+ * was zero.
+ *
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+ENTRY(ffs)
+ bsfl 4(%esp),%eax
+ jz L1 /* ZF is set if all bits are 0 */
+ incl %eax /* bits numbered from 1, not 0 */
+ ret
+
+ .align 2
+L1: xorl %eax,%eax /* clear result */
+ ret
+END(ffs)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/i386/string/memchr.S b/lib/libc/i386/string/memchr.S
new file mode 100644
index 000000000000..3bd4d9c3a4d6
--- /dev/null
+++ b/lib/libc/i386/string/memchr.S
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1993 Winning Strategies, 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Winning Strategies, Inc.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * memchr (b, c, len)
+ * locates the first occurrence of c in string b.
+ *
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+ENTRY(memchr)
+ pushl %edi
+ movl 8(%esp),%edi /* string address */
+ movl 12(%esp),%eax /* set character to search for */
+ movl 16(%esp),%ecx /* set length of search */
+ testl %esp,%esp /* clear Z flag, for len == 0 */
+ cld /* set search forward */
+ repne /* search! */
+ scasb
+ jnz L1 /* scan failed, return null */
+ leal -1(%edi),%eax /* adjust result of scan */
+ popl %edi
+ ret
+ .align 2,0x90
+L1: xorl %eax,%eax
+ popl %edi
+ ret
+END(memchr)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/i386/string/memcmp.S b/lib/libc/i386/string/memcmp.S
new file mode 100644
index 000000000000..cbb3b8a468a3
--- /dev/null
+++ b/lib/libc/i386/string/memcmp.S
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 1993 Winning Strategies, 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Winning Strategies, Inc.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * memcmp (void *b1, void *b2, size_t len)
+ *
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+ENTRY(memcmp)
+ pushl %edi
+ pushl %esi
+ movl 12(%esp),%edi
+ movl 16(%esp),%esi
+ cld /* set compare direction forward */
+
+ movl 20(%esp),%ecx /* compare by words */
+ shrl $2,%ecx
+ repe
+ cmpsl
+ jne L5 /* do we match so far? */
+
+ movl 20(%esp),%ecx /* compare remainder by bytes */
+ andl $3,%ecx
+ repe
+ cmpsb
+ jne L6 /* do we match? */
+
+ xorl %eax,%eax /* we match, return zero */
+ popl %esi
+ popl %edi
+ ret
+
+L5: movl $4,%ecx /* We know that one of the next */
+ subl %ecx,%edi /* four pairs of bytes do not */
+ subl %ecx,%esi /* match. */
+ repe
+ cmpsb
+L6: movzbl -1(%edi),%eax /* Perform unsigned comparison */
+ movzbl -1(%esi),%edx
+ subl %edx,%eax
+ popl %esi
+ popl %edi
+ ret
+END(memcmp)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/i386/string/memcpy.S b/lib/libc/i386/string/memcpy.S
new file mode 100644
index 000000000000..f85a1a5b8021
--- /dev/null
+++ b/lib/libc/i386/string/memcpy.S
@@ -0,0 +1,5 @@
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#define MEMCOPY
+#include "bcopy.S"
diff --git a/lib/libc/i386/string/memmove.S b/lib/libc/i386/string/memmove.S
new file mode 100644
index 000000000000..02330c44414b
--- /dev/null
+++ b/lib/libc/i386/string/memmove.S
@@ -0,0 +1,5 @@
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#define MEMMOVE
+#include "bcopy.S"
diff --git a/lib/libc/i386/string/memset.S b/lib/libc/i386/string/memset.S
new file mode 100644
index 000000000000..f5da603bae21
--- /dev/null
+++ b/lib/libc/i386/string/memset.S
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 1993 Winning Strategies, 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Winning Strategies, Inc.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * memset(void *b, int c, size_t len)
+ * write len bytes of value c (converted to an unsigned char) to
+ * the string b.
+ *
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+ENTRY(memset)
+ pushl %edi
+ pushl %ebx
+ movl 12(%esp),%edi
+ movzbl 16(%esp),%eax /* unsigned char, zero extend */
+ movl 20(%esp),%ecx
+ pushl %edi /* push address of buffer */
+
+ cld /* set fill direction forward */
+
+ /*
+ * if the string is too short, it's really not worth the overhead
+ * of aligning to word boundries, etc. So we jump to a plain
+ * unaligned set.
+ */
+ cmpl $0x0f,%ecx
+ jle L1
+
+ movb %al,%ah /* copy char to all bytes in word */
+ movl %eax,%edx
+ sall $16,%eax
+ orl %edx,%eax
+
+ movl %edi,%edx /* compute misalignment */
+ negl %edx
+ andl $3,%edx
+ movl %ecx,%ebx
+ subl %edx,%ebx
+
+ movl %edx,%ecx /* set until word aligned */
+ rep
+ stosb
+
+ movl %ebx,%ecx
+ shrl $2,%ecx /* set by words */
+ rep
+ stosl
+
+ movl %ebx,%ecx /* set remainder by bytes */
+ andl $3,%ecx
+L1: rep
+ stosb
+
+ popl %eax /* pop address of buffer */
+ popl %ebx
+ popl %edi
+ ret
+END(memset)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/i386/string/strcat.S b/lib/libc/i386/string/strcat.S
new file mode 100644
index 000000000000..835a7e9ccf48
--- /dev/null
+++ b/lib/libc/i386/string/strcat.S
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 1993 Winning Strategies, 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Winning Strategies, Inc.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * strcat(s, append)
+ * append a copy of the null-terminated string "append" to the end
+ * of the null-terminated string s, then add a terminating `\0'.
+ *
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+/*
+ * I've unrolled the loop eight times: large enough to make a
+ * significant difference, and small enough not to totally trash the
+ * cache.
+ */
+
+ENTRY(strcat)
+ pushl %edi /* save edi */
+ movl 8(%esp),%edi /* dst address */
+ movl 12(%esp),%edx /* src address */
+ pushl %edi /* push destination address */
+
+ cld /* set search forward */
+ xorl %eax,%eax /* set search for null terminator */
+ movl $-1,%ecx /* set search for lots of characters */
+ repne /* search! */
+ scasb
+
+ leal -1(%edi),%ecx /* correct dst address */
+
+ .align 2,0x90
+L1: movb (%edx),%al /* unroll loop, but not too much */
+ movb %al,(%ecx)
+ testb %al,%al
+ je L2
+ movb 1(%edx),%al
+ movb %al,1(%ecx)
+ testb %al,%al
+ je L2
+ movb 2(%edx),%al
+ movb %al,2(%ecx)
+ testb %al,%al
+ je L2
+ movb 3(%edx),%al
+ movb %al,3(%ecx)
+ testb %al,%al
+ je L2
+ movb 4(%edx),%al
+ movb %al,4(%ecx)
+ testb %al,%al
+ je L2
+ movb 5(%edx),%al
+ movb %al,5(%ecx)
+ testb %al,%al
+ je L2
+ movb 6(%edx),%al
+ movb %al,6(%ecx)
+ testb %al,%al
+ je L2
+ movb 7(%edx),%al
+ movb %al,7(%ecx)
+ addl $8,%edx
+ addl $8,%ecx
+ testb %al,%al
+ jne L1
+L2: popl %eax /* pop destination address */
+ popl %edi /* restore edi */
+ ret
+END(strcat)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/i386/string/strchr.S b/lib/libc/i386/string/strchr.S
new file mode 100644
index 000000000000..83aa87f1919e
--- /dev/null
+++ b/lib/libc/i386/string/strchr.S
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 1993 Winning Strategies, 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Winning Strategies, Inc.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * strchr(s, c)
+ * return a pointer to the first occurrence of the character c in
+ * string s, or NULL if c does not occur in the string.
+ *
+ * %edx - pointer iterating through string
+ * %eax - pointer to first occurrence of 'c'
+ * %cl - character we're comparing against
+ * %bl - character at %edx
+ *
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+ENTRY(strchr)
+ pushl %ebx
+ movl 8(%esp),%eax
+ movb 12(%esp),%cl
+ .align 2,0x90
+L1:
+ movb (%eax),%bl
+ cmpb %bl,%cl /* found char??? */
+ je L2
+ incl %eax
+ testb %bl,%bl /* null terminator??? */
+ jne L1
+ xorl %eax,%eax
+L2:
+ popl %ebx
+ ret
+END(strchr)
+
+WEAK_REFERENCE(strchr, index)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/i386/string/strcmp.S b/lib/libc/i386/string/strcmp.S
new file mode 100644
index 000000000000..6599577b9e96
--- /dev/null
+++ b/lib/libc/i386/string/strcmp.S
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 1993 Winning Strategies, 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Winning Strategies, Inc.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * strcmp(s1, s2)
+ * return an integer greater than, equal to, or less than 0,
+ * according as string s1 is greater than, equal to, or less
+ * than the string s2.
+ *
+ * %eax - pointer to s1
+ * %edx - pointer to s2
+ *
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+/*
+ * I've unrolled the loop eight times: large enough to make a
+ * significant difference, and small enough not to totally trash the
+ * cache.
+ */
+
+ENTRY(strcmp)
+ movl 0x04(%esp),%eax
+ movl 0x08(%esp),%edx
+ jmp L2 /* Jump into the loop! */
+
+ .align 2,0x90
+L1: incl %eax
+ incl %edx
+L2: movb (%eax),%cl
+ testb %cl,%cl
+ je L3
+ cmpb %cl,(%edx)
+ jne L3
+ incl %eax
+ incl %edx
+ movb (%eax),%cl
+ testb %cl,%cl
+ je L3
+ cmpb %cl,(%edx)
+ jne L3
+ incl %eax
+ incl %edx
+ movb (%eax),%cl
+ testb %cl,%cl
+ je L3
+ cmpb %cl,(%edx)
+ jne L3
+ incl %eax
+ incl %edx
+ movb (%eax),%cl
+ testb %cl,%cl
+ je L3
+ cmpb %cl,(%edx)
+ jne L3
+ incl %eax
+ incl %edx
+ movb (%eax),%cl
+ testb %cl,%cl
+ je L3
+ cmpb %cl,(%edx)
+ jne L3
+ incl %eax
+ incl %edx
+ movb (%eax),%cl
+ testb %cl,%cl
+ je L3
+ cmpb %cl,(%edx)
+ jne L3
+ incl %eax
+ incl %edx
+ movb (%eax),%cl
+ testb %cl,%cl
+ je L3
+ cmpb %cl,(%edx)
+ jne L3
+ incl %eax
+ incl %edx
+ movb (%eax),%cl
+ testb %cl,%cl
+ je L3
+ cmpb %cl,(%edx)
+ je L1
+ .align 2, 0x90
+L3: movzbl (%eax),%eax /* unsigned comparison */
+ movzbl (%edx),%edx
+ subl %edx,%eax
+ ret
+END(strcmp)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/i386/string/strcpy.S b/lib/libc/i386/string/strcpy.S
new file mode 100644
index 000000000000..c5113f6a1959
--- /dev/null
+++ b/lib/libc/i386/string/strcpy.S
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 1993 Winning Strategies, 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Winning Strategies, Inc.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * strcpy (dst, src)
+ * copy the string src to dst.
+ *
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+/*
+ * I've unrolled the loop eight times: large enough to make a
+ * significant difference, and small enough not to totally trash the
+ * cache.
+ */
+
+ENTRY(strcpy)
+ movl 4(%esp),%ecx /* dst address */
+ movl 8(%esp),%edx /* src address */
+ pushl %ecx /* push dst address */
+
+ .align 2,0x90
+L1: movb (%edx),%al /* unroll loop, but not too much */
+ movb %al,(%ecx)
+ testb %al,%al
+ je L2
+ movb 1(%edx),%al
+ movb %al,1(%ecx)
+ testb %al,%al
+ je L2
+ movb 2(%edx),%al
+ movb %al,2(%ecx)
+ testb %al,%al
+ je L2
+ movb 3(%edx),%al
+ movb %al,3(%ecx)
+ testb %al,%al
+ je L2
+ movb 4(%edx),%al
+ movb %al,4(%ecx)
+ testb %al,%al
+ je L2
+ movb 5(%edx),%al
+ movb %al,5(%ecx)
+ testb %al,%al
+ je L2
+ movb 6(%edx),%al
+ movb %al,6(%ecx)
+ testb %al,%al
+ je L2
+ movb 7(%edx),%al
+ movb %al,7(%ecx)
+ addl $8,%edx
+ addl $8,%ecx
+ testb %al,%al
+ jne L1
+L2: popl %eax /* pop dst address */
+ ret
+END(strcpy)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/i386/string/strncmp.S b/lib/libc/i386/string/strncmp.S
new file mode 100644
index 000000000000..ec9b5311c6ab
--- /dev/null
+++ b/lib/libc/i386/string/strncmp.S
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 1993,94 Winning Strategies, 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Winning Strategies, Inc.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * strncmp(s1, s2, n)
+ * return an integer greater than, equal to, or less than 0,
+ * according as the first n characters of string s1 is greater
+ * than, equal to, or less than the string s2.
+ *
+ * %eax - pointer to s1
+ * %ecx - pointer to s2
+ * %edx - length
+ *
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+/*
+ * I've unrolled the loop eight times: large enough to make a
+ * significant difference, and small enough not to totally trash the
+ * cache.
+ *
+ * TODO: change all the jz's back to je for consistency.
+ */
+
+ENTRY(strncmp)
+ pushl %ebx
+ movl 8(%esp),%eax
+ movl 12(%esp),%ecx
+ movl 16(%esp),%edx
+ testl %edx,%edx
+ jmp L2 /* Jump into the loop! */
+
+ .align 2,0x90
+L1: incl %eax
+ incl %ecx
+ decl %edx
+L2: jz L4 /* strings are equal */
+ movb (%eax),%bl
+ testb %bl,%bl
+ jz L3
+ cmpb %bl,(%ecx)
+ jne L3
+
+/*
+ * XXX it might be best to move the next 4 instructions to the end of the
+ * unrolled part of the loop. The unrolled part would then be
+ * movb n(%eax),%bl; testb %bl, %bl; je L3; cmpb n(%ecx); jne L3
+ * or maybe better
+ * movb n(%eax),%bl; cmpb n(%ecx); jne L3; testb %bl,%bl; je return_0
+ * for n = 0, 1, ..., 8. The end of the loop would be
+ * L1: addl $8,%eax; addl $8,%ecx; subl $8,%edx; cmpl $8,%edx; jae Lx
+ * where residual counts of 0 to 7 are handled at Lx. However, this would
+ * be slower for short strings. Cache effects are probably not so
+ * important because we are only handling a byte at a time.
+ */
+ incl %eax
+ incl %ecx
+ decl %edx
+ jz L4
+ movb (%eax),%bl
+ testb %bl,%bl
+ jz L3
+ cmpb %bl,(%ecx)
+ jne L3
+
+ incl %eax
+ incl %ecx
+ decl %edx
+ jz L4
+ movb (%eax),%bl
+ testb %bl,%bl
+ jz L3
+ cmpb %bl,(%ecx)
+ jne L3
+
+ incl %eax
+ incl %ecx
+ decl %edx
+ jz L4
+ movb (%eax),%bl
+ testb %bl,%bl
+ jz L3
+ cmpb %bl,(%ecx)
+ jne L3
+
+ incl %eax
+ incl %ecx
+ decl %edx
+ jz L4
+ movb (%eax),%bl
+ testb %bl,%bl
+ jz L3
+ cmpb %bl,(%ecx)
+ jne L3
+
+ incl %eax
+ incl %ecx
+ decl %edx
+ jz L4
+ movb (%eax),%bl
+ testb %bl,%bl
+ jz L3
+ cmpb %bl,(%ecx)
+ jne L3
+
+ incl %eax
+ incl %ecx
+ decl %edx
+ jz L4
+ movb (%eax),%bl
+ testb %bl,%bl
+ jz L3
+ cmpb %bl,(%ecx)
+ jne L3
+
+ incl %eax
+ incl %ecx
+ decl %edx
+ jz L4
+ movb (%eax),%bl
+ testb %bl,%bl
+ jz L3
+ cmpb %bl,(%ecx)
+ je L1
+
+ .align 2,0x90
+L3: movzbl (%eax),%eax /* unsigned comparison */
+ movzbl (%ecx),%ecx
+ subl %ecx,%eax
+ popl %ebx
+ ret
+ .align 2,0x90
+L4: xorl %eax,%eax
+ popl %ebx
+ ret
+END(strncmp)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/i386/string/strrchr.S b/lib/libc/i386/string/strrchr.S
new file mode 100644
index 000000000000..5e250b0c91aa
--- /dev/null
+++ b/lib/libc/i386/string/strrchr.S
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 1993 Winning Strategies, 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Winning Strategies, Inc.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * strrchr(s, c)
+ * return a pointer to the last occurrence of the character c in
+ * string s, or NULL if c does not occur in the string.
+ *
+ * %edx - pointer iterating through string
+ * %eax - pointer to last occurrence of 'c'
+ * %cl - character we're comparing against
+ * %bl - character at %edx
+ *
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+ENTRY(strrchr)
+ pushl %ebx
+ movl 8(%esp),%edx
+ movb 12(%esp),%cl
+ xorl %eax,%eax /* init pointer to null */
+ .align 2,0x90
+L1:
+ movb (%edx),%bl
+ cmpb %bl,%cl
+ jne L2
+ movl %edx,%eax
+L2:
+ incl %edx
+ testb %bl,%bl /* null terminator??? */
+ jne L1
+ popl %ebx
+ ret
+END(strrchr)
+
+WEAK_REFERENCE(strrchr, rindex)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/i386/string/swab.S b/lib/libc/i386/string/swab.S
new file mode 100644
index 000000000000..3d21e6496576
--- /dev/null
+++ b/lib/libc/i386/string/swab.S
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 1993,94 Winning Strategies, 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Winning Strategies, Inc.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * void
+ * swab (const void *src, void *dst, size_t len)
+ * copy len bytes from src to dst, swapping adjacent bytes
+ *
+ * On the i486, this code is negligibly faster than the code generated
+ * by gcc at about half the size. If my i386 databook is correct, it
+ * should be considerably faster than the gcc code on an i386.
+ *
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
+ */
+
+ENTRY(swab)
+ pushl %esi
+ pushl %edi
+ movl 12(%esp),%esi
+ movl 16(%esp),%edi
+ movl 20(%esp),%ecx
+
+ cld # set direction forward
+
+ shrl $1,%ecx
+ testl $7,%ecx # copy first group of 1 to 7 words
+ jz L2 # while swaping alternate bytes.
+ .align 2,0x90
+L1: lodsw
+ rorw $8,%ax
+ stosw
+ decl %ecx
+ testl $7,%ecx
+ jnz L1
+
+L2: shrl $3,%ecx # copy remainder 8 words at a time
+ jz L4 # while swapping alternate bytes.
+ .align 2,0x90
+L3: lodsw
+ rorw $8,%ax
+ stosw
+ lodsw
+ rorw $8,%ax
+ stosw
+ lodsw
+ rorw $8,%ax
+ stosw
+ lodsw
+ rorw $8,%ax
+ stosw
+ lodsw
+ rorw $8,%ax
+ stosw
+ lodsw
+ rorw $8,%ax
+ stosw
+ lodsw
+ rorw $8,%ax
+ stosw
+ lodsw
+ rorw $8,%ax
+ stosw
+ decl %ecx
+ jnz L3
+
+L4: popl %edi
+ popl %esi
+ ret
+END(swab)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/i386/string/wcschr.S b/lib/libc/i386/string/wcschr.S
new file mode 100644
index 000000000000..37862a96f53e
--- /dev/null
+++ b/lib/libc/i386/string/wcschr.S
@@ -0,0 +1,79 @@
+/*-
+ * Copyright (c) 2003 Tim J. Robbins.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * wchar_t *
+ * wcschr(const wchar_t *s, wchar_t c) --
+ * Return pointer to first occurrence of the character `c' in the wide
+ * character string `s', or NULL if not found.
+ */
+ENTRY(wcschr)
+ movl 4(%esp),%ecx /* String */
+ movl 8(%esp),%eax /* Character */
+ pushl %ebx
+.p2align 4,0x90
+L1: movl (%ecx),%ebx
+ cmpl %eax,%ebx
+ je found0
+ testl %ebx,%ebx
+ jz no
+ movl 4(%ecx),%ebx
+ cmpl %eax,%ebx
+ je found1
+ testl %ebx,%ebx
+ jz no
+ movl 8(%ecx),%ebx
+ cmpl %eax,%ebx
+ je found2
+ testl %ebx,%ebx
+ jz no
+ movl 12(%ecx),%ebx
+ cmpl %eax,%ebx
+ je found3
+ testl %ebx,%ebx
+ jz no
+ leal 16(%ecx),%ecx
+ jmp L1
+.p2align 2,0x90
+found3: leal 4(%ecx),%ecx
+.p2align 2,0x90
+found2: leal 4(%ecx),%ecx
+.p2align 2,0x90
+found1: leal 4(%ecx),%ecx
+.p2align 2,0x90
+found0: popl %ebx
+ movl %ecx,%eax
+ ret
+.p2align 2,0x90
+no: popl %ebx
+ xorl %eax,%eax
+ ret
+END(wcschr)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/i386/string/wcscmp.S b/lib/libc/i386/string/wcscmp.S
new file mode 100644
index 000000000000..6fbcb8cc35ba
--- /dev/null
+++ b/lib/libc/i386/string/wcscmp.S
@@ -0,0 +1,82 @@
+/*-
+ * Copyright (c) 2003 Tim J. Robbins.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * int
+ * wcscmp(const wchar_t *s1, const wchar_t *s2) --
+ * Return an integer greater than, equal to, or less than 0, when
+ * the string s1 is greater than, equal to, or less than the string s2.
+ */
+ENTRY(wcscmp)
+ pushl %edi
+ pushl %esi
+ movl 12(%esp),%edi /* s1 */
+ movl 16(%esp),%esi /* s2 */
+.p2align 4,0x90
+top: movl (%edi),%eax
+ cmpl %eax,(%esi)
+ jne no0
+ testl %eax,%eax
+ jz same
+ movl 4(%edi),%eax
+ cmpl %eax,4(%esi)
+ jne no4
+ testl %eax,%eax
+ jz same
+ movl 8(%edi),%eax
+ cmpl %eax,8(%esi)
+ jne no8
+ testl %eax,%eax
+ jz same
+ movl 12(%edi),%eax
+ cmpl %eax,12(%esi)
+ jne no12
+ leal 16(%edi),%edi
+ leal 16(%esi),%esi
+ testl %eax,%eax
+ jnz top
+.p2align 2,0x90
+same: xorl %eax,%eax
+ popl %esi
+ popl %edi
+ ret
+.p2align 2,0x90
+no12: leal 4(%esi),%esi
+.p2align 2,0x90
+no8: leal 4(%esi),%esi
+.p2align 2,0x90
+no4: leal 4(%esi),%esi
+.p2align 2,0x90
+no0: subl (%esi),%eax
+ popl %esi
+ popl %edi
+ ret
+END(wcscmp)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/i386/string/wcslen.S b/lib/libc/i386/string/wcslen.S
new file mode 100644
index 000000000000..691e17f98410
--- /dev/null
+++ b/lib/libc/i386/string/wcslen.S
@@ -0,0 +1,71 @@
+/*-
+ * Copyright (c) 2003 Tim J. Robbins.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * size_t
+ * wcslen(const wchar_t *s) --
+ * Find the length of a wide character string.
+ */
+ENTRY(wcslen)
+ movl 4(%esp),%ecx /* String */
+ pushl %ebx
+ xorl %ebx,%ebx
+ xorl %eax,%eax
+.p2align 4,0x90
+L1: cmpl %ebx,(%ecx)
+ jz found0
+ cmpl %ebx,4(%ecx)
+ jz found1
+ cmpl %ebx,8(%ecx)
+ jz found2
+ cmpl %ebx,12(%ecx)
+ jz found3
+ cmpl %ebx,16(%ecx)
+ jz found4
+ cmpl %ebx,20(%ecx)
+ jz found5
+ cmpl %ebx,24(%ecx)
+ jz found6
+ cmpl %ebx,28(%ecx)
+ jz found7
+ leal 32(%ecx),%ecx
+ addl $8,%eax
+ jmp L1
+found7: incl %eax
+found6: incl %eax
+found5: incl %eax
+found4: incl %eax
+found3: incl %eax
+found2: incl %eax
+found1: incl %eax
+found0: popl %ebx
+ ret
+END(wcslen)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/i386/string/wmemchr.S b/lib/libc/i386/string/wmemchr.S
new file mode 100644
index 000000000000..2e81c09bdca1
--- /dev/null
+++ b/lib/libc/i386/string/wmemchr.S
@@ -0,0 +1,108 @@
+/*-
+ * Copyright (c) 2003 Tim J. Robbins.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * wchar_t *
+ * wmemchr(const wchar_t *buf, wchar_t c, size_t n) --
+ * Search the wide character array `buf', which has length `n',
+ * the character `c', return a pointer to it if found, or NULL on
+ * failure.
+ */
+ENTRY(wmemchr)
+ pushl %edi
+ pushl %ebx
+ movl 12(%esp),%edi /* Buffer */
+ movl 16(%esp),%eax /* Wide character */
+ movl 20(%esp),%ecx /* Length of buffer */
+
+ /*
+ * Search in chunks of 8 wide characters (32 bytes).
+ */
+ movl %ecx,%ebx
+ shrl $3,%ecx
+ jz small
+.p2align 4,0x90
+bigloop:cmpl %eax,(%edi)
+ je found
+ cmpl %eax,4(%edi)
+ je found4
+ cmpl %eax,8(%edi)
+ je found8
+ cmpl %eax,12(%edi)
+ je found12
+ cmpl %eax,16(%edi)
+ je found16
+ cmpl %eax,20(%edi)
+ je found20
+ cmpl %eax,24(%edi)
+ je found24
+ cmpl %eax,28(%edi)
+ je found28
+ leal 32(%edi),%edi
+ decl %ecx
+ jnz bigloop
+ jmp small
+found: movl %edi,%eax
+ popl %ebx
+ popl %edi
+ ret
+found4: leal 4(%edi),%edi
+ jmp found
+found8: leal 8(%edi),%edi
+ jmp found
+found12:leal 12(%edi),%edi
+ jmp found
+found16:leal 16(%edi),%edi
+ jmp found
+found20:leal 20(%edi),%edi
+ jmp found
+found24:leal 24(%edi),%edi
+ jmp found
+found28:leal 28(%edi),%edi
+ jmp found
+
+ /*
+ * Search remaining part of string.
+ */
+small: movl %ebx,%ecx
+ andl $7,%ecx
+ jz no
+.p2align 2,0x90
+smltop: cmpl %eax,(%edi)
+ je found
+ leal 4(%edi),%edi
+ decl %ecx
+ jnz smltop
+no: xorl %eax,%eax
+ popl %ebx
+ popl %edi
+ ret
+END(wmemchr)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/i386/sys/Makefile.inc b/lib/libc/i386/sys/Makefile.inc
new file mode 100644
index 000000000000..450948ec7f2f
--- /dev/null
+++ b/lib/libc/i386/sys/Makefile.inc
@@ -0,0 +1,20 @@
+# from: Makefile.inc,v 1.1 1993/09/03 19:04:23 jtc Exp
+# $FreeBSD$
+
+.if !defined(COMPAT_32BIT)
+SRCS+= i386_clr_watch.c i386_set_watch.c i386_vm86.c
+.endif
+SRCS+= i386_get_fsbase.c i386_get_gsbase.c i386_get_ioperm.c i386_get_ldt.c \
+ i386_set_fsbase.c i386_set_gsbase.c i386_set_ioperm.c i386_set_ldt.c
+
+MDASM= Ovfork.S brk.S cerror.S exect.S getcontext.S \
+ sbrk.S setlogin.S sigreturn.S syscall.S
+
+NOASM+= vfork.o
+
+MAN+= i386_get_ioperm.2 i386_get_ldt.2 i386_vm86.2
+MAN+= i386_set_watch.3
+
+MLINKS+=i386_get_ioperm.2 i386_set_ioperm.2
+MLINKS+=i386_get_ldt.2 i386_set_ldt.2
+MLINKS+=i386_set_watch.3 i386_clr_watch.3
diff --git a/lib/libc/i386/sys/Ovfork.S b/lib/libc/i386/sys/Ovfork.S
new file mode 100644
index 000000000000..b36492098806
--- /dev/null
+++ b/lib/libc/i386/sys/Ovfork.S
@@ -0,0 +1,54 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(SYSLIBC_SCCS) && !defined(lint)
+ .asciz "@(#)Ovfork.s 5.1 (Berkeley) 4/23/90"
+#endif /* SYSLIBC_SCCS and not lint */
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+ WEAK_REFERENCE(__sys_vfork, _vfork)
+ WEAK_REFERENCE(__sys_vfork, vfork)
+ENTRY(__sys_vfork)
+ popl %ecx /* my rta into ecx */
+ mov $SYS_vfork,%eax
+ KERNCALL
+ jb 1f
+ jmp *%ecx
+1:
+ pushl %ecx
+ jmp HIDENAME(cerror)
+END(__sys_vfork)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/i386/sys/brk.S b/lib/libc/i386/sys/brk.S
new file mode 100644
index 000000000000..8a465d2a4a59
--- /dev/null
+++ b/lib/libc/i386/sys/brk.S
@@ -0,0 +1,85 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(SYSLIBC_SCCS) && !defined(lint)
+ .asciz "@(#)brk.s 5.2 (Berkeley) 12/17/90"
+#endif /* SYSLIBC_SCCS and not lint */
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+ .globl HIDENAME(curbrk)
+ .globl HIDENAME(minbrk)
+ENTRY(_brk)
+ jmp ok
+END(_brk)
+
+ENTRY(brk)
+#ifdef PIC
+ movl 4(%esp),%eax
+ PIC_PROLOGUE
+ movl PIC_GOT(HIDENAME(curbrk)),%edx # set up GOT addressing
+ movl PIC_GOT(HIDENAME(minbrk)),%ecx #
+ PIC_EPILOGUE
+ cmpl %eax,(%ecx)
+ jbe ok
+ movl (%ecx),%eax
+ movl %eax,4(%esp)
+ok:
+ mov $SYS_break,%eax
+ KERNCALL
+ jb HIDENAME(cerror)
+ movl 4(%esp),%eax
+ movl %eax,(%edx)
+ movl $0,%eax
+ ret
+
+#else
+
+ movl 4(%esp),%eax
+ cmpl %eax,HIDENAME(minbrk)
+ jbe ok
+ movl HIDENAME(minbrk),%eax
+ movl %eax,4(%esp)
+ok:
+ mov $SYS_break,%eax
+ KERNCALL
+ jb HIDENAME(cerror)
+ movl 4(%esp),%eax
+ movl %eax,HIDENAME(curbrk)
+ movl $0,%eax
+ ret
+#endif
+END(brk)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/i386/sys/cerror.S b/lib/libc/i386/sys/cerror.S
new file mode 100644
index 000000000000..5101e9e00530
--- /dev/null
+++ b/lib/libc/i386/sys/cerror.S
@@ -0,0 +1,68 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(SYSLIBC_SCCS) && !defined(lint)
+ .asciz "@(#)cerror.s 5.1 (Berkeley) 4/23/90"
+#endif /* SYSLIBC_SCCS and not lint */
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+ .globl HIDENAME(cerror)
+ .hidden HIDENAME(cerror)
+
+ /*
+ * The __error() function is thread aware. For non-threaded
+ * programs and the initial threaded in threaded programs,
+ * it returns a pointer to the global errno variable.
+ */
+ .globl CNAME(__error)
+ .type CNAME(__error),@function
+HIDENAME(cerror):
+#ifdef PIC
+ PIC_PROLOGUE
+ pushl %eax
+ call PIC_PLT(CNAME(__error))
+ popl %ecx
+ PIC_EPILOGUE
+#else
+ pushl %eax
+ call CNAME(__error)
+ popl %ecx
+#endif
+ movl %ecx,(%eax)
+ movl $-1,%eax
+ movl $-1,%edx
+ ret
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/i386/sys/exect.S b/lib/libc/i386/sys/exect.S
new file mode 100644
index 000000000000..1378b4bad15e
--- /dev/null
+++ b/lib/libc/i386/sys/exect.S
@@ -0,0 +1,53 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(SYSLIBC_SCCS) && !defined(lint)
+ .asciz "@(#)exect.s 5.1 (Berkeley) 4/23/90"
+#endif /* SYSLIBC_SCCS and not lint */
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+#include <machine/psl.h>
+
+ENTRY(exect)
+ mov $SYS_execve,%eax
+ pushf
+ popl %edx
+ orl $ PSL_T,%edx
+ pushl %edx
+ popf
+ KERNCALL
+ jmp HIDENAME(cerror) /* exect(file, argv, env); */
+END(exect)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/i386/sys/getcontext.S b/lib/libc/i386/sys/getcontext.S
new file mode 100644
index 000000000000..4923382e7368
--- /dev/null
+++ b/lib/libc/i386/sys/getcontext.S
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 2003 Peter Wemm <peter@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include <SYS.h>
+
+/*
+ * This has to be magic to handle the multiple returns.
+ * Otherwise, the setcontext() syscall will return here and we'll
+ * pop off the return address and go to the *setcontext* call.
+ */
+ WEAK_REFERENCE(__sys_getcontext, _getcontext)
+ WEAK_REFERENCE(__sys_getcontext, getcontext)
+ENTRY(__sys_getcontext)
+ movl (%esp),%ecx /* save getcontext return address */
+ mov $SYS_getcontext,%eax
+ KERNCALL
+ jb HIDENAME(cerror)
+ addl $4,%esp /* remove stale (setcontext) return address */
+ jmp *%ecx /* restore return address */
+END(__sys_getcontext)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/i386/sys/i386_clr_watch.c b/lib/libc/i386/sys/i386_clr_watch.c
new file mode 100644
index 000000000000..721c1b8cc46c
--- /dev/null
+++ b/lib/libc/i386/sys/i386_clr_watch.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2000 Brian S. Dean <bsd@bsdhome.com>
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BRIAN S. DEAN ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BRIAN S. DEAN BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <machine/reg.h>
+#include <machine/sysarch.h>
+
+int
+i386_clr_watch(int watchnum, struct dbreg * d)
+{
+
+ if (watchnum < 0 || watchnum >= 4)
+ return -1;
+
+ DBREG_DRX(d,7) = DBREG_DRX(d,7) & ~((0x3 << (watchnum*2)) | (0x0f << (watchnum*4+16)));
+ DBREG_DRX(d,watchnum) = 0;
+
+ return 0;
+}
diff --git a/lib/libc/i386/sys/i386_get_fsbase.c b/lib/libc/i386/sys/i386_get_fsbase.c
new file mode 100644
index 000000000000..24c47648e431
--- /dev/null
+++ b/lib/libc/i386/sys/i386_get_fsbase.c
@@ -0,0 +1,37 @@
+/*-
+ * Copyright (c) 2005 Peter Wemm
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <machine/sysarch.h>
+
+int
+i386_get_fsbase(void **addr)
+{
+
+ return (sysarch(I386_GET_FSBASE, addr));
+}
diff --git a/lib/libc/i386/sys/i386_get_gsbase.c b/lib/libc/i386/sys/i386_get_gsbase.c
new file mode 100644
index 000000000000..f524f310e02c
--- /dev/null
+++ b/lib/libc/i386/sys/i386_get_gsbase.c
@@ -0,0 +1,37 @@
+/*-
+ * Copyright (c) 2005 Peter Wemm
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <machine/sysarch.h>
+
+int
+i386_get_gsbase(void **addr)
+{
+
+ return (sysarch(I386_GET_GSBASE, addr));
+}
diff --git a/lib/libc/i386/sys/i386_get_ioperm.2 b/lib/libc/i386/sys/i386_get_ioperm.2
new file mode 100644
index 000000000000..75fdd10e94b9
--- /dev/null
+++ b/lib/libc/i386/sys/i386_get_ioperm.2
@@ -0,0 +1,87 @@
+.\" Copyright (c) 1998 Jonathan Lemon
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd July 27, 1998
+.Dt I386_GET_IOPERM 2
+.Os
+.Sh NAME
+.Nm i386_get_ioperm ,
+.Nm i386_set_ioperm
+.Nd manage per-process access to the i386 I/O port space
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In machine/sysarch.h
+.Ft int
+.Fn i386_get_ioperm "unsigned int start" "unsigned int *length" "int *enable"
+.Ft int
+.Fn i386_set_ioperm "unsigned int start" "unsigned int length" "int enable"
+.Sh DESCRIPTION
+The
+.Fn i386_get_ioperm
+system call
+will return the permission for the process' I/O port space in the
+.Fa *enable
+argument.
+The port range starts at
+.Fa start
+and the number of contiguous entries will be returned in
+.Fa *length .
+.Pp
+The
+.Fn i386_set_ioperm
+system call
+will set access to a range of I/O ports described by the
+.Fa start
+and
+.Fa length
+arguments to the state specified by the
+.Fa enable
+argument.
+.Sh RETURN VALUES
+.Rv -std
+.Sh ERRORS
+The
+.Fn i386_get_ioperm
+and
+.Fn i386_set_ioperm
+system calls
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+An invalid range was specified by the
+.Fa start
+or
+.Fa length
+arguments.
+.It Bq Er EPERM
+The caller of i386_set_ioperm was not the superuser.
+.El
+.Sh SEE ALSO
+.Xr io 4
+.Sh AUTHORS
+This man page was written by
+.An Jonathan Lemon .
diff --git a/lib/libc/i386/sys/i386_get_ioperm.c b/lib/libc/i386/sys/i386_get_ioperm.c
new file mode 100644
index 000000000000..7bc27f812654
--- /dev/null
+++ b/lib/libc/i386/sys/i386_get_ioperm.c
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 1998 Jonathan Lemon
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <machine/sysarch.h>
+
+int
+i386_get_ioperm(unsigned int start, unsigned int *length, int *enable)
+{
+ struct i386_ioperm_args p;
+ int error;
+
+ p.start = start;
+ p.length = *length;
+ p.enable = *enable;
+
+ error = sysarch(I386_GET_IOPERM, &p);
+
+ *length = p.length;
+ *enable = p.enable;
+
+ return (error);
+}
diff --git a/lib/libc/i386/sys/i386_get_ldt.2 b/lib/libc/i386/sys/i386_get_ldt.2
new file mode 100644
index 000000000000..d6bf872faa60
--- /dev/null
+++ b/lib/libc/i386/sys/i386_get_ldt.2
@@ -0,0 +1,139 @@
+.\" Copyright (c) 1980, 1991 Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" from: @(#)fork.2 6.5 (Berkeley) 3/10/91
+.\" $FreeBSD$
+.\"
+.Dd October 14, 2006
+.Dt I386_GET_LDT 2
+.Os
+.Sh NAME
+.Nm i386_get_ldt ,
+.Nm i386_set_ldt
+.Nd manage i386 per-process Local Descriptor Table entries
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In machine/segments.h
+.In machine/sysarch.h
+.Ft int
+.Fn i386_get_ldt "int start_sel" "union descriptor *descs" "int num_sels"
+.Ft int
+.Fn i386_set_ldt "int start_sel" "union descriptor *descs" "int num_sels"
+.Sh DESCRIPTION
+The
+.Fn i386_get_ldt
+system call
+returns a list of the i386 descriptors in the current process'
+LDT.
+The
+.Fn i386_set_ldt
+system call
+sets a list of i386 descriptors in the current process'
+LDT.
+For both routines,
+.Fa start_sel
+specifies the index of the selector in the LDT at which to begin and
+.Fa descs
+points to an array of
+.Fa num_sels
+descriptors to be set or returned.
+.Pp
+Each entry in the
+.Fa descs
+array can be either a segment_descriptor or gate_descriptor and are defined in
+.In i386/segments.h .
+These structures are defined by the architecture
+as disjoint bit-fields, so care must be taken in constructing them.
+.Pp
+If
+.Fa start_sel
+is
+.Em LDT_AUTO_ALLOC ,
+.Fa num_sels
+is 1 and the descriptor pointed to by
+.Fa descs
+is legal, then
+.Fn i386_set_ldt
+will allocate a descriptor and return its
+selector number.
+.Pp
+If
+.Fa num_descs
+is 1,
+.Fa start_sels
+is valid, and
+.Fa descs
+is NULL, then
+.Fn i386_set_ldt
+will free that descriptor
+(making it available to be reallocated again later).
+.Pp
+If
+.Fa num_descs
+is 0,
+.Fa start_sels
+is 0 and
+.Fa descs
+is NULL then, as a special case,
+.Fn i386_set_ldt
+will free all descriptors.
+.Sh RETURN VALUES
+Upon successful completion,
+.Fn i386_get_ldt
+returns the number of descriptors currently in the LDT.
+The
+.Fn i386_set_ldt
+system call
+returns the first selector set on success.
+If the kernel allocated a descriptor in the LDT,
+the allocated index is returned.
+Otherwise, a value of -1 is returned and the global
+variable
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+The
+.Fn i386_get_ldt
+and
+.Fn i386_set_ldt
+system calls
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+An inappropriate value was used for
+.Fa start_sel
+or
+.Fa num_sels .
+.It Bq Er EACCES
+The caller attempted to use a descriptor that would
+circumvent protection or cause a failure.
+.El
+.Sh SEE ALSO
+i386 Microprocessor Programmer's Reference Manual, Intel
+.Sh WARNING
+You can really hose your process using this.
diff --git a/lib/libc/i386/sys/i386_get_ldt.c b/lib/libc/i386/sys/i386_get_ldt.c
new file mode 100644
index 000000000000..73d76670bb8b
--- /dev/null
+++ b/lib/libc/i386/sys/i386_get_ldt.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 1993 John Brezak
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/cdefs.h>
+#include <machine/segments.h>
+#include <machine/sysarch.h>
+
+int
+i386_get_ldt(int start, union descriptor *descs, int num)
+{
+ struct i386_ldt_args p;
+
+ p.start = start;
+ p.descs = descs;
+ p.num = num;
+
+ return sysarch(I386_GET_LDT, &p);
+}
diff --git a/lib/libc/i386/sys/i386_set_fsbase.c b/lib/libc/i386/sys/i386_set_fsbase.c
new file mode 100644
index 000000000000..6b5544641749
--- /dev/null
+++ b/lib/libc/i386/sys/i386_set_fsbase.c
@@ -0,0 +1,37 @@
+/*-
+ * Copyright (c) 2005 Peter Wemm
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <machine/sysarch.h>
+
+int
+i386_set_fsbase(void *addr)
+{
+
+ return (sysarch(I386_SET_FSBASE, &addr));
+}
diff --git a/lib/libc/i386/sys/i386_set_gsbase.c b/lib/libc/i386/sys/i386_set_gsbase.c
new file mode 100644
index 000000000000..aaf2312d2882
--- /dev/null
+++ b/lib/libc/i386/sys/i386_set_gsbase.c
@@ -0,0 +1,37 @@
+/*-
+ * Copyright (c) 2005 Peter Wemm
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <machine/sysarch.h>
+
+int
+i386_set_gsbase(void *addr)
+{
+
+ return (sysarch(I386_SET_GSBASE, &addr));
+}
diff --git a/lib/libc/i386/sys/i386_set_ioperm.c b/lib/libc/i386/sys/i386_set_ioperm.c
new file mode 100644
index 000000000000..258e2af417b0
--- /dev/null
+++ b/lib/libc/i386/sys/i386_set_ioperm.c
@@ -0,0 +1,42 @@
+/*-
+ * Copyright (c) 1998 Jonathan Lemon
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <machine/sysarch.h>
+
+int
+i386_set_ioperm(unsigned int start, unsigned int length, int enable)
+{
+ struct i386_ioperm_args p;
+
+ p.start = start;
+ p.length = length;
+ p.enable = enable;
+
+ return (sysarch(I386_SET_IOPERM, &p));
+}
diff --git a/lib/libc/i386/sys/i386_set_ldt.c b/lib/libc/i386/sys/i386_set_ldt.c
new file mode 100644
index 000000000000..0bb109aee970
--- /dev/null
+++ b/lib/libc/i386/sys/i386_set_ldt.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 1993 John Brezak
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/cdefs.h>
+#include <machine/segments.h>
+#include <machine/sysarch.h>
+
+int
+i386_set_ldt(int start, union descriptor *descs, int num)
+{
+ struct i386_ldt_args p;
+
+ p.start = start;
+ p.descs = descs;
+ p.num = num;
+
+ return sysarch(I386_SET_LDT, &p);
+}
diff --git a/lib/libc/i386/sys/i386_set_watch.3 b/lib/libc/i386/sys/i386_set_watch.3
new file mode 100644
index 000000000000..9f37c9d65136
--- /dev/null
+++ b/lib/libc/i386/sys/i386_set_watch.3
@@ -0,0 +1,118 @@
+.\" Copyright (c) 2000 Brian S. Dean
+.\" All rights reserved.
+.\"
+.\" This man-page is based on a similar man-page by Jonathan Lemon
+.\" which is copyrighted under the following conditions:
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 August 24, 2000
+.Dt I386_SET_WATCH 3
+.Os
+.Sh NAME
+.Nm i386_clr_watch ,
+.Nm i386_set_watch
+.Nd manage i386 debug register values
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In machine/reg.h
+.In machine/sysarch.h
+.Ft int
+.Fn i386_clr_watch "int watchnum" "struct dbreg *d"
+.Ft int
+.Fn i386_set_watch "int watchnum" "unsigned int watchaddr" "int size" "int access" "struct dbreg *d"
+.Sh DESCRIPTION
+The
+.Fn i386_clr_watch
+function
+will disable the indicated watch point within the specified debug
+register set.
+.Pp
+The
+.Fn i386_set_watch
+function
+will set up the specified debug registers as indicated by the
+arguments.
+The
+.Fa watchnum
+argument specifies which watch register is used, 0, 1, 2, 3, or \-1.
+If
+.Fa watchnum
+is \-1, a free watch register is found and used.
+If there are no free
+watch registers, an error code of \-1 is returned.
+The
+.Fa watchaddr
+argument
+specifies the watch address,
+.Fa size
+specifies the size in bytes of the area to be watched (1, 2, or 4 bytes),
+and
+.Fa access
+specifies the type of watch point:
+.Pp
+.Bd -literal -offset indent -compact
+DBREG_DR7_EXEC An execution breakpoint.
+DBREG_DR7_WRONLY Break only when the watch area is written to.
+DBREG_DR7_RDWR Break when the watch area is read from or written
+ to.
+.Ed
+.Pp
+Note that these functions do not actually set or clear breakpoints;
+they manipulate the indicated debug register set.
+You must use
+.Xr ptrace 2
+to retrieve and install the debug register values for a process.
+.Sh RETURN VALUES
+On success, the
+.Fn i386_clr_watch
+function returns 0.
+On error, \-1 returned which indicates that
+.Fa watchnum
+is invalid (not in the range of 0-3).
+If the specified watchnum was already disabled, no error is returned.
+.Pp
+On success, the
+.Fn i386_set_watch
+function returns the
+.Fa watchnum
+argument, or the watchnum actually used in the case where the specified
+.Fa watchnum
+was \-1.
+On error, the
+.Fn i386_set_watch
+function returns \-1 indicating that the watchpoint could not established
+because either no more watchpoints are available, or
+.Fa watchnum ,
+.Fa size ,
+or
+.Fa access
+is invalid.
+.Sh SEE ALSO
+.Xr ptrace 2 ,
+.Xr procfs 5
+.Sh AUTHORS
+This man page was written by
+.An Brian S. Dean .
diff --git a/lib/libc/i386/sys/i386_set_watch.c b/lib/libc/i386/sys/i386_set_watch.c
new file mode 100644
index 000000000000..cc1b8ed03b7c
--- /dev/null
+++ b/lib/libc/i386/sys/i386_set_watch.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2000 Brian S. Dean <bsd@bsdhome.com>
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BRIAN S. DEAN ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BRIAN S. DEAN BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <machine/reg.h>
+#include <machine/sysarch.h>
+
+int
+i386_set_watch(int watchnum, unsigned int watchaddr, int size,
+ int access, struct dbreg * d)
+{
+ int i;
+ unsigned int mask;
+
+ if (watchnum == -1) {
+ for (i = 0, mask = 0x3; i < 4; i++, mask <<= 2)
+ if ((DBREG_DRX(d,7) & mask) == 0)
+ break;
+ if (i < 4)
+ watchnum = i;
+ else
+ return -1;
+ }
+
+ switch (access) {
+ case DBREG_DR7_EXEC:
+ size = 1; /* size must be 1 for an execution breakpoint */
+ /* fall through */
+ case DBREG_DR7_WRONLY:
+ case DBREG_DR7_RDWR:
+ break;
+ default : return -1; break;
+ }
+
+ /*
+ * we can watch a 1, 2, or 4 byte sized location
+ */
+ switch (size) {
+ case 1 : mask = 0x00; break;
+ case 2 : mask = 0x01 << 2; break;
+ case 4 : mask = 0x03 << 2; break;
+ default : return -1; break;
+ }
+
+ mask |= access;
+
+ /* clear the bits we are about to affect */
+ DBREG_DRX(d,7) &= ~((0x3 << (watchnum*2)) | (0x0f << (watchnum*4+16)));
+
+ /* set drN register to the address, N=watchnum */
+ DBREG_DRX(d,watchnum) = watchaddr;
+
+ /* enable the watchpoint */
+ DBREG_DRX(d,7) |= (0x2 << (watchnum*2)) | (mask << (watchnum*4+16));
+
+ return watchnum;
+}
diff --git a/lib/libc/i386/sys/i386_vm86.2 b/lib/libc/i386/sys/i386_vm86.2
new file mode 100644
index 000000000000..5958f31d2cbf
--- /dev/null
+++ b/lib/libc/i386/sys/i386_vm86.2
@@ -0,0 +1,141 @@
+.\" Copyright (c) 1998 Jonathan Lemon
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd July 27, 1998
+.Dt I386_VM86 2
+.Os
+.Sh NAME
+.Nm i386_vm86
+.Nd control vm86-related functions
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In machine/sysarch.h
+.In machine/vm86.h
+.Ft int
+.Fn i386_vm86 "int function" "void *data"
+.Sh DESCRIPTION
+The
+.Fn i386_vm86
+system call
+is used to call various vm86 related functions.
+The
+.Fa function
+argument
+can be one of the following values:
+.Bl -tag -offset indent -width VM86_SET_VME
+.It Dv VM86_INIT
+This will initialize the kernel's vm86 parameter area for the
+process, and permit the process to make vm86 calls.
+The
+.Fa data
+argument
+points to the following structure:
+.Bd -literal
+struct vm86_init_args {
+ int debug;
+ int cpu_type;
+ u_char int_map[32];
+};
+.Ed
+.Pp
+The
+.Fa debug
+argument
+is used to turn on debugging code.
+The
+.Fa cpu_type
+argument
+controls the type of CPU being emulated, and is currently unimplemented.
+The
+.Fa int_map
+argument
+is a bitmap which determines whether vm86 interrupts should be handled
+in vm86 mode, or reflected back to the process.
+If the
+.Em Nth
+bit is set, the interrupt will be reflected to the process, otherwise
+it will be dispatched by the vm86 interrupt table.
+.It Dv VM86_INTCALL
+This allows calls to be made to vm86 interrupt handlers by the process.
+It effectively simulates an INT instruction.
+.Fa data
+should point to the following structure:
+.Bd -literal
+struct vm86_intcall_args {
+ int intnum;
+ struct vm86frame vmf;
+};
+.Ed
+.Pp
+.Fa intnum
+specifies the operand of INT for the simulated call.
+A value of 0x10, for example, would often be used to call into the VGA BIOS.
+.Fa vmf
+is used to initialize CPU registers according to the calling convention for
+the interrupt handler.
+.It Dv VM86_GET_VME
+This is used to retrieve the current state of the Pentium(r) processor's
+VME (Virtual-8086 Mode Extensions) flag, which is bit 0 of CR4.
+.Fa data
+should be initialized to point to the following:
+.Bd -literal
+struct vm86_vme_args {
+ int state; /* status */
+};
+.Ed
+.Pp
+.Fa state
+will contain the state of the VME flag on return.
+.\" .It Dv VM86_SET_VME
+.El
+.Pp
+vm86 mode is entered by calling
+.Xr sigreturn 2
+with the correct machine context for vm86, and with the
+.Dv PSL_VM
+bit set.
+Control returns to the process upon delivery of a signal.
+.Sh RETURN VALUES
+.Rv -std i386_vm86
+.Sh ERRORS
+The
+.Fn i386_vm86
+system call
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The kernel does not have vm86 support, or an invalid function was specified.
+.It Bq Er ENOMEM
+There is not enough memory to initialize the kernel data structures.
+.El
+.Sh AUTHORS
+.An -nosplit
+This man page was written by
+.An Jonathan Lemon ,
+and updated by
+.An Bruce M Simpson .
diff --git a/lib/libc/i386/sys/i386_vm86.c b/lib/libc/i386/sys/i386_vm86.c
new file mode 100644
index 000000000000..c007608e6220
--- /dev/null
+++ b/lib/libc/i386/sys/i386_vm86.c
@@ -0,0 +1,41 @@
+/*-
+ * Copyright (c) 1998 Jonathan Lemon
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <machine/sysarch.h>
+
+int
+i386_vm86(int fcn, void *data)
+{
+ struct i386_vm86_args p;
+
+ p.sub_op = fcn;
+ p.sub_args = (char *)data;
+
+ return (sysarch(I386_VM86, &p));
+}
diff --git a/lib/libc/i386/sys/sbrk.S b/lib/libc/i386/sys/sbrk.S
new file mode 100644
index 000000000000..99fc2203b00b
--- /dev/null
+++ b/lib/libc/i386/sys/sbrk.S
@@ -0,0 +1,88 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(SYSLIBC_SCCS) && !defined(lint)
+ .asciz "@(#)sbrk.s 5.1 (Berkeley) 4/23/90"
+#endif /* SYSLIBC_SCCS and not lint */
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+ .globl CNAME(_end)
+ .globl HIDENAME(minbrk)
+ .globl HIDENAME(curbrk)
+
+ .data
+HIDENAME(minbrk): .long CNAME(_end)
+HIDENAME(curbrk): .long CNAME(_end)
+ .text
+
+ENTRY(sbrk)
+#ifdef PIC
+ movl 4(%esp),%ecx
+ PIC_PROLOGUE
+ movl PIC_GOT(HIDENAME(curbrk)),%edx
+ movl (%edx),%eax
+ PIC_EPILOGUE
+ testl %ecx,%ecx
+ jz back
+ addl %eax,4(%esp)
+ mov $SYS_break,%eax
+ KERNCALL
+ jb HIDENAME(cerror)
+ PIC_PROLOGUE
+ movl PIC_GOT(HIDENAME(curbrk)),%edx
+ movl (%edx),%eax
+ addl %ecx,(%edx)
+ PIC_EPILOGUE
+back:
+ ret
+
+#else /* !PIC */
+
+ movl 4(%esp),%ecx
+ movl HIDENAME(curbrk),%eax
+ testl %ecx,%ecx
+ jz back
+ addl %eax,4(%esp)
+ mov $SYS_break,%eax
+ KERNCALL
+ jb HIDENAME(cerror)
+ movl HIDENAME(curbrk),%eax
+ addl %ecx,HIDENAME(curbrk)
+back:
+ ret
+#endif /* PIC */
+END(sbrk)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/i386/sys/setlogin.S b/lib/libc/i386/sys/setlogin.S
new file mode 100644
index 000000000000..9247955c5664
--- /dev/null
+++ b/lib/libc/i386/sys/setlogin.S
@@ -0,0 +1,50 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+ .asciz "@(#)setlogin.s 5.2 (Berkeley) 4/12/91"
+#endif /* LIBC_SCCS and not lint */
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+.globl CNAME(_logname_valid) /* in _getlogin() */
+
+SYSCALL(setlogin)
+ PIC_PROLOGUE
+ movl $0,PIC_GOTOFF(CNAME(_logname_valid))
+ PIC_EPILOGUE
+ ret /* setlogin(name) */
+END(__sys_setlogin)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/i386/sys/sigreturn.S b/lib/libc/i386/sys/sigreturn.S
new file mode 100644
index 000000000000..f91816edd443
--- /dev/null
+++ b/lib/libc/i386/sys/sigreturn.S
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(SYSLIBC_SCCS) && !defined(lint)
+ .asciz "@(#)sigreturn.s 5.2 (Berkeley) 12/17/90"
+#endif /* SYSLIBC_SCCS and not lint */
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+/*
+ * NOTE: If the profiling ENTRY() code ever changes any registers, they
+ * must be saved. On FreeBSD, this is not the case.
+ */
+
+RSYSCALL(sigreturn)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/i386/sys/syscall.S b/lib/libc/i386/sys/syscall.S
new file mode 100644
index 000000000000..8a086310414b
--- /dev/null
+++ b/lib/libc/i386/sys/syscall.S
@@ -0,0 +1,52 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(SYSLIBC_SCCS) && !defined(lint)
+ .asciz "@(#)syscall.s 5.1 (Berkeley) 4/23/90"
+#endif /* SYSLIBC_SCCS and not lint */
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+ENTRY(syscall)
+ pop %ecx /* rta */
+ pop %eax /* syscall number */
+ push %ecx
+ KERNCALL
+ push %ecx /* need to push a word to keep stack frame intact
+ upon return; the word must be the return address. */
+ jb HIDENAME(cerror)
+ ret
+END(syscall)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/iconv/Makefile.inc b/lib/libc/iconv/Makefile.inc
new file mode 100644
index 000000000000..25094ce8d9e6
--- /dev/null
+++ b/lib/libc/iconv/Makefile.inc
@@ -0,0 +1,26 @@
+# $FreeBSD$
+
+# iconv sources
+.PATH: ${LIBC_SRCTOP}/iconv
+
+MAN+= iconv.3 iconvctl.3 iconv_canonicalize.3 iconvlist.3 __iconv_get_list.3
+MLINKS+= iconv.3 iconv_open.3 \
+ iconv.3 iconv_open_into.3 \
+ iconv.3 iconv_close.3 \
+ iconv.3 __iconv.3 \
+ __iconv_get_list.3 __iconv_free_list.3
+SRCS+= citrus_bcs.c citrus_bcs_strtol.c citrus_bcs_strtoul.c \
+ citrus_csmapper.c citrus_db.c citrus_db_factory.c citrus_db_hash.c \
+ citrus_esdb.c citrus_hash.c citrus_iconv.c citrus_lookup.c \
+ citrus_lookup_factory.c citrus_mapper.c citrus_memstream.c \
+ citrus_mmap.c citrus_module.c citrus_none.c citrus_pivot_factory.c \
+ citrus_prop.c citrus_stdenc.c bsd_iconv.c
+.if ${MK_SYMVER} == yes
+SRCS+= iconv_compat.c
+.endif
+
+SYM_MAPS+= ${LIBC_SRCTOP}/iconv/Symbol.map
+
+.if ${MK_ICONV} == yes
+.include "${SRCTOP}/lib/libc_nonshared/Makefile.iconv"
+.endif
diff --git a/lib/libc/iconv/Symbol.map b/lib/libc/iconv/Symbol.map
new file mode 100644
index 000000000000..8a9a75d519ed
--- /dev/null
+++ b/lib/libc/iconv/Symbol.map
@@ -0,0 +1,104 @@
+/*
+ * $FreeBSD$
+ */
+
+FBSD_1.3 {
+ __bsd___iconv;
+ __bsd___iconv_free_list;
+ __bsd___iconv_get_list;
+ __bsd_iconv;
+ __bsd_iconv_canonicalize;
+ __bsd_iconv_close;
+ __bsd_iconv_open;
+ __bsd_iconv_open_into;
+ __bsd_iconv_set_relocation_prefix;
+ __bsd_iconvctl;
+ __bsd_iconvlist;
+};
+
+FBSDprivate_1.0 {
+ _citrus_bcs_convert_to_lower;
+ _citrus_bcs_convert_to_upper;
+ _citrus_bcs_isalnum;
+ _citrus_bcs_isalpha;
+ _citrus_bcs_isblank;
+ _citrus_bcs_isdigit;
+ _citrus_bcs_iseol;
+ _citrus_bcs_islower;
+ _citrus_bcs_isspace;
+ _citrus_bcs_isupper;
+ _citrus_bcs_isxdigit;
+ _citrus_bcs_skip_nonws;
+ _citrus_bcs_skip_nonws_len;
+ _citrus_bcs_skip_ws;
+ _citrus_bcs_skip_ws_len;
+ _citrus_bcs_strcasecmp;
+ _citrus_bcs_strncasecmp;
+ _citrus_bcs_strtol;
+ _citrus_bcs_strtoul;
+ _citrus_bcs_tolower;
+ _citrus_bcs_toupper;
+ _citrus_bcs_trunc_rws_len;
+ _citrus_bcs_trunc_ws_len;
+ _citrus_csmapper_open;
+ _citrus_csmapper_close;
+ _citrus_db_factory_add_by_string;
+ _citrus_db_factory_add_string_by_string;
+ _citrus_db_factory_add32_by_string;
+ _citrus_db_factory_calc_size;
+ _citrus_db_factory_create;
+ _citrus_db_factory_serialize;
+ _citrus_db_hash_std;
+ _citrus_db_close;
+ _citrus_db_get_entry;
+ _citrus_db_get_number_of_entries;
+ _citrus_db_lookup;
+ _citrus_db_lookup_by_string;
+ _citrus_db_lookup8_by_string;
+ _citrus_db_lookup16_by_string;
+ _citrus_db_lookup_string_by_string;
+ _citrus_db_open;
+ _citrus_esdb_close;
+ _citrus_esdb_open;
+ _citrus_lookup_factory_convert;
+ _citrus_map_file;
+ _citrus_mapper_close;
+ _citrus_mapper_convert;
+ _citrus_mapper_create_area;
+ _citrus_mapper_get_dst_max;
+ _citrus_mapper_get_src_max;
+ _citrus_mapper_get_state_size;
+ _citrus_mapper_init_state;
+ _citrus_mapper_open;
+ _citrus_mapper_open_direct;
+ _citrus_mapper_set_persistent;
+ _citrus_memory_stream_bind;
+ _citrus_memory_stream_chr;
+ _citrus_memory_stream_getc;
+ _citrus_memory_stream_getln;
+ _citrus_memory_stream_getln_region;
+ _citrus_memory_stream_getregion;
+ _citrus_memory_stream_iseof;
+ _citrus_memory_stream_matchline;
+ _citrus_memory_stream_peek;
+ _citrus_memory_stream_remainder;
+ _citrus_memory_stream_rewind;
+ _citrus_memory_stream_seek;
+ _citrus_memory_stream_skip_ws;
+ _citrus_memory_stream_tell;
+ _citrus_memory_stream_ungetc;
+ _citrus_pivot_factory_convert;
+ _citrus_prop_object_init;
+ _citrus_prop_object_uninit;
+ _citrus_prop_parse_variable;
+ _citrus_prop_read_bool;
+ _citrus_prop_read_character;
+ _citrus_prop_read_character_common;
+ _citrus_prop_read_element;
+ _citrus_prop_read_num;
+ _citrus_prop_read_str;
+ _citrus_prop_read_symbol;
+ _citrus_stdenc_close;
+ _citrus_stdenc_open;
+ _citrus_unmap_file;
+};
diff --git a/lib/libc/iconv/__iconv.c b/lib/libc/iconv/__iconv.c
new file mode 100644
index 000000000000..85170b74540a
--- /dev/null
+++ b/lib/libc/iconv/__iconv.c
@@ -0,0 +1,38 @@
+/*-
+ * Copyright (c) 2013 Peter Wemm
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <iconv.h>
+#include "iconv-internal.h"
+
+size_t
+__iconv(iconv_t a, char **b, size_t *c, char **d,
+ size_t *e, __uint32_t f, size_t *g)
+{
+ return __bsd___iconv(a, b, c, d, e, f, g);
+}
diff --git a/lib/libc/iconv/__iconv_free_list.c b/lib/libc/iconv/__iconv_free_list.c
new file mode 100644
index 000000000000..de9701e9924d
--- /dev/null
+++ b/lib/libc/iconv/__iconv_free_list.c
@@ -0,0 +1,37 @@
+/*-
+ * Copyright (c) 2013 Peter Wemm
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <iconv.h>
+#include "iconv-internal.h"
+
+void
+__iconv_free_list(char **a, size_t b)
+{
+ __bsd___iconv_free_list(a, b);
+}
diff --git a/lib/libc/iconv/__iconv_get_list.3 b/lib/libc/iconv/__iconv_get_list.3
new file mode 100644
index 000000000000..076f4d5b6a1d
--- /dev/null
+++ b/lib/libc/iconv/__iconv_get_list.3
@@ -0,0 +1,95 @@
+.\" Copyright (c) 2009 Gabor Kovesdan <gabor@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" Portions of this text are reprinted and reproduced in electronic form
+.\" from IEEE Std 1003.1, 2004 Edition, Standard for Information Technology --
+.\" Portable Operating System Interface (POSIX), The Open Group Base
+.\" Specifications Issue 6, Copyright (C) 2001-2004 by the Institute of
+.\" Electrical and Electronics Engineers, Inc and The Open Group. In the
+.\" event of any discrepancy between this version and the original IEEE and
+.\" The Open Group Standard, the original IEEE and The Open Group Standard is
+.\" the referee document. The original Standard can be obtained online at
+.\" http://www.opengroup.org/unix/online.html.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd October 20, 2009
+.Dt __ICONV_GET_LIST 3
+.Os
+.Sh NAME
+.Nm __iconv_get_list
+.Nm __iconv_free_list
+.Nd retrieving a list of character encodings supported by
+.Xr iconv 3
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In iconv.h
+.Ft int
+.Fn __iconv_get_list "char ***names" "size_t count" "bool paired"
+.Ft void
+.Fn __iconv_free_list "char **names" "size_t count"
+.Sh DESCRIPTION
+The
+.Fn __iconv_get_list
+function obtains a list of character encodings that are supported by the
+.Xr iconv 3
+call.
+The list of the encoding names will be stored in
+.Fa names
+and the number of the entries is stored in
+.Fa count .
+If the
+.Fa paired
+variable is true, the list will be arranged into
+canonical/alias name pairs.
+.Pp
+The
+.Fn __iconv_free_list
+function is to free the allocated memory during the call of
+.Fn __iconv_get_list .
+.Sh RETURN VALUES
+Upon successful completion
+.Fn __iconv_get_list
+returns 0 and set the
+.Fa names
+and
+.Fa count
+arguments.
+Otherwise, \-1 is returned and errno is set to indicate the error.
+.Sh SEE ALSO
+.Xr iconv 3 ,
+.Xr iconvlist 3
+.Sh STANDARDS
+The
+.Nm __iconv_get_list
+and
+.Nm __iconv_free_list
+functions are non-standard interfaces, which appeared in
+the implementation of the Citrus Project.
+The iconv implementation of the Citrus Project was adopted in
+.Fx 9.0 .
+.Sh AUTHORS
+This manual page was written by
+.An Gabor Kovesdan Aq Mt gabor@FreeBSD.org .
diff --git a/lib/libc/iconv/__iconv_get_list.c b/lib/libc/iconv/__iconv_get_list.c
new file mode 100644
index 000000000000..437d413d98a5
--- /dev/null
+++ b/lib/libc/iconv/__iconv_get_list.c
@@ -0,0 +1,37 @@
+/*-
+ * Copyright (c) 2013 Peter Wemm
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <iconv.h>
+#include "iconv-internal.h"
+
+int
+__iconv_get_list(char ***a, size_t *b, __iconv_bool c)
+{
+ return __bsd___iconv_get_list(a, b, c);
+}
diff --git a/lib/libc/iconv/_strtol.h b/lib/libc/iconv/_strtol.h
new file mode 100644
index 000000000000..d2d9d84fd97d
--- /dev/null
+++ b/lib/libc/iconv/_strtol.h
@@ -0,0 +1,167 @@
+/* $FreeBSD$ */
+/* $NetBSD: _strtol.h,v 1.2 2009/05/20 22:03:29 christos Exp $ */
+
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Original version ID:
+ * NetBSD: src/lib/libc/locale/_wcstol.h,v 1.2 2003/08/07 16:43:03 agc Exp
+ */
+
+/*
+ * function template for strtol, strtoll and strtoimax.
+ *
+ * parameters:
+ * _FUNCNAME : function name
+ * __INT : return type
+ * __INT_MIN : lower limit of the return type
+ * __INT_MAX : upper limit of the return type
+ */
+
+__INT
+_FUNCNAME(const char *nptr, char **endptr, int base)
+{
+ const char *s;
+ __INT acc, cutoff;
+ unsigned char c;
+ int any, cutlim, i, neg;
+
+ /* check base value */
+ if (base && (base < 2 || base > 36)) {
+#if !defined(_KERNEL) && !defined(_STANDALONE)
+ errno = EINVAL;
+ if (endptr != NULL)
+ /* LINTED interface specification */
+ *endptr = __DECONST(void *, nptr);
+ return (0);
+#else
+ panic("%s: invalid base %d", __func__, base);
+#endif
+ }
+
+ /*
+ * Skip white space and pick up leading +/- sign if any.
+ * If base is 0, allow 0x for hex and 0 for octal, else
+ * assume decimal; if base is already 16, allow 0x.
+ */
+ s = nptr;
+ do {
+ c = *s++;
+ } while (isspace(c));
+ if (c == '-') {
+ neg = 1;
+ c = *s++;
+ } else {
+ neg = 0;
+ if (c == '+')
+ c = *s++;
+ }
+ if ((base == 0 || base == 16) &&
+ c == '0' && (*s == 'x' || *s == 'X')) {
+ c = s[1];
+ s += 2;
+ base = 16;
+ }
+ if (base == 0)
+ base = (c == '0' ? 8 : 10);
+
+ /*
+ * Compute the cutoff value between legal numbers and illegal
+ * numbers. That is the largest legal value, divided by the
+ * base. An input number that is greater than this value, if
+ * followed by a legal input character, is too big. One that
+ * is equal to this value may be valid or not; the limit
+ * between valid and invalid numbers is then based on the last
+ * digit. For instance, if the range for longs is
+ * [-2147483648..2147483647] and the input base is 10,
+ * cutoff will be set to 214748364 and cutlim to either
+ * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
+ * a value > 214748364, or equal but the next digit is > 7 (or 8),
+ * the number is too big, and we will return a range error.
+ *
+ * Set any if any `digits' consumed; make it negative to indicate
+ * overflow.
+ */
+ cutoff = (neg ? __INT_MIN : __INT_MAX);
+ cutlim = (int)(cutoff % base);
+ cutoff /= base;
+ if (neg) {
+ if (cutlim > 0) {
+ cutlim -= base;
+ cutoff += 1;
+ }
+ cutlim = -cutlim;
+ }
+ for (acc = 0, any = 0;; c = *s++) {
+ if (isdigit(c))
+ i = c - '0';
+ else if (isalpha(c))
+ i = c - (isupper(c) ? 'A' - 10 : 'a' - 10);
+ else
+ break;
+ if (i >= base)
+ break;
+ if (any < 0)
+ continue;
+ if (neg) {
+ if (acc < cutoff || (acc == cutoff && i > cutlim)) {
+ acc = __INT_MIN;
+#if !defined(_KERNEL) && !defined(_STANDALONE)
+ any = -1;
+ errno = ERANGE;
+#else
+ any = 0;
+ break;
+#endif
+ } else {
+ any = 1;
+ acc *= base;
+ acc -= i;
+ }
+ } else {
+ if (acc > cutoff || (acc == cutoff && i > cutlim)) {
+ acc = __INT_MAX;
+#if !defined(_KERNEL) && !defined(_STANDALONE)
+ any = -1;
+ errno = ERANGE;
+#else
+ any = 0;
+ break;
+#endif
+ } else {
+ any = 1;
+ acc *= base;
+ acc += i;
+ }
+ }
+ }
+ if (endptr != NULL)
+ /* LINTED interface specification */
+ *endptr = __DECONST(void *, any ? s - 1 : nptr);
+ return(acc);
+}
diff --git a/lib/libc/iconv/_strtoul.h b/lib/libc/iconv/_strtoul.h
new file mode 100644
index 000000000000..64e0d466b364
--- /dev/null
+++ b/lib/libc/iconv/_strtoul.h
@@ -0,0 +1,126 @@
+/* $FreeBSD$ */
+/* $NetBSD: _strtoul.h,v 1.1 2008/08/20 12:42:26 joerg Exp $ */
+
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Original version ID:
+ * NetBSD: src/lib/libc/locale/_wcstoul.h,v 1.2 2003/08/07 16:43:03 agc Exp
+ */
+
+/*
+ * function template for strtoul, strtoull and strtoumax.
+ *
+ * parameters:
+ * _FUNCNAME : function name
+ * __UINT : return type
+ * __UINT_MAX : upper limit of the return type
+ */
+
+__UINT
+_FUNCNAME(const char *nptr, char **endptr, int base)
+{
+ const char *s;
+ __UINT acc, cutoff;
+ unsigned char c;
+ int any, cutlim, i, neg;
+
+ /* check base value */
+ if (base && (base < 2 || base > 36)) {
+#if !defined(_KERNEL) && !defined(_STANDALONE)
+ errno = EINVAL;
+ return (0);
+#else
+ panic("%s: invalid base %d", __func__, base);
+#endif
+ }
+
+ /*
+ * Skip white space and pick up leading +/- sign if any.
+ * If base is 0, allow 0x for hex and 0 for octal, else
+ * assume decimal; if base is already 16, allow 0x.
+ */
+ s = nptr;
+ do {
+ c = *s++;
+ } while (isspace(c));
+ if (c == '-') {
+ neg = 1;
+ c = *s++;
+ } else {
+ neg = 0;
+ if (c == '+')
+ c = *s++;
+ }
+ if ((base == 0 || base == 16) &&
+ c == '0' && (*s == 'x' || *s == 'X')) {
+ c = s[1];
+ s += 2;
+ base = 16;
+ }
+ if (base == 0)
+ base = (c == '0' ? 8 : 10);
+
+ /*
+ * See strtol for comments as to the logic used.
+ */
+ cutoff = __UINT_MAX / (__UINT)base;
+ cutlim = (int)(__UINT_MAX % (__UINT)base);
+ for (acc = 0, any = 0;; c = *s++) {
+ if (isdigit(c))
+ i = c - '0';
+ else if (isalpha(c))
+ i = c - (isupper(c) ? 'A' - 10 : 'a' - 10);
+ else
+ break;
+ if (i >= base)
+ break;
+ if (any < 0)
+ continue;
+ if (acc > cutoff || (acc == cutoff && i > cutlim)) {
+ acc = __UINT_MAX;
+#if !defined(_KERNEL) && !defined(_STANDALONE)
+ any = -1;
+ errno = ERANGE;
+#else
+ any = 0;
+ break;
+#endif
+ } else {
+ any = 1;
+ acc *= (__UINT)base;
+ acc += i;
+ }
+ }
+ if (neg && any > 0)
+ acc = -acc;
+ if (endptr != NULL)
+ /* LINTED interface specification */
+ *endptr = __DECONST(void *, any ? s - 1 : nptr);
+ return (acc);
+}
diff --git a/lib/libc/iconv/bsd_iconv.c b/lib/libc/iconv/bsd_iconv.c
new file mode 100644
index 000000000000..ca0b706d5dc5
--- /dev/null
+++ b/lib/libc/iconv/bsd_iconv.c
@@ -0,0 +1,325 @@
+/* $FreeBSD$ */
+/* $NetBSD: iconv.c,v 1.11 2009/03/03 16:22:33 explorer Exp $ */
+
+/*-
+ * Copyright (c) 2003 Citrus Project,
+ * Copyright (c) 2009, 2010 Gabor Kovesdan <gabor@FreeBSD.org>,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#include <sys/queue.h>
+#include <sys/types.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <iconv.h>
+#include <limits.h>
+#include <paths.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "citrus_types.h"
+#include "citrus_module.h"
+#include "citrus_esdb.h"
+#include "citrus_hash.h"
+#include "citrus_iconv.h"
+
+#include "iconv-internal.h"
+
+#define ISBADF(_h_) (!(_h_) || (_h_) == (iconv_t)-1)
+
+static iconv_t
+__bsd___iconv_open(const char *out, const char *in, struct _citrus_iconv *handle)
+{
+ const char *out_slashes;
+ char *out_noslashes;
+ int ret;
+
+ /*
+ * Remove anything following a //, as these are options (like
+ * //ignore, //translate, etc) and we just don't handle them.
+ * This is for compatibility with software that uses these
+ * blindly.
+ */
+ out_slashes = strstr(out, "//");
+ if (out_slashes != NULL) {
+ out_noslashes = strndup(out, out_slashes - out);
+ if (out_noslashes == NULL) {
+ errno = ENOMEM;
+ return ((iconv_t)-1);
+ }
+ ret = _citrus_iconv_open(&handle, in, out_noslashes);
+ free(out_noslashes);
+ } else {
+ ret = _citrus_iconv_open(&handle, in, out);
+ }
+
+ if (ret) {
+ errno = ret == ENOENT ? EINVAL : ret;
+ return ((iconv_t)-1);
+ }
+
+ handle->cv_shared->ci_discard_ilseq = strcasestr(out, "//IGNORE");
+ handle->cv_shared->ci_ilseq_invalid = false;
+ handle->cv_shared->ci_hooks = NULL;
+
+ return ((iconv_t)(void *)handle);
+}
+
+iconv_t
+__bsd_iconv_open(const char *out, const char *in)
+{
+
+ return (__bsd___iconv_open(out, in, NULL));
+}
+
+int
+__bsd_iconv_open_into(const char *out, const char *in, iconv_allocation_t *ptr)
+{
+ struct _citrus_iconv *handle;
+
+ handle = (struct _citrus_iconv *)ptr;
+ return ((__bsd___iconv_open(out, in, handle) == (iconv_t)-1) ? -1 : 0);
+}
+
+int
+__bsd_iconv_close(iconv_t handle)
+{
+
+ if (ISBADF(handle)) {
+ errno = EBADF;
+ return (-1);
+ }
+
+ _citrus_iconv_close((struct _citrus_iconv *)(void *)handle);
+
+ return (0);
+}
+
+size_t
+__bsd_iconv(iconv_t handle, char **in, size_t *szin, char **out, size_t *szout)
+{
+ size_t ret;
+ int err;
+
+ if (ISBADF(handle)) {
+ errno = EBADF;
+ return ((size_t)-1);
+ }
+
+ err = _citrus_iconv_convert((struct _citrus_iconv *)(void *)handle,
+ in, szin, out, szout, 0, &ret);
+ if (err) {
+ errno = err;
+ ret = (size_t)-1;
+ }
+
+ return (ret);
+}
+
+size_t
+__bsd___iconv(iconv_t handle, char **in, size_t *szin, char **out,
+ size_t *szout, uint32_t flags, size_t *invalids)
+{
+ size_t ret;
+ int err;
+
+ if (ISBADF(handle)) {
+ errno = EBADF;
+ return ((size_t)-1);
+ }
+
+ err = _citrus_iconv_convert((struct _citrus_iconv *)(void *)handle,
+ in, szin, out, szout, flags, &ret);
+ if (invalids)
+ *invalids = ret;
+ if (err) {
+ errno = err;
+ ret = (size_t)-1;
+ }
+
+ return (ret);
+}
+
+int
+__bsd___iconv_get_list(char ***rlist, size_t *rsz, bool sorted)
+{
+ int ret;
+
+ ret = _citrus_esdb_get_list(rlist, rsz, sorted);
+ if (ret) {
+ errno = ret;
+ return (-1);
+ }
+
+ return (0);
+}
+
+void
+__bsd___iconv_free_list(char **list, size_t sz)
+{
+
+ _citrus_esdb_free_list(list, sz);
+}
+
+/*
+ * GNU-compatibile non-standard interfaces.
+ */
+static int
+qsort_helper(const void *first, const void *second)
+{
+ const char * const *s1;
+ const char * const *s2;
+
+ s1 = first;
+ s2 = second;
+ return (strcmp(*s1, *s2));
+}
+
+void
+__bsd_iconvlist(int (*do_one) (unsigned int, const char * const *,
+ void *), void *data)
+{
+ char **list, **names;
+ const char * const *np;
+ char *curitem, *curkey, *slashpos;
+ size_t sz;
+ unsigned int i, j, n;
+
+ i = 0;
+ names = NULL;
+
+ if (__bsd___iconv_get_list(&list, &sz, true)) {
+ list = NULL;
+ goto out;
+ }
+ qsort((void *)list, sz, sizeof(char *), qsort_helper);
+ while (i < sz) {
+ j = 0;
+ slashpos = strchr(list[i], '/');
+ names = malloc(sz * sizeof(char *));
+ if (names == NULL)
+ goto out;
+ curkey = strndup(list[i], slashpos - list[i]);
+ if (curkey == NULL)
+ goto out;
+ names[j++] = curkey;
+ for (; (i < sz) && (memcmp(curkey, list[i], strlen(curkey)) == 0); i++) {
+ slashpos = strchr(list[i], '/');
+ if (strcmp(curkey, &slashpos[1]) == 0)
+ continue;
+ curitem = strdup(&slashpos[1]);
+ if (curitem == NULL)
+ goto out;
+ names[j++] = curitem;
+ }
+ np = (const char * const *)names;
+ do_one(j, np, data);
+ for (n = 0; n < j; n++)
+ free(names[n]);
+ free(names);
+ names = NULL;
+ }
+
+out:
+ if (names != NULL) {
+ for (n = 0; n < j; n++)
+ free(names[n]);
+ free(names);
+ }
+ if (list != NULL)
+ __bsd___iconv_free_list(list, sz);
+}
+
+__inline const char *
+__bsd_iconv_canonicalize(const char *name)
+{
+
+ return (_citrus_iconv_canonicalize(name));
+}
+
+int
+__bsd_iconvctl(iconv_t cd, int request, void *argument)
+{
+ struct _citrus_iconv *cv;
+ struct iconv_hooks *hooks;
+ const char *convname;
+ char *dst;
+ int *i;
+ size_t srclen;
+
+ cv = (struct _citrus_iconv *)(void *)cd;
+ hooks = (struct iconv_hooks *)argument;
+ i = (int *)argument;
+
+ if (ISBADF(cd)) {
+ errno = EBADF;
+ return (-1);
+ }
+
+ switch (request) {
+ case ICONV_TRIVIALP:
+ convname = cv->cv_shared->ci_convname;
+ dst = strchr(convname, '/');
+ srclen = dst - convname;
+ dst++;
+ *i = (srclen == strlen(dst)) && !memcmp(convname, dst, srclen);
+ return (0);
+ case ICONV_GET_TRANSLITERATE:
+ *i = 1;
+ return (0);
+ case ICONV_SET_TRANSLITERATE:
+ return ((*i == 1) ? 0 : -1);
+ case ICONV_GET_DISCARD_ILSEQ:
+ *i = cv->cv_shared->ci_discard_ilseq ? 1 : 0;
+ return (0);
+ case ICONV_SET_DISCARD_ILSEQ:
+ cv->cv_shared->ci_discard_ilseq = *i;
+ return (0);
+ case ICONV_SET_HOOKS:
+ cv->cv_shared->ci_hooks = hooks;
+ return (0);
+ case ICONV_SET_FALLBACKS:
+ errno = EOPNOTSUPP;
+ return (-1);
+ case ICONV_GET_ILSEQ_INVALID:
+ *i = cv->cv_shared->ci_ilseq_invalid ? 1 : 0;
+ return (0);
+ case ICONV_SET_ILSEQ_INVALID:
+ cv->cv_shared->ci_ilseq_invalid = *i;
+ return (0);
+ default:
+ errno = EINVAL;
+ return (-1);
+ }
+}
+
+void
+__bsd_iconv_set_relocation_prefix(const char *orig_prefix __unused,
+ const char *curr_prefix __unused)
+{
+
+}
diff --git a/lib/libc/iconv/citrus_aliasname_local.h b/lib/libc/iconv/citrus_aliasname_local.h
new file mode 100644
index 000000000000..687362b12bbd
--- /dev/null
+++ b/lib/libc/iconv/citrus_aliasname_local.h
@@ -0,0 +1,49 @@
+/* $FreeBSD$ */
+/* $NetBSD: citrus_aliasname_local.h,v 1.2 2009/01/11 02:46:24 christos Exp $ */
+
+/*-
+ * Copyright (c)2008 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _CITRUS_ALIASNAME_LOCAL_H_
+#define _CITRUS_ALIASNAME_LOCAL_H_
+
+static __inline const char *
+__unaliasname(const char *dbname, const char *alias,
+ void *buf, size_t bufsize)
+{
+
+ return (_lookup_simple(dbname, alias,
+ buf, bufsize, _LOOKUP_CASE_SENSITIVE));
+}
+
+static __inline int
+__isforcemapping(const char *name)
+{
+
+ return (_bcs_strcasecmp("/force", name));
+}
+
+#endif /*_CITRUS_ALIASNAME_LOCAL_H_*/
diff --git a/lib/libc/iconv/citrus_bcs.c b/lib/libc/iconv/citrus_bcs.c
new file mode 100644
index 000000000000..e86fb37034cb
--- /dev/null
+++ b/lib/libc/iconv/citrus_bcs.c
@@ -0,0 +1,168 @@
+/* $FreeBSD$ */
+/* $NetBSD: citrus_bcs.c,v 1.5 2005/05/14 17:55:42 tshiozak Exp $ */
+
+/*-
+ * Copyright (c)2003 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include "citrus_namespace.h"
+#include "citrus_bcs.h"
+
+/*
+ * case insensitive comparison between two C strings.
+ */
+int
+_citrus_bcs_strcasecmp(const char * __restrict str1,
+ const char * __restrict str2)
+{
+ int c1, c2;
+
+ c1 = c2 = 1;
+
+ while (c1 && c2 && c1 == c2) {
+ c1 = _bcs_toupper(*str1++);
+ c2 = _bcs_toupper(*str2++);
+ }
+
+ return ((c1 == c2) ? 0 : ((c1 > c2) ? 1 : -1));
+}
+
+/*
+ * case insensitive comparison between two C strings with limitation of length.
+ */
+int
+_citrus_bcs_strncasecmp(const char * __restrict str1,
+ const char * __restrict str2, size_t sz)
+{
+ int c1, c2;
+
+ c1 = c2 = 1;
+
+ while (c1 && c2 && c1 == c2 && sz != 0) {
+ c1 = _bcs_toupper(*str1++);
+ c2 = _bcs_toupper(*str2++);
+ sz--;
+ }
+
+ return ((c1 == c2) ? 0 : ((c1 > c2) ? 1 : -1));
+}
+
+/*
+ * skip white space characters.
+ */
+const char *
+_citrus_bcs_skip_ws(const char *p)
+{
+
+ while (*p && _bcs_isspace(*p))
+ p++;
+
+ return (p);
+}
+
+/*
+ * skip non white space characters.
+ */
+const char *
+_citrus_bcs_skip_nonws(const char *p)
+{
+
+ while (*p && !_bcs_isspace(*p))
+ p++;
+
+ return (p);
+}
+
+/*
+ * skip white space characters with limitation of length.
+ */
+const char *
+_citrus_bcs_skip_ws_len(const char * __restrict p, size_t * __restrict len)
+{
+
+ while (*p && *len > 0 && _bcs_isspace(*p)) {
+ p++;
+ (*len)--;
+ }
+
+ return (p);
+}
+
+/*
+ * skip non white space characters with limitation of length.
+ */
+const char *
+_citrus_bcs_skip_nonws_len(const char * __restrict p, size_t * __restrict len)
+{
+
+ while (*p && *len > 0 && !_bcs_isspace(*p)) {
+ p++;
+ (*len)--;
+ }
+
+ return (p);
+}
+
+/*
+ * truncate trailing white space characters.
+ */
+void
+_citrus_bcs_trunc_rws_len(const char * __restrict p, size_t * __restrict len)
+{
+
+ while (*len > 0 && _bcs_isspace(p[*len - 1]))
+ (*len)--;
+}
+
+/*
+ * destructive transliterate to lowercase.
+ */
+void
+_citrus_bcs_convert_to_lower(char *s)
+{
+
+ while (*s) {
+ *s = _bcs_tolower(*s);
+ s++;
+ }
+}
+
+/*
+ * destructive transliterate to uppercase.
+ */
+void
+_citrus_bcs_convert_to_upper(char *s)
+{
+
+ while (*s) {
+ *s = _bcs_toupper(*s);
+ s++;
+ }
+}
diff --git a/lib/libc/iconv/citrus_bcs.h b/lib/libc/iconv/citrus_bcs.h
new file mode 100644
index 000000000000..3b1f53766579
--- /dev/null
+++ b/lib/libc/iconv/citrus_bcs.h
@@ -0,0 +1,102 @@
+/* $FreeBSD$ */
+/* $NetBSD: citrus_bcs.h,v 1.6 2009/01/11 02:46:24 christos Exp $ */
+
+/*-
+ * Copyright (c)2003 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+
+#ifndef _CITRUS_BCS_H_
+#define _CITRUS_BCS_H_
+
+/*
+ * predicate/conversion for basic character set.
+ *
+ * `Basic character set' is a term defined in the ISO C standard.
+ * Citrus bcs is, if anything, close to `portable character set'
+ * defined in the POSIX.
+ */
+
+#define _CITRUS_BCS_PRED(_name_, _cond_) \
+static __inline int _citrus_bcs_##_name_(uint8_t c) { return (_cond_); }
+
+/*
+ * predicates.
+ * Unlike predicates defined in ctype.h, these do not accept EOF.
+ */
+_CITRUS_BCS_PRED(isblank, c == ' ' || c == '\t')
+_CITRUS_BCS_PRED(iseol, c == '\n' || c == '\r')
+_CITRUS_BCS_PRED(isspace, _citrus_bcs_isblank(c) || _citrus_bcs_iseol(c) ||
+ c == '\f' || c == '\v')
+_CITRUS_BCS_PRED(isdigit, c >= '0' && c <= '9')
+_CITRUS_BCS_PRED(isupper, c >= 'A' && c <= 'Z')
+_CITRUS_BCS_PRED(islower, c >= 'a' && c <= 'z')
+_CITRUS_BCS_PRED(isalpha, _citrus_bcs_isupper(c) || _citrus_bcs_islower(c))
+_CITRUS_BCS_PRED(isalnum, _citrus_bcs_isdigit(c) || _citrus_bcs_isalpha(c))
+_CITRUS_BCS_PRED(isxdigit, _citrus_bcs_isdigit(c) ||
+ (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'))
+
+/*
+ * transliterate between uppercase and lowercase.
+ * Unlike transliterator defined in ctype.h, these do not accept EOF.
+ */
+static __inline uint8_t
+_citrus_bcs_toupper(uint8_t c)
+{
+
+ return (_citrus_bcs_islower(c) ? (c - 'a' + 'A') : c);
+}
+
+static __inline uint8_t
+_citrus_bcs_tolower(uint8_t c)
+{
+
+ return (_citrus_bcs_isupper(c) ? (c - 'A' + 'a') : c);
+}
+
+__BEGIN_DECLS
+int _citrus_bcs_strcasecmp(const char * __restrict,
+ const char * __restrict);
+int _citrus_bcs_strncasecmp(const char * __restrict,
+ const char * __restrict, size_t);
+const char *_citrus_bcs_skip_ws(const char * __restrict);
+const char *_citrus_bcs_skip_nonws(const char * __restrict);
+const char *_citrus_bcs_skip_ws_len(const char * __restrict,
+ size_t * __restrict);
+const char *_citrus_bcs_skip_nonws_len(const char * __restrict,
+ size_t * __restrict);
+void _citrus_bcs_trunc_rws_len(const char * __restrict,
+ size_t * __restrict);
+void _citrus_bcs_convert_to_lower(char *);
+void _citrus_bcs_convert_to_upper(char *);
+
+long int _citrus_bcs_strtol(const char * __restrict,
+ char ** __restrict, int);
+unsigned long _citrus_bcs_strtoul(const char * __restrict,
+ char ** __restrict, int);
+__END_DECLS
+
+#endif
diff --git a/lib/libc/iconv/citrus_bcs_strtol.c b/lib/libc/iconv/citrus_bcs_strtol.c
new file mode 100644
index 000000000000..ac874a3549c7
--- /dev/null
+++ b/lib/libc/iconv/citrus_bcs_strtol.c
@@ -0,0 +1,57 @@
+/* $FreeBSD$ */
+/* $NetBSD: citrus_bcs_strtol.c,v 1.4 2013/04/26 21:20:47 joerg Exp $ */
+
+/*-
+ * Copyright (c) 2005 The DragonFly Project. All rights reserved.
+ * Copyright (c) 2003, 2008 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "citrus_namespace.h"
+#include "citrus_bcs.h"
+
+#define _FUNCNAME _bcs_strtol
+#define __INT long int
+
+#undef isspace
+#define isspace(c) _bcs_isspace(c)
+
+#undef isdigit
+#define isdigit(c) _bcs_isdigit(c)
+
+#undef isalpha
+#define isalpha(c) _bcs_isalpha(c)
+
+#undef isupper
+#define isupper(c) _bcs_isupper(c)
+
+#include "_strtol.h"
diff --git a/lib/libc/iconv/citrus_bcs_strtoul.c b/lib/libc/iconv/citrus_bcs_strtoul.c
new file mode 100644
index 000000000000..b33334a91fdd
--- /dev/null
+++ b/lib/libc/iconv/citrus_bcs_strtoul.c
@@ -0,0 +1,57 @@
+/* $FreeBSD$ */
+/* $NetBSD: citrus_bcs_strtoul.c,v 1.5 2013/04/26 21:20:48 joerg Exp $ */
+
+/*-
+ * Copyright (c) 2005 The DragonFly Project. All rights reserved.
+ * Copyright (c) 2003, 2008 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "citrus_namespace.h"
+#include "citrus_bcs.h"
+
+#define _FUNCNAME _bcs_strtoul
+#define __UINT unsigned long int
+
+#undef isspace
+#define isspace(c) _bcs_isspace(c)
+
+#undef isdigit
+#define isdigit(c) _bcs_isdigit(c)
+
+#undef isalpha
+#define isalpha(c) _bcs_isalpha(c)
+
+#undef isupper
+#define isupper(c) _bcs_isupper(c)
+
+#include "_strtoul.h"
diff --git a/lib/libc/iconv/citrus_csmapper.c b/lib/libc/iconv/citrus_csmapper.c
new file mode 100644
index 000000000000..353adc9bb056
--- /dev/null
+++ b/lib/libc/iconv/citrus_csmapper.c
@@ -0,0 +1,386 @@
+/* $FreeBSD$ */
+/* $NetBSD: citrus_csmapper.c,v 1.11 2011/11/20 07:43:52 tnozaki Exp $ */
+
+/*-
+ * Copyright (c)2003 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#include <sys/endian.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "citrus_namespace.h"
+#include "citrus_types.h"
+#include "citrus_bcs.h"
+#include "citrus_region.h"
+#include "citrus_lock.h"
+#include "citrus_memstream.h"
+#include "citrus_mmap.h"
+#include "citrus_module.h"
+#include "citrus_hash.h"
+#include "citrus_mapper.h"
+#include "citrus_csmapper.h"
+#include "citrus_pivot_file.h"
+#include "citrus_db.h"
+#include "citrus_db_hash.h"
+#include "citrus_lookup.h"
+
+static struct _citrus_mapper_area *maparea = NULL;
+
+static pthread_rwlock_t ma_lock = PTHREAD_RWLOCK_INITIALIZER;
+
+#define CS_ALIAS _PATH_CSMAPPER "/charset.alias"
+#define CS_PIVOT _PATH_CSMAPPER "/charset.pivot"
+
+
+/* ---------------------------------------------------------------------- */
+
+static int
+get32(struct _region *r, uint32_t *rval)
+{
+
+ if (_region_size(r) != 4)
+ return (EFTYPE);
+
+ memcpy(rval, _region_head(r), (size_t)4);
+ *rval = be32toh(*rval);
+
+ return (0);
+}
+
+static int
+open_subdb(struct _citrus_db **subdb, struct _citrus_db *db, const char *src)
+{
+ struct _region r;
+ int ret;
+
+ ret = _db_lookup_by_s(db, src, &r, NULL);
+ if (ret)
+ return (ret);
+ ret = _db_open(subdb, &r, _CITRUS_PIVOT_SUB_MAGIC, _db_hash_std, NULL);
+ if (ret)
+ return (ret);
+
+ return (0);
+}
+
+
+#define NO_SUCH_FILE EOPNOTSUPP
+static int
+find_best_pivot_pvdb(const char *src, const char *dst, char *pivot,
+ size_t pvlen, unsigned long *rnorm)
+{
+ struct _citrus_db *db1, *db2, *db3;
+ struct _region fr, r1, r2;
+ char buf[LINE_MAX];
+ uint32_t val32;
+ unsigned long norm;
+ int i, num, ret;
+
+ ret = _map_file(&fr, CS_PIVOT ".pvdb");
+ if (ret) {
+ if (ret == ENOENT)
+ ret = NO_SUCH_FILE;
+ return (ret);
+ }
+ ret = _db_open(&db1, &fr, _CITRUS_PIVOT_MAGIC, _db_hash_std, NULL);
+ if (ret)
+ goto quit1;
+ ret = open_subdb(&db2, db1, src);
+ if (ret)
+ goto quit2;
+
+ num = _db_get_num_entries(db2);
+ *rnorm = ULONG_MAX;
+ for (i = 0; i < num; i++) {
+ /* iterate each pivot */
+ ret = _db_get_entry(db2, i, &r1, &r2);
+ if (ret)
+ goto quit3;
+ /* r1:pivot name, r2:norm among src and pivot */
+ ret = get32(&r2, &val32);
+ if (ret)
+ goto quit3;
+ norm = val32;
+ snprintf(buf, sizeof(buf), "%.*s",
+ (int)_region_size(&r1), (char *)_region_head(&r1));
+ /* buf: pivot name */
+ ret = open_subdb(&db3, db1, buf);
+ if (ret)
+ goto quit3;
+ if (_db_lookup_by_s(db3, dst, &r2, NULL) != 0)
+ /* don't break the loop, test all src/dst pairs. */
+ goto quit4;
+ /* r2: norm among pivot and dst */
+ ret = get32(&r2, &val32);
+ if (ret)
+ goto quit4;
+ norm += val32;
+ /* judge minimum norm */
+ if (norm < *rnorm) {
+ *rnorm = norm;
+ strlcpy(pivot, buf, pvlen);
+ }
+quit4:
+ _db_close(db3);
+ if (ret)
+ goto quit3;
+ }
+quit3:
+ _db_close(db2);
+quit2:
+ _db_close(db1);
+quit1:
+ _unmap_file(&fr);
+ if (ret)
+ return (ret);
+
+ if (*rnorm == ULONG_MAX)
+ return (ENOENT);
+
+ return (0);
+}
+
+/* ---------------------------------------------------------------------- */
+
+struct zone {
+ const char *begin, *end;
+};
+
+struct parse_arg {
+ char dst[PATH_MAX];
+ unsigned long norm;
+};
+
+static int
+parse_line(struct parse_arg *pa, struct _region *r)
+{
+ struct zone z1, z2;
+ char buf[20];
+ size_t len;
+
+ len = _region_size(r);
+ z1.begin = _bcs_skip_ws_len(_region_head(r), &len);
+ if (len == 0)
+ return (EFTYPE);
+ z1.end = _bcs_skip_nonws_len(z1.begin, &len);
+ if (len == 0)
+ return (EFTYPE);
+ z2.begin = _bcs_skip_ws_len(z1.end, &len);
+ if (len == 0)
+ return (EFTYPE);
+ z2.end = _bcs_skip_nonws_len(z2.begin, &len);
+
+ /* z1 : dst name, z2 : norm */
+ snprintf(pa->dst, sizeof(pa->dst),
+ "%.*s", (int)(z1.end-z1.begin), z1.begin);
+ snprintf(buf, sizeof(buf),
+ "%.*s", (int)(z2.end-z2.begin), z2.begin);
+ pa->norm = _bcs_strtoul(buf, NULL, 0);
+
+ return (0);
+}
+
+static int
+find_dst(struct parse_arg *pasrc, const char *dst)
+{
+ struct _lookup *cl;
+ struct parse_arg padst;
+ struct _region data;
+ int ret;
+
+ ret = _lookup_seq_open(&cl, CS_PIVOT, _LOOKUP_CASE_IGNORE);
+ if (ret)
+ return (ret);
+
+ ret = _lookup_seq_lookup(cl, pasrc->dst, &data);
+ while (ret == 0) {
+ ret = parse_line(&padst, &data);
+ if (ret)
+ break;
+ if (strcmp(dst, padst.dst) == 0) {
+ pasrc->norm += padst.norm;
+ break;
+ }
+ ret = _lookup_seq_next(cl, NULL, &data);
+ }
+ _lookup_seq_close(cl);
+
+ return (ret);
+}
+
+static int
+find_best_pivot_lookup(const char *src, const char *dst, char *pivot,
+ size_t pvlen, unsigned long *rnorm)
+{
+ struct _lookup *cl;
+ struct _region data;
+ struct parse_arg pa;
+ char pivot_min[PATH_MAX];
+ unsigned long norm_min;
+ int ret;
+
+ ret = _lookup_seq_open(&cl, CS_PIVOT, _LOOKUP_CASE_IGNORE);
+ if (ret)
+ return (ret);
+
+ norm_min = ULONG_MAX;
+
+ /* find pivot code */
+ ret = _lookup_seq_lookup(cl, src, &data);
+ while (ret == 0) {
+ ret = parse_line(&pa, &data);
+ if (ret)
+ break;
+ ret = find_dst(&pa, dst);
+ if (ret)
+ break;
+ if (pa.norm < norm_min) {
+ norm_min = pa.norm;
+ strlcpy(pivot_min, pa.dst, sizeof(pivot_min));
+ }
+ ret = _lookup_seq_next(cl, NULL, &data);
+ }
+ _lookup_seq_close(cl);
+
+ if (ret != ENOENT)
+ return (ret);
+ if (norm_min == ULONG_MAX)
+ return (ENOENT);
+ strlcpy(pivot, pivot_min, pvlen);
+ if (rnorm)
+ *rnorm = norm_min;
+
+ return (0);
+}
+
+static int
+find_best_pivot(const char *src, const char *dst, char *pivot, size_t pvlen,
+ unsigned long *rnorm)
+{
+ int ret;
+
+ ret = find_best_pivot_pvdb(src, dst, pivot, pvlen, rnorm);
+ if (ret == NO_SUCH_FILE)
+ ret = find_best_pivot_lookup(src, dst, pivot, pvlen, rnorm);
+
+ return (ret);
+}
+
+static __inline int
+open_serial_mapper(struct _citrus_mapper_area *__restrict ma,
+ struct _citrus_mapper * __restrict * __restrict rcm,
+ const char *src, const char *pivot, const char *dst)
+{
+ char buf[PATH_MAX];
+
+ snprintf(buf, sizeof(buf), "%s/%s,%s/%s", src, pivot, pivot, dst);
+
+ return (_mapper_open_direct(ma, rcm, "mapper_serial", buf));
+}
+
+static struct _citrus_csmapper *csm_none = NULL;
+static int
+get_none(struct _citrus_mapper_area *__restrict ma,
+ struct _citrus_csmapper *__restrict *__restrict rcsm)
+{
+ int ret;
+
+ WLOCK(&ma_lock);
+ if (csm_none) {
+ *rcsm = csm_none;
+ ret = 0;
+ goto quit;
+ }
+
+ ret = _mapper_open_direct(ma, &csm_none, "mapper_none", "");
+ if (ret)
+ goto quit;
+ _mapper_set_persistent(csm_none);
+
+ *rcsm = csm_none;
+ ret = 0;
+quit:
+ UNLOCK(&ma_lock);
+ return (ret);
+}
+
+int
+_citrus_csmapper_open(struct _citrus_csmapper * __restrict * __restrict rcsm,
+ const char * __restrict src, const char * __restrict dst, uint32_t flags,
+ unsigned long *rnorm)
+{
+ const char *realsrc, *realdst;
+ char buf1[PATH_MAX], buf2[PATH_MAX], key[PATH_MAX], pivot[PATH_MAX];
+ unsigned long norm;
+ int ret;
+
+ norm = 0;
+
+ ret = _citrus_mapper_create_area(&maparea, _PATH_CSMAPPER);
+ if (ret)
+ return (ret);
+
+ realsrc = _lookup_alias(CS_ALIAS, src, buf1, sizeof(buf1),
+ _LOOKUP_CASE_IGNORE);
+ realdst = _lookup_alias(CS_ALIAS, dst, buf2, sizeof(buf2),
+ _LOOKUP_CASE_IGNORE);
+ if (!strcmp(realsrc, realdst)) {
+ ret = get_none(maparea, rcsm);
+ if (ret == 0 && rnorm != NULL)
+ *rnorm = 0;
+ return (ret);
+ }
+
+ snprintf(key, sizeof(key), "%s/%s", realsrc, realdst);
+
+ ret = _mapper_open(maparea, rcsm, key);
+ if (ret == 0) {
+ if (rnorm != NULL)
+ *rnorm = 0;
+ return (0);
+ }
+ if (ret != ENOENT || (flags & _CSMAPPER_F_PREVENT_PIVOT)!=0)
+ return (ret);
+
+ ret = find_best_pivot(realsrc, realdst, pivot, sizeof(pivot), &norm);
+ if (ret)
+ return (ret);
+
+ ret = open_serial_mapper(maparea, rcsm, realsrc, pivot, realdst);
+ if (ret == 0 && rnorm != NULL)
+ *rnorm = norm;
+
+ return (ret);
+}
diff --git a/lib/libc/iconv/citrus_csmapper.h b/lib/libc/iconv/citrus_csmapper.h
new file mode 100644
index 000000000000..cb1c4f1f7439
--- /dev/null
+++ b/lib/libc/iconv/citrus_csmapper.h
@@ -0,0 +1,48 @@
+/* $FreeBSD$ */
+/* $NetBSD: citrus_csmapper.h,v 1.3 2013/06/24 17:28:35 joerg Exp $ */
+
+/*-
+ * Copyright (c)2003 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _CITRUS_CSMAPPER_H_
+#define _CITRUS_CSMAPPER_H_
+
+#define _citrus_csmapper _citrus_mapper
+#define _citrus_csmapper_close _citrus_mapper_close
+#define _citrus_csmapper_convert _citrus_mapper_convert
+#define _citrus_csmapper_init_state _citrus_mapper_init_state
+#define _citrus_csmapper_get_state_size _citrus_mapper_get_state_size
+#define _citrus_csmapper_get_src_max _citrus_mapper_get_src_max
+#define _citrus_csmapper_get_dst_max _citrus_mapper_get_dst_max
+
+#define _CITRUS_CSMAPPER_F_PREVENT_PIVOT 0x00000001
+__BEGIN_DECLS
+int _citrus_csmapper_open(struct _citrus_csmapper *__restrict *__restrict,
+ const char *__restrict, const char *__restrict, uint32_t,
+ unsigned long *);
+__END_DECLS
+
+#endif
diff --git a/lib/libc/iconv/citrus_db.c b/lib/libc/iconv/citrus_db.c
new file mode 100644
index 000000000000..2de848b98938
--- /dev/null
+++ b/lib/libc/iconv/citrus_db.c
@@ -0,0 +1,331 @@
+/* $FreeBSD$ */
+/* $NetBSD: citrus_db.c,v 1.5 2008/02/09 14:56:20 junyoung Exp $ */
+
+/*-
+ * Copyright (c)2003 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#include <sys/endian.h>
+#include <sys/types.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "citrus_namespace.h"
+#include "citrus_bcs.h"
+#include "citrus_region.h"
+#include "citrus_memstream.h"
+#include "citrus_mmap.h"
+#include "citrus_db.h"
+#include "citrus_db_factory.h"
+#include "citrus_db_file.h"
+
+struct _citrus_db {
+ struct _region db_region;
+ _citrus_db_hash_func_t db_hashfunc;
+ void *db_hashfunc_closure;
+};
+
+int
+_citrus_db_open(struct _citrus_db **rdb, struct _region *r, const char *magic,
+ _citrus_db_hash_func_t hashfunc, void *hashfunc_closure)
+{
+ struct _citrus_db *db;
+ struct _citrus_db_header_x *dhx;
+ struct _memstream ms;
+
+ _memstream_bind(&ms, r);
+
+ /* sanity check */
+ dhx = _memstream_getregion(&ms, NULL, sizeof(*dhx));
+ if (dhx == NULL)
+ return (EFTYPE);
+ if (strncmp(dhx->dhx_magic, magic, _CITRUS_DB_MAGIC_SIZE) != 0)
+ return (EFTYPE);
+ if (_memstream_seek(&ms, be32toh(dhx->dhx_entry_offset), SEEK_SET))
+ return (EFTYPE);
+
+ if (be32toh(dhx->dhx_num_entries)*_CITRUS_DB_ENTRY_SIZE >
+ _memstream_remainder(&ms))
+ return (EFTYPE);
+
+ db = malloc(sizeof(*db));
+ if (db == NULL)
+ return (errno);
+ db->db_region = *r;
+ db->db_hashfunc = hashfunc;
+ db->db_hashfunc_closure = hashfunc_closure;
+ *rdb = db;
+
+ return (0);
+}
+
+void
+_citrus_db_close(struct _citrus_db *db)
+{
+
+ free(db);
+}
+
+int
+_citrus_db_lookup(struct _citrus_db *db, struct _citrus_region *key,
+ struct _citrus_region *data, struct _citrus_db_locator *dl)
+{
+ struct _citrus_db_entry_x *dex;
+ struct _citrus_db_header_x *dhx;
+ struct _citrus_region r;
+ struct _memstream ms;
+ uint32_t hashval, num_entries;
+ size_t offset;
+
+ _memstream_bind(&ms, &db->db_region);
+
+ dhx = _memstream_getregion(&ms, NULL, sizeof(*dhx));
+ num_entries = be32toh(dhx->dhx_num_entries);
+ if (num_entries == 0)
+ return (ENOENT);
+
+ if (dl != NULL && dl->dl_offset>0) {
+ hashval = dl->dl_hashval;
+ offset = dl->dl_offset;
+ if (offset >= _region_size(&db->db_region))
+ return (ENOENT);
+ } else {
+ hashval = db->db_hashfunc(key)%num_entries;
+ offset = be32toh(dhx->dhx_entry_offset) +
+ hashval * _CITRUS_DB_ENTRY_SIZE;
+ if (dl)
+ dl->dl_hashval = hashval;
+ }
+ do {
+ /* seek to the next entry */
+ if (_citrus_memory_stream_seek(&ms, offset, SEEK_SET))
+ return (EFTYPE);
+ /* get the entry record */
+ dex = _memstream_getregion(&ms, NULL, _CITRUS_DB_ENTRY_SIZE);
+ if (dex == NULL)
+ return (EFTYPE);
+
+ /* jump to next entry having the same hash value. */
+ offset = be32toh(dex->dex_next_offset);
+
+ /* save the current position */
+ if (dl) {
+ dl->dl_offset = offset;
+ if (offset == 0)
+ dl->dl_offset = _region_size(&db->db_region);
+ }
+
+ /* compare hash value. */
+ if (be32toh(dex->dex_hash_value) != hashval)
+ /* not found */
+ break;
+ /* compare key length */
+ if (be32toh(dex->dex_key_size) == _region_size(key)) {
+ /* seek to the head of the key. */
+ if (_memstream_seek(&ms, be32toh(dex->dex_key_offset),
+ SEEK_SET))
+ return (EFTYPE);
+ /* get the region of the key */
+ if (_memstream_getregion(&ms, &r,
+ _region_size(key)) == NULL)
+ return (EFTYPE);
+ /* compare key byte stream */
+ if (memcmp(_region_head(&r), _region_head(key),
+ _region_size(key)) == 0) {
+ /* match */
+ if (_memstream_seek(
+ &ms, be32toh(dex->dex_data_offset),
+ SEEK_SET))
+ return (EFTYPE);
+ if (_memstream_getregion(
+ &ms, data,
+ be32toh(dex->dex_data_size)) == NULL)
+ return (EFTYPE);
+ return (0);
+ }
+ }
+ } while (offset != 0);
+
+ return (ENOENT);
+}
+
+int
+_citrus_db_lookup_by_string(struct _citrus_db *db, const char *key,
+ struct _citrus_region *data, struct _citrus_db_locator *dl)
+{
+ struct _region r;
+
+ _region_init(&r, __DECONST(void *, key), strlen(key));
+
+ return (_citrus_db_lookup(db, &r, data, dl));
+}
+
+int
+_citrus_db_lookup8_by_string(struct _citrus_db *db, const char *key,
+ uint8_t *rval, struct _citrus_db_locator *dl)
+{
+ struct _region r;
+ int ret;
+
+ ret = _citrus_db_lookup_by_string(db, key, &r, dl);
+ if (ret)
+ return (ret);
+
+ if (_region_size(&r) != 1)
+ return (EFTYPE);
+
+ if (rval)
+ memcpy(rval, _region_head(&r), 1);
+
+ return (0);
+}
+
+int
+_citrus_db_lookup16_by_string(struct _citrus_db *db, const char *key,
+ uint16_t *rval, struct _citrus_db_locator *dl)
+{
+ struct _region r;
+ int ret;
+ uint16_t val;
+
+ ret = _citrus_db_lookup_by_string(db, key, &r, dl);
+ if (ret)
+ return (ret);
+
+ if (_region_size(&r) != 2)
+ return (EFTYPE);
+
+ if (rval) {
+ memcpy(&val, _region_head(&r), 2);
+ *rval = be16toh(val);
+ }
+
+ return (0);
+}
+
+int
+_citrus_db_lookup32_by_string(struct _citrus_db *db, const char *key,
+ uint32_t *rval, struct _citrus_db_locator *dl)
+{
+ struct _region r;
+ uint32_t val;
+ int ret;
+
+ ret = _citrus_db_lookup_by_string(db, key, &r, dl);
+ if (ret)
+ return (ret);
+
+ if (_region_size(&r) != 4)
+ return (EFTYPE);
+
+ if (rval) {
+ memcpy(&val, _region_head(&r), 4);
+ *rval = be32toh(val);
+ }
+
+ return (0);
+}
+
+int
+_citrus_db_lookup_string_by_string(struct _citrus_db *db, const char *key,
+ const char **rdata, struct _citrus_db_locator *dl)
+{
+ struct _region r;
+ int ret;
+
+ ret = _citrus_db_lookup_by_string(db, key, &r, dl);
+ if (ret)
+ return (ret);
+
+ /* check whether the string is null terminated */
+ if (_region_size(&r) == 0)
+ return (EFTYPE);
+ if (*((const char*)_region_head(&r)+_region_size(&r)-1) != '\0')
+ return (EFTYPE);
+
+ if (rdata)
+ *rdata = _region_head(&r);
+
+ return (0);
+}
+
+int
+_citrus_db_get_number_of_entries(struct _citrus_db *db)
+{
+ struct _citrus_db_header_x *dhx;
+ struct _memstream ms;
+
+ _memstream_bind(&ms, &db->db_region);
+
+ dhx = _memstream_getregion(&ms, NULL, sizeof(*dhx));
+ return ((int)be32toh(dhx->dhx_num_entries));
+}
+
+int
+_citrus_db_get_entry(struct _citrus_db *db, int idx, struct _region *key,
+ struct _region *data)
+{
+ struct _citrus_db_entry_x *dex;
+ struct _citrus_db_header_x *dhx;
+ struct _memstream ms;
+ uint32_t num_entries;
+ size_t offset;
+
+ _memstream_bind(&ms, &db->db_region);
+
+ dhx = _memstream_getregion(&ms, NULL, sizeof(*dhx));
+ num_entries = be32toh(dhx->dhx_num_entries);
+ if (idx < 0 || (uint32_t)idx >= num_entries)
+ return (EINVAL);
+
+ /* seek to the next entry */
+ offset = be32toh(dhx->dhx_entry_offset) + idx * _CITRUS_DB_ENTRY_SIZE;
+ if (_citrus_memory_stream_seek(&ms, offset, SEEK_SET))
+ return (EFTYPE);
+ /* get the entry record */
+ dex = _memstream_getregion(&ms, NULL, _CITRUS_DB_ENTRY_SIZE);
+ if (dex == NULL)
+ return (EFTYPE);
+ /* seek to the head of the key. */
+ if (_memstream_seek(&ms, be32toh(dex->dex_key_offset), SEEK_SET))
+ return (EFTYPE);
+ /* get the region of the key. */
+ if (_memstream_getregion(&ms, key, be32toh(dex->dex_key_size))==NULL)
+ return (EFTYPE);
+ /* seek to the head of the data. */
+ if (_memstream_seek(&ms, be32toh(dex->dex_data_offset), SEEK_SET))
+ return (EFTYPE);
+ /* get the region of the data. */
+ if (_memstream_getregion(&ms, data, be32toh(dex->dex_data_size))==NULL)
+ return (EFTYPE);
+
+ return (0);
+}
diff --git a/lib/libc/iconv/citrus_db.h b/lib/libc/iconv/citrus_db.h
new file mode 100644
index 000000000000..27e16f345cd5
--- /dev/null
+++ b/lib/libc/iconv/citrus_db.h
@@ -0,0 +1,70 @@
+/* $FreeBSD$ */
+/* $NetBSD: citrus_db.h,v 1.2 2008/02/09 14:56:20 junyoung Exp $ */
+
+/*-
+ * Copyright (c)2003 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _CITRUS_DB_H_
+#define _CITRUS_DB_H_
+
+#include "citrus_db_factory.h"
+
+struct _citrus_db;
+struct _citrus_db_locator {
+ uint32_t dl_hashval;
+ size_t dl_offset;
+};
+
+__BEGIN_DECLS
+int _citrus_db_open(struct _citrus_db **, struct _citrus_region *,
+ const char *, _citrus_db_hash_func_t, void *);
+void _citrus_db_close(struct _citrus_db *);
+int _citrus_db_lookup(struct _citrus_db *, struct _citrus_region *,
+ struct _citrus_region *, struct _citrus_db_locator *);
+int _citrus_db_lookup_by_string(struct _citrus_db *, const char *,
+ struct _citrus_region *, struct _citrus_db_locator *);
+int _citrus_db_lookup8_by_string(struct _citrus_db *, const char *,
+ uint8_t *, struct _citrus_db_locator *);
+int _citrus_db_lookup16_by_string(struct _citrus_db *, const char *,
+ uint16_t *, struct _citrus_db_locator *);
+int _citrus_db_lookup32_by_string(struct _citrus_db *, const char *,
+ uint32_t *, struct _citrus_db_locator *);
+int _citrus_db_lookup_string_by_string(struct _citrus_db *, const char *,
+ const char **, struct _citrus_db_locator *);
+int _citrus_db_get_number_of_entries(struct _citrus_db *);
+int _citrus_db_get_entry(struct _citrus_db *, int,
+ struct _citrus_region *, struct _citrus_region *);
+__END_DECLS
+
+static __inline void
+_citrus_db_locator_init(struct _citrus_db_locator *dl)
+{
+
+ dl->dl_hashval = 0;
+ dl->dl_offset = 0;
+}
+
+#endif
diff --git a/lib/libc/iconv/citrus_db_factory.c b/lib/libc/iconv/citrus_db_factory.c
new file mode 100644
index 000000000000..691fe4e84351
--- /dev/null
+++ b/lib/libc/iconv/citrus_db_factory.c
@@ -0,0 +1,337 @@
+/* $FreeBSD$ */
+/* $NetBSD: citrus_db_factory.c,v 1.10 2013/09/14 13:05:51 joerg Exp $ */
+
+/*-
+ * Copyright (c)2003 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+
+#include <arpa/inet.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "citrus_namespace.h"
+#include "citrus_region.h"
+#include "citrus_db_file.h"
+#include "citrus_db_factory.h"
+
+struct _citrus_db_factory_entry {
+ STAILQ_ENTRY(_citrus_db_factory_entry) de_entry;
+ struct _citrus_db_factory_entry *de_next;
+ uint32_t de_hashvalue;
+ struct _region de_key;
+ int de_key_free;
+ struct _region de_data;
+ int de_data_free;
+ int de_idx;
+};
+
+struct _citrus_db_factory {
+ size_t df_num_entries;
+ STAILQ_HEAD(, _citrus_db_factory_entry) df_entries;
+ size_t df_total_key_size;
+ size_t df_total_data_size;
+ uint32_t (*df_hashfunc)(struct _citrus_region *);
+ void *df_hashfunc_closure;
+};
+
+#define DB_ALIGN 16
+
+int
+_citrus_db_factory_create(struct _citrus_db_factory **rdf,
+ _citrus_db_hash_func_t hashfunc, void *hashfunc_closure)
+{
+ struct _citrus_db_factory *df;
+
+ df = malloc(sizeof(*df));
+ if (df == NULL)
+ return (errno);
+ df->df_num_entries = 0;
+ df->df_total_key_size = df->df_total_data_size = 0;
+ STAILQ_INIT(&df->df_entries);
+ df->df_hashfunc = hashfunc;
+ df->df_hashfunc_closure = hashfunc_closure;
+
+ *rdf = df;
+
+ return (0);
+}
+
+void
+_citrus_db_factory_free(struct _citrus_db_factory *df)
+{
+ struct _citrus_db_factory_entry *de;
+
+ while ((de = STAILQ_FIRST(&df->df_entries)) != NULL) {
+ STAILQ_REMOVE_HEAD(&df->df_entries, de_entry);
+ if (de->de_key_free)
+ free(_region_head(&de->de_key));
+ if (de->de_data_free)
+ free(_region_head(&de->de_data));
+ free(de);
+ }
+ free(df);
+}
+
+static __inline size_t
+ceilto(size_t sz)
+{
+ return ((sz + DB_ALIGN - 1) & ~(DB_ALIGN - 1));
+}
+
+int
+_citrus_db_factory_add(struct _citrus_db_factory *df, struct _region *key,
+ int keyfree, struct _region *data, int datafree)
+{
+ struct _citrus_db_factory_entry *de;
+
+ de = malloc(sizeof(*de));
+ if (de == NULL)
+ return (-1);
+
+ de->de_hashvalue = df->df_hashfunc(key);
+ de->de_key = *key;
+ de->de_key_free = keyfree;
+ de->de_data = *data;
+ de->de_data_free = datafree;
+ de->de_idx = -1;
+
+ STAILQ_INSERT_TAIL(&df->df_entries, de, de_entry);
+ df->df_total_key_size += _region_size(key);
+ df->df_total_data_size += ceilto(_region_size(data));
+ df->df_num_entries++;
+
+ return (0);
+
+}
+
+int
+_citrus_db_factory_add_by_string(struct _citrus_db_factory *df,
+ const char *key, struct _citrus_region *data, int datafree)
+{
+ struct _region r;
+ char *tmp;
+
+ tmp = strdup(key);
+ if (tmp == NULL)
+ return (errno);
+ _region_init(&r, tmp, strlen(key));
+ return _citrus_db_factory_add(df, &r, 1, data, datafree);
+}
+
+int
+_citrus_db_factory_add8_by_string(struct _citrus_db_factory *df,
+ const char *key, uint8_t val)
+{
+ struct _region r;
+ uint8_t *p;
+
+ p = malloc(sizeof(*p));
+ if (p == NULL)
+ return (errno);
+ *p = val;
+ _region_init(&r, p, 1);
+ return (_citrus_db_factory_add_by_string(df, key, &r, 1));
+}
+
+int
+_citrus_db_factory_add16_by_string(struct _citrus_db_factory *df,
+ const char *key, uint16_t val)
+{
+ struct _region r;
+ uint16_t *p;
+
+ p = malloc(sizeof(*p));
+ if (p == NULL)
+ return (errno);
+ *p = htons(val);
+ _region_init(&r, p, 2);
+ return (_citrus_db_factory_add_by_string(df, key, &r, 1));
+}
+
+int
+_citrus_db_factory_add32_by_string(struct _citrus_db_factory *df,
+ const char *key, uint32_t val)
+{
+ struct _region r;
+ uint32_t *p;
+
+ p = malloc(sizeof(*p));
+ if (p == NULL)
+ return (errno);
+ *p = htonl(val);
+ _region_init(&r, p, 4);
+ return (_citrus_db_factory_add_by_string(df, key, &r, 1));
+}
+
+int
+_citrus_db_factory_add_string_by_string(struct _citrus_db_factory *df,
+ const char *key, const char *data)
+{
+ char *p;
+ struct _region r;
+
+ p = strdup(data);
+ if (p == NULL)
+ return (errno);
+ _region_init(&r, p, strlen(p) + 1);
+ return (_citrus_db_factory_add_by_string(df, key, &r, 1));
+}
+
+size_t
+_citrus_db_factory_calc_size(struct _citrus_db_factory *df)
+{
+ size_t sz;
+
+ sz = ceilto(_CITRUS_DB_HEADER_SIZE);
+ sz += ceilto(_CITRUS_DB_ENTRY_SIZE * df->df_num_entries);
+ sz += ceilto(df->df_total_key_size);
+ sz += df->df_total_data_size;
+
+ return (sz);
+}
+
+static __inline void
+put8(struct _region *r, size_t *rofs, uint8_t val)
+{
+
+ *(uint8_t *)_region_offset(r, *rofs) = val;
+ *rofs += 1;
+}
+
+static __inline void
+put32(struct _region *r, size_t *rofs, uint32_t val)
+{
+
+ val = htonl(val);
+ memcpy(_region_offset(r, *rofs), &val, 4);
+ *rofs += 4;
+}
+
+static __inline void
+putpad(struct _region *r, size_t *rofs)
+{
+ size_t i;
+
+ for (i = ceilto(*rofs) - *rofs; i > 0; i--)
+ put8(r, rofs, 0);
+}
+
+static __inline void
+dump_header(struct _region *r, const char *magic, size_t *rofs,
+ size_t num_entries)
+{
+
+ while (*rofs<_CITRUS_DB_MAGIC_SIZE)
+ put8(r, rofs, *magic++);
+ put32(r, rofs, num_entries);
+ put32(r, rofs, _CITRUS_DB_HEADER_SIZE);
+}
+
+int
+_citrus_db_factory_serialize(struct _citrus_db_factory *df, const char *magic,
+ struct _region *r)
+{
+ struct _citrus_db_factory_entry *de, **depp, *det;
+ size_t dataofs, i, keyofs, nextofs, ofs;
+
+ ofs = 0;
+ /* check whether more than 0 entries exist */
+ if (df->df_num_entries == 0) {
+ dump_header(r, magic, &ofs, 0);
+ return (0);
+ }
+ /* allocate hash table */
+ depp = calloc(df->df_num_entries, sizeof(*depp));
+ if (depp == NULL)
+ return (-1);
+
+ /* step1: store the entries which are not conflicting */
+ STAILQ_FOREACH(de, &df->df_entries, de_entry) {
+ de->de_hashvalue %= df->df_num_entries;
+ de->de_idx = -1;
+ de->de_next = NULL;
+ if (depp[de->de_hashvalue] == NULL) {
+ depp[de->de_hashvalue] = de;
+ de->de_idx = (int)de->de_hashvalue;
+ }
+ }
+
+ /* step2: resolve conflicts */
+ i = 0;
+ STAILQ_FOREACH(de, &df->df_entries, de_entry) {
+ if (de->de_idx == -1) {
+ det = depp[de->de_hashvalue];
+ while (det->de_next != NULL)
+ det = det->de_next;
+ det->de_next = de;
+ while (depp[i] != NULL)
+ i++;
+ depp[i] = de;
+ de->de_idx = (int)i;
+ }
+ }
+
+ keyofs = _CITRUS_DB_HEADER_SIZE +
+ ceilto(df->df_num_entries*_CITRUS_DB_ENTRY_SIZE);
+ dataofs = keyofs + ceilto(df->df_total_key_size);
+
+ /* dump header */
+ dump_header(r, magic, &ofs, df->df_num_entries);
+
+ /* dump entries */
+ for (i = 0; i < df->df_num_entries; i++) {
+ de = depp[i];
+ nextofs = 0;
+ if (de->de_next) {
+ nextofs = _CITRUS_DB_HEADER_SIZE +
+ de->de_next->de_idx * _CITRUS_DB_ENTRY_SIZE;
+ }
+ put32(r, &ofs, de->de_hashvalue);
+ put32(r, &ofs, nextofs);
+ put32(r, &ofs, keyofs);
+ put32(r, &ofs, _region_size(&de->de_key));
+ put32(r, &ofs, dataofs);
+ put32(r, &ofs, _region_size(&de->de_data));
+ memcpy(_region_offset(r, keyofs),
+ _region_head(&de->de_key), _region_size(&de->de_key));
+ keyofs += _region_size(&de->de_key);
+ memcpy(_region_offset(r, dataofs),
+ _region_head(&de->de_data), _region_size(&de->de_data));
+ dataofs += _region_size(&de->de_data);
+ putpad(r, &dataofs);
+ }
+ putpad(r, &ofs);
+ putpad(r, &keyofs);
+ free(depp);
+
+ return (0);
+}
diff --git a/lib/libc/iconv/citrus_db_factory.h b/lib/libc/iconv/citrus_db_factory.h
new file mode 100644
index 000000000000..b98b19c9e7f0
--- /dev/null
+++ b/lib/libc/iconv/citrus_db_factory.h
@@ -0,0 +1,57 @@
+/* $FreeBSD$ */
+/* $NetBSD: citrus_db_factory.h,v 1.3 2008/02/09 14:56:20 junyoung Exp $ */
+
+/*-
+ * Copyright (c)2003 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _CITRUS_DB_FACTORY_H_
+#define _CITRUS_DB_FACTORY_H_
+
+struct _citrus_db_factory;
+typedef uint32_t (*_citrus_db_hash_func_t)(struct _citrus_region *);
+
+__BEGIN_DECLS
+int _citrus_db_factory_create(struct _citrus_db_factory **,
+ _citrus_db_hash_func_t, void *);
+void _citrus_db_factory_free(struct _citrus_db_factory *);
+int _citrus_db_factory_add(struct _citrus_db_factory *,
+ struct _citrus_region *, int, struct _citrus_region *, int);
+int _citrus_db_factory_add_by_string(struct _citrus_db_factory *,
+ const char *, struct _citrus_region *, int);
+int _citrus_db_factory_add8_by_string(struct _citrus_db_factory *,
+ const char *, uint8_t);
+int _citrus_db_factory_add16_by_string(struct _citrus_db_factory *,
+ const char *, uint16_t);
+int _citrus_db_factory_add32_by_string(struct _citrus_db_factory *,
+ const char *, uint32_t);
+int _citrus_db_factory_add_string_by_string(struct _citrus_db_factory *,
+ const char *, const char *);
+size_t _citrus_db_factory_calc_size(struct _citrus_db_factory *);
+int _citrus_db_factory_serialize(struct _citrus_db_factory *,
+ const char *, struct _citrus_region *);
+__END_DECLS
+
+#endif
diff --git a/lib/libc/iconv/citrus_db_file.h b/lib/libc/iconv/citrus_db_file.h
new file mode 100644
index 000000000000..aed07e8d1ea0
--- /dev/null
+++ b/lib/libc/iconv/citrus_db_file.h
@@ -0,0 +1,85 @@
+/* $FreeBSD$ */
+/* $NetBSD: citrus_db_file.h,v 1.4 2008/02/10 05:58:22 junyoung Exp $ */
+
+/*-
+ * Copyright (c)2003 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _CITRUS_DB_FILE_H_
+#define _CITRUS_DB_FILE_H_
+
+/*
+ * db format:
+ * +---
+ * | header
+ * | - magic
+ * | - num entries
+ * +---
+ * | entry directory
+ * | +------------
+ * | | entry0
+ * | | - hash value
+ * | | - next entry
+ * | | - key offset
+ * | | - key len
+ * | | - data offset
+ * | | - data size
+ * | |---
+ * | | entry1
+ * | | ..
+ * | | entryN
+ * | +---
+ * +---
+ * | key table
+ * | - key0
+ * | ...
+ * | - keyN
+ * +---
+ * | data table
+ * | - data0
+ * | ...
+ * | - dataN
+ * +---
+ */
+
+#define _CITRUS_DB_MAGIC_SIZE 8
+#define _CITRUS_DB_HEADER_SIZE 16
+struct _citrus_db_header_x {
+ char dhx_magic[_CITRUS_DB_MAGIC_SIZE];
+ uint32_t dhx_num_entries;
+ uint32_t dhx_entry_offset;
+} __packed;
+
+struct _citrus_db_entry_x {
+ uint32_t dex_hash_value;
+ uint32_t dex_next_offset;
+ uint32_t dex_key_offset;
+ uint32_t dex_key_size;
+ uint32_t dex_data_offset;
+ uint32_t dex_data_size;
+} __packed;
+#define _CITRUS_DB_ENTRY_SIZE 24
+
+#endif
diff --git a/lib/libc/iconv/citrus_db_hash.c b/lib/libc/iconv/citrus_db_hash.c
new file mode 100644
index 000000000000..2c599ff8ca77
--- /dev/null
+++ b/lib/libc/iconv/citrus_db_hash.c
@@ -0,0 +1,64 @@
+/* $FreeBSD$ */
+/* $NetBSD: citrus_db_hash.c,v 1.5 2008/02/09 14:56:20 junyoung Exp $ */
+
+/*-
+ * Copyright (c)2003 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "citrus_namespace.h"
+#include "citrus_types.h"
+#include "citrus_bcs.h"
+#include "citrus_region.h"
+#include "citrus_db_hash.h"
+
+uint32_t
+_citrus_db_hash_std(struct _region *r)
+{
+ const uint8_t *p;
+ uint32_t hash, tmp;
+ size_t i;
+
+ hash = 0;
+ p = _region_head(r);
+
+ for (i = _region_size(r); i > 0; i--) {
+ hash <<= 4;
+ hash += _bcs_tolower(*p);
+ tmp = hash & 0xF0000000;
+ if (tmp != 0) {
+ hash ^= tmp;
+ hash ^= tmp >> 24;
+ }
+ p++;
+ }
+ return (hash);
+}
diff --git a/lib/libc/iconv/citrus_db_hash.h b/lib/libc/iconv/citrus_db_hash.h
new file mode 100644
index 000000000000..549af2631b39
--- /dev/null
+++ b/lib/libc/iconv/citrus_db_hash.h
@@ -0,0 +1,37 @@
+/* $FreeBSD$ */
+/* $NetBSD: citrus_db_hash.h,v 1.2 2008/02/09 14:56:20 junyoung Exp $ */
+
+/*-
+ * Copyright (c)2003 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _CITRUS_DB_HASH_H_
+#define _CITRUS_DB_HASH_H_
+
+__BEGIN_DECLS
+uint32_t _citrus_db_hash_std(struct _citrus_region *);
+__END_DECLS
+
+#endif
diff --git a/lib/libc/iconv/citrus_esdb.c b/lib/libc/iconv/citrus_esdb.c
new file mode 100644
index 000000000000..299dd5ff8470
--- /dev/null
+++ b/lib/libc/iconv/citrus_esdb.c
@@ -0,0 +1,368 @@
+/* $FreeBSD$ */
+/* $NetBSD: citrus_esdb.c,v 1.5 2008/02/09 14:56:20 junyoung Exp $ */
+
+/*-
+ * Copyright (c)2003 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <paths.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "citrus_namespace.h"
+#include "citrus_types.h"
+#include "citrus_bcs.h"
+#include "citrus_region.h"
+#include "citrus_memstream.h"
+#include "citrus_mmap.h"
+#include "citrus_lookup.h"
+#include "citrus_db.h"
+#include "citrus_db_hash.h"
+#include "citrus_esdb.h"
+#include "citrus_esdb_file.h"
+
+#define ESDB_DIR "esdb.dir"
+#define ESDB_ALIAS "esdb.alias"
+
+/*
+ * _citrus_esdb_alias:
+ * resolve encoding scheme name aliases.
+ */
+const char *
+_citrus_esdb_alias(const char *esname, char *buf, size_t bufsize)
+{
+
+ return (_lookup_alias(_PATH_ESDB "/" ESDB_ALIAS, esname, buf, bufsize,
+ _LOOKUP_CASE_IGNORE));
+}
+
+
+/*
+ * conv_esdb:
+ * external representation -> local structure.
+ */
+static int
+conv_esdb(struct _citrus_esdb *esdb, struct _region *fr)
+{
+ struct _citrus_db *db;
+ const char *str;
+ char buf[100];
+ uint32_t csid, i, num_charsets, tmp, version;
+ int ret;
+
+ /* open db */
+ ret = _db_open(&db, fr, _CITRUS_ESDB_MAGIC, &_db_hash_std, NULL);
+ if (ret)
+ goto err0;
+
+ /* check version */
+ ret = _db_lookup32_by_s(db, _CITRUS_ESDB_SYM_VERSION, &version, NULL);
+ if (ret)
+ goto err1;
+ switch (version) {
+ case 0x00000001:
+ /* current version */
+ /* initial version */
+ break;
+ default:
+ ret = EFTYPE;
+ goto err1;
+ }
+
+ /* get encoding/variable */
+ ret = _db_lookupstr_by_s(db, _CITRUS_ESDB_SYM_ENCODING, &str, NULL);
+ if (ret)
+ goto err1;
+ esdb->db_encname = strdup(str);
+ if (esdb->db_encname == NULL) {
+ ret = errno;
+ goto err1;
+ }
+
+ esdb->db_len_variable = 0;
+ esdb->db_variable = NULL;
+ ret = _db_lookupstr_by_s(db, _CITRUS_ESDB_SYM_VARIABLE, &str, NULL);
+ if (ret == 0) {
+ esdb->db_len_variable = strlen(str) + 1;
+ esdb->db_variable = strdup(str);
+ if (esdb->db_variable == NULL) {
+ ret = errno;
+ goto err2;
+ }
+ } else if (ret != ENOENT)
+ goto err2;
+
+ /* get number of charsets */
+ ret = _db_lookup32_by_s(db, _CITRUS_ESDB_SYM_NUM_CHARSETS,
+ &num_charsets, NULL);
+ if (ret)
+ goto err3;
+ esdb->db_num_charsets = num_charsets;
+
+ /* get invalid character */
+ ret = _db_lookup32_by_s(db, _CITRUS_ESDB_SYM_INVALID, &tmp, NULL);
+ if (ret == 0) {
+ esdb->db_use_invalid = 1;
+ esdb->db_invalid = tmp;
+ } else if (ret == ENOENT)
+ esdb->db_use_invalid = 0;
+ else
+ goto err3;
+
+ /* get charsets */
+ esdb->db_charsets = malloc(num_charsets * sizeof(*esdb->db_charsets));
+ if (esdb->db_charsets == NULL) {
+ ret = errno;
+ goto err3;
+ }
+ for (i = 0; i < num_charsets; i++) {
+ snprintf(buf, sizeof(buf),
+ _CITRUS_ESDB_SYM_CSID_PREFIX "%d", i);
+ ret = _db_lookup32_by_s(db, buf, &csid, NULL);
+ if (ret)
+ goto err4;
+ esdb->db_charsets[i].ec_csid = csid;
+
+ snprintf(buf, sizeof(buf),
+ _CITRUS_ESDB_SYM_CSNAME_PREFIX "%d", i);
+ ret = _db_lookupstr_by_s(db, buf, &str, NULL);
+ if (ret)
+ goto err4;
+ esdb->db_charsets[i].ec_csname = strdup(str);
+ if (esdb->db_charsets[i].ec_csname == NULL) {
+ ret = errno;
+ goto err4;
+ }
+ }
+
+ _db_close(db);
+ return (0);
+
+err4:
+ for (; i > 0; i--)
+ free(esdb->db_charsets[i - 1].ec_csname);
+ free(esdb->db_charsets);
+err3:
+ free(esdb->db_variable);
+err2:
+ free(esdb->db_encname);
+err1:
+ _db_close(db);
+ if (ret == ENOENT)
+ ret = EFTYPE;
+err0:
+ return (ret);
+}
+
+/*
+ * _citrus_esdb_open:
+ * open an ESDB file.
+ */
+int
+_citrus_esdb_open(struct _citrus_esdb *db, const char *esname)
+{
+ struct _region fr;
+ const char *realname, *encfile;
+ char buf1[PATH_MAX], buf2[PATH_MAX], path[PATH_MAX];
+ int ret;
+
+ snprintf(path, sizeof(path), "%s/%s", _PATH_ESDB, ESDB_ALIAS);
+ realname = _lookup_alias(path, esname, buf1, sizeof(buf1),
+ _LOOKUP_CASE_IGNORE);
+
+ snprintf(path, sizeof(path), "%s/%s", _PATH_ESDB, ESDB_DIR);
+ encfile = _lookup_simple(path, realname, buf2, sizeof(buf2),
+ _LOOKUP_CASE_IGNORE);
+ if (encfile == NULL)
+ return (ENOENT);
+
+ /* open file */
+ snprintf(path, sizeof(path), "%s/%s", _PATH_ESDB, encfile);
+ ret = _map_file(&fr, path);
+ if (ret)
+ return (ret);
+
+ ret = conv_esdb(db, &fr);
+
+ _unmap_file(&fr);
+
+ return (ret);
+}
+
+/*
+ * _citrus_esdb_close:
+ * free an ESDB.
+ */
+void
+_citrus_esdb_close(struct _citrus_esdb *db)
+{
+
+ for (int i = 0; i < db->db_num_charsets; i++)
+ free(db->db_charsets[i].ec_csname);
+ db->db_num_charsets = 0;
+ free(db->db_charsets); db->db_charsets = NULL;
+ free(db->db_encname); db->db_encname = NULL;
+ db->db_len_variable = 0;
+ free(db->db_variable); db->db_variable = NULL;
+}
+
+/*
+ * _citrus_esdb_free_list:
+ * free the list.
+ */
+void
+_citrus_esdb_free_list(char **list, size_t num)
+{
+
+ for (size_t i = 0; i < num; i++)
+ free(list[i]);
+ free(list);
+}
+
+/*
+ * _citrus_esdb_get_list:
+ * get esdb entries.
+ */
+int
+_citrus_esdb_get_list(char ***rlist, size_t *rnum, bool sorted)
+{
+ struct _citrus_lookup *cla, *cld;
+ struct _region key, data;
+ char **list, **q;
+ char buf[PATH_MAX];
+ size_t num;
+ int ret;
+
+ num = 0;
+
+ ret = _lookup_seq_open(&cla, _PATH_ESDB "/" ESDB_ALIAS,
+ _LOOKUP_CASE_IGNORE);
+ if (ret)
+ goto quit0;
+
+ ret = _lookup_seq_open(&cld, _PATH_ESDB "/" ESDB_DIR,
+ _LOOKUP_CASE_IGNORE);
+ if (ret)
+ goto quit1;
+
+ /* count number of entries */
+ num = _lookup_get_num_entries(cla) + _lookup_get_num_entries(cld);
+
+ _lookup_seq_rewind(cla);
+ _lookup_seq_rewind(cld);
+
+ /* allocate list pointer space */
+ list = malloc(num * sizeof(char *));
+ num = 0;
+ if (list == NULL) {
+ ret = errno;
+ goto quit3;
+ }
+
+ /* get alias entries */
+ while ((ret = _lookup_seq_next(cla, &key, &data)) == 0) {
+ /* XXX: sorted? */
+ snprintf(buf, sizeof(buf), "%.*s/%.*s",
+ (int)_region_size(&data),
+ (const char *)_region_head(&data),
+ (int)_region_size(&key),
+ (const char *)_region_head(&key));
+ _bcs_convert_to_upper(buf);
+ list[num] = strdup(buf);
+ if (list[num] == NULL) {
+ ret = errno;
+ goto quit3;
+ }
+ num++;
+ }
+ if (ret != ENOENT)
+ goto quit3;
+ /* get dir entries */
+ while ((ret = _lookup_seq_next(cld, &key, &data)) == 0) {
+ if (!sorted)
+ snprintf(buf, sizeof(buf), "%.*s",
+ (int)_region_size(&key),
+ (const char *)_region_head(&key));
+ else {
+ /* check duplicated entry */
+ char *p;
+ char buf1[PATH_MAX];
+
+ snprintf(buf1, sizeof(buf1), "%.*s",
+ (int)_region_size(&data),
+ (const char *)_region_head(&data));
+ if ((p = strchr(buf1, '/')) != NULL)
+ memmove(buf1, p + 1, strlen(p) - 1);
+ if ((p = strstr(buf1, ".esdb")) != NULL)
+ *p = '\0';
+ snprintf(buf, sizeof(buf), "%s/%.*s", buf1,
+ (int)_region_size(&key),
+ (const char *)_region_head(&key));
+ }
+ _bcs_convert_to_upper(buf);
+ ret = _lookup_seq_lookup(cla, buf, NULL);
+ if (ret) {
+ if (ret != ENOENT)
+ goto quit3;
+ /* not duplicated */
+ list[num] = strdup(buf);
+ if (list[num] == NULL) {
+ ret = errno;
+ goto quit3;
+ }
+ num++;
+ }
+ }
+ if (ret != ENOENT)
+ goto quit3;
+
+ ret = 0;
+ /* XXX: why reallocing the list space posteriorly?
+ shouldn't be done earlier? */
+ q = realloc(list, num * sizeof(char *));
+ if (!q) {
+ ret = ENOMEM;
+ goto quit3;
+ }
+ list = q;
+ *rlist = list;
+ *rnum = num;
+quit3:
+ if (ret)
+ _citrus_esdb_free_list(list, num);
+ _lookup_seq_close(cld);
+quit1:
+ _lookup_seq_close(cla);
+quit0:
+ return (ret);
+}
diff --git a/lib/libc/iconv/citrus_esdb.h b/lib/libc/iconv/citrus_esdb.h
new file mode 100644
index 000000000000..f82a3989a43c
--- /dev/null
+++ b/lib/libc/iconv/citrus_esdb.h
@@ -0,0 +1,58 @@
+/* $FreeBSD$ */
+/* $NetBSD: citrus_esdb.h,v 1.1 2003/06/25 09:51:32 tshiozak Exp $ */
+
+/*-
+ * Copyright (c)2003 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _CITRUS_ESDB_H_
+#define _CITRUS_ESDB_H_
+
+#include "citrus_types.h"
+
+struct _citrus_esdb_charset {
+ _citrus_csid_t ec_csid;
+ char *ec_csname;
+};
+
+struct _citrus_esdb {
+ char *db_encname;
+ void *db_variable;
+ size_t db_len_variable;
+ int db_num_charsets;
+ struct _citrus_esdb_charset *db_charsets;
+ int db_use_invalid;
+ _citrus_wc_t db_invalid;
+};
+
+__BEGIN_DECLS
+const char *_citrus_esdb_alias(const char *, char *, size_t);
+int _citrus_esdb_open(struct _citrus_esdb *, const char *);
+void _citrus_esdb_close(struct _citrus_esdb *);
+void _citrus_esdb_free_list(char **, size_t);
+int _citrus_esdb_get_list(char ***, size_t *, bool);
+__END_DECLS
+
+#endif
diff --git a/lib/libc/iconv/citrus_esdb_file.h b/lib/libc/iconv/citrus_esdb_file.h
new file mode 100644
index 000000000000..98609d1ecd42
--- /dev/null
+++ b/lib/libc/iconv/citrus_esdb_file.h
@@ -0,0 +1,45 @@
+/* $FreeBSD$ */
+/* $NetBSD: citrus_esdb_file.h,v 1.1 2003/06/25 09:51:32 tshiozak Exp $ */
+
+/*-
+ * Copyright (c)2003 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _CITRUS_ESDB_FILE_H_
+#define _CITRUS_ESDB_FILE_H_
+
+#define _CITRUS_ESDB_MAGIC "ESDB\0\0\0\0"
+
+#define _CITRUS_ESDB_SYM_VERSION "version"
+#define _CITRUS_ESDB_SYM_ENCODING "encoding"
+#define _CITRUS_ESDB_SYM_VARIABLE "variable"
+#define _CITRUS_ESDB_SYM_NUM_CHARSETS "num_charsets"
+#define _CITRUS_ESDB_SYM_INVALID "invalid"
+#define _CITRUS_ESDB_SYM_CSNAME_PREFIX "csname_"
+#define _CITRUS_ESDB_SYM_CSID_PREFIX "csid_"
+
+#define _CITRUS_ESDB_VERSION 0x00000001
+
+#endif
diff --git a/lib/libc/iconv/citrus_fix_grouping.h b/lib/libc/iconv/citrus_fix_grouping.h
new file mode 100644
index 000000000000..fbb1788e776b
--- /dev/null
+++ b/lib/libc/iconv/citrus_fix_grouping.h
@@ -0,0 +1,53 @@
+/* $FreeBSD$ */
+/* $NetBSD: citrus_fix_grouping.h,v 1.2 2009/01/11 02:46:24 christos Exp $ */
+
+/*-
+ * Copyright (c)2008 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _CITRUS_FIX_GROUPING_H_
+#define _CITRUS_FIX_GROUPING_H_
+
+#define _CITRUS_LC_GROUPING_VALUE_MIN 0
+#define _CITRUS_LC_GROUPING_VALUE_MAX 126
+#define _CITRUS_LC_GROUPING_VALUE_NO_FUTHER 127
+
+#if CHAR_MAX != _CITRUS_LC_GROUPING_VALUE_NO_FUTHER
+static __inline void
+_citrus_fixup_char_max_md(char *grouping)
+{
+ char *p;
+
+ for (p = grouping; *p != '\0'; ++p)
+ if (*p == _CITRUS_LC_GROUPING_VALUE_NO_FUTHER)
+ *p = (char)CHAR_MAX;
+}
+#define _CITRUS_FIXUP_CHAR_MAX_MD(grouping) \
+ _citrus_fixup_char_max_md(__DECONST(void *, grouping))
+#else
+#define _CITRUS_FIXUP_CHAR_MAX_MD(grouping) /* nothing to do */
+#endif
+
+#endif /*_CITRUS_FIX_GROUPING_H_*/
diff --git a/lib/libc/iconv/citrus_hash.c b/lib/libc/iconv/citrus_hash.c
new file mode 100644
index 000000000000..4db1bda47305
--- /dev/null
+++ b/lib/libc/iconv/citrus_hash.c
@@ -0,0 +1,51 @@
+/* $FreeBSD$ */
+/* $NetBSD: citrus_hash.c,v 1.3 2008/02/09 14:56:20 junyoung Exp $ */
+
+/*-
+ * Copyright (c)2003 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "citrus_namespace.h"
+#include "citrus_types.h"
+#include "citrus_region.h"
+#include "citrus_hash.h"
+#include "citrus_db_hash.h"
+
+int
+_citrus_string_hash_func(const char *key, int hashsize)
+{
+ struct _region r;
+
+ _region_init(&r, __DECONST(void *, key), strlen(key));
+
+ return ((int)(_db_hash_std(&r) % (uint32_t)hashsize));
+}
diff --git a/lib/libc/iconv/citrus_hash.h b/lib/libc/iconv/citrus_hash.h
new file mode 100644
index 000000000000..c3e73118571f
--- /dev/null
+++ b/lib/libc/iconv/citrus_hash.h
@@ -0,0 +1,59 @@
+/* $FreeBSD$ */
+/* $NetBSD: citrus_hash.h,v 1.3 2004/01/02 21:49:35 itojun Exp $ */
+
+/*-
+ * Copyright (c)2003 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _CITRUS_HASH_H_
+#define _CITRUS_HASH_H_
+
+#define _CITRUS_HASH_ENTRY(type) LIST_ENTRY(type)
+#define _CITRUS_HASH_HEAD(headname, type, hashsize) \
+struct headname { \
+ LIST_HEAD(, type) chh_table[hashsize]; \
+}
+#define _CITRUS_HASH_INIT(head, hashsize) \
+do { \
+ int _ch_loop; \
+ \
+ for (_ch_loop = 0; _ch_loop < hashsize; _ch_loop++) \
+ LIST_INIT(&(head)->chh_table[_ch_loop]); \
+} while (0)
+#define _CITRUS_HASH_REMOVE(elm, field) LIST_REMOVE(elm, field)
+#define _CITRUS_HASH_INSERT(head, elm, field, hashval) \
+ LIST_INSERT_HEAD(&(head)->chh_table[hashval], elm, field)
+#define _CITRUS_HASH_SEARCH(head, elm, field, matchfunc, key, hashval) \
+do { \
+ LIST_FOREACH((elm), &(head)->chh_table[hashval], field) \
+ if (matchfunc((elm), key) == 0) \
+ break; \
+} while (0)
+
+__BEGIN_DECLS
+int _citrus_string_hash_func(const char *, int);
+__END_DECLS
+
+#endif
diff --git a/lib/libc/iconv/citrus_iconv.c b/lib/libc/iconv/citrus_iconv.c
new file mode 100644
index 000000000000..59940631f53b
--- /dev/null
+++ b/lib/libc/iconv/citrus_iconv.c
@@ -0,0 +1,359 @@
+/* $FreeBSD$ */
+/* $NetBSD: citrus_iconv.c,v 1.10 2011/11/19 18:34:21 tnozaki Exp $ */
+
+/*-
+ * Copyright (c)2003 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+
+#include <assert.h>
+#include <dirent.h>
+#include <errno.h>
+#include <iconv.h>
+#include <langinfo.h>
+#include <limits.h>
+#include <paths.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "citrus_namespace.h"
+#include "citrus_bcs.h"
+#include "citrus_esdb.h"
+#include "citrus_region.h"
+#include "citrus_memstream.h"
+#include "citrus_mmap.h"
+#include "citrus_module.h"
+#include "citrus_lock.h"
+#include "citrus_lookup.h"
+#include "citrus_hash.h"
+#include "citrus_iconv.h"
+
+#define _CITRUS_ICONV_DIR "iconv.dir"
+#define _CITRUS_ICONV_ALIAS "iconv.alias"
+
+#define CI_HASH_SIZE 101
+#define CI_INITIAL_MAX_REUSE 5
+#define CI_ENV_MAX_REUSE "ICONV_MAX_REUSE"
+
+static bool isinit = false;
+static int shared_max_reuse, shared_num_unused;
+static _CITRUS_HASH_HEAD(, _citrus_iconv_shared, CI_HASH_SIZE) shared_pool;
+static TAILQ_HEAD(, _citrus_iconv_shared) shared_unused;
+
+static pthread_rwlock_t ci_lock = PTHREAD_RWLOCK_INITIALIZER;
+
+static __inline void
+init_cache(void)
+{
+
+ WLOCK(&ci_lock);
+ if (!isinit) {
+ _CITRUS_HASH_INIT(&shared_pool, CI_HASH_SIZE);
+ TAILQ_INIT(&shared_unused);
+ shared_max_reuse = -1;
+ if (!issetugid() && getenv(CI_ENV_MAX_REUSE))
+ shared_max_reuse = atoi(getenv(CI_ENV_MAX_REUSE));
+ if (shared_max_reuse < 0)
+ shared_max_reuse = CI_INITIAL_MAX_REUSE;
+ isinit = true;
+ }
+ UNLOCK(&ci_lock);
+}
+
+static __inline void
+close_shared(struct _citrus_iconv_shared *ci)
+{
+
+ if (ci) {
+ if (ci->ci_module) {
+ if (ci->ci_ops) {
+ if (ci->ci_closure)
+ (*ci->ci_ops->io_uninit_shared)(ci);
+ free(ci->ci_ops);
+ }
+ _citrus_unload_module(ci->ci_module);
+ }
+ free(ci);
+ }
+}
+
+static __inline int
+open_shared(struct _citrus_iconv_shared * __restrict * __restrict rci,
+ const char * __restrict convname, const char * __restrict src,
+ const char * __restrict dst)
+{
+ struct _citrus_iconv_shared *ci;
+ _citrus_iconv_getops_t getops;
+ const char *module;
+ size_t len_convname;
+ int ret;
+
+#ifdef INCOMPATIBLE_WITH_GNU_ICONV
+ /*
+ * Sadly, the gnu tools expect iconv to actually parse the
+ * byte stream and don't allow for a pass-through when
+ * the (src,dest) encodings are the same.
+ * See gettext-0.18.3+ NEWS:
+ * msgfmt now checks PO file headers more strictly with less
+ * false-positives.
+ * NetBSD don't do this either.
+ */
+ module = (strcmp(src, dst) != 0) ? "iconv_std" : "iconv_none";
+#else
+ module = "iconv_std";
+#endif
+
+ /* initialize iconv handle */
+ len_convname = strlen(convname);
+ ci = malloc(sizeof(*ci) + len_convname + 1);
+ if (!ci) {
+ ret = errno;
+ goto err;
+ }
+ ci->ci_module = NULL;
+ ci->ci_ops = NULL;
+ ci->ci_closure = NULL;
+ ci->ci_convname = (void *)&ci[1];
+ memcpy(ci->ci_convname, convname, len_convname + 1);
+
+ /* load module */
+ ret = _citrus_load_module(&ci->ci_module, module);
+ if (ret)
+ goto err;
+
+ /* get operators */
+ getops = (_citrus_iconv_getops_t)_citrus_find_getops(ci->ci_module,
+ module, "iconv");
+ if (!getops) {
+ ret = EOPNOTSUPP;
+ goto err;
+ }
+ ci->ci_ops = malloc(sizeof(*ci->ci_ops));
+ if (!ci->ci_ops) {
+ ret = errno;
+ goto err;
+ }
+ ret = (*getops)(ci->ci_ops);
+ if (ret)
+ goto err;
+
+ if (ci->ci_ops->io_init_shared == NULL ||
+ ci->ci_ops->io_uninit_shared == NULL ||
+ ci->ci_ops->io_init_context == NULL ||
+ ci->ci_ops->io_uninit_context == NULL ||
+ ci->ci_ops->io_convert == NULL) {
+ ret = EINVAL;
+ goto err;
+ }
+
+ /* initialize the converter */
+ ret = (*ci->ci_ops->io_init_shared)(ci, src, dst);
+ if (ret)
+ goto err;
+
+ *rci = ci;
+
+ return (0);
+err:
+ close_shared(ci);
+ return (ret);
+}
+
+static __inline int
+hash_func(const char *key)
+{
+
+ return (_string_hash_func(key, CI_HASH_SIZE));
+}
+
+static __inline int
+match_func(struct _citrus_iconv_shared * __restrict ci,
+ const char * __restrict key)
+{
+
+ return (strcmp(ci->ci_convname, key));
+}
+
+static int
+get_shared(struct _citrus_iconv_shared * __restrict * __restrict rci,
+ const char *src, const char *dst)
+{
+ struct _citrus_iconv_shared * ci;
+ char convname[PATH_MAX];
+ int hashval, ret = 0;
+
+ snprintf(convname, sizeof(convname), "%s/%s", src, dst);
+
+ WLOCK(&ci_lock);
+
+ /* lookup alread existing entry */
+ hashval = hash_func(convname);
+ _CITRUS_HASH_SEARCH(&shared_pool, ci, ci_hash_entry, match_func,
+ convname, hashval);
+ if (ci != NULL) {
+ /* found */
+ if (ci->ci_used_count == 0) {
+ TAILQ_REMOVE(&shared_unused, ci, ci_tailq_entry);
+ shared_num_unused--;
+ }
+ ci->ci_used_count++;
+ *rci = ci;
+ goto quit;
+ }
+
+ /* create new entry */
+ ret = open_shared(&ci, convname, src, dst);
+ if (ret)
+ goto quit;
+
+ _CITRUS_HASH_INSERT(&shared_pool, ci, ci_hash_entry, hashval);
+ ci->ci_used_count = 1;
+ *rci = ci;
+
+quit:
+ UNLOCK(&ci_lock);
+
+ return (ret);
+}
+
+static void
+release_shared(struct _citrus_iconv_shared * __restrict ci)
+{
+
+ WLOCK(&ci_lock);
+ ci->ci_used_count--;
+ if (ci->ci_used_count == 0) {
+ /* put it into unused list */
+ shared_num_unused++;
+ TAILQ_INSERT_TAIL(&shared_unused, ci, ci_tailq_entry);
+ /* flood out */
+ while (shared_num_unused > shared_max_reuse) {
+ ci = TAILQ_FIRST(&shared_unused);
+ TAILQ_REMOVE(&shared_unused, ci, ci_tailq_entry);
+ _CITRUS_HASH_REMOVE(ci, ci_hash_entry);
+ shared_num_unused--;
+ close_shared(ci);
+ }
+ }
+
+ UNLOCK(&ci_lock);
+}
+
+/*
+ * _citrus_iconv_open:
+ * open a converter for the specified in/out codes.
+ */
+int
+_citrus_iconv_open(struct _citrus_iconv * __restrict * __restrict rcv,
+ const char * __restrict src, const char * __restrict dst)
+{
+ struct _citrus_iconv *cv = NULL;
+ struct _citrus_iconv_shared *ci = NULL;
+ char realdst[PATH_MAX], realsrc[PATH_MAX];
+#ifdef _PATH_ICONV
+ char buf[PATH_MAX], path[PATH_MAX];
+#endif
+ int ret;
+
+ init_cache();
+
+ /* GNU behaviour, using locale encoding if "" or "char" is specified */
+ if ((strcmp(src, "") == 0) || (strcmp(src, "char") == 0))
+ src = nl_langinfo(CODESET);
+ if ((strcmp(dst, "") == 0) || (strcmp(dst, "char") == 0))
+ dst = nl_langinfo(CODESET);
+
+ /* resolve codeset name aliases */
+#ifdef _PATH_ICONV
+ snprintf(path, sizeof(path), "%s/%s", _PATH_ICONV, _CITRUS_ICONV_ALIAS);
+ strlcpy(realsrc, _lookup_alias(path, src, buf, (size_t)PATH_MAX,
+ _LOOKUP_CASE_IGNORE), (size_t)PATH_MAX);
+ strlcpy(realdst, _lookup_alias(path, dst, buf, (size_t)PATH_MAX,
+ _LOOKUP_CASE_IGNORE), (size_t)PATH_MAX);
+#else
+ strlcpy(realsrc, src, (size_t)PATH_MAX);
+ strlcpy(realdst, dst, (size_t)PATH_MAX);
+#endif
+
+ /* sanity check */
+ if (strchr(realsrc, '/') != NULL || strchr(realdst, '/'))
+ return (EINVAL);
+
+ /* get shared record */
+ ret = get_shared(&ci, realsrc, realdst);
+ if (ret)
+ return (ret);
+
+ /* create/init context */
+ if (*rcv == NULL) {
+ cv = malloc(sizeof(*cv));
+ if (cv == NULL) {
+ ret = errno;
+ release_shared(ci);
+ return (ret);
+ }
+ *rcv = cv;
+ }
+ (*rcv)->cv_shared = ci;
+ ret = (*ci->ci_ops->io_init_context)(*rcv);
+ if (ret) {
+ release_shared(ci);
+ free(cv);
+ return (ret);
+ }
+ return (0);
+}
+
+/*
+ * _citrus_iconv_close:
+ * close the specified converter.
+ */
+void
+_citrus_iconv_close(struct _citrus_iconv *cv)
+{
+
+ if (cv) {
+ (*cv->cv_shared->ci_ops->io_uninit_context)(cv);
+ release_shared(cv->cv_shared);
+ free(cv);
+ }
+}
+
+const char
+*_citrus_iconv_canonicalize(const char *name)
+{
+ char *buf;
+
+ if ((buf = calloc((size_t)PATH_MAX, sizeof(*buf))) == NULL)
+ return (NULL);
+ _citrus_esdb_alias(name, buf, (size_t)PATH_MAX);
+ return (buf);
+}
diff --git a/lib/libc/iconv/citrus_iconv.h b/lib/libc/iconv/citrus_iconv.h
new file mode 100644
index 000000000000..99604e92063d
--- /dev/null
+++ b/lib/libc/iconv/citrus_iconv.h
@@ -0,0 +1,64 @@
+/* $FreeBSD$ */
+/* $NetBSD: citrus_iconv.h,v 1.5 2008/02/09 14:56:20 junyoung Exp $ */
+
+/*-
+ * Copyright (c)2003 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _CITRUS_ICONV_H_
+#define _CITRUS_ICONV_H_
+
+struct _citrus_iconv_shared;
+struct _citrus_iconv_ops;
+struct _citrus_iconv;
+
+__BEGIN_DECLS
+int _citrus_iconv_open(struct _citrus_iconv * __restrict * __restrict,
+ const char * __restrict, const char * __restrict);
+void _citrus_iconv_close(struct _citrus_iconv *);
+const char *_citrus_iconv_canonicalize(const char *);
+__END_DECLS
+
+
+#include "citrus_iconv_local.h"
+
+#define _CITRUS_ICONV_F_HIDE_INVALID 0x0001
+
+/*
+ * _citrus_iconv_convert:
+ * convert a string.
+ */
+static __inline int
+_citrus_iconv_convert(struct _citrus_iconv * __restrict cv,
+ char * __restrict * __restrict in, size_t * __restrict inbytes,
+ char * __restrict * __restrict out, size_t * __restrict outbytes,
+ uint32_t flags, size_t * __restrict nresults)
+{
+
+ return (*cv->cv_shared->ci_ops->io_convert)(cv, in, inbytes, out,
+ outbytes, flags, nresults);
+}
+
+#endif
diff --git a/lib/libc/iconv/citrus_iconv_local.h b/lib/libc/iconv/citrus_iconv_local.h
new file mode 100644
index 000000000000..5392da1ddf20
--- /dev/null
+++ b/lib/libc/iconv/citrus_iconv_local.h
@@ -0,0 +1,110 @@
+/* $FreeBSD$ */
+/* $NetBSD: citrus_iconv_local.h,v 1.3 2008/02/09 14:56:20 junyoung Exp $ */
+
+/*-
+ * Copyright (c)2003 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _CITRUS_ICONV_LOCAL_H_
+#define _CITRUS_ICONV_LOCAL_H_
+
+#include <iconv.h>
+#include <stdbool.h>
+
+#define _CITRUS_ICONV_GETOPS_FUNC_BASE(_n_) \
+ int _n_(struct _citrus_iconv_ops *)
+#define _CITRUS_ICONV_GETOPS_FUNC(_n_) \
+ _CITRUS_ICONV_GETOPS_FUNC_BASE(_citrus_##_n_##_iconv_getops)
+
+#define _CITRUS_ICONV_DECLS(_m_) \
+static int _citrus_##_m_##_iconv_init_shared \
+ (struct _citrus_iconv_shared * __restrict, \
+ const char * __restrict, const char * __restrict); \
+static void _citrus_##_m_##_iconv_uninit_shared \
+ (struct _citrus_iconv_shared *); \
+static int _citrus_##_m_##_iconv_convert \
+ (struct _citrus_iconv * __restrict, \
+ char * __restrict * __restrict, \
+ size_t * __restrict, \
+ char * __restrict * __restrict, \
+ size_t * __restrict outbytes, \
+ uint32_t, size_t * __restrict); \
+static int _citrus_##_m_##_iconv_init_context \
+ (struct _citrus_iconv *); \
+static void _citrus_##_m_##_iconv_uninit_context \
+ (struct _citrus_iconv *)
+
+
+#define _CITRUS_ICONV_DEF_OPS(_m_) \
+extern struct _citrus_iconv_ops _citrus_##_m_##_iconv_ops; \
+struct _citrus_iconv_ops _citrus_##_m_##_iconv_ops = { \
+ /* io_init_shared */ &_citrus_##_m_##_iconv_init_shared, \
+ /* io_uninit_shared */ &_citrus_##_m_##_iconv_uninit_shared, \
+ /* io_init_context */ &_citrus_##_m_##_iconv_init_context, \
+ /* io_uninit_context */ &_citrus_##_m_##_iconv_uninit_context, \
+ /* io_convert */ &_citrus_##_m_##_iconv_convert \
+}
+
+typedef _CITRUS_ICONV_GETOPS_FUNC_BASE((*_citrus_iconv_getops_t));
+typedef int (*_citrus_iconv_init_shared_t)
+ (struct _citrus_iconv_shared * __restrict,
+ const char * __restrict, const char * __restrict);
+typedef void (*_citrus_iconv_uninit_shared_t)
+ (struct _citrus_iconv_shared *);
+typedef int (*_citrus_iconv_convert_t)
+ (struct _citrus_iconv * __restrict,
+ char *__restrict* __restrict, size_t * __restrict,
+ char * __restrict * __restrict, size_t * __restrict, uint32_t,
+ size_t * __restrict);
+typedef int (*_citrus_iconv_init_context_t)(struct _citrus_iconv *);
+typedef void (*_citrus_iconv_uninit_context_t)(struct _citrus_iconv *);
+
+struct _citrus_iconv_ops {
+ _citrus_iconv_init_shared_t io_init_shared;
+ _citrus_iconv_uninit_shared_t io_uninit_shared;
+ _citrus_iconv_init_context_t io_init_context;
+ _citrus_iconv_uninit_context_t io_uninit_context;
+ _citrus_iconv_convert_t io_convert;
+};
+
+struct _citrus_iconv_shared {
+ struct _citrus_iconv_ops *ci_ops;
+ void *ci_closure;
+ _CITRUS_HASH_ENTRY(_citrus_iconv_shared) ci_hash_entry;
+ TAILQ_ENTRY(_citrus_iconv_shared) ci_tailq_entry;
+ _citrus_module_t ci_module;
+ unsigned int ci_used_count;
+ char *ci_convname;
+ bool ci_discard_ilseq;
+ struct iconv_hooks *ci_hooks;
+ bool ci_ilseq_invalid;
+};
+
+struct _citrus_iconv {
+ struct _citrus_iconv_shared *cv_shared;
+ void *cv_closure;
+};
+
+#endif
diff --git a/lib/libc/iconv/citrus_lock.h b/lib/libc/iconv/citrus_lock.h
new file mode 100644
index 000000000000..395064453b67
--- /dev/null
+++ b/lib/libc/iconv/citrus_lock.h
@@ -0,0 +1,33 @@
+/* $FreeBSD$ */
+/*-
+ * Copyright (C) 2010 Gabor Kovesdan <gabor@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <pthread.h>
+
+#define WLOCK(lock) if (__isthreaded) \
+ pthread_rwlock_wrlock(lock);
+#define UNLOCK(lock) if (__isthreaded) \
+ pthread_rwlock_unlock(lock);
diff --git a/lib/libc/iconv/citrus_lookup.c b/lib/libc/iconv/citrus_lookup.c
new file mode 100644
index 000000000000..bb9934a4847f
--- /dev/null
+++ b/lib/libc/iconv/citrus_lookup.c
@@ -0,0 +1,362 @@
+/* $FreeBSD$ */
+/* $NetBSD: citrus_lookup.c,v 1.7 2012/05/04 16:45:05 joerg Exp $ */
+
+/*-
+ * Copyright (c)2003 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+#include <assert.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "citrus_namespace.h"
+#include "citrus_bcs.h"
+#include "citrus_region.h"
+#include "citrus_memstream.h"
+#include "citrus_mmap.h"
+#include "citrus_db.h"
+#include "citrus_db_hash.h"
+#include "citrus_lookup.h"
+#include "citrus_lookup_file.h"
+
+struct _citrus_lookup {
+ union {
+ struct {
+ struct _citrus_db *db;
+ struct _citrus_region file;
+ int num, idx;
+ struct _db_locator locator;
+ } db;
+ struct {
+ struct _region r;
+ struct _memstream ms;
+ } plain;
+ } u;
+#define cl_db u.db.db
+#define cl_dbidx u.db.idx
+#define cl_dbfile u.db.file
+#define cl_dbnum u.db.num
+#define cl_dblocator u.db.locator
+#define cl_plainr u.plain.r
+#define cl_plainms u.plain.ms
+ int cl_ignore_case;
+ int cl_rewind;
+ char *cl_key;
+ size_t cl_keylen;
+ int (*cl_next)(struct _citrus_lookup *, struct _region *,
+ struct _region *);
+ int (*cl_lookup)(struct _citrus_lookup *, const char *,
+ struct _region *);
+ int (*cl_num_entries)(struct _citrus_lookup *);
+ void (*cl_close)(struct _citrus_lookup *);
+};
+
+static int
+seq_get_num_entries_db(struct _citrus_lookup *cl)
+{
+
+ return (cl->cl_dbnum);
+}
+
+static int
+seq_next_db(struct _citrus_lookup *cl, struct _region *key,
+ struct _region *data)
+{
+
+ if (cl->cl_key) {
+ if (key)
+ _region_init(key, cl->cl_key, cl->cl_keylen);
+ return (_db_lookup_by_s(cl->cl_db, cl->cl_key, data,
+ &cl->cl_dblocator));
+ }
+
+ if (cl->cl_rewind) {
+ cl->cl_dbidx = 0;
+ }
+ cl->cl_rewind = 0;
+ if (cl->cl_dbidx >= cl->cl_dbnum)
+ return (ENOENT);
+
+ return (_db_get_entry(cl->cl_db, cl->cl_dbidx++, key, data));
+}
+
+static int
+seq_lookup_db(struct _citrus_lookup *cl, const char *key, struct _region *data)
+{
+
+ cl->cl_rewind = 0;
+ free(cl->cl_key);
+ cl->cl_key = strdup(key);
+ if (cl->cl_ignore_case)
+ _bcs_convert_to_lower(cl->cl_key);
+ cl->cl_keylen = strlen(cl->cl_key);
+ _db_locator_init(&cl->cl_dblocator);
+ return (_db_lookup_by_s(cl->cl_db, cl->cl_key, data,
+ &cl->cl_dblocator));
+}
+
+static void
+seq_close_db(struct _citrus_lookup *cl)
+{
+
+ _db_close(cl->cl_db);
+ _unmap_file(&cl->cl_dbfile);
+}
+
+static int
+seq_open_db(struct _citrus_lookup *cl, const char *name)
+{
+ struct _region r;
+ char path[PATH_MAX];
+ int ret;
+
+ snprintf(path, sizeof(path), "%s.db", name);
+ ret = _map_file(&r, path);
+ if (ret)
+ return (ret);
+
+ ret = _db_open(&cl->cl_db, &r, _CITRUS_LOOKUP_MAGIC,
+ _db_hash_std, NULL);
+ if (ret) {
+ _unmap_file(&r);
+ return (ret);
+ }
+
+ cl->cl_dbfile = r;
+ cl->cl_dbnum = _db_get_num_entries(cl->cl_db);
+ cl->cl_dbidx = 0;
+ cl->cl_rewind = 1;
+ cl->cl_lookup = &seq_lookup_db;
+ cl->cl_next = &seq_next_db;
+ cl->cl_num_entries = &seq_get_num_entries_db;
+ cl->cl_close = &seq_close_db;
+
+ return (0);
+}
+
+#define T_COMM '#'
+static int
+seq_next_plain(struct _citrus_lookup *cl, struct _region *key,
+ struct _region *data)
+{
+ const char *p, *q;
+ size_t len;
+
+ if (cl->cl_rewind)
+ _memstream_bind(&cl->cl_plainms, &cl->cl_plainr);
+ cl->cl_rewind = 0;
+
+retry:
+ p = _memstream_getln(&cl->cl_plainms, &len);
+ if (p == NULL)
+ return (ENOENT);
+ /* ignore comment */
+ q = memchr(p, T_COMM, len);
+ if (q) {
+ len = q - p;
+ }
+ /* ignore trailing spaces */
+ _bcs_trunc_rws_len(p, &len);
+ p = _bcs_skip_ws_len(p, &len);
+ q = _bcs_skip_nonws_len(p, &len);
+ if (p == q)
+ goto retry;
+ if (cl->cl_key && ((size_t)(q - p) != cl->cl_keylen ||
+ memcmp(p, cl->cl_key, (size_t)(q - p)) != 0))
+ goto retry;
+
+ /* found a entry */
+ if (key)
+ _region_init(key, __DECONST(void *, p), (size_t)(q - p));
+ p = _bcs_skip_ws_len(q, &len);
+ if (data)
+ _region_init(data, len ? __DECONST(void *, p) : NULL, len);
+
+ return (0);
+}
+
+static int
+seq_get_num_entries_plain(struct _citrus_lookup *cl)
+{
+ int num;
+
+ num = 0;
+ while (seq_next_plain(cl, NULL, NULL) == 0)
+ num++;
+
+ return (num);
+}
+
+static int
+seq_lookup_plain(struct _citrus_lookup *cl, const char *key,
+ struct _region *data)
+{
+ size_t len;
+ const char *p;
+
+ cl->cl_rewind = 0;
+ free(cl->cl_key);
+ cl->cl_key = strdup(key);
+ if (cl->cl_ignore_case)
+ _bcs_convert_to_lower(cl->cl_key);
+ cl->cl_keylen = strlen(cl->cl_key);
+ _memstream_bind(&cl->cl_plainms, &cl->cl_plainr);
+ p = _memstream_matchline(&cl->cl_plainms, cl->cl_key, &len, 0);
+ if (p == NULL)
+ return (ENOENT);
+ if (data)
+ _region_init(data, __DECONST(void *, p), len);
+
+ return (0);
+}
+
+static void
+seq_close_plain(struct _citrus_lookup *cl)
+{
+
+ _unmap_file(&cl->cl_plainr);
+}
+
+static int
+seq_open_plain(struct _citrus_lookup *cl, const char *name)
+{
+ int ret;
+
+ /* open read stream */
+ ret = _map_file(&cl->cl_plainr, name);
+ if (ret)
+ return (ret);
+
+ cl->cl_rewind = 1;
+ cl->cl_next = &seq_next_plain;
+ cl->cl_lookup = &seq_lookup_plain;
+ cl->cl_num_entries = &seq_get_num_entries_plain;
+ cl->cl_close = &seq_close_plain;
+
+ return (0);
+}
+
+int
+_citrus_lookup_seq_open(struct _citrus_lookup **rcl, const char *name,
+ int ignore_case)
+{
+ int ret;
+ struct _citrus_lookup *cl;
+
+ cl = malloc(sizeof(*cl));
+ if (cl == NULL)
+ return (errno);
+
+ cl->cl_key = NULL;
+ cl->cl_keylen = 0;
+ cl->cl_ignore_case = ignore_case;
+ ret = seq_open_db(cl, name);
+ if (ret == ENOENT)
+ ret = seq_open_plain(cl, name);
+ if (!ret)
+ *rcl = cl;
+ else
+ free(cl);
+
+ return (ret);
+}
+
+void
+_citrus_lookup_seq_rewind(struct _citrus_lookup *cl)
+{
+
+ cl->cl_rewind = 1;
+ free(cl->cl_key);
+ cl->cl_key = NULL;
+ cl->cl_keylen = 0;
+}
+
+int
+_citrus_lookup_seq_next(struct _citrus_lookup *cl,
+ struct _region *key, struct _region *data)
+{
+
+ return ((*cl->cl_next)(cl, key, data));
+}
+
+int
+_citrus_lookup_seq_lookup(struct _citrus_lookup *cl, const char *key,
+ struct _region *data)
+{
+
+ return ((*cl->cl_lookup)(cl, key, data));
+}
+
+int
+_citrus_lookup_get_number_of_entries(struct _citrus_lookup *cl)
+{
+
+ return ((*cl->cl_num_entries)(cl));
+}
+
+void
+_citrus_lookup_seq_close(struct _citrus_lookup *cl)
+{
+
+ free(cl->cl_key);
+ (*cl->cl_close)(cl);
+ free(cl);
+}
+
+char *
+_citrus_lookup_simple(const char *name, const char *key,
+ char *linebuf, size_t linebufsize, int ignore_case)
+{
+ struct _citrus_lookup *cl;
+ struct _region data;
+ int ret;
+
+ ret = _citrus_lookup_seq_open(&cl, name, ignore_case);
+ if (ret)
+ return (NULL);
+
+ ret = _citrus_lookup_seq_lookup(cl, key, &data);
+ if (ret) {
+ _citrus_lookup_seq_close(cl);
+ return (NULL);
+ }
+
+ snprintf(linebuf, linebufsize, "%.*s", (int)_region_size(&data),
+ (const char *)_region_head(&data));
+
+ _citrus_lookup_seq_close(cl);
+
+ return (linebuf);
+}
diff --git a/lib/libc/iconv/citrus_lookup.h b/lib/libc/iconv/citrus_lookup.h
new file mode 100644
index 000000000000..e7a7150a73a4
--- /dev/null
+++ b/lib/libc/iconv/citrus_lookup.h
@@ -0,0 +1,64 @@
+/* $FreeBSD$ */
+/* $NetBSD: citrus_lookup.h,v 1.2 2004/07/21 14:16:34 tshiozak Exp $ */
+
+/*-
+ * Copyright (c)2003 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _CITRUS_LOOKUP_H_
+#define _CITRUS_LOOKUP_H_
+
+#define _CITRUS_LOOKUP_CASE_SENSITIVE 0
+#define _CITRUS_LOOKUP_CASE_IGNORE 1
+
+struct _citrus_lookup;
+__BEGIN_DECLS
+char *_citrus_lookup_simple(const char *, const char *, char *,
+ size_t, int);
+int _citrus_lookup_seq_open(struct _citrus_lookup **,
+ const char *, int);
+void _citrus_lookup_seq_rewind(struct _citrus_lookup *);
+int _citrus_lookup_seq_next(struct _citrus_lookup *,
+ struct _region *, struct _region *);
+int _citrus_lookup_seq_lookup(struct _citrus_lookup *,
+ const char *, struct _region *);
+int _citrus_lookup_get_number_of_entries(struct _citrus_lookup *);
+void _citrus_lookup_seq_close(struct _citrus_lookup *);
+__END_DECLS
+
+static __inline const char *
+_citrus_lookup_alias(const char *path, const char *key, char *buf, size_t n,
+ int ignore_case)
+{
+ const char *ret;
+
+ ret = _citrus_lookup_simple(path, key, buf, n, ignore_case);
+ if (ret == NULL)
+ ret = key;
+
+ return (ret);
+}
+
+#endif
diff --git a/lib/libc/iconv/citrus_lookup_factory.c b/lib/libc/iconv/citrus_lookup_factory.c
new file mode 100644
index 000000000000..ec5a5d6b78ca
--- /dev/null
+++ b/lib/libc/iconv/citrus_lookup_factory.c
@@ -0,0 +1,121 @@
+/* $FreeBSD$ */
+/* $NetBSD: citrus_lookup_factory.c,v 1.4 2003/10/27 00:12:42 lukem Exp $ */
+
+/*-
+ * Copyright (c)2003 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "citrus_namespace.h"
+#include "citrus_region.h"
+#include "citrus_bcs.h"
+#include "citrus_db_factory.h"
+#include "citrus_db_hash.h"
+#include "citrus_lookup_factory.h"
+#include "citrus_lookup_file.h"
+
+#define T_COMM '#'
+static int
+convert_line(struct _citrus_db_factory *df, const char *line, size_t len)
+{
+ const char *p;
+ char data[LINE_MAX], key[LINE_MAX];
+
+ /* cut off trailing comment */
+ p = memchr(line, T_COMM, len);
+ if (p)
+ len = p - line;
+
+ /* key */
+ line = _bcs_skip_ws_len(line, &len);
+ if (len == 0)
+ return (0);
+ p = _bcs_skip_nonws_len(line, &len);
+ if (p == line)
+ return (0);
+ snprintf(key, sizeof(key), "%.*s", (int)(p-line), line);
+ _bcs_convert_to_lower(key);
+
+ /* data */
+ line = _bcs_skip_ws_len(p, &len);
+ _bcs_trunc_rws_len(line, &len);
+ snprintf(data, sizeof(data), "%.*s", (int)len, line);
+
+ return (_db_factory_addstr_by_s(df, key, data));
+}
+
+static int
+dump_db(struct _citrus_db_factory *df, struct _region *r)
+{
+ void *ptr;
+ size_t size;
+
+ size = _db_factory_calc_size(df);
+ ptr = malloc(size);
+ if (ptr == NULL)
+ return (errno);
+ _region_init(r, ptr, size);
+
+ return (_db_factory_serialize(df, _CITRUS_LOOKUP_MAGIC, r));
+}
+
+int
+_citrus_lookup_factory_convert(FILE *out, FILE *in)
+{
+ struct _citrus_db_factory *df;
+ struct _region r;
+ char *line;
+ size_t size;
+ int ret;
+
+ ret = _db_factory_create(&df, &_db_hash_std, NULL);
+ if (ret)
+ return (ret);
+
+ while ((line = fgetln(in, &size)) != NULL)
+ if ((ret = convert_line(df, line, size))) {
+ _db_factory_free(df);
+ return (ret);
+ }
+
+ ret = dump_db(df, &r);
+ _db_factory_free(df);
+ if (ret)
+ return (ret);
+
+ if (fwrite(_region_head(&r), _region_size(&r), 1, out) != 1)
+ return (errno);
+
+ return (0);
+}
diff --git a/lib/libc/iconv/citrus_lookup_factory.h b/lib/libc/iconv/citrus_lookup_factory.h
new file mode 100644
index 000000000000..9016de5507e1
--- /dev/null
+++ b/lib/libc/iconv/citrus_lookup_factory.h
@@ -0,0 +1,37 @@
+/* $FreeBSD$ */
+/* $NetBSD: citrus_lookup_factory.h,v 1.1 2003/06/25 09:51:35 tshiozak Exp $ */
+
+/*-
+ * Copyright (c)2003 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _CITRUS_LOOKUP_FACTORY_H_
+#define _CITRUS_LOOKUP_FACTORY_H_
+
+__BEGIN_DECLS
+int _citrus_lookup_factory_convert(FILE *, FILE *);
+__END_DECLS
+
+#endif
diff --git a/lib/libc/iconv/citrus_lookup_file.h b/lib/libc/iconv/citrus_lookup_file.h
new file mode 100644
index 000000000000..43944b3d9815
--- /dev/null
+++ b/lib/libc/iconv/citrus_lookup_file.h
@@ -0,0 +1,35 @@
+/* $FreeBSD$ */
+/* $NetBSD: citrus_lookup_file.h,v 1.1 2003/06/25 09:51:36 tshiozak Exp $ */
+
+/*-
+ * Copyright (c)2003 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _CITRUS_LOOKUP_FILE_H_
+#define _CITRUS_LOOKUP_FILE_H_
+
+#define _CITRUS_LOOKUP_MAGIC "LOOKUP\0\0"
+
+#endif
diff --git a/lib/libc/iconv/citrus_mapper.c b/lib/libc/iconv/citrus_mapper.c
new file mode 100644
index 000000000000..ea65ae95bc7a
--- /dev/null
+++ b/lib/libc/iconv/citrus_mapper.c
@@ -0,0 +1,405 @@
+/* $FreeBSD$ */
+/* $NetBSD: citrus_mapper.c,v 1.10 2012/06/08 07:49:42 martin Exp $ */
+
+/*-
+ * Copyright (c)2003 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/queue.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "citrus_namespace.h"
+#include "citrus_types.h"
+#include "citrus_region.h"
+#include "citrus_lock.h"
+#include "citrus_memstream.h"
+#include "citrus_bcs.h"
+#include "citrus_mmap.h"
+#include "citrus_module.h"
+#include "citrus_hash.h"
+#include "citrus_mapper.h"
+
+#define _CITRUS_MAPPER_DIR "mapper.dir"
+
+#define CM_HASH_SIZE 101
+#define REFCOUNT_PERSISTENT -1
+
+static pthread_rwlock_t cm_lock = PTHREAD_RWLOCK_INITIALIZER;
+
+struct _citrus_mapper_area {
+ _CITRUS_HASH_HEAD(, _citrus_mapper, CM_HASH_SIZE) ma_cache;
+ char *ma_dir;
+};
+
+/*
+ * _citrus_mapper_create_area:
+ * create mapper area
+ */
+
+int
+_citrus_mapper_create_area(
+ struct _citrus_mapper_area *__restrict *__restrict rma,
+ const char *__restrict area)
+{
+ struct _citrus_mapper_area *ma;
+ struct stat st;
+ char path[PATH_MAX];
+ int ret;
+
+ WLOCK(&cm_lock);
+
+ if (*rma != NULL) {
+ ret = 0;
+ goto quit;
+ }
+
+ snprintf(path, (size_t)PATH_MAX, "%s/%s", area, _CITRUS_MAPPER_DIR);
+
+ ret = stat(path, &st);
+ if (ret)
+ goto quit;
+
+ ma = malloc(sizeof(*ma));
+ if (ma == NULL) {
+ ret = errno;
+ goto quit;
+ }
+ ma->ma_dir = strdup(area);
+ if (ma->ma_dir == NULL) {
+ ret = errno;
+ free(ma);
+ goto quit;
+ }
+ _CITRUS_HASH_INIT(&ma->ma_cache, CM_HASH_SIZE);
+
+ *rma = ma;
+ ret = 0;
+quit:
+ UNLOCK(&cm_lock);
+
+ return (ret);
+}
+
+
+/*
+ * lookup_mapper_entry:
+ * lookup mapper.dir entry in the specified directory.
+ *
+ * line format of iconv.dir file:
+ * mapper module arg
+ * mapper : mapper name.
+ * module : mapper module name.
+ * arg : argument for the module (generally, description file name)
+ */
+
+static int
+lookup_mapper_entry(const char *dir, const char *mapname, void *linebuf,
+ size_t linebufsize, const char **module, const char **variable)
+{
+ struct _region r;
+ struct _memstream ms;
+ const char *cp, *cq;
+ char *p;
+ char path[PATH_MAX];
+ size_t len;
+ int ret;
+
+ /* create mapper.dir path */
+ snprintf(path, (size_t)PATH_MAX, "%s/%s", dir, _CITRUS_MAPPER_DIR);
+
+ /* open read stream */
+ ret = _map_file(&r, path);
+ if (ret)
+ return (ret);
+
+ _memstream_bind(&ms, &r);
+
+ /* search the line matching to the map name */
+ cp = _memstream_matchline(&ms, mapname, &len, 0);
+ if (!cp) {
+ ret = ENOENT;
+ goto quit;
+ }
+ if (!len || len > linebufsize - 1) {
+ ret = EINVAL;
+ goto quit;
+ }
+
+ p = linebuf;
+ /* get module name */
+ *module = p;
+ cq = _bcs_skip_nonws_len(cp, &len);
+ strlcpy(p, cp, (size_t)(cq - cp + 1));
+ p += cq - cp + 1;
+
+ /* get variable */
+ *variable = p;
+ cp = _bcs_skip_ws_len(cq, &len);
+ strlcpy(p, cp, len + 1);
+
+ ret = 0;
+
+quit:
+ _unmap_file(&r);
+ return (ret);
+}
+
+/*
+ * mapper_close:
+ * simply close a mapper. (without handling hash)
+ */
+static void
+mapper_close(struct _citrus_mapper *cm)
+{
+ if (cm->cm_module) {
+ if (cm->cm_ops) {
+ if (cm->cm_closure)
+ (*cm->cm_ops->mo_uninit)(cm);
+ free(cm->cm_ops);
+ }
+ _citrus_unload_module(cm->cm_module);
+ }
+ free(cm->cm_traits);
+ free(cm);
+}
+
+/*
+ * mapper_open:
+ * simply open a mapper. (without handling hash)
+ */
+static int
+mapper_open(struct _citrus_mapper_area *__restrict ma,
+ struct _citrus_mapper * __restrict * __restrict rcm,
+ const char * __restrict module,
+ const char * __restrict variable)
+{
+ struct _citrus_mapper *cm;
+ _citrus_mapper_getops_t getops;
+ int ret;
+
+ /* initialize mapper handle */
+ cm = malloc(sizeof(*cm));
+ if (!cm)
+ return (errno);
+
+ cm->cm_module = NULL;
+ cm->cm_ops = NULL;
+ cm->cm_closure = NULL;
+ cm->cm_traits = NULL;
+ cm->cm_refcount = 0;
+ cm->cm_key = NULL;
+
+ /* load module */
+ ret = _citrus_load_module(&cm->cm_module, module);
+ if (ret)
+ goto err;
+
+ /* get operators */
+ getops = (_citrus_mapper_getops_t)
+ _citrus_find_getops(cm->cm_module, module, "mapper");
+ if (!getops) {
+ ret = EOPNOTSUPP;
+ goto err;
+ }
+ cm->cm_ops = malloc(sizeof(*cm->cm_ops));
+ if (!cm->cm_ops) {
+ ret = errno;
+ goto err;
+ }
+ ret = (*getops)(cm->cm_ops);
+ if (ret)
+ goto err;
+
+ if (!cm->cm_ops->mo_init ||
+ !cm->cm_ops->mo_uninit ||
+ !cm->cm_ops->mo_convert ||
+ !cm->cm_ops->mo_init_state) {
+ ret = EINVAL;
+ goto err;
+ }
+
+ /* allocate traits structure */
+ cm->cm_traits = malloc(sizeof(*cm->cm_traits));
+ if (cm->cm_traits == NULL) {
+ ret = errno;
+ goto err;
+ }
+ /* initialize the mapper */
+ ret = (*cm->cm_ops->mo_init)(ma, cm, ma->ma_dir,
+ (const void *)variable, strlen(variable) + 1,
+ cm->cm_traits, sizeof(*cm->cm_traits));
+ if (ret)
+ goto err;
+
+ *rcm = cm;
+
+ return (0);
+
+err:
+ mapper_close(cm);
+ return (ret);
+}
+
+/*
+ * _citrus_mapper_open_direct:
+ * open a mapper.
+ */
+int
+_citrus_mapper_open_direct(struct _citrus_mapper_area *__restrict ma,
+ struct _citrus_mapper * __restrict * __restrict rcm,
+ const char * __restrict module, const char * __restrict variable)
+{
+
+ return (mapper_open(ma, rcm, module, variable));
+}
+
+/*
+ * hash_func
+ */
+static __inline int
+hash_func(const char *key)
+{
+
+ return (_string_hash_func(key, CM_HASH_SIZE));
+}
+
+/*
+ * match_func
+ */
+static __inline int
+match_func(struct _citrus_mapper *cm, const char *key)
+{
+
+ return (strcmp(cm->cm_key, key));
+}
+
+/*
+ * _citrus_mapper_open:
+ * open a mapper with looking up "mapper.dir".
+ */
+int
+_citrus_mapper_open(struct _citrus_mapper_area *__restrict ma,
+ struct _citrus_mapper * __restrict * __restrict rcm,
+ const char * __restrict mapname)
+{
+ struct _citrus_mapper *cm;
+ char linebuf[PATH_MAX];
+ const char *module, *variable;
+ int hashval, ret;
+
+ variable = NULL;
+
+ WLOCK(&cm_lock);
+
+ /* search in the cache */
+ hashval = hash_func(mapname);
+ _CITRUS_HASH_SEARCH(&ma->ma_cache, cm, cm_entry, match_func, mapname,
+ hashval);
+ if (cm) {
+ /* found */
+ cm->cm_refcount++;
+ *rcm = cm;
+ ret = 0;
+ goto quit;
+ }
+
+ /* search mapper entry */
+ ret = lookup_mapper_entry(ma->ma_dir, mapname, linebuf,
+ (size_t)PATH_MAX, &module, &variable);
+ if (ret)
+ goto quit;
+
+ /* open mapper */
+ UNLOCK(&cm_lock);
+ ret = mapper_open(ma, &cm, module, variable);
+ WLOCK(&cm_lock);
+ if (ret)
+ goto quit;
+ cm->cm_key = strdup(mapname);
+ if (cm->cm_key == NULL) {
+ ret = errno;
+ _mapper_close(cm);
+ goto quit;
+ }
+
+ /* insert to the cache */
+ cm->cm_refcount = 1;
+ _CITRUS_HASH_INSERT(&ma->ma_cache, cm, cm_entry, hashval);
+
+ *rcm = cm;
+ ret = 0;
+quit:
+ UNLOCK(&cm_lock);
+
+ return (ret);
+}
+
+/*
+ * _citrus_mapper_close:
+ * close the specified mapper.
+ */
+void
+_citrus_mapper_close(struct _citrus_mapper *cm)
+{
+
+ if (cm) {
+ WLOCK(&cm_lock);
+ if (cm->cm_refcount == REFCOUNT_PERSISTENT)
+ goto quit;
+ if (cm->cm_refcount > 0) {
+ if (--cm->cm_refcount > 0)
+ goto quit;
+ _CITRUS_HASH_REMOVE(cm, cm_entry);
+ free(cm->cm_key);
+ }
+ UNLOCK(&cm_lock);
+ mapper_close(cm);
+ return;
+quit:
+ UNLOCK(&cm_lock);
+ }
+}
+
+/*
+ * _citrus_mapper_set_persistent:
+ * set persistent count.
+ */
+void
+_citrus_mapper_set_persistent(struct _citrus_mapper * __restrict cm)
+{
+
+ WLOCK(&cm_lock);
+ cm->cm_refcount = REFCOUNT_PERSISTENT;
+ UNLOCK(&cm_lock);
+}
diff --git a/lib/libc/iconv/citrus_mapper.h b/lib/libc/iconv/citrus_mapper.h
new file mode 100644
index 000000000000..429b2a1a0ce9
--- /dev/null
+++ b/lib/libc/iconv/citrus_mapper.h
@@ -0,0 +1,131 @@
+/* $FreeBSD$ */
+/* $NetBSD: citrus_mapper.h,v 1.3 2003/07/12 15:39:19 tshiozak Exp $ */
+
+/*-
+ * Copyright (c)2003 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _CITRUS_MAPPER_H_
+#define _CITRUS_MAPPER_H_
+
+struct _citrus_mapper_area;
+struct _citrus_mapper;
+struct _citrus_mapper_ops;
+struct _citrus_mapper_traits;
+
+__BEGIN_DECLS
+int _citrus_mapper_create_area(
+ struct _citrus_mapper_area *__restrict *__restrict,
+ const char *__restrict);
+int _citrus_mapper_open(struct _citrus_mapper_area *__restrict,
+ struct _citrus_mapper *__restrict *__restrict,
+ const char *__restrict);
+int _citrus_mapper_open_direct(
+ struct _citrus_mapper_area *__restrict,
+ struct _citrus_mapper *__restrict *__restrict,
+ const char *__restrict, const char *__restrict);
+void _citrus_mapper_close(struct _citrus_mapper *);
+void _citrus_mapper_set_persistent(struct _citrus_mapper * __restrict);
+__END_DECLS
+
+#include "citrus_mapper_local.h"
+
+/* return values of _citrus_mapper_convert */
+#define _CITRUS_MAPPER_CONVERT_SUCCESS (0)
+#define _CITRUS_MAPPER_CONVERT_NONIDENTICAL (1)
+#define _CITRUS_MAPPER_CONVERT_SRC_MORE (2)
+#define _CITRUS_MAPPER_CONVERT_DST_MORE (3)
+#define _CITRUS_MAPPER_CONVERT_ILSEQ (4)
+#define _CITRUS_MAPPER_CONVERT_FATAL (5)
+
+/*
+ * _citrus_mapper_convert:
+ * convert an index.
+ * - if the converter supports M:1 converter, the function may return
+ * _CITRUS_MAPPER_CONVERT_SRC_MORE and the storage pointed by dst
+ * may be unchanged in this case, although the internal status of
+ * the mapper is affected.
+ * - if the converter supports 1:N converter, the function may return
+ * _CITRUS_MAPPER_CONVERT_DST_MORE. In this case, the contiguous
+ * call of this function ignores src and changes the storage pointed
+ * by dst.
+ * - if the converter supports M:N converter, the function may behave
+ * the combination of the above.
+ *
+ */
+static __inline int
+_citrus_mapper_convert(struct _citrus_mapper * __restrict cm,
+ _citrus_index_t * __restrict dst, _citrus_index_t src,
+ void * __restrict ps)
+{
+
+ return ((*cm->cm_ops->mo_convert)(cm, dst, src, ps));
+}
+
+/*
+ * _citrus_mapper_init_state:
+ * initialize the state.
+ */
+static __inline void
+_citrus_mapper_init_state(struct _citrus_mapper * __restrict cm)
+{
+
+ (*cm->cm_ops->mo_init_state)();
+}
+
+/*
+ * _citrus_mapper_get_state_size:
+ * get the size of state storage.
+ */
+static __inline size_t
+_citrus_mapper_get_state_size(struct _citrus_mapper * __restrict cm)
+{
+
+ return (cm->cm_traits->mt_state_size);
+}
+
+/*
+ * _citrus_mapper_get_src_max:
+ * get the maximum number of suspended sources.
+ */
+static __inline size_t
+_citrus_mapper_get_src_max(struct _citrus_mapper * __restrict cm)
+{
+
+ return (cm->cm_traits->mt_src_max);
+}
+
+/*
+ * _citrus_mapper_get_dst_max:
+ * get the maximum number of suspended destinations.
+ */
+static __inline size_t
+_citrus_mapper_get_dst_max(struct _citrus_mapper * __restrict cm)
+{
+
+ return (cm->cm_traits->mt_dst_max);
+}
+
+#endif
diff --git a/lib/libc/iconv/citrus_mapper_local.h b/lib/libc/iconv/citrus_mapper_local.h
new file mode 100644
index 000000000000..8d29e63a4a96
--- /dev/null
+++ b/lib/libc/iconv/citrus_mapper_local.h
@@ -0,0 +1,97 @@
+/* $FreeBSD$ */
+/* $NetBSD: citrus_mapper_local.h,v 1.2 2008/02/09 14:56:20 junyoung Exp $ */
+
+/*-
+ * Copyright (c)2003 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _CITRUS_MAPPER_LOCAL_H_
+#define _CITRUS_MAPPER_LOCAL_H_
+
+#define _CITRUS_MAPPER_GETOPS_FUNC_BASE(_n_) \
+int _n_(struct _citrus_mapper_ops *)
+#define _CITRUS_MAPPER_GETOPS_FUNC(_n_) \
+_CITRUS_MAPPER_GETOPS_FUNC_BASE(_citrus_##_n_##_mapper_getops)
+
+#define _CITRUS_MAPPER_DECLS(_m_) \
+static int _citrus_##_m_##_mapper_init \
+ (struct _citrus_mapper_area *__restrict, \
+ struct _citrus_mapper * __restrict, \
+ const char * __restrict, const void * __restrict, \
+ size_t, struct _citrus_mapper_traits * __restrict, \
+ size_t); \
+static void _citrus_##_m_##_mapper_uninit( \
+ struct _citrus_mapper *); \
+static int _citrus_##_m_##_mapper_convert \
+ (struct _citrus_mapper * __restrict, \
+ _citrus_index_t * __restrict, _citrus_index_t, \
+ void * __restrict); \
+static void _citrus_##_m_##_mapper_init_state \
+ (void);
+
+#define _CITRUS_MAPPER_DEF_OPS(_m_) \
+extern struct _citrus_mapper_ops _citrus_##_m_##_mapper_ops; \
+struct _citrus_mapper_ops _citrus_##_m_##_mapper_ops = { \
+ /* mo_init */ &_citrus_##_m_##_mapper_init, \
+ /* mo_uninit */ &_citrus_##_m_##_mapper_uninit, \
+ /* mo_convert */ &_citrus_##_m_##_mapper_convert, \
+ /* mo_init_state */ &_citrus_##_m_##_mapper_init_state \
+}
+
+typedef _CITRUS_MAPPER_GETOPS_FUNC_BASE((*_citrus_mapper_getops_t));
+typedef int (*_citrus_mapper_init_t)(
+ struct _citrus_mapper_area *__restrict,
+ struct _citrus_mapper *__restrict, const char *__restrict,
+ const void *__restrict, size_t,
+ struct _citrus_mapper_traits * __restrict, size_t);
+typedef void (*_citrus_mapper_uninit_t)(struct _citrus_mapper *);
+typedef int (*_citrus_mapper_convert_t)(struct _citrus_mapper * __restrict,
+ _citrus_index_t * __restrict, _citrus_index_t, void * __restrict);
+typedef void (*_citrus_mapper_init_state_t)(void);
+
+struct _citrus_mapper_ops {
+ _citrus_mapper_init_t mo_init;
+ _citrus_mapper_uninit_t mo_uninit;
+ _citrus_mapper_convert_t mo_convert;
+ _citrus_mapper_init_state_t mo_init_state;
+};
+
+struct _citrus_mapper_traits {
+ /* version 0x00000001 */
+ size_t mt_state_size;
+ size_t mt_src_max;
+ size_t mt_dst_max;
+};
+
+struct _citrus_mapper {
+ struct _citrus_mapper_ops *cm_ops;
+ void *cm_closure;
+ _citrus_module_t cm_module;
+ struct _citrus_mapper_traits *cm_traits;
+ _CITRUS_HASH_ENTRY(_citrus_mapper) cm_entry;
+ int cm_refcount;
+ char *cm_key;
+};
+#endif
diff --git a/lib/libc/iconv/citrus_memstream.c b/lib/libc/iconv/citrus_memstream.c
new file mode 100644
index 000000000000..f99a19d8ba57
--- /dev/null
+++ b/lib/libc/iconv/citrus_memstream.c
@@ -0,0 +1,147 @@
+/* $FreeBSD$ */
+/* $NetBSD: citrus_memstream.c,v 1.5 2012/03/13 21:13:31 christos Exp $ */
+
+/*-
+ * Copyright (c)2003 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "citrus_namespace.h"
+#include "citrus_region.h"
+#include "citrus_memstream.h"
+#include "citrus_bcs.h"
+
+const char *
+_citrus_memory_stream_getln(struct _citrus_memory_stream * __restrict ms,
+ size_t * __restrict rlen)
+{
+ const uint8_t *h, *p;
+ size_t i, ret;
+
+ if (ms->ms_pos>=_region_size(&ms->ms_region))
+ return (NULL);
+
+ h = p = (uint8_t *)_region_offset(&ms->ms_region, ms->ms_pos);
+ ret = 0;
+ for (i = _region_size(&ms->ms_region) - ms->ms_pos; i > 0; i--) {
+ ret++;
+ if (_bcs_iseol(*p))
+ break;
+ p++;
+ }
+
+ ms->ms_pos += ret;
+ *rlen = ret;
+ return ((const char *)h);
+}
+
+#define T_COMM '#'
+
+const char *
+_citrus_memory_stream_matchline(struct _citrus_memory_stream * __restrict ms,
+ const char * __restrict key, size_t * __restrict rlen, int iscasesensitive)
+{
+ const char *p, *q;
+ size_t keylen, len;
+
+ keylen = strlen(key);
+ for(;;) {
+ p = _citrus_memory_stream_getln(ms, &len);
+ if (p == NULL)
+ return (NULL);
+
+ /* ignore comment */
+ q = memchr(p, T_COMM, len);
+ if (q) {
+ len = q - p;
+ }
+ /* ignore trailing white space and newline */
+ _bcs_trunc_rws_len(p, &len);
+ if (len == 0)
+ continue; /* ignore null line */
+
+ /* skip white spaces at the head of the line */
+ p = _bcs_skip_ws_len(p, &len);
+ q = _bcs_skip_nonws_len(p, &len);
+
+ if ((size_t)(q - p) == keylen) {
+ if (iscasesensitive) {
+ if (memcmp(key, p, keylen) == 0)
+ break; /* match */
+ } else {
+ if (_bcs_strncasecmp(key, p, keylen) == 0)
+ break; /* match */
+ }
+ }
+ }
+
+ p = _bcs_skip_ws_len(q, &len);
+ *rlen = len;
+
+ return (p);
+}
+
+void *
+_citrus_memory_stream_chr(struct _citrus_memory_stream *ms,
+ struct _citrus_region *r, char ch)
+{
+ void *chr, *head;
+ size_t sz;
+
+ if (ms->ms_pos >= _region_size(&ms->ms_region))
+ return (NULL);
+
+ head = _region_offset(&ms->ms_region, ms->ms_pos);
+ chr = memchr(head, ch, _memstream_remainder(ms));
+ if (chr == NULL) {
+ _region_init(r, head, _memstream_remainder(ms));
+ ms->ms_pos = _region_size(&ms->ms_region);
+ return (NULL);
+ }
+ sz = (char *)chr - (char *)head;
+
+ _region_init(r, head, sz);
+ ms->ms_pos += sz + 1;
+
+ return (chr);
+}
+
+void
+_citrus_memory_stream_skip_ws(struct _citrus_memory_stream *ms)
+{
+ int ch;
+
+ while ((ch = _memstream_peek(ms)) != EOF) {
+ if (!_bcs_isspace(ch))
+ break;
+ _memstream_getc(ms);
+ }
+}
diff --git a/lib/libc/iconv/citrus_memstream.h b/lib/libc/iconv/citrus_memstream.h
new file mode 100644
index 000000000000..cd5ef134f2cc
--- /dev/null
+++ b/lib/libc/iconv/citrus_memstream.h
@@ -0,0 +1,226 @@
+/* $FreeBSD$ */
+/* $NetBSD: citrus_memstream.h,v 1.3 2005/05/14 17:55:42 tshiozak Exp $ */
+
+/*-
+ * Copyright (c)2003 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#ifndef _CITRUS_MEMSTREAM_H_
+#define _CITRUS_MEMSTREAM_H_
+
+struct _citrus_memory_stream {
+ struct _citrus_region ms_region;
+ size_t ms_pos;
+};
+
+__BEGIN_DECLS
+const char *_citrus_memory_stream_getln(
+ struct _citrus_memory_stream * __restrict,
+ size_t * __restrict);
+const char *_citrus_memory_stream_matchline(
+ struct _citrus_memory_stream * __restrict,
+ const char * __restrict, size_t * __restrict, int);
+void *_citrus_memory_stream_chr(struct _citrus_memory_stream *,
+ struct _citrus_region *, char);
+void _citrus_memory_stream_skip_ws(struct _citrus_memory_stream *);
+__END_DECLS
+
+static __inline int
+_citrus_memory_stream_iseof(struct _citrus_memory_stream *ms)
+{
+
+ return (ms->ms_pos >= _citrus_region_size(&ms->ms_region));
+}
+
+static __inline void
+_citrus_memory_stream_bind(struct _citrus_memory_stream * __restrict ms,
+ const struct _citrus_region * __restrict r)
+{
+
+ ms->ms_region = *r;
+ ms->ms_pos = 0;
+}
+
+static __inline void
+_citrus_memory_stream_bind_ptr(struct _citrus_memory_stream * __restrict ms,
+ void *ptr, size_t sz)
+{
+ struct _citrus_region r;
+
+ _citrus_region_init(&r, ptr, sz);
+ _citrus_memory_stream_bind(ms, &r);
+}
+
+static __inline void
+_citrus_memory_stream_rewind(struct _citrus_memory_stream *ms)
+{
+
+ ms->ms_pos = 0;
+}
+
+static __inline size_t
+_citrus_memory_stream_tell(struct _citrus_memory_stream *ms)
+{
+
+ return (ms->ms_pos);
+}
+
+static __inline size_t
+_citrus_memory_stream_remainder(struct _citrus_memory_stream *ms)
+{
+ size_t sz;
+
+ sz = _citrus_region_size(&ms->ms_region);
+ if (ms->ms_pos>sz)
+ return (0);
+ return (sz-ms->ms_pos);
+}
+
+static __inline int
+_citrus_memory_stream_seek(struct _citrus_memory_stream *ms, size_t pos, int w)
+{
+ size_t sz;
+
+ sz = _citrus_region_size(&ms->ms_region);
+
+ switch (w) {
+ case SEEK_SET:
+ if (pos >= sz)
+ return (-1);
+ ms->ms_pos = pos;
+ break;
+ case SEEK_CUR:
+ pos += (ssize_t)ms->ms_pos;
+ if (pos >= sz)
+ return (-1);
+ ms->ms_pos = pos;
+ break;
+ case SEEK_END:
+ if (sz < pos)
+ return (-1);
+ ms->ms_pos = sz - pos;
+ break;
+ }
+ return (0);
+}
+
+static __inline int
+_citrus_memory_stream_getc(struct _citrus_memory_stream *ms)
+{
+
+ if (_citrus_memory_stream_iseof(ms))
+ return (EOF);
+ return (_citrus_region_peek8(&ms->ms_region, ms->ms_pos++));
+}
+
+static __inline void
+_citrus_memory_stream_ungetc(struct _citrus_memory_stream *ms, int ch)
+{
+
+ if (ch != EOF && ms->ms_pos > 0)
+ ms->ms_pos--;
+}
+
+static __inline int
+_citrus_memory_stream_peek(struct _citrus_memory_stream *ms)
+{
+
+ if (_citrus_memory_stream_iseof(ms))
+ return (EOF);
+ return (_citrus_region_peek8(&ms->ms_region, ms->ms_pos));
+}
+
+static __inline void *
+_citrus_memory_stream_getregion(struct _citrus_memory_stream *ms,
+ struct _citrus_region *r, size_t sz)
+{
+ void *ret;
+
+ if (ms->ms_pos + sz > _citrus_region_size(&ms->ms_region))
+ return (NULL);
+
+ ret = _citrus_region_offset(&ms->ms_region, ms->ms_pos);
+ ms->ms_pos += sz;
+ if (r)
+ _citrus_region_init(r, ret, sz);
+
+ return (ret);
+}
+
+static __inline int
+_citrus_memory_stream_get8(struct _citrus_memory_stream *ms, uint8_t *rval)
+{
+
+ if (ms->ms_pos + 1 > _citrus_region_size(&ms->ms_region))
+ return (-1);
+
+ *rval = _citrus_region_peek8(&ms->ms_region, ms->ms_pos);
+ ms->ms_pos += 2;
+
+ return (0);
+}
+
+static __inline int
+_citrus_memory_stream_get16(struct _citrus_memory_stream *ms, uint16_t *rval)
+{
+
+ if (ms->ms_pos + 2 > _citrus_region_size(&ms->ms_region))
+ return (-1);
+
+ *rval = _citrus_region_peek16(&ms->ms_region, ms->ms_pos);
+ ms->ms_pos += 2;
+
+ return (0);
+}
+
+static __inline int
+_citrus_memory_stream_get32(struct _citrus_memory_stream *ms, uint32_t *rval)
+{
+
+ if (ms->ms_pos + 4 > _citrus_region_size(&ms->ms_region))
+ return (-1);
+
+ *rval = _citrus_region_peek32(&ms->ms_region, ms->ms_pos);
+ ms->ms_pos += 4;
+
+ return (0);
+}
+
+static __inline int
+_citrus_memory_stream_getln_region(struct _citrus_memory_stream *ms,
+ struct _citrus_region *r)
+{
+ const char *ptr;
+ size_t sz;
+
+ ptr = _citrus_memory_stream_getln(ms, &sz);
+ if (ptr)
+ _citrus_region_init(r, __DECONST(void *, ptr), sz);
+
+ return (ptr == NULL);
+}
+
+#endif
diff --git a/lib/libc/iconv/citrus_mmap.c b/lib/libc/iconv/citrus_mmap.c
new file mode 100644
index 000000000000..83dd70b03fb6
--- /dev/null
+++ b/lib/libc/iconv/citrus_mmap.c
@@ -0,0 +1,95 @@
+/* $FreeBSD$ */
+/* $NetBSD: citrus_mmap.c,v 1.4 2011/10/15 23:00:01 christos Exp $ */
+
+/*-
+ * Copyright (c)2003 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "namespace.h"
+#include <sys/cdefs.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+#include "citrus_namespace.h"
+#include "citrus_region.h"
+#include "citrus_mmap.h"
+
+int
+_citrus_map_file(struct _citrus_region * __restrict r,
+ const char * __restrict path)
+{
+ struct stat st;
+ void *head;
+ int fd, ret;
+
+ ret = 0;
+
+ _region_init(r, NULL, 0);
+
+ if ((fd = _open(path, O_RDONLY | O_CLOEXEC)) == -1)
+ return (errno);
+
+ if (_fstat(fd, &st) == -1) {
+ ret = errno;
+ goto error;
+ }
+ if (!S_ISREG(st.st_mode)) {
+ ret = EOPNOTSUPP;
+ goto error;
+ }
+
+ head = mmap(NULL, (size_t)st.st_size, PROT_READ, MAP_FILE|MAP_PRIVATE,
+ fd, (off_t)0);
+ if (head == MAP_FAILED) {
+ ret = errno;
+ goto error;
+ }
+ _region_init(r, head, (size_t)st.st_size);
+
+error:
+ (void)_close(fd);
+ return (ret);
+}
+
+void
+_citrus_unmap_file(struct _citrus_region *r)
+{
+
+ if (_region_head(r) != NULL) {
+ (void)munmap(_region_head(r), _region_size(r));
+ _region_init(r, NULL, 0);
+ }
+}
diff --git a/lib/libc/iconv/citrus_mmap.h b/lib/libc/iconv/citrus_mmap.h
new file mode 100644
index 000000000000..590e7fbe202d
--- /dev/null
+++ b/lib/libc/iconv/citrus_mmap.h
@@ -0,0 +1,40 @@
+/* $FreeBSD$ */
+/* $NetBSD: citrus_mmap.h,v 1.1 2003/06/25 09:51:38 tshiozak Exp $ */
+
+/*-
+ * Copyright (c)2003 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#ifndef _CITRUS_MMAP_H_
+#define _CITRUS_MMAP_H_
+
+__BEGIN_DECLS
+int _citrus_map_file(struct _citrus_region * __restrict,
+ const char * __restrict);
+void _citrus_unmap_file(struct _citrus_region *);
+__END_DECLS
+
+#endif
diff --git a/lib/libc/iconv/citrus_module.c b/lib/libc/iconv/citrus_module.c
new file mode 100644
index 000000000000..32b7e6e834ad
--- /dev/null
+++ b/lib/libc/iconv/citrus_module.c
@@ -0,0 +1,315 @@
+/* $FreeBSD$ */
+/* $NetBSD: citrus_module.c,v 1.9 2009/01/11 02:46:24 christos Exp $ */
+
+/*-
+ * Copyright (c)1999, 2000, 2001, 2002 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*-
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Paul Kranenburg.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Borman at Krystal Technologies.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+#include <assert.h>
+#include <dirent.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <limits.h>
+#include <paths.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define I18NMODULE_MAJOR 4
+
+#include "citrus_namespace.h"
+#include "citrus_bcs.h"
+#include "citrus_module.h"
+#include "libc_private.h"
+
+static int _getdewey(int[], char *);
+static int _cmpndewey(int[], int, int[], int);
+static const char *_findshlib(char *, int *, int *);
+
+static const char *_pathI18nModule = NULL;
+
+/* from libexec/ld.aout_so/shlib.c */
+#undef major
+#undef minor
+#define MAXDEWEY 3 /*ELF*/
+
+static int
+_getdewey(int dewey[], char *cp)
+{
+ int i, n;
+
+ for (n = 0, i = 0; i < MAXDEWEY; i++) {
+ if (*cp == '\0')
+ break;
+
+ if (*cp == '.') cp++;
+ if (*cp < '0' || '9' < *cp)
+ return (0);
+
+ dewey[n++] = (int)_bcs_strtol(cp, &cp, 10);
+ }
+
+ return (n);
+}
+
+/*
+ * Compare two dewey arrays.
+ * Return -1 if `d1' represents a smaller value than `d2'.
+ * Return 1 if `d1' represents a greater value than `d2'.
+ * Return 0 if equal.
+ */
+static int
+_cmpndewey(int d1[], int n1, int d2[], int n2)
+{
+ int i;
+
+ for (i = 0; i < n1 && i < n2; i++) {
+ if (d1[i] < d2[i])
+ return (-1);
+ if (d1[i] > d2[i])
+ return (1);
+ }
+
+ if (n1 == n2)
+ return (0);
+
+ if (i == n1)
+ return (-1);
+
+ if (i == n2)
+ return (1);
+
+ /* cannot happen */
+ return (0);
+}
+
+static const char *
+_findshlib(char *name, int *majorp, int *minorp)
+{
+ char *lname;
+ const char *search_dirs[1];
+ static char path[PATH_MAX];
+ int dewey[MAXDEWEY], tmp[MAXDEWEY];
+ int i, len, major, minor, ndewey, n_search_dirs;
+
+ n_search_dirs = 1;
+ major = *majorp;
+ minor = *minorp;
+ path[0] = '\0';
+ search_dirs[0] = _pathI18nModule;
+ len = strlen(name);
+ lname = name;
+
+ ndewey = 0;
+
+ for (i = 0; i < n_search_dirs; i++) {
+ struct dirent *dp;
+ DIR *dd = opendir(search_dirs[i]);
+ int found_dot_a = 0, found_dot_so = 0;
+
+ if (dd == NULL)
+ break;
+
+ while ((dp = readdir(dd)) != NULL) {
+ int n;
+
+ if (dp->d_namlen < len + 4)
+ continue;
+ if (strncmp(dp->d_name, lname, (size_t)len) != 0)
+ continue;
+ if (strncmp(dp->d_name+len, ".so.", 4) != 0)
+ continue;
+
+ if ((n = _getdewey(tmp, dp->d_name+len+4)) == 0)
+ continue;
+
+ if (major != -1 && found_dot_a)
+ found_dot_a = 0;
+
+ /* XXX should verify the library is a.out/ELF? */
+
+ if (major == -1 && minor == -1)
+ goto compare_version;
+ else if (major != -1 && minor == -1) {
+ if (tmp[0] == major)
+ goto compare_version;
+ } else if (major != -1 && minor != -1) {
+ if (tmp[0] == major) {
+ if (n == 1 || tmp[1] >= minor)
+ goto compare_version;
+ }
+ }
+
+ /* else, this file does not qualify */
+ continue;
+
+ compare_version:
+ if (_cmpndewey(tmp, n, dewey, ndewey) <= 0)
+ continue;
+
+ /* We have a better version */
+ found_dot_so = 1;
+ snprintf(path, sizeof(path), "%s/%s", search_dirs[i],
+ dp->d_name);
+ found_dot_a = 0;
+ bcopy(tmp, dewey, sizeof(dewey));
+ ndewey = n;
+ *majorp = dewey[0];
+ *minorp = dewey[1];
+ }
+ closedir(dd);
+
+ if (found_dot_a || found_dot_so)
+ /*
+ * There's a lib in this dir; take it.
+ */
+ return (path[0] ? path : NULL);
+ }
+
+ return (path[0] ? path : NULL);
+}
+
+void *
+_citrus_find_getops(_citrus_module_t handle, const char *modname,
+ const char *ifname)
+{
+ char name[PATH_MAX];
+ void *p;
+
+ snprintf(name, sizeof(name), "_citrus_%s_%s_getops",
+ modname, ifname);
+ p = dlsym((void *)handle, name);
+ return (p);
+}
+
+int
+_citrus_load_module(_citrus_module_t *rhandle, const char *encname)
+{
+ const char *p;
+ char path[PATH_MAX];
+ void *handle;
+ int maj, min;
+
+ if (_pathI18nModule == NULL) {
+ p = getenv("PATH_I18NMODULE");
+ if (p != NULL && !issetugid()) {
+ _pathI18nModule = strdup(p);
+ if (_pathI18nModule == NULL)
+ return (ENOMEM);
+ } else
+ _pathI18nModule = _PATH_I18NMODULE;
+ }
+
+ (void)snprintf(path, sizeof(path), "lib%s", encname);
+ maj = I18NMODULE_MAJOR;
+ min = -1;
+ p = _findshlib(path, &maj, &min);
+ if (!p)
+ return (EINVAL);
+ handle = libc_dlopen(p, RTLD_LAZY);
+ if (!handle) {
+ printf("%s", dlerror());
+ return (EINVAL);
+ }
+
+ *rhandle = (_citrus_module_t)handle;
+
+ return (0);
+}
+
+void
+_citrus_unload_module(_citrus_module_t handle)
+{
+
+ if (handle)
+ dlclose((void *)handle);
+}
diff --git a/lib/libc/iconv/citrus_module.h b/lib/libc/iconv/citrus_module.h
new file mode 100644
index 000000000000..b004b87efb38
--- /dev/null
+++ b/lib/libc/iconv/citrus_module.h
@@ -0,0 +1,54 @@
+/* $FreeBSD$ */
+/* $NetBSD: citrus_module.h,v 1.1 2002/03/17 22:14:20 tshiozak Exp $ */
+
+/*-
+ * Copyright (c)2002 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#ifndef _CITRUS_MODULE_H_
+#define _CITRUS_MODULE_H_
+
+#define MATCH(x, act) \
+do { \
+ if (lenvar >= (sizeof(#x)-1) && \
+ _bcs_strncasecmp(p, #x, sizeof(#x)-1) == 0) { \
+ act; \
+ lenvar -= sizeof(#x)-1; \
+ p += sizeof(#x)-1; \
+ } \
+} while (0)
+
+typedef struct _citrus_module_rec *_citrus_module_t;
+
+__BEGIN_DECLS
+void *_citrus_find_getops(_citrus_module_t __restrict,
+ const char * __restrict, const char * __restrict);
+int _citrus_load_module(_citrus_module_t * __restrict,
+ const char * __restrict);
+void _citrus_unload_module(_citrus_module_t);
+__END_DECLS
+
+#endif
diff --git a/lib/libc/iconv/citrus_namespace.h b/lib/libc/iconv/citrus_namespace.h
new file mode 100644
index 000000000000..6e9ffe0509f8
--- /dev/null
+++ b/lib/libc/iconv/citrus_namespace.h
@@ -0,0 +1,241 @@
+/* $FreeBSD$ */
+/* $NetBSD: citrus_namespace.h,v 1.8 2009/01/11 02:46:24 christos Exp $ */
+
+/*-
+ * Copyright (c)2003 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "citrus_bcs.h"
+
+#ifndef _CITRUS_NAMESPACE_H_
+#define _CITRUS_NAMESPACE_H_
+
+/* citrus_alias */
+#ifndef _CITRUS_ALIAS_NO_NAMESPACE
+#define _alias_lookup _citrus_alias_lookup
+#endif /* _CITRUS_ALIAS_NO_NAMESPACE */
+
+/* citrus_bcs */
+#ifndef _CITRUS_BCS_NO_NAMESPACE
+#define _bcs_isalnum _citrus_bcs_isalnum
+#define _bcs_isalpha _citrus_bcs_isalpha
+#define _bcs_isblank _citrus_bcs_isblank
+#define _bcs_isdigit _citrus_bcs_isdigit
+#define _bcs_islower _citrus_bcs_islower
+#define _bcs_iseol _citrus_bcs_iseol
+#define _bcs_isspace _citrus_bcs_isspace
+#define _bcs_isupper _citrus_bcs_isupper
+#define _bcs_isxdigit _citrus_bcs_isxdigit
+#define _bcs_skip_nonws _citrus_bcs_skip_nonws
+#define _bcs_skip_nonws_len _citrus_bcs_skip_nonws_len
+#define _bcs_skip_ws _citrus_bcs_skip_ws
+#define _bcs_skip_ws_len _citrus_bcs_skip_ws_len
+#define _bcs_strcasecmp _citrus_bcs_strcasecmp
+#define _bcs_strncasecmp _citrus_bcs_strncasecmp
+#define _bcs_tolower _citrus_bcs_tolower
+#define _bcs_toupper _citrus_bcs_toupper
+#define _bcs_trunc_rws_len _citrus_bcs_trunc_rws_len
+#define _bcs_convert_to_lower _citrus_bcs_convert_to_lower
+#define _bcs_convert_to_upper _citrus_bcs_convert_to_upper
+#define _bcs_strtol _citrus_bcs_strtol
+#define _bcs_strtoul _citrus_bcs_strtoul
+#endif /* _CITRUS_BCS_NO_NAMESPACE */
+
+/* citrus_csmapper */
+#ifndef _CITRUS_CSMAPPER_NO_NAMESPACE
+#define _csmapper _citrus_csmapper
+#define _csmapper_open _citrus_csmapper_open
+#define _csmapper_close _citrus_csmapper_close
+#define _csmapper_convert _citrus_csmapper_convert
+#define _csmapper_init_state _citrus_csmapper_init_state
+#define _csmapper_get_state_size _citrus_csmapper_get_state_size
+#define _csmapper_get_src_max _citrus_csmapper_get_src_max
+#define _csmapper_get_dst_max _citrus_csmapper_get_dst_max
+#define _CSMAPPER_F_PREVENT_PIVOT _CITRUS_CSMAPPER_F_PREVENT_PIVOT
+#endif /* _CITRUS_CSMAPPER_NO_NAMESPACE */
+
+/* citrus_db */
+#ifndef _CITRUS_DB_NO_NAMESPACE
+#define _db_open _citrus_db_open
+#define _db_close _citrus_db_close
+#define _db_lookup _citrus_db_lookup
+#define _db_lookup_by_s _citrus_db_lookup_by_string
+#define _db_lookup8_by_s _citrus_db_lookup8_by_string
+#define _db_lookup16_by_s _citrus_db_lookup16_by_string
+#define _db_lookup32_by_s _citrus_db_lookup32_by_string
+#define _db_lookupstr_by_s _citrus_db_lookup_string_by_string
+#define _db_hash_std _citrus_db_hash_std
+#define _db_get_num_entries _citrus_db_get_number_of_entries
+#define _db_get_entry _citrus_db_get_entry
+#define _db_locator _citrus_db_locator
+#define _db_locator_init _citrus_db_locator_init
+#endif /* _CITRUS_DB_NO_NAMESPACE */
+
+/* citrus_db_factory */
+#ifndef _CITRUS_DB_FACTORY_NO_NAMESPACE
+#define _db_factory _citrus_db_factory
+#define _db_factory_create _citrus_db_factory_create
+#define _db_factory_free _citrus_db_factory_free
+#define _db_factory_add _citrus_db_factory_add
+#define _db_factory_add_by_s _citrus_db_factory_add_by_string
+#define _db_factory_add8_by_s _citrus_db_factory_add8_by_string
+#define _db_factory_add16_by_s _citrus_db_factory_add16_by_string
+#define _db_factory_add32_by_s _citrus_db_factory_add32_by_string
+#define _db_factory_addstr_by_s _citrus_db_factory_add_string_by_string
+#define _db_factory_calc_size _citrus_db_factory_calc_size
+#define _db_factory_serialize _citrus_db_factory_serialize
+#endif /* _CITRUS_DB_FACTORY_NO_NAMESPACE */
+
+/* citrus_lookup */
+#ifndef _CITRUS_DB_NO_NAMESPACE
+#define _LOOKUP_CASE_SENSITIVE _CITRUS_LOOKUP_CASE_SENSITIVE
+#define _LOOKUP_CASE_IGNORE _CITRUS_LOOKUP_CASE_IGNORE
+#define _lookup _citrus_lookup
+#define _lookup_simple _citrus_lookup_simple
+#define _lookup_alias _citrus_lookup_alias
+#define _lookup_seq_open _citrus_lookup_seq_open
+#define _lookup_seq_rewind _citrus_lookup_seq_rewind
+#define _lookup_seq_next _citrus_lookup_seq_next
+#define _lookup_seq_lookup _citrus_lookup_seq_lookup
+#define _lookup_get_num_entries _citrus_lookup_get_number_of_entries
+#define _lookup_seq_close _citrus_lookup_seq_close
+#define _lookup_factory_convert _citrus_lookup_factory_convert
+#endif /* _CITRUS_DB_NO_NAMESPACE */
+
+/* citrus_esdb */
+#ifndef _CITRUS_ESDB_NO_NAMESPACE
+#define _esdb _citrus_esdb
+#define _esdb_charset _citrus_esdb_charset
+#define _esdb_open _citrus_esdb_open
+#define _esdb_close _citrus_esdb_close
+#define _esdb_get_list _citrus_esdb_get_list
+#define _esdb_free_list _citrus_esdb_free_list
+#endif /* _CITRUS_ESDB_NO_NAMESPACE */
+
+/* citrus_hash */
+#ifndef _CITRUS_HASH_NO_NAMESPACE
+#define _citrus_string_hash_func _string_hash_func
+#endif /* _CITRUS_HASH_NO_NAMESPACE */
+
+/* citrus_mapper */
+#ifndef _CITRUS_MAPPER_NO_NAMESPACE
+#define _mapper _citrus_mapper
+#define _mapper_ops _citrus_mapper_ops
+#define _mapper_traits _citrus_mapper_traits
+#define _mapper_open _citrus_mapper_open
+#define _mapper_open_direct _citrus_mapper_open_direct
+#define _mapper_close _citrus_mapper_close
+#define _MAPPER_CONVERT_SUCCESS _CITRUS_MAPPER_CONVERT_SUCCESS
+#define _MAPPER_CONVERT_NONIDENTICAL _CITRUS_MAPPER_CONVERT_NONIDENTICAL
+#define _MAPPER_CONVERT_SRC_MORE _CITRUS_MAPPER_CONVERT_SRC_MORE
+#define _MAPPER_CONVERT_DST_MORE _CITRUS_MAPPER_CONVERT_DST_MORE
+#define _MAPPER_CONVERT_ILSEQ _CITRUS_MAPPER_CONVERT_ILSEQ
+#define _MAPPER_CONVERT_FATAL _CITRUS_MAPPER_CONVERT_FATAL
+#define _mapper_convert _citrus_mapper_convert
+#define _mapper_init_state _citrus_mapper_init_state
+#define _mapper_get_state_size _citrus_mapper_get_state_size
+#define _mapper_get_src_max _citrus_mapper_get_src_max
+#define _mapper_get_dst_max _citrus_mapper_get_dst_max
+#define _mapper_set_persistent _citrus_mapper_set_persistent
+#endif /* _CITRUS_MAPPER_NO_NAMESPACE */
+
+/* citrus_memstream */
+#ifndef _CITRUS_MEMSTREAM_NO_NAMESPACE
+#define _memstream _citrus_memory_stream
+#define _memstream_getln _citrus_memory_stream_getln
+#define _memstream_matchline _citrus_memory_stream_matchline
+#define _memstream_chr _citrus_memory_stream_chr
+#define _memstream_skip_ws _citrus_memory_stream_skip_ws
+#define _memstream_iseof _citrus_memory_stream_iseof
+#define _memstream_bind _citrus_memory_stream_bind
+#define _memstream_bind_ptr _citrus_memory_stream_bind_ptr
+#define _memstream_seek _citrus_memory_stream_seek
+#define _memstream_rewind _citrus_memory_stream_rewind
+#define _memstream_tell _citrus_memory_stream_tell
+#define _memstream_remainder _citrus_memory_stream_remainder
+#define _memstream_getc _citrus_memory_stream_getc
+#define _memstream_ungetc _citrus_memory_stream_ungetc
+#define _memstream_peek _citrus_memory_stream_peek
+#define _memstream_getregion _citrus_memory_stream_getregion
+#define _memstream_getln_region _citrus_memory_stream_getln_region
+#endif /* _CITRUS_MEMSTREAM_NO_NAMESPACE */
+
+/* citrus_mmap */
+#ifndef _CITRUS_MMAP_NO_NAMESPACE
+#define _map_file _citrus_map_file
+#define _unmap_file _citrus_unmap_file
+#endif /* _CITRUS_MMAP_NO_NAMESPACE */
+
+#ifndef _CITRUS_PIVOT_NO_NAMESPACE
+#define _pivot_factory_convert _citrus_pivot_factory_convert
+#endif /* _CITRUS_PIVOT_NO_NAMESPACE */
+
+/* citrus_region.h */
+#ifndef _CITRUS_REGION_NO_NAMESPACE
+#define _region _citrus_region
+#define _region_init _citrus_region_init
+#define _region_head _citrus_region_head
+#define _region_size _citrus_region_size
+#define _region_check _citrus_region_check
+#define _region_offset _citrus_region_offset
+#define _region_peek8 _citrus_region_peek8
+#define _region_peek16 _citrus_region_peek16
+#define _region_peek32 _citrus_region_peek32
+#define _region_get_subregion _citrus_region_get_subregion
+#endif /* _CITRUS_REGION_NO_NAMESPACE */
+
+/* citrus_stdenc.h */
+#ifndef _CITRUS_STDENC_NO_NAMESPACE
+#define _stdenc _citrus_stdenc
+#define _stdenc_ops _citrus_stdenc_ops
+#define _stdenc_traits _citrus_stdenc_traits
+#define _stdenc_state_desc _citrus_stdenc_state_desc
+#define _stdenc_open _citrus_stdenc_open
+#define _stdenc_close _citrus_stdenc_close
+#define _stdenc_init_state _citrus_stdenc_init_state
+#define _stdenc_mbtocs _citrus_stdenc_mbtocs
+#define _stdenc_cstomb _citrus_stdenc_cstomb
+#define _stdenc_mbtowc _citrus_stdenc_mbtowc
+#define _stdenc_wctomb _citrus_stdenc_wctomb
+#define _stdenc_put_state_reset _citrus_stdenc_put_state_reset
+#define _stdenc_get_state_size _citrus_stdenc_get_state_size
+#define _stdenc_get_mb_cur_max _citrus_stdenc_get_mb_cur_max
+#define _stdenc_get_state_desc _citrus_stdenc_get_state_desc
+#define _STDENC_SDID_GENERIC _CITRUS_STDENC_SDID_GENERIC
+#define _STDENC_SDGEN_UNKNOWN _CITRUS_STDENC_SDGEN_UNKNOWN
+#define _STDENC_SDGEN_INITIAL _CITRUS_STDENC_SDGEN_INITIAL
+#define _STDENC_SDGEN_STABLE _CITRUS_STDENC_SDGEN_STABLE
+#define _STDENC_SDGEN_INCOMPLETE_CHAR _CITRUS_STDENC_SDGEN_INCOMPLETE_CHAR
+#define _STDENC_SDGEN_INCOMPLETE_SHIFT _CITRUS_STDENC_SDGEN_INCOMPLETE_SHIFT
+#endif /* _CITRUS_STDENC_NO_NAMESPACE */
+
+/* citrus_types.h */
+#ifndef _CITRUS_TYPES_NO_NAMESPACE
+#define _index_t _citrus_index_t
+#define _csid_t _citrus_csid_t
+#define _wc_t _citrus_wc_t
+#endif /* _CITRUS_TYPES_NO_NAMESPACE */
+
+#endif
diff --git a/lib/libc/iconv/citrus_none.c b/lib/libc/iconv/citrus_none.c
new file mode 100644
index 000000000000..9ec4bd360cb8
--- /dev/null
+++ b/lib/libc/iconv/citrus_none.c
@@ -0,0 +1,237 @@
+/* $FreeBSD$ */
+/* $NetBSD: citrus_none.c,v 1.18 2008/06/14 16:01:07 tnozaki Exp $ */
+
+/*-
+ * Copyright (c) 2002 Citrus Project,
+ * Copyright (c) 2010 Gabor Kovesdan <gabor@FreeBSD.org>,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <iconv.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+
+#include "citrus_namespace.h"
+#include "citrus_types.h"
+#include "citrus_module.h"
+#include "citrus_none.h"
+#include "citrus_stdenc.h"
+
+_CITRUS_STDENC_DECLS(NONE);
+_CITRUS_STDENC_DEF_OPS(NONE);
+struct _citrus_stdenc_traits _citrus_NONE_stdenc_traits = {
+ 0, /* et_state_size */
+ 1, /* mb_cur_max */
+};
+
+static int
+_citrus_NONE_stdenc_init(struct _citrus_stdenc * __restrict ce,
+ const void *var __unused, size_t lenvar __unused,
+ struct _citrus_stdenc_traits * __restrict et)
+{
+
+ et->et_state_size = 0;
+ et->et_mb_cur_max = 1;
+
+ ce->ce_closure = NULL;
+
+ return (0);
+}
+
+static void
+_citrus_NONE_stdenc_uninit(struct _citrus_stdenc *ce __unused)
+{
+
+}
+
+static int
+_citrus_NONE_stdenc_init_state(struct _citrus_stdenc * __restrict ce __unused,
+ void * __restrict ps __unused)
+{
+
+ return (0);
+}
+
+static int
+_citrus_NONE_stdenc_mbtocs(struct _citrus_stdenc * __restrict ce __unused,
+ _csid_t *csid, _index_t *idx, char **s, size_t n,
+ void *ps __unused, size_t *nresult, struct iconv_hooks *hooks)
+{
+
+ if (n < 1) {
+ *nresult = (size_t)-2;
+ return (0);
+ }
+
+ *csid = 0;
+ *idx = (_index_t)(unsigned char)*(*s)++;
+ *nresult = *idx == 0 ? 0 : 1;
+
+ if ((hooks != NULL) && (hooks->uc_hook != NULL))
+ hooks->uc_hook((unsigned int)*idx, hooks->data);
+
+ return (0);
+}
+
+static int
+_citrus_NONE_stdenc_cstomb(struct _citrus_stdenc * __restrict ce __unused,
+ char *s, size_t n, _csid_t csid, _index_t idx, void *ps __unused,
+ size_t *nresult, struct iconv_hooks *hooks __unused)
+{
+
+ if (csid == _CITRUS_CSID_INVALID) {
+ *nresult = 0;
+ return (0);
+ }
+ if (csid != 0)
+ return (EILSEQ);
+
+ if ((idx & 0x000000FF) == idx) {
+ if (n < 1) {
+ *nresult = (size_t)-1;
+ return (E2BIG);
+ }
+ *s = (char)idx;
+ *nresult = 1;
+ } else if ((idx & 0x0000FFFF) == idx) {
+ if (n < 2) {
+ *nresult = (size_t)-1;
+ return (E2BIG);
+ }
+ s[0] = (char)idx;
+ /* XXX: might be endian dependent */
+ s[1] = (char)(idx >> 8);
+ *nresult = 2;
+ } else if ((idx & 0x00FFFFFF) == idx) {
+ if (n < 3) {
+ *nresult = (size_t)-1;
+ return (E2BIG);
+ }
+ s[0] = (char)idx;
+ /* XXX: might be endian dependent */
+ s[1] = (char)(idx >> 8);
+ s[2] = (char)(idx >> 16);
+ *nresult = 3;
+ } else {
+ if (n < 3) {
+ *nresult = (size_t)-1;
+ return (E2BIG);
+ }
+ s[0] = (char)idx;
+ /* XXX: might be endian dependent */
+ s[1] = (char)(idx >> 8);
+ s[2] = (char)(idx >> 16);
+ s[3] = (char)(idx >> 24);
+ *nresult = 4;
+ }
+
+ return (0);
+}
+
+static int
+_citrus_NONE_stdenc_mbtowc(struct _citrus_stdenc * __restrict ce __unused,
+ _wc_t * __restrict pwc, char ** __restrict s, size_t n,
+ void * __restrict pspriv __unused, size_t * __restrict nresult,
+ struct iconv_hooks *hooks)
+{
+
+ if (s == NULL) {
+ *nresult = 0;
+ return (0);
+ }
+ if (n == 0) {
+ *nresult = (size_t)-2;
+ return (0);
+ }
+
+ if (pwc != NULL)
+ *pwc = (_wc_t)(unsigned char) **s;
+
+ *nresult = *s == '\0' ? 0 : 1;
+
+ if ((hooks != NULL) && (hooks->wc_hook != NULL))
+ hooks->wc_hook(*pwc, hooks->data);
+
+ return (0);
+}
+
+static int
+_citrus_NONE_stdenc_wctomb(struct _citrus_stdenc * __restrict ce __unused,
+ char * __restrict s, size_t n, _wc_t wc,
+ void * __restrict pspriv __unused, size_t * __restrict nresult,
+ struct iconv_hooks *hooks __unused)
+{
+
+ if ((wc & ~0xFFU) != 0) {
+ *nresult = (size_t)-1;
+ return (EILSEQ);
+ }
+ if (n == 0) {
+ *nresult = (size_t)-1;
+ return (E2BIG);
+ }
+
+ *nresult = 1;
+ if (s != NULL && n > 0)
+ *s = (char)wc;
+
+ return (0);
+}
+
+static int
+_citrus_NONE_stdenc_put_state_reset(struct _citrus_stdenc * __restrict ce __unused,
+ char * __restrict s __unused, size_t n __unused,
+ void * __restrict pspriv __unused, size_t * __restrict nresult)
+{
+
+ *nresult = 0;
+
+ return (0);
+}
+
+static int
+_citrus_NONE_stdenc_get_state_desc(struct _stdenc * __restrict ce __unused,
+ void * __restrict ps __unused, int id,
+ struct _stdenc_state_desc * __restrict d)
+{
+ int ret = 0;
+
+ switch (id) {
+ case _STDENC_SDID_GENERIC:
+ d->u.generic.state = _STDENC_SDGEN_INITIAL;
+ break;
+ default:
+ ret = EOPNOTSUPP;
+ }
+
+ return (ret);
+}
diff --git a/lib/libc/iconv/citrus_none.h b/lib/libc/iconv/citrus_none.h
new file mode 100644
index 000000000000..20d27910ebcf
--- /dev/null
+++ b/lib/libc/iconv/citrus_none.h
@@ -0,0 +1,36 @@
+/* $FreeBSD$ */
+/* $NetBSD: citrus_none.h,v 1.3 2003/06/25 09:51:38 tshiozak Exp $ */
+
+/*-
+ * Copyright (c)2002 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _CITRUS_NONE_H_
+#define _CITRUS_NONE_H_
+
+extern struct _citrus_stdenc_ops _citrus_NONE_stdenc_ops;
+extern struct _citrus_stdenc_traits _citrus_NONE_stdenc_traits;
+
+#endif
diff --git a/lib/libc/iconv/citrus_pivot_factory.c b/lib/libc/iconv/citrus_pivot_factory.c
new file mode 100644
index 000000000000..0f279b10cf71
--- /dev/null
+++ b/lib/libc/iconv/citrus_pivot_factory.c
@@ -0,0 +1,225 @@
+/* $FreeBSD$ */
+/* $NetBSD: citrus_pivot_factory.c,v 1.7 2009/04/12 14:20:19 lukem Exp $ */
+
+/*-
+ * Copyright (c)2003 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#include <sys/queue.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "citrus_namespace.h"
+#include "citrus_region.h"
+#include "citrus_bcs.h"
+#include "citrus_db_factory.h"
+#include "citrus_db_hash.h"
+#include "citrus_pivot_file.h"
+#include "citrus_pivot_factory.h"
+
+struct src_entry {
+ char *se_name;
+ struct _citrus_db_factory *se_df;
+ STAILQ_ENTRY(src_entry) se_entry;
+};
+STAILQ_HEAD(src_head, src_entry);
+
+static int
+find_src(struct src_head *sh, struct src_entry **rse, const char *name)
+{
+ int ret;
+ struct src_entry *se;
+
+ STAILQ_FOREACH(se, sh, se_entry) {
+ if (_bcs_strcasecmp(se->se_name, name) == 0) {
+ *rse = se;
+ return (0);
+ }
+ }
+ se = malloc(sizeof(*se));
+ if (se == NULL)
+ return (errno);
+ se->se_name = strdup(name);
+ if (se->se_name == NULL) {
+ ret = errno;
+ free(se);
+ return (ret);
+ }
+ ret = _db_factory_create(&se->se_df, &_db_hash_std, NULL);
+ if (ret) {
+ free(se->se_name);
+ free(se);
+ return (ret);
+ }
+ STAILQ_INSERT_TAIL(sh, se, se_entry);
+ *rse = se;
+
+ return (0);
+}
+
+static void
+free_src(struct src_head *sh)
+{
+ struct src_entry *se;
+
+ while ((se = STAILQ_FIRST(sh)) != NULL) {
+ STAILQ_REMOVE_HEAD(sh, se_entry);
+ _db_factory_free(se->se_df);
+ free(se->se_name);
+ free(se);
+ }
+}
+
+
+#define T_COMM '#'
+static int
+convert_line(struct src_head *sh, const char *line, size_t len)
+{
+ struct src_entry *se;
+ const char *p;
+ char key1[LINE_MAX], key2[LINE_MAX], data[LINE_MAX];
+ char *ep;
+ uint32_t val;
+ int ret;
+
+ se = NULL;
+
+ /* cut off trailing comment */
+ p = memchr(line, T_COMM, len);
+ if (p)
+ len = p - line;
+
+ /* key1 */
+ line = _bcs_skip_ws_len(line, &len);
+ if (len == 0)
+ return (0);
+ p = _bcs_skip_nonws_len(line, &len);
+ if (p == line)
+ return (0);
+ snprintf(key1, sizeof(key1), "%.*s", (int)(p - line), line);
+
+ /* key2 */
+ line = _bcs_skip_ws_len(p, &len);
+ if (len == 0)
+ return (0);
+ p = _bcs_skip_nonws_len(line, &len);
+ if (p == line)
+ return (0);
+ snprintf(key2, sizeof(key2), "%.*s", (int)(p - line), line);
+
+ /* data */
+ line = _bcs_skip_ws_len(p, &len);
+ _bcs_trunc_rws_len(line, &len);
+ snprintf(data, sizeof(data), "%.*s", (int)len, line);
+ val = strtoul(data, &ep, 0);
+ if (*ep != '\0')
+ return (EFTYPE);
+
+ /* insert to DB */
+ ret = find_src(sh, &se, key1);
+ if (ret)
+ return (ret);
+
+ return (_db_factory_add32_by_s(se->se_df, key2, val));
+}
+
+static int
+dump_db(struct src_head *sh, struct _region *r)
+{
+ struct _db_factory *df;
+ struct src_entry *se;
+ struct _region subr;
+ void *ptr;
+ size_t size;
+ int ret;
+
+ ret = _db_factory_create(&df, &_db_hash_std, NULL);
+ if (ret)
+ return (ret);
+
+ STAILQ_FOREACH(se, sh, se_entry) {
+ size = _db_factory_calc_size(se->se_df);
+ ptr = malloc(size);
+ if (ptr == NULL)
+ goto quit;
+ _region_init(&subr, ptr, size);
+ ret = _db_factory_serialize(se->se_df, _CITRUS_PIVOT_SUB_MAGIC,
+ &subr);
+ if (ret)
+ goto quit;
+ ret = _db_factory_add_by_s(df, se->se_name, &subr, 1);
+ if (ret)
+ goto quit;
+ }
+
+ size = _db_factory_calc_size(df);
+ ptr = malloc(size);
+ if (ptr == NULL)
+ goto quit;
+ _region_init(r, ptr, size);
+
+ ret = _db_factory_serialize(df, _CITRUS_PIVOT_MAGIC, r);
+ ptr = NULL;
+
+quit:
+ free(ptr);
+ _db_factory_free(df);
+ return (ret);
+}
+
+int
+_citrus_pivot_factory_convert(FILE *out, FILE *in)
+{
+ struct src_head sh;
+ struct _region r;
+ char *line;
+ size_t size;
+ int ret;
+
+ STAILQ_INIT(&sh);
+
+ while ((line = fgetln(in, &size)) != NULL)
+ if ((ret = convert_line(&sh, line, size))) {
+ free_src(&sh);
+ return (ret);
+ }
+
+ ret = dump_db(&sh, &r);
+ free_src(&sh);
+ if (ret)
+ return (ret);
+
+ if (fwrite(_region_head(&r), _region_size(&r), 1, out) != 1)
+ return (errno);
+
+ return (0);
+}
diff --git a/lib/libc/iconv/citrus_pivot_factory.h b/lib/libc/iconv/citrus_pivot_factory.h
new file mode 100644
index 000000000000..76f0f707c9ac
--- /dev/null
+++ b/lib/libc/iconv/citrus_pivot_factory.h
@@ -0,0 +1,37 @@
+/* $FreeBSD$ */
+/* $NetBSD: citrus_pivot_factory.h,v 1.1 2003/06/25 09:51:39 tshiozak Exp $ */
+
+/*-
+ * Copyright (c)2003 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _CITRUS_PIVOT_FACTORY_H_
+#define _CITRUS_PIVOT_FACTORY_H_
+
+__BEGIN_DECLS
+int _citrus_pivot_factory_convert(FILE *, FILE *);
+__END_DECLS
+
+#endif
diff --git a/lib/libc/iconv/citrus_pivot_file.h b/lib/libc/iconv/citrus_pivot_file.h
new file mode 100644
index 000000000000..454e93a9d29f
--- /dev/null
+++ b/lib/libc/iconv/citrus_pivot_file.h
@@ -0,0 +1,36 @@
+/* $FreeBSD$ */
+/* $NetBSD: citrus_pivot_file.h,v 1.1 2003/06/25 09:51:39 tshiozak Exp $ */
+
+/*-
+ * Copyright (c)2003 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _CITRUS_PIVOT_FILE_H_
+#define _CITRUS_PIVOT_FILE_H_
+
+#define _CITRUS_PIVOT_MAGIC "CSPIVOT\0"
+#define _CITRUS_PIVOT_SUB_MAGIC "CSPIVSUB"
+
+#endif
diff --git a/lib/libc/iconv/citrus_prop.c b/lib/libc/iconv/citrus_prop.c
new file mode 100644
index 000000000000..642e4230986a
--- /dev/null
+++ b/lib/libc/iconv/citrus_prop.c
@@ -0,0 +1,445 @@
+/* $FreeBSD$ */
+/* $NetBSD: citrus_prop.c,v 1.4 2011/03/30 08:22:01 jruoho Exp $ */
+
+/*-
+ * Copyright (c)2006 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "citrus_namespace.h"
+#include "citrus_bcs.h"
+#include "citrus_region.h"
+#include "citrus_memstream.h"
+#include "citrus_prop.h"
+
+typedef struct {
+ _citrus_prop_type_t type;
+ union {
+ const char *str;
+ int chr;
+ bool boolean;
+ uint64_t num;
+ } u;
+} _citrus_prop_object_t;
+
+static __inline void
+_citrus_prop_object_init(_citrus_prop_object_t *obj, _citrus_prop_type_t type)
+{
+
+ obj->type = type;
+ memset(&obj->u, 0, sizeof(obj->u));
+}
+
+static __inline void
+_citrus_prop_object_uninit(_citrus_prop_object_t *obj)
+{
+
+ if (obj->type == _CITRUS_PROP_STR)
+ free(__DECONST(void *, obj->u.str));
+}
+
+static const char *xdigit = "0123456789ABCDEF";
+
+#define _CITRUS_PROP_READ_UINT_COMMON(_func_, _type_, _max_) \
+static int \
+_citrus_prop_read_##_func_##_common(struct _memstream * __restrict ms, \
+ _type_ * __restrict result, int base) \
+{ \
+ _type_ acc, cutoff; \
+ int ch, cutlim, n; \
+ char *p; \
+ \
+ acc = (_type_)0; \
+ cutoff = _max_ / base; \
+ cutlim = _max_ % base; \
+ for (;;) { \
+ ch = _memstream_getc(ms); \
+ p = strchr(xdigit, _bcs_toupper(ch)); \
+ if (p == NULL || (n = (p - xdigit)) >= base) \
+ break; \
+ if (acc > cutoff || (acc == cutoff && n > cutlim)) \
+ break; \
+ acc *= base; \
+ acc += n; \
+ } \
+ _memstream_ungetc(ms, ch); \
+ *result = acc; \
+ return (0); \
+}
+_CITRUS_PROP_READ_UINT_COMMON(chr, int, UCHAR_MAX)
+_CITRUS_PROP_READ_UINT_COMMON(num, uint64_t, UINT64_MAX)
+#undef _CITRUS_PROP_READ_UINT_COMMON
+
+#define _CITRUS_PROP_READ_INT(_func_, _type_) \
+static int \
+_citrus_prop_read_##_func_(struct _memstream * __restrict ms, \
+ _citrus_prop_object_t * __restrict obj) \
+{ \
+ int base, ch, neg; \
+ \
+ _memstream_skip_ws(ms); \
+ ch = _memstream_getc(ms); \
+ neg = 0; \
+ switch (ch) { \
+ case '-': \
+ neg = 1; \
+ case '+': \
+ ch = _memstream_getc(ms); \
+ } \
+ base = 10; \
+ if (ch == '0') { \
+ base -= 2; \
+ ch = _memstream_getc(ms); \
+ if (ch == 'x' || ch == 'X') { \
+ ch = _memstream_getc(ms); \
+ if (_bcs_isxdigit(ch) == 0) { \
+ _memstream_ungetc(ms, ch); \
+ obj->u._func_ = 0; \
+ return (0); \
+ } \
+ base += 8; \
+ } \
+ } else if (_bcs_isdigit(ch) == 0) \
+ return (EINVAL); \
+ _memstream_ungetc(ms, ch); \
+ return (_citrus_prop_read_##_func_##_common \
+ (ms, &obj->u._func_, base)); \
+}
+_CITRUS_PROP_READ_INT(chr, int)
+_CITRUS_PROP_READ_INT(num, uint64_t)
+#undef _CITRUS_PROP_READ_INT
+
+static int
+_citrus_prop_read_character_common(struct _memstream * __restrict ms,
+ int * __restrict result)
+{
+ int base, ch;
+
+ ch = _memstream_getc(ms);
+ if (ch != '\\')
+ *result = ch;
+ else {
+ ch = _memstream_getc(ms);
+ base = 16;
+ switch (ch) {
+ case 'a':
+ *result = '\a';
+ break;
+ case 'b':
+ *result = '\b';
+ break;
+ case 'f':
+ *result = '\f';
+ break;
+ case 'n':
+ *result = '\n';
+ break;
+ case 'r':
+ *result = '\r';
+ break;
+ case 't':
+ *result = '\t';
+ break;
+ case 'v':
+ *result = '\v';
+ break;
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ _memstream_ungetc(ms, ch);
+ base -= 8;
+ /*FALLTHROUGH*/
+ case 'x':
+ return (_citrus_prop_read_chr_common(ms, result, base));
+ /*NOTREACHED*/
+ default:
+ /* unknown escape */
+ *result = ch;
+ }
+ }
+ return (0);
+}
+
+static int
+_citrus_prop_read_character(struct _memstream * __restrict ms,
+ _citrus_prop_object_t * __restrict obj)
+{
+ int ch, errnum;
+
+ _memstream_skip_ws(ms);
+ ch = _memstream_getc(ms);
+ if (ch != '\'') {
+ _memstream_ungetc(ms, ch);
+ return (_citrus_prop_read_chr(ms, obj));
+ }
+ errnum = _citrus_prop_read_character_common(ms, &ch);
+ if (errnum != 0)
+ return (errnum);
+ obj->u.chr = ch;
+ ch = _memstream_getc(ms);
+ if (ch != '\'')
+ return (EINVAL);
+ return (0);
+}
+
+static int
+_citrus_prop_read_bool(struct _memstream * __restrict ms,
+ _citrus_prop_object_t * __restrict obj)
+{
+
+ _memstream_skip_ws(ms);
+ switch (_bcs_tolower(_memstream_getc(ms))) {
+ case 't':
+ if (_bcs_tolower(_memstream_getc(ms)) == 'r' &&
+ _bcs_tolower(_memstream_getc(ms)) == 'u' &&
+ _bcs_tolower(_memstream_getc(ms)) == 'e') {
+ obj->u.boolean = true;
+ return (0);
+ }
+ break;
+ case 'f':
+ if (_bcs_tolower(_memstream_getc(ms)) == 'a' &&
+ _bcs_tolower(_memstream_getc(ms)) == 'l' &&
+ _bcs_tolower(_memstream_getc(ms)) == 's' &&
+ _bcs_tolower(_memstream_getc(ms)) == 'e') {
+ obj->u.boolean = false;
+ return (0);
+ }
+ }
+ return (EINVAL);
+}
+
+static int
+_citrus_prop_read_str(struct _memstream * __restrict ms,
+ _citrus_prop_object_t * __restrict obj)
+{
+ int ch, errnum, quot;
+ char *s, *t;
+#define _CITRUS_PROP_STR_BUFSIZ 512
+ size_t m, n;
+
+ m = _CITRUS_PROP_STR_BUFSIZ;
+ s = malloc(m);
+ if (s == NULL)
+ return (ENOMEM);
+ n = 0;
+ _memstream_skip_ws(ms);
+ quot = _memstream_getc(ms);
+ switch (quot) {
+ case EOF:
+ goto done;
+ /*NOTREACHED*/
+ case '\\':
+ _memstream_ungetc(ms, quot);
+ quot = EOF;
+ /*FALLTHROUGH*/
+ case '\"': case '\'':
+ break;
+ default:
+ s[n] = quot;
+ ++n, --m;
+ quot = EOF;
+ }
+ for (;;) {
+ if (m < 1) {
+ m = _CITRUS_PROP_STR_BUFSIZ;
+ t = realloc(s, n + m);
+ if (t == NULL) {
+ free(s);
+ return (ENOMEM);
+ }
+ s = t;
+ }
+ ch = _memstream_getc(ms);
+ if (quot == ch || (quot == EOF &&
+ (ch == ';' || _bcs_isspace(ch)))) {
+done:
+ s[n] = '\0';
+ obj->u.str = (const char *)s;
+ return (0);
+ }
+ _memstream_ungetc(ms, ch);
+ errnum = _citrus_prop_read_character_common(ms, &ch);
+ if (errnum != 0) {
+ free(s);
+ return (errnum);
+ }
+ s[n] = ch;
+ ++n, --m;
+ }
+ free(s);
+ return (EINVAL);
+#undef _CITRUS_PROP_STR_BUFSIZ
+}
+
+typedef int (*_citrus_prop_read_type_t)(struct _memstream * __restrict,
+ _citrus_prop_object_t * __restrict);
+
+static const _citrus_prop_read_type_t readers[] = {
+ _citrus_prop_read_bool,
+ _citrus_prop_read_str,
+ _citrus_prop_read_character,
+ _citrus_prop_read_num,
+};
+
+static __inline int
+_citrus_prop_read_symbol(struct _memstream * __restrict ms,
+ char * __restrict s, size_t n)
+{
+ int ch;
+ size_t m;
+
+ for (m = 0; m < n; ++m) {
+ ch = _memstream_getc(ms);
+ if (ch != '_' && _bcs_isalnum(ch) == 0)
+ goto name_found;
+ s[m] = ch;
+ }
+ ch = _memstream_getc(ms);
+ if (ch == '_' || _bcs_isalnum(ch) != 0)
+ return (EINVAL);
+
+name_found:
+ _memstream_ungetc(ms, ch);
+ s[m] = '\0';
+
+ return (0);
+}
+
+static int
+_citrus_prop_parse_element(struct _memstream * __restrict ms,
+ const _citrus_prop_hint_t * __restrict hints, void * __restrict context)
+{
+ int ch, errnum;
+#define _CITRUS_PROP_HINT_NAME_LEN_MAX 255
+ char name[_CITRUS_PROP_HINT_NAME_LEN_MAX + 1];
+ const _citrus_prop_hint_t *hint;
+ _citrus_prop_object_t ostart, oend;
+
+ errnum = _citrus_prop_read_symbol(ms, name, sizeof(name));
+ if (errnum != 0)
+ return (errnum);
+ for (hint = hints; hint->name != NULL; ++hint)
+ if (_citrus_bcs_strcasecmp(name, hint->name) == 0)
+ goto hint_found;
+ return (EINVAL);
+
+hint_found:
+ _memstream_skip_ws(ms);
+ ch = _memstream_getc(ms);
+ if (ch != '=' && ch != ':')
+ _memstream_ungetc(ms, ch);
+ do {
+ _citrus_prop_object_init(&ostart, hint->type);
+ _citrus_prop_object_init(&oend, hint->type);
+ errnum = (*readers[hint->type])(ms, &ostart);
+ if (errnum != 0)
+ return (errnum);
+ _memstream_skip_ws(ms);
+ ch = _memstream_getc(ms);
+ switch (hint->type) {
+ case _CITRUS_PROP_BOOL:
+ /*FALLTHROUGH*/
+ case _CITRUS_PROP_STR:
+ break;
+ default:
+ if (ch != '-')
+ break;
+ errnum = (*readers[hint->type])(ms, &oend);
+ if (errnum != 0)
+ return (errnum);
+ _memstream_skip_ws(ms);
+ ch = _memstream_getc(ms);
+ }
+#define CALL0(_func_) \
+do { \
+ errnum = (*hint->cb._func_.func)(context, \
+ hint->name, ostart.u._func_); \
+} while (0)
+#define CALL1(_func_) \
+do { \
+ errnum = (*hint->cb._func_.func)(context, \
+ hint->name, ostart.u._func_, oend.u._func_);\
+} while (0)
+ switch (hint->type) {
+ case _CITRUS_PROP_BOOL:
+ CALL0(boolean);
+ break;
+ case _CITRUS_PROP_STR:
+ CALL0(str);
+ break;
+ case _CITRUS_PROP_CHR:
+ CALL1(chr);
+ break;
+ case _CITRUS_PROP_NUM:
+ CALL1(num);
+ break;
+ default:
+ abort();
+ /*NOTREACHED*/
+ }
+#undef CALL0
+#undef CALL1
+ _citrus_prop_object_uninit(&ostart);
+ _citrus_prop_object_uninit(&oend);
+ if (errnum != 0)
+ return (errnum);
+ } while (ch == ',');
+ if (ch != ';')
+ _memstream_ungetc(ms, ch);
+ return (0);
+}
+
+int
+_citrus_prop_parse_variable(const _citrus_prop_hint_t * __restrict hints,
+ void * __restrict context, const void *var, size_t lenvar)
+{
+ struct _memstream ms;
+ int ch, errnum;
+
+ _memstream_bind_ptr(&ms, __DECONST(void *, var), lenvar);
+ for (;;) {
+ _memstream_skip_ws(&ms);
+ ch = _memstream_getc(&ms);
+ if (ch == EOF || ch == '\0')
+ break;
+ _memstream_ungetc(&ms, ch);
+ errnum = _citrus_prop_parse_element(&ms, hints, context);
+ if (errnum != 0)
+ return (errnum);
+ }
+ return (0);
+}
diff --git a/lib/libc/iconv/citrus_prop.h b/lib/libc/iconv/citrus_prop.h
new file mode 100644
index 000000000000..48fc066295c6
--- /dev/null
+++ b/lib/libc/iconv/citrus_prop.h
@@ -0,0 +1,92 @@
+/* $FreeBSD$ */
+/* $NetBSD: citrus_prop.h,v 1.5 2011/05/23 14:52:32 joerg Exp $ */
+
+/*-
+ * Copyright (c)2006 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#ifndef _CITRUS_PROP_H_
+#define _CITRUS_PROP_H_
+
+typedef enum {
+ _CITRUS_PROP_BOOL = 0,
+ _CITRUS_PROP_STR = 1,
+ _CITRUS_PROP_CHR = 2,
+ _CITRUS_PROP_NUM = 3,
+} _citrus_prop_type_t;
+
+typedef struct _citrus_prop_hint_t _citrus_prop_hint_t;
+
+#define _CITRUS_PROP_CB0_T(_func_, _type_) \
+typedef int (*_citrus_prop_##_func_##_cb_func_t) \
+ (void * __restrict, const char *, _type_); \
+typedef struct { \
+ _citrus_prop_##_func_##_cb_func_t func; \
+} _citrus_prop_##_func_##_cb_t;
+_CITRUS_PROP_CB0_T(boolean, int)
+_CITRUS_PROP_CB0_T(str, const char *)
+#undef _CITRUS_PROP_CB0_T
+
+#define _CITRUS_PROP_CB1_T(_func_, _type_) \
+typedef int (*_citrus_prop_##_func_##_cb_func_t) \
+ (void * __restrict, const char *, _type_, _type_); \
+typedef struct { \
+ _citrus_prop_##_func_##_cb_func_t func; \
+} _citrus_prop_##_func_##_cb_t;
+_CITRUS_PROP_CB1_T(chr, int)
+_CITRUS_PROP_CB1_T(num, uint64_t)
+#undef _CITRUS_PROP_CB1_T
+
+struct _citrus_prop_hint_t {
+ const char *name;
+ _citrus_prop_type_t type;
+#define _CITRUS_PROP_CB_T_OPS(_name_) \
+ _citrus_prop_##_name_##_cb_t _name_
+ union {
+ _CITRUS_PROP_CB_T_OPS(boolean);
+ _CITRUS_PROP_CB_T_OPS(str);
+ _CITRUS_PROP_CB_T_OPS(chr);
+ _CITRUS_PROP_CB_T_OPS(num);
+ } cb;
+};
+
+#define _CITRUS_PROP_HINT_BOOL(name, cb) \
+ { name, _CITRUS_PROP_BOOL, { .boolean = { cb } } }
+#define _CITRUS_PROP_HINT_STR(name, cb) \
+ { name, _CITRUS_PROP_STR, { .str = { cb } } }
+#define _CITRUS_PROP_HINT_CHR(name, cb) \
+ { name, _CITRUS_PROP_CHR, { .chr = { cb } } }
+#define _CITRUS_PROP_HINT_NUM(name, cb) \
+ { name, _CITRUS_PROP_NUM, { .num = { cb } } }
+#define _CITRUS_PROP_HINT_END \
+ { .name = NULL }
+
+__BEGIN_DECLS
+int _citrus_prop_parse_variable(const _citrus_prop_hint_t * __restrict,
+ void * __restrict, const void *, size_t);
+__END_DECLS
+
+#endif /* !_CITRUS_PROP_H_ */
diff --git a/lib/libc/iconv/citrus_region.h b/lib/libc/iconv/citrus_region.h
new file mode 100644
index 000000000000..8cecb409bec3
--- /dev/null
+++ b/lib/libc/iconv/citrus_region.h
@@ -0,0 +1,113 @@
+/* $FreeBSD$ */
+/* $NetBSD: citrus_region.h,v 1.7 2008/02/09 14:56:20 junyoung Exp $ */
+
+/*-
+ * Copyright (c)2003 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#ifndef _CITRUS_REGION_H_
+#define _CITRUS_REGION_H_
+
+#include <sys/types.h>
+
+struct _citrus_region {
+ void *r_head;
+ size_t r_size;
+};
+
+static __inline void
+_citrus_region_init(struct _citrus_region *r, void *h, size_t sz)
+{
+
+ r->r_head = h;
+ r->r_size = sz;
+}
+
+static __inline void *
+_citrus_region_head(const struct _citrus_region *r)
+{
+
+ return (r->r_head);
+}
+
+static __inline size_t
+_citrus_region_size(const struct _citrus_region *r)
+{
+
+ return (r->r_size);
+}
+
+static __inline int
+_citrus_region_check(const struct _citrus_region *r, size_t ofs, size_t sz)
+{
+
+ return (r->r_size >= ofs + sz ? 0 : -1);
+}
+
+static __inline void *
+_citrus_region_offset(const struct _citrus_region *r, size_t pos)
+{
+
+ return ((void *)((uint8_t *)r->r_head + pos));
+}
+
+static __inline uint8_t
+_citrus_region_peek8(const struct _citrus_region *r, size_t pos)
+{
+
+ return (*(uint8_t *)_citrus_region_offset(r, pos));
+}
+
+static __inline uint16_t
+_citrus_region_peek16(const struct _citrus_region *r, size_t pos)
+{
+ uint16_t val;
+
+ memcpy(&val, _citrus_region_offset(r, pos), (size_t)2);
+ return (val);
+}
+
+static __inline uint32_t
+_citrus_region_peek32(const struct _citrus_region *r, size_t pos)
+{
+ uint32_t val;
+
+ memcpy(&val, _citrus_region_offset(r, pos), (size_t)4);
+ return (val);
+}
+
+static __inline int
+_citrus_region_get_subregion(struct _citrus_region *subr,
+ const struct _citrus_region *r, size_t ofs, size_t sz)
+{
+
+ if (_citrus_region_check(r, ofs, sz))
+ return (-1);
+ _citrus_region_init(subr, _citrus_region_offset(r, ofs), sz);
+ return (0);
+}
+
+#endif
diff --git a/lib/libc/iconv/citrus_stdenc.c b/lib/libc/iconv/citrus_stdenc.c
new file mode 100644
index 000000000000..cef530e2a69e
--- /dev/null
+++ b/lib/libc/iconv/citrus_stdenc.c
@@ -0,0 +1,147 @@
+/* $FreeBSD$ */
+/* $NetBSD: citrus_stdenc.c,v 1.4 2011/11/19 18:39:58 tnozaki Exp $ */
+
+/*-
+ * Copyright (c)2003 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "citrus_namespace.h"
+#include "citrus_types.h"
+#include "citrus_module.h"
+#include "citrus_none.h"
+#include "citrus_stdenc.h"
+
+struct _citrus_stdenc _citrus_stdenc_default = {
+ &_citrus_NONE_stdenc_ops, /* ce_ops */
+ NULL, /* ce_closure */
+ NULL, /* ce_module */
+ &_citrus_NONE_stdenc_traits, /* ce_traits */
+};
+
+int
+_citrus_stdenc_open(struct _citrus_stdenc * __restrict * __restrict rce,
+ char const * __restrict encname, const void * __restrict variable,
+ size_t lenvar)
+{
+ struct _citrus_stdenc *ce;
+ _citrus_module_t handle;
+ _citrus_stdenc_getops_t getops;
+ int ret;
+
+ if (!strcmp(encname, _CITRUS_DEFAULT_STDENC_NAME)) {
+ *rce = &_citrus_stdenc_default;
+ return (0);
+ }
+ ce = malloc(sizeof(*ce));
+ if (ce == NULL) {
+ ret = errno;
+ goto bad;
+ }
+ ce->ce_ops = NULL;
+ ce->ce_closure = NULL;
+ ce->ce_module = NULL;
+ ce->ce_traits = NULL;
+
+ ret = _citrus_load_module(&handle, encname);
+ if (ret)
+ goto bad;
+
+ ce->ce_module = handle;
+
+ getops = (_citrus_stdenc_getops_t)_citrus_find_getops(ce->ce_module,
+ encname, "stdenc");
+ if (getops == NULL) {
+ ret = EINVAL;
+ goto bad;
+ }
+
+ ce->ce_ops = (struct _citrus_stdenc_ops *)malloc(sizeof(*ce->ce_ops));
+ if (ce->ce_ops == NULL) {
+ ret = errno;
+ goto bad;
+ }
+
+ ret = (*getops)(ce->ce_ops, sizeof(*ce->ce_ops));
+ if (ret)
+ goto bad;
+
+ /* validation check */
+ if (ce->ce_ops->eo_init == NULL ||
+ ce->ce_ops->eo_uninit == NULL ||
+ ce->ce_ops->eo_init_state == NULL ||
+ ce->ce_ops->eo_mbtocs == NULL ||
+ ce->ce_ops->eo_cstomb == NULL ||
+ ce->ce_ops->eo_mbtowc == NULL ||
+ ce->ce_ops->eo_wctomb == NULL ||
+ ce->ce_ops->eo_get_state_desc == NULL) {
+ ret = EINVAL;
+ goto bad;
+ }
+
+ /* allocate traits */
+ ce->ce_traits = malloc(sizeof(*ce->ce_traits));
+ if (ce->ce_traits == NULL) {
+ ret = errno;
+ goto bad;
+ }
+ /* init and get closure */
+ ret = (*ce->ce_ops->eo_init)(ce, variable, lenvar, ce->ce_traits);
+ if (ret)
+ goto bad;
+
+ *rce = ce;
+
+ return (0);
+
+bad:
+ _citrus_stdenc_close(ce);
+ return (ret);
+}
+
+void
+_citrus_stdenc_close(struct _citrus_stdenc *ce)
+{
+
+ if (ce == &_citrus_stdenc_default)
+ return;
+
+ if (ce->ce_module) {
+ if (ce->ce_ops) {
+ if (ce->ce_closure && ce->ce_ops->eo_uninit)
+ (*ce->ce_ops->eo_uninit)(ce);
+ free(ce->ce_ops);
+ }
+ free(ce->ce_traits);
+ _citrus_unload_module(ce->ce_module);
+ }
+ free(ce);
+}
diff --git a/lib/libc/iconv/citrus_stdenc.h b/lib/libc/iconv/citrus_stdenc.h
new file mode 100644
index 000000000000..50f4dffa4e16
--- /dev/null
+++ b/lib/libc/iconv/citrus_stdenc.h
@@ -0,0 +1,124 @@
+/* $FreeBSD$ */
+/* $NetBSD: citrus_stdenc.h,v 1.4 2005/10/29 18:02:04 tshiozak Exp $ */
+
+/*-
+ * Copyright (c)2003 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#ifndef _CITRUS_STDENC_H_
+#define _CITRUS_STDENC_H_
+
+struct _citrus_stdenc;
+struct _citrus_stdenc_ops;
+struct _citrus_stdenc_traits;
+
+#define _CITRUS_STDENC_SDID_GENERIC 0
+struct _citrus_stdenc_state_desc
+{
+ union {
+ struct {
+ int state;
+#define _CITRUS_STDENC_SDGEN_UNKNOWN 0
+#define _CITRUS_STDENC_SDGEN_INITIAL 1
+#define _CITRUS_STDENC_SDGEN_STABLE 2
+#define _CITRUS_STDENC_SDGEN_INCOMPLETE_CHAR 3
+#define _CITRUS_STDENC_SDGEN_INCOMPLETE_SHIFT 4
+ } generic;
+ } u;
+};
+
+#include "citrus_stdenc_local.h"
+
+__BEGIN_DECLS
+int _citrus_stdenc_open(struct _citrus_stdenc * __restrict * __restrict,
+ char const * __restrict, const void * __restrict, size_t);
+void _citrus_stdenc_close(struct _citrus_stdenc *);
+__END_DECLS
+
+static __inline int
+_citrus_stdenc_init_state(struct _citrus_stdenc * __restrict ce,
+ void * __restrict ps)
+{
+
+ return ((*ce->ce_ops->eo_init_state)(ce, ps));
+}
+
+static __inline int
+_citrus_stdenc_mbtocs(struct _citrus_stdenc * __restrict ce,
+ _citrus_csid_t * __restrict csid, _citrus_index_t * __restrict idx,
+ char ** __restrict s, size_t n, void * __restrict ps,
+ size_t * __restrict nresult, struct iconv_hooks *hooks)
+{
+
+ return ((*ce->ce_ops->eo_mbtocs)(ce, csid, idx, s, n, ps, nresult,
+ hooks));
+}
+
+static __inline int
+_citrus_stdenc_cstomb(struct _citrus_stdenc * __restrict ce,
+ char * __restrict s, size_t n, _citrus_csid_t csid, _citrus_index_t idx,
+ void * __restrict ps, size_t * __restrict nresult,
+ struct iconv_hooks *hooks)
+{
+
+ return ((*ce->ce_ops->eo_cstomb)(ce, s, n, csid, idx, ps, nresult,
+ hooks));
+}
+
+static __inline int
+_citrus_stdenc_wctomb(struct _citrus_stdenc * __restrict ce,
+ char * __restrict s, size_t n, _citrus_wc_t wc, void * __restrict ps,
+ size_t * __restrict nresult, struct iconv_hooks *hooks)
+{
+
+ return ((*ce->ce_ops->eo_wctomb)(ce, s, n, wc, ps, nresult, hooks));
+}
+
+static __inline int
+_citrus_stdenc_put_state_reset(struct _citrus_stdenc * __restrict ce,
+ char * __restrict s, size_t n, void * __restrict ps,
+ size_t * __restrict nresult)
+{
+
+ return ((*ce->ce_ops->eo_put_state_reset)(ce, s, n, ps, nresult));
+}
+
+static __inline size_t
+_citrus_stdenc_get_state_size(struct _citrus_stdenc *ce)
+{
+
+ return (ce->ce_traits->et_state_size);
+}
+
+static __inline int
+_citrus_stdenc_get_state_desc(struct _citrus_stdenc * __restrict ce,
+ void * __restrict ps, int id,
+ struct _citrus_stdenc_state_desc * __restrict d)
+{
+
+ return ((*ce->ce_ops->eo_get_state_desc)(ce, ps, id, d));
+}
+#endif
diff --git a/lib/libc/iconv/citrus_stdenc_local.h b/lib/libc/iconv/citrus_stdenc_local.h
new file mode 100644
index 000000000000..141abffea9b9
--- /dev/null
+++ b/lib/libc/iconv/citrus_stdenc_local.h
@@ -0,0 +1,162 @@
+/* $FreeBSD$ */
+/* $NetBSD: citrus_stdenc_local.h,v 1.4 2008/02/09 14:56:20 junyoung Exp $ */
+
+/*-
+ * Copyright (c)2003 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#ifndef _CITRUS_STDENC_LOCAL_H_
+#define _CITRUS_STDENC_LOCAL_H_
+
+#include <iconv.h>
+
+#include "citrus_module.h"
+
+#define _CITRUS_STDENC_GETOPS_FUNC_BASE(n) \
+ int n(struct _citrus_stdenc_ops *, size_t)
+#define _CITRUS_STDENC_GETOPS_FUNC(_e_) \
+ _CITRUS_STDENC_GETOPS_FUNC_BASE(_citrus_##_e_##_stdenc_getops)
+typedef _CITRUS_STDENC_GETOPS_FUNC_BASE((*_citrus_stdenc_getops_t));
+
+
+#define _CITRUS_STDENC_DECLS(_e_) \
+static int _citrus_##_e_##_stdenc_init \
+ (struct _citrus_stdenc * __restrict, \
+ const void * __restrict, size_t, \
+ struct _citrus_stdenc_traits * __restrict); \
+static void _citrus_##_e_##_stdenc_uninit(struct _citrus_stdenc *);\
+static int _citrus_##_e_##_stdenc_init_state \
+ (struct _citrus_stdenc * __restrict, \
+ void * __restrict); \
+static int _citrus_##_e_##_stdenc_mbtocs \
+ (struct _citrus_stdenc * __restrict, \
+ _citrus_csid_t * __restrict, \
+ _citrus_index_t * __restrict, \
+ char ** __restrict, size_t, \
+ void * __restrict, size_t * __restrict, \
+ struct iconv_hooks *); \
+static int _citrus_##_e_##_stdenc_cstomb \
+ (struct _citrus_stdenc * __restrict, \
+ char * __restrict, size_t, _citrus_csid_t, \
+ _citrus_index_t, void * __restrict, \
+ size_t * __restrict, struct iconv_hooks *); \
+static int _citrus_##_e_##_stdenc_mbtowc \
+ (struct _citrus_stdenc * __restrict, \
+ _citrus_wc_t * __restrict, \
+ char ** __restrict, size_t, \
+ void * __restrict, size_t * __restrict, \
+ struct iconv_hooks *); \
+static int _citrus_##_e_##_stdenc_wctomb \
+ (struct _citrus_stdenc * __restrict, \
+ char * __restrict, size_t, _citrus_wc_t, \
+ void * __restrict, size_t * __restrict, \
+ struct iconv_hooks *); \
+static int _citrus_##_e_##_stdenc_put_state_reset \
+ (struct _citrus_stdenc * __restrict, \
+ char * __restrict, size_t, void * __restrict, \
+ size_t * __restrict); \
+static int _citrus_##_e_##_stdenc_get_state_desc \
+ (struct _citrus_stdenc * __restrict, \
+ void * __restrict, int, \
+ struct _citrus_stdenc_state_desc * __restrict)
+
+#define _CITRUS_STDENC_DEF_OPS(_e_) \
+extern struct _citrus_stdenc_ops _citrus_##_e_##_stdenc_ops; \
+struct _citrus_stdenc_ops _citrus_##_e_##_stdenc_ops = { \
+ /* eo_init */ &_citrus_##_e_##_stdenc_init, \
+ /* eo_uninit */ &_citrus_##_e_##_stdenc_uninit, \
+ /* eo_init_state */ &_citrus_##_e_##_stdenc_init_state, \
+ /* eo_mbtocs */ &_citrus_##_e_##_stdenc_mbtocs, \
+ /* eo_cstomb */ &_citrus_##_e_##_stdenc_cstomb, \
+ /* eo_mbtowc */ &_citrus_##_e_##_stdenc_mbtowc, \
+ /* eo_wctomb */ &_citrus_##_e_##_stdenc_wctomb, \
+ /* eo_put_state_reset */&_citrus_##_e_##_stdenc_put_state_reset,\
+ /* eo_get_state_desc */ &_citrus_##_e_##_stdenc_get_state_desc \
+}
+
+typedef int (*_citrus_stdenc_init_t)
+ (struct _citrus_stdenc * __reatrict, const void * __restrict , size_t,
+ struct _citrus_stdenc_traits * __restrict);
+typedef void (*_citrus_stdenc_uninit_t)(struct _citrus_stdenc * __restrict);
+typedef int (*_citrus_stdenc_init_state_t)
+ (struct _citrus_stdenc * __restrict, void * __restrict);
+typedef int (*_citrus_stdenc_mbtocs_t)
+ (struct _citrus_stdenc * __restrict,
+ _citrus_csid_t * __restrict, _citrus_index_t * __restrict,
+ char ** __restrict, size_t,
+ void * __restrict, size_t * __restrict,
+ struct iconv_hooks *);
+typedef int (*_citrus_stdenc_cstomb_t)
+ (struct _citrus_stdenc *__restrict, char * __restrict, size_t,
+ _citrus_csid_t, _citrus_index_t, void * __restrict,
+ size_t * __restrict, struct iconv_hooks *);
+typedef int (*_citrus_stdenc_mbtowc_t)
+ (struct _citrus_stdenc * __restrict,
+ _citrus_wc_t * __restrict,
+ char ** __restrict, size_t,
+ void * __restrict, size_t * __restrict,
+ struct iconv_hooks *);
+typedef int (*_citrus_stdenc_wctomb_t)
+ (struct _citrus_stdenc *__restrict, char * __restrict, size_t,
+ _citrus_wc_t, void * __restrict, size_t * __restrict,
+ struct iconv_hooks *);
+typedef int (*_citrus_stdenc_put_state_reset_t)
+ (struct _citrus_stdenc *__restrict, char * __restrict, size_t,
+ void * __restrict, size_t * __restrict);
+typedef int (*_citrus_stdenc_get_state_desc_t)
+ (struct _citrus_stdenc * __restrict, void * __restrict, int,
+ struct _citrus_stdenc_state_desc * __restrict);
+
+struct _citrus_stdenc_ops {
+ _citrus_stdenc_init_t eo_init;
+ _citrus_stdenc_uninit_t eo_uninit;
+ _citrus_stdenc_init_state_t eo_init_state;
+ _citrus_stdenc_mbtocs_t eo_mbtocs;
+ _citrus_stdenc_cstomb_t eo_cstomb;
+ _citrus_stdenc_mbtowc_t eo_mbtowc;
+ _citrus_stdenc_wctomb_t eo_wctomb;
+ _citrus_stdenc_put_state_reset_t eo_put_state_reset;
+ /* version 0x00000002 */
+ _citrus_stdenc_get_state_desc_t eo_get_state_desc;
+};
+
+struct _citrus_stdenc_traits {
+ /* version 0x00000001 */
+ size_t et_state_size;
+ size_t et_mb_cur_max;
+};
+
+struct _citrus_stdenc {
+ /* version 0x00000001 */
+ struct _citrus_stdenc_ops *ce_ops;
+ void *ce_closure;
+ _citrus_module_t ce_module;
+ struct _citrus_stdenc_traits *ce_traits;
+};
+
+#define _CITRUS_DEFAULT_STDENC_NAME "NONE"
+
+#endif
diff --git a/lib/libc/iconv/citrus_stdenc_template.h b/lib/libc/iconv/citrus_stdenc_template.h
new file mode 100644
index 000000000000..9a05fa789fa6
--- /dev/null
+++ b/lib/libc/iconv/citrus_stdenc_template.h
@@ -0,0 +1,211 @@
+/* $FreeBSD$ */
+/* $NetBSD: citrus_stdenc_template.h,v 1.4 2008/02/09 14:56:20 junyoung Exp $ */
+
+/*-
+ * Copyright (c)2003 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <iconv.h>
+
+/*
+ * CAUTION: THIS IS NOT STANDALONE FILE
+ *
+ * function templates of iconv standard encoding handler for each encodings.
+ *
+ */
+
+/*
+ * macros
+ */
+
+#undef _TO_EI
+#undef _CE_TO_EI
+#undef _TO_STATE
+#define _TO_EI(_cl_) ((_ENCODING_INFO*)(_cl_))
+#define _CE_TO_EI(_ce_) (_TO_EI((_ce_)->ce_closure))
+#define _TO_STATE(_ps_) ((_ENCODING_STATE*)(_ps_))
+
+/* ----------------------------------------------------------------------
+ * templates for public functions
+ */
+
+int
+_FUNCNAME(stdenc_getops)(struct _citrus_stdenc_ops *ops,
+ size_t lenops __unused)
+{
+
+ memcpy(ops, &_FUNCNAME(stdenc_ops), sizeof(_FUNCNAME(stdenc_ops)));
+
+ return (0);
+}
+
+static int
+_FUNCNAME(stdenc_init)(struct _citrus_stdenc * __restrict ce,
+ const void * __restrict var, size_t lenvar,
+ struct _citrus_stdenc_traits * __restrict et)
+{
+ _ENCODING_INFO *ei;
+ int ret;
+
+ ei = NULL;
+ if (sizeof(_ENCODING_INFO) > 0) {
+ ei = calloc(1, sizeof(_ENCODING_INFO));
+ if (ei == NULL)
+ return (errno);
+ }
+
+ ret = _FUNCNAME(encoding_module_init)(ei, var, lenvar);
+ if (ret) {
+ free((void *)ei);
+ return (ret);
+ }
+
+ ce->ce_closure = ei;
+ et->et_state_size = sizeof(_ENCODING_STATE);
+ et->et_mb_cur_max = _ENCODING_MB_CUR_MAX(_CE_TO_EI(ce));
+
+ return (0);
+}
+
+static void
+_FUNCNAME(stdenc_uninit)(struct _citrus_stdenc * __restrict ce)
+{
+
+ if (ce) {
+ _FUNCNAME(encoding_module_uninit)(_CE_TO_EI(ce));
+ free(ce->ce_closure);
+ }
+}
+
+static int
+_FUNCNAME(stdenc_init_state)(struct _citrus_stdenc * __restrict ce,
+ void * __restrict ps)
+{
+
+ _FUNCNAME(init_state)(_CE_TO_EI(ce), _TO_STATE(ps));
+
+ return (0);
+}
+
+static int
+_FUNCNAME(stdenc_mbtocs)(struct _citrus_stdenc * __restrict ce,
+ _citrus_csid_t * __restrict csid, _citrus_index_t * __restrict idx,
+ char ** __restrict s, size_t n, void * __restrict ps,
+ size_t * __restrict nresult, struct iconv_hooks *hooks)
+{
+ wchar_t wc;
+ int ret;
+
+ ret = _FUNCNAME(mbrtowc_priv)(_CE_TO_EI(ce), &wc, s, n,
+ _TO_STATE(ps), nresult);
+
+ if ((ret == 0) && *nresult != (size_t)-2)
+ ret = _FUNCNAME(stdenc_wctocs)(_CE_TO_EI(ce), csid, idx, wc);
+
+ if ((ret == 0) && (hooks != NULL) && (hooks->uc_hook != NULL))
+ hooks->uc_hook((unsigned int)*idx, hooks->data);
+ return (ret);
+}
+
+static int
+_FUNCNAME(stdenc_cstomb)(struct _citrus_stdenc * __restrict ce,
+ char * __restrict s, size_t n, _citrus_csid_t csid, _citrus_index_t idx,
+ void * __restrict ps, size_t * __restrict nresult,
+ struct iconv_hooks *hooks __unused)
+{
+ wchar_t wc;
+ int ret;
+
+ wc = ret = 0;
+
+ if (csid != _CITRUS_CSID_INVALID)
+ ret = _FUNCNAME(stdenc_cstowc)(_CE_TO_EI(ce), &wc, csid, idx);
+
+ if (ret == 0)
+ ret = _FUNCNAME(wcrtomb_priv)(_CE_TO_EI(ce), s, n, wc,
+ _TO_STATE(ps), nresult);
+ return (ret);
+}
+
+static int
+_FUNCNAME(stdenc_mbtowc)(struct _citrus_stdenc * __restrict ce,
+ _citrus_wc_t * __restrict wc, char ** __restrict s, size_t n,
+ void * __restrict ps, size_t * __restrict nresult,
+ struct iconv_hooks *hooks)
+{
+ int ret;
+
+ ret = _FUNCNAME(mbrtowc_priv)(_CE_TO_EI(ce), wc, s, n,
+ _TO_STATE(ps), nresult);
+ if ((ret == 0) && (hooks != NULL) && (hooks->wc_hook != NULL))
+ hooks->wc_hook(*wc, hooks->data);
+ return (ret);
+}
+
+static int
+_FUNCNAME(stdenc_wctomb)(struct _citrus_stdenc * __restrict ce,
+ char * __restrict s, size_t n, _citrus_wc_t wc, void * __restrict ps,
+ size_t * __restrict nresult, struct iconv_hooks *hooks __unused)
+{
+ int ret;
+
+ ret = _FUNCNAME(wcrtomb_priv)(_CE_TO_EI(ce), s, n, wc, _TO_STATE(ps),
+ nresult);
+ return (ret);
+}
+
+static int
+_FUNCNAME(stdenc_put_state_reset)(struct _citrus_stdenc * __restrict ce __unused,
+ char * __restrict s __unused, size_t n __unused,
+ void * __restrict ps __unused, size_t * __restrict nresult)
+{
+
+#if _ENCODING_IS_STATE_DEPENDENT
+ return ((_FUNCNAME(put_state_reset)(_CE_TO_EI(ce), s, n, _TO_STATE(ps),
+ nresult)));
+#else
+ *nresult = 0;
+ return (0);
+#endif
+}
+
+static int
+_FUNCNAME(stdenc_get_state_desc)(struct _citrus_stdenc * __restrict ce,
+ void * __restrict ps, int id,
+ struct _citrus_stdenc_state_desc * __restrict d)
+{
+ int ret;
+
+ switch (id) {
+ case _STDENC_SDID_GENERIC:
+ ret = _FUNCNAME(stdenc_get_state_desc_generic)(
+ _CE_TO_EI(ce), _TO_STATE(ps), &d->u.generic.state);
+ break;
+ default:
+ ret = EOPNOTSUPP;
+ }
+
+ return (ret);
+}
diff --git a/lib/libc/iconv/citrus_types.h b/lib/libc/iconv/citrus_types.h
new file mode 100644
index 000000000000..5f9c4e30d40b
--- /dev/null
+++ b/lib/libc/iconv/citrus_types.h
@@ -0,0 +1,40 @@
+/* $FreeBSD$ */
+/* $NetBSD: citrus_types.h,v 1.3 2003/10/27 00:12:42 lukem Exp $ */
+
+/*-
+ * Copyright (c)2003 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+
+#ifndef _CITRUS_TYPES_H_
+#define _CITRUS_TYPES_H_
+
+typedef uint32_t _citrus_wc_t;
+typedef uint32_t _citrus_index_t;
+typedef uint32_t _citrus_csid_t;
+#define _CITRUS_CSID_INVALID ((_citrus_csid_t)-1)
+
+#endif
diff --git a/lib/libc/iconv/iconv-internal.h b/lib/libc/iconv/iconv-internal.h
new file mode 100644
index 000000000000..214a8adf97ef
--- /dev/null
+++ b/lib/libc/iconv/iconv-internal.h
@@ -0,0 +1,45 @@
+/*-
+ * Copyright (c) 2013 Peter Wemm
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Internal prototypes for our back-end functions.
+ */
+size_t __bsd___iconv(iconv_t, char **, size_t *, char **,
+ size_t *, __uint32_t, size_t *);
+void __bsd___iconv_free_list(char **, size_t);
+int __bsd___iconv_get_list(char ***, size_t *, __iconv_bool);
+size_t __bsd_iconv(iconv_t, char ** __restrict,
+ size_t * __restrict, char ** __restrict,
+ size_t * __restrict);
+const char *__bsd_iconv_canonicalize(const char *);
+int __bsd_iconv_close(iconv_t);
+iconv_t __bsd_iconv_open(const char *, const char *);
+int __bsd_iconv_open_into(const char *, const char *, iconv_allocation_t *);
+void __bsd_iconv_set_relocation_prefix(const char *, const char *);
+int __bsd_iconvctl(iconv_t, int, void *);
+void __bsd_iconvlist(int (*) (unsigned int, const char * const *, void *), void *);
diff --git a/lib/libc/iconv/iconv.3 b/lib/libc/iconv/iconv.3
new file mode 100644
index 000000000000..1a4f8c3cfd75
--- /dev/null
+++ b/lib/libc/iconv/iconv.3
@@ -0,0 +1,309 @@
+.\" $FreeBSD$
+.\" $NetBSD: iconv.3,v 1.12 2004/08/02 13:38:21 tshiozak Exp $
+.\"
+.\" Copyright (c) 2003 Citrus Project,
+.\" Copyright (c) 2009, 2010 Gabor Kovesdan <gabor@FreeBSD.org>,
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.Dd August 4, 2014
+.Dt ICONV 3
+.Os
+.Sh NAME
+.Nm iconv_open ,
+.Nm iconv_open_into ,
+.Nm iconv_close ,
+.Nm iconv
+.Nd codeset conversion functions
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In iconv.h
+.Ft iconv_t
+.Fn iconv_open "const char *dstname" "const char *srcname"
+.Ft int
+.Fn iconv_open_into "const char *dstname" "const char *srcname" "iconv_allocation_t *ptr"
+.Ft int
+.Fn iconv_close "iconv_t cd"
+.Ft size_t
+.Fn iconv "iconv_t cd" "char ** restrict src" "size_t * restrict srcleft" "char ** restrict dst" "size_t * restrict dstleft"
+.Ft size_t
+.Fn __iconv "iconv_t cd" "char ** restrict src" "size_t * restrict srcleft" "char ** restrict dst" "size_t * restrict dstleft" "uint32_t flags" "size_t * invalids"
+.Sh DESCRIPTION
+The
+.Fn iconv_open
+function opens a converter from the codeset
+.Fa srcname
+to the codeset
+.Fa dstname
+and returns its descriptor.
+The arguments
+.Fa srcname
+and
+.Fa dstname
+accept "" and "char", which refer to the current locale encoding.
+.Pp
+The
+.Fn iconv_open_into
+creates a conversion descriptor on a preallocated space.
+The
+.Ft iconv_allocation_t
+is used as a spaceholder type when allocating such space.
+The
+.Fa dstname
+and
+.Fa srcname
+arguments are the same as in the case of
+.Fn iconv_open .
+The
+.Fa ptr
+argument is a pointer of
+.Ft iconv_allocation_t
+to the preallocated space.
+.Pp
+The
+.Fn iconv_close
+function closes the specified converter
+.Fa cd .
+.Pp
+The
+.Fn iconv
+function converts the string in the buffer
+.Fa *src
+of length
+.Fa *srcleft
+bytes and stores the converted string in the buffer
+.Fa *dst
+of size
+.Fa *dstleft
+bytes.
+After calling
+.Fn iconv ,
+the values pointed to by
+.Fa src ,
+.Fa srcleft ,
+.Fa dst ,
+and
+.Fa dstleft
+are updated as follows:
+.Bl -tag -width 01234567
+.It *src
+Pointer to the byte just after the last character fetched.
+.It *srcleft
+Number of remaining bytes in the source buffer.
+.It *dst
+Pointer to the byte just after the last character stored.
+.It *dstleft
+Number of remainder bytes in the destination buffer.
+.El
+.Pp
+If the string pointed to by
+.Fa *src
+contains a byte sequence which is not a valid character in the source
+codeset, the conversion stops just after the last successful conversion.
+If the output buffer is too small to store the converted
+character, the conversion also stops in the same way.
+In these cases, the values pointed to by
+.Fa src ,
+.Fa srcleft ,
+.Fa dst ,
+and
+.Fa dstleft
+are updated to the state just after the last successful conversion.
+.Pp
+If the string pointed to by
+.Fa *src
+contains a character which is valid under the source codeset but
+can not be converted to the destination codeset,
+the character is replaced by an
+.Dq invalid character
+which depends on the destination codeset, e.g.,
+.Sq \&? ,
+and the conversion is continued.
+.Fn iconv
+returns the number of such
+.Dq invalid conversions .
+.Pp
+There are two special cases of
+.Fn iconv :
+.Bl -tag -width 0123
+.It "src == NULL || *src == NULL"
+If the source and/or destination codesets are stateful,
+.Fn iconv
+places these into their initial state.
+.Pp
+If both
+.Fa dst
+and
+.Fa *dst
+are
+.No non- Ns Dv NULL ,
+.Fn iconv
+stores the shift sequence for the destination switching to the initial state
+in the buffer pointed to by
+.Fa *dst .
+The buffer size is specified by the value pointed to by
+.Fa dstleft
+as above.
+.Fn iconv
+will fail if the buffer is too small to store the shift sequence.
+.Pp
+On the other hand,
+.Fa dst
+or
+.Fa *dst
+may be
+.Dv NULL .
+In this case, the shift sequence for the destination switching
+to the initial state is discarded.
+.El
+.Pp
+The
+.Fn __iconv
+function works just like
+.Fn iconv
+but if
+.Fn iconv
+fails, the invalid character count is lost there.
+This is a not bug rather a limitation of
+.St -p1003.1-2008 ,
+so
+.Fn __iconv
+is provided as an alternative but non-standard interface.
+It also has a flags argument, where currently the following
+flags can be passed:
+.Bl -tag -width 0123
+.It __ICONV_F_HIDE_INVALID
+Skip invalid characters, instead of returning with an error.
+.El
+.Sh RETURN VALUES
+Upon successful completion of
+.Fn iconv_open ,
+it returns a conversion descriptor.
+Otherwise,
+.Fn iconv_open
+returns (iconv_t)\-1 and sets errno to indicate the error.
+.Pp
+Upon successful completion of
+.Fn iconv_open_into ,
+it returns 0.
+Otherwise,
+.Fn iconv_open_into
+returns \-1, and sets errno to indicate the error.
+.Pp
+Upon successful completion of
+.Fn iconv_close ,
+it returns 0.
+Otherwise,
+.Fn iconv_close
+returns \-1 and sets errno to indicate the error.
+.Pp
+Upon successful completion of
+.Fn iconv ,
+it returns the number of
+.Dq invalid
+conversions.
+Otherwise,
+.Fn iconv
+returns (size_t)\-1 and sets errno to indicate the error.
+.Sh ERRORS
+The
+.Fn iconv_open
+function may cause an error in the following cases:
+.Bl -tag -width Er
+.It Bq Er ENOMEM
+Memory is exhausted.
+.It Bq Er EINVAL
+There is no converter specified by
+.Fa srcname
+and
+.Fa dstname .
+.El
+The
+.Fn iconv_open_into
+function may cause an error in the following cases:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+There is no converter specified by
+.Fa srcname
+and
+.Fa dstname .
+.El
+.Pp
+The
+.Fn iconv_close
+function may cause an error in the following case:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The conversion descriptor specified by
+.Fa cd
+is invalid.
+.El
+.Pp
+The
+.Fn iconv
+function may cause an error in the following cases:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The conversion descriptor specified by
+.Fa cd
+is invalid.
+.It Bq Er EILSEQ
+The string pointed to by
+.Fa *src
+contains a byte sequence which does not describe a valid character of
+the source codeset.
+.It Bq Er E2BIG
+The output buffer pointed to by
+.Fa *dst
+is too small to store the result string.
+.It Bq Er EINVAL
+The string pointed to by
+.Fa *src
+terminates with an incomplete character or shift sequence.
+.El
+.Sh SEE ALSO
+.Xr iconv 1 ,
+.Xr mkcsmapper 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 ,
+.Fn iconv_close ,
+and
+.Fn iconv
+functions conform to
+.St -p1003.1-2008 .
+.Pp
+The
+.Fn iconv_open_into
+function is a GNU-specific extension and it is not part of any standard,
+thus its use may break portability.
+The
+.Fn __iconv
+function is an own extension and it is not part of any standard,
+thus its use may break portability.
diff --git a/lib/libc/iconv/iconv.c b/lib/libc/iconv/iconv.c
new file mode 100644
index 000000000000..4bd962009e65
--- /dev/null
+++ b/lib/libc/iconv/iconv.c
@@ -0,0 +1,39 @@
+/*-
+ * Copyright (c) 2013 Peter Wemm
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <iconv.h>
+#include "iconv-internal.h"
+
+size_t
+iconv(iconv_t a, char ** __restrict b,
+ size_t * __restrict c, char ** __restrict d,
+ size_t * __restrict e)
+{
+ return __bsd_iconv(a, b, c, d, e);
+}
diff --git a/lib/libc/iconv/iconv_canonicalize.3 b/lib/libc/iconv/iconv_canonicalize.3
new file mode 100644
index 000000000000..d98235aabbfd
--- /dev/null
+++ b/lib/libc/iconv/iconv_canonicalize.3
@@ -0,0 +1,74 @@
+.\" Copyright (c) 2009 Gabor Kovesdan <gabor@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" Portions of this text are reprinted and reproduced in electronic form
+.\" from IEEE Std 1003.1, 2004 Edition, Standard for Information Technology --
+.\" Portable Operating System Interface (POSIX), The Open Group Base
+.\" Specifications Issue 6, Copyright (C) 2001-2004 by the Institute of
+.\" Electrical and Electronics Engineers, Inc and The Open Group. In the
+.\" event of any discrepancy between this version and the original IEEE and
+.\" The Open Group Standard, the original IEEE and The Open Group Standard is
+.\" the referee document. The original Standard can be obtained online at
+.\" http://www.opengroup.org/unix/online.html.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd October 20, 2009
+.Dt ICONV_CANONICALIZE 3
+.Os
+.Sh NAME
+.Nm iconv_canonicalize
+.Nd resolving character encoding names to canonical form
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In iconv.h
+.Ft const char *
+.Fn iconv_canonicalize "const char *name"
+.Sh DESCRIPTION
+The
+.Fn iconv_canonicalize
+function resolves the character encoding name specified by the
+.Fa name
+argument to its canonical form.
+.Sh RETURN VALUES
+Upon successful completion
+.Fn iconv_canonicalize ,
+returns the canonical name of the given encoding.
+If the specified name is already a canonical name, the same
+value is returned.
+If the specified name is not an existing character encoding
+name, NULL is returned.
+.Sh SEE ALSO
+.Xr iconv 3
+.Sh STANDARDS
+The
+.Nm
+function is a non-standard extension, which appeared in
+the GNU implementation and was adopted in
+.Fx 9.0
+for compatibility's sake.
+.Sh AUTHORS
+This manual page was written by
+.An Gabor Kovesdan Aq Mt gabor@FreeBSD.org .
diff --git a/lib/libc/iconv/iconv_canonicalize.c b/lib/libc/iconv/iconv_canonicalize.c
new file mode 100644
index 000000000000..702a4168f295
--- /dev/null
+++ b/lib/libc/iconv/iconv_canonicalize.c
@@ -0,0 +1,37 @@
+/*-
+ * Copyright (c) 2013 Peter Wemm
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <iconv.h>
+#include "iconv-internal.h"
+
+const char *
+iconv_canonicalize(const char *a)
+{
+ return __bsd_iconv_canonicalize(a);
+}
diff --git a/lib/libc/iconv/iconv_close.c b/lib/libc/iconv/iconv_close.c
new file mode 100644
index 000000000000..1adbb8c6eb69
--- /dev/null
+++ b/lib/libc/iconv/iconv_close.c
@@ -0,0 +1,37 @@
+/*-
+ * Copyright (c) 2013 Peter Wemm
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <iconv.h>
+#include "iconv-internal.h"
+
+int
+iconv_close(iconv_t a)
+{
+ return __bsd_iconv_close(a);
+}
diff --git a/lib/libc/iconv/iconv_compat.c b/lib/libc/iconv/iconv_compat.c
new file mode 100644
index 000000000000..ded249956db9
--- /dev/null
+++ b/lib/libc/iconv/iconv_compat.c
@@ -0,0 +1,121 @@
+/*-
+ * Copyright (c) 2013 Peter Wemm
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * These are ABI implementations for when the raw iconv_* symbol
+ * space was exposed via libc.so.7 in its early life. This is
+ * a transition aide, these wrappers will not normally ever be
+ * executed except via __sym_compat() references.
+ */
+#include <sys/types.h>
+#include <iconv.h>
+#include "iconv-internal.h"
+
+size_t
+__iconv_compat(iconv_t a, char ** b, size_t * c, char ** d,
+ size_t * e, __uint32_t f, size_t *g)
+{
+ return __bsd___iconv(a, b, c, d, e, f, g);
+}
+
+void
+__iconv_free_list_compat(char ** a, size_t b)
+{
+ __bsd___iconv_free_list(a, b);
+}
+
+int
+__iconv_get_list_compat(char ***a, size_t *b, __iconv_bool c)
+{
+ return __bsd___iconv_get_list(a, b, c);
+}
+
+size_t
+iconv_compat(iconv_t a, char ** __restrict b,
+ size_t * __restrict c, char ** __restrict d,
+ size_t * __restrict e)
+{
+ return __bsd_iconv(a, b, c, d, e);
+}
+
+const char *
+iconv_canonicalize_compat(const char *a)
+{
+ return __bsd_iconv_canonicalize(a);
+}
+
+int
+iconv_close_compat(iconv_t a)
+{
+ return __bsd_iconv_close(a);
+}
+
+iconv_t
+iconv_open_compat(const char *a, const char *b)
+{
+ return __bsd_iconv_open(a, b);
+}
+
+int
+iconv_open_into_compat(const char *a, const char *b, iconv_allocation_t *c)
+{
+ return __bsd_iconv_open_into(a, b, c);
+}
+
+void
+iconv_set_relocation_prefix_compat(const char *a, const char *b)
+{
+ return __bsd_iconv_set_relocation_prefix(a, b);
+}
+
+int
+iconvctl_compat(iconv_t a, int b, void *c)
+{
+ return __bsd_iconvctl(a, b, c);
+}
+
+void
+iconvlist_compat(int (*a) (unsigned int, const char * const *, void *), void *b)
+{
+ return __bsd_iconvlist(a, b);
+}
+
+int _iconv_version_compat = 0x0108; /* Magic - not used */
+
+__sym_compat(__iconv, __iconv_compat, FBSD_1.2);
+__sym_compat(__iconv_free_list, __iconv_free_list_compat, FBSD_1.2);
+__sym_compat(__iconv_get_list, __iconv_get_list_compat, FBSD_1.2);
+__sym_compat(_iconv_version, _iconv_version_compat, FBSD_1.3);
+__sym_compat(iconv, iconv_compat, FBSD_1.3);
+__sym_compat(iconv_canonicalize, iconv_canonicalize_compat, FBSD_1.2);
+__sym_compat(iconv_close, iconv_close_compat, FBSD_1.3);
+__sym_compat(iconv_open, iconv_open_compat, FBSD_1.3);
+__sym_compat(iconv_open_into, iconv_open_into_compat, FBSD_1.3);
+__sym_compat(iconv_set_relocation_prefix, iconv_set_relocation_prefix_compat, FBSD_1.3);
+__sym_compat(iconvctl, iconvctl_compat, FBSD_1.3);
+__sym_compat(iconvlist, iconvlist_compat, FBSD_1.3);
diff --git a/lib/libc/iconv/iconv_open.c b/lib/libc/iconv/iconv_open.c
new file mode 100644
index 000000000000..f14925c446eb
--- /dev/null
+++ b/lib/libc/iconv/iconv_open.c
@@ -0,0 +1,37 @@
+/*-
+ * Copyright (c) 2013 Peter Wemm
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <iconv.h>
+#include "iconv-internal.h"
+
+iconv_t
+iconv_open(const char *a, const char *b)
+{
+ return __bsd_iconv_open(a, b);
+}
diff --git a/lib/libc/iconv/iconv_open_into.c b/lib/libc/iconv/iconv_open_into.c
new file mode 100644
index 000000000000..8a1278bad066
--- /dev/null
+++ b/lib/libc/iconv/iconv_open_into.c
@@ -0,0 +1,37 @@
+/*-
+ * Copyright (c) 2013 Peter Wemm
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <iconv.h>
+#include "iconv-internal.h"
+
+int
+iconv_open_into(const char *a, const char *b, iconv_allocation_t *c)
+{
+ return __bsd_iconv_open_into(a, b, c);
+}
diff --git a/lib/libc/iconv/iconv_set_relocation_prefix.c b/lib/libc/iconv/iconv_set_relocation_prefix.c
new file mode 100644
index 000000000000..7615c942ebaa
--- /dev/null
+++ b/lib/libc/iconv/iconv_set_relocation_prefix.c
@@ -0,0 +1,37 @@
+/*-
+ * Copyright (c) 2013 Peter Wemm
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <iconv.h>
+#include "iconv-internal.h"
+
+void
+iconv_set_relocation_prefix(const char *a, const char *b)
+{
+ return __bsd_iconv_set_relocation_prefix(a, b);
+}
diff --git a/lib/libc/iconv/iconvctl.3 b/lib/libc/iconv/iconvctl.3
new file mode 100644
index 000000000000..d6bc67f9b98d
--- /dev/null
+++ b/lib/libc/iconv/iconvctl.3
@@ -0,0 +1,189 @@
+.\" Copyright (c) 2009 Gabor Kovesdan <gabor@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" Portions of this text are reprinted and reproduced in electronic form
+.\" from IEEE Std 1003.1, 2004 Edition, Standard for Information Technology --
+.\" Portable Operating System Interface (POSIX), The Open Group Base
+.\" Specifications Issue 6, Copyright (C) 2001-2004 by the Institute of
+.\" Electrical and Electronics Engineers, Inc and The Open Group. In the
+.\" event of any discrepancy between this version and the original IEEE and
+.\" The Open Group Standard, the original IEEE and The Open Group Standard is
+.\" the referee document. The original Standard can be obtained online at
+.\" http://www.opengroup.org/unix/online.html.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd November 25, 2009
+.Dt ICONVCTL 3
+.Os
+.Sh NAME
+.Nm iconvctl
+.Nd controlling and diagnostical facility for
+.Xr iconv 3
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In iconv.h
+.Ft int
+.Fn iconvctl "iconv_t cd" "int request" "void *argument"
+.Sh DESCRIPTION
+The
+.Fn iconvctl
+function can retrieve or set specific conversion
+setting from the
+.Fa cd
+conversion descriptor.
+The
+.Fa request
+parameter specifies the operation to accomplish and
+.Fa argument
+is an operation-specific argument.
+.Pp
+The possible operations are the following:
+.Bl -tag -width indent
+.It ICONV_TRIVIALP
+In this case
+.Fa argument
+is an
+.Ft int *
+variable, which is set to 1 if the encoding is trivial one, i.e.
+the input and output encodings are the same.
+Otherwise, the variable will be 0.
+.It ICONV_GET_TRANSLITERATE
+Determines if transliteration is enabled.
+The answer is stored in
+.Fa argument ,
+which is of
+.Ft int * .
+It will be set to 1 if this feature is enabled or set to 0 otherwise.
+.It ICONV_SET_TRANSLITERATE
+Enables transliteration if
+.Fa argument ,
+which is of
+.Ft int *
+set to 1 or disables it if
+.Fa argument
+is set to 0.
+.It ICONV_GET_DISCARD_ILSEQ
+Determines if illegal sequences are discarded or not.
+The answer is stored in
+.Fa argument ,
+which is of
+.Ft int * .
+It will be set to 1 if this feature is enabled or set to 0 otherwise.
+.It ICONV_SET_DISCARD_ILSEQ
+Sets whether illegal sequences are discarded or not.
+.Fa argument ,
+which is of
+.Ft int *
+set to 1 or disables it if
+.Fa argument
+is set to 0.
+.It ICONV_SET_HOOKS
+Sets callback functions, which will be called back after successful
+conversions.
+The callback functions are stored in a
+.Ft struct iconv_hooks
+variable, which is passed to
+.Nm
+via
+.Fa argument
+by its address.
+.It ICONV_GET_ILSEQ_INVALID
+Determines if a character in the input buffer that is valid,
+but for which an identical character does not exist in the target
+codeset returns
+.Er EILSEQ
+or not.
+The answer is stored in
+.Fa argument ,
+which is of
+.Ft int * .
+It will be set to 1 if this feature is enabled or set to 0 otherwise.
+.It ICONV_SET_ILSEQ_INVALID
+Sets whether a character in the input buffer that is valid,
+but for which an identical character does not exist in the target
+codeset returns
+.Er EILSEQ
+or not.
+If
+.Fa argument ,
+which is of
+.Ft int *
+is set to 1 it will be enabled,
+and if
+.Fa argument
+is set to 0 it will be disabled.
+.El
+.\" XXX: fallbacks are unimplemented and trying to set them will always
+.\" return EOPNOTSUPP but definitions are provided for source-level
+.\" compatibility.
+.\".It ICONV_SET_FALLBACKS
+.\"Sets callback functions, which will be called back after failed
+.\"conversions.
+.\"The callback functions are stored in a
+.\".Ft struct iconv_fallbacks
+.\"variable, which is passed to
+.\".Nm
+.\"via
+.\".Fa argument
+.\"by its address.
+.Sh RETURN VALUES
+Upon successful completion
+.Fn iconvctl ,
+returns 0.
+Otherwise, \-1 is returned and errno is set to
+specify the kind of error.
+.Sh ERRORS
+The
+.Fn iconvctl
+function may cause an error in the following cases:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Unknown or unimplemented operation.
+.It Bq Er EBADF
+The conversion descriptor specified by
+.Fa cd
+is invalid.
+.El
+.Sh SEE ALSO
+.Xr iconv 1 ,
+.Xr iconv 3
+.Sh STANDARDS
+The
+.Nm
+facility is a non-standard extension, which appeared in
+the GNU implementation and was adopted in
+.Fx 9.0
+for compatibility's sake.
+.Sh AUTHORS
+This manual page was written by
+.An Gabor Kovesdan Aq Mt gabor@FreeBSD.org .
+.Sh BUGS
+Transliteration is enabled in this implementation by default, so it
+is impossible by design to turn it off.
+Accordingly, trying to turn it off will always fail and \-1 will be
+returned.
+Getting the transliteration state will always succeed and indicate
+that it is turned on, though.
diff --git a/lib/libc/iconv/iconvctl.c b/lib/libc/iconv/iconvctl.c
new file mode 100644
index 000000000000..50c108cfd219
--- /dev/null
+++ b/lib/libc/iconv/iconvctl.c
@@ -0,0 +1,37 @@
+/*-
+ * Copyright (c) 2013 Peter Wemm
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <iconv.h>
+#include "iconv-internal.h"
+
+int
+iconvctl(iconv_t a, int b, void *c)
+{
+ return __bsd_iconvctl(a, b, c);
+}
diff --git a/lib/libc/iconv/iconvlist.3 b/lib/libc/iconv/iconvlist.3
new file mode 100644
index 000000000000..b1a6e0564341
--- /dev/null
+++ b/lib/libc/iconv/iconvlist.3
@@ -0,0 +1,93 @@
+.\" Copyright (c) 2009 Gabor Kovesdan <gabor@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" Portions of this text are reprinted and reproduced in electronic form
+.\" from IEEE Std 1003.1, 2004 Edition, Standard for Information Technology --
+.\" Portable Operating System Interface (POSIX), The Open Group Base
+.\" Specifications Issue 6, Copyright (C) 2001-2004 by the Institute of
+.\" Electrical and Electronics Engineers, Inc and The Open Group. In the
+.\" event of any discrepancy between this version and the original IEEE and
+.\" The Open Group Standard, the original IEEE and The Open Group Standard is
+.\" the referee document. The original Standard can be obtained online at
+.\" http://www.opengroup.org/unix/online.html.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd October 20, 2009
+.Dt ICONVLIST 3
+.Os
+.Sh NAME
+.Nm iconvlist
+.Nd retrieving a list of character encodings supported by
+.Xr iconv 3
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In iconv.h
+.Ft void
+.Fo iconvlist
+.Fa "int \*[lp]*do_one\*[rp]\*[lp]unsigned int *count, const char * const *names, void *arg\*[rp]"
+.Fa "void *arg"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn iconvlist
+function obtains a list of character encodings that are supported by the
+.Xr iconv 3
+call.
+The
+.Fn do_one
+callback function will be called, where the
+.Fa count
+argument will be set to the number of the encoding names found, the
+.Fa names
+argument will be the list of the supported encoding names and the
+.Fa arg
+argument will be the \"outer\"
+.Fa arg
+argument of the
+.Fn iconvlist
+function.
+This argument can be used to interchange custom data between the caller of
+.Fn iconvlist
+and the callback function.
+.Pp
+If an error occurs,
+.Fa names
+will be NULL when calling
+.Fn do_one .
+.Sh SEE ALSO
+.Xr __iconv_free_list 3 ,
+.Xr __iconv_get_list 3 ,
+.Xr iconv 3
+.Sh STANDARDS
+The
+.Nm
+function is a non-standard extension, which appeared in
+the GNU implementation and was adopted in
+.Fx 9.0
+for compatibility's sake.
+.Sh AUTHORS
+This manual page was written by
+.An Gabor Kovesdan Aq Mt gabor@FreeBSD.org .
diff --git a/lib/libc/iconv/iconvlist.c b/lib/libc/iconv/iconvlist.c
new file mode 100644
index 000000000000..418b4a75970c
--- /dev/null
+++ b/lib/libc/iconv/iconvlist.c
@@ -0,0 +1,37 @@
+/*-
+ * Copyright (c) 2013 Peter Wemm
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <iconv.h>
+#include "iconv-internal.h"
+
+void
+iconvlist(int (*a) (unsigned int, const char * const *, void *), void *b)
+{
+ return __bsd_iconvlist(a, b);
+}
diff --git a/lib/libc/include/block_abi.h b/lib/libc/include/block_abi.h
new file mode 100644
index 000000000000..b0d6e5723937
--- /dev/null
+++ b/lib/libc/include/block_abi.h
@@ -0,0 +1,63 @@
+/*-
+ * Copyright (c) 2014 David T Chisnall
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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$
+ */
+
+#ifdef __BLOCKS__
+/**
+ * Declares a block variable. This macro is defined in the trivial way for
+ * compilers that support blocks and exposing the ABI in the source for other
+ * compilers.
+ */
+#define DECLARE_BLOCK(retTy, name, argTys, ...)\
+ retTy(^name)(argTys, ## __VA_ARGS__)
+/**
+ * Calls a block variable. This macro is defined in the trivial way for
+ * compilers that support blocks and exposing the ABI in the source for other
+ * compilers.
+ */
+#define CALL_BLOCK(name, ...) name(__VA_ARGS__)
+#else // !__BLOCKS__
+#define DECLARE_BLOCK(retTy, name, argTys, ...)\
+ struct {\
+ void *isa;\
+ int flags;\
+ int reserved;\
+ retTy (*invoke)(void *, ...);\
+ } *name
+#define CALL_BLOCK(name, ...) (name)->invoke(name, __VA_ARGS__)
+#endif // __BLOCKS__
+/**
+ * Returns the pointer to the block-invoke function. This is used for passing
+ * blocks to functions that want a function pointer and a data pointer.
+ */
+#define GET_BLOCK_FUNCTION(x) \
+ (((struct {\
+ void *isa;\
+ int flags;\
+ int reserved;\
+ void (*invoke)(void *, ...);\
+ }*)(void*)x)->invoke)
diff --git a/lib/libc/include/compat.h b/lib/libc/include/compat.h
new file mode 100644
index 000000000000..d0abfdf70fdb
--- /dev/null
+++ b/lib/libc/include/compat.h
@@ -0,0 +1,57 @@
+/*-
+ * Copyright (c) 2009 Hudson River Trading LLC
+ * Written by: John H. Baldwin <jhb@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * This file defines compatibility symbol versions for old system calls. It
+ * is included in all generated system call files.
+ */
+
+#ifndef __LIBC_COMPAT_H__
+#define __LIBC_COMPAT_H__
+
+#define __sym_compat(sym,impl,verid) \
+ .symver impl, sym@verid
+
+#ifndef NO_COMPAT7
+__sym_compat(__semctl, freebsd7___semctl, FBSD_1.0);
+__sym_compat(msgctl, freebsd7_msgctl, FBSD_1.0);
+__sym_compat(shmctl, freebsd7_shmctl, FBSD_1.0);
+#endif
+
+#undef __sym_compat
+
+#define __weak_reference(sym,alias) \
+ .weak alias;.equ alias,sym
+
+__weak_reference(__sys_fcntl,__fcntl_compat)
+
+#undef __weak_reference
+
+#endif /* __LIBC_COMPAT_H__ */
+
diff --git a/lib/libc/include/errlst.h b/lib/libc/include/errlst.h
new file mode 100644
index 000000000000..4e9e29fc3345
--- /dev/null
+++ b/lib/libc/include/errlst.h
@@ -0,0 +1,43 @@
+/*-
+ * Copyright (c) 2013 Jilles Tjoelker
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef __ERRLST_H__
+#define __ERRLST_H__
+
+#include <sys/cdefs.h>
+
+#ifdef PIC
+/* If the main executable imports these, do not use its copy from libc.so. */
+extern const char *const __hidden_sys_errlist[] __hidden;
+extern const int __hidden_sys_nerr __hidden;
+#else
+#define __hidden_sys_errlist sys_errlist
+#define __hidden_sys_nerr sys_nerr
+#endif
+
+#endif /* __ERRLST_H__ */
diff --git a/lib/libc/include/fpmath.h b/lib/libc/include/fpmath.h
new file mode 100644
index 000000000000..697d5828bfc5
--- /dev/null
+++ b/lib/libc/include/fpmath.h
@@ -0,0 +1,75 @@
+/*-
+ * Copyright (c) 2003 Mike Barcroft <mike@FreeBSD.org>
+ * Copyright (c) 2002 David Schultz <das@FreeBSD.ORG>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/endian.h>
+#include "_fpmath.h"
+
+#ifndef _IEEE_WORD_ORDER
+#define _IEEE_WORD_ORDER _BYTE_ORDER
+#endif
+
+union IEEEf2bits {
+ float f;
+ struct {
+#if _BYTE_ORDER == _LITTLE_ENDIAN
+ unsigned int man :23;
+ unsigned int exp :8;
+ unsigned int sign :1;
+#else /* _BIG_ENDIAN */
+ unsigned int sign :1;
+ unsigned int exp :8;
+ unsigned int man :23;
+#endif
+ } bits;
+};
+
+#define DBL_MANH_SIZE 20
+#define DBL_MANL_SIZE 32
+
+union IEEEd2bits {
+ double d;
+ struct {
+#if _BYTE_ORDER == _LITTLE_ENDIAN
+#if _IEEE_WORD_ORDER == _LITTLE_ENDIAN
+ unsigned int manl :32;
+#endif
+ unsigned int manh :20;
+ unsigned int exp :11;
+ unsigned int sign :1;
+#if _IEEE_WORD_ORDER == _BIG_ENDIAN
+ unsigned int manl :32;
+#endif
+#else /* _BIG_ENDIAN */
+ unsigned int sign :1;
+ unsigned int exp :11;
+ unsigned int manh :20;
+ unsigned int manl :32;
+#endif
+ } bits;
+};
diff --git a/lib/libc/include/isc/eventlib.h b/lib/libc/include/isc/eventlib.h
new file mode 100644
index 000000000000..a4cfdf909226
--- /dev/null
+++ b/lib/libc/include/isc/eventlib.h
@@ -0,0 +1,206 @@
+/*
+ * 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/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.
+ */
+
+/* eventlib.h - exported interfaces for eventlib
+ * vix 09sep95 [initial]
+ *
+ * $Id: eventlib.h,v 1.7 2008/11/14 02:36:51 marka Exp $
+ */
+
+#ifndef _EVENTLIB_H
+#define _EVENTLIB_H
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/time.h>
+#include <stdio.h>
+
+#include <isc/platform.h>
+
+#ifndef __P
+# define __EVENTLIB_P_DEFINED
+# ifdef __STDC__
+# define __P(x) x
+# else
+# define __P(x) ()
+# endif
+#endif
+
+/* In the absence of branded types... */
+typedef struct { void *opaque; } evConnID;
+typedef struct { void *opaque; } evFileID;
+typedef struct { void *opaque; } evStreamID;
+typedef struct { void *opaque; } evTimerID;
+typedef struct { void *opaque; } evWaitID;
+typedef struct { void *opaque; } evContext;
+typedef struct { void *opaque; } evEvent;
+
+#define evInitID(id) ((id)->opaque = NULL)
+#define evTestID(id) ((id).opaque != NULL)
+
+typedef void (*evConnFunc)__P((evContext, void *, int, const void *, int,
+ const void *, int));
+typedef void (*evFileFunc)__P((evContext, void *, int, int));
+typedef void (*evStreamFunc)__P((evContext, void *, int, int));
+typedef void (*evTimerFunc)__P((evContext, void *,
+ struct timespec, struct timespec));
+typedef void (*evWaitFunc)__P((evContext, void *, const void *));
+
+typedef struct { unsigned char mask[256/8]; } evByteMask;
+#define EV_BYTEMASK_BYTE(b) ((b) / 8)
+#define EV_BYTEMASK_MASK(b) (1 << ((b) % 8))
+#define EV_BYTEMASK_SET(bm, b) \
+ ((bm).mask[EV_BYTEMASK_BYTE(b)] |= EV_BYTEMASK_MASK(b))
+#define EV_BYTEMASK_CLR(bm, b) \
+ ((bm).mask[EV_BYTEMASK_BYTE(b)] &= ~EV_BYTEMASK_MASK(b))
+#define EV_BYTEMASK_TST(bm, b) \
+ ((bm).mask[EV_BYTEMASK_BYTE(b)] & EV_BYTEMASK_MASK(b))
+
+#define EV_POLL 1
+#define EV_WAIT 2
+#define EV_NULL 4
+
+#define EV_READ 1
+#define EV_WRITE 2
+#define EV_EXCEPT 4
+
+#define EV_WASNONBLOCKING 8 /* Internal library use. */
+
+/* eventlib.c */
+#define evCreate __evCreate
+#define evSetDebug __evSetDebug
+#define evDestroy __evDestroy
+#define evGetNext __evGetNext
+#define evDispatch __evDispatch
+#define evDrop __evDrop
+#define evMainLoop __evMainLoop
+#define evHighestFD __evHighestFD
+#define evGetOption __evGetOption
+#define evSetOption __evSetOption
+
+int evCreate __P((evContext *));
+void evSetDebug __P((evContext, int, FILE *));
+int evDestroy __P((evContext));
+int evGetNext __P((evContext, evEvent *, int));
+int evDispatch __P((evContext, evEvent));
+void evDrop __P((evContext, evEvent));
+int evMainLoop __P((evContext));
+int evHighestFD __P((evContext));
+int evGetOption __P((evContext *, const char *, int *));
+int evSetOption __P((evContext *, const char *, int));
+
+/* ev_connects.c */
+#define evListen __evListen
+#define evConnect __evConnect
+#define evCancelConn __evCancelConn
+#define evHold __evHold
+#define evUnhold __evUnhold
+#define evTryAccept __evTryAccept
+
+int evListen __P((evContext, int, int, evConnFunc, void *, evConnID *));
+int evConnect __P((evContext, int, const void *, int,
+ evConnFunc, void *, evConnID *));
+int evCancelConn __P((evContext, evConnID));
+int evHold __P((evContext, evConnID));
+int evUnhold __P((evContext, evConnID));
+int evTryAccept __P((evContext, evConnID, int *));
+
+/* ev_files.c */
+#define evSelectFD __evSelectFD
+#define evDeselectFD __evDeselectFD
+
+int evSelectFD __P((evContext, int, int, evFileFunc, void *, evFileID *));
+int evDeselectFD __P((evContext, evFileID));
+
+/* ev_streams.c */
+#define evConsIovec __evConsIovec
+#define evWrite __evWrite
+#define evRead __evRead
+#define evTimeRW __evTimeRW
+#define evUntimeRW __evUntimeRW
+#define evCancelRW __evCancelRW
+
+struct iovec evConsIovec __P((void *, size_t));
+int evWrite __P((evContext, int, const struct iovec *, int,
+ evStreamFunc func, void *, evStreamID *));
+int evRead __P((evContext, int, const struct iovec *, int,
+ evStreamFunc func, void *, evStreamID *));
+int evTimeRW __P((evContext, evStreamID, evTimerID timer));
+int evUntimeRW __P((evContext, evStreamID));
+int evCancelRW __P((evContext, evStreamID));
+
+/* ev_timers.c */
+#define evConsTime __evConsTime
+#define evAddTime __evAddTime
+#define evSubTime __evSubTime
+#define evCmpTime __evCmpTime
+#define evTimeSpec __evTimeSpec
+#define evTimeVal __evTimeVal
+
+#define evNowTime __evNowTime
+#define evUTCTime __evUTCTime
+#define evLastEventTime __evLastEventTime
+#define evSetTimer __evSetTimer
+#define evClearTimer __evClearTimer
+#define evConfigTimer __evConfigTimer
+#define evResetTimer __evResetTimer
+#define evSetIdleTimer __evSetIdleTimer
+#define evClearIdleTimer __evClearIdleTimer
+#define evResetIdleTimer __evResetIdleTimer
+#define evTouchIdleTimer __evTouchIdleTimer
+
+struct timespec evConsTime __P((time_t sec, long nsec));
+struct timespec evAddTime __P((struct timespec, struct timespec));
+struct timespec evSubTime __P((struct timespec, struct timespec));
+struct timespec evNowTime __P((void));
+struct timespec evUTCTime __P((void));
+struct timespec evLastEventTime __P((evContext));
+struct timespec evTimeSpec __P((struct timeval));
+struct timeval evTimeVal __P((struct timespec));
+int evCmpTime __P((struct timespec, struct timespec));
+int evSetTimer __P((evContext, evTimerFunc, void *, struct timespec,
+ struct timespec, evTimerID *));
+int evClearTimer __P((evContext, evTimerID));
+int evConfigTimer __P((evContext, evTimerID, const char *param,
+ int value));
+int evResetTimer __P((evContext, evTimerID, evTimerFunc, void *,
+ struct timespec, struct timespec));
+int evSetIdleTimer __P((evContext, evTimerFunc, void *, struct timespec,
+ evTimerID *));
+int evClearIdleTimer __P((evContext, evTimerID));
+int evResetIdleTimer __P((evContext, evTimerID, evTimerFunc, void *,
+ struct timespec));
+int evTouchIdleTimer __P((evContext, evTimerID));
+
+/* ev_waits.c */
+#define evWaitFor __evWaitFor
+#define evDo __evDo
+#define evUnwait __evUnwait
+#define evDefer __evDefer
+
+int evWaitFor __P((evContext, const void *, evWaitFunc, void *, evWaitID *));
+int evDo __P((evContext, const void *));
+int evUnwait __P((evContext, evWaitID));
+int evDefer __P((evContext, evWaitFunc, void *));
+
+#ifdef __EVENTLIB_P_DEFINED
+# undef __P
+#endif
+
+#endif /*_EVENTLIB_H*/
+
+/*! \file */
diff --git a/lib/libc/include/isc/list.h b/lib/libc/include/isc/list.h
new file mode 100644
index 000000000000..ffd0c511d763
--- /dev/null
+++ b/lib/libc/include/isc/list.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1997,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.
+ */
+
+/* $FreeBSD$ */
+
+#ifndef LIST_H
+#define LIST_H 1
+#ifdef _LIBC
+#include <assert.h>
+#define INSIST(cond) assert(cond)
+#else
+#include <isc/assertions.h>
+#endif
+
+#define LIST(type) struct { type *head, *tail; }
+#define INIT_LIST(list) \
+ do { (list).head = NULL; (list).tail = NULL; } while (0)
+
+#define LINK(type) struct { type *prev, *next; }
+#define INIT_LINK_TYPE(elt, link, type) \
+ do { \
+ (elt)->link.prev = (type *)(-1); \
+ (elt)->link.next = (type *)(-1); \
+ } while (0)
+#define INIT_LINK(elt, link) \
+ INIT_LINK_TYPE(elt, link, void)
+#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)
+#define EMPTY(list) ((list).head == NULL)
+
+#define PREPEND(list, elt, link) \
+ do { \
+ INSIST(!LINKED(elt, link));\
+ if ((list).head != NULL) \
+ (list).head->link.prev = (elt); \
+ else \
+ (list).tail = (elt); \
+ (elt)->link.prev = NULL; \
+ (elt)->link.next = (list).head; \
+ (list).head = (elt); \
+ } while (0)
+
+#define APPEND(list, elt, link) \
+ do { \
+ INSIST(!LINKED(elt, link));\
+ if ((list).tail != NULL) \
+ (list).tail->link.next = (elt); \
+ else \
+ (list).head = (elt); \
+ (elt)->link.prev = (list).tail; \
+ (elt)->link.next = NULL; \
+ (list).tail = (elt); \
+ } while (0)
+
+#define UNLINK_TYPE(list, elt, link, type) \
+ do { \
+ INSIST(LINKED(elt, link));\
+ if ((elt)->link.next != NULL) \
+ (elt)->link.next->link.prev = (elt)->link.prev; \
+ else { \
+ INSIST((list).tail == (elt)); \
+ (list).tail = (elt)->link.prev; \
+ } \
+ if ((elt)->link.prev != NULL) \
+ (elt)->link.prev->link.next = (elt)->link.next; \
+ else { \
+ INSIST((list).head == (elt)); \
+ (list).head = (elt)->link.next; \
+ } \
+ INIT_LINK_TYPE(elt, link, type); \
+ } while (0)
+#define UNLINK(list, elt, link) \
+ UNLINK_TYPE(list, elt, link, void)
+
+#define PREV(elt, link) ((elt)->link.prev)
+#define NEXT(elt, link) ((elt)->link.next)
+
+#define INSERT_BEFORE(list, before, elt, link) \
+ do { \
+ INSIST(!LINKED(elt, link));\
+ if ((before)->link.prev == NULL) \
+ PREPEND(list, elt, link); \
+ else { \
+ (elt)->link.prev = (before)->link.prev; \
+ (before)->link.prev = (elt); \
+ (elt)->link.prev->link.next = (elt); \
+ (elt)->link.next = (before); \
+ } \
+ } while (0)
+
+#define INSERT_AFTER(list, after, elt, link) \
+ do { \
+ INSIST(!LINKED(elt, link));\
+ if ((after)->link.next == NULL) \
+ APPEND(list, elt, link); \
+ else { \
+ (elt)->link.next = (after)->link.next; \
+ (after)->link.next = (elt); \
+ (elt)->link.next->link.prev = (elt); \
+ (elt)->link.prev = (after); \
+ } \
+ } while (0)
+
+#define ENQUEUE(list, elt, link) APPEND(list, elt, link)
+#define DEQUEUE(list, elt, link) UNLINK(list, elt, link)
+
+#endif /* LIST_H */
+/*! \file */
diff --git a/lib/libc/include/isc/platform.h b/lib/libc/include/isc/platform.h
new file mode 100644
index 000000000000..a0513be8dde0
--- /dev/null
+++ b/lib/libc/include/isc/platform.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2008 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * 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.
+ */
+
+/* $Id: platform.h.in,v 1.2.6.2 2008/01/23 02:15:02 tbox Exp $ */
+/* $FreeBSD$ */
+
+/*! \file */
+
+#ifndef ISC_PLATFORM_H
+#define ISC_PLATFORM_H
+
+/*
+ * Define if the OS does not define struct timespec.
+ */
+#undef ISC_PLATFORM_NEEDTIMESPEC
+#ifdef ISC_PLATFORM_NEEDTIMESPEC
+#include <time.h> /* For time_t */
+struct timespec {
+ time_t tv_sec; /* seconds */
+ long tv_nsec; /* nanoseconds */
+};
+#endif
+
+#endif
diff --git a/lib/libc/include/libc_private.h b/lib/libc/include/libc_private.h
new file mode 100644
index 000000000000..74a7e3a841b0
--- /dev/null
+++ b/lib/libc/include/libc_private.h
@@ -0,0 +1,404 @@
+/*
+ * Copyright (c) 1998 John Birrell <jb@cimlogic.com.au>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ *
+ * Private definitions for libc, libc_r and libpthread.
+ *
+ */
+
+#ifndef _LIBC_PRIVATE_H_
+#define _LIBC_PRIVATE_H_
+#include <sys/_types.h>
+#include <sys/_pthreadtypes.h>
+
+/*
+ * This global flag is non-zero when a process has created one
+ * or more threads. It is used to avoid calling locking functions
+ * when they are not required.
+ */
+extern int __isthreaded;
+
+/*
+ * Elf_Auxinfo *__elf_aux_vector, the pointer to the ELF aux vector
+ * provided by kernel. Either set for us by rtld, or found at runtime
+ * on stack for static binaries.
+ *
+ * Type is void to avoid polluting whole libc with ELF types.
+ */
+extern void *__elf_aux_vector;
+
+/*
+ * libc should use libc_dlopen internally, which respects a global
+ * flag where loading of new shared objects can be restricted.
+ */
+void *libc_dlopen(const char *, int);
+
+/*
+ * For dynamic linker.
+ */
+void _rtld_error(const char *fmt, ...);
+
+/*
+ * File lock contention is difficult to diagnose without knowing
+ * where locks were set. Allow a debug library to be built which
+ * records the source file and line number of each lock call.
+ */
+#ifdef _FLOCK_DEBUG
+#define _FLOCKFILE(x) _flockfile_debug(x, __FILE__, __LINE__)
+#else
+#define _FLOCKFILE(x) _flockfile(x)
+#endif
+
+/*
+ * Macros for locking and unlocking FILEs. These test if the
+ * process is threaded to avoid locking when not required.
+ */
+#define FLOCKFILE(fp) if (__isthreaded) _FLOCKFILE(fp)
+#define FUNLOCKFILE(fp) if (__isthreaded) _funlockfile(fp)
+
+struct _spinlock;
+extern struct _spinlock __stdio_thread_lock __hidden;
+#define STDIO_THREAD_LOCK() \
+do { \
+ if (__isthreaded) \
+ _SPINLOCK(&__stdio_thread_lock); \
+} while (0)
+#define STDIO_THREAD_UNLOCK() \
+do { \
+ if (__isthreaded) \
+ _SPINUNLOCK(&__stdio_thread_lock); \
+} while (0)
+
+void __libc_spinlock_stub(struct _spinlock *);
+void __libc_spinunlock_stub(struct _spinlock *);
+
+/*
+ * Indexes into the pthread jump table.
+ *
+ * Warning! If you change this type, you must also change the threads
+ * libraries that reference it (libc_r, libpthread).
+ */
+typedef enum {
+ PJT_ATFORK,
+ PJT_ATTR_DESTROY,
+ PJT_ATTR_GETDETACHSTATE,
+ PJT_ATTR_GETGUARDSIZE,
+ PJT_ATTR_GETINHERITSCHED,
+ PJT_ATTR_GETSCHEDPARAM,
+ PJT_ATTR_GETSCHEDPOLICY,
+ PJT_ATTR_GETSCOPE,
+ PJT_ATTR_GETSTACKADDR,
+ PJT_ATTR_GETSTACKSIZE,
+ PJT_ATTR_INIT,
+ PJT_ATTR_SETDETACHSTATE,
+ PJT_ATTR_SETGUARDSIZE,
+ PJT_ATTR_SETINHERITSCHED,
+ PJT_ATTR_SETSCHEDPARAM,
+ PJT_ATTR_SETSCHEDPOLICY,
+ PJT_ATTR_SETSCOPE,
+ PJT_ATTR_SETSTACKADDR,
+ PJT_ATTR_SETSTACKSIZE,
+ PJT_CANCEL,
+ PJT_CLEANUP_POP,
+ PJT_CLEANUP_PUSH,
+ PJT_COND_BROADCAST,
+ PJT_COND_DESTROY,
+ PJT_COND_INIT,
+ PJT_COND_SIGNAL,
+ PJT_COND_TIMEDWAIT,
+ PJT_COND_WAIT,
+ PJT_DETACH,
+ PJT_EQUAL,
+ PJT_EXIT,
+ PJT_GETSPECIFIC,
+ PJT_JOIN,
+ PJT_KEY_CREATE,
+ PJT_KEY_DELETE,
+ PJT_KILL,
+ PJT_MAIN_NP,
+ PJT_MUTEXATTR_DESTROY,
+ PJT_MUTEXATTR_INIT,
+ PJT_MUTEXATTR_SETTYPE,
+ PJT_MUTEX_DESTROY,
+ PJT_MUTEX_INIT,
+ PJT_MUTEX_LOCK,
+ PJT_MUTEX_TRYLOCK,
+ PJT_MUTEX_UNLOCK,
+ PJT_ONCE,
+ PJT_RWLOCK_DESTROY,
+ PJT_RWLOCK_INIT,
+ PJT_RWLOCK_RDLOCK,
+ PJT_RWLOCK_TRYRDLOCK,
+ PJT_RWLOCK_TRYWRLOCK,
+ PJT_RWLOCK_UNLOCK,
+ PJT_RWLOCK_WRLOCK,
+ PJT_SELF,
+ PJT_SETCANCELSTATE,
+ PJT_SETCANCELTYPE,
+ PJT_SETSPECIFIC,
+ PJT_SIGMASK,
+ PJT_TESTCANCEL,
+ PJT_CLEANUP_POP_IMP,
+ PJT_CLEANUP_PUSH_IMP,
+ PJT_CANCEL_ENTER,
+ PJT_CANCEL_LEAVE,
+ PJT_MUTEX_CONSISTENT,
+ PJT_MUTEXATTR_GETROBUST,
+ PJT_MUTEXATTR_SETROBUST,
+ PJT_MAX
+} pjt_index_t;
+
+typedef int (*pthread_func_t)(void);
+typedef pthread_func_t pthread_func_entry_t[2];
+
+extern pthread_func_entry_t __thr_jtable[];
+
+void __set_error_selector(int *(*arg)(void));
+int _pthread_mutex_init_calloc_cb_stub(pthread_mutex_t *mutex,
+ void *(calloc_cb)(__size_t, __size_t));
+
+typedef int (*interpos_func_t)(void);
+interpos_func_t *__libc_interposing_slot(int interposno);
+extern interpos_func_t __libc_interposing[] __hidden;
+
+enum {
+ INTERPOS_accept,
+ INTERPOS_accept4,
+ INTERPOS_aio_suspend,
+ INTERPOS_close,
+ INTERPOS_connect,
+ INTERPOS_fcntl,
+ INTERPOS_fsync,
+ INTERPOS_fork,
+ INTERPOS_msync,
+ INTERPOS_nanosleep,
+ INTERPOS_openat,
+ INTERPOS_poll,
+ INTERPOS_pselect,
+ INTERPOS_recvfrom,
+ INTERPOS_recvmsg,
+ INTERPOS_select,
+ INTERPOS_sendmsg,
+ INTERPOS_sendto,
+ INTERPOS_setcontext,
+ INTERPOS_sigaction,
+ INTERPOS_sigprocmask,
+ INTERPOS_sigsuspend,
+ INTERPOS_sigwait,
+ INTERPOS_sigtimedwait,
+ INTERPOS_sigwaitinfo,
+ INTERPOS_swapcontext,
+ INTERPOS_system,
+ INTERPOS_tcdrain,
+ INTERPOS_read,
+ INTERPOS_readv,
+ INTERPOS_wait4,
+ INTERPOS_write,
+ INTERPOS_writev,
+ INTERPOS__pthread_mutex_init_calloc_cb,
+ INTERPOS_spinlock,
+ INTERPOS_spinunlock,
+ INTERPOS_kevent,
+ INTERPOS_wait6,
+ INTERPOS_ppoll,
+ INTERPOS_map_stacks_exec,
+ INTERPOS_fdatasync,
+ INTERPOS_MAX
+};
+
+/*
+ * yplib internal interfaces
+ */
+#ifdef YP
+int _yp_check(char **);
+#endif
+
+/*
+ * Initialise TLS for static programs
+ */
+void _init_tls(void);
+
+/*
+ * Provides pthread_once()-like functionality for both single-threaded
+ * and multi-threaded applications.
+ */
+int _once(pthread_once_t *, void (*)(void));
+
+/*
+ * Set the TLS thread pointer
+ */
+void _set_tp(void *tp);
+
+/*
+ * This is a pointer in the C run-time startup code. It is used
+ * by getprogname() and setprogname().
+ */
+extern const char *__progname;
+
+/*
+ * This function is used by the threading libraries to notify malloc that a
+ * thread is exiting.
+ */
+void _malloc_thread_cleanup(void);
+
+/*
+ * This function is used by the threading libraries to notify libc that a
+ * thread is exiting, so its thread-local dtors should be called.
+ */
+void __cxa_thread_call_dtors(void);
+int __cxa_thread_atexit_hidden(void (*dtor_func)(void *), void *obj,
+ void *dso_symbol) __hidden;
+
+/*
+ * These functions are used by the threading libraries in order to protect
+ * malloc across fork().
+ */
+void _malloc_prefork(void);
+void _malloc_postfork(void);
+
+void _malloc_first_thread(void);
+
+/*
+ * Function to clean up streams, called from abort() and exit().
+ */
+extern void (*__cleanup)(void) __hidden;
+
+/*
+ * Get kern.osreldate to detect ABI revisions. Explicitly
+ * ignores value of $OSVERSION and caches result.
+ */
+int __getosreldate(void);
+#include <sys/_types.h>
+#include <sys/_sigset.h>
+
+struct aiocb;
+struct fd_set;
+struct iovec;
+struct kevent;
+struct msghdr;
+struct pollfd;
+struct rusage;
+struct sigaction;
+struct sockaddr;
+struct timespec;
+struct timeval;
+struct timezone;
+struct __siginfo;
+struct __ucontext;
+struct __wrusage;
+enum idtype;
+int __sys_aio_suspend(const struct aiocb * const[], int,
+ const struct timespec *);
+int __sys_accept(int, struct sockaddr *, __socklen_t *);
+int __sys_accept4(int, struct sockaddr *, __socklen_t *, int);
+int __sys_clock_gettime(__clockid_t, struct timespec *ts);
+int __sys_close(int);
+int __sys_connect(int, const struct sockaddr *, __socklen_t);
+int __sys_fcntl(int, int, ...);
+int __sys_fdatasync(int);
+int __sys_fsync(int);
+__pid_t __sys_fork(void);
+int __sys_ftruncate(int, __off_t);
+int __sys_gettimeofday(struct timeval *, struct timezone *);
+int __sys_kevent(int, const struct kevent *, int, struct kevent *,
+ int, const struct timespec *);
+__off_t __sys_lseek(int, __off_t, int);
+void *__sys_mmap(void *, __size_t, int, int, int, __off_t);
+int __sys_msync(void *, __size_t, int);
+int __sys_nanosleep(const struct timespec *, struct timespec *);
+int __sys_open(const char *, int, ...);
+int __sys_openat(int, const char *, int, ...);
+int __sys_pselect(int, struct fd_set *, struct fd_set *,
+ struct fd_set *, const struct timespec *,
+ const __sigset_t *);
+int __sys_ptrace(int, __pid_t, char *, int);
+int __sys_poll(struct pollfd *, unsigned, int);
+int __sys_ppoll(struct pollfd *, unsigned, const struct timespec *,
+ const __sigset_t *);
+__ssize_t __sys_pread(int, void *, __size_t, __off_t);
+__ssize_t __sys_pwrite(int, const void *, __size_t, __off_t);
+__ssize_t __sys_read(int, void *, __size_t);
+__ssize_t __sys_readv(int, const struct iovec *, int);
+__ssize_t __sys_recv(int, void *, __size_t, int);
+__ssize_t __sys_recvfrom(int, void *, __size_t, int, struct sockaddr *,
+ __socklen_t *);
+__ssize_t __sys_recvmsg(int, struct msghdr *, int);
+int __sys_select(int, struct fd_set *, struct fd_set *,
+ struct fd_set *, struct timeval *);
+__ssize_t __sys_sendmsg(int, const struct msghdr *, int);
+__ssize_t __sys_sendto(int, const void *, __size_t, int,
+ const struct sockaddr *, __socklen_t);
+int __sys_setcontext(const struct __ucontext *);
+int __sys_sigaction(int, const struct sigaction *,
+ struct sigaction *);
+int __sys_sigprocmask(int, const __sigset_t *, __sigset_t *);
+int __sys_sigsuspend(const __sigset_t *);
+int __sys_sigtimedwait(const __sigset_t *, struct __siginfo *,
+ const struct timespec *);
+int __sys_sigwait(const __sigset_t *, int *);
+int __sys_sigwaitinfo(const __sigset_t *, struct __siginfo *);
+int __sys_swapcontext(struct __ucontext *,
+ const struct __ucontext *);
+int __sys_thr_kill(long, int);
+int __sys_thr_self(long *);
+int __sys_truncate(const char *, __off_t);
+__pid_t __sys_wait4(__pid_t, int *, int, struct rusage *);
+__pid_t __sys_wait6(enum idtype, __id_t, int *, int,
+ struct __wrusage *, struct __siginfo *);
+__ssize_t __sys_write(int, const void *, __size_t);
+__ssize_t __sys_writev(int, const struct iovec *, int);
+
+int __libc_sigaction(int, const struct sigaction *,
+ struct sigaction *) __hidden;
+int __libc_sigprocmask(int, const __sigset_t *, __sigset_t *)
+ __hidden;
+int __libc_sigsuspend(const __sigset_t *) __hidden;
+int __libc_sigwait(const __sigset_t * __restrict,
+ int * restrict sig);
+int __libc_system(const char *);
+int __libc_tcdrain(int);
+int __fcntl_compat(int fd, int cmd, ...);
+
+int __sys_futimens(int fd, const struct timespec *times) __hidden;
+int __sys_utimensat(int fd, const char *path,
+ const struct timespec *times, int flag) __hidden;
+
+/* execve() with PATH processing to implement posix_spawnp() */
+int _execvpe(const char *, char * const *, char * const *);
+
+int _elf_aux_info(int aux, void *buf, int buflen);
+struct dl_phdr_info;
+int __elf_phdr_match_addr(struct dl_phdr_info *, void *);
+void __init_elf_aux_vector(void);
+void __libc_map_stacks_exec(void);
+
+void _pthread_cancel_enter(int);
+void _pthread_cancel_leave(int);
+
+#endif /* _LIBC_PRIVATE_H_ */
diff --git a/lib/libc/include/namespace.h b/lib/libc/include/namespace.h
new file mode 100644
index 000000000000..c95829e401f1
--- /dev/null
+++ b/lib/libc/include/namespace.h
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) 2001 Daniel Eischen <deischen@FreeBSD.org>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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 _NAMESPACE_H_
+#define _NAMESPACE_H_
+
+/*
+ * Adjust names so that headers declare "hidden" names.
+ *
+ * README: When modifying this file don't forget to make the appropriate
+ * changes in un-namespace.h!!!
+ */
+
+/*
+ * ISO C (C90) section. Most names in libc aren't in ISO C, so they
+ * should be here. Most aren't here...
+ */
+#define err _err
+#define warn _warn
+#define nsdispatch _nsdispatch
+
+/*
+ * Prototypes for syscalls/functions that need to be overridden
+ * in libc_r/libpthread.
+ */
+#define accept _accept
+#define __acl_aclcheck_fd ___acl_aclcheck_fd
+#define __acl_delete_fd ___acl_delete_fd
+#define __acl_get_fd ___acl_get_fd
+#define __acl_set_fd ___acl_set_fd
+#define bind _bind
+#define __cap_get_fd ___cap_get_fd
+#define __cap_set_fd ___cap_set_fd
+#define close _close
+#define connect _connect
+#define dup _dup
+#define dup2 _dup2
+#define execve _execve
+#define fcntl _fcntl
+/*#define flock _flock */
+#define flockfile _flockfile
+#define fpathconf _fpathconf
+#define fstat _fstat
+#define fstatfs _fstatfs
+#define fsync _fsync
+#define funlockfile _funlockfile
+#define getdirentries _getdirentries
+#define getlogin _getlogin
+#define getpeername _getpeername
+#define getprogname _getprogname
+#define getsockname _getsockname
+#define getsockopt _getsockopt
+#define ioctl _ioctl
+/* #define kevent _kevent */
+#define listen _listen
+#define nanosleep _nanosleep
+#define open _open
+#define openat _openat
+#define poll _poll
+#define pthread_atfork _pthread_atfork
+#define pthread_attr_destroy _pthread_attr_destroy
+#define pthread_attr_get_np _pthread_attr_get_np
+#define pthread_attr_getaffinity_np _pthread_attr_getaffinity_np
+#define pthread_attr_getdetachstate _pthread_attr_getdetachstate
+#define pthread_attr_getguardsize _pthread_attr_getguardsize
+#define pthread_attr_getinheritsched _pthread_attr_getinheritsched
+#define pthread_attr_getschedparam _pthread_attr_getschedparam
+#define pthread_attr_getschedpolicy _pthread_attr_getschedpolicy
+#define pthread_attr_getscope _pthread_attr_getscope
+#define pthread_attr_getstack _pthread_attr_getstack
+#define pthread_attr_getstackaddr _pthread_attr_getstackaddr
+#define pthread_attr_getstacksize _pthread_attr_getstacksize
+#define pthread_attr_init _pthread_attr_init
+#define pthread_attr_setaffinity_np _pthread_attr_setaffinity_np
+#define pthread_attr_setcreatesuspend_np _pthread_attr_setcreatesuspend_np
+#define pthread_attr_setdetachstate _pthread_attr_setdetachstate
+#define pthread_attr_setguardsize _pthread_attr_setguardsize
+#define pthread_attr_setinheritsched _pthread_attr_setinheritsched
+#define pthread_attr_setschedparam _pthread_attr_setschedparam
+#define pthread_attr_setschedpolicy _pthread_attr_setschedpolicy
+#define pthread_attr_setscope _pthread_attr_setscope
+#define pthread_attr_setstack _pthread_attr_setstack
+#define pthread_attr_setstackaddr _pthread_attr_setstackaddr
+#define pthread_attr_setstacksize _pthread_attr_setstacksize
+#define pthread_barrier_destroy _pthread_barrier_destroy
+#define pthread_barrier_init _pthread_barrier_init
+#define pthread_barrier_wait _pthread_barrier_wait
+#define pthread_barrierattr_destroy _pthread_barrierattr_destroy
+#define pthread_barrierattr_getpshared _pthread_barrierattr_getpshared
+#define pthread_barrierattr_init _pthread_barrierattr_init
+#define pthread_barrierattr_setpshared _pthread_barrierattr_setpshared
+#define pthread_cancel _pthread_cancel
+#define pthread_cond_broadcast _pthread_cond_broadcast
+#define pthread_cond_destroy _pthread_cond_destroy
+#define pthread_cond_init _pthread_cond_init
+#define pthread_cond_signal _pthread_cond_signal
+#define pthread_cond_timedwait _pthread_cond_timedwait
+#define pthread_cond_wait _pthread_cond_wait
+#define pthread_condattr_destroy _pthread_condattr_destroy
+#define pthread_condattr_getclock _pthread_condattr_getclock
+#define pthread_condattr_getpshared _pthread_condattr_getpshared
+#define pthread_condattr_init _pthread_condattr_init
+#define pthread_condattr_setclock _pthread_condattr_setclock
+#define pthread_condattr_setpshared _pthread_condattr_setpshared
+#define pthread_create _pthread_create
+#define pthread_detach _pthread_detach
+#define pthread_equal _pthread_equal
+#define pthread_exit _pthread_exit
+#define pthread_getaffinity_np _pthread_getaffinity_np
+#define pthread_getconcurrency _pthread_getconcurrency
+#define pthread_getcpuclockid _pthread_getcpuclockid
+#define pthread_getprio _pthread_getprio
+#define pthread_getschedparam _pthread_getschedparam
+#define pthread_getspecific _pthread_getspecific
+#define pthread_getthreadid_np _pthread_getthreadid_np
+#define pthread_join _pthread_join
+#define pthread_key_create _pthread_key_create
+#define pthread_key_delete _pthread_key_delete
+#define pthread_kill _pthread_kill
+#define pthread_main_np _pthread_main_np
+#define pthread_multi_np _pthread_multi_np
+#define pthread_mutex_destroy _pthread_mutex_destroy
+#define pthread_mutex_getprioceiling _pthread_mutex_getprioceiling
+#define pthread_mutex_init _pthread_mutex_init
+#define pthread_mutex_isowned_np _pthread_mutex_isowned_np
+#define pthread_mutex_lock _pthread_mutex_lock
+#define pthread_mutex_setprioceiling _pthread_mutex_setprioceiling
+#define pthread_mutex_timedlock _pthread_mutex_timedlock
+#define pthread_mutex_trylock _pthread_mutex_trylock
+#define pthread_mutex_unlock _pthread_mutex_unlock
+#define pthread_mutexattr_destroy _pthread_mutexattr_destroy
+#define pthread_mutexattr_getkind_np _pthread_mutexattr_getkind_np
+#define pthread_mutexattr_getprioceiling _pthread_mutexattr_getprioceiling
+#define pthread_mutexattr_getprotocol _pthread_mutexattr_getprotocol
+#define pthread_mutexattr_getpshared _pthread_mutexattr_getpshared
+#define pthread_mutexattr_gettype _pthread_mutexattr_gettype
+#define pthread_mutexattr_init _pthread_mutexattr_init
+#define pthread_mutexattr_setkind_np _pthread_mutexattr_setkind_np
+#define pthread_mutexattr_setprioceiling _pthread_mutexattr_setprioceiling
+#define pthread_mutexattr_setprotocol _pthread_mutexattr_setprotocol
+#define pthread_mutexattr_setpshared _pthread_mutexattr_setpshared
+#define pthread_mutexattr_settype _pthread_mutexattr_settype
+#define pthread_once _pthread_once
+#define pthread_resume_all_np _pthread_resume_all_np
+#define pthread_resume_np _pthread_resume_np
+#define pthread_rwlock_destroy _pthread_rwlock_destroy
+#define pthread_rwlock_init _pthread_rwlock_init
+#define pthread_rwlock_rdlock _pthread_rwlock_rdlock
+#define pthread_rwlock_timedrdlock _pthread_rwlock_timedrdlock
+#define pthread_rwlock_timedwrlock _pthread_rwlock_timedwrlock
+#define pthread_rwlock_tryrdlock _pthread_rwlock_tryrdlock
+#define pthread_rwlock_trywrlock _pthread_rwlock_trywrlock
+#define pthread_rwlock_unlock _pthread_rwlock_unlock
+#define pthread_rwlock_wrlock _pthread_rwlock_wrlock
+#define pthread_rwlockattr_destroy _pthread_rwlockattr_destroy
+#define pthread_rwlockattr_getpshared _pthread_rwlockattr_getpshared
+#define pthread_rwlockattr_init _pthread_rwlockattr_init
+#define pthread_rwlockattr_setpshared _pthread_rwlockattr_setpshared
+#define pthread_self _pthread_self
+#define pthread_set_name_np _pthread_set_name_np
+#define pthread_setaffinity_np _pthread_setaffinity_np
+#define pthread_setcancelstate _pthread_setcancelstate
+#define pthread_setcanceltype _pthread_setcanceltype
+#define pthread_setconcurrency _pthread_setconcurrency
+#define pthread_setprio _pthread_setprio
+#define pthread_setschedparam _pthread_setschedparam
+#define pthread_setspecific _pthread_setspecific
+#define pthread_sigmask _pthread_sigmask
+#define pthread_single_np _pthread_single_np
+#define pthread_spin_destroy _pthread_spin_destroy
+#define pthread_spin_init _pthread_spin_init
+#define pthread_spin_lock _pthread_spin_lock
+#define pthread_spin_trylock _pthread_spin_trylock
+#define pthread_spin_unlock _pthread_spin_unlock
+#define pthread_suspend_all_np _pthread_suspend_all_np
+#define pthread_suspend_np _pthread_suspend_np
+#define pthread_switch_add_np _pthread_switch_add_np
+#define pthread_switch_delete_np _pthread_switch_delete_np
+#define pthread_testcancel _pthread_testcancel
+#define pthread_timedjoin_np _pthread_timedjoin_np
+#define pthread_yield _pthread_yield
+#define read _read
+#define readv _readv
+#define recvfrom _recvfrom
+#define recvmsg _recvmsg
+#define recvmmsg _recvmmsg
+#define select _select
+#define sem_close _sem_close
+#define sem_destroy _sem_destroy
+#define sem_getvalue _sem_getvalue
+#define sem_init _sem_init
+#define sem_open _sem_open
+#define sem_post _sem_post
+#define sem_timedwait _sem_timedwait
+#define sem_trywait _sem_trywait
+#define sem_unlink _sem_unlink
+#define sem_wait _sem_wait
+#define sendmsg _sendmsg
+#define sendmmsg _sendmmsg
+#define sendto _sendto
+#define setsockopt _setsockopt
+/*#define sigaction _sigaction*/
+#define sigprocmask _sigprocmask
+#define sigsuspend _sigsuspend
+#define socket _socket
+#define socketpair _socketpair
+#define usleep _usleep
+#define wait4 _wait4
+#define wait6 _wait6
+#define waitpid _waitpid
+#define write _write
+#define writev _writev
+
+
+/*
+ * Other hidden syscalls/functions that libc_r needs to override
+ * but are not used internally by libc.
+ *
+ * XXX - When modifying libc to use one of the following, remove
+ * the prototype from below and place it in the list above.
+ */
+#if 0
+#define creat _creat
+#define fchflags _fchflags
+#define fchmod _fchmod
+#define ftrylockfile _ftrylockfile
+#define msync _msync
+#define nfssvc _nfssvc
+#define pause _pause
+#define sched_yield _sched_yield
+#define sendfile _sendfile
+#define shutdown _shutdown
+#define sigaltstack _sigaltstack
+#define sigpending _sigpending
+#define sigreturn _sigreturn
+#define sigsetmask _sigsetmask
+#define sleep _sleep
+#define system _system
+#define tcdrain _tcdrain
+#define wait _wait
+#endif
+
+#endif /* _NAMESPACE_H_ */
diff --git a/lib/libc/include/nscache.h b/lib/libc/include/nscache.h
new file mode 100644
index 000000000000..015c4ec74ffe
--- /dev/null
+++ b/lib/libc/include/nscache.h
@@ -0,0 +1,197 @@
+/*-
+ * Copyright (c) 2005 Michael Bushkov <bushman@rsu.ru>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef __NS_CACHE_H__
+#define __NS_CACHE_H__
+
+#include "nscachedcli.h"
+
+typedef int (*nss_cache_id_func_t)(char *, size_t *, va_list, void *);
+typedef int (*nss_cache_marshal_func_t)(char *, size_t *, void *, va_list,
+ void *);
+typedef int (*nss_cache_unmarshal_func_t)(char *, size_t, void *, va_list,
+ void *);
+
+typedef void (*nss_set_mp_ws_func_t)(cached_mp_write_session);
+typedef cached_mp_write_session (*nss_get_mp_ws_func_t)(void);
+
+typedef void (*nss_set_mp_rs_func_t)(cached_mp_read_session);
+typedef cached_mp_read_session (*nss_get_mp_rs_func_t)(void);
+
+typedef struct _nss_cache_info {
+ char *entry_name;
+ void *mdata;
+
+ /*
+ * These 3 functions should be implemented specifically for each
+ * nsswitch database.
+ */
+ nss_cache_id_func_t id_func; /* marshals the request parameters */
+ nss_cache_marshal_func_t marshal_func; /* marshals response */
+ nss_cache_unmarshal_func_t unmarshal_func; /* unmarshals response */
+
+ /*
+ * These 4 functions should be generated with NSS_MP_CACHE_HANDLING
+ * macro.
+ */
+ nss_set_mp_ws_func_t set_mp_ws_func; /* sets current write session */
+ nss_get_mp_ws_func_t get_mp_ws_func; /* gets current write session */
+
+ nss_set_mp_rs_func_t set_mp_rs_func; /* sets current read session */
+ nss_get_mp_rs_func_t get_mp_rs_func; /* gets current read session */
+} nss_cache_info;
+
+/*
+ * NSS_MP_CACHE_HANDLING implements the set_mp_ws, get_mp_ws, set_mp_rs,
+ * get_mp_rs functions, that are used in _nss_cache_info. It uses
+ * NSS_TLS_HANDLING macro to organize thread local storage.
+ */
+#define NSS_MP_CACHE_HANDLING(name) \
+struct name##_mp_state { \
+ cached_mp_write_session mp_write_session; \
+ cached_mp_read_session mp_read_session; \
+}; \
+ \
+static void \
+name##_mp_endstate(void *s) { \
+ struct name##_mp_state *mp_state; \
+ \
+ mp_state = (struct name##_mp_state *)s; \
+ if (mp_state->mp_write_session != INVALID_CACHED_MP_WRITE_SESSION)\
+ __abandon_cached_mp_write_session(mp_state->mp_write_session);\
+ \
+ if (mp_state->mp_read_session != INVALID_CACHED_MP_READ_SESSION)\
+ __close_cached_mp_read_session(mp_state->mp_read_session);\
+} \
+NSS_TLS_HANDLING(name##_mp); \
+ \
+static void \
+name##_set_mp_ws(cached_mp_write_session ws) \
+{ \
+ struct name##_mp_state *mp_state; \
+ int res; \
+ \
+ res = name##_mp_getstate(&mp_state); \
+ if (res != 0) \
+ return; \
+ \
+ mp_state->mp_write_session = ws; \
+} \
+ \
+static cached_mp_write_session \
+name##_get_mp_ws(void) \
+{ \
+ struct name##_mp_state *mp_state; \
+ int res; \
+ \
+ res = name##_mp_getstate(&mp_state); \
+ if (res != 0) \
+ return (INVALID_CACHED_MP_WRITE_SESSION); \
+ \
+ return (mp_state->mp_write_session); \
+} \
+ \
+static void \
+name##_set_mp_rs(cached_mp_read_session rs) \
+{ \
+ struct name##_mp_state *mp_state; \
+ int res; \
+ \
+ res = name##_mp_getstate(&mp_state); \
+ if (res != 0) \
+ return; \
+ \
+ mp_state->mp_read_session = rs; \
+} \
+ \
+static cached_mp_read_session \
+name##_get_mp_rs(void) \
+{ \
+ struct name##_mp_state *mp_state; \
+ int res; \
+ \
+ res = name##_mp_getstate(&mp_state); \
+ if (res != 0) \
+ return (INVALID_CACHED_MP_READ_SESSION); \
+ \
+ return (mp_state->mp_read_session); \
+}
+
+/*
+ * These macros should be used to initialize _nss_cache_info structure. For
+ * multipart queries in setXXXent and getXXXent functions mf and uf
+ * (marshal function and unmarshal function) should be both NULL.
+ */
+#define NS_COMMON_CACHE_INFO_INITIALIZER(name, mdata, if, mf, uf) \
+ {#name, mdata, if, mf, uf, NULL, NULL, NULL, NULL}
+#define NS_MP_CACHE_INFO_INITIALIZER(name, mdata, mf, uf) \
+ {#name, mdata, NULL, mf, uf, name##_set_mp_ws, name##_get_mp_ws,\
+ name##_set_mp_rs, name##_get_mp_rs }
+
+/*
+ * Analog of other XXX_CB macros. Has the pointer to _nss_cache_info
+ * structure as the only argument.
+ */
+#define NS_CACHE_CB(cinfo) {NSSRC_CACHE, __nss_cache_handler, (void *)(cinfo) },
+
+/* args are: current pointer, current buffer, initial buffer, pointer type */
+#define NS_APPLY_OFFSET(cp, cb, ib, p_type) \
+ if ((cp) != NULL) \
+ (cp) = (p_type)((char *)(cb) + (size_t)(cp) - (size_t)(ib))
+/*
+ * Gets new pointer from the marshalled buffer by uisng initial address
+ * and initial buffer address
+ */
+#define NS_GET_NEWP(cp, cb, ib) \
+ ((char *)(cb) + (size_t)(cp) - (size_t)(ib))
+
+typedef struct _nss_cache_data {
+ char *key;
+ size_t key_size;
+
+ nss_cache_info const *info;
+} nss_cache_data;
+
+__BEGIN_DECLS
+/* dummy function, which is needed to make nss_method_lookup happy */
+extern int __nss_cache_handler(void *, void *, va_list);
+
+#ifdef _NS_PRIVATE
+extern int __nss_common_cache_read(void *, void *, va_list);
+extern int __nss_common_cache_write(void *, void *, va_list);
+extern int __nss_common_cache_write_negative(void *);
+
+extern int __nss_mp_cache_read(void *, void *, va_list);
+extern int __nss_mp_cache_write(void *, void *, va_list);
+extern int __nss_mp_cache_write_submit(void *, void *, va_list);
+extern int __nss_mp_cache_end(void *, void *, va_list);
+#endif /* _NS_PRIVATE */
+
+__END_DECLS
+
+#endif
diff --git a/lib/libc/include/nscachedcli.h b/lib/libc/include/nscachedcli.h
new file mode 100644
index 000000000000..b0f79bd9d05c
--- /dev/null
+++ b/lib/libc/include/nscachedcli.h
@@ -0,0 +1,107 @@
+/*-
+ * Copyright (c) 2004 Michael Bushkov <bushman@rsu.ru>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef __NS_CACHED_CLI_H__
+#define __NS_CACHED_CLI_H__
+
+/*
+ * This file contains API for working with caching daemon
+ */
+
+enum comm_element_t {
+ CET_UNDEFINED = 0,
+ CET_WRITE_REQUEST = 1,
+ CET_WRITE_RESPONSE = 2,
+ CET_READ_REQUEST = 3,
+ CET_READ_RESPONSE = 4,
+ CET_TRANSFORM_REQUEST = 5,
+ CET_TRANSFORM_RESPONSE = 6,
+ CET_MP_WRITE_SESSION_REQUEST = 7,
+ CET_MP_WRITE_SESSION_RESPONSE = 8,
+ CET_MP_WRITE_SESSION_WRITE_REQUEST = 9,
+ CET_MP_WRITE_SESSION_WRITE_RESPONSE = 10,
+ CET_MP_WRITE_SESSION_CLOSE_NOTIFICATION = 11,
+ CET_MP_WRITE_SESSION_ABANDON_NOTIFICATION = 12,
+ CET_MP_READ_SESSION_REQUEST = 13,
+ CET_MP_READ_SESSION_RESPONSE = 14,
+ CET_MP_READ_SESSION_READ_REQUEST = 15,
+ CET_MP_READ_SESSION_READ_RESPONSE = 16,
+ CET_MP_READ_SESSION_CLOSE_NOTIFICATION = 17
+};
+
+struct cached_connection_params {
+ char *socket_path;
+ struct timeval timeout;
+};
+
+struct cached_connection_ {
+ int sockfd;
+ int read_queue;
+ int write_queue;
+
+ int mp_flag; /* shows if the connection is used for
+ * multipart operations */
+};
+
+/* simple abstractions for not to write "struct" every time */
+typedef struct cached_connection_ *cached_connection;
+typedef struct cached_connection_ *cached_mp_write_session;
+typedef struct cached_connection_ *cached_mp_read_session;
+
+#define INVALID_CACHED_CONNECTION (NULL)
+#define INVALID_CACHED_MP_WRITE_SESSION (NULL)
+#define INVALID_CACHED_MP_READ_SESSION (NULL)
+
+__BEGIN_DECLS
+
+/* initialization/destruction routines */
+extern cached_connection __open_cached_connection(
+ struct cached_connection_params const *);
+extern void __close_cached_connection(cached_connection);
+
+/* simple read/write operations */
+extern int __cached_write(cached_connection, const char *, const char *,
+ size_t, const char *, size_t);
+extern int __cached_read(cached_connection, const char *, const char *,
+ size_t, char *, size_t *);
+
+/* multipart read/write operations */
+extern cached_mp_write_session __open_cached_mp_write_session(
+ struct cached_connection_params const *, const char *);
+extern int __cached_mp_write(cached_mp_write_session, const char *, size_t);
+extern int __abandon_cached_mp_write_session(cached_mp_write_session);
+extern int __close_cached_mp_write_session(cached_mp_write_session);
+
+extern cached_mp_read_session __open_cached_mp_read_session(
+ struct cached_connection_params const *, const char *);
+extern int __cached_mp_read(cached_mp_read_session, char *, size_t *);
+extern int __close_cached_mp_read_session(cached_mp_read_session);
+
+__END_DECLS
+
+#endif
diff --git a/lib/libc/include/nss_tls.h b/lib/libc/include/nss_tls.h
new file mode 100644
index 000000000000..13ab367d06b5
--- /dev/null
+++ b/lib/libc/include/nss_tls.h
@@ -0,0 +1,80 @@
+/*-
+ * Copyright (c) 2003 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project by
+ * Jacques A. Vidrine, Safeport Network Services, and Network
+ * Associates Laboratories, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+ * ("CBOSS"), as part of the DARPA CHATS research program.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ *
+ * Macros which generate thread local storage handling code in NSS modules.
+ */
+#ifndef _NSS_TLS_H_
+#define _NSS_TLS_H_
+
+#define NSS_TLS_HANDLING(name) \
+static pthread_key_t name##_state_key; \
+static void name##_keyinit(void); \
+static int name##_getstate(struct name##_state **); \
+\
+static void \
+name##_keyinit(void) \
+{ \
+ (void)_pthread_key_create(&name##_state_key, name##_endstate); \
+} \
+\
+static int \
+name##_getstate(struct name##_state **p) \
+{ \
+ static struct name##_state st; \
+ static pthread_once_t keyinit = PTHREAD_ONCE_INIT; \
+ int rv; \
+ \
+ if (!__isthreaded || _pthread_main_np() != 0) { \
+ *p = &st; \
+ return (0); \
+ } \
+ rv = _pthread_once(&keyinit, name##_keyinit); \
+ if (rv != 0) \
+ return (rv); \
+ *p = _pthread_getspecific(name##_state_key); \
+ if (*p != NULL) \
+ return (0); \
+ *p = calloc(1, sizeof(**p)); \
+ if (*p == NULL) \
+ return (ENOMEM); \
+ rv = _pthread_setspecific(name##_state_key, *p); \
+ if (rv != 0) { \
+ free(*p); \
+ *p = NULL; \
+ } \
+ return (rv); \
+} \
+/* allow the macro invocation to end with a semicolon */ \
+struct _clashproof_bmVjdGFy
+
+#endif /* _NSS_TLS_H_ */
diff --git a/lib/libc/include/port_after.h b/lib/libc/include/port_after.h
new file mode 100644
index 000000000000..94f3a6431e98
--- /dev/null
+++ b/lib/libc/include/port_after.h
@@ -0,0 +1,11 @@
+/* $FreeBSD$ */
+
+#ifndef _PORT_AFTER_H_
+#define _PORT_AFTER_H_
+
+#define HAVE_SA_LEN 1
+#define HAS_INET6_STRUCTS 1
+#define HAVE_SIN6_SCOPE_ID 1
+#define HAVE_TIME_R 1
+
+#endif /* _PORT_AFTER_H_ */
diff --git a/lib/libc/include/port_before.h b/lib/libc/include/port_before.h
new file mode 100644
index 000000000000..430d23363c87
--- /dev/null
+++ b/lib/libc/include/port_before.h
@@ -0,0 +1,23 @@
+/* $FreeBSD$ */
+
+#ifndef _PORT_BEFORE_H_
+#define _PORT_BEFORE_H_
+
+#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) \
+ __attribute__((__format__(__printf__, fmt, args)))
+#define DE_CONST(konst, var) \
+ do { \
+ union { const void *k; void *v; } _u; \
+ _u.k = konst; \
+ var = _u.v; \
+ } while (0)
+
+#define UNUSED(x) (void)(x)
+
+#endif /* _PORT_BEFORE_H_ */
diff --git a/lib/libc/include/reentrant.h b/lib/libc/include/reentrant.h
new file mode 100644
index 000000000000..423c9f69b5fc
--- /dev/null
+++ b/lib/libc/include/reentrant.h
@@ -0,0 +1,128 @@
+/*-
+ * Copyright (c) 1997,98 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by J.T. Conklin.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Requirements:
+ *
+ * 1. The thread safe mechanism should be lightweight so the library can
+ * be used by non-threaded applications without unreasonable overhead.
+ *
+ * 2. There should be no dependency on a thread engine for non-threaded
+ * applications.
+ *
+ * 3. There should be no dependency on any particular thread engine.
+ *
+ * 4. The library should be able to be compiled without support for thread
+ * safety.
+ *
+ *
+ * Rationale:
+ *
+ * One approach for thread safety is to provide discrete versions of the
+ * library: one thread safe, the other not. The disadvantage of this is
+ * that libc is rather large, and two copies of a library which are 99%+
+ * identical is not an efficient use of resources.
+ *
+ * Another approach is to provide a single thread safe library. However,
+ * it should not add significant run time or code size overhead to non-
+ * threaded applications.
+ *
+ * Since the NetBSD C library is used in other projects, it should be
+ * easy to replace the mutual exclusion primitives with ones provided by
+ * another system. Similarly, it should also be easy to remove all
+ * support for thread safety completely if the target environment does
+ * not support threads.
+ *
+ *
+ * Implementation Details:
+ *
+ * The mutex primitives used by the library (mutex_t, mutex_lock, etc.)
+ * are macros which expand to the cooresponding primitives provided by
+ * the thread engine or to nothing. The latter is used so that code is
+ * not unreasonably cluttered with #ifdefs when all thread safe support
+ * is removed.
+ *
+ * The mutex macros can be directly mapped to the mutex primitives from
+ * pthreads, however it should be reasonably easy to wrap another mutex
+ * implementation so it presents a similar interface.
+ *
+ * Stub implementations of the mutex functions are provided with *weak*
+ * linkage. These functions simply return success. When linked with a
+ * thread library (i.e. -lpthread), the functions will override the
+ * stubs.
+ */
+
+#include <pthread.h>
+#include <pthread_np.h>
+#include "libc_private.h"
+
+#define mutex_t pthread_mutex_t
+#define cond_t pthread_cond_t
+#define rwlock_t pthread_rwlock_t
+#define once_t pthread_once_t
+
+#define thread_key_t pthread_key_t
+#define MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
+#define RWLOCK_INITIALIZER PTHREAD_RWLOCK_INITIALIZER
+#define ONCE_INITIALIZER PTHREAD_ONCE_INIT
+
+#define mutex_init(m, a) _pthread_mutex_init(m, a)
+#define mutex_lock(m) if (__isthreaded) \
+ _pthread_mutex_lock(m)
+#define mutex_unlock(m) if (__isthreaded) \
+ _pthread_mutex_unlock(m)
+#define mutex_trylock(m) (__isthreaded ? 0 : _pthread_mutex_trylock(m))
+
+#define cond_init(c, a, p) _pthread_cond_init(c, a)
+#define cond_signal(m) if (__isthreaded) \
+ _pthread_cond_signal(m)
+#define cond_broadcast(m) if (__isthreaded) \
+ _pthread_cond_broadcast(m)
+#define cond_wait(c, m) if (__isthreaded) \
+ _pthread_cond_wait(c, m)
+
+#define rwlock_init(l, a) _pthread_rwlock_init(l, a)
+#define rwlock_rdlock(l) if (__isthreaded) \
+ _pthread_rwlock_rdlock(l)
+#define rwlock_wrlock(l) if (__isthreaded) \
+ _pthread_rwlock_wrlock(l)
+#define rwlock_unlock(l) if (__isthreaded) \
+ _pthread_rwlock_unlock(l)
+
+#define thr_keycreate(k, d) _pthread_key_create(k, d)
+#define thr_setspecific(k, p) _pthread_setspecific(k, p)
+#define thr_getspecific(k) _pthread_getspecific(k)
+#define thr_sigsetmask(f, n, o) _pthread_sigmask(f, n, o)
+
+#define thr_once(o, i) _pthread_once(o, i)
+#define thr_self() _pthread_self()
+#define thr_exit(x) _pthread_exit(x)
+#define thr_main() _pthread_main_np()
diff --git a/lib/libc/include/resolv_mt.h b/lib/libc/include/resolv_mt.h
new file mode 100644
index 000000000000..27963a12077a
--- /dev/null
+++ b/lib/libc/include/resolv_mt.h
@@ -0,0 +1,47 @@
+#ifndef _RESOLV_MT_H
+#define _RESOLV_MT_H
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+/* Access functions for the libresolv private interface */
+
+int __res_enable_mt(void);
+int __res_disable_mt(void);
+
+/* Per-thread context */
+
+typedef struct {
+int no_hosts_fallback_private;
+int retry_save;
+int retry_private;
+char inet_nsap_ntoa_tmpbuf[255*3];
+char sym_ntos_unname[20];
+char sym_ntop_unname[20];
+char p_option_nbuf[40];
+char p_time_nbuf[40];
+char precsize_ntoa_retbuf[sizeof "90000000.00"];
+char loc_ntoa_tmpbuf[sizeof
+"1000 60 60.000 N 1000 60 60.000 W -12345678.00m 90000000.00m 90000000.00m 90000000.00m"];
+char p_secstodate_output[15];
+} mtctxres_t;
+
+/* Thread-specific data (TSD) */
+
+mtctxres_t *___mtctxres(void);
+#define mtctxres (___mtctxres())
+
+/* Various static data that should be TSD */
+
+#define sym_ntos_unname (mtctxres->sym_ntos_unname)
+#define sym_ntop_unname (mtctxres->sym_ntop_unname)
+#define inet_nsap_ntoa_tmpbuf (mtctxres->inet_nsap_ntoa_tmpbuf)
+#define p_option_nbuf (mtctxres->p_option_nbuf)
+#define p_time_nbuf (mtctxres->p_time_nbuf)
+#define precsize_ntoa_retbuf (mtctxres->precsize_ntoa_retbuf)
+#define loc_ntoa_tmpbuf (mtctxres->loc_ntoa_tmpbuf)
+#define p_secstodate_output (mtctxres->p_secstodate_output)
+
+#endif /* _RESOLV_MT_H */
diff --git a/lib/libc/include/spinlock.h b/lib/libc/include/spinlock.h
new file mode 100644
index 000000000000..c9facc517d52
--- /dev/null
+++ b/lib/libc/include/spinlock.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 1998 John Birrell <jb@cimlogic.com.au>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ *
+ * Lock definitions used in both libc and libpthread.
+ *
+ */
+
+#ifndef _SPINLOCK_H_
+#define _SPINLOCK_H_
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+/*
+ * Lock structure with room for debugging information.
+ */
+struct _spinlock {
+ volatile long access_lock;
+ volatile long lock_owner;
+ volatile char *fname;
+ volatile int lineno;
+};
+typedef struct _spinlock spinlock_t;
+
+#define _SPINLOCK_INITIALIZER { 0, 0, 0, 0 }
+
+#define _SPINUNLOCK(_lck) _spinunlock(_lck);
+#ifdef _LOCK_DEBUG
+#define _SPINLOCK(_lck) _spinlock_debug(_lck, __FILE__, __LINE__)
+#else
+#define _SPINLOCK(_lck) _spinlock(_lck)
+#endif
+
+/*
+ * Thread function prototype definitions:
+ */
+__BEGIN_DECLS
+long _atomic_lock(volatile long *);
+void _spinlock(spinlock_t *);
+void _spinunlock(spinlock_t *);
+void _spinlock_debug(spinlock_t *, char *, int);
+__END_DECLS
+
+#endif /* _SPINLOCK_H_ */
diff --git a/lib/libc/include/un-namespace.h b/lib/libc/include/un-namespace.h
new file mode 100644
index 000000000000..023334858572
--- /dev/null
+++ b/lib/libc/include/un-namespace.h
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2001 Daniel Eischen <deischen@FreeBSD.org>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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 _UN_NAMESPACE_H_
+#define _UN_NAMESPACE_H_
+
+#undef accept
+#undef __acl_aclcheck_fd
+#undef __acl_delete_fd
+#undef __acl_get_fd
+#undef __acl_set_fd
+#undef bind
+#undef __cap_get_fd
+#undef __cap_set_fd
+#undef close
+#undef connect
+#undef dup
+#undef dup2
+#undef execve
+#undef fcntl
+#undef flock
+#undef flockfile
+#undef fpathconf
+#undef fstat
+#undef fstatfs
+#undef fsync
+#undef funlockfile
+#undef getdirentries
+#undef getlogin
+#undef getpeername
+#undef getprogname
+#undef getsockname
+#undef getsockopt
+#undef ioctl
+#undef kevent
+#undef listen
+#undef nanosleep
+#undef open
+#undef openat
+#undef poll
+#undef pthread_atfork
+#undef pthread_attr_destroy
+#undef pthread_attr_get_np
+#undef pthread_attr_getaffinity_np
+#undef pthread_attr_getdetachstate
+#undef pthread_attr_getguardsize
+#undef pthread_attr_getinheritsched
+#undef pthread_attr_getschedparam
+#undef pthread_attr_getschedpolicy
+#undef pthread_attr_getscope
+#undef pthread_attr_getstack
+#undef pthread_attr_getstackaddr
+#undef pthread_attr_getstacksize
+#undef pthread_attr_init
+#undef pthread_attr_setaffinity_np
+#undef pthread_attr_setcreatesuspend_np
+#undef pthread_attr_setdetachstate
+#undef pthread_attr_setguardsize
+#undef pthread_attr_setinheritsched
+#undef pthread_attr_setschedparam
+#undef pthread_attr_setschedpolicy
+#undef pthread_attr_setscope
+#undef pthread_attr_setstack
+#undef pthread_attr_setstackaddr
+#undef pthread_attr_setstacksize
+#undef pthread_barrier_destroy
+#undef pthread_barrier_init
+#undef pthread_barrier_wait
+#undef pthread_barrierattr_destroy
+#undef pthread_barrierattr_getpshared
+#undef pthread_barrierattr_init
+#undef pthread_barrierattr_setpshared
+#undef pthread_cancel
+#undef pthread_cond_broadcast
+#undef pthread_cond_destroy
+#undef pthread_cond_init
+#undef pthread_cond_signal
+#undef pthread_cond_timedwait
+#undef pthread_cond_wait
+#undef pthread_condattr_destroy
+#undef pthread_condattr_getclock
+#undef pthread_condattr_getpshared
+#undef pthread_condattr_init
+#undef pthread_condattr_setclock
+#undef pthread_condattr_setpshared
+#undef pthread_create
+#undef pthread_detach
+#undef pthread_equal
+#undef pthread_exit
+#undef pthread_getaffinity_np
+#undef pthread_getconcurrency
+#undef pthread_getcpuclockid
+#undef pthread_getprio
+#undef pthread_getschedparam
+#undef pthread_getspecific
+#undef pthread_getthreadid_np
+#undef pthread_join
+#undef pthread_key_create
+#undef pthread_key_delete
+#undef pthread_kill
+#undef pthread_main_np
+#undef pthread_multi_np
+#undef pthread_mutex_destroy
+#undef pthread_mutex_getprioceiling
+#undef pthread_mutex_init
+#undef pthread_mutex_isowned_np
+#undef pthread_mutex_lock
+#undef pthread_mutex_setprioceiling
+#undef pthread_mutex_timedlock
+#undef pthread_mutex_trylock
+#undef pthread_mutex_unlock
+#undef pthread_mutexattr_destroy
+#undef pthread_mutexattr_getkind_np
+#undef pthread_mutexattr_getprioceiling
+#undef pthread_mutexattr_getprotocol
+#undef pthread_mutexattr_getpshared
+#undef pthread_mutexattr_gettype
+#undef pthread_mutexattr_init
+#undef pthread_mutexattr_setkind_np
+#undef pthread_mutexattr_setprioceiling
+#undef pthread_mutexattr_setprotocol
+#undef pthread_mutexattr_setpshared
+#undef pthread_mutexattr_settype
+#undef pthread_once
+#undef pthread_resume_all_np
+#undef pthread_resume_np
+#undef pthread_rwlock_destroy
+#undef pthread_rwlock_init
+#undef pthread_rwlock_rdlock
+#undef pthread_rwlock_timedrdlock
+#undef pthread_rwlock_timedwrlock
+#undef pthread_rwlock_tryrdlock
+#undef pthread_rwlock_trywrlock
+#undef pthread_rwlock_unlock
+#undef pthread_rwlock_wrlock
+#undef pthread_rwlockattr_destroy
+#undef pthread_rwlockattr_getpshared
+#undef pthread_rwlockattr_init
+#undef pthread_rwlockattr_setpshared
+#undef pthread_self
+#undef pthread_set_name_np
+#undef pthread_setaffinity_np
+#undef pthread_setcancelstate
+#undef pthread_setcanceltype
+#undef pthread_setconcurrency
+#undef pthread_setprio
+#undef pthread_setschedparam
+#undef pthread_setspecific
+#undef pthread_sigmask
+#undef pthread_single_np
+#undef pthread_spin_destroy
+#undef pthread_spin_init
+#undef pthread_spin_lock
+#undef pthread_spin_trylock
+#undef pthread_spin_unlock
+#undef pthread_suspend_all_np
+#undef pthread_suspend_np
+#undef pthread_switch_add_np
+#undef pthread_switch_delete_np
+#undef pthread_testcancel
+#undef pthread_timedjoin_np
+#undef pthread_yield
+#undef read
+#undef readv
+#undef recvfrom
+#undef recvmsg
+#undef recvmmsg
+#undef select
+#undef sem_close
+#undef sem_destroy
+#undef sem_getvalue
+#undef sem_init
+#undef sem_open
+#undef sem_post
+#undef sem_timedwait
+#undef sem_trywait
+#undef sem_unlink
+#undef sem_wait
+#undef sendmsg
+#undef sendmmsg
+#undef sendto
+#undef setsockopt
+#undef sigaction
+#undef sigprocmask
+#undef sigsuspend
+#undef socket
+#undef socketpair
+#undef usleep
+#undef wait4
+#undef wait6
+#undef waitpid
+#undef write
+#undef writev
+
+#if 0
+#undef creat
+#undef fchflags
+#undef fchmod
+#undef ftrylockfile
+#undef msync
+#undef nfssvc
+#undef pause
+#undef sched_yield
+#undef sendfile
+#undef shutdown
+#undef sigaltstack
+#undef sigpending
+#undef sigreturn
+#undef sigsetmask
+#undef sleep
+#undef system
+#undef tcdrain
+#undef wait
+#endif /* 0 */
+
+#ifdef _SIGNAL_H_
+int _sigaction(int, const struct sigaction *, struct sigaction *);
+#endif
+
+#ifdef _SYS_EVENT_H_
+int _kevent(int, const struct kevent *, int, struct kevent *,
+ int, const struct timespec *);
+#endif
+
+#ifdef _SYS_FCNTL_H_
+int _flock(int, int);
+#endif
+
+#undef err
+#undef warn
+#undef nsdispatch
+
+#endif /* _UN_NAMESPACE_H_ */
diff --git a/lib/libc/inet/Makefile.inc b/lib/libc/inet/Makefile.inc
new file mode 100644
index 000000000000..c957b11533a2
--- /dev/null
+++ b/lib/libc/inet/Makefile.inc
@@ -0,0 +1,11 @@
+# $FreeBSD$
+
+# inet sources
+.PATH: ${LIBC_SRCTOP}/inet
+
+SRCS+= inet_addr.c inet_cidr_ntop.c inet_cidr_pton.c inet_lnaof.c \
+ inet_makeaddr.c inet_net_ntop.c inet_net_pton.c inet_neta.c \
+ inet_netof.c inet_network.c inet_ntoa.c inet_ntop.c \
+ inet_pton.c nsap_addr.c
+
+SYM_MAPS+= ${LIBC_SRCTOP}/inet/Symbol.map
diff --git a/lib/libc/inet/Symbol.map b/lib/libc/inet/Symbol.map
new file mode 100644
index 000000000000..f188b137de94
--- /dev/null
+++ b/lib/libc/inet/Symbol.map
@@ -0,0 +1,38 @@
+/*
+ * $FreeBSD$
+ */
+
+FBSD_1.0 {
+ __inet_addr;
+ __inet_aton;
+ inet_addr;
+ inet_aton;
+ __inet_cidr_ntop;
+ __inet_cidr_pton;
+ __inet_lnaof;
+ inet_lnaof;
+ __inet_makeaddr;
+ inet_makeaddr;
+ __inet_net_ntop;
+ inet_net_ntop;
+ __inet_net_pton;
+ inet_net_pton;
+ __inet_neta;
+ inet_neta;
+ __inet_netof;
+ inet_netof;
+ __inet_network;
+ inet_network;
+ __inet_ntoa;
+ inet_ntoa;
+ __inet_ntoa_r;
+ inet_ntoa_r;
+ __inet_ntop;
+ inet_ntop;
+ __inet_pton;
+ inet_pton;
+ __inet_nsap_addr;
+ __inet_nsap_ntoa;
+ inet_nsap_addr;
+ inet_nsap_ntoa;
+};
diff --git a/lib/libc/inet/inet_addr.c b/lib/libc/inet/inet_addr.c
new file mode 100644
index 000000000000..2f97175826ad
--- /dev/null
+++ b/lib/libc/inet/inet_addr.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 1983, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)inet_addr.c 8.1 (Berkeley) 6/17/93";
+static const char rcsid[] = "$Id: inet_addr.c,v 1.5 2005/04/27 04:56:19 sra Exp $";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "port_before.h"
+
+#include <sys/param.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <ctype.h>
+
+#include "port_after.h"
+
+/*%
+ * Ascii internet address interpretation routine.
+ * The value returned is in network order.
+ */
+in_addr_t /* XXX should be struct in_addr :( */
+inet_addr(const char *cp) {
+ struct in_addr val;
+
+ if (inet_aton(cp, &val))
+ return (val.s_addr);
+ return (INADDR_NONE);
+}
+
+/*%
+ * Check whether "cp" is a valid ascii representation
+ * of an Internet address and convert to a binary address.
+ * Returns 1 if the address is valid, 0 if not.
+ * This replaces inet_addr, the return value from which
+ * cannot distinguish between failure and a local broadcast address.
+ */
+int
+inet_aton(const char *cp, struct in_addr *addr) {
+ u_long val;
+ int base, n;
+ char c;
+ u_int8_t parts[4];
+ u_int8_t *pp = parts;
+ int digit;
+
+ c = *cp;
+ for (;;) {
+ /*
+ * Collect number up to ``.''.
+ * Values are specified as for C:
+ * 0x=hex, 0=octal, isdigit=decimal.
+ */
+ if (!isdigit((unsigned char)c))
+ return (0);
+ val = 0; base = 10; digit = 0;
+ if (c == '0') {
+ c = *++cp;
+ if (c == 'x' || c == 'X')
+ base = 16, c = *++cp;
+ else {
+ base = 8;
+ digit = 1 ;
+ }
+ }
+ for (;;) {
+ if (isascii(c) && isdigit((unsigned char)c)) {
+ if (base == 8 && (c == '8' || c == '9'))
+ return (0);
+ val = (val * base) + (c - '0');
+ c = *++cp;
+ digit = 1;
+ } else if (base == 16 && isascii(c) &&
+ isxdigit((unsigned char)c)) {
+ val = (val << 4) |
+ (c + 10 - (islower((unsigned char)c) ? 'a' : 'A'));
+ c = *++cp;
+ digit = 1;
+ } else
+ break;
+ }
+ if (c == '.') {
+ /*
+ * Internet format:
+ * a.b.c.d
+ * a.b.c (with c treated as 16 bits)
+ * a.b (with b treated as 24 bits)
+ */
+ if (pp >= parts + 3 || val > 0xffU)
+ return (0);
+ *pp++ = val;
+ c = *++cp;
+ } else
+ break;
+ }
+ /*
+ * Check for trailing characters.
+ */
+ if (c != '\0' && (!isascii(c) || !isspace((unsigned char)c)))
+ return (0);
+ /*
+ * Did we get a valid digit?
+ */
+ if (!digit)
+ return (0);
+ /*
+ * Concoct the address according to
+ * the number of parts specified.
+ */
+ n = pp - parts + 1;
+ switch (n) {
+ case 1: /*%< a -- 32 bits */
+ break;
+
+ case 2: /*%< a.b -- 8.24 bits */
+ if (val > 0xffffffU)
+ return (0);
+ val |= parts[0] << 24;
+ break;
+
+ case 3: /*%< a.b.c -- 8.8.16 bits */
+ if (val > 0xffffU)
+ return (0);
+ val |= (parts[0] << 24) | (parts[1] << 16);
+ break;
+
+ case 4: /*%< a.b.c.d -- 8.8.8.8 bits */
+ if (val > 0xffU)
+ return (0);
+ val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
+ break;
+ }
+ if (addr != NULL)
+ addr->s_addr = htonl(val);
+ return (1);
+}
+
+/*
+ * Weak aliases for applications that use certain private entry points,
+ * and fail to include <arpa/inet.h>.
+ */
+#undef inet_addr
+__weak_reference(__inet_addr, inet_addr);
+#undef inet_aton
+__weak_reference(__inet_aton, inet_aton);
+
+/*! \file */
diff --git a/lib/libc/inet/inet_cidr_ntop.c b/lib/libc/inet/inet_cidr_ntop.c
new file mode 100644
index 000000000000..33d8ea114202
--- /dev/null
+++ b/lib/libc/inet/inet_cidr_ntop.c
@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1998,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: inet_cidr_ntop.c,v 1.7 2006/10/11 02:18:18 marka Exp $";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "port_after.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) ((size_t)sprintf x)
+#endif
+
+static char *
+inet_cidr_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size);
+static char *
+inet_cidr_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size);
+
+/*%
+ * char *
+ * inet_cidr_ntop(af, src, bits, dst, size)
+ * convert network address from network to presentation format.
+ * "src"'s size is determined from its "af".
+ * return:
+ * pointer to dst, or NULL if an error occurred (check errno).
+ * note:
+ * 192.5.5.1/28 has a nonzero host part, which means it isn't a network
+ * as called for by inet_net_ntop() but it can be a host address with
+ * an included netmask.
+ * author:
+ * Paul Vixie (ISC), October 1998
+ */
+char *
+inet_cidr_ntop(int af, const void *src, int bits, char *dst, size_t size) {
+ switch (af) {
+ case AF_INET:
+ return (inet_cidr_ntop_ipv4(src, bits, dst, size));
+ case AF_INET6:
+ return (inet_cidr_ntop_ipv6(src, bits, dst, size));
+ default:
+ errno = EAFNOSUPPORT;
+ return (NULL);
+ }
+}
+
+static int
+decoct(const u_char *src, int bytes, char *dst, size_t size) {
+ char *odst = dst;
+ char *t;
+ int b;
+
+ for (b = 1; b <= bytes; b++) {
+ if (size < sizeof "255.")
+ return (0);
+ t = dst;
+ dst += SPRINTF((dst, "%u", *src++));
+ if (b != bytes) {
+ *dst++ = '.';
+ *dst = '\0';
+ }
+ size -= (size_t)(dst - t);
+ }
+ return (dst - odst);
+}
+
+/*%
+ * static char *
+ * inet_cidr_ntop_ipv4(src, bits, dst, size)
+ * convert IPv4 network address from network to presentation format.
+ * "src"'s size is determined from its "af".
+ * return:
+ * pointer to dst, or NULL if an error occurred (check errno).
+ * note:
+ * network byte order assumed. this means 192.5.5.240/28 has
+ * 0b11110000 in its fourth octet.
+ * author:
+ * Paul Vixie (ISC), October 1998
+ */
+static char *
+inet_cidr_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size) {
+ char *odst = dst;
+ size_t len = 4;
+ size_t b;
+ size_t bytes;
+
+ if ((bits < -1) || (bits > 32)) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ /* Find number of significant bytes in address. */
+ if (bits == -1)
+ len = 4;
+ else
+ for (len = 1, b = 1 ; b < 4U; b++)
+ if (*(src + b))
+ len = b + 1;
+
+ /* Format whole octets plus nonzero trailing octets. */
+ bytes = (((bits <= 0) ? 1 : bits) + 7) / 8;
+ if (len > bytes)
+ bytes = len;
+ b = decoct(src, bytes, dst, size);
+ if (b == 0U)
+ goto emsgsize;
+ dst += b;
+ size -= b;
+
+ if (bits != -1) {
+ /* Format CIDR /width. */
+ if (size < sizeof "/32")
+ goto emsgsize;
+ dst += SPRINTF((dst, "/%u", bits));
+ }
+
+ return (odst);
+
+ emsgsize:
+ errno = EMSGSIZE;
+ return (NULL);
+}
+
+static char *
+inet_cidr_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size) {
+ /*
+ * Note that int32_t and int16_t need only be "at least" large enough
+ * to contain a value of the specified size. On some systems, like
+ * Crays, there is no such thing as an integer variable with 16 bits.
+ * Keep this in mind if you think this function should have been coded
+ * to use pointer overlays. All the world's not a VAX.
+ */
+ char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255/128"];
+ char *tp;
+ struct { int base, len; } best, cur;
+ u_int words[NS_IN6ADDRSZ / NS_INT16SZ];
+ int i;
+
+ if ((bits < -1) || (bits > 128)) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ /*
+ * Preprocess:
+ * Copy the input (bytewise) array into a wordwise array.
+ * Find the longest run of 0x00's in src[] for :: shorthanding.
+ */
+ memset(words, '\0', sizeof words);
+ for (i = 0; i < NS_IN6ADDRSZ; i++)
+ words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
+ best.base = -1;
+ best.len = 0;
+ cur.base = -1;
+ cur.len = 0;
+ for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
+ if (words[i] == 0) {
+ if (cur.base == -1)
+ cur.base = i, cur.len = 1;
+ else
+ cur.len++;
+ } else {
+ if (cur.base != -1) {
+ if (best.base == -1 || cur.len > best.len)
+ best = cur;
+ cur.base = -1;
+ }
+ }
+ }
+ if (cur.base != -1) {
+ if (best.base == -1 || cur.len > best.len)
+ best = cur;
+ }
+ if (best.base != -1 && best.len < 2)
+ best.base = -1;
+
+ /*
+ * Format the result.
+ */
+ tp = tmp;
+ for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
+ /* Are we inside the best run of 0x00's? */
+ if (best.base != -1 && i >= best.base &&
+ i < (best.base + best.len)) {
+ if (i == best.base)
+ *tp++ = ':';
+ continue;
+ }
+ /* Are we following an initial run of 0x00s or any real hex? */
+ if (i != 0)
+ *tp++ = ':';
+ /* Is this address an encapsulated IPv4? */
+ if (i == 6 && best.base == 0 && (best.len == 6 ||
+ (best.len == 7 && words[7] != 0x0001) ||
+ (best.len == 5 && words[5] == 0xffff))) {
+ int n;
+
+ if (src[15] || bits == -1 || bits > 120)
+ n = 4;
+ else if (src[14] || bits > 112)
+ n = 3;
+ else
+ n = 2;
+ n = decoct(src+12, n, tp, sizeof tmp - (tp - tmp));
+ if (n == 0) {
+ errno = EMSGSIZE;
+ return (NULL);
+ }
+ tp += strlen(tp);
+ break;
+ }
+ tp += SPRINTF((tp, "%x", words[i]));
+ }
+
+ /* Was it a trailing run of 0x00's? */
+ if (best.base != -1 && (best.base + best.len) ==
+ (NS_IN6ADDRSZ / NS_INT16SZ))
+ *tp++ = ':';
+ *tp = '\0';
+
+ if (bits != -1)
+ tp += SPRINTF((tp, "/%u", bits));
+
+ /*
+ * Check for overflow, copy, and we're done.
+ */
+ if ((size_t)(tp - tmp) > size) {
+ errno = EMSGSIZE;
+ return (NULL);
+ }
+ strcpy(dst, tmp);
+ return (dst);
+}
+
+/*! \file */
diff --git a/lib/libc/inet/inet_cidr_pton.c b/lib/libc/inet/inet_cidr_pton.c
new file mode 100644
index 000000000000..a6a5c7d94488
--- /dev/null
+++ b/lib/libc/inet/inet_cidr_pton.c
@@ -0,0 +1,279 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1998,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: inet_cidr_pton.c,v 1.6 2005/04/27 04:56:19 sra Exp $";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "port_after.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) ((size_t)sprintf x)
+#endif
+
+static int inet_cidr_pton_ipv4 __P((const char *src, u_char *dst,
+ int *bits, int ipv6));
+static int inet_cidr_pton_ipv6 __P((const char *src, u_char *dst,
+ int *bits));
+
+static int getbits(const char *, int ipv6);
+
+/*%
+ * int
+ * inet_cidr_pton(af, src, dst, *bits)
+ * convert network address from presentation to network format.
+ * accepts inet_pton()'s input for this "af" plus trailing "/CIDR".
+ * "dst" is assumed large enough for its "af". "bits" is set to the
+ * /CIDR prefix length, which can have defaults (like /32 for IPv4).
+ * return:
+ * -1 if an error occurred (inspect errno; ENOENT means bad format).
+ * 0 if successful conversion occurred.
+ * note:
+ * 192.5.5.1/28 has a nonzero host part, which means it isn't a network
+ * as called for by inet_net_pton() but it can be a host address with
+ * an included netmask.
+ * author:
+ * Paul Vixie (ISC), October 1998
+ */
+int
+inet_cidr_pton(int af, const char *src, void *dst, int *bits) {
+ switch (af) {
+ case AF_INET:
+ return (inet_cidr_pton_ipv4(src, dst, bits, 0));
+ case AF_INET6:
+ return (inet_cidr_pton_ipv6(src, dst, bits));
+ default:
+ errno = EAFNOSUPPORT;
+ return (-1);
+ }
+}
+
+static const char digits[] = "0123456789";
+
+static int
+inet_cidr_pton_ipv4(const char *src, u_char *dst, int *pbits, int ipv6) {
+ const u_char *odst = dst;
+ int n, ch, tmp, bits;
+ size_t size = 4;
+
+ /* Get the mantissa. */
+ while (ch = *src++, (isascii(ch) && isdigit(ch))) {
+ tmp = 0;
+ do {
+ n = strchr(digits, ch) - digits;
+ assert(n >= 0 && n <= 9);
+ tmp *= 10;
+ tmp += n;
+ if (tmp > 255)
+ goto enoent;
+ } while ((ch = *src++) != '\0' && isascii(ch) && isdigit(ch));
+ if (size-- == 0U)
+ goto emsgsize;
+ *dst++ = (u_char) tmp;
+ if (ch == '\0' || ch == '/')
+ break;
+ if (ch != '.')
+ goto enoent;
+ }
+
+ /* Get the prefix length if any. */
+ bits = -1;
+ if (ch == '/' && dst > odst) {
+ bits = getbits(src, ipv6);
+ if (bits == -2)
+ goto enoent;
+ } else if (ch != '\0')
+ goto enoent;
+
+ /* Prefix length can default to /32 only if all four octets spec'd. */
+ if (bits == -1) {
+ if (dst - odst == 4)
+ bits = ipv6 ? 128 : 32;
+ else
+ goto enoent;
+ }
+
+ /* If nothing was written to the destination, we found no address. */
+ if (dst == odst)
+ goto enoent;
+
+ /* If prefix length overspecifies mantissa, life is bad. */
+ if (((bits - (ipv6 ? 96 : 0)) / 8) > (dst - odst))
+ goto enoent;
+
+ /* Extend address to four octets. */
+ while (size-- > 0U)
+ *dst++ = 0;
+
+ *pbits = bits;
+ return (0);
+
+ enoent:
+ errno = ENOENT;
+ return (-1);
+
+ emsgsize:
+ errno = EMSGSIZE;
+ return (-1);
+}
+
+static int
+inet_cidr_pton_ipv6(const char *src, u_char *dst, int *pbits) {
+ static const char xdigits_l[] = "0123456789abcdef",
+ xdigits_u[] = "0123456789ABCDEF";
+ u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
+ const char *xdigits, *curtok;
+ int ch, saw_xdigit;
+ u_int val;
+ int bits;
+
+ memset((tp = tmp), '\0', NS_IN6ADDRSZ);
+ endp = tp + NS_IN6ADDRSZ;
+ colonp = NULL;
+ /* Leading :: requires some special handling. */
+ if (*src == ':')
+ if (*++src != ':')
+ return (0);
+ curtok = src;
+ saw_xdigit = 0;
+ val = 0;
+ bits = -1;
+ while ((ch = *src++) != '\0') {
+ const char *pch;
+
+ if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
+ pch = strchr((xdigits = xdigits_u), ch);
+ if (pch != NULL) {
+ val <<= 4;
+ val |= (pch - xdigits);
+ if (val > 0xffff)
+ return (0);
+ saw_xdigit = 1;
+ continue;
+ }
+ if (ch == ':') {
+ curtok = src;
+ if (!saw_xdigit) {
+ if (colonp)
+ return (0);
+ colonp = tp;
+ continue;
+ } else if (*src == '\0') {
+ return (0);
+ }
+ if (tp + NS_INT16SZ > endp)
+ return (0);
+ *tp++ = (u_char) (val >> 8) & 0xff;
+ *tp++ = (u_char) val & 0xff;
+ saw_xdigit = 0;
+ val = 0;
+ continue;
+ }
+ if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
+ inet_cidr_pton_ipv4(curtok, tp, &bits, 1) == 0) {
+ tp += NS_INADDRSZ;
+ saw_xdigit = 0;
+ break; /*%< '\\0' was seen by inet_pton4(). */
+ }
+ if (ch == '/') {
+ bits = getbits(src, 1);
+ if (bits == -2)
+ goto enoent;
+ break;
+ }
+ goto enoent;
+ }
+ if (saw_xdigit) {
+ if (tp + NS_INT16SZ > endp)
+ goto emsgsize;
+ *tp++ = (u_char) (val >> 8) & 0xff;
+ *tp++ = (u_char) val & 0xff;
+ }
+ if (colonp != NULL) {
+ /*
+ * Since some memmove()'s erroneously fail to handle
+ * overlapping regions, we'll do the shift by hand.
+ */
+ const int n = tp - colonp;
+ int i;
+
+ if (tp == endp)
+ goto enoent;
+ for (i = 1; i <= n; i++) {
+ endp[- i] = colonp[n - i];
+ colonp[n - i] = 0;
+ }
+ tp = endp;
+ }
+
+ memcpy(dst, tmp, NS_IN6ADDRSZ);
+
+ *pbits = bits;
+ return (0);
+
+ enoent:
+ errno = ENOENT;
+ return (-1);
+
+ emsgsize:
+ errno = EMSGSIZE;
+ return (-1);
+}
+
+static int
+getbits(const char *src, int ipv6) {
+ int bits = 0;
+ char *cp, ch;
+
+ if (*src == '\0') /*%< syntax */
+ return (-2);
+ do {
+ ch = *src++;
+ cp = strchr(digits, ch);
+ if (cp == NULL) /*%< syntax */
+ return (-2);
+ bits *= 10;
+ bits += cp - digits;
+ if (bits == 0 && *src != '\0') /*%< no leading zeros */
+ return (-2);
+ if (bits > (ipv6 ? 128 : 32)) /*%< range error */
+ return (-2);
+ } while (*src != '\0');
+
+ return (bits);
+}
+
+/*! \file */
diff --git a/lib/libc/inet/inet_lnaof.c b/lib/libc/inet/inet_lnaof.c
new file mode 100644
index 000000000000..274253f4a310
--- /dev/null
+++ b/lib/libc/inet/inet_lnaof.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)inet_lnaof.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "port_before.h"
+
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "port_after.h"
+
+/*%
+ * Return the local network address portion of an
+ * internet address; handles class a/b/c network
+ * number formats.
+ */
+in_addr_t
+inet_lnaof(struct in_addr in)
+{
+ in_addr_t i = ntohl(in.s_addr);
+
+ if (IN_CLASSA(i))
+ return ((i)&IN_CLASSA_HOST);
+ else if (IN_CLASSB(i))
+ return ((i)&IN_CLASSB_HOST);
+ else
+ return ((i)&IN_CLASSC_HOST);
+}
+
+/*
+ * Weak aliases for applications that use certain private entry points,
+ * and fail to include <arpa/inet.h>.
+ */
+#undef inet_lnaof
+__weak_reference(__inet_lnaof, inet_lnaof);
+
+/*! \file */
diff --git a/lib/libc/inet/inet_makeaddr.c b/lib/libc/inet/inet_makeaddr.c
new file mode 100644
index 000000000000..bce0aa1c127f
--- /dev/null
+++ b/lib/libc/inet/inet_makeaddr.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)inet_makeaddr.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "port_before.h"
+
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "port_after.h"
+
+/*%
+ * Formulate an Internet address from network + host. Used in
+ * building addresses stored in the ifnet structure.
+ */
+struct in_addr
+inet_makeaddr(in_addr_t net, in_addr_t host)
+{
+ struct in_addr a;
+
+ if (net < 128U)
+ a.s_addr = (net << IN_CLASSA_NSHIFT) | (host & IN_CLASSA_HOST);
+ else if (net < 65536U)
+ a.s_addr = (net << IN_CLASSB_NSHIFT) | (host & IN_CLASSB_HOST);
+ else if (net < 16777216L)
+ a.s_addr = (net << IN_CLASSC_NSHIFT) | (host & IN_CLASSC_HOST);
+ else
+ a.s_addr = net | host;
+ a.s_addr = htonl(a.s_addr);
+ return (a);
+}
+
+/*
+ * Weak aliases for applications that use certain private entry points,
+ * and fail to include <arpa/inet.h>.
+ */
+#undef inet_makeaddr
+__weak_reference(__inet_makeaddr, inet_makeaddr);
+
+/*! \file */
diff --git a/lib/libc/inet/inet_net_ntop.c b/lib/libc/inet/inet_net_ntop.c
new file mode 100644
index 000000000000..001a30408c50
--- /dev/null
+++ b/lib/libc/inet/inet_net_ntop.c
@@ -0,0 +1,279 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: inet_net_ntop.c,v 1.5 2006/06/20 02:50:14 marka Exp $";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "port_after.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) ((size_t)sprintf x)
+#endif
+
+static char * inet_net_ntop_ipv4(const u_char *src, int bits, char *dst,
+ size_t size);
+static char * inet_net_ntop_ipv6(const u_char *src, int bits, char *dst,
+ size_t size);
+
+/*%
+ * char *
+ * inet_net_ntop(af, src, bits, dst, size)
+ * convert network number from network to presentation format.
+ * generates CIDR style result always.
+ * return:
+ * pointer to dst, or NULL if an error occurred (check errno).
+ * author:
+ * Paul Vixie (ISC), July 1996
+ */
+char *
+inet_net_ntop(int af, const void *src, int bits, char *dst, size_t size)
+{
+ switch (af) {
+ case AF_INET:
+ return (inet_net_ntop_ipv4(src, bits, dst, size));
+ case AF_INET6:
+ return (inet_net_ntop_ipv6(src, bits, dst, size));
+ default:
+ errno = EAFNOSUPPORT;
+ return (NULL);
+ }
+}
+
+/*%
+ * static char *
+ * inet_net_ntop_ipv4(src, bits, dst, size)
+ * convert IPv4 network number from network to presentation format.
+ * generates CIDR style result always.
+ * return:
+ * pointer to dst, or NULL if an error occurred (check errno).
+ * note:
+ * network byte order assumed. this means 192.5.5.240/28 has
+ * 0b11110000 in its fourth octet.
+ * author:
+ * Paul Vixie (ISC), July 1996
+ */
+static char *
+inet_net_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size)
+{
+ char *odst = dst;
+ char *t;
+ u_int m;
+ int b;
+
+ if (bits < 0 || bits > 32) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ if (bits == 0) {
+ if (size < sizeof "0")
+ goto emsgsize;
+ *dst++ = '0';
+ size--;
+ *dst = '\0';
+ }
+
+ /* Format whole octets. */
+ for (b = bits / 8; b > 0; b--) {
+ if (size <= sizeof "255.")
+ goto emsgsize;
+ t = dst;
+ dst += SPRINTF((dst, "%u", *src++));
+ if (b > 1) {
+ *dst++ = '.';
+ *dst = '\0';
+ }
+ size -= (size_t)(dst - t);
+ }
+
+ /* Format partial octet. */
+ b = bits % 8;
+ if (b > 0) {
+ if (size <= sizeof ".255")
+ goto emsgsize;
+ t = dst;
+ if (dst != odst)
+ *dst++ = '.';
+ m = ((1 << b) - 1) << (8 - b);
+ dst += SPRINTF((dst, "%u", *src & m));
+ size -= (size_t)(dst - t);
+ }
+
+ /* Format CIDR /width. */
+ if (size <= sizeof "/32")
+ goto emsgsize;
+ dst += SPRINTF((dst, "/%u", bits));
+ return (odst);
+
+ emsgsize:
+ errno = EMSGSIZE;
+ return (NULL);
+}
+
+/*%
+ * static char *
+ * inet_net_ntop_ipv6(src, bits, fakebits, dst, size)
+ * convert IPv6 network number from network to presentation format.
+ * generates CIDR style result always. Picks the shortest representation
+ * unless the IP is really IPv4.
+ * always prints specified number of bits (bits).
+ * return:
+ * pointer to dst, or NULL if an error occurred (check errno).
+ * note:
+ * network byte order assumed. this means 192.5.5.240/28 has
+ * 0b11110000 in its fourth octet.
+ * author:
+ * Vadim Kogan (UCB), June 2001
+ * Original version (IPv4) by Paul Vixie (ISC), July 1996
+ */
+
+static char *
+inet_net_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size) {
+ u_int m;
+ int b;
+ int p;
+ int zero_s, zero_l, tmp_zero_s, tmp_zero_l;
+ int i;
+ int is_ipv4 = 0;
+ unsigned char inbuf[16];
+ char outbuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
+ char *cp;
+ int words;
+ u_char *s;
+
+ if (bits < 0 || bits > 128) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ cp = outbuf;
+
+ if (bits == 0) {
+ *cp++ = ':';
+ *cp++ = ':';
+ *cp = '\0';
+ } else {
+ /* Copy src to private buffer. Zero host part. */
+ p = (bits + 7) / 8;
+ memcpy(inbuf, src, p);
+ memset(inbuf + p, 0, 16 - p);
+ b = bits % 8;
+ if (b != 0) {
+ m = ~0 << (8 - b);
+ inbuf[p-1] &= m;
+ }
+
+ s = inbuf;
+
+ /* how many words need to be displayed in output */
+ words = (bits + 15) / 16;
+ if (words == 1)
+ words = 2;
+
+ /* Find the longest substring of zero's */
+ zero_s = zero_l = tmp_zero_s = tmp_zero_l = 0;
+ for (i = 0; i < (words * 2); i += 2) {
+ if ((s[i] | s[i+1]) == 0) {
+ if (tmp_zero_l == 0)
+ tmp_zero_s = i / 2;
+ tmp_zero_l++;
+ } else {
+ if (tmp_zero_l && zero_l < tmp_zero_l) {
+ zero_s = tmp_zero_s;
+ zero_l = tmp_zero_l;
+ tmp_zero_l = 0;
+ }
+ }
+ }
+
+ if (tmp_zero_l && zero_l < tmp_zero_l) {
+ zero_s = tmp_zero_s;
+ zero_l = tmp_zero_l;
+ }
+
+ if (zero_l != words && zero_s == 0 && ((zero_l == 6) ||
+ ((zero_l == 5 && s[10] == 0xff && s[11] == 0xff) ||
+ ((zero_l == 7 && s[14] != 0 && s[15] != 1)))))
+ is_ipv4 = 1;
+
+ /* Format whole words. */
+ for (p = 0; p < words; p++) {
+ if (zero_l != 0 && p >= zero_s && p < zero_s + zero_l) {
+ /* Time to skip some zeros */
+ if (p == zero_s)
+ *cp++ = ':';
+ if (p == words - 1)
+ *cp++ = ':';
+ s++;
+ s++;
+ continue;
+ }
+
+ if (is_ipv4 && p > 5 ) {
+ *cp++ = (p == 6) ? ':' : '.';
+ cp += SPRINTF((cp, "%u", *s++));
+ /* we can potentially drop the last octet */
+ if (p != 7 || bits > 120) {
+ *cp++ = '.';
+ cp += SPRINTF((cp, "%u", *s++));
+ }
+ } else {
+ if (cp != outbuf)
+ *cp++ = ':';
+ cp += SPRINTF((cp, "%x", *s * 256 + s[1]));
+ s += 2;
+ }
+ }
+ }
+ /* Format CIDR /width. */
+ sprintf(cp, "/%u", bits);
+ if (strlen(outbuf) + 1 > size)
+ goto emsgsize;
+ strcpy(dst, outbuf);
+
+ return (dst);
+
+emsgsize:
+ errno = EMSGSIZE;
+ return (NULL);
+}
+
+/*
+ * Weak aliases for applications that use certain private entry points,
+ * and fail to include <arpa/inet.h>.
+ */
+#undef inet_net_ntop
+__weak_reference(__inet_net_ntop, inet_net_ntop);
+
+/*! \file */
diff --git a/lib/libc/inet/inet_net_pton.c b/lib/libc/inet/inet_net_pton.c
new file mode 100644
index 000000000000..fa187591f09b
--- /dev/null
+++ b/lib/libc/inet/inet_net_pton.c
@@ -0,0 +1,416 @@
+/*
+ * Copyright (C) 2004, 2005, 2008 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1996, 1998, 1999, 2001, 2003 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: inet_net_pton.c,v 1.10 2008/11/14 02:36:51 marka Exp $";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "port_after.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) ((size_t)sprintf x)
+#endif
+
+/*%
+ * static int
+ * inet_net_pton_ipv4(src, dst, size)
+ * convert IPv4 network number from presentation to network format.
+ * accepts hex octets, hex strings, decimal octets, and /CIDR.
+ * "size" is in bytes and describes "dst".
+ * return:
+ * number of bits, either imputed classfully or specified with /CIDR,
+ * or -1 if some failure occurred (check errno). ENOENT means it was
+ * not an IPv4 network specification.
+ * note:
+ * network byte order assumed. this means 192.5.5.240/28 has
+ * 0b11110000 in its fourth octet.
+ * author:
+ * Paul Vixie (ISC), June 1996
+ */
+static int
+inet_net_pton_ipv4(const char *src, u_char *dst, size_t size) {
+ static const char xdigits[] = "0123456789abcdef";
+ static const char digits[] = "0123456789";
+ int n, ch, tmp = 0, dirty, bits;
+ const u_char *odst = dst;
+
+ ch = *src++;
+ if (ch == '0' && (src[0] == 'x' || src[0] == 'X')
+ && isascii((unsigned char)(src[1]))
+ && isxdigit((unsigned char)(src[1]))) {
+ /* Hexadecimal: Eat nybble string. */
+ if (size <= 0U)
+ goto emsgsize;
+ dirty = 0;
+ src++; /*%< skip x or X. */
+ while ((ch = *src++) != '\0' && isascii(ch) && isxdigit(ch)) {
+ if (isupper(ch))
+ ch = tolower(ch);
+ n = strchr(xdigits, ch) - xdigits;
+ assert(n >= 0 && n <= 15);
+ if (dirty == 0)
+ tmp = n;
+ else
+ tmp = (tmp << 4) | n;
+ if (++dirty == 2) {
+ if (size-- <= 0U)
+ goto emsgsize;
+ *dst++ = (u_char) tmp;
+ dirty = 0;
+ }
+ }
+ if (dirty) { /*%< Odd trailing nybble? */
+ if (size-- <= 0U)
+ goto emsgsize;
+ *dst++ = (u_char) (tmp << 4);
+ }
+ } else if (isascii(ch) && isdigit(ch)) {
+ /* Decimal: eat dotted digit string. */
+ for (;;) {
+ tmp = 0;
+ do {
+ n = strchr(digits, ch) - digits;
+ assert(n >= 0 && n <= 9);
+ tmp *= 10;
+ tmp += n;
+ if (tmp > 255)
+ goto enoent;
+ } while ((ch = *src++) != '\0' &&
+ isascii(ch) && isdigit(ch));
+ if (size-- <= 0U)
+ goto emsgsize;
+ *dst++ = (u_char) tmp;
+ if (ch == '\0' || ch == '/')
+ break;
+ if (ch != '.')
+ goto enoent;
+ ch = *src++;
+ if (!isascii(ch) || !isdigit(ch))
+ goto enoent;
+ }
+ } else
+ goto enoent;
+
+ bits = -1;
+ if (ch == '/' && isascii((unsigned char)(src[0])) &&
+ isdigit((unsigned char)(src[0])) && dst > odst) {
+ /* CIDR width specifier. Nothing can follow it. */
+ ch = *src++; /*%< Skip over the /. */
+ bits = 0;
+ do {
+ n = strchr(digits, ch) - digits;
+ assert(n >= 0 && n <= 9);
+ bits *= 10;
+ bits += n;
+ if (bits > 32)
+ goto enoent;
+ } while ((ch = *src++) != '\0' && isascii(ch) && isdigit(ch));
+ if (ch != '\0')
+ goto enoent;
+ }
+
+ /* Firey death and destruction unless we prefetched EOS. */
+ if (ch != '\0')
+ goto enoent;
+
+ /* If nothing was written to the destination, we found no address. */
+ if (dst == odst)
+ goto enoent;
+ /* If no CIDR spec was given, infer width from net class. */
+ if (bits == -1) {
+ if (*odst >= 240) /*%< Class E */
+ bits = 32;
+ else if (*odst >= 224) /*%< Class D */
+ bits = 8;
+ else if (*odst >= 192) /*%< Class C */
+ bits = 24;
+ else if (*odst >= 128) /*%< Class B */
+ bits = 16;
+ else /*%< Class A */
+ bits = 8;
+ /* If imputed mask is narrower than specified octets, widen. */
+ if (bits < ((dst - odst) * 8))
+ bits = (dst - odst) * 8;
+ /*
+ * If there are no additional bits specified for a class D
+ * address adjust bits to 4.
+ */
+ if (bits == 8 && *odst == 224)
+ bits = 4;
+ }
+ /* Extend network to cover the actual mask. */
+ while (bits > ((dst - odst) * 8)) {
+ if (size-- <= 0U)
+ goto emsgsize;
+ *dst++ = '\0';
+ }
+ return (bits);
+
+ enoent:
+ errno = ENOENT;
+ return (-1);
+
+ emsgsize:
+ errno = EMSGSIZE;
+ return (-1);
+}
+
+static int
+getbits(const char *src, int *bitsp) {
+ static const char digits[] = "0123456789";
+ int n;
+ int val;
+ char ch;
+
+ val = 0;
+ n = 0;
+ while ((ch = *src++) != '\0') {
+ const char *pch;
+
+ pch = strchr(digits, ch);
+ if (pch != NULL) {
+ if (n++ != 0 && val == 0) /*%< no leading zeros */
+ return (0);
+ val *= 10;
+ val += (pch - digits);
+ if (val > 128) /*%< range */
+ return (0);
+ continue;
+ }
+ return (0);
+ }
+ if (n == 0)
+ return (0);
+ *bitsp = val;
+ return (1);
+}
+
+static int
+getv4(const char *src, u_char *dst, int *bitsp) {
+ static const char digits[] = "0123456789";
+ u_char *odst = dst;
+ int n;
+ u_int val;
+ char ch;
+
+ val = 0;
+ n = 0;
+ while ((ch = *src++) != '\0') {
+ const char *pch;
+
+ pch = strchr(digits, ch);
+ if (pch != NULL) {
+ if (n++ != 0 && val == 0) /*%< no leading zeros */
+ return (0);
+ val *= 10;
+ val += (pch - digits);
+ if (val > 255) /*%< range */
+ return (0);
+ continue;
+ }
+ if (ch == '.' || ch == '/') {
+ if (dst - odst > 3) /*%< too many octets? */
+ return (0);
+ *dst++ = val;
+ if (ch == '/')
+ return (getbits(src, bitsp));
+ val = 0;
+ n = 0;
+ continue;
+ }
+ return (0);
+ }
+ if (n == 0)
+ return (0);
+ if (dst - odst > 3) /*%< too many octets? */
+ return (0);
+ *dst++ = val;
+ return (1);
+}
+
+static int
+inet_net_pton_ipv6(const char *src, u_char *dst, size_t size) {
+ static const char xdigits_l[] = "0123456789abcdef",
+ xdigits_u[] = "0123456789ABCDEF";
+ u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
+ const char *xdigits, *curtok;
+ int ch, saw_xdigit;
+ u_int val;
+ int digits;
+ int bits;
+ size_t bytes;
+ int words;
+ int ipv4;
+
+ memset((tp = tmp), '\0', NS_IN6ADDRSZ);
+ endp = tp + NS_IN6ADDRSZ;
+ colonp = NULL;
+ /* Leading :: requires some special handling. */
+ if (*src == ':')
+ if (*++src != ':')
+ goto enoent;
+ curtok = src;
+ saw_xdigit = 0;
+ val = 0;
+ digits = 0;
+ bits = -1;
+ ipv4 = 0;
+ while ((ch = *src++) != '\0') {
+ const char *pch;
+
+ if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
+ pch = strchr((xdigits = xdigits_u), ch);
+ if (pch != NULL) {
+ val <<= 4;
+ val |= (pch - xdigits);
+ if (++digits > 4)
+ goto enoent;
+ saw_xdigit = 1;
+ continue;
+ }
+ if (ch == ':') {
+ curtok = src;
+ if (!saw_xdigit) {
+ if (colonp)
+ goto enoent;
+ colonp = tp;
+ continue;
+ } else if (*src == '\0')
+ goto enoent;
+ if (tp + NS_INT16SZ > endp)
+ return (0);
+ *tp++ = (u_char) (val >> 8) & 0xff;
+ *tp++ = (u_char) val & 0xff;
+ saw_xdigit = 0;
+ digits = 0;
+ val = 0;
+ continue;
+ }
+ if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
+ getv4(curtok, tp, &bits) > 0) {
+ tp += NS_INADDRSZ;
+ saw_xdigit = 0;
+ ipv4 = 1;
+ break; /*%< '\\0' was seen by inet_pton4(). */
+ }
+ if (ch == '/' && getbits(src, &bits) > 0)
+ break;
+ goto enoent;
+ }
+ if (saw_xdigit) {
+ if (tp + NS_INT16SZ > endp)
+ goto enoent;
+ *tp++ = (u_char) (val >> 8) & 0xff;
+ *tp++ = (u_char) val & 0xff;
+ }
+ if (bits == -1)
+ bits = 128;
+
+ words = (bits + 15) / 16;
+ if (words < 2)
+ words = 2;
+ if (ipv4)
+ words = 8;
+ endp = tmp + 2 * words;
+
+ if (colonp != NULL) {
+ /*
+ * Since some memmove()'s erroneously fail to handle
+ * overlapping regions, we'll do the shift by hand.
+ */
+ const int n = tp - colonp;
+ int i;
+
+ if (tp == endp)
+ goto enoent;
+ for (i = 1; i <= n; i++) {
+ endp[- i] = colonp[n - i];
+ colonp[n - i] = 0;
+ }
+ tp = endp;
+ }
+ if (tp != endp)
+ goto enoent;
+
+ bytes = (bits + 7) / 8;
+ if (bytes > size)
+ goto emsgsize;
+ memcpy(dst, tmp, bytes);
+ return (bits);
+
+ enoent:
+ errno = ENOENT;
+ return (-1);
+
+ emsgsize:
+ errno = EMSGSIZE;
+ return (-1);
+}
+
+/*%
+ * int
+ * inet_net_pton(af, src, dst, size)
+ * convert network number from presentation to network format.
+ * accepts hex octets, hex strings, decimal octets, and /CIDR.
+ * "size" is in bytes and describes "dst".
+ * return:
+ * number of bits, either imputed classfully or specified with /CIDR,
+ * or -1 if some failure occurred (check errno). ENOENT means it was
+ * not a valid network specification.
+ * author:
+ * Paul Vixie (ISC), June 1996
+ */
+int
+inet_net_pton(int af, const char *src, void *dst, size_t size) {
+ switch (af) {
+ case AF_INET:
+ return (inet_net_pton_ipv4(src, dst, size));
+ case AF_INET6:
+ return (inet_net_pton_ipv6(src, dst, size));
+ default:
+ errno = EAFNOSUPPORT;
+ return (-1);
+ }
+}
+
+/*
+ * Weak aliases for applications that use certain private entry points,
+ * and fail to include <arpa/inet.h>.
+ */
+#undef inet_net_pton
+__weak_reference(__inet_net_pton, inet_net_pton);
+
+/*! \file */
diff --git a/lib/libc/inet/inet_neta.c b/lib/libc/inet/inet_neta.c
new file mode 100644
index 000000000000..06a1bdbe1365
--- /dev/null
+++ b/lib/libc/inet/inet_neta.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: inet_neta.c,v 1.3 2005/04/27 04:56:20 sra Exp $";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "port_after.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) ((size_t)sprintf x)
+#endif
+
+/*%
+ * char *
+ * inet_neta(src, dst, size)
+ * format an in_addr_t network number into presentation format.
+ * return:
+ * pointer to dst, or NULL if an error occurred (check errno).
+ * note:
+ * format of ``src'' is as for inet_network().
+ * author:
+ * Paul Vixie (ISC), July 1996
+ */
+char *
+inet_neta(in_addr_t src, char *dst, size_t size)
+{
+ char *odst = dst;
+ char *tp;
+
+ while (src & 0xffffffff) {
+ u_char b = (src & 0xff000000) >> 24;
+
+ src <<= 8;
+ if (b) {
+ if (size < sizeof "255.")
+ goto emsgsize;
+ tp = dst;
+ dst += SPRINTF((dst, "%u", b));
+ if (src != 0L) {
+ *dst++ = '.';
+ *dst = '\0';
+ }
+ size -= (size_t)(dst - tp);
+ }
+ }
+ if (dst == odst) {
+ if (size < sizeof "0.0.0.0")
+ goto emsgsize;
+ strcpy(dst, "0.0.0.0");
+ }
+ return (odst);
+
+ emsgsize:
+ errno = EMSGSIZE;
+ return (NULL);
+}
+
+/*
+ * Weak aliases for applications that use certain private entry points,
+ * and fail to include <arpa/inet.h>.
+ */
+#undef inet_neta
+__weak_reference(__inet_neta, inet_neta);
+
+/*! \file */
diff --git a/lib/libc/inet/inet_netof.c b/lib/libc/inet/inet_netof.c
new file mode 100644
index 000000000000..2335772b68dc
--- /dev/null
+++ b/lib/libc/inet/inet_netof.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)inet_netof.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "port_before.h"
+
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "port_after.h"
+
+/*%
+ * Return the network number from an internet
+ * address; handles class a/b/c network #'s.
+ */
+in_addr_t
+inet_netof(struct in_addr in)
+{
+ in_addr_t i = ntohl(in.s_addr);
+
+ if (IN_CLASSA(i))
+ return (((i)&IN_CLASSA_NET) >> IN_CLASSA_NSHIFT);
+ else if (IN_CLASSB(i))
+ return (((i)&IN_CLASSB_NET) >> IN_CLASSB_NSHIFT);
+ else
+ return (((i)&IN_CLASSC_NET) >> IN_CLASSC_NSHIFT);
+}
+
+/*
+ * Weak aliases for applications that use certain private entry points,
+ * and fail to include <arpa/inet.h>.
+ */
+#undef inet_netof
+__weak_reference(__inet_netof, inet_netof);
+
+/*! \file */
diff --git a/lib/libc/inet/inet_network.c b/lib/libc/inet/inet_network.c
new file mode 100644
index 000000000000..b5b9190ac184
--- /dev/null
+++ b/lib/libc/inet/inet_network.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)inet_network.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <ctype.h>
+
+#include "port_after.h"
+
+/*%
+ * Internet network address interpretation routine.
+ * The library routines call this routine to interpret
+ * network numbers.
+ */
+in_addr_t
+inet_network(const char *cp)
+{
+ in_addr_t val, base, n;
+ char c;
+ in_addr_t parts[4], *pp = parts;
+ int i, digit;
+
+again:
+ val = 0; base = 10; digit = 0;
+ if (*cp == '0')
+ digit = 1, base = 8, cp++;
+ if (*cp == 'x' || *cp == 'X')
+ base = 16, cp++;
+ while ((c = *cp) != 0) {
+ if (isdigit((unsigned char)c)) {
+ if (base == 8U && (c == '8' || c == '9'))
+ return (INADDR_NONE);
+ val = (val * base) + (c - '0');
+ cp++;
+ digit = 1;
+ continue;
+ }
+ if (base == 16U && isxdigit((unsigned char)c)) {
+ val = (val << 4) +
+ (c + 10 - (islower((unsigned char)c) ? 'a' : 'A'));
+ cp++;
+ digit = 1;
+ continue;
+ }
+ break;
+ }
+ if (!digit)
+ return (INADDR_NONE);
+ if (pp >= parts + 4 || val > 0xffU)
+ return (INADDR_NONE);
+ if (*cp == '.') {
+ *pp++ = val, cp++;
+ goto again;
+ }
+ if (*cp && !isspace(*cp&0xff))
+ return (INADDR_NONE);
+ *pp++ = val;
+ n = pp - parts;
+ if (n > 4U)
+ return (INADDR_NONE);
+ for (val = 0, i = 0; i < n; i++) {
+ val <<= 8;
+ val |= parts[i] & 0xff;
+ }
+ return (val);
+}
+
+/*
+ * Weak aliases for applications that use certain private entry points,
+ * and fail to include <arpa/inet.h>.
+ */
+#undef inet_network
+__weak_reference(__inet_network, inet_network);
+
+/*! \file */
diff --git a/lib/libc/inet/inet_ntoa.c b/lib/libc/inet/inet_ntoa.c
new file mode 100644
index 000000000000..d8afd0d57c34
--- /dev/null
+++ b/lib/libc/inet/inet_ntoa.c
@@ -0,0 +1,78 @@
+/*-
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)inet_ntoa.c 8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: inet_ntoa.c,v 1.2 2005/04/27 04:56:21 sra Exp $";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include "port_after.h"
+
+/*%
+ * Convert network-format internet address
+ * to base 256 d.d.d.d representation.
+ */
+/*const*/ char *
+inet_ntoa(struct in_addr in) {
+ static char ret[18];
+
+ strcpy(ret, "[inet_ntoa error]");
+ (void) inet_ntop(AF_INET, &in, ret, sizeof ret);
+ return (ret);
+}
+
+char *
+inet_ntoa_r(struct in_addr in, char *buf, socklen_t size)
+{
+
+ (void) inet_ntop(AF_INET, &in, buf, size);
+ return (buf);
+}
+
+/*
+ * Weak aliases for applications that use certain private entry points,
+ * and fail to include <arpa/inet.h>.
+ */
+#undef inet_ntoa
+__weak_reference(__inet_ntoa, inet_ntoa);
+__weak_reference(__inet_ntoa_r, inet_ntoa_r);
+
+/*! \file */
diff --git a/lib/libc/inet/inet_ntop.c b/lib/libc/inet/inet_ntop.c
new file mode 100644
index 000000000000..22f1db22d185
--- /dev/null
+++ b/lib/libc/inet/inet_ntop.c
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: inet_ntop.c,v 1.5 2005/11/03 22:59:52 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "port_before.h"
+
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "port_after.h"
+
+/*%
+ * WARNING: Don't even consider trying to compile this on a system where
+ * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
+ */
+
+static const char *inet_ntop4(const u_char *src, char *dst, socklen_t size);
+static const char *inet_ntop6(const u_char *src, char *dst, socklen_t size);
+
+/* const char *
+ * inet_ntop(af, src, dst, size)
+ * convert a network format address to presentation format.
+ * return:
+ * pointer to presentation format address (`dst'), or NULL (see errno).
+ * author:
+ * Paul Vixie, 1996.
+ */
+const char *
+inet_ntop(int af, const void * __restrict src, char * __restrict dst,
+ socklen_t size)
+{
+ switch (af) {
+ case AF_INET:
+ return (inet_ntop4(src, dst, size));
+ case AF_INET6:
+ return (inet_ntop6(src, dst, size));
+ default:
+ errno = EAFNOSUPPORT;
+ return (NULL);
+ }
+ /* NOTREACHED */
+}
+
+/* const char *
+ * inet_ntop4(src, dst, size)
+ * format an IPv4 address
+ * return:
+ * `dst' (as a const)
+ * notes:
+ * (1) uses no statics
+ * (2) takes a u_char* not an in_addr as input
+ * author:
+ * Paul Vixie, 1996.
+ */
+static const char *
+inet_ntop4(const u_char *src, char *dst, socklen_t size)
+{
+ static const char fmt[] = "%u.%u.%u.%u";
+ char tmp[sizeof "255.255.255.255"];
+ int l;
+
+ l = snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]);
+ if (l <= 0 || (socklen_t) l >= size) {
+ errno = ENOSPC;
+ return (NULL);
+ }
+ strlcpy(dst, tmp, size);
+ return (dst);
+}
+
+/* const char *
+ * inet_ntop6(src, dst, size)
+ * convert IPv6 binary address into presentation (printable) format
+ * author:
+ * Paul Vixie, 1996.
+ */
+static const char *
+inet_ntop6(const u_char *src, char *dst, socklen_t size)
+{
+ /*
+ * Note that int32_t and int16_t need only be "at least" large enough
+ * to contain a value of the specified size. On some systems, like
+ * Crays, there is no such thing as an integer variable with 16 bits.
+ * Keep this in mind if you think this function should have been coded
+ * to use pointer overlays. All the world's not a VAX.
+ */
+ char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
+ struct { int base, len; } best, cur;
+ u_int words[NS_IN6ADDRSZ / NS_INT16SZ];
+ int i;
+
+ /*
+ * Preprocess:
+ * Copy the input (bytewise) array into a wordwise array.
+ * Find the longest run of 0x00's in src[] for :: shorthanding.
+ */
+ memset(words, '\0', sizeof words);
+ for (i = 0; i < NS_IN6ADDRSZ; i++)
+ words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
+ best.base = -1;
+ best.len = 0;
+ cur.base = -1;
+ cur.len = 0;
+ for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
+ if (words[i] == 0) {
+ if (cur.base == -1)
+ cur.base = i, cur.len = 1;
+ else
+ cur.len++;
+ } else {
+ if (cur.base != -1) {
+ if (best.base == -1 || cur.len > best.len)
+ best = cur;
+ cur.base = -1;
+ }
+ }
+ }
+ if (cur.base != -1) {
+ if (best.base == -1 || cur.len > best.len)
+ best = cur;
+ }
+ if (best.base != -1 && best.len < 2)
+ best.base = -1;
+
+ /*
+ * Format the result.
+ */
+ tp = tmp;
+ for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
+ /* Are we inside the best run of 0x00's? */
+ if (best.base != -1 && i >= best.base &&
+ i < (best.base + best.len)) {
+ if (i == best.base)
+ *tp++ = ':';
+ continue;
+ }
+ /* Are we following an initial run of 0x00s or any real hex? */
+ if (i != 0)
+ *tp++ = ':';
+ /* Is this address an encapsulated IPv4? */
+ if (i == 6 && best.base == 0 && (best.len == 6 ||
+ (best.len == 7 && words[7] != 0x0001) ||
+ (best.len == 5 && words[5] == 0xffff))) {
+ if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp))) {
+ errno = ENOSPC;
+ return (NULL);
+ }
+ tp += strlen(tp);
+ break;
+ }
+ tp += sprintf(tp, "%x", words[i]);
+ }
+ /* Was it a trailing run of 0x00's? */
+ if (best.base != -1 && (best.base + best.len) ==
+ (NS_IN6ADDRSZ / NS_INT16SZ))
+ *tp++ = ':';
+ *tp++ = '\0';
+
+ /*
+ * Check for overflow, copy, and we're done.
+ */
+ if ((socklen_t)(tp - tmp) > size) {
+ errno = ENOSPC;
+ return (NULL);
+ }
+ strcpy(dst, tmp);
+ return (dst);
+}
+
+/*
+ * Weak aliases for applications that use certain private entry points,
+ * and fail to include <arpa/inet.h>.
+ */
+#undef inet_ntop
+__weak_reference(__inet_ntop, inet_ntop);
+
+/*! \file */
diff --git a/lib/libc/inet/inet_pton.c b/lib/libc/inet/inet_pton.c
new file mode 100644
index 000000000000..852a613f110e
--- /dev/null
+++ b/lib/libc/inet/inet_pton.c
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: inet_pton.c,v 1.5 2005/07/28 06:51:47 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "port_before.h"
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include <string.h>
+#include <errno.h>
+#include "port_after.h"
+
+/*%
+ * WARNING: Don't even consider trying to compile this on a system where
+ * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
+ */
+
+static int inet_pton4(const char *src, u_char *dst);
+static int inet_pton6(const char *src, u_char *dst);
+
+/* int
+ * inet_pton(af, src, dst)
+ * convert from presentation format (which usually means ASCII printable)
+ * to network format (which is usually some kind of binary format).
+ * return:
+ * 1 if the address was valid for the specified address family
+ * 0 if the address wasn't valid (`dst' is untouched in this case)
+ * -1 if some other error occurred (`dst' is untouched in this case, too)
+ * author:
+ * Paul Vixie, 1996.
+ */
+int
+inet_pton(int af, const char * __restrict src, void * __restrict dst)
+{
+ switch (af) {
+ case AF_INET:
+ return (inet_pton4(src, dst));
+ case AF_INET6:
+ return (inet_pton6(src, dst));
+ default:
+ errno = EAFNOSUPPORT;
+ return (-1);
+ }
+ /* NOTREACHED */
+}
+
+/* int
+ * inet_pton4(src, dst)
+ * like inet_aton() but without all the hexadecimal and shorthand.
+ * return:
+ * 1 if `src' is a valid dotted quad, else 0.
+ * notice:
+ * does not touch `dst' unless it's returning 1.
+ * author:
+ * Paul Vixie, 1996.
+ */
+static int
+inet_pton4(const char *src, u_char *dst)
+{
+ static const char digits[] = "0123456789";
+ int saw_digit, octets, ch;
+ u_char tmp[NS_INADDRSZ], *tp;
+
+ saw_digit = 0;
+ octets = 0;
+ *(tp = tmp) = 0;
+ while ((ch = *src++) != '\0') {
+ const char *pch;
+
+ if ((pch = strchr(digits, ch)) != NULL) {
+ u_int new = *tp * 10 + (pch - digits);
+
+ if (saw_digit && *tp == 0)
+ return (0);
+ if (new > 255)
+ return (0);
+ *tp = new;
+ if (!saw_digit) {
+ if (++octets > 4)
+ return (0);
+ saw_digit = 1;
+ }
+ } else if (ch == '.' && saw_digit) {
+ if (octets == 4)
+ return (0);
+ *++tp = 0;
+ saw_digit = 0;
+ } else
+ return (0);
+ }
+ if (octets < 4)
+ return (0);
+ memcpy(dst, tmp, NS_INADDRSZ);
+ return (1);
+}
+
+/* int
+ * inet_pton6(src, dst)
+ * convert presentation level address to network order binary form.
+ * return:
+ * 1 if `src' is a valid [RFC1884 2.2] address, else 0.
+ * notice:
+ * (1) does not touch `dst' unless it's returning 1.
+ * (2) :: in a full address is silently ignored.
+ * credit:
+ * inspired by Mark Andrews.
+ * author:
+ * Paul Vixie, 1996.
+ */
+static int
+inet_pton6(const char *src, u_char *dst)
+{
+ static const char xdigits_l[] = "0123456789abcdef",
+ xdigits_u[] = "0123456789ABCDEF";
+ u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
+ const char *xdigits, *curtok;
+ int ch, seen_xdigits;
+ u_int val;
+
+ memset((tp = tmp), '\0', NS_IN6ADDRSZ);
+ endp = tp + NS_IN6ADDRSZ;
+ colonp = NULL;
+ /* Leading :: requires some special handling. */
+ if (*src == ':')
+ if (*++src != ':')
+ return (0);
+ curtok = src;
+ seen_xdigits = 0;
+ val = 0;
+ while ((ch = *src++) != '\0') {
+ const char *pch;
+
+ if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
+ pch = strchr((xdigits = xdigits_u), ch);
+ if (pch != NULL) {
+ val <<= 4;
+ val |= (pch - xdigits);
+ if (++seen_xdigits > 4)
+ return (0);
+ continue;
+ }
+ if (ch == ':') {
+ curtok = src;
+ if (!seen_xdigits) {
+ if (colonp)
+ return (0);
+ colonp = tp;
+ continue;
+ } else if (*src == '\0') {
+ return (0);
+ }
+ if (tp + NS_INT16SZ > endp)
+ return (0);
+ *tp++ = (u_char) (val >> 8) & 0xff;
+ *tp++ = (u_char) val & 0xff;
+ seen_xdigits = 0;
+ val = 0;
+ continue;
+ }
+ if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
+ inet_pton4(curtok, tp) > 0) {
+ tp += NS_INADDRSZ;
+ seen_xdigits = 0;
+ break; /*%< '\\0' was seen by inet_pton4(). */
+ }
+ return (0);
+ }
+ if (seen_xdigits) {
+ if (tp + NS_INT16SZ > endp)
+ return (0);
+ *tp++ = (u_char) (val >> 8) & 0xff;
+ *tp++ = (u_char) val & 0xff;
+ }
+ if (colonp != NULL) {
+ /*
+ * Since some memmove()'s erroneously fail to handle
+ * overlapping regions, we'll do the shift by hand.
+ */
+ const int n = tp - colonp;
+ int i;
+
+ if (tp == endp)
+ return (0);
+ for (i = 1; i <= n; i++) {
+ endp[- i] = colonp[n - i];
+ colonp[n - i] = 0;
+ }
+ tp = endp;
+ }
+ if (tp != endp)
+ return (0);
+ memcpy(dst, tmp, NS_IN6ADDRSZ);
+ return (1);
+}
+
+/*
+ * Weak aliases for applications that use certain private entry points,
+ * and fail to include <arpa/inet.h>.
+ */
+#undef inet_pton
+__weak_reference(__inet_pton, inet_pton);
+
+/*! \file */
diff --git a/lib/libc/inet/nsap_addr.c b/lib/libc/inet/nsap_addr.c
new file mode 100644
index 000000000000..015ab50fd106
--- /dev/null
+++ b/lib/libc/inet/nsap_addr.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: nsap_addr.c,v 1.5 2005/07/28 06:51:48 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "port_before.h"
+
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <resolv.h>
+#include <resolv_mt.h>
+
+#include "port_after.h"
+
+static char
+xtob(int c) {
+ return (c - (((c >= '0') && (c <= '9')) ? '0' : '7'));
+}
+
+u_int
+inet_nsap_addr(const char *ascii, u_char *binary, int maxlen) {
+ u_char c, nib;
+ u_int len = 0;
+
+ if (ascii[0] != '0' || (ascii[1] != 'x' && ascii[1] != 'X'))
+ return (0);
+ ascii += 2;
+
+ while ((c = *ascii++) != '\0' && len < (u_int)maxlen) {
+ if (c == '.' || c == '+' || c == '/')
+ continue;
+ if (!isascii(c))
+ return (0);
+ if (islower(c))
+ c = toupper(c);
+ if (isxdigit(c)) {
+ nib = xtob(c);
+ c = *ascii++;
+ if (c != '\0') {
+ c = toupper(c);
+ if (isxdigit(c)) {
+ *binary++ = (nib << 4) | xtob(c);
+ len++;
+ } else
+ return (0);
+ }
+ else
+ return (0);
+ }
+ else
+ return (0);
+ }
+ return (len);
+}
+
+char *
+inet_nsap_ntoa(int binlen, const u_char *binary, char *ascii) {
+ int nib;
+ int i;
+ char *tmpbuf = inet_nsap_ntoa_tmpbuf;
+ char *start;
+
+ if (ascii)
+ start = ascii;
+ else {
+ ascii = tmpbuf;
+ start = tmpbuf;
+ }
+
+ *ascii++ = '0';
+ *ascii++ = 'x';
+
+ if (binlen > 255)
+ binlen = 255;
+
+ for (i = 0; i < binlen; i++) {
+ nib = *binary >> 4;
+ *ascii++ = nib + (nib < 10 ? '0' : '7');
+ nib = *binary++ & 0x0f;
+ *ascii++ = nib + (nib < 10 ? '0' : '7');
+ if (((i % 2) == 0 && (i + 1) < binlen))
+ *ascii++ = '.';
+ }
+ *ascii = '\0';
+ return (start);
+}
+
+/*
+ * Weak aliases for applications that use certain private entry points,
+ * and fail to include <arpa/inet.h>.
+ */
+#undef inet_nsap_addr
+__weak_reference(__inet_nsap_addr, inet_nsap_addr);
+#undef inet_nsap_ntoa
+__weak_reference(__inet_nsap_ntoa, inet_nsap_ntoa);
+
+/*! \file */
diff --git a/lib/libc/isc/Makefile.inc b/lib/libc/isc/Makefile.inc
new file mode 100644
index 000000000000..aa63ecd8f583
--- /dev/null
+++ b/lib/libc/isc/Makefile.inc
@@ -0,0 +1,6 @@
+# $FreeBSD$
+
+# isc sources
+.PATH: ${LIBC_SRCTOP}/isc
+
+SRCS+= ev_streams.c ev_timers.c
diff --git a/lib/libc/isc/ev_streams.c b/lib/libc/isc/ev_streams.c
new file mode 100644
index 000000000000..1854350ef97b
--- /dev/null
+++ b/lib/libc/isc/ev_streams.c
@@ -0,0 +1,318 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996-1999 by Internet Software Consortium
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* ev_streams.c - implement asynch stream file IO for the eventlib
+ * vix 04mar96 [initial]
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: ev_streams.c,v 1.5 2005/04/27 04:56:36 sra Exp $";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "port_before.h"
+#ifndef _LIBC
+#include "fd_setsize.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/uio.h>
+
+#include <errno.h>
+
+#include <isc/eventlib.h>
+#ifndef _LIBC
+#include <isc/assertions.h>
+#endif
+#include "eventlib_p.h"
+
+#include "port_after.h"
+
+#ifndef _LIBC
+static int copyvec(evStream *str, const struct iovec *iov, int iocnt);
+static void consume(evStream *str, size_t bytes);
+static void done(evContext opaqueCtx, evStream *str);
+static void writable(evContext opaqueCtx, void *uap, int fd, int evmask);
+static void readable(evContext opaqueCtx, void *uap, int fd, int evmask);
+#endif
+
+struct iovec
+evConsIovec(void *buf, size_t cnt) {
+ struct iovec ret;
+
+ memset(&ret, 0xf5, sizeof ret);
+ ret.iov_base = buf;
+ ret.iov_len = cnt;
+ return (ret);
+}
+
+#ifndef _LIBC
+int
+evWrite(evContext opaqueCtx, int fd, const struct iovec *iov, int iocnt,
+ evStreamFunc func, void *uap, evStreamID *id)
+{
+ evContext_p *ctx = opaqueCtx.opaque;
+ evStream *new;
+ int save;
+
+ OKNEW(new);
+ new->func = func;
+ new->uap = uap;
+ new->fd = fd;
+ new->flags = 0;
+ if (evSelectFD(opaqueCtx, fd, EV_WRITE, writable, new, &new->file) < 0)
+ goto free;
+ if (copyvec(new, iov, iocnt) < 0)
+ goto free;
+ new->prevDone = NULL;
+ new->nextDone = NULL;
+ if (ctx->streams != NULL)
+ ctx->streams->prev = new;
+ new->prev = NULL;
+ new->next = ctx->streams;
+ ctx->streams = new;
+ if (id != NULL)
+ id->opaque = new;
+ return (0);
+ free:
+ save = errno;
+ FREE(new);
+ errno = save;
+ return (-1);
+}
+
+int
+evRead(evContext opaqueCtx, int fd, const struct iovec *iov, int iocnt,
+ evStreamFunc func, void *uap, evStreamID *id)
+{
+ evContext_p *ctx = opaqueCtx.opaque;
+ evStream *new;
+ int save;
+
+ OKNEW(new);
+ new->func = func;
+ new->uap = uap;
+ new->fd = fd;
+ new->flags = 0;
+ if (evSelectFD(opaqueCtx, fd, EV_READ, readable, new, &new->file) < 0)
+ goto free;
+ if (copyvec(new, iov, iocnt) < 0)
+ goto free;
+ new->prevDone = NULL;
+ new->nextDone = NULL;
+ if (ctx->streams != NULL)
+ ctx->streams->prev = new;
+ new->prev = NULL;
+ new->next = ctx->streams;
+ ctx->streams = new;
+ if (id)
+ id->opaque = new;
+ return (0);
+ free:
+ save = errno;
+ FREE(new);
+ errno = save;
+ return (-1);
+}
+
+int
+evTimeRW(evContext opaqueCtx, evStreamID id, evTimerID timer) /*ARGSUSED*/ {
+ evStream *str = id.opaque;
+
+ UNUSED(opaqueCtx);
+
+ str->timer = timer;
+ str->flags |= EV_STR_TIMEROK;
+ return (0);
+}
+
+int
+evUntimeRW(evContext opaqueCtx, evStreamID id) /*ARGSUSED*/ {
+ evStream *str = id.opaque;
+
+ UNUSED(opaqueCtx);
+
+ str->flags &= ~EV_STR_TIMEROK;
+ return (0);
+}
+
+int
+evCancelRW(evContext opaqueCtx, evStreamID id) {
+ evContext_p *ctx = opaqueCtx.opaque;
+ evStream *old = id.opaque;
+
+ /*
+ * The streams list is doubly threaded. First, there's ctx->streams
+ * that's used by evDestroy() to find and cancel all streams. Second,
+ * there's ctx->strDone (head) and ctx->strLast (tail) which thread
+ * through the potentially smaller number of "IO completed" streams,
+ * used in evGetNext() to avoid scanning the entire list.
+ */
+
+ /* Unlink from ctx->streams. */
+ if (old->prev != NULL)
+ old->prev->next = old->next;
+ else
+ ctx->streams = old->next;
+ if (old->next != NULL)
+ old->next->prev = old->prev;
+
+ /*
+ * If 'old' is on the ctx->strDone list, remove it. Update
+ * ctx->strLast if necessary.
+ */
+ if (old->prevDone == NULL && old->nextDone == NULL) {
+ /*
+ * Either 'old' is the only item on the done list, or it's
+ * not on the done list. If the former, then we unlink it
+ * from the list. If the latter, we leave the list alone.
+ */
+ if (ctx->strDone == old) {
+ ctx->strDone = NULL;
+ ctx->strLast = NULL;
+ }
+ } else {
+ if (old->prevDone != NULL)
+ old->prevDone->nextDone = old->nextDone;
+ else
+ ctx->strDone = old->nextDone;
+ if (old->nextDone != NULL)
+ old->nextDone->prevDone = old->prevDone;
+ else
+ ctx->strLast = old->prevDone;
+ }
+
+ /* Deallocate the stream. */
+ if (old->file.opaque)
+ evDeselectFD(opaqueCtx, old->file);
+ memput(old->iovOrig, sizeof (struct iovec) * old->iovOrigCount);
+ FREE(old);
+ return (0);
+}
+
+/* Copy a scatter/gather vector and initialize a stream handler's IO. */
+static int
+copyvec(evStream *str, const struct iovec *iov, int iocnt) {
+ int i;
+
+ str->iovOrig = (struct iovec *)memget(sizeof(struct iovec) * iocnt);
+ if (str->iovOrig == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ str->ioTotal = 0;
+ for (i = 0; i < iocnt; i++) {
+ str->iovOrig[i] = iov[i];
+ str->ioTotal += iov[i].iov_len;
+ }
+ str->iovOrigCount = iocnt;
+ str->iovCur = str->iovOrig;
+ str->iovCurCount = str->iovOrigCount;
+ str->ioDone = 0;
+ return (0);
+}
+
+/* Pull off or truncate lead iovec(s). */
+static void
+consume(evStream *str, size_t bytes) {
+ while (bytes > 0U) {
+ if (bytes < (size_t)str->iovCur->iov_len) {
+ str->iovCur->iov_len -= bytes;
+ str->iovCur->iov_base = (void *)
+ ((u_char *)str->iovCur->iov_base + bytes);
+ str->ioDone += bytes;
+ bytes = 0;
+ } else {
+ bytes -= str->iovCur->iov_len;
+ str->ioDone += str->iovCur->iov_len;
+ str->iovCur++;
+ str->iovCurCount--;
+ }
+ }
+}
+
+/* Add a stream to Done list and deselect the FD. */
+static void
+done(evContext opaqueCtx, evStream *str) {
+ evContext_p *ctx = opaqueCtx.opaque;
+
+ if (ctx->strLast != NULL) {
+ str->prevDone = ctx->strLast;
+ ctx->strLast->nextDone = str;
+ ctx->strLast = str;
+ } else {
+ INSIST(ctx->strDone == NULL);
+ ctx->strDone = ctx->strLast = str;
+ }
+ evDeselectFD(opaqueCtx, str->file);
+ str->file.opaque = NULL;
+ /* evDrop() will call evCancelRW() on us. */
+}
+
+/* Dribble out some bytes on the stream. (Called by evDispatch().) */
+static void
+writable(evContext opaqueCtx, void *uap, int fd, int evmask) {
+ evStream *str = uap;
+ int bytes;
+
+ UNUSED(evmask);
+
+ bytes = writev(fd, str->iovCur, str->iovCurCount);
+ if (bytes > 0) {
+ if ((str->flags & EV_STR_TIMEROK) != 0)
+ evTouchIdleTimer(opaqueCtx, str->timer);
+ consume(str, bytes);
+ } else {
+ if (bytes < 0 && errno != EINTR) {
+ str->ioDone = -1;
+ str->ioErrno = errno;
+ }
+ }
+ if (str->ioDone == -1 || str->ioDone == str->ioTotal)
+ done(opaqueCtx, str);
+}
+
+/* Scoop up some bytes from the stream. (Called by evDispatch().) */
+static void
+readable(evContext opaqueCtx, void *uap, int fd, int evmask) {
+ evStream *str = uap;
+ int bytes;
+
+ UNUSED(evmask);
+
+ bytes = readv(fd, str->iovCur, str->iovCurCount);
+ if (bytes > 0) {
+ if ((str->flags & EV_STR_TIMEROK) != 0)
+ evTouchIdleTimer(opaqueCtx, str->timer);
+ consume(str, bytes);
+ } else {
+ if (bytes == 0)
+ str->ioDone = 0;
+ else {
+ if (errno != EINTR) {
+ str->ioDone = -1;
+ str->ioErrno = errno;
+ }
+ }
+ }
+ if (str->ioDone <= 0 || str->ioDone == str->ioTotal)
+ done(opaqueCtx, str);
+}
+#endif
+
+/*! \file */
diff --git a/lib/libc/isc/ev_timers.c b/lib/libc/isc/ev_timers.c
new file mode 100644
index 000000000000..6d08e370fd2a
--- /dev/null
+++ b/lib/libc/isc/ev_timers.c
@@ -0,0 +1,515 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1995-1999 by Internet Software Consortium
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* ev_timers.c - implement timers for the eventlib
+ * vix 09sep95 [initial]
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: ev_timers.c,v 1.6 2005/04/27 04:56:36 sra Exp $";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/* Import. */
+
+#include "port_before.h"
+#ifndef _LIBC
+#include "fd_setsize.h"
+#endif
+
+#include <errno.h>
+
+#ifndef _LIBC
+#include <isc/assertions.h>
+#endif
+#include <isc/eventlib.h>
+#include "eventlib_p.h"
+
+#include "port_after.h"
+
+/* Constants. */
+
+#define MILLION 1000000
+#define BILLION 1000000000
+
+/* Forward. */
+
+#ifdef _LIBC
+static int __evOptMonoTime;
+#else
+static int due_sooner(void *, void *);
+static void set_index(void *, int);
+static void free_timer(void *, void *);
+static void print_timer(void *, void *);
+static void idle_timeout(evContext, void *, struct timespec, struct timespec);
+
+/* Private type. */
+
+typedef struct {
+ evTimerFunc func;
+ void * uap;
+ struct timespec lastTouched;
+ struct timespec max_idle;
+ evTimer * timer;
+} idle_timer;
+#endif
+
+/* Public. */
+
+struct timespec
+evConsTime(time_t sec, long nsec) {
+ struct timespec x;
+
+ x.tv_sec = sec;
+ x.tv_nsec = nsec;
+ return (x);
+}
+
+struct timespec
+evAddTime(struct timespec addend1, struct timespec addend2) {
+ struct timespec x;
+
+ x.tv_sec = addend1.tv_sec + addend2.tv_sec;
+ x.tv_nsec = addend1.tv_nsec + addend2.tv_nsec;
+ if (x.tv_nsec >= BILLION) {
+ x.tv_sec++;
+ x.tv_nsec -= BILLION;
+ }
+ return (x);
+}
+
+struct timespec
+evSubTime(struct timespec minuend, struct timespec subtrahend) {
+ struct timespec x;
+
+ x.tv_sec = minuend.tv_sec - subtrahend.tv_sec;
+ if (minuend.tv_nsec >= subtrahend.tv_nsec)
+ x.tv_nsec = minuend.tv_nsec - subtrahend.tv_nsec;
+ else {
+ x.tv_nsec = BILLION - subtrahend.tv_nsec + minuend.tv_nsec;
+ x.tv_sec--;
+ }
+ return (x);
+}
+
+int
+evCmpTime(struct timespec a, struct timespec b) {
+ long x = a.tv_sec - b.tv_sec;
+
+ if (x == 0L)
+ x = a.tv_nsec - b.tv_nsec;
+ return (x < 0L ? (-1) : x > 0L ? (1) : (0));
+}
+
+struct timespec
+evNowTime(void) {
+ struct timeval now;
+#ifdef CLOCK_REALTIME
+ struct timespec tsnow;
+ int m = CLOCK_REALTIME;
+
+#ifdef CLOCK_MONOTONIC
+ if (__evOptMonoTime)
+ m = CLOCK_MONOTONIC;
+#endif
+ if (clock_gettime(m, &tsnow) == 0)
+ return (tsnow);
+#endif
+ if (gettimeofday(&now, NULL) < 0)
+ return (evConsTime(0, 0));
+ return (evTimeSpec(now));
+}
+
+struct timespec
+evUTCTime(void) {
+ struct timeval now;
+#ifdef CLOCK_REALTIME
+ struct timespec tsnow;
+ if (clock_gettime(CLOCK_REALTIME, &tsnow) == 0)
+ return (tsnow);
+#endif
+ if (gettimeofday(&now, NULL) < 0)
+ return (evConsTime(0, 0));
+ return (evTimeSpec(now));
+}
+
+#ifndef _LIBC
+struct timespec
+evLastEventTime(evContext opaqueCtx) {
+ evContext_p *ctx = opaqueCtx.opaque;
+
+ return (ctx->lastEventTime);
+}
+#endif
+
+struct timespec
+evTimeSpec(struct timeval tv) {
+ struct timespec ts;
+
+ ts.tv_sec = tv.tv_sec;
+ ts.tv_nsec = tv.tv_usec * 1000;
+ return (ts);
+}
+
+#if !defined(USE_KQUEUE) || !defined(_LIBC)
+struct timeval
+evTimeVal(struct timespec ts) {
+ struct timeval tv;
+
+ tv.tv_sec = ts.tv_sec;
+ tv.tv_usec = ts.tv_nsec / 1000;
+ return (tv);
+}
+#endif
+
+#ifndef _LIBC
+int
+evSetTimer(evContext opaqueCtx,
+ evTimerFunc func,
+ void *uap,
+ struct timespec due,
+ struct timespec inter,
+ evTimerID *opaqueID
+) {
+ evContext_p *ctx = opaqueCtx.opaque;
+ evTimer *id;
+
+ evPrintf(ctx, 1,
+"evSetTimer(ctx %p, func %p, uap %p, due %ld.%09ld, inter %ld.%09ld)\n",
+ ctx, func, uap,
+ (long)due.tv_sec, due.tv_nsec,
+ (long)inter.tv_sec, inter.tv_nsec);
+
+#ifdef __hpux
+ /*
+ * tv_sec and tv_nsec are unsigned.
+ */
+ if (due.tv_nsec >= BILLION)
+ EV_ERR(EINVAL);
+
+ if (inter.tv_nsec >= BILLION)
+ EV_ERR(EINVAL);
+#else
+ if (due.tv_sec < 0 || due.tv_nsec < 0 || due.tv_nsec >= BILLION)
+ EV_ERR(EINVAL);
+
+ if (inter.tv_sec < 0 || inter.tv_nsec < 0 || inter.tv_nsec >= BILLION)
+ EV_ERR(EINVAL);
+#endif
+
+ /* due={0,0} is a magic cookie meaning "now." */
+ if (due.tv_sec == (time_t)0 && due.tv_nsec == 0L)
+ due = evNowTime();
+
+ /* Allocate and fill. */
+ OKNEW(id);
+ id->func = func;
+ id->uap = uap;
+ id->due = due;
+ id->inter = inter;
+
+ if (heap_insert(ctx->timers, id) < 0)
+ return (-1);
+
+ /* Remember the ID if the caller provided us a place for it. */
+ if (opaqueID)
+ opaqueID->opaque = id;
+
+ if (ctx->debug > 7) {
+ evPrintf(ctx, 7, "timers after evSetTimer:\n");
+ (void) heap_for_each(ctx->timers, print_timer, (void *)ctx);
+ }
+
+ return (0);
+}
+
+int
+evClearTimer(evContext opaqueCtx, evTimerID id) {
+ evContext_p *ctx = opaqueCtx.opaque;
+ evTimer *del = id.opaque;
+
+ if (ctx->cur != NULL &&
+ ctx->cur->type == Timer &&
+ ctx->cur->u.timer.this == del) {
+ evPrintf(ctx, 8, "deferring delete of timer (executing)\n");
+ /*
+ * Setting the interval to zero ensures that evDrop() will
+ * clean up the timer.
+ */
+ del->inter = evConsTime(0, 0);
+ return (0);
+ }
+
+ if (heap_element(ctx->timers, del->index) != del)
+ EV_ERR(ENOENT);
+
+ if (heap_delete(ctx->timers, del->index) < 0)
+ return (-1);
+ FREE(del);
+
+ if (ctx->debug > 7) {
+ evPrintf(ctx, 7, "timers after evClearTimer:\n");
+ (void) heap_for_each(ctx->timers, print_timer, (void *)ctx);
+ }
+
+ return (0);
+}
+
+int
+evConfigTimer(evContext opaqueCtx,
+ evTimerID id,
+ const char *param,
+ int value
+) {
+ evContext_p *ctx = opaqueCtx.opaque;
+ evTimer *timer = id.opaque;
+ int result=0;
+
+ UNUSED(value);
+
+ if (heap_element(ctx->timers, timer->index) != timer)
+ EV_ERR(ENOENT);
+
+ if (strcmp(param, "rate") == 0)
+ timer->mode |= EV_TMR_RATE;
+ else if (strcmp(param, "interval") == 0)
+ timer->mode &= ~EV_TMR_RATE;
+ else
+ EV_ERR(EINVAL);
+
+ return (result);
+}
+
+int
+evResetTimer(evContext opaqueCtx,
+ evTimerID id,
+ evTimerFunc func,
+ void *uap,
+ struct timespec due,
+ struct timespec inter
+) {
+ evContext_p *ctx = opaqueCtx.opaque;
+ evTimer *timer = id.opaque;
+ struct timespec old_due;
+ int result=0;
+
+ if (heap_element(ctx->timers, timer->index) != timer)
+ EV_ERR(ENOENT);
+
+#ifdef __hpux
+ /*
+ * tv_sec and tv_nsec are unsigned.
+ */
+ if (due.tv_nsec >= BILLION)
+ EV_ERR(EINVAL);
+
+ if (inter.tv_nsec >= BILLION)
+ EV_ERR(EINVAL);
+#else
+ if (due.tv_sec < 0 || due.tv_nsec < 0 || due.tv_nsec >= BILLION)
+ EV_ERR(EINVAL);
+
+ if (inter.tv_sec < 0 || inter.tv_nsec < 0 || inter.tv_nsec >= BILLION)
+ EV_ERR(EINVAL);
+#endif
+
+ old_due = timer->due;
+
+ timer->func = func;
+ timer->uap = uap;
+ timer->due = due;
+ timer->inter = inter;
+
+ switch (evCmpTime(due, old_due)) {
+ case -1:
+ result = heap_increased(ctx->timers, timer->index);
+ break;
+ case 0:
+ result = 0;
+ break;
+ case 1:
+ result = heap_decreased(ctx->timers, timer->index);
+ break;
+ }
+
+ if (ctx->debug > 7) {
+ evPrintf(ctx, 7, "timers after evResetTimer:\n");
+ (void) heap_for_each(ctx->timers, print_timer, (void *)ctx);
+ }
+
+ return (result);
+}
+
+int
+evSetIdleTimer(evContext opaqueCtx,
+ evTimerFunc func,
+ void *uap,
+ struct timespec max_idle,
+ evTimerID *opaqueID
+) {
+ evContext_p *ctx = opaqueCtx.opaque;
+ idle_timer *tt;
+
+ /* Allocate and fill. */
+ OKNEW(tt);
+ tt->func = func;
+ tt->uap = uap;
+ tt->lastTouched = ctx->lastEventTime;
+ tt->max_idle = max_idle;
+
+ if (evSetTimer(opaqueCtx, idle_timeout, tt,
+ evAddTime(ctx->lastEventTime, max_idle),
+ max_idle, opaqueID) < 0) {
+ FREE(tt);
+ return (-1);
+ }
+
+ tt->timer = opaqueID->opaque;
+
+ return (0);
+}
+
+int
+evClearIdleTimer(evContext opaqueCtx, evTimerID id) {
+ evTimer *del = id.opaque;
+ idle_timer *tt = del->uap;
+
+ FREE(tt);
+ return (evClearTimer(opaqueCtx, id));
+}
+
+int
+evResetIdleTimer(evContext opaqueCtx,
+ evTimerID opaqueID,
+ evTimerFunc func,
+ void *uap,
+ struct timespec max_idle
+) {
+ evContext_p *ctx = opaqueCtx.opaque;
+ evTimer *timer = opaqueID.opaque;
+ idle_timer *tt = timer->uap;
+
+ tt->func = func;
+ tt->uap = uap;
+ tt->lastTouched = ctx->lastEventTime;
+ tt->max_idle = max_idle;
+
+ return (evResetTimer(opaqueCtx, opaqueID, idle_timeout, tt,
+ evAddTime(ctx->lastEventTime, max_idle),
+ max_idle));
+}
+
+int
+evTouchIdleTimer(evContext opaqueCtx, evTimerID id) {
+ evContext_p *ctx = opaqueCtx.opaque;
+ evTimer *t = id.opaque;
+ idle_timer *tt = t->uap;
+
+ tt->lastTouched = ctx->lastEventTime;
+
+ return (0);
+}
+
+/* Public to the rest of eventlib. */
+
+heap_context
+evCreateTimers(const evContext_p *ctx) {
+
+ UNUSED(ctx);
+
+ return (heap_new(due_sooner, set_index, 2048));
+}
+
+void
+evDestroyTimers(const evContext_p *ctx) {
+ (void) heap_for_each(ctx->timers, free_timer, NULL);
+ (void) heap_free(ctx->timers);
+}
+
+/* Private. */
+
+static int
+due_sooner(void *a, void *b) {
+ evTimer *a_timer, *b_timer;
+
+ a_timer = a;
+ b_timer = b;
+ return (evCmpTime(a_timer->due, b_timer->due) < 0);
+}
+
+static void
+set_index(void *what, int index) {
+ evTimer *timer;
+
+ timer = what;
+ timer->index = index;
+}
+
+static void
+free_timer(void *what, void *uap) {
+ evTimer *t = what;
+
+ UNUSED(uap);
+
+ FREE(t);
+}
+
+static void
+print_timer(void *what, void *uap) {
+ evTimer *cur = what;
+ evContext_p *ctx = uap;
+
+ cur = what;
+ evPrintf(ctx, 7,
+ " func %p, uap %p, due %ld.%09ld, inter %ld.%09ld\n",
+ cur->func, cur->uap,
+ (long)cur->due.tv_sec, cur->due.tv_nsec,
+ (long)cur->inter.tv_sec, cur->inter.tv_nsec);
+}
+
+static void
+idle_timeout(evContext opaqueCtx,
+ void *uap,
+ struct timespec due,
+ struct timespec inter
+) {
+ evContext_p *ctx = opaqueCtx.opaque;
+ idle_timer *this = uap;
+ struct timespec idle;
+
+ UNUSED(due);
+ UNUSED(inter);
+
+ idle = evSubTime(ctx->lastEventTime, this->lastTouched);
+ if (evCmpTime(idle, this->max_idle) >= 0) {
+ (this->func)(opaqueCtx, this->uap, this->timer->due,
+ this->max_idle);
+ /*
+ * Setting the interval to zero will cause the timer to
+ * be cleaned up in evDrop().
+ */
+ this->timer->inter = evConsTime(0, 0);
+ FREE(this);
+ } else {
+ /* evDrop() will reschedule the timer. */
+ this->timer->inter = evSubTime(this->max_idle, idle);
+ }
+}
+#endif
+
+/*! \file */
diff --git a/lib/libc/isc/eventlib_p.h b/lib/libc/isc/eventlib_p.h
new file mode 100644
index 000000000000..07db816fd0cd
--- /dev/null
+++ b/lib/libc/isc/eventlib_p.h
@@ -0,0 +1,289 @@
+/*
+ * Copyright (c) 2005 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1995-1999 by Internet Software Consortium
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*! \file
+ * \brief private interfaces for eventlib
+ * \author vix 09sep95 [initial]
+ *
+ * $Id: eventlib_p.h,v 1.9 2006/03/09 23:57:56 marka Exp $
+ * $FreeBSD$
+ */
+
+#ifndef _EVENTLIB_P_H
+#define _EVENTLIB_P_H
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/un.h>
+
+#define EVENTLIB_DEBUG 1
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef _LIBC
+#include <isc/list.h>
+#include <isc/heap.h>
+#include <isc/memcluster.h>
+#endif
+
+#define EV_MASK_ALL (EV_READ | EV_WRITE | EV_EXCEPT)
+#define EV_ERR(e) return (errno = (e), -1)
+#define OK(x) if ((x) < 0) EV_ERR(errno); else (void)NULL
+#define OKFREE(x, y) if ((x) < 0) { FREE((y)); EV_ERR(errno); } \
+ else (void)NULL
+
+#define NEW(p) if (((p) = memget(sizeof *(p))) != NULL) \
+ FILL(p); \
+ else \
+ (void)NULL;
+#define OKNEW(p) if (!((p) = memget(sizeof *(p)))) { \
+ errno = ENOMEM; \
+ return (-1); \
+ } else \
+ FILL(p)
+#define FREE(p) memput((p), sizeof *(p))
+
+#if EVENTLIB_DEBUG
+#define FILL(p) memset((p), 0xF5, sizeof *(p))
+#else
+#define FILL(p)
+#endif
+
+#ifdef USE_POLL
+#ifdef HAVE_STROPTS_H
+#include <stropts.h>
+#endif
+#include <poll.h>
+#endif /* USE_POLL */
+
+typedef struct evConn {
+ evConnFunc func;
+ void * uap;
+ int fd;
+ int flags;
+#define EV_CONN_LISTEN 0x0001 /*%< Connection is a listener. */
+#define EV_CONN_SELECTED 0x0002 /*%< evSelectFD(conn->file). */
+#define EV_CONN_BLOCK 0x0004 /*%< Listener fd was blocking. */
+ evFileID file;
+ struct evConn * prev;
+ struct evConn * next;
+} evConn;
+
+#ifndef _LIBC
+typedef struct evAccept {
+ int fd;
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in in;
+#ifndef NO_SOCKADDR_UN
+ struct sockaddr_un un;
+#endif
+ } la;
+ ISC_SOCKLEN_T lalen;
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in in;
+#ifndef NO_SOCKADDR_UN
+ struct sockaddr_un un;
+#endif
+ } ra;
+ ISC_SOCKLEN_T ralen;
+ int ioErrno;
+ evConn * conn;
+ LINK(struct evAccept) link;
+} evAccept;
+
+typedef struct evFile {
+ evFileFunc func;
+ void * uap;
+ int fd;
+ int eventmask;
+ int preemptive;
+ struct evFile * prev;
+ struct evFile * next;
+ struct evFile * fdprev;
+ struct evFile * fdnext;
+} evFile;
+
+typedef struct evStream {
+ evStreamFunc func;
+ void * uap;
+ evFileID file;
+ evTimerID timer;
+ int flags;
+#define EV_STR_TIMEROK 0x0001 /*%< IFF timer valid. */
+ int fd;
+ struct iovec * iovOrig;
+ int iovOrigCount;
+ struct iovec * iovCur;
+ int iovCurCount;
+ int ioTotal;
+ int ioDone;
+ int ioErrno;
+ struct evStream *prevDone, *nextDone;
+ struct evStream *prev, *next;
+} evStream;
+
+typedef struct evTimer {
+ evTimerFunc func;
+ void * uap;
+ struct timespec due, inter;
+ int index;
+ int mode;
+#define EV_TMR_RATE 1
+} evTimer;
+
+typedef struct evWait {
+ evWaitFunc func;
+ void * uap;
+ const void * tag;
+ struct evWait * next;
+} evWait;
+
+typedef struct evWaitList {
+ evWait * first;
+ evWait * last;
+ struct evWaitList * prev;
+ struct evWaitList * next;
+} evWaitList;
+
+typedef struct evEvent_p {
+ enum { Accept, File, Stream, Timer, Wait, Free, Null } type;
+ union {
+ struct { evAccept *this; } accept;
+ struct { evFile *this; int eventmask; } file;
+ struct { evStream *this; } stream;
+ struct { evTimer *this; } timer;
+ struct { evWait *this; } wait;
+ struct { struct evEvent_p *next; } free;
+ struct { const void *placeholder; } null;
+ } u;
+} evEvent_p;
+#endif
+
+#ifdef USE_POLL
+typedef struct {
+ void *ctx; /* pointer to the evContext_p */
+ uint32_t type; /* READ, WRITE, EXCEPT, nonblk */
+ uint32_t result; /* 1 => revents, 0 => events */
+} __evEmulMask;
+
+#define emulMaskInit(ctx, field, ev, lastnext) \
+ ctx->field.ctx = ctx; \
+ ctx->field.type = ev; \
+ ctx->field.result = lastnext;
+
+extern short *__fd_eventfield(int fd, __evEmulMask *maskp);
+extern short __poll_event(__evEmulMask *maskp);
+extern void __fd_clr(int fd, __evEmulMask *maskp);
+extern void __fd_set(int fd, __evEmulMask *maskp);
+
+#undef FD_ZERO
+#define FD_ZERO(maskp)
+
+#undef FD_SET
+#define FD_SET(fd, maskp) \
+ __fd_set(fd, maskp)
+
+#undef FD_CLR
+#define FD_CLR(fd, maskp) \
+ __fd_clr(fd, maskp)
+
+#undef FD_ISSET
+#define FD_ISSET(fd, maskp) \
+ ((*__fd_eventfield(fd, maskp) & __poll_event(maskp)) != 0)
+
+#endif /* USE_POLL */
+
+#ifndef _LIBC
+typedef struct {
+ /* Global. */
+ const evEvent_p *cur;
+ /* Debugging. */
+ int debug;
+ FILE *output;
+ /* Connections. */
+ evConn *conns;
+ LIST(evAccept) accepts;
+ /* Files. */
+ evFile *files, *fdNext;
+#ifndef USE_POLL
+ fd_set rdLast, rdNext;
+ fd_set wrLast, wrNext;
+ fd_set exLast, exNext;
+ fd_set nonblockBefore;
+ int fdMax, fdCount, highestFD;
+ evFile *fdTable[FD_SETSIZE];
+#else
+ struct pollfd *pollfds; /* Allocated as needed */
+ evFile **fdTable; /* Ditto */
+ int maxnfds; /* # elements in above */
+ int firstfd; /* First active fd */
+ int fdMax; /* Last active fd */
+ int fdCount; /* # fd:s with I/O */
+ int highestFD; /* max fd allowed by OS */
+ __evEmulMask rdLast, rdNext;
+ __evEmulMask wrLast, wrNext;
+ __evEmulMask exLast, exNext;
+ __evEmulMask nonblockBefore;
+#endif /* USE_POLL */
+#ifdef EVENTLIB_TIME_CHECKS
+ struct timespec lastSelectTime;
+ int lastFdCount;
+#endif
+ /* Streams. */
+ evStream *streams;
+ evStream *strDone, *strLast;
+ /* Timers. */
+ struct timespec lastEventTime;
+ heap_context timers;
+ /* Waits. */
+ evWaitList *waitLists;
+ evWaitList waitDone;
+} evContext_p;
+
+/* eventlib.c */
+#define evPrintf __evPrintf
+void evPrintf(const evContext_p *ctx, int level, const char *fmt, ...)
+ ISC_FORMAT_PRINTF(3, 4);
+
+#ifdef USE_POLL
+extern int evPollfdRealloc(evContext_p *ctx, int pollfd_chunk_size, int fd);
+#endif /* USE_POLL */
+
+/* ev_timers.c */
+#define evCreateTimers __evCreateTimers
+heap_context evCreateTimers(const evContext_p *);
+#define evDestroyTimers __evDestroyTimers
+void evDestroyTimers(const evContext_p *);
+
+/* ev_waits.c */
+#define evFreeWait __evFreeWait
+evWait *evFreeWait(evContext_p *ctx, evWait *old);
+#endif
+
+/* Global options */
+#ifndef _LIBC
+extern int __evOptMonoTime;
+#endif
+
+#endif /*_EVENTLIB_P_H*/
diff --git a/lib/libc/libc.ldscript b/lib/libc/libc.ldscript
new file mode 100644
index 000000000000..02e4d962a318
--- /dev/null
+++ b/lib/libc/libc.ldscript
@@ -0,0 +1,2 @@
+/* $FreeBSD$ */
+GROUP ( @@SHLIB@@ @@LIBDIR@@/libc_nonshared.a @@LIBDIR@@/libssp_nonshared.a )
diff --git a/lib/libc/libc_nossp.ldscript b/lib/libc/libc_nossp.ldscript
new file mode 100644
index 000000000000..c610cc21e018
--- /dev/null
+++ b/lib/libc/libc_nossp.ldscript
@@ -0,0 +1,2 @@
+/* $FreeBSD$ */
+GROUP ( @@SHLIB@@ @@LIBDIR@@/libc_nonshared.a )
diff --git a/lib/libc/locale/DESIGN.xlocale b/lib/libc/locale/DESIGN.xlocale
new file mode 100644
index 000000000000..5d998d32314d
--- /dev/null
+++ b/lib/libc/locale/DESIGN.xlocale
@@ -0,0 +1,159 @@
+$FreeBSD$
+
+Design of xlocale
+=================
+
+The xlocale APIs come from Darwin, although a subset is now part of POSIX 2008.
+They fall into two broad categories:
+
+- Manipulation of per-thread locales (POSIX)
+- Locale-aware functions taking an explicit locale argument (Darwin)
+
+This document describes the implementation of these APIs for FreeBSD.
+
+Goals
+-----
+
+The overall goal of this implementation is to be compatible with the Darwin
+version. Additionally, it should include minimal changes to the existing
+locale code. A lot of the existing locale code originates with 4BSD or earlier
+and has had over a decade of testing. Replacing this code, unless absolutely
+necessary, gives us the potential for more bugs without much benefit.
+
+With this in mind, various libc-private functions have been modified to take a
+locale_t parameter. This causes a compiler error if they are accidentally
+called without a locale. This approach was taken, rather than adding _l
+variants of these functions, to make it harder for accidental uses of the
+global-locale versions to slip in.
+
+Locale Objects
+--------------
+
+A locale is encapsulated in a `locale_t`, which is an opaque type: a pointer to
+a `struct _xlocale`. The name `_xlocale` is unfortunate, as it does not fit
+well with existing conventions, but is used because this is the name the Darwin
+implementation gives to this structure and so may be used by existing (bad) code.
+
+This structure should include all of the information corresponding to a locale.
+A locale_t is almost immutable after creation. There are no functions that modify it,
+and it can therefore be used without locking. It is the responsibility of the
+caller to ensure that a locale is not deallocated during a call that uses it.
+
+Each locale contains a number of components, one for each of the categories
+supported by `setlocale()`. These are likewise immutable after creation. This
+differs from the Darwin implementation, which includes a deprecated
+`setinvalidrune()` function that can modify the rune locale.
+
+The exception to these mutability rules is a set of `mbstate_t` flags stored
+with each locale. These are used by various functions that previously had a
+static local `mbstate_t` variable.
+
+The components are reference counted, and so can be aliased between locale
+objects. This makes copying locales very cheap.
+
+The Global Locale
+-----------------
+
+All locales and locale components are reference counted. The global locale,
+however, is special. It, and all of its components, are static and so no
+malloc() memory is required when using a single locale.
+
+This means that threads using the global locale are subject to the same
+constraints as with the pre-xlocale libc. Calls to any locale-aware functions
+in threads using the global locale, while modifying the global locale, have
+undefined behaviour.
+
+Because of this, we have to ensure that we always copy the components of the
+global locale, rather than alias them.
+
+It would be cleaner to simply remove the special treatment of the global locale
+and have a locale_t lazily allocated for the global context. This would cost a
+little more `malloc()` memory, so is not done in the initial version.
+
+Caching
+-------
+
+The existing locale implementation included several ad-hoc caching layers.
+None of these were thread safe. Caching is only really of use for supporting
+the pattern where the locale is briefly changed to something and then changed
+back.
+
+The current xlocale implementation removes the caching entirely. This pattern
+is not one that should be encouraged. If you need to make some calls with a
+modified locale, then you should use the _l suffix versions of the calls,
+rather than switch the global locale. If you do need to temporarily switch the
+locale and then switch it back, `uselocale()` provides a way of doing this very
+easily: It returns the old locale, which can then be passed to a subsequent
+call to `uselocale()` to restore it, without the need to load any locale data
+from the disk.
+
+If, in the future, it is determined that caching is beneficial, it can be added
+quite easily in xlocale.c. Given, however, that any locale-aware call is going
+to be a preparation for presenting data to the user, and so is invariably going
+to be part of an I/O operation, this seems like a case of premature
+optimisation.
+
+localeconv
+----------
+
+The `localeconv()` function is an exception to the immutable-after-creation
+rule. In the classic implementation, this function returns a pointer to some
+global storage, which is initialised with the data from the current locale.
+This is not possible in a multithreaded environment, with multiple locales.
+
+Instead, each locale contains a `struct lconv` that is lazily initialised on
+calls to `localeconv()`. This is not protected by any locking, however this is
+still safe on any machine where word-sized stores are atomic: two concurrent
+calls will write the same data into the structure.
+
+Explicit Locale Calls
+---------------------
+
+A large number of functions have been modified to take an explicit `locale_t`
+parameter. The old APIs are then reimplemented with a call to `__get_locale()`
+to supply the `locale_t` parameter. This is in line with the Darwin public
+APIs, but also simplifies the modifications to these functions. The
+`__get_locale()` function is now the only way to access the current locale
+within libc. All of the old globals have gone, so there is now a linker error
+if any functions attempt to use them.
+
+The ctype.h functions are a little different. These are not implemented in
+terms of their locale-aware versions, for performance reasons. Each of these
+is implemented as a short inline function.
+
+Differences to Darwin APIs
+--------------------------
+
+`strtoq_l()` and `strtouq_l() `are not provided. These are extensions to
+deprecated functions - we should not be encouraging people to use deprecated
+interfaces.
+
+Locale Placeholders
+-------------------
+
+The pointer values 0 and -1 have special meanings as `locale_t` values. Any
+public function that accepts a `locale_t` parameter must use the `FIX_LOCALE()`
+macro on it before using it. For efficiency, this can be emitted in functions
+which *only* use their locale parameter as an argument to another public
+function, as the callee will do the `FIX_LOCALE()` itself.
+
+Potential Improvements
+----------------------
+
+Currently, the current rune set is accessed via a function call. This makes it
+fairly expensive to use any of the ctype.h functions. We could improve this
+quite a lot by storing the rune locale data in a __thread-qualified variable.
+
+Several of the existing FreeBSD locale-aware functions appear to be wrong. For
+example, most of the `strto*()` family should probably use `digittoint_l()`,
+but instead they assume ASCII. These will break if using a character encoding
+that does not put numbers and the letters A-F in the same location as ASCII.
+Some functions, like `strcoll()` only work on single-byte encodings. No
+attempt has been made to fix existing limitations in the libc functions other
+than to add support for xlocale.
+
+Intuitively, setting a thread-local locale should ensure that all locale-aware
+functions can be used safely from that thread. In fact, this is not the case
+in either this implementation or the Darwin one. You must call `duplocale()`
+or `newlocale()` before calling `uselocale()`. This is a bit ugly, and it
+would be better if libc ensure that every thread had its own locale object.
diff --git a/lib/libc/locale/Makefile.inc b/lib/libc/locale/Makefile.inc
new file mode 100644
index 000000000000..a8daa1ff284e
--- /dev/null
+++ b/lib/libc/locale/Makefile.inc
@@ -0,0 +1,90 @@
+# from @(#)Makefile.inc 8.1 (Berkeley) 6/4/93
+# $FreeBSD$
+
+# locale sources
+.PATH: ${LIBC_SRCTOP}/${LIBC_ARCH}/locale ${LIBC_SRCTOP}/locale
+
+SRCS+= ascii.c big5.c btowc.c collate.c collcmp.c euc.c fix_grouping.c \
+ gb18030.c gb2312.c gbk.c ctype.c isctype.c iswctype.c \
+ ldpart.c lmessages.c lmonetary.c lnumeric.c localeconv.c mblen.c \
+ mbrlen.c \
+ mbrtowc.c mbsinit.c mbsnrtowcs.c \
+ mbsrtowcs.c mbtowc.c mbstowcs.c \
+ mskanji.c nextwctype.c nl_langinfo.c nomacros.c none.c rpmatch.c \
+ rune.c \
+ runetype.c setlocale.c setrunelocale.c \
+ table.c \
+ tolower.c toupper.c utf8.c wcrtomb.c wcsnrtombs.c \
+ wcsrtombs.c wcsftime.c \
+ wcstof.c wcstod.c \
+ wcstoimax.c wcstol.c wcstold.c wcstoll.c \
+ wcstombs.c \
+ wcstoul.c wcstoull.c wcstoumax.c wctob.c wctomb.c wctrans.c wctype.c \
+ wcwidth.c\
+ xlocale.c
+
+.if ${MK_ICONV} != "no"
+SRCS+= c16rtomb_iconv.c c32rtomb_iconv.c mbrtoc16_iconv.c mbrtoc32_iconv.c
+.else
+SRCS+= c16rtomb.c c32rtomb.c mbrtoc16.c mbrtoc32.c
+.endif
+
+SYM_MAPS+=${LIBC_SRCTOP}/locale/Symbol.map
+
+MAN+= btowc.3 \
+ ctype_l.3 \
+ ctype.3 digittoint.3 isalnum.3 isalpha.3 isascii.3 isblank.3 iscntrl.3 \
+ isdigit.3 isgraph.3 isideogram.3 islower.3 isphonogram.3 isprint.3 \
+ ispunct.3 isrune.3 isspace.3 isspecial.3 \
+ isupper.3 iswalnum.3 iswalnum_l.3 isxdigit.3 \
+ localeconv.3 mblen.3 mbrlen.3 \
+ mbrtowc.3 \
+ mbsinit.3 \
+ mbsrtowcs.3 mbstowcs.3 mbtowc.3 multibyte.3 \
+ nextwctype.3 nl_langinfo.3 rpmatch.3 \
+ setlocale.3 toascii.3 tolower.3 toupper.3 towlower.3 towupper.3 \
+ wcsftime.3 \
+ wcrtomb.3 \
+ wcsrtombs.3 wcstod.3 wcstol.3 wcstombs.3 wctomb.3 \
+ wctrans.3 wctype.3 wcwidth.3 \
+ duplocale.3 freelocale.3 newlocale.3 querylocale.3 uselocale.3 xlocale.3
+
+MAN+= big5.5 euc.5 gb18030.5 gb2312.5 gbk.5 mskanji.5 utf8.5
+
+MLINKS+=btowc.3 wctob.3
+MLINKS+=isdigit.3 isnumber.3
+MLINKS+=isgraph.3 isgraph_l.3
+MLINKS+=islower.3 islower_l.3
+MLINKS+=ispunct.3 ispunct_l.3
+MLINKS+=isspace.3 isspace_l.3
+MLINKS+=nl_langinfo.3 nl_langinfo_l.3
+MLINKS+=iswalnum.3 iswalpha.3 iswalnum.3 iswascii.3 iswalnum.3 iswblank.3 \
+ iswalnum.3 iswcntrl.3 iswalnum.3 iswdigit.3 iswalnum.3 iswgraph.3 \
+ iswalnum.3 iswhexnumber.3 \
+ iswalnum.3 iswideogram.3 iswalnum.3 iswlower.3 iswalnum.3 iswnumber.3 \
+ iswalnum.3 iswphonogram.3 iswalnum.3 iswprint.3 iswalnum.3 iswpunct.3 \
+ iswalnum.3 iswrune.3 iswalnum.3 iswspace.3 iswalnum.3 iswspecial.3 \
+ iswalnum.3 iswupper.3 iswalnum.3 iswxdigit.3
+MLINKS+=iswalnum_l.3 iswalpha_l.3 iswalnum_l.3 iswcntrl_l.3 \
+ iswalnum_l.3 iswctype_l.3 iswalnum_l.3 iswdigit_l.3 \
+ iswalnum_l.3 iswgraph_l.3 iswalnum_l.3 iswlower_l.3 \
+ iswalnum_l.3 iswprint_l.3 iswalnum_l.3 iswpunct_l.3 \
+ iswalnum_l.3 iswspace_l.3 iswalnum_l.3 iswupper_l.3 \
+ iswalnum_l.3 iswxdigit_l.3 iswalnum_l.3 towlower_l.3 \
+ iswalnum_l.3 towupper_l.3 iswalnum_l.3 wctype_l.3 \
+ iswalnum_l.3 iswblank_l.3 iswalnum_l.3 iswhexnumber_l.3 \
+ iswalnum_l.3 iswideogram_l.3 iswalnum_l.3 iswnumber_l.3 \
+ iswalnum_l.3 iswphonogram_l.3 iswalnum_l.3 iswrune_l.3 \
+ iswalnum_l.3 iswspecial_l.3 iswalnum_l.3 nextwctype_l.3 \
+ iswalnum_l.3 towctrans_l.3 iswalnum_l.3 wctrans_l.3
+MLINKS+=isxdigit.3 ishexnumber.3
+MLINKS+=localeconv.3 localeconv_l.3
+MLINKS+=mbrtowc.3 mbrtoc16.3 mbrtowc.3 mbrtoc32.3
+MLINKS+=mbsrtowcs.3 mbsnrtowcs.3
+MLINKS+=wcrtomb.3 c16rtomb.3 wcrtomb.3 c32rtomb.3
+MLINKS+=wcsrtombs.3 wcsnrtombs.3
+MLINKS+=wcstod.3 wcstof.3 wcstod.3 wcstold.3
+MLINKS+=wcstol.3 wcstoul.3 wcstol.3 wcstoll.3 wcstol.3 wcstoull.3 \
+ wcstol.3 wcstoimax.3 wcstol.3 wcstoumax.3
+MLINKS+=wctrans.3 towctrans.3
+MLINKS+=wctype.3 iswctype.3
diff --git a/lib/libc/locale/Symbol.map b/lib/libc/locale/Symbol.map
new file mode 100644
index 000000000000..b2f2a35f2fe4
--- /dev/null
+++ b/lib/libc/locale/Symbol.map
@@ -0,0 +1,217 @@
+/*
+ * $FreeBSD$
+ */
+
+FBSD_1.0 {
+ btowc;
+ digittoint;
+ isalnum;
+ isalpha;
+ isascii;
+ isblank;
+ iscntrl;
+ isdigit;
+ isgraph;
+ ishexnumber;
+ isideogram;
+ islower;
+ isnumber;
+ isphonogram;
+ isprint;
+ ispunct;
+ isrune;
+ isspace;
+ isspecial;
+ isupper;
+ isxdigit;
+ toascii;
+ tolower;
+ toupper;
+ iswalnum;
+ iswalpha;
+ iswascii;
+ iswblank;
+ iswcntrl;
+ iswdigit;
+ iswgraph;
+ iswhexnumber;
+ iswideogram;
+ iswlower;
+ iswnumber;
+ iswphonogram;
+ iswprint;
+ iswpunct;
+ iswrune;
+ iswspace;
+ iswspecial;
+ iswupper;
+ iswxdigit;
+ towlower;
+ towupper;
+ localeconv;
+ mblen;
+ mbrlen;
+ mbrtowc;
+ mbsinit;
+ mbsnrtowcs;
+ mbsrtowcs;
+ mbstowcs;
+ mbtowc;
+ nextwctype;
+ nl_langinfo;
+ __maskrune;
+ __sbmaskrune;
+ __istype;
+ __sbistype;
+ __isctype;
+ __toupper;
+ __sbtoupper;
+ __tolower;
+ __sbtolower;
+ __wcwidth;
+ __mb_cur_max;
+ __mb_sb_limit;
+ rpmatch;
+ ___runetype;
+ setlocale;
+ _DefaultRuneLocale;
+ _CurrentRuneLocale;
+ ___tolower;
+ ___toupper;
+ wcrtomb;
+ wcsftime;
+ wcsnrtombs;
+ wcsrtombs;
+ wcstod;
+ wcstof;
+ wcstoimax;
+ wcstol;
+ wcstold;
+ wcstoll;
+ wcstombs;
+ wcstoul;
+ wcstoull;
+ wcstoumax;
+ wctob;
+ wctomb;
+ towctrans;
+ wctrans;
+ iswctype;
+ wctype;
+ wcwidth;
+};
+
+FBSD_1.3 {
+ newlocale;
+ duplocale;
+ freelocale;
+ querylocale;
+ uselocale;
+ __getCurrentRuneLocale;
+ btowc_l;
+ localeconv_l;
+ mblen_l;
+ mbrlen_l;
+ mbrtowc_l;
+ mbsinit_l;
+ mbsnrtowcs_l;
+ mbsrtowcs_l;
+ mbstowcs_l;
+ mbtowc_l;
+ nl_langinfo_l;
+ strcoll_l;
+ strfmon_l;
+ strftime_l;
+ strptime_l;
+ strxfrm_l;
+ wcrtomb_l;
+ wcscoll_l;
+ wcsnrtombs_l;
+ wcsrtombs_l;
+ wcstombs_l;
+ wcsxfrm_l;
+ wctob_l;
+ wctomb_l;
+ ___tolower_l;
+ ___toupper_l;
+ ___runetype_l;
+ digittoint_l;
+ isalnum_l;
+ isalpha_l;
+ isblank_l;
+ iscntrl_l;
+ isdigit_l;
+ isgraph_l;
+ ishexnumber_l;
+ isideogram_l;
+ islower_l;
+ isnumber_l;
+ isphonogram_l;
+ isprint_l;
+ ispunct_l;
+ isrune_l;
+ isspace_l;
+ isspecial_l;
+ isupper_l;
+ isxdigit_l;
+ tolower_l;
+ toupper_l;
+ iswalnum_l;
+ iswalpha_l;
+ iswblank_l;
+ iswcntrl_l;
+ iswdigit_l;
+ iswgraph_l;
+ iswhexnumber_l;
+ iswideogram_l;
+ iswlower_l;
+ iswnumber_l;
+ iswphonogram_l;
+ iswprint_l;
+ iswpunct_l;
+ iswrune_l;
+ iswspace_l;
+ iswspecial_l;
+ iswupper_l;
+ iswxdigit_l;
+ towlower_l;
+ towupper_l;
+ iswctype_l;
+ wctype_l;
+ nextwctype_l;
+ ___mb_cur_max;
+ ___mb_cur_max_l;
+ towctrans_l;
+ wctrans_l;
+ wcsftime_l;
+ wcstod_l;
+ wcstof_l;
+ wcstoimax_l;
+ wcstol_l;
+ wcstold_l;
+ wcstoll_l;
+ wcstoul_l;
+ wcstoull_l;
+ wcstoumax_l;
+ __sbistype_l;
+ __maskrune_l;
+ __sbmaskrune_l;
+ __istype_l;
+ __runes_for_locale;
+ _ThreadRuneLocale;
+ c16rtomb;
+ c16rtomb_l;
+ c32rtomb;
+ c32rtomb_l;
+ mbrtoc16;
+ mbrtoc16_l;
+ mbrtoc32;
+ mbrtoc32_l;
+};
+
+FBSDprivate_1.0 {
+ _PathLocale;
+ __detect_path_locale;
+ __collate_load_error;
+ __collate_range_cmp;
+};
diff --git a/lib/libc/locale/ascii.c b/lib/libc/locale/ascii.c
new file mode 100644
index 000000000000..a70d71a7b88c
--- /dev/null
+++ b/lib/libc/locale/ascii.c
@@ -0,0 +1,194 @@
+/*-
+ * Copyright (c) 2002-2004 Tim J. Robbins. All rights reserved.
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Borman at Krystal Technologies.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <limits.h>
+#include <runetype.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include "mblocal.h"
+
+static size_t _ascii_mbrtowc(wchar_t * __restrict, const char * __restrict,
+ size_t, mbstate_t * __restrict);
+static int _ascii_mbsinit(const mbstate_t *);
+static size_t _ascii_mbsnrtowcs(wchar_t * __restrict dst,
+ const char ** __restrict src, size_t nms, size_t len,
+ mbstate_t * __restrict ps __unused);
+static size_t _ascii_wcrtomb(char * __restrict, wchar_t,
+ mbstate_t * __restrict);
+static size_t _ascii_wcsnrtombs(char * __restrict, const wchar_t ** __restrict,
+ size_t, size_t, mbstate_t * __restrict);
+
+int
+_ascii_init(struct xlocale_ctype *l,_RuneLocale *rl)
+{
+
+ l->__mbrtowc = _ascii_mbrtowc;
+ l->__mbsinit = _ascii_mbsinit;
+ l->__mbsnrtowcs = _ascii_mbsnrtowcs;
+ l->__wcrtomb = _ascii_wcrtomb;
+ l->__wcsnrtombs = _ascii_wcsnrtombs;
+ l->runes = rl;
+ l->__mb_cur_max = 1;
+ l->__mb_sb_limit = 128;
+ return(0);
+}
+
+static int
+_ascii_mbsinit(const mbstate_t *ps __unused)
+{
+
+ /*
+ * Encoding is not state dependent - we are always in the
+ * initial state.
+ */
+ return (1);
+}
+
+static size_t
+_ascii_mbrtowc(wchar_t * __restrict pwc, const char * __restrict s, size_t n,
+ mbstate_t * __restrict ps __unused)
+{
+
+ if (s == NULL)
+ /* Reset to initial shift state (no-op) */
+ return (0);
+ if (n == 0)
+ /* Incomplete multibyte sequence */
+ return ((size_t)-2);
+ if (*s & 0x80) {
+ errno = EILSEQ;
+ return ((size_t)-1);
+ }
+ if (pwc != NULL)
+ *pwc = (unsigned char)*s;
+ return (*s == '\0' ? 0 : 1);
+}
+
+static size_t
+_ascii_wcrtomb(char * __restrict s, wchar_t wc,
+ mbstate_t * __restrict ps __unused)
+{
+
+ if (s == NULL)
+ /* Reset to initial shift state (no-op) */
+ return (1);
+ if (wc < 0 || wc > 127) {
+ errno = EILSEQ;
+ return ((size_t)-1);
+ }
+ *s = (unsigned char)wc;
+ return (1);
+}
+
+static size_t
+_ascii_mbsnrtowcs(wchar_t * __restrict dst, const char ** __restrict src,
+ size_t nms, size_t len, mbstate_t * __restrict ps __unused)
+{
+ const char *s;
+ size_t nchr;
+
+ if (dst == NULL) {
+ for (s = *src; nms > 0 && *s != '\0'; s++, nms--) {
+ if (*s & 0x80) {
+ errno = EILSEQ;
+ return ((size_t)-1);
+ }
+ }
+ return (s - *src);
+ }
+
+ s = *src;
+ nchr = 0;
+ while (len-- > 0 && nms-- > 0) {
+ if (*s & 0x80) {
+ *src = s;
+ errno = EILSEQ;
+ return ((size_t)-1);
+ }
+ if ((*dst++ = (unsigned char)*s++) == L'\0') {
+ *src = NULL;
+ return (nchr);
+ }
+ nchr++;
+ }
+ *src = s;
+ return (nchr);
+}
+
+static size_t
+_ascii_wcsnrtombs(char * __restrict dst, const wchar_t ** __restrict src,
+ size_t nwc, size_t len, mbstate_t * __restrict ps __unused)
+{
+ const wchar_t *s;
+ size_t nchr;
+
+ if (dst == NULL) {
+ for (s = *src; nwc > 0 && *s != L'\0'; s++, nwc--) {
+ if (*s < 0 || *s > 127) {
+ errno = EILSEQ;
+ return ((size_t)-1);
+ }
+ }
+ return (s - *src);
+ }
+
+ s = *src;
+ nchr = 0;
+ while (len-- > 0 && nwc-- > 0) {
+ if (*s < 0 || *s > 127) {
+ *src = s;
+ errno = EILSEQ;
+ return ((size_t)-1);
+ }
+ if ((*dst++ = *s++) == '\0') {
+ *src = NULL;
+ return (nchr);
+ }
+ nchr++;
+ }
+ *src = s;
+ return (nchr);
+}
+
diff --git a/lib/libc/locale/big5.5 b/lib/libc/locale/big5.5
new file mode 100644
index 000000000000..13d0c7b64e53
--- /dev/null
+++ b/lib/libc/locale/big5.5
@@ -0,0 +1,51 @@
+.\" Copyright (c) 2002, 2003 Tim J. Robbins
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd August 7, 2003
+.Dt BIG5 5
+.Os
+.Sh NAME
+.Nm big5
+.Nd
+.Dq "Big Five"
+encoding for Traditional Chinese text
+.Sh SYNOPSIS
+.Nm ENCODING
+.Qq BIG5
+.Sh DESCRIPTION
+.Dq Big Five
+is the de facto standard for encoding Traditional Chinese text.
+Each character is represented by either one or two bytes.
+Characters from the
+.Tn ASCII
+character set are represented as single bytes in the range 0x00 - 0x7F.
+Traditional Chinese characters are represented by two bytes:
+the first in the range 0xA1 - 0xFE, the second in the range
+0x40 - 0xFE.
+.Sh SEE ALSO
+.Xr euc 5 ,
+.Xr gb18030 5 ,
+.Xr utf8 5
diff --git a/lib/libc/locale/big5.c b/lib/libc/locale/big5.c
new file mode 100644
index 000000000000..c1f94d39c7da
--- /dev/null
+++ b/lib/libc/locale/big5.c
@@ -0,0 +1,200 @@
+/*-
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
+ * Copyright 2010 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2002-2004 Tim J. Robbins. All rights reserved.
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Borman at Krystal Technologies.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)big5.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <errno.h>
+#include <runetype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include "mblocal.h"
+
+extern int __mb_sb_limit;
+
+static size_t _BIG5_mbrtowc(wchar_t * __restrict, const char * __restrict,
+ size_t, mbstate_t * __restrict);
+static int _BIG5_mbsinit(const mbstate_t *);
+static size_t _BIG5_wcrtomb(char * __restrict, wchar_t,
+ mbstate_t * __restrict);
+static size_t _BIG5_mbsnrtowcs(wchar_t * __restrict,
+ const char ** __restrict, size_t, size_t,
+ mbstate_t * __restrict);
+static size_t _BIG5_wcsnrtombs(char * __restrict,
+ const wchar_t ** __restrict, size_t, size_t,
+ mbstate_t * __restrict);
+
+typedef struct {
+ wchar_t ch;
+} _BIG5State;
+
+int
+_BIG5_init(struct xlocale_ctype *l, _RuneLocale *rl)
+{
+
+ l->__mbrtowc = _BIG5_mbrtowc;
+ l->__wcrtomb = _BIG5_wcrtomb;
+ l->__mbsnrtowcs = _BIG5_mbsnrtowcs;
+ l->__wcsnrtombs = _BIG5_wcsnrtombs;
+ l->__mbsinit = _BIG5_mbsinit;
+ l->runes = rl;
+ l->__mb_cur_max = 2;
+ l->__mb_sb_limit = 128;
+ return (0);
+}
+
+static int
+_BIG5_mbsinit(const mbstate_t *ps)
+{
+
+ return (ps == NULL || ((const _BIG5State *)ps)->ch == 0);
+}
+
+static __inline int
+_big5_check(u_int c)
+{
+
+ c &= 0xff;
+ return ((c >= 0xa1 && c <= 0xfe) ? 2 : 1);
+}
+
+static size_t
+_BIG5_mbrtowc(wchar_t * __restrict pwc, const char * __restrict s, size_t n,
+ mbstate_t * __restrict ps)
+{
+ _BIG5State *bs;
+ wchar_t wc;
+ size_t len;
+
+ bs = (_BIG5State *)ps;
+
+ if ((bs->ch & ~0xFF) != 0) {
+ /* Bad conversion state. */
+ errno = EINVAL;
+ return ((size_t)-1);
+ }
+
+ if (s == NULL) {
+ s = "";
+ n = 1;
+ pwc = NULL;
+ }
+
+ if (n == 0)
+ /* Incomplete multibyte sequence */
+ return ((size_t)-2);
+
+ if (bs->ch != 0) {
+ if (*s == '\0') {
+ errno = EILSEQ;
+ return ((size_t)-1);
+ }
+ wc = (bs->ch << 8) | (*s & 0xFF);
+ if (pwc != NULL)
+ *pwc = wc;
+ bs->ch = 0;
+ return (1);
+ }
+
+ len = (size_t)_big5_check(*s);
+ wc = *s++ & 0xff;
+ if (len == 2) {
+ if (n < 2) {
+ /* Incomplete multibyte sequence */
+ bs->ch = wc;
+ return ((size_t)-2);
+ }
+ if (*s == '\0') {
+ errno = EILSEQ;
+ return ((size_t)-1);
+ }
+ wc = (wc << 8) | (*s++ & 0xff);
+ if (pwc != NULL)
+ *pwc = wc;
+ return (2);
+ } else {
+ if (pwc != NULL)
+ *pwc = wc;
+ return (wc == L'\0' ? 0 : 1);
+ }
+}
+
+static size_t
+_BIG5_wcrtomb(char * __restrict s, wchar_t wc, mbstate_t * __restrict ps)
+{
+ _BIG5State *bs;
+
+ bs = (_BIG5State *)ps;
+
+ if (bs->ch != 0) {
+ errno = EINVAL;
+ return ((size_t)-1);
+ }
+
+ if (s == NULL)
+ /* Reset to initial shift state (no-op) */
+ return (1);
+ if (wc & 0x8000) {
+ *s++ = (wc >> 8) & 0xff;
+ *s = wc & 0xff;
+ return (2);
+ }
+ *s = wc & 0xff;
+ return (1);
+}
+
+static size_t
+_BIG5_mbsnrtowcs(wchar_t * __restrict dst, const char ** __restrict src,
+ size_t nms, size_t len, mbstate_t * __restrict ps)
+{
+ return (__mbsnrtowcs_std(dst, src, nms, len, ps, _BIG5_mbrtowc));
+}
+
+static size_t
+_BIG5_wcsnrtombs(char * __restrict dst, const wchar_t ** __restrict src,
+ size_t nwc, size_t len, mbstate_t * __restrict ps)
+{
+ return (__wcsnrtombs_std(dst, src, nwc, len, ps, _BIG5_wcrtomb));
+}
diff --git a/lib/libc/locale/btowc.3 b/lib/libc/locale/btowc.3
new file mode 100644
index 000000000000..2d8cb493351b
--- /dev/null
+++ b/lib/libc/locale/btowc.3
@@ -0,0 +1,88 @@
+.\" Copyright (c) 2002 Tim J. Robbins
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd February 13, 2012
+.Dt BTOWC 3
+.Os
+.Sh NAME
+.Nm btowc ,
+.Nm wctob
+.Nd "convert between wide and single-byte characters"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In wchar.h
+.Ft wint_t
+.Fn btowc "int c"
+.Ft int
+.Fn wctob "wint_t c"
+.In wchar.h
+.In xlocale.h
+.Ft wint_t
+.Fn btowc_l "int c" "locale_t loc"
+.Ft int
+.Fn wctob_l "wint_t c" "locale_t loc"
+.Sh DESCRIPTION
+The
+.Fn btowc
+function converts a single-byte character into a corresponding wide character.
+If the character is
+.Dv EOF
+or not valid in the initial shift state,
+.Fn btowc
+returns
+.Dv WEOF .
+.Pp
+The
+.Fn wctob
+function converts a wide character into a corresponding single-byte character.
+If the wide character is
+.Dv WEOF
+or not able to be represented as a single byte in the initial shift state,
+.Fn wctob
+returns
+.Dv EOF .
+.Pp
+The _l-suffixed versions take an explicit locale argument, while the
+non-suffixed versions use the current global or per-thread locale.
+.Sh SEE ALSO
+.Xr mbrtowc 3 ,
+.Xr multibyte 3 ,
+.Xr wcrtomb 3
+.Sh STANDARDS
+The
+.Fn btowc
+and
+.Fn wctob
+functions conform to
+.St -p1003.1-2001 .
+.Sh HISTORY
+The
+.Fn btowc
+and
+.Fn wctob
+functions first appeared in
+.Fx 5.0 .
diff --git a/lib/libc/locale/btowc.c b/lib/libc/locale/btowc.c
new file mode 100644
index 000000000000..72507bc857e1
--- /dev/null
+++ b/lib/libc/locale/btowc.c
@@ -0,0 +1,64 @@
+/*-
+ * Copyright (c) 2002, 2003 Tim J. Robbins.
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 <stdio.h>
+#include <wchar.h>
+#include "mblocal.h"
+
+wint_t
+btowc_l(int c, locale_t l)
+{
+ static const mbstate_t initial;
+ mbstate_t mbs = initial;
+ char cc;
+ wchar_t wc;
+ FIX_LOCALE(l);
+
+ if (c == EOF)
+ return (WEOF);
+ /*
+ * We expect mbrtowc() to return 0 or 1, hence the check for n > 1
+ * which detects error return values as well as "impossible" byte
+ * counts.
+ */
+ cc = (char)c;
+ if (XLOCALE_CTYPE(l)->__mbrtowc(&wc, &cc, 1, &mbs) > 1)
+ return (WEOF);
+ return (wc);
+}
+wint_t
+btowc(int c)
+{
+ return btowc_l(c, __get_locale());
+}
diff --git a/lib/libc/locale/c16rtomb.c b/lib/libc/locale/c16rtomb.c
new file mode 100644
index 000000000000..8bad98267b69
--- /dev/null
+++ b/lib/libc/locale/c16rtomb.c
@@ -0,0 +1,81 @@
+/*-
+ * Copyright (c) 2013 Ed Schouten <ed@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <uchar.h>
+#include "xlocale_private.h"
+
+typedef struct {
+ char16_t lead_surrogate;
+ mbstate_t c32_mbstate;
+} _Char16State;
+
+size_t
+c16rtomb_l(char * __restrict s, char16_t c16, mbstate_t * __restrict ps,
+ locale_t locale)
+{
+ _Char16State *cs;
+ char32_t c32;
+
+ FIX_LOCALE(locale);
+ if (ps == NULL)
+ ps = &locale->c16rtomb;
+ cs = (_Char16State *)ps;
+
+ /* If s is a null pointer, the value of parameter c16 is ignored. */
+ if (s == NULL) {
+ c32 = 0;
+ } else if (cs->lead_surrogate >= 0xd800 &&
+ cs->lead_surrogate <= 0xdbff) {
+ /* We should see a trail surrogate now. */
+ if (c16 < 0xdc00 || c16 > 0xdfff) {
+ errno = EILSEQ;
+ return ((size_t)-1);
+ }
+ c32 = 0x10000 + ((cs->lead_surrogate & 0x3ff) << 10 |
+ (c16 & 0x3ff));
+ } else if (c16 >= 0xd800 && c16 <= 0xdbff) {
+ /* Store lead surrogate for next invocation. */
+ cs->lead_surrogate = c16;
+ return (0);
+ } else {
+ /* Regular character. */
+ c32 = c16;
+ }
+ cs->lead_surrogate = 0;
+
+ return (c32rtomb_l(s, c32, &cs->c32_mbstate, locale));
+}
+
+size_t
+c16rtomb(char * __restrict s, char16_t c16, mbstate_t * __restrict ps)
+{
+
+ return (c16rtomb_l(s, c16, ps, __get_locale()));
+}
diff --git a/lib/libc/locale/c16rtomb_iconv.c b/lib/libc/locale/c16rtomb_iconv.c
new file mode 100644
index 000000000000..86bd9dab2a52
--- /dev/null
+++ b/lib/libc/locale/c16rtomb_iconv.c
@@ -0,0 +1,8 @@
+/* $FreeBSD$ */
+#define charXX_t char16_t
+#define cXXrtomb c16rtomb
+#define cXXrtomb_l c16rtomb_l
+#define SRCBUF_LEN 2
+#define UTF_XX_INTERNAL "UTF-16-INTERNAL"
+
+#include "cXXrtomb_iconv.h"
diff --git a/lib/libc/locale/c32rtomb.c b/lib/libc/locale/c32rtomb.c
new file mode 100644
index 000000000000..c5f008fdea69
--- /dev/null
+++ b/lib/libc/locale/c32rtomb.c
@@ -0,0 +1,59 @@
+/*-
+ * Copyright (c) 2013 Ed Schouten <ed@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <uchar.h>
+#include <wchar.h>
+#include "xlocale_private.h"
+
+size_t
+c32rtomb_l(char * __restrict s, char32_t c32, mbstate_t * __restrict ps,
+ locale_t locale)
+{
+
+ /* Unicode Standard 5.0, D90: ill-formed characters. */
+ if ((c32 >= 0xd800 && c32 <= 0xdfff) || c32 > 0x10ffff) {
+ errno = EILSEQ;
+ return ((size_t)-1);
+ }
+
+ FIX_LOCALE(locale);
+ if (ps == NULL)
+ ps = &locale->c32rtomb;
+
+ /* Assume wchar_t uses UTF-32. */
+ return (wcrtomb_l(s, c32, ps, locale));
+}
+
+size_t
+c32rtomb(char * __restrict s, char32_t c32, mbstate_t * __restrict ps)
+{
+
+ return (c32rtomb_l(s, c32, ps, __get_locale()));
+}
diff --git a/lib/libc/locale/c32rtomb_iconv.c b/lib/libc/locale/c32rtomb_iconv.c
new file mode 100644
index 000000000000..dabbfd7f7ab4
--- /dev/null
+++ b/lib/libc/locale/c32rtomb_iconv.c
@@ -0,0 +1,8 @@
+/* $FreeBSD$ */
+#define charXX_t char32_t
+#define cXXrtomb c32rtomb
+#define cXXrtomb_l c32rtomb_l
+#define SRCBUF_LEN 1
+#define UTF_XX_INTERNAL "UTF-32-INTERNAL"
+
+#include "cXXrtomb_iconv.h"
diff --git a/lib/libc/locale/cXXrtomb_iconv.h b/lib/libc/locale/cXXrtomb_iconv.h
new file mode 100644
index 000000000000..d6e7ce0ae3ac
--- /dev/null
+++ b/lib/libc/locale/cXXrtomb_iconv.h
@@ -0,0 +1,115 @@
+/*-
+ * Copyright (c) 2013 Ed Schouten <ed@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/queue.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <langinfo.h>
+#include <uchar.h>
+
+#include "../iconv/citrus_hash.h"
+#include "../iconv/citrus_module.h"
+#include "../iconv/citrus_iconv.h"
+#include "xlocale_private.h"
+
+typedef struct {
+ bool initialized;
+ struct _citrus_iconv iconv;
+ union {
+ charXX_t widechar[SRCBUF_LEN];
+ char bytes[sizeof(charXX_t) * SRCBUF_LEN];
+ } srcbuf;
+ size_t srcbuf_len;
+} _ConversionState;
+_Static_assert(sizeof(_ConversionState) <= sizeof(mbstate_t),
+ "Size of _ConversionState must not exceed mbstate_t's size.");
+
+size_t
+cXXrtomb_l(char * __restrict s, charXX_t c, mbstate_t * __restrict ps,
+ locale_t locale)
+{
+ _ConversionState *cs;
+ struct _citrus_iconv *handle;
+ char *src, *dst;
+ size_t srcleft, dstleft, invlen;
+ int err;
+
+ FIX_LOCALE(locale);
+ if (ps == NULL)
+ ps = &locale->cXXrtomb;
+ cs = (_ConversionState *)ps;
+ handle = &cs->iconv;
+
+ /* Reinitialize mbstate_t. */
+ if (s == NULL || !cs->initialized) {
+ if (_citrus_iconv_open(&handle, UTF_XX_INTERNAL,
+ nl_langinfo_l(CODESET, locale)) != 0) {
+ cs->initialized = false;
+ errno = EINVAL;
+ return (-1);
+ }
+ handle->cv_shared->ci_discard_ilseq = true;
+ handle->cv_shared->ci_hooks = NULL;
+ cs->srcbuf_len = 0;
+ cs->initialized = true;
+ if (s == NULL)
+ return (1);
+ }
+
+ assert(cs->srcbuf_len < sizeof(cs->srcbuf.widechar) / sizeof(charXX_t));
+ cs->srcbuf.widechar[cs->srcbuf_len++] = c;
+
+ /* Perform conversion. */
+ src = cs->srcbuf.bytes;
+ srcleft = cs->srcbuf_len * sizeof(charXX_t);
+ dst = s;
+ dstleft = MB_CUR_MAX_L(locale);
+ err = _citrus_iconv_convert(handle, &src, &srcleft, &dst, &dstleft,
+ 0, &invlen);
+
+ /* Character is part of a surrogate pair. We need more input. */
+ if (err == EINVAL)
+ return (0);
+ cs->srcbuf_len = 0;
+
+ /* Illegal sequence. */
+ if (dst == s) {
+ errno = EILSEQ;
+ return ((size_t)-1);
+ }
+ return (dst - s);
+}
+
+size_t
+cXXrtomb(char * __restrict s, charXX_t c, mbstate_t * __restrict ps)
+{
+
+ return (cXXrtomb_l(s, c, ps, __get_locale()));
+}
diff --git a/lib/libc/locale/collate.c b/lib/libc/locale/collate.c
new file mode 100644
index 000000000000..045b847bd29a
--- /dev/null
+++ b/lib/libc/locale/collate.c
@@ -0,0 +1,709 @@
+/*-
+ * Copyright 2014 Garrett D'Amore <garrett@damore.org>
+ * Copyright 2010 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 1995 Alex Tatmanjants <alex@elvisti.kiev.ua>
+ * at Electronni Visti IA, Kiev, Ukraine.
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Adapted to xlocale by John Marino <draco@marino.st>
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include "un-namespace.h"
+
+#include "endian.h"
+#include "collate.h"
+#include "setlocale.h"
+#include "ldpart.h"
+#include "libc_private.h"
+
+struct xlocale_collate __xlocale_global_collate = {
+ {{0}, "C"}, 1, 0, 0, 0
+};
+
+struct xlocale_collate __xlocale_C_collate = {
+ {{0}, "C"}, 1, 0, 0, 0
+};
+
+static int
+__collate_load_tables_l(const char *encoding, struct xlocale_collate *table);
+
+static void
+destruct_collate(void *t)
+{
+ struct xlocale_collate *table = t;
+ if (table->map && (table->maplen > 0)) {
+ (void) munmap(table->map, table->maplen);
+ }
+ free(t);
+}
+
+void *
+__collate_load(const char *encoding, __unused locale_t unused)
+{
+ if (strcmp(encoding, "C") == 0 || strcmp(encoding, "POSIX") == 0) {
+ return &__xlocale_C_collate;
+ }
+ struct xlocale_collate *table = calloc(sizeof(struct xlocale_collate), 1);
+ table->header.header.destructor = destruct_collate;
+ // FIXME: Make sure that _LDP_CACHE is never returned. We should be doing
+ // the caching outside of this section
+ if (__collate_load_tables_l(encoding, table) != _LDP_LOADED) {
+ xlocale_release(table);
+ return NULL;
+ }
+ return table;
+}
+
+/**
+ * Load the collation tables for the specified encoding into the global table.
+ */
+int
+__collate_load_tables(const char *encoding)
+{
+
+ return (__collate_load_tables_l(encoding, &__xlocale_global_collate));
+}
+
+int
+__collate_load_tables_l(const char *encoding, struct xlocale_collate *table)
+{
+ int i, chains, z;
+ char *buf;
+ char *TMP;
+ char *map;
+ collate_info_t *info;
+ struct stat sbuf;
+ int fd;
+
+ table->__collate_load_error = 1;
+
+ /* 'encoding' must be already checked. */
+ if (strcmp(encoding, "C") == 0 || strcmp(encoding, "POSIX") == 0) {
+ return (_LDP_CACHE);
+ }
+
+ asprintf(&buf, "%s/%s/LC_COLLATE", _PathLocale, encoding);
+ if (buf == NULL)
+ return (_LDP_ERROR);
+
+ if ((fd = _open(buf, O_RDONLY)) < 0) {
+ free(buf);
+ return (_LDP_ERROR);
+ }
+ free(buf);
+ if (_fstat(fd, &sbuf) < 0) {
+ (void) _close(fd);
+ return (_LDP_ERROR);
+ }
+ if (sbuf.st_size < (COLLATE_STR_LEN + sizeof (info))) {
+ (void) _close(fd);
+ errno = EINVAL;
+ return (_LDP_ERROR);
+ }
+ map = mmap(NULL, sbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ (void) _close(fd);
+ if ((TMP = map) == NULL) {
+ return (_LDP_ERROR);
+ }
+
+ if (strncmp(TMP, COLLATE_VERSION, COLLATE_STR_LEN) != 0) {
+ (void) munmap(map, sbuf.st_size);
+ errno = EINVAL;
+ return (_LDP_ERROR);
+ }
+ TMP += COLLATE_STR_LEN;
+
+ info = (void *)TMP;
+ TMP += sizeof (*info);
+
+ if ((info->directive_count < 1) ||
+ (info->directive_count >= COLL_WEIGHTS_MAX) ||
+ ((chains = BSWAP(info->chain_count)) < 0)) {
+ (void) munmap(map, sbuf.st_size);
+ errno = EINVAL;
+ return (_LDP_ERROR);
+ }
+
+ i = (sizeof (collate_char_t) * (UCHAR_MAX + 1)) +
+ (sizeof (collate_chain_t) * chains) +
+ (sizeof (collate_large_t) * BSWAP(info->large_count));
+ for (z = 0; z < info->directive_count; z++) {
+ i += sizeof (collate_subst_t) * BSWAP(info->subst_count[z]);
+ }
+ if (i != (sbuf.st_size - (TMP - map))) {
+ (void) munmap(map, sbuf.st_size);
+ errno = EINVAL;
+ return (_LDP_ERROR);
+ }
+
+ table->info = info;
+ table->char_pri_table = (void *)TMP;
+ TMP += sizeof (collate_char_t) * (UCHAR_MAX + 1);
+
+ for (z = 0; z < info->directive_count; z++) {
+ if (BSWAP(info->subst_count[z]) > 0) {
+ table->subst_table[z] = (void *)TMP;
+ TMP += BSWAP(info->subst_count[z]) * sizeof (collate_subst_t);
+ } else {
+ table->subst_table[z] = NULL;
+ }
+ }
+
+ if (chains > 0) {
+ table->chain_pri_table = (void *)TMP;
+ TMP += chains * sizeof (collate_chain_t);
+ } else
+ table->chain_pri_table = NULL;
+ if (BSWAP(info->large_count) > 0)
+ table->large_pri_table = (void *)TMP;
+ else
+ table->large_pri_table = NULL;
+
+ table->__collate_load_error = 0;
+ return (_LDP_LOADED);
+}
+
+static const int32_t *
+substsearch(struct xlocale_collate *table, const wchar_t key, int pass)
+{
+ const collate_subst_t *p;
+ int n = BSWAP(table->info->subst_count[pass]);
+
+ if (n == 0)
+ return (NULL);
+
+ if (pass >= table->info->directive_count)
+ return (NULL);
+
+ if (!(key & COLLATE_SUBST_PRIORITY))
+ return (NULL);
+
+ p = table->subst_table[pass] + (key & ~COLLATE_SUBST_PRIORITY);
+ assert(BSWAP(p->key) == key);
+
+ return (p->pri);
+}
+
+static collate_chain_t *
+chainsearch(struct xlocale_collate *table, const wchar_t *key, int *len)
+{
+ int low = 0;
+ int high = BSWAP(table->info->chain_count) - 1;
+ int next, compar, l;
+ collate_chain_t *p;
+ collate_chain_t *tab = table->chain_pri_table;
+
+ if (high < 0)
+ return (NULL);
+
+ while (low <= high) {
+ next = (low + high) / 2;
+ p = tab + next;
+ compar = *key - le16toh(*p->str);
+ if (compar == 0) {
+ l = wcsnlen(p->str, COLLATE_STR_LEN);
+ compar = wcsncmp(key, p->str, l);
+ if (compar == 0) {
+ *len = l;
+ return (p);
+ }
+ }
+ if (compar > 0)
+ low = next + 1;
+ else
+ high = next - 1;
+ }
+ return (NULL);
+}
+
+static collate_large_t *
+largesearch(struct xlocale_collate *table, const wchar_t key)
+{
+ int low = 0;
+ int high = BSWAP(table->info->large_count) - 1;
+ int next, compar;
+ collate_large_t *p;
+ collate_large_t *tab = table->large_pri_table;
+
+ if (high < 0)
+ return (NULL);
+
+ while (low <= high) {
+ next = (low + high) / 2;
+ p = tab + next;
+ compar = key - BSWAP(p->val);
+ if (compar == 0)
+ return (p);
+ if (compar > 0)
+ low = next + 1;
+ else
+ high = next - 1;
+ }
+ return (NULL);
+}
+
+void
+_collate_lookup(struct xlocale_collate *table, const wchar_t *t, int *len,
+ int *pri, int which, const int **state)
+{
+ collate_chain_t *p2;
+ collate_large_t *match;
+ int p, l;
+ const int *sptr;
+
+ /*
+ * If this is the "last" pass for the UNDEFINED, then
+ * we just return the priority itself.
+ */
+ if (which >= table->info->directive_count) {
+ *pri = *t;
+ *len = 1;
+ *state = NULL;
+ return;
+ }
+
+ /*
+ * If we have remaining substitution data from a previous
+ * call, consume it first.
+ */
+ if ((sptr = *state) != NULL) {
+ *pri = *sptr;
+ sptr++;
+ if ((sptr == *state) || (sptr == NULL))
+ *state = NULL;
+ else
+ *state = sptr;
+ *len = 0;
+ return;
+ }
+
+ /* No active substitutions */
+ *len = 1;
+
+ /*
+ * Check for composites such as diphthongs that collate as a
+ * single element (aka chains or collating-elements).
+ */
+ if (((p2 = chainsearch(table, t, &l)) != NULL) &&
+ ((p = p2->pri[which]) >= 0)) {
+
+ *len = l;
+ *pri = p;
+
+ } else if (*t <= UCHAR_MAX) {
+
+ /*
+ * Character is a small (8-bit) character.
+ * We just look these up directly for speed.
+ */
+ *pri = BSWAP(table->char_pri_table[*t].pri[which]);
+
+ } else if ((BSWAP(table->info->large_count) > 0) &&
+ ((match = largesearch(table, *t)) != NULL)) {
+
+ /*
+ * Character was found in the extended table.
+ */
+ *pri = BSWAP(match->pri.pri[which]);
+
+ } else {
+ /*
+ * Character lacks a specific definition.
+ */
+ if (table->info->directive[which] & DIRECTIVE_UNDEFINED) {
+ /* Mask off sign bit to prevent ordering confusion. */
+ *pri = (*t & COLLATE_MAX_PRIORITY);
+ } else {
+ *pri = BSWAP(table->info->undef_pri[which]);
+ }
+ /* No substitutions for undefined characters! */
+ return;
+ }
+
+ /*
+ * Try substituting (expanding) the character. We are
+ * currently doing this *after* the chain compression. I
+ * think it should not matter, but this way might be slightly
+ * faster.
+ *
+ * We do this after the priority search, as this will help us
+ * to identify a single key value. In order for this to work,
+ * its important that the priority assigned to a given element
+ * to be substituted be unique for that level. The localedef
+ * code ensures this for us.
+ */
+ if ((sptr = substsearch(table, *pri, which)) != NULL) {
+ if ((*pri = BSWAP(*sptr)) > 0) {
+ sptr++;
+ *state = BSWAP(*sptr) ? sptr : NULL;
+ }
+ }
+
+}
+
+/*
+ * This is the meaty part of wcsxfrm & strxfrm. Note that it does
+ * NOT NULL terminate. That is left to the caller.
+ */
+size_t
+_collate_wxfrm(struct xlocale_collate *table, const wchar_t *src, wchar_t *xf,
+ size_t room)
+{
+ int pri;
+ int len;
+ const wchar_t *t;
+ wchar_t *tr = NULL;
+ int direc;
+ int pass;
+ const int32_t *state;
+ size_t want = 0;
+ size_t need = 0;
+ int ndir = table->info->directive_count;
+
+ assert(src);
+
+ for (pass = 0; pass <= ndir; pass++) {
+
+ state = NULL;
+
+ if (pass != 0) {
+ /* insert level separator from the previous pass */
+ if (room) {
+ *xf++ = 1;
+ room--;
+ }
+ want++;
+ }
+
+ /* special pass for undefined */
+ if (pass == ndir) {
+ direc = DIRECTIVE_FORWARD | DIRECTIVE_UNDEFINED;
+ } else {
+ direc = table->info->directive[pass];
+ }
+
+ t = src;
+
+ if (direc & DIRECTIVE_BACKWARD) {
+ wchar_t *bp, *fp, c;
+ free(tr);
+ if ((tr = wcsdup(t)) == NULL) {
+ errno = ENOMEM;
+ goto fail;
+ }
+ bp = tr;
+ fp = tr + wcslen(tr) - 1;
+ while (bp < fp) {
+ c = *bp;
+ *bp++ = *fp;
+ *fp-- = c;
+ }
+ t = (const wchar_t *)tr;
+ }
+
+ if (direc & DIRECTIVE_POSITION) {
+ while (*t || state) {
+ _collate_lookup(table, t, &len, &pri, pass, &state);
+ t += len;
+ if (pri <= 0) {
+ if (pri < 0) {
+ errno = EINVAL;
+ goto fail;
+ }
+ state = NULL;
+ pri = COLLATE_MAX_PRIORITY;
+ }
+ if (room) {
+ *xf++ = pri;
+ room--;
+ }
+ want++;
+ need = want;
+ }
+ } else {
+ while (*t || state) {
+ _collate_lookup(table, t, &len, &pri, pass, &state);
+ t += len;
+ if (pri <= 0) {
+ if (pri < 0) {
+ errno = EINVAL;
+ goto fail;
+ }
+ state = NULL;
+ continue;
+ }
+ if (room) {
+ *xf++ = pri;
+ room--;
+ }
+ want++;
+ need = want;
+ }
+ }
+ }
+ free(tr);
+ return (need);
+
+fail:
+ free(tr);
+ return ((size_t)(-1));
+}
+
+/*
+ * In the non-POSIX case, we transform each character into a string of
+ * characters representing the character's priority. Since char is usually
+ * signed, we are limited by 7 bits per byte. To avoid zero, we need to add
+ * XFRM_OFFSET, so we can't use a full 7 bits. For simplicity, we choose 6
+ * bits per byte.
+ *
+ * It turns out that we sometimes have real priorities that are
+ * 31-bits wide. (But: be careful using priorities where the high
+ * order bit is set -- i.e. the priority is negative. The sort order
+ * may be surprising!)
+ *
+ * TODO: This would be a good area to optimize somewhat. It turns out
+ * that real prioririties *except for the last UNDEFINED pass* are generally
+ * very small. We need the localedef code to precalculate the max
+ * priority for us, and ideally also give us a mask, and then we could
+ * severely limit what we expand to.
+ */
+#define XFRM_BYTES 6
+#define XFRM_OFFSET ('0') /* make all printable characters */
+#define XFRM_SHIFT 6
+#define XFRM_MASK ((1 << XFRM_SHIFT) - 1)
+#define XFRM_SEP ('.') /* chosen to be less than XFRM_OFFSET */
+
+static int
+xfrm(struct xlocale_collate *table, unsigned char *p, int pri, int pass)
+{
+ /* we use unsigned to ensure zero fill on right shift */
+ uint32_t val = BSWAP((uint32_t)table->info->pri_count[pass]);
+ int nc = 0;
+
+ while (val) {
+ *p = (pri & XFRM_MASK) + XFRM_OFFSET;
+ pri >>= XFRM_SHIFT;
+ val >>= XFRM_SHIFT;
+ p++;
+ nc++;
+ }
+ return (nc);
+}
+
+size_t
+_collate_sxfrm(struct xlocale_collate *table, const wchar_t *src, char *xf,
+ size_t room)
+{
+ int pri;
+ int len;
+ const wchar_t *t;
+ wchar_t *tr = NULL;
+ int direc;
+ int pass;
+ const int32_t *state;
+ size_t want = 0;
+ size_t need = 0;
+ int b;
+ uint8_t buf[XFRM_BYTES];
+ int ndir = table->info->directive_count;
+
+ assert(src);
+
+ for (pass = 0; pass <= ndir; pass++) {
+
+ state = NULL;
+
+ if (pass != 0) {
+ /* insert level separator from the previous pass */
+ if (room) {
+ *xf++ = XFRM_SEP;
+ room--;
+ }
+ want++;
+ }
+
+ /* special pass for undefined */
+ if (pass == ndir) {
+ direc = DIRECTIVE_FORWARD | DIRECTIVE_UNDEFINED;
+ } else {
+ direc = table->info->directive[pass];
+ }
+
+ t = src;
+
+ if (direc & DIRECTIVE_BACKWARD) {
+ wchar_t *bp, *fp, c;
+ free(tr);
+ if ((tr = wcsdup(t)) == NULL) {
+ errno = ENOMEM;
+ goto fail;
+ }
+ bp = tr;
+ fp = tr + wcslen(tr) - 1;
+ while (bp < fp) {
+ c = *bp;
+ *bp++ = *fp;
+ *fp-- = c;
+ }
+ t = (const wchar_t *)tr;
+ }
+
+ if (direc & DIRECTIVE_POSITION) {
+ while (*t || state) {
+
+ _collate_lookup(table, t, &len, &pri, pass, &state);
+ t += len;
+ if (pri <= 0) {
+ if (pri < 0) {
+ errno = EINVAL;
+ goto fail;
+ }
+ state = NULL;
+ pri = COLLATE_MAX_PRIORITY;
+ }
+
+ b = xfrm(table, buf, pri, pass);
+ want += b;
+ if (room) {
+ while (b) {
+ b--;
+ if (room) {
+ *xf++ = buf[b];
+ room--;
+ }
+ }
+ }
+ need = want;
+ }
+ } else {
+ while (*t || state) {
+ _collate_lookup(table, t, &len, &pri, pass, &state);
+ t += len;
+ if (pri <= 0) {
+ if (pri < 0) {
+ errno = EINVAL;
+ goto fail;
+ }
+ state = NULL;
+ continue;
+ }
+
+ b = xfrm(table, buf, pri, pass);
+ want += b;
+ if (room) {
+
+ while (b) {
+ b--;
+ if (room) {
+ *xf++ = buf[b];
+ room--;
+ }
+ }
+ }
+ need = want;
+ }
+ }
+ }
+ free(tr);
+ return (need);
+
+fail:
+ free(tr);
+ return ((size_t)(-1));
+}
+
+/*
+ * __collate_equiv_value returns the primary collation value for the given
+ * collating symbol specified by str and len. Zero or negative is returned
+ * if the collating symbol was not found. This function is used by bracket
+ * code in the TRE regex library.
+ */
+int
+__collate_equiv_value(locale_t locale, const wchar_t *str, size_t len)
+{
+ int32_t e;
+
+ if (len < 1 || len >= COLLATE_STR_LEN)
+ return (-1);
+
+ FIX_LOCALE(locale);
+ struct xlocale_collate *table =
+ (struct xlocale_collate*)locale->components[XLC_COLLATE];
+
+ if (table->__collate_load_error)
+ return ((len == 1 && *str <= UCHAR_MAX) ? *str : -1);
+
+ if (len == 1) {
+ e = -1;
+ if (*str <= UCHAR_MAX)
+ e = table->char_pri_table[*str].pri[0];
+ else if (BSWAP(table->info->large_count) > 0) {
+ collate_large_t *match_large;
+ match_large = largesearch(table, *str);
+ if (match_large)
+ e = match_large->pri.pri[0];
+ }
+ if (e == 0)
+ return (1);
+ return (e > 0 ? e : 0);
+ }
+ if (BSWAP(table->info->chain_count) > 0) {
+ wchar_t name[COLLATE_STR_LEN];
+ collate_chain_t *match_chain;
+ int clen;
+
+ wcsncpy (name, str, len);
+ name[len] = 0;
+ match_chain = chainsearch(table, name, &clen);
+ if (match_chain) {
+ e = match_chain->pri[0];
+ if (e == 0)
+ return (1);
+ return (e < 0 ? -e : e);
+ }
+ }
+ return (0);
+}
diff --git a/lib/libc/locale/collate.h b/lib/libc/locale/collate.h
new file mode 100644
index 000000000000..c8968c69f5a6
--- /dev/null
+++ b/lib/libc/locale/collate.h
@@ -0,0 +1,139 @@
+/*-
+ * Copyright 2010 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 1995 Alex Tatmanjants <alex@elvisti.kiev.ua>
+ * at Electronni Visti IA, Kiev, Ukraine.
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _COLLATE_H_
+#define _COLLATE_H_
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <limits.h>
+#include "xlocale_private.h"
+
+/*
+ * Work around buildworld bootstrapping from older systems whose limits.h
+ * sets COLL_WEIGHTS_MAX to 0.
+ */
+#if COLL_WEIGHTS_MAX == 0
+#undef COLL_WEIGHTS_MAX
+#define COLL_WEIGHTS_MAX 10
+#endif
+
+#define COLLATE_STR_LEN 24 /* should be 64-bit multiple */
+#define COLLATE_VERSION "BSD 1.0\n"
+
+#define COLLATE_MAX_PRIORITY (0x7fffffff) /* max signed value */
+#define COLLATE_SUBST_PRIORITY (0x40000000) /* bit indicates subst table */
+
+#define DIRECTIVE_UNDEF 0x00
+#define DIRECTIVE_FORWARD 0x01
+#define DIRECTIVE_BACKWARD 0x02
+#define DIRECTIVE_POSITION 0x04
+#define DIRECTIVE_UNDEFINED 0x08 /* special last weight for UNDEFINED */
+
+#define DIRECTIVE_DIRECTION_MASK (DIRECTIVE_FORWARD | DIRECTIVE_BACKWARD)
+
+/*
+ * The collate file format is as follows:
+ *
+ * char version[COLLATE_STR_LEN]; // must be COLLATE_VERSION
+ * collate_info_t info; // see below, includes padding
+ * collate_char_pri_t char_data[256]; // 8 bit char values
+ * collate_subst_t subst[*]; // 0 or more substitutions
+ * collate_chain_pri_t chains[*]; // 0 or more chains
+ * collate_large_pri_t large[*]; // extended char priorities
+ *
+ * Note that all structures must be 32-bit aligned, as each structure
+ * contains 32-bit member fields. The entire file is mmap'd, so its
+ * critical that alignment be observed. It is not generally safe to
+ * use any 64-bit values in the structures.
+ */
+
+typedef struct collate_info {
+ uint8_t directive_count;
+ uint8_t directive[COLL_WEIGHTS_MAX];
+ int32_t pri_count[COLL_WEIGHTS_MAX];
+ int32_t flags;
+ int32_t chain_count;
+ int32_t large_count;
+ int32_t subst_count[COLL_WEIGHTS_MAX];
+ int32_t undef_pri[COLL_WEIGHTS_MAX];
+} collate_info_t;
+
+typedef struct collate_char {
+ int32_t pri[COLL_WEIGHTS_MAX];
+} collate_char_t;
+
+typedef struct collate_chain {
+ wchar_t str[COLLATE_STR_LEN];
+ int32_t pri[COLL_WEIGHTS_MAX];
+} collate_chain_t;
+
+typedef struct collate_large {
+ int32_t val;
+ collate_char_t pri;
+} collate_large_t;
+
+typedef struct collate_subst {
+ int32_t key;
+ int32_t pri[COLLATE_STR_LEN];
+} collate_subst_t;
+
+struct xlocale_collate {
+ struct xlocale_component header;
+ int __collate_load_error;
+ char * map;
+ size_t maplen;
+
+ collate_info_t *info;
+ collate_char_t *char_pri_table;
+ collate_large_t *large_pri_table;
+ collate_chain_t *chain_pri_table;
+ collate_subst_t *subst_table[COLL_WEIGHTS_MAX];
+};
+
+__BEGIN_DECLS
+int __collate_load_tables(const char *);
+int __collate_equiv_value(locale_t, const wchar_t *, size_t);
+void _collate_lookup(struct xlocale_collate *,const wchar_t *, int *, int *,
+ int, const int **);
+int __collate_range_cmp(char, char);
+int __wcollate_range_cmp(wchar_t, wchar_t);
+size_t _collate_wxfrm(struct xlocale_collate *, const wchar_t *, wchar_t *,
+ size_t);
+size_t _collate_sxfrm(struct xlocale_collate *, const wchar_t *, char *,
+ size_t);
+__END_DECLS
+
+#endif /* !_COLLATE_H_ */
diff --git a/lib/libc/locale/collcmp.c b/lib/libc/locale/collcmp.c
new file mode 100644
index 000000000000..ce71a714f42f
--- /dev/null
+++ b/lib/libc/locale/collcmp.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 1996 by Andrey A. Chernov, Moscow, Russia.
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <string.h>
+#include <wchar.h>
+#include "collate.h"
+
+/*
+ * Compare two characters using collate
+ */
+
+int __collate_range_cmp(char c1, char c2)
+{
+ char s1[2], s2[2];
+
+ s1[0] = c1;
+ s1[1] = '\0';
+ s2[0] = c2;
+ s2[1] = '\0';
+ return (strcoll(s1, s2));
+}
+
+int __wcollate_range_cmp(wchar_t c1, wchar_t c2)
+{
+ wchar_t s1[2], s2[2];
+
+ s1[0] = c1;
+ s1[1] = L'\0';
+ s2[0] = c2;
+ s2[1] = L'\0';
+ return (wcscoll(s1, s2));
+}
diff --git a/lib/libc/locale/ctype.3 b/lib/libc/locale/ctype.3
new file mode 100644
index 000000000000..62ec05fbbed2
--- /dev/null
+++ b/lib/libc/locale/ctype.3
@@ -0,0 +1,151 @@
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)ctype.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd March 30, 2004
+.Dt CTYPE 3
+.Os
+.Sh NAME
+.Nm digittoint ,
+.Nm isalnum ,
+.Nm isalpha ,
+.Nm isascii ,
+.Nm isblank ,
+.Nm iscntrl ,
+.Nm isdigit ,
+.Nm isgraph ,
+.Nm ishexnumber ,
+.Nm isideogram ,
+.Nm islower ,
+.Nm isnumber ,
+.Nm isphonogram ,
+.Nm isprint ,
+.Nm ispunct ,
+.Nm isrune ,
+.Nm isspace ,
+.Nm isspecial ,
+.Nm isupper ,
+.Nm isxdigit ,
+.Nm toascii ,
+.Nm tolower ,
+.Nm toupper
+.Nd character classification functions
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In ctype.h
+.Ft int
+.Fn digittoint "int c"
+.Ft int
+.Fn isalnum "int c"
+.Ft int
+.Fn isalpha "int c"
+.Ft int
+.Fn isascii "int c"
+.Ft int
+.Fn iscntrl "int c"
+.Ft int
+.Fn isdigit "int c"
+.Ft int
+.Fn isgraph "int c"
+.Ft int
+.Fn ishexnumber "int c"
+.Ft int
+.Fn isideogram "int c"
+.Ft int
+.Fn islower "int c"
+.Ft int
+.Fn isnumber "int c"
+.Ft int
+.Fn isphonogram "int c"
+.Ft int
+.Fn isspecial "int c"
+.Ft int
+.Fn isprint "int c"
+.Ft int
+.Fn ispunct "int c"
+.Ft int
+.Fn isrune "int c"
+.Ft int
+.Fn isspace "int c"
+.Ft int
+.Fn isupper "int c"
+.Ft int
+.Fn isxdigit "int c"
+.Ft int
+.Fn toascii "int c"
+.Ft int
+.Fn tolower "int c"
+.Ft int
+.Fn toupper "int c"
+.Sh DESCRIPTION
+The above functions perform character tests and conversions on the integer
+.Fa c .
+They are available as macros, defined in the include file
+.In ctype.h ,
+or as true functions in the C library.
+See the specific manual pages for more information.
+.Sh SEE ALSO
+.Xr digittoint 3 ,
+.Xr isalnum 3 ,
+.Xr isalpha 3 ,
+.Xr isascii 3 ,
+.Xr isblank 3 ,
+.Xr iscntrl 3 ,
+.Xr isdigit 3 ,
+.Xr isgraph 3 ,
+.Xr isideogram 3 ,
+.Xr islower 3 ,
+.Xr isphonogram 3 ,
+.Xr isprint 3 ,
+.Xr ispunct 3 ,
+.Xr isrune 3 ,
+.Xr isspace 3 ,
+.Xr isspecial 3 ,
+.Xr isupper 3 ,
+.Xr isxdigit 3 ,
+.Xr toascii 3 ,
+.Xr tolower 3 ,
+.Xr toupper 3 ,
+.Xr wctype 3 ,
+.Xr ascii 7
+.Sh STANDARDS
+These functions, except for
+.Fn digittoint ,
+.Fn isascii ,
+.Fn ishexnumber ,
+.Fn isideogram ,
+.Fn isnumber ,
+.Fn isphonogram ,
+.Fn isrune ,
+.Fn isspecial
+and
+.Fn toascii ,
+conform to
+.St -isoC .
diff --git a/lib/libc/locale/ctype.c b/lib/libc/locale/ctype.c
new file mode 100644
index 000000000000..f0ec3f6d8b0f
--- /dev/null
+++ b/lib/libc/locale/ctype.c
@@ -0,0 +1,33 @@
+/*-
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by David Chisnall under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions * are met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#define _XLOCALE_INLINE
+#include <ctype.h>
+#include <wctype.h>
+#include <xlocale.h>
diff --git a/lib/libc/locale/ctype_l.3 b/lib/libc/locale/ctype_l.3
new file mode 100644
index 000000000000..5f427de06394
--- /dev/null
+++ b/lib/libc/locale/ctype_l.3
@@ -0,0 +1,151 @@
+.\" Copyright (c) 2011 The FreeBSD Foundation
+.\" All rights reserved.
+.\"
+.\" This documentation was written by David Chisnall under sponsorship from
+.\" the FreeBSD Foundation.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 March 6, 2012
+.Dt CTYPE_L 3
+.Os
+.Sh NAME
+.Nm digittoint_l ,
+.Nm isalnum_l ,
+.Nm isalpha_l ,
+.Nm isascii_l ,
+.Nm isblank_l ,
+.Nm iscntrl_l ,
+.Nm isdigit_l ,
+.Nm isgraph_l ,
+.Nm ishexnumber_l ,
+.Nm isideogram_l ,
+.Nm islower_l ,
+.Nm isnumber_l ,
+.Nm isphonogram_l ,
+.Nm isprint_l ,
+.Nm ispunct_l ,
+.Nm isrune_l ,
+.Nm isspace_l ,
+.Nm isspecial_l ,
+.Nm isupper_l ,
+.Nm isxdigit_l ,
+.Nm tolower_l ,
+.Nm toupper_l
+.Nd character classification functions
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In ctype.h
+.Ft int
+.Fn digittoint_l "int c" "locale_t loc"
+.Ft int
+.Fn isalnum_l "int c" "locale_t loc"
+.Ft int
+.Fn isalpha_l "int c" "locale_t loc"
+.Ft int
+.Fn isascii_l "int c" "locale_t loc"
+.Ft int
+.Fn iscntrl_l "int c" "locale_t loc"
+.Ft int
+.Fn isdigit_l "int c" "locale_t loc"
+.Ft int
+.Fn isgraph_l "int c" "locale_t loc"
+.Ft int
+.Fn ishexnumber_l "int c" "locale_t loc"
+.Ft int
+.Fn isideogram_l "int c" "locale_t loc"
+.Ft int
+.Fn islower_l "int c" "locale_t loc"
+.Ft int
+.Fn isnumber_l "int c" "locale_t loc"
+.Ft int
+.Fn isphonogram_l "int c" "locale_t loc"
+.Ft int
+.Fn isspecial_l "int c" "locale_t loc"
+.Ft int
+.Fn isprint_l "int c" "locale_t loc"
+.Ft int
+.Fn ispunct_l "int c" "locale_t loc"
+.Ft int
+.Fn isrune_l "int c" "locale_t loc"
+.Ft int
+.Fn isspace_l "int c" "locale_t loc"
+.Ft int
+.Fn isupper_l "int c" "locale_t loc"
+.Ft int
+.Fn isxdigit_l "int c" "locale_t loc"
+.Ft int
+.Fn tolower_l "int c" "locale_t loc"
+.Ft int
+.Fn toupper_l "int c" "locale_t loc"
+.Sh DESCRIPTION
+The above functions perform character tests and conversions on the integer
+.Fa c
+in the locale
+.Fa loc .
+They behave in the same way as the versions without the _l suffix, but use the
+specified locale rather than the global or per-thread locale.
+.In ctype.h ,
+or as true functions in the C library.
+See the specific manual pages for more information.
+.Sh SEE ALSO
+.Xr digittoint 3 ,
+.Xr isalnum 3 ,
+.Xr isalpha 3 ,
+.Xr isascii 3 ,
+.Xr isblank 3 ,
+.Xr iscntrl 3 ,
+.Xr isdigit 3 ,
+.Xr isgraph 3 ,
+.Xr isideogram 3 ,
+.Xr islower 3 ,
+.Xr isphonogram 3 ,
+.Xr isprint 3 ,
+.Xr ispunct 3 ,
+.Xr isrune 3 ,
+.Xr isspace 3 ,
+.Xr isspecial 3 ,
+.Xr isupper 3 ,
+.Xr isxdigit 3 ,
+.Xr tolower 3 ,
+.Xr toupper 3 ,
+.Xr wctype 3 ,
+.Xr xlocale 3
+.Sh STANDARDS
+These functions conform to
+.St -p1003.1-2008 ,
+except for
+.Fn digittoint_l ,
+.Fn isascii_l ,
+.Fn ishexnumber_l ,
+.Fn isideogram_l ,
+.Fn isnumber_l ,
+.Fn isphonogram_l ,
+.Fn isrune_l
+and
+.Fn isspecial_l
+which are
+.Fx
+extensions.
diff --git a/lib/libc/locale/digittoint.3 b/lib/libc/locale/digittoint.3
new file mode 100644
index 000000000000..6670abe424ab
--- /dev/null
+++ b/lib/libc/locale/digittoint.3
@@ -0,0 +1,68 @@
+.\" Copyright (c) 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)digittoint.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd April 6, 2001
+.Dt DIGITTOINT 3
+.Os
+.Sh NAME
+.Nm digittoint
+.Nd convert a numeric character to its integer value
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In ctype.h
+.Ft int
+.Fn digittoint "int c"
+.Ft int
+.Fn digittoint_l "int c" "locale_t loc"
+.Sh DESCRIPTION
+The
+.Fn digittoint
+function converts a numeric character to its corresponding integer value.
+The character can be any decimal digit or hexadecimal digit.
+With hexadecimal characters, the case of the values does not matter.
+.Pp
+The
+.Fn digittoint_l
+function takes an explicit locale argument, whereas the
+.Fn digittoint
+function use the current global or per-thread locale.
+.Sh RETURN VALUES
+The
+.Fn digittoint
+function always returns an integer from the range of 0 to 15.
+If the given character was not a digit as defined by
+.Xr isxdigit 3 ,
+the function will return 0.
+.Sh SEE ALSO
+.Xr ctype 3 ,
+.Xr isdigit 3 ,
+.Xr isxdigit 3 ,
+.Xr xlocale 3
diff --git a/lib/libc/locale/duplocale.3 b/lib/libc/locale/duplocale.3
new file mode 100644
index 000000000000..bc0c4bced812
--- /dev/null
+++ b/lib/libc/locale/duplocale.3
@@ -0,0 +1,79 @@
+.\" Copyright (c) 2011 The FreeBSD Foundation
+.\" All rights reserved.
+.\"
+.\" This documentation was written by David Chisnall under sponsorship from
+.\" the FreeBSD Foundation.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 September 17, 2011
+.Dt DUPLOCALE 3
+.Os
+.Sh NAME
+.Nm duplocale
+.Nd duplicate an locale
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In locale.h
+.Ft locale_t
+.Fn duplocale "locale_t locale"
+.Sh DESCRIPTION
+Duplicates an existing
+.Fa locale_t
+returning a new
+.Fa locale_t
+that refers to the same locale values but has an independent internal state.
+Various functions, such as
+.Xr mblen 3
+require a persistent state.
+These functions formerly used static variables and calls to them from multiple
+threads had undefined behavior.
+They now use fields in the
+.Fa locale_t
+associated with the current thread by
+.Xr uselocale 3 .
+These calls are therefore only thread safe on threads with a unique per-thread
+locale.
+The locale returned by this call must be freed with
+.Xr freelocale 3 .
+.Sh SEE ALSO
+.Xr freelocale 3 ,
+.Xr localeconv 3 ,
+.Xr newlocale 3 ,
+.Xr querylocale 3 ,
+.Xr uselocale 3 ,
+.Xr xlocale 3
+.Sh STANDARDS
+This function conforms to
+.St -p1003.1-2008 .
+.Sh BUGS
+Ideally,
+.Xr uselocale 3
+should make a copy of the
+.Fa locale_t
+implicitly to ensure thread safety,
+and a copy of the global locale should be installed lazily on each thread.
+The FreeBSD implementation does not do this,
+for compatibility with Darwin.
diff --git a/lib/libc/locale/endian.h b/lib/libc/locale/endian.h
new file mode 100644
index 000000000000..d3b822788688
--- /dev/null
+++ b/lib/libc/locale/endian.h
@@ -0,0 +1,52 @@
+/*-
+ * Copyright (c) 2016 Ruslan Bukin <br@bsdpad.com>
+ * All rights reserved.
+ *
+ * Portions of this software were developed by SRI International and the
+ * University of Cambridge Computer Laboratory under DARPA/AFRL contract
+ * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme.
+ *
+ * Portions of this software were developed by the University of Cambridge
+ * Computer Laboratory as part of the CTSRD Project, with support from the
+ * UK Higher Education Innovation Fund (HEIF).
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/endian.h>
+
+/*
+ * We assume locale files were generated on EL machine
+ * (e.g. during cross build on amd64 host), but used on EB
+ * machine (e.g. MIPS64EB), so convert it to host endianness.
+ *
+ * TODO: detect host endianness on the build machine and use
+ * correct macros here.
+ */
+
+#if BYTE_ORDER == BIG_ENDIAN && defined(__mips__)
+#define BSWAP(x) le32toh(x)
+#else
+#define BSWAP(x) x
+#endif
diff --git a/lib/libc/locale/euc.5 b/lib/libc/locale/euc.5
new file mode 100644
index 000000000000..b438ede8ddcd
--- /dev/null
+++ b/lib/libc/locale/euc.5
@@ -0,0 +1,134 @@
+.\" Copyright (c) 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Paul Borman at Krystal Technologies.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)euc.4 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd November 8, 2003
+.Dt EUC 5
+.Os
+.Sh NAME
+.Nm euc
+.Nd EUC encoding of wide characters
+.Sh SYNOPSIS
+.Nm ENCODING
+.Qq EUC
+.Pp
+.Nm VARIABLE
+.Ar len1
+.Ar mask1
+.Ar len2
+.Ar mask2
+.Ar len3
+.Ar mask3
+.Ar len4
+.Ar mask4
+.Ar mask
+.Sh DESCRIPTION
+.\"The
+.\".Nm EUC
+.\"encoding is provided for compatibility with
+.\".Ux
+.\"based systems.
+.\"See
+.\".Xr mklocale 1
+.\"for a complete description of the
+.\".Ev LC_CTYPE
+.\"source file format.
+.\".Pp
+.Nm EUC
+implements a system of 4 multibyte codesets.
+A multibyte character in the first codeset consists of
+.Ar len1
+bytes starting with a byte in the range of 0x00 to 0x7f.
+To allow use of
+.Tn ASCII ,
+.Ar len1
+is always 1.
+A multibyte character in the second codeset consists of
+.Ar len2
+bytes starting with a byte in the range of 0x80-0xff excluding 0x8e and 0x8f.
+A multibyte character in the third codeset consists of
+.Ar len3
+bytes starting with the byte 0x8e.
+A multibyte character in the fourth codeset consists of
+.Ar len4
+bytes starting with the byte 0x8f.
+.Pp
+The
+.Vt wchar_t
+encoding of
+.Nm EUC
+multibyte characters is dependent on the
+.Ar len
+and
+.Ar mask
+arguments.
+First, the bytes are moved into a
+.Vt wchar_t
+as follows:
+.Bd -literal
+byte0 << ((\fIlen\fPN-1) * 8) | byte1 << ((\fIlen\fPN-2) * 8) | ... | byte\fIlen\fPN-1
+.Ed
+.Pp
+The result is then ANDed with
+.Ar ~mask
+and ORed with
+.Ar maskN .
+Codesets 2 and 3 are special in that the leading byte (0x8e or 0x8f) is
+first removed and the
+.Ar lenN
+argument is reduced by 1.
+.Pp
+For example, the
+.Li ja_JP.eucJP
+locale has the following
+.Va VARIABLE
+line:
+.Bd -literal
+VARIABLE 1 0x0000 2 0x8080 2 0x0080 3 0x8000 0x8080
+.Ed
+.Pp
+Codeset 1 consists of the values 0x0000 - 0x007f.
+.Pp
+Codeset 2 consists of the values who have the bits 0x8080 set.
+.Pp
+Codeset 3 consists of the values 0x0080 - 0x00ff.
+.Pp
+Codeset 4 consists of the values 0x8000 - 0xff7f excluding the values
+which have the 0x0080 bit set.
+.Pp
+Notice that the global
+.Ar mask
+is set to 0x8080, this implies that from those 2 bits the codeset can
+be determined.
+.Sh SEE ALSO
+.Xr mklocale 1 ,
+.Xr setlocale 3
diff --git a/lib/libc/locale/euc.c b/lib/libc/locale/euc.c
new file mode 100644
index 000000000000..2fe40462e9be
--- /dev/null
+++ b/lib/libc/locale/euc.c
@@ -0,0 +1,455 @@
+/*-
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2002-2004 Tim J. Robbins. All rights reserved.
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Borman at Krystal Technologies.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)euc.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/param.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <limits.h>
+#include <runetype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include "mblocal.h"
+
+extern int __mb_sb_limit;
+
+static size_t _EUC_mbrtowc_impl(wchar_t * __restrict, const char * __restrict,
+ size_t, mbstate_t * __restrict, uint8_t, uint8_t, uint8_t, uint8_t);
+static size_t _EUC_wcrtomb_impl(char * __restrict, wchar_t,
+ mbstate_t * __restrict, uint8_t, uint8_t, uint8_t, uint8_t);
+
+static size_t _EUC_CN_mbrtowc(wchar_t * __restrict, const char * __restrict,
+ size_t, mbstate_t * __restrict);
+static size_t _EUC_JP_mbrtowc(wchar_t * __restrict, const char * __restrict,
+ size_t, mbstate_t * __restrict);
+static size_t _EUC_KR_mbrtowc(wchar_t * __restrict, const char * __restrict,
+ size_t, mbstate_t * __restrict);
+static size_t _EUC_TW_mbrtowc(wchar_t * __restrict, const char * __restrict,
+ size_t, mbstate_t * __restrict);
+
+static size_t _EUC_CN_wcrtomb(char * __restrict, wchar_t,
+ mbstate_t * __restrict);
+static size_t _EUC_JP_wcrtomb(char * __restrict, wchar_t,
+ mbstate_t * __restrict);
+static size_t _EUC_KR_wcrtomb(char * __restrict, wchar_t,
+ mbstate_t * __restrict);
+static size_t _EUC_TW_wcrtomb(char * __restrict, wchar_t,
+ mbstate_t * __restrict);
+
+static size_t _EUC_CN_mbsnrtowcs(wchar_t * __restrict,
+ const char ** __restrict, size_t, size_t,
+ mbstate_t * __restrict);
+static size_t _EUC_JP_mbsnrtowcs(wchar_t * __restrict,
+ const char ** __restrict, size_t, size_t,
+ mbstate_t * __restrict);
+static size_t _EUC_KR_mbsnrtowcs(wchar_t * __restrict,
+ const char ** __restrict, size_t, size_t,
+ mbstate_t * __restrict);
+static size_t _EUC_TW_mbsnrtowcs(wchar_t * __restrict,
+ const char ** __restrict, size_t, size_t,
+ mbstate_t * __restrict);
+
+static size_t _EUC_CN_wcsnrtombs(char * __restrict,
+ const wchar_t ** __restrict, size_t, size_t,
+ mbstate_t * __restrict);
+static size_t _EUC_JP_wcsnrtombs(char * __restrict,
+ const wchar_t ** __restrict, size_t, size_t,
+ mbstate_t * __restrict);
+static size_t _EUC_KR_wcsnrtombs(char * __restrict,
+ const wchar_t ** __restrict, size_t, size_t,
+ mbstate_t * __restrict);
+static size_t _EUC_TW_wcsnrtombs(char * __restrict,
+ const wchar_t ** __restrict, size_t, size_t,
+ mbstate_t * __restrict);
+
+static int _EUC_mbsinit(const mbstate_t *);
+
+typedef struct {
+ wchar_t ch;
+ int set;
+ int want;
+} _EucState;
+
+static int
+_EUC_mbsinit(const mbstate_t *ps)
+{
+
+ return (ps == NULL || ((const _EucState *)ps)->want == 0);
+}
+
+/*
+ * EUC-CN uses CS0, CS1 and CS2 (4 bytes).
+ */
+int
+_EUC_CN_init(struct xlocale_ctype *l, _RuneLocale *rl)
+{
+ l->__mbrtowc = _EUC_CN_mbrtowc;
+ l->__wcrtomb = _EUC_CN_wcrtomb;
+ l->__mbsnrtowcs = _EUC_CN_mbsnrtowcs;
+ l->__wcsnrtombs = _EUC_CN_wcsnrtombs;
+ l->__mbsinit = _EUC_mbsinit;
+
+ l->runes = rl;
+ l->__mb_cur_max = 4;
+ l->__mb_sb_limit = 128;
+ return (0);
+}
+
+static size_t
+_EUC_CN_mbrtowc(wchar_t * __restrict pwc, const char * __restrict s,
+ size_t n, mbstate_t * __restrict ps)
+{
+ return (_EUC_mbrtowc_impl(pwc, s, n, ps, SS2, 4, 0, 0));
+}
+
+static size_t
+_EUC_CN_mbsnrtowcs(wchar_t * __restrict dst,
+ const char ** __restrict src,
+ size_t nms, size_t len, mbstate_t * __restrict ps)
+{
+ return (__mbsnrtowcs_std(dst, src, nms, len, ps, _EUC_CN_mbrtowc));
+}
+
+static size_t
+_EUC_CN_wcrtomb(char * __restrict s, wchar_t wc,
+ mbstate_t * __restrict ps)
+{
+ return (_EUC_wcrtomb_impl(s, wc, ps, SS2, 4, 0, 0));
+}
+
+static size_t
+_EUC_CN_wcsnrtombs(char * __restrict dst, const wchar_t ** __restrict src,
+ size_t nwc, size_t len, mbstate_t * __restrict ps)
+{
+ return (__wcsnrtombs_std(dst, src, nwc, len, ps, _EUC_CN_wcrtomb));
+}
+
+/*
+ * EUC-KR uses only CS0 and CS1.
+ */
+int
+_EUC_KR_init(struct xlocale_ctype *l, _RuneLocale *rl)
+{
+ l->__mbrtowc = _EUC_KR_mbrtowc;
+ l->__wcrtomb = _EUC_KR_wcrtomb;
+ l->__mbsnrtowcs = _EUC_KR_mbsnrtowcs;
+ l->__wcsnrtombs = _EUC_KR_wcsnrtombs;
+ l->__mbsinit = _EUC_mbsinit;
+
+ l->runes = rl;
+ l->__mb_cur_max = 2;
+ l->__mb_sb_limit = 128;
+ return (0);
+}
+
+static size_t
+_EUC_KR_mbrtowc(wchar_t * __restrict pwc, const char * __restrict s,
+ size_t n, mbstate_t * __restrict ps)
+{
+ return (_EUC_mbrtowc_impl(pwc, s, n, ps, 0, 0, 0, 0));
+}
+
+static size_t
+_EUC_KR_mbsnrtowcs(wchar_t * __restrict dst,
+ const char ** __restrict src,
+ size_t nms, size_t len, mbstate_t * __restrict ps)
+{
+ return (__mbsnrtowcs_std(dst, src, nms, len, ps, _EUC_KR_mbrtowc));
+}
+
+static size_t
+_EUC_KR_wcrtomb(char * __restrict s, wchar_t wc,
+ mbstate_t * __restrict ps)
+{
+ return (_EUC_wcrtomb_impl(s, wc, ps, 0, 0, 0, 0));
+}
+
+static size_t
+_EUC_KR_wcsnrtombs(char * __restrict dst, const wchar_t ** __restrict src,
+ size_t nwc, size_t len, mbstate_t * __restrict ps)
+{
+ return (__wcsnrtombs_std(dst, src, nwc, len, ps, _EUC_KR_wcrtomb));
+}
+
+/*
+ * EUC-JP uses CS0, CS1, CS2, and CS3.
+ */
+int
+_EUC_JP_init(struct xlocale_ctype *l, _RuneLocale *rl)
+{
+ l->__mbrtowc = _EUC_JP_mbrtowc;
+ l->__wcrtomb = _EUC_JP_wcrtomb;
+ l->__mbsnrtowcs = _EUC_JP_mbsnrtowcs;
+ l->__wcsnrtombs = _EUC_JP_wcsnrtombs;
+ l->__mbsinit = _EUC_mbsinit;
+
+ l->runes = rl;
+ l->__mb_cur_max = 3;
+ l->__mb_sb_limit = 128;
+ return (0);
+}
+
+static size_t
+_EUC_JP_mbrtowc(wchar_t * __restrict pwc, const char * __restrict s,
+ size_t n, mbstate_t * __restrict ps)
+{
+ return (_EUC_mbrtowc_impl(pwc, s, n, ps, SS2, 2, SS3, 3));
+}
+
+static size_t
+_EUC_JP_mbsnrtowcs(wchar_t * __restrict dst,
+ const char ** __restrict src,
+ size_t nms, size_t len, mbstate_t * __restrict ps)
+{
+ return (__mbsnrtowcs_std(dst, src, nms, len, ps, _EUC_JP_mbrtowc));
+}
+
+static size_t
+_EUC_JP_wcrtomb(char * __restrict s, wchar_t wc,
+ mbstate_t * __restrict ps)
+{
+ return (_EUC_wcrtomb_impl(s, wc, ps, SS2, 2, SS3, 3));
+}
+
+static size_t
+_EUC_JP_wcsnrtombs(char * __restrict dst, const wchar_t ** __restrict src,
+ size_t nwc, size_t len, mbstate_t * __restrict ps)
+{
+ return (__wcsnrtombs_std(dst, src, nwc, len, ps, _EUC_JP_wcrtomb));
+}
+
+/*
+ * EUC-TW uses CS0, CS1, and CS2.
+ */
+int
+_EUC_TW_init(struct xlocale_ctype *l, _RuneLocale *rl)
+{
+ l->__mbrtowc = _EUC_TW_mbrtowc;
+ l->__wcrtomb = _EUC_TW_wcrtomb;
+ l->__mbsnrtowcs = _EUC_TW_mbsnrtowcs;
+ l->__wcsnrtombs = _EUC_TW_wcsnrtombs;
+ l->__mbsinit = _EUC_mbsinit;
+
+ l->runes = rl;
+ l->__mb_cur_max = 4;
+ l->__mb_sb_limit = 128;
+ return (0);
+}
+
+static size_t
+_EUC_TW_mbrtowc(wchar_t * __restrict pwc, const char * __restrict s,
+ size_t n, mbstate_t * __restrict ps)
+{
+ return (_EUC_mbrtowc_impl(pwc, s, n, ps, SS2, 4, 0, 0));
+}
+
+static size_t
+_EUC_TW_mbsnrtowcs(wchar_t * __restrict dst,
+ const char ** __restrict src,
+ size_t nms, size_t len, mbstate_t * __restrict ps)
+{
+ return (__mbsnrtowcs_std(dst, src, nms, len, ps, _EUC_TW_mbrtowc));
+}
+
+static size_t
+_EUC_TW_wcrtomb(char * __restrict s, wchar_t wc,
+ mbstate_t * __restrict ps)
+{
+ return (_EUC_wcrtomb_impl(s, wc, ps, SS2, 4, 0, 0));
+}
+
+static size_t
+_EUC_TW_wcsnrtombs(char * __restrict dst, const wchar_t ** __restrict src,
+ size_t nwc, size_t len, mbstate_t * __restrict ps)
+{
+ return (__wcsnrtombs_std(dst, src, nwc, len, ps, _EUC_TW_wcrtomb));
+}
+
+/*
+ * Common EUC code.
+ */
+
+static size_t
+_EUC_mbrtowc_impl(wchar_t * __restrict pwc, const char * __restrict s,
+ size_t n, mbstate_t * __restrict ps,
+ uint8_t cs2, uint8_t cs2width, uint8_t cs3, uint8_t cs3width)
+{
+ _EucState *es;
+ int i, want;
+ wchar_t wc = 0;
+ unsigned char ch, chs;
+
+ es = (_EucState *)ps;
+
+ if (es->want < 0 || es->want > MB_CUR_MAX) {
+ errno = EINVAL;
+ return ((size_t)-1);
+ }
+
+ if (s == NULL) {
+ s = "";
+ n = 1;
+ pwc = NULL;
+ }
+
+ if (n == 0)
+ /* Incomplete multibyte sequence */
+ return ((size_t)-2);
+
+ if (es->want == 0) {
+ /* Fast path for plain ASCII (CS0) */
+ if (((ch = (unsigned char)*s) & 0x80) == 0) {
+ if (pwc != NULL)
+ *pwc = ch;
+ return (ch != '\0' ? 1 : 0);
+ }
+
+ if (ch >= 0xa1) {
+ /* CS1 */
+ want = 2;
+ } else if (ch == cs2) {
+ want = cs2width;
+ } else if (ch == cs3) {
+ want = cs3width;
+ } else {
+ errno = EILSEQ;
+ return ((size_t)-1);
+ }
+
+
+ es->want = want;
+ es->ch = 0;
+ } else {
+ want = es->want;
+ wc = es->ch;
+ }
+
+ for (i = 0; i < MIN(want, n); i++) {
+ wc <<= 8;
+ chs = *s;
+ wc |= chs;
+ s++;
+ }
+ if (i < want) {
+ /* Incomplete multibyte sequence */
+ es->want = want - i;
+ es->ch = wc;
+ errno = EILSEQ;
+ return ((size_t)-2);
+ }
+ if (pwc != NULL)
+ *pwc = wc;
+ es->want = 0;
+ return (wc == L'\0' ? 0 : want);
+}
+
+static size_t
+_EUC_wcrtomb_impl(char * __restrict s, wchar_t wc,
+ mbstate_t * __restrict ps,
+ uint8_t cs2, uint8_t cs2width, uint8_t cs3, uint8_t cs3width)
+{
+ _EucState *es;
+ int i, len;
+ wchar_t nm;
+
+ es = (_EucState *)ps;
+
+ if (es->want != 0) {
+ errno = EINVAL;
+ return ((size_t)-1);
+ }
+
+ if (s == NULL)
+ /* Reset to initial shift state (no-op) */
+ return (1);
+
+ if ((wc & ~0x7f) == 0) {
+ /* Fast path for plain ASCII (CS0) */
+ *s = (char)wc;
+ return (1);
+ }
+
+ /* Determine the "length" */
+ if ((unsigned)wc > 0xffffff) {
+ len = 4;
+ } else if ((unsigned)wc > 0xffff) {
+ len = 3;
+ } else if ((unsigned)wc > 0xff) {
+ len = 2;
+ } else {
+ len = 1;
+ }
+
+ if (len > MB_CUR_MAX) {
+ errno = EILSEQ;
+ return ((size_t)-1);
+ }
+
+ /* This first check excludes CS1, which is implicitly valid. */
+ if ((wc < 0xa100) || (wc > 0xffff)) {
+ /* Check for valid CS2 or CS3 */
+ nm = (wc >> ((len - 1) * 8));
+ if (nm == cs2) {
+ if (len != cs2width) {
+ errno = EILSEQ;
+ return ((size_t)-1);
+ }
+ } else if (nm == cs3) {
+ if (len != cs3width) {
+ errno = EILSEQ;
+ return ((size_t)-1);
+ }
+ } else {
+ errno = EILSEQ;
+ return ((size_t)-1);
+ }
+ }
+
+ /* Stash the bytes, least significant last */
+ for (i = len - 1; i >= 0; i--) {
+ s[i] = (wc & 0xff);
+ wc >>= 8;
+ }
+ return (len);
+}
diff --git a/lib/libc/locale/fix_grouping.c b/lib/libc/locale/fix_grouping.c
new file mode 100644
index 000000000000..2e5bc047d592
--- /dev/null
+++ b/lib/libc/locale/fix_grouping.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2001 Alexey Zelkin <phantom@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <ctype.h>
+#include <limits.h>
+#include <stddef.h>
+
+static const char nogrouping[] = { CHAR_MAX, '\0' };
+
+/*
+ * Internal helper used to convert grouping sequences from string
+ * representation into POSIX specified form, i.e.
+ *
+ * "3;3;-1" -> "\003\003\177\000"
+ */
+
+const char *
+__fix_locale_grouping_str(const char *str)
+{
+ char *src, *dst;
+ char n;
+
+ if (str == NULL || *str == '\0') {
+ return nogrouping;
+ }
+
+ for (src = (char*)str, dst = (char*)str; *src != '\0'; src++) {
+
+ /* input string examples: "3;3", "3;2;-1" */
+ if (*src == ';')
+ continue;
+
+ if (*src == '-' && *(src+1) == '1') {
+ *dst++ = CHAR_MAX;
+ src++;
+ continue;
+ }
+
+ if (!isdigit((unsigned char)*src)) {
+ /* broken grouping string */
+ return nogrouping;
+ }
+
+ /* assume all numbers <= 99 */
+ n = *src - '0';
+ if (isdigit((unsigned char)*(src+1))) {
+ src++;
+ n *= 10;
+ n += *src - '0';
+ }
+
+ *dst = n;
+ /* NOTE: assume all input started with "0" as 'no grouping' */
+ if (*dst == '\0')
+ return (dst == (char*)str) ? nogrouping : str;
+ dst++;
+ }
+ *dst = '\0';
+ return str;
+}
diff --git a/lib/libc/locale/freelocale.3 b/lib/libc/locale/freelocale.3
new file mode 100644
index 000000000000..d3e2d4498226
--- /dev/null
+++ b/lib/libc/locale/freelocale.3
@@ -0,0 +1,59 @@
+.\" Copyright (c) 2011 The FreeBSD Foundation
+.\" All rights reserved.
+.\"
+.\" This documentation was written by David Chisnall under sponsorship from
+.\" the FreeBSD Foundation.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 July 26, 2016
+.Dt FREELOCALE 3
+.Os
+.Sh NAME
+.Nm freelocale
+.Nd Frees a locale created with
+.Xr duplocale 3
+or
+.Xr newlocale 3
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In locale.h
+.Ft void
+.Fn freelocale "locale_t locale"
+.Sh DESCRIPTION
+Frees a
+.Fa locale_t .
+This relinquishes any resources held exclusively by this locale.
+Note that locales share reference-counted components,
+so a call to this function is not guaranteed to free all of the components.
+.Sh SEE ALSO
+.Xr duplocale 3 ,
+.Xr localeconv 3 ,
+.Xr newlocale 3 ,
+.Xr querylocale 3 ,
+.Xr uselocale 3 ,
+.Xr xlocale 3
+.Sh STANDARDS
+This function conforms to
+.St -p1003.1-2008 .
diff --git a/lib/libc/locale/gb18030.5 b/lib/libc/locale/gb18030.5
new file mode 100644
index 000000000000..3a296c017844
--- /dev/null
+++ b/lib/libc/locale/gb18030.5
@@ -0,0 +1,78 @@
+.\" Copyright (c) 2002, 2003 Tim J. Robbins
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd August 10, 2003
+.Dt GB18030 5
+.Os
+.Sh NAME
+.Nm gb18030
+.Nd "GB 18030 encoding method for Chinese text"
+.Sh SYNOPSIS
+.Nm ENCODING
+.Qq GB18030
+.Sh DESCRIPTION
+The
+.Nm GB18030
+encoding implements GB 18030-2000, a PRC national standard for the encoding of
+Chinese characters.
+It is a superset of the older GB\ 2312-1980 and GBK encodings,
+and incorporates Unicode's Unihan Extension A completely.
+It also provides code space for all Unicode 3.0 code points.
+.Pp
+Multibyte characters in the
+.Nm GB18030
+encoding can be one byte, two bytes, or
+four bytes long.
+There are a total of over 1.5 million code positions.
+.Pp
+.No GB\ 11383-1981 Pq Tn ASCII
+characters are represented by single bytes in the range 0x00 to 0x7F.
+.Pp
+Chinese characters are represented as either two bytes or four bytes.
+Characters that are represented by two bytes begin with a byte in the range
+0x81-0xFE and end with a byte either in the range 0x40-0x7E or 0x80-0xFE.
+.Pp
+Characters that are represented by four bytes begin with a byte in the range
+0x81-0xFE, have a second byte in the range 0x30-0x39, a third byte in the range
+0x81-0xFE and a fourth byte in the range 0x30-0x39.
+.Sh SEE ALSO
+.Xr euc 5 ,
+.Xr gb2312 5 ,
+.Xr gbk 5 ,
+.Xr utf8 5
+.Rs
+.%T "Chinese National Standard GB 18030-2000: Information Technology -- Chinese ideograms coded character set for information interchange -- Extension for the basic set"
+.%D "March 2000"
+.Re
+.Rs
+.%Q "The Unicode Consortium"
+.%T "The Unicode Standard, Version 3.0"
+.%D "2000"
+.Re
+.Sh STANDARDS
+The
+.Nm GB18030
+encoding is believed to be compatible with GB 18030-2000.
diff --git a/lib/libc/locale/gb18030.c b/lib/libc/locale/gb18030.c
new file mode 100644
index 000000000000..d87b6f78d5d9
--- /dev/null
+++ b/lib/libc/locale/gb18030.c
@@ -0,0 +1,252 @@
+/*-
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
+ * Copyright 2010 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2002-2004 Tim J. Robbins
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * PRC National Standard GB 18030-2000 encoding of Chinese text.
+ *
+ * See gb18030(5) for details.
+ */
+
+#include <sys/param.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <runetype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include "mblocal.h"
+
+static size_t _GB18030_mbrtowc(wchar_t * __restrict, const char * __restrict,
+ size_t, mbstate_t * __restrict);
+static int _GB18030_mbsinit(const mbstate_t *);
+static size_t _GB18030_wcrtomb(char * __restrict, wchar_t,
+ mbstate_t * __restrict);
+static size_t _GB18030_mbsnrtowcs(wchar_t * __restrict,
+ const char ** __restrict, size_t, size_t,
+ mbstate_t * __restrict);
+static size_t _GB18030_wcsnrtombs(char * __restrict,
+ const wchar_t ** __restrict, size_t, size_t,
+ mbstate_t * __restrict);
+
+
+typedef struct {
+ int count;
+ u_char bytes[4];
+} _GB18030State;
+
+int
+_GB18030_init(struct xlocale_ctype *l, _RuneLocale *rl)
+{
+
+ l->__mbrtowc = _GB18030_mbrtowc;
+ l->__wcrtomb = _GB18030_wcrtomb;
+ l->__mbsinit = _GB18030_mbsinit;
+ l->__mbsnrtowcs = _GB18030_mbsnrtowcs;
+ l->__wcsnrtombs = _GB18030_wcsnrtombs;
+ l->runes = rl;
+ l->__mb_cur_max = 4;
+ l->__mb_sb_limit = 128;
+
+ return (0);
+}
+
+static int
+_GB18030_mbsinit(const mbstate_t *ps)
+{
+
+ return (ps == NULL || ((const _GB18030State *)ps)->count == 0);
+}
+
+static size_t
+_GB18030_mbrtowc(wchar_t * __restrict pwc, const char * __restrict s,
+ size_t n, mbstate_t * __restrict ps)
+{
+ _GB18030State *gs;
+ wchar_t wch;
+ int ch, len, ocount;
+ size_t ncopy;
+
+ gs = (_GB18030State *)ps;
+
+ if (gs->count < 0 || gs->count > sizeof(gs->bytes)) {
+ errno = EINVAL;
+ return ((size_t)-1);
+ }
+
+ if (s == NULL) {
+ s = "";
+ n = 1;
+ pwc = NULL;
+ }
+
+ ncopy = MIN(MIN(n, MB_CUR_MAX), sizeof(gs->bytes) - gs->count);
+ memcpy(gs->bytes + gs->count, s, ncopy);
+ ocount = gs->count;
+ gs->count += ncopy;
+ s = (char *)gs->bytes;
+ n = gs->count;
+
+ if (n == 0)
+ /* Incomplete multibyte sequence */
+ return ((size_t)-2);
+
+ /*
+ * Single byte: [00-7f]
+ * Two byte: [81-fe][40-7e,80-fe]
+ * Four byte: [81-fe][30-39][81-fe][30-39]
+ */
+ ch = (unsigned char)*s++;
+ if (ch <= 0x7f) {
+ len = 1;
+ wch = ch;
+ } else if (ch >= 0x81 && ch <= 0xfe) {
+ wch = ch;
+ if (n < 2)
+ return ((size_t)-2);
+ ch = (unsigned char)*s++;
+ if ((ch >= 0x40 && ch <= 0x7e) || (ch >= 0x80 && ch <= 0xfe)) {
+ wch = (wch << 8) | ch;
+ len = 2;
+ } else if (ch >= 0x30 && ch <= 0x39) {
+ /*
+ * Strip high bit off the wide character we will
+ * eventually output so that it is positive when
+ * cast to wint_t on 32-bit twos-complement machines.
+ */
+ wch = ((wch & 0x7f) << 8) | ch;
+ if (n < 3)
+ return ((size_t)-2);
+ ch = (unsigned char)*s++;
+ if (ch < 0x81 || ch > 0xfe)
+ goto ilseq;
+ wch = (wch << 8) | ch;
+ if (n < 4)
+ return ((size_t)-2);
+ ch = (unsigned char)*s++;
+ if (ch < 0x30 || ch > 0x39)
+ goto ilseq;
+ wch = (wch << 8) | ch;
+ len = 4;
+ } else
+ goto ilseq;
+ } else
+ goto ilseq;
+
+ if (pwc != NULL)
+ *pwc = wch;
+ gs->count = 0;
+ return (wch == L'\0' ? 0 : len - ocount);
+ilseq:
+ errno = EILSEQ;
+ return ((size_t)-1);
+}
+
+static size_t
+_GB18030_wcrtomb(char * __restrict s, wchar_t wc, mbstate_t * __restrict ps)
+{
+ _GB18030State *gs;
+ size_t len;
+ int c;
+
+ gs = (_GB18030State *)ps;
+
+ if (gs->count != 0) {
+ errno = EINVAL;
+ return ((size_t)-1);
+ }
+
+ if (s == NULL)
+ /* Reset to initial shift state (no-op) */
+ return (1);
+ if ((wc & ~0x7fffffff) != 0)
+ goto ilseq;
+ if (wc & 0x7f000000) {
+ /* Replace high bit that mbrtowc() removed. */
+ wc |= 0x80000000;
+ c = (wc >> 24) & 0xff;
+ if (c < 0x81 || c > 0xfe)
+ goto ilseq;
+ *s++ = c;
+ c = (wc >> 16) & 0xff;
+ if (c < 0x30 || c > 0x39)
+ goto ilseq;
+ *s++ = c;
+ c = (wc >> 8) & 0xff;
+ if (c < 0x81 || c > 0xfe)
+ goto ilseq;
+ *s++ = c;
+ c = wc & 0xff;
+ if (c < 0x30 || c > 0x39)
+ goto ilseq;
+ *s++ = c;
+ len = 4;
+ } else if (wc & 0x00ff0000)
+ goto ilseq;
+ else if (wc & 0x0000ff00) {
+ c = (wc >> 8) & 0xff;
+ if (c < 0x81 || c > 0xfe)
+ goto ilseq;
+ *s++ = c;
+ c = wc & 0xff;
+ if (c < 0x40 || c == 0x7f || c == 0xff)
+ goto ilseq;
+ *s++ = c;
+ len = 2;
+ } else if (wc <= 0x7f) {
+ *s++ = wc;
+ len = 1;
+ } else
+ goto ilseq;
+
+ return (len);
+ilseq:
+ errno = EILSEQ;
+ return ((size_t)-1);
+}
+
+static size_t
+_GB18030_mbsnrtowcs(wchar_t * __restrict dst,
+ const char ** __restrict src, size_t nms, size_t len,
+ mbstate_t * __restrict ps)
+{
+ return (__mbsnrtowcs_std(dst, src, nms, len, ps, _GB18030_mbrtowc));
+}
+
+static size_t
+_GB18030_wcsnrtombs(char * __restrict dst,
+ const wchar_t ** __restrict src, size_t nwc, size_t len,
+ mbstate_t * __restrict ps)
+{
+ return (__wcsnrtombs_std(dst, src, nwc, len, ps, _GB18030_wcrtomb));
+}
diff --git a/lib/libc/locale/gb2312.5 b/lib/libc/locale/gb2312.5
new file mode 100644
index 000000000000..5f1f712097d5
--- /dev/null
+++ b/lib/libc/locale/gb2312.5
@@ -0,0 +1,57 @@
+.\" Copyright (c) 2003 Tim J. Robbins
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd November 7, 2003
+.Dt GB2312 5
+.Os
+.Sh NAME
+.Nm gb2312
+.Nd "GB2312 encoding method for Chinese text"
+.Sh SYNOPSIS
+.Nm ENCODING
+.Qq GB2312
+.Sh DESCRIPTION
+The
+.Nm GB2312
+encoding implements GB\ 2312-1980, a PRC national standard
+for the encoding of simplified Chinese characters.
+.Pp
+Multibyte characters in the GB2312
+encoding can be one byte or two bytes long.
+.No GB\ 11383-1981 Pq Tn ASCII
+characters are represented by single bytes in the range 0x00 to 0x7F.
+Simplified Chinese characters are represented by two bytes, both in
+the range 0xA1-0xFE.
+.Sh SEE ALSO
+.Xr euc 5 ,
+.Xr gb18030 5 ,
+.Xr gbk 5
+.Sh STANDARDS
+The
+.Nm GB2312
+encoding is believed to be compatible with GB\ 2312-1980.
+This standard has been superseded by GB\ 18030-2000, but is still
+in wide use.
diff --git a/lib/libc/locale/gb2312.c b/lib/libc/locale/gb2312.c
new file mode 100644
index 000000000000..032a3e2fff98
--- /dev/null
+++ b/lib/libc/locale/gb2312.c
@@ -0,0 +1,187 @@
+/*-
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
+ * Copyright 2010 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2004 Tim J. Robbins. All rights reserved.
+ * Copyright (c) 2003 David Xu <davidxu@freebsd.org>
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <runetype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include "mblocal.h"
+
+static size_t _GB2312_mbrtowc(wchar_t * __restrict, const char * __restrict,
+ size_t, mbstate_t * __restrict);
+static int _GB2312_mbsinit(const mbstate_t *);
+static size_t _GB2312_wcrtomb(char * __restrict, wchar_t,
+ mbstate_t * __restrict);
+static size_t _GB2312_mbsnrtowcs(wchar_t * __restrict,
+ const char ** __restrict, size_t, size_t,
+ mbstate_t * __restrict);
+static size_t _GB2312_wcsnrtombs(char * __restrict,
+ const wchar_t ** __restrict, size_t, size_t,
+ mbstate_t * __restrict);
+
+
+typedef struct {
+ int count;
+ u_char bytes[2];
+} _GB2312State;
+
+int
+_GB2312_init(struct xlocale_ctype *l, _RuneLocale *rl)
+{
+
+ l->runes = rl;
+ l->__mbrtowc = _GB2312_mbrtowc;
+ l->__wcrtomb = _GB2312_wcrtomb;
+ l->__mbsinit = _GB2312_mbsinit;
+ l->__mbsnrtowcs = _GB2312_mbsnrtowcs;
+ l->__wcsnrtombs = _GB2312_wcsnrtombs;
+ l->__mb_cur_max = 2;
+ l->__mb_sb_limit = 128;
+ return (0);
+}
+
+static int
+_GB2312_mbsinit(const mbstate_t *ps)
+{
+
+ return (ps == NULL || ((const _GB2312State *)ps)->count == 0);
+}
+
+static int
+_GB2312_check(const char *str, size_t n)
+{
+ const u_char *s = (const u_char *)str;
+
+ if (n == 0)
+ /* Incomplete multibyte sequence */
+ return (-2);
+ if (s[0] >= 0xa1 && s[0] <= 0xfe) {
+ if (n < 2)
+ /* Incomplete multibyte sequence */
+ return (-2);
+ if (s[1] < 0xa1 || s[1] > 0xfe)
+ /* Invalid multibyte sequence */
+ return (-1);
+ return (2);
+ } else if (s[0] & 0x80) {
+ /* Invalid multibyte sequence */
+ return (-1);
+ }
+ return (1);
+}
+
+static size_t
+_GB2312_mbrtowc(wchar_t * __restrict pwc, const char * __restrict s, size_t n,
+ mbstate_t * __restrict ps)
+{
+ _GB2312State *gs;
+ wchar_t wc;
+ int i, len, ocount;
+ size_t ncopy;
+
+ gs = (_GB2312State *)ps;
+
+ if (gs->count < 0 || gs->count > sizeof(gs->bytes)) {
+ errno = EINVAL;
+ return ((size_t)-1);
+ }
+
+ if (s == NULL) {
+ s = "";
+ n = 1;
+ pwc = NULL;
+ }
+
+ ncopy = MIN(MIN(n, MB_CUR_MAX), sizeof(gs->bytes) - gs->count);
+ memcpy(gs->bytes + gs->count, s, ncopy);
+ ocount = gs->count;
+ gs->count += ncopy;
+ s = (char *)gs->bytes;
+ n = gs->count;
+
+ if ((len = _GB2312_check(s, n)) < 0)
+ return ((size_t)len);
+ wc = 0;
+ i = len;
+ while (i-- > 0)
+ wc = (wc << 8) | (unsigned char)*s++;
+ if (pwc != NULL)
+ *pwc = wc;
+ gs->count = 0;
+ return (wc == L'\0' ? 0 : len - ocount);
+}
+
+static size_t
+_GB2312_wcrtomb(char * __restrict s, wchar_t wc, mbstate_t * __restrict ps)
+{
+ _GB2312State *gs;
+
+ gs = (_GB2312State *)ps;
+
+ if (gs->count != 0) {
+ errno = EINVAL;
+ return ((size_t)-1);
+ }
+
+ if (s == NULL)
+ /* Reset to initial shift state (no-op) */
+ return (1);
+ if (wc & 0x8000) {
+ *s++ = (wc >> 8) & 0xff;
+ *s = wc & 0xff;
+ return (2);
+ }
+ *s = wc & 0xff;
+ return (1);
+}
+
+static size_t
+_GB2312_mbsnrtowcs(wchar_t * __restrict dst,
+ const char ** __restrict src, size_t nms, size_t len,
+ mbstate_t * __restrict ps)
+{
+ return (__mbsnrtowcs_std(dst, src, nms, len, ps, _GB2312_mbrtowc));
+}
+
+static size_t
+_GB2312_wcsnrtombs(char * __restrict dst,
+ const wchar_t ** __restrict src, size_t nwc, size_t len,
+ mbstate_t * __restrict ps)
+{
+ return (__wcsnrtombs_std(dst, src, nwc, len, ps, _GB2312_wcrtomb));
+}
diff --git a/lib/libc/locale/gbk.5 b/lib/libc/locale/gbk.5
new file mode 100644
index 000000000000..cec22c639540
--- /dev/null
+++ b/lib/libc/locale/gbk.5
@@ -0,0 +1,63 @@
+.\" Copyright (c) 2003 Tim J. Robbins
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd August 10, 2003
+.Dt GBK 5
+.Os
+.Sh NAME
+.Nm gbk
+.Nd "Guojia biaozhun kuozhan (GBK) encoding method for Chinese text"
+.Sh SYNOPSIS
+.Nm ENCODING
+.Qq GBK
+.Sh DESCRIPTION
+GBK is a backwards-compatible extension of the GB\ 2312-1980 encoding
+method for Chinese text, which adds the characters defined in the
+Unified Han portion of the Unicode 2.1 standard.
+.Pp
+Multibyte characters in the GBK
+encoding can be one byte or two bytes long.
+.No GB\ 11383-1981 Pq Tn ASCII
+characters are represented by single bytes in the range 0x00 to 0x7F.
+Chinese characters are represented by two bytes, beginning with a byte in
+the range 0x80-0xFE and ending with a byte in the range 0x40-0xFE.
+.Sh SEE ALSO
+.Xr euc 5 ,
+.Xr gb18030 5 ,
+.Xr gb2312 5 ,
+.Xr utf8 5
+.Rs
+.%Q "The Unicode Consortium"
+.%T "The Unicode Standard, Version 2.1"
+.%D "1999"
+.Re
+.Rs
+.%T "Chinese National Standard GB 18030-2000: Information Technology -- Chinese ideograms coded character set for information interchange -- Extension for the basic set"
+.%D "March 2000"
+.Re
+.Sh STANDARDS
+GBK is not a standard, but has been superseded by
+GB\ 18030-2000.
diff --git a/lib/libc/locale/gbk.c b/lib/libc/locale/gbk.c
new file mode 100644
index 000000000000..c3d16f664a26
--- /dev/null
+++ b/lib/libc/locale/gbk.c
@@ -0,0 +1,197 @@
+/*-
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
+ * Copyright 2010 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2002-2004 Tim J. Robbins. All rights reserved.
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Borman at Krystal Technologies.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <errno.h>
+#include <runetype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include "mblocal.h"
+
+extern int __mb_sb_limit;
+
+static size_t _GBK_mbrtowc(wchar_t * __restrict, const char * __restrict,
+ size_t, mbstate_t * __restrict);
+static int _GBK_mbsinit(const mbstate_t *);
+static size_t _GBK_wcrtomb(char * __restrict, wchar_t,
+ mbstate_t * __restrict);
+static size_t _GBK_mbsnrtowcs(wchar_t * __restrict,
+ const char ** __restrict, size_t, size_t,
+ mbstate_t * __restrict);
+static size_t _GBK_wcsnrtombs(char * __restrict,
+ const wchar_t ** __restrict, size_t, size_t,
+ mbstate_t * __restrict);
+
+typedef struct {
+ wchar_t ch;
+} _GBKState;
+
+int
+_GBK_init(struct xlocale_ctype *l, _RuneLocale *rl)
+{
+
+ l->__mbrtowc = _GBK_mbrtowc;
+ l->__wcrtomb = _GBK_wcrtomb;
+ l->__mbsinit = _GBK_mbsinit;
+ l->__mbsnrtowcs = _GBK_mbsnrtowcs;
+ l->__wcsnrtombs = _GBK_wcsnrtombs;
+ l->runes = rl;
+ l->__mb_cur_max = 2;
+ l->__mb_sb_limit = 128;
+ return (0);
+}
+
+static int
+_GBK_mbsinit(const mbstate_t *ps)
+{
+
+ return (ps == NULL || ((const _GBKState *)ps)->ch == 0);
+}
+
+static int
+_gbk_check(u_int c)
+{
+
+ c &= 0xff;
+ return ((c >= 0x81 && c <= 0xfe) ? 2 : 1);
+}
+
+static size_t
+_GBK_mbrtowc(wchar_t * __restrict pwc, const char * __restrict s, size_t n,
+ mbstate_t * __restrict ps)
+{
+ _GBKState *gs;
+ wchar_t wc;
+ size_t len;
+
+ gs = (_GBKState *)ps;
+
+ if ((gs->ch & ~0xFF) != 0) {
+ /* Bad conversion state. */
+ errno = EINVAL;
+ return ((size_t)-1);
+ }
+
+ if (s == NULL) {
+ s = "";
+ n = 1;
+ pwc = NULL;
+ }
+
+ if (n == 0)
+ /* Incomplete multibyte sequence */
+ return ((size_t)-2);
+
+ if (gs->ch != 0) {
+ if (*s == '\0') {
+ errno = EILSEQ;
+ return ((size_t)-1);
+ }
+ wc = (gs->ch << 8) | (*s & 0xFF);
+ if (pwc != NULL)
+ *pwc = wc;
+ gs->ch = 0;
+ return (1);
+ }
+
+ len = (size_t)_gbk_check(*s);
+ wc = *s++ & 0xff;
+ if (len == 2) {
+ if (n < 2) {
+ /* Incomplete multibyte sequence */
+ gs->ch = wc;
+ return ((size_t)-2);
+ }
+ if (*s == '\0') {
+ errno = EILSEQ;
+ return ((size_t)-1);
+ }
+ wc = (wc << 8) | (*s++ & 0xff);
+ if (pwc != NULL)
+ *pwc = wc;
+ return (2);
+ } else {
+ if (pwc != NULL)
+ *pwc = wc;
+ return (wc == L'\0' ? 0 : 1);
+ }
+}
+
+static size_t
+_GBK_wcrtomb(char * __restrict s, wchar_t wc, mbstate_t * __restrict ps)
+{
+ _GBKState *gs;
+
+ gs = (_GBKState *)ps;
+
+ if (gs->ch != 0) {
+ errno = EINVAL;
+ return ((size_t)-1);
+ }
+
+ if (s == NULL)
+ /* Reset to initial shift state (no-op) */
+ return (1);
+ if (wc & 0x8000) {
+ *s++ = (wc >> 8) & 0xff;
+ *s = wc & 0xff;
+ return (2);
+ }
+ *s = wc & 0xff;
+ return (1);
+}
+
+static size_t
+_GBK_mbsnrtowcs(wchar_t * __restrict dst, const char ** __restrict src,
+ size_t nms, size_t len, mbstate_t * __restrict ps)
+{
+ return (__mbsnrtowcs_std(dst, src, nms, len, ps, _GBK_mbrtowc));
+}
+
+static size_t
+_GBK_wcsnrtombs(char * __restrict dst, const wchar_t ** __restrict src,
+ size_t nwc, size_t len, mbstate_t * __restrict ps)
+{
+ return (__wcsnrtombs_std(dst, src, nwc, len, ps, _GBK_wcrtomb));
+}
diff --git a/lib/libc/locale/isalnum.3 b/lib/libc/locale/isalnum.3
new file mode 100644
index 000000000000..816191793d15
--- /dev/null
+++ b/lib/libc/locale/isalnum.3
@@ -0,0 +1,115 @@
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)isalnum.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd July 17, 2005
+.Dt ISALNUM 3
+.Os
+.Sh NAME
+.Nm isalnum
+.Nd alphanumeric character test
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In ctype.h
+.Ft int
+.Fn isalnum "int c"
+.Ft int
+.Fn isalnum_l "int c" "locale_t loc"
+.Sh DESCRIPTION
+The
+.Fn isalnum
+function tests for any character for which
+.Xr isalpha 3
+or
+.Xr isdigit 3
+is true.
+The value of the argument must be representable as an
+.Vt "unsigned char"
+or the value of
+.Dv EOF .
+.Pp
+In the ASCII character set, this includes the following characters
+(with their numeric values shown in octal):
+.Bl -column \&000_``0''__ \&000_``0''__ \&000_``0''__ \&000_``0''__ \&000_``0''__
+.It "\&060\ ``0''" Ta "061\ ``1''" Ta "062\ ``2''" Ta "063\ ``3''" Ta "064\ ``4''"
+.It "\&065\ ``5''" Ta "066\ ``6''" Ta "067\ ``7''" Ta "070\ ``8''" Ta "071\ ``9''"
+.It "\&101\ ``A''" Ta "102\ ``B''" Ta "103\ ``C''" Ta "104\ ``D''" Ta "105\ ``E''"
+.It "\&106\ ``F''" Ta "107\ ``G''" Ta "110\ ``H''" Ta "111\ ``I''" Ta "112\ ``J''"
+.It "\&113\ ``K''" Ta "114\ ``L''" Ta "115\ ``M''" Ta "116\ ``N''" Ta "117\ ``O''"
+.It "\&120\ ``P''" Ta "121\ ``Q''" Ta "122\ ``R''" Ta "123\ ``S''" Ta "124\ ``T''"
+.It "\&125\ ``U''" Ta "126\ ``V''" Ta "127\ ``W''" Ta "130\ ``X''" Ta "131\ ``Y''"
+.It "\&132\ ``Z''" Ta "141\ ``a''" Ta "142\ ``b''" Ta "143\ ``c''" Ta "144\ ``d''"
+.It "\&145\ ``e''" Ta "146\ ``f''" Ta "147\ ``g''" Ta "150\ ``h''" Ta "151\ ``i''"
+.It "\&152\ ``j''" Ta "153\ ``k''" Ta "154\ ``l''" Ta "155\ ``m''" Ta "156\ ``n''"
+.It "\&157\ ``o''" Ta "160\ ``p''" Ta "161\ ``q''" Ta "162\ ``r''" Ta "163\ ``s''"
+.It "\&164\ ``t''" Ta "165\ ``u''" Ta "166\ ``v''" Ta "167\ ``w''" Ta "170\ ``x''"
+.It "\&171\ ``y''" Ta "172\ ``z''" Ta \& Ta \& Ta \&
+.El
+.Pp
+The
+.Fn isalnum_l
+function takes an explicit locale argument, whereas the
+.Fn isalnum
+function uses the current global or per-thread locale.
+.Sh RETURN VALUES
+The
+.Fn isalnum
+function returns zero if the character tests false and
+returns non-zero if the character tests true.
+.Sh COMPATIBILITY
+The
+.Bx 4.4
+extension of accepting arguments outside of the range of the
+.Vt "unsigned char"
+type in locales with large character sets is considered obsolete
+and may not be supported in future releases.
+The
+.Fn iswalnum
+function should be used instead.
+.Sh SEE ALSO
+.Xr ctype 3 ,
+.Xr isalpha 3 ,
+.Xr isdigit 3 ,
+.Xr iswalnum 3 ,
+.Xr xlocale 3 ,
+.Xr ascii 7
+.Sh STANDARDS
+The
+.Fn isalnum
+function conforms to
+.St -isoC .
+The
+.Fn isalnum_l
+function conforms to
+.St -p1003.1-2008 .
diff --git a/lib/libc/locale/isalpha.3 b/lib/libc/locale/isalpha.3
new file mode 100644
index 000000000000..0ea3a8822ac8
--- /dev/null
+++ b/lib/libc/locale/isalpha.3
@@ -0,0 +1,113 @@
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)isalpha.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd July 17, 2005
+.Dt ISALPHA 3
+.Os
+.Sh NAME
+.Nm isalpha
+.Nd alphabetic character test
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In ctype.h
+.Ft int
+.Fn isalpha "int c"
+.Ft int
+.Fn isalpha_l "int c" "locale_t loc"
+.Sh DESCRIPTION
+The
+.Fn isalpha
+function tests for any character for which
+.Xr isupper 3
+or
+.Xr islower 3
+is true.
+The value of the argument must be representable as an
+.Vt "unsigned char"
+or the value of
+.Dv EOF .
+.Pp
+In the ASCII character set, this includes the following characters
+(with their numeric values shown in octal):
+.Bl -column \&000_``0''__ \&000_``0''__ \&000_``0''__ \&000_``0''__ \&000_``0''__
+.It "\&101\ ``A''" Ta "102\ ``B''" Ta "103\ ``C''" Ta "104\ ``D''" Ta "105\ ``E''"
+.It "\&106\ ``F''" Ta "107\ ``G''" Ta "110\ ``H''" Ta "111\ ``I''" Ta "112\ ``J''"
+.It "\&113\ ``K''" Ta "114\ ``L''" Ta "115\ ``M''" Ta "116\ ``N''" Ta "117\ ``O''"
+.It "\&120\ ``P''" Ta "121\ ``Q''" Ta "122\ ``R''" Ta "123\ ``S''" Ta "124\ ``T''"
+.It "\&125\ ``U''" Ta "126\ ``V''" Ta "127\ ``W''" Ta "130\ ``X''" Ta "131\ ``Y''"
+.It "\&132\ ``Z''" Ta "141\ ``a''" Ta "142\ ``b''" Ta "143\ ``c''" Ta "144\ ``d''"
+.It "\&145\ ``e''" Ta "146\ ``f''" Ta "147\ ``g''" Ta "150\ ``h''" Ta "151\ ``i''"
+.It "\&152\ ``j''" Ta "153\ ``k''" Ta "154\ ``l''" Ta "155\ ``m''" Ta "156\ ``n''"
+.It "\&157\ ``o''" Ta "160\ ``p''" Ta "161\ ``q''" Ta "162\ ``r''" Ta "163\ ``s''"
+.It "\&164\ ``t''" Ta "165\ ``u''" Ta "166\ ``v''" Ta "167\ ``w''" Ta "170\ ``x''"
+.It "\&171\ ``y''" Ta "172\ ``z''" Ta \& Ta \& Ta \&
+.El
+.Pp
+The
+.Fn isalpha_l
+function takes an explicit locale argument, whereas the
+.Fn isalpha
+function uses the current global or per-thread locale.
+.Sh RETURN VALUES
+The
+.Fn isalpha
+function returns zero if the character tests false and
+returns non-zero if the character tests true.
+.Sh COMPATIBILITY
+The
+.Bx 4.4
+extension of accepting arguments outside of the range of the
+.Vt "unsigned char"
+type in locales with large character sets is considered obsolete
+and may not be supported in future releases.
+The
+.Fn iswalpha
+function should be used instead.
+.Sh SEE ALSO
+.Xr ctype 3 ,
+.Xr islower 3 ,
+.Xr isupper 3 ,
+.Xr iswalpha 3 ,
+.Xr xlocale 3 ,
+.Xr ascii 7
+.Sh STANDARDS
+The
+.Fn isalpha
+function conforms to
+.St -isoC .
+The
+.Fn isalpha_l
+function conforms to
+.St -p1003.1-2008 .
diff --git a/lib/libc/locale/isascii.3 b/lib/libc/locale/isascii.3
new file mode 100644
index 000000000000..f7e1325db59d
--- /dev/null
+++ b/lib/libc/locale/isascii.3
@@ -0,0 +1,53 @@
+.\" Copyright (c) 1989, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)isascii.3 8.2 (Berkeley) 12/11/93
+.\" $FreeBSD$
+.\"
+.Dd October 6, 2002
+.Dt ISASCII 3
+.Os
+.Sh NAME
+.Nm isascii
+.Nd test for ASCII character
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In ctype.h
+.Ft int
+.Fn isascii "int c"
+.Sh DESCRIPTION
+The
+.Fn isascii
+function tests for an
+.Tn ASCII
+character, which is any character
+between 0 and octal 0177 inclusive.
+.Sh SEE ALSO
+.Xr ctype 3 ,
+.Xr iswascii 3 ,
+.Xr ascii 7
diff --git a/lib/libc/locale/isblank.3 b/lib/libc/locale/isblank.3
new file mode 100644
index 000000000000..731a88b5bd81
--- /dev/null
+++ b/lib/libc/locale/isblank.3
@@ -0,0 +1,96 @@
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)isblank.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd July 17, 2005
+.Dt ISBLANK 3
+.Os
+.Sh NAME
+.Nm isblank
+.Nd space or tab character test
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In ctype.h
+.Ft int
+.Fn isblank "int c"
+.Ft int
+.Fn isblank_l "int c" "locale_t loc"
+.Sh DESCRIPTION
+The
+.Fn isblank
+function tests for a space or tab character.
+For any locale, this includes the following standard characters:
+.Bl -column XXXX
+.It Do \et Dc Ta Dq " "
+.El
+.Pp
+In the "C" locale, a successful
+.Fn isblank
+test is limited to these characters only.
+The value of the argument must be representable as an
+.Vt "unsigned char"
+or the value of
+.Dv EOF .
+.Pp
+The
+.Fn isblank_l
+function takes an explicit locale argument, whereas the
+.Fn isblank
+function uses the current global or per-thread locale.
+.Sh RETURN VALUES
+The
+.Fn isblank
+function returns zero if the character tests false and
+returns non-zero if the character tests true.
+.Sh COMPATIBILITY
+The
+.Bx 4.4
+extension of accepting arguments outside of the range of the
+.Vt "unsigned char"
+type in locales with large character sets is considered obsolete
+and may not be supported in future releases.
+The
+.Fn iswblank
+function should be used instead.
+.Sh SEE ALSO
+.Xr ctype 3 ,
+.Xr iswblank 3 ,
+.Xr xlocale 3 ,
+.Xr ascii 7
+.Sh STANDARDS
+The
+.Fn isblank
+function
+conforms to
+.St -isoC-99 .
+The
+.Fn isblank_l
+function conforms to
+.St -p1003.1-2008 .
diff --git a/lib/libc/locale/iscntrl.3 b/lib/libc/locale/iscntrl.3
new file mode 100644
index 000000000000..e973f204b4b8
--- /dev/null
+++ b/lib/libc/locale/iscntrl.3
@@ -0,0 +1,103 @@
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)iscntrl.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd July 17, 2005
+.Dt ISCNTRL 3
+.Os
+.Sh NAME
+.Nm iscntrl
+.Nd control character test
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In ctype.h
+.Ft int
+.Fn iscntrl "int c"
+.Ft int
+.Fn iscntrl_l "int c" "locale_t loc"
+.Sh DESCRIPTION
+The
+.Fn iscntrl
+function tests for any control character.
+The value of the argument must be representable as an
+.Vt "unsigned char"
+or the value of
+.Dv EOF .
+.Pp
+In the ASCII character set, this includes the following characters
+(with their numeric values shown in octal):
+.Bl -column \&000_``0''__ \&000_``0''__ \&000_``0''__ \&000_``0''__ \&000_``0''__
+.It "\&000\ NUL" Ta "001\ SOH" Ta "002\ STX" Ta "003\ ETX" Ta "004\ EOT"
+.It "\&005\ ENQ" Ta "006\ ACK" Ta "007\ BEL" Ta "010\ BS" Ta "011\ HT"
+.It "\&012\ NL" Ta "013\ VT" Ta "014\ NP" Ta "015\ CR" Ta "016\ SO"
+.It "\&017\ SI" Ta "020\ DLE" Ta "021\ DC1" Ta "022\ DC2" Ta "023\ DC3"
+.It "\&024\ DC4" Ta "025\ NAK" Ta "026\ SYN" Ta "027\ ETB" Ta "030\ CAN"
+.It "\&031\ EM" Ta "032\ SUB" Ta "033\ ESC" Ta "034\ FS" Ta "035\ GS"
+.It "\&036\ RS" Ta "037\ US" Ta "177\ DEL" Ta \& Ta \&
+.El
+.Pp
+The
+.Fn iscntrl_l
+function takes an explicit locale argument, whereas the
+.Fn iscntrl
+function uses the current global or per-thread locale.
+.Sh RETURN VALUES
+The
+.Fn iscntrl
+function returns zero if the character tests false and
+returns non-zero if the character tests true.
+.Sh COMPATIBILITY
+The
+.Bx 4.4
+extension of accepting arguments outside of the range of the
+.Vt "unsigned char"
+type in locales with large character sets is considered obsolete
+and may not be supported in future releases.
+The
+.Fn iswcntrl
+function should be used instead.
+.Sh SEE ALSO
+.Xr ctype 3 ,
+.Xr iswcntrl 3 ,
+.Xr xlocale 3 ,
+.Xr ascii 7
+.Sh STANDARDS
+The
+.Fn iscntrl
+function conforms to
+.St -isoC .
+The
+.Fn iscntrl_l
+function conforms to
+.St -p1003.1-2008 .
diff --git a/lib/libc/locale/isctype.c b/lib/libc/locale/isctype.c
new file mode 100644
index 000000000000..8f93f1919bfb
--- /dev/null
+++ b/lib/libc/locale/isctype.c
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Borman at Krystal Technologies.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)isctype.c 8.3 (Berkeley) 2/24/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <ctype.h>
+
+#undef digittoint
+int
+digittoint(int c)
+{
+ return (__sbmaskrune(c, 0xFF));
+}
+
+#undef isalnum
+int
+isalnum(int c)
+{
+ return (__sbistype(c, _CTYPE_A|_CTYPE_N));
+}
+
+#undef isalpha
+int
+isalpha(int c)
+{
+ return (__sbistype(c, _CTYPE_A));
+}
+
+#undef isascii
+int
+isascii(int c)
+{
+ return ((c & ~0x7F) == 0);
+}
+
+#undef isblank
+int
+isblank(int c)
+{
+ return (__sbistype(c, _CTYPE_B));
+}
+
+#undef iscntrl
+int
+iscntrl(int c)
+{
+ return (__sbistype(c, _CTYPE_C));
+}
+
+#undef isdigit
+int
+isdigit(int c)
+{
+ return (__isctype(c, _CTYPE_D));
+}
+
+#undef isgraph
+int
+isgraph(int c)
+{
+ return (__sbistype(c, _CTYPE_G));
+}
+
+#undef ishexnumber
+int
+ishexnumber(int c)
+{
+ return (__sbistype(c, _CTYPE_X));
+}
+
+#undef isideogram
+int
+isideogram(int c)
+{
+ return (__sbistype(c, _CTYPE_I));
+}
+
+#undef islower
+int
+islower(int c)
+{
+ return (__sbistype(c, _CTYPE_L));
+}
+
+#undef isnumber
+int
+isnumber(int c)
+{
+ return (__sbistype(c, _CTYPE_N));
+}
+
+#undef isphonogram
+int
+isphonogram(int c)
+{
+ return (__sbistype(c, _CTYPE_Q));
+}
+
+#undef isprint
+int
+isprint(int c)
+{
+ return (__sbistype(c, _CTYPE_R));
+}
+
+#undef ispunct
+int
+ispunct(int c)
+{
+ return (__sbistype(c, _CTYPE_P));
+}
+
+#undef isrune
+int
+isrune(int c)
+{
+ return (__sbistype(c, 0xFFFFFF00L));
+}
+
+#undef isspace
+int
+isspace(int c)
+{
+ return (__sbistype(c, _CTYPE_S));
+}
+
+#undef isspecial
+int
+isspecial(int c)
+{
+ return (__sbistype(c, _CTYPE_T));
+}
+
+#undef isupper
+int
+isupper(int c)
+{
+ return (__sbistype(c, _CTYPE_U));
+}
+
+#undef isxdigit
+int
+isxdigit(int c)
+{
+ return (__isctype(c, _CTYPE_X));
+}
+
+#undef toascii
+int
+toascii(int c)
+{
+ return (c & 0x7F);
+}
+
+#undef tolower
+int
+tolower(int c)
+{
+ return (__sbtolower(c));
+}
+
+#undef toupper
+int
+toupper(int c)
+{
+ return (__sbtoupper(c));
+}
+
diff --git a/lib/libc/locale/isdigit.3 b/lib/libc/locale/isdigit.3
new file mode 100644
index 000000000000..a648ced9c819
--- /dev/null
+++ b/lib/libc/locale/isdigit.3
@@ -0,0 +1,113 @@
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)isdigit.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd May 4, 2007
+.Dt ISDIGIT 3
+.Os
+.Sh NAME
+.Nm isdigit, isnumber
+.Nd decimal-digit character test
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In ctype.h
+.Ft int
+.Fn isdigit "int c"
+.Ft int
+.Fn isnumber "int c"
+.Ft int
+.Fn isdigit_l "int c" "locale_t loc"
+.Ft int
+.Fn isnumber_l "int c" "locale_t loc"
+.Sh DESCRIPTION
+The
+.Fn isdigit
+function tests for a decimal digit character.
+Regardless of locale, this includes the following characters only:
+.Bl -column \&``0''______ \&``0''______ \&``0''______ \&``0''______ \&``0''______
+.It "\&``0''" Ta "``1''" Ta "``2''" Ta "``3''" Ta "``4''"
+.It "\&``5''" Ta "``6''" Ta "``7''" Ta "``8''" Ta "``9''"
+.El
+.Pp
+The
+.Fn isnumber
+function behaves similarly to
+.Fn isdigit ,
+but may recognize additional characters, depending on the current locale
+setting.
+.Pp
+The value of the argument must be representable as an
+.Vt "unsigned char"
+or the value of
+.Dv EOF .
+.Pp
+The _l-suffixed versions take an explicit locale argument, whereas the
+non-suffixed versions use the current global or per-thread locale.
+.Sh RETURN VALUES
+The
+.Fn isdigit
+and
+.Fn isnumber
+functions return zero if the character tests false and
+return non-zero if the character tests true.
+.Sh COMPATIBILITY
+The
+.Bx 4.4
+extension of accepting arguments outside of the range of the
+.Vt "unsigned char"
+type in locales with large character sets is considered obsolete
+and may not be supported in future releases.
+The
+.Fn iswdigit
+function should be used instead.
+.Sh SEE ALSO
+.Xr ctype 3 ,
+.Xr iswdigit 3 ,
+.Xr multibyte 3 ,
+.Xr xlocale 3 ,
+.Xr ascii 7
+.Sh STANDARDS
+The
+.Fn isdigit
+function conforms to
+.St -isoC .
+The
+.Fn isdigit_l
+function conforms to
+.St -p1003.1-2008 .
+.Sh HISTORY
+The
+.Fn isnumber
+function appeared in
+.Bx 4.4 .
diff --git a/lib/libc/locale/isgraph.3 b/lib/libc/locale/isgraph.3
new file mode 100644
index 000000000000..95a8319f669f
--- /dev/null
+++ b/lib/libc/locale/isgraph.3
@@ -0,0 +1,119 @@
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)isgraph.3 8.2 (Berkeley) 12/11/93
+.\" $FreeBSD$
+.\"
+.Dd July 30, 2012
+.Dt ISGRAPH 3
+.Os
+.Sh NAME
+.Nm isgraph
+.Nd printing character test (space character exclusive)
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In ctype.h
+.Ft int
+.Fn isgraph "int c"
+.Ft int
+.Fn isgraph_l "int c" "locale_t loc"
+.Sh DESCRIPTION
+The
+.Fn isgraph
+function tests for any printing character except space
+.Pq Ql "\~"
+and other
+locale-specific space-like characters.
+The value of the argument must be representable as an
+.Vt "unsigned char"
+or the value of
+.Dv EOF .
+.Pp
+In the ASCII character set, this includes the following characters
+(with their numeric values shown in octal):
+.Bl -column \&000_``0''__ \&000_``0''__ \&000_``0''__ \&000_``0''__ \&000_``0''__
+.It "\&041\ ``!''" Ta "042\ ``""''" Ta "043\ ``#''" Ta "044\ ``$''" Ta "045\ ``%''"
+.It "\&046\ ``&''" Ta "047\ ``'''" Ta "050\ ``(''" Ta "051\ ``)''" Ta "052\ ``*''"
+.It "\&053\ ``+''" Ta "054\ ``,''" Ta "055\ ``-''" Ta "056\ ``.''" Ta "057\ ``/''"
+.It "\&060\ ``0''" Ta "061\ ``1''" Ta "062\ ``2''" Ta "063\ ``3''" Ta "064\ ``4''"
+.It "\&065\ ``5''" Ta "066\ ``6''" Ta "067\ ``7''" Ta "070\ ``8''" Ta "071\ ``9''"
+.It "\&072\ ``:''" Ta "073\ ``;''" Ta "074\ ``<''" Ta "075\ ``=''" Ta "076\ ``>''"
+.It "\&077\ ``?''" Ta "100\ ``@''" Ta "101\ ``A''" Ta "102\ ``B''" Ta "103\ ``C''"
+.It "\&104\ ``D''" Ta "105\ ``E''" Ta "106\ ``F''" Ta "107\ ``G''" Ta "110\ ``H''"
+.It "\&111\ ``I''" Ta "112\ ``J''" Ta "113\ ``K''" Ta "114\ ``L''" Ta "115\ ``M''"
+.It "\&116\ ``N''" Ta "117\ ``O''" Ta "120\ ``P''" Ta "121\ ``Q''" Ta "122\ ``R''"
+.It "\&123\ ``S''" Ta "124\ ``T''" Ta "125\ ``U''" Ta "126\ ``V''" Ta "127\ ``W''"
+.It "\&130\ ``X''" Ta "131\ ``Y''" Ta "132\ ``Z''" Ta "133\ ``[''" Ta "134\ ``\e\|''"
+.It "\&135\ ``]''" Ta "136\ ``^''" Ta "137\ ``_''" Ta "140\ ```''" Ta "141\ ``a''"
+.It "\&142\ ``b''" Ta "143\ ``c''" Ta "144\ ``d''" Ta "145\ ``e''" Ta "146\ ``f''"
+.It "\&147\ ``g''" Ta "150\ ``h''" Ta "151\ ``i''" Ta "152\ ``j''" Ta "153\ ``k''"
+.It "\&154\ ``l''" Ta "155\ ``m''" Ta "156\ ``n''" Ta "157\ ``o''" Ta "160\ ``p''"
+.It "\&161\ ``q''" Ta "162\ ``r''" Ta "163\ ``s''" Ta "164\ ``t''" Ta "165\ ``u''"
+.It "\&166\ ``v''" Ta "167\ ``w''" Ta "170\ ``x''" Ta "171\ ``y''" Ta "172\ ``z''"
+.It "\&173\ ``{''" Ta "174\ ``|''" Ta "175\ ``}''" Ta "176\ ``~''" Ta \&
+.El
+.Pp
+The
+.Fn isgraph_l
+function takes an explicit locale argument, whereas the
+.Fn isgraph
+function uses the current global or per-thread locale.
+.Sh RETURN VALUES
+The
+.Fn isgraph
+and
+.Fn isgraph_l
+functions return zero if the character tests false and
+return non-zero if the character tests true.
+.Sh COMPATIBILITY
+The
+.Bx 4.4
+extension of accepting arguments outside of the range of the
+.Vt "unsigned char"
+type in locales with large character sets is considered obsolete
+and may not be supported in future releases.
+The
+.Fn iswgraph
+function should be used instead.
+.Sh SEE ALSO
+.Xr ctype 3 ,
+.Xr iswgraph 3 ,
+.Xr ascii 7
+.Sh STANDARDS
+The
+.Fn isgraph
+function conforms to
+.St -isoC .
+The
+.Fn isgraph_l
+function conforms to
+.St -p1003.1-2008 .
diff --git a/lib/libc/locale/isideogram.3 b/lib/libc/locale/isideogram.3
new file mode 100644
index 000000000000..cbaa625e91df
--- /dev/null
+++ b/lib/libc/locale/isideogram.3
@@ -0,0 +1,57 @@
+.\"
+.\" Copyright (c) 2004 Tim J. Robbins
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd March 30, 2004
+.Dt ISIDEOGRAM 3
+.Os
+.Sh NAME
+.Nm isideogram
+.Nd ideographic character test
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In ctype.h
+.Ft int
+.Fn isideogram "int c"
+.Sh DESCRIPTION
+The
+.Fn isideogram
+function tests for an ideographic character.
+.Sh RETURN VALUES
+The
+.Fn isideogram
+function returns zero if the character tests false and
+returns non-zero if the character tests true.
+.Sh SEE ALSO
+.Xr ctype 3 ,
+.Xr isphonogram 3 ,
+.Xr iswideogram 3
+.Sh HISTORY
+The
+.Fn isideogram
+function appeared in
+.Bx 4.4 .
diff --git a/lib/libc/locale/islower.3 b/lib/libc/locale/islower.3
new file mode 100644
index 000000000000..0b340da7f547
--- /dev/null
+++ b/lib/libc/locale/islower.3
@@ -0,0 +1,103 @@
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)islower.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd July 30, 2012
+.Dt ISLOWER 3
+.Os
+.Sh NAME
+.Nm islower
+.Nd lower-case character test
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In ctype.h
+.Ft int
+.Fn islower "int c"
+.Ft int
+.Fn islower_l "int c" "locale_t loc"
+.Sh DESCRIPTION
+The
+.Fn islower
+function tests for any lower-case letters.
+The value of the argument must be representable as an
+.Vt "unsigned char"
+or the value of
+.Dv EOF .
+.Pp
+In the ASCII character set, this includes the following characters
+(with their numeric values shown in octal):
+.Bl -column \&000_``0''__ \&000_``0''__ \&000_``0''__ \&000_``0''__ \&000_``0''__
+.It "\&141\ ``a''" Ta "142\ ``b''" Ta "143\ ``c''" Ta "144\ ``d''" Ta "145\ ``e''"
+.It "\&146\ ``f''" Ta "147\ ``g''" Ta "150\ ``h''" Ta "151\ ``i''" Ta "152\ ``j''"
+.It "\&153\ ``k''" Ta "154\ ``l''" Ta "155\ ``m''" Ta "156\ ``n''" Ta "157\ ``o''"
+.It "\&160\ ``p''" Ta "161\ ``q''" Ta "162\ ``r''" Ta "163\ ``s''" Ta "164\ ``t''"
+.It "\&165\ ``u''" Ta "166\ ``v''" Ta "167\ ``w''" Ta "170\ ``x''" Ta "171\ ``y''"
+.It "\&172\ ``z''" Ta \& Ta \& Ta \& Ta \&
+.El
+The
+.Fn islower_l
+function takes an explicit locale argument, whereas the
+.Fn islower
+function uses the current global or per-thread locale.
+.Sh RETURN VALUES
+The
+.Fn islower
+and
+.Fn islower_l
+functions return zero if the character tests false and
+return non-zero if the character tests true.
+.Sh COMPATIBILITY
+The
+.Bx 4.4
+extension of accepting arguments outside of the range of the
+.Vt "unsigned char"
+type in locales with large character sets is considered obsolete
+and may not be supported in future releases.
+The
+.Fn iswlower
+function should be used instead.
+.Sh SEE ALSO
+.Xr ctype 3 ,
+.Xr iswlower 3 ,
+.Xr tolower 3 ,
+.Xr ascii 7
+.Sh STANDARDS
+The
+.Fn islower
+function conforms to
+.St -isoC .
+The
+.Fn islower_l
+function conforms to
+.St -p1003.1-2008 .
diff --git a/lib/libc/locale/isphonogram.3 b/lib/libc/locale/isphonogram.3
new file mode 100644
index 000000000000..b0d82c428cba
--- /dev/null
+++ b/lib/libc/locale/isphonogram.3
@@ -0,0 +1,57 @@
+.\"
+.\" Copyright (c) 2004 Tim J. Robbins
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd March 30, 2004
+.Dt ISPHONOGRAM 3
+.Os
+.Sh NAME
+.Nm isphonogram
+.Nd phonographic character test
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In ctype.h
+.Ft int
+.Fn isphonogram "int c"
+.Sh DESCRIPTION
+The
+.Fn isphonogram
+function tests for a phonographic character.
+.Sh RETURN VALUES
+The
+.Fn isphonogram
+function returns zero if the character tests false and
+returns non-zero if the character tests true.
+.Sh SEE ALSO
+.Xr ctype 3 ,
+.Xr isideogram 3 ,
+.Xr iswphonogram 3
+.Sh HISTORY
+The
+.Fn isphonogram
+function appeared in
+.Bx 4.4 .
diff --git a/lib/libc/locale/isprint.3 b/lib/libc/locale/isprint.3
new file mode 100644
index 000000000000..e752c0340294
--- /dev/null
+++ b/lib/libc/locale/isprint.3
@@ -0,0 +1,103 @@
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)isprint.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd July 17, 2005
+.Dt ISPRINT 3
+.Os
+.Sh NAME
+.Nm isprint
+.Nd printing character test (space character inclusive)
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In ctype.h
+.Ft int
+.Fn isprint "int c"
+.Sh DESCRIPTION
+The
+.Fn isprint
+function tests for any printing character, including space
+.Pq Ql "\ " .
+The value of the argument must be representable as an
+.Vt "unsigned char"
+or the value of
+.Dv EOF .
+.Pp
+In the ASCII character set, this includes the following characters
+(with their numeric values shown in octal):
+.Bl -column \&000_``0''__ \&000_``0''__ \&000_``0''__ \&000_``0''__ \&000_``0''__
+.It "\&040\ sp" Ta "041\ ``!''" Ta "042\ ``""''" Ta "043\ ``#''" Ta "044\ ``$''"
+.It "\&045\ ``%''" Ta "046\ ``&''" Ta "047\ ``'''" Ta "050\ ``(''" Ta "051\ ``)''"
+.It "\&052\ ``*''" Ta "053\ ``+''" Ta "054\ ``,''" Ta "055\ ``-''" Ta "056\ ``.''"
+.It "\&057\ ``/''" Ta "060\ ``0''" Ta "061\ ``1''" Ta "062\ ``2''" Ta "063\ ``3''"
+.It "\&064\ ``4''" Ta "065\ ``5''" Ta "066\ ``6''" Ta "067\ ``7''" Ta "070\ ``8''"
+.It "\&071\ ``9''" Ta "072\ ``:''" Ta "073\ ``;''" Ta "074\ ``<''" Ta "075\ ``=''"
+.It "\&076\ ``>''" Ta "077\ ``?''" Ta "100\ ``@''" Ta "101\ ``A''" Ta "102\ ``B''"
+.It "\&103\ ``C''" Ta "104\ ``D''" Ta "105\ ``E''" Ta "106\ ``F''" Ta "107\ ``G''"
+.It "\&110\ ``H''" Ta "111\ ``I''" Ta "112\ ``J''" Ta "113\ ``K''" Ta "114\ ``L''"
+.It "\&115\ ``M''" Ta "116\ ``N''" Ta "117\ ``O''" Ta "120\ ``P''" Ta "121\ ``Q''"
+.It "\&122\ ``R''" Ta "123\ ``S''" Ta "124\ ``T''" Ta "125\ ``U''" Ta "126\ ``V''"
+.It "\&127\ ``W''" Ta "130\ ``X''" Ta "131\ ``Y''" Ta "132\ ``Z''" Ta "133\ ``[''"
+.It "\&134\ ``\e\|''" Ta "135\ ``]''" Ta "136\ ``^''" Ta "137\ ``_''" Ta "140\ ```''"
+.It "\&141\ ``a''" Ta "142\ ``b''" Ta "143\ ``c''" Ta "144\ ``d''" Ta "145\ ``e''"
+.It "\&146\ ``f''" Ta "147\ ``g''" Ta "150\ ``h''" Ta "151\ ``i''" Ta "152\ ``j''"
+.It "\&153\ ``k''" Ta "154\ ``l''" Ta "155\ ``m''" Ta "156\ ``n''" Ta "157\ ``o''"
+.It "\&160\ ``p''" Ta "161\ ``q''" Ta "162\ ``r''" Ta "163\ ``s''" Ta "164\ ``t''"
+.It "\&165\ ``u''" Ta "166\ ``v''" Ta "167\ ``w''" Ta "170\ ``x''" Ta "171\ ``y''"
+.It "\&172\ ``z''" Ta "173\ ``{''" Ta "174\ ``|''" Ta "175\ ``}''" Ta "176\ ``~''"
+.El
+.Sh RETURN VALUES
+The
+.Fn isprint
+function returns zero if the character tests false and
+returns non-zero if the character tests true.
+.Sh COMPATIBILITY
+The
+.Bx 4.4
+extension of accepting arguments outside of the range of the
+.Vt "unsigned char"
+type in locales with large character sets is considered obsolete
+and may not be supported in future releases.
+The
+.Fn iswprint
+function should be used instead.
+.Sh SEE ALSO
+.Xr ctype 3 ,
+.Xr iswprint 3 ,
+.Xr ascii 7
+.Sh STANDARDS
+The
+.Fn isprint
+function conforms to
+.St -isoC .
diff --git a/lib/libc/locale/ispunct.3 b/lib/libc/locale/ispunct.3
new file mode 100644
index 000000000000..c06b25d5380f
--- /dev/null
+++ b/lib/libc/locale/ispunct.3
@@ -0,0 +1,109 @@
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)ispunct.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd July 30, 2012
+.Dt ISPUNCT 3
+.Os
+.Sh NAME
+.Nm ispunct
+.Nd punctuation character test
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In ctype.h
+.Ft int
+.Fn ispunct "int c"
+.Ft int
+.Fn ispunct_l "int c" "locale_t loc"
+.Sh DESCRIPTION
+The
+.Fn ispunct
+function tests for any printing character except for space
+.Pq Ql "\ "
+or a
+character for which
+.Xr isalnum 3
+is true.
+The value of the argument must be representable as an
+.Vt "unsigned char"
+or the value of
+.Dv EOF .
+.Pp
+In the ASCII character set, this includes the following characters
+(with their numeric values shown in octal):
+.Bl -column \&000_``0''__ \&000_``0''__ \&000_``0''__ \&000_``0''__ \&000_``0''__
+.It "\&041\ ``!''" Ta "042\ ``""''" Ta "043\ ``#''" Ta "044\ ``$''" Ta "045\ ``%''"
+.It "\&046\ ``&''" Ta "047\ ``'''" Ta "050\ ``(''" Ta "051\ ``)''" Ta "052\ ``*''"
+.It "\&053\ ``+''" Ta "054\ ``,''" Ta "055\ ``-''" Ta "056\ ``.''" Ta "057\ ``/''"
+.It "\&072\ ``:''" Ta "073\ ``;''" Ta "074\ ``<''" Ta "075\ ``=''" Ta "076\ ``>''"
+.It "\&077\ ``?''" Ta "100\ ``@''" Ta "133\ ``[''" Ta "134\ ``\e\|''" Ta "135\ ``]''"
+.It "\&136\ ``^''" Ta "137\ ``_''" Ta "140\ ```''" Ta "173\ ``{''" Ta "174\ ``|''"
+.It "\&175\ ``}''" Ta "176\ ``~''" Ta \& Ta \& Ta \&
+.El
+.Pp
+The
+.Fn ispunct_l
+function takes an explicit locale argument, whereas the
+.Fn ispunct
+function uses the current global or per-thread locale.
+.Sh RETURN VALUES
+The
+.Fn ispunct
+and
+.Fn ispunct_l
+functions return zero if the character tests false and
+return non-zero if the character tests true.
+.Sh COMPATIBILITY
+The
+.Bx 4.4
+extension of accepting arguments outside of the range of the
+.Vt "unsigned char"
+type in locales with large character sets is considered obsolete
+and may not be supported in future releases.
+The
+.Fn iswpunct
+function should be used instead.
+.Sh SEE ALSO
+.Xr ctype 3 ,
+.Xr iswpunct 3 ,
+.Xr ascii 7
+.Sh STANDARDS
+The
+.Fn ispunct
+function conforms to
+.St -isoC .
+The
+.Fn ispunct_l
+function conforms to
+.St -p1003.1-2008 .
diff --git a/lib/libc/locale/isrune.3 b/lib/libc/locale/isrune.3
new file mode 100644
index 000000000000..424c367d2014
--- /dev/null
+++ b/lib/libc/locale/isrune.3
@@ -0,0 +1,63 @@
+.\"
+.\" Copyright (c) 2004 Tim J. Robbins
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd March 30, 2004
+.Dt ISRUNE 3
+.Os
+.Sh NAME
+.Nm isrune
+.Nd valid character test
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In ctype.h
+.Ft int
+.Fn isrune "int c"
+.Sh DESCRIPTION
+The
+.Fn isrune
+function tests for any character that is valid in the current
+character set.
+In the
+.Tn ASCII
+character set, this is equivalent to
+.Fn isascii .
+.Sh RETURN VALUES
+The
+.Fn isrune
+function returns zero if the character tests false and
+returns non-zero if the character tests true.
+.Sh SEE ALSO
+.Xr ctype 3 ,
+.Xr isascii 3 ,
+.Xr iswrune 3 ,
+.Xr ascii 7
+.Sh HISTORY
+The
+.Fn isrune
+function appeared in
+.Bx 4.4 .
diff --git a/lib/libc/locale/isspace.3 b/lib/libc/locale/isspace.3
new file mode 100644
index 000000000000..5dfd1b608e12
--- /dev/null
+++ b/lib/libc/locale/isspace.3
@@ -0,0 +1,101 @@
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)isspace.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd July 30, 2012
+.Dt ISSPACE 3
+.Os
+.Sh NAME
+.Nm isspace
+.Nd white-space character test
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In ctype.h
+.Ft int
+.Fn isspace "int c"
+.Ft int
+.Fn isspace_l "int c" "locale_t loc"
+.Sh DESCRIPTION
+The
+.Fn isspace
+function tests for white-space characters.
+For any locale, this includes the following standard characters:
+.Bl -column \&`\et''___ \&``\et''___ \&``\et''___ \&``\et''___ \&``\et''___ \&``\et''___
+.It "\&``\et''" Ta "``\en''" Ta "``\ev''" Ta "``\ef''" Ta "``\er''" Ta "`` ''"
+.El
+.Pp
+In the "C" locale,
+.Fn isspace
+returns non-zero for these characters only.
+The value of the argument must be representable as an
+.Vt "unsigned char"
+or the value of
+.Dv EOF .
+.Pp
+The
+.Fn isspace_l
+function takes an explicit locale argument, whereas the
+.Fn isspace
+function uses the current global or per-thread locale.
+.Sh RETURN VALUES
+The
+.Fn isspace
+and
+.Fn isspace_l
+functions return zero if the character tests false and
+return non-zero if the character tests true.
+.Sh COMPATIBILITY
+The
+.Bx 4.4
+extension of accepting arguments outside of the range of the
+.Vt "unsigned char"
+type in locales with large character sets is considered obsolete
+and may not be supported in future releases.
+The
+.Fn iswspace
+function should be used instead.
+.Sh SEE ALSO
+.Xr ctype 3 ,
+.Xr iswspace 3 ,
+.Xr multibyte 3 ,
+.Xr ascii 7
+.Sh STANDARDS
+The
+.Fn isspace
+function conforms to
+.St -isoC .
+The
+.Fn isspace_l
+function conforms to
+.St -p1003.1-2008 .
diff --git a/lib/libc/locale/isspecial.3 b/lib/libc/locale/isspecial.3
new file mode 100644
index 000000000000..de361d28f96b
--- /dev/null
+++ b/lib/libc/locale/isspecial.3
@@ -0,0 +1,56 @@
+.\"
+.\" Copyright (c) 2004 Tim J. Robbins
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd March 30, 2004
+.Dt ISSPECIAL 3
+.Os
+.Sh NAME
+.Nm isspecial
+.Nd special character test
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In ctype.h
+.Ft int
+.Fn isspecial "int c"
+.Sh DESCRIPTION
+The
+.Fn isspecial
+function tests for a special character.
+.Sh RETURN VALUES
+The
+.Fn isspecial
+function returns zero if the character tests false and
+returns non-zero if the character tests true.
+.Sh SEE ALSO
+.Xr ctype 3 ,
+.Xr iswspecial 3
+.Sh HISTORY
+The
+.Fn isspecial
+function appeared in
+.Bx 4.4 .
diff --git a/lib/libc/locale/isupper.3 b/lib/libc/locale/isupper.3
new file mode 100644
index 000000000000..570e076518d9
--- /dev/null
+++ b/lib/libc/locale/isupper.3
@@ -0,0 +1,90 @@
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)isupper.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd July 17, 2005
+.Dt ISUPPER 3
+.Os
+.Sh NAME
+.Nm isupper
+.Nd upper-case character test
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In ctype.h
+.Ft int
+.Fn isupper "int c"
+.Sh DESCRIPTION
+The
+.Fn isupper
+function tests for any upper-case letter.
+The value of the argument must be representable as an
+.Vt "unsigned char"
+or the value of
+.Dv EOF .
+.Pp
+In the ASCII character set, this includes the following characters
+(with their numeric values shown in octal):
+.Bl -column \&000_``0''__ \&000_``0''__ \&000_``0''__ \&000_``0''__ \&000_``0''__
+.It "\&101\ ``A''" Ta "102\ ``B''" Ta "103\ ``C''" Ta "104\ ``D''" Ta "105\ ``E''"
+.It "\&106\ ``F''" Ta "107\ ``G''" Ta "110\ ``H''" Ta "111\ ``I''" Ta "112\ ``J''"
+.It "\&113\ ``K''" Ta "114\ ``L''" Ta "115\ ``M''" Ta "116\ ``N''" Ta "117\ ``O''"
+.It "\&120\ ``P''" Ta "121\ ``Q''" Ta "122\ ``R''" Ta "123\ ``S''" Ta "124\ ``T''"
+.It "\&125\ ``U''" Ta "126\ ``V''" Ta "127\ ``W''" Ta "130\ ``X''" Ta "131\ ``Y''"
+.It "\&132\ ``Z''" Ta \& Ta \& Ta \& Ta \&
+.El
+.Sh RETURN VALUES
+The
+.Fn isupper
+function returns zero if the character tests false and
+returns non-zero if the character tests true.
+.Sh COMPATIBILITY
+The
+.Bx 4.4
+extension of accepting arguments outside of the range of the
+.Vt "unsigned char"
+type in locales with large character sets is considered obsolete
+and may not be supported in future releases.
+The
+.Fn iswupper
+function should be used instead.
+.Sh SEE ALSO
+.Xr ctype 3 ,
+.Xr iswupper 3 ,
+.Xr toupper 3 ,
+.Xr ascii 7
+.Sh STANDARDS
+The
+.Fn isupper
+function conforms to
+.St -isoC .
diff --git a/lib/libc/locale/iswalnum.3 b/lib/libc/locale/iswalnum.3
new file mode 100644
index 000000000000..89960974f19d
--- /dev/null
+++ b/lib/libc/locale/iswalnum.3
@@ -0,0 +1,158 @@
+.\" $NetBSD: iswalnum.3,v 1.5 2002/07/10 14:46:10 yamt Exp $
+.\"
+.\" Copyright (c) 1991 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)isalnum.3 5.2 (Berkeley) 6/29/91
+.\" $FreeBSD$
+.\"
+.Dd October 3, 2002
+.Dt ISWALNUM 3
+.Os
+.Sh NAME
+.Nm iswalnum ,
+.Nm iswalpha ,
+.Nm iswascii ,
+.Nm iswblank ,
+.Nm iswcntrl ,
+.Nm iswdigit ,
+.Nm iswgraph ,
+.Nm iswhexnumber ,
+.Nm iswideogram ,
+.Nm iswlower ,
+.Nm iswnumber ,
+.Nm iswphonogram ,
+.Nm iswprint ,
+.Nm iswpunct ,
+.Nm iswrune ,
+.Nm iswspace ,
+.Nm iswspecial ,
+.Nm iswupper ,
+.Nm iswxdigit
+.Nd wide character classification utilities
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In wctype.h
+.Ft int
+.Fn iswalnum "wint_t wc"
+.Ft int
+.Fn iswalpha "wint_t wc"
+.Ft int
+.Fn iswascii "wint_t wc"
+.Ft int
+.Fn iswblank "wint_t wc"
+.Ft int
+.Fn iswcntrl "wint_t wc"
+.Ft int
+.Fn iswdigit "wint_t wc"
+.Ft int
+.Fn iswgraph "wint_t wc"
+.Ft int
+.Fn iswhexnumber "wint_t wc"
+.Ft int
+.Fn iswideogram "wint_t wc"
+.Ft int
+.Fn iswlower "wint_t wc"
+.Ft int
+.Fn iswnumber "wint_t wc"
+.Ft int
+.Fn iswphonogram "wint_t wc"
+.Ft int
+.Fn iswprint "wint_t wc"
+.Ft int
+.Fn iswpunct "wint_t wc"
+.Ft int
+.Fn iswrune "wint_t wc"
+.Ft int
+.Fn iswspace "wint_t wc"
+.Ft int
+.Fn iswspecial "wint_t wc"
+.Ft int
+.Fn iswupper "wint_t wc"
+.Ft int
+.Fn iswxdigit "wint_t wc"
+.Sh DESCRIPTION
+The above functions are character classification utility functions,
+for use with wide characters
+.Vt ( wchar_t
+or
+.Vt wint_t ) .
+See the description for the similarly-named single byte classification
+functions (like
+.Xr isalnum 3 ) ,
+for details.
+.Sh RETURN VALUES
+The functions return zero if the character tests false and
+return non-zero if the character tests true.
+.Sh SEE ALSO
+.Xr isalnum 3 ,
+.Xr isalpha 3 ,
+.Xr isascii 3 ,
+.Xr isblank 3 ,
+.Xr iscntrl 3 ,
+.Xr isdigit 3 ,
+.Xr isgraph 3 ,
+.Xr ishexnumber 3 ,
+.Xr isideogram 3 ,
+.Xr islower 3 ,
+.Xr isnumber 3 ,
+.Xr isphonogram 3 ,
+.Xr isprint 3 ,
+.Xr ispunct 3 ,
+.Xr isrune 3 ,
+.Xr isspace 3 ,
+.Xr isspecial 3 ,
+.Xr isupper 3 ,
+.Xr isxdigit 3 ,
+.Xr wctype 3
+.Sh STANDARDS
+These functions conform to
+.St -p1003.1-2001 ,
+except
+.Fn iswascii ,
+.Fn iswhexnumber ,
+.Fn iswideogram ,
+.Fn iswnumber ,
+.Fn iswphonogram ,
+.Fn iswrune
+and
+.Fn iswspecial ,
+which are
+.Fx
+extensions.
+.Sh CAVEATS
+The result of these functions is undefined unless
+the argument is
+.Dv WEOF
+or a valid
+.Vt wchar_t
+value for the current locale.
diff --git a/lib/libc/locale/iswalnum_l.3 b/lib/libc/locale/iswalnum_l.3
new file mode 100644
index 000000000000..21ee48fa7b5b
--- /dev/null
+++ b/lib/libc/locale/iswalnum_l.3
@@ -0,0 +1,168 @@
+.\" Copyright (c) 2012 Isabell Long <issyl0@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 July 25, 2012
+.Dt ISWALNUM_L 3
+.Os
+.Sh NAME
+.Nm iswalnum_l ,
+.Nm iswalpha_l ,
+.Nm iswcntrl_l ,
+.Nm iswctype_l ,
+.Nm iswdigit_l ,
+.Nm iswgraph_l ,
+.Nm iswlower_l ,
+.Nm iswprint_l ,
+.Nm iswpunct_l ,
+.Nm iswspace_l ,
+.Nm iswupper_l ,
+.Nm iswxdigit_l ,
+.Nm towlower_l ,
+.Nm towupper_l ,
+.Nm wctype_l ,
+.Nm iswblank_l ,
+.Nm iswhexnumber_l ,
+.Nm iswideogram_l ,
+.Nm iswnumber_l ,
+.Nm iswphonogram_l ,
+.Nm iswrune_l ,
+.Nm iswspecial_l ,
+.Nm nextwctype_l ,
+.Nm towctrans_l ,
+.Nm wctrans_l
+.Nd wide character classification utilities
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In wctype.h
+.Ft int
+.Fn iswalnum_l "wint_t wc" "locale_t loc"
+.Ft int
+.Fn iswalpha_l "wint_t wc" "locale_t loc"
+.Ft int
+.Fn iswcntrl_l "wint_t wc" "locale_t loc"
+.Ft int
+.Fn iswctype_l "wint_t wc" "locale_t loc"
+.Ft int
+.Fn iswdigit_l "wint_t wc" "locale_t loc"
+.Ft int
+.Fn iswgraph_l "wint_t wc" "locale_t loc"
+.Ft int
+.Fn iswlower_l "wint_t wc" "locale_t loc"
+.Ft int
+.Fn iswprint_l "wint_t wc" "locale_t loc"
+.Ft int
+.Fn iswpunct_l "wint_t wc" "locale_t loc"
+.Ft int
+.Fn iswspace_l "wint_t wc" "locale_t loc"
+.Ft int
+.Fn iswupper_l "wint_t wc" "locale_t loc"
+.Ft int
+.Fn iswxdigit_l "wint_t wc" "locale_t loc"
+.Ft wint_t
+.Fn towlower_l "wint_t wc" "locale_t loc"
+.Ft wint_t
+.Fn towupper_l "wint_t wc" "locale_t loc"
+.Ft wctype_t
+.Fn wctype_l "wint_t wc" "locale_t loc"
+.Ft int
+.Fn iswblank_l "wint_t wc" "locale_t loc"
+.Ft int
+.Fn iswhexnumber_l "wint_t wc" "locale_t loc"
+.Ft int
+.Fn iswideogram_l "wint_t wc" "locale_t loc"
+.Ft int
+.Fn iswnumber_l "wint_t wc" "locale_t loc"
+.Ft int
+.Fn iswphonogram_l "wint_t wc" "locale_t loc"
+.Ft int
+.Fn iswrune_l "wint_t wc" "locale_t loc"
+.Ft int
+.Fn iswspecial_l "wint_t wc" "locale_t loc"
+.Ft wint_t
+.Fn nextwctype_l "wint_t wc" "locale_t loc"
+.Ft wint_t
+.Fn towctrans_l "wint_t wc" "wctrans_t" "locale_t loc"
+.Ft wctrans_t
+.Fn wctrans_l "const char *" "locale_t loc"
+.Sh DESCRIPTION
+The above functions are character classification utility functions,
+for use with wide characters
+.Vt ( wchar_t
+or
+.Vt wint_t )
+in the locale
+.Fa loc .
+They behave in the same way as the versions without the _l suffix, but use
+the specified locale rather than the global or per-thread locale.
+These functions may be implemented as inline functions in
+.In wctype.h
+and as functions in the C library.
+See the specific manual pages for more information.
+.Sh RETURN VALUES
+These functions return the same things as their non-locale versions.
+If the locale is invalid, their behaviors are undefined.
+.Sh SEE ALSO
+.Xr iswalnum 3 ,
+.Xr iswalpha 3 ,
+.Xr iswblank 3 ,
+.Xr iswcntrl 3 ,
+.Xr iswctype 3 ,
+.Xr iswdigit 3 ,
+.Xr iswgraph 3 ,
+.Xr iswhexnumber 3 ,
+.Xr iswideogram 3 ,
+.Xr iswlower 3 ,
+.Xr iswnumber 3 ,
+.Xr iswphonogram 3 ,
+.Xr iswprint 3 ,
+.Xr iswpunct 3 ,
+.Xr iswrune 3 ,
+.Xr iswspace 3 ,
+.Xr iswspecial 3 ,
+.Xr iswupper 3 ,
+.Xr iswxdigit 3 ,
+.Xr nextwctype 3 ,
+.Xr towctrans 3 ,
+.Xr towlower 3 ,
+.Xr towupper 3 ,
+.Xr wctrans 3 ,
+.Xr wctype 3
+.Sh STANDARDS
+These functions conform to
+.St -p1003.1-2008 ,
+except for
+.Fn iswascii_l ,
+.Fn iswhexnumber_l ,
+.Fn iswideogram_l ,
+.Fn iswphonogram_l ,
+.Fn iswrune_l ,
+.Fn iswspecial_l
+and
+.Fn nextwctype_l
+which are
+.Fx
+extensions.
diff --git a/lib/libc/locale/iswctype.c b/lib/libc/locale/iswctype.c
new file mode 100644
index 000000000000..dad0621bebd5
--- /dev/null
+++ b/lib/libc/locale/iswctype.c
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Borman at Krystal Technologies.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <wctype.h>
+
+#undef iswalnum
+int
+iswalnum(wint_t wc)
+{
+ return (__istype(wc, _CTYPE_A|_CTYPE_N));
+}
+
+#undef iswalpha
+int
+iswalpha(wint_t wc)
+{
+ return (__istype(wc, _CTYPE_A));
+}
+
+#undef iswascii
+int
+iswascii(wint_t wc)
+{
+ return ((wc & ~0x7F) == 0);
+}
+
+#undef iswblank
+int
+iswblank(wint_t wc)
+{
+ return (__istype(wc, _CTYPE_B));
+}
+
+#undef iswcntrl
+int
+iswcntrl(wint_t wc)
+{
+ return (__istype(wc, _CTYPE_C));
+}
+
+#undef iswdigit
+int
+iswdigit(wint_t wc)
+{
+ return (__istype(wc, _CTYPE_D));
+}
+
+#undef iswgraph
+int
+iswgraph(wint_t wc)
+{
+ return (__istype(wc, _CTYPE_G));
+}
+
+#undef iswhexnumber
+int
+iswhexnumber(wint_t wc)
+{
+ return (__istype(wc, _CTYPE_X));
+}
+
+#undef iswideogram
+int
+iswideogram(wint_t wc)
+{
+ return (__istype(wc, _CTYPE_I));
+}
+
+#undef iswlower
+int
+iswlower(wint_t wc)
+{
+ return (__istype(wc, _CTYPE_L));
+}
+
+#undef iswnumber
+int
+iswnumber(wint_t wc)
+{
+ return (__istype(wc, _CTYPE_N));
+}
+
+#undef iswphonogram
+int
+iswphonogram(wint_t wc)
+{
+ return (__istype(wc, _CTYPE_Q));
+}
+
+#undef iswprint
+int
+iswprint(wint_t wc)
+{
+ return (__istype(wc, _CTYPE_R));
+}
+
+#undef iswpunct
+int
+iswpunct(wint_t wc)
+{
+ return (__istype(wc, _CTYPE_P));
+}
+
+#undef iswrune
+int
+iswrune(wint_t wc)
+{
+ return (__istype(wc, 0xFFFFFF00L));
+}
+
+#undef iswspace
+int
+iswspace(wint_t wc)
+{
+ return (__istype(wc, _CTYPE_S));
+}
+
+#undef iswspecial
+int
+iswspecial(wint_t wc)
+{
+ return (__istype(wc, _CTYPE_T));
+}
+
+#undef iswupper
+int
+iswupper(wint_t wc)
+{
+ return (__istype(wc, _CTYPE_U));
+}
+
+#undef iswxdigit
+int
+iswxdigit(wint_t wc)
+{
+ return (__istype(wc, _CTYPE_X));
+}
+
+#undef towlower
+wint_t
+towlower(wint_t wc)
+{
+ return (__tolower(wc));
+}
+
+#undef towupper
+wint_t
+towupper(wint_t wc)
+{
+ return (__toupper(wc));
+}
+
diff --git a/lib/libc/locale/isxdigit.3 b/lib/libc/locale/isxdigit.3
new file mode 100644
index 000000000000..eb9f8d5b861e
--- /dev/null
+++ b/lib/libc/locale/isxdigit.3
@@ -0,0 +1,101 @@
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)isxdigit.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd July 17, 2005
+.Dt ISXDIGIT 3
+.Os
+.Sh NAME
+.Nm isxdigit, ishexnumber
+.Nd hexadecimal-digit character test
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In ctype.h
+.Ft int
+.Fn isxdigit "int c"
+.Ft int
+.Fn ishexnumber "int c"
+.Sh DESCRIPTION
+The
+.Fn isxdigit
+function tests for any hexadecimal-digit character.
+Regardless of locale, this includes the following characters only:
+.Bl -column \&``0''______ \&``0''______ \&``0''______ \&``0''______ \&``0''______
+.It "\&``0''" Ta "``1''" Ta "``2''" Ta "``3''" Ta "``4''"
+.It "\&``5''" Ta "``6''" Ta "``7''" Ta "``8''" Ta "``9''"
+.It "\&``A''" Ta "``B''" Ta "``C''" Ta "``D''" Ta "``E''"
+.It "\&``F''" Ta "``a''" Ta "``b''" Ta "``c''" Ta "``d''"
+.It "\&``e''" Ta "``f''" Ta \& Ta \& Ta \&
+.El
+.Pp
+The
+.Fn ishexnumber
+function behaves similarly to
+.Fn isxdigit ,
+but may recognize additional characters,
+depending on the current locale setting.
+.Pp
+The value of the argument must be representable as an
+.Vt "unsigned char"
+or the value of
+.Dv EOF .
+.Sh RETURN VALUES
+The
+.Fn isxdigit
+function returns zero if the character tests false and
+returns non-zero if the character tests true.
+.Sh COMPATIBILITY
+The
+.Bx 4.4
+extension of accepting arguments outside of the range of the
+.Vt "unsigned char"
+type in locales with large character sets is considered obsolete
+and may not be supported in future releases.
+The
+.Fn iswxdigit
+function should be used instead.
+.Sh SEE ALSO
+.Xr ctype 3 ,
+.Xr iswxdigit 3 ,
+.Xr ascii 7
+.Sh STANDARDS
+The
+.Fn isxdigit
+function conforms to
+.St -isoC .
+.Sh HISTORY
+The
+.Fn ishexnumber
+function appeared in
+.Bx 4.4 .
diff --git a/lib/libc/locale/ldpart.c b/lib/libc/locale/ldpart.c
new file mode 100644
index 000000000000..ccf5e7f81fb9
--- /dev/null
+++ b/lib/libc/locale/ldpart.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+#include "ldpart.h"
+#include "setlocale.h"
+
+static int split_lines(char *, const char *);
+
+int
+__part_load_locale(const char *name,
+ int *using_locale,
+ char **locale_buf,
+ const char *category_filename,
+ int locale_buf_size_max,
+ int locale_buf_size_min,
+ const char **dst_localebuf)
+{
+ int saverr, fd, i, num_lines;
+ char *lbuf, *p;
+ const char *plim;
+ char filename[PATH_MAX];
+ struct stat st;
+ size_t namesize, bufsize;
+
+ /* 'name' must be already checked. */
+ if (strcmp(name, "C") == 0 || strcmp(name, "POSIX") == 0) {
+ *using_locale = 0;
+ return (_LDP_CACHE);
+ }
+
+ /*
+ * If the locale name is the same as our cache, use the cache.
+ */
+ if (*locale_buf != NULL && strcmp(name, *locale_buf) == 0) {
+ *using_locale = 1;
+ return (_LDP_CACHE);
+ }
+
+ /*
+ * Slurp the locale file into the cache.
+ */
+ namesize = strlen(name) + 1;
+
+ /* 'PathLocale' must be already set & checked. */
+
+ /* Range checking not needed, 'name' size is limited */
+ strcpy(filename, _PathLocale);
+ strcat(filename, "/");
+ strcat(filename, name);
+ strcat(filename, "/");
+ strcat(filename, category_filename);
+ if ((fd = _open(filename, O_RDONLY | O_CLOEXEC)) < 0)
+ return (_LDP_ERROR);
+ if (_fstat(fd, &st) != 0)
+ goto bad_locale;
+ if (st.st_size <= 0) {
+ errno = EFTYPE;
+ goto bad_locale;
+ }
+ bufsize = namesize + st.st_size;
+ if ((lbuf = malloc(bufsize)) == NULL) {
+ errno = ENOMEM;
+ goto bad_locale;
+ }
+ (void)strcpy(lbuf, name);
+ p = lbuf + namesize;
+ plim = p + st.st_size;
+ if (_read(fd, p, (size_t) st.st_size) != st.st_size)
+ goto bad_lbuf;
+ /*
+ * Parse the locale file into localebuf.
+ */
+ if (plim[-1] != '\n') {
+ errno = EFTYPE;
+ goto bad_lbuf;
+ }
+ num_lines = split_lines(p, plim);
+ if (num_lines >= locale_buf_size_max)
+ num_lines = locale_buf_size_max;
+ else if (num_lines >= locale_buf_size_min)
+ num_lines = locale_buf_size_min;
+ else {
+ errno = EFTYPE;
+ goto bad_lbuf;
+ }
+ (void)_close(fd);
+ /*
+ * Record the successful parse in the cache.
+ */
+ if (*locale_buf != NULL)
+ free(*locale_buf);
+ *locale_buf = lbuf;
+ for (p = *locale_buf, i = 0; i < num_lines; i++)
+ dst_localebuf[i] = (p += strlen(p) + 1);
+ for (i = num_lines; i < locale_buf_size_max; i++)
+ dst_localebuf[i] = NULL;
+ *using_locale = 1;
+
+ return (_LDP_LOADED);
+
+bad_lbuf:
+ saverr = errno;
+ free(lbuf);
+ errno = saverr;
+bad_locale:
+ saverr = errno;
+ (void)_close(fd);
+ errno = saverr;
+
+ return (_LDP_ERROR);
+}
+
+static int
+split_lines(char *p, const char *plim)
+{
+ int i;
+
+ i = 0;
+ while (p < plim) {
+ if (*p == '\n') {
+ *p = '\0';
+ i++;
+ }
+ p++;
+ }
+ return (i);
+}
+
diff --git a/lib/libc/locale/ldpart.h b/lib/libc/locale/ldpart.h
new file mode 100644
index 000000000000..45f7339fe8fb
--- /dev/null
+++ b/lib/libc/locale/ldpart.h
@@ -0,0 +1,39 @@
+/*-
+ * Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LDPART_H_
+#define _LDPART_H_
+
+#define _LDP_LOADED 0
+#define _LDP_ERROR (-1)
+#define _LDP_CACHE 1
+
+int __part_load_locale(const char *, int*, char **, const char *,
+ int, int, const char **);
+
+#endif /* !_LDPART_H_ */
diff --git a/lib/libc/locale/lmessages.c b/lib/libc/locale/lmessages.c
new file mode 100644
index 000000000000..a0664d074ecd
--- /dev/null
+++ b/lib/libc/locale/lmessages.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2001 Alexey Zelkin <phantom@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 <stddef.h>
+
+#include "ldpart.h"
+#include "lmessages.h"
+
+#define LCMESSAGES_SIZE_FULL (sizeof(struct lc_messages_T) / sizeof(char *))
+#define LCMESSAGES_SIZE_MIN \
+ (offsetof(struct lc_messages_T, yesstr) / sizeof(char *))
+
+struct xlocale_messages {
+ struct xlocale_component header;
+ char *buffer;
+ struct lc_messages_T locale;
+};
+
+struct xlocale_messages __xlocale_global_messages;
+
+static char empty[] = "";
+
+static const struct lc_messages_T _C_messages_locale = {
+ "^[yY]" , /* yesexpr */
+ "^[nN]" , /* noexpr */
+ "yes" , /* yesstr */
+ "no" /* nostr */
+};
+
+static void destruct_messages(void *v)
+{
+ struct xlocale_messages *l = v;
+ if (l->buffer)
+ free(l->buffer);
+ free(l);
+}
+
+static int
+messages_load_locale(struct xlocale_messages *loc, int *using_locale, const char *name)
+{
+ int ret;
+ struct lc_messages_T *l = &loc->locale;
+
+ ret = __part_load_locale(name, using_locale,
+ &loc->buffer, "LC_MESSAGES",
+ LCMESSAGES_SIZE_FULL, LCMESSAGES_SIZE_MIN,
+ (const char **)l);
+ if (ret == _LDP_LOADED) {
+ if (l->yesstr == NULL)
+ l->yesstr = empty;
+ if (l->nostr == NULL)
+ l->nostr = empty;
+ }
+ return (ret);
+}
+int
+__messages_load_locale(const char *name)
+{
+ return messages_load_locale(&__xlocale_global_messages,
+ &__xlocale_global_locale.using_messages_locale, name);
+}
+void *
+__messages_load(const char *name, locale_t l)
+{
+ struct xlocale_messages *new = calloc(sizeof(struct xlocale_messages), 1);
+ new->header.header.destructor = destruct_messages;
+ if (messages_load_locale(new, &l->using_messages_locale, name) == _LDP_ERROR) {
+ xlocale_release(new);
+ return NULL;
+ }
+ return new;
+}
+
+struct lc_messages_T *
+__get_current_messages_locale(locale_t loc)
+{
+ return (loc->using_messages_locale
+ ? &((struct xlocale_messages *)loc->components[XLC_MESSAGES])->locale
+ : (struct lc_messages_T *)&_C_messages_locale);
+}
+
+#ifdef LOCALE_DEBUG
+void
+msgdebug() {
+printf( "yesexpr = %s\n"
+ "noexpr = %s\n"
+ "yesstr = %s\n"
+ "nostr = %s\n",
+ _messages_locale.yesexpr,
+ _messages_locale.noexpr,
+ _messages_locale.yesstr,
+ _messages_locale.nostr
+);
+}
+#endif /* LOCALE_DEBUG */
diff --git a/lib/libc/locale/lmessages.h b/lib/libc/locale/lmessages.h
new file mode 100644
index 000000000000..ea9c57e28943
--- /dev/null
+++ b/lib/libc/locale/lmessages.h
@@ -0,0 +1,49 @@
+/*-
+ * Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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 _LMESSAGES_H_
+#define _LMESSAGES_H_
+
+#include "xlocale_private.h"
+
+struct lc_messages_T {
+ const char *yesexpr;
+ const char *noexpr;
+ const char *yesstr;
+ const char *nostr;
+};
+
+struct lc_messages_T *__get_current_messages_locale(locale_t);
+int __messages_load_locale(const char *);
+
+#endif /* !_LMESSAGES_H_ */
diff --git a/lib/libc/locale/lmonetary.c b/lib/libc/locale/lmonetary.c
new file mode 100644
index 000000000000..84eccdb6ab32
--- /dev/null
+++ b/lib/libc/locale/lmonetary.c
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 <limits.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+#include "ldpart.h"
+#include "lmonetary.h"
+
+extern const char * __fix_locale_grouping_str(const char *);
+
+#define LCMONETARY_SIZE_FULL (sizeof(struct lc_monetary_T) / sizeof(char *))
+#define LCMONETARY_SIZE_MIN \
+ (offsetof(struct lc_monetary_T, int_p_cs_precedes) / \
+ sizeof(char *))
+
+static char empty[] = "";
+static char numempty[] = { CHAR_MAX, '\0'};
+
+static const struct lc_monetary_T _C_monetary_locale = {
+ empty, /* int_curr_symbol */
+ empty, /* currency_symbol */
+ empty, /* mon_decimal_point */
+ empty, /* mon_thousands_sep */
+ numempty, /* mon_grouping */
+ empty, /* positive_sign */
+ empty, /* negative_sign */
+ numempty, /* int_frac_digits */
+ numempty, /* frac_digits */
+ numempty, /* p_cs_precedes */
+ numempty, /* p_sep_by_space */
+ numempty, /* n_cs_precedes */
+ numempty, /* n_sep_by_space */
+ numempty, /* p_sign_posn */
+ numempty, /* n_sign_posn */
+ numempty, /* int_p_cs_precedes */
+ numempty, /* int_n_cs_precedes */
+ numempty, /* int_p_sep_by_space */
+ numempty, /* int_n_sep_by_space */
+ numempty, /* int_p_sign_posn */
+ numempty /* int_n_sign_posn */
+};
+
+struct xlocale_monetary __xlocale_global_monetary;
+
+static char
+cnv(const char *str)
+{
+ int i = strtol(str, NULL, 10);
+
+ if (i == -1)
+ i = CHAR_MAX;
+ return ((char)i);
+}
+
+static void
+destruct_monetary(void *v)
+{
+ struct xlocale_monetary *l = v;
+ if (l->buffer)
+ free(l->buffer);
+ free(l);
+}
+
+static int
+monetary_load_locale_l(struct xlocale_monetary *loc, int *using_locale,
+ int *changed, const char *name)
+{
+ int ret;
+ struct lc_monetary_T *l = &loc->locale;
+
+ ret = __part_load_locale(name, using_locale,
+ &loc->buffer, "LC_MONETARY",
+ LCMONETARY_SIZE_FULL, LCMONETARY_SIZE_MIN,
+ (const char **)l);
+ if (ret != _LDP_ERROR)
+ *changed = 1;
+ if (ret == _LDP_LOADED) {
+ l->mon_grouping =
+ __fix_locale_grouping_str(l->mon_grouping);
+
+#define M_ASSIGN_CHAR(NAME) (((char *)l->NAME)[0] = \
+ cnv(l->NAME))
+
+ M_ASSIGN_CHAR(int_frac_digits);
+ M_ASSIGN_CHAR(frac_digits);
+ M_ASSIGN_CHAR(p_cs_precedes);
+ M_ASSIGN_CHAR(p_sep_by_space);
+ M_ASSIGN_CHAR(n_cs_precedes);
+ M_ASSIGN_CHAR(n_sep_by_space);
+ M_ASSIGN_CHAR(p_sign_posn);
+ M_ASSIGN_CHAR(n_sign_posn);
+
+ /*
+ * The six additional C99 international monetary formatting
+ * parameters default to the national parameters when
+ * reading FreeBSD LC_MONETARY data files.
+ */
+#define M_ASSIGN_ICHAR(NAME) \
+ do { \
+ if (l->int_##NAME == NULL) \
+ l->int_##NAME = \
+ l->NAME; \
+ else \
+ M_ASSIGN_CHAR(int_##NAME); \
+ } while (0)
+
+ M_ASSIGN_ICHAR(p_cs_precedes);
+ M_ASSIGN_ICHAR(n_cs_precedes);
+ M_ASSIGN_ICHAR(p_sep_by_space);
+ M_ASSIGN_ICHAR(n_sep_by_space);
+ M_ASSIGN_ICHAR(p_sign_posn);
+ M_ASSIGN_ICHAR(n_sign_posn);
+ }
+ return (ret);
+}
+int
+__monetary_load_locale(const char *name)
+{
+ return monetary_load_locale_l(&__xlocale_global_monetary,
+ &__xlocale_global_locale.using_monetary_locale,
+ &__xlocale_global_locale.monetary_locale_changed, name);
+}
+void* __monetary_load(const char *name, locale_t l)
+{
+ struct xlocale_monetary *new = calloc(sizeof(struct xlocale_monetary), 1);
+ new->header.header.destructor = destruct_monetary;
+ if (monetary_load_locale_l(new, &l->using_monetary_locale,
+ &l->monetary_locale_changed, name) == _LDP_ERROR)
+ {
+ xlocale_release(new);
+ return NULL;
+ }
+ return new;
+}
+
+
+struct lc_monetary_T *
+__get_current_monetary_locale(locale_t loc)
+{
+ return (loc->using_monetary_locale
+ ? &((struct xlocale_monetary*)loc->components[XLC_MONETARY])->locale
+ : (struct lc_monetary_T *)&_C_monetary_locale);
+}
+
+#ifdef LOCALE_DEBUG
+void
+monetdebug() {
+printf( "int_curr_symbol = %s\n"
+ "currency_symbol = %s\n"
+ "mon_decimal_point = %s\n"
+ "mon_thousands_sep = %s\n"
+ "mon_grouping = %s\n"
+ "positive_sign = %s\n"
+ "negative_sign = %s\n"
+ "int_frac_digits = %d\n"
+ "frac_digits = %d\n"
+ "p_cs_precedes = %d\n"
+ "p_sep_by_space = %d\n"
+ "n_cs_precedes = %d\n"
+ "n_sep_by_space = %d\n"
+ "p_sign_posn = %d\n"
+ "n_sign_posn = %d\n"
+ "int_p_cs_precedes = %d\n"
+ "int_p_sep_by_space = %d\n"
+ "int_n_cs_precedes = %d\n"
+ "int_n_sep_by_space = %d\n"
+ "int_p_sign_posn = %d\n"
+ "int_n_sign_posn = %d\n",
+ _monetary_locale.int_curr_symbol,
+ _monetary_locale.currency_symbol,
+ _monetary_locale.mon_decimal_point,
+ _monetary_locale.mon_thousands_sep,
+ _monetary_locale.mon_grouping,
+ _monetary_locale.positive_sign,
+ _monetary_locale.negative_sign,
+ _monetary_locale.int_frac_digits[0],
+ _monetary_locale.frac_digits[0],
+ _monetary_locale.p_cs_precedes[0],
+ _monetary_locale.p_sep_by_space[0],
+ _monetary_locale.n_cs_precedes[0],
+ _monetary_locale.n_sep_by_space[0],
+ _monetary_locale.p_sign_posn[0],
+ _monetary_locale.n_sign_posn[0],
+ _monetary_locale.int_p_cs_precedes[0],
+ _monetary_locale.int_p_sep_by_space[0],
+ _monetary_locale.int_n_cs_precedes[0],
+ _monetary_locale.int_n_sep_by_space[0],
+ _monetary_locale.int_p_sign_posn[0],
+ _monetary_locale.int_n_sign_posn[0]
+);
+}
+#endif /* LOCALE_DEBUG */
diff --git a/lib/libc/locale/lmonetary.h b/lib/libc/locale/lmonetary.h
new file mode 100644
index 000000000000..b606862f54af
--- /dev/null
+++ b/lib/libc/locale/lmonetary.h
@@ -0,0 +1,70 @@
+/*-
+ * Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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 _LMONETARY_H_
+#define _LMONETARY_H_
+#include "xlocale_private.h"
+
+struct lc_monetary_T {
+ const char *int_curr_symbol;
+ const char *currency_symbol;
+ const char *mon_decimal_point;
+ const char *mon_thousands_sep;
+ const char *mon_grouping;
+ const char *positive_sign;
+ const char *negative_sign;
+ const char *int_frac_digits;
+ const char *frac_digits;
+ const char *p_cs_precedes;
+ const char *p_sep_by_space;
+ const char *n_cs_precedes;
+ const char *n_sep_by_space;
+ const char *p_sign_posn;
+ const char *n_sign_posn;
+ const char *int_p_cs_precedes;
+ const char *int_n_cs_precedes;
+ const char *int_p_sep_by_space;
+ const char *int_n_sep_by_space;
+ const char *int_p_sign_posn;
+ const char *int_n_sign_posn;
+};
+struct xlocale_monetary {
+ struct xlocale_component header;
+ char *buffer;
+ struct lc_monetary_T locale;
+};
+
+struct lc_monetary_T *__get_current_monetary_locale(locale_t loc);
+int __monetary_load_locale(const char *);
+
+#endif /* !_LMONETARY_H_ */
diff --git a/lib/libc/locale/lnumeric.c b/lib/libc/locale/lnumeric.c
new file mode 100644
index 000000000000..a2468f4e28b5
--- /dev/null
+++ b/lib/libc/locale/lnumeric.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 <limits.h>
+
+#include "ldpart.h"
+#include "lnumeric.h"
+
+extern const char *__fix_locale_grouping_str(const char *);
+
+#define LCNUMERIC_SIZE (sizeof(struct lc_numeric_T) / sizeof(char *))
+
+static char numempty[] = { CHAR_MAX, '\0' };
+
+static const struct lc_numeric_T _C_numeric_locale = {
+ ".", /* decimal_point */
+ "", /* thousands_sep */
+ numempty /* grouping */
+};
+
+static void
+destruct_numeric(void *v)
+{
+ struct xlocale_numeric *l = v;
+ if (l->buffer)
+ free(l->buffer);
+ free(l);
+}
+
+struct xlocale_numeric __xlocale_global_numeric;
+
+static int
+numeric_load_locale(struct xlocale_numeric *loc, int *using_locale, int *changed,
+ const char *name)
+{
+ int ret;
+ struct lc_numeric_T *l = &loc->locale;
+
+ ret = __part_load_locale(name, using_locale,
+ &loc->buffer, "LC_NUMERIC",
+ LCNUMERIC_SIZE, LCNUMERIC_SIZE,
+ (const char**)l);
+ if (ret != _LDP_ERROR)
+ *changed= 1;
+ if (ret == _LDP_LOADED) {
+ /* Can't be empty according to C99 */
+ if (*l->decimal_point == '\0')
+ l->decimal_point =
+ _C_numeric_locale.decimal_point;
+ l->grouping =
+ __fix_locale_grouping_str(l->grouping);
+ }
+ return (ret);
+}
+
+int
+__numeric_load_locale(const char *name)
+{
+ return numeric_load_locale(&__xlocale_global_numeric,
+ &__xlocale_global_locale.using_numeric_locale,
+ &__xlocale_global_locale.numeric_locale_changed, name);
+}
+void *
+__numeric_load(const char *name, locale_t l)
+{
+ struct xlocale_numeric *new = calloc(sizeof(struct xlocale_numeric), 1);
+ new->header.header.destructor = destruct_numeric;
+ if (numeric_load_locale(new, &l->using_numeric_locale,
+ &l->numeric_locale_changed, name) == _LDP_ERROR)
+ {
+ xlocale_release(new);
+ return NULL;
+ }
+ return new;
+}
+
+struct lc_numeric_T *
+__get_current_numeric_locale(locale_t loc)
+{
+ return (loc->using_numeric_locale
+ ? &((struct xlocale_numeric *)loc->components[XLC_NUMERIC])->locale
+ : (struct lc_numeric_T *)&_C_numeric_locale);
+}
+
+#ifdef LOCALE_DEBUG
+void
+numericdebug(void) {
+printf( "decimal_point = %s\n"
+ "thousands_sep = %s\n"
+ "grouping = %s\n",
+ _numeric_locale.decimal_point,
+ _numeric_locale.thousands_sep,
+ _numeric_locale.grouping
+);
+}
+#endif /* LOCALE_DEBUG */
diff --git a/lib/libc/locale/lnumeric.h b/lib/libc/locale/lnumeric.h
new file mode 100644
index 000000000000..5088dd444b5f
--- /dev/null
+++ b/lib/libc/locale/lnumeric.h
@@ -0,0 +1,52 @@
+/*-
+ * Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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 _LNUMERIC_H_
+#define _LNUMERIC_H_
+#include "xlocale_private.h"
+
+struct lc_numeric_T {
+ const char *decimal_point;
+ const char *thousands_sep;
+ const char *grouping;
+};
+struct xlocale_numeric {
+ struct xlocale_component header;
+ char *buffer;
+ struct lc_numeric_T locale;
+};
+
+struct lc_numeric_T *__get_current_numeric_locale(locale_t loc);
+int __numeric_load_locale(const char *);
+
+#endif /* !_LNUMERIC_H_ */
diff --git a/lib/libc/locale/localeconv.3 b/lib/libc/locale/localeconv.3
new file mode 100644
index 000000000000..c831bf53f121
--- /dev/null
+++ b/lib/libc/locale/localeconv.3
@@ -0,0 +1,237 @@
+.\" Copyright (c) 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Donn Seeley at BSDI.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" From @(#)setlocale.3 8.1 (Berkeley) 6/9/93
+.\" From FreeBSD: src/lib/libc/locale/setlocale.3,v 1.28 2003/11/15 02:26:04 tjr Exp
+.\" $FreeBSD$
+.\"
+.Dd November 21, 2003
+.Dt LOCALECONV 3
+.Os
+.Sh NAME
+.Nm localeconv
+.Nd natural language formatting for C
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In locale.h
+.Ft struct lconv *
+.Fn localeconv "void"
+.In xlocale.h
+.Ft struct lconv *
+.Fn localeconv_l "locale_t locale"
+.Sh DESCRIPTION
+The
+.Fn localeconv
+function returns a pointer to a structure
+which provides parameters for formatting numbers,
+especially currency values:
+.Bd -literal -offset indent
+struct lconv {
+ char *decimal_point;
+ char *thousands_sep;
+ char *grouping;
+ char *int_curr_symbol;
+ char *currency_symbol;
+ char *mon_decimal_point;
+ char *mon_thousands_sep;
+ char *mon_grouping;
+ char *positive_sign;
+ char *negative_sign;
+ char int_frac_digits;
+ char frac_digits;
+ char p_cs_precedes;
+ char p_sep_by_space;
+ char n_cs_precedes;
+ char n_sep_by_space;
+ char p_sign_posn;
+ char n_sign_posn;
+ char int_p_cs_precedes;
+ char int_n_cs_precedes;
+ char int_p_sep_by_space;
+ char int_n_sep_by_space;
+ char int_p_sign_posn;
+ char int_n_sign_posn;
+};
+.Ed
+.Pp
+The individual fields have the following meanings:
+.Bl -tag -width mon_decimal_point
+.It Va decimal_point
+The decimal point character, except for currency values,
+cannot be an empty string.
+.It Va thousands_sep
+The separator between groups of digits
+before the decimal point, except for currency values.
+.It Va grouping
+The sizes of the groups of digits, except for currency values.
+This is a pointer to a vector of integers, each of size
+.Vt char ,
+representing group size from low order digit groups
+to high order (right to left).
+The list may be terminated with 0 or
+.Dv CHAR_MAX .
+If the list is terminated with 0,
+the last group size before the 0 is repeated to account for all the digits.
+If the list is terminated with
+.Dv CHAR_MAX ,
+no more grouping is performed.
+.It Va int_curr_symbol
+The standardized international currency symbol.
+.It Va currency_symbol
+The local currency symbol.
+.It Va mon_decimal_point
+The decimal point character for currency values.
+.It Va mon_thousands_sep
+The separator for digit groups in currency values.
+.It Va mon_grouping
+Like
+.Va grouping
+but for currency values.
+.It Va positive_sign
+The character used to denote nonnegative currency values,
+usually the empty string.
+.It Va negative_sign
+The character used to denote negative currency values,
+usually a minus sign.
+.It Va int_frac_digits
+The number of digits after the decimal point
+in an international-style currency value.
+.It Va frac_digits
+The number of digits after the decimal point
+in the local style for currency values.
+.It Va p_cs_precedes
+1 if the currency symbol precedes the currency value
+for nonnegative values, 0 if it follows.
+.It Va p_sep_by_space
+1 if a space is inserted between the currency symbol
+and the currency value for nonnegative values, 0 otherwise.
+.It Va n_cs_precedes
+Like
+.Va p_cs_precedes
+but for negative values.
+.It Va n_sep_by_space
+Like
+.Va p_sep_by_space
+but for negative values.
+.It Va p_sign_posn
+The location of the
+.Va positive_sign
+with respect to a nonnegative quantity and the
+.Va currency_symbol ,
+coded as follows:
+.Pp
+.Bl -tag -width 3n -compact
+.It Li 0
+Parentheses around the entire string.
+.It Li 1
+Before the string.
+.It Li 2
+After the string.
+.It Li 3
+Just before
+.Va currency_symbol .
+.It Li 4
+Just after
+.Va currency_symbol .
+.El
+.It Va n_sign_posn
+Like
+.Va p_sign_posn
+but for negative currency values.
+.It Va int_p_cs_precedes
+Same as
+.Va p_cs_precedes ,
+but for internationally formatted monetary quantities.
+.It Va int_n_cs_precedes
+Same as
+.Va n_cs_precedes ,
+but for internationally formatted monetary quantities.
+.It Va int_p_sep_by_space
+Same as
+.Va p_sep_by_space ,
+but for internationally formatted monetary quantities.
+.It Va int_n_sep_by_space
+Same as
+.Va n_sep_by_space ,
+but for internationally formatted monetary quantities.
+.It Va int_p_sign_posn
+Same as
+.Va p_sign_posn ,
+but for internationally formatted monetary quantities.
+.It Va int_n_sign_posn
+Same as
+.Va n_sign_posn ,
+but for internationally formatted monetary quantities.
+.El
+.Pp
+Unless mentioned above,
+an empty string as a value for a field
+indicates a zero length result or
+a value that is not in the current locale.
+A
+.Dv CHAR_MAX
+result similarly denotes an unavailable value.
+.Pp
+The
+.Fn localeconv_l
+function takes an explicit locale parameter. For more information, see
+.Xr xlocale 3 .
+.Sh RETURN VALUES
+The
+.Fn localeconv
+function returns a pointer to a static object
+which may be altered by later calls to
+.Xr setlocale 3
+or
+.Fn localeconv .
+The return value for
+.Fn localeconv_l
+is stored with the locale.
+It will remain valid until a subsequent call to
+.Xr freelocale 3 .
+If a thread-local locale is in effect then the return value from
+.Fn localeconv
+will remain valid until the locale is destroyed.
+.Sh ERRORS
+No errors are defined.
+.Sh SEE ALSO
+.Xr setlocale 3 ,
+.Xr strfmon 3
+.Sh STANDARDS
+The
+.Fn localeconv
+function conforms to
+.St -isoC-99 .
+.Sh HISTORY
+The
+.Fn localeconv
+function first appeared in
+.Bx 4.4 .
diff --git a/lib/libc/locale/localeconv.c b/lib/libc/locale/localeconv.c
new file mode 100644
index 000000000000..4b19160c35dd
--- /dev/null
+++ b/lib/libc/locale/localeconv.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2001 Alexey Zelkin <phantom@FreeBSD.org>
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)localeconv.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <locale.h>
+
+#include "lmonetary.h"
+#include "lnumeric.h"
+
+/*
+ * The localeconv() function constructs a struct lconv from the current
+ * monetary and numeric locales.
+ *
+ * Because localeconv() may be called many times (especially by library
+ * routines like printf() & strtod()), the approprate members of the
+ * lconv structure are computed only when the monetary or numeric
+ * locale has been changed.
+ */
+
+/*
+ * Return the current locale conversion.
+ */
+struct lconv *
+localeconv_l(locale_t loc)
+{
+ FIX_LOCALE(loc);
+ struct lconv *ret = &loc->lconv;
+
+ if (loc->monetary_locale_changed) {
+ /* LC_MONETARY part */
+ struct lc_monetary_T * mptr;
+
+#define M_ASSIGN_STR(NAME) (ret->NAME = (char*)mptr->NAME)
+#define M_ASSIGN_CHAR(NAME) (ret->NAME = mptr->NAME[0])
+
+ mptr = __get_current_monetary_locale(loc);
+ M_ASSIGN_STR(int_curr_symbol);
+ M_ASSIGN_STR(currency_symbol);
+ M_ASSIGN_STR(mon_decimal_point);
+ M_ASSIGN_STR(mon_thousands_sep);
+ M_ASSIGN_STR(mon_grouping);
+ M_ASSIGN_STR(positive_sign);
+ M_ASSIGN_STR(negative_sign);
+ M_ASSIGN_CHAR(int_frac_digits);
+ M_ASSIGN_CHAR(frac_digits);
+ M_ASSIGN_CHAR(p_cs_precedes);
+ M_ASSIGN_CHAR(p_sep_by_space);
+ M_ASSIGN_CHAR(n_cs_precedes);
+ M_ASSIGN_CHAR(n_sep_by_space);
+ M_ASSIGN_CHAR(p_sign_posn);
+ M_ASSIGN_CHAR(n_sign_posn);
+ M_ASSIGN_CHAR(int_p_cs_precedes);
+ M_ASSIGN_CHAR(int_n_cs_precedes);
+ M_ASSIGN_CHAR(int_p_sep_by_space);
+ M_ASSIGN_CHAR(int_n_sep_by_space);
+ M_ASSIGN_CHAR(int_p_sign_posn);
+ M_ASSIGN_CHAR(int_n_sign_posn);
+ loc->monetary_locale_changed = 0;
+ }
+
+ if (loc->numeric_locale_changed) {
+ /* LC_NUMERIC part */
+ struct lc_numeric_T * nptr;
+
+#define N_ASSIGN_STR(NAME) (ret->NAME = (char*)nptr->NAME)
+
+ nptr = __get_current_numeric_locale(loc);
+ N_ASSIGN_STR(decimal_point);
+ N_ASSIGN_STR(thousands_sep);
+ N_ASSIGN_STR(grouping);
+ loc->numeric_locale_changed = 0;
+ }
+
+ return ret;
+}
+struct lconv *
+localeconv(void)
+{
+ return localeconv_l(__get_locale());
+}
diff --git a/lib/libc/locale/mblen.3 b/lib/libc/locale/mblen.3
new file mode 100644
index 000000000000..f142f390a8fb
--- /dev/null
+++ b/lib/libc/locale/mblen.3
@@ -0,0 +1,106 @@
+.\" Copyright (c) 2002-2004 Tim J. Robbins. All rights reserved.
+.\" Copyright (c) 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Donn Seeley of BSDI.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" From @(#)multibyte.3 8.1 (Berkeley) 6/4/93
+.\" From FreeBSD: src/lib/libc/locale/multibyte.3,v 1.22 2003/11/08 03:23:11 tjr Exp
+.\" $FreeBSD$
+.\"
+.Dd April 11, 2004
+.Dt MBLEN 3
+.Os
+.Sh NAME
+.Nm mblen
+.Nd get number of bytes in a character
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft int
+.Fn mblen "const char *mbchar" "size_t nbytes"
+.Sh DESCRIPTION
+The
+.Fn mblen
+function computes the length in bytes
+of a multibyte character
+.Fa mbchar
+according to the current conversion state.
+Up to
+.Fa nbytes
+bytes are examined.
+.Pp
+A call with a null
+.Fa mbchar
+pointer returns nonzero if the current locale requires shift states,
+zero otherwise;
+if shift states are required, the shift state is reset to the initial state.
+.Sh RETURN VALUES
+If
+.Fa mbchar
+is
+.Dv NULL ,
+the
+.Fn mblen
+function returns nonzero if shift states are supported,
+zero otherwise.
+.Pp
+Otherwise, if
+.Fa mbchar
+is not a null pointer,
+.Fn mblen
+either returns 0 if
+.Fa mbchar
+represents the null wide character, or returns
+the number of bytes processed in
+.Fa mbchar ,
+or returns \-1 if no multibyte character
+could be recognized or converted.
+In this case,
+.Fn mblen Ns 's
+internal conversion state is undefined.
+.Sh ERRORS
+The
+.Fn mblen
+function will fail if:
+.Bl -tag -width Er
+.It Bq Er EILSEQ
+An invalid multibyte sequence was detected.
+.It Bq Er EINVAL
+The internal conversion state is not valid.
+.El
+.Sh SEE ALSO
+.Xr mbrlen 3 ,
+.Xr mbtowc 3 ,
+.Xr multibyte 3
+.Sh STANDARDS
+The
+.Fn mblen
+function conforms to
+.St -isoC-99 .
diff --git a/lib/libc/locale/mblen.c b/lib/libc/locale/mblen.c
new file mode 100644
index 000000000000..1bacf3eb837b
--- /dev/null
+++ b/lib/libc/locale/mblen.c
@@ -0,0 +1,61 @@
+/*-
+ * Copyright (c) 2002-2004 Tim J. Robbins.
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 <stdlib.h>
+#include <wchar.h>
+#include "mblocal.h"
+
+int
+mblen_l(const char *s, size_t n, locale_t locale)
+{
+ static const mbstate_t initial;
+ size_t rval;
+ FIX_LOCALE(locale);
+
+ if (s == NULL) {
+ /* No support for state dependent encodings. */
+ locale->mblen = initial;
+ return (0);
+ }
+ rval = XLOCALE_CTYPE(locale)->__mbrtowc(NULL, s, n, &locale->mblen);
+ if (rval == (size_t)-1 || rval == (size_t)-2)
+ return (-1);
+ return ((int)rval);
+}
+
+int
+mblen(const char *s, size_t n)
+{
+ return mblen_l(s, n, __get_locale());
+}
diff --git a/lib/libc/locale/mblocal.h b/lib/libc/locale/mblocal.h
new file mode 100644
index 000000000000..acb1c21940b8
--- /dev/null
+++ b/lib/libc/locale/mblocal.h
@@ -0,0 +1,90 @@
+/*-
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2004 Tim J. Robbins.
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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 _MBLOCAL_H_
+#define _MBLOCAL_H_
+
+#include <runetype.h>
+#include "xlocale_private.h"
+
+#define SS2 0x008e
+#define SS3 0x008f
+
+/*
+ * Conversion function pointers for current encoding.
+ */
+struct xlocale_ctype {
+ struct xlocale_component header;
+ _RuneLocale *runes;
+ size_t (*__mbrtowc)(wchar_t * __restrict, const char * __restrict,
+ size_t, mbstate_t * __restrict);
+ int (*__mbsinit)(const mbstate_t *);
+ size_t (*__mbsnrtowcs)(wchar_t * __restrict, const char ** __restrict,
+ size_t, size_t, mbstate_t * __restrict);
+ size_t (*__wcrtomb)(char * __restrict, wchar_t, mbstate_t * __restrict);
+ size_t (*__wcsnrtombs)(char * __restrict, const wchar_t ** __restrict,
+ size_t, size_t, mbstate_t * __restrict);
+ int __mb_cur_max;
+ int __mb_sb_limit;
+};
+#define XLOCALE_CTYPE(x) ((struct xlocale_ctype*)(x)->components[XLC_CTYPE])
+extern struct xlocale_ctype __xlocale_global_ctype;
+
+/*
+ * Rune initialization function prototypes.
+ */
+int _none_init(struct xlocale_ctype *, _RuneLocale *) __hidden;
+int _UTF8_init(struct xlocale_ctype *, _RuneLocale *) __hidden;
+int _EUC_CN_init(struct xlocale_ctype *, _RuneLocale *) __hidden;
+int _EUC_JP_init(struct xlocale_ctype *, _RuneLocale *) __hidden;
+int _EUC_KR_init(struct xlocale_ctype *, _RuneLocale *) __hidden;
+int _EUC_TW_init(struct xlocale_ctype *, _RuneLocale *) __hidden;
+int _GB18030_init(struct xlocale_ctype *, _RuneLocale *) __hidden;
+int _GB2312_init(struct xlocale_ctype *, _RuneLocale *) __hidden;
+int _GBK_init(struct xlocale_ctype *, _RuneLocale *) __hidden;
+int _BIG5_init(struct xlocale_ctype *, _RuneLocale *) __hidden;
+int _MSKanji_init(struct xlocale_ctype *, _RuneLocale *) __hidden;
+int _ascii_init(struct xlocale_ctype *, _RuneLocale *) __hidden;
+
+typedef size_t (*mbrtowc_pfn_t)(wchar_t * __restrict,
+ const char * __restrict, size_t, mbstate_t * __restrict);
+typedef size_t (*wcrtomb_pfn_t)(char * __restrict, wchar_t,
+ mbstate_t * __restrict);
+size_t __mbsnrtowcs_std(wchar_t * __restrict, const char ** __restrict,
+ size_t, size_t, mbstate_t * __restrict, mbrtowc_pfn_t);
+size_t __wcsnrtombs_std(char * __restrict, const wchar_t ** __restrict,
+ size_t, size_t, mbstate_t * __restrict, wcrtomb_pfn_t);
+
+#endif /* _MBLOCAL_H_ */
diff --git a/lib/libc/locale/mbrlen.3 b/lib/libc/locale/mbrlen.3
new file mode 100644
index 000000000000..524d2c7b4016
--- /dev/null
+++ b/lib/libc/locale/mbrlen.3
@@ -0,0 +1,145 @@
+.\" Copyright (c) 2002-2004 Tim J. Robbins
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd April 7, 2004
+.Dt MBRLEN 3
+.Os
+.Sh NAME
+.Nm mbrlen
+.Nd "get number of bytes in a character (restartable)"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In wchar.h
+.Ft size_t
+.Fn mbrlen "const char * restrict s" "size_t n" "mbstate_t * restrict ps"
+.Sh DESCRIPTION
+The
+.Fn mbrlen
+function inspects at most
+.Fa n
+bytes pointed to by
+.Fa s
+to determine the number of bytes needed to complete the next
+multibyte character.
+.Pp
+The
+.Vt mbstate_t
+argument,
+.Fa ps ,
+is used to keep track of the shift state.
+If it is
+.Dv NULL ,
+.Fn mbrlen
+uses an internal, static
+.Vt mbstate_t
+object, which is initialized to the initial conversion state
+at program startup.
+.Pp
+It is equivalent to:
+.Pp
+.Dl "mbrtowc(NULL, s, n, ps);"
+.Pp
+Except that when
+.Fa ps
+is a
+.Dv NULL
+pointer,
+.Fn mbrlen
+uses its own static, internal
+.Vt mbstate_t
+object to keep track of the shift state.
+.Sh RETURN VALUES
+The
+.Fn mbrlen
+functions returns:
+.Bl -tag -width indent
+.It 0
+The next
+.Fa n
+or fewer bytes
+represent the null wide character
+.Pq Li "L'\e0'" .
+.It >0
+The next
+.Fa n
+or fewer bytes
+represent a valid character,
+.Fn mbrlen
+returns the number of bytes used to complete the multibyte character.
+.It Po Vt size_t Pc Ns \-2
+The next
+.Fa n
+contribute to, but do not complete, a valid multibyte character sequence,
+and all
+.Fa n
+bytes have been processed.
+.It Po Vt size_t Pc Ns \-1
+An encoding error has occurred.
+The next
+.Fa n
+or fewer bytes do not contribute to a valid multibyte character.
+.El
+.Sh EXAMPLES
+A function that calculates the number of characters in a multibyte
+character string:
+.Bd -literal -offset indent
+size_t
+nchars(const char *s)
+{
+ size_t charlen, chars;
+ mbstate_t mbs;
+
+ chars = 0;
+ memset(&mbs, 0, sizeof(mbs));
+ while ((charlen = mbrlen(s, MB_CUR_MAX, &mbs)) != 0 &&
+ charlen != (size_t)-1 && charlen != (size_t)-2) {
+ s += charlen;
+ chars++;
+ }
+
+ return (chars);
+}
+.Ed
+.Sh ERRORS
+The
+.Fn mbrlen
+function will fail if:
+.Bl -tag -width Er
+.It Bq Er EILSEQ
+An invalid multibyte sequence was detected.
+.It Bq Er EINVAL
+The conversion state is invalid.
+.El
+.Sh SEE ALSO
+.Xr mblen 3 ,
+.Xr mbrtowc 3 ,
+.Xr multibyte 3
+.Sh STANDARDS
+The
+.Fn mbrlen
+function conforms to
+.St -isoC-99 .
diff --git a/lib/libc/locale/mbrlen.c b/lib/libc/locale/mbrlen.c
new file mode 100644
index 000000000000..9ce0bc067642
--- /dev/null
+++ b/lib/libc/locale/mbrlen.c
@@ -0,0 +1,51 @@
+/*-
+ * Copyright (c) 2002-2004 Tim J. Robbins.
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 <wchar.h>
+#include "mblocal.h"
+
+size_t
+mbrlen_l(const char * __restrict s, size_t n, mbstate_t * __restrict ps, locale_t locale)
+{
+ FIX_LOCALE(locale);
+ if (ps == NULL)
+ ps = &locale->mbrlen;
+ return (XLOCALE_CTYPE(locale)->__mbrtowc(NULL, s, n, ps));
+}
+
+size_t
+mbrlen(const char * __restrict s, size_t n, mbstate_t * __restrict ps)
+{
+ return mbrlen_l(s, n, ps, __get_locale());
+}
diff --git a/lib/libc/locale/mbrtoc16.c b/lib/libc/locale/mbrtoc16.c
new file mode 100644
index 000000000000..a47514c3d93b
--- /dev/null
+++ b/lib/libc/locale/mbrtoc16.c
@@ -0,0 +1,89 @@
+/*-
+ * Copyright (c) 2013 Ed Schouten <ed@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <uchar.h>
+#include "xlocale_private.h"
+
+typedef struct {
+ char16_t trail_surrogate;
+ mbstate_t c32_mbstate;
+} _Char16State;
+
+size_t
+mbrtoc16_l(char16_t * __restrict pc16, const char * __restrict s, size_t n,
+ mbstate_t * __restrict ps, locale_t locale)
+{
+ _Char16State *cs;
+ char32_t c32;
+ ssize_t len;
+
+ FIX_LOCALE(locale);
+ if (ps == NULL)
+ ps = &locale->mbrtoc16;
+ cs = (_Char16State *)ps;
+
+ /*
+ * Call straight into mbrtoc32_l() if we don't need to return a
+ * character value. According to the spec, if s is a null
+ * pointer, the value of parameter pc16 is also ignored.
+ */
+ if (pc16 == NULL || s == NULL) {
+ cs->trail_surrogate = 0;
+ return (mbrtoc32_l(NULL, s, n, &cs->c32_mbstate, locale));
+ }
+
+ /* Return the trail surrogate from the previous invocation. */
+ if (cs->trail_surrogate >= 0xdc00 && cs->trail_surrogate <= 0xdfff) {
+ *pc16 = cs->trail_surrogate;
+ cs->trail_surrogate = 0;
+ return ((size_t)-3);
+ }
+
+ len = mbrtoc32_l(&c32, s, n, &cs->c32_mbstate, locale);
+ if (len >= 0) {
+ if (c32 < 0x10000) {
+ /* Fits in one UTF-16 character. */
+ *pc16 = c32;
+ } else {
+ /* Split up in a surrogate pair. */
+ c32 -= 0x10000;
+ *pc16 = 0xd800 | (c32 >> 10);
+ cs->trail_surrogate = 0xdc00 | (c32 & 0x3ff);
+ }
+ }
+ return (len);
+}
+
+size_t
+mbrtoc16(char16_t * __restrict pc16, const char * __restrict s, size_t n,
+ mbstate_t * __restrict ps)
+{
+
+ return (mbrtoc16_l(pc16, s, n, ps, __get_locale()));
+}
diff --git a/lib/libc/locale/mbrtoc16_iconv.c b/lib/libc/locale/mbrtoc16_iconv.c
new file mode 100644
index 000000000000..f1eaf1925496
--- /dev/null
+++ b/lib/libc/locale/mbrtoc16_iconv.c
@@ -0,0 +1,8 @@
+/* $FreeBSD$ */
+#define charXX_t char16_t
+#define mbrtocXX mbrtoc16
+#define mbrtocXX_l mbrtoc16_l
+#define DSTBUF_LEN 2
+#define UTF_XX_INTERNAL "UTF-16-INTERNAL"
+
+#include "mbrtocXX_iconv.h"
diff --git a/lib/libc/locale/mbrtoc32.c b/lib/libc/locale/mbrtoc32.c
new file mode 100644
index 000000000000..ee9e47d6a3e5
--- /dev/null
+++ b/lib/libc/locale/mbrtoc32.c
@@ -0,0 +1,53 @@
+/*-
+ * Copyright (c) 2013 Ed Schouten <ed@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <uchar.h>
+#include <wchar.h>
+#include "xlocale_private.h"
+
+size_t
+mbrtoc32_l(char32_t * __restrict pc32, const char * __restrict s, size_t n,
+ mbstate_t * __restrict ps, locale_t locale)
+{
+
+ FIX_LOCALE(locale);
+ if (ps == NULL)
+ ps = &locale->mbrtoc32;
+
+ /* Assume wchar_t uses UTF-32. */
+ return (mbrtowc_l(pc32, s, n, ps, locale));
+}
+
+size_t
+mbrtoc32(char32_t * __restrict pc32, const char * __restrict s, size_t n,
+ mbstate_t * __restrict ps)
+{
+
+ return (mbrtoc32_l(pc32, s, n, ps, __get_locale()));
+}
diff --git a/lib/libc/locale/mbrtoc32_iconv.c b/lib/libc/locale/mbrtoc32_iconv.c
new file mode 100644
index 000000000000..ec2c0145d9d6
--- /dev/null
+++ b/lib/libc/locale/mbrtoc32_iconv.c
@@ -0,0 +1,8 @@
+/* $FreeBSD$ */
+#define charXX_t char32_t
+#define mbrtocXX mbrtoc32
+#define mbrtocXX_l mbrtoc32_l
+#define DSTBUF_LEN 1
+#define UTF_XX_INTERNAL "UTF-32-INTERNAL"
+
+#include "mbrtocXX_iconv.h"
diff --git a/lib/libc/locale/mbrtocXX_iconv.h b/lib/libc/locale/mbrtocXX_iconv.h
new file mode 100644
index 000000000000..9eb6f6831eb6
--- /dev/null
+++ b/lib/libc/locale/mbrtocXX_iconv.h
@@ -0,0 +1,158 @@
+/*-
+ * Copyright (c) 2013 Ed Schouten <ed@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/queue.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <langinfo.h>
+#include <limits.h>
+#include <string.h>
+#include <uchar.h>
+
+#include "../iconv/citrus_hash.h"
+#include "../iconv/citrus_module.h"
+#include "../iconv/citrus_iconv.h"
+#include "xlocale_private.h"
+
+typedef struct {
+ bool initialized;
+ struct _citrus_iconv iconv;
+ char srcbuf[MB_LEN_MAX];
+ size_t srcbuf_len;
+ union {
+ charXX_t widechar[DSTBUF_LEN];
+ char bytes[sizeof(charXX_t) * DSTBUF_LEN];
+ } dstbuf;
+ size_t dstbuf_len;
+} _ConversionState;
+_Static_assert(sizeof(_ConversionState) <= sizeof(mbstate_t),
+ "Size of _ConversionState must not exceed mbstate_t's size.");
+
+size_t
+mbrtocXX_l(charXX_t * __restrict pc, const char * __restrict s, size_t n,
+ mbstate_t * __restrict ps, locale_t locale)
+{
+ _ConversionState *cs;
+ struct _citrus_iconv *handle;
+ size_t i, retval;
+ charXX_t retchar;
+
+ FIX_LOCALE(locale);
+ if (ps == NULL)
+ ps = &locale->mbrtocXX;
+ cs = (_ConversionState *)ps;
+ handle = &cs->iconv;
+
+ /* Reinitialize mbstate_t. */
+ if (s == NULL || !cs->initialized) {
+ if (_citrus_iconv_open(&handle,
+ nl_langinfo_l(CODESET, locale), UTF_XX_INTERNAL) != 0) {
+ cs->initialized = false;
+ errno = EINVAL;
+ return (-1);
+ }
+ handle->cv_shared->ci_discard_ilseq = true;
+ handle->cv_shared->ci_hooks = NULL;
+ cs->srcbuf_len = cs->dstbuf_len = 0;
+ cs->initialized = true;
+ if (s == NULL)
+ return (0);
+ }
+
+ /* See if we still have characters left from the previous invocation. */
+ if (cs->dstbuf_len > 0) {
+ retval = (size_t)-3;
+ goto return_char;
+ }
+
+ /* Fill up the read buffer as far as possible. */
+ if (n > sizeof(cs->srcbuf) - cs->srcbuf_len)
+ n = sizeof(cs->srcbuf) - cs->srcbuf_len;
+ memcpy(cs->srcbuf + cs->srcbuf_len, s, n);
+
+ /* Convert as few characters to the dst buffer as possible. */
+ for (i = 0; ; i++) {
+ char *src, *dst;
+ size_t srcleft, dstleft, invlen;
+ int err;
+
+ src = cs->srcbuf;
+ srcleft = cs->srcbuf_len + n;
+ dst = cs->dstbuf.bytes;
+ dstleft = i * sizeof(charXX_t);
+ assert(srcleft <= sizeof(cs->srcbuf) &&
+ dstleft <= sizeof(cs->dstbuf.bytes));
+ err = _citrus_iconv_convert(handle, &src, &srcleft,
+ &dst, &dstleft, 0, &invlen);
+ cs->dstbuf_len = (dst - cs->dstbuf.bytes) / sizeof(charXX_t);
+
+ /* Got new character(s). Return the first. */
+ if (cs->dstbuf_len > 0) {
+ assert(src - cs->srcbuf > cs->srcbuf_len);
+ retval = src - cs->srcbuf - cs->srcbuf_len;
+ cs->srcbuf_len = 0;
+ goto return_char;
+ }
+
+ /* Increase dst buffer size, to obtain the surrogate pair. */
+ if (err == E2BIG)
+ continue;
+
+ /* Illegal sequence. */
+ if (invlen > 0) {
+ cs->srcbuf_len = 0;
+ errno = EILSEQ;
+ return ((size_t)-1);
+ }
+
+ /* Save unprocessed remainder for the next invocation. */
+ memmove(cs->srcbuf, src, srcleft);
+ cs->srcbuf_len = srcleft;
+ return ((size_t)-2);
+ }
+
+return_char:
+ retchar = cs->dstbuf.widechar[0];
+ memmove(&cs->dstbuf.widechar[0], &cs->dstbuf.widechar[1],
+ --cs->dstbuf_len * sizeof(charXX_t));
+ if (pc != NULL)
+ *pc = retchar;
+ if (retchar == 0)
+ return (0);
+ return (retval);
+}
+
+size_t
+mbrtocXX(charXX_t * __restrict pc, const char * __restrict s, size_t n,
+ mbstate_t * __restrict ps)
+{
+
+ return (mbrtocXX_l(pc, s, n, ps, __get_locale()));
+}
diff --git a/lib/libc/locale/mbrtowc.3 b/lib/libc/locale/mbrtowc.3
new file mode 100644
index 000000000000..22b26cd2a244
--- /dev/null
+++ b/lib/libc/locale/mbrtowc.3
@@ -0,0 +1,179 @@
+.\" Copyright (c) 2002-2004 Tim J. Robbins
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd May 21, 2013
+.Dt MBRTOWC 3
+.Os
+.Sh NAME
+.Nm mbrtowc ,
+.Nm mbrtoc16 ,
+.Nm mbrtoc32
+.Nd "convert a character to a wide-character code (restartable)"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In wchar.h
+.Ft size_t
+.Fo mbrtowc
+.Fa "wchar_t * restrict pc" "const char * restrict s" "size_t n"
+.Fa "mbstate_t * restrict ps"
+.Fc
+.In uchar.h
+.Ft size_t
+.Fo mbrtoc16
+.Fa "char16_t * restrict pc" "const char * restrict s" "size_t n"
+.Fa "mbstate_t * restrict ps"
+.Fc
+.Ft size_t
+.Fo mbrtoc32
+.Fa "char32_t * restrict pc" "const char * restrict s" "size_t n"
+.Fa "mbstate_t * restrict ps"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn mbrtowc ,
+.Fn mbrtoc16
+and
+.Fn mbrtoc32
+functions inspect at most
+.Fa n
+bytes pointed to by
+.Fa s
+to determine the number of bytes needed to complete the next multibyte
+character.
+If a character can be completed, and
+.Fa pc
+is not
+.Dv NULL ,
+the wide character which is represented by
+.Fa s
+is stored in the
+.Vt wchar_t ,
+.Vt char16_t
+or
+.Vt char32_t
+it points to.
+.Pp
+If
+.Fa s
+is
+.Dv NULL ,
+these functions behave as if
+.Fa pc
+was
+.Dv NULL ,
+.Fa s
+was an empty string
+.Pq Qq
+and
+.Fa n
+was 1.
+.Pp
+The
+.Vt mbstate_t
+argument,
+.Fa ps ,
+is used to keep track of the shift state.
+If it is
+.Dv NULL ,
+these functions use an internal, static
+.Vt mbstate_t
+object, which is initialized to the initial conversion state
+at program startup.
+.Pp
+As a single
+.Vt char16_t
+is not large enough to represent certain multibyte characters, the
+.Fn mbrtoc16
+function may need to be invoked multiple times to convert a single
+multibyte character sequence.
+.Sh RETURN VALUES
+The
+.Fn mbrtowc ,
+.Fn mbrtoc16
+and
+.Fn mbrtoc32
+functions return:
+.Bl -tag -width indent
+.It 0
+The next
+.Fa n
+or fewer bytes
+represent the null wide character
+.Pq Li "L'\e0'" .
+.It >0
+The next
+.Fa n
+or fewer bytes represent a valid character, these functions
+return the number of bytes used to complete the multibyte character.
+.It Po Vt size_t Pc Ns \-1
+An encoding error has occurred.
+The next
+.Fa n
+or fewer bytes do not contribute to a valid multibyte character.
+.It Po Vt size_t Pc Ns \-2
+The next
+.Fa n
+contribute to, but do not complete, a valid multibyte character sequence,
+and all
+.Fa n
+bytes have been processed.
+.El
+.Pp
+The
+.Fn mbrtoc16
+function also returns:
+.Bl -tag -width indent
+.It Po Vt size_t Pc Ns \-3
+The next character resulting from a previous call has been stored.
+No bytes from the input have been consumed.
+.El
+.Sh ERRORS
+The
+.Fn mbrtowc ,
+.Fn mbrtoc16
+and
+.Fn mbrtoc32
+functions will fail if:
+.Bl -tag -width Er
+.It Bq Er EILSEQ
+An invalid multibyte sequence was detected.
+.It Bq Er EINVAL
+The conversion state is invalid.
+.El
+.Sh SEE ALSO
+.Xr mbtowc 3 ,
+.Xr multibyte 3 ,
+.Xr setlocale 3 ,
+.Xr wcrtomb 3
+.Sh STANDARDS
+The
+.Fn mbrtowc ,
+.Fn mbrtoc16
+and
+.Fn mbrtoc32
+functions conform to
+.St -isoC-2011 .
diff --git a/lib/libc/locale/mbrtowc.c b/lib/libc/locale/mbrtowc.c
new file mode 100644
index 000000000000..8f1aebd5762a
--- /dev/null
+++ b/lib/libc/locale/mbrtowc.c
@@ -0,0 +1,53 @@
+/*-
+ * Copyright (c) 2002-2004 Tim J. Robbins.
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 <wchar.h>
+#include "mblocal.h"
+
+size_t
+mbrtowc_l(wchar_t * __restrict pwc, const char * __restrict s,
+ size_t n, mbstate_t * __restrict ps, locale_t locale)
+{
+ FIX_LOCALE(locale);
+ if (ps == NULL)
+ ps = &locale->mbrtowc;
+ return (XLOCALE_CTYPE(locale)->__mbrtowc(pwc, s, n, ps));
+}
+
+size_t
+mbrtowc(wchar_t * __restrict pwc, const char * __restrict s,
+ size_t n, mbstate_t * __restrict ps)
+{
+ return mbrtowc_l(pwc, s, n, ps, __get_locale());
+}
diff --git a/lib/libc/locale/mbsinit.3 b/lib/libc/locale/mbsinit.3
new file mode 100644
index 000000000000..afc2500c3a77
--- /dev/null
+++ b/lib/libc/locale/mbsinit.3
@@ -0,0 +1,67 @@
+.\" Copyright (c) 2002-2004 Tim J. Robbins
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd April 8, 2004
+.Dt MBSINIT 3
+.Os
+.Sh NAME
+.Nm mbsinit
+.Nd "determine conversion object status"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In wchar.h
+.Ft int
+.Fn mbsinit "const mbstate_t *ps"
+.Sh DESCRIPTION
+The
+.Fn mbsinit
+function determines whether the
+.Vt mbstate_t
+object pointed to by
+.Fa ps
+describes an initial conversion state.
+.Sh RETURN VALUES
+The
+.Fn mbsinit
+function returns non-zero if
+.Fa ps
+is
+.Dv NULL
+or describes an initial conversion state,
+otherwise it returns zero.
+.Sh SEE ALSO
+.Xr mbrlen 3 ,
+.Xr mbrtowc 3 ,
+.Xr mbsrtowcs 3 ,
+.Xr multibyte 3 ,
+.Xr wcrtomb 3 ,
+.Xr wcsrtombs 3
+.Sh STANDARDS
+The
+.Fn mbsinit
+function conforms to
+.St -isoC-99 .
diff --git a/lib/libc/locale/mbsinit.c b/lib/libc/locale/mbsinit.c
new file mode 100644
index 000000000000..be44fe5e31c0
--- /dev/null
+++ b/lib/libc/locale/mbsinit.c
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 2002-2004 Tim J. Robbins.
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 <wchar.h>
+#include "mblocal.h"
+
+int
+mbsinit_l(const mbstate_t *ps, locale_t locale)
+{
+ FIX_LOCALE(locale);
+ return (XLOCALE_CTYPE(locale)->__mbsinit(ps));
+}
+int
+mbsinit(const mbstate_t *ps)
+{
+ return mbsinit_l(ps, __get_locale());
+}
diff --git a/lib/libc/locale/mbsnrtowcs.c b/lib/libc/locale/mbsnrtowcs.c
new file mode 100644
index 000000000000..9e6baad4b131
--- /dev/null
+++ b/lib/libc/locale/mbsnrtowcs.c
@@ -0,0 +1,104 @@
+/*-
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
+ * Copyright 2010 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2002-2004 Tim J. Robbins.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include "mblocal.h"
+
+size_t
+mbsnrtowcs_l(wchar_t * __restrict dst, const char ** __restrict src,
+ size_t nms, size_t len, mbstate_t * __restrict ps, locale_t locale)
+{
+ FIX_LOCALE(locale);
+ if (ps == NULL)
+ ps = &locale->mbsnrtowcs;
+ return (XLOCALE_CTYPE(locale)->__mbsnrtowcs(dst, src, nms, len, ps));
+}
+size_t
+mbsnrtowcs(wchar_t * __restrict dst, const char ** __restrict src,
+ size_t nms, size_t len, mbstate_t * __restrict ps)
+{
+ return mbsnrtowcs_l(dst, src, nms, len, ps, __get_locale());
+}
+
+size_t
+__mbsnrtowcs_std(wchar_t * __restrict dst, const char ** __restrict src,
+ size_t nms, size_t len, mbstate_t * __restrict ps,
+ mbrtowc_pfn_t pmbrtowc)
+{
+ const char *s;
+ size_t nchr;
+ wchar_t wc;
+ size_t nb;
+
+ s = *src;
+ nchr = 0;
+
+ if (dst == NULL) {
+ for (;;) {
+ if ((nb = pmbrtowc(&wc, s, nms, ps)) == (size_t)-1)
+ /* Invalid sequence - mbrtowc() sets errno. */
+ return ((size_t)-1);
+ else if (nb == 0 || nb == (size_t)-2)
+ return (nchr);
+ s += nb;
+ nms -= nb;
+ nchr++;
+ }
+ /*NOTREACHED*/
+ }
+
+ while (len-- > 0) {
+ if ((nb = pmbrtowc(dst, s, nms, ps)) == (size_t)-1) {
+ *src = s;
+ return ((size_t)-1);
+ } else if (nb == (size_t)-2) {
+ *src = s + nms;
+ return (nchr);
+ } else if (nb == 0) {
+ *src = NULL;
+ return (nchr);
+ }
+ s += nb;
+ nms -= nb;
+ nchr++;
+ dst++;
+ }
+ *src = s;
+ return (nchr);
+}
diff --git a/lib/libc/locale/mbsrtowcs.3 b/lib/libc/locale/mbsrtowcs.3
new file mode 100644
index 000000000000..eaf9f9093056
--- /dev/null
+++ b/lib/libc/locale/mbsrtowcs.3
@@ -0,0 +1,135 @@
+.\" Copyright (c) 2002-2004 Tim J. Robbins
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.Dd July 21, 2004
+.Dt MBSRTOWCS 3
+.Os
+.Sh NAME
+.Nm mbsrtowcs ,
+.Nm mbsnrtowcs
+.Nd "convert a character string to a wide-character string (restartable)"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In wchar.h
+.Ft size_t
+.Fo mbsrtowcs
+.Fa "wchar_t * restrict dst" "const char ** restrict src" "size_t len"
+.Fa "mbstate_t * restrict ps"
+.Fc
+.Ft size_t
+.Fo mbsnrtowcs
+.Fa "wchar_t * restrict dst" "const char ** restrict src" "size_t nms"
+.Fa "size_t len" "mbstate_t * restrict ps"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn mbsrtowcs
+function converts a sequence of multibyte characters pointed to indirectly by
+.Fa src
+into a sequence of corresponding wide characters and stores at most
+.Fa len
+of them in the
+.Vt wchar_t
+array pointed to by
+.Fa dst ,
+until it encounters a terminating null character
+.Pq Li '\e0' .
+.Pp
+If
+.Fa dst
+is
+.Dv NULL ,
+no characters are stored.
+.Pp
+If
+.Fa dst
+is not
+.Dv NULL ,
+the pointer pointed to by
+.Fa src
+is updated to point to the character after the one that conversion stopped at.
+If conversion stops because a null character is encountered,
+.Fa *src
+is set to
+.Dv NULL .
+.Pp
+The
+.Vt mbstate_t
+argument,
+.Fa ps ,
+is used to keep track of the shift state.
+If it is
+.Dv NULL ,
+.Fn mbsrtowcs
+uses an internal, static
+.Vt mbstate_t
+object, which is initialized to the initial conversion state
+at program startup.
+.Pp
+The
+.Fn mbsnrtowcs
+function behaves identically to
+.Fn mbsrtowcs ,
+except that conversion stops after reading at most
+.Fa nms
+bytes from the buffer pointed to by
+.Fa src .
+.Sh RETURN VALUES
+The
+.Fn mbsrtowcs
+and
+.Fn mbsnrtowcs
+functions return the number of wide characters stored in
+the array pointed to by
+.Fa dst
+if successful, otherwise it returns
+.Po Vt size_t Pc Ns \-1 .
+.Sh ERRORS
+The
+.Fn mbsrtowcs
+and
+.Fn mbsnrtowcs
+functions will fail if:
+.Bl -tag -width Er
+.It Bq Er EILSEQ
+An invalid multibyte character sequence was encountered.
+.It Bq Er EINVAL
+The conversion state is invalid.
+.El
+.Sh SEE ALSO
+.Xr mbrtowc 3 ,
+.Xr mbstowcs 3 ,
+.Xr multibyte 3 ,
+.Xr wcsrtombs 3
+.Sh STANDARDS
+The
+.Fn mbsrtowcs
+function conforms to
+.St -isoC-99 .
+.Pp
+The
+.Fn mbsnrtowcs
+function is an extension to the standard.
diff --git a/lib/libc/locale/mbsrtowcs.c b/lib/libc/locale/mbsrtowcs.c
new file mode 100644
index 000000000000..9032b94fffba
--- /dev/null
+++ b/lib/libc/locale/mbsrtowcs.c
@@ -0,0 +1,55 @@
+/*-
+ * Copyright (c) 2002-2004 Tim J. Robbins.
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include "mblocal.h"
+
+size_t
+mbsrtowcs_l(wchar_t * __restrict dst, const char ** __restrict src, size_t len,
+ mbstate_t * __restrict ps, locale_t locale)
+{
+ FIX_LOCALE(locale);
+ if (ps == NULL)
+ ps = &locale->mbsrtowcs;
+ return (XLOCALE_CTYPE(locale)->__mbsnrtowcs(dst, src, SIZE_T_MAX, len, ps));
+}
+size_t
+mbsrtowcs(wchar_t * __restrict dst, const char ** __restrict src, size_t len,
+ mbstate_t * __restrict ps)
+{
+ return mbsrtowcs_l(dst, src, len, ps, __get_locale());
+}
diff --git a/lib/libc/locale/mbstowcs.3 b/lib/libc/locale/mbstowcs.3
new file mode 100644
index 000000000000..fb9168303ad1
--- /dev/null
+++ b/lib/libc/locale/mbstowcs.3
@@ -0,0 +1,87 @@
+.\" Copyright (c) 2002-2004 Tim J. Robbins. All rights reserved.
+.\" Copyright (c) 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Donn Seeley of BSDI.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" From @(#)multibyte.3 8.1 (Berkeley) 6/4/93
+.\" From FreeBSD: src/lib/libc/locale/multibyte.3,v 1.22 2003/11/08 03:23:11 tjr Exp
+.\" $FreeBSD$
+.\"
+.Dd April 8, 2004
+.Dt MBSTOWCS 3
+.Os
+.Sh NAME
+.Nm mbstowcs
+.Nd convert a character string to a wide-character string
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft size_t
+.Fo mbstowcs
+.Fa "wchar_t * restrict wcstring" "const char * restrict mbstring"
+.Fa "size_t nwchars"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn mbstowcs
+function converts a multibyte character string
+.Fa mbstring
+beginning in the initial conversion state
+into a wide character string
+.Fa wcstring .
+No more than
+.Fa nwchars
+wide characters are stored.
+A terminating null wide character is appended if there is room.
+.Sh RETURN VALUES
+The
+.Fn mbstowcs
+function returns the number of wide characters converted,
+not counting any terminating null wide character, or \-1
+if an invalid multibyte character was encountered.
+.Sh ERRORS
+The
+.Fn mbstowcs
+function will fail if:
+.Bl -tag -width Er
+.It Bq Er EILSEQ
+An invalid multibyte sequence was detected.
+.It Bq Er EINVAL
+The conversion state is invalid.
+.El
+.Sh SEE ALSO
+.Xr mbsrtowcs 3 ,
+.Xr mbtowc 3 ,
+.Xr multibyte 3
+.Sh STANDARDS
+The
+.Fn mbstowcs
+function conforms to
+.St -isoC-99 .
diff --git a/lib/libc/locale/mbstowcs.c b/lib/libc/locale/mbstowcs.c
new file mode 100644
index 000000000000..6905d2e6604e
--- /dev/null
+++ b/lib/libc/locale/mbstowcs.c
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 2002-2004 Tim J. Robbins.
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 <limits.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include "mblocal.h"
+
+size_t
+mbstowcs_l(wchar_t * __restrict pwcs, const char * __restrict s, size_t n, locale_t locale)
+{
+ static const mbstate_t initial;
+ mbstate_t mbs;
+ const char *sp;
+ FIX_LOCALE(locale);
+
+ mbs = initial;
+ sp = s;
+ return (XLOCALE_CTYPE(locale)->__mbsnrtowcs(pwcs, &sp, SIZE_T_MAX, n, &mbs));
+}
+size_t
+mbstowcs(wchar_t * __restrict pwcs, const char * __restrict s, size_t n)
+{
+ return mbstowcs_l(pwcs, s, n, __get_locale());
+}
diff --git a/lib/libc/locale/mbtowc.3 b/lib/libc/locale/mbtowc.3
new file mode 100644
index 000000000000..b59dbf4b3144
--- /dev/null
+++ b/lib/libc/locale/mbtowc.3
@@ -0,0 +1,114 @@
+.\" Copyright (c) 2002-2004 Tim J. Robbins. All rights reserved.
+.\" Copyright (c) 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Donn Seeley of BSDI.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" From @(#)multibyte.3 8.1 (Berkeley) 6/4/93
+.\" From FreeBSD: src/lib/libc/locale/multibyte.3,v 1.22 2003/11/08 03:23:11 tjr Exp
+.\" $FreeBSD$
+.\"
+.Dd April 11, 2004
+.Dt MBTOWC 3
+.Os
+.Sh NAME
+.Nm mbtowc
+.Nd convert a character to a wide-character code
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft int
+.Fo mbtowc
+.Fa "wchar_t * restrict wcharp" "const char * restrict mbchar"
+.Fa "size_t nbytes"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn mbtowc
+function converts a multibyte character
+.Fa mbchar
+into a wide character according to the current conversion state,
+and stores the result
+in the object pointed to by
+.Fa wcharp .
+Up to
+.Fa nbytes
+bytes are examined.
+.Pp
+A call with a null
+.Fa mbchar
+pointer returns nonzero if the current encoding requires shift states,
+zero otherwise;
+if shift states are required, the shift state is reset to the initial state.
+.Sh RETURN VALUES
+If
+.Fa mbchar
+is
+.Dv NULL ,
+the
+.Fn mbtowc
+function returns nonzero if shift states are supported,
+zero otherwise.
+.Pp
+Otherwise, if
+.Fa mbchar
+is not a null pointer,
+.Fn mbtowc
+either returns 0 if
+.Fa mbchar
+represents the null wide character, or returns
+the number of bytes processed in
+.Fa mbchar ,
+or returns \-1 if no multibyte character
+could be recognized or converted.
+In this case,
+.Fn mbtowc Ns 's
+internal conversion state is undefined.
+.Sh ERRORS
+The
+.Fn mbtowc
+function will fail if:
+.Bl -tag -width Er
+.It Bq Er EILSEQ
+An invalid multibyte sequence was detected.
+.It Bq Er EINVAL
+The internal conversion state is invalid.
+.El
+.Sh SEE ALSO
+.Xr btowc 3 ,
+.Xr mblen 3 ,
+.Xr mbrtowc 3 ,
+.Xr mbstowcs 3 ,
+.Xr multibyte 3 ,
+.Xr wctomb 3
+.Sh STANDARDS
+The
+.Fn mbtowc
+function conforms to
+.St -isoC-99 .
diff --git a/lib/libc/locale/mbtowc.c b/lib/libc/locale/mbtowc.c
new file mode 100644
index 000000000000..376d6cfa5d6d
--- /dev/null
+++ b/lib/libc/locale/mbtowc.c
@@ -0,0 +1,67 @@
+/*-
+ * Copyright (c) 2002-2004 Tim J. Robbins.
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 <errno.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include "mblocal.h"
+
+int
+mbtowc_l(wchar_t * __restrict pwc, const char * __restrict s, size_t n, locale_t locale)
+{
+ static const mbstate_t initial;
+ size_t rval;
+ FIX_LOCALE(locale);
+
+ if (s == NULL) {
+ /* No support for state dependent encodings. */
+ locale->mbtowc = initial;
+ return (0);
+ }
+ rval = XLOCALE_CTYPE(locale)->__mbrtowc(pwc, s, n, &locale->mbtowc);
+ switch (rval) {
+ case (size_t)-2:
+ errno = EILSEQ;
+ /* FALLTHROUGH */
+ case (size_t)-1:
+ return (-1);
+ default:
+ return ((int)rval);
+ }
+}
+int
+mbtowc(wchar_t * __restrict pwc, const char * __restrict s, size_t n)
+{
+ return mbtowc_l(pwc, s, n, __get_locale());
+}
diff --git a/lib/libc/locale/mskanji.5 b/lib/libc/locale/mskanji.5
new file mode 100644
index 000000000000..8ebaccdd7af2
--- /dev/null
+++ b/lib/libc/locale/mskanji.5
@@ -0,0 +1,70 @@
+.\" Copyright (c) 2002, 2003 Tim J. Robbins
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd August 7, 2003
+.Dt MSKANJI 5
+.Os
+.Sh NAME
+.Nm mskanji
+.Nd "Shift-JIS (MS Kanji) encoding for Japanese text"
+.Sh SYNOPSIS
+.Nm ENCODING
+.Qq MSKanji
+.Sh DESCRIPTION
+Shift-JIS, also known as MS Kanji or SJIS, is an encoding system for
+Japanese characters, developed by Microsoft Corporation.
+It encodes the characters from the
+.Tn JIS
+X 0201 (ASCII/JIS-Roman) and
+.Tn JIS
+X 0208 (Japanese) character sets as sequences of either one or two bytes.
+.Pp
+Characters from the
+.Tn ASCII Ns
+/JIS-Roman character set are encoded as single bytes between 0x00 and 0x7F
+(ASCII) or 0xA1 and 0xDF (Half-width katakana).
+.Pp
+Characters from the
+.Tn JIS
+X 0208 character set are encoded as two bytes.
+The first ranges from
+0x81 - 0x9F, 0xE0 - 0xEA, 0xED - 0xEE (not
+.Tn JIS :
+.Tn NEC Ns - Ns
+selected
+.Tn IBM
+extended characters),
+0xF0 - 0xF9 (not
+.Tn JIS :
+user defined),
+or 0xFA - 0xFC (not
+.Tn JIS :
+.Tn IBM
+extended characters).
+The second byte ranges from 0x40 - 0xFC, excluding 0x7F (delete).
+.Sh SEE ALSO
+.Xr euc 5 ,
+.Xr utf8 5
diff --git a/lib/libc/locale/mskanji.c b/lib/libc/locale/mskanji.c
new file mode 100644
index 000000000000..c7da4b5e8c0f
--- /dev/null
+++ b/lib/libc/locale/mskanji.c
@@ -0,0 +1,191 @@
+/*
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
+ * Copyright 2010 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2002-2004 Tim J. Robbins. All rights reserved.
+ *
+ * ja_JP.SJIS locale table for BSD4.4/rune
+ * version 1.0
+ * (C) Sin'ichiro MIYATANI / Phase One, Inc
+ * May 12, 1995
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Phase One, Inc.
+ * 4. The name of Phase One, Inc. may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)mskanji.c 1.0 (Phase One) 5/5/95";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <errno.h>
+#include <runetype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include "mblocal.h"
+
+extern int __mb_sb_limit;
+
+static size_t _MSKanji_mbrtowc(wchar_t * __restrict, const char * __restrict,
+ size_t, mbstate_t * __restrict);
+static int _MSKanji_mbsinit(const mbstate_t *);
+static size_t _MSKanji_wcrtomb(char * __restrict, wchar_t,
+ mbstate_t * __restrict);
+static size_t _MSKanji_mbsnrtowcs(wchar_t * __restrict,
+ const char ** __restrict, size_t, size_t,
+ mbstate_t * __restrict);
+static size_t _MSKanji_wcsnrtombs(char * __restrict,
+ const wchar_t ** __restrict, size_t, size_t,
+ mbstate_t * __restrict);
+
+typedef struct {
+ wchar_t ch;
+} _MSKanjiState;
+
+int
+_MSKanji_init(struct xlocale_ctype *l, _RuneLocale *rl)
+{
+
+ l->__mbrtowc = _MSKanji_mbrtowc;
+ l->__wcrtomb = _MSKanji_wcrtomb;
+ l->__mbsnrtowcs = _MSKanji_mbsnrtowcs;
+ l->__wcsnrtombs = _MSKanji_wcsnrtombs;
+ l->__mbsinit = _MSKanji_mbsinit;
+ l->runes = rl;
+ l->__mb_cur_max = 2;
+ l->__mb_sb_limit = 224;
+ return (0);
+}
+
+static int
+_MSKanji_mbsinit(const mbstate_t *ps)
+{
+
+ return (ps == NULL || ((const _MSKanjiState *)ps)->ch == 0);
+}
+
+static size_t
+_MSKanji_mbrtowc(wchar_t * __restrict pwc, const char * __restrict s, size_t n,
+ mbstate_t * __restrict ps)
+{
+ _MSKanjiState *ms;
+ wchar_t wc;
+
+ ms = (_MSKanjiState *)ps;
+
+ if ((ms->ch & ~0xFF) != 0) {
+ /* Bad conversion state. */
+ errno = EINVAL;
+ return ((size_t)-1);
+ }
+
+ if (s == NULL) {
+ s = "";
+ n = 1;
+ pwc = NULL;
+ }
+
+ if (n == 0)
+ /* Incomplete multibyte sequence */
+ return ((size_t)-2);
+
+ if (ms->ch != 0) {
+ if (*s == '\0') {
+ errno = EILSEQ;
+ return ((size_t)-1);
+ }
+ wc = (ms->ch << 8) | (*s & 0xFF);
+ if (pwc != NULL)
+ *pwc = wc;
+ ms->ch = 0;
+ return (1);
+ }
+ wc = *s++ & 0xff;
+ if ((wc > 0x80 && wc < 0xa0) || (wc >= 0xe0 && wc < 0xfd)) {
+ if (n < 2) {
+ /* Incomplete multibyte sequence */
+ ms->ch = wc;
+ return ((size_t)-2);
+ }
+ if (*s == '\0') {
+ errno = EILSEQ;
+ return ((size_t)-1);
+ }
+ wc = (wc << 8) | (*s++ & 0xff);
+ if (pwc != NULL)
+ *pwc = wc;
+ return (2);
+ } else {
+ if (pwc != NULL)
+ *pwc = wc;
+ return (wc == L'\0' ? 0 : 1);
+ }
+}
+
+static size_t
+_MSKanji_wcrtomb(char * __restrict s, wchar_t wc, mbstate_t * __restrict ps)
+{
+ _MSKanjiState *ms;
+ int len, i;
+
+ ms = (_MSKanjiState *)ps;
+
+ if (ms->ch != 0) {
+ errno = EINVAL;
+ return ((size_t)-1);
+ }
+
+ if (s == NULL)
+ /* Reset to initial shift state (no-op) */
+ return (1);
+ len = (wc > 0x100) ? 2 : 1;
+ for (i = len; i-- > 0; )
+ *s++ = wc >> (i << 3);
+ return (len);
+}
+
+static size_t
+_MSKanji_mbsnrtowcs(wchar_t * __restrict dst,
+ const char ** __restrict src, size_t nms,
+ size_t len, mbstate_t * __restrict ps)
+{
+ return (__mbsnrtowcs_std(dst, src, nms, len, ps, _MSKanji_mbrtowc));
+}
+
+static size_t
+_MSKanji_wcsnrtombs(char * __restrict dst,
+ const wchar_t ** __restrict src, size_t nwc,
+ size_t len, mbstate_t * __restrict ps)
+{
+ return (__wcsnrtombs_std(dst, src, nwc, len, ps, _MSKanji_wcrtomb));
+}
diff --git a/lib/libc/locale/multibyte.3 b/lib/libc/locale/multibyte.3
new file mode 100644
index 000000000000..465bf66e76d6
--- /dev/null
+++ b/lib/libc/locale/multibyte.3
@@ -0,0 +1,142 @@
+.\" Copyright (c) 2002-2004 Tim J. Robbins. All rights reserved.
+.\" Copyright (c) 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Donn Seeley of BSDI.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)multibyte.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd April 8, 2004
+.Dt MULTIBYTE 3
+.Os
+.Sh NAME
+.Nm multibyte
+.Nd multibyte and wide character manipulation functions
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In limits.h
+.In stdlib.h
+.In wchar.h
+.Sh DESCRIPTION
+The basic elements of some written natural languages, such as Chinese,
+cannot be represented uniquely with single C
+.Vt char Ns s .
+The C standard supports two different ways of dealing with
+extended natural language encodings:
+wide characters and
+multibyte characters.
+Wide characters are an internal representation
+which allows each basic element to map
+to a single object of type
+.Vt wchar_t .
+Multibyte characters are used for input and output
+and code each basic element as a sequence of C
+.Vt char Ns s .
+Individual basic elements may map into one or more
+(up to
+.Dv MB_LEN_MAX )
+bytes in a multibyte character.
+.Pp
+The current locale
+.Pq Xr setlocale 3
+governs the interpretation of wide and multibyte characters.
+The locale category
+.Dv LC_CTYPE
+specifically controls this interpretation.
+The
+.Vt wchar_t
+type is wide enough to hold the largest value
+in the wide character representations for all locales.
+.Pp
+Multibyte strings may contain
+.Sq shift
+indicators to switch to and from
+particular modes within the given representation.
+If explicit bytes are used to signal shifting,
+these are not recognized as separate characters
+but are lumped with a neighboring character.
+There is always a distinguished
+.Sq initial
+shift state.
+Some functions (e.g.,
+.Xr mblen 3 ,
+.Xr mbtowc 3
+and
+.Xr wctomb 3 )
+maintain static shift state internally, whereas
+others store it in an
+.Vt mbstate_t
+object passed by the caller.
+Shift states are undefined after a call to
+.Xr setlocale 3
+with the
+.Dv LC_CTYPE
+or
+.Dv LC_ALL
+categories.
+.Pp
+For convenience in processing,
+the wide character with value 0
+(the null wide character)
+is recognized as the wide character string terminator,
+and the character with value 0
+(the null byte)
+is recognized as the multibyte character string terminator.
+Null bytes are not permitted within multibyte characters.
+.Pp
+The C library provides the following functions for dealing with
+multibyte characters:
+.Bl -column "Description"
+.It Sy "Function Description"
+.It Xr mblen 3 Ta "get number of bytes in a character"
+.It Xr mbrlen 3 Ta "get number of bytes in a character (restartable)"
+.It Xr mbrtowc 3 Ta "convert a character to a wide-character code (restartable)"
+.It Xr mbsrtowcs 3 Ta "convert a character string to a wide-character string (restartable)"
+.It Xr mbstowcs 3 Ta "convert a character string to a wide-character string"
+.It Xr mbtowc 3 Ta "convert a character to a wide-character code"
+.It Xr wcrtomb 3 Ta "convert a wide-character code to a character (restartable)"
+.It Xr wcstombs 3 Ta "convert a wide-character string to a character string"
+.It Xr wcsrtombs 3 Ta "convert a wide-character string to a character string (restartable)"
+.It Xr wctomb 3 Ta "convert a wide-character code to a character"
+.El
+.Sh SEE ALSO
+.Xr mklocale 1 ,
+.Xr setlocale 3 ,
+.Xr stdio 3 ,
+.Xr big5 5 ,
+.Xr euc 5 ,
+.Xr gb18030 5 ,
+.Xr gb2312 5 ,
+.Xr gbk 5 ,
+.Xr mskanji 5 ,
+.Xr utf8 5
+.Sh STANDARDS
+These functions conform to
+.St -isoC-99 .
diff --git a/lib/libc/locale/newlocale.3 b/lib/libc/locale/newlocale.3
new file mode 100644
index 000000000000..c7414be73d3a
--- /dev/null
+++ b/lib/libc/locale/newlocale.3
@@ -0,0 +1,112 @@
+.\" Copyright (c) 2011 The FreeBSD Foundation
+.\" All rights reserved.
+.\"
+.\" This documentation was written by David Chisnall under sponsorship from
+.\" the FreeBSD Foundation.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 September 17, 2011
+.Dt NEWLOCALE 3
+.Os
+.Sh NAME
+.Nm newlocale
+.Nd Creates a new locale
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In locale.h
+.Ft locale_t
+.Fn newlocale "int mask" "const char * locale" "locale_t base"
+.Sh DESCRIPTION
+Creates a new locale, inheriting some properties from an existing locale.
+The
+.Fa mask
+defines the components that the new locale will have set to the locale with the
+name specified in the
+.Fa locale
+parameter.
+Any other components will be inherited from
+.Fa base .
+The
+.Fa mask
+is either
+.Fa LC_ALL_MASK ,
+indicating all possible locale components,
+or the logical OR of some combination of the following:
+.Bl -tag -width "LC_MESSAGES_MASK" -offset indent
+.It LC_COLLATE_MASK
+The locale for string collation routines.
+This controls alphabetic ordering in
+.Xr strcoll 3
+and
+.Xr strxfrm 3 .
+.It LC_CTYPE_MASK
+The locale for the
+.Xr ctype 3
+and
+.Xr multibyte 3
+functions.
+This controls recognition of upper and lower case, alphabetic or
+non-alphabetic characters, and so on.
+.It LC_MESSAGES_MASK
+Set a locale for message catalogs, see
+.Xr catopen 3
+function.
+.It LC_MONETARY_MASK
+Set a locale for formatting monetary values; this affects
+the
+.Xr localeconv 3
+function.
+.It LC_NUMERIC_MASK
+Set a locale for formatting numbers.
+This controls the formatting of decimal points in input and output of floating
+point numbers in functions such as
+.Xr printf 3
+and
+.Xr scanf 3 ,
+as well as values returned by
+.Xr localeconv 3 .
+.It LC_TIME_MASK
+Set a locale for formatting dates and times using the
+.Xr strftime 3
+function.
+.El
+This function uses the same rules for loading locale components as
+.Xr setlocale 3 .
+.Sh RETURN VALUES
+Returns a new, valid,
+.Fa locale_t
+or NULL if an error occurs.
+You must free the returned locale with
+.Xr freelocale 3 .
+.Sh SEE ALSO
+.Xr duplocale 3 ,
+.Xr freelocale 3 ,
+.Xr localeconv 3 ,
+.Xr querylocale 3 ,
+.Xr uselocale 3 ,
+.Xr xlocale 3
+.Sh STANDARDS
+This function conforms to
+.St -p1003.1-2008 .
diff --git a/lib/libc/locale/nextwctype.3 b/lib/libc/locale/nextwctype.3
new file mode 100644
index 000000000000..0f6f88079f64
--- /dev/null
+++ b/lib/libc/locale/nextwctype.3
@@ -0,0 +1,67 @@
+.\"
+.\" Copyright (c) 2004 Tim J. Robbins
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd July 21, 2005
+.Dt NEXTWCTYPE 3
+.Os
+.Sh NAME
+.Nm nextwctype
+.Nd "iterate through character classes"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In wctype.h
+.Ft wint_t
+.Fn nextwctype "wint_t ch" "wctype_t wct"
+.Sh DESCRIPTION
+The
+.Fn nextwctype
+function determines the next character after
+.Fa ch
+that is a member of character class
+.Fa wct .
+If
+.Fa ch
+is \-1, the search begins at the first member of
+.Fa wct .
+.Sh RETURN VALUES
+The
+.Fn nextwctype
+function returns the next character, or \-1 if there are no more.
+.Sh COMPATIBILITY
+This function is a non-standard
+.Fx
+extension and should not be used where the standard
+.Fn iswctype
+function would suffice.
+.Sh SEE ALSO
+.Xr wctype 3
+.Sh HISTORY
+The
+.Fn nextwctype
+function appeared in
+.Fx 5.4 .
diff --git a/lib/libc/locale/nextwctype.c b/lib/libc/locale/nextwctype.c
new file mode 100644
index 000000000000..9fc8ce05ecee
--- /dev/null
+++ b/lib/libc/locale/nextwctype.c
@@ -0,0 +1,103 @@
+/*-
+ * Copyright (c) 2004 Tim J. Robbins.
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 <runetype.h>
+#include <wchar.h>
+#include <wctype.h>
+#include "mblocal.h"
+
+wint_t
+nextwctype_l(wint_t wc, wctype_t wct, locale_t locale)
+{
+ size_t lim;
+ FIX_LOCALE(locale);
+ _RuneLocale *runes = XLOCALE_CTYPE(locale)->runes;
+ _RuneRange *rr = &runes->__runetype_ext;
+ _RuneEntry *base, *re;
+ int noinc;
+
+ noinc = 0;
+ if (wc < _CACHED_RUNES) {
+ wc++;
+ while (wc < _CACHED_RUNES) {
+ if (runes->__runetype[wc] & wct)
+ return (wc);
+ wc++;
+ }
+ wc--;
+ }
+ if (rr->__ranges != NULL && wc < rr->__ranges[0].__min) {
+ wc = rr->__ranges[0].__min;
+ noinc = 1;
+ }
+
+ /* Binary search -- see bsearch.c for explanation. */
+ base = rr->__ranges;
+ for (lim = rr->__nranges; lim != 0; lim >>= 1) {
+ re = base + (lim >> 1);
+ if (re->__min <= wc && wc <= re->__max)
+ goto found;
+ else if (wc > re->__max) {
+ base = re + 1;
+ lim--;
+ }
+ }
+ return (-1);
+found:
+ if (!noinc)
+ wc++;
+ if (re->__min <= wc && wc <= re->__max) {
+ if (re->__types != NULL) {
+ for (; wc <= re->__max; wc++)
+ if (re->__types[wc - re->__min] & wct)
+ return (wc);
+ } else if (re->__map & wct)
+ return (wc);
+ }
+ while (++re < rr->__ranges + rr->__nranges) {
+ wc = re->__min;
+ if (re->__types != NULL) {
+ for (; wc <= re->__max; wc++)
+ if (re->__types[wc - re->__min] & wct)
+ return (wc);
+ } else if (re->__map & wct)
+ return (wc);
+ }
+ return (-1);
+}
+wint_t
+nextwctype(wint_t wc, wctype_t wct)
+{
+ return nextwctype_l(wc, wct, __get_locale());
+}
diff --git a/lib/libc/locale/nl_langinfo.3 b/lib/libc/locale/nl_langinfo.3
new file mode 100644
index 000000000000..d8c01b2f135f
--- /dev/null
+++ b/lib/libc/locale/nl_langinfo.3
@@ -0,0 +1,102 @@
+.\" Copyright (c) 2001 Alexey Zelkin <phantom@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 July 30, 2012
+.Dt NL_LANGINFO 3
+.Os
+.Sh NAME
+.Nm nl_langinfo
+.Nd language information
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In langinfo.h
+.Ft char *
+.Fn nl_langinfo "nl_item item"
+.Ft char *
+.Fn nl_langinfo_l "nl_item item" "locale_t loc"
+.Sh DESCRIPTION
+The
+.Fn nl_langinfo
+function returns a pointer to a string containing information relevant to
+the particular language or cultural area defined in the program or thread's
+locale, or in the case of
+.Fn nl_langinfo_l ,
+the locale passed as the second argument.
+The manifest constant names and values of
+.Fa item
+are defined in
+.In langinfo.h .
+.Pp
+Calls to
+.Fn setlocale
+with a category corresponding to the category of
+.Fa item ,
+or to the
+category
+.Dv LC_ALL ,
+may overwrite the buffer pointed to by the return value.
+.Sh RETURN VALUES
+In a locale where langinfo data is not defined,
+.Fn nl_langinfo
+returns a pointer to the corresponding string in the
+.Tn POSIX
+locale.
+.Fn nl_langinfo_l
+returns the same values as
+.Fn nl_langinfo .
+In all locales,
+.Fn nl_langinfo
+returns a pointer to an empty string if
+.Fa item
+contains an invalid setting.
+.Sh EXAMPLES
+For example:
+.Pp
+.Dl nl_langinfo(ABDAY_1)
+.Pp
+would return a pointer to the string
+.Qq Li Dom
+if the identified language was
+Portuguese, and
+.Qq Li Sun
+if the identified language was English.
+.Sh SEE ALSO
+.Xr setlocale 3
+.Sh STANDARDS
+The
+.Fn nl_langinfo
+function conforms to
+.St -susv2 .
+The
+.Fn nl_langinfo_l
+function conforms to
+.St -p1003.1-2008 .
+.Sh HISTORY
+The
+.Fn nl_langinfo
+function first appeared in
+.Fx 4.6 .
diff --git a/lib/libc/locale/nl_langinfo.c b/lib/libc/locale/nl_langinfo.c
new file mode 100644
index 000000000000..7f19a575f208
--- /dev/null
+++ b/lib/libc/locale/nl_langinfo.c
@@ -0,0 +1,207 @@
+/*-
+ * Copyright (c) 2001, 2003 Alexey Zelkin <phantom@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 <langinfo.h>
+#include <limits.h>
+#include <locale.h>
+#include <stdlib.h>
+#include <string.h>
+#include <runetype.h>
+#include <wchar.h>
+
+#include "mblocal.h"
+#include "lnumeric.h"
+#include "lmessages.h"
+#include "lmonetary.h"
+#include "../stdtime/timelocal.h"
+
+#define _REL(BASE) ((int)item-BASE)
+
+char *
+nl_langinfo_l(nl_item item, locale_t loc)
+{
+ char *ret, *cs;
+ const char *s;
+ FIX_LOCALE(loc);
+
+ switch (item) {
+ case CODESET:
+ s = XLOCALE_CTYPE(loc)->runes->__encoding;
+ if (strcmp(s, "EUC-CN") == 0)
+ ret = "eucCN";
+ else if (strcmp(s, "EUC-JP") == 0)
+ ret = "eucJP";
+ else if (strcmp(s, "EUC-KR") == 0)
+ ret = "eucKR";
+ else if (strcmp(s, "EUC-TW") == 0)
+ ret = "eucTW";
+ else if (strcmp(s, "BIG5") == 0)
+ ret = "Big5";
+ else if (strcmp(s, "MSKanji") == 0)
+ ret = "SJIS";
+ else if (strcmp(s, "NONE") == 0)
+ ret = "US-ASCII";
+ else if (strncmp(s, "NONE:", 5) == 0)
+ ret = (char *)(s + 5);
+ else
+ ret = (char *)s;
+ break;
+ case D_T_FMT:
+ ret = (char *) __get_current_time_locale(loc)->c_fmt;
+ break;
+ case D_FMT:
+ ret = (char *) __get_current_time_locale(loc)->x_fmt;
+ break;
+ case T_FMT:
+ ret = (char *) __get_current_time_locale(loc)->X_fmt;
+ break;
+ case T_FMT_AMPM:
+ ret = (char *) __get_current_time_locale(loc)->ampm_fmt;
+ break;
+ case AM_STR:
+ ret = (char *) __get_current_time_locale(loc)->am;
+ break;
+ case PM_STR:
+ ret = (char *) __get_current_time_locale(loc)->pm;
+ break;
+ case DAY_1: case DAY_2: case DAY_3:
+ case DAY_4: case DAY_5: case DAY_6: case DAY_7:
+ ret = (char*) __get_current_time_locale(loc)->weekday[_REL(DAY_1)];
+ break;
+ case ABDAY_1: case ABDAY_2: case ABDAY_3:
+ case ABDAY_4: case ABDAY_5: case ABDAY_6: case ABDAY_7:
+ ret = (char*) __get_current_time_locale(loc)->wday[_REL(ABDAY_1)];
+ break;
+ case MON_1: case MON_2: case MON_3: case MON_4:
+ case MON_5: case MON_6: case MON_7: case MON_8:
+ case MON_9: case MON_10: case MON_11: case MON_12:
+ ret = (char*) __get_current_time_locale(loc)->month[_REL(MON_1)];
+ break;
+ case ABMON_1: case ABMON_2: case ABMON_3: case ABMON_4:
+ case ABMON_5: case ABMON_6: case ABMON_7: case ABMON_8:
+ case ABMON_9: case ABMON_10: case ABMON_11: case ABMON_12:
+ ret = (char*) __get_current_time_locale(loc)->mon[_REL(ABMON_1)];
+ break;
+ case ALTMON_1: case ALTMON_2: case ALTMON_3: case ALTMON_4:
+ case ALTMON_5: case ALTMON_6: case ALTMON_7: case ALTMON_8:
+ case ALTMON_9: case ALTMON_10: case ALTMON_11: case ALTMON_12:
+ ret = (char*)
+ __get_current_time_locale(loc)->alt_month[_REL(ALTMON_1)];
+ break;
+ case ERA:
+ /* XXX: need to be implemented */
+ ret = "";
+ break;
+ case ERA_D_FMT:
+ /* XXX: need to be implemented */
+ ret = "";
+ break;
+ case ERA_D_T_FMT:
+ /* XXX: need to be implemented */
+ ret = "";
+ break;
+ case ERA_T_FMT:
+ /* XXX: need to be implemented */
+ ret = "";
+ break;
+ case ALT_DIGITS:
+ /* XXX: need to be implemented */
+ ret = "";
+ break;
+ case RADIXCHAR:
+ ret = (char*) __get_current_numeric_locale(loc)->decimal_point;
+ break;
+ case THOUSEP:
+ ret = (char*) __get_current_numeric_locale(loc)->thousands_sep;
+ break;
+ case YESEXPR:
+ ret = (char*) __get_current_messages_locale(loc)->yesexpr;
+ break;
+ case NOEXPR:
+ ret = (char*) __get_current_messages_locale(loc)->noexpr;
+ break;
+ /*
+ * YESSTR and NOSTR items marked with LEGACY are available, but not
+ * recommended by SUSv2 to be used in portable applications since
+ * they're subject to remove in future specification editions.
+ */
+ case YESSTR: /* LEGACY */
+ ret = (char*) __get_current_messages_locale(loc)->yesstr;
+ break;
+ case NOSTR: /* LEGACY */
+ ret = (char*) __get_current_messages_locale(loc)->nostr;
+ break;
+ /*
+ * SUSv2 special formatted currency string
+ */
+ case CRNCYSTR:
+ ret = "";
+ cs = (char*) __get_current_monetary_locale(loc)->currency_symbol;
+ if (*cs != '\0') {
+ char pos = localeconv_l(loc)->p_cs_precedes;
+
+ if (pos == localeconv_l(loc)->n_cs_precedes) {
+ char psn = '\0';
+
+ if (pos == CHAR_MAX) {
+ if (strcmp(cs, __get_current_monetary_locale(loc)->mon_decimal_point) == 0)
+ psn = '.';
+ } else
+ psn = pos ? '-' : '+';
+ if (psn != '\0') {
+ int clen = strlen(cs);
+
+ if ((loc->csym = reallocf(loc->csym, clen + 2)) != NULL) {
+ *loc->csym = psn;
+ strcpy(loc->csym + 1, cs);
+ ret = loc->csym;
+ }
+ }
+ }
+ }
+ break;
+ case D_MD_ORDER: /* FreeBSD local extension */
+ ret = (char *) __get_current_time_locale(loc)->md_order;
+ break;
+ default:
+ ret = "";
+ }
+ return (ret);
+}
+
+char *
+nl_langinfo(nl_item item)
+{
+ return nl_langinfo_l(item, __get_locale());
+}
diff --git a/lib/libc/locale/nomacros.c b/lib/libc/locale/nomacros.c
new file mode 100644
index 000000000000..66cf40e61ec9
--- /dev/null
+++ b/lib/libc/locale/nomacros.c
@@ -0,0 +1,18 @@
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Tell <ctype.h> to generate extern versions of all its inline
+ * functions. The extern versions get called if the system doesn't
+ * support inlines or the user defines _DONT_USE_CTYPE_INLINE_
+ * before including <ctype.h>.
+ */
+#define _EXTERNALIZE_CTYPE_INLINES_
+
+/*
+ * Also make sure <runetype.h> does not generate an inline definition
+ * of __getCurrentRuneLocale().
+ */
+#define __RUNETYPE_INTERNAL
+
+#include <ctype.h>
diff --git a/lib/libc/locale/none.c b/lib/libc/locale/none.c
new file mode 100644
index 000000000000..4e5a61d99540
--- /dev/null
+++ b/lib/libc/locale/none.c
@@ -0,0 +1,215 @@
+/*-
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
+ * Copyright 2010 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2002-2004 Tim J. Robbins. All rights reserved.
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Borman at Krystal Technologies.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)none.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <limits.h>
+#include <runetype.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include "mblocal.h"
+
+static size_t _none_mbrtowc(wchar_t * __restrict, const char * __restrict,
+ size_t, mbstate_t * __restrict);
+static int _none_mbsinit(const mbstate_t *);
+static size_t _none_mbsnrtowcs(wchar_t * __restrict dst,
+ const char ** __restrict src, size_t nms, size_t len,
+ mbstate_t * __restrict ps __unused);
+static size_t _none_wcrtomb(char * __restrict, wchar_t,
+ mbstate_t * __restrict);
+static size_t _none_wcsnrtombs(char * __restrict, const wchar_t ** __restrict,
+ size_t, size_t, mbstate_t * __restrict);
+
+/* setup defaults */
+
+int __mb_cur_max = 1;
+int __mb_sb_limit = 256; /* Expected to be <= _CACHED_RUNES */
+
+int
+_none_init(struct xlocale_ctype *l, _RuneLocale *rl)
+{
+
+ l->__mbrtowc = _none_mbrtowc;
+ l->__mbsinit = _none_mbsinit;
+ l->__mbsnrtowcs = _none_mbsnrtowcs;
+ l->__wcrtomb = _none_wcrtomb;
+ l->__wcsnrtombs = _none_wcsnrtombs;
+ l->runes = rl;
+ l->__mb_cur_max = 1;
+ l->__mb_sb_limit = 256;
+ return(0);
+}
+
+static int
+_none_mbsinit(const mbstate_t *ps __unused)
+{
+
+ /*
+ * Encoding is not state dependent - we are always in the
+ * initial state.
+ */
+ return (1);
+}
+
+static size_t
+_none_mbrtowc(wchar_t * __restrict pwc, const char * __restrict s, size_t n,
+ mbstate_t * __restrict ps __unused)
+{
+
+ if (s == NULL)
+ /* Reset to initial shift state (no-op) */
+ return (0);
+ if (n == 0)
+ /* Incomplete multibyte sequence */
+ return ((size_t)-2);
+ if (pwc != NULL)
+ *pwc = (unsigned char)*s;
+ return (*s == '\0' ? 0 : 1);
+}
+
+static size_t
+_none_wcrtomb(char * __restrict s, wchar_t wc,
+ mbstate_t * __restrict ps __unused)
+{
+
+ if (s == NULL)
+ /* Reset to initial shift state (no-op) */
+ return (1);
+ if (wc < 0 || wc > UCHAR_MAX) {
+ errno = EILSEQ;
+ return ((size_t)-1);
+ }
+ *s = (unsigned char)wc;
+ return (1);
+}
+
+static size_t
+_none_mbsnrtowcs(wchar_t * __restrict dst, const char ** __restrict src,
+ size_t nms, size_t len, mbstate_t * __restrict ps __unused)
+{
+ const char *s;
+ size_t nchr;
+
+ if (dst == NULL) {
+ s = memchr(*src, '\0', nms);
+ return (s != NULL ? s - *src : nms);
+ }
+
+ s = *src;
+ nchr = 0;
+ while (len-- > 0 && nms-- > 0) {
+ if ((*dst++ = (unsigned char)*s++) == L'\0') {
+ *src = NULL;
+ return (nchr);
+ }
+ nchr++;
+ }
+ *src = s;
+ return (nchr);
+}
+
+static size_t
+_none_wcsnrtombs(char * __restrict dst, const wchar_t ** __restrict src,
+ size_t nwc, size_t len, mbstate_t * __restrict ps __unused)
+{
+ const wchar_t *s;
+ size_t nchr;
+
+ if (dst == NULL) {
+ for (s = *src; nwc > 0 && *s != L'\0'; s++, nwc--) {
+ if (*s < 0 || *s > UCHAR_MAX) {
+ errno = EILSEQ;
+ return ((size_t)-1);
+ }
+ }
+ return (s - *src);
+ }
+
+ s = *src;
+ nchr = 0;
+ while (len-- > 0 && nwc-- > 0) {
+ if (*s < 0 || *s > UCHAR_MAX) {
+ *src = s;
+ errno = EILSEQ;
+ return ((size_t)-1);
+ }
+ if ((*dst++ = *s++) == '\0') {
+ *src = NULL;
+ return (nchr);
+ }
+ nchr++;
+ }
+ *src = s;
+ return (nchr);
+}
+
+/* setup defaults */
+
+struct xlocale_ctype __xlocale_global_ctype = {
+ {{0}, "C"},
+ (_RuneLocale*)&_DefaultRuneLocale,
+ _none_mbrtowc,
+ _none_mbsinit,
+ _none_mbsnrtowcs,
+ _none_wcrtomb,
+ _none_wcsnrtombs,
+ 1, /* __mb_cur_max, */
+ 256 /* __mb_sb_limit */
+};
+
+struct xlocale_ctype __xlocale_C_ctype = {
+ {{0}, "C"},
+ (_RuneLocale*)&_DefaultRuneLocale,
+ _none_mbrtowc,
+ _none_mbsinit,
+ _none_mbsnrtowcs,
+ _none_wcrtomb,
+ _none_wcsnrtombs,
+ 1, /* __mb_cur_max, */
+ 256 /* __mb_sb_limit */
+};
diff --git a/lib/libc/locale/querylocale.3 b/lib/libc/locale/querylocale.3
new file mode 100644
index 000000000000..d1bb688ed907
--- /dev/null
+++ b/lib/libc/locale/querylocale.3
@@ -0,0 +1,54 @@
+.\" Copyright (c) 2011 The FreeBSD Foundation
+.\" All rights reserved.
+.\"
+.\" This documentation was written by David Chisnall under sponsorship from
+.\" the FreeBSD Foundation.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 May 3, 2013
+.Dt QUERYLOCALE 3
+.Os
+.Sh NAME
+.Nm querylocale
+.Nd Look up the locale name for a specified category
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In locale.h
+.Ft const char *
+.Fn querylocale "int mask" "locale_t locale"
+.Sh DESCRIPTION
+Returns the name of the locale for the category specified by
+.Fa mask .
+This possible values for the mask are the same as those in
+.Xr newlocale 3 .
+If more than one bit in the mask is set, the returned value is undefined.
+.Sh SEE ALSO
+.Xr duplocale 3 ,
+.Xr freelocale 3 ,
+.Xr localeconv 3 ,
+.Xr newlocale 3 ,
+.Xr uselocale 3 ,
+.Xr xlocale 3
diff --git a/lib/libc/locale/rpmatch.3 b/lib/libc/locale/rpmatch.3
new file mode 100644
index 000000000000..b34c5bfa199a
--- /dev/null
+++ b/lib/libc/locale/rpmatch.3
@@ -0,0 +1,66 @@
+.\"
+.\" Copyright (c) 2005 Tim J. Robbins
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd July 21, 2005
+.Dt RPMATCH 3
+.Os
+.Sh NAME
+.Nm rpmatch
+.Nd "determine whether the response to a question is affirmative or negative"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft int
+.Fn rpmatch "const char *response"
+.Sh DESCRIPTION
+The
+.Fn rpmatch
+function determines whether the
+.Fa response
+argument is an affirmative or negative response to a question
+according to the current locale.
+.Sh RETURN VALUES
+The
+.Fn rpmatch
+functions returns:
+.Bl -tag -width indent
+.It 1
+The response is affirmative.
+.It 0
+The response is negative.
+.It \&-1
+The response is not recognized.
+.El
+.Sh SEE ALSO
+.Xr nl_langinfo 3 ,
+.Xr setlocale 3
+.Sh HISTORY
+The
+.Fn rpmatch
+function appeared in
+.Fx 6.0 .
diff --git a/lib/libc/locale/rpmatch.c b/lib/libc/locale/rpmatch.c
new file mode 100644
index 000000000000..4d90eb8dcf8b
--- /dev/null
+++ b/lib/libc/locale/rpmatch.c
@@ -0,0 +1,55 @@
+/*-
+ * Copyright (c) 2004-2005 Tim J. Robbins.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <langinfo.h>
+#include <regex.h>
+#include <stdlib.h>
+
+int
+rpmatch(const char *response)
+{
+ regex_t yes, no;
+ int ret;
+
+ if (regcomp(&yes, nl_langinfo(YESEXPR), REG_EXTENDED|REG_NOSUB) != 0)
+ return (-1);
+ if (regcomp(&no, nl_langinfo(NOEXPR), REG_EXTENDED|REG_NOSUB) != 0) {
+ regfree(&yes);
+ return (-1);
+ }
+ if (regexec(&yes, response, 0, NULL, 0) == 0)
+ ret = 1;
+ else if (regexec(&no, response, 0, NULL, 0) == 0)
+ ret = 0;
+ else
+ ret = -1;
+ regfree(&yes);
+ regfree(&no);
+ return (ret);
+}
diff --git a/lib/libc/locale/rune.c b/lib/libc/locale/rune.c
new file mode 100644
index 000000000000..0b835f34ba07
--- /dev/null
+++ b/lib/libc/locale/rune.c
@@ -0,0 +1,252 @@
+/*-
+ * Copyright 2014 Garrett D'Amore <garrett@damore.org>
+ * Copyright 2010 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Borman at Krystal Technologies.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)rune.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <arpa/inet.h>
+#include <errno.h>
+#include <runetype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+#include "endian.h"
+#include "runefile.h"
+
+_RuneLocale *
+_Read_RuneMagi(const char *fname)
+{
+ char *fdata, *data;
+ void *lastp;
+ _FileRuneLocale *frl;
+ _RuneLocale *rl;
+ _FileRuneEntry *frr;
+ _RuneEntry *rr;
+ struct stat sb;
+ int x, saverr;
+ void *variable;
+ _FileRuneEntry *runetype_ext_ranges;
+ _FileRuneEntry *maplower_ext_ranges;
+ _FileRuneEntry *mapupper_ext_ranges;
+ int runetype_ext_len = 0;
+ int fd;
+
+ if ((fd = _open(fname, O_RDONLY)) < 0) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ if (_fstat(fd, &sb) < 0) {
+ (void) _close(fd);
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ if ((size_t)sb.st_size < sizeof (_FileRuneLocale)) {
+ (void) _close(fd);
+ errno = EINVAL;
+ return (NULL);
+ }
+
+
+ fdata = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ (void) _close(fd);
+ if (fdata == NULL) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ frl = (_FileRuneLocale *)(void *)fdata;
+ lastp = fdata + sb.st_size;
+
+ variable = frl + 1;
+
+ if (memcmp(frl->magic, _FILE_RUNE_MAGIC_1, sizeof (frl->magic))) {
+ goto invalid;
+ }
+
+ runetype_ext_ranges = (_FileRuneEntry *)variable;
+ variable = runetype_ext_ranges + BSWAP(frl->runetype_ext_nranges);
+ if (variable > lastp) {
+ goto invalid;
+ }
+
+ maplower_ext_ranges = (_FileRuneEntry *)variable;
+ variable = maplower_ext_ranges + BSWAP(frl->maplower_ext_nranges);
+ if (variable > lastp) {
+ goto invalid;
+ }
+
+ mapupper_ext_ranges = (_FileRuneEntry *)variable;
+ variable = mapupper_ext_ranges + BSWAP(frl->mapupper_ext_nranges);
+ if (variable > lastp) {
+ goto invalid;
+ }
+
+ frr = runetype_ext_ranges;
+ for (x = 0; x < BSWAP(frl->runetype_ext_nranges); ++x) {
+ uint32_t *types;
+
+ if (BSWAP(frr[x].map) == 0) {
+ int len = BSWAP(frr[x].max) - BSWAP(frr[x].min) + 1;
+ types = variable;
+ variable = types + len;
+ runetype_ext_len += len;
+ if (variable > lastp) {
+ goto invalid;
+ }
+ }
+ }
+
+ if ((char *)variable + BSWAP(frl->variable_len) > (char *)lastp) {
+ goto invalid;
+ }
+
+ /*
+ * Convert from disk format to host format.
+ */
+ data = malloc(sizeof(_RuneLocale) +
+ (BSWAP(frl->runetype_ext_nranges) + BSWAP(frl->maplower_ext_nranges) +
+ BSWAP(frl->mapupper_ext_nranges)) * sizeof(_RuneEntry) +
+ runetype_ext_len * sizeof(*rr->__types) +
+ BSWAP(frl->variable_len));
+ if (data == NULL) {
+ saverr = errno;
+ munmap(fdata, sb.st_size);
+ errno = saverr;
+ return (NULL);
+ }
+
+ rl = (_RuneLocale *)data;
+ rl->__variable = rl + 1;
+
+ memcpy(rl->__magic, _RUNE_MAGIC_1, sizeof(rl->__magic));
+ memcpy(rl->__encoding, frl->encoding, sizeof(rl->__encoding));
+
+ rl->__variable_len = BSWAP(frl->variable_len);
+ rl->__runetype_ext.__nranges = BSWAP(frl->runetype_ext_nranges);
+ rl->__maplower_ext.__nranges = BSWAP(frl->maplower_ext_nranges);
+ rl->__mapupper_ext.__nranges = BSWAP(frl->mapupper_ext_nranges);
+
+ for (x = 0; x < _CACHED_RUNES; ++x) {
+ rl->__runetype[x] = BSWAP(frl->runetype[x]);
+ rl->__maplower[x] = BSWAP(frl->maplower[x]);
+ rl->__mapupper[x] = BSWAP(frl->mapupper[x]);
+ }
+
+ rl->__runetype_ext.__ranges = (_RuneEntry *)rl->__variable;
+ rl->__variable = rl->__runetype_ext.__ranges +
+ rl->__runetype_ext.__nranges;
+
+ rl->__maplower_ext.__ranges = (_RuneEntry *)rl->__variable;
+ rl->__variable = rl->__maplower_ext.__ranges +
+ rl->__maplower_ext.__nranges;
+
+ rl->__mapupper_ext.__ranges = (_RuneEntry *)rl->__variable;
+ rl->__variable = rl->__mapupper_ext.__ranges +
+ rl->__mapupper_ext.__nranges;
+
+ variable = mapupper_ext_ranges + BSWAP(frl->mapupper_ext_nranges);
+ frr = runetype_ext_ranges;
+ rr = rl->__runetype_ext.__ranges;
+ for (x = 0; x < rl->__runetype_ext.__nranges; ++x) {
+ uint32_t *types;
+
+ rr[x].__min = BSWAP(frr[x].min);
+ rr[x].__max = BSWAP(frr[x].max);
+ rr[x].__map = BSWAP(frr[x].map);
+ if (rr[x].__map == 0) {
+ int len = rr[x].__max - rr[x].__min + 1;
+ types = variable;
+ variable = types + len;
+ rr[x].__types = rl->__variable;
+ rl->__variable = rr[x].__types + len;
+ while (len-- > 0)
+ rr[x].__types[len] = types[len];
+ } else
+ rr[x].__types = NULL;
+ }
+
+ frr = maplower_ext_ranges;
+ rr = rl->__maplower_ext.__ranges;
+ for (x = 0; x < rl->__maplower_ext.__nranges; ++x) {
+ rr[x].__min = BSWAP(frr[x].min);
+ rr[x].__max = BSWAP(frr[x].max);
+ rr[x].__map = BSWAP(frr[x].map);
+ }
+
+ frr = mapupper_ext_ranges;
+ rr = rl->__mapupper_ext.__ranges;
+ for (x = 0; x < rl->__mapupper_ext.__nranges; ++x) {
+ rr[x].__min = BSWAP(frr[x].min);
+ rr[x].__max = BSWAP(frr[x].max);
+ rr[x].__map = BSWAP(frr[x].map);
+ }
+
+ memcpy(rl->__variable, variable, rl->__variable_len);
+ munmap(fdata, sb.st_size);
+
+ /*
+ * Go out and zero pointers that should be zero.
+ */
+ if (!rl->__variable_len)
+ rl->__variable = NULL;
+
+ if (!rl->__runetype_ext.__nranges)
+ rl->__runetype_ext.__ranges = NULL;
+
+ if (!rl->__maplower_ext.__nranges)
+ rl->__maplower_ext.__ranges = NULL;
+
+ if (!rl->__mapupper_ext.__nranges)
+ rl->__mapupper_ext.__ranges = NULL;
+
+ return (rl);
+
+invalid:
+ munmap(fdata, sb.st_size);
+ errno = EINVAL;
+ return (NULL);
+}
diff --git a/lib/libc/locale/runefile.h b/lib/libc/locale/runefile.h
new file mode 100644
index 000000000000..ce1e47e5f92d
--- /dev/null
+++ b/lib/libc/locale/runefile.h
@@ -0,0 +1,61 @@
+/*-
+ * Copyright (c) 2005 Ruslan Ermilov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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 _RUNEFILE_H_
+#define _RUNEFILE_H_
+
+#include <sys/types.h>
+
+#ifndef _CACHED_RUNES
+#define _CACHED_RUNES (1 << 8)
+#endif
+
+typedef struct {
+ int32_t min;
+ int32_t max;
+ int32_t map;
+} _FileRuneEntry;
+
+typedef struct {
+ char magic[8];
+ char encoding[32];
+
+ uint32_t runetype[_CACHED_RUNES];
+ int32_t maplower[_CACHED_RUNES];
+ int32_t mapupper[_CACHED_RUNES];
+
+ int32_t runetype_ext_nranges;
+ int32_t maplower_ext_nranges;
+ int32_t mapupper_ext_nranges;
+
+ int32_t variable_len;
+} _FileRuneLocale;
+
+#define _FILE_RUNE_MAGIC_1 "RuneMag1"
+
+#endif /* !_RUNEFILE_H_ */
diff --git a/lib/libc/locale/runetype.c b/lib/libc/locale/runetype.c
new file mode 100644
index 000000000000..a0da47b5de98
--- /dev/null
+++ b/lib/libc/locale/runetype.c
@@ -0,0 +1,89 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Borman at Krystal Technologies.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <ctype.h>
+#include <stdio.h>
+#include <runetype.h>
+#include <wchar.h>
+#include "mblocal.h"
+
+unsigned long
+___runetype_l(__ct_rune_t c, locale_t locale)
+{
+ size_t lim;
+ FIX_LOCALE(locale);
+ _RuneRange *rr = &(XLOCALE_CTYPE(locale)->runes->__runetype_ext);
+ _RuneEntry *base, *re;
+
+ if (c < 0 || c == EOF)
+ return(0L);
+
+ /* Binary search -- see bsearch.c for explanation. */
+ base = rr->__ranges;
+ for (lim = rr->__nranges; lim != 0; lim >>= 1) {
+ re = base + (lim >> 1);
+ if (re->__min <= c && c <= re->__max) {
+ if (re->__types)
+ return(re->__types[c - re->__min]);
+ else
+ return(re->__map);
+ } else if (c > re->__max) {
+ base = re + 1;
+ lim--;
+ }
+ }
+
+ return(0L);
+}
+unsigned long
+___runetype(__ct_rune_t c)
+{
+ return ___runetype_l(c, __get_locale());
+}
+
+int ___mb_cur_max(void)
+{
+ return XLOCALE_CTYPE(__get_locale())->__mb_cur_max;
+}
+int ___mb_cur_max_l(locale_t locale)
+{
+ FIX_LOCALE(locale);
+ return XLOCALE_CTYPE(locale)->__mb_cur_max;
+}
diff --git a/lib/libc/locale/setlocale.3 b/lib/libc/locale/setlocale.3
new file mode 100644
index 000000000000..e0d06e8b8d5e
--- /dev/null
+++ b/lib/libc/locale/setlocale.3
@@ -0,0 +1,173 @@
+.\" Copyright (c) 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Donn Seeley at BSDI.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)setlocale.3 8.1 (Berkeley) 6/9/93
+.\" $FreeBSD$
+.\"
+.Dd November 21, 2003
+.Dt SETLOCALE 3
+.Os
+.Sh NAME
+.Nm setlocale
+.Nd natural language formatting for C
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In locale.h
+.Ft char *
+.Fn setlocale "int category" "const char *locale"
+.Sh DESCRIPTION
+The
+.Fn setlocale
+function sets the C library's notion
+of natural language formatting style
+for particular sets of routines.
+Each such style is called a
+.Sq locale
+and is invoked using an appropriate name passed as a C string.
+.Pp
+The
+.Fn setlocale
+function recognizes several categories of routines.
+These are the categories and the sets of routines they select:
+.Bl -tag -width LC_MONETARY
+.It Dv LC_ALL
+Set the entire locale generically.
+.It Dv LC_COLLATE
+Set a locale for string collation routines.
+This controls alphabetic ordering in
+.Fn strcoll
+and
+.Fn strxfrm .
+.It Dv LC_CTYPE
+Set a locale for the
+.Xr ctype 3
+and
+.Xr multibyte 3
+functions.
+This controls recognition of upper and lower case,
+alphabetic or non-alphabetic characters,
+and so on.
+.It Dv LC_MESSAGES
+Set a locale for message catalogs, see
+.Xr catopen 3
+function.
+.It Dv LC_MONETARY
+Set a locale for formatting monetary values;
+this affects the
+.Fn localeconv
+function.
+.It Dv LC_NUMERIC
+Set a locale for formatting numbers.
+This controls the formatting of decimal points
+in input and output of floating point numbers
+in functions such as
+.Fn printf
+and
+.Fn scanf ,
+as well as values returned by
+.Fn localeconv .
+.It Dv LC_TIME
+Set a locale for formatting dates and times using the
+.Fn strftime
+function.
+.El
+.Pp
+Only three locales are defined by default,
+the empty string
+.Li \&"\|"
+which denotes the native environment, and the
+.Li \&"C"
+and
+.Li \&"POSIX"
+locales, which denote the C language environment.
+A
+.Fa locale
+argument of
+.Dv NULL
+causes
+.Fn setlocale
+to return the current locale.
+By default, C programs start in the
+.Li \&"C"
+locale.
+The only function in the library that sets the locale is
+.Fn setlocale ;
+the locale is never changed as a side effect of some other routine.
+.Sh RETURN VALUES
+Upon successful completion,
+.Fn setlocale
+returns the string associated with the specified
+.Fa category
+for the requested
+.Fa locale .
+The
+.Fn setlocale
+function returns
+.Dv NULL
+and fails to change the locale
+if the given combination of
+.Fa category
+and
+.Fa locale
+makes no sense.
+.Sh FILES
+.Bl -tag -width /usr/share/locale/locale/category -compact
+.It Pa $PATH_LOCALE/ Ns Em locale/category
+.It Pa /usr/share/locale/ Ns Em locale/category
+locale file for the locale
+.Em locale
+and the category
+.Em category .
+.El
+.Sh ERRORS
+No errors are defined.
+.Sh SEE ALSO
+.Xr colldef 1 ,
+.Xr mklocale 1 ,
+.Xr catopen 3 ,
+.Xr ctype 3 ,
+.Xr localeconv 3 ,
+.Xr multibyte 3 ,
+.Xr strcoll 3 ,
+.Xr strxfrm 3 ,
+.Xr euc 5 ,
+.Xr utf8 5 ,
+.Xr environ 7
+.Sh STANDARDS
+The
+.Fn setlocale
+function conforms to
+.St -isoC-99 .
+.Sh HISTORY
+The
+.Fn setlocale
+function first appeared in
+.Bx 4.4 .
diff --git a/lib/libc/locale/setlocale.c b/lib/libc/locale/setlocale.c
new file mode 100644
index 000000000000..13ff25bfd88e
--- /dev/null
+++ b/lib/libc/locale/setlocale.c
@@ -0,0 +1,329 @@
+/*
+ * Copyright (c) 1996 - 2002 FreeBSD Project
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Borman at Krystal Technologies.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)setlocale.c 8.1 (Berkeley) 7/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <limits.h>
+#include <locale.h>
+#include <paths.h> /* for _PATH_LOCALE */
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "collate.h"
+#include "lmonetary.h" /* for __monetary_load_locale() */
+#include "lnumeric.h" /* for __numeric_load_locale() */
+#include "lmessages.h" /* for __messages_load_locale() */
+#include "setlocale.h"
+#include "ldpart.h"
+#include "../stdtime/timelocal.h" /* for __time_load_locale() */
+
+/*
+ * Category names for getenv()
+ */
+static const char categories[_LC_LAST][12] = {
+ "LC_ALL",
+ "LC_COLLATE",
+ "LC_CTYPE",
+ "LC_MONETARY",
+ "LC_NUMERIC",
+ "LC_TIME",
+ "LC_MESSAGES",
+};
+
+/*
+ * Current locales for each category
+ */
+static char current_categories[_LC_LAST][ENCODING_LEN + 1] = {
+ "C",
+ "C",
+ "C",
+ "C",
+ "C",
+ "C",
+ "C",
+};
+
+/*
+ * Path to locale storage directory
+ */
+char *_PathLocale;
+
+/*
+ * The locales we are going to try and load
+ */
+static char new_categories[_LC_LAST][ENCODING_LEN + 1];
+static char saved_categories[_LC_LAST][ENCODING_LEN + 1];
+
+static char current_locale_string[_LC_LAST * (ENCODING_LEN + 1/*"/"*/ + 1)];
+
+static char *currentlocale(void);
+static char *loadlocale(int);
+const char *__get_locale_env(int);
+
+char *
+setlocale(int category, const char *locale)
+{
+ int i, j, len, saverr;
+ const char *env, *r;
+
+ if (category < LC_ALL || category >= _LC_LAST) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ if (locale == NULL)
+ return (category != LC_ALL ?
+ current_categories[category] : currentlocale());
+
+ /*
+ * Default to the current locale for everything.
+ */
+ for (i = 1; i < _LC_LAST; ++i)
+ (void)strcpy(new_categories[i], current_categories[i]);
+
+ /*
+ * Now go fill up new_categories from the locale argument
+ */
+ if (!*locale) {
+ if (category == LC_ALL) {
+ for (i = 1; i < _LC_LAST; ++i) {
+ env = __get_locale_env(i);
+ if (strlen(env) > ENCODING_LEN) {
+ errno = EINVAL;
+ return (NULL);
+ }
+ (void)strcpy(new_categories[i], env);
+ }
+ } else {
+ env = __get_locale_env(category);
+ if (strlen(env) > ENCODING_LEN) {
+ errno = EINVAL;
+ return (NULL);
+ }
+ (void)strcpy(new_categories[category], env);
+ }
+ } else if (category != LC_ALL) {
+ if (strlen(locale) > ENCODING_LEN) {
+ errno = EINVAL;
+ return (NULL);
+ }
+ (void)strcpy(new_categories[category], locale);
+ } else {
+ if ((r = strchr(locale, '/')) == NULL) {
+ if (strlen(locale) > ENCODING_LEN) {
+ errno = EINVAL;
+ return (NULL);
+ }
+ for (i = 1; i < _LC_LAST; ++i)
+ (void)strcpy(new_categories[i], locale);
+ } else {
+ for (i = 1; r[1] == '/'; ++r)
+ ;
+ if (!r[1]) {
+ errno = EINVAL;
+ return (NULL); /* Hmm, just slashes... */
+ }
+ do {
+ if (i == _LC_LAST)
+ break; /* Too many slashes... */
+ if ((len = r - locale) > ENCODING_LEN) {
+ errno = EINVAL;
+ return (NULL);
+ }
+ (void)strlcpy(new_categories[i], locale,
+ len + 1);
+ i++;
+ while (*r == '/')
+ r++;
+ locale = r;
+ while (*r && *r != '/')
+ r++;
+ } while (*locale);
+ while (i < _LC_LAST) {
+ (void)strcpy(new_categories[i],
+ new_categories[i-1]);
+ i++;
+ }
+ }
+ }
+
+ if (category != LC_ALL)
+ return (loadlocale(category));
+
+ for (i = 1; i < _LC_LAST; ++i) {
+ (void)strcpy(saved_categories[i], current_categories[i]);
+ if (loadlocale(i) == NULL) {
+ saverr = errno;
+ for (j = 1; j < i; j++) {
+ (void)strcpy(new_categories[j],
+ saved_categories[j]);
+ if (loadlocale(j) == NULL) {
+ (void)strcpy(new_categories[j], "C");
+ (void)loadlocale(j);
+ }
+ }
+ errno = saverr;
+ return (NULL);
+ }
+ }
+ return (currentlocale());
+}
+
+static char *
+currentlocale(void)
+{
+ int i;
+
+ (void)strcpy(current_locale_string, current_categories[1]);
+
+ for (i = 2; i < _LC_LAST; ++i)
+ if (strcmp(current_categories[1], current_categories[i])) {
+ for (i = 2; i < _LC_LAST; ++i) {
+ (void)strcat(current_locale_string, "/");
+ (void)strcat(current_locale_string,
+ current_categories[i]);
+ }
+ break;
+ }
+ return (current_locale_string);
+}
+
+static char *
+loadlocale(int category)
+{
+ char *new = new_categories[category];
+ char *old = current_categories[category];
+ int (*func)(const char *);
+ int saved_errno;
+
+ if ((new[0] == '.' &&
+ (new[1] == '\0' || (new[1] == '.' && new[2] == '\0'))) ||
+ strchr(new, '/') != NULL) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ saved_errno = errno;
+ errno = __detect_path_locale();
+ if (errno != 0)
+ return (NULL);
+ errno = saved_errno;
+
+ switch (category) {
+ case LC_CTYPE:
+ func = __wrap_setrunelocale;
+ break;
+ case LC_COLLATE:
+ func = __collate_load_tables;
+ break;
+ case LC_TIME:
+ func = __time_load_locale;
+ break;
+ case LC_NUMERIC:
+ func = __numeric_load_locale;
+ break;
+ case LC_MONETARY:
+ func = __monetary_load_locale;
+ break;
+ case LC_MESSAGES:
+ func = __messages_load_locale;
+ break;
+ default:
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ if (strcmp(new, old) == 0)
+ return (old);
+
+ if (func(new) != _LDP_ERROR) {
+ (void)strcpy(old, new);
+ (void)strcpy(__xlocale_global_locale.components[category-1]->locale, new);
+ return (old);
+ }
+
+ return (NULL);
+}
+
+const char *
+__get_locale_env(int category)
+{
+ const char *env;
+
+ /* 1. check LC_ALL. */
+ env = getenv(categories[0]);
+
+ /* 2. check LC_* */
+ if (env == NULL || !*env)
+ env = getenv(categories[category]);
+
+ /* 3. check LANG */
+ if (env == NULL || !*env)
+ env = getenv("LANG");
+
+ /* 4. if none is set, fall to "C" */
+ if (env == NULL || !*env)
+ env = "C";
+
+ return (env);
+}
+
+/*
+ * Detect locale storage location and store its value to _PathLocale variable
+ */
+int
+__detect_path_locale(void)
+{
+ if (_PathLocale == NULL) {
+ char *p = getenv("PATH_LOCALE");
+
+ if (p != NULL && !issetugid()) {
+ if (strlen(p) + 1/*"/"*/ + ENCODING_LEN +
+ 1/*"/"*/ + CATEGORY_LEN >= PATH_MAX)
+ return (ENAMETOOLONG);
+ _PathLocale = strdup(p);
+ if (_PathLocale == NULL)
+ return (errno == 0 ? ENOMEM : errno);
+ } else
+ _PathLocale = _PATH_LOCALE;
+ }
+ return (0);
+}
+
diff --git a/lib/libc/locale/setlocale.h b/lib/libc/locale/setlocale.h
new file mode 100644
index 000000000000..33b4b6e9aeea
--- /dev/null
+++ b/lib/libc/locale/setlocale.h
@@ -0,0 +1,40 @@
+/*-
+ * Copyright (C) 1997 by Andrey A. Chernov, Moscow, Russia.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _SETLOCALE_H_
+#define _SETLOCALE_H_
+
+#define ENCODING_LEN 31
+#define CATEGORY_LEN 11
+
+extern char *_PathLocale;
+
+int __detect_path_locale(void);
+int __wrap_setrunelocale(const char *);
+
+#endif /* !_SETLOCALE_H_ */
diff --git a/lib/libc/locale/setrunelocale.c b/lib/libc/locale/setrunelocale.c
new file mode 100644
index 000000000000..1ebfc38e25cc
--- /dev/null
+++ b/lib/libc/locale/setrunelocale.c
@@ -0,0 +1,213 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Borman at Krystal Technologies.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#define __RUNETYPE_INTERNAL 1
+
+#include <runetype.h>
+#include <errno.h>
+#include <limits.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <wchar.h>
+#include "ldpart.h"
+#include "mblocal.h"
+#include "setlocale.h"
+
+#undef _CurrentRuneLocale
+extern _RuneLocale const *_CurrentRuneLocale;
+#ifndef __NO_TLS
+/*
+ * A cached version of the runes for this thread. Used by ctype.h
+ */
+_Thread_local const _RuneLocale *_ThreadRuneLocale;
+#endif
+
+extern int __mb_sb_limit;
+
+extern _RuneLocale *_Read_RuneMagi(const char *);
+
+static int __setrunelocale(struct xlocale_ctype *l, const char *);
+
+static void
+destruct_ctype(void *v)
+{
+ struct xlocale_ctype *l = v;
+
+ if (&_DefaultRuneLocale != l->runes)
+ free(l->runes);
+ free(l);
+}
+
+const _RuneLocale *
+__getCurrentRuneLocale(void)
+{
+
+ return XLOCALE_CTYPE(__get_locale())->runes;
+}
+
+static void
+free_runes(_RuneLocale *rl)
+{
+ if ((rl != &_DefaultRuneLocale) && (rl)) {
+ free(rl);
+ }
+}
+
+static int
+__setrunelocale(struct xlocale_ctype *l, const char *encoding)
+{
+ _RuneLocale *rl;
+ int ret;
+ char *path;
+ struct xlocale_ctype saved = *l;
+
+ /*
+ * The "C" and "POSIX" locale are always here.
+ */
+ if (strcmp(encoding, "C") == 0 || strcmp(encoding, "POSIX") == 0) {
+ free_runes(saved.runes);
+ (void) _none_init(l, (_RuneLocale*)&_DefaultRuneLocale);
+ return (0);
+ }
+
+ /* Range checking not needed, encoding length already checked before */
+ asprintf(&path, "%s/%s/LC_CTYPE", _PathLocale, encoding);
+ if (path == NULL)
+ return (0);
+
+ if ((rl = _Read_RuneMagi(path)) == NULL) {
+ free(path);
+ errno = EINVAL;
+ return (errno);
+ }
+ free(path);
+
+ l->__mbrtowc = NULL;
+ l->__mbsinit = NULL;
+ l->__mbsnrtowcs = NULL;
+ l->__wcrtomb = NULL;
+ l->__wcsnrtombs = NULL;
+
+ rl->__sputrune = NULL;
+ rl->__sgetrune = NULL;
+ if (strcmp(rl->__encoding, "NONE:US-ASCII") == 0)
+ ret = _ascii_init(l, rl);
+ else if (strncmp(rl->__encoding, "NONE", 4) == 0)
+ ret = _none_init(l, rl);
+ else if (strcmp(rl->__encoding, "UTF-8") == 0)
+ ret = _UTF8_init(l, rl);
+ else if (strcmp(rl->__encoding, "EUC-CN") == 0)
+ ret = _EUC_CN_init(l, rl);
+ else if (strcmp(rl->__encoding, "EUC-JP") == 0)
+ ret = _EUC_JP_init(l, rl);
+ else if (strcmp(rl->__encoding, "EUC-KR") == 0)
+ ret = _EUC_KR_init(l, rl);
+ else if (strcmp(rl->__encoding, "EUC-TW") == 0)
+ ret = _EUC_TW_init(l, rl);
+ else if (strcmp(rl->__encoding, "GB18030") == 0)
+ ret = _GB18030_init(l, rl);
+ else if (strcmp(rl->__encoding, "GB2312") == 0)
+ ret = _GB2312_init(l, rl);
+ else if (strcmp(rl->__encoding, "GBK") == 0)
+ ret = _GBK_init(l, rl);
+ else if (strcmp(rl->__encoding, "BIG5") == 0)
+ ret = _BIG5_init(l, rl);
+ else if (strcmp(rl->__encoding, "MSKanji") == 0)
+ ret = _MSKanji_init(l, rl);
+ else
+ ret = EFTYPE;
+
+ if (ret == 0) {
+ /* Free the old runes if it exists. */
+ free_runes(saved.runes);
+ } else {
+ /* Restore the saved version if this failed. */
+ memcpy(l, &saved, sizeof(struct xlocale_ctype));
+ free(rl);
+ }
+
+ return (ret);
+}
+
+int
+__wrap_setrunelocale(const char *locale)
+{
+ int ret = __setrunelocale(&__xlocale_global_ctype, locale);
+
+ if (ret != 0) {
+ errno = ret;
+ return (_LDP_ERROR);
+ }
+ __mb_cur_max = __xlocale_global_ctype.__mb_cur_max;
+ __mb_sb_limit = __xlocale_global_ctype.__mb_sb_limit;
+ _CurrentRuneLocale = __xlocale_global_ctype.runes;
+ return (_LDP_LOADED);
+}
+
+#ifndef __NO_TLS
+void
+__set_thread_rune_locale(locale_t loc)
+{
+
+ if (loc == NULL) {
+ _ThreadRuneLocale = &_DefaultRuneLocale;
+ } else if (loc == LC_GLOBAL_LOCALE) {
+ _ThreadRuneLocale = 0;
+ } else {
+ _ThreadRuneLocale = XLOCALE_CTYPE(loc)->runes;
+ }
+}
+#endif
+
+void *
+__ctype_load(const char *locale, locale_t unused __unused)
+{
+ struct xlocale_ctype *l = calloc(sizeof(struct xlocale_ctype), 1);
+
+ l->header.header.destructor = destruct_ctype;
+ if (__setrunelocale(l, locale))
+ {
+ free(l);
+ return NULL;
+ }
+ return l;
+}
diff --git a/lib/libc/locale/table.c b/lib/libc/locale/table.c
new file mode 100644
index 000000000000..80b19f5ced5e
--- /dev/null
+++ b/lib/libc/locale/table.c
@@ -0,0 +1,263 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Borman at Krystal Technologies.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)table.c 8.1 (Berkeley) 6/27/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <ctype.h>
+#include <runetype.h>
+#include <wchar.h>
+#include "mblocal.h"
+
+const _RuneLocale _DefaultRuneLocale = {
+ _RUNE_MAGIC_1,
+ "NONE",
+ NULL,
+ NULL,
+ 0xFFFD,
+
+ { /*00*/ _CTYPE_C,
+ _CTYPE_C,
+ _CTYPE_C,
+ _CTYPE_C,
+ _CTYPE_C,
+ _CTYPE_C,
+ _CTYPE_C,
+ _CTYPE_C,
+ /*08*/ _CTYPE_C,
+ _CTYPE_C|_CTYPE_S|_CTYPE_B,
+ _CTYPE_C|_CTYPE_S,
+ _CTYPE_C|_CTYPE_S,
+ _CTYPE_C|_CTYPE_S,
+ _CTYPE_C|_CTYPE_S,
+ _CTYPE_C,
+ _CTYPE_C,
+ /*10*/ _CTYPE_C,
+ _CTYPE_C,
+ _CTYPE_C,
+ _CTYPE_C,
+ _CTYPE_C,
+ _CTYPE_C,
+ _CTYPE_C,
+ _CTYPE_C,
+ /*18*/ _CTYPE_C,
+ _CTYPE_C,
+ _CTYPE_C,
+ _CTYPE_C,
+ _CTYPE_C,
+ _CTYPE_C,
+ _CTYPE_C,
+ _CTYPE_C,
+ /*20*/ _CTYPE_S|_CTYPE_B|_CTYPE_R,
+ _CTYPE_P|_CTYPE_R|_CTYPE_G,
+ _CTYPE_P|_CTYPE_R|_CTYPE_G,
+ _CTYPE_P|_CTYPE_R|_CTYPE_G,
+ _CTYPE_P|_CTYPE_R|_CTYPE_G,
+ _CTYPE_P|_CTYPE_R|_CTYPE_G,
+ _CTYPE_P|_CTYPE_R|_CTYPE_G,
+ _CTYPE_P|_CTYPE_R|_CTYPE_G,
+ /*28*/ _CTYPE_P|_CTYPE_R|_CTYPE_G,
+ _CTYPE_P|_CTYPE_R|_CTYPE_G,
+ _CTYPE_P|_CTYPE_R|_CTYPE_G,
+ _CTYPE_P|_CTYPE_R|_CTYPE_G,
+ _CTYPE_P|_CTYPE_R|_CTYPE_G,
+ _CTYPE_P|_CTYPE_R|_CTYPE_G,
+ _CTYPE_P|_CTYPE_R|_CTYPE_G,
+ _CTYPE_P|_CTYPE_R|_CTYPE_G,
+ /*30*/ _CTYPE_D|_CTYPE_R|_CTYPE_G|_CTYPE_X|_CTYPE_N|0,
+ _CTYPE_D|_CTYPE_R|_CTYPE_G|_CTYPE_X|_CTYPE_N|1,
+ _CTYPE_D|_CTYPE_R|_CTYPE_G|_CTYPE_X|_CTYPE_N|2,
+ _CTYPE_D|_CTYPE_R|_CTYPE_G|_CTYPE_X|_CTYPE_N|3,
+ _CTYPE_D|_CTYPE_R|_CTYPE_G|_CTYPE_X|_CTYPE_N|4,
+ _CTYPE_D|_CTYPE_R|_CTYPE_G|_CTYPE_X|_CTYPE_N|5,
+ _CTYPE_D|_CTYPE_R|_CTYPE_G|_CTYPE_X|_CTYPE_N|6,
+ _CTYPE_D|_CTYPE_R|_CTYPE_G|_CTYPE_X|_CTYPE_N|7,
+ /*38*/ _CTYPE_D|_CTYPE_R|_CTYPE_G|_CTYPE_X|_CTYPE_N|8,
+ _CTYPE_D|_CTYPE_R|_CTYPE_G|_CTYPE_X|_CTYPE_N|9,
+ _CTYPE_P|_CTYPE_R|_CTYPE_G,
+ _CTYPE_P|_CTYPE_R|_CTYPE_G,
+ _CTYPE_P|_CTYPE_R|_CTYPE_G,
+ _CTYPE_P|_CTYPE_R|_CTYPE_G,
+ _CTYPE_P|_CTYPE_R|_CTYPE_G,
+ _CTYPE_P|_CTYPE_R|_CTYPE_G,
+ /*40*/ _CTYPE_P|_CTYPE_R|_CTYPE_G,
+ _CTYPE_U|_CTYPE_X|_CTYPE_R|_CTYPE_G|_CTYPE_A|10,
+ _CTYPE_U|_CTYPE_X|_CTYPE_R|_CTYPE_G|_CTYPE_A|11,
+ _CTYPE_U|_CTYPE_X|_CTYPE_R|_CTYPE_G|_CTYPE_A|12,
+ _CTYPE_U|_CTYPE_X|_CTYPE_R|_CTYPE_G|_CTYPE_A|13,
+ _CTYPE_U|_CTYPE_X|_CTYPE_R|_CTYPE_G|_CTYPE_A|14,
+ _CTYPE_U|_CTYPE_X|_CTYPE_R|_CTYPE_G|_CTYPE_A|15,
+ _CTYPE_U|_CTYPE_R|_CTYPE_G|_CTYPE_A,
+ /*48*/ _CTYPE_U|_CTYPE_R|_CTYPE_G|_CTYPE_A,
+ _CTYPE_U|_CTYPE_R|_CTYPE_G|_CTYPE_A,
+ _CTYPE_U|_CTYPE_R|_CTYPE_G|_CTYPE_A,
+ _CTYPE_U|_CTYPE_R|_CTYPE_G|_CTYPE_A,
+ _CTYPE_U|_CTYPE_R|_CTYPE_G|_CTYPE_A,
+ _CTYPE_U|_CTYPE_R|_CTYPE_G|_CTYPE_A,
+ _CTYPE_U|_CTYPE_R|_CTYPE_G|_CTYPE_A,
+ _CTYPE_U|_CTYPE_R|_CTYPE_G|_CTYPE_A,
+ /*50*/ _CTYPE_U|_CTYPE_R|_CTYPE_G|_CTYPE_A,
+ _CTYPE_U|_CTYPE_R|_CTYPE_G|_CTYPE_A,
+ _CTYPE_U|_CTYPE_R|_CTYPE_G|_CTYPE_A,
+ _CTYPE_U|_CTYPE_R|_CTYPE_G|_CTYPE_A,
+ _CTYPE_U|_CTYPE_R|_CTYPE_G|_CTYPE_A,
+ _CTYPE_U|_CTYPE_R|_CTYPE_G|_CTYPE_A,
+ _CTYPE_U|_CTYPE_R|_CTYPE_G|_CTYPE_A,
+ _CTYPE_U|_CTYPE_R|_CTYPE_G|_CTYPE_A,
+ /*58*/ _CTYPE_U|_CTYPE_R|_CTYPE_G|_CTYPE_A,
+ _CTYPE_U|_CTYPE_R|_CTYPE_G|_CTYPE_A,
+ _CTYPE_U|_CTYPE_R|_CTYPE_G|_CTYPE_A,
+ _CTYPE_P|_CTYPE_R|_CTYPE_G,
+ _CTYPE_P|_CTYPE_R|_CTYPE_G,
+ _CTYPE_P|_CTYPE_R|_CTYPE_G,
+ _CTYPE_P|_CTYPE_R|_CTYPE_G,
+ _CTYPE_P|_CTYPE_R|_CTYPE_G,
+ /*60*/ _CTYPE_P|_CTYPE_R|_CTYPE_G,
+ _CTYPE_L|_CTYPE_X|_CTYPE_R|_CTYPE_G|_CTYPE_A|10,
+ _CTYPE_L|_CTYPE_X|_CTYPE_R|_CTYPE_G|_CTYPE_A|11,
+ _CTYPE_L|_CTYPE_X|_CTYPE_R|_CTYPE_G|_CTYPE_A|12,
+ _CTYPE_L|_CTYPE_X|_CTYPE_R|_CTYPE_G|_CTYPE_A|13,
+ _CTYPE_L|_CTYPE_X|_CTYPE_R|_CTYPE_G|_CTYPE_A|14,
+ _CTYPE_L|_CTYPE_X|_CTYPE_R|_CTYPE_G|_CTYPE_A|15,
+ _CTYPE_L|_CTYPE_R|_CTYPE_G|_CTYPE_A,
+ /*68*/ _CTYPE_L|_CTYPE_R|_CTYPE_G|_CTYPE_A,
+ _CTYPE_L|_CTYPE_R|_CTYPE_G|_CTYPE_A,
+ _CTYPE_L|_CTYPE_R|_CTYPE_G|_CTYPE_A,
+ _CTYPE_L|_CTYPE_R|_CTYPE_G|_CTYPE_A,
+ _CTYPE_L|_CTYPE_R|_CTYPE_G|_CTYPE_A,
+ _CTYPE_L|_CTYPE_R|_CTYPE_G|_CTYPE_A,
+ _CTYPE_L|_CTYPE_R|_CTYPE_G|_CTYPE_A,
+ _CTYPE_L|_CTYPE_R|_CTYPE_G|_CTYPE_A,
+ /*70*/ _CTYPE_L|_CTYPE_R|_CTYPE_G|_CTYPE_A,
+ _CTYPE_L|_CTYPE_R|_CTYPE_G|_CTYPE_A,
+ _CTYPE_L|_CTYPE_R|_CTYPE_G|_CTYPE_A,
+ _CTYPE_L|_CTYPE_R|_CTYPE_G|_CTYPE_A,
+ _CTYPE_L|_CTYPE_R|_CTYPE_G|_CTYPE_A,
+ _CTYPE_L|_CTYPE_R|_CTYPE_G|_CTYPE_A,
+ _CTYPE_L|_CTYPE_R|_CTYPE_G|_CTYPE_A,
+ _CTYPE_L|_CTYPE_R|_CTYPE_G|_CTYPE_A,
+ /*78*/ _CTYPE_L|_CTYPE_R|_CTYPE_G|_CTYPE_A,
+ _CTYPE_L|_CTYPE_R|_CTYPE_G|_CTYPE_A,
+ _CTYPE_L|_CTYPE_R|_CTYPE_G|_CTYPE_A,
+ _CTYPE_P|_CTYPE_R|_CTYPE_G,
+ _CTYPE_P|_CTYPE_R|_CTYPE_G,
+ _CTYPE_P|_CTYPE_R|_CTYPE_G,
+ _CTYPE_P|_CTYPE_R|_CTYPE_G,
+ _CTYPE_C,
+ },
+ { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+ 'x', 'y', 'z', 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+ 'x', 'y', 'z', 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
+ },
+ { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
+ },
+};
+
+#undef _CurrentRuneLocale
+const _RuneLocale *_CurrentRuneLocale = &_DefaultRuneLocale;
+
+_RuneLocale *
+__runes_for_locale(locale_t locale, int *mb_sb_limit)
+{
+ FIX_LOCALE(locale);
+ struct xlocale_ctype *c = XLOCALE_CTYPE(locale);
+ *mb_sb_limit = c->__mb_sb_limit;
+ return c->runes;
+}
diff --git a/lib/libc/locale/toascii.3 b/lib/libc/locale/toascii.3
new file mode 100644
index 000000000000..97243cb53acf
--- /dev/null
+++ b/lib/libc/locale/toascii.3
@@ -0,0 +1,69 @@
+.\" Copyright (c) 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)toascii.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt TOASCII 3
+.Os
+.Sh NAME
+.Nm toascii
+.Nd convert a byte to 7-bit ASCII
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In ctype.h
+.Ft int
+.Fn toascii "int c"
+.Sh DESCRIPTION
+The
+.Fn toascii
+function strips all but the low 7 bits from a letter,
+including parity or other marker bits.
+.Sh RETURN VALUES
+The
+.Fn toascii
+function always returns a valid ASCII character.
+.Sh SEE ALSO
+.Xr digittoint 3 ,
+.Xr isalnum 3 ,
+.Xr isalpha 3 ,
+.Xr isascii 3 ,
+.Xr iscntrl 3 ,
+.Xr isdigit 3 ,
+.Xr isgraph 3 ,
+.Xr islower 3 ,
+.Xr isprint 3 ,
+.Xr ispunct 3 ,
+.Xr isspace 3 ,
+.Xr isupper 3 ,
+.Xr isxdigit 3 ,
+.Xr stdio 3 ,
+.Xr tolower 3 ,
+.Xr toupper 3 ,
+.Xr ascii 7
diff --git a/lib/libc/locale/tolower.3 b/lib/libc/locale/tolower.3
new file mode 100644
index 000000000000..a5cb819d7b44
--- /dev/null
+++ b/lib/libc/locale/tolower.3
@@ -0,0 +1,79 @@
+.\" Copyright (c) 1989, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)tolower.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd July 25, 2010
+.Dt TOLOWER 3
+.Os
+.Sh NAME
+.Nm tolower
+.Nd upper case to lower case letter conversion
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In ctype.h
+.Ft int
+.Fn tolower "int c"
+.Sh DESCRIPTION
+The
+.Fn tolower
+function converts an upper-case letter to the corresponding lower-case
+letter.
+The argument must be representable as an
+.Vt "unsigned char"
+or the value of
+.Dv EOF .
+.Sh RETURN VALUES
+If the argument is an upper-case letter, the
+.Fn tolower
+function returns the corresponding lower-case letter if there is
+one; otherwise, the argument is returned unchanged.
+.Sh COMPATIBILITY
+The
+.Bx 4.4
+extension of accepting arguments outside of the range of the
+.Vt "unsigned char"
+type in locales with large character sets is considered obsolete
+and may not be supported in future releases.
+The
+.Fn towlower
+function should be used instead.
+.Sh SEE ALSO
+.Xr ctype 3 ,
+.Xr islower 3 ,
+.Xr towlower 3
+.Sh STANDARDS
+The
+.Fn tolower
+function conforms to
+.St -isoC .
diff --git a/lib/libc/locale/tolower.c b/lib/libc/locale/tolower.c
new file mode 100644
index 000000000000..c74791da370c
--- /dev/null
+++ b/lib/libc/locale/tolower.c
@@ -0,0 +1,76 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Borman at Krystal Technologies.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <ctype.h>
+#include <stdio.h>
+#include <runetype.h>
+#include <wchar.h>
+#include "mblocal.h"
+
+__ct_rune_t
+___tolower_l(__ct_rune_t c, locale_t l)
+{
+ size_t lim;
+ FIX_LOCALE(l);
+ _RuneRange *rr = &XLOCALE_CTYPE(l)->runes->__maplower_ext;
+ _RuneEntry *base, *re;
+
+ if (c < 0 || c == EOF)
+ return(c);
+
+ /* Binary search -- see bsearch.c for explanation. */
+ base = rr->__ranges;
+ for (lim = rr->__nranges; lim != 0; lim >>= 1) {
+ re = base + (lim >> 1);
+ if (re->__min <= c && c <= re->__max)
+ return (re->__map + c - re->__min);
+ else if (c > re->__max) {
+ base = re + 1;
+ lim--;
+ }
+ }
+
+ return(c);
+}
+__ct_rune_t
+___tolower(__ct_rune_t c)
+{
+ return ___tolower_l(c, __get_locale());
+}
diff --git a/lib/libc/locale/toupper.3 b/lib/libc/locale/toupper.3
new file mode 100644
index 000000000000..0fd3cbb1a1b4
--- /dev/null
+++ b/lib/libc/locale/toupper.3
@@ -0,0 +1,79 @@
+.\" Copyright (c) 1989, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)toupper.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd July 25, 2010
+.Dt TOUPPER 3
+.Os
+.Sh NAME
+.Nm toupper
+.Nd lower case to upper case letter conversion
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In ctype.h
+.Ft int
+.Fn toupper "int c"
+.Sh DESCRIPTION
+The
+.Fn toupper
+function converts a lower-case letter to the corresponding
+upper-case letter.
+The argument must be representable as an
+.Vt "unsigned char"
+or the value of
+.Dv EOF .
+.Sh RETURN VALUES
+If the argument is a lower-case letter, the
+.Fn toupper
+function returns the corresponding upper-case letter if there is
+one; otherwise, the argument is returned unchanged.
+.Sh COMPATIBILITY
+The
+.Bx 4.4
+extension of accepting arguments outside of the range of the
+.Vt "unsigned char"
+type in locales with large character sets is considered obsolete
+and may not be supported in future releases.
+The
+.Fn towupper
+function should be used instead.
+.Sh SEE ALSO
+.Xr ctype 3 ,
+.Xr isupper 3 ,
+.Xr towupper 3
+.Sh STANDARDS
+The
+.Fn toupper
+function conforms to
+.St -isoC .
diff --git a/lib/libc/locale/toupper.c b/lib/libc/locale/toupper.c
new file mode 100644
index 000000000000..2c5ec86de434
--- /dev/null
+++ b/lib/libc/locale/toupper.c
@@ -0,0 +1,78 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Borman at Krystal Technologies.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <ctype.h>
+#include <stdio.h>
+#include <runetype.h>
+#include <wchar.h>
+#include "mblocal.h"
+
+__ct_rune_t
+___toupper_l(__ct_rune_t c, locale_t l)
+{
+ size_t lim;
+ FIX_LOCALE(l);
+ _RuneRange *rr = &XLOCALE_CTYPE(l)->runes->__mapupper_ext;
+ _RuneEntry *base, *re;
+
+ if (c < 0 || c == EOF)
+ return(c);
+
+ /* Binary search -- see bsearch.c for explanation. */
+ base = rr->__ranges;
+ for (lim = rr->__nranges; lim != 0; lim >>= 1) {
+ re = base + (lim >> 1);
+ if (re->__min <= c && c <= re->__max)
+ {
+ return (re->__map + c - re->__min);
+ }
+ else if (c > re->__max) {
+ base = re + 1;
+ lim--;
+ }
+ }
+
+ return(c);
+}
+__ct_rune_t
+___toupper(__ct_rune_t c)
+{
+ return ___toupper_l(c, __get_locale());
+}
diff --git a/lib/libc/locale/towlower.3 b/lib/libc/locale/towlower.3
new file mode 100644
index 000000000000..96e2951cfc33
--- /dev/null
+++ b/lib/libc/locale/towlower.3
@@ -0,0 +1,66 @@
+.\" Copyright (c) 1989, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)tolower.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd October 3, 2002
+.Dt TOWLOWER 3
+.Os
+.Sh NAME
+.Nm towlower
+.Nd "upper case to lower case letter conversion (wide character version)"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In wctype.h
+.Ft wint_t
+.Fn towlower "wint_t wc"
+.Sh DESCRIPTION
+The
+.Fn towlower
+function converts an upper-case letter to the corresponding lower-case
+letter.
+.Sh RETURN VALUES
+If the argument is an upper-case letter, the
+.Fn towlower
+function returns the corresponding lower-case letter if there is
+one; otherwise the argument is returned unchanged.
+.Sh SEE ALSO
+.Xr iswlower 3 ,
+.Xr tolower 3 ,
+.Xr towupper 3 ,
+.Xr wctrans 3
+.Sh STANDARDS
+The
+.Fn towlower
+function conforms to
+.St -isoC-99 .
diff --git a/lib/libc/locale/towupper.3 b/lib/libc/locale/towupper.3
new file mode 100644
index 000000000000..05216709facb
--- /dev/null
+++ b/lib/libc/locale/towupper.3
@@ -0,0 +1,66 @@
+.\" Copyright (c) 1989, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)toupper.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd October 3, 2002
+.Dt TOWUPPER 3
+.Os
+.Sh NAME
+.Nm towupper
+.Nd "lower case to upper case letter conversion (wide character version)"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In wctype.h
+.Ft wint_t
+.Fn towupper "wint_t wc"
+.Sh DESCRIPTION
+The
+.Fn towupper
+function converts a lower-case letter to the corresponding
+upper-case letter.
+.Sh RETURN VALUES
+If the argument is a lower-case letter, the
+.Fn towupper
+function returns the corresponding upper-case letter if there is
+one; otherwise the argument is returned unchanged.
+.Sh SEE ALSO
+.Xr iswupper 3 ,
+.Xr toupper 3 ,
+.Xr towlower 3 ,
+.Xr wctrans 3
+.Sh STANDARDS
+The
+.Fn towupper
+function conforms to
+.St -isoC-99 .
diff --git a/lib/libc/locale/uselocale.3 b/lib/libc/locale/uselocale.3
new file mode 100644
index 000000000000..96d0008f7837
--- /dev/null
+++ b/lib/libc/locale/uselocale.3
@@ -0,0 +1,60 @@
+.\" Copyright (c) 2011 The FreeBSD Foundation
+.\" All rights reserved.
+.\"
+.\" This documentation was written by David Chisnall under sponsorship from
+.\" the FreeBSD Foundation.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 September 17, 2011
+.Dt USELOCALE 3
+.Os
+.Sh NAME
+.Nm uselocale
+.Nd Sets a thread-local locale
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In locale.h
+.Ft locale_t
+.Fn uselocale "locale_t locale"
+.Sh DESCRIPTION
+Specifies the locale for this thread to use.
+Specifying
+.Fa LC_GLOBAL_LOCALE
+disables the per-thread locale,
+while NULL returns the current locale without setting a new one.
+.Sh RETURN VALUES
+Returns the previous locale,
+or LC_GLOBAL_LOCALE if this thread has no locale associated with it.
+.Sh SEE ALSO
+.Xr duplocale 3 ,
+.Xr freelocale 3 ,
+.Xr localeconv 3 ,
+.Xr newlocale 3 ,
+.Xr querylocale 3 ,
+.Xr xlocale 3
+.Sh STANDARDS
+This function conforms to
+.St -p1003.1-2008 .
diff --git a/lib/libc/locale/utf8.5 b/lib/libc/locale/utf8.5
new file mode 100644
index 000000000000..c11aa01af676
--- /dev/null
+++ b/lib/libc/locale/utf8.5
@@ -0,0 +1,102 @@
+.\" Copyright (c) 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Paul Borman at Krystal Technologies.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)utf2.4 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd April 7, 2004
+.Dt UTF8 5
+.Os
+.Sh NAME
+.Nm utf8
+.Nd "UTF-8, a transformation format of ISO 10646"
+.Sh SYNOPSIS
+.Nm ENCODING
+.Qq UTF-8
+.Sh DESCRIPTION
+The
+.Nm UTF-8
+encoding represents UCS-4 characters as a sequence of octets, using
+between 1 and 6 for each character.
+It is backwards compatible with
+.Tn ASCII ,
+so 0x00-0x7f refer to the
+.Tn ASCII
+character set.
+The multibyte encoding of
+.No non- Ns Tn ASCII
+characters
+consist entirely of bytes whose high order bit is set.
+The actual
+encoding is represented by the following table:
+.Bd -literal
+[0x00000000 - 0x0000007f] [00000000.0bbbbbbb] -> 0bbbbbbb
+[0x00000080 - 0x000007ff] [00000bbb.bbbbbbbb] -> 110bbbbb, 10bbbbbb
+[0x00000800 - 0x0000ffff] [bbbbbbbb.bbbbbbbb] ->
+ 1110bbbb, 10bbbbbb, 10bbbbbb
+[0x00010000 - 0x001fffff] [00000000.000bbbbb.bbbbbbbb.bbbbbbbb] ->
+ 11110bbb, 10bbbbbb, 10bbbbbb, 10bbbbbb
+[0x00200000 - 0x03ffffff] [000000bb.bbbbbbbb.bbbbbbbb.bbbbbbbb] ->
+ 111110bb, 10bbbbbb, 10bbbbbb, 10bbbbbb, 10bbbbbb
+[0x04000000 - 0x7fffffff] [0bbbbbbb.bbbbbbbb.bbbbbbbb.bbbbbbbb] ->
+ 1111110b, 10bbbbbb, 10bbbbbb, 10bbbbbb, 10bbbbbb, 10bbbbbb
+.Ed
+.Pp
+If more than a single representation of a value exists (for example,
+0x00; 0xC0 0x80; 0xE0 0x80 0x80) the shortest representation is always
+used.
+Longer ones are detected as an error as they pose a potential
+security risk, and destroy the 1:1 character:octet sequence mapping.
+.Sh SEE ALSO
+.Xr euc 5
+.Rs
+.%A "Rob Pike"
+.%A "Ken Thompson"
+.%T "Hello World"
+.%J "Proceedings of the Winter 1993 USENIX Technical Conference"
+.%Q "USENIX Association"
+.%D "January 1993"
+.Re
+.Rs
+.%A "F. Yergeau"
+.%T "UTF-8, a transformation format of ISO 10646"
+.%O "RFC 2279"
+.%D "January 1998"
+.Re
+.Rs
+.%Q "The Unicode Consortium"
+.%T "The Unicode Standard, Version 3.0"
+.%D "2000"
+.%O "as amended by the Unicode Standard Annex #27: Unicode 3.1 and by the Unicode Standard Annex #28: Unicode 3.2"
+.Re
+.Sh STANDARDS
+The
+.Nm
+encoding is compatible with RFC 2279 and Unicode 3.2.
diff --git a/lib/libc/locale/utf8.c b/lib/libc/locale/utf8.c
new file mode 100644
index 000000000000..e096b8783947
--- /dev/null
+++ b/lib/libc/locale/utf8.c
@@ -0,0 +1,424 @@
+/*-
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2002-2004 Tim J. Robbins
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <limits.h>
+#include <runetype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include "mblocal.h"
+
+extern int __mb_sb_limit;
+
+static size_t _UTF8_mbrtowc(wchar_t * __restrict, const char * __restrict,
+ size_t, mbstate_t * __restrict);
+static int _UTF8_mbsinit(const mbstate_t *);
+static size_t _UTF8_mbsnrtowcs(wchar_t * __restrict,
+ const char ** __restrict, size_t, size_t,
+ mbstate_t * __restrict);
+static size_t _UTF8_wcrtomb(char * __restrict, wchar_t,
+ mbstate_t * __restrict);
+static size_t _UTF8_wcsnrtombs(char * __restrict, const wchar_t ** __restrict,
+ size_t, size_t, mbstate_t * __restrict);
+
+typedef struct {
+ wchar_t ch;
+ int want;
+ wchar_t lbound;
+} _UTF8State;
+
+int
+_UTF8_init(struct xlocale_ctype *l, _RuneLocale *rl)
+{
+
+ l->__mbrtowc = _UTF8_mbrtowc;
+ l->__wcrtomb = _UTF8_wcrtomb;
+ l->__mbsinit = _UTF8_mbsinit;
+ l->__mbsnrtowcs = _UTF8_mbsnrtowcs;
+ l->__wcsnrtombs = _UTF8_wcsnrtombs;
+ l->runes = rl;
+ l->__mb_cur_max = 4;
+ /*
+ * UCS-4 encoding used as the internal representation, so
+ * slots 0x0080-0x00FF are occuped and must be excluded
+ * from the single byte ctype by setting the limit.
+ */
+ l->__mb_sb_limit = 128;
+
+ return (0);
+}
+
+static int
+_UTF8_mbsinit(const mbstate_t *ps)
+{
+
+ return (ps == NULL || ((const _UTF8State *)ps)->want == 0);
+}
+
+static size_t
+_UTF8_mbrtowc(wchar_t * __restrict pwc, const char * __restrict s, size_t n,
+ mbstate_t * __restrict ps)
+{
+ _UTF8State *us;
+ int ch, i, mask, want;
+ wchar_t lbound, wch;
+
+ us = (_UTF8State *)ps;
+
+ if (us->want < 0 || us->want > 6) {
+ errno = EINVAL;
+ return ((size_t)-1);
+ }
+
+ if (s == NULL) {
+ s = "";
+ n = 1;
+ pwc = NULL;
+ }
+
+ if (n == 0)
+ /* Incomplete multibyte sequence */
+ return ((size_t)-2);
+
+ if (us->want == 0) {
+ /*
+ * Determine the number of octets that make up this character
+ * from the first octet, and a mask that extracts the
+ * interesting bits of the first octet. We already know
+ * the character is at least two bytes long.
+ *
+ * We also specify a lower bound for the character code to
+ * detect redundant, non-"shortest form" encodings. For
+ * example, the sequence C0 80 is _not_ a legal representation
+ * of the null character. This enforces a 1-to-1 mapping
+ * between character codes and their multibyte representations.
+ */
+ ch = (unsigned char)*s;
+ if ((ch & 0x80) == 0) {
+ /* Fast path for plain ASCII characters. */
+ if (pwc != NULL)
+ *pwc = ch;
+ return (ch != '\0' ? 1 : 0);
+ }
+ if ((ch & 0xe0) == 0xc0) {
+ mask = 0x1f;
+ want = 2;
+ lbound = 0x80;
+ } else if ((ch & 0xf0) == 0xe0) {
+ mask = 0x0f;
+ want = 3;
+ lbound = 0x800;
+ } else if ((ch & 0xf8) == 0xf0) {
+ mask = 0x07;
+ want = 4;
+ lbound = 0x10000;
+ } else {
+ /*
+ * Malformed input; input is not UTF-8.
+ */
+ errno = EILSEQ;
+ return ((size_t)-1);
+ }
+ } else {
+ want = us->want;
+ lbound = us->lbound;
+ }
+
+ /*
+ * Decode the octet sequence representing the character in chunks
+ * of 6 bits, most significant first.
+ */
+ if (us->want == 0)
+ wch = (unsigned char)*s++ & mask;
+ else
+ wch = us->ch;
+
+ for (i = (us->want == 0) ? 1 : 0; i < MIN(want, n); i++) {
+ if ((*s & 0xc0) != 0x80) {
+ /*
+ * Malformed input; bad characters in the middle
+ * of a character.
+ */
+ errno = EILSEQ;
+ return ((size_t)-1);
+ }
+ wch <<= 6;
+ wch |= *s++ & 0x3f;
+ }
+ if (i < want) {
+ /* Incomplete multibyte sequence. */
+ us->want = want - i;
+ us->lbound = lbound;
+ us->ch = wch;
+ return ((size_t)-2);
+ }
+ if (wch < lbound) {
+ /*
+ * Malformed input; redundant encoding.
+ */
+ errno = EILSEQ;
+ return ((size_t)-1);
+ }
+ if ((wch >= 0xd800 && wch <= 0xdfff) || wch > 0x10ffff) {
+ /*
+ * Malformed input; invalid code points.
+ */
+ errno = EILSEQ;
+ return ((size_t)-1);
+ }
+ if (pwc != NULL)
+ *pwc = wch;
+ us->want = 0;
+ return (wch == L'\0' ? 0 : want);
+}
+
+static size_t
+_UTF8_mbsnrtowcs(wchar_t * __restrict dst, const char ** __restrict src,
+ size_t nms, size_t len, mbstate_t * __restrict ps)
+{
+ _UTF8State *us;
+ const char *s;
+ size_t nchr;
+ wchar_t wc;
+ size_t nb;
+
+ us = (_UTF8State *)ps;
+
+ s = *src;
+ nchr = 0;
+
+ if (dst == NULL) {
+ /*
+ * The fast path in the loop below is not safe if an ASCII
+ * character appears as anything but the first byte of a
+ * multibyte sequence. Check now to avoid doing it in the loop.
+ */
+ if (nms > 0 && us->want > 0 && (signed char)*s > 0) {
+ errno = EILSEQ;
+ return ((size_t)-1);
+ }
+ for (;;) {
+ if (nms > 0 && (signed char)*s > 0)
+ /*
+ * Fast path for plain ASCII characters
+ * excluding NUL.
+ */
+ nb = 1;
+ else if ((nb = _UTF8_mbrtowc(&wc, s, nms, ps)) ==
+ (size_t)-1)
+ /* Invalid sequence - mbrtowc() sets errno. */
+ return ((size_t)-1);
+ else if (nb == 0 || nb == (size_t)-2)
+ return (nchr);
+ s += nb;
+ nms -= nb;
+ nchr++;
+ }
+ /*NOTREACHED*/
+ }
+
+ /*
+ * The fast path in the loop below is not safe if an ASCII
+ * character appears as anything but the first byte of a
+ * multibyte sequence. Check now to avoid doing it in the loop.
+ */
+ if (nms > 0 && len > 0 && us->want > 0 && (signed char)*s > 0) {
+ errno = EILSEQ;
+ return ((size_t)-1);
+ }
+ while (len-- > 0) {
+ if (nms > 0 && (signed char)*s > 0) {
+ /*
+ * Fast path for plain ASCII characters
+ * excluding NUL.
+ */
+ *dst = (wchar_t)*s;
+ nb = 1;
+ } else if ((nb = _UTF8_mbrtowc(dst, s, nms, ps)) ==
+ (size_t)-1) {
+ *src = s;
+ return ((size_t)-1);
+ } else if (nb == (size_t)-2) {
+ *src = s + nms;
+ return (nchr);
+ } else if (nb == 0) {
+ *src = NULL;
+ return (nchr);
+ }
+ s += nb;
+ nms -= nb;
+ nchr++;
+ dst++;
+ }
+ *src = s;
+ return (nchr);
+}
+
+static size_t
+_UTF8_wcrtomb(char * __restrict s, wchar_t wc, mbstate_t * __restrict ps)
+{
+ _UTF8State *us;
+ unsigned char lead;
+ int i, len;
+
+ us = (_UTF8State *)ps;
+
+ if (us->want != 0) {
+ errno = EINVAL;
+ return ((size_t)-1);
+ }
+
+ if (s == NULL)
+ /* Reset to initial shift state (no-op) */
+ return (1);
+
+ /*
+ * Determine the number of octets needed to represent this character.
+ * We always output the shortest sequence possible. Also specify the
+ * first few bits of the first octet, which contains the information
+ * about the sequence length.
+ */
+ if ((wc & ~0x7f) == 0) {
+ /* Fast path for plain ASCII characters. */
+ *s = (char)wc;
+ return (1);
+ } else if ((wc & ~0x7ff) == 0) {
+ lead = 0xc0;
+ len = 2;
+ } else if ((wc & ~0xffff) == 0) {
+ if (wc >= 0xd800 && wc <= 0xdfff) {
+ errno = EILSEQ;
+ return ((size_t)-1);
+ }
+ lead = 0xe0;
+ len = 3;
+ } else if (wc >= 0 && wc <= 0x10ffff) {
+ lead = 0xf0;
+ len = 4;
+ } else {
+ errno = EILSEQ;
+ return ((size_t)-1);
+ }
+
+ /*
+ * Output the octets representing the character in chunks
+ * of 6 bits, least significant last. The first octet is
+ * a special case because it contains the sequence length
+ * information.
+ */
+ for (i = len - 1; i > 0; i--) {
+ s[i] = (wc & 0x3f) | 0x80;
+ wc >>= 6;
+ }
+ *s = (wc & 0xff) | lead;
+
+ return (len);
+}
+
+static size_t
+_UTF8_wcsnrtombs(char * __restrict dst, const wchar_t ** __restrict src,
+ size_t nwc, size_t len, mbstate_t * __restrict ps)
+{
+ _UTF8State *us;
+ char buf[MB_LEN_MAX];
+ const wchar_t *s;
+ size_t nbytes;
+ size_t nb;
+
+ us = (_UTF8State *)ps;
+
+ if (us->want != 0) {
+ errno = EINVAL;
+ return ((size_t)-1);
+ }
+
+ s = *src;
+ nbytes = 0;
+
+ if (dst == NULL) {
+ while (nwc-- > 0) {
+ if (0 <= *s && *s < 0x80)
+ /* Fast path for plain ASCII characters. */
+ nb = 1;
+ else if ((nb = _UTF8_wcrtomb(buf, *s, ps)) ==
+ (size_t)-1)
+ /* Invalid character - wcrtomb() sets errno. */
+ return ((size_t)-1);
+ if (*s == L'\0')
+ return (nbytes + nb - 1);
+ s++;
+ nbytes += nb;
+ }
+ return (nbytes);
+ }
+
+ while (len > 0 && nwc-- > 0) {
+ if (0 <= *s && *s < 0x80) {
+ /* Fast path for plain ASCII characters. */
+ nb = 1;
+ *dst = *s;
+ } else if (len > (size_t)MB_CUR_MAX) {
+ /* Enough space to translate in-place. */
+ if ((nb = _UTF8_wcrtomb(dst, *s, ps)) == (size_t)-1) {
+ *src = s;
+ return ((size_t)-1);
+ }
+ } else {
+ /*
+ * May not be enough space; use temp. buffer.
+ */
+ if ((nb = _UTF8_wcrtomb(buf, *s, ps)) == (size_t)-1) {
+ *src = s;
+ return ((size_t)-1);
+ }
+ if (nb > (int)len)
+ /* MB sequence for character won't fit. */
+ break;
+ memcpy(dst, buf, nb);
+ }
+ if (*s == L'\0') {
+ *src = NULL;
+ return (nbytes + nb - 1);
+ }
+ s++;
+ dst += nb;
+ len -= nb;
+ nbytes += nb;
+ }
+ *src = s;
+ return (nbytes);
+}
diff --git a/lib/libc/locale/wcrtomb.3 b/lib/libc/locale/wcrtomb.3
new file mode 100644
index 000000000000..bc741740a249
--- /dev/null
+++ b/lib/libc/locale/wcrtomb.3
@@ -0,0 +1,123 @@
+.\" Copyright (c) 2002-2004 Tim J. Robbins
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd May 21, 2013
+.Dt WCRTOMB 3
+.Os
+.Sh NAME
+.Nm wcrtomb ,
+.Nm c16rtomb ,
+.Nm c32rtomb
+.Nd "convert a wide-character code to a character (restartable)"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In wchar.h
+.Ft size_t
+.Fn wcrtomb "char * restrict s" "wchar_t c" "mbstate_t * restrict ps"
+.In uchar.h
+.Ft size_t
+.Fn c16rtomb "char * restrict s" "char16_t c" "mbstate_t * restrict ps"
+.Ft size_t
+.Fn c32rtomb "char * restrict s" "char32_t c" "mbstate_t * restrict ps"
+.Sh DESCRIPTION
+The
+.Fn wcrtomb ,
+.Fn c16rtomb
+and
+.Fn c32rtomb
+functions store a multibyte sequence representing the
+wide character
+.Fa c ,
+including any necessary shift sequences, to the
+character array
+.Fa s ,
+storing a maximum of
+.Dv MB_CUR_MAX
+bytes.
+.Pp
+If
+.Fa s
+is
+.Dv NULL ,
+these functions behave as if
+.Fa s
+pointed to an internal buffer and
+.Fa c
+was a null wide character (L'\e0').
+.Pp
+The
+.Ft mbstate_t
+argument,
+.Fa ps ,
+is used to keep track of the shift state.
+If it is
+.Dv NULL ,
+these functions use an internal, static
+.Vt mbstate_t
+object, which is initialized to the initial conversion state
+at program startup.
+.Pp
+As certain multibyte characters may only be represented by a series of
+16-bit characters, the
+.Fn c16rtomb
+may need to invoked multiple times before a multibyte sequence is
+returned.
+.Sh RETURN VALUES
+These functions return the length (in bytes) of the multibyte sequence
+needed to represent
+.Fa c ,
+or
+.Po Vt size_t Pc Ns \-1
+if
+.Fa c
+is not a valid wide character code.
+.Sh ERRORS
+The
+.Fn wcrtomb ,
+.Fn c16rtomb
+and
+.Fn c32rtomb
+functions will fail if:
+.Bl -tag -width Er
+.It Bq Er EILSEQ
+An invalid wide character code was specified.
+.It Bq Er EINVAL
+The conversion state is invalid.
+.El
+.Sh SEE ALSO
+.Xr mbrtowc 3 ,
+.Xr multibyte 3 ,
+.Xr setlocale 3 ,
+.Xr wctomb 3
+.Sh STANDARDS
+The
+.Fn wcrtomb ,
+.Fn c16rtomb
+and
+.Fn c32rtomb
+functions conform to
+.St -isoC-2011 .
diff --git a/lib/libc/locale/wcrtomb.c b/lib/libc/locale/wcrtomb.c
new file mode 100644
index 000000000000..32d4df2af64c
--- /dev/null
+++ b/lib/libc/locale/wcrtomb.c
@@ -0,0 +1,52 @@
+/*-
+ * Copyright (c) 2002-2004 Tim J. Robbins.
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 <wchar.h>
+#include "mblocal.h"
+
+size_t
+wcrtomb_l(char * __restrict s, wchar_t wc, mbstate_t * __restrict ps,
+ locale_t locale)
+{
+ FIX_LOCALE(locale);
+ if (ps == NULL)
+ ps = &locale->wcrtomb;
+ return (XLOCALE_CTYPE(locale)->__wcrtomb(s, wc, ps));
+}
+
+size_t
+wcrtomb(char * __restrict s, wchar_t wc, mbstate_t * __restrict ps)
+{
+ return wcrtomb_l(s, wc, ps, __get_locale());
+}
diff --git a/lib/libc/locale/wcsftime.3 b/lib/libc/locale/wcsftime.3
new file mode 100644
index 000000000000..92aee9313f59
--- /dev/null
+++ b/lib/libc/locale/wcsftime.3
@@ -0,0 +1,66 @@
+.\" Copyright (c) 2002 Tim J. Robbins
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd September 8, 2002
+.Dt WCSFTIME 3
+.Os
+.Sh NAME
+.Nm wcsftime
+.Nd "convert date and time to a wide-character string"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In wchar.h
+.Ft size_t
+.Fo wcsftime
+.Fa "wchar_t * restrict wcs" "size_t maxsize"
+.Fa "const wchar_t * restrict format" "const struct tm * restrict timeptr"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn wcsftime
+function is equivalent to the
+.Fn strftime
+function except for the types of its arguments.
+Refer to
+.Xr strftime 3
+for a detailed description.
+.Sh COMPATIBILITY
+Some early implementations of
+.Fn wcsftime
+had a
+.Fa format
+argument with type
+.Vt "const char *"
+instead of
+.Vt "const wchar_t *" .
+.Sh SEE ALSO
+.Xr strftime 3
+.Sh STANDARDS
+The
+.Fn wcsftime
+function conforms to
+.St -isoC-99 .
diff --git a/lib/libc/locale/wcsftime.c b/lib/libc/locale/wcsftime.c
new file mode 100644
index 000000000000..c4f6b2ee4e5f
--- /dev/null
+++ b/lib/libc/locale/wcsftime.c
@@ -0,0 +1,122 @@
+/*-
+ * Copyright (c) 2002 Tim J. Robbins
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <time.h>
+#include <wchar.h>
+#include "xlocale_private.h"
+
+/*
+ * Convert date and time to a wide-character string.
+ *
+ * This is the wide-character counterpart of strftime(). So that we do not
+ * have to duplicate the code of strftime(), we convert the format string to
+ * multibyte, call strftime(), then convert the result back into wide
+ * characters.
+ *
+ * This technique loses in the presence of stateful multibyte encoding if any
+ * of the conversions in the format string change conversion state. When
+ * stateful encoding is implemented, we will need to reset the state between
+ * format specifications in the format string.
+ */
+size_t
+wcsftime_l(wchar_t * __restrict wcs, size_t maxsize,
+ const wchar_t * __restrict format, const struct tm * __restrict timeptr,
+ locale_t locale)
+{
+ static const mbstate_t initial;
+ mbstate_t mbs;
+ char *dst, *sformat;
+ const char *dstp;
+ const wchar_t *formatp;
+ size_t n, sflen;
+ int sverrno;
+ FIX_LOCALE(locale);
+
+ sformat = dst = NULL;
+
+ /*
+ * Convert the supplied format string to a multibyte representation
+ * for strftime(), which only handles single-byte characters.
+ */
+ mbs = initial;
+ formatp = format;
+ sflen = wcsrtombs_l(NULL, &formatp, 0, &mbs, locale);
+ if (sflen == (size_t)-1)
+ goto error;
+ if ((sformat = malloc(sflen + 1)) == NULL)
+ goto error;
+ mbs = initial;
+ wcsrtombs_l(sformat, &formatp, sflen + 1, &mbs, locale);
+
+ /*
+ * Allocate memory for longest multibyte sequence that will fit
+ * into the caller's buffer and call strftime() to fill it.
+ * Then, copy and convert the result back into wide characters in
+ * the caller's buffer.
+ */
+ if (SIZE_T_MAX / MB_CUR_MAX <= maxsize) {
+ /* maxsize is prepostorously large - avoid int. overflow. */
+ errno = EINVAL;
+ goto error;
+ }
+ if ((dst = malloc(maxsize * MB_CUR_MAX)) == NULL)
+ goto error;
+ if (strftime_l(dst, maxsize, sformat, timeptr, locale) == 0)
+ goto error;
+ dstp = dst;
+ mbs = initial;
+ n = mbsrtowcs_l(wcs, &dstp, maxsize, &mbs, locale);
+ if (n == (size_t)-2 || n == (size_t)-1 || dstp != NULL)
+ goto error;
+
+ free(sformat);
+ free(dst);
+ return (n);
+
+error:
+ sverrno = errno;
+ free(sformat);
+ free(dst);
+ errno = sverrno;
+ return (0);
+}
+size_t
+wcsftime(wchar_t * __restrict wcs, size_t maxsize,
+ const wchar_t * __restrict format, const struct tm * __restrict timeptr)
+{
+ return wcsftime_l(wcs, maxsize, format, timeptr, __get_locale());
+}
diff --git a/lib/libc/locale/wcsnrtombs.c b/lib/libc/locale/wcsnrtombs.c
new file mode 100644
index 000000000000..ce77ebbffc4c
--- /dev/null
+++ b/lib/libc/locale/wcsnrtombs.c
@@ -0,0 +1,125 @@
+/*-
+ * Copyright 2013 Garrett D'Amore <garrett@damore.org>
+ * Copyright 2010 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2002-2004 Tim J. Robbins.
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include "mblocal.h"
+
+size_t
+wcsnrtombs_l(char * __restrict dst, const wchar_t ** __restrict src, size_t nwc,
+ size_t len, mbstate_t * __restrict ps, locale_t locale)
+{
+ FIX_LOCALE(locale);
+ if (ps == NULL)
+ ps = &locale->wcsnrtombs;
+ return (XLOCALE_CTYPE(locale)->__wcsnrtombs(dst, src, nwc, len, ps));
+}
+size_t
+wcsnrtombs(char * __restrict dst, const wchar_t ** __restrict src, size_t nwc,
+ size_t len, mbstate_t * __restrict ps)
+{
+ return wcsnrtombs_l(dst, src, nwc, len, ps, __get_locale());
+}
+
+
+size_t
+__wcsnrtombs_std(char * __restrict dst, const wchar_t ** __restrict src,
+ size_t nwc, size_t len, mbstate_t * __restrict ps,
+ wcrtomb_pfn_t pwcrtomb)
+{
+ mbstate_t mbsbak;
+ char buf[MB_LEN_MAX];
+ const wchar_t *s;
+ size_t nbytes;
+ size_t nb;
+
+ s = *src;
+ nbytes = 0;
+
+ if (dst == NULL) {
+ while (nwc-- > 0) {
+ if ((nb = pwcrtomb(buf, *s, ps)) == (size_t)-1)
+ /* Invalid character - wcrtomb() sets errno. */
+ return ((size_t)-1);
+ else if (*s == L'\0')
+ return (nbytes + nb - 1);
+ s++;
+ nbytes += nb;
+ }
+ return (nbytes);
+ }
+
+ while (len > 0 && nwc-- > 0) {
+ if (len > (size_t)MB_CUR_MAX) {
+ /* Enough space to translate in-place. */
+ if ((nb = pwcrtomb(dst, *s, ps)) == (size_t)-1) {
+ *src = s;
+ return ((size_t)-1);
+ }
+ } else {
+ /*
+ * May not be enough space; use temp. buffer.
+ *
+ * We need to save a copy of the conversion state
+ * here so we can restore it if the multibyte
+ * character is too long for the buffer.
+ */
+ mbsbak = *ps;
+ if ((nb = pwcrtomb(buf, *s, ps)) == (size_t)-1) {
+ *src = s;
+ return ((size_t)-1);
+ }
+ if (nb > (int)len) {
+ /* MB sequence for character won't fit. */
+ *ps = mbsbak;
+ break;
+ }
+ memcpy(dst, buf, nb);
+ }
+ if (*s == L'\0') {
+ *src = NULL;
+ return (nbytes + nb - 1);
+ }
+ s++;
+ dst += nb;
+ len -= nb;
+ nbytes += nb;
+ }
+ *src = s;
+ return (nbytes);
+}
diff --git a/lib/libc/locale/wcsrtombs.3 b/lib/libc/locale/wcsrtombs.3
new file mode 100644
index 000000000000..ff607c2dad11
--- /dev/null
+++ b/lib/libc/locale/wcsrtombs.3
@@ -0,0 +1,134 @@
+.\" Copyright (c) 2002-2004 Tim J. Robbins
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd July 21, 2004
+.Dt WCSRTOMBS 3
+.Os
+.Sh NAME
+.Nm wcsrtombs ,
+.Nm wcsnrtombs
+.Nd "convert a wide-character string to a character string (restartable)"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In wchar.h
+.Ft size_t
+.Fo wcsrtombs
+.Fa "char * restrict dst" "const wchar_t ** restrict src"
+.Fa "size_t len" "mbstate_t * restrict ps"
+.Fc
+.Ft size_t
+.Fo wcsnrtombs
+.Fa "char * restrict dst" "const wchar_t ** restrict src" "size_t nwc"
+.Fa "size_t len" "mbstate_t * restrict ps"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn wcsrtombs
+function converts a string of wide characters indirectly pointed to by
+.Fa src
+to a corresponding multibyte character string stored in the array
+pointed to by
+.Fa dst .
+No more than
+.Fa len
+bytes are written to
+.Fa dst .
+.Pp
+If
+.Fa dst
+is
+.Dv NULL ,
+no characters are stored.
+.Pp
+If
+.Fa dst
+is not
+.Dv NULL ,
+the pointer pointed to by
+.Fa src
+is updated to point to the character after the one that conversion stopped at.
+If conversion stops because a null character is encountered,
+.Fa *src
+is set to
+.Dv NULL .
+.Pp
+The
+.Vt mbstate_t
+argument,
+.Fa ps ,
+is used to keep track of the shift state.
+If it is
+.Dv NULL ,
+.Fn wcsrtombs
+uses an internal, static
+.Vt mbstate_t
+object, which is initialized to the initial conversion state
+at program startup.
+.Pp
+The
+.Fn wcsnrtombs
+function behaves identically to
+.Fn wcsrtombs ,
+except that conversion stops after reading at most
+.Fa nwc
+characters from the buffer pointed to by
+.Fa src .
+.Sh RETURN VALUES
+The
+.Fn wcsrtombs
+and
+.Fn wcsnrtombs
+functions return the number of bytes stored in
+the array pointed to by
+.Fa dst
+(not including any terminating null), if successful, otherwise it returns
+.Po Vt size_t Pc Ns \-1 .
+.Sh ERRORS
+The
+.Fn wcsrtombs
+and
+.Fn wcsnrtombs
+functions will fail if:
+.Bl -tag -width Er
+.It Bq Er EILSEQ
+An invalid wide character was encountered.
+.It Bq Er EINVAL
+The conversion state is invalid.
+.El
+.Sh SEE ALSO
+.Xr mbsrtowcs 3 ,
+.Xr wcrtomb 3 ,
+.Xr wcstombs 3
+.Sh STANDARDS
+The
+.Fn wcsrtombs
+function conforms to
+.St -isoC-99 .
+.Pp
+The
+.Fn wcsnrtombs
+function is an extension to the standard.
diff --git a/lib/libc/locale/wcsrtombs.c b/lib/libc/locale/wcsrtombs.c
new file mode 100644
index 000000000000..f6d1ca07f523
--- /dev/null
+++ b/lib/libc/locale/wcsrtombs.c
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 2002-2004 Tim J. Robbins.
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include "mblocal.h"
+
+size_t
+wcsrtombs_l(char * __restrict dst, const wchar_t ** __restrict src, size_t len,
+ mbstate_t * __restrict ps, locale_t locale)
+{
+ FIX_LOCALE(locale);
+ if (ps == NULL)
+ ps = &locale->wcsrtombs;
+ return (XLOCALE_CTYPE(locale)->__wcsnrtombs(dst, src, SIZE_T_MAX, len, ps));
+}
+
+size_t
+wcsrtombs(char * __restrict dst, const wchar_t ** __restrict src, size_t len,
+ mbstate_t * __restrict ps)
+{
+ return wcsrtombs_l(dst, src, len, ps, __get_locale());
+}
diff --git a/lib/libc/locale/wcstod.3 b/lib/libc/locale/wcstod.3
new file mode 100644
index 000000000000..f8c5135ee86b
--- /dev/null
+++ b/lib/libc/locale/wcstod.3
@@ -0,0 +1,73 @@
+.\" Copyright (c) 2002, 2003 Tim J. Robbins
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd February 22, 2003
+.Dt WCSTOD 3
+.Os
+.Sh NAME
+.Nm wcstof ,
+.Nm wcstod ,
+.Nm wcstold
+.Nd convert string to
+.Vt float , double
+or
+.Vt "long double"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In wchar.h
+.Ft float
+.Fn wcstof "const wchar_t * restrict nptr" "wchar_t ** restrict endptr"
+.Ft "long double"
+.Fn wcstold "const wchar_t * restrict nptr" "wchar_t ** restrict endptr"
+.Ft double
+.Fn wcstod "const wchar_t * restrict nptr" "wchar_t ** restrict endptr"
+.Sh DESCRIPTION
+The
+.Fn wcstof ,
+.Fn wcstod
+and
+.Fn wcstold
+functions are the wide-character versions of the
+.Fn strtof ,
+.Fn strtod
+and
+.Fn strtold
+functions.
+Refer to
+.Xr strtod 3
+for details.
+.Sh SEE ALSO
+.Xr strtod 3 ,
+.Xr wcstol 3
+.Sh STANDARDS
+The
+.Fn wcstof ,
+.Fn wcstod
+and
+.Fn wcstold
+functions conform to
+.St -isoC-99 .
diff --git a/lib/libc/locale/wcstod.c b/lib/libc/locale/wcstod.c
new file mode 100644
index 000000000000..c6ae1417c1de
--- /dev/null
+++ b/lib/libc/locale/wcstod.c
@@ -0,0 +1,116 @@
+/*-
+ * Copyright (c) 2002 Tim J. Robbins
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 <stdlib.h>
+#include <wchar.h>
+#include <wctype.h>
+#include "xlocale_private.h"
+
+/*
+ * Convert a string to a double-precision number.
+ *
+ * This is the wide-character counterpart of strtod(). So that we do not
+ * have to duplicate the code of strtod() here, we convert the supplied
+ * wide character string to multibyte and call strtod() on the result.
+ * This assumes that the multibyte encoding is compatible with ASCII
+ * for at least the digits, radix character and letters.
+ */
+double
+wcstod_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
+ locale_t locale)
+{
+ static const mbstate_t initial;
+ mbstate_t mbs;
+ double val;
+ char *buf, *end;
+ const wchar_t *wcp;
+ size_t len;
+ size_t spaces;
+ FIX_LOCALE(locale);
+
+ wcp = nptr;
+ spaces = 0;
+ while (iswspace_l(*wcp, locale)) {
+ wcp++;
+ spaces++;
+ }
+
+ /*
+ * Convert the supplied numeric wide char. string to multibyte.
+ *
+ * We could attempt to find the end of the numeric portion of the
+ * wide char. string to avoid converting unneeded characters but
+ * choose not to bother; optimising the uncommon case where
+ * the input string contains a lot of text after the number
+ * duplicates a lot of strtod()'s functionality and slows down the
+ * most common cases.
+ */
+ mbs = initial;
+ if ((len = wcsrtombs_l(NULL, &wcp, 0, &mbs, locale)) == (size_t)-1) {
+ if (endptr != NULL)
+ *endptr = (wchar_t *)nptr;
+ return (0.0);
+ }
+ if ((buf = malloc(len + 1)) == NULL) {
+ if (endptr != NULL)
+ *endptr = (wchar_t *)nptr;
+ return (0.0);
+ }
+ mbs = initial;
+ wcsrtombs_l(buf, &wcp, len + 1, &mbs, locale);
+
+ /* Let strtod() do most of the work for us. */
+ val = strtod_l(buf, &end, locale);
+
+ /*
+ * We only know where the number ended in the _multibyte_
+ * representation of the string. If the caller wants to know
+ * where it ended, count multibyte characters to find the
+ * corresponding position in the wide char string.
+ */
+ if (endptr != NULL) {
+ *endptr = (wchar_t *)nptr + (end - buf);
+ if (buf != end)
+ *endptr += spaces;
+ }
+
+ free(buf);
+
+ return (val);
+}
+double
+wcstod(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr)
+{
+ return wcstod_l(nptr, endptr, __get_locale());
+}
diff --git a/lib/libc/locale/wcstof.c b/lib/libc/locale/wcstof.c
new file mode 100644
index 000000000000..99ce0fe4af2c
--- /dev/null
+++ b/lib/libc/locale/wcstof.c
@@ -0,0 +1,93 @@
+/*-
+ * Copyright (c) 2002, 2003 Tim J. Robbins
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 <stdlib.h>
+#include <wchar.h>
+#include <wctype.h>
+#include "xlocale_private.h"
+
+/*
+ * See wcstod() for comments as to the logic used.
+ */
+float
+wcstof_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
+ locale_t locale)
+{
+ static const mbstate_t initial;
+ mbstate_t mbs;
+ float val;
+ char *buf, *end;
+ const wchar_t *wcp;
+ size_t len;
+ size_t spaces;
+ FIX_LOCALE(locale);
+
+ wcp = nptr;
+ spaces = 0;
+ while (iswspace_l(*wcp, locale)) {
+ wcp++;
+ spaces++;
+ }
+
+ mbs = initial;
+ if ((len = wcsrtombs_l(NULL, &wcp, 0, &mbs, locale)) == (size_t)-1) {
+ if (endptr != NULL)
+ *endptr = (wchar_t *)nptr;
+ return (0.0);
+ }
+ if ((buf = malloc(len + 1)) == NULL) {
+ if (endptr != NULL)
+ *endptr = (wchar_t *)nptr;
+ return (0.0);
+ }
+ mbs = initial;
+ wcsrtombs_l(buf, &wcp, len + 1, &mbs, locale);
+
+ val = strtof_l(buf, &end, locale);
+
+ if (endptr != NULL) {
+ *endptr = (wchar_t *)nptr + (end - buf);
+ if (buf != end)
+ *endptr += spaces;
+ }
+
+ free(buf);
+
+ return (val);
+}
+float
+wcstof(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr)
+{
+ return wcstof_l(nptr, endptr, __get_locale());
+}
diff --git a/lib/libc/locale/wcstoimax.c b/lib/libc/locale/wcstoimax.c
new file mode 100644
index 000000000000..ce066a53462b
--- /dev/null
+++ b/lib/libc/locale/wcstoimax.c
@@ -0,0 +1,137 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#if 0
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "from @(#)strtol.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+__FBSDID("FreeBSD: src/lib/libc/stdlib/strtoimax.c,v 1.8 2002/09/06 11:23:59 tjr Exp ");
+#endif
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include <wctype.h>
+#include "xlocale_private.h"
+
+/*
+ * Convert a wide character string to an intmax_t integer.
+ */
+intmax_t
+wcstoimax_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
+ int base, locale_t locale)
+{
+ const wchar_t *s;
+ uintmax_t acc;
+ wchar_t c;
+ uintmax_t cutoff;
+ int neg, any, cutlim;
+ FIX_LOCALE(locale);
+
+ /*
+ * See strtoimax for comments as to the logic used.
+ */
+ s = nptr;
+ do {
+ c = *s++;
+ } while (iswspace_l(c, locale));
+ if (c == L'-') {
+ neg = 1;
+ c = *s++;
+ } else {
+ neg = 0;
+ if (c == L'+')
+ c = *s++;
+ }
+ if ((base == 0 || base == 16) &&
+ c == L'0' && (*s == L'x' || *s == L'X')) {
+ c = s[1];
+ s += 2;
+ base = 16;
+ }
+ if (base == 0)
+ base = c == L'0' ? 8 : 10;
+ acc = any = 0;
+ if (base < 2 || base > 36)
+ goto noconv;
+
+ cutoff = neg ? (uintmax_t)-(INTMAX_MIN + INTMAX_MAX) + INTMAX_MAX
+ : INTMAX_MAX;
+ cutlim = cutoff % base;
+ cutoff /= base;
+ for ( ; ; c = *s++) {
+#ifdef notyet
+ if (iswdigit_l(c, locale))
+ c = digittoint_l(c, locale);
+ else
+#endif
+ if (c >= L'0' && c <= L'9')
+ c -= L'0';
+ else if (c >= L'A' && c <= L'Z')
+ c -= L'A' - 10;
+ else if (c >= 'a' && c <= 'z')
+ c -= L'a' - 10;
+ else
+ break;
+ if (c >= base)
+ break;
+ if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
+ any = -1;
+ else {
+ any = 1;
+ acc *= base;
+ acc += c;
+ }
+ }
+ if (any < 0) {
+ acc = neg ? INTMAX_MIN : INTMAX_MAX;
+ errno = ERANGE;
+ } else if (!any) {
+noconv:
+ errno = EINVAL;
+ } else if (neg)
+ acc = -acc;
+ if (endptr != NULL)
+ *endptr = (wchar_t *)(any ? s - 1 : nptr);
+ return (acc);
+}
+intmax_t
+wcstoimax(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
+ int base)
+{
+ return wcstoimax_l(nptr, endptr, base, __get_locale());
+}
diff --git a/lib/libc/locale/wcstol.3 b/lib/libc/locale/wcstol.3
new file mode 100644
index 000000000000..e69a72672d54
--- /dev/null
+++ b/lib/libc/locale/wcstol.3
@@ -0,0 +1,94 @@
+.\" Copyright (c) 2002 Tim J. Robbins
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd September 7, 2002
+.Dt WCSTOL 3
+.Os
+.Sh NAME
+.Nm wcstol , wcstoul ,
+.Nm wcstoll , wcstoull ,
+.Nm wcstoimax , wcstoumax
+.Nd "convert a wide character string value to a"
+.Vt long ,
+.Vt "unsigned long" ,
+.Vt "long long" ,
+.Vt "unsigned long long" ,
+.Vt intmax_t
+or
+.Vt uintmax_t
+integer
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In wchar.h
+.Ft long
+.Fn wcstol "const wchar_t * restrict nptr" "wchar_t ** restrict endptr" "int base"
+.Ft "unsigned long"
+.Fn wcstoul "const wchar_t * restrict nptr" "wchar_t ** restrict endptr" "int base"
+.Ft "long long"
+.Fn wcstoll "const wchar_t * restrict nptr" "wchar_t ** restrict endptr" "int base"
+.Ft "unsigned long long"
+.Fn wcstoull "const wchar_t * restrict nptr" "wchar_t ** restrict endptr" "int base"
+.In inttypes.h
+.Ft intmax_t
+.Fn wcstoimax "const wchar_t * restrict nptr" "wchar_t ** restrict endptr" "int base"
+.Ft uintmax_t
+.Fn wcstoumax "const wchar_t * restrict nptr" "wchar_t ** restrict endptr" "int base"
+.Sh DESCRIPTION
+The
+.Fn wcstol ,
+.Fn wcstoul ,
+.Fn wcstoll ,
+.Fn wcstoull ,
+.Fn wcstoimax
+and
+.Fn wcstoumax
+functions are wide-character versions of the
+.Fn strtol ,
+.Fn strtoul ,
+.Fn strtoll ,
+.Fn strtoull ,
+.Fn strtoimax
+and
+.Fn strtoumax
+functions, respectively.
+Refer to their manual pages (for example
+.Xr strtol 3 )
+for details.
+.Sh SEE ALSO
+.Xr strtol 3 ,
+.Xr strtoul 3
+.Sh STANDARDS
+The
+.Fn wcstol ,
+.Fn wcstoul ,
+.Fn wcstoll ,
+.Fn wcstoull ,
+.Fn wcstoimax
+and
+.Fn wcstoumax
+functions conform to
+.St -isoC-99 .
diff --git a/lib/libc/locale/wcstol.c b/lib/libc/locale/wcstol.c
new file mode 100644
index 000000000000..2b21d126c700
--- /dev/null
+++ b/lib/libc/locale/wcstol.c
@@ -0,0 +1,130 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <wchar.h>
+#include <wctype.h>
+#include "xlocale_private.h"
+
+/*
+ * Convert a string to a long integer.
+ */
+long
+wcstol_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int
+ base, locale_t locale)
+{
+ const wchar_t *s;
+ unsigned long acc;
+ wchar_t c;
+ unsigned long cutoff;
+ int neg, any, cutlim;
+ FIX_LOCALE(locale);
+
+ /*
+ * See strtol for comments as to the logic used.
+ */
+ s = nptr;
+ do {
+ c = *s++;
+ } while (iswspace_l(c, locale));
+ if (c == '-') {
+ neg = 1;
+ c = *s++;
+ } else {
+ neg = 0;
+ if (c == L'+')
+ c = *s++;
+ }
+ if ((base == 0 || base == 16) &&
+ c == L'0' && (*s == L'x' || *s == L'X')) {
+ c = s[1];
+ s += 2;
+ base = 16;
+ }
+ if (base == 0)
+ base = c == L'0' ? 8 : 10;
+ acc = any = 0;
+ if (base < 2 || base > 36)
+ goto noconv;
+
+ cutoff = neg ? (unsigned long)-(LONG_MIN + LONG_MAX) + LONG_MAX
+ : LONG_MAX;
+ cutlim = cutoff % base;
+ cutoff /= base;
+ for ( ; ; c = *s++) {
+#ifdef notyet
+ if (iswdigit_l(c, locale))
+ c = digittoint_l(c, locale);
+ else
+#endif
+ if (c >= L'0' && c <= L'9')
+ c -= L'0';
+ else if (c >= L'A' && c <= L'Z')
+ c -= L'A' - 10;
+ else if (c >= L'a' && c <= L'z')
+ c -= L'a' - 10;
+ else
+ break;
+ if (c >= base)
+ break;
+ if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
+ any = -1;
+ else {
+ any = 1;
+ acc *= base;
+ acc += c;
+ }
+ }
+ if (any < 0) {
+ acc = neg ? LONG_MIN : LONG_MAX;
+ errno = ERANGE;
+ } else if (!any) {
+noconv:
+ errno = EINVAL;
+ } else if (neg)
+ acc = -acc;
+ if (endptr != NULL)
+ *endptr = (wchar_t *)(any ? s - 1 : nptr);
+ return (acc);
+}
+long
+wcstol(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int base)
+{
+ return wcstol_l(nptr, endptr, base, __get_locale());
+}
diff --git a/lib/libc/locale/wcstold.c b/lib/libc/locale/wcstold.c
new file mode 100644
index 000000000000..89c92d95d4f3
--- /dev/null
+++ b/lib/libc/locale/wcstold.c
@@ -0,0 +1,93 @@
+/*-
+ * Copyright (c) 2002, 2003 Tim J. Robbins
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 <stdlib.h>
+#include <wchar.h>
+#include <wctype.h>
+#include "xlocale_private.h"
+
+/*
+ * See wcstod() for comments as to the logic used.
+ */
+long double
+wcstold_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
+ locale_t locale)
+{
+ static const mbstate_t initial;
+ mbstate_t mbs;
+ long double val;
+ char *buf, *end;
+ const wchar_t *wcp;
+ size_t len;
+ size_t spaces;
+ FIX_LOCALE(locale);
+
+ wcp = nptr;
+ spaces = 0;
+ while (iswspace_l(*wcp, locale)) {
+ wcp++;
+ spaces++;
+ }
+
+ mbs = initial;
+ if ((len = wcsrtombs_l(NULL, &wcp, 0, &mbs, locale)) == (size_t)-1) {
+ if (endptr != NULL)
+ *endptr = (wchar_t *)nptr;
+ return (0.0);
+ }
+ if ((buf = malloc(len + 1)) == NULL) {
+ if (endptr != NULL)
+ *endptr = (wchar_t *)nptr;
+ return (0.0);
+ }
+ mbs = initial;
+ wcsrtombs_l(buf, &wcp, len + 1, &mbs, locale);
+
+ val = strtold_l(buf, &end, locale);
+
+ if (endptr != NULL) {
+ *endptr = (wchar_t *)nptr + (end - buf);
+ if (buf != end)
+ *endptr += spaces;
+ }
+
+ free(buf);
+
+ return (val);
+}
+long double
+wcstold(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr)
+{
+ return wcstold_l(nptr, endptr, __get_locale());
+}
diff --git a/lib/libc/locale/wcstoll.c b/lib/libc/locale/wcstoll.c
new file mode 100644
index 000000000000..f246502bb2fa
--- /dev/null
+++ b/lib/libc/locale/wcstoll.c
@@ -0,0 +1,136 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#if 0
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strtoq.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+__FBSDID("FreeBSD: src/lib/libc/stdlib/strtoll.c,v 1.19 2002/09/06 11:23:59 tjr Exp ");
+#endif
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include <wctype.h>
+#include "xlocale_private.h"
+
+/*
+ * Convert a wide character string to a long long integer.
+ */
+long long
+wcstoll_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
+ int base, locale_t locale)
+{
+ const wchar_t *s;
+ unsigned long long acc;
+ wchar_t c;
+ unsigned long long cutoff;
+ int neg, any, cutlim;
+ FIX_LOCALE(locale);
+
+ /*
+ * See strtoll for comments as to the logic used.
+ */
+ s = nptr;
+ do {
+ c = *s++;
+ } while (iswspace_l(c, locale));
+ if (c == L'-') {
+ neg = 1;
+ c = *s++;
+ } else {
+ neg = 0;
+ if (c == L'+')
+ c = *s++;
+ }
+ if ((base == 0 || base == 16) &&
+ c == L'0' && (*s == L'x' || *s == L'X')) {
+ c = s[1];
+ s += 2;
+ base = 16;
+ }
+ if (base == 0)
+ base = c == L'0' ? 8 : 10;
+ acc = any = 0;
+ if (base < 2 || base > 36)
+ goto noconv;
+
+ cutoff = neg ? (unsigned long long)-(LLONG_MIN + LLONG_MAX) + LLONG_MAX
+ : LLONG_MAX;
+ cutlim = cutoff % base;
+ cutoff /= base;
+ for ( ; ; c = *s++) {
+#ifdef notyet
+ if (iswdigit_l(c, locale))
+ c = digittoint_l(c, locale);
+ else
+#endif
+ if (c >= L'0' && c <= L'9')
+ c -= L'0';
+ else if (c >= L'A' && c <= L'Z')
+ c -= L'A' - 10;
+ else if (c >= L'a' && c <= L'z')
+ c -= L'a' - 10;
+ else
+ break;
+ if (c >= base)
+ break;
+ if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
+ any = -1;
+ else {
+ any = 1;
+ acc *= base;
+ acc += c;
+ }
+ }
+ if (any < 0) {
+ acc = neg ? LLONG_MIN : LLONG_MAX;
+ errno = ERANGE;
+ } else if (!any) {
+noconv:
+ errno = EINVAL;
+ } else if (neg)
+ acc = -acc;
+ if (endptr != NULL)
+ *endptr = (wchar_t *)(any ? s - 1 : nptr);
+ return (acc);
+}
+long long
+wcstoll(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int base)
+{
+ return wcstoll_l(nptr, endptr, base, __get_locale());
+}
diff --git a/lib/libc/locale/wcstombs.3 b/lib/libc/locale/wcstombs.3
new file mode 100644
index 000000000000..723ae801b99a
--- /dev/null
+++ b/lib/libc/locale/wcstombs.3
@@ -0,0 +1,90 @@
+.\" Copyright (c) 2002-2004 Tim J. Robbins. All rights reserved.
+.\" Copyright (c) 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Donn Seeley of BSDI.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" From @(#)multibyte.3 8.1 (Berkeley) 6/4/93
+.\" From FreeBSD: src/lib/libc/locale/multibyte.3,v 1.22 2003/11/08 03:23:11 tjr Exp
+.\" $FreeBSD$
+.\"
+.Dd April 8, 2004
+.Dt WCSTOMBS 3
+.Os
+.Sh NAME
+.Nm wcstombs
+.Nd convert a wide-character string to a character string
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft size_t
+.Fo wcstombs
+.Fa "char * restrict mbstring" "const wchar_t * restrict wcstring"
+.Fa "size_t nbytes"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn wcstombs
+function converts a wide character string
+.Fa wcstring
+into a multibyte character string,
+.Fa mbstring ,
+beginning in the initial conversion state.
+Up to
+.Fa nbytes
+bytes are stored in
+.Fa mbstring .
+Partial multibyte characters at the end of the string are not stored.
+The multibyte character string is null terminated if there is room.
+.Sh RETURN VALUES
+The
+.Fn wcstombs
+function returns the number of bytes converted
+(not including any terminating null), if successful, otherwise it returns
+.Po Vt size_t Pc Ns \-1 .
+.Sh ERRORS
+The
+.Fn wcstombs
+function will fail if:
+.Bl -tag -width Er
+.It Bq Er EILSEQ
+An invalid wide character was encountered.
+.It Bq Er EINVAL
+The conversion state is invalid.
+.El
+.Sh SEE ALSO
+.Xr mbstowcs 3 ,
+.Xr multibyte 3 ,
+.Xr wcsrtombs 3 ,
+.Xr wctomb 3
+.Sh STANDARDS
+The
+.Fn wcstombs
+function conforms to
+.St -isoC-99 .
diff --git a/lib/libc/locale/wcstombs.c b/lib/libc/locale/wcstombs.c
new file mode 100644
index 000000000000..8d4ae1c0b4e1
--- /dev/null
+++ b/lib/libc/locale/wcstombs.c
@@ -0,0 +1,58 @@
+/*-
+ * Copyright (c) 2002-2004 Tim J. Robbins.
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 <limits.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include "mblocal.h"
+
+size_t
+wcstombs_l(char * __restrict s, const wchar_t * __restrict pwcs, size_t n,
+ locale_t locale)
+{
+ static const mbstate_t initial;
+ mbstate_t mbs;
+ const wchar_t *pwcsp;
+ FIX_LOCALE(locale);
+
+ mbs = initial;
+ pwcsp = pwcs;
+ return (XLOCALE_CTYPE(locale)->__wcsnrtombs(s, &pwcsp, SIZE_T_MAX, n, &mbs));
+}
+size_t
+wcstombs(char * __restrict s, const wchar_t * __restrict pwcs, size_t n)
+{
+ return wcstombs_l(s, pwcs, n, __get_locale());
+}
+
diff --git a/lib/libc/locale/wcstoul.c b/lib/libc/locale/wcstoul.c
new file mode 100644
index 000000000000..54e6b4fb9111
--- /dev/null
+++ b/lib/libc/locale/wcstoul.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <wchar.h>
+#include <wctype.h>
+#include "xlocale_private.h"
+
+/*
+ * Convert a wide character string to an unsigned long integer.
+ */
+unsigned long
+wcstoul_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
+ int base, locale_t locale)
+{
+ const wchar_t *s;
+ unsigned long acc;
+ wchar_t c;
+ unsigned long cutoff;
+ int neg, any, cutlim;
+ FIX_LOCALE(locale);
+
+ /*
+ * See strtol for comments as to the logic used.
+ */
+ s = nptr;
+ do {
+ c = *s++;
+ } while (iswspace_l(c, locale));
+ if (c == L'-') {
+ neg = 1;
+ c = *s++;
+ } else {
+ neg = 0;
+ if (c == L'+')
+ c = *s++;
+ }
+ if ((base == 0 || base == 16) &&
+ c == L'0' && (*s == L'x' || *s == L'X')) {
+ c = s[1];
+ s += 2;
+ base = 16;
+ }
+ if (base == 0)
+ base = c == L'0' ? 8 : 10;
+ acc = any = 0;
+ if (base < 2 || base > 36)
+ goto noconv;
+
+ cutoff = ULONG_MAX / base;
+ cutlim = ULONG_MAX % base;
+ for ( ; ; c = *s++) {
+#ifdef notyet
+ if (iswdigit_l(c, locale))
+ c = digittoint_l(c, locale);
+ else
+#endif
+ if (c >= L'0' && c <= L'9')
+ c -= L'0';
+ else if (c >= L'A' && c <= L'Z')
+ c -= L'A' - 10;
+ else if (c >= L'a' && c <= L'z')
+ c -= L'a' - 10;
+ else
+ break;
+ if (c >= base)
+ break;
+ if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
+ any = -1;
+ else {
+ any = 1;
+ acc *= base;
+ acc += c;
+ }
+ }
+ if (any < 0) {
+ acc = ULONG_MAX;
+ errno = ERANGE;
+ } else if (!any) {
+noconv:
+ errno = EINVAL;
+ } else if (neg)
+ acc = -acc;
+ if (endptr != NULL)
+ *endptr = (wchar_t *)(any ? s - 1 : nptr);
+ return (acc);
+}
+unsigned long
+wcstoul(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int base)
+{
+ return wcstoul_l(nptr, endptr, base, __get_locale());
+}
diff --git a/lib/libc/locale/wcstoull.c b/lib/libc/locale/wcstoull.c
new file mode 100644
index 000000000000..c56ee770f032
--- /dev/null
+++ b/lib/libc/locale/wcstoull.c
@@ -0,0 +1,135 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#if 0
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strtouq.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+__FBSDID("FreeBSD: src/lib/libc/stdlib/strtoull.c,v 1.18 2002/09/06 11:23:59 tjr Exp ");
+#endif
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include <wctype.h>
+#include "xlocale_private.h"
+
+/*
+ * Convert a wide character string to an unsigned long long integer.
+ */
+unsigned long long
+wcstoull_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
+ int base, locale_t locale)
+{
+ const wchar_t *s;
+ unsigned long long acc;
+ wchar_t c;
+ unsigned long long cutoff;
+ int neg, any, cutlim;
+ FIX_LOCALE(locale);
+
+ /*
+ * See strtoull for comments as to the logic used.
+ */
+ s = nptr;
+ do {
+ c = *s++;
+ } while (iswspace_l(c, locale));
+ if (c == L'-') {
+ neg = 1;
+ c = *s++;
+ } else {
+ neg = 0;
+ if (c == L'+')
+ c = *s++;
+ }
+ if ((base == 0 || base == 16) &&
+ c == L'0' && (*s == L'x' || *s == L'X')) {
+ c = s[1];
+ s += 2;
+ base = 16;
+ }
+ if (base == 0)
+ base = c == L'0' ? 8 : 10;
+ acc = any = 0;
+ if (base < 2 || base > 36)
+ goto noconv;
+
+ cutoff = ULLONG_MAX / base;
+ cutlim = ULLONG_MAX % base;
+ for ( ; ; c = *s++) {
+#ifdef notyet
+ if (iswdigit_l(c, locale))
+ c = digittoint_l(c, locale);
+ else
+#endif
+ if (c >= L'0' && c <= L'9')
+ c -= L'0';
+ else if (c >= L'A' && c <= L'Z')
+ c -= L'A' - 10;
+ else if (c >= L'a' && c <= L'z')
+ c -= L'a' - 10;
+ else
+ break;
+ if (c >= base)
+ break;
+ if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
+ any = -1;
+ else {
+ any = 1;
+ acc *= base;
+ acc += c;
+ }
+ }
+ if (any < 0) {
+ acc = ULLONG_MAX;
+ errno = ERANGE;
+ } else if (!any) {
+noconv:
+ errno = EINVAL;
+ } else if (neg)
+ acc = -acc;
+ if (endptr != NULL)
+ *endptr = (wchar_t *)(any ? s - 1 : nptr);
+ return (acc);
+}
+unsigned long long
+wcstoull(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
+ int base)
+{
+ return wcstoull_l(nptr, endptr, base, __get_locale());
+}
diff --git a/lib/libc/locale/wcstoumax.c b/lib/libc/locale/wcstoumax.c
new file mode 100644
index 000000000000..397c1e37410f
--- /dev/null
+++ b/lib/libc/locale/wcstoumax.c
@@ -0,0 +1,135 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#if 0
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "from @(#)strtoul.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+__FBSDID("FreeBSD: src/lib/libc/stdlib/strtoumax.c,v 1.8 2002/09/06 11:23:59 tjr Exp ");
+#endif
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include <wctype.h>
+#include "xlocale_private.h"
+
+/*
+ * Convert a wide character string to a uintmax_t integer.
+ */
+uintmax_t
+wcstoumax_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
+ int base, locale_t locale)
+{
+ const wchar_t *s;
+ uintmax_t acc;
+ wchar_t c;
+ uintmax_t cutoff;
+ int neg, any, cutlim;
+ FIX_LOCALE(locale);
+
+ /*
+ * See strtoimax for comments as to the logic used.
+ */
+ s = nptr;
+ do {
+ c = *s++;
+ } while (iswspace_l(c, locale));
+ if (c == L'-') {
+ neg = 1;
+ c = *s++;
+ } else {
+ neg = 0;
+ if (c == L'+')
+ c = *s++;
+ }
+ if ((base == 0 || base == 16) &&
+ c == L'0' && (*s == L'x' || *s == L'X')) {
+ c = s[1];
+ s += 2;
+ base = 16;
+ }
+ if (base == 0)
+ base = c == L'0' ? 8 : 10;
+ acc = any = 0;
+ if (base < 2 || base > 36)
+ goto noconv;
+
+ cutoff = UINTMAX_MAX / base;
+ cutlim = UINTMAX_MAX % base;
+ for ( ; ; c = *s++) {
+#ifdef notyet
+ if (iswdigit_l(c, locale))
+ c = digittoint_l(c, locale);
+ else
+#endif
+ if (c >= L'0' && c <= L'9')
+ c -= L'0';
+ else if (c >= L'A' && c <= L'Z')
+ c -= L'A' - 10;
+ else if (c >= L'a' && c <= L'z')
+ c -= L'a' - 10;
+ else
+ break;
+ if (c >= base)
+ break;
+ if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
+ any = -1;
+ else {
+ any = 1;
+ acc *= base;
+ acc += c;
+ }
+ }
+ if (any < 0) {
+ acc = UINTMAX_MAX;
+ errno = ERANGE;
+ } else if (!any) {
+noconv:
+ errno = EINVAL;
+ } else if (neg)
+ acc = -acc;
+ if (endptr != NULL)
+ *endptr = (wchar_t *)(any ? s - 1 : nptr);
+ return (acc);
+}
+uintmax_t
+wcstoumax(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
+ int base)
+{
+ return wcstoumax_l(nptr, endptr, base, __get_locale());
+}
diff --git a/lib/libc/locale/wctob.c b/lib/libc/locale/wctob.c
new file mode 100644
index 000000000000..96e8b730a903
--- /dev/null
+++ b/lib/libc/locale/wctob.c
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 2002-2004 Tim J. Robbins.
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 <limits.h>
+#include <stdio.h>
+#include <wchar.h>
+#include "mblocal.h"
+
+int
+wctob_l(wint_t c, locale_t locale)
+{
+ static const mbstate_t initial;
+ mbstate_t mbs = initial;
+ char buf[MB_LEN_MAX];
+ FIX_LOCALE(locale);
+
+ if (c == WEOF || XLOCALE_CTYPE(locale)->__wcrtomb(buf, c, &mbs) != 1)
+ return (EOF);
+ return ((unsigned char)*buf);
+}
+int
+wctob(wint_t c)
+{
+ return wctob_l(c, __get_locale());
+}
diff --git a/lib/libc/locale/wctomb.3 b/lib/libc/locale/wctomb.3
new file mode 100644
index 000000000000..fe08d837b49d
--- /dev/null
+++ b/lib/libc/locale/wctomb.3
@@ -0,0 +1,108 @@
+.\" Copyright (c) 2002-2004 Tim J. Robbins. All rights reserved.
+.\" Copyright (c) 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Donn Seeley of BSDI.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" From @(#)multibyte.3 8.1 (Berkeley) 6/4/93
+.\" From FreeBSD: src/lib/libc/locale/multibyte.3,v 1.22 2003/11/08 03:23:11 tjr Exp
+.\" $FreeBSD$
+.\"
+.Dd April 8, 2004
+.Dt WCTOMB 3
+.Os
+.Sh NAME
+.Nm wctomb
+.Nd convert a wide-character code to a character
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft int
+.Fn wctomb "char *mbchar" "wchar_t wchar"
+.Sh DESCRIPTION
+The
+.Fn wctomb
+function converts a wide character
+.Fa wchar
+into a multibyte character and stores
+the result in
+.Fa mbchar .
+The object pointed to by
+.Fa mbchar
+must be large enough to accommodate the multibyte character, which
+may be up to
+.Dv MB_LEN_MAX
+bytes.
+.Pp
+A call with a null
+.Fa mbchar
+pointer returns nonzero if the current locale requires shift states,
+zero otherwise;
+if shift states are required, the shift state is reset to the initial state.
+.Sh RETURN VALUES
+If
+.Fa mbchar
+is
+.Dv NULL ,
+the
+.Fn wctomb
+function returns nonzero if shift states are supported,
+zero otherwise.
+If
+.Fa mbchar
+is valid,
+.Fn wctomb
+returns
+the number of bytes processed in
+.Fa mbchar ,
+or \-1 if no multibyte character
+could be recognized or converted.
+In this case,
+.Fn wctomb Ns 's
+internal conversion state is undefined.
+.Sh ERRORS
+The
+.Fn wctomb
+function will fail if:
+.Bl -tag -width Er
+.It Bq Er EILSEQ
+An invalid multibyte sequence was detected.
+.It Bq Er EINVAL
+The internal conversion state is invalid.
+.El
+.Sh SEE ALSO
+.Xr mbtowc 3 ,
+.Xr wcrtomb 3 ,
+.Xr wcstombs 3 ,
+.Xr wctob 3
+.Sh STANDARDS
+The
+.Fn wctomb
+function conforms to
+.St -isoC-99 .
diff --git a/lib/libc/locale/wctomb.c b/lib/libc/locale/wctomb.c
new file mode 100644
index 000000000000..da3d2635a967
--- /dev/null
+++ b/lib/libc/locale/wctomb.c
@@ -0,0 +1,59 @@
+/*-
+ * Copyright (c) 2002-2004 Tim J. Robbins.
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 <stdlib.h>
+#include <wchar.h>
+#include "mblocal.h"
+
+int
+wctomb_l(char *s, wchar_t wchar, locale_t locale)
+{
+ static const mbstate_t initial;
+ size_t rval;
+ FIX_LOCALE(locale);
+
+ if (s == NULL) {
+ /* No support for state dependent encodings. */
+ locale->wctomb = initial;
+ return (0);
+ }
+ if ((rval = XLOCALE_CTYPE(locale)->__wcrtomb(s, wchar, &locale->wctomb)) == (size_t)-1)
+ return (-1);
+ return ((int)rval);
+}
+int
+wctomb(char *s, wchar_t wchar)
+{
+ return wctomb_l(s, wchar, __get_locale());
+}
diff --git a/lib/libc/locale/wctrans.3 b/lib/libc/locale/wctrans.3
new file mode 100644
index 000000000000..ce3e68c9eb34
--- /dev/null
+++ b/lib/libc/locale/wctrans.3
@@ -0,0 +1,122 @@
+.\" Copyright (c) 2002 Tim J. Robbins
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd October 3, 2002
+.Dt WCTRANS 3
+.Os
+.Sh NAME
+.Nm towctrans , wctrans
+.Nd "wide character mapping functions"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In wctype.h
+.Ft wint_t
+.Fn towctrans "wint_t wc" "wctrans_t desc"
+.Ft wctrans_t
+.Fn wctrans "const char *charclass"
+.Sh DESCRIPTION
+The
+.Fn wctrans
+function returns a value of type
+.Vt wctrans_t
+which represents the requested wide character mapping operation and
+may be used as the second argument for calls to
+.Fn towctrans .
+.Pp
+The following character mapping names are recognised:
+.Bl -column -offset indent ".Li tolower" ".Li toupper"
+.It Li "tolower toupper"
+.El
+.Pp
+The
+.Fn towctrans
+function transliterates the wide character
+.Fa wc
+according to the mapping described by
+.Fa desc .
+.Sh RETURN VALUES
+The
+.Fn towctrans
+function returns the transliterated character if successful, otherwise
+it returns the character unchanged and sets
+.Va errno .
+.Pp
+The
+.Fn wctrans
+function returns non-zero if successful, otherwise it returns zero
+and sets
+.Va errno .
+.Sh EXAMPLES
+Reimplement
+.Fn towupper
+in terms of
+.Fn towctrans
+and
+.Fn wctrans :
+.Bd -literal -offset indent
+wint_t
+mytowupper(wint_t wc)
+{
+ return (towctrans(wc, wctrans("toupper")));
+}
+.Ed
+.Sh ERRORS
+The
+.Fn towctrans
+function will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The supplied
+.Fa desc
+argument is invalid.
+.El
+.Pp
+The
+.Fn wctrans
+function will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The requested mapping name is invalid.
+.El
+.Sh SEE ALSO
+.Xr tolower 3 ,
+.Xr toupper 3 ,
+.Xr wctype 3
+.Sh STANDARDS
+The
+.Fn towctrans
+and
+.Fn wctrans
+functions conform to
+.St -p1003.1-2001 .
+.Sh HISTORY
+The
+.Fn towctrans
+and
+.Fn wctrans
+functions first appeared in
+.Fx 5.0 .
diff --git a/lib/libc/locale/wctrans.c b/lib/libc/locale/wctrans.c
new file mode 100644
index 000000000000..0831146b0103
--- /dev/null
+++ b/lib/libc/locale/wctrans.c
@@ -0,0 +1,101 @@
+/*-
+ * Copyright (c) 2002 Tim J. Robbins.
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 <errno.h>
+#include <string.h>
+#include <wctype.h>
+#include "xlocale_private.h"
+
+enum {
+ _WCT_ERROR = 0,
+ _WCT_TOLOWER = 1,
+ _WCT_TOUPPER = 2
+};
+
+wint_t
+towctrans_l(wint_t wc, wctrans_t desc, locale_t locale)
+{
+ switch (desc) {
+ case _WCT_TOLOWER:
+ wc = towlower_l(wc, locale);
+ break;
+ case _WCT_TOUPPER:
+ wc = towupper_l(wc, locale);
+ break;
+ case _WCT_ERROR:
+ default:
+ errno = EINVAL;
+ break;
+ }
+
+ return (wc);
+}
+wint_t
+towctrans(wint_t wc, wctrans_t desc)
+{
+ return towctrans_l(wc, desc, __get_locale());
+}
+
+/*
+ * wctrans() calls this will a 0 locale. If this is ever modified to actually
+ * use the locale, wctrans() must be modified to call __get_locale().
+ */
+wctrans_t
+wctrans_l(const char *charclass, locale_t locale)
+{
+ struct {
+ const char *name;
+ wctrans_t trans;
+ } ccls[] = {
+ { "tolower", _WCT_TOLOWER },
+ { "toupper", _WCT_TOUPPER },
+ { NULL, _WCT_ERROR }, /* Default */
+ };
+ int i;
+
+ i = 0;
+ while (ccls[i].name != NULL && strcmp(ccls[i].name, charclass) != 0)
+ i++;
+
+ if (ccls[i].trans == _WCT_ERROR)
+ errno = EINVAL;
+ return (ccls[i].trans);
+}
+
+wctrans_t
+wctrans(const char *charclass)
+{
+ return wctrans_l(charclass, 0);
+}
+
diff --git a/lib/libc/locale/wctype.3 b/lib/libc/locale/wctype.3
new file mode 100644
index 000000000000..099631d51790
--- /dev/null
+++ b/lib/libc/locale/wctype.3
@@ -0,0 +1,119 @@
+.\" Copyright (c) 2002 Tim J. Robbins
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd March 27, 2004
+.Dt WCTYPE 3
+.Os
+.Sh NAME
+.Nm iswctype , wctype
+.Nd "wide character class functions"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In wctype.h
+.Ft int
+.Fn iswctype "wint_t wc" "wctype_t charclass"
+.Ft wctype_t
+.Fn wctype "const char *property"
+.Sh DESCRIPTION
+The
+.Fn wctype
+function returns a value of type
+.Vt wctype_t
+which represents the requested wide character class and
+may be used as the second argument for calls to
+.Fn iswctype .
+.Pp
+The following character class names are recognised:
+.Bl -column -offset indent ".Li alnum" ".Li cntrl" ".Li ideogram" ".Li print" ".Li space"
+.It Li "alnum cntrl ideogram print space xdigit"
+.It Li "alpha digit lower punct special"
+.It Li "blank graph phonogram rune upper"
+.El
+.Pp
+The
+.Fn iswctype
+function checks whether the wide character
+.Fa wc
+is in the character class
+.Fa charclass .
+.Sh RETURN VALUES
+The
+.Fn iswctype
+function returns non-zero if and only if
+.Fa wc
+has the property described by
+.Fa charclass ,
+or
+.Fa charclass
+is zero.
+.Pp
+The
+.Fn wctype
+function returns 0 if
+.Fa property
+is invalid, otherwise it returns a value of type
+.Vt wctype_t
+that can be used in subsequent calls to
+.Fn iswctype .
+.Sh EXAMPLES
+Reimplement
+.Xr iswalpha 3
+in terms of
+.Fn iswctype
+and
+.Fn wctype :
+.Bd -literal -offset indent
+int
+myiswalpha(wint_t wc)
+{
+ return (iswctype(wc, wctype("alpha")));
+}
+.Ed
+.Sh SEE ALSO
+.Xr ctype 3 ,
+.Xr nextwctype 3
+.Sh STANDARDS
+The
+.Fn iswctype
+and
+.Fn wctype
+functions conform to
+.St -p1003.1-2001 .
+The
+.Dq Li ideogram ,
+.Dq Li phonogram ,
+.Dq Li special ,
+and
+.Dq Li rune
+character classes are extensions.
+.Sh HISTORY
+The
+.Fn iswctype
+and
+.Fn wctype
+functions first appeared in
+.Fx 5.0 .
diff --git a/lib/libc/locale/wctype.c b/lib/libc/locale/wctype.c
new file mode 100644
index 000000000000..e20712175154
--- /dev/null
+++ b/lib/libc/locale/wctype.c
@@ -0,0 +1,115 @@
+/*-
+ * Copyright (c) 2002 Tim J. Robbins.
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 <ctype.h>
+#include <string.h>
+#include <wctype.h>
+#include <xlocale.h>
+
+#undef iswctype
+int
+iswctype(wint_t wc, wctype_t charclass)
+{
+ return (__istype(wc, charclass));
+}
+int
+iswctype_l(wint_t wc, wctype_t charclass, locale_t locale)
+{
+ return __istype_l(wc, charclass, locale);
+}
+
+/*
+ * IMPORTANT: The 0 in the call to this function in wctype() must be changed to
+ * __get_locale() if wctype_l() is ever modified to actually use the locale
+ * parameter.
+ */
+wctype_t
+wctype_l(const char *property, locale_t locale)
+{
+ const char *propnames =
+ "alnum\0"
+ "alpha\0"
+ "blank\0"
+ "cntrl\0"
+ "digit\0"
+ "graph\0"
+ "lower\0"
+ "print\0"
+ "punct\0"
+ "space\0"
+ "upper\0"
+ "xdigit\0"
+ "ideogram\0" /* BSD extension */
+ "special\0" /* BSD extension */
+ "phonogram\0" /* BSD extension */
+ "number\0" /* BSD extension */
+ "rune\0"; /* BSD extension */
+ static const wctype_t propmasks[] = {
+ _CTYPE_A|_CTYPE_N,
+ _CTYPE_A,
+ _CTYPE_B,
+ _CTYPE_C,
+ _CTYPE_D,
+ _CTYPE_G,
+ _CTYPE_L,
+ _CTYPE_R,
+ _CTYPE_P,
+ _CTYPE_S,
+ _CTYPE_U,
+ _CTYPE_X,
+ _CTYPE_I,
+ _CTYPE_T,
+ _CTYPE_Q,
+ _CTYPE_N,
+ 0xFFFFFF00L
+ };
+ size_t len1, len2;
+ const char *p;
+ const wctype_t *q;
+
+ len1 = strlen(property);
+ q = propmasks;
+ for (p = propnames; (len2 = strlen(p)) != 0; p += len2 + 1) {
+ if (len1 == len2 && memcmp(property, p, len1) == 0)
+ return (*q);
+ q++;
+ }
+
+ return (0UL);
+}
+
+wctype_t wctype(const char *property)
+{
+ return wctype_l(property, 0);
+}
diff --git a/lib/libc/locale/wcwidth.3 b/lib/libc/locale/wcwidth.3
new file mode 100644
index 000000000000..0c7c74fed155
--- /dev/null
+++ b/lib/libc/locale/wcwidth.3
@@ -0,0 +1,87 @@
+.\" Copyright (c) 2002 Tim J. Robbins
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd August 17, 2004
+.Dt WCWIDTH 3
+.Os
+.Sh NAME
+.Nm wcwidth
+.Nd "number of column positions of a wide-character code"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In wchar.h
+.Ft int
+.Fn wcwidth "wchar_t wc"
+.Sh DESCRIPTION
+The
+.Fn wcwidth
+function determines the number of column positions required to
+display the wide character
+.Fa wc .
+.Sh RETURN VALUES
+The
+.Fn wcwidth
+function returns 0 if the
+.Fa wc
+argument is a null wide character (L'\e0'),
+\-1 if
+.Fa wc
+is not printable,
+otherwise it returns the number of column positions the
+character occupies.
+.Sh EXAMPLES
+This code fragment reads text from standard input and
+breaks lines that are more than 20 column positions wide,
+similar to the
+.Xr fold 1
+utility:
+.Bd -literal -offset indent
+wint_t ch;
+int column, w;
+
+column = 0;
+while ((ch = getwchar()) != WEOF) {
+ w = wcwidth(ch);
+ if (w > 0 && column + w >= 20) {
+ putwchar(L'\en');
+ column = 0;
+ }
+ putwchar(ch);
+ if (ch == L'\en')
+ column = 0;
+ else if (w > 0)
+ column += w;
+}
+.Ed
+.Sh SEE ALSO
+.Xr iswprint 3 ,
+.Xr wcswidth 3
+.Sh STANDARDS
+The
+.Fn wcwidth
+function conforms to
+.St -p1003.1-2001 .
diff --git a/lib/libc/locale/wcwidth.c b/lib/libc/locale/wcwidth.c
new file mode 100644
index 000000000000..9e74217f6d8e
--- /dev/null
+++ b/lib/libc/locale/wcwidth.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Borman at Krystal Technologies.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <wchar.h>
+#include <wctype.h>
+#include <xlocale.h>
+
+#undef wcwidth
+
+int
+wcwidth(wchar_t wc)
+{
+ return (__wcwidth(wc));
+}
+int
+wcwidth_l(wchar_t wc, locale_t locale)
+{
+ return (__wcwidth_l(wc, locale));
+}
diff --git a/lib/libc/locale/xlocale.3 b/lib/libc/locale/xlocale.3
new file mode 100644
index 000000000000..da217c601100
--- /dev/null
+++ b/lib/libc/locale/xlocale.3
@@ -0,0 +1,280 @@
+.\" Copyright (c) 2011 The FreeBSD Foundation
+.\" All rights reserved.
+.\"
+.\" This documentation was written by David Chisnall under sponsorship from
+.\" the FreeBSD Foundation.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 September 17, 2011
+.Dt XLOCALE 3
+.Os
+.Sh NAME
+.Nm xlocale
+.Nd Thread-safe extended locale support
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In xlocale.h
+.Sh DESCRIPTION
+The extended locale support includes a set of functions for setting
+thread-local locales,
+as well convenience functions for performing locale-aware
+calls with a specified locale.
+.Pp
+The core of the xlocale API is the
+.Fa locale_t
+type.
+This is an opaque type encapsulating a locale.
+Instances of this can be either set as the locale for a specific thread or
+passed directly to the
+.Fa _l
+suffixed variants of various standard C functions.
+Two special
+.Fa locale_t
+values are available:
+.Bl -bullet -offset indent
+.It
+NULL refers to the current locale for the thread,
+or to the global locale if no locale has been set for this thread.
+.It
+LC_GLOBAL_LOCALE refers to the global locale.
+.El
+.Pp
+The global locale is the locale set with the
+.Xr setlocale 3
+function.
+.Sh SEE ALSO
+.Xr duplocale 3 ,
+.Xr freelocale 3 ,
+.Xr localeconv 3 ,
+.Xr newlocale 3 ,
+.Xr querylocale 3 ,
+.Xr uselocale 3
+.Sh CONVENIENCE FUNCTIONS
+The xlocale API includes a number of
+.Fa _l
+suffixed convenience functions.
+These are variants of standard C functions
+that have been modified to take an explicit
+.Fa locale_t
+parameter as the final argument or, in the case of variadic functions,
+as an additional argument directly before the format string.
+Each of these functions accepts either NULL or LC_GLOBAL_LOCALE.
+In these functions, NULL refers to the C locale,
+rather than the thread's current locale.
+If you wish to use the thread's current locale,
+then use the unsuffixed version of the function.
+.Pp
+These functions are exposed by including
+.In xlocale.h
+.Em after
+including the relevant headers for the standard variant.
+For example, the
+.Xr strtol_l 3
+function is exposed by including
+.In xlocale.h
+after
+.In stdlib.h ,
+which defines
+.Xr strtol 3 .
+.Pp
+For reference,
+a complete list of the locale-aware functions that are available in this form,
+along with the headers that expose them, is provided here:
+.Bl -tag -width "<monetary.h> "
+.It In wctype.h
+.Xr iswalnum_l 3 ,
+.Xr iswalpha_l 3 ,
+.Xr iswcntrl_l 3 ,
+.Xr iswctype_l 3 ,
+.Xr iswdigit_l 3 ,
+.Xr iswgraph_l 3 ,
+.Xr iswlower_l 3 ,
+.Xr iswprint_l 3 ,
+.Xr iswpunct_l 3 ,
+.Xr iswspace_l 3 ,
+.Xr iswupper_l 3 ,
+.Xr iswxdigit_l 3 ,
+.Xr towlower_l 3 ,
+.Xr towupper_l 3 ,
+.Xr wctype_l 3 ,
+.It In ctype.h
+.Xr digittoint_l 3 ,
+.Xr isalnum_l 3 ,
+.Xr isalpha_l 3 ,
+.Xr isblank_l 3 ,
+.Xr iscntrl_l 3 ,
+.Xr isdigit_l 3 ,
+.Xr isgraph_l 3 ,
+.Xr ishexnumber_l 3 ,
+.Xr isideogram_l 3 ,
+.Xr islower_l 3 ,
+.Xr isnumber_l 3 ,
+.Xr isphonogram_l 3 ,
+.Xr isprint_l 3 ,
+.Xr ispunct_l 3 ,
+.Xr isrune_l 3 ,
+.Xr isspace_l 3 ,
+.Xr isspecial_l 3 ,
+.Xr isupper_l 3 ,
+.Xr isxdigit_l 3 ,
+.Xr tolower_l 3 ,
+.Xr toupper_l 3
+.It In inttypes.h
+.Xr strtoimax_l 3 ,
+.Xr strtoumax_l 3 ,
+.Xr wcstoimax_l 3 ,
+.Xr wcstoumax_l 3
+.It In langinfo.h
+.Xr nl_langinfo_l 3
+.It In monetary.h
+.Xr strfmon_l 3
+.It In stdio.h
+.Xr asprintf_l 3 ,
+.Xr fprintf_l 3 ,
+.Xr fscanf_l 3 ,
+.Xr printf_l 3 ,
+.Xr scanf_l 3 ,
+.Xr snprintf_l 3 ,
+.Xr sprintf_l 3 ,
+.Xr sscanf_l 3 ,
+.Xr vasprintf_l 3 ,
+.Xr vfprintf_l 3 ,
+.Xr vfscanf_l 3 ,
+.Xr vprintf_l 3 ,
+.Xr vscanf_l 3 ,
+.Xr vsnprintf_l 3 ,
+.Xr vsprintf_l 3 ,
+.Xr vsscanf_l 3
+.It In stdlib.h
+.Xr atof_l 3 ,
+.Xr atoi_l 3 ,
+.Xr atol_l 3 ,
+.Xr atoll_l 3 ,
+.Xr mblen_l 3 ,
+.Xr mbstowcs_l 3 ,
+.Xr mbtowc_l 3 ,
+.Xr strtod_l 3 ,
+.Xr strtof_l 3 ,
+.Xr strtol_l 3 ,
+.Xr strtold_l 3 ,
+.Xr strtoll_l 3 ,
+.Xr strtoq_l 3 ,
+.Xr strtoul_l 3 ,
+.Xr strtoull_l 3 ,
+.Xr strtouq_l 3 ,
+.Xr wcstombs_l 3 ,
+.Xr wctomb_l 3
+.It In string.h
+.Xr strcoll_l 3 ,
+.Xr strxfrm_l 3 ,
+.Xr strcasecmp_l 3 ,
+.Xr strcasestr_l 3 ,
+.Xr strncasecmp_l 3
+.It In time.h
+.Xr strftime_l 3
+.Xr strptime_l 3
+.It In wchar.h
+.Xr btowc_l 3 ,
+.Xr fgetwc_l 3 ,
+.Xr fgetws_l 3 ,
+.Xr fputwc_l 3 ,
+.Xr fputws_l 3 ,
+.Xr fwprintf_l 3 ,
+.Xr fwscanf_l 3 ,
+.Xr getwc_l 3 ,
+.Xr getwchar_l 3 ,
+.Xr mbrlen_l 3 ,
+.Xr mbrtowc_l 3 ,
+.Xr mbsinit_l 3 ,
+.Xr mbsnrtowcs_l 3 ,
+.Xr mbsrtowcs_l 3 ,
+.Xr putwc_l 3 ,
+.Xr putwchar_l 3 ,
+.Xr swprintf_l 3 ,
+.Xr swscanf_l 3 ,
+.Xr ungetwc_l 3 ,
+.Xr vfwprintf_l 3 ,
+.Xr vfwscanf_l 3 ,
+.Xr vswprintf_l 3 ,
+.Xr vswscanf_l 3 ,
+.Xr vwprintf_l 3 ,
+.Xr vwscanf_l 3 ,
+.Xr wcrtomb_l 3 ,
+.Xr wcscoll_l 3 ,
+.Xr wcsftime_l 3 ,
+.Xr wcsnrtombs_l 3 ,
+.Xr wcsrtombs_l 3 ,
+.Xr wcstod_l 3 ,
+.Xr wcstof_l 3 ,
+.Xr wcstol_l 3 ,
+.Xr wcstold_l 3 ,
+.Xr wcstoll_l 3 ,
+.Xr wcstoul_l 3 ,
+.Xr wcstoull_l 3 ,
+.Xr wcswidth_l 3 ,
+.Xr wcsxfrm_l 3 ,
+.Xr wctob_l 3 ,
+.Xr wcwidth_l 3 ,
+.Xr wprintf_l 3 ,
+.Xr wscanf_l 3
+.It In wctype.h
+.Xr iswblank_l 3 ,
+.Xr iswhexnumber_l 3 ,
+.Xr iswideogram_l 3 ,
+.Xr iswnumber_l 3 ,
+.Xr iswphonogram_l 3 ,
+.Xr iswrune_l 3 ,
+.Xr iswspecial_l 3 ,
+.Xr nextwctype_l 3 ,
+.Xr towctrans_l 3 ,
+.Xr wctrans_l 3
+.It In xlocale.h
+.Xr localeconv_l 3
+.El
+.Sh STANDARDS
+The functions
+conform to
+.St -p1003.1-2008 .
+.Sh HISTORY
+The xlocale APIs first appeared in Darwin 8.0.
+This implementation was written by David Chisnall,
+under sponsorship from the FreeBSD Foundation and first appeared in
+.Fx 9.1 .
+.Sh CAVEATS
+The
+.Xr setlocale 3
+function, and others in the family, refer to the global locale.
+Other functions that depend on the locale, however,
+will take the thread-local locale if one has been set.
+This means that the idiom of setting the locale using
+.Xr setlocale 3 ,
+calling a locale-dependent function,
+and then restoring the locale will not
+have the expected behavior if the current thread has had a locale set using
+.Xr uselocale 3 .
+You should avoid this idiom and prefer to use the
+.Fa _l
+suffixed versions instead.
diff --git a/lib/libc/locale/xlocale.c b/lib/libc/locale/xlocale.c
new file mode 100644
index 000000000000..a005f0fca7e3
--- /dev/null
+++ b/lib/libc/locale/xlocale.c
@@ -0,0 +1,367 @@
+/*-
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by David Chisnall under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <string.h>
+#include <runetype.h>
+#include "libc_private.h"
+#include "xlocale_private.h"
+
+/**
+ * Each locale loader declares a global component. This is used by setlocale()
+ * and also by xlocale with LC_GLOBAL_LOCALE..
+ */
+extern struct xlocale_component __xlocale_global_collate;
+extern struct xlocale_component __xlocale_global_ctype;
+extern struct xlocale_component __xlocale_global_monetary;
+extern struct xlocale_component __xlocale_global_numeric;
+extern struct xlocale_component __xlocale_global_time;
+extern struct xlocale_component __xlocale_global_messages;
+/*
+ * And another version for the statically-allocated C locale. We only have
+ * components for the parts that are expected to be sensible.
+ */
+extern struct xlocale_component __xlocale_C_collate;
+extern struct xlocale_component __xlocale_C_ctype;
+
+#ifndef __NO_TLS
+/*
+ * The locale for this thread.
+ */
+_Thread_local locale_t __thread_locale;
+#endif
+/*
+ * Flag indicating that one or more per-thread locales exist.
+ */
+int __has_thread_locale;
+/*
+ * Private functions in setlocale.c.
+ */
+const char *
+__get_locale_env(int category);
+int
+__detect_path_locale(void);
+
+struct _xlocale __xlocale_global_locale = {
+ {0},
+ {
+ &__xlocale_global_collate,
+ &__xlocale_global_ctype,
+ &__xlocale_global_monetary,
+ &__xlocale_global_numeric,
+ &__xlocale_global_time,
+ &__xlocale_global_messages
+ },
+ 1,
+ 0,
+ 1,
+ 0
+};
+
+struct _xlocale __xlocale_C_locale = {
+ {0},
+ {
+ &__xlocale_C_collate,
+ &__xlocale_C_ctype,
+ 0, 0, 0, 0
+ },
+ 1,
+ 0,
+ 1,
+ 0
+};
+
+static void*(*constructors[])(const char*, locale_t) =
+{
+ __collate_load,
+ __ctype_load,
+ __monetary_load,
+ __numeric_load,
+ __time_load,
+ __messages_load
+};
+
+static pthread_key_t locale_info_key;
+static int fake_tls;
+static locale_t thread_local_locale;
+
+static void init_key(void)
+{
+
+ pthread_key_create(&locale_info_key, xlocale_release);
+ pthread_setspecific(locale_info_key, (void*)42);
+ if (pthread_getspecific(locale_info_key) == (void*)42) {
+ pthread_setspecific(locale_info_key, 0);
+ } else {
+ fake_tls = 1;
+ }
+ /* At least one per-thread locale has now been set. */
+ __has_thread_locale = 1;
+ __detect_path_locale();
+}
+
+static pthread_once_t once_control = PTHREAD_ONCE_INIT;
+
+static locale_t
+get_thread_locale(void)
+{
+
+ _once(&once_control, init_key);
+
+ return (fake_tls ? thread_local_locale :
+ pthread_getspecific(locale_info_key));
+}
+
+#ifdef __NO_TLS
+locale_t
+__get_locale(void)
+{
+ locale_t l = get_thread_locale();
+ return (l ? l : &__xlocale_global_locale);
+
+}
+#endif
+
+static void
+set_thread_locale(locale_t loc)
+{
+ locale_t l = (loc == LC_GLOBAL_LOCALE) ? 0 : loc;
+
+ _once(&once_control, init_key);
+
+ if (NULL != l) {
+ xlocale_retain((struct xlocale_refcounted*)l);
+ }
+ locale_t old = pthread_getspecific(locale_info_key);
+ if ((NULL != old) && (l != old)) {
+ xlocale_release((struct xlocale_refcounted*)old);
+ }
+ if (fake_tls) {
+ thread_local_locale = l;
+ } else {
+ pthread_setspecific(locale_info_key, l);
+ }
+#ifndef __NO_TLS
+ __thread_locale = l;
+ __set_thread_rune_locale(loc);
+#endif
+}
+
+/**
+ * Clean up a locale, once its reference count reaches zero. This function is
+ * called by xlocale_release(), it should not be called directly.
+ */
+static void
+destruct_locale(void *l)
+{
+ locale_t loc = l;
+
+ for (int type=0 ; type<XLC_LAST ; type++) {
+ if (loc->components[type]) {
+ xlocale_release(loc->components[type]);
+ }
+ }
+ if (loc->csym) {
+ free(loc->csym);
+ }
+ free(l);
+}
+
+/**
+ * Allocates a new, uninitialised, locale.
+ */
+static locale_t
+alloc_locale(void)
+{
+ locale_t new = calloc(sizeof(struct _xlocale), 1);
+
+ new->header.destructor = destruct_locale;
+ new->monetary_locale_changed = 1;
+ new->numeric_locale_changed = 1;
+ return (new);
+}
+static void
+copyflags(locale_t new, locale_t old)
+{
+ new->using_monetary_locale = old->using_monetary_locale;
+ new->using_numeric_locale = old->using_numeric_locale;
+ new->using_time_locale = old->using_time_locale;
+ new->using_messages_locale = old->using_messages_locale;
+}
+
+static int dupcomponent(int type, locale_t base, locale_t new)
+{
+ /* Always copy from the global locale, since it has mutable components.
+ */
+ struct xlocale_component *src = base->components[type];
+
+ if (&__xlocale_global_locale == base) {
+ new->components[type] = constructors[type](src->locale, new);
+ if (new->components[type]) {
+ strncpy(new->components[type]->locale, src->locale,
+ ENCODING_LEN);
+ }
+ } else if (base->components[type]) {
+ new->components[type] = xlocale_retain(base->components[type]);
+ } else {
+ /* If the component was NULL, return success - if base is a
+ * valid locale then the flag indicating that this isn't
+ * present should be set. If it isn't a valid locale, then
+ * we're stuck anyway. */
+ return 1;
+ }
+ return (0 != new->components[type]);
+}
+
+/*
+ * Public interfaces. These are the five public functions described by the
+ * xlocale interface.
+ */
+
+locale_t newlocale(int mask, const char *locale, locale_t base)
+{
+ int type;
+ const char *realLocale = locale;
+ int useenv = 0;
+ int success = 1;
+
+ _once(&once_control, init_key);
+
+ locale_t new = alloc_locale();
+ if (NULL == new) {
+ return (NULL);
+ }
+
+ FIX_LOCALE(base);
+ copyflags(new, base);
+
+ if (NULL == locale) {
+ realLocale = "C";
+ } else if ('\0' == locale[0]) {
+ useenv = 1;
+ }
+
+ for (type=0 ; type<XLC_LAST ; type++) {
+ if (mask & 1) {
+ if (useenv) {
+ realLocale = __get_locale_env(type);
+ }
+ new->components[type] =
+ constructors[type](realLocale, new);
+ if (new->components[type]) {
+ strncpy(new->components[type]->locale,
+ realLocale, ENCODING_LEN);
+ } else {
+ success = 0;
+ break;
+ }
+ } else {
+ if (!dupcomponent(type, base, new)) {
+ success = 0;
+ break;
+ }
+ }
+ mask >>= 1;
+ }
+ if (0 == success) {
+ xlocale_release(new);
+ new = NULL;
+ }
+
+ return (new);
+}
+
+locale_t duplocale(locale_t base)
+{
+ locale_t new = alloc_locale();
+ int type;
+
+ _once(&once_control, init_key);
+
+ if (NULL == new) {
+ return (NULL);
+ }
+
+ FIX_LOCALE(base);
+ copyflags(new, base);
+
+ for (type=0 ; type<XLC_LAST ; type++) {
+ dupcomponent(type, base, new);
+ }
+
+ return (new);
+}
+
+/*
+ * Free a locale_t. This is quite a poorly named function. It actually
+ * disclaims a reference to a locale_t, rather than freeing it.
+ */
+void
+freelocale(locale_t loc)
+{
+
+ /*
+ * Fail if we're passed something that isn't a locale. If we're
+ * passed the global locale, pretend that we freed it but don't
+ * actually do anything.
+ */
+ if (loc != NULL && loc != LC_GLOBAL_LOCALE &&
+ loc != &__xlocale_global_locale)
+ xlocale_release(loc);
+}
+
+/*
+ * Returns the name of the locale for a particular component of a locale_t.
+ */
+const char *querylocale(int mask, locale_t loc)
+{
+ int type = ffs(mask) - 1;
+ FIX_LOCALE(loc);
+ if (type >= XLC_LAST)
+ return (NULL);
+ if (loc->components[type])
+ return (loc->components[type]->locale);
+ return ("C");
+}
+
+/*
+ * Installs the specified locale_t as this thread's locale.
+ */
+locale_t uselocale(locale_t loc)
+{
+ locale_t old = get_thread_locale();
+ if (NULL != loc) {
+ set_thread_locale(loc);
+ }
+ return (old ? old : LC_GLOBAL_LOCALE);
+}
+
diff --git a/lib/libc/locale/xlocale_private.h b/lib/libc/locale/xlocale_private.h
new file mode 100644
index 000000000000..77b9ff4ee44f
--- /dev/null
+++ b/lib/libc/locale/xlocale_private.h
@@ -0,0 +1,231 @@
+/*-
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by David Chisnall under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _XLOCALE_PRIVATE__H_
+#define _XLOCALE_PRIVATE__H_
+
+#include <xlocale.h>
+#include <locale.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <machine/atomic.h>
+#include "setlocale.h"
+
+enum {
+ XLC_COLLATE = 0,
+ XLC_CTYPE,
+ XLC_MONETARY,
+ XLC_NUMERIC,
+ XLC_TIME,
+ XLC_MESSAGES,
+ XLC_LAST
+};
+
+
+/**
+ * Header used for objects that are reference counted. Objects may optionally
+ * have a destructor associated, which is responsible for destroying the
+ * structure. Global / static versions of the structure should have no
+ * destructor set - they can then have their reference counts manipulated as
+ * normal, but will not do anything with them.
+ *
+ * The header stores a retain count - objects are assumed to have a reference
+ * count of 1 when they are created, but the retain count is 0. When the
+ * retain count is less than 0, they are freed.
+ */
+struct xlocale_refcounted {
+ /** Number of references to this component. */
+ long retain_count;
+ /** Function used to destroy this component, if one is required*/
+ void(*destructor)(void*);
+};
+/**
+ * Header for a locale component. All locale components must begin with this
+ * header.
+ */
+struct xlocale_component {
+ struct xlocale_refcounted header;
+ /** Name of the locale used for this component. */
+ char locale[ENCODING_LEN+1];
+};
+
+/**
+ * xlocale structure, stores per-thread locale information.
+ */
+struct _xlocale {
+ struct xlocale_refcounted header;
+ /** Components for the locale. */
+ struct xlocale_component *components[XLC_LAST];
+ /** Flag indicating if components[XLC_MONETARY] has changed since the
+ * last call to localeconv_l() with this locale. */
+ int monetary_locale_changed;
+ /** Flag indicating whether this locale is actually using a locale for
+ * LC_MONETARY (1), or if it should use the C default instead (0). */
+ int using_monetary_locale;
+ /** Flag indicating if components[XLC_NUMERIC] has changed since the
+ * last call to localeconv_l() with this locale. */
+ int numeric_locale_changed;
+ /** Flag indicating whether this locale is actually using a locale for
+ * LC_NUMERIC (1), or if it should use the C default instead (0). */
+ int using_numeric_locale;
+ /** Flag indicating whether this locale is actually using a locale for
+ * LC_TIME (1), or if it should use the C default instead (0). */
+ int using_time_locale;
+ /** Flag indicating whether this locale is actually using a locale for
+ * LC_MESSAGES (1), or if it should use the C default instead (0). */
+ int using_messages_locale;
+ /** The structure to be returned from localeconv_l() for this locale. */
+ struct lconv lconv;
+ /** Persistent state used by mblen() calls. */
+ __mbstate_t mblen;
+ /** Persistent state used by mbrlen() calls. */
+ __mbstate_t mbrlen;
+ /** Persistent state used by mbrtoc16() calls. */
+ __mbstate_t mbrtoc16;
+ /** Persistent state used by mbrtoc32() calls. */
+ __mbstate_t mbrtoc32;
+ /** Persistent state used by mbrtowc() calls. */
+ __mbstate_t mbrtowc;
+ /** Persistent state used by mbsnrtowcs() calls. */
+ __mbstate_t mbsnrtowcs;
+ /** Persistent state used by mbsrtowcs() calls. */
+ __mbstate_t mbsrtowcs;
+ /** Persistent state used by mbtowc() calls. */
+ __mbstate_t mbtowc;
+ /** Persistent state used by c16rtomb() calls. */
+ __mbstate_t c16rtomb;
+ /** Persistent state used by c32rtomb() calls. */
+ __mbstate_t c32rtomb;
+ /** Persistent state used by wcrtomb() calls. */
+ __mbstate_t wcrtomb;
+ /** Persistent state used by wcsnrtombs() calls. */
+ __mbstate_t wcsnrtombs;
+ /** Persistent state used by wcsrtombs() calls. */
+ __mbstate_t wcsrtombs;
+ /** Persistent state used by wctomb() calls. */
+ __mbstate_t wctomb;
+ /** Buffer used by nl_langinfo_l() */
+ char *csym;
+};
+
+/**
+ * Increments the reference count of a reference-counted structure.
+ */
+__attribute__((unused)) static void*
+xlocale_retain(void *val)
+{
+ struct xlocale_refcounted *obj = val;
+ atomic_add_long(&(obj->retain_count), 1);
+ return (val);
+}
+/**
+ * Decrements the reference count of a reference-counted structure, freeing it
+ * if this is the last reference, calling its destructor if it has one.
+ */
+__attribute__((unused)) static void
+xlocale_release(void *val)
+{
+ struct xlocale_refcounted *obj = val;
+ long count;
+
+ count = atomic_fetchadd_long(&(obj->retain_count), -1) - 1;
+ if (count < 0 && obj->destructor != NULL)
+ obj->destructor(obj);
+}
+
+/**
+ * Load functions. Each takes the name of a locale and a pointer to the data
+ * to be initialised as arguments. Two special values are allowed for the
+ */
+extern void* __collate_load(const char*, locale_t);
+extern void* __ctype_load(const char*, locale_t);
+extern void* __messages_load(const char*, locale_t);
+extern void* __monetary_load(const char*, locale_t);
+extern void* __numeric_load(const char*, locale_t);
+extern void* __time_load(const char*, locale_t);
+
+extern struct _xlocale __xlocale_global_locale;
+extern struct _xlocale __xlocale_C_locale;
+
+/**
+ * Caches the rune table in TLS for fast access.
+ */
+void __set_thread_rune_locale(locale_t loc);
+/**
+ * Flag indicating whether a per-thread locale has been set. If no per-thread
+ * locale has ever been set, then we always use the global locale.
+ */
+extern int __has_thread_locale;
+#ifndef __NO_TLS
+/**
+ * The per-thread locale. Avoids the need to use pthread lookup functions when
+ * getting the per-thread locale.
+ */
+extern _Thread_local locale_t __thread_locale;
+
+/**
+ * Returns the current locale for this thread, or the global locale if none is
+ * set. The caller does not have to free the locale. The return value from
+ * this call is not guaranteed to remain valid after the locale changes. As
+ * such, this should only be called within libc functions.
+ */
+static inline locale_t __get_locale(void)
+{
+
+ if (!__has_thread_locale) {
+ return (&__xlocale_global_locale);
+ }
+ return (__thread_locale ? __thread_locale : &__xlocale_global_locale);
+}
+#else
+locale_t __get_locale(void);
+#endif
+
+/**
+ * Two magic values are allowed for locale_t objects. NULL and -1. This
+ * function maps those to the real locales that they represent.
+ */
+static inline locale_t get_real_locale(locale_t locale)
+{
+ switch ((intptr_t)locale) {
+ case 0: return (&__xlocale_C_locale);
+ case -1: return (&__xlocale_global_locale);
+ default: return (locale);
+ }
+}
+
+/**
+ * Replace a placeholder locale with the real global or thread-local locale_t.
+ */
+#define FIX_LOCALE(l) (l = get_real_locale(l))
+
+#endif
diff --git a/lib/libc/md/Makefile.inc b/lib/libc/md/Makefile.inc
new file mode 100644
index 000000000000..3f173c866d1d
--- /dev/null
+++ b/lib/libc/md/Makefile.inc
@@ -0,0 +1,5 @@
+# $FreeBSD$
+
+.PATH: ${SRCTOP}/lib/libmd
+
+SRCS+= md5c.c
diff --git a/lib/libc/mips/Makefile.inc b/lib/libc/mips/Makefile.inc
new file mode 100644
index 000000000000..54ce38e49bfa
--- /dev/null
+++ b/lib/libc/mips/Makefile.inc
@@ -0,0 +1,9 @@
+# $NetBSD: Makefile.inc,v 1.7 2005/09/17 11:49:39 tsutsui Exp $
+# $FreeBSD$
+
+.if ${MACHINE_ARCH:Mmips*hf} == ""
+CFLAGS+=-DSOFTFLOAT
+.endif
+
+MDSRCS+= machdep_ldisd.c
+SYM_MAPS+= ${LIBC_SRCTOP}/mips/Symbol.map
diff --git a/lib/libc/mips/SYS.h b/lib/libc/mips/SYS.h
new file mode 100644
index 000000000000..ceb68121b07d
--- /dev/null
+++ b/lib/libc/mips/SYS.h
@@ -0,0 +1,151 @@
+/* $NetBSD: SYS.h,v 1.19 2009/12/14 01:07:41 matt Exp $ */
+/* $FreeBSD$ */
+
+/*-
+ * Copyright (c) 1996 Jonathan Stone
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jonathan Stone for
+ * the NetBSD Project.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ralph Campbell.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)SYS.h 8.1 (Berkeley) 6/4/93
+ */
+
+#include <sys/syscall.h>
+
+#include <machine/asm.h>
+
+/*
+ * If compiling for shared libs, Emit sysV ABI PIC segment pseudo-ops.
+ *
+ * i) Emit .abicalls before .LEAF entrypoint, and .cpload/.cprestore after.
+ * ii) Do interprocedure jumps indirectly via t9, with the side-effect of
+ * preserving the callee's entry address in t9.
+ */
+#ifdef __ABICALLS__
+ .abicalls
+# if defined(__mips_o32) || defined(__mips_o64)
+# define PIC_PROLOGUE(x) SETUP_GP
+# define PIC_TAILCALL(l) PTR_LA t9, _C_LABEL(l); jr t9
+# define PIC_RETURN() j ra
+# else
+# define PIC_PROLOGUE(x) SETUP_GP64(t3, x)
+# define PIC_TAILCALL(l) PTR_LA t9, _C_LABEL(l); RESTORE_GP64; jr t9
+# define PIC_RETURN() RESTORE_GP64; j ra
+# endif
+#else
+# define PIC_PROLOGUE(x)
+# define PIC_TAILCALL(l) j _C_LABEL(l)
+# define PIC_RETURN() j ra
+#endif /* __ABICALLS__ */
+
+# define SYSTRAP(x) li v0,SYS_ ## x; syscall;
+
+/*
+ * Do a syscall that cannot fail (sync, get{p,u,g,eu,eg)id)
+ */
+#define RSYSCALL_NOERROR(x) \
+LEAF(__sys_ ## x); \
+ .weak _C_LABEL(x); \
+ _C_LABEL(x) = _C_LABEL(__CONCAT(__sys_,x)); \
+ .weak _C_LABEL(__CONCAT(_,x)); \
+ _C_LABEL(__CONCAT(_,x)) = _C_LABEL(__CONCAT(__sys_,x)); \
+ SYSTRAP(x); \
+ j ra; \
+END(__sys_ ## x)
+
+/*
+ * Do a normal syscall.
+ */
+#define RSYSCALL(x) \
+LEAF(__sys_ ## x); \
+ .weak _C_LABEL(x); \
+ _C_LABEL(x) = _C_LABEL(__CONCAT(__sys_,x)); \
+ .weak _C_LABEL(__CONCAT(_,x)); \
+ _C_LABEL(__CONCAT(_,x)) = _C_LABEL(__CONCAT(__sys_,x)); \
+ PIC_PROLOGUE(__sys_ ## x); \
+ SYSTRAP(x); \
+ bne a3,zero,err; \
+ PIC_RETURN(); \
+err: \
+ PIC_TAILCALL(__cerror); \
+END(__sys_ ## x)
+
+/*
+ * Do a renamed or pseudo syscall (e.g., _exit()), where the entrypoint
+ * and syscall name are not the same.
+ */
+#define PSEUDO_NOERROR(x) \
+LEAF(__sys_ ## x); \
+ .weak _C_LABEL(__CONCAT(_,x)); \
+ _C_LABEL(__CONCAT(_,x)) = _C_LABEL(__CONCAT(__sys_,x)); \
+ SYSTRAP(x); \
+ j ra; \
+END(__sys_ ## x)
+
+#define PSEUDO(x) \
+LEAF(__sys_ ## x); \
+ .weak _C_LABEL(__CONCAT(_,x)); \
+ _C_LABEL(__CONCAT(_,x)) = _C_LABEL(__CONCAT(__sys_,x)); \
+ PIC_PROLOGUE(__sys_ ## x); \
+ SYSTRAP(x); \
+ bne a3,zero,err; \
+ PIC_RETURN(); \
+err: \
+ PIC_TAILCALL(__cerror); \
+END(__sys_ ## x)
diff --git a/lib/libc/mips/Symbol.map b/lib/libc/mips/Symbol.map
new file mode 100644
index 000000000000..9791359c93f6
--- /dev/null
+++ b/lib/libc/mips/Symbol.map
@@ -0,0 +1,78 @@
+/*
+ * $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, ...).
+ */
+FBSD_1.0 {
+ /* PSEUDO syscalls */
+ _exit;
+
+ _setjmp;
+ _longjmp;
+ alloca;
+ fabs;
+ __infinity;
+ __nan;
+ makecontext;
+ setjmp;
+ longjmp;
+ sigsetjmp;
+ siglongjmp;
+ htonl;
+ htons;
+ ntohl;
+ ntohs;
+ vfork;
+ brk;
+ sbrk;
+};
+
+FBSD_1.3 {
+ __flt_rounds;
+};
+
+FBSDprivate_1.0 {
+ /* PSEUDO syscalls */
+ __sys_getlogin;
+ _getlogin;
+ __sys_exit;
+
+ _set_tp;
+ ___longjmp;
+ __umodsi3;
+ __modsi3;
+ __udivsi3;
+ __divsi3;
+ __makecontext;
+ __longjmp;
+ signalcontext;
+ _signalcontext;
+ __siglongjmp;
+ __sys_vfork;
+ _vfork;
+ _end;
+ _brk;
+ _sbrk;
+
+ /* softfloat */
+ __addsf3;
+ __adddf3;
+ __subsf3;
+ __subdf3;
+ __mulsf3;
+ __muldf3;
+ __divsf3;
+ __divdf3;
+ __floatsisf;
+ __floatsidf;
+ __fixsfsi;
+ __fixdfsi;
+ __fixunssfsi;
+ __fixunsdfsi;
+ __extendsfdf2;
+ __truncdfsf2;
+};
diff --git a/lib/libc/mips/_fpmath.h b/lib/libc/mips/_fpmath.h
new file mode 100644
index 000000000000..f006a583bc7c
--- /dev/null
+++ b/lib/libc/mips/_fpmath.h
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 2002, 2003 David Schultz <das@FreeBSD.ORG>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+union IEEEl2bits {
+ long double e;
+ struct {
+#ifndef __MIPSEB__
+ unsigned int manl :32;
+ unsigned int manh :20;
+ unsigned int exp :11;
+ unsigned int sign :1;
+#else
+ unsigned int sign :1;
+ unsigned int exp :11;
+ unsigned int manh :20;
+ unsigned int manl :32;
+#endif
+ } bits;
+};
+
+#define LDBL_NBIT 0
+#define mask_nbit_l(u) ((void)0)
+#define LDBL_IMPLICIT_NBIT
+
+#define LDBL_MANH_SIZE 20
+#define LDBL_MANL_SIZE 32
+
+#define LDBL_TO_ARRAY32(u, a) do { \
+ (a)[0] = (uint32_t)(u).bits.manl; \
+ (a)[1] = (uint32_t)(u).bits.manh; \
+} while(0)
diff --git a/lib/libc/mips/arith.h b/lib/libc/mips/arith.h
new file mode 100644
index 000000000000..61f3930f4a89
--- /dev/null
+++ b/lib/libc/mips/arith.h
@@ -0,0 +1,26 @@
+/*
+ * MD header for contrib/gdtoa
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * NOTE: The definitions in this file must be correct or strtod(3) and
+ * floating point formats in printf(3) will break! The file can be
+ * generated by running contrib/gdtoa/arithchk.c on the target
+ * architecture. See contrib/gdtoa/gdtoaimp.h for details.
+ */
+#include <machine/endian.h>
+
+#if BYTE_ORDER == BIG_ENDIAN
+#define IEEE_MC68k
+#define Arith_Kind_ASL 2
+#define Double_Align
+#else
+/* TODO: Generate these values on a LE machine */
+#define IEEE_8087
+#define Arith_Kind_ASL 1
+#define Long int
+#define Intcast (int)(long)
+#define Double_Align
+#endif
diff --git a/lib/libc/mips/gd_qnan.h b/lib/libc/mips/gd_qnan.h
new file mode 100644
index 000000000000..69eeaf988fa0
--- /dev/null
+++ b/lib/libc/mips/gd_qnan.h
@@ -0,0 +1,48 @@
+/*
+ * MD header for contrib/gdtoa
+ *
+ * This file can be generated by compiling and running contrib/gdtoa/qnan.c
+ * on the target architecture after arith.h has been generated.
+ *
+ * $FreeBSD$
+ */
+
+
+#include <machine/endian.h>
+
+#if BYTE_ORDER == BIG_ENDIAN
+/* These values were gained on a running
+ * Octeon in Big Endian order. They were gotten
+ * by running ./qnan after arithchk was ran and
+ * got us the proper values for arith.h.
+ */
+#define f_QNAN 0x7f900000
+#define d_QNAN0 0x7ff80000
+#define d_QNAN1 0x0
+#define ld_QNAN0 0x7ff80000
+#define ld_QNAN1 0x0
+#define ld_QNAN2 0x0
+#define ld_QNAN3 0x0
+#define ldus_QNAN0 0x7ff8
+#define ldus_QNAN1 0x0
+#define ldus_QNAN2 0x0
+#define ldus_QNAN3 0x0
+#define ldus_QNAN4 0x0
+#else
+/* FIX FIX, need to run this on a Little Endian
+ * machine and get the proper values, these here
+ * were stolen fromn i386/gd_qnan.h
+ */
+#define f_QNAN 0x7fc00000
+#define d_QNAN0 0x0
+#define d_QNAN1 0x7ff80000
+#define ld_QNAN0 0x0
+#define ld_QNAN1 0xc0000000
+#define ld_QNAN2 0x7fff
+#define ld_QNAN3 0x0
+#define ldus_QNAN0 0x0
+#define ldus_QNAN1 0x0
+#define ldus_QNAN2 0x0
+#define ldus_QNAN3 0xc000
+#define ldus_QNAN4 0x7fff
+#endif
diff --git a/lib/libc/mips/gdtoa/Makefile.inc b/lib/libc/mips/gdtoa/Makefile.inc
new file mode 100644
index 000000000000..dd6268c4b917
--- /dev/null
+++ b/lib/libc/mips/gdtoa/Makefile.inc
@@ -0,0 +1,4 @@
+# $NetBSD: Makefile.inc,v 1.1 2006/03/15 17:35:18 kleink Exp $
+# $FreeBSD$
+
+SRCS+= strtof.c
diff --git a/lib/libc/mips/gdtoa/arith.h b/lib/libc/mips/gdtoa/arith.h
new file mode 100644
index 000000000000..8b700f8acfcd
--- /dev/null
+++ b/lib/libc/mips/gdtoa/arith.h
@@ -0,0 +1,10 @@
+/* $NetBSD: arith.h,v 1.1 2006/01/25 15:33:28 kleink Exp $ */
+/* $FreeBSD$ */
+
+#include <machine/endian.h>
+
+#if BYTE_ORDER == BIG_ENDIAN
+#define IEEE_BIG_ENDIAN
+#else
+#define IEEE_LITTLE_ENDIAN
+#endif
diff --git a/lib/libc/mips/gen/Makefile.inc b/lib/libc/mips/gen/Makefile.inc
new file mode 100644
index 000000000000..56fa380f7777
--- /dev/null
+++ b/lib/libc/mips/gen/Makefile.inc
@@ -0,0 +1,11 @@
+# $NetBSD: Makefile.inc,v 1.27 2005/10/07 17:16:40 tsutsui Exp $
+# $FreeBSD$
+
+SRCS+= infinity.c fabs.c ldexp.c flt_rounds.c
+
+# SRCS+= flt_rounds.c fpgetmask.c fpgetround.c fpgetsticky.c fpsetmask.c \
+# fpsetround.c fpsetsticky.c
+
+SRCS+= _ctx_start.S _set_tp.c _setjmp.S makecontext.c \
+ setjmp.S signalcontext.c sigsetjmp.S \
+ trivial-getcontextx.c
diff --git a/lib/libc/mips/gen/_ctx_start.S b/lib/libc/mips/gen/_ctx_start.S
new file mode 100644
index 000000000000..5d754a9927d1
--- /dev/null
+++ b/lib/libc/mips/gen/_ctx_start.S
@@ -0,0 +1,41 @@
+/*-
+ * Copyright (c) 2010 Juli Mallett.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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$");
+
+/*
+ * XXX gp?
+ */
+ENTRY(_ctx_start)
+ jalr t9
+
+ move a0, s0
+ PTR_LA t9, _ctx_done
+ jalr t9
+
+ break 0
+END(_ctx_start)
diff --git a/lib/libc/mips/gen/_set_tp.c b/lib/libc/mips/gen/_set_tp.c
new file mode 100644
index 000000000000..a1a30c54b597
--- /dev/null
+++ b/lib/libc/mips/gen/_set_tp.c
@@ -0,0 +1,40 @@
+/*-
+ * Copyright (c) 2004 Doug Rabson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <string.h>
+#include <stdint.h>
+
+#include <machine/sysarch.h>
+#include "libc_private.h"
+
+void
+_set_tp(void *tp)
+{
+
+ sysarch(MIPS_SET_TLS, tp);
+}
diff --git a/lib/libc/mips/gen/_setjmp.S b/lib/libc/mips/gen/_setjmp.S
new file mode 100644
index 000000000000..0f7a75a82a6d
--- /dev/null
+++ b/lib/libc/mips/gen/_setjmp.S
@@ -0,0 +1,201 @@
+/* $NetBSD: _setjmp.S,v 1.20.34.5 2010/02/03 23:46:47 matt Exp $ */
+
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ralph Campbell.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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$");
+#include <machine/regnum.h>
+
+#include "SYS.h"
+
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+ RCSID("from: @(#)_setjmp.s 8.1 (Berkeley) 6/4/93")
+#else
+ RCSID("$NetBSD: _setjmp.S,v 1.20.34.5 2010/02/03 23:46:47 matt Exp $")
+#endif
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * C library -- _setjmp, _longjmp
+ *
+ * _longjmp(a,v)
+ * will generate a "return(v)" from
+ * the last call to
+ * _setjmp(a)
+ * by restoring registers from the stack,
+ * The previous signal state is NOT restored.
+ */
+
+ .set noreorder
+
+LEAF(_setjmp)
+ REG_PROLOGUE
+ REG_LI v0, _JB_MAGIC__SETJMP # sigcontext magic number
+ REG_S v0, (_JB_MAGIC * SZREG)(a0)
+ REG_S ra, (_JB_REG_RA * SZREG)(a0)
+ /*
+ * From "MIPSpro N32 ABI Handbook", Table 2-1:
+ * Registers s0..s7 are callee-saved.
+ * The sp register is callee-saved.
+ * The fp (or s8) register is callee-saved.
+ * The gp register is callee-saved (for n32/n64).
+ */
+ REG_S s0, (_JB_REG_S0 * SZREG)(a0)
+ REG_S s1, (_JB_REG_S1 * SZREG)(a0)
+ REG_S s2, (_JB_REG_S2 * SZREG)(a0)
+ REG_S s3, (_JB_REG_S3 * SZREG)(a0)
+ REG_S s4, (_JB_REG_S4 * SZREG)(a0)
+ REG_S s5, (_JB_REG_S5 * SZREG)(a0)
+ REG_S s6, (_JB_REG_S6 * SZREG)(a0)
+ REG_S s7, (_JB_REG_S7 * SZREG)(a0)
+ REG_S sp, (_JB_REG_SP * SZREG)(a0)
+ REG_S s8, (_JB_REG_S8 * SZREG)(a0)
+#if defined(__mips_n32) || defined(__mips_n64)
+ REG_S gp, (_JB_REG_GP * SZREG)(a0) # newabi gp is callee-saved
+#endif
+ /*
+ * From "MIPSpro N32 ABI Handbook", Table 2-1:
+ * In N32, FP registers F20, F22, F24, F26, F28, F30 are callee-saved.
+ * In N64, FP registers F24 .. F31 are callee-saved.
+ * In O32, FP registers F20 .. F23 are callee-saved.
+ */
+#ifndef SOFTFLOAT
+ cfc1 v0, $31 # too bad can't check if FP used
+#if defined(__mips_n64) || defined(__mips_n32)
+ FP_S $f30, (_JB_FPREG_F30 * SZREG)(a0)
+ FP_S $f28, (_JB_FPREG_F28 * SZREG)(a0)
+ FP_S $f26, (_JB_FPREG_F26 * SZREG)(a0)
+ FP_S $f24, (_JB_FPREG_F24 * SZREG)(a0)
+#endif
+#if defined(__mips_n32) || defined(__mips_o32) || defined(__mips_o64)
+ FP_S $f22, (_JB_FPREG_F22 * SZREG)(a0)
+ FP_S $f20, (_JB_FPREG_F20 * SZREG)(a0)
+#endif
+#if defined(__mips_o32) || defined(__mips_o64)
+ FP_S $f21, (_JB_FPREG_F21 * SZREG)(a0)
+ FP_S $f23, (_JB_FPREG_F23 * SZREG)(a0)
+#endif
+#if defined(__mips_n64)
+ FP_S $f25, (_JB_FPREG_F25 * SZREG)(a0)
+ FP_S $f27, (_JB_FPREG_F27 * SZREG)(a0)
+ FP_S $f29, (_JB_FPREG_F29 * SZREG)(a0)
+ FP_S $f31, (_JB_FPREG_F31 * SZREG)(a0)
+#endif
+ INT_S v0, (_JB_FPREG_FCSR * SZREG)(a0)
+#endif /* ! SOFTFLOAT */
+ REG_EPILOGUE
+
+ j ra
+ move v0, zero
+END(_setjmp)
+
+LEAF(_longjmp)
+ PIC_PROLOGUE(_longjmp)
+ PTR_SUBU sp, sp, CALLFRAME_SIZ
+ SAVE_GP(CALLFRAME_GP)
+
+ REG_PROLOGUE
+ REG_L v0, (_JB_MAGIC * SZREG)(a0) # get magic number
+ REG_L ra, (_JB_REG_RA * SZREG)(a0)
+ REG_LI t0, _JB_MAGIC__SETJMP
+ bne v0, t0, botch # jump if error
+ PTR_ADDU sp, sp, CALLFRAME_SIZ # does not matter, sanity
+ /*
+ * From "MIPSpro N32 ABI Handbook", Table 2-1:
+ * Registers s0..s7 are callee-saved.
+ * The sp register is callee-saved.
+ * The fp (or s8) register is callee-saved.
+ * The gp register is callee-saved (for n32/n64).
+ */
+ REG_L s0, (_JB_REG_S0 * SZREG)(a0)
+ REG_L s1, (_JB_REG_S1 * SZREG)(a0)
+ REG_L s2, (_JB_REG_S2 * SZREG)(a0)
+ REG_L s3, (_JB_REG_S3 * SZREG)(a0)
+ REG_L s4, (_JB_REG_S4 * SZREG)(a0)
+ REG_L s5, (_JB_REG_S5 * SZREG)(a0)
+ REG_L s6, (_JB_REG_S6 * SZREG)(a0)
+ REG_L s7, (_JB_REG_S7 * SZREG)(a0)
+ REG_L sp, (_JB_REG_SP * SZREG)(a0)
+ REG_L s8, (_JB_REG_S8 * SZREG)(a0)
+#if defined(__mips_n32) || defined(__mips_n64)
+ REG_L gp, (_JB_REG_GP * SZREG)(a0)
+#endif
+#ifndef SOFTFLOAT
+ # get fpu status
+ INT_L v0, (_JB_FPREG_FCSR * SZREG)(a0)
+ ctc1 v0, $31
+ /*
+ * From "MIPSpro N32 ABI Handbook", Table 2-1:
+ * In N32, FP registers F20, F22, F24, F26, F28, F30 are callee-saved.
+ * In N64, FP registers F24 .. F31 are callee-saved.
+ * In O32, FP registers F20 .. F23 are callee-saved.
+ */
+#if defined(__mips_n64) || defined(__mips_n32)
+ FP_L $f30, (_JB_FPREG_F30 * SZREG)(a0)
+ FP_L $f28, (_JB_FPREG_F28 * SZREG)(a0)
+ FP_L $f26, (_JB_FPREG_F26 * SZREG)(a0)
+ FP_L $f24, (_JB_FPREG_F24 * SZREG)(a0)
+#endif
+#if defined(__mips_n32) || defined(__mips_o32) || defined(__mips_o64)
+ FP_L $f22, (_JB_FPREG_F22 * SZREG)(a0)
+ FP_L $f20, (_JB_FPREG_F20 * SZREG)(a0)
+#endif
+#if defined(__mips_o32) || defined(__mips_o64)
+ FP_L $f21, (_JB_FPREG_F21 * SZREG)(a0)
+ FP_L $f23, (_JB_FPREG_F23 * SZREG)(a0)
+#endif
+#if defined(__mips_n64)
+ FP_L $f25, (_JB_FPREG_F25 * SZREG)(a0)
+ FP_L $f27, (_JB_FPREG_F27 * SZREG)(a0)
+ FP_L $f29, (_JB_FPREG_F29 * SZREG)(a0)
+ FP_L $f31, (_JB_FPREG_F31 * SZREG)(a0)
+#endif
+#endif /* ! SOFTFLOAT */
+
+ REG_EPILOGUE
+ move v0, a1 # get return value in 1st arg
+ j ra
+ nop
+
+botch:
+ /*
+ * We know we aren't returning so we don't care about restoring
+ * our caller's GP.
+ */
+ PTR_LA t9, _C_LABEL(longjmperror)
+ jalr t9
+ nop
+
+ PIC_TAILCALL(abort)
+END(_longjmp)
diff --git a/lib/libc/mips/gen/fabs.S b/lib/libc/mips/gen/fabs.S
new file mode 100644
index 000000000000..3b79249864d1
--- /dev/null
+++ b/lib/libc/mips/gen/fabs.S
@@ -0,0 +1,58 @@
+/* $NetBSD: fabs.S,v 1.7 2003/08/07 16:42:15 agc Exp $ */
+
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ralph Campbell.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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$");
+
+#if defined(LIBC_SCCS) && !defined(lint)
+ ASMSTR("from: @(#)fabs.s 8.1 (Berkeley) 2/16/94")
+ ASMSTR("$NetBSD: fabs.S,v 1.7 2003/08/07 16:42:15 agc Exp $")
+#endif /* LIBC_SCCS and not lint */
+
+
+#ifdef __ABICALLS__
+ .abicalls
+#endif
+ .set noreorder
+
+/*
+ * fabs(x)
+ * double x;
+ *
+ * Return absolute value of x.
+ */
+LEAF(fabs)
+ j ra
+ abs.d $f0, $f12 # compute absolute value of x
+END(fabs)
diff --git a/lib/libc/mips/gen/fabs.c b/lib/libc/mips/gen/fabs.c
new file mode 100644
index 000000000000..8bb15025aead
--- /dev/null
+++ b/lib/libc/mips/gen/fabs.c
@@ -0,0 +1,46 @@
+/* $NetBSD: fabs.c,v 1.2 2002/05/26 11:48:01 wiz Exp $ */
+
+/*
+ * Copyright (c) 1996 Mark Brinicombe
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Mark Brinicombe
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * fabs(x) returns the absolute value of x.
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+double
+fabs(double x)
+{
+ if (x < 0)
+ x = -x;
+ return(x);
+}
diff --git a/lib/libc/mips/gen/flt_rounds.c b/lib/libc/mips/gen/flt_rounds.c
new file mode 100644
index 000000000000..73428d907d11
--- /dev/null
+++ b/lib/libc/mips/gen/flt_rounds.c
@@ -0,0 +1,42 @@
+/* $NetBSD: flt_rounds.c,v 1.5 2005/12/24 23:10:08 perry Exp $ */
+
+/*
+ * Written by J.T. Conklin, Apr 11, 1995
+ * Public domain.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: flt_rounds.c,v 1.5 2005/12/24 23:10:08 perry Exp $");
+#endif /* LIBC_SCCS and not lint */
+
+#include <fenv.h>
+#include <float.h>
+
+#ifdef SOFTFLOAT
+#include "softfloat-for-gcc.h"
+#include "milieu.h"
+#include "softfloat.h"
+#endif
+
+static const int map[] = {
+ 1, /* round to nearest */
+ 0, /* round to zero */
+ 2, /* round to positive infinity */
+ 3 /* round to negative infinity */
+};
+
+int
+__flt_rounds()
+{
+ int mode;
+
+#ifdef SOFTFLOAT
+ mode = __softfloat_float_rounding_mode;
+#else
+ __asm __volatile("cfc1 %0,$31" : "=r" (mode));
+#endif
+
+ return map[mode & 0x03];
+}
diff --git a/lib/libc/mips/gen/hardfloat/fpgetmask.c b/lib/libc/mips/gen/hardfloat/fpgetmask.c
new file mode 100644
index 000000000000..505a74c68466
--- /dev/null
+++ b/lib/libc/mips/gen/hardfloat/fpgetmask.c
@@ -0,0 +1,29 @@
+/* $NetBSD: fpgetmask.c,v 1.5 2005/12/24 23:10:08 perry Exp $ */
+
+/*
+ * Written by J.T. Conklin, Apr 11, 1995
+ * Public domain.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: fpgetmask.c,v 1.5 2005/12/24 23:10:08 perry Exp $");
+#endif /* LIBC_SCCS and not lint */
+
+#include "namespace.h"
+
+#include <ieeefp.h>
+
+#ifdef __weak_alias
+__weak_alias(fpgetmask,_fpgetmask)
+#endif
+
+fp_except_t
+fpgetmask()
+{
+ int x;
+
+ __asm("cfc1 %0,$31" : "=r" (x));
+ return (x >> 7) & 0x1f;
+}
diff --git a/lib/libc/mips/gen/hardfloat/fpgetround.c b/lib/libc/mips/gen/hardfloat/fpgetround.c
new file mode 100644
index 000000000000..6d0f11a5cb6e
--- /dev/null
+++ b/lib/libc/mips/gen/hardfloat/fpgetround.c
@@ -0,0 +1,29 @@
+/* $NetBSD: fpgetround.c,v 1.5 2005/12/24 23:10:08 perry Exp $ */
+
+/*
+ * Written by J.T. Conklin, Apr 11, 1995
+ * Public domain.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: fpgetround.c,v 1.5 2005/12/24 23:10:08 perry Exp $");
+#endif /* LIBC_SCCS and not lint */
+
+#include "namespace.h"
+
+#include <ieeefp.h>
+
+#ifdef __weak_alias
+__weak_alias(fpgetround,_fpgetround)
+#endif
+
+fp_rnd_t
+fpgetround()
+{
+ int x;
+
+ __asm("cfc1 %0,$31" : "=r" (x));
+ return x & 0x03;
+}
diff --git a/lib/libc/mips/gen/hardfloat/fpgetsticky.c b/lib/libc/mips/gen/hardfloat/fpgetsticky.c
new file mode 100644
index 000000000000..8028261c2c81
--- /dev/null
+++ b/lib/libc/mips/gen/hardfloat/fpgetsticky.c
@@ -0,0 +1,29 @@
+/* $NetBSD: fpgetsticky.c,v 1.5 2005/12/24 23:10:08 perry Exp $ */
+
+/*
+ * Written by J.T. Conklin, Apr 11, 1995
+ * Public domain.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: fpgetsticky.c,v 1.5 2005/12/24 23:10:08 perry Exp $");
+#endif /* LIBC_SCCS and not lint */
+
+#include "namespace.h"
+
+#include <ieeefp.h>
+
+#ifdef __weak_alias
+__weak_alias(fpgetsticky,_fpgetsticky)
+#endif
+
+fp_except_t
+fpgetsticky()
+{
+ int x;
+
+ __asm("cfc1 %0,$31" : "=r" (x));
+ return (x >> 2) & 0x1f;
+}
diff --git a/lib/libc/mips/gen/hardfloat/fpsetmask.c b/lib/libc/mips/gen/hardfloat/fpsetmask.c
new file mode 100644
index 000000000000..7abb3fd05f92
--- /dev/null
+++ b/lib/libc/mips/gen/hardfloat/fpsetmask.c
@@ -0,0 +1,38 @@
+/* $NetBSD: fpsetmask.c,v 1.5 2005/12/24 23:10:08 perry Exp $ */
+
+/*
+ * Written by J.T. Conklin, Apr 11, 1995
+ * Public domain.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: fpsetmask.c,v 1.5 2005/12/24 23:10:08 perry Exp $");
+#endif /* LIBC_SCCS and not lint */
+
+#include "namespace.h"
+
+#include <ieeefp.h>
+
+#ifdef __weak_alias
+__weak_alias(fpsetmask,_fpsetmask)
+#endif
+
+fp_except_t
+fpsetmask(mask)
+ fp_except_t mask;
+{
+ fp_except_t old;
+ fp_except_t new;
+
+ __asm("cfc1 %0,$31" : "=r" (old));
+
+ new = old;
+ new &= ~(0x1f << 7);
+ new |= ((mask & 0x1f) << 7);
+
+ __asm("ctc1 %0,$31" : : "r" (new));
+
+ return (old >> 7) & 0x1f;
+}
diff --git a/lib/libc/mips/gen/hardfloat/fpsetround.c b/lib/libc/mips/gen/hardfloat/fpsetround.c
new file mode 100644
index 000000000000..020516180033
--- /dev/null
+++ b/lib/libc/mips/gen/hardfloat/fpsetround.c
@@ -0,0 +1,37 @@
+/* $NetBSD: fpsetround.c,v 1.5 2005/12/24 23:10:08 perry Exp $ */
+
+/*
+ * Written by J.T. Conklin, Apr 11, 1995
+ * Public domain.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: fpsetround.c,v 1.5 2005/12/24 23:10:08 perry Exp $");
+#endif /* LIBC_SCCS and not lint */
+
+#include "namespace.h"
+
+#include <ieeefp.h>
+
+#ifdef __weak_alias
+__weak_alias(fpsetround,_fpsetround)
+#endif
+
+fp_rnd_t
+fpsetround(fp_rnd_t rnd_dir)
+{
+ fp_rnd_t old;
+ fp_rnd_t new;
+
+ __asm("cfc1 %0,$31" : "=r" (old));
+
+ new = old;
+ new &= ~0x03;
+ new |= (rnd_dir & 0x03);
+
+ __asm("ctc1 %0,$31" : : "r" (new));
+
+ return old & 0x03;
+}
diff --git a/lib/libc/mips/gen/hardfloat/fpsetsticky.c b/lib/libc/mips/gen/hardfloat/fpsetsticky.c
new file mode 100644
index 000000000000..e43367117792
--- /dev/null
+++ b/lib/libc/mips/gen/hardfloat/fpsetsticky.c
@@ -0,0 +1,38 @@
+/* $NetBSD: fpsetsticky.c,v 1.5 2005/12/24 23:10:08 perry Exp $ */
+
+/*
+ * Written by J.T. Conklin, Apr 11, 1995
+ * Public domain.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: fpsetsticky.c,v 1.5 2005/12/24 23:10:08 perry Exp $");
+#endif /* LIBC_SCCS and not lint */
+
+#include "namespace.h"
+
+#include <ieeefp.h>
+
+#ifdef __weak_alias
+__weak_alias(fpsetsticky,_fpsetsticky)
+#endif
+
+fp_except
+fpsetsticky(sticky)
+ fp_except sticky;
+{
+ fp_except old;
+ fp_except new;
+
+ __asm("cfc1 %0,$31" : "=r" (old));
+
+ new = old;
+ new &= ~(0x1f << 2);
+ new |= ((sticky & 0x1f) << 2);
+
+ __asm("ctc1 %0,$31" : : "r" (new));
+
+ return (old >> 2) & 0x1f;
+}
diff --git a/lib/libc/mips/gen/infinity.c b/lib/libc/mips/gen/infinity.c
new file mode 100644
index 000000000000..55cf25f8e9d7
--- /dev/null
+++ b/lib/libc/mips/gen/infinity.c
@@ -0,0 +1,26 @@
+/*
+ * infinity.c
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <math.h>
+
+/* bytes for +Infinity on a 387 */
+const union __infinity_un __infinity = {
+#if BYTE_ORDER == BIG_ENDIAN
+ { 0x7f, 0xf0, 0, 0, 0, 0, 0, 0 }
+#else
+ { 0, 0, 0, 0, 0, 0, 0xf0, 0x7f }
+#endif
+};
+
+/* bytes for NaN */
+const union __nan_un __nan = {
+#if BYTE_ORDER == BIG_ENDIAN
+ {0x7f, 0xa0, 0, 0}
+#else
+ { 0, 0, 0xa0, 0x7f }
+#endif
+};
diff --git a/lib/libc/mips/gen/ldexp.S b/lib/libc/mips/gen/ldexp.S
new file mode 100644
index 000000000000..caee70380707
--- /dev/null
+++ b/lib/libc/mips/gen/ldexp.S
@@ -0,0 +1,219 @@
+/* $NetBSD: ldexp.S,v 1.8 2003/08/07 16:42:15 agc Exp $ */
+
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ralph Campbell.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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$");
+
+#if defined(LIBC_SCCS) && !defined(lint)
+ ASMSTR("from: @(#)ldexp.s 8.1 (Berkeley) 6/4/93")
+ ASMSTR("$NetBSD: ldexp.S,v 1.8 2003/08/07 16:42:15 agc Exp $")
+#endif /* LIBC_SCCS and not lint */
+
+#ifdef __ABICALLS__
+ .abicalls
+#endif
+
+#define DEXP_INF 0x7ff
+#define DEXP_BIAS 1023
+#define DEXP_MIN -1022
+#define DEXP_MAX 1023
+#define DFRAC_BITS 52
+#define DIMPL_ONE 0x00100000
+#define DLEAD_ZEROS 31 - 20
+#define STICKYBIT 1
+#define GUARDBIT 0x80000000
+#define DSIGNAL_NAN 0x00040000
+#define DQUIET_NAN0 0x0007ffff
+#define DQUIET_NAN1 0xffffffff
+
+/*
+ * double ldexp(x, N)
+ * double x; int N;
+ *
+ * Return x * (2**N), for integer values N.
+ */
+LEAF(ldexp)
+ mfc1 v1, $f13 # get MSW of x
+ mfc1 t3, $f12 # get LSW of x
+ sll t1, v1, 1 # get x exponent
+ srl t1, t1, 32 - 11
+ beq t1, DEXP_INF, 9f # is it a NAN or infinity?
+ beq t1, zero, 1f # zero or denormalized number?
+ addu t1, t1, a2 # scale exponent
+ sll v0, a2, 20 # position N for addition
+ bge t1, DEXP_INF, 8f # overflow?
+ addu v0, v0, v1 # multiply by (2**N)
+ ble t1, zero, 4f # underflow?
+ mtc1 v0, $f1 # save MSW of result
+ mtc1 t3, $f0 # save LSW of result
+ j ra
+1:
+ sll t2, v1, 32 - 20 # get x fraction
+ srl t2, t2, 32 - 20
+ srl t0, v1, 31 # get x sign
+ bne t2, zero, 1f
+ beq t3, zero, 9f # result is zero
+1:
+/*
+ * Find out how many leading zero bits are in t2,t3 and put in t9.
+ */
+ move v0, t2
+ move t9, zero
+ bne t2, zero, 1f
+ move v0, t3
+ addu t9, 32
+1:
+ srl ta0, v0, 16
+ bne ta0, zero, 1f
+ addu t9, 16
+ sll v0, 16
+1:
+ srl ta0, v0, 24
+ bne ta0, zero, 1f
+ addu t9, 8
+ sll v0, 8
+1:
+ srl ta0, v0, 28
+ bne ta0, zero, 1f
+ addu t9, 4
+ sll v0, 4
+1:
+ srl ta0, v0, 30
+ bne ta0, zero, 1f
+ addu t9, 2
+ sll v0, 2
+1:
+ srl ta0, v0, 31
+ bne ta0, zero, 1f
+ addu t9, 1
+/*
+ * Now shift t2,t3 the correct number of bits.
+ */
+1:
+ subu t9, t9, DLEAD_ZEROS # dont count normal leading zeros
+ li t1, DEXP_MIN + DEXP_BIAS
+ subu t1, t1, t9 # adjust exponent
+ addu t1, t1, a2 # scale exponent
+ li v0, 32
+ blt t9, v0, 1f
+ subu t9, t9, v0 # shift fraction left >= 32 bits
+ sll t2, t3, t9
+ move t3, zero
+ b 2f
+1:
+ subu v0, v0, t9 # shift fraction left < 32 bits
+ sll t2, t2, t9
+ srl ta0, t3, v0
+ or t2, t2, ta0
+ sll t3, t3, t9
+2:
+ bge t1, DEXP_INF, 8f # overflow?
+ ble t1, zero, 4f # underflow?
+ sll t2, t2, 32 - 20 # clear implied one bit
+ srl t2, t2, 32 - 20
+3:
+ sll t1, t1, 31 - 11 # reposition exponent
+ sll t0, t0, 31 # reposition sign
+ or t0, t0, t1 # put result back together
+ or t0, t0, t2
+ mtc1 t0, $f1 # save MSW of result
+ mtc1 t3, $f0 # save LSW of result
+ j ra
+4:
+ li v0, 0x80000000
+ ble t1, -52, 7f # is result too small for denorm?
+ sll t2, v1, 31 - 20 # clear exponent, extract fraction
+ or t2, t2, v0 # set implied one bit
+ blt t1, -30, 2f # will all bits in t3 be shifted out?
+ srl t2, t2, 31 - 20 # shift fraction back to normal position
+ subu t1, t1, 1
+ sll ta0, t2, t1 # shift right t2,t3 based on exponent
+ srl t8, t3, t1 # save bits shifted out
+ negu t1
+ srl t3, t3, t1
+ or t3, t3, ta0
+ srl t2, t2, t1
+ bge t8, zero, 1f # does result need to be rounded?
+ addu t3, t3, 1 # round result
+ sltu ta0, t3, 1
+ sll t8, t8, 1
+ addu t2, t2, ta0
+ bne t8, zero, 1f # round result to nearest
+ and t3, t3, ~1
+1:
+ mtc1 t3, $f0 # save denormalized result (LSW)
+ mtc1 t2, $f1 # save denormalized result (MSW)
+ bge v1, zero, 1f # should result be negative?
+ neg.d $f0, $f0 # negate result
+1:
+ j ra
+2:
+ mtc1 zero, $f1 # exponent and upper fraction
+ addu t1, t1, 20 # compute amount to shift right by
+ sll t8, t2, t1 # save bits shifted out
+ negu t1
+ srl t3, t2, t1
+ bge t8, zero, 1f # does result need to be rounded?
+ addu t3, t3, 1 # round result
+ sltu ta0, t3, 1
+ sll t8, t8, 1
+ mtc1 ta0, $f1 # exponent and upper fraction
+ bne t8, zero, 1f # round result to nearest
+ and t3, t3, ~1
+1:
+ mtc1 t3, $f0
+ bge v1, zero, 1f # is result negative?
+ neg.d $f0, $f0 # negate result
+1:
+ j ra
+7:
+ mtc1 zero, $f0 # result is zero
+ mtc1 zero, $f1
+ beq t0, zero, 1f # is result positive?
+ neg.d $f0, $f0 # negate result
+1:
+ j ra
+8:
+ li t1, 0x7ff00000 # result is infinity (MSW)
+ mtc1 t1, $f1
+ mtc1 zero, $f0 # result is infinity (LSW)
+ bge v1, zero, 1f # should result be negative infinity?
+ neg.d $f0, $f0 # result is negative infinity
+1:
+ add.d $f0, $f0 # cause overflow faults if enabled
+ j ra
+9:
+ mov.d $f0, $f12 # yes, result is just x
+ j ra
+END(ldexp)
diff --git a/lib/libc/mips/gen/longjmp.c b/lib/libc/mips/gen/longjmp.c
new file mode 100644
index 000000000000..7c684706c042
--- /dev/null
+++ b/lib/libc/mips/gen/longjmp.c
@@ -0,0 +1,103 @@
+/* $NetBSD: longjmp.c,v 1.1 2005/09/17 11:49:39 tsutsui Exp $ */
+
+/*-
+ * Copyright (c) 2003 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christian Limpach and Matt Thomas.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+#include "namespace.h"
+#include <sys/types.h>
+#include <ucontext.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <machine/regnum.h>
+
+void
+__longjmp14(jmp_buf env, int val)
+{
+ struct sigcontext *sc = (void *)env;
+ ucontext_t uc;
+
+ /* Ensure non-zero SP and sigcontext magic number is present */
+ if (sc->sc_regs[_R_SP] == 0 || sc->sc_regs[_R_ZERO] != 0xACEDBADE)
+ goto err;
+
+ /* Ensure non-zero return value */
+ if (val == 0)
+ val = 1;
+
+ /*
+ * Set _UC_{SET,CLR}STACK according to SS_ONSTACK.
+ *
+ * Restore the signal mask with sigprocmask() instead of _UC_SIGMASK,
+ * since libpthread may want to interpose on signal handling.
+ */
+ uc.uc_flags = _UC_CPU | (sc->sc_onstack ? _UC_SETSTACK : _UC_CLRSTACK);
+
+ sigprocmask(SIG_SETMASK, &sc->sc_mask, NULL);
+
+ /* Clear uc_link */
+ uc.uc_link = 0;
+
+ /* Save return value in context */
+ uc.uc_mcontext.__gregs[_R_V0] = val;
+
+ /* Copy saved registers */
+ uc.uc_mcontext.__gregs[_REG_S0] = sc->sc_regs[_R_S0];
+ uc.uc_mcontext.__gregs[_REG_S1] = sc->sc_regs[_R_S1];
+ uc.uc_mcontext.__gregs[_REG_S2] = sc->sc_regs[_R_S2];
+ uc.uc_mcontext.__gregs[_REG_S3] = sc->sc_regs[_R_S3];
+ uc.uc_mcontext.__gregs[_REG_S4] = sc->sc_regs[_R_S4];
+ uc.uc_mcontext.__gregs[_REG_S5] = sc->sc_regs[_R_S5];
+ uc.uc_mcontext.__gregs[_REG_S6] = sc->sc_regs[_R_S6];
+ uc.uc_mcontext.__gregs[_REG_S7] = sc->sc_regs[_R_S7];
+ uc.uc_mcontext.__gregs[_REG_S8] = sc->sc_regs[_R_S8];
+ uc.uc_mcontext.__gregs[_REG_SP] = sc->sc_regs[_R_SP];
+ uc.uc_mcontext.__gregs[_REG_RA] = sc->sc_regs[_R_RA];
+ uc.uc_mcontext.__gregs[_REG_EPC] = sc->sc_pc;
+
+ /* Copy FP state */
+ if (sc->sc_fpused) {
+ /* FP saved regs are $f20 .. $f31 */
+ memcpy(&uc.uc_mcontext.__fpregs.__fp_r.__fp_regs[20],
+ &sc->sc_fpregs[20], 32 - 20);
+ uc.uc_mcontext.__fpregs.__fp_csr =
+ sc->sc_fpregs[_R_FSR - _FPBASE];
+ /* XXX sc_fp_control */
+ uc.uc_flags |= _UC_FPU;
+ }
+
+ setcontext(&uc);
+ err:
+ longjmperror();
+ abort();
+ /* NOTREACHED */
+}
diff --git a/lib/libc/mips/gen/makecontext.c b/lib/libc/mips/gen/makecontext.c
new file mode 100644
index 000000000000..f2a826e77bdd
--- /dev/null
+++ b/lib/libc/mips/gen/makecontext.c
@@ -0,0 +1,123 @@
+/* $NetBSD: makecontext.c,v 1.5 2009/12/14 01:07:42 matt Exp $ */
+
+/*-
+ * Copyright (c) 2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Klaus Klein.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: makecontext.c,v 1.5 2009/12/14 01:07:42 matt Exp $");
+#endif
+
+#include <sys/param.h>
+#include <machine/regnum.h>
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <ucontext.h>
+
+__weak_reference(__makecontext, makecontext);
+
+void _ctx_done(ucontext_t *);
+void _ctx_start(void);
+
+void
+__makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...)
+{
+ mcontext_t *mc;
+ register_t *sp;
+ int i;
+ va_list ap;
+
+ /*
+ * XXX/juli
+ * We need an mc_len or mc_flags like other architectures
+ * so that we can mark a context as invalid. Store it in
+ * mc->mc_regs[ZERO] perhaps?
+ */
+ if (argc < 0 || argc > 6 || ucp == NULL ||
+ ucp->uc_stack.ss_sp == NULL ||
+ ucp->uc_stack.ss_size < MINSIGSTKSZ)
+ return;
+ mc = &ucp->uc_mcontext;
+
+ sp = (register_t *)
+ ((uintptr_t)ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size);
+#if defined(__mips_o32) || defined(__mips_o64)
+ sp -= (argc >= 4 ? argc : 4); /* Make room for >=4 arguments. */
+ sp = (register_t *)
+ ((uintptr_t)sp & ~0x7); /* Align on double-word boundary. */
+#elif defined(__mips_n32) || defined(__mips_n64)
+ sp -= (argc > 8 ? argc - 8 : 0); /* Make room for > 8 arguments. */
+ sp = (register_t *)
+ ((uintptr_t)sp & ~0xf); /* Align on quad-word boundary. */
+#endif
+
+ mc->mc_regs[SP] = (intptr_t)sp;
+ mc->mc_regs[S0] = (intptr_t)ucp;
+ mc->mc_regs[T9] = (intptr_t)func;
+ mc->mc_pc = (intptr_t)_ctx_start;
+
+ /* Construct argument list. */
+ va_start(ap, argc);
+#if defined(__mips_o32) || defined(__mips_o64)
+ /* Up to the first four arguments are passed in $a0-3. */
+ for (i = 0; i < argc && i < 4; i++)
+ /* LINTED register_t is safe */
+ mc->mc_regs[A0 + i] = va_arg(ap, register_t);
+ /* Pass remaining arguments on the stack above the $a0-3 gap. */
+ sp += i;
+#endif
+#if defined(__mips_n32) || defined(__mips_n64)
+ /* Up to the first 8 arguments are passed in $a0-7. */
+ for (i = 0; i < argc && i < 8; i++)
+ /* LINTED register_t is safe */
+ mc->mc_regs[A0 + i] = va_arg(ap, register_t);
+ /* Pass remaining arguments on the stack above the $a0-3 gap. */
+#endif
+ /* Pass remaining arguments on the stack above the $a0-3 gap. */
+ for (; i < argc; i++)
+ /* LINTED uintptr_t is safe */
+ *sp++ = va_arg(ap, register_t);
+ va_end(ap);
+}
+
+void
+_ctx_done(ucontext_t *ucp)
+{
+
+ if (ucp->uc_link == NULL)
+ exit(0);
+ else {
+ setcontext((const ucontext_t *)ucp->uc_link);
+ abort();
+ }
+}
diff --git a/lib/libc/mips/gen/setjmp.S b/lib/libc/mips/gen/setjmp.S
new file mode 100644
index 000000000000..9c9e8b8d9ee0
--- /dev/null
+++ b/lib/libc/mips/gen/setjmp.S
@@ -0,0 +1,238 @@
+/* $NetBSD: setjmp.S,v 1.17 2005/09/17 11:49:39 tsutsui Exp $ */
+
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ralph Campbell.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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$");
+#include <machine/regnum.h>
+
+#if defined(LIBC_SCCS) && !defined(lint)
+ ASMSTR("from: @(#)setjmp.s 8.1 (Berkeley) 6/4/93")
+ ASMSTR("$NetBSD: setjmp.S,v 1.17 2005/09/17 11:49:39 tsutsui Exp $")
+#endif /* LIBC_SCCS and not lint */
+
+#include "SYS.h"
+
+#ifdef __ABICALLS__
+ .abicalls
+#endif
+
+/*
+ * C library -- setjmp, longjmp
+ *
+ * longjmp(a,v)
+ * will generate a "return(v)" from
+ * the last call to
+ * setjmp(a)
+ * by restoring registers from the stack,
+ * and a struct sigcontext, see <signal.h>
+ */
+
+#define SETJMP_FRAME_SIZE (CALLFRAME_SIZ + (SZREG * 2))
+
+
+NESTED(setjmp, SETJMP_FRAME_SIZE, ra)
+ .mask 0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ)
+ SETUP_GP
+ PTR_SUBU sp, sp, SETJMP_FRAME_SIZE # allocate stack frame
+ SAVE_GP(CALLFRAME_GP)
+ SETUP_GP64(CALLFRAME_GP, setjmp)
+
+ REG_S ra, CALLFRAME_RA(sp) # save RA
+ REG_S a0, CALLFRAME_SIZ(sp) # store env
+
+ /* Get the signal mask. */
+ PTR_ADDU a2, a0, _JB_SIGMASK * SZREG # &oenv
+ li a0, 1 # SIG_SETBLOCK
+ move a1, zero # &env == 0
+ PTR_LA t9, _C_LABEL(sigprocmask) # get current signal mask
+ jalr t9
+
+ RESTORE_GP64
+ REG_L a0, CALLFRAME_SIZ(sp) # restore env pointer
+ REG_L ra, CALLFRAME_RA(sp) # restore RA
+ PTR_ADDU sp, sp, SETJMP_FRAME_SIZE # pop stack frame
+
+ REG_LI v0, _JB_MAGIC_SETJMP
+ REG_S v0, (_JB_MAGIC * SZREG)(a0)
+ REG_S ra, (_JB_REG_RA * SZREG)(a0)
+ /*
+ * From "MIPSpro N32 ABI Handbook", Table 2-1:
+ * Registers s0..s7 are callee-saved.
+ * The sp register is callee-saved.
+ * The fp (or s8) register is callee-saved.
+ * The gp register is callee-saved (for n32/n64).
+ */
+ REG_S s0, (_JB_REG_S0 * SZREG)(a0)
+ REG_S s1, (_JB_REG_S1 * SZREG)(a0)
+ REG_S s2, (_JB_REG_S2 * SZREG)(a0)
+ REG_S s3, (_JB_REG_S3 * SZREG)(a0)
+ REG_S s4, (_JB_REG_S4 * SZREG)(a0)
+ REG_S s5, (_JB_REG_S5 * SZREG)(a0)
+ REG_S s6, (_JB_REG_S6 * SZREG)(a0)
+ REG_S s7, (_JB_REG_S7 * SZREG)(a0)
+ REG_S sp, (_JB_REG_SP * SZREG)(a0)
+ REG_S s8, (_JB_REG_S8 * SZREG)(a0)
+#if defined(__mips_n32) || defined(__mips_n64)
+ REG_S gp, (_JB_REG_GP * SZREG)(a0)
+#endif
+#ifndef SOFTFLOAT
+ /*
+ * From "MIPSpro N32 ABI Handbook", Table 2-1:
+ * In N32, FP registers F20, F22, F24, F26, F28, F30 are callee-saved.
+ * In N64, FP registers F24 .. F31 are callee-saved.
+ * In O32, FP registers F20 .. F23 are callee-saved.
+ */
+ cfc1 v0, $31
+ INT_S v0, (_JB_FPREG_FCSR * SZREG)(a0)
+#if defined(__mips_o32) || defined(__mips_o64) || defined(__mips_n32)
+ FP_S $f20, (_JB_FPREG_F20 * SZREG)(a0)
+ FP_S $f22, (_JB_FPREG_F22 * SZREG)(a0)
+#endif
+#if defined(__mips_o32) || defined(__mips_o64)
+ FP_S $f21, (_JB_FPREG_F21 * SZREG)(a0)
+ FP_S $f23, (_JB_FPREG_F23 * SZREG)(a0)
+#endif
+#if defined(__mips_n32) || defined(__mips_n64)
+ FP_S $f24, (_JB_FPREG_F24 * SZREG)(a0)
+ FP_S $f26, (_JB_FPREG_F26 * SZREG)(a0)
+ FP_S $f28, (_JB_FPREG_F28 * SZREG)(a0)
+ FP_S $f30, (_JB_FPREG_F30 * SZREG)(a0)
+#endif
+#if defined(__mips_n64)
+ FP_S $f25, (_JB_FPREG_F25 * SZREG)(a0)
+ FP_S $f27, (_JB_FPREG_F27 * SZREG)(a0)
+ FP_S $f29, (_JB_FPREG_F29 * SZREG)(a0)
+ FP_S $f31, (_JB_FPREG_F31 * SZREG)(a0)
+#endif
+#endif /* ! SOFTFLOAT */
+
+ move v0, zero
+ jr ra
+END(setjmp)
+
+#define LONGJMP_FRAME_SIZE (CALLFRAME_SIZ + (SZREG * 2))
+
+NESTED(longjmp, LONGJMP_FRAME_SIZE, ra)
+ .mask 0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ)
+ PIC_PROLOGUE(longjmp)
+ PTR_SUBU sp, sp, LONGJMP_FRAME_SIZE # allocate stack frame
+ SAVE_GP(CALLFRAME_GP)
+
+ REG_S ra, CALLFRAME_RA(sp) # save RA
+ REG_L v0, (_JB_MAGIC * SZREG)(a0)
+ REG_LI t0, _JB_MAGIC_SETJMP
+ bne v0, t0, botch # jump if error
+ nop
+
+ REG_S a0, CALLFRAME_SIZ(sp) # save env
+ REG_S a1, (CALLFRAME_SIZ + SZREG)(sp) # save return value
+
+ # set sigmask
+ PTR_ADDU a1, a0, _JB_SIGMASK * SZREG # &set
+ move a2, zero # &oset == NULL
+ li a0, 3 # SIG_SETMASK
+ PTR_LA t9,_C_LABEL(sigprocmask) # set current signal mask
+ jal t9
+ nop
+
+ REG_L a0, CALLFRAME_SIZ(sp) # restore env
+ REG_L a1, (CALLFRAME_SIZ + SZREG)(sp) # restore return value
+
+ REG_L ra, (_JB_REG_RA * SZREG)(a0)
+ /*
+ * From "MIPSpro N32 ABI Handbook", Table 2-1:
+ * Registers s0..s7 are callee-saved.
+ * The sp register is callee-saved.
+ * The fp (or s8) register is callee-saved.
+ * The gp register is callee-saved (for n32/n64).
+ */
+ REG_L s0, (_JB_REG_S0 * SZREG)(a0)
+ REG_L s1, (_JB_REG_S1 * SZREG)(a0)
+ REG_L s2, (_JB_REG_S2 * SZREG)(a0)
+ REG_L s3, (_JB_REG_S3 * SZREG)(a0)
+ REG_L s4, (_JB_REG_S4 * SZREG)(a0)
+ REG_L s5, (_JB_REG_S5 * SZREG)(a0)
+ REG_L s6, (_JB_REG_S6 * SZREG)(a0)
+ REG_L s7, (_JB_REG_S7 * SZREG)(a0)
+ REG_L sp, (_JB_REG_SP * SZREG)(a0)
+ REG_L s8, (_JB_REG_S8 * SZREG)(a0)
+#if defined(__mips_n32) || defined(__mips_n64)
+ REG_L gp, (_JB_REG_GP * SZREG)(a0)
+#endif
+#ifndef SOFTFLOAT
+ /*
+ * From "MIPSpro N32 ABI Handbook", Table 2-1:
+ * In N32, FP registers F20, F22, F24, F26, F28, F30 are callee-saved.
+ * In N64, FP registers F23 .. F31 are callee-saved.
+ * In O32, FP registers F20 .. F23 are callee-saved.
+ */
+ INT_L v0, (_JB_FPREG_FCSR * SZREG)(a0)
+ ctc1 v0, $31
+#if defined(__mips_n64) || defined(__mips_n32)
+ FP_L $f30, (_JB_FPREG_F30 * SZREG)(a0)
+ FP_L $f28, (_JB_FPREG_F28 * SZREG)(a0)
+ FP_L $f26, (_JB_FPREG_F26 * SZREG)(a0)
+ FP_L $f24, (_JB_FPREG_F24 * SZREG)(a0)
+#endif
+#if defined(__mips_n32) || defined(__mips_o32) || defined(__mips_o64)
+ FP_L $f22, (_JB_FPREG_F22 * SZREG)(a0)
+ FP_L $f20, (_JB_FPREG_F20 * SZREG)(a0)
+#endif
+#if defined(__mips_o32) || defined(__mips_o64)
+ FP_L $f21, (_JB_FPREG_F21 * SZREG)(a0)
+ FP_L $f23, (_JB_FPREG_F23 * SZREG)(a0)
+#endif
+#if defined(__mips_n64)
+ FP_L $f25, (_JB_FPREG_F25 * SZREG)(a0)
+ FP_L $f27, (_JB_FPREG_F27 * SZREG)(a0)
+ FP_L $f29, (_JB_FPREG_F29 * SZREG)(a0)
+ FP_L $f31, (_JB_FPREG_F31 * SZREG)(a0)
+#endif
+#endif /* ! SOFTFLOAT */
+
+ move v0, a1
+ j ra
+ nop
+
+botch:
+ /*
+ * We know we aren't returning so we don't care about restoring
+ * our caller's GP.
+ */
+ PTR_LA t9, _C_LABEL(longjmperror)
+ jalr t9
+ nop
+
+ PIC_TAILCALL(abort)
+END(longjmp)
diff --git a/lib/libc/mips/gen/signalcontext.c b/lib/libc/mips/gen/signalcontext.c
new file mode 100644
index 000000000000..694468c314dd
--- /dev/null
+++ b/lib/libc/mips/gen/signalcontext.c
@@ -0,0 +1,53 @@
+/*-
+ * Copyright (c) 2004 Olivier Houchard
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/signal.h>
+#include <sys/ucontext.h>
+
+#include <machine/frame.h>
+#include <machine/sigframe.h>
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <strings.h>
+#include <signal.h>
+
+__weak_reference(__signalcontext, signalcontext);
+
+extern void _ctx_start(void);
+
+int
+__signalcontext(ucontext_t *ucp, int sig, __sighandler_t *func)
+{
+ /* XXXMIPS: Implement me */
+ return (0);
+}
diff --git a/lib/libc/mips/gen/sigsetjmp.S b/lib/libc/mips/gen/sigsetjmp.S
new file mode 100644
index 000000000000..41c47f284433
--- /dev/null
+++ b/lib/libc/mips/gen/sigsetjmp.S
@@ -0,0 +1,77 @@
+/* $NetBSD: sigsetjmp.S,v 1.8 2005/09/17 11:49:39 tsutsui Exp $ */
+
+/*-
+ * Copyright (c) 1991, 1993, 1995,
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Havard Eidnes.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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$");
+#include <machine/regnum.h>
+#if defined(LIBC_SCCS) && !defined(lint)
+ ASMSTR("from: @(#)setjmp.s 8.1 (Berkeley) 6/4/93")
+ ASMSTR("$NetBSD: sigsetjmp.S,v 1.8 2005/09/17 11:49:39 tsutsui Exp $")
+#endif /* LIBC_SCCS and not lint */
+
+#include "SYS.h"
+
+#ifdef __ABICALLS__
+ .abicalls
+#endif
+
+/*
+ * C library -- sigsetjmp, siglongjmp
+ *
+ * siglongjmp(a,v)
+ * will generate a "return(v)" from
+ * the last call to
+ * sigsetjmp(a, savemask)
+ * by restoring registers from the stack,
+ * and dependent on savemask restores the
+ * signal mask.
+ */
+
+LEAF(sigsetjmp)
+ PIC_PROLOGUE(sigsetjmp)
+
+ bne a1, zero, 1f # do saving of signal mask?
+ PIC_TAILCALL(_setjmp)
+
+1: PIC_TAILCALL(setjmp)
+END(sigsetjmp)
+
+LEAF(siglongjmp)
+ PIC_PROLOGUE(siglongjmp)
+ REG_L t0, (_JB_MAGIC * SZREG)(a0)
+ REG_LI t1, _JB_MAGIC__SETJMP
+ bne t0, t1, 1f # setjmp or _setjmp magic?
+ PIC_TAILCALL(_longjmp)
+1: PIC_TAILCALL(longjmp)
+END(siglongjmp)
diff --git a/lib/libc/mips/net/Makefile.inc b/lib/libc/mips/net/Makefile.inc
new file mode 100644
index 000000000000..304d5cac1a3e
--- /dev/null
+++ b/lib/libc/mips/net/Makefile.inc
@@ -0,0 +1,4 @@
+# $NetBSD: Makefile.inc,v 1.3 2003/08/01 17:03:51 lukem Exp $
+# $FreeBSD$
+
+SRCS+= htonl.S ntohl.S htons.S ntohs.S
diff --git a/lib/libc/mips/net/htonl.S b/lib/libc/mips/net/htonl.S
new file mode 100644
index 000000000000..66c4f90fd65f
--- /dev/null
+++ b/lib/libc/mips/net/htonl.S
@@ -0,0 +1,51 @@
+/* $NetBSD: byte_swap_4.S,v 1.2 2006/02/08 21:52:36 simonb Exp $ */
+
+/*-
+ * Copyright (c) 1997 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Neil A. Carson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+
+__FBSDID("$FreeBSD$");
+
+LEAF(htonl) # a0 = 0x11223344, return 0x44332211
+#ifdef __MIPSEB__
+ move v0, a0
+#else
+ srl v1, a0, 24 # v1 = 0x00000011
+ sll v0, a0, 24 # v0 = 0x44000000
+ or v0, v0, v1
+ and v1, a0, 0xff00
+ sll v1, v1, 8 # v1 = 0x00330000
+ or v0, v0, v1
+ srl v1, a0, 8
+ and v1, v1, 0xff00 # v1 = 0x00002200
+ or v0, v0, v1
+#endif
+ j ra
+END(htonl)
diff --git a/lib/libc/mips/net/htons.S b/lib/libc/mips/net/htons.S
new file mode 100644
index 000000000000..0449c4d82e5c
--- /dev/null
+++ b/lib/libc/mips/net/htons.S
@@ -0,0 +1,47 @@
+/* $NetBSD: byte_swap_2.S,v 1.2 2006/02/08 21:52:36 simonb Exp $ */
+
+/*-
+ * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Charles M. Hannum.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+
+__FBSDID("$FreeBSD$");
+
+LEAF(htons)
+#ifdef __MIPSEB__
+ move v0, a0
+#else
+ srl v0, a0, 8
+ and v0, v0, 0xff
+ sll v1, a0, 8
+ and v1, v1, 0xff00
+ or v0, v0, v1
+#endif
+ j ra
+END(htons)
diff --git a/lib/libc/mips/net/ntohl.S b/lib/libc/mips/net/ntohl.S
new file mode 100644
index 000000000000..39001aa86bbe
--- /dev/null
+++ b/lib/libc/mips/net/ntohl.S
@@ -0,0 +1,51 @@
+/* $NetBSD: byte_swap_4.S,v 1.2 2006/02/08 21:52:36 simonb Exp $ */
+
+/*-
+ * Copyright (c) 1997 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Neil A. Carson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+
+__FBSDID("$FreeBSD$");
+
+LEAF(ntohl) # a0 = 0x11223344, return 0x44332211
+#ifdef __MIPSEB__
+ move v0, a0
+#else
+ srl v1, a0, 24 # v1 = 0x00000011
+ sll v0, a0, 24 # v0 = 0x44000000
+ or v0, v0, v1
+ and v1, a0, 0xff00
+ sll v1, v1, 8 # v1 = 0x00330000
+ or v0, v0, v1
+ srl v1, a0, 8
+ and v1, v1, 0xff00 # v1 = 0x00002200
+ or v0, v0, v1
+#endif
+ j ra
+END(ntohl)
diff --git a/lib/libc/mips/net/ntohs.S b/lib/libc/mips/net/ntohs.S
new file mode 100644
index 000000000000..4761371be1af
--- /dev/null
+++ b/lib/libc/mips/net/ntohs.S
@@ -0,0 +1,46 @@
+/* $NetBSD: byte_swap_2.S,v 1.2 2006/02/08 21:52:36 simonb Exp $ */
+
+/*-
+ * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Charles M. Hannum.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+LEAF(ntohs)
+#ifdef __MIPSEB__
+ move v0, a0
+#else
+ srl v0, a0, 8
+ and v0, v0, 0xff
+ sll v1, a0, 8
+ and v1, v1, 0xff00
+ or v0, v0, v1
+#endif
+ j ra
+END(ntohs)
diff --git a/lib/libc/mips/softfloat/milieu.h b/lib/libc/mips/softfloat/milieu.h
new file mode 100644
index 000000000000..e04b26692113
--- /dev/null
+++ b/lib/libc/mips/softfloat/milieu.h
@@ -0,0 +1,48 @@
+/* $FreeBSD$ */
+
+/*
+===============================================================================
+
+This C header file is part of the SoftFloat IEC/IEEE Floating-point
+Arithmetic Package, Release 2a.
+
+Written by John R. Hauser. This work was made possible in part by the
+International Computer Science Institute, located at Suite 600, 1947 Center
+Street, Berkeley, California 94704. Funding was partially provided by the
+National Science Foundation under grant MIP-9311980. The original version
+of this code was written as part of a project to build a fixed-point vector
+processor in collaboration with the University of California at Berkeley,
+overseen by Profs. Nelson Morgan and John Wawrzynek. More information
+is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
+arithmetic/SoftFloat.html'.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
+has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
+TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
+PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
+AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
+
+Derivative works are acceptable, even for commercial purposes, so long as
+(1) they include prominent notice that the work is derivative, and (2) they
+include prominent notice akin to these four paragraphs for those parts of
+this code that are retained.
+
+===============================================================================
+*/
+
+/*
+-------------------------------------------------------------------------------
+Include common integer types and flags.
+-------------------------------------------------------------------------------
+*/
+#include "mips-gcc.h"
+
+/*
+-------------------------------------------------------------------------------
+Symbolic Boolean literals.
+-------------------------------------------------------------------------------
+*/
+enum {
+ FALSE = 0,
+ TRUE = 1
+};
diff --git a/lib/libc/mips/softfloat/mips-gcc.h b/lib/libc/mips/softfloat/mips-gcc.h
new file mode 100644
index 000000000000..c8ec07c839c8
--- /dev/null
+++ b/lib/libc/mips/softfloat/mips-gcc.h
@@ -0,0 +1,91 @@
+/* $NetBSD: arm-gcc.h,v 1.2 2001/02/21 18:09:25 bjh21 Exp $ */
+/* $FreeBSD$ */
+
+/*
+-------------------------------------------------------------------------------
+One of the macros `BIGENDIAN' or `LITTLEENDIAN' must be defined.
+-------------------------------------------------------------------------------
+*/
+#ifdef __MIPSEB__
+#define BIGENDIAN
+#else
+#define LITTLEENDIAN
+#endif
+
+/*
+-------------------------------------------------------------------------------
+The macro `BITS64' can be defined to indicate that 64-bit integer types are
+supported by the compiler.
+-------------------------------------------------------------------------------
+*/
+#define BITS64
+
+/*
+-------------------------------------------------------------------------------
+Each of the following `typedef's defines the most convenient type that holds
+integers of at least as many bits as specified. For example, `uint8' should
+be the most convenient type that can hold unsigned integers of as many as
+8 bits. The `flag' type must be able to hold either a 0 or 1. For most
+implementations of C, `flag', `uint8', and `int8' should all be `typedef'ed
+to the same as `int'.
+-------------------------------------------------------------------------------
+*/
+typedef int flag;
+typedef int uint8;
+typedef int int8;
+typedef int uint16;
+typedef int int16;
+typedef unsigned int uint32;
+typedef signed int int32;
+#ifdef BITS64
+typedef unsigned long long int uint64;
+typedef signed long long int int64;
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Each of the following `typedef's defines a type that holds integers
+of _exactly_ the number of bits specified. For instance, for most
+implementation of C, `bits16' and `sbits16' should be `typedef'ed to
+`unsigned short int' and `signed short int' (or `short int'), respectively.
+-------------------------------------------------------------------------------
+*/
+typedef unsigned char bits8;
+typedef signed char sbits8;
+typedef unsigned short int bits16;
+typedef signed short int sbits16;
+typedef unsigned int bits32;
+typedef signed int sbits32;
+#ifdef BITS64
+typedef unsigned long long int bits64;
+typedef signed long long int sbits64;
+#endif
+
+#ifdef BITS64
+/*
+-------------------------------------------------------------------------------
+The `LIT64' macro takes as its argument a textual integer literal and
+if necessary ``marks'' the literal as having a 64-bit integer type.
+For example, the GNU C Compiler (`gcc') requires that 64-bit literals be
+appended with the letters `LL' standing for `long long', which is `gcc's
+name for the 64-bit integer type. Some compilers may allow `LIT64' to be
+defined as the identity macro: `#define LIT64( a ) a'.
+-------------------------------------------------------------------------------
+*/
+#define LIT64( a ) a##LL
+#endif
+
+/*
+-------------------------------------------------------------------------------
+The macro `INLINE' can be used before functions that should be inlined. If
+a compiler does not support explicit inlining, this macro should be defined
+to be `static'.
+-------------------------------------------------------------------------------
+*/
+#define INLINE static __inline
+
+#if defined(SOFTFLOAT_FOR_GCC)
+/* XXXMIPS: check this one */
+#define FLOAT64_DEMANGLE(a) (a)
+#define FLOAT64_MANGLE(a) (a)
+#endif
diff --git a/lib/libc/mips/softfloat/softfloat.h b/lib/libc/mips/softfloat/softfloat.h
new file mode 100644
index 000000000000..6aef49975a38
--- /dev/null
+++ b/lib/libc/mips/softfloat/softfloat.h
@@ -0,0 +1,315 @@
+/* $NetBSD: softfloat.h,v 1.6 2002/05/12 13:12:46 bjh21 Exp $ */
+/* $FreeBSD$ */
+
+/* This is a derivative work. */
+
+/*
+===============================================================================
+
+This C header file is part of the SoftFloat IEC/IEEE Floating-point
+Arithmetic Package, Release 2a.
+
+Written by John R. Hauser. This work was made possible in part by the
+International Computer Science Institute, located at Suite 600, 1947 Center
+Street, Berkeley, California 94704. Funding was partially provided by the
+National Science Foundation under grant MIP-9311980. The original version
+of this code was written as part of a project to build a fixed-point vector
+processor in collaboration with the University of California at Berkeley,
+overseen by Profs. Nelson Morgan and John Wawrzynek. More information
+is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
+arithmetic/SoftFloat.html'.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
+has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
+TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
+PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
+AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
+
+Derivative works are acceptable, even for commercial purposes, so long as
+(1) they include prominent notice that the work is derivative, and (2) they
+include prominent notice akin to these four paragraphs for those parts of
+this code that are retained.
+
+===============================================================================
+*/
+
+/*
+-------------------------------------------------------------------------------
+The macro `FLOATX80' must be defined to enable the extended double-precision
+floating-point format `floatx80'. If this macro is not defined, the
+`floatx80' type will not be defined, and none of the functions that either
+input or output the `floatx80' type will be defined. The same applies to
+the `FLOAT128' macro and the quadruple-precision format `float128'.
+-------------------------------------------------------------------------------
+*/
+/* #define FLOATX80 */
+/* #define FLOAT128 */
+
+#include <fenv.h>
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE floating-point types.
+-------------------------------------------------------------------------------
+*/
+typedef unsigned int float32;
+typedef unsigned long long float64;
+#ifdef FLOATX80
+typedef struct {
+ unsigned short high;
+ unsigned long long low;
+} floatx80;
+#endif
+#ifdef FLOAT128
+typedef struct {
+ unsigned long long high, low;
+} float128;
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE floating-point underflow tininess-detection mode.
+-------------------------------------------------------------------------------
+*/
+#ifndef SOFTFLOAT_FOR_GCC
+extern int float_detect_tininess;
+#endif
+enum {
+ float_tininess_after_rounding = 0,
+ float_tininess_before_rounding = 1
+};
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE floating-point rounding mode.
+-------------------------------------------------------------------------------
+*/
+extern int float_rounding_mode;
+enum {
+ float_round_nearest_even = FE_TONEAREST,
+ float_round_to_zero = FE_TOWARDZERO,
+ float_round_down = FE_DOWNWARD,
+ float_round_up = FE_UPWARD
+};
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE floating-point exception flags.
+-------------------------------------------------------------------------------
+*/
+extern int float_exception_flags;
+extern int float_exception_mask;
+enum {
+ float_flag_inexact = FE_INEXACT,
+ float_flag_underflow = FE_UNDERFLOW,
+ float_flag_overflow = FE_OVERFLOW,
+ float_flag_divbyzero = FE_DIVBYZERO,
+ float_flag_invalid = FE_INVALID
+};
+
+/*
+-------------------------------------------------------------------------------
+Routine to raise any or all of the software IEC/IEEE floating-point
+exception flags.
+-------------------------------------------------------------------------------
+*/
+void float_raise( int );
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE integer-to-floating-point conversion routines.
+-------------------------------------------------------------------------------
+*/
+float32 int32_to_float32( int );
+float64 int32_to_float64( int );
+#ifdef FLOATX80
+floatx80 int32_to_floatx80( int );
+#endif
+#ifdef FLOAT128
+float128 int32_to_float128( int );
+#endif
+#ifndef SOFTFLOAT_FOR_GCC /* __floatdi?f is in libgcc2.c */
+float32 int64_to_float32( long long );
+float64 int64_to_float64( long long );
+#ifdef FLOATX80
+floatx80 int64_to_floatx80( long long );
+#endif
+#ifdef FLOAT128
+float128 int64_to_float128( long long );
+#endif
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE single-precision conversion routines.
+-------------------------------------------------------------------------------
+*/
+int float32_to_int32( float32 );
+int float32_to_int32_round_to_zero( float32 );
+#if defined(SOFTFLOAT_FOR_GCC) && defined(SOFTFLOAT_NEED_FIXUNS)
+unsigned int float32_to_uint32_round_to_zero( float32 );
+#endif
+#ifndef SOFTFLOAT_FOR_GCC /* __fix?fdi provided by libgcc2.c */
+long long float32_to_int64( float32 );
+long long float32_to_int64_round_to_zero( float32 );
+#endif
+float64 float32_to_float64( float32 );
+#ifdef FLOATX80
+floatx80 float32_to_floatx80( float32 );
+#endif
+#ifdef FLOAT128
+float128 float32_to_float128( float32 );
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE single-precision operations.
+-------------------------------------------------------------------------------
+*/
+float32 float32_round_to_int( float32 );
+float32 float32_add( float32, float32 );
+float32 float32_sub( float32, float32 );
+float32 float32_mul( float32, float32 );
+float32 float32_div( float32, float32 );
+float32 float32_rem( float32, float32 );
+float32 float32_sqrt( float32 );
+int float32_eq( float32, float32 );
+int float32_le( float32, float32 );
+int float32_lt( float32, float32 );
+int float32_eq_signaling( float32, float32 );
+int float32_le_quiet( float32, float32 );
+int float32_lt_quiet( float32, float32 );
+#ifndef SOFTFLOAT_FOR_GCC
+int float32_is_signaling_nan( float32 );
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE double-precision conversion routines.
+-------------------------------------------------------------------------------
+*/
+int float64_to_int32( float64 );
+int float64_to_int32_round_to_zero( float64 );
+#if defined(SOFTFLOAT_FOR_GCC) && defined(SOFTFLOAT_NEED_FIXUNS)
+unsigned int float64_to_uint32_round_to_zero( float64 );
+#endif
+#ifndef SOFTFLOAT_FOR_GCC /* __fix?fdi provided by libgcc2.c */
+long long float64_to_int64( float64 );
+long long float64_to_int64_round_to_zero( float64 );
+#endif
+float32 float64_to_float32( float64 );
+#ifdef FLOATX80
+floatx80 float64_to_floatx80( float64 );
+#endif
+#ifdef FLOAT128
+float128 float64_to_float128( float64 );
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE double-precision operations.
+-------------------------------------------------------------------------------
+*/
+float64 float64_round_to_int( float64 );
+float64 float64_add( float64, float64 );
+float64 float64_sub( float64, float64 );
+float64 float64_mul( float64, float64 );
+float64 float64_div( float64, float64 );
+float64 float64_rem( float64, float64 );
+float64 float64_sqrt( float64 );
+int float64_eq( float64, float64 );
+int float64_le( float64, float64 );
+int float64_lt( float64, float64 );
+int float64_eq_signaling( float64, float64 );
+int float64_le_quiet( float64, float64 );
+int float64_lt_quiet( float64, float64 );
+#ifndef SOFTFLOAT_FOR_GCC
+int float64_is_signaling_nan( float64 );
+#endif
+
+#ifdef FLOATX80
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE extended double-precision conversion routines.
+-------------------------------------------------------------------------------
+*/
+int floatx80_to_int32( floatx80 );
+int floatx80_to_int32_round_to_zero( floatx80 );
+long long floatx80_to_int64( floatx80 );
+long long floatx80_to_int64_round_to_zero( floatx80 );
+float32 floatx80_to_float32( floatx80 );
+float64 floatx80_to_float64( floatx80 );
+#ifdef FLOAT128
+float128 floatx80_to_float128( floatx80 );
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE extended double-precision rounding precision. Valid
+values are 32, 64, and 80.
+-------------------------------------------------------------------------------
+*/
+extern int floatx80_rounding_precision;
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE extended double-precision operations.
+-------------------------------------------------------------------------------
+*/
+floatx80 floatx80_round_to_int( floatx80 );
+floatx80 floatx80_add( floatx80, floatx80 );
+floatx80 floatx80_sub( floatx80, floatx80 );
+floatx80 floatx80_mul( floatx80, floatx80 );
+floatx80 floatx80_div( floatx80, floatx80 );
+floatx80 floatx80_rem( floatx80, floatx80 );
+floatx80 floatx80_sqrt( floatx80 );
+int floatx80_eq( floatx80, floatx80 );
+int floatx80_le( floatx80, floatx80 );
+int floatx80_lt( floatx80, floatx80 );
+int floatx80_eq_signaling( floatx80, floatx80 );
+int floatx80_le_quiet( floatx80, floatx80 );
+int floatx80_lt_quiet( floatx80, floatx80 );
+int floatx80_is_signaling_nan( floatx80 );
+
+#endif
+
+#ifdef FLOAT128
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE quadruple-precision conversion routines.
+-------------------------------------------------------------------------------
+*/
+int float128_to_int32( float128 );
+int float128_to_int32_round_to_zero( float128 );
+long long float128_to_int64( float128 );
+long long float128_to_int64_round_to_zero( float128 );
+float32 float128_to_float32( float128 );
+float64 float128_to_float64( float128 );
+#ifdef FLOATX80
+floatx80 float128_to_floatx80( float128 );
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE quadruple-precision operations.
+-------------------------------------------------------------------------------
+*/
+float128 float128_round_to_int( float128 );
+float128 float128_add( float128, float128 );
+float128 float128_sub( float128, float128 );
+float128 float128_mul( float128, float128 );
+float128 float128_div( float128, float128 );
+float128 float128_rem( float128, float128 );
+float128 float128_sqrt( float128 );
+int float128_eq( float128, float128 );
+int float128_le( float128, float128 );
+int float128_lt( float128, float128 );
+int float128_eq_signaling( float128, float128 );
+int float128_le_quiet( float128, float128 );
+int float128_lt_quiet( float128, float128 );
+int float128_is_signaling_nan( float128 );
+
+#endif
+
diff --git a/lib/libc/mips/string/Makefile.inc b/lib/libc/mips/string/Makefile.inc
new file mode 100644
index 000000000000..f37b9af51efb
--- /dev/null
+++ b/lib/libc/mips/string/Makefile.inc
@@ -0,0 +1,8 @@
+# $NetBSD: Makefile.inc,v 1.2 2000/10/10 21:51:54 jeffs Exp $
+# $FreeBSD$
+
+SRCS+= bcmp.S bcopy.S bzero.S ffs.S memchr.c memcmp.c memset.c \
+ memcpy.S memmove.S \
+ strcat.c strchr.S strcmp.S strcpy.c strcspn.c strlen.S \
+ strncat.c strncmp.c strncpy.c strrchr.S strpbrk.c strsep.c \
+ strspn.c strstr.c swab.c
diff --git a/lib/libc/mips/string/bcmp.S b/lib/libc/mips/string/bcmp.S
new file mode 100644
index 000000000000..ffcaeeb1a3fa
--- /dev/null
+++ b/lib/libc/mips/string/bcmp.S
@@ -0,0 +1,130 @@
+/* $NetBSD: bcmp.S,v 1.9 2009/12/14 01:07:42 matt Exp $ */
+
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ralph Campbell.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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 _LOCORE /* XXX not really, just assembly-code source */
+#include <machine/endian.h> /* LWLO/LWHI, SWLO/SWHI */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+ ASMSTR("from: @(#)bcmp.s 8.1 (Berkeley) 6/4/93")
+#else
+ ASMSTR("$NetBSD: bcmp.S,v 1.9 2009/12/14 01:07:42 matt Exp $")
+#endif
+#endif /* LIBC_SCCS and not lint */
+
+#ifdef __ABICALLS__
+ .abicalls
+#endif
+
+/* bcmp(s1, s2, n) */
+
+
+LEAF(bcmp)
+ .set noreorder
+ blt a2, 16, small # is it worth any trouble?
+ xor v0, a0, a1 # compare low two bits of addresses
+ and v0, v0, 3
+ PTR_SUBU a3, zero, a1 # compute # bytes to word align address
+ bne v0, zero, unaligned # not possible to align addresses
+ and a3, a3, 3
+
+ beq a3, zero, 1f
+ PTR_SUBU a2, a2, a3 # subtract from remaining count
+ move v0, v1 # init v0,v1 so unmodified bytes match
+ LWHI v0, 0(a0) # read 1, 2, or 3 bytes
+ LWHI v1, 0(a1)
+ PTR_ADDU a1, a1, a3
+ bne v0, v1, nomatch
+ PTR_ADDU a0, a0, a3
+1:
+ and a3, a2, ~3 # compute number of whole words left
+ PTR_SUBU a2, a2, a3 # which has to be >= (16-3) & ~3
+ PTR_ADDU a3, a3, a0 # compute ending address
+2:
+ lw v0, 0(a0) # compare words
+ lw v1, 0(a1)
+ PTR_ADDU a0, a0, 4
+ bne v0, v1, nomatch
+ PTR_ADDU a1, a1, 4
+ bne a0, a3, 2b
+ nop
+ b small # finish remainder
+ nop
+unaligned:
+ beq a3, zero, 2f
+ PTR_SUBU a2, a2, a3 # subtract from remaining count
+ PTR_ADDU a3, a3, a0 # compute ending address
+1:
+ lbu v0, 0(a0) # compare bytes until a1 word aligned
+ lbu v1, 0(a1)
+ PTR_ADDU a0, a0, 1
+ bne v0, v1, nomatch
+ PTR_ADDU a1, a1, 1
+ bne a0, a3, 1b
+ nop
+2:
+ and a3, a2, ~3 # compute number of whole words left
+ PTR_SUBU a2, a2, a3 # which has to be >= (16-3) & ~3
+ PTR_ADDU a3, a3, a0 # compute ending address
+3:
+ LWHI v0, 0(a0) # compare words a0 unaligned, a1 aligned
+ LWLO v0, 3(a0)
+ lw v1, 0(a1)
+ PTR_ADDU a0, a0, 4
+ bne v0, v1, nomatch
+ PTR_ADDU a1, a1, 4
+ bne a0, a3, 3b
+ nop
+small:
+ ble a2, zero, match
+ PTR_ADDU a3, a2, a0 # compute ending address
+1:
+ lbu v0, 0(a0)
+ lbu v1, 0(a1)
+ PTR_ADDU a0, a0, 1
+ bne v0, v1, nomatch
+ PTR_ADDU a1, a1, 1
+ bne a0, a3, 1b
+ nop
+match:
+ j ra
+ move v0, zero
+nomatch:
+ j ra
+ li v0, 1
+ .set reorder
+END(bcmp)
diff --git a/lib/libc/mips/string/bcopy.S b/lib/libc/mips/string/bcopy.S
new file mode 100644
index 000000000000..bc227e07d662
--- /dev/null
+++ b/lib/libc/mips/string/bcopy.S
@@ -0,0 +1,297 @@
+/* $NetBSD: bcopy.S,v 1.3 2009/12/14 00:39:00 matt Exp $ */
+
+/*
+ * Mach Operating System
+ * Copyright (c) 1993 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+/*
+ * File: mips_bcopy.s
+ * Author: Chris Maeda
+ * Date: June 1993
+ *
+ * Fast copy routine. Derived from aligned_block_copy.
+ */
+
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#define _LOCORE /* XXX not really, just assembly-code source */
+#include <machine/endian.h>
+
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+ ASMSTR("from: @(#)mips_bcopy.s 2.2 CMU 18/06/93")
+#else
+ ASMSTR("$NetBSD: bcopy.S,v 1.3 2009/12/14 00:39:00 matt Exp $")
+#endif
+#endif /* LIBC_SCCS and not lint */
+
+#ifdef __ABICALLS__
+ .abicalls
+#endif
+
+/*
+ * bcopy(caddr_t src, caddr_t dst, unsigned int len)
+ *
+ * a0 src address
+ * a1 dst address
+ * a2 length
+ */
+
+#if defined(MEMCOPY) || defined(MEMMOVE)
+#ifdef MEMCOPY
+#define FUNCTION memcpy
+#else
+#define FUNCTION memmove
+#endif
+#define SRCREG a1
+#define DSTREG a0
+#else
+#define FUNCTION bcopy
+#define SRCREG a0
+#define DSTREG a1
+#endif
+
+#define SIZEREG a2
+
+LEAF(FUNCTION)
+ .set noat
+ .set noreorder
+
+#if defined(MEMCOPY) || defined(MEMMOVE)
+ /* set up return value, while we still can */
+ move v0,DSTREG
+#endif
+ /*
+ * Make sure we can copy forwards.
+ */
+ sltu t0,SRCREG,DSTREG # t0 == SRCREG < DSTREG
+ bne t0,zero,6f # copy backwards
+
+ /*
+ * There are four alignment cases (with frequency)
+ * (Based on measurements taken with a DECstation 5000/200
+ * inside a Mach kernel.)
+ *
+ * aligned -> aligned (mostly)
+ * unaligned -> aligned (sometimes)
+ * aligned,unaligned -> unaligned (almost never)
+ *
+ * Note that we could add another case that checks if
+ * the destination and source are unaligned but the
+ * copy is alignable. eg if src and dest are both
+ * on a halfword boundary.
+ */
+ andi t1,DSTREG,(SZREG-1) # get last bits of dest
+ bne t1,zero,3f # dest unaligned
+ andi t0,SRCREG,(SZREG-1) # get last bits of src
+ bne t0,zero,5f
+
+ /*
+ * Forward aligned->aligned copy, 8 words at a time.
+ */
+98:
+ li AT,-(SZREG*8)
+ and t0,SIZEREG,AT # count truncated to multiples
+ PTR_ADDU a3,SRCREG,t0 # run fast loop up to this addr
+ sltu AT,SRCREG,a3 # any work to do?
+ beq AT,zero,2f
+ PTR_SUBU SIZEREG,t0
+
+ /*
+ * loop body
+ */
+1: # cp
+ REG_L t3,(0*SZREG)(SRCREG)
+ REG_L v1,(1*SZREG)(SRCREG)
+ REG_L t0,(2*SZREG)(SRCREG)
+ REG_L t1,(3*SZREG)(SRCREG)
+ PTR_ADDU SRCREG,SZREG*8
+ REG_S t3,(0*SZREG)(DSTREG)
+ REG_S v1,(1*SZREG)(DSTREG)
+ REG_S t0,(2*SZREG)(DSTREG)
+ REG_S t1,(3*SZREG)(DSTREG)
+ REG_L t1,(-1*SZREG)(SRCREG)
+ REG_L t0,(-2*SZREG)(SRCREG)
+ REG_L v1,(-3*SZREG)(SRCREG)
+ REG_L t3,(-4*SZREG)(SRCREG)
+ PTR_ADDU DSTREG,SZREG*8
+ REG_S t1,(-1*SZREG)(DSTREG)
+ REG_S t0,(-2*SZREG)(DSTREG)
+ REG_S v1,(-3*SZREG)(DSTREG)
+ bne SRCREG,a3,1b
+ REG_S t3,(-4*SZREG)(DSTREG)
+
+ /*
+ * Copy a word at a time, no loop unrolling.
+ */
+2: # wordcopy
+ andi t2,SIZEREG,(SZREG-1) # get byte count / SZREG
+ PTR_SUBU t2,SIZEREG,t2 # t2 = words to copy * SZREG
+ beq t2,zero,3f
+ PTR_ADDU t0,SRCREG,t2 # stop at t0
+ PTR_SUBU SIZEREG,SIZEREG,t2
+1:
+ REG_L t3,0(SRCREG)
+ PTR_ADDU SRCREG,SZREG
+ REG_S t3,0(DSTREG)
+ bne SRCREG,t0,1b
+ PTR_ADDU DSTREG,SZREG
+
+3: # bytecopy
+ beq SIZEREG,zero,4f # nothing left to do?
+ nop
+1:
+ lb t3,0(SRCREG)
+ PTR_ADDU SRCREG,1
+ sb t3,0(DSTREG)
+ PTR_SUBU SIZEREG,1
+ bgtz SIZEREG,1b
+ PTR_ADDU DSTREG,1
+
+4: # copydone
+ j ra
+ nop
+
+ /*
+ * Copy from unaligned source to aligned dest.
+ */
+5: # destaligned
+ andi t0,SIZEREG,(SZREG-1) # t0 = bytecount mod SZREG
+ PTR_SUBU a3,SIZEREG,t0 # number of words to transfer
+ beq a3,zero,3b
+ nop
+ move SIZEREG,t0 # this many to do after we are done
+ PTR_ADDU a3,SRCREG,a3 # stop point
+
+1:
+ REG_LHI t3,0(SRCREG)
+ REG_LLO t3,SZREG-1(SRCREG)
+ PTR_ADDI SRCREG,SZREG
+ REG_S t3,0(DSTREG)
+ bne SRCREG,a3,1b
+ PTR_ADDI DSTREG,SZREG
+
+ b 3b
+ nop
+
+6: # backcopy -- based on above
+ PTR_ADDU SRCREG,SIZEREG
+ PTR_ADDU DSTREG,SIZEREG
+ andi t1,DSTREG,SZREG-1 # get last 3 bits of dest
+ bne t1,zero,3f
+ andi t0,SRCREG,SZREG-1 # get last 3 bits of src
+ bne t0,zero,5f
+
+ /*
+ * Forward aligned->aligned copy, 8*4 bytes at a time.
+ */
+ li AT,(-8*SZREG)
+ and t0,SIZEREG,AT # count truncated to multiple of 32
+ beq t0,zero,2f # any work to do?
+ PTR_SUBU SIZEREG,t0
+ PTR_SUBU a3,SRCREG,t0
+
+ /*
+ * loop body
+ */
+1: # cp
+ REG_L t3,(-4*SZREG)(SRCREG)
+ REG_L v1,(-3*SZREG)(SRCREG)
+ REG_L t0,(-2*SZREG)(SRCREG)
+ REG_L t1,(-1*SZREG)(SRCREG)
+ PTR_SUBU SRCREG,8*SZREG
+ REG_S t3,(-4*SZREG)(DSTREG)
+ REG_S v1,(-3*SZREG)(DSTREG)
+ REG_S t0,(-2*SZREG)(DSTREG)
+ REG_S t1,(-1*SZREG)(DSTREG)
+ REG_L t1,(3*SZREG)(SRCREG)
+ REG_L t0,(2*SZREG)(SRCREG)
+ REG_L v1,(1*SZREG)(SRCREG)
+ REG_L t3,(0*SZREG)(SRCREG)
+ PTR_SUBU DSTREG,8*SZREG
+ REG_S t1,(3*SZREG)(DSTREG)
+ REG_S t0,(2*SZREG)(DSTREG)
+ REG_S v1,(1*SZREG)(DSTREG)
+ bne SRCREG,a3,1b
+ REG_S t3,(0*SZREG)(DSTREG)
+
+ /*
+ * Copy a word at a time, no loop unrolling.
+ */
+2: # wordcopy
+ andi t2,SIZEREG,SZREG-1 # get byte count / 4
+ PTR_SUBU t2,SIZEREG,t2 # t2 = number of words to copy
+ beq t2,zero,3f
+ PTR_SUBU t0,SRCREG,t2 # stop at t0
+ PTR_SUBU SIZEREG,SIZEREG,t2
+1:
+ REG_L t3,-SZREG(SRCREG)
+ PTR_SUBU SRCREG,SZREG
+ REG_S t3,-SZREG(DSTREG)
+ bne SRCREG,t0,1b
+ PTR_SUBU DSTREG,SZREG
+
+3: # bytecopy
+ beq SIZEREG,zero,4f # nothing left to do?
+ nop
+1:
+ lb t3,-1(SRCREG)
+ PTR_SUBU SRCREG,1
+ sb t3,-1(DSTREG)
+ PTR_SUBU SIZEREG,1
+ bgtz SIZEREG,1b
+ PTR_SUBU DSTREG,1
+
+4: # copydone
+ j ra
+ nop
+
+ /*
+ * Copy from unaligned source to aligned dest.
+ */
+5: # destaligned
+ andi t0,SIZEREG,SZREG-1 # t0 = bytecount mod 4
+ PTR_SUBU a3,SIZEREG,t0 # number of words to transfer
+ beq a3,zero,3b
+ nop
+ move SIZEREG,t0 # this many to do after we are done
+ PTR_SUBU a3,SRCREG,a3 # stop point
+
+1:
+ REG_LHI t3,-SZREG(SRCREG)
+ REG_LLO t3,-1(SRCREG)
+ PTR_SUBU SRCREG,SZREG
+ REG_S t3,-SZREG(DSTREG)
+ bne SRCREG,a3,1b
+ PTR_SUBU DSTREG,SZREG
+
+ b 3b
+ nop
+
+ .set reorder
+ .set at
+ END(FUNCTION)
diff --git a/lib/libc/mips/string/bzero.S b/lib/libc/mips/string/bzero.S
new file mode 100644
index 000000000000..83e54ba4baea
--- /dev/null
+++ b/lib/libc/mips/string/bzero.S
@@ -0,0 +1,83 @@
+/* $NetBSD: bzero.S,v 1.10 2009/12/14 02:53:52 matt Exp $ */
+
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ralph Campbell.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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$");
+
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+ ASMSTR("from: @(#)bzero.s 8.1 (Berkeley) 6/4/93")
+#else
+ ASMSTR("$NetBSD: bzero.S,v 1.10 2009/12/14 02:53:52 matt Exp $")
+#endif
+#endif /* LIBC_SCCS and not lint */
+
+#define _LOCORE /* XXX not really, just assembly-code source */
+#include <machine/endian.h>
+
+#ifdef __ABICALLS__
+ .abicalls
+#endif
+
+/* bzero(s1, n) */
+
+LEAF(bzero)
+ .set noreorder
+ blt a1, 3*SZREG, smallclr # small amount to clear?
+ PTR_SUBU a3, zero, a0 # compute # bytes to word align address
+ and a3, a3, SZREG-1
+ beq a3, zero, 1f # skip if word aligned
+ PTR_SUBU a1, a1, a3 # subtract from remaining count
+ REG_SHI zero, 0(a0) # clear 1, 2, or 3 bytes to align
+ PTR_ADDU a0, a0, a3
+1:
+ and v0, a1, SZREG-1 # compute number of words left
+ PTR_SUBU a3, a1, v0
+ move a1, v0
+ PTR_ADDU a3, a3, a0 # compute ending address
+2:
+ PTR_ADDU a0, a0, SZREG # clear words
+ bne a0, a3, 2b # unrolling loop doesnt help
+ REG_S zero, -SZREG(a0) # since we are limited by memory speed
+smallclr:
+ ble a1, zero, 2f
+ PTR_ADDU a3, a1, a0 # compute ending address
+1:
+ PTR_ADDU a0, a0, 1 # clear bytes
+ bne a0, a3, 1b
+ sb zero, -1(a0)
+2:
+ j ra
+ nop
+END(bzero)
diff --git a/lib/libc/mips/string/ffs.S b/lib/libc/mips/string/ffs.S
new file mode 100644
index 000000000000..17e509c24637
--- /dev/null
+++ b/lib/libc/mips/string/ffs.S
@@ -0,0 +1,59 @@
+/* $NetBSD: ffs.S,v 1.2 2009/12/14 00:39:00 matt Exp $ */
+
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ralph Campbell.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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$");
+
+#if defined(LIBC_SCCS) && !defined(lint)
+ ASMSTR("from: @(#)ffs.s 8.1 (Berkeley) 6/4/93")
+ ASMSTR("$NetBSD: ffs.S,v 1.2 2009/12/14 00:39:00 matt Exp $")
+#endif /* LIBC_SCCS and not lint */
+
+#ifdef __ABICALLS__
+ .abicalls
+#endif
+
+/* bit = ffs(value) */
+
+LEAF(ffs)
+ move v0, zero
+ beq a0, zero, done
+1:
+ and v1, a0, 1 # bit set?
+ addu v0, v0, 1
+ srl a0, a0, 1
+ beq v1, zero, 1b # no, continue
+done:
+ j ra
+END(ffs)
diff --git a/lib/libc/mips/string/memcpy.S b/lib/libc/mips/string/memcpy.S
new file mode 100644
index 000000000000..8d3c0dbfcf2c
--- /dev/null
+++ b/lib/libc/mips/string/memcpy.S
@@ -0,0 +1,7 @@
+/* $NetBSD: memcpy.S,v 1.1 2005/12/20 19:28:50 christos Exp $ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#define MEMCOPY
+#include "bcopy.S"
diff --git a/lib/libc/mips/string/memmove.S b/lib/libc/mips/string/memmove.S
new file mode 100644
index 000000000000..29d9e707ee46
--- /dev/null
+++ b/lib/libc/mips/string/memmove.S
@@ -0,0 +1,7 @@
+/* $NetBSD: memmove.S,v 1.1 2005/12/20 19:28:50 christos Exp $ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#define MEMMOVE
+#include "bcopy.S"
diff --git a/lib/libc/mips/string/strchr.S b/lib/libc/mips/string/strchr.S
new file mode 100644
index 000000000000..19dae58415e2
--- /dev/null
+++ b/lib/libc/mips/string/strchr.S
@@ -0,0 +1,66 @@
+/* $NetBSD: index.S,v 1.8 2005/04/22 06:59:00 simonb Exp $ */
+
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ralph Campbell.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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$");
+
+#if defined(LIBC_SCCS) && !defined(lint)
+ ASMSTR("from: @(#)index.s 8.1 (Berkeley) 6/4/93")
+ ASMSTR("$NetBSD: index.S,v 1.8 2005/04/22 06:59:00 simonb Exp $")
+#endif /* LIBC_SCCS and not lint */
+
+#ifdef __ABICALLS__
+ .abicalls
+#endif
+
+/*
+ * char *
+ * strchr(const char *s, int c);
+ */
+LEAF(strchr)
+ and a1, a1, 0xff
+1:
+ lbu a2, 0(a0) # get a byte
+ PTR_ADDU a0, a0, 1
+ beq a2, a1, fnd
+ bne a2, zero, 1b
+notfnd:
+ move v0, zero
+ j ra
+fnd:
+ PTR_SUBU v0, a0, 1
+ j ra
+END(strchr)
+
+WEAK_ALIAS(index, strchr)
diff --git a/lib/libc/mips/string/strcmp.S b/lib/libc/mips/string/strcmp.S
new file mode 100644
index 000000000000..8a9905630ce8
--- /dev/null
+++ b/lib/libc/mips/string/strcmp.S
@@ -0,0 +1,68 @@
+/* $NetBSD: strcmp.S,v 1.2 2009/12/14 00:39:00 matt Exp $ */
+
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ralph Campbell.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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$");
+
+#if defined(LIBC_SCCS) && !defined(lint)
+ ASMSTR("from: @(#)strcmp.s 8.1 (Berkeley) 6/4/93")
+ ASMSTR("$NetBSD: strcmp.S,v 1.2 2009/12/14 00:39:00 matt Exp $")
+#endif /* LIBC_SCCS and not lint */
+
+#ifdef __ABICALLS__
+ .abicalls
+#endif
+
+/*
+ * NOTE: this version assumes unsigned chars in order to be "8 bit clean".
+ */
+LEAF(strcmp)
+1:
+ lbu t0, 0(a0) # get two bytes and compare them
+ lbu t1, 0(a1)
+ beq t0, zero, LessOrEq # end of first string?
+ bne t0, t1, NotEq
+ lbu t0, 1(a0) # unroll loop
+ lbu t1, 1(a1)
+ PTR_ADD a0, a0, 2
+ beq t0, zero, LessOrEq # end of first string?
+ PTR_ADD a1, a1, 2
+ beq t0, t1, 1b
+NotEq:
+ subu v0, t0, t1
+ j ra
+LessOrEq:
+ subu v0, zero, t1
+ j ra
+END(strcmp)
diff --git a/lib/libc/mips/string/strlen.S b/lib/libc/mips/string/strlen.S
new file mode 100644
index 000000000000..3b46ccceb54b
--- /dev/null
+++ b/lib/libc/mips/string/strlen.S
@@ -0,0 +1,55 @@
+/* $NetBSD: strlen.S,v 1.2 2009/12/14 00:39:00 matt Exp $ */
+
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ralph Campbell.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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$");
+
+#if defined(LIBC_SCCS) && !defined(lint)
+ ASMSTR("from: @(#)strlen.s 8.1 (Berkeley) 6/4/93")
+ ASMSTR("$NetBSD: strlen.S,v 1.2 2009/12/14 00:39:00 matt Exp $")
+#endif /* LIBC_SCCS and not lint */
+
+#ifdef __ABICALLS__
+ .abicalls
+#endif
+
+LEAF(strlen)
+ PTR_ADDU v1, a0, 1
+1:
+ lb v0, 0(a0) # get byte from string
+ PTR_ADDU a0, a0, 1 # increment pointer
+ bne v0, zero, 1b # continue if not end
+ PTR_SUBU v0, a0, v1 # compute length - 1 for '\0' char
+ j ra
+END(strlen)
diff --git a/lib/libc/mips/string/strrchr.S b/lib/libc/mips/string/strrchr.S
new file mode 100644
index 000000000000..c0dcef049d6e
--- /dev/null
+++ b/lib/libc/mips/string/strrchr.S
@@ -0,0 +1,64 @@
+/* $NetBSD: rindex.S,v 1.7 2003/08/07 16:42:16 agc Exp $ */
+
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ralph Campbell.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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$");
+
+#if defined(LIBC_SCCS) && !defined(lint)
+ ASMSTR("from: @(#)rindex.s 8.1 (Berkeley) 6/4/93")
+ ASMSTR("$NetBSD: rindex.S,v 1.7 2003/08/07 16:42:16 agc Exp $")
+#endif /* LIBC_SCCS and not lint */
+
+#ifdef __ABICALLS__
+ .abicalls
+#endif
+
+/*
+ * char *
+ * strrchr(const char *s, int c);
+ */
+LEAF(strrchr)
+ move v0, zero # default if not found
+ and a1, a1, 0xff
+1:
+ lbu a3, 0(a0) # get a byte
+ PTR_ADDU a0, a0, 1
+ bne a3, a1, 2f
+ PTR_SUBU v0, a0, 1 # save address of last match
+2:
+ bne a3, zero, 1b # continue if not end
+ j ra
+END(strrchr)
+
+WEAK_ALIAS(rindex, strrchr)
diff --git a/lib/libc/mips/sys/Makefile.inc b/lib/libc/mips/sys/Makefile.inc
new file mode 100644
index 000000000000..f8af45378b90
--- /dev/null
+++ b/lib/libc/mips/sys/Makefile.inc
@@ -0,0 +1,9 @@
+# $FreeBSD$
+
+SRCS+= trivial-vdso_tc.c
+
+MDASM= Ovfork.S brk.S cerror.S exect.S \
+ sbrk.S syscall.S
+
+# Don't generate default code for these syscalls:
+NOASM+= vfork.o
diff --git a/lib/libc/mips/sys/Ovfork.S b/lib/libc/mips/sys/Ovfork.S
new file mode 100644
index 000000000000..9df93ea59e9d
--- /dev/null
+++ b/lib/libc/mips/sys/Ovfork.S
@@ -0,0 +1,64 @@
+/* $NetBSD: compat_Ovfork.S,v 1.1 2005/09/17 11:49:39 tsutsui Exp $ */
+
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ralph Campbell.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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$");
+#include "SYS.h"
+
+#if defined(LIBC_SCCS) && !defined(lint)
+ ASMSTR("from: @(#)Ovfork.s 8.1 (Berkeley) 6/4/93")
+ ASMSTR("$NetBSD: compat_Ovfork.S,v 1.1 2005/09/17 11:49:39 tsutsui Exp $")
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * pid = vfork();
+ *
+ * v1 == 0 in parent process, v1 == 1 in child process.
+ * v0 == pid of child in parent, v0 == pid of parent in child.
+ */
+
+LEAF(__sys_vfork)
+ WEAK_ALIAS(vfork, __sys_vfork)
+ WEAK_ALIAS(_vfork, __sys_vfork)
+ PIC_PROLOGUE(__sys_vfork)
+ li v0, SYS_vfork # system call number for vfork
+ syscall
+ beq a3, zero, 1f # jump if no errors
+ PIC_TAILCALL(__cerror)
+1:
+ beq v1, zero, 2f # parent process ?
+ move v0, zero # return zero in child
+2:
+ PIC_RETURN()
+END(__sys_vfork)
diff --git a/lib/libc/mips/sys/brk.S b/lib/libc/mips/sys/brk.S
new file mode 100644
index 000000000000..68f0bd45b32a
--- /dev/null
+++ b/lib/libc/mips/sys/brk.S
@@ -0,0 +1,71 @@
+/* $NetBSD: brk.S,v 1.16 2003/08/07 16:42:17 agc Exp $ */
+
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ralph Campbell.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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$");
+#include "SYS.h"
+
+#if defined(LIBC_SCCS) && !defined(lint)
+ ASMSTR("from: @(#)brk.s 8.1 (Berkeley) 6/4/93")
+ ASMSTR("$NetBSD: brk.S,v 1.16 2003/08/07 16:42:17 agc Exp $")
+#endif /* LIBC_SCCS and not lint */
+
+ .globl _C_LABEL(minbrk)
+ .globl _C_LABEL(__curbrk)
+ .globl _C_LABEL(_end)
+
+ .data
+_C_LABEL(minbrk):
+ PTR_WORD _C_LABEL(_end)
+
+ .text
+LEAF(__sys_brk)
+ WEAK_ALIAS(brk, __sys_brk)
+ WEAK_ALIAS(_brk, __sys_brk)
+ PIC_PROLOGUE(__sys_brk)
+ PTR_LA v0, _C_LABEL(minbrk)
+ PTR_L v0, 0(v0)
+ bgeu a0, v0, 1f
+ move a0, v0 # dont allow break < minbrk
+1:
+ li v0, SYS_break
+ syscall
+ bne a3, zero, 2f
+ PTR_LA t0, _C_LABEL(__curbrk)
+ PTR_S a0, 0(t0)
+ move v0, zero
+ PIC_RETURN()
+2:
+ PIC_TAILCALL(__cerror)
+END(__sys_brk)
diff --git a/lib/libc/mips/sys/cerror.S b/lib/libc/mips/sys/cerror.S
new file mode 100644
index 000000000000..c504d73afa3f
--- /dev/null
+++ b/lib/libc/mips/sys/cerror.S
@@ -0,0 +1,72 @@
+/* $NetBSD: cerror.S,v 1.14 2009/12/14 01:07:42 matt Exp $ */
+
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ralph Campbell.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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$");
+#include "SYS.h"
+
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+ RCSID("from: @(#)cerror.s 8.1 (Berkeley) 6/16/93")
+#else
+ RCSID("$NetBSD: cerror.S,v 1.14 2009/12/14 01:07:42 matt Exp $")
+#endif
+#endif /* LIBC_SCCS and not lint */
+
+ .globl _C_LABEL(__error)
+NESTED_NOPROFILE(__cerror, CALLFRAME_SIZ, ra)
+ .mask 0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ)
+ SETUP_GP
+ PTR_SUBU sp, sp, CALLFRAME_SIZ
+ SETUP_GP64(CALLFRAME_GP, __cerror)
+ SAVE_GP(CALLFRAME_GP)
+
+ PTR_S ra, CALLFRAME_RA(sp)
+ REG_S v0, CALLFRAME_S0(sp) # save errno value
+
+ PTR_LA t9, _C_LABEL(__error) # locate address of errno
+ jalr t9
+
+ REG_L t0, CALLFRAME_S0(sp)
+ PTR_L ra, CALLFRAME_RA(sp)
+ INT_S t0, 0(v0) # update errno value
+
+ RESTORE_GP64
+ PTR_ADDU sp, sp, CALLFRAME_SIZ
+
+ li v0, -1
+ li v1, -1
+
+ j ra
+END(__cerror)
diff --git a/lib/libc/mips/sys/exect.S b/lib/libc/mips/sys/exect.S
new file mode 100644
index 000000000000..613d47c5d6d5
--- /dev/null
+++ b/lib/libc/mips/sys/exect.S
@@ -0,0 +1,51 @@
+/* $NetBSD: exect.S,v 1.9 2003/08/07 16:42:17 agc Exp $ */
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ralph Campbell.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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$");
+#include "SYS.h"
+
+#if defined(LIBC_SCCS) && !defined(lint)
+ ASMSTR("from: @(#)exect.s 8.1 (Berkeley) 6/4/93")
+ ASMSTR("$NetBSD: exect.S,v 1.9 2003/08/07 16:42:17 agc Exp $")
+#endif /* LIBC_SCCS and not lint */
+
+LEAF(exect)
+ PIC_PROLOGUE(exect)
+ li v0, SYS_execve
+ syscall
+ bne a3, zero, 1f
+ PIC_RETURN()
+1:
+ PIC_TAILCALL(__cerror)
+END(exect)
diff --git a/lib/libc/mips/sys/sbrk.S b/lib/libc/mips/sys/sbrk.S
new file mode 100644
index 000000000000..0989493a6172
--- /dev/null
+++ b/lib/libc/mips/sys/sbrk.S
@@ -0,0 +1,73 @@
+/* $NetBSD: sbrk.S,v 1.16 2005/04/22 06:58:01 simonb Exp $ */
+
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ralph Campbell.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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$");
+#include "SYS.h"
+
+#if defined(LIBC_SCCS) && !defined(lint)
+ ASMSTR("from: @(#)sbrk.s 8.1 (Berkeley) 6/4/93")
+ ASMSTR("$NetBSD: sbrk.S,v 1.16 2005/04/22 06:58:01 simonb Exp $")
+#endif /* LIBC_SCCS and not lint */
+
+ .globl _C_LABEL(__curbrk)
+ .globl _C_LABEL(_end)
+
+ .data
+_C_LABEL(__curbrk):
+ PTR_WORD _C_LABEL(_end)
+ .text
+
+LEAF(__sys_sbrk)
+ WEAK_ALIAS(sbrk, __sys_sbrk)
+ WEAK_ALIAS(_sbrk, __sys_sbrk)
+ PIC_PROLOGUE(__sys_sbrk)
+ PTR_LA t0, _C_LABEL(__curbrk)
+ PTR_L t0, 0(t0)
+ PTR_ADDU a0, a0, t0
+
+ li v0, SYS_break
+ syscall
+
+ bne a3, zero, 1f
+ nop
+ move v0, t0 # return old val of curbrk from above
+ PTR_LA t0, _C_LABEL(__curbrk)
+ PTR_S a0, 0(t0) # save current val of curbrk from above
+ PIC_RETURN()
+ j ra
+
+1:
+ PIC_TAILCALL(__cerror)
+END(__sys_sbrk)
diff --git a/lib/libc/mips/sys/shmat.S b/lib/libc/mips/sys/shmat.S
new file mode 100644
index 000000000000..d81f6bfb82a1
--- /dev/null
+++ b/lib/libc/mips/sys/shmat.S
@@ -0,0 +1,7 @@
+/* $NetBSD: shmat.S,v 1.1 2000/07/07 08:20:52 itohy Exp $ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+#include "SYS.h"
+
+RSYSCALL(shmat)
diff --git a/lib/libc/mips/sys/syscall.S b/lib/libc/mips/sys/syscall.S
new file mode 100644
index 000000000000..b3c6708b5da5
--- /dev/null
+++ b/lib/libc/mips/sys/syscall.S
@@ -0,0 +1,44 @@
+/* $NetBSD: syscall.S,v 1.5 2003/08/07 16:42:18 agc Exp $ */
+
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ralph Campbell.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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$");
+#include "SYS.h"
+
+#if defined(LIBC_SCCS) && !defined(lint)
+ ASMSTR("from: @(#)syscall.s 8.1 (Berkeley) 6/4/93")
+ ASMSTR("$NetBSD: syscall.S,v 1.5 2003/08/07 16:42:18 agc Exp $")
+#endif /* LIBC_SCCS and not lint */
+
+RSYSCALL(syscall)
diff --git a/lib/libc/nameser/Makefile.inc b/lib/libc/nameser/Makefile.inc
new file mode 100644
index 000000000000..cbb21220040b
--- /dev/null
+++ b/lib/libc/nameser/Makefile.inc
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+# nameser sources
+.PATH: ${LIBC_SRCTOP}/nameser
+
+SRCS+= ns_name.c ns_netint.c ns_parse.c ns_print.c ns_samedomain.c ns_ttl.c
+
+SYM_MAPS+= ${LIBC_SRCTOP}/nameser/Symbol.map
diff --git a/lib/libc/nameser/Symbol.map b/lib/libc/nameser/Symbol.map
new file mode 100644
index 000000000000..2c4b76e69410
--- /dev/null
+++ b/lib/libc/nameser/Symbol.map
@@ -0,0 +1,52 @@
+/*
+ * $FreeBSD$
+ */
+
+FBSD_1.0 {
+ __ns_makecanon;
+ __ns_msg_getflag;
+ __ns_name_ntol;
+ __ns_name_ntop;
+ __ns_name_pton;
+ __ns_name_unpack;
+ __ns_name_pack;
+ __ns_name_uncompress;
+ __ns_name_compress;
+ __ns_name_rollback;
+ __ns_name_skip;
+ __ns_get16;
+ __ns_get32;
+ __ns_put16;
+ __ns_put32;
+ __ns_initparse;
+ __ns_parserr;
+ _ns_flagdata;
+ __ns_samedomain;
+ __ns_samename;
+ __ns_skiprr;
+ __ns_sprintrr;
+ __ns_sprintrrf;
+ __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
new file mode 100644
index 000000000000..5b8a8cb2b17c
--- /dev/null
+++ b/lib/libc/nameser/ns_name.c
@@ -0,0 +1,1156 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id: ns_name.c,v 1.11 2009/01/23 19:59:16 each Exp $";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "port_before.h"
+
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <resolv.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <limits.h>
+
+#include "port_after.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) ((size_t)sprintf x)
+#endif
+
+#define NS_TYPE_ELT 0x40 /*%< EDNS0 extended label type */
+#define DNS_LABELTYPE_BITSTRING 0x41
+
+/* Data. */
+
+static const char digits[] = "0123456789";
+
+static const char digitvalue[256] = {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*16*/
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*32*/
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*48*/
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /*64*/
+ -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*80*/
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*96*/
+ -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*112*/
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*128*/
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*256*/
+};
+
+/* Forward. */
+
+static int special(int);
+static int printable(int);
+static int dn_find(const u_char *, const u_char *,
+ const u_char * const *,
+ const u_char * const *);
+static int encode_bitsring(const char **, const char *,
+ unsigned char **, unsigned char **,
+ unsigned const char *);
+static int labellen(const u_char *);
+static int decode_bitstring(const unsigned char **,
+ char *, const char *);
+
+/* Public. */
+
+/*%
+ * Convert an encoded domain name to printable ascii as per RFC1035.
+
+ * return:
+ *\li Number of bytes written to buffer, or -1 (with errno set)
+ *
+ * notes:
+ *\li The root is returned as "."
+ *\li All other domains are returned in non absolute form
+ */
+int
+ns_name_ntop(const u_char *src, char *dst, size_t dstsiz)
+{
+ const u_char *cp;
+ char *dn, *eom;
+ u_char c;
+ u_int n;
+ int l;
+
+ cp = src;
+ dn = dst;
+ eom = dst + dstsiz;
+
+ while ((n = *cp++) != 0) {
+ if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
+ /* Some kind of compression pointer. */
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ if (dn != dst) {
+ if (dn >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *dn++ = '.';
+ }
+ if ((l = labellen(cp - 1)) < 0) {
+ errno = EMSGSIZE; /*%< XXX */
+ return (-1);
+ }
+ if (dn + l >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ if ((n & NS_CMPRSFLGS) == NS_TYPE_ELT) {
+ int m;
+
+ if (n != DNS_LABELTYPE_BITSTRING) {
+ /* XXX: labellen should reject this case */
+ errno = EINVAL;
+ return (-1);
+ }
+ if ((m = decode_bitstring(&cp, dn, eom)) < 0)
+ {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ dn += m;
+ continue;
+ }
+ for ((void)NULL; l > 0; l--) {
+ c = *cp++;
+ if (special(c)) {
+ if (dn + 1 >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *dn++ = '\\';
+ *dn++ = (char)c;
+ } else if (!printable(c)) {
+ if (dn + 3 >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *dn++ = '\\';
+ *dn++ = digits[c / 100];
+ *dn++ = digits[(c % 100) / 10];
+ *dn++ = digits[c % 10];
+ } else {
+ if (dn >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *dn++ = (char)c;
+ }
+ }
+ }
+ if (dn == dst) {
+ if (dn >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *dn++ = '.';
+ }
+ if (dn >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *dn++ = '\0';
+ return (dn - dst);
+}
+
+/*%
+ * Convert a ascii string into an encoded domain name as per RFC1035.
+ *
+ * return:
+ *
+ *\li -1 if it fails
+ *\li 1 if string was fully qualified
+ *\li 0 is string was not fully qualified
+ *
+ * notes:
+ *\li Enforces label and domain length limits.
+ */
+int
+ns_name_pton(const char *src, u_char *dst, size_t dstsiz) {
+ return (ns_name_pton2(src, dst, dstsiz, NULL));
+}
+
+/*
+ * ns_name_pton2(src, dst, dstsiz, *dstlen)
+ * Convert a ascii string into an encoded domain name as per RFC1035.
+ * return:
+ * -1 if it fails
+ * 1 if string was fully qualified
+ * 0 is string was not fully qualified
+ * side effects:
+ * fills in *dstlen (if non-NULL)
+ * notes:
+ * Enforces label and domain length limits.
+ */
+int
+ns_name_pton2(const char *src, u_char *dst, size_t dstsiz, size_t *dstlen) {
+ u_char *label, *bp, *eom;
+ int c, n, escaped, e = 0;
+ char *cp;
+
+ escaped = 0;
+ bp = dst;
+ eom = dst + dstsiz;
+ label = bp++;
+
+ while ((c = *src++) != 0) {
+ if (escaped) {
+ if (c == '[') { /*%< start a bit string label */
+ if ((cp = strchr(src, ']')) == NULL) {
+ errno = EINVAL; /*%< ??? */
+ return (-1);
+ }
+ if ((e = encode_bitsring(&src, cp + 2,
+ &label, &bp, eom))
+ != 0) {
+ errno = e;
+ return (-1);
+ }
+ escaped = 0;
+ label = bp++;
+ if ((c = *src++) == 0)
+ goto done;
+ else if (c != '.') {
+ errno = EINVAL;
+ return (-1);
+ }
+ continue;
+ }
+ else if ((cp = strchr(digits, c)) != NULL) {
+ n = (cp - digits) * 100;
+ if ((c = *src++) == 0 ||
+ (cp = strchr(digits, c)) == NULL) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ n += (cp - digits) * 10;
+ if ((c = *src++) == 0 ||
+ (cp = strchr(digits, c)) == NULL) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ n += (cp - digits);
+ if (n > 255) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ c = n;
+ }
+ escaped = 0;
+ } else if (c == '\\') {
+ escaped = 1;
+ continue;
+ } else if (c == '.') {
+ c = (bp - label - 1);
+ if ((c & NS_CMPRSFLGS) != 0) { /*%< Label too big. */
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ if (label >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *label = c;
+ /* Fully qualified ? */
+ if (*src == '\0') {
+ if (c != 0) {
+ if (bp >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *bp++ = '\0';
+ }
+ if ((bp - dst) > MAXCDNAME) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ if (dstlen != NULL)
+ *dstlen = (bp - dst);
+ return (1);
+ }
+ if (c == 0 || *src == '.') {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ label = bp++;
+ continue;
+ }
+ if (bp >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *bp++ = (u_char)c;
+ }
+ c = (bp - label - 1);
+ if ((c & NS_CMPRSFLGS) != 0) { /*%< Label too big. */
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ done:
+ if (label >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *label = c;
+ if (c != 0) {
+ if (bp >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *bp++ = 0;
+ }
+ if ((bp - dst) > MAXCDNAME) { /*%< src too big */
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ if (dstlen != NULL)
+ *dstlen = (bp - dst);
+ return (0);
+}
+
+/*%
+ * Convert a network strings labels into all lowercase.
+ *
+ * return:
+ *\li Number of bytes written to buffer, or -1 (with errno set)
+ *
+ * notes:
+ *\li Enforces label and domain length limits.
+ */
+
+int
+ns_name_ntol(const u_char *src, u_char *dst, size_t dstsiz)
+{
+ const u_char *cp;
+ u_char *dn, *eom;
+ u_char c;
+ u_int n;
+ int l;
+
+ cp = src;
+ dn = dst;
+ eom = dst + dstsiz;
+
+ if (dn >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ while ((n = *cp++) != 0) {
+ if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
+ /* Some kind of compression pointer. */
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *dn++ = n;
+ if ((l = labellen(cp - 1)) < 0) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ if (dn + l >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ for ((void)NULL; l > 0; l--) {
+ c = *cp++;
+ if (isascii(c) && isupper(c))
+ *dn++ = tolower(c);
+ else
+ *dn++ = c;
+ }
+ }
+ *dn++ = '\0';
+ return (dn - dst);
+}
+
+/*%
+ * Unpack a domain name from a message, source may be compressed.
+ *
+ * return:
+ *\li -1 if it fails, or consumed octets if it succeeds.
+ */
+int
+ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src,
+ u_char *dst, size_t dstsiz)
+{
+ return (ns_name_unpack2(msg, eom, src, dst, dstsiz, NULL));
+}
+
+/*
+ * ns_name_unpack2(msg, eom, src, dst, dstsiz, *dstlen)
+ * Unpack a domain name from a message, source may be compressed.
+ * return:
+ * -1 if it fails, or consumed octets if it succeeds.
+ * side effect:
+ * fills in *dstlen (if non-NULL).
+ */
+int
+ns_name_unpack2(const u_char *msg, const u_char *eom, const u_char *src,
+ u_char *dst, size_t dstsiz, size_t *dstlen)
+{
+ const u_char *srcp, *dstlim;
+ u_char *dstp;
+ int n, len, checked, l;
+
+ len = -1;
+ checked = 0;
+ dstp = dst;
+ srcp = src;
+ dstlim = dst + dstsiz;
+ if (srcp < msg || srcp >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ /* Fetch next label in domain name. */
+ while ((n = *srcp++) != 0) {
+ /* Check for indirection. */
+ switch (n & NS_CMPRSFLGS) {
+ case 0:
+ case NS_TYPE_ELT:
+ /* Limit checks. */
+ if ((l = labellen(srcp - 1)) < 0) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ if (dstp + l + 1 >= dstlim || srcp + l >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ checked += l + 1;
+ *dstp++ = n;
+ memcpy(dstp, srcp, l);
+ dstp += l;
+ srcp += l;
+ break;
+
+ case NS_CMPRSFLGS:
+ if (srcp >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ if (len < 0)
+ len = srcp - src + 1;
+ l = ((n & 0x3f) << 8) | (*srcp & 0xff);
+ if (l >= eom - msg) { /*%< Out of range. */
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ srcp = msg + l;
+ checked += 2;
+ /*
+ * Check for loops in the compressed name;
+ * if we've looked at the whole message,
+ * there must be a loop.
+ */
+ if (checked >= eom - msg) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ break;
+
+ default:
+ errno = EMSGSIZE;
+ return (-1); /*%< flag error */
+ }
+ }
+ *dstp++ = 0;
+ if (dstlen != NULL)
+ *dstlen = dstp - dst;
+ if (len < 0)
+ len = srcp - src;
+ return (len);
+}
+
+/*%
+ * Pack domain name 'domain' into 'comp_dn'.
+ *
+ * return:
+ *\li Size of the compressed name, or -1.
+ *
+ * notes:
+ *\li 'dnptrs' is an array of pointers to previous compressed names.
+ *\li dnptrs[0] is a pointer to the beginning of the message. The array
+ * ends with NULL.
+ *\li 'lastdnptr' is a pointer to the end of the array pointed to
+ * by 'dnptrs'.
+ *
+ * Side effects:
+ *\li The list of pointers in dnptrs is updated for labels inserted into
+ * the message as we compress the name. If 'dnptr' is NULL, we don't
+ * try to compress names. If 'lastdnptr' is NULL, we don't update the
+ * list.
+ */
+int
+ns_name_pack(const u_char *src, u_char *dst, int dstsiz,
+ const u_char **dnptrs, const u_char **lastdnptr)
+{
+ u_char *dstp;
+ const u_char **cpp, **lpp, *eob, *msg;
+ const u_char *srcp;
+ int n, l, first = 1;
+
+ srcp = src;
+ dstp = dst;
+ eob = dstp + dstsiz;
+ lpp = cpp = NULL;
+ if (dnptrs != NULL) {
+ if ((msg = *dnptrs++) != NULL) {
+ for (cpp = dnptrs; *cpp != NULL; cpp++)
+ (void)NULL;
+ lpp = cpp; /*%< end of list to search */
+ }
+ } else
+ msg = NULL;
+
+ /* make sure the domain we are about to add is legal */
+ l = 0;
+ do {
+ int l0;
+
+ n = *srcp;
+ if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ if ((l0 = labellen(srcp)) < 0) {
+ errno = EINVAL;
+ return (-1);
+ }
+ l += l0 + 1;
+ if (l > MAXCDNAME) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ srcp += l0 + 1;
+ } while (n != 0);
+
+ /* from here on we need to reset compression pointer array on error */
+ srcp = src;
+ do {
+ /* Look to see if we can use pointers. */
+ n = *srcp;
+ if (n != 0 && msg != NULL) {
+ l = dn_find(srcp, msg, (const u_char * const *)dnptrs,
+ (const u_char * const *)lpp);
+ if (l >= 0) {
+ if (dstp + 1 >= eob) {
+ goto cleanup;
+ }
+ *dstp++ = (l >> 8) | NS_CMPRSFLGS;
+ *dstp++ = l % 256;
+ return (dstp - dst);
+ }
+ /* Not found, save it. */
+ if (lastdnptr != NULL && cpp < lastdnptr - 1 &&
+ (dstp - msg) < 0x4000 && first) {
+ *cpp++ = dstp;
+ *cpp = NULL;
+ first = 0;
+ }
+ }
+ /* copy label to buffer */
+ if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
+ /* Should not happen. */
+ goto cleanup;
+ }
+ n = labellen(srcp);
+ if (dstp + 1 + n >= eob) {
+ goto cleanup;
+ }
+ memcpy(dstp, srcp, n + 1);
+ srcp += n + 1;
+ dstp += n + 1;
+ } while (n != 0);
+
+ if (dstp > eob) {
+cleanup:
+ if (msg != NULL)
+ *lpp = NULL;
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ return (dstp - dst);
+}
+
+/*%
+ * Expand compressed domain name to presentation format.
+ *
+ * return:
+ *\li Number of bytes read out of `src', or -1 (with errno set).
+ *
+ * note:
+ *\li Root domain returns as "." not "".
+ */
+int
+ns_name_uncompress(const u_char *msg, const u_char *eom, const u_char *src,
+ char *dst, size_t dstsiz)
+{
+ u_char tmp[NS_MAXCDNAME];
+ int n;
+
+ if ((n = ns_name_unpack(msg, eom, src, tmp, sizeof tmp)) == -1)
+ return (-1);
+ if (ns_name_ntop(tmp, dst, dstsiz) == -1)
+ return (-1);
+ return (n);
+}
+
+/*%
+ * Compress a domain name into wire format, using compression pointers.
+ *
+ * return:
+ *\li Number of bytes consumed in `dst' or -1 (with errno set).
+ *
+ * notes:
+ *\li 'dnptrs' is an array of pointers to previous compressed names.
+ *\li dnptrs[0] is a pointer to the beginning of the message.
+ *\li The list ends with NULL. 'lastdnptr' is a pointer to the end of the
+ * array pointed to by 'dnptrs'. Side effect is to update the list of
+ * pointers for labels inserted into the message as we compress the name.
+ *\li If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr'
+ * is NULL, we don't update the list.
+ */
+int
+ns_name_compress(const char *src, u_char *dst, size_t dstsiz,
+ const u_char **dnptrs, const u_char **lastdnptr)
+{
+ u_char tmp[NS_MAXCDNAME];
+
+ if (ns_name_pton(src, tmp, sizeof tmp) == -1)
+ return (-1);
+ return (ns_name_pack(tmp, dst, dstsiz, dnptrs, lastdnptr));
+}
+
+/*%
+ * Reset dnptrs so that there are no active references to pointers at or
+ * after src.
+ */
+void
+ns_name_rollback(const u_char *src, const u_char **dnptrs,
+ const u_char **lastdnptr)
+{
+ while (dnptrs < lastdnptr && *dnptrs != NULL) {
+ if (*dnptrs >= src) {
+ *dnptrs = NULL;
+ break;
+ }
+ dnptrs++;
+ }
+}
+
+/*%
+ * Advance *ptrptr to skip over the compressed name it points at.
+ *
+ * return:
+ *\li 0 on success, -1 (with errno set) on failure.
+ */
+int
+ns_name_skip(const u_char **ptrptr, const u_char *eom)
+{
+ const u_char *cp;
+ u_int n;
+ int l;
+
+ cp = *ptrptr;
+ while (cp < eom && (n = *cp++) != 0) {
+ /* Check for indirection. */
+ switch (n & NS_CMPRSFLGS) {
+ case 0: /*%< normal case, n == len */
+ cp += n;
+ continue;
+ case NS_TYPE_ELT: /*%< EDNS0 extended label */
+ if ((l = labellen(cp - 1)) < 0) {
+ errno = EMSGSIZE; /*%< XXX */
+ return (-1);
+ }
+ cp += l;
+ continue;
+ case NS_CMPRSFLGS: /*%< indirection */
+ cp++;
+ break;
+ default: /*%< illegal type */
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ break;
+ }
+ if (cp > eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *ptrptr = cp;
+ return (0);
+}
+
+/* Find the number of octets an nname takes up, including the root label.
+ * (This is basically ns_name_skip() without compression-pointer support.)
+ * ((NOTE: can only return zero if passed-in namesiz argument is zero.))
+ */
+ssize_t
+ns_name_length(ns_nname_ct nname, size_t namesiz) {
+ ns_nname_ct orig = nname;
+ u_int n;
+
+ while (namesiz-- > 0 && (n = *nname++) != 0) {
+ if ((n & NS_CMPRSFLGS) != 0) {
+ errno = EISDIR;
+ return (-1);
+ }
+ if (n > namesiz) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ nname += n;
+ namesiz -= n;
+ }
+ return (nname - orig);
+}
+
+/* Compare two nname's for equality. Return -1 on error (setting errno).
+ */
+int
+ns_name_eq(ns_nname_ct a, size_t as, ns_nname_ct b, size_t bs) {
+ ns_nname_ct ae = a + as, be = b + bs;
+ int ac, bc;
+
+ while (ac = *a, bc = *b, ac != 0 && bc != 0) {
+ if ((ac & NS_CMPRSFLGS) != 0 || (bc & NS_CMPRSFLGS) != 0) {
+ errno = EISDIR;
+ return (-1);
+ }
+ if (a + ac >= ae || b + bc >= be) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ if (ac != bc || strncasecmp((const char *) ++a,
+ (const char *) ++b, ac) != 0)
+ return (0);
+ a += ac, b += bc;
+ }
+ return (ac == 0 && bc == 0);
+}
+
+/* Is domain "A" owned by (at or below) domain "B"?
+ */
+int
+ns_name_owned(ns_namemap_ct a, int an, ns_namemap_ct b, int bn) {
+ /* If A is shorter, it cannot be owned by B. */
+ if (an < bn)
+ return (0);
+
+ /* If they are unequal before the length of the shorter, A cannot... */
+ while (bn > 0) {
+ if (a->len != b->len ||
+ strncasecmp((const char *) a->base,
+ (const char *) b->base, a->len) != 0)
+ return (0);
+ a++, an--;
+ b++, bn--;
+ }
+
+ /* A might be longer or not, but either way, B owns it. */
+ return (1);
+}
+
+/* Build an array of <base,len> tuples from an nname, top-down order.
+ * Return the number of tuples (labels) thus discovered.
+ */
+int
+ns_name_map(ns_nname_ct nname, size_t namelen, ns_namemap_t map, int mapsize) {
+ u_int n;
+ int l;
+
+ n = *nname++;
+ namelen--;
+
+ /* Root zone? */
+ if (n == 0) {
+ /* Extra data follows name? */
+ if (namelen > 0) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ return (0);
+ }
+
+ /* Compression pointer? */
+ if ((n & NS_CMPRSFLGS) != 0) {
+ errno = EISDIR;
+ return (-1);
+ }
+
+ /* Label too long? */
+ if (n > namelen) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+
+ /* Recurse to get rest of name done first. */
+ l = ns_name_map(nname + n, namelen - n, map, mapsize);
+ if (l < 0)
+ return (-1);
+
+ /* Too many labels? */
+ if (l >= mapsize) {
+ errno = ENAMETOOLONG;
+ return (-1);
+ }
+
+ /* We're on our way back up-stack, store current map data. */
+ map[l].base = nname;
+ map[l].len = n;
+ return (l + 1);
+}
+
+/* Count the labels in a domain name. Root counts, so COM. has two. This
+ * is to make the result comparable to the result of ns_name_map().
+ */
+int
+ns_name_labels(ns_nname_ct nname, size_t namesiz) {
+ int ret = 0;
+ u_int n;
+
+ while (namesiz-- > 0 && (n = *nname++) != 0) {
+ if ((n & NS_CMPRSFLGS) != 0) {
+ errno = EISDIR;
+ return (-1);
+ }
+ if (n > namesiz) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ nname += n;
+ namesiz -= n;
+ ret++;
+ }
+ return (ret + 1);
+}
+
+/* Private. */
+
+/*%
+ * Thinking in noninternationalized USASCII (per the DNS spec),
+ * is this characted special ("in need of quoting") ?
+ *
+ * return:
+ *\li boolean.
+ */
+static int
+special(int ch) {
+ switch (ch) {
+ case 0x22: /*%< '"' */
+ case 0x2E: /*%< '.' */
+ case 0x3B: /*%< ';' */
+ case 0x5C: /*%< '\\' */
+ case 0x28: /*%< '(' */
+ case 0x29: /*%< ')' */
+ /* Special modifiers in zone files. */
+ case 0x40: /*%< '@' */
+ case 0x24: /*%< '$' */
+ return (1);
+ default:
+ return (0);
+ }
+}
+
+/*%
+ * Thinking in noninternationalized USASCII (per the DNS spec),
+ * is this character visible and not a space when printed ?
+ *
+ * return:
+ *\li boolean.
+ */
+static int
+printable(int ch) {
+ return (ch > 0x20 && ch < 0x7f);
+}
+
+/*%
+ * Thinking in noninternationalized USASCII (per the DNS spec),
+ * convert this character to lower case if it's upper case.
+ */
+static int
+mklower(int ch) {
+ if (ch >= 0x41 && ch <= 0x5A)
+ return (ch + 0x20);
+ return (ch);
+}
+
+/*%
+ * Search for the counted-label name in an array of compressed names.
+ *
+ * return:
+ *\li offset from msg if found, or -1.
+ *
+ * notes:
+ *\li dnptrs is the pointer to the first name on the list,
+ *\li not the pointer to the start of the message.
+ */
+static int
+dn_find(const u_char *domain, const u_char *msg,
+ const u_char * const *dnptrs,
+ const u_char * const *lastdnptr)
+{
+ const u_char *dn, *cp, *sp;
+ const u_char * const *cpp;
+ u_int n;
+
+ for (cpp = dnptrs; cpp < lastdnptr; cpp++) {
+ sp = *cpp;
+ /*
+ * terminate search on:
+ * root label
+ * compression pointer
+ * unusable offset
+ */
+ while (*sp != 0 && (*sp & NS_CMPRSFLGS) == 0 &&
+ (sp - msg) < 0x4000) {
+ dn = domain;
+ cp = sp;
+ while ((n = *cp++) != 0) {
+ /*
+ * check for indirection
+ */
+ switch (n & NS_CMPRSFLGS) {
+ case 0: /*%< normal case, n == len */
+ n = labellen(cp - 1); /*%< XXX */
+ if (n != *dn++)
+ goto next;
+
+ for ((void)NULL; n > 0; n--)
+ if (mklower(*dn++) !=
+ mklower(*cp++))
+ goto next;
+ /* Is next root for both ? */
+ if (*dn == '\0' && *cp == '\0')
+ return (sp - msg);
+ if (*dn)
+ continue;
+ goto next;
+ case NS_CMPRSFLGS: /*%< indirection */
+ cp = msg + (((n & 0x3f) << 8) | *cp);
+ break;
+
+ default: /*%< illegal type */
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ }
+ next: ;
+ sp += *sp + 1;
+ }
+ }
+ errno = ENOENT;
+ return (-1);
+}
+
+static int
+decode_bitstring(const unsigned char **cpp, char *dn, const char *eom)
+{
+ const unsigned char *cp = *cpp;
+ char *beg = dn, tc;
+ int b, blen, plen, i;
+
+ if ((blen = (*cp & 0xff)) == 0)
+ blen = 256;
+ plen = (blen + 3) / 4;
+ plen += sizeof("\\[x/]") + (blen > 99 ? 3 : (blen > 9) ? 2 : 1);
+ if (dn + plen >= eom)
+ return (-1);
+
+ cp++;
+ i = SPRINTF((dn, "\\[x"));
+ if (i < 0)
+ return (-1);
+ dn += i;
+ for (b = blen; b > 7; b -= 8, cp++) {
+ i = SPRINTF((dn, "%02x", *cp & 0xff));
+ if (i < 0)
+ return (-1);
+ dn += i;
+ }
+ if (b > 4) {
+ tc = *cp++;
+ i = SPRINTF((dn, "%02x", tc & (0xff << (8 - b))));
+ if (i < 0)
+ return (-1);
+ dn += i;
+ } else if (b > 0) {
+ tc = *cp++;
+ i = SPRINTF((dn, "%1x",
+ ((tc >> 4) & 0x0f) & (0x0f << (4 - b))));
+ if (i < 0)
+ return (-1);
+ dn += i;
+ }
+ i = SPRINTF((dn, "/%d]", blen));
+ if (i < 0)
+ return (-1);
+ dn += i;
+
+ *cpp = cp;
+ return (dn - beg);
+}
+
+static int
+encode_bitsring(const char **bp, const char *end, unsigned char **labelp,
+ unsigned char ** dst, unsigned const char *eom)
+{
+ int afterslash = 0;
+ const char *cp = *bp;
+ unsigned char *tp;
+ char c;
+ const char *beg_blen;
+ char *end_blen = NULL;
+ int value = 0, count = 0, tbcount = 0, blen = 0;
+
+ beg_blen = end_blen = NULL;
+
+ /* a bitstring must contain at least 2 characters */
+ if (end - cp < 2)
+ return (EINVAL);
+
+ /* XXX: currently, only hex strings are supported */
+ if (*cp++ != 'x')
+ return (EINVAL);
+ if (!isxdigit((*cp) & 0xff)) /*%< reject '\[x/BLEN]' */
+ return (EINVAL);
+
+ for (tp = *dst + 1; cp < end && tp < eom; cp++) {
+ switch((c = *cp)) {
+ case ']': /*%< end of the bitstring */
+ if (afterslash) {
+ if (beg_blen == NULL)
+ return (EINVAL);
+ blen = (int)strtol(beg_blen, &end_blen, 10);
+ if (*end_blen != ']')
+ return (EINVAL);
+ }
+ if (count)
+ *tp++ = ((value << 4) & 0xff);
+ cp++; /*%< skip ']' */
+ goto done;
+ case '/':
+ afterslash = 1;
+ break;
+ default:
+ if (afterslash) {
+ if (!isdigit(c&0xff))
+ return (EINVAL);
+ if (beg_blen == NULL) {
+
+ if (c == '0') {
+ /* blen never begings with 0 */
+ return (EINVAL);
+ }
+ beg_blen = cp;
+ }
+ } else {
+ if (!isxdigit(c&0xff))
+ return (EINVAL);
+ value <<= 4;
+ value += digitvalue[(int)c];
+ count += 4;
+ tbcount += 4;
+ if (tbcount > 256)
+ return (EINVAL);
+ if (count == 8) {
+ *tp++ = value;
+ count = 0;
+ }
+ }
+ break;
+ }
+ }
+ done:
+ if (cp >= end || tp >= eom)
+ return (EMSGSIZE);
+
+ /*
+ * bit length validation:
+ * If a <length> is present, the number of digits in the <bit-data>
+ * MUST be just sufficient to contain the number of bits specified
+ * by the <length>. If there are insignificant bits in a final
+ * hexadecimal or octal digit, they MUST be zero.
+ * RFC2673, Section 3.2.
+ */
+ if (blen > 0) {
+ int traillen;
+
+ if (((blen + 3) & ~3) != tbcount)
+ return (EINVAL);
+ traillen = tbcount - blen; /*%< between 0 and 3 */
+ if (((value << (8 - traillen)) & 0xff) != 0)
+ return (EINVAL);
+ }
+ else
+ blen = tbcount;
+ if (blen == 256)
+ blen = 0;
+
+ /* encode the type and the significant bit fields */
+ **labelp = DNS_LABELTYPE_BITSTRING;
+ **dst = blen;
+
+ *bp = cp;
+ *dst = tp;
+
+ return (0);
+}
+
+static int
+labellen(const u_char *lp)
+{
+ int bitlen;
+ u_char l = *lp;
+
+ if ((l & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
+ /* should be avoided by the caller */
+ return (-1);
+ }
+
+ if ((l & NS_CMPRSFLGS) == NS_TYPE_ELT) {
+ if (l == DNS_LABELTYPE_BITSTRING) {
+ if ((bitlen = *(lp + 1)) == 0)
+ bitlen = 256;
+ return ((bitlen + 7 ) / 8 + 1);
+ }
+ return (-1); /*%< unknwon ELT */
+ }
+ return (l);
+}
+
+/*! \file */
diff --git a/lib/libc/nameser/ns_netint.c b/lib/libc/nameser/ns_netint.c
new file mode 100644
index 000000000000..5ddd5bc6c646
--- /dev/null
+++ b/lib/libc/nameser/ns_netint.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id: ns_netint.c,v 1.3 2005/04/27 04:56:40 sra Exp $";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/* Import. */
+
+#include "port_before.h"
+
+#include <arpa/nameser.h>
+
+#include "port_after.h"
+
+/* Public. */
+
+u_int
+ns_get16(const u_char *src) {
+ u_int dst;
+
+ NS_GET16(dst, src);
+ return (dst);
+}
+
+u_long
+ns_get32(const u_char *src) {
+ u_long dst;
+
+ NS_GET32(dst, src);
+ return (dst);
+}
+
+void
+ns_put16(u_int src, u_char *dst) {
+ NS_PUT16(src, dst);
+}
+
+void
+ns_put32(u_long src, u_char *dst) {
+ NS_PUT32(src, dst);
+}
+
+/*! \file */
diff --git a/lib/libc/nameser/ns_parse.c b/lib/libc/nameser/ns_parse.c
new file mode 100644
index 000000000000..7294c9298b67
--- /dev/null
+++ b/lib/libc/nameser/ns_parse.c
@@ -0,0 +1,277 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id: ns_parse.c,v 1.10 2009/01/23 19:59:16 each Exp $";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/* Import. */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <resolv.h>
+#include <string.h>
+
+#include "port_after.h"
+
+/* Forward. */
+
+static void setsection(ns_msg *msg, ns_sect sect);
+
+/* Macros. */
+
+#if !defined(SOLARIS2) || defined(__COVERITY__)
+#define RETERR(err) do { errno = (err); return (-1); } while (0)
+#else
+#define RETERR(err) \
+ do { errno = (err); if (errno == errno) return (-1); } while (0)
+#endif
+
+#define PARSE_FMT_PRESO 0 /* Parse using presentation-format names */
+#define PARSE_FMT_WIRE 1 /* Parse using network-format names */
+
+/* Public. */
+
+/* These need to be in the same order as the nres.h:ns_flag enum. */
+struct _ns_flagdata _ns_flagdata[16] = {
+ { 0x8000, 15 }, /*%< qr. */
+ { 0x7800, 11 }, /*%< opcode. */
+ { 0x0400, 10 }, /*%< aa. */
+ { 0x0200, 9 }, /*%< tc. */
+ { 0x0100, 8 }, /*%< rd. */
+ { 0x0080, 7 }, /*%< ra. */
+ { 0x0040, 6 }, /*%< z. */
+ { 0x0020, 5 }, /*%< ad. */
+ { 0x0010, 4 }, /*%< cd. */
+ { 0x000f, 0 }, /*%< rcode. */
+ { 0x0000, 0 }, /*%< expansion (1/6). */
+ { 0x0000, 0 }, /*%< expansion (2/6). */
+ { 0x0000, 0 }, /*%< expansion (3/6). */
+ { 0x0000, 0 }, /*%< expansion (4/6). */
+ { 0x0000, 0 }, /*%< expansion (5/6). */
+ { 0x0000, 0 }, /*%< expansion (6/6). */
+};
+
+int ns_msg_getflag(ns_msg handle, int flag) {
+ return(((handle)._flags & _ns_flagdata[flag].mask) >> _ns_flagdata[flag].shift);
+}
+
+int
+ns_skiprr(const u_char *ptr, const u_char *eom, ns_sect section, int count) {
+ const u_char *optr = ptr;
+
+ for ((void)NULL; count > 0; count--) {
+ int b, rdlength;
+
+ b = dn_skipname(ptr, eom);
+ if (b < 0)
+ RETERR(EMSGSIZE);
+ ptr += b/*Name*/ + NS_INT16SZ/*Type*/ + NS_INT16SZ/*Class*/;
+ if (section != ns_s_qd) {
+ if (ptr + NS_INT32SZ + NS_INT16SZ > eom)
+ RETERR(EMSGSIZE);
+ ptr += NS_INT32SZ/*TTL*/;
+ NS_GET16(rdlength, ptr);
+ ptr += rdlength/*RData*/;
+ }
+ }
+ if (ptr > eom)
+ RETERR(EMSGSIZE);
+ return (ptr - optr);
+}
+
+int
+ns_initparse(const u_char *msg, int msglen, ns_msg *handle) {
+ const u_char *eom = msg + msglen;
+ int i;
+
+ handle->_msg = msg;
+ handle->_eom = eom;
+ if (msg + NS_INT16SZ > eom)
+ RETERR(EMSGSIZE);
+ NS_GET16(handle->_id, msg);
+ if (msg + NS_INT16SZ > eom)
+ RETERR(EMSGSIZE);
+ NS_GET16(handle->_flags, msg);
+ for (i = 0; i < ns_s_max; i++) {
+ if (msg + NS_INT16SZ > eom)
+ RETERR(EMSGSIZE);
+ NS_GET16(handle->_counts[i], msg);
+ }
+ for (i = 0; i < ns_s_max; i++)
+ if (handle->_counts[i] == 0)
+ handle->_sections[i] = NULL;
+ else {
+ int b = ns_skiprr(msg, eom, (ns_sect)i,
+ handle->_counts[i]);
+
+ if (b < 0)
+ return (-1);
+ handle->_sections[i] = msg;
+ msg += b;
+ }
+ if (msg != eom)
+ RETERR(EMSGSIZE);
+ setsection(handle, ns_s_max);
+ return (0);
+}
+
+int
+ns_parserr(ns_msg *handle, ns_sect section, int rrnum, ns_rr *rr) {
+ int b;
+ int tmp;
+
+ /* Make section right. */
+ tmp = section;
+ if (tmp < 0 || section >= ns_s_max)
+ RETERR(ENODEV);
+ if (section != handle->_sect)
+ setsection(handle, section);
+
+ /* Make rrnum right. */
+ if (rrnum == -1)
+ rrnum = handle->_rrnum;
+ if (rrnum < 0 || rrnum >= handle->_counts[(int)section])
+ RETERR(ENODEV);
+ if (rrnum < handle->_rrnum)
+ setsection(handle, section);
+ if (rrnum > handle->_rrnum) {
+ b = ns_skiprr(handle->_msg_ptr, handle->_eom, section,
+ rrnum - handle->_rrnum);
+
+ if (b < 0)
+ return (-1);
+ handle->_msg_ptr += b;
+ handle->_rrnum = rrnum;
+ }
+
+ /* Do the parse. */
+ b = dn_expand(handle->_msg, handle->_eom,
+ handle->_msg_ptr, rr->name, NS_MAXDNAME);
+ if (b < 0)
+ return (-1);
+ handle->_msg_ptr += b;
+ if (handle->_msg_ptr + NS_INT16SZ + NS_INT16SZ > handle->_eom)
+ RETERR(EMSGSIZE);
+ NS_GET16(rr->type, handle->_msg_ptr);
+ NS_GET16(rr->rr_class, handle->_msg_ptr);
+ if (section == ns_s_qd) {
+ rr->ttl = 0;
+ rr->rdlength = 0;
+ rr->rdata = NULL;
+ } else {
+ if (handle->_msg_ptr + NS_INT32SZ + NS_INT16SZ > handle->_eom)
+ RETERR(EMSGSIZE);
+ NS_GET32(rr->ttl, handle->_msg_ptr);
+ NS_GET16(rr->rdlength, handle->_msg_ptr);
+ if (handle->_msg_ptr + rr->rdlength > handle->_eom)
+ RETERR(EMSGSIZE);
+ rr->rdata = handle->_msg_ptr;
+ handle->_msg_ptr += rr->rdlength;
+ }
+ if (++handle->_rrnum > handle->_counts[(int)section])
+ setsection(handle, (ns_sect)((int)section + 1));
+
+ /* All done. */
+ return (0);
+}
+
+/*
+ * This is identical to the above but uses network-format (uncompressed) names.
+ */
+int
+ns_parserr2(ns_msg *handle, ns_sect section, int rrnum, ns_rr2 *rr) {
+ int b;
+ int tmp;
+
+ /* Make section right. */
+ if ((tmp = section) < 0 || section >= ns_s_max)
+ RETERR(ENODEV);
+ if (section != handle->_sect)
+ setsection(handle, section);
+
+ /* Make rrnum right. */
+ if (rrnum == -1)
+ rrnum = handle->_rrnum;
+ if (rrnum < 0 || rrnum >= handle->_counts[(int)section])
+ RETERR(ENODEV);
+ if (rrnum < handle->_rrnum)
+ setsection(handle, section);
+ if (rrnum > handle->_rrnum) {
+ b = ns_skiprr(handle->_msg_ptr, handle->_eom, section,
+ rrnum - handle->_rrnum);
+
+ if (b < 0)
+ return (-1);
+ handle->_msg_ptr += b;
+ handle->_rrnum = rrnum;
+ }
+
+ /* Do the parse. */
+ b = ns_name_unpack2(handle->_msg, handle->_eom, handle->_msg_ptr,
+ rr->nname, NS_MAXNNAME, &rr->nnamel);
+ if (b < 0)
+ return (-1);
+ handle->_msg_ptr += b;
+ if (handle->_msg_ptr + NS_INT16SZ + NS_INT16SZ > handle->_eom)
+ RETERR(EMSGSIZE);
+ NS_GET16(rr->type, handle->_msg_ptr);
+ NS_GET16(rr->rr_class, handle->_msg_ptr);
+ if (section == ns_s_qd) {
+ rr->ttl = 0;
+ rr->rdlength = 0;
+ rr->rdata = NULL;
+ } else {
+ if (handle->_msg_ptr + NS_INT32SZ + NS_INT16SZ > handle->_eom)
+ RETERR(EMSGSIZE);
+ NS_GET32(rr->ttl, handle->_msg_ptr);
+ NS_GET16(rr->rdlength, handle->_msg_ptr);
+ if (handle->_msg_ptr + rr->rdlength > handle->_eom)
+ RETERR(EMSGSIZE);
+ rr->rdata = handle->_msg_ptr;
+ handle->_msg_ptr += rr->rdlength;
+ }
+ if (++handle->_rrnum > handle->_counts[(int)section])
+ setsection(handle, (ns_sect)((int)section + 1));
+
+ /* All done. */
+ return (0);
+}
+
+/* Private. */
+
+static void
+setsection(ns_msg *msg, ns_sect sect) {
+ msg->_sect = sect;
+ if (sect == ns_s_max) {
+ msg->_rrnum = -1;
+ msg->_msg_ptr = NULL;
+ } else {
+ msg->_rrnum = 0;
+ msg->_msg_ptr = msg->_sections[(int)sect];
+ }
+}
+
+/*! \file */
diff --git a/lib/libc/nameser/ns_print.c b/lib/libc/nameser/ns_print.c
new file mode 100644
index 000000000000..27d653871176
--- /dev/null
+++ b/lib/libc/nameser/ns_print.c
@@ -0,0 +1,1254 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id: ns_print.c,v 1.12 2009/03/03 05:29:58 each Exp $";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/* Import. */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#ifdef _LIBC
+#include <assert.h>
+#define INSIST(cond) assert(cond)
+#else
+#include <isc/assertions.h>
+#include <isc/dst.h>
+#endif
+#include <errno.h>
+#include <resolv.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "port_after.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) ((size_t)sprintf x)
+#endif
+
+/* Forward. */
+
+static size_t prune_origin(const char *name, const char *origin);
+static int charstr(const u_char *rdata, const u_char *edata,
+ char **buf, size_t *buflen);
+static int addname(const u_char *msg, size_t msglen,
+ const u_char **p, const char *origin,
+ char **buf, size_t *buflen);
+static void addlen(size_t len, char **buf, size_t *buflen);
+static int addstr(const char *src, size_t len,
+ char **buf, size_t *buflen);
+static int addtab(size_t len, size_t target, int spaced,
+ char **buf, size_t *buflen);
+
+/* Macros. */
+
+#define T(x) \
+ do { \
+ if ((x) < 0) \
+ return (-1); \
+ } while (0)
+
+static const char base32hex[] =
+ "0123456789ABCDEFGHIJKLMNOPQRSTUV=0123456789abcdefghijklmnopqrstuv";
+
+/* Public. */
+
+/*%
+ * Convert an RR to presentation format.
+ *
+ * return:
+ *\li Number of characters written to buf, or -1 (check errno).
+ */
+int
+ns_sprintrr(const ns_msg *handle, const ns_rr *rr,
+ const char *name_ctx, const char *origin,
+ char *buf, size_t buflen)
+{
+ int n;
+
+ n = ns_sprintrrf(ns_msg_base(*handle), ns_msg_size(*handle),
+ ns_rr_name(*rr), ns_rr_class(*rr), ns_rr_type(*rr),
+ ns_rr_ttl(*rr), ns_rr_rdata(*rr), ns_rr_rdlen(*rr),
+ name_ctx, origin, buf, buflen);
+ return (n);
+}
+
+/*%
+ * Convert the fields of an RR into presentation format.
+ *
+ * return:
+ *\li Number of characters written to buf, or -1 (check errno).
+ */
+int
+ns_sprintrrf(const u_char *msg, size_t msglen,
+ const char *name, ns_class class, ns_type type,
+ u_long ttl, const u_char *rdata, size_t rdlen,
+ const char *name_ctx, const char *origin,
+ char *buf, size_t buflen)
+{
+ const char *obuf = buf;
+ const u_char *edata = rdata + rdlen;
+ int spaced = 0;
+
+ const char *comment;
+ char tmp[100];
+ int len, x;
+
+ /*
+ * Owner.
+ */
+ if (name_ctx != NULL && ns_samename(name_ctx, name) == 1) {
+ T(addstr("\t\t\t", 3, &buf, &buflen));
+ } else {
+ len = prune_origin(name, origin);
+ if (*name == '\0') {
+ goto root;
+ } else if (len == 0) {
+ T(addstr("@\t\t\t", 4, &buf, &buflen));
+ } else {
+ T(addstr(name, len, &buf, &buflen));
+ /* Origin not used or not root, and no trailing dot? */
+ if (((origin == NULL || origin[0] == '\0') ||
+ (origin[0] != '.' && origin[1] != '\0' &&
+ name[len] == '\0')) && name[len - 1] != '.') {
+ root:
+ T(addstr(".", 1, &buf, &buflen));
+ len++;
+ }
+ T(spaced = addtab(len, 24, spaced, &buf, &buflen));
+ }
+ }
+
+ /*
+ * TTL, Class, Type.
+ */
+ T(x = ns_format_ttl(ttl, buf, buflen));
+ addlen(x, &buf, &buflen);
+ len = SPRINTF((tmp, " %s %s", p_class(class), p_type(type)));
+ T(addstr(tmp, len, &buf, &buflen));
+ T(spaced = addtab(x + len, 16, spaced, &buf, &buflen));
+
+ /*
+ * RData.
+ */
+ switch (type) {
+ case ns_t_a:
+ if (rdlen != (size_t)NS_INADDRSZ)
+ goto formerr;
+ (void) inet_ntop(AF_INET, rdata, buf, buflen);
+ addlen(strlen(buf), &buf, &buflen);
+ break;
+
+ case ns_t_cname:
+ case ns_t_mb:
+ case ns_t_mg:
+ case ns_t_mr:
+ case ns_t_ns:
+ case ns_t_ptr:
+ case ns_t_dname:
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+ break;
+
+ case ns_t_hinfo:
+ case ns_t_isdn:
+ /* First word. */
+ T(len = charstr(rdata, edata, &buf, &buflen));
+ if (len == 0)
+ goto formerr;
+ rdata += len;
+ T(addstr(" ", 1, &buf, &buflen));
+
+
+ /* Second word, optional in ISDN records. */
+ if (type == ns_t_isdn && rdata == edata)
+ break;
+
+ T(len = charstr(rdata, edata, &buf, &buflen));
+ if (len == 0)
+ goto formerr;
+ rdata += len;
+ break;
+
+ case ns_t_soa: {
+ u_long t;
+
+ /* Server name. */
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+ T(addstr(" ", 1, &buf, &buflen));
+
+ /* Administrator name. */
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+ T(addstr(" (\n", 3, &buf, &buflen));
+ spaced = 0;
+
+ if ((edata - rdata) != 5*NS_INT32SZ)
+ goto formerr;
+
+ /* Serial number. */
+ t = ns_get32(rdata); rdata += NS_INT32SZ;
+ T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
+ len = SPRINTF((tmp, "%lu", t));
+ T(addstr(tmp, len, &buf, &buflen));
+ T(spaced = addtab(len, 16, spaced, &buf, &buflen));
+ T(addstr("; serial\n", 9, &buf, &buflen));
+ spaced = 0;
+
+ /* Refresh interval. */
+ t = ns_get32(rdata); rdata += NS_INT32SZ;
+ T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
+ T(len = ns_format_ttl(t, buf, buflen));
+ addlen(len, &buf, &buflen);
+ T(spaced = addtab(len, 16, spaced, &buf, &buflen));
+ T(addstr("; refresh\n", 10, &buf, &buflen));
+ spaced = 0;
+
+ /* Retry interval. */
+ t = ns_get32(rdata); rdata += NS_INT32SZ;
+ T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
+ T(len = ns_format_ttl(t, buf, buflen));
+ addlen(len, &buf, &buflen);
+ T(spaced = addtab(len, 16, spaced, &buf, &buflen));
+ T(addstr("; retry\n", 8, &buf, &buflen));
+ spaced = 0;
+
+ /* Expiry. */
+ t = ns_get32(rdata); rdata += NS_INT32SZ;
+ T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
+ T(len = ns_format_ttl(t, buf, buflen));
+ addlen(len, &buf, &buflen);
+ T(spaced = addtab(len, 16, spaced, &buf, &buflen));
+ T(addstr("; expiry\n", 9, &buf, &buflen));
+ spaced = 0;
+
+ /* Minimum TTL. */
+ t = ns_get32(rdata); rdata += NS_INT32SZ;
+ T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
+ T(len = ns_format_ttl(t, buf, buflen));
+ addlen(len, &buf, &buflen);
+ T(addstr(" )", 2, &buf, &buflen));
+ T(spaced = addtab(len, 16, spaced, &buf, &buflen));
+ T(addstr("; minimum\n", 10, &buf, &buflen));
+
+ break;
+ }
+
+ case ns_t_mx:
+ case ns_t_afsdb:
+ case ns_t_rt:
+ case ns_t_kx: {
+ u_int t;
+
+ if (rdlen < (size_t)NS_INT16SZ)
+ goto formerr;
+
+ /* Priority. */
+ t = ns_get16(rdata);
+ rdata += NS_INT16SZ;
+ len = SPRINTF((tmp, "%u ", t));
+ T(addstr(tmp, len, &buf, &buflen));
+
+ /* Target. */
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+
+ break;
+ }
+
+ case ns_t_px: {
+ u_int t;
+
+ if (rdlen < (size_t)NS_INT16SZ)
+ goto formerr;
+
+ /* Priority. */
+ t = ns_get16(rdata);
+ rdata += NS_INT16SZ;
+ len = SPRINTF((tmp, "%u ", t));
+ T(addstr(tmp, len, &buf, &buflen));
+
+ /* Name1. */
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+ T(addstr(" ", 1, &buf, &buflen));
+
+ /* Name2. */
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+
+ break;
+ }
+
+ case ns_t_x25:
+ T(len = charstr(rdata, edata, &buf, &buflen));
+ if (len == 0)
+ goto formerr;
+ rdata += len;
+ break;
+
+ case ns_t_txt:
+ case ns_t_spf:
+ while (rdata < edata) {
+ T(len = charstr(rdata, edata, &buf, &buflen));
+ if (len == 0)
+ goto formerr;
+ rdata += len;
+ if (rdata < edata)
+ T(addstr(" ", 1, &buf, &buflen));
+ }
+ break;
+
+ case ns_t_nsap: {
+ char t[2+255*3];
+
+ (void) inet_nsap_ntoa(rdlen, rdata, t);
+ T(addstr(t, strlen(t), &buf, &buflen));
+ break;
+ }
+
+ case ns_t_aaaa:
+ if (rdlen != (size_t)NS_IN6ADDRSZ)
+ goto formerr;
+ (void) inet_ntop(AF_INET6, rdata, buf, buflen);
+ addlen(strlen(buf), &buf, &buflen);
+ break;
+
+ case ns_t_loc: {
+ char t[255];
+
+ /* XXX protocol format checking? */
+ (void) loc_ntoa(rdata, t);
+ T(addstr(t, strlen(t), &buf, &buflen));
+ break;
+ }
+
+ case ns_t_naptr: {
+ u_int order, preference;
+ char t[50];
+
+ if (rdlen < 2U*NS_INT16SZ)
+ goto formerr;
+
+ /* Order, Precedence. */
+ order = ns_get16(rdata); rdata += NS_INT16SZ;
+ preference = ns_get16(rdata); rdata += NS_INT16SZ;
+ len = SPRINTF((t, "%u %u ", order, preference));
+ T(addstr(t, len, &buf, &buflen));
+
+ /* Flags. */
+ T(len = charstr(rdata, edata, &buf, &buflen));
+ if (len == 0)
+ goto formerr;
+ rdata += len;
+ T(addstr(" ", 1, &buf, &buflen));
+
+ /* Service. */
+ T(len = charstr(rdata, edata, &buf, &buflen));
+ if (len == 0)
+ goto formerr;
+ rdata += len;
+ T(addstr(" ", 1, &buf, &buflen));
+
+ /* Regexp. */
+ T(len = charstr(rdata, edata, &buf, &buflen));
+ if (len < 0)
+ return (-1);
+ if (len == 0)
+ goto formerr;
+ rdata += len;
+ T(addstr(" ", 1, &buf, &buflen));
+
+ /* Server. */
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+ break;
+ }
+
+ case ns_t_srv: {
+ u_int priority, weight, port;
+ char t[50];
+
+ if (rdlen < 3U*NS_INT16SZ)
+ goto formerr;
+
+ /* Priority, Weight, Port. */
+ priority = ns_get16(rdata); rdata += NS_INT16SZ;
+ weight = ns_get16(rdata); rdata += NS_INT16SZ;
+ port = ns_get16(rdata); rdata += NS_INT16SZ;
+ len = SPRINTF((t, "%u %u %u ", priority, weight, port));
+ T(addstr(t, len, &buf, &buflen));
+
+ /* Server. */
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+ break;
+ }
+
+ case ns_t_minfo:
+ case ns_t_rp:
+ /* Name1. */
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+ T(addstr(" ", 1, &buf, &buflen));
+
+ /* Name2. */
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+
+ break;
+
+ case ns_t_wks: {
+ int n, lcnt;
+
+ if (rdlen < 1U + NS_INT32SZ)
+ goto formerr;
+
+ /* Address. */
+ (void) inet_ntop(AF_INET, rdata, buf, buflen);
+ addlen(strlen(buf), &buf, &buflen);
+ rdata += NS_INADDRSZ;
+
+ /* Protocol. */
+ len = SPRINTF((tmp, " %u ( ", *rdata));
+ T(addstr(tmp, len, &buf, &buflen));
+ rdata += NS_INT8SZ;
+
+ /* Bit map. */
+ n = 0;
+ lcnt = 0;
+ while (rdata < edata) {
+ u_int c = *rdata++;
+ do {
+ if (c & 0200) {
+ if (lcnt == 0) {
+ T(addstr("\n\t\t\t\t", 5,
+ &buf, &buflen));
+ lcnt = 10;
+ spaced = 0;
+ }
+ len = SPRINTF((tmp, "%d ", n));
+ T(addstr(tmp, len, &buf, &buflen));
+ lcnt--;
+ }
+ c <<= 1;
+ } while (++n & 07);
+ }
+ T(addstr(")", 1, &buf, &buflen));
+
+ break;
+ }
+
+ case ns_t_key:
+ case ns_t_dnskey: {
+ char base64_key[NS_MD5RSA_MAX_BASE64];
+ u_int keyflags, protocol, algorithm, key_id;
+ const char *leader;
+ int n;
+
+ if (rdlen < 0U + NS_INT16SZ + NS_INT8SZ + NS_INT8SZ)
+ goto formerr;
+
+ /* Key flags, Protocol, Algorithm. */
+#ifndef _LIBC
+ key_id = dst_s_dns_key_id(rdata, edata-rdata);
+#else
+ key_id = 0;
+#endif
+ keyflags = ns_get16(rdata); rdata += NS_INT16SZ;
+ protocol = *rdata++;
+ algorithm = *rdata++;
+ len = SPRINTF((tmp, "0x%04x %u %u",
+ keyflags, protocol, algorithm));
+ T(addstr(tmp, len, &buf, &buflen));
+
+ /* Public key data. */
+ len = b64_ntop(rdata, edata - rdata,
+ base64_key, sizeof base64_key);
+ if (len < 0)
+ goto formerr;
+ if (len > 15) {
+ T(addstr(" (", 2, &buf, &buflen));
+ leader = "\n\t\t";
+ spaced = 0;
+ } else
+ leader = " ";
+ for (n = 0; n < len; n += 48) {
+ T(addstr(leader, strlen(leader), &buf, &buflen));
+ T(addstr(base64_key + n, MIN(len - n, 48),
+ &buf, &buflen));
+ }
+ if (len > 15)
+ T(addstr(" )", 2, &buf, &buflen));
+ n = SPRINTF((tmp, " ; key_tag= %u", key_id));
+ T(addstr(tmp, n, &buf, &buflen));
+
+ break;
+ }
+
+ case ns_t_sig:
+ case ns_t_rrsig: {
+ char base64_key[NS_MD5RSA_MAX_BASE64];
+ u_int type, algorithm, labels, footprint;
+ const char *leader;
+ u_long t;
+ int n;
+
+ if (rdlen < 22U)
+ goto formerr;
+
+ /* Type covered, Algorithm, Label count, Original TTL. */
+ type = ns_get16(rdata); rdata += NS_INT16SZ;
+ algorithm = *rdata++;
+ labels = *rdata++;
+ t = ns_get32(rdata); rdata += NS_INT32SZ;
+ len = SPRINTF((tmp, "%s %d %d %lu ",
+ p_type(type), algorithm, labels, t));
+ T(addstr(tmp, len, &buf, &buflen));
+ if (labels > (u_int)dn_count_labels(name))
+ goto formerr;
+
+ /* Signature expiry. */
+ t = ns_get32(rdata); rdata += NS_INT32SZ;
+ len = SPRINTF((tmp, "%s ", p_secstodate(t)));
+ T(addstr(tmp, len, &buf, &buflen));
+
+ /* Time signed. */
+ t = ns_get32(rdata); rdata += NS_INT32SZ;
+ len = SPRINTF((tmp, "%s ", p_secstodate(t)));
+ T(addstr(tmp, len, &buf, &buflen));
+
+ /* Signature Footprint. */
+ footprint = ns_get16(rdata); rdata += NS_INT16SZ;
+ len = SPRINTF((tmp, "%u ", footprint));
+ T(addstr(tmp, len, &buf, &buflen));
+
+ /* Signer's name. */
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+
+ /* Signature. */
+ len = b64_ntop(rdata, edata - rdata,
+ base64_key, sizeof base64_key);
+ if (len > 15) {
+ T(addstr(" (", 2, &buf, &buflen));
+ leader = "\n\t\t";
+ spaced = 0;
+ } else
+ leader = " ";
+ if (len < 0)
+ goto formerr;
+ for (n = 0; n < len; n += 48) {
+ T(addstr(leader, strlen(leader), &buf, &buflen));
+ T(addstr(base64_key + n, MIN(len - n, 48),
+ &buf, &buflen));
+ }
+ if (len > 15)
+ T(addstr(" )", 2, &buf, &buflen));
+ break;
+ }
+
+ case ns_t_nxt: {
+ int n, c;
+
+ /* Next domain name. */
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+
+ /* Type bit map. */
+ n = edata - rdata;
+ for (c = 0; c < n*8; c++)
+ if (NS_NXT_BIT_ISSET(c, rdata)) {
+ len = SPRINTF((tmp, " %s", p_type(c)));
+ T(addstr(tmp, len, &buf, &buflen));
+ }
+ break;
+ }
+
+ case ns_t_cert: {
+ u_int c_type, key_tag, alg;
+ int n;
+ unsigned int siz;
+ char base64_cert[8192], tmp[40];
+ const char *leader;
+
+ c_type = ns_get16(rdata); rdata += NS_INT16SZ;
+ key_tag = ns_get16(rdata); rdata += NS_INT16SZ;
+ alg = (u_int) *rdata++;
+
+ len = SPRINTF((tmp, "%d %d %d ", c_type, key_tag, alg));
+ T(addstr(tmp, len, &buf, &buflen));
+ siz = (edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */
+ if (siz > sizeof(base64_cert) * 3/4) {
+ const char *str = "record too long to print";
+ T(addstr(str, strlen(str), &buf, &buflen));
+ }
+ else {
+ len = b64_ntop(rdata, edata-rdata, base64_cert, siz);
+
+ if (len < 0)
+ goto formerr;
+ else if (len > 15) {
+ T(addstr(" (", 2, &buf, &buflen));
+ leader = "\n\t\t";
+ spaced = 0;
+ }
+ else
+ leader = " ";
+
+ for (n = 0; n < len; n += 48) {
+ T(addstr(leader, strlen(leader),
+ &buf, &buflen));
+ T(addstr(base64_cert + n, MIN(len - n, 48),
+ &buf, &buflen));
+ }
+ if (len > 15)
+ T(addstr(" )", 2, &buf, &buflen));
+ }
+ break;
+ }
+
+ case ns_t_tkey: {
+ /* KJD - need to complete this */
+ u_long t;
+ int mode, err, keysize;
+
+ /* Algorithm name. */
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+ T(addstr(" ", 1, &buf, &buflen));
+
+ /* Inception. */
+ t = ns_get32(rdata); rdata += NS_INT32SZ;
+ len = SPRINTF((tmp, "%s ", p_secstodate(t)));
+ T(addstr(tmp, len, &buf, &buflen));
+
+ /* Experation. */
+ t = ns_get32(rdata); rdata += NS_INT32SZ;
+ len = SPRINTF((tmp, "%s ", p_secstodate(t)));
+ T(addstr(tmp, len, &buf, &buflen));
+
+ /* Mode , Error, Key Size. */
+ /* Priority, Weight, Port. */
+ mode = ns_get16(rdata); rdata += NS_INT16SZ;
+ err = ns_get16(rdata); rdata += NS_INT16SZ;
+ keysize = ns_get16(rdata); rdata += NS_INT16SZ;
+ len = SPRINTF((tmp, "%u %u %u ", mode, err, keysize));
+ T(addstr(tmp, len, &buf, &buflen));
+
+ /* XXX need to dump key, print otherdata length & other data */
+ break;
+ }
+
+ case ns_t_tsig: {
+ /* BEW - need to complete this */
+ int n;
+
+ T(len = addname(msg, msglen, &rdata, origin, &buf, &buflen));
+ T(addstr(" ", 1, &buf, &buflen));
+ rdata += 8; /*%< time */
+ n = ns_get16(rdata); rdata += INT16SZ;
+ rdata += n; /*%< sig */
+ n = ns_get16(rdata); rdata += INT16SZ; /*%< original id */
+ sprintf(buf, "%d", ns_get16(rdata));
+ rdata += INT16SZ;
+ addlen(strlen(buf), &buf, &buflen);
+ break;
+ }
+
+ case ns_t_a6: {
+ struct in6_addr a;
+ int pbyte, pbit;
+
+ /* prefix length */
+ if (rdlen == 0U) goto formerr;
+ len = SPRINTF((tmp, "%d ", *rdata));
+ T(addstr(tmp, len, &buf, &buflen));
+ pbit = *rdata;
+ if (pbit > 128) goto formerr;
+ pbyte = (pbit & ~7) / 8;
+ rdata++;
+
+ /* address suffix: provided only when prefix len != 128 */
+ if (pbit < 128) {
+ if (rdata + pbyte >= edata) goto formerr;
+ memset(&a, 0, sizeof(a));
+ memcpy(&a.s6_addr[pbyte], rdata, sizeof(a) - pbyte);
+ (void) inet_ntop(AF_INET6, &a, buf, buflen);
+ addlen(strlen(buf), &buf, &buflen);
+ rdata += sizeof(a) - pbyte;
+ }
+
+ /* prefix name: provided only when prefix len > 0 */
+ if (pbit == 0)
+ break;
+ if (rdata >= edata) goto formerr;
+ T(addstr(" ", 1, &buf, &buflen));
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+
+ break;
+ }
+
+ case ns_t_opt: {
+ len = SPRINTF((tmp, "%u bytes", class));
+ T(addstr(tmp, len, &buf, &buflen));
+ break;
+ }
+
+ case ns_t_ds:
+ case ns_t_dlv:
+ case ns_t_sshfp: {
+ u_int t;
+
+ if (type == ns_t_ds || type == ns_t_dlv) {
+ if (rdlen < 4U) goto formerr;
+ t = ns_get16(rdata);
+ rdata += NS_INT16SZ;
+ len = SPRINTF((tmp, "%u ", t));
+ T(addstr(tmp, len, &buf, &buflen));
+ } else
+ if (rdlen < 2U) goto formerr;
+
+ len = SPRINTF((tmp, "%u ", *rdata));
+ T(addstr(tmp, len, &buf, &buflen));
+ rdata++;
+
+ len = SPRINTF((tmp, "%u ", *rdata));
+ T(addstr(tmp, len, &buf, &buflen));
+ rdata++;
+
+ while (rdata < edata) {
+ len = SPRINTF((tmp, "%02X", *rdata));
+ T(addstr(tmp, len, &buf, &buflen));
+ rdata++;
+ }
+ break;
+ }
+
+ case ns_t_nsec3:
+ case ns_t_nsec3param: {
+ u_int t, w, l, j, k, c;
+
+ len = SPRINTF((tmp, "%u ", *rdata));
+ T(addstr(tmp, len, &buf, &buflen));
+ rdata++;
+
+ len = SPRINTF((tmp, "%u ", *rdata));
+ T(addstr(tmp, len, &buf, &buflen));
+ rdata++;
+
+ t = ns_get16(rdata);
+ rdata += NS_INT16SZ;
+ len = SPRINTF((tmp, "%u ", t));
+ T(addstr(tmp, len, &buf, &buflen));
+
+ t = *rdata++;
+ if (t == 0) {
+ T(addstr("-", 1, &buf, &buflen));
+ } else {
+ while (t-- > 0) {
+ len = SPRINTF((tmp, "%02X", *rdata));
+ T(addstr(tmp, len, &buf, &buflen));
+ rdata++;
+ }
+ }
+ if (type == ns_t_nsec3param)
+ break;
+ T(addstr(" ", 1, &buf, &buflen));
+
+ t = *rdata++;
+ while (t > 0) {
+ switch (t) {
+ case 1:
+ tmp[0] = base32hex[((rdata[0]>>3)&0x1f)];
+ tmp[1] = base32hex[((rdata[0]<<2)&0x1c)];
+ tmp[2] = tmp[3] = tmp[4] = '=';
+ tmp[5] = tmp[6] = tmp[7] = '=';
+ break;
+ case 2:
+ tmp[0] = base32hex[((rdata[0]>>3)&0x1f)];
+ tmp[1] = base32hex[((rdata[0]<<2)&0x1c)|
+ ((rdata[1]>>6)&0x03)];
+ tmp[2] = base32hex[((rdata[1]>>1)&0x1f)];
+ tmp[3] = base32hex[((rdata[1]<<4)&0x10)];
+ tmp[4] = tmp[5] = tmp[6] = tmp[7] = '=';
+ break;
+ case 3:
+ tmp[0] = base32hex[((rdata[0]>>3)&0x1f)];
+ tmp[1] = base32hex[((rdata[0]<<2)&0x1c)|
+ ((rdata[1]>>6)&0x03)];
+ tmp[2] = base32hex[((rdata[1]>>1)&0x1f)];
+ tmp[3] = base32hex[((rdata[1]<<4)&0x10)|
+ ((rdata[2]>>4)&0x0f)];
+ tmp[4] = base32hex[((rdata[2]<<1)&0x1e)];
+ tmp[5] = tmp[6] = tmp[7] = '=';
+ break;
+ case 4:
+ tmp[0] = base32hex[((rdata[0]>>3)&0x1f)];
+ tmp[1] = base32hex[((rdata[0]<<2)&0x1c)|
+ ((rdata[1]>>6)&0x03)];
+ tmp[2] = base32hex[((rdata[1]>>1)&0x1f)];
+ tmp[3] = base32hex[((rdata[1]<<4)&0x10)|
+ ((rdata[2]>>4)&0x0f)];
+ tmp[4] = base32hex[((rdata[2]<<1)&0x1e)|
+ ((rdata[3]>>7)&0x01)];
+ tmp[5] = base32hex[((rdata[3]>>2)&0x1f)];
+ tmp[6] = base32hex[(rdata[3]<<3)&0x18];
+ tmp[7] = '=';
+ break;
+ default:
+ tmp[0] = base32hex[((rdata[0]>>3)&0x1f)];
+ tmp[1] = base32hex[((rdata[0]<<2)&0x1c)|
+ ((rdata[1]>>6)&0x03)];
+ tmp[2] = base32hex[((rdata[1]>>1)&0x1f)];
+ tmp[3] = base32hex[((rdata[1]<<4)&0x10)|
+ ((rdata[2]>>4)&0x0f)];
+ tmp[4] = base32hex[((rdata[2]<<1)&0x1e)|
+ ((rdata[3]>>7)&0x01)];
+ tmp[5] = base32hex[((rdata[3]>>2)&0x1f)];
+ tmp[6] = base32hex[((rdata[3]<<3)&0x18)|
+ ((rdata[4]>>5)&0x07)];
+ tmp[7] = base32hex[(rdata[4]&0x1f)];
+ break;
+ }
+ T(addstr(tmp, 8, &buf, &buflen));
+ if (t >= 5) {
+ rdata += 5;
+ t -= 5;
+ } else {
+ rdata += t;
+ t -= t;
+ }
+ }
+
+ while (rdata < edata) {
+ w = *rdata++;
+ l = *rdata++;
+ for (j = 0; j < l; j++) {
+ if (rdata[j] == 0)
+ continue;
+ for (k = 0; k < 8; k++) {
+ if ((rdata[j] & (0x80 >> k)) == 0)
+ continue;
+ c = w * 256 + j * 8 + k;
+ len = SPRINTF((tmp, " %s", p_type(c)));
+ T(addstr(tmp, len, &buf, &buflen));
+ }
+ }
+ rdata += l;
+ }
+ break;
+ }
+
+ case ns_t_nsec: {
+ u_int w, l, j, k, c;
+
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+
+ while (rdata < edata) {
+ w = *rdata++;
+ l = *rdata++;
+ for (j = 0; j < l; j++) {
+ if (rdata[j] == 0)
+ continue;
+ for (k = 0; k < 8; k++) {
+ if ((rdata[j] & (0x80 >> k)) == 0)
+ continue;
+ c = w * 256 + j * 8 + k;
+ len = SPRINTF((tmp, " %s", p_type(c)));
+ T(addstr(tmp, len, &buf, &buflen));
+ }
+ }
+ rdata += l;
+ }
+ break;
+ }
+
+ case ns_t_dhcid: {
+ int n;
+ unsigned int siz;
+ char base64_dhcid[8192];
+ const char *leader;
+
+ siz = (edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */
+ if (siz > sizeof(base64_dhcid) * 3/4) {
+ const char *str = "record too long to print";
+ T(addstr(str, strlen(str), &buf, &buflen));
+ } else {
+ len = b64_ntop(rdata, edata-rdata, base64_dhcid, siz);
+
+ if (len < 0)
+ goto formerr;
+
+ else if (len > 15) {
+ T(addstr(" (", 2, &buf, &buflen));
+ leader = "\n\t\t";
+ spaced = 0;
+ }
+ else
+ leader = " ";
+
+ for (n = 0; n < len; n += 48) {
+ T(addstr(leader, strlen(leader),
+ &buf, &buflen));
+ T(addstr(base64_dhcid + n, MIN(len - n, 48),
+ &buf, &buflen));
+ }
+ if (len > 15)
+ T(addstr(" )", 2, &buf, &buflen));
+ }
+ break;
+ }
+
+ case ns_t_ipseckey: {
+ int n;
+ unsigned int siz;
+ char base64_key[8192];
+ const char *leader;
+
+ if (rdlen < 2)
+ goto formerr;
+
+ switch (rdata[1]) {
+ case 0:
+ case 3:
+ if (rdlen < 3)
+ goto formerr;
+ break;
+ case 1:
+ if (rdlen < 7)
+ goto formerr;
+ break;
+ case 2:
+ if (rdlen < 19)
+ goto formerr;
+ break;
+ default:
+ comment = "unknown IPSECKEY gateway type";
+ goto hexify;
+ }
+
+ len = SPRINTF((tmp, "%u ", *rdata));
+ T(addstr(tmp, len, &buf, &buflen));
+ rdata++;
+
+ len = SPRINTF((tmp, "%u ", *rdata));
+ T(addstr(tmp, len, &buf, &buflen));
+ rdata++;
+
+ len = SPRINTF((tmp, "%u ", *rdata));
+ T(addstr(tmp, len, &buf, &buflen));
+ rdata++;
+
+ switch (rdata[-2]) {
+ case 0:
+ T(addstr(".", 1, &buf, &buflen));
+ break;
+ case 1:
+ (void) inet_ntop(AF_INET, rdata, buf, buflen);
+ addlen(strlen(buf), &buf, &buflen);
+ rdata += 4;
+ break;
+ case 2:
+ (void) inet_ntop(AF_INET6, rdata, buf, buflen);
+ addlen(strlen(buf), &buf, &buflen);
+ rdata += 16;
+ break;
+ case 3:
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+ break;
+ }
+
+ if (rdata >= edata)
+ break;
+
+ siz = (edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */
+ if (siz > sizeof(base64_key) * 3/4) {
+ const char *str = "record too long to print";
+ T(addstr(str, strlen(str), &buf, &buflen));
+ } else {
+ len = b64_ntop(rdata, edata-rdata, base64_key, siz);
+
+ if (len < 0)
+ goto formerr;
+
+ else if (len > 15) {
+ T(addstr(" (", 2, &buf, &buflen));
+ leader = "\n\t\t";
+ spaced = 0;
+ }
+ else
+ leader = " ";
+
+ for (n = 0; n < len; n += 48) {
+ T(addstr(leader, strlen(leader),
+ &buf, &buflen));
+ T(addstr(base64_key + n, MIN(len - n, 48),
+ &buf, &buflen));
+ }
+ if (len > 15)
+ T(addstr(" )", 2, &buf, &buflen));
+ }
+ }
+
+ case ns_t_hip: {
+ unsigned int i, hip_len, algorithm, key_len;
+ char base64_key[NS_MD5RSA_MAX_BASE64];
+ unsigned int siz;
+ const char *leader = "\n\t\t\t\t\t";
+
+ hip_len = *rdata++;
+ algorithm = *rdata++;
+ key_len = ns_get16(rdata);
+ rdata += NS_INT16SZ;
+
+ siz = key_len*4/3 + 4; /* "+4" accounts for trailing \0 */
+ if (siz > sizeof(base64_key) * 3/4) {
+ const char *str = "record too long to print";
+ T(addstr(str, strlen(str), &buf, &buflen));
+ } else {
+ len = sprintf(tmp, "( %u ", algorithm);
+ T(addstr(tmp, len, &buf, &buflen));
+
+ for (i = 0; i < hip_len; i++) {
+ len = sprintf(tmp, "%02X", *rdata);
+ T(addstr(tmp, len, &buf, &buflen));
+ rdata++;
+ }
+ T(addstr(leader, strlen(leader), &buf, &buflen));
+
+ len = b64_ntop(rdata, key_len, base64_key, siz);
+ if (len < 0)
+ goto formerr;
+
+ T(addstr(base64_key, len, &buf, &buflen));
+
+ rdata += key_len;
+ while (rdata < edata) {
+ T(addstr(leader, strlen(leader), &buf, &buflen));
+ T(addname(msg, msglen, &rdata, origin,
+ &buf, &buflen));
+ }
+ T(addstr(" )", 2, &buf, &buflen));
+ }
+ break;
+ }
+
+ default:
+ comment = "unknown RR type";
+ goto hexify;
+ }
+ return (buf - obuf);
+ formerr:
+ comment = "RR format error";
+ hexify: {
+ int n, m;
+ char *p;
+
+ len = SPRINTF((tmp, "\\# %u%s\t; %s", (unsigned)(edata - rdata),
+ rdlen != 0U ? " (" : "", comment));
+ T(addstr(tmp, len, &buf, &buflen));
+ while (rdata < edata) {
+ p = tmp;
+ p += SPRINTF((p, "\n\t"));
+ spaced = 0;
+ n = MIN(16, edata - rdata);
+ for (m = 0; m < n; m++)
+ p += SPRINTF((p, "%02x ", rdata[m]));
+ T(addstr(tmp, p - tmp, &buf, &buflen));
+ if (n < 16) {
+ T(addstr(")", 1, &buf, &buflen));
+ T(addtab(p - tmp + 1, 48, spaced, &buf, &buflen));
+ }
+ p = tmp;
+ p += SPRINTF((p, "; "));
+ for (m = 0; m < n; m++)
+ *p++ = (isascii(rdata[m]) && isprint(rdata[m]))
+ ? rdata[m]
+ : '.';
+ T(addstr(tmp, p - tmp, &buf, &buflen));
+ rdata += n;
+ }
+ return (buf - obuf);
+ }
+}
+
+/* Private. */
+
+/*%
+ * size_t
+ * prune_origin(name, origin)
+ * Find out if the name is at or under the current origin.
+ * return:
+ * Number of characters in name before start of origin,
+ * or length of name if origin does not match.
+ * notes:
+ * This function should share code with samedomain().
+ */
+static size_t
+prune_origin(const char *name, const char *origin) {
+ const char *oname = name;
+
+ while (*name != '\0') {
+ if (origin != NULL && ns_samename(name, origin) == 1)
+ return (name - oname - (name > oname));
+ while (*name != '\0') {
+ if (*name == '\\') {
+ name++;
+ /* XXX need to handle \nnn form. */
+ if (*name == '\0')
+ break;
+ } else if (*name == '.') {
+ name++;
+ break;
+ }
+ name++;
+ }
+ }
+ return (name - oname);
+}
+
+/*%
+ * int
+ * charstr(rdata, edata, buf, buflen)
+ * Format a <character-string> into the presentation buffer.
+ * return:
+ * Number of rdata octets consumed
+ * 0 for protocol format error
+ * -1 for output buffer error
+ * side effects:
+ * buffer is advanced on success.
+ */
+static int
+charstr(const u_char *rdata, const u_char *edata, char **buf, size_t *buflen) {
+ const u_char *odata = rdata;
+ size_t save_buflen = *buflen;
+ char *save_buf = *buf;
+
+ if (addstr("\"", 1, buf, buflen) < 0)
+ goto enospc;
+ if (rdata < edata) {
+ int n = *rdata;
+
+ if (rdata + 1 + n <= edata) {
+ rdata++;
+ while (n-- > 0) {
+ if (strchr("\n\"\\", *rdata) != NULL)
+ if (addstr("\\", 1, buf, buflen) < 0)
+ goto enospc;
+ if (addstr((const char *)rdata, 1,
+ buf, buflen) < 0)
+ goto enospc;
+ rdata++;
+ }
+ }
+ }
+ if (addstr("\"", 1, buf, buflen) < 0)
+ goto enospc;
+ return (rdata - odata);
+ enospc:
+ errno = ENOSPC;
+ *buf = save_buf;
+ *buflen = save_buflen;
+ return (-1);
+}
+
+static int
+addname(const u_char *msg, size_t msglen,
+ const u_char **pp, const char *origin,
+ char **buf, size_t *buflen)
+{
+ size_t newlen, save_buflen = *buflen;
+ char *save_buf = *buf;
+ int n;
+
+ n = dn_expand(msg, msg + msglen, *pp, *buf, *buflen);
+ if (n < 0)
+ goto enospc; /*%< Guess. */
+ newlen = prune_origin(*buf, origin);
+ if (**buf == '\0') {
+ goto root;
+ } else if (newlen == 0U) {
+ /* Use "@" instead of name. */
+ if (newlen + 2 > *buflen)
+ goto enospc; /* No room for "@\0". */
+ (*buf)[newlen++] = '@';
+ (*buf)[newlen] = '\0';
+ } else {
+ if (((origin == NULL || origin[0] == '\0') ||
+ (origin[0] != '.' && origin[1] != '\0' &&
+ (*buf)[newlen] == '\0')) && (*buf)[newlen - 1] != '.') {
+ /* No trailing dot. */
+ root:
+ if (newlen + 2 > *buflen)
+ goto enospc; /* No room for ".\0". */
+ (*buf)[newlen++] = '.';
+ (*buf)[newlen] = '\0';
+ }
+ }
+ *pp += n;
+ addlen(newlen, buf, buflen);
+ **buf = '\0';
+ return (newlen);
+ enospc:
+ errno = ENOSPC;
+ *buf = save_buf;
+ *buflen = save_buflen;
+ return (-1);
+}
+
+static void
+addlen(size_t len, char **buf, size_t *buflen) {
+ INSIST(len <= *buflen);
+ *buf += len;
+ *buflen -= len;
+}
+
+static int
+addstr(const char *src, size_t len, char **buf, size_t *buflen) {
+ if (len >= *buflen) {
+ errno = ENOSPC;
+ return (-1);
+ }
+ memcpy(*buf, src, len);
+ addlen(len, buf, buflen);
+ **buf = '\0';
+ return (0);
+}
+
+static int
+addtab(size_t len, size_t target, int spaced, char **buf, size_t *buflen) {
+ size_t save_buflen = *buflen;
+ char *save_buf = *buf;
+ int t;
+
+ if (spaced || len >= target - 1) {
+ T(addstr(" ", 2, buf, buflen));
+ spaced = 1;
+ } else {
+ for (t = (target - len - 1) / 8; t >= 0; t--)
+ if (addstr("\t", 1, buf, buflen) < 0) {
+ *buflen = save_buflen;
+ *buf = save_buf;
+ return (-1);
+ }
+ spaced = 0;
+ }
+ return (spaced);
+}
+
+/*! \file */
diff --git a/lib/libc/nameser/ns_samedomain.c b/lib/libc/nameser/ns_samedomain.c
new file mode 100644
index 000000000000..549b773cd9a7
--- /dev/null
+++ b/lib/libc/nameser/ns_samedomain.c
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1995,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id: ns_samedomain.c,v 1.6 2005/04/27 04:56:40 sra Exp $";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <arpa/nameser.h>
+#include <errno.h>
+#include <string.h>
+
+#include "port_after.h"
+
+/*%
+ * Check whether a name belongs to a domain.
+ *
+ * Inputs:
+ *\li a - the domain whose ancestry is being verified
+ *\li b - the potential ancestor we're checking against
+ *
+ * Return:
+ *\li boolean - is a at or below b?
+ *
+ * Notes:
+ *\li Trailing dots are first removed from name and domain.
+ * Always compare complete subdomains, not only whether the
+ * domain name is the trailing string of the given name.
+ *
+ *\li "host.foobar.top" lies in "foobar.top" and in "top" and in ""
+ * but NOT in "bar.top"
+ */
+
+int
+ns_samedomain(const char *a, const char *b) {
+ size_t la, lb;
+ int diff, i, escaped;
+ const char *cp;
+
+ la = strlen(a);
+ lb = strlen(b);
+
+ /* Ignore a trailing label separator (i.e. an unescaped dot) in 'a'. */
+ if (la != 0U && a[la - 1] == '.') {
+ escaped = 0;
+ /* Note this loop doesn't get executed if la==1. */
+ for (i = la - 2; i >= 0; i--)
+ if (a[i] == '\\') {
+ if (escaped)
+ escaped = 0;
+ else
+ escaped = 1;
+ } else
+ break;
+ if (!escaped)
+ la--;
+ }
+
+ /* Ignore a trailing label separator (i.e. an unescaped dot) in 'b'. */
+ if (lb != 0U && b[lb - 1] == '.') {
+ escaped = 0;
+ /* note this loop doesn't get executed if lb==1 */
+ for (i = lb - 2; i >= 0; i--)
+ if (b[i] == '\\') {
+ if (escaped)
+ escaped = 0;
+ else
+ escaped = 1;
+ } else
+ break;
+ if (!escaped)
+ lb--;
+ }
+
+ /* lb == 0 means 'b' is the root domain, so 'a' must be in 'b'. */
+ if (lb == 0U)
+ return (1);
+
+ /* 'b' longer than 'a' means 'a' can't be in 'b'. */
+ if (lb > la)
+ return (0);
+
+ /* 'a' and 'b' being equal at this point indicates sameness. */
+ if (lb == la)
+ return (strncasecmp(a, b, lb) == 0);
+
+ /* Ok, we know la > lb. */
+
+ diff = la - lb;
+
+ /*
+ * If 'a' is only 1 character longer than 'b', then it can't be
+ * a subdomain of 'b' (because of the need for the '.' label
+ * separator).
+ */
+ if (diff < 2)
+ return (0);
+
+ /*
+ * If the character before the last 'lb' characters of 'b'
+ * isn't '.', then it can't be a match (this lets us avoid
+ * having "foobar.com" match "bar.com").
+ */
+ if (a[diff - 1] != '.')
+ return (0);
+
+ /*
+ * We're not sure about that '.', however. It could be escaped
+ * and thus not a really a label separator.
+ */
+ escaped = 0;
+ for (i = diff - 2; i >= 0; i--)
+ if (a[i] == '\\') {
+ if (escaped)
+ escaped = 0;
+ else
+ escaped = 1;
+ } else
+ break;
+ if (escaped)
+ return (0);
+
+ /* Now compare aligned trailing substring. */
+ cp = a + diff;
+ return (strncasecmp(cp, b, lb) == 0);
+}
+
+#ifndef _LIBC
+/*%
+ * is "a" a subdomain of "b"?
+ */
+int
+ns_subdomain(const char *a, const char *b) {
+ return (ns_samename(a, b) != 1 && ns_samedomain(a, b));
+}
+#endif
+
+/*%
+ * make a canonical copy of domain name "src"
+ *
+ * notes:
+ * \code
+ * foo -> foo.
+ * foo. -> foo.
+ * foo.. -> foo.
+ * foo\. -> foo\..
+ * foo\\. -> foo\\.
+ * \endcode
+ */
+
+int
+ns_makecanon(const char *src, char *dst, size_t dstsize) {
+ size_t n = strlen(src);
+
+ if (n + sizeof "." > dstsize) { /*%< Note: sizeof == 2 */
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ strcpy(dst, src);
+ while (n >= 1U && dst[n - 1] == '.') /*%< Ends in "." */
+ if (n >= 2U && dst[n - 2] == '\\' && /*%< Ends in "\." */
+ (n < 3U || dst[n - 3] != '\\')) /*%< But not "\\." */
+ break;
+ else
+ dst[--n] = '\0';
+ dst[n++] = '.';
+ dst[n] = '\0';
+ return (0);
+}
+
+/*%
+ * determine whether domain name "a" is the same as domain name "b"
+ *
+ * return:
+ *\li -1 on error
+ *\li 0 if names differ
+ *\li 1 if names are the same
+ */
+
+int
+ns_samename(const char *a, const char *b) {
+ char ta[NS_MAXDNAME], tb[NS_MAXDNAME];
+
+ if (ns_makecanon(a, ta, sizeof ta) < 0 ||
+ ns_makecanon(b, tb, sizeof tb) < 0)
+ return (-1);
+ if (strcasecmp(ta, tb) == 0)
+ return (1);
+ else
+ return (0);
+}
+
+/*! \file */
diff --git a/lib/libc/nameser/ns_ttl.c b/lib/libc/nameser/ns_ttl.c
new file mode 100644
index 000000000000..da7df67bf52f
--- /dev/null
+++ b/lib/libc/nameser/ns_ttl.c
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id: ns_ttl.c,v 1.4 2005/07/28 06:51:49 marka Exp $";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/* Import. */
+
+#include "port_before.h"
+
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "port_after.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) ((size_t)sprintf x)
+#endif
+
+/* Forward. */
+
+static int fmt1(int t, char s, char **buf, size_t *buflen);
+
+/* Macros. */
+
+#define T(x) if ((x) < 0) return (-1); else (void)NULL
+
+/* Public. */
+
+int
+ns_format_ttl(u_long src, char *dst, size_t dstlen) {
+ char *odst = dst;
+ int secs, mins, hours, days, weeks, x;
+ char *p;
+
+ secs = src % 60; src /= 60;
+ mins = src % 60; src /= 60;
+ hours = src % 24; src /= 24;
+ days = src % 7; src /= 7;
+ weeks = src; src = 0;
+
+ x = 0;
+ if (weeks) {
+ T(fmt1(weeks, 'W', &dst, &dstlen));
+ x++;
+ }
+ if (days) {
+ T(fmt1(days, 'D', &dst, &dstlen));
+ x++;
+ }
+ if (hours) {
+ T(fmt1(hours, 'H', &dst, &dstlen));
+ x++;
+ }
+ if (mins) {
+ T(fmt1(mins, 'M', &dst, &dstlen));
+ x++;
+ }
+ if (secs || !(weeks || days || hours || mins)) {
+ T(fmt1(secs, 'S', &dst, &dstlen));
+ x++;
+ }
+
+ if (x > 1) {
+ int ch;
+
+ for (p = odst; (ch = *p) != '\0'; p++)
+ if (isascii(ch) && isupper(ch))
+ *p = tolower(ch);
+ }
+
+ return (dst - odst);
+}
+
+int
+ns_parse_ttl(const char *src, u_long *dst) {
+ u_long ttl, tmp;
+ int ch, digits, dirty;
+
+ ttl = 0;
+ tmp = 0;
+ digits = 0;
+ dirty = 0;
+ while ((ch = *src++) != '\0') {
+ if (!isascii(ch) || !isprint(ch))
+ goto einval;
+ if (isdigit(ch)) {
+ tmp *= 10;
+ tmp += (ch - '0');
+ digits++;
+ continue;
+ }
+ if (digits == 0)
+ goto einval;
+ if (islower(ch))
+ ch = toupper(ch);
+ switch (ch) {
+ case 'W': tmp *= 7;
+ case 'D': tmp *= 24;
+ case 'H': tmp *= 60;
+ case 'M': tmp *= 60;
+ case 'S': break;
+ default: goto einval;
+ }
+ ttl += tmp;
+ tmp = 0;
+ digits = 0;
+ dirty = 1;
+ }
+ if (digits > 0) {
+ if (dirty)
+ goto einval;
+ else
+ ttl += tmp;
+ } else if (!dirty)
+ goto einval;
+ *dst = ttl;
+ return (0);
+
+ einval:
+ errno = EINVAL;
+ return (-1);
+}
+
+/* Private. */
+
+static int
+fmt1(int t, char s, char **buf, size_t *buflen) {
+ char tmp[50];
+ size_t len;
+
+ len = SPRINTF((tmp, "%d%c", t, s));
+ if (len + 1 > *buflen)
+ return (-1);
+ strcpy(*buf, tmp);
+ *buf += len;
+ *buflen -= len;
+ return (0);
+}
+
+/*! \file */
diff --git a/lib/libc/net/Makefile.inc b/lib/libc/net/Makefile.inc
new file mode 100644
index 000000000000..304c465b8545
--- /dev/null
+++ b/lib/libc/net/Makefile.inc
@@ -0,0 +1,125 @@
+# from @(#)Makefile.inc 8.2 (Berkeley) 9/5/93
+# $FreeBSD$
+
+# machine-independent net sources
+.PATH: ${LIBC_SRCTOP}/net
+
+SRCS+= base64.c ether_addr.c eui64.c \
+ gai_strerror.c getaddrinfo.c \
+ gethostbydns.c gethostbyht.c gethostbynis.c gethostnamadr.c \
+ getifaddrs.c getifmaddrs.c getnameinfo.c \
+ getnetbydns.c getnetbyht.c getnetbynis.c getnetnamadr.c \
+ getproto.c getprotoent.c getprotoname.c getservent.c \
+ if_indextoname.c if_nameindex.c if_nametoindex.c \
+ ip6opt.c linkaddr.c map_v4v6.c name6.c ntoh.c \
+ nsdispatch.c nslexer.l nsparser.y nss_compat.c \
+ rcmd.c rcmdsh.c recv.c rthdr.c sctp_sys_calls.c send.c \
+ sockatmark.c sourcefilter.c vars.c
+
+.if ${MK_NS_CACHING} != "no"
+SRCS+= nscache.c nscachedcli.c
+.endif
+
+SYM_MAPS+=${LIBC_SRCTOP}/net/Symbol.map
+
+.if ${MK_INET6_SUPPORT} != "no"
+CFLAGS+=-DINET6
+.endif
+
+CFLAGS+=-I${.OBJDIR}
+
+# name6.c refers res_private.h
+CFLAGS+=-I${LIBC_SRCTOP}/resolv
+
+YFLAGS+=-p_nsyy
+LFLAGS+=-P_nsyy
+
+CFLAGS.nslexer.c= -DYY_BUF_SIZE=1024
+
+MAN+= byteorder.3 ethers.3 eui64.3 \
+ getaddrinfo.3 gai_strerror.3 gethostbyname.3 \
+ getifaddrs.3 getifmaddrs.3 getipnodebyname.3 \
+ getnameinfo.3 getnetent.3 getprotoent.3 getservent.3 \
+ if_indextoname.3 \
+ inet.3 inet_net.3 \
+ inet6_opt_init.3 inet6_option_space.3 inet6_rth_space.3 \
+ inet6_rthdr_space.3 linkaddr.3 \
+ nsdispatch.3 rcmd.3 rcmdsh.3 resolver.3 sockatmark.3 \
+ sourcefilter.3 \
+ sctp_bindx.3 sctp_connectx.3 sctp_freepaddrs.3 \
+ sctp_getaddrlen.3 sctp_getassocid.3 sctp_getpaddrs.3 \
+ sctp_opt_info.3 sctp_recvmsg.3 sctp_send.3 sctp_sendmsg.3 \
+
+MLINKS+=byteorder.3 htonl.3 byteorder.3 htons.3 byteorder.3 ntohl.3 \
+ byteorder.3 ntohs.3
+MLINKS+=ethers.3 ether_aton.3 ethers.3 ether_hostton.3 ethers.3 ether_line.3 \
+ ethers.3 ether_ntoa.3 ethers.3 ether_ntohost.3
+MLINKS+=eui64.3 eui64_aton.3 eui64.3 eui64_hostton.3 \
+ eui64.3 eui64_ntoa.3 eui64.3 eui64_ntohost.3
+MLINKS+=getaddrinfo.3 freeaddrinfo.3
+MLINKS+=gethostbyname.3 endhostent.3 gethostbyname.3 gethostbyaddr.3 \
+ gethostbyname.3 gethostbyname2.3 gethostbyname.3 gethostent.3 \
+ gethostbyname.3 herror.3 gethostbyname.3 hstrerror.3 \
+ gethostbyname.3 sethostent.3
+MLINKS+=getifaddrs.3 freeifaddrs.3
+MLINKS+=getifmaddrs.3 freeifmaddrs.3
+MLINKS+=getipnodebyname.3 getipnodebyaddr.3 getipnodebyname.3 freehostent.3
+MLINKS+=getnetent.3 endnetent.3 getnetent.3 getnetbyaddr.3 \
+ getnetent.3 getnetbyname.3 getnetent.3 setnetent.3
+MLINKS+=getprotoent.3 endprotoent.3 getprotoent.3 getprotobyname.3 \
+ getprotoent.3 getprotobynumber.3 getprotoent.3 setprotoent.3
+MLINKS+=getservent.3 endservent.3 getservent.3 getservbyname.3 \
+ getservent.3 getservbyport.3 getservent.3 setservent.3
+MLINKS+=if_indextoname.3 if_nametoindex.3 if_indextoname.3 if_nameindex.3 \
+ if_indextoname.3 if_freenameindex.3
+MLINKS+=inet.3 addr.3 inet.3 inet_addr.3 inet.3 inet_aton.3 \
+ inet.3 inet_lnaof.3 inet.3 inet_makeaddr.3 inet.3 inet_netof.3 \
+ inet.3 inet_network.3 inet.3 inet_ntoa.3 inet.3 inet_ntoa_r.3\
+ inet.3 inet_ntop.3 inet.3 inet_pton.3 \
+ inet.3 network.3 inet.3 ntoa.3
+MLINKS+= sctp_send.3 sctp_sendx.3
+MLINKS+= sctp_sendmsg.3 sctp_sendmsgx.3
+MLINKS+= sctp_freepaddrs.3 sctp_freeladdrs.3
+MLINKS+= sctp_getpaddrs.3 sctp_getladdrs.3
+MLINKS+=inet_net.3 inet_net_ntop.3 inet_net.3 inet_net_pton.3
+MLINKS+=inet6_opt_init.3 inet6_opt_append.3 \
+ inet6_opt_init.3 inet6_opt_find.3 \
+ inet6_opt_init.3 inet6_opt_finish.3 \
+ inet6_opt_init.3 inet6_opt_get_val.3 \
+ inet6_opt_init.3 inet6_opt_next.3 \
+ inet6_opt_init.3 inet6_opt_set_val.3 \
+ inet6_option_space.3 inet6_option_alloc.3 \
+ inet6_option_space.3 inet6_option_append.3 \
+ inet6_option_space.3 inet6_option_find.3 \
+ inet6_option_space.3 inet6_option_init.3 \
+ inet6_option_space.3 inet6_option_next.3 \
+ inet6_rth_space.3 inet6_rth_add.3 \
+ inet6_rth_space.3 inet6_rth_getaddr.3 \
+ inet6_rth_space.3 inet6_rth_init.3 \
+ inet6_rth_space.3 inet6_rth_reverse.3 \
+ inet6_rth_space.3 inet6_rth_segments.3 \
+ inet6_rthdr_space.3 inet6_rthdr_add.3 \
+ inet6_rthdr_space.3 inet6_rthdr_getaddr.3 \
+ inet6_rthdr_space.3 inet6_rthdr_getflags.3 \
+ inet6_rthdr_space.3 inet6_rthdr_init.3 \
+ inet6_rthdr_space.3 inet6_rthdr_lasthop.3 \
+ inet6_rthdr_space.3 inet6_rthdr_reverse.3 \
+ inet6_rthdr_space.3 inet6_rthdr_segments.3
+MLINKS+=linkaddr.3 link_addr.3 linkaddr.3 link_ntoa.3
+MLINKS+=rcmd.3 iruserok.3 rcmd.3 iruserok_sa.3 \
+ rcmd.3 rcmd_af.3 \
+ rcmd.3 rresvport.3 rcmd.3 rresvport_af.3 \
+ rcmd.3 ruserok.3
+MLINKS+=resolver.3 dn_comp.3 resolver.3 dn_expand.3 resolver.3 res_init.3 \
+ resolver.3 res_mkquery.3 resolver.3 res_query.3 \
+ resolver.3 res_search.3 resolver.3 res_send.3 resolver.3 dn_skipname.3 \
+ resolver.3 ns_get16.3 resolver.3 ns_get32.3 \
+ resolver.3 ns_put16.3 resolver.3 ns_put32.3
+MLINKS+=sourcefilter.3 setipv4sourcefilter.3 sourcefilter.3 getipv4sourcefilter.3 \
+ sourcefilter.3 setsourcefilter.3 sourcefilter.3 getsourcefilter.3
+
+.if ${MK_HESIOD} != "no"
+SRCS+= hesiod.c
+MAN+= hesiod.3
+.endif
+
diff --git a/lib/libc/net/Symbol.map b/lib/libc/net/Symbol.map
new file mode 100644
index 000000000000..01d3bcb888d0
--- /dev/null
+++ b/lib/libc/net/Symbol.map
@@ -0,0 +1,174 @@
+/*
+ * $FreeBSD$
+ */
+
+FBSD_1.0 {
+ __b64_ntop;
+ __b64_pton;
+ ether_line;
+ ether_aton;
+ ether_aton_r;
+ ether_ntoa;
+ ether_ntoa_r;
+ ether_ntohost;
+ ether_hostton;
+ eui64_aton;
+ eui64_ntoa;
+ eui64_ntohost;
+ eui64_hostton;
+ gai_strerror;
+ freeaddrinfo;
+ getaddrinfo;
+ gethostent;
+ gethostent_r;
+ gethostbyname;
+ gethostbyname_r;
+ gethostbyname2;
+ gethostbyname2_r;
+ gethostbyaddr;
+ gethostbyaddr_r;
+ sethostent;
+ endhostent;
+ getifaddrs;
+ freeifaddrs;
+ getifmaddrs;
+ freeifmaddrs;
+ getnameinfo;
+ getnetent;
+ getnetent_r;
+ getnetbyname;
+ getnetbyname_r;
+ getnetbyaddr;
+ getnetbyaddr_r;
+ setnetent;
+ endnetent;
+ getprotobynumber;
+ getprotobynumber_r;
+ setprotoent;
+ endprotoent;
+ getprotoent;
+ getprotoent_r;
+ getprotobyname;
+ getprotobyname_r;
+ getservbyname;
+ getservbyname_r;
+ getservbyport;
+ getservbyport_r;
+ setservent;
+ endservent;
+ getservent;
+ getservent_r;
+ hesiod_init;
+ hesiod_end;
+ hesiod_to_bind;
+ hesiod_resolve;
+ hesiod_free_list;
+ hes_init;
+ hes_to_bind;
+ hes_resolve;
+ hes_error;
+ hes_free;
+ if_indextoname;
+ if_nameindex;
+ if_freenameindex;
+ if_nametoindex;
+ inet6_option_space;
+ inet6_option_init;
+ inet6_option_append;
+ inet6_option_alloc;
+ inet6_option_next;
+ inet6_option_find;
+ inet6_opt_init;
+ inet6_opt_append;
+ inet6_opt_finish;
+ inet6_opt_set_val;
+ inet6_opt_next;
+ inet6_opt_find;
+ inet6_opt_get_val;
+ link_addr;
+ link_ntoa;
+ getipnodebyname;
+ getipnodebyaddr;
+ freehostent;
+ __nsdefaultsrc;
+ _nsdbtaddsrc;
+ _nsdbtdump;
+ _nsdbtput;
+ nsdispatch;
+ rcmd;
+ rcmd_af;
+ rresvport;
+ rresvport_af;
+ ruserok;
+ iruserok;
+ iruserok_sa;
+ rcmdsh;
+ recv;
+ inet6_rthdr_space;
+ inet6_rthdr_init;
+ inet6_rthdr_add;
+ inet6_rthdr_lasthop;
+ inet6_rthdr_segments;
+ inet6_rthdr_getaddr;
+ inet6_rthdr_getflags;
+ inet6_rth_space;
+ inet6_rth_init;
+ inet6_rth_add;
+ inet6_rth_reverse;
+ inet6_rth_segments;
+ inet6_rth_getaddr;
+ send;
+ sockatmark;
+ in6addr_any;
+ in6addr_loopback;
+ in6addr_nodelocal_allnodes;
+ in6addr_linklocal_allnodes;
+ sctp_getaddrlen;
+ sctp_getassocid;
+ sctp_bindx;
+ sctp_connectx;
+ sctp_peeloff;
+ sctp_opt_info;
+ sctp_getpaddrs;
+ sctp_freepaddrs;
+ sctp_getladdrs;
+ sctp_freeladdrs;
+ sctp_sendmsg;
+ sctp_sendmsgx;
+ sctp_send;
+ sctp_sendx;
+ sctp_recvmsg;
+ setipv4sourcefilter;
+ getipv4sourcefilter;
+ getsourcefilter;
+ setsourcefilter;
+};
+
+FBSD_1.3 {
+ sctp_recvv;
+ sctp_sendv;
+};
+
+FBSDprivate_1.0 {
+ _nsdispatch;
+ _nsyyerror; /* generated from nslexer.l */
+ _nsyylex; /* generated from nslexer.l */
+ _nsyyparse; /* generated from nsparser.y */
+ _nsyylineno; /* generated from nsparser.y */
+ __dns_getanswer;
+ __ivaliduser;
+ __ivaliduser_af;
+ __ivaliduser_sa;
+ __check_rhosts_file;
+ __rcmd_errstr;
+ __nss_compat_getgrnam_r;
+ __nss_compat_getgrgid_r;
+ __nss_compat_getgrent_r;
+ __nss_compat_setgrent;
+ __nss_compat_endgrent;
+ __nss_compat_getpwnam_r;
+ __nss_compat_getpwuid_r;
+ __nss_compat_getpwent_r;
+ __nss_compat_setpwent;
+ __nss_compat_endpwent;
+};
diff --git a/lib/libc/net/base64.c b/lib/libc/net/base64.c
new file mode 100644
index 000000000000..998c3c213834
--- /dev/null
+++ b/lib/libc/net/base64.c
@@ -0,0 +1,319 @@
+/*
+ * Copyright (c) 1996, 1998 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*
+ * Portions Copyright (c) 1995 by International Business Machines, Inc.
+ *
+ * International Business Machines, Inc. (hereinafter called IBM) grants
+ * permission under its copyrights to use, copy, modify, and distribute this
+ * Software with or without fee, provided that the above copyright notice and
+ * all paragraphs of this notice appear in all copies, and that the name of IBM
+ * not be used in connection with the marketing of any product incorporating
+ * the Software or modifications thereof, without specific, written prior
+ * permission.
+ *
+ * To the extent it has a right to do so, IBM grants an immunity from suit
+ * under its patents, if any, for the use, sale or manufacture of products to
+ * the extent that such products are used for performing Domain Name System
+ * dynamic updates in TCP/IP networks by means of the Software. No immunity is
+ * granted for any product per se or for any other function of any product.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
+ * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
+ * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define Assert(Cond) if (!(Cond)) abort()
+
+static const char Base64[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+static const char Pad64 = '=';
+
+/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt)
+ The following encoding technique is taken from RFC 1521 by Borenstein
+ and Freed. It is reproduced here in a slightly edited form for
+ convenience.
+
+ A 65-character subset of US-ASCII is used, enabling 6 bits to be
+ represented per printable character. (The extra 65th character, "=",
+ is used to signify a special processing function.)
+
+ The encoding process represents 24-bit groups of input bits as output
+ strings of 4 encoded characters. Proceeding from left to right, a
+ 24-bit input group is formed by concatenating 3 8-bit input groups.
+ These 24 bits are then treated as 4 concatenated 6-bit groups, each
+ of which is translated into a single digit in the base64 alphabet.
+
+ Each 6-bit group is used as an index into an array of 64 printable
+ characters. The character referenced by the index is placed in the
+ output string.
+
+ Table 1: The Base64 Alphabet
+
+ Value Encoding Value Encoding Value Encoding Value Encoding
+ 0 A 17 R 34 i 51 z
+ 1 B 18 S 35 j 52 0
+ 2 C 19 T 36 k 53 1
+ 3 D 20 U 37 l 54 2
+ 4 E 21 V 38 m 55 3
+ 5 F 22 W 39 n 56 4
+ 6 G 23 X 40 o 57 5
+ 7 H 24 Y 41 p 58 6
+ 8 I 25 Z 42 q 59 7
+ 9 J 26 a 43 r 60 8
+ 10 K 27 b 44 s 61 9
+ 11 L 28 c 45 t 62 +
+ 12 M 29 d 46 u 63 /
+ 13 N 30 e 47 v
+ 14 O 31 f 48 w (pad) =
+ 15 P 32 g 49 x
+ 16 Q 33 h 50 y
+
+ Special processing is performed if fewer than 24 bits are available
+ at the end of the data being encoded. A full encoding quantum is
+ always completed at the end of a quantity. When fewer than 24 input
+ bits are available in an input group, zero bits are added (on the
+ right) to form an integral number of 6-bit groups. Padding at the
+ end of the data is performed using the '=' character.
+
+ Since all base64 input is an integral number of octets, only the
+ -------------------------------------------------
+ following cases can arise:
+
+ (1) the final quantum of encoding input is an integral
+ multiple of 24 bits; here, the final unit of encoded
+ output will be an integral multiple of 4 characters
+ with no "=" padding,
+ (2) the final quantum of encoding input is exactly 8 bits;
+ here, the final unit of encoded output will be two
+ characters followed by two "=" padding characters, or
+ (3) the final quantum of encoding input is exactly 16 bits;
+ here, the final unit of encoded output will be three
+ characters followed by one "=" padding character.
+ */
+
+int
+b64_ntop(u_char const *src, size_t srclength, char *target, size_t targsize) {
+ size_t datalength = 0;
+ u_char input[3];
+ u_char output[4];
+ size_t i;
+
+ while (2 < srclength) {
+ input[0] = *src++;
+ input[1] = *src++;
+ input[2] = *src++;
+ srclength -= 3;
+
+ output[0] = input[0] >> 2;
+ output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
+ output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
+ output[3] = input[2] & 0x3f;
+ Assert(output[0] < 64);
+ Assert(output[1] < 64);
+ Assert(output[2] < 64);
+ Assert(output[3] < 64);
+
+ if (datalength + 4 > targsize)
+ return (-1);
+ target[datalength++] = Base64[output[0]];
+ target[datalength++] = Base64[output[1]];
+ target[datalength++] = Base64[output[2]];
+ target[datalength++] = Base64[output[3]];
+ }
+
+ /* Now we worry about padding. */
+ if (0 != srclength) {
+ /* Get what's left. */
+ input[0] = input[1] = input[2] = '\0';
+ for (i = 0; i < srclength; i++)
+ input[i] = *src++;
+
+ output[0] = input[0] >> 2;
+ output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
+ output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
+ Assert(output[0] < 64);
+ Assert(output[1] < 64);
+ Assert(output[2] < 64);
+
+ if (datalength + 4 > targsize)
+ return (-1);
+ target[datalength++] = Base64[output[0]];
+ target[datalength++] = Base64[output[1]];
+ if (srclength == 1)
+ target[datalength++] = Pad64;
+ else
+ target[datalength++] = Base64[output[2]];
+ target[datalength++] = Pad64;
+ }
+ if (datalength >= targsize)
+ return (-1);
+ target[datalength] = '\0'; /* Returned value doesn't count \0. */
+ return (datalength);
+}
+
+/* skips all whitespace anywhere.
+ converts characters, four at a time, starting at (or after)
+ src from base - 64 numbers into three 8 bit bytes in the target area.
+ it returns the number of data bytes stored at the target, or -1 on error.
+ */
+
+int
+b64_pton(const char *src, u_char *target, size_t targsize)
+{
+ int tarindex, state, ch;
+ u_char nextbyte;
+ char *pos;
+
+ state = 0;
+ tarindex = 0;
+
+ while ((ch = *src++) != '\0') {
+ if (isspace((unsigned char)ch)) /* Skip whitespace anywhere. */
+ continue;
+
+ if (ch == Pad64)
+ break;
+
+ pos = strchr(Base64, ch);
+ if (pos == NULL) /* A non-base64 character. */
+ return (-1);
+
+ switch (state) {
+ case 0:
+ if (target) {
+ if ((size_t)tarindex >= targsize)
+ return (-1);
+ target[tarindex] = (pos - Base64) << 2;
+ }
+ state = 1;
+ break;
+ case 1:
+ if (target) {
+ if ((size_t)tarindex >= targsize)
+ return (-1);
+ target[tarindex] |= (pos - Base64) >> 4;
+ nextbyte = ((pos - Base64) & 0x0f) << 4;
+ if ((size_t)tarindex + 1 < targsize)
+ target[tarindex + 1] = nextbyte;
+ else if (nextbyte)
+ return (-1);
+ }
+ tarindex++;
+ state = 2;
+ break;
+ case 2:
+ if (target) {
+ if ((size_t)tarindex >= targsize)
+ return (-1);
+ target[tarindex] |= (pos - Base64) >> 2;
+ nextbyte = ((pos - Base64) & 0x03) << 6;
+ if ((size_t)tarindex + 1 < targsize)
+ target[tarindex + 1] = nextbyte;
+ else if (nextbyte)
+ return (-1);
+ }
+ tarindex++;
+ state = 3;
+ break;
+ case 3:
+ if (target) {
+ if ((size_t)tarindex >= targsize)
+ return (-1);
+ target[tarindex] |= (pos - Base64);
+ }
+ tarindex++;
+ state = 0;
+ break;
+ default:
+ abort();
+ }
+ }
+
+ /*
+ * We are done decoding Base-64 chars. Let's see if we ended
+ * on a byte boundary, and/or with erroneous trailing characters.
+ */
+
+ if (ch == Pad64) { /* We got a pad char. */
+ ch = *src++; /* Skip it, get next. */
+ switch (state) {
+ case 0: /* Invalid = in first position */
+ case 1: /* Invalid = in second position */
+ return (-1);
+
+ case 2: /* Valid, means one byte of info */
+ /* Skip any number of spaces. */
+ for ((void)NULL; ch != '\0'; ch = *src++)
+ if (!isspace((unsigned char)ch))
+ break;
+ /* Make sure there is another trailing = sign. */
+ if (ch != Pad64)
+ return (-1);
+ ch = *src++; /* Skip the = */
+ /* Fall through to "single trailing =" case. */
+ /* FALLTHROUGH */
+
+ case 3: /* Valid, means two bytes of info */
+ /*
+ * We know this char is an =. Is there anything but
+ * whitespace after it?
+ */
+ for ((void)NULL; ch != '\0'; ch = *src++)
+ if (!isspace((unsigned char)ch))
+ return (-1);
+
+ /*
+ * Now make sure for cases 2 and 3 that the "extra"
+ * bits that slopped past the last full byte were
+ * zeros. If we don't check them, they become a
+ * subliminal channel.
+ */
+ if (target && (size_t)tarindex < targsize &&
+ target[tarindex] != 0)
+ return (-1);
+ }
+ } else {
+ /*
+ * We ended by seeing the end of the string. Make sure we
+ * have no partial bytes lying around.
+ */
+ if (state != 0)
+ return (-1);
+ }
+
+ return (tarindex);
+}
diff --git a/lib/libc/net/byteorder.3 b/lib/libc/net/byteorder.3
new file mode 100644
index 000000000000..ebb56d8c23a9
--- /dev/null
+++ b/lib/libc/net/byteorder.3
@@ -0,0 +1,86 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)byteorder.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd March 20, 2005
+.Dt BYTEORDER 3
+.Os
+.Sh NAME
+.Nm htonl ,
+.Nm htons ,
+.Nm ntohl ,
+.Nm ntohs
+.Nd convert values between host and network byte order
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In arpa/inet.h
+.Pp
+or
+.Pp
+.In netinet/in.h
+.Ft uint32_t
+.Fn htonl "uint32_t hostlong"
+.Ft uint16_t
+.Fn htons "uint16_t hostshort"
+.Ft uint32_t
+.Fn ntohl "uint32_t netlong"
+.Ft uint16_t
+.Fn ntohs "uint16_t netshort"
+.Sh DESCRIPTION
+These routines convert 16 and 32 bit quantities between network
+byte order and host byte order.
+On machines which have a byte order which is the same as the network
+order, routines are defined as null macros.
+.Pp
+These routines are most often used in conjunction with Internet
+addresses and ports as returned by
+.Xr gethostbyname 3
+and
+.Xr getservent 3 .
+.Sh SEE ALSO
+.Xr gethostbyname 3 ,
+.Xr getservent 3 ,
+.Xr byteorder 9
+.Sh STANDARDS
+The
+.Nm byteorder
+functions conform to
+.St -p1003.1-2001 .
+.Sh HISTORY
+The
+.Nm byteorder
+functions appeared in
+.Bx 4.2 .
+.Sh BUGS
+On the
+.Tn VAX
+bytes are handled backwards from most everyone else in
+the world.
+This is not expected to be fixed in the near future.
diff --git a/lib/libc/net/ether_addr.c b/lib/libc/net/ether_addr.c
new file mode 100644
index 000000000000..19aa6f64e8c4
--- /dev/null
+++ b/lib/libc/net/ether_addr.c
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 1995 Bill Paul <wpaul@ctr.columbia.edu>.
+ * Copyright (c) 2007 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * ethernet address conversion and lookup routines
+ *
+ * Written by Bill Paul <wpaul@ctr.columbia.edu>
+ * Center for Telecommunications Research
+ * Columbia University, New York City
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <net/ethernet.h>
+
+#ifdef YP
+#include <rpc/rpc.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+#endif
+
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef _PATH_ETHERS
+#define _PATH_ETHERS "/etc/ethers"
+#endif
+
+/*
+ * Parse a string of text containing an ethernet address and hostname and
+ * separate it into its component parts.
+ */
+int
+ether_line(const char *l, struct ether_addr *e, char *hostname)
+{
+ int i, o[6];
+
+ i = sscanf(l, "%x:%x:%x:%x:%x:%x %s", &o[0], &o[1], &o[2], &o[3],
+ &o[4], &o[5], hostname);
+ if (i == 7) {
+ for (i = 0; i < 6; i++)
+ e->octet[i] = o[i];
+ return (0);
+ } else {
+ return (-1);
+ }
+}
+
+/*
+ * Convert an ASCII representation of an ethernet address to binary form.
+ */
+struct ether_addr *
+ether_aton_r(const char *a, struct ether_addr *e)
+{
+ int i;
+ unsigned int o0, o1, o2, o3, o4, o5;
+
+ i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o0, &o1, &o2, &o3, &o4, &o5);
+ if (i != 6)
+ return (NULL);
+ e->octet[0]=o0;
+ e->octet[1]=o1;
+ e->octet[2]=o2;
+ e->octet[3]=o3;
+ e->octet[4]=o4;
+ e->octet[5]=o5;
+ return (e);
+}
+
+struct ether_addr *
+ether_aton(const char *a)
+{
+ static struct ether_addr e;
+
+ return (ether_aton_r(a, &e));
+}
+
+/*
+ * Convert a binary representation of an ethernet address to an ASCII string.
+ */
+char *
+ether_ntoa_r(const struct ether_addr *n, char *a)
+{
+ int i;
+
+ i = sprintf(a, "%02x:%02x:%02x:%02x:%02x:%02x", n->octet[0],
+ n->octet[1], n->octet[2], n->octet[3], n->octet[4], n->octet[5]);
+ if (i < 17)
+ return (NULL);
+ return (a);
+}
+
+char *
+ether_ntoa(const struct ether_addr *n)
+{
+ static char a[18];
+
+ return (ether_ntoa_r(n, a));
+}
+
+/*
+ * Map an ethernet address to a hostname. Use either /etc/ethers or NIS/YP.
+ */
+int
+ether_ntohost(char *hostname, const struct ether_addr *e)
+{
+ FILE *fp;
+ char buf[BUFSIZ + 2];
+ struct ether_addr local_ether;
+ char local_host[MAXHOSTNAMELEN];
+#ifdef YP
+ char *result;
+ int resultlen;
+ char *ether_a;
+ char *yp_domain;
+#endif
+
+ if ((fp = fopen(_PATH_ETHERS, "re")) == NULL)
+ return (1);
+ while (fgets(buf,BUFSIZ,fp)) {
+ if (buf[0] == '#')
+ continue;
+#ifdef YP
+ if (buf[0] == '+') {
+ if (yp_get_default_domain(&yp_domain))
+ continue;
+ ether_a = ether_ntoa(e);
+ if (yp_match(yp_domain, "ethers.byaddr", ether_a,
+ strlen(ether_a), &result, &resultlen)) {
+ continue;
+ }
+ strncpy(buf, result, resultlen);
+ buf[resultlen] = '\0';
+ free(result);
+ }
+#endif
+ if (!ether_line(buf, &local_ether, local_host)) {
+ if (!bcmp((char *)&local_ether.octet[0],
+ (char *)&e->octet[0], 6)) {
+ /* We have a match. */
+ strcpy(hostname, local_host);
+ fclose(fp);
+ return(0);
+ }
+ }
+ }
+ fclose(fp);
+ return (1);
+}
+
+/*
+ * Map a hostname to an ethernet address using /etc/ethers or NIS/YP.
+ */
+int
+ether_hostton(const char *hostname, struct ether_addr *e)
+{
+ FILE *fp;
+ char buf[BUFSIZ + 2];
+ struct ether_addr local_ether;
+ char local_host[MAXHOSTNAMELEN];
+#ifdef YP
+ char *result;
+ int resultlen;
+ char *yp_domain;
+#endif
+
+ if ((fp = fopen(_PATH_ETHERS, "re")) == NULL)
+ return (1);
+ while (fgets(buf,BUFSIZ,fp)) {
+ if (buf[0] == '#')
+ continue;
+#ifdef YP
+ if (buf[0] == '+') {
+ if (yp_get_default_domain(&yp_domain))
+ continue;
+ if (yp_match(yp_domain, "ethers.byname", hostname,
+ strlen(hostname), &result, &resultlen)) {
+ continue;
+ }
+ strncpy(buf, result, resultlen);
+ buf[resultlen] = '\0';
+ free(result);
+ }
+#endif
+ if (!ether_line(buf, &local_ether, local_host)) {
+ if (!strcmp(hostname, local_host)) {
+ /* We have a match. */
+ bcopy((char *)&local_ether.octet[0],
+ (char *)&e->octet[0], 6);
+ fclose(fp);
+ return(0);
+ }
+ }
+ }
+ fclose(fp);
+ return (1);
+}
diff --git a/lib/libc/net/ethers.3 b/lib/libc/net/ethers.3
new file mode 100644
index 000000000000..6fe568b8765f
--- /dev/null
+++ b/lib/libc/net/ethers.3
@@ -0,0 +1,233 @@
+.\" Copyright (c) 1995 Bill Paul <wpaul@ctr.columbia.edu>.
+.\" Copyright (c) 2007 Robert N. M. Watson
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by Bill Paul.
+.\" 4. Neither the name of the author nor the names of any co-contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd October 30, 2007
+.Dt ETHERS 3
+.Os
+.Sh NAME
+.Nm ethers ,
+.Nm ether_line ,
+.Nm ether_aton ,
+.Nm ether_aton_r ,
+.Nm ether_ntoa ,
+.Nm ether_ntoa_r ,
+.Nm ether_ntohost ,
+.Nm ether_hostton
+.Nd Ethernet address conversion and lookup routines
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/socket.h
+.In net/ethernet.h
+.Ft int
+.Fn ether_line "const char *l" "struct ether_addr *e" "char *hostname"
+.Ft struct ether_addr *
+.Fn ether_aton "const char *a"
+.Ft struct ether_addr *
+.Fn ether_aton_r "const char *a" "struct ether_addr *e"
+.Ft char *
+.Fn ether_ntoa "const struct ether_addr *n"
+.Ft char *
+.Fn ether_ntoa_r "const struct ether_addr *n" "char *buf"
+.Ft int
+.Fn ether_ntohost "char *hostname" "const struct ether_addr *e"
+.Ft int
+.Fn ether_hostton "const char *hostname" "struct ether_addr *e"
+.Sh DESCRIPTION
+These functions operate on ethernet addresses using an
+.Vt ether_addr
+structure, which is defined in the header file
+.In net/ethernet.h :
+.Bd -literal -offset indent
+/*
+ * The number of bytes in an ethernet (MAC) address.
+ */
+#define ETHER_ADDR_LEN 6
+
+/*
+ * Structure of a 48-bit Ethernet address.
+ */
+struct ether_addr {
+ u_char octet[ETHER_ADDR_LEN];
+};
+.Ed
+.Pp
+The function
+.Fn ether_line
+scans
+.Fa l ,
+an
+.Tn ASCII
+string in
+.Xr ethers 5
+format and sets
+.Fa e
+to the ethernet address specified in the string and
+.Fa h
+to the hostname.
+This function is used to parse lines from
+.Pa /etc/ethers
+into their component parts.
+.Pp
+The
+.Fn ether_aton
+and
+.Fn ether_aton_r
+functions convert
+.Tn ASCII
+representation of ethernet addresses into
+.Vt ether_addr
+structures.
+Likewise, the
+.Fn ether_ntoa
+and
+.Fn ether_ntoa_r
+functions
+convert ethernet addresses specified as
+.Vt ether_addr
+structures into
+.Tn ASCII
+strings.
+.Pp
+The
+.Fn ether_ntohost
+and
+.Fn ether_hostton
+functions map ethernet addresses to their corresponding hostnames
+as specified in the
+.Pa /etc/ethers
+database.
+The
+.Fn ether_ntohost
+function
+converts from ethernet address to hostname, and
+.Fn ether_hostton
+converts from hostname to ethernet address.
+.Sh RETURN VALUES
+The
+.Fn ether_line
+function
+returns zero on success and non-zero if it was unable to parse
+any part of the supplied line
+.Fa l .
+It returns the extracted ethernet address in the supplied
+.Vt ether_addr
+structure
+.Fa e
+and the hostname in the supplied string
+.Fa h .
+.Pp
+On success,
+.Fn ether_ntoa
+and
+.Fn ether_ntoa_r
+functions return a pointer to a string containing an
+.Tn ASCII
+representation of an ethernet address.
+If it is unable to convert
+the supplied
+.Vt ether_addr
+structure, it returns a
+.Dv NULL
+pointer.
+.Fn ether_ntoa
+stores the result in a static buffer;
+.Fn ether_ntoa_r
+stores the result in a user-passed buffer.
+.Pp
+Likewise,
+.Fn ether_aton
+and
+.Fn ether_aton_r
+return a pointer to an
+.Vt ether_addr
+structure on success and a
+.Dv NULL
+pointer on failure.
+.Fn ether_aton
+stores the result in a static buffer;
+.Fn ether_aton_r
+stores the result in a user-passed buffer.
+.Pp
+The
+.Fn ether_ntohost
+and
+.Fn ether_hostton
+functions both return zero on success or non-zero if they were
+unable to find a match in the
+.Pa /etc/ethers
+database.
+.Sh NOTES
+The user must ensure that the hostname strings passed to the
+.Fn ether_line ,
+.Fn ether_ntohost
+and
+.Fn ether_hostton
+functions are large enough to contain the returned hostnames.
+.Sh NIS INTERACTION
+If the
+.Pa /etc/ethers
+contains a line with a single + in it, the
+.Fn ether_ntohost
+and
+.Fn ether_hostton
+functions will attempt to consult the NIS
+.Pa ethers.byname
+and
+.Pa ethers.byaddr
+maps in addition to the data in the
+.Pa /etc/ethers
+file.
+.Sh SEE ALSO
+.Xr ethers 5 ,
+.Xr yp 8
+.Sh HISTORY
+This particular implementation of the
+.Nm
+library functions were written for and first appeared in
+.Fx 2.1 .
+Thread-safe function variants first appeared in
+.Fx 7.0 .
+.Sh BUGS
+The
+.Fn ether_aton
+and
+.Fn ether_ntoa
+functions returns values that are stored in static memory areas
+which may be overwritten the next time they are called.
+.Pp
+.Fn ether_ntoa_r
+accepts a character buffer pointer, but not a buffer length.
+The caller must ensure adequate space is available in the buffer in order to
+avoid a buffer overflow.
diff --git a/lib/libc/net/eui64.3 b/lib/libc/net/eui64.3
new file mode 100644
index 000000000000..fc563d157a14
--- /dev/null
+++ b/lib/libc/net/eui64.3
@@ -0,0 +1,223 @@
+.\" Copyright 2004 The Aerospace Corporation. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions, and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions, and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. The name of The Aerospace Corporation may not be used to endorse or
+.\" promote products derived from this software.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AEROSPACE CORPORATION "AS IS" AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AEROSPACE CORPORATION BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" Copyright (c) 1995
+.\" Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by Bill Paul.
+.\" 4. Neither the name of the author nor the names of any co-contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd March 4, 2004
+.Dt EUI64 3
+.Os
+.Sh NAME
+.Nm eui64 ,
+.\" .Nm eui64_line ,
+.Nm eui64_aton ,
+.Nm eui64_ntoa ,
+.Nm eui64_ntohost ,
+.Nm eui64_hostton
+.Nd IEEE EUI-64 conversion and lookup routines
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/eui64.h
+.\" .Ft int
+.\" .Fn eui64_line "const char *l" "struct eui64 *e" "char *hostname" "size_t len"
+.Ft int
+.Fn eui64_aton "const char *a" "struct eui64 *e"
+.Ft int
+.Fn eui64_ntoa "const struct eui64 *id" "char *a" "size_t len"
+.Ft int
+.Fn eui64_ntohost "char *hostname" "size_t len" "const struct eui64 *id"
+.Ft int
+.Fn eui64_hostton "const char *hostname" "struct eui64 *id"
+.Sh DESCRIPTION
+These functions operate on IEEE EUI-64s using an
+.Vt eui64
+structure, which is defined in the header file
+.In sys/eui64.h :
+.Bd -literal -offset indent
+/*
+ * The number of bytes in an EUI-64.
+ */
+#define EUI64_LEN 8
+
+/*
+ * Structure of an IEEE EUI-64.
+ */
+struct eui64 {
+ u_char octet[EUI64_LEN];
+};
+.Ed
+.\" .Pp
+.\" The function
+.\" .Fn eui64_line
+.\" scans
+.\" .Fa l ,
+.\" an
+.\" .Tn ASCII
+.\" string in
+.\" .Xr eui64 5
+.\" format and sets
+.\" .Fa e
+.\" to the EUI-64 specified in the string and
+.\" .Fa h
+.\" to the hostname.
+.\" This function is used to parse lines from
+.\" .Pa /etc/eui64
+.\" into their component parts.
+.Pp
+The
+.Fn eui64_aton
+function converts an
+.Tn ASCII
+representation of an EUI-64 into an
+.Vt eui64
+structure.
+Likewise,
+.Fn eui64_ntoa
+converts an EUI-64 specified as an
+.Vt eui64
+structure into an
+.Tn ASCII
+string.
+.Pp
+The
+.Fn eui64_ntohost
+and
+.Fn eui64_hostton
+functions map EUI-64s to their corresponding hostnames
+as specified in the
+.Pa /etc/eui64
+database.
+The
+.Fn eui64_ntohost
+function
+converts from EUI-64 to hostname, and
+.Fn eui64_hostton
+converts from hostname to EUI-64.
+.Sh RETURN VALUES
+.\" The
+.\" .Fn eui64_line
+.\" function
+.\" returns zero on success and non-zero if it was unable to parse
+.\" any part of the supplied line
+.\" .Fa l .
+.\" It returns the extracted EUI-64 in the supplied
+.\" .Vt eui64
+.\" structure
+.\" .Fa e
+.\" and the hostname in the supplied string
+.\" .Fa h .
+.\" .Pp
+On success,
+.Fn eui64_ntoa
+returns a pointer to a string containing an
+.Tn ASCII
+representation of an EUI-64.
+If it is unable to convert
+the supplied
+.Vt eui64
+structure, it returns a
+.Dv NULL
+pointer.
+Likewise,
+.Fn eui64_aton
+returns a pointer to an
+.Vt eui64
+structure on success and a
+.Dv NULL
+pointer on failure.
+.Pp
+The
+.Fn eui64_ntohost
+and
+.Fn eui64_hostton
+functions both return zero on success or non-zero if they were
+unable to find a match in the
+.Pa /etc/eui64
+database.
+.Sh NOTES
+The user must ensure that the hostname strings passed to the
+.\" .Fn eui64_line ,
+.Fn eui64_ntohost
+and
+.Fn eui64_hostton
+functions are large enough to contain the returned hostnames.
+.Sh NIS INTERACTION
+If the
+.Pa /etc/eui64
+contains a line with a single
+.Ql +
+in it, the
+.Fn eui64_ntohost
+and
+.Fn eui64_hostton
+functions will attempt to consult the NIS
+.Pa eui64.byname
+and
+.Pa eui64.byid
+maps in addition to the data in the
+.Pa /etc/eui64
+file.
+.Sh SEE ALSO
+.Xr firewire 4 ,
+.Xr eui64 5 ,
+.Xr yp 8
+.Sh HISTORY
+These functions first appears in
+.Fx 5.3 .
+They are derived from the
+.Xr ethers 3
+family of functions.
diff --git a/lib/libc/net/eui64.c b/lib/libc/net/eui64.c
new file mode 100644
index 000000000000..2c2c4ea57b21
--- /dev/null
+++ b/lib/libc/net/eui64.c
@@ -0,0 +1,311 @@
+/*
+ * Copyright 2004 The Aerospace Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions, and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of The Aerospace Corporation may not be used to endorse or
+ * promote products derived from this software.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AEROSPACE CORPORATION "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AEROSPACE CORPORATION BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Copyright (c) 1995
+ * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * EUI-64 conversion and lookup routines
+ *
+ *
+ * Converted from ether_addr.c rev
+ * FreeBSD: src/lib/libc/net/eui64.c,v 1.15 2002/04/08 07:51:10 ru Exp
+ * by Brooks Davis
+ *
+ * Written by Bill Paul <wpaul@ctr.columbia.edu>
+ * Center for Telecommunications Research
+ * Columbia University, New York City
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <paths.h>
+#include <sys/param.h>
+#include <sys/eui64.h>
+#include <string.h>
+#include <stdlib.h>
+#ifdef YP
+#include <rpc/rpc.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+#endif
+
+#ifndef _PATH_EUI64
+#define _PATH_EUI64 "/etc/eui64"
+#endif
+
+static int eui64_line(const char *l, struct eui64 *e, char *hostname,
+ size_t len);
+
+/*
+ * Parse a string of text containing an EUI-64 and hostname
+ * and separate it into its component parts.
+ */
+static int
+eui64_line(const char *l, struct eui64 *e, char *hostname, size_t len)
+{
+ char *line, *linehead, *cur;
+
+ linehead = strdup(l);
+ if (linehead == NULL)
+ return (-1);
+ line = linehead;
+
+ /* Find and parse the EUI64 */
+ while ((cur = strsep(&line, " \t\r\n")) != NULL) {
+ if (*cur != '\0') {
+ if (eui64_aton(cur, e) == 0)
+ break;
+ else
+ goto bad;
+ }
+ }
+
+ /* Find the hostname */
+ while ((cur = strsep(&line, " \t\r\n")) != NULL) {
+ if (*cur != '\0') {
+ if (strlcpy(hostname, cur, len) <= len)
+ break;
+ else
+ goto bad;
+ }
+ }
+
+ /* Make sure what remains is either whitespace or a comment */
+ while ((cur = strsep(&line, " \t\r\n")) != NULL) {
+ if (*cur == '#')
+ break;
+ if (*cur != '\0')
+ goto bad;
+ }
+
+ free(linehead);
+ return (0);
+
+bad:
+ free(linehead);
+ return (-1);
+}
+
+/*
+ * Convert an ASCII representation of an EUI-64 to binary form.
+ */
+int
+eui64_aton(const char *a, struct eui64 *e)
+{
+ int i;
+ unsigned int o0, o1, o2, o3, o4, o5, o6, o7;
+
+ /* canonical form */
+ i = sscanf(a, "%x-%x-%x-%x-%x-%x-%x-%x",
+ &o0, &o1, &o2, &o3, &o4, &o5, &o6, &o7);
+ if (i == EUI64_LEN)
+ goto good;
+ /* ethernet form */
+ i = sscanf(a, "%x:%x:%x:%x:%x:%x:%x:%x",
+ &o0, &o1, &o2, &o3, &o4, &o5, &o6, &o7);
+ if (i == EUI64_LEN)
+ goto good;
+ /* classic fwcontrol/dconschat form */
+ i = sscanf(a, "0x%2x%2x%2x%2x%2x%2x%2x%2x",
+ &o0, &o1, &o2, &o3, &o4, &o5, &o6, &o7);
+ if (i == EUI64_LEN)
+ goto good;
+ /* MAC format (-) */
+ i = sscanf(a, "%x-%x-%x-%x-%x-%x",
+ &o0, &o1, &o2, &o5, &o6, &o7);
+ if (i == 6) {
+ o3 = 0xff;
+ o4 = 0xfe;
+ goto good;
+ }
+ /* MAC format (:) */
+ i = sscanf(a, "%x:%x:%x:%x:%x:%x",
+ &o0, &o1, &o2, &o5, &o6, &o7);
+ if (i == 6) {
+ o3 = 0xff;
+ o4 = 0xfe;
+ goto good;
+ }
+
+ return (-1);
+
+good:
+ e->octet[0]=o0;
+ e->octet[1]=o1;
+ e->octet[2]=o2;
+ e->octet[3]=o3;
+ e->octet[4]=o4;
+ e->octet[5]=o5;
+ e->octet[6]=o6;
+ e->octet[7]=o7;
+
+ return (0);
+}
+
+/*
+ * Convert a binary representation of an EUI-64 to an ASCII string.
+ */
+int
+eui64_ntoa(const struct eui64 *id, char *a, size_t len)
+{
+ int i;
+
+ i = snprintf(a, len, "%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x",
+ id->octet[0], id->octet[1], id->octet[2], id->octet[3],
+ id->octet[4], id->octet[5], id->octet[6], id->octet[7]);
+ if (i < 23 || i >= len)
+ return (-1);
+ return (0);
+}
+
+/*
+ * Map an EUI-64 to a hostname. Use either /etc/eui64 or NIS/YP.
+ */
+int
+eui64_ntohost(char *hostname, size_t len, const struct eui64 *id)
+{
+ FILE *fp;
+ char buf[BUFSIZ + 2];
+ struct eui64 local_eui64;
+ char local_host[MAXHOSTNAMELEN];
+#ifdef YP
+ char *result;
+ int resultlen;
+ char eui64_a[24];
+ char *yp_domain;
+#endif
+ if ((fp = fopen(_PATH_EUI64, "re")) == NULL)
+ return (1);
+
+ while (fgets(buf,BUFSIZ,fp)) {
+ if (buf[0] == '#')
+ continue;
+#ifdef YP
+ if (buf[0] == '+') {
+ if (yp_get_default_domain(&yp_domain))
+ continue;
+ eui64_ntoa(id, eui64_a, sizeof(eui64_a));
+ if (yp_match(yp_domain, "eui64.byid", eui64_a,
+ strlen(eui64_a), &result, &resultlen)) {
+ continue;
+ }
+ strncpy(buf, result, resultlen);
+ buf[resultlen] = '\0';
+ free(result);
+ }
+#endif
+ if (eui64_line(buf, &local_eui64, local_host,
+ sizeof(local_host)) == 0) {
+ if (bcmp(&local_eui64.octet[0],
+ &id->octet[0], EUI64_LEN) == 0) {
+ /* We have a match */
+ strcpy(hostname, local_host);
+ fclose(fp);
+ return(0);
+ }
+ }
+ }
+ fclose(fp);
+ return (1);
+}
+
+/*
+ * Map a hostname to an EUI-64 using /etc/eui64 or NIS/YP.
+ */
+int
+eui64_hostton(const char *hostname, struct eui64 *id)
+{
+ FILE *fp;
+ char buf[BUFSIZ + 2];
+ struct eui64 local_eui64;
+ char local_host[MAXHOSTNAMELEN];
+#ifdef YP
+ char *result;
+ int resultlen;
+ char *yp_domain;
+#endif
+ if ((fp = fopen(_PATH_EUI64, "re")) == NULL)
+ return (1);
+
+ while (fgets(buf,BUFSIZ,fp)) {
+ if (buf[0] == '#')
+ continue;
+#ifdef YP
+ if (buf[0] == '+') {
+ if (yp_get_default_domain(&yp_domain))
+ continue;
+ if (yp_match(yp_domain, "eui64.byname", hostname,
+ strlen(hostname), &result, &resultlen)) {
+ continue;
+ }
+ strncpy(buf, result, resultlen);
+ buf[resultlen] = '\0';
+ free(result);
+ }
+#endif
+ if (eui64_line(buf, &local_eui64, local_host,
+ sizeof(local_host)) == 0) {
+ if (strcmp(hostname, local_host) == 0) {
+ /* We have a match */
+ bcopy(&local_eui64, id, sizeof(struct eui64));
+ fclose(fp);
+ return(0);
+ }
+ }
+ }
+ fclose(fp);
+ return (1);
+}
diff --git a/lib/libc/net/gai_strerror.3 b/lib/libc/net/gai_strerror.3
new file mode 100644
index 000000000000..25cff0c01cf1
--- /dev/null
+++ b/lib/libc/net/gai_strerror.3
@@ -0,0 +1,92 @@
+.\" $KAME: gai_strerror.3,v 1.1 2005/01/05 03:04:47 itojun Exp $
+.\" $OpenBSD: gai_strerror.3,v 1.4 2004/12/20 23:04:53 millert Exp $
+.\"
+.\" Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+.\" Copyright (C) 2000, 2001 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd May 21, 2006
+.Dt GAI_STRERROR 3
+.Os
+.Sh NAME
+.Nm gai_strerror
+.Nd get error message string from EAI_xxx error code
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/socket.h
+.In netdb.h
+.Ft "const char *"
+.Fn gai_strerror "int ecode"
+.Sh DESCRIPTION
+The
+.Fn gai_strerror
+function returns an error message string corresponding to the error code
+returned by
+.Xr getaddrinfo 3
+or
+.Xr getnameinfo 3 .
+.Pp
+The following error codes and their meaning are defined in
+.In netdb.h :
+.Pp
+.Bl -tag -width ".Dv EAI_BADFLAGS" -offset indent -compact
+.It Dv EAI_AGAIN
+temporary failure in name resolution
+.It Dv EAI_BADFLAGS
+invalid value for
+.Fa ai_flags
+.It Dv EAI_BADHINTS
+invalid value for
+.Fa hints
+.It Dv EAI_FAIL
+non-recoverable failure in name resolution
+.It Dv EAI_FAMILY
+.Fa ai_family
+not supported
+.It Dv EAI_MEMORY
+memory allocation failure
+.It Dv EAI_NONAME
+.Fa hostname
+or
+.Fa servname
+not provided, or not known
+.It Dv EAI_OVERFLOW
+argument buffer overflow
+.It Dv EAI_PROTOCOL
+resolved protocol is unknown
+.It Dv EAI_SERVICE
+.Fa servname
+not supported for
+.Fa ai_socktype
+.It Dv EAI_SOCKTYPE
+.Fa ai_socktype
+not supported
+.It Dv EAI_SYSTEM
+system error returned in
+.Va errno
+.El
+.Sh RETURN VALUES
+The
+.Fn gai_strerror
+function
+returns a pointer to the error message string corresponding to
+.Fa ecode .
+If
+.Fa ecode
+is out of range, an implementation-specific error message string is returned.
+.Sh SEE ALSO
+.Xr getaddrinfo 3 ,
+.Xr getnameinfo 3
diff --git a/lib/libc/net/gai_strerror.c b/lib/libc/net/gai_strerror.c
new file mode 100644
index 000000000000..4f60f2db3917
--- /dev/null
+++ b/lib/libc/net/gai_strerror.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <netdb.h>
+#if defined(NLS)
+#include <nl_types.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include "reentrant.h"
+#endif
+#include "un-namespace.h"
+
+/* Entries EAI_ADDRFAMILY (1) and EAI_NODATA (7) are obsoleted, but left */
+/* for backward compatibility with userland code prior to 2553bis-02 */
+static const char *ai_errlist[] = {
+ "Success", /* 0 */
+ "Address family for hostname not supported", /* 1 */
+ "Temporary failure in name resolution", /* EAI_AGAIN */
+ "Invalid value for ai_flags", /* EAI_BADFLAGS */
+ "Non-recoverable failure in name resolution", /* EAI_FAIL */
+ "ai_family not supported", /* EAI_FAMILY */
+ "Memory allocation failure", /* EAI_MEMORY */
+ "No address associated with hostname", /* 7 */
+ "hostname nor servname provided, or not known", /* EAI_NONAME */
+ "servname not supported for ai_socktype", /* EAI_SERVICE */
+ "ai_socktype not supported", /* EAI_SOCKTYPE */
+ "System error returned in errno", /* EAI_SYSTEM */
+ "Invalid value for hints", /* EAI_BADHINTS */
+ "Resolved protocol is unknown", /* EAI_PROTOCOL */
+ "Argument buffer overflow" /* EAI_OVERFLOW */
+};
+
+#if defined(NLS)
+static char gai_buf[NL_TEXTMAX];
+static once_t gai_init_once = ONCE_INITIALIZER;
+static thread_key_t gai_key;
+static int gai_keycreated = 0;
+
+static void
+gai_keycreate(void)
+{
+ gai_keycreated = (thr_keycreate(&gai_key, free) == 0);
+}
+#endif
+
+const char *
+gai_strerror(int ecode)
+{
+#if defined(NLS)
+ nl_catd catd;
+ char *buf;
+
+ if (thr_main() != 0)
+ buf = gai_buf;
+ else {
+ if (thr_once(&gai_init_once, gai_keycreate) != 0 ||
+ !gai_keycreated)
+ goto thr_err;
+ if ((buf = thr_getspecific(gai_key)) == NULL) {
+ if ((buf = malloc(sizeof(gai_buf))) == NULL)
+ goto thr_err;
+ if (thr_setspecific(gai_key, buf) != 0) {
+ free(buf);
+ goto thr_err;
+ }
+ }
+ }
+
+ catd = catopen("libc", NL_CAT_LOCALE);
+ if (ecode > 0 && ecode < EAI_MAX)
+ strlcpy(buf, catgets(catd, 3, ecode, ai_errlist[ecode]),
+ sizeof(gai_buf));
+ else if (ecode == 0)
+ strlcpy(buf, catgets(catd, 3, NL_MSGMAX - 1, "Success"),
+ sizeof(gai_buf));
+ else
+ strlcpy(buf, catgets(catd, 3, NL_MSGMAX, "Unknown error"),
+ sizeof(gai_buf));
+ catclose(catd);
+ return buf;
+
+thr_err:
+#endif
+ if (ecode >= 0 && ecode < EAI_MAX)
+ return ai_errlist[ecode];
+ return "Unknown error";
+}
diff --git a/lib/libc/net/getaddrinfo.3 b/lib/libc/net/getaddrinfo.3
new file mode 100644
index 000000000000..7380428e9fb3
--- /dev/null
+++ b/lib/libc/net/getaddrinfo.3
@@ -0,0 +1,509 @@
+.\" $KAME: getaddrinfo.3,v 1.36 2005/01/05 03:23:05 itojun Exp $
+.\" $OpenBSD: getaddrinfo.3,v 1.35 2004/12/21 03:40:31 jaredy Exp $
+.\"
+.\" Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+.\" Copyright (C) 2000, 2001 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd December 21, 2015
+.Dt GETADDRINFO 3
+.Os
+.Sh NAME
+.Nm getaddrinfo ,
+.Nm freeaddrinfo
+.Nd socket address structure to host and service name
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/socket.h
+.In netdb.h
+.Ft int
+.Fo getaddrinfo
+.Fa "const char *hostname" "const char *servname"
+.Fa "const struct addrinfo *hints" "struct addrinfo **res"
+.Fc
+.Ft void
+.Fn freeaddrinfo "struct addrinfo *ai"
+.Sh DESCRIPTION
+The
+.Fn getaddrinfo
+function is used to get a list of
+addresses and port numbers for host
+.Fa hostname
+and service
+.Fa servname .
+It is a replacement for and provides more flexibility than the
+.Xr gethostbyname 3
+and
+.Xr getservbyname 3
+functions.
+.Pp
+The
+.Fa hostname
+and
+.Fa servname
+arguments are either pointers to NUL-terminated strings or the null pointer.
+An acceptable value for
+.Fa hostname
+is either a valid host name or a numeric host address string consisting
+of a dotted decimal IPv4 address,
+an IPv6 address,
+or a UNIX-domain address.
+The
+.Fa servname
+is either a decimal port number or a service name listed in
+.Xr services 5 .
+At least one of
+.Fa hostname
+and
+.Fa servname
+must be non-null.
+.Pp
+.Fa hints
+is an optional pointer to a
+.Li struct addrinfo ,
+as defined by
+.Aq Pa netdb.h :
+.Bd -literal
+struct addrinfo {
+ int ai_flags; /* input flags */
+ int ai_family; /* address family for socket */
+ int ai_socktype; /* socket type */
+ int ai_protocol; /* protocol for socket */
+ socklen_t ai_addrlen; /* length of socket-address */
+ struct sockaddr *ai_addr; /* socket-address for socket */
+ char *ai_canonname; /* canonical name for service location */
+ struct addrinfo *ai_next; /* pointer to next in list */
+};
+.Ed
+.Pp
+This structure can be used to provide hints concerning the type of socket
+that the caller supports or wishes to use.
+The caller can supply the following structure elements in
+.Fa hints :
+.Bl -tag -width "ai_socktypeXX"
+.It Fa ai_family
+The address family that should be used.
+When
+.Fa ai_family
+is set to
+.Dv AF_UNSPEC ,
+it means the caller will accept any address family supported by the
+operating system.
+.It Fa ai_socktype
+Denotes the type of socket that is wanted:
+.Dv SOCK_STREAM ,
+.Dv SOCK_DGRAM ,
+.Dv SOCK_SEQPACKET ,
+or
+.Dv SOCK_RAW .
+When
+.Fa ai_socktype
+is zero the caller will accept any socket type.
+.It Fa ai_protocol
+Indicates which transport protocol is desired,
+.Dv IPPROTO_UDP ,
+.Dv IPPROTO_TCP ,
+.Dv IPPROTO_SCTP ,
+or
+.Dv IPPROTO_UDPLITE .
+If
+.Fa ai_protocol
+is zero the caller will accept any protocol.
+.It Fa ai_flags
+The
+.Fa ai_flags
+field to which the
+.Fa hints
+parameter points shall be set to zero
+or be the bitwise-inclusive OR of one or more of the values
+.Dv AI_ADDRCONFIG ,
+.Dv AI_ALL ,
+.Dv AI_CANONNAME ,
+.Dv AI_NUMERICHOST ,
+.Dv AI_NUMERICSERV ,
+.Dv AI_PASSIVE
+and
+.Dv AI_V4MAPPED .
+For a UNIX-domain address,
+.Fa ai_flags
+is ignored.
+.Bl -tag -width "AI_CANONNAMEXX"
+.It Dv AI_ADDRCONFIG
+If the
+.Dv AI_ADDRCONFIG
+bit is set, IPv4 addresses shall be returned only if
+an IPv4 address is configured on the local system,
+and IPv6 addresses shall be returned only if
+an IPv6 address is configured on the local system.
+.It Dv AI_ALL
+If the
+.Dv AI_ALL
+flag is used with the
+.Dv AI_V4MAPPED
+flag, then
+.Fn getaddrinfo
+shall return all matching IPv6 and IPv4 addresses.
+.Pp
+For example, when using the DNS, queries are made for both AAAA records and A records, and
+.Fn getaddrinfo
+returns the combined results of both queries.
+Any IPv4 addresses found are returned as IPv4-mapped IPv6 addresses.
+.Pp
+The
+.Dv AI_ALL
+flag without the
+.Dv AI_V4MAPPED
+flag is ignored.
+.It Dv AI_CANONNAME
+If the
+.Dv AI_CANONNAME
+bit is set, a successful call to
+.Fn getaddrinfo
+will return a NUL-terminated string containing the canonical name
+of the specified hostname in the
+.Fa ai_canonname
+element of the first
+.Li addrinfo
+structure returned.
+.It Dv AI_NUMERICHOST
+If the
+.Dv AI_NUMERICHOST
+bit is set, it indicates that
+.Fa hostname
+should be treated as a numeric string defining an IPv4 or IPv6 address
+and no name resolution should be attempted.
+.It Dv AI_NUMERICSERV
+If the
+.Dv AI_NUMERICSERV
+bit is set,
+then a non-null
+.Fa servname
+string supplied shall be a numeric port string.
+Otherwise, an
+.Dv EAI_NONAME
+error shall be returned.
+This bit shall prevent any type of name resolution service
+(for example, NIS+) from being invoked.
+.It Dv AI_PASSIVE
+If the
+.Dv AI_PASSIVE
+bit is set it indicates that the returned socket address structure
+is intended for use in a call to
+.Xr bind 2 .
+In this case, if the
+.Fa hostname
+argument is the null pointer, then the IP address portion of the
+socket address structure will be set to
+.Dv INADDR_ANY
+for an IPv4 address or
+.Dv IN6ADDR_ANY_INIT
+for an IPv6 address.
+.Pp
+If the
+.Dv AI_PASSIVE
+bit is not set, the returned socket address structure will be ready
+for use in a call to
+.Xr connect 2
+for a connection-oriented protocol or
+.Xr connect 2 ,
+.Xr sendto 2 ,
+or
+.Xr sendmsg 2
+if a connectionless protocol was chosen.
+The
+.Tn IP
+address portion of the socket address structure will be set to the
+loopback address if
+.Fa hostname
+is the null pointer and
+.Dv AI_PASSIVE
+is not set.
+.It Dv AI_V4MAPPED
+If the
+.Dv AI_V4MAPPED
+flag is specified along with an ai_family of
+.Dv AF_INET6 ,
+then
+.Fn getaddrinfo
+shall return IPv4-mapped IPv6 addresses on finding no matching IPv6 addresses (
+.Fa ai_addrlen
+shall be 16).
+.Pp
+For example, when using the DNS, if no AAAA records are found then a query is made for A records and any found are returned as IPv4-mapped IPv6 addresses.
+.Pp
+The
+.Dv AI_V4MAPPED
+flag shall be ignored unless
+.Fa ai_family
+equals
+.Dv AF_INET6 .
+.El
+.El
+.Pp
+All other elements of the
+.Li addrinfo
+structure passed via
+.Fa hints
+must be zero or the null pointer.
+.Pp
+If
+.Fa hints
+is the null pointer,
+.Fn getaddrinfo
+behaves as if the caller provided a
+.Li struct addrinfo
+with
+.Fa ai_family
+set to
+.Dv AF_UNSPEC
+and all other elements set to zero or
+.Dv NULL .
+.Pp
+After a successful call to
+.Fn getaddrinfo ,
+.Fa *res
+is a pointer to a linked list of one or more
+.Li addrinfo
+structures.
+The list can be traversed by following the
+.Fa ai_next
+pointer in each
+.Li addrinfo
+structure until a null pointer is encountered.
+Each returned
+.Li addrinfo
+structure contains three members that are suitable for a call to
+.Xr socket 2 :
+.Fa ai_family ,
+.Fa ai_socktype ,
+and
+.Fa ai_protocol .
+For each
+.Li addrinfo
+structure in the list, the
+.Fa ai_addr
+member points to a filled-in socket address structure of length
+.Fa ai_addrlen .
+.Pp
+This implementation of
+.Fn getaddrinfo
+allows numeric IPv6 address notation with scope identifier,
+as documented in chapter 11 of RFC 4007.
+By appending the percent character and scope identifier to addresses,
+one can fill the
+.Li sin6_scope_id
+field for addresses.
+This would make management of scoped addresses easier
+and allows cut-and-paste input of scoped addresses.
+.Pp
+At this moment the code supports only link-local addresses with the format.
+The scope identifier is hardcoded to the name of the hardware interface
+associated
+with the link
+.Po
+such as
+.Li ne0
+.Pc .
+An example is
+.Dq Li fe80::1%ne0 ,
+which means
+.Do
+.Li fe80::1
+on the link associated with the
+.Li ne0
+interface
+.Dc .
+.Pp
+The current implementation assumes a one-to-one relationship between
+the interface and link, which is not necessarily true from the specification.
+.Pp
+All of the information returned by
+.Fn getaddrinfo
+is dynamically allocated: the
+.Li addrinfo
+structures themselves as well as the socket address structures and
+the canonical host name strings included in the
+.Li addrinfo
+structures.
+.Pp
+Memory allocated for the dynamically allocated structures created by
+a successful call to
+.Fn getaddrinfo
+is released by the
+.Fn freeaddrinfo
+function.
+The
+.Fa ai
+pointer should be a
+.Li addrinfo
+structure created by a call to
+.Fn getaddrinfo .
+.Sh RETURN VALUES
+.Fn getaddrinfo
+returns zero on success or one of the error codes listed in
+.Xr gai_strerror 3
+if an error occurs.
+.Sh EXAMPLES
+The following code tries to connect to
+.Dq Li www.kame.net
+service
+.Dq Li http
+via a stream socket.
+It loops through all the addresses available, regardless of address family.
+If the destination resolves to an IPv4 address, it will use an
+.Dv AF_INET
+socket.
+Similarly, if it resolves to IPv6, an
+.Dv AF_INET6
+socket is used.
+Observe that there is no hardcoded reference to a particular address family.
+The code works even if
+.Fn getaddrinfo
+returns addresses that are not IPv4/v6.
+.Bd -literal -offset indent
+struct addrinfo hints, *res, *res0;
+int error;
+int s;
+const char *cause = NULL;
+
+memset(&hints, 0, sizeof(hints));
+hints.ai_family = AF_UNSPEC;
+hints.ai_socktype = SOCK_STREAM;
+error = getaddrinfo("www.kame.net", "http", &hints, &res0);
+if (error) {
+ errx(1, "%s", gai_strerror(error));
+ /* NOTREACHED */
+}
+s = -1;
+for (res = res0; res; res = res->ai_next) {
+ s = socket(res->ai_family, res->ai_socktype,
+ res->ai_protocol);
+ if (s < 0) {
+ cause = "socket";
+ continue;
+ }
+
+ if (connect(s, res->ai_addr, res->ai_addrlen) < 0) {
+ cause = "connect";
+ close(s);
+ s = -1;
+ continue;
+ }
+
+ break; /* okay we got one */
+}
+if (s < 0) {
+ err(1, "%s", cause);
+ /* NOTREACHED */
+}
+freeaddrinfo(res0);
+.Ed
+.Pp
+The following example tries to open a wildcard listening socket onto service
+.Dq Li http ,
+for all the address families available.
+.Bd -literal -offset indent
+struct addrinfo hints, *res, *res0;
+int error;
+int s[MAXSOCK];
+int nsock;
+const char *cause = NULL;
+
+memset(&hints, 0, sizeof(hints));
+hints.ai_family = AF_UNSPEC;
+hints.ai_socktype = SOCK_STREAM;
+hints.ai_flags = AI_PASSIVE;
+error = getaddrinfo(NULL, "http", &hints, &res0);
+if (error) {
+ errx(1, "%s", gai_strerror(error));
+ /* NOTREACHED */
+}
+nsock = 0;
+for (res = res0; res && nsock < MAXSOCK; res = res->ai_next) {
+ s[nsock] = socket(res->ai_family, res->ai_socktype,
+ res->ai_protocol);
+ if (s[nsock] < 0) {
+ cause = "socket";
+ continue;
+ }
+
+ if (bind(s[nsock], res->ai_addr, res->ai_addrlen) < 0) {
+ cause = "bind";
+ close(s[nsock]);
+ continue;
+ }
+ (void) listen(s[nsock], 5);
+
+ nsock++;
+}
+if (nsock == 0) {
+ err(1, "%s", cause);
+ /* NOTREACHED */
+}
+freeaddrinfo(res0);
+.Ed
+.Sh SEE ALSO
+.Xr bind 2 ,
+.Xr connect 2 ,
+.Xr send 2 ,
+.Xr socket 2 ,
+.Xr gai_strerror 3 ,
+.Xr gethostbyname 3 ,
+.Xr getnameinfo 3 ,
+.Xr getservbyname 3 ,
+.Xr resolver 3 ,
+.Xr inet 4 ,
+.Xr inet6 4 ,
+.Xr unix 4 ,
+.Xr hosts 5 ,
+.Xr resolv.conf 5 ,
+.Xr services 5 ,
+.Xr hostname 7 ,
+.Xr named 8
+.Rs
+.%A R. Gilligan
+.%A S. Thomson
+.%A J. Bound
+.%A J. McCann
+.%A W. Stevens
+.%T Basic Socket Interface Extensions for IPv6
+.%R RFC 3493
+.%D February 2003
+.Re
+.Rs
+.%A S. Deering
+.%A B. Haberman
+.%A T. Jinmei
+.%A E. Nordmark
+.%A B. Zill
+.%T "IPv6 Scoped Address Architecture"
+.%R RFC 4007
+.%D March 2005
+.Re
+.Rs
+.%A Craig Metz
+.%T Protocol Independence Using the Sockets API
+.%B "Proceedings of the freenix track: 2000 USENIX annual technical conference"
+.%D June 2000
+.Re
+.Sh STANDARDS
+The
+.Fn getaddrinfo
+function is defined by the
+.St -p1003.1-2004
+specification and documented in
+.Dv "RFC 3493" ,
+.Dq Basic Socket Interface Extensions for IPv6 .
diff --git a/lib/libc/net/getaddrinfo.c b/lib/libc/net/getaddrinfo.c
new file mode 100644
index 000000000000..5988ebc1372b
--- /dev/null
+++ b/lib/libc/net/getaddrinfo.c
@@ -0,0 +1,3033 @@
+/* $KAME: getaddrinfo.c,v 1.15 2000/07/09 04:37:24 itojun Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Issues to be discussed:
+ * - Return values. There are nonstandard return values defined and used
+ * in the source code. This is because RFC2553 is silent about which error
+ * code must be returned for which situation.
+ * - freeaddrinfo(NULL). RFC2553 is silent about it. XNET 5.2 says it is
+ * invalid. current code - SEGV on freeaddrinfo(NULL)
+ *
+ * Note:
+ * - The code filters out AFs that are not supported by the kernel,
+ * when globbing NULL hostname (to loopback, or wildcard). Is it the right
+ * thing to do? What is the relationship with post-RFC2553 AI_ADDRCONFIG
+ * in ai_flags?
+ * - (post-2553) semantics of AI_ADDRCONFIG itself is too vague.
+ * (1) what should we do against numeric hostname (2) what should we do
+ * against NULL hostname (3) what is AI_ADDRCONFIG itself. AF not ready?
+ * non-loopback address configured? global address configured?
+ *
+ * OS specific notes for freebsd4:
+ * - FreeBSD supported $GAI. The code does not.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <net/if_types.h>
+#include <ifaddrs.h>
+#include <sys/queue.h>
+#ifdef INET6
+#include <sys/sysctl.h>
+#include <sys/ioctl.h>
+#include <netinet6/in6_var.h>
+#include <netinet6/nd6.h>
+#endif
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include <rpc/rpc.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include "res_config.h"
+
+#ifdef DEBUG
+#include <syslog.h>
+#endif
+
+#include <stdarg.h>
+#include <nsswitch.h>
+#include "un-namespace.h"
+#include "netdb_private.h"
+#include "libc_private.h"
+#ifdef NS_CACHING
+#include "nscache.h"
+#endif
+
+#define ANY 0
+#define YES 1
+#define NO 0
+
+static const char in_addrany[] = { 0, 0, 0, 0 };
+static const char in_loopback[] = { 127, 0, 0, 1 };
+#ifdef INET6
+static const char in6_addrany[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+static const char in6_loopback[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
+};
+#endif
+
+struct policyqueue {
+ TAILQ_ENTRY(policyqueue) pc_entry;
+#ifdef INET6
+ struct in6_addrpolicy pc_policy;
+#endif
+};
+TAILQ_HEAD(policyhead, policyqueue);
+
+static const struct afd {
+ int a_af;
+ int a_addrlen;
+ socklen_t a_socklen;
+ int a_off;
+ const char *a_addrany;
+ const char *a_loopback;
+ int a_scoped;
+} afdl [] = {
+#ifdef INET6
+#define N_INET6 0
+ {PF_INET6, sizeof(struct in6_addr),
+ sizeof(struct sockaddr_in6),
+ offsetof(struct sockaddr_in6, sin6_addr),
+ in6_addrany, in6_loopback, 1},
+#define N_INET 1
+#define N_LOCAL 2
+#else
+#define N_INET 0
+#define N_LOCAL 1
+#endif
+ {PF_INET, sizeof(struct in_addr),
+ sizeof(struct sockaddr_in),
+ offsetof(struct sockaddr_in, sin_addr),
+ in_addrany, in_loopback, 0},
+#define sizeofmember(type, member) (sizeof(((type *)0)->member))
+ {PF_LOCAL, sizeofmember(struct sockaddr_un, sun_path),
+ sizeof(struct sockaddr_un),
+ offsetof(struct sockaddr_un, sun_path),
+ NULL, NULL, 0},
+ {0, 0, 0, 0, NULL, NULL, 0},
+};
+
+struct explore {
+ int e_af;
+ int e_socktype;
+ int e_protocol;
+ int e_wild;
+#define AF_ANY 0x01
+#define SOCKTYPE_ANY 0x02
+#define PROTOCOL_ANY 0x04
+#define WILD_AF(ex) ((ex)->e_wild & AF_ANY)
+#define WILD_SOCKTYPE(ex) ((ex)->e_wild & SOCKTYPE_ANY)
+#define WILD_PROTOCOL(ex) ((ex)->e_wild & PROTOCOL_ANY)
+};
+
+static const struct explore explore[] = {
+#ifdef INET6
+ { PF_INET6, SOCK_DGRAM, IPPROTO_UDP,
+ AF_ANY | SOCKTYPE_ANY | PROTOCOL_ANY },
+ { PF_INET6, SOCK_STREAM, IPPROTO_TCP,
+ AF_ANY | SOCKTYPE_ANY | PROTOCOL_ANY },
+ { PF_INET6, SOCK_STREAM, IPPROTO_SCTP,
+ AF_ANY | SOCKTYPE_ANY },
+ { PF_INET6, SOCK_SEQPACKET, IPPROTO_SCTP,
+ AF_ANY | SOCKTYPE_ANY | PROTOCOL_ANY },
+ { PF_INET6, SOCK_DGRAM, IPPROTO_UDPLITE,
+ AF_ANY | SOCKTYPE_ANY },
+ { PF_INET6, SOCK_RAW, ANY,
+ AF_ANY | PROTOCOL_ANY },
+#endif
+ { PF_INET, SOCK_DGRAM, IPPROTO_UDP,
+ AF_ANY | SOCKTYPE_ANY | PROTOCOL_ANY },
+ { PF_INET, SOCK_STREAM, IPPROTO_TCP,
+ AF_ANY | SOCKTYPE_ANY | PROTOCOL_ANY },
+ { PF_INET, SOCK_STREAM, IPPROTO_SCTP,
+ AF_ANY | SOCKTYPE_ANY },
+ { PF_INET, SOCK_SEQPACKET, IPPROTO_SCTP,
+ AF_ANY | SOCKTYPE_ANY | PROTOCOL_ANY },
+ { PF_INET, SOCK_DGRAM, IPPROTO_UDPLITE,
+ AF_ANY | SOCKTYPE_ANY },
+ { PF_INET, SOCK_RAW, ANY,
+ AF_ANY | PROTOCOL_ANY },
+ { PF_LOCAL, SOCK_DGRAM, ANY,
+ AF_ANY | SOCKTYPE_ANY | PROTOCOL_ANY },
+ { PF_LOCAL, SOCK_STREAM, ANY,
+ AF_ANY | SOCKTYPE_ANY | PROTOCOL_ANY },
+ { PF_LOCAL, SOCK_SEQPACKET, ANY,
+ AF_ANY | SOCKTYPE_ANY | PROTOCOL_ANY },
+ { -1, 0, 0, 0 },
+};
+
+#ifdef INET6
+#define PTON_MAX 16
+#else
+#define PTON_MAX 4
+#endif
+
+#define AIO_SRCFLAG_DEPRECATED 0x1
+
+struct ai_order {
+ union {
+ struct sockaddr_storage aiou_ss;
+ struct sockaddr aiou_sa;
+ } aio_src_un;
+#define aio_srcsa aio_src_un.aiou_sa
+ u_int32_t aio_srcflag;
+ int aio_srcscope;
+ int aio_dstscope;
+ struct policyqueue *aio_srcpolicy;
+ struct policyqueue *aio_dstpolicy;
+ struct addrinfo *aio_ai;
+ int aio_matchlen;
+ int aio_initial_sequence;
+};
+
+static const ns_src default_dns_files[] = {
+ { NSSRC_FILES, NS_SUCCESS },
+ { NSSRC_DNS, NS_SUCCESS },
+ { 0 }
+};
+
+struct res_target {
+ struct res_target *next;
+ const char *name; /* domain name */
+ int qclass, qtype; /* class and type of query */
+ u_char *answer; /* buffer to put answer */
+ int anslen; /* size of answer buffer */
+ int n; /* result length */
+};
+
+#define MAXPACKET (64*1024)
+
+typedef union {
+ HEADER hdr;
+ u_char buf[MAXPACKET];
+} querybuf;
+
+static int str2number(const char *, int *);
+static int explore_copy(const struct addrinfo *, const struct addrinfo *,
+ struct addrinfo **);
+static int explore_null(const struct addrinfo *,
+ const char *, struct addrinfo **);
+static int explore_numeric(const struct addrinfo *, const char *,
+ const char *, struct addrinfo **, const char *);
+static int explore_numeric_scope(const struct addrinfo *, const char *,
+ const char *, struct addrinfo **);
+static int get_canonname(const struct addrinfo *,
+ struct addrinfo *, const char *);
+static struct addrinfo *get_ai(const struct addrinfo *,
+ const struct afd *, const char *);
+static struct addrinfo *copy_ai(const struct addrinfo *);
+static int get_portmatch(const struct addrinfo *, const char *);
+static int get_port(struct addrinfo *, const char *, int);
+static const struct afd *find_afd(int);
+static int addrconfig(struct addrinfo *);
+#ifdef INET6
+static int is_ifdisabled(char *);
+#endif
+static void set_source(struct ai_order *, struct policyhead *);
+static int comp_dst(const void *, const void *);
+#ifdef INET6
+static int ip6_str2scopeid(char *, struct sockaddr_in6 *, u_int32_t *);
+#endif
+static int gai_addr2scopetype(struct sockaddr *);
+
+static int explore_fqdn(const struct addrinfo *, const char *,
+ const char *, struct addrinfo **);
+
+static int reorder(struct addrinfo *);
+static int get_addrselectpolicy(struct policyhead *);
+static void free_addrselectpolicy(struct policyhead *);
+static struct policyqueue *match_addrselectpolicy(struct sockaddr *,
+ struct policyhead *);
+static int matchlen(struct sockaddr *, struct sockaddr *);
+
+static struct addrinfo *getanswer(const querybuf *, int, const char *, int,
+ const struct addrinfo *, res_state);
+#if defined(RESOLVSORT)
+static int addr4sort(struct addrinfo *, res_state);
+#endif
+static int _dns_getaddrinfo(void *, void *, va_list);
+static void _sethtent(FILE **);
+static void _endhtent(FILE **);
+static struct addrinfo *_gethtent(FILE **, const char *,
+ const struct addrinfo *);
+static int _files_getaddrinfo(void *, void *, va_list);
+#ifdef YP
+static struct addrinfo *_yphostent(char *, const struct addrinfo *);
+static int _yp_getaddrinfo(void *, void *, va_list);
+#endif
+#ifdef NS_CACHING
+static int addrinfo_id_func(char *, size_t *, va_list, void *);
+static int addrinfo_marshal_func(char *, size_t *, void *, va_list, void *);
+static int addrinfo_unmarshal_func(char *, size_t, void *, va_list, void *);
+#endif
+
+static int res_queryN(const char *, struct res_target *, res_state);
+static int res_searchN(const char *, struct res_target *, res_state);
+static int res_querydomainN(const char *, const char *,
+ struct res_target *, res_state);
+
+/* XXX macros that make external reference is BAD. */
+
+#define GET_AI(ai, afd, addr) \
+do { \
+ /* external reference: pai, error, and label free */ \
+ (ai) = get_ai(pai, (afd), (addr)); \
+ if ((ai) == NULL) { \
+ error = EAI_MEMORY; \
+ goto free; \
+ } \
+} while (/*CONSTCOND*/0)
+
+#define GET_PORT(ai, serv) \
+do { \
+ /* external reference: error and label free */ \
+ error = get_port((ai), (serv), 0); \
+ if (error != 0) \
+ goto free; \
+} while (/*CONSTCOND*/0)
+
+#define GET_CANONNAME(ai, str) \
+do { \
+ /* external reference: pai, error and label free */ \
+ error = get_canonname(pai, (ai), (str)); \
+ if (error != 0) \
+ goto free; \
+} while (/*CONSTCOND*/0)
+
+#define ERR(err) \
+do { \
+ /* external reference: error, and label bad */ \
+ error = (err); \
+ goto bad; \
+ /*NOTREACHED*/ \
+} while (/*CONSTCOND*/0)
+
+#define MATCH_FAMILY(x, y, w) \
+ ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == PF_UNSPEC || (y) == PF_UNSPEC)))
+#define MATCH(x, y, w) \
+ ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY)))
+
+void
+freeaddrinfo(struct addrinfo *ai)
+{
+ struct addrinfo *next;
+
+ do {
+ next = ai->ai_next;
+ if (ai->ai_canonname)
+ free(ai->ai_canonname);
+ /* no need to free(ai->ai_addr) */
+ free(ai);
+ ai = next;
+ } while (ai);
+}
+
+static int
+str2number(const char *p, int *portp)
+{
+ char *ep;
+ unsigned long v;
+
+ if (*p == '\0')
+ return -1;
+ ep = NULL;
+ errno = 0;
+ v = strtoul(p, &ep, 10);
+ if (errno == 0 && ep && *ep == '\0' && v <= UINT_MAX) {
+ *portp = v;
+ return 0;
+ } else
+ return -1;
+}
+
+int
+getaddrinfo(const char *hostname, const char *servname,
+ const struct addrinfo *hints, struct addrinfo **res)
+{
+ struct addrinfo sentinel;
+ struct addrinfo *cur;
+ int error = 0;
+ struct addrinfo ai, ai0, *afai;
+ struct addrinfo *pai;
+ const struct afd *afd;
+ const struct explore *ex;
+ struct addrinfo *afailist[nitems(afdl)];
+ struct addrinfo *afai_unspec;
+ int found;
+ int numeric = 0;
+
+ /* ensure we return NULL on errors */
+ *res = NULL;
+
+ memset(&ai, 0, sizeof(ai));
+
+ memset(afailist, 0, sizeof(afailist));
+ afai_unspec = NULL;
+
+ memset(&sentinel, 0, sizeof(sentinel));
+ cur = &sentinel;
+ pai = &ai;
+ pai->ai_flags = 0;
+ pai->ai_family = PF_UNSPEC;
+ pai->ai_socktype = ANY;
+ pai->ai_protocol = ANY;
+ pai->ai_addrlen = 0;
+ pai->ai_canonname = NULL;
+ pai->ai_addr = NULL;
+ pai->ai_next = NULL;
+
+ if (hostname == NULL && servname == NULL)
+ return EAI_NONAME;
+ if (hints) {
+ /* error check for hints */
+ if (hints->ai_addrlen || hints->ai_canonname ||
+ hints->ai_addr || hints->ai_next)
+ ERR(EAI_BADHINTS); /* xxx */
+ if (hints->ai_flags & ~AI_MASK)
+ ERR(EAI_BADFLAGS);
+ switch (hints->ai_family) {
+ case PF_UNSPEC:
+ case PF_LOCAL:
+ case PF_INET:
+#ifdef INET6
+ case PF_INET6:
+#endif
+ break;
+ default:
+ ERR(EAI_FAMILY);
+ }
+ memcpy(pai, hints, sizeof(*pai));
+
+ /*
+ * if both socktype/protocol are specified, check if they
+ * are meaningful combination.
+ */
+ if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) {
+ for (ex = explore; ex->e_af >= 0; ex++) {
+ if (!MATCH_FAMILY(pai->ai_family, ex->e_af,
+ WILD_AF(ex)))
+ continue;
+ if (!MATCH(pai->ai_socktype, ex->e_socktype,
+ WILD_SOCKTYPE(ex)))
+ continue;
+ if (!MATCH(pai->ai_protocol, ex->e_protocol,
+ WILD_PROTOCOL(ex)))
+ continue;
+
+ /* matched */
+ break;
+ }
+
+ if (ex->e_af < 0)
+ ERR(EAI_BADHINTS);
+ }
+ }
+
+ /*
+ * RFC 3493: AI_ALL and AI_V4MAPPED are effective only against
+ * AF_INET6 query. They need to be ignored if specified in other
+ * occasions.
+ */
+ switch (pai->ai_flags & (AI_ALL | AI_V4MAPPED)) {
+ case AI_V4MAPPED:
+ case AI_ALL | AI_V4MAPPED:
+#ifdef INET6
+ if (pai->ai_family != AF_INET6)
+ pai->ai_flags &= ~(AI_ALL | AI_V4MAPPED);
+ break;
+#endif
+ case AI_ALL:
+ pai->ai_flags &= ~(AI_ALL | AI_V4MAPPED);
+ break;
+ }
+
+ /*
+ * check for special cases. (1) numeric servname is disallowed if
+ * socktype/protocol are left unspecified. (2) servname is disallowed
+ * for raw and other inet{,6} sockets.
+ */
+ if (MATCH_FAMILY(pai->ai_family, PF_INET, 1)
+#ifdef PF_INET6
+ || MATCH_FAMILY(pai->ai_family, PF_INET6, 1)
+#endif
+ ) {
+ ai0 = *pai; /* backup *pai */
+
+ if (pai->ai_family == PF_UNSPEC) {
+#ifdef PF_INET6
+ pai->ai_family = PF_INET6;
+#else
+ pai->ai_family = PF_INET;
+#endif
+ }
+ error = get_portmatch(pai, servname);
+ if (error)
+ goto bad;
+
+ *pai = ai0;
+ }
+
+ ai0 = *pai;
+
+ /*
+ * NULL hostname, or numeric hostname.
+ * If numeric representation of AF1 can be interpreted as FQDN
+ * representation of AF2, we need to think again about the code below.
+ */
+ found = 0;
+ for (afd = afdl; afd->a_af; afd++) {
+ *pai = ai0;
+
+ if (!MATCH_FAMILY(pai->ai_family, afd->a_af, 1))
+ continue;
+
+ if (pai->ai_family == PF_UNSPEC)
+ pai->ai_family = afd->a_af;
+
+ if (hostname == NULL) {
+ error = explore_null(pai, servname,
+ &afailist[afd - afdl]);
+
+ /*
+ * Errors from explore_null should be unexpected and
+ * be caught to avoid returning an incomplete result.
+ */
+ if (error != 0)
+ goto bad;
+ } else {
+ error = explore_numeric_scope(pai, hostname, servname,
+ &afailist[afd - afdl]);
+
+ /*
+ * explore_numeric_scope returns an error for address
+ * families that do not match that of hostname.
+ * Thus we should not catch the error at this moment.
+ */
+ }
+
+ if (!error && afailist[afd - afdl])
+ found++;
+ }
+ if (found) {
+ numeric = 1;
+ goto globcopy;
+ }
+
+ if (hostname == NULL)
+ ERR(EAI_NONAME); /* used to be EAI_NODATA */
+ if (pai->ai_flags & AI_NUMERICHOST)
+ ERR(EAI_NONAME);
+
+ if ((pai->ai_flags & AI_ADDRCONFIG) != 0 && !addrconfig(&ai0))
+ ERR(EAI_FAIL);
+
+ /*
+ * hostname as alphabetical name.
+ */
+ *pai = ai0;
+ error = explore_fqdn(pai, hostname, servname, &afai_unspec);
+
+globcopy:
+ for (ex = explore; ex->e_af >= 0; ex++) {
+ *pai = ai0;
+
+ if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex)))
+ continue;
+ if (!MATCH(pai->ai_socktype, ex->e_socktype,
+ WILD_SOCKTYPE(ex)))
+ continue;
+ if (!MATCH(pai->ai_protocol, ex->e_protocol,
+ WILD_PROTOCOL(ex)))
+ continue;
+
+ if (pai->ai_family == PF_UNSPEC)
+ pai->ai_family = ex->e_af;
+ if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
+ pai->ai_socktype = ex->e_socktype;
+ if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
+ pai->ai_protocol = ex->e_protocol;
+
+ /*
+ * if the servname does not match socktype/protocol, ignore it.
+ */
+ if (get_portmatch(pai, servname) != 0)
+ continue;
+
+ if (afai_unspec)
+ afai = afai_unspec;
+ else {
+ if ((afd = find_afd(pai->ai_family)) == NULL)
+ continue;
+ /* XXX assumes that afd points inside afdl[] */
+ afai = afailist[afd - afdl];
+ }
+ if (!afai)
+ continue;
+
+ error = explore_copy(pai, afai, &cur->ai_next);
+ if (error != 0)
+ goto bad;
+
+ while (cur && cur->ai_next)
+ cur = cur->ai_next;
+ }
+
+ /*
+ * ensure we return either:
+ * - error == 0, non-NULL *res
+ * - error != 0, NULL *res
+ */
+ if (error == 0) {
+ if (sentinel.ai_next) {
+ /*
+ * If the returned entry is for an active connection,
+ * and the given name is not numeric, reorder the
+ * list, so that the application would try the list
+ * in the most efficient order. Since the head entry
+ * of the original list may contain ai_canonname and
+ * that entry may be moved elsewhere in the new list,
+ * we keep the pointer and will restore it in the new
+ * head entry. (Note that RFC3493 requires the head
+ * entry store it when requested by the caller).
+ */
+ if (hints == NULL || !(hints->ai_flags & AI_PASSIVE)) {
+ if (!numeric) {
+ char *canonname;
+
+ canonname =
+ sentinel.ai_next->ai_canonname;
+ sentinel.ai_next->ai_canonname = NULL;
+ (void)reorder(&sentinel);
+ if (sentinel.ai_next->ai_canonname ==
+ NULL) {
+ sentinel.ai_next->ai_canonname
+ = canonname;
+ } else if (canonname != NULL)
+ free(canonname);
+ }
+ }
+ *res = sentinel.ai_next;
+ } else
+ error = EAI_FAIL;
+ }
+
+bad:
+ if (afai_unspec)
+ freeaddrinfo(afai_unspec);
+ for (afd = afdl; afd->a_af; afd++) {
+ if (afailist[afd - afdl])
+ freeaddrinfo(afailist[afd - afdl]);
+ }
+ if (!*res)
+ if (sentinel.ai_next)
+ freeaddrinfo(sentinel.ai_next);
+
+ return (error);
+}
+
+static int
+reorder(struct addrinfo *sentinel)
+{
+ struct addrinfo *ai, **aip;
+ struct ai_order *aio;
+ int i, n;
+ struct policyhead policyhead;
+
+ /* count the number of addrinfo elements for sorting. */
+ for (n = 0, ai = sentinel->ai_next; ai != NULL; ai = ai->ai_next, n++)
+ ;
+
+ /*
+ * If the number is small enough, we can skip the reordering process.
+ */
+ if (n <= 1)
+ return(n);
+
+ /* allocate a temporary array for sort and initialization of it. */
+ if ((aio = calloc(n, sizeof(*aio))) == NULL)
+ return(n); /* give up reordering */
+
+ /* retrieve address selection policy from the kernel */
+ TAILQ_INIT(&policyhead);
+ if (!get_addrselectpolicy(&policyhead)) {
+ /* no policy is installed into kernel, we don't sort. */
+ free(aio);
+ return (n);
+ }
+
+ for (i = 0, ai = sentinel->ai_next; i < n; ai = ai->ai_next, i++) {
+ aio[i].aio_ai = ai;
+ aio[i].aio_dstscope = gai_addr2scopetype(ai->ai_addr);
+ aio[i].aio_dstpolicy = match_addrselectpolicy(ai->ai_addr,
+ &policyhead);
+ set_source(&aio[i], &policyhead);
+ aio[i].aio_initial_sequence = i;
+ }
+
+ /* perform sorting. */
+ qsort(aio, n, sizeof(*aio), comp_dst);
+
+ /* reorder the addrinfo chain. */
+ for (i = 0, aip = &sentinel->ai_next; i < n; i++) {
+ *aip = aio[i].aio_ai;
+ aip = &aio[i].aio_ai->ai_next;
+ }
+ *aip = NULL;
+
+ /* cleanup and return */
+ free(aio);
+ free_addrselectpolicy(&policyhead);
+ return(n);
+}
+
+static int
+get_addrselectpolicy(struct policyhead *head)
+{
+#ifdef INET6
+ int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_ADDRCTLPOLICY };
+ size_t l;
+ char *buf;
+ struct in6_addrpolicy *pol, *ep;
+
+ if (sysctl(mib, nitems(mib), NULL, &l, NULL, 0) < 0)
+ return (0);
+ if (l == 0)
+ return (0);
+ if ((buf = malloc(l)) == NULL)
+ return (0);
+ if (sysctl(mib, nitems(mib), buf, &l, NULL, 0) < 0) {
+ free(buf);
+ return (0);
+ }
+
+ ep = (struct in6_addrpolicy *)(buf + l);
+ for (pol = (struct in6_addrpolicy *)buf; pol + 1 <= ep; pol++) {
+ struct policyqueue *new;
+
+ if ((new = malloc(sizeof(*new))) == NULL) {
+ free_addrselectpolicy(head); /* make the list empty */
+ break;
+ }
+ new->pc_policy = *pol;
+ TAILQ_INSERT_TAIL(head, new, pc_entry);
+ }
+
+ free(buf);
+ return (1);
+#else
+ return (0);
+#endif
+}
+
+static void
+free_addrselectpolicy(struct policyhead *head)
+{
+ struct policyqueue *ent, *nent;
+
+ for (ent = TAILQ_FIRST(head); ent; ent = nent) {
+ nent = TAILQ_NEXT(ent, pc_entry);
+ TAILQ_REMOVE(head, ent, pc_entry);
+ free(ent);
+ }
+}
+
+static struct policyqueue *
+match_addrselectpolicy(struct sockaddr *addr, struct policyhead *head)
+{
+#ifdef INET6
+ struct policyqueue *ent, *bestent = NULL;
+ struct in6_addrpolicy *pol;
+ int matchlen, bestmatchlen = -1;
+ u_char *mp, *ep, *k, *p, m;
+ struct sockaddr_in6 key;
+
+ switch(addr->sa_family) {
+ case AF_INET6:
+ key = *(struct sockaddr_in6 *)addr;
+ break;
+ case AF_INET:
+ /* convert the address into IPv4-mapped IPv6 address. */
+ memset(&key, 0, sizeof(key));
+ key.sin6_family = AF_INET6;
+ key.sin6_len = sizeof(key);
+ _map_v4v6_address(
+ (char *)&((struct sockaddr_in *)addr)->sin_addr,
+ (char *)&key.sin6_addr);
+ break;
+ default:
+ return(NULL);
+ }
+
+ for (ent = TAILQ_FIRST(head); ent; ent = TAILQ_NEXT(ent, pc_entry)) {
+ pol = &ent->pc_policy;
+ matchlen = 0;
+
+ mp = (u_char *)&pol->addrmask.sin6_addr;
+ ep = mp + 16; /* XXX: scope field? */
+ k = (u_char *)&key.sin6_addr;
+ p = (u_char *)&pol->addr.sin6_addr;
+ for (; mp < ep && *mp; mp++, k++, p++) {
+ m = *mp;
+ if ((*k & m) != *p)
+ goto next; /* not match */
+ if (m == 0xff) /* short cut for a typical case */
+ matchlen += 8;
+ else {
+ while (m >= 0x80) {
+ matchlen++;
+ m <<= 1;
+ }
+ }
+ }
+
+ /* matched. check if this is better than the current best. */
+ if (matchlen > bestmatchlen) {
+ bestent = ent;
+ bestmatchlen = matchlen;
+ }
+
+ next:
+ continue;
+ }
+
+ return(bestent);
+#else
+ return(NULL);
+#endif
+
+}
+
+static void
+set_source(struct ai_order *aio, struct policyhead *ph)
+{
+ struct addrinfo ai = *aio->aio_ai;
+ struct sockaddr_storage ss;
+ socklen_t srclen;
+ int s;
+
+ /* set unspec ("no source is available"), just in case */
+ aio->aio_srcsa.sa_family = AF_UNSPEC;
+ aio->aio_srcscope = -1;
+
+ switch(ai.ai_family) {
+ case AF_INET:
+#ifdef INET6
+ case AF_INET6:
+#endif
+ break;
+ default: /* ignore unsupported AFs explicitly */
+ return;
+ }
+
+ /* XXX: make a dummy addrinfo to call connect() */
+ ai.ai_socktype = SOCK_DGRAM;
+ ai.ai_protocol = IPPROTO_UDP; /* is UDP too specific? */
+ ai.ai_next = NULL;
+ memset(&ss, 0, sizeof(ss));
+ memcpy(&ss, ai.ai_addr, ai.ai_addrlen);
+ ai.ai_addr = (struct sockaddr *)&ss;
+ get_port(&ai, "1", 0);
+
+ /* open a socket to get the source address for the given dst */
+ if ((s = _socket(ai.ai_family, ai.ai_socktype | SOCK_CLOEXEC,
+ ai.ai_protocol)) < 0)
+ return; /* give up */
+#ifdef INET6
+ if (ai.ai_family == AF_INET6) {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ai.ai_addr;
+ int off = 0;
+
+ if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
+ (void)_setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
+ (char *)&off, sizeof(off));
+ }
+#endif
+ if (_connect(s, ai.ai_addr, ai.ai_addrlen) < 0)
+ goto cleanup;
+ srclen = ai.ai_addrlen;
+ if (_getsockname(s, &aio->aio_srcsa, &srclen) < 0) {
+ aio->aio_srcsa.sa_family = AF_UNSPEC;
+ goto cleanup;
+ }
+ aio->aio_srcscope = gai_addr2scopetype(&aio->aio_srcsa);
+ aio->aio_srcpolicy = match_addrselectpolicy(&aio->aio_srcsa, ph);
+ aio->aio_matchlen = matchlen(&aio->aio_srcsa, aio->aio_ai->ai_addr);
+#ifdef INET6
+ if (ai.ai_family == AF_INET6) {
+ struct in6_ifreq ifr6;
+ u_int32_t flags6;
+
+ memset(&ifr6, 0, sizeof(ifr6));
+ memcpy(&ifr6.ifr_addr, ai.ai_addr, ai.ai_addrlen);
+ if (_ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) == 0) {
+ flags6 = ifr6.ifr_ifru.ifru_flags6;
+ if ((flags6 & IN6_IFF_DEPRECATED))
+ aio->aio_srcflag |= AIO_SRCFLAG_DEPRECATED;
+ }
+ }
+#endif
+
+ cleanup:
+ _close(s);
+ return;
+}
+
+static int
+matchlen(struct sockaddr *src, struct sockaddr *dst)
+{
+ int match = 0;
+ u_char *s, *d;
+ u_char *lim, r;
+ int addrlen;
+
+ switch (src->sa_family) {
+#ifdef INET6
+ case AF_INET6:
+ s = (u_char *)&((struct sockaddr_in6 *)src)->sin6_addr;
+ d = (u_char *)&((struct sockaddr_in6 *)dst)->sin6_addr;
+ addrlen = sizeof(struct in6_addr);
+ lim = s + addrlen;
+ break;
+#endif
+ case AF_INET:
+ s = (u_char *)&((struct sockaddr_in *)src)->sin_addr;
+ d = (u_char *)&((struct sockaddr_in *)dst)->sin_addr;
+ addrlen = sizeof(struct in_addr);
+ lim = s + addrlen;
+ break;
+ default:
+ return(0);
+ }
+
+ while (s < lim)
+ if ((r = (*d++ ^ *s++)) != 0) {
+ while ((r & 0x80) == 0) {
+ match++;
+ r <<= 1;
+ }
+ break;
+ } else
+ match += 8;
+ return(match);
+}
+
+static int
+comp_dst(const void *arg1, const void *arg2)
+{
+ const struct ai_order *dst1 = arg1, *dst2 = arg2;
+
+ /*
+ * Rule 1: Avoid unusable destinations.
+ * XXX: we currently do not consider if an appropriate route exists.
+ */
+ if (dst1->aio_srcsa.sa_family != AF_UNSPEC &&
+ dst2->aio_srcsa.sa_family == AF_UNSPEC) {
+ return(-1);
+ }
+ if (dst1->aio_srcsa.sa_family == AF_UNSPEC &&
+ dst2->aio_srcsa.sa_family != AF_UNSPEC) {
+ return(1);
+ }
+
+ /* Rule 2: Prefer matching scope. */
+ if (dst1->aio_dstscope == dst1->aio_srcscope &&
+ dst2->aio_dstscope != dst2->aio_srcscope) {
+ return(-1);
+ }
+ if (dst1->aio_dstscope != dst1->aio_srcscope &&
+ dst2->aio_dstscope == dst2->aio_srcscope) {
+ return(1);
+ }
+
+ /* Rule 3: Avoid deprecated addresses. */
+ if (dst1->aio_srcsa.sa_family != AF_UNSPEC &&
+ dst2->aio_srcsa.sa_family != AF_UNSPEC) {
+ if (!(dst1->aio_srcflag & AIO_SRCFLAG_DEPRECATED) &&
+ (dst2->aio_srcflag & AIO_SRCFLAG_DEPRECATED)) {
+ return(-1);
+ }
+ if ((dst1->aio_srcflag & AIO_SRCFLAG_DEPRECATED) &&
+ !(dst2->aio_srcflag & AIO_SRCFLAG_DEPRECATED)) {
+ return(1);
+ }
+ }
+
+ /* Rule 4: Prefer home addresses. */
+ /* XXX: not implemented yet */
+
+ /* Rule 5: Prefer matching label. */
+#ifdef INET6
+ if (dst1->aio_srcpolicy && dst1->aio_dstpolicy &&
+ dst1->aio_srcpolicy->pc_policy.label ==
+ dst1->aio_dstpolicy->pc_policy.label &&
+ (dst2->aio_srcpolicy == NULL || dst2->aio_dstpolicy == NULL ||
+ dst2->aio_srcpolicy->pc_policy.label !=
+ dst2->aio_dstpolicy->pc_policy.label)) {
+ return(-1);
+ }
+ if (dst2->aio_srcpolicy && dst2->aio_dstpolicy &&
+ dst2->aio_srcpolicy->pc_policy.label ==
+ dst2->aio_dstpolicy->pc_policy.label &&
+ (dst1->aio_srcpolicy == NULL || dst1->aio_dstpolicy == NULL ||
+ dst1->aio_srcpolicy->pc_policy.label !=
+ dst1->aio_dstpolicy->pc_policy.label)) {
+ return(1);
+ }
+#endif
+
+ /* Rule 6: Prefer higher precedence. */
+#ifdef INET6
+ if (dst1->aio_dstpolicy &&
+ (dst2->aio_dstpolicy == NULL ||
+ dst1->aio_dstpolicy->pc_policy.preced >
+ dst2->aio_dstpolicy->pc_policy.preced)) {
+ return(-1);
+ }
+ if (dst2->aio_dstpolicy &&
+ (dst1->aio_dstpolicy == NULL ||
+ dst2->aio_dstpolicy->pc_policy.preced >
+ dst1->aio_dstpolicy->pc_policy.preced)) {
+ return(1);
+ }
+#endif
+
+ /* Rule 7: Prefer native transport. */
+ /* XXX: not implemented yet */
+
+ /* Rule 8: Prefer smaller scope. */
+ if (dst1->aio_dstscope >= 0 &&
+ dst1->aio_dstscope < dst2->aio_dstscope) {
+ return(-1);
+ }
+ if (dst2->aio_dstscope >= 0 &&
+ dst2->aio_dstscope < dst1->aio_dstscope) {
+ return(1);
+ }
+
+ /*
+ * Rule 9: Use longest matching prefix.
+ * We compare the match length in a same AF only.
+ */
+ if (dst1->aio_ai->ai_addr->sa_family ==
+ dst2->aio_ai->ai_addr->sa_family &&
+ dst1->aio_ai->ai_addr->sa_family != AF_INET) {
+ if (dst1->aio_matchlen > dst2->aio_matchlen) {
+ return(-1);
+ }
+ if (dst1->aio_matchlen < dst2->aio_matchlen) {
+ return(1);
+ }
+ }
+
+ /* Rule 10: Otherwise, leave the order unchanged. */
+
+ /*
+ * Note that qsort is unstable; so, we can't return zero and
+ * expect the order to be unchanged.
+ * That also means we can't depend on the current position of
+ * dst2 being after dst1. We must enforce the initial order
+ * with an explicit compare on the original position.
+ * The qsort specification requires that "When the same objects
+ * (consisting of width bytes, irrespective of their current
+ * positions in the array) are passed more than once to the
+ * comparison function, the results shall be consistent with one
+ * another."
+ * In other words, If A < B, then we must also return B > A.
+ */
+ if (dst2->aio_initial_sequence < dst1->aio_initial_sequence)
+ return(1);
+
+ return(-1);
+}
+
+/*
+ * Copy from scope.c.
+ * XXX: we should standardize the functions and link them as standard
+ * library.
+ */
+static int
+gai_addr2scopetype(struct sockaddr *sa)
+{
+#ifdef INET6
+ struct sockaddr_in6 *sa6;
+#endif
+ struct sockaddr_in *sa4;
+
+ switch(sa->sa_family) {
+#ifdef INET6
+ case AF_INET6:
+ sa6 = (struct sockaddr_in6 *)sa;
+ if (IN6_IS_ADDR_MULTICAST(&sa6->sin6_addr)) {
+ /* just use the scope field of the multicast address */
+ return(sa6->sin6_addr.s6_addr[2] & 0x0f);
+ }
+ /*
+ * Unicast addresses: map scope type to corresponding scope
+ * value defined for multcast addresses.
+ * XXX: hardcoded scope type values are bad...
+ */
+ if (IN6_IS_ADDR_LOOPBACK(&sa6->sin6_addr))
+ return(1); /* node local scope */
+ if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr))
+ return(2); /* link-local scope */
+ if (IN6_IS_ADDR_SITELOCAL(&sa6->sin6_addr))
+ return(5); /* site-local scope */
+ return(14); /* global scope */
+ break;
+#endif
+ case AF_INET:
+ /*
+ * IPv4 pseudo scoping according to RFC 3484.
+ */
+ sa4 = (struct sockaddr_in *)sa;
+ /* IPv4 autoconfiguration addresses have link-local scope. */
+ if (((u_char *)&sa4->sin_addr)[0] == 169 &&
+ ((u_char *)&sa4->sin_addr)[1] == 254)
+ return(2);
+ /* Private addresses have site-local scope. */
+ if (((u_char *)&sa4->sin_addr)[0] == 10 ||
+ (((u_char *)&sa4->sin_addr)[0] == 172 &&
+ (((u_char *)&sa4->sin_addr)[1] & 0xf0) == 16) ||
+ (((u_char *)&sa4->sin_addr)[0] == 192 &&
+ ((u_char *)&sa4->sin_addr)[1] == 168))
+ return(14); /* XXX: It should be 5 unless NAT */
+ /* Loopback addresses have link-local scope. */
+ if (((u_char *)&sa4->sin_addr)[0] == 127)
+ return(2);
+ return(14);
+ break;
+ default:
+ errno = EAFNOSUPPORT; /* is this a good error? */
+ return(-1);
+ }
+}
+
+static int
+explore_copy(const struct addrinfo *pai, const struct addrinfo *src0,
+ struct addrinfo **res)
+{
+ int error;
+ struct addrinfo sentinel, *cur;
+ const struct addrinfo *src;
+
+ error = 0;
+ sentinel.ai_next = NULL;
+ cur = &sentinel;
+
+ for (src = src0; src != NULL; src = src->ai_next) {
+ if (src->ai_family != pai->ai_family)
+ continue;
+
+ cur->ai_next = copy_ai(src);
+ if (!cur->ai_next) {
+ error = EAI_MEMORY;
+ goto fail;
+ }
+
+ cur->ai_next->ai_socktype = pai->ai_socktype;
+ cur->ai_next->ai_protocol = pai->ai_protocol;
+ cur = cur->ai_next;
+ }
+
+ *res = sentinel.ai_next;
+ return 0;
+
+fail:
+ freeaddrinfo(sentinel.ai_next);
+ return error;
+}
+
+/*
+ * hostname == NULL.
+ * passive socket -> anyaddr (0.0.0.0 or ::)
+ * non-passive socket -> localhost (127.0.0.1 or ::1)
+ */
+static int
+explore_null(const struct addrinfo *pai, const char *servname,
+ struct addrinfo **res)
+{
+ int s;
+ const struct afd *afd;
+ struct addrinfo *ai;
+ int error;
+
+ *res = NULL;
+ ai = NULL;
+
+ if (pai->ai_family == PF_LOCAL)
+ return (0);
+
+ /*
+ * filter out AFs that are not supported by the kernel
+ * XXX errno?
+ */
+ s = _socket(pai->ai_family, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+ if (s < 0) {
+ if (errno != EMFILE)
+ return 0;
+ } else
+ _close(s);
+
+ afd = find_afd(pai->ai_family);
+ if (afd == NULL)
+ return 0;
+
+ if (pai->ai_flags & AI_PASSIVE) {
+ GET_AI(ai, afd, afd->a_addrany);
+ GET_PORT(ai, servname);
+ } else {
+ GET_AI(ai, afd, afd->a_loopback);
+ GET_PORT(ai, servname);
+ }
+
+ *res = ai;
+ return 0;
+
+free:
+ if (ai != NULL)
+ freeaddrinfo(ai);
+ return error;
+}
+
+/*
+ * numeric hostname
+ */
+static int
+explore_numeric(const struct addrinfo *pai, const char *hostname,
+ const char *servname, struct addrinfo **res, const char *canonname)
+{
+ const struct afd *afd;
+ struct addrinfo *ai, ai0;
+ int error;
+ char pton[PTON_MAX], path[PATH_MAX], *p;
+
+#ifdef CTASSERT
+ CTASSERT(sizeofmember(struct sockaddr_un, sun_path) <= PATH_MAX);
+#endif
+ *res = NULL;
+ ai = NULL;
+
+ afd = find_afd(pai->ai_family);
+ if (afd == NULL)
+ return 0;
+
+ switch (afd->a_af) {
+ case AF_LOCAL:
+ if (hostname[0] != '/')
+ ERR(EAI_NONAME);
+ if (strlen(hostname) > afd->a_addrlen)
+ ERR(EAI_MEMORY);
+ /* NUL-termination does not need to be guaranteed. */
+ strncpy(path, hostname, afd->a_addrlen);
+ p = &path[0];
+ break;
+ case AF_INET:
+ /*
+ * RFC3493 requires getaddrinfo() to accept AF_INET formats
+ * that are accepted by inet_addr() and its family. The
+ * accepted forms includes the "classful" one, which inet_pton
+ * does not accept. So we need to separate the case for
+ * AF_INET.
+ */
+ if (inet_aton(hostname, (struct in_addr *)pton) != 1)
+ return 0;
+ p = pton;
+ break;
+ default:
+ if (inet_pton(afd->a_af, hostname, pton) != 1) {
+ if (pai->ai_family != AF_INET6 ||
+ (pai->ai_flags & AI_V4MAPPED) != AI_V4MAPPED)
+ return 0;
+ if (inet_aton(hostname, (struct in_addr *)pton) != 1)
+ return 0;
+ afd = &afdl[N_INET];
+ ai0 = *pai;
+ ai0.ai_family = AF_INET;
+ pai = &ai0;
+ }
+ p = pton;
+ break;
+ }
+
+ if (pai->ai_family == afd->a_af) {
+ GET_AI(ai, afd, p);
+ GET_PORT(ai, servname);
+ if ((pai->ai_family == AF_INET ||
+ pai->ai_family == AF_INET6) &&
+ (pai->ai_flags & AI_CANONNAME)) {
+ /*
+ * Set the numeric address itself as the canonical
+ * name, based on a clarification in RFC3493.
+ */
+ GET_CANONNAME(ai, canonname);
+ }
+ } else {
+ /*
+ * XXX: This should not happen since we already matched the AF
+ * by find_afd.
+ */
+ ERR(EAI_FAMILY);
+ }
+
+ *res = ai;
+ return 0;
+
+free:
+bad:
+ if (ai != NULL)
+ freeaddrinfo(ai);
+ return error;
+}
+
+/*
+ * numeric hostname with scope
+ */
+static int
+explore_numeric_scope(const struct addrinfo *pai, const char *hostname,
+ const char *servname, struct addrinfo **res)
+{
+#if !defined(SCOPE_DELIMITER) || !defined(INET6)
+ return explore_numeric(pai, hostname, servname, res, hostname);
+#else
+ const struct afd *afd;
+ struct addrinfo *cur;
+ int error;
+ char *cp, *hostname2 = NULL, *scope, *addr;
+ struct sockaddr_in6 *sin6;
+
+ afd = find_afd(pai->ai_family);
+ if (afd == NULL)
+ return 0;
+
+ if (!afd->a_scoped)
+ return explore_numeric(pai, hostname, servname, res, hostname);
+
+ cp = strchr(hostname, SCOPE_DELIMITER);
+ if (cp == NULL)
+ return explore_numeric(pai, hostname, servname, res, hostname);
+
+ /*
+ * Handle special case of <scoped_address><delimiter><scope id>
+ */
+ hostname2 = strdup(hostname);
+ if (hostname2 == NULL)
+ return EAI_MEMORY;
+ /* terminate at the delimiter */
+ hostname2[cp - hostname] = '\0';
+ addr = hostname2;
+ scope = cp + 1;
+
+ error = explore_numeric(pai, addr, servname, res, hostname);
+ if (error == 0) {
+ u_int32_t scopeid;
+
+ for (cur = *res; cur; cur = cur->ai_next) {
+ if (cur->ai_family != AF_INET6)
+ continue;
+ sin6 = (struct sockaddr_in6 *)(void *)cur->ai_addr;
+ if (ip6_str2scopeid(scope, sin6, &scopeid) == -1) {
+ free(hostname2);
+ freeaddrinfo(*res);
+ *res = NULL;
+ return(EAI_NONAME); /* XXX: is return OK? */
+ }
+ sin6->sin6_scope_id = scopeid;
+ }
+ }
+
+ free(hostname2);
+
+ if (error && *res) {
+ freeaddrinfo(*res);
+ *res = NULL;
+ }
+ return error;
+#endif
+}
+
+static int
+get_canonname(const struct addrinfo *pai, struct addrinfo *ai, const char *str)
+{
+ if ((pai->ai_flags & AI_CANONNAME) != 0) {
+ ai->ai_canonname = strdup(str);
+ if (ai->ai_canonname == NULL)
+ return EAI_MEMORY;
+ }
+ return 0;
+}
+
+static struct addrinfo *
+get_ai(const struct addrinfo *pai, const struct afd *afd, const char *addr)
+{
+ char *p;
+ struct addrinfo *ai;
+#ifdef INET6
+ struct in6_addr mapaddr;
+
+ if (afd->a_af == AF_INET && (pai->ai_flags & AI_V4MAPPED) != 0) {
+ afd = &afdl[N_INET6];
+ _map_v4v6_address(addr, (char *)&mapaddr);
+ addr = (char *)&mapaddr;
+ }
+#endif
+
+ ai = (struct addrinfo *)malloc(sizeof(struct addrinfo)
+ + (afd->a_socklen));
+ if (ai == NULL)
+ return NULL;
+
+ memcpy(ai, pai, sizeof(struct addrinfo));
+ ai->ai_addr = (struct sockaddr *)(void *)(ai + 1);
+ memset(ai->ai_addr, 0, (size_t)afd->a_socklen);
+ ai->ai_addr->sa_len = afd->a_socklen;
+ ai->ai_addrlen = afd->a_socklen;
+ if (ai->ai_family == PF_LOCAL) {
+ size_t n = strnlen(addr, afd->a_addrlen);
+
+ ai->ai_addrlen -= afd->a_addrlen - n;
+ ai->ai_addr->sa_len -= afd->a_addrlen - n;
+ }
+ ai->ai_addr->sa_family = ai->ai_family = afd->a_af;
+ p = (char *)(void *)(ai->ai_addr);
+ memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen);
+ return ai;
+}
+
+/* XXX need to malloc() the same way we do from other functions! */
+static struct addrinfo *
+copy_ai(const struct addrinfo *pai)
+{
+ struct addrinfo *ai;
+ size_t l;
+
+ l = sizeof(*ai) + pai->ai_addrlen;
+ if ((ai = calloc(1, l)) == NULL)
+ return NULL;
+ memcpy(ai, pai, sizeof(*ai));
+ ai->ai_addr = (struct sockaddr *)(void *)(ai + 1);
+ memcpy(ai->ai_addr, pai->ai_addr, pai->ai_addrlen);
+
+ if (pai->ai_canonname) {
+ l = strlen(pai->ai_canonname) + 1;
+ if ((ai->ai_canonname = malloc(l)) == NULL) {
+ free(ai);
+ return NULL;
+ }
+ strlcpy(ai->ai_canonname, pai->ai_canonname, l);
+ } else {
+ /* just to make sure */
+ ai->ai_canonname = NULL;
+ }
+
+ ai->ai_next = NULL;
+
+ return ai;
+}
+
+static int
+get_portmatch(const struct addrinfo *ai, const char *servname)
+{
+
+ /* get_port does not touch first argument when matchonly == 1. */
+ /* LINTED const cast */
+ return get_port((struct addrinfo *)ai, servname, 1);
+}
+
+static int
+get_port(struct addrinfo *ai, const char *servname, int matchonly)
+{
+ const char *proto;
+ struct servent *sp;
+ int port, error;
+ int allownumeric;
+
+ if (servname == NULL)
+ return 0;
+ switch (ai->ai_family) {
+ case AF_LOCAL:
+ /* AF_LOCAL ignores servname silently. */
+ return (0);
+ case AF_INET:
+#ifdef AF_INET6
+ case AF_INET6:
+#endif
+ break;
+ default:
+ return 0;
+ }
+
+ switch (ai->ai_socktype) {
+ case SOCK_RAW:
+ return EAI_SERVICE;
+ case SOCK_DGRAM:
+ case SOCK_STREAM:
+ case SOCK_SEQPACKET:
+ allownumeric = 1;
+ break;
+ case ANY:
+ switch (ai->ai_family) {
+ case AF_INET:
+#ifdef AF_INET6
+ case AF_INET6:
+#endif
+ allownumeric = 1;
+ break;
+ default:
+ allownumeric = 0;
+ break;
+ }
+ break;
+ default:
+ return EAI_SOCKTYPE;
+ }
+
+ error = str2number(servname, &port);
+ if (error == 0) {
+ if (!allownumeric)
+ return EAI_SERVICE;
+ if (port < 0 || port > 65535)
+ return EAI_SERVICE;
+ port = htons(port);
+ } else {
+ if (ai->ai_flags & AI_NUMERICSERV)
+ return EAI_NONAME;
+
+ switch (ai->ai_protocol) {
+ case IPPROTO_UDP:
+ proto = "udp";
+ break;
+ case IPPROTO_TCP:
+ proto = "tcp";
+ break;
+ case IPPROTO_SCTP:
+ proto = "sctp";
+ break;
+ case IPPROTO_UDPLITE:
+ proto = "udplite";
+ break;
+ default:
+ proto = NULL;
+ break;
+ }
+
+ if ((sp = getservbyname(servname, proto)) == NULL)
+ return EAI_SERVICE;
+ port = sp->s_port;
+ }
+
+ if (!matchonly) {
+ switch (ai->ai_family) {
+ case AF_INET:
+ ((struct sockaddr_in *)(void *)
+ ai->ai_addr)->sin_port = port;
+ break;
+#ifdef INET6
+ case AF_INET6:
+ ((struct sockaddr_in6 *)(void *)
+ ai->ai_addr)->sin6_port = port;
+ break;
+#endif
+ }
+ }
+
+ return 0;
+}
+
+static const struct afd *
+find_afd(int af)
+{
+ const struct afd *afd;
+
+ if (af == PF_UNSPEC)
+ return NULL;
+ for (afd = afdl; afd->a_af; afd++) {
+ if (afd->a_af == af)
+ return afd;
+ }
+ return NULL;
+}
+
+/*
+ * RFC 3493: AI_ADDRCONFIG check. Determines which address families are
+ * configured on the local system and correlates with pai->ai_family value.
+ * If an address family is not configured on the system, it will not be
+ * queried for. For this purpose, loopback addresses are not considered
+ * configured addresses.
+ *
+ * XXX PF_UNSPEC -> PF_INET6 + PF_INET mapping needs to be in sync with
+ * _dns_getaddrinfo.
+ */
+static int
+addrconfig(struct addrinfo *pai)
+{
+ struct ifaddrs *ifaddrs, *ifa;
+ struct sockaddr_in *sin;
+#ifdef INET6
+ struct sockaddr_in6 *sin6;
+#endif
+ int seen_inet = 0, seen_inet6 = 0;
+
+ if (getifaddrs(&ifaddrs) != 0)
+ return (0);
+
+ for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr == NULL || (ifa->ifa_flags & IFF_UP) == 0)
+ continue;
+ switch (ifa->ifa_addr->sa_family) {
+ case AF_INET:
+ if (seen_inet)
+ continue;
+ sin = (struct sockaddr_in *)(ifa->ifa_addr);
+ if (htonl(sin->sin_addr.s_addr) == INADDR_LOOPBACK)
+ continue;
+ seen_inet = 1;
+ break;
+#ifdef INET6
+ case AF_INET6:
+ if (seen_inet6)
+ continue;
+ sin6 = (struct sockaddr_in6 *)(ifa->ifa_addr);
+ if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr))
+ continue;
+ if ((ifa->ifa_flags & IFT_LOOP) != 0 &&
+ IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
+ continue;
+ if (is_ifdisabled(ifa->ifa_name))
+ continue;
+ seen_inet6 = 1;
+ break;
+#endif
+ }
+ }
+ freeifaddrs(ifaddrs);
+
+ switch(pai->ai_family) {
+ case AF_INET6:
+ return (seen_inet6);
+ case AF_INET:
+ return (seen_inet);
+ case AF_UNSPEC:
+ if (seen_inet == seen_inet6)
+ return (seen_inet);
+ pai->ai_family = seen_inet ? AF_INET : AF_INET6;
+ return (1);
+ }
+ return (1);
+}
+
+#ifdef INET6
+static int
+is_ifdisabled(char *name)
+{
+ struct in6_ndireq nd;
+ int fd;
+
+ if ((fd = _socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0)) < 0)
+ return (-1);
+ memset(&nd, 0, sizeof(nd));
+ strlcpy(nd.ifname, name, sizeof(nd.ifname));
+ if (_ioctl(fd, SIOCGIFINFO_IN6, &nd) < 0) {
+ _close(fd);
+ return (-1);
+ }
+ _close(fd);
+ return ((nd.ndi.flags & ND6_IFF_IFDISABLED) != 0);
+}
+
+/* convert a string to a scope identifier. XXX: IPv6 specific */
+static int
+ip6_str2scopeid(char *scope, struct sockaddr_in6 *sin6, u_int32_t *scopeid)
+{
+ u_long lscopeid;
+ struct in6_addr *a6;
+ char *ep;
+
+ a6 = &sin6->sin6_addr;
+
+ /* empty scopeid portion is invalid */
+ if (*scope == '\0')
+ return -1;
+
+ if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6) ||
+ IN6_IS_ADDR_MC_NODELOCAL(a6)) {
+ /*
+ * We currently assume a one-to-one mapping between links
+ * and interfaces, so we simply use interface indices for
+ * like-local scopes.
+ */
+ *scopeid = if_nametoindex(scope);
+ if (*scopeid == 0)
+ goto trynumeric;
+ return 0;
+ }
+
+ /* still unclear about literal, allow numeric only - placeholder */
+ if (IN6_IS_ADDR_SITELOCAL(a6) || IN6_IS_ADDR_MC_SITELOCAL(a6))
+ goto trynumeric;
+ if (IN6_IS_ADDR_MC_ORGLOCAL(a6))
+ goto trynumeric;
+ else
+ goto trynumeric; /* global */
+
+ /* try to convert to a numeric id as a last resort */
+ trynumeric:
+ errno = 0;
+ lscopeid = strtoul(scope, &ep, 10);
+ *scopeid = (u_int32_t)(lscopeid & 0xffffffffUL);
+ if (errno == 0 && ep && *ep == '\0' && *scopeid == lscopeid)
+ return 0;
+ else
+ return -1;
+}
+#endif
+
+
+#ifdef NS_CACHING
+static int
+addrinfo_id_func(char *buffer, size_t *buffer_size, va_list ap,
+ void *cache_mdata)
+{
+ res_state statp;
+ u_long res_options;
+
+ const int op_id = 0; /* identifies the getaddrinfo for the cache */
+ char *hostname;
+ struct addrinfo *hints;
+
+ char *p;
+ int ai_flags, ai_family, ai_socktype, ai_protocol;
+ size_t desired_size, size;
+
+ statp = __res_state();
+ res_options = statp->options & (RES_RECURSE | RES_DEFNAMES |
+ RES_DNSRCH | RES_NOALIASES | RES_USE_INET6);
+
+ hostname = va_arg(ap, char *);
+ hints = va_arg(ap, struct addrinfo *);
+
+ desired_size = sizeof(res_options) + sizeof(int) + sizeof(int) * 4;
+ if (hostname != NULL) {
+ size = strlen(hostname);
+ desired_size += size + 1;
+ } else
+ size = 0;
+
+ if (desired_size > *buffer_size) {
+ *buffer_size = desired_size;
+ return (NS_RETURN);
+ }
+
+ if (hints == NULL)
+ ai_flags = ai_family = ai_socktype = ai_protocol = 0;
+ else {
+ ai_flags = hints->ai_flags;
+ ai_family = hints->ai_family;
+ ai_socktype = hints->ai_socktype;
+ ai_protocol = hints->ai_protocol;
+ }
+
+ p = buffer;
+ memcpy(p, &res_options, sizeof(res_options));
+ p += sizeof(res_options);
+
+ memcpy(p, &op_id, sizeof(int));
+ p += sizeof(int);
+
+ memcpy(p, &ai_flags, sizeof(int));
+ p += sizeof(int);
+
+ memcpy(p, &ai_family, sizeof(int));
+ p += sizeof(int);
+
+ memcpy(p, &ai_socktype, sizeof(int));
+ p += sizeof(int);
+
+ memcpy(p, &ai_protocol, sizeof(int));
+ p += sizeof(int);
+
+ if (hostname != NULL)
+ memcpy(p, hostname, size);
+
+ *buffer_size = desired_size;
+ return (NS_SUCCESS);
+}
+
+static int
+addrinfo_marshal_func(char *buffer, size_t *buffer_size, void *retval,
+ va_list ap, void *cache_mdata)
+{
+ struct addrinfo *ai, *cai;
+ char *p;
+ size_t desired_size, size, ai_size;
+
+ ai = *((struct addrinfo **)retval);
+
+ desired_size = sizeof(size_t);
+ ai_size = 0;
+ for (cai = ai; cai != NULL; cai = cai->ai_next) {
+ desired_size += sizeof(struct addrinfo) + cai->ai_addrlen;
+ if (cai->ai_canonname != NULL)
+ desired_size += sizeof(size_t) +
+ strlen(cai->ai_canonname);
+ ++ai_size;
+ }
+
+ if (desired_size > *buffer_size) {
+ /* this assignment is here for future use */
+ errno = ERANGE;
+ *buffer_size = desired_size;
+ return (NS_RETURN);
+ }
+
+ memset(buffer, 0, desired_size);
+ p = buffer;
+
+ memcpy(p, &ai_size, sizeof(size_t));
+ p += sizeof(size_t);
+ for (cai = ai; cai != NULL; cai = cai->ai_next) {
+ memcpy(p, cai, sizeof(struct addrinfo));
+ p += sizeof(struct addrinfo);
+
+ memcpy(p, cai->ai_addr, cai->ai_addrlen);
+ p += cai->ai_addrlen;
+
+ if (cai->ai_canonname != NULL) {
+ size = strlen(cai->ai_canonname);
+ memcpy(p, &size, sizeof(size_t));
+ p += sizeof(size_t);
+
+ memcpy(p, cai->ai_canonname, size);
+ p += size;
+ }
+ }
+
+ return (NS_SUCCESS);
+}
+
+static int
+addrinfo_unmarshal_func(char *buffer, size_t buffer_size, void *retval,
+ va_list ap, void *cache_mdata)
+{
+ struct addrinfo new_ai, *result, *sentinel, *lasts;
+
+ char *p;
+ size_t ai_size, ai_i, size;
+
+ p = buffer;
+ memcpy(&ai_size, p, sizeof(size_t));
+ p += sizeof(size_t);
+
+ result = NULL;
+ lasts = NULL;
+ for (ai_i = 0; ai_i < ai_size; ++ai_i) {
+ memcpy(&new_ai, p, sizeof(struct addrinfo));
+ p += sizeof(struct addrinfo);
+ size = new_ai.ai_addrlen + sizeof(struct addrinfo) +
+ _ALIGNBYTES;
+
+ sentinel = calloc(1, size);
+
+ memcpy(sentinel, &new_ai, sizeof(struct addrinfo));
+ sentinel->ai_addr = (struct sockaddr *)_ALIGN((char *)sentinel +
+ sizeof(struct addrinfo));
+
+ memcpy(sentinel->ai_addr, p, new_ai.ai_addrlen);
+ p += new_ai.ai_addrlen;
+
+ if (new_ai.ai_canonname != NULL) {
+ memcpy(&size, p, sizeof(size_t));
+ p += sizeof(size_t);
+
+ sentinel->ai_canonname = calloc(1, size + 1);
+
+ memcpy(sentinel->ai_canonname, p, size);
+ p += size;
+ }
+
+ if (result == NULL) {
+ result = sentinel;
+ lasts = sentinel;
+ } else {
+ lasts->ai_next = sentinel;
+ lasts = sentinel;
+ }
+ }
+
+ *((struct addrinfo **)retval) = result;
+ return (NS_SUCCESS);
+}
+#endif /* NS_CACHING */
+
+/*
+ * FQDN hostname, DNS lookup
+ */
+static int
+explore_fqdn(const struct addrinfo *pai, const char *hostname,
+ const char *servname, struct addrinfo **res)
+{
+ struct addrinfo *result;
+ struct addrinfo *cur;
+ int error = 0;
+
+#ifdef NS_CACHING
+ static const nss_cache_info cache_info =
+ NS_COMMON_CACHE_INFO_INITIALIZER(
+ hosts, NULL, addrinfo_id_func, addrinfo_marshal_func,
+ addrinfo_unmarshal_func);
+#endif
+ static const ns_dtab dtab[] = {
+ NS_FILES_CB(_files_getaddrinfo, NULL)
+ { NSSRC_DNS, _dns_getaddrinfo, NULL }, /* force -DHESIOD */
+ NS_NIS_CB(_yp_getaddrinfo, NULL)
+#ifdef NS_CACHING
+ NS_CACHE_CB(&cache_info)
+#endif
+ { 0 }
+ };
+
+ result = NULL;
+
+ /*
+ * if the servname does not match socktype/protocol, ignore it.
+ */
+ if (get_portmatch(pai, servname) != 0)
+ return 0;
+
+ switch (_nsdispatch(&result, dtab, NSDB_HOSTS, "getaddrinfo",
+ default_dns_files, hostname, pai)) {
+ case NS_TRYAGAIN:
+ error = EAI_AGAIN;
+ goto free;
+ case NS_UNAVAIL:
+ error = EAI_FAIL;
+ goto free;
+ case NS_NOTFOUND:
+ error = EAI_NONAME;
+ goto free;
+ case NS_SUCCESS:
+ error = 0;
+ for (cur = result; cur; cur = cur->ai_next) {
+ GET_PORT(cur, servname);
+ /* canonname should be filled already */
+ }
+ break;
+ }
+
+ *res = result;
+
+ return 0;
+
+free:
+ if (result)
+ freeaddrinfo(result);
+ return error;
+}
+
+#ifdef DEBUG
+static const char AskedForGot[] =
+ "gethostby*.getanswer: asked for \"%s\", got \"%s\"";
+#endif
+
+static struct addrinfo *
+getanswer(const querybuf *answer, int anslen, const char *qname, int qtype,
+ const struct addrinfo *pai, res_state res)
+{
+ struct addrinfo sentinel, *cur;
+ struct addrinfo ai;
+ const struct afd *afd;
+ char *canonname;
+ const HEADER *hp;
+ const u_char *cp;
+ int n;
+ const u_char *eom;
+ char *bp, *ep;
+ int type, class, ancount, qdcount;
+ int haveanswer, had_error;
+ char tbuf[MAXDNAME];
+ int (*name_ok)(const char *);
+ char hostbuf[8*1024];
+
+ memset(&sentinel, 0, sizeof(sentinel));
+ cur = &sentinel;
+
+ canonname = NULL;
+ eom = answer->buf + anslen;
+ switch (qtype) {
+ case T_A:
+ case T_AAAA:
+ case T_ANY: /*use T_ANY only for T_A/T_AAAA lookup*/
+ name_ok = res_hnok;
+ break;
+ default:
+ return (NULL); /* XXX should be abort(); */
+ }
+ /*
+ * find first satisfactory answer
+ */
+ hp = &answer->hdr;
+ ancount = ntohs(hp->ancount);
+ qdcount = ntohs(hp->qdcount);
+ bp = hostbuf;
+ ep = hostbuf + sizeof hostbuf;
+ cp = answer->buf + HFIXEDSZ;
+ if (qdcount != 1) {
+ RES_SET_H_ERRNO(res, NO_RECOVERY);
+ return (NULL);
+ }
+ n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
+ if ((n < 0) || !(*name_ok)(bp)) {
+ RES_SET_H_ERRNO(res, NO_RECOVERY);
+ return (NULL);
+ }
+ cp += n + QFIXEDSZ;
+ if (qtype == T_A || qtype == T_AAAA || qtype == T_ANY) {
+ /* res_send() has already verified that the query name is the
+ * same as the one we sent; this just gets the expanded name
+ * (i.e., with the succeeding search-domain tacked on).
+ */
+ n = strlen(bp) + 1; /* for the \0 */
+ if (n >= MAXHOSTNAMELEN) {
+ RES_SET_H_ERRNO(res, NO_RECOVERY);
+ return (NULL);
+ }
+ canonname = bp;
+ bp += n;
+ /* The qname can be abbreviated, but h_name is now absolute. */
+ qname = canonname;
+ }
+ haveanswer = 0;
+ had_error = 0;
+ while (ancount-- > 0 && cp < eom && !had_error) {
+ n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
+ if ((n < 0) || !(*name_ok)(bp)) {
+ had_error++;
+ continue;
+ }
+ cp += n; /* name */
+ type = _getshort(cp);
+ cp += INT16SZ; /* type */
+ class = _getshort(cp);
+ cp += INT16SZ + INT32SZ; /* class, TTL */
+ n = _getshort(cp);
+ cp += INT16SZ; /* len */
+ if (class != C_IN) {
+ /* XXX - debug? syslog? */
+ cp += n;
+ continue; /* XXX - had_error++ ? */
+ }
+ if ((qtype == T_A || qtype == T_AAAA || qtype == T_ANY) &&
+ type == T_CNAME) {
+ n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
+ if ((n < 0) || !(*name_ok)(tbuf)) {
+ had_error++;
+ continue;
+ }
+ cp += n;
+ /* Get canonical name. */
+ n = strlen(tbuf) + 1; /* for the \0 */
+ if (n > ep - bp || n >= MAXHOSTNAMELEN) {
+ had_error++;
+ continue;
+ }
+ strlcpy(bp, tbuf, ep - bp);
+ canonname = bp;
+ bp += n;
+ continue;
+ }
+ if (qtype == T_ANY) {
+ if (!(type == T_A || type == T_AAAA)) {
+ cp += n;
+ continue;
+ }
+ } else if (type != qtype) {
+#ifdef DEBUG
+ if (type != T_KEY && type != T_SIG &&
+ type != ns_t_dname)
+ syslog(LOG_NOTICE|LOG_AUTH,
+ "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
+ qname, p_class(C_IN), p_type(qtype),
+ p_type(type));
+#endif
+ cp += n;
+ continue; /* XXX - had_error++ ? */
+ }
+ switch (type) {
+ case T_A:
+ case T_AAAA:
+ if (strcasecmp(canonname, bp) != 0) {
+#ifdef DEBUG
+ syslog(LOG_NOTICE|LOG_AUTH,
+ AskedForGot, canonname, bp);
+#endif
+ cp += n;
+ continue; /* XXX - had_error++ ? */
+ }
+ if (type == T_A && n != INADDRSZ) {
+ cp += n;
+ continue;
+ }
+ if (type == T_AAAA && n != IN6ADDRSZ) {
+ cp += n;
+ continue;
+ }
+#ifdef FILTER_V4MAPPED
+ if (type == T_AAAA) {
+ struct in6_addr in6;
+ memcpy(&in6, cp, sizeof(in6));
+ if (IN6_IS_ADDR_V4MAPPED(&in6)) {
+ cp += n;
+ continue;
+ }
+ }
+#endif
+ if (!haveanswer) {
+ int nn;
+
+ canonname = bp;
+ nn = strlen(bp) + 1; /* for the \0 */
+ bp += nn;
+ }
+
+ /* don't overwrite pai */
+ ai = *pai;
+ ai.ai_family = (type == T_A) ? AF_INET : AF_INET6;
+ afd = find_afd(ai.ai_family);
+ if (afd == NULL) {
+ cp += n;
+ continue;
+ }
+ cur->ai_next = get_ai(&ai, afd, (const char *)cp);
+ if (cur->ai_next == NULL)
+ had_error++;
+ while (cur && cur->ai_next)
+ cur = cur->ai_next;
+ cp += n;
+ break;
+ default:
+ abort();
+ }
+ if (!had_error)
+ haveanswer++;
+ }
+ if (haveanswer) {
+#if defined(RESOLVSORT)
+ /*
+ * We support only IPv4 address for backward
+ * compatibility against gethostbyname(3).
+ */
+ if (res->nsort && qtype == T_A) {
+ if (addr4sort(&sentinel, res) < 0) {
+ freeaddrinfo(sentinel.ai_next);
+ RES_SET_H_ERRNO(res, NO_RECOVERY);
+ return NULL;
+ }
+ }
+#endif /*RESOLVSORT*/
+ if (!canonname)
+ (void)get_canonname(pai, sentinel.ai_next, qname);
+ else
+ (void)get_canonname(pai, sentinel.ai_next, canonname);
+ RES_SET_H_ERRNO(res, NETDB_SUCCESS);
+ return sentinel.ai_next;
+ }
+
+ /*
+ * We could have walked a CNAME chain, but the ultimate target
+ * may not have what we looked for.
+ */
+ RES_SET_H_ERRNO(res, ntohs(hp->ancount) > 0 ? NO_DATA : NO_RECOVERY);
+ return NULL;
+}
+
+#ifdef RESOLVSORT
+struct addr_ptr {
+ struct addrinfo *ai;
+ int aval;
+};
+
+static int
+addr4sort(struct addrinfo *sentinel, res_state res)
+{
+ struct addrinfo *ai;
+ struct addr_ptr *addrs, addr;
+ struct sockaddr_in *sin;
+ int naddrs, i, j;
+ int needsort = 0;
+
+ if (!sentinel)
+ return -1;
+ naddrs = 0;
+ for (ai = sentinel->ai_next; ai; ai = ai->ai_next)
+ naddrs++;
+ if (naddrs < 2)
+ return 0; /* We don't need sorting. */
+ if ((addrs = malloc(sizeof(struct addr_ptr) * naddrs)) == NULL)
+ return -1;
+ i = 0;
+ for (ai = sentinel->ai_next; ai; ai = ai->ai_next) {
+ sin = (struct sockaddr_in *)ai->ai_addr;
+ for (j = 0; (unsigned)j < res->nsort; j++) {
+ if (res->sort_list[j].addr.s_addr ==
+ (sin->sin_addr.s_addr & res->sort_list[j].mask))
+ break;
+ }
+ addrs[i].ai = ai;
+ addrs[i].aval = j;
+ if (needsort == 0 && i > 0 && j < addrs[i - 1].aval)
+ needsort = i;
+ i++;
+ }
+ if (!needsort) {
+ free(addrs);
+ return 0;
+ }
+
+ while (needsort < naddrs) {
+ for (j = needsort - 1; j >= 0; j--) {
+ if (addrs[j].aval > addrs[j+1].aval) {
+ addr = addrs[j];
+ addrs[j] = addrs[j + 1];
+ addrs[j + 1] = addr;
+ } else
+ break;
+ }
+ needsort++;
+ }
+
+ ai = sentinel;
+ for (i = 0; i < naddrs; ++i) {
+ ai->ai_next = addrs[i].ai;
+ ai = ai->ai_next;
+ }
+ ai->ai_next = NULL;
+ free(addrs);
+ return 0;
+}
+#endif /*RESOLVSORT*/
+
+/*ARGSUSED*/
+static int
+_dns_getaddrinfo(void *rv, void *cb_data, va_list ap)
+{
+ struct addrinfo *ai, ai0;
+ querybuf *buf, *buf2;
+ const char *hostname;
+ const struct addrinfo *pai;
+ struct addrinfo sentinel, *cur;
+ struct res_target q, q2;
+ res_state res;
+
+ ai = NULL;
+
+ hostname = va_arg(ap, char *);
+ pai = va_arg(ap, const struct addrinfo *);
+
+ memset(&q, 0, sizeof(q));
+ memset(&q2, 0, sizeof(q2));
+ memset(&sentinel, 0, sizeof(sentinel));
+ cur = &sentinel;
+
+ res = __res_state();
+
+ buf = malloc(sizeof(*buf));
+ if (!buf) {
+ RES_SET_H_ERRNO(res, NETDB_INTERNAL);
+ return NS_NOTFOUND;
+ }
+ buf2 = malloc(sizeof(*buf2));
+ if (!buf2) {
+ free(buf);
+ RES_SET_H_ERRNO(res, NETDB_INTERNAL);
+ return NS_NOTFOUND;
+ }
+
+ if (pai->ai_family == AF_INET6 &&
+ (pai->ai_flags & AI_V4MAPPED) == AI_V4MAPPED) {
+ ai0 = *pai;
+ ai0.ai_family = AF_UNSPEC;
+ pai = &ai0;
+ }
+
+ switch (pai->ai_family) {
+ case AF_UNSPEC:
+ q.name = hostname;
+ q.qclass = C_IN;
+ q.qtype = T_A;
+ q.answer = buf->buf;
+ q.anslen = sizeof(buf->buf);
+ q.next = &q2;
+ q2.name = hostname;
+ q2.qclass = C_IN;
+ q2.qtype = T_AAAA;
+ q2.answer = buf2->buf;
+ q2.anslen = sizeof(buf2->buf);
+ break;
+ case AF_INET:
+ q.name = hostname;
+ q.qclass = C_IN;
+ q.qtype = T_A;
+ q.answer = buf->buf;
+ q.anslen = sizeof(buf->buf);
+ break;
+ case AF_INET6:
+ q.name = hostname;
+ q.qclass = C_IN;
+ q.qtype = T_AAAA;
+ q.answer = buf->buf;
+ q.anslen = sizeof(buf->buf);
+ break;
+ default:
+ free(buf);
+ free(buf2);
+ return NS_UNAVAIL;
+ }
+
+ if ((res->options & RES_INIT) == 0 && res_ninit(res) == -1) {
+ RES_SET_H_ERRNO(res, NETDB_INTERNAL);
+ free(buf);
+ free(buf2);
+ return NS_NOTFOUND;
+ }
+
+ if (res_searchN(hostname, &q, res) < 0) {
+ free(buf);
+ free(buf2);
+ return NS_NOTFOUND;
+ }
+ /* prefer IPv6 */
+ if (q.next) {
+ ai = getanswer(buf2, q2.n, q2.name, q2.qtype, pai, res);
+ if (ai != NULL) {
+ cur->ai_next = ai;
+ while (cur && cur->ai_next)
+ cur = cur->ai_next;
+ }
+ }
+ if (ai == NULL || pai->ai_family != AF_UNSPEC ||
+ (pai->ai_flags & (AI_ALL | AI_V4MAPPED)) != AI_V4MAPPED) {
+ ai = getanswer(buf, q.n, q.name, q.qtype, pai, res);
+ if (ai != NULL)
+ cur->ai_next = ai;
+ }
+ free(buf);
+ free(buf2);
+ if (sentinel.ai_next == NULL)
+ switch (res->res_h_errno) {
+ case HOST_NOT_FOUND:
+ case NO_DATA:
+ return NS_NOTFOUND;
+ case TRY_AGAIN:
+ return NS_TRYAGAIN;
+ default:
+ return NS_UNAVAIL;
+ }
+ *((struct addrinfo **)rv) = sentinel.ai_next;
+ return NS_SUCCESS;
+}
+
+static void
+_sethtent(FILE **hostf)
+{
+ if (!*hostf)
+ *hostf = fopen(_PATH_HOSTS, "re");
+ else
+ rewind(*hostf);
+}
+
+static void
+_endhtent(FILE **hostf)
+{
+ if (*hostf) {
+ (void) fclose(*hostf);
+ *hostf = NULL;
+ }
+}
+
+static struct addrinfo *
+_gethtent(FILE **hostf, const char *name, const struct addrinfo *pai)
+{
+ char *p;
+ char *cp, *tname, *cname;
+ struct addrinfo hints, *res0, *res;
+ int error;
+ const char *addr;
+ char hostbuf[8*1024];
+
+ if (!*hostf && !(*hostf = fopen(_PATH_HOSTS, "re")))
+ return (NULL);
+again:
+ if (!(p = fgets(hostbuf, sizeof hostbuf, *hostf)))
+ return (NULL);
+ if (*p == '#')
+ goto again;
+ cp = strpbrk(p, "#\n");
+ if (cp != NULL)
+ *cp = '\0';
+ if (!(cp = strpbrk(p, " \t")))
+ goto again;
+ *cp++ = '\0';
+ addr = p;
+ cname = NULL;
+ /* if this is not something we're looking for, skip it. */
+ while (cp && *cp) {
+ if (*cp == ' ' || *cp == '\t') {
+ cp++;
+ continue;
+ }
+ tname = cp;
+ if (cname == NULL)
+ cname = cp;
+ if ((cp = strpbrk(cp, " \t")) != NULL)
+ *cp++ = '\0';
+ if (strcasecmp(name, tname) == 0)
+ goto found;
+ }
+ goto again;
+
+found:
+ /* we should not glob socktype/protocol here */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = pai->ai_family;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_protocol = 0;
+ hints.ai_flags = AI_NUMERICHOST;
+ if (pai->ai_family == AF_INET6 &&
+ (pai->ai_flags & AI_V4MAPPED) == AI_V4MAPPED)
+ hints.ai_flags |= AI_V4MAPPED;
+ error = getaddrinfo(addr, "0", &hints, &res0);
+ if (error)
+ goto again;
+#ifdef FILTER_V4MAPPED
+ /* XXX should check all items in the chain */
+ if (res0->ai_family == AF_INET6 &&
+ IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)res0->ai_addr)->sin6_addr)) {
+ freeaddrinfo(res0);
+ goto again;
+ }
+#endif
+ for (res = res0; res; res = res->ai_next) {
+ /* cover it up */
+ res->ai_flags = pai->ai_flags;
+ res->ai_socktype = pai->ai_socktype;
+ res->ai_protocol = pai->ai_protocol;
+
+ if (pai->ai_flags & AI_CANONNAME) {
+ if (get_canonname(pai, res, cname) != 0) {
+ freeaddrinfo(res0);
+ goto again;
+ }
+ }
+ }
+ return res0;
+}
+
+static struct addrinfo *
+_getht(FILE **hostf, const char *name, const struct addrinfo *pai,
+ struct addrinfo *cur)
+{
+ struct addrinfo *p;
+
+ while ((p = _gethtent(hostf, name, pai)) != NULL) {
+ cur->ai_next = p;
+ while (cur && cur->ai_next)
+ cur = cur->ai_next;
+ }
+ return (cur);
+}
+
+/*ARGSUSED*/
+static int
+_files_getaddrinfo(void *rv, void *cb_data, va_list ap)
+{
+ const char *name;
+ const struct addrinfo *pai;
+ struct addrinfo sentinel, *cur;
+ FILE *hostf = NULL;
+
+ name = va_arg(ap, char *);
+ pai = va_arg(ap, struct addrinfo *);
+
+ memset(&sentinel, 0, sizeof(sentinel));
+ cur = &sentinel;
+
+ _sethtent(&hostf);
+ if (pai->ai_family == AF_INET6 &&
+ (pai->ai_flags & (AI_ALL | AI_V4MAPPED)) == AI_V4MAPPED) {
+ struct addrinfo ai0 = *pai;
+
+ ai0.ai_flags &= ~AI_V4MAPPED;
+ cur = _getht(&hostf, name, &ai0, cur);
+ if (sentinel.ai_next == NULL) {
+ _sethtent(&hostf);
+ ai0.ai_flags |= AI_V4MAPPED;
+ cur = _getht(&hostf, name, &ai0, cur);
+ }
+ } else
+ cur = _getht(&hostf, name, pai, cur);
+ _endhtent(&hostf);
+
+ *((struct addrinfo **)rv) = sentinel.ai_next;
+ if (sentinel.ai_next == NULL)
+ return NS_NOTFOUND;
+ return NS_SUCCESS;
+}
+
+#ifdef YP
+/*ARGSUSED*/
+static struct addrinfo *
+_yphostent(char *line, const struct addrinfo *pai)
+{
+ struct addrinfo sentinel, *cur;
+ struct addrinfo hints, *res, *res0;
+ int error;
+ char *p = line;
+ const char *addr, *canonname;
+ char *nextline;
+ char *cp;
+
+ addr = canonname = NULL;
+
+ memset(&sentinel, 0, sizeof(sentinel));
+ cur = &sentinel;
+
+nextline:
+ /* terminate line */
+ cp = strchr(p, '\n');
+ if (cp) {
+ *cp++ = '\0';
+ nextline = cp;
+ } else
+ nextline = NULL;
+
+ cp = strpbrk(p, " \t");
+ if (cp == NULL) {
+ if (canonname == NULL)
+ return (NULL);
+ else
+ goto done;
+ }
+ *cp++ = '\0';
+
+ addr = p;
+
+ while (cp && *cp) {
+ if (*cp == ' ' || *cp == '\t') {
+ cp++;
+ continue;
+ }
+ if (!canonname)
+ canonname = cp;
+ if ((cp = strpbrk(cp, " \t")) != NULL)
+ *cp++ = '\0';
+ }
+
+ hints = *pai;
+ hints.ai_flags = AI_NUMERICHOST;
+ if (pai->ai_family == AF_INET6 &&
+ (pai->ai_flags & AI_V4MAPPED) == AI_V4MAPPED)
+ hints.ai_flags |= AI_V4MAPPED;
+ error = getaddrinfo(addr, NULL, &hints, &res0);
+ if (error == 0) {
+ for (res = res0; res; res = res->ai_next) {
+ /* cover it up */
+ res->ai_flags = pai->ai_flags;
+
+ if (pai->ai_flags & AI_CANONNAME)
+ (void)get_canonname(pai, res, canonname);
+ }
+ } else
+ res0 = NULL;
+ if (res0) {
+ cur->ai_next = res0;
+ while (cur && cur->ai_next)
+ cur = cur->ai_next;
+ }
+
+ if (nextline) {
+ p = nextline;
+ goto nextline;
+ }
+
+done:
+ return sentinel.ai_next;
+}
+
+/*ARGSUSED*/
+static int
+_yp_getaddrinfo(void *rv, void *cb_data, va_list ap)
+{
+ struct addrinfo sentinel, *cur;
+ struct addrinfo *ai = NULL;
+ char *ypbuf;
+ int ypbuflen, r;
+ const char *name;
+ const struct addrinfo *pai;
+ char *ypdomain;
+
+ if (_yp_check(&ypdomain) == 0)
+ return NS_UNAVAIL;
+
+ name = va_arg(ap, char *);
+ pai = va_arg(ap, const struct addrinfo *);
+
+ memset(&sentinel, 0, sizeof(sentinel));
+ cur = &sentinel;
+
+ /* ipnodes.byname can hold both IPv4/v6 */
+ r = yp_match(ypdomain, "ipnodes.byname", name,
+ (int)strlen(name), &ypbuf, &ypbuflen);
+ if (r == 0) {
+ ai = _yphostent(ypbuf, pai);
+ if (ai) {
+ cur->ai_next = ai;
+ while (cur && cur->ai_next)
+ cur = cur->ai_next;
+ }
+ free(ypbuf);
+ }
+
+ if (ai != NULL) {
+ struct sockaddr_in6 *sin6;
+
+ switch (ai->ai_family) {
+ case AF_INET:
+ goto done;
+ case AF_INET6:
+ sin6 = (struct sockaddr_in6 *)ai->ai_addr;
+ if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
+ goto done;
+ break;
+ }
+ }
+
+ /* hosts.byname is only for IPv4 (Solaris8) */
+ if (pai->ai_family == AF_UNSPEC || pai->ai_family == AF_INET ||
+ ((pai->ai_family == AF_INET6 &&
+ (pai->ai_flags & AI_V4MAPPED) == AI_V4MAPPED) &&
+ (ai == NULL || (pai->ai_flags & AI_ALL) == AI_ALL))) {
+ r = yp_match(ypdomain, "hosts.byname", name,
+ (int)strlen(name), &ypbuf, &ypbuflen);
+ if (r == 0) {
+ struct addrinfo ai4;
+
+ ai4 = *pai;
+ if (pai->ai_family == AF_UNSPEC)
+ ai4.ai_family = AF_INET;
+ ai = _yphostent(ypbuf, &ai4);
+ if (ai) {
+ cur->ai_next = ai;
+ while (cur && cur->ai_next)
+ cur = cur->ai_next;
+ }
+ free(ypbuf);
+ }
+ }
+
+done:
+ if (sentinel.ai_next == NULL) {
+ RES_SET_H_ERRNO(__res_state(), HOST_NOT_FOUND);
+ return NS_NOTFOUND;
+ }
+ *((struct addrinfo **)rv) = sentinel.ai_next;
+ return NS_SUCCESS;
+}
+#endif
+
+/* resolver logic */
+
+/*
+ * Formulate a normal query, send, and await answer.
+ * Returned answer is placed in supplied buffer "answer".
+ * Perform preliminary check of answer, returning success only
+ * if no error is indicated and the answer count is nonzero.
+ * Return the size of the response on success, -1 on error.
+ * Error number is left in h_errno.
+ *
+ * Caller must parse answer and determine whether it answers the question.
+ */
+static int
+res_queryN(const char *name, struct res_target *target, res_state res)
+{
+ u_char *buf;
+ HEADER *hp;
+ int n;
+ u_int oflags;
+ struct res_target *t;
+ int rcode;
+ int ancount;
+
+ rcode = NOERROR;
+ ancount = 0;
+
+ buf = malloc(MAXPACKET);
+ if (!buf) {
+ RES_SET_H_ERRNO(res, NETDB_INTERNAL);
+ return -1;
+ }
+
+ for (t = target; t; t = t->next) {
+ int class, type;
+ u_char *answer;
+ int anslen;
+
+ hp = (HEADER *)(void *)t->answer;
+
+ /* make it easier... */
+ class = t->qclass;
+ type = t->qtype;
+ answer = t->answer;
+ anslen = t->anslen;
+
+ oflags = res->_flags;
+
+again:
+ hp->rcode = NOERROR; /* default */
+
+#ifdef DEBUG
+ if (res->options & RES_DEBUG)
+ printf(";; res_query(%s, %d, %d)\n", name, class, type);
+#endif
+
+ n = res_nmkquery(res, QUERY, name, class, type, NULL, 0, NULL,
+ buf, MAXPACKET);
+ if (n > 0 && (res->_flags & RES_F_EDNS0ERR) == 0 &&
+ (res->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0U)
+ n = res_nopt(res, n, buf, MAXPACKET, anslen);
+ if (n <= 0) {
+#ifdef DEBUG
+ if (res->options & RES_DEBUG)
+ printf(";; res_query: mkquery failed\n");
+#endif
+ free(buf);
+ RES_SET_H_ERRNO(res, NO_RECOVERY);
+ return (n);
+ }
+ n = res_nsend(res, buf, n, answer, anslen);
+ if (n < 0) {
+ /*
+ * if the query choked with EDNS0, retry
+ * without EDNS0
+ */
+ if ((res->options & (RES_USE_EDNS0|RES_USE_DNSSEC))
+ != 0U &&
+ ((oflags ^ res->_flags) & RES_F_EDNS0ERR) != 0) {
+ res->_flags |= RES_F_EDNS0ERR;
+ if (res->options & RES_DEBUG)
+ printf(";; res_nquery: retry without EDNS0\n");
+ goto again;
+ }
+ rcode = hp->rcode; /* record most recent error */
+#ifdef DEBUG
+ if (res->options & RES_DEBUG)
+ printf(";; res_query: send error\n");
+#endif
+ continue;
+ }
+
+ if (n > anslen)
+ hp->rcode = FORMERR; /* XXX not very informative */
+ if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
+ rcode = hp->rcode; /* record most recent error */
+#ifdef DEBUG
+ if (res->options & RES_DEBUG)
+ printf(";; rcode = %u, ancount=%u\n", hp->rcode,
+ ntohs(hp->ancount));
+#endif
+ continue;
+ }
+
+ ancount += ntohs(hp->ancount);
+
+ t->n = n;
+ }
+
+ free(buf);
+
+ if (ancount == 0) {
+ switch (rcode) {
+ case NXDOMAIN:
+ RES_SET_H_ERRNO(res, HOST_NOT_FOUND);
+ break;
+ case SERVFAIL:
+ RES_SET_H_ERRNO(res, TRY_AGAIN);
+ break;
+ case NOERROR:
+ RES_SET_H_ERRNO(res, NO_DATA);
+ break;
+ case FORMERR:
+ case NOTIMP:
+ case REFUSED:
+ default:
+ RES_SET_H_ERRNO(res, NO_RECOVERY);
+ break;
+ }
+ return (-1);
+ }
+ return (ancount);
+}
+
+/*
+ * Formulate a normal query, send, and retrieve answer in supplied buffer.
+ * Return the size of the response on success, -1 on error.
+ * If enabled, implement search rules until answer or unrecoverable failure
+ * is detected. Error code, if any, is left in h_errno.
+ */
+static int
+res_searchN(const char *name, struct res_target *target, res_state res)
+{
+ const char *cp, * const *domain;
+ HEADER *hp = (HEADER *)(void *)target->answer; /*XXX*/
+ u_int dots;
+ int trailing_dot, ret, saved_herrno;
+ int got_nodata = 0, got_servfail = 0, root_on_list = 0;
+ int tried_as_is = 0;
+ int searched = 0;
+ char abuf[MAXDNAME];
+
+ errno = 0;
+ RES_SET_H_ERRNO(res, HOST_NOT_FOUND); /* default, if we never query */
+ dots = 0;
+ for (cp = name; *cp; cp++)
+ dots += (*cp == '.');
+ trailing_dot = 0;
+ if (cp > name && *--cp == '.')
+ trailing_dot++;
+
+ /*
+ * if there aren't any dots, it could be a user-level alias
+ */
+ if (!dots &&
+ (cp = res_hostalias(res, name, abuf, sizeof(abuf))) != NULL)
+ return (res_queryN(cp, target, res));
+
+ /*
+ * If there are enough dots in the name, let's just give it a
+ * try 'as is'. The threshold can be set with the "ndots" option.
+ * Also, query 'as is', if there is a trailing dot in the name.
+ */
+ saved_herrno = -1;
+ if (dots >= res->ndots || trailing_dot) {
+ ret = res_querydomainN(name, NULL, target, res);
+ if (ret > 0 || trailing_dot)
+ return (ret);
+ if (errno == ECONNREFUSED) {
+ RES_SET_H_ERRNO(res, TRY_AGAIN);
+ return (-1);
+ }
+ switch (res->res_h_errno) {
+ case NO_DATA:
+ case HOST_NOT_FOUND:
+ break;
+ case TRY_AGAIN:
+ if (hp->rcode == SERVFAIL)
+ break;
+ /* FALLTHROUGH */
+ default:
+ return (-1);
+ }
+ saved_herrno = res->res_h_errno;
+ tried_as_is++;
+ }
+
+ /*
+ * We do at least one level of search if
+ * - there is no dot and RES_DEFNAME is set, or
+ * - there is at least one dot, there is no trailing dot,
+ * and RES_DNSRCH is set.
+ */
+ if ((!dots && (res->options & RES_DEFNAMES)) ||
+ (dots && !trailing_dot && (res->options & RES_DNSRCH))) {
+ int done = 0;
+
+ for (domain = (const char * const *)res->dnsrch;
+ *domain && !done;
+ domain++) {
+ searched = 1;
+
+ if (domain[0][0] == '\0' ||
+ (domain[0][0] == '.' && domain[0][1] == '\0'))
+ root_on_list++;
+
+ if (root_on_list && tried_as_is)
+ continue;
+
+ ret = res_querydomainN(name, *domain, target, res);
+ if (ret > 0)
+ return (ret);
+
+ /*
+ * If no server present, give up.
+ * If name isn't found in this domain,
+ * keep trying higher domains in the search list
+ * (if that's enabled).
+ * On a NO_DATA error, keep trying, otherwise
+ * a wildcard entry of another type could keep us
+ * from finding this entry higher in the domain.
+ * If we get some other error (negative answer or
+ * server failure), then stop searching up,
+ * but try the input name below in case it's
+ * fully-qualified.
+ */
+ if (errno == ECONNREFUSED) {
+ RES_SET_H_ERRNO(res, TRY_AGAIN);
+ return (-1);
+ }
+
+ switch (res->res_h_errno) {
+ case NO_DATA:
+ got_nodata++;
+ /* FALLTHROUGH */
+ case HOST_NOT_FOUND:
+ /* keep trying */
+ break;
+ case TRY_AGAIN:
+ got_servfail++;
+ if (hp->rcode == SERVFAIL) {
+ /* try next search element, if any */
+ break;
+ }
+ /* FALLTHROUGH */
+ default:
+ /* anything else implies that we're done */
+ done++;
+ }
+ /*
+ * if we got here for some reason other than DNSRCH,
+ * we only wanted one iteration of the loop, so stop.
+ */
+ if (!(res->options & RES_DNSRCH))
+ done++;
+ }
+ }
+
+ switch (res->res_h_errno) {
+ case NO_DATA:
+ case HOST_NOT_FOUND:
+ break;
+ case TRY_AGAIN:
+ if (hp->rcode == SERVFAIL)
+ break;
+ /* FALLTHROUGH */
+ default:
+ goto giveup;
+ }
+
+ /*
+ * If the query has not already been tried as is then try it
+ * unless RES_NOTLDQUERY is set and there were no dots.
+ */
+ if ((dots || !searched || !(res->options & RES_NOTLDQUERY)) &&
+ !(tried_as_is || root_on_list)) {
+ ret = res_querydomainN(name, NULL, target, res);
+ if (ret > 0)
+ return (ret);
+ }
+
+ /*
+ * if we got here, we didn't satisfy the search.
+ * if we did an initial full query, return that query's h_errno
+ * (note that we wouldn't be here if that query had succeeded).
+ * else if we ever got a nodata, send that back as the reason.
+ * else send back meaningless h_errno, that being the one from
+ * the last DNSRCH we did.
+ */
+giveup:
+ if (saved_herrno != -1)
+ RES_SET_H_ERRNO(res, saved_herrno);
+ else if (got_nodata)
+ RES_SET_H_ERRNO(res, NO_DATA);
+ else if (got_servfail)
+ RES_SET_H_ERRNO(res, TRY_AGAIN);
+ return (-1);
+}
+
+/*
+ * Perform a call on res_query on the concatenation of name and domain,
+ * removing a trailing dot from name if domain is NULL.
+ */
+static int
+res_querydomainN(const char *name, const char *domain,
+ struct res_target *target, res_state res)
+{
+ char nbuf[MAXDNAME];
+ const char *longname = nbuf;
+ size_t n, d;
+
+#ifdef DEBUG
+ if (res->options & RES_DEBUG)
+ printf(";; res_querydomain(%s, %s)\n",
+ name, domain?domain:"<Nil>");
+#endif
+ if (domain == NULL) {
+ /*
+ * Check for trailing '.';
+ * copy without '.' if present.
+ */
+ n = strlen(name);
+ if (n >= MAXDNAME) {
+ RES_SET_H_ERRNO(res, NO_RECOVERY);
+ return (-1);
+ }
+ if (n > 0 && name[--n] == '.') {
+ strncpy(nbuf, name, n);
+ nbuf[n] = '\0';
+ } else
+ longname = name;
+ } else {
+ n = strlen(name);
+ d = strlen(domain);
+ if (n + d + 1 >= MAXDNAME) {
+ RES_SET_H_ERRNO(res, NO_RECOVERY);
+ return (-1);
+ }
+ snprintf(nbuf, sizeof(nbuf), "%s.%s", name, domain);
+ }
+ return (res_queryN(longname, target, res));
+}
diff --git a/lib/libc/net/gethostbydns.c b/lib/libc/net/gethostbydns.c
new file mode 100644
index 000000000000..2ee66e3e55fe
--- /dev/null
+++ b/lib/libc/net/gethostbydns.c
@@ -0,0 +1,775 @@
+/*
+ * ++Copyright++ 1985, 1988, 1993
+ * -
+ * Copyright (c) 1985, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * -
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ * -
+ * --Copyright--
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)gethostnamadr.c 8.1 (Berkeley) 6/4/93";
+static char fromrcsid[] = "From: Id: gethnamaddr.c,v 8.23 1998/04/07 04:59:46 vixie Exp $";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <ctype.h>
+#include <errno.h>
+#include <syslog.h>
+#include <stdarg.h>
+#include <nsswitch.h>
+
+#include "netdb_private.h"
+#include "res_config.h"
+
+#define SPRINTF(x) ((size_t)sprintf x)
+
+static const char AskedForGot[] =
+ "gethostby*.gethostanswer: asked for \"%s\", got \"%s\"";
+
+#ifdef RESOLVSORT
+static void addrsort(char **, int, res_state);
+#endif
+
+#ifdef DEBUG
+static void dbg_printf(char *, int, res_state) __printflike(1, 0);
+#endif
+
+#define MAXPACKET (64*1024)
+
+typedef union {
+ HEADER hdr;
+ u_char buf[MAXPACKET];
+} querybuf;
+
+typedef union {
+ int32_t al;
+ char ac;
+} align;
+
+int _dns_ttl_;
+
+#ifdef DEBUG
+static void
+dbg_printf(char *msg, int num, res_state res)
+{
+ if (res->options & RES_DEBUG) {
+ int save = errno;
+
+ printf(msg, num);
+ errno = save;
+ }
+}
+#else
+# define dbg_printf(msg, num, res) /*nada*/
+#endif
+
+#define BOUNDED_INCR(x) \
+ do { \
+ cp += x; \
+ if (cp > eom) { \
+ RES_SET_H_ERRNO(statp, NO_RECOVERY); \
+ return (-1); \
+ } \
+ } while (0)
+
+#define BOUNDS_CHECK(ptr, count) \
+ do { \
+ if ((ptr) + (count) > eom) { \
+ RES_SET_H_ERRNO(statp, NO_RECOVERY); \
+ return (-1); \
+ } \
+ } while (0)
+
+static int
+gethostanswer(const querybuf *answer, int anslen, const char *qname, int qtype,
+ struct hostent *he, struct hostent_data *hed, res_state statp)
+{
+ const HEADER *hp;
+ const u_char *cp;
+ int n;
+ const u_char *eom, *erdata;
+ char *bp, *ep, **ap, **hap;
+ int type, class, ancount, qdcount;
+ int haveanswer, had_error;
+ int toobig = 0;
+ char tbuf[MAXDNAME];
+ const char *tname;
+ int (*name_ok)(const char *);
+
+ tname = qname;
+ he->h_name = NULL;
+ eom = answer->buf + anslen;
+ switch (qtype) {
+ case T_A:
+ case T_AAAA:
+ name_ok = res_hnok;
+ break;
+ case T_PTR:
+ name_ok = res_dnok;
+ break;
+ default:
+ RES_SET_H_ERRNO(statp, NO_RECOVERY);
+ return (-1); /* XXX should be abort(); */
+ }
+ /*
+ * find first satisfactory answer
+ */
+ hp = &answer->hdr;
+ ancount = ntohs(hp->ancount);
+ qdcount = ntohs(hp->qdcount);
+ bp = hed->hostbuf;
+ ep = hed->hostbuf + sizeof hed->hostbuf;
+ cp = answer->buf;
+ BOUNDED_INCR(HFIXEDSZ);
+ if (qdcount != 1) {
+ RES_SET_H_ERRNO(statp, NO_RECOVERY);
+ return (-1);
+ }
+ n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
+ if ((n < 0) || !(*name_ok)(bp)) {
+ RES_SET_H_ERRNO(statp, NO_RECOVERY);
+ return (-1);
+ }
+ BOUNDED_INCR(n + QFIXEDSZ);
+ if (qtype == T_A || qtype == T_AAAA) {
+ /* res_send() has already verified that the query name is the
+ * same as the one we sent; this just gets the expanded name
+ * (i.e., with the succeeding search-domain tacked on).
+ */
+ n = strlen(bp) + 1; /* for the \0 */
+ if (n >= MAXHOSTNAMELEN) {
+ RES_SET_H_ERRNO(statp, NO_RECOVERY);
+ return (-1);
+ }
+ he->h_name = bp;
+ bp += n;
+ /* The qname can be abbreviated, but h_name is now absolute. */
+ qname = he->h_name;
+ }
+ ap = hed->host_aliases;
+ *ap = NULL;
+ he->h_aliases = hed->host_aliases;
+ hap = hed->h_addr_ptrs;
+ *hap = NULL;
+ he->h_addr_list = hed->h_addr_ptrs;
+ haveanswer = 0;
+ had_error = 0;
+ _dns_ttl_ = -1;
+ while (ancount-- > 0 && cp < eom && !had_error) {
+ n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
+ if ((n < 0) || !(*name_ok)(bp)) {
+ had_error++;
+ continue;
+ }
+ cp += n; /* name */
+ BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ);
+ type = _getshort(cp);
+ cp += INT16SZ; /* type */
+ class = _getshort(cp);
+ cp += INT16SZ; /* class */
+ if (qtype == T_A && type == T_A)
+ _dns_ttl_ = _getlong(cp);
+ cp += INT32SZ; /* TTL */
+ n = _getshort(cp);
+ cp += INT16SZ; /* len */
+ BOUNDS_CHECK(cp, n);
+ erdata = cp + n;
+ if (class != C_IN) {
+ /* XXX - debug? syslog? */
+ cp += n;
+ continue; /* XXX - had_error++ ? */
+ }
+ if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) {
+ if (ap >= &hed->host_aliases[_MAXALIASES-1])
+ continue;
+ n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
+ if ((n < 0) || !(*name_ok)(tbuf)) {
+ had_error++;
+ continue;
+ }
+ cp += n;
+ if (cp != erdata) {
+ RES_SET_H_ERRNO(statp, NO_RECOVERY);
+ return (-1);
+ }
+ /* Store alias. */
+ *ap++ = bp;
+ n = strlen(bp) + 1; /* for the \0 */
+ if (n >= MAXHOSTNAMELEN) {
+ had_error++;
+ continue;
+ }
+ bp += n;
+ /* Get canonical name. */
+ n = strlen(tbuf) + 1; /* for the \0 */
+ if (n > ep - bp || n >= MAXHOSTNAMELEN) {
+ had_error++;
+ continue;
+ }
+ strcpy(bp, tbuf);
+ he->h_name = bp;
+ bp += n;
+ continue;
+ }
+ if (qtype == T_PTR && type == T_CNAME) {
+ n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
+ if (n < 0 || !res_dnok(tbuf)) {
+ had_error++;
+ continue;
+ }
+ cp += n;
+ if (cp != erdata) {
+ RES_SET_H_ERRNO(statp, NO_RECOVERY);
+ return (-1);
+ }
+ /* Get canonical name. */
+ n = strlen(tbuf) + 1; /* for the \0 */
+ if (n > ep - bp || n >= MAXHOSTNAMELEN) {
+ had_error++;
+ continue;
+ }
+ strcpy(bp, tbuf);
+ tname = bp;
+ bp += n;
+ continue;
+ }
+ if (type != qtype) {
+ if (type != T_SIG && type != ns_t_dname)
+ syslog(LOG_NOTICE|LOG_AUTH,
+ "gethostby*.gethostanswer: asked for \"%s %s %s\", got type \"%s\"",
+ qname, p_class(C_IN), p_type(qtype),
+ p_type(type));
+ cp += n;
+ continue; /* XXX - had_error++ ? */
+ }
+ switch (type) {
+ case T_PTR:
+ if (strcasecmp(tname, bp) != 0) {
+ syslog(LOG_NOTICE|LOG_AUTH,
+ AskedForGot, qname, bp);
+ cp += n;
+ continue; /* XXX - had_error++ ? */
+ }
+ n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
+ if ((n < 0) || !res_hnok(bp)) {
+ had_error++;
+ break;
+ }
+#if MULTI_PTRS_ARE_ALIASES
+ cp += n;
+ if (cp != erdata) {
+ RES_SET_H_ERRNO(statp, NO_RECOVERY);
+ return (-1);
+ }
+ if (!haveanswer)
+ he->h_name = bp;
+ else if (ap < &hed->host_aliases[_MAXALIASES-1])
+ *ap++ = bp;
+ else
+ n = -1;
+ if (n != -1) {
+ n = strlen(bp) + 1; /* for the \0 */
+ if (n >= MAXHOSTNAMELEN) {
+ had_error++;
+ break;
+ }
+ bp += n;
+ }
+ break;
+#else
+ he->h_name = bp;
+ if (statp->options & RES_USE_INET6) {
+ n = strlen(bp) + 1; /* for the \0 */
+ if (n >= MAXHOSTNAMELEN) {
+ had_error++;
+ break;
+ }
+ bp += n;
+ _map_v4v6_hostent(he, &bp, ep);
+ }
+ RES_SET_H_ERRNO(statp, NETDB_SUCCESS);
+ return (0);
+#endif
+ case T_A:
+ case T_AAAA:
+ if (strcasecmp(he->h_name, bp) != 0) {
+ syslog(LOG_NOTICE|LOG_AUTH,
+ AskedForGot, he->h_name, bp);
+ cp += n;
+ continue; /* XXX - had_error++ ? */
+ }
+ if (n != he->h_length) {
+ cp += n;
+ continue;
+ }
+ if (!haveanswer) {
+ int nn;
+
+ he->h_name = bp;
+ nn = strlen(bp) + 1; /* for the \0 */
+ bp += nn;
+ }
+
+ bp += sizeof(align) - ((u_long)bp % sizeof(align));
+
+ if (bp + n >= ep) {
+ dbg_printf("size (%d) too big\n", n, statp);
+ had_error++;
+ continue;
+ }
+ if (hap >= &hed->h_addr_ptrs[_MAXADDRS-1]) {
+ if (!toobig++)
+ dbg_printf("Too many addresses (%d)\n",
+ _MAXADDRS, statp);
+ cp += n;
+ continue;
+ }
+ memcpy(*hap++ = bp, cp, n);
+ bp += n;
+ cp += n;
+ if (cp != erdata) {
+ RES_SET_H_ERRNO(statp, NO_RECOVERY);
+ return (-1);
+ }
+ break;
+ default:
+ dbg_printf("Impossible condition (type=%d)\n", type,
+ statp);
+ RES_SET_H_ERRNO(statp, NO_RECOVERY);
+ return (-1);
+ /* BIND has abort() here, too risky on bad data */
+ }
+ if (!had_error)
+ haveanswer++;
+ }
+ if (haveanswer) {
+ *ap = NULL;
+ *hap = NULL;
+# if defined(RESOLVSORT)
+ /*
+ * Note: we sort even if host can take only one address
+ * in its return structures - should give it the "best"
+ * address in that case, not some random one
+ */
+ if (statp->nsort && haveanswer > 1 && qtype == T_A)
+ addrsort(hed->h_addr_ptrs, haveanswer, statp);
+# endif /*RESOLVSORT*/
+ if (!he->h_name) {
+ n = strlen(qname) + 1; /* for the \0 */
+ if (n > ep - bp || n >= MAXHOSTNAMELEN)
+ goto no_recovery;
+ strcpy(bp, qname);
+ he->h_name = bp;
+ bp += n;
+ }
+ if (statp->options & RES_USE_INET6)
+ _map_v4v6_hostent(he, &bp, ep);
+ RES_SET_H_ERRNO(statp, NETDB_SUCCESS);
+ return (0);
+ }
+ no_recovery:
+ RES_SET_H_ERRNO(statp, NO_RECOVERY);
+ return (-1);
+}
+
+/* XXX: for async DNS resolver in ypserv */
+struct hostent *
+__dns_getanswer(const char *answer, int anslen, const char *qname, int qtype)
+{
+ struct hostent *he;
+ struct hostent_data *hed;
+ int error;
+ res_state statp;
+
+ statp = __res_state();
+ if ((he = __hostent_init()) == NULL ||
+ (hed = __hostent_data_init()) == NULL) {
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ return (NULL);
+ }
+ switch (qtype) {
+ case T_AAAA:
+ he->h_addrtype = AF_INET6;
+ he->h_length = NS_IN6ADDRSZ;
+ break;
+ case T_A:
+ default:
+ he->h_addrtype = AF_INET;
+ he->h_length = NS_INADDRSZ;
+ break;
+ }
+
+ error = gethostanswer((const querybuf *)answer, anslen, qname, qtype,
+ he, hed, statp);
+ return (error == 0) ? he : NULL;
+}
+
+int
+_dns_gethostbyname(void *rval, void *cb_data, va_list ap)
+{
+ const char *name;
+ int af;
+ char *buffer;
+ size_t buflen;
+ int *errnop, *h_errnop;
+ struct hostent *hptr, he;
+ struct hostent_data *hed;
+ querybuf *buf;
+ int n, type, error;
+ res_state statp;
+
+ name = va_arg(ap, const char *);
+ af = va_arg(ap, int);
+ hptr = va_arg(ap, struct hostent *);
+ buffer = va_arg(ap, char *);
+ buflen = va_arg(ap, size_t);
+ errnop = va_arg(ap, int *);
+ h_errnop = va_arg(ap, int *);
+
+ *((struct hostent **)rval) = NULL;
+
+ statp = __res_state();
+ if ((hed = __hostent_data_init()) == NULL) {
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ *h_errnop = statp->res_h_errno;
+ return (NS_NOTFOUND);
+ }
+
+ he.h_addrtype = af;
+ switch (af) {
+ case AF_INET:
+ he.h_length = NS_INADDRSZ;
+ type = T_A;
+ break;
+ case AF_INET6:
+ he.h_length = NS_IN6ADDRSZ;
+ type = T_AAAA;
+ break;
+ default:
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ *h_errnop = statp->res_h_errno;
+ errno = EAFNOSUPPORT;
+ return (NS_UNAVAIL);
+ }
+
+ if ((buf = malloc(sizeof(*buf))) == NULL) {
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ *h_errnop = statp->res_h_errno;
+ return (NS_NOTFOUND);
+ }
+ n = res_nsearch(statp, name, C_IN, type, buf->buf, sizeof(buf->buf));
+ if (n < 0) {
+ free(buf);
+ dbg_printf("res_nsearch failed (%d)\n", n, statp);
+ *h_errnop = statp->res_h_errno;
+ return (NS_NOTFOUND);
+ } else if (n > sizeof(buf->buf)) {
+ free(buf);
+ dbg_printf("static buffer is too small (%d)\n", n, statp);
+ *h_errnop = statp->res_h_errno;
+ return (NS_UNAVAIL);
+ }
+ error = gethostanswer(buf, n, name, type, &he, hed, statp);
+ free(buf);
+ if (error != 0) {
+ *h_errnop = statp->res_h_errno;
+ switch (statp->res_h_errno) {
+ case HOST_NOT_FOUND:
+ return (NS_NOTFOUND);
+ case TRY_AGAIN:
+ return (NS_TRYAGAIN);
+ default:
+ return (NS_UNAVAIL);
+ }
+ /*NOTREACHED*/
+ }
+ if (__copy_hostent(&he, hptr, buffer, buflen) != 0) {
+ *errnop = errno;
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ *h_errnop = statp->res_h_errno;
+ return (NS_RETURN);
+ }
+ RES_SET_H_ERRNO(statp, NETDB_SUCCESS);
+ *((struct hostent **)rval) = hptr;
+ return (NS_SUCCESS);
+}
+
+int
+_dns_gethostbyaddr(void *rval, void *cb_data, va_list ap)
+{
+ const void *addr;
+ socklen_t len;
+ int af;
+ char *buffer;
+ size_t buflen;
+ int *errnop, *h_errnop;
+ const u_char *uaddr;
+ struct hostent *hptr, he;
+ struct hostent_data *hed;
+ int n;
+ querybuf *buf;
+ char qbuf[MAXDNAME+1], *qp;
+ res_state statp;
+#ifdef SUNSECURITY
+ struct hostdata rhd;
+ struct hostent *rhe;
+ char **haddr;
+ u_long old_options;
+ char hname2[MAXDNAME+1], numaddr[46];
+ int ret_h_error;
+#endif /*SUNSECURITY*/
+
+ addr = va_arg(ap, const void *);
+ len = va_arg(ap, socklen_t);
+ af = va_arg(ap, int);
+ hptr = va_arg(ap, struct hostent *);
+ buffer = va_arg(ap, char *);
+ buflen = va_arg(ap, size_t);
+ errnop = va_arg(ap, int *);
+ h_errnop = va_arg(ap, int *);
+ uaddr = (const u_char *)addr;
+
+ *((struct hostent **)rval) = NULL;
+
+ statp = __res_state();
+ if ((hed = __hostent_data_init()) == NULL) {
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ *h_errnop = statp->res_h_errno;
+ return (NS_NOTFOUND);
+ }
+
+ switch (af) {
+ case AF_INET:
+ (void) sprintf(qbuf, "%u.%u.%u.%u.in-addr.arpa",
+ (uaddr[3] & 0xff),
+ (uaddr[2] & 0xff),
+ (uaddr[1] & 0xff),
+ (uaddr[0] & 0xff));
+ break;
+ case AF_INET6:
+ qp = qbuf;
+ for (n = NS_IN6ADDRSZ - 1; n >= 0; n--) {
+ qp += SPRINTF((qp, "%x.%x.",
+ uaddr[n] & 0xf,
+ (uaddr[n] >> 4) & 0xf));
+ }
+ strlcat(qbuf, "ip6.arpa", sizeof(qbuf));
+ break;
+ default:
+ abort();
+ }
+ if ((buf = malloc(sizeof(*buf))) == NULL) {
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ *h_errnop = statp->res_h_errno;
+ return NS_NOTFOUND;
+ }
+ n = res_nquery(statp, qbuf, C_IN, T_PTR, (u_char *)buf->buf,
+ sizeof buf->buf);
+ if (n < 0) {
+ free(buf);
+ dbg_printf("res_nquery failed (%d)\n", n, statp);
+ *h_errnop = statp->res_h_errno;
+ return (NS_UNAVAIL);
+ }
+ if (n > sizeof buf->buf) {
+ free(buf);
+ dbg_printf("static buffer is too small (%d)\n", n, statp);
+ *h_errnop = statp->res_h_errno;
+ return (NS_UNAVAIL);
+ }
+ if (gethostanswer(buf, n, qbuf, T_PTR, &he, hed, statp) != 0) {
+ free(buf);
+ *h_errnop = statp->res_h_errno;
+ switch (statp->res_h_errno) {
+ case HOST_NOT_FOUND:
+ return (NS_NOTFOUND);
+ case TRY_AGAIN:
+ return (NS_TRYAGAIN);
+ default:
+ return (NS_UNAVAIL);
+ }
+ /*NOTREACHED*/
+ }
+ free(buf);
+#ifdef SUNSECURITY
+ if (af == AF_INET) {
+ /*
+ * turn off search as the name should be absolute,
+ * 'localhost' should be matched by defnames
+ */
+ strncpy(hname2, he.h_name, MAXDNAME);
+ hname2[MAXDNAME] = '\0';
+ old_options = statp->options;
+ statp->options &= ~RES_DNSRCH;
+ statp->options |= RES_DEFNAMES;
+ memset(&rhd, 0, sizeof rhd);
+ rhe = gethostbyname_r(hname2, &rhd.host, &rhd.data,
+ sizeof(rhd.data), &ret_h_error);
+ if (rhe == NULL) {
+ if (inet_ntop(af, addr, numaddr, sizeof(numaddr)) == NULL)
+ strlcpy(numaddr, "UNKNOWN", sizeof(numaddr));
+ syslog(LOG_NOTICE|LOG_AUTH,
+ "gethostbyaddr: No A record for %s (verifying [%s])",
+ hname2, numaddr);
+ statp->options = old_options;
+ RES_SET_H_ERRNO(statp, HOST_NOT_FOUND);
+ *h_errnop = statp->res_h_errno;
+ return (NS_NOTFOUND);
+ }
+ statp->options = old_options;
+ for (haddr = rhe->h_addr_list; *haddr; haddr++)
+ if (!memcmp(*haddr, addr, NS_INADDRSZ))
+ break;
+ if (!*haddr) {
+ if (inet_ntop(af, addr, numaddr, sizeof(numaddr)) == NULL)
+ strlcpy(numaddr, "UNKNOWN", sizeof(numaddr));
+ syslog(LOG_NOTICE|LOG_AUTH,
+ "gethostbyaddr: A record of %s != PTR record [%s]",
+ hname2, numaddr);
+ RES_SET_H_ERRNO(statp, HOST_NOT_FOUND);
+ *h_errnop = statp->res_h_errno;
+ return (NS_NOTFOUND);
+ }
+ }
+#endif /*SUNSECURITY*/
+ he.h_addrtype = af;
+ he.h_length = len;
+ memcpy(hed->host_addr, uaddr, len);
+ hed->h_addr_ptrs[0] = (char *)hed->host_addr;
+ hed->h_addr_ptrs[1] = NULL;
+ if (af == AF_INET && (statp->options & RES_USE_INET6)) {
+ _map_v4v6_address((char*)hed->host_addr, (char*)hed->host_addr);
+ he.h_addrtype = AF_INET6;
+ he.h_length = NS_IN6ADDRSZ;
+ }
+ if (__copy_hostent(&he, hptr, buffer, buflen) != 0) {
+ *errnop = errno;
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ *h_errnop = statp->res_h_errno;
+ return (NS_RETURN);
+ }
+ RES_SET_H_ERRNO(statp, NETDB_SUCCESS);
+ *((struct hostent **)rval) = hptr;
+ return (NS_SUCCESS);
+}
+
+#ifdef RESOLVSORT
+static void
+addrsort(char **ap, int num, res_state res)
+{
+ int i, j;
+ char **p;
+ short aval[_MAXADDRS];
+ int needsort = 0;
+
+ p = ap;
+ for (i = 0; i < num; i++, p++) {
+ for (j = 0 ; (unsigned)j < res->nsort; j++)
+ if (res->sort_list[j].addr.s_addr ==
+ (((struct in_addr *)(*p))->s_addr & res->sort_list[j].mask))
+ break;
+ aval[i] = j;
+ if (needsort == 0 && i > 0 && j < aval[i-1])
+ needsort = i;
+ }
+ if (!needsort)
+ return;
+
+ while (needsort < num) {
+ for (j = needsort - 1; j >= 0; j--) {
+ if (aval[j] > aval[j+1]) {
+ char *hp;
+
+ i = aval[j];
+ aval[j] = aval[j+1];
+ aval[j+1] = i;
+
+ hp = ap[j];
+ ap[j] = ap[j+1];
+ ap[j+1] = hp;
+
+ } else
+ break;
+ }
+ needsort++;
+ }
+}
+#endif
+
+void
+_sethostdnsent(int stayopen)
+{
+ res_state statp;
+
+ statp = __res_state();
+ if ((statp->options & RES_INIT) == 0 && res_ninit(statp) == -1)
+ return;
+ if (stayopen)
+ statp->options |= RES_STAYOPEN | RES_USEVC;
+}
+
+void
+_endhostdnsent(void)
+{
+ res_state statp;
+
+ statp = __res_state();
+ statp->options &= ~(RES_STAYOPEN | RES_USEVC);
+ res_nclose(statp);
+}
diff --git a/lib/libc/net/gethostbyht.c b/lib/libc/net/gethostbyht.c
new file mode 100644
index 000000000000..1468afb6304f
--- /dev/null
+++ b/lib/libc/net/gethostbyht.c
@@ -0,0 +1,339 @@
+/*-
+ * Copyright (c) 1985, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * -
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ * -
+ * --Copyright--
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)gethostnamadr.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <stdarg.h>
+#include <nsswitch.h>
+#include <arpa/nameser.h> /* XXX */
+#include <resolv.h> /* XXX */
+#include "netdb_private.h"
+
+void
+_sethosthtent(int f, struct hostent_data *hed)
+{
+ if (!hed->hostf)
+ hed->hostf = fopen(_PATH_HOSTS, "re");
+ else
+ rewind(hed->hostf);
+ hed->stayopen = f;
+}
+
+void
+_endhosthtent(struct hostent_data *hed)
+{
+ if (hed->hostf && !hed->stayopen) {
+ (void) fclose(hed->hostf);
+ hed->hostf = NULL;
+ }
+}
+
+static int
+gethostent_p(struct hostent *he, struct hostent_data *hed, int mapped,
+ res_state statp)
+{
+ char *p, *bp, *ep;
+ char *cp, **q;
+ int af, len;
+ char hostbuf[BUFSIZ + 1];
+
+ if (!hed->hostf && !(hed->hostf = fopen(_PATH_HOSTS, "re"))) {
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ return (-1);
+ }
+ again:
+ if (!(p = fgets(hostbuf, sizeof hostbuf, hed->hostf))) {
+ RES_SET_H_ERRNO(statp, HOST_NOT_FOUND);
+ return (-1);
+ }
+ if (*p == '#')
+ goto again;
+ cp = strpbrk(p, "#\n");
+ if (cp != NULL)
+ *cp = '\0';
+ if (!(cp = strpbrk(p, " \t")))
+ goto again;
+ *cp++ = '\0';
+ if (inet_pton(AF_INET6, p, hed->host_addr) > 0) {
+ af = AF_INET6;
+ len = IN6ADDRSZ;
+ } else if (inet_pton(AF_INET, p, hed->host_addr) > 0) {
+ if (mapped) {
+ _map_v4v6_address((char *)hed->host_addr,
+ (char *)hed->host_addr);
+ af = AF_INET6;
+ len = IN6ADDRSZ;
+ } else {
+ af = AF_INET;
+ len = INADDRSZ;
+ }
+ } else {
+ goto again;
+ }
+ hed->h_addr_ptrs[0] = (char *)hed->host_addr;
+ hed->h_addr_ptrs[1] = NULL;
+ he->h_addr_list = hed->h_addr_ptrs;
+ he->h_length = len;
+ he->h_addrtype = af;
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ bp = hed->hostbuf;
+ ep = hed->hostbuf + sizeof hed->hostbuf;
+ he->h_name = bp;
+ q = he->h_aliases = hed->host_aliases;
+ if ((p = strpbrk(cp, " \t")) != NULL)
+ *p++ = '\0';
+ len = strlen(cp) + 1;
+ if (ep - bp < len) {
+ RES_SET_H_ERRNO(statp, NO_RECOVERY);
+ return (-1);
+ }
+ strlcpy(bp, cp, ep - bp);
+ bp += len;
+ cp = p;
+ while (cp && *cp) {
+ if (*cp == ' ' || *cp == '\t') {
+ cp++;
+ continue;
+ }
+ if (q >= &hed->host_aliases[_MAXALIASES - 1])
+ break;
+ if ((p = strpbrk(cp, " \t")) != NULL)
+ *p++ = '\0';
+ len = strlen(cp) + 1;
+ if (ep - bp < len)
+ break;
+ strlcpy(bp, cp, ep - bp);
+ *q++ = bp;
+ bp += len;
+ cp = p;
+ }
+ *q = NULL;
+ RES_SET_H_ERRNO(statp, NETDB_SUCCESS);
+ return (0);
+}
+
+int
+gethostent_r(struct hostent *hptr, char *buffer, size_t buflen,
+ struct hostent **result, int *h_errnop)
+{
+ struct hostent_data *hed;
+ struct hostent he;
+ res_state statp;
+
+ statp = __res_state();
+ if ((statp->options & RES_INIT) == 0 && res_ninit(statp) == -1) {
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ *h_errnop = statp->res_h_errno;
+ return (-1);
+ }
+ if ((hed = __hostent_data_init()) == NULL) {
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ *h_errnop = statp->res_h_errno;
+ return (-1);
+ }
+ if (gethostent_p(&he, hed, statp->options & RES_USE_INET6, statp) != 0)
+ return (-1);
+ if (__copy_hostent(&he, hptr, buffer, buflen) != 0) {
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ *h_errnop = statp->res_h_errno;
+ return ((errno != 0) ? errno : -1);
+ }
+ *result = hptr;
+ return (0);
+}
+
+struct hostent *
+gethostent(void)
+{
+ struct hostdata *hd;
+ struct hostent *rval;
+ int ret_h_errno;
+
+ if ((hd = __hostdata_init()) == NULL)
+ return (NULL);
+ if (gethostent_r(&hd->host, hd->data, sizeof(hd->data), &rval,
+ &ret_h_errno) != 0)
+ return (NULL);
+ return (rval);
+}
+
+int
+_ht_gethostbyname(void *rval, void *cb_data, va_list ap)
+{
+ const char *name;
+ int af;
+ char *buffer;
+ size_t buflen;
+ int *errnop, *h_errnop;
+ struct hostent *hptr, he;
+ struct hostent_data *hed;
+ char **cp;
+ res_state statp;
+ int error;
+
+ name = va_arg(ap, const char *);
+ af = va_arg(ap, int);
+ hptr = va_arg(ap, struct hostent *);
+ buffer = va_arg(ap, char *);
+ buflen = va_arg(ap, size_t);
+ errnop = va_arg(ap, int *);
+ h_errnop = va_arg(ap, int *);
+
+ *((struct hostent **)rval) = NULL;
+
+ statp = __res_state();
+ if ((hed = __hostent_data_init()) == NULL) {
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ *h_errnop = statp->res_h_errno;
+ return (NS_NOTFOUND);
+ }
+
+ _sethosthtent(0, hed);
+ while ((error = gethostent_p(&he, hed, 0, statp)) == 0) {
+ if (he.h_addrtype != af)
+ continue;
+ if (he.h_addrtype == AF_INET &&
+ statp->options & RES_USE_INET6) {
+ _map_v4v6_address(he.h_addr, he.h_addr);
+ he.h_length = IN6ADDRSZ;
+ he.h_addrtype = AF_INET6;
+ }
+ if (strcasecmp(he.h_name, name) == 0)
+ break;
+ for (cp = he.h_aliases; *cp != 0; cp++)
+ if (strcasecmp(*cp, name) == 0)
+ goto found;
+ }
+found:
+ _endhosthtent(hed);
+
+ if (error != 0) {
+ *h_errnop = statp->res_h_errno;
+ return (NS_NOTFOUND);
+ }
+ if (__copy_hostent(&he, hptr, buffer, buflen) != 0) {
+ *errnop = errno;
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ *h_errnop = statp->res_h_errno;
+ return (NS_RETURN);
+ }
+ *((struct hostent **)rval) = hptr;
+ return (NS_SUCCESS);
+}
+
+int
+_ht_gethostbyaddr(void *rval, void *cb_data, va_list ap)
+{
+ const void *addr;
+ socklen_t len;
+ int af;
+ char *buffer;
+ size_t buflen;
+ int *errnop, *h_errnop;
+ struct hostent *hptr, he;
+ struct hostent_data *hed;
+ res_state statp;
+ int error;
+
+ addr = va_arg(ap, const void *);
+ len = va_arg(ap, socklen_t);
+ af = va_arg(ap, int);
+ hptr = va_arg(ap, struct hostent *);
+ buffer = va_arg(ap, char *);
+ buflen = va_arg(ap, size_t);
+ errnop = va_arg(ap, int *);
+ h_errnop = va_arg(ap, int *);
+
+ *((struct hostent **)rval) = NULL;
+
+ statp = __res_state();
+ if ((hed = __hostent_data_init()) == NULL) {
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ *h_errnop = statp->res_h_errno;
+ return (NS_NOTFOUND);
+ }
+
+ _sethosthtent(0, hed);
+ while ((error = gethostent_p(&he, hed, 0, statp)) == 0)
+ if (he.h_addrtype == af && !bcmp(he.h_addr, addr, len)) {
+ if (he.h_addrtype == AF_INET &&
+ statp->options & RES_USE_INET6) {
+ _map_v4v6_address(he.h_addr, he.h_addr);
+ he.h_length = IN6ADDRSZ;
+ he.h_addrtype = AF_INET6;
+ }
+ break;
+ }
+ _endhosthtent(hed);
+
+ if (error != 0)
+ return (NS_NOTFOUND);
+ if (__copy_hostent(&he, hptr, buffer, buflen) != 0) {
+ *errnop = errno;
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ *h_errnop = statp->res_h_errno;
+ return (NS_RETURN);
+ }
+ *((struct hostent **)rval) = hptr;
+ return (NS_SUCCESS);
+}
diff --git a/lib/libc/net/gethostbyname.3 b/lib/libc/net/gethostbyname.3
new file mode 100644
index 000000000000..35f031b5727a
--- /dev/null
+++ b/lib/libc/net/gethostbyname.3
@@ -0,0 +1,375 @@
+.\" Copyright (c) 1983, 1987, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" From: @(#)gethostbyname.3 8.4 (Berkeley) 5/25/95
+.\" $FreeBSD$
+.\"
+.Dd May 12, 2006
+.Dt GETHOSTBYNAME 3
+.Os
+.Sh NAME
+.Nm gethostbyname ,
+.Nm gethostbyname2 ,
+.Nm gethostbyaddr ,
+.Nm gethostent ,
+.Nm sethostent ,
+.Nm endhostent ,
+.Nm herror ,
+.Nm hstrerror
+.Nd get network host entry
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In netdb.h
+.Vt int h_errno ;
+.Ft struct hostent *
+.Fn gethostbyname "const char *name"
+.Ft struct hostent *
+.Fn gethostbyname2 "const char *name" "int af"
+.Ft struct hostent *
+.Fn gethostbyaddr "const void *addr" "socklen_t len" "int af"
+.Ft struct hostent *
+.Fn gethostent void
+.Ft void
+.Fn sethostent "int stayopen"
+.Ft void
+.Fn endhostent void
+.Ft void
+.Fn herror "const char *string"
+.Ft const char *
+.Fn hstrerror "int err"
+.Sh DESCRIPTION
+.Bf -symbolic
+The
+.Xr getaddrinfo 3
+and
+.Xr getnameinfo 3
+functions are preferred over the
+.Fn gethostbyname ,
+.Fn gethostbyname2 ,
+and
+.Fn gethostbyaddr
+functions.
+.Ef
+.Pp
+The
+.Fn gethostbyname ,
+.Fn gethostbyname2
+and
+.Fn gethostbyaddr
+functions
+each return a pointer to an object with the
+following structure describing an internet host
+referenced by name or by address, respectively.
+.Pp
+The
+.Fa name
+argument passed to
+.Fn gethostbyname
+or
+.Fn gethostbyname2
+should point to a
+.Dv NUL Ns -terminated
+hostname.
+The
+.Fa addr
+argument passed to
+.Fn gethostbyaddr
+should point to an address which is
+.Fa len
+bytes long,
+in binary form
+(i.e., not an IP address in human readable
+.Tn ASCII
+form).
+The
+.Fa af
+argument specifies the address family
+(e.g.\&
+.Dv AF_INET , AF_INET6 ,
+etc.) of this address.
+.Pp
+The structure returned contains either the information obtained from the name
+server,
+.Xr named 8 ,
+broken-out fields from a line in
+.Pa /etc/hosts ,
+or database entries supplied by the
+.Xr yp 8
+system.
+The order of the lookups is controlled by the
+.Sq hosts
+entry in
+.Xr nsswitch.conf 5 .
+.Bd -literal
+struct hostent {
+ char *h_name; /* official name of host */
+ char **h_aliases; /* alias list */
+ int h_addrtype; /* host address type */
+ int h_length; /* length of address */
+ char **h_addr_list; /* list of addresses from name server */
+};
+#define h_addr h_addr_list[0] /* address, for backward compatibility */
+.Ed
+.Pp
+The members of this structure are:
+.Bl -tag -width h_addr_list
+.It Va h_name
+Official name of the host.
+.It Va h_aliases
+A
+.Dv NULL Ns -terminated
+array of alternate names for the host.
+.It Va h_addrtype
+The type of address being returned; usually
+.Dv AF_INET .
+.It Va h_length
+The length, in bytes, of the address.
+.It Va h_addr_list
+A
+.Dv NULL Ns -terminated
+array of network addresses for the host.
+Host addresses are returned in network byte order.
+.It Va h_addr
+The first address in
+.Va h_addr_list ;
+this is for backward compatibility.
+.El
+.Pp
+When using the nameserver,
+.Fn gethostbyname
+and
+.Fn gethostbyname2
+will search for the named host in the current domain and its parents
+unless the name ends in a dot.
+If the name contains no dot, and if the environment variable
+.Dq Ev HOSTALIASES
+contains the name of an alias file, the alias file will first be searched
+for an alias matching the input name.
+See
+.Xr hostname 7
+for the domain search procedure and the alias file format.
+.Pp
+The
+.Fn gethostbyname2
+function is an evolution of
+.Fn gethostbyname
+which is intended to allow lookups in address families other than
+.Dv AF_INET ,
+for example
+.Dv AF_INET6 .
+.Pp
+The
+.Fn sethostent
+function
+may be used to request the use of a connected
+.Tn TCP
+socket for queries.
+If the
+.Fa stayopen
+flag is non-zero,
+this sets the option to send all queries to the name server using
+.Tn TCP
+and to retain the connection after each call to
+.Fn gethostbyname ,
+.Fn gethostbyname2
+or
+.Fn gethostbyaddr .
+Otherwise, queries are performed using
+.Tn UDP
+datagrams.
+.Pp
+The
+.Fn endhostent
+function
+closes the
+.Tn TCP
+connection.
+.Pp
+The
+.Fn herror
+function writes a message to the diagnostic output consisting of the
+string argument
+.Fa string ,
+the constant string
+.Qq Li ":\ " ,
+and a message corresponding to the value of
+.Va h_errno .
+.Pp
+The
+.Fn hstrerror
+function returns a string which is the message text corresponding to the
+value of the
+.Fa err
+argument.
+.Sh FILES
+.Bl -tag -width /etc/nsswitch.conf -compact
+.It Pa /etc/hosts
+.It Pa /etc/nsswitch.conf
+.It Pa /etc/resolv.conf
+.El
+.Sh EXAMPLES
+Print out the hostname associated with a specific IP address:
+.Bd -literal -offset indent
+const char *ipstr = "127.0.0.1";
+struct in_addr ip;
+struct hostent *hp;
+
+if (!inet_aton(ipstr, &ip))
+ errx(1, "can't parse IP address %s", ipstr);
+
+if ((hp = gethostbyaddr((const void *)&ip,
+ sizeof ip, AF_INET)) == NULL)
+ errx(1, "no name associated with %s", ipstr);
+
+printf("name associated with %s is %s\en", ipstr, hp->h_name);
+.Ed
+.Sh DIAGNOSTICS
+Error return status from
+.Fn gethostbyname ,
+.Fn gethostbyname2
+and
+.Fn gethostbyaddr
+is indicated by return of a
+.Dv NULL
+pointer.
+The integer
+.Va h_errno
+may then be checked to see whether this is a temporary failure
+or an invalid or unknown host.
+The routine
+.Fn herror
+can be used to print an error message describing the failure.
+If its argument
+.Fa string
+is
+.Pf non- Dv NULL ,
+it is printed, followed by a colon and a space.
+The error message is printed with a trailing newline.
+.Pp
+The variable
+.Va h_errno
+can have the following values:
+.Bl -tag -width HOST_NOT_FOUND
+.It Dv HOST_NOT_FOUND
+No such host is known.
+.It Dv TRY_AGAIN
+This is usually a temporary error
+and means that the local server did not receive
+a response from an authoritative server.
+A retry at some later time may succeed.
+.It Dv NO_RECOVERY
+Some unexpected server failure was encountered.
+This is a non-recoverable error.
+.It Dv NO_DATA
+The requested name is valid but does not have an IP address;
+this is not a temporary error.
+This means that the name is known to the name server but there is no address
+associated with this name.
+Another type of request to the name server using this domain name
+will result in an answer;
+for example, a mail-forwarder may be registered for this domain.
+.El
+.Sh SEE ALSO
+.Xr getaddrinfo 3 ,
+.Xr getnameinfo 3 ,
+.Xr inet_aton 3 ,
+.Xr resolver 3 ,
+.Xr hosts 5 ,
+.Xr hostname 7 ,
+.Xr named 8
+.Sh CAVEAT
+The
+.Fn gethostent
+function
+is defined, and
+.Fn sethostent
+and
+.Fn endhostent
+are redefined,
+when
+.Lb libc
+is built to use only the routines to lookup in
+.Pa /etc/hosts
+and not the name server.
+.Pp
+The
+.Fn gethostent
+function
+reads the next line of
+.Pa /etc/hosts ,
+opening the file if necessary.
+.Pp
+The
+.Fn sethostent
+function
+opens and/or rewinds the file
+.Pa /etc/hosts .
+If the
+.Fa stayopen
+argument is non-zero,
+the file will not be closed after each call to
+.Fn gethostbyname ,
+.Fn gethostbyname2
+or
+.Fn gethostbyaddr .
+.Pp
+The
+.Fn endhostent
+function
+closes the file.
+.Sh HISTORY
+The
+.Fn herror
+function appeared in
+.Bx 4.3 .
+The
+.Fn endhostent ,
+.Fn gethostbyaddr ,
+.Fn gethostbyname ,
+.Fn gethostent ,
+and
+.Fn sethostent
+functions appeared in
+.Bx 4.2 .
+The
+.Fn gethostbyname2
+function first appeared in
+.Tn BIND
+version 4.9.4.
+.Sh BUGS
+These functions use a thread-specific data storage;
+if the data is needed for future use, it should be
+copied before any subsequent calls overwrite it.
+.Pp
+Though these functions are thread-safe,
+still it is recommended to use the
+.Xr getaddrinfo 3
+family of functions, instead.
+.Pp
+Only the Internet
+address format is currently understood.
diff --git a/lib/libc/net/gethostbynis.c b/lib/libc/net/gethostbynis.c
new file mode 100644
index 000000000000..6bafdb116fd1
--- /dev/null
+++ b/lib/libc/net/gethostbynis.c
@@ -0,0 +1,297 @@
+/*-
+ * Copyright (c) 1994, Garrett Wollman
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <stdarg.h>
+#include <nsswitch.h>
+#include <resolv.h> /* XXX */
+#ifdef YP
+#include <rpc/rpc.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+#endif
+#include "netdb_private.h"
+
+#ifdef YP
+static int
+_gethostbynis(const char *name, char *map, int af, struct hostent *he,
+ struct hostent_data *hed)
+{
+ char *p, *bp, *ep;
+ char *cp, **q;
+ char *result;
+ int resultlen, size, addrok = 0;
+ char ypbuf[YPMAXRECORD + 2];
+ res_state statp;
+
+ statp = __res_state();
+ switch(af) {
+ case AF_INET:
+ size = NS_INADDRSZ;
+ break;
+ case AF_INET6:
+ size = NS_IN6ADDRSZ;
+ break;
+ default:
+ errno = EAFNOSUPPORT;
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ return (-1);
+ }
+
+ if (hed->yp_domain == (char *)NULL)
+ if (yp_get_default_domain (&hed->yp_domain)) {
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ return (-1);
+ }
+
+ if (yp_match(hed->yp_domain, map, name, strlen(name), &result,
+ &resultlen)) {
+ RES_SET_H_ERRNO(statp, HOST_NOT_FOUND);
+ return (-1);
+ }
+
+ /* avoid potential memory leak */
+ bcopy((char *)result, (char *)&ypbuf, resultlen);
+ ypbuf[resultlen] = '\0';
+ free(result);
+ result = (char *)&ypbuf;
+
+ if ((cp = strchr(result, '\n')))
+ *cp = '\0';
+
+ cp = strpbrk(result, " \t");
+ *cp++ = '\0';
+ he->h_addr_list = hed->h_addr_ptrs;
+ he->h_addr = (char *)hed->host_addr;
+ switch (af) {
+ case AF_INET:
+ addrok = inet_aton(result, (struct in_addr *)hed->host_addr);
+ if (addrok != 1)
+ break;
+ if (statp->options & RES_USE_INET6) {
+ _map_v4v6_address((char *)hed->host_addr,
+ (char *)hed->host_addr);
+ af = AF_INET6;
+ size = NS_IN6ADDRSZ;
+ }
+ break;
+ case AF_INET6:
+ addrok = inet_pton(af, result, hed->host_addr);
+ break;
+ }
+ if (addrok != 1) {
+ RES_SET_H_ERRNO(statp, HOST_NOT_FOUND);
+ return (-1);
+ }
+ he->h_addr_list[1] = NULL;
+ he->h_length = size;
+ he->h_addrtype = af;
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ bp = hed->hostbuf;
+ ep = hed->hostbuf + sizeof hed->hostbuf;
+ he->h_name = bp;
+ q = he->h_aliases = hed->host_aliases;
+ p = strpbrk(cp, " \t");
+ if (p != NULL)
+ *p++ = '\0';
+ size = strlen(cp) + 1;
+ if (ep - bp < size) {
+ RES_SET_H_ERRNO(statp, NO_RECOVERY);
+ return (-1);
+ }
+ strlcpy(bp, cp, ep - bp);
+ bp += size;
+ cp = p;
+ while (cp && *cp) {
+ if (*cp == ' ' || *cp == '\t') {
+ cp++;
+ continue;
+ }
+ if (q >= &hed->host_aliases[_MAXALIASES - 1])
+ break;
+ p = strpbrk(cp, " \t");
+ if (p != NULL)
+ *p++ = '\0';
+ size = strlen(cp) + 1;
+ if (ep - bp < size)
+ break;
+ strlcpy(bp, cp, ep - bp);
+ *q++ = bp;
+ bp += size;
+ cp = p;
+ }
+ *q = NULL;
+ return (0);
+}
+
+static int
+_gethostbynisname_r(const char *name, int af, struct hostent *he,
+ struct hostent_data *hed)
+{
+ char *map;
+
+ switch (af) {
+ case AF_INET:
+ map = "hosts.byname";
+ break;
+ default:
+ map = "ipnodes.byname";
+ break;
+ }
+ return (_gethostbynis(name, map, af, he, hed));
+}
+
+static int
+_gethostbynisaddr_r(const void *addr, socklen_t len, int af,
+ struct hostent *he, struct hostent_data *hed)
+{
+ char *map;
+ char numaddr[46];
+
+ switch (af) {
+ case AF_INET:
+ map = "hosts.byaddr";
+ break;
+ default:
+ map = "ipnodes.byaddr";
+ break;
+ }
+ if (inet_ntop(af, addr, numaddr, sizeof(numaddr)) == NULL)
+ return (-1);
+ return (_gethostbynis(numaddr, map, af, he, hed));
+}
+#endif /* YP */
+
+int
+_nis_gethostbyname(void *rval, void *cb_data, va_list ap)
+{
+#ifdef YP
+ const char *name;
+ int af;
+ char *buffer;
+ size_t buflen;
+ int *errnop, *h_errnop;
+ struct hostent *hptr, he;
+ struct hostent_data *hed;
+ res_state statp;
+
+ name = va_arg(ap, const char *);
+ af = va_arg(ap, int);
+ hptr = va_arg(ap, struct hostent *);
+ buffer = va_arg(ap, char *);
+ buflen = va_arg(ap, size_t);
+ errnop = va_arg(ap, int *);
+ h_errnop = va_arg(ap, int *);
+
+ *((struct hostent **)rval) = NULL;
+
+ statp = __res_state();
+ if ((hed = __hostent_data_init()) == NULL) {
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ *h_errnop = statp->res_h_errno;
+ return (NS_NOTFOUND);
+ }
+
+ if (_gethostbynisname_r(name, af, &he, hed) != 0) {
+ *h_errnop = statp->res_h_errno;
+ return (NS_NOTFOUND);
+ }
+ if (__copy_hostent(&he, hptr, buffer, buflen) != 0) {
+ *errnop = errno;
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ *h_errnop = statp->res_h_errno;
+ return (NS_RETURN);
+ }
+ *((struct hostent **)rval) = hptr;
+ return (NS_SUCCESS);
+#else
+ *((struct hostent **)rval) = NULL;
+ return (NS_UNAVAIL);
+#endif
+}
+
+int
+_nis_gethostbyaddr(void *rval, void *cb_data, va_list ap)
+{
+#ifdef YP
+ const void *addr;
+ socklen_t len;
+ int af;
+ char *buffer;
+ size_t buflen;
+ int *errnop, *h_errnop;
+ struct hostent *hptr, he;
+ struct hostent_data *hed;
+ res_state statp;
+
+ addr = va_arg(ap, const void *);
+ len = va_arg(ap, socklen_t);
+ af = va_arg(ap, int);
+ hptr = va_arg(ap, struct hostent *);
+ buffer = va_arg(ap, char *);
+ buflen = va_arg(ap, size_t);
+ errnop = va_arg(ap, int *);
+ h_errnop = va_arg(ap, int *);
+
+ *((struct hostent **)rval) = NULL;
+
+ statp = __res_state();
+ if ((hed = __hostent_data_init()) == NULL) {
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ *h_errnop = statp->res_h_errno;
+ return (NS_NOTFOUND);
+ }
+
+ if (_gethostbynisaddr_r(addr, len, af, &he, hed) != 0) {
+ *h_errnop = statp->res_h_errno;
+ return (NS_NOTFOUND);
+ }
+ if (__copy_hostent(&he, hptr, buffer, buflen) != 0) {
+ *errnop = errno;
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ *h_errnop = statp->res_h_errno;
+ return (NS_RETURN);
+ }
+ *((struct hostent **)rval) = hptr;
+ return (NS_SUCCESS);
+#else
+ *((struct hostent **)rval) = NULL;
+ return (NS_UNAVAIL);
+#endif
+}
diff --git a/lib/libc/net/gethostnamadr.c b/lib/libc/net/gethostnamadr.c
new file mode 100644
index 000000000000..9286e397527a
--- /dev/null
+++ b/lib/libc/net/gethostnamadr.c
@@ -0,0 +1,727 @@
+/*-
+ * Copyright (c) 1994, Garrett Wollman
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include "reentrant.h"
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <nsswitch.h>
+#include <arpa/nameser.h> /* XXX hack for _res */
+#include <resolv.h> /* XXX hack for _res */
+#include "un-namespace.h"
+#include "netdb_private.h"
+#ifdef NS_CACHING
+#include "nscache.h"
+#endif
+
+static int gethostbyname_internal(const char *, int, struct hostent *, char *,
+ size_t, struct hostent **, int *, res_state);
+
+/* Host lookup order if nsswitch.conf is broken or nonexistent */
+static const ns_src default_src[] = {
+ { NSSRC_FILES, NS_SUCCESS },
+ { NSSRC_DNS, NS_SUCCESS },
+ { 0 }
+};
+#ifdef NS_CACHING
+static int host_id_func(char *, size_t *, va_list, void *);
+static int host_marshal_func(char *, size_t *, void *, va_list, void *);
+static int host_unmarshal_func(char *, size_t, void *, va_list, void *);
+#endif
+
+NETDB_THREAD_ALLOC(hostent)
+NETDB_THREAD_ALLOC(hostent_data)
+NETDB_THREAD_ALLOC(hostdata)
+
+static void
+hostent_free(void *ptr)
+{
+ free(ptr);
+}
+
+static void
+hostent_data_free(void *ptr)
+{
+ struct hostent_data *hed = ptr;
+
+ if (hed == NULL)
+ return;
+ hed->stayopen = 0;
+ _endhosthtent(hed);
+ free(hed);
+}
+
+static void
+hostdata_free(void *ptr)
+{
+ free(ptr);
+}
+
+int
+__copy_hostent(struct hostent *he, struct hostent *hptr, char *buf,
+ size_t buflen)
+{
+ char *cp;
+ char **ptr;
+ int i, n;
+ int nptr, len;
+
+ /* Find out the amount of space required to store the answer. */
+ nptr = 2; /* NULL ptrs */
+ len = (char *)ALIGN(buf) - buf;
+ for (i = 0; he->h_addr_list[i]; i++, nptr++) {
+ len += he->h_length;
+ }
+ for (i = 0; he->h_aliases[i]; i++, nptr++) {
+ len += strlen(he->h_aliases[i]) + 1;
+ }
+ len += strlen(he->h_name) + 1;
+ len += nptr * sizeof(char*);
+
+ if (len > buflen) {
+ errno = ERANGE;
+ return (-1);
+ }
+
+ /* copy address size and type */
+ hptr->h_addrtype = he->h_addrtype;
+ n = hptr->h_length = he->h_length;
+
+ ptr = (char **)ALIGN(buf);
+ cp = (char *)ALIGN(buf) + nptr * sizeof(char *);
+
+ /* copy address list */
+ hptr->h_addr_list = ptr;
+ for (i = 0; he->h_addr_list[i]; i++ , ptr++) {
+ memcpy(cp, he->h_addr_list[i], n);
+ hptr->h_addr_list[i] = cp;
+ cp += n;
+ }
+ hptr->h_addr_list[i] = NULL;
+ ptr++;
+
+ /* copy official name */
+ n = strlen(he->h_name) + 1;
+ strcpy(cp, he->h_name);
+ hptr->h_name = cp;
+ cp += n;
+
+ /* copy aliases */
+ hptr->h_aliases = ptr;
+ for (i = 0 ; he->h_aliases[i]; i++) {
+ n = strlen(he->h_aliases[i]) + 1;
+ strcpy(cp, he->h_aliases[i]);
+ hptr->h_aliases[i] = cp;
+ cp += n;
+ }
+ hptr->h_aliases[i] = NULL;
+
+ return (0);
+}
+
+#ifdef NS_CACHING
+static int
+host_id_func(char *buffer, size_t *buffer_size, va_list ap, void *cache_mdata)
+{
+ res_state statp;
+ u_long res_options;
+
+ const int op_id = 1;
+ char *str;
+ void *addr;
+ socklen_t len;
+ int type;
+
+ size_t desired_size, size;
+ enum nss_lookup_type lookup_type;
+ char *p;
+ int res = NS_UNAVAIL;
+
+ statp = __res_state();
+ res_options = statp->options & (RES_RECURSE | RES_DEFNAMES |
+ RES_DNSRCH | RES_NOALIASES | RES_USE_INET6);
+
+ lookup_type = (enum nss_lookup_type)cache_mdata;
+ switch (lookup_type) {
+ case nss_lt_name:
+ str = va_arg(ap, char *);
+ type = va_arg(ap, int);
+
+ size = strlen(str);
+ desired_size = sizeof(res_options) + sizeof(int) +
+ sizeof(enum nss_lookup_type) + sizeof(int) + size + 1;
+
+ if (desired_size > *buffer_size) {
+ res = NS_RETURN;
+ goto fin;
+ }
+
+ p = buffer;
+
+ memcpy(p, &res_options, sizeof(res_options));
+ p += sizeof(res_options);
+
+ memcpy(p, &op_id, sizeof(int));
+ p += sizeof(int);
+
+ memcpy(p, &lookup_type, sizeof(enum nss_lookup_type));
+ p += sizeof(int);
+
+ memcpy(p, &type, sizeof(int));
+ p += sizeof(int);
+
+ memcpy(p, str, size + 1);
+
+ res = NS_SUCCESS;
+ break;
+ case nss_lt_id:
+ addr = va_arg(ap, void *);
+ len = va_arg(ap, socklen_t);
+ type = va_arg(ap, int);
+
+ desired_size = sizeof(res_options) + sizeof(int) +
+ sizeof(enum nss_lookup_type) + sizeof(int) +
+ sizeof(socklen_t) + len;
+
+ if (desired_size > *buffer_size) {
+ res = NS_RETURN;
+ goto fin;
+ }
+
+ p = buffer;
+ memcpy(p, &res_options, sizeof(res_options));
+ p += sizeof(res_options);
+
+ memcpy(p, &op_id, sizeof(int));
+ p += sizeof(int);
+
+ memcpy(p, &lookup_type, sizeof(enum nss_lookup_type));
+ p += sizeof(int);
+
+ memcpy(p, &type, sizeof(int));
+ p += sizeof(int);
+
+ memcpy(p, &len, sizeof(socklen_t));
+ p += sizeof(socklen_t);
+
+ memcpy(p, addr, len);
+
+ res = NS_SUCCESS;
+ break;
+ default:
+ /* should be unreachable */
+ return (NS_UNAVAIL);
+ }
+
+fin:
+ *buffer_size = desired_size;
+ return (res);
+}
+
+static int
+host_marshal_func(char *buffer, size_t *buffer_size, void *retval, va_list ap,
+ void *cache_mdata)
+{
+ char *str;
+ void *addr;
+ socklen_t len;
+ int type;
+ struct hostent *ht;
+
+ struct hostent new_ht;
+ size_t desired_size, aliases_size, addr_size, size;
+ char *p, **iter;
+
+ switch ((enum nss_lookup_type)cache_mdata) {
+ case nss_lt_name:
+ str = va_arg(ap, char *);
+ type = va_arg(ap, int);
+ break;
+ case nss_lt_id:
+ addr = va_arg(ap, void *);
+ len = va_arg(ap, socklen_t);
+ type = va_arg(ap, int);
+ break;
+ default:
+ /* should be unreachable */
+ return (NS_UNAVAIL);
+ }
+ ht = va_arg(ap, struct hostent *);
+
+ desired_size = _ALIGNBYTES + sizeof(struct hostent) + sizeof(char *);
+ if (ht->h_name != NULL)
+ desired_size += strlen(ht->h_name) + 1;
+
+ if (ht->h_aliases != NULL) {
+ aliases_size = 0;
+ for (iter = ht->h_aliases; *iter; ++iter) {
+ desired_size += strlen(*iter) + 1;
+ ++aliases_size;
+ }
+
+ desired_size += _ALIGNBYTES +
+ (aliases_size + 1) * sizeof(char *);
+ }
+
+ if (ht->h_addr_list != NULL) {
+ addr_size = 0;
+ for (iter = ht->h_addr_list; *iter; ++iter)
+ ++addr_size;
+
+ desired_size += addr_size * _ALIGN(ht->h_length);
+ desired_size += _ALIGNBYTES + (addr_size + 1) * sizeof(char *);
+ }
+
+ if (desired_size > *buffer_size) {
+ /* this assignment is here for future use */
+ *buffer_size = desired_size;
+ return (NS_RETURN);
+ }
+
+ memcpy(&new_ht, ht, sizeof(struct hostent));
+ memset(buffer, 0, desired_size);
+
+ *buffer_size = desired_size;
+ p = buffer + sizeof(struct hostent) + sizeof(char *);
+ memcpy(buffer + sizeof(struct hostent), &p, sizeof(char *));
+ p = (char *)_ALIGN(p);
+
+ if (new_ht.h_name != NULL) {
+ size = strlen(new_ht.h_name);
+ memcpy(p, new_ht.h_name, size);
+ new_ht.h_name = p;
+ p += size + 1;
+ }
+
+ if (new_ht.h_aliases != NULL) {
+ p = (char *)_ALIGN(p);
+ memcpy(p, new_ht.h_aliases, sizeof(char *) * aliases_size);
+ new_ht.h_aliases = (char **)p;
+ p += sizeof(char *) * (aliases_size + 1);
+
+ for (iter = new_ht.h_aliases; *iter; ++iter) {
+ size = strlen(*iter);
+ memcpy(p, *iter, size);
+ *iter = p;
+ p += size + 1;
+ }
+ }
+
+ if (new_ht.h_addr_list != NULL) {
+ p = (char *)_ALIGN(p);
+ memcpy(p, new_ht.h_addr_list, sizeof(char *) * addr_size);
+ new_ht.h_addr_list = (char **)p;
+ p += sizeof(char *) * (addr_size + 1);
+
+ size = _ALIGN(new_ht.h_length);
+ for (iter = new_ht.h_addr_list; *iter; ++iter) {
+ memcpy(p, *iter, size);
+ *iter = p;
+ p += size + 1;
+ }
+ }
+ memcpy(buffer, &new_ht, sizeof(struct hostent));
+ return (NS_SUCCESS);
+}
+
+static int
+host_unmarshal_func(char *buffer, size_t buffer_size, void *retval, va_list ap,
+ void *cache_mdata)
+{
+ char *str;
+ void *addr;
+ socklen_t len;
+ int type;
+ struct hostent *ht;
+
+ char *p;
+ char **iter;
+ char *orig_buf;
+ size_t orig_buf_size;
+
+ switch ((enum nss_lookup_type)cache_mdata) {
+ case nss_lt_name:
+ str = va_arg(ap, char *);
+ type = va_arg(ap, int);
+ break;
+ case nss_lt_id:
+ addr = va_arg(ap, void *);
+ len = va_arg(ap, socklen_t);
+ type = va_arg(ap, int);
+ break;
+ default:
+ /* should be unreachable */
+ return (NS_UNAVAIL);
+ }
+
+ ht = va_arg(ap, struct hostent *);
+ orig_buf = va_arg(ap, char *);
+ orig_buf_size = va_arg(ap, size_t);
+
+ if (orig_buf_size <
+ buffer_size - sizeof(struct hostent) - sizeof(char *)) {
+ errno = ERANGE;
+ return (NS_RETURN);
+ }
+
+ memcpy(ht, buffer, sizeof(struct hostent));
+ memcpy(&p, buffer + sizeof(struct hostent), sizeof(char *));
+
+ orig_buf = (char *)_ALIGN(orig_buf);
+ memcpy(orig_buf, buffer + sizeof(struct hostent) + sizeof(char *) +
+ _ALIGN(p) - (size_t)p,
+ buffer_size - sizeof(struct hostent) - sizeof(char *) -
+ _ALIGN(p) + (size_t)p);
+ p = (char *)_ALIGN(p);
+
+ NS_APPLY_OFFSET(ht->h_name, orig_buf, p, char *);
+ if (ht->h_aliases != NULL) {
+ NS_APPLY_OFFSET(ht->h_aliases, orig_buf, p, char **);
+
+ for (iter = ht->h_aliases; *iter; ++iter)
+ NS_APPLY_OFFSET(*iter, orig_buf, p, char *);
+ }
+
+ if (ht->h_addr_list != NULL) {
+ NS_APPLY_OFFSET(ht->h_addr_list, orig_buf, p, char **);
+
+ for (iter = ht->h_addr_list; *iter; ++iter)
+ NS_APPLY_OFFSET(*iter, orig_buf, p, char *);
+ }
+
+ *((struct hostent **)retval) = ht;
+ return (NS_SUCCESS);
+}
+#endif /* NS_CACHING */
+
+static int
+fakeaddr(const char *name, int af, struct hostent *hp, char *buf,
+ size_t buflen, res_state statp)
+{
+ struct hostent_data *hed;
+ struct hostent he;
+
+ if ((hed = __hostent_data_init()) == NULL) {
+ errno = ENOMEM;
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ return (-1);
+ }
+
+ if ((af != AF_INET ||
+ inet_aton(name, (struct in_addr *)hed->host_addr) != 1) &&
+ inet_pton(af, name, hed->host_addr) != 1) {
+ RES_SET_H_ERRNO(statp, HOST_NOT_FOUND);
+ return (-1);
+ }
+ strncpy(hed->hostbuf, name, MAXDNAME);
+ hed->hostbuf[MAXDNAME] = '\0';
+ if (af == AF_INET && (statp->options & RES_USE_INET6) != 0U) {
+ _map_v4v6_address((char *)hed->host_addr,
+ (char *)hed->host_addr);
+ af = AF_INET6;
+ }
+ he.h_addrtype = af;
+ switch(af) {
+ case AF_INET:
+ he.h_length = NS_INADDRSZ;
+ break;
+ case AF_INET6:
+ he.h_length = NS_IN6ADDRSZ;
+ break;
+ default:
+ errno = EAFNOSUPPORT;
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ return (-1);
+ }
+ he.h_name = hed->hostbuf;
+ he.h_aliases = hed->host_aliases;
+ hed->host_aliases[0] = NULL;
+ hed->h_addr_ptrs[0] = (char *)hed->host_addr;
+ hed->h_addr_ptrs[1] = NULL;
+ he.h_addr_list = hed->h_addr_ptrs;
+ if (__copy_hostent(&he, hp, buf, buflen) != 0) {
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ return (-1);
+ }
+ RES_SET_H_ERRNO(statp, NETDB_SUCCESS);
+ return (0);
+}
+
+int
+gethostbyname_r(const char *name, struct hostent *he, char *buffer,
+ size_t buflen, struct hostent **result, int *h_errnop)
+{
+ res_state statp;
+
+ statp = __res_state();
+ if ((statp->options & RES_INIT) == 0 && res_ninit(statp) == -1) {
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ return (-1);
+ }
+ if (statp->options & RES_USE_INET6) {
+ if (fakeaddr(name, AF_INET, he, buffer, buflen, statp) == 0) {
+ *result = he;
+ return (0);
+ }
+ if (gethostbyname_internal(name, AF_INET6, he, buffer, buflen,
+ result, h_errnop, statp) == 0)
+ return (0);
+ }
+ return (gethostbyname_internal(name, AF_INET, he, buffer, buflen,
+ result, h_errnop, statp));
+}
+
+int
+gethostbyname2_r(const char *name, int af, struct hostent *he, char *buffer,
+ size_t buflen, struct hostent **result, int *h_errnop)
+{
+ res_state statp;
+
+ statp = __res_state();
+ if ((statp->options & RES_INIT) == 0 && res_ninit(statp) == -1) {
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ return (-1);
+ }
+ return (gethostbyname_internal(name, af, he, buffer, buflen, result,
+ h_errnop, statp));
+}
+
+int
+gethostbyname_internal(const char *name, int af, struct hostent *hp, char *buf,
+ size_t buflen, struct hostent **result, int *h_errnop, res_state statp)
+{
+ const char *cp;
+ int rval, ret_errno = 0;
+ char abuf[MAXDNAME];
+
+#ifdef NS_CACHING
+ static const nss_cache_info cache_info =
+ NS_COMMON_CACHE_INFO_INITIALIZER(
+ hosts, (void *)nss_lt_name,
+ host_id_func, host_marshal_func, host_unmarshal_func);
+#endif
+ static const ns_dtab dtab[] = {
+ NS_FILES_CB(_ht_gethostbyname, NULL)
+ { NSSRC_DNS, _dns_gethostbyname, NULL },
+ NS_NIS_CB(_nis_gethostbyname, NULL) /* force -DHESIOD */
+#ifdef NS_CACHING
+ NS_CACHE_CB(&cache_info)
+#endif
+ { 0 }
+ };
+
+ switch (af) {
+ case AF_INET:
+ case AF_INET6:
+ break;
+ default:
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ *h_errnop = statp->res_h_errno;
+ errno = EAFNOSUPPORT;
+ return (-1);
+ }
+
+ /*
+ * if there aren't any dots, it could be a user-level alias.
+ * this is also done in res_query() since we are not the only
+ * function that looks up host names.
+ */
+ if (!strchr(name, '.') &&
+ (cp = res_hostalias(statp, name, abuf, sizeof abuf)))
+ name = cp;
+
+ if (fakeaddr(name, af, hp, buf, buflen, statp) == 0) {
+ *result = hp;
+ return (0);
+ }
+
+ rval = _nsdispatch((void *)result, dtab, NSDB_HOSTS,
+ "gethostbyname2_r", default_src, name, af, hp, buf, buflen,
+ &ret_errno, h_errnop);
+
+ if (rval != NS_SUCCESS) {
+ errno = ret_errno;
+ return ((ret_errno != 0) ? ret_errno : -1);
+ }
+ return (0);
+}
+
+int
+gethostbyaddr_r(const void *addr, socklen_t len, int af, struct hostent *hp,
+ char *buf, size_t buflen, struct hostent **result, int *h_errnop)
+{
+ const u_char *uaddr = (const u_char *)addr;
+ const struct in6_addr *addr6;
+ socklen_t size;
+ int rval, ret_errno = 0;
+ res_state statp;
+
+#ifdef NS_CACHING
+ static const nss_cache_info cache_info =
+ NS_COMMON_CACHE_INFO_INITIALIZER(
+ hosts, (void *)nss_lt_id,
+ host_id_func, host_marshal_func, host_unmarshal_func);
+#endif
+ static const ns_dtab dtab[] = {
+ NS_FILES_CB(_ht_gethostbyaddr, NULL)
+ { NSSRC_DNS, _dns_gethostbyaddr, NULL },
+ NS_NIS_CB(_nis_gethostbyaddr, NULL) /* force -DHESIOD */
+#ifdef NS_CACHING
+ NS_CACHE_CB(&cache_info)
+#endif
+ { 0 }
+ };
+
+ statp = __res_state();
+ if ((statp->options & RES_INIT) == 0 && res_ninit(statp) == -1) {
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ *h_errnop = statp->res_h_errno;
+ return (-1);
+ }
+
+ if (af == AF_INET6 && len == NS_IN6ADDRSZ) {
+ addr6 = (const struct in6_addr *)addr;
+ if (IN6_IS_ADDR_LINKLOCAL(addr6)) {
+ RES_SET_H_ERRNO(statp, HOST_NOT_FOUND);
+ *h_errnop = statp->res_h_errno;
+ return (-1);
+ }
+ if (IN6_IS_ADDR_V4MAPPED(addr6) ||
+ IN6_IS_ADDR_V4COMPAT(addr6)) {
+ /* Unmap. */
+ uaddr += NS_IN6ADDRSZ - NS_INADDRSZ;
+ af = AF_INET;
+ len = NS_INADDRSZ;
+ }
+ }
+ switch (af) {
+ case AF_INET:
+ size = NS_INADDRSZ;
+ break;
+ case AF_INET6:
+ size = NS_IN6ADDRSZ;
+ break;
+ default:
+ errno = EAFNOSUPPORT;
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ *h_errnop = statp->res_h_errno;
+ return (-1);
+ }
+ if (size != len) {
+ errno = EINVAL;
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ *h_errnop = statp->res_h_errno;
+ return (-1);
+ }
+
+ rval = _nsdispatch((void *)result, dtab, NSDB_HOSTS,
+ "gethostbyaddr_r", default_src, uaddr, len, af, hp, buf, buflen,
+ &ret_errno, h_errnop);
+
+ if (rval != NS_SUCCESS) {
+ errno = ret_errno;
+ return ((ret_errno != 0) ? ret_errno : -1);
+ }
+ return (0);
+}
+
+struct hostent *
+gethostbyname(const char *name)
+{
+ struct hostdata *hd;
+ struct hostent *rval;
+ int ret_h_errno;
+
+ if ((hd = __hostdata_init()) == NULL)
+ return (NULL);
+ if (gethostbyname_r(name, &hd->host, hd->data, sizeof(hd->data), &rval,
+ &ret_h_errno) != 0)
+ return (NULL);
+ return (rval);
+}
+
+struct hostent *
+gethostbyname2(const char *name, int af)
+{
+ struct hostdata *hd;
+ struct hostent *rval;
+ int ret_h_errno;
+
+ if ((hd = __hostdata_init()) == NULL)
+ return (NULL);
+ if (gethostbyname2_r(name, af, &hd->host, hd->data, sizeof(hd->data),
+ &rval, &ret_h_errno) != 0)
+ return (NULL);
+ return (rval);
+}
+
+struct hostent *
+gethostbyaddr(const void *addr, socklen_t len, int af)
+{
+ struct hostdata *hd;
+ struct hostent *rval;
+ int ret_h_errno;
+
+ if ((hd = __hostdata_init()) == NULL)
+ return (NULL);
+ if (gethostbyaddr_r(addr, len, af, &hd->host, hd->data,
+ sizeof(hd->data), &rval, &ret_h_errno) != 0)
+ return (NULL);
+ return (rval);
+}
+
+void
+sethostent(int stayopen)
+{
+ struct hostent_data *hed;
+
+ if ((hed = __hostent_data_init()) == NULL)
+ return;
+ _sethosthtent(stayopen, hed);
+ _sethostdnsent(stayopen);
+}
+
+void
+endhostent(void)
+{
+ struct hostent_data *hed;
+
+ if ((hed = __hostent_data_init()) == NULL)
+ return;
+ _endhosthtent(hed);
+ _endhostdnsent();
+}
diff --git a/lib/libc/net/getifaddrs.3 b/lib/libc/net/getifaddrs.3
new file mode 100644
index 000000000000..b0b17bb388da
--- /dev/null
+++ b/lib/libc/net/getifaddrs.3
@@ -0,0 +1,163 @@
+.\" $KAME: getifaddrs.3,v 1.4 2000/05/17 14:13:14 itojun Exp $
+.\" BSDI getifaddrs.3,v 2.5 2000/02/23 14:51:59 dab Exp
+.\"
+.\" Copyright (c) 1995, 1999
+.\" Berkeley Software Design, Inc. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd November 25, 2014
+.Dt GETIFADDRS 3
+.Os
+.Sh NAME
+.Nm getifaddrs
+.Nd get interface addresses
+.Sh SYNOPSIS
+.In ifaddrs.h
+.Ft int
+.Fn getifaddrs "struct ifaddrs **ifap"
+.Ft void
+.Fn freeifaddrs "struct ifaddrs *ifp"
+.Sh DESCRIPTION
+The
+.Fn getifaddrs
+function stores a reference to a linked list of the network interfaces
+on the local machine in the memory referenced by
+.Fa ifap .
+The list consists of
+.Nm ifaddrs
+structures, as defined in the include file
+.In ifaddrs.h .
+The
+.Nm ifaddrs
+structure contains at least the following entries:
+.Bd -literal
+ struct ifaddrs *ifa_next; /* Pointer to next struct */
+ char *ifa_name; /* Interface name */
+ u_int ifa_flags; /* Interface flags */
+ struct sockaddr *ifa_addr; /* Interface address */
+ struct sockaddr *ifa_netmask; /* Interface netmask */
+ struct sockaddr *ifa_broadaddr; /* Interface broadcast address */
+ struct sockaddr *ifa_dstaddr; /* P2P interface destination */
+ void *ifa_data; /* Address specific data */
+.Ed
+.Pp
+The
+.Li ifa_next
+field contains a pointer to the next structure on the list.
+This field is
+.Dv NULL
+in last structure on the list.
+.Pp
+The
+.Li ifa_name
+field contains the interface name.
+.Pp
+The
+.Li ifa_flags
+field contains the interface flags, as set by
+.Xr ifconfig 8
+utility.
+.Pp
+The
+.Li ifa_addr
+field references either the address of the interface or the link level
+address of the interface, if one exists, otherwise it is NULL.
+(The
+.Li sa_family
+field of the
+.Li ifa_addr
+field should be consulted to determine the format of the
+.Li ifa_addr
+address.)
+.Pp
+The
+.Li ifa_netmask
+field references the netmask associated with
+.Li ifa_addr ,
+if one is set, otherwise it is NULL.
+.Pp
+The
+.Li ifa_broadaddr
+field,
+which should only be referenced for non-P2P interfaces,
+references the broadcast address associated with
+.Li ifa_addr ,
+if one exists, otherwise it is NULL.
+.Pp
+The
+.Li ifa_dstaddr
+field references the destination address on a P2P interface,
+if one exists, otherwise it is NULL.
+.Pp
+The
+.Li ifa_data
+field references address family specific data
+in a pointer to the
+.Fa struct if_data
+(as defined in include file
+.In net/if.h ) .
+For
+.Dv AF_LINK
+addresses,
+it contains various interface attributes and statistics.
+For all other address families,
+it contains per-address interface statistics.
+.Pp
+The data returned by
+.Fn getifaddrs
+is dynamically allocated and should be freed using
+.Fn freeifaddrs
+when no longer needed.
+.Sh RETURN VALUES
+.Rv -std getifaddrs
+.Sh ERRORS
+The
+.Fn getifaddrs
+may fail and set
+.Va errno
+for any of the errors specified for the library routines
+.Xr ioctl 2 ,
+.Xr socket 2 ,
+.Xr malloc 3
+or
+.Xr sysctl 3 .
+.Sh SEE ALSO
+.Xr ioctl 2 ,
+.Xr socket 2 ,
+.Xr sysctl 3 ,
+.Xr networking 4 ,
+.Xr ifconfig 8
+.Sh HISTORY
+The
+.Nm
+implementation first appeared in BSDi
+.Bsx .
+.Sh BUGS
+If both
+.In net/if.h
+and
+.In ifaddrs.h
+are being included,
+.In net/if.h
+.Em must
+be included before
+.In ifaddrs.h .
diff --git a/lib/libc/net/getifaddrs.c b/lib/libc/net/getifaddrs.c
new file mode 100644
index 000000000000..4c04e9ef0591
--- /dev/null
+++ b/lib/libc/net/getifaddrs.c
@@ -0,0 +1,344 @@
+/* $KAME: getifaddrs.c,v 1.9 2001/08/20 02:31:20 itojun Exp $ */
+
+/*
+ * Copyright (c) 1995, 1999
+ * Berkeley Software Design, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BSDI getifaddrs.c,v 2.12 2000/02/23 14:51:59 dab Exp
+ */
+/*
+ * NOTE: SIOCGIFCONF case is not LP64 friendly. it also does not perform
+ * try-and-error for region size.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#ifdef NET_RT_IFLIST
+#include <sys/param.h>
+#include <net/route.h>
+#include <sys/sysctl.h>
+#include <net/if_dl.h>
+#endif
+
+#include <errno.h>
+#include <ifaddrs.h>
+#include <stdlib.h>
+#include <string.h>
+#include "un-namespace.h"
+
+#if !defined(AF_LINK)
+#define SA_LEN(sa) sizeof(struct sockaddr)
+#endif
+
+#if !defined(SA_LEN)
+#define SA_LEN(sa) (sa)->sa_len
+#endif
+
+#define SALIGN (sizeof(long) - 1)
+#define SA_RLEN(sa) ((sa)->sa_len ? (((sa)->sa_len + SALIGN) & ~SALIGN) : (SALIGN + 1))
+
+#ifndef ALIGNBYTES
+/*
+ * On systems with a routing socket, ALIGNBYTES should match the value
+ * that the kernel uses when building the messages.
+ */
+#define ALIGNBYTES XXX
+#endif
+#ifndef ALIGN
+#define ALIGN(p) (((u_long)(p) + ALIGNBYTES) &~ ALIGNBYTES)
+#endif
+
+#define MAX_SYSCTL_TRY 5
+
+int
+getifaddrs(struct ifaddrs **pif)
+{
+ int icnt = 1;
+ int dcnt = 0;
+ int ncnt = 0;
+ int ntry = 0;
+ int mib[6];
+ size_t needed;
+ char *buf;
+ char *next;
+ struct ifaddrs *cif;
+ char *p, *p0;
+ struct rt_msghdr *rtm;
+ struct if_msghdrl *ifm;
+ struct ifa_msghdrl *ifam;
+ struct sockaddr_dl *dl;
+ struct sockaddr *sa;
+ struct ifaddrs *ifa, *ift;
+ struct if_data *if_data;
+ u_short idx = 0;
+ int i;
+ size_t len, alen;
+ char *data;
+ char *names;
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_ROUTE;
+ mib[2] = 0; /* protocol */
+ mib[3] = 0; /* wildcard address family */
+ mib[4] = NET_RT_IFLISTL;/* extra fields for extensible msghdr structs */
+ mib[5] = 0; /* no flags */
+ do {
+ /*
+ * We'll try to get addresses several times in case that
+ * the number of addresses is unexpectedly increased during
+ * the two sysctl calls. This should rarely happen, but we'll
+ * try to do our best for applications that assume success of
+ * this library (which should usually be the case).
+ * Portability note: since FreeBSD does not add margin of
+ * memory at the first sysctl, the possibility of failure on
+ * the second sysctl call is a bit higher.
+ */
+
+ if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
+ return (-1);
+ if ((buf = malloc(needed)) == NULL)
+ return (-1);
+ if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
+ if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) {
+ free(buf);
+ return (-1);
+ }
+ free(buf);
+ buf = NULL;
+ }
+ } while (buf == NULL);
+
+ for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
+ rtm = (struct rt_msghdr *)(void *)next;
+ if (rtm->rtm_version != RTM_VERSION)
+ continue;
+ switch (rtm->rtm_type) {
+ case RTM_IFINFO:
+ ifm = (struct if_msghdrl *)(void *)rtm;
+ if (ifm->ifm_addrs & RTA_IFP) {
+ idx = ifm->ifm_index;
+ ++icnt;
+ if_data = IF_MSGHDRL_IFM_DATA(ifm);
+ dcnt += if_data->ifi_datalen;
+ dl = (struct sockaddr_dl *)IF_MSGHDRL_RTA(ifm);
+ dcnt += SA_RLEN((struct sockaddr *)(void*)dl) +
+ ALIGNBYTES;
+ ncnt += dl->sdl_nlen + 1;
+ } else
+ idx = 0;
+ break;
+
+ case RTM_NEWADDR:
+ ifam = (struct ifa_msghdrl *)(void *)rtm;
+ if (idx && ifam->ifam_index != idx)
+ abort(); /* this cannot happen */
+
+#define RTA_MASKS (RTA_NETMASK | RTA_IFA | RTA_BRD)
+ if (idx == 0 || (ifam->ifam_addrs & RTA_MASKS) == 0)
+ break;
+ p = (char *)IFA_MSGHDRL_RTA(ifam);
+ ++icnt;
+ if_data = IFA_MSGHDRL_IFAM_DATA(ifam);
+ dcnt += if_data->ifi_datalen + ALIGNBYTES;
+
+ /* Scan to look for length of address */
+ alen = 0;
+ for (p0 = p, i = 0; i < RTAX_MAX; i++) {
+ if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
+ == 0)
+ continue;
+ sa = (struct sockaddr *)(void *)p;
+ len = SA_RLEN(sa);
+ if (i == RTAX_IFA) {
+ alen = len;
+ break;
+ }
+ p += len;
+ }
+ for (p = p0, i = 0; i < RTAX_MAX; i++) {
+ if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
+ == 0)
+ continue;
+ sa = (struct sockaddr *)(void *)p;
+ len = SA_RLEN(sa);
+ if (i == RTAX_NETMASK && SA_LEN(sa) == 0)
+ dcnt += alen;
+ else
+ dcnt += len;
+ p += len;
+ }
+ break;
+ }
+ }
+
+ if (icnt + dcnt + ncnt == 1) {
+ *pif = NULL;
+ free(buf);
+ return (0);
+ }
+ data = malloc(sizeof(struct ifaddrs) * icnt + dcnt + ncnt);
+ if (data == NULL) {
+ free(buf);
+ return(-1);
+ }
+
+ ifa = (struct ifaddrs *)(void *)data;
+ data += sizeof(struct ifaddrs) * icnt;
+ names = data + dcnt;
+
+ memset(ifa, 0, sizeof(struct ifaddrs) * icnt);
+ ift = ifa;
+
+ idx = 0;
+ cif = NULL;
+ for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
+ rtm = (struct rt_msghdr *)(void *)next;
+ if (rtm->rtm_version != RTM_VERSION)
+ continue;
+ switch (rtm->rtm_type) {
+ case RTM_IFINFO:
+ ifm = (struct if_msghdrl *)(void *)rtm;
+ if ((ifm->ifm_addrs & RTA_IFP) == 0) {
+ idx = 0;
+ break;
+ }
+
+ idx = ifm->ifm_index;
+ dl = (struct sockaddr_dl *)IF_MSGHDRL_RTA(ifm);
+
+ cif = ift;
+ ift->ifa_name = names;
+ ift->ifa_flags = (int)ifm->ifm_flags;
+ memcpy(names, dl->sdl_data, (size_t)dl->sdl_nlen);
+ names[dl->sdl_nlen] = 0;
+ names += dl->sdl_nlen + 1;
+
+ ift->ifa_addr = (struct sockaddr *)(void *)data;
+ memcpy(data, dl, (size_t)SA_LEN((struct sockaddr *)
+ (void *)dl));
+ data += SA_RLEN((struct sockaddr *)(void *)dl);
+
+ if_data = IF_MSGHDRL_IFM_DATA(ifm);
+ /* ifm_data needs to be aligned */
+ ift->ifa_data = data = (void *)ALIGN(data);
+ memcpy(data, if_data, if_data->ifi_datalen);
+ data += if_data->ifi_datalen;
+
+ ift = (ift->ifa_next = ift + 1);
+ break;
+
+ case RTM_NEWADDR:
+ ifam = (struct ifa_msghdrl *)(void *)rtm;
+ if (idx && ifam->ifam_index != idx)
+ abort(); /* this cannot happen */
+
+ if (idx == 0 || (ifam->ifam_addrs & RTA_MASKS) == 0)
+ break;
+ ift->ifa_name = cif->ifa_name;
+ ift->ifa_flags = cif->ifa_flags;
+ ift->ifa_data = NULL;
+
+ p = (char *)IFA_MSGHDRL_RTA(ifam);
+ /* Scan to look for length of address */
+ alen = 0;
+ for (p0 = p, i = 0; i < RTAX_MAX; i++) {
+ if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
+ == 0)
+ continue;
+ sa = (struct sockaddr *)(void *)p;
+ len = SA_RLEN(sa);
+ if (i == RTAX_IFA) {
+ alen = len;
+ break;
+ }
+ p += len;
+ }
+ for (p = p0, i = 0; i < RTAX_MAX; i++) {
+ if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
+ == 0)
+ continue;
+ sa = (struct sockaddr *)(void *)p;
+ len = SA_RLEN(sa);
+ switch (i) {
+ case RTAX_IFA:
+ ift->ifa_addr =
+ (struct sockaddr *)(void *)data;
+ memcpy(data, p, len);
+ data += len;
+ break;
+
+ case RTAX_NETMASK:
+ ift->ifa_netmask =
+ (struct sockaddr *)(void *)data;
+ if (SA_LEN(sa) == 0) {
+ memset(data, 0, alen);
+ data += alen;
+ break;
+ }
+ memcpy(data, p, len);
+ data += len;
+ break;
+
+ case RTAX_BRD:
+ ift->ifa_broadaddr =
+ (struct sockaddr *)(void *)data;
+ memcpy(data, p, len);
+ data += len;
+ break;
+ }
+ p += len;
+ }
+
+ if_data = IFA_MSGHDRL_IFAM_DATA(ifam);
+ /* ifam_data needs to be aligned */
+ ift->ifa_data = data = (void *)ALIGN(data);
+ memcpy(data, if_data, if_data->ifi_datalen);
+ data += if_data->ifi_datalen;
+
+ ift = (ift->ifa_next = ift + 1);
+ break;
+ }
+ }
+
+ free(buf);
+
+ if (--ift >= ifa) {
+ ift->ifa_next = NULL;
+ *pif = ifa;
+ } else {
+ *pif = NULL;
+ free(ifa);
+ }
+ return (0);
+}
+
+void
+freeifaddrs(struct ifaddrs *ifp)
+{
+
+ free(ifp);
+}
diff --git a/lib/libc/net/getifmaddrs.3 b/lib/libc/net/getifmaddrs.3
new file mode 100644
index 000000000000..14c40875439c
--- /dev/null
+++ b/lib/libc/net/getifmaddrs.3
@@ -0,0 +1,114 @@
+.\" Copyright (c) 2003 Bruce M. Simpson. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY Bruce M. Simpson ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL Bruce M. Simpson BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 May 21, 2013
+.Dt GETIFMADDRS 3
+.Os
+.Sh NAME
+.Nm getifmaddrs
+.Nd get multicast group memberships
+.Sh SYNOPSIS
+.In ifaddrs.h
+.Ft int
+.Fn getifmaddrs "struct ifmaddrs **ifmap"
+.Ft void
+.Fn freeifmaddrs "struct ifmaddrs *ifmp"
+.Sh DESCRIPTION
+The
+.Fn getifmaddrs
+function stores a reference to a linked list of the multicast memberships
+on the local machine in the memory referenced by
+.Fa ifmap .
+The list consists of
+.Vt ifmaddrs
+structures, as defined in the include file
+.In ifaddrs.h .
+The
+.Vt ifmaddrs
+structure contains at least the following entries:
+.Bd -literal
+ struct ifmaddrs *ifma_next; /* Pointer to next struct */
+ struct sockaddr *ifma_name; /* Interface name (AF_LINK) */
+ struct sockaddr *ifma_addr; /* Multicast address */
+ struct sockaddr *ifma_lladdr; /* Link-layer translation, if any */
+.Ed
+.Pp
+The
+.Va ifma_next
+field contains a pointer to the next structure on the list.
+This field is
+.Dv NULL
+in last structure on the list.
+.Pp
+The
+.Va ifma_name
+field references an
+.Dv AF_LINK
+address structure, containing the name of the
+interface where the membership exists.
+.Pp
+The
+.Va ifma_addr
+references the address that this membership is for.
+.Pp
+The
+.Va ifma_lladdr
+field references a link-layer translation for the protocol-level address in
+.Va ifma_addr ,
+if one is set, otherwise it is
+.Dv NULL .
+.Pp
+The data returned by
+.Fn getifmaddrs
+is dynamically allocated and should be freed using
+.Fn freeifmaddrs
+when no longer needed.
+.Sh RETURN VALUES
+.Rv -std getifmaddrs
+.Sh ERRORS
+The
+.Fn getifmaddrs
+may fail and set
+.Va errno
+for any of the errors specified for the library routines
+.Xr malloc 3
+or
+.Xr sysctl 3 .
+.Sh SEE ALSO
+.Xr sysctl 3 ,
+.Xr networking 4 ,
+.Xr ifconfig 8
+.Sh HISTORY
+The
+.Fn getifmaddrs
+function first appeared in
+.Fx 5.2 .
+.Sh BUGS
+If both
+.In net/if.h
+and
+.In ifaddrs.h
+are being included,
+.In net/if.h
+.Em must
+be included before
+.In ifaddrs.h .
diff --git a/lib/libc/net/getifmaddrs.c b/lib/libc/net/getifmaddrs.c
new file mode 100644
index 000000000000..c05d6de57b25
--- /dev/null
+++ b/lib/libc/net/getifmaddrs.c
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2003 Bruce M. Simpson.
+ * All rights reserved
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+
+#include <errno.h>
+#include <ifaddrs.h>
+#include <stdlib.h>
+#include <string.h>
+#include "un-namespace.h"
+
+#define SALIGN (sizeof(long) - 1)
+#define SA_RLEN(sa) ((sa)->sa_len ? (((sa)->sa_len + SALIGN) & ~SALIGN) : \
+ (SALIGN + 1))
+#define MAX_SYSCTL_TRY 5
+#define RTA_MASKS (RTA_GATEWAY | RTA_IFP | RTA_IFA)
+
+int
+getifmaddrs(struct ifmaddrs **pif)
+{
+ int icnt = 1;
+ int dcnt = 0;
+ int ntry = 0;
+ size_t len;
+ size_t needed;
+ int mib[6];
+ int i;
+ char *buf;
+ char *data;
+ char *next;
+ char *p;
+ struct ifma_msghdr *ifmam;
+ struct ifmaddrs *ifa, *ift;
+ struct rt_msghdr *rtm;
+ struct sockaddr *sa;
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_ROUTE;
+ mib[2] = 0; /* protocol */
+ mib[3] = 0; /* wildcard address family */
+ mib[4] = NET_RT_IFMALIST;
+ mib[5] = 0; /* no flags */
+ do {
+ if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
+ return (-1);
+ if ((buf = malloc(needed)) == NULL)
+ return (-1);
+ if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
+ if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) {
+ free(buf);
+ return (-1);
+ }
+ free(buf);
+ buf = NULL;
+ }
+ } while (buf == NULL);
+
+ for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
+ rtm = (struct rt_msghdr *)(void *)next;
+ if (rtm->rtm_version != RTM_VERSION)
+ continue;
+ switch (rtm->rtm_type) {
+ case RTM_NEWMADDR:
+ ifmam = (struct ifma_msghdr *)(void *)rtm;
+ if ((ifmam->ifmam_addrs & RTA_IFA) == 0)
+ break;
+ icnt++;
+ p = (char *)(ifmam + 1);
+ for (i = 0; i < RTAX_MAX; i++) {
+ if ((RTA_MASKS & ifmam->ifmam_addrs &
+ (1 << i)) == 0)
+ continue;
+ sa = (struct sockaddr *)(void *)p;
+ len = SA_RLEN(sa);
+ dcnt += len;
+ p += len;
+ }
+ break;
+ }
+ }
+
+ data = malloc(sizeof(struct ifmaddrs) * icnt + dcnt);
+ if (data == NULL) {
+ free(buf);
+ return (-1);
+ }
+
+ ifa = (struct ifmaddrs *)(void *)data;
+ data += sizeof(struct ifmaddrs) * icnt;
+
+ memset(ifa, 0, sizeof(struct ifmaddrs) * icnt);
+ ift = ifa;
+
+ for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
+ rtm = (struct rt_msghdr *)(void *)next;
+ if (rtm->rtm_version != RTM_VERSION)
+ continue;
+
+ switch (rtm->rtm_type) {
+ case RTM_NEWMADDR:
+ ifmam = (struct ifma_msghdr *)(void *)rtm;
+ if ((ifmam->ifmam_addrs & RTA_IFA) == 0)
+ break;
+
+ p = (char *)(ifmam + 1);
+ for (i = 0; i < RTAX_MAX; i++) {
+ if ((RTA_MASKS & ifmam->ifmam_addrs &
+ (1 << i)) == 0)
+ continue;
+ sa = (struct sockaddr *)(void *)p;
+ len = SA_RLEN(sa);
+ switch (i) {
+ case RTAX_GATEWAY:
+ ift->ifma_lladdr =
+ (struct sockaddr *)(void *)data;
+ memcpy(data, p, len);
+ data += len;
+ break;
+
+ case RTAX_IFP:
+ ift->ifma_name =
+ (struct sockaddr *)(void *)data;
+ memcpy(data, p, len);
+ data += len;
+ break;
+
+ case RTAX_IFA:
+ ift->ifma_addr =
+ (struct sockaddr *)(void *)data;
+ memcpy(data, p, len);
+ data += len;
+ break;
+
+ default:
+ data += len;
+ break;
+ }
+ p += len;
+ }
+ ift->ifma_next = ift + 1;
+ ift = ift->ifma_next;
+ break;
+ }
+ }
+
+ free(buf);
+
+ if (ift > ifa) {
+ ift--;
+ ift->ifma_next = NULL;
+ *pif = ifa;
+ } else {
+ *pif = NULL;
+ free(ifa);
+ }
+ return (0);
+}
+
+void
+freeifmaddrs(struct ifmaddrs *ifmp)
+{
+
+ free(ifmp);
+}
diff --git a/lib/libc/net/getipnodebyname.3 b/lib/libc/net/getipnodebyname.3
new file mode 100644
index 000000000000..0697c64e68bd
--- /dev/null
+++ b/lib/libc/net/getipnodebyname.3
@@ -0,0 +1,474 @@
+.\" $KAME: getipnodebyname.3,v 1.6 2000/08/09 21:16:17 itojun Exp $
+.\"
+.\" Copyright (c) 1983, 1987, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" From: @(#)gethostbyname.3 8.4 (Berkeley) 5/25/95
+.\" $FreeBSD$
+.\"
+.Dd August 6, 2004
+.Dt GETIPNODEBYNAME 3
+.Os
+.\"
+.Sh NAME
+.Nm getipnodebyname ,
+.Nm getipnodebyaddr ,
+.Nm freehostent
+.Nd nodename-to-address and address-to-nodename translation
+.\"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/socket.h
+.In netdb.h
+.Ft "struct hostent *"
+.Fn getipnodebyname "const char *name" "int af" "int flags" "int *error_num"
+.Ft "struct hostent *"
+.Fn getipnodebyaddr "const void *src" "size_t len" "int af" "int *error_num"
+.Ft void
+.Fn freehostent "struct hostent *ptr"
+.\"
+.Sh DESCRIPTION
+The
+.Fn getipnodebyname
+and
+.Fn getipnodebyaddr
+functions are very similar to
+.Xr gethostbyname 3 ,
+.Xr gethostbyname2 3
+and
+.Xr gethostbyaddr 3 .
+The functions cover all the functionalities provided by the older ones,
+and provide better interface to programmers.
+The functions require additional arguments,
+.Fa af ,
+and
+.Fa flags ,
+for specifying address family and operation mode.
+The additional arguments allow programmer to get address for a nodename,
+for specific address family
+(such as
+.Dv AF_INET
+or
+.Dv AF_INET6 ) .
+The functions also require an additional pointer argument,
+.Fa error_num
+to return the appropriate error code,
+to support thread safe error code returns.
+.Pp
+The type and usage of the return value,
+.Li "struct hostent"
+is described in
+.Xr gethostbyname 3 .
+.Pp
+For
+.Fn getipnodebyname ,
+the
+.Fa name
+argument can be either a node name or a numeric address
+string
+(i.e., a dotted-decimal IPv4 address or an IPv6 hex address).
+The
+.Fa af
+argument specifies the address family, either
+.Dv AF_INET
+or
+.Dv AF_INET6 .
+The
+.Fa flags
+argument specifies the types of addresses that are searched for,
+and the types of addresses that are returned.
+We note that a special flags value of
+.Dv AI_DEFAULT
+(defined below)
+should handle most applications.
+That is, porting simple applications to use IPv6 replaces the call
+.Bd -literal -offset indent
+hptr = gethostbyname(name);
+.Ed
+.Pp
+with
+.Bd -literal -offset indent
+hptr = getipnodebyname(name, AF_INET6, AI_DEFAULT, &error_num);
+.Ed
+.Pp
+Applications desiring finer control over the types of addresses
+searched for and returned, can specify other combinations of the
+.Fa flags
+argument.
+.Pp
+A
+.Fa flags
+of
+.Li 0
+implies a strict interpretation of the
+.Fa af
+argument:
+.Bl -bullet
+.It
+If
+.Fa flags
+is 0 and
+.Fa af
+is
+.Dv AF_INET ,
+then the caller wants only IPv4 addresses.
+A query is made for
+.Li A
+records.
+If successful, the IPv4 addresses are returned and the
+.Li h_length
+member of the
+.Li hostent
+structure will be 4, else the function returns a
+.Dv NULL
+pointer.
+.It
+If
+.Fa flags
+is 0 and if
+.Fa af
+is
+.Li AF_INET6 ,
+then the caller wants only IPv6 addresses.
+A query is made for
+.Li AAAA
+records.
+If successful, the IPv6 addresses are returned and the
+.Li h_length
+member of the
+.Li hostent
+structure will be 16, else the function returns a
+.Dv NULL
+pointer.
+.El
+.Pp
+Other constants can be logically-ORed into the
+.Fa flags
+argument, to modify the behavior of the function.
+.Bl -bullet
+.It
+If the
+.Dv AI_V4MAPPED
+flag is specified along with an
+.Fa af
+of
+.Dv AF_INET6 ,
+then the caller will accept IPv4-mapped IPv6 addresses.
+That is, if no
+.Li AAAA
+records are found then a query is made for
+.Li A
+records and any found are returned as IPv4-mapped IPv6 addresses
+.Li ( h_length
+will be 16).
+The
+.Dv AI_V4MAPPED
+flag is ignored unless
+.Fa af
+equals
+.Dv AF_INET6 .
+.It
+The
+.Dv AI_V4MAPPED_CFG
+flag is exact same as the
+.Dv AI_V4MAPPED
+flag only if the kernel supports IPv4-mapped IPv6 address.
+.It
+If the
+.Dv AI_ALL
+flag is used in conjunction with the
+.Dv AI_V4MAPPED
+flag, and only used with the IPv6 address family.
+When
+.Dv AI_ALL
+is logically or'd with
+.Dv AI_V4MAPPED
+flag then the caller wants all addresses: IPv6 and IPv4-mapped IPv6.
+A query is first made for
+.Li AAAA
+records and if successful, the
+IPv6 addresses are returned.
+Another query is then made for
+.Li A
+records and any found are returned as IPv4-mapped IPv6 addresses.
+.Li h_length
+will be 16.
+Only if both queries fail does the function
+return a
+.Dv NULL
+pointer.
+This flag is ignored unless af equals
+AF_INET6.
+If both
+.Dv AI_ALL
+and
+.Dv AI_V4MAPPED
+are specified,
+.Dv AI_ALL
+takes precedence.
+.It
+The
+.Dv AI_ADDRCONFIG
+flag specifies that a query for
+.Li AAAA
+records
+should occur only if the node has at least one IPv6 source
+address configured and a query for
+.Li A
+records should occur only if the node has at least one IPv4 source address
+configured.
+.Pp
+For example, if the node has no IPv6 source addresses configured,
+and
+.Fa af
+equals AF_INET6, and the node name being looked up has both
+.Li AAAA
+and
+.Li A
+records, then:
+(a) if only
+.Dv AI_ADDRCONFIG
+is
+specified, the function returns a
+.Dv NULL
+pointer;
+(b) if
+.Dv AI_ADDRCONFIG
+|
+.Dv AI_V4MAPPED
+is specified, the
+.Li A
+records are returned as IPv4-mapped IPv6 addresses;
+.El
+.Pp
+The special flags value of
+.Dv AI_DEFAULT
+is defined as
+.Bd -literal -offset indent
+#define AI_DEFAULT (AI_V4MAPPED_CFG | AI_ADDRCONFIG)
+.Ed
+.Pp
+We noted that the
+.Fn getipnodebyname
+function must allow the
+.Fa name
+argument to be either a node name or a literal address string
+(i.e., a dotted-decimal IPv4 address or an IPv6 hex address).
+This saves applications from having to call
+.Xr inet_pton 3
+to handle literal address strings.
+When the
+.Fa name
+argument is a literal address string,
+the
+.Fa flags
+argument is always ignored.
+.Pp
+There are four scenarios based on the type of literal address string
+and the value of the
+.Fa af
+argument.
+The two simple cases are when
+.Fa name
+is a dotted-decimal IPv4 address and
+.Fa af
+equals
+.Dv AF_INET ,
+or when
+.Fa name
+is an IPv6 hex address and
+.Fa af
+equals
+.Dv AF_INET6 .
+The members of the
+returned hostent structure are:
+.Li h_name
+points to a copy of the
+.Fa name
+argument,
+.Li h_aliases
+is a
+.Dv NULL
+pointer,
+.Li h_addrtype
+is a copy of the
+.Fa af
+argument,
+.Li h_length
+is either 4
+(for
+.Dv AF_INET )
+or 16
+(for
+.Dv AF_INET6 ) ,
+.Li h_addr_list[0]
+is a pointer to the 4-byte or 16-byte binary address,
+and
+.Li h_addr_list[1]
+is a
+.Dv NULL
+pointer.
+.Pp
+When
+.Fa name
+is a dotted-decimal IPv4 address and
+.Fa af
+equals
+.Dv AF_INET6 ,
+and
+.Dv AI_V4MAPPED
+is specified,
+an IPv4-mapped IPv6 address is returned:
+.Li h_name
+points to an IPv6 hex address containing the IPv4-mapped IPv6 address,
+.Li h_aliases
+is a
+.Dv NULL
+pointer,
+.Li h_addrtype
+is
+.Dv AF_INET6 ,
+.Li h_length
+is 16,
+.Li h_addr_list[0]
+is a pointer to the 16-byte binary address, and
+.Li h_addr_list[1]
+is a
+.Dv NULL
+pointer.
+.Pp
+It is an error when
+.Fa name
+is an IPv6 hex address and
+.Fa af
+equals
+.Dv AF_INET .
+The function's return value is a
+.Dv NULL
+pointer and the value pointed to by
+.Fa error_num
+equals
+.Dv HOST_NOT_FOUND .
+.Pp
+The
+.Fn getipnodebyaddr
+function
+takes almost the same argument as
+.Xr gethostbyaddr 3 ,
+but adds a pointer to return an error number.
+Additionally it takes care of IPv4-mapped IPv6 addresses,
+and IPv4-compatible IPv6 addresses.
+.Pp
+The
+.Fn getipnodebyname
+and
+.Fn getipnodebyaddr
+functions
+dynamically allocate the structure to be returned to the caller.
+The
+.Fn freehostent
+function
+reclaims memory region allocated and returned by
+.Fn getipnodebyname
+or
+.Fn getipnodebyaddr .
+.\"
+.Sh FILES
+.Bl -tag -width /etc/nsswitch.conf -compact
+.It Pa /etc/hosts
+.It Pa /etc/nsswitch.conf
+.It Pa /etc/resolv.conf
+.El
+.\"
+.Sh DIAGNOSTICS
+The
+.Fn getipnodebyname
+and
+.Fn getipnodebyaddr
+functions
+returns
+.Dv NULL
+on errors.
+The integer values pointed to by
+.Fa error_num
+may then be checked to see whether this is a temporary failure
+or an invalid or unknown host.
+The meanings of each error code are described in
+.Xr gethostbyname 3 .
+.\"
+.Sh SEE ALSO
+.Xr getaddrinfo 3 ,
+.Xr gethostbyaddr 3 ,
+.Xr gethostbyname 3 ,
+.Xr getnameinfo 3 ,
+.Xr hosts 5 ,
+.Xr nsswitch.conf 5 ,
+.Xr services 5 ,
+.Xr hostname 7 ,
+.Xr named 8
+.Pp
+.Rs
+.%A R. Gilligan
+.%A S. Thomson
+.%A J. Bound
+.%A W. Stevens
+.%T Basic Socket Interface Extensions for IPv6
+.%R RFC2553
+.%D March 1999
+.Re
+.\"
+.Sh STANDARDS
+The
+.Fn getipnodebyname
+and
+.Fn getipnodebyaddr
+functions
+are documented in
+.Dq Basic Socket Interface Extensions for IPv6
+(RFC2553).
+.\"
+.Sh HISTORY
+The implementation first appeared in KAME advanced networking kit.
+.\"
+.Sh BUGS
+The
+.Fn getipnodebyname
+and
+.Fn getipnodebyaddr
+functions
+do not handle scoped IPv6 address properly.
+If you use these functions,
+your program will not be able to handle scoped IPv6 addresses.
+For IPv6 address manipulation,
+.Fn getaddrinfo 3
+and
+.Fn getnameinfo 3
+are recommended.
+.Pp
+The text was shamelessly copied from RFC2553.
diff --git a/lib/libc/net/getnameinfo.3 b/lib/libc/net/getnameinfo.3
new file mode 100644
index 000000000000..9e49eaccf3f1
--- /dev/null
+++ b/lib/libc/net/getnameinfo.3
@@ -0,0 +1,298 @@
+.\" $KAME: getnameinfo.3,v 1.37 2005/01/05 03:23:05 itojun Exp $
+.\" $OpenBSD: getnameinfo.3,v 1.36 2004/12/21 09:48:20 jmc Exp $
+.\"
+.\" Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+.\" Copyright (C) 2000, 2001 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd July 28, 2016
+.Dt GETNAMEINFO 3
+.Os
+.Sh NAME
+.Nm getnameinfo
+.Nd socket address structure to hostname and service name
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/socket.h
+.In netdb.h
+.Ft int
+.Fo getnameinfo
+.Fa "const struct sockaddr *sa" "socklen_t salen" "char *host"
+.Fa "size_t hostlen" "char *serv" "size_t servlen" "int flags"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn getnameinfo
+function is used to convert a
+.Li sockaddr
+structure to a pair of host name and service strings.
+It is a replacement for and provides more flexibility than the
+.Xr gethostbyaddr 3
+and
+.Xr getservbyport 3
+functions and is the converse of the
+.Xr getaddrinfo 3
+function.
+.Pp
+If a link-layer address or UNIX-domain address is passed to
+.Fn getnameinfo ,
+its ASCII representation will be stored in
+.Fa host .
+The string pointed to by
+.Fa serv
+will be set to the empty string if non-NULL;
+.Fa flags
+will always be ignored.
+For a link-layer address,
+this can be used as a replacement of the legacy
+.Xr link_ntoa 3
+function.
+.Pp
+The
+.Li sockaddr
+structure
+.Fa sa
+should point to either a
+.Li sockaddr_in ,
+.Li sockaddr_in6 ,
+.Li sockaddr_dl ,
+or
+.Li sockaddr_un
+structure
+.Po for IPv4 ,
+IPv6,
+link-layer,
+or UNIX-domain respectively
+.Pc
+that is
+.Fa salen
+bytes long.
+.Pp
+The host and service names associated with
+.Fa sa
+are stored in
+.Fa host
+and
+.Fa serv
+which have length parameters
+.Fa hostlen
+and
+.Fa servlen .
+The maximum value for
+.Fa hostlen
+is
+.Dv NI_MAXHOST
+and
+the maximum value for
+.Fa servlen
+is
+.Dv NI_MAXSERV ,
+as defined by
+.Aq Pa netdb.h .
+If a length parameter is zero, no string will be stored.
+Otherwise, enough space must be provided to store the
+host name or service string plus a byte for the NUL terminator.
+.Pp
+The
+.Fa flags
+argument is formed by
+.Tn OR Ns 'ing
+the following values:
+.Bl -tag -width "NI_NUMERICSCOPEXX"
+.It Dv NI_NOFQDN
+A fully qualified domain name is not required for local hosts.
+The local part of the fully qualified domain name is returned instead.
+.It Dv NI_NUMERICHOST
+Return the address in numeric form, as if calling
+.Xr inet_ntop 3 ,
+instead of a host name.
+.It Dv NI_NAMEREQD
+A name is required.
+If the host name cannot be found in DNS and this flag is set,
+a non-zero error code is returned.
+If the host name is not found and the flag is not set, the
+address is returned in numeric form.
+.It NI_NUMERICSERV
+The service name is returned as a digit string representing the port number.
+.It NI_NUMERICSCOPE
+The scope identifier is returned as a digit string.
+.It NI_DGRAM
+Specifies that the service being looked up is a datagram
+service, and causes
+.Xr getservbyport 3
+to be called with a second argument of
+.Dq udp
+instead of its default of
+.Dq tcp .
+This is required for the few ports (512\-514) that have different services
+for
+.Tn UDP
+and
+.Tn TCP .
+.El
+.Pp
+This implementation allows numeric IPv6 address notation with scope identifier,
+as documented in chapter 11 of RFC 4007.
+IPv6 link-local address will appear as a string like
+.Dq Li fe80::1%ne0 .
+Refer to
+.Xr getaddrinfo 3
+for more information.
+.Sh RETURN VALUES
+.Fn getnameinfo
+returns zero on success or one of the error codes listed in
+.Xr gai_strerror 3
+if an error occurs.
+.Sh EXAMPLES
+The following code tries to get a numeric host name, and service name,
+for a given socket address.
+Observe that there is no hardcoded reference to a particular address family.
+.Bd -literal -offset indent
+struct sockaddr *sa; /* input */
+char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
+
+if (getnameinfo(sa, sa->sa_len, hbuf, sizeof(hbuf), sbuf,
+ sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV)) {
+ errx(1, "could not get numeric hostname");
+ /* NOTREACHED */
+}
+printf("host=%s, serv=%s\en", hbuf, sbuf);
+.Ed
+.Pp
+The following version checks if the socket address has a reverse address mapping:
+.Bd -literal -offset indent
+struct sockaddr *sa; /* input */
+char hbuf[NI_MAXHOST];
+
+if (getnameinfo(sa, sa->sa_len, hbuf, sizeof(hbuf), NULL, 0,
+ NI_NAMEREQD)) {
+ errx(1, "could not resolve hostname");
+ /* NOTREACHED */
+}
+printf("host=%s\en", hbuf);
+.Ed
+.Sh SEE ALSO
+.Xr gai_strerror 3 ,
+.Xr getaddrinfo 3 ,
+.Xr gethostbyaddr 3 ,
+.Xr getservbyport 3 ,
+.Xr inet_ntop 3 ,
+.Xr link_ntoa 3 ,
+.Xr resolver 3 ,
+.Xr inet 4 ,
+.Xr inet6 4 ,
+.Xr unix 4 ,
+.Xr hosts 5 ,
+.Xr resolv.conf 5 ,
+.Xr services 5 ,
+.Xr hostname 7 ,
+.Xr named 8
+.Rs
+.%A R. Gilligan
+.%A S. Thomson
+.%A J. Bound
+.%A J. McCann
+.%A W. Stevens
+.%T Basic Socket Interface Extensions for IPv6
+.%R RFC 3493
+.%D February 2003
+.Re
+.Rs
+.%A S. Deering
+.%A B. Haberman
+.%A T. Jinmei
+.%A E. Nordmark
+.%A B. Zill
+.%T "IPv6 Scoped Address Architecture"
+.%R RFC 4007
+.%D March 2005
+.Re
+.Rs
+.%A Craig Metz
+.%T Protocol Independence Using the Sockets API
+.%B "Proceedings of the freenix track: 2000 USENIX annual technical conference"
+.%D June 2000
+.Re
+.Sh STANDARDS
+The
+.Fn getnameinfo
+function is defined by the
+.St -p1003.1-2004
+specification and documented in
+.Tn "RFC 3493" ,
+.Dq Basic Socket Interface Extensions for IPv6 .
+.Sh CAVEATS
+.Fn getnameinfo
+can return both numeric and FQDN forms of the address specified in
+.Fa sa .
+There is no return value that indicates whether the string returned in
+.Fa host
+is a result of binary to numeric-text translation (like
+.Xr inet_ntop 3 ) ,
+or is the result of a DNS reverse lookup.
+Because of this, malicious parties could set up a PTR record as follows:
+.Bd -literal -offset indent
+1.0.0.127.in-addr.arpa. IN PTR 10.1.1.1
+.Ed
+.Pp
+and trick the caller of
+.Fn getnameinfo
+into believing that
+.Fa sa
+is
+.Li 10.1.1.1
+when it is actually
+.Li 127.0.0.1 .
+.Pp
+To prevent such attacks, the use of
+.Dv NI_NAMEREQD
+is recommended when the result of
+.Fn getnameinfo
+is used
+for access control purposes:
+.Bd -literal -offset indent
+struct sockaddr *sa;
+socklen_t salen;
+char addr[NI_MAXHOST];
+struct addrinfo hints, *res;
+int error;
+
+error = getnameinfo(sa, salen, addr, sizeof(addr),
+ NULL, 0, NI_NAMEREQD);
+if (error == 0) {
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_socktype = SOCK_DGRAM; /*dummy*/
+ hints.ai_flags = AI_NUMERICHOST;
+ if (getaddrinfo(addr, "0", &hints, &res) == 0) {
+ /* malicious PTR record */
+ freeaddrinfo(res);
+ printf("bogus PTR record\en");
+ return -1;
+ }
+ /* addr is FQDN as a result of PTR lookup */
+} else {
+ /* addr is numeric string */
+ error = getnameinfo(sa, salen, addr, sizeof(addr),
+ NULL, 0, NI_NUMERICHOST);
+}
+.Ed
+.\".Pp
+.\".Ox
+.\"intentionally uses a different
+.\".Dv NI_MAXHOST
+.\"value from what
+.\".Tn "RFC 2553"
+.\"suggests, to avoid buffer length handling mistakes.
diff --git a/lib/libc/net/getnameinfo.c b/lib/libc/net/getnameinfo.c
new file mode 100644
index 000000000000..54f232449fc2
--- /dev/null
+++ b/lib/libc/net/getnameinfo.c
@@ -0,0 +1,529 @@
+/* $KAME: getnameinfo.c,v 1.61 2002/06/27 09:25:47 itojun Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * Copyright (c) 2000 Ben Harris.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Issues to be discussed:
+ * - Thread safe-ness must be checked
+ * - RFC2553 says that we should raise error on short buffer. X/Open says
+ * we need to truncate the result. We obey RFC2553 (and X/Open should be
+ * modified). ipngwg rough consensus seems to follow RFC2553.
+ * - What is "local" in NI_FQDN?
+ * - NI_NAMEREQD and NI_NUMERICHOST conflict with each other.
+ * - (KAME extension) always attach textual scopeid (fe80::1%lo0), if
+ * sin6_scope_id is filled - standardization status?
+ * XXX breaks backward compat for code that expects no scopeid.
+ * beware on merge.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/firewire.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <string.h>
+#include <stddef.h>
+#include <errno.h>
+
+static const struct afd *find_afd(int);
+static int getnameinfo_inet(const struct afd *,
+ const struct sockaddr *, socklen_t, char *,
+ size_t, char *, size_t, int);
+#ifdef INET6
+static int ip6_parsenumeric(const struct sockaddr *, const char *, char *,
+ size_t, int);
+static int ip6_sa2str(const struct sockaddr_in6 *, char *, size_t, int);
+#endif
+static int getnameinfo_link(const struct afd *,
+ const struct sockaddr *, socklen_t, char *,
+ size_t, char *, size_t, int);
+static int hexname(const u_int8_t *, size_t, char *, size_t);
+static int getnameinfo_un(const struct afd *,
+ const struct sockaddr *, socklen_t, char *,
+ size_t, char *, size_t, int);
+
+static const struct afd {
+ int a_af;
+ size_t a_addrlen;
+ socklen_t a_socklen;
+ int a_off;
+ int (*a_func)(const struct afd *,
+ const struct sockaddr *, socklen_t, char *,
+ size_t, char *, size_t, int);
+} afdl [] = {
+#ifdef INET6
+ {PF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6),
+ offsetof(struct sockaddr_in6, sin6_addr),
+ getnameinfo_inet},
+#endif
+ {PF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in),
+ offsetof(struct sockaddr_in, sin_addr),
+ getnameinfo_inet},
+#define sizeofmember(type, member) (sizeof(((type *)0)->member))
+ {PF_LOCAL, sizeofmember(struct sockaddr_un, sun_path),
+ sizeof(struct sockaddr_un),
+ offsetof(struct sockaddr_un, sun_path),
+ getnameinfo_un},
+ {PF_LINK, sizeofmember(struct sockaddr_dl, sdl_data),
+ sizeof(struct sockaddr_dl),
+ offsetof(struct sockaddr_dl, sdl_data),
+ getnameinfo_link},
+ {0, 0, 0},
+};
+
+int
+getnameinfo(const struct sockaddr *sa, socklen_t salen,
+ char *host, size_t hostlen, char *serv, size_t servlen,
+ int flags)
+{
+ const struct afd *afd;
+
+ if (sa == NULL)
+ return (EAI_FAIL);
+
+ afd = find_afd(sa->sa_family);
+ if (afd == NULL)
+ return (EAI_FAMILY);
+ switch (sa->sa_family) {
+ case PF_LOCAL:
+ /*
+ * PF_LOCAL uses variable sa->sa_len depending on the
+ * content length of sun_path. Require 1 byte in
+ * sun_path at least.
+ */
+ if (salen > afd->a_socklen ||
+ salen <= afd->a_socklen -
+ sizeofmember(struct sockaddr_un, sun_path))
+ return (EAI_FAIL);
+ break;
+ case PF_LINK:
+ if (salen <= afd->a_socklen -
+ sizeofmember(struct sockaddr_dl, sdl_data))
+ return (EAI_FAIL);
+ break;
+ default:
+ if (salen != afd->a_socklen)
+ return (EAI_FAIL);
+ break;
+ }
+
+ return ((*afd->a_func)(afd, sa, salen, host, hostlen,
+ serv, servlen, flags));
+}
+
+static const struct afd *
+find_afd(int af)
+{
+ const struct afd *afd;
+
+ if (af == PF_UNSPEC)
+ return (NULL);
+ for (afd = &afdl[0]; afd->a_af > 0; afd++) {
+ if (afd->a_af == af)
+ return (afd);
+ }
+ return (NULL);
+}
+
+static int
+getnameinfo_inet(const struct afd *afd,
+ const struct sockaddr *sa, socklen_t salen,
+ char *host, size_t hostlen, char *serv, size_t servlen,
+ int flags)
+{
+ struct servent *sp;
+ struct hostent *hp;
+ u_short port;
+ const char *addr;
+ u_int32_t v4a;
+ int h_error;
+ char numserv[512];
+ char numaddr[512];
+
+ /* network byte order */
+ port = ((const struct sockaddr_in *)sa)->sin_port;
+ addr = (const char *)sa + afd->a_off;
+
+ if (serv == NULL || servlen == 0) {
+ /*
+ * do nothing in this case.
+ * in case you are wondering if "&&" is more correct than
+ * "||" here: rfc2553bis-03 says that serv == NULL OR
+ * servlen == 0 means that the caller does not want the result.
+ */
+ } else {
+ if (flags & NI_NUMERICSERV)
+ sp = NULL;
+ else {
+ sp = getservbyport(port,
+ (flags & NI_DGRAM) ? "udp" : "tcp");
+ }
+ if (sp) {
+ if (strlen(sp->s_name) + 1 > servlen)
+ return EAI_MEMORY;
+ strlcpy(serv, sp->s_name, servlen);
+ } else {
+ snprintf(numserv, sizeof(numserv), "%u", ntohs(port));
+ if (strlen(numserv) + 1 > servlen)
+ return EAI_MEMORY;
+ strlcpy(serv, numserv, servlen);
+ }
+ }
+
+ switch (sa->sa_family) {
+ case AF_INET:
+ v4a = (u_int32_t)
+ ntohl(((const struct sockaddr_in *)sa)->sin_addr.s_addr);
+ if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
+ flags |= NI_NUMERICHOST;
+ v4a >>= IN_CLASSA_NSHIFT;
+ if (v4a == 0)
+ flags |= NI_NUMERICHOST;
+ break;
+#ifdef INET6
+ case AF_INET6:
+ {
+ const struct sockaddr_in6 *sin6;
+ sin6 = (const struct sockaddr_in6 *)sa;
+ switch (sin6->sin6_addr.s6_addr[0]) {
+ case 0x00:
+ if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
+ ;
+ else if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr))
+ ;
+ else
+ flags |= NI_NUMERICHOST;
+ break;
+ default:
+ if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
+ flags |= NI_NUMERICHOST;
+ }
+ else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
+ flags |= NI_NUMERICHOST;
+ break;
+ }
+ }
+ break;
+#endif
+ }
+ if (host == NULL || hostlen == 0) {
+ /*
+ * do nothing in this case.
+ * in case you are wondering if "&&" is more correct than
+ * "||" here: rfc2553bis-03 says that host == NULL or
+ * hostlen == 0 means that the caller does not want the result.
+ */
+ } else if (flags & NI_NUMERICHOST) {
+ size_t numaddrlen;
+
+ /* NUMERICHOST and NAMEREQD conflicts with each other */
+ if (flags & NI_NAMEREQD)
+ return EAI_NONAME;
+
+ switch(afd->a_af) {
+#ifdef INET6
+ case AF_INET6:
+ {
+ int error;
+
+ if ((error = ip6_parsenumeric(sa, addr, host,
+ hostlen, flags)) != 0)
+ return(error);
+ break;
+ }
+#endif
+ default:
+ if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr))
+ == NULL)
+ return EAI_SYSTEM;
+ numaddrlen = strlen(numaddr);
+ if (numaddrlen + 1 > hostlen) /* don't forget terminator */
+ return EAI_MEMORY;
+ strlcpy(host, numaddr, hostlen);
+ break;
+ }
+ } else {
+ hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error);
+
+ if (hp) {
+#if 0
+ /*
+ * commented out, since "for local host" is not
+ * implemented here - see RFC2553 p30
+ */
+ if (flags & NI_NOFQDN) {
+ char *p;
+ p = strchr(hp->h_name, '.');
+ if (p)
+ *p = '\0';
+ }
+#endif
+ if (strlen(hp->h_name) + 1 > hostlen) {
+ freehostent(hp);
+ return EAI_MEMORY;
+ }
+ strlcpy(host, hp->h_name, hostlen);
+ freehostent(hp);
+ } else {
+ if (flags & NI_NAMEREQD)
+ return EAI_NONAME;
+ switch(afd->a_af) {
+#ifdef INET6
+ case AF_INET6:
+ {
+ int error;
+
+ if ((error = ip6_parsenumeric(sa, addr, host,
+ hostlen,
+ flags)) != 0)
+ return(error);
+ break;
+ }
+#endif
+ default:
+ if (inet_ntop(afd->a_af, addr, host,
+ hostlen) == NULL)
+ return EAI_SYSTEM;
+ break;
+ }
+ }
+ }
+ return(0);
+}
+
+#ifdef INET6
+static int
+ip6_parsenumeric(const struct sockaddr *sa, const char *addr,
+ char *host, size_t hostlen, int flags)
+{
+ size_t numaddrlen;
+ char numaddr[512];
+
+ if (inet_ntop(AF_INET6, addr, numaddr, sizeof(numaddr)) == NULL)
+ return EAI_SYSTEM;
+
+ numaddrlen = strlen(numaddr);
+ if (numaddrlen + 1 > hostlen) /* don't forget terminator */
+ return EAI_OVERFLOW;
+ strlcpy(host, numaddr, hostlen);
+
+ if (((const struct sockaddr_in6 *)sa)->sin6_scope_id) {
+ char zonebuf[MAXHOSTNAMELEN];
+ int zonelen;
+
+ zonelen = ip6_sa2str(
+ (const struct sockaddr_in6 *)(const void *)sa,
+ zonebuf, sizeof(zonebuf), flags);
+ if (zonelen < 0)
+ return EAI_OVERFLOW;
+ if (zonelen + 1 + numaddrlen + 1 > hostlen)
+ return EAI_OVERFLOW;
+
+ /* construct <numeric-addr><delim><zoneid> */
+ memcpy(host + numaddrlen + 1, zonebuf,
+ (size_t)zonelen);
+ host[numaddrlen] = SCOPE_DELIMITER;
+ host[numaddrlen + 1 + zonelen] = '\0';
+ }
+
+ return 0;
+}
+
+/* ARGSUSED */
+static int
+ip6_sa2str(const struct sockaddr_in6 *sa6, char *buf, size_t bufsiz, int flags)
+{
+ unsigned int ifindex;
+ const struct in6_addr *a6;
+ int n;
+
+ ifindex = (unsigned int)sa6->sin6_scope_id;
+ a6 = &sa6->sin6_addr;
+
+ if ((flags & NI_NUMERICSCOPE) != 0) {
+ n = snprintf(buf, bufsiz, "%u", sa6->sin6_scope_id);
+ if (n < 0 || n >= bufsiz)
+ return -1;
+ else
+ return n;
+ }
+
+ /* if_indextoname() does not take buffer size. not a good api... */
+ if ((IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6) ||
+ IN6_IS_ADDR_MC_NODELOCAL(a6)) && bufsiz >= IF_NAMESIZE) {
+ char *p = if_indextoname(ifindex, buf);
+ if (p) {
+ return(strlen(p));
+ }
+ }
+
+ /* last resort */
+ n = snprintf(buf, bufsiz, "%u", sa6->sin6_scope_id);
+ if (n < 0 || (size_t)n >= bufsiz)
+ return -1;
+ else
+ return n;
+}
+#endif /* INET6 */
+
+/*
+ * getnameinfo_link():
+ * Format a link-layer address into a printable format, paying attention to
+ * the interface type.
+ */
+/* ARGSUSED */
+static int
+getnameinfo_link(const struct afd *afd,
+ const struct sockaddr *sa, socklen_t salen,
+ char *host, size_t hostlen, char *serv, size_t servlen, int flags)
+{
+ const struct sockaddr_dl *sdl =
+ (const struct sockaddr_dl *)(const void *)sa;
+ const struct fw_hwaddr *iha;
+ int n;
+
+ if (serv != NULL && servlen > 0)
+ *serv = '\0';
+
+ if (sdl->sdl_nlen == 0 && sdl->sdl_alen == 0 && sdl->sdl_slen == 0) {
+ n = snprintf(host, hostlen, "link#%d", sdl->sdl_index);
+ if (n >= hostlen) {
+ *host = '\0';
+ return (EAI_MEMORY);
+ }
+ return (0);
+ }
+
+ if (sdl->sdl_nlen > 0 && sdl->sdl_alen == 0) {
+ n = sdl->sdl_nlen;
+ if (n >= hostlen) {
+ *host = '\0';
+ return (EAI_MEMORY);
+ }
+ memcpy(host, sdl->sdl_data, sdl->sdl_nlen);
+ host[n] = '\0';
+ return (0);
+ }
+
+ switch (sdl->sdl_type) {
+ case IFT_IEEE1394:
+ if (sdl->sdl_alen < sizeof(iha->sender_unique_ID_hi) +
+ sizeof(iha->sender_unique_ID_lo))
+ return EAI_FAMILY;
+ iha = (const struct fw_hwaddr *)(const void *)LLADDR(sdl);
+ return hexname((const u_int8_t *)&iha->sender_unique_ID_hi,
+ sizeof(iha->sender_unique_ID_hi) +
+ sizeof(iha->sender_unique_ID_lo),
+ host, hostlen);
+ /*
+ * The following have zero-length addresses.
+ * IFT_ATM (net/if_atmsubr.c)
+ * IFT_GIF (net/if_gif.c)
+ * IFT_LOOP (net/if_loop.c)
+ * IFT_PPP (net/if_ppp.c, net/if_spppsubr.c)
+ * IFT_SLIP (net/if_sl.c, net/if_strip.c)
+ * IFT_STF (net/if_stf.c)
+ * IFT_L2VLAN (net/if_vlan.c)
+ * IFT_BRIDGE (net/if_bridge.h>
+ */
+ /*
+ * The following use IPv4 addresses as link-layer addresses:
+ * IFT_OTHER (net/if_gre.c)
+ * IFT_OTHER (netinet/ip_ipip.c)
+ */
+ /* default below is believed correct for all these. */
+ case IFT_ARCNET:
+ case IFT_ETHER:
+ case IFT_FDDI:
+ case IFT_HIPPI:
+ case IFT_ISO88025:
+ default:
+ return hexname((u_int8_t *)LLADDR(sdl), (size_t)sdl->sdl_alen,
+ host, hostlen);
+ }
+}
+
+static int
+hexname(const u_int8_t *cp, size_t len, char *host, size_t hostlen)
+{
+ int i, n;
+ char *outp = host;
+
+ *outp = '\0';
+ for (i = 0; i < len; i++) {
+ n = snprintf(outp, hostlen, "%s%02x",
+ i ? ":" : "", cp[i]);
+ if (n < 0 || n >= hostlen) {
+ *host = '\0';
+ return EAI_MEMORY;
+ }
+ outp += n;
+ hostlen -= n;
+ }
+ return 0;
+}
+
+/*
+ * getnameinfo_un():
+ * Format a UNIX IPC domain address (pathname).
+ */
+/* ARGSUSED */
+static int
+getnameinfo_un(const struct afd *afd,
+ const struct sockaddr *sa, socklen_t salen,
+ char *host, size_t hostlen, char *serv, size_t servlen, int flags)
+{
+ size_t pathlen;
+
+ if (serv != NULL && servlen > 0)
+ *serv = '\0';
+ if (host != NULL && hostlen > 0) {
+ pathlen = sa->sa_len - afd->a_off;
+
+ if (pathlen + 1 > hostlen) {
+ *host = '\0';
+ return (EAI_MEMORY);
+ }
+ strlcpy(host, (const char *)sa + afd->a_off, pathlen + 1);
+ }
+
+ return (0);
+}
diff --git a/lib/libc/net/getnetbydns.c b/lib/libc/net/getnetbydns.c
new file mode 100644
index 000000000000..6667a82f4645
--- /dev/null
+++ b/lib/libc/net/getnetbydns.c
@@ -0,0 +1,465 @@
+/*-
+ * Copyright (c) 1985, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * -
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ * -
+ * --Copyright--
+ */
+/* Portions Copyright (c) 1993 Carlos Leandro and Rui Salgueiro
+ * Dep. Matematica Universidade de Coimbra, Portugal, Europe
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)gethostnamadr.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <ctype.h>
+#include <string.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <stdarg.h>
+#include <nsswitch.h>
+
+#include "netdb_private.h"
+#include "res_config.h"
+
+#define BYADDR 0
+#define BYNAME 1
+
+#define MAXPACKET (64*1024)
+
+typedef union {
+ HEADER hdr;
+ u_char buf[MAXPACKET];
+} querybuf;
+
+typedef union {
+ long al;
+ char ac;
+} align;
+
+/*
+ * Reverse the order of first four dotted entries of in.
+ * Out must contain space for at least strlen(in) characters.
+ * The result does not include any leading 0s of in.
+ */
+static void
+ipreverse(char *in, char *out)
+{
+ char *pos[4];
+ int len[4];
+ char *p, *start;
+ int i = 0;
+ int leading = 1;
+
+ /* Fill-in element positions and lengths: pos[], len[]. */
+ start = p = in;
+ for (;;) {
+ if (*p == '.' || *p == '\0') {
+ /* Leading 0? */
+ if (leading && p - start == 1 && *start == '0')
+ len[i] = 0;
+ else {
+ len[i] = p - start;
+ leading = 0;
+ }
+ pos[i] = start;
+ start = p + 1;
+ i++;
+ }
+ if (i == 4)
+ break;
+ if (*p == 0) {
+ for (; i < 4; i++) {
+ pos[i] = p;
+ len[i] = 0;
+ }
+ break;
+ }
+ p++;
+ }
+
+ /* Copy the entries in reverse order */
+ p = out;
+ leading = 1;
+ for (i = 3; i >= 0; i--) {
+ memcpy(p, pos[i], len[i]);
+ if (len[i])
+ leading = 0;
+ p += len[i];
+ /* Need a . separator? */
+ if (!leading && i > 0 && len[i - 1])
+ *p++ = '.';
+ }
+ *p = '\0';
+}
+
+static int
+getnetanswer(querybuf *answer, int anslen, int net_i, struct netent *ne,
+ struct netent_data *ned, res_state statp)
+{
+
+ HEADER *hp;
+ u_char *cp;
+ int n;
+ u_char *eom;
+ int type, class, ancount, qdcount, haveanswer;
+ char aux[MAXHOSTNAMELEN];
+ char ans[MAXHOSTNAMELEN];
+ char *in, *bp, *ep, **ap;
+
+ /*
+ * find first satisfactory answer
+ *
+ * answer --> +------------+ ( MESSAGE )
+ * | Header |
+ * +------------+
+ * | Question | the question for the name server
+ * +------------+
+ * | Answer | RRs answering the question
+ * +------------+
+ * | Authority | RRs pointing toward an authority
+ * | Additional | RRs holding additional information
+ * +------------+
+ */
+ eom = answer->buf + anslen;
+ hp = &answer->hdr;
+ ancount = ntohs(hp->ancount); /* #/records in the answer section */
+ qdcount = ntohs(hp->qdcount); /* #/entries in the question section */
+ bp = ned->netbuf;
+ ep = ned->netbuf + sizeof(ned->netbuf);
+ cp = answer->buf + HFIXEDSZ;
+ if (!qdcount) {
+ if (hp->aa)
+ RES_SET_H_ERRNO(statp, HOST_NOT_FOUND);
+ else
+ RES_SET_H_ERRNO(statp, TRY_AGAIN);
+ return (-1);
+ }
+ while (qdcount-- > 0)
+ cp += __dn_skipname(cp, eom) + QFIXEDSZ;
+ ap = ned->net_aliases;
+ *ap = NULL;
+ ne->n_aliases = ned->net_aliases;
+ haveanswer = 0;
+ while (--ancount >= 0 && cp < eom) {
+ n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
+ if ((n < 0) || !res_dnok(bp))
+ break;
+ cp += n;
+ ans[0] = '\0';
+ (void)strncpy(&ans[0], bp, sizeof(ans) - 1);
+ ans[sizeof(ans) - 1] = '\0';
+ GETSHORT(type, cp);
+ GETSHORT(class, cp);
+ cp += INT32SZ; /* TTL */
+ GETSHORT(n, cp);
+ if (class == C_IN && type == T_PTR) {
+ n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
+ if ((n < 0) || !res_hnok(bp)) {
+ cp += n;
+ return (-1);
+ }
+ cp += n;
+ *ap++ = bp;
+ n = strlen(bp) + 1;
+ bp += n;
+ ne->n_addrtype = (class == C_IN) ? AF_INET : AF_UNSPEC;
+ haveanswer++;
+ }
+ }
+ if (haveanswer) {
+ *ap = NULL;
+ switch (net_i) {
+ case BYADDR:
+ ne->n_name = *ne->n_aliases;
+ ne->n_net = 0L;
+ break;
+ case BYNAME:
+ in = *ne->n_aliases;
+ n = strlen(ans) + 1;
+ if (ep - bp < n) {
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ errno = ENOBUFS;
+ return (-1);
+ }
+ strlcpy(bp, ans, ep - bp);
+ ne->n_name = bp;
+ if (strlen(in) + 1 > sizeof(aux)) {
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ errno = ENOBUFS;
+ return (-1);
+ }
+ ipreverse(in, aux);
+ ne->n_net = inet_network(aux);
+ break;
+ }
+ ne->n_aliases++;
+ return (0);
+ }
+ RES_SET_H_ERRNO(statp, TRY_AGAIN);
+ return (-1);
+}
+
+int
+_dns_getnetbyaddr(void *rval, void *cb_data, va_list ap)
+{
+ uint32_t net;
+ int net_type;
+ char *buffer;
+ size_t buflen;
+ int *errnop, *h_errnop;
+ struct netent *nptr, ne;
+ struct netent_data *ned;
+ unsigned int netbr[4];
+ int nn, anslen, error;
+ querybuf *buf;
+ char qbuf[MAXDNAME];
+ uint32_t net2;
+ res_state statp;
+
+ net = va_arg(ap, uint32_t);
+ net_type = va_arg(ap, int);
+ nptr = va_arg(ap, struct netent *);
+ buffer = va_arg(ap, char *);
+ buflen = va_arg(ap, size_t);
+ errnop = va_arg(ap, int *);
+ h_errnop = va_arg(ap, int *);
+
+ statp = __res_state();
+ if ((statp->options & RES_INIT) == 0 && res_ninit(statp) == -1) {
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ *h_errnop = statp->res_h_errno;
+ return (NS_UNAVAIL);
+ }
+
+ if ((ned = __netent_data_init()) == NULL) {
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ *h_errnop = statp->res_h_errno;
+ return (NS_UNAVAIL);
+ }
+
+ *((struct netent **)rval) = NULL;
+
+ if (net_type != AF_INET) {
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ *h_errnop = statp->res_h_errno;
+ return (NS_UNAVAIL);
+ }
+
+ for (nn = 4, net2 = net; net2; net2 >>= 8)
+ netbr[--nn] = net2 & 0xff;
+ switch (nn) {
+ case 3: /* Class A */
+ sprintf(qbuf, "0.0.0.%u.in-addr.arpa", netbr[3]);
+ break;
+ case 2: /* Class B */
+ sprintf(qbuf, "0.0.%u.%u.in-addr.arpa", netbr[3], netbr[2]);
+ break;
+ case 1: /* Class C */
+ sprintf(qbuf, "0.%u.%u.%u.in-addr.arpa", netbr[3], netbr[2],
+ netbr[1]);
+ break;
+ case 0: /* Class D - E */
+ sprintf(qbuf, "%u.%u.%u.%u.in-addr.arpa", netbr[3], netbr[2],
+ netbr[1], netbr[0]);
+ break;
+ }
+ if ((buf = malloc(sizeof(*buf))) == NULL) {
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ *h_errnop = statp->res_h_errno;
+ return (NS_NOTFOUND);
+ }
+ anslen = res_nquery(statp, qbuf, C_IN, T_PTR, (u_char *)buf,
+ sizeof(*buf));
+ if (anslen < 0) {
+ free(buf);
+#ifdef DEBUG
+ if (statp->options & RES_DEBUG)
+ printf("res_nsearch failed\n");
+#endif
+ *h_errnop = statp->res_h_errno;
+ return (NS_UNAVAIL);
+ } else if (anslen > sizeof(*buf)) {
+ free(buf);
+#ifdef DEBUG
+ if (statp->options & RES_DEBUG)
+ printf("res_nsearch static buffer too small\n");
+#endif
+ *h_errnop = statp->res_h_errno;
+ return (NS_UNAVAIL);
+ }
+ error = getnetanswer(buf, anslen, BYADDR, &ne, ned, statp);
+ free(buf);
+ if (error == 0) {
+ /* Strip trailing zeros */
+ while ((net & 0xff) == 0 && net != 0)
+ net >>= 8;
+ ne.n_net = net;
+ if (__copy_netent(&ne, nptr, buffer, buflen) != 0) {
+ *errnop = errno;
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ *h_errnop = statp->res_h_errno;
+ return (NS_RETURN);
+ }
+ *((struct netent **)rval) = nptr;
+ return (NS_SUCCESS);
+ }
+ *h_errnop = statp->res_h_errno;
+ return (NS_NOTFOUND);
+}
+
+int
+_dns_getnetbyname(void *rval, void *cb_data, va_list ap)
+{
+ const char *net;
+ char *buffer;
+ size_t buflen;
+ int *errnop, *h_errnop;
+ struct netent *nptr, ne;
+ struct netent_data *ned;
+ int anslen, error;
+ querybuf *buf;
+ char qbuf[MAXDNAME];
+ res_state statp;
+
+ net = va_arg(ap, const char *);
+ nptr = va_arg(ap, struct netent *);
+ buffer = va_arg(ap, char *);
+ buflen = va_arg(ap, size_t);
+ errnop = va_arg(ap, int *);
+ h_errnop = va_arg(ap, int *);
+
+ statp = __res_state();
+ if ((statp->options & RES_INIT) == 0 && res_ninit(statp) == -1) {
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ *h_errnop = statp->res_h_errno;
+ return (NS_UNAVAIL);
+ }
+ if ((ned = __netent_data_init()) == NULL) {
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ *h_errnop = statp->res_h_errno;
+ return (NS_UNAVAIL);
+ }
+ if ((buf = malloc(sizeof(*buf))) == NULL) {
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ *h_errnop = statp->res_h_errno;
+ return (NS_NOTFOUND);
+ }
+
+ *((struct netent **)rval) = NULL;
+
+ strncpy(qbuf, net, sizeof(qbuf) - 1);
+ qbuf[sizeof(qbuf) - 1] = '\0';
+ anslen = res_nsearch(statp, qbuf, C_IN, T_PTR, (u_char *)buf,
+ sizeof(*buf));
+ if (anslen < 0) {
+ free(buf);
+#ifdef DEBUG
+ if (statp->options & RES_DEBUG)
+ printf("res_nsearch failed\n");
+#endif
+ return (NS_UNAVAIL);
+ } else if (anslen > sizeof(*buf)) {
+ free(buf);
+#ifdef DEBUG
+ if (statp->options & RES_DEBUG)
+ printf("res_search static buffer too small\n");
+#endif
+ return (NS_UNAVAIL);
+ }
+ error = getnetanswer(buf, anslen, BYNAME, &ne, ned, statp);
+ free(buf);
+ if (error != 0) {
+ *h_errnop = statp->res_h_errno;
+ return (NS_NOTFOUND);
+ }
+ if (__copy_netent(&ne, nptr, buffer, buflen) != 0) {
+ *errnop = errno;
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ *h_errnop = statp->res_h_errno;
+ return (NS_RETURN);
+ }
+ *((struct netent **)rval) = nptr;
+ return (NS_SUCCESS);
+}
+
+void
+_setnetdnsent(int stayopen)
+{
+ res_state statp;
+
+ statp = __res_state();
+ if ((statp->options & RES_INIT) == 0 && res_ninit(statp) == -1)
+ return;
+ if (stayopen)
+ statp->options |= RES_STAYOPEN | RES_USEVC;
+}
+
+void
+_endnetdnsent(void)
+{
+ res_state statp;
+
+ statp = __res_state();
+ statp->options &= ~(RES_STAYOPEN | RES_USEVC);
+ res_nclose(statp);
+}
diff --git a/lib/libc/net/getnetbyht.c b/lib/libc/net/getnetbyht.c
new file mode 100644
index 000000000000..bee00e807fe3
--- /dev/null
+++ b/lib/libc/net/getnetbyht.c
@@ -0,0 +1,288 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* Portions Copyright (c) 1993 Carlos Leandro and Rui Salgueiro
+ * Dep. Matematica Universidade de Coimbra, Portugal, Europe
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * from getnetent.c 1.1 (Coimbra) 93/06/02
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)getnetent.c 8.1 (Berkeley) 6/4/93";
+static char orig_rcsid[] = "From: Id: getnetent.c,v 8.4 1997/06/01 20:34:37 vixie Exp";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include <errno.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <nsswitch.h>
+#include "netdb_private.h"
+
+void
+_setnethtent(int f, struct netent_data *ned)
+{
+
+ if (ned->netf == NULL)
+ ned->netf = fopen(_PATH_NETWORKS, "re");
+ else
+ rewind(ned->netf);
+ ned->stayopen |= f;
+}
+
+void
+_endnethtent(struct netent_data *ned)
+{
+
+ if (ned->netf) {
+ fclose(ned->netf);
+ ned->netf = NULL;
+ }
+ ned->stayopen = 0;
+}
+
+static int
+getnetent_p(struct netent *ne, struct netent_data *ned)
+{
+ char *p, *bp, *ep;
+ char *cp, **q;
+ int len;
+ char line[BUFSIZ + 1];
+
+ if (ned->netf == NULL &&
+ (ned->netf = fopen(_PATH_NETWORKS, "re")) == NULL)
+ return (-1);
+again:
+ p = fgets(line, sizeof line, ned->netf);
+ if (p == NULL)
+ return (-1);
+ if (*p == '#')
+ goto again;
+ cp = strpbrk(p, "#\n");
+ if (cp != NULL)
+ *cp = '\0';
+ bp = ned->netbuf;
+ ep = ned->netbuf + sizeof ned->netbuf;
+ ne->n_name = bp;
+ cp = strpbrk(p, " \t");
+ if (cp == NULL)
+ goto again;
+ *cp++ = '\0';
+ len = strlen(p) + 1;
+ if (ep - bp < len) {
+ RES_SET_H_ERRNO(__res_state(), NO_RECOVERY);
+ return (-1);
+ }
+ strlcpy(bp, p, ep - bp);
+ bp += len;
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ p = strpbrk(cp, " \t");
+ if (p != NULL)
+ *p++ = '\0';
+ ne->n_net = inet_network(cp);
+ ne->n_addrtype = AF_INET;
+ q = ne->n_aliases = ned->net_aliases;
+ if (p != NULL) {
+ cp = p;
+ while (cp && *cp) {
+ if (*cp == ' ' || *cp == '\t') {
+ cp++;
+ continue;
+ }
+ if (q >= &ned->net_aliases[_MAXALIASES - 1])
+ break;
+ p = strpbrk(cp, " \t");
+ if (p != NULL)
+ *p++ = '\0';
+ len = strlen(cp) + 1;
+ if (ep - bp < len)
+ break;
+ strlcpy(bp, cp, ep - bp);
+ *q++ = bp;
+ bp += len;
+ cp = p;
+ }
+ }
+ *q = NULL;
+ return (0);
+}
+
+int
+getnetent_r(struct netent *nptr, char *buffer, size_t buflen,
+ struct netent **result, int *h_errnop)
+{
+ struct netent_data *ned;
+ struct netent ne;
+ res_state statp;
+
+ statp = __res_state();
+ if ((ned = __netent_data_init()) == NULL) {
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ *h_errnop = statp->res_h_errno;
+ return (-1);
+ }
+ if (getnetent_p(&ne, ned) != 0)
+ return (-1);
+ if (__copy_netent(&ne, nptr, buffer, buflen) != 0) {
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ *h_errnop = statp->res_h_errno;
+ return ((errno != 0) ? errno : -1);
+ }
+ *result = nptr;
+ return (0);
+}
+
+struct netent *
+getnetent(void)
+{
+ struct netdata *nd;
+ struct netent *rval;
+ int ret_h_errno;
+
+ if ((nd = __netdata_init()) == NULL)
+ return (NULL);
+ if (getnetent_r(&nd->net, nd->data, sizeof(nd->data), &rval,
+ &ret_h_errno) != 0)
+ return (NULL);
+ return (rval);
+}
+
+int
+_ht_getnetbyname(void *rval, void *cb_data, va_list ap)
+{
+ const char *name;
+ char *buffer;
+ size_t buflen;
+ int *errnop, *h_errnop;
+ struct netent *nptr, ne;
+ struct netent_data *ned;
+ char **cp;
+ res_state statp;
+ int error;
+
+ name = va_arg(ap, const char *);
+ nptr = va_arg(ap, struct netent *);
+ buffer = va_arg(ap, char *);
+ buflen = va_arg(ap, size_t);
+ errnop = va_arg(ap, int *);
+ h_errnop = va_arg(ap, int *);
+
+ statp = __res_state();
+ if ((ned = __netent_data_init()) == NULL) {
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ *h_errnop = statp->res_h_errno;
+ return (NS_UNAVAIL);
+ }
+
+ _setnethtent(ned->stayopen, ned);
+ while ((error = getnetent_p(&ne, ned)) == 0) {
+ if (strcasecmp(ne.n_name, name) == 0)
+ break;
+ for (cp = ne.n_aliases; *cp != 0; cp++)
+ if (strcasecmp(*cp, name) == 0)
+ goto found;
+ }
+found:
+ if (!ned->stayopen)
+ _endnethtent(ned);
+ if (error != 0) {
+ *h_errnop = statp->res_h_errno;
+ return (NS_NOTFOUND);
+ }
+ if (__copy_netent(&ne, nptr, buffer, buflen) != 0) {
+ *errnop = errno;
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ *h_errnop = statp->res_h_errno;
+ return (NS_RETURN);
+ }
+ *((struct netent **)rval) = nptr;
+ return (NS_SUCCESS);
+}
+
+int
+_ht_getnetbyaddr(void *rval, void *cb_data, va_list ap)
+{
+ uint32_t net;
+ int type;
+ char *buffer;
+ size_t buflen;
+ int *errnop, *h_errnop;
+ struct netent *nptr, ne;
+ struct netent_data *ned;
+ res_state statp;
+ int error;
+
+ net = va_arg(ap, uint32_t);
+ type = va_arg(ap, int);
+ nptr = va_arg(ap, struct netent *);
+ buffer = va_arg(ap, char *);
+ buflen = va_arg(ap, size_t);
+ errnop = va_arg(ap, int *);
+ h_errnop = va_arg(ap, int *);
+
+ statp = __res_state();
+ if ((ned = __netent_data_init()) == NULL) {
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ *h_errnop = statp->res_h_errno;
+ return (NS_UNAVAIL);
+ }
+
+ _setnethtent(ned->stayopen, ned);
+ while ((error = getnetent_p(&ne, ned)) == 0)
+ if (ne.n_addrtype == type && ne.n_net == net)
+ break;
+ if (!ned->stayopen)
+ _endnethtent(ned);
+ if (error != 0) {
+ *h_errnop = statp->res_h_errno;
+ return (NS_NOTFOUND);
+ }
+ if (__copy_netent(&ne, nptr, buffer, buflen) != 0) {
+ *errnop = errno;
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ *h_errnop = statp->res_h_errno;
+ return (NS_RETURN);
+ }
+ *((struct netent **)rval) = nptr;
+ return (NS_SUCCESS);
+}
diff --git a/lib/libc/net/getnetbynis.c b/lib/libc/net/getnetbynis.c
new file mode 100644
index 000000000000..1dbed83f1b26
--- /dev/null
+++ b/lib/libc/net/getnetbynis.c
@@ -0,0 +1,259 @@
+/*-
+ * Copyright (c) 1994, Garrett Wollman
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <stdarg.h>
+#include <nsswitch.h>
+#include <arpa/nameser.h>
+#ifdef YP
+#include <rpc/rpc.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+#endif
+#include "netdb_private.h"
+
+#ifdef YP
+static int
+_getnetbynis(const char *name, char *map, int af, struct netent *ne,
+ struct netent_data *ned)
+{
+ char *p, *bp, *ep;
+ char *cp, **q;
+ char *result;
+ int resultlen, len;
+ char ypbuf[YPMAXRECORD + 2];
+
+ switch(af) {
+ case AF_INET:
+ break;
+ default:
+ case AF_INET6:
+ errno = EAFNOSUPPORT;
+ return (-1);
+ }
+
+ if (ned->yp_domain == (char *)NULL)
+ if (yp_get_default_domain (&ned->yp_domain))
+ return (-1);
+
+ if (yp_match(ned->yp_domain, map, name, strlen(name), &result,
+ &resultlen))
+ return (-1);
+
+ bcopy((char *)result, (char *)&ypbuf, resultlen);
+ ypbuf[resultlen] = '\0';
+ free(result);
+ result = (char *)&ypbuf;
+
+ if ((cp = strchr(result, '\n')))
+ *cp = '\0';
+
+ cp = strpbrk(result, " \t");
+ *cp++ = '\0';
+ bp = ned->netbuf;
+ ep = ned->netbuf + sizeof ned->netbuf;
+ len = strlen(result) + 1;
+ if (ep - bp < len) {
+ RES_SET_H_ERRNO(__res_state(), NO_RECOVERY);
+ return (-1);
+ }
+ strlcpy(bp, result, ep - bp);
+ ne->n_name = bp;
+ bp += len;
+
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+
+ ne->n_net = inet_network(cp);
+ ne->n_addrtype = AF_INET;
+
+ q = ne->n_aliases = ned->net_aliases;
+ cp = strpbrk(cp, " \t");
+ if (cp != NULL)
+ *cp++ = '\0';
+ while (cp && *cp) {
+ if (*cp == ' ' || *cp == '\t') {
+ cp++;
+ continue;
+ }
+ if (q > &ned->net_aliases[_MAXALIASES - 1])
+ break;
+ p = strpbrk(cp, " \t");
+ if (p != NULL)
+ *p++ = '\0';
+ len = strlen(cp) + 1;
+ if (ep - bp < len)
+ break;
+ strlcpy(bp, cp, ep - bp);
+ *q++ = bp;
+ bp += len;
+ cp = p;
+ }
+ *q = NULL;
+ return (0);
+}
+#endif /* YP */
+
+int
+_nis_getnetbyname(void *rval, void *cb_data, va_list ap)
+{
+#ifdef YP
+ const char *name;
+ char *buffer;
+ size_t buflen;
+ int *errnop, *h_errnop;
+ struct netent *nptr, ne;
+ struct netent_data *ned;
+ res_state statp;
+
+ name = va_arg(ap, const char *);
+ nptr = va_arg(ap, struct netent *);
+ buffer = va_arg(ap, char *);
+ buflen = va_arg(ap, size_t);
+ errnop = va_arg(ap, int *);
+ h_errnop = va_arg(ap, int *);
+
+ statp = __res_state();
+ if ((ned = __netent_data_init()) == NULL) {
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ *h_errnop = statp->res_h_errno;
+ return (NS_UNAVAIL);
+ }
+
+ if (_getnetbynis(name, "networks.byname", AF_INET, &ne, ned) != 0) {
+ *h_errnop = statp->res_h_errno;
+ return (NS_NOTFOUND);
+ }
+ if (__copy_netent(&ne, nptr, buffer, buflen) != 0) {
+ *errnop = errno;
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ *h_errnop = statp->res_h_errno;
+ return (NS_RETURN);
+ }
+ *((struct netent **)rval) = nptr;
+ return (NS_SUCCESS);
+#else
+ return (NS_UNAVAIL);
+#endif
+
+}
+
+int
+_nis_getnetbyaddr(void *rval, void *cb_data, va_list ap)
+{
+#ifdef YP
+ uint32_t addr;
+ int af;
+ char *buffer;
+ size_t buflen;
+ int *errnop, *h_errnop;
+ struct netent *nptr, ne;
+ struct netent_data *ned;
+ char *str, *cp;
+ uint32_t net2;
+ int nn;
+ unsigned int netbr[4];
+ char buf[MAXDNAME];
+ res_state statp;
+
+ addr = va_arg(ap, uint32_t);
+ af = va_arg(ap, int);
+ nptr = va_arg(ap, struct netent *);
+ buffer = va_arg(ap, char *);
+ buflen = va_arg(ap, size_t);
+ errnop = va_arg(ap, int *);
+ h_errnop = va_arg(ap, int *);
+
+ statp = __res_state();
+ if ((ned = __netent_data_init()) == NULL) {
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ *h_errnop = statp->res_h_errno;
+ return (NS_UNAVAIL);
+ }
+
+ if (af != AF_INET) {
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ *h_errnop = statp->res_h_errno;
+ errno = EAFNOSUPPORT;
+ return (NS_UNAVAIL);
+ }
+
+ for (nn = 4, net2 = addr; net2; net2 >>= 8) {
+ netbr[--nn] = net2 & 0xff;
+ }
+
+ switch (nn) {
+ case 3: /* Class A */
+ sprintf(buf, "%u", netbr[3]);
+ break;
+ case 2: /* Class B */
+ sprintf(buf, "%u.%u", netbr[2], netbr[3]);
+ break;
+ case 1: /* Class C */
+ sprintf(buf, "%u.%u.%u", netbr[1], netbr[2], netbr[3]);
+ break;
+ case 0: /* Class D - E */
+ sprintf(buf, "%u.%u.%u.%u", netbr[0], netbr[1],
+ netbr[2], netbr[3]);
+ break;
+ }
+
+ str = (char *)&buf;
+ cp = str + (strlen(str) - 2);
+
+ while(!strcmp(cp, ".0")) {
+ *cp = '\0';
+ cp = str + (strlen(str) - 2);
+ }
+
+ if (_getnetbynis(str, "networks.byaddr", af, &ne, ned) != 0) {
+ *h_errnop = statp->res_h_errno;
+ return (NS_NOTFOUND);
+ }
+ if (__copy_netent(&ne, nptr, buffer, buflen) != 0) {
+ *errnop = errno;
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ *h_errnop = statp->res_h_errno;
+ return (NS_RETURN);
+ }
+ *((struct netent **)rval) = nptr;
+ return (NS_SUCCESS);
+#else
+ return (NS_UNAVAIL);
+#endif /* YP */
+}
diff --git a/lib/libc/net/getnetent.3 b/lib/libc/net/getnetent.3
new file mode 100644
index 000000000000..ec08b6b1f852
--- /dev/null
+++ b/lib/libc/net/getnetent.3
@@ -0,0 +1,170 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)getnetent.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt GETNETENT 3
+.Os
+.Sh NAME
+.Nm getnetent ,
+.Nm getnetbyaddr ,
+.Nm getnetbyname ,
+.Nm setnetent ,
+.Nm endnetent
+.Nd get network entry
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In netdb.h
+.Ft struct netent *
+.Fn getnetent void
+.Ft struct netent *
+.Fn getnetbyname "const char *name"
+.Ft struct netent *
+.Fn getnetbyaddr "uint32_t net" "int type"
+.Ft void
+.Fn setnetent "int stayopen"
+.Ft void
+.Fn endnetent void
+.Sh DESCRIPTION
+The
+.Fn getnetent ,
+.Fn getnetbyname ,
+and
+.Fn getnetbyaddr
+functions
+each return a pointer to an object with the
+following structure describing an internet network.
+This structure contains either the information obtained
+from the nameserver,
+.Xr named 8 ,
+broken-out fields of a line in the network data base
+.Pa /etc/networks ,
+or entries supplied by the
+.Xr yp 8
+system.
+The order of the lookups is controlled by the
+`networks' entry in
+.Xr nsswitch.conf 5 .
+.Bd -literal -offset indent
+struct netent {
+ char *n_name; /* official name of net */
+ char **n_aliases; /* alias list */
+ int n_addrtype; /* net number type */
+ uint32_t n_net; /* net number */
+};
+.Ed
+.Pp
+The members of this structure are:
+.Bl -tag -width n_addrtype
+.It Fa n_name
+The official name of the network.
+.It Fa n_aliases
+A zero terminated list of alternate names for the network.
+.It Fa n_addrtype
+The type of the network number returned; currently only AF_INET.
+.It Fa n_net
+The network number.
+Network numbers are returned in machine byte
+order.
+.El
+.Pp
+The
+.Fn getnetent
+function
+reads the next line of the file, opening the file if necessary.
+.Pp
+The
+.Fn setnetent
+function
+opens and rewinds the file.
+If the
+.Fa stayopen
+flag is non-zero,
+the net data base will not be closed after each call to
+.Fn getnetbyname
+or
+.Fn getnetbyaddr .
+.Pp
+The
+.Fn endnetent
+function
+closes the file.
+.Pp
+The
+.Fn getnetbyname
+function
+and
+.Fn getnetbyaddr
+sequentially search from the beginning
+of the file until a matching
+net name or
+net address and type is found,
+or until
+.Dv EOF
+is encountered.
+The
+.Fa type
+argument
+must be
+.Dv AF_INET .
+Network numbers are supplied in host order.
+.Sh FILES
+.Bl -tag -width /etc/nsswitch.conf -compact
+.It Pa /etc/networks
+.It Pa /etc/nsswitch.conf
+.It Pa /etc/resolv.conf
+.El
+.Sh DIAGNOSTICS
+Null pointer returned on
+.Dv EOF
+or error.
+.Sh SEE ALSO
+.Xr networks 5
+.Pp
+.%T RFC 1101
+.Sh HISTORY
+The
+.Fn getnetent ,
+.Fn getnetbyaddr ,
+.Fn getnetbyname ,
+.Fn setnetent ,
+and
+.Fn endnetent
+functions appeared in
+.Bx 4.2 .
+.Sh BUGS
+The data space used by
+these functions is thread-specific; if future use requires the data, it should be
+copied before any subsequent calls to these functions overwrite it.
+Only Internet network
+numbers are currently understood.
+Expecting network numbers to fit
+in no more than 32 bits is probably
+naive.
diff --git a/lib/libc/net/getnetnamadr.c b/lib/libc/net/getnetnamadr.c
new file mode 100644
index 000000000000..e08f8915b457
--- /dev/null
+++ b/lib/libc/net/getnetnamadr.c
@@ -0,0 +1,451 @@
+/*-
+ * Copyright (c) 1994, Garrett Wollman
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include "reentrant.h"
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <nsswitch.h>
+#include "un-namespace.h"
+#include "netdb_private.h"
+#ifdef NS_CACHING
+#include "nscache.h"
+#endif
+
+/* Network lookup order if nsswitch.conf is broken or nonexistent */
+static const ns_src default_src[] = {
+ { NSSRC_FILES, NS_SUCCESS },
+ { NSSRC_DNS, NS_SUCCESS },
+ { 0 }
+};
+
+NETDB_THREAD_ALLOC(netent_data)
+NETDB_THREAD_ALLOC(netdata)
+
+#ifdef NS_CACHING
+static int
+net_id_func(char *buffer, size_t *buffer_size, va_list ap, void *cache_mdata)
+{
+ char *name;
+ uint32_t net;
+ int type;
+
+ size_t desired_size, size;
+ enum nss_lookup_type lookup_type;
+ int res = NS_UNAVAIL;
+
+ lookup_type = (enum nss_lookup_type)cache_mdata;
+ switch (lookup_type) {
+ case nss_lt_name:
+ name = va_arg(ap, char *);
+
+ size = strlen(name);
+ desired_size = sizeof(enum nss_lookup_type) + size + 1;
+ if (desired_size > *buffer_size) {
+ res = NS_RETURN;
+ goto fin;
+ }
+
+ memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type));
+ memcpy(buffer + sizeof(enum nss_lookup_type), name, size + 1);
+
+ res = NS_SUCCESS;
+ break;
+ case nss_lt_id:
+ net = va_arg(ap, uint32_t);
+ type = va_arg(ap, int);
+
+ desired_size = sizeof(enum nss_lookup_type) +
+ sizeof(uint32_t) + sizeof(int);
+ if (desired_size > *buffer_size) {
+ res = NS_RETURN;
+ goto fin;
+ }
+
+ memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type));
+ memcpy(buffer + sizeof(enum nss_lookup_type), &net,
+ sizeof(uint32_t));
+ memcpy(buffer + sizeof(enum nss_lookup_type) + sizeof(uint32_t),
+ &type, sizeof(int));
+
+ res = NS_SUCCESS;
+ break;
+ default:
+ /* should be unreachable */
+ return (NS_UNAVAIL);
+ }
+
+fin:
+ *buffer_size = desired_size;
+ return (res);
+}
+
+
+static int
+net_marshal_func(char *buffer, size_t *buffer_size, void *retval, va_list ap,
+ void *cache_mdata)
+{
+ char *name;
+ uint32_t net;
+ int type;
+ struct netent *ne;
+ char *orig_buf;
+ size_t orig_buf_size;
+
+ struct netent new_ne;
+ size_t desired_size, size, aliases_size;
+ char *p;
+ char **alias;
+
+ switch ((enum nss_lookup_type)cache_mdata) {
+ case nss_lt_name:
+ name = va_arg(ap, char *);
+ break;
+ case nss_lt_id:
+ net = va_arg(ap, uint32_t);
+ type = va_arg(ap, int);
+ break;
+ case nss_lt_all:
+ break;
+ default:
+ /* should be unreachable */
+ return (NS_UNAVAIL);
+ }
+
+ ne = va_arg(ap, struct netent *);
+ orig_buf = va_arg(ap, char *);
+ orig_buf_size = va_arg(ap, size_t);
+
+ desired_size = _ALIGNBYTES + sizeof(struct netent) + sizeof(char *);
+ if (ne->n_name != NULL)
+ desired_size += strlen(ne->n_name) + 1;
+
+ if (ne->n_aliases != NULL) {
+ aliases_size = 0;
+ for (alias = ne->n_aliases; *alias; ++alias) {
+ desired_size += strlen(*alias) + 1;
+ ++aliases_size;
+ }
+
+ desired_size += _ALIGNBYTES +
+ (aliases_size + 1) * sizeof(char *);
+ }
+
+ if (*buffer_size < desired_size) {
+ /* this assignment is here for future use */
+ *buffer_size = desired_size;
+ return (NS_RETURN);
+ }
+
+ memcpy(&new_ne, ne, sizeof(struct netent));
+
+ *buffer_size = desired_size;
+ memset(buffer, 0, desired_size);
+ p = buffer + sizeof(struct netent) + sizeof(char *);
+ memcpy(buffer + sizeof(struct netent), &p, sizeof(char *));
+ p = (char *)_ALIGN(p);
+
+ if (new_ne.n_name != NULL) {
+ size = strlen(new_ne.n_name);
+ memcpy(p, new_ne.n_name, size);
+ new_ne.n_name = p;
+ p += size + 1;
+ }
+
+ if (new_ne.n_aliases != NULL) {
+ p = (char *)_ALIGN(p);
+ memcpy(p, new_ne.n_aliases, sizeof(char *) * aliases_size);
+ new_ne.n_aliases = (char **)p;
+ p += sizeof(char *) * (aliases_size + 1);
+
+ for (alias = new_ne.n_aliases; *alias; ++alias) {
+ size = strlen(*alias);
+ memcpy(p, *alias, size);
+ *alias = p;
+ p += size + 1;
+ }
+ }
+
+ memcpy(buffer, &new_ne, sizeof(struct netent));
+ return (NS_SUCCESS);
+}
+
+static int
+net_unmarshal_func(char *buffer, size_t buffer_size, void *retval, va_list ap,
+ void *cache_mdata)
+{
+ char *name;
+ uint32_t net;
+ int type;
+ struct netent *ne;
+ char *orig_buf;
+ size_t orig_buf_size;
+ int *ret_errno;
+
+ char *p;
+ char **alias;
+
+ switch ((enum nss_lookup_type)cache_mdata) {
+ case nss_lt_name:
+ name = va_arg(ap, char *);
+ break;
+ case nss_lt_id:
+ net = va_arg(ap, uint32_t);
+ type = va_arg(ap, int);
+ break;
+ case nss_lt_all:
+ break;
+ default:
+ /* should be unreachable */
+ return (NS_UNAVAIL);
+ }
+
+ ne = va_arg(ap, struct netent *);
+ orig_buf = va_arg(ap, char *);
+ orig_buf_size = va_arg(ap, size_t);
+ ret_errno = va_arg(ap, int *);
+
+ if (orig_buf_size <
+ buffer_size - sizeof(struct netent) - sizeof(char *)) {
+ *ret_errno = ERANGE;
+ return (NS_RETURN);
+ }
+
+ memcpy(ne, buffer, sizeof(struct netent));
+ memcpy(&p, buffer + sizeof(struct netent), sizeof(char *));
+
+ orig_buf = (char *)_ALIGN(orig_buf);
+ memcpy(orig_buf, buffer + sizeof(struct netent) + sizeof(char *) +
+ _ALIGN(p) - (size_t)p,
+ buffer_size - sizeof(struct netent) - sizeof(char *) -
+ _ALIGN(p) + (size_t)p);
+ p = (char *)_ALIGN(p);
+
+ NS_APPLY_OFFSET(ne->n_name, orig_buf, p, char *);
+ if (ne->n_aliases != NULL) {
+ NS_APPLY_OFFSET(ne->n_aliases, orig_buf, p, char **);
+
+ for (alias = ne->n_aliases; *alias; ++alias)
+ NS_APPLY_OFFSET(*alias, orig_buf, p, char *);
+ }
+
+ if (retval != NULL)
+ *((struct netent **)retval) = ne;
+
+ return (NS_SUCCESS);
+}
+#endif /* NS_CACHING */
+
+static void
+netent_data_free(void *ptr)
+{
+ struct netent_data *ned = ptr;
+
+ if (ned == NULL)
+ return;
+ ned->stayopen = 0;
+ _endnethtent(ned);
+ free(ned);
+}
+
+static void
+netdata_free(void *ptr)
+{
+ free(ptr);
+}
+
+int
+__copy_netent(struct netent *ne, struct netent *nptr, char *buf, size_t buflen)
+{
+ char *cp;
+ int i, n;
+ int numptr, len;
+
+ /* Find out the amount of space required to store the answer. */
+ numptr = 1; /* NULL ptr */
+ len = (char *)ALIGN(buf) - buf;
+ for (i = 0; ne->n_aliases[i]; i++, numptr++) {
+ len += strlen(ne->n_aliases[i]) + 1;
+ }
+ len += strlen(ne->n_name) + 1;
+ len += numptr * sizeof(char*);
+
+ if (len > (int)buflen) {
+ errno = ERANGE;
+ return (-1);
+ }
+
+ /* copy net value and type */
+ nptr->n_addrtype = ne->n_addrtype;
+ nptr->n_net = ne->n_net;
+
+ cp = (char *)ALIGN(buf) + numptr * sizeof(char *);
+
+ /* copy official name */
+ n = strlen(ne->n_name) + 1;
+ strcpy(cp, ne->n_name);
+ nptr->n_name = cp;
+ cp += n;
+
+ /* copy aliases */
+ nptr->n_aliases = (char **)ALIGN(buf);
+ for (i = 0 ; ne->n_aliases[i]; i++) {
+ n = strlen(ne->n_aliases[i]) + 1;
+ strcpy(cp, ne->n_aliases[i]);
+ nptr->n_aliases[i] = cp;
+ cp += n;
+ }
+ nptr->n_aliases[i] = NULL;
+
+ return (0);
+}
+
+int
+getnetbyname_r(const char *name, struct netent *ne, char *buffer,
+ size_t buflen, struct netent **result, int *h_errorp)
+{
+#ifdef NS_CACHING
+ static const nss_cache_info cache_info =
+ NS_COMMON_CACHE_INFO_INITIALIZER(
+ networks, (void *)nss_lt_name,
+ net_id_func, net_marshal_func, net_unmarshal_func);
+#endif
+ static const ns_dtab dtab[] = {
+ NS_FILES_CB(_ht_getnetbyname, NULL)
+ { NSSRC_DNS, _dns_getnetbyname, NULL },
+ NS_NIS_CB(_nis_getnetbyname, NULL) /* force -DHESIOD */
+#ifdef NS_CACHING
+ NS_CACHE_CB(&cache_info)
+#endif
+ { 0 }
+ };
+ int rval, ret_errno = 0;
+
+ rval = _nsdispatch((void *)result, dtab, NSDB_NETWORKS,
+ "getnetbyname_r", default_src, name, ne, buffer, buflen,
+ &ret_errno, h_errorp);
+
+ if (rval != NS_SUCCESS) {
+ errno = ret_errno;
+ return ((ret_errno != 0) ? ret_errno : -1);
+ }
+ return (0);
+}
+
+int
+getnetbyaddr_r(uint32_t addr, int af, struct netent *ne, char *buffer,
+ size_t buflen, struct netent **result, int *h_errorp)
+{
+#ifdef NS_CACHING
+ static const nss_cache_info cache_info =
+ NS_COMMON_CACHE_INFO_INITIALIZER(
+ networks, (void *)nss_lt_id,
+ net_id_func, net_marshal_func, net_unmarshal_func);
+#endif
+ static const ns_dtab dtab[] = {
+ NS_FILES_CB(_ht_getnetbyaddr, NULL)
+ { NSSRC_DNS, _dns_getnetbyaddr, NULL },
+ NS_NIS_CB(_nis_getnetbyaddr, NULL) /* force -DHESIOD */
+#ifdef NS_CACHING
+ NS_CACHE_CB(&cache_info)
+#endif
+ { 0 }
+ };
+ int rval, ret_errno = 0;
+
+ rval = _nsdispatch((void *)result, dtab, NSDB_NETWORKS,
+ "getnetbyaddr_r", default_src, addr, af, ne, buffer, buflen,
+ &ret_errno, h_errorp);
+
+ if (rval != NS_SUCCESS) {
+ errno = ret_errno;
+ return ((ret_errno != 0) ? ret_errno : -1);
+ }
+ return (0);
+}
+
+struct netent *
+getnetbyname(const char *name)
+{
+ struct netdata *nd;
+ struct netent *rval;
+ int ret_h_errno;
+
+ if ((nd = __netdata_init()) == NULL)
+ return (NULL);
+ if (getnetbyname_r(name, &nd->net, nd->data, sizeof(nd->data), &rval,
+ &ret_h_errno) != 0)
+ return (NULL);
+ return (rval);
+}
+
+struct netent *
+getnetbyaddr(uint32_t addr, int af)
+{
+ struct netdata *nd;
+ struct netent *rval;
+ int ret_h_errno;
+
+ if ((nd = __netdata_init()) == NULL)
+ return (NULL);
+ if (getnetbyaddr_r(addr, af, &nd->net, nd->data, sizeof(nd->data),
+ &rval, &ret_h_errno) != 0)
+ return (NULL);
+ return (rval);
+}
+
+void
+setnetent(int stayopen)
+{
+ struct netent_data *ned;
+
+ if ((ned = __netent_data_init()) == NULL)
+ return;
+ _setnethtent(stayopen, ned);
+ _setnetdnsent(stayopen);
+}
+
+void
+endnetent(void)
+{
+ struct netent_data *ned;
+
+ if ((ned = __netent_data_init()) == NULL)
+ return;
+ _endnethtent(ned);
+ _endnetdnsent();
+}
diff --git a/lib/libc/net/getproto.c b/lib/libc/net/getproto.c
new file mode 100644
index 000000000000..36eeb90a8a32
--- /dev/null
+++ b/lib/libc/net/getproto.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)getproto.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <netdb.h>
+#include <nsswitch.h>
+#include "netdb_private.h"
+#ifdef NS_CACHING
+#include "nscache.h"
+#endif
+#include "nss_tls.h"
+
+static const ns_src defaultsrc[] = {
+ { NSSRC_FILES, NS_SUCCESS },
+ { NULL, 0 }
+};
+
+static int
+files_getprotobynumber(void *retval, void *mdata, va_list ap)
+{
+ struct protoent pe;
+ struct protoent_data *ped;
+ int error;
+
+ int number;
+ struct protoent *pptr;
+ char *buffer;
+ size_t buflen;
+ int *errnop;
+
+ number = va_arg(ap, int);
+ pptr = va_arg(ap, struct protoent *);
+ buffer = va_arg(ap, char *);
+ buflen = va_arg(ap, size_t);
+ errnop = va_arg(ap, int *);
+
+ if ((ped = __protoent_data_init()) == NULL) {
+ *errnop = errno;
+ return (NS_NOTFOUND);
+ }
+
+ __setprotoent_p(ped->stayopen, ped);
+ while ((error = __getprotoent_p(&pe, ped)) == 0)
+ if (pe.p_proto == number)
+ break;
+ if (!ped->stayopen)
+ __endprotoent_p(ped);
+ if (error != 0) {
+ *errnop = errno;
+ return (NS_NOTFOUND);
+ }
+ if (__copy_protoent(&pe, pptr, buffer, buflen) != 0) {
+ *errnop = errno;
+ return (NS_RETURN);
+ }
+
+ *((struct protoent **)retval) = pptr;
+ return (NS_SUCCESS);
+}
+
+int
+getprotobynumber_r(int proto, struct protoent *pptr, char *buffer,
+ size_t buflen, struct protoent **result)
+{
+#ifdef NS_CACHING
+ static const nss_cache_info cache_info =
+ NS_COMMON_CACHE_INFO_INITIALIZER(
+ protocols, (void *)nss_lt_id,
+ __proto_id_func, __proto_marshal_func, __proto_unmarshal_func);
+#endif
+
+ static const ns_dtab dtab[] = {
+ { NSSRC_FILES, files_getprotobynumber, NULL },
+#ifdef NS_CACHING
+ NS_CACHE_CB(&cache_info)
+#endif
+ { NULL, NULL, NULL }
+ };
+ int rv, ret_errno;
+
+ ret_errno = 0;
+ *result = NULL;
+ rv = nsdispatch(result, dtab, NSDB_PROTOCOLS, "getprotobynumber_r",
+ defaultsrc, proto, pptr, buffer, buflen, &ret_errno);
+
+ if (rv != NS_SUCCESS) {
+ errno = ret_errno;
+ return (ret_errno);
+ }
+ return (0);
+}
+
+struct protoent *
+getprotobynumber(int proto)
+{
+ struct protodata *pd;
+ struct protoent *rval;
+
+ if ((pd = __protodata_init()) == NULL)
+ return (NULL);
+ if (getprotobynumber_r(proto, &pd->proto, pd->data, sizeof(pd->data),
+ &rval) != 0)
+ return (NULL);
+ return (rval);
+}
diff --git a/lib/libc/net/getprotoent.3 b/lib/libc/net/getprotoent.3
new file mode 100644
index 000000000000..565e038fa252
--- /dev/null
+++ b/lib/libc/net/getprotoent.3
@@ -0,0 +1,144 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)getprotoent.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt GETPROTOENT 3
+.Os
+.Sh NAME
+.Nm getprotoent ,
+.Nm getprotobynumber ,
+.Nm getprotobyname ,
+.Nm setprotoent ,
+.Nm endprotoent
+.Nd get protocol entry
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In netdb.h
+.Ft struct protoent *
+.Fn getprotoent void
+.Ft struct protoent *
+.Fn getprotobyname "const char *name"
+.Ft struct protoent *
+.Fn getprotobynumber "int proto"
+.Ft void
+.Fn setprotoent "int stayopen"
+.Ft void
+.Fn endprotoent void
+.Sh DESCRIPTION
+The
+.Fn getprotoent ,
+.Fn getprotobyname ,
+and
+.Fn getprotobynumber
+functions
+each return a pointer to an object with the
+following structure
+containing the broken-out
+fields of a line in the network protocol data base,
+.Pa /etc/protocols .
+.Bd -literal -offset indent
+struct protoent {
+ char *p_name; /* official name of protocol */
+ char **p_aliases; /* alias list */
+ int p_proto; /* protocol number */
+};
+.Ed
+.Pp
+The members of this structure are:
+.Bl -tag -width p_aliases
+.It Fa p_name
+The official name of the protocol.
+.It Fa p_aliases
+A zero terminated list of alternate names for the protocol.
+.It Fa p_proto
+The protocol number.
+.El
+.Pp
+The
+.Fn getprotoent
+function
+reads the next line of the file, opening the file if necessary.
+.Pp
+The
+.Fn setprotoent
+function
+opens and rewinds the file.
+If the
+.Fa stayopen
+flag is non-zero,
+the net data base will not be closed after each call to
+.Fn getprotobyname
+or
+.Fn getprotobynumber .
+.Pp
+The
+.Fn endprotoent
+function
+closes the file.
+.Pp
+The
+.Fn getprotobyname
+function
+and
+.Fn getprotobynumber
+sequentially search from the beginning
+of the file until a matching
+protocol name or
+protocol number is found,
+or until
+.Dv EOF
+is encountered.
+.Sh RETURN VALUES
+Null pointer returned on
+.Dv EOF
+or error.
+.Sh FILES
+.Bl -tag -width /etc/protocols -compact
+.It Pa /etc/protocols
+.El
+.Sh SEE ALSO
+.Xr protocols 5
+.Sh HISTORY
+The
+.Fn getprotoent ,
+.Fn getprotobynumber ,
+.Fn getprotobyname ,
+.Fn setprotoent ,
+and
+.Fn endprotoent
+functions appeared in
+.Bx 4.2 .
+.Sh BUGS
+These functions use a thread-specific data space;
+if the data is needed for future use, it should be
+copied before any subsequent calls overwrite it.
+Only the Internet
+protocols are currently understood.
diff --git a/lib/libc/net/getprotoent.c b/lib/libc/net/getprotoent.c
new file mode 100644
index 000000000000..41ff89687f1e
--- /dev/null
+++ b/lib/libc/net/getprotoent.c
@@ -0,0 +1,553 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)getprotoent.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <limits.h>
+#include <netdb.h>
+#include <nsswitch.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "namespace.h"
+#include "reentrant.h"
+#include "un-namespace.h"
+#include "netdb_private.h"
+#ifdef NS_CACHING
+#include "nscache.h"
+#endif
+#include "nss_tls.h"
+
+static const ns_src defaultsrc[] = {
+ { NSSRC_FILES, NS_SUCCESS },
+ { NULL, 0 }
+};
+
+NETDB_THREAD_ALLOC(protoent_data)
+NETDB_THREAD_ALLOC(protodata)
+
+static void
+protoent_data_clear(struct protoent_data *ped)
+{
+ if (ped->fp) {
+ fclose(ped->fp);
+ ped->fp = NULL;
+ }
+}
+
+static void
+protoent_data_free(void *ptr)
+{
+ struct protoent_data *ped = ptr;
+
+ protoent_data_clear(ped);
+ free(ped);
+}
+
+static void
+protodata_free(void *ptr)
+{
+ free(ptr);
+}
+
+#ifdef NS_CACHING
+int
+__proto_id_func(char *buffer, size_t *buffer_size, va_list ap,
+ void *cache_mdata)
+{
+ char *name;
+ int proto;
+
+ size_t desired_size, size;
+ enum nss_lookup_type lookup_type;
+ int res = NS_UNAVAIL;
+
+ lookup_type = (enum nss_lookup_type)cache_mdata;
+ switch (lookup_type) {
+ case nss_lt_name:
+ name = va_arg(ap, char *);
+
+ size = strlen(name);
+ desired_size = sizeof(enum nss_lookup_type) + size + 1;
+ if (desired_size > *buffer_size) {
+ res = NS_RETURN;
+ goto fin;
+ }
+
+ memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type));
+ memcpy(buffer + sizeof(enum nss_lookup_type), name, size + 1);
+
+ res = NS_SUCCESS;
+ break;
+ case nss_lt_id:
+ proto = va_arg(ap, int);
+
+ desired_size = sizeof(enum nss_lookup_type) + sizeof(int);
+ if (desired_size > *buffer_size) {
+ res = NS_RETURN;
+ goto fin;
+ }
+
+ memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type));
+ memcpy(buffer + sizeof(enum nss_lookup_type), &proto,
+ sizeof(int));
+
+ res = NS_SUCCESS;
+ break;
+ default:
+ /* should be unreachable */
+ return (NS_UNAVAIL);
+ }
+
+fin:
+ *buffer_size = desired_size;
+ return (res);
+}
+
+
+int
+__proto_marshal_func(char *buffer, size_t *buffer_size, void *retval,
+ va_list ap, void *cache_mdata)
+{
+ char *name;
+ int num;
+ struct protoent *proto;
+ char *orig_buf;
+ size_t orig_buf_size;
+
+ struct protoent new_proto;
+ size_t desired_size, size, aliases_size;
+ char *p;
+ char **alias;
+
+ switch ((enum nss_lookup_type)cache_mdata) {
+ case nss_lt_name:
+ name = va_arg(ap, char *);
+ break;
+ case nss_lt_id:
+ num = va_arg(ap, int);
+ break;
+ case nss_lt_all:
+ break;
+ default:
+ /* should be unreachable */
+ return (NS_UNAVAIL);
+ }
+
+ proto = va_arg(ap, struct protoent *);
+ orig_buf = va_arg(ap, char *);
+ orig_buf_size = va_arg(ap, size_t);
+
+ desired_size = _ALIGNBYTES + sizeof(struct protoent) + sizeof(char *);
+ if (proto->p_name != NULL)
+ desired_size += strlen(proto->p_name) + 1;
+
+ if (proto->p_aliases != NULL) {
+ aliases_size = 0;
+ for (alias = proto->p_aliases; *alias; ++alias) {
+ desired_size += strlen(*alias) + 1;
+ ++aliases_size;
+ }
+
+ desired_size += _ALIGNBYTES + (aliases_size + 1) *
+ sizeof(char *);
+ }
+
+ if (*buffer_size < desired_size) {
+ /* this assignment is here for future use */
+ *buffer_size = desired_size;
+ return (NS_RETURN);
+ }
+
+ memcpy(&new_proto, proto, sizeof(struct protoent));
+
+ *buffer_size = desired_size;
+ memset(buffer, 0, desired_size);
+ p = buffer + sizeof(struct protoent) + sizeof(char *);
+ memcpy(buffer + sizeof(struct protoent), &p, sizeof(char *));
+ p = (char *)_ALIGN(p);
+
+ if (new_proto.p_name != NULL) {
+ size = strlen(new_proto.p_name);
+ memcpy(p, new_proto.p_name, size);
+ new_proto.p_name = p;
+ p += size + 1;
+ }
+
+ if (new_proto.p_aliases != NULL) {
+ p = (char *)_ALIGN(p);
+ memcpy(p, new_proto.p_aliases, sizeof(char *) * aliases_size);
+ new_proto.p_aliases = (char **)p;
+ p += sizeof(char *) * (aliases_size + 1);
+
+ for (alias = new_proto.p_aliases; *alias; ++alias) {
+ size = strlen(*alias);
+ memcpy(p, *alias, size);
+ *alias = p;
+ p += size + 1;
+ }
+ }
+
+ memcpy(buffer, &new_proto, sizeof(struct protoent));
+ return (NS_SUCCESS);
+}
+
+int
+__proto_unmarshal_func(char *buffer, size_t buffer_size, void *retval,
+ va_list ap, void *cache_mdata)
+{
+ char *name;
+ int num;
+ struct protoent *proto;
+ char *orig_buf;
+ size_t orig_buf_size;
+ int *ret_errno;
+
+ char *p;
+ char **alias;
+
+ switch ((enum nss_lookup_type)cache_mdata) {
+ case nss_lt_name:
+ name = va_arg(ap, char *);
+ break;
+ case nss_lt_id:
+ num = va_arg(ap, int);
+ break;
+ case nss_lt_all:
+ break;
+ default:
+ /* should be unreachable */
+ return (NS_UNAVAIL);
+ }
+
+ proto = va_arg(ap, struct protoent *);
+ orig_buf = va_arg(ap, char *);
+ orig_buf_size = va_arg(ap, size_t);
+ ret_errno = va_arg(ap, int *);
+
+ if (orig_buf_size <
+ buffer_size - sizeof(struct protoent) - sizeof(char *)) {
+ *ret_errno = ERANGE;
+ return (NS_RETURN);
+ }
+
+ memcpy(proto, buffer, sizeof(struct protoent));
+ memcpy(&p, buffer + sizeof(struct protoent), sizeof(char *));
+
+ orig_buf = (char *)_ALIGN(orig_buf);
+ memcpy(orig_buf, buffer + sizeof(struct protoent) + sizeof(char *) +
+ _ALIGN(p) - (size_t)p,
+ buffer_size - sizeof(struct protoent) - sizeof(char *) -
+ _ALIGN(p) + (size_t)p);
+ p = (char *)_ALIGN(p);
+
+ NS_APPLY_OFFSET(proto->p_name, orig_buf, p, char *);
+ if (proto->p_aliases != NULL) {
+ NS_APPLY_OFFSET(proto->p_aliases, orig_buf, p, char **);
+
+ for (alias = proto->p_aliases; *alias; ++alias)
+ NS_APPLY_OFFSET(*alias, orig_buf, p, char *);
+ }
+
+ if (retval != NULL)
+ *((struct protoent **)retval) = proto;
+
+ return (NS_SUCCESS);
+}
+
+NSS_MP_CACHE_HANDLING(protocols);
+#endif /* NS_CACHING */
+
+int
+__copy_protoent(struct protoent *pe, struct protoent *pptr, char *buf,
+ size_t buflen)
+{
+ char *cp;
+ int i, n;
+ int numptr, len;
+
+ /* Find out the amount of space required to store the answer. */
+ numptr = 1; /* NULL ptr */
+ len = (char *)ALIGN(buf) - buf;
+ for (i = 0; pe->p_aliases[i]; i++, numptr++) {
+ len += strlen(pe->p_aliases[i]) + 1;
+ }
+ len += strlen(pe->p_name) + 1;
+ len += numptr * sizeof(char*);
+
+ if (len > (int)buflen) {
+ errno = ERANGE;
+ return (-1);
+ }
+
+ /* copy protocol value*/
+ pptr->p_proto = pe->p_proto;
+
+ cp = (char *)ALIGN(buf) + numptr * sizeof(char *);
+
+ /* copy official name */
+ n = strlen(pe->p_name) + 1;
+ strcpy(cp, pe->p_name);
+ pptr->p_name = cp;
+ cp += n;
+
+ /* copy aliases */
+ pptr->p_aliases = (char **)ALIGN(buf);
+ for (i = 0 ; pe->p_aliases[i]; i++) {
+ n = strlen(pe->p_aliases[i]) + 1;
+ strcpy(cp, pe->p_aliases[i]);
+ pptr->p_aliases[i] = cp;
+ cp += n;
+ }
+ pptr->p_aliases[i] = NULL;
+
+ return (0);
+}
+
+void
+__setprotoent_p(int f, struct protoent_data *ped)
+{
+ if (ped->fp == NULL)
+ ped->fp = fopen(_PATH_PROTOCOLS, "re");
+ else
+ rewind(ped->fp);
+ ped->stayopen |= f;
+}
+
+void
+__endprotoent_p(struct protoent_data *ped)
+{
+ if (ped->fp) {
+ fclose(ped->fp);
+ ped->fp = NULL;
+ }
+ ped->stayopen = 0;
+}
+
+int
+__getprotoent_p(struct protoent *pe, struct protoent_data *ped)
+{
+ char *p;
+ char *cp, **q, *endp;
+ long l;
+
+ if (ped->fp == NULL && (ped->fp = fopen(_PATH_PROTOCOLS, "re")) == NULL)
+ return (-1);
+again:
+ if ((p = fgets(ped->line, sizeof ped->line, ped->fp)) == NULL)
+ return (-1);
+ if (*p == '#')
+ goto again;
+ cp = strpbrk(p, "#\n");
+ if (cp != NULL)
+ *cp = '\0';
+ pe->p_name = p;
+ cp = strpbrk(p, " \t");
+ if (cp == NULL)
+ goto again;
+ *cp++ = '\0';
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ p = strpbrk(cp, " \t");
+ if (p != NULL)
+ *p++ = '\0';
+ l = strtol(cp, &endp, 10);
+ if (endp == cp || *endp != '\0' || l < 0 || l > USHRT_MAX)
+ goto again;
+ pe->p_proto = l;
+ q = pe->p_aliases = ped->aliases;
+ if (p != NULL) {
+ cp = p;
+ while (cp && *cp) {
+ if (*cp == ' ' || *cp == '\t') {
+ cp++;
+ continue;
+ }
+ if (q < &ped->aliases[_MAXALIASES - 1])
+ *q++ = cp;
+ cp = strpbrk(cp, " \t");
+ if (cp != NULL)
+ *cp++ = '\0';
+ }
+ }
+ *q = NULL;
+ return (0);
+}
+
+static int
+files_getprotoent_r(void *retval, void *mdata, va_list ap)
+{
+ struct protoent pe;
+ struct protoent_data *ped;
+
+ struct protoent *pptr;
+ char *buffer;
+ size_t buflen;
+ int *errnop;
+
+ pptr = va_arg(ap, struct protoent *);
+ buffer = va_arg(ap, char *);
+ buflen = va_arg(ap, size_t);
+ errnop = va_arg(ap, int *);
+
+ if ((ped = __protoent_data_init()) == NULL) {
+ *errnop = errno;
+ return (NS_NOTFOUND);
+ }
+
+ if (__getprotoent_p(&pe, ped) != 0) {
+ *errnop = errno;
+ return (NS_NOTFOUND);
+ }
+
+ if (__copy_protoent(&pe, pptr, buffer, buflen) != 0) {
+ *errnop = errno;
+ return (NS_RETURN);
+ }
+
+ *((struct protoent **)retval) = pptr;
+ return (NS_SUCCESS);
+}
+
+static int
+files_setprotoent(void *retval, void *mdata, va_list ap)
+{
+ struct protoent_data *ped;
+ int f;
+
+ f = va_arg(ap, int);
+ if ((ped = __protoent_data_init()) == NULL)
+ return (NS_UNAVAIL);
+
+ __setprotoent_p(f, ped);
+ return (NS_UNAVAIL);
+}
+
+static int
+files_endprotoent(void *retval, void *mdata, va_list ap)
+{
+ struct protoent_data *ped;
+
+ if ((ped = __protoent_data_init()) == NULL)
+ return (NS_UNAVAIL);
+
+ __endprotoent_p(ped);
+ return (NS_UNAVAIL);
+}
+
+int
+getprotoent_r(struct protoent *pptr, char *buffer, size_t buflen,
+ struct protoent **result)
+{
+#ifdef NS_CACHING
+ static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
+ protocols, (void *)nss_lt_all,
+ __proto_marshal_func, __proto_unmarshal_func);
+#endif
+ static const ns_dtab dtab[] = {
+ { NSSRC_FILES, files_getprotoent_r, (void *)nss_lt_all },
+#ifdef NS_CACHING
+ NS_CACHE_CB(&cache_info)
+#endif
+ { NULL, NULL, NULL }
+ };
+ int rv, ret_errno;
+
+ ret_errno = 0;
+ *result = NULL;
+ rv = nsdispatch(result, dtab, NSDB_PROTOCOLS, "getprotoent_r",
+ defaultsrc, pptr, buffer, buflen, &ret_errno);
+
+ if (rv != NS_SUCCESS) {
+ errno = ret_errno;
+ return (ret_errno);
+ }
+ return (0);
+}
+
+void
+setprotoent(int stayopen)
+{
+#ifdef NS_CACHING
+ static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
+ protocols, (void *)nss_lt_all,
+ NULL, NULL);
+#endif
+
+ static const ns_dtab dtab[] = {
+ { NSSRC_FILES, files_setprotoent, NULL },
+#ifdef NS_CACHING
+ NS_CACHE_CB(&cache_info)
+#endif
+ { NULL, NULL, NULL }
+ };
+
+ (void)nsdispatch(NULL, dtab, NSDB_PROTOCOLS, "setprotoent", defaultsrc,
+ stayopen);
+}
+
+void
+endprotoent(void)
+{
+#ifdef NS_CACHING
+ static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
+ protocols, (void *)nss_lt_all,
+ NULL, NULL);
+#endif
+
+ static const ns_dtab dtab[] = {
+ { NSSRC_FILES, files_endprotoent, NULL },
+#ifdef NS_CACHING
+ NS_CACHE_CB(&cache_info)
+#endif
+ { NULL, NULL, NULL }
+ };
+
+ (void)nsdispatch(NULL, dtab, NSDB_PROTOCOLS, "endprotoent", defaultsrc);
+}
+
+struct protoent *
+getprotoent(void)
+{
+ struct protodata *pd;
+ struct protoent *rval;
+
+ if ((pd = __protodata_init()) == NULL)
+ return (NULL);
+ if (getprotoent_r(&pd->proto, pd->data, sizeof(pd->data), &rval) != 0)
+ return (NULL);
+ return (rval);
+}
diff --git a/lib/libc/net/getprotoname.c b/lib/libc/net/getprotoname.c
new file mode 100644
index 000000000000..22c57594f6db
--- /dev/null
+++ b/lib/libc/net/getprotoname.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)getprotoname.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <netdb.h>
+#include <nsswitch.h>
+#include <string.h>
+#include "netdb_private.h"
+#ifdef NS_CACHING
+#include "nscache.h"
+#endif
+#include "nss_tls.h"
+
+static const ns_src defaultsrc[] = {
+ { NSSRC_FILES, NS_SUCCESS },
+ { NULL, 0 }
+};
+
+#ifdef NS_CACHING
+extern int __proto_id_func(char *, size_t *, va_list, void *);
+extern int __proto_marshal_func(char *, size_t *, void *, va_list, void *);
+extern int __proto_unmarshal_func(char *, size_t, void *, va_list, void *);
+#endif
+
+static int
+files_getprotobyname(void *retval, void *mdata, va_list ap)
+{
+ struct protoent pe;
+ struct protoent_data *ped;
+ char **cp;
+ int error;
+
+ char *name;
+ struct protoent *pptr;
+ char *buffer;
+ size_t buflen;
+ int *errnop;
+
+ name = va_arg(ap, char *);
+ pptr = va_arg(ap, struct protoent *);
+ buffer = va_arg(ap, char *);
+ buflen = va_arg(ap, size_t);
+ errnop = va_arg(ap, int *);
+
+
+ if ((ped = __protoent_data_init()) == NULL) {
+ *errnop = errno;
+ return (NS_NOTFOUND);
+ }
+
+ __setprotoent_p(ped->stayopen, ped);
+ while ((error = __getprotoent_p(&pe, ped)) == 0) {
+ if (strcmp(pe.p_name, name) == 0)
+ break;
+ for (cp = pe.p_aliases; *cp != 0; cp++)
+ if (strcmp(*cp, name) == 0)
+ goto found;
+ }
+found:
+ if (!ped->stayopen)
+ __endprotoent_p(ped);
+ if (error != 0) {
+ *errnop = errno;
+ return (NS_NOTFOUND);
+ }
+ if (__copy_protoent(&pe, pptr, buffer, buflen) != 0) {
+ *errnop = errno;
+ return (NS_RETURN);
+ }
+
+ *((struct protoent **)retval) = pptr;
+ return (NS_SUCCESS);
+}
+
+
+int
+getprotobyname_r(const char *name, struct protoent *pptr, char *buffer,
+ size_t buflen, struct protoent **result)
+{
+#ifdef NS_CACHING
+ static const nss_cache_info cache_info =
+ NS_COMMON_CACHE_INFO_INITIALIZER(
+ protocols, (void *)nss_lt_name,
+ __proto_id_func, __proto_marshal_func, __proto_unmarshal_func);
+#endif
+ static const ns_dtab dtab[] = {
+ { NSSRC_FILES, files_getprotobyname, NULL },
+#ifdef NS_CACHING
+ NS_CACHE_CB(&cache_info)
+#endif
+ { NULL, NULL, NULL }
+ };
+ int rv, ret_errno;
+
+ ret_errno = 0;
+ *result = NULL;
+ rv = nsdispatch(result, dtab, NSDB_PROTOCOLS, "getprotobyname_r",
+ defaultsrc, name, pptr, buffer, buflen, &ret_errno);
+
+ if (rv != NS_SUCCESS) {
+ errno = ret_errno;
+ return (ret_errno);
+ }
+ return (0);
+}
+
+struct protoent *
+getprotobyname(const char *name)
+{
+ struct protodata *pd;
+ struct protoent *rval;
+
+ if ((pd = __protodata_init()) == NULL)
+ return (NULL);
+ if (getprotobyname_r(name, &pd->proto, pd->data, sizeof(pd->data),
+ &rval) != 0)
+ return (NULL);
+ return (rval);
+}
diff --git a/lib/libc/net/getservent.3 b/lib/libc/net/getservent.3
new file mode 100644
index 000000000000..5f5a452c0973
--- /dev/null
+++ b/lib/libc/net/getservent.3
@@ -0,0 +1,154 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" From: @(#)getservent.3 8.3 (Berkeley) 1/12/94
+.\" $FreeBSD$
+.\"
+.Dd July 9, 1995
+.Dt GETSERVENT 3
+.Os
+.Sh NAME
+.Nm getservent ,
+.Nm getservbyport ,
+.Nm getservbyname ,
+.Nm setservent ,
+.Nm endservent
+.Nd get service entry
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In netdb.h
+.Ft struct servent *
+.Fn getservent
+.Ft struct servent *
+.Fn getservbyname "const char *name" "const char *proto"
+.Ft struct servent *
+.Fn getservbyport "int port" "const char *proto"
+.Ft void
+.Fn setservent "int stayopen"
+.Ft void
+.Fn endservent void
+.Sh DESCRIPTION
+The
+.Fn getservent ,
+.Fn getservbyname ,
+and
+.Fn getservbyport
+functions
+each return a pointer to an object with the
+following structure
+containing the broken-out
+fields of a line in the network services data base,
+.Pa /etc/services .
+.Bd -literal -offset indent
+struct servent {
+ char *s_name; /* official name of service */
+ char **s_aliases; /* alias list */
+ int s_port; /* port service resides at */
+ char *s_proto; /* protocol to use */
+};
+.Ed
+.Pp
+The members of this structure are:
+.Bl -tag -width s_aliases
+.It Fa s_name
+The official name of the service.
+.It Fa s_aliases
+A zero terminated list of alternate names for the service.
+.It Fa s_port
+The port number at which the service resides.
+Port numbers are returned in network byte order.
+.It Fa s_proto
+The name of the protocol to use when contacting the
+service.
+.El
+.Pp
+The
+.Fn getservent
+function
+reads the next line of the file, opening the file if necessary.
+.Pp
+The
+.Fn setservent
+function
+opens and rewinds the file.
+If the
+.Fa stayopen
+flag is non-zero,
+the net data base will not be closed after each call to
+.Fn getservbyname
+or
+.Fn getservbyport .
+.Pp
+The
+.Fn endservent
+function
+closes the file.
+.Pp
+The
+.Fn getservbyname
+and
+.Fn getservbyport
+functions
+sequentially search from the beginning
+of the file until a matching
+protocol name or
+port number (which must be specified in
+network byte order) is found,
+or until
+.Dv EOF
+is encountered.
+If a protocol name is also supplied (non-
+.Dv NULL ) ,
+searches must also match the protocol.
+.Sh FILES
+.Bl -tag -width /etc/services -compact
+.It Pa /etc/services
+.El
+.Sh DIAGNOSTICS
+Null pointer returned on
+.Dv EOF
+or error.
+.Sh SEE ALSO
+.Xr getprotoent 3 ,
+.Xr services 5
+.Sh HISTORY
+The
+.Fn getservent ,
+.Fn getservbyport ,
+.Fn getservbyname ,
+.Fn setservent ,
+and
+.Fn endservent
+functions appeared in
+.Bx 4.2 .
+.Sh BUGS
+These functions use a thread-specific data storage;
+if the data is needed for future use, it should be
+copied before any subsequent calls overwrite it.
+Expecting port numbers to fit in a 32 bit
+quantity is probably naive.
diff --git a/lib/libc/net/getservent.c b/lib/libc/net/getservent.c
new file mode 100644
index 000000000000..5614588aa263
--- /dev/null
+++ b/lib/libc/net/getservent.c
@@ -0,0 +1,1372 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)getservent.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <db.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <netdb.h>
+#include <nsswitch.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#ifdef YP
+#include <rpc/rpc.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+#endif
+#include "namespace.h"
+#include "reentrant.h"
+#include "un-namespace.h"
+#include "netdb_private.h"
+#ifdef NS_CACHING
+#include "nscache.h"
+#endif
+#include "nss_tls.h"
+
+enum constants
+{
+ SETSERVENT = 1,
+ ENDSERVENT = 2,
+ SERVENT_STORAGE_INITIAL = 1 << 10, /* 1 KByte */
+ SERVENT_STORAGE_MAX = 1 << 20, /* 1 MByte */
+};
+
+struct servent_mdata
+{
+ enum nss_lookup_type how;
+ int compat_mode;
+};
+
+static const ns_src defaultsrc[] = {
+ { NSSRC_COMPAT, NS_SUCCESS },
+ { NULL, 0 }
+};
+
+static int servent_unpack(char *, struct servent *, char **, size_t, int *);
+
+/* files backend declarations */
+struct files_state
+{
+ FILE *fp;
+ int stayopen;
+
+ int compat_mode_active;
+};
+static void files_endstate(void *);
+NSS_TLS_HANDLING(files);
+
+static int files_servent(void *, void *, va_list);
+static int files_setservent(void *, void *, va_list);
+
+/* db backend declarations */
+struct db_state
+{
+ DB *db;
+ int stayopen;
+ int keynum;
+};
+static void db_endstate(void *);
+NSS_TLS_HANDLING(db);
+
+static int db_servent(void *, void *, va_list);
+static int db_setservent(void *, void *, va_list);
+
+#ifdef YP
+/* nis backend declarations */
+static int nis_servent(void *, void *, va_list);
+static int nis_setservent(void *, void *, va_list);
+
+struct nis_state
+{
+ int yp_stepping;
+ char yp_domain[MAXHOSTNAMELEN];
+ char *yp_key;
+ int yp_keylen;
+};
+static void nis_endstate(void *);
+NSS_TLS_HANDLING(nis);
+
+static int nis_servent(void *, void *, va_list);
+static int nis_setservent(void *, void *, va_list);
+#endif
+
+/* compat backend declarations */
+static int compat_setservent(void *, void *, va_list);
+
+/* get** wrappers for get**_r functions declarations */
+struct servent_state {
+ struct servent serv;
+ char *buffer;
+ size_t bufsize;
+};
+static void servent_endstate(void *);
+NSS_TLS_HANDLING(servent);
+
+struct key {
+ const char *proto;
+ union {
+ const char *name;
+ int port;
+ };
+};
+
+static int wrap_getservbyname_r(struct key, struct servent *, char *, size_t,
+ struct servent **);
+static int wrap_getservbyport_r(struct key, struct servent *, char *, size_t,
+ struct servent **);
+static int wrap_getservent_r(struct key, struct servent *, char *, size_t,
+ struct servent **);
+static struct servent *getserv(int (*fn)(struct key, struct servent *, char *,
+ size_t, struct servent **), struct key);
+
+#ifdef NS_CACHING
+static int serv_id_func(char *, size_t *, va_list, void *);
+static int serv_marshal_func(char *, size_t *, void *, va_list, void *);
+static int serv_unmarshal_func(char *, size_t, void *, va_list, void *);
+#endif
+
+static int
+servent_unpack(char *p, struct servent *serv, char **aliases,
+ size_t aliases_size, int *errnop)
+{
+ char *cp, **q, *endp;
+ long l;
+
+ if (*p == '#')
+ return -1;
+
+ memset(serv, 0, sizeof(struct servent));
+
+ cp = strpbrk(p, "#\n");
+ if (cp != NULL)
+ *cp = '\0';
+ serv->s_name = p;
+
+ p = strpbrk(p, " \t");
+ if (p == NULL)
+ return -1;
+ *p++ = '\0';
+ while (*p == ' ' || *p == '\t')
+ p++;
+ cp = strpbrk(p, ",/");
+ if (cp == NULL)
+ return -1;
+
+ *cp++ = '\0';
+ l = strtol(p, &endp, 10);
+ if (endp == p || *endp != '\0' || l < 0 || l > USHRT_MAX)
+ return -1;
+ serv->s_port = htons((in_port_t)l);
+ serv->s_proto = cp;
+
+ q = serv->s_aliases = aliases;
+ cp = strpbrk(cp, " \t");
+ if (cp != NULL)
+ *cp++ = '\0';
+ while (cp && *cp) {
+ if (*cp == ' ' || *cp == '\t') {
+ cp++;
+ continue;
+ }
+ if (q < &aliases[aliases_size - 1]) {
+ *q++ = cp;
+ } else {
+ *q = NULL;
+ *errnop = ERANGE;
+ return -1;
+ }
+ cp = strpbrk(cp, " \t");
+ if (cp != NULL)
+ *cp++ = '\0';
+ }
+ *q = NULL;
+
+ return 0;
+}
+
+static int
+parse_result(struct servent *serv, char *buffer, size_t bufsize,
+ char *resultbuf, size_t resultbuflen, int *errnop)
+{
+ char **aliases;
+ int aliases_size;
+
+ if (bufsize <= resultbuflen + _ALIGNBYTES + sizeof(char *)) {
+ *errnop = ERANGE;
+ return (NS_RETURN);
+ }
+ aliases = (char **)_ALIGN(&buffer[resultbuflen + 1]);
+ aliases_size = (buffer + bufsize - (char *)aliases) / sizeof(char *);
+ if (aliases_size < 1) {
+ *errnop = ERANGE;
+ return (NS_RETURN);
+ }
+
+ memcpy(buffer, resultbuf, resultbuflen);
+ buffer[resultbuflen] = '\0';
+
+ if (servent_unpack(buffer, serv, aliases, aliases_size, errnop) != 0)
+ return ((*errnop == 0) ? NS_NOTFOUND : NS_RETURN);
+ return (NS_SUCCESS);
+}
+
+/* files backend implementation */
+static void
+files_endstate(void *p)
+{
+ FILE * f;
+
+ if (p == NULL)
+ return;
+
+ f = ((struct files_state *)p)->fp;
+ if (f != NULL)
+ fclose(f);
+
+ free(p);
+}
+
+/*
+ * compat structures. compat and files sources functionalities are almost
+ * equal, so they all are managed by files_servent function
+ */
+static int
+files_servent(void *retval, void *mdata, va_list ap)
+{
+ static const ns_src compat_src[] = {
+#ifdef YP
+ { NSSRC_NIS, NS_SUCCESS },
+#endif
+ { NULL, 0 }
+ };
+ ns_dtab compat_dtab[] = {
+ { NSSRC_DB, db_servent,
+ (void *)((struct servent_mdata *)mdata)->how },
+#ifdef YP
+ { NSSRC_NIS, nis_servent,
+ (void *)((struct servent_mdata *)mdata)->how },
+#endif
+ { NULL, NULL, NULL }
+ };
+
+ struct files_state *st;
+ int rv;
+ int stayopen;
+
+ struct servent_mdata *serv_mdata;
+ char *name;
+ char *proto;
+ int port;
+
+ struct servent *serv;
+ char *buffer;
+ size_t bufsize;
+ int *errnop;
+
+ size_t linesize;
+ char *line;
+ char **cp;
+
+ name = NULL;
+ proto = NULL;
+ serv_mdata = (struct servent_mdata *)mdata;
+ switch (serv_mdata->how) {
+ case nss_lt_name:
+ name = va_arg(ap, char *);
+ proto = va_arg(ap, char *);
+ break;
+ case nss_lt_id:
+ port = va_arg(ap, int);
+ proto = va_arg(ap, char *);
+ break;
+ case nss_lt_all:
+ break;
+ default:
+ return NS_NOTFOUND;
+ }
+
+ serv = va_arg(ap, struct servent *);
+ buffer = va_arg(ap, char *);
+ bufsize = va_arg(ap, size_t);
+ errnop = va_arg(ap,int *);
+
+ *errnop = files_getstate(&st);
+ if (*errnop != 0)
+ return (NS_UNAVAIL);
+
+ if (st->fp == NULL)
+ st->compat_mode_active = 0;
+
+ if (st->fp == NULL && (st->fp = fopen(_PATH_SERVICES, "re")) == NULL) {
+ *errnop = errno;
+ return (NS_UNAVAIL);
+ }
+
+ if (serv_mdata->how == nss_lt_all)
+ stayopen = 1;
+ else {
+ rewind(st->fp);
+ stayopen = st->stayopen;
+ }
+
+ rv = NS_NOTFOUND;
+ do {
+ if (!st->compat_mode_active) {
+ if ((line = fgetln(st->fp, &linesize)) == NULL) {
+ *errnop = errno;
+ rv = NS_RETURN;
+ break;
+ }
+
+ if (*line=='+' && serv_mdata->compat_mode != 0)
+ st->compat_mode_active = 1;
+ }
+
+ if (st->compat_mode_active != 0) {
+ switch (serv_mdata->how) {
+ case nss_lt_name:
+ rv = nsdispatch(retval, compat_dtab,
+ NSDB_SERVICES_COMPAT, "getservbyname_r",
+ compat_src, name, proto, serv, buffer,
+ bufsize, errnop);
+ break;
+ case nss_lt_id:
+ rv = nsdispatch(retval, compat_dtab,
+ NSDB_SERVICES_COMPAT, "getservbyport_r",
+ compat_src, port, proto, serv, buffer,
+ bufsize, errnop);
+ break;
+ case nss_lt_all:
+ rv = nsdispatch(retval, compat_dtab,
+ NSDB_SERVICES_COMPAT, "getservent_r",
+ compat_src, serv, buffer, bufsize, errnop);
+ break;
+ }
+
+ if (!(rv & NS_TERMINATE) ||
+ serv_mdata->how != nss_lt_all)
+ st->compat_mode_active = 0;
+
+ continue;
+ }
+
+ rv = parse_result(serv, buffer, bufsize, line, linesize,
+ errnop);
+ if (rv == NS_NOTFOUND)
+ continue;
+ if (rv == NS_RETURN)
+ break;
+
+ rv = NS_NOTFOUND;
+ switch (serv_mdata->how) {
+ case nss_lt_name:
+ if (strcmp(name, serv->s_name) == 0)
+ goto gotname;
+ for (cp = serv->s_aliases; *cp; cp++)
+ if (strcmp(name, *cp) == 0)
+ goto gotname;
+
+ continue;
+ gotname:
+ if (proto == NULL || strcmp(serv->s_proto, proto) == 0)
+ rv = NS_SUCCESS;
+ break;
+ case nss_lt_id:
+ if (port != serv->s_port)
+ continue;
+
+ if (proto == NULL || strcmp(serv->s_proto, proto) == 0)
+ rv = NS_SUCCESS;
+ break;
+ case nss_lt_all:
+ rv = NS_SUCCESS;
+ break;
+ }
+
+ } while (!(rv & NS_TERMINATE));
+
+ if (!stayopen && st->fp != NULL) {
+ fclose(st->fp);
+ st->fp = NULL;
+ }
+
+ if ((rv == NS_SUCCESS) && (retval != NULL))
+ *(struct servent **)retval=serv;
+
+ return (rv);
+}
+
+static int
+files_setservent(void *retval, void *mdata, va_list ap)
+{
+ struct files_state *st;
+ int rv;
+ int f;
+
+ rv = files_getstate(&st);
+ if (rv != 0)
+ return (NS_UNAVAIL);
+
+ switch ((enum constants)mdata) {
+ case SETSERVENT:
+ f = va_arg(ap,int);
+ if (st->fp == NULL)
+ st->fp = fopen(_PATH_SERVICES, "re");
+ else
+ rewind(st->fp);
+ st->stayopen |= f;
+ break;
+ case ENDSERVENT:
+ if (st->fp != NULL) {
+ fclose(st->fp);
+ st->fp = NULL;
+ }
+ st->stayopen = 0;
+ break;
+ default:
+ break;
+ }
+
+ st->compat_mode_active = 0;
+ return (NS_UNAVAIL);
+}
+
+/* db backend implementation */
+static void
+db_endstate(void *p)
+{
+ DB *db;
+
+ if (p == NULL)
+ return;
+
+ db = ((struct db_state *)p)->db;
+ if (db != NULL)
+ db->close(db);
+
+ free(p);
+}
+
+static int
+db_servent(void *retval, void *mdata, va_list ap)
+{
+ char buf[BUFSIZ];
+ DBT key, data, *result;
+ DB *db;
+
+ struct db_state *st;
+ int rv;
+ int stayopen;
+
+ enum nss_lookup_type how;
+ char *name;
+ char *proto;
+ int port;
+
+ struct servent *serv;
+ char *buffer;
+ size_t bufsize;
+ int *errnop;
+
+ name = NULL;
+ proto = NULL;
+ how = (enum nss_lookup_type)mdata;
+ switch (how) {
+ case nss_lt_name:
+ name = va_arg(ap, char *);
+ proto = va_arg(ap, char *);
+ break;
+ case nss_lt_id:
+ port = va_arg(ap, int);
+ proto = va_arg(ap, char *);
+ break;
+ case nss_lt_all:
+ break;
+ default:
+ return NS_NOTFOUND;
+ }
+
+ serv = va_arg(ap, struct servent *);
+ buffer = va_arg(ap, char *);
+ bufsize = va_arg(ap, size_t);
+ errnop = va_arg(ap,int *);
+
+ *errnop = db_getstate(&st);
+ if (*errnop != 0)
+ return (NS_UNAVAIL);
+
+ if (how == nss_lt_all && st->keynum < 0)
+ return (NS_NOTFOUND);
+
+ if (st->db == NULL) {
+ st->db = dbopen(_PATH_SERVICES_DB, O_RDONLY, 0, DB_HASH, NULL);
+ if (st->db == NULL) {
+ *errnop = errno;
+ return (NS_UNAVAIL);
+ }
+ }
+
+ stayopen = (how == nss_lt_all) ? 1 : st->stayopen;
+ db = st->db;
+
+ do {
+ switch (how) {
+ case nss_lt_name:
+ key.data = buf;
+ if (proto == NULL)
+ key.size = snprintf(buf, sizeof(buf),
+ "\376%s", name);
+ else
+ key.size = snprintf(buf, sizeof(buf),
+ "\376%s/%s", name, proto);
+ key.size++;
+ if (db->get(db, &key, &data, 0) != 0 ||
+ db->get(db, &data, &key, 0) != 0) {
+ rv = NS_NOTFOUND;
+ goto db_fin;
+ }
+ result = &key;
+ break;
+ case nss_lt_id:
+ key.data = buf;
+ port = htons(port);
+ if (proto == NULL)
+ key.size = snprintf(buf, sizeof(buf),
+ "\377%d", port);
+ else
+ key.size = snprintf(buf, sizeof(buf),
+ "\377%d/%s", port, proto);
+ key.size++;
+ if (db->get(db, &key, &data, 0) != 0 ||
+ db->get(db, &data, &key, 0) != 0) {
+ rv = NS_NOTFOUND;
+ goto db_fin;
+ }
+ result = &key;
+ break;
+ case nss_lt_all:
+ key.data = buf;
+ key.size = snprintf(buf, sizeof(buf), "%d",
+ st->keynum++);
+ key.size++;
+ if (db->get(db, &key, &data, 0) != 0) {
+ st->keynum = -1;
+ rv = NS_NOTFOUND;
+ goto db_fin;
+ }
+ result = &data;
+ break;
+ }
+
+ rv = parse_result(serv, buffer, bufsize, result->data,
+ result->size - 1, errnop);
+
+ } while (!(rv & NS_TERMINATE) && how == nss_lt_all);
+
+db_fin:
+ if (!stayopen && st->db != NULL) {
+ db->close(db);
+ st->db = NULL;
+ }
+
+ if (rv == NS_SUCCESS && retval != NULL)
+ *(struct servent **)retval = serv;
+
+ return (rv);
+}
+
+static int
+db_setservent(void *retval, void *mdata, va_list ap)
+{
+ DB *db;
+ struct db_state *st;
+ int rv;
+ int f;
+
+ rv = db_getstate(&st);
+ if (rv != 0)
+ return (NS_UNAVAIL);
+
+ switch ((enum constants)mdata) {
+ case SETSERVENT:
+ f = va_arg(ap, int);
+ st->stayopen |= f;
+ st->keynum = 0;
+ break;
+ case ENDSERVENT:
+ db = st->db;
+ if (db != NULL) {
+ db->close(db);
+ st->db = NULL;
+ }
+ st->stayopen = 0;
+ break;
+ default:
+ break;
+ }
+
+ return (NS_UNAVAIL);
+}
+
+/* nis backend implementation */
+#ifdef YP
+static void
+nis_endstate(void *p)
+{
+ if (p == NULL)
+ return;
+
+ free(((struct nis_state *)p)->yp_key);
+ free(p);
+}
+
+static int
+nis_servent(void *retval, void *mdata, va_list ap)
+{
+ char *resultbuf, *lastkey;
+ int resultbuflen;
+ char buf[YPMAXRECORD + 2];
+
+ struct nis_state *st;
+ int rv;
+
+ enum nss_lookup_type how;
+ char *name;
+ char *proto;
+ int port;
+
+ struct servent *serv;
+ char *buffer;
+ size_t bufsize;
+ int *errnop;
+
+ name = NULL;
+ proto = NULL;
+ how = (enum nss_lookup_type)mdata;
+ switch (how) {
+ case nss_lt_name:
+ name = va_arg(ap, char *);
+ proto = va_arg(ap, char *);
+ break;
+ case nss_lt_id:
+ port = va_arg(ap, int);
+ proto = va_arg(ap, char *);
+ break;
+ case nss_lt_all:
+ break;
+ default:
+ return NS_NOTFOUND;
+ }
+
+ serv = va_arg(ap, struct servent *);
+ buffer = va_arg(ap, char *);
+ bufsize = va_arg(ap, size_t);
+ errnop = va_arg(ap, int *);
+
+ *errnop = nis_getstate(&st);
+ if (*errnop != 0)
+ return (NS_UNAVAIL);
+
+ if (st->yp_domain[0] == '\0') {
+ if (getdomainname(st->yp_domain, sizeof st->yp_domain)) {
+ *errnop = errno;
+ return (NS_UNAVAIL);
+ }
+ }
+
+ do {
+ switch (how) {
+ case nss_lt_name:
+ snprintf(buf, sizeof(buf), "%s/%s", name, proto);
+ if (yp_match(st->yp_domain, "services.byname", buf,
+ strlen(buf), &resultbuf, &resultbuflen)) {
+ rv = NS_NOTFOUND;
+ goto fin;
+ }
+ break;
+ case nss_lt_id:
+ snprintf(buf, sizeof(buf), "%d/%s", ntohs(port),
+ proto);
+
+ /*
+ * We have to be a little flexible
+ * here. Ideally you're supposed to have both
+ * a services.byname and a services.byport
+ * map, but some systems have only
+ * services.byname. FreeBSD cheats a little by
+ * putting the services.byport information in
+ * the same map as services.byname so that
+ * either case will work. We allow for both
+ * possibilities here: if there is no
+ * services.byport map, we try services.byname
+ * instead.
+ */
+ rv = yp_match(st->yp_domain, "services.byport", buf,
+ strlen(buf), &resultbuf, &resultbuflen);
+ if (rv) {
+ if (rv == YPERR_MAP) {
+ if (yp_match(st->yp_domain,
+ "services.byname", buf,
+ strlen(buf), &resultbuf,
+ &resultbuflen)) {
+ rv = NS_NOTFOUND;
+ goto fin;
+ }
+ } else {
+ rv = NS_NOTFOUND;
+ goto fin;
+ }
+ }
+
+ break;
+ case nss_lt_all:
+ if (!st->yp_stepping) {
+ free(st->yp_key);
+ rv = yp_first(st->yp_domain, "services.byname",
+ &st->yp_key, &st->yp_keylen, &resultbuf,
+ &resultbuflen);
+ if (rv) {
+ rv = NS_NOTFOUND;
+ goto fin;
+ }
+ st->yp_stepping = 1;
+ } else {
+ lastkey = st->yp_key;
+ rv = yp_next(st->yp_domain, "services.byname",
+ st->yp_key, st->yp_keylen, &st->yp_key,
+ &st->yp_keylen, &resultbuf, &resultbuflen);
+ free(lastkey);
+ if (rv) {
+ st->yp_stepping = 0;
+ rv = NS_NOTFOUND;
+ goto fin;
+ }
+ }
+ break;
+ }
+
+ rv = parse_result(serv, buffer, bufsize, resultbuf,
+ resultbuflen, errnop);
+ free(resultbuf);
+
+ } while (!(rv & NS_TERMINATE) && how == nss_lt_all);
+
+fin:
+ if (rv == NS_SUCCESS && retval != NULL)
+ *(struct servent **)retval = serv;
+
+ return (rv);
+}
+
+static int
+nis_setservent(void *result, void *mdata, va_list ap)
+{
+ struct nis_state *st;
+ int rv;
+
+ rv = nis_getstate(&st);
+ if (rv != 0)
+ return (NS_UNAVAIL);
+
+ switch ((enum constants)mdata) {
+ case SETSERVENT:
+ case ENDSERVENT:
+ free(st->yp_key);
+ st->yp_key = NULL;
+ st->yp_stepping = 0;
+ break;
+ default:
+ break;
+ }
+
+ return (NS_UNAVAIL);
+}
+#endif
+
+/* compat backend implementation */
+static int
+compat_setservent(void *retval, void *mdata, va_list ap)
+{
+ static const ns_src compat_src[] = {
+#ifdef YP
+ { NSSRC_NIS, NS_SUCCESS },
+#endif
+ { NULL, 0 }
+ };
+ ns_dtab compat_dtab[] = {
+ { NSSRC_DB, db_setservent, mdata },
+#ifdef YP
+ { NSSRC_NIS, nis_setservent, mdata },
+#endif
+ { NULL, NULL, NULL }
+ };
+ int f;
+
+ (void)files_setservent(retval, mdata, ap);
+
+ switch ((enum constants)mdata) {
+ case SETSERVENT:
+ f = va_arg(ap,int);
+ (void)nsdispatch(retval, compat_dtab, NSDB_SERVICES_COMPAT,
+ "setservent", compat_src, f);
+ break;
+ case ENDSERVENT:
+ (void)nsdispatch(retval, compat_dtab, NSDB_SERVICES_COMPAT,
+ "endservent", compat_src);
+ break;
+ default:
+ break;
+ }
+
+ return (NS_UNAVAIL);
+}
+
+#ifdef NS_CACHING
+static int
+serv_id_func(char *buffer, size_t *buffer_size, va_list ap, void *cache_mdata)
+{
+ char *name;
+ char *proto;
+ int port;
+
+ size_t desired_size, size, size2;
+ enum nss_lookup_type lookup_type;
+ int res = NS_UNAVAIL;
+
+ lookup_type = (enum nss_lookup_type)cache_mdata;
+ switch (lookup_type) {
+ case nss_lt_name:
+ name = va_arg(ap, char *);
+ proto = va_arg(ap, char *);
+
+ size = strlen(name);
+ desired_size = sizeof(enum nss_lookup_type) + size + 1;
+ if (proto != NULL) {
+ size2 = strlen(proto);
+ desired_size += size2 + 1;
+ } else
+ size2 = 0;
+
+ if (desired_size > *buffer_size) {
+ res = NS_RETURN;
+ goto fin;
+ }
+
+ memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type));
+ memcpy(buffer + sizeof(enum nss_lookup_type), name, size + 1);
+
+ if (proto != NULL)
+ memcpy(buffer + sizeof(enum nss_lookup_type) + size + 1,
+ proto, size2 + 1);
+
+ res = NS_SUCCESS;
+ break;
+ case nss_lt_id:
+ port = va_arg(ap, int);
+ proto = va_arg(ap, char *);
+
+ desired_size = sizeof(enum nss_lookup_type) + sizeof(int);
+ if (proto != NULL) {
+ size = strlen(proto);
+ desired_size += size + 1;
+ } else
+ size = 0;
+
+ if (desired_size > *buffer_size) {
+ res = NS_RETURN;
+ goto fin;
+ }
+
+ memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type));
+ memcpy(buffer + sizeof(enum nss_lookup_type), &port,
+ sizeof(int));
+
+ if (proto != NULL)
+ memcpy(buffer + sizeof(enum nss_lookup_type) +
+ sizeof(int), proto, size + 1);
+
+ res = NS_SUCCESS;
+ break;
+ default:
+ /* should be unreachable */
+ return (NS_UNAVAIL);
+ }
+
+fin:
+ *buffer_size = desired_size;
+ return (res);
+}
+
+int
+serv_marshal_func(char *buffer, size_t *buffer_size, void *retval, va_list ap,
+ void *cache_mdata)
+{
+ char *name;
+ char *proto;
+ int port;
+ struct servent *serv;
+ char *orig_buf;
+ size_t orig_buf_size;
+
+ struct servent new_serv;
+ size_t desired_size;
+ char **alias;
+ char *p;
+ size_t size;
+ size_t aliases_size;
+
+ switch ((enum nss_lookup_type)cache_mdata) {
+ case nss_lt_name:
+ name = va_arg(ap, char *);
+ proto = va_arg(ap, char *);
+ break;
+ case nss_lt_id:
+ port = va_arg(ap, int);
+ proto = va_arg(ap, char *);
+ break;
+ case nss_lt_all:
+ break;
+ default:
+ /* should be unreachable */
+ return (NS_UNAVAIL);
+ }
+
+ serv = va_arg(ap, struct servent *);
+ orig_buf = va_arg(ap, char *);
+ orig_buf_size = va_arg(ap, size_t);
+
+ desired_size = _ALIGNBYTES + sizeof(struct servent) + sizeof(char *);
+ if (serv->s_name != NULL)
+ desired_size += strlen(serv->s_name) + 1;
+ if (serv->s_proto != NULL)
+ desired_size += strlen(serv->s_proto) + 1;
+
+ aliases_size = 0;
+ if (serv->s_aliases != NULL) {
+ for (alias = serv->s_aliases; *alias; ++alias) {
+ desired_size += strlen(*alias) + 1;
+ ++aliases_size;
+ }
+
+ desired_size += _ALIGNBYTES +
+ sizeof(char *) * (aliases_size + 1);
+ }
+
+ if (*buffer_size < desired_size) {
+ /* this assignment is here for future use */
+ *buffer_size = desired_size;
+ return (NS_RETURN);
+ }
+
+ memcpy(&new_serv, serv, sizeof(struct servent));
+ memset(buffer, 0, desired_size);
+
+ *buffer_size = desired_size;
+ p = buffer + sizeof(struct servent) + sizeof(char *);
+ memcpy(buffer + sizeof(struct servent), &p, sizeof(char *));
+ p = (char *)_ALIGN(p);
+
+ if (new_serv.s_name != NULL) {
+ size = strlen(new_serv.s_name);
+ memcpy(p, new_serv.s_name, size);
+ new_serv.s_name = p;
+ p += size + 1;
+ }
+
+ if (new_serv.s_proto != NULL) {
+ size = strlen(new_serv.s_proto);
+ memcpy(p, new_serv.s_proto, size);
+ new_serv.s_proto = p;
+ p += size + 1;
+ }
+
+ if (new_serv.s_aliases != NULL) {
+ p = (char *)_ALIGN(p);
+ memcpy(p, new_serv.s_aliases, sizeof(char *) * aliases_size);
+ new_serv.s_aliases = (char **)p;
+ p += sizeof(char *) * (aliases_size + 1);
+
+ for (alias = new_serv.s_aliases; *alias; ++alias) {
+ size = strlen(*alias);
+ memcpy(p, *alias, size);
+ *alias = p;
+ p += size + 1;
+ }
+ }
+
+ memcpy(buffer, &new_serv, sizeof(struct servent));
+ return (NS_SUCCESS);
+}
+
+int
+serv_unmarshal_func(char *buffer, size_t buffer_size, void *retval, va_list ap,
+ void *cache_mdata)
+{
+ char *name;
+ char *proto;
+ int port;
+ struct servent *serv;
+ char *orig_buf;
+ char *p;
+ char **alias;
+ size_t orig_buf_size;
+ int *ret_errno;
+
+ switch ((enum nss_lookup_type)cache_mdata) {
+ case nss_lt_name:
+ name = va_arg(ap, char *);
+ proto = va_arg(ap, char *);
+ break;
+ case nss_lt_id:
+ port = va_arg(ap, int);
+ proto = va_arg(ap, char *);
+ break;
+ case nss_lt_all:
+ break;
+ default:
+ /* should be unreachable */
+ return (NS_UNAVAIL);
+ }
+
+ serv = va_arg(ap, struct servent *);
+ orig_buf = va_arg(ap, char *);
+ orig_buf_size = va_arg(ap, size_t);
+ ret_errno = va_arg(ap, int *);
+
+ if (orig_buf_size <
+ buffer_size - sizeof(struct servent) - sizeof(char *)) {
+ *ret_errno = ERANGE;
+ return (NS_RETURN);
+ }
+
+ memcpy(serv, buffer, sizeof(struct servent));
+ memcpy(&p, buffer + sizeof(struct servent), sizeof(char *));
+
+ orig_buf = (char *)_ALIGN(orig_buf);
+ memcpy(orig_buf, buffer + sizeof(struct servent) + sizeof(char *) +
+ (_ALIGN(p) - (size_t)p),
+ buffer_size - sizeof(struct servent) - sizeof(char *) -
+ (_ALIGN(p) - (size_t)p));
+ p = (char *)_ALIGN(p);
+
+ NS_APPLY_OFFSET(serv->s_name, orig_buf, p, char *);
+ NS_APPLY_OFFSET(serv->s_proto, orig_buf, p, char *);
+ if (serv->s_aliases != NULL) {
+ NS_APPLY_OFFSET(serv->s_aliases, orig_buf, p, char **);
+
+ for (alias = serv->s_aliases; *alias; ++alias)
+ NS_APPLY_OFFSET(*alias, orig_buf, p, char *);
+ }
+
+ if (retval != NULL)
+ *((struct servent **)retval) = serv;
+ return (NS_SUCCESS);
+}
+
+NSS_MP_CACHE_HANDLING(services);
+#endif /* NS_CACHING */
+
+/* get**_r functions implementation */
+int
+getservbyname_r(const char *name, const char *proto, struct servent *serv,
+ char *buffer, size_t bufsize, struct servent **result)
+{
+ static const struct servent_mdata mdata = { nss_lt_name, 0 };
+ static const struct servent_mdata compat_mdata = { nss_lt_name, 1 };
+#ifdef NS_CACHING
+ static const nss_cache_info cache_info =
+ NS_COMMON_CACHE_INFO_INITIALIZER(
+ services, (void *)nss_lt_name,
+ serv_id_func, serv_marshal_func, serv_unmarshal_func);
+#endif /* NS_CACHING */
+ static const ns_dtab dtab[] = {
+ { NSSRC_FILES, files_servent, (void *)&mdata },
+ { NSSRC_DB, db_servent, (void *)nss_lt_name },
+#ifdef YP
+ { NSSRC_NIS, nis_servent, (void *)nss_lt_name },
+#endif
+ { NSSRC_COMPAT, files_servent, (void *)&compat_mdata },
+#ifdef NS_CACHING
+ NS_CACHE_CB(&cache_info)
+#endif
+ { NULL, NULL, NULL }
+ };
+ int rv, ret_errno;
+
+ ret_errno = 0;
+ *result = NULL;
+ rv = nsdispatch(result, dtab, NSDB_SERVICES, "getservbyname_r",
+ defaultsrc, name, proto, serv, buffer, bufsize, &ret_errno);
+
+ if (rv == NS_SUCCESS)
+ return (0);
+ else
+ return (ret_errno);
+}
+
+int
+getservbyport_r(int port, const char *proto, struct servent *serv,
+ char *buffer, size_t bufsize, struct servent **result)
+{
+ static const struct servent_mdata mdata = { nss_lt_id, 0 };
+ static const struct servent_mdata compat_mdata = { nss_lt_id, 1 };
+#ifdef NS_CACHING
+ static const nss_cache_info cache_info =
+ NS_COMMON_CACHE_INFO_INITIALIZER(
+ services, (void *)nss_lt_id,
+ serv_id_func, serv_marshal_func, serv_unmarshal_func);
+#endif
+ static const ns_dtab dtab[] = {
+ { NSSRC_FILES, files_servent, (void *)&mdata },
+ { NSSRC_DB, db_servent, (void *)nss_lt_id },
+#ifdef YP
+ { NSSRC_NIS, nis_servent, (void *)nss_lt_id },
+#endif
+ { NSSRC_COMPAT, files_servent, (void *)&compat_mdata },
+#ifdef NS_CACHING
+ NS_CACHE_CB(&cache_info)
+#endif
+ { NULL, NULL, NULL }
+ };
+ int rv, ret_errno;
+
+ ret_errno = 0;
+ *result = NULL;
+ rv = nsdispatch(result, dtab, NSDB_SERVICES, "getservbyport_r",
+ defaultsrc, port, proto, serv, buffer, bufsize, &ret_errno);
+
+ if (rv == NS_SUCCESS)
+ return (0);
+ else
+ return (ret_errno);
+}
+
+int
+getservent_r(struct servent *serv, char *buffer, size_t bufsize,
+ struct servent **result)
+{
+ static const struct servent_mdata mdata = { nss_lt_all, 0 };
+ static const struct servent_mdata compat_mdata = { nss_lt_all, 1 };
+#ifdef NS_CACHING
+ static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
+ services, (void *)nss_lt_all,
+ serv_marshal_func, serv_unmarshal_func);
+#endif
+ static const ns_dtab dtab[] = {
+ { NSSRC_FILES, files_servent, (void *)&mdata },
+ { NSSRC_DB, db_servent, (void *)nss_lt_all },
+#ifdef YP
+ { NSSRC_NIS, nis_servent, (void *)nss_lt_all },
+#endif
+ { NSSRC_COMPAT, files_servent, (void *)&compat_mdata },
+#ifdef NS_CACHING
+ NS_CACHE_CB(&cache_info)
+#endif
+ { NULL, NULL, NULL }
+ };
+ int rv, ret_errno;
+
+ ret_errno = 0;
+ *result = NULL;
+ rv = nsdispatch(result, dtab, NSDB_SERVICES, "getservent_r",
+ defaultsrc, serv, buffer, bufsize, &ret_errno);
+
+ if (rv == NS_SUCCESS)
+ return (0);
+ else
+ return (ret_errno);
+}
+
+void
+setservent(int stayopen)
+{
+#ifdef NS_CACHING
+ static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
+ services, (void *)nss_lt_all,
+ NULL, NULL);
+#endif
+ static const ns_dtab dtab[] = {
+ { NSSRC_FILES, files_setservent, (void *)SETSERVENT },
+ { NSSRC_DB, db_setservent, (void *)SETSERVENT },
+#ifdef YP
+ { NSSRC_NIS, nis_setservent, (void *)SETSERVENT },
+#endif
+ { NSSRC_COMPAT, compat_setservent, (void *)SETSERVENT },
+#ifdef NS_CACHING
+ NS_CACHE_CB(&cache_info)
+#endif
+ { NULL, NULL, NULL }
+ };
+
+ (void)nsdispatch(NULL, dtab, NSDB_SERVICES, "setservent", defaultsrc,
+ stayopen);
+}
+
+void
+endservent(void)
+{
+#ifdef NS_CACHING
+ static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
+ services, (void *)nss_lt_all,
+ NULL, NULL);
+#endif
+ static const ns_dtab dtab[] = {
+ { NSSRC_FILES, files_setservent, (void *)ENDSERVENT },
+ { NSSRC_DB, db_setservent, (void *)ENDSERVENT },
+#ifdef YP
+ { NSSRC_NIS, nis_setservent, (void *)ENDSERVENT },
+#endif
+ { NSSRC_COMPAT, compat_setservent, (void *)ENDSERVENT },
+#ifdef NS_CACHING
+ NS_CACHE_CB(&cache_info)
+#endif
+ { NULL, NULL, NULL }
+ };
+
+ (void)nsdispatch(NULL, dtab, NSDB_SERVICES, "endservent", defaultsrc);
+}
+
+/* get** wrappers for get**_r functions implementation */
+static void
+servent_endstate(void *p)
+{
+ if (p == NULL)
+ return;
+
+ free(((struct servent_state *)p)->buffer);
+ free(p);
+}
+
+static int
+wrap_getservbyname_r(struct key key, struct servent *serv, char *buffer,
+ size_t bufsize, struct servent **res)
+{
+ return (getservbyname_r(key.name, key.proto, serv, buffer, bufsize,
+ res));
+}
+
+static int
+wrap_getservbyport_r(struct key key, struct servent *serv, char *buffer,
+ size_t bufsize, struct servent **res)
+{
+ return (getservbyport_r(key.port, key.proto, serv, buffer, bufsize,
+ res));
+}
+
+static int
+wrap_getservent_r(struct key key, struct servent *serv, char *buffer,
+ size_t bufsize, struct servent **res)
+{
+ return (getservent_r(serv, buffer, bufsize, res));
+}
+
+static struct servent *
+getserv(int (*fn)(struct key, struct servent *, char *, size_t,
+ struct servent **), struct key key)
+{
+ int rv;
+ struct servent *res;
+ struct servent_state * st;
+
+ rv = servent_getstate(&st);
+ if (rv != 0) {
+ errno = rv;
+ return NULL;
+ }
+
+ if (st->buffer == NULL) {
+ st->buffer = malloc(SERVENT_STORAGE_INITIAL);
+ if (st->buffer == NULL)
+ return (NULL);
+ st->bufsize = SERVENT_STORAGE_INITIAL;
+ }
+ do {
+ rv = fn(key, &st->serv, st->buffer, st->bufsize, &res);
+ if (res == NULL && rv == ERANGE) {
+ free(st->buffer);
+ if ((st->bufsize << 1) > SERVENT_STORAGE_MAX) {
+ st->buffer = NULL;
+ errno = ERANGE;
+ return (NULL);
+ }
+ st->bufsize <<= 1;
+ st->buffer = malloc(st->bufsize);
+ if (st->buffer == NULL)
+ return (NULL);
+ }
+ } while (res == NULL && rv == ERANGE);
+ if (rv != 0)
+ errno = rv;
+
+ return (res);
+}
+
+struct servent *
+getservbyname(const char *name, const char *proto)
+{
+ struct key key;
+
+ key.name = name;
+ key.proto = proto;
+
+ return (getserv(wrap_getservbyname_r, key));
+}
+
+struct servent *
+getservbyport(int port, const char *proto)
+{
+ struct key key;
+
+ key.port = port;
+ key.proto = proto;
+
+ return (getserv(wrap_getservbyport_r, key));
+}
+
+struct servent *
+getservent(void)
+{
+ struct key key;
+
+ key.proto = NULL;
+ key.port = 0;
+
+ return (getserv(wrap_getservent_r, key));
+}
diff --git a/lib/libc/net/hesiod.3 b/lib/libc/net/hesiod.3
new file mode 100644
index 000000000000..bae4e4419f82
--- /dev/null
+++ b/lib/libc/net/hesiod.3
@@ -0,0 +1,176 @@
+.\" $NetBSD: hesiod.3,v 1.1 1999/01/25 03:43:04 lukem Exp $
+.\"
+.\" from: #Id: hesiod.3,v 1.9.2.1 1997/01/03 21:02:23 ghudson Exp #
+.\"
+.\" Copyright 1988, 1996 by the Massachusetts Institute of Technology.
+.\"
+.\" Permission to use, copy, modify, and distribute this
+.\" software and its documentation for any purpose and without
+.\" fee is hereby granted, provided that the above copyright
+.\" notice appear in all copies and that both that copyright
+.\" notice and this permission notice appear in supporting
+.\" documentation, and that the name of M.I.T. not be used in
+.\" advertising or publicity pertaining to distribution of the
+.\" software without specific, written prior permission.
+.\" M.I.T. makes no representations about the suitability of
+.\" this software for any purpose. It is provided "as is"
+.\" without express or implied warranty.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd November 30, 1996
+.Dt HESIOD 3
+.Os
+.Sh NAME
+.Nm hesiod ,
+.Nm hesiod_init ,
+.Nm hesiod_resolve ,
+.Nm hesiod_free_list ,
+.Nm hesiod_to_bind ,
+.Nm hesiod_end
+.Nd Hesiod name server interface library
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In hesiod.h
+.Ft int
+.Fn hesiod_init "void **context"
+.Ft char **
+.Fn hesiod_resolve "void *context" "const char *name" "const char *type"
+.Ft void
+.Fn hesiod_free_list "void *context" "char **list"
+.Ft char *
+.Fn hesiod_to_bind "void *context" "const char *name" "const char *type"
+.Ft void
+.Fn hesiod_end "void *context"
+.Sh DESCRIPTION
+This family of functions allows you to perform lookups of Hesiod
+information, which is stored as text records in the Domain Name
+Service.
+To perform lookups, you must first initialize a
+.Fa context ,
+an opaque object which stores information used internally by the
+library between calls.
+The
+.Fn hesiod_init
+function
+initializes a context, storing a pointer to the context in the
+location pointed to by the
+.Fa context
+argument.
+The
+.Fn hesiod_end
+function
+frees the resources used by a context.
+.Pp
+The
+.Fn hesiod_resolve
+function
+is the primary interface to the library.
+If successful, it returns a
+list of one or more strings giving the records matching
+.Fa name
+and
+.Fa type .
+The last element of the list is followed by a
+.Dv NULL
+pointer.
+It is the
+caller's responsibility to call
+.Fn hesiod_free_list
+to free the resources used by the returned list.
+.Pp
+The
+.Fn hesiod_to_bind
+function
+converts
+.Fa name
+and
+.Fa type
+into the DNS name used by
+.Fn hesiod_resolve .
+It is the caller's responsibility to free the returned string using
+.Fn free .
+.Sh RETURN VALUES
+.Rv -std hesiod_init
+On failure,
+.Fn hesiod_resolve
+and
+.Fn hesiod_to_bind
+return
+.Dv NULL
+and set the global variable
+.Va errno
+to indicate the error.
+.Sh ENVIRONMENT
+.Bl -tag -width HESIOD_CONFIG
+.It Ev HES_DOMAIN
+If the environment variable
+.Ev HES_DOMAIN
+is set, it will override the domain in the Hesiod configuration file.
+.It Ev HESIOD_CONFIG
+If the environment variable
+.Ev HESIOD_CONFIG
+is set, it specifies the location of the Hesiod configuration file.
+.El
+.Sh ERRORS
+Hesiod calls may fail because of:
+.Bl -tag -width Er
+.It Bq Er ENOMEM
+Insufficient memory was available to carry out the requested
+operation.
+.It Bq Er ENOEXEC
+The
+.Fn hesiod_init
+function
+failed because the Hesiod configuration file was invalid.
+.It Bq Er ECONNREFUSED
+The
+.Fn hesiod_resolve
+function
+failed because no name server could be contacted to answer the query.
+.It Bq Er EMSGSIZE
+The
+.Fn hesiod_resolve
+or
+.Fn hesiod_to_bind
+function
+failed because the query or response was too big to fit into the
+packet buffers.
+.It Bq Er ENOENT
+The
+.Fn hesiod_resolve
+function
+failed because the name server had no text records matching
+.Fa name
+and
+.Fa type ,
+or
+.Fn hesiod_to_bind
+failed because the
+.Fa name
+argument had a domain extension which could not be resolved with type
+.Dq rhs\-extension
+in the local Hesiod domain.
+.El
+.Sh SEE ALSO
+.Xr hesiod.conf 5 ,
+.Xr named 8
+.Rs
+.%T "Hesiod - Project Athena Technical Plan -- Name Service"
+.Re
+.Sh AUTHORS
+.An Steve Dyer ,
+IBM/Project Athena
+.An Greg Hudson ,
+MIT Team Athena
+.Pp
+Copyright 1987, 1988, 1995, 1996 by the Massachusetts Institute of Technology.
+.Sh BUGS
+The strings corresponding to the
+.Va errno
+values set by the Hesiod functions are not particularly indicative of
+what went wrong, especially for
+.Er ENOEXEC
+and
+.Er ENOENT .
diff --git a/lib/libc/net/hesiod.c b/lib/libc/net/hesiod.c
new file mode 100644
index 000000000000..0966b6d7ef91
--- /dev/null
+++ b/lib/libc/net/hesiod.c
@@ -0,0 +1,583 @@
+/* $NetBSD: hesiod.c,v 1.9 1999/02/11 06:16:38 simonb Exp $ */
+
+/* Copyright (c) 1996 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/* Copyright 1996 by the Massachusetts Institute of Technology.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software and its documentation for any purpose and without
+ * fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in
+ * advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ */
+
+/* This file is part of the hesiod library. It implements the core
+ * portion of the hesiod resolver.
+ *
+ * This file is loosely based on an interim version of hesiod.c from
+ * the BIND IRS library, which was in turn based on an earlier version
+ * of this file. Extensive changes have been made on each step of the
+ * path.
+ *
+ * This implementation is not truly thread-safe at the moment because
+ * it uses res_send() and accesses _res.
+ */
+
+#include <sys/cdefs.h>
+
+#if 0
+static char *orig_rcsid = "$NetBSD: hesiod.c,v 1.9 1999/02/11 06:16:38 simonb Exp $";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <hesiod.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+struct hesiod_p {
+ char *lhs; /* normally ".ns" */
+ char *rhs; /* AKA the default hesiod domain */
+ int classes[2]; /* The class search order. */
+};
+
+#define MAX_HESRESP 1024
+
+static int read_config_file(struct hesiod_p *, const char *);
+static char **get_txt_records(int, const char *);
+static int init_context(void);
+static void translate_errors(void);
+
+
+/*
+ * hesiod_init --
+ * initialize a hesiod_p.
+ */
+int
+hesiod_init(context)
+ void **context;
+{
+ struct hesiod_p *ctx;
+ const char *p, *configname;
+
+ ctx = malloc(sizeof(struct hesiod_p));
+ if (ctx) {
+ *context = ctx;
+ if (!issetugid())
+ configname = getenv("HESIOD_CONFIG");
+ else
+ configname = NULL;
+ if (!configname)
+ configname = _PATH_HESIOD_CONF;
+ if (read_config_file(ctx, configname) >= 0) {
+ /*
+ * The default rhs can be overridden by an
+ * environment variable.
+ */
+ if (!issetugid())
+ p = getenv("HES_DOMAIN");
+ else
+ p = NULL;
+ if (p) {
+ if (ctx->rhs)
+ free(ctx->rhs);
+ ctx->rhs = malloc(strlen(p) + 2);
+ if (ctx->rhs) {
+ *ctx->rhs = '.';
+ strcpy(ctx->rhs + 1,
+ (*p == '.') ? p + 1 : p);
+ return 0;
+ } else
+ errno = ENOMEM;
+ } else
+ return 0;
+ }
+ } else
+ errno = ENOMEM;
+
+ if (ctx->lhs)
+ free(ctx->lhs);
+ if (ctx->rhs)
+ free(ctx->rhs);
+ if (ctx)
+ free(ctx);
+ return -1;
+}
+
+/*
+ * hesiod_end --
+ * Deallocates the hesiod_p.
+ */
+void
+hesiod_end(context)
+ void *context;
+{
+ struct hesiod_p *ctx = (struct hesiod_p *) context;
+
+ free(ctx->rhs);
+ if (ctx->lhs)
+ free(ctx->lhs);
+ free(ctx);
+}
+
+/*
+ * hesiod_to_bind --
+ * takes a hesiod (name, type) and returns a DNS
+ * name which is to be resolved.
+ */
+char *
+hesiod_to_bind(void *context, const char *name, const char *type)
+{
+ struct hesiod_p *ctx = (struct hesiod_p *) context;
+ char bindname[MAXDNAME], *p, *ret, **rhs_list = NULL;
+ const char *rhs;
+ int len;
+
+ if (strlcpy(bindname, name, sizeof(bindname)) >= sizeof(bindname)) {
+ errno = EMSGSIZE;
+ return NULL;
+ }
+
+ /*
+ * Find the right right hand side to use, possibly
+ * truncating bindname.
+ */
+ p = strchr(bindname, '@');
+ if (p) {
+ *p++ = 0;
+ if (strchr(p, '.'))
+ rhs = name + (p - bindname);
+ else {
+ rhs_list = hesiod_resolve(context, p, "rhs-extension");
+ if (rhs_list)
+ rhs = *rhs_list;
+ else {
+ errno = ENOENT;
+ return NULL;
+ }
+ }
+ } else
+ rhs = ctx->rhs;
+
+ /* See if we have enough room. */
+ len = strlen(bindname) + 1 + strlen(type);
+ if (ctx->lhs)
+ len += strlen(ctx->lhs) + ((ctx->lhs[0] != '.') ? 1 : 0);
+ len += strlen(rhs) + ((rhs[0] != '.') ? 1 : 0);
+ if (len > sizeof(bindname) - 1) {
+ if (rhs_list)
+ hesiod_free_list(context, rhs_list);
+ errno = EMSGSIZE;
+ return NULL;
+ }
+ /* Put together the rest of the domain. */
+ strcat(bindname, ".");
+ strcat(bindname, type);
+ /* Only append lhs if it isn't empty. */
+ if (ctx->lhs && ctx->lhs[0] != '\0' ) {
+ if (ctx->lhs[0] != '.')
+ strcat(bindname, ".");
+ strcat(bindname, ctx->lhs);
+ }
+ if (rhs[0] != '.')
+ strcat(bindname, ".");
+ strcat(bindname, rhs);
+
+ /* rhs_list is no longer needed, since we're done with rhs. */
+ if (rhs_list)
+ hesiod_free_list(context, rhs_list);
+
+ /* Make a copy of the result and return it to the caller. */
+ ret = strdup(bindname);
+ if (!ret)
+ errno = ENOMEM;
+ return ret;
+}
+
+/*
+ * hesiod_resolve --
+ * Given a hesiod name and type, return an array of strings returned
+ * by the resolver.
+ */
+char **
+hesiod_resolve(context, name, type)
+ void *context;
+ const char *name;
+ const char *type;
+{
+ struct hesiod_p *ctx = (struct hesiod_p *) context;
+ char *bindname, **retvec;
+
+ bindname = hesiod_to_bind(context, name, type);
+ if (!bindname)
+ return NULL;
+
+ retvec = get_txt_records(ctx->classes[0], bindname);
+ if (retvec == NULL && errno == ENOENT && ctx->classes[1])
+ retvec = get_txt_records(ctx->classes[1], bindname);
+
+ free(bindname);
+ return retvec;
+}
+
+/*ARGSUSED*/
+void
+hesiod_free_list(context, list)
+ void *context;
+ char **list;
+{
+ char **p;
+
+ if (list == NULL)
+ return;
+ for (p = list; *p; p++)
+ free(*p);
+ free(list);
+}
+
+
+/* read_config_file --
+ * Parse the /etc/hesiod.conf file. Returns 0 on success,
+ * -1 on failure. On failure, it might leave values in ctx->lhs
+ * or ctx->rhs which need to be freed by the caller.
+ */
+static int
+read_config_file(ctx, filename)
+ struct hesiod_p *ctx;
+ const char *filename;
+{
+ char *key, *data, *p, **which;
+ char buf[MAXDNAME + 7];
+ int n;
+ FILE *fp;
+
+ /* Set default query classes. */
+ ctx->classes[0] = C_IN;
+ ctx->classes[1] = C_HS;
+
+ /* Try to open the configuration file. */
+ fp = fopen(filename, "re");
+ if (!fp) {
+ /* Use compiled in default domain names. */
+ ctx->lhs = strdup(DEF_LHS);
+ ctx->rhs = strdup(DEF_RHS);
+ if (ctx->lhs && ctx->rhs)
+ return 0;
+ else {
+ errno = ENOMEM;
+ return -1;
+ }
+ }
+ ctx->lhs = NULL;
+ ctx->rhs = NULL;
+ while (fgets(buf, sizeof(buf), fp) != NULL) {
+ p = buf;
+ if (*p == '#' || *p == '\n' || *p == '\r')
+ continue;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ key = p;
+ while (*p != ' ' && *p != '\t' && *p != '=')
+ p++;
+ *p++ = 0;
+
+ while (isspace(*p) || *p == '=')
+ p++;
+ data = p;
+ while (!isspace(*p))
+ p++;
+ *p = 0;
+
+ if (strcasecmp(key, "lhs") == 0 ||
+ strcasecmp(key, "rhs") == 0) {
+ which = (strcasecmp(key, "lhs") == 0)
+ ? &ctx->lhs : &ctx->rhs;
+ *which = strdup(data);
+ if (!*which) {
+ fclose(fp);
+ errno = ENOMEM;
+ return -1;
+ }
+ } else {
+ if (strcasecmp(key, "classes") == 0) {
+ n = 0;
+ while (*data && n < 2) {
+ p = data;
+ while (*p && *p != ',')
+ p++;
+ if (*p)
+ *p++ = 0;
+ if (strcasecmp(data, "IN") == 0)
+ ctx->classes[n++] = C_IN;
+ else
+ if (strcasecmp(data, "HS") == 0)
+ ctx->classes[n++] =
+ C_HS;
+ data = p;
+ }
+ while (n < 2)
+ ctx->classes[n++] = 0;
+ }
+ }
+ }
+ fclose(fp);
+
+ if (!ctx->rhs || ctx->classes[0] == 0 ||
+ ctx->classes[0] == ctx->classes[1]) {
+ errno = ENOEXEC;
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * get_txt_records --
+ * Given a DNS class and a DNS name, do a lookup for TXT records, and
+ * return a list of them.
+ */
+static char **
+get_txt_records(qclass, name)
+ int qclass;
+ const char *name;
+{
+ HEADER *hp;
+ unsigned char qbuf[PACKETSZ], abuf[MAX_HESRESP], *p, *eom, *eor;
+ char *dst, **list;
+ int ancount, qdcount, i, j, n, skip, type, class, len;
+
+ /* Make sure the resolver is initialized. */
+ if ((_res.options & RES_INIT) == 0 && res_init() == -1)
+ return NULL;
+
+ /* Construct the query. */
+ n = res_mkquery(QUERY, name, qclass, T_TXT, NULL, 0,
+ NULL, qbuf, PACKETSZ);
+ if (n < 0)
+ return NULL;
+
+ /* Send the query. */
+ n = res_send(qbuf, n, abuf, MAX_HESRESP);
+ if (n < 0 || n > MAX_HESRESP) {
+ errno = ECONNREFUSED; /* XXX */
+ return NULL;
+ }
+ /* Parse the header of the result. */
+ hp = (HEADER *) (void *) abuf;
+ ancount = ntohs(hp->ancount);
+ qdcount = ntohs(hp->qdcount);
+ p = abuf + sizeof(HEADER);
+ eom = abuf + n;
+
+ /*
+ * Skip questions, trying to get to the answer section
+ * which follows.
+ */
+ for (i = 0; i < qdcount; i++) {
+ skip = dn_skipname(p, eom);
+ if (skip < 0 || p + skip + QFIXEDSZ > eom) {
+ errno = EMSGSIZE;
+ return NULL;
+ }
+ p += skip + QFIXEDSZ;
+ }
+
+ /* Allocate space for the text record answers. */
+ list = malloc((ancount + 1) * sizeof(char *));
+ if (!list) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ /* Parse the answers. */
+ j = 0;
+ for (i = 0; i < ancount; i++) {
+ /* Parse the header of this answer. */
+ skip = dn_skipname(p, eom);
+ if (skip < 0 || p + skip + 10 > eom)
+ break;
+ type = p[skip + 0] << 8 | p[skip + 1];
+ class = p[skip + 2] << 8 | p[skip + 3];
+ len = p[skip + 8] << 8 | p[skip + 9];
+ p += skip + 10;
+ if (p + len > eom) {
+ errno = EMSGSIZE;
+ break;
+ }
+ /* Skip entries of the wrong class and type. */
+ if (class != qclass || type != T_TXT) {
+ p += len;
+ continue;
+ }
+ /* Allocate space for this answer. */
+ list[j] = malloc((size_t)len);
+ if (!list[j]) {
+ errno = ENOMEM;
+ break;
+ }
+ dst = list[j++];
+
+ /* Copy answer data into the allocated area. */
+ eor = p + len;
+ while (p < eor) {
+ n = (unsigned char) *p++;
+ if (p + n > eor) {
+ errno = EMSGSIZE;
+ break;
+ }
+ memcpy(dst, p, (size_t)n);
+ p += n;
+ dst += n;
+ }
+ if (p < eor) {
+ errno = EMSGSIZE;
+ break;
+ }
+ *dst = 0;
+ }
+
+ /*
+ * If we didn't terminate the loop normally, something
+ * went wrong.
+ */
+ if (i < ancount) {
+ for (i = 0; i < j; i++)
+ free(list[i]);
+ free(list);
+ return NULL;
+ }
+ if (j == 0) {
+ errno = ENOENT;
+ free(list);
+ return NULL;
+ }
+ list[j] = NULL;
+ return list;
+}
+
+ /*
+ * COMPATIBILITY FUNCTIONS
+ */
+
+static int inited = 0;
+static void *context;
+static int errval = HES_ER_UNINIT;
+
+int
+hes_init()
+{
+ init_context();
+ return errval;
+}
+
+char *
+hes_to_bind(name, type)
+ const char *name;
+ const char *type;
+{
+ static char *bindname;
+ if (init_context() < 0)
+ return NULL;
+ if (bindname)
+ free(bindname);
+ bindname = hesiod_to_bind(context, name, type);
+ if (!bindname)
+ translate_errors();
+ return bindname;
+}
+
+char **
+hes_resolve(name, type)
+ const char *name;
+ const char *type;
+{
+ static char **list;
+
+ if (init_context() < 0)
+ return NULL;
+
+ /*
+ * In the old Hesiod interface, the caller was responsible for
+ * freeing the returned strings but not the vector of strings itself.
+ */
+ if (list)
+ free(list);
+
+ list = hesiod_resolve(context, name, type);
+ if (!list)
+ translate_errors();
+ return list;
+}
+
+int
+hes_error()
+{
+ return errval;
+}
+
+void
+hes_free(hp)
+ char **hp;
+{
+ hesiod_free_list(context, hp);
+}
+
+static int
+init_context()
+{
+ if (!inited) {
+ inited = 1;
+ if (hesiod_init(&context) < 0) {
+ errval = HES_ER_CONFIG;
+ return -1;
+ }
+ errval = HES_ER_OK;
+ }
+ return 0;
+}
+
+static void
+translate_errors()
+{
+ switch (errno) {
+ case ENOENT:
+ errval = HES_ER_NOTFOUND;
+ break;
+ case ECONNREFUSED:
+ case EMSGSIZE:
+ errval = HES_ER_NET;
+ break;
+ case ENOMEM:
+ default:
+ /* Not a good match, but the best we can do. */
+ errval = HES_ER_CONFIG;
+ break;
+ }
+}
diff --git a/lib/libc/net/if_indextoname.3 b/lib/libc/net/if_indextoname.3
new file mode 100644
index 000000000000..715c33cfedcd
--- /dev/null
+++ b/lib/libc/net/if_indextoname.3
@@ -0,0 +1,152 @@
+.\" $KAME: if_indextoname.3,v 1.10 2000/11/24 08:13:51 itojun Exp $
+.\" BSDI Id: if_indextoname.3,v 2.2 2000/04/17 22:38:05 dab Exp
+.\"
+.\" Copyright (c) 1997, 2000
+.\" Berkeley Software Design, Inc. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd November 23, 2005
+.Dt IF_NAMETOINDEX 3
+.Os
+.Sh NAME
+.Nm if_nametoindex ,
+.Nm if_indextoname ,
+.Nm if_nameindex ,
+.Nm if_freenameindex
+.Nd provide mappings between interface names and indexes
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/socket.h
+.In net/if.h
+.Ft "unsigned int"
+.Fn if_nametoindex "const char *ifname"
+.Ft "char *"
+.Fn if_indextoname "unsigned int ifindex" "char *ifname"
+.Ft "struct if_nameindex *"
+.Fn if_nameindex "void"
+.Ft void
+.Fn if_freenameindex "struct if_nameindex *ptr"
+.Sh DESCRIPTION
+The
+.Fn if_nametoindex
+function maps the interface name specified in
+.Fa ifname
+to its corresponding index.
+If the specified interface does not exist, it returns 0.
+.Pp
+The
+.Fn if_indextoname
+function maps the interface index specified in
+.Fa ifindex
+to it corresponding name, which is copied into the
+buffer pointed to by
+.Fa ifname ,
+which must be of at least
+.Dv IFNAMSIZ
+bytes.
+This pointer is also the return value of the function.
+If there is no interface corresponding to the specified
+index,
+.Dv NULL
+is returned.
+.Pp
+The
+.Fn if_nameindex
+function returns an array of
+.Vt if_nameindex
+structures, one structure per interface, as
+defined in the include file
+.In net/if.h .
+The
+.Vt if_nameindex
+structure contains at least the following entries:
+.Bd -literal
+ unsigned int if_index; /* 1, 2, ... */
+ char *if_name; /* null terminated name: "le0", ... */
+.Ed
+.Pp
+The end of the array of structures is indicated by a structure with an
+.Va if_index
+of 0 and an
+.Va if_name
+of
+.Dv NULL .
+A
+.Dv NULL
+pointer is returned upon an error.
+.Pp
+The
+.Fn if_freenameindex
+function frees the dynamic memory that was
+allocated by
+.Fn if_nameindex .
+.Sh RETURN VALUES
+Upon successful completion,
+.Fn if_nametoindex
+returns the index number of the interface.
+If the interface is not found, a value of 0 is returned and
+.Va errno
+is set to
+.Er ENXIO .
+A value of 0 is also returned if an error
+occurs while retrieving the list of interfaces via
+.Xr getifaddrs 3 .
+.Pp
+Upon successful completion,
+.Fn if_indextoname
+returns
+.Fa ifname .
+If the interface is not found, a
+.Dv NULL
+pointer is returned and
+.Va errno
+is set to
+.Er ENXIO .
+A
+.Dv NULL
+pointer is also returned if an error
+occurs while retrieving the list of interfaces via
+.Xr getifaddrs 3 .
+.Pp
+The
+.Fn if_nameindex
+returns a
+.Dv NULL
+pointer if an error
+occurs while retrieving the list of interfaces via
+.Xr getifaddrs 3 ,
+or if sufficient memory cannot be allocated.
+.Sh SEE ALSO
+.Xr getifaddrs 3 ,
+.Xr networking 4
+.Sh STANDARDS
+The
+.Fn if_nametoindex ,
+.Fn if_indextoname ,
+.Fn if_nameindex ,
+and
+.Fn if_freenameindex
+functions conform to
+.%T "RFC 2553" .
+.Sh HISTORY
+The implementation first appeared in BSDi
+.Bsx .
diff --git a/lib/libc/net/if_indextoname.c b/lib/libc/net/if_indextoname.c
new file mode 100644
index 000000000000..4b16433a4ee6
--- /dev/null
+++ b/lib/libc/net/if_indextoname.c
@@ -0,0 +1,88 @@
+/* $KAME: if_indextoname.c,v 1.7 2000/11/08 03:09:30 itojun Exp $ */
+
+/*-
+ * Copyright (c) 1997, 2000
+ * Berkeley Software Design, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BSDI Id: if_indextoname.c,v 2.3 2000/04/17 22:38:05 dab Exp
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <net/if_dl.h>
+#include <net/if.h>
+#include <ifaddrs.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+/*
+ * From RFC 2533:
+ *
+ * The second function maps an interface index into its corresponding
+ * name.
+ *
+ * #include <net/if.h>
+ *
+ * char *if_indextoname(unsigned int ifindex, char *ifname);
+ *
+ * The ifname argument must point to a buffer of at least IF_NAMESIZE
+ * bytes into which the interface name corresponding to the specified
+ * index is returned. (IF_NAMESIZE is also defined in <net/if.h> and
+ * its value includes a terminating null byte at the end of the
+ * interface name.) This pointer is also the return value of the
+ * function. If there is no interface corresponding to the specified
+ * index, NULL is returned, and errno is set to ENXIO, if there was a
+ * system error (such as running out of memory), if_indextoname returns
+ * NULL and errno would be set to the proper value (e.g., ENOMEM).
+ */
+
+char *
+if_indextoname(unsigned int ifindex, char *ifname)
+{
+ struct ifaddrs *ifaddrs, *ifa;
+ int error = 0;
+
+ if (getifaddrs(&ifaddrs) < 0)
+ return(NULL); /* getifaddrs properly set errno */
+
+ for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr &&
+ ifa->ifa_addr->sa_family == AF_LINK &&
+ ifindex == LLINDEX((struct sockaddr_dl*)ifa->ifa_addr))
+ break;
+ }
+
+ if (ifa == NULL) {
+ error = ENXIO;
+ ifname = NULL;
+ }
+ else
+ strncpy(ifname, ifa->ifa_name, IFNAMSIZ);
+
+ freeifaddrs(ifaddrs);
+
+ errno = error;
+ return(ifname);
+}
diff --git a/lib/libc/net/if_nameindex.c b/lib/libc/net/if_nameindex.c
new file mode 100644
index 000000000000..138289c6814e
--- /dev/null
+++ b/lib/libc/net/if_nameindex.c
@@ -0,0 +1,147 @@
+/* $KAME: if_nameindex.c,v 1.8 2000/11/24 08:20:01 itojun Exp $ */
+
+/*-
+ * Copyright (c) 1997, 2000
+ * Berkeley Software Design, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BSDI Id: if_nameindex.c,v 2.3 2000/04/17 22:38:05 dab Exp
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <net/if_dl.h>
+#include <net/if.h>
+#include <ifaddrs.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * From RFC 2553:
+ *
+ * 4.3 Return All Interface Names and Indexes
+ *
+ * The if_nameindex structure holds the information about a single
+ * interface and is defined as a result of including the <net/if.h>
+ * header.
+ *
+ * struct if_nameindex {
+ * unsigned int if_index;
+ * char *if_name;
+ * };
+ *
+ * The final function returns an array of if_nameindex structures, one
+ * structure per interface.
+ *
+ * struct if_nameindex *if_nameindex(void);
+ *
+ * The end of the array of structures is indicated by a structure with
+ * an if_index of 0 and an if_name of NULL. The function returns a NULL
+ * pointer upon an error, and would set errno to the appropriate value.
+ *
+ * The memory used for this array of structures along with the interface
+ * names pointed to by the if_name members is obtained dynamically.
+ * This memory is freed by the next function.
+ *
+ * 4.4. Free Memory
+ *
+ * The following function frees the dynamic memory that was allocated by
+ * if_nameindex().
+ *
+ * #include <net/if.h>
+ *
+ * void if_freenameindex(struct if_nameindex *ptr);
+ *
+ * The argument to this function must be a pointer that was returned by
+ * if_nameindex().
+ */
+
+struct if_nameindex *
+if_nameindex(void)
+{
+ struct ifaddrs *ifaddrs, *ifa;
+ unsigned int ni;
+ int nbytes;
+ struct if_nameindex *ifni, *ifni2;
+ char *cp;
+
+ if (getifaddrs(&ifaddrs) < 0)
+ return(NULL);
+
+ /*
+ * First, find out how many interfaces there are, and how
+ * much space we need for the string names.
+ */
+ ni = 0;
+ nbytes = 0;
+ for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr &&
+ ifa->ifa_addr->sa_family == AF_LINK) {
+ nbytes += strlen(ifa->ifa_name) + 1;
+ ni++;
+ }
+ }
+
+ /*
+ * Next, allocate a chunk of memory, use the first part
+ * for the array of structures, and the last part for
+ * the strings.
+ */
+ cp = malloc((ni + 1) * sizeof(struct if_nameindex) + nbytes);
+ ifni = (struct if_nameindex *)cp;
+ if (ifni == NULL)
+ goto out;
+ cp += (ni + 1) * sizeof(struct if_nameindex);
+
+ /*
+ * Now just loop through the list of interfaces again,
+ * filling in the if_nameindex array and making copies
+ * of all the strings.
+ */
+ ifni2 = ifni;
+ for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr &&
+ ifa->ifa_addr->sa_family == AF_LINK) {
+ ifni2->if_index =
+ LLINDEX((struct sockaddr_dl*)ifa->ifa_addr);
+ ifni2->if_name = cp;
+ strcpy(cp, ifa->ifa_name);
+ ifni2++;
+ cp += strlen(cp) + 1;
+ }
+ }
+ /*
+ * Finally, don't forget to terminate the array.
+ */
+ ifni2->if_index = 0;
+ ifni2->if_name = NULL;
+out:
+ freeifaddrs(ifaddrs);
+ return(ifni);
+}
+
+void
+if_freenameindex(struct if_nameindex *ptr)
+{
+ free(ptr);
+}
diff --git a/lib/libc/net/if_nametoindex.c b/lib/libc/net/if_nametoindex.c
new file mode 100644
index 000000000000..debf3fabc6af
--- /dev/null
+++ b/lib/libc/net/if_nametoindex.c
@@ -0,0 +1,100 @@
+/* $KAME: if_nametoindex.c,v 1.6 2000/11/24 08:18:54 itojun Exp $ */
+
+/*-
+ * Copyright (c) 1997, 2000
+ * Berkeley Software Design, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BSDI Id: if_nametoindex.c,v 2.3 2000/04/17 22:38:05 dab Exp
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <ifaddrs.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+/*
+ * From RFC 2553:
+ *
+ * 4.1 Name-to-Index
+ *
+ *
+ * The first function maps an interface name into its corresponding
+ * index.
+ *
+ * #include <net/if.h>
+ *
+ * unsigned int if_nametoindex(const char *ifname);
+ *
+ * If the specified interface name does not exist, the return value is
+ * 0, and errno is set to ENXIO. If there was a system error (such as
+ * running out of memory), the return value is 0 and errno is set to the
+ * proper value (e.g., ENOMEM).
+ */
+
+unsigned int
+if_nametoindex(const char *ifname)
+{
+ int s;
+ struct ifreq ifr;
+ struct ifaddrs *ifaddrs, *ifa;
+ unsigned int ni;
+
+ s = _socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+ if (s != -1) {
+ memset(&ifr, 0, sizeof(ifr));
+ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ if (_ioctl(s, SIOCGIFINDEX, &ifr) != -1) {
+ _close(s);
+ return (ifr.ifr_index);
+ }
+ _close(s);
+ }
+
+ if (getifaddrs(&ifaddrs) < 0)
+ return(0);
+
+ ni = 0;
+
+ for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr &&
+ ifa->ifa_addr->sa_family == AF_LINK &&
+ strcmp(ifa->ifa_name, ifname) == 0) {
+ ni = LLINDEX((struct sockaddr_dl*)ifa->ifa_addr);
+ break;
+ }
+ }
+
+ freeifaddrs(ifaddrs);
+ if (!ni)
+ errno = ENXIO;
+ return(ni);
+}
diff --git a/lib/libc/net/inet.3 b/lib/libc/net/inet.3
new file mode 100644
index 000000000000..af48143d9f68
--- /dev/null
+++ b/lib/libc/net/inet.3
@@ -0,0 +1,305 @@
+.\" Copyright (c) 1983, 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" From: @(#)inet.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 14, 2007
+.Dt INET 3
+.Os
+.Sh NAME
+.Nm inet_aton ,
+.Nm inet_addr ,
+.Nm inet_network ,
+.Nm inet_ntoa ,
+.Nm inet_ntoa_r ,
+.Nm inet_ntop ,
+.Nm inet_pton ,
+.Nm inet_makeaddr ,
+.Nm inet_lnaof ,
+.Nm inet_netof
+.Nd Internet address manipulation routines
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/socket.h
+.In netinet/in.h
+.In arpa/inet.h
+.Ft int
+.Fn inet_aton "const char *cp" "struct in_addr *pin"
+.Ft in_addr_t
+.Fn inet_addr "const char *cp"
+.Ft in_addr_t
+.Fn inet_network "const char *cp"
+.Ft char *
+.Fn inet_ntoa "struct in_addr in"
+.Ft char *
+.Fo inet_ntoa_r
+.Fa "struct in_addr in"
+.Fa "char *buf"
+.Fa "socklen_t size"
+.Fc
+.Ft const char *
+.Fo inet_ntop
+.Fa "int af"
+.Fa "const void * restrict src"
+.Fa "char * restrict dst"
+.Fa "socklen_t size"
+.Fc
+.Ft int
+.Fn inet_pton "int af" "const char * restrict src" "void * restrict dst"
+.Ft struct in_addr
+.Fn inet_makeaddr "in_addr_t net" "in_addr_t lna"
+.Ft in_addr_t
+.Fn inet_lnaof "struct in_addr in"
+.Ft in_addr_t
+.Fn inet_netof "struct in_addr in"
+.Sh DESCRIPTION
+The routines
+.Fn inet_aton ,
+.Fn inet_addr
+and
+.Fn inet_network
+interpret character strings representing
+numbers expressed in the Internet standard
+.Ql .\&
+notation.
+.Pp
+The
+.Fn inet_pton
+function converts a presentation format address (that is, printable form
+as held in a character string) to network format (usually a
+.Ft struct in_addr
+or some other internal binary representation, in network byte order).
+It returns 1 if the address was valid for the specified address family, or
+0 if the address was not parseable in the specified address family, or -1
+if some system error occurred (in which case
+.Va errno
+will have been set).
+This function is presently valid for
+.Dv AF_INET
+and
+.Dv AF_INET6 .
+.Pp
+The
+.Fn inet_aton
+routine interprets the specified character string as an Internet address,
+placing the address into the structure provided.
+It returns 1 if the string was successfully interpreted,
+or 0 if the string is invalid.
+The
+.Fn inet_addr
+and
+.Fn inet_network
+functions return numbers suitable for use
+as Internet addresses and Internet network
+numbers, respectively.
+.Pp
+The function
+.Fn inet_ntop
+converts an address
+.Fa *src
+from network format
+(usually a
+.Ft struct in_addr
+or some other binary form, in network byte order) to presentation format
+(suitable for external display purposes).
+The
+.Fa size
+argument specifies the size, in bytes, of the buffer
+.Fa *dst .
+.Dv INET_ADDRSTRLEN
+and
+.Dv INET6_ADDRSTRLEN
+define the maximum size required to convert an address of the respective
+type.
+It returns NULL if a system error occurs (in which case,
+.Va errno
+will have been set), or it returns a pointer to the destination string.
+This function is presently valid for
+.Dv AF_INET
+and
+.Dv AF_INET6 .
+.Pp
+The routine
+.Fn inet_ntoa
+takes an Internet address and returns an
+.Tn ASCII
+string representing the address in
+.Ql .\&
+notation.
+The routine
+.Fn inet_ntoa_r
+is the reentrant version of
+.Fn inet_ntoa .
+The routine
+.Fn inet_makeaddr
+takes an Internet network number and a local
+network address and constructs an Internet address
+from it.
+The routines
+.Fn inet_netof
+and
+.Fn inet_lnaof
+break apart Internet host addresses, returning
+the network number and local network address part,
+respectively.
+.Pp
+All Internet addresses are returned in network
+order (bytes ordered from left to right).
+All network numbers and local address parts are
+returned as machine byte order integer values.
+.Sh INTERNET ADDRESSES
+Values specified using the
+.Ql .\&
+notation take one
+of the following forms:
+.Bd -literal -offset indent
+a.b.c.d
+a.b.c
+a.b
+a
+.Ed
+.Pp
+When four parts are specified, each is interpreted
+as a byte of data and assigned, from left to right,
+to the four bytes of an Internet address.
+Note
+that when an Internet address is viewed as a 32-bit
+integer quantity on the
+.Tn VAX
+the bytes referred to
+above appear as
+.Dq Li d.c.b.a .
+That is,
+.Tn VAX
+bytes are
+ordered from right to left.
+.Pp
+When a three part address is specified, the last
+part is interpreted as a 16-bit quantity and placed
+in the right-most two bytes of the network address.
+This makes the three part address format convenient
+for specifying Class B network addresses as
+.Dq Li 128.net.host .
+.Pp
+When a two part address is supplied, the last part
+is interpreted as a 24-bit quantity and placed in
+the right most three bytes of the network address.
+This makes the two part address format convenient
+for specifying Class A network addresses as
+.Dq Li net.host .
+.Pp
+When only one part is given, the value is stored
+directly in the network address without any byte
+rearrangement.
+.Pp
+All numbers supplied as
+.Dq parts
+in a
+.Ql .\&
+notation
+may be decimal, octal, or hexadecimal, as specified
+in the C language (i.e., a leading 0x or 0X implies
+hexadecimal; otherwise, a leading 0 implies octal;
+otherwise, the number is interpreted as decimal).
+.Sh DIAGNOSTICS
+The constant
+.Dv INADDR_NONE
+is returned by
+.Fn inet_addr
+and
+.Fn inet_network
+for malformed requests.
+.Sh ERRORS
+The
+.Fn inet_ntop
+call fails if:
+.Bl -tag -width Er
+.It Bq Er ENOSPC
+.Fa size
+was not large enough to store the presentation form of the address.
+.It Bq Er EAFNOSUPPORT
+.Fa *src
+was not an
+.Dv AF_INET
+or
+.Dv AF_INET6
+family address.
+.El
+.Sh SEE ALSO
+.Xr byteorder 3 ,
+.Xr getaddrinfo 3 ,
+.Xr gethostbyname 3 ,
+.Xr getnameinfo 3 ,
+.Xr getnetent 3 ,
+.Xr inet_net 3 ,
+.Xr hosts 5 ,
+.Xr networks 5
+.Rs
+.%R RFC
+.%N 2373
+.%D July 1998
+.%T "IP Version 6 Addressing Architecture"
+.Re
+.Sh STANDARDS
+The
+.Fn inet_ntop
+and
+.Fn inet_pton
+functions conform to
+.St -xns5.2 .
+Note that
+.Fn inet_pton
+does not accept 1-, 2-, or 3-part dotted addresses; all four parts
+must be specified and are interpreted only as decimal values.
+This is a narrower input set than that accepted by
+.Fn inet_aton .
+.Sh HISTORY
+These
+functions appeared in
+.Bx 4.2 .
+.Sh BUGS
+The value
+.Dv INADDR_NONE
+(0xffffffff) is a valid broadcast address, but
+.Fn inet_addr
+cannot return that value without indicating failure.
+The newer
+.Fn inet_aton
+function does not share this problem.
+The problem of host byte ordering versus network byte ordering is
+confusing.
+The string returned by
+.Fn inet_ntoa
+resides in a static memory area.
+.Pp
+The
+.Fn inet_addr
+function should return a
+.Fa struct in_addr .
diff --git a/lib/libc/net/inet6_opt_init.3 b/lib/libc/net/inet6_opt_init.3
new file mode 100644
index 000000000000..671346818470
--- /dev/null
+++ b/lib/libc/net/inet6_opt_init.3
@@ -0,0 +1,337 @@
+.\" $KAME: inet6_opt_init.3,v 1.7 2004/12/27 05:08:23 itojun Exp $
+.\"
+.\" Copyright (C) 2004 WIDE Project.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the project nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd December 23, 2004
+.Dt INET6_OPT_INIT 3
+.Os
+.\"
+.Sh NAME
+.Nm inet6_opt_init ,
+.Nm inet6_opt_append ,
+.Nm inet6_opt_finish ,
+.Nm inet6_opt_set_val ,
+.Nm inet6_opt_next ,
+.Nm inet6_opt_find ,
+.Nm inet6_opt_get_val
+.Nd IPv6 Hop-by-Hop and Destination Options manipulation
+.\"
+.Sh SYNOPSIS
+.In netinet/in.h
+.Ft "int"
+.Fn inet6_opt_init "void *extbuf" "socklen_t extlen"
+.Ft "int"
+.Fn inet6_opt_append "void *extbuf" "socklen_t extlen" "int offset" "u_int8_t type" "socklen_t len" "u_int8_t align" "void **databufp"
+.Ft "int"
+.Fn inet6_opt_finish "void *extbuf" "socklen_t extlen" "int offset"
+.Ft "int"
+.Fn inet6_opt_set_val "void *databuf" "int offset" "void *val" "socklen_t vallen"
+.Ft "int"
+.Fn inet6_opt_next "void *extbuf" "socklen_t extlen" "int offset" "u_int8_t *typep" "socklen_t *lenp" "void **databufp"
+.Ft "int"
+.Fn inet6_opt_find "void *extbuf" "socklen_t extlen" "int offset" "u_int8_t type" "socklen_t *lenp" "void **databufp"
+.Ft "int"
+.Fn inet6_opt_get_val "void *databuf" "int offset" "void *val" "socklen_t vallen"
+.\"
+.Sh DESCRIPTION
+Building and parsing the Hop-by-Hop and Destination options is
+complicated.
+The advanced sockets API defines a set of functions to
+help applications create and manipulate Hop-by-Hop and Destination
+options.
+This man page describes the functions specified in
+IETF Draft RFC3542.
+These functions use the
+formatting rules specified in Appendix B in RFC2460, i.e., that the
+largest field is placed last in the option.
+The function prototypes
+for these functions are all contained in the
+.In netinet/in.h
+header file.
+.\"
+.Ss inet6_opt_init
+The
+.Fn inet6_opt_init
+function
+returns the number of bytes needed for an empty
+extension header, one without any options.
+If the
+.Fa extbuf
+argument points to a valid section of memory
+then the
+.Fn inet6_opt_init
+function also initializes the extension header's length field.
+When attempting to initialize an extension buffer passed in the
+.Fa extbuf
+argument,
+.Fa extlen
+must be a positive multiple of 8 or else the function fails and
+returns \-1 to the caller.
+.\"
+.Ss inet6_opt_append
+The
+.Fn inet6_opt_append
+function can perform two different jobs.
+When a valid
+.Fa extbuf
+argument is supplied it appends an option to the extension buffer and
+returns the updated total length as well as a pointer to the newly
+created option in
+.Fa databufp .
+If the value
+of
+.Fa extbuf
+is
+.Dv NULL
+then the
+.Fn inet6_opt_append
+function only reports what the total length would
+be if the option were actually appended.
+The
+.Fa len
+and
+.Fa align
+arguments specify the length of the option and the required data
+alignment which must be used when appending the option.
+The
+.Fa offset
+argument should be the length returned by the
+.Fn inet6_opt_init
+function or a previous call to
+.Fn inet6_opt_append .
+.Pp
+The
+.Fa type
+argument is the 8-bit option type.
+.Pp
+After
+.Fn inet6_opt_append
+has been called, the application can use the buffer pointed to by
+.Fa databufp
+directly, or use
+.Fn inet6_opt_set_val
+to specify the data to be contained in the option.
+.Pp
+Option types of
+.Li 0
+and
+.Li 1
+are reserved for the
+.Li Pad1
+and
+.Li PadN
+options.
+All other values from 2 through 255 may be used by applications.
+.Pp
+The length of the option data is contained in an 8-bit value and so
+may contain any value from 0 through 255.
+.Pp
+The
+.Fa align
+parameter must have a value of 1, 2, 4, or 8 and cannot exceed the
+value of
+.Fa len .
+The alignment values represent no alignment, 16 bit, 32 bit and 64 bit
+alignments, respectively.
+.\"
+.Ss inet6_opt_finish
+The
+.Fn inet6_opt_finish
+function
+calculates the final padding necessary to make the extension header a
+multiple of 8 bytes, as required by the IPv6 extension header
+specification, and returns the extension header's updated total
+length.
+The
+.Fa offset
+argument should be the length returned by
+.Fn inet6_opt_init
+or
+.Fn inet6_opt_append .
+When
+.Fa extbuf
+is not
+.Dv NULL
+the function also sets up the appropriate padding bytes by inserting a
+Pad1 or PadN option of the proper length.
+.Pp
+If the extension header is too small to contain the proper padding
+then an error of \-1 is returned to the caller.
+.\"
+.Ss inet6_opt_set_val
+The
+.Fn inet6_opt_set_val
+function inserts data items of various sizes into the data portion of
+the option.
+The
+.Fa databuf
+argument is a pointer to memory that was returned by the
+.Fn inet6_opt_append
+call and the
+.Fa offset
+argument specifies where the option should be placed in the
+data buffer.
+The
+.Fa val
+argument points to an area of memory containing the data to be
+inserted into the extension header, and the
+.Fa vallen
+argument indicates how much data to copy.
+.Pp
+The caller should ensure that each field is aligned on its natural
+boundaries as described in Appendix B of RFC2460.
+.Pp
+The function returns the offset for the next field which is calculated as
+.Fa offset
++
+.Fa vallen
+and is used when composing options with multiple fields.
+.\"
+.Ss inet6_opt_next
+The
+.Fn inet6_opt_next
+function parses received extension headers.
+The
+.Fa extbuf
+and
+.Fa extlen
+arguments specify the location and length of the extension header
+being parsed.
+The
+.Fa offset
+argument should either be zero, for the first option, or the length value
+returned by a previous call to
+.Fn inet6_opt_next
+or
+.Fn inet6_opt_find .
+The return value specifies the position where to continue scanning the
+extension buffer.
+The option is returned in the arguments
+.Fa typep , lenp ,
+and
+.Fa databufp ,
+which
+point to the 8-bit option type, the 8-bit option length and the option
+data, respectively.
+This function does not return any PAD1 or PADN options.
+When an error occurs or there are no more options, the return
+value is \-1.
+.\"
+.Ss inet6_opt_find
+The
+.Fn inet6_opt_find
+function searches the extension buffer for a particular option type,
+passed in through the
+.Fa type
+argument.
+If the option is found then the
+.Fa lenp
+and
+.Fa databufp
+arguments are updated to point to the option's length and data,
+respectively.
+The
+.Fa extbuf
+and
+.Fa extlen
+arguments
+must point to a valid extension buffer and give its length.
+The
+.Fa offset
+argument can be used to search from a location anywhere in the
+extension header.
+.Ss inet6_opt_get_val
+The
+.Fn inet6_opt_get_val
+function extracts data items of various sizes in the data portion of
+the option.
+The
+.Fa databuf
+is a pointer returned by the
+.Fn inet6_opt_next
+or
+.Fn inet6_opt_find
+functions.
+The
+.Fa val
+argument points where the data will be extracted.
+The
+.Fa offset
+argument specifies from where in the data portion of the option the
+value should be extracted; the first byte of option data is specified
+by an offset of zero.
+.Pp
+It is expected that each field is aligned on its natural boundaries as
+described in Appendix B of RFC2460.
+.Pp
+The function returns the offset for the next field
+by calculating
+.Fa offset
++
+.Fa vallen
+which can be used when extracting option content with multiple fields.
+Robust receivers must verify alignment before calling this function.
+.\"
+.Sh RETURN VALUES
+All the functions return
+\-1
+on an error.
+.\"
+.Sh EXAMPLES
+RFC3542 gives comprehensive examples in Section 23.
+.Pp
+KAME also provides examples in the
+.Pa advapitest
+directory of its kit.
+.\"
+.Sh SEE ALSO
+.Rs
+.%A W. Stevens
+.%A M. Thomas
+.%A E. Nordmark
+.%A T. Jinmei
+.%T "Advanced Sockets API for IPv6"
+.%N RFC3542
+.%D October 2002
+.Re
+.Rs
+.%A S. Deering
+.%A R. Hinden
+.%T "Internet Protocol, Version 6 (IPv6) Specification"
+.%N RFC2460
+.%D December 1998
+.Re
+.Sh STANDARDS
+The functions are documented in
+.Dq Advanced Sockets API for IPv6
+.Pq RFC3542 .
+.\"
+.Sh HISTORY
+The implementation first appeared in KAME advanced networking kit.
diff --git a/lib/libc/net/inet6_option_space.3 b/lib/libc/net/inet6_option_space.3
new file mode 100644
index 000000000000..e17855a32ba7
--- /dev/null
+++ b/lib/libc/net/inet6_option_space.3
@@ -0,0 +1,54 @@
+.\" $KAME: inet6_option_space.3,v 1.11 2005/01/05 03:00:44 itojun Exp $
+.\"
+.\" Copyright (C) 2004 WIDE Project.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the project nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd January 24, 2005
+.Dt INET6_OPTION_SPACE 3
+.Os
+.\"
+.Sh NAME
+.Nm inet6_option_space ,
+.Nm inet6_option_init ,
+.Nm inet6_option_append ,
+.Nm inet6_option_alloc ,
+.Nm inet6_option_next ,
+.Nm inet6_option_find
+.Nd IPv6 Hop-by-Hop and Destination Option Manipulation
+.\"
+.Sh DESCRIPTION
+The functions that were documented in this manual page are now
+deprecated in favor of those described in
+.Xr inet6_opt_init 3 .
+Please refer to that manual page for information on how to manipulate
+IPv6 Hop-by-Hop and Destination options.
+.Sh SEE ALSO
+.Xr inet6_opt_init 3
+.\"
+.\"
diff --git a/lib/libc/net/inet6_rth_space.3 b/lib/libc/net/inet6_rth_space.3
new file mode 100644
index 000000000000..a3db7942c6cd
--- /dev/null
+++ b/lib/libc/net/inet6_rth_space.3
@@ -0,0 +1,225 @@
+.\" $KAME: inet6_rth_space.3,v 1.7 2005/01/05 03:00:44 itojun Exp $
+.\"
+.\" Copyright (C) 2004 WIDE Project.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the project nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd December 24, 2004
+.Dt INET6_RTH_SPACE 3
+.Os
+.\"
+.Sh NAME
+.Nm inet6_rth_space ,
+.Nm inet6_rth_init ,
+.Nm inet6_rth_add ,
+.Nm inet6_rth_reverse ,
+.Nm inet6_rth_segments ,
+.Nm inet6_rth_getaddr
+.Nd IPv6 Routing Header Options manipulation
+.\"
+.Sh SYNOPSIS
+.In netinet/in.h
+.Ft socklen_t
+.Fn inet6_rth_space "int" "int"
+.Ft "void *"
+.Fn inet6_rth_init "void *" "socklen_t" "int" "int"
+.Ft int
+.Fn inet6_rth_add "void *" "const struct in6_addr *"
+.Ft int
+.Fn inet6_rth_reverse "const void *" "void *"
+.Ft int
+.Fn inet6_rth_segments "const void *"
+.Ft "struct in6_addr *"
+.Fn inet6_rth_getaddr "const void *" "int"
+.\"
+.Sh DESCRIPTION
+The IPv6 Advanced API, RFC 3542, defines the functions that an
+application calls to build and examine IPv6 Routing headers.
+Routing headers are used to perform source routing in IPv6 networks.
+The RFC uses the word
+.Dq segments
+to describe addresses and that is the term used here as well.
+All of the functions are defined in the
+.In netinet/in.h
+header file.
+The functions described in this manual page all operate
+on routing header structures which are defined in
+.In netinet/ip6.h
+but which should not need to be modified outside the use of this API.
+The size and shape of the route header structures may change, so using
+the APIs is a more portable, long term, solution.
+.Pp
+The functions in the API are split into two groups, those that build a
+routing header and those that parse a received routing header.
+We will describe the builder functions followed by the parser functions.
+.Ss inet6_rth_space
+The
+.Fn inet6_rth_space
+function returns the number of bytes required to hold a Routing Header
+of the type, specified in the
+.Fa type
+argument and containing the number of addresses specified in the
+.Fa segments
+argument.
+When the type is
+.Dv IPV6_RTHDR_TYPE_0
+the number of segments must be from 0 through 127.
+Routing headers of type
+.Dv IPV6_RTHDR_TYPE_2
+contain only one segment, and are only used with Mobile IPv6.
+The return value from this function is the number of bytes required to
+store the routing header.
+If the value 0 is returned then either the
+route header type was not recognized or another error occurred.
+.Ss inet6_rth_init
+The
+.Fn inet6_rth_init
+function initializes the pre-allocated buffer pointed to by
+.Fa bp
+to contain a routing header of the specified type.
+The
+.Fa bp_len
+argument is used to verify that the buffer is large enough.
+The caller must allocate the buffer pointed to by bp.
+The necessary buffer size should be determined by calling
+.Fn inet6_rth_space
+described in the previous sections.
+.Pp
+The
+.Fn inet6_rth_init
+function returns a pointer to
+.Fa bp
+on success and
+.Dv NULL
+when there is an error.
+.Ss inet6_rth_add
+The
+.Fn inet6_rth_add
+function adds the IPv6 address pointed to by
+.Fa addr
+to the end of the routing header being constructed.
+.Pp
+A successful addition results in the function returning 0, otherwise
+\-1 is returned.
+.Ss inet6_rth_reverse
+The
+.Fn inet6_rth_reverse
+function takes a routing header, pointed to by the
+argument
+.Fa in ,
+and writes a new routing header into the argument pointed to by
+.Fa out .
+The routing header at that sends datagrams along the reverse of that
+route.
+Both arguments are allowed to point to the same buffer meaning
+that the reversal can occur in place.
+.Pp
+The return value of the function is 0 on success, or \-1 when
+there is an error.
+.\"
+.Pp
+The next set of functions operate on a routing header that the
+application wants to parse.
+In the usual case such a routing header
+is received from the network, although these functions can also be
+used with routing headers that the application itself created.
+.Ss inet6_rth_segments
+The
+.Fn inet6_rth_segments
+function returns the number of segments contained in the
+routing header pointed to by
+.Fa bp .
+The return value is the number of segments contained in the routing
+header, or \-1 if an error occurred.
+It is not an error for 0 to be
+returned as a routing header may contain 0 segments.
+.\"
+.Ss inet6_rth_getaddr
+The
+.Fn inet6_rth_getaddr
+function is used to retrieve a single address from a routing header.
+The
+.Fa index
+is the location in the routing header from which the application wants
+to retrieve an address.
+The
+.Fa index
+parameter must have a value between 0 and one less than the number of
+segments present in the routing header.
+The
+.Fn inet6_rth_segments
+function, described in the last section, should be used to determine
+the total number of segments in the routing header.
+The
+.Fn inet6_rth_getaddr
+function returns a pointer to an IPv6 address on success or
+.Dv NULL
+when an error has occurred.
+.\"
+.Sh EXAMPLES
+RFC 3542 gives extensive examples in Section 21, Appendix B.
+.Pp
+KAME also provides examples in the advapitest directory of its kit.
+.\"
+.Sh DIAGNOSTICS
+The
+.Fn inet6_rth_space
+and
+.Fn inet6_rth_getaddr
+functions return 0 on errors.
+.Pp
+The
+.Fn inet6_rthdr_init
+function returns
+.Dv NULL
+on error.
+The
+.Fn inet6_rth_add
+and
+.Fn inet6_rth_reverse
+functions return 0 on success, or \-1 upon an error.
+.\"
+.Sh SEE ALSO
+.Rs
+.%A W. Stevens
+.%A M. Thomas
+.%A E. Nordmark
+.%A T. Jinmei
+.%T "Advanced Sockets API for IPv6"
+.%N RFC 3542
+.%D May 2003
+.Re
+.Rs
+.%A S. Deering
+.%A R. Hinden
+.%T "Internet Protocol, Version 6 (IPv6) Specification"
+.%N RFC2460
+.%D December 1998
+.Re
+.Sh HISTORY
+The implementation first appeared in KAME advanced networking kit.
diff --git a/lib/libc/net/inet6_rthdr_space.3 b/lib/libc/net/inet6_rthdr_space.3
new file mode 100644
index 000000000000..bfb2f231a874
--- /dev/null
+++ b/lib/libc/net/inet6_rthdr_space.3
@@ -0,0 +1,57 @@
+.\" $KAME: inet6_rthdr_space.3,v 1.11 2005/01/05 03:00:44 itojun Exp $
+.\"
+.\" Copyright (C) 2004 WIDE Project.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the project nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd January 24, 2005
+.Dt INET6_RTHDR_SPACE 3
+.Os
+.\"
+.Sh NAME
+.Nm inet6_rthdr_space ,
+.Nm inet6_rthdr_init ,
+.Nm inet6_rthdr_add ,
+.Nm inet6_rthdr_lasthop ,
+.Nm inet6_rthdr_reverse ,
+.Nm inet6_rthdr_segments ,
+.Nm inet6_rthdr_getaddr ,
+.Nm inet6_rthdr_getflags
+.Nd IPv6 Routing Header Options Manipulation
+.\"
+.Sh DESCRIPTION
+The RFC 2292 IPv6 Advanced API has been deprecated in favor of the
+newer, RFC 3542 APIs documented in
+.Xr inet6_rth_space 3 .
+On platforms that support it, currently only
+.Fx ,
+please use the newer API to manipulate routing header
+options.
+.\"
+.Sh SEE ALSO
+.Xr inet6_rth_space 3
diff --git a/lib/libc/net/inet_net.3 b/lib/libc/net/inet_net.3
new file mode 100644
index 000000000000..336aa3c3ec93
--- /dev/null
+++ b/lib/libc/net/inet_net.3
@@ -0,0 +1,161 @@
+.\" $NetBSD: inet_net.3,v 1.4 1999/03/22 19:44:52 garbled Exp $
+.\"
+.\" Copyright (c) 1997 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Luke Mewburn.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of The NetBSD Foundation nor the names of its
+.\" contributors may be used to endorse or promote products derived
+.\" from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd August 18, 2016
+.Dt INET_NET 3
+.Os
+.Sh NAME
+.Nm inet_net_ntop ,
+.Nm inet_net_pton
+.Nd Internet network number manipulation routines
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/socket.h
+.In netinet/in.h
+.In arpa/inet.h
+.Ft char *
+.Fn inet_net_ntop "int af" "const void *src" "int bits" "char *dst" "size_t size"
+.Ft int
+.Fn inet_net_pton "int af" "const char *src" "void *dst" "size_t size"
+.Sh DESCRIPTION
+The
+.Fn inet_net_ntop
+function converts an Internet network number from network format (usually a
+.Vt "struct in_addr"
+or some other binary form, in network byte order) to CIDR presentation format
+(suitable for external display purposes).
+The
+.Fa bits
+argument
+is the number of bits in
+.Fa src
+that are the network number.
+It returns
+.Dv NULL
+if a system error occurs (in which case,
+.Va errno
+will have been set), or it returns a pointer to the destination string.
+.Pp
+The
+.Fn inet_net_pton
+function converts a presentation format Internet network number (that is,
+printable form as held in a character string) to network format (usually a
+.Vt "struct in_addr"
+or some other internal binary representation, in network byte order).
+It returns the number of bits (either computed based on the class, or
+specified with /CIDR), or \-1 if a failure occurred
+(in which case
+.Va errno
+will have been set.
+It will be set to
+.Er ENOENT
+if the Internet network number was not valid).
+.Pp
+The currently supported values for
+.Fa af
+are
+.Dv AF_INET
+and
+.Dv AF_INET6 .
+The
+.Fa size
+argument
+is the size of the result buffer
+.Fa dst .
+.Sh NETWORK NUMBERS (IP VERSION 4)
+Internet network numbers may be specified in one of the following forms:
+.Bd -literal -offset indent
+a.b.c.d/bits
+a.b.c.d
+a.b.c
+a.b
+a
+.Ed
+.Pp
+When four parts are specified, each is interpreted
+as a byte of data and assigned, from left to right,
+to the four bytes of an Internet network number.
+Note
+that when an Internet network number is viewed as a 32-bit
+integer quantity on a system that uses little-endian
+byte order (such as the
+.Tn Intel 386 , 486 ,
+and
+.Tn Pentium
+processors) the bytes referred to above appear as
+.Dq Li d.c.b.a .
+That is, little-endian bytes are ordered from right to left.
+.Pp
+When a three part number is specified, the last
+part is interpreted as a 16-bit quantity and placed
+in the rightmost two bytes of the Internet network number.
+This makes the three part number format convenient
+for specifying Class B network numbers as
+.Dq Li 128.net.host .
+.Pp
+When a two part number is supplied, the last part
+is interpreted as a 24-bit quantity and placed in
+the rightmost three bytes of the Internet network number.
+This makes the two part number format convenient
+for specifying Class A network numbers as
+.Dq Li net.host .
+.Pp
+When only one part is given, the value is stored
+directly in the Internet network number without any byte
+rearrangement.
+.Pp
+All numbers supplied as
+.Dq parts
+in a
+.Ql \&.
+notation
+may be decimal, octal, or hexadecimal, as specified
+in the C language (i.e., a leading 0x or 0X implies
+hexadecimal; otherwise, a leading 0 implies octal;
+otherwise, the number is interpreted as decimal).
+.\"
+.\" .Sh NETWORK NUMBERS (IP VERSION 6)
+.\" XXX - document this!
+.\"
+.Sh SEE ALSO
+.Xr byteorder 3 ,
+.Xr inet 3 ,
+.Xr networks 5
+.Sh HISTORY
+The
+.Fn inet_net_ntop
+and
+.Fn inet_net_pton
+functions appeared in BIND 4.9.4.
diff --git a/lib/libc/net/ip6opt.c b/lib/libc/net/ip6opt.c
new file mode 100644
index 000000000000..db3f8ce66c3a
--- /dev/null
+++ b/lib/libc/net/ip6opt.c
@@ -0,0 +1,599 @@
+/* $KAME: ip6opt.c,v 1.13 2003/06/06 10:08:20 suz Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <netinet/ip6.h>
+
+#include <string.h>
+#include <stdio.h>
+
+static int ip6optlen(u_int8_t *opt, u_int8_t *lim);
+static void inet6_insert_padopt(u_char *p, int len);
+
+#ifndef IPV6_2292HOPOPTS
+#define IPV6_2292HOPOPTS 22
+#endif
+#ifndef IPV6_2292DSTOPTS
+#define IPV6_2292DSTOPTS 23
+#endif
+
+#define is_ipv6_hopopts(x) \
+ ((x) == IPV6_HOPOPTS || (x) == IPV6_2292HOPOPTS)
+#define is_ipv6_dstopts(x) \
+ ((x) == IPV6_DSTOPTS || (x) == IPV6_2292DSTOPTS)
+
+/*
+ * This function returns the number of bytes required to hold an option
+ * when it is stored as ancillary data, including the cmsghdr structure
+ * at the beginning, and any padding at the end (to make its size a
+ * multiple of 8 bytes). The argument is the size of the structure
+ * defining the option, which must include any pad bytes at the
+ * beginning (the value y in the alignment term "xn + y"), the type
+ * byte, the length byte, and the option data.
+ */
+int
+inet6_option_space(int nbytes)
+{
+ nbytes += 2; /* we need space for nxt-hdr and length fields */
+ return(CMSG_SPACE((nbytes + 7) & ~7));
+}
+
+/*
+ * This function is called once per ancillary data object that will
+ * contain either Hop-by-Hop or Destination options. It returns 0 on
+ * success or -1 on an error.
+ */
+int
+inet6_option_init(void *bp, struct cmsghdr **cmsgp, int type)
+{
+ struct cmsghdr *ch = (struct cmsghdr *)bp;
+
+ /* argument validation */
+ if (!is_ipv6_hopopts(type) && !is_ipv6_dstopts(type))
+ return(-1);
+
+ ch->cmsg_level = IPPROTO_IPV6;
+ ch->cmsg_type = type;
+ ch->cmsg_len = CMSG_LEN(0);
+
+ *cmsgp = ch;
+ return(0);
+}
+
+/*
+ * This function appends a Hop-by-Hop option or a Destination option
+ * into an ancillary data object that has been initialized by
+ * inet6_option_init(). This function returns 0 if it succeeds or -1 on
+ * an error.
+ * multx is the value x in the alignment term "xn + y" described
+ * earlier. It must have a value of 1, 2, 4, or 8.
+ * plusy is the value y in the alignment term "xn + y" described
+ * earlier. It must have a value between 0 and 7, inclusive.
+ */
+int
+inet6_option_append(struct cmsghdr *cmsg, const u_int8_t *typep, int multx,
+ int plusy)
+{
+ int padlen, optlen, off;
+ u_char *bp = (u_char *)cmsg + cmsg->cmsg_len;
+ struct ip6_ext *eh = (struct ip6_ext *)CMSG_DATA(cmsg);
+
+ /* argument validation */
+ if (multx != 1 && multx != 2 && multx != 4 && multx != 8)
+ return(-1);
+ if (plusy < 0 || plusy > 7)
+ return(-1);
+
+ /*
+ * If this is the first option, allocate space for the
+ * first 2 bytes(for next header and length fields) of
+ * the option header.
+ */
+ if (bp == (u_char *)eh) {
+ bp += 2;
+ cmsg->cmsg_len += 2;
+ }
+
+ /* calculate pad length before the option. */
+ off = bp - (u_char *)eh;
+ padlen = roundup2(off % multx, multx) - (off % multx);
+ padlen += plusy;
+ padlen %= multx; /* keep the pad as short as possible */
+ /* insert padding */
+ inet6_insert_padopt(bp, padlen);
+ cmsg->cmsg_len += padlen;
+ bp += padlen;
+
+ /* copy the option */
+ if (typep[0] == IP6OPT_PAD1)
+ optlen = 1;
+ else
+ optlen = typep[1] + 2;
+ memcpy(bp, typep, optlen);
+ bp += optlen;
+ cmsg->cmsg_len += optlen;
+
+ /* calculate pad length after the option and insert the padding */
+ off = bp - (u_char *)eh;
+ padlen = ((off + 7) & ~7) - off;
+ inet6_insert_padopt(bp, padlen);
+ bp += padlen;
+ cmsg->cmsg_len += padlen;
+
+ /* update the length field of the ip6 option header */
+ eh->ip6e_len = ((bp - (u_char *)eh) >> 3) - 1;
+
+ return(0);
+}
+
+/*
+ * This function appends a Hop-by-Hop option or a Destination option
+ * into an ancillary data object that has been initialized by
+ * inet6_option_init(). This function returns a pointer to the 8-bit
+ * option type field that starts the option on success, or NULL on an
+ * error.
+ * The difference between this function and inet6_option_append() is
+ * that the latter copies the contents of a previously built option into
+ * the ancillary data object while the current function returns a
+ * pointer to the space in the data object where the option's TLV must
+ * then be built by the caller.
+ *
+ */
+u_int8_t *
+inet6_option_alloc(struct cmsghdr *cmsg, int datalen, int multx, int plusy)
+{
+ int padlen, off;
+ u_int8_t *bp = (u_char *)cmsg + cmsg->cmsg_len;
+ u_int8_t *retval;
+ struct ip6_ext *eh = (struct ip6_ext *)CMSG_DATA(cmsg);
+
+ /* argument validation */
+ if (multx != 1 && multx != 2 && multx != 4 && multx != 8)
+ return(NULL);
+ if (plusy < 0 || plusy > 7)
+ return(NULL);
+
+ /*
+ * If this is the first option, allocate space for the
+ * first 2 bytes(for next header and length fields) of
+ * the option header.
+ */
+ if (bp == (u_char *)eh) {
+ bp += 2;
+ cmsg->cmsg_len += 2;
+ }
+
+ /* calculate pad length before the option. */
+ off = bp - (u_char *)eh;
+ padlen = roundup2(off % multx, multx) - (off % multx);
+ padlen += plusy;
+ padlen %= multx; /* keep the pad as short as possible */
+ /* insert padding */
+ inet6_insert_padopt(bp, padlen);
+ cmsg->cmsg_len += padlen;
+ bp += padlen;
+
+ /* keep space to store specified length of data */
+ retval = bp;
+ bp += datalen;
+ cmsg->cmsg_len += datalen;
+
+ /* calculate pad length after the option and insert the padding */
+ off = bp - (u_char *)eh;
+ padlen = ((off + 7) & ~7) - off;
+ inet6_insert_padopt(bp, padlen);
+ bp += padlen;
+ cmsg->cmsg_len += padlen;
+
+ /* update the length field of the ip6 option header */
+ eh->ip6e_len = ((bp - (u_char *)eh) >> 3) - 1;
+
+ return(retval);
+}
+
+/*
+ * This function processes the next Hop-by-Hop option or Destination
+ * option in an ancillary data object. If another option remains to be
+ * processed, the return value of the function is 0 and *tptrp points to
+ * the 8-bit option type field (which is followed by the 8-bit option
+ * data length, followed by the option data). If no more options remain
+ * to be processed, the return value is -1 and *tptrp is NULL. If an
+ * error occurs, the return value is -1 and *tptrp is not NULL.
+ * (RFC 2292, 6.3.5)
+ */
+int
+inet6_option_next(const struct cmsghdr *cmsg, u_int8_t **tptrp)
+{
+ struct ip6_ext *ip6e;
+ int hdrlen, optlen;
+ u_int8_t *lim;
+
+ if (cmsg->cmsg_level != IPPROTO_IPV6 ||
+ (!is_ipv6_hopopts(cmsg->cmsg_type) &&
+ !is_ipv6_dstopts(cmsg->cmsg_type)))
+ return(-1);
+
+ /* message length validation */
+ if (cmsg->cmsg_len < CMSG_SPACE(sizeof(struct ip6_ext)))
+ return(-1);
+ ip6e = (struct ip6_ext *)CMSG_DATA(cmsg);
+ hdrlen = (ip6e->ip6e_len + 1) << 3;
+ if (cmsg->cmsg_len < CMSG_SPACE(hdrlen))
+ return(-1);
+
+ /*
+ * If the caller does not specify the starting point,
+ * simply return the 1st option.
+ * Otherwise, search the option list for the next option.
+ */
+ lim = (u_int8_t *)ip6e + hdrlen;
+ if (*tptrp == NULL)
+ *tptrp = (u_int8_t *)(ip6e + 1);
+ else {
+ if ((optlen = ip6optlen(*tptrp, lim)) == 0)
+ return(-1);
+
+ *tptrp = *tptrp + optlen;
+ }
+ if (*tptrp >= lim) { /* there is no option */
+ *tptrp = NULL;
+ return(-1);
+ }
+ /*
+ * Finally, checks if the next option is safely stored in the
+ * cmsg data.
+ */
+ if (ip6optlen(*tptrp, lim) == 0)
+ return(-1);
+ else
+ return(0);
+}
+
+/*
+ * This function is similar to the inet6_option_next() function,
+ * except this function lets the caller specify the option type to be
+ * searched for, instead of always returning the next option in the
+ * ancillary data object.
+ * Note: RFC 2292 says the type of tptrp is u_int8_t *, but we think
+ * it's a typo. The variable should be type of u_int8_t **.
+ */
+int
+inet6_option_find(const struct cmsghdr *cmsg, u_int8_t **tptrp, int type)
+{
+ struct ip6_ext *ip6e;
+ int hdrlen, optlen;
+ u_int8_t *optp, *lim;
+
+ if (cmsg->cmsg_level != IPPROTO_IPV6 ||
+ (!is_ipv6_hopopts(cmsg->cmsg_type) &&
+ !is_ipv6_dstopts(cmsg->cmsg_type)))
+ return(-1);
+
+ /* message length validation */
+ if (cmsg->cmsg_len < CMSG_SPACE(sizeof(struct ip6_ext)))
+ return(-1);
+ ip6e = (struct ip6_ext *)CMSG_DATA(cmsg);
+ hdrlen = (ip6e->ip6e_len + 1) << 3;
+ if (cmsg->cmsg_len < CMSG_SPACE(hdrlen))
+ return(-1);
+
+ /*
+ * If the caller does not specify the starting point,
+ * search from the beginning of the option list.
+ * Otherwise, search from *the next option* of the specified point.
+ */
+ lim = (u_int8_t *)ip6e + hdrlen;
+ if (*tptrp == NULL)
+ *tptrp = (u_int8_t *)(ip6e + 1);
+ else {
+ if ((optlen = ip6optlen(*tptrp, lim)) == 0)
+ return(-1);
+
+ *tptrp = *tptrp + optlen;
+ }
+ for (optp = *tptrp; optp < lim; optp += optlen) {
+ if (*optp == type) {
+ *tptrp = optp;
+ return(0);
+ }
+ if ((optlen = ip6optlen(optp, lim)) == 0)
+ return(-1);
+ }
+
+ /* search failed */
+ *tptrp = NULL;
+ return(-1);
+}
+
+/*
+ * Calculate the length of a given IPv6 option. Also checks
+ * if the option is safely stored in user's buffer according to the
+ * calculated length and the limitation of the buffer.
+ */
+static int
+ip6optlen(u_int8_t *opt, u_int8_t *lim)
+{
+ int optlen;
+
+ if (*opt == IP6OPT_PAD1)
+ optlen = 1;
+ else {
+ /* is there enough space to store type and len? */
+ if (opt + 2 > lim)
+ return(0);
+ optlen = *(opt + 1) + 2;
+ }
+ if (opt + optlen <= lim)
+ return(optlen);
+
+ return(0);
+}
+
+static void
+inet6_insert_padopt(u_char *p, int len)
+{
+ switch(len) {
+ case 0:
+ return;
+ case 1:
+ p[0] = IP6OPT_PAD1;
+ return;
+ default:
+ p[0] = IP6OPT_PADN;
+ p[1] = len - 2;
+ memset(&p[2], 0, len - 2);
+ return;
+ }
+}
+
+/*
+ * The following functions are defined in RFC3542, which is a successor
+ * of RFC2292.
+ */
+
+int
+inet6_opt_init(void *extbuf, socklen_t extlen)
+{
+ struct ip6_ext *ext = (struct ip6_ext *)extbuf;
+
+ if (ext) {
+ if (extlen <= 0 || (extlen % 8))
+ return(-1);
+ ext->ip6e_len = (extlen >> 3) - 1;
+ }
+
+ return(2); /* sizeof the next and the length fields */
+}
+
+int
+inet6_opt_append(void *extbuf, socklen_t extlen, int offset, u_int8_t type,
+ socklen_t len, u_int8_t align, void **databufp)
+{
+ int currentlen = offset, padlen = 0;
+
+ /*
+ * The option type must have a value from 2 to 255, inclusive.
+ * (0 and 1 are reserved for the Pad1 and PadN options, respectively.)
+ */
+ if (type < 2)
+ return(-1);
+
+ /*
+ * The option data length must have a value between 0 and 255,
+ * inclusive, and is the length of the option data that follows.
+ */
+ if (len > 255 || len < 0 )
+ return(-1);
+
+ /*
+ * The align parameter must have a value of 1, 2, 4, or 8.
+ * The align value can not exceed the value of len.
+ */
+ if (align != 1 && align != 2 && align != 4 && align != 8)
+ return(-1);
+ if (align > len)
+ return(-1);
+
+ /* Calculate the padding length. */
+ currentlen += 2 + len; /* 2 means "type + len" */
+ if (currentlen % align)
+ padlen = align - (currentlen % align);
+
+ /* The option must fit in the extension header buffer. */
+ currentlen += padlen;
+ if (extlen && /* XXX: right? */
+ currentlen > extlen)
+ return(-1);
+
+ if (extbuf) {
+ u_int8_t *optp = (u_int8_t *)extbuf + offset;
+
+ if (padlen == 1) {
+ /* insert a Pad1 option */
+ *optp = IP6OPT_PAD1;
+ optp++;
+ }
+ else if (padlen > 0) {
+ /* insert a PadN option for alignment */
+ *optp++ = IP6OPT_PADN;
+ *optp++ = padlen - 2;
+ memset(optp, 0, padlen - 2);
+ optp += (padlen - 2);
+ }
+
+ *optp++ = type;
+ *optp++ = len;
+
+ *databufp = optp;
+ }
+
+ return(currentlen);
+}
+
+int
+inet6_opt_finish(void *extbuf, socklen_t extlen, int offset)
+{
+ int updatelen = offset > 0 ? (1 + ((offset - 1) | 7)) : 0;
+
+ if (extbuf) {
+ u_int8_t *padp;
+ int padlen = updatelen - offset;
+
+ if (updatelen > extlen)
+ return(-1);
+
+ padp = (u_int8_t *)extbuf + offset;
+ if (padlen == 1)
+ *padp = IP6OPT_PAD1;
+ else if (padlen > 0) {
+ *padp++ = IP6OPT_PADN;
+ *padp++ = (padlen - 2);
+ memset(padp, 0, padlen - 2);
+ }
+ }
+
+ return(updatelen);
+}
+
+int
+inet6_opt_set_val(void *databuf, int offset, void *val, socklen_t vallen)
+{
+
+ memcpy((u_int8_t *)databuf + offset, val, vallen);
+ return(offset + vallen);
+}
+
+int
+inet6_opt_next(void *extbuf, socklen_t extlen, int offset, u_int8_t *typep,
+ socklen_t *lenp, void **databufp)
+{
+ u_int8_t *optp, *lim;
+ int optlen;
+
+ /* Validate extlen. XXX: is the variable really necessary?? */
+ if (extlen == 0 || (extlen % 8))
+ return(-1);
+ lim = (u_int8_t *)extbuf + extlen;
+
+ /*
+ * If this is the first time this function called for this options
+ * header, simply return the 1st option.
+ * Otherwise, search the option list for the next option.
+ */
+ if (offset == 0) {
+ optp = (u_int8_t *)((struct ip6_hbh *)extbuf + 1);
+ }
+ else
+ optp = (u_int8_t *)extbuf + offset;
+
+ /* Find the next option skipping any padding options. */
+ while(optp < lim) {
+ switch(*optp) {
+ case IP6OPT_PAD1:
+ optp++;
+ break;
+ case IP6OPT_PADN:
+ if ((optlen = ip6optlen(optp, lim)) == 0)
+ goto optend;
+ optp += optlen;
+ break;
+ default: /* found */
+ if ((optlen = ip6optlen(optp, lim)) == 0)
+ goto optend;
+ *typep = *optp;
+ *lenp = optlen - 2;
+ *databufp = optp + 2;
+ return(optp + optlen - (u_int8_t *)extbuf);
+ }
+ }
+
+ optend:
+ *databufp = NULL; /* for safety */
+ return(-1);
+}
+
+int
+inet6_opt_find(void *extbuf, socklen_t extlen, int offset, u_int8_t type,
+ socklen_t *lenp, void **databufp)
+{
+ u_int8_t *optp, *lim;
+ int optlen;
+
+ /* Validate extlen. XXX: is the variable really necessary?? */
+ if (extlen == 0 || (extlen % 8))
+ return(-1);
+ lim = (u_int8_t *)extbuf + extlen;
+
+ /*
+ * If this is the first time this function called for this options
+ * header, simply return the 1st option.
+ * Otherwise, search the option list for the next option.
+ */
+ if (offset == 0) {
+ optp = (u_int8_t *)((struct ip6_hbh *)extbuf + 1);
+ }
+ else
+ optp = (u_int8_t *)extbuf + offset;
+
+ /* Find the specified option */
+ while(optp < lim) {
+ if ((optlen = ip6optlen(optp, lim)) == 0)
+ goto optend;
+
+ if (*optp == type) { /* found */
+ *lenp = optlen - 2;
+ *databufp = optp + 2;
+ return(optp + optlen - (u_int8_t *)extbuf);
+ }
+
+ optp += optlen;
+ }
+
+ optend:
+ *databufp = NULL; /* for safety */
+ return(-1);
+}
+
+int
+inet6_opt_get_val(void *databuf, int offset, void *val, socklen_t vallen)
+{
+
+ /* we can't assume alignment here */
+ memcpy(val, (u_int8_t *)databuf + offset, vallen);
+
+ return(offset + vallen);
+}
diff --git a/lib/libc/net/linkaddr.3 b/lib/libc/net/linkaddr.3
new file mode 100644
index 000000000000..43876753ea33
--- /dev/null
+++ b/lib/libc/net/linkaddr.3
@@ -0,0 +1,134 @@
+.\" Copyright (c) 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Donn Seeley at BSDI.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" From: @(#)linkaddr.3 8.1 (Berkeley) 7/28/93
+.\" $FreeBSD$
+.\"
+.Dd February 28, 2007
+.Dt LINK_ADDR 3
+.Os
+.Sh NAME
+.Nm link_addr ,
+.Nm link_ntoa
+.Nd elementary address specification routines for link level access
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/socket.h
+.In net/if_dl.h
+.Ft void
+.Fn link_addr "const char *addr" "struct sockaddr_dl *sdl"
+.Ft char *
+.Fn link_ntoa "const struct sockaddr_dl *sdl"
+.Sh DESCRIPTION
+The routine
+.Fn link_addr
+interprets character strings representing
+link-level addresses, returning binary information suitable
+for use in system calls.
+The routine
+.Fn link_ntoa
+takes
+a link-level
+address and returns an
+.Tn ASCII
+string representing some of the information present,
+including the link level address itself, and the interface name
+or number, if present.
+This facility is experimental and is
+still subject to change.
+.Pp
+For
+.Fn link_addr ,
+the string
+.Fa addr
+may contain
+an optional network interface identifier of the form
+.Dq "name unit-number" ,
+suitable for the first argument to
+.Xr ifconfig 8 ,
+followed in all cases by a colon and
+an interface address in the form of
+groups of hexadecimal digits
+separated by periods.
+Each group represents a byte of address;
+address bytes are filled left to right from
+low order bytes through high order bytes.
+.Pp
+.\" A regular expression may make this format clearer:
+.\" .Bd -literal -offset indent
+.\" ([a-z]+[0-9]+:)?[0-9a-f]+(\e.[0-9a-f]+)*
+.\" .Ed
+.\" .Pp
+Thus
+.Li le0:8.0.9.13.d.30
+represents an ethernet address
+to be transmitted on the first Lance ethernet interface.
+.Sh RETURN VALUES
+The
+.Fn link_ntoa
+function
+always returns a null terminated string.
+The
+.Fn link_addr
+function
+has no return value.
+(See
+.Sx BUGS . )
+.Sh SEE ALSO
+.Xr getnameinfo 3
+.Sh HISTORY
+The
+.Fn link_addr
+and
+.Fn link_ntoa
+functions appeared in
+.Bx 4.3 Reno .
+.Sh BUGS
+The returned values for link_ntoa
+reside in a static memory area.
+.Pp
+The function
+.Fn link_addr
+should diagnose improperly formed input, and there should be an unambiguous
+way to recognize this.
+.Pp
+If the
+.Va sdl_len
+field of the link socket address
+.Fa sdl
+is 0,
+.Fn link_ntoa
+will not insert a colon before the interface address bytes.
+If this translated address is given to
+.Fn link_addr
+without inserting an initial colon,
+the latter will not interpret it correctly.
diff --git a/lib/libc/net/linkaddr.c b/lib/libc/net/linkaddr.c
new file mode 100644
index 000000000000..9432a53127df
--- /dev/null
+++ b/lib/libc/net/linkaddr.c
@@ -0,0 +1,169 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)linkaddr.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <string.h>
+
+/* States*/
+#define NAMING 0
+#define GOTONE 1
+#define GOTTWO 2
+#define RESET 3
+/* Inputs */
+#define DIGIT (4*0)
+#define END (4*1)
+#define DELIM (4*2)
+#define LETTER (4*3)
+
+void
+link_addr(const char *addr, struct sockaddr_dl *sdl)
+{
+ char *cp = sdl->sdl_data;
+ char *cplim = sdl->sdl_len + (char *)sdl;
+ int byte = 0, state = NAMING, new;
+
+ bzero((char *)&sdl->sdl_family, sdl->sdl_len - 1);
+ sdl->sdl_family = AF_LINK;
+ do {
+ state &= ~LETTER;
+ if ((*addr >= '0') && (*addr <= '9')) {
+ new = *addr - '0';
+ } else if ((*addr >= 'a') && (*addr <= 'f')) {
+ new = *addr - 'a' + 10;
+ } else if ((*addr >= 'A') && (*addr <= 'F')) {
+ new = *addr - 'A' + 10;
+ } else if (*addr == 0) {
+ state |= END;
+ } else if (state == NAMING &&
+ (((*addr >= 'A') && (*addr <= 'Z')) ||
+ ((*addr >= 'a') && (*addr <= 'z'))))
+ state |= LETTER;
+ else
+ state |= DELIM;
+ addr++;
+ switch (state /* | INPUT */) {
+ case NAMING | DIGIT:
+ case NAMING | LETTER:
+ *cp++ = addr[-1];
+ continue;
+ case NAMING | DELIM:
+ state = RESET;
+ sdl->sdl_nlen = cp - sdl->sdl_data;
+ continue;
+ case GOTTWO | DIGIT:
+ *cp++ = byte;
+ /* FALLTHROUGH */
+ case RESET | DIGIT:
+ state = GOTONE;
+ byte = new;
+ continue;
+ case GOTONE | DIGIT:
+ state = GOTTWO;
+ byte = new + (byte << 4);
+ continue;
+ default: /* | DELIM */
+ state = RESET;
+ *cp++ = byte;
+ byte = 0;
+ continue;
+ case GOTONE | END:
+ case GOTTWO | END:
+ *cp++ = byte;
+ /* FALLTHROUGH */
+ case RESET | END:
+ break;
+ }
+ break;
+ } while (cp < cplim);
+ sdl->sdl_alen = cp - LLADDR(sdl);
+ new = cp - (char *)sdl;
+ if (new > sizeof(*sdl))
+ sdl->sdl_len = new;
+ return;
+}
+
+static const char hexlist[] = "0123456789abcdef";
+
+char *
+link_ntoa(const struct sockaddr_dl *sdl)
+{
+ static char obuf[64];
+ _Static_assert(sizeof(obuf) >= IFNAMSIZ + 20, "obuf is too small");
+ char *out;
+ const u_char *in, *inlim;
+ int namelen, i, rem;
+
+ namelen = (sdl->sdl_nlen <= IFNAMSIZ) ? sdl->sdl_nlen : IFNAMSIZ;
+
+ out = obuf;
+ rem = sizeof(obuf);
+ if (namelen > 0) {
+ bcopy(sdl->sdl_data, out, namelen);
+ out += namelen;
+ rem -= namelen;
+ if (sdl->sdl_alen > 0) {
+ *out++ = ':';
+ rem--;
+ }
+ }
+
+ in = (const u_char *)sdl->sdl_data + sdl->sdl_nlen;
+ inlim = in + sdl->sdl_alen;
+
+ while (in < inlim && rem > 1) {
+ if (in != (const u_char *)sdl->sdl_data + sdl->sdl_nlen) {
+ *out++ = '.';
+ rem--;
+ }
+ i = *in++;
+ if (i > 0xf) {
+ if (rem < 3)
+ break;
+ *out++ = hexlist[i >> 4];
+ *out++ = hexlist[i & 0xf];
+ rem -= 2;
+ } else {
+ if (rem < 2)
+ break;
+ *out++ = hexlist[i];
+ rem--;
+ }
+ }
+ *out = 0;
+ return (obuf);
+}
diff --git a/lib/libc/net/map_v4v6.c b/lib/libc/net/map_v4v6.c
new file mode 100644
index 000000000000..d9329ec2074c
--- /dev/null
+++ b/lib/libc/net/map_v4v6.c
@@ -0,0 +1,111 @@
+/*
+ * ++Copyright++ 1985, 1988, 1993
+ * -
+ * Copyright (c) 1985, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * -
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ * -
+ * --Copyright--
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)gethostnamadr.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <ctype.h>
+#include <syslog.h>
+#include "netdb_private.h"
+
+typedef union {
+ int32_t al;
+ char ac;
+} align;
+
+void
+_map_v4v6_address(const char *src, char *dst)
+{
+ /* Our caller may update in place. */
+ memmove(&dst[12], src, NS_INADDRSZ);
+ /* Mark this ipv6 addr as a mapped ipv4. */
+ memset(&dst[10], 0xff, 2);
+ memset(&dst[0], 0, 10);
+}
+
+void
+_map_v4v6_hostent(struct hostent *hp, char **bpp, char *ep) {
+ char **ap;
+
+ if (hp->h_addrtype != AF_INET || hp->h_length != INADDRSZ)
+ return;
+ hp->h_addrtype = AF_INET6;
+ hp->h_length = IN6ADDRSZ;
+ for (ap = hp->h_addr_list; *ap; ap++) {
+ int i = (u_long)*bpp % sizeof(align);
+
+ if (i != 0)
+ i = sizeof(align) - i;
+
+ if ((ep - *bpp) < (i + IN6ADDRSZ)) {
+ /* Out of memory. Truncate address list here. */
+ *ap = NULL;
+ return;
+ }
+ *bpp += i;
+ _map_v4v6_address(*ap, *bpp);
+ *ap = *bpp;
+ *bpp += IN6ADDRSZ;
+ }
+}
diff --git a/lib/libc/net/name6.c b/lib/libc/net/name6.c
new file mode 100644
index 000000000000..b0970786dd8c
--- /dev/null
+++ b/lib/libc/net/name6.c
@@ -0,0 +1,1131 @@
+/* $KAME: name6.c,v 1.25 2000/06/26 16:44:40 itojun Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * ++Copyright++ 1985, 1988, 1993
+ * -
+ * Copyright (c) 1985, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * -
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ * -
+ * --Copyright--
+ */
+
+/*
+ * Atsushi Onoe <onoe@sm.sony.co.jp>
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/queue.h>
+#include <netinet/in.h>
+#ifdef INET6
+#include <net/if.h>
+#include <sys/sysctl.h>
+#include <sys/ioctl.h>
+#include <netinet6/in6_var.h> /* XXX */
+#endif
+
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <nsswitch.h>
+#include <unistd.h>
+#include "un-namespace.h"
+#include "netdb_private.h"
+#include "res_private.h"
+
+#ifndef MAXALIASES
+#define MAXALIASES 10
+#endif
+#ifndef MAXADDRS
+#define MAXADDRS 20
+#endif
+#ifndef MAXDNAME
+#define MAXDNAME 1025
+#endif
+
+#ifdef INET6
+#define ADDRLEN(af) ((af) == AF_INET6 ? sizeof(struct in6_addr) : \
+ sizeof(struct in_addr))
+#else
+#define ADDRLEN(af) sizeof(struct in_addr)
+#endif
+
+#define MAPADDR(ab, ina) \
+do { \
+ memcpy(&(ab)->map_inaddr, ina, sizeof(struct in_addr)); \
+ memset((ab)->map_zero, 0, sizeof((ab)->map_zero)); \
+ memset((ab)->map_one, 0xff, sizeof((ab)->map_one)); \
+} while (0)
+#define MAPADDRENABLED(flags) \
+ (((flags) & AI_V4MAPPED) || \
+ (((flags) & AI_V4MAPPED_CFG)))
+
+union inx_addr {
+ struct in_addr in_addr;
+#ifdef INET6
+ struct in6_addr in6_addr;
+#endif
+ struct {
+ u_char mau_zero[10];
+ u_char mau_one[2];
+ struct in_addr mau_inaddr;
+ } map_addr_un;
+#define map_zero map_addr_un.mau_zero
+#define map_one map_addr_un.mau_one
+#define map_inaddr map_addr_un.mau_inaddr
+};
+
+struct policyqueue {
+ TAILQ_ENTRY(policyqueue) pc_entry;
+#ifdef INET6
+ struct in6_addrpolicy pc_policy;
+#endif
+};
+TAILQ_HEAD(policyhead, policyqueue);
+
+#define AIO_SRCFLAG_DEPRECATED 0x1
+
+struct hp_order {
+ union {
+ struct sockaddr_storage aiou_ss;
+ struct sockaddr aiou_sa;
+ } aio_src_un;
+#define aio_srcsa aio_src_un.aiou_sa
+ u_int32_t aio_srcflag;
+ int aio_srcscope;
+ int aio_dstscope;
+ struct policyqueue *aio_srcpolicy;
+ struct policyqueue *aio_dstpolicy;
+ union {
+ struct sockaddr_storage aiou_ss;
+ struct sockaddr aiou_sa;
+ } aio_un;
+#define aio_sa aio_un.aiou_sa
+ int aio_matchlen;
+ char *aio_h_addr;
+ int aio_initial_sequence;
+};
+
+static struct hostent *_hpcopy(struct hostent *, int *);
+static struct hostent *_hpaddr(int, const char *, void *, int *);
+#ifdef INET6
+static struct hostent *_hpmerge(struct hostent *, struct hostent *, int *);
+static struct hostent *_hpmapv6(struct hostent *, int *);
+#endif
+static struct hostent *_hpsort(struct hostent *, res_state);
+
+#ifdef INET6
+static struct hostent *_hpreorder(struct hostent *);
+static int get_addrselectpolicy(struct policyhead *);
+static void free_addrselectpolicy(struct policyhead *);
+static struct policyqueue *match_addrselectpolicy(struct sockaddr *,
+ struct policyhead *);
+static void set_source(struct hp_order *, struct policyhead *);
+static int matchlen(struct sockaddr *, struct sockaddr *);
+static int comp_dst(const void *, const void *);
+static int gai_addr2scopetype(struct sockaddr *);
+#endif
+
+/*
+ * Functions defined in RFC2553
+ * getipnodebyname, getipnodebyaddr, freehostent
+ */
+
+struct hostent *
+getipnodebyname(const char *name, int af, int flags, int *errp)
+{
+ struct hostent *hp;
+ union inx_addr addrbuf;
+ res_state statp;
+ u_long options;
+
+ switch (af) {
+ case AF_INET:
+#ifdef INET6
+ case AF_INET6:
+#endif
+ break;
+ default:
+ *errp = NO_RECOVERY;
+ return NULL;
+ }
+
+ if (flags & AI_ADDRCONFIG) {
+ int s;
+
+ if ((s = _socket(af, SOCK_DGRAM | SOCK_CLOEXEC, 0)) < 0)
+ return NULL;
+ /*
+ * TODO:
+ * Note that implementation dependent test for address
+ * configuration should be done every time called
+ * (or appropriate interval),
+ * because addresses will be dynamically assigned or deleted.
+ */
+ _close(s);
+ }
+
+#ifdef INET6
+ /* special case for literal address */
+ if (inet_pton(AF_INET6, name, &addrbuf) == 1) {
+ if (af != AF_INET6) {
+ *errp = HOST_NOT_FOUND;
+ return NULL;
+ }
+ return _hpaddr(af, name, &addrbuf, errp);
+ }
+#endif
+ if (inet_aton(name, (struct in_addr *)&addrbuf) == 1) {
+ if (af != AF_INET) {
+ if (MAPADDRENABLED(flags)) {
+ MAPADDR(&addrbuf, &addrbuf.in_addr);
+ } else {
+ *errp = HOST_NOT_FOUND;
+ return NULL;
+ }
+ }
+ return _hpaddr(af, name, &addrbuf, errp);
+ }
+
+
+ statp = __res_state();
+ if ((statp->options & RES_INIT) == 0) {
+ if (res_ninit(statp) < 0) {
+ *errp = NETDB_INTERNAL;
+ return NULL;
+ }
+ }
+
+ options = statp->options;
+ statp->options &= ~RES_USE_INET6;
+
+ hp = gethostbyname2(name, af);
+ hp = _hpcopy(hp, errp);
+#ifdef INET6
+ if (af == AF_INET6)
+ hp = _hpreorder(hp);
+
+ if (af == AF_INET6 && ((flags & AI_ALL) || hp == NULL) &&
+ MAPADDRENABLED(flags)) {
+ struct hostent *hp2 = gethostbyname2(name, AF_INET);
+ if (hp == NULL)
+ if (hp2 == NULL)
+ *errp = statp->res_h_errno;
+ else
+ hp = _hpmapv6(hp2, errp);
+ else {
+ if (hp2 && strcmp(hp->h_name, hp2->h_name) == 0) {
+ struct hostent *hpb = hp;
+ hp = _hpmerge(hpb, hp2, errp);
+ freehostent(hpb);
+ }
+ }
+ }
+#endif
+
+ if (hp == NULL)
+ *errp = statp->res_h_errno;
+
+ statp->options = options;
+ return _hpsort(hp, statp);
+}
+
+struct hostent *
+getipnodebyaddr(const void *src, size_t len, int af, int *errp)
+{
+ struct hostent *hp;
+ res_state statp;
+ u_long options;
+
+#ifdef INET6
+ struct in6_addr addrbuf;
+#else
+ struct in_addr addrbuf;
+#endif
+
+ switch (af) {
+ case AF_INET:
+ if (len != sizeof(struct in_addr)) {
+ *errp = NO_RECOVERY;
+ return NULL;
+ }
+ if (rounddown2((long)src, sizeof(struct in_addr))) {
+ memcpy(&addrbuf, src, len);
+ src = &addrbuf;
+ }
+ if (((struct in_addr *)src)->s_addr == 0)
+ return NULL;
+ break;
+#ifdef INET6
+ case AF_INET6:
+ if (len != sizeof(struct in6_addr)) {
+ *errp = NO_RECOVERY;
+ return NULL;
+ }
+ if (rounddown2((long)src, sizeof(struct in6_addr) / 2)) {
+ /* XXX */
+ memcpy(&addrbuf, src, len);
+ src = &addrbuf;
+ }
+ if (IN6_IS_ADDR_UNSPECIFIED((struct in6_addr *)src))
+ return NULL;
+ if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)src)
+ || IN6_IS_ADDR_V4COMPAT((struct in6_addr *)src)) {
+ src = (char *)src +
+ (sizeof(struct in6_addr) - sizeof(struct in_addr));
+ af = AF_INET;
+ len = sizeof(struct in_addr);
+ }
+ break;
+#endif
+ default:
+ *errp = NO_RECOVERY;
+ return NULL;
+ }
+
+ statp = __res_state();
+ if ((statp->options & RES_INIT) == 0) {
+ if (res_ninit(statp) < 0) {
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ return NULL;
+ }
+ }
+
+ options = statp->options;
+ statp->options &= ~RES_USE_INET6;
+
+ hp = gethostbyaddr(src, len, af);
+ if (hp == NULL)
+ *errp = statp->res_h_errno;
+
+ statp->options = options;
+ return (_hpcopy(hp, errp));
+}
+
+void
+freehostent(struct hostent *ptr)
+{
+ free(ptr);
+}
+
+/*
+ * Private utility functions
+ */
+
+/*
+ * _hpcopy: allocate and copy hostent structure
+ */
+static struct hostent *
+_hpcopy(struct hostent *hp, int *errp)
+{
+ struct hostent *nhp;
+ char *cp, **pp;
+ int size, addrsize;
+ int nalias = 0, naddr = 0;
+ int al_off;
+ int i;
+
+ if (hp == NULL)
+ return hp;
+
+ /* count size to be allocated */
+ size = sizeof(struct hostent);
+ if (hp->h_name != NULL)
+ size += strlen(hp->h_name) + 1;
+ if ((pp = hp->h_aliases) != NULL) {
+ for (i = 0; *pp != NULL; i++, pp++) {
+ if (**pp != '\0') {
+ size += strlen(*pp) + 1;
+ nalias++;
+ }
+ }
+ }
+ /* adjust alignment */
+ size = ALIGN(size);
+ al_off = size;
+ size += sizeof(char *) * (nalias + 1);
+ addrsize = ALIGN(hp->h_length);
+ if ((pp = hp->h_addr_list) != NULL) {
+ while (*pp++ != NULL)
+ naddr++;
+ }
+ size += addrsize * naddr;
+ size += sizeof(char *) * (naddr + 1);
+
+ /* copy */
+ if ((nhp = (struct hostent *)malloc(size)) == NULL) {
+ *errp = TRY_AGAIN;
+ return NULL;
+ }
+ cp = (char *)&nhp[1];
+ if (hp->h_name != NULL) {
+ nhp->h_name = cp;
+ strcpy(cp, hp->h_name);
+ cp += strlen(cp) + 1;
+ } else
+ nhp->h_name = NULL;
+ nhp->h_aliases = (char **)((char *)nhp + al_off);
+ if ((pp = hp->h_aliases) != NULL) {
+ for (i = 0; *pp != NULL; pp++) {
+ if (**pp != '\0') {
+ nhp->h_aliases[i++] = cp;
+ strcpy(cp, *pp);
+ cp += strlen(cp) + 1;
+ }
+ }
+ }
+ nhp->h_aliases[nalias] = NULL;
+ cp = (char *)&nhp->h_aliases[nalias + 1];
+ nhp->h_addrtype = hp->h_addrtype;
+ nhp->h_length = hp->h_length;
+ nhp->h_addr_list = (char **)cp;
+ if ((pp = hp->h_addr_list) != NULL) {
+ cp = (char *)&nhp->h_addr_list[naddr + 1];
+ for (i = 0; *pp != NULL; pp++) {
+ nhp->h_addr_list[i++] = cp;
+ memcpy(cp, *pp, hp->h_length);
+ cp += addrsize;
+ }
+ }
+ nhp->h_addr_list[naddr] = NULL;
+ return nhp;
+}
+
+/*
+ * _hpaddr: construct hostent structure with one address
+ */
+static struct hostent *
+_hpaddr(int af, const char *name, void *addr, int *errp)
+{
+ struct hostent *hp, hpbuf;
+ char *addrs[2];
+
+ hp = &hpbuf;
+ hp->h_name = (char *)name;
+ hp->h_aliases = NULL;
+ hp->h_addrtype = af;
+ hp->h_length = ADDRLEN(af);
+ hp->h_addr_list = addrs;
+ addrs[0] = (char *)addr;
+ addrs[1] = NULL;
+ return (_hpcopy(hp, errp));
+}
+
+#ifdef INET6
+/*
+ * _hpmerge: merge 2 hostent structure, arguments will be freed
+ */
+static struct hostent *
+_hpmerge(struct hostent *hp1, struct hostent *hp2, int *errp)
+{
+ int i, j;
+ int naddr, nalias;
+ char **pp;
+ struct hostent *hp, hpbuf;
+ char *aliases[MAXALIASES + 1], *addrs[MAXADDRS + 1];
+ union inx_addr addrbuf[MAXADDRS];
+
+ if (hp1 == NULL)
+ return _hpcopy(hp2, errp);
+ if (hp2 == NULL)
+ return _hpcopy(hp1, errp);
+
+#define HP(i) (i == 1 ? hp1 : hp2)
+ hp = &hpbuf;
+ hp->h_name = (hp1->h_name != NULL ? hp1->h_name : hp2->h_name);
+ hp->h_aliases = aliases;
+ nalias = 0;
+ for (i = 1; i <= 2; i++) {
+ if ((pp = HP(i)->h_aliases) == NULL)
+ continue;
+ for (; nalias < MAXALIASES && *pp != NULL; pp++) {
+ /* check duplicates */
+ for (j = 0; j < nalias; j++)
+ if (strcasecmp(*pp, aliases[j]) == 0)
+ break;
+ if (j == nalias)
+ aliases[nalias++] = *pp;
+ }
+ }
+ aliases[nalias] = NULL;
+ if (hp1->h_length != hp2->h_length) {
+ hp->h_addrtype = AF_INET6;
+ hp->h_length = sizeof(struct in6_addr);
+ } else {
+ hp->h_addrtype = hp1->h_addrtype;
+ hp->h_length = hp1->h_length;
+ }
+
+ hp->h_addr_list = addrs;
+ naddr = 0;
+ for (i = 1; i <= 2; i++) {
+ if ((pp = HP(i)->h_addr_list) == NULL)
+ continue;
+ if (HP(i)->h_length == hp->h_length) {
+ while (naddr < MAXADDRS && *pp != NULL)
+ addrs[naddr++] = *pp++;
+ } else {
+ /* copy IPv4 addr as mapped IPv6 addr */
+ while (naddr < MAXADDRS && *pp != NULL) {
+ MAPADDR(&addrbuf[naddr], *pp++);
+ addrs[naddr] = (char *)&addrbuf[naddr];
+ naddr++;
+ }
+ }
+ }
+ addrs[naddr] = NULL;
+ return (_hpcopy(hp, errp));
+}
+#endif
+
+/*
+ * _hpmapv6: convert IPv4 hostent into IPv4-mapped IPv6 addresses
+ */
+#ifdef INET6
+static struct hostent *
+_hpmapv6(struct hostent *hp, int *errp)
+{
+ struct hostent hp6;
+
+ if (hp == NULL)
+ return NULL;
+ if (hp->h_addrtype == AF_INET6)
+ return _hpcopy(hp, errp);
+
+ memset(&hp6, 0, sizeof(struct hostent));
+ hp6.h_addrtype = AF_INET6;
+ hp6.h_length = sizeof(struct in6_addr);
+ return _hpmerge(&hp6, hp, errp);
+}
+#endif
+
+/*
+ * _hpsort: sort address by sortlist
+ */
+static struct hostent *
+_hpsort(struct hostent *hp, res_state statp)
+{
+ int i, j, n;
+ u_char *ap, *sp, *mp, **pp;
+ char t;
+ char order[MAXADDRS];
+ int nsort = statp->nsort;
+
+ if (hp == NULL || hp->h_addr_list[1] == NULL || nsort == 0)
+ return hp;
+ for (i = 0; (ap = (u_char *)hp->h_addr_list[i]); i++) {
+ for (j = 0; j < nsort; j++) {
+#ifdef INET6
+ if (statp->_u._ext.ext->sort_list[j].af !=
+ hp->h_addrtype)
+ continue;
+ sp = (u_char *)&statp->_u._ext.ext->sort_list[j].addr;
+ mp = (u_char *)&statp->_u._ext.ext->sort_list[j].mask;
+#else
+ sp = (u_char *)&statp->sort_list[j].addr;
+ mp = (u_char *)&statp->sort_list[j].mask;
+#endif
+ for (n = 0; n < hp->h_length; n++) {
+ if ((ap[n] & mp[n]) != sp[n])
+ break;
+ }
+ if (n == hp->h_length)
+ break;
+ }
+ order[i] = j;
+ }
+ n = i;
+ pp = (u_char **)hp->h_addr_list;
+ for (i = 0; i < n - 1; i++) {
+ for (j = i + 1; j < n; j++) {
+ if (order[i] > order[j]) {
+ ap = pp[i];
+ pp[i] = pp[j];
+ pp[j] = ap;
+ t = order[i];
+ order[i] = order[j];
+ order[j] = t;
+ }
+ }
+ }
+ return hp;
+}
+
+#ifdef INET6
+/*
+ * _hpreorder: sort address by default address selection
+ */
+static struct hostent *
+_hpreorder(struct hostent *hp)
+{
+ struct hp_order *aio;
+ int i, n;
+ char *ap;
+ struct sockaddr *sa;
+ struct policyhead policyhead;
+
+ if (hp == NULL)
+ return hp;
+
+ switch (hp->h_addrtype) {
+ case AF_INET:
+#ifdef INET6
+ case AF_INET6:
+#endif
+ break;
+ default:
+ return hp;
+ }
+
+ /* count the number of addrinfo elements for sorting. */
+ for (n = 0; hp->h_addr_list[n] != NULL; n++)
+ ;
+
+ /*
+ * If the number is small enough, we can skip the reordering process.
+ */
+ if (n <= 1)
+ return hp;
+
+ /* allocate a temporary array for sort and initialization of it. */
+ if ((aio = malloc(sizeof(*aio) * n)) == NULL)
+ return hp; /* give up reordering */
+ memset(aio, 0, sizeof(*aio) * n);
+
+ /* retrieve address selection policy from the kernel */
+ TAILQ_INIT(&policyhead);
+ if (!get_addrselectpolicy(&policyhead)) {
+ /* no policy is installed into kernel, we don't sort. */
+ free(aio);
+ return hp;
+ }
+
+ for (i = 0; i < n; i++) {
+ ap = hp->h_addr_list[i];
+ aio[i].aio_h_addr = ap;
+ sa = &aio[i].aio_sa;
+ switch (hp->h_addrtype) {
+ case AF_INET:
+ sa->sa_family = AF_INET;
+ sa->sa_len = sizeof(struct sockaddr_in);
+ memcpy(&((struct sockaddr_in *)sa)->sin_addr, ap,
+ sizeof(struct in_addr));
+ break;
+#ifdef INET6
+ case AF_INET6:
+ if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) {
+ sa->sa_family = AF_INET;
+ sa->sa_len = sizeof(struct sockaddr_in);
+ memcpy(&((struct sockaddr_in *)sa)->sin_addr,
+ &ap[12], sizeof(struct in_addr));
+ } else {
+ sa->sa_family = AF_INET6;
+ sa->sa_len = sizeof(struct sockaddr_in6);
+ memcpy(&((struct sockaddr_in6 *)sa)->sin6_addr,
+ ap, sizeof(struct in6_addr));
+ }
+ break;
+#endif
+ }
+ aio[i].aio_dstscope = gai_addr2scopetype(sa);
+ aio[i].aio_dstpolicy = match_addrselectpolicy(sa, &policyhead);
+ set_source(&aio[i], &policyhead);
+ aio[i].aio_initial_sequence = i;
+ }
+
+ /* perform sorting. */
+ qsort(aio, n, sizeof(*aio), comp_dst);
+
+ /* reorder the h_addr_list. */
+ for (i = 0; i < n; i++)
+ hp->h_addr_list[i] = aio[i].aio_h_addr;
+
+ /* cleanup and return */
+ free(aio);
+ free_addrselectpolicy(&policyhead);
+ return hp;
+}
+
+static int
+get_addrselectpolicy(struct policyhead *head)
+{
+#ifdef INET6
+ int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_ADDRCTLPOLICY };
+ size_t l;
+ char *buf;
+ struct in6_addrpolicy *pol, *ep;
+
+ if (sysctl(mib, nitems(mib), NULL, &l, NULL, 0) < 0)
+ return (0);
+ if ((buf = malloc(l)) == NULL)
+ return (0);
+ if (sysctl(mib, nitems(mib), buf, &l, NULL, 0) < 0) {
+ free(buf);
+ return (0);
+ }
+
+ ep = (struct in6_addrpolicy *)(buf + l);
+ for (pol = (struct in6_addrpolicy *)buf; pol + 1 <= ep; pol++) {
+ struct policyqueue *new;
+
+ if ((new = malloc(sizeof(*new))) == NULL) {
+ free_addrselectpolicy(head); /* make the list empty */
+ break;
+ }
+ new->pc_policy = *pol;
+ TAILQ_INSERT_TAIL(head, new, pc_entry);
+ }
+
+ free(buf);
+ return (1);
+#else
+ return (0);
+#endif
+}
+
+static void
+free_addrselectpolicy(struct policyhead *head)
+{
+ struct policyqueue *ent, *nent;
+
+ for (ent = TAILQ_FIRST(head); ent; ent = nent) {
+ nent = TAILQ_NEXT(ent, pc_entry);
+ TAILQ_REMOVE(head, ent, pc_entry);
+ free(ent);
+ }
+}
+
+static struct policyqueue *
+match_addrselectpolicy(struct sockaddr *addr, struct policyhead *head)
+{
+#ifdef INET6
+ struct policyqueue *ent, *bestent = NULL;
+ struct in6_addrpolicy *pol;
+ int matchlen, bestmatchlen = -1;
+ u_char *mp, *ep, *k, *p, m;
+ struct sockaddr_in6 key;
+
+ switch(addr->sa_family) {
+ case AF_INET6:
+ key = *(struct sockaddr_in6 *)addr;
+ break;
+ case AF_INET:
+ /* convert the address into IPv4-mapped IPv6 address. */
+ memset(&key, 0, sizeof(key));
+ key.sin6_family = AF_INET6;
+ key.sin6_len = sizeof(key);
+ _map_v4v6_address(
+ (char *)&((struct sockaddr_in *)addr)->sin_addr,
+ (char *)&key.sin6_addr);
+ break;
+ default:
+ return(NULL);
+ }
+
+ for (ent = TAILQ_FIRST(head); ent; ent = TAILQ_NEXT(ent, pc_entry)) {
+ pol = &ent->pc_policy;
+ matchlen = 0;
+
+ mp = (u_char *)&pol->addrmask.sin6_addr;
+ ep = mp + 16; /* XXX: scope field? */
+ k = (u_char *)&key.sin6_addr;
+ p = (u_char *)&pol->addr.sin6_addr;
+ for (; mp < ep && *mp; mp++, k++, p++) {
+ m = *mp;
+ if ((*k & m) != *p)
+ goto next; /* not match */
+ if (m == 0xff) /* short cut for a typical case */
+ matchlen += 8;
+ else {
+ while (m >= 0x80) {
+ matchlen++;
+ m <<= 1;
+ }
+ }
+ }
+
+ /* matched. check if this is better than the current best. */
+ if (matchlen > bestmatchlen) {
+ bestent = ent;
+ bestmatchlen = matchlen;
+ }
+
+ next:
+ continue;
+ }
+
+ return(bestent);
+#else
+ return(NULL);
+#endif
+
+}
+
+static void
+set_source(struct hp_order *aio, struct policyhead *ph)
+{
+ struct sockaddr_storage ss = aio->aio_un.aiou_ss;
+ socklen_t srclen;
+ int s;
+
+ /* set unspec ("no source is available"), just in case */
+ aio->aio_srcsa.sa_family = AF_UNSPEC;
+ aio->aio_srcscope = -1;
+
+ switch(ss.ss_family) {
+ case AF_INET:
+ ((struct sockaddr_in *)&ss)->sin_port = htons(1);
+ break;
+#ifdef INET6
+ case AF_INET6:
+ ((struct sockaddr_in6 *)&ss)->sin6_port = htons(1);
+ break;
+#endif
+ default: /* ignore unsupported AFs explicitly */
+ return;
+ }
+
+ /* open a socket to get the source address for the given dst */
+ if ((s = _socket(ss.ss_family, SOCK_DGRAM | SOCK_CLOEXEC,
+ IPPROTO_UDP)) < 0)
+ return; /* give up */
+ if (_connect(s, (struct sockaddr *)&ss, ss.ss_len) < 0)
+ goto cleanup;
+ srclen = ss.ss_len;
+ if (_getsockname(s, &aio->aio_srcsa, &srclen) < 0) {
+ aio->aio_srcsa.sa_family = AF_UNSPEC;
+ goto cleanup;
+ }
+ aio->aio_srcscope = gai_addr2scopetype(&aio->aio_srcsa);
+ aio->aio_srcpolicy = match_addrselectpolicy(&aio->aio_srcsa, ph);
+ aio->aio_matchlen = matchlen(&aio->aio_srcsa, (struct sockaddr *)&ss);
+#ifdef INET6
+ if (ss.ss_family == AF_INET6) {
+ struct in6_ifreq ifr6;
+ u_int32_t flags6;
+
+ memset(&ifr6, 0, sizeof(ifr6));
+ memcpy(&ifr6.ifr_addr, &ss, ss.ss_len);
+ if (_ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) == 0) {
+ flags6 = ifr6.ifr_ifru.ifru_flags6;
+ if ((flags6 & IN6_IFF_DEPRECATED))
+ aio->aio_srcflag |= AIO_SRCFLAG_DEPRECATED;
+ }
+ }
+#endif
+
+ cleanup:
+ _close(s);
+ return;
+}
+
+static int
+matchlen(struct sockaddr *src, struct sockaddr *dst)
+{
+ int match = 0;
+ u_char *s, *d;
+ u_char *lim, r;
+ int addrlen;
+
+ switch (src->sa_family) {
+#ifdef INET6
+ case AF_INET6:
+ s = (u_char *)&((struct sockaddr_in6 *)src)->sin6_addr;
+ d = (u_char *)&((struct sockaddr_in6 *)dst)->sin6_addr;
+ addrlen = sizeof(struct in6_addr);
+ lim = s + addrlen;
+ break;
+#endif
+ case AF_INET:
+ s = (u_char *)&((struct sockaddr_in *)src)->sin_addr;
+ d = (u_char *)&((struct sockaddr_in *)dst)->sin_addr;
+ addrlen = sizeof(struct in_addr);
+ lim = s + addrlen;
+ break;
+ default:
+ return(0);
+ }
+
+ while (s < lim)
+ if ((r = (*d++ ^ *s++)) != 0) {
+ while ((r & 0x80) == 0) {
+ match++;
+ r <<= 1;
+ }
+ break;
+ } else
+ match += 8;
+ return(match);
+}
+
+static int
+comp_dst(const void *arg1, const void *arg2)
+{
+ const struct hp_order *dst1 = arg1, *dst2 = arg2;
+
+ /*
+ * Rule 1: Avoid unusable destinations.
+ * XXX: we currently do not consider if an appropriate route exists.
+ */
+ if (dst1->aio_srcsa.sa_family != AF_UNSPEC &&
+ dst2->aio_srcsa.sa_family == AF_UNSPEC) {
+ return(-1);
+ }
+ if (dst1->aio_srcsa.sa_family == AF_UNSPEC &&
+ dst2->aio_srcsa.sa_family != AF_UNSPEC) {
+ return(1);
+ }
+
+ /* Rule 2: Prefer matching scope. */
+ if (dst1->aio_dstscope == dst1->aio_srcscope &&
+ dst2->aio_dstscope != dst2->aio_srcscope) {
+ return(-1);
+ }
+ if (dst1->aio_dstscope != dst1->aio_srcscope &&
+ dst2->aio_dstscope == dst2->aio_srcscope) {
+ return(1);
+ }
+
+ /* Rule 3: Avoid deprecated addresses. */
+ if (dst1->aio_srcsa.sa_family != AF_UNSPEC &&
+ dst2->aio_srcsa.sa_family != AF_UNSPEC) {
+ if (!(dst1->aio_srcflag & AIO_SRCFLAG_DEPRECATED) &&
+ (dst2->aio_srcflag & AIO_SRCFLAG_DEPRECATED)) {
+ return(-1);
+ }
+ if ((dst1->aio_srcflag & AIO_SRCFLAG_DEPRECATED) &&
+ !(dst2->aio_srcflag & AIO_SRCFLAG_DEPRECATED)) {
+ return(1);
+ }
+ }
+
+ /* Rule 4: Prefer home addresses. */
+ /* XXX: not implemented yet */
+
+ /* Rule 5: Prefer matching label. */
+#ifdef INET6
+ if (dst1->aio_srcpolicy && dst1->aio_dstpolicy &&
+ dst1->aio_srcpolicy->pc_policy.label ==
+ dst1->aio_dstpolicy->pc_policy.label &&
+ (dst2->aio_srcpolicy == NULL || dst2->aio_dstpolicy == NULL ||
+ dst2->aio_srcpolicy->pc_policy.label !=
+ dst2->aio_dstpolicy->pc_policy.label)) {
+ return(-1);
+ }
+ if (dst2->aio_srcpolicy && dst2->aio_dstpolicy &&
+ dst2->aio_srcpolicy->pc_policy.label ==
+ dst2->aio_dstpolicy->pc_policy.label &&
+ (dst1->aio_srcpolicy == NULL || dst1->aio_dstpolicy == NULL ||
+ dst1->aio_srcpolicy->pc_policy.label !=
+ dst1->aio_dstpolicy->pc_policy.label)) {
+ return(1);
+ }
+#endif
+
+ /* Rule 6: Prefer higher precedence. */
+#ifdef INET6
+ if (dst1->aio_dstpolicy &&
+ (dst2->aio_dstpolicy == NULL ||
+ dst1->aio_dstpolicy->pc_policy.preced >
+ dst2->aio_dstpolicy->pc_policy.preced)) {
+ return(-1);
+ }
+ if (dst2->aio_dstpolicy &&
+ (dst1->aio_dstpolicy == NULL ||
+ dst2->aio_dstpolicy->pc_policy.preced >
+ dst1->aio_dstpolicy->pc_policy.preced)) {
+ return(1);
+ }
+#endif
+
+ /* Rule 7: Prefer native transport. */
+ /* XXX: not implemented yet */
+
+ /* Rule 8: Prefer smaller scope. */
+ if (dst1->aio_dstscope >= 0 &&
+ dst1->aio_dstscope < dst2->aio_dstscope) {
+ return(-1);
+ }
+ if (dst2->aio_dstscope >= 0 &&
+ dst2->aio_dstscope < dst1->aio_dstscope) {
+ return(1);
+ }
+
+ /*
+ * Rule 9: Use longest matching prefix.
+ * We compare the match length in a same AF only.
+ */
+ if (dst1->aio_sa.sa_family == dst2->aio_sa.sa_family) {
+ if (dst1->aio_matchlen > dst2->aio_matchlen) {
+ return(-1);
+ }
+ if (dst1->aio_matchlen < dst2->aio_matchlen) {
+ return(1);
+ }
+ }
+
+ /* Rule 10: Otherwise, leave the order unchanged. */
+
+ /*
+ * Note that qsort is unstable; so, we can't return zero and
+ * expect the order to be unchanged.
+ * That also means we can't depend on the current position of
+ * dst2 being after dst1. We must enforce the initial order
+ * with an explicit compare on the original position.
+ * The qsort specification requires that "When the same objects
+ * (consisting of width bytes, irrespective of their current
+ * positions in the array) are passed more than once to the
+ * comparison function, the results shall be consistent with one
+ * another."
+ * In other words, If A < B, then we must also return B > A.
+ */
+ if (dst2->aio_initial_sequence < dst1->aio_initial_sequence)
+ return(1);
+
+ return(-1);
+}
+
+/*
+ * Copy from scope.c.
+ * XXX: we should standardize the functions and link them as standard
+ * library.
+ */
+static int
+gai_addr2scopetype(struct sockaddr *sa)
+{
+#ifdef INET6
+ struct sockaddr_in6 *sa6;
+#endif
+ struct sockaddr_in *sa4;
+
+ switch(sa->sa_family) {
+#ifdef INET6
+ case AF_INET6:
+ sa6 = (struct sockaddr_in6 *)sa;
+ if (IN6_IS_ADDR_MULTICAST(&sa6->sin6_addr)) {
+ /* just use the scope field of the multicast address */
+ return(sa6->sin6_addr.s6_addr[2] & 0x0f);
+ }
+ /*
+ * Unicast addresses: map scope type to corresponding scope
+ * value defined for multcast addresses.
+ * XXX: hardcoded scope type values are bad...
+ */
+ if (IN6_IS_ADDR_LOOPBACK(&sa6->sin6_addr))
+ return(1); /* node local scope */
+ if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr))
+ return(2); /* link-local scope */
+ if (IN6_IS_ADDR_SITELOCAL(&sa6->sin6_addr))
+ return(5); /* site-local scope */
+ return(14); /* global scope */
+ break;
+#endif
+ case AF_INET:
+ /*
+ * IPv4 pseudo scoping according to RFC 3484.
+ */
+ sa4 = (struct sockaddr_in *)sa;
+ /* IPv4 autoconfiguration addresses have link-local scope. */
+ if (((u_char *)&sa4->sin_addr)[0] == 169 &&
+ ((u_char *)&sa4->sin_addr)[1] == 254)
+ return(2);
+ /* Private addresses have site-local scope. */
+ if (((u_char *)&sa4->sin_addr)[0] == 10 ||
+ (((u_char *)&sa4->sin_addr)[0] == 172 &&
+ (((u_char *)&sa4->sin_addr)[1] & 0xf0) == 16) ||
+ (((u_char *)&sa4->sin_addr)[0] == 192 &&
+ ((u_char *)&sa4->sin_addr)[1] == 168))
+ return(14); /* XXX: It should be 5 unless NAT */
+ /* Loopback addresses have link-local scope. */
+ if (((u_char *)&sa4->sin_addr)[0] == 127)
+ return(2);
+ return(14);
+ break;
+ default:
+ errno = EAFNOSUPPORT; /* is this a good error? */
+ return(-1);
+ }
+}
+#endif
diff --git a/lib/libc/net/netdb_private.h b/lib/libc/net/netdb_private.h
new file mode 100644
index 000000000000..8ab224717cc1
--- /dev/null
+++ b/lib/libc/net/netdb_private.h
@@ -0,0 +1,162 @@
+/*-
+ * Copyright (C) 2005 The FreeBSD Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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 _NETDB_PRIVATE_H_
+#define _NETDB_PRIVATE_H_
+
+#include <stdio.h> /* XXX: for FILE */
+
+#define NETDB_THREAD_ALLOC(name) \
+static struct name name; \
+static thread_key_t name##_key; \
+static once_t name##_init_once = ONCE_INITIALIZER; \
+static int name##_thr_keycreated = 0; \
+\
+static void name##_free(void *); \
+\
+static void \
+name##_keycreate(void) \
+{ \
+ name##_thr_keycreated = \
+ (thr_keycreate(&name##_key, name##_free) == 0); \
+} \
+\
+struct name * \
+__##name##_init(void) \
+{ \
+ struct name *he; \
+ \
+ if (thr_main() != 0) \
+ return (&name); \
+ if (thr_once(&name##_init_once, name##_keycreate) != 0 || \
+ !name##_thr_keycreated) \
+ return (NULL); \
+ if ((he = thr_getspecific(name##_key)) != NULL) \
+ return (he); \
+ if ((he = calloc(1, sizeof(*he))) == NULL) \
+ return (NULL); \
+ if (thr_setspecific(name##_key, he) == 0) \
+ return (he); \
+ free(he); \
+ return (NULL); \
+}
+
+#define _MAXALIASES 35
+#define _MAXLINELEN 1024
+#define _MAXADDRS 35
+#define _HOSTBUFSIZE (8 * 1024)
+#define _NETBUFSIZE 1025
+
+struct hostent_data {
+ uint32_t host_addr[4]; /* IPv4 or IPv6 */
+ char *h_addr_ptrs[_MAXADDRS + 1];
+ char *host_aliases[_MAXALIASES];
+ char hostbuf[_HOSTBUFSIZE];
+ FILE *hostf;
+ int stayopen;
+#ifdef YP
+ char *yp_domain;
+#endif
+};
+
+struct netent_data {
+ char *net_aliases[_MAXALIASES];
+ char netbuf[_NETBUFSIZE];
+ FILE *netf;
+ int stayopen;
+#ifdef YP
+ char *yp_domain;
+#endif
+};
+
+struct protoent_data {
+ FILE *fp;
+ char *aliases[_MAXALIASES];
+ int stayopen;
+ char line[_MAXLINELEN + 1];
+};
+
+struct hostdata {
+ struct hostent host;
+ char data[sizeof(struct hostent_data)];
+};
+
+struct netdata {
+ struct netent net;
+ char data[sizeof(struct netent_data)];
+};
+
+struct protodata {
+ struct protoent proto;
+ char data[sizeof(struct protoent_data)];
+};
+
+struct hostdata *__hostdata_init(void);
+struct hostent *__hostent_init(void);
+struct hostent_data *__hostent_data_init(void);
+struct netdata *__netdata_init(void);
+struct netent_data *__netent_data_init(void);
+struct protodata *__protodata_init(void);
+struct protoent_data *__protoent_data_init(void);
+int __copy_hostent(struct hostent *, struct hostent *, char *, size_t);
+int __copy_netent(struct netent *, struct netent *, char *, size_t);
+int __copy_protoent(struct protoent *, struct protoent *, char *, size_t);
+
+void __endprotoent_p(struct protoent_data *);
+int __getprotoent_p(struct protoent *, struct protoent_data *);
+void __setprotoent_p(int, struct protoent_data *);
+void _endhostdnsent(void);
+void _endhosthtent(struct hostent_data *);
+void _endnetdnsent(void);
+void _endnethtent(struct netent_data *);
+void _map_v4v6_address(const char *, char *);
+void _map_v4v6_hostent(struct hostent *, char **, char *);
+void _sethostdnsent(int);
+void _sethosthtent(int, struct hostent_data *);
+void _setnetdnsent(int);
+void _setnethtent(int, struct netent_data *);
+
+struct hostent *__dns_getanswer(const char *, int, const char *, int);
+int _dns_gethostbyaddr(void *, void *, va_list);
+int _dns_gethostbyname(void *, void *, va_list);
+int _dns_getnetbyaddr(void *, void *, va_list);
+int _dns_getnetbyname(void *, void *, va_list);
+int _ht_gethostbyaddr(void *, void *, va_list);
+int _ht_gethostbyname(void *, void *, va_list);
+int _ht_getnetbyaddr(void *, void *, va_list);
+int _ht_getnetbyname(void *, void *, va_list);
+int _nis_gethostbyaddr(void *, void *, va_list);
+int _nis_gethostbyname(void *, void *, va_list);
+int _nis_getnetbyaddr(void *, void *, va_list);
+int _nis_getnetbyname(void *, void *, va_list);
+#ifdef NS_CACHING
+int __proto_id_func(char *, size_t *, va_list, void *);
+int __proto_marshal_func(char *, size_t *, void *, va_list, void *);
+int __proto_unmarshal_func(char *, size_t, void *, va_list, void *);
+#endif
+
+#endif /* _NETDB_PRIVATE_H_ */
diff --git a/lib/libc/net/nscache.c b/lib/libc/net/nscache.c
new file mode 100644
index 000000000000..88a115be673b
--- /dev/null
+++ b/lib/libc/net/nscache.c
@@ -0,0 +1,439 @@
+/*-
+ * Copyright (c) 2005 Michael Bushkov <bushman@rsu.ru>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#define _NS_PRIVATE
+#include <nsswitch.h>
+#include <stdlib.h>
+#include <string.h>
+#include "un-namespace.h"
+#include "nscachedcli.h"
+#include "nscache.h"
+
+#define NSS_CACHE_KEY_INITIAL_SIZE (256)
+#define NSS_CACHE_KEY_SIZE_LIMIT (NSS_CACHE_KEY_INITIAL_SIZE << 4)
+
+#define NSS_CACHE_BUFFER_INITIAL_SIZE (1024)
+#define NSS_CACHE_BUFFER_SIZE_LIMIT (NSS_CACHE_BUFFER_INITIAL_SIZE << 8)
+
+#define CACHED_SOCKET_PATH "/var/run/nscd"
+
+int
+__nss_cache_handler(void *retval, void *mdata, va_list ap)
+{
+ return (NS_UNAVAIL);
+}
+
+int
+__nss_common_cache_read(void *retval, void *mdata, va_list ap)
+{
+ struct cached_connection_params params;
+ cached_connection connection;
+
+ char *buffer;
+ size_t buffer_size, size;
+
+ nss_cache_info const *cache_info;
+ nss_cache_data *cache_data;
+ va_list ap_new;
+ int res;
+
+ cache_data = (nss_cache_data *)mdata;
+ cache_info = cache_data->info;
+
+ memset(&params, 0, sizeof(struct cached_connection_params));
+ params.socket_path = CACHED_SOCKET_PATH;
+
+ cache_data->key = (char *)malloc(NSS_CACHE_KEY_INITIAL_SIZE);
+ memset(cache_data->key, 0, NSS_CACHE_KEY_INITIAL_SIZE);
+ cache_data->key_size = NSS_CACHE_KEY_INITIAL_SIZE;
+ va_copy(ap_new, ap);
+
+ do {
+ size = cache_data->key_size;
+ res = cache_info->id_func(cache_data->key, &size, ap_new,
+ cache_info->mdata);
+ va_end(ap_new);
+ if (res == NS_RETURN) {
+ if (cache_data->key_size > NSS_CACHE_KEY_SIZE_LIMIT)
+ break;
+
+ cache_data->key_size <<= 1;
+ cache_data->key = realloc(cache_data->key,
+ cache_data->key_size);
+ memset(cache_data->key, 0, cache_data->key_size);
+ va_copy(ap_new, ap);
+ }
+ } while (res == NS_RETURN);
+
+ if (res != NS_SUCCESS) {
+ free(cache_data->key);
+ cache_data->key = NULL;
+ cache_data->key_size = 0;
+ return (res);
+ } else
+ cache_data->key_size = size;
+
+ buffer_size = NSS_CACHE_BUFFER_INITIAL_SIZE;
+ buffer = (char *)malloc(NSS_CACHE_BUFFER_INITIAL_SIZE);
+ memset(buffer, 0, NSS_CACHE_BUFFER_INITIAL_SIZE);
+
+ do {
+ connection = __open_cached_connection(&params);
+ if (connection == NULL) {
+ res = -1;
+ break;
+ }
+ res = __cached_read(connection, cache_info->entry_name,
+ cache_data->key, cache_data->key_size, buffer,
+ &buffer_size);
+ __close_cached_connection(connection);
+ if (res == -2 && buffer_size < NSS_CACHE_BUFFER_SIZE_LIMIT) {
+ buffer = (char *)realloc(buffer, buffer_size);
+ memset(buffer, 0, buffer_size);
+ }
+ } while (res == -2);
+
+ if (res == 0) {
+ if (buffer_size == 0) {
+ free(buffer);
+ free(cache_data->key);
+ cache_data->key = NULL;
+ cache_data->key_size = 0;
+ return (NS_RETURN);
+ }
+
+ va_copy(ap_new, ap);
+ res = cache_info->unmarshal_func(buffer, buffer_size, retval,
+ ap_new, cache_info->mdata);
+ va_end(ap_new);
+
+ if (res != NS_SUCCESS) {
+ free(buffer);
+ free(cache_data->key);
+ cache_data->key = NULL;
+ cache_data->key_size = 0;
+ return (res);
+ } else
+ res = 0;
+ }
+
+ if (res == 0) {
+ free(cache_data->key);
+ cache_data->key = NULL;
+ cache_data->key_size = 0;
+ }
+
+ free(buffer);
+ return (res == 0 ? NS_SUCCESS : NS_NOTFOUND);
+}
+
+int
+__nss_common_cache_write(void *retval, void *mdata, va_list ap)
+{
+ struct cached_connection_params params;
+ cached_connection connection;
+
+ char *buffer;
+ size_t buffer_size;
+
+ nss_cache_info const *cache_info;
+ nss_cache_data *cache_data;
+ va_list ap_new;
+ int res;
+
+ cache_data = (nss_cache_data *)mdata;
+ cache_info = cache_data->info;
+
+ if (cache_data->key == NULL)
+ return (NS_UNAVAIL);
+
+ memset(&params, 0, sizeof(struct cached_connection_params));
+ params.socket_path = CACHED_SOCKET_PATH;
+
+ connection = __open_cached_connection(&params);
+ if (connection == NULL) {
+ free(cache_data->key);
+ return (NS_UNAVAIL);
+ }
+
+ buffer_size = NSS_CACHE_BUFFER_INITIAL_SIZE;
+ buffer = (char *)malloc(NSS_CACHE_BUFFER_INITIAL_SIZE);
+ memset(buffer, 0, NSS_CACHE_BUFFER_INITIAL_SIZE);
+
+ do {
+ size_t size;
+
+ size = buffer_size;
+ va_copy(ap_new, ap);
+ res = cache_info->marshal_func(buffer, &size, retval, ap_new,
+ cache_info->mdata);
+ va_end(ap_new);
+
+ if (res == NS_RETURN) {
+ if (buffer_size > NSS_CACHE_BUFFER_SIZE_LIMIT)
+ break;
+
+ buffer_size <<= 1;
+ buffer = (char *)realloc(buffer, buffer_size);
+ memset(buffer, 0, buffer_size);
+ }
+ } while (res == NS_RETURN);
+
+ if (res != NS_SUCCESS) {
+ __close_cached_connection(connection);
+ free(cache_data->key);
+ free(buffer);
+ return (res);
+ }
+
+ res = __cached_write(connection, cache_info->entry_name,
+ cache_data->key, cache_data->key_size, buffer, buffer_size);
+ __close_cached_connection(connection);
+
+ free(cache_data->key);
+ free(buffer);
+
+ return (res == 0 ? NS_SUCCESS : NS_UNAVAIL);
+}
+
+int
+__nss_common_cache_write_negative(void *mdata)
+{
+ struct cached_connection_params params;
+ cached_connection connection;
+ int res;
+
+ nss_cache_info const *cache_info;
+ nss_cache_data *cache_data;
+
+ cache_data = (nss_cache_data *)mdata;
+ cache_info = cache_data->info;
+
+ if (cache_data->key == NULL)
+ return (NS_UNAVAIL);
+
+ memset(&params, 0, sizeof(struct cached_connection_params));
+ params.socket_path = CACHED_SOCKET_PATH;
+
+ connection = __open_cached_connection(&params);
+ if (connection == NULL) {
+ free(cache_data->key);
+ return (NS_UNAVAIL);
+ }
+
+ res = __cached_write(connection, cache_info->entry_name,
+ cache_data->key, cache_data->key_size, NULL, 0);
+ __close_cached_connection(connection);
+
+ free(cache_data->key);
+ return (res == 0 ? NS_SUCCESS : NS_UNAVAIL);
+}
+
+int
+__nss_mp_cache_read(void *retval, void *mdata, va_list ap)
+{
+ struct cached_connection_params params;
+ cached_mp_read_session rs;
+
+ char *buffer;
+ size_t buffer_size;
+
+ nss_cache_info const *cache_info;
+ nss_cache_data *cache_data;
+ va_list ap_new;
+ int res;
+
+ cache_data = (nss_cache_data *)mdata;
+ cache_info = cache_data->info;
+
+ if (cache_info->get_mp_ws_func() != INVALID_CACHED_MP_WRITE_SESSION)
+ return (NS_UNAVAIL);
+
+ rs = cache_info->get_mp_rs_func();
+ if (rs == INVALID_CACHED_MP_READ_SESSION) {
+ memset(&params, 0, sizeof(struct cached_connection_params));
+ params.socket_path = CACHED_SOCKET_PATH;
+
+ rs = __open_cached_mp_read_session(&params,
+ cache_info->entry_name);
+ if (rs == INVALID_CACHED_MP_READ_SESSION)
+ return (NS_UNAVAIL);
+
+ cache_info->set_mp_rs_func(rs);
+ }
+
+ buffer_size = NSS_CACHE_BUFFER_INITIAL_SIZE;
+ buffer = (char *)malloc(NSS_CACHE_BUFFER_INITIAL_SIZE);
+ memset(buffer, 0, NSS_CACHE_BUFFER_INITIAL_SIZE);
+
+ do {
+ res = __cached_mp_read(rs, buffer, &buffer_size);
+ if (res == -2 && buffer_size < NSS_CACHE_BUFFER_SIZE_LIMIT) {
+ buffer = (char *)realloc(buffer, buffer_size);
+ memset(buffer, 0, buffer_size);
+ }
+ } while (res == -2);
+
+ if (res == 0) {
+ va_copy(ap_new, ap);
+ res = cache_info->unmarshal_func(buffer, buffer_size, retval,
+ ap_new, cache_info->mdata);
+ va_end(ap_new);
+
+ if (res != NS_SUCCESS) {
+ free(buffer);
+ return (res);
+ } else
+ res = 0;
+ } else {
+ free(buffer);
+ __close_cached_mp_read_session(rs);
+ rs = INVALID_CACHED_MP_READ_SESSION;
+ cache_info->set_mp_rs_func(rs);
+ return (res == -1 ? NS_RETURN : NS_UNAVAIL);
+ }
+
+ free(buffer);
+ return (res == 0 ? NS_SUCCESS : NS_NOTFOUND);
+}
+
+int
+__nss_mp_cache_write(void *retval, void *mdata, va_list ap)
+{
+ struct cached_connection_params params;
+ cached_mp_write_session ws;
+
+ char *buffer;
+ size_t buffer_size;
+
+ nss_cache_info const *cache_info;
+ nss_cache_data *cache_data;
+ va_list ap_new;
+ int res;
+
+ cache_data = (nss_cache_data *)mdata;
+ cache_info = cache_data->info;
+
+ ws = cache_info->get_mp_ws_func();
+ if (ws == INVALID_CACHED_MP_WRITE_SESSION) {
+ memset(&params, 0, sizeof(struct cached_connection_params));
+ params.socket_path = CACHED_SOCKET_PATH;
+
+ ws = __open_cached_mp_write_session(&params,
+ cache_info->entry_name);
+ if (ws == INVALID_CACHED_MP_WRITE_SESSION)
+ return (NS_UNAVAIL);
+
+ cache_info->set_mp_ws_func(ws);
+ }
+
+ buffer_size = NSS_CACHE_BUFFER_INITIAL_SIZE;
+ buffer = (char *)malloc(NSS_CACHE_BUFFER_INITIAL_SIZE);
+ memset(buffer, 0, NSS_CACHE_BUFFER_INITIAL_SIZE);
+
+ do {
+ size_t size;
+
+ size = buffer_size;
+ va_copy(ap_new, ap);
+ res = cache_info->marshal_func(buffer, &size, retval, ap_new,
+ cache_info->mdata);
+ va_end(ap_new);
+
+ if (res == NS_RETURN) {
+ if (buffer_size > NSS_CACHE_BUFFER_SIZE_LIMIT)
+ break;
+
+ buffer_size <<= 1;
+ buffer = (char *)realloc(buffer, buffer_size);
+ memset(buffer, 0, buffer_size);
+ }
+ } while (res == NS_RETURN);
+
+ if (res != NS_SUCCESS) {
+ free(buffer);
+ return (res);
+ }
+
+ res = __cached_mp_write(ws, buffer, buffer_size);
+
+ free(buffer);
+ return (res == 0 ? NS_SUCCESS : NS_UNAVAIL);
+}
+
+int
+__nss_mp_cache_write_submit(void *retval, void *mdata, va_list ap)
+{
+ cached_mp_write_session ws;
+
+ nss_cache_info const *cache_info;
+ nss_cache_data *cache_data;
+
+ cache_data = (nss_cache_data *)mdata;
+ cache_info = cache_data->info;
+
+ ws = cache_info->get_mp_ws_func();
+ if (ws != INVALID_CACHED_MP_WRITE_SESSION) {
+ __close_cached_mp_write_session(ws);
+ ws = INVALID_CACHED_MP_WRITE_SESSION;
+ cache_info->set_mp_ws_func(ws);
+ }
+ return (NS_UNAVAIL);
+}
+
+int
+__nss_mp_cache_end(void *retval, void *mdata, va_list ap)
+{
+ cached_mp_write_session ws;
+ cached_mp_read_session rs;
+
+ nss_cache_info const *cache_info;
+ nss_cache_data *cache_data;
+
+ cache_data = (nss_cache_data *)mdata;
+ cache_info = cache_data->info;
+
+ ws = cache_info->get_mp_ws_func();
+ if (ws != INVALID_CACHED_MP_WRITE_SESSION) {
+ __abandon_cached_mp_write_session(ws);
+ ws = INVALID_CACHED_MP_WRITE_SESSION;
+ cache_info->set_mp_ws_func(ws);
+ }
+
+ rs = cache_info->get_mp_rs_func();
+ if (rs != INVALID_CACHED_MP_READ_SESSION) {
+ __close_cached_mp_read_session(rs);
+ rs = INVALID_CACHED_MP_READ_SESSION;
+ cache_info->set_mp_rs_func(rs);
+ }
+
+ return (NS_UNAVAIL);
+}
diff --git a/lib/libc/net/nscachedcli.c b/lib/libc/net/nscachedcli.c
new file mode 100644
index 000000000000..35dbe20f722c
--- /dev/null
+++ b/lib/libc/net/nscachedcli.c
@@ -0,0 +1,577 @@
+/*-
+ * Copyright (c) 2005 Michael Bushkov <bushman@rsu.ru>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/event.h>
+#include <sys/uio.h>
+#include <sys/un.h>
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "un-namespace.h"
+#include "nscachedcli.h"
+
+#define NS_DEFAULT_CACHED_IO_TIMEOUT 4
+
+static int safe_write(struct cached_connection_ *, const void *, size_t);
+static int safe_read(struct cached_connection_ *, void *, size_t);
+static int send_credentials(struct cached_connection_ *, int);
+
+/*
+ * safe_write writes data to the specified connection and tries to do it in
+ * the very safe manner. We ensure, that we can write to the socket with
+ * kevent. If the data_size can't be sent in one piece, then it would be
+ * splitted.
+ */
+static int
+safe_write(struct cached_connection_ *connection, const void *data,
+ size_t data_size)
+{
+ struct kevent eventlist;
+ int nevents;
+ size_t result;
+ ssize_t s_result;
+ struct timespec timeout;
+
+ if (data_size == 0)
+ return (0);
+
+ timeout.tv_sec = NS_DEFAULT_CACHED_IO_TIMEOUT;
+ timeout.tv_nsec = 0;
+ result = 0;
+ do {
+ nevents = _kevent(connection->write_queue, NULL, 0, &eventlist,
+ 1, &timeout);
+ if ((nevents == 1) && (eventlist.filter == EVFILT_WRITE)) {
+ s_result = _sendto(connection->sockfd, data + result,
+ eventlist.data < data_size - result ?
+ eventlist.data : data_size - result, MSG_NOSIGNAL,
+ NULL, 0);
+ if (s_result == -1)
+ return (-1);
+ else
+ result += s_result;
+
+ if (eventlist.flags & EV_EOF)
+ return (result < data_size ? -1 : 0);
+ } else
+ return (-1);
+ } while (result < data_size);
+
+ return (0);
+}
+
+/*
+ * safe_read reads data from connection and tries to do it in the very safe
+ * and stable way. It uses kevent to ensure, that the data are available for
+ * reading. If the amount of data to be read is too large, then they would
+ * be splitted.
+ */
+static int
+safe_read(struct cached_connection_ *connection, void *data, size_t data_size)
+{
+ struct kevent eventlist;
+ size_t result;
+ ssize_t s_result;
+ struct timespec timeout;
+ int nevents;
+
+ if (data_size == 0)
+ return (0);
+
+ timeout.tv_sec = NS_DEFAULT_CACHED_IO_TIMEOUT;
+ timeout.tv_nsec = 0;
+ result = 0;
+ do {
+ nevents = _kevent(connection->read_queue, NULL, 0, &eventlist,
+ 1, &timeout);
+ if (nevents == 1 && eventlist.filter == EVFILT_READ) {
+ s_result = _read(connection->sockfd, data + result,
+ eventlist.data <= data_size - result ?
+ eventlist.data : data_size - result);
+ if (s_result == -1)
+ return (-1);
+ else
+ result += s_result;
+
+ if (eventlist.flags & EV_EOF)
+ return (result < data_size ? -1 : 0);
+ } else
+ return (-1);
+ } while (result < data_size);
+
+ return (0);
+}
+
+/*
+ * Sends the credentials information to the connection along with the
+ * communication element type.
+ */
+static int
+send_credentials(struct cached_connection_ *connection, int type)
+{
+ struct kevent eventlist;
+ int nevents;
+ ssize_t result;
+ int res;
+
+ struct msghdr cred_hdr;
+ struct iovec iov;
+
+ struct {
+ struct cmsghdr hdr;
+ char cred[CMSG_SPACE(sizeof(struct cmsgcred))];
+ } cmsg;
+
+ memset(&cmsg, 0, sizeof(cmsg));
+ cmsg.hdr.cmsg_len = CMSG_LEN(sizeof(struct cmsgcred));
+ cmsg.hdr.cmsg_level = SOL_SOCKET;
+ cmsg.hdr.cmsg_type = SCM_CREDS;
+
+ memset(&cred_hdr, 0, sizeof(struct msghdr));
+ cred_hdr.msg_iov = &iov;
+ cred_hdr.msg_iovlen = 1;
+ cred_hdr.msg_control = (caddr_t)&cmsg;
+ cred_hdr.msg_controllen = CMSG_SPACE(sizeof(struct cmsgcred));
+
+ iov.iov_base = &type;
+ iov.iov_len = sizeof(int);
+
+ EV_SET(&eventlist, connection->sockfd, EVFILT_WRITE, EV_ADD,
+ NOTE_LOWAT, sizeof(int), NULL);
+ res = _kevent(connection->write_queue, &eventlist, 1, NULL, 0, NULL);
+
+ nevents = _kevent(connection->write_queue, NULL, 0, &eventlist, 1,
+ NULL);
+ if (nevents == 1 && eventlist.filter == EVFILT_WRITE) {
+ result = (_sendmsg(connection->sockfd, &cred_hdr,
+ MSG_NOSIGNAL) == -1) ? -1 : 0;
+ EV_SET(&eventlist, connection->sockfd, EVFILT_WRITE, EV_ADD,
+ 0, 0, NULL);
+ _kevent(connection->write_queue, &eventlist, 1, NULL, 0, NULL);
+ return (result);
+ } else
+ return (-1);
+}
+
+/*
+ * Opens the connection with the specified params. Initializes all kqueues.
+ */
+struct cached_connection_ *
+__open_cached_connection(struct cached_connection_params const *params)
+{
+ struct cached_connection_ *retval;
+ struct kevent eventlist;
+ struct sockaddr_un client_address;
+ int client_address_len, client_socket;
+ int res;
+
+ assert(params != NULL);
+
+ client_socket = _socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
+ client_address.sun_family = PF_LOCAL;
+ strncpy(client_address.sun_path, params->socket_path,
+ sizeof(client_address.sun_path));
+ client_address_len = sizeof(client_address.sun_family) +
+ strlen(client_address.sun_path) + 1;
+
+ res = _connect(client_socket, (struct sockaddr *)&client_address,
+ client_address_len);
+ if (res == -1) {
+ _close(client_socket);
+ return (NULL);
+ }
+ _fcntl(client_socket, F_SETFL, O_NONBLOCK);
+
+ retval = malloc(sizeof(struct cached_connection_));
+ assert(retval != NULL);
+ memset(retval, 0, sizeof(struct cached_connection_));
+
+ retval->sockfd = client_socket;
+
+ retval->write_queue = kqueue();
+ assert(retval->write_queue != -1);
+
+ EV_SET(&eventlist, retval->sockfd, EVFILT_WRITE, EV_ADD, 0, 0, NULL);
+ res = _kevent(retval->write_queue, &eventlist, 1, NULL, 0, NULL);
+
+ retval->read_queue = kqueue();
+ assert(retval->read_queue != -1);
+
+ EV_SET(&eventlist, retval->sockfd, EVFILT_READ, EV_ADD, 0, 0, NULL);
+ res = _kevent(retval->read_queue, &eventlist, 1, NULL, 0, NULL);
+
+ return (retval);
+}
+
+void
+__close_cached_connection(struct cached_connection_ *connection)
+{
+ assert(connection != NULL);
+
+ _close(connection->sockfd);
+ _close(connection->read_queue);
+ _close(connection->write_queue);
+ free(connection);
+}
+
+/*
+ * This function is very close to the cache_write function of the caching
+ * library, which is used in the caching daemon. It caches the data with the
+ * specified key in the cache entry with entry_name.
+ */
+int
+__cached_write(struct cached_connection_ *connection, const char *entry_name,
+ const char *key, size_t key_size, const char *data, size_t data_size)
+{
+ size_t name_size;
+ int error_code;
+ int result;
+
+ error_code = -1;
+ result = 0;
+ result = send_credentials(connection, CET_WRITE_REQUEST);
+ if (result != 0)
+ goto fin;
+
+ name_size = strlen(entry_name);
+ result = safe_write(connection, &name_size, sizeof(size_t));
+ if (result != 0)
+ goto fin;
+
+ result = safe_write(connection, &key_size, sizeof(size_t));
+ if (result != 0)
+ goto fin;
+
+ result = safe_write(connection, &data_size, sizeof(size_t));
+ if (result != 0)
+ goto fin;
+
+ result = safe_write(connection, entry_name, name_size);
+ if (result != 0)
+ goto fin;
+
+ result = safe_write(connection, key, key_size);
+ if (result != 0)
+ goto fin;
+
+ result = safe_write(connection, data, data_size);
+ if (result != 0)
+ goto fin;
+
+ result = safe_read(connection, &error_code, sizeof(int));
+ if (result != 0)
+ error_code = -1;
+
+fin:
+ return (error_code);
+}
+
+/*
+ * This function is very close to the cache_read function of the caching
+ * library, which is used in the caching daemon. It reads cached data with the
+ * specified key from the cache entry with entry_name.
+ */
+int
+__cached_read(struct cached_connection_ *connection, const char *entry_name,
+ const char *key, size_t key_size, char *data, size_t *data_size)
+{
+ size_t name_size, result_size;
+ int error_code, rec_error_code;
+ int result;
+
+ assert(connection != NULL);
+ result = 0;
+ error_code = -1;
+
+ result = send_credentials(connection, CET_READ_REQUEST);
+ if (result != 0)
+ goto fin;
+
+ name_size = strlen(entry_name);
+ result = safe_write(connection, &name_size, sizeof(size_t));
+ if (result != 0)
+ goto fin;
+
+ result = safe_write(connection, &key_size, sizeof(size_t));
+ if (result != 0)
+ goto fin;
+
+ result = safe_write(connection, entry_name, name_size);
+ if (result != 0)
+ goto fin;
+
+ result = safe_write(connection, key, key_size);
+ if (result != 0)
+ goto fin;
+
+ result = safe_read(connection, &rec_error_code, sizeof(int));
+ if (result != 0)
+ goto fin;
+
+ if (rec_error_code != 0) {
+ error_code = rec_error_code;
+ goto fin;
+ }
+
+ result = safe_read(connection, &result_size, sizeof(size_t));
+ if (result != 0)
+ goto fin;
+
+ if (result_size > *data_size) {
+ *data_size = result_size;
+ error_code = -2;
+ goto fin;
+ }
+
+ result = safe_read(connection, data, result_size);
+ if (result != 0)
+ goto fin;
+
+ *data_size = result_size;
+ error_code = 0;
+
+fin:
+ return (error_code);
+}
+
+/*
+ * Initializes the mp_write_session. For such a session the new connection
+ * would be opened. The data should be written to the session with
+ * __cached_mp_write function. The __close_cached_mp_write_session function
+ * should be used to submit session and __abandon_cached_mp_write_session - to
+ * abandon it. When the session is submitted, the whole se
+ */
+struct cached_connection_ *
+__open_cached_mp_write_session(struct cached_connection_params const *params,
+ const char *entry_name)
+{
+ struct cached_connection_ *connection, *retval;
+ size_t name_size;
+ int error_code;
+ int result;
+
+ retval = NULL;
+ connection = __open_cached_connection(params);
+ if (connection == NULL)
+ return (NULL);
+ connection->mp_flag = 1;
+
+ result = send_credentials(connection, CET_MP_WRITE_SESSION_REQUEST);
+ if (result != 0)
+ goto fin;
+
+ name_size = strlen(entry_name);
+ result = safe_write(connection, &name_size, sizeof(size_t));
+ if (result != 0)
+ goto fin;
+
+ result = safe_write(connection, entry_name, name_size);
+ if (result != 0)
+ goto fin;
+
+ result = safe_read(connection, &error_code, sizeof(int));
+ if (result != 0)
+ goto fin;
+
+ if (error_code != 0)
+ result = error_code;
+
+fin:
+ if (result != 0)
+ __close_cached_connection(connection);
+ else
+ retval = connection;
+ return (retval);
+}
+
+/*
+ * Adds new portion of data to the opened write session
+ */
+int
+__cached_mp_write(struct cached_connection_ *ws, const char *data,
+ size_t data_size)
+{
+ int request, result;
+ int error_code;
+
+ error_code = -1;
+
+ request = CET_MP_WRITE_SESSION_WRITE_REQUEST;
+ result = safe_write(ws, &request, sizeof(int));
+ if (result != 0)
+ goto fin;
+
+ result = safe_write(ws, &data_size, sizeof(size_t));
+ if (result != 0)
+ goto fin;
+
+ result = safe_write(ws, data, data_size);
+ if (result != 0)
+ goto fin;
+
+ result = safe_read(ws, &error_code, sizeof(int));
+ if (result != 0)
+ error_code = -1;
+
+fin:
+ return (error_code);
+}
+
+/*
+ * Abandons all operations with the write session. All data, that were written
+ * to the session before, are discarded.
+ */
+int
+__abandon_cached_mp_write_session(struct cached_connection_ *ws)
+{
+ int notification;
+ int result;
+
+ notification = CET_MP_WRITE_SESSION_ABANDON_NOTIFICATION;
+ result = safe_write(ws, &notification, sizeof(int));
+ __close_cached_connection(ws);
+ return (result);
+}
+
+/*
+ * Gracefully closes the write session. The data, that were previously written
+ * to the session, are committed.
+ */
+int
+__close_cached_mp_write_session(struct cached_connection_ *ws)
+{
+ int notification;
+ int result;
+
+ notification = CET_MP_WRITE_SESSION_CLOSE_NOTIFICATION;
+ result = safe_write(ws, &notification, sizeof(int));
+ __close_cached_connection(ws);
+ return (0);
+}
+
+struct cached_connection_ *
+__open_cached_mp_read_session(struct cached_connection_params const *params,
+ const char *entry_name)
+{
+ struct cached_connection_ *connection, *retval;
+ size_t name_size;
+ int error_code;
+ int result;
+
+ retval = NULL;
+ connection = __open_cached_connection(params);
+ if (connection == NULL)
+ return (NULL);
+ connection->mp_flag = 1;
+
+ result = send_credentials(connection, CET_MP_READ_SESSION_REQUEST);
+ if (result != 0)
+ goto fin;
+
+ name_size = strlen(entry_name);
+ result = safe_write(connection, &name_size, sizeof(size_t));
+ if (result != 0)
+ goto fin;
+
+ result = safe_write(connection, entry_name, name_size);
+ if (result != 0)
+ goto fin;
+
+ result = safe_read(connection, &error_code, sizeof(int));
+ if (result != 0)
+ goto fin;
+
+ if (error_code != 0)
+ result = error_code;
+
+fin:
+ if (result != 0)
+ __close_cached_connection(connection);
+ else
+ retval = connection;
+ return (retval);
+}
+
+int
+__cached_mp_read(struct cached_connection_ *rs, char *data, size_t *data_size)
+{
+ size_t result_size;
+ int error_code, rec_error_code;
+ int request, result;
+
+ error_code = -1;
+ request = CET_MP_READ_SESSION_READ_REQUEST;
+ result = safe_write(rs, &request, sizeof(int));
+ if (result != 0)
+ goto fin;
+
+ result = safe_read(rs, &rec_error_code, sizeof(int));
+ if (result != 0)
+ goto fin;
+
+ if (rec_error_code != 0) {
+ error_code = rec_error_code;
+ goto fin;
+ }
+
+ result = safe_read(rs, &result_size, sizeof(size_t));
+ if (result != 0)
+ goto fin;
+
+ if (result_size > *data_size) {
+ *data_size = result_size;
+ error_code = -2;
+ goto fin;
+ }
+
+ result = safe_read(rs, data, result_size);
+ if (result != 0)
+ goto fin;
+
+ *data_size = result_size;
+ error_code = 0;
+
+fin:
+ return (error_code);
+}
+
+int
+__close_cached_mp_read_session(struct cached_connection_ *rs)
+{
+
+ __close_cached_connection(rs);
+ return (0);
+}
diff --git a/lib/libc/net/nsdispatch.3 b/lib/libc/net/nsdispatch.3
new file mode 100644
index 000000000000..e08e9bef7cae
--- /dev/null
+++ b/lib/libc/net/nsdispatch.3
@@ -0,0 +1,257 @@
+.\" $NetBSD: nsdispatch.3,v 1.8 1999/03/22 19:44:53 garbled Exp $
+.\"
+.\" Copyright (c) 1997, 1998, 1999 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Luke Mewburn.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of The NetBSD Foundation nor the names of its
+.\" contributors may be used to endorse or promote products derived
+.\" from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd April 4, 2010
+.Dt NSDISPATCH 3
+.Os
+.Sh NAME
+.Nm nsdispatch
+.Nd name-service switch dispatcher routine
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In stdarg.h
+.In nsswitch.h
+.Ft int
+.Fo nsdispatch
+.Fa "void *retval"
+.Fa "const ns_dtab dtab[]"
+.Fa "const char *database"
+.Fa "const char *method_name"
+.Fa "const ns_src defaults[]"
+.Fa "..."
+.Fc
+.Sh DESCRIPTION
+The
+.Fn nsdispatch
+function invokes the methods specified in
+.Va dtab
+in the order given by
+.Xr nsswitch.conf 5
+for the database
+.Va database
+until a successful entry is found.
+.Pp
+.Va retval
+is passed to each method to modify as necessary, to pass back results to
+the caller of
+.Fn nsdispatch .
+.Pp
+Each method has the function signature described by the typedef:
+.Pp
+.Ft typedef int
+.Fn \*(lp*nss_method\*(rp "void *retval" "void *mdata" "va_list *ap" ;
+.Pp
+.Va dtab
+is an array of
+.Va ns_dtab
+structures, which have the following format:
+.Bd -literal -offset indent
+typedef struct _ns_dtab {
+ const char *src;
+ nss_method method;
+ void *mdata;
+} ns_dtab;
+.Ed
+.Pp
+The
+.Fa dtab
+array should consist of one entry for each source type that is
+implemented, with
+.Va src
+as the name of the source,
+.Va method
+as a function which handles that source, and
+.Va mdata
+as a handle on arbitrary data to be passed to the method.
+The last entry in
+.Va dtab
+should contain
+.Dv NULL
+values for
+.Va src ,
+.Va method ,
+and
+.Va mdata .
+.Pp
+Additionally, methods may be implemented in NSS modules, in
+which case they are selected using the
+.Fa database
+and
+.Fa method_name
+arguments along with the configured source.
+(The methods supplied via
+.Fa dtab
+take priority over those implemented in NSS modules in the event
+of a conflict.)
+.Pp
+.Va defaults
+contains a list of default sources to try if
+.Xr nsswitch.conf 5
+is missing or corrupted, or if there is no relevant entry for
+.Va database .
+It is an array of
+.Va ns_src
+structures, which have the following format:
+.Bd -literal -offset indent
+typedef struct _ns_src {
+ const char *src;
+ uint32_t flags;
+} ns_src;
+.Ed
+.Pp
+The
+.Fa defaults
+array should consist of one entry for each source to be configured by
+default indicated by
+.Va src ,
+and
+.Va flags
+set to the criterion desired
+(usually
+.Dv NS_SUCCESS ;
+refer to
+.Sx Method return values
+for more information).
+The last entry in
+.Va defaults
+should have
+.Va src
+set to
+.Dv NULL
+and
+.Va flags
+set to 0.
+.Pp
+For convenience, a global variable defined as:
+.Pp
+.Dl extern const ns_src __nsdefaultsrc[];
+.Pp
+exists which contains a single default entry for the source
+.Sq files
+that may be used by callers which do not require complicated default
+rules.
+.Pp
+.Sq Va ...
+are optional extra arguments, which are passed to the appropriate method
+as a variable argument list of the type
+.Vt va_list .
+.Ss Valid source types
+While there is support for arbitrary sources, the following
+#defines for commonly implemented sources are available:
+.Bl -column NSSRC_COMPAT compat -offset indent
+.It Sy "#define value"
+.It Dv NSSRC_FILES Ta \&"files\&"
+.It Dv NSSRC_DB Ta \&"db\&"
+.It Dv NSSRC_DNS Ta \&"dns\&"
+.It Dv NSSRC_NIS Ta \&"nis\&"
+.It Dv NSSRC_COMPAT Ta \&"compat\&"
+.El
+.Pp
+Refer to
+.Xr nsswitch.conf 5
+for a complete description of what each source type is.
+.Ss Method return values
+The
+.Vt nss_method
+functions must return one of the following values depending upon status
+of the lookup:
+.Bl -column "Return value" "Status code"
+.It Sy "Return value Status code"
+.It Dv NS_SUCCESS Ta success
+.It Dv NS_NOTFOUND Ta notfound
+.It Dv NS_UNAVAIL Ta unavail
+.It Dv NS_TRYAGAIN Ta tryagain
+.It Dv NS_RETURN Ta -none-
+.El
+.Pp
+Refer to
+.Xr nsswitch.conf 5
+for a complete description of each status code.
+.Pp
+The
+.Fn nsdispatch
+function returns the value of the method that caused the dispatcher to
+terminate, or
+.Dv NS_NOTFOUND
+otherwise.
+.Sh NOTES
+.Fx Ns 's
+.Lb libc
+provides stubs for compatibility with NSS modules
+written for the
+.Tn GNU
+C Library
+.Nm nsswitch
+interface.
+However, these stubs only support the use of the
+.Dq Li passwd
+and
+.Dq Li group
+databases.
+.Sh SEE ALSO
+.Xr hesiod 3 ,
+.Xr stdarg 3 ,
+.Xr nsswitch.conf 5 ,
+.Xr yp 8
+.Sh HISTORY
+The
+.Fn nsdispatch
+function first appeared in
+.Fx 5.0 .
+It was imported from the
+.Nx
+Project,
+where it appeared first in
+.Nx 1.4 .
+Support for NSS modules first appeared in
+.Fx 5.1 .
+.Sh AUTHORS
+.An Luke Mewburn Aq Mt lukem@netbsd.org
+wrote this freely-distributable name-service switch implementation,
+using ideas from the
+.Tn ULTRIX
+svc.conf(5)
+and
+.Tn Solaris
+nsswitch.conf(4)
+manual pages.
+The
+.Fx
+Project
+added the support for threads and NSS modules, and normalized the uses
+of
+.Fn nsdispatch
+within the standard C library.
diff --git a/lib/libc/net/nsdispatch.c b/lib/libc/net/nsdispatch.c
new file mode 100644
index 000000000000..4de1df3ffd16
--- /dev/null
+++ b/lib/libc/net/nsdispatch.c
@@ -0,0 +1,763 @@
+/* $NetBSD: nsdispatch.c,v 1.9 1999/01/25 00:16:17 lukem Exp $ */
+
+/*-
+ * Copyright (c) 1997, 1998, 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Luke Mewburn.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*-
+ * Copyright (c) 2003 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * Jacques A. Vidrine, Safeport Network Services, and Network
+ * Associates Laboratories, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+ * ("CBOSS"), as part of the DARPA CHATS research program.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <fcntl.h>
+#define _NS_PRIVATE
+#include <nsswitch.h>
+#include <pthread.h>
+#include <pthread_np.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include "un-namespace.h"
+#include "nss_tls.h"
+#include "libc_private.h"
+#ifdef NS_CACHING
+#include "nscache.h"
+#endif
+
+enum _nss_constants {
+ /* Number of elements allocated when we grow a vector */
+ ELEMSPERCHUNK = 8
+};
+
+/*
+ * Global NSS data structures are mostly read-only, but we update
+ * them when we read or re-read the nsswitch.conf.
+ */
+static pthread_rwlock_t nss_lock = PTHREAD_RWLOCK_INITIALIZER;
+
+/*
+ * Runtime determination of whether we are dynamically linked or not.
+ */
+extern int _DYNAMIC __attribute__ ((weak));
+#define is_dynamic() (&_DYNAMIC != NULL)
+
+/*
+ * default sourcelist: `files'
+ */
+const ns_src __nsdefaultsrc[] = {
+ { NSSRC_FILES, NS_SUCCESS },
+ { 0 },
+};
+
+/* Database, source mappings. */
+static unsigned int _nsmapsize;
+static ns_dbt *_nsmap = NULL;
+
+/* NSS modules. */
+static unsigned int _nsmodsize;
+static ns_mod *_nsmod;
+
+/* Placeholder for builtin modules' dlopen `handle'. */
+static int __nss_builtin_handle;
+static void *nss_builtin_handle = &__nss_builtin_handle;
+
+#ifdef NS_CACHING
+/*
+ * Cache lookup cycle prevention function - if !NULL then no cache lookups
+ * will be made
+ */
+static void *nss_cache_cycle_prevention_func = NULL;
+#endif
+
+/*
+ * We keep track of nsdispatch() nesting depth in dispatch_depth. When a
+ * fallback method is invoked from nsdispatch(), we temporarily set
+ * fallback_depth to the current dispatch depth plus one. Subsequent
+ * calls at that exact depth will run in fallback mode (restricted to the
+ * same source as the call that was handled by the fallback method), while
+ * calls below that depth will be handled normally, allowing fallback
+ * methods to perform arbitrary lookups.
+ */
+struct fb_state {
+ int dispatch_depth;
+ int fallback_depth;
+};
+static void fb_endstate(void *);
+NSS_TLS_HANDLING(fb);
+
+/*
+ * Attempt to spew relatively uniform messages to syslog.
+ */
+#define nss_log(level, fmt, ...) \
+ syslog((level), "NSSWITCH(%s): " fmt, __func__, __VA_ARGS__)
+#define nss_log_simple(level, s) \
+ syslog((level), "NSSWITCH(%s): " s, __func__)
+
+/*
+ * Dynamically growable arrays are used for lists of databases, sources,
+ * and modules. The following `vector' interface is used to isolate the
+ * common operations.
+ */
+typedef int (*vector_comparison)(const void *, const void *);
+typedef void (*vector_free_elem)(void *);
+static void vector_sort(void *, unsigned int, size_t,
+ vector_comparison);
+static void vector_free(void *, unsigned int *, size_t,
+ vector_free_elem);
+static void *vector_ref(unsigned int, void *, unsigned int, size_t);
+static void *vector_search(const void *, void *, unsigned int, size_t,
+ vector_comparison);
+static void *vector_append(const void *, void *, unsigned int *, size_t);
+
+
+/*
+ * Internal interfaces.
+ */
+static int string_compare(const void *, const void *);
+static int mtab_compare(const void *, const void *);
+static int nss_configure(void);
+static void ns_dbt_free(ns_dbt *);
+static void ns_mod_free(ns_mod *);
+static void ns_src_free(ns_src **, int);
+static void nss_load_builtin_modules(void);
+static void nss_load_module(const char *, nss_module_register_fn);
+static void nss_atexit(void);
+/* nsparser */
+extern FILE *_nsyyin;
+
+
+/*
+ * The vector operations
+ */
+static void
+vector_sort(void *vec, unsigned int count, size_t esize,
+ vector_comparison comparison)
+{
+ qsort(vec, count, esize, comparison);
+}
+
+
+static void *
+vector_search(const void *key, void *vec, unsigned int count, size_t esize,
+ vector_comparison comparison)
+{
+ return (bsearch(key, vec, count, esize, comparison));
+}
+
+
+static void *
+vector_append(const void *elem, void *vec, unsigned int *count, size_t esize)
+{
+ void *p;
+
+ if ((*count % ELEMSPERCHUNK) == 0) {
+ p = realloc(vec, (*count + ELEMSPERCHUNK) * esize);
+ if (p == NULL) {
+ nss_log_simple(LOG_ERR, "memory allocation failure");
+ return (vec);
+ }
+ vec = p;
+ }
+ memmove((void *)(((uintptr_t)vec) + (*count * esize)), elem, esize);
+ (*count)++;
+ return (vec);
+}
+
+
+static void *
+vector_ref(unsigned int i, void *vec, unsigned int count, size_t esize)
+{
+ if (i < count)
+ return (void *)((uintptr_t)vec + (i * esize));
+ else
+ return (NULL);
+}
+
+
+#define VECTOR_FREE(v, c, s, f) \
+ do { vector_free(v, c, s, f); v = NULL; } while (0)
+static void
+vector_free(void *vec, unsigned int *count, size_t esize,
+ vector_free_elem free_elem)
+{
+ unsigned int i;
+ void *elem;
+
+ for (i = 0; i < *count; i++) {
+ elem = vector_ref(i, vec, *count, esize);
+ if (elem != NULL)
+ free_elem(elem);
+ }
+ free(vec);
+ *count = 0;
+}
+
+/*
+ * Comparison functions for vector_search.
+ */
+static int
+string_compare(const void *a, const void *b)
+{
+ return (strcasecmp(*(const char * const *)a, *(const char * const *)b));
+}
+
+
+static int
+mtab_compare(const void *a, const void *b)
+{
+ int cmp;
+
+ cmp = strcmp(((const ns_mtab *)a)->name, ((const ns_mtab *)b)->name);
+ if (cmp != 0)
+ return (cmp);
+ else
+ return (strcmp(((const ns_mtab *)a)->database,
+ ((const ns_mtab *)b)->database));
+}
+
+/*
+ * NSS nsmap management.
+ */
+void
+_nsdbtaddsrc(ns_dbt *dbt, const ns_src *src)
+{
+ const ns_mod *modp;
+
+ dbt->srclist = vector_append(src, dbt->srclist, &dbt->srclistsize,
+ sizeof(*src));
+ modp = vector_search(&src->name, _nsmod, _nsmodsize, sizeof(*_nsmod),
+ string_compare);
+ if (modp == NULL)
+ nss_load_module(src->name, NULL);
+}
+
+
+#ifdef _NSS_DEBUG
+void
+_nsdbtdump(const ns_dbt *dbt)
+{
+ int i;
+
+ printf("%s (%d source%s):", dbt->name, dbt->srclistsize,
+ dbt->srclistsize == 1 ? "" : "s");
+ for (i = 0; i < (int)dbt->srclistsize; i++) {
+ printf(" %s", dbt->srclist[i].name);
+ if (!(dbt->srclist[i].flags &
+ (NS_UNAVAIL|NS_NOTFOUND|NS_TRYAGAIN)) &&
+ (dbt->srclist[i].flags & NS_SUCCESS))
+ continue;
+ printf(" [");
+ if (!(dbt->srclist[i].flags & NS_SUCCESS))
+ printf(" SUCCESS=continue");
+ if (dbt->srclist[i].flags & NS_UNAVAIL)
+ printf(" UNAVAIL=return");
+ if (dbt->srclist[i].flags & NS_NOTFOUND)
+ printf(" NOTFOUND=return");
+ if (dbt->srclist[i].flags & NS_TRYAGAIN)
+ printf(" TRYAGAIN=return");
+ printf(" ]");
+ }
+ printf("\n");
+}
+#endif
+
+
+/*
+ * The first time nsdispatch is called (during a process's lifetime,
+ * or after nsswitch.conf has been updated), nss_configure will
+ * prepare global data needed by NSS.
+ */
+static int
+nss_configure(void)
+{
+ static time_t confmod;
+ struct stat statbuf;
+ int result, isthreaded;
+ const char *path;
+#ifdef NS_CACHING
+ void *handle;
+#endif
+
+ result = 0;
+ isthreaded = __isthreaded;
+#if defined(_NSS_DEBUG) && defined(_NSS_SHOOT_FOOT)
+ /* NOTE WELL: THIS IS A SECURITY HOLE. This must only be built
+ * for debugging purposes and MUST NEVER be used in production.
+ */
+ path = getenv("NSSWITCH_CONF");
+ if (path == NULL)
+#endif
+ path = _PATH_NS_CONF;
+ if (stat(path, &statbuf) != 0)
+ return (0);
+ if (statbuf.st_mtime <= confmod)
+ return (0);
+ if (isthreaded) {
+ (void)_pthread_rwlock_unlock(&nss_lock);
+ result = _pthread_rwlock_wrlock(&nss_lock);
+ if (result != 0)
+ return (result);
+ if (stat(path, &statbuf) != 0)
+ goto fin;
+ if (statbuf.st_mtime <= confmod)
+ goto fin;
+ }
+ _nsyyin = fopen(path, "re");
+ if (_nsyyin == NULL)
+ goto fin;
+ VECTOR_FREE(_nsmap, &_nsmapsize, sizeof(*_nsmap),
+ (vector_free_elem)ns_dbt_free);
+ VECTOR_FREE(_nsmod, &_nsmodsize, sizeof(*_nsmod),
+ (vector_free_elem)ns_mod_free);
+ nss_load_builtin_modules();
+ _nsyyparse();
+ (void)fclose(_nsyyin);
+ vector_sort(_nsmap, _nsmapsize, sizeof(*_nsmap), string_compare);
+ if (confmod == 0)
+ (void)atexit(nss_atexit);
+ confmod = statbuf.st_mtime;
+
+#ifdef NS_CACHING
+ handle = libc_dlopen(NULL, RTLD_LAZY | RTLD_GLOBAL);
+ if (handle != NULL) {
+ nss_cache_cycle_prevention_func = dlsym(handle,
+ "_nss_cache_cycle_prevention_function");
+ dlclose(handle);
+ }
+#endif
+fin:
+ if (isthreaded) {
+ (void)_pthread_rwlock_unlock(&nss_lock);
+ if (result == 0)
+ result = _pthread_rwlock_rdlock(&nss_lock);
+ }
+ return (result);
+}
+
+
+void
+_nsdbtput(const ns_dbt *dbt)
+{
+ unsigned int i;
+ ns_dbt *p;
+
+ for (i = 0; i < _nsmapsize; i++) {
+ p = vector_ref(i, _nsmap, _nsmapsize, sizeof(*_nsmap));
+ if (string_compare(&dbt->name, &p->name) == 0) {
+ /* overwrite existing entry */
+ if (p->srclist != NULL)
+ ns_src_free(&p->srclist, p->srclistsize);
+ memmove(p, dbt, sizeof(*dbt));
+ return;
+ }
+ }
+ _nsmap = vector_append(dbt, _nsmap, &_nsmapsize, sizeof(*_nsmap));
+}
+
+
+static void
+ns_dbt_free(ns_dbt *dbt)
+{
+ ns_src_free(&dbt->srclist, dbt->srclistsize);
+ if (dbt->name)
+ free((void *)dbt->name);
+}
+
+
+static void
+ns_src_free(ns_src **src, int srclistsize)
+{
+ int i;
+
+ for (i = 0; i < srclistsize; i++)
+ if ((*src)[i].name != NULL)
+ /* This one was allocated by nslexer. You'll just
+ * have to trust me.
+ */
+ free((void *)((*src)[i].name));
+ free(*src);
+ *src = NULL;
+}
+
+
+
+/*
+ * NSS module management.
+ */
+/* The built-in NSS modules are all loaded at once. */
+#define NSS_BACKEND(name, reg) \
+ns_mtab *reg(unsigned int *, nss_module_unregister_fn *);
+#include "nss_backends.h"
+#undef NSS_BACKEND
+
+static void
+nss_load_builtin_modules(void)
+{
+#define NSS_BACKEND(name, reg) nss_load_module(#name, reg);
+#include "nss_backends.h"
+#undef NSS_BACKEND
+}
+
+
+/* Load a built-in or dynamically linked module. If the `reg_fn'
+ * argument is non-NULL, assume a built-in module and use reg_fn to
+ * register it. Otherwise, search for a dynamic NSS module.
+ */
+static void
+nss_load_module(const char *source, nss_module_register_fn reg_fn)
+{
+ char buf[PATH_MAX];
+ ns_mod mod;
+ nss_module_register_fn fn;
+
+ memset(&mod, 0, sizeof(mod));
+ mod.name = strdup(source);
+ if (mod.name == NULL) {
+ nss_log_simple(LOG_ERR, "memory allocation failure");
+ return;
+ }
+ if (reg_fn != NULL) {
+ /* The placeholder is required, as a NULL handle
+ * represents an invalid module.
+ */
+ mod.handle = nss_builtin_handle;
+ fn = reg_fn;
+ } else if (!is_dynamic())
+ goto fin;
+ else {
+ if (snprintf(buf, sizeof(buf), "nss_%s.so.%d", mod.name,
+ NSS_MODULE_INTERFACE_VERSION) >= (int)sizeof(buf))
+ goto fin;
+ mod.handle = libc_dlopen(buf, RTLD_LOCAL|RTLD_LAZY);
+ if (mod.handle == NULL) {
+#ifdef _NSS_DEBUG
+ /* This gets pretty annoying since the built-in
+ * sources aren't modules yet.
+ */
+ nss_log(LOG_DEBUG, "%s, %s", mod.name, dlerror());
+#endif
+ goto fin;
+ }
+ fn = (nss_module_register_fn)dlfunc(mod.handle,
+ "nss_module_register");
+ if (fn == NULL) {
+ (void)dlclose(mod.handle);
+ mod.handle = NULL;
+ nss_log(LOG_ERR, "%s, %s", mod.name, dlerror());
+ goto fin;
+ }
+ }
+ mod.mtab = fn(mod.name, &mod.mtabsize, &mod.unregister);
+ if (mod.mtab == NULL || mod.mtabsize == 0) {
+ if (mod.handle != nss_builtin_handle)
+ (void)dlclose(mod.handle);
+ mod.handle = NULL;
+ nss_log(LOG_ERR, "%s, registration failed", mod.name);
+ goto fin;
+ }
+ if (mod.mtabsize > 1)
+ qsort(mod.mtab, mod.mtabsize, sizeof(mod.mtab[0]),
+ mtab_compare);
+fin:
+ _nsmod = vector_append(&mod, _nsmod, &_nsmodsize, sizeof(*_nsmod));
+ vector_sort(_nsmod, _nsmodsize, sizeof(*_nsmod), string_compare);
+}
+
+
+
+static void
+ns_mod_free(ns_mod *mod)
+{
+
+ free(mod->name);
+ if (mod->handle == NULL)
+ return;
+ if (mod->unregister != NULL)
+ mod->unregister(mod->mtab, mod->mtabsize);
+ if (mod->handle != nss_builtin_handle)
+ (void)dlclose(mod->handle);
+}
+
+
+
+/*
+ * Cleanup
+ */
+static void
+nss_atexit(void)
+{
+ int isthreaded;
+
+ isthreaded = __isthreaded;
+ if (isthreaded)
+ (void)_pthread_rwlock_wrlock(&nss_lock);
+ VECTOR_FREE(_nsmap, &_nsmapsize, sizeof(*_nsmap),
+ (vector_free_elem)ns_dbt_free);
+ VECTOR_FREE(_nsmod, &_nsmodsize, sizeof(*_nsmod),
+ (vector_free_elem)ns_mod_free);
+ if (isthreaded)
+ (void)_pthread_rwlock_unlock(&nss_lock);
+}
+
+
+
+/*
+ * Finally, the actual implementation.
+ */
+static nss_method
+nss_method_lookup(const char *source, const char *database,
+ const char *method, const ns_dtab disp_tab[], void **mdata)
+{
+ ns_mod *mod;
+ ns_mtab *match, key;
+ int i;
+
+ if (disp_tab != NULL)
+ for (i = 0; disp_tab[i].src != NULL; i++)
+ if (strcasecmp(source, disp_tab[i].src) == 0) {
+ *mdata = disp_tab[i].mdata;
+ return (disp_tab[i].method);
+ }
+ mod = vector_search(&source, _nsmod, _nsmodsize, sizeof(*_nsmod),
+ string_compare);
+ if (mod != NULL && mod->handle != NULL) {
+ key.database = database;
+ key.name = method;
+ match = bsearch(&key, mod->mtab, mod->mtabsize,
+ sizeof(mod->mtab[0]), mtab_compare);
+ if (match != NULL) {
+ *mdata = match->mdata;
+ return (match->method);
+ }
+ }
+
+ *mdata = NULL;
+ return (NULL);
+}
+
+static void
+fb_endstate(void *p)
+{
+ free(p);
+}
+
+__weak_reference(_nsdispatch, nsdispatch);
+
+int
+_nsdispatch(void *retval, const ns_dtab disp_tab[], const char *database,
+ const char *method_name, const ns_src defaults[], ...)
+{
+ va_list ap;
+ const ns_dbt *dbt;
+ const ns_src *srclist;
+ nss_method method, fb_method;
+ void *mdata;
+ int isthreaded, serrno, i, result, srclistsize;
+ struct fb_state *st;
+ int saved_depth;
+
+#ifdef NS_CACHING
+ nss_cache_data cache_data;
+ nss_cache_data *cache_data_p;
+ int cache_flag;
+#endif
+
+ dbt = NULL;
+ fb_method = NULL;
+
+ isthreaded = __isthreaded;
+ serrno = errno;
+ if (isthreaded) {
+ result = _pthread_rwlock_rdlock(&nss_lock);
+ if (result != 0) {
+ result = NS_UNAVAIL;
+ goto fin;
+ }
+ }
+
+ result = fb_getstate(&st);
+ if (result != 0) {
+ result = NS_UNAVAIL;
+ goto fin;
+ }
+
+ result = nss_configure();
+ if (result != 0) {
+ result = NS_UNAVAIL;
+ goto fin;
+ }
+ ++st->dispatch_depth;
+ if (st->dispatch_depth > st->fallback_depth) {
+ dbt = vector_search(&database, _nsmap, _nsmapsize, sizeof(*_nsmap),
+ string_compare);
+ fb_method = nss_method_lookup(NSSRC_FALLBACK, database,
+ method_name, disp_tab, &mdata);
+ }
+
+ if (dbt != NULL) {
+ srclist = dbt->srclist;
+ srclistsize = dbt->srclistsize;
+ } else {
+ srclist = defaults;
+ srclistsize = 0;
+ while (srclist[srclistsize].name != NULL)
+ srclistsize++;
+ }
+
+#ifdef NS_CACHING
+ cache_data_p = NULL;
+ cache_flag = 0;
+#endif
+ for (i = 0; i < srclistsize; i++) {
+ result = NS_NOTFOUND;
+ method = nss_method_lookup(srclist[i].name, database,
+ method_name, disp_tab, &mdata);
+
+ if (method != NULL) {
+#ifdef NS_CACHING
+ if (strcmp(srclist[i].name, NSSRC_CACHE) == 0 &&
+ nss_cache_cycle_prevention_func == NULL) {
+#ifdef NS_STRICT_LIBC_EID_CHECKING
+ if (issetugid() != 0)
+ continue;
+#endif
+ cache_flag = 1;
+
+ memset(&cache_data, 0, sizeof(nss_cache_data));
+ cache_data.info = (nss_cache_info const *)mdata;
+ cache_data_p = &cache_data;
+
+ va_start(ap, defaults);
+ if (cache_data.info->id_func != NULL)
+ result = __nss_common_cache_read(retval,
+ cache_data_p, ap);
+ else if (cache_data.info->marshal_func != NULL)
+ result = __nss_mp_cache_read(retval,
+ cache_data_p, ap);
+ else
+ result = __nss_mp_cache_end(retval,
+ cache_data_p, ap);
+ va_end(ap);
+ } else {
+ cache_flag = 0;
+ errno = 0;
+ va_start(ap, defaults);
+ result = method(retval, mdata, ap);
+ va_end(ap);
+ }
+#else /* NS_CACHING */
+ errno = 0;
+ va_start(ap, defaults);
+ result = method(retval, mdata, ap);
+ va_end(ap);
+#endif /* NS_CACHING */
+
+ if (result & (srclist[i].flags))
+ break;
+ } else {
+ if (fb_method != NULL) {
+ saved_depth = st->fallback_depth;
+ st->fallback_depth = st->dispatch_depth + 1;
+ va_start(ap, defaults);
+ result = fb_method(retval,
+ (void *)srclist[i].name, ap);
+ va_end(ap);
+ st->fallback_depth = saved_depth;
+ } else
+ nss_log(LOG_DEBUG, "%s, %s, %s, not found, "
+ "and no fallback provided",
+ srclist[i].name, database, method_name);
+ }
+ }
+
+#ifdef NS_CACHING
+ if (cache_data_p != NULL &&
+ (result & (NS_NOTFOUND | NS_SUCCESS)) && cache_flag == 0) {
+ va_start(ap, defaults);
+ if (result == NS_SUCCESS) {
+ if (cache_data.info->id_func != NULL)
+ __nss_common_cache_write(retval, cache_data_p,
+ ap);
+ else if (cache_data.info->marshal_func != NULL)
+ __nss_mp_cache_write(retval, cache_data_p, ap);
+ } else if (result == NS_NOTFOUND) {
+ if (cache_data.info->id_func == NULL) {
+ if (cache_data.info->marshal_func != NULL)
+ __nss_mp_cache_write_submit(retval,
+ cache_data_p, ap);
+ } else
+ __nss_common_cache_write_negative(cache_data_p);
+ }
+ va_end(ap);
+ }
+#endif /* NS_CACHING */
+
+ if (isthreaded)
+ (void)_pthread_rwlock_unlock(&nss_lock);
+ --st->dispatch_depth;
+fin:
+ errno = serrno;
+ return (result);
+}
diff --git a/lib/libc/net/nslexer.l b/lib/libc/net/nslexer.l
new file mode 100644
index 000000000000..c7a95f614da8
--- /dev/null
+++ b/lib/libc/net/nslexer.l
@@ -0,0 +1,111 @@
+%{
+/* $NetBSD: nslexer.l,v 1.3 1999/01/25 00:16:17 lukem Exp $ */
+
+/*-
+ * Copyright (c) 1997, 1998, 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Luke Mewburn.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *rcsid =
+ "$FreeBSD$";
+#endif /* LIBC_SCCS and not lint */
+
+#include "namespace.h"
+#include <ctype.h>
+#define _NS_PRIVATE
+#include <nsswitch.h>
+#include <string.h>
+#include <syslog.h>
+#include "un-namespace.h"
+
+#include "nsparser.h"
+
+%}
+
+%option noinput
+%option nounput
+%option yylineno
+
+BLANK [ \t]
+CR \n
+STRING [a-zA-Z][a-zA-Z0-9_]*
+
+%%
+
+{BLANK}+ ; /* skip whitespace */
+
+#.* ; /* skip comments */
+
+\\{CR} ; /* allow continuation */
+
+{CR} return NL;
+
+[sS][uU][cC][cC][eE][sS][sS] return SUCCESS;
+[uU][nN][aA][vV][aA][iI][lL] return UNAVAIL;
+[nN][oO][tT][fF][oO][uU][nN][dD] return NOTFOUND;
+[tT][rR][yY][aA][gG][aA][iI][nN] return TRYAGAIN;
+
+[rR][eE][tT][uU][rR][nN] return RETURN;
+[cC][oO][nN][tT][iI][nN][uU][eE] return CONTINUE;
+
+{STRING} {
+ char *p;
+ int i;
+
+ if ((p = strdup(yytext)) == NULL) {
+ syslog(LOG_ERR,
+ "NSSWITCH(nslexer): memory allocation failure");
+ return ERRORTOKEN;
+ }
+ for (i = 0; i < strlen(p); i++) {
+ if (isupper((unsigned char)p[i]))
+ p[i] = tolower((unsigned char)p[i]);
+ }
+ _nsyylval.str = p;
+ return STRING;
+ }
+
+. return yytext[0];
+
+%%
+
+#undef _nsyywrap
+int
+_nsyywrap(void)
+{
+ return 1;
+} /* _nsyywrap */
+
+void
+_nsyyerror(const char *msg)
+{
+
+ syslog(LOG_ERR, "NSSWITCH(nslexer): %s line %d: %s at '%s'",
+ _PATH_NS_CONF, yylineno, msg, yytext);
+} /* _nsyyerror */
diff --git a/lib/libc/net/nsparser.y b/lib/libc/net/nsparser.y
new file mode 100644
index 000000000000..7d2f6e208521
--- /dev/null
+++ b/lib/libc/net/nsparser.y
@@ -0,0 +1,177 @@
+%{
+/* $NetBSD: nsparser.y,v 1.3 1999/01/25 00:16:18 lukem Exp $ */
+
+/*-
+ * Copyright (c) 1997, 1998, 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Luke Mewburn.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#define _NS_PRIVATE
+#include <nsswitch.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include "un-namespace.h"
+
+static void _nsaddsrctomap(const char *);
+
+static ns_dbt curdbt;
+static ns_src cursrc;
+%}
+
+%union {
+ char *str;
+ int mapval;
+}
+
+%token NL
+%token SUCCESS UNAVAIL NOTFOUND TRYAGAIN
+%token RETURN CONTINUE
+%token ERRORTOKEN
+%token <str> STRING
+
+%type <mapval> Status Action
+
+%%
+
+File
+ : /* empty */
+ | Lines
+ ;
+
+Lines
+ : Entry
+ | Lines Entry
+ ;
+
+Entry
+ : NL
+ | Database ':' NL
+ {
+ free((char*)curdbt.name);
+ }
+ | Database ':' Srclist NL
+ {
+ _nsdbtput(&curdbt);
+ }
+ | error NL
+ {
+ yyerrok;
+ }
+ ;
+
+Database
+ : STRING
+ {
+ curdbt.name = yylval.str;
+ curdbt.srclist = NULL;
+ curdbt.srclistsize = 0;
+ }
+ ;
+
+Srclist
+ : Item
+ | Srclist Item
+ ;
+
+Item
+ : STRING
+ {
+ cursrc.flags = NS_TERMINATE;
+ _nsaddsrctomap($1);
+ }
+ | STRING '[' { cursrc.flags = NS_SUCCESS; } Criteria ']'
+ {
+ _nsaddsrctomap($1);
+ }
+ ;
+
+Criteria
+ : Criterion
+ | Criteria Criterion
+ ;
+
+Criterion
+ : Status '=' Action
+ {
+ if ($3) /* if action == RETURN set RETURN bit */
+ cursrc.flags |= $1;
+ else /* else unset it */
+ cursrc.flags &= ~$1;
+ }
+ ;
+
+Status
+ : SUCCESS { $$ = NS_SUCCESS; }
+ | UNAVAIL { $$ = NS_UNAVAIL; }
+ | NOTFOUND { $$ = NS_NOTFOUND; }
+ | TRYAGAIN { $$ = NS_TRYAGAIN; }
+ ;
+
+Action
+ : RETURN { $$ = NS_ACTION_RETURN; }
+ | CONTINUE { $$ = NS_ACTION_CONTINUE; }
+ ;
+
+%%
+
+static void
+_nsaddsrctomap(const char *elem)
+{
+ int i, lineno;
+ extern int _nsyylineno;
+ extern char * _nsyytext;
+
+ lineno = _nsyylineno - (*_nsyytext == '\n' ? 1 : 0);
+ if (curdbt.srclistsize > 0) {
+ if (((strcasecmp(elem, NSSRC_COMPAT) == 0) &&
+ (strcasecmp(curdbt.srclist[0].name, NSSRC_CACHE) != 0)) ||
+ (strcasecmp(curdbt.srclist[0].name, NSSRC_COMPAT) == 0)) {
+ syslog(LOG_ERR,
+ "NSSWITCH(nsparser): %s line %d: 'compat' used with sources, other than 'cache'",
+ _PATH_NS_CONF, lineno);
+ free((void*)elem);
+ return;
+ }
+ }
+ for (i = 0; i < curdbt.srclistsize; i++) {
+ if (strcasecmp(curdbt.srclist[i].name, elem) == 0) {
+ syslog(LOG_ERR,
+ "NSSWITCH(nsparser): %s line %d: duplicate source '%s'",
+ _PATH_NS_CONF, lineno, elem);
+ free((void*)elem);
+ return;
+ }
+ }
+ cursrc.name = elem;
+ _nsdbtaddsrc(&curdbt, &cursrc);
+}
diff --git a/lib/libc/net/nss_backends.h b/lib/libc/net/nss_backends.h
new file mode 100644
index 000000000000..9bea37b1c24b
--- /dev/null
+++ b/lib/libc/net/nss_backends.h
@@ -0,0 +1,43 @@
+/*-
+ * Copyright (c) 2003 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project by
+ * Jacques A. Vidrine, Safeport Network Services, and Network
+ * Associates Laboratories, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+ * ("CBOSS"), as part of the DARPA CHATS research program.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+/*
+ * Eventually, the implementations of existing built-in NSS functions
+ * may be moved into NSS modules and live here.
+ */
+#if 0
+NSS_BACKEND( files, _files_nss_module_register )
+NSS_BACKEND( dns, _dns_nss_module_register )
+NSS_BACKEND( nis, _nis_nss_module_register )
+NSS_BACKEND( compat, _compat_nss_module_register )
+#endif
diff --git a/lib/libc/net/nss_compat.c b/lib/libc/net/nss_compat.c
new file mode 100644
index 000000000000..be2f75762bc2
--- /dev/null
+++ b/lib/libc/net/nss_compat.c
@@ -0,0 +1,288 @@
+/*-
+ * Copyright (c) 2003 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project by
+ * Jacques A. Vidrine, Safeport Network Services, and Network
+ * Associates Laboratories, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+ * ("CBOSS"), as part of the DARPA CHATS research program.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Compatibility shims for the GNU C Library-style nsswitch interface.
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <errno.h>
+#include <nss.h>
+#include <pthread.h>
+#include <pthread_np.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+
+
+struct group;
+struct passwd;
+
+static int terminator;
+
+#define DECLARE_TERMINATOR(x) \
+static pthread_key_t _term_key_##x; \
+static void \
+_term_create_##x(void) \
+{ \
+ (void)_pthread_key_create(&_term_key_##x, NULL); \
+} \
+static void *_term_main_##x; \
+static pthread_once_t _term_once_##x = PTHREAD_ONCE_INIT
+
+#define SET_TERMINATOR(x, y) \
+do { \
+ if (!__isthreaded || _pthread_main_np()) \
+ _term_main_##x = (y); \
+ else { \
+ (void)_pthread_once(&_term_once_##x, _term_create_##x); \
+ (void)_pthread_setspecific(_term_key_##x, y); \
+ } \
+} while (0)
+
+#define CHECK_TERMINATOR(x) \
+(!__isthreaded || _pthread_main_np() ? \
+ (_term_main_##x) : \
+ ((void)_pthread_once(&_term_once_##x, _term_create_##x), \
+ _pthread_getspecific(_term_key_##x)))
+
+
+
+DECLARE_TERMINATOR(group);
+
+int __nss_compat_getgrnam_r(void *retval, void *mdata, va_list ap);
+int __nss_compat_getgrgid_r(void *retval, void *mdata, va_list ap);
+int __nss_compat_getgrent_r(void *retval, void *mdata, va_list ap);
+int __nss_compat_setgrent(void *retval, void *mdata, va_list ap);
+int __nss_compat_endgrent(void *retval, void *mdata, va_list ap);
+int __nss_compat_getpwnam_r(void *retval, void *mdata, va_list ap);
+int __nss_compat_getpwuid_r(void *retval, void *mdata, va_list ap);
+int __nss_compat_getpwent_r(void *retval, void *mdata, va_list ap);
+int __nss_compat_setpwent(void *retval, void *mdata, va_list ap);
+int __nss_compat_endpwent(void *retval, void *mdata, va_list ap);
+
+int
+__nss_compat_getgrnam_r(void *retval, void *mdata, va_list ap)
+{
+ int (*fn)(const char *, struct group *, char *, size_t, int *);
+ const char *name;
+ struct group *grp;
+ char *buffer;
+ int *errnop, ns_status;
+ size_t bufsize;
+ enum nss_status nss_status;
+
+ fn = mdata;
+ name = va_arg(ap, const char *);
+ grp = va_arg(ap, struct group *);
+ buffer = va_arg(ap, char *);
+ bufsize = va_arg(ap, size_t);
+ errnop = va_arg(ap, int *);
+ nss_status = fn(name, grp, buffer, bufsize, errnop);
+ ns_status = __nss_compat_result(nss_status, *errnop);
+ if (ns_status == NS_SUCCESS)
+ *(struct group **)retval = grp;
+ return (ns_status);
+}
+
+
+int
+__nss_compat_getgrgid_r(void *retval, void *mdata, va_list ap)
+{
+ int (*fn)(gid_t, struct group *, char *, size_t, int *);
+ gid_t gid;
+ struct group *grp;
+ char *buffer;
+ int *errnop, ns_status;
+ size_t bufsize;
+ enum nss_status nss_status;
+
+ fn = mdata;
+ gid = va_arg(ap, gid_t);
+ grp = va_arg(ap, struct group *);
+ buffer = va_arg(ap, char *);
+ bufsize = va_arg(ap, size_t);
+ errnop = va_arg(ap, int *);
+ nss_status = fn(gid, grp, buffer, bufsize, errnop);
+ ns_status = __nss_compat_result(nss_status, *errnop);
+ if (ns_status == NS_SUCCESS)
+ *(struct group **)retval = grp;
+ return (ns_status);
+}
+
+
+int
+__nss_compat_getgrent_r(void *retval, void *mdata, va_list ap)
+{
+ int (*fn)(struct group *, char *, size_t, int *);
+ struct group *grp;
+ char *buffer;
+ int *errnop, ns_status;
+ size_t bufsize;
+ enum nss_status nss_status;
+
+ if (CHECK_TERMINATOR(group))
+ return (NS_NOTFOUND);
+ fn = mdata;
+ grp = va_arg(ap, struct group *);
+ buffer = va_arg(ap, char *);
+ bufsize = va_arg(ap, size_t);
+ errnop = va_arg(ap, int *);
+ nss_status = fn(grp, buffer, bufsize, errnop);
+ ns_status = __nss_compat_result(nss_status, *errnop);
+ if (ns_status == NS_SUCCESS)
+ *(struct group **)retval = grp;
+ else if (ns_status != NS_RETURN)
+ SET_TERMINATOR(group, &terminator);
+ return (ns_status);
+}
+
+
+int
+__nss_compat_setgrent(void *retval, void *mdata, va_list ap)
+{
+
+ SET_TERMINATOR(group, NULL);
+ ((int (*)(void))mdata)();
+ return (NS_UNAVAIL);
+}
+
+
+int
+__nss_compat_endgrent(void *retval, void *mdata, va_list ap)
+{
+
+ SET_TERMINATOR(group, NULL);
+ ((int (*)(void))mdata)();
+ return (NS_UNAVAIL);
+}
+
+
+
+DECLARE_TERMINATOR(passwd);
+
+
+int
+__nss_compat_getpwnam_r(void *retval, void *mdata, va_list ap)
+{
+ int (*fn)(const char *, struct passwd *, char *, size_t, int *);
+ const char *name;
+ struct passwd *pwd;
+ char *buffer;
+ int *errnop, ns_status;
+ size_t bufsize;
+ enum nss_status nss_status;
+
+ fn = mdata;
+ name = va_arg(ap, const char *);
+ pwd = va_arg(ap, struct passwd *);
+ buffer = va_arg(ap, char *);
+ bufsize = va_arg(ap, size_t);
+ errnop = va_arg(ap, int *);
+ nss_status = fn(name, pwd, buffer, bufsize, errnop);
+ ns_status = __nss_compat_result(nss_status, *errnop);
+ if (ns_status == NS_SUCCESS)
+ *(struct passwd **)retval = pwd;
+ return (ns_status);
+}
+
+
+int
+__nss_compat_getpwuid_r(void *retval, void *mdata, va_list ap)
+{
+ int (*fn)(uid_t, struct passwd *, char *, size_t, int *);
+ uid_t uid;
+ struct passwd *pwd;
+ char *buffer;
+ int *errnop, ns_status;
+ size_t bufsize;
+ enum nss_status nss_status;
+
+ fn = mdata;
+ uid = va_arg(ap, uid_t);
+ pwd = va_arg(ap, struct passwd *);
+ buffer = va_arg(ap, char *);
+ bufsize = va_arg(ap, size_t);
+ errnop = va_arg(ap, int *);
+ nss_status = fn(uid, pwd, buffer, bufsize, errnop);
+ ns_status = __nss_compat_result(nss_status, *errnop);
+ if (ns_status == NS_SUCCESS)
+ *(struct passwd **)retval = pwd;
+ return (ns_status);
+}
+
+
+int
+__nss_compat_getpwent_r(void *retval, void *mdata, va_list ap)
+{
+ int (*fn)(struct passwd *, char *, size_t, int *);
+ struct passwd *pwd;
+ char *buffer;
+ int *errnop, ns_status;
+ size_t bufsize;
+ enum nss_status nss_status;
+
+ if (CHECK_TERMINATOR(passwd))
+ return (NS_NOTFOUND);
+ fn = mdata;
+ pwd = va_arg(ap, struct passwd *);
+ buffer = va_arg(ap, char *);
+ bufsize = va_arg(ap, size_t);
+ errnop = va_arg(ap, int *);
+ nss_status = fn(pwd, buffer, bufsize, errnop);
+ ns_status = __nss_compat_result(nss_status, *errnop);
+ if (ns_status == NS_SUCCESS)
+ *(struct passwd **)retval = pwd;
+ else if (ns_status != NS_RETURN)
+ SET_TERMINATOR(passwd, &terminator);
+ return (ns_status);
+}
+
+
+int
+__nss_compat_setpwent(void *retval, void *mdata, va_list ap)
+{
+
+ SET_TERMINATOR(passwd, NULL);
+ ((int (*)(void))mdata)();
+ return (NS_UNAVAIL);
+}
+
+
+int
+__nss_compat_endpwent(void *retval, void *mdata, va_list ap)
+{
+
+ SET_TERMINATOR(passwd, NULL);
+ ((int (*)(void))mdata)();
+ return (NS_UNAVAIL);
+}
diff --git a/lib/libc/net/ntoh.c b/lib/libc/net/ntoh.c
new file mode 100644
index 000000000000..d658c90b68ac
--- /dev/null
+++ b/lib/libc/net/ntoh.c
@@ -0,0 +1,60 @@
+/*-
+ * Copyright (c) 2006 Olivier Houchard
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/endian.h>
+#define _BYTEORDER_FUNC_DEFINED
+#include <arpa/inet.h>
+
+uint32_t
+htonl(uint32_t hl)
+{
+
+ return (__htonl(hl));
+}
+
+uint16_t
+htons(uint16_t hs)
+{
+
+ return (__htons(hs));
+}
+
+uint32_t
+ntohl(uint32_t nl)
+{
+
+ return (__ntohl(nl));
+}
+
+uint16_t
+ntohs(uint16_t ns)
+{
+
+ return (__ntohs(ns));
+}
diff --git a/lib/libc/net/rcmd.3 b/lib/libc/net/rcmd.3
new file mode 100644
index 000000000000..1cd43279d023
--- /dev/null
+++ b/lib/libc/net/rcmd.3
@@ -0,0 +1,306 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" From: @(#)rcmd.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd March 3, 2000
+.Dt RCMD 3
+.Os
+.Sh NAME
+.Nm rcmd ,
+.Nm rresvport ,
+.Nm iruserok ,
+.Nm ruserok ,
+.Nm rcmd_af ,
+.Nm rresvport_af ,
+.Nm iruserok_sa
+.Nd routines for returning a stream to a remote command
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft int
+.Fn rcmd "char **ahost" "int inport" "const char *locuser" "const char *remuser" "const char *cmd" "int *fd2p"
+.Ft int
+.Fn rresvport "int *port"
+.Ft int
+.Fn iruserok "u_long raddr" "int superuser" "const char *ruser" "const char *luser"
+.Ft int
+.Fn ruserok "const char *rhost" "int superuser" "const char *ruser" "const char *luser"
+.Ft int
+.Fn rcmd_af "char **ahost" "int inport" "const char *locuser" "const char *remuser" "const char *cmd" "int *fd2p" "int af"
+.Ft int
+.Fn rresvport_af "int *port" "int af"
+.Ft int
+.Fn iruserok_sa "const void *addr" "int addrlen" "int superuser" "const char *ruser" "const char *luser"
+.Sh DESCRIPTION
+The
+.Fn rcmd
+function
+is used by the super-user to execute a command on
+a remote machine using an authentication scheme based
+on reserved port numbers.
+The
+.Fn rresvport
+function
+returns a descriptor to a socket
+with an address in the privileged port space.
+The
+.Fn ruserok
+function
+is used by servers
+to authenticate clients requesting service with
+.Fn rcmd .
+All three functions are present in the same file and are used
+by the
+.Xr rshd 8
+server (among others).
+.Pp
+The
+.Fn rcmd
+function
+looks up the host
+.Fa *ahost
+using
+.Xr gethostbyname 3 ,
+returning -1 if the host does not exist.
+Otherwise
+.Fa *ahost
+is set to the standard name of the host
+and a connection is established to a server
+residing at the well-known Internet port
+.Fa inport .
+.Pp
+If the connection succeeds,
+a socket in the Internet domain of type
+.Dv SOCK_STREAM
+is returned to the caller, and given to the remote
+command as
+.Dv stdin
+and
+.Dv stdout .
+If
+.Fa fd2p
+is non-zero, then an auxiliary channel to a control
+process will be set up, and a descriptor for it will be placed
+in
+.Fa *fd2p .
+The control process will return diagnostic
+output from the command (unit 2) on this channel, and will also
+accept bytes on this channel as being
+.Ux
+signal numbers, to be
+forwarded to the process group of the command.
+If
+.Fa fd2p
+is 0, then the
+.Dv stderr
+(unit 2 of the remote
+command) will be made the same as the
+.Dv stdout
+and no
+provision is made for sending arbitrary signals to the remote process,
+although you may be able to get its attention by using out-of-band data.
+.Pp
+The protocol is described in detail in
+.Xr rshd 8 .
+.Pp
+The
+.Fn rresvport
+function is used to obtain a socket to which an address with a Privileged
+Internet port is bound.
+This socket is suitable for use by
+.Fn rcmd
+and several other functions.
+Privileged Internet ports are those in the range 0 to 1023.
+Only the super-user is allowed to bind an address of this sort
+to a socket.
+.Pp
+The
+.Fn iruserok
+and
+.Fn ruserok
+functions take a remote host's IP address or name, as returned by the
+.Xr gethostbyname 3
+routines, two user names and a flag indicating whether the local user's
+name is that of the super-user.
+Then, if the user is
+.Em NOT
+the super-user, it checks the
+.Pa /etc/hosts.equiv
+file.
+If that lookup is not done, or is unsuccessful, the
+.Pa .rhosts
+in the local user's home directory is checked to see if the request for
+service is allowed.
+.Pp
+If this file does not exist, is not a regular file, is owned by anyone
+other than the user or the super-user, or is writable by anyone other
+than the owner, the check automatically fails.
+Zero is returned if the machine name is listed in the
+.Dq Pa hosts.equiv
+file, or the host and remote user name are found in the
+.Dq Pa .rhosts
+file; otherwise
+.Fn iruserok
+and
+.Fn ruserok
+return -1.
+If the local domain (as obtained from
+.Xr gethostname 3 )
+is the same as the remote domain, only the machine name need be specified.
+.Pp
+The
+.Fn iruserok
+function is strongly preferred for security reasons.
+It requires trusting the local DNS at most, while the
+.Fn ruserok
+function requires trusting the entire DNS, which can be spoofed.
+.Pp
+The functions with an
+.Dq Li _af
+or
+.Dq Li _sa
+suffix, i.e.,
+.Fn rcmd_af ,
+.Fn rresvport_af
+and
+.Fn iruserok_sa ,
+work the same as the corresponding functions without a
+suffix, except that they are capable of handling both IPv6 and IPv4 ports.
+.Pp
+The
+.Dq Li _af
+suffix means that the function has an additional
+.Fa af
+argument which is used to specify the address family,
+(see below).
+The
+.Fa af
+argument extension is implemented for functions
+that have no binary address argument.
+Instead, the
+.Fa af
+argument specifies which address family is desired.
+.Pp
+The
+.Dq Li _sa
+suffix means that the function has general socket address and
+length arguments.
+As the socket address is a protocol independent data structure,
+IPv4 and IPv6 socket address can be passed as desired.
+The
+.Fa sa
+argument extension is implemented for functions
+that pass a protocol dependent binary address argument.
+The argument needs to be replaced with a more general address structure
+to support multiple address families in a general way.
+.Pp
+The functions with neither an
+.Dq Li _af
+suffix nor an
+.Dq Li _sa
+suffix work for IPv4 only, except for
+.Fn ruserok
+which can handle both IPv6 and IPv4.
+To switch the address family, the
+.Fa af
+argument must be filled with
+.Dv AF_INET ,
+or
+.Dv AF_INET6 .
+For
+.Fn rcmd_af ,
+.Dv PF_UNSPEC
+is also allowed.
+.Sh ENVIRONMENT
+.Bl -tag -width RSH
+.It Ev RSH
+When using the
+.Fn rcmd
+function, this variable is used as the program to run instead of
+.Xr rsh 1 .
+.El
+.Sh DIAGNOSTICS
+The
+.Fn rcmd
+function
+returns a valid socket descriptor on success.
+It returns -1 on error and prints a diagnostic message
+on the standard error.
+.Pp
+The
+.Fn rresvport
+function
+returns a valid, bound socket descriptor on success.
+It returns -1 on error with the global value
+.Va errno
+set according to the reason for failure.
+The error code
+.Er EAGAIN
+is overloaded to mean ``All network ports in use.''
+.Sh SEE ALSO
+.Xr rlogin 1 ,
+.Xr rsh 1 ,
+.Xr intro 2 ,
+.Xr rlogind 8 ,
+.Xr rshd 8
+.Pp
+.Rs
+.%A W. Stevens
+.%A M. Thomas
+.%T "Advanced Socket API for IPv6"
+.%O RFC2292
+.Re
+.Rs
+.%A W. Stevens
+.%A M. Thomas
+.%A E. Nordmark
+.%T "Advanced Socket API for IPv6"
+.%O RFC3542
+.Re
+.Sh HISTORY
+Most of these
+functions appeared in
+.Bx 4.2 .
+The
+.Fn rresvport_af
+function
+appeared in RFC2292, and was implemented by the WIDE project
+for the Hydrangea IPv6 protocol stack kit.
+The
+.Fn rcmd_af
+function
+appeared in draft-ietf-ipngwg-rfc2292bis-01.txt,
+and was implemented in the WIDE/KAME IPv6 protocol stack kit.
+The
+.Fn iruserok_sa
+function
+appeared in discussion on the IETF ipngwg mailing list,
+and was implemented in
+.Fx 4.0 .
diff --git a/lib/libc/net/rcmd.c b/lib/libc/net/rcmd.c
new file mode 100644
index 000000000000..7b92f0816261
--- /dev/null
+++ b/lib/libc/net/rcmd.c
@@ -0,0 +1,733 @@
+/*
+ * Copyright (c) 1983, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)rcmd.c 8.3 (Berkeley) 3/26/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <signal.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <errno.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <rpc/rpc.h>
+#ifdef YP
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+#endif
+#include <arpa/nameser.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+
+extern int innetgr( const char *, const char *, const char *, const char * );
+
+#define max(a, b) ((a > b) ? a : b)
+
+int __ivaliduser(FILE *, u_int32_t, const char *, const char *);
+int __ivaliduser_af(FILE *,const void *, const char *, const char *, int, int);
+int __ivaliduser_sa(FILE *, const struct sockaddr *, socklen_t, const char *,
+ const char *);
+static int __icheckhost(const struct sockaddr *, socklen_t, const char *);
+
+char paddr[NI_MAXHOST];
+
+int
+rcmd(char **ahost, int rport, const char *locuser, const char *remuser,
+ const char *cmd, int *fd2p)
+{
+ return rcmd_af(ahost, rport, locuser, remuser, cmd, fd2p, AF_INET);
+}
+
+int
+rcmd_af(char **ahost, int rport, const char *locuser, const char *remuser,
+ const char *cmd, int *fd2p, int af)
+{
+ struct addrinfo hints, *res, *ai;
+ struct sockaddr_storage from;
+ fd_set reads;
+ sigset_t oldmask, newmask;
+ pid_t pid;
+ int s, aport, lport, timo, error;
+ char c, *p;
+ int refused, nres;
+ char num[8];
+ static char canonnamebuf[MAXDNAME]; /* is it proper here? */
+
+ /* call rcmdsh() with specified remote shell if appropriate. */
+ if (!issetugid() && (p = getenv("RSH"))) {
+ struct servent *sp = getservbyname("shell", "tcp");
+
+ if (sp && sp->s_port == rport)
+ return (rcmdsh(ahost, rport, locuser, remuser,
+ cmd, p));
+ }
+
+ /* use rsh(1) if non-root and remote port is shell. */
+ if (geteuid()) {
+ struct servent *sp = getservbyname("shell", "tcp");
+
+ if (sp && sp->s_port == rport)
+ return (rcmdsh(ahost, rport, locuser, remuser,
+ cmd, NULL));
+ }
+
+ pid = getpid();
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_CANONNAME;
+ hints.ai_family = af;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = 0;
+ (void)snprintf(num, sizeof(num), "%d", ntohs(rport));
+ error = getaddrinfo(*ahost, num, &hints, &res);
+ if (error) {
+ fprintf(stderr, "rcmd: getaddrinfo: %s\n",
+ gai_strerror(error));
+ if (error == EAI_SYSTEM)
+ fprintf(stderr, "rcmd: getaddrinfo: %s\n",
+ strerror(errno));
+ return (-1);
+ }
+
+ if (res->ai_canonname
+ && strlen(res->ai_canonname) + 1 < sizeof(canonnamebuf)) {
+ strncpy(canonnamebuf, res->ai_canonname, sizeof(canonnamebuf));
+ *ahost = canonnamebuf;
+ }
+ nres = 0;
+ for (ai = res; ai; ai = ai->ai_next)
+ nres++;
+ ai = res;
+ refused = 0;
+ sigemptyset(&newmask);
+ sigaddset(&newmask, SIGURG);
+ __libc_sigprocmask(SIG_BLOCK, (const sigset_t *)&newmask, &oldmask);
+ for (timo = 1, lport = IPPORT_RESERVED - 1;;) {
+ s = rresvport_af(&lport, ai->ai_family);
+ if (s < 0) {
+ if (errno != EAGAIN && ai->ai_next) {
+ ai = ai->ai_next;
+ continue;
+ }
+ if (errno == EAGAIN)
+ (void)fprintf(stderr,
+ "rcmd: socket: All ports in use\n");
+ else
+ (void)fprintf(stderr, "rcmd: socket: %s\n",
+ strerror(errno));
+ freeaddrinfo(res);
+ __libc_sigprocmask(SIG_SETMASK, (const sigset_t *)&oldmask,
+ NULL);
+ return (-1);
+ }
+ _fcntl(s, F_SETOWN, pid);
+ if (_connect(s, ai->ai_addr, ai->ai_addrlen) >= 0)
+ break;
+ (void)_close(s);
+ if (errno == EADDRINUSE) {
+ lport--;
+ continue;
+ }
+ if (errno == ECONNREFUSED)
+ refused = 1;
+ if (ai->ai_next == NULL && (!refused || timo > 16)) {
+ (void)fprintf(stderr, "%s: %s\n",
+ *ahost, strerror(errno));
+ freeaddrinfo(res);
+ __libc_sigprocmask(SIG_SETMASK, (const sigset_t *)&oldmask,
+ NULL);
+ return (-1);
+ }
+ if (nres > 1) {
+ int oerrno = errno;
+
+ getnameinfo(ai->ai_addr, ai->ai_addrlen, paddr,
+ sizeof(paddr), NULL, 0, NI_NUMERICHOST);
+ (void)fprintf(stderr, "connect to address %s: ",
+ paddr);
+ errno = oerrno;
+ perror(0);
+ }
+ if ((ai = ai->ai_next) == NULL) {
+ /* refused && timo <= 16 */
+ struct timespec time_to_sleep, time_remaining;
+
+ time_to_sleep.tv_sec = timo;
+ time_to_sleep.tv_nsec = 0;
+ (void)_nanosleep(&time_to_sleep, &time_remaining);
+ timo *= 2;
+ ai = res;
+ refused = 0;
+ }
+ if (nres > 1) {
+ getnameinfo(ai->ai_addr, ai->ai_addrlen, paddr,
+ sizeof(paddr), NULL, 0, NI_NUMERICHOST);
+ fprintf(stderr, "Trying %s...\n", paddr);
+ }
+ }
+ lport--;
+ if (fd2p == NULL) {
+ _write(s, "", 1);
+ lport = 0;
+ } else {
+ int s2 = rresvport_af(&lport, ai->ai_family), s3;
+ socklen_t len = ai->ai_addrlen;
+ int nfds;
+
+ if (s2 < 0)
+ goto bad;
+ _listen(s2, 1);
+ (void)snprintf(num, sizeof(num), "%d", lport);
+ if (_write(s, num, strlen(num)+1) != strlen(num)+1) {
+ (void)fprintf(stderr,
+ "rcmd: write (setting up stderr): %s\n",
+ strerror(errno));
+ (void)_close(s2);
+ goto bad;
+ }
+ nfds = max(s, s2)+1;
+ if(nfds > FD_SETSIZE) {
+ fprintf(stderr, "rcmd: too many files\n");
+ (void)_close(s2);
+ goto bad;
+ }
+again:
+ FD_ZERO(&reads);
+ FD_SET(s, &reads);
+ FD_SET(s2, &reads);
+ errno = 0;
+ if (_select(nfds, &reads, 0, 0, 0) < 1 || !FD_ISSET(s2, &reads)){
+ if (errno != 0)
+ (void)fprintf(stderr,
+ "rcmd: select (setting up stderr): %s\n",
+ strerror(errno));
+ else
+ (void)fprintf(stderr,
+ "select: protocol failure in circuit setup\n");
+ (void)_close(s2);
+ goto bad;
+ }
+ s3 = _accept(s2, (struct sockaddr *)&from, &len);
+ switch (from.ss_family) {
+ case AF_INET:
+ aport = ntohs(((struct sockaddr_in *)&from)->sin_port);
+ break;
+#ifdef INET6
+ case AF_INET6:
+ aport = ntohs(((struct sockaddr_in6 *)&from)->sin6_port);
+ break;
+#endif
+ default:
+ aport = 0; /* error */
+ break;
+ }
+ /*
+ * XXX careful for ftp bounce attacks. If discovered, shut them
+ * down and check for the real auxiliary channel to connect.
+ */
+ if (aport == 20) {
+ _close(s3);
+ goto again;
+ }
+ (void)_close(s2);
+ if (s3 < 0) {
+ (void)fprintf(stderr,
+ "rcmd: accept: %s\n", strerror(errno));
+ lport = 0;
+ goto bad;
+ }
+ *fd2p = s3;
+ if (aport >= IPPORT_RESERVED || aport < IPPORT_RESERVED / 2) {
+ (void)fprintf(stderr,
+ "socket: protocol failure in circuit setup.\n");
+ goto bad2;
+ }
+ }
+ (void)_write(s, locuser, strlen(locuser)+1);
+ (void)_write(s, remuser, strlen(remuser)+1);
+ (void)_write(s, cmd, strlen(cmd)+1);
+ if (_read(s, &c, 1) != 1) {
+ (void)fprintf(stderr,
+ "rcmd: %s: %s\n", *ahost, strerror(errno));
+ goto bad2;
+ }
+ if (c != 0) {
+ while (_read(s, &c, 1) == 1) {
+ (void)_write(STDERR_FILENO, &c, 1);
+ if (c == '\n')
+ break;
+ }
+ goto bad2;
+ }
+ __libc_sigprocmask(SIG_SETMASK, (const sigset_t *)&oldmask, NULL);
+ freeaddrinfo(res);
+ return (s);
+bad2:
+ if (lport)
+ (void)_close(*fd2p);
+bad:
+ (void)_close(s);
+ __libc_sigprocmask(SIG_SETMASK, (const sigset_t *)&oldmask, NULL);
+ freeaddrinfo(res);
+ return (-1);
+}
+
+int
+rresvport(int *port)
+{
+ return rresvport_af(port, AF_INET);
+}
+
+int
+rresvport_af(int *alport, int family)
+{
+ int s;
+ struct sockaddr_storage ss;
+ u_short *sport;
+
+ memset(&ss, 0, sizeof(ss));
+ ss.ss_family = family;
+ switch (family) {
+ case AF_INET:
+ ((struct sockaddr *)&ss)->sa_len = sizeof(struct sockaddr_in);
+ sport = &((struct sockaddr_in *)&ss)->sin_port;
+ ((struct sockaddr_in *)&ss)->sin_addr.s_addr = INADDR_ANY;
+ break;
+#ifdef INET6
+ case AF_INET6:
+ ((struct sockaddr *)&ss)->sa_len = sizeof(struct sockaddr_in6);
+ sport = &((struct sockaddr_in6 *)&ss)->sin6_port;
+ ((struct sockaddr_in6 *)&ss)->sin6_addr = in6addr_any;
+ break;
+#endif
+ default:
+ errno = EAFNOSUPPORT;
+ return -1;
+ }
+
+ s = _socket(ss.ss_family, SOCK_STREAM, 0);
+ if (s < 0)
+ return (-1);
+#if 0 /* compat_exact_traditional_rresvport_semantics */
+ sin.sin_port = htons((u_short)*alport);
+ if (_bind(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
+ return (s);
+ if (errno != EADDRINUSE) {
+ (void)_close(s);
+ return (-1);
+ }
+#endif
+ *sport = 0;
+ if (bindresvport_sa(s, (struct sockaddr *)&ss) == -1) {
+ (void)_close(s);
+ return (-1);
+ }
+ *alport = (int)ntohs(*sport);
+ return (s);
+}
+
+int __check_rhosts_file = 1;
+char *__rcmd_errstr;
+
+int
+ruserok(const char *rhost, int superuser, const char *ruser, const char *luser)
+{
+ struct addrinfo hints, *res, *r;
+ int error;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_DGRAM; /*dummy*/
+ error = getaddrinfo(rhost, "0", &hints, &res);
+ if (error)
+ return (-1);
+
+ for (r = res; r; r = r->ai_next) {
+ if (iruserok_sa(r->ai_addr, r->ai_addrlen, superuser, ruser,
+ luser) == 0) {
+ freeaddrinfo(res);
+ return (0);
+ }
+ }
+ freeaddrinfo(res);
+ return (-1);
+}
+
+/*
+ * New .rhosts strategy: We are passed an ip address. We spin through
+ * hosts.equiv and .rhosts looking for a match. When the .rhosts only
+ * has ip addresses, we don't have to trust a nameserver. When it
+ * contains hostnames, we spin through the list of addresses the nameserver
+ * gives us and look for a match.
+ *
+ * Returns 0 if ok, -1 if not ok.
+ */
+int
+iruserok(unsigned long raddr, int superuser, const char *ruser, const char *luser)
+{
+ struct sockaddr_in sin;
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_len = sizeof(struct sockaddr_in);
+ memcpy(&sin.sin_addr, &raddr, sizeof(sin.sin_addr));
+ return iruserok_sa((struct sockaddr *)&sin, sin.sin_len, superuser,
+ ruser, luser);
+}
+
+/*
+ * AF independent extension of iruserok.
+ *
+ * Returns 0 if ok, -1 if not ok.
+ */
+int
+iruserok_sa(const void *ra, int rlen, int superuser, const char *ruser,
+ const char *luser)
+{
+ char *cp;
+ struct stat sbuf;
+ struct passwd *pwd;
+ FILE *hostf;
+ uid_t uid;
+ int first;
+ char pbuf[MAXPATHLEN];
+ const struct sockaddr *raddr;
+ struct sockaddr_storage ss;
+
+ /* avoid alignment issue */
+ if (rlen > sizeof(ss))
+ return(-1);
+ memcpy(&ss, ra, rlen);
+ raddr = (struct sockaddr *)&ss;
+
+ first = 1;
+ hostf = superuser ? NULL : fopen(_PATH_HEQUIV, "re");
+again:
+ if (hostf) {
+ if (__ivaliduser_sa(hostf, raddr, rlen, luser, ruser) == 0) {
+ (void)fclose(hostf);
+ return (0);
+ }
+ (void)fclose(hostf);
+ }
+ if (first == 1 && (__check_rhosts_file || superuser)) {
+ first = 0;
+ if ((pwd = getpwnam(luser)) == NULL)
+ return (-1);
+ (void)strcpy(pbuf, pwd->pw_dir);
+ (void)strcat(pbuf, "/.rhosts");
+
+ /*
+ * Change effective uid while opening .rhosts. If root and
+ * reading an NFS mounted file system, can't read files that
+ * are protected read/write owner only.
+ */
+ uid = geteuid();
+ (void)seteuid(pwd->pw_uid);
+ hostf = fopen(pbuf, "re");
+ (void)seteuid(uid);
+
+ if (hostf == NULL)
+ return (-1);
+ /*
+ * If not a regular file, or is owned by someone other than
+ * user or root or if writeable by anyone but the owner, quit.
+ */
+ cp = NULL;
+ if (lstat(pbuf, &sbuf) < 0)
+ cp = ".rhosts lstat failed";
+ else if (!S_ISREG(sbuf.st_mode))
+ cp = ".rhosts not regular file";
+ else if (_fstat(fileno(hostf), &sbuf) < 0)
+ cp = ".rhosts fstat failed";
+ else if (sbuf.st_uid && sbuf.st_uid != pwd->pw_uid)
+ cp = "bad .rhosts owner";
+ else if (sbuf.st_mode & (S_IWGRP|S_IWOTH))
+ cp = ".rhosts writeable by other than owner";
+ /* If there were any problems, quit. */
+ if (cp) {
+ __rcmd_errstr = cp;
+ (void)fclose(hostf);
+ return (-1);
+ }
+ goto again;
+ }
+ return (-1);
+}
+
+/*
+ * XXX
+ * Don't make static, used by lpd(8).
+ *
+ * Returns 0 if ok, -1 if not ok.
+ */
+int
+__ivaliduser(FILE *hostf, u_int32_t raddr, const char *luser, const char *ruser)
+{
+ struct sockaddr_in sin;
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_len = sizeof(struct sockaddr_in);
+ memcpy(&sin.sin_addr, &raddr, sizeof(sin.sin_addr));
+ return __ivaliduser_sa(hostf, (struct sockaddr *)&sin, sin.sin_len,
+ luser, ruser);
+}
+
+/*
+ * Returns 0 if ok, -1 if not ok.
+ *
+ * XXX obsolete API.
+ */
+int
+__ivaliduser_af(FILE *hostf, const void *raddr, const char *luser,
+ const char *ruser, int af, int len)
+{
+ struct sockaddr *sa = NULL;
+ struct sockaddr_in *sin = NULL;
+#ifdef INET6
+ struct sockaddr_in6 *sin6 = NULL;
+#endif
+ struct sockaddr_storage ss;
+
+ memset(&ss, 0, sizeof(ss));
+ switch (af) {
+ case AF_INET:
+ if (len != sizeof(sin->sin_addr))
+ return -1;
+ sin = (struct sockaddr_in *)&ss;
+ sin->sin_family = AF_INET;
+ sin->sin_len = sizeof(struct sockaddr_in);
+ memcpy(&sin->sin_addr, raddr, sizeof(sin->sin_addr));
+ break;
+#ifdef INET6
+ case AF_INET6:
+ if (len != sizeof(sin6->sin6_addr))
+ return -1;
+ /* you will lose scope info */
+ sin6 = (struct sockaddr_in6 *)&ss;
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_len = sizeof(struct sockaddr_in6);
+ memcpy(&sin6->sin6_addr, raddr, sizeof(sin6->sin6_addr));
+ break;
+#endif
+ default:
+ return -1;
+ }
+
+ sa = (struct sockaddr *)&ss;
+ return __ivaliduser_sa(hostf, sa, sa->sa_len, luser, ruser);
+}
+
+int
+__ivaliduser_sa(FILE *hostf, const struct sockaddr *raddr, socklen_t salen,
+ const char *luser, const char *ruser)
+{
+ char *user, *p;
+ int ch;
+ char buf[MAXHOSTNAMELEN + 128]; /* host + login */
+ char hname[MAXHOSTNAMELEN];
+ /* Presumed guilty until proven innocent. */
+ int userok = 0, hostok = 0;
+#ifdef YP
+ char *ypdomain;
+
+ if (yp_get_default_domain(&ypdomain))
+ ypdomain = NULL;
+#else
+#define ypdomain NULL
+#endif
+ /* We need to get the damn hostname back for netgroup matching. */
+ if (getnameinfo(raddr, salen, hname, sizeof(hname), NULL, 0,
+ NI_NAMEREQD) != 0)
+ hname[0] = '\0';
+
+ while (fgets(buf, sizeof(buf), hostf)) {
+ p = buf;
+ /* Skip lines that are too long. */
+ if (strchr(p, '\n') == NULL) {
+ while ((ch = getc(hostf)) != '\n' && ch != EOF);
+ continue;
+ }
+ if (*p == '\n' || *p == '#') {
+ /* comment... */
+ continue;
+ }
+ while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') {
+ *p = isupper((unsigned char)*p) ? tolower((unsigned char)*p) : *p;
+ p++;
+ }
+ if (*p == ' ' || *p == '\t') {
+ *p++ = '\0';
+ while (*p == ' ' || *p == '\t')
+ p++;
+ user = p;
+ while (*p != '\n' && *p != ' ' &&
+ *p != '\t' && *p != '\0')
+ p++;
+ } else
+ user = p;
+ *p = '\0';
+ /*
+ * Do +/- and +@/-@ checking. This looks really nasty,
+ * but it matches SunOS's behavior so far as I can tell.
+ */
+ switch(buf[0]) {
+ case '+':
+ if (!buf[1]) { /* '+' matches all hosts */
+ hostok = 1;
+ break;
+ }
+ if (buf[1] == '@') /* match a host by netgroup */
+ hostok = hname[0] != '\0' &&
+ innetgr(&buf[2], hname, NULL, ypdomain);
+ else /* match a host by addr */
+ hostok = __icheckhost(raddr, salen,
+ (char *)&buf[1]);
+ break;
+ case '-': /* reject '-' hosts and all their users */
+ if (buf[1] == '@') {
+ if (hname[0] == '\0' ||
+ innetgr(&buf[2], hname, NULL, ypdomain))
+ return(-1);
+ } else {
+ if (__icheckhost(raddr, salen,
+ (char *)&buf[1]))
+ return(-1);
+ }
+ break;
+ default: /* if no '+' or '-', do a simple match */
+ hostok = __icheckhost(raddr, salen, buf);
+ break;
+ }
+ switch(*user) {
+ case '+':
+ if (!*(user+1)) { /* '+' matches all users */
+ userok = 1;
+ break;
+ }
+ if (*(user+1) == '@') /* match a user by netgroup */
+ userok = innetgr(user+2, NULL, ruser, ypdomain);
+ else /* match a user by direct specification */
+ userok = !(strcmp(ruser, user+1));
+ break;
+ case '-': /* if we matched a hostname, */
+ if (hostok) { /* check for user field rejections */
+ if (!*(user+1))
+ return(-1);
+ if (*(user+1) == '@') {
+ if (innetgr(user+2, NULL,
+ ruser, ypdomain))
+ return(-1);
+ } else {
+ if (!strcmp(ruser, user+1))
+ return(-1);
+ }
+ }
+ break;
+ default: /* no rejections: try to match the user */
+ if (hostok)
+ userok = !(strcmp(ruser,*user ? user : luser));
+ break;
+ }
+ if (hostok && userok)
+ return(0);
+ }
+ return (-1);
+}
+
+/*
+ * Returns "true" if match, 0 if no match.
+ */
+static int
+__icheckhost(const struct sockaddr *raddr, socklen_t salen, const char *lhost)
+{
+ struct sockaddr_in sin;
+ struct sockaddr_in6 *sin6;
+ struct addrinfo hints, *res, *r;
+ int error;
+ char h1[NI_MAXHOST], h2[NI_MAXHOST];
+
+ if (raddr->sa_family == AF_INET6) {
+ sin6 = (struct sockaddr_in6 *)raddr;
+ if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_len = sizeof(struct sockaddr_in);
+ memcpy(&sin.sin_addr, &sin6->sin6_addr.s6_addr[12],
+ sizeof(sin.sin_addr));
+ raddr = (struct sockaddr *)&sin;
+ salen = sin.sin_len;
+ }
+ }
+
+ h1[0] = '\0';
+ if (getnameinfo(raddr, salen, h1, sizeof(h1), NULL, 0,
+ NI_NUMERICHOST) != 0)
+ return (0);
+
+ /* Resolve laddr into sockaddr */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = raddr->sa_family;
+ hints.ai_socktype = SOCK_DGRAM; /*XXX dummy*/
+ res = NULL;
+ error = getaddrinfo(lhost, "0", &hints, &res);
+ if (error)
+ return (0);
+
+ for (r = res; r ; r = r->ai_next) {
+ h2[0] = '\0';
+ if (getnameinfo(r->ai_addr, r->ai_addrlen, h2, sizeof(h2),
+ NULL, 0, NI_NUMERICHOST) != 0)
+ continue;
+ if (strcmp(h1, h2) == 0) {
+ freeaddrinfo(res);
+ return (1);
+ }
+ }
+
+ /* No match. */
+ freeaddrinfo(res);
+ return (0);
+}
diff --git a/lib/libc/net/rcmdsh.3 b/lib/libc/net/rcmdsh.3
new file mode 100644
index 000000000000..54c3a0a25205
--- /dev/null
+++ b/lib/libc/net/rcmdsh.3
@@ -0,0 +1,116 @@
+.\" $OpenBSD: rcmdsh.3,v 1.6 1999/07/05 04:41:00 aaron Exp $
+.\"
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd September 1, 1996
+.Dt RCMDSH 3
+.Os
+.Sh NAME
+.Nm rcmdsh
+.Nd return a stream to a remote command without superuser
+.Sh SYNOPSIS
+.In unistd.h
+.Ft int
+.Fo rcmdsh
+.Fa "char **ahost"
+.Fa "int inport"
+.Fa "const char *locuser"
+.Fa "const char *remuser"
+.Fa "const char *cmd"
+.Fa "const char *rshprog"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn rcmdsh
+function
+is used by normal users to execute a command on
+a remote machine using an authentication scheme based
+on reserved port numbers using
+.Xr rshd 8
+or the value of
+.Fa rshprog
+(if
+.No non- Ns Dv NULL ) .
+.Pp
+The
+.Fn rcmdsh
+function
+looks up the host
+.Fa *ahost
+using
+.Xr gethostbyname 3 ,
+returning \-1 if the host does not exist.
+Otherwise
+.Fa *ahost
+is set to the standard name of the host
+and a connection is established to a server
+residing at the well-known Internet port
+.Dq Li shell/tcp
+(or whatever port is used by
+.Fa rshprog ) .
+The
+.Fa inport
+argument
+is ignored; it is only included to provide an interface similar to
+.Xr rcmd 3 .
+.Pp
+If the connection succeeds,
+a socket in the
+.Ux
+domain of type
+.Dv SOCK_STREAM
+is returned to the caller, and given to the remote
+command as
+.Dv stdin , stdout ,
+and
+.Dv stderr .
+.Sh RETURN VALUES
+The
+.Fn rcmdsh
+function
+returns a valid socket descriptor on success.
+Otherwise, \-1 is returned
+and a diagnostic message is printed on the standard error.
+.Sh SEE ALSO
+.Xr rsh 1 ,
+.Xr socketpair 2 ,
+.Xr rcmd 3 ,
+.Xr rshd 8
+.Sh HISTORY
+The
+.Fn rcmdsh
+function first appeared in
+.Ox 2.0 ,
+and made its way into
+.Fx 4.6 .
+.Sh BUGS
+If
+.Xr rsh 1
+encounters an error, a file descriptor is still returned instead of \-1.
diff --git a/lib/libc/net/rcmdsh.c b/lib/libc/net/rcmdsh.c
new file mode 100644
index 000000000000..13278df11b2a
--- /dev/null
+++ b/lib/libc/net/rcmdsh.c
@@ -0,0 +1,167 @@
+/* $OpenBSD: rcmdsh.c,v 1.7 2002/03/12 00:05:44 millert Exp $ */
+
+/*
+ * Copyright (c) 2001, MagniComp
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the MagniComp nor the names of its contributors may
+ * be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This is an rcmd() replacement originally by
+ * Chris Siebenmann <cks@utcc.utoronto.ca>.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <netdb.h>
+#include <paths.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+/*
+ * This is a replacement rcmd() function that uses the rsh(1)
+ * program in place of a direct rcmd(3) function call so as to
+ * avoid having to be root. Note that rport is ignored.
+ */
+int
+rcmdsh(char **ahost, int rport, const char *locuser, const char *remuser,
+ const char *cmd, const char *rshprog)
+{
+ struct addrinfo hints, *res;
+ int sp[2], error;
+ pid_t cpid;
+ char *p;
+ struct passwd *pw;
+ char num[8];
+ static char hbuf[NI_MAXHOST];
+
+ /* What rsh/shell to use. */
+ if (rshprog == NULL)
+ rshprog = _PATH_RSH;
+
+ /* locuser must exist on this host. */
+ if ((pw = getpwnam(locuser)) == NULL) {
+ (void)fprintf(stderr, "rcmdsh: unknown user: %s\n", locuser);
+ return (-1);
+ }
+
+ /* Validate remote hostname. */
+ if (strcmp(*ahost, "localhost") != 0) {
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_CANONNAME;
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ (void)snprintf(num, sizeof(num), "%u",
+ (unsigned int)ntohs(rport));
+ error = getaddrinfo(*ahost, num, &hints, &res);
+ if (error) {
+ fprintf(stderr, "rcmdsh: getaddrinfo: %s\n",
+ gai_strerror(error));
+ return (-1);
+ }
+ if (res->ai_canonname) {
+ strncpy(hbuf, res->ai_canonname, sizeof(hbuf) - 1);
+ hbuf[sizeof(hbuf) - 1] = '\0';
+ *ahost = hbuf;
+ }
+ freeaddrinfo(res);
+ }
+
+ /* Get a socketpair we'll use for stdin and stdout. */
+ if (_socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, sp) == -1) {
+ perror("rcmdsh: socketpair");
+ return (-1);
+ }
+
+ cpid = fork();
+ if (cpid == -1) {
+ perror("rcmdsh: fork failed");
+ return (-1);
+ } else if (cpid == 0) {
+ /*
+ * Child. We use sp[1] to be stdin/stdout, and close sp[0].
+ */
+ (void)_close(sp[0]);
+ if (_dup2(sp[1], 0) == -1 || _dup2(0, 1) == -1) {
+ perror("rcmdsh: dup2 failed");
+ _exit(255);
+ }
+ /* Fork again to lose parent. */
+ cpid = fork();
+ if (cpid == -1) {
+ perror("rcmdsh: fork to lose parent failed");
+ _exit(255);
+ }
+ if (cpid > 0)
+ _exit(0);
+
+ /* In grandchild here. Become local user for rshprog. */
+ if (setuid(pw->pw_uid) == -1) {
+ (void)fprintf(stderr, "rcmdsh: setuid(%u): %s\n",
+ pw->pw_uid, strerror(errno));
+ _exit(255);
+ }
+
+ /*
+ * If remote host is "localhost" and local and remote users
+ * are the same, avoid running remote shell for efficiency.
+ */
+ if (strcmp(*ahost, "localhost") == 0 &&
+ strcmp(locuser, remuser) == 0) {
+ if (pw->pw_shell[0] == '\0')
+ rshprog = _PATH_BSHELL;
+ else
+ rshprog = pw->pw_shell;
+ p = strrchr(rshprog, '/');
+ execlp(rshprog, p ? p + 1 : rshprog, "-c", cmd,
+ (char *)NULL);
+ } else {
+ p = strrchr(rshprog, '/');
+ execlp(rshprog, p ? p + 1 : rshprog, *ahost, "-l",
+ remuser, cmd, (char *)NULL);
+ }
+ (void)fprintf(stderr, "rcmdsh: execlp %s failed: %s\n",
+ rshprog, strerror(errno));
+ _exit(255);
+ } else {
+ /* Parent. close sp[1], return sp[0]. */
+ (void)_close(sp[1]);
+ /* Reap child. */
+ (void)_waitpid(cpid, NULL, 0);
+ return (sp[0]);
+ }
+ /* NOTREACHED */
+}
diff --git a/lib/libc/net/recv.c b/lib/libc/net/recv.c
new file mode 100644
index 000000000000..68d3ce51015d
--- /dev/null
+++ b/lib/libc/net/recv.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)recv.c 8.2 (Berkeley) 2/21/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "libc_private.h"
+
+#include <stddef.h>
+
+ssize_t
+recv(int s, void *buf, size_t len, int flags)
+{
+ /*
+ * POSIX says recv() shall be a cancellation point, so call the
+ * cancellation-enabled recvfrom() and not _recvfrom().
+ */
+ return (((ssize_t (*)(int, void *, size_t, int,
+ struct sockaddr *, socklen_t *))
+ __libc_interposing[INTERPOS_recvfrom])(s, buf, len, flags,
+ NULL, NULL));
+}
diff --git a/lib/libc/net/res_config.h b/lib/libc/net/res_config.h
new file mode 100644
index 000000000000..51b609b48eaf
--- /dev/null
+++ b/lib/libc/net/res_config.h
@@ -0,0 +1,6 @@
+/* $FreeBSD$ */
+
+#define DEBUG 1 /* enable debugging code (needed for dig) */
+#define RESOLVSORT /* allow sorting of addresses in gethostbyname */
+#undef SUNSECURITY /* verify gethostbyaddr() calls - WE DON'T NEED IT */
+#define MULTI_PTRS_ARE_ALIASES 1 /* fold multiple PTR records into aliases */
diff --git a/lib/libc/net/resolver.3 b/lib/libc/net/resolver.3
new file mode 100644
index 000000000000..c1a37b3a24c8
--- /dev/null
+++ b/lib/libc/net/resolver.3
@@ -0,0 +1,461 @@
+.\" Copyright (c) 1985, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)resolver.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd May 29, 2009
+.Dt RESOLVER 3
+.Os
+.Sh NAME
+.Nm res_query ,
+.Nm res_search ,
+.Nm res_mkquery ,
+.Nm res_send ,
+.Nm res_init ,
+.Nm dn_comp ,
+.Nm dn_expand ,
+.Nm dn_skipname ,
+.Nm ns_get16 ,
+.Nm ns_get32 ,
+.Nm ns_put16 ,
+.Nm ns_put32
+.Nd resolver routines
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In netinet/in.h
+.In arpa/nameser.h
+.In resolv.h
+.Ft int
+.Fo res_query
+.Fa "const char *dname"
+.Fa "int class"
+.Fa "int type"
+.Fa "u_char *answer"
+.Fa "int anslen"
+.Fc
+.Ft int
+.Fo res_search
+.Fa "const char *dname"
+.Fa "int class"
+.Fa "int type"
+.Fa "u_char *answer"
+.Fa "int anslen"
+.Fc
+.Ft int
+.Fo res_mkquery
+.Fa "int op"
+.Fa "const char *dname"
+.Fa "int class"
+.Fa "int type"
+.Fa "const u_char *data"
+.Fa "int datalen"
+.Fa "const u_char *newrr_in"
+.Fa "u_char *buf"
+.Fa "int buflen"
+.Fc
+.Ft int
+.Fo res_send
+.Fa "const u_char *msg"
+.Fa "int msglen"
+.Fa "u_char *answer"
+.Fa "int anslen"
+.Fc
+.Ft int
+.Fn res_init void
+.Ft int
+.Fo dn_comp
+.Fa "const char *exp_dn"
+.Fa "u_char *comp_dn"
+.Fa "int length"
+.Fa "u_char **dnptrs"
+.Fa "u_char **lastdnptr"
+.Fc
+.Ft int
+.Fo dn_expand
+.Fa "const u_char *msg"
+.Fa "const u_char *eomorig"
+.Fa "const u_char *comp_dn"
+.Fa "char *exp_dn"
+.Fa "int length"
+.Fc
+.Ft int
+.Fn dn_skipname "const u_char *comp_dn" "const u_char *eom"
+.Ft u_int
+.Fn ns_get16 "const u_char *src"
+.Ft u_long
+.Fn ns_get32 "const u_char *src"
+.Ft void
+.Fn ns_put16 "u_int src" "u_char *dst"
+.Ft void
+.Fn ns_put32 "u_long src" "u_char *dst"
+.Sh DESCRIPTION
+These routines are used for making, sending and interpreting
+query and reply messages with Internet domain name servers.
+.Pp
+Global configuration and state information that is used by the
+resolver routines is kept in the structure
+.Va _res .
+Most of the values have reasonable defaults and can be ignored.
+Options
+stored in
+.Va _res.options
+are defined in
+.In resolv.h
+and are as follows.
+Options are stored as a simple bit mask containing the bitwise ``or''
+of the options enabled.
+.Bl -tag -width RES_USE_INET6
+.It Dv RES_INIT
+True if the initial name server address and default domain name are
+initialized (i.e.,
+.Fn res_init
+has been called).
+.It Dv RES_DEBUG
+Print debugging messages.
+.It Dv RES_AAONLY
+Accept authoritative answers only.
+With this option,
+.Fn res_send
+should continue until it finds an authoritative answer or finds an error.
+Currently this is not implemented.
+.It Dv RES_USEVC
+Use
+.Tn TCP
+connections for queries instead of
+.Tn UDP
+datagrams.
+.It Dv RES_STAYOPEN
+Used with
+.Dv RES_USEVC
+to keep the
+.Tn TCP
+connection open between
+queries.
+This is useful only in programs that regularly do many queries.
+.Tn UDP
+should be the normal mode used.
+.It Dv RES_IGNTC
+Unused currently (ignore truncation errors, i.e., do not retry with
+.Tn TCP ) .
+.It Dv RES_RECURSE
+Set the recursion-desired bit in queries.
+This is the default.
+.Pf ( Fn res_send
+does not do iterative queries and expects the name server
+to handle recursion.)
+.It Dv RES_DEFNAMES
+If set,
+.Fn res_search
+will append the default domain name to single-component names
+(those that do not contain a dot).
+This option is enabled by default.
+.It Dv RES_DNSRCH
+If this option is set,
+.Fn res_search
+will search for host names in the current domain and in parent domains; see
+.Xr hostname 7 .
+This is used by the standard host lookup routine
+.Xr gethostbyname 3 .
+This option is enabled by default.
+.It Dv RES_NOALIASES
+This option turns off the user level aliasing feature controlled by the
+.Dq Ev HOSTALIASES
+environment variable.
+Network daemons should set this option.
+.It Dv RES_USE_INET6
+Enables support for IPv6-only applications.
+This causes IPv4 addresses to be returned as an IPv4 mapped address.
+For example,
+.Li 10.1.1.1
+will be returned as
+.Li ::ffff:10.1.1.1 .
+The option is meaningful with certain kernel configuration only.
+.It Dv RES_USE_EDNS0
+Enables support for OPT pseudo-RR for EDNS0 extension.
+With the option, resolver code will attach OPT pseudo-RR into DNS queries,
+to inform of our receive buffer size.
+The option will allow DNS servers to take advantage of non-default receive
+buffer size, and to send larger replies.
+DNS query packets with EDNS0 extension is not compatible with
+non-EDNS0 DNS servers.
+.El
+.Pp
+The
+.Fn res_init
+routine
+reads the configuration file (if any; see
+.Xr resolver 5 )
+to get the default domain name,
+search list and
+the Internet address of the local name server(s).
+If no server is configured, the host running
+the resolver is tried.
+The current domain name is defined by the hostname
+if not specified in the configuration file;
+it can be overridden by the environment variable
+.Ev LOCALDOMAIN .
+This environment variable may contain several blank-separated
+tokens if you wish to override the
+.Em "search list"
+on a per-process basis.
+This is similar to the
+.Ic search
+command in the configuration file.
+Another environment variable
+.Dq Ev RES_OPTIONS
+can be set to
+override certain internal resolver options which are otherwise
+set by changing fields in the
+.Va _res
+structure or are inherited from the configuration file's
+.Ic options
+command.
+The syntax of the
+.Dq Ev RES_OPTIONS
+environment variable is explained in
+.Xr resolver 5 .
+Initialization normally occurs on the first call
+to one of the following routines.
+.Pp
+The
+.Fn res_query
+function provides an interface to the server query mechanism.
+It constructs a query, sends it to the local server,
+awaits a response, and makes preliminary checks on the reply.
+The query requests information of the specified
+.Fa type
+and
+.Fa class
+for the specified fully-qualified domain name
+.Fa dname .
+The reply message is left in the
+.Fa answer
+buffer with length
+.Fa anslen
+supplied by the caller.
+.Pp
+The
+.Fn res_search
+routine makes a query and awaits a response like
+.Fn res_query ,
+but in addition, it implements the default and search rules
+controlled by the
+.Dv RES_DEFNAMES
+and
+.Dv RES_DNSRCH
+options.
+It returns the first successful reply.
+.Pp
+The remaining routines are lower-level routines used by
+.Fn res_query .
+The
+.Fn res_mkquery
+function
+constructs a standard query message and places it in
+.Fa buf .
+It returns the size of the query, or \-1 if the query is
+larger than
+.Fa buflen .
+The query type
+.Fa op
+is usually
+.Dv QUERY ,
+but can be any of the query types defined in
+.In arpa/nameser.h .
+The domain name for the query is given by
+.Fa dname .
+The
+.Fa newrr_in
+argument
+is currently unused but is intended for making update messages.
+.Pp
+The
+.Fn res_send
+routine
+sends a pre-formatted query and returns an answer.
+It will call
+.Fn res_init
+if
+.Dv RES_INIT
+is not set, send the query to the local name server, and
+handle timeouts and retries.
+The length of the reply message is returned, or
+\-1 if there were errors.
+.Pp
+The
+.Fn dn_comp
+function
+compresses the domain name
+.Fa exp_dn
+and stores it in
+.Fa comp_dn .
+The size of the compressed name is returned or \-1 if there were errors.
+The size of the array pointed to by
+.Fa comp_dn
+is given by
+.Fa length .
+The compression uses
+an array of pointers
+.Fa dnptrs
+to previously-compressed names in the current message.
+The first pointer points to
+the beginning of the message and the list ends with
+.Dv NULL .
+The limit to the array is specified by
+.Fa lastdnptr .
+A side effect of
+.Fn dn_comp
+is to update the list of pointers for
+labels inserted into the message
+as the name is compressed.
+If
+.Fa dnptr
+is
+.Dv NULL ,
+names are not compressed.
+If
+.Fa lastdnptr
+is
+.Dv NULL ,
+the list of labels is not updated.
+.Pp
+The
+.Fn dn_expand
+entry
+expands the compressed domain name
+.Fa comp_dn
+to a full domain name
+The compressed name is contained in a query or reply message;
+.Fa msg
+is a pointer to the beginning of the message.
+The uncompressed name is placed in the buffer indicated by
+.Fa exp_dn
+which is of size
+.Fa length .
+The size of compressed name is returned or \-1 if there was an error.
+.Pp
+The
+.Fn dn_skipname
+function skips over a compressed domain name, which starts at a location
+pointed to by
+.Fa comp_dn .
+The compressed name is contained in a query or reply message;
+.Fa eom
+is a pointer to the end of the message.
+The size of compressed name is returned or \-1 if there was
+an error.
+.Pp
+The
+.Fn ns_get16
+function gets a 16-bit quantity from a buffer pointed to by
+.Fa src .
+.Pp
+The
+.Fn ns_get32
+function gets a 32-bit quantity from a buffer pointed to by
+.Fa src .
+.Pp
+The
+.Fn ns_put16
+function puts a 16-bit quantity
+.Fa src
+to a buffer pointed to by
+.Fa dst .
+.Pp
+The
+.Fn ns_put32
+function puts a 32-bit quantity
+.Fa src
+to a buffer pointed to by
+.Fa dst .
+.Sh IMPLEMENTATION NOTES
+This implementation of the resolver is thread-safe, but it will not
+function properly if the programmer attempts to declare his or her own
+.Va _res
+structure in an attempt to replace the per-thread version referred to
+by that macro.
+.Pp
+The following compile-time option can be specified to change the default
+behavior of resolver routines when necessary.
+.Bl -tag -width RES_ENFORCE_RFC1034
+.It Dv RES_ENFORCE_RFC1034
+If this symbol is defined during compile-time,
+.Fn res_search
+will enforce RFC 1034 check, namely, disallow using of underscore character
+within host names.
+This is used by the standard host lookup routines like
+.Xr gethostbyname 3 .
+For compatibility reasons this option is not enabled by default.
+.El
+.Sh RETURN VALUES
+The
+.Fn res_init
+function will return 0 on success, or \-1 in a threaded program if
+per-thread storage could not be allocated.
+.Pp
+The
+.Fn res_mkquery ,
+.Fn res_search ,
+and
+.Fn res_query
+functions return the size of the response on success, or \-1 if an
+error occurs.
+The integer
+.Vt h_errno
+may be checked to determine the reason for error.
+See
+.Xr gethostbyname 3
+for more information.
+.Sh FILES
+.Bl -tag -width /etc/resolv.conf
+.It Pa /etc/resolv.conf
+The configuration file,
+see
+.Xr resolver 5 .
+.El
+.Sh SEE ALSO
+.Xr gethostbyname 3 ,
+.Xr resolver 5 ,
+.Xr hostname 7 ,
+.Xr named 8
+.Pp
+.%T RFC1032 ,
+.%T RFC1033 ,
+.%T RFC1034 ,
+.%T RFC1035 ,
+.%T RFC974
+.Rs
+.%T "Name Server Operations Guide for BIND"
+.Re
+.Sh HISTORY
+The
+.Nm
+function appeared in
+.Bx 4.3 .
diff --git a/lib/libc/net/rthdr.c b/lib/libc/net/rthdr.c
new file mode 100644
index 000000000000..d91c98aa42b7
--- /dev/null
+++ b/lib/libc/net/rthdr.c
@@ -0,0 +1,434 @@
+/* $KAME: rthdr.c,v 1.19 2003/06/06 10:48:51 itojun Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <netinet/ip6.h>
+
+#include <string.h>
+#include <stdio.h>
+
+/*
+ * RFC2292 API
+ */
+
+size_t
+inet6_rthdr_space(int type, int seg)
+{
+ switch (type) {
+ case IPV6_RTHDR_TYPE_0:
+ if (seg < 1 || seg > 23)
+ return (0);
+#ifdef COMPAT_RFC2292
+ return (CMSG_SPACE(sizeof(struct in6_addr) * (seg - 1) +
+ sizeof(struct ip6_rthdr0)));
+#else
+ return (CMSG_SPACE(sizeof(struct in6_addr) * seg +
+ sizeof(struct ip6_rthdr0)));
+#endif
+ default:
+ return (0);
+ }
+}
+
+struct cmsghdr *
+inet6_rthdr_init(void *bp, int type)
+{
+ struct cmsghdr *ch = (struct cmsghdr *)bp;
+ struct ip6_rthdr *rthdr;
+
+ rthdr = (struct ip6_rthdr *)CMSG_DATA(ch);
+
+ ch->cmsg_level = IPPROTO_IPV6;
+ ch->cmsg_type = IPV6_RTHDR;
+
+ switch (type) {
+ case IPV6_RTHDR_TYPE_0:
+#ifdef COMPAT_RFC2292
+ ch->cmsg_len = CMSG_LEN(sizeof(struct ip6_rthdr0) -
+ sizeof(struct in6_addr));
+#else
+ ch->cmsg_len = CMSG_LEN(sizeof(struct ip6_rthdr0));
+#endif
+
+ bzero(rthdr, sizeof(struct ip6_rthdr0));
+ rthdr->ip6r_type = IPV6_RTHDR_TYPE_0;
+ return (ch);
+ default:
+ return (NULL);
+ }
+}
+
+/* ARGSUSED */
+int
+inet6_rthdr_add(struct cmsghdr *cmsg, const struct in6_addr *addr, u_int flags)
+{
+ struct ip6_rthdr *rthdr;
+
+ rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
+
+ switch (rthdr->ip6r_type) {
+ case IPV6_RTHDR_TYPE_0:
+ {
+ struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
+ if (flags != IPV6_RTHDR_LOOSE && flags != IPV6_RTHDR_STRICT)
+ return (-1);
+ if (rt0->ip6r0_segleft == 23)
+ return (-1);
+
+#ifdef COMPAT_RFC1883 /* XXX */
+ if (flags == IPV6_RTHDR_STRICT) {
+ int c, b;
+ c = rt0->ip6r0_segleft / 8;
+ b = rt0->ip6r0_segleft % 8;
+ rt0->ip6r0_slmap[c] |= (1 << (7 - b));
+ }
+#else
+ if (flags != IPV6_RTHDR_LOOSE)
+ return (-1);
+#endif
+ rt0->ip6r0_segleft++;
+ bcopy(addr, (caddr_t)rt0 + ((rt0->ip6r0_len + 1) << 3),
+ sizeof(struct in6_addr));
+ rt0->ip6r0_len += sizeof(struct in6_addr) >> 3;
+ cmsg->cmsg_len = CMSG_LEN((rt0->ip6r0_len + 1) << 3);
+ break;
+ }
+ default:
+ return (-1);
+ }
+
+ return (0);
+}
+
+/* ARGSUSED */
+int
+inet6_rthdr_lasthop(struct cmsghdr *cmsg, unsigned int flags)
+{
+ struct ip6_rthdr *rthdr;
+
+ rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
+
+ switch (rthdr->ip6r_type) {
+ case IPV6_RTHDR_TYPE_0:
+ {
+ struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
+#ifdef COMPAT_RFC1883 /* XXX */
+ if (flags != IPV6_RTHDR_LOOSE && flags != IPV6_RTHDR_STRICT)
+ return (-1);
+#endif /* COMPAT_RFC1883 */
+ if (rt0->ip6r0_segleft > 23)
+ return (-1);
+#ifdef COMPAT_RFC1883 /* XXX */
+ if (flags == IPV6_RTHDR_STRICT) {
+ int c, b;
+ c = rt0->ip6r0_segleft / 8;
+ b = rt0->ip6r0_segleft % 8;
+ rt0->ip6r0_slmap[c] |= (1 << (7 - b));
+ }
+#else
+ if (flags != IPV6_RTHDR_LOOSE)
+ return (-1);
+#endif /* COMPAT_RFC1883 */
+ break;
+ }
+ default:
+ return (-1);
+ }
+
+ return (0);
+}
+
+#if 0
+int
+inet6_rthdr_reverse(const struct cmsghdr *in, struct cmsghdr *out)
+{
+
+ return (-1);
+}
+#endif
+
+int
+inet6_rthdr_segments(const struct cmsghdr *cmsg)
+{
+ struct ip6_rthdr *rthdr;
+
+ rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
+
+ switch (rthdr->ip6r_type) {
+ case IPV6_RTHDR_TYPE_0:
+ {
+ struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
+
+ if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len)
+ return (-1);
+
+ return (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
+ }
+
+ default:
+ return (-1);
+ }
+}
+
+struct in6_addr *
+inet6_rthdr_getaddr(struct cmsghdr *cmsg, int idx)
+{
+ struct ip6_rthdr *rthdr;
+
+ rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
+
+ switch (rthdr->ip6r_type) {
+ case IPV6_RTHDR_TYPE_0:
+ {
+ struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
+ int naddr;
+
+ if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len)
+ return NULL;
+ naddr = (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
+ if (idx <= 0 || naddr < idx)
+ return NULL;
+#ifdef COMPAT_RFC2292
+ return (((struct in6_addr *)(rt0 + 1)) + idx - 1);
+#else
+ return (((struct in6_addr *)(rt0 + 1)) + idx);
+#endif
+ }
+
+ default:
+ return NULL;
+ }
+}
+
+int
+inet6_rthdr_getflags(const struct cmsghdr *cmsg, int idx)
+{
+ struct ip6_rthdr *rthdr;
+
+ rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
+
+ switch (rthdr->ip6r_type) {
+ case IPV6_RTHDR_TYPE_0:
+ {
+ struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
+ int naddr;
+
+ if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len)
+ return (-1);
+ naddr = (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
+ if (idx < 0 || naddr < idx)
+ return (-1);
+#ifdef COMPAT_RFC1883 /* XXX */
+ if (rt0->ip6r0_slmap[idx / 8] & (0x80 >> (idx % 8)))
+ return IPV6_RTHDR_STRICT;
+ else
+ return IPV6_RTHDR_LOOSE;
+#else
+ return IPV6_RTHDR_LOOSE;
+#endif /* COMPAT_RFC1883 */
+ }
+
+ default:
+ return (-1);
+ }
+}
+
+/*
+ * RFC3542 API
+ */
+
+socklen_t
+inet6_rth_space(int type, int segments)
+{
+ switch (type) {
+ case IPV6_RTHDR_TYPE_0:
+ if ((segments >= 0) && (segments <= 127))
+ return (((segments * 2) + 1) << 3);
+ /* FALLTHROUGH */
+ default:
+ return (0); /* type not suppported */
+ }
+}
+
+void *
+inet6_rth_init(void *bp, socklen_t bp_len, int type, int segments)
+{
+ struct ip6_rthdr *rth = (struct ip6_rthdr *)bp;
+ struct ip6_rthdr0 *rth0;
+
+ switch (type) {
+ case IPV6_RTHDR_TYPE_0:
+ /* length validation */
+ if (bp_len < inet6_rth_space(IPV6_RTHDR_TYPE_0, segments))
+ return (NULL);
+ /* segment validation */
+ if ((segments < 0) || (segments > 127))
+ return (NULL);
+
+ memset(bp, 0, bp_len);
+ rth0 = (struct ip6_rthdr0 *)rth;
+ rth0->ip6r0_len = segments * 2;
+ rth0->ip6r0_type = IPV6_RTHDR_TYPE_0;
+ rth0->ip6r0_segleft = 0;
+ rth0->ip6r0_reserved = 0;
+ break;
+ default:
+ return (NULL); /* type not supported */
+ }
+
+ return (bp);
+}
+
+int
+inet6_rth_add(void *bp, const struct in6_addr *addr)
+{
+ struct ip6_rthdr *rth = (struct ip6_rthdr *)bp;
+ struct ip6_rthdr0 *rth0;
+ struct in6_addr *nextaddr;
+
+ switch (rth->ip6r_type) {
+ case IPV6_RTHDR_TYPE_0:
+ rth0 = (struct ip6_rthdr0 *)rth;
+ /* Don't exceed the number of stated segments */
+ if (rth0->ip6r0_segleft == (rth0->ip6r0_len / 2))
+ return (-1);
+ nextaddr = (struct in6_addr *)(rth0 + 1) + rth0->ip6r0_segleft;
+ *nextaddr = *addr;
+ rth0->ip6r0_segleft++;
+ break;
+ default:
+ return (-1); /* type not supported */
+ }
+
+ return (0);
+}
+
+int
+inet6_rth_reverse(const void *in, void *out)
+{
+ struct ip6_rthdr *rth_in = (struct ip6_rthdr *)in;
+ struct ip6_rthdr0 *rth0_in, *rth0_out;
+ int i, segments;
+
+ switch (rth_in->ip6r_type) {
+ case IPV6_RTHDR_TYPE_0:
+ rth0_in = (struct ip6_rthdr0 *)in;
+ rth0_out = (struct ip6_rthdr0 *)out;
+
+ /* parameter validation XXX too paranoid? */
+ if (rth0_in->ip6r0_len % 2)
+ return (-1);
+ segments = rth0_in->ip6r0_len / 2;
+
+ /* we can't use memcpy here, since in and out may overlap */
+ memmove((void *)rth0_out, (void *)rth0_in,
+ ((rth0_in->ip6r0_len) + 1) << 3);
+ rth0_out->ip6r0_segleft = segments;
+
+ /* reverse the addresses */
+ for (i = 0; i < segments / 2; i++) {
+ struct in6_addr addr_tmp, *addr1, *addr2;
+
+ addr1 = (struct in6_addr *)(rth0_out + 1) + i;
+ addr2 = (struct in6_addr *)(rth0_out + 1) +
+ (segments - i - 1);
+ addr_tmp = *addr1;
+ *addr1 = *addr2;
+ *addr2 = addr_tmp;
+ }
+
+ break;
+ default:
+ return (-1); /* type not supported */
+ }
+
+ return (0);
+}
+
+int
+inet6_rth_segments(const void *bp)
+{
+ struct ip6_rthdr *rh = (struct ip6_rthdr *)bp;
+ struct ip6_rthdr0 *rh0;
+ int addrs;
+
+ switch (rh->ip6r_type) {
+ case IPV6_RTHDR_TYPE_0:
+ rh0 = (struct ip6_rthdr0 *)bp;
+
+ /*
+ * Validation for a type-0 routing header.
+ * Is this too strict?
+ */
+ if ((rh0->ip6r0_len % 2) != 0 ||
+ (addrs = (rh0->ip6r0_len >> 1)) < rh0->ip6r0_segleft)
+ return (-1);
+
+ return (addrs);
+ default:
+ return (-1); /* unknown type */
+ }
+}
+
+struct in6_addr *
+inet6_rth_getaddr(const void *bp, int idx)
+{
+ struct ip6_rthdr *rh = (struct ip6_rthdr *)bp;
+ struct ip6_rthdr0 *rh0;
+ int addrs;
+
+ switch (rh->ip6r_type) {
+ case IPV6_RTHDR_TYPE_0:
+ rh0 = (struct ip6_rthdr0 *)bp;
+
+ /*
+ * Validation for a type-0 routing header.
+ * Is this too strict?
+ */
+ if ((rh0->ip6r0_len % 2) != 0 ||
+ (addrs = (rh0->ip6r0_len >> 1)) < rh0->ip6r0_segleft)
+ return (NULL);
+
+ if (idx < 0 || addrs <= idx)
+ return (NULL);
+
+ return (((struct in6_addr *)(rh0 + 1)) + idx);
+ default:
+ return (NULL); /* unknown type */
+ break;
+ }
+}
diff --git a/lib/libc/net/sctp_bindx.3 b/lib/libc/net/sctp_bindx.3
new file mode 100644
index 000000000000..96d63cda39cc
--- /dev/null
+++ b/lib/libc/net/sctp_bindx.3
@@ -0,0 +1,110 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" From: @(#)send.2 8.2 (Berkeley) 2/21/94
+.\" $FreeBSD$
+.\"
+.Dd June 14, 2015
+.Dt SCTP_BINDX 3
+.Os
+.Sh NAME
+.Nm sctp_bindx
+.Nd bind or unbind an SCTP socket to a list of addresses.
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/socket.h
+.In netinet/sctp.h
+.Ft int
+.Fn sctp_bindx "int s" "struct sockaddr *addrs" "int num" "int type"
+.Sh DESCRIPTION
+The
+.Fn sctp_bindx
+call binds or unbinds a address or a list of addresses to an
+SCTP endpoint.
+This allows a user to bind a subset of
+addresses.
+The
+.Fn sctp_bindx
+call operates similarly to
+.Fn bind
+but allows a list of addresses and also allows a bind or an
+unbind.
+The argument
+.Fa s
+must be a valid SCTP socket descriptor.
+The argument
+.Fa addrs
+is a list of addresses (where the list may be only 1 in
+length) that the user wishes to bind or unbind to the
+socket.
+The argument
+.Fa type
+must be one of the following values.
+.Pp
+.Dv SCTP_BINDX_ADD_ADDR
+This value indicates that the listed address(es) need to
+be added to the endpoint.
+.Pp
+.Dv SCTP_BINDX_REM_ADDR
+This value indicates that the listed address(es) need to
+be removed from the endpoint.
+.Pp
+Note that when a user adds or deletes an address to an
+association if the dynamic address flag
+.Va net.inet.sctp.auto_asconf
+is enabled any associations in the endpoint will attempt to
+have the address(es) added dynamically to the existing
+association.
+.Sh RETURN VALUES
+The call returns 0 on success and -1 upon failure.
+.Sh ERRORS
+The
+.Fn sctp_bindx
+function can return the following errors:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+This value is returned if the
+.Fa type
+field is not one of the allowed values (see above).
+.It Bq Er ENOMEM
+This value is returned if the number of addresses
+being added causes a memory allocation failure in
+the call.
+.It Bq Er EBADF
+The argument
+.Fa s
+is not a valid descriptor.
+.It Bq Er ENOTSOCK
+The argument
+.Fa s
+is not a socket.
+.El
+.Sh SEE ALSO
+.Xr bind 2 ,
+.Xr sctp 4
diff --git a/lib/libc/net/sctp_connectx.3 b/lib/libc/net/sctp_connectx.3
new file mode 100644
index 000000000000..0c298e1ea00a
--- /dev/null
+++ b/lib/libc/net/sctp_connectx.3
@@ -0,0 +1,102 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd June 19, 2007
+.Dt SCTP_CONNECTX 3
+.Os
+.Sh NAME
+.Nm sctp_connectx
+.Nd connect an SCTP socket with multiple destination addresses
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/socket.h
+.In netinet/sctp.h
+.Ft int
+.Fn sctp_connectx "int sd" "struct sockaddr *addrs" "int addrcnt" "sctp_assoc_t *id"
+.Sh DESCRIPTION
+The
+.Fn sctp_connectx
+call attempts to initiate an association to a peer SCTP
+endpoint.
+The call operates similarly to
+.Fn connect
+but it also provides the ability to specify multiple destination
+addresses for the peer.
+This allows a fault tolerant method
+of initiating an association.
+When one of the peers addresses
+is unreachable, the subsequent listed addresses will also be used
+to set up the association with the peer.
+.Pp
+The user also needs to consider that any address listed in an
+.Fn sctp_connectx
+call is also considered "confirmed".
+A confirmed address is one in
+which the SCTP transport will trust is a part of the association
+and it will not send a confirmation heartbeat to it with
+a random nonce.
+.Pp
+If the peer SCTP stack does not list one or more of
+the provided addresses in its response message then
+the extra addresses sent in the
+.Fn sctp_connectx
+call will be silently discarded from the association.
+On
+successful completion the provided
+.Fa id
+will be
+filled in with the association identification of the newly
+forming association.
+.Sh RETURN VALUES
+The call returns 0 on success and -1 upon failure.
+.Sh ERRORS
+The
+.Fn sctp_connectx
+function can return the following errors:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+An address listed has an invalid family or no
+addresses were provided.
+.It Bq Er E2BIG
+The size of the address list exceeds the amount of
+data provided.
+.It Bq Er EBADF
+The argument
+.Fa s
+is not a valid descriptor.
+.It Bq Er ENOTSOCK
+The argument
+.Fa s
+is not a socket.
+.El
+.Sh SEE ALSO
+.Xr connect 2 ,
+.Xr sctp 4
diff --git a/lib/libc/net/sctp_freepaddrs.3 b/lib/libc/net/sctp_freepaddrs.3
new file mode 100644
index 000000000000..400f21d8d808
--- /dev/null
+++ b/lib/libc/net/sctp_freepaddrs.3
@@ -0,0 +1,64 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" From: @(#)send.2 8.2 (Berkeley) 2/21/94
+.\" $FreeBSD$
+.\"
+.Dd December 15, 2006
+.Dt SCTP_FREEPADDRS 3
+.Os
+.Sh NAME
+.Nm sctp_freepaddrs ,
+.Nm sctp_freeladdrs
+.Nd release the memory returned from a previous call
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/socket.h
+.In netinet/sctp.h
+.Ft void
+.Fn sctp_freepaddrs "struct sockaddr *"
+.Ft void
+.Fn sctp_freeladdrs "struct sockaddr *"
+.Sh DESCRIPTION
+The
+.Fn sctp_freepaddrs
+and
+.Fn sctp_freeladdrs
+functions are used to release the memory allocated by previous
+calls to
+.Fn sctp_getpaddrs
+or
+.Fn sctp_getladdrs
+respectively.
+.Sh RETURN VALUES
+none.
+.Sh SEE ALSO
+.Xr sctp_getladdrs 3 ,
+.Xr sctp_getpaddrs 3 ,
+.Xr sctp 4
diff --git a/lib/libc/net/sctp_getaddrlen.3 b/lib/libc/net/sctp_getaddrlen.3
new file mode 100644
index 000000000000..70e3688c74d6
--- /dev/null
+++ b/lib/libc/net/sctp_getaddrlen.3
@@ -0,0 +1,83 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" From: @(#)send.2 8.2 (Berkeley) 2/21/94
+.\" $FreeBSD$
+.\"
+.Dd December 15, 2006
+.Dt SCTP_GETADDRLEN 3
+.Os
+.Sh NAME
+.Nm sctp_getaddrlen
+.Nd return the address length of an address family
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/socket.h
+.In netinet/sctp.h
+.Ft int
+.Fn sctp_getaddrlen "sa_family_t family"
+.Sh DESCRIPTION
+The
+.Fn sctp_getaddrlen
+function returns the size of a specific address family.
+This function
+is provided for application binary compatibility since it
+provides the application with the size the operating system
+thinks the specific address family is.
+Note that the function
+will actually create an SCTP socket and then gather the
+information via a
+.Fn getsockopt
+system calls.
+If for some reason a SCTP socket cannot
+be created or the
+.Fn getsockopt
+call fails, an error will be returned
+with
+.Va errno
+set as specified in the
+.Fn socket
+or
+.Fn getsockopt
+system call.
+.Sh RETURN VALUES
+The call returns the number of bytes that the operating
+system expects for the specific address family or -1.
+.Sh ERRORS
+The
+.Fn sctp_getaddrlen
+function can return the following errors:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The address family specified does NOT exist.
+.El
+.Sh SEE ALSO
+.Xr getsockopt 2 ,
+.Xr socket 2 ,
+.Xr sctp 4
diff --git a/lib/libc/net/sctp_getassocid.3 b/lib/libc/net/sctp_getassocid.3
new file mode 100644
index 000000000000..3c89fdc0c057
--- /dev/null
+++ b/lib/libc/net/sctp_getassocid.3
@@ -0,0 +1,70 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd December 15, 2006
+.Dt SCTP_GETASSOCID 3
+.Os
+.Sh NAME
+.Nm sctp_getassocid
+.Nd return an association id for a specified socket address.
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/socket.h
+.In netinet/sctp.h
+.Ft sctp_assoc_t
+.Fn sctp_getassocid "int s" "struct sockaddr *addr"
+.Sh DESCRIPTION
+The
+.Fn sctp_getassocid
+call attempts to look up the specified socket address
+.Fa addr
+and find the respective association identification.
+.Sh RETURN VALUES
+The call returns the association id upon success and
+0 is returned upon failure.
+.Sh ERRORS
+The
+.Fn sctp_getassocid
+function can return the following errors:
+.Bl -tag -width Er
+.It Bq Er ENOENT
+The address does not have an association setup to it.
+.It Bq Er EBADF
+The argument
+.Fa s
+is not a valid descriptor.
+.It Bq Er ENOTSOCK
+The argument
+.Fa s
+is not a socket.
+.El
+.Sh SEE ALSO
+.Xr sctp 4
diff --git a/lib/libc/net/sctp_getpaddrs.3 b/lib/libc/net/sctp_getpaddrs.3
new file mode 100644
index 000000000000..0c7b8ecb5051
--- /dev/null
+++ b/lib/libc/net/sctp_getpaddrs.3
@@ -0,0 +1,96 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" From: @(#)send.2 8.2 (Berkeley) 2/21/94
+.\" $FreeBSD$
+.\"
+.Dd December 15, 2006
+.Dt SCTP_GETPADDRS 3
+.Os
+.Sh NAME
+.Nm sctp_getpaddrs ,
+.Nm sctp_getladdrs
+.Nd return a list of addresses to the caller
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/socket.h
+.In netinet/sctp.h
+.Ft int
+.Fn sctp_getpaddrs "int s" "sctp_assoc_t asocid" "struct sockaddr **addrs"
+.Ft int
+.Fn sctp_getladdrs "int s" "sctp_assoc_t asocid" "struct sockaddr **addrs"
+.Sh DESCRIPTION
+The
+.Fn sctp_getpaddrs
+function is used to get the list of the peers addresses.
+The
+.Fn sctp_getladdrs
+function is used to get the list of the local addresses.
+The association of interest is identified by the
+.Fa asocid
+argument.
+The addresses are returned in a newly allocated
+array of socket addresses returned in the argument
+.Fa addrs
+upon success.
+.Pp
+After the caller is finished, the function
+.Fn sctp_freepaddrs
+or
+.Fn sctp_freeladdrs
+should be used to release the memory allocated by these
+calls.
+.Sh RETURN VALUES
+The call returns -1 upon failure and a count of
+the number of addresses returned in
+.Fa addrs
+upon success.
+.Sh ERRORS
+The functions can return the following errors:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+An address listed has an invalid family or no
+addresses were provided.
+.It Bq Er ENOMEM
+The call cannot allocate memory to hold the
+socket addresses.
+.It Bq Er EBADF
+The argument
+.Fa s
+is not a valid descriptor.
+.It Bq Er ENOTSOCK
+The argument
+.Fa s
+is not a socket.
+.El
+.Sh SEE ALSO
+.Xr getsockopt 2 ,
+.Xr sctp_freeladdrs 3 ,
+.Xr sctp_freepaddrs 3 ,
+.Xr sctp 4
diff --git a/lib/libc/net/sctp_opt_info.3 b/lib/libc/net/sctp_opt_info.3
new file mode 100644
index 000000000000..170692cfd3fc
--- /dev/null
+++ b/lib/libc/net/sctp_opt_info.3
@@ -0,0 +1,140 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" From: @(#)send.2 8.2 (Berkeley) 2/21/94
+.\" $FreeBSD$
+.\"
+.Dd June 18, 2011
+.Dt SCTP_OPT_INFO 3
+.Os
+.Sh NAME
+.Nm sctp_opt_info
+.Nd get SCTP socket information
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/socket.h
+.In netinet/sctp.h
+.Ft int
+.Fn sctp_opt_info "int sd" "sctp_assoc_t id" "int opt" "void *arg" "socklen_t *size"
+.Sh DESCRIPTION
+The
+.Fn sctp_opt_info
+call provides a multi-os compatible method for getting
+specific
+.Fn getsockopt
+data where an association identification needs to be passed
+into the operating system.
+For
+.Fx
+a direct
+.Fn getsockopt
+may be used, since
+.Fx
+has the ability to pass information
+into the operating system on a
+.Fn getsockopt
+call.
+Other operating systems may not have this ability.
+For those
+who wish to write portable code amongst multiple operating systems
+this call should be used for the following SCTP
+socket options.
+.Pp
+.Dv SCTP_RTOINFO
+.Pp
+.Dv SCTP_ASSOCINFO
+.Pp
+.Dv SCTP_PRIMARY_ADDR
+.Pp
+.Dv SCTP_PEER_ADDR_PARAMS
+.Pp
+.Dv SCTP_DEFAULT_SEND_PARAM
+.Pp
+.Dv SCTP_MAX_SEG
+.Pp
+.Dv SCTP_AUTH_ACTIVE_KEY
+.Pp
+.Dv SCTP_DELAYED_SACK
+.Pp
+.Dv SCTP_MAX_BURST
+.Pp
+.Dv SCTP_CONTEXT
+.Pp
+.Dv SCTP_EVENT
+.Pp
+.Dv SCTP_DEFAULT_SNDINFO
+.Pp
+.Dv SCTP_DEFAULT_PRINFO
+.Pp
+.Dv SCTP_STATUS
+.Pp
+.Dv SCTP_GET_PEER_ADDR_INFO
+.Pp
+.Dv SCTP_PEER_AUTH_CHUNKS
+.Pp
+.Dv SCTP_LOCAL_AUTH_CHUNKS
+.Sh RETURN VALUES
+The call returns 0 on success and -1 upon error.
+.Sh ERRORS
+The
+.Fn sctp_opt_info
+function can return the following errors:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The argument
+.Fa arg
+value was invalid.
+.It Bq Er EOPNOTSUPP
+The argument
+.Fa opt
+was not one of the above listed SCTP socket
+options.
+.It Bq Er EBADF
+The argument
+.Fa s
+is not a valid descriptor.
+.It Bq Er ENOTSOCK
+The argument
+.Fa s
+is not a socket.
+.El
+.Sh SEE ALSO
+.Xr getsockopt 2 ,
+.Xr sctp 4
+.Sh BUGS
+Because the structure used for
+.Fa arg
+of the
+.Dv SCTP_MAX_BURST
+socket option has changed in FreeBSD 9.0 and higher,
+using
+.Dv SCTP_MAX_BURST
+as
+.Fa opt
+is only supported in FreeBSD 9.0 and higher.
diff --git a/lib/libc/net/sctp_recvmsg.3 b/lib/libc/net/sctp_recvmsg.3
new file mode 100644
index 000000000000..a8b073418657
--- /dev/null
+++ b/lib/libc/net/sctp_recvmsg.3
@@ -0,0 +1,294 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd April 23, 2015
+.Dt SCTP_RECVMSG 3
+.Os
+.Sh NAME
+.Nm sctp_recvmsg
+.Nd receive a message from an SCTP socket
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/socket.h
+.In netinet/sctp.h
+.Ft ssize_t
+.Fo sctp_recvmsg
+.Fa "int s" "void *msg" "size_t len" "struct sockaddr * restrict from"
+.Fa "socklen_t * restrict fromlen" "struct sctp_sndrcvinfo *sinfo" "int *flags"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn sctp_recvmsg
+system call
+is used to receive a message from another SCTP endpoint.
+The
+.Fn sctp_recvmsg
+call is used by one-to-one (SOCK_STREAM) type sockets after a
+successful
+.Fn connect
+call or after the application has performed a
+.Fn listen
+followed by a successful
+.Fn accept .
+For a one-to-many (SOCK_SEQPACKET) type socket, an endpoint may call
+.Fn sctp_recvmsg
+after having implicitly started an association via one
+of the send calls including
+.Fn sctp_sendmsg ,
+.Fn sendto
+and
+.Fn sendmsg .
+Or, an application may also receive a message after having
+called
+.Fn listen
+with a positive backlog to enable the reception of new associations.
+.Pp
+The address of the sender is held in the
+.Fa from
+argument with
+.Fa fromlen
+specifying its size.
+At the completion of a successful
+.Fn sctp_recvmsg
+call
+.Fa from
+will hold the address of the peer and
+.Fa fromlen
+will hold the length of that address.
+Note that
+the address is bounded by the initial value of
+.Fa fromlen
+which is used as an in/out variable.
+.Pp
+The length of the message
+.Fa msg
+to be received is bounded by
+.Fa len .
+If the message is too long to fit in the users
+receive buffer, then the
+.Fa flags
+argument will
+.Em not
+have the
+.Dv MSG_EOR
+flag applied.
+If the message is a complete message then
+the
+.Fa flags
+argument will have
+.Dv MSG_EOR
+set.
+Locally detected errors are
+indicated by a return value of -1 with
+.Va errno
+set accordingly.
+The
+.Fa flags
+argument may also hold the value
+.Dv MSG_NOTIFICATION .
+When this
+occurs it indicates that the message received is
+.Em not
+from
+the peer endpoint, but instead is a notification from the
+SCTP stack (see
+.Xr sctp 4
+for more details).
+Note that no notifications are ever
+given unless the user subscribes to such notifications using
+the
+.Dv SCTP_EVENTS
+socket option.
+.Pp
+If no messages are available at the socket then
+.Fn sctp_recvmsg
+normally blocks on the reception of a message or NOTIFICATION, unless the
+socket has been placed in non-blocking I/O mode.
+The
+.Xr select 2
+system call may be used to determine when it is possible to
+receive a message.
+.Pp
+The
+.Fa sinfo
+argument is defined as follows.
+.Bd -literal
+struct sctp_sndrcvinfo {
+ uint16_t sinfo_stream; /* Stream arriving on */
+ uint16_t sinfo_ssn; /* Stream Sequence Number */
+ uint16_t sinfo_flags; /* Flags on the incoming message */
+ uint32_t sinfo_ppid; /* The ppid field */
+ uint32_t sinfo_context; /* context field */
+ uint32_t sinfo_timetolive; /* not used by sctp_recvmsg */
+ uint32_t sinfo_tsn; /* The transport sequence number */
+ uint32_t sinfo_cumtsn; /* The cumulative acknowledgment point */
+ sctp_assoc_t sinfo_assoc_id; /* The association id of the peer */
+};
+.Ed
+.Pp
+The
+.Fa sinfo->sinfo_ppid
+field is an opaque 32 bit value that is passed transparently
+through the stack from the peer endpoint.
+Note that the stack passes this value without regard to byte
+order.
+.Pp
+The
+.Fa sinfo->sinfo_flags
+field may include the following:
+.Bd -literal
+#define SCTP_UNORDERED 0x0400 /* Message is un-ordered */
+.Ed
+.Pp
+The
+.Dv SCTP_UNORDERED
+flag is used to specify that the message arrived with no
+specific order and was delivered to the peer application
+as soon as possible.
+When this flag is absent the message
+was delivered in order within the stream it was received.
+.Pp
+The
+.Fa sinfo->sinfo_stream
+field is the SCTP stream that the message was received on.
+Streams in SCTP are reliable (or partially reliable) flows of ordered
+messages.
+.Pp
+The
+.Fa sinfo->sinfo_context
+field is used only if the local application set an association level
+context with the
+.Dv SCTP_CONTEXT
+socket option.
+Optionally a user process can use this value to index some application
+specific data structure for all data coming from a specific
+association.
+.Pp
+The
+.Fa sinfo->sinfo_ssn
+field will hold the stream sequence number assigned
+by the peer endpoint if the message is
+.Em not
+unordered.
+For unordered messages this field holds an undefined value.
+.Pp
+The
+.Fa sinfo->sinfo_tsn
+field holds a transport sequence number (TSN) that was assigned
+to this message by the peer endpoint.
+For messages that fit in or less
+than the path MTU this will be the only TSN assigned.
+Note that for messages that span multiple TSNs this
+value will be one of the TSNs that was used on the
+message.
+.Pp
+The
+.Fa sinfo->sinfo_cumtsn
+field holds the current cumulative acknowledgment point of
+the transport association.
+Note that this may be larger
+or smaller than the TSN assigned to the message itself.
+.Pp
+The
+.Fa sinfo->sinfo_assoc_id
+is the unique association identification that was assigned
+to the association.
+For one-to-many (SOCK_SEQPACKET) type
+sockets this value can be used to send data to the peer without
+the use of an address field.
+It is also quite useful in
+setting various socket options on the specific association
+(see
+.Xr sctp 4 ) .
+.Pp
+The
+.Fa sinfo->info_timetolive
+field is not used by
+.Fn sctp_recvmsg .
+.Sh RETURN VALUES
+The call returns the number of bytes received, or -1
+if an error occurred.
+.Sh ERRORS
+The
+.Fn sctp_recvmsg
+system call
+fails if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+An invalid descriptor was specified.
+.It Bq Er ENOTSOCK
+The argument
+.Fa s
+is not a socket.
+.It Bq Er EFAULT
+An invalid user space address was specified for an argument.
+.It Bq Er EMSGSIZE
+The socket requires that message be sent atomically,
+and the size of the message to be sent made this impossible.
+.It Bq Er EAGAIN
+The socket is marked non-blocking and the requested operation
+would block.
+.It Bq Er ENOBUFS
+The system was unable to allocate an internal buffer.
+The operation may succeed when buffers become available.
+.It Bq Er ENOBUFS
+The output queue for a network interface was full.
+This generally indicates that the interface has stopped sending,
+but may be caused by transient congestion.
+.It Bq Er EHOSTUNREACH
+The remote host was unreachable.
+.It Bq Er ENOTCONN
+On a one-to-one style socket no association exists.
+.It Bq Er ECONNRESET
+An abort was received by the stack while the user was
+attempting to send data to the peer.
+.It Bq Er ENOENT
+On a one to many style socket no address is specified
+so that the association cannot be located or the
+SCTP_ABORT flag was specified on a non-existing association.
+.It Bq Er EPIPE
+The socket is unable to send anymore data
+.Dv ( SBS_CANTSENDMORE
+has been set on the socket).
+This typically means that the socket
+is not connected and is a one-to-one style socket.
+.El
+.Sh SEE ALSO
+.Xr getsockopt 2 ,
+.Xr recv 2 ,
+.Xr select 2 ,
+.Xr sendmsg 2 ,
+.Xr setsockopt 2 ,
+.Xr socket 2 ,
+.Xr write 2 ,
+.Xr sctp_send 3 ,
+.Xr sctp_sendmsg 3 ,
+.Xr sctp 4
diff --git a/lib/libc/net/sctp_send.3 b/lib/libc/net/sctp_send.3
new file mode 100644
index 000000000000..9c7f833918ba
--- /dev/null
+++ b/lib/libc/net/sctp_send.3
@@ -0,0 +1,350 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd December 15, 2006
+.Dt SCTP_SEND 3
+.Os
+.Sh NAME
+.Nm sctp_send ,
+.Nm sctp_sendx
+.Nd send a message from an SCTP socket
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/socket.h
+.In netinet/sctp.h
+.Ft ssize_t
+.Fo sctp_send
+.Fa "int sd" "const void *msg" "size_t len"
+.Fa "const struct sctp_sndrcvinfo *sinfo" "int flags"
+.Fc
+.Ft ssize_t
+.Fo sctp_sendx
+.Fa "int sd" "const void *msg" "size_t len" "struct sockaddr *addrs"
+.Fa "int addrcnt" "const struct sctp_sndrcvinfo *sinfo" "int flags"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn sctp_send
+system call
+is used to transmit a message to another SCTP endpoint.
+.Fn sctp_send
+may be used to send data to an existing association for both
+one-to-many (SOCK_SEQPACKET) and one-to-one (SOCK_STREAM) socket types.
+The length of the message
+.Fa msg
+is given by
+.Fa len .
+If the message is too long to pass atomically through the
+underlying protocol,
+.Va errno
+is set to
+.Er EMSGSIZE ,
+-1 is returned, and
+the message is not transmitted.
+.Pp
+No indication of failure to deliver is implicit in a
+.Fn sctp_send .
+Locally detected errors are indicated by a return value of -1.
+.Pp
+If no space is available at the socket to hold
+the message to be transmitted, then
+.Fn sctp_send
+normally blocks, unless the socket has been placed in
+non-blocking I/O mode.
+The
+.Xr select 2
+system call may be used to determine when it is possible to
+send more data on one-to-one type (SOCK_STREAM) sockets.
+.Pp
+The
+.Fa sinfo
+structure is used to control various SCTP features
+and has the following format:
+.Bd -literal
+struct sctp_sndrcvinfo {
+ uint16_t sinfo_stream; /* Stream sending to */
+ uint16_t sinfo_ssn; /* valid for recv only */
+ uint16_t sinfo_flags; /* flags to control sending */
+ uint32_t sinfo_ppid; /* ppid field */
+ uint32_t sinfo_context; /* context field */
+ uint32_t sinfo_timetolive; /* timetolive for PR-SCTP */
+ uint32_t sinfo_tsn; /* valid for recv only */
+ uint32_t sinfo_cumtsn; /* valid for recv only */
+ sctp_assoc_t sinfo_assoc_id; /* The association id */
+};
+.Ed
+.Pp
+The
+.Fa sinfo->sinfo_ppid
+argument is an opaque 32 bit value that is passed transparently
+through the stack to the peer endpoint. It will be available on
+reception of a message (see
+.Xr sctp_recvmsg 3 ) .
+Note that the stack passes this value without regard to byte
+order.
+.Pp
+The
+.Fa sinfo->sinfo_flags
+argument may include one or more of the following:
+.Bd -literal
+#define SCTP_EOF 0x0100 /* Start a shutdown procedures */
+#define SCTP_ABORT 0x0200 /* Send an ABORT to peer */
+#define SCTP_UNORDERED 0x0400 /* Message is un-ordered */
+#define SCTP_ADDR_OVER 0x0800 /* Override the primary-address */
+#define SCTP_SENDALL 0x1000 /* Send this on all associations */
+ /* for the endpoint */
+/* The lower byte is an enumeration of PR-SCTP policies */
+#define SCTP_PR_SCTP_TTL 0x0001 /* Time based PR-SCTP */
+#define SCTP_PR_SCTP_BUF 0x0002 /* Buffer based PR-SCTP */
+#define SCTP_PR_SCTP_RTX 0x0003 /* Number of retransmissions based PR-SCTP */
+.Ed
+.Pp
+The flag
+.Dv SCTP_EOF
+is used to instruct the SCTP stack to queue this message
+and then start a graceful shutdown of the association.
+All
+remaining data in queue will be sent after which the association
+will be shut down.
+.Pp
+.Dv SCTP_ABORT
+is used to immediately terminate an association.
+An abort
+is sent to the peer and the local TCB is destroyed.
+.Pp
+.Dv SCTP_UNORDERED
+is used to specify that the message being sent has no
+specific order and should be delivered to the peer application
+as soon as possible.
+When this flag is absent messages
+are delivered in order within the stream they are sent, but without
+respect to order to peer streams.
+.Pp
+The flag
+.Dv SCTP_ADDR_OVER
+is used to specify that a specific address should be used.
+Normally
+SCTP will use only one of a multi-homed peers addresses as the primary
+address to send to.
+By default, no matter what the
+.Fa to
+argument is, this primary address is used to send data.
+By specifying
+this flag, the user is asking the stack to ignore the primary address
+and instead use the specified address not only as a lookup mechanism
+to find the association but also as the actual address to send to.
+.Pp
+For a one-to-many type (SOCK_SEQPACKET) socket the flag
+.Dv SCTP_SENDALL
+can be used as a convenient way to make one send call and have
+all associations that are under the socket get a copy of the message.
+Note that this mechanism is quite efficient and makes only one actual
+copy of the data which is shared by all the associations for sending.
+.Pp
+The remaining flags are used for the partial reliability extension (RFC3758)
+and will only be effective if the peer endpoint supports this extension.
+This option specifies what local policy the local endpoint should use
+in skipping data.
+If none of these options are set, then data is
+never skipped over.
+.Pp
+.Dv SCTP_PR_SCTP_TTL
+is used to indicate that a time based lifetime is being applied
+to the data.
+The
+.Fa sinfo->sinfo_timetolive
+argument is then a number of milliseconds for which the data is
+attempted to be transmitted.
+If that many milliseconds elapse
+and the peer has not acknowledged the data, the data will be
+skipped and no longer transmitted.
+Note that this policy does
+not even assure that the data will ever be sent.
+In times of a congestion
+with large amounts of data being queued, the
+.Fa sinfo->sinfo_timetolive
+may expire before the first transmission is ever made.
+.Pp
+The
+.Dv SCTP_PR_SCTP_BUF
+based policy transforms the
+.Fa sinfo->sinfo_timetolive
+field into a total number of bytes allowed on the outbound
+send queue.
+If that number or more bytes are in queue, then
+other buffer-based sends are looked to be removed and
+skipped.
+Note that this policy may also result in the data
+never being sent if no buffer based sends are in queue and
+the maximum specified by
+.Fa timetolive
+bytes is in queue.
+.Pp
+The
+.Dv SCTP_PR_SCTP_RTX
+policy transforms the
+.Fa sinfo->sinfo_timetolive
+into a number of retransmissions to allow.
+This policy
+always assures that at a minimum one send attempt is
+made of the data.
+After which no more than
+.Fa sinfo->sinfo_timetolive
+retransmissions will be made before the data is skipped.
+.Pp
+.Fa sinfo->sinfo_stream
+is the SCTP stream that you wish to send the
+message on.
+Streams in SCTP are reliable (or partially reliable) flows of ordered
+messages.
+.Pp
+The
+.Fa sinfo->sinfo_assoc_id
+field is used to
+select the association to send to on a one-to-many socket.
+For a one-to-one socket, this field is ignored.
+.Pp
+The
+.Fa sinfo->sinfo_context
+field is used only in the event the message cannot be sent.
+This is an opaque
+value that the stack retains and will give to the user when a failed send
+is given if that notification is enabled (see
+.Xr sctp 4 ) .
+Normally a user process can use this value to index some application
+specific data structure when a send cannot be fulfilled.
+.Pp
+The
+.Fa flags
+argument holds the same meaning and values as those found in
+.Xr sendmsg 2
+but is generally ignored by SCTP.
+.Pp
+The fields
+.Fa sinfo->sinfo_ssn ,
+.Fa sinfo->sinfo_tsn ,
+and
+.Fa sinfo->sinfo_cumtsn
+are used only when receiving messages and are thus ignored by
+.Fn sctp_send .
+The function
+.Fn sctp_sendx
+has the same properties as
+.Fn sctp_send
+with the additional arguments of an array of sockaddr structures
+passed in.
+With the
+.Fa addrs
+argument being given as an array of addresses to be sent to and
+the
+.Fa addrcnt
+argument indicating how many socket addresses are in the passed
+in array.
+Note that all of the addresses will only be used
+when an implicit association is being set up.
+This allows the
+user the equivalent behavior as doing a
+.Fn sctp_connectx
+followed by a
+.Fn sctp_send
+to the association.
+Note that if the
+.Fa sinfo->sinfo_assoc_id
+field is 0, then the first address will be used to look up
+the association in place of the association id.
+If both
+an address and an association id are specified, the association
+id has priority.
+.Sh RETURN VALUES
+The call returns the number of characters sent, or -1
+if an error occurred.
+.Sh ERRORS
+The
+.Fn sctp_send
+system call
+fails if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+An invalid descriptor was specified.
+.It Bq Er ENOTSOCK
+The argument
+.Fa s
+is not a socket.
+.It Bq Er EFAULT
+An invalid user space address was specified for an argument.
+.It Bq Er EMSGSIZE
+The socket requires that message be sent atomically,
+and the size of the message to be sent made this impossible.
+.It Bq Er EAGAIN
+The socket is marked non-blocking and the requested operation
+would block.
+.It Bq Er ENOBUFS
+The system was unable to allocate an internal buffer.
+The operation may succeed when buffers become available.
+.It Bq Er ENOBUFS
+The output queue for a network interface was full.
+This generally indicates that the interface has stopped sending,
+but may be caused by transient congestion.
+.It Bq Er EHOSTUNREACH
+The remote host was unreachable.
+.It Bq Er ENOTCONN
+On a one-to-one style socket no association exists.
+.It Bq Er ECONNRESET
+An abort was received by the stack while the user was
+attempting to send data to the peer.
+.It Bq Er ENOENT
+On a one-to-many style socket no address is specified
+so that the association cannot be located or the
+SCTP_ABORT flag was specified on a non-existing association.
+.It Bq Er EPIPE
+The socket is unable to send anymore data
+.Dv ( SBS_CANTSENDMORE
+has been set on the socket).
+This typically means that the socket
+is not connected and is a one-to-one style socket.
+.El
+.Sh SEE ALSO
+.Xr getsockopt 2 ,
+.Xr recv 2 ,
+.Xr select 2 ,
+.Xr sendmsg 2 ,
+.Xr socket 2 ,
+.Xr write 2 ,
+.Xr sctp_connectx 3 ,
+.Xr sctp_recvmsg 3 ,
+.Xr sctp_sendmsg 3 ,
+.Xr sctp 4
+.Sh BUGS
+Because
+.Fn sctp_send
+may have multiple associations under one endpoint, a
+select on write will only work for a one-to-one style
+socket.
diff --git a/lib/libc/net/sctp_sendmsg.3 b/lib/libc/net/sctp_sendmsg.3
new file mode 100644
index 000000000000..65f790ab8a3f
--- /dev/null
+++ b/lib/libc/net/sctp_sendmsg.3
@@ -0,0 +1,329 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" From: @(#)send.2 8.2 (Berkeley) 2/21/94
+.\" $FreeBSD$
+.\"
+.Dd December 15, 2006
+.Dt SCTP_SENDMSG 3
+.Os
+.Sh NAME
+.Nm sctp_sendmsg ,
+.Nm sctp_sendmsgx
+.Nd send a message from an SCTP socket
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/socket.h
+.In netinet/sctp.h
+.Ft ssize_t
+.Fo sctp_sendmsg
+.Fa "int s" "const void *msg" "size_t len" "const struct sockaddr *to"
+.Fa "socklen_t tolen" "uint32_t ppid" "uint32_t flags" "uint16_t stream_no"
+.Fa "uint32_t timetolive" "uint32_t context"
+.Fc
+.Ft ssize_t
+.Fo sctp_sendmsgx
+.Fa "int s" "const void *msg" "size_t len" "const struct sockaddr *to"
+.Fa "int addrcnt" "uint32_t ppid" "uint32_t flags" "uint16_t stream_no"
+.Fa "uint32_t timetolive" "uint32_t context"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn sctp_sendmsg
+system call
+is used to transmit a message to another SCTP endpoint.
+The
+.Fn sctp_sendmsg
+may be used at any time.
+If the socket is a one-to-many type (SOCK_SEQPACKET)
+socket then an attempt to send to an address that no association exists to will
+implicitly create a new association.
+Data sent in such an instance will result in
+the data being sent on the third leg of the SCTP four-way handshake.
+Note that if
+the socket is a one-to-one type (SOCK_STREAM) socket then an association must
+be in existence (by use of the
+.Xr connect 2
+system call).
+Calling
+.Fn sctp_sendmsg
+or
+.Fn sctp_sendmsgx
+on a non-connected one-to-one socket will result in
+.Va errno
+being set to
+.Er ENOTCONN ,
+-1 being returned, and the message not being transmitted.
+.Pp
+The address of the target is given by
+.Fa to
+with
+.Fa tolen
+specifying its size.
+The length of the message
+.Fa msg
+is given by
+.Fa len .
+If the message is too long to pass atomically through the
+underlying protocol,
+.Va errno
+is set to
+.Er EMSGSIZE ,
+-1 is returned, and
+the message is not transmitted.
+.Pp
+No indication of failure to deliver is implicit in a
+.Xr sctp_sendmsg 3
+call.
+Locally detected errors are indicated by a return value of -1.
+.Pp
+If no space is available at the socket to hold
+the message to be transmitted, then
+.Xr sctp_sendmsg 3
+normally blocks, unless the socket has been placed in
+non-blocking I/O mode.
+The
+.Xr select 2
+system call may be used to determine when it is possible to
+send more data on one-to-one type (SOCK_STREAM) sockets.
+.Pp
+The
+.Fa ppid
+argument is an opaque 32 bit value that is passed transparently
+through the stack to the peer endpoint.
+It will be available on
+reception of a message (see
+.Xr sctp_recvmsg 3 ) .
+Note that the stack passes this value without regard to byte
+order.
+.Pp
+The
+.Fa flags
+argument may include one or more of the following:
+.Bd -literal
+#define SCTP_EOF 0x0100 /* Start a shutdown procedures */
+#define SCTP_ABORT 0x0200 /* Send an ABORT to peer */
+#define SCTP_UNORDERED 0x0400 /* Message is un-ordered */
+#define SCTP_ADDR_OVER 0x0800 /* Override the primary-address */
+#define SCTP_SENDALL 0x1000 /* Send this on all associations */
+ /* for the endpoint */
+/* The lower byte is an enumeration of PR-SCTP policies */
+#define SCTP_PR_SCTP_TTL 0x0001 /* Time based PR-SCTP */
+#define SCTP_PR_SCTP_BUF 0x0002 /* Buffer based PR-SCTP */
+#define SCTP_PR_SCTP_RTX 0x0003 /* Number of retransmissions based PR-SCTP */
+.Ed
+.Pp
+The flag
+.Dv SCTP_EOF
+is used to instruct the SCTP stack to queue this message
+and then start a graceful shutdown of the association.
+All
+remaining data in queue will be sent after which the association
+will be shut down.
+.Pp
+.Dv SCTP_ABORT
+is used to immediately terminate an association.
+An abort
+is sent to the peer and the local TCB is destroyed.
+.Pp
+.Dv SCTP_UNORDERED
+is used to specify that the message being sent has no
+specific order and should be delivered to the peer application
+as soon as possible.
+When this flag is absent messages
+are delivered in order within the stream they are sent, but without
+respect to order to peer streams.
+.Pp
+The flag
+.Dv SCTP_ADDR_OVER
+is used to specify that an specific address should be used.
+Normally
+SCTP will use only one of a multi-homed peers addresses as the primary
+address to send to.
+By default, no matter what the
+.Fa to
+argument is, this primary address is used to send data.
+By specifying
+this flag, the user is asking the stack to ignore the primary address
+and instead use the specified address not only as a lookup mechanism
+to find the association but also as the actual address to send to.
+.Pp
+For a one-to-many type (SOCK_SEQPACKET) socket the flag
+.Dv SCTP_SENDALL
+can be used as a convenient way to make one send call and have
+all associations that are under the socket get a copy of the message.
+Note that this mechanism is quite efficient and makes only one actual
+copy of the data which is shared by all the associations for sending.
+.Pp
+The remaining flags are used for the partial reliability extension (RFC3758)
+and will only be effective if the peer endpoint supports this extension.
+This option specifies what local policy the local endpoint should use
+in skipping data.
+If none of these options are set, then data is
+never skipped over.
+.Pp
+.Dv SCTP_PR_SCTP_TTL
+is used to indicate that a time based lifetime is being applied
+to the data.
+The
+.Fa timetolive
+argument is then a number of milliseconds for which the data is
+attempted to be transmitted.
+If that many milliseconds elapse
+and the peer has not acknowledged the data, the data will be
+skipped and no longer transmitted.
+Note that this policy does
+not even assure that the data will ever be sent.
+In times of a congestion
+with large amounts of data being queued, the
+.Fa timetolive
+may expire before the first transmission is ever made.
+.Pp
+The
+.Dv SCTP_PR_SCTP_BUF
+based policy transforms the
+.Fa timetolive
+field into a total number of bytes allowed on the outbound
+send queue.
+If that number or more bytes are in queue, then
+other buffer based sends are looked to be removed and
+skipped.
+Note that this policy may also result in the data
+never being sent if no buffer based sends are in queue and
+the maximum specified by
+.Fa timetolive
+bytes is in queue.
+.Pp
+The
+.Dv SCTP_PR_SCTP_RTX
+policy transforms the
+.Fa timetolive
+into a number of retransmissions to allow.
+This policy
+always assures that at a minimum one send attempt is
+made of the data.
+After which no more than
+.Fa timetolive
+retransmissions will be made before the data is skipped.
+.Pp
+.Fa stream_no
+is the SCTP stream that you wish to send the
+message on.
+Streams in SCTP are reliable (or partially reliable) flows of ordered
+messages.
+The
+.Fa context
+field is used only in the event the message cannot be sent.
+This is an opaque
+value that the stack retains and will give to the user when a failed send
+is given if that notification is enabled (see
+.Xr sctp 4 ) .
+Normally a user process can use this value to index some application
+specific data structure when a send cannot be fulfilled.
+.Fn sctp_sendmsgx
+is identical to
+.Fn sctp_sendmsg
+with the exception that it takes an array of sockaddr structures in the
+argument
+.Fa to
+and adds the additional argument
+.Fa addrcnt
+which specifies how many addresses are in the array.
+This allows a
+caller to implicitly set up an association passing multiple addresses
+as if
+.Fn sctp_connectx
+had been called to set up the association.
+.Sh RETURN VALUES
+The call returns the number of characters sent, or -1
+if an error occurred.
+.Sh ERRORS
+The
+.Fn sctp_sendmsg
+system call
+fails if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+An invalid descriptor was specified.
+.It Bq Er ENOTSOCK
+The argument
+.Fa s
+is not a socket.
+.It Bq Er EFAULT
+An invalid user space address was specified for an argument.
+.It Bq Er EMSGSIZE
+The socket requires that message be sent atomically,
+and the size of the message to be sent made this impossible.
+.It Bq Er EAGAIN
+The socket is marked non-blocking and the requested operation
+would block.
+.It Bq Er ENOBUFS
+The system was unable to allocate an internal buffer.
+The operation may succeed when buffers become available.
+.It Bq Er ENOBUFS
+The output queue for a network interface was full.
+This generally indicates that the interface has stopped sending,
+but may be caused by transient congestion.
+.It Bq Er EHOSTUNREACH
+The remote host was unreachable.
+.It Bq Er ENOTCONN
+On a one-to-one style socket no association exists.
+.It Bq Er ECONNRESET
+An abort was received by the stack while the user was
+attempting to send data to the peer.
+.It Bq Er ENOENT
+On a one-to-many style socket no address is specified
+so that the association cannot be located or the
+.Dv SCTP_ABORT
+flag was specified on a non-existing association.
+.It Bq Er EPIPE
+The socket is unable to send anymore data
+.Dv ( SBS_CANTSENDMORE
+has been set on the socket).
+This typically means that the socket
+is not connected and is a one-to-one style socket.
+.El
+.Sh SEE ALSO
+.Xr connect 2 ,
+.Xr getsockopt 2 ,
+.Xr recv 2 ,
+.Xr select 2 ,
+.Xr sendmsg 2 ,
+.Xr socket 2 ,
+.Xr write 2 ,
+.Xr sctp_connectx 3 ,
+.Xr sctp 4
+.Sh BUGS
+Because in the one-to-many style socket
+.Fn sctp_sendmsg
+or
+.Fn sctp_sendmsgx
+may have multiple associations under one endpoint, a
+select on write will only work for a one-to-one style
+socket.
diff --git a/lib/libc/net/sctp_sys_calls.c b/lib/libc/net/sctp_sys_calls.c
new file mode 100644
index 000000000000..25b9ec87d195
--- /dev/null
+++ b/lib/libc/net/sctp_sys_calls.c
@@ -0,0 +1,1203 @@
+/*-
+ * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
+ * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
+ * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * a) Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * b) Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the distribution.
+ *
+ * c) Neither the name of Cisco Systems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/syscall.h>
+#include <sys/uio.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netinet/sctp_uio.h>
+#include <netinet/sctp.h>
+
+#ifndef IN6_IS_ADDR_V4MAPPED
+#define IN6_IS_ADDR_V4MAPPED(a) \
+ ((*(const uint32_t *)(const void *)(&(a)->s6_addr[0]) == 0) && \
+ (*(const uint32_t *)(const void *)(&(a)->s6_addr[4]) == 0) && \
+ (*(const uint32_t *)(const void *)(&(a)->s6_addr[8]) == ntohl(0x0000ffff)))
+#endif
+
+#define SCTP_CONTROL_VEC_SIZE_RCV 16384
+
+
+static void
+in6_sin6_2_sin(struct sockaddr_in *sin, struct sockaddr_in6 *sin6)
+{
+ bzero(sin, sizeof(*sin));
+ sin->sin_len = sizeof(struct sockaddr_in);
+ sin->sin_family = AF_INET;
+ sin->sin_port = sin6->sin6_port;
+ sin->sin_addr.s_addr = sin6->sin6_addr.__u6_addr.__u6_addr32[3];
+}
+
+int
+sctp_getaddrlen(sa_family_t family)
+{
+ int ret, sd;
+ socklen_t siz;
+ struct sctp_assoc_value av;
+
+ av.assoc_value = family;
+ siz = sizeof(av);
+#if defined(AF_INET)
+ sd = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
+#elif defined(AF_INET6)
+ sd = socket(AF_INET6, SOCK_SEQPACKET, IPPROTO_SCTP);
+#else
+ sd = -1;
+#endif
+ if (sd == -1) {
+ return (-1);
+ }
+ ret = getsockopt(sd, IPPROTO_SCTP, SCTP_GET_ADDR_LEN, &av, &siz);
+ close(sd);
+ if (ret == 0) {
+ return ((int)av.assoc_value);
+ } else {
+ return (-1);
+ }
+}
+
+int
+sctp_connectx(int sd, const struct sockaddr *addrs, int addrcnt,
+ sctp_assoc_t * id)
+{
+ char *buf;
+ int i, ret, *aa;
+ char *cpto;
+ const struct sockaddr *at;
+ size_t len;
+
+ /* validate the address count and list */
+ if ((addrs == NULL) || (addrcnt <= 0)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ if ((buf = malloc(sizeof(int) + (size_t)addrcnt * sizeof(struct sockaddr_in6))) == NULL) {
+ errno = E2BIG;
+ return (-1);
+ }
+ len = sizeof(int);
+ at = addrs;
+ cpto = buf + sizeof(int);
+ /* validate all the addresses and get the size */
+ for (i = 0; i < addrcnt; i++) {
+ switch (at->sa_family) {
+ case AF_INET:
+ if (at->sa_len != sizeof(struct sockaddr_in)) {
+ free(buf);
+ errno = EINVAL;
+ return (-1);
+ }
+ memcpy(cpto, at, sizeof(struct sockaddr_in));
+ cpto = ((caddr_t)cpto + sizeof(struct sockaddr_in));
+ len += sizeof(struct sockaddr_in);
+ break;
+ case AF_INET6:
+ if (at->sa_len != sizeof(struct sockaddr_in6)) {
+ free(buf);
+ errno = EINVAL;
+ return (-1);
+ }
+ if (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)at)->sin6_addr)) {
+ in6_sin6_2_sin((struct sockaddr_in *)cpto, (struct sockaddr_in6 *)at);
+ cpto = ((caddr_t)cpto + sizeof(struct sockaddr_in));
+ len += sizeof(struct sockaddr_in);
+ } else {
+ memcpy(cpto, at, sizeof(struct sockaddr_in6));
+ cpto = ((caddr_t)cpto + sizeof(struct sockaddr_in6));
+ len += sizeof(struct sockaddr_in6);
+ }
+ break;
+ default:
+ free(buf);
+ errno = EINVAL;
+ return (-1);
+ }
+ at = (struct sockaddr *)((caddr_t)at + at->sa_len);
+ }
+ aa = (int *)buf;
+ *aa = addrcnt;
+ ret = setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X, (void *)buf,
+ (socklen_t) len);
+ if ((ret == 0) && (id != NULL)) {
+ *id = *(sctp_assoc_t *) buf;
+ }
+ free(buf);
+ return (ret);
+}
+
+int
+sctp_bindx(int sd, struct sockaddr *addrs, int addrcnt, int flags)
+{
+ struct sctp_getaddresses *gaddrs;
+ struct sockaddr *sa;
+ struct sockaddr_in *sin;
+ struct sockaddr_in6 *sin6;
+ int i;
+ size_t argsz;
+ uint16_t sport = 0;
+
+ /* validate the flags */
+ if ((flags != SCTP_BINDX_ADD_ADDR) &&
+ (flags != SCTP_BINDX_REM_ADDR)) {
+ errno = EFAULT;
+ return (-1);
+ }
+ /* validate the address count and list */
+ if ((addrcnt <= 0) || (addrs == NULL)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ /* First pre-screen the addresses */
+ sa = addrs;
+ for (i = 0; i < addrcnt; i++) {
+ switch (sa->sa_family) {
+ case AF_INET:
+ if (sa->sa_len != sizeof(struct sockaddr_in)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ sin = (struct sockaddr_in *)sa;
+ if (sin->sin_port) {
+ /* non-zero port, check or save */
+ if (sport) {
+ /* Check against our port */
+ if (sport != sin->sin_port) {
+ errno = EINVAL;
+ return (-1);
+ }
+ } else {
+ /* save off the port */
+ sport = sin->sin_port;
+ }
+ }
+ break;
+ case AF_INET6:
+ if (sa->sa_len != sizeof(struct sockaddr_in6)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ sin6 = (struct sockaddr_in6 *)sa;
+ if (sin6->sin6_port) {
+ /* non-zero port, check or save */
+ if (sport) {
+ /* Check against our port */
+ if (sport != sin6->sin6_port) {
+ errno = EINVAL;
+ return (-1);
+ }
+ } else {
+ /* save off the port */
+ sport = sin6->sin6_port;
+ }
+ }
+ break;
+ default:
+ /* Invalid address family specified. */
+ errno = EAFNOSUPPORT;
+ return (-1);
+ }
+ sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len);
+ }
+ argsz = sizeof(struct sctp_getaddresses) +
+ sizeof(struct sockaddr_storage);
+ if ((gaddrs = (struct sctp_getaddresses *)malloc(argsz)) == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ sa = addrs;
+ for (i = 0; i < addrcnt; i++) {
+ memset(gaddrs, 0, argsz);
+ gaddrs->sget_assoc_id = 0;
+ memcpy(gaddrs->addr, sa, sa->sa_len);
+ /*
+ * Now, if there was a port mentioned, assure that the first
+ * address has that port to make sure it fails or succeeds
+ * correctly.
+ */
+ if ((i == 0) && (sport != 0)) {
+ switch (gaddrs->addr->sa_family) {
+ case AF_INET:
+ sin = (struct sockaddr_in *)gaddrs->addr;
+ sin->sin_port = sport;
+ break;
+ case AF_INET6:
+ sin6 = (struct sockaddr_in6 *)gaddrs->addr;
+ sin6->sin6_port = sport;
+ break;
+ }
+ }
+ if (setsockopt(sd, IPPROTO_SCTP, flags, gaddrs,
+ (socklen_t) argsz) != 0) {
+ free(gaddrs);
+ return (-1);
+ }
+ sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len);
+ }
+ free(gaddrs);
+ return (0);
+}
+
+int
+sctp_opt_info(int sd, sctp_assoc_t id, int opt, void *arg, socklen_t * size)
+{
+ if (arg == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+ if ((id == SCTP_CURRENT_ASSOC) ||
+ (id == SCTP_ALL_ASSOC)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ switch (opt) {
+ case SCTP_RTOINFO:
+ ((struct sctp_rtoinfo *)arg)->srto_assoc_id = id;
+ break;
+ case SCTP_ASSOCINFO:
+ ((struct sctp_assocparams *)arg)->sasoc_assoc_id = id;
+ break;
+ case SCTP_DEFAULT_SEND_PARAM:
+ ((struct sctp_assocparams *)arg)->sasoc_assoc_id = id;
+ break;
+ case SCTP_PRIMARY_ADDR:
+ ((struct sctp_setprim *)arg)->ssp_assoc_id = id;
+ break;
+ case SCTP_PEER_ADDR_PARAMS:
+ ((struct sctp_paddrparams *)arg)->spp_assoc_id = id;
+ break;
+ case SCTP_MAXSEG:
+ ((struct sctp_assoc_value *)arg)->assoc_id = id;
+ break;
+ case SCTP_AUTH_KEY:
+ ((struct sctp_authkey *)arg)->sca_assoc_id = id;
+ break;
+ case SCTP_AUTH_ACTIVE_KEY:
+ ((struct sctp_authkeyid *)arg)->scact_assoc_id = id;
+ break;
+ case SCTP_DELAYED_SACK:
+ ((struct sctp_sack_info *)arg)->sack_assoc_id = id;
+ break;
+ case SCTP_CONTEXT:
+ ((struct sctp_assoc_value *)arg)->assoc_id = id;
+ break;
+ case SCTP_STATUS:
+ ((struct sctp_status *)arg)->sstat_assoc_id = id;
+ break;
+ case SCTP_GET_PEER_ADDR_INFO:
+ ((struct sctp_paddrinfo *)arg)->spinfo_assoc_id = id;
+ break;
+ case SCTP_PEER_AUTH_CHUNKS:
+ ((struct sctp_authchunks *)arg)->gauth_assoc_id = id;
+ break;
+ case SCTP_LOCAL_AUTH_CHUNKS:
+ ((struct sctp_authchunks *)arg)->gauth_assoc_id = id;
+ break;
+ case SCTP_TIMEOUTS:
+ ((struct sctp_timeouts *)arg)->stimo_assoc_id = id;
+ break;
+ case SCTP_EVENT:
+ ((struct sctp_event *)arg)->se_assoc_id = id;
+ break;
+ case SCTP_DEFAULT_SNDINFO:
+ ((struct sctp_sndinfo *)arg)->snd_assoc_id = id;
+ break;
+ case SCTP_DEFAULT_PRINFO:
+ ((struct sctp_default_prinfo *)arg)->pr_assoc_id = id;
+ break;
+ case SCTP_PEER_ADDR_THLDS:
+ ((struct sctp_paddrthlds *)arg)->spt_assoc_id = id;
+ break;
+ case SCTP_REMOTE_UDP_ENCAPS_PORT:
+ ((struct sctp_udpencaps *)arg)->sue_assoc_id = id;
+ break;
+ case SCTP_ECN_SUPPORTED:
+ ((struct sctp_assoc_value *)arg)->assoc_id = id;
+ break;
+ case SCTP_PR_SUPPORTED:
+ ((struct sctp_assoc_value *)arg)->assoc_id = id;
+ break;
+ case SCTP_AUTH_SUPPORTED:
+ ((struct sctp_assoc_value *)arg)->assoc_id = id;
+ break;
+ case SCTP_ASCONF_SUPPORTED:
+ ((struct sctp_assoc_value *)arg)->assoc_id = id;
+ break;
+ case SCTP_RECONFIG_SUPPORTED:
+ ((struct sctp_assoc_value *)arg)->assoc_id = id;
+ break;
+ case SCTP_NRSACK_SUPPORTED:
+ ((struct sctp_assoc_value *)arg)->assoc_id = id;
+ break;
+ case SCTP_PKTDROP_SUPPORTED:
+ ((struct sctp_assoc_value *)arg)->assoc_id = id;
+ break;
+ case SCTP_MAX_BURST:
+ ((struct sctp_assoc_value *)arg)->assoc_id = id;
+ break;
+ case SCTP_ENABLE_STREAM_RESET:
+ ((struct sctp_assoc_value *)arg)->assoc_id = id;
+ break;
+ case SCTP_PR_STREAM_STATUS:
+ ((struct sctp_prstatus *)arg)->sprstat_assoc_id = id;
+ break;
+ case SCTP_PR_ASSOC_STATUS:
+ ((struct sctp_prstatus *)arg)->sprstat_assoc_id = id;
+ break;
+ case SCTP_MAX_CWND:
+ ((struct sctp_assoc_value *)arg)->assoc_id = id;
+ break;
+ default:
+ break;
+ }
+ return (getsockopt(sd, IPPROTO_SCTP, opt, arg, size));
+}
+
+int
+sctp_getpaddrs(int sd, sctp_assoc_t id, struct sockaddr **raddrs)
+{
+ struct sctp_getaddresses *addrs;
+ struct sockaddr *sa;
+ sctp_assoc_t asoc;
+ caddr_t lim;
+ socklen_t opt_len;
+ int cnt;
+
+ if (raddrs == NULL) {
+ errno = EFAULT;
+ return (-1);
+ }
+ asoc = id;
+ opt_len = (socklen_t) sizeof(sctp_assoc_t);
+ if (getsockopt(sd, IPPROTO_SCTP, SCTP_GET_REMOTE_ADDR_SIZE,
+ &asoc, &opt_len) != 0) {
+ return (-1);
+ }
+ /* size required is returned in 'asoc' */
+ opt_len = (socklen_t) ((size_t)asoc + sizeof(struct sctp_getaddresses));
+ addrs = calloc(1, (size_t)opt_len);
+ if (addrs == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ addrs->sget_assoc_id = id;
+ /* Now lets get the array of addresses */
+ if (getsockopt(sd, IPPROTO_SCTP, SCTP_GET_PEER_ADDRESSES,
+ addrs, &opt_len) != 0) {
+ free(addrs);
+ return (-1);
+ }
+ *raddrs = (struct sockaddr *)&addrs->addr[0];
+ cnt = 0;
+ sa = (struct sockaddr *)&addrs->addr[0];
+ lim = (caddr_t)addrs + opt_len;
+ while (((caddr_t)sa < lim) && (sa->sa_len > 0)) {
+ sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len);
+ cnt++;
+ }
+ return (cnt);
+}
+
+void
+sctp_freepaddrs(struct sockaddr *addrs)
+{
+ void *fr_addr;
+
+ /* Take away the hidden association id */
+ fr_addr = (void *)((caddr_t)addrs - sizeof(sctp_assoc_t));
+ /* Now free it */
+ free(fr_addr);
+}
+
+int
+sctp_getladdrs(int sd, sctp_assoc_t id, struct sockaddr **raddrs)
+{
+ struct sctp_getaddresses *addrs;
+ caddr_t lim;
+ struct sockaddr *sa;
+ size_t size_of_addresses;
+ socklen_t opt_len;
+ int cnt;
+
+ if (raddrs == NULL) {
+ errno = EFAULT;
+ return (-1);
+ }
+ size_of_addresses = 0;
+ opt_len = (socklen_t) sizeof(int);
+ if (getsockopt(sd, IPPROTO_SCTP, SCTP_GET_LOCAL_ADDR_SIZE,
+ &size_of_addresses, &opt_len) != 0) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ if (size_of_addresses == 0) {
+ errno = ENOTCONN;
+ return (-1);
+ }
+ opt_len = (socklen_t) (size_of_addresses +
+ sizeof(struct sockaddr_storage) +
+ sizeof(struct sctp_getaddresses));
+ addrs = calloc(1, (size_t)opt_len);
+ if (addrs == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ addrs->sget_assoc_id = id;
+ /* Now lets get the array of addresses */
+ if (getsockopt(sd, IPPROTO_SCTP, SCTP_GET_LOCAL_ADDRESSES, addrs,
+ &opt_len) != 0) {
+ free(addrs);
+ errno = ENOMEM;
+ return (-1);
+ }
+ *raddrs = (struct sockaddr *)&addrs->addr[0];
+ cnt = 0;
+ sa = (struct sockaddr *)&addrs->addr[0];
+ lim = (caddr_t)addrs + opt_len;
+ while (((caddr_t)sa < lim) && (sa->sa_len > 0)) {
+ sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len);
+ cnt++;
+ }
+ return (cnt);
+}
+
+void
+sctp_freeladdrs(struct sockaddr *addrs)
+{
+ void *fr_addr;
+
+ /* Take away the hidden association id */
+ fr_addr = (void *)((caddr_t)addrs - sizeof(sctp_assoc_t));
+ /* Now free it */
+ free(fr_addr);
+}
+
+ssize_t
+sctp_sendmsg(int s,
+ const void *data,
+ size_t len,
+ const struct sockaddr *to,
+ socklen_t tolen,
+ uint32_t ppid,
+ uint32_t flags,
+ uint16_t stream_no,
+ uint32_t timetolive,
+ uint32_t context)
+{
+#ifdef SYS_sctp_generic_sendmsg
+ struct sctp_sndrcvinfo sinfo;
+
+ memset(&sinfo, 0, sizeof(struct sctp_sndrcvinfo));
+ sinfo.sinfo_ppid = ppid;
+ sinfo.sinfo_flags = flags;
+ sinfo.sinfo_stream = stream_no;
+ sinfo.sinfo_timetolive = timetolive;
+ sinfo.sinfo_context = context;
+ sinfo.sinfo_assoc_id = 0;
+ return (syscall(SYS_sctp_generic_sendmsg, s,
+ data, len, to, tolen, &sinfo, 0));
+#else
+ struct msghdr msg;
+ struct sctp_sndrcvinfo *sinfo;
+ struct iovec iov;
+ char cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
+ struct cmsghdr *cmsg;
+ struct sockaddr *who = NULL;
+ union {
+ struct sockaddr_in in;
+ struct sockaddr_in6 in6;
+ } addr;
+
+ if ((tolen > 0) &&
+ ((to == NULL) || (tolen < sizeof(struct sockaddr)))) {
+ errno = EINVAL;
+ return (-1);
+ }
+ if ((to != NULL) && (tolen > 0)) {
+ switch (to->sa_family) {
+ case AF_INET:
+ if (tolen != sizeof(struct sockaddr_in)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ if ((to->sa_len > 0) &&
+ (to->sa_len != sizeof(struct sockaddr_in))) {
+ errno = EINVAL;
+ return (-1);
+ }
+ memcpy(&addr, to, sizeof(struct sockaddr_in));
+ addr.in.sin_len = sizeof(struct sockaddr_in);
+ break;
+ case AF_INET6:
+ if (tolen != sizeof(struct sockaddr_in6)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ if ((to->sa_len > 0) &&
+ (to->sa_len != sizeof(struct sockaddr_in6))) {
+ errno = EINVAL;
+ return (-1);
+ }
+ memcpy(&addr, to, sizeof(struct sockaddr_in6));
+ addr.in6.sin6_len = sizeof(struct sockaddr_in6);
+ break;
+ default:
+ errno = EAFNOSUPPORT;
+ return (-1);
+ }
+ who = (struct sockaddr *)&addr;
+ }
+ iov.iov_base = (char *)data;
+ iov.iov_len = len;
+
+ if (who) {
+ msg.msg_name = (caddr_t)who;
+ msg.msg_namelen = who->sa_len;
+ } else {
+ msg.msg_name = (caddr_t)NULL;
+ msg.msg_namelen = 0;
+ }
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = cmsgbuf;
+ msg.msg_controllen = CMSG_SPACE(sizeof(struct sctp_sndrcvinfo));
+ msg.msg_flags = 0;
+ cmsg = (struct cmsghdr *)cmsgbuf;
+ cmsg->cmsg_level = IPPROTO_SCTP;
+ cmsg->cmsg_type = SCTP_SNDRCV;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
+ sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
+ memset(sinfo, 0, sizeof(struct sctp_sndrcvinfo));
+ sinfo->sinfo_stream = stream_no;
+ sinfo->sinfo_ssn = 0;
+ sinfo->sinfo_flags = flags;
+ sinfo->sinfo_ppid = ppid;
+ sinfo->sinfo_context = context;
+ sinfo->sinfo_assoc_id = 0;
+ sinfo->sinfo_timetolive = timetolive;
+ return (sendmsg(s, &msg, 0));
+#endif
+}
+
+
+sctp_assoc_t
+sctp_getassocid(int sd, struct sockaddr *sa)
+{
+ struct sctp_paddrinfo sp;
+ socklen_t siz;
+
+ /* First get the assoc id */
+ siz = sizeof(sp);
+ memset(&sp, 0, sizeof(sp));
+ memcpy((caddr_t)&sp.spinfo_address, sa, sa->sa_len);
+ if (getsockopt(sd, IPPROTO_SCTP,
+ SCTP_GET_PEER_ADDR_INFO, &sp, &siz) != 0) {
+ /* We depend on the fact that 0 can never be returned */
+ return ((sctp_assoc_t) 0);
+ }
+ return (sp.spinfo_assoc_id);
+}
+
+ssize_t
+sctp_send(int sd, const void *data, size_t len,
+ const struct sctp_sndrcvinfo *sinfo,
+ int flags)
+{
+
+#ifdef SYS_sctp_generic_sendmsg
+ struct sockaddr *to = NULL;
+
+ return (syscall(SYS_sctp_generic_sendmsg, sd,
+ data, len, to, 0, sinfo, flags));
+#else
+ struct msghdr msg;
+ struct iovec iov;
+ char cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
+ struct cmsghdr *cmsg;
+
+ if (sinfo == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+ iov.iov_base = (char *)data;
+ iov.iov_len = len;
+
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = cmsgbuf;
+ msg.msg_controllen = CMSG_SPACE(sizeof(struct sctp_sndrcvinfo));
+ msg.msg_flags = 0;
+ cmsg = (struct cmsghdr *)cmsgbuf;
+ cmsg->cmsg_level = IPPROTO_SCTP;
+ cmsg->cmsg_type = SCTP_SNDRCV;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
+ memcpy(CMSG_DATA(cmsg), sinfo, sizeof(struct sctp_sndrcvinfo));
+ return (sendmsg(sd, &msg, flags));
+#endif
+}
+
+
+
+ssize_t
+sctp_sendx(int sd, const void *msg, size_t msg_len,
+ struct sockaddr *addrs, int addrcnt,
+ struct sctp_sndrcvinfo *sinfo,
+ int flags)
+{
+ struct sctp_sndrcvinfo __sinfo;
+ ssize_t ret;
+ int i, cnt, *aa, saved_errno;
+ char *buf;
+ int no_end_cx = 0;
+ size_t len, add_len;
+ struct sockaddr *at;
+
+ if (addrs == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+#ifdef SYS_sctp_generic_sendmsg
+ if (addrcnt == 1) {
+ socklen_t l;
+ ssize_t ret;
+
+ /*
+ * Quick way, we don't need to do a connectx so lets use the
+ * syscall directly.
+ */
+ l = addrs->sa_len;
+ ret = syscall(SYS_sctp_generic_sendmsg, sd,
+ msg, msg_len, addrs, l, sinfo, flags);
+ if ((ret >= 0) && (sinfo != NULL)) {
+ sinfo->sinfo_assoc_id = sctp_getassocid(sd, addrs);
+ }
+ return (ret);
+ }
+#endif
+
+ len = sizeof(int);
+ at = addrs;
+ cnt = 0;
+ /* validate all the addresses and get the size */
+ for (i = 0; i < addrcnt; i++) {
+ if (at->sa_family == AF_INET) {
+ add_len = sizeof(struct sockaddr_in);
+ } else if (at->sa_family == AF_INET6) {
+ add_len = sizeof(struct sockaddr_in6);
+ } else {
+ errno = EINVAL;
+ return (-1);
+ }
+ len += add_len;
+ at = (struct sockaddr *)((caddr_t)at + add_len);
+ cnt++;
+ }
+ /* do we have any? */
+ if (cnt == 0) {
+ errno = EINVAL;
+ return (-1);
+ }
+ buf = malloc(len);
+ if (buf == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ aa = (int *)buf;
+ *aa = cnt;
+ aa++;
+ memcpy((caddr_t)aa, addrs, (size_t)(len - sizeof(int)));
+ ret = setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X_DELAYED, (void *)buf,
+ (socklen_t) len);
+
+ free(buf);
+ if (ret != 0) {
+ if (errno == EALREADY) {
+ no_end_cx = 1;
+ goto continue_send;
+ }
+ return (ret);
+ }
+continue_send:
+ if (sinfo == NULL) {
+ sinfo = &__sinfo;
+ memset(&__sinfo, 0, sizeof(__sinfo));
+ }
+ sinfo->sinfo_assoc_id = sctp_getassocid(sd, addrs);
+ if (sinfo->sinfo_assoc_id == 0) {
+ (void)setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X_COMPLETE, (void *)addrs,
+ (socklen_t) addrs->sa_len);
+ errno = ENOENT;
+ return (-1);
+ }
+ ret = sctp_send(sd, msg, msg_len, sinfo, flags);
+ saved_errno = errno;
+ if (no_end_cx == 0)
+ (void)setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X_COMPLETE, (void *)addrs,
+ (socklen_t) addrs->sa_len);
+
+ errno = saved_errno;
+ return (ret);
+}
+
+ssize_t
+sctp_sendmsgx(int sd,
+ const void *msg,
+ size_t len,
+ struct sockaddr *addrs,
+ int addrcnt,
+ uint32_t ppid,
+ uint32_t flags,
+ uint16_t stream_no,
+ uint32_t timetolive,
+ uint32_t context)
+{
+ struct sctp_sndrcvinfo sinfo;
+
+ memset((void *)&sinfo, 0, sizeof(struct sctp_sndrcvinfo));
+ sinfo.sinfo_ppid = ppid;
+ sinfo.sinfo_flags = flags;
+ sinfo.sinfo_stream = stream_no;
+ sinfo.sinfo_timetolive = timetolive;
+ sinfo.sinfo_context = context;
+ return (sctp_sendx(sd, msg, len, addrs, addrcnt, &sinfo, 0));
+}
+
+ssize_t
+sctp_recvmsg(int s,
+ void *dbuf,
+ size_t len,
+ struct sockaddr *from,
+ socklen_t * fromlen,
+ struct sctp_sndrcvinfo *sinfo,
+ int *msg_flags)
+{
+#ifdef SYS_sctp_generic_recvmsg
+ struct iovec iov;
+
+ iov.iov_base = dbuf;
+ iov.iov_len = len;
+ return (syscall(SYS_sctp_generic_recvmsg, s,
+ &iov, 1, from, fromlen, sinfo, msg_flags));
+#else
+ ssize_t sz;
+ struct msghdr msg;
+ struct iovec iov;
+ char cmsgbuf[SCTP_CONTROL_VEC_SIZE_RCV];
+ struct cmsghdr *cmsg;
+
+ if (msg_flags == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+ iov.iov_base = dbuf;
+ iov.iov_len = len;
+ msg.msg_name = (caddr_t)from;
+ if (fromlen == NULL)
+ msg.msg_namelen = 0;
+ else
+ msg.msg_namelen = *fromlen;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = cmsgbuf;
+ msg.msg_controllen = sizeof(cmsgbuf);
+ msg.msg_flags = 0;
+ sz = recvmsg(s, &msg, *msg_flags);
+ *msg_flags = msg.msg_flags;
+ if (sz <= 0) {
+ return (sz);
+ }
+ if (sinfo) {
+ sinfo->sinfo_assoc_id = 0;
+ }
+ if ((msg.msg_controllen > 0) && (sinfo != NULL)) {
+ /*
+ * parse through and see if we find the sctp_sndrcvinfo (if
+ * the user wants it).
+ */
+ for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+ if (cmsg->cmsg_level != IPPROTO_SCTP) {
+ continue;
+ }
+ if (cmsg->cmsg_type == SCTP_SNDRCV) {
+ memcpy(sinfo, CMSG_DATA(cmsg), sizeof(struct sctp_sndrcvinfo));
+ break;
+ }
+ if (cmsg->cmsg_type == SCTP_EXTRCV) {
+ /*
+ * Let's hope that the user provided enough
+ * enough memory. At least he asked for more
+ * information.
+ */
+ memcpy(sinfo, CMSG_DATA(cmsg), sizeof(struct sctp_extrcvinfo));
+ break;
+ }
+ }
+ }
+ return (sz);
+#endif
+}
+
+ssize_t
+sctp_recvv(int sd,
+ const struct iovec *iov,
+ int iovlen,
+ struct sockaddr *from,
+ socklen_t * fromlen,
+ void *info,
+ socklen_t * infolen,
+ unsigned int *infotype,
+ int *flags)
+{
+ char cmsgbuf[SCTP_CONTROL_VEC_SIZE_RCV];
+ struct msghdr msg;
+ struct cmsghdr *cmsg;
+ ssize_t ret;
+ struct sctp_rcvinfo *rcvinfo;
+ struct sctp_nxtinfo *nxtinfo;
+
+ if (((info != NULL) && (infolen == NULL)) ||
+ ((info == NULL) && (infolen != NULL) && (*infolen != 0)) ||
+ ((info != NULL) && (infotype == NULL))) {
+ errno = EINVAL;
+ return (-1);
+ }
+ if (infotype) {
+ *infotype = SCTP_RECVV_NOINFO;
+ }
+ msg.msg_name = from;
+ if (fromlen == NULL) {
+ msg.msg_namelen = 0;
+ } else {
+ msg.msg_namelen = *fromlen;
+ }
+ msg.msg_iov = (struct iovec *)iov;
+ msg.msg_iovlen = iovlen;
+ msg.msg_control = cmsgbuf;
+ msg.msg_controllen = sizeof(cmsgbuf);
+ msg.msg_flags = 0;
+ ret = recvmsg(sd, &msg, *flags);
+ *flags = msg.msg_flags;
+ if ((ret > 0) &&
+ (msg.msg_controllen > 0) &&
+ (infotype != NULL) &&
+ (infolen != NULL) &&
+ (*infolen > 0)) {
+ rcvinfo = NULL;
+ nxtinfo = NULL;
+ for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+ if (cmsg->cmsg_level != IPPROTO_SCTP) {
+ continue;
+ }
+ if (cmsg->cmsg_type == SCTP_RCVINFO) {
+ rcvinfo = (struct sctp_rcvinfo *)CMSG_DATA(cmsg);
+ if (nxtinfo != NULL) {
+ break;
+ } else {
+ continue;
+ }
+ }
+ if (cmsg->cmsg_type == SCTP_NXTINFO) {
+ nxtinfo = (struct sctp_nxtinfo *)CMSG_DATA(cmsg);
+ if (rcvinfo != NULL) {
+ break;
+ } else {
+ continue;
+ }
+ }
+ }
+ if (rcvinfo != NULL) {
+ if ((nxtinfo != NULL) && (*infolen >= sizeof(struct sctp_recvv_rn))) {
+ struct sctp_recvv_rn *rn_info;
+
+ rn_info = (struct sctp_recvv_rn *)info;
+ rn_info->recvv_rcvinfo = *rcvinfo;
+ rn_info->recvv_nxtinfo = *nxtinfo;
+ *infolen = (socklen_t) sizeof(struct sctp_recvv_rn);
+ *infotype = SCTP_RECVV_RN;
+ } else if (*infolen >= sizeof(struct sctp_rcvinfo)) {
+ memcpy(info, rcvinfo, sizeof(struct sctp_rcvinfo));
+ *infolen = (socklen_t) sizeof(struct sctp_rcvinfo);
+ *infotype = SCTP_RECVV_RCVINFO;
+ }
+ } else if (nxtinfo != NULL) {
+ if (*infolen >= sizeof(struct sctp_nxtinfo)) {
+ memcpy(info, nxtinfo, sizeof(struct sctp_nxtinfo));
+ *infolen = (socklen_t) sizeof(struct sctp_nxtinfo);
+ *infotype = SCTP_RECVV_NXTINFO;
+ }
+ }
+ }
+ return (ret);
+}
+
+ssize_t
+sctp_sendv(int sd,
+ const struct iovec *iov, int iovcnt,
+ struct sockaddr *addrs, int addrcnt,
+ void *info, socklen_t infolen, unsigned int infotype,
+ int flags)
+{
+ ssize_t ret;
+ int i;
+ socklen_t addr_len;
+ struct msghdr msg;
+ in_port_t port;
+ struct sctp_sendv_spa *spa_info;
+ struct cmsghdr *cmsg;
+ char *cmsgbuf;
+ struct sockaddr *addr;
+ struct sockaddr_in *addr_in;
+ struct sockaddr_in6 *addr_in6;
+ sctp_assoc_t *assoc_id;
+
+ if ((addrcnt < 0) ||
+ (iovcnt < 0) ||
+ ((addrs == NULL) && (addrcnt > 0)) ||
+ ((addrs != NULL) && (addrcnt == 0)) ||
+ ((iov == NULL) && (iovcnt > 0)) ||
+ ((iov != NULL) && (iovcnt == 0))) {
+ errno = EINVAL;
+ return (-1);
+ }
+ cmsgbuf = malloc(CMSG_SPACE(sizeof(struct sctp_sndinfo)) +
+ CMSG_SPACE(sizeof(struct sctp_prinfo)) +
+ CMSG_SPACE(sizeof(struct sctp_authinfo)) +
+ (size_t)addrcnt * CMSG_SPACE(sizeof(struct in6_addr)));
+ if (cmsgbuf == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ assoc_id = NULL;
+ msg.msg_control = cmsgbuf;
+ msg.msg_controllen = 0;
+ cmsg = (struct cmsghdr *)cmsgbuf;
+ switch (infotype) {
+ case SCTP_SENDV_NOINFO:
+ if ((infolen != 0) || (info != NULL)) {
+ free(cmsgbuf);
+ errno = EINVAL;
+ return (-1);
+ }
+ break;
+ case SCTP_SENDV_SNDINFO:
+ if ((info == NULL) || (infolen < sizeof(struct sctp_sndinfo))) {
+ free(cmsgbuf);
+ errno = EINVAL;
+ return (-1);
+ }
+ cmsg->cmsg_level = IPPROTO_SCTP;
+ cmsg->cmsg_type = SCTP_SNDINFO;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndinfo));
+ memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_sndinfo));
+ msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndinfo));
+ cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_sndinfo)));
+ assoc_id = &(((struct sctp_sndinfo *)info)->snd_assoc_id);
+ break;
+ case SCTP_SENDV_PRINFO:
+ if ((info == NULL) || (infolen < sizeof(struct sctp_prinfo))) {
+ free(cmsgbuf);
+ errno = EINVAL;
+ return (-1);
+ }
+ cmsg->cmsg_level = IPPROTO_SCTP;
+ cmsg->cmsg_type = SCTP_PRINFO;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_prinfo));
+ memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_prinfo));
+ msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_prinfo));
+ cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_prinfo)));
+ break;
+ case SCTP_SENDV_AUTHINFO:
+ if ((info == NULL) || (infolen < sizeof(struct sctp_authinfo))) {
+ free(cmsgbuf);
+ errno = EINVAL;
+ return (-1);
+ }
+ cmsg->cmsg_level = IPPROTO_SCTP;
+ cmsg->cmsg_type = SCTP_AUTHINFO;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_authinfo));
+ memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_authinfo));
+ msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_authinfo));
+ cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_authinfo)));
+ break;
+ case SCTP_SENDV_SPA:
+ if ((info == NULL) || (infolen < sizeof(struct sctp_sendv_spa))) {
+ free(cmsgbuf);
+ errno = EINVAL;
+ return (-1);
+ }
+ spa_info = (struct sctp_sendv_spa *)info;
+ if (spa_info->sendv_flags & SCTP_SEND_SNDINFO_VALID) {
+ cmsg->cmsg_level = IPPROTO_SCTP;
+ cmsg->cmsg_type = SCTP_SNDINFO;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndinfo));
+ memcpy(CMSG_DATA(cmsg), &spa_info->sendv_sndinfo, sizeof(struct sctp_sndinfo));
+ msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndinfo));
+ cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_sndinfo)));
+ assoc_id = &(spa_info->sendv_sndinfo.snd_assoc_id);
+ }
+ if (spa_info->sendv_flags & SCTP_SEND_PRINFO_VALID) {
+ cmsg->cmsg_level = IPPROTO_SCTP;
+ cmsg->cmsg_type = SCTP_PRINFO;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_prinfo));
+ memcpy(CMSG_DATA(cmsg), &spa_info->sendv_prinfo, sizeof(struct sctp_prinfo));
+ msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_prinfo));
+ cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_prinfo)));
+ }
+ if (spa_info->sendv_flags & SCTP_SEND_AUTHINFO_VALID) {
+ cmsg->cmsg_level = IPPROTO_SCTP;
+ cmsg->cmsg_type = SCTP_AUTHINFO;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_authinfo));
+ memcpy(CMSG_DATA(cmsg), &spa_info->sendv_authinfo, sizeof(struct sctp_authinfo));
+ msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_authinfo));
+ cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_authinfo)));
+ }
+ break;
+ default:
+ free(cmsgbuf);
+ errno = EINVAL;
+ return (-1);
+ }
+ addr = addrs;
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+
+ for (i = 0; i < addrcnt; i++) {
+ switch (addr->sa_family) {
+ case AF_INET:
+ addr_len = (socklen_t) sizeof(struct sockaddr_in);
+ addr_in = (struct sockaddr_in *)addr;
+ if (addr_in->sin_len != addr_len) {
+ free(cmsgbuf);
+ errno = EINVAL;
+ return (-1);
+ }
+ if (i == 0) {
+ port = addr_in->sin_port;
+ } else {
+ if (port == addr_in->sin_port) {
+ cmsg->cmsg_level = IPPROTO_SCTP;
+ cmsg->cmsg_type = SCTP_DSTADDRV4;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
+ memcpy(CMSG_DATA(cmsg), &addr_in->sin_addr, sizeof(struct in_addr));
+ msg.msg_controllen += CMSG_SPACE(sizeof(struct in_addr));
+ cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct in_addr)));
+ } else {
+ free(cmsgbuf);
+ errno = EINVAL;
+ return (-1);
+ }
+ }
+ break;
+ case AF_INET6:
+ addr_len = (socklen_t) sizeof(struct sockaddr_in6);
+ addr_in6 = (struct sockaddr_in6 *)addr;
+ if (addr_in6->sin6_len != addr_len) {
+ free(cmsgbuf);
+ errno = EINVAL;
+ return (-1);
+ }
+ if (i == 0) {
+ port = addr_in6->sin6_port;
+ } else {
+ if (port == addr_in6->sin6_port) {
+ cmsg->cmsg_level = IPPROTO_SCTP;
+ cmsg->cmsg_type = SCTP_DSTADDRV6;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_addr));
+ memcpy(CMSG_DATA(cmsg), &addr_in6->sin6_addr, sizeof(struct in6_addr));
+ msg.msg_controllen += CMSG_SPACE(sizeof(struct in6_addr));
+ cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct in6_addr)));
+ } else {
+ free(cmsgbuf);
+ errno = EINVAL;
+ return (-1);
+ }
+ }
+ break;
+ default:
+ free(cmsgbuf);
+ errno = EINVAL;
+ return (-1);
+ }
+ if (i == 0) {
+ msg.msg_name = addr;
+ msg.msg_namelen = addr_len;
+ }
+ addr = (struct sockaddr *)((caddr_t)addr + addr_len);
+ }
+ if (msg.msg_controllen == 0) {
+ msg.msg_control = NULL;
+ }
+ msg.msg_iov = (struct iovec *)iov;
+ msg.msg_iovlen = iovcnt;
+ msg.msg_flags = 0;
+ ret = sendmsg(sd, &msg, flags);
+ free(cmsgbuf);
+ if ((ret >= 0) && (addrs != NULL) && (assoc_id != NULL)) {
+ *assoc_id = sctp_getassocid(sd, addrs);
+ }
+ return (ret);
+}
+
+
+#if !defined(SYS_sctp_peeloff) && !defined(HAVE_SCTP_PEELOFF_SOCKOPT)
+
+int
+sctp_peeloff(int sd, sctp_assoc_t assoc_id)
+{
+ /* NOT supported, return invalid sd */
+ errno = ENOTSUP;
+ return (-1);
+}
+
+#endif
+#if defined(SYS_sctp_peeloff) && !defined(HAVE_SCTP_PEELOFF_SOCKOPT)
+int
+sctp_peeloff(int sd, sctp_assoc_t assoc_id)
+{
+ return (syscall(SYS_sctp_peeloff, sd, assoc_id));
+}
+
+#endif
+
+#undef SCTP_CONTROL_VEC_SIZE_RCV
diff --git a/lib/libc/net/send.c b/lib/libc/net/send.c
new file mode 100644
index 000000000000..ff984363300a
--- /dev/null
+++ b/lib/libc/net/send.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)send.c 8.2 (Berkeley) 2/21/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "libc_private.h"
+
+#include <stddef.h>
+
+ssize_t
+send(int s, const void *msg, size_t len, int flags)
+{
+ /*
+ * POSIX says send() shall be a cancellation point, so call the
+ * cancellation-enabled sendto() and not _sendto().
+ */
+ return (((ssize_t (*)(int, const void *, size_t, int,
+ const struct sockaddr *, socklen_t))
+ __libc_interposing[INTERPOS_sendto])(s, msg, len, flags,
+ NULL, 0));
+}
diff --git a/lib/libc/net/sockatmark.3 b/lib/libc/net/sockatmark.3
new file mode 100644
index 000000000000..61a1a9f52989
--- /dev/null
+++ b/lib/libc/net/sockatmark.3
@@ -0,0 +1,123 @@
+.\" Copyright (c) 2002 William C. Fenner. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd October 13, 2002
+.Dt SOCKATMARK 3
+.Os
+.Sh NAME
+.Nm sockatmark
+.Nd determine whether the read pointer is at the OOB mark
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/socket.h
+.Ft int
+.Fn sockatmark "int s"
+.Sh DESCRIPTION
+To find out if the read pointer is currently pointing at
+the mark in the data stream, the
+.Fn sockatmark
+function is provided.
+If
+.Fn sockatmark
+returns 1, the next read will return data
+after the mark.
+Otherwise (assuming out of band data has arrived),
+the next read will provide data sent by the client prior
+to transmission of the out of band signal.
+The routine used
+in the remote login process to flush output on receipt of an
+interrupt or quit signal is shown below.
+It reads the normal data up to the mark (to discard it),
+then reads the out-of-band byte.
+.Bd -literal -offset indent
+#include <sys/socket.h>
+\&...
+oob()
+{
+ int out = FWRITE, mark;
+ char waste[BUFSIZ];
+
+ /* flush local terminal output */
+ ioctl(1, TIOCFLUSH, (char *)&out);
+ for (;;) {
+ if ((mark = sockatmark(rem)) < 0) {
+ perror("sockatmark");
+ break;
+ }
+ if (mark)
+ break;
+ (void) read(rem, waste, sizeof (waste));
+ }
+ if (recv(rem, &mark, 1, MSG_OOB) < 0) {
+ perror("recv");
+ ...
+ }
+ ...
+}
+.Ed
+.Sh RETURN VALUES
+Upon successful completion, the
+.Fn sockatmark
+function returns the value 1 if the read pointer is pointing at
+the OOB mark, 0 if it is not.
+Otherwise the value \-1 is returned
+and the global variable
+.Va errno
+is set to
+indicate the error.
+.Sh ERRORS
+The
+.Fn sockatmark
+call fails if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa s
+argument
+is not a valid descriptor.
+.It Bq Er ENOTTY
+The
+.Fa s
+argument
+is a descriptor for a file, not a socket.
+.El
+.Sh SEE ALSO
+.Xr recv 2 ,
+.Xr send 2
+.Sh HISTORY
+The
+.Fn sockatmark
+function was introduced by
+.St -p1003.1-2001 ,
+to standardize the historical
+.Dv SIOCATMARK
+.Xr ioctl 2 .
+The
+.Er ENOTTY
+error instead of the usual
+.Er ENOTSOCK
+is to match the historical behavior of
+.Dv SIOCATMARK .
diff --git a/lib/libc/net/sockatmark.c b/lib/libc/net/sockatmark.c
new file mode 100644
index 000000000000..9337da5d5d30
--- /dev/null
+++ b/lib/libc/net/sockatmark.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2002 William C. Fenner. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include "namespace.h"
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include "un-namespace.h"
+
+int sockatmark(int s)
+{
+ int atmark;
+
+ if (_ioctl(s, SIOCATMARK, &atmark) == -1)
+ return -1;
+ return atmark;
+}
diff --git a/lib/libc/net/sourcefilter.3 b/lib/libc/net/sourcefilter.3
new file mode 100644
index 000000000000..a123ff38d68e
--- /dev/null
+++ b/lib/libc/net/sourcefilter.3
@@ -0,0 +1,239 @@
+.\" Copyright (c) 2007-2009 Bruce Simpson.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd February 13, 2009
+.Dt SOURCEFILTER 3
+.Os
+.Sh NAME
+.Nm sourcefilter
+.Nd advanced multicast group membership API
+.Sh SYNOPSIS
+.In sys/socket.h
+.In netinet/in.h
+.Ft int
+.Fo getipv4sourcefilter
+.Fa "int s"
+.Fa "struct in_addr interface"
+.Fa "struct in_addr group"
+.Fa "uint32_t *fmode"
+.Fa "uint32_t *numsrc"
+.Fa "struct in_addr *slist"
+.Fc
+.Ft int
+.Fo getsourcefilter
+.Fa "int s"
+.Fa "uint32_t interface"
+.Fa "struct sockaddr *group"
+.Fa "socklen_t grouplen"
+.Fa "uint32_t *fmode"
+.Fa "uint32_t *numsrc"
+.Fa "struct sockaddr_storage *slist"
+.Fc
+.Ft int
+.Fo setipv4sourcefilter
+.Fa "int s"
+.Fa "struct in_addr interface"
+.Fa "struct in_addr group"
+.Fa "uint32_t fmode"
+.Fa "uint32_t numsrc"
+.Fa "struct in_addr *slist"
+.Fc
+.Ft int
+.Fo setsourcefilter
+.Fa "int s"
+.Fa "uint32_t interface"
+.Fa "struct sockaddr *group"
+.Fa "socklen_t grouplen"
+.Fa "uint32_t fmode"
+.Fa "uint32_t numsrc"
+.Fa "struct sockaddr_storage *slist"
+.Fc
+.Sh DESCRIPTION
+The
+.Nm
+functions implement the advanced, full-state multicast API
+defined in RFC 3678.
+An application may use these functions to atomically set and
+retrieve the multicast source address filters associated with a socket
+.Fa s
+and a multicast
+.Fa group .
+.Pp
+The functions
+.Fn getipv4sourcefilter
+and
+.Fn getsourcefilter
+allow an application to discover the filter mode, and
+source filter entries,
+for an existing group membership.
+.Pp
+The kernel will always return the number of source filter
+entries on the socket for that group in
+.Fa *numsrc .
+If the
+.Fa *numsrc
+argument is non-zero, the kernel will attempt to return up to
+.Fa *numsrc
+filter entries in the array pointed to by
+.Fa slist .
+The
+.Fa *numsrc
+argument may be set to 0, in which case the
+.Fa slist
+argument will be ignored.
+.Pp
+For the
+.Fn setipv4sourcefilter
+and
+.Fn setsourcefilter
+functions,
+the
+.Fa fmode
+argument may be used to place the socket into inclusive or exclusive
+group membership modes, by using the
+.Dv MCAST_INCLUDE
+or
+.Dv MCAST_EXCLUDE
+constants respectively.
+The
+.Fa numsrc
+argument specifies the number of source entries in the
+.Fa slist
+array.
+If the
+.Fa numsrc
+argument has a value of 0,
+all source filters will be removed from the socket.
+Removing all source filters from a membership which is in the
+.Dv MCAST_INCLUDE
+filter mode will cause the group to be left on that socket.
+.Pp
+The protocol-independent function
+.Fn setsourcefilter
+allows an application to join a multicast group on an interface
+which may not have an assigned protocol address,
+by passing its index for the
+.Fa interface
+argument.
+.Pp
+Any changes made by these functions
+will be communicated to IGMPv3 and/or MLDv2 routers
+on the local network as appropriate.
+If no IGMPv3 or MLDv2 routers are present, changes in the source filter
+lists made by these functions will not cause
+state changes to be transmitted, with the exception of any
+change which causes a group to be joined or left.
+The kernel will continue to maintain the source filter state
+regardless of the IGMP or MLD version in use on the link.
+.Sh IMPLEMENTATION NOTES
+The IPv4 specific versions of these functions are implemented in terms
+of the protocol-independent functions.
+Application writers are encouraged to use the protocol-independent functions
+for efficiency, and forwards compatibility with IPv6 networks.
+.Pp
+For the protocol-independent functions
+.Fn getsourcefilter
+and
+.Fn setsourcefilter ,
+the
+.Fa grouplen
+argument specifies the size of the structure pointed to by
+.Fa group .
+This is required in order to differentiate between different
+address families.
+.Pp
+Currently
+.Fx
+does not support source address selection for the IPv4
+protocol family, therefore the use of multicast APIs with
+an unnumbered IPv4 interface is
+.Em not recommended.
+In all cases, the first assigned IPv4 address on the interface
+will be used as the source address of IGMP control traffic.
+If this address is removed or changed, the results are undefined.
+.Sh RETURN VALUES
+.Rv -std getsourcefilter getipv4sourcefilter setsourcefilter setipv4sourcefilter
+.Sh ERRORS
+The
+.Nm
+functions may fail because of:
+.Bl -tag -width Er
+.It Bq Er EADDRNOTAVAIL
+The network interface which the
+.Dv interface
+argument refers to was not configured in the system,
+or the system is not a member of the
+.Dv group .
+.It Bq Er EAFNOSUPPORT
+The
+.Dv group
+and/or one or more of the
+.Dv slist
+arguments were of an address family unsupported by the system,
+or the address family of the
+.Dv group
+and
+.Dv slist
+arguments were not identical.
+.It Bq Er EINVAL
+The
+.Dv group
+argument does not contain a multicast address.
+The
+.Dv fmode
+argument is invalid; it must be set to either
+.Dv MCAST_INCLUDE
+or
+.Dv MCAST_EXCLUDE .
+The
+.Dv numsrc
+or
+.Dv slist
+arguments do not specify a source list.
+.It Bq Er ENOMEM
+Insufficient memory was available to carry out the requested
+operation.
+.El
+.Sh SEE ALSO
+.Xr ip 4 ,
+.Xr ip6 4 ,
+.Xr multicast 4 ,
+.Xr ifmcstat 8
+.Rs
+.%A D. Thaler
+.%A B. Fenner
+.%A B. Quinn
+.%T "Socket Interface Extensions for Multicast Source Filters"
+.%N RFC 3678
+.%D Jan 2004
+.Re
+.Sh HISTORY
+The
+.Nm
+functions first appeared in
+.Fx 7.0 .
+.Sh AUTHORS
+.An Bruce M. Simpson Aq Mt bms@FreeBSD.org
diff --git a/lib/libc/net/sourcefilter.c b/lib/libc/net/sourcefilter.c
new file mode 100644
index 000000000000..50a73d87dad3
--- /dev/null
+++ b/lib/libc/net/sourcefilter.c
@@ -0,0 +1,402 @@
+/*-
+ * Copyright (c) 2007-2009 Bruce Simpson.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <net/if_dl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <ifaddrs.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "un-namespace.h"
+
+/*
+ * Advanced (Full-state) multicast group membership APIs [RFC3678]
+ * Currently this module assumes IPv4 support (INET) in the base system.
+ */
+#ifndef INET
+#define INET
+#endif
+
+union sockunion {
+ struct sockaddr_storage ss;
+ struct sockaddr sa;
+ struct sockaddr_dl sdl;
+#ifdef INET
+ struct sockaddr_in sin;
+#endif
+#ifdef INET6
+ struct sockaddr_in6 sin6;
+#endif
+};
+typedef union sockunion sockunion_t;
+
+#ifndef MIN
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#endif
+
+/*
+ * Internal: Map an IPv4 unicast address to an interface index.
+ * This is quite inefficient so it is recommended applications use
+ * the newer, more portable, protocol independent API.
+ */
+static uint32_t
+__inaddr_to_index(in_addr_t ifaddr)
+{
+ struct ifaddrs *ifa;
+ struct ifaddrs *ifaddrs;
+ char *ifname;
+ int ifindex;
+ sockunion_t *psu;
+
+ if (getifaddrs(&ifaddrs) < 0)
+ return (0);
+
+ ifindex = 0;
+ ifname = NULL;
+
+ /*
+ * Pass #1: Find the ifaddr entry corresponding to the
+ * supplied IPv4 address. We should really use the ifindex
+ * consistently for matches, however it is not available to
+ * us on this pass.
+ */
+ for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
+ psu = (sockunion_t *)ifa->ifa_addr;
+ if (psu && psu->ss.ss_family == AF_INET &&
+ psu->sin.sin_addr.s_addr == ifaddr) {
+ ifname = ifa->ifa_name;
+ break;
+ }
+ }
+ if (ifname == NULL)
+ goto out;
+
+ /*
+ * Pass #2: Find the index of the interface matching the name
+ * we obtained from looking up the IPv4 ifaddr in pass #1.
+ * There must be a better way of doing this.
+ */
+ for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
+ psu = (sockunion_t *)ifa->ifa_addr;
+ if (psu && psu->ss.ss_family == AF_LINK &&
+ strcmp(ifa->ifa_name, ifname) == 0) {
+ ifindex = LLINDEX(&psu->sdl);
+ break;
+ }
+ }
+ assert(ifindex != 0);
+
+out:
+ freeifaddrs(ifaddrs);
+ return (ifindex);
+}
+
+/*
+ * Set IPv4 source filter list in use on socket.
+ *
+ * Stubbed to setsourcefilter(). Performs conversion of structures which
+ * may be inefficient; applications are encouraged to use the
+ * protocol-independent API.
+ */
+int
+setipv4sourcefilter(int s, struct in_addr interface, struct in_addr group,
+ uint32_t fmode, uint32_t numsrc, struct in_addr *slist)
+{
+#ifdef INET
+ sockunion_t tmpgroup;
+ struct in_addr *pina;
+ sockunion_t *psu, *tmpslist;
+ int err;
+ size_t i;
+ uint32_t ifindex;
+
+ assert(s != -1);
+
+ tmpslist = NULL;
+
+ if (!IN_MULTICAST(ntohl(group.s_addr)) ||
+ (fmode != MCAST_INCLUDE && fmode != MCAST_EXCLUDE)) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ ifindex = __inaddr_to_index(interface.s_addr);
+ if (ifindex == 0) {
+ errno = EADDRNOTAVAIL;
+ return (-1);
+ }
+
+ memset(&tmpgroup, 0, sizeof(sockunion_t));
+ tmpgroup.sin.sin_family = AF_INET;
+ tmpgroup.sin.sin_len = sizeof(struct sockaddr_in);
+ tmpgroup.sin.sin_addr = group;
+
+ if (numsrc != 0 || slist != NULL) {
+ tmpslist = calloc(numsrc, sizeof(sockunion_t));
+ if (tmpslist == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+
+ pina = slist;
+ psu = tmpslist;
+ for (i = 0; i < numsrc; i++, pina++, psu++) {
+ psu->sin.sin_family = AF_INET;
+ psu->sin.sin_len = sizeof(struct sockaddr_in);
+ psu->sin.sin_addr = *pina;
+ }
+ }
+
+ err = setsourcefilter(s, ifindex, (struct sockaddr *)&tmpgroup,
+ sizeof(struct sockaddr_in), fmode, numsrc,
+ (struct sockaddr_storage *)tmpslist);
+
+ if (tmpslist != NULL)
+ free(tmpslist);
+
+ return (err);
+#else /* !INET */
+ return (EAFNOSUPPORT);
+#endif /* INET */
+}
+
+/*
+ * Get IPv4 source filter list in use on socket.
+ *
+ * Stubbed to getsourcefilter(). Performs conversion of structures which
+ * may be inefficient; applications are encouraged to use the
+ * protocol-independent API.
+ * An slist of NULL may be used for guessing the required buffer size.
+ */
+int
+getipv4sourcefilter(int s, struct in_addr interface, struct in_addr group,
+ uint32_t *fmode, uint32_t *numsrc, struct in_addr *slist)
+{
+ sockunion_t *psu, *tmpslist;
+ sockunion_t tmpgroup;
+ struct in_addr *pina;
+ int err;
+ size_t i;
+ uint32_t ifindex, onumsrc;
+
+ assert(s != -1);
+ assert(fmode != NULL);
+ assert(numsrc != NULL);
+
+ onumsrc = *numsrc;
+ *numsrc = 0;
+ tmpslist = NULL;
+
+ if (!IN_MULTICAST(ntohl(group.s_addr)) ||
+ (onumsrc != 0 && slist == NULL)) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ ifindex = __inaddr_to_index(interface.s_addr);
+ if (ifindex == 0) {
+ errno = EADDRNOTAVAIL;
+ return (-1);
+ }
+
+ memset(&tmpgroup, 0, sizeof(sockunion_t));
+ tmpgroup.sin.sin_family = AF_INET;
+ tmpgroup.sin.sin_len = sizeof(struct sockaddr_in);
+ tmpgroup.sin.sin_addr = group;
+
+ if (onumsrc != 0 || slist != NULL) {
+ tmpslist = calloc(onumsrc, sizeof(sockunion_t));
+ if (tmpslist == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ }
+
+ err = getsourcefilter(s, ifindex, (struct sockaddr *)&tmpgroup,
+ sizeof(struct sockaddr_in), fmode, numsrc,
+ (struct sockaddr_storage *)tmpslist);
+
+ if (tmpslist != NULL && *numsrc != 0) {
+ pina = slist;
+ psu = tmpslist;
+ for (i = 0; i < MIN(onumsrc, *numsrc); i++, psu++) {
+ if (psu->ss.ss_family != AF_INET)
+ continue;
+ *pina++ = psu->sin.sin_addr;
+ }
+ free(tmpslist);
+ }
+
+ return (err);
+}
+
+/*
+ * Set protocol-independent source filter list in use on socket.
+ */
+int
+setsourcefilter(int s, uint32_t interface, struct sockaddr *group,
+ socklen_t grouplen, uint32_t fmode, uint32_t numsrc,
+ struct sockaddr_storage *slist)
+{
+ struct __msfilterreq msfr;
+ sockunion_t *psu;
+ int level, optname;
+
+ if (fmode != MCAST_INCLUDE && fmode != MCAST_EXCLUDE) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ psu = (sockunion_t *)group;
+ switch (psu->ss.ss_family) {
+#ifdef INET
+ case AF_INET:
+ if ((grouplen != sizeof(struct sockaddr_in) ||
+ !IN_MULTICAST(ntohl(psu->sin.sin_addr.s_addr)))) {
+ errno = EINVAL;
+ return (-1);
+ }
+ level = IPPROTO_IP;
+ optname = IP_MSFILTER;
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ if (grouplen != sizeof(struct sockaddr_in6) ||
+ !IN6_IS_ADDR_MULTICAST(&psu->sin6.sin6_addr)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ level = IPPROTO_IPV6;
+ optname = IPV6_MSFILTER;
+ break;
+#endif
+ default:
+ errno = EAFNOSUPPORT;
+ return (-1);
+ }
+
+ memset(&msfr, 0, sizeof(msfr));
+ msfr.msfr_ifindex = interface;
+ msfr.msfr_fmode = fmode;
+ msfr.msfr_nsrcs = numsrc;
+ memcpy(&msfr.msfr_group, &psu->ss, psu->ss.ss_len);
+ msfr.msfr_srcs = slist; /* pointer */
+
+ return (_setsockopt(s, level, optname, &msfr, sizeof(msfr)));
+}
+
+/*
+ * Get protocol-independent source filter list in use on socket.
+ * An slist of NULL may be used for guessing the required buffer size.
+ */
+int
+getsourcefilter(int s, uint32_t interface, struct sockaddr *group,
+ socklen_t grouplen, uint32_t *fmode, uint32_t *numsrc,
+ struct sockaddr_storage *slist)
+{
+ struct __msfilterreq msfr;
+ sockunion_t *psu;
+ socklen_t optlen;
+ int err, level, nsrcs, optname;
+
+ if (interface == 0 || group == NULL || numsrc == NULL ||
+ fmode == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ nsrcs = *numsrc;
+ *numsrc = 0;
+ *fmode = 0;
+
+ psu = (sockunion_t *)group;
+ switch (psu->ss.ss_family) {
+#ifdef INET
+ case AF_INET:
+ if ((grouplen != sizeof(struct sockaddr_in) ||
+ !IN_MULTICAST(ntohl(psu->sin.sin_addr.s_addr)))) {
+ errno = EINVAL;
+ return (-1);
+ }
+ level = IPPROTO_IP;
+ optname = IP_MSFILTER;
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ if (grouplen != sizeof(struct sockaddr_in6) ||
+ !IN6_IS_ADDR_MULTICAST(&psu->sin6.sin6_addr)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ level = IPPROTO_IPV6;
+ optname = IPV6_MSFILTER;
+ break;
+#endif
+ default:
+ errno = EAFNOSUPPORT;
+ return (-1);
+ break;
+ }
+
+ optlen = sizeof(struct __msfilterreq);
+ memset(&msfr, 0, optlen);
+ msfr.msfr_ifindex = interface;
+ msfr.msfr_fmode = 0;
+ msfr.msfr_nsrcs = nsrcs;
+ memcpy(&msfr.msfr_group, &psu->ss, psu->ss.ss_len);
+
+ /*
+ * msfr_srcs is a pointer to a vector of sockaddr_storage. It
+ * may be NULL. The kernel will always return the total number
+ * of filter entries for the group in msfr.msfr_nsrcs.
+ */
+ msfr.msfr_srcs = slist;
+ err = _getsockopt(s, level, optname, &msfr, &optlen);
+ if (err == 0) {
+ *numsrc = msfr.msfr_nsrcs;
+ *fmode = msfr.msfr_fmode;
+ }
+
+ return (err);
+}
diff --git a/lib/libc/net/vars.c b/lib/libc/net/vars.c
new file mode 100644
index 000000000000..42ee2054d4e7
--- /dev/null
+++ b/lib/libc/net/vars.c
@@ -0,0 +1,45 @@
+/* $KAME: vars.c,v 1.2 2001/08/20 02:32:41 itojun Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <netinet/in.h>
+
+/*
+ * Definitions of some costant IPv6 addresses.
+ */
+const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
+const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
+const struct in6_addr in6addr_nodelocal_allnodes = IN6ADDR_NODELOCAL_ALLNODES_INIT;
+const struct in6_addr in6addr_linklocal_allnodes = IN6ADDR_LINKLOCAL_ALLNODES_INIT;
+
diff --git a/lib/libc/nls/C.msg b/lib/libc/nls/C.msg
new file mode 100644
index 000000000000..d08c5719225e
--- /dev/null
+++ b/lib/libc/nls/C.msg
@@ -0,0 +1,301 @@
+$ $FreeBSD$
+$
+$ Message catalog for C locale (template)
+$
+$ strerror() support catalog
+$
+$set 1
+$ EPERM
+1 Operation not permitted
+$ ENOENT
+2 No such file or directory
+$ ESRCH
+3 No such process
+$ EINTR
+4 Interrupted system call
+$ EIO
+5 Input/output error
+$ ENXIO
+6 Device not configured
+$ E2BIG
+7 Argument list too long
+$ ENOEXEC
+8 Exec format error
+$ EBADF
+9 Bad file descriptor
+$ ECHILD
+10 No child processes
+$ EDEADLK
+11 Resource deadlock avoided
+$ ENOMEM
+12 Cannot allocate memory
+$ EACCES
+13 Permission denied
+$ EFAULT
+14 Bad address
+$ ENOTBLK
+15 Block device required
+$ EBUSY
+16 Device busy
+$ EEXIST
+17 File exists
+$ EXDEV
+18 Cross-device link
+$ ENODEV
+19 Operation not supported by device
+$ ENOTDIR
+20 Not a directory
+$ EISDIR
+21 Is a directory
+$ EINVAL
+22 Invalid argument
+$ ENFILE
+23 Too many open files in system
+$ EMFILE
+24 Too many open files
+$ ENOTTY
+25 Inappropriate ioctl for device
+$ ETXTBSY
+26 Text file busy
+$ EFBIG
+27 File too large
+$ ENOSPC
+28 No space left on device
+$ ESPIPE
+29 Illegal seek
+$ EROFS
+30 Read-only file system
+$ EMLINK
+31 Too many links
+$ EPIPE
+32 Broken pipe
+$ EDOM
+33 Numerical argument out of domain
+$ ERANGE
+34 Result too large
+$ EAGAIN, EWOULDBLOCK
+35 Resource temporarily unavailable
+$ EINPROGRESS
+36 Operation now in progress
+$ EALREADY
+37 Operation already in progress
+$ ENOTSOCK
+38 Socket operation on non-socket
+$ EDESTADDRREQ
+39 Destination address required
+$ EMSGSIZE
+40 Message too long
+$ EPROTOTYPE
+41 Protocol wrong type for socket
+$ ENOPROTOOPT
+42 Protocol not available
+$ EPROTONOSUPPORT
+43 Protocol not supported
+$ ESOCKTNOSUPPORT
+44 Socket type not supported
+$ EOPNOTSUPP
+45 Operation not supported
+$ EPFNOSUPPORT
+46 Protocol family not supported
+$ EAFNOSUPPORT
+47 Address family not supported by protocol family
+$ EADDRINUSE
+48 Address already in use
+$ EADDRNOTAVAIL
+49 Can't assign requested address
+$ ENETDOWN
+50 Network is down
+$ ENETUNREACH
+51 Network is unreachable
+$ ENETRESET
+52 Network dropped connection on reset
+$ ECONNABORTED
+53 Software caused connection abort
+$ ECONNRESET
+54 Connection reset by peer
+$ ENOBUFS
+55 No buffer space available
+$ EISCONN
+56 Socket is already connected
+$ ENOTCONN
+57 Socket is not connected
+$ ESHUTDOWN
+58 Can't send after socket shutdown
+$ ETOOMANYREFS
+59 Too many references: can't splice
+$ ETIMEDOUT
+60 Operation timed out
+$ ECONNREFUSED
+61 Connection refused
+$ ELOOP
+62 Too many levels of symbolic links
+$ ENAMETOOLONG
+63 File name too long
+$ EHOSTDOWN
+64 Host is down
+$ EHOSTUNREACH
+65 No route to host
+$ ENOTEMPTY
+66 Directory not empty
+$ EPROCLIM
+67 Too many processes
+$ EUSERS
+68 Too many users
+$ EDQUOT
+69 Disc quota exceeded
+$ ESTALE
+70 Stale NFS file handle
+$ EREMOTE
+71 Too many levels of remote in path
+$ EBADRPC
+72 RPC struct is bad
+$ ERPCMISMATCH
+73 RPC version wrong
+$ EPROGUNAVAIL
+74 RPC prog. not avail
+$ EPROGMISMATCH
+75 Program version wrong
+$ EPROCUNAVAIL
+76 Bad procedure for program
+$ ENOLCK
+77 No locks available
+$ ENOSYS
+78 Function not implemented
+$ EFTYPE
+79 Inappropriate file type or format
+$ EAUTH
+80 Authentication error
+$ ENEEDAUTH
+81 Need authenticator
+$ EIDRM
+82 Identifier removed
+$ ENOMSG
+83 No message of desired type
+$ EOVERFLOW
+84 Value too large to be stored in data type
+$ ECANCELED
+85 Operation canceled
+$ EILSEQ
+86 Illegal byte sequence
+$ ENOATTR
+87 Attribute not found
+$ EDOOFUS
+88 Programming error
+$ EBADMSG
+89 Bad message
+$ EMULTIHOP
+90 Multihop attempted
+$ ENOLINK
+91 Link has been severed
+$ EPROTO
+92 Protocol error
+$ ENOTCAPABLE
+93 Capabilities insufficient
+$ ECAPMODE
+94 Not permitted in capability mode
+$ ENOTRECOVERABLE
+95 State not recoverable
+$ EOWNERDEAD
+96 Previous owner died
+$
+$ strsignal() support catalog
+$
+$set 2
+$ SIGHUP
+1 Hangup
+$ SIGINT
+2 Interrupt
+$ SIGQUIT
+3 Quit
+$ SIGILL
+4 Illegal instruction
+$ SIGTRAP
+5 Trace/BPT trap
+$ SIGABRT
+6 Abort trap
+$ SIGEMT
+7 EMT trap
+$ SIGFPE
+8 Floating point exception
+$ SIGKILL
+9 Killed
+$ SIGBUS
+10 Bus error
+$ SIGSEGV
+11 Segmentation fault
+$ SIGSYS
+12 Bad system call
+$ SIGPIPE
+13 Broken pipe
+$ SIGALRM
+14 Alarm clock
+$ SIGTERM
+15 Terminated
+$ SIGURG
+16 Urgent I/O condition
+$ SIGSTOP
+17 Suspended (signal)
+$ SIGTSTP
+18 Suspended
+$ SIGCONT
+19 Continued
+$ SIGCHLD
+20 Child exited
+$ SIGTTIN
+21 Stopped (tty input)
+$ SIGTTOU
+22 Stopped (tty output)
+$ SIGIO
+23 I/O possible
+$ SIGXCPU
+24 Cputime limit exceeded
+$ SIGXFSZ
+25 Filesize limit exceeded
+$ SIGVTALRM
+26 Virtual timer expired
+$ SIGPROF
+27 Profiling timer expired
+$ SIGWINCH
+28 Window size changes
+$ SIGINFO
+29 Information request
+$ SIGUSR1
+30 User defined signal 1
+$ SIGUSR2
+31 User defined signal 2
+$
+$ gai_strerror() support catalog
+$
+$set 3
+$ 1 (obsolete)
+1 Address family for hostname not supported
+$ EAI_AGAIN
+2 Temporary failure in name resolution
+$ EAI_BADFLAGS
+3 Invalid value for ai_flags
+$ EAI_FAIL
+4 Non-recoverable failure in name resolution
+$ EAI_FAMILY
+5 ai_family not supported
+$ EAI_MEMORY
+6 Memory allocation failure
+$ 7 (obsolete)
+7 No address associated with hostname
+$ EAI_NONAME
+8 hostname nor servname provided, or not known
+$ EAI_SERVICE
+9 servname not supported for ai_socktype
+$ EAI_SOCKTYPE
+10 ai_socktype not supported
+$ EAI_SYSTEM
+11 System error returned in errno
+$ EAI_BADHINTS
+12 Invalid value for hints
+$ EAI_PROTOCOL
+13 Resolved protocol is unknown
+$ EAI_OVERFLOW
+14 Argument buffer overflow
+$ 0
+32766 Success
+$ NL_MSGMAX
+32767 Unknown error
diff --git a/lib/libc/nls/Makefile.inc b/lib/libc/nls/Makefile.inc
new file mode 100644
index 000000000000..2734e51fe216
--- /dev/null
+++ b/lib/libc/nls/Makefile.inc
@@ -0,0 +1,41 @@
+# from $NetBSD: Makefile.inc,v 1.7 1995/02/27 13:06:20 cgd Exp $
+# $FreeBSD$
+
+.PATH: ${LIBC_SRCTOP}/nls
+
+SRCS+= msgcat.c
+
+SYM_MAPS+=${LIBC_SRCTOP}/nls/Symbol.map
+
+MAN+= catclose.3 catgets.3 catopen.3
+
+# NOTE: C.msg should not be processed here, it's used as a template
+# for translators.
+
+NLSNAME= libc
+NLS+= be_BY.UTF-8
+NLS+= ca_ES.ISO8859-1
+NLS+= de_DE.ISO8859-1
+NLS+= el_GR.ISO8859-7
+NLS+= es_ES.ISO8859-1
+NLS+= fi_FI.ISO8859-1
+NLS+= fr_FR.ISO8859-1
+NLS+= gl_ES.ISO8859-1
+NLS+= hu_HU.ISO8859-2
+NLS+= it_IT.ISO8859-15
+NLS+= ja_JP.UTF-8
+NLS+= ja_JP.eucJP
+NLS+= ko_KR.UTF-8
+NLS+= ko_KR.eucKR
+NLS+= mn_MN.UTF-8
+NLS+= nl_NL.ISO8859-1
+NLS+= no_NO.ISO8859-1
+NLS+= pl_PL.ISO8859-2
+NLS+= pt_BR.ISO8859-1
+NLS+= ru_RU.KOI8-R
+NLS+= sk_SK.ISO8859-2
+NLS+= sv_SE.ISO8859-1
+NLS+= uk_UA.UTF-8
+NLS+= zh_CN.GB18030
+NLS+= zh_CN.GB2312
+NLS+= zh_CN.UTF-8
diff --git a/lib/libc/nls/Symbol.map b/lib/libc/nls/Symbol.map
new file mode 100644
index 000000000000..818466e6ffb1
--- /dev/null
+++ b/lib/libc/nls/Symbol.map
@@ -0,0 +1,9 @@
+/*
+ * $FreeBSD$
+ */
+
+FBSD_1.0 {
+ catopen;
+ catgets;
+ catclose;
+};
diff --git a/lib/libc/nls/be_BY.UTF-8.msg b/lib/libc/nls/be_BY.UTF-8.msg
new file mode 100644
index 000000000000..56bd038aca48
--- /dev/null
+++ b/lib/libc/nls/be_BY.UTF-8.msg
@@ -0,0 +1,249 @@
+$ $FreeBSD$
+$
+$ Message catalog for be_BY.UTF-8 locale
+$
+$ strerror() support catalog
+$
+$set 1
+$ EPERM
+1 ÐÐ¿ÐµÑ€Ð°Ñ†Ñ‹Ñ Ð½Ðµ дазволена
+$ ENOENT
+2 ÐÑма такога файлу ці каталогу
+$ ESRCH
+3 ÐÑма такога працÑÑу
+$ EINTR
+4 Перарваны ÑÑ–ÑÑ‚Ñмны выклік
+$ EIO
+5 Памылка ўводу/вываду
+$ ENXIO
+6 ПрыÑтаÑаванне не Ñканфігуравана
+$ E2BIG
+7 Ðадта доўгі ÑÐ¿Ñ–Ñ Ð°Ñ€Ð³ÑƒÐ¼ÐµÐ½Ñ‚Ð°Ñž
+$ ENOEXEC
+8 Памылка фармату файлу, Ñкі выконваецца
+$ EBADF
+9 ÐекарÑктны дÑÑкрыптар файлу
+$ ECHILD
+10 ÐÑма дачÑрніх працÑÑаў
+$ EDEADLK
+11 Прадухілена ÑžÐ·Ð°ÐµÐ¼Ð½Ð°Ñ Ð±Ð»Ð°ÐºÑ–Ñ€Ð¾ÑžÐºÐ° Ð¿Ð°Ð´Ñ‡Ð°Ñ Ð´Ð¾Ñтупу да Ñ€ÑÑурÑу
+$ ENOMEM
+12 Ðе даÑтае памÑці
+$ EACCES
+13 Ðе даÑтае прывілеÑÑž
+$ EFAULT
+14 ÐекарÑктны адраÑ
+$ ENOTBLK
+15 Ðеабходна блочнае прыÑтаÑаванне
+$ EBUSY
+16 ПрыÑтаÑаванне занÑтае
+$ EEXIST
+17 Файл Ñ–Ñнуе
+$ EXDEV
+18 СпаÑылка на іншае прыÑтаÑаванне
+$ ENODEV
+19 ÐÐ¿ÐµÑ€Ð°Ñ†Ñ‹Ñ Ð½Ðµ падтрымліваецца прыÑтаÑаваннем
+$ ENOTDIR
+20 Пазначаны файл не з'ÑўлÑецца каталогам
+$ EISDIR
+21 Пазначаны файл з'ÑўлÑецца каталогам
+$ EINVAL
+22 Ðедапушчальны аргумент
+$ ENFILE
+23 Ðадта шмат адчыненых файлаў у ÑÑ–ÑÑ‚Ñме
+$ EMFILE
+24 Ðадта шмат адчыненых файлаў
+$ ENOTTY
+25 Выклік ioctl не падтрымліваецца прыÑтаÑаваннем
+$ ETXTBSY
+26 ТекÑтавы файл занÑÑ‚Ñ‹
+$ EFBIG
+27 Ðадта вÑлікі файл
+$ ENOSPC
+28 Ðа прыÑтаÑаванні не заÑталоÑÑ Ð¼ÐµÑца
+$ ESPIPE
+29 Ðедапушчальнае пазіцыÑнаванне
+$ EROFS
+30 Ð¤Ð°Ð¹Ð»Ð°Ð²Ð°Ñ ÑÑ–ÑÑ‚Ñма толькі Ð´Ð»Ñ Ñ‡Ñ‹Ñ‚Ð°Ð½Ð½Ñ
+$ EMLINK
+31 Ðадта шмат ÑпаÑылак
+$ EPIPE
+32 Канал пашкоджаны
+$ EDOM
+33 Ðедапушчальнае значÑнне лічбавага аргументу
+$ ERANGE
+34 Ðадта вÑлікі Ñ€Ñзультат
+$ EAGAIN, EWOULDBLOCK
+35 РÑÑÑƒÑ€Ñ Ñ‡Ð°Ñова недаÑтупны
+$ EINPROGRESS
+36 ÐÐ¿ÐµÑ€Ð°Ñ†Ñ‹Ñ Ñž працÑÑе выкананнÑ
+$ EALREADY
+37 ÐÐ¿ÐµÑ€Ð°Ñ†Ñ‹Ñ ÑžÐ¶Ð¾ выконваецца
+$ ENOTSOCK
+38 ÐÐ¿ÐµÑ€Ð°Ñ†Ñ‹Ñ Ð· Ñокетам прыменена не да Ñокету
+$ EDESTADDRREQ
+39 Патрабуецца Ð°Ð´Ñ€Ð°Ñ Ð¿Ñ€Ñ‹Ð·Ð½Ð°Ñ‡ÑннÑ
+$ EMSGSIZE
+40 Ðадта доўгае паведамленне
+$ EPROTOTYPE
+41 ÐÑправільны тып пратаколу Ð´Ð»Ñ Ñокету
+$ ENOPROTOOPT
+42 Пратакол недаÑтупны
+$ EPROTONOSUPPORT
+43 Пратакол не падтрымліваецца
+$ ESOCKTNOSUPPORT
+44 Тып Ñокету не падтрымліваецца
+$ EOPNOTSUPP
+45 ÐÐ¿ÐµÑ€Ð°Ñ†Ñ‹Ñ Ð½Ðµ падтрымліваецца
+$ EPFNOSUPPORT
+46 СÑмейÑтва пратаколаў не падтрымліваецца
+$ EAFNOSUPPORT
+47 СÑмейÑтва адраÑоў не падтрымліваецца ÑÑмейÑтвам пратаколаў
+$ EADDRINUSE
+48 ÐÐ´Ñ€Ð°Ñ ÑžÐ¶Ð¾ выкарыÑтоўваецца
+$ EADDRNOTAVAIL
+49 Ðе магчыма прызначыць дадзены адраÑ
+$ ENETDOWN
+50 Сетка не працуе
+$ ENETUNREACH
+51 Сетка недаÑÑжна
+$ ENETRESET
+52 ЗлучÑнне прыпынена Ñеткай
+$ ECONNABORTED
+53 Праграма выклікала аварыйнае завÑршÑнне злучÑннÑ
+$ ECONNRESET
+54 ЗлучÑнне завÑршана Ñупрацьлеглым бокам
+$ ENOBUFS
+55 Ðе заÑталоÑÑ Ð¼ÐµÑца пад буфер
+$ EISCONN
+56 Сокет ужо падлучаны
+$ ENOTCONN
+57 Сокет не падлучаны
+$ ESHUTDOWN
+58 Ðе магчыма даÑылаць паÑÐ»Ñ Ð·Ð°ÐºÑ€Ñ‹Ñ†Ñ†Ñ Ñокету
+$ ETOOMANYREFS
+59 Ðадта шмат ÑпаÑылак: не магчыма злучыць
+$ ETIMEDOUT
+60 ÐÐ¿ÐµÑ€Ð°Ñ†Ñ‹Ñ Ð¿ÐµÑ€Ð°Ð²Ñ‹Ñіла чаÑавы ліміт
+$ ECONNREFUSED
+61 У злучÑнні адмоўлена
+$ ELOOP
+62 Ðадта шмат узроўнÑÑž Ñімвальных ÑпаÑылак
+$ ENAMETOOLONG
+63 Ðадта доўгае Ñ–Ð¼Ñ Ñ„Ð°Ð¹Ð»Ñƒ
+$ EHOSTDOWN
+64 ХоÑÑ‚ не працуе
+$ EHOSTUNREACH
+65 ÐÑма маршруту да хоÑту
+$ ENOTEMPTY
+66 Каталог не пуÑÑ‚Ñ‹
+$ EPROCLIM
+67 Ðадта шмат працÑÑаў
+$ EUSERS
+68 Ðадта шмат карыÑтальнікаў
+$ EDQUOT
+69 Перавышана дыÑÐºÐ°Ð²Ð°Ñ ÐºÐ²Ð¾Ñ‚Ð°
+$ ESTALE
+70 СаÑтарÑлы дÑÑкрыптар файлу NFS
+$ EREMOTE
+71 Ðадта шмат дыÑтанцыйных пераходаў на шлÑху
+$ EBADRPC
+72 ÐекарÑÐºÑ‚Ð½Ð°Ñ Ñтруктура RPC
+$ ERPCMISMATCH
+73 ÐÑÐ¿Ñ€Ð°Ð²Ñ–Ð»ÑŒÐ½Ð°Ñ Ð²ÐµÑ€ÑÑ–Ñ RPC
+$ EPROGUNAVAIL
+74 Праграма RPC недаÑÑжнаÑ
+$ EPROGMISMATCH
+75 ÐÑÐ¿Ñ€Ð°Ð²Ñ–Ð»ÑŒÐ½Ð°Ñ Ð²ÐµÑ€ÑÑ–Ñ Ð¿Ñ€Ð°Ð³Ñ€Ð°Ð¼Ñ‹
+$ EPROCUNAVAIL
+76 ÐекарÑÐºÑ‚Ð½Ð°Ñ Ð¿Ñ€Ð°Ñ†Ñдура Ð´Ð»Ñ Ð¿Ñ€Ð°Ð³Ñ€Ð°Ð¼Ñ‹
+$ ENOLCK
+77 Блакіроўкі недаÑтупны
+$ ENOSYS
+78 Ð¤ÑƒÐ½ÐºÑ†Ñ‹Ñ Ð½Ðµ Ñ€Ñалізавана
+$ EFTYPE
+79 ÐепадыходзÑчы тып ці фармат файлу
+$ EAUTH
+80 Памылка аўтÑнтыфікацыі
+$ ENEEDAUTH
+81 Ðеабходна аўтÑнтыфікацыÑ
+$ EIDRM
+82 ІдÑнтыфікатар выдалены
+$ ENOMSG
+83 ÐÑма Ð¿Ð°Ð²ÐµÐ´Ð°Ð¼Ð»ÐµÐ½Ð½Ñ Ð¿Ð°Ñ‚Ñ€Ñбнага тыпу
+$ EOVERFLOW
+84 Ðадта вÑлікае значÑнне Ð´Ð»Ñ Ð·Ð°Ñ…Ð¾ÑžÐ²Ð°Ð½Ð½Ñ Ñž пазначаным тыпе дадзеных
+$ ECANCELED
+85 ÐÐ¿ÐµÑ€Ð°Ñ†Ñ‹Ñ Ð°Ð´Ð¼ÐµÐ½ÐµÐ½Ð°
+$ EILSEQ
+86 ÐÐµÐ´Ð°Ð·Ð²Ð¾Ð»ÐµÐ½Ð°Ñ Ð¿Ð°ÑлÑдоўнаÑць байтаў
+$ ENOATTR
+87 Ðтрыбут не знойдзены
+$ EDOOFUS
+88 Памылка праграмаваннÑ
+$
+$ strsignal() support catalog
+$
+$set 2
+$ SIGHUP
+1 Разрыў ÑувÑзі
+$ SIGINT
+2 Перарванне па Ñігналу
+$ SIGQUIT
+3 Выхад
+$ SIGILL
+4 ÐÐµÐ´Ð°Ð¿ÑƒÑˆÑ‡Ð°Ð»ÑŒÐ½Ð°Ñ Ñ–Ð½ÑтрукцыÑ
+$ SIGTRAP
+5 ПаÑтка траÑіроўкі/кропкі ÑпыненнÑ
+$ SIGABRT
+6 ПаÑтка аварыйнага завÑршÑннÑ
+$ SIGEMT
+7 ПаÑтка EMT
+$ SIGFPE
+8 Памылка Ð¿Ð°Ð´Ñ‡Ð°Ñ Ð¿Ñ€Ð°Ñ†Ñ‹ з Ñ€Ñчыўным лікам
+$ SIGKILL
+9 ПрымуÑова Ñпынены
+$ SIGBUS
+10 Памылка шыны
+$ SIGSEGV
+11 Памылка Ñегментацыі
+$ SIGSYS
+12 Ðедапушчальны ÑÑ–ÑÑ‚Ñмны выклік
+$ SIGPIPE
+13 Канал пашкоджаны
+$ SIGALRM
+14 Спрацаваў таймер
+$ SIGTERM
+15 Завершаны
+$ SIGURG
+16 Ðеабходны Ñ‚Ñрміновы ўвод-вывад
+$ SIGSTOP
+17 Прыпыненне (Ñігнал)
+$ SIGTSTP
+18 Прыпыненне
+$ SIGCONT
+19 ПрацÑг працы
+$ SIGCHLD
+20 Завершана праца дачÑрнÑга працÑÑу
+$ SIGTTIN
+21 Спынены (увод з Ñ‚Ñрміналу)
+$ SIGTTOU
+22 Спынены (увод на Ñ‚Ñрмінал)
+$ SIGIO
+23 Увод-вывад магчымы
+$ SIGXCPU
+24 Перавышана абмежаванне працÑÑарнага чаÑу
+$ SIGXFSZ
+25 Перавышаны макÑімальны памер файлу
+$ SIGVTALRM
+26 Вычарпаны віртуальны таймер
+$ SIGPROF
+27 Вычарпаны таймер прафілÑваннÑ
+$ SIGWINCH
+28 Змена памеру вакна
+$ SIGINFO
+29 Запыт інфармацыі
+$ SIGUSR1
+30 Сігнал карыÑтальніка 1
+$ SIGUSR2
+31 Сігнал карыÑтальніка 2
diff --git a/lib/libc/nls/ca_ES.ISO8859-1.msg b/lib/libc/nls/ca_ES.ISO8859-1.msg
new file mode 100644
index 000000000000..e786c29c6b26
--- /dev/null
+++ b/lib/libc/nls/ca_ES.ISO8859-1.msg
@@ -0,0 +1,267 @@
+$ $FreeBSD$
+$
+$ Message catalog for ca_ES.ISO8859-1 locale
+$
+$ strerror() support catalog
+$
+$set 1
+$ EPERM
+1 Operació no permesa
+$ ENOENT
+2 Arxiu o directori inexistent
+$ ESRCH
+3 Procés inexistent
+$ EINTR
+4 Crida del sistema interrompuda
+$ EIO
+5 Error d'entrada/sortida
+$ ENXIO
+6 Dispositiu no configurat
+$ E2BIG
+7 Llista de paràmetres massa llarga
+$ ENOEXEC
+8 Error en el format de l'executable
+$ EBADF
+9 Descriptor d'arxiu incorrecte
+$ ECHILD
+10 No hi ha processos fills
+$ EDEADLK
+11 S'ha evitat el bloqueig del recurs
+$ ENOMEM
+12 No es pot assignar la memòria demanada
+$ EACCES
+13 Permís denegat
+$ EFAULT
+14 Adreça incorrecta
+$ ENOTBLK
+15 Es necessita un dispositiu de blocs
+$ EBUSY
+16 Dispositiu ocupat
+$ EEXIST
+17 L'arxiu ja existeix
+$ EXDEV
+18 Enllaç entre dispositius
+$ ENODEV
+19 Operació no suportada pel dispositiu
+$ ENOTDIR
+20 No és un directori
+$ EISDIR
+21 És un directori
+$ EINVAL
+22 Paràmetre incorrecte
+$ ENFILE
+23 Hi ha massa arxius oberts al sistema
+$ EMFILE
+24 Hi ha massa arxius oberts
+$ ENOTTY
+25 L'ioctl no és adecuat per al dispositiu
+$ ETXTBSY
+26 Arxiu de text ocupat
+$ EFBIG
+27 Arxiu massa gran
+$ ENOSPC
+28 No queda espai lliure en el dispositiu
+$ ESPIPE
+29 Cerca il·legal
+$ EROFS
+30 Sistema d'arxius de només lectura
+$ EMLINK
+31 Massa enllaços
+$ EPIPE
+32 Canal (pipe) trencat
+$ EDOM
+33 El resultat surt fora de rang
+$ ERANGE
+34 Resultat massa gran
+$ EAGAIN, EWOULDBLOCK
+35 El recurs no està disponible temporalment
+$ EINPROGRESS
+36 L'operació es troba en progrés actualment
+$ EALREADY
+37 L'operació ja es troba en progrés
+$ ENOTSOCK
+38 Operació de tipus socket en quelcom que no ho és
+$ EDESTADDRREQ
+39 Es requereix l'adreça de destí
+$ EMSGSIZE
+40 Missatge massa llarg
+$ EPROTOTYPE
+41 Tipus de protocol incorrecte per al socket
+$ ENOPROTOOPT
+42 Protocol no disponible
+$ EPROTONOSUPPORT
+43 Protocol no suportat
+$ ESOCKTNOSUPPORT
+44 Tipus de socket no suportat
+$ EOPNOTSUPP
+45 Operació no suportada
+$ EPFNOSUPPORT
+46 Família de protocols no suportada
+$ EAFNOSUPPORT
+47 Família d'adreces no suportada per la família de protocols
+$ EADDRINUSE
+48 L'adreça ja es troba en ús
+$ EADDRNOTAVAIL
+49 No es pot assignar l'adreça demanada
+$ ENETDOWN
+50 La xarxa no es troba disponible
+$ ENETUNREACH
+51 No es pot accedir a la xarxa
+$ ENETRESET
+52 La connexió a la xarxa s'ha perdut durant la reinicialització
+$ ECONNABORTED
+53 El programari ha causat l'avort de la connexió
+$ ECONNRESET
+54 L'interlocutor ha reinicialitzat la comunicació
+$ ENOBUFS
+55 No hi ha prou espai per a la memoria intermèdia (buffer)
+$ EISCONN
+56 El socket ja es troba connectat
+$ ENOTCONN
+57 El socket no es troba connectat
+$ ESHUTDOWN
+58 No es pot enviar desprès de la desconnexió del socket
+$ ETOOMANYREFS
+59 Hi ha massa referències: no es poden unir
+$ ETIMEDOUT
+60 El temps de connexió s'ha esgotat
+$ ECONNREFUSED
+61 Connexió rebutjada
+$ ELOOP
+62 Hi ha massa nivells d'enllaços simbòlics
+$ ENAMETOOLONG
+63 Nom d'arxiu massa llarg
+$ EHOSTDOWN
+64 La màquina no es troba disponible
+$ EHOSTUNREACH
+65 No hi ha cap camí fins a la màquina
+$ ENOTEMPTY
+66 El directori no està buit
+$ EPROCLIM
+67 Hi ha massa processos
+$ EUSERS
+68 Hi ha massa usuaris
+$ EDQUOT
+69 Quota de disc sobrepassada
+$ ESTALE
+70 Descriptor d'arxiu NFS incorrecte
+$ EREMOTE
+71 Massa nivells en el camí de destí
+$ EBADRPC
+72 L'estructura RPC es incorrecta
+$ ERPCMISMATCH
+73 La versió del RPC es incorrecta
+$ EPROGUNAVAIL
+74 El programa RPC no es troba disponible
+$ EPROGMISMATCH
+75 Versió incorrecta del programa
+$ EPROCUNAVAIL
+76 Procediment erroni per al programa
+$ ENOLCK
+77 No hi ha bloquejos disponibles
+$ ENOSYS
+78 Funció no implementada
+$ EFTYPE
+79 Tipus d'arxiu o de format inadequat
+$ EAUTH
+80 Error d'autenticació
+$ ENEEDAUTH
+81 Es necessita un autenticador
+$ EIDRM
+82 Identificador eliminat
+$ ENOMSG
+83 No hi ha missatges del tipus desitjat
+$ EOVERFLOW
+84 Valor massa gran per a ésser emmagatzemat en el tipus de dades
+$ EILSEQ
+85 Seqüència de bytes il·legal
+$ ENOTSUP
+86 No suportat
+$ ECANCELED
+87 Operació cancel·lada
+$ EBADMSG
+88 Missatje incorrecte o corrupte
+$ ENODATA
+89 No hi ha missatges disponibles
+$ ENOSR
+90 No hi ha recursos de tipus STREAM
+$ ENOSTR
+91 No és un STREAM
+$ ETIME
+92 Temps d'espera esgotat en el ioctl STREAM
+$ ENOATTR
+93 Atribut inexistent
+$ EMULTIHOP
+94 S'ha intentat un multisalt
+$ ENOLINK
+95 L'enllaç s'ha servit
+$ EPROTO
+96 Error de protocol
+$
+$ strsignal() support catalog
+$
+$set 2
+$ SIGHUP
+1 Fí de línia (hangup)
+$ SIGINT
+2 Interrupció
+$ SIGQUIT
+3 Finalització
+$ SIGILL
+4 Instrucció il·legal
+$ SIGTRAP
+5 Depuració (Trace/BPT)
+$ SIGABRT
+6 Crida d'avort
+$ SIGEMT
+7 Captura d'EMT
+$ SIGFPE
+8 Excepció de coma flotant
+$ SIGKILL
+9 Matat
+$ SIGBUS
+10 Error del bus
+$ SIGSEGV
+11 Error de segmentació
+$ SIGSYS
+12 Crida al sistema incorrecta
+$ SIGPIPE
+13 Canal (pipe) trencat
+$ SIGALRM
+14 Alarma de rellotge
+$ SIGTERM
+15 Finalitzat
+$ SIGURG
+16 Condició urgent d'E/S
+$ SIGSTOP
+17 Parat (per senyal)
+$ SIGTSTP
+18 Parat
+$ SIGCONT
+19 Continuant
+$ SIGCHLD
+20 El fill ha acabat
+$ SIGTTIN
+21 Parat (entrada de tty)
+$ SIGTTOU
+22 Parat (sortida de tty)
+$ SIGIO
+23 I/O permesa
+$ SIGXCPU
+24 S'ha sobrepassat el límit de temps de la CPU
+$ SIGXFSZ
+25 S'ha sobrepassat el límit de la longitud de l'arxiu
+$ SIGVTALRM
+26 El temporitzador virtual ha expirat
+$ SIGPROF
+27 El temporitzador del perfilador ha expirat
+$ SIGWINCH
+28 Canvis en la mida de la finestra
+$ SIGINFO
+29 Demanda d'informació
+$ SIGUSR1
+30 Senyal 1 definida per l'usuari
+$ SIGUSR2
+31 Senyal 2 definida per l'usuari
+$ SIGPWR
+32 Fallada/reinicialització de l'alimentació
diff --git a/lib/libc/nls/catclose.3 b/lib/libc/nls/catclose.3
new file mode 100644
index 000000000000..ed0f639d2393
--- /dev/null
+++ b/lib/libc/nls/catclose.3
@@ -0,0 +1,64 @@
+.\" Copyright (c) 1994 Winning Strategies, 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.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by Winning Strategies, Inc.
+.\" 4. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.Dd February 12, 2005
+.Dt CATCLOSE 3
+.Os
+.Sh NAME
+.Nm catclose
+.Nd close message catalog
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In nl_types.h
+.Ft int
+.Fn catclose "nl_catd catd"
+.Sh DESCRIPTION
+The
+.Fn catclose
+function closes the message catalog specified by the argument
+.Fa catd .
+.Sh RETURN VALUES
+.Rv -std catclose
+.Sh ERRORS
+.Bl -tag -width Er
+.It Bq Er EBADF
+An invalid message catalog descriptor was passed by the
+.Fa catd
+argument.
+.El
+.Sh SEE ALSO
+.Xr gencat 1 ,
+.Xr catgets 3 ,
+.Xr catopen 3
+.Sh STANDARDS
+The
+.Fn catclose
+function conforms to
+.St -p1003.1-2001 .
diff --git a/lib/libc/nls/catgets.3 b/lib/libc/nls/catgets.3
new file mode 100644
index 000000000000..38e92ba23c30
--- /dev/null
+++ b/lib/libc/nls/catgets.3
@@ -0,0 +1,82 @@
+.\" Copyright (c) 1994 Winning Strategies, 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.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by Winning Strategies, Inc.
+.\" 4. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.Dd February 12, 2005
+.Dt CATGETS 3
+.Os
+.Sh NAME
+.Nm catgets
+.Nd retrieve string from message catalog
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In nl_types.h
+.Ft char *
+.Fn catgets "nl_catd catd" "int set_id" "int msg_id" "const char *s"
+.Sh DESCRIPTION
+The
+.Fn catgets
+function attempts to retrieve message
+.Fa msg_id
+of set
+.Fa set_id
+from the message catalog referenced by the descriptor
+.Fa catd .
+The argument
+.Fa s
+points to a default message which is returned if the function
+is unable to retrieve the specified message.
+.Sh RETURN VALUES
+If the specified message was retrieved successfully,
+.Fn catgets
+returns a pointer to an internal buffer containing the message string;
+otherwise it returns
+.Fa s .
+.Sh ERRORS
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa catd
+argument is not a valid message catalog descriptor.
+.It Bq Er EBADMSG
+The message identified by
+.Fa set_id
+and
+.Fa msg_id
+is not in the message catalog.
+.El
+.Sh SEE ALSO
+.Xr gencat 1 ,
+.Xr catclose 3 ,
+.Xr catopen 3
+.Sh STANDARDS
+The
+.Fn catgets
+function conforms to
+.St -p1003.1-2001 .
diff --git a/lib/libc/nls/catopen.3 b/lib/libc/nls/catopen.3
new file mode 100644
index 000000000000..7744b0bd864c
--- /dev/null
+++ b/lib/libc/nls/catopen.3
@@ -0,0 +1,157 @@
+.\" Copyright (c) 1994 Winning Strategies, 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.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by Winning Strategies, Inc.
+.\" 4. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.Dd February 12, 2005
+.Dt CATOPEN 3
+.Os
+.Sh NAME
+.Nm catopen
+.Nd open message catalog
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In nl_types.h
+.Ft nl_catd
+.Fn catopen "const char *name" "int oflag"
+.Sh DESCRIPTION
+The
+.Fn catopen
+function opens the message catalog specified by
+.Fa name
+and returns a message catalog descriptor.
+If
+.Fa name
+contains a
+.Sq /
+then
+.Fa name
+specifies the full pathname for the message catalog, otherwise the value
+of the environment variable
+.Ev NLSPATH
+is used with
+the following substitutions:
+.Bl -tag -width XXX
+.It \&%N
+The value of the
+.Fa name
+argument.
+.It \&%L
+The value of the
+.Ev LANG
+environment variable or the
+.Dv LC_MESSAGES
+category (see below).
+.It \&%l
+The language element from the
+.Ev LANG
+environment variable or from the
+.Dv LC_MESSAGES
+category.
+.It \&%t
+The territory element from the
+.Ev LANG
+environment variable or from the
+.Dv LC_MESSAGES
+category.
+.It \&%c
+The codeset element from the
+.Ev LANG
+environment variable or from the
+.Dv LC_MESSAGES
+category.
+.It \&%%
+A single % character.
+.El
+.Pp
+An empty string is substituted for undefined values.
+.Pp
+Path names templates defined in
+.Ev NLSPATH
+are separated by colons
+.Pq Sq \&: .
+A leading or two adjacent colons
+is equivalent to specifying %N.
+.Pp
+If the
+.Fa oflag
+argument is set to the
+.Dv NL_CAT_LOCALE
+constant,
+.Dv LC_MESSAGES
+locale category used to open the message catalog; using
+.Dv NL_CAT_LOCALE
+conforms to the
+.St -xpg4
+standard.
+You can specify 0 for compatibility with
+.St -xpg3 ;
+when
+.Fa oflag
+is set to 0, the
+.Ev LANG
+environment variable
+determines the message catalog locale.
+.Pp
+A message catalog descriptor
+remains valid in a process until that process closes it, or
+until a successful call to one of the
+.Xr exec 3
+function.
+.Sh RETURN VALUES
+Upon successful completion,
+.Fn catopen
+returns a message catalog descriptor.
+Otherwise, (nl_catd) -1 is returned and
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Fa name
+does not point to a valid message catalog, or catalog is corrupt.
+.It Bq Er ENAMETOOLONG
+An entire path to the message catalog exceeded 1024 characters.
+.It Bq Er ENOENT
+The named message catalog does not exists, or the
+.Fa name
+argument points to an empty string.
+.It Bq Er ENOMEM
+Insufficient memory is available.
+.El
+.Sh SEE ALSO
+.Xr gencat 1 ,
+.Xr catclose 3 ,
+.Xr catgets 3 ,
+.Xr setlocale 3
+.Sh STANDARDS
+The
+.Fn catopen
+function conforms to
+.St -p1003.1-2001 .
diff --git a/lib/libc/nls/de_DE.ISO8859-1.msg b/lib/libc/nls/de_DE.ISO8859-1.msg
new file mode 100644
index 000000000000..1bb4a3b45334
--- /dev/null
+++ b/lib/libc/nls/de_DE.ISO8859-1.msg
@@ -0,0 +1,249 @@
+$ $FreeBSD$
+$
+$ Message catalog for de_DE.ISO8859-1 locale
+$
+$ strerror() support catalog
+$
+$set 1
+$ EPERM
+1 Operation nicht erlaubt
+$ ENOENT
+2 Datei oder Verzeichnis nicht gefunden
+$ ESRCH
+3 Prozess nicht gefunden
+$ EINTR
+4 Interrupt innerhalb eines Systemaufrufs
+$ EIO
+5 Ein-/Ausgabefehler
+$ ENXIO
+6 Gerät ist nicht konfiguriert
+$ E2BIG
+7 Argumentliste ist zu lang
+$ ENOEXEC
+8 Die Datei hat kein bekanntes ausführbares Format
+$ EBADF
+9 Ungültiger Dateideskriptor
+$ ECHILD
+10 Keine Kindprozesse
+$ EDEADLK
+11 Ein Deadlock wurde vermieden
+$ ENOMEM
+12 Kann nicht genug Speicher belegen
+$ EACCES
+13 Zugriff verweigert
+$ EFAULT
+14 Ungültige Adresse
+$ ENOTBLK
+15 Es wird ein Blockgerät benötigt
+$ EBUSY
+16 Das Gerät ist belegt
+$ EEXIST
+17 Datei existiert bereits
+$ EXDEV
+18 Link zwischen verschiedenen Geräten
+$ ENODEV
+19 Die Operation wird von diesem Gerät nicht unterstützt
+$ ENOTDIR
+20 Kein Verzeichnis
+$ EISDIR
+21 Ist ein Verzeichnis
+$ EINVAL
+22 Ungültiges Argument
+$ ENFILE
+23 Zu viele offene Dateien im System
+$ EMFILE
+24 Zu viele offene Dateien
+$ ENOTTY
+25 Ungültiger IOCTL für dieses Gerät
+$ ETXTBSY
+26 Datei wird benutzt
+$ EFBIG
+27 Datei zu groß
+$ ENOSPC
+28 Kein Platz mehr auf dem Gerät
+$ ESPIPE
+29 Ungültige Positionierung
+$ EROFS
+30 Dateisystem ist schreibgeschützt
+$ EMLINK
+31 Zu viele Links
+$ EPIPE
+32 Unterbrochene Pipe
+$ EDOM
+33 Numerisches Argument außerhalb des Wertebereichs
+$ ERANGE
+34 Ergebnis außerhalb des Wertebereichs
+$ EAGAIN, EWOULDBLOCK
+35 Ressource vorübergehend nicht verfügbar
+$ EINPROGRESS
+36 Operation wird gerade ausgeführt
+$ EALREADY
+37 Operation wird bereits ausgeführt
+$ ENOTSOCK
+38 Deskriptor ist kein Socket
+$ EDESTADDRREQ
+39 Zieladresse benötigt
+$ EMSGSIZE
+40 Nachricht zu lang
+$ EPROTOTYPE
+41 Ungültiger Protokolltyp für diesen Socket
+$ ENOPROTOOPT
+42 Protokoll nicht verfügbar
+$ EPROTONOSUPPORT
+43 Protokoll nicht unterstützt
+$ ESOCKTNOSUPPORT
+44 Sockettyp nicht unterstützt
+$ EOPNOTSUPP
+45 Operation nicht unterstützt
+$ EPFNOSUPPORT
+46 Protokollfamilie nicht unterstützt
+$ EAFNOSUPPORT
+47 Adressfamilie wird von der Protokollfamilie nicht unterstützt
+$ EADDRINUSE
+48 Adresse wird bereits benutzt
+$ EADDRNOTAVAIL
+49 Kann angeforderte Adresse nicht belegen
+$ ENETDOWN
+50 Netzwerk nicht verfügbar
+$ ENETUNREACH
+51 Netzwerk nicht erreichbar
+$ ENETRESET
+52 Netzwerk hat Verbindung mit Reset abgebrochen
+$ ECONNABORTED
+53 Software verursachte einen Verbindungsabbruch
+$ ECONNRESET
+54 Verbindung wurde von der Gegenstelle geschlossen
+$ ENOBUFS
+55 Keine Buffer verfügbar
+$ EISCONN
+56 Socket ist schon verbunden
+$ ENOTCONN
+57 Socket ist nicht verbunden
+$ ESHUTDOWN
+58 Kann nach einem Socket-Shutdown nicht mehr senden
+$ ETOOMANYREFS
+59 Zu viele Referenzen, kann nicht verbinden
+$ ETIMEDOUT
+60 Verbindungsabbruch durch Zeitüberschreitung
+$ ECONNREFUSED
+61 Verbindung wurde abgelehnt
+$ ELOOP
+62 Zu viele symbolische Links (zirkulär?)
+$ ENAMETOOLONG
+63 Dateiname zu lang
+$ EHOSTDOWN
+64 Host nicht verfügbar
+$ EHOSTUNREACH
+65 Keine Route zum Host
+$ ENOTEMPTY
+66 Verzeichnis ist nicht leer
+$ EPROCLIM
+67 Zu viele Prozesse
+$ EUSERS
+68 Zu viele Benutzer
+$ EDQUOT
+69 Platzlimit überschritten
+$ ESTALE
+70 Verwaister NFS-Dateideskriptor
+$ EREMOTE
+71 Zu viele Fernverweise in diesem Zugriff
+$ EBADRPC
+72 RPC-Struktur ist ungültig
+$ ERPCMISMATCH
+73 RPC-Version ist falsch
+$ EPROGUNAVAIL
+74 RPC-Programm nicht verfügbar
+$ EPROGMISMATCH
+75 Falsche Programmversion
+$ EPROCUNAVAIL
+76 Falsche Prozedur für dieses Programm
+$ ENOLCK
+77 Keine Dateisperren verfügbar
+$ ENOSYS
+78 Funktion nicht implementiert
+$ EFTYPE
+79 Ungültiger Dateityp oder Dateiformat
+$ EAUTH
+80 Authentifizierungsfehler
+$ ENEEDAUTH
+81 Authentikator benötigt
+$ EIDRM
+82 Identifizierung entfernt
+$ ENOMSG
+83 Keine Nachricht vom gewünschten Typ
+$ EOVERFLOW
+84 Wert zu groß, um in Datentyp zu speichern
+$ ECANCELED
+85 Operation abgebrochen
+$ EILSEQ
+86 Ungültige Byte-Sequenz
+$ ENOATTR
+87 Attribut nicht gefunden
+$ EDOOFUS
+88 Programmierfehler
+$
+$ strsignal() support catalog
+$
+$set 2
+$ SIGHUP
+1 Verbindungsende
+$ SIGINT
+2 Unterbrechung
+$ SIGQUIT
+3 Programmende
+$ SIGILL
+4 Ungültiger Maschinenbefehl
+$ SIGTRAP
+5 Trace/BPT trap
+$ SIGABRT
+6 Abort trap
+$ SIGEMT
+7 EMT trap
+$ SIGFPE
+8 Fließkommafehler
+$ SIGKILL
+9 Unbedingter Programmabbruch
+$ SIGBUS
+10 Bus-Zugriffsfehler
+$ SIGSEGV
+11 Illegaler Speicherzugriff
+$ SIGSYS
+12 Ungültiger Systemaufruf
+$ SIGPIPE
+13 Unterbrochene Pipe
+$ SIGALRM
+14 Wecker
+$ SIGTERM
+15 Beendet
+$ SIGURG
+16 Dringende Ein/Ausgabeanforderung
+$ SIGSTOP
+17 Gestoppt (Signal)
+$ SIGTSTP
+18 Gestoppt
+$ SIGCONT
+19 Fortgesetzt
+$ SIGCHLD
+20 Kindprozess beendet
+$ SIGTTIN
+21 Gestoppt (Eingabe)
+$ SIGTTOU
+22 Gestoppt (Ausgabe)
+$ SIGIO
+23 Ein/Ausgabe möglich
+$ SIGXCPU
+24 CPU-Zeitlimit überschritten
+$ SIGXFSZ
+25 Dateigrößenlimit überschritten
+$ SIGVTALRM
+26 Virtueller Wecker abgelaufen
+$ SIGPROF
+27 Profil-Wecker abgelaufen
+$ SIGWINCH
+28 Fenstergröße hat sich verändert
+$ SIGINFO
+29 Informationsanforderung
+$ SIGUSR1
+30 Benutzerdefiniertes Signal 1
+$ SIGUSR2
+31 Benutzerdefiniertes Signal 2
diff --git a/lib/libc/nls/el_GR.ISO8859-7.msg b/lib/libc/nls/el_GR.ISO8859-7.msg
new file mode 100644
index 000000000000..ca84929b9eed
--- /dev/null
+++ b/lib/libc/nls/el_GR.ISO8859-7.msg
@@ -0,0 +1,249 @@
+$ $FreeBSD$
+$
+$ Message catalog for C locale (template)
+$
+$ strerror() support catalog
+$
+$set 1
+$ EPERM
+1 Ìç åðéôñåðôÞ åíÝñãåéá
+$ ENOENT
+2 Äåí õðÜñ÷åé ôÝôïéï áñ÷åßï Þ êáôÜëïãïò
+$ ESRCH
+3 Ç äéåñãáóßá áõôÞ äåí õðÜñ÷åé
+$ EINTR
+4 Ç êëÞóç óõóôÞìáôïò äéáêüðçêå
+$ EIO
+5 ÓöÜëìá åéóüäïõ/åîüäïõ
+$ ENXIO
+6 Ç óõóêåõÞ äåí Ý÷åé ñõèìéóôåß
+$ E2BIG
+7 Ç ëßóôá ôùí ðáñáìÝôñùí åßíáé ðïëý ìåãÜëç
+$ ENOEXEC
+8 ËáíèáóìÝíç ìïñöÞ åêôåëÝóéìïõ
+$ EBADF
+9 Ðñïâëçìáôéêüò ðåñéãñáöÝáò áñ÷åßïõ
+$ ECHILD
+10 Äåí õðÜñ÷ïõí åîáñôþìåíåò äéåñãáóßåò
+$ EDEADLK
+11 Áðïöåý÷èçêå áäéÝîïäï ðüñïõ
+$ ENOMEM
+12 Áäõíáìßá åê÷þñçóçò ìíÞìçò
+$ EACCES
+13 ¶ñíçóç ðñüóâáóçò
+$ EFAULT
+14 ËÜèïò äéåýèõíóç
+$ ENOTBLK
+15 Áðáéôåßôáé óõóêåõÞ ôýðïõ block
+$ EBUSY
+16 ÓõóêåõÞ êáôåéëçììÝíç
+$ EEXIST
+17 Ôï áñ÷åßï õðÜñ÷åé
+$ EXDEV
+18 Óýíäåóìïò ìåôáîý óõóêåõþí
+$ ENODEV
+19 Ç ëåéôïõñãßá äåí õðïóôçñßæåôáé áðü ôç óõóêåõÞ
+$ ENOTDIR
+20 Äåí åßíáé êáôÜëïãïò
+$ EISDIR
+21 Åßíáé êáôÜëïãïò
+$ EINVAL
+22 Ìç Ýãêõñç ðáñÜìåôñïò
+$ ENFILE
+23 ÕðåñâïëéêÜ ðïëëÜ áíïéêôÜ áñ÷åßá óôï óýóôçìá
+$ EMFILE
+24 ÕðåñâïëéêÜ ðïëëÜ áíïéêôÜ áñ÷åßá
+$ ENOTTY
+25 ÁêáôÜëëçëï ioctl ãéá ôç óõóêåõÞ
+$ ETXTBSY
+26 Ôï áñ÷åßï êåéìÝíïõ åßíáé êáôåéëçììÝíï
+$ EFBIG
+27 Ðïëý ìåãÜëï áñ÷åßï
+$ ENOSPC
+28 Äåí Ý÷åé ìåßíåé åëåýèåñïò ÷þñïò óôç óõóêåõÞ
+$ ESPIPE
+29 ÁêáôÜëëçëç áíß÷íåõóç
+$ EROFS
+30 Ôï óýóôçìá áñ÷åßùí åßíáé ìüíï ãéá áíÜãíùóç
+$ EMLINK
+31 ÐÜñá ðïëëïß óýíäåóìïé
+$ EPIPE
+32 Äéáêïðåßóá óùëÞíùóç
+$ EDOM
+33 Ôï áñéèìçôéêü üñéóìá åßíáé åêôüò ïñßùí
+$ ERANGE
+34 Ðïëý ìåãÜëï áðïôÝëåóìá
+$ EAGAIN, EWOULDBLOCK
+35 Ï ðüñïò äåí åßíáé äéáèÝóéìïò ðñïóùñéíÜ
+$ EINPROGRESS
+36 Ç ëåéôïõñãßá âñßóêåôáé óå åîÝëéîç ôþñá
+$ EALREADY
+37 Ç ëåéôïõñãßá åßíáé Þäç óå åîÝëéîç
+$ ENOTSOCK
+38 Ëåéôïõñãßá õðïäï÷Þò óå ìç-õðïäï÷Þ
+$ EDESTADDRREQ
+39 Áðáéôåßôáé äéåýèõíóç ðñïïñéóìïý
+$ EMSGSIZE
+40 Ðïëý ìåãÜëï ìÞíõìá
+$ EPROTOTYPE
+41 ËÜèïò ôýðïõ ðñùôüêïëëï ãéá õðïäï÷Þ
+$ ENOPROTOOPT
+42 Ôï ðñùôüêïëëï äåí åßíáé äéáèÝóéìï
+$ EPROTONOSUPPORT
+43 Ôï ðñùôüêïëëï äåí õðïóôçñßæåôáé
+$ ESOCKTNOSUPPORT
+44 Ï ôýðïò ôçò õðïäï÷Þò äåí õðóôçñßæåôáé
+$ EOPNOTSUPP
+45 Ç ëåéôïõñãßá äåí õðïóôçñßæåôáé
+$ EPFNOSUPPORT
+46 Äåí õðïóôçñßæåôáé ç ïéêïãÝíåéá ðñùôïêüëëùí
+$ EAFNOSUPPORT
+47 Ç ïéêïãÝíåéá äéåõèýíóåùí äåí õðïóôçñßæåôáé áðü ôçí ïéêïãÝíåéá ðñùôïêüëëùí
+$ EADDRINUSE
+48 Ç äéåýèõíóç ÷ñçóéìïðïéåßôáé Þäç
+$ EADDRNOTAVAIL
+49 Äåí ìðïñåß íá ãßíåé áíÜèåóç ôçò æçôïýìåíçò äéåýèõíóçò
+$ ENETDOWN
+50 Ôï äßêôõï äåí ëåéôïõñãåß
+$ ENETUNREACH
+51 Äåí õðÜñ÷åé äéáäñïìÞ ðñïò ôï äßêôõï
+$ ENETRESET
+52 Ôï äßêôõï äéÝêïøå ôç óýíäåóç êáôÜ ôçí åðáíáöïñÜ
+$ ECONNABORTED
+53 Ôï ëïãéóìéêü ðñïêÜëåóå ôåñìáôéóìü ôçò óýíäåóçò
+$ ECONNRESET
+54 Ç óýíäåóç ôåñìáôßóôçêå áðü ôçí Üëëç ìåñéÜ
+$ ENOBUFS
+55 Äåí õðÜñ÷åé äéáèÝóéìïò ðñïóùñéíüò ÷þñïò
+$ EISCONN
+56 Ç õðïäï÷Þ Ý÷åé Þäç óõíäåèåß
+$ ENOTCONN
+57 Ç õðïäï÷Þ äåí Ý÷åé óõíäåèåß
+$ ESHUTDOWN
+58 Äåí åßíáé äõíáôÞ ç áðïóôïëÞ ìåôÜ ôïí ôåñìáôéóìü ôçò õðïäï÷Þò
+$ ETOOMANYREFS
+59 ÐÜñá ðïëëÝò áíáöïñÝò: äåí ìðïñåß íá ãßíåé óõíÝíùóç
+$ ETIMEDOUT
+60 ÔÝëïò ÷ñüíïõ äéáäéêáóßáò
+$ ECONNREFUSED
+61 ¶ñíçóç óýíäåóçò
+$ ELOOP
+62 ÐÜñá ðïëëÜ åðßðåäá óõìâïëéêþí óõíäÝóåùí
+$ ENAMETOOLONG
+63 Ðïëý ìåãÜëï üíïìá áñ÷åßïõ
+$ EHOSTDOWN
+64 Ôï óýóôçìá äåí åßíáé óå ëåéôïõñãßá
+$ EHOSTUNREACH
+65 Äåí õðÜñ÷åé äéáäñïìÞ ðñïò ôï óýóôçìá
+$ ENOTEMPTY
+66 Ï êáôÜëïãïò äåí åßíáé Üäåéïò
+$ EPROCLIM
+67 ÕðåñâïëéêÜ ðïëëÝò äéåñãáóßåò
+$ EUSERS
+68 ÕðåñâïëéêÜ ðïëëïß ÷ñÞóôåò
+$ EDQUOT
+69 ÕðÝñâáóç ïñßùí ÷ñÞóçò äßóêïõ
+$ ESTALE
+70 ¶êõñï handle áñ÷åßïõ óôï NFS
+$ EREMOTE
+71 ÐÜñá ðïëëÜ áðïìáêñõóìÝíá åðßðåäá óôç äéáäñïìÞ
+$ EBADRPC
+72 Ç äïìÞ RPC åßíáé ðñïâëçìáôéêÞ
+$ ERPCMISMATCH
+73 ËáíèáóìÝíç Ýêäïóç RPC
+$ EPROGUNAVAIL
+74 Ôï ðñüãñáììá RPC äåí åßíáé äéáèÝóéìï
+$ EPROGMISMATCH
+75 ËáíèáóìÝíç Ýêäïóç ðñïãñÜììáôïò
+$ EPROCUNAVAIL
+76 ÐñïâëçìáôéêÞ äéáäéêáóßá ãéá ôï ðñüãñáììá
+$ ENOLCK
+77 Äåí õðÜñ÷ïõí äéáèÝóéìá êëåéäþìáôá
+$ ENOSYS
+78 Ç ëåéôïõñãßá äåí Ý÷åé õëïðïéçèåß
+$ EFTYPE
+79 ËáíèáóìÝíïò ôýðïò Þ ìïñöÞ áñ÷åßïõ
+$ EAUTH
+80 ÓöÜëìá êáôÜ ôçí ðéóôïðïßçóç áõèåíôéêüôçôáò
+$ ENEEDAUTH
+81 Áðáéôåßôáé ðéóôïðïéçôÞò áõèåíôéêüôçôáò
+$ EIDRM
+82 Ôï áíáãíùñéóôéêü Ý÷åé áöáéñåèåß
+$ ENOMSG
+83 Äåí õðÜñ÷åé ìÞíõìá ôïõ êáèïñéóìÝíïõ ôýðïõ
+$ EOVERFLOW
+84 Ç ôéìÞ åßíáé ðïëý ìåãÜëç ãéá íá áðïèçêåõèåß óôïí ôýðï äåäïìÝíùí
+$ ECANCELED
+85 Ç ëåéôïõñãßá áêõñþèçêå
+$ EILSEQ
+86 Ìç-Ýãêõñç áêïëïõèßá bytes
+$ ENOATTR
+87 Ôï ÷áñáêôçñéóôéêü äåí âñÝèçêå
+$ EDOOFUS
+88 ÓöÜëìá ðñïãñáììáôéóìïý
+$
+$ strsignal() support catalog
+$
+$set 2
+$ SIGHUP
+1 Êëåßóéìï
+$ SIGINT
+2 ÄéáêïðÞ
+$ SIGQUIT
+3 Ôåñìáôéóìüò
+$ SIGILL
+4 Ìç-Ýãêõñç åíôïëÞ
+$ SIGTRAP
+5 Ðáãßäá Trace/BPT
+$ SIGABRT
+6 Ðáãßäá áêýñùóçò
+$ SIGEMT
+7 Ðáãßäá EMT
+$ SIGFPE
+8 Åîáßñåóç êéíçôÞò õðïäéáóôïëÞò
+$ SIGKILL
+9 Ôåñìáôßóôçêå
+$ SIGBUS
+10 ÓöÜëìá äéáýëïõ
+$ SIGSEGV
+11 ÓöÜëìá Segmentation
+$ SIGSYS
+12 ÊáêÞ êëÞóç óõóôÞìáôïò
+$ SIGPIPE
+13 ÄéáêïðÞ pipe
+$ SIGALRM
+14 Ñïëüé åéäïðïßçóçò
+$ SIGTERM
+15 Ôåñìáôßóôçêå
+$ SIGURG
+16 ¸êôáêôç êáôÜóôáóç É/Ï
+$ SIGSTOP
+17 Óå áíáìïíÞ (óÞìá)
+$ SIGTSTP
+18 Óå áíáìïíÞ
+$ SIGCONT
+19 Óõíå÷ßæåôáé
+$ SIGCHLD
+20 ÔÝëïò åîáñôþìåíçò äéåñãáóßáò
+$ SIGTTIN
+21 ÄéáêïðÞ (åßóïäïò tty)
+$ SIGTTOU
+22 ÄéáêïðÞ (Ýîïäïò tty)
+$ SIGIO
+23 Äõíáôüôçôá I/O
+$ SIGXCPU
+24 ÎåðåñÜóôçêå ôï üñéï ÷ñÞóçò ôçò CPU
+$ SIGXFSZ
+25 ÎåðåñÜóôçêå ôï ìÝãéóôï ìÝãåèïò áñ÷åßïõ
+$ SIGVTALRM
+26 ÅîáíôëÞèçêå ï åéêïíéêüò ÷ñïíïìåôñçôÞò
+$ SIGPROF
+27 ÅîáíôëÞèçêå ï ÷ñïíïìåôñçôÞò profiling
+$ SIGWINCH
+28 Ôï ìÝãåèïò ôïõ ðáñáèýñïõ áëëÜæåé
+$ SIGINFO
+29 Áßôçóç ãéá ðëçñïöïñßá
+$ SIGUSR1
+30 ÓÞìá 1 êáèïñéóìÝíï áðü ôï ÷ñÞóôç
+$ SIGUSR2
+31 ÓÞìá 2 êáèïñéóìÝíï áðü ôï ÷ñÞóôç
diff --git a/lib/libc/nls/es_ES.ISO8859-1.msg b/lib/libc/nls/es_ES.ISO8859-1.msg
new file mode 100644
index 000000000000..2687c177fd57
--- /dev/null
+++ b/lib/libc/nls/es_ES.ISO8859-1.msg
@@ -0,0 +1,295 @@
+$ $FreeBSD$
+$
+$ Message catalog for es_ES.ISO8859-1 locale
+$
+$ strerror() support catalog
+$
+$set 1
+$ EPERM
+1 Operación no permitida
+$ ENOENT
+2 Fichero o directorio inexistente
+$ ESRCH
+3 Proceso inexistente
+$ EINTR
+4 Llamada del sistema interrumpida
+$ EIO
+5 Error de Entrada/Salida
+$ ENXIO
+6 Dispositivo no configurado
+$ E2BIG
+7 La lista de argumentos es demasiado larga
+$ ENOEXEC
+8 Error en el formato del ejecutable
+$ EBADF
+9 Descriptor incorrecto de fichero
+$ ECHILD
+10 No hay procesos hijo
+$ EDEADLK
+11 Se ha evitado el bloqueo del recurso
+$ ENOMEM
+12 No se pudo asignar memoria
+$ EACCES
+13 Permiso denegado
+$ EFAULT
+14 Dirección incorrecta
+$ ENOTBLK
+15 Se necesita un dispositivo de bloques
+$ EBUSY
+16 Dispositivo ocupado
+$ EEXIST
+17 El fichero ya existe
+$ EXDEV
+18 Enlace entre dispositivos
+$ ENODEV
+19 Operación inadecuada para este dispositivo
+$ ENOTDIR
+20 No es un directorio
+$ EISDIR
+21 Es un directorio
+$ EINVAL
+22 Argumento inadecuado
+$ ENFILE
+23 Hay demasiados ficheros abiertos en el sistema
+$ EMFILE
+24 Hay demasiados ficheros abiertos
+$ ENOTTY
+25 ioctl inapropiado para el dispositivo
+$ ETXTBSY
+26 Fichero de texto ocupado
+$ EFBIG
+27 Fichero demasiado grande
+$ ENOSPC
+28 No queda espacio libre en el dispositivo
+$ ESPIPE
+29 Búsqueda ilegal
+$ EROFS
+30 Sistema de ficheros de solo lectura
+$ EMLINK
+31 Demasiados enlaces
+$ EPIPE
+32 Canal (pipe) roto
+$ EDOM
+33 Argumento numérico fuera de rango
+$ ERANGE
+34 El resultado es demasiado grande
+$ EAGAIN, EWOULDBLOCK
+35 el recurso no está disponible temporalmente
+$ EINPROGRESS
+36 Operación en proceso
+$ EALREADY
+37 La operación ya se está ejecutando
+$ ENOTSOCK
+38 Operación de socket inaceptable para el dispositivo
+$ EDESTADDRREQ
+39 Se necesita una dirección de destino
+$ EMSGSIZE
+40 Mensaje demasiado largo
+$ EPROTOTYPE
+41 Tipo erróneo de protocolo para el socket
+$ ENOPROTOOPT
+42 Protocolo no disponible
+$ EPROTONOSUPPORT
+43 Protocolo no contemplado
+$ ESOCKTNOSUPPORT
+44 Tipo de socket no contemplado
+$ EOPNOTSUPP
+45 Operación no contemplada
+$ EPFNOSUPPORT
+46 Familia de protocolos no contemplada
+$ EAFNOSUPPORT
+47 Familia de direcciones no contemplada por la familia de protocolos
+$ EADDRINUSE
+48 La dirección ya está siendo usada
+$ EADDRNOTAVAIL
+49 No se pudo asignar la dirección requerida
+$ ENETDOWN
+50 La red no funciona
+$ ENETUNREACH
+51 No se ha podido acceder a la red
+$ ENETRESET
+52 La conexión de red se ha interrumpido al reinicializar
+$ ECONNABORTED
+53 Conexión perdida por problemas en el software
+$ ECONNRESET
+54 El interlocutor ha reinicializado la conexión
+$ ENOBUFS
+55 No queda espacio en el búfer
+$ EISCONN
+56 El socket ya estaba conectado
+$ ENOTCONN
+57 El socket no está conectado
+$ ESHUTDOWN
+58 No se puede enviar tras la desconexión del socket
+$ ETOOMANYREFS
+59 Demasiadas referencias: no se pueden unir
+$ ETIMEDOUT
+60 El tiempo de conexión ha expirado
+$ ECONNREFUSED
+61 Conexión rehusada
+$ ELOOP
+62 Demasiados niveles de enlaces simbólicos
+$ ENAMETOOLONG
+63 Nombre de fichero demasiado largo
+$ EHOSTDOWN
+64 La máquina está fuera de servicio
+$ EHOSTUNREACH
+65 No hay ruta hasta la máquina
+$ ENOTEMPTY
+66 Directorio no vacío
+$ EPROCLIM
+67 Demasiados procesos
+$ EUSERS
+68 Demasiados usuarios
+$ EDQUOT
+69 Cuota de disco sobrepasada
+$ ESTALE
+70 Descriptor de fichero NFS inválido
+$ EREMOTE
+71 Ruta con demasiados niveles
+$ EBADRPC
+72 La estructura de la RPC es errónea
+$ ERPCMISMATCH
+73 La versón de la RPC es errónea
+$ EPROGUNAVAIL
+74 La RPC no está accesible
+$ EPROGMISMATCH
+75 Versión errónea del programa
+$ EPROCUNAVAIL
+76 Procedimiento erróneo para el programa
+$ ENOLCK
+77 No hay bloqueos disponibles
+$ ENOSYS
+78 Función no realizada
+$ EFTYPE
+79 Tipo de fichero o formato inapropiado
+$ EAUTH
+80 Error de autentificación
+$ ENEEDAUTH
+81 Se necesita un autenticador
+$ EIDRM
+82 Identificador eliminado
+$ ENOMSG
+83 No hay mensajes del tipo deseado
+$ EOVERFLOW
+84 Valor demasiado grande para almacenarse en el tipo deseado
+$ ECANCELED
+85 Operación cancelada
+$ EILSEQ
+86 Secuencia de bytes ilegal
+$ ENOATTR
+87 Atributo no encontrado
+$ EDOOFUS
+88 Error de programación
+$ EBADMSG
+89 Mensaje inválido
+$ EMULTIHOP
+90 Intento de hop multiple
+$ ENOLINK
+91 El enlace se ha roto
+$ EPROTO
+92 Fallo de protocolo
+$ ENOTCAPABLE
+93 Habilidades insuficientes
+$
+$ strsignal() support catalog
+$
+$set 2
+$ SIGHUP
+1 Fin de línea (Hangup)
+$ SIGINT
+2 Interrumpido
+$ SIGQUIT
+3 Terminado
+$ SIGILL
+4 Instrucción ilegal
+$ SIGTRAP
+5 Trace/BPT trap
+$ SIGABRT
+6 Abort trap
+$ SIGEMT
+7 EMT trap
+$ SIGFPE
+8 Excepción de coma flotante
+$ SIGKILL
+9 Matado
+$ SIGBUS
+10 Error en el bus
+$ SIGSEGV
+11 Fallo de segmentación
+$ SIGSYS
+12 Llamada al sistema errónea
+$ SIGPIPE
+13 Canal (pipe) roto
+$ SIGALRM
+14 Alarma del reloj
+$ SIGTERM
+15 Terminado
+$ SIGURG
+16 Condición urgente de E/S
+$ SIGSTOP
+17 Detenido (señal)
+$ SIGTSTP
+18 Detenido
+$ SIGCONT
+19 Continuando
+$ SIGCHLD
+20 Proceso hijo terminado
+$ SIGTTIN
+21 Detenido (entrada tty)
+$ SIGTTOU
+22 Detenido (salida tty)
+$ SIGIO
+23 E/S posible
+$ SIGXCPU
+24 Se ha sobrepasado el tiempo límite de la CPU
+$ SIGXFSZ
+25 Se ha sobrepasado el límite de tamaño de fichero
+$ SIGVTALRM
+26 Temporizador virtual expirado
+$ SIGPROF
+27 Temporizador de perfilación expirado
+$ SIGWINCH
+28 Cambios en el tamaño de ventana
+$ SIGINFO
+29 Petición de información
+$ SIGUSR1
+30 Señal definida por el usuario n1
+$ SIGUSR2
+31 Señal definida por el usuario n2
+$
+$ gai_strerror() support catalog
+$
+$set 3
+$ 1 (obsoleto)
+1 Tipo de dirección no contemplado
+$ EAI_AGAIN
+2 Error transitorio en la resolución de nombres
+$ EAI_BADFLAGS
+3 Valor inválido de ai_flags
+$ EAI_FAIL
+4 Error no recuperable en la resolución de nombres
+$ EAI_FAMILY
+5 ai_family no contemplado
+$ EAI_MEMORY
+6 Error en la asignación de memoria
+$ 7 (obsoleto)
+7 No hay dirección asociada con el nombre de máquina
+$ EAI_NONAME
+8 No se dispone nombre de máquina, ni nombre de servicio
+$ EAI_SERVICE
+9 Nombre de servicio no contemplado en ai_socktype
+$ EAI_SOCKTYPE
+10 ai_socktype no contemplado
+$ EAI_SYSTEM
+11 Error de sistema devuelto en errno
+$ EAI_BADHINTS
+12 Valor inválido de hints
+$ EAI_PROTOCOL
+13 Protocolo resuelto desconocido
+$ EAI_OVERFLOW
+14 Búfer de argumentos sobrepasado
+$ 0
+32766 Éxito
+$ NL_MSGMAX
+32767 Error desconocido
diff --git a/lib/libc/nls/fi_FI.ISO8859-1.msg b/lib/libc/nls/fi_FI.ISO8859-1.msg
new file mode 100644
index 000000000000..491f9a13ab6e
--- /dev/null
+++ b/lib/libc/nls/fi_FI.ISO8859-1.msg
@@ -0,0 +1,233 @@
+$ $FreeBSD$
+$
+$ Message catalog for fi_FI.ISO8859-1 locale
+$
+$ strerror() support catalog
+$
+$set 1
+$ EPERM
+1 Toimintoa ei sallita
+$ ENOENT
+2 Tiedostoa tai hakemistoa ei löydy
+$ ESRCH
+3 Prosessia ei löydy
+$ EINTR
+4 Systeemikutsu keskeytyi
+$ EIO
+5 Syöttö/tulostusvirhe
+$ ENXIO
+6 Laitetta ei määritelty
+$ E2BIG
+7 Liikaa argumentteja
+$ ENOEXEC
+8 Tuntematon ohjelmatyyppi
+$ EBADF
+9 Virheellinen tiedosto-osoitin
+$ ECHILD
+10 Ei lapsiprosesseja
+$ EDEADLK
+11 Resurssin ristiinlukitus vältetty
+$ ENOMEM
+12 Muistinvaraus epäonnistui
+$ EACCES
+13 Lupa kielletty
+$ EFAULT
+14 Virheellinen osoite
+$ ENOTBLK
+15 Tarvitaan lohko-osoitettava laite
+$ EBUSY
+16 Laite käytössä
+$ EEXIST
+17 Tiedosto on jo olemassa
+$ EXDEV
+18 Laitteiden välinen linkki
+$ ENODEV
+19 Laite ei tue toimintoa
+$ ENOTDIR
+20 Kohde ei ole hakemisto
+$ EISDIR
+21 Kohde on hakemisto
+$ EINVAL
+22 Virheellinen argumentti
+$ ENFILE
+23 Järjestelmässä on liian monta avointa tiedostoa
+$ EMFILE
+24 Liian monta avointa tiedostoa
+$ ENOTTY
+25 Virheellinen ohjaustoiminto laitteelle
+$ ETXTBSY
+26 Tiedosto on käytössä
+$ EFBIG
+27 Tiedosto liian suuri
+$ ENOSPC
+28 Laitteella ei ole tilaa
+$ ESPIPE
+29 Virheellinen haku
+$ EROFS
+30 Vain luettava tiedostojärjestelmä
+$ EMLINK
+31 Liian monta linkkiä
+$ EPIPE
+32 Katkennut putki
+$ EDOM
+33 Numeerinen syöte virheellinen
+$ ERANGE
+34 Tulos liian suuri
+$ EAGAIN, EWOULDBLOCK
+35 Resurssi ei ole tilapäisesti saatavilla
+$ EINPROGRESS
+36 Toiminta on käynnissä
+$ EALREADY
+37 Toiminta oli jo käynnissä
+$ ENOTSOCK
+38 Socket-operaatio muulla kuin socketilla
+$ EDESTADDRREQ
+39 Tarvitaan kohdeosoite
+$ EMSGSIZE
+40 Sanoma liian pitkä
+$ EPROTOTYPE
+41 Väärä protokolla socketille
+$ ENOPROTOOPT
+42 Protokolla ei ole käytettävissä
+$ EPROTONOSUPPORT
+43 Protokollaa ei tueta
+$ ESOCKTNOSUPPORT
+44 Socket-tyyppiä ei tueta
+$ EOPNOTSUPP
+45 Toimintoa ei tueta
+$ EPFNOSUPPORT
+46 Protokollaperhettä ei tueta
+$ EAFNOSUPPORT
+47 Protokollaperhe ei tue osoiteperhettä
+$ EADDRINUSE
+48 Osoite on jo käytössä
+$ EADDRNOTAVAIL
+49 Ei pysty antamaan pyydettyä osoitetta
+$ ENETDOWN
+50 Verkko ei ole käytettävissä
+$ ENETUNREACH
+51 Verkkoon ei ole yhteyttä
+$ ENETRESET
+52 Verkko sulki yhteyden
+$ ECONNABORTED
+53 Ohjelmiston aiheuttama yhteyden keskeytyminen
+$ ECONNRESET
+54 Isäntä nollasi yhteyden
+$ ENOBUFS
+55 Puskuritila on lopussa
+$ EISCONN
+56 Yhteys on jo olemassa
+$ ENOTCONN
+57 Yhteyttä ei ole olemassa
+$ ESHUTDOWN
+58 Lähettäminen ei ole mahdollista yhteyden katkaisun jälkeen
+$ ETOOMANYREFS
+59 Liikaa viittauksia: ei voi yhdistää
+$ ETIMEDOUT
+60 Yhteyden aikavalvontakatkaisu
+$ ECONNREFUSED
+61 Yhteys hylätty
+$ ELOOP
+62 Liian monta peräkkäistä symbolista linkkiä
+$ ENAMETOOLONG
+63 Tiedoston nimi on liian pitkä
+$ EHOSTDOWN
+64 Isäntä ei vastaa
+$ EHOSTUNREACH
+65 Ei reittiä isäntään
+$ ENOTEMPTY
+66 Hakemisto ei ole tyhjä
+$ EPROCLIM
+67 Liian monta prosessia
+$ EUSERS
+68 Liian monta käyttäjää
+$ EDQUOT
+69 Levytilarajoitus ylittyi
+$ ESTALE
+70 Vanhentunut NFS-yhteys
+$ EREMOTE
+71 Liian monta verkkolevyä polussa
+$ EBADRPC
+72 Virheellinen RPC-pyyntö
+$ ERPCMISMATCH
+73 Väärä RPC-versio
+$ EPROGUNAVAIL
+74 RPC ei käytettävissä
+$ EPROGMISMATCH
+75 Väärä ohjelmaversio
+$ EPROCUNAVAIL
+76 Väärä RPC-pyyntö ohjelmalle
+$ ENOLCK
+77 Lukitus ei käytettävissä
+$ ENOSYS
+78 Toimintoa ei ole
+$ EFTYPE
+79 Väärä tiedostotyyppi tai -formaatti
+$
+$ strsignal() support catalog
+$
+$set 2
+$ SIGHUP
+1 Katkaisu
+$ SIGINT
+2 Keskeytys
+$ SIGQUIT
+3 Lopetus
+$ SIGILL
+4 Laiton käsky
+$ SIGTRAP
+5 Jäljitys/BPT ansa
+$ SIGABRT
+6 Poistumisansa
+$ SIGEMT
+7 EMT-ansa
+$ SIGFPE
+8 Liukulukuvirhe
+$ SIGKILL
+9 Tapettu
+$ SIGBUS
+10 Väylävirhe
+$ SIGSEGV
+11 Suojausvirhe
+$ SIGSYS
+12 Virheellinen systeemikutsu
+$ SIGPIPE
+13 Katkennut putki
+$ SIGALRM
+14 Hälytyskello
+$ SIGTERM
+15 Lopetettu
+$ SIGURG
+16 Kiireellinen syöttö/tulostus
+$ SIGSTOP
+17 Pysäytetty (signaali)
+$ SIGTSTP
+18 Pysäytetty
+$ SIGCONT
+19 Jatkettu
+$ SIGCHLD
+20 Lapsiprosessi päättynyt
+$ SIGTTIN
+21 Pysäytetty (tty-syöte)
+$ SIGTTOU
+22 Pysäytetty (tty-tuloste)
+$ SIGIO
+23 Syöttö ja tulostus mahdollisia
+$ SIGXCPU
+24 Keskusyksikköaikarajoitus ylitetty
+$ SIGXFSZ
+25 Tiedoston kokorajoitus ylitetty
+$ SIGVTALRM
+26 Virtuaali-ajastin laukesi
+$ SIGPROF
+27 Profilointiajastin laukesi
+$ SIGWINCH
+28 Ikkunan koko muuttuu
+$ SIGINFO
+29 Informaatiopyyntö
+$ SIGUSR1
+30 Käyttäjän määriteltävä signaali 1
+$ SIGUSR2
+31 Käyttäjän määriteltävä signaali 2
+$ SIGPWR
+32 Virransaannin tilassa muutos
diff --git a/lib/libc/nls/fr_FR.ISO8859-1.msg b/lib/libc/nls/fr_FR.ISO8859-1.msg
new file mode 100644
index 000000000000..ebc1739ea28c
--- /dev/null
+++ b/lib/libc/nls/fr_FR.ISO8859-1.msg
@@ -0,0 +1,249 @@
+$ $FreeBSD$
+$
+$ Message catalog for fr_FR.ISO8859-1 locale
+$
+$ strerror() support catalog
+$
+$set 1
+$ EPERM
+1 Opération non autorisée
+$ ENOENT
+2 Fichier ou répertoire inexistant
+$ ESRCH
+3 Processus inconnu
+$ EINTR
+4 Appel système interrompu
+$ EIO
+5 Erreur d'entrée/sortie
+$ ENXIO
+6 Dispositif non configuré
+$ E2BIG
+7 Liste d'arguments trop longue
+$ ENOEXEC
+8 Format d'exécutable invalide
+$ EBADF
+9 Mauvais descripteur de fichier
+$ ECHILD
+10 Pas de processus fils
+$ EDEADLK
+11 Étreinte mortelle détectée
+$ ENOMEM
+12 Impossible d'allouer de la mémoire
+$ EACCES
+13 Permission refusée
+$ EFAULT
+14 Mauvaise adresse
+$ ENOTBLK
+15 Dispositif en mode bloc requis
+$ EBUSY
+16 Dispositif occupé
+$ EEXIST
+17 Le fichier existe
+$ EXDEV
+18 Lien inter-unités
+$ ENODEV
+19 Opération non supportée par le dispositif
+$ ENOTDIR
+20 Pas un répertoire
+$ EISDIR
+21 Est un répertoire
+$ EINVAL
+22 Argument invalide
+$ ENFILE
+23 Trop de fichiers ouverts sur le système
+$ EMFILE
+24 Trop de fichiers ouverts
+$ ENOTTY
+25 Fonction inadaptée au dispositif
+$ ETXTBSY
+26 Fichier en cours d'utilisation
+$ EFBIG
+27 Fichier trop grand
+$ ENOSPC
+28 Plus d'espace disponible
+$ ESPIPE
+29 Recherche illégale
+$ EROFS
+30 Système de fichier en lecture seulement
+$ EMLINK
+31 Trop de liens
+$ EPIPE
+32 Tube déconnecté
+$ EDOM
+33 Argument numérique hors définition
+$ ERANGE
+34 Résultat trop grand
+$ EAGAIN, EWOULDBLOCK
+35 Ressource indisponible temporairement
+$ EINPROGRESS
+36 Opération en cours
+$ EALREADY
+37 Opération déjà en cours
+$ ENOTSOCK
+38 Opération de type socket sur un descripteur de fichier
+$ EDESTADDRREQ
+39 Adresse de destination obligatoire
+$ EMSGSIZE
+40 Message trop long
+$ EPROTOTYPE
+41 Mauvais type de protocole pour la socket
+$ ENOPROTOOPT
+42 Protocole non disponible
+$ EPROTONOSUPPORT
+43 Protocole non supporté
+$ ESOCKTNOSUPPORT
+44 Type de socket non supporté
+$ EOPNOTSUPP
+45 Opération non supportée
+$ EPFNOSUPPORT
+46 Famille de protocole non supportée
+$ EAFNOSUPPORT
+47 Famille d'adresse non supportée par la famille de protocole
+$ EADDRINUSE
+48 Adresse en cours d'utilisation
+$ EADDRNOTAVAIL
+49 Impossible d'assigner l'adresse demandée
+$ ENETDOWN
+50 Plus de réseau
+$ ENETUNREACH
+51 Réseau inaccessible
+$ ENETRESET
+52 Connexion coupée par le réseau
+$ ECONNABORTED
+53 Connexion interrompue
+$ ECONNRESET
+54 Connexion interrompue par l'hôte distant
+$ ENOBUFS
+55 Tampon saturé
+$ EISCONN
+56 La socket est déjà connectée
+$ ENOTCONN
+57 La socket n'est pas connectée
+$ ESHUTDOWN
+58 Impossible d'envoyer après la coupure
+$ ETOOMANYREFS
+59 Trop de références : lien impossible
+$ ETIMEDOUT
+60 Dépassement du délai d'attente
+$ ECONNREFUSED
+61 Connexion refusée
+$ ELOOP
+62 Trop de niveaux de liens symboliques
+$ ENAMETOOLONG
+63 Nom de fichier trop long
+$ EHOSTDOWN
+64 Hôte distant arrêté
+$ EHOSTUNREACH
+65 Pas de route vers l'hôte distant
+$ ENOTEMPTY
+66 Répertoire non vide
+$ EPROCLIM
+67 Trop de processus
+$ EUSERS
+68 Trop d'utilisateurs
+$ EDQUOT
+69 Quota de disque dépassé
+$ ESTALE
+70 Identificateur de fichier NFS périmé
+$ EREMOTE
+71 Trop de niveaux extérieurs dans le path
+$ EBADRPC
+72 Mauvaise structure RPC
+$ ERPCMISMATCH
+73 Mauvaise version RPC
+$ EPROGUNAVAIL
+74 Prog. RPC indisponible
+$ EPROGMISMATCH
+75 Mauvaise version de programme
+$ EPROCUNAVAIL
+76 Mauvaise procédure pour le programme
+$ ENOLCK
+77 Plus de verrous disponibles
+$ ENOSYS
+78 Fonction non implémentée
+$ EFTYPE
+79 Type de fichier ou format inapproprié
+$ EAUTH
+80 Erreur d'authentification
+$ ENEEDAUTH
+81 Authentification requise
+$ EIDRM
+82 Identifiant retiré
+$ ENOMSG
+83 Aucun message du type souhaité
+$ EOVERFLOW
+84 Valeur trop grande pour le type de donnée
+$ ECANCELED
+85 Opération annulée
+$ EILSEQ
+86 Séquence d'octets illégale
+$ ENOATTR
+87 Attribut non trouvé
+$ EDOOFUS
+88 Erreur de programmation
+$
+$ strsignal() support catalog
+$
+$set 2
+$ SIGHUP
+1 Fin de connexion
+$ SIGINT
+2 Interruption
+$ SIGQUIT
+3 Quitter
+$ SIGILL
+4 Instruction illégale
+$ SIGTRAP
+5 Trace/BPT trap
+$ SIGABRT
+6 Abort trap
+$ SIGEMT
+7 EMT trap
+$ SIGFPE
+8 Exception sur virgule flottante
+$ SIGKILL
+9 Tué
+$ SIGBUS
+10 Bus error
+$ SIGSEGV
+11 Segmentation fault
+$ SIGSYS
+12 Bad system call
+$ SIGPIPE
+13 Broken pipe
+$ SIGALRM
+14 Alarm clock
+$ SIGTERM
+15 Terminé
+$ SIGURG
+16 Urgent I/O condition
+$ SIGSTOP
+17 Suspended (signal)
+$ SIGTSTP
+18 Suspended
+$ SIGCONT
+19 Continued
+$ SIGCHLD
+20 Child exited
+$ SIGTTIN
+21 Stopped (tty input)
+$ SIGTTOU
+22 Stopped (tty output)
+$ SIGIO
+23 I/O possible
+$ SIGXCPU
+24 Cputime limit exceeded
+$ SIGXFSZ
+25 Filesize limit exceeded
+$ SIGVTALRM
+26 Virtual timer expired
+$ SIGPROF
+27 Profiling timer expired
+$ SIGWINCH
+28 Window size changes
+$ SIGINFO
+29 Information request
+$ SIGUSR1
+30 User defined signal 1
+$ SIGUSR2
+31 User defined signal 2
diff --git a/lib/libc/nls/gl_ES.ISO8859-1.msg b/lib/libc/nls/gl_ES.ISO8859-1.msg
new file mode 100644
index 000000000000..4255dc8a959a
--- /dev/null
+++ b/lib/libc/nls/gl_ES.ISO8859-1.msg
@@ -0,0 +1,295 @@
+$ $FreeBSD$
+$
+$ Message catalog for gl_ES.ISO8859-1 locale
+$
+$ strerror() support catalog
+$
+$set 1
+$ EPERM
+1 Operación non permitida
+$ ENOENT
+2 Ficheiro ou directorio inexistente
+$ ESRCH
+3 Proceso inexistente
+$ EINTR
+4 Chamada do sistema interrompida
+$ EIO
+5 Erro de Entrada/Saída
+$ ENXIO
+6 Dispositivo non configurado
+$ E2BIG
+7 A lista de argumentos é demasiado larga
+$ ENOEXEC
+8 Erro no formato do executable
+$ EBADF
+9 Descriptor incorrecto de ficheiro
+$ ECHILD
+10 Non hai procesos fillos
+$ EDEADLK
+11 Evitouse o bloqueo do recurso
+$ ENOMEM
+12 Non se puido asignar memoria
+$ EACCES
+13 Permiso denegado
+$ EFAULT
+14 Dirección incorrecta
+$ ENOTBLK
+15 Precísase un dispositivo de bloques
+$ EBUSY
+16 Dispositivo ocupado
+$ EEXIST
+17 O ficheiro xa existe
+$ EXDEV
+18 Enlace entre dispositivos
+$ ENODEV
+19 Operación inadecuada para este dispositivo
+$ ENOTDIR
+20 Non é un directorio
+$ EISDIR
+21 É un directorio
+$ EINVAL
+22 Argumento inadecuado
+$ ENFILE
+23 Hai demasiados ficheiros abertos no sistema
+$ EMFILE
+24 Hai demasiados ficheiros abertos
+$ ENOTTY
+25 ioctl inapropiado para o dispositivo
+$ ETXTBSY
+26 Ficheiro de texto ocupado
+$ EFBIG
+27 Ficheiro demasiado grande
+$ ENOSPC
+28 Non queda espacio libre no dispositivo
+$ ESPIPE
+29 seek inválido
+$ EROFS
+30 Sistema de ficheiros de só lectura
+$ EMLINK
+31 Demasiados enlaces
+$ EPIPE
+32 Canal (pipe) roto
+$ EDOM
+33 Argumento numérico fóra de rango
+$ ERANGE
+34 O resultado é demasiado grande
+$ EAGAIN, EWOULDBLOCK
+35 O recurso non está dispoñible temporalmente
+$ EINPROGRESS
+36 Operación en proceso
+$ EALREADY
+37 A operación xa estase executando
+$ ENOTSOCK
+38 Operación de socket inaceptable para o dispositivo
+$ EDESTADDRREQ
+39 Precísase unha dirección de destino
+$ EMSGSIZE
+40 Mensaxe demasiado largo
+$ EPROTOTYPE
+41 Tipo malo de protocolo para o socket
+$ ENOPROTOOPT
+42 Protocolo non dispoñible
+$ EPROTONOSUPPORT
+43 Protocolo non contemplado
+$ ESOCKTNOSUPPORT
+44 Tipo de socket non contemplado
+$ EOPNOTSUPP
+45 Operación non contemplada
+$ EPFNOSUPPORT
+46 Familia de protocolos non contemplada
+$ EAFNOSUPPORT
+47 Familia de direcciones non contemplada pola familia de protocolos
+$ EADDRINUSE
+48 A dirección xa está en uso
+$ EADDRNOTAVAIL
+49 Non se puido asignar a dirección requerida
+$ ENETDOWN
+50 A rede non funciona
+$ ENETUNREACH
+51 Non se puido acceder á rede
+$ ENETRESET
+52 A conexión de rede interrompiuse ao reinicializar
+$ ECONNABORTED
+53 Conexión perdida por problemas no software
+$ ECONNRESET
+54 O interlocutor reinicializou a conexión
+$ ENOBUFS
+55 Non queda espacio no búfer
+$ EISCONN
+56 O socket xa estaba conectado
+$ ENOTCONN
+57 O socket non está conectado
+$ ESHUTDOWN
+58 Non se pode enviar tras a desconexión do socket
+$ ETOOMANYREFS
+59 Demasiadas referencias: non poden unirse
+$ ETIMEDOUT
+60 O tempo de conexión expirou
+$ ECONNREFUSED
+61 Conexión rexeitada
+$ ELOOP
+62 Demasiados niveles de enlaces simbólicos
+$ ENAMETOOLONG
+63 Nome de ficheiro demasiado largo
+$ EHOSTDOWN
+64 A máquina está fóra de servicio
+$ EHOSTUNREACH
+65 Non hai ruta ata a máquina
+$ ENOTEMPTY
+66 Directorio non baleiro
+$ EPROCLIM
+67 Demasiados procesos
+$ EUSERS
+68 Demasiados usuarios
+$ EDQUOT
+69 Cuota de disco sobrepasada
+$ ESTALE
+70 Descriptor de ficheiro NFS inválido
+$ EREMOTE
+71 Ruta con demasiados niveles
+$ EBADRPC
+72 A estructura da RPC é mala
+$ ERPCMISMATCH
+73 A versión da RPC é mala
+$ EPROGUNAVAIL
+74 A RPC non está accesible
+$ EPROGMISMATCH
+75 Versión mala do programa
+$ EPROCUNAVAIL
+76 Procedemento malo para o programa
+$ ENOLCK
+77 Non hai bloqueos dispoñibles
+$ ENOSYS
+78 Función non realizada
+$ EFTYPE
+79 Tipo de ficheiro ou formato inapropiado
+$ EAUTH
+80 Erro de autenticación
+$ ENEEDAUTH
+81 Precísase un autenticador
+$ EIDRM
+82 Identificador eliminado
+$ ENOMSG
+83 Non hai mensaxes do tipo desexado
+$ EOVERFLOW
+84 Valor demasiado grande para se almacenar no tipo desexado
+$ ECANCELED
+85 Operación cancelada
+$ EILSEQ
+86 Secuencia inválida de byte
+$ ENOATTR
+87 Atributo non encontrado
+$ EDOOFUS
+88 Erro de programación
+$ EBADMSG
+89 Mensaxe inválido
+$ EMULTIHOP
+90 Intento de Multihop
+$ ENOLINK
+91 Enlace fortaleceuse
+$ EPROTO
+92 Erro de protocolo
+$ ENOTCAPABLE
+93 Habilidades non suficientes
+$
+$ strsignal() support catalog
+$
+$set 2
+$ SIGHUP
+1 Fin de liña (Hangup)
+$ SIGINT
+2 Interrompido
+$ SIGQUIT
+3 Terminado
+$ SIGILL
+4 Instrucción inválida
+$ SIGTRAP
+5 Trace/BPT trap
+$ SIGABRT
+6 Abort trap
+$ SIGEMT
+7 EMT trap
+$ SIGFPE
+8 Excepción de coma flotante
+$ SIGKILL
+9 Matado
+$ SIGBUS
+10 Erro no bus
+$ SIGSEGV
+11 Fallo de segmentación
+$ SIGSYS
+12 Chamada ao sistema mala
+$ SIGPIPE
+13 Canal (pipe) roto
+$ SIGALRM
+14 Alarma do reloxo
+$ SIGTERM
+15 Terminado
+$ SIGURG
+16 Condición urxente de E/S
+$ SIGSTOP
+17 Detido (sinal)
+$ SIGTSTP
+18 Detido
+$ SIGCONT
+19 Continuando
+$ SIGCHLD
+20 Proceso fillo terminado
+$ SIGTTIN
+21 Detido (entrada tty)
+$ SIGTTOU
+22 Detido (sída tty)
+$ SIGIO
+23 E/S posible
+$ SIGXCPU
+24 Sobrepasouse o tempo límite da CPU
+$ SIGXFSZ
+25 Sobrepasouse o límite de tamaño de ficheiro
+$ SIGVTALRM
+26 Temporizador virtual caducado
+$ SIGPROF
+27 Temporizador de perfilación caducado
+$ SIGWINCH
+28 Cambios no tamaño de xanela
+$ SIGINFO
+29 Petición de información
+$ SIGUSR1
+30 Sinal definida polo usuario no. 1
+$ SIGUSR2
+31 Sinal definida polo usuario no. 2
+$
+$ gai_strerror() support catalog
+$
+$set 3
+$ 1 (obsoleto)
+1 Tipo de dirección non soportado
+$ EAI_AGAIN
+2 Erro temporal na resolución de nomes
+$ EAI_BADFLAGS
+3 Valor inválido de ai_flags
+$ EAI_FAIL
+4 Erro non recuperable na resolución de nomes
+$ EAI_FAMILY
+5 ai_family non soportado
+$ EAI_MEMORY
+6 Erro na asignación de memoria
+$ 7 (obsoleto)
+7 Non hai dirección asociada co nome de máquina
+$ EAI_NONAME
+8 Non se dispón nome de máquina, nin nome de servizo
+$ EAI_SERVICE
+9 Nome de servizo non soportado en ai_socktype
+$ EAI_SOCKTYPE
+10 ai_socktype non soportado
+$ EAI_SYSTEM
+11 Erro de sistema devolto en errno
+$ EAI_BADHINTS
+12 Valor inválido de hints
+$ EAI_PROTOCOL
+13 Protocolo resolto descoñecido
+$ EAI_OVERFLOW
+14 Búfer de argumentos excedido
+$ 0
+32766 Éxito
+$ NL_MSGMAX
+32767 Erro descoñecido
diff --git a/lib/libc/nls/hu_HU.ISO8859-2.msg b/lib/libc/nls/hu_HU.ISO8859-2.msg
new file mode 100644
index 000000000000..330d486a7b8e
--- /dev/null
+++ b/lib/libc/nls/hu_HU.ISO8859-2.msg
@@ -0,0 +1,295 @@
+$ $FreeBSD$
+$
+$ Message catalog for hu_HU.ISO8859-2 locale
+$
+$ strerror() support catalog
+$
+$set 1
+$ EPERM
+1 Nem engedélyezett mûvelet
+$ ENOENT
+2 Fájl vagy könyvtár nem található
+$ ESRCH
+3 Processz nem található
+$ EINTR
+4 Megszakított rendszerhívás
+$ EIO
+5 B/K hiba
+$ ENXIO
+6 Konfigurálatlan eszköz
+$ E2BIG
+7 Túl hosszú argumentumlista
+$ ENOEXEC
+8 Hibás végrehajtható formátum
+$ EBADF
+9 Rossz fájlleíró
+$ ECHILD
+10 Nem létezõ gyermek processz
+$ EDEADLK
+11 Resource deadlock avoided
+$ ENOMEM
+12 Memória nem foglalható le
+$ EACCES
+13 Hozzáférés megtagadva
+$ EFAULT
+14 Rossz cím
+$ ENOTBLK
+15 Blokkos eszköz szükséges
+$ EBUSY
+16 Eszköz foglalt
+$ EEXIST
+17 Fájl létezik
+$ EXDEV
+18 Kereszthivatkozás eszközökön
+$ ENODEV
+19 A mûvelet nem támogatott az eszköz által
+$ ENOTDIR
+20 Nem könyvtár
+$ EISDIR
+21 Könyvtár
+$ EINVAL
+22 Érvénytelen argumentum
+$ ENFILE
+23 Túl sok megnyitott fájl a rendszerben
+$ EMFILE
+24 Túl sok megnyitott fájl
+$ ENOTTY
+25 Nem megfelelõ ioctl az eszközhöz
+$ ETXTBSY
+26 Szöveges fájl foglalt
+$ EFBIG
+27 Fájl túl nagy
+$ ENOSPC
+28 Nincs hely az eszközön
+$ ESPIPE
+29 Érvénytelen seek
+$ EROFS
+30 Csak olvasható fájlrendszer
+$ EMLINK
+31 Túl sok link
+$ EPIPE
+32 Hibás csõvezeték
+$ EDOM
+33 Numerikus argumentum nem esik a tartományba
+$ ERANGE
+34 Az esermény túl nagy
+$ EAGAIN, EWOULDBLOCK
+35 Az erõforrás ideiglenesen nem érhetõ el
+$ EINPROGRESS
+36 A mûvelet folyamatban van
+$ EALREADY
+37 A mûvelet már folyamatban van
+$ ENOTSOCK
+38 Socket mûvelet nem socketen
+$ EDESTADDRREQ
+39 Cél cím szükséges
+$ EMSGSIZE
+40 Túl hosszú üzenet
+$ EPROTOTYPE
+41 Rossz protokolltípus a sockethez
+$ ENOPROTOOPT
+42 Protokoll nem érhetõ el
+$ EPROTONOSUPPORT
+43 Protokoll nem támogatott
+$ ESOCKTNOSUPPORT
+44 Sockettípus nem támogatott
+$ EOPNOTSUPP
+45 Mûvelet nem támogatott
+$ EPFNOSUPPORT
+46 Protokollcsalád nem támogatott
+$ EAFNOSUPPORT
+47 A címcsalád nem támogatott a protokollcsalád által
+$ EADDRINUSE
+48 A cím már használatban van
+$ EADDRNOTAVAIL
+49 A kért cím nem osztható ki
+$ ENETDOWN
+50 A hálózat nem mûködik
+$ ENETUNREACH
+51 A hálózat nem érhetõ el
+$ ENETRESET
+52 A hálózat megszakította a kapcsolatot
+$ ECONNABORTED
+53 A szoftver megszakította a kapcsolatot
+$ ECONNRESET
+54 A kapcsolatot megszakította a peer
+$ ENOBUFS
+55 Nincs rendelkezésre álló pufferterület
+$ EISCONN
+56 A socket már kapcsolódva van
+$ ENOTCONN
+57 A socket nincs kapcsolódva
+$ ESHUTDOWN
+58 Nem küldhetõ el a socket lebontása után
+$ ETOOMANYREFS
+59 Túl sok hivatkozás: nem illeszthetõ össze
+$ ETIMEDOUT
+60 A mûvelet túllépte a rendelkezésre álló idõt
+$ ECONNREFUSED
+61 Kapcsolat elutasítva
+$ ELOOP
+62 Túl sok szint a szimbolikus linkekben
+$ ENAMETOOLONG
+63 Túl hosszú fájlnév
+$ EHOSTDOWN
+64 A kiszolgáló nem érhetõ el
+$ EHOSTUNREACH
+65 Nincs útvonal a kiszolgálóhoz
+$ ENOTEMPTY
+66 Könyvtár nem üres
+$ EPROCLIM
+67 Túl sok processz
+$ EUSERS
+68 Túl sok felhasználó
+$ EDQUOT
+69 A lemezkvóta túllépve
+$ ESTALE
+70 Elavult NFS fájlkezelõ
+$ EREMOTE
+71 Túl sok szint a távoli útvonalban
+$ EBADRPC
+72 Rossz RPC struktúra
+$ ERPCMISMATCH
+73 Rossz RPC verzió
+$ EPROGUNAVAIL
+74 RPC program nem érhetõ el
+$ EPROGMISMATCH
+75 Rossz programverzió
+$ EPROCUNAVAIL
+76 Rossz eljárás a programhoz
+$ ENOLCK
+77 Nincs elérhetõ zárolás
+$ ENOSYS
+78 Nem implementált funkció
+$ EFTYPE
+79 Nem megfelelõ fájltípus vagy formátum
+$ EAUTH
+80 Azonosítási hiba
+$ ENEEDAUTH
+81 Azonosítás szükséges
+$ EIDRM
+82 Azonosító eltávolítva
+$ ENOMSG
+83 Nincs üzenet a kívánt típusból
+$ EOVERFLOW
+84 Az érték túl nagy az adott adattípusban való tároláshoz
+$ ECANCELED
+85 Mûvelet törölva
+$ EILSEQ
+86 Érvénytelen bájtsorrend
+$ ENOATTR
+87 Attribútum nem található
+$ EDOOFUS
+88 Programozási hiba
+$ EBADMSG
+89 Helytelen üzenet
+$ EMULTIHOP
+90 Multihop kísérlet
+$ ENOLINK
+91 A kapcsolat szigorítva lett
+$ EPROTO
+92 Protokol hiba
+$ ENOTCAPABLE
+93 Elégtelen képességek
+$
+$ strsignal() support catalog
+$
+$set 2
+$ SIGHUP
+1 Hangup
+$ SIGINT
+2 Megszakítás
+$ SIGQUIT
+3 Kilépés
+$ SIGILL
+4 Érvénytelen mûvelet
+$ SIGTRAP
+5 Trace/BPT csapda
+$ SIGABRT
+6 Abort csapda
+$ SIGEMT
+7 EMT csapda
+$ SIGFPE
+8 Lebegõpontos kivétel
+$ SIGKILL
+9 Megölve
+$ SIGBUS
+10 Busz hiba
+$ SIGSEGV
+11 Szegmentációs hiba
+$ SIGSYS
+12 Rossz rendszerhívás
+$ SIGPIPE
+13 Hibás csõvezeték
+$ SIGALRM
+14 Idõzítési riasztás
+$ SIGTERM
+15 Befejezve
+$ SIGURG
+16 Sürgõs B/K feltétel
+$ SIGSTOP
+17 Elaltatva (szignál)
+$ SIGTSTP
+18 Elaltatva
+$ SIGCONT
+19 Folytatva
+$ SIGCHLD
+20 Gyermek befejezõdött
+$ SIGTTIN
+21 Leállítva (tty bevitel)
+$ SIGTTOU
+22 Leállítva (tty kivitel)
+$ SIGIO
+23 B/K lehetséges
+$ SIGXCPU
+24 Processzoridõ-korlátozás túllépve
+$ SIGXFSZ
+25 ájlméret-korlátozás túllépve
+$ SIGVTALRM
+26 Virtuális idõzítõ lejárt
+$ SIGPROF
+27 Profilidõzítõ lejárt
+$ SIGWINCH
+28 Ablakméret-változások
+$ SIGINFO
+29 Információkérés
+$ SIGUSR1
+30 Felhasználói szignál 1
+$ SIGUSR2
+31 Felhasználói szignál 2
+$
+$ gai_strerror() support catalog
+$
+$set 3
+$ 1 (elavult)
+1 A hosztnévhez tartozó címcsalád nem támogatott
+$ EAI_AGAIN
+2 Ideiglenes hiba a névfeloldáskor
+$ EAI_BADFLAGS
+3 Érvénytelen ai_flags érték
+$ EAI_FAIL
+4 Nem helyreállítható hiba a névfeloldásban
+$ EAI_FAMILY
+5 ai_family nem támogatott
+$ EAI_MEMORY
+6 Memóriafoglalási hiba
+$ 7 (elavult)
+7 Nem tartozik cím í hosztnévhez
+$ EAI_NONAME
+8 Se hosztnév, se szolgáltatásnév nem áll rendelkezésre
+$ EAI_SERVICE
+9 Nem támogatott ai_socktype szolgáltatásnév
+$ EAI_SOCKTYPE
+10 ai_socktype nem támogatott
+$ EAI_SYSTEM
+11 Rendszerhiba jött vissza az errno változóban
+$ EAI_BADHINTS
+12 Érvénytelen hint érték
+$ EAI_PROTOCOL
+13 A feloldott protokol ismeretlen
+$ EAI_OVERFLOW
+14 Az argumentumok puffere túlcsordult
+$ 0
+32766 Siker
+$ NL_MSGMAX
+32767 Ismeretlen hiba
diff --git a/lib/libc/nls/it_IT.ISO8859-15.msg b/lib/libc/nls/it_IT.ISO8859-15.msg
new file mode 100644
index 000000000000..da3734d04d50
--- /dev/null
+++ b/lib/libc/nls/it_IT.ISO8859-15.msg
@@ -0,0 +1,231 @@
+$ $FreeBSD$
+$
+$ Message catalog for it_IT.ISO8859-15 locale
+$
+$ strerror() support catalog
+$
+$set 1
+$ EPERM
+1 Operazione non permessa
+$ ENOENT
+2 File o directory inesistente
+$ ESRCH
+3 Processo inesistente
+$ EINTR
+4 Chiamata di sistema interrotta
+$ EIO
+5 Errore di input/output
+$ ENXIO
+6 Periferica non configurata
+$ E2BIG
+7 Lista degli argomenti troppo lunga
+$ ENOEXEC
+8 Errore nel formato eseguibile
+$ EBADF
+9 Descrittore di file non valido
+$ ECHILD
+10 Nessun processo figlio
+$ EDEADLK
+11 Situazione di deadlock evitata
+$ ENOMEM
+12 Impossibile allocare memoria
+$ EACCES
+13 Permesso negato
+$ EFAULT
+14 Indirizzo non valido
+$ ENOTBLK
+15 Periferica a blocchi necessaria
+$ EBUSY
+16 Periferica occupata
+$ EEXIST
+17 Il file esiste
+$ EXDEV
+18 Link improprio
+$ ENODEV
+19 Operazione non supportata dalla periferica
+$ ENOTDIR
+20 Non è una directory
+$ EISDIR
+21 E' una directory
+$ EINVAL
+22 Argomento non valido
+$ ENFILE
+23 Troppi file aperti nel sistema
+$ EMFILE
+24 Troppi file aperti
+$ ENOTTY
+25 Ioctl inappropriata per la periferica
+$ ETXTBSY
+26 File di testo occupato
+$ EFBIG
+27 File troppo grande
+$ ENOSPC
+28 Spazio sulla periferica esaurito
+$ ESPIPE
+29 Ricerca non valida
+$ EROFS
+30 Filesystem di sola lettura
+$ EMLINK
+31 Troppi link
+$ EPIPE
+32 Pipe rotta
+$ EDOM
+33 Argomento numerico fuori dal dominio
+$ ERANGE
+34 Risultato troppo grande
+$ EAGAIN, EWOULDBLOCK
+35 Risorsa temporaneamente non disponibile
+$ EINPROGRESS
+36 Operazione in esecuzione
+$ EALREADY
+37 Operazione già in esecuzione
+$ ENOTSOCK
+38 Operazione sui socket eseguita su un non-socket
+$ EDESTADDRREQ
+39 Indirizzo destinazione necessario
+$ EMSGSIZE
+40 Messaggio troppo lungo
+$ EPROTOTYPE
+41 Tipo di protocollo non valido per il socket
+$ ENOPROTOOPT
+42 Protocollo non disponibile
+$ EPROTONOSUPPORT
+43 Protocollo non supportato
+$ ESOCKTNOSUPPORT
+44 Tipo di socket non supportato
+$ EOPNOTSUPP
+45 Operazione non supportata
+$ EPFNOSUPPORT
+46 Famiglia di protocolli non supportata
+$ EAFNOSUPPORT
+47 Famiglia di indirizzi non supportata dalla famiglia di protocolli
+$ EADDRINUSE
+48 Indirizzo già in uso
+$ EADDRNOTAVAIL
+49 Impossibile assegnare l'indirizzo richiesto
+$ ENETDOWN
+50 Network fuori uso
+$ ENETUNREACH
+51 Network non raggiungibile
+$ ENETRESET
+52 Network dropped connection on reset
+$ ECONNABORTED
+53 Interruzione della connessione causata dal software
+$ ECONNRESET
+54 Connessione azzerata dal corrispondente
+$ ENOBUFS
+55 Spazio del buffer esaurito
+$ EISCONN
+56 Socket già connesso
+$ ENOTCONN
+57 Socket non connesso
+$ ESHUTDOWN
+58 Impossibile inviare dopo la chiusura del socket
+$ ETOOMANYREFS
+59 Troppe referenze: impossibile raccordare
+$ ETIMEDOUT
+60 Connessione scaduta
+$ ECONNREFUSED
+61 Connection rifiutata
+$ ELOOP
+62 Troppi livelli di link simbolici
+$ ENAMETOOLONG
+63 Nome di file troppo lungo
+$ EHOSTDOWN
+64 Host fuori uso
+$ EHOSTUNREACH
+65 Host irraggiungibile
+$ ENOTEMPTY
+66 Directory non vuota
+$ EPROCLIM
+67 Troppi processi
+$ EUSERS
+68 Troppi utenti
+$ EDQUOT
+69 Quota disco superata
+$ ESTALE
+70 Manipolatore di file NFS scaduto
+$ EREMOTE
+71 Troppi livelli remoti nel path
+$ EBADRPC
+72 Struttura RPC non valida
+$ ERPCMISMATCH
+73 Versione RPC non corrispondente
+$ EPROGUNAVAIL
+74 Programma RPC non disponibile
+$ EPROGMISMATCH
+75 Versione del programma non corrispodente
+$ EPROCUNAVAIL
+76 Procedura non disponibile
+$ ENOLCK
+77 Nessun lock disponibile
+$ ENOSYS
+78 Funzione non implementata
+$ EFTYPE
+79 Tipo di file o formato inappropriato
+$
+$ strsignal() support catalog
+$
+$set 2
+$ SIGHUP
+1 Hangup
+$ SIGINT
+2 Interruzione
+$ SIGQUIT
+3 Chiusura
+$ SIGILL
+4 Istruzione illegale
+$ SIGTRAP
+5 Trappola Trace/breakpoint
+$ SIGABRT
+6 Trappola abort()
+$ SIGEMT
+7 Trappola EMT
+$ SIGFPE
+8 Errore di virgola mobile
+$ SIGKILL
+9 Ucciso
+$ SIGBUS
+10 Errore di bus
+$ SIGSEGV
+11 Errore di segmentazione
+$ SIGSYS
+12 Chiamata di sistema non valida
+$ SIGPIPE
+13 Pipe rotta
+$ SIGALRM
+14 Sveglia
+$ SIGTERM
+15 Terminato
+$ SIGURG
+16 I/O urgente
+$ SIGSTOP
+17 Processo fermato
+$ SIGTSTP
+18 Stop da terminale
+$ SIGCONT
+19 Continuato
+$ SIGCHLD
+20 Processo figlio uscito
+$ SIGTTIN
+21 Input da terminale per processo in background
+$ SIGTTOU
+22 Output a terminale per processo in background
+$ SIGIO
+23 I/O possibile
+$ SIGXCPU
+24 Limite del tempo di CPU superato
+$ SIGXFSZ
+25 Limite della dimensione del file superato
+$ SIGVTALRM
+26 Timer virtuale scaduto
+$ SIGPROF
+27 Timer di profilo expired
+$ SIGWINCH
+28 Cambio di dimensione della finestra
+$ SIGINFO
+29 Richiesta di informazioni
+$ SIGUSR1
+30 Segnale definito dall'utente 1
+$ SIGUSR2
+31 Segnale definito dall'utente 2
diff --git a/lib/libc/nls/ja_JP.UTF-8.msg b/lib/libc/nls/ja_JP.UTF-8.msg
new file mode 100644
index 000000000000..6be65fbb5c0a
--- /dev/null
+++ b/lib/libc/nls/ja_JP.UTF-8.msg
@@ -0,0 +1,295 @@
+$ $FreeBSD$
+$
+$ Message catalog for ja_JP.UTF-8 locale
+$
+$ strerror() support catalog
+$
+$set 1
+$ EPERM
+1 許å¯ã•ã‚Œã¦ã„ãªã„æ“作ã§ã™
+$ ENOENT
+2 ãã®ã‚ˆã†ãªãƒ•ã‚¡ã‚¤ãƒ«ã¾ãŸã¯ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã¯ã‚ã‚Šã¾ã›ã‚“
+$ ESRCH
+3 ãã®ã‚ˆã†ãªãƒ—ロセスã¯ã‚ã‚Šã¾ã›ã‚“
+$ EINTR
+4 システムコールãŒä¸­æ–­ã•ã‚Œã¾ã—ãŸ
+$ EIO
+5 入出力エラーã§ã™
+$ ENXIO
+6 デãƒã‚¤ã‚¹ãŒæº–å‚™ã•ã‚Œã¦ã„ã¾ã›ã‚“
+$ E2BIG
+7 引数ã®ãƒªã‚¹ãƒˆãŒé•·ã™ãŽã¾ã™
+$ ENOEXEC
+8 無効ãªå®Ÿè¡Œå½¢å¼ã§ã™
+$ EBADF
+9 無効ãªãƒ•ã‚¡ã‚¤ãƒ«è¨˜è¿°å­ã§ã™
+$ ECHILD
+10 å­ãƒ—ロセスãŒã‚ã‚Šã¾ã›ã‚“
+$ EDEADLK
+11 リソースデッドロックを回é¿ã—ã¾ã—ãŸ
+$ ENOMEM
+12 メモリã®å‰²ã‚Šå½“ã¦ãŒã§ãã¾ã›ã‚“
+$ EACCES
+13 パーミッションãŒæ‹’絶ã•ã‚Œã¾ã—ãŸ
+$ EFAULT
+14 無効ãªã‚¢ãƒ‰ãƒ¬ã‚¹ã§ã™
+$ ENOTBLK
+15 ブロックデãƒã‚¤ã‚¹ãŒè¦æ±‚ã•ã‚Œã¦ã„ã¾ã™
+$ EBUSY
+16 デãƒã‚¤ã‚¹ãŒãƒ“ジー状態ã§ã™
+$ EEXIST
+17 ファイルãŒå­˜åœ¨ã—ã¾ã™
+$ EXDEV
+18 デãƒã‚¤ã‚¹ã‚’ã¾ãŸãリンクã§ã™
+$ ENODEV
+19 デãƒã‚¤ã‚¹ãŒå¯¾å¿œã—ã¦ãªã„æ“作ã§ã™
+$ ENOTDIR
+20 ディレクトリã§ã¯ã‚ã‚Šã¾ã›ã‚“
+$ EISDIR
+21 ディレクトリã§ã™
+$ EINVAL
+22 無効ãªå¼•æ•°ã§ã™
+$ ENFILE
+23 システム内ã§ã‚ªãƒ¼ãƒ—ンã•ã‚Œã¦ã„るファイルãŒå¤šã™ãŽã¾ã™
+$ EMFILE
+24 オープンã—ã¦ã„るファイルãŒå¤šã™ãŽã¾ã™
+$ ENOTTY
+25 デãƒã‚¤ã‚¹ãŒå¯¾å¿œã—ã¦ã„ãªã„ ioctl ã§ã™
+$ ETXTBSY
+26 テキストファイルãŒãƒ“ジー状態ã§ã™
+$ EFBIG
+27 ファイルãŒå¤§ãã™ãŽã¾ã™
+$ ENOSPC
+28 デãƒã‚¤ã‚¹ã®ç©ºã領域ä¸è¶³ã§ã™
+$ ESPIPE
+29 無効ãªã‚·ãƒ¼ã‚¯ã§ã™
+$ EROFS
+30 読ã¿è¾¼ã¿å°‚用ファイルシステムã§ã™
+$ EMLINK
+31 リンク数ãŒå¤šã™ãŽã¾ã™
+$ EPIPE
+32 パイプãŒç ´å£Šã•ã‚Œã¦ã¾ã—ãŸ
+$ EDOM
+33 数値引数ãŒç¯„囲外ã§ã™
+$ ERANGE
+34 çµæžœãŒå¤§ãéŽãŽã¾ã™
+$ EAGAIN, EWOULDBLOCK
+35 リソースãŒä¸€æ™‚çš„ã«åˆ©ç”¨ã§ãã¾ã›ã‚“
+$ EINPROGRESS
+36 æ“作ãŒç¾åœ¨é€²è¡Œä¸­ã§ã™
+$ EALREADY
+37 æ“作ã¯æ—¢ã«é€²è¡Œä¸­ã§ã™
+$ ENOTSOCK
+38 ソケットã§ãªã„ã‚‚ã®ã«ã¤ã„ã¦ã‚½ã‚±ãƒƒãƒˆæ“作を行ã„ã¾ã—ãŸ
+$ EDESTADDRREQ
+39 宛先アドレスãŒè¦æ±‚ã•ã‚Œã¦ã„ã¾ã™
+$ EMSGSIZE
+40 メッセージãŒé•·ã™ãŽã¾ã™
+$ EPROTOTYPE
+41 ソケットãŒå¯¾å¿œã—ã¦ã„ãªã„プロトコルタイプã§ã™
+$ ENOPROTOOPT
+42 利用ã§ããªã„プロトコルã§ã™
+$ EPROTONOSUPPORT
+43 対応ã—ã¦ã„ãªã„プロトコルã§ã™
+$ ESOCKTNOSUPPORT
+44 対応ã—ã¦ã„ãªã„ソケットタイプã§ã™
+$ EOPNOTSUPP
+45 対応ã—ã¦ã„ãªã„æ“作ã§ã™
+$ EPFNOSUPPORT
+46 対応ã—ã¦ã„ãªã„プロトコルファミリã§ã™
+$ EAFNOSUPPORT
+47 プロトコルファミリãŒå¯¾å¿œã—ã¦ã„ãªã„アドレスファミリãŒæŒ‡å®šã•ã‚Œã¾ã—ãŸ
+$ EADDRINUSE
+48 アドレスãŒæ—¢ã«ä½¿ç”¨ä¸­ã§ã™
+$ EADDRNOTAVAIL
+49 è¦æ±‚ã•ã‚ŒãŸã‚¢ãƒ‰ãƒ¬ã‚¹ã‚’割り当ã¦ã§ãã¾ã›ã‚“
+$ ENETDOWN
+50 ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ãŒãƒ€ã‚¦ãƒ³ã—ã¦ã„ã¾ã™
+$ ENETUNREACH
+51 ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã«åˆ°é”ã§ãã¾ã›ã‚“
+$ ENETRESET
+52 リセットã«ã‚ˆã‚Šãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã®æŽ¥ç¶šãŒå¤±ã‚ã‚Œã¾ã—ãŸ
+$ ECONNABORTED
+53 ソフトウェアã«ã‚ˆã£ã¦æŽ¥ç¶šãŒåˆ‡æ–­ã•ã‚Œã¾ã—ãŸ
+$ ECONNRESET
+54 接続ãŒé€šä¿¡ç›¸æ‰‹ã«ã‚ˆã£ã¦ãƒªã‚»ãƒƒãƒˆã•ã‚Œã¾ã—ãŸ
+$ ENOBUFS
+55 ãƒãƒƒãƒ•ã‚¡ã®å®¹é‡ä¸è¶³ã§ã™
+$ EISCONN
+56 ソケットã¯æ—¢ã«æŽ¥ç¶šã•ã‚Œã¦ã„ã¾ã™
+$ ENOTCONN
+57 ソケットã¯æŽ¥ç¶šã•ã‚Œã¦ã„ã¾ã›ã‚“
+$ ESHUTDOWN
+58 ソケットã®ã‚·ãƒ£ãƒƒãƒˆãƒ€ã‚¦ãƒ³ã®å¾Œã§é€ä¿¡ãŒã§ãã¾ã›ã‚“
+$ ETOOMANYREFS
+59 処ç†é™ç•Œã‚’超ãˆã‚‹å¤šé‡å‚ç…§ã§ã™
+$ ETIMEDOUT
+60 æ“作ãŒã‚¿ã‚¤ãƒ ã‚¢ã‚¦ãƒˆã—ã¾ã—ãŸ
+$ ECONNREFUSED
+61 接続ãŒæ‹’絶ã•ã‚Œã¾ã—ãŸ
+$ ELOOP
+62 処ç†é™ç•Œã‚’超ãˆã‚‹ã‚·ãƒ³ãƒœãƒªãƒƒã‚¯ãƒªãƒ³ã‚¯ãƒ¬ãƒ™ãƒ«ã§ã™
+$ ENAMETOOLONG
+63 ファイルåãŒé•·ã™ãŽã¾ã™
+$ EHOSTDOWN
+64 ホストãŒãƒ€ã‚¦ãƒ³ã—ã¦ã„ã¾ã™
+$ EHOSTUNREACH
+65 ホストã¸ã®çµŒè·¯ãŒã‚ã‚Šã¾ã›ã‚“
+$ ENOTEMPTY
+66 ディレクトリãŒç©ºã§ã¯ã‚ã‚Šã¾ã›ã‚“
+$ EPROCLIM
+67 プロセスãŒå¤šã™ãŽã¾ã™
+$ EUSERS
+68 ユーザãŒå¤šã™ãŽã¾ã™
+$ EDQUOT
+69 ディスククォータãŒè¶…éŽã—ã¾ã—ãŸ
+$ ESTALE
+70 失効ã—㟠NFS ファイルãƒãƒ³ãƒ‰ãƒ«ã§ã™
+$ EREMOTE
+71 パス中ã®ãƒªãƒ¢ãƒ¼ãƒˆã®ãƒ¬ãƒ™ãƒ«ãŒå¤šã™ãŽã¾ã™
+$ EBADRPC
+72 無効㪠RPC 構造体ã§ã™
+$ ERPCMISMATCH
+73 RPC ãƒãƒ¼ã‚¸ãƒ§ãƒ³ãŒé–“é•ã£ã¦ã„ã¾ã™
+$ EPROGUNAVAIL
+74 RPC プログラムãŒåˆ©ç”¨ã§ãã¾ã›ã‚“
+$ EPROGMISMATCH
+75 プログラムã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ãŒåˆã£ã¦ã„ã¾ã›ã‚“
+$ EPROCUNAVAIL
+76 プログラムã§ã¯åˆ©ç”¨ã§ããªã„ procedure ã§ã™
+$ ENOLCK
+77 ロックãŒåˆ©ç”¨ã§ãã¾ã›ã‚“
+$ ENOSYS
+78 関数ãŒå®Ÿè£…ã•ã‚Œã¦ã„ã¾ã›ã‚“
+$ EFTYPE
+79 ファイルã®åž‹ã¾ãŸã¯å½¢å¼ãŒä¸é©åˆ‡ã§ã™
+$ EAUTH
+80 èªè¨¼ã‚¨ãƒ©ãƒ¼ã§ã™
+$ ENEEDAUTH
+81 èªè¨¼ç‰©ãŒå¿…è¦ã§ã™
+$ EIDRM
+82 識別å­ã¯å‰Šé™¤ã•ã‚Œã¾ã—ãŸ
+$ ENOMSG
+83 è¦æ±‚ã•ã‚ŒãŸåž‹ã®ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ãŒã‚ã‚Šã¾ã›ã‚“
+$ EOVERFLOW
+84 データ型ã«æ ¼ç´ã™ã‚‹ã«ã¯å¤§ãã™ãŽã‚‹å€¤ã§ã™
+$ ECANCELED
+85 処ç†ãŒã‚­ãƒ£ãƒ³ã‚»ãƒ«ã•ã‚Œã¾ã—ãŸ
+$ EILSEQ
+86 ä¸æ­£ãªãƒã‚¤ãƒˆåˆ—ã§ã™
+$ ENOATTR
+87 ãã®ã‚ˆã†ãªå±žæ€§ã¯ã‚ã‚Šã¾ã›ã‚“
+$ EDOOFUS
+88 プログラミングエラーã§ã™
+$ EBADMSG
+89 無効ãªãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã§ã™
+$ EMULTIHOP
+90 マルãƒãƒ›ãƒƒãƒ—ãŒè©¦ã¿ã‚‰ã‚Œã¾ã—ãŸ
+$ ENOLINK
+91 リンクãŒåˆ‡æ–­ã•ã‚Œã¦ã„ã¾ã™
+$ EPROTO
+92 プロトコルエラーã§ã™
+$ ENOTCAPABLE
+93 ケーパビリティãŒä¸è¶³ã§ã™
+$
+$ strsignal() support catalog
+$
+$set 2
+$ SIGHUP
+1 ãƒãƒ³ã‚°ã‚¢ãƒƒãƒ—
+$ SIGINT
+2 割り込ã¿
+$ SIGQUIT
+3 中断
+$ SIGILL
+4 ä¸æ­£å‘½ä»¤
+$ SIGTRAP
+5 トレース/BPT トラップ
+$ SIGABRT
+6 アボートトラップ
+$ SIGEMT
+7 EMT トラップ
+$ SIGFPE
+8 浮動å°æ•°ç‚¹ä¾‹å¤–
+$ SIGKILL
+9 Kill ã•ã‚ŒãŸ
+$ SIGBUS
+10 ãƒã‚¹ã‚¨ãƒ©ãƒ¼
+$ SIGSEGV
+11 セグメンテーションé•å
+$ SIGSYS
+12 存在ã—ãªã„システムコール
+$ SIGPIPE
+13 パイプ破壊
+$ SIGALRM
+14 アラームクロック
+$ SIGTERM
+15 終了
+$ SIGURG
+16 緊急入出力状æ³
+$ SIGSTOP
+17 一時åœæ­¢ (シグナル)
+$ SIGTSTP
+18 一時åœæ­¢
+$ SIGCONT
+19 継続
+$ SIGCHLD
+20 å­ãƒ—ロセスã®çµ‚了
+$ SIGTTIN
+21 一時åœæ­¢ (tty 入力)
+$ SIGTTOU
+22 一時åœæ­¢ (tty 出力)
+$ SIGIO
+23 入出力å¯èƒ½
+$ SIGXCPU
+24 CPU 時間ã®åˆ¶é™è¶…éŽ
+$ SIGXFSZ
+25 ファイルサイズã®åˆ¶é™è¶…éŽ
+$ SIGVTALRM
+26 仮想タイマã®æœŸé™è¶…éŽ
+$ SIGPROF
+27 プロファイルタイマã®æœŸé™è¶…éŽ
+$ SIGWINCH
+28 ウィンドウサイズã®å¤‰åŒ–
+$ SIGINFO
+29 情報è¦æ±‚
+$ SIGUSR1
+30 ユーザ定義シグナル 1
+$ SIGUSR2
+31 ユーザ定義シグナル 2
+$
+$ gai_strerror() support catalog
+$
+$set 3
+$ 1 (obsolete)
+1 ホストåã®ã‚¢ãƒ‰ãƒ¬ã‚¹ãƒ•ã‚¡ãƒŸãƒªãƒ¼ã¯ã‚µãƒãƒ¼ãƒˆã•ã‚Œã¾ã›ã‚“
+$ EAI_AGAIN
+2 åå‰è§£æ±ºã§ã®ä¸€æ™‚çš„ãªå¤±æ•—
+$ EAI_BADFLAGS
+3 ai_flags ã®å€¤ãŒç„¡åŠ¹
+$ EAI_FAIL
+4 åå‰è§£æ±ºã§ã®å›žå¾©ä¸èƒ½ãªå¤±æ•—
+$ EAI_FAMILY
+5 ai_family ã¯ã‚µãƒãƒ¼ãƒˆã•ã‚Œã¾ã›ã‚“
+$ EAI_MEMORY
+6 メモリ割り当ã¦å¤±æ•—
+$ 7 (obsolete)
+7 ホストåã«å¯¾å¿œã™ã‚‹ã‚¢ãƒ‰ãƒ¬ã‚¹ã¯ã‚ã‚Šã¾ã›ã‚“
+$ EAI_NONAME
+8 ホストåã‹ã‚µãƒ¼ãƒ“スåãŒæŒ‡å®šã•ã‚Œãªã„ã€ã¾ãŸã¯ä¸æ˜Ž
+$ EAI_SERVICE
+9 サービスå㯠ai_socktype ã«å¯¾ã—ã¦ã‚µãƒãƒ¼ãƒˆã•ã‚Œã¾ã›ã‚“
+$ EAI_SOCKTYPE
+10 ai_socktype ã¯ã‚µãƒãƒ¼ãƒˆã•ã‚Œã¾ã›ã‚“
+$ EAI_SYSTEM
+11 システムエラーã€errno å‚ç…§
+$ EAI_BADHINTS
+12 hints ã®å€¤ãŒç„¡åŠ¹
+$ EAI_PROTOCOL
+13 解決ã•ã‚ŒãŸãƒ—ロトコルã¯ä¸æ˜Žã§ã™
+$ EAI_OVERFLOW
+14 引数ãƒãƒƒãƒ•ã‚¡ã‚ªãƒ¼ãƒãƒ•ãƒ­ãƒ¼
+$ 0
+32766 æˆåŠŸ
+$ NL_MSGMAX
+32767 ä¸æ˜Žãªã‚¨ãƒ©ãƒ¼
diff --git a/lib/libc/nls/ja_JP.eucJP.msg b/lib/libc/nls/ja_JP.eucJP.msg
new file mode 100644
index 000000000000..e3fac48c6a13
--- /dev/null
+++ b/lib/libc/nls/ja_JP.eucJP.msg
@@ -0,0 +1,295 @@
+$ $FreeBSD$
+$
+$ Message catalog for ja_JP.eucJP locale
+$
+$ strerror() support catalog
+$
+$set 1
+$ EPERM
+1 µö²Ä¤µ¤ì¤Æ¤¤¤Ê¤¤Áàºî¤Ç¤¹
+$ ENOENT
+2 ¤½¤Î¤è¤¦¤Ê¥Õ¥¡¥¤¥ë¤Þ¤¿¤Ï¥Ç¥£¥ì¥¯¥È¥ê¤Ï¤¢¤ê¤Þ¤»¤ó
+$ ESRCH
+3 ¤½¤Î¤è¤¦¤Ê¥×¥í¥»¥¹¤Ï¤¢¤ê¤Þ¤»¤ó
+$ EINTR
+4 ¥·¥¹¥Æ¥à¥³¡¼¥ë¤¬ÃæÃǤµ¤ì¤Þ¤·¤¿
+$ EIO
+5 Æþ½ÐÎÏ¥¨¥é¡¼¤Ç¤¹
+$ ENXIO
+6 ¥Ç¥Ð¥¤¥¹¤¬½àÈ÷¤µ¤ì¤Æ¤¤¤Þ¤»¤ó
+$ E2BIG
+7 °ú¿ô¤Î¥ê¥¹¥È¤¬Ä¹¤¹¤®¤Þ¤¹
+$ ENOEXEC
+8 ̵¸ú¤Ê¼Â¹Ô·Á¼°¤Ç¤¹
+$ EBADF
+9 ̵¸ú¤Ê¥Õ¥¡¥¤¥ëµ­½Ò»Ò¤Ç¤¹
+$ ECHILD
+10 »Ò¥×¥í¥»¥¹¤¬¤¢¤ê¤Þ¤»¤ó
+$ EDEADLK
+11 ¥ê¥½¡¼¥¹¥Ç¥Ã¥É¥í¥Ã¥¯¤ò²óÈò¤·¤Þ¤·¤¿
+$ ENOMEM
+12 ¥á¥â¥ê¤Î³ä¤êÅö¤Æ¤¬¤Ç¤­¤Þ¤»¤ó
+$ EACCES
+13 ¥Ñ¡¼¥ß¥Ã¥·¥ç¥ó¤¬µñÀ䤵¤ì¤Þ¤·¤¿
+$ EFAULT
+14 ̵¸ú¤Ê¥¢¥É¥ì¥¹¤Ç¤¹
+$ ENOTBLK
+15 ¥Ö¥í¥Ã¥¯¥Ç¥Ð¥¤¥¹¤¬Í׵ᤵ¤ì¤Æ¤¤¤Þ¤¹
+$ EBUSY
+16 ¥Ç¥Ð¥¤¥¹¤¬¥Ó¥¸¡¼¾õÂ֤Ǥ¹
+$ EEXIST
+17 ¥Õ¥¡¥¤¥ë¤¬Â¸ºß¤·¤Þ¤¹
+$ EXDEV
+18 ¥Ç¥Ð¥¤¥¹¤ò¤Þ¤¿¤°¥ê¥ó¥¯¤Ç¤¹
+$ ENODEV
+19 ¥Ç¥Ð¥¤¥¹¤¬Âбþ¤·¤Æ¤Ê¤¤Áàºî¤Ç¤¹
+$ ENOTDIR
+20 ¥Ç¥£¥ì¥¯¥È¥ê¤Ç¤Ï¤¢¤ê¤Þ¤»¤ó
+$ EISDIR
+21 ¥Ç¥£¥ì¥¯¥È¥ê¤Ç¤¹
+$ EINVAL
+22 ̵¸ú¤Ê°ú¿ô¤Ç¤¹
+$ ENFILE
+23 ¥·¥¹¥Æ¥àÆâ¤Ç¥ª¡¼¥×¥ó¤µ¤ì¤Æ¤¤¤ë¥Õ¥¡¥¤¥ë¤¬Â¿¤¹¤®¤Þ¤¹
+$ EMFILE
+24 ¥ª¡¼¥×¥ó¤·¤Æ¤¤¤ë¥Õ¥¡¥¤¥ë¤¬Â¿¤¹¤®¤Þ¤¹
+$ ENOTTY
+25 ¥Ç¥Ð¥¤¥¹¤¬Âбþ¤·¤Æ¤¤¤Ê¤¤ ioctl ¤Ç¤¹
+$ ETXTBSY
+26 ¥Æ¥­¥¹¥È¥Õ¥¡¥¤¥ë¤¬¥Ó¥¸¡¼¾õÂ֤Ǥ¹
+$ EFBIG
+27 ¥Õ¥¡¥¤¥ë¤¬Â礭¤¹¤®¤Þ¤¹
+$ ENOSPC
+28 ¥Ç¥Ð¥¤¥¹¤Î¶õ¤­ÎΰèÉÔ­¤Ç¤¹
+$ ESPIPE
+29 ̵¸ú¤Ê¥·¡¼¥¯¤Ç¤¹
+$ EROFS
+30 Æɤ߹þ¤ßÀìÍÑ¥Õ¥¡¥¤¥ë¥·¥¹¥Æ¥à¤Ç¤¹
+$ EMLINK
+31 ¥ê¥ó¥¯¿ô¤¬Â¿¤¹¤®¤Þ¤¹
+$ EPIPE
+32 ¥Ñ¥¤¥×¤¬Ç˲õ¤µ¤ì¤Æ¤Þ¤·¤¿
+$ EDOM
+33 ¿ôÃÍ°ú¿ô¤¬Èϰϳ°¤Ç¤¹
+$ ERANGE
+34 ·ë²Ì¤¬Â礭²á¤®¤Þ¤¹
+$ EAGAIN, EWOULDBLOCK
+35 ¥ê¥½¡¼¥¹¤¬°ì»þŪ¤ËÍøÍѤǤ­¤Þ¤»¤ó
+$ EINPROGRESS
+36 Áàºî¤¬¸½ºß¿Ê¹ÔÃæ¤Ç¤¹
+$ EALREADY
+37 Áàºî¤Ï´û¤Ë¿Ê¹ÔÃæ¤Ç¤¹
+$ ENOTSOCK
+38 ¥½¥±¥Ã¥È¤Ç¤Ê¤¤¤â¤Î¤Ë¤Ä¤¤¤Æ¥½¥±¥Ã¥ÈÁàºî¤ò¹Ô¤¤¤Þ¤·¤¿
+$ EDESTADDRREQ
+39 °¸À襢¥É¥ì¥¹¤¬Í׵ᤵ¤ì¤Æ¤¤¤Þ¤¹
+$ EMSGSIZE
+40 ¥á¥Ã¥»¡¼¥¸¤¬Ä¹¤¹¤®¤Þ¤¹
+$ EPROTOTYPE
+41 ¥½¥±¥Ã¥È¤¬Âбþ¤·¤Æ¤¤¤Ê¤¤¥×¥í¥È¥³¥ë¥¿¥¤¥×¤Ç¤¹
+$ ENOPROTOOPT
+42 ÍøÍѤǤ­¤Ê¤¤¥×¥í¥È¥³¥ë¤Ç¤¹
+$ EPROTONOSUPPORT
+43 Âбþ¤·¤Æ¤¤¤Ê¤¤¥×¥í¥È¥³¥ë¤Ç¤¹
+$ ESOCKTNOSUPPORT
+44 Âбþ¤·¤Æ¤¤¤Ê¤¤¥½¥±¥Ã¥È¥¿¥¤¥×¤Ç¤¹
+$ EOPNOTSUPP
+45 Âбþ¤·¤Æ¤¤¤Ê¤¤Áàºî¤Ç¤¹
+$ EPFNOSUPPORT
+46 Âбþ¤·¤Æ¤¤¤Ê¤¤¥×¥í¥È¥³¥ë¥Õ¥¡¥ß¥ê¤Ç¤¹
+$ EAFNOSUPPORT
+47 ¥×¥í¥È¥³¥ë¥Õ¥¡¥ß¥ê¤¬Âбþ¤·¤Æ¤¤¤Ê¤¤¥¢¥É¥ì¥¹¥Õ¥¡¥ß¥ê¤¬»ØÄꤵ¤ì¤Þ¤·¤¿
+$ EADDRINUSE
+48 ¥¢¥É¥ì¥¹¤¬´û¤Ë»ÈÍÑÃæ¤Ç¤¹
+$ EADDRNOTAVAIL
+49 Í׵ᤵ¤ì¤¿¥¢¥É¥ì¥¹¤ò³ä¤êÅö¤Æ¤Ç¤­¤Þ¤»¤ó
+$ ENETDOWN
+50 ¥Í¥Ã¥È¥ï¡¼¥¯¤¬¥À¥¦¥ó¤·¤Æ¤¤¤Þ¤¹
+$ ENETUNREACH
+51 ¥Í¥Ã¥È¥ï¡¼¥¯¤ËÅþã¤Ç¤­¤Þ¤»¤ó
+$ ENETRESET
+52 ¥ê¥»¥Ã¥È¤Ë¤è¤ê¥Í¥Ã¥È¥ï¡¼¥¯¤ÎÀܳ¤¬¼º¤ï¤ì¤Þ¤·¤¿
+$ ECONNABORTED
+53 ¥½¥Õ¥È¥¦¥§¥¢¤Ë¤è¤Ã¤ÆÀܳ¤¬ÀÚÃǤµ¤ì¤Þ¤·¤¿
+$ ECONNRESET
+54 Àܳ¤¬ÄÌ¿®Áê¼ê¤Ë¤è¤Ã¤Æ¥ê¥»¥Ã¥È¤µ¤ì¤Þ¤·¤¿
+$ ENOBUFS
+55 ¥Ð¥Ã¥Õ¥¡¤ÎÍÆÎÌÉÔ­¤Ç¤¹
+$ EISCONN
+56 ¥½¥±¥Ã¥È¤Ï´û¤ËÀܳ¤µ¤ì¤Æ¤¤¤Þ¤¹
+$ ENOTCONN
+57 ¥½¥±¥Ã¥È¤ÏÀܳ¤µ¤ì¤Æ¤¤¤Þ¤»¤ó
+$ ESHUTDOWN
+58 ¥½¥±¥Ã¥È¤Î¥·¥ã¥Ã¥È¥À¥¦¥ó¤Î¸å¤ÇÁ÷¿®¤¬¤Ç¤­¤Þ¤»¤ó
+$ ETOOMANYREFS
+59 ½èÍý¸Â³¦¤òĶ¤¨¤ë¿½Å»²¾È¤Ç¤¹
+$ ETIMEDOUT
+60 Áàºî¤¬¥¿¥¤¥à¥¢¥¦¥È¤·¤Þ¤·¤¿
+$ ECONNREFUSED
+61 Àܳ¤¬µñÀ䤵¤ì¤Þ¤·¤¿
+$ ELOOP
+62 ½èÍý¸Â³¦¤òĶ¤¨¤ë¥·¥ó¥Ü¥ê¥Ã¥¯¥ê¥ó¥¯¥ì¥Ù¥ë¤Ç¤¹
+$ ENAMETOOLONG
+63 ¥Õ¥¡¥¤¥ë̾¤¬Ä¹¤¹¤®¤Þ¤¹
+$ EHOSTDOWN
+64 ¥Û¥¹¥È¤¬¥À¥¦¥ó¤·¤Æ¤¤¤Þ¤¹
+$ EHOSTUNREACH
+65 ¥Û¥¹¥È¤Ø¤Î·ÐÏ©¤¬¤¢¤ê¤Þ¤»¤ó
+$ ENOTEMPTY
+66 ¥Ç¥£¥ì¥¯¥È¥ê¤¬¶õ¤Ç¤Ï¤¢¤ê¤Þ¤»¤ó
+$ EPROCLIM
+67 ¥×¥í¥»¥¹¤¬Â¿¤¹¤®¤Þ¤¹
+$ EUSERS
+68 ¥æ¡¼¥¶¤¬Â¿¤¹¤®¤Þ¤¹
+$ EDQUOT
+69 ¥Ç¥£¥¹¥¯¥¯¥©¡¼¥¿¤¬Ä¶²á¤·¤Þ¤·¤¿
+$ ESTALE
+70 ¼º¸ú¤·¤¿ NFS ¥Õ¥¡¥¤¥ë¥Ï¥ó¥É¥ë¤Ç¤¹
+$ EREMOTE
+71 ¥Ñ¥¹Ãæ¤Î¥ê¥â¡¼¥È¤Î¥ì¥Ù¥ë¤¬Â¿¤¹¤®¤Þ¤¹
+$ EBADRPC
+72 ̵¸ú¤Ê RPC ¹½Â¤ÂΤǤ¹
+$ ERPCMISMATCH
+73 RPC ¥Ð¡¼¥¸¥ç¥ó¤¬´Ö°ã¤Ã¤Æ¤¤¤Þ¤¹
+$ EPROGUNAVAIL
+74 RPC ¥×¥í¥°¥é¥à¤¬ÍøÍѤǤ­¤Þ¤»¤ó
+$ EPROGMISMATCH
+75 ¥×¥í¥°¥é¥à¤Î¥Ð¡¼¥¸¥ç¥ó¤¬¹ç¤Ã¤Æ¤¤¤Þ¤»¤ó
+$ EPROCUNAVAIL
+76 ¥×¥í¥°¥é¥à¤Ç¤ÏÍøÍѤǤ­¤Ê¤¤ procedure ¤Ç¤¹
+$ ENOLCK
+77 ¥í¥Ã¥¯¤¬ÍøÍѤǤ­¤Þ¤»¤ó
+$ ENOSYS
+78 ´Ø¿ô¤¬¼ÂÁõ¤µ¤ì¤Æ¤¤¤Þ¤»¤ó
+$ EFTYPE
+79 ¥Õ¥¡¥¤¥ë¤Î·¿¤Þ¤¿¤Ï·Á¼°¤¬ÉÔŬÀڤǤ¹
+$ EAUTH
+80 ǧ¾Ú¥¨¥é¡¼¤Ç¤¹
+$ ENEEDAUTH
+81 ǧ¾Úʪ¤¬É¬ÍפǤ¹
+$ EIDRM
+82 ¼±Ê̻ҤϺï½ü¤µ¤ì¤Þ¤·¤¿
+$ ENOMSG
+83 Í׵ᤵ¤ì¤¿·¿¤Î¥á¥Ã¥»¡¼¥¸¤¬¤¢¤ê¤Þ¤»¤ó
+$ EOVERFLOW
+84 ¥Ç¡¼¥¿·¿¤Ë³ÊǼ¤¹¤ë¤Ë¤ÏÂ礭¤¹¤®¤ëÃͤǤ¹
+$ ECANCELED
+85 ½èÍý¤¬¥­¥ã¥ó¥»¥ë¤µ¤ì¤Þ¤·¤¿
+$ EILSEQ
+86 ÉÔÀµ¤Ê¥Ð¥¤¥ÈÎó¤Ç¤¹
+$ ENOATTR
+87 ¤½¤Î¤è¤¦¤Ê°À­¤Ï¤¢¤ê¤Þ¤»¤ó
+$ EDOOFUS
+88 ¥×¥í¥°¥é¥ß¥ó¥°¥¨¥é¡¼¤Ç¤¹
+$ EBADMSG
+89 ̵¸ú¤Ê¥á¥Ã¥»¡¼¥¸¤Ç¤¹
+$ EMULTIHOP
+90 ¥Þ¥ë¥Á¥Û¥Ã¥×¤¬»î¤ß¤é¤ì¤Þ¤·¤¿
+$ ENOLINK
+91 ¥ê¥ó¥¯¤¬ÀÚÃǤµ¤ì¤Æ¤¤¤Þ¤¹
+$ EPROTO
+92 ¥×¥í¥È¥³¥ë¥¨¥é¡¼¤Ç¤¹
+$ ENOTCAPABLE
+93 ¥±¡¼¥Ñ¥Ó¥ê¥Æ¥£¤¬ÉÔ­¤Ç¤¹
+$
+$ strsignal() support catalog
+$
+$set 2
+$ SIGHUP
+1 ¥Ï¥ó¥°¥¢¥Ã¥×
+$ SIGINT
+2 ³ä¤ê¹þ¤ß
+$ SIGQUIT
+3 ̾̂
+$ SIGILL
+4 ÉÔÀµÌ¿Îá
+$ SIGTRAP
+5 ¥È¥ì¡¼¥¹/BPT ¥È¥é¥Ã¥×
+$ SIGABRT
+6 ¥¢¥Ü¡¼¥È¥È¥é¥Ã¥×
+$ SIGEMT
+7 EMT ¥È¥é¥Ã¥×
+$ SIGFPE
+8 ÉâÆ°¾®¿ôÅÀÎã³°
+$ SIGKILL
+9 Kill ¤µ¤ì¤¿
+$ SIGBUS
+10 ¥Ð¥¹¥¨¥é¡¼
+$ SIGSEGV
+11 ¥»¥°¥á¥ó¥Æ¡¼¥·¥ç¥ó°ãÈ¿
+$ SIGSYS
+12 ¸ºß¤·¤Ê¤¤¥·¥¹¥Æ¥à¥³¡¼¥ë
+$ SIGPIPE
+13 ¥Ñ¥¤¥×Ç˲õ
+$ SIGALRM
+14 ¥¢¥é¡¼¥à¥¯¥í¥Ã¥¯
+$ SIGTERM
+15 ½ªÎ»
+$ SIGURG
+16 ¶ÛµÞÆþ½ÐÎϾõ¶·
+$ SIGSTOP
+17 °ì»þÄä»ß (¥·¥°¥Ê¥ë)
+$ SIGTSTP
+18 °ì»þÄä»ß
+$ SIGCONT
+19 ·Ñ³
+$ SIGCHLD
+20 »Ò¥×¥í¥»¥¹¤Î½ªÎ»
+$ SIGTTIN
+21 °ì»þÄä»ß (tty ÆþÎÏ)
+$ SIGTTOU
+22 °ì»þÄä»ß (tty ½ÐÎÏ)
+$ SIGIO
+23 Æþ½ÐÎϲÄǽ
+$ SIGXCPU
+24 CPU »þ´Ö¤ÎÀ©¸ÂĶ²á
+$ SIGXFSZ
+25 ¥Õ¥¡¥¤¥ë¥µ¥¤¥º¤ÎÀ©¸ÂĶ²á
+$ SIGVTALRM
+26 ²¾ÁÛ¥¿¥¤¥Þ¤Î´ü¸ÂĶ²á
+$ SIGPROF
+27 ¥×¥í¥Õ¥¡¥¤¥ë¥¿¥¤¥Þ¤Î´ü¸ÂĶ²á
+$ SIGWINCH
+28 ¥¦¥£¥ó¥É¥¦¥µ¥¤¥º¤ÎÊѲ½
+$ SIGINFO
+29 ¾ðÊóÍ×µá
+$ SIGUSR1
+30 ¥æ¡¼¥¶ÄêµÁ¥·¥°¥Ê¥ë 1
+$ SIGUSR2
+31 ¥æ¡¼¥¶ÄêµÁ¥·¥°¥Ê¥ë 2
+$
+$ gai_strerror() support catalog
+$
+$set 3
+$ 1 (obsolete)
+1 ¥Û¥¹¥È̾¤Î¥¢¥É¥ì¥¹¥Õ¥¡¥ß¥ê¡¼¤Ï¥µ¥Ý¡¼¥È¤µ¤ì¤Þ¤»¤ó
+$ EAI_AGAIN
+2 ̾Á°²ò·è¤Ç¤Î°ì»þŪ¤Ê¼ºÇÔ
+$ EAI_BADFLAGS
+3 ai_flags ¤ÎÃͤ¬Ìµ¸ú
+$ EAI_FAIL
+4 ̾Á°²ò·è¤Ç¤Î²óÉüÉÔǽ¤Ê¼ºÇÔ
+$ EAI_FAMILY
+5 ai_family ¤Ï¥µ¥Ý¡¼¥È¤µ¤ì¤Þ¤»¤ó
+$ EAI_MEMORY
+6 ¥á¥â¥ê³ä¤êÅö¤Æ¼ºÇÔ
+$ 7 (obsolete)
+7 ¥Û¥¹¥È̾¤ËÂбþ¤¹¤ë¥¢¥É¥ì¥¹¤Ï¤¢¤ê¤Þ¤»¤ó
+$ EAI_NONAME
+8 ¥Û¥¹¥È̾¤«¥µ¡¼¥Ó¥¹Ì¾¤¬»ØÄꤵ¤ì¤Ê¤¤¡¢¤Þ¤¿¤ÏÉÔÌÀ
+$ EAI_SERVICE
+9 ¥µ¡¼¥Ó¥¹Ì¾¤Ï ai_socktype ¤ËÂФ·¤Æ¥µ¥Ý¡¼¥È¤µ¤ì¤Þ¤»¤ó
+$ EAI_SOCKTYPE
+10 ai_socktype ¤Ï¥µ¥Ý¡¼¥È¤µ¤ì¤Þ¤»¤ó
+$ EAI_SYSTEM
+11 ¥·¥¹¥Æ¥à¥¨¥é¡¼¡¢errno »²¾È
+$ EAI_BADHINTS
+12 hints ¤ÎÃͤ¬Ìµ¸ú
+$ EAI_PROTOCOL
+13 ²ò·è¤µ¤ì¤¿¥×¥í¥È¥³¥ë¤ÏÉÔÌÀ¤Ç¤¹
+$ EAI_OVERFLOW
+14 °ú¿ô¥Ð¥Ã¥Õ¥¡¥ª¡¼¥Ð¥Õ¥í¡¼
+$ 0
+32766 À®¸ù
+$ NL_MSGMAX
+32767 ÉÔÌÀ¤Ê¥¨¥é¡¼
diff --git a/lib/libc/nls/ko_KR.UTF-8.msg b/lib/libc/nls/ko_KR.UTF-8.msg
new file mode 100644
index 000000000000..60e8a121dfe4
--- /dev/null
+++ b/lib/libc/nls/ko_KR.UTF-8.msg
@@ -0,0 +1,295 @@
+$ $FreeBSD$
+$
+$ Message catalog for ko_KR.UTF-8 locale
+$
+$ strerror() support catalog
+$
+$set 1
+$ EPERM
+1 ëª…ë ¹ì´ í—ˆìš©ë˜ì§€ 않습니다
+$ ENOENT
+2 íŒŒì¼ ë˜ëŠ” 디렉터리가 없습니다
+$ ESRCH
+3 존재하지 않는 프로세스입니다
+$ EINTR
+4 시스템 í˜¸ì¶œì´ ì¤‘ë‹¨ë˜ì—ˆìŠµë‹ˆë‹¤
+$ EIO
+5 입출력 ì—러입니다
+$ ENXIO
+6 장치가 설정ë˜ì§€ 않았습니다
+$ E2BIG
+7 ì¸ìžê°€ 너무 ê¹ë‹ˆë‹¤
+$ ENOEXEC
+8 실행 íŒŒì¼ í˜•ì‹ì´ 잘못ë˜ì—ˆìŠµë‹ˆë‹¤
+$ EBADF
+9 ìž˜ëª»ëœ íŒŒì¼ ë””ìŠ¤í¬ë¦½í„°ìž…니다
+$ ECHILD
+10 ìžì‹ 프로세스가 없습니다
+$ EDEADLK
+11 ìžì› ë°ë“œë½ì„ 중단하였습니다
+$ ENOMEM
+12 메모리를 할당할 수 없습니다
+$ EACCES
+13 ê¶Œí•œì´ ì—†ìŠµë‹ˆë‹¤
+$ EFAULT
+14 ìž˜ëª»ëœ ì£¼ì†Œê°€ 지정ë˜ì—ˆìŠµë‹ˆë‹¤
+$ ENOTBLK
+15 블럭 장치여야 합니다
+$ EBUSY
+16 장치가 사용 중입니다
+$ EEXIST
+17 파ì¼ì´ ì´ë¯¸ 존재합니다
+$ EXDEV
+18 다른 장치 ê°„ì˜ ì—°ê²°ìž…ë‹ˆë‹¤
+$ ENODEV
+19 ê·¸ 장치가 지ì›í•˜ì§€ 않는 명령입니다
+$ ENOTDIR
+20 디렉터리가 아닙니다
+$ EISDIR
+21 디렉터리입니다
+$ EINVAL
+22 ì¸ìžê°€ 잘못ë˜ì—ˆìŠµë‹ˆë‹¤
+$ ENFILE
+23 ì‹œìŠ¤í…œì— íŒŒì¼ì´ 너무 ë§Žì´ ì—´ë ¤ìžˆìŠµë‹ˆë‹¤
+$ EMFILE
+24 파ì¼ì´ 너무 ë§Žì´ ì—´ë ¤ìžˆìŠµë‹ˆë‹¤
+$ ENOTTY
+25 장치가 지ì›í•˜ì§€ 않는 ioctl입니다
+$ ETXTBSY
+26 Text 파ì¼ì´ 사용 중입니다
+$ EFBIG
+27 파ì¼ì´ 너무 í½ë‹ˆë‹¤
+$ ENOSPC
+28 ìž¥ì¹˜ì— ì—¬ìœ  ê³µê°„ì´ ë‚¨ì•„ìžˆì§€ 않습니다
+$ ESPIPE
+29 ìž˜ëª»ëœ íƒìƒ‰ìž…니다
+$ EROFS
+30 ì½ê¸° ì „ìš© íŒŒì¼ ì‹œìŠ¤í…œìž…ë‹ˆë‹¤
+$ EMLINK
+31 ì—°ê²°ì´ ë„ˆë¬´ 많습니다
+$ EPIPE
+32 파ì´í”„ê°€ ëŠì–´ì¡ŒìŠµë‹ˆë‹¤
+$ EDOM
+33 수치 ì¸ìžê°€ ì˜ì—­ì„ 벗어났습니다
+$ ERANGE
+34 결과가 너무 í½ë‹ˆë‹¤
+$ EAGAIN, EWOULDBLOCK
+35 ìžì›ì„ ìž ì‹œ 사용할 수 없습니다
+$ EINPROGRESS
+36 ìž‘ì—…ì´ ì§„í–‰ 중입니다
+$ EALREADY
+37 ìž‘ì—…ì´ ì´ë¯¸ 진행 중입니다
+$ ENOTSOCK
+38 ì†Œì¼“ì´ ì•„ë‹Œ ê°ì²´ì— 대한 소켓 작업입니다
+$ EDESTADDRREQ
+39 목ì ì§€ 주소가 필요합니다
+$ EMSGSIZE
+40 메시지가 너무 ê¹ë‹ˆë‹¤
+$ EPROTOTYPE
+41 ì†Œì¼“ì— ì‚¬ìš©í•  수 없는 프로토콜 유형입니다
+$ ENOPROTOOPT
+42 í”„ë¡œí† ì½œì„ ì‚¬ìš©í•  수 없습니다
+$ EPROTONOSUPPORT
+43 지ì›í•˜ì§€ 않는 프로토콜입니다
+$ ESOCKTNOSUPPORT
+44 지ì›í•˜ì§€ 않는 ì¢…ë¥˜ì˜ ì†Œì¼“ìž…ë‹ˆë‹¤
+$ EOPNOTSUPP
+45 지ì›ë˜ì§€ 않는 명령입니다
+$ EPFNOSUPPORT
+46 지ì›ë˜ì§€ 않는 프로토콜군입니다
+$ EAFNOSUPPORT
+47 프로토콜군ì—ì„œ 지ì›ë˜ì§€ 않는 주소군입니다
+$ EADDRINUSE
+48 ì´ë¯¸ 사용 ì¤‘ì¸ ì£¼ì†Œìž…ë‹ˆë‹¤
+$ EADDRNOTAVAIL
+49 요청한 주소를 할당할 수 없습니다
+$ ENETDOWN
+50 네트워í¬ê°€ 단절ë˜ì—ˆìŠµë‹ˆë‹¤
+$ ENETUNREACH
+51 네트워í¬ì— ë„달할 수 없습니다
+$ ENETRESET
+52 네트워í¬ê°€ 재설정ë˜ì–´ ì ‘ì†ì´ ëŠì–´ì¡ŒìŠµë‹ˆë‹¤
+$ ECONNABORTED
+53 소프트웨어ì ì¸ ì´ìœ ë¡œ ì—°ê²°ì´ ëŠì–´ì¡ŒìŠµë‹ˆë‹¤
+$ ECONNRESET
+54 ìƒëŒ€ë°©ì´ ì—°ê²°ì„ ëŠì—ˆìŠµë‹ˆë‹¤
+$ ENOBUFS
+55 ë²„í¼ ê³µê°„ì´ ëª¨ìžëžë‹ˆë‹¤
+$ EISCONN
+56 ì†Œì¼“ì´ ì´ë¯¸ ì—°ê²°ë˜ìžˆìŠµë‹ˆë‹¤
+$ ENOTCONN
+57 ì†Œì¼“ì´ ì—°ê²°ë˜ì–´ 있지 않습니다
+$ ESHUTDOWN
+58 ì†Œì¼“ì´ ì´ë¯¸ 중단ë˜ì–´, ë” ì´ìƒ 전송할 수 없습니다
+$ ETOOMANYREFS
+59 참조수가 너무 많아 나눌 수 없습니다
+$ ETIMEDOUT
+60 ì‹œê°„ì´ ë„ˆë¬´ ë§Žì´ ì§€ë‚˜ ìž‘ì—…ì´ ì¤‘ë‹¨ë˜ì—ˆìŠµë‹ˆë‹¤
+$ ECONNREFUSED
+61 ì ‘ì†ì´ 거부ë˜ì—ˆìŠµë‹ˆë‹¤
+$ ELOOP
+62 심볼릭 ì—°ê²°ì´ ë„ˆë¬´ ë§Žì´ ê±°ì³ì„œ ì—°ê²°ë˜ì—ˆìŠµë‹ˆë‹¤
+$ ENAMETOOLONG
+63 íŒŒì¼ ì´ë¦„ì´ ë„ˆë¬´ ê¹ë‹ˆë‹¤
+$ EHOSTDOWN
+64 호스트가 죽었습니다
+$ EHOSTUNREACH
+65 호스트로 갈 경로가 없습니다
+$ ENOTEMPTY
+66 디렉터리가 비어있지 않습니다
+$ EPROCLIM
+67 프로세스가 너무 많습니다
+$ EUSERS
+68 사용ìžê°€ 너무 많습니다
+$ EDQUOT
+69 ë””ìŠ¤í¬ í• ë‹¹ëŸ‰ì„ ì´ˆê³¼í–ˆìŠµë‹ˆë‹¤
+$ ESTALE
+70 ëŠì–´ì§„ NFS 연결입니다
+$ EREMOTE
+71 너무 ë§Žì€ ê²½ë¡œë¡œ ì›ê²©ì— 접근하였습니다
+$ EBADRPC
+72 RPC 구조체가 잘못ë˜ì—ˆìŠµë‹ˆë‹¤
+$ ERPCMISMATCH
+73 RPC ë²„ì „ì´ ë§žì§€ 않습니다
+$ EPROGUNAVAIL
+74 RPC í”„ë¡œê·¸ëž¨ì´ ì—†ìŠµë‹ˆë‹¤
+$ EPROGMISMATCH
+75 프로그램 ë²„ì „ì´ ë§žì§€ 않습니다
+$ EPROCUNAVAIL
+76 í”„ë¡œê·¸ëž¨ì— ì›ê²© 프로시저가 없습니다
+$ ENOLCK
+77 ìž ê¸ˆì´ ë¶ˆê°€ëŠ¥í•©ë‹ˆë‹¤
+$ ENOSYS
+78 구현ë˜ì§€ ì•Šì€ ê¸°ëŠ¥ìž…ë‹ˆë‹¤
+$ EFTYPE
+79 ìž˜ëª»ëœ íŒŒì¼ ì¢…ë¥˜ì´ê±°ë‚˜ 형ì‹ì´ 잘못ë습니다
+$ EAUTH
+80 ì¸ì¦ì´ 실패했습니다
+$ ENEEDAUTH
+81 ì¸ì¦ 서버가 지정ë˜ì§€ 않았습니다
+$ EIDRM
+82 ì‹ë³„ìžê°€ 제거ë˜ì—ˆìŠµë‹ˆë‹¤
+$ ENOMSG
+83 ìš”ì²­ëœ í˜•ì‹ì˜ 메시지는 없습니다
+$ EOVERFLOW
+84 ë°ì´í„° 형ì‹ì— ì €ìž¥í•˜ê¸°ì— ë„ˆë¬´ í° ê°’ìž…ë‹ˆë‹¤
+$ ECANCELED
+85 ìž‘ì—…ì´ ì·¨ì†Œë˜ì—ˆìŠµë‹ˆë‹¤
+$ EILSEQ
+86 ë°”ì´íŠ¸ ë°°ì—´ì´ ìž˜ëª»ë˜ì—ˆìŠµë‹ˆë‹¤
+$ ENOATTR
+87 ì†ì„±ì„ ì°¾ì„ ìˆ˜ 없습니다
+$ EDOOFUS
+88 í”„ë¡œê·¸ëž¨ìƒ ì˜¤ë¥˜ìž…ë‹ˆë‹¤
+$ EBADMSG
+89 ìž˜ëª»ëœ ë©”ì‹œì§€ìž…ë‹ˆë‹¤
+$ EMULTIHOP
+90 ë©€í‹°í™‰ì´ ì‹œë„ë˜ì—ˆìŠµë‹ˆë‹¤
+$ ENOLINK
+91 ì—°ê²°ì´ ëŠê²¼ìŠµë‹ˆë‹¤
+$ EPROTO
+92 í”„ë¡œí† ì½œì´ ìž˜ëª»ë˜ì—ˆìŠµë‹ˆë‹¤
+$ ENOTCAPABLE
+93 ì ‘ê·¼ ëŠ¥ë ¥ì´ ì¶©ë¶„ì¹˜ 않습니다
+$
+$ strsignal() support catalog
+$
+$set 2
+$ SIGHUP
+1 ëŠê¹€
+$ SIGINT
+2 중단
+$ SIGQUIT
+3 종료
+$ SIGILL
+4 ìž˜ëª»ëœ ëª…ë ¹
+$ SIGTRAP
+5 Trace/BPT 트랩
+$ SIGABRT
+6 Abort 트랩
+$ SIGEMT
+7 EMT 트랩
+$ SIGFPE
+8 부ë™ì†Œìˆ˜ì  ì—°ì‚° 예외
+$ SIGKILL
+9 강제종료
+$ SIGBUS
+10 버스 오류
+$ SIGSEGV
+11 세그먼테ì´ì…˜ 오류
+$ SIGSYS
+12 ìž˜ëª»ëœ ì‹œìŠ¤í…œ 호출
+$ SIGPIPE
+13 파ì´í”„ê°€ ëŠê¹€
+$ SIGALRM
+14 시간 경보
+$ SIGTERM
+15 종료ë¨
+$ SIGURG
+16 긴급 I/O 조건
+$ SIGSTOP
+17 ì¼ì‹œì •ì§€ (시그ë„)
+$ SIGTSTP
+18 ì¼ì‹œì •ì§€
+$ SIGCONT
+19 계ì†
+$ SIGCHLD
+20 ìžì‹ 프로세스 종료
+$ SIGTTIN
+21 정지 (í„°ë¯¸ë„ ìž…ë ¥)
+$ SIGTTOU
+22 정지 (í„°ë¯¸ë„ ì¶œë ¥)
+$ SIGIO
+23 I/O 가능
+$ SIGXCPU
+24 CPU 사용 시간 초과
+$ SIGXFSZ
+25 íŒŒì¼ ìš©ëŸ‰ 제한 초과
+$ SIGVTALRM
+26 ê°€ìƒ íƒ€ì´ë¨¸ 만료
+$ SIGPROF
+27 프로파ì¼ë§ 타ì´ë¨¸ 만료
+$ SIGWINCH
+28 ì°½ í¬ê¸° 변경
+$ SIGINFO
+29 정보 요청
+$ SIGUSR1
+30 ì‚¬ìš©ìž ì •ì˜ ì‹œê·¸ë„ 1
+$ SIGUSR2
+31 ì‚¬ìš©ìž ì •ì˜ ì‹œê·¸ë„ 2
+$
+$ gai_strerror() support catalog
+$
+$set 3
+$ 1 (obsolete)
+1 호스트 ì´ë¦„ì´ ì§€ì›í•˜ì§€ 않는 주소군입니다
+$ EAI_AGAIN
+2 주소 ë³€í™˜ì— ì¼ì‹œì ìœ¼ë¡œ 실패했습니다
+$ EAI_BADFLAGS
+3 ìž˜ëª»ëœ ai_flags입니다
+$ EAI_FAIL
+4 주소 ë³€í™˜ì— ì™„ì „ížˆ 실패했습니다
+$ EAI_FAMILY
+5 지ì›ë˜ì§€ 않는 ai_family입니다
+$ EAI_MEMORY
+6 메모리 í• ë‹¹ì— ì‹¤íŒ¨í–ˆìŠµë‹ˆë‹¤
+$ 7 (obsolete)
+7 호스트 ì´ë¦„ê³¼ ì¼ì¹˜í•˜ëŠ” 주소가 없습니다
+$ EAI_NONAME
+8 호스트 ì´ë¦„ ë˜ëŠ” 서비스 ì´ë¦„ì´ ì§€ì •ë˜ì§€ 않았거나 ì•Œ 수 없습니다
+$ EAI_SERVICE
+9 서비스 ì´ë¦„ì€ ai_socktypeì—ì„œ 지ì›ë˜ì§€ 않습니다
+$ EAI_SOCKTYPE
+10 지ì›ë˜ì§€ 않는 ai_socktype입니다
+$ EAI_SYSTEM
+11 시스템 오류가 errnoì— ë°˜í™˜ë˜ì—ˆìŠµë‹ˆë‹¤
+$ EAI_BADHINTS
+12 ìž˜ëª»ëœ hints입니다
+$ EAI_PROTOCOL
+13 ì•Œ 수 없는 í”„ë¡œí† ì½œì´ ë³€í™˜ë˜ì—ˆìŠµë‹ˆë‹¤
+$ EAI_OVERFLOW
+14 ì¸ìž ë²„í¼ ê³µê°„ì´ ëª¨ìžëžë‹ˆë‹¤
+$ 0
+32766 성공
+$ NL_MSGMAX
+32767 알 수 없는 오류
diff --git a/lib/libc/nls/ko_KR.eucKR.msg b/lib/libc/nls/ko_KR.eucKR.msg
new file mode 100644
index 000000000000..bb1fa300b164
--- /dev/null
+++ b/lib/libc/nls/ko_KR.eucKR.msg
@@ -0,0 +1,295 @@
+$ $FreeBSD$
+$
+$ Message catalog for ko_KR.eucKR locale
+$
+$ strerror() support catalog
+$
+$set 1
+$ EPERM
+1 ¸í·ÉÀÌ Çã¿ëµÇÁö ¾Ê½À´Ï´Ù
+$ ENOENT
+2 ÆÄÀÏ ¶Ç´Â µð·ºÅ͸®°¡ ¾ø½À´Ï´Ù
+$ ESRCH
+3 Á¸ÀçÇÏÁö ¾Ê´Â ÇÁ·Î¼¼½ºÀÔ´Ï´Ù
+$ EINTR
+4 ½Ã½ºÅÛ È£ÃâÀÌ ÁߴܵǾú½À´Ï´Ù
+$ EIO
+5 ÀÔÃâ·Â ¿¡·¯ÀÔ´Ï´Ù
+$ ENXIO
+6 ÀåÄ¡°¡ ¼³Á¤µÇÁö ¾Ê¾Ò½À´Ï´Ù
+$ E2BIG
+7 ÀÎÀÚ°¡ ³Ê¹« ±é´Ï´Ù
+$ ENOEXEC
+8 ½ÇÇà ÆÄÀÏ Çü½ÄÀÌ À߸øµÇ¾ú½À´Ï´Ù
+$ EBADF
+9 À߸øµÈ ÆÄÀÏ µð½ºÅ©¸³ÅÍÀÔ´Ï´Ù
+$ ECHILD
+10 ÀÚ½Ä ÇÁ·Î¼¼½º°¡ ¾ø½À´Ï´Ù
+$ EDEADLK
+11 ÀÚ¿ø µ¥µå¶ôÀ» Áß´ÜÇÏ¿´½À´Ï´Ù
+$ ENOMEM
+12 ¸Þ¸ð¸®¸¦ ÇÒ´çÇÒ ¼ö ¾ø½À´Ï´Ù
+$ EACCES
+13 ±ÇÇÑÀÌ ¾ø½À´Ï´Ù
+$ EFAULT
+14 À߸øµÈ ÁÖ¼Ò°¡ ÁöÁ¤µÇ¾ú½À´Ï´Ù
+$ ENOTBLK
+15 ºí·° ÀåÄ¡¿©¾ß ÇÕ´Ï´Ù
+$ EBUSY
+16 ÀåÄ¡°¡ »ç¿ë ÁßÀÔ´Ï´Ù
+$ EEXIST
+17 ÆÄÀÏÀÌ ÀÌ¹Ì Á¸ÀçÇÕ´Ï´Ù
+$ EXDEV
+18 ´Ù¸¥ ÀåÄ¡ °£ÀÇ ¿¬°áÀÔ´Ï´Ù
+$ ENODEV
+19 ±× ÀåÄ¡°¡ Áö¿øÇÏÁö ¾Ê´Â ¸í·ÉÀÔ´Ï´Ù
+$ ENOTDIR
+20 µð·ºÅ͸®°¡ ¾Æ´Õ´Ï´Ù
+$ EISDIR
+21 µð·ºÅ͸®ÀÔ´Ï´Ù
+$ EINVAL
+22 ÀÎÀÚ°¡ À߸øµÇ¾ú½À´Ï´Ù
+$ ENFILE
+23 ½Ã½ºÅÛ¿¡ ÆÄÀÏÀÌ ³Ê¹« ¸¹ÀÌ ¿­·ÁÀÖ½À´Ï´Ù
+$ EMFILE
+24 ÆÄÀÏÀÌ ³Ê¹« ¸¹ÀÌ ¿­·ÁÀÖ½À´Ï´Ù
+$ ENOTTY
+25 ÀåÄ¡°¡ Áö¿øÇÏÁö ¾Ê´Â ioctlÀÔ´Ï´Ù
+$ ETXTBSY
+26 Text ÆÄÀÏÀÌ »ç¿ë ÁßÀÔ´Ï´Ù
+$ EFBIG
+27 ÆÄÀÏÀÌ ³Ê¹« Å®´Ï´Ù
+$ ENOSPC
+28 ÀåÄ¡¿¡ ¿©À¯ °ø°£ÀÌ ³²¾ÆÀÖÁö ¾Ê½À´Ï´Ù
+$ ESPIPE
+29 À߸øµÈ Ž»öÀÔ´Ï´Ù
+$ EROFS
+30 Àбâ Àü¿ë ÆÄÀÏ ½Ã½ºÅÛÀÔ´Ï´Ù
+$ EMLINK
+31 ¿¬°áÀÌ ³Ê¹« ¸¹½À´Ï´Ù
+$ EPIPE
+32 ÆÄÀÌÇÁ°¡ ²÷¾îÁ³½À´Ï´Ù
+$ EDOM
+33 ¼öÄ¡ ÀÎÀÚ°¡ ¿µ¿ªÀ» ¹þ¾î³µ½À´Ï´Ù
+$ ERANGE
+34 °á°ú°¡ ³Ê¹« Å®´Ï´Ù
+$ EAGAIN, EWOULDBLOCK
+35 ÀÚ¿øÀ» Àá½Ã »ç¿ëÇÒ ¼ö ¾ø½À´Ï´Ù
+$ EINPROGRESS
+36 ÀÛ¾÷ÀÌ ÁøÇà ÁßÀÔ´Ï´Ù
+$ EALREADY
+37 ÀÛ¾÷ÀÌ ÀÌ¹Ì ÁøÇà ÁßÀÔ´Ï´Ù
+$ ENOTSOCK
+38 ¼ÒÄÏÀÌ ¾Æ´Ñ °´Ã¼¿¡ ´ëÇÑ ¼ÒÄÏ ÀÛ¾÷ÀÔ´Ï´Ù
+$ EDESTADDRREQ
+39 ¸ñÀûÁö ÁÖ¼Ò°¡ ÇÊ¿äÇÕ´Ï´Ù
+$ EMSGSIZE
+40 ¸Þ½ÃÁö°¡ ³Ê¹« ±é´Ï´Ù
+$ EPROTOTYPE
+41 ¼ÒÄÏ¿¡ »ç¿ëÇÒ ¼ö ¾ø´Â ÇÁ·ÎÅäÄÝ À¯ÇüÀÔ´Ï´Ù
+$ ENOPROTOOPT
+42 ÇÁ·ÎÅäÄÝÀ» »ç¿ëÇÒ ¼ö ¾ø½À´Ï´Ù
+$ EPROTONOSUPPORT
+43 Áö¿øÇÏÁö ¾Ê´Â ÇÁ·ÎÅäÄÝÀÔ´Ï´Ù
+$ ESOCKTNOSUPPORT
+44 Áö¿øÇÏÁö ¾Ê´Â Á¾·ùÀÇ ¼ÒÄÏÀÔ´Ï´Ù
+$ EOPNOTSUPP
+45 Áö¿øµÇÁö ¾Ê´Â ¸í·ÉÀÔ´Ï´Ù
+$ EPFNOSUPPORT
+46 Áö¿øµÇÁö ¾Ê´Â ÇÁ·ÎÅäÄݱºÀÔ´Ï´Ù
+$ EAFNOSUPPORT
+47 ÇÁ·ÎÅäÄݱº¿¡¼­ Áö¿øµÇÁö ¾Ê´Â ÁÖ¼Ò±ºÀÔ´Ï´Ù
+$ EADDRINUSE
+48 ÀÌ¹Ì »ç¿ë ÁßÀÎ ÁÖ¼ÒÀÔ´Ï´Ù
+$ EADDRNOTAVAIL
+49 ¿äûÇÑ ÁÖ¼Ò¸¦ ÇÒ´çÇÒ ¼ö ¾ø½À´Ï´Ù
+$ ENETDOWN
+50 ³×Æ®¿öÅ©°¡ ´ÜÀýµÇ¾ú½À´Ï´Ù
+$ ENETUNREACH
+51 ³×Æ®¿öÅ©¿¡ µµ´ÞÇÒ ¼ö ¾ø½À´Ï´Ù
+$ ENETRESET
+52 ³×Æ®¿öÅ©°¡ Àç¼³Á¤µÇ¾î Á¢¼ÓÀÌ ²÷¾îÁ³½À´Ï´Ù
+$ ECONNABORTED
+53 ¼ÒÇÁÆ®¿þ¾îÀûÀÎ ÀÌÀ¯·Î ¿¬°áÀÌ ²÷¾îÁ³½À´Ï´Ù
+$ ECONNRESET
+54 »ó´ë¹æÀÌ ¿¬°áÀ» ²÷¾ú½À´Ï´Ù
+$ ENOBUFS
+55 ¹öÆÛ °ø°£ÀÌ ¸ðÀÚ¶ø´Ï´Ù
+$ EISCONN
+56 ¼ÒÄÏÀÌ ÀÌ¹Ì ¿¬°áµÇÀÖ½À´Ï´Ù
+$ ENOTCONN
+57 ¼ÒÄÏÀÌ ¿¬°áµÇ¾î ÀÖÁö ¾Ê½À´Ï´Ù
+$ ESHUTDOWN
+58 ¼ÒÄÏÀÌ ÀÌ¹Ì ÁߴܵǾî, ´õ ÀÌ»ó Àü¼ÛÇÒ ¼ö ¾ø½À´Ï´Ù
+$ ETOOMANYREFS
+59 ÂüÁ¶¼ö°¡ ³Ê¹« ¸¹¾Æ ³ª´­ ¼ö ¾ø½À´Ï´Ù
+$ ETIMEDOUT
+60 ½Ã°£ÀÌ ³Ê¹« ¸¹ÀÌ Áö³ª ÀÛ¾÷ÀÌ ÁߴܵǾú½À´Ï´Ù
+$ ECONNREFUSED
+61 Á¢¼ÓÀÌ °ÅºÎµÇ¾ú½À´Ï´Ù
+$ ELOOP
+62 ½Éº¼¸¯ ¿¬°áÀÌ ³Ê¹« ¸¹ÀÌ °ÅÃļ­ ¿¬°áµÇ¾ú½À´Ï´Ù
+$ ENAMETOOLONG
+63 ÆÄÀÏ À̸§ÀÌ ³Ê¹« ±é´Ï´Ù
+$ EHOSTDOWN
+64 È£½ºÆ®°¡ Á×¾ú½À´Ï´Ù
+$ EHOSTUNREACH
+65 È£½ºÆ®·Î °¥ °æ·Î°¡ ¾ø½À´Ï´Ù
+$ ENOTEMPTY
+66 µð·ºÅ͸®°¡ ºñ¾îÀÖÁö ¾Ê½À´Ï´Ù
+$ EPROCLIM
+67 ÇÁ·Î¼¼½º°¡ ³Ê¹« ¸¹½À´Ï´Ù
+$ EUSERS
+68 »ç¿ëÀÚ°¡ ³Ê¹« ¸¹½À´Ï´Ù
+$ EDQUOT
+69 µð½ºÅ© ÇÒ´ç·®À» ÃÊ°úÇß½À´Ï´Ù
+$ ESTALE
+70 ²÷¾îÁø NFS ¿¬°áÀÔ´Ï´Ù
+$ EREMOTE
+71 ³Ê¹« ¸¹Àº °æ·Î·Î ¿ø°Ý¿¡ Á¢±ÙÇÏ¿´½À´Ï´Ù
+$ EBADRPC
+72 RPC ±¸Á¶Ã¼°¡ À߸øµÇ¾ú½À´Ï´Ù
+$ ERPCMISMATCH
+73 RPC ¹öÀüÀÌ ¸ÂÁö ¾Ê½À´Ï´Ù
+$ EPROGUNAVAIL
+74 RPC ÇÁ·Î±×·¥ÀÌ ¾ø½À´Ï´Ù
+$ EPROGMISMATCH
+75 ÇÁ·Î±×·¥ ¹öÀüÀÌ ¸ÂÁö ¾Ê½À´Ï´Ù
+$ EPROCUNAVAIL
+76 ÇÁ·Î±×·¥¿¡ ¿ø°Ý ÇÁ·Î½ÃÀú°¡ ¾ø½À´Ï´Ù
+$ ENOLCK
+77 Àá±ÝÀÌ ºÒ°¡´ÉÇÕ´Ï´Ù
+$ ENOSYS
+78 ±¸ÇöµÇÁö ¾ÊÀº ±â´ÉÀÔ´Ï´Ù
+$ EFTYPE
+79 À߸øµÈ ÆÄÀÏ Á¾·ùÀ̰ųª Çü½ÄÀÌ À߸øµÆ½À´Ï´Ù
+$ EAUTH
+80 ÀÎÁõÀÌ ½ÇÆÐÇß½À´Ï´Ù
+$ ENEEDAUTH
+81 ÀÎÁõ ¼­¹ö°¡ ÁöÁ¤µÇÁö ¾Ê¾Ò½À´Ï´Ù
+$ EIDRM
+82 ½Äº°ÀÚ°¡ Á¦°ÅµÇ¾ú½À´Ï´Ù
+$ ENOMSG
+83 ¿äûµÈ Çü½ÄÀÇ ¸Þ½ÃÁö´Â ¾ø½À´Ï´Ù
+$ EOVERFLOW
+84 µ¥ÀÌÅÍ Çü½Ä¿¡ ÀúÀåÇϱ⿡ ³Ê¹« Å« °ªÀÔ´Ï´Ù
+$ ECANCELED
+85 ÀÛ¾÷ÀÌ Ãë¼ÒµÇ¾ú½À´Ï´Ù
+$ EILSEQ
+86 ¹ÙÀÌÆ® ¹è¿­ÀÌ À߸øµÇ¾ú½À´Ï´Ù
+$ ENOATTR
+87 ¼Ó¼ºÀ» ãÀ» ¼ö ¾ø½À´Ï´Ù
+$ EDOOFUS
+88 ÇÁ·Î±×·¥»ó ¿À·ùÀÔ´Ï´Ù
+$ EBADMSG
+89 À߸øµÈ ¸Þ½ÃÁöÀÔ´Ï´Ù
+$ EMULTIHOP
+90 ¸ÖƼȩÀÌ ½ÃµµµÇ¾ú½À´Ï´Ù
+$ ENOLINK
+91 ¿¬°áÀÌ ²÷°å½À´Ï´Ù
+$ EPROTO
+92 ÇÁ·ÎÅäÄÝÀÌ À߸øµÇ¾ú½À´Ï´Ù
+$ ENOTCAPABLE
+93 Á¢±Ù ´É·ÂÀÌ ÃæºÐÄ¡ ¾Ê½À´Ï´Ù
+$
+$ strsignal() support catalog
+$
+$set 2
+$ SIGHUP
+1 ²÷±è
+$ SIGINT
+2 Áß´Ü
+$ SIGQUIT
+3 Á¾·á
+$ SIGILL
+4 À߸øµÈ ¸í·É
+$ SIGTRAP
+5 Trace/BPT Æ®·¦
+$ SIGABRT
+6 Abort Æ®·¦
+$ SIGEMT
+7 EMT Æ®·¦
+$ SIGFPE
+8 ºÎµ¿¼Ò¼öÁ¡ ¿¬»ê ¿¹¿Ü
+$ SIGKILL
+9 °­Á¦Á¾·á
+$ SIGBUS
+10 ¹ö½º ¿À·ù
+$ SIGSEGV
+11 ¼¼±×¸ÕÅ×ÀÌ¼Ç ¿À·ù
+$ SIGSYS
+12 À߸øµÈ ½Ã½ºÅÛ È£Ãâ
+$ SIGPIPE
+13 ÆÄÀÌÇÁ°¡ ²÷±è
+$ SIGALRM
+14 ½Ã°£ °æº¸
+$ SIGTERM
+15 Á¾·áµÊ
+$ SIGURG
+16 ±ä±Þ I/O Á¶°Ç
+$ SIGSTOP
+17 ÀϽÃÁ¤Áö (½Ã±×³Î)
+$ SIGTSTP
+18 ÀϽÃÁ¤Áö
+$ SIGCONT
+19 °è¼Ó
+$ SIGCHLD
+20 ÀÚ½Ä ÇÁ·Î¼¼½º Á¾·á
+$ SIGTTIN
+21 Á¤Áö (Å͹̳ΠÀÔ·Â)
+$ SIGTTOU
+22 Á¤Áö (Å͹̳ΠÃâ·Â)
+$ SIGIO
+23 I/O °¡´É
+$ SIGXCPU
+24 CPU »ç¿ë ½Ã°£ ÃÊ°ú
+$ SIGXFSZ
+25 ÆÄÀÏ ¿ë·® Á¦ÇÑ ÃÊ°ú
+$ SIGVTALRM
+26 °¡»ó ŸÀÌ¸Ó ¸¸·á
+$ SIGPROF
+27 ÇÁ·ÎÆÄÀϸµ ŸÀÌ¸Ó ¸¸·á
+$ SIGWINCH
+28 â Å©±â º¯°æ
+$ SIGINFO
+29 Á¤º¸ ¿äû
+$ SIGUSR1
+30 »ç¿ëÀÚ Á¤ÀÇ ½Ã±×³Î 1
+$ SIGUSR2
+31 »ç¿ëÀÚ Á¤ÀÇ ½Ã±×³Î 2
+$
+$ gai_strerror() support catalog
+$
+$set 3
+$ 1 (obsolete)
+1 È£½ºÆ® À̸§ÀÌ Áö¿øÇÏÁö ¾Ê´Â ÁÖ¼Ò±ºÀÔ´Ï´Ù
+$ EAI_AGAIN
+2 ÁÖ¼Ò º¯È¯¿¡ ÀϽÃÀûÀ¸·Î ½ÇÆÐÇß½À´Ï´Ù
+$ EAI_BADFLAGS
+3 À߸øµÈ ai_flagsÀÔ´Ï´Ù
+$ EAI_FAIL
+4 ÁÖ¼Ò º¯È¯¿¡ ¿ÏÀüÈ÷ ½ÇÆÐÇß½À´Ï´Ù
+$ EAI_FAMILY
+5 Áö¿øµÇÁö ¾Ê´Â ai_familyÀÔ´Ï´Ù
+$ EAI_MEMORY
+6 ¸Þ¸ð¸® ÇÒ´ç¿¡ ½ÇÆÐÇß½À´Ï´Ù
+$ 7 (obsolete)
+7 È£½ºÆ® À̸§°ú ÀÏÄ¡ÇÏ´Â ÁÖ¼Ò°¡ ¾ø½À´Ï´Ù
+$ EAI_NONAME
+8 È£½ºÆ® À̸§ ¶Ç´Â ¼­ºñ½º À̸§ÀÌ ÁöÁ¤µÇÁö ¾Ê¾Ò°Å³ª ¾Ë ¼ö ¾ø½À´Ï´Ù
+$ EAI_SERVICE
+9 ¼­ºñ½º À̸§Àº ai_socktype¿¡¼­ Áö¿øµÇÁö ¾Ê½À´Ï´Ù
+$ EAI_SOCKTYPE
+10 Áö¿øµÇÁö ¾Ê´Â ai_socktypeÀÔ´Ï´Ù
+$ EAI_SYSTEM
+11 ½Ã½ºÅÛ ¿À·ù°¡ errno¿¡ ¹ÝȯµÇ¾ú½À´Ï´Ù
+$ EAI_BADHINTS
+12 À߸øµÈ hintsÀÔ´Ï´Ù
+$ EAI_PROTOCOL
+13 ¾Ë ¼ö ¾ø´Â ÇÁ·ÎÅäÄÝÀÌ º¯È¯µÇ¾ú½À´Ï´Ù
+$ EAI_OVERFLOW
+14 ÀÎÀÚ ¹öÆÛ °ø°£ÀÌ ¸ðÀÚ¶ø´Ï´Ù
+$ 0
+32766 ¼º°ø
+$ NL_MSGMAX
+32767 ¾Ë ¼ö ¾ø´Â ¿À·ù
diff --git a/lib/libc/nls/mn_MN.UTF-8.msg b/lib/libc/nls/mn_MN.UTF-8.msg
new file mode 100644
index 000000000000..29ab4c15f50d
--- /dev/null
+++ b/lib/libc/nls/mn_MN.UTF-8.msg
@@ -0,0 +1,249 @@
+$ $FreeBSD$
+$
+$ Message catalog for mn_MN.UTF-8 locale
+$
+$ strerror() support catalog
+$
+$set 1
+$ EPERM
+1 ҮйлдÑл зөвшөөрөгдөхгүй
+$ ENOENT
+2 Тийм файл ÑÑвÑл Ñан алга
+$ ESRCH
+3 Тийм процеÑÑ Ð±Ð°Ð¹Ñ…Ð³Ò¯Ð¹
+$ EINTR
+4 СиÑтемийн таÑалдÑан дуудлага
+$ EIO
+5 Оролт/гаралтын алдаа
+$ ENXIO
+6 Төхөөрөмж тохируулагдаагүй
+$ E2BIG
+7 Дагавар өгөгдлийн жагÑаалт Ñ…ÑÑ‚Ñрхий урт
+$ ENOEXEC
+8 Exec Ñ…ÑлбÑршилтийн алдаа
+$ EBADF
+9 Файлын буруу тодорхойлогч
+$ ECHILD
+10 ХүүхÑд процеÑÑ Ð°Ð»Ð³Ð°
+$ EDEADLK
+11 Эх Ò¯Ò¯ÑвÑрийн Ð³Ð°Ñ†Ð°Ð°Ð½Ð°Ð°Ñ Ð·Ð°Ð¹Ð»ÑхийÑÑн
+$ ENOMEM
+12 Санах ойд зай байрлуулж чадахгүй байна
+$ EACCES
+13 Ð—Ó©Ð²ÑˆÓ©Ó©Ñ€Ó©Ñ…Ó©Ó©Ñ Ñ‚Ð°Ñ‚Ð³Ð°Ð»Ð·Ñан
+$ EFAULT
+14 Буруу хаÑг
+$ ENOTBLK
+15 Блок төхөөрөмж шаардагдÑан
+$ EBUSY
+16 Төхөөрөмж завгүй
+$ EEXIST
+17 Файл байна
+$ EXDEV
+18 Төхөөрөмж хоорондын холбооÑ
+$ ENODEV
+19 Үйлдлийг төхөөрөмж дÑмжÑÑгүй
+$ ENOTDIR
+20 Сан биш
+$ EISDIR
+21 Сан мөн
+$ EINVAL
+22 Дагавар өгөгдөл буруу
+$ ENFILE
+23 СиÑтемд Ñ…ÑÑ‚Ñрхий олон нÑÑлттÑй файл байна
+$ EMFILE
+24 Ð¥ÑÑ‚Ñрхий олон нÑÑлттÑй файл байна
+$ ENOTTY
+25 ТөхөөрөмжтÑй тохирохгүй ioctl үйлдÑл
+$ ETXTBSY
+26 ТекÑÑ‚ файл завгүй
+$ EFBIG
+27 Файл Ñ…ÑÑ‚Ñрхий том
+$ ENOSPC
+28 Төхөөрөмж дÑÑÑ€ зай үлдÑÑнгүй
+$ ESPIPE
+29 Хайлт буруу
+$ EROFS
+30 Зөвхөн-уншигдах файлын ÑиÑтем
+$ EMLINK
+31 Ð¥ÑÑ‚Ñрхий олон Ñ…Ð¾Ð»Ð±Ð¾Ð¾Ñ Ð±Ð°Ð¹Ð½Ð°
+$ EPIPE
+32 ЭвдÑрхий хоолой
+$ EDOM
+33 Тоон дагавар өгөгдөл Ñ‚Ð°Ð»Ð±Ð°Ñ€Ð°Ð°Ñ Ð³Ð°Ð´Ð½Ð° байна
+$ ERANGE
+34 Үр дүн Ñ…ÑÑ‚Ñрхий том
+$ EAGAIN, EWOULDBLOCK
+35 Эх Ò¯Ò¯ÑвÑÑ€ түр зуур боломжгүй байна
+$ EINPROGRESS
+36 ҮйлдÑл одоо хийгдÑж байна
+$ EALREADY
+37 ҮйлдÑл аль Ñ…Ñдийн хийгдÑж байна
+$ ENOTSOCK
+38 Сокет Ð±ÑƒÑ Ð·Ò¯Ð¹Ð» дÑÑÑ€ Ñокет үйлдÑл
+$ EDESTADDRREQ
+39 Очих хаÑг шаардагдÑан
+$ EMSGSIZE
+40 Ð—ÑƒÑ€Ð²Ð°Ñ Ð¼ÑдÑÑ Ñ…ÑÑ‚Ñрхий урт
+$ EPROTOTYPE
+41 Сокетийн хувьд протокол буруу төрлийнх байна
+$ ENOPROTOOPT
+42 Протокол байхгүй
+$ EPROTONOSUPPORT
+43 Протокол дÑмжигдÑÑгүй
+$ ESOCKTNOSUPPORT
+44 Сокетийн төрөл дÑмжигдÑÑгүй
+$ EOPNOTSUPP
+45 ҮйлдÑл дÑмжигдÑÑгүй
+$ EPFNOSUPPORT
+46 Протоколын гÑÑ€ бүл дÑмжигдÑÑгүй
+$ EAFNOSUPPORT
+47 ХаÑгийн гÑÑ€ бүлийг протоколын гÑÑ€ бүл дÑмжÑÑгүй
+$ EADDRINUSE
+48 ХаÑг ашиглагдаж байна
+$ EADDRNOTAVAIL
+49 Ð¥Ò¯ÑÑÑн хаÑгийг өгч чадахгүй
+$ ENETDOWN
+50 СүлжÑÑ ÑƒÐ½Ð°Ñан байна
+$ ENETUNREACH
+51 СүлжÑÑнд хүрÑÑ… боломжгүй
+$ ENETRESET
+52 Салгалт хийгдÑÑ…Ñд ÑүлжÑÑ Ñ…Ð¾Ð»Ð±Ð¾Ð»Ñ‚Ñ‹Ð³ унагалаа
+$ ECONNABORTED
+53 Програм Ñ…Ð°Ð½Ð³Ð°Ð¼Ð¶Ð°Ð°Ñ Ð±Ð¾Ð»Ð¶ холболт зогÑлоо
+$ ECONNRESET
+54 Холболтыг харилцагч Ñалгалаа
+$ ENOBUFS
+55 Буфферийн зай байхгүй
+$ EISCONN
+56 Сокет аль Ñ…Ñдийн холбогдÑон
+$ ENOTCONN
+57 Сокет холбогдоогүй
+$ ESHUTDOWN
+58 Сокет унтарÑны дараа илгÑÑж чадахгүй
+$ ETOOMANYREFS
+59 Ð¥ÑÑ‚Ñрхий их хамаарлууд байна: залгаж чадахгүй
+$ ETIMEDOUT
+60 Үйлдлийн хугацаа дууÑÑан
+$ ECONNREFUSED
+61 Холболт Ñ‚Ð¾Ð³Ñ‚Ð¾Ð¾Ñ…Ð¾Ð¾Ñ Ñ‚Ð°Ñ‚Ð³Ð°Ð»Ð·Ð»Ð°Ð°
+$ ELOOP
+62 ТÑмдÑгт холбооÑуудын түвшин Ñ…ÑÑ‚Ñрхий олон байна
+$ ENAMETOOLONG
+63 Файлын нÑÑ€ Ñ…ÑÑ‚Ñрхий урт
+$ EHOSTDOWN
+64 Төв компьютер зогÑÑон байна
+$ EHOSTUNREACH
+65 Төв компьютер Ñ€Ò¯Ò¯ чиглүүлÑлт байхгүй
+$ ENOTEMPTY
+66 Сан хооÑон биш
+$ EPROCLIM
+67 Ð¥ÑÑ‚Ñрхий олон үйлдÑл байна
+$ EUSERS
+68 Ð¥ÑÑ‚Ñрхий олон Ñ…ÑÑ€ÑглÑгч байна
+$ EDQUOT
+69 ДиÑкийн Ñ…Ñзгаар Ñ…ÑмжÑÑ Ñ…ÑÑ‚ÑÑ€ÑÑн
+$ ESTALE
+70 ХуучирÑан NFS файлын жолоо
+$ EREMOTE
+71 Зам Ñ…ÑÑ‚Ñрхий алÑлагдÑан түвшинтÑй байна
+$ EBADRPC
+2 RPC бүтÑц буруу
+$ ERPCMISMATCH
+73 RPC-ийн хувилбар буруу
+$ EPROGUNAVAIL
+74 RPC програм байхгүй
+$ EPROGMISMATCH
+75 Програмын хувилбар буруу
+$ EPROCUNAVAIL
+76 Програмын хувьд процедур буруу
+$ ENOLCK
+77 ТүгжÑÑ Ð±Ð°Ð¹Ñ…Ð³Ò¯Ð¹
+$ ENOSYS
+78 Функц гүйцÑтгÑгдÑÑгүй
+$ EFTYPE
+79 Файлын төрөл ÑÑвÑл Ñ…ÑлбÑршилт тохироогүй
+$ EAUTH
+80 ÐÑвтрүүлÑÑ… алдаа
+$ ENEEDAUTH
+81 ÐÑвтррүүлÑгч Ñ…ÑÑ€ÑгтÑй
+$ EIDRM
+82 Танигч уÑтгагдÑан
+$ ENOMSG
+83 Ð¥Ò¯ÑÑÑн төрлийн Ð·ÑƒÑ€Ð²Ð°Ñ Ð¼ÑдÑÑ Ð±Ð°Ð¹Ñ…Ð³Ò¯Ð¹
+$ EOVERFLOW
+84 Утга нь өгөгдлийн төрөлд хадгалагдаж болохооргүй Ñ…ÑÑ‚Ñрхий том байна
+$ ECANCELED
+85 ҮйлдÑл зогÑоогдÑон
+$ EILSEQ
+86 Байтын дараалал буруу
+$ ENOATTR
+87 Ðтрибут олдÑонгүй
+$ EDOOFUS
+88 Програмчлалын алдаа
+$
+$ strsignal() support catalog
+$
+$set 2
+$ SIGHUP
+1 ЗогÑоох (Hangup)
+$ SIGINT
+2 ТаÑалдал
+$ SIGQUIT
+3 Гарах
+$ SIGILL
+4 Буруу заавар
+$ SIGTRAP
+5 Мөр/BPT занга
+$ SIGABRT
+6 ТаÑлан зогÑоох занга
+$ SIGEMT
+7 EMT занга
+$ SIGFPE
+8 Хөвөгч цÑгийн онцгой алдаа
+$ SIGKILL
+9 ХөнөөÑөн
+$ SIGBUS
+10 Шугамын алдаа
+$ SIGSEGV
+11 Сегментийн гÑмтÑл
+$ SIGSYS
+12 СиÑтемийн буруу дуудлага
+$ SIGPIPE
+13 ЭвдÑрхий хоолой
+$ SIGALRM
+14 СÑрүүлÑгт цаг
+$ SIGTERM
+15 ТөгÑÑөн
+$ SIGURG
+16 Яаралтай I/O нөхцөл
+$ SIGSTOP
+17 Түр зогÑÑон (дохио)
+$ SIGTSTP
+18 Түр зогÑÑон
+$ SIGCONT
+19 ҮргÑлжилÑÑн
+$ SIGCHLD
+20 ХүүхÑд процеÑÑ Ð³Ð°Ñ€Ñан
+$ SIGTTIN
+21 ЗогÑÑон (tty оролт)
+$ SIGTTOU
+22 ЗогÑÑон (tty гаралт)
+$ SIGIO
+23 I/O боломжтой
+$ SIGXCPU
+24 CPU-ийн хугацааны Ñ…Ñзгаар Ñ…ÑÑ‚ÑÑ€ÑÑн
+$ SIGXFSZ
+25 Файлын Ñ…ÑмжÑÑний Ñ…Ñзгаар Ñ…ÑÑ‚ÑÑ€ÑÑн
+$ SIGVTALRM
+26 Виртуал цаг Ñ…Ñмжигчийн хугацаа дууÑÑан
+$ SIGPROF
+27 Профил хийх цаг Ñ…Ñмжигчийн хугацаа дууÑÑан
+$ SIGWINCH
+28 Цонхны Ñ…ÑмжÑÑний өөрчлөлт
+$ SIGINFO
+29 ÐœÑдÑÑллийн Ñ…Ò¯ÑÑлт
+$ SIGUSR1
+30 Ð¥ÑÑ€ÑглÑгчийн тодорхойлÑон дохио 1
+$ SIGUSR2
+31 Ð¥ÑÑ€ÑглÑгчийн тодорхойлÑон дохио 2
diff --git a/lib/libc/nls/msgcat.c b/lib/libc/nls/msgcat.c
new file mode 100644
index 000000000000..f2d95842a0a0
--- /dev/null
+++ b/lib/libc/nls/msgcat.c
@@ -0,0 +1,457 @@
+/***********************************************************
+Copyright 1990, by Alfalfa Software Incorporated, Cambridge, Massachusetts.
+Copyright 2010, Gabor Kovesdan <gabor@FreeBSD.org>
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that Alfalfa's name not be used in
+advertising or publicity pertaining to distribution of the software
+without specific, written prior permission.
+
+ALPHALPHA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+ALPHALPHA BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+If you make any modifications, bugfixes or other changes to this software
+we'd appreciate it if you could send a copy to us so we can keep things
+up-to-date. Many thanks.
+ Kee Hinckley
+ Alfalfa Software, Inc.
+ 267 Allston St., #3
+ Cambridge, MA 02139 USA
+ nazgul@alfalfa.com
+
+******************************************************************/
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#define _NLS_PRIVATE
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/queue.h>
+
+#include <arpa/inet.h> /* for ntohl() */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <nl_types.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+#include "../locale/xlocale_private.h"
+
+#define _DEFAULT_NLS_PATH "/usr/share/nls/%L/%N.cat:/usr/share/nls/%N/%L:/usr/local/share/nls/%L/%N.cat:/usr/local/share/nls/%N/%L"
+
+#define RLOCK(fail) { int ret; \
+ if (__isthreaded && \
+ ((ret = _pthread_rwlock_rdlock(&rwlock)) != 0)) { \
+ errno = ret; \
+ return (fail); \
+ }}
+#define WLOCK(fail) { int ret; \
+ if (__isthreaded && \
+ ((ret = _pthread_rwlock_wrlock(&rwlock)) != 0)) { \
+ errno = ret; \
+ return (fail); \
+ }}
+#define UNLOCK { if (__isthreaded) \
+ _pthread_rwlock_unlock(&rwlock); }
+
+#define NLERR ((nl_catd) -1)
+#define NLRETERR(errc) { errno = errc; return (NLERR); }
+#define SAVEFAIL(n, l, e) { WLOCK(NLERR); \
+ np = malloc(sizeof(struct catentry)); \
+ if (np != NULL) { \
+ np->name = strdup(n); \
+ np->path = NULL; \
+ np->catd = NLERR; \
+ np->refcount = 0; \
+ np->lang = (l == NULL) ? NULL : \
+ strdup(l); \
+ np->caterrno = e; \
+ SLIST_INSERT_HEAD(&cache, np, list); \
+ } \
+ UNLOCK; \
+ errno = e; \
+ }
+
+static nl_catd load_msgcat(const char *, const char *, const char *);
+
+static pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
+
+struct catentry {
+ SLIST_ENTRY(catentry) list;
+ char *name;
+ char *path;
+ int caterrno;
+ nl_catd catd;
+ char *lang;
+ int refcount;
+};
+
+SLIST_HEAD(listhead, catentry) cache =
+ SLIST_HEAD_INITIALIZER(cache);
+
+nl_catd
+catopen(const char *name, int type)
+{
+ struct stat sbuf;
+ struct catentry *np;
+ char *base, *cptr, *cptr1, *nlspath, *pathP, *pcode;
+ char *plang, *pter;
+ int saverr, spcleft;
+ const char *lang, *tmpptr;
+ char path[PATH_MAX];
+
+ /* sanity checking */
+ if (name == NULL || *name == '\0')
+ NLRETERR(EINVAL);
+
+ if (strchr(name, '/') != NULL)
+ /* have a pathname */
+ lang = NULL;
+ else {
+ if (type == NL_CAT_LOCALE)
+ lang = querylocale(LC_MESSAGES_MASK, __get_locale());
+ else
+ lang = getenv("LANG");
+
+ if (lang == NULL || *lang == '\0' || strlen(lang) > ENCODING_LEN ||
+ (lang[0] == '.' &&
+ (lang[1] == '\0' || (lang[1] == '.' && lang[2] == '\0'))) ||
+ strchr(lang, '/') != NULL)
+ lang = "C";
+ }
+
+ /* Try to get it from the cache first */
+ RLOCK(NLERR);
+ SLIST_FOREACH(np, &cache, list) {
+ if ((strcmp(np->name, name) == 0) &&
+ ((lang != NULL && np->lang != NULL &&
+ strcmp(np->lang, lang) == 0) || (np->lang == lang))) {
+ if (np->caterrno != 0) {
+ /* Found cached failing entry */
+ UNLOCK;
+ NLRETERR(np->caterrno);
+ } else {
+ /* Found cached successful entry */
+ np->refcount++;
+ UNLOCK;
+ return (np->catd);
+ }
+ }
+ }
+ UNLOCK;
+
+ /* is it absolute path ? if yes, load immediately */
+ if (strchr(name, '/') != NULL)
+ return (load_msgcat(name, name, lang));
+
+ /* sanity checking */
+ if ((plang = cptr1 = strdup(lang)) == NULL)
+ return (NLERR);
+ if ((cptr = strchr(cptr1, '@')) != NULL)
+ *cptr = '\0';
+ pter = pcode = "";
+ if ((cptr = strchr(cptr1, '_')) != NULL) {
+ *cptr++ = '\0';
+ pter = cptr1 = cptr;
+ }
+ if ((cptr = strchr(cptr1, '.')) != NULL) {
+ *cptr++ = '\0';
+ pcode = cptr;
+ }
+
+ if ((nlspath = getenv("NLSPATH")) == NULL || issetugid())
+ nlspath = _DEFAULT_NLS_PATH;
+
+ if ((base = cptr = strdup(nlspath)) == NULL) {
+ saverr = errno;
+ free(plang);
+ errno = saverr;
+ return (NLERR);
+ }
+
+ while ((nlspath = strsep(&cptr, ":")) != NULL) {
+ pathP = path;
+ if (*nlspath) {
+ for (; *nlspath; ++nlspath) {
+ if (*nlspath == '%') {
+ switch (*(nlspath + 1)) {
+ case 'l':
+ tmpptr = plang;
+ break;
+ case 't':
+ tmpptr = pter;
+ break;
+ case 'c':
+ tmpptr = pcode;
+ break;
+ case 'L':
+ tmpptr = lang;
+ break;
+ case 'N':
+ tmpptr = (char *)name;
+ break;
+ case '%':
+ ++nlspath;
+ /* FALLTHROUGH */
+ default:
+ if (pathP - path >=
+ sizeof(path) - 1)
+ goto too_long;
+ *(pathP++) = *nlspath;
+ continue;
+ }
+ ++nlspath;
+ put_tmpptr:
+ spcleft = sizeof(path) -
+ (pathP - path) - 1;
+ if (strlcpy(pathP, tmpptr, spcleft) >=
+ spcleft) {
+ too_long:
+ free(plang);
+ free(base);
+ SAVEFAIL(name, lang, ENAMETOOLONG);
+ NLRETERR(ENAMETOOLONG);
+ }
+ pathP += strlen(tmpptr);
+ } else {
+ if (pathP - path >= sizeof(path) - 1)
+ goto too_long;
+ *(pathP++) = *nlspath;
+ }
+ }
+ *pathP = '\0';
+ if (stat(path, &sbuf) == 0) {
+ free(plang);
+ free(base);
+ return (load_msgcat(path, name, lang));
+ }
+ } else {
+ tmpptr = (char *)name;
+ --nlspath;
+ goto put_tmpptr;
+ }
+ }
+ free(plang);
+ free(base);
+ SAVEFAIL(name, lang, ENOENT);
+ NLRETERR(ENOENT);
+}
+
+char *
+catgets(nl_catd catd, int set_id, int msg_id, const char *s)
+{
+ struct _nls_cat_hdr *cat_hdr;
+ struct _nls_msg_hdr *msg_hdr;
+ struct _nls_set_hdr *set_hdr;
+ int i, l, r, u;
+
+ if (catd == NULL || catd == NLERR) {
+ errno = EBADF;
+ /* LINTED interface problem */
+ return ((char *)s);
+ }
+
+ cat_hdr = (struct _nls_cat_hdr *)catd->__data;
+ set_hdr = (struct _nls_set_hdr *)(void *)((char *)catd->__data +
+ sizeof(struct _nls_cat_hdr));
+
+ /* binary search, see knuth algorithm b */
+ l = 0;
+ u = ntohl((u_int32_t)cat_hdr->__nsets) - 1;
+ while (l <= u) {
+ i = (l + u) / 2;
+ r = set_id - ntohl((u_int32_t)set_hdr[i].__setno);
+
+ if (r == 0) {
+ msg_hdr = (struct _nls_msg_hdr *)
+ (void *)((char *)catd->__data +
+ sizeof(struct _nls_cat_hdr) +
+ ntohl((u_int32_t)cat_hdr->__msg_hdr_offset));
+
+ l = ntohl((u_int32_t)set_hdr[i].__index);
+ u = l + ntohl((u_int32_t)set_hdr[i].__nmsgs) - 1;
+ while (l <= u) {
+ i = (l + u) / 2;
+ r = msg_id -
+ ntohl((u_int32_t)msg_hdr[i].__msgno);
+ if (r == 0) {
+ return ((char *) catd->__data +
+ sizeof(struct _nls_cat_hdr) +
+ ntohl((u_int32_t)
+ cat_hdr->__msg_txt_offset) +
+ ntohl((u_int32_t)
+ msg_hdr[i].__offset));
+ } else if (r < 0) {
+ u = i - 1;
+ } else {
+ l = i + 1;
+ }
+ }
+
+ /* not found */
+ goto notfound;
+
+ } else if (r < 0) {
+ u = i - 1;
+ } else {
+ l = i + 1;
+ }
+ }
+
+notfound:
+ /* not found */
+ errno = ENOMSG;
+ /* LINTED interface problem */
+ return ((char *)s);
+}
+
+static void
+catfree(struct catentry *np)
+{
+
+ if (np->catd != NULL && np->catd != NLERR) {
+ munmap(np->catd->__data, (size_t)np->catd->__size);
+ free(np->catd);
+ }
+ SLIST_REMOVE(&cache, np, catentry, list);
+ free(np->name);
+ free(np->path);
+ free(np->lang);
+ free(np);
+}
+
+int
+catclose(nl_catd catd)
+{
+ struct catentry *np;
+
+ /* sanity checking */
+ if (catd == NULL || catd == NLERR) {
+ errno = EBADF;
+ return (-1);
+ }
+
+ /* Remove from cache if not referenced any more */
+ WLOCK(-1);
+ SLIST_FOREACH(np, &cache, list) {
+ if (catd == np->catd) {
+ np->refcount--;
+ if (np->refcount == 0)
+ catfree(np);
+ break;
+ }
+ }
+ UNLOCK;
+ return (0);
+}
+
+/*
+ * Internal support functions
+ */
+
+static nl_catd
+load_msgcat(const char *path, const char *name, const char *lang)
+{
+ struct stat st;
+ nl_catd catd;
+ struct catentry *np;
+ void *data;
+ int fd;
+
+ /* path/name will never be NULL here */
+
+ /*
+ * One more try in cache; if it was not found by name,
+ * it might still be found by absolute path.
+ */
+ RLOCK(NLERR);
+ SLIST_FOREACH(np, &cache, list) {
+ if ((np->path != NULL) && (strcmp(np->path, path) == 0)) {
+ np->refcount++;
+ UNLOCK;
+ return (np->catd);
+ }
+ }
+ UNLOCK;
+
+ if ((fd = _open(path, O_RDONLY | O_CLOEXEC)) == -1) {
+ SAVEFAIL(name, lang, errno);
+ NLRETERR(errno);
+ }
+
+ if (_fstat(fd, &st) != 0) {
+ _close(fd);
+ SAVEFAIL(name, lang, EFTYPE);
+ NLRETERR(EFTYPE);
+ }
+
+ /*
+ * If the file size cannot be held in size_t we cannot mmap()
+ * it to the memory. Probably, this will not be a problem given
+ * that catalog files are usually small.
+ */
+ if (st.st_size > SIZE_T_MAX) {
+ _close(fd);
+ SAVEFAIL(name, lang, EFBIG);
+ NLRETERR(EFBIG);
+ }
+
+ if ((data = mmap(0, (size_t)st.st_size, PROT_READ,
+ MAP_FILE|MAP_SHARED, fd, (off_t)0)) == MAP_FAILED) {
+ int saved_errno = errno;
+ _close(fd);
+ SAVEFAIL(name, lang, saved_errno);
+ NLRETERR(saved_errno);
+ }
+ _close(fd);
+
+ if (ntohl((u_int32_t)((struct _nls_cat_hdr *)data)->__magic) !=
+ _NLS_MAGIC) {
+ munmap(data, (size_t)st.st_size);
+ SAVEFAIL(name, lang, EFTYPE);
+ NLRETERR(EFTYPE);
+ }
+
+ if ((catd = malloc(sizeof (*catd))) == NULL) {
+ munmap(data, (size_t)st.st_size);
+ SAVEFAIL(name, lang, ENOMEM);
+ NLRETERR(ENOMEM);
+ }
+
+ catd->__data = data;
+ catd->__size = (int)st.st_size;
+
+ /* Caching opened catalog */
+ WLOCK(NLERR);
+ if ((np = malloc(sizeof(struct catentry))) != NULL) {
+ np->name = strdup(name);
+ np->path = strdup(path);
+ np->catd = catd;
+ np->lang = (lang == NULL) ? NULL : strdup(lang);
+ np->refcount = 1;
+ np->caterrno = 0;
+ SLIST_INSERT_HEAD(&cache, np, list);
+ }
+ UNLOCK;
+ return (catd);
+}
diff --git a/lib/libc/nls/nl_NL.ISO8859-1.msg b/lib/libc/nls/nl_NL.ISO8859-1.msg
new file mode 100644
index 000000000000..2939116fc97c
--- /dev/null
+++ b/lib/libc/nls/nl_NL.ISO8859-1.msg
@@ -0,0 +1,294 @@
+$ $FreeBSD$
+$
+$ Message catalog for nl_NL.ISO8859-1 locale
+$
+$ strerror() support catalog
+$
+$set 1
+$ EPERM
+1 Bewerking niet toegestaan
+$ ENOENT
+2 Bestand of map niet gevonden
+$ ESRCH
+3 Taak bestaat niet
+$ EINTR
+4 Onderbroken systeemaanroep
+$ EIO
+5 Invoer/uitvoer fout
+$ ENXIO
+6 Apparaat niet geconfigureerd
+$ E2BIG
+7 Argumentenlijst is te lang
+$ ENOEXEC
+8 Programma kan niet worden uitgevoerd
+$ EBADF
+9 Ongeldige bestandsverwijzing
+$ ECHILD
+10 Geen kindprocessen
+$ EDEADLK
+11 Een deadlock op een bron is vermeden
+$ ENOMEM
+12 Kan geen geheugen meer verkrijgen
+$ EACCES
+13 Toegang geweigerd
+$ EFAULT
+14 Ongeldig adres
+$ ENOTBLK
+15 Een per blok adresseerbaar apparaat is vereist
+$ EBUSY
+16 Apparaat is bezig
+$ EEXIST
+17 Bestand bestaat reeds
+$ EXDEV
+18 Verwijzing tussen verschillende apparaten
+$ ENODEV
+19 Bewerking wordt niet ondersteund door dit apparaat
+$ ENOTDIR
+20 Dit is geen map
+$ EISDIR
+21 Dit is een map
+$ EINVAL
+22 Ongeldig argument
+$ ENFILE
+23 Te veel open bestanden in het systeem
+$ EMFILE
+24 Te veel open bestanden
+$ ENOTTY
+25 ioctl niet van toepassing op dit apparaat
+$ ETXTBSY
+26 Programmabestand is bezig
+$ EFBIG
+27 Bestand is te groot
+$ ENOSPC
+28 Geen ruimte meer op dit apparaat
+$ ESPIPE
+29 Ongeldige zoekopdracht
+$ EROFS
+30 Van dit bestandssysteem kan alleen worden gelezen
+$ EMLINK
+31 Te veel bestandsverwijzingen
+$ EPIPE
+32 Gebroken pijp
+$ EDOM
+33 Numeriek argument valt buiten domein
+$ ERANGE
+34 Resultaat te groot of te klein
+$ EAGAIN, EWOULDBLOCK
+35 Middel tijdelijk onbeschikbaar
+$ EINPROGRESS
+36 Bewerking in gang gezet
+$ EALREADY
+37 Bewerking is al in gang gezet
+$ ENOTSOCK
+38 Voor deze bewerking is een contactpunt vereist
+$ EDESTADDRREQ
+39 Een bestemmingsadres is vereist
+$ EMSGSIZE
+40 Te groot bericht
+$ EPROTOTYPE
+41 Protocol past niet bij dit contactpunt
+$ ENOPROTOOPT
+42 Protocol is niet beschikbaar
+$ EPROTONOSUPPORT
+43 Protocol is niet ondersteund
+$ ESOCKTNOSUPPORT
+44 Dit soort contactpunt is niet ondersteund
+$ EOPNOTSUPP
+45 Bewerking niet ondersteund
+$ EPFNOSUPPORT
+46 Protocolfamilie niet ondersteund
+$ EAFNOSUPPORT
+47 Adressenfamilie niet ondersteund door protocolfamilie
+$ EADDRINUSE
+48 Adres is al in gebruik
+$ EADDRNOTAVAIL
+49 Het gevraagde adres kan niet worden toegekend
+$ ENETDOWN
+50 Netwerk is plat
+$ ENETUNREACH
+51 Netwerk is onbereikbaar
+$ ENETRESET
+52 Netwerk onderbrak verbinding tijdens herstart
+$ ECONNABORTED
+53 Verbroken verbinding veroorzaakt door software
+$ ECONNRESET
+54 Verbinding werd aan de andere kant verbroken
+$ ENOBUFS
+55 Geen bufferruimte meer beschikbaar
+$ EISCONN
+56 Contactpunt is al verbonden
+$ ENOTCONN
+57 Contactpunt is niet verbonden
+$ ESHUTDOWN
+58 Een afgesloten contactpunt kan geen gegevens meer verzenden
+$ ETOOMANYREFS
+59 Te veel verwijzingen: splitsen niet mogelijk
+$ ETIMEDOUT
+60 Verbinding te lang niet mogelijk
+$ ECONNREFUSED
+61 Verbinding geweigerd
+$ ELOOP
+62 Te veel niveaus van symbolische verwijzingen
+$ ENAMETOOLONG
+63 Bestandsnaam te lang
+$ EHOSTDOWN
+64 Bestemming niet actief
+$ EHOSTUNREACH
+65 Bestemming niet bereikbaar
+$ ENOTEMPTY
+66 Map is niet leeg
+$ EPROCLIM
+67 Te veel processen
+$ EUSERS
+68 Te veel gebruikers
+$ EDQUOT
+69 Schijfquota overschreden
+$ ESTALE
+70 Verlopen NFS-bestandsverwijzing
+$ EREMOTE
+71 Te veel verwijzingen op afstand in dit pad
+$ EBADRPC
+72 RPC-argumentstructuur is incorrect
+$ ERPCMISMATCH
+73 RPC-versie is verkeerd
+$ EPROGUNAVAIL
+74 RPC-programma niet beschikbaar
+$ EPROGMISMATCH
+75 Programmaversie is verkeerd
+$ EPROCUNAVAIL
+76 Taak kan niet door dit programma worden uitgevoerd
+$ ENOLCK
+77 Geen sloten beschikbaar
+$ ENOSYS
+78 Systeemfunctie is niet geimplementeerd
+$ EFTYPE
+79 Bestandsformaat niet van toepassing
+$ EAUTH
+80 Aanmeldingsfout
+$ ENEEDAUTH
+81 Aanmeldingsprocedure benodigd
+$ EIDRM
+82 De aanwijzer is verwijderd
+$ ENOMSG
+83 Geen bericht van het gewenste type
+$ EOVERFLOW
+84 Waarde te groot om te bewaren in gegevenstype
+$ ECANCELED
+85 Bewerking geannuleerd
+$ EILSEQ
+86 Ongeldige bytereeks
+$ ENOATTR
+87 Attribuut niet gevonden
+$ EDOOFUS
+88 Programmeerfout
+$ EBADMSG
+89 Verkeerd of defect bericht
+$ EMULTIHOP
+90 Multihopverzoek
+$ ENOLINK
+91 Verbinding werd verstoord
+$ EPROTO
+92 Protocolfout
+$ ENOTCAPABLE
+93 Onvoldoende mogelijkheden
+$
+$ strsignal() support catalog
+$
+$set 2
+$ SIGHUP
+1 Opgehangen
+$ SIGINT
+2 Onderbroken
+$ SIGQUIT
+3 Opgegeven
+$ SIGILL
+4 Verboden instructie
+$ SIGTRAP
+5 Spoor/BPT-val
+$ SIGABRT
+6 Abort-val
+$ SIGEMT
+7 EMT-val
+$ SIGFPE
+8 Drijvende kommafout
+$ SIGKILL
+9 Gedood
+$ SIGBUS
+10 Busfout
+$ SIGSEGV
+11 Segmentatiefout
+$ SIGSYS
+12 Verkeerde systeemaanroep
+$ SIGPIPE
+13 Gebroken pijp
+$ SIGALRM
+14 Wekker
+$ SIGTERM
+15 Beeindigd
+$ SIGURG
+16 Dringende I/O opgemerkt
+$ SIGSTOP
+17 Gestopt (signaal)
+$ SIGTSTP
+18 Gestopt
+$ SIGCONT
+19 Voortgezet
+$ SIGCHLD
+20 Kindproces beeindigd
+$ SIGTTIN
+21 Gestopt (TTY-invoer)
+$ SIGTTOU
+22 Gestopt (TTY-uitvoer)
+$ SIGIO
+23 I/O mogelijk
+$ SIGXCPU
+24 Te veel CPU-tijd verbruikt
+$ SIGXFSZ
+25 Maximale bestandsgrootte overschreden
+$ SIGVTALRM
+26 Virtuele wekker
+$ SIGPROF
+27 Profiling-wekker
+$ SIGWINCH
+28 Venstergrootte veranderd
+$ SIGINFO
+29 Informatieverzoek
+$ SIGUSR1
+30 Gebruikersignaal 1
+$ SIGUSR2
+31 Gebruikersignaal 2
+$
+$ gai_strerror() support catalog
+$set 3
+$ 1 (obsolete)
+1 Adresfamilie voor hostnaam niet ondersteund
+$ EAI_AGAIN
+2 Tijdelijke fout in naamresolutie
+$ EAI_BADFLAGS
+3 Ongeldige waarde voor ai_flags
+$ EAI_FAIL
+4 Onherstelbare fout in naamresolutie
+$ EAI_FAMILY
+5 ai_familie niet ondersteund
+$ EAI_MEMORY
+6 Geheugenallocatiefout
+$ 7 (obsolete)
+7 Geen adres met hostnaam geassocieerd
+$ EAI_NONAME
+8 hostname noch servname gegeven, of onbekend
+$ EAI_SERVICE
+9 servname niet ondersteund voor ai_socktype
+$ EAI_SOCKTYPE
+10 ai_socktype niet ondersteund
+$ EAI_SYSTEM
+11 Systeemfout geretourneerd in errno
+$ EAI_BADHINTS
+12 Ongeldige waarde voor hints
+$ EAI_PROTOCOL
+13 Opgelost protocol is onbekend
+$ EAI_OVERFLOW
+14 Argumentbuffer overstroomd
+$ 0
+32766 Succes
+$ NL_MSGMAX
+32767 Onbekende fout
diff --git a/lib/libc/nls/no_NO.ISO8859-1.msg b/lib/libc/nls/no_NO.ISO8859-1.msg
new file mode 100644
index 000000000000..2598f4d9357e
--- /dev/null
+++ b/lib/libc/nls/no_NO.ISO8859-1.msg
@@ -0,0 +1,231 @@
+$ $FreeBSD$
+$
+$ Message catalog for no_NO.ISO8859-1 locale
+$
+$ strerror() support catalog
+$
+$set 1
+$ EPERM
+1 Operasjonen er ikke tillatt
+$ ENOENT
+2 Filen eller katalogen finnes ikke
+$ ESRCH
+3 Prosessen finnes ikke
+$ EINTR
+4 Avbrudt systemkall
+$ EIO
+5 I/O feil
+$ ENXIO
+6 Enheten er ikke konfigurert
+$ E2BIG
+7 Argumentlisten er for lang
+$ ENOEXEC
+8 Ukjent kjørbart format
+$ EBADF
+9 Ugyldig fildeskriptor
+$ ECHILD
+10 Ingen barneprosess
+$ EDEADLK
+11 Vranglås unngått
+$ ENOMEM
+12 Kan ikke allokere nok minne
+$ EACCES
+13 Ingen adgang
+$ EFAULT
+14 Ugyldig adresse
+$ ENOTBLK
+15 Blokk-enhet påkrevd
+$ EBUSY
+16 Enheten er opptatt
+$ EEXIST
+17 Filen finnes
+$ EXDEV
+18 Link mellom forskjellige enheter
+$ ENODEV
+19 Operasjonen er ikke støttet av enheten
+$ ENOTDIR
+20 Ikke en katalog
+$ EISDIR
+21 Er en katalog
+$ EINVAL
+22 Ugyldig argument
+$ ENFILE
+23 For mange åpne filer i systemet
+$ EMFILE
+24 For mange åpne filer
+$ ENOTTY
+25 Ugyldig ioctl for enheten
+$ ETXTBSY
+26 Kjørbar fil i bruk
+$ EFBIG
+27 Filen er for stor
+$ ENOSPC
+28 Ingen ledig plass på enheten
+$ ESPIPE
+29 Ugyldig seek operasjon
+$ EROFS
+30 Filsystemet er skrivebeskyttet
+$ EMLINK
+31 For mange linker
+$ EPIPE
+32 Brudt pipe
+$ EDOM
+33 Numerisk argument utenfor arbeidsområdet
+$ ERANGE
+34 Resultatet er for stort
+$ EAGAIN, EWOULDBLOCK
+35 Ressurs midlertidig utilgjengelig
+$ EINPROGRESS
+36 Operasjonen er nå i gang
+$ EALREADY
+37 Operasjonen er allerede i gang
+$ ENOTSOCK
+38 Deskriptoren er ikke en socket
+$ EDESTADDRREQ
+39 Mottakeradresse er påkrevd
+$ EMSGSIZE
+40 Meldingen er for lang
+$ EPROTOTYPE
+41 Ugyldig protokolltype for denne socketen
+$ ENOPROTOOPT
+42 Protokollen er ikke tilgjengelig
+$ EPROTONOSUPPORT
+43 Protokollen er ikke støttet
+$ ESOCKTNOSUPPORT
+44 Socket-typen er ikke støttet
+$ EOPNOTSUPP
+45 Operasjonen er ikke støttet
+$ EPFNOSUPPORT
+46 Protokollfamilien er ikke støttet
+$ EAFNOSUPPORT
+47 Adressetypen er ikke støttet av protokollfamilien
+$ EADDRINUSE
+48 Adressen er allerede i bruk
+$ EADDRNOTAVAIL
+49 Kan ikke bruke den ønskede adressen
+$ ENETDOWN
+50 Nettverket er nede
+$ ENETUNREACH
+51 Nettverket er utilgjengelig
+$ ENETRESET
+52 Nettverket kuttet forbindelsen ved reset
+$ ECONNABORTED
+53 Programvaren forårsaket brudd av forbindelsen
+$ ECONNRESET
+54 Forbindelsen avbrudt av korrespondenten
+$ ENOBUFS
+55 Buffer-plass ikke tilgjengelig
+$ EISCONN
+56 Socketen er allerede forbundet
+$ ENOTCONN
+57 Socketen er ikke forbundet
+$ ESHUTDOWN
+58 Kan ikke sende etter at socketen er tatt ned
+$ ETOOMANYREFS
+59 For mange referanser: kan ikke slå dem sammen
+$ ETIMEDOUT
+60 Tiden til forbindelsen utløp
+$ ECONNREFUSED
+61 Forbindelse nektet
+$ ELOOP
+62 For mange nivåer med symbolske linker
+$ ENAMETOOLONG
+63 Filnavnet er for langt
+$ EHOSTDOWN
+64 Maskinen er nede
+$ EHOSTUNREACH
+65 Ingen rute til maskinen
+$ ENOTEMPTY
+66 Katalogen er ikke tom
+$ EPROCLIM
+67 For mange prosesser
+$ EUSERS
+68 For mange brukere
+$ EDQUOT
+69 Diskkvote overskredet
+$ ESTALE
+70 Fastlåst NFS fildeskriptor
+$ EREMOTE
+71 For mange nivåer med remote i stien
+$ EBADRPC
+72 Ugyldig RPC struktur
+$ ERPCMISMATCH
+73 Feil RPC versjon
+$ EPROGUNAVAIL
+74 RPC program ikke tilgjengelig
+$ EPROGMISMATCH
+75 Feil programversjon
+$ EPROCUNAVAIL
+76 Prosedyren finnes ikke i programmet
+$ ENOLCK
+77 Ingen låsing tilgjengelig
+$ ENOSYS
+78 Funksjonen er ikke implementert
+$ EFTYPE
+79 Ugyldig filtype eller format
+$
+$ strsignal() support catalog
+$
+$set 2
+$ SIGHUP
+1 Hangup
+$ SIGINT
+2 Avbrudd
+$ SIGQUIT
+3 Avslutt
+$ SIGILL
+4 Ugyldig instruksjon
+$ SIGTRAP
+5 Trace/BPT trap
+$ SIGABRT
+6 Abort trap
+$ SIGEMT
+7 EMT trap
+$ SIGFPE
+8 Flyttallsfeil
+$ SIGKILL
+9 Drept
+$ SIGBUS
+10 Buss feil
+$ SIGSEGV
+11 Segmenteringsfeil
+$ SIGSYS
+12 Ugyldig systemkall
+$ SIGPIPE
+13 Brudt pipe
+$ SIGALRM
+14 Alarmklokke
+$ SIGTERM
+15 Terminert
+$ SIGURG
+16 Urgent I/O condition
+$ SIGSTOP
+17 Stoppet (signal)
+$ SIGTSTP
+18 Stoppet
+$ SIGCONT
+19 Fortsetter
+$ SIGCHLD
+20 Barn avsluttet
+$ SIGTTIN
+21 Stoppet (tty input)
+$ SIGTTOU
+22 Stoppet (tty output)
+$ SIGIO
+23 I/O mulig
+$ SIGXCPU
+24 CPU-tid overskredet
+$ SIGXFSZ
+25 Maksimal filstørrelse overskredet
+$ SIGVTALRM
+26 Virtuell timer utløpt
+$ SIGPROF
+27 Profileringstimer utløpt
+$ SIGWINCH
+28 Vindustørrelse endres
+$ SIGINFO
+29 Informasjonsforespørsel
+$ SIGUSR1
+30 Brukerdefinert signal 1
+$ SIGUSR2
+31 Brukerdefinert signal 2
diff --git a/lib/libc/nls/pl_PL.ISO8859-2.msg b/lib/libc/nls/pl_PL.ISO8859-2.msg
new file mode 100644
index 000000000000..1c184b30997d
--- /dev/null
+++ b/lib/libc/nls/pl_PL.ISO8859-2.msg
@@ -0,0 +1,249 @@
+$ $FreeBSD$
+$
+$ Message catalog for pl_PL.ISO8859-2 locale
+$
+$ strerror() support catalog
+$
+$set 1
+$ EPERM
+1 Operacja niedozwolona
+$ ENOENT
+2 Nie ma takiego pliku/katalogu
+$ ESRCH
+3 Nie ma takiego procesu
+$ EINTR
+4 Wywo³anie systemowe przerwane
+$ EIO
+5 B³±d wej¶cia/wyj¶cia
+$ ENXIO
+6 Nieskonfigurowane urz±dzenie
+$ E2BIG
+7 Zbyt d³uga lista argumentów
+$ ENOEXEC
+8 B³êdny format pliku wykonywalnego
+$ EBADF
+9 Z³y deskryptor pliku
+$ ECHILD
+10 Brak procesów potomnych
+$ EDEADLK
+11 Unikniêto zakleszczenia zasobów
+$ ENOMEM
+12 Brak pamiêci do przydzia³u
+$ EACCES
+13 Brak dostêpu
+$ EFAULT
+14 Z³y adres
+$ ENOTBLK
+15 Wymagane urz±dzenie blokowe
+$ EBUSY
+16 Urz±dzenie zajête
+$ EEXIST
+17 Plik istnieje
+$ EXDEV
+18 Dowi±zanie miedzy urz±dzeniami
+$ ENODEV
+19 Operacja nieobs³ugiwana przez urz±dzenie
+$ ENOTDIR
+20 To nie jest katalog
+$ EISDIR
+21 To jest katalog
+$ EINVAL
+22 B³êdny argument
+$ ENFILE
+23 Zbyt wiele otwartych plików w systemie
+$ EMFILE
+24 Zbyt wiele otwartych plików
+$ ENOTTY
+25 Niew³a¶ciwy dostêp do urz±dzenia
+$ ETXTBSY
+26 Plik wykonywalny jest zajêty
+$ EFBIG
+27 Zbyt du¿y plik
+$ ENOSPC
+28 Brak miejsca na urz±dzeniu
+$ ESPIPE
+29 Przesuniêcie niemo¿liwe
+$ EROFS
+30 System plików tylko do odczytu
+$ EMLINK
+31 Zbyt wiele dowi±zañ
+$ EPIPE
+32 Potok przerwany
+$ EDOM
+33 Argument liczbowy z poza zakresu
+$ ERANGE
+34 Wynik z poza zakresu
+$ EAGAIN, EWOULDBLOCK
+35 Zasoby chwilowo niedostêpne
+$ EINPROGRESS
+36 Operacja jest w³a¶nie wykonywana
+$ EALREADY
+37 Operacja jest ju¿ wykonywana
+$ ENOTSOCK
+38 Operacja na obiekcie, który nie jest gniazdem
+$ EDESTADDRREQ
+39 Wymagany adres przeznaczenia
+$ EMSGSIZE
+40 Wiadomo¶æ zbyt d³uga
+$ EPROTOTYPE
+41 Typ protoko³u nie pasuje do gniazda
+$ ENOPROTOOPT
+42 Protokó³ nie jest dostêpny
+$ EPROTONOSUPPORT
+43 Nieobs³ugiwany protokó³
+$ ESOCKTNOSUPPORT
+44 Nieobs³ugiwany typ gniazda
+$ EOPNOTSUPP
+45 Nieobs³ugiwana operacja
+$ EPFNOSUPPORT
+46 Nieobs³ugiwana rodzina protoko³ów
+$ EAFNOSUPPORT
+47 Rodzina adresów nie jest obs³ugiwana przez rodzinê protoko³ów
+$ EADDRINUSE
+48 Adres jest ju¿ w u¿yciu
+$ EADDRNOTAVAIL
+49 Adres nie mo¿e byæ przydzielony
+$ ENETDOWN
+50 Sieæ nie dzia³a
+$ ENETUNREACH
+51 Sieæ jest niedostêpna
+$ ENETRESET
+52 Sieæ przerwa³a po³±czenie po resecie
+$ ECONNABORTED
+53 Oprogramowanie spowodowa³o przerwanie po³±czenia
+$ ECONNRESET
+54 Po³±czenie zerwane przez drug± stronê
+$ ENOBUFS
+55 Brak miejsca w buforze
+$ EISCONN
+56 Gniazdo jest ju¿ po³±czone
+$ ENOTCONN
+57 Gniazdo nie jest po³±czone
+$ ESHUTDOWN
+58 Nie mo¿na wysy³aæ po zamkniêciu gniazda
+$ ETOOMANYREFS
+59 Za du¿o powi±zañ: dowi±zanie niemo¿liwe
+$ ETIMEDOUT
+60 Limit czasu operacji przekroczony
+$ ECONNREFUSED
+61 Po³±czenie odrzucone
+$ ELOOP
+62 Zbyt wiele wzajemnych dowi±zañ symbolicznych
+$ ENAMETOOLONG
+63 Zbyt d³uga nazwa pliku
+$ EHOSTDOWN
+64 Host jest wy³±czony
+$ EHOSTUNREACH
+65 Brak drogi do hosta
+$ ENOTEMPTY
+66 Katalog nie jest pusty
+$ EPROCLIM
+67 Zbyt wiele procesów
+$ EUSERS
+68 Zbyt wielu u¿ytkowników
+$ EDQUOT
+69 Przekroczono limit miejsca na dysku
+$ ESTALE
+70 Uchwyt pliku NFS jest nieaktualny
+$ EREMOTE
+71 Zbyt wiele poziomów zagnie¿d¿enia w ¶cie¿ce
+$ EBADRPC
+72 RPC b³êdna struktura
+$ ERPCMISMATCH
+73 RPC niekompatybilna wersja
+$ EPROGUNAVAIL
+74 RPC program niedostêpny
+$ EPROGMISMATCH
+75 Nieobs³ugiwana wersja programu
+$ EPROCUNAVAIL
+76 Nieobs³ugiwana procedura
+$ ENOLCK
+77 Wyczerpany limit blokad
+$ ENOSYS
+78 Nieobs³ugiwana funkcja
+$ EFTYPE
+79 Niew³a¶ciwy typ lub format pliku
+$ EAUTH
+80 B³±d uwierzytelnienia
+$ ENEEDAUTH
+81 Wymagane uwierzytelnienie
+$ EIDRM
+82 Identyfikator zosta³ usuniêty
+$ ENOMSG
+83 Brak komunikatu po¿±danego typu
+$ EOVERFLOW
+84 Warto¶æ zbyt du¿a dla zdefiniowanego typu danych
+$ ECANCELED
+85 Operacja anulowana
+$ EILSEQ
+86 B³êdna sekwencja bajtów
+$ ENOATTR
+87 Nie znaleziono atrybutu
+$ EDOOFUS
+88 Wewnêtrzny b³±d programu
+$
+$ strsignal() support catalog
+$
+$set 2
+$ SIGHUP
+1 Roz³±czenie
+$ SIGINT
+2 Przerwanie
+$ SIGQUIT
+3 Wyj¶cie
+$ SIGILL
+4 Nieznana instrukcja
+$ SIGTRAP
+5 Pu³apka debuggera/BPT
+$ SIGABRT
+6 Przerwana pu³apka
+$ SIGEMT
+7 Pu³apka EMT
+$ SIGFPE
+8 B³±d w obliczeniach zmiennoprzecinkowych
+$ SIGKILL
+9 Unicestwiony
+$ SIGBUS
+10 B³±d szyny
+$ SIGSEGV
+11 Naruszenie ochrony pamiêci
+$ SIGSYS
+12 B³êdne wywo³anie systemowe
+$ SIGPIPE
+13 Przerwany potok
+$ SIGALRM
+14 Budzik
+$ SIGTERM
+15 Zakoñczony
+$ SIGURG
+16 Nag³y wypadek I/O
+$ SIGSTOP
+17 Zatrzymany (sygna³)
+$ SIGTSTP
+18 Zatrzymany
+$ SIGCONT
+19 Kontynuacja
+$ SIGCHLD
+20 Proces potomny zakoñczy³ pracê
+$ SIGTTIN
+21 Zatrzymany (wej¶cie z tty)
+$ SIGTTOU
+22 Zatrzymany (wyj¶cie z tty)
+$ SIGIO
+23 Wej/Wyj dozwolone
+$ SIGXCPU
+24 Przekroczony limit czasu procesora
+$ SIGXFSZ
+25 Przekroczony limit wielko¶ci pliku
+$ SIGVTALRM
+26 Alarm stopera wirtualnego
+$ SIGPROF
+27 Alarm stopera profiluj±cego
+$ SIGWINCH
+28 Zmiana rozmiaru okna
+$ SIGINFO
+29 ¯±danie informacji
+$ SIGUSR1
+30 Sygna³ u¿ytkownika 1
+$ SIGUSR2
+31 Sygna³ u¿ytkownika 2
diff --git a/lib/libc/nls/pt_BR.ISO8859-1.msg b/lib/libc/nls/pt_BR.ISO8859-1.msg
new file mode 100644
index 000000000000..fb1c10056ccf
--- /dev/null
+++ b/lib/libc/nls/pt_BR.ISO8859-1.msg
@@ -0,0 +1,249 @@
+$ $FreeBSD$
+$
+$ Message catalog for pt_BR.ISO8859-1 locale
+$
+$ strerror() support catalog
+$
+$set 1
+$ EPERM
+1 Operação não permitida
+$ ENOENT
+2 Nenhum arquivo ou diretório encontrado
+$ ESRCH
+3 Nenhum processo encontrado
+$ EINTR
+4 Chamada de sistema interrompida
+$ EIO
+5 Erro de entrada/saída
+$ ENXIO
+6 Dispositivo não configurado
+$ E2BIG
+7 Lista de argumentos muito grande
+$ ENOEXEC
+8 Erro no formato de execução
+$ EBADF
+9 Erro no descritor de arquivo
+$ ECHILD
+10 Nenhum processo filho
+$ EDEADLK
+11 Bloqueio de recurso evitado
+$ ENOMEM
+12 Impossível alocar memória
+$ EACCES
+13 Permissão negada
+$ EFAULT
+14 Endereço errado
+$ ENOTBLK
+15 Dispositivo de bloco requerido
+$ EBUSY
+16 Dispositivo ocupado
+$ EEXIST
+17 Arquivo existe
+$ EXDEV
+18 Ligação entre dispositivos
+$ ENODEV
+19 Operação não suportada pelo dispositivo
+$ ENOTDIR
+20 Não é um diretório
+$ EISDIR
+21 É um diretório
+$ EINVAL
+22 Argumento inválido
+$ ENFILE
+23 Muitos arquivos abertos no sistema
+$ EMFILE
+24 Muitos arquivos abertos no sistema
+$ ENOTTY
+25 ioctl inapropriado para o dispositivo
+$ ETXTBSY
+26 Arquivo texto sendo utilizado
+$ EFBIG
+27 Arquivo muito grande
+$ ENOSPC
+28 Sem espaço no dispositivo
+$ ESPIPE
+29 seek ilegal
+$ EROFS
+30 Sistema de arquivos apenas para leitura
+$ EMLINK
+31 Muitos links
+$ EPIPE
+32 pipe quebrado
+$ EDOM
+33 Argumento numérico fora do domínio
+$ ERANGE
+34 Resultado muito grande
+$ EAGAIN, EWOULDBLOCK
+35 Recurso temporariamente indisponível
+$ EINPROGRESS
+36 Operação em progresso agora
+$ EALREADY
+37 Operação em progresso pronta
+$ ENOTSOCK
+38 Operação de socket em um não-socket
+$ EDESTADDRREQ
+39 Endereço de destino requerido
+$ EMSGSIZE
+40 Mensagem muito grande
+$ EPROTOTYPE
+41 Tipo de protocolo errado para socket
+$ ENOPROTOOPT
+42 Protocolo não disponível
+$ EPROTONOSUPPORT
+43 Protocolo não suportado
+$ ESOCKTNOSUPPORT
+44 Tipo de socket não suportado
+$ EOPNOTSUPP
+45 Operação não permitida
+$ EPFNOSUPPORT
+46 Família de protocolo não suportada
+$ EAFNOSUPPORT
+47 Família de endereços não suportada pela família de protocolos
+$ EADDRINUSE
+48 Endereço já está em uso
+$ EADDRNOTAVAIL
+49 Impossível obter endereço solicitado
+$ ENETDOWN
+50 Rede está parada
+$ ENETUNREACH
+51 Rede está inalcançável
+$ ENETRESET
+52 Conexão de rede perdida durante reset
+$ ECONNABORTED
+53 Conexão abortada por software
+$ ECONNRESET
+54 Conexão reiniciada pelo outro ponto
+$ ENOBUFS
+55 Sem espaço de buffer disponível
+$ EISCONN
+56 Socket já está conectado
+$ ENOTCONN
+57 Socket não está conectado
+$ ESHUTDOWN
+58 Impossível enviar depois que o socket foi finalizado
+$ ETOOMANYREFS
+59 Muitas referências: impossível ligar
+$ ETIMEDOUT
+60 Tempo de operação expirou
+$ ECONNREFUSED
+61 Conexão recusada
+$ ELOOP
+62 Muitos níveis de links simbólicos
+$ ENAMETOOLONG
+63 Nome de arquivo muito grande
+$ EHOSTDOWN
+64 Host está desligado
+$ EHOSTUNREACH
+65 Sem rota para o host
+$ ENOTEMPTY
+66 Diretório não está vazio
+$ EPROCLIM
+67 Muitos processos
+$ EUSERS
+68 Muitos usuários
+$ EDQUOT
+69 Quota de disco excedida
+$ ESTALE
+70 Manipulador de arquivo NFS velho
+$ EREMOTE
+71 Muitos níveis no caminho remoto
+$ EBADRPC
+72 Estrutura RPC incorreta
+$ ERPCMISMATCH
+73 Versão RPC incorreta
+$ EPROGUNAVAIL
+74 Programa RPC indisponível
+$ EPROGMISMATCH
+75 Versão do programa incorreta
+$ EPROCUNAVAIL
+76 Procedimento incorreto para o programa
+$ ENOLCK
+77 Nenhum lock disponível
+$ ENOSYS
+78 Função não implementada
+$ EFTYPE
+79 Tipo de arquivo ou formato inapropriados
+$ EAUTH
+80 Erro de autenticação
+$ ENEEDAUTH
+81 Necessidade de autenticador
+$ EIDRM
+82 Identificador removido
+$ ENOMSG
+83 Nenhuma mensagem do tipo desejado
+$ EOVERFLOW
+84 Valor muito grande para ser armazenado neste tipo de dado
+$ ECANCELED
+85 Operação cancelada
+$ EILSEQ
+86 Sequência de bytes ilegal
+$ ENOATTR
+87 Atributo não encontrado
+$ EDOOFUS
+88 Erro de programação
+$
+$ strsignal() support catalog
+$
+$set 2
+$ SIGHUP
+1 Fim da linha (Hangup)
+$ SIGINT
+2 Interrupção
+$ SIGQUIT
+3 Saída
+$ SIGILL
+4 Instrução ilegal
+$ SIGTRAP
+5 Trap de Trace/BPT
+$ SIGABRT
+6 Abortar trap
+$ SIGEMT
+7 EMT trap
+$ SIGFPE
+8 Exceção de ponto flutuante
+$ SIGKILL
+9 Morreu
+$ SIGBUS
+10 Erro de barramento
+$ SIGSEGV
+11 Falha de segmentação
+$ SIGSYS
+12 Chamada de sistema incorreta
+$ SIGPIPE
+13 Pipe incorreto
+$ SIGALRM
+14 Alarme do relógio
+$ SIGTERM
+15 Terminado
+$ SIGURG
+16 Condição urgente de E/S
+$ SIGSTOP
+17 Suspendido (sinal)
+$ SIGTSTP
+18 Suspendido
+$ SIGCONT
+19 Continuado
+$ SIGCHLD
+20 Filho saiu
+$ SIGTTIN
+21 Parado (entrada de tty)
+$ SIGTTOU
+22 Parado (saída de tty)
+$ SIGIO
+23 E/S possível
+$ SIGXCPU
+24 Limite de tempo de CPU excedido
+$ SIGXFSZ
+25 Tamanho de arquivo excedido
+$ SIGVTALRM
+26 Temporizador virtual expirou
+$ SIGPROF
+27 Temporizador de profiling expirou
+$ SIGWINCH
+28 Mudança no tamanho de janela
+$ SIGINFO
+29 Requisição de informação
+$ SIGUSR1
+30 Sinal 1 definido pelo usuário
+$ SIGUSR2
+31 Sinal 2 definido pelo usuário
diff --git a/lib/libc/nls/ru_RU.KOI8-R.msg b/lib/libc/nls/ru_RU.KOI8-R.msg
new file mode 100644
index 000000000000..48bc1d400150
--- /dev/null
+++ b/lib/libc/nls/ru_RU.KOI8-R.msg
@@ -0,0 +1,266 @@
+$ $FreeBSD$
+$
+$ Message catalog for ru_RU.KOI8-R locale
+$
+$ strerror() support catalog
+$
+$set 1
+$ EPERM
+1 ïÐÅÒÁÃÉÑ ÎÅ ÒÁÚÒÅÛÅÎÁ
+$ ENOENT
+2 îÅÔ ÔÁËÏÇÏ ÆÁÊÌÁ ÉÌÉ ËÁÔÁÌÏÇÁ
+$ ESRCH
+3 îÅÔ ÔÁËÏÇÏ ÐÒÏÃÅÓÓÁ
+$ EINTR
+4 ðÒÅÒ×ÁÎÎÙÊ ÓÉÓÔÅÍÎÙÊ ×ÙÚÏ×
+$ EIO
+5 ïÛÉÂËÁ ××ÏÄÁ/×Ù×ÏÄÁ
+$ ENXIO
+6 õÓÔÒÏÊÓÔ×Ï ÎÅ ÓËÏÎÆÉÇÕÒÉÒÏ×ÁÎÏ
+$ E2BIG
+7 óÌÉÛËÏÍ ÄÌÉÎÎÙÊ ÓÐÉÓÏË ÁÒÇÕÍÅÎÔÏ×
+$ ENOEXEC
+8 ïÛÉÂËÁ ÆÏÒÍÁÔÁ ×ÙÐÏÌÎÑÅÍÏÇÏ ÆÁÊÌÁ
+$ EBADF
+9 îÅËÏÒÒÅËÔÎÙÊ ÄÅÓËÒÉÐÔÏÒ ÆÁÊÌÁ
+$ ECHILD
+10 îÅÔ ÐÏÒÏÖÄÅÎÎÙÈ ÐÒÏÃÅÓÓÏ×
+$ EDEADLK
+11 ðÒÅÄÏÔ×ÒÁÝÅÎÁ ×ÚÁÉÍÎÁÑ ÂÌÏËÉÒÏ×ËÁ ÐÒÉ ÄÏÓÔÕÐÅ Ë ÒÅÓÕÒÓÕ
+$ ENOMEM
+12 îÅ×ÏÚÍÏÖÎÏ ×ÙÄÅÌÉÔØ ÐÁÍÑÔØ
+$ EACCES
+13 îÅÄÏÓÔÁÔÏÞÎÏ ÐÒÉ×ÉÌÅÇÉÊ
+$ EFAULT
+14 îÅËÏÒÒÅËÔÎÙÊ ÁÄÒÅÓ
+$ ENOTBLK
+15 îÅÏÂÈÏÄÉÍÏ ÕËÁÚÁÔØ ÂÌÏÞÎÏÅ ÕÓÔÒÏÊÓÔ×Ï
+$ EBUSY
+16 õÓÔÒÏÊÓÔ×Ï ÚÁÎÑÔÏ
+$ EEXIST
+17 æÁÊÌ ÓÕÝÅÓÔ×ÕÅÔ
+$ EXDEV
+18 óÓÙÌËÁ ÎÁ ÄÒÕÇÏÅ ÕÓÔÒÏÊÓÔ×Ï
+$ ENODEV
+19 ïÐÅÒÁÃÉÑ ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÔÓÑ ÕÓÔÒÏÊÓÔ×ÏÍ
+$ ENOTDIR
+20 õËÁÚÁÎÎÙÊ ÆÁÊÌ ÎÅ Ñ×ÌÑÅÔÓÑ ËÁÔÁÌÏÇÏÍ
+$ EISDIR
+21 õËÁÚÁÎÎÙÊ ÆÁÊÌ Ñ×ÌÑÅÔÓÑ ËÁÔÁÌÏÇÏÍ
+$ EINVAL
+22 îÅÄÏÐÕÓÔÉÍÙÊ ÁÒÇÕÍÅÎÔ
+$ ENFILE
+23 óÌÉÛËÏÍ ÍÎÏÇÏ ÏÔËÒÙÔÙÈ ÆÁÊÌÏ× × ÓÉÓÔÅÍÅ
+$ EMFILE
+24 óÌÉÛËÏÍ ÍÎÏÇÏ ÏÔËÒÙÔÙÈ ÆÁÊÌÏ×
+$ ENOTTY
+25 ÷ÙÚÏ× ioctl ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÔÓÑ ÕÓÔÒÏÊÓÔ×ÏÍ
+$ ETXTBSY
+26 ôÅËÓÔÏ×ÙÊ ÆÁÊÌ ÚÁÎÑÔ
+$ EFBIG
+27 óÌÉÛËÏÍ ÂÏÌØÛÏÊ ÆÁÊÌ
+$ ENOSPC
+28 îÁ ÕÓÔÒÏÊÓÔ×Å ÎÅ ÏÓÔÁÌÏÓØ ÍÅÓÔÁ
+$ ESPIPE
+29 îÅÄÏÐÕÓÔÉÍÏÅ ÓÍÅÝÅÎÉÅ
+$ EROFS
+30 æÁÊÌÏ×ÁÑ ÓÉÓÔÅÍÁ ÔÏÌØËÏ ÄÌÑ ÞÔÅÎÉÑ
+$ EMLINK
+31 óÌÉÛËÏÍ ÍÎÏÇÏ ÓÓÙÌÏË
+$ EPIPE
+$ XXX???
+32 ëÁÎÁÌ ÒÁÚÒÕÛÅÎ
+$ EDOM
+33 îÅÄÏÐÕÓÔÉÍÏÅ ÚÎÁÞÅÎÉÅ ÞÉÓÌÏ×ÏÇÏ ÁÒÇÕÍÅÎÔÁ
+$ ERANGE
+34 óÌÉÛËÏÍ ÂÏÌØÛÏÊ ÒÅÚÕÌØÔÁÔ
+$ EAGAIN, EWOULDBLOCK
+35 òÅÓÕÒÓ ×ÒÅÍÅÎÎÏ ÎÅÄÏÓÔÕÐÅÎ
+$ EINPROGRESS
+36 ïÐÅÒÁÃÉÑ × ÐÒÏÃÅÓÓÅ ×ÙÐÏÌÎÅÎÉÑ
+$ EALREADY
+$ XXX???
+37 ïÐÅÒÁÃÉÑ ÕÖÅ ×ÙÐÏÌÎÑÅÔÓÑ
+$ ENOTSOCK
+38 ïÐÅÒÁÃÉÑ Ó ÓÏËÅÔÏÍ ÐÒÉÍÅÎÅÎÁ ÎÅ Ë ÓÏËÅÔÕ
+$ EDESTADDRREQ
+39 ôÒÅÂÕÅÔÓÑ ÃÅÌÅ×ÏÊ ÁÄÒÅÓ
+$ EMSGSIZE
+40 óÌÉÛËÏÍ ÄÌÉÎÎÏÅ ÓÏÏÂÝÅÎÉÅ
+$ EPROTOTYPE
+41 îÅ×ÅÒÎÙÊ ÔÉÐ ÐÒÏÔÏËÏÌÁ ÄÌÑ ÓÏËÅÔÁ
+$ ENOPROTOOPT
+42 ðÒÏÔÏËÏÌ ÎÅÄÏÓÔÕÐÅÎ
+$ EPROTONOSUPPORT
+43 ðÒÏÔÏËÏÌ ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÔÓÑ
+$ ESOCKTNOSUPPORT
+44 üÔÏÔ ÔÉÐ ÓÏËÅÔÁ ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÔÓÑ
+$ EOPNOTSUPP
+45 ïÐÅÒÁÃÉÑ ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÔÓÑ
+$ EPFNOSUPPORT
+46 óÅÍÅÊÓÔ×Ï ÐÒÏÔÏËÏÌÏ× ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÔÓÑ
+$ EAFNOSUPPORT
+47 óÅÍÅÊÓÔ×Ï ÁÄÒÅÓÏ× ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÔÓÑ ÓÅÍÅÊÓÔ×ÏÍ ÐÒÏÔÏËÏÌÏ×
+$ EADDRINUSE
+48 áÄÒÅÓ ÕÖÅ ÉÓÐÏÌØÚÕÅÔÓÑ
+$ EADDRNOTAVAIL
+49 îÅ ÍÏÇÕ ÎÁÚÎÁÞÉÔØ ÕËÁÚÁÎÎÙÊ ÁÄÒÅÓ
+$ ENETDOWN
+50 óÅÔØ ÎÅ ÒÁÂÏÔÁÅÔ
+$ ENETUNREACH
+51 óÅÔØ ÎÅÄÏÓÔÉÖÉÍÁ
+$ ENETRESET
+52 óÅÔØ ÚÁËÒÙÌÁ ÐÏÄËÌÀÞÅÎÉÅ ÐÒÉ ÓÂÒÏÓÅ
+$ ECONNABORTED
+53 ðÒÏÇÒÁÍÍÁ ×ÙÚ×ÁÌÁ Á×ÁÒÉÊÎÏÅ ÐÒÅËÒÁÝÅÎÉÅ ÐÏÄËÌÀÞÅÎÉÑ
+$ ECONNRESET
+54 ðÏÄËÌÀÞÅÎÉÅ ÓÂÒÏÛÅÎÏ ÐÒÏÔÉ×ÏÐÏÌÏÖÎÏÊ ÓÔÏÒÏÎÏÊ
+$ ENOBUFS
+55 îÅ ÏÓÔÁÌÏÓØ ÍÅÓÔÁ ÐÏÄ ÂÕÆÅÒ
+$ EISCONN
+56 óÏËÅÔ ÕÖÅ ÐÏÄËÌÀÞÅÎ
+$ ENOTCONN
+57 óÏËÅÔ ÎÅ ÐÏÄËÌÀÞÅÎ
+$ ESHUTDOWN
+58 îÅ ÍÏÇÕ ÐÏÓÌÁÔØ ÐÏÓÌÅ ÚÁËÒÙÔÉÑ ÓÏËÅÔÁ
+$ ETOOMANYREFS
+59 óÌÉÛËÏÍ ÍÎÏÇÏ ÓÓÙÌÏË: ÎÅ ÍÏÇÕ ÓÏÅÄÉÎÉÔØ
+$ ETIMEDOUT
+60 ïÐÅÒÁÃÉÑ ÐÒÅ×ÙÓÉÌÁ ÌÉÍÉÔ ×ÒÅÍÅÎÉ
+$ ECONNREFUSED
+61 ðÏÄËÌÀÞÅÎÉÅ ÏÔ×ÅÒÇÎÕÔÏ
+$ ELOOP
+62 óÌÉÛËÏÍ ÍÎÏÇÏ ÕÒÏ×ÎÅÊ ÓÉÍ×ÏÌØÎÙÈ ÓÓÙÌÏË
+$ ENAMETOOLONG
+63 óÌÉÛËÏÍ ÄÌÉÎÎÏÅ ÉÍÑ ÆÁÊÌÁ
+$ EHOSTDOWN
+64 èÏÓÔ ÎÅ ÒÁÂÏÔÁÅÔ
+$ EHOSTUNREACH
+65 îÅÔ ÍÁÒÛÒÕÔÁ Ë ÈÏÓÔÕ
+$ ENOTEMPTY
+66 ëÁÔÁÌÏÇ ÎÅ ÐÕÓÔ
+$ EPROCLIM
+67 óÌÉÛËÏÍ ÍÎÏÇÏ ÐÒÏÃÅÓÓÏ×
+$ EUSERS
+68 óÌÉÛËÏÍ ÍÎÏÇÏ ÐÏÌØÚÏ×ÁÔÅÌÅÊ
+$ EDQUOT
+69 ðÒÅ×ÚÏÊÄÅÎÁ ÄÉÓËÏ×ÁÑ Ë×ÏÔÁ
+$ ESTALE
+70 õÓÔÁÒÅ×ÛÉÊ ÄÅÓËÒÉÐÔÏÒ ÆÁÊÌÁ NFS
+$ EREMOTE
+71 óÌÉÛËÏÍ ÍÎÏÇÏ ÄÉÓÔÁÎÃÉÏÎÎÙÈ ÐÅÒÅÈÏÄÏ× × ÐÕÔÉ
+$ EBADRPC
+72 îÅËÏÒÒÅËÔÎÁÑ ÓÔÒÕËÔÕÒÁ RPC
+$ ERPCMISMATCH
+73 îÅ×ÅÒÎÁÑ ×ÅÒÓÉÑ RPC
+$ EPROGUNAVAIL
+74 ðÒÏÇÒÁÍÍÁ RPC ÎÅÄÏÓÔÕÐÎÁ
+$ EPROGMISMATCH
+75 îÅ×ÅÒÎÁÑ ×ÅÒÓÉÑ ÐÒÏÇÒÁÍÍÙ
+$ EPROCUNAVAIL
+76 îÅËÏÒÒÅËÔÎÁÑ ÐÒÏÃÅÄÕÒÁ ÄÌÑ ÐÒÏÇÒÁÍÍÙ
+$ ENOLCK
+77 âÌÏËÉÒÏ×ËÉ ÎÅÄÏÓÔÕÐÎÙ
+$ ENOSYS
+78 æÕÎËÃÉÑ ÎÅ ÒÅÁÌÉÚÏ×ÁÎÁ
+$ EFTYPE
+79 îÅÐÏÄÈÏÄÑÝÉÊ ÔÉÐ ÉÌÉ ÆÏÒÍÁÔ ÆÁÊÌÁ
+$ EAUTH
+80 ïÛÉÂËÁ ÁÕÔÅÎÔÉÆÉËÁÃÉÉ
+$ ENEEDAUTH
+81 îÅÏÂÈÏÄÉÍÏ ÕÄÏÓÔÏ×ÅÒÅÎÉÅ
+$ EIDRM
+82 éÄÅÎÔÉÆÉËÁÔÏÒ ÕÄÁÌÅÎ
+$ ENOMSG
+83 îÅÔ ÓÏÏÂÝÅÎÉÑ ÔÒÅÂÕÅÍÏÇÏ ÔÉÐÁ
+$ EOVERFLOW
+84 óÌÉÛËÏÍ ÂÏÌØÛÏÅ ÚÎÁÞÅÎÉÅ ÄÌÑ ÈÒÁÎÅÎÉÑ × ÕËÁÚÁÎÎÏÍ ÔÉÐÅ ÄÁÎÎÙÈ
+$ ECANCELED
+85 ïÐÅÒÁÃÉÑ ÏÔÍÅÎÅÎÁ
+$ EILSEQ
+86 îÅÄÏÐÕÓÔÉÍÁÑ ÐÏÓÌÅÄÏ×ÁÔÅÌØÎÏÓÔØ ÂÁÊÔÏ×
+$ ENOATTR
+87 áÔÒÉÂÕÔ ÎÅ ÎÁÊÄÅÎ
+$ EDOOFUS
+88 ïÛÉÂËÁ ÐÒÏÇÒÁÍÍÉÒÏ×ÁÎÉÑ
+$ EBADMSG
+89 ðÌÏÈÏÊ ÆÏÒÍÁÔ ÓÏÏÂÝÅÎÉÑ
+$ EMULTIHOP
+90 ðÏÐÙÔËÁ ÍÕÌØÔÉÈÏÐÁ
+$ ENOLINK
+91 ëÁÎÁÌ ÒÁÚÏÒ×ÁÎ
+$ EPROTO
+92 ïÛÉÂËÁ ÐÒÏÔÏËÏÌÁ
+$ ENOTCAPABLE
+93 îÅÄÏÓÔÁÔÏÞÎÏ ×ÏÚÍÏÖÎÏÓÔÅÊ
+$
+$ strsignal() support catalog
+$
+$set 2
+$ SIGHUP
+$ XXX: ïÔËÌÀÞÅÎÉÅ?
+1 òÁÚÒÙ× Ó×ÑÚÉ
+$ SIGINT
+2 ðÒÅÒÙ×ÁÎÉÅ ÐÏ ÓÉÇÎÁÌÕ
+$ SIGQUIT
+3 ÷ÙÈÏÄ
+$ SIGILL
+4 îÅÄÏÐÕÓÔÉÍÁÑ ÉÎÓÔÒÕËÃÉÑ
+$ SIGTRAP
+5 ìÏ×ÕÛËÁ ÔÒÁÓÓÉÒÏ×ËÉ/ÔÏÞËÉ ÏÓÔÁÎÏ×Á
+$ SIGABRT
+$ XXX: á×ÁÒÉÊÎÏÅ ÚÁ×ÅÒÛÅÎÉÅ
+6 ìÏ×ÕÛËÁ Á×ÁÒÉÊÎÏÇÏ ÐÒÅËÒÁÝÅÎÉÑ
+$ SIGEMT
+7 ìÏ×ÕÛËÁ EMT
+$ SIGFPE
+$ XXX: ïÛÉÂËÁ ÏÐÅÒÁÃÉÉ Ó ÐÌÁ×ÁÀÝÅÊ ÔÏÞËÏÊ?
+8 ïÛÉÂËÁ ÐÒÉ ÒÁÂÏÔÅ Ó ×ÅÝÅÓÔ×ÅÎÎÙÍ ÞÉÓÌÏÍ
+$ SIGKILL
+$ XXX: õÂÉÔ
+9 ðÒÉÎÕÄÉÔÅÌØÎÏ ÐÒÅËÒÁÝÅÎ
+$ SIGBUS
+$ XXX: ïÛÉÂËÁ ÁÄÒÅÓÁÃÉÉ ÎÁ ÛÉÎÅ
+10 ïÛÉÂËÁ ÛÉÎÙ
+$ SIGSEGV
+11 ïÛÉÂËÁ ÓÅÇÍÅÎÔÁÃÉÉ
+$ SIGSYS
+12 îÅÄÏÐÕÓÔÉÍÙÊ ÓÉÓÔÅÍÎÙÊ ×ÙÚÏ×
+$ SIGPIPE
+13 ëÁÎÁÌ ÒÁÚÒÕÛÅÎ
+$ SIGALRM
+14 óÒÁÂÏÔÁÌ ÔÁÊÍÅÒ
+$ SIGTERM
+15 úÁ×ÅÒÛÅÎ
+$ SIGURG
+16 îÅÏÂÈÏÄÉÍ ÓÒÏÞÎÙÊ ××ÏÄ-×Ù×ÏÄ
+$ SIGSTOP
+17 ðÒÉÏÓÔÁÎÏ×ËÁ (ÓÉÇÎÁÌ)
+$ SIGTSTP
+18 ðÒÉÏÓÔÁÎÏ×ËÁ
+$ SIGCONT
+19 ðÒÏÄÏÌÖÅÎÉÅ ÒÁÂÏÔÙ
+$ SIGCHLD
+20 úÁ×ÅÒÛÅÎÁ ÒÁÂÏÔÁ ÐÏÒÏÖÄÅÎÎÏÇÏ ÐÒÏÃÅÓÓÁ
+$ SIGTTIN
+21 ïÓÔÁÎÏ×ÌÅÎ (××ÏÄ Ó ÔÅÒÍÉÎÁÌÁ)
+$ SIGTTOU
+22 ïÓÔÁÎÏ×ÌÅÎ (×Ù×ÏÄ ÎÁ ÔÅÒÍÉÎÁÌ)
+$ SIGIO
+23 ÷×ÏÄ-×Ù×ÏÄ ×ÏÚÍÏÖÅÎ
+$ SIGXCPU
+24 ðÒÅ×ÙÛÅÎÏ ÏÇÒÁÎÉÞÅÎÉÅ ÐÒÏÃÅÓÓÏÒÎÏÇÏ ×ÒÅÍÅÎÉ
+$ SIGXFSZ
+25 ðÒÅ×ÙÛÅÎ ÍÁËÓÉÍÁÌØÎÙÊ ÒÁÚÍÅÒ ÆÁÊÌÁ
+$ SIGVTALRM
+26 éÓÔÅË ×ÉÒÔÕÁÌØÎÙÊ ÔÁÊÍÅÒ
+$ SIGPROF
+27 éÓÔÅË ÔÁÊÍÅÒ ÐÒÏÆÉÌÉÒÏ×ÁÎÉÑ
+$ SIGWINCH
+28 éÚÍÅÎÅÎÉÅ ÒÁÚÍÅÒÁ ÏËÎÁ
+$ SIGINFO
+29 úÁÐÒÏÓ ÉÎÆÏÒÍÁÃÉÉ
+$ SIGUSR1
+30 ðÏÌØÚÏ×ÁÔÅÌØÓËÉÊ ÓÉÇÎÁÌ 1
+$ SIGUSR2
+31 ðÏÌØÚÏ×ÁÔÅÌØÓËÉÊ ÓÉÇÎÁÌ 2
diff --git a/lib/libc/nls/sk_SK.ISO8859-2.msg b/lib/libc/nls/sk_SK.ISO8859-2.msg
new file mode 100644
index 000000000000..8efa17d754a1
--- /dev/null
+++ b/lib/libc/nls/sk_SK.ISO8859-2.msg
@@ -0,0 +1,267 @@
+$ $FreeBSD$
+$
+$ Message catalog for sk_SK.ISO8859-2 locale
+$
+$ strerror() support catalog
+$
+$set 1
+$ EPERM
+1 Operácia nie je povolená
+$ ENOENT
+2 Neexistujúci súbor alebo adresár
+$ ESRCH
+3 Proces neexistuje
+$ EINTR
+4 Systémové volanie preru¹ené
+$ EIO
+5 Chyba vstupu/výstupu
+$ ENXIO
+6 Zariadenie nie je nakonfigurované
+$ E2BIG
+7 Príli¹ dlhý zoznam argumentov
+$ ENOEXEC
+8 Chybný formát spusteného súboru
+$ EBADF
+9 Chybný deskriptor súboru
+$ ECHILD
+10 Neexistuje ¾iaden potomok procesu
+$ EDEADLK
+11 Bolo zabránené zablokovaniu prostriedku
+$ ENOMEM
+12 Nie je mo¾né prideli» pamä»
+$ EACCES
+13 Prístup odmietnutý
+$ EFAULT
+14 Chybná adresa
+$ ENOTBLK
+15 Vy¾adované blokové zariadenie
+$ EBUSY
+16 Zariadenie je pou¾ívané
+$ EEXIST
+17 Súbor existuje
+$ EXDEV
+18 Odkaz medzi zariadeniami
+$ ENODEV
+19 Operácia nie je zariadením podporovaná
+$ ENOTDIR
+20 Nie je adresár
+$ EISDIR
+21 Je adresár
+$ EINVAL
+22 Chybný argument
+$ ENFILE
+23 Priveµa otvorených súborov v systéme
+$ EMFILE
+24 Priveµa otvorených súborov
+$ ENOTTY
+25 Nevhodné ioctl pre dané zariadenie
+$ ETXTBSY
+26 Textový súbor je pou¾ívaný
+$ EFBIG
+27 Súbor je príli¹ veµký
+$ ENOSPC
+28 Na zariadení nie je voµné miesto
+$ ESPIPE
+29 Neprípustné nastavenie pozície
+$ EROFS
+30 Súborový systém je len na èítanie
+$ EMLINK
+31 Priveµa odkazov
+$ EPIPE
+32 Preru¹ená rúra
+$ EDOM
+33 Èíselný argument mimo definièný obor
+$ ERANGE
+34 Výsledok príli¹ veµký alebo príli¹ malý
+$ EAGAIN, EWOULDBLOCK
+35 Zdroj je doèasne nedostupný
+$ EINPROGRESS
+36 Operácia práve prebieha
+$ EALREADY
+37 Operácia u¾ prebieha
+$ ENOTSOCK
+38 Socketová operácia na objekte, ktorý nie je socket
+$ EDESTADDRREQ
+39 Vy¾adovaná cieµová adresa
+$ EMSGSIZE
+40 Príli¹ dlhá správa
+$ EPROTOTYPE
+41 Protokol nie je socketom podporovaný
+$ ENOPROTOOPT
+42 Protokol nie je k dispozícii
+$ EPROTONOSUPPORT
+43 Protokol nie je podporovaný
+$ ESOCKTNOSUPPORT
+44 Typ socketu nie je podporovaný
+$ EOPNOTSUPP
+45 Operácia nie je podporovaná
+$ EPFNOSUPPORT
+46 Rodina protokolov nie je podporovaná
+$ EAFNOSUPPORT
+47 Rodina adries nie je podporovaná rodinou protokolov
+$ EADDRINUSE
+48 Adresa je u¾ pou¾ívaná
+$ EADDRNOTAVAIL
+49 Nie je mo¾né prideli» po¾adovanú adresu
+$ ENETDOWN
+50 Sie» je nefunkèná
+$ ENETUNREACH
+51 Sie» je nedostupná
+$ ENETRESET
+52 Sie» zru¹ila spojenie po resete
+$ ECONNABORTED
+53 Program spôsobil ukonèenie spojenia
+$ ECONNRESET
+54 Spojenie zru¹ené druhou stranou
+$ ENOBUFS
+55 Vyrovnávacia pamä» nie je k dispozícii
+$ EISCONN
+56 Socket je u¾ pripojený
+$ ENOTCONN
+57 Socket nie je pripojený
+$ ESHUTDOWN
+58 Nie je mo¾né posiela» po uzavretí socketu
+$ ETOOMANYREFS
+59 Príli¹ mnoho odkazov: nie je mo¾né spoji»
+$ ETIMEDOUT
+60 Èasový limit pre spojenie vypr¹al
+$ ECONNREFUSED
+61 Spojenie odmietnuté
+$ ELOOP
+62 Priveµa úrovní symbolických odkazov
+$ ENAMETOOLONG
+63 Meno súboru príli¹ dlhé
+$ EHOSTDOWN
+64 Vzdialený uzol je odpojený
+$ EHOSTUNREACH
+65 Neexistuje cesta k vzdialenému uzlu
+$ ENOTEMPTY
+66 Adresár nie je prázdny
+$ EPROCLIM
+67 Priveµa procesov
+$ EUSERS
+68 Priveµa pou¾ívateµov
+$ EDQUOT
+69 Disková kvóta prekroèená
+$ ESTALE
+70 Zastaralý NFS súborový ukazateµ
+$ EREMOTE
+71 Priveµa úrovní vzdialeného v ceste
+$ EBADRPC
+72 RPC ¹truktúra je chybná
+$ ERPCMISMATCH
+73 Chybná verzia RPC
+$ EPROGUNAVAIL
+74 RPC program nie je k dispozícii
+$ EPROGMISMATCH
+75 Chybná verzia RPC programu
+$ EPROCUNAVAIL
+76 Chybná RPC procedúra pre program
+$ ENOLCK
+77 Zámky nie sú k dispozícii
+$ ENOSYS
+78 Funkcia nie je implementovaná
+$ EFTYPE
+79 Nevhodný typ alebo formát súboru
+$ EAUTH
+80 Overenie práv neúspe¹né
+$ ENEEDAUTH
+81 Vy¾adovaný overovací objekt
+$ EIDRM
+82 Identifikátor odstránený
+$ ENOMSG
+83 Neexistuje správa ¾elaného typu
+$ EOVERFLOW
+84 Hodnota je pre daný dátový typ priveµká
+$ EILSEQ
+85 Neprípustná postupnos» bajtov
+$ ENOTSUP
+86 Nie je podporované
+$ ECANCELED
+87 Operácia zru¹ená
+$ EBADMSG
+88 Chybná alebo poru¹ená správa
+$ ENODATA
+89 ®iadna správa nie je k dispozícii
+$ ENOSR
+90 ®iadne STREAM zdroje
+$ ENOSTR
+91 Nie je STREAM
+$ ETIME
+92 Èasový limit pre STREAM ioctl vypr¹al
+$ ENOATTR
+93 Atribút nenájdený
+$ EMULTIHOP
+94 Pokus o spojenie cez viacero uzlov
+$ ENOLINK
+95 Odkaz bol pretrhnutý
+$ EPROTO
+96 Chyba protokolu
+$
+$ strsignal() support catalog
+$
+$set 2
+$ SIGHUP
+1 Terminál odpojený
+$ SIGINT
+2 Preru¹enie
+$ SIGQUIT
+3 Koniec
+$ SIGILL
+4 Chybná in¹trukcia
+$ SIGTRAP
+5 Trasovacia/ladiaca in¹trukcia
+$ SIGABRT
+6 Násilné ukonèenie
+$ SIGEMT
+7 Emulovaná in¹trukcia
+$ SIGFPE
+8 Výnimka pohyblivej rádovej èiarky
+$ SIGKILL
+9 Zabité
+$ SIGBUS
+10 Chyba na zbernici
+$ SIGSEGV
+11 Chyba segmentácie
+$ SIGSYS
+12 Chybné systémové volanie
+$ SIGPIPE
+13 Preru¹ená rúra
+$ SIGALRM
+14 Budík
+$ SIGTERM
+15 Ukonèené
+$ SIGURG
+16 Naliehavý vstupný/výstupný stav
+$ SIGSTOP
+17 Pozastavené (signál)
+$ SIGTSTP
+18 Pozastavené
+$ SIGCONT
+19 Pokraèovanie
+$ SIGCHLD
+20 Potomok procesu ukonèený
+$ SIGTTIN
+21 Pozastavené (terminálový vstup)
+$ SIGTTOU
+22 Pozastavené (terminálový výstup)
+$ SIGIO
+23 Vstup/výstup mo¾ný
+$ SIGXCPU
+24 Prekroèený èasový limit pre procesor
+$ SIGXFSZ
+25 Prekroèený limit veµkosti súboru
+$ SIGVTALRM
+26 Vypr¹al virtuálny èasovaè
+$ SIGPROF
+27 Vypr¹al profilovací èasovaè
+$ SIGWINCH
+28 Veµkos» okna zmenená
+$ SIGINFO
+29 ®iados» o informáciu
+$ SIGUSR1
+30 Pou¾ívateµom definovaný signál 1
+$ SIGUSR2
+31 Pou¾ívateµom definovaný signál 2
+$ SIGPWR
+32 Zlyhanie/opakované spustenie napájania
diff --git a/lib/libc/nls/sv_SE.ISO8859-1.msg b/lib/libc/nls/sv_SE.ISO8859-1.msg
new file mode 100644
index 000000000000..13cdd23f87f7
--- /dev/null
+++ b/lib/libc/nls/sv_SE.ISO8859-1.msg
@@ -0,0 +1,233 @@
+$ $FreeBSD$
+$
+$ Message catalog for sv_SE.ISO8859-1 locale
+$
+$ strerror() support catalog
+$
+$set 1
+$ EPERM
+1 Otillåten operation
+$ ENOENT
+2 Filen eller katalogen finns ej
+$ ESRCH
+3 Denna process finns ej
+$ EINTR
+4 Avbrutet systemanrop
+$ EIO
+5 In-/utmatningsfel
+$ ENXIO
+6 Enheten är ej konfigurerad
+$ E2BIG
+7 Argumentlistan är för lång
+$ ENOEXEC
+8 Ej körbar fil
+$ EBADF
+9 Felaktigt filhandtag
+$ ECHILD
+10 Inga barnprocesser
+$ EDEADLK
+11 Undvek resursdödläge
+$ ENOMEM
+12 Kan ej erhålla minne
+$ EACCES
+13 Tillstånd nekas
+$ EFAULT
+14 Felaktig adress
+$ ENOTBLK
+15 Blockenhet krävs
+$ EBUSY
+16 Enheten är upptagen
+$ EEXIST
+17 Filen finns redan
+$ EXDEV
+18 Länken korsar enheter
+$ ENODEV
+19 Enheten stöder ej operationen
+$ ENOTDIR
+20 Är ej en katalog
+$ EISDIR
+21 Är en katalog
+$ EINVAL
+22 Ogiltigt argument
+$ ENFILE
+23 För många öppna filer i systemet
+$ EMFILE
+24 För många öppna filer
+$ ENOTTY
+25 Olämplig ioctl för enheten
+$ ETXTBSY
+26 Programfilen är upptagen
+$ EFBIG
+27 Filen är för stor
+$ ENOSPC
+28 Inget utrymme kvar på enheten
+$ ESPIPE
+29 Otillåten sökning
+$ EROFS
+30 Skrivskyddat filsystem
+$ EMLINK
+31 För många länkar
+$ EPIPE
+32 Avbruten kommunikationskanal
+$ EDOM
+33 Numeriskt argument utanför domänen
+$ ERANGE
+34 Resultatet är för stort
+$ EAGAIN, EWOULDBLOCK
+35 Resursen är tillfälligt otillgänglig
+$ EINPROGRESS
+36 Operationen är igång
+$ EALREADY
+37 Operationen är redan igång
+$ ENOTSOCK
+38 Sockeloperation på icke-sockel
+$ EDESTADDRREQ
+39 Destinationsadress erfordras
+$ EMSGSIZE
+40 För långt meddelande
+$ EPROTOTYPE
+41 Fel protokolltyp för sockeln
+$ ENOPROTOOPT
+42 Protokollet otillgängligt
+$ EPROTONOSUPPORT
+43 Protokollet är ej understött
+$ ESOCKTNOSUPPORT
+44 Sockeltypen är ej understödd
+$ EOPNOTSUPP
+45 Operationen är ej understödd
+$ EPFNOSUPPORT
+46 Protokollfamiljen är ej understödd
+$ EAFNOSUPPORT
+47 Adressfamiljen är ej understödd av protokollfamiljen
+$ EADDRINUSE
+48 Adressen är upptagen
+$ EADDRNOTAVAIL
+49 Kan ej tilldela den begärda adressen
+$ ENETDOWN
+50 Nätverket fungerar inte
+$ ENETUNREACH
+51 Nätverket är ej kontaktbart
+$ ENETRESET
+52 Nätverket tappade kontakten vid återställningen
+$ ECONNABORTED
+53 Mjukvara orsakade nedkoppling
+$ ECONNRESET
+54 Motparten avbröt uppkopplingen
+$ ENOBUFS
+55 Inget buffertutrymme tillgängligt
+$ EISCONN
+56 Sockeln är redan uppkopplad
+$ ENOTCONN
+57 Sockeln är ej uppkopplad
+$ ESHUTDOWN
+58 Kan ej sända efter att sockeln nedkopplats
+$ ETOOMANYREFS
+59 För många referenser: kan inte delas
+$ ETIMEDOUT
+60 Uppkopplingstiden tog slut
+$ ECONNREFUSED
+61 Uppkopplingen nekad
+$ ELOOP
+62 För många nivåer av symboliska länkar
+$ ENAMETOOLONG
+63 Alldeles för långt filnamn
+$ EHOSTDOWN
+64 Värddatorn är nere
+$ EHOSTUNREACH
+65 Väg till värddatorn saknas
+$ ENOTEMPTY
+66 Katalogen ej tom
+$ EPROCLIM
+67 För många processer
+$ EUSERS
+68 För många användare
+$ EDQUOT
+69 Diskkvot överskriden
+$ ESTALE
+70 Inaktuellt NFS-filhandtag
+$ EREMOTE
+71 För många fjärrnivåer i sökvägen
+$ EBADRPC
+72 Felaktig RPC-struktur
+$ ERPCMISMATCH
+73 Felaktig RPC-version
+$ EPROGUNAVAIL
+74 RPC-programmet otillgängligt
+$ EPROGMISMATCH
+75 Fel programversion
+$ EPROCUNAVAIL
+76 Felaktig procedur för programmet
+$ ENOLCK
+77 Inga lås tillgängliga
+$ ENOSYS
+78 Funktionen är ej implementerad
+$ EFTYPE
+79 Olämplig filtyp eller format
+$
+$ strsignal() support catalog
+$
+$set 2
+$ SIGHUP
+1 Lägg på
+$ SIGINT
+2 Avbryt
+$ SIGQUIT
+3 Avsluta
+$ SIGILL
+4 Olaglig instruktion
+$ SIGTRAP
+5 Spår- eller brytpunktsfälla
+$ SIGABRT
+6 Avslutsfälla
+$ SIGEMT
+7 Emuleringsfälla
+$ SIGFPE
+8 Flyttalsavbrott
+$ SIGKILL
+9 Dräpt
+$ SIGBUS
+10 Bussfel
+$ SIGSEGV
+11 Segmentfel
+$ SIGSYS
+12 Felaktigt systemanrop
+$ SIGPIPE
+13 Avbruten kommunikationskanal
+$ SIGALRM
+14 Äggklocka
+$ SIGTERM
+15 Terminerad
+$ SIGURG
+16 Brådskande In/Ut-tillstånd
+$ SIGSTOP
+17 Stoppad (signal)
+$ SIGTSTP
+18 Stoppad
+$ SIGCONT
+19 Fortsätter
+$ SIGCHLD
+20 Barn avslutat
+$ SIGTTIN
+21 Stoppad (terminalinmatning)
+$ SIGTTOU
+22 Stoppad (terminalutmatning)
+$ SIGIO
+23 In- och utmatning möjlig
+$ SIGXCPU
+24 Cputidsgränsen överskriden
+$ SIGXFSZ
+25 Filstorleksgränsen överskriden
+$ SIGVTALRM
+26 Virtuella äggklockan ringde
+$ SIGPROF
+27 Profileringsäggklockan ringde
+$ SIGWINCH
+28 Fönsterstorleken ändras
+$ SIGINFO
+29 Informationsförfrågan
+$ SIGUSR1
+30 Användardefinierad signal 1
+$ SIGUSR2
+31 Användardefinierad signal 2
+$ SIGPWR
+32 Kraftbortfall/omstart
diff --git a/lib/libc/nls/uk_UA.UTF-8.msg b/lib/libc/nls/uk_UA.UTF-8.msg
new file mode 100644
index 000000000000..af871d942766
--- /dev/null
+++ b/lib/libc/nls/uk_UA.UTF-8.msg
@@ -0,0 +1,259 @@
+$ $FreeBSD$
+$
+$ Message catalog for uk_UA.UTF-8 locale
+$
+$ strerror() support catalog
+$
+$set 1
+$ EPERM
+1 ÐžÐ¿ÐµÑ€Ð°Ñ†Ñ–Ñ Ð½Ðµ дозволена
+$ ENOENT
+2 Ðемає такого файлу або каталогу
+$ ESRCH
+3 Ðемає такого процеÑу
+$ EINTR
+4 Перервано виклик функції
+$ EIO
+5 Помилка вводу-виводу
+$ ENXIO
+6 Ðемає такого приÑтрою або адреÑи
+$ E2BIG
+7 Перелік аргументів надто довгий
+$ ENOEXEC
+8 Помилка формату виконуваного файлу
+$ EBADF
+9 Ðевірний деÑкриптор файлу
+$ ECHILD
+10 Ðемає дочірнього процеÑу
+$ EDEADLK
+11 Уникнуто взаємне Ð±Ð»Ð¾ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ñ€ÐµÑурÑів
+$ ENOMEM
+12 Ðе доÑтатньо пам'ÑÑ‚Ñ–
+$ EACCES
+13 Відмова у доÑтупі
+$ EFAULT
+14 Ðевірна адреÑа
+$ ENOTBLK
+15 Потрібен блочний приÑтрій
+$ EBUSY
+16 РеÑÑƒÑ€Ñ Ð·Ð°Ð¹Ð½Ñтий
+$ EEXIST
+17 Файл вже Ñ–Ñнує
+$ EXDEV
+18 ПоÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð·Ð° межі приÑтрою
+$ ENODEV
+19 Ðемає такого приÑтрою
+$ ENOTDIR
+20 Це не каталог
+$ EISDIR
+21 Це каталог
+$ EINVAL
+22 Ðедозволений аргумент
+$ ENFILE
+23 Забагато відкритих файлів у ÑиÑтемі
+$ EMFILE
+24 Забагато відкритих файлів
+$ ENOTTY
+25 Це не термінал
+$ ETXTBSY
+26 ТекÑтовий файл зайнÑтий
+$ EFBIG
+27 Файл надто великий
+$ ENOSPC
+28 Ðе залишилоÑÑŒ міÑÑ†Ñ Ð½Ð° приÑтрої
+$ ESPIPE
+29 Ðедозволене позиціонуваннÑ
+$ EROFS
+30 Файлова ÑиÑтема лише Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ
+$ EMLINK
+31 Забагато поÑилань
+$ EPIPE
+32 Канал зруйновано
+$ EDOM
+33 Помилка облаÑÑ‚Ñ– визначеннÑ
+$ ERANGE
+34 Результат надто великий
+$ EAGAIN, EWOULDBLOCK
+35 РеÑÑƒÑ€Ñ Ñ‚Ð¸Ð¼Ñ‡Ð°Ñово не доÑтупний
+$ EINPROGRESS
+36 ÐžÐ¿ÐµÑ€Ð°Ñ†Ñ–Ñ Ñƒ процеÑÑ– виконаннÑ
+$ EALREADY
+37 ÐžÐ¿ÐµÑ€Ð°Ñ†Ñ–Ñ Ð²Ð¶Ðµ виконуєтьÑÑ
+$ ENOTSOCK
+38 Це не Ñокет
+$ EDESTADDRREQ
+39 Ðеобхідна адреÑа призначеннÑ
+$ EMSGSIZE
+40 ÐŸÐ¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð½Ð°Ð´Ñ‚Ð¾ довге
+$ EPROTOTYPE
+41 Помилковий тип протоколу Ð´Ð»Ñ Ñокету
+$ ENOPROTOOPT
+42 Ðемає такого протоколу
+$ EPROTONOSUPPORT
+43 Протокол не підтримуєтьÑÑ
+$ ESOCKTNOSUPPORT
+44 Цей тип Ñокету не підтримуєтьÑÑ
+$ EOPNOTSUPP
+45 ÐžÐ¿ÐµÑ€Ð°Ñ†Ñ–Ñ Ð½Ðµ підтримуєтьÑÑ
+$ EPFNOSUPPORT
+46 Родина протоколів не підтримуєтьÑÑ
+$ EAFNOSUPPORT
+47 Родина Ð°Ð´Ñ€ÐµÑ Ð½Ðµ підтримуєтьÑÑ Ð¿Ñ€Ð¾Ñ‚Ð¾ÐºÐ¾Ð»Ð¾Ð¼
+$ EADDRINUSE
+48 ÐдреÑа вже викориÑтовуєтьÑÑ
+$ EADDRNOTAVAIL
+49 ÐдреÑа недоÑÑжна
+$ ENETDOWN
+50 Мережа не працює
+$ ENETUNREACH
+51 Мережа недоÑÑжна
+$ ENETRESET
+52 З'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¸Ð¿Ð¸Ð½ÐµÐ½Ð¾ мережею
+$ ECONNABORTED
+53 З'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¸Ð¿Ð¸Ð½ÐµÐ½Ð¾
+$ ECONNRESET
+54 З'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¸Ð¿Ð¸Ð½ÐµÐ½Ð¾ протилежною Ñтороною
+$ ENOBUFS
+55 Ðемає вільних буферів
+$ EISCONN
+56 Сокет вже під'єднано
+$ ENOTCONN
+57 Сокет не під'єднано
+$ ESHUTDOWN
+58 Ðе можу відіÑлати піÑÐ»Ñ Ð·Ð°ÐºÑ€Ð¸Ñ‚Ñ‚Ñ Ñокету протилежною Ñтороною
+$ ETOOMANYREFS
+59 Забагато поÑилань: не можу з'єднати
+$ ETIMEDOUT
+60 Вийшов ліміт чаÑу Ð´Ð»Ñ Ð·'єднаннÑ
+$ ECONNREFUSED
+61 Відмова у з'єднанні
+$ ELOOP
+62 Забагато рівнів Ñимволічних поÑилань
+$ ENAMETOOLONG
+63 Ім'Ñ Ñ„Ð°Ð¹Ð»Ñƒ надто довге
+$ EHOSTDOWN
+64 ХоÑÑ‚ не працює
+$ EHOSTUNREACH
+65 ХоÑÑ‚ недоÑÑжний
+$ ENOTEMPTY
+66 Каталог не порожній
+$ EPROCLIM
+67 Забагато процеÑів
+$ EUSERS
+68 Забагато кориÑтувачів
+$ EDQUOT
+69 Перевищена диÑкова квота
+$ ESTALE
+70 ЗаÑтарілий деÑкриптор файлу NFS
+$ EREMOTE
+71 Віддалений об'єкт
+$ EBADRPC
+72 Погана Ñтруктура RPC
+$ ERPCMISMATCH
+73 Ðевірна верÑÑ–Ñ RPC
+$ EPROGUNAVAIL
+74 Програма RPC недоÑÑжна
+$ EPROGMISMATCH
+75 Ðевірна верÑÑ–Ñ Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð¸
+$ EPROCUNAVAIL
+76 Погана процедура Ð´Ð»Ñ Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð¸
+$ ENOLCK
+77 Ð‘Ð»Ð¾ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ð½Ðµ доÑтупне
+$ ENOSYS
+78 Функцію не реалізовано
+$ EFTYPE
+79 Ðепридатний тип чи формат файлу
+$ EAUTH
+80 Помилка аутентифікації
+$ ENEEDAUTH
+81 Потрібна аутентифікаціÑ
+$ EIDRM
+82 Ідентифікатор вилучено
+$ ENOMSG
+83 Ðемає Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð±Ð°Ð¶Ð°Ð½Ð¾Ð³Ð¾ типу
+$ EOVERFLOW
+84 Завелике Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ типу даних
+$ ECANCELED
+85 Операцію ÑкаÑовано
+$ EILSEQ
+86 Ðедозволена поÑлідовніÑÑ‚ÑŒ байтів
+$ ENOATTR
+87 Ðтрибут не знайдено
+$ EDOOFUS
+88 Помилка програмуваннÑ
+$ EBADMSG
+89 Поганий формат повідомленнÑ
+$ EMULTIHOP XXX
+90 Спроба мултіхопу
+$ ENOLINK
+91 Мережовий канал розірвано
+$ EPROTO
+92 Помилка протоколу
+$ ENOTCAPABLE
+93 МожливоÑÑ‚Ñ– недоÑтатні
+$
+$ strsignal() support catalog
+$
+$set 2
+$ SIGHUP
+1 ВідключеннÑ
+$ SIGINT
+2 ПерериваннÑ
+$ SIGQUIT
+3 Вихід
+$ SIGILL
+4 ÐеприпуÑтима інÑтрукціÑ
+$ SIGTRAP
+5 ПаÑтка траÑуваннÑ
+$ SIGABRT
+6 Ðварійне завершеннÑ
+$ SIGEMT
+7 ÐŸÐµÑ€ÐµÑ…Ð¾Ð¿Ð»ÐµÐ½Ð½Ñ ÐµÐ¼ÑƒÐ»ÑŒÐ¾Ð²Ð°Ð½Ð¾Ñ— інÑтрукції
+$ SIGFPE
+8 Помилка роботи з плаваючою крапкою
+$ SIGKILL
+9 Вбито
+$ SIGBUS
+10 Помилка шини
+$ SIGSEGV
+11 ÐŸÐ¾Ñ€ÑƒÑˆÐµÐ½Ð½Ñ Ñегментації
+$ SIGSYS
+12 Поганий ÑиÑтемний виклик
+$ SIGPIPE
+13 Канал зруйновано
+$ SIGALRM
+14 Таймер вичерпано
+$ SIGTERM
+15 ЗавершеннÑ
+$ SIGURG
+16 Ðевідкладний Ñтан на Ñокеті
+$ SIGSTOP
+17 Призупинено (Ñигнал)
+$ SIGTSTP
+18 Призупинено
+$ SIGCONT
+19 ÐŸÑ€Ð¾Ð´Ð¾Ð²Ð¶ÐµÐ½Ð½Ñ Ñ€Ð¾Ð±Ð¾Ñ‚Ð¸
+$ SIGCHLD
+20 Зміна ÑтатуÑу дочірнього процеÑу
+$ SIGTTIN
+21 Зупинено (ввід з терміналу)
+$ SIGTTOU
+22 Зупинено (вивід на термінал)
+$ SIGIO
+23 Ввід-вивід можливий
+$ SIGXCPU
+24 Перевищено ліміт процеÑорного чаÑу
+$ SIGXFSZ
+25 Перевищено ліміт макÑимального розміру файла
+$ SIGVTALRM
+26 Віртуальний таймер вичерпано
+$ SIGPROF
+27 Таймер Ð¿Ñ€Ð¾Ñ„Ñ–Ð»ÑŽÐ²Ð°Ð½Ð½Ñ Ð²Ð¸Ñ‡ÐµÑ€Ð¿Ð°Ð½Ð¾
+$ SIGWINCH
+28 Розмір вікна змінено
+$ SIGINFO
+29 Запит інформації
+$ SIGUSR1
+30 Сигнал кориÑтувача 1
+$ SIGUSR2
+31 Сигнал кориÑтувача 2
diff --git a/lib/libc/nls/zh_CN.GB18030.msg b/lib/libc/nls/zh_CN.GB18030.msg
new file mode 100644
index 000000000000..0e35d7e9eb73
--- /dev/null
+++ b/lib/libc/nls/zh_CN.GB18030.msg
@@ -0,0 +1,297 @@
+$ $FreeBSD$
+$
+$ Message catalog for zh_CN.GB18030 locale
+$
+$ Derived from FreeBSD: head/lib/libc/nls/zh_CN.UTF-8.msg 244756 2012-12-28 01:09:30Z delphij
+$
+$ strerror() support catalog
+$
+$set 1
+$ EPERM
+1 ²»ÔÊÐíµÄ²Ù×÷
+$ ENOENT
+2 Îļþ»òĿ¼²»´æÔÚ
+$ ESRCH
+3 ½ø³Ì²»´æÔÚ
+$ EINTR
+4 ϵͳµ÷ÓÃÖÐÖ¹
+$ EIO
+5 ÊäÈë/Êä³ö´íÎó
+$ ENXIO
+6 δÅäÖõÄÉ豸
+$ E2BIG
+7 ²ÎÊý±í¹ý³¤
+$ ENOEXEC
+8 ¿ÉÖ´ÐÐÎļþ¸ñʽ´íÎó
+$ EBADF
+9 ÎļþÃèÊö·ûÎÞЧ
+$ ECHILD
+10 Ö¸¶¨×Ó½ø³Ì²»´æÔÚ
+$ EDEADLK
+11 ´Ë²Ù×÷»áµ¼ÖÂËÀËø
+$ ENOMEM
+12 ÎÞ·¨·ÖÅäÄÚ´æ
+$ EACCES
+13 ¾Ü¾ø·ÃÎÊ
+$ EFAULT
+14 ÎÞЧµØÖ·
+$ ENOTBLK
+15 ¸Ã²Ù×÷ÐèÒª¿éÉ豸
+$ EBUSY
+16 É豸ʹÓÃÖÐ
+$ EEXIST
+17 ÎļþÒÑ´æÔÚ
+$ EXDEV
+18 Á´½Ó¿çÉ豸
+$ ENODEV
+19 É豸²»Ö§³Ö´Ë²Ù×÷
+$ ENOTDIR
+20 ¶ÔÏó·ÇĿ¼
+$ EISDIR
+21 ¶ÔÏóΪĿ¼
+$ EINVAL
+22 ²ÎÊýÎÞЧ
+$ ENFILE
+23 ϵͳ´ò¿ªÎļþ¹ý¶à
+$ EMFILE
+24 ½ø³Ì´ò¿ªÎļþ¹ý¶à
+$ ENOTTY
+25 ÎÞЧÉ豸 ioctl
+$ ETXTBSY
+26 ¿ÉÖ´ÐÐÎļþæ
+$ EFBIG
+27 Îļþ¹ý´ó
+$ ENOSPC
+28 É豸ÎÞ¿ÉÓÿռä
+$ ESPIPE
+29 ²»ÔÊÐíÖ´ÐÐ seek ²Ù×÷
+$ EROFS
+30 Îļþϵͳֻ¶Á
+$ EMLINK
+31 ÎļþÁ´½Ó¹ý¶à
+$ EPIPE
+32 ¹ÜµÀÒÑÖÐÖ¹
+$ EDOM
+33 ÊýÖµ²ÎÊýÔ½½ç
+$ ERANGE
+34 ½á¹û¹ý´ó
+$ EAGAIN, EWOULDBLOCK
+35 ×ÊÔ´ÔÝʱ²»¿ÉÓÃ
+$ EINPROGRESS
+36 ²Ù×÷½øÐÐÖÐ
+$ EALREADY
+37 ²Ù×÷ÒÑ¿ªÊ¼
+$ ENOTSOCK
+38 ³¢ÊÔÔÚ·Ç socket ÉÏÖ´ÐÐ socket ²Ù×÷
+$ EDESTADDRREQ
+39 ÐèҪĿµÄµØÖ·
+$ EMSGSIZE
+40 ÏûÏ¢¹ý³¤
+$ EPROTOTYPE
+41 socketЭÒéÀàÐÍ´íÎó
+$ ENOPROTOOPT
+42 ЭÒé²»¿ÉÓÃ
+$ EPROTONOSUPPORT
+43 ²»Ö§³ÖµÄЭÒé
+$ ESOCKTNOSUPPORT
+44 ²»Ö§³ÖµÄ socket ÀàÐÍ
+$ EOPNOTSUPP
+45 ²»Ö§³ÖµÄ²Ù×÷
+$ EPFNOSUPPORT
+46 ²»Ö§³ÖµÄЭÒé×å
+$ EAFNOSUPPORT
+47 ЭÒé×å²»Ö§³ÖµÄµØÖ·×å
+$ EADDRINUSE
+48 µØÖ·Òѱ»Õ¼ÓÃ
+$ EADDRNOTAVAIL
+49 ÎÞ·¨Ö¸¶¨ÇëÇóµÄµØÖ·
+$ ENETDOWN
+50 ÍøÂçÒѹرÕ
+$ ENETUNREACH
+51 ÍøÂç²»¿É´ï
+$ ENETRESET
+52 ¸´Î»µ¼ÖÂÍøÂçÁ¬½Ó¶ªÊ§
+$ ECONNABORTED
+53 Èí¼þµ¼ÖµÄÁ¬½ÓÖÐÖ¹
+$ ECONNRESET
+54 ¶Ô·½¸´Î»ÁËÁ¬½Ó
+$ ENOBUFS
+55 »º³åÇø¿Õ¼ä²»×ã
+$ EISCONN
+56 socket ÒÑÁ¬½Ó
+$ ENOTCONN
+57 socket δÁ¬½Ó
+$ ESHUTDOWN
+58 socket shutdown Ö®ºóÎÞ·¨·¢ËÍÊý¾Ý
+$ ETOOMANYREFS
+59 ÒýÓÃÊý¹ý¶à£ºÎÞ·¨Æ´½Ó
+$ ETIMEDOUT
+60 ²Ù×÷³¬Ê±
+$ ECONNREFUSED
+61 ¾Ü¾øÁ¬½Ó
+$ ELOOP
+62 ·ûºÅÁ´½Ó²ãÊý¹ý¶à
+$ ENAMETOOLONG
+63 ÎļþÃû¹ý³¤
+$ EHOSTDOWN
+64 Ö÷»úÒѹرÕ
+$ EHOSTUNREACH
+65 ûÓе½Ö÷»úµÄ·ÓÉ
+$ ENOTEMPTY
+66 Ŀ¼·Ç¿Õ
+$ EPROCLIM
+67 ½ø³ÌÊý³¬ÏÞ
+$ EUSERS
+68 Óû§Êý³¬ÏÞ
+$ EDQUOT
+69 ´ÅÅÌ¿Õ¼äÅä¶î³¬ÏÞ
+$ ESTALE
+70 NFS Îļþ¾ä±úÒÑʧЧ
+$ EREMOTE
+71 Ô¶³ÌĿ¼²ãÊý¹ý¶à
+$ EBADRPC
+72 RPC ½á¹¹ÎÞЧ
+$ ERPCMISMATCH
+73 RPC °æ±¾´íÎó
+$ EPROGUNAVAIL
+74 RPC ³ÌÐò²»¿ÉÓÃ
+$ EPROGMISMATCH
+75 ³ÌÐò°æ±¾´íÎó
+$ EPROCUNAVAIL
+76 δÌṩµÄÔ¶³Ìº¯Êý
+$ ENOLCK
+77 ²»Ö§³ÖËø
+$ ENOSYS
+78 ¹¦ÄÜδʵÏÖ
+$ EFTYPE
+79 ÎļþÀàÐÍ»ò¸ñʽÎÞЧ
+$ EAUTH
+80 Éí·ÝÎÞЧ
+$ ENEEDAUTH
+81 ÎÞÐÅÈÎƾ¾Ý
+$ EIDRM
+82 ÎÞ±êʶ·û
+$ ENOMSG
+83 ÎÞÏûÏ¢ÀàÐÍ
+$ EOVERFLOW
+84 ÊýÖµÒç³ö
+$ ECANCELED
+85 ²Ù×÷ÒÑÈ¡Ïû
+$ EILSEQ
+86 ÎÞЧ×Ö·ûÐòÁÐ
+$ ENOATTR
+87 ÎÞÀ©Õ¹ÊôÐÔ
+$ EDOOFUS
+88 ³ÌÐòÉè¼Æ´íÎó
+$ EBADMSG
+89 ÎÞЧÏûÏ¢
+$ EMULTIHOP
+90 Multihop attempted
+$ ENOLINK
+91 Link has been severed
+$ EPROTO
+92 ЭÒé´íÎó
+$ ENOTCAPABLE
+93 ȨÄܲ»×ã
+$
+$ strsignal() support catalog
+$
+$set 2
+$ SIGHUP
+1 ÖÕ¶ËÏß·¹Ò¶Ï
+$ SIGINT
+2 ÖжÏ
+$ SIGQUIT
+3 Í˳ö
+$ SIGILL
+4 ÎÞЧָÁî
+$ SIGTRAP
+5 ¸ú×Ù/BPT ÏÝÚå
+$ SIGABRT
+6 ÖÕÖ¹ÏÝÚå
+$ SIGEMT
+7 EMT ÏÝÚå
+$ SIGFPE
+8 ¸¡µãÒì³£
+$ SIGKILL
+9 Ç¿ÖÆÖÕÖ¹½ø³Ì
+$ SIGBUS
+10 ϵͳÄÚ´æ·ÃÎÊÔ½½ç
+$ SIGSEGV
+11 ÄÚ´æ·ÃÎÊÔ½½ç
+$ SIGSYS
+12 ÎÞЧϵͳµ÷ÓÃ
+$ SIGPIPE
+13 д¹ÜµÀʱ¶ÁÈ¡Õß²»´æÔÚ
+$ SIGALRM
+14 ʵʱµ¹¼Æʱµ½ÆÚ
+$ SIGTERM
+15 ÖÕÖ¹
+$ SIGURG
+16 ÐèÁ¢¼´´¦ÀíµÄ I/O ½ô¼±×´¿ö
+$ SIGSTOP
+17 ¹ÒÆð (ÐźÅ)
+$ SIGTSTP
+18 ¹ÒÆð
+$ SIGCONT
+19 ¼ÌÐøÔËÐÐ
+$ SIGCHLD
+20 ×Ó½ø³ÌÖÕÖ¹
+$ SIGTTIN
+21 TTY ÊäÈë×èÈû
+$ SIGTTOU
+22 TTY Êä³ö×èÈû
+$ SIGIO
+23 I/O ¾ÍÐ÷
+$ SIGXCPU
+24 CPU ʹÓÃʱ¼ä¹ý³¤
+$ SIGXFSZ
+25 Îļþ³ß´ç¹ý´ó
+$ SIGVTALRM
+26 ÐéÄâµ¹¼Æʱµ½ÆÚ
+$ SIGPROF
+27 ÆÊÎöµ¹¼Æʱµ½ÆÚ
+$ SIGWINCH
+28 ´°¿Ú³ß´ç±ä»¯
+$ SIGINFO
+29 ÇëÇóÐÅÏ¢
+$ SIGUSR1
+30 Óû§×Ô¶¨ÒåÐźŠ1
+$ SIGUSR2
+31 Óû§×Ô¶¨ÒåÐźŠ2
+$
+$ gai_strerror() support catalog
+$
+$set 3
+$ 1 (obsolete)
+1 Ö÷»úÃûʹÓÃÁ˲»Ö§³ÖµÄµØÖ·ÀàÐÍ
+$ EAI_AGAIN
+2 ÔÝʱÎÞ·¨½âÎöÃû³Æ
+$ EAI_BADFLAGS
+3 ÎÞЧµÄ ai_flags Öµ
+$ EAI_FAIL
+4 ½âÎöÃû³Æʱ³öÏÖÎÞ·¨»Ö¸´µÄ´íÎó
+$ EAI_FAMILY
+5 ²»Ö§³ÖµÄµØÖ·ÐÅÏ¢ÀàÐÍ
+$ EAI_MEMORY
+6 ÄÚ´æ·ÖÅäʧ°Ü
+$ 7 (obsolete)
+7 Ö÷»úÃûÎÞÏà¹ØÁªµÄµØÖ·
+$ EAI_NONAME
+8 δ֪µÄÖ÷»úÃû»ò·þÎñÃû
+$ EAI_SERVICE
+9 Ì×½Ó×ÖÀàÐͲ»Ö§³Ö´Ë·þÎñÃû
+$ EAI_SOCKTYPE
+10 ²»Ö§³ÖµÄÌ×½Ó×ÖÀàÐÍ
+$ EAI_SYSTEM
+11 ϵͳµ÷Ó÷µ»ØÁË errno ´íÎó
+$ EAI_BADHINTS
+12 ÎÞЧÌáʾ²ÎÊý
+$ EAI_PROTOCOL
+13 δ֪ЭÒé
+$ EAI_OVERFLOW
+14 ²ÎÊý»º³åÒç³ö
+$ 0
+32766 ³É¹¦
+$ NL_MSGMAX
+32767 δ֪´íÎó
diff --git a/lib/libc/nls/zh_CN.GB2312.msg b/lib/libc/nls/zh_CN.GB2312.msg
new file mode 100644
index 000000000000..46ebb422ff84
--- /dev/null
+++ b/lib/libc/nls/zh_CN.GB2312.msg
@@ -0,0 +1,297 @@
+$ $FreeBSD$
+$
+$ Message catalog for zh_CN.GB2312 locale
+$
+$ Derived from FreeBSD: head/lib/libc/nls/zh_CN.UTF-8.msg 244756 2012-12-28 01:09:30Z delphij
+$
+$ strerror() support catalog
+$
+$set 1
+$ EPERM
+1 ²»ÔÊÐíµÄ²Ù×÷
+$ ENOENT
+2 Îļþ»òĿ¼²»´æÔÚ
+$ ESRCH
+3 ½ø³Ì²»´æÔÚ
+$ EINTR
+4 ϵͳµ÷ÓÃÖÐÖ¹
+$ EIO
+5 ÊäÈë/Êä³ö´íÎó
+$ ENXIO
+6 δÅäÖõÄÉ豸
+$ E2BIG
+7 ²ÎÊý±í¹ý³¤
+$ ENOEXEC
+8 ¿ÉÖ´ÐÐÎļþ¸ñʽ´íÎó
+$ EBADF
+9 ÎļþÃèÊö·ûÎÞЧ
+$ ECHILD
+10 Ö¸¶¨×Ó½ø³Ì²»´æÔÚ
+$ EDEADLK
+11 ´Ë²Ù×÷»áµ¼ÖÂËÀËø
+$ ENOMEM
+12 ÎÞ·¨·ÖÅäÄÚ´æ
+$ EACCES
+13 ¾Ü¾ø·ÃÎÊ
+$ EFAULT
+14 ÎÞЧµØÖ·
+$ ENOTBLK
+15 ¸Ã²Ù×÷ÐèÒª¿éÉ豸
+$ EBUSY
+16 É豸ʹÓÃÖÐ
+$ EEXIST
+17 ÎļþÒÑ´æÔÚ
+$ EXDEV
+18 Á´½Ó¿çÉ豸
+$ ENODEV
+19 É豸²»Ö§³Ö´Ë²Ù×÷
+$ ENOTDIR
+20 ¶ÔÏó·ÇĿ¼
+$ EISDIR
+21 ¶ÔÏóΪĿ¼
+$ EINVAL
+22 ²ÎÊýÎÞЧ
+$ ENFILE
+23 ϵͳ´ò¿ªÎļþ¹ý¶à
+$ EMFILE
+24 ½ø³Ì´ò¿ªÎļþ¹ý¶à
+$ ENOTTY
+25 ÎÞЧÉ豸 ioctl
+$ ETXTBSY
+26 ¿ÉÖ´ÐÐÎļþæ
+$ EFBIG
+27 Îļþ¹ý´ó
+$ ENOSPC
+28 É豸ÎÞ¿ÉÓÿռä
+$ ESPIPE
+29 ²»ÔÊÐíÖ´ÐÐ seek ²Ù×÷
+$ EROFS
+30 Îļþϵͳֻ¶Á
+$ EMLINK
+31 ÎļþÁ´½Ó¹ý¶à
+$ EPIPE
+32 ¹ÜµÀÒÑÖÐÖ¹
+$ EDOM
+33 ÊýÖµ²ÎÊýÔ½½ç
+$ ERANGE
+34 ½á¹û¹ý´ó
+$ EAGAIN, EWOULDBLOCK
+35 ×ÊÔ´ÔÝʱ²»¿ÉÓÃ
+$ EINPROGRESS
+36 ²Ù×÷½øÐÐÖÐ
+$ EALREADY
+37 ²Ù×÷ÒÑ¿ªÊ¼
+$ ENOTSOCK
+38 ³¢ÊÔÔÚ·Ç socket ÉÏÖ´ÐÐ socket ²Ù×÷
+$ EDESTADDRREQ
+39 ÐèҪĿµÄµØÖ·
+$ EMSGSIZE
+40 ÏûÏ¢¹ý³¤
+$ EPROTOTYPE
+41 socketЭÒéÀàÐÍ´íÎó
+$ ENOPROTOOPT
+42 ЭÒé²»¿ÉÓÃ
+$ EPROTONOSUPPORT
+43 ²»Ö§³ÖµÄЭÒé
+$ ESOCKTNOSUPPORT
+44 ²»Ö§³ÖµÄ socket ÀàÐÍ
+$ EOPNOTSUPP
+45 ²»Ö§³ÖµÄ²Ù×÷
+$ EPFNOSUPPORT
+46 ²»Ö§³ÖµÄЭÒé×å
+$ EAFNOSUPPORT
+47 ЭÒé×å²»Ö§³ÖµÄµØÖ·×å
+$ EADDRINUSE
+48 µØÖ·Òѱ»Õ¼ÓÃ
+$ EADDRNOTAVAIL
+49 ÎÞ·¨Ö¸¶¨ÇëÇóµÄµØÖ·
+$ ENETDOWN
+50 ÍøÂçÒѹرÕ
+$ ENETUNREACH
+51 ÍøÂç²»¿É´ï
+$ ENETRESET
+52 ¸´Î»µ¼ÖÂÍøÂçÁ¬½Ó¶ªÊ§
+$ ECONNABORTED
+53 Èí¼þµ¼ÖµÄÁ¬½ÓÖÐÖ¹
+$ ECONNRESET
+54 ¶Ô·½¸´Î»ÁËÁ¬½Ó
+$ ENOBUFS
+55 »º³åÇø¿Õ¼ä²»×ã
+$ EISCONN
+56 socket ÒÑÁ¬½Ó
+$ ENOTCONN
+57 socket δÁ¬½Ó
+$ ESHUTDOWN
+58 socket shutdown Ö®ºóÎÞ·¨·¢ËÍÊý¾Ý
+$ ETOOMANYREFS
+59 ÒýÓÃÊý¹ý¶à£ºÎÞ·¨Æ´½Ó
+$ ETIMEDOUT
+60 ²Ù×÷³¬Ê±
+$ ECONNREFUSED
+61 ¾Ü¾øÁ¬½Ó
+$ ELOOP
+62 ·ûºÅÁ´½Ó²ãÊý¹ý¶à
+$ ENAMETOOLONG
+63 ÎļþÃû¹ý³¤
+$ EHOSTDOWN
+64 Ö÷»úÒѹرÕ
+$ EHOSTUNREACH
+65 ûÓе½Ö÷»úµÄ·ÓÉ
+$ ENOTEMPTY
+66 Ŀ¼·Ç¿Õ
+$ EPROCLIM
+67 ½ø³ÌÊý³¬ÏÞ
+$ EUSERS
+68 Óû§Êý³¬ÏÞ
+$ EDQUOT
+69 ´ÅÅÌ¿Õ¼äÅä¶î³¬ÏÞ
+$ ESTALE
+70 NFS Îļþ¾ä±úÒÑʧЧ
+$ EREMOTE
+71 Ô¶³ÌĿ¼²ãÊý¹ý¶à
+$ EBADRPC
+72 RPC ½á¹¹ÎÞЧ
+$ ERPCMISMATCH
+73 RPC °æ±¾´íÎó
+$ EPROGUNAVAIL
+74 RPC ³ÌÐò²»¿ÉÓÃ
+$ EPROGMISMATCH
+75 ³ÌÐò°æ±¾´íÎó
+$ EPROCUNAVAIL
+76 δÌṩµÄÔ¶³Ìº¯Êý
+$ ENOLCK
+77 ²»Ö§³ÖËø
+$ ENOSYS
+78 ¹¦ÄÜδʵÏÖ
+$ EFTYPE
+79 ÎļþÀàÐÍ»ò¸ñʽÎÞЧ
+$ EAUTH
+80 Éí·ÝÎÞЧ
+$ ENEEDAUTH
+81 ÎÞÐÅÈÎƾ¾Ý
+$ EIDRM
+82 ÎÞ±êʶ·û
+$ ENOMSG
+83 ÎÞÏûÏ¢ÀàÐÍ
+$ EOVERFLOW
+84 ÊýÖµÒç³ö
+$ ECANCELED
+85 ²Ù×÷ÒÑÈ¡Ïû
+$ EILSEQ
+86 ÎÞЧ×Ö·ûÐòÁÐ
+$ ENOATTR
+87 ÎÞÀ©Õ¹ÊôÐÔ
+$ EDOOFUS
+88 ³ÌÐòÉè¼Æ´íÎó
+$ EBADMSG
+89 ÎÞЧÏûÏ¢
+$ EMULTIHOP
+90 Multihop attempted
+$ ENOLINK
+91 Link has been severed
+$ EPROTO
+92 ЭÒé´íÎó
+$ ENOTCAPABLE
+93 ȨÄܲ»×ã
+$
+$ strsignal() support catalog
+$
+$set 2
+$ SIGHUP
+1 ÖÕ¶ËÏß·¹Ò¶Ï
+$ SIGINT
+2 ÖжÏ
+$ SIGQUIT
+3 Í˳ö
+$ SIGILL
+4 ÎÞЧָÁî
+$ SIGTRAP
+5 ¸ú×Ù/BPT ÏÝÚå
+$ SIGABRT
+6 ÖÕÖ¹ÏÝÚå
+$ SIGEMT
+7 EMT ÏÝÚå
+$ SIGFPE
+8 ¸¡µãÒì³£
+$ SIGKILL
+9 Ç¿ÖÆÖÕÖ¹½ø³Ì
+$ SIGBUS
+10 ϵͳÄÚ´æ·ÃÎÊÔ½½ç
+$ SIGSEGV
+11 ÄÚ´æ·ÃÎÊÔ½½ç
+$ SIGSYS
+12 ÎÞЧϵͳµ÷ÓÃ
+$ SIGPIPE
+13 д¹ÜµÀʱ¶ÁÈ¡Õß²»´æÔÚ
+$ SIGALRM
+14 ʵʱµ¹¼Æʱµ½ÆÚ
+$ SIGTERM
+15 ÖÕÖ¹
+$ SIGURG
+16 ÐèÁ¢¼´´¦ÀíµÄ I/O ½ô¼±×´¿ö
+$ SIGSTOP
+17 ¹ÒÆð (ÐźÅ)
+$ SIGTSTP
+18 ¹ÒÆð
+$ SIGCONT
+19 ¼ÌÐøÔËÐÐ
+$ SIGCHLD
+20 ×Ó½ø³ÌÖÕÖ¹
+$ SIGTTIN
+21 TTY ÊäÈë×èÈû
+$ SIGTTOU
+22 TTY Êä³ö×èÈû
+$ SIGIO
+23 I/O ¾ÍÐ÷
+$ SIGXCPU
+24 CPU ʹÓÃʱ¼ä¹ý³¤
+$ SIGXFSZ
+25 Îļþ³ß´ç¹ý´ó
+$ SIGVTALRM
+26 ÐéÄâµ¹¼Æʱµ½ÆÚ
+$ SIGPROF
+27 ÆÊÎöµ¹¼Æʱµ½ÆÚ
+$ SIGWINCH
+28 ´°¿Ú³ß´ç±ä»¯
+$ SIGINFO
+29 ÇëÇóÐÅÏ¢
+$ SIGUSR1
+30 Óû§×Ô¶¨ÒåÐźŠ1
+$ SIGUSR2
+31 Óû§×Ô¶¨ÒåÐźŠ2
+$
+$ gai_strerror() support catalog
+$
+$set 3
+$ 1 (obsolete)
+1 Ö÷»úÃûʹÓÃÁ˲»Ö§³ÖµÄµØÖ·ÀàÐÍ
+$ EAI_AGAIN
+2 ÔÝʱÎÞ·¨½âÎöÃû³Æ
+$ EAI_BADFLAGS
+3 ÎÞЧµÄ ai_flags Öµ
+$ EAI_FAIL
+4 ½âÎöÃû³Æʱ³öÏÖÎÞ·¨»Ö¸´µÄ´íÎó
+$ EAI_FAMILY
+5 ²»Ö§³ÖµÄµØÖ·ÐÅÏ¢ÀàÐÍ
+$ EAI_MEMORY
+6 ÄÚ´æ·ÖÅäʧ°Ü
+$ 7 (obsolete)
+7 Ö÷»úÃûÎÞÏà¹ØÁªµÄµØÖ·
+$ EAI_NONAME
+8 δ֪µÄÖ÷»úÃû»ò·þÎñÃû
+$ EAI_SERVICE
+9 Ì×½Ó×ÖÀàÐͲ»Ö§³Ö´Ë·þÎñÃû
+$ EAI_SOCKTYPE
+10 ²»Ö§³ÖµÄÌ×½Ó×ÖÀàÐÍ
+$ EAI_SYSTEM
+11 ϵͳµ÷Ó÷µ»ØÁË errno ´íÎó
+$ EAI_BADHINTS
+12 ÎÞЧÌáʾ²ÎÊý
+$ EAI_PROTOCOL
+13 δ֪ЭÒé
+$ EAI_OVERFLOW
+14 ²ÎÊý»º³åÒç³ö
+$ 0
+32766 ³É¹¦
+$ NL_MSGMAX
+32767 δ֪´íÎó
diff --git a/lib/libc/nls/zh_CN.UTF-8.msg b/lib/libc/nls/zh_CN.UTF-8.msg
new file mode 100644
index 000000000000..9475ea8e82da
--- /dev/null
+++ b/lib/libc/nls/zh_CN.UTF-8.msg
@@ -0,0 +1,295 @@
+$ $FreeBSD$
+$
+$ Message catalog for zh_CN.UTF-8 locale
+$
+$ strerror() support catalog
+$
+$set 1
+$ EPERM
+1 ä¸å…许的æ“作
+$ ENOENT
+2 文件或目录ä¸å­˜åœ¨
+$ ESRCH
+3 进程ä¸å­˜åœ¨
+$ EINTR
+4 系统调用中止
+$ EIO
+5 输入/输出错误
+$ ENXIO
+6 未é…置的设备
+$ E2BIG
+7 å‚数表过长
+$ ENOEXEC
+8 å¯æ‰§è¡Œæ–‡ä»¶æ ¼å¼é”™è¯¯
+$ EBADF
+9 文件æ述符无效
+$ ECHILD
+10 指定å­è¿›ç¨‹ä¸å­˜åœ¨
+$ EDEADLK
+11 æ­¤æ“作会导致死é”
+$ ENOMEM
+12 无法分é…内存
+$ EACCES
+13 æ‹’ç»è®¿é—®
+$ EFAULT
+14 无效地å€
+$ ENOTBLK
+15 该æ“作需è¦å—设备
+$ EBUSY
+16 设备使用中
+$ EEXIST
+17 文件已存在
+$ EXDEV
+18 链接跨设备
+$ ENODEV
+19 设备ä¸æ”¯æŒæ­¤æ“作
+$ ENOTDIR
+20 对象éžç›®å½•
+$ EISDIR
+21 对象为目录
+$ EINVAL
+22 å‚数无效
+$ ENFILE
+23 系统打开文件过多
+$ EMFILE
+24 进程打开文件过多
+$ ENOTTY
+25 无效设备 ioctl
+$ ETXTBSY
+26 å¯æ‰§è¡Œæ–‡ä»¶å¿™
+$ EFBIG
+27 文件过大
+$ ENOSPC
+28 设备无å¯ç”¨ç©ºé—´
+$ ESPIPE
+29 ä¸å…许执行 seek æ“作
+$ EROFS
+30 文件系统åªè¯»
+$ EMLINK
+31 文件链接过多
+$ EPIPE
+32 管é“已中止
+$ EDOM
+33 数值å‚数越界
+$ ERANGE
+34 结果过大
+$ EAGAIN, EWOULDBLOCK
+35 资æºæš‚æ—¶ä¸å¯ç”¨
+$ EINPROGRESS
+36 æ“作进行中
+$ EALREADY
+37 æ“作已开始
+$ ENOTSOCK
+38 å°è¯•åœ¨éž socket 上执行 socket æ“作
+$ EDESTADDRREQ
+39 需è¦ç›®çš„地å€
+$ EMSGSIZE
+40 消æ¯è¿‡é•¿
+$ EPROTOTYPE
+41 socketå议类型错误
+$ ENOPROTOOPT
+42 åè®®ä¸å¯ç”¨
+$ EPROTONOSUPPORT
+43 ä¸æ”¯æŒçš„åè®®
+$ ESOCKTNOSUPPORT
+44 ä¸æ”¯æŒçš„ socket 类型
+$ EOPNOTSUPP
+45 ä¸æ”¯æŒçš„æ“作
+$ EPFNOSUPPORT
+46 ä¸æ”¯æŒçš„åè®®æ—
+$ EAFNOSUPPORT
+47 åè®®æ—ä¸æ”¯æŒçš„地å€æ—
+$ EADDRINUSE
+48 地å€å·²è¢«å ç”¨
+$ EADDRNOTAVAIL
+49 无法指定请求的地å€
+$ ENETDOWN
+50 网络已关闭
+$ ENETUNREACH
+51 网络ä¸å¯è¾¾
+$ ENETRESET
+52 å¤ä½å¯¼è‡´ç½‘络连接丢失
+$ ECONNABORTED
+53 软件导致的连接中止
+$ ECONNRESET
+54 对方å¤ä½äº†è¿žæŽ¥
+$ ENOBUFS
+55 缓冲区空间ä¸è¶³
+$ EISCONN
+56 socket 已连接
+$ ENOTCONN
+57 socket 未连接
+$ ESHUTDOWN
+58 socket shutdown 之åŽæ— æ³•å‘é€æ•°æ®
+$ ETOOMANYREFS
+59 引用数过多:无法拼接
+$ ETIMEDOUT
+60 æ“作超时
+$ ECONNREFUSED
+61 æ‹’ç»è¿žæŽ¥
+$ ELOOP
+62 符å·é“¾æŽ¥å±‚数过多
+$ ENAMETOOLONG
+63 文件å过长
+$ EHOSTDOWN
+64 主机已关闭
+$ EHOSTUNREACH
+65 没有到主机的路由
+$ ENOTEMPTY
+66 目录éžç©º
+$ EPROCLIM
+67 进程数超é™
+$ EUSERS
+68 用户数超é™
+$ EDQUOT
+69 ç£ç›˜ç©ºé—´é…é¢è¶…é™
+$ ESTALE
+70 NFS 文件å¥æŸ„已失效
+$ EREMOTE
+71 远程目录层数过多
+$ EBADRPC
+72 RPC 结构无效
+$ ERPCMISMATCH
+73 RPC 版本错误
+$ EPROGUNAVAIL
+74 RPC 程åºä¸å¯ç”¨
+$ EPROGMISMATCH
+75 程åºç‰ˆæœ¬é”™è¯¯
+$ EPROCUNAVAIL
+76 未æ供的远程函数
+$ ENOLCK
+77 ä¸æ”¯æŒé”
+$ ENOSYS
+78 功能未实现
+$ EFTYPE
+79 文件类型或格å¼æ— æ•ˆ
+$ EAUTH
+80 身份无效
+$ ENEEDAUTH
+81 无信任凭æ®
+$ EIDRM
+82 无标识符
+$ ENOMSG
+83 无消æ¯ç±»åž‹
+$ EOVERFLOW
+84 数值溢出
+$ ECANCELED
+85 æ“作已å–消
+$ EILSEQ
+86 无效字符åºåˆ—
+$ ENOATTR
+87 无扩展属性
+$ EDOOFUS
+88 程åºè®¾è®¡é”™è¯¯
+$ EBADMSG
+89 无效消æ¯
+$ EMULTIHOP
+90 Multihop attempted
+$ ENOLINK
+91 Link has been severed
+$ EPROTO
+92 å议错误
+$ ENOTCAPABLE
+93 æƒèƒ½ä¸è¶³
+$
+$ strsignal() support catalog
+$
+$set 2
+$ SIGHUP
+1 终端线路挂断
+$ SIGINT
+2 中断
+$ SIGQUIT
+3 退出
+$ SIGILL
+4 无效指令
+$ SIGTRAP
+5 跟踪/BPT 陷阱
+$ SIGABRT
+6 终止陷阱
+$ SIGEMT
+7 EMT 陷阱
+$ SIGFPE
+8 浮点异常
+$ SIGKILL
+9 强制终止进程
+$ SIGBUS
+10 系统内存访问越界
+$ SIGSEGV
+11 内存访问越界
+$ SIGSYS
+12 无效系统调用
+$ SIGPIPE
+13 写管é“时读å–者ä¸å­˜åœ¨
+$ SIGALRM
+14 实时倒计时到期
+$ SIGTERM
+15 终止
+$ SIGURG
+16 需立å³å¤„ç†çš„ I/O 紧急状况
+$ SIGSTOP
+17 挂起 (ä¿¡å·)
+$ SIGTSTP
+18 挂起
+$ SIGCONT
+19 继续è¿è¡Œ
+$ SIGCHLD
+20 å­è¿›ç¨‹ç»ˆæ­¢
+$ SIGTTIN
+21 TTY 输入阻塞
+$ SIGTTOU
+22 TTY 输出阻塞
+$ SIGIO
+23 I/O 就绪
+$ SIGXCPU
+24 CPU 使用时间过长
+$ SIGXFSZ
+25 文件尺寸过大
+$ SIGVTALRM
+26 虚拟倒计时到期
+$ SIGPROF
+27 剖æžå€’计时到期
+$ SIGWINCH
+28 窗å£å°ºå¯¸å˜åŒ–
+$ SIGINFO
+29 请求信æ¯
+$ SIGUSR1
+30 ç”¨æˆ·è‡ªå®šä¹‰ä¿¡å· 1
+$ SIGUSR2
+31 ç”¨æˆ·è‡ªå®šä¹‰ä¿¡å· 2
+$
+$ gai_strerror() support catalog
+$
+$set 3
+$ 1 (obsolete)
+1 主机å使用了ä¸æ”¯æŒçš„地å€ç±»åž‹
+$ EAI_AGAIN
+2 暂时无法解æžå称
+$ EAI_BADFLAGS
+3 无效的 ai_flags 值
+$ EAI_FAIL
+4 解æžå称时出现无法æ¢å¤çš„错误
+$ EAI_FAMILY
+5 ä¸æ”¯æŒçš„地å€ä¿¡æ¯ç±»åž‹
+$ EAI_MEMORY
+6 内存分é…失败
+$ 7 (obsolete)
+7 主机å无相关è”的地å€
+$ EAI_NONAME
+8 未知的主机å或æœåŠ¡å
+$ EAI_SERVICE
+9 套接字类型ä¸æ”¯æŒæ­¤æœåŠ¡å
+$ EAI_SOCKTYPE
+10 ä¸æ”¯æŒçš„套接字类型
+$ EAI_SYSTEM
+11 系统调用返回了 errno 错误
+$ EAI_BADHINTS
+12 无效æ示å‚æ•°
+$ EAI_PROTOCOL
+13 未知åè®®
+$ EAI_OVERFLOW
+14 å‚数缓冲溢出
+$ 0
+32766 æˆåŠŸ
+$ NL_MSGMAX
+32767 未知错误
diff --git a/lib/libc/posix1e/Makefile.inc b/lib/libc/posix1e/Makefile.inc
new file mode 100644
index 000000000000..151f85068204
--- /dev/null
+++ b/lib/libc/posix1e/Makefile.inc
@@ -0,0 +1,126 @@
+# $FreeBSD$
+
+.PATH: ${LIBC_SRCTOP}/posix1e
+
+CFLAGS+=-D_ACL_PRIVATE
+
+# Copy kern/subr_acl_nfs4.c to the libc object directory.
+subr_acl_nfs4.c: ${SRCTOP}/sys/kern/subr_acl_nfs4.c
+ cat ${.ALLSRC} > ${.TARGET}
+
+SRCS+= acl_branding.c \
+ acl_calc_mask.c \
+ acl_copy.c \
+ acl_delete.c \
+ acl_delete_entry.c \
+ acl_entry.c \
+ acl_flag.c \
+ acl_free.c \
+ acl_from_text.c \
+ acl_from_text_nfs4.c \
+ acl_get.c \
+ acl_id_to_name.c \
+ acl_init.c \
+ acl_perm.c \
+ acl_set.c \
+ acl_strip.c \
+ acl_support.c \
+ acl_support_nfs4.c \
+ acl_to_text.c \
+ acl_to_text_nfs4.c \
+ acl_valid.c \
+ extattr.c \
+ mac.c \
+ mac_exec.c \
+ mac_get.c \
+ mac_set.c \
+ subr_acl_nfs4.c
+.if ${MK_SYMVER} == yes
+SRCS+= acl_compat.c
+.endif
+
+SYM_MAPS+=${LIBC_SRCTOP}/posix1e/Symbol.map
+
+MAN+= acl.3 \
+ acl_add_flag_np.3 \
+ acl_add_perm.3 \
+ acl_calc_mask.3 \
+ acl_clear_flags_np.3 \
+ acl_clear_perms.3 \
+ acl_copy_entry.3 \
+ acl_create_entry.3 \
+ acl_delete.3 \
+ acl_delete_entry.3 \
+ acl_delete_flag_np.3 \
+ acl_delete_perm.3 \
+ acl_dup.3 \
+ acl_free.3 \
+ acl_from_text.3 \
+ acl_get.3 \
+ acl_get_brand_np.3 \
+ acl_get_entry.3 \
+ acl_get_entry_type_np.3 \
+ acl_get_flagset_np.3 \
+ acl_get_flag_np.3 \
+ acl_get_permset.3 \
+ acl_get_perm_np.3 \
+ acl_get_qualifier.3 \
+ acl_get_tag_type.3 \
+ acl_init.3 \
+ acl_is_trivial_np.3 \
+ acl_set.3 \
+ acl_set_entry_type_np.3 \
+ acl_set_flagset_np.3 \
+ acl_set_permset.3 \
+ acl_set_qualifier.3 \
+ acl_set_tag_type.3 \
+ acl_strip_np.3 \
+ acl_to_text.3 \
+ acl_valid.3 \
+ extattr.3 \
+ mac.3 \
+ mac.conf.5 \
+ mac_free.3 \
+ mac_is_present.3 \
+ mac_get.3 \
+ mac_prepare.3 \
+ mac_set.3 \
+ mac_text.3 \
+ posix1e.3
+
+MLINKS+=acl_create_entry.3 acl_create_entry_np.3\
+ acl_delete.3 acl_delete_def_file.3 \
+ acl_delete.3 acl_delete_file_np.3 \
+ acl_delete.3 acl_delete_fd_np.3 \
+ acl_delete_entry.3 acl_delete_entry_np.3\
+ acl_get.3 acl_get_file.3 \
+ acl_get.3 acl_get_fd.3 \
+ acl_get.3 acl_get_fd_np.3 \
+ acl_get.3 acl_get_link_np.3 \
+ acl_set.3 acl_set_file.3 \
+ acl_set.3 acl_set_fd.3 \
+ acl_set.3 acl_set_fd_np.3 \
+ acl_set.3 acl_set_link_np.3 \
+ acl_to_text.3 acl_to_text_np.3 \
+ acl_valid.3 acl_valid_file_np.3 \
+ acl_valid.3 acl_valid_fd_np.3 \
+ extattr.3 extattr_namespace_to_string.3 \
+ extattr.3 extattr_string_to_namespace.3 \
+ mac_get.3 mac_get_fd.3 \
+ mac_get.3 mac_get_file.3 \
+ mac_get.3 mac_get_link.3 \
+ mac_get.3 mac_get_peer.3 \
+ mac_get.3 mac_get_pid.3 \
+ mac_get.3 mac_get_proc.3 \
+ mac_prepare.3 mac_prepare_file_label.3 \
+ mac_prepare.3 mac_prepare_ifnet_label.3 \
+ mac_prepare.3 mac_prepare_process_label.3 \
+ mac_prepare.3 mac_prepare_type.3 \
+ mac_set.3 mac_set_fd.3 \
+ mac_set.3 mac_set_file.3 \
+ mac_set.3 mac_set_link.3 \
+ mac_set.3 mac_set_proc.3 \
+ mac_text.3 mac_from_text.3 \
+ mac_text.3 mac_to_text.3
+
+CLEANFILES+= subr_acl_nfs4.c
diff --git a/lib/libc/posix1e/Symbol.map b/lib/libc/posix1e/Symbol.map
new file mode 100644
index 000000000000..346c8ca7e290
--- /dev/null
+++ b/lib/libc/posix1e/Symbol.map
@@ -0,0 +1,86 @@
+/*
+ * $FreeBSD$
+ */
+
+FBSD_1.0 {
+ acl_calc_mask;
+ acl_copy_entry;
+ acl_copy_ext;
+ acl_copy_int;
+ acl_delete_def_file;
+ acl_delete_def_link_np;
+ acl_delete_file_np;
+ acl_delete_link_np;
+ acl_delete_fd_np;
+ acl_delete_entry;
+ acl_create_entry;
+ acl_get_entry;
+ acl_free;
+ acl_from_text;
+ acl_get_file;
+ acl_get_link_np;
+ acl_get_fd;
+ acl_get_fd_np;
+ acl_get_permset;
+ acl_get_qualifier;
+ acl_get_tag_type;
+ acl_init;
+ acl_dup;
+ acl_clear_perms;
+ acl_set_file;
+ acl_set_link_np;
+ acl_set_fd;
+ acl_set_fd_np;
+ acl_set_permset;
+ acl_set_qualifier;
+ acl_set_tag_type;
+ acl_to_text;
+ acl_valid;
+ acl_valid_file_np;
+ acl_valid_link_np;
+ acl_valid_fd_np;
+ extattr_namespace_to_string;
+ extattr_string_to_namespace;
+ mac_reload;
+ mac_free;
+ mac_from_text;
+ mac_to_text;
+ mac_prepare;
+ mac_prepare_type;
+ mac_prepare_ifnet_label;
+ mac_prepare_file_label;
+ mac_prepare_packet_label;
+ mac_prepare_process_label;
+ mac_is_present;
+ mac_execve;
+ mac_get_fd;
+ mac_get_file;
+ mac_get_link;
+ mac_get_peer;
+ mac_get_pid;
+ mac_get_proc;
+ mac_set_fd;
+ mac_set_file;
+ mac_set_link;
+ mac_set_proc;
+};
+
+FBSD_1.1 {
+ acl_add_flag_np;
+ acl_add_perm;
+ acl_clear_flags_np;
+ acl_create_entry_np;
+ acl_delete_entry_np;
+ acl_delete_flag_np;
+ acl_delete_perm;
+ acl_get_brand_np;
+ acl_get_entry_type_np;
+ acl_get_flag_np;
+ acl_get_flagset_np;
+ acl_get_perm_np;
+ acl_is_trivial_np;
+ acl_set_entry_type_np;
+ acl_set_flagset_np;
+ acl_strip_np;
+ acl_to_text_np;
+};
diff --git a/lib/libc/posix1e/acl.3 b/lib/libc/posix1e/acl.3
new file mode 100644
index 000000000000..2c7ebd63ad4e
--- /dev/null
+++ b/lib/libc/posix1e/acl.3
@@ -0,0 +1,307 @@
+.\"-
+.\" Copyright (c) 2000, 2001, 2002 Robert N. M. Watson
+.\" All rights reserved.
+.\"
+.\" This software was developed by Robert Watson for the TrustedBSD Project.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd October 30, 2014
+.Dt ACL 3
+.Os
+.Sh NAME
+.Nm acl
+.Nd introduction to the POSIX.1e/NFSv4 ACL security API
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Sh DESCRIPTION
+.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.
+.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 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
+POSIX.1e describes a set of ACL manipulation routines to manage the
+contents of ACLs, as well as their relationships with files; almost
+all of these support routines are implemented in
+.Fx .
+.Pp
+Available functions, sorted by behavior, include:
+.Bl -tag -width indent
+.It Fn acl_add_flag_np
+This function is described in
+.Xr acl_add_flag_np 3 ,
+and may be used to add flags to a flagset.
+.It Fn acl_add_perm
+This function is described in
+.Xr acl_add_perm 3 ,
+and may be used to add permissions to a permission set.
+.It Fn acl_calc_mask
+This function is described in
+.Xr acl_calc_mask 3 ,
+and may be used to calculate and set the permissions associated with
+the
+.Dv ACL_MASK
+entry.
+.It Fn acl_clear_flags_np
+This function is described in
+.Xr acl_clear_flags_np 3 ,
+and may be used to clear all flags from a flagset.
+.It Fn acl_clear_perms
+This function is described in
+.Xr acl_clear_perms 3 ,
+and may be used to clear all permissions from a permission set.
+.It Fn acl_copy_entry
+This function is described in
+.Xr acl_copy_entry 3 ,
+and may be used to copy the contents of an ACL entry.
+.It Xo
+.Fn acl_create_entry ,
+.Fn acl_create_entry_np
+.Xc
+These functions are described in
+.Xr acl_create_entry 3 ,
+and may be used to create an empty entry in an ACL.
+.It Xo
+.Fn acl_delete_def_file ,
+.Fn acl_delete_def_link_np ,
+.Fn acl_delete_fd_np ,
+.Fn acl_delete_file_np ,
+.Fn acl_delete_link_np
+.Xc
+These functions are described in
+.Xr acl_delete 3 ,
+and may be used to delete ACLs from file system objects.
+.It Xo
+.Fn acl_delete_entry ,
+.Fn acl_delete_entry_np ,
+.Xc
+This functions are described in
+.Xr acl_delete_entry 3 ,
+and may be used to delete an entry from an ACL.
+.It Fn acl_delete_flag_np
+This function is described in
+.Xr acl_delete_flag_np 3 ,
+and may be used to delete flags from a flagset.
+.It Fn acl_delete_perm
+This function is described in
+.Xr acl_delete_perm 3 ,
+and may be used to delete permissions from a permset.
+.It Fn acl_dup
+This function is described in
+.Xr acl_dup 3 ,
+and may be used to duplicate an ACL structure.
+.It Fn acl_free
+This function is described in
+.Xr acl_free 3 ,
+and may be used to free userland working ACL storage.
+.It Fn acl_from_text
+This function is described in
+.Xr acl_from_text 3 ,
+and may be used to convert a text-form ACL into working ACL state, if
+the ACL has POSIX.1e or NFSv4 semantics.
+.It Fn acl_get_brand_np
+This function is described in
+.Xr acl_get_brand_np 3
+and may be used to determine whether the ACL has POSIX.1e or NFSv4 semantics.
+.It Fn acl_get_entry
+This function is described in
+.Xr acl_get_entry 3 ,
+and may be used to retrieve a designated ACL entry from an ACL.
+.It Xo
+.Fn acl_get_fd ,
+.Fn acl_get_fd_np ,
+.Fn acl_get_file ,
+.Fn acl_get_link_np
+.Xc
+These functions are described in
+.Xr acl_get 3 ,
+and may be used to retrieve ACLs from file system objects.
+.It Fn acl_get_entry_type_np
+This function is described in
+.Xr acl_get_entry_type_np 3 ,
+and may be used to retrieve an ACL type from an ACL entry.
+.It Fn acl_get_flagset_np
+This function is described in
+.Xr acl_get_flagset_np 3 ,
+and may be used to retrieve a flagset from an ACL entry.
+.It Fn acl_get_permset
+This function is described in
+.Xr acl_get_permset 3 ,
+and may be used to retrieve a permset from an ACL entry.
+.It Fn acl_get_qualifier
+This function is described in
+.Xr acl_get_qualifier 3 ,
+and may be used to retrieve the qualifier from an ACL entry.
+.It Fn acl_get_tag_type
+This function is described in
+.Xr acl_get_tag_type 3 ,
+and may be used to retrieve the tag type from an ACL entry.
+.It Fn acl_init
+This function is described in
+.Xr acl_init 3 ,
+and may be used to allocate a fresh (empty) ACL structure.
+.It Fn acl_is_trivial_np
+This function is described in
+.Xr acl_is_trivial_np 3 ,
+and may be used to find out whether ACL is trivial.
+.It Xo
+.Fn acl_set_fd ,
+.Fn acl_set_fd_np ,
+.Fn acl_set_file ,
+.Fn acl_set_link_np
+.Xc
+These functions are described in
+.Xr acl_set 3 ,
+and may be used to assign an ACL to a file system object.
+.It Fn acl_set_entry_type_np
+This function is described in
+.Xr acl_set_entry_type_np 3 ,
+and may be used to set the ACL type of an ACL entry.
+.It Fn acl_set_flagset_np
+This function is described in
+.Xr acl_set_flagset_np 3 ,
+and may be used to set the flags of an ACL entry from a flagset.
+.It Fn acl_set_permset
+This function is described in
+.Xr acl_set_permset 3 ,
+and may be used to set the permissions of an ACL entry from a permset.
+.It Fn acl_set_qualifier
+This function is described in
+.Xr acl_set_qualifier 3 ,
+and may be used to set the qualifier of an ACL.
+.It Fn acl_set_tag_type
+This function is described in
+.Xr acl_set_tag_type 3 ,
+and may be used to set the tag type of an ACL.
+.It Fn acl_strip_np
+This function is described in
+.Xr acl_strip_np 3 ,
+and may be used to remove extended entries from an ACL.
+.It Xo
+.Fn acl_to_text ,
+.Fn acl_to_text_np
+.Xc
+These functions are described in
+.Xr acl_to_text 3 ,
+and may be used to generate a text-form of a POSIX.1e or NFSv4 semantics ACL.
+.It Xo
+.Fn acl_valid ,
+.Fn acl_valid_fd_np ,
+.Fn acl_valid_file_np ,
+.Fn acl_valid_link_np
+.Xc
+These functions are described in
+.Xr acl_valid 3 ,
+and may be used to validate an ACL as correct POSIX.1e-semantics, or
+as appropriate for a particular file system object regardless of semantics.
+.El
+.Pp
+Documentation of the internal kernel interfaces backing these calls may
+be found in
+.Xr acl 9 .
+The syscalls between the internal interfaces and the public library
+routines may change over time, and as such are not documented.
+They are not intended to be called directly without going through the
+library.
+.Sh SEE ALSO
+.Xr getfacl 1 ,
+.Xr setfacl 1 ,
+.Xr acl_add_flag_np 3 ,
+.Xr acl_add_perm 3 ,
+.Xr acl_calc_mask 3 ,
+.Xr acl_clear_flags_np 3 ,
+.Xr acl_clear_perms 3 ,
+.Xr acl_copy_entry 3 ,
+.Xr acl_create_entry 3 ,
+.Xr acl_delete_entry 3 ,
+.Xr acl_delete_flag_np 3 ,
+.Xr acl_delete_perm 3 ,
+.Xr acl_dup 3 ,
+.Xr acl_free 3 ,
+.Xr acl_from_text 3 ,
+.Xr acl_get 3 ,
+.Xr acl_get_brand_np 3 ,
+.Xr acl_get_entry_type_np 3 ,
+.Xr acl_get_flagset_np 3 ,
+.Xr acl_get_permset 3 ,
+.Xr acl_get_qualifier 3 ,
+.Xr acl_get_tag_type 3 ,
+.Xr acl_init 3 ,
+.Xr acl_is_trivial_np 3 ,
+.Xr acl_set 3 ,
+.Xr acl_set_entry_type_np 3 ,
+.Xr acl_set_flagset_np 3 ,
+.Xr acl_set_permset 3 ,
+.Xr acl_set_qualifier 3 ,
+.Xr acl_set_tag_type 3 ,
+.Xr acl_strip_np 3 ,
+.Xr acl_to_text 3 ,
+.Xr acl_valid 3 ,
+.Xr posix1e 3 ,
+.Xr acl 9
+.Sh STANDARDS
+POSIX.1e assigns security labels to all objects, extending the security
+functionality described in POSIX.1.
+These additional labels provide fine-grained discretionary access control,
+fine-grained capabilities, and labels necessary for mandatory access
+control.
+POSIX.2c describes a set of userland utilities for manipulating these
+labels.
+.Pp
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+Discussion of the draft continues on the cross-platform POSIX.1e
+implementation mailing list.
+To join this list, see the
+.Fx
+POSIX.1e implementation page for more information.
+.Sh HISTORY
+POSIX.1e support was introduced in
+.Fx 4.0 ;
+.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
+and
+.Xr setfacl 1
+utilities describe the user tools that permit direct manipulation of complete
+file ACLs.
+.Sh AUTHORS
+.An Robert N M Watson
diff --git a/lib/libc/posix1e/acl_add_flag_np.3 b/lib/libc/posix1e/acl_add_flag_np.3
new file mode 100644
index 000000000000..22048268706a
--- /dev/null
+++ b/lib/libc/posix1e/acl_add_flag_np.3
@@ -0,0 +1,98 @@
+.\"-
+.\" Copyright (c) 2008, 2009 Edward Tomasz Napierala
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 September 4, 2015
+.Dt ACL_ADD_FLAG_NP 3
+.Os
+.Sh NAME
+.Nm acl_add_flag_np
+.Nd add flags to a flagset
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_add_flag_np "acl_flagset_t flagset_d" "acl_flag_t flag"
+.Sh DESCRIPTION
+The
+.Fn acl_add_flag_np
+function
+is a non-portable call that adds the NFSv4 ACL flags contained in
+.Fa flags
+to the flagset
+.Fa flagset_d .
+.Pp
+Note: it is not considered an error to attempt to add flags
+that already exist in the flagset.
+.Pp
+Valid values are:
+.Bl -column -offset 3n "ACL_ENTRY_NO_PROPAGATE_INHERIT"
+.It ACL_ENTRY_FILE_INHERIT Ta "Will be inherited by files."
+.It ACL_ENTRY_DIRECTORY_INHERIT Ta "Will be inherited by directories."
+.It ACL_ENTRY_NO_PROPAGATE_INHERIT Ta "Will not propagate."
+.It ACL_ENTRY_INHERIT_ONLY Ta "Inherit-only."
+.It ACL_ENTRY_INHERITED Ta "Inherited from parent"
+.El
+.Sh RETURN VALUES
+.Rv -std acl_add_flag_np
+.Sh ERRORS
+The
+.Fn acl_add_flag_np
+function fails if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Fa flagset_d
+is not a valid descriptor for a flagset within an ACL entry.
+Argument
+.Fa flag
+does not contain a valid
+.Vt acl_flag_t
+value.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_clear_flags_np 3 ,
+.Xr acl_delete_flag_np 3 ,
+.Xr acl_get_flagset_np 3 ,
+.Xr acl_set_flagset_np 3 ,
+.Xr posix1e 3
+.Sh STANDARDS
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+.Sh HISTORY
+POSIX.1e support was introduced in
+.Fx 4.0 .
+The
+.Fn acl_add_flag_np
+function was added in
+.Fx 8.0 .
+.Sh AUTHORS
+The
+.Fn acl_add_flag_np
+function was written by
+.An Edward Tomasz Napierala Aq Mt trasz@FreeBSD.org .
diff --git a/lib/libc/posix1e/acl_add_perm.3 b/lib/libc/posix1e/acl_add_perm.3
new file mode 100644
index 000000000000..c59aac8e41fa
--- /dev/null
+++ b/lib/libc/posix1e/acl_add_perm.3
@@ -0,0 +1,129 @@
+.\"-
+.\" Copyright (c) 2001 Chris D. Faulhaber
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd June 25, 2009
+.Dt ACL_ADD_PERM 3
+.Os
+.Sh NAME
+.Nm acl_add_perm
+.Nd add permissions to a permission set
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_add_perm "acl_permset_t permset_d" "acl_perm_t perm"
+.Sh DESCRIPTION
+The
+.Fn acl_add_perm
+function
+is a POSIX.1e call that adds the permission contained in
+.Fa perm
+to the permission set
+.Fa permset_d .
+.Pp
+Note: it is not considered an error to attempt to add permissions
+that already exist in the permission set.
+.Pp
+For POSIX.1e ACLs, valid values are:
+.Bl -column -offset 3n "ACL_WRITE_NAMED_ATTRS"
+.It ACL_EXECUTE Execute permission
+.It ACL_WRITE Write permission
+.It ACL_READ Read permission
+.El
+.Pp
+For NFSv4 ACLs, valid values are:
+.Bl -column -offset 3n "ACL_WRITE_NAMED_ATTRS"
+.It ACL_READ_DATA Ta "Read permission"
+.It ACL_LIST_DIRECTORY Ta "Same as ACL_READ_DATA"
+.It ACL_WRITE_DATA Ta "Write permission, or permission to create files"
+.It ACL_ADD_FILE Ta "Same as ACL_READ_DATA"
+.It ACL_APPEND_DATA Ta "Permission to create directories. Ignored for files"
+.It ACL_ADD_SUBDIRECTORY Ta "Same as ACL_APPEND_DATA"
+.It ACL_READ_NAMED_ATTRS Ta "Ignored"
+.It ACL_WRITE_NAMED_ATTRS Ta "Ignored"
+.It ACL_EXECUTE Ta "Execute permission"
+.It ACL_DELETE_CHILD Ta "Permission to delete files and subdirectories"
+.It ACL_READ_ATTRIBUTES Ta "Permission to read basic attributes"
+.It ACL_WRITE_ATTRIBUTES Ta "Permission to change basic attributes"
+.It ACL_DELETE Ta "Permission to delete the object this ACL is placed on"
+.It ACL_READ_ACL Ta "Permission to read ACL"
+.It ACL_WRITE_ACL Ta "Permission to change the ACL and file mode"
+.It ACL_SYNCHRONIZE Ta "Ignored"
+.El
+.Pp
+Calling
+.Fn acl_add_perm
+with
+.Fa perm
+equal to ACL_WRITE or ACL_READ brands the ACL as POSIX.
+Calling it with ACL_READ_DATA, ACL_LIST_DIRECTORY, ACL_WRITE_DATA,
+ACL_ADD_FILE, ACL_APPEND_DATA, ACL_ADD_SUBDIRECTORY, ACL_READ_NAMED_ATTRS,
+ACL_WRITE_NAMED_ATTRS, ACL_DELETE_CHILD, ACL_READ_ATTRIBUTES,
+ACL_WRITE_ATTRIBUTES, ACL_DELETE, ACL_READ_ACL, ACL_WRITE_ACL
+or ACL_SYNCHRONIZE brands the ACL as NFSv4.
+.Sh RETURN VALUES
+.Rv -std acl_add_perm
+.Sh ERRORS
+The
+.Fn acl_add_perm
+function fails if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Fa permset_d
+is not a valid descriptor for a permission set within an ACL entry.
+Argument
+.Fa perm
+does not contain a valid
+.Vt acl_perm_t
+value.
+ACL is already branded differently.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_clear_perms 3 ,
+.Xr acl_delete_perm 3 ,
+.Xr acl_get_brand_np 3 ,
+.Xr acl_get_permset 3 ,
+.Xr acl_set_permset 3 ,
+.Xr posix1e 3
+.Sh STANDARDS
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+.Sh HISTORY
+POSIX.1e support was introduced in
+.Fx 4.0 .
+The
+.Fn acl_add_perm
+function was added in
+.Fx 5.0 .
+.Sh AUTHORS
+The
+.Fn acl_add_perm
+function was written by
+.An Chris D. Faulhaber Aq Mt jedgar@fxp.org .
diff --git a/lib/libc/posix1e/acl_branding.c b/lib/libc/posix1e/acl_branding.c
new file mode 100644
index 000000000000..84b00636c195
--- /dev/null
+++ b/lib/libc/posix1e/acl_branding.c
@@ -0,0 +1,169 @@
+/*-
+ * Copyright (c) 2008, 2009 Edward Tomasz Napierała <trasz@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 <assert.h>
+#include <errno.h>
+#include <sys/acl.h>
+
+#include "acl_support.h"
+
+/*
+ * An ugly detail of the implementation - fortunately not visible
+ * to the API users - is the "branding": libc needs to keep track
+ * of what "brand" ACL is: NFSv4, POSIX.1e or unknown. It happens
+ * automatically - for example, during acl_get_file(3) ACL gets
+ * branded according to the "type" argument; during acl_set_permset
+ * ACL, if its brand is unknown it gets branded as NFSv4 if any of the
+ * NFSv4 permissions that are not valid for POSIX.1e ACL are set etc.
+ * Branding information is used for printing out the ACL (acl_to_text(3)),
+ * veryfying acl_set_whatever arguments (checking against setting
+ * bits that are valid only for NFSv4 in ACL branded as POSIX.1e) etc.
+ */
+
+static acl_t
+entry2acl(acl_entry_t entry)
+{
+ acl_t aclp;
+
+ aclp = (acl_t)(((long)entry >> _ACL_T_ALIGNMENT_BITS) << _ACL_T_ALIGNMENT_BITS);
+
+ return (aclp);
+}
+
+/*
+ * Return brand of an ACL.
+ */
+int
+_acl_brand(const acl_t acl)
+{
+
+ return (acl->ats_brand);
+}
+
+int
+_entry_brand(const acl_entry_t entry)
+{
+
+ return (_acl_brand(entry2acl(entry)));
+}
+
+/*
+ * Return 1, iff branding ACL as "brand" is ok.
+ */
+int
+_acl_brand_may_be(const acl_t acl, int brand)
+{
+
+ if (_acl_brand(acl) == ACL_BRAND_UNKNOWN)
+ return (1);
+
+ if (_acl_brand(acl) == brand)
+ return (1);
+
+ return (0);
+}
+
+int
+_entry_brand_may_be(const acl_entry_t entry, int brand)
+{
+
+ return (_acl_brand_may_be(entry2acl(entry), brand));
+}
+
+/*
+ * Brand ACL as "brand".
+ */
+void
+_acl_brand_as(acl_t acl, int brand)
+{
+
+ assert(_acl_brand_may_be(acl, brand));
+
+ acl->ats_brand = brand;
+}
+
+void
+_entry_brand_as(const acl_entry_t entry, int brand)
+{
+
+ _acl_brand_as(entry2acl(entry), brand);
+}
+
+int
+_acl_type_not_valid_for_acl(const acl_t acl, acl_type_t type)
+{
+
+ switch (_acl_brand(acl)) {
+ case ACL_BRAND_NFS4:
+ if (type == ACL_TYPE_NFS4)
+ return (0);
+ break;
+
+ case ACL_BRAND_POSIX:
+ if (type == ACL_TYPE_ACCESS || type == ACL_TYPE_DEFAULT)
+ return (0);
+ break;
+
+ case ACL_BRAND_UNKNOWN:
+ return (0);
+ }
+
+ return (-1);
+}
+
+void
+_acl_brand_from_type(acl_t acl, acl_type_t type)
+{
+
+ switch (type) {
+ case ACL_TYPE_NFS4:
+ _acl_brand_as(acl, ACL_BRAND_NFS4);
+ break;
+ case ACL_TYPE_ACCESS:
+ case ACL_TYPE_DEFAULT:
+ _acl_brand_as(acl, ACL_BRAND_POSIX);
+ break;
+ default:
+ /* XXX: What to do here? */
+ break;
+ }
+}
+
+int
+acl_get_brand_np(acl_t acl, int *brand_p)
+{
+
+ if (acl == NULL || brand_p == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+ *brand_p = _acl_brand(acl);
+
+ return (0);
+}
diff --git a/lib/libc/posix1e/acl_calc_mask.3 b/lib/libc/posix1e/acl_calc_mask.3
new file mode 100644
index 000000000000..1cd3fd7c03c7
--- /dev/null
+++ b/lib/libc/posix1e/acl_calc_mask.3
@@ -0,0 +1,98 @@
+.\"-
+.\" Copyright (c) 2001 Chris D. Faulhaber
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 March 10, 2001
+.Dt ACL_CALC_MASK 3
+.Os
+.Sh NAME
+.Nm acl_calc_mask
+.Nd calculate and set ACL mask permissions
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_calc_mask "acl_t *acl_p"
+.Sh DESCRIPTION
+The
+.Fn acl_calc_mask
+function
+is a POSIX.1e call that calculates and set the permissions
+associated with the
+.Dv ACL_MASK
+ACL entry of the ACL referred to by
+.Fa acl_p .
+.Pp
+The value of new permissions are the union of the permissions
+granted by the
+.Dv ACL_GROUP , ACL_GROUP_OBJ , ACL_USER
+tag types which
+match processes in the file group class contained in the ACL
+referred to by
+.Fa acl_p .
+.Pp
+If the ACL referred to by
+.Fa acl_p
+already contains an
+.Dv ACL_MASK
+entry, its permissions shall be
+overwritten; if it does not contain an
+.Dv ACL_MASK
+entry, one shall
+be added.
+.Sh RETURN VALUES
+.Rv -std acl_calc_mask
+.Sh ERRORS
+The
+.Fn acl_calc_mask
+function fails if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Fa acl_p
+does not point to a pointer to a valid ACL.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_get_entry 3 ,
+.Xr acl_valid 3 ,
+.Xr posix1e 3
+.Sh STANDARDS
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+.Sh HISTORY
+POSIX.1e support was introduced in
+.Fx 4.0 .
+The
+.Fn acl_calc_mask
+function was added in
+.Fx 5.0 .
+.Sh AUTHORS
+The
+.Fn acl_calc_mask
+function was written by
+.An Chris D. Faulhaber Aq Mt jedgar@fxp.org .
diff --git a/lib/libc/posix1e/acl_calc_mask.c b/lib/libc/posix1e/acl_calc_mask.c
new file mode 100644
index 000000000000..56215b9094c6
--- /dev/null
+++ b/lib/libc/posix1e/acl_calc_mask.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2001-2002 Chris D. Faulhaber
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include "namespace.h"
+#include <sys/acl.h>
+#include "un-namespace.h"
+
+#include <errno.h>
+#include <stdio.h>
+
+#include "acl_support.h"
+
+/*
+ * acl_calc_mask() (23.4.2): calculate and set the permissions
+ * associated with the ACL_MASK ACL entry. If the ACL already
+ * contains an ACL_MASK entry, its permissions shall be
+ * overwritten; if not, one shall be added.
+ */
+int
+acl_calc_mask(acl_t *acl_p)
+{
+ struct acl *acl_int, *acl_int_new;
+ acl_t acl_new;
+ int i, mask_mode, mask_num;
+
+ /*
+ * (23.4.2.4) requires acl_p to point to a pointer to a valid ACL.
+ * Since one of the primary reasons to use this function would be
+ * to calculate the appropriate mask to obtain a valid ACL, we only
+ * perform sanity checks here and validate the ACL prior to
+ * returning.
+ */
+ if (acl_p == NULL || *acl_p == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (!_acl_brand_may_be(*acl_p, ACL_BRAND_POSIX)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ _acl_brand_as(*acl_p, ACL_BRAND_POSIX);
+
+ acl_int = &(*acl_p)->ats_acl;
+ if ((acl_int->acl_cnt < 3) || (acl_int->acl_cnt > ACL_MAX_ENTRIES)) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ acl_new = acl_dup(*acl_p);
+ if (acl_new == NULL)
+ return (-1);
+ acl_int_new = &acl_new->ats_acl;
+
+ mask_mode = 0;
+ mask_num = -1;
+
+ /* gather permissions and find a mask entry */
+ for (i = 0; i < acl_int_new->acl_cnt; i++) {
+ switch(acl_int_new->acl_entry[i].ae_tag) {
+ case ACL_USER:
+ case ACL_GROUP:
+ case ACL_GROUP_OBJ:
+ mask_mode |=
+ acl_int_new->acl_entry[i].ae_perm & ACL_PERM_BITS;
+ break;
+ case ACL_MASK:
+ mask_num = i;
+ break;
+ }
+ }
+
+ /* if a mask entry already exists, overwrite the perms */
+ if (mask_num != -1)
+ acl_int_new->acl_entry[mask_num].ae_perm = mask_mode;
+ else {
+ /* if no mask exists, check acl_cnt... */
+ if (acl_int_new->acl_cnt == ACL_MAX_ENTRIES) {
+ errno = ENOMEM;
+ acl_free(acl_new);
+ return (-1);
+ }
+ /* ...and add the mask entry */
+ acl_int_new->acl_entry[acl_int_new->acl_cnt].ae_tag = ACL_MASK;
+ acl_int_new->acl_entry[acl_int_new->acl_cnt].ae_id =
+ ACL_UNDEFINED_ID;
+ acl_int_new->acl_entry[acl_int_new->acl_cnt].ae_perm =
+ mask_mode;
+ acl_int_new->acl_cnt++;
+ }
+
+ if (acl_valid(acl_new) == -1) {
+ errno = EINVAL;
+ acl_free(acl_new);
+ return (-1);
+ }
+
+ **acl_p = *acl_new;
+ acl_free(acl_new);
+
+ return (0);
+}
diff --git a/lib/libc/posix1e/acl_clear_flags_np.3 b/lib/libc/posix1e/acl_clear_flags_np.3
new file mode 100644
index 000000000000..06dee97ac089
--- /dev/null
+++ b/lib/libc/posix1e/acl_clear_flags_np.3
@@ -0,0 +1,79 @@
+.\"-
+.\" Copyright (c) 2008, 2009 Edward Tomasz Napierala
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd October 30, 2014
+.Dt ACL_CLEAR_FLAGS_NP 3
+.Os
+.Sh NAME
+.Nm acl_clear_flags_np
+.Nd clear flags from a flagset
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_clear_flags_np "acl_flagset_t flagset_d"
+.Sh DESCRIPTION
+The
+.Fn acl_clear_flags_np
+function
+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
+.Sh ERRORS
+The
+.Fn acl_clear_flags_np
+function fails if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Fa flagset_d
+is not a valid descriptor for a flagset.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_add_flag_np 3 ,
+.Xr acl_delete_flag_np 3 ,
+.Xr acl_get_flagset_np 3 ,
+.Xr acl_set_flagset_np 3 ,
+.Xr posix1e 3
+.Sh STANDARDS
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+.Sh HISTORY
+POSIX.1e support was introduced in
+.Fx 4.0 .
+The
+.Fn acl_clear_flags_np
+function was added in
+.Fx 5.0 .
+.Sh AUTHORS
+The
+.Fn acl_clear_flags_np
+function was written by
+.An Edward Tomasz Napierala Aq Mt trasz@FreeBSD.org .
diff --git a/lib/libc/posix1e/acl_clear_perms.3 b/lib/libc/posix1e/acl_clear_perms.3
new file mode 100644
index 000000000000..4b055fcf5e64
--- /dev/null
+++ b/lib/libc/posix1e/acl_clear_perms.3
@@ -0,0 +1,79 @@
+.\"-
+.\" Copyright (c) 2001 Chris D. Faulhaber
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 March 10, 2001
+.Dt ACL_CLEAR_PERMS 3
+.Os
+.Sh NAME
+.Nm acl_clear_perms
+.Nd clear permissions from a permission set
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_clear_perms "acl_permset_t permset_d"
+.Sh DESCRIPTION
+The
+.Fn acl_clear_perms
+function
+is a POSIX.1e call that clears all permissions from permissions set
+.Fa permset_d .
+.Sh RETURN VALUES
+.Rv -std acl_clear_perms
+.Sh ERRORS
+The
+.Fn acl_clear_perms
+function fails if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Fa permset_d
+is not a valid descriptor for a permission set.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_add_perm 3 ,
+.Xr acl_delete_perm 3 ,
+.Xr acl_get_permset 3 ,
+.Xr acl_set_permset 3 ,
+.Xr posix1e 3
+.Sh STANDARDS
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+.Sh HISTORY
+POSIX.1e support was introduced in
+.Fx 4.0 .
+The
+.Fn acl_clear_perms
+function was added in
+.Fx 5.0 .
+.Sh AUTHORS
+The
+.Fn acl_clear_perms
+function was written by
+.An Chris D. Faulhaber Aq Mt jedgar@fxp.org .
diff --git a/lib/libc/posix1e/acl_compat.c b/lib/libc/posix1e/acl_compat.c
new file mode 100644
index 000000000000..ab1bdf6244cb
--- /dev/null
+++ b/lib/libc/posix1e/acl_compat.c
@@ -0,0 +1,63 @@
+/*-
+ * Copyright (c) 2008 Edward Tomasz Napierała <trasz@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/acl.h>
+
+int __oldacl_get_perm_np(acl_permset_t, oldacl_perm_t);
+int __oldacl_add_perm(acl_permset_t, oldacl_perm_t);
+int __oldacl_delete_perm(acl_permset_t, oldacl_perm_t);
+
+/*
+ * Compatibility wrappers for applications compiled against libc from before
+ * NFSv4 ACLs were added.
+ */
+int
+__oldacl_get_perm_np(acl_permset_t permset_d, oldacl_perm_t perm)
+{
+
+ return (acl_get_perm_np(permset_d, perm));
+}
+
+int
+__oldacl_add_perm(acl_permset_t permset_d, oldacl_perm_t perm)
+{
+
+ return (acl_add_perm(permset_d, perm));
+}
+
+int
+__oldacl_delete_perm(acl_permset_t permset_d, oldacl_perm_t perm)
+{
+
+ return (acl_delete_perm(permset_d, perm));
+}
+
+__sym_compat(acl_get_perm_np, __oldacl_get_perm_np, FBSD_1.0);
+__sym_compat(acl_add_perm, __oldacl_add_perm, FBSD_1.0);
+__sym_compat(acl_delete_perm, __oldacl_delete_perm, FBSD_1.0);
diff --git a/lib/libc/posix1e/acl_copy.c b/lib/libc/posix1e/acl_copy.c
new file mode 100644
index 000000000000..fc4c25d1ee49
--- /dev/null
+++ b/lib/libc/posix1e/acl_copy.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2001-2002 Chris D. Faulhaber
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include "namespace.h"
+#include <sys/acl.h>
+#include "un-namespace.h"
+
+#include <errno.h>
+#include <string.h>
+
+#include "acl_support.h"
+
+/*
+ * acl_copy_entry() (23.4.4): copy the contents of ACL entry src_d to
+ * ACL entry dest_d
+ */
+int
+acl_copy_entry(acl_entry_t dest_d, acl_entry_t src_d)
+{
+
+ if (src_d == NULL || dest_d == NULL || src_d == dest_d) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ /*
+ * Can we brand the new entry the same as the source entry?
+ */
+ if (!_entry_brand_may_be(dest_d, _entry_brand(src_d))) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ _entry_brand_as(dest_d, _entry_brand(src_d));
+
+ dest_d->ae_tag = src_d->ae_tag;
+ dest_d->ae_id = src_d->ae_id;
+ dest_d->ae_perm = src_d->ae_perm;
+ dest_d->ae_entry_type = src_d->ae_entry_type;
+ dest_d->ae_flags = src_d->ae_flags;
+
+ return (0);
+}
+
+ssize_t
+acl_copy_ext(void *buf_p, acl_t acl, ssize_t size)
+{
+
+ errno = ENOSYS;
+ return (-1);
+}
+
+acl_t
+acl_copy_int(const void *buf_p)
+{
+
+ errno = ENOSYS;
+ return (NULL);
+}
diff --git a/lib/libc/posix1e/acl_copy_entry.3 b/lib/libc/posix1e/acl_copy_entry.3
new file mode 100644
index 000000000000..5fd31ed793e6
--- /dev/null
+++ b/lib/libc/posix1e/acl_copy_entry.3
@@ -0,0 +1,85 @@
+.\"-
+.\" Copyright (c) 2001 Chris D. Faulhaber
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 March 10, 2001
+.Dt ACL_COPY_ENTRY 3
+.Os
+.Sh NAME
+.Nm acl_copy_entry
+.Nd copy an ACL entry to another ACL entry
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_copy_entry "acl_entry_t dest_d" "acl_entry_t src_d"
+.Sh DESCRIPTION
+The
+.Fn acl_copy_entry
+function
+is a POSIX.1e call that copies the contents of ACL entry
+.Fa src_d
+to ACL entry
+.Fa dest_d .
+.Sh RETURN VALUES
+.Rv -std acl_copy_entry
+.Sh ERRORS
+The
+.Fn acl_copy_entry
+function fails if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Fa src_d
+or
+.Fa dest_d
+is not a valid descriptor for an ACL entry, or
+arguments
+.Fa src_d
+and
+.Fa dest_d
+reference the same ACL entry.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_get_entry 3 ,
+.Xr posix1e 3
+.Sh STANDARDS
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+.Sh HISTORY
+POSIX.1e support was introduced in
+.Fx 4.0 .
+The
+.Fn acl_copy_entry
+function was added in
+.Fx 5.0 .
+.Sh AUTHORS
+The
+.Fn acl_copy_entry
+function was written by
+.An Chris D. Faulhaber Aq Mt jedgar@fxp.org .
diff --git a/lib/libc/posix1e/acl_create_entry.3 b/lib/libc/posix1e/acl_create_entry.3
new file mode 100644
index 000000000000..76c14f3f0e91
--- /dev/null
+++ b/lib/libc/posix1e/acl_create_entry.3
@@ -0,0 +1,98 @@
+.\"-
+.\" Copyright (c) 2001 Chris D. Faulhaber
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd June 25, 2009
+.Dt ACL_CREATE_ENTRY 3
+.Os
+.Sh NAME
+.Nm acl_create_entry
+.Nm acl_create_entry_np
+.Nd create a new ACL entry
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_create_entry "acl_t *acl_p" "acl_entry_t *entry_p"
+.Ft int
+.Fn acl_create_entry_np "acl_t *acl_p" "acl_entry_t *entry_p" "int index"
+.Sh DESCRIPTION
+The
+.Fn acl_create_entry
+function
+is a POSIX.1e call that creates a new ACL entry in the ACL
+pointed to by
+.Fa acl_p .
+The
+.Fn acl_create_entry_np
+function is a non-portable version that creates the ACL entry
+at position
+.Fa index .
+Positions are numbered starting from zero, i.e. calling
+.Fn acl_create_entry_np
+with
+.Fa index
+argument equal to zero will prepend the entry to the ACL.
+.Sh RETURN VALUES
+.Rv -std acl_create_entry
+.Sh ERRORS
+The
+.Fn acl_create_entry
+function fails if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Fa acl_p
+does not point to a pointer to a valid ACL.
+Argument
+.Fa index
+is out of bounds.
+.It Bq Er ENOMEM
+The ACL working storage requires more memory than is
+allowed by the hardware or system-imposed memory
+management constraints.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_delete_entry 3 ,
+.Xr acl_get_entry 3 ,
+.Xr posix1e 3
+.Sh STANDARDS
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+.Sh HISTORY
+POSIX.1e support was introduced in
+.Fx 4.0 .
+The
+.Fn acl_create_entry
+function was added in
+.Fx 5.0 .
+.Sh AUTHORS
+The
+.Fn acl_create_entry
+function was written by
+.An Chris D. Faulhaber Aq Mt jedgar@fxp.org .
diff --git a/lib/libc/posix1e/acl_delete.3 b/lib/libc/posix1e/acl_delete.3
new file mode 100644
index 000000000000..fb2958b73e49
--- /dev/null
+++ b/lib/libc/posix1e/acl_delete.3
@@ -0,0 +1,140 @@
+.\"-
+.\" Copyright (c) 2000, 2002 Robert N. M. Watson
+.\" All rights reserved.
+.\"
+.\" This software was developed by Robert Watson for the TrustedBSD Project.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd December 29, 2002
+.Dt ACL_DELETE 3
+.Os
+.Sh NAME
+.Nm acl_delete_def_file ,
+.Nm acl_delete_def_link_np ,
+.Nm acl_delete_fd_np ,
+.Nm acl_delete_file_np ,
+.Nm acl_delete_link_np
+.Nd delete an ACL from a file
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_delete_def_file "const char *path_p"
+.Ft int
+.Fn acl_delete_def_link_np "const char *path_p"
+.Ft int
+.Fn acl_delete_fd_np "int filedes" "acl_type_t type"
+.Ft int
+.Fn acl_delete_file_np "const char *path_p" "acl_type_t type"
+.Ft int
+.Fn acl_delete_link_np "const char *path_p" "acl_type_t type"
+.Sh DESCRIPTION
+The
+.Fn acl_delete_def_file ,
+.Fn acl_delete_def_link_np ,
+.Fn acl_delete_fd_np ,
+.Fn acl_delete_file_np ,
+and
+.Fn acl_delete_link_np
+each allow the deletion of an ACL from a file.
+The
+.Fn acl_delete_def_file
+function
+is a POSIX.1e call that deletes the default ACL from a file (normally a
+directory) by name; the remainder of the calls are non-portable extensions
+that permit the deletion of arbitrary ACL types from a file/directory
+either by path name or file descriptor.
+The
+.Fn _file
+variations follow a symlink if it occurs in the last segment of the
+path name; the
+.Fn _link
+variations operate on the symlink itself.
+.Sh IMPLEMENTATION NOTES
+.Fx Ns 's
+support for POSIX.1e interfaces and features is still under
+development at this time.
+.Sh RETURN VALUES
+.Rv -std
+.Sh ERRORS
+If any of the following conditions occur, these functions shall return -1
+and set
+.Va errno
+to the corresponding value:
+.Bl -tag -width Er
+.It Bq Er EACCES
+Search permission is denied for a component of the path prefix, or the
+object exists and the process does not have appropriate access rights.
+.It Bq Er EBADF
+The
+.Va fd
+argument is not a valid file descriptor.
+.It Bq Er EINVAL
+The ACL type passed is invalid for this file object.
+.It Bq Er ENAMETOOLONG
+A component of a pathname exceeded 255 characters, or an
+entire path name exceeded 1023 characters.
+.It Bq Er ENOENT
+The named object does not exist, or the
+.Va path_p
+argument points to an empty string.
+.It Bq Er ENOMEM
+Insufficient memory available to fulfill request.
+.It Bq Er ENOTDIR
+A component of the path prefix is not a directory.
+.Pp
+Argument
+.Va path_p
+must be a directory, and is not.
+.It Bq Er EOPNOTSUPP
+The file system does not support ACL deletion.
+.It Bq Er EPERM
+The process does not have appropriate privilege to perform the operation
+to delete an ACL.
+.It Bq Er EROFS
+The file system is read-only.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_get 3 ,
+.Xr acl_set 3 ,
+.Xr posix1e 3
+.Sh STANDARDS
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+Discussion
+of the draft continues on the cross-platform POSIX.1e implementation
+mailing list.
+To join this list, see the
+.Fx
+POSIX.1e implementation
+page for more information.
+.Sh HISTORY
+POSIX.1e support was introduced in
+.Fx 4.0 ,
+and development continues.
+.Sh AUTHORS
+.An Robert N M Watson
diff --git a/lib/libc/posix1e/acl_delete.c b/lib/libc/posix1e/acl_delete.c
new file mode 100644
index 000000000000..1bbadd583396
--- /dev/null
+++ b/lib/libc/posix1e/acl_delete.c
@@ -0,0 +1,79 @@
+/*-
+ * Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * This software was developed by Robert Watson for the TrustedBSD Project.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * acl_delete_def_file -- remove a default acl from a file
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include "namespace.h"
+#include <sys/acl.h>
+#include "un-namespace.h"
+#include <sys/errno.h>
+
+#include "acl_support.h"
+
+int
+acl_delete_def_file(const char *path_p)
+{
+
+ return (__acl_delete_file(path_p, ACL_TYPE_DEFAULT));
+}
+
+int
+acl_delete_def_link_np(const char *path_p)
+{
+
+ return (__acl_delete_link(path_p, ACL_TYPE_DEFAULT));
+}
+
+int
+acl_delete_file_np(const char *path_p, acl_type_t type)
+{
+
+ type = _acl_type_unold(type);
+ return (__acl_delete_file(path_p, type));
+}
+
+int
+acl_delete_link_np(const char *path_p, acl_type_t type)
+{
+
+ type = _acl_type_unold(type);
+ return (__acl_delete_link(path_p, type));
+}
+
+int
+acl_delete_fd_np(int filedes, acl_type_t type)
+{
+
+ type = _acl_type_unold(type);
+ return (___acl_delete_fd(filedes, type));
+}
diff --git a/lib/libc/posix1e/acl_delete_entry.3 b/lib/libc/posix1e/acl_delete_entry.3
new file mode 100644
index 000000000000..06bb0ded1ed0
--- /dev/null
+++ b/lib/libc/posix1e/acl_delete_entry.3
@@ -0,0 +1,101 @@
+.\"-
+.\" Copyright (c) 2001 Chris D. Faulhaber
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd June 25, 2009
+.Dt ACL_DELETE_ENTRY 3
+.Os
+.Sh NAME
+.Nm acl_delete_entry ,
+.Nm acl_delete_entry_np
+.Nd delete an ACL entry from an ACL
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_delete_entry "acl_t acl" "acl_entry_t entry_d"
+.Ft int
+.Fn acl_delete_entry_np "acl_t acl" "int index"
+.Sh DESCRIPTION
+The
+.Fn acl_delete_entry
+function
+is a POSIX.1e call that removes the ACL entry
+.Fa entry_d
+from ACL
+.Fa acl .
+The
+.Fn acl_delete_entry_np
+function is a non-portable version that removes the ACL entry
+at position
+.Fa index
+from ACL
+.Fa acl .
+Positions are numbered starting from zero, i.e. calling
+.Fn acl_delete_entry_np
+with
+.Fa index
+argument equal to zero will remove the first ACL entry.
+.Sh RETURN VALUES
+.Rv -std acl_delete_entry
+.Sh ERRORS
+The
+.Fn acl_delete_entry
+function fails if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Fa acl
+does not point to a valid ACL.
+Argument
+.Fa entry_d
+is not a valid descriptor for an ACL entry in
+.Fa acl .
+Argument
+.Fa index
+is out of bounds.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_copy_entry 3 ,
+.Xr acl_get_entry 3 ,
+.Xr posix1e 3
+.Sh STANDARDS
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+.Sh HISTORY
+POSIX.1e support was introduced in
+.Fx 4.0 .
+The
+.Fn acl_delete_entry
+function was added in
+.Fx 5.0 .
+.Sh AUTHORS
+The
+.Fn acl_delete_entry
+function was written by
+.An Chris D. Faulhaber Aq Mt jedgar@fxp.org .
diff --git a/lib/libc/posix1e/acl_delete_entry.c b/lib/libc/posix1e/acl_delete_entry.c
new file mode 100644
index 000000000000..4564dde693b3
--- /dev/null
+++ b/lib/libc/posix1e/acl_delete_entry.c
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2001-2002 Chris D. Faulhaber
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include "namespace.h"
+#include <sys/acl.h>
+#include "un-namespace.h"
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "acl_support.h"
+
+static int
+_entry_matches(const acl_entry_t a, const acl_entry_t b)
+{
+ /*
+ * There is a semantical difference here between NFSv4 and POSIX
+ * draft ACLs. In POSIX, there may be only one entry for the particular
+ * user or group. In NFSv4 ACL, there may be any number of them. We're
+ * trying to be more specific here in that case.
+ */
+ switch (_entry_brand(a)) {
+ case ACL_BRAND_NFS4:
+ if (a->ae_tag != b->ae_tag || a->ae_entry_type != b->ae_entry_type)
+ return (0);
+
+ /* If ae_ids matter, compare them as well. */
+ if (a->ae_tag == ACL_USER || a->ae_tag == ACL_GROUP) {
+ if (a->ae_id != b->ae_id)
+ return (0);
+ }
+
+ return (1);
+
+ default:
+ if ((a->ae_tag == b->ae_tag) && (a->ae_id == b->ae_id))
+ return (1);
+ }
+
+ return (0);
+}
+
+/*
+ * acl_delete_entry() (23.4.9): remove the ACL entry indicated by entry_d
+ * from acl.
+ */
+int
+acl_delete_entry(acl_t acl, acl_entry_t entry_d)
+{
+ struct acl *acl_int;
+ struct acl_entry entry_int;
+ int i, j, found = 0;
+
+ if (acl == NULL || entry_d == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ acl_int = &acl->ats_acl;
+
+ if (_entry_brand(entry_d) != _acl_brand(acl)) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if ((acl->ats_acl.acl_cnt < 1) ||
+ (acl->ats_acl.acl_cnt > ACL_MAX_ENTRIES)) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ /* Use a local copy to prevent deletion of more than this entry */
+ entry_int = *entry_d;
+
+ for (i = 0; i < acl->ats_acl.acl_cnt;) {
+ if (_entry_matches(&(acl->ats_acl.acl_entry[i]), &entry_int)) {
+ /* ...shift the remaining entries... */
+ for (j = i; j < acl->ats_acl.acl_cnt - 1; ++j)
+ acl->ats_acl.acl_entry[j] =
+ acl->ats_acl.acl_entry[j+1];
+ /* ...drop the count and zero the unused entry... */
+ acl->ats_acl.acl_cnt--;
+ bzero(&acl->ats_acl.acl_entry[j],
+ sizeof(struct acl_entry));
+ acl->ats_cur_entry = 0;
+
+ /* Continue with the loop to remove all matching entries. */
+ found = 1;
+ } else
+ i++;
+ }
+
+ if (found)
+ return (0);
+
+ errno = EINVAL;
+ return (-1);
+}
+
+int
+acl_delete_entry_np(acl_t acl, int offset)
+{
+ struct acl *acl_int;
+ int i;
+
+ if (acl == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ acl_int = &acl->ats_acl;
+
+ if (offset < 0 || offset >= acl_int->acl_cnt) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if ((acl->ats_acl.acl_cnt < 1) ||
+ (acl->ats_acl.acl_cnt > ACL_MAX_ENTRIES)) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ /* ...shift the remaining entries... */
+ for (i = offset; i < acl->ats_acl.acl_cnt - 1; ++i)
+ acl->ats_acl.acl_entry[i] =
+ acl->ats_acl.acl_entry[i+1];
+ /* ...drop the count and zero the unused entry... */
+ acl->ats_acl.acl_cnt--;
+ bzero(&acl->ats_acl.acl_entry[i],
+ sizeof(struct acl_entry));
+ acl->ats_cur_entry = 0;
+
+ return (0);
+}
diff --git a/lib/libc/posix1e/acl_delete_flag_np.3 b/lib/libc/posix1e/acl_delete_flag_np.3
new file mode 100644
index 000000000000..3e298a435ef2
--- /dev/null
+++ b/lib/libc/posix1e/acl_delete_flag_np.3
@@ -0,0 +1,84 @@
+.\"-
+.\" Copyright (c) 2008, 2009 Edward Tomasz Napierala
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd October 30, 2014
+.Dt ACL_DELETE_FLAG_NP 3
+.Os
+.Sh NAME
+.Nm acl_delete_flag_np
+.Nd delete flags from a flagset
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_delete_flag_np "acl_flagset_t flagset_d" "acl_flag_t flag"
+.Sh DESCRIPTION
+The
+.Fn acl_delete_flag_np
+function
+is a non-portable call that removes specific NFSv4 ACL flags from flagset
+.Fa flags .
+.Sh RETURN VALUES
+.Rv -std acl_delete_flag_np
+.Sh ERRORS
+The
+.Fn acl_delete_flag_np
+function fails if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Fa flagset_d
+is not a valid descriptor for a flagset.
+Argument
+.Fa flag
+does not contain a valid
+.Vt acl_flag_t
+value.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_add_flag_np 3 ,
+.Xr acl_clear_flags_np 3 ,
+.Xr acl_get_flagset_np 3 ,
+.Xr acl_set_flagset_np 3 ,
+.Xr posix1e 3
+.Sh STANDARDS
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+.Sh HISTORY
+POSIX.1e support was introduced in
+.Fx 4.0 .
+The
+.Fn acl_delete_flag_np
+function was added in
+.Fx 8.0 .
+.Sh AUTHORS
+The
+.Fn acl_delete_flag_np
+function was written by
+.An Edward Tomasz Napierala Aq Mt trasz@FreeBSD.org .
diff --git a/lib/libc/posix1e/acl_delete_perm.3 b/lib/libc/posix1e/acl_delete_perm.3
new file mode 100644
index 000000000000..90f244e147c2
--- /dev/null
+++ b/lib/libc/posix1e/acl_delete_perm.3
@@ -0,0 +1,84 @@
+.\"-
+.\" Copyright (c) 2001 Chris D. Faulhaber
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 March 10, 2001
+.Dt ACL_DELETE_PERM 3
+.Os
+.Sh NAME
+.Nm acl_delete_perm
+.Nd delete permissions from a permission set
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_delete_perm "acl_permset_t permset_d" "acl_perm_t perm"
+.Sh DESCRIPTION
+The
+.Fn acl_delete_perm
+function
+is a POSIX.1e call that removes specific permissions from permissions set
+.Fa perm .
+.Sh RETURN VALUES
+.Rv -std acl_delete_perm
+.Sh ERRORS
+The
+.Fn acl_delete_perm
+function fails if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Fa permset_d
+is not a valid descriptor for a permission set.
+Argument
+.Fa perm
+does not contain a valid
+.Vt acl_perm_t
+value.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_add_perm 3 ,
+.Xr acl_clear_perms 3 ,
+.Xr acl_get_permset 3 ,
+.Xr acl_set_permset 3 ,
+.Xr posix1e 3
+.Sh STANDARDS
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+.Sh HISTORY
+POSIX.1e support was introduced in
+.Fx 4.0 .
+The
+.Fn acl_delete_perm
+function was added in
+.Fx 5.0 .
+.Sh AUTHORS
+The
+.Fn acl_delete_perm
+function was written by
+.An Chris D. Faulhaber Aq Mt jedgar@fxp.org .
diff --git a/lib/libc/posix1e/acl_dup.3 b/lib/libc/posix1e/acl_dup.3
new file mode 100644
index 000000000000..ae4ff4f7b474
--- /dev/null
+++ b/lib/libc/posix1e/acl_dup.3
@@ -0,0 +1,110 @@
+.\"-
+.\" Copyright (c) 2000, 2002 Robert N. M. Watson
+.\" All rights reserved.
+.\"
+.\" This software was developed by Robert Watson for the TrustedBSD Project.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd January 28, 2000
+.Dt ACL_DUP 3
+.Os
+.Sh NAME
+.Nm acl_dup
+.Nd duplicate an ACL
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft acl_t
+.Fn acl_dup "acl_t acl"
+.Sh DESCRIPTION
+The
+.Fn acl_dup
+function returns a pointer to a copy of the ACL pointed to by the argument
+.Va acl .
+.Pp
+This function may cause memory to be allocated.
+The caller should free any
+releasable memory, when the new ACL is no longer required, by calling
+.Xr acl_free 3
+with the
+.Va (void*)acl_t
+as an argument.
+.Pp
+Any existing ACL pointers that refer to the ACL referred to by
+.Va acl
+shall continue to refer to the ACL.
+.Sh IMPLEMENTATION NOTES
+.Fx Ns 's
+support for POSIX.1e interfaces and features is still under
+development at this time.
+.Sh RETURN VALUES
+Upon successful completion, this function shall return a pointer to the
+duplicate ACL.
+Otherwise, a value of
+.Va (acl_t)NULL
+shall be returned, and
+.Va errno
+shall be set to indicate the error.
+.Sh ERRORS
+If any of the following conditions occur, the
+.Fn acl_init
+function shall return a value of
+.Va (acl_t)NULL
+and set
+.Va errno
+to the corresponding value:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Va acl
+does not point to a valid ACL.
+.It Bq Er ENOMEM
+The
+.Va acl_t
+to be returned requires more memory than is allowed by the hardware or
+system-imposed memory management constraints.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_free 3 ,
+.Xr acl_get 3 ,
+.Xr posix1e 3
+.Sh STANDARDS
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+Discussion
+of the draft continues on the cross-platform POSIX.1e implementation
+mailing list.
+To join this list, see the
+.Fx
+POSIX.1e implementation
+page for more information.
+.Sh HISTORY
+POSIX.1e support was introduced in
+.Fx 4.0 ,
+and development continues.
+.Sh AUTHORS
+.An Robert N M Watson
diff --git a/lib/libc/posix1e/acl_entry.c b/lib/libc/posix1e/acl_entry.c
new file mode 100644
index 000000000000..2cffaa33d54c
--- /dev/null
+++ b/lib/libc/posix1e/acl_entry.c
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2001-2002 Chris D. Faulhaber
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include "namespace.h"
+#include <sys/acl.h>
+#include "un-namespace.h"
+
+#include <errno.h>
+#include <stdlib.h>
+
+/*
+ * acl_create_entry() (23.4.7): create a new ACL entry in the ACL pointed
+ * to by acl_p.
+ */
+int
+acl_create_entry(acl_t *acl_p, acl_entry_t *entry_p)
+{
+ struct acl *acl_int;
+
+ if (acl_p == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ acl_int = &(*acl_p)->ats_acl;
+
+ /*
+ * +1, because we are checking if there is space left for one more
+ * entry.
+ */
+ if (acl_int->acl_cnt + 1 >= ACL_MAX_ENTRIES) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ *entry_p = &acl_int->acl_entry[acl_int->acl_cnt++];
+
+ (**entry_p).ae_tag = ACL_UNDEFINED_TAG;
+ (**entry_p).ae_id = ACL_UNDEFINED_ID;
+ (**entry_p).ae_perm = ACL_PERM_NONE;
+ (**entry_p).ae_entry_type = 0;
+ (**entry_p).ae_flags = 0;
+
+ (*acl_p)->ats_cur_entry = 0;
+
+ return (0);
+}
+
+int
+acl_create_entry_np(acl_t *acl_p, acl_entry_t *entry_p, int offset)
+{
+ int i;
+ struct acl *acl_int;
+
+ if (acl_p == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ acl_int = &(*acl_p)->ats_acl;
+
+ if (acl_int->acl_cnt + 1 >= ACL_MAX_ENTRIES) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (offset < 0 || offset > acl_int->acl_cnt) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ /* Make room for the new entry. */
+ for (i = acl_int->acl_cnt; i > offset; i--)
+ acl_int->acl_entry[i] = acl_int->acl_entry[i - 1];
+
+ acl_int->acl_cnt++;
+
+ *entry_p = &acl_int->acl_entry[offset];
+
+ (**entry_p).ae_tag = ACL_UNDEFINED_TAG;
+ (**entry_p).ae_id = ACL_UNDEFINED_ID;
+ (**entry_p).ae_perm = ACL_PERM_NONE;
+ (**entry_p).ae_entry_type = 0;
+ (**entry_p).ae_flags= 0;
+
+ (*acl_p)->ats_cur_entry = 0;
+
+ return (0);
+}
+
+/*
+ * acl_get_entry() (23.4.14): returns an ACL entry from an ACL
+ * indicated by entry_id.
+ */
+int
+acl_get_entry(acl_t acl, int entry_id, acl_entry_t *entry_p)
+{
+ struct acl *acl_int;
+
+ if (acl == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+ acl_int = &acl->ats_acl;
+
+ switch(entry_id) {
+ case ACL_FIRST_ENTRY:
+ acl->ats_cur_entry = 0;
+ /* PASSTHROUGH */
+ case ACL_NEXT_ENTRY:
+ if (acl->ats_cur_entry >= acl->ats_acl.acl_cnt)
+ return 0;
+ *entry_p = &acl_int->acl_entry[acl->ats_cur_entry++];
+ return (1);
+ }
+
+ errno = EINVAL;
+ return (-1);
+}
diff --git a/lib/libc/posix1e/acl_flag.c b/lib/libc/posix1e/acl_flag.c
new file mode 100644
index 000000000000..8ad10c52d9d8
--- /dev/null
+++ b/lib/libc/posix1e/acl_flag.c
@@ -0,0 +1,155 @@
+/*-
+ * Copyright (c) 2008, 2009 Edward Tomasz Napierała <trasz@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 <stdio.h>
+#include <errno.h>
+#include <sys/acl.h>
+
+#include "acl_support.h"
+
+static int
+_flag_is_invalid(acl_flag_t flag)
+{
+
+ if ((flag & ACL_FLAGS_BITS) == flag)
+ return (0);
+
+ errno = EINVAL;
+
+ return (1);
+}
+
+int
+acl_add_flag_np(acl_flagset_t flagset_d, acl_flag_t flag)
+{
+
+ if (flagset_d == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (_flag_is_invalid(flag))
+ return (-1);
+
+ *flagset_d |= flag;
+
+ return (0);
+}
+
+int
+acl_clear_flags_np(acl_flagset_t flagset_d)
+{
+
+ if (flagset_d == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ *flagset_d = 0;
+
+ return (0);
+}
+
+int
+acl_delete_flag_np(acl_flagset_t flagset_d, acl_flag_t flag)
+{
+
+ if (flagset_d == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (_flag_is_invalid(flag))
+ return (-1);
+
+ *flagset_d &= ~flag;
+
+ return (0);
+}
+
+int
+acl_get_flag_np(acl_flagset_t flagset_d, acl_flag_t flag)
+{
+
+ if (flagset_d == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (_flag_is_invalid(flag))
+ return (-1);
+
+ if (*flagset_d & flag)
+ return (1);
+
+ return (0);
+}
+
+int
+acl_get_flagset_np(acl_entry_t entry_d, acl_flagset_t *flagset_p)
+{
+
+ if (entry_d == NULL || flagset_p == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (!_entry_brand_may_be(entry_d, ACL_BRAND_NFS4)) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ *flagset_p = &entry_d->ae_flags;
+
+ return (0);
+}
+
+int
+acl_set_flagset_np(acl_entry_t entry_d, acl_flagset_t flagset_d)
+{
+
+ if (entry_d == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (!_entry_brand_may_be(entry_d, ACL_BRAND_NFS4)) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ _entry_brand_as(entry_d, ACL_BRAND_NFS4);
+
+ if (_flag_is_invalid(*flagset_d))
+ return (-1);
+
+ entry_d->ae_flags = *flagset_d;
+
+ return (0);
+}
diff --git a/lib/libc/posix1e/acl_free.3 b/lib/libc/posix1e/acl_free.3
new file mode 100644
index 000000000000..d64c72a7c7e2
--- /dev/null
+++ b/lib/libc/posix1e/acl_free.3
@@ -0,0 +1,89 @@
+.\"-
+.\" Copyright (c) 2000, 2002 Robert N. M. Watson
+.\" All rights reserved.
+.\"
+.\" This software was developed by Robert Watson for the TrustedBSD Project.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd January 28, 2000
+.Dt ACL_FREE 3
+.Os
+.Sh NAME
+.Nm acl_free
+.Nd free ACL working state
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_free "void *obj_p"
+.Sh DESCRIPTION
+The
+.Fn acl_free
+call allows the freeing of ACL working space, such as is allocated by
+.Xr acl_dup 3 ,
+or
+.Xr acl_from_text 3 .
+.Sh IMPLEMENTATION NOTES
+.Fx Ns 's
+support for POSIX.1e interfaces and features is still under
+development at this time.
+.Sh RETURN VALUES
+.Rv -std acl_free
+.Sh ERRORS
+If any of the following conditions occur, the
+.Fn acl_free
+function shall return -1 and set
+.Va errno
+to the corresponding value:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The value of the
+.Va obj_p
+argument is invalid.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_dup 3 ,
+.Xr acl_from_text 3 ,
+.Xr acl_get 3 ,
+.Xr acl_init 3 ,
+.Xr posix1e 3
+.Sh STANDARDS
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+Discussion
+of the draft continues on the cross-platform POSIX.1e implementation
+mailing list.
+To join this list, see the
+.Fx
+POSIX.1e implementation
+page for more information.
+.Sh HISTORY
+POSIX.1e support was introduced in
+.Fx 4.0 ,
+and development continues.
+.Sh AUTHORS
+.An Robert N M Watson
diff --git a/lib/libc/posix1e/acl_free.c b/lib/libc/posix1e/acl_free.c
new file mode 100644
index 000000000000..6de41da8abfb
--- /dev/null
+++ b/lib/libc/posix1e/acl_free.c
@@ -0,0 +1,54 @@
+/*-
+ * Copyright (c) 1999, 2000, 2001 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * acl_free -- free ACL objects from user memory
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include "namespace.h"
+#include <sys/acl.h>
+#include "un-namespace.h"
+#include <sys/errno.h>
+#include <stdlib.h>
+
+/*
+ * acl_free() (23.4.12): free any releasable memory allocated to the
+ * ACL data object identified by obj_p.
+ */
+int
+acl_free(void *obj_p)
+{
+
+ if (obj_p) {
+ free(obj_p);
+ obj_p = NULL;
+ }
+
+ return (0);
+}
diff --git a/lib/libc/posix1e/acl_from_text.3 b/lib/libc/posix1e/acl_from_text.3
new file mode 100644
index 000000000000..8b10784e502b
--- /dev/null
+++ b/lib/libc/posix1e/acl_from_text.3
@@ -0,0 +1,130 @@
+.\"-
+.\" Copyright (c) 2000, 2002 Robert N. M. Watson
+.\" All rights reserved.
+.\"
+.\" This software was developed by Robert Watson for the TrustedBSD Project.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd January 28, 2000
+.Dt ACL_FROM_TEXT 3
+.Os
+.Sh NAME
+.Nm acl_from_text
+.Nd create an ACL from text
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft acl_t
+.Fn acl_from_text "const char *buf_p"
+.Sh DESCRIPTION
+The
+.Fn acl_from_text
+function converts the text form of an ACL referred to by
+.Va buf_p
+into the internal working structure for ACLs, appropriate for applying to
+files or manipulating.
+.Pp
+This function may cause memory to be allocated.
+The caller should free any
+releasable memory, when the new ACL is no longer required, by calling
+.Xr acl_free 3
+with the
+.Va (void *)acl_t
+as an argument.
+.Sh IMPLEMENTATION NOTES
+.Fx Ns 's
+support for POSIX.1e interfaces and features is still under
+development at this time.
+.Sh RETURN VALUES
+Upon successful completion, the function shall return a pointer to the
+internal representation of the ACL in working storage.
+Otherwise, a value
+of
+.Va (acl_t)NULL
+shall be returned, and
+.Va errno
+shall be set to indicate the error.
+.Sh ERRORS
+If any of the following conditions occur, the
+.Fn acl_from_text
+function shall return a value of
+.Va (acl_t)NULL
+and set
+.Va errno
+to the corresponding value:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Va buf_p
+cannot be translated into an ACL.
+.It Bq Er ENOMEM
+The ACL working storage requires more memory than is allowed by the
+hardware or system-imposed memory management constraints.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_free 3 ,
+.Xr acl_get 3 ,
+.Xr acl_to_text 3 ,
+.Xr posix1e 3
+.Sh STANDARDS
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+Discussion
+of the draft continues on the cross-platform POSIX.1e implementation
+mailing list.
+To join this list, see the
+.Fx
+POSIX.1e implementation
+page for more information.
+.Sh HISTORY
+POSIX.1e support was introduced in
+.Fx 4.0 ,
+and development continues.
+.Sh AUTHORS
+.An Robert N M Watson
+.Sh BUGS
+The
+.Fn acl_from_text
+and
+.Fn acl_to_text
+functions
+rely on the
+.Xr getpwent 3
+library calls to manage username and uid mapping, as well as the
+.Xr getgrent 3
+library calls to manage groupname and gid mapping.
+These calls are not
+thread safe, and so transitively, neither are
+.Fn acl_from_text
+and
+.Fn acl_to_text .
+These functions may also interfere with stateful
+calls associated with the
+.Fn getpwent
+and
+.Fn getgrent
+calls.
diff --git a/lib/libc/posix1e/acl_from_text.c b/lib/libc/posix1e/acl_from_text.c
new file mode 100644
index 000000000000..7f15463e50de
--- /dev/null
+++ b/lib/libc/posix1e/acl_from_text.c
@@ -0,0 +1,313 @@
+/*-
+ * Copyright (c) 1999, 2000, 2001 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * acl_from_text: Convert a text-form ACL from a string to an acl_t.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include "namespace.h"
+#include <sys/acl.h>
+#include "un-namespace.h"
+#include <sys/errno.h>
+#include <grp.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "acl_support.h"
+
+static acl_tag_t acl_string_to_tag(char *tag, char *qualifier);
+
+int _nfs4_acl_entry_from_text(acl_t aclp, char *entry);
+int _text_could_be_nfs4_acl(const char *entry);
+
+static acl_tag_t
+acl_string_to_tag(char *tag, char *qualifier)
+{
+
+ if (*qualifier == '\0') {
+ if ((!strcmp(tag, "user")) || (!strcmp(tag, "u"))) {
+ return (ACL_USER_OBJ);
+ } else
+ if ((!strcmp(tag, "group")) || (!strcmp(tag, "g"))) {
+ return (ACL_GROUP_OBJ);
+ } else
+ if ((!strcmp(tag, "mask")) || (!strcmp(tag, "m"))) {
+ return (ACL_MASK);
+ } else
+ if ((!strcmp(tag, "other")) || (!strcmp(tag, "o"))) {
+ return (ACL_OTHER);
+ } else
+ return(-1);
+ } else {
+ if ((!strcmp(tag, "user")) || (!strcmp(tag, "u"))) {
+ return(ACL_USER);
+ } else
+ if ((!strcmp(tag, "group")) || (!strcmp(tag, "g"))) {
+ return(ACL_GROUP);
+ } else
+ return(-1);
+ }
+}
+
+static int
+_posix1e_acl_entry_from_text(acl_t aclp, char *entry)
+{
+ acl_tag_t t;
+ acl_perm_t p;
+ char *tag, *qualifier, *permission;
+ uid_t id;
+ int error;
+
+ assert(_acl_brand(aclp) == ACL_BRAND_POSIX);
+
+ /* Split into three ':' delimited fields. */
+ tag = strsep(&entry, ":");
+ if (tag == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+ tag = string_skip_whitespace(tag);
+ if ((*tag == '\0') && (!entry)) {
+ /*
+ * Is an entirely comment line, skip to next
+ * comma.
+ */
+ return (0);
+ }
+ string_trim_trailing_whitespace(tag);
+
+ qualifier = strsep(&entry, ":");
+ if (qualifier == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+ qualifier = string_skip_whitespace(qualifier);
+ string_trim_trailing_whitespace(qualifier);
+
+ permission = strsep(&entry, ":");
+ if (permission == NULL || entry) {
+ errno = EINVAL;
+ return (-1);
+ }
+ permission = string_skip_whitespace(permission);
+ string_trim_trailing_whitespace(permission);
+
+ t = acl_string_to_tag(tag, qualifier);
+ if (t == -1) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ error = _posix1e_acl_string_to_perm(permission, &p);
+ if (error == -1) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ switch(t) {
+ case ACL_USER_OBJ:
+ case ACL_GROUP_OBJ:
+ case ACL_MASK:
+ case ACL_OTHER:
+ if (*qualifier != '\0') {
+ errno = EINVAL;
+ return (-1);
+ }
+ id = 0;
+ break;
+
+ case ACL_USER:
+ case ACL_GROUP:
+ error = _acl_name_to_id(t, qualifier, &id);
+ if (error == -1)
+ return (-1);
+ break;
+
+ default:
+ errno = EINVAL;
+ return (-1);
+ }
+
+ error = _posix1e_acl_add_entry(aclp, t, id, p);
+ if (error == -1)
+ return (-1);
+
+ return (0);
+}
+
+static int
+_text_is_nfs4_entry(const char *entry)
+{
+ int count = 0;
+
+ assert(strlen(entry) > 0);
+
+ while (*entry != '\0') {
+ if (*entry == ':' || *entry == '@')
+ count++;
+ entry++;
+ }
+
+ if (count <= 2)
+ return (0);
+
+ return (1);
+}
+
+/*
+ * acl_from_text -- Convert a string into an ACL.
+ * Postpone most validity checking until the end and call acl_valid() to do
+ * that.
+ */
+acl_t
+acl_from_text(const char *buf_p)
+{
+ acl_t acl;
+ char *mybuf_p, *line, *cur, *notcomment, *comment, *entry;
+ int error;
+
+ /* Local copy we can mess up. */
+ mybuf_p = strdup(buf_p);
+ if (mybuf_p == NULL)
+ return(NULL);
+
+ acl = acl_init(3); /* XXX: WTF, 3? */
+ if (acl == NULL) {
+ free(mybuf_p);
+ return(NULL);
+ }
+
+ /* Outer loop: delimit at \n boundaries. */
+ cur = mybuf_p;
+ while ((line = strsep(&cur, "\n"))) {
+ /* Now split the line on the first # to strip out comments. */
+ comment = line;
+ notcomment = strsep(&comment, "#");
+
+ /* Inner loop: delimit at ',' boundaries. */
+ while ((entry = strsep(&notcomment, ","))) {
+
+ /* Skip empty lines. */
+ if (strlen(string_skip_whitespace(entry)) == 0)
+ continue;
+
+ if (_acl_brand(acl) == ACL_BRAND_UNKNOWN) {
+ if (_text_is_nfs4_entry(entry))
+ _acl_brand_as(acl, ACL_BRAND_NFS4);
+ else
+ _acl_brand_as(acl, ACL_BRAND_POSIX);
+ }
+
+ switch (_acl_brand(acl)) {
+ case ACL_BRAND_NFS4:
+ error = _nfs4_acl_entry_from_text(acl, entry);
+ break;
+
+ case ACL_BRAND_POSIX:
+ error = _posix1e_acl_entry_from_text(acl, entry);
+ break;
+
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ if (error)
+ goto error_label;
+ }
+ }
+
+#if 0
+ /* XXX Should we only return ACLs valid according to acl_valid? */
+ /* Verify validity of the ACL we read in. */
+ if (acl_valid(acl) == -1) {
+ errno = EINVAL;
+ goto error_label;
+ }
+#endif
+
+ free(mybuf_p);
+ return(acl);
+
+error_label:
+ acl_free(acl);
+ free(mybuf_p);
+ return(NULL);
+}
+
+/*
+ * Given a username/groupname from a text form of an ACL, return the uid/gid
+ * XXX NOT THREAD SAFE, RELIES ON GETPWNAM, GETGRNAM
+ * XXX USES *PW* AND *GR* WHICH ARE STATEFUL AND THEREFORE THIS ROUTINE
+ * MAY HAVE SIDE-EFFECTS
+ */
+int
+_acl_name_to_id(acl_tag_t tag, char *name, uid_t *id)
+{
+ struct group *g;
+ struct passwd *p;
+ unsigned long l;
+ char *endp;
+
+ switch(tag) {
+ case ACL_USER:
+ p = getpwnam(name);
+ if (p == NULL) {
+ l = strtoul(name, &endp, 0);
+ if (*endp != '\0' || l != (unsigned long)(uid_t)l) {
+ errno = EINVAL;
+ return (-1);
+ }
+ *id = (uid_t)l;
+ return (0);
+ }
+ *id = p->pw_uid;
+ return (0);
+
+ case ACL_GROUP:
+ g = getgrnam(name);
+ if (g == NULL) {
+ l = strtoul(name, &endp, 0);
+ if (*endp != '\0' || l != (unsigned long)(gid_t)l) {
+ errno = EINVAL;
+ return (-1);
+ }
+ *id = (gid_t)l;
+ return (0);
+ }
+ *id = g->gr_gid;
+ return (0);
+
+ default:
+ return (EINVAL);
+ }
+}
diff --git a/lib/libc/posix1e/acl_from_text_nfs4.c b/lib/libc/posix1e/acl_from_text_nfs4.c
new file mode 100644
index 000000000000..5a0b36ab93a3
--- /dev/null
+++ b/lib/libc/posix1e/acl_from_text_nfs4.c
@@ -0,0 +1,283 @@
+/*-
+ * Copyright (c) 2008, 2009 Edward Tomasz Napierała <trasz@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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <assert.h>
+#include <string.h>
+#include <pwd.h>
+#include <grp.h>
+#include <ctype.h>
+#include <err.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/acl.h>
+
+#include "acl_support.h"
+
+#define MAX_ENTRY_LENGTH 512
+
+/*
+ * Parse the tag field of ACL entry passed as "str". If qualifier
+ * needs to follow, then the variable referenced by "need_qualifier"
+ * is set to 1, otherwise it's set to 0.
+ */
+static int
+parse_tag(const char *str, acl_entry_t entry, int *need_qualifier)
+{
+
+ assert(need_qualifier != NULL);
+ *need_qualifier = 0;
+
+ if (strcmp(str, "owner@") == 0)
+ return (acl_set_tag_type(entry, ACL_USER_OBJ));
+ if (strcmp(str, "group@") == 0)
+ return (acl_set_tag_type(entry, ACL_GROUP_OBJ));
+ if (strcmp(str, "everyone@") == 0)
+ return (acl_set_tag_type(entry, ACL_EVERYONE));
+
+ *need_qualifier = 1;
+
+ if (strcmp(str, "user") == 0 || strcmp(str, "u") == 0)
+ return (acl_set_tag_type(entry, ACL_USER));
+ if (strcmp(str, "group") == 0 || strcmp(str, "g") == 0)
+ return (acl_set_tag_type(entry, ACL_GROUP));
+
+ warnx("malformed ACL: invalid \"tag\" field");
+
+ return (-1);
+}
+
+/*
+ * Parse the qualifier field of ACL entry passed as "str".
+ * If user or group name cannot be resolved, then the variable
+ * referenced by "need_qualifier" is set to 1; it will be checked
+ * later to figure out whether the appended_id is required.
+ */
+static int
+parse_qualifier(char *str, acl_entry_t entry, int *need_qualifier)
+{
+ int qualifier_length, error;
+ uid_t id;
+ acl_tag_t tag;
+
+ assert(need_qualifier != NULL);
+ *need_qualifier = 0;
+
+ qualifier_length = strlen(str);
+
+ if (qualifier_length == 0) {
+ warnx("malformed ACL: empty \"qualifier\" field");
+ return (-1);
+ }
+
+ error = acl_get_tag_type(entry, &tag);
+ if (error)
+ return (error);
+
+ error = _acl_name_to_id(tag, str, &id);
+ if (error) {
+ *need_qualifier = 1;
+ return (0);
+ }
+
+ return (acl_set_qualifier(entry, &id));
+}
+
+static int
+parse_access_mask(char *str, acl_entry_t entry)
+{
+ int error;
+ acl_perm_t perm;
+
+ error = _nfs4_parse_access_mask(str, &perm);
+ if (error)
+ return (error);
+
+ error = acl_set_permset(entry, &perm);
+
+ return (error);
+}
+
+static int
+parse_flags(char *str, acl_entry_t entry)
+{
+ int error;
+ acl_flag_t flags;
+
+ error = _nfs4_parse_flags(str, &flags);
+ if (error)
+ return (error);
+
+ error = acl_set_flagset_np(entry, &flags);
+
+ return (error);
+}
+
+static int
+parse_entry_type(const char *str, acl_entry_t entry)
+{
+
+ if (strcmp(str, "allow") == 0)
+ return (acl_set_entry_type_np(entry, ACL_ENTRY_TYPE_ALLOW));
+ if (strcmp(str, "deny") == 0)
+ return (acl_set_entry_type_np(entry, ACL_ENTRY_TYPE_DENY));
+ if (strcmp(str, "audit") == 0)
+ return (acl_set_entry_type_np(entry, ACL_ENTRY_TYPE_AUDIT));
+ if (strcmp(str, "alarm") == 0)
+ return (acl_set_entry_type_np(entry, ACL_ENTRY_TYPE_ALARM));
+
+ warnx("malformed ACL: invalid \"type\" field");
+
+ return (-1);
+}
+
+static int
+parse_appended_id(char *str, acl_entry_t entry)
+{
+ int qualifier_length;
+ char *end;
+ id_t id;
+
+ qualifier_length = strlen(str);
+ if (qualifier_length == 0) {
+ warnx("malformed ACL: \"appended id\" field present, "
+ "but empty");
+ return (-1);
+ }
+
+ id = strtod(str, &end);
+ if (end - str != qualifier_length) {
+ warnx("malformed ACL: appended id is not a number");
+ return (-1);
+ }
+
+ return (acl_set_qualifier(entry, &id));
+}
+
+static int
+number_of_colons(const char *str)
+{
+ int count = 0;
+
+ while (*str != '\0') {
+ if (*str == ':')
+ count++;
+
+ str++;
+ }
+
+ return (count);
+}
+
+int
+_nfs4_acl_entry_from_text(acl_t aclp, char *str)
+{
+ int error, need_qualifier;
+ acl_entry_t entry;
+ char *field, *qualifier_field;
+
+ error = acl_create_entry(&aclp, &entry);
+ if (error)
+ return (error);
+
+ assert(_entry_brand(entry) == ACL_BRAND_NFS4);
+
+ if (str == NULL)
+ goto truncated_entry;
+ field = strsep(&str, ":");
+
+ field = string_skip_whitespace(field);
+ if ((*field == '\0') && (!str)) {
+ /*
+ * Is an entirely comment line, skip to next
+ * comma.
+ */
+ return (0);
+ }
+
+ error = parse_tag(field, entry, &need_qualifier);
+ if (error)
+ goto malformed_field;
+
+ if (need_qualifier) {
+ if (str == NULL)
+ goto truncated_entry;
+ qualifier_field = field = strsep(&str, ":");
+ error = parse_qualifier(field, entry, &need_qualifier);
+ if (error)
+ goto malformed_field;
+ }
+
+ if (str == NULL)
+ goto truncated_entry;
+ field = strsep(&str, ":");
+ error = parse_access_mask(field, entry);
+ if (error)
+ goto malformed_field;
+
+ if (str == NULL)
+ goto truncated_entry;
+ /* Do we have "flags" field? */
+ if (number_of_colons(str) > 0) {
+ field = strsep(&str, ":");
+ error = parse_flags(field, entry);
+ if (error)
+ goto malformed_field;
+ }
+
+ if (str == NULL)
+ goto truncated_entry;
+ field = strsep(&str, ":");
+ error = parse_entry_type(field, entry);
+ if (error)
+ goto malformed_field;
+
+ if (need_qualifier) {
+ if (str == NULL) {
+ warnx("malformed ACL: unknown user or group name "
+ "\"%s\"", qualifier_field);
+ goto truncated_entry;
+ }
+
+ error = parse_appended_id(str, entry);
+ if (error)
+ goto malformed_field;
+ }
+
+ return (0);
+
+truncated_entry:
+malformed_field:
+ acl_delete_entry(aclp, entry);
+ errno = EINVAL;
+ return (-1);
+}
diff --git a/lib/libc/posix1e/acl_get.3 b/lib/libc/posix1e/acl_get.3
new file mode 100644
index 000000000000..ae0c48d93822
--- /dev/null
+++ b/lib/libc/posix1e/acl_get.3
@@ -0,0 +1,168 @@
+.\"-
+.\" Copyright (c) 2000, 2002 Robert N. M. Watson
+.\" All rights reserved.
+.\"
+.\" This software was developed by Robert Watson for the TrustedBSD Project.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd June 25, 2009
+.Dt ACL_GET 3
+.Os
+.Sh NAME
+.Nm acl_get_fd ,
+.Nm acl_get_fd_np ,
+.Nm acl_get_file ,
+.Nm acl_get_link_np
+.Nd get an ACL for a file
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft acl_t
+.Fn acl_get_fd "int fd"
+.Ft acl_t
+.Fn acl_get_fd_np "int fd" "acl_type_t type"
+.Ft acl_t
+.Fn acl_get_file "const char *path_p" "acl_type_t type"
+.Ft acl_t
+.Fn acl_get_link_np "const char *path_p" "acl_type_t type"
+.Sh DESCRIPTION
+The
+.Fn acl_get_fd ,
+.Fn acl_get_file ,
+.Fn acl_get_link_np ,
+and
+.Fn acl_get_fd_np
+each allow the retrieval of an ACL from a file.
+The
+.Fn acl_get_fd
+is a POSIX.1e call that allows the retrieval of an ACL of type
+ACL_TYPE_ACCESS
+from a file descriptor.
+The
+.Fn acl_get_fd_np
+function
+is a non-portable form of
+.Fn acl_get_fd
+that allows the retrieval of any type of ACL from a file descriptor.
+The
+.Fn acl_get_file
+function is a POSIX.1e call that allows the retrieval of a
+specified type of ACL from a file by name;
+.Fn acl_get_link_np
+is a non-portable variation on
+.Fn acl_get_file
+which does not follow a symlink if the target of the call is a
+symlink.
+.Pp
+These functions may cause memory to be allocated.
+The caller should free
+any releasable memory, when the new ACL is no longer required, by calling
+.Xr acl_free 3
+with the
+.Va (void *)acl_t
+as an argument.
+.Pp
+The ACL in the working storage is an independent copy of the ACL associated
+with the object referred to by
+.Va fd .
+The ACL in the working storage shall not participate in any access control
+decisions.
+.Pp
+Valid values for the
+.Va type
+argument are:
+.Bl -column -offset 3n "ACL_TYPE_DEFAULT"
+.It ACL_TYPE_ACCESS POSIX.1e access ACL
+.It ACL_TYPE_DEFAULT POSIX.1e default ACL
+.It ACL_TYPE_NFS4 NFSv4 ACL
+.El
+.Pp
+The ACL returned will be branded accordingly.
+.Sh IMPLEMENTATION NOTES
+.Fx Ns 's
+support for POSIX.1e interfaces and features is still under
+development at this time.
+.Sh RETURN VALUES
+Upon successful completion, the function shall return a pointer to the ACL
+that was retrieved.
+Otherwise, a value of
+.Va (acl_t)NULL
+shall be returned, and
+.Va errno
+shall be set to indicate the error.
+.Sh ERRORS
+If any of the following conditions occur, the
+.Fn acl_get_fd
+function shall return a value of
+.Va (acl_t)NULL
+and set
+.Va errno
+to the corresponding value:
+.Bl -tag -width Er
+.It Bq Er EACCES
+Search permission is denied for a component of the path prefix, or the
+object exists and the process does not have appropriate access rights.
+.It Bq Er EBADF
+The
+.Va fd
+argument is not a valid file descriptor.
+.It Bq Er EINVAL
+The ACL type passed is invalid for this file object.
+.It Bq Er ENAMETOOLONG
+A component of a pathname exceeded 255 characters, or an
+entire path name exceeded 1023 characters.
+.It Bq Er ENOENT
+The named object does not exist, or the
+.Va path_p
+argument points to an empty string.
+.It Bq Er ENOMEM
+Insufficient memory available to fulfill request.
+.It Bq Er EOPNOTSUPP
+The file system does not support ACL retrieval.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_free 3 ,
+.Xr acl_get 3 ,
+.Xr acl_get_brand_np 3 ,
+.Xr acl_set 3 ,
+.Xr posix1e 3
+.Sh STANDARDS
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+Discussion
+of the draft continues on the cross-platform POSIX.1e implementation
+mailing list.
+To join this list, see the
+.Fx
+POSIX.1e implementation
+page for more information.
+.Sh HISTORY
+POSIX.1e support was introduced in
+.Fx 4.0 ,
+and development continues.
+.Sh AUTHORS
+.An Robert N M Watson
diff --git a/lib/libc/posix1e/acl_get.c b/lib/libc/posix1e/acl_get.c
new file mode 100644
index 000000000000..b3235016ed1a
--- /dev/null
+++ b/lib/libc/posix1e/acl_get.c
@@ -0,0 +1,216 @@
+/*-
+ * Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * This software was developed by Robert Watson for the TrustedBSD Project.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * acl_get_fd - syscall wrapper for retrieving access ACL by fd
+ * acl_get_fd_np - syscall wrapper for retrieving ACL by fd (non-POSIX)
+ * acl_get_file - syscall wrapper for retrieving ACL by filename
+ * acl_get_link_np - syscall wrapper for retrieving ACL by filename (NOFOLLOW)
+ * (non-POSIX)
+ * acl_get_perm_np() checks if a permission is in the specified
+ * permset (non-POSIX)
+ * acl_get_permset() returns the permission set in the ACL entry
+ * acl_get_qualifier() retrieves the qualifier of the tag from the ACL entry
+ * acl_get_tag_type() returns the tag type for the ACL entry entry_d
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include "namespace.h"
+#include <sys/acl.h>
+#include "un-namespace.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "acl_support.h"
+
+acl_t
+acl_get_file(const char *path_p, acl_type_t type)
+{
+ acl_t aclp;
+ int error;
+
+ aclp = acl_init(ACL_MAX_ENTRIES);
+ if (aclp == NULL)
+ return (NULL);
+
+ type = _acl_type_unold(type);
+ error = __acl_get_file(path_p, type, &aclp->ats_acl);
+ if (error) {
+ acl_free(aclp);
+ return (NULL);
+ }
+
+ aclp->ats_acl.acl_maxcnt = ACL_MAX_ENTRIES;
+ _acl_brand_from_type(aclp, type);
+
+ return (aclp);
+}
+
+acl_t
+acl_get_link_np(const char *path_p, acl_type_t type)
+{
+ acl_t aclp;
+ int error;
+
+ aclp = acl_init(ACL_MAX_ENTRIES);
+ if (aclp == NULL)
+ return (NULL);
+
+ type = _acl_type_unold(type);
+ error = __acl_get_link(path_p, type, &aclp->ats_acl);
+ if (error) {
+ acl_free(aclp);
+ return (NULL);
+ }
+
+ aclp->ats_acl.acl_maxcnt = ACL_MAX_ENTRIES;
+ _acl_brand_from_type(aclp, type);
+
+ return (aclp);
+}
+
+acl_t
+acl_get_fd(int fd)
+{
+ if (fpathconf(fd, _PC_ACL_NFS4) == 1)
+ return (acl_get_fd_np(fd, ACL_TYPE_NFS4));
+
+ return (acl_get_fd_np(fd, ACL_TYPE_ACCESS));
+}
+
+acl_t
+acl_get_fd_np(int fd, acl_type_t type)
+{
+ acl_t aclp;
+ int error;
+
+ aclp = acl_init(ACL_MAX_ENTRIES);
+ if (aclp == NULL)
+ return (NULL);
+
+ type = _acl_type_unold(type);
+ error = ___acl_get_fd(fd, type, &aclp->ats_acl);
+ if (error) {
+ acl_free(aclp);
+ return (NULL);
+ }
+
+ aclp->ats_acl.acl_maxcnt = ACL_MAX_ENTRIES;
+ _acl_brand_from_type(aclp, type);
+
+ return (aclp);
+}
+
+/*
+ * acl_get_permset() (23.4.17): return via permset_p a descriptor to
+ * the permission set in the ACL entry entry_d.
+ */
+int
+acl_get_permset(acl_entry_t entry_d, acl_permset_t *permset_p)
+{
+
+ if (entry_d == NULL || permset_p == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ *permset_p = &entry_d->ae_perm;
+
+ return (0);
+}
+
+/*
+ * acl_get_qualifier() (23.4.18): retrieve the qualifier of the tag
+ * for the ACL entry entry_d.
+ */
+void *
+acl_get_qualifier(acl_entry_t entry_d)
+{
+ uid_t *retval;
+
+ if (entry_d == NULL) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ switch(entry_d->ae_tag) {
+ case ACL_USER:
+ case ACL_GROUP:
+ retval = malloc(sizeof(uid_t));
+ if (retval == NULL)
+ return (NULL);
+ *retval = entry_d->ae_id;
+ return (retval);
+ }
+
+ errno = EINVAL;
+ return (NULL);
+}
+
+/*
+ * acl_get_tag_type() (23.4.19): return the tag type for the ACL
+ * entry entry_p.
+ */
+int
+acl_get_tag_type(acl_entry_t entry_d, acl_tag_t *tag_type_p)
+{
+
+ if (entry_d == NULL || tag_type_p == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ *tag_type_p = entry_d->ae_tag;
+
+ return (0);
+}
+
+int
+acl_get_entry_type_np(acl_entry_t entry_d, acl_entry_type_t *entry_type_p)
+{
+
+ if (entry_d == NULL || entry_type_p == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (!_entry_brand_may_be(entry_d, ACL_BRAND_NFS4)) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ *entry_type_p = entry_d->ae_entry_type;
+
+ return (0);
+}
diff --git a/lib/libc/posix1e/acl_get_brand_np.3 b/lib/libc/posix1e/acl_get_brand_np.3
new file mode 100644
index 000000000000..44b83e23293c
--- /dev/null
+++ b/lib/libc/posix1e/acl_get_brand_np.3
@@ -0,0 +1,86 @@
+.\"-
+.\" Copyright (c) 2008, 2009 Edward Tomasz Napierala
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd June 25, 2009
+.Dt ACL_GET_BRAND_NP 3
+.Os
+.Sh NAME
+.Nm acl_get_brand_np
+.Nd retrieve the ACL brand from an ACL entry
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_get_brand_np "acl_t acl" "int *brand_p"
+.Sh DESCRIPTION
+The
+.Fn acl_get_brand_np
+function
+is a non-portable call that returns the ACL brand for the ACL
+.Fa acl .
+Upon successful completion, the location referred to by the argument
+.Fa brand_p
+will be set to the ACL brand of the ACL
+.Fa acl .
+.Pp
+Branding is an internal mechanism intended to prevent mixing POSIX.1e
+and NFSv4 entries by mistake.
+It's also used by the libc to determine how to print out the ACL.
+The first call to function that is specific for one particular brand - POSIX.1e
+or NFSv4 - "brands" the ACL.
+After that, calling function specific to another brand will result in error.
+.Sh RETURN VALUES
+.Rv -std acl_get_brand_np
+.Sh ERRORS
+The
+.Fn acl_get_brand_np
+function fails if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Fa acl
+does not point to a valid ACL.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr posix1e 3
+.Sh STANDARDS
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+.Sh HISTORY
+POSIX.1e support was introduced in
+.Fx 4.0 .
+The
+.Fn acl_get_brand_np
+function was added in
+.Fx 8.0 .
+.Sh AUTHORS
+The
+.Fn acl_get_brand_np
+function was written by
+.An Edward Tomasz Napierala Aq Mt trasz@FreeBSD.org .
diff --git a/lib/libc/posix1e/acl_get_entry.3 b/lib/libc/posix1e/acl_get_entry.3
new file mode 100644
index 000000000000..88c72db2559a
--- /dev/null
+++ b/lib/libc/posix1e/acl_get_entry.3
@@ -0,0 +1,145 @@
+.\"-
+.\" Copyright (c) 2001 Chris D. Faulhaber
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 April 13, 2001
+.Dt ACL_GET_ENTRY 3
+.Os
+.Sh NAME
+.Nm acl_get_entry
+.Nd retrieve an ACL entry from an ACL
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_get_entry "acl_t acl" "int entry_id" "acl_entry_t *entry_p"
+.Sh DESCRIPTION
+The
+.Fn acl_get_entry
+function
+is a POSIX.1e call that retrieves a descriptor for an ACL entry
+specified by the argument
+.Fa entry_d
+within the ACL indicated by the argument
+.Fa acl .
+.Pp
+If the value of
+.Fa entry_id
+is
+.Dv ACL_FIRST_ENTRY ,
+then the function will return in
+.Fa entry_p
+a descriptor for the first ACL entry within
+.Fa acl .
+If a call is made to
+.Fn acl_get_entry
+with
+.Fa entry_id
+set to
+.Dv ACL_NEXT_ENTRY
+when there has not been either an initial successful call to
+.Fn acl_get_entry ,
+or a previous successful call to
+.Fn acl_create_entry ,
+.Fn acl_delete_entry ,
+.Fn acl_dup ,
+.Fn acl_from_text ,
+.Fn acl_get_fd ,
+.Fn acl_get_file ,
+.Fn acl_set_fd ,
+.Fn acl_set_file ,
+or
+.Fn acl_valid ,
+then the result is unspecified.
+.Sh RETURN VALUES
+If the
+.Fn acl_get_entry
+function successfully obtains an ACL entry, a value of 1 is returned.
+If the ACL has no ACL entries, the
+.Fn acl_get_entry
+returns a value of 0.
+If the value of
+.Fa entry_id
+is
+.Dv ACL_NEXT_ENTRY
+and the last ACL entry in the ACL has already been returned by a
+previous call to
+.Fn acl_get_entry ,
+a value of 0 will be returned until a successful call with
+.Fa entry_id
+of
+.Dv ACL_FIRST_ENTRY
+is made.
+Otherwise, a value of -1 will be returned and
+the global variable
+.Va errno
+will be set to indicate the error.
+.Sh ERRORS
+The
+.Fn acl_get_entry
+fails if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Fa acl
+does not point to a valid ACL.
+Argument
+.Fa entry_id
+is neither
+.Dv ACL_FIRST_ENTRY
+nor
+.Dv ACL_NEXT_ENTRY .
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_calc_mask 3 ,
+.Xr acl_create_entry 3 ,
+.Xr acl_delete_entry 3 ,
+.Xr acl_dup 3 ,
+.Xr acl_from_text 3 ,
+.Xr acl_get_fd 3 ,
+.Xr acl_get_file 3 ,
+.Xr acl_init 3 ,
+.Xr acl_set_fd 3 ,
+.Xr acl_set_file 3 ,
+.Xr acl_valid 3 ,
+.Xr posix1e 3
+.Sh STANDARDS
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+.Sh HISTORY
+POSIX.1e support was introduced in
+.Fx 4.0 .
+The
+.Fn acl_get_entry
+function was added in
+.Fx 5.0 .
+.Sh AUTHORS
+The
+.Fn acl_get_entry
+function was written by
+.An Chris D. Faulhaber Aq Mt jedgar@fxp.org .
diff --git a/lib/libc/posix1e/acl_get_entry_type_np.3 b/lib/libc/posix1e/acl_get_entry_type_np.3
new file mode 100644
index 000000000000..6313d0607c7d
--- /dev/null
+++ b/lib/libc/posix1e/acl_get_entry_type_np.3
@@ -0,0 +1,80 @@
+.\"-
+.\" Copyright (c) 2008, 2009 Edward Tomasz Napierala
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd June 25, 2009
+.Dt ACL_GET_ENTRY_TYPE_NP 3
+.Os
+.Sh NAME
+.Nm acl_get_entry_type_np
+.Nd retrieve the ACL type from an NFSv4 ACL entry
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_get_entry_type_np "acl_entry_t entry_d" "acl_entry_type_t *entry_type_p"
+.Sh DESCRIPTION
+The
+.Fn acl_get_entry_type_np
+function
+is a non-portable call that returns the ACL type for the NFSv4 ACL entry
+.Fa entry_d .
+Upon successful completion, the location referred to by the argument
+.Fa entry_type_p
+will be set to the ACL type of the ACL entry
+.Fa entry_d .
+.Sh RETURN VALUES
+.Rv -std acl_get_entry_type_np
+.Sh ERRORS
+The
+.Fn acl_get_entry_type_np
+function fails if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Fa entry_d
+is not a valid descriptor for an NFSv4 ACL entry;
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_set_entry_type_np 3 ,
+.Xr posix1e 3
+.Sh STANDARDS
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+.Sh HISTORY
+POSIX.1e support was introduced in
+.Fx 4.0 .
+The
+.Fn acl_get_entry_type_np
+function was added in
+.Fx 8.0 .
+.Sh AUTHORS
+The
+.Fn acl_get_entry_type_np
+function was written by
+.An Edward Tomasz Napierala Aq Mt trasz@FreeBSD.org .
diff --git a/lib/libc/posix1e/acl_get_flag_np.3 b/lib/libc/posix1e/acl_get_flag_np.3
new file mode 100644
index 000000000000..f7ee5d71ddb0
--- /dev/null
+++ b/lib/libc/posix1e/acl_get_flag_np.3
@@ -0,0 +1,94 @@
+.\"-
+.\" Copyright (c) 2008, 2009 Edward Tomasz Napierala
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd October 30, 2014
+.Dt ACL_GET_FLAG_NP 3
+.Os
+.Sh NAME
+.Nm acl_get_flag_np
+.Nd check if a flag is set in a flagset
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_get_flag_np "acl_flagset_t flagset_d" "acl_flag_t flag"
+.Sh DESCRIPTION
+The
+.Fn acl_get_flag_np
+function
+is a non-portable function that checks if a NFSv4 ACL flag is set in
+a flagset.
+.Sh RETURN VALUES
+If the flag in
+.Fa flag
+is set in the flagset
+.Fa flagset_d ,
+a value of
+1
+is returned, otherwise a value of
+0
+is returned.
+.Sh ERRORS
+If any of the following conditions occur, the
+.Fn acl_get_flag_np
+function will return a value of
+\-1
+and set global variable
+.Va errno
+to the corresponding value:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Fa flag
+does not contain a valid ACL flag or argument
+.Fa flagset_d
+is not a valid ACL flagset.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_add_flag_np 3 ,
+.Xr acl_clear_flags_np 3 ,
+.Xr acl_delete_flag_np 3 ,
+.Xr acl_get_flagset_np 3 ,
+.Xr acl_set_flagset_np 3 ,
+.Xr posix1e 3
+.Sh STANDARDS
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+.Sh HISTORY
+POSIX.1e support was introduced in
+.Fx 4.0 .
+The
+.Fn acl_get_flag_np
+function was added in
+.Fx 8.0 .
+.Sh AUTHORS
+The
+.Fn acl_get_flag_np
+function was written by
+.An Edward Tomasz Napierala Aq Mt trasz@FreeBSD.org .
diff --git a/lib/libc/posix1e/acl_get_flagset_np.3 b/lib/libc/posix1e/acl_get_flagset_np.3
new file mode 100644
index 000000000000..31573c1760c3
--- /dev/null
+++ b/lib/libc/posix1e/acl_get_flagset_np.3
@@ -0,0 +1,83 @@
+.\"-
+.\" Copyright (c) 2008, 2009 Edward Tomasz Napierala
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd October 30, 2014
+.Dt ACL_GET_FLAGSET_NP 3
+.Os
+.Sh NAME
+.Nm acl_get_flagset_np
+.Nd retrieve flagset from an NFSv4 ACL entry
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_get_flagset_np "acl_entry_t entry_d" "acl_flagset_t *flagset_p"
+.Sh DESCRIPTION
+The
+.Fn acl_get_flagset_np
+function
+is a non-portable call that returns via
+.Fa flagset_np_p
+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.
+.Sh RETURN VALUES
+.Rv -std acl_get_flagset_np
+.Sh ERRORS
+The
+.Fn acl_get_flagset_np
+function fails if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Fa entry_d
+is not a valid descriptor for an ACL entry.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_add_flag_np 3 ,
+.Xr acl_clear_flags_np 3 ,
+.Xr acl_delete_flag_np 3 ,
+.Xr acl_set_flagset_np 3 ,
+.Xr posix1e 3
+.Sh STANDARDS
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+.Sh HISTORY
+POSIX.1e support was introduced in
+.Fx 4.0 .
+The
+.Fn acl_get_flagset_np
+function was added in
+.Fx 8.0 .
+.Sh AUTHORS
+The
+.Fn acl_get_flagset_np
+function was written by
+.An Edward Tomasz Napierala Aq Mt trasz@FreeBSD.org .
diff --git a/lib/libc/posix1e/acl_get_perm_np.3 b/lib/libc/posix1e/acl_get_perm_np.3
new file mode 100644
index 000000000000..0f4126ecbe64
--- /dev/null
+++ b/lib/libc/posix1e/acl_get_perm_np.3
@@ -0,0 +1,94 @@
+.\"-
+.\" Copyright (c) 2001 Chris D. Faulhaber
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 April 10, 2001
+.Dt ACL_GET_PERM_NP 3
+.Os
+.Sh NAME
+.Nm acl_get_perm_np
+.Nd "check if a permission is set in a permission set"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_get_perm_np "acl_permset_t permset_d" "acl_perm_t perm"
+.Sh DESCRIPTION
+The
+.Fn acl_get_perm_np
+function
+is a non-portable function that checks if a permission is set in
+a permission set.
+.Sh RETURN VALUES
+If the permission in
+.Fa perm
+is set in the permission set
+.Fa permset_d ,
+a value of
+1
+is returned, otherwise a value of
+0
+is returned.
+.Sh ERRORS
+If any of the following conditions occur, the
+.Fn acl_get_perm_np
+function will return a value of
+\-1
+and set global variable
+.Va errno
+to the corresponding value:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Fa perm
+does not contain a valid ACL permission or argument
+.Fa permset_d
+is not a valid ACL permset.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_add_perm 3 ,
+.Xr acl_clear_perms 3 ,
+.Xr acl_delete_perm 3 ,
+.Xr acl_get_permset 3 ,
+.Xr acl_set_permset 3 ,
+.Xr posix1e 3
+.Sh STANDARDS
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+.Sh HISTORY
+POSIX.1e support was introduced in
+.Fx 4.0 .
+The
+.Fn acl_get_perm_np
+function was added in
+.Fx 5.0 .
+.Sh AUTHORS
+The
+.Fn acl_get_perm_np
+function was written by
+.An Chris D. Faulhaber Aq Mt jedgar@fxp.org .
diff --git a/lib/libc/posix1e/acl_get_permset.3 b/lib/libc/posix1e/acl_get_permset.3
new file mode 100644
index 000000000000..064f71ce45bc
--- /dev/null
+++ b/lib/libc/posix1e/acl_get_permset.3
@@ -0,0 +1,83 @@
+.\"-
+.\" Copyright (c) 2001 Chris D. Faulhaber
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 March 10, 2001
+.Dt ACL_GET_PERMSET 3
+.Os
+.Sh NAME
+.Nm acl_get_permset
+.Nd retrieve permission set from an ACL entry
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_get_permset "acl_entry_t entry_d" "acl_permset_t *permset_p"
+.Sh DESCRIPTION
+The
+.Fn acl_get_permset
+function
+is a POSIX.1e call that returns via
+.Fa permset_p
+a descriptor to the permission set in the ACL entry
+.Fa entry_d .
+Subsequent operations using the returned permission set operate
+on the permission set within the ACL entry.
+.Sh RETURN VALUES
+.Rv -std acl_get_permset
+.Sh ERRORS
+The
+.Fn acl_get_permset
+function fails if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Fa entry_d
+is not a valid descriptor for an ACL entry.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_add_perm 3 ,
+.Xr acl_clear_perms 3 ,
+.Xr acl_delete_perm 3 ,
+.Xr acl_set_permset 3 ,
+.Xr posix1e 3
+.Sh STANDARDS
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+.Sh HISTORY
+POSIX.1e support was introduced in
+.Fx 4.0 .
+The
+.Fn acl_get_permset
+function was added in
+.Fx 5.0 .
+.Sh AUTHORS
+The
+.Fn acl_get_permset
+function was written by
+.An Chris D. Faulhaber Aq Mt jedgar@fxp.org .
diff --git a/lib/libc/posix1e/acl_get_qualifier.3 b/lib/libc/posix1e/acl_get_qualifier.3
new file mode 100644
index 000000000000..fcafd2cc3bbb
--- /dev/null
+++ b/lib/libc/posix1e/acl_get_qualifier.3
@@ -0,0 +1,140 @@
+.\"-
+.\" Copyright (c) 2001 Chris D. Faulhaber
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 March 13, 2001
+.Dt ACL_GET_QUALIFIER 3
+.Os
+.Sh NAME
+.Nm acl_get_qualifier
+.Nd retrieve the qualifier from an ACL entry
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft void *
+.Fn acl_get_qualifier "acl_entry_t entry_d"
+.Sh DESCRIPTION
+The
+.Fn acl_get_qualifier
+function
+is a POSIX.1e call that retrieves the qualifier of the tag for
+the ACL entry indicated by the argument
+.Fa entry_d
+into working storage and returns a pointer to that storage.
+.Pp
+If the value of the tag type in the ACL entry referred to by
+.Fa entry_d
+is
+.Dv ACL_USER ,
+then the value returned by
+.Fn acl_get_qualifier
+will be a pointer to type
+.Vt uid_t .
+.Pp
+If the value of the tag type in
+the ACL entry referred to by
+.Fa entry_d
+is
+.Dv ACL_GROUP ,
+then the value returned by
+.Fn acl_get_qualifier
+will be a pointer to type
+.Vt gid_t .
+.Pp
+If the value of the tag type in the ACL entry referred to by
+.Fa entry_d
+is
+.Dv ACL_UNDEFINED_TAG , ACL_USER_OBJ , ACL_GROUP_OBJ ,
+.Dv ACL_OTHER , ACL_MASK ,
+or an implementation-defined value for which a qualifier
+is not supported, then
+.Fn acl_get_qualifier
+will return a value of
+.Vt ( void * ) Ns Dv NULL
+and the function will fail.
+.Pp
+This function may cause memory to be allocated.
+The caller should
+free any releasable memory, when the new qualifier is no longer
+required, by calling
+.Fn acl_free
+with
+.Vt void *
+as the argument.
+.Sh RETURN VALUES
+The
+.Fn acl_get_qualifier
+function returns a pointer to the allocated storage if successful;
+otherwise a
+.Dv NULL
+pointer is returned and the global variable
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+The
+.Fn acl_get_qualifier
+fails if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Fa entry_d
+does not point to a valid descriptor for an ACL entry.
+The
+value of the tag type in the ACL entry referenced by argument
+.Fa entry_d
+is not
+.Dv ACL_USER
+or
+.Dv ACL_GROUP .
+.It Bq Er ENOMEM
+The value to be returned requires more memory than is allowed
+by the hardware or system-imposed memory management constraints.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_create_entry 3 ,
+.Xr acl_free 3 ,
+.Xr acl_get_entry 3 ,
+.Xr acl_get_tag_type 3 ,
+.Xr acl_set_qualifier 3 ,
+.Xr acl_set_tag_type 3 ,
+.Xr posix1e 3
+.Sh STANDARDS
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+.Sh HISTORY
+POSIX.1e support was introduced in
+.Fx 4.0 .
+The
+.Fn acl_get_qualifier
+function was added in
+.Fx 5.0 .
+.Sh AUTHORS
+The
+.Fn acl_get_qualifier
+function was written by
+.An Chris D. Faulhaber Aq Mt jedgar@fxp.org .
diff --git a/lib/libc/posix1e/acl_get_tag_type.3 b/lib/libc/posix1e/acl_get_tag_type.3
new file mode 100644
index 000000000000..64c57efed732
--- /dev/null
+++ b/lib/libc/posix1e/acl_get_tag_type.3
@@ -0,0 +1,85 @@
+.\"-
+.\" Copyright (c) 2001 Chris D. Faulhaber
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 March 10, 2001
+.Dt ACL_GET_TAG_TYPE 3
+.Os
+.Sh NAME
+.Nm acl_get_tag_type
+.Nd retrieve the tag type from an ACL entry
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_get_tag_type "acl_entry_t entry_d" "acl_tag_t *tag_type_p"
+.Sh DESCRIPTION
+The
+.Fn acl_get_tag_type
+function
+is a POSIX.1e call that returns the tag type for the ACL entry
+.Fa entry_d .
+Upon successful completion, the location referred to by the argument
+.Fa tag_type_p
+will be set to the tag type of the ACL entry
+.Fa entry_d .
+.Sh RETURN VALUES
+.Rv -std acl_get_tag_type
+.Sh ERRORS
+The
+.Fn acl_get_tag_type
+function fails if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Fa entry_d
+is not a valid descriptor for an ACL entry;
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_create_entry 3 ,
+.Xr acl_get_entry 3 ,
+.Xr acl_get_qualifier 3 ,
+.Xr acl_init 3 ,
+.Xr acl_set_qualifier 3 ,
+.Xr acl_set_tag_type 3 ,
+.Xr posix1e 3
+.Sh STANDARDS
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+.Sh HISTORY
+POSIX.1e support was introduced in
+.Fx 4.0 .
+The
+.Fn acl_get_tag_type
+function was added in
+.Fx 5.0 .
+.Sh AUTHORS
+The
+.Fn acl_get_tag_type
+function was written by
+.An Chris D. Faulhaber Aq Mt jedgar@fxp.org .
diff --git a/lib/libc/posix1e/acl_id_to_name.c b/lib/libc/posix1e/acl_id_to_name.c
new file mode 100644
index 000000000000..aa108098aa87
--- /dev/null
+++ b/lib/libc/posix1e/acl_id_to_name.c
@@ -0,0 +1,100 @@
+/*-
+ * Copyright (c) 1999-2001, 2008 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * Support functionality for the POSIX.1e ACL interface
+ * These calls are intended only to be called within the library.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include "namespace.h"
+#include <sys/acl.h>
+#include "un-namespace.h"
+#include <errno.h>
+#include <grp.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "acl_support.h"
+
+/*
+ * Given a uid/gid, return a username/groupname for the text form of an ACL.
+ * Note that we truncate user and group names, rather than error out, as
+ * this is consistent with other tools manipulating user and group names.
+ * XXX NOT THREAD SAFE, RELIES ON GETPWUID, GETGRGID
+ * XXX USES *PW* AND *GR* WHICH ARE STATEFUL AND THEREFORE THIS ROUTINE
+ * MAY HAVE SIDE-EFFECTS
+ */
+int
+_posix1e_acl_id_to_name(acl_tag_t tag, uid_t id, ssize_t buf_len, char *buf,
+ int flags)
+{
+ struct group *g;
+ struct passwd *p;
+ int i;
+
+ switch(tag) {
+ case ACL_USER:
+ if (flags & ACL_TEXT_NUMERIC_IDS)
+ p = NULL;
+ else
+ p = getpwuid(id);
+ if (!p)
+ i = snprintf(buf, buf_len, "%d", id);
+ else
+ i = snprintf(buf, buf_len, "%s", p->pw_name);
+
+ if (i < 0) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ return (0);
+
+ case ACL_GROUP:
+ if (flags & ACL_TEXT_NUMERIC_IDS)
+ g = NULL;
+ else
+ g = getgrgid(id);
+ if (g == NULL)
+ i = snprintf(buf, buf_len, "%d", id);
+ else
+ i = snprintf(buf, buf_len, "%s", g->gr_name);
+
+ if (i < 0) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ return (0);
+
+ default:
+ return (EINVAL);
+ }
+}
diff --git a/lib/libc/posix1e/acl_init.3 b/lib/libc/posix1e/acl_init.3
new file mode 100644
index 000000000000..dba89231c44a
--- /dev/null
+++ b/lib/libc/posix1e/acl_init.3
@@ -0,0 +1,111 @@
+.\"-
+.\" Copyright (c) 2000, 2002 Robert N. M. Watson
+.\" All rights reserved.
+.\"
+.\" This software was developed by Robert Watson for the TrustedBSD Project.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd January 28, 2000
+.Dt ACL_INIT 3
+.Os
+.Sh NAME
+.Nm acl_init
+.Nd initialize ACL working storage
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft acl_t
+.Fn acl_init "int count"
+.Sh DESCRIPTION
+The
+.Fn acl_init
+function allocates and initializes the working storage for an ACL of at
+least
+.Va count
+ACL entries.
+A pointer to the working storage is returned.
+The working
+storage allocated to contain the ACL is freed by a call to
+.Xr acl_free 3 .
+When the area is first allocated, it shall contain an ACL that contains
+no ACL entries.
+.Pp
+This function may cause memory to be allocated.
+The caller should free any
+releasable memory, when the new ACL is no longer required, by calling
+.Xr acl_free 3
+with the
+.Va (void*)acl_t
+as an argument.
+.Sh IMPLEMENTATION NOTES
+.Fx Ns 's
+support for POSIX.1e interfaces and features is still under
+development at this time.
+.Sh RETURN VALUES
+Upon successful completion, this function shall return a pointer to the
+working storage.
+Otherwise, a value of
+.Va (acl_t)NULL
+shall be returned, and
+.Va errno
+shall be set to indicate the error.
+.Sh ERRORS
+If any of the following conditions occur, the
+.Fn acl_init
+function shall return a value of
+.Va (acl_t)NULL
+and set
+.Va errno
+to the corresponding value:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The value of count is less than zero.
+.It Bq Er ENOMEM
+The
+.Va acl_t
+to be returned requires more memory than is allowed by the hardware or
+system-imposed memory management constraints.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_free 3 ,
+.Xr posix1e 3
+.Sh STANDARDS
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+Discussion
+of the draft continues on the cross-platform POSIX.1e implementation
+mailing list.
+To join this list, see the
+.Fx
+POSIX.1e implementation
+page for more information.
+.Sh HISTORY
+POSIX.1e support was introduced in
+.Fx 4.0 ,
+and development continues.
+.Sh AUTHORS
+.An Robert N M Watson
diff --git a/lib/libc/posix1e/acl_init.c b/lib/libc/posix1e/acl_init.c
new file mode 100644
index 000000000000..88a1fc5aaf1c
--- /dev/null
+++ b/lib/libc/posix1e/acl_init.c
@@ -0,0 +1,95 @@
+/*-
+ * Copyright (c) 1999, 2000, 2001 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * acl_init -- return a fresh acl structure
+ * acl_dup -- duplicate an acl and return the new copy
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include "namespace.h"
+#include <sys/acl.h>
+#include "un-namespace.h"
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "acl_support.h"
+
+#ifndef CTASSERT
+#define CTASSERT(x) _CTASSERT(x, __LINE__)
+#define _CTASSERT(x, y) __CTASSERT(x, y)
+#define __CTASSERT(x, y) typedef char __assert_ ## y [(x) ? 1 : -1]
+#endif
+
+CTASSERT(1 << _ACL_T_ALIGNMENT_BITS > sizeof(struct acl_t_struct));
+
+acl_t
+acl_init(int count)
+{
+ int error;
+ acl_t acl;
+
+ if (count > ACL_MAX_ENTRIES) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ if (count < 0) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ error = posix_memalign((void *)&acl, 1 << _ACL_T_ALIGNMENT_BITS,
+ sizeof(struct acl_t_struct));
+ if (error) {
+ errno = error;
+ return (NULL);
+ }
+
+ bzero(acl, sizeof(struct acl_t_struct));
+ acl->ats_brand = ACL_BRAND_UNKNOWN;
+ acl->ats_acl.acl_maxcnt = ACL_MAX_ENTRIES;
+
+ return (acl);
+}
+
+acl_t
+acl_dup(acl_t acl)
+{
+ acl_t acl_new;
+
+ acl_new = acl_init(ACL_MAX_ENTRIES);
+ if (acl_new != NULL) {
+ *acl_new = *acl;
+ acl->ats_cur_entry = 0;
+ acl_new->ats_cur_entry = 0;
+ }
+
+ return (acl_new);
+}
diff --git a/lib/libc/posix1e/acl_is_trivial_np.3 b/lib/libc/posix1e/acl_is_trivial_np.3
new file mode 100644
index 000000000000..142a76c8f1a8
--- /dev/null
+++ b/lib/libc/posix1e/acl_is_trivial_np.3
@@ -0,0 +1,85 @@
+.\"-
+.\" Copyright (c) 2008, 2009 Edward Tomasz Napierala
+.\" All rights reserved.
+.\"
+.\" This software was developed by Robert Watson for the TrustedBSD Project.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd November 12, 2013
+.Dt ACL_STRIP_NP 3
+.Os
+.Sh NAME
+.Nm acl_is_trivial_np
+.Nd determine whether ACL is trivial
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_is_trivial_np "const acl_t aclp" "int *trivialp"
+.Sh DESCRIPTION
+The
+.Fn acl_is_trivial
+function determines whether the ACL pointed to by the argument
+.Va acl
+is trivial.
+Upon successful completion, the location referred to by the argument
+.Fa trivialp
+will be set to 1, if the ACL
+.Fa aclp
+points to is trivial, or 0 if it's not.
+.Pp
+ACL is trivial if it can be fully expressed as a file mode without losing
+any access rules.
+For POSIX.1e ACLs, ACL is trivial if it has the three required entries,
+one for owner, one for owning group, and one for other.
+For NFSv4 ACLs, ACL is trivial if it is identical to the ACL generated by
+.Fn acl_strip_np 3 .
+Files that have non-trivial ACL have a plus sign appended after mode bits
+in "ls -l" output.
+.Sh RETURN VALUES
+.Rv -std acl_get_tag_type
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr posix1e 3
+.Sh STANDARDS
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+Discussion
+of the draft continues on the cross-platform POSIX.1e implementation
+mailing list.
+To join this list, see the
+.Fx
+POSIX.1e implementation
+page for more information.
+.Sh HISTORY
+POSIX.1e support was introduced in
+.Fx 4.0 .
+The
+.Fn acl_is_trivial_np
+function was added in
+.Fx 8.0 .
+.Sh AUTHORS
+.An Edward Tomasz Napierala Aq Mt trasz@FreeBSD.org
diff --git a/lib/libc/posix1e/acl_perm.c b/lib/libc/posix1e/acl_perm.c
new file mode 100644
index 000000000000..ad2f47e62313
--- /dev/null
+++ b/lib/libc/posix1e/acl_perm.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2001-2002 Chris D. Faulhaber
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include "namespace.h"
+#include <sys/acl.h>
+#include "un-namespace.h"
+
+#include <errno.h>
+#include <string.h>
+
+static int
+_perm_is_invalid(acl_perm_t perm)
+{
+
+ /* Check if more than a single bit is set. */
+ if ((perm & -perm) == perm &&
+ (perm & (ACL_POSIX1E_BITS | ACL_NFS4_PERM_BITS)) == perm)
+ return (0);
+
+ errno = EINVAL;
+
+ return (1);
+}
+
+/*
+ * acl_add_perm() (23.4.1): add the permission contained in perm to the
+ * permission set permset_d
+ */
+int
+acl_add_perm(acl_permset_t permset_d, acl_perm_t perm)
+{
+
+ if (permset_d == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (_perm_is_invalid(perm))
+ return (-1);
+
+ *permset_d |= perm;
+
+ return (0);
+}
+
+/*
+ * acl_clear_perms() (23.4.3): clear all permisions from the permission
+ * set permset_d
+ */
+int
+acl_clear_perms(acl_permset_t permset_d)
+{
+
+ if (permset_d == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ *permset_d = ACL_PERM_NONE;
+
+ return (0);
+}
+
+/*
+ * acl_delete_perm() (23.4.10): remove the permission in perm from the
+ * permission set permset_d
+ */
+int
+acl_delete_perm(acl_permset_t permset_d, acl_perm_t perm)
+{
+
+ if (permset_d == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (_perm_is_invalid(perm))
+ return (-1);
+
+ *permset_d &= ~perm;
+
+ return (0);
+}
+
+int
+acl_get_perm_np(acl_permset_t permset_d, acl_perm_t perm)
+{
+
+ if (permset_d == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (_perm_is_invalid(perm))
+ return (-1);
+
+ if (*permset_d & perm)
+ return (1);
+
+ return (0);
+}
diff --git a/lib/libc/posix1e/acl_set.3 b/lib/libc/posix1e/acl_set.3
new file mode 100644
index 000000000000..7450dc93eb9e
--- /dev/null
+++ b/lib/libc/posix1e/acl_set.3
@@ -0,0 +1,157 @@
+.\"-
+.\" Copyright (c) 2000, 2002 Robert N. M. Watson
+.\" All rights reserved.
+.\"
+.\" This software was developed by Robert Watson for the TrustedBSD Project.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd June 25, 2009
+.Dt ACL_SET 3
+.Os
+.Sh NAME
+.Nm acl_set_fd ,
+.Nm acl_set_fd_np ,
+.Nm acl_set_file ,
+.Nm acl_set_link_np
+.Nd set an ACL for a file
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_set_fd "int fd" "acl_t acl"
+.Ft int
+.Fn acl_set_fd_np "int fd" "acl_t acl" "acl_type_t type"
+.Ft int
+.Fn acl_set_file "const char *path_p" "acl_type_t type" "acl_t acl"
+.Ft int
+.Fn acl_set_link_np "const char *path_p" "acl_type_t type" "acl_t acl"
+.Sh DESCRIPTION
+The
+.Fn acl_set_fd ,
+.Fn acl_set_fd_np ,
+.Fn acl_set_file ,
+and
+.Fn acl_set_link_np
+each associate an ACL with an object referred to by
+.Va fd
+or
+.Va path_p .
+The
+.Fn acl_set_fd_np
+and
+.Fn acl_set_link_np
+functions are not POSIX.1e calls.
+The
+.Fn acl_set_fd
+function allows only the setting of ACLs of type ACL_TYPE_ACCESS
+where as
+.Fn acl_set_fd_np
+allows the setting of ACLs of any type.
+The
+.Fn acl_set_link_np
+function acts on a symlink rather than its target, if the target of the
+path is a symlink.
+.Pp
+Valid values for the
+.Va type
+argument are:
+.Bl -column -offset 3n "ACL_TYPE_DEFAULT"
+.It ACL_TYPE_ACCESS POSIX.1e access ACL
+.It ACL_TYPE_DEFAULT POSIX.1e default ACL
+.It ACL_TYPE_NFS4 NFSv4 ACL
+.El
+.Pp
+Trying to set ACL_TYPE_NFS4 with
+.Va acl
+branded as POSIX.1e, or ACL_TYPE_ACCESS or ACL_TYPE_DEFAULT with ACL
+branded as NFSv4, will result in error.
+.Sh IMPLEMENTATION NOTES
+.Fx Ns 's
+support for POSIX.1e interfaces and features is still under
+development at this time.
+.Sh RETURN VALUES
+.Rv -std
+.Sh ERRORS
+If any of the following conditions occur, these functions shall return
+-1 and set
+.Va errno
+to the corresponding value:
+.Bl -tag -width Er
+.It Bq Er EACCES
+Search permission is denied for a component of the path prefix, or the
+object exists and the process does not have appropriate access rights.
+.It Bq Er EBADF
+The
+.Va fd
+argument is not a valid file descriptor.
+.It Bq Er EINVAL
+Argument
+.Va acl
+does not point to a valid ACL for this object, or the ACL type
+specified in
+.Va type
+is invalid for this object, or there is branding mismatch.
+.It Bq Er ENAMETOOLONG
+A component of a pathname exceeded 255 characters, or an
+entire path name exceeded 1023 characters.
+.It Bq Er ENOENT
+The named object does not exist, or the
+.Va path_p
+argument points to an empty string.
+.It Bq Er ENOMEM
+Insufficient memory available to fulfill request.
+.It Bq Er ENOSPC
+The directory or file system that would contain the new ACL cannot be
+extended, or the file system is out of file allocation resources.
+.It Bq Er EOPNOTSUPP
+The file system does not support ACL retrieval.
+.It Bq Er EROFS
+This function requires modification of a file system which is currently
+read-only.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_delete 3 ,
+.Xr acl_get 3 ,
+.Xr acl_get_brand_np 3 ,
+.Xr acl_valid 3 ,
+.Xr posix1e 3
+.Sh STANDARDS
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+Discussion
+of the draft continues on the cross-platform POSIX.1e implementation
+mailing list.
+To join this list, see the
+.Fx
+POSIX.1e implementation
+page for more information.
+.Sh HISTORY
+POSIX.1e support was introduced in
+.Fx 4.0 ,
+and development continues.
+.Sh AUTHORS
+.An Robert N M Watson
diff --git a/lib/libc/posix1e/acl_set.c b/lib/libc/posix1e/acl_set.c
new file mode 100644
index 000000000000..fdc12b6f7303
--- /dev/null
+++ b/lib/libc/posix1e/acl_set.c
@@ -0,0 +1,253 @@
+/*-
+ * Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * This software was developed by Robert Watson for the TrustedBSD Project.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * acl_set_file -- set a file/directory ACL by name
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include "namespace.h"
+#include <sys/acl.h>
+#include "un-namespace.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "acl_support.h"
+
+/*
+ * For POSIX.1e-semantic ACLs, do a presort so the kernel doesn't have to
+ * (the POSIX.1e semantic code will reject unsorted ACL submission). If it's
+ * not a semantic that the library knows about, just submit it flat and
+ * assume the caller knows what they're up to.
+ */
+int
+acl_set_file(const char *path_p, acl_type_t type, acl_t acl)
+{
+
+ if (acl == NULL || path_p == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+ type = _acl_type_unold(type);
+ if (_acl_type_not_valid_for_acl(acl, type)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ if (_posix1e_acl(acl, type))
+ _posix1e_acl_sort(acl);
+
+ acl->ats_cur_entry = 0;
+
+ return (__acl_set_file(path_p, type, &acl->ats_acl));
+}
+
+int
+acl_set_link_np(const char *path_p, acl_type_t type, acl_t acl)
+{
+
+ if (acl == NULL || path_p == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+ type = _acl_type_unold(type);
+ if (_acl_type_not_valid_for_acl(acl, type)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ if (_posix1e_acl(acl, type))
+ _posix1e_acl_sort(acl);
+
+ acl->ats_cur_entry = 0;
+
+ return (__acl_set_link(path_p, type, &acl->ats_acl));
+}
+
+int
+acl_set_fd(int fd, acl_t acl)
+{
+
+ if (fpathconf(fd, _PC_ACL_NFS4) == 1)
+ return (acl_set_fd_np(fd, acl, ACL_TYPE_NFS4));
+
+ return (acl_set_fd_np(fd, acl, ACL_TYPE_ACCESS));
+}
+
+int
+acl_set_fd_np(int fd, acl_t acl, acl_type_t type)
+{
+
+ if (acl == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+ type = _acl_type_unold(type);
+ if (_acl_type_not_valid_for_acl(acl, type)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ if (_posix1e_acl(acl, type))
+ _posix1e_acl_sort(acl);
+
+ acl->ats_cur_entry = 0;
+
+ return (___acl_set_fd(fd, type, &acl->ats_acl));
+}
+
+/*
+ * acl_set_permset() (23.4.23): sets the permissions of ACL entry entry_d
+ * with the permissions in permset_d
+ */
+int
+acl_set_permset(acl_entry_t entry_d, acl_permset_t permset_d)
+{
+
+ if (!entry_d) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if ((*permset_d & ACL_POSIX1E_BITS) != *permset_d) {
+ if ((*permset_d & ACL_NFS4_PERM_BITS) != *permset_d) {
+ errno = EINVAL;
+ return (-1);
+ }
+ if (!_entry_brand_may_be(entry_d, ACL_BRAND_NFS4)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ _entry_brand_as(entry_d, ACL_BRAND_NFS4);
+ }
+
+ entry_d->ae_perm = *permset_d;
+
+ return (0);
+}
+
+/*
+ * acl_set_qualifier() sets the qualifier (ae_id) of the tag for
+ * ACL entry entry_d to the value referred to by tag_qualifier_p
+ */
+int
+acl_set_qualifier(acl_entry_t entry_d, const void *tag_qualifier_p)
+{
+
+ if (!entry_d || !tag_qualifier_p) {
+ errno = EINVAL;
+ return (-1);
+ }
+ switch(entry_d->ae_tag) {
+ case ACL_USER:
+ case ACL_GROUP:
+ entry_d->ae_id = *(uid_t *)tag_qualifier_p;
+ break;
+ default:
+ errno = EINVAL;
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * acl_set_tag_type() sets the tag type for ACL entry entry_d to the
+ * value of tag_type
+ */
+int
+acl_set_tag_type(acl_entry_t entry_d, acl_tag_t tag_type)
+{
+
+ if (entry_d == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ switch(tag_type) {
+ case ACL_OTHER:
+ case ACL_MASK:
+ if (!_entry_brand_may_be(entry_d, ACL_BRAND_POSIX)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ _entry_brand_as(entry_d, ACL_BRAND_POSIX);
+ break;
+ case ACL_EVERYONE:
+ if (!_entry_brand_may_be(entry_d, ACL_BRAND_NFS4)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ _entry_brand_as(entry_d, ACL_BRAND_NFS4);
+ break;
+ }
+
+ switch(tag_type) {
+ case ACL_USER_OBJ:
+ case ACL_USER:
+ case ACL_GROUP_OBJ:
+ case ACL_GROUP:
+ case ACL_MASK:
+ case ACL_OTHER:
+ case ACL_EVERYONE:
+ entry_d->ae_tag = tag_type;
+ return (0);
+ }
+
+ errno = EINVAL;
+ return (-1);
+}
+
+int
+acl_set_entry_type_np(acl_entry_t entry_d, acl_entry_type_t entry_type)
+{
+
+ if (entry_d == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+ if (!_entry_brand_may_be(entry_d, ACL_BRAND_NFS4)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ _entry_brand_as(entry_d, ACL_BRAND_NFS4);
+
+ switch (entry_type) {
+ case ACL_ENTRY_TYPE_ALLOW:
+ case ACL_ENTRY_TYPE_DENY:
+ case ACL_ENTRY_TYPE_AUDIT:
+ case ACL_ENTRY_TYPE_ALARM:
+ entry_d->ae_entry_type = entry_type;
+ return (0);
+ }
+
+ errno = EINVAL;
+ return (-1);
+}
diff --git a/lib/libc/posix1e/acl_set_entry_type_np.3 b/lib/libc/posix1e/acl_set_entry_type_np.3
new file mode 100644
index 000000000000..90772e0005af
--- /dev/null
+++ b/lib/libc/posix1e/acl_set_entry_type_np.3
@@ -0,0 +1,94 @@
+.\"-
+.\" Copyright (c) 2008, 2009 Edward Tomasz Napierala
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd October 30, 2014
+.Dt ACL_SET_ENTRY_TYPE_NP 3
+.Os
+.Sh NAME
+.Nm acl_set_entry_type_np
+.Nd set NFSv4 ACL entry type
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_set_entry_type_np "acl_entry_t entry_d" "acl_entry_type_t entry_type"
+.Sh DESCRIPTION
+The
+.Fn acl_set_entry_type_np
+function
+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 .
+.Pp
+Valid values are:
+.Bl -column -offset 3n "ACL_ENTRY_TYPE_ALLOW"
+.It ACL_ENTRY_TYPE_ALLOW Ta "allow" type entry
+.It ACL_ENTRY_TYPE_DENY Ta "deny" type entry
+.El
+.Pp
+This call brands the ACL as NFSv4.
+.Sh RETURN VALUES
+.Rv -std acl_set_entry_type_np
+.Sh ERRORS
+The
+.Fn acl_set_entry_type_np
+function fails if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Fa entry_d
+is not a valid descriptor for an ACL entry.
+The value pointed to by
+.Fa entry_type
+is not valid.
+ACL is already branded as POSIX.1e.
+.It Bq Er ENOMEM
+The value to be returned requires more memory than is allowed
+by the hardware or system-imposed memory management constraints.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_get_brand_np 3 ,
+.Xr acl_get_entry_type_np 3 ,
+.Xr posix1e 3
+.Sh STANDARDS
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+.Sh HISTORY
+POSIX.1e support was introduced in
+.Fx 4.0 .
+The
+.Fn acl_get_entry_type_np
+function was added in
+.Fx 8.0 .
+.Sh AUTHORS
+The
+.Fn acl_get_entry_type_np
+function was written by
+.An Edward Tomasz Napierala Aq Mt trasz@FreeBSD.org .
diff --git a/lib/libc/posix1e/acl_set_flagset_np.3 b/lib/libc/posix1e/acl_set_flagset_np.3
new file mode 100644
index 000000000000..685680d3b351
--- /dev/null
+++ b/lib/libc/posix1e/acl_set_flagset_np.3
@@ -0,0 +1,85 @@
+.\"-
+.\" Copyright (c) 2008, 2009 Edward Tomasz Napierala
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd October 30, 2014
+.Dt ACL_SET_FLAGSET_NP 3
+.Os
+.Sh NAME
+.Nm acl_set_flagset_np
+.Nd set the flags of an NFSv4 ACL entry
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_set_flagset_np "acl_entry_t entry_d" "acl_flagset_t flagset_d"
+.Sh DESCRIPTION
+The
+.Fn acl_set_flagset_np
+function
+is a non-portable call that sets the flags of NFSv4 ACL entry
+.Fa entry_d
+with the flags contained in
+.Fa flagset_d .
+.Pp
+This call brands the ACL as NFSv4.
+.Sh RETURN VALUES
+.Rv -std acl_set_flagset_np
+.Sh ERRORS
+The
+.Fn acl_set_flagset_np
+function fails if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Fa entry_d
+is not a valid descriptor for an ACL entry.
+ACL is already branded as POSIX.1e.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_add_flag_np 3 ,
+.Xr acl_clear_flags_np 3 ,
+.Xr acl_delete_flag_np 3 ,
+.Xr acl_get_brand_np 3 ,
+.Xr acl_get_flagset_np 3 ,
+.Xr posix1e 3
+.Sh STANDARDS
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+.Sh HISTORY
+POSIX.1e support was introduced in
+.Fx 4.0 .
+The
+.Fn acl_set_flagset_np
+function was added in
+.Fx 8.0 .
+.Sh AUTHORS
+The
+.Fn acl_set_flagset_np
+function was written by
+.An Edward Tomasz Napierala Aq Mt trasz@FreeBSD.org .
diff --git a/lib/libc/posix1e/acl_set_permset.3 b/lib/libc/posix1e/acl_set_permset.3
new file mode 100644
index 000000000000..259aef6b8458
--- /dev/null
+++ b/lib/libc/posix1e/acl_set_permset.3
@@ -0,0 +1,81 @@
+.\"-
+.\" Copyright (c) 2001 Chris D. Faulhaber
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 March 10, 2001
+.Dt ACL_SET_PERMSET 3
+.Os
+.Sh NAME
+.Nm acl_set_permset
+.Nd set the permissions of an ACL entry
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_set_permset "acl_entry_t entry_d" "acl_permset_t permset_d"
+.Sh DESCRIPTION
+The
+.Fn acl_set_permset
+function
+is a POSIX.1e call that sets the permissions of ACL entry
+.Fa entry_d
+with the permissions contained in
+.Fa permset_d .
+.Sh RETURN VALUES
+.Rv -std acl_set_permset
+.Sh ERRORS
+The
+.Fn acl_set_permset
+function fails if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Fa entry_d
+is not a valid descriptor for an ACL entry.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_add_perm 3 ,
+.Xr acl_clear_perms 3 ,
+.Xr acl_delete_perm 3 ,
+.Xr acl_get_permset 3 ,
+.Xr posix1e 3
+.Sh STANDARDS
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+.Sh HISTORY
+POSIX.1e support was introduced in
+.Fx 4.0 .
+The
+.Fn acl_set_permset
+function was added in
+.Fx 5.0 .
+.Sh AUTHORS
+The
+.Fn acl_set_permset
+function was written by
+.An Chris D. Faulhaber Aq Mt jedgar@fxp.org .
diff --git a/lib/libc/posix1e/acl_set_qualifier.3 b/lib/libc/posix1e/acl_set_qualifier.3
new file mode 100644
index 000000000000..26542ce28388
--- /dev/null
+++ b/lib/libc/posix1e/acl_set_qualifier.3
@@ -0,0 +1,91 @@
+.\"-
+.\" Copyright (c) 2001 Chris D. Faulhaber
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 March 10, 2001
+.Dt ACL_SET_QUALIFIER 3
+.Os
+.Sh NAME
+.Nm acl_set_qualifier
+.Nd set ACL tag qualifier
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_set_qualifier "acl_entry_t entry_d" "const void *tag_qualifier_p"
+.Sh DESCRIPTION
+The
+.Fn acl_set_qualifier
+function
+is a POSIX.1e call that sets the qualifier of the tag for the ACL entry
+.Fa entry_d
+to the value referred to by
+.Fa tag_qualifier_p .
+.Sh RETURN VALUES
+.Rv -std acl_set_qualifier
+.Sh ERRORS
+The
+.Fn acl_set_qualifier
+function fails if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Fa entry_d
+is not a valid descriptor for an ACL entry.
+The tag type of the
+ACL entry
+.Fa entry_d
+is not
+.Dv ACL_USER
+or
+.Dv ACL_GROUP .
+The value pointed to by
+.Fa tag_qualifier_p
+is not valid.
+.It Bq Er ENOMEM
+The value to be returned requires more memory than is allowed
+by the hardware or system-imposed memory management constraints.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_get_qualifier 3 ,
+.Xr posix1e 3
+.Sh STANDARDS
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+.Sh HISTORY
+POSIX.1e support was introduced in
+.Fx 4.0 .
+The
+.Fn acl_get_qualifier
+function was added in
+.Fx 5.0 .
+.Sh AUTHORS
+The
+.Fn acl_get_qualifier
+function was written by
+.An Chris D. Faulhaber Aq Mt jedgar@fxp.org .
diff --git a/lib/libc/posix1e/acl_set_tag_type.3 b/lib/libc/posix1e/acl_set_tag_type.3
new file mode 100644
index 000000000000..42834c2657d0
--- /dev/null
+++ b/lib/libc/posix1e/acl_set_tag_type.3
@@ -0,0 +1,102 @@
+.\"-
+.\" Copyright (c) 2001 Chris D. Faulhaber
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd June 25, 2009
+.Dt ACL_SET_TAG_TYPE 3
+.Os
+.Sh NAME
+.Nm acl_set_tag_type
+.Nd set the tag type of an ACL entry
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_set_tag_type "acl_entry_t entry_d" "acl_tag_t tag_type"
+.Sh DESCRIPTION
+The
+.Fn acl_set_tag_type
+function
+is a POSIX.1e call that sets the ACL tag type of ACL entry
+.Fa entry_d
+to the value of
+.Fa tag_type .
+.Pp
+Valid values are:
+.Bl -column -offset 3n "ACL_OTHER_OBJ"
+.It ACL_USER_OBJ Ta "Permissions apply to file owner"
+.It ACL_USER Ta "Permissions apply to additional user specified by qualifier"
+.It ACL_GROUP_OBJ Ta "Permissions apply to file group"
+.It ACL_GROUP Ta "Permissions apply to additional group specified by qualifier"
+.It ACL_MASK Ta "Permissions specify mask"
+.It ACL_OTHER Ta Permissions apply to "other"
+.It ACL_OTHER_OBJ Ta "Same as ACL_OTHER"
+.It ACL_EVERYONE Ta Permissions apply to "everyone@"
+.El
+.Pp
+Calling
+.Fn acl_set_tag_type
+with
+.Fa tag_type
+equal to ACL_MASK, ACL_OTHER or ACL_OTHER_OBJ brands the ACL as POSIX.1e.
+Calling it with ACL_EVERYONE brands the ACL as NFSv4.
+.Sh RETURN VALUES
+.Rv -std acl_set_tag_type
+.Sh ERRORS
+The
+.Fn acl_set_tag_type
+function fails if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Fa entry_d
+is not a valid descriptor for an ACL entry.
+Argument
+.Fa tag_type
+is not a valid ACL tag type.
+ACL is already branded differently.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_get_brand_np 3 ,
+.Xr acl_get_tag_type 3 ,
+.Xr posix1e 3
+.Sh STANDARDS
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+.Sh HISTORY
+POSIX.1e support was introduced in
+.Fx 4.0 .
+The
+.Fn acl_set_tag_type
+function was added in
+.Fx 5.0 .
+.Sh AUTHORS
+The
+.Fn acl_set_tag_type
+function was written by
+.An Chris D. Faulhaber Aq Mt jedgar@fxp.org .
diff --git a/lib/libc/posix1e/acl_strip.c b/lib/libc/posix1e/acl_strip.c
new file mode 100644
index 000000000000..24fda8480646
--- /dev/null
+++ b/lib/libc/posix1e/acl_strip.c
@@ -0,0 +1,233 @@
+/*-
+ * Copyright (c) 2001 Chris D. Faulhaber
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <stdio.h>
+#include <assert.h>
+#include <sys/acl.h>
+#include <sys/stat.h>
+
+#include "acl_support.h"
+
+/*
+ * These routines from sys/kern/subr_acl_nfs4.c are used by both kernel
+ * and libc.
+ */
+void acl_nfs4_sync_mode_from_acl(mode_t *_mode, const struct acl *aclp);
+void acl_nfs4_trivial_from_mode_libc(struct acl *aclp, int file_owner_id,
+ int canonical_six);
+
+static acl_t
+_nfs4_acl_strip_np(const acl_t aclp, int canonical_six)
+{
+ acl_t newacl;
+ mode_t mode = 0;
+
+ newacl = acl_init(ACL_MAX_ENTRIES);
+ if (newacl == NULL) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+
+ _acl_brand_as(newacl, ACL_BRAND_NFS4);
+
+ acl_nfs4_sync_mode_from_acl(&mode, &(aclp->ats_acl));
+ acl_nfs4_trivial_from_mode_libc(&(newacl->ats_acl), mode, canonical_six);
+
+ return (newacl);
+}
+
+static acl_t
+_posix1e_acl_strip_np(const acl_t aclp, int recalculate_mask)
+{
+ acl_t acl_new, acl_old;
+ acl_entry_t entry, entry_new;
+ acl_permset_t perm;
+ acl_tag_t tag;
+ int entry_id, have_mask_entry;
+
+ assert(_acl_brand(aclp) == ACL_BRAND_POSIX);
+
+ acl_old = acl_dup(aclp);
+ if (acl_old == NULL)
+ return (NULL);
+
+ assert(_acl_brand(acl_old) == ACL_BRAND_POSIX);
+
+ have_mask_entry = 0;
+ acl_new = acl_init(ACL_MAX_ENTRIES);
+ if (acl_new == NULL) {
+ acl_free(acl_old);
+ return (NULL);
+ }
+ tag = ACL_UNDEFINED_TAG;
+
+ /* only save the default user/group/other entries */
+ entry_id = ACL_FIRST_ENTRY;
+ while (acl_get_entry(acl_old, entry_id, &entry) == 1) {
+ entry_id = ACL_NEXT_ENTRY;
+
+ assert(_entry_brand(entry) == ACL_BRAND_POSIX);
+
+ if (acl_get_tag_type(entry, &tag) == -1)
+ goto fail;
+
+ switch(tag) {
+ case ACL_USER_OBJ:
+ case ACL_GROUP_OBJ:
+ case ACL_OTHER:
+ if (acl_get_tag_type(entry, &tag) == -1)
+ goto fail;
+ if (acl_get_permset(entry, &perm) == -1)
+ goto fail;
+ if (acl_create_entry(&acl_new, &entry_new) == -1)
+ goto fail;
+ if (acl_set_tag_type(entry_new, tag) == -1)
+ goto fail;
+ if (acl_set_permset(entry_new, perm) == -1)
+ goto fail;
+ if (acl_copy_entry(entry_new, entry) == -1)
+ goto fail;
+ assert(_entry_brand(entry_new) == ACL_BRAND_POSIX);
+ break;
+ case ACL_MASK:
+ have_mask_entry = 1;
+ break;
+ default:
+ break;
+ }
+ }
+
+ assert(_acl_brand(acl_new) == ACL_BRAND_POSIX);
+
+ if (have_mask_entry && recalculate_mask) {
+ if (acl_calc_mask(&acl_new) == -1)
+ goto fail;
+ }
+
+ return (acl_new);
+
+fail:
+ acl_free(acl_new);
+ acl_free(acl_old);
+
+ return (NULL);
+}
+
+acl_t
+acl_strip_np(const acl_t aclp, int recalculate_mask)
+{
+ switch (_acl_brand(aclp)) {
+ case ACL_BRAND_NFS4:
+ return (_nfs4_acl_strip_np(aclp, 0));
+
+ case ACL_BRAND_POSIX:
+ return (_posix1e_acl_strip_np(aclp, recalculate_mask));
+
+ default:
+ errno = EINVAL;
+ return (NULL);
+ }
+}
+
+/*
+ * Return 1, if ACL is trivial, 0 otherwise.
+ *
+ * ACL is trivial, iff its meaning could be fully expressed using just file
+ * mode. In other words, ACL is trivial iff it doesn't have "+" to the right
+ * of the mode bits in "ls -l" output ;-)
+ */
+int
+acl_is_trivial_np(const acl_t aclp, int *trivialp)
+{
+ acl_t tmpacl;
+ int differs;
+
+ if (aclp == NULL || trivialp == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ switch (_acl_brand(aclp)) {
+ case ACL_BRAND_POSIX:
+ if (aclp->ats_acl.acl_cnt == 3)
+ *trivialp = 1;
+ else
+ *trivialp = 0;
+
+ return (0);
+
+ case ACL_BRAND_NFS4:
+ /*
+ * If the ACL has more than canonical six entries,
+ * it's non trivial by definition.
+ */
+ if (aclp->ats_acl.acl_cnt > 6) {
+ *trivialp = 0;
+ return (0);
+ }
+
+ /*
+ * Calculate trivial ACL - using acl_strip_np(3) - and compare
+ * with the original.
+ */
+ tmpacl = _nfs4_acl_strip_np(aclp, 0);
+ if (tmpacl == NULL)
+ return (-1);
+
+ differs = _acl_differs(aclp, tmpacl);
+ acl_free(tmpacl);
+
+ if (differs == 0) {
+ *trivialp = 1;
+ return (0);
+ }
+
+ /*
+ * Try again with an old-style, "canonical six" trivial ACL.
+ */
+ tmpacl = _nfs4_acl_strip_np(aclp, 1);
+ if (tmpacl == NULL)
+ return (-1);
+
+ differs = _acl_differs(aclp, tmpacl);
+ acl_free(tmpacl);
+
+ if (differs)
+ *trivialp = 0;
+ else
+ *trivialp = 1;
+
+ return (0);
+
+ default:
+ errno = EINVAL;
+ return (-1);
+ }
+}
diff --git a/lib/libc/posix1e/acl_strip_np.3 b/lib/libc/posix1e/acl_strip_np.3
new file mode 100644
index 000000000000..8c1a920a717b
--- /dev/null
+++ b/lib/libc/posix1e/acl_strip_np.3
@@ -0,0 +1,109 @@
+.\"-
+.\" Copyright (c) 2008, 2009 Edward Tomasz Napierala
+.\" All rights reserved.
+.\"
+.\" This software was developed by Robert Watson for the TrustedBSD Project.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd June 25, 2009
+.Dt ACL_STRIP_NP 3
+.Os
+.Sh NAME
+.Nm acl_strip_np
+.Nd strip extended entries from an ACL
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft acl_t
+.Fn acl_strip_np "const acl_t acl" "int recalculate_mask"
+.Sh DESCRIPTION
+The
+.Fn acl_strip_np
+function returns a pointer to a trivial ACL computed from the ACL pointed
+to by the argument
+.Va acl .
+.Pp
+This function may cause memory to be allocated.
+The caller should free any
+releasable memory, when the new ACL is no longer required, by calling
+.Xr acl_free 3
+with the
+.Va (void*)acl_t
+as an argument.
+.Pp
+Any existing ACL pointers that refer to the ACL referred to by
+.Va acl
+shall continue to refer to the ACL.
+.Sh RETURN VALUES
+Upon successful completion, this function shall return a pointer to the
+newly allocated ACL.
+Otherwise, a value of
+.Va (acl_t)NULL
+shall be returned, and
+.Va errno
+shall be set to indicate the error.
+.Sh ERRORS
+If any of the following conditions occur, the
+.Fn acl_init
+function shall return a value of
+.Va (acl_t)NULL
+and set
+.Va errno
+to the corresponding value:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Va acl
+does not point to a valid ACL.
+.It Bq Er ENOMEM
+The
+.Va acl_t
+to be returned requires more memory than is allowed by the hardware or
+system-imposed memory management constraints.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_is_trivial_np 3 ,
+.Xr posix1e 3
+.Sh STANDARDS
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+Discussion
+of the draft continues on the cross-platform POSIX.1e implementation
+mailing list.
+To join this list, see the
+.Fx
+POSIX.1e implementation
+page for more information.
+.Sh HISTORY
+POSIX.1e support was introduced in
+.Fx 4.0 .
+The
+.Fn acl_strip_np
+function was added in
+.Fx 8.0 .
+.Sh AUTHORS
+.An Edward Tomasz Napierala Aq Mt trasz@FreeBSD.org
diff --git a/lib/libc/posix1e/acl_support.c b/lib/libc/posix1e/acl_support.c
new file mode 100644
index 000000000000..00848cbd2ed5
--- /dev/null
+++ b/lib/libc/posix1e/acl_support.c
@@ -0,0 +1,418 @@
+/*-
+ * Copyright (c) 1999-2001, 2008 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * Support functionality for the POSIX.1e ACL interface
+ * These calls are intended only to be called within the library.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include "namespace.h"
+#include <sys/acl.h>
+#include "un-namespace.h"
+#include <errno.h>
+#include <grp.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "acl_support.h"
+
+#define ACL_STRING_PERM_WRITE 'w'
+#define ACL_STRING_PERM_READ 'r'
+#define ACL_STRING_PERM_EXEC 'x'
+#define ACL_STRING_PERM_NONE '-'
+
+/*
+ * Return 0, if both ACLs are identical.
+ */
+int
+_acl_differs(const acl_t a, const acl_t b)
+{
+ int i;
+ struct acl_entry *entrya, *entryb;
+
+ assert(_acl_brand(a) == _acl_brand(b));
+ assert(_acl_brand(a) != ACL_BRAND_UNKNOWN);
+ assert(_acl_brand(b) != ACL_BRAND_UNKNOWN);
+
+ if (a->ats_acl.acl_cnt != b->ats_acl.acl_cnt)
+ return (1);
+
+ for (i = 0; i < b->ats_acl.acl_cnt; i++) {
+ entrya = &(a->ats_acl.acl_entry[i]);
+ entryb = &(b->ats_acl.acl_entry[i]);
+
+ if (entrya->ae_tag != entryb->ae_tag ||
+ entrya->ae_id != entryb->ae_id ||
+ entrya->ae_perm != entryb->ae_perm ||
+ entrya->ae_entry_type != entryb->ae_entry_type ||
+ entrya->ae_flags != entryb->ae_flags)
+ return (1);
+ }
+
+ return (0);
+}
+
+/*
+ * _posix1e_acl_entry_compare -- compare two acl_entry structures to
+ * determine the order they should appear in. Used by _posix1e_acl_sort to
+ * sort ACL entries into the kernel-desired order -- i.e., the order useful
+ * for evaluation and O(n) validity checking. Beter to have an O(nlogn) sort
+ * in userland and an O(n) in kernel than to have both in kernel.
+ */
+typedef int (*compare)(const void *, const void *);
+static int
+_posix1e_acl_entry_compare(struct acl_entry *a, struct acl_entry *b)
+{
+
+ assert(_entry_brand(a) == ACL_BRAND_POSIX);
+ assert(_entry_brand(b) == ACL_BRAND_POSIX);
+
+ /*
+ * First, sort between tags -- conveniently defined in the correct
+ * order for verification.
+ */
+ if (a->ae_tag < b->ae_tag)
+ return (-1);
+ if (a->ae_tag > b->ae_tag)
+ return (1);
+
+ /*
+ * Next compare uids/gids on appropriate types.
+ */
+
+ if (a->ae_tag == ACL_USER || a->ae_tag == ACL_GROUP) {
+ if (a->ae_id < b->ae_id)
+ return (-1);
+ if (a->ae_id > b->ae_id)
+ return (1);
+
+ /* shouldn't be equal, fall through to the invalid case */
+ }
+
+ /*
+ * Don't know how to sort multiple entries of the rest--either it's
+ * a bad entry, or there shouldn't be more than one. Ignore and the
+ * validity checker can get it later.
+ */
+ return (0);
+}
+
+/*
+ * _posix1e_acl_sort -- sort ACL entries in POSIX.1e-formatted ACLs.
+ */
+void
+_posix1e_acl_sort(acl_t acl)
+{
+ struct acl *acl_int;
+
+ acl_int = &acl->ats_acl;
+
+ qsort(&acl_int->acl_entry[0], acl_int->acl_cnt,
+ sizeof(struct acl_entry), (compare) _posix1e_acl_entry_compare);
+}
+
+/*
+ * acl_posix1e -- in what situations should we acl_sort before submission?
+ * We apply posix1e ACL semantics for any ACL of type ACL_TYPE_ACCESS or
+ * ACL_TYPE_DEFAULT
+ */
+int
+_posix1e_acl(acl_t acl, acl_type_t type)
+{
+
+ if (_acl_brand(acl) != ACL_BRAND_POSIX)
+ return (0);
+
+ return ((type == ACL_TYPE_ACCESS) || (type == ACL_TYPE_DEFAULT));
+}
+
+/*
+ * _posix1e_acl_check -- given an ACL, check its validity. This is mirrored
+ * from code in sys/kern/kern_acl.c, and if changes are made in one, they
+ * should be made in the other also. This copy of acl_check is made
+ * available * in userland for the benefit of processes wanting to check ACLs
+ * for validity before submitting them to the kernel, or for performing
+ * in userland file system checking. Needless to say, the kernel makes
+ * the real checks on calls to get/setacl.
+ *
+ * See the comments in kernel for explanation -- just briefly, it assumes
+ * an already sorted ACL, and checks based on that assumption. The
+ * POSIX.1e interface, acl_valid(), will perform the sort before calling
+ * this. Returns 0 on success, EINVAL on failure.
+ */
+int
+_posix1e_acl_check(acl_t acl)
+{
+ struct acl *acl_int;
+ struct acl_entry *entry; /* current entry */
+ uid_t highest_uid=0, highest_gid=0;
+ int stage = ACL_USER_OBJ;
+ int i = 0;
+ int count_user_obj=0, count_user=0, count_group_obj=0,
+ count_group=0, count_mask=0, count_other=0;
+
+ acl_int = &acl->ats_acl;
+
+ /* printf("_posix1e_acl_check: checking acl with %d entries\n",
+ acl->acl_cnt); */
+ while (i < acl_int->acl_cnt) {
+ entry = &acl_int->acl_entry[i];
+
+ if ((entry->ae_perm | ACL_PERM_BITS) != ACL_PERM_BITS)
+ return (EINVAL);
+
+ switch(entry->ae_tag) {
+ case ACL_USER_OBJ:
+ /* printf("_posix1e_acl_check: %d: ACL_USER_OBJ\n",
+ i); */
+ if (stage > ACL_USER_OBJ)
+ return (EINVAL);
+ stage = ACL_USER;
+ count_user_obj++;
+ break;
+
+ case ACL_USER:
+ /* printf("_posix1e_acl_check: %d: ACL_USER\n", i); */
+ if (stage > ACL_USER)
+ return (EINVAL);
+ stage = ACL_USER;
+ if (count_user && (entry->ae_id <= highest_uid))
+ return (EINVAL);
+ highest_uid = entry->ae_id;
+ count_user++;
+ break;
+
+ case ACL_GROUP_OBJ:
+ /* printf("_posix1e_acl_check: %d: ACL_GROUP_OBJ\n",
+ i); */
+ if (stage > ACL_GROUP_OBJ)
+ return (EINVAL);
+ stage = ACL_GROUP;
+ count_group_obj++;
+ break;
+
+ case ACL_GROUP:
+ /* printf("_posix1e_acl_check: %d: ACL_GROUP\n", i); */
+ if (stage > ACL_GROUP)
+ return (EINVAL);
+ stage = ACL_GROUP;
+ if (count_group && (entry->ae_id <= highest_gid))
+ return (EINVAL);
+ highest_gid = entry->ae_id;
+ count_group++;
+ break;
+
+ case ACL_MASK:
+ /* printf("_posix1e_acl_check: %d: ACL_MASK\n", i); */
+ if (stage > ACL_MASK)
+ return (EINVAL);
+ stage = ACL_MASK;
+ count_mask++;
+ break;
+
+ case ACL_OTHER:
+ /* printf("_posix1e_acl_check: %d: ACL_OTHER\n", i); */
+ if (stage > ACL_OTHER)
+ return (EINVAL);
+ stage = ACL_OTHER;
+ count_other++;
+ break;
+
+ default:
+ /* printf("_posix1e_acl_check: %d: INVALID\n", i); */
+ return (EINVAL);
+ }
+ i++;
+ }
+
+ if (count_user_obj != 1)
+ return (EINVAL);
+
+ if (count_group_obj != 1)
+ return (EINVAL);
+
+ if (count_mask != 0 && count_mask != 1)
+ return (EINVAL);
+
+ if (count_other != 1)
+ return (EINVAL);
+
+ return (0);
+}
+
+/*
+ * Given a right-shifted permission (i.e., direct ACL_PERM_* mask), fill
+ * in a string describing the permissions.
+ */
+int
+_posix1e_acl_perm_to_string(acl_perm_t perm, ssize_t buf_len, char *buf)
+{
+
+ if (buf_len < _POSIX1E_ACL_STRING_PERM_MAXSIZE + 1) {
+ errno = ENOMEM;
+ return (-1);
+ }
+
+ if ((perm | ACL_PERM_BITS) != ACL_PERM_BITS) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ buf[3] = 0; /* null terminate */
+
+ if (perm & ACL_READ)
+ buf[0] = ACL_STRING_PERM_READ;
+ else
+ buf[0] = ACL_STRING_PERM_NONE;
+
+ if (perm & ACL_WRITE)
+ buf[1] = ACL_STRING_PERM_WRITE;
+ else
+ buf[1] = ACL_STRING_PERM_NONE;
+
+ if (perm & ACL_EXECUTE)
+ buf[2] = ACL_STRING_PERM_EXEC;
+ else
+ buf[2] = ACL_STRING_PERM_NONE;
+
+ return (0);
+}
+
+/*
+ * given a string, return a permission describing it
+ */
+int
+_posix1e_acl_string_to_perm(char *string, acl_perm_t *perm)
+{
+ acl_perm_t myperm = ACL_PERM_NONE;
+ char *ch;
+
+ ch = string;
+ while (*ch) {
+ switch(*ch) {
+ case ACL_STRING_PERM_READ:
+ myperm |= ACL_READ;
+ break;
+ case ACL_STRING_PERM_WRITE:
+ myperm |= ACL_WRITE;
+ break;
+ case ACL_STRING_PERM_EXEC:
+ myperm |= ACL_EXECUTE;
+ break;
+ case ACL_STRING_PERM_NONE:
+ break;
+ default:
+ return (EINVAL);
+ }
+ ch++;
+ }
+
+ *perm = myperm;
+ return (0);
+}
+
+/*
+ * Add an ACL entry without doing much checking, et al
+ */
+int
+_posix1e_acl_add_entry(acl_t acl, acl_tag_t tag, uid_t id, acl_perm_t perm)
+{
+ struct acl *acl_int;
+ struct acl_entry *e;
+
+ acl_int = &acl->ats_acl;
+
+ if (acl_int->acl_cnt >= ACL_MAX_ENTRIES) {
+ errno = ENOMEM;
+ return (-1);
+ }
+
+ e = &(acl_int->acl_entry[acl_int->acl_cnt]);
+ e->ae_perm = perm;
+ e->ae_tag = tag;
+ e->ae_id = id;
+ acl_int->acl_cnt++;
+
+ return (0);
+}
+
+/*
+ * Convert "old" type - ACL_TYPE_{ACCESS,DEFAULT}_OLD - into its "new"
+ * counterpart. It's necessary for the old (pre-NFSv4 ACLs) binaries
+ * to work with new libc and kernel. Fixing 'type' for old binaries with
+ * old libc and new kernel is being done by kern/vfs_acl.c:type_unold().
+ */
+int
+_acl_type_unold(acl_type_t type)
+{
+
+ switch (type) {
+ case ACL_TYPE_ACCESS_OLD:
+ return (ACL_TYPE_ACCESS);
+ case ACL_TYPE_DEFAULT_OLD:
+ return (ACL_TYPE_DEFAULT);
+ default:
+ return (type);
+ }
+}
+
+char *
+string_skip_whitespace(char *string)
+{
+
+ while (*string && ((*string == ' ') || (*string == '\t')))
+ string++;
+
+ return (string);
+}
+
+void
+string_trim_trailing_whitespace(char *string)
+{
+ char *end;
+
+ if (*string == '\0')
+ return;
+
+ end = string + strlen(string) - 1;
+
+ while (end != string) {
+ if ((*end == ' ') || (*end == '\t')) {
+ *end = '\0';
+ end--;
+ } else {
+ return;
+ }
+ }
+
+ return;
+}
diff --git a/lib/libc/posix1e/acl_support.h b/lib/libc/posix1e/acl_support.h
new file mode 100644
index 000000000000..e7f35d5ad68c
--- /dev/null
+++ b/lib/libc/posix1e/acl_support.h
@@ -0,0 +1,68 @@
+/*-
+ * Copyright (c) 1999, 2000, 2001 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+/*
+ * Support functionality for the POSIX.1e ACL interface
+ * These calls are intended only to be called within the library.
+ */
+#ifndef _ACL_SUPPORT_H
+#define _ACL_SUPPORT_H
+
+#define _POSIX1E_ACL_STRING_PERM_MAXSIZE 3 /* read, write, exec */
+#define _ACL_T_ALIGNMENT_BITS 13
+
+int _acl_type_unold(acl_type_t type);
+int _acl_differs(const acl_t a, const acl_t b);
+int _acl_type_not_valid_for_acl(const acl_t acl, acl_type_t type);
+void _acl_brand_from_type(acl_t acl, acl_type_t type);
+int _acl_brand(const acl_t acl);
+int _entry_brand(const acl_entry_t entry);
+int _acl_brand_may_be(const acl_t acl, int brand);
+int _entry_brand_may_be(const acl_entry_t entry, int brand);
+void _acl_brand_as(acl_t acl, int brand);
+void _entry_brand_as(const acl_entry_t entry, int brand);
+int _nfs4_acl_entry_from_text(acl_t, char *);
+char *_nfs4_acl_to_text_np(const acl_t, ssize_t *, int);
+int _nfs4_format_flags(char *str, size_t size, acl_flag_t var, int verbose);
+int _nfs4_format_access_mask(char *str, size_t size, acl_perm_t var, int verbose);
+int _nfs4_parse_flags(const char *str, acl_flag_t *var);
+int _nfs4_parse_access_mask(const char *str, acl_perm_t *var);
+int _posix1e_acl_check(acl_t acl);
+void _posix1e_acl_sort(acl_t acl);
+int _posix1e_acl(acl_t acl, acl_type_t type);
+int _posix1e_acl_id_to_name(acl_tag_t tag, uid_t id, ssize_t buf_len,
+ char *buf, int flags);
+int _posix1e_acl_perm_to_string(acl_perm_t perm, ssize_t buf_len,
+ char *buf);
+int _posix1e_acl_string_to_perm(char *string, acl_perm_t *perm);
+int _posix1e_acl_add_entry(acl_t acl, acl_tag_t tag, uid_t id,
+ acl_perm_t perm);
+char *string_skip_whitespace(char *string);
+void string_trim_trailing_whitespace(char *string);
+int _acl_name_to_id(acl_tag_t tag, char *name, uid_t *id);
+
+#endif
diff --git a/lib/libc/posix1e/acl_support_nfs4.c b/lib/libc/posix1e/acl_support_nfs4.c
new file mode 100644
index 000000000000..7dd7f04daaf3
--- /dev/null
+++ b/lib/libc/posix1e/acl_support_nfs4.c
@@ -0,0 +1,261 @@
+/*-
+ * Copyright (c) 2008, 2009 Edward Tomasz Napierała <trasz@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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <err.h>
+#include <sys/acl.h>
+#include "acl_support.h"
+
+struct flagnames_struct {
+ uint32_t flag;
+ const char *name;
+ char letter;
+};
+
+struct flagnames_struct a_flags[] =
+ {{ ACL_ENTRY_FILE_INHERIT, "file_inherit", 'f'},
+ { ACL_ENTRY_DIRECTORY_INHERIT, "dir_inherit", 'd'},
+ { ACL_ENTRY_INHERIT_ONLY, "inherit_only", 'i'},
+ { ACL_ENTRY_NO_PROPAGATE_INHERIT, "no_propagate", 'n'},
+ { ACL_ENTRY_SUCCESSFUL_ACCESS, "successfull_access", 'S'},
+ { ACL_ENTRY_FAILED_ACCESS, "failed_access", 'F'},
+ { ACL_ENTRY_INHERITED, "inherited", 'I' },
+ /*
+ * There is no ACE_IDENTIFIER_GROUP here - SunOS does not show it
+ * in the "flags" field. There is no ACE_OWNER, ACE_GROUP or
+ * ACE_EVERYONE either, for obvious reasons.
+ */
+ { 0, 0, 0}};
+
+struct flagnames_struct a_access_masks[] =
+ {{ ACL_READ_DATA, "read_data", 'r'},
+ { ACL_WRITE_DATA, "write_data", 'w'},
+ { ACL_EXECUTE, "execute", 'x'},
+ { ACL_APPEND_DATA, "append_data", 'p'},
+ { ACL_DELETE_CHILD, "delete_child", 'D'},
+ { ACL_DELETE, "delete", 'd'},
+ { ACL_READ_ATTRIBUTES, "read_attributes", 'a'},
+ { ACL_WRITE_ATTRIBUTES, "write_attributes", 'A'},
+ { ACL_READ_NAMED_ATTRS, "read_xattr", 'R'},
+ { ACL_WRITE_NAMED_ATTRS, "write_xattr", 'W'},
+ { ACL_READ_ACL, "read_acl", 'c'},
+ { ACL_WRITE_ACL, "write_acl", 'C'},
+ { ACL_WRITE_OWNER, "write_owner", 'o'},
+ { ACL_SYNCHRONIZE, "synchronize", 's'},
+ { ACL_FULL_SET, "full_set", '\0'},
+ { ACL_MODIFY_SET, "modify_set", '\0'},
+ { ACL_READ_SET, "read_set", '\0'},
+ { ACL_WRITE_SET, "write_set", '\0'},
+ { 0, 0, 0}};
+
+static const char *
+format_flag(uint32_t *var, const struct flagnames_struct *flags)
+{
+
+ for (; flags->name != NULL; flags++) {
+ if ((flags->flag & *var) == 0)
+ continue;
+
+ *var &= ~flags->flag;
+ return (flags->name);
+ }
+
+ return (NULL);
+}
+
+static int
+format_flags_verbose(char *str, size_t size, uint32_t var,
+ const struct flagnames_struct *flags)
+{
+ size_t off = 0;
+ const char *tmp;
+
+ while ((tmp = format_flag(&var, flags)) != NULL) {
+ off += snprintf(str + off, size - off, "%s/", tmp);
+ assert (off < size);
+ }
+
+ /* If there were any flags added... */
+ if (off > 0) {
+ off--;
+ /* ... then remove the last slash. */
+ assert(str[off] == '/');
+ }
+
+ str[off] = '\0';
+
+ return (0);
+}
+
+static int
+format_flags_compact(char *str, size_t size, uint32_t var,
+ const struct flagnames_struct *flags)
+{
+ size_t i;
+
+ for (i = 0; flags[i].letter != '\0'; i++) {
+ assert(i < size);
+ if ((flags[i].flag & var) == 0)
+ str[i] = '-';
+ else
+ str[i] = flags[i].letter;
+ }
+
+ str[i] = '\0';
+
+ return (0);
+}
+
+static int
+parse_flags_verbose(const char *strp, uint32_t *var,
+ const struct flagnames_struct *flags, const char *flags_name,
+ int *try_compact)
+{
+ int i, found, ever_found = 0;
+ char *str, *flag;
+
+ str = strdup(strp);
+ *try_compact = 0;
+ *var = 0;
+
+ while (str != NULL) {
+ flag = strsep(&str, "/:");
+
+ found = 0;
+ for (i = 0; flags[i].name != NULL; i++) {
+ if (strcmp(flags[i].name, flag) == 0) {
+ *var |= flags[i].flag;
+ found = 1;
+ ever_found = 1;
+ }
+ }
+
+ if (!found) {
+ if (ever_found)
+ warnx("malformed ACL: \"%s\" field contains "
+ "invalid flag \"%s\"", flags_name, flag);
+ else
+ *try_compact = 1;
+ free(str);
+ return (-1);
+ }
+ }
+
+ free(str);
+ return (0);
+}
+
+static int
+parse_flags_compact(const char *str, uint32_t *var,
+ const struct flagnames_struct *flags, const char *flags_name)
+{
+ int i, j, found;
+
+ *var = 0;
+
+ for (i = 0;; i++) {
+ if (str[i] == '\0')
+ return (0);
+
+ /* Ignore minus signs. */
+ if (str[i] == '-')
+ continue;
+
+ found = 0;
+
+ for (j = 0; flags[j].name != NULL; j++) {
+ if (flags[j].letter == str[i]) {
+ *var |= flags[j].flag;
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ warnx("malformed ACL: \"%s\" field contains "
+ "invalid flag \"%c\"", flags_name, str[i]);
+ return (-1);
+ }
+ }
+}
+
+int
+_nfs4_format_flags(char *str, size_t size, acl_flag_t var, int verbose)
+{
+
+ if (verbose)
+ return (format_flags_verbose(str, size, var, a_flags));
+
+ return (format_flags_compact(str, size, var, a_flags));
+}
+
+int
+_nfs4_format_access_mask(char *str, size_t size, acl_perm_t var, int verbose)
+{
+
+ if (verbose)
+ return (format_flags_verbose(str, size, var, a_access_masks));
+
+ return (format_flags_compact(str, size, var, a_access_masks));
+}
+
+int
+_nfs4_parse_flags(const char *str, acl_flag_t *flags)
+{
+ int error, try_compact;
+ int tmpflags;
+
+ error = parse_flags_verbose(str, &tmpflags, a_flags, "flags", &try_compact);
+ if (error && try_compact)
+ error = parse_flags_compact(str, &tmpflags, a_flags, "flags");
+
+ *flags = tmpflags;
+
+ return (error);
+}
+
+int
+_nfs4_parse_access_mask(const char *str, acl_perm_t *perms)
+{
+ int error, try_compact;
+ int tmpperms;
+
+ error = parse_flags_verbose(str, &tmpperms, a_access_masks,
+ "access permissions", &try_compact);
+ if (error && try_compact)
+ error = parse_flags_compact(str, &tmpperms,
+ a_access_masks, "access permissions");
+
+ *perms = tmpperms;
+
+ return (error);
+}
diff --git a/lib/libc/posix1e/acl_to_text.3 b/lib/libc/posix1e/acl_to_text.3
new file mode 100644
index 000000000000..08fec2005195
--- /dev/null
+++ b/lib/libc/posix1e/acl_to_text.3
@@ -0,0 +1,158 @@
+.\"-
+.\" Copyright (c) 2000, 2002 Robert N. M. Watson
+.\" All rights reserved.
+.\"
+.\" This software was developed by Robert Watson for the TrustedBSD Project.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd June 25, 2009
+.Dt ACL_TO_TEXT 3
+.Os
+.Sh NAME
+.Nm acl_to_text ,
+.Nm acl_to_text_np
+.Nd convert an ACL to text
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft char *
+.Fn acl_to_text "acl_t acl" "ssize_t *len_p"
+.Ft char *
+.Fn acl_to_text_np "acl_t acl" "ssize_t *len_p" "int flags"
+.Sh DESCRIPTION
+The
+.Fn acl_to_text
+and
+.Fn acl_to_text_np
+functions translate the ACL pointed to by argument
+.Va acl
+into a NULL terminated character string.
+If the pointer
+.Va len_p
+is not NULL, then the function shall return the length of the string (not
+including the NULL terminator) in the location pointed to by
+.Va len_p .
+If the ACL is POSIX.1e, the format of the text string returned by
+.Fn acl_to_text
+shall be the POSIX.1e long ACL form. If the ACL is NFSv4, the format
+of the text string shall be the compact form, unless the
+.Va ACL_TEXT_VERBOSE
+flag is given.
+.Pp
+The flags specified are formed by
+.Em or Ns 'ing
+the following values
+.Bl -column -offset 3n "ACL_TEXT_NUMERIC_IDS"
+.It ACL_TEXT_VERBOSE Ta "Format ACL using verbose form"
+.It ACL_TEXT_NUMERIC_IDS Ta "Do not resolve IDs into user or group names"
+.It ACL_TEXT_APPEND_ID Ta "In addition to user and group names, append numeric IDs"
+.El
+.Pp
+This function allocates any memory necessary to contain the string and
+returns a pointer to the string.
+The caller should free any releasable
+memory, when the new string is no longer required, by calling
+.Xr acl_free 3
+with the
+.Va (void*)char
+as an argument.
+.Sh IMPLEMENTATION NOTES
+.Fx Ns 's
+support for POSIX.1e interfaces and features is still under
+development at this time.
+.Sh RETURN VALUES
+Upon successful completion, the function shall return a pointer to the
+long text form of an ACL.
+Otherwise, a value of
+.Va (char*)NULL
+shall be returned and
+.Va errno
+shall be set to indicate the error.
+.Sh ERRORS
+If any of the following conditions occur, the
+.Fn acl_to_text
+function shall return a value of
+.Va (acl_t)NULL
+and set
+.Va errno
+to the corresponding value:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Argument
+.Va acl
+does not point to a valid ACL.
+.Pp
+The ACL denoted by
+.Va acl
+contains one or more improperly formed ACL entries, or for some other
+reason cannot be translated into a text form of an ACL.
+.It Bq Er ENOMEM
+The character string to be returned requires more memory than is allowed
+by the hardware or software-imposed memory management constraints.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_free 3 ,
+.Xr acl_from_text 3 ,
+.Xr posix1e 3
+.Sh STANDARDS
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+Discussion
+of the draft continues on the cross-platform POSIX.1e implementation
+mailing list.
+To join this list, see the
+.Fx
+POSIX.1e implementation
+page for more information.
+.Sh HISTORY
+POSIX.1e support was introduced in
+.Fx 4.0 ,
+and development continues.
+.Sh AUTHORS
+.An Robert N M Watson
+.Sh BUGS
+The
+.Fn acl_from_text
+and
+.Fn acl_to_text
+functions
+rely on the
+.Xr getpwent 3
+library calls to manage username and uid mapping, as well as the
+.Xr getgrent 3
+library calls to manage groupname and gid mapping.
+These calls are not
+thread safe, and so transitively, neither are
+.Fn acl_from_text
+and
+.Fn acl_to_text .
+These functions may also interfere with stateful
+calls associated with the
+.Fn getpwent
+and
+.Fn getgrent
+calls.
diff --git a/lib/libc/posix1e/acl_to_text.c b/lib/libc/posix1e/acl_to_text.c
new file mode 100644
index 000000000000..e5fd1f79d1ce
--- /dev/null
+++ b/lib/libc/posix1e/acl_to_text.c
@@ -0,0 +1,261 @@
+/*-
+ * Copyright (c) 1999-2002 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * acl_to_text - return a text string with a text representation of the acl
+ * in it.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include "namespace.h"
+#include <sys/acl.h>
+#include "un-namespace.h"
+#include <sys/errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "acl_support.h"
+
+/*
+ * acl_to_text - generate a text form of an acl
+ * spec says nothing about output ordering, so leave in acl order
+ *
+ * This function will not produce nice results if it is called with
+ * a non-POSIX.1e semantics ACL.
+ */
+
+char *_nfs4_acl_to_text_np(const acl_t acl, ssize_t *len_p, int flags);
+
+static char *
+_posix1e_acl_to_text(acl_t acl, ssize_t *len_p, int flags)
+{
+ struct acl *acl_int;
+ char *buf, *tmpbuf;
+ char name_buf[MAXLOGNAME];
+ char perm_buf[_POSIX1E_ACL_STRING_PERM_MAXSIZE+1],
+ effective_perm_buf[_POSIX1E_ACL_STRING_PERM_MAXSIZE+1];
+ int i, error, len;
+ uid_t ae_id;
+ acl_tag_t ae_tag;
+ acl_perm_t ae_perm, effective_perm, mask_perm;
+
+ buf = strdup("");
+ if (buf == NULL)
+ return(NULL);
+
+ acl_int = &acl->ats_acl;
+
+ mask_perm = ACL_PERM_BITS; /* effective is regular if no mask */
+ for (i = 0; i < acl_int->acl_cnt; i++)
+ if (acl_int->acl_entry[i].ae_tag == ACL_MASK)
+ mask_perm = acl_int->acl_entry[i].ae_perm;
+
+ for (i = 0; i < acl_int->acl_cnt; i++) {
+ ae_tag = acl_int->acl_entry[i].ae_tag;
+ ae_id = acl_int->acl_entry[i].ae_id;
+ ae_perm = acl_int->acl_entry[i].ae_perm;
+
+ switch(ae_tag) {
+ case ACL_USER_OBJ:
+ error = _posix1e_acl_perm_to_string(ae_perm,
+ _POSIX1E_ACL_STRING_PERM_MAXSIZE+1, perm_buf);
+ if (error)
+ goto error_label;
+ len = asprintf(&tmpbuf, "%suser::%s\n", buf,
+ perm_buf);
+ if (len == -1)
+ goto error_label;
+ free(buf);
+ buf = tmpbuf;
+ break;
+
+ case ACL_USER:
+ error = _posix1e_acl_perm_to_string(ae_perm,
+ _POSIX1E_ACL_STRING_PERM_MAXSIZE+1, perm_buf);
+ if (error)
+ goto error_label;
+
+ error = _posix1e_acl_id_to_name(ae_tag, ae_id,
+ MAXLOGNAME, name_buf, flags);
+ if (error)
+ goto error_label;
+
+ effective_perm = ae_perm & mask_perm;
+ if (effective_perm != ae_perm) {
+ error = _posix1e_acl_perm_to_string(
+ effective_perm,
+ _POSIX1E_ACL_STRING_PERM_MAXSIZE+1,
+ effective_perm_buf);
+ if (error)
+ goto error_label;
+ len = asprintf(&tmpbuf, "%suser:%s:%s\t\t# "
+ "effective: %s\n",
+ buf, name_buf, perm_buf,
+ effective_perm_buf);
+ } else {
+ len = asprintf(&tmpbuf, "%suser:%s:%s\n", buf,
+ name_buf, perm_buf);
+ }
+ if (len == -1)
+ goto error_label;
+ free(buf);
+ buf = tmpbuf;
+ break;
+
+ case ACL_GROUP_OBJ:
+ error = _posix1e_acl_perm_to_string(ae_perm,
+ _POSIX1E_ACL_STRING_PERM_MAXSIZE+1, perm_buf);
+ if (error)
+ goto error_label;
+
+ effective_perm = ae_perm & mask_perm;
+ if (effective_perm != ae_perm) {
+ error = _posix1e_acl_perm_to_string(
+ effective_perm,
+ _POSIX1E_ACL_STRING_PERM_MAXSIZE+1,
+ effective_perm_buf);
+ if (error)
+ goto error_label;
+ len = asprintf(&tmpbuf, "%sgroup::%s\t\t# "
+ "effective: %s\n",
+ buf, perm_buf, effective_perm_buf);
+ } else {
+ len = asprintf(&tmpbuf, "%sgroup::%s\n", buf,
+ perm_buf);
+ }
+ if (len == -1)
+ goto error_label;
+ free(buf);
+ buf = tmpbuf;
+ break;
+
+ case ACL_GROUP:
+ error = _posix1e_acl_perm_to_string(ae_perm,
+ _POSIX1E_ACL_STRING_PERM_MAXSIZE+1, perm_buf);
+ if (error)
+ goto error_label;
+
+ error = _posix1e_acl_id_to_name(ae_tag, ae_id,
+ MAXLOGNAME, name_buf, flags);
+ if (error)
+ goto error_label;
+
+ effective_perm = ae_perm & mask_perm;
+ if (effective_perm != ae_perm) {
+ error = _posix1e_acl_perm_to_string(
+ effective_perm,
+ _POSIX1E_ACL_STRING_PERM_MAXSIZE+1,
+ effective_perm_buf);
+ if (error)
+ goto error_label;
+ len = asprintf(&tmpbuf, "%sgroup:%s:%s\t\t# "
+ "effective: %s\n",
+ buf, name_buf, perm_buf,
+ effective_perm_buf);
+ } else {
+ len = asprintf(&tmpbuf, "%sgroup:%s:%s\n", buf,
+ name_buf, perm_buf);
+ }
+ if (len == -1)
+ goto error_label;
+ free(buf);
+ buf = tmpbuf;
+ break;
+
+ case ACL_MASK:
+ error = _posix1e_acl_perm_to_string(ae_perm,
+ _POSIX1E_ACL_STRING_PERM_MAXSIZE+1, perm_buf);
+ if (error)
+ goto error_label;
+
+ len = asprintf(&tmpbuf, "%smask::%s\n", buf,
+ perm_buf);
+ if (len == -1)
+ goto error_label;
+ free(buf);
+ buf = tmpbuf;
+ break;
+
+ case ACL_OTHER:
+ error = _posix1e_acl_perm_to_string(ae_perm,
+ _POSIX1E_ACL_STRING_PERM_MAXSIZE+1, perm_buf);
+ if (error)
+ goto error_label;
+
+ len = asprintf(&tmpbuf, "%sother::%s\n", buf,
+ perm_buf);
+ if (len == -1)
+ goto error_label;
+ free(buf);
+ buf = tmpbuf;
+ break;
+
+ default:
+ errno = EINVAL;
+ goto error_label;
+ }
+ }
+
+ if (len_p) {
+ *len_p = strlen(buf);
+ }
+ return (buf);
+
+error_label:
+ /* jump to here sets errno already, we just clean up */
+ if (buf) free(buf);
+ return (NULL);
+}
+
+char *
+acl_to_text_np(acl_t acl, ssize_t *len_p, int flags)
+{
+
+ if (acl == NULL) {
+ errno = EINVAL;
+ return(NULL);
+ }
+
+ switch (_acl_brand(acl)) {
+ case ACL_BRAND_POSIX:
+ return (_posix1e_acl_to_text(acl, len_p, flags));
+ case ACL_BRAND_NFS4:
+ return (_nfs4_acl_to_text_np(acl, len_p, flags));
+ default:
+ errno = EINVAL;
+ return (NULL);
+ }
+}
+
+char *
+acl_to_text(acl_t acl, ssize_t *len_p)
+{
+
+ return (acl_to_text_np(acl, len_p, 0));
+}
diff --git a/lib/libc/posix1e/acl_to_text_nfs4.c b/lib/libc/posix1e/acl_to_text_nfs4.c
new file mode 100644
index 000000000000..f9945ab1d410
--- /dev/null
+++ b/lib/libc/posix1e/acl_to_text_nfs4.c
@@ -0,0 +1,264 @@
+/*-
+ * Copyright (c) 2008, 2009 Edward Tomasz Napierała <trasz@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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <assert.h>
+#include <string.h>
+#include <pwd.h>
+#include <grp.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/acl.h>
+
+#include "acl_support.h"
+
+#define MAX_ENTRY_LENGTH 512
+
+static int
+format_who(char *str, size_t size, const acl_entry_t entry, int numeric)
+{
+ int error;
+ acl_tag_t tag;
+ struct passwd *pwd;
+ struct group *grp;
+ uid_t *id;
+
+ error = acl_get_tag_type(entry, &tag);
+ if (error)
+ return (error);
+
+ switch (tag) {
+ case ACL_USER_OBJ:
+ snprintf(str, size, "owner@");
+ break;
+
+ case ACL_USER:
+ id = (uid_t *)acl_get_qualifier(entry);
+ if (id == NULL)
+ return (-1);
+ /* XXX: Thread-unsafe. */
+ if (!numeric)
+ pwd = getpwuid(*id);
+ else
+ pwd = NULL;
+ if (pwd == NULL)
+ snprintf(str, size, "user:%d", (unsigned int)*id);
+ else
+ snprintf(str, size, "user:%s", pwd->pw_name);
+ break;
+
+ case ACL_GROUP_OBJ:
+ snprintf(str, size, "group@");
+ break;
+
+ case ACL_GROUP:
+ id = (uid_t *)acl_get_qualifier(entry);
+ if (id == NULL)
+ return (-1);
+ /* XXX: Thread-unsafe. */
+ if (!numeric)
+ grp = getgrgid(*id);
+ else
+ grp = NULL;
+ if (grp == NULL)
+ snprintf(str, size, "group:%d", (unsigned int)*id);
+ else
+ snprintf(str, size, "group:%s", grp->gr_name);
+ break;
+
+ case ACL_EVERYONE:
+ snprintf(str, size, "everyone@");
+ break;
+
+ default:
+ return (-1);
+ }
+
+ return (0);
+}
+
+static int
+format_entry_type(char *str, size_t size, const acl_entry_t entry)
+{
+ int error;
+ acl_entry_type_t entry_type;
+
+ error = acl_get_entry_type_np(entry, &entry_type);
+ if (error)
+ return (error);
+
+ switch (entry_type) {
+ case ACL_ENTRY_TYPE_ALLOW:
+ snprintf(str, size, "allow");
+ break;
+ case ACL_ENTRY_TYPE_DENY:
+ snprintf(str, size, "deny");
+ break;
+ case ACL_ENTRY_TYPE_AUDIT:
+ snprintf(str, size, "audit");
+ break;
+ case ACL_ENTRY_TYPE_ALARM:
+ snprintf(str, size, "alarm");
+ break;
+ default:
+ return (-1);
+ }
+
+ return (0);
+}
+
+static int
+format_additional_id(char *str, size_t size, const acl_entry_t entry)
+{
+ int error;
+ acl_tag_t tag;
+ uid_t *id;
+
+ error = acl_get_tag_type(entry, &tag);
+ if (error)
+ return (error);
+
+ switch (tag) {
+ case ACL_USER_OBJ:
+ case ACL_GROUP_OBJ:
+ case ACL_EVERYONE:
+ str[0] = '\0';
+ break;
+
+ default:
+ id = (uid_t *)acl_get_qualifier(entry);
+ if (id == NULL)
+ return (-1);
+ snprintf(str, size, ":%d", (unsigned int)*id);
+ }
+
+ return (0);
+}
+
+static int
+format_entry(char *str, size_t size, const acl_entry_t entry, int flags)
+{
+ size_t off = 0, min_who_field_length = 18;
+ acl_permset_t permset;
+ acl_flagset_t flagset;
+ int error, len;
+ char buf[MAX_ENTRY_LENGTH + 1];
+
+ assert(_entry_brand(entry) == ACL_BRAND_NFS4);
+
+ error = acl_get_flagset_np(entry, &flagset);
+ if (error)
+ return (error);
+
+ error = acl_get_permset(entry, &permset);
+ if (error)
+ return (error);
+
+ error = format_who(buf, sizeof(buf), entry,
+ flags & ACL_TEXT_NUMERIC_IDS);
+ if (error)
+ return (error);
+ len = strlen(buf);
+ if (len < min_who_field_length)
+ len = min_who_field_length;
+ off += snprintf(str + off, size - off, "%*s:", len, buf);
+
+ error = _nfs4_format_access_mask(buf, sizeof(buf), *permset,
+ flags & ACL_TEXT_VERBOSE);
+ if (error)
+ return (error);
+ off += snprintf(str + off, size - off, "%s:", buf);
+
+ error = _nfs4_format_flags(buf, sizeof(buf), *flagset,
+ flags & ACL_TEXT_VERBOSE);
+ if (error)
+ return (error);
+ off += snprintf(str + off, size - off, "%s:", buf);
+
+ error = format_entry_type(buf, sizeof(buf), entry);
+ if (error)
+ return (error);
+ off += snprintf(str + off, size - off, "%s", buf);
+
+ if (flags & ACL_TEXT_APPEND_ID) {
+ error = format_additional_id(buf, sizeof(buf), entry);
+ if (error)
+ return (error);
+ off += snprintf(str + off, size - off, "%s", buf);
+ }
+
+ off += snprintf(str + off, size - off, "\n");
+
+ /* Make sure we didn't truncate anything. */
+ assert (off < size);
+
+ return (0);
+}
+
+char *
+_nfs4_acl_to_text_np(const acl_t aclp, ssize_t *len_p, int flags)
+{
+ int error, off = 0, size, entry_id = ACL_FIRST_ENTRY;
+ char *str;
+ acl_entry_t entry;
+
+ if (aclp->ats_acl.acl_cnt == 0)
+ return strdup("");
+
+ size = aclp->ats_acl.acl_cnt * MAX_ENTRY_LENGTH;
+ str = malloc(size);
+ if (str == NULL)
+ return (NULL);
+
+ while (acl_get_entry(aclp, entry_id, &entry) == 1) {
+ entry_id = ACL_NEXT_ENTRY;
+
+ assert(off < size);
+
+ error = format_entry(str + off, size - off, entry, flags);
+ if (error) {
+ free(str);
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ off = strlen(str);
+ }
+
+ assert(off < size);
+ str[off] = '\0';
+
+ if (len_p != NULL)
+ *len_p = off;
+
+ return (str);
+}
diff --git a/lib/libc/posix1e/acl_valid.3 b/lib/libc/posix1e/acl_valid.3
new file mode 100644
index 000000000000..83f7746774a9
--- /dev/null
+++ b/lib/libc/posix1e/acl_valid.3
@@ -0,0 +1,170 @@
+.\"-
+.\" Copyright (c) 2000, 2002 Robert N. M. Watson
+.\" All rights reserved.
+.\"
+.\" This software was developed by Robert Watson for the TrustedBSD Project.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd December 29, 2002
+.Dt ACL_VALID 3
+.Os
+.Sh NAME
+.Nm acl_valid ,
+.Nm acl_valid_fd_np ,
+.Nm acl_valid_file_np ,
+.Nm acl_valid_link_np
+.Nd validate an ACL
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.Ft int
+.Fn acl_valid "acl_t acl"
+.Ft int
+.Fn acl_valid_fd_np "int fd" "acl_type_t type" "acl_t acl"
+.Ft int
+.Fn acl_valid_file_np "const char *path_p" "acl_type_t type" "acl_t acl"
+.Ft int
+.Fn acl_valid_link_np "const char *path_p" "acl_type_t type" "acl_t acl"
+.Sh DESCRIPTION
+These functions check that the ACL referred to by the argument
+.Va acl
+is valid.
+The POSIX.1e routine,
+.Fn acl_valid ,
+checks this validity only with POSIX.1e ACL semantics, and irrespective
+of the context in which the ACL is to be used.
+The non-portable forms,
+.Fn acl_valid_fd_np ,
+.Fn acl_valid_file_np ,
+and
+.Fn acl_valid_link_np
+allow an ACL to be checked in the context of a specific acl type,
+.Va type ,
+and file system object.
+In environments where additional ACL types are
+supported than just POSIX.1e, this makes more sense.
+Whereas
+.Fn acl_valid_file_np
+will follow the symlink if the specified path is to a symlink,
+.Fn acl_valid_link_np
+will not.
+.Pp
+For POSIX.1e semantics, the checks include:
+.Bl -bullet
+.It
+The three required entries
+.Dv ( ACL_USER_OBJ , ACL_GROUP_OBJ ,
+and
+.Dv ACL_OTHER )
+shall exist exactly once in the ACL.
+If the ACL contains any
+.Dv ACL_USER , ACL_GROUP ,
+or any other
+implementation-defined entries in the file group class
+then one
+.Dv ACL_MASK
+entry shall also be required.
+The ACL shall contain at most one
+.Dv ACL_MASK
+entry.
+.It
+The qualifier field shall be unique among all entries of
+the same POSIX.1e ACL facility defined tag type.
+The
+tag type field shall contain valid values including any
+implementation-defined values.
+Validation of the values
+of the qualifier field is implementation-defined.
+.El
+.Pp
+The POSIX.1e
+.Fn acl_valid
+function may reorder the ACL for the purposes of verification; the
+non-portable validation functions will not.
+.Sh IMPLEMENTATION NOTES
+.Fx Ns 's
+support for POSIX.1e interfaces and features is still under
+development at this time.
+.Sh RETURN VALUES
+.Rv -std
+.Sh ERRORS
+If any of the following conditions occur, these functions shall return
+-1 and set
+.Va errno
+to the corresponding value:
+.Bl -tag -width Er
+.It Bq Er EACCES
+Search permission is denied for a component of the path prefix, or the
+object exists and the process does not have appropriate access rights.
+.It Bq Er EBADF
+The
+.Va fd
+argument is not a valid file descriptor.
+.It Bq Er EINVAL
+Argument
+.Va acl
+does not point to a valid ACL.
+.Pp
+One or more of the required ACL entries is not present in
+.Va acl .
+.Pp
+The ACL contains entries that are not unique.
+.Pp
+The file system rejects the ACL based on fs-specific semantics issues.
+.It Bq Er ENAMETOOLONG
+A component of a pathname exceeded 255 characters, or an
+entire path name exceeded 1023 characters.
+.It Bq Er ENOENT
+The named object does not exist, or the
+.Va path_p
+argument points to an empty string.
+.It Bq Er ENOMEM
+Insufficient memory available to fulfill request.
+.It Bq Er EOPNOTSUPP
+The file system does not support ACL retrieval.
+.El
+.Sh SEE ALSO
+.Xr acl 3 ,
+.Xr acl_get 3 ,
+.Xr acl_init 3 ,
+.Xr acl_set 3 ,
+.Xr posix1e 3
+.Sh STANDARDS
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+Discussion
+of the draft continues on the cross-platform POSIX.1e implementation
+mailing list.
+To join this list, see the
+.Fx
+POSIX.1e implementation
+page for more information.
+.Sh HISTORY
+POSIX.1e support was introduced in
+.Fx 4.0 ,
+and development continues.
+.Sh AUTHORS
+.An Robert N M Watson
diff --git a/lib/libc/posix1e/acl_valid.c b/lib/libc/posix1e/acl_valid.c
new file mode 100644
index 000000000000..d4cb872e2145
--- /dev/null
+++ b/lib/libc/posix1e/acl_valid.c
@@ -0,0 +1,124 @@
+/*-
+ * Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * This software was developed by Robert Watson for the TrustedBSD Project.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * acl_valid -- POSIX.1e ACL check routine
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include "namespace.h"
+#include <sys/acl.h>
+#include "un-namespace.h"
+#include <sys/errno.h>
+#include <stdlib.h>
+
+#include "acl_support.h"
+
+/*
+ * acl_valid: accepts an ACL, returns 0 on valid ACL, -1 for invalid,
+ * and errno set to EINVAL.
+ *
+ * Implemented by calling the acl_check routine in acl_support, which
+ * requires ordering. We call acl_support's _posix1e_acl_sort to make this
+ * true. POSIX.1e allows acl_valid() to reorder the ACL as it sees fit.
+ *
+ * This call is deprecated, as it doesn't ask whether the ACL is valid
+ * for a particular target. However, this call is standardized, unlike
+ * the other two forms.
+ */
+int
+acl_valid(acl_t acl)
+{
+ int error;
+
+ if (acl == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+ if (!_acl_brand_may_be(acl, ACL_BRAND_POSIX)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ _posix1e_acl_sort(acl);
+ error = _posix1e_acl_check(acl);
+ if (error) {
+ errno = error;
+ return (-1);
+ } else {
+ return (0);
+ }
+}
+
+int
+acl_valid_file_np(const char *pathp, acl_type_t type, acl_t acl)
+{
+
+ if (pathp == NULL || acl == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+ type = _acl_type_unold(type);
+ if (_posix1e_acl(acl, type))
+ _posix1e_acl_sort(acl);
+
+ return (__acl_aclcheck_file(pathp, type, &acl->ats_acl));
+}
+
+int
+acl_valid_link_np(const char *pathp, acl_type_t type, acl_t acl)
+{
+
+ if (pathp == NULL || acl == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+ type = _acl_type_unold(type);
+ if (_posix1e_acl(acl, type))
+ _posix1e_acl_sort(acl);
+
+ return (__acl_aclcheck_link(pathp, type, &acl->ats_acl));
+}
+
+int
+acl_valid_fd_np(int fd, acl_type_t type, acl_t acl)
+{
+
+ if (acl == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+ type = _acl_type_unold(type);
+ if (_posix1e_acl(acl, type))
+ _posix1e_acl_sort(acl);
+
+ acl->ats_cur_entry = 0;
+
+ return (___acl_aclcheck_fd(fd, type, &acl->ats_acl));
+}
diff --git a/lib/libc/posix1e/extattr.3 b/lib/libc/posix1e/extattr.3
new file mode 100644
index 000000000000..5e606861c622
--- /dev/null
+++ b/lib/libc/posix1e/extattr.3
@@ -0,0 +1,100 @@
+.\"
+.\" Copyright (c) 2001 Dima Dorfman <dd@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 June 24, 2001
+.Dt EXTATTR 3
+.Os
+.Sh NAME
+.Nm extattr_namespace_to_string ,
+.Nm extattr_string_to_namespace
+.Nd convert an extended attribute namespace identifier to a string and
+vice versa
+.Sh LIBRARY
+.Lb libutil
+.Sh SYNOPSIS
+.In sys/extattr.h
+.In libutil.h
+.Ft int
+.Fn extattr_namespace_to_string "int attrnamespace" "char **string"
+.Ft int
+.Fn extattr_string_to_namespace "const char *string" "int *attrnamespace"
+.Sh DESCRIPTION
+The
+.Fn extattr_namespace_to_string
+function converts a VFS extended attribute identifier to a human-readable
+string;
+the
+.Fn extattr_string_to_namespace
+function undoes the aforementioned operation,
+and converts a human-readable string representing a namespace to a
+namespace identifier.
+Although a file system may implement arbitrary namespaces,
+these functions only support the
+.Dv EXTATTR_NAMESPACE_USER
+.Pq Dq user
+and
+.Dv EXTATTR_NAMESPACE_SYSTEM
+.Pq Dq system
+namespaces,
+which are defined in
+.Xr extattr 9 .
+.Pp
+These functions are meant to be used in error reporting and other
+interactive tasks.
+For example,
+instead of printing the integer identifying an extended attribute in
+an error message,
+a program might use
+.Fn extattr_namespace_to_string
+to obtain a human-readable representation.
+Likewise,
+instead of requiring a user to enter the integer representing a namespace,
+an interactive program might ask for a name and use
+.Fn extattr_string_to_namespace
+to get the desired identifier.
+.Sh RETURN VALUES
+If any of the calls are unsuccessful, the value \-1 is returned
+and the global variable
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The requested namespace could not be identified.
+.El
+.Sh SEE ALSO
+.Xr extattr 2 ,
+.Xr getextattr 8 ,
+.Xr setextattr 8 ,
+.Xr extattr 9
+.Sh HISTORY
+Extended attribute support was developed as part of the
+.Tn TrustedBSD
+Project, and introduced in
+.Fx 5.0 .
+It was developed to support security extensions requiring additional labels
+to be associated with each file or directory.
diff --git a/lib/libc/posix1e/extattr.c b/lib/libc/posix1e/extattr.c
new file mode 100644
index 000000000000..5a9ddce3a088
--- /dev/null
+++ b/lib/libc/posix1e/extattr.c
@@ -0,0 +1,77 @@
+/*-
+ * Copyright (c) 2001 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * TrustedBSD: Utility functions for extended attributes.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/extattr.h>
+
+#include <errno.h>
+#include <libutil.h>
+#include <string.h>
+
+int
+extattr_namespace_to_string(int attrnamespace, char **string)
+{
+
+ switch(attrnamespace) {
+ case EXTATTR_NAMESPACE_USER:
+ if (string != NULL)
+ *string = strdup(EXTATTR_NAMESPACE_USER_STRING);
+ return (0);
+
+ case EXTATTR_NAMESPACE_SYSTEM:
+ if (string != NULL)
+ *string = strdup(EXTATTR_NAMESPACE_SYSTEM_STRING);
+ return (0);
+
+ default:
+ errno = EINVAL;
+ return (-1);
+ }
+}
+
+int
+extattr_string_to_namespace(const char *string, int *attrnamespace)
+{
+
+ if (!strcmp(string, EXTATTR_NAMESPACE_USER_STRING)) {
+ if (attrnamespace != NULL)
+ *attrnamespace = EXTATTR_NAMESPACE_USER;
+ return (0);
+ } else if (!strcmp(string, EXTATTR_NAMESPACE_SYSTEM_STRING)) {
+ if (attrnamespace != NULL)
+ *attrnamespace = EXTATTR_NAMESPACE_SYSTEM;
+ return (0);
+ } else {
+ errno = EINVAL;
+ return (-1);
+ }
+}
diff --git a/lib/libc/posix1e/mac.3 b/lib/libc/posix1e/mac.3
new file mode 100644
index 000000000000..5d2d5c4f49df
--- /dev/null
+++ b/lib/libc/posix1e/mac.3
@@ -0,0 +1,165 @@
+.\" Copyright (c) 2001, 2003 Networks Associates Technology, Inc.
+.\" Copyright (c) 2009 Robert N. M. Watson
+.\" All rights reserved.
+.\"
+.\" This software was developed for the FreeBSD Project by Chris
+.\" Costello at Safeport Network Services and Network Associates
+.\" Laboratories, the Security Research Division of Network Associates,
+.\" Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part
+.\" of the DARPA CHATS research program.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd July 25, 2015
+.Dt MAC 3
+.Os
+.Sh NAME
+.Nm mac
+.Nd introduction to the MAC security API
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/mac.h
+.Pp
+In the kernel configuration file:
+.Cd "options MAC"
+.Sh DESCRIPTION
+Mandatory Access Control labels describe confidentiality, integrity, and
+other security attributes of operating system objects, overriding
+discretionary access control.
+Not all system objects support MAC labeling, and MAC policies must be
+explicitly enabled by the administrator.
+This API, based on POSIX.1e, includes routines to retrieve, manipulate, set,
+and convert to and from text the MAC labels on files and processes.
+.Pp
+MAC labels consist of a set of (name, value) tuples, representing security
+attributes from MAC policies.
+For example, this label contains security labels defined by two policies,
+.Xr mac_biba 4
+and
+.Xr mac_mls 4 :
+.Bd -literal -offset indent
+biba/low,mls/low
+.Ed
+.Pp
+Further syntax and semantics of MAC labels may be found in
+.Xr maclabel 7 .
+.Pp
+Applications operate on labels stored in
+.Vt mac_t ,
+but can convert between this internal format and a text format for the
+purposes of presentation to uses or external storage.
+When querying a label on an object, a
+.Vt mac_t
+must first be prepared using the interfaces described in
+.Xr mac_prepare 3 ,
+allowing the application to declare which policies it wishes to interrogate.
+The application writer can also rely on default label names declared in
+.Xr mac.conf 5 .
+.Pp
+When finished with a
+.Vt mac_t ,
+the application must call
+.Xr mac_free 3
+to release its storage.
+.Pp
+The following functions are defined:
+.Bl -tag -width indent
+.It Fn mac_is_present
+This function, described in
+.Xr mac_is_present 3 ,
+allows applications to test whether MAC is configured, as well as whether
+specific policies are configured.
+.It Fn mac_get_fd , Fn mac_get_file , Fn mac_get_link , Fn mac_get_peer
+These functions, described in
+.Xr mac_get 3 ,
+retrieve the MAC labels associated with file descriptors, files, and socket
+peers.
+.It Fn mac_get_pid , Fn mac_get_proc
+These functions, described in
+.Xr mac_get 3 ,
+retrieve the MAC labels associated with processes.
+.It Fn mac_set_fd , Fn mac_set_file , Fn mac_set_link
+These functions, described in
+.Xr mac_set 3 ,
+set the MAC labels associated with file descriptors and files.
+.It Fn mac_set_proc
+This function, described in
+.Xr mac_set 3 ,
+sets the MAC label associated with the current process.
+.It Fn mac_free
+This function, described in
+.Xr mac_free 3 ,
+frees working MAC label storage.
+.It Fn mac_from_text
+This function, described in
+.Xr mac_text 3 ,
+converts a text-form MAC label into working MAC label storage,
+.Vt mac_t .
+.It Fn mac_prepare , Fn mac_prepare_file_label , Fn mac_prepare_ifnet_label , Fn mac_prepare_process_label , Fn mac_prepare_type
+These functions, described in
+.Xr mac_prepare 3 ,
+allocate working storage for MAC label operations.
+.Xr mac_prepare 3
+prepares a label based on caller-specified label names; the other calls
+rely on the default configuration specified in
+.Xr mac.conf 5 .
+.It Fn mac_to_text
+This function is described in
+.Xr mac_text 3 ,
+and may be used to convert a
+.Vt mac_t
+into a text-form MAC label.
+.El
+.Sh FILES
+.Bl -tag -width ".Pa /etc/mac.conf" -compact
+.It Pa /etc/mac.conf
+MAC library configuration file, documented in
+.Xr mac.conf 5 .
+Provides default behavior for applications aware of MAC labels on
+system objects, but without policy-specific knowledge.
+.El
+.Sh SEE ALSO
+.Xr mac_free 3 ,
+.Xr mac_get 3 ,
+.Xr mac_is_present 3 ,
+.Xr mac_prepare 3 ,
+.Xr mac_set 3 ,
+.Xr mac_text 3 ,
+.Xr posix1e 3 ,
+.Xr mac 4 ,
+.Xr mac.conf 5 ,
+.Xr mac 9
+.Sh STANDARDS
+These APIs are loosely based on the APIs described in POSIX.1e, as described
+in IEEE POSIX.1e draft 17.
+However, the resemblance of these APIs to the POSIX APIs is loose, as the
+POSIX APIs were unable to express some notions required for flexible and
+extensible access control.
+.Sh HISTORY
+Support for Mandatory Access Control was introduced in
+.Fx 5.0
+as part of the
+.Tn TrustedBSD
+Project.
diff --git a/lib/libc/posix1e/mac.c b/lib/libc/posix1e/mac.c
new file mode 100644
index 000000000000..6bc9b773c22a
--- /dev/null
+++ b/lib/libc/posix1e/mac.c
@@ -0,0 +1,449 @@
+/*
+ * Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson
+ * Copyright (c) 2002, 2003 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * This software was developed by Robert Watson for the TrustedBSD Project.
+ *
+ * This software was developed for the FreeBSD Project in part by Network
+ * Associates Laboratories, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
+ * as part of the DARPA CHATS research program.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/sysctl.h>
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/mac.h>
+
+static int internal_initialized;
+
+/*
+ * Maintain a list of default label preparations for various object
+ * types. Each name will appear only once in the list.
+ *
+ * XXXMAC: Not thread-safe.
+ */
+static LIST_HEAD(, label_default) label_default_head;
+struct label_default {
+ char *ld_name;
+ char *ld_labels;
+ LIST_ENTRY(label_default) ld_entries;
+};
+
+static void
+mac_destroy_labels(void)
+{
+ struct label_default *ld;
+
+ while ((ld = LIST_FIRST(&label_default_head))) {
+ free(ld->ld_name);
+ free(ld->ld_labels);
+ LIST_REMOVE(ld, ld_entries);
+ free(ld);
+ }
+}
+
+static void
+mac_destroy_internal(void)
+{
+
+ mac_destroy_labels();
+
+ internal_initialized = 0;
+}
+
+static int
+mac_add_type(const char *name, const char *labels)
+{
+ struct label_default *ld, *ld_new;
+ char *name_dup, *labels_dup;
+
+ /*
+ * Speculatively allocate all the memory now to avoid allocating
+ * later when we will someday hold a mutex.
+ */
+ name_dup = strdup(name);
+ if (name_dup == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ labels_dup = strdup(labels);
+ if (labels_dup == NULL) {
+ free(name_dup);
+ errno = ENOMEM;
+ return (-1);
+ }
+ ld_new = malloc(sizeof(*ld));
+ if (ld_new == NULL) {
+ free(name_dup);
+ free(labels_dup);
+ errno = ENOMEM;
+ return (-1);
+ }
+
+ /*
+ * If the type is already present, replace the current entry
+ * rather than add a new instance.
+ */
+ for (ld = LIST_FIRST(&label_default_head); ld != NULL;
+ ld = LIST_NEXT(ld, ld_entries)) {
+ if (strcmp(name, ld->ld_name) == 0)
+ break;
+ }
+
+ if (ld != NULL) {
+ free(ld->ld_labels);
+ ld->ld_labels = labels_dup;
+ labels_dup = NULL;
+ } else {
+ ld = ld_new;
+ ld->ld_name = name_dup;
+ ld->ld_labels = labels_dup;
+
+ ld_new = NULL;
+ name_dup = NULL;
+ labels_dup = NULL;
+
+ LIST_INSERT_HEAD(&label_default_head, ld, ld_entries);
+ }
+
+ if (name_dup != NULL)
+ free(name_dup);
+ if (labels_dup != NULL)
+ free(labels_dup);
+ if (ld_new != NULL)
+ free(ld_new);
+
+ return (0);
+}
+
+static char *
+next_token(char **string)
+{
+ char *token;
+
+ token = strsep(string, " \t");
+ while (token != NULL && *token == '\0')
+ token = strsep(string, " \t");
+
+ return (token);
+}
+
+static int
+mac_init_internal(int ignore_errors)
+{
+ const char *filename;
+ char line[LINE_MAX];
+ FILE *file;
+ int error;
+
+ error = 0;
+
+ LIST_INIT(&label_default_head);
+
+ if (!issetugid() && getenv("MAC_CONFFILE") != NULL)
+ filename = getenv("MAC_CONFFILE");
+ else
+ filename = MAC_CONFFILE;
+ file = fopen(filename, "re");
+ if (file == NULL)
+ return (0);
+
+ while (fgets(line, LINE_MAX, file)) {
+ char *comment, *parse, *statement;
+
+ if (line[strlen(line)-1] == '\n')
+ line[strlen(line)-1] = '\0';
+ else {
+ if (ignore_errors)
+ continue;
+ fclose(file);
+ error = EINVAL;
+ goto just_return;
+ }
+
+ /* Remove any comment. */
+ comment = line;
+ parse = strsep(&comment, "#");
+
+ /* Blank lines OK. */
+ statement = next_token(&parse);
+ if (statement == NULL)
+ continue;
+
+ if (strcmp(statement, "default_labels") == 0) {
+ char *name, *labels;
+
+ name = next_token(&parse);
+ labels = next_token(&parse);
+ if (name == NULL || labels == NULL ||
+ next_token(&parse) != NULL) {
+ if (ignore_errors)
+ continue;
+ error = EINVAL;
+ fclose(file);
+ goto just_return;
+ }
+
+ if (mac_add_type(name, labels) == -1) {
+ if (ignore_errors)
+ continue;
+ fclose(file);
+ goto just_return;
+ }
+ } else if (strcmp(statement, "default_ifnet_labels") == 0 ||
+ strcmp(statement, "default_file_labels") == 0 ||
+ strcmp(statement, "default_process_labels") == 0) {
+ char *labels, *type;
+
+ if (strcmp(statement, "default_ifnet_labels") == 0)
+ type = "ifnet";
+ else if (strcmp(statement, "default_file_labels") == 0)
+ type = "file";
+ else if (strcmp(statement, "default_process_labels") ==
+ 0)
+ type = "process";
+
+ labels = next_token(&parse);
+ if (labels == NULL || next_token(&parse) != NULL) {
+ if (ignore_errors)
+ continue;
+ error = EINVAL;
+ fclose(file);
+ goto just_return;
+ }
+
+ if (mac_add_type(type, labels) == -1) {
+ if (ignore_errors)
+ continue;
+ fclose(file);
+ goto just_return;
+ }
+ } else {
+ if (ignore_errors)
+ continue;
+ fclose(file);
+ error = EINVAL;
+ goto just_return;
+ }
+ }
+
+ fclose(file);
+
+ internal_initialized = 1;
+
+just_return:
+ if (error != 0)
+ mac_destroy_internal();
+ return (error);
+}
+
+static int
+mac_maybe_init_internal(void)
+{
+
+ if (!internal_initialized)
+ return (mac_init_internal(1));
+ else
+ return (0);
+}
+
+int
+mac_reload(void)
+{
+
+ if (internal_initialized)
+ mac_destroy_internal();
+ return (mac_init_internal(0));
+}
+
+int
+mac_free(struct mac *mac)
+{
+
+ if (mac->m_string != NULL)
+ free(mac->m_string);
+ free(mac);
+
+ return (0);
+}
+
+int
+mac_from_text(struct mac **mac, const char *text)
+{
+
+ *mac = (struct mac *) malloc(sizeof(**mac));
+ if (*mac == NULL)
+ return (ENOMEM);
+
+ (*mac)->m_string = strdup(text);
+ if ((*mac)->m_string == NULL) {
+ free(*mac);
+ *mac = NULL;
+ return (ENOMEM);
+ }
+
+ (*mac)->m_buflen = strlen((*mac)->m_string)+1;
+
+ return (0);
+}
+
+int
+mac_to_text(struct mac *mac, char **text)
+{
+
+ *text = strdup(mac->m_string);
+ if (*text == NULL)
+ return (ENOMEM);
+ return (0);
+}
+
+int
+mac_prepare(struct mac **mac, const char *elements)
+{
+
+ if (strlen(elements) >= MAC_MAX_LABEL_BUF_LEN)
+ return (EINVAL);
+
+ *mac = (struct mac *) malloc(sizeof(**mac));
+ if (*mac == NULL)
+ return (ENOMEM);
+
+ (*mac)->m_string = malloc(MAC_MAX_LABEL_BUF_LEN);
+ if ((*mac)->m_string == NULL) {
+ free(*mac);
+ *mac = NULL;
+ return (ENOMEM);
+ }
+
+ strcpy((*mac)->m_string, elements);
+ (*mac)->m_buflen = MAC_MAX_LABEL_BUF_LEN;
+
+ return (0);
+}
+
+int
+mac_prepare_type(struct mac **mac, const char *name)
+{
+ struct label_default *ld;
+ int error;
+
+ error = mac_maybe_init_internal();
+ if (error != 0)
+ return (error);
+
+ for (ld = LIST_FIRST(&label_default_head); ld != NULL;
+ ld = LIST_NEXT(ld, ld_entries)) {
+ if (strcmp(name, ld->ld_name) == 0)
+ return (mac_prepare(mac, ld->ld_labels));
+ }
+
+ errno = ENOENT;
+ return (-1); /* XXXMAC: ENOLABEL */
+}
+
+int
+mac_prepare_ifnet_label(struct mac **mac)
+{
+
+ return (mac_prepare_type(mac, "ifnet"));
+}
+
+int
+mac_prepare_file_label(struct mac **mac)
+{
+
+ return (mac_prepare_type(mac, "file"));
+}
+
+int
+mac_prepare_packet_label(struct mac **mac)
+{
+
+ return (mac_prepare_type(mac, "packet"));
+}
+
+int
+mac_prepare_process_label(struct mac **mac)
+{
+
+ return (mac_prepare_type(mac, "process"));
+}
+
+/*
+ * Simply test whether the TrustedBSD/MAC MIB tree is present; if so,
+ * return 1 to indicate that the system has MAC enabled overall or for
+ * a given policy.
+ */
+int
+mac_is_present(const char *policyname)
+{
+ int mib[5];
+ size_t siz;
+ char *mibname;
+ int error;
+
+ if (policyname != NULL) {
+ if (policyname[strcspn(policyname, ".=")] != '\0') {
+ errno = EINVAL;
+ return (-1);
+ }
+ mibname = malloc(sizeof("security.mac.") - 1 +
+ strlen(policyname) + sizeof(".enabled"));
+ if (mibname == NULL)
+ return (-1);
+ strcpy(mibname, "security.mac.");
+ strcat(mibname, policyname);
+ strcat(mibname, ".enabled");
+ siz = 5;
+ error = sysctlnametomib(mibname, mib, &siz);
+ free(mibname);
+ } else {
+ siz = 3;
+ error = sysctlnametomib("security.mac", mib, &siz);
+ }
+ if (error == -1) {
+ switch (errno) {
+ case ENOTDIR:
+ case ENOENT:
+ return (0);
+ default:
+ return (error);
+ }
+ }
+ return (1);
+}
diff --git a/lib/libc/posix1e/mac.conf.5 b/lib/libc/posix1e/mac.conf.5
new file mode 100644
index 000000000000..3946be18db16
--- /dev/null
+++ b/lib/libc/posix1e/mac.conf.5
@@ -0,0 +1,112 @@
+.\" Copyright (c) 2003 Networks Associates Technology, Inc.
+.\" All rights reserved.
+.\"
+.\" This software was developed for the FreeBSD Project in part by Network
+.\" Associates Laboratories, the Security Research Division of Network
+.\" Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
+.\" as part of the DARPA CHATS research program.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd July 25, 2015
+.Dt MAC.CONF 5
+.Os
+.Sh NAME
+.Nm mac.conf
+.Nd format of the MAC library configuration file
+.Sh DESCRIPTION
+The
+.Nm
+file configures the default label elements to be used by policy-agnostic
+applications that operate on MAC labels.
+A file contains a series of default label sets specified by object class,
+in addition to blank lines and comments preceded by a
+.Ql #
+symbol.
+.Pp
+Currently, the implementation supports two syntax styles for label
+element declaration.
+The old (deprecated) syntax consists of a
+single line with two fields separated by white space: the object
+class name, and a list of label elements as used by the
+.Xr mac_prepare 3
+library calls prior to an application invocation of a function from
+.Xr mac_get 3 .
+.Pp
+The newer more preferred syntax consists of three fields separated by
+white space: the label group, object class name and a list of
+label elements.
+.Pp
+Label element names may optionally begin with a
+.Ql \&?
+symbol to indicate that a failure to retrieve the label element for
+an object should be silently ignored, and improves usability if the
+set of MAC policies may change over time.
+.Sh FILES
+.Bl -tag -width ".Pa /etc/mac.conf" -compact
+.It Pa /etc/mac.conf
+MAC library configuration file.
+.El
+.Sh EXAMPLES
+The following example configures user applications to operate with
+four MAC policies:
+.Xr mac_biba 4 ,
+.Xr mac_mls 4 ,
+SEBSD,
+and
+.Xr mac_partition 4 .
+.Bd -literal -offset indent
+#
+# Default label set to be used by simple MAC applications
+
+default_labels file ?biba,?lomac,?mls,?sebsd
+default_labels ifnet ?biba,?lomac,?mls,?sebsd
+default_labels process ?biba,?lomac,?mls,?partition,?sebsd
+default_labels socket ?biba,?lomac,?mls
+
+#
+# Deprecated (old) syntax
+
+default_file_labels ?biba,?mls,?sebsd
+default_ifnet_labels ?biba,?mls,?sebsd
+default_process_labels ?biba,?mls,partition,?sebsd
+.Ed
+.Pp
+In this example, userland applications will attempt to retrieve Biba,
+MLS, and SEBSD labels for all object classes; for processes, they will
+additionally attempt to retrieve a Partition identifier.
+In all cases except the Partition identifier, failure to retrieve a
+label due to the respective policy not being present will be ignored.
+.Sh SEE ALSO
+.Xr mac 3 ,
+.Xr mac_get 3 ,
+.Xr mac_prepare 3 ,
+.Xr mac 4 ,
+.Xr mac 9
+.Sh HISTORY
+Support for Mandatory Access Control was introduced in
+.Fx 5.0
+as part of the
+.Tn TrustedBSD
+Project.
diff --git a/lib/libc/posix1e/mac_exec.c b/lib/libc/posix1e/mac_exec.c
new file mode 100644
index 000000000000..f57d1cefee51
--- /dev/null
+++ b/lib/libc/posix1e/mac_exec.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2002 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project in part by Network
+ * Associates Laboratories, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
+ * as part of the DARPA CHATS research program.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/mac.h>
+
+extern int __mac_execve(char *fname, char **argv, char **envv,
+ struct mac *mac_p);
+
+int
+mac_execve(char *fname, char **argv, char **envv, struct mac *label)
+{
+
+ return (__mac_execve(fname, argv, envv, label));
+}
diff --git a/lib/libc/posix1e/mac_free.3 b/lib/libc/posix1e/mac_free.3
new file mode 100644
index 000000000000..78118a1efa5e
--- /dev/null
+++ b/lib/libc/posix1e/mac_free.3
@@ -0,0 +1,99 @@
+.\" Copyright (c) 2001, 2002 Networks Associates Technology, Inc.
+.\" All rights reserved.
+.\"
+.\" This software was developed for the FreeBSD Project by Chris
+.\" Costello at Safeport Network Services and NAI Labs, the Security
+.\" Research Division of Network Associates, Inc. under DARPA/SPAWAR
+.\" contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS
+.\" research program.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. The name of the author may not be used to endorse or promote
+.\" products derived from this software without specific prior written
+.\" permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd December 21, 2001
+.Dt MAC_FREE 3
+.Os
+.Sh NAME
+.Nm mac_free
+.Nd free MAC label
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/mac.h
+.Ft int
+.Fn mac_free "mac_t label"
+.Sh DESCRIPTION
+The
+.Fn mac_free
+function frees the storage allocated to contain a
+.Vt mac_t .
+.Sh RETURN VALUES
+The
+.Fn mac_free
+function always returns 0.
+WARNING: see the notes in the
+.Sx BUGS
+section regarding the use of this
+function.
+.Sh SEE ALSO
+.Xr mac 3 ,
+.Xr mac_get 3 ,
+.Xr mac_prepare 3 ,
+.Xr mac_set 3 ,
+.Xr mac_text 3 ,
+.Xr posix1e 3 ,
+.Xr mac 4 ,
+.Xr mac 9
+.Sh STANDARDS
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+Discussion of the draft
+continues on the cross-platform POSIX.1e implementation mailing list.
+To join this list, see the
+.Fx
+POSIX.1e implementation page
+for more information.
+.Sh HISTORY
+Support for Mandatory Access Control was introduced in
+.Fx 5.0
+as part of the
+.Tn TrustedBSD
+Project.
+.Sh BUGS
+POSIX.1e specifies that
+.Fn mac_free
+will be used to free text strings created using
+.Xr mac_to_text 3 .
+Because
+.Vt mac_t
+is a complex structure in the
+.Tn TrustedBSD
+implementation,
+.Fn mac_free
+is specific to
+.Vt mac_3 ,
+and must not be used to free the character strings returned from
+.Fn mac_to_text .
+Doing so may result in undefined behavior.
diff --git a/lib/libc/posix1e/mac_get.3 b/lib/libc/posix1e/mac_get.3
new file mode 100644
index 000000000000..35fa72b08241
--- /dev/null
+++ b/lib/libc/posix1e/mac_get.3
@@ -0,0 +1,152 @@
+.\" Copyright (c) 2001, 2004 Networks Associates Technology, Inc.
+.\" All rights reserved.
+.\"
+.\" This software was developed for the FreeBSD Project by Chris
+.\" Costello at Safeport Network Services and NAI Labs, the Security
+.\" Research Division of Network Associates, Inc. under DARPA/SPAWAR
+.\" contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS
+.\" research program.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd December 21, 2001
+.Dt MAC_GET 3
+.Os
+.Sh NAME
+.Nm mac_get_file ,
+.Nm mac_get_link ,
+.Nm mac_get_fd ,
+.Nm mac_get_peer ,
+.Nm mac_get_pid ,
+.Nm mac_get_proc
+.Nd get the label of a file, socket, socket peer or process
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/mac.h
+.Ft int
+.Fn mac_get_file "const char *path" "mac_t label"
+.Ft int
+.Fn mac_get_link "const char *path" "mac_t label"
+.Ft int
+.Fn mac_get_fd "int fd" "mac_t label"
+.Ft int
+.Fn mac_get_peer "int fd" "mac_t label"
+.Ft int
+.Fn mac_get_pid "pid_t pid" "mac_t label"
+.Ft int
+.Fn mac_get_proc "mac_t label"
+.Sh DESCRIPTION
+The
+.Fn mac_get_file
+system call returns the label associated with a file specified by
+pathname.
+The
+.Fn mac_get_link
+function is the same as
+.Fn mac_get_file ,
+except that it does not follow symlinks.
+.Pp
+The
+.Fn mac_get_fd
+system call returns the label associated with an object referenced by
+the specified file descriptor.
+Note that in the case of a file system socket, the label returned will
+be the socket label, which may be different from the label of the
+on-disk node acting as a rendezvous for the socket.
+The
+.Fn mac_get_peer
+system call returns the label associated with the remote endpoint of
+a socket; the exact semantics of this call will depend on the protocol
+domain, communications type, and endpoint; typically this label will
+be cached when a connection-oriented protocol instance is first set up,
+and is undefined for datagram protocols.
+.Pp
+The
+.Fn mac_get_pid
+and
+.Fn mac_get_proc
+system calls return the process label associated with an arbitrary
+process ID, or the current process.
+.Pp
+Label storage for use with these calls must first be allocated and
+prepared using the
+.Xr mac_prepare 3
+functions.
+When an application is done using a label, the memory may be returned
+using
+.Xr mac_free 3 .
+.Sh ERRORS
+.Bl -tag -width Er
+.It Bq Er EACCES
+A component of
+.Fa path
+is not searchable,
+or MAC read access to the file
+is denied.
+.It Bq Er EINVAL
+The requested label operation is not valid for the object referenced by
+.Fa fd .
+.It Bq Er ENAMETOOLONG
+The pathname pointed to by
+.Fa path
+exceeds
+.Dv PATH_MAX ,
+or a component of the pathname exceeds
+.Dv NAME_MAX .
+.It Bq Er ENOENT
+A component of
+.Fa path
+does not exist.
+.It Bq Er ENOMEM
+Insufficient memory is available
+to allocate a new MAC label structure.
+.It Bq Er ENOTDIR
+A component of
+.Fa path
+is not a directory.
+.El
+.Sh SEE ALSO
+.Xr mac 3 ,
+.Xr mac_free 3 ,
+.Xr mac_prepare 3 ,
+.Xr mac_set 3 ,
+.Xr mac_text 3 ,
+.Xr posix1e 3 ,
+.Xr mac 4 ,
+.Xr mac 9
+.Sh STANDARDS
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+Discussion of the draft
+continues on the cross-platform POSIX.1e implementation mailing list.
+To join this list, see the
+.Fx
+POSIX.1e implementation page
+for more information.
+.Sh HISTORY
+Support for Mandatory Access Control was introduced in
+.Fx 5.0
+as part of the
+.Tn TrustedBSD
+Project.
diff --git a/lib/libc/posix1e/mac_get.c b/lib/libc/posix1e/mac_get.c
new file mode 100644
index 000000000000..b641fc054807
--- /dev/null
+++ b/lib/libc/posix1e/mac_get.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * This software was developed by Robert Watson for the TrustedBSD Project.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The names of the authors may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/mac.h>
+#include <sys/socket.h>
+
+extern int __mac_get_fd(int fd, struct mac *mac_p);
+extern int __mac_get_file(const char *path_p, struct mac *mac_p);
+extern int __mac_get_link(const char *path_p, struct mac *mac_p);
+extern int __mac_get_pid(pid_t pid, struct mac *mac_p);
+extern int __mac_get_proc(struct mac *mac_p);
+
+int
+mac_get_fd(int fd, struct mac *label)
+{
+
+ return (__mac_get_fd(fd, label));
+}
+
+int
+mac_get_file(const char *path, struct mac *label)
+{
+
+ return (__mac_get_file(path, label));
+}
+
+int
+mac_get_link(const char *path, struct mac *label)
+{
+
+ return (__mac_get_link(path, label));
+}
+
+int
+mac_get_peer(int fd, struct mac *label)
+{
+ socklen_t len;
+
+ len = sizeof(*label);
+ return (getsockopt(fd, SOL_SOCKET, SO_PEERLABEL, label, &len));
+}
+
+int
+mac_get_pid(pid_t pid, struct mac *label)
+{
+
+ return (__mac_get_pid(pid, label));
+}
+
+int
+mac_get_proc(struct mac *label)
+{
+
+ return (__mac_get_proc(label));
+}
diff --git a/lib/libc/posix1e/mac_is_present.3 b/lib/libc/posix1e/mac_is_present.3
new file mode 100644
index 000000000000..96d8cbfd9b76
--- /dev/null
+++ b/lib/libc/posix1e/mac_is_present.3
@@ -0,0 +1,87 @@
+.\" Copyright (c) 2002 Networks Associates Technology, Inc.
+.\" All rights reserved.
+.\"
+.\" This software was developed for the FreeBSD Project by Chris
+.\" Costello at Safeport Network Services and NAI Labs, the Security
+.\" Research Division of Network Associates, Inc. under DARPA/SPAWAR
+.\" contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS
+.\" research program.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd July 7, 2006
+.Dt MAC_IS_PRESENT 3
+.Os
+.Sh NAME
+.Nm mac_is_present
+.Nd report whether the running system has MAC support
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/mac.h
+.Ft int
+.Fn mac_is_present "const char *policyname"
+.Sh DESCRIPTION
+The
+.Fn mac_is_present
+function determines whether the currently-running kernel supports MAC for
+a given policy or not.
+If
+.Fa policyname
+is
+.Pf non- Dv NULL ,
+the presence of the named policy
+(e.g.\&
+.Dq Li biba ,
+.Dq Li mls ,
+.Dq Li te )
+is checked, otherwise the presence of any MAC policies at all is checked.
+.Sh RETURN VALUES
+If the system supports the given MAC policy, the value 1 is returned.
+If the specified MAC policy is not supported, the value 0 is returned.
+If an error occurs, the value \-1 is returned.
+.Sh ERRORS
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The value of
+.Fa policyname
+is not valid.
+.It Bq Er ENOMEM
+Insufficient memory was available to allocate internal storage.
+.El
+.Sh SEE ALSO
+.Xr mac 3 ,
+.Xr mac_free 3 ,
+.Xr mac_get 3 ,
+.Xr mac_prepare 3 ,
+.Xr mac_set 3 ,
+.Xr mac_text 3 ,
+.Xr mac 4 ,
+.Xr mac 9
+.Sh HISTORY
+Support for Mandatory Access Control was introduced in
+.Fx 5.0
+as part of the
+.Tn TrustedBSD
+Project.
diff --git a/lib/libc/posix1e/mac_prepare.3 b/lib/libc/posix1e/mac_prepare.3
new file mode 100644
index 000000000000..e217b7132ef9
--- /dev/null
+++ b/lib/libc/posix1e/mac_prepare.3
@@ -0,0 +1,126 @@
+.\" Copyright (c) 2002, 2003 Networks Associates Technology, Inc.
+.\" All rights reserved.
+.\"
+.\" This software was developed for the FreeBSD Project by Chris
+.\" Costello at Safeport Network Services and Network Associates Labs,
+.\" the Security Research Division of Network Associates, Inc. under
+.\" DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
+.\" DARPA CHATS research program.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd August 22, 2003
+.Dt MAC_PREPARE 3
+.Os
+.Sh NAME
+.Nm mac_prepare , mac_prepare_type , mac_prepare_file_label ,
+.Nm mac_prepare_ifnet_label , mac_prepare_process_label
+.Nd allocate appropriate storage for
+.Vt mac_t
+.Sh SYNOPSIS
+.In sys/mac.h
+.Ft int
+.Fn mac_prepare "mac_t *mac" "const char *elements"
+.Ft int
+.Fn mac_prepare_type "mac_t *mac" "const char *name"
+.Ft int
+.Fn mac_prepare_file_label "mac_t *mac"
+.Ft int
+.Fn mac_prepare_ifnet_label "mac_t *mac"
+.Ft int
+.Fn mac_prepare_process_label "mac_t *mac"
+.Sh DESCRIPTION
+The
+.Nm
+family of functions allocates the appropriate amount of storage and initializes
+.Fa *mac
+for use by
+.Xr mac_get 3 .
+When the resulting label is passed into the
+.Xr mac_get 3
+functions, the kernel will attempt to fill in the label elements specified
+when the label was prepared.
+Elements are specified in a nul-terminated string, using commas to
+delimit fields.
+Element names may be prefixed with the
+.Ql \&?
+character to indicate that a failure by the kernel to retrieve that
+element should not be considered fatal.
+.Pp
+The
+.Fn mac_prepare
+function accepts a list of policy names as a parameter, and allocates the
+storage to fit those label elements accordingly.
+The remaining functions in the family make use of system defaults defined
+in
+.Xr mac.conf 5
+instead of an explicit
+.Va elements
+argument, deriving the default from the specified object type.
+.Pp
+.Fn mac_prepare_type
+allocates the storage to fit an object label of the type specified by
+the
+.Va name
+argument.
+The
+.Fn mac_prepare_file_label ,
+.Fn mac_prepare_ifnet_label ,
+and
+.Fn mac_prepare_process_label
+functions are equivalent to invocations of
+.Fn mac_prepare_type
+with arguments of
+.Qq file ,
+.Qq ifnet ,
+and
+.Qq process
+respectively.
+.Sh RETURN VALUES
+.Rv -std
+.Sh SEE ALSO
+.Xr mac 3 ,
+.Xr mac_free 3 ,
+.Xr mac_get 3 ,
+.Xr mac_is_present 3 ,
+.Xr mac_set 3 ,
+.Xr mac 4 ,
+.Xr mac.conf 5 ,
+.Xr maclabel 7
+.Sh STANDARDS
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+Discussion of the draft
+continues on the cross-platform POSIX.1e implementation mailing list.
+To join this list, see the
+.Fx
+POSIX.1e implementation page
+for more information.
+.Sh HISTORY
+Support for Mandatory Access Control was introduced in
+.Fx 5.0
+as part of the
+.Tn TrustedBSD
+Project.
+Support for generic object types first appeared in
+.Fx 5.2 .
diff --git a/lib/libc/posix1e/mac_set.3 b/lib/libc/posix1e/mac_set.3
new file mode 100644
index 000000000000..0b245a000277
--- /dev/null
+++ b/lib/libc/posix1e/mac_set.3
@@ -0,0 +1,149 @@
+.\" Copyright (c) 2001 Networks Associates Technology, Inc.
+.\" All rights reserved.
+.\"
+.\" This software was developed for the FreeBSD Project by Chris
+.\" Costello at Safeport Network Services and NAI Labs, the Security
+.\" Research Division of Network Associates, Inc. under DARPA/SPAWAR
+.\" contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS
+.\" research program.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd January 14, 2003
+.Dt MAC_SET 3
+.Os
+.Sh NAME
+.Nm mac_set_file ,
+.Nm mac_set_fd ,
+.Nm mac_set_proc
+.Nd set the MAC label for a file or process
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/mac.h
+.Ft int
+.Fn mac_set_file "const char *path" "mac_t label"
+.Ft int
+.Fn mac_set_link "const char *path" "mac_t label"
+.Ft int
+.Fn mac_set_fd "int fd" "mac_t label"
+.Ft int
+.Fn mac_set_proc "mac_t label"
+.Sh DESCRIPTION
+The
+.Fn mac_set_file
+and
+.Fn mac_set_fd
+functions associate a MAC label
+specified by
+.Fa label
+to the file referenced to by
+.Fa path_p ,
+or to the file descriptor
+.Fa fd ,
+respectively.
+Note that when a file descriptor references a socket, label operations
+on the file descriptor act on the socket, not on the file that may
+have been used as a rendezvous when binding the socket.
+The
+.Fn mac_set_link
+function is the same as
+.Fn mac_set_file ,
+except that it does not follow symlinks.
+.Pp
+The
+.Fn mac_set_proc
+function associates the MAC label
+specified by
+.Fa label
+to the calling process.
+.Pp
+A process is allowed to set a label for a file
+only if it has MAC write access to the file,
+and its effective user ID is equal to
+the owner of the file,
+or has appropriate privileges.
+.Sh RETURN VALUES
+.Rv -std mac_set_fd mac_set_file mac_set_link mac_set_proc
+.Sh ERRORS
+.Bl -tag -width Er
+.It Bq Er EACCES
+MAC write access to the file is denied.
+.It Bq Er EBADF
+The
+.Fa fd
+argument
+is not a valid file descriptor.
+.It Bq Er EINVAL
+The
+.Fa label
+argument
+is not a valid MAC label, or the object referenced by
+.Fa fd
+is not appropriate for label operations.
+.It Bq Er EOPNOTSUPP
+Setting MAC labels is not supported
+by the file referenced by
+.Fa fd .
+.It Bq Er EPERM
+The calling process had insufficient privilege
+to change the MAC label.
+.It Bq Er EROFS
+File system for the object being modified
+is read only.
+.It Bq Er ENAMETOOLONG
+.\" XXX POSIX_NO_TRUNC?
+The length of the pathname in
+.Fa path_p
+exceeds
+.Dv PATH_MAX ,
+or a component of the pathname
+is longer than
+.Dv NAME_MAX .
+.It Bq Er ENOENT
+The file referenced by
+.Fa path_p
+does not exist.
+.It Bq Er ENOTDIR
+A component of the pathname
+referenced by
+.Fa path_p
+is not a directory.
+.El
+.Sh SEE ALSO
+.Xr mac 3 ,
+.Xr mac_free 3 ,
+.Xr mac_get 3 ,
+.Xr mac_is_present 3 ,
+.Xr mac_prepare 3 ,
+.Xr mac_text 3 ,
+.Xr posix1e 3 ,
+.Xr mac 4 ,
+.Xr mac 9
+.Sh HISTORY
+Support for Mandatory Access Control was introduced in
+.Fx 5.0
+as part of the
+.Tn TrustedBSD
+Project.
diff --git a/lib/libc/posix1e/mac_set.c b/lib/libc/posix1e/mac_set.c
new file mode 100644
index 000000000000..c657f10b45fe
--- /dev/null
+++ b/lib/libc/posix1e/mac_set.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * This software was developed by Robert Watson for the TrustedBSD Project.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The names of the authors may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/mac.h>
+
+extern int __mac_set_fd(int fd, struct mac *mac_p);
+extern int __mac_set_file(const char *path_p, struct mac *mac_p);
+extern int __mac_set_link(const char *path_p, struct mac *mac_p);
+extern int __mac_set_proc(struct mac *mac_p);
+
+int
+mac_set_fd(int fd, struct mac *label)
+{
+
+ return (__mac_set_fd(fd, label));
+}
+
+int
+mac_set_file(const char *path, struct mac *label)
+{
+
+ return (__mac_set_file(path, label));
+}
+
+int
+mac_set_link(const char *path, struct mac *label)
+{
+
+ return (__mac_set_link(path, label));
+}
+
+int
+mac_set_proc(struct mac *label)
+{
+
+ return (__mac_set_proc(label));
+}
diff --git a/lib/libc/posix1e/mac_text.3 b/lib/libc/posix1e/mac_text.3
new file mode 100644
index 000000000000..dde6ccf5e23c
--- /dev/null
+++ b/lib/libc/posix1e/mac_text.3
@@ -0,0 +1,117 @@
+.\" Copyright (c) 2001 Networks Associates Technology, Inc.
+.\" All rights reserved.
+.\"
+.\" This software was developed for the FreeBSD Project by Chris
+.\" Costello at Safeport Network Services and NAI Labs, the Security
+.\" Research Division of Network Associates, Inc. under DARPA/SPAWAR
+.\" contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS
+.\" research program.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd December 21, 2001
+.Dt MAC_TEXT 3
+.Os
+.Sh NAME
+.Nm mac_from_text ,
+.Nm mac_to_text
+.Nd convert MAC label to/from text representation
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/mac.h
+.Ft int
+.Fn mac_from_text "mac_t *mac" "const char *text"
+.Ft int
+.Fn mac_to_text "mac_t label" "char **text"
+.Sh DESCRIPTION
+The
+.Fn mac_from_text
+function converts the text representation of a label
+into the internal policy label format
+.Pq Vt mac_t
+and places it in
+.Fa *mac ,
+which must later be freed with
+.Xr free 3 .
+.Pp
+The
+.Fn mac_to_text
+function allocates storage for
+.Fa *text ,
+which will be set to the text representation of
+.Fa label .
+.Pp
+Refer to
+.Xr maclabel 7
+for the MAC label format.
+.Sh RETURN VALUES
+.Rv -std mac_from_text mac_to_text
+.Sh COMPATIBILITY
+POSIX.1e does not define
+a format for text representations
+of MAC labels.
+.Pp
+POSIX.1e requires that text strings allocated using
+.Fn mac_to_text
+be freed using
+.Xr mac_free 3 ;
+in the
+.Fx
+implementation, they must be freed using
+.Xr free 3 ,
+as
+.Xr mac_free 3
+is used only to free memory used for type
+.Vt mac_t .
+.Sh ERRORS
+.Bl -tag -width Er
+.It Bq Er ENOMEM
+Insufficient memory was available
+to allocate internal storage.
+.El
+.Sh SEE ALSO
+.Xr free 3 ,
+.Xr mac 3 ,
+.Xr mac_get 3 ,
+.Xr mac_is_present 3 ,
+.Xr mac_prepare 3 ,
+.Xr mac_set 3 ,
+.Xr posix1e 3 ,
+.Xr mac 4 ,
+.Xr maclabel 7
+.Sh STANDARDS
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+Discussion of the draft
+continues on the cross-platform POSIX.1e implementation mailing list.
+To join this list, see the
+.Fx
+POSIX.1e implementation page
+for more information.
+.Sh HISTORY
+Support for Mandatory Access Control was introduced in
+.Fx 5.0
+as part of the
+.Tn TrustedBSD
+Project.
diff --git a/lib/libc/posix1e/posix1e.3 b/lib/libc/posix1e/posix1e.3
new file mode 100644
index 000000000000..02fb3ef27e99
--- /dev/null
+++ b/lib/libc/posix1e/posix1e.3
@@ -0,0 +1,118 @@
+.\"-
+.\" Copyright (c) 2000, 2009 Robert N. M. Watson
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd February 25, 2016
+.Dt POSIX1E 3
+.Os
+.Sh NAME
+.Nm posix1e
+.Nd introduction to the POSIX.1e security API
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/acl.h
+.In sys/mac.h
+.Sh DESCRIPTION
+POSIX.1e describes five security extensions to the POSIX.1 API: Access
+Control Lists (ACLs), Auditing, Capabilities, Mandatory Access Control, and
+Information Flow Labels.
+While IEEE POSIX.1e D17 specification has not been standardized, several of
+its interfaces are widely used.
+.Pp
+.Fx
+implements POSIX.1e interface for access control lists, described in
+.Xr acl 3 ,
+and supports ACLs on the
+.Xr ffs 7
+file system; ACLs must be administratively enabled using
+.Xr tunefs 8 .
+.Pp
+.Fx
+implements a POSIX.1e-like mandatory access control interface, described in
+.Xr mac 3 ,
+although with a number of extensions and important semantic differences.
+.Pp
+.Fx
+does not implement the POSIX.1e audit, privilege (capability), or information
+flow label APIs.
+However,
+.Fx
+does implement the
+.Xr libbsm
+audit API.
+It also provides
+.Xr capsicum 4 ,
+a lightweight OS capability and sandbox framework implementing a
+hybrid capability system model.
+.Sh ENVIRONMENT
+POSIX.1e assigns security attributes to all objects, extending the security
+functionality described in POSIX.1.
+These additional attributes store fine-grained discretionary access control
+information and mandatory access control labels; for files, they are stored
+in extended attributes, described in
+.Xr extattr 3 .
+.Pp
+POSIX.2c describes
+a set of userland utilities for manipulating these attributes, including
+.Xr getfacl 1
+and
+.Xr setfacl 1
+for access control lists, and
+.Xr getfmac 8
+and
+.Xr setfmac 8
+for mandatory access control labels.
+.Sh SEE ALSO
+.Xr getfacl 1 ,
+.Xr setfacl 1 ,
+.Xr extattr 2 ,
+.Xr acl 3 ,
+.Xr extattr 3 ,
+.Xr libbsm 3 ,
+.Xr libcasper 3 ,
+.Xr mac 3 ,
+.Xr capsicum 4 ,
+.Xr ffs 7 ,
+.Xr getfmac 8 ,
+.Xr setfmac 8 ,
+.Xr tunefs 8 ,
+.Xr acl 9 ,
+.Xr extattr 9 ,
+.Xr mac 9
+.Sh STANDARDS
+POSIX.1e is described in IEEE POSIX.1e draft 17.
+.Sh HISTORY
+POSIX.1e support was introduced in
+.Fx 4.0 ;
+most features were available as of
+.Fx 5.0 .
+.Sh AUTHORS
+.An Robert N M Watson
+.An Chris D. Faulhaber
+.An Thomas Moestl
+.An Ilmar S Habibulin
diff --git a/lib/libc/powerpc/Makefile.inc b/lib/libc/powerpc/Makefile.inc
new file mode 100644
index 000000000000..429826711c44
--- /dev/null
+++ b/lib/libc/powerpc/Makefile.inc
@@ -0,0 +1,7 @@
+# $FreeBSD$
+
+SRCS+= trivial-vdso_tc.c
+
+# Long double is 64-bits
+MDSRCS+=machdep_ldisd.c
+SYM_MAPS+=${LIBC_SRCTOP}/powerpc/Symbol.map
diff --git a/lib/libc/powerpc/SYS.h b/lib/libc/powerpc/SYS.h
new file mode 100644
index 000000000000..f0665c09c144
--- /dev/null
+++ b/lib/libc/powerpc/SYS.h
@@ -0,0 +1,70 @@
+/*-
+ * Copyright (c) 2002 Benno Rice. All rights reserved.
+ * Copyright (c) 2002 David E. O'Brien. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $NetBSD: SYS.h,v 1.8 2002/01/14 00:55:56 thorpej Exp $
+ * $FreeBSD$
+ */
+
+#include <sys/syscall.h>
+#include <machine/asm.h>
+
+#define _SYSCALL(name) \
+ .text; \
+ .align 2; \
+ li 0,(SYS_##name); \
+ sc
+
+#define SYSCALL(name) \
+ .text; \
+ .align 2; \
+2: b PIC_PLT(CNAME(HIDENAME(cerror))); \
+ENTRY(__sys_##name); \
+ WEAK_REFERENCE(__sys_##name, name); \
+ WEAK_REFERENCE(__sys_##name, _##name); \
+ _SYSCALL(name); \
+ bso 2b
+
+#define PSEUDO(name) \
+ .text; \
+ .align 2; \
+ENTRY(__sys_##name); \
+ WEAK_REFERENCE(__sys_##name, _##name); \
+ _SYSCALL(name); \
+ bnslr; \
+ b PIC_PLT(CNAME(HIDENAME(cerror)))
+
+#define RSYSCALL(name) \
+ .text; \
+ .align 2; \
+2: b PIC_PLT(CNAME(HIDENAME(cerror))); \
+ENTRY(__sys_##name); \
+ WEAK_REFERENCE(__sys_##name, name); \
+ WEAK_REFERENCE(__sys_##name, _##name); \
+ _SYSCALL(name); \
+ bnslr; \
+ b PIC_PLT(CNAME(HIDENAME(cerror)))
diff --git a/lib/libc/powerpc/Symbol.map b/lib/libc/powerpc/Symbol.map
new file mode 100644
index 000000000000..f695c81bb27f
--- /dev/null
+++ b/lib/libc/powerpc/Symbol.map
@@ -0,0 +1,59 @@
+/*
+ * $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, ...).
+ */
+FBSD_1.0 {
+ /* PSEUDO syscalls */
+ _exit;
+
+ _mcount;
+ _setjmp;
+ _longjmp;
+ fabs;
+ __flt_rounds;
+ fpgetmask;
+ fpgetround;
+ fpgetsticky;
+ fpsetmask;
+ fpsetround;
+ __infinity;
+ __nan;
+ makecontext;
+ setjmp;
+ longjmp;
+ sigsetjmp;
+ siglongjmp;
+ htonl;
+ htons;
+ ntohl;
+ ntohs;
+ brk;
+ exect;
+ sbrk;
+ vfork;
+};
+
+FBSD_1.3 {
+ __eabi;
+};
+
+FBSDprivate_1.0 {
+ /* PSEUDO syscalls */
+ __sys_getlogin;
+ _getlogin;
+ __sys_exit;
+
+ _set_tp;
+ _fpgetsticky;
+ __makecontext;
+ __longjmp;
+ signalcontext;
+ __signalcontext;
+ __syncicache;
+ _end;
+};
diff --git a/lib/libc/powerpc/_fpmath.h b/lib/libc/powerpc/_fpmath.h
new file mode 100644
index 000000000000..4b7971e4da8a
--- /dev/null
+++ b/lib/libc/powerpc/_fpmath.h
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 2003 David Schultz <das@FreeBSD.ORG>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+union IEEEl2bits {
+ long double e;
+ struct {
+#if _BYTE_ORDER == _LITTLE_ENDIAN
+ unsigned int manl :32;
+ unsigned int manh :20;
+ unsigned int exp :11;
+ unsigned int sign :1;
+#else /* _BYTE_ORDER == _LITTLE_ENDIAN */
+ unsigned int sign :1;
+ unsigned int exp :11;
+ unsigned int manh :20;
+ unsigned int manl :32;
+#endif
+ } bits;
+};
+
+#define mask_nbit_l(u) ((void)0)
+#define LDBL_IMPLICIT_NBIT
+#define LDBL_NBIT 0
+
+#define LDBL_MANH_SIZE 20
+#define LDBL_MANL_SIZE 32
+
+#define LDBL_TO_ARRAY32(u, a) do { \
+ (a)[0] = (uint32_t)(u).bits.manl; \
+ (a)[1] = (uint32_t)(u).bits.manh; \
+} while(0)
diff --git a/lib/libc/powerpc/arith.h b/lib/libc/powerpc/arith.h
new file mode 100644
index 000000000000..8e2c9ec597b3
--- /dev/null
+++ b/lib/libc/powerpc/arith.h
@@ -0,0 +1,16 @@
+/*
+ * MD header for contrib/gdtoa
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * NOTE: The definitions in this file must be correct or strtod(3) and
+ * floating point formats in printf(3) will break! The file can be
+ * generated by running contrib/gdtoa/arithchk.c on the target
+ * architecture. See contrib/gdtoa/gdtoaimp.h for details.
+ */
+
+#define IEEE_MC68k
+#define Arith_Kind_ASL 2
+#define Double_Align
diff --git a/lib/libc/powerpc/gd_qnan.h b/lib/libc/powerpc/gd_qnan.h
new file mode 100644
index 000000000000..d70d8c318c4c
--- /dev/null
+++ b/lib/libc/powerpc/gd_qnan.h
@@ -0,0 +1,21 @@
+/*
+ * MD header for contrib/gdtoa
+ *
+ * This file can be generated by compiling and running contrib/gdtoa/qnan.c
+ * on the target architecture after arith.h has been generated.
+ *
+ * $FreeBSD$
+ */
+
+#define f_QNAN 0x7fc00000
+#define d_QNAN0 0x7ff80000
+#define d_QNAN1 0x0
+#define ld_QNAN0 0x7ff80000
+#define ld_QNAN1 0x0
+#define ld_QNAN2 0x0
+#define ld_QNAN3 0x0
+#define ldus_QNAN0 0x7ff8
+#define ldus_QNAN1 0x0
+#define ldus_QNAN2 0x0
+#define ldus_QNAN3 0x0
+#define ldus_QNAN4 0x0
diff --git a/lib/libc/powerpc/gen/Makefile.common b/lib/libc/powerpc/gen/Makefile.common
new file mode 100644
index 000000000000..4ba72799a5cf
--- /dev/null
+++ b/lib/libc/powerpc/gen/Makefile.common
@@ -0,0 +1,6 @@
+# $FreeBSD$
+
+.PATH: ${LIBC_SRCTOP}/powerpc/gen
+
+SRCS += _ctx_start.S eabi.S infinity.c ldexp.c makecontext.c \
+ signalcontext.c syncicache.c _set_tp.c trivial-getcontextx.c
diff --git a/lib/libc/powerpc/gen/Makefile.inc b/lib/libc/powerpc/gen/Makefile.inc
new file mode 100644
index 000000000000..f96ad9fb0a6f
--- /dev/null
+++ b/lib/libc/powerpc/gen/Makefile.inc
@@ -0,0 +1,7 @@
+# $FreeBSD$
+
+.include "${LIBC_SRCTOP}/powerpc/gen/Makefile.common"
+
+SRCS += fabs.S flt_rounds.c fpgetmask.c fpgetround.c \
+ fpgetsticky.c fpsetmask.c fpsetround.c \
+ _setjmp.S setjmp.S sigsetjmp.S
diff --git a/lib/libc/powerpc/gen/_ctx_start.S b/lib/libc/powerpc/gen/_ctx_start.S
new file mode 100644
index 000000000000..4b9fc1d53ae0
--- /dev/null
+++ b/lib/libc/powerpc/gen/_ctx_start.S
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2004 Suleiman Souhlal
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+ #include <machine/asm.h>
+
+ __FBSDID("$FreeBSD$");
+
+ .globl CNAME(_ctx_done)
+ .globl CNAME(abort)
+
+ ENTRY(_ctx_start)
+ mtlr %r14
+ blrl /* branch to start function */
+ mr %r3,%r15 /* pass pointer to ucontext as argument */
+ bl PIC_PLT(CNAME(_ctx_done)) /* branch to ctxt completion func */
+ /*
+ * we should never return from the
+ * above branch.
+ */
+ bl PIC_PLT(CNAME(abort)) /* abort */
+ END(_cts_start)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/powerpc/gen/_set_tp.c b/lib/libc/powerpc/gen/_set_tp.c
new file mode 100644
index 000000000000..eeb062f30217
--- /dev/null
+++ b/lib/libc/powerpc/gen/_set_tp.c
@@ -0,0 +1,35 @@
+/*-
+ * Copyright (c) 2004 Doug Rabson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include "libc_private.h"
+
+void
+_set_tp(void *tpval)
+{
+
+ __asm __volatile("mr 2,%0" :: "r"((char*)tpval + 0x7008));
+}
diff --git a/lib/libc/powerpc/gen/_setjmp.S b/lib/libc/powerpc/gen/_setjmp.S
new file mode 100644
index 000000000000..663a8b6ed32a
--- /dev/null
+++ b/lib/libc/powerpc/gen/_setjmp.S
@@ -0,0 +1,116 @@
+/*-
+ * Copyright (c) 2002 Peter Grehan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/* $NetBSD: _setjmp.S,v 1.1 1997/03/29 20:55:53 thorpej Exp $ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * C library -- _setjmp, _longjmp
+ *
+ * _longjmp(a,v)
+ * will generate a "return(v?v:1)" from the last call to
+ * _setjmp(a)
+ * by restoring registers from the stack.
+ * The previous signal state is NOT restored.
+ *
+ * jmpbuf layout:
+ * +------------+
+ * | unused |
+ * +------------+
+ * | unused |
+ * | |
+ * | (4 words) |
+ * | |
+ * +------------+
+ * | saved regs |
+ * | ... |
+ */
+
+ENTRY(_setjmp)
+ mflr %r11
+ mfcr %r12
+ mr %r10,%r1
+ mr %r9,%r2
+ stmw %r9,20(%r3)
+
+ /* FPRs */
+ stfd %f14,112+0*8(%r3)
+ stfd %f15,112+1*8(%r3)
+ stfd %f16,112+2*8(%r3)
+ stfd %f17,112+3*8(%r3)
+ stfd %f18,112+4*8(%r3)
+ stfd %f19,112+5*8(%r3)
+ stfd %f20,112+6*8(%r3)
+ stfd %f21,112+7*8(%r3)
+ stfd %f22,112+8*8(%r3)
+ stfd %f23,112+9*8(%r3)
+ stfd %f24,112+10*8(%r3)
+ stfd %f25,112+11*8(%r3)
+ stfd %f26,112+12*8(%r3)
+ stfd %f27,112+13*8(%r3)
+ stfd %f28,112+14*8(%r3)
+ stfd %f29,112+15*8(%r3)
+ stfd %f30,112+16*8(%r3)
+ stfd %f31,112+17*8(%r3)
+
+ li %r3,0
+ blr
+END(_setjmp)
+
+ENTRY(_longjmp)
+ lmw %r9,20(%r3)
+
+ /* FPRs */
+ lfd %f14,112+0*8(%r3)
+ lfd %f15,112+1*8(%r3)
+ lfd %f16,112+2*8(%r3)
+ lfd %f17,112+3*8(%r3)
+ lfd %f18,112+4*8(%r3)
+ lfd %f19,112+5*8(%r3)
+ lfd %f20,112+6*8(%r3)
+ lfd %f21,112+7*8(%r3)
+ lfd %f22,112+8*8(%r3)
+ lfd %f23,112+9*8(%r3)
+ lfd %f24,112+10*8(%r3)
+ lfd %f25,112+11*8(%r3)
+ lfd %f26,112+12*8(%r3)
+ lfd %f27,112+13*8(%r3)
+ lfd %f28,112+14*8(%r3)
+ lfd %f29,112+15*8(%r3)
+ lfd %f30,112+16*8(%r3)
+ lfd %f31,112+17*8(%r3)
+
+ mtlr %r11
+ mtcr %r12
+ mr %r1,%r10
+ or. %r3,%r4,%r4
+ 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
new file mode 100644
index 000000000000..3296af88a4d1
--- /dev/null
+++ b/lib/libc/powerpc/gen/eabi.S
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2011 Marcel Moolenaar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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$");
+
+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
new file mode 100644
index 000000000000..ac083ae636ac
--- /dev/null
+++ b/lib/libc/powerpc/gen/fabs.S
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2004 Peter Grehan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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$");
+
+/*
+ * double fabs(double)
+ */
+ENTRY(fabs)
+ fabs %f1,%f1
+ blr
+END(fabs)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/powerpc/gen/flt_rounds.c b/lib/libc/powerpc/gen/flt_rounds.c
new file mode 100644
index 000000000000..6294be72422e
--- /dev/null
+++ b/lib/libc/powerpc/gen/flt_rounds.c
@@ -0,0 +1,56 @@
+/* $NetBSD: flt_rounds.c,v 1.4.10.3 2002/03/22 20:41:53 nathanw Exp $ */
+
+/*
+ * Copyright (c) 1996 Mark Brinicombe
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Mark Brinicombe
+ * for the NetBSD Project.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <machine/float.h>
+
+#ifndef _SOFT_FLOAT
+static const int map[] = {
+ 1, /* round to nearest */
+ 0, /* round to zero */
+ 2, /* round to positive infinity */
+ 3 /* round to negative infinity */
+};
+
+int
+__flt_rounds()
+{
+ uint64_t fpscr;
+
+ __asm__ __volatile("mffs %0" : "=f"(fpscr));
+ return map[(fpscr & 0x03)];
+}
+#endif
diff --git a/lib/libc/powerpc/gen/fpgetmask.c b/lib/libc/powerpc/gen/fpgetmask.c
new file mode 100644
index 000000000000..b67b1bcb4dc0
--- /dev/null
+++ b/lib/libc/powerpc/gen/fpgetmask.c
@@ -0,0 +1,48 @@
+/* $NetBSD: fpgetmask.c,v 1.3 2002/01/13 21:45:47 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Dan Winship.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <ieeefp.h>
+
+#ifndef _SOFT_FLOAT
+fp_except_t
+fpgetmask()
+{
+ u_int64_t fpscr;
+
+ __asm__("mffs %0" : "=f"(fpscr));
+ return ((fp_except_t)((fpscr >> 3) & 0x1f));
+}
+#endif
diff --git a/lib/libc/powerpc/gen/fpgetround.c b/lib/libc/powerpc/gen/fpgetround.c
new file mode 100644
index 000000000000..097e82aa9a41
--- /dev/null
+++ b/lib/libc/powerpc/gen/fpgetround.c
@@ -0,0 +1,48 @@
+/* $NetBSD: fpgetround.c,v 1.3 2002/01/13 21:45:47 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Dan Winship.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <ieeefp.h>
+
+#ifndef _SOFT_FLOAT
+fp_rnd_t
+fpgetround()
+{
+ u_int64_t fpscr;
+
+ __asm__("mffs %0" : "=f"(fpscr));
+ return ((fp_rnd_t)(fpscr & 0x3));
+}
+#endif
diff --git a/lib/libc/powerpc/gen/fpgetsticky.c b/lib/libc/powerpc/gen/fpgetsticky.c
new file mode 100644
index 000000000000..57152ac50104
--- /dev/null
+++ b/lib/libc/powerpc/gen/fpgetsticky.c
@@ -0,0 +1,54 @@
+/* $NetBSD: fpgetsticky.c,v 1.3 2002/01/13 21:45:48 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Dan Winship.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/cdefs.h>
+
+#include "namespace.h"
+
+#include <sys/types.h>
+#include <ieeefp.h>
+
+#ifndef _SOFT_FLOAT
+#ifdef __weak_alias
+__weak_alias(fpgetsticky,_fpgetsticky)
+#endif
+
+fp_except_t
+fpgetsticky()
+{
+ u_int64_t fpscr;
+
+ __asm__ __volatile("mffs %0" : "=f"(fpscr));
+ return ((fp_except_t)((fpscr >> 25) & 0x1f));
+}
+#endif
diff --git a/lib/libc/powerpc/gen/fpsetmask.c b/lib/libc/powerpc/gen/fpsetmask.c
new file mode 100644
index 000000000000..81cd19e57f1b
--- /dev/null
+++ b/lib/libc/powerpc/gen/fpsetmask.c
@@ -0,0 +1,52 @@
+/* $NetBSD: fpsetmask.c,v 1.3 2002/01/13 21:45:48 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Dan Winship.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <ieeefp.h>
+
+#ifndef _SOFT_FLOAT
+fp_except_t
+fpsetmask(fp_except_t mask)
+{
+ u_int64_t fpscr;
+ fp_rnd_t old;
+
+ __asm__("mffs %0" : "=f"(fpscr));
+ old = (fp_rnd_t)((fpscr >> 3) & 0x1f);
+ fpscr = (fpscr & 0xffffff07) | (mask << 3);
+ __asm__ __volatile("mtfsf 0xff,%0" :: "f"(fpscr));
+ return (old);
+}
+#endif
diff --git a/lib/libc/powerpc/gen/fpsetround.c b/lib/libc/powerpc/gen/fpsetround.c
new file mode 100644
index 000000000000..17f70a0cab64
--- /dev/null
+++ b/lib/libc/powerpc/gen/fpsetround.c
@@ -0,0 +1,52 @@
+/* $NetBSD: fpsetround.c,v 1.3 2002/01/13 21:45:48 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Dan Winship.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <ieeefp.h>
+
+#ifndef _SOFT_FLOAT
+fp_rnd_t
+fpsetround(fp_rnd_t rnd_dir)
+{
+ u_int64_t fpscr;
+ fp_rnd_t old;
+
+ __asm__ __volatile("mffs %0" : "=f"(fpscr));
+ old = (fp_rnd_t)(fpscr & 0x3);
+ fpscr = (fpscr & 0xfffffffc) | rnd_dir;
+ __asm__ __volatile("mtfsf 0xff,%0" :: "f"(fpscr));
+ return (old);
+}
+#endif
diff --git a/lib/libc/powerpc/gen/infinity.c b/lib/libc/powerpc/gen/infinity.c
new file mode 100644
index 000000000000..f5324389d5b6
--- /dev/null
+++ b/lib/libc/powerpc/gen/infinity.c
@@ -0,0 +1,30 @@
+#include <sys/cdefs.h>
+#if 0
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: infinity.c,v 1.2 1998/11/14 19:31:02 christos Exp $");
+#endif /* LIBC_SCCS and not lint */
+#endif
+__FBSDID("$FreeBSD$");
+
+/* infinity.c */
+
+#include <math.h>
+
+/* bytes for +Infinity on powerpc */
+const union __infinity_un __infinity = {
+#if BYTE_ORDER == BIG_ENDIAN
+ { 0x7f, 0xf0, 0, 0, 0, 0, 0, 0 }
+#else
+ { 0, 0, 0, 0, 0, 0, 0xf0, 0x7f }
+#endif
+};
+
+/* bytes for NaN */
+const union __nan_un __nan = {
+#if BYTE_ORDER == BIG_ENDIAN
+ {0xff, 0xc0, 0, 0}
+#else
+ { 0, 0, 0xc0, 0xff }
+#endif
+};
+
diff --git a/lib/libc/powerpc/gen/makecontext.c b/lib/libc/powerpc/gen/makecontext.c
new file mode 100644
index 000000000000..d66e82457a4e
--- /dev/null
+++ b/lib/libc/powerpc/gen/makecontext.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2004 Suleiman Souhlal
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <ucontext.h>
+
+__weak_reference(__makecontext, makecontext);
+
+void _ctx_done(ucontext_t *ucp);
+void _ctx_start(void);
+
+void
+_ctx_done(ucontext_t *ucp)
+{
+ if (ucp->uc_link == NULL)
+ exit(0);
+ else {
+ /* invalidate context */
+ ucp->uc_mcontext.mc_len = 0;
+
+ setcontext((const ucontext_t *)ucp->uc_link);
+
+ abort(); /* should never return from above call */
+ }
+}
+
+void
+__makecontext(ucontext_t *ucp, void (*start)(void), int argc, ...)
+{
+ mcontext_t *mc;
+ char *sp;
+ va_list ap;
+ int i, regargs, stackargs;
+
+ /* Sanity checks */
+ if ((ucp == NULL) || (argc < 0) || (argc > NCARGS)
+ || (ucp->uc_stack.ss_sp == NULL)
+ || (ucp->uc_stack.ss_size < MINSIGSTKSZ)) {
+ /* invalidate context */
+ ucp->uc_mcontext.mc_len = 0;
+ return;
+ }
+
+ /*
+ * The stack must have space for the frame pointer, saved
+ * link register, overflow arguments, and be 16-byte
+ * aligned.
+ */
+ stackargs = (argc > 8) ? argc - 8 : 0;
+ sp = (char *) ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size
+ - sizeof(uint32_t)*(stackargs + 2);
+ sp = (char *)((uint32_t)sp & ~0x1f);
+
+ mc = &ucp->uc_mcontext;
+
+ /*
+ * Up to 8 register args. Assumes all args are 32-bit and
+ * integer only. Not sure how to cater for floating point,
+ * although 64-bit args will work if aligned correctly
+ * in the arg list.
+ */
+ regargs = (argc > 8) ? 8 : argc;
+ va_start(ap, argc);
+ for (i = 0; i < regargs; i++)
+ mc->mc_gpr[3 + i] = va_arg(ap, uint32_t);
+
+ /*
+ * Overflow args go onto the stack
+ */
+ if (argc > 8) {
+ uint32_t *argp;
+
+ /* Skip past frame pointer and saved LR */
+ argp = (uint32_t *)sp + 2;
+
+ for (i = 0; i < stackargs; i++)
+ *argp++ = va_arg(ap, uint32_t);
+ }
+ va_end(ap);
+
+ /*
+ * Use caller-saved regs 14/15 to hold params that _ctx_start
+ * will use to invoke the user-supplied func
+ */
+ mc->mc_srr0 = (uint32_t) _ctx_start;
+ mc->mc_gpr[1] = (uint32_t) sp; /* new stack pointer */
+ mc->mc_gpr[14] = (uint32_t) start; /* r14 <- start */
+ mc->mc_gpr[15] = (uint32_t) ucp; /* r15 <- ucp */
+}
diff --git a/lib/libc/powerpc/gen/setjmp.S b/lib/libc/powerpc/gen/setjmp.S
new file mode 100644
index 000000000000..ef7cb7e7be6e
--- /dev/null
+++ b/lib/libc/powerpc/gen/setjmp.S
@@ -0,0 +1,134 @@
+/*-
+ * Copyright (c) 2002 Peter Grehan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/* $NetBSD: setjmp.S,v 1.3 1998/10/03 12:30:38 tsubai Exp $ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/syscall.h>
+
+/*
+ * C library -- setjmp, longjmp
+ *
+ * longjmp(a,v)
+ * will generate a "return(v?v:1)" from the last call to
+ * setjmp(a)
+ * by restoring registers from the stack.
+ * The previous signal state is restored.
+ *
+ * jmpbuf layout:
+ * +------------+
+ * | unused |
+ * +------------+
+ * | sig state |
+ * | |
+ * | (4 words) |
+ * | |
+ * +------------+
+ * | saved regs |
+ * | ... |
+ */
+
+ENTRY(setjmp)
+ mr %r6,%r3
+ li %r3,1 /* SIG_BLOCK, but doesn't matter */
+ /* since set == NULL */
+ li %r4,0 /* set = NULL */
+ mr %r5,%r6 /* &oset */
+ addi %r5,%r5,4
+ li %r0, SYS_sigprocmask /*sigprocmask(SIG_BLOCK, NULL, &oset)*/
+ sc /*assume no error XXX */
+ mflr %r11 /* r11 <- link reg */
+ mfcr %r12 /* r12 <- condition reg */
+ mr %r10,%r1 /* r10 <- stackptr */
+ mr %r9,%r2 /* r9 <- global ptr */
+ stmw %r9,20(%r6)
+
+ /* FPRs */
+ stfd %f14,112+0*8(%r6)
+ stfd %f15,112+1*8(%r6)
+ stfd %f16,112+2*8(%r6)
+ stfd %f17,112+3*8(%r6)
+ stfd %f18,112+4*8(%r6)
+ stfd %f19,112+5*8(%r6)
+ stfd %f20,112+6*8(%r6)
+ stfd %f21,112+7*8(%r6)
+ stfd %f22,112+8*8(%r6)
+ stfd %f23,112+9*8(%r6)
+ stfd %f24,112+10*8(%r6)
+ stfd %f25,112+11*8(%r6)
+ stfd %f26,112+12*8(%r6)
+ stfd %f27,112+13*8(%r6)
+ stfd %f28,112+14*8(%r6)
+ stfd %f29,112+15*8(%r6)
+ stfd %f30,112+16*8(%r6)
+ stfd %f31,112+17*8(%r6)
+
+ li %r3,0 /* return (0) */
+ blr
+END(setjmp)
+
+ WEAK_REFERENCE(CNAME(__longjmp), longjmp)
+ENTRY(__longjmp)
+ lmw %r9,20(%r3) /* restore regs */
+
+ /* FPRs */
+ lfd %f14,112+0*8(%r3)
+ lfd %f15,112+1*8(%r3)
+ lfd %f16,112+2*8(%r3)
+ lfd %f17,112+3*8(%r3)
+ lfd %f18,112+4*8(%r3)
+ lfd %f19,112+5*8(%r3)
+ lfd %f20,112+6*8(%r3)
+ lfd %f21,112+7*8(%r3)
+ lfd %f22,112+8*8(%r3)
+ lfd %f23,112+9*8(%r3)
+ lfd %f24,112+10*8(%r3)
+ lfd %f25,112+11*8(%r3)
+ lfd %f26,112+12*8(%r3)
+ lfd %f27,112+13*8(%r3)
+ lfd %f28,112+14*8(%r3)
+ lfd %f29,112+15*8(%r3)
+ lfd %f30,112+16*8(%r3)
+ lfd %f31,112+17*8(%r3)
+
+ mr %r6,%r4 /* save val param */
+ mtlr %r11 /* r11 -> link reg */
+ mtcr %r12 /* r12 -> condition reg */
+ mr %r1,%r10 /* r10 -> stackptr */
+ mr %r4,%r3
+ li %r3,3 /* SIG_SETMASK */
+ addi %r4,%r4,4 /* &set */
+ li %r5,0 /* oset = NULL */
+ li %r0,SYS_sigprocmask /* sigprocmask(SIG_SET, &set, NULL) */
+ sc /* assume no error XXX */
+ or. %r3,%r6,%r6
+ bnelr
+ li %r3,1
+ blr
+END(__longjmp)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/powerpc/gen/signalcontext.c b/lib/libc/powerpc/gen/signalcontext.c
new file mode 100644
index 000000000000..30e2be848b2b
--- /dev/null
+++ b/lib/libc/powerpc/gen/signalcontext.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2004 Marcel Moolenaar, Peter Grehan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/ucontext.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <strings.h>
+
+typedef void (*handler_t)(uint32_t, uint32_t, uint32_t);
+
+/* Prototypes */
+static void ctx_wrapper(ucontext_t *ucp, handler_t func, uint32_t sig,
+ uint32_t sig_si, uint32_t sig_uc);
+
+__weak_reference(__signalcontext, signalcontext);
+
+int
+__signalcontext(ucontext_t *ucp, int sig, __sighandler_t *func)
+{
+ siginfo_t *sig_si;
+ ucontext_t *sig_uc;
+ uint32_t sp;
+
+ /* Bail out if we don't have a valid ucontext pointer. */
+ if (ucp == NULL)
+ abort();
+
+ /*
+ * Build a 16-byte-aligned signal frame
+ */
+ sp = (ucp->uc_mcontext.mc_gpr[1] - sizeof(ucontext_t)) & ~15UL;
+ sig_uc = (ucontext_t *)sp;
+ bcopy(ucp, sig_uc, sizeof(*sig_uc));
+ sp = (sp - sizeof(siginfo_t)) & ~15UL;
+ sig_si = (siginfo_t *)sp;
+ bzero(sig_si, sizeof(*sig_si));
+ sig_si->si_signo = sig;
+
+ /*
+ * Subtract 8 bytes from stack to allow for frameptr
+ */
+ sp -= 2*sizeof(uint32_t);
+ sp &= ~15UL;
+
+ /*
+ * Setup the ucontext of the signal handler.
+ */
+ bzero(&ucp->uc_mcontext, sizeof(ucp->uc_mcontext));
+ ucp->uc_link = sig_uc;
+ sigdelset(&ucp->uc_sigmask, sig);
+
+ ucp->uc_mcontext.mc_vers = _MC_VERSION;
+ ucp->uc_mcontext.mc_len = sizeof(struct __mcontext);
+ ucp->uc_mcontext.mc_srr0 = (uint32_t) ctx_wrapper;
+ ucp->uc_mcontext.mc_gpr[1] = (uint32_t) sp;
+ ucp->uc_mcontext.mc_gpr[3] = (uint32_t) func;
+ ucp->uc_mcontext.mc_gpr[4] = (uint32_t) sig;
+ ucp->uc_mcontext.mc_gpr[5] = (uint32_t) sig_si;
+ ucp->uc_mcontext.mc_gpr[6] = (uint32_t) sig_uc;
+
+ return (0);
+}
+
+static void
+ctx_wrapper(ucontext_t *ucp, handler_t func, uint32_t sig, uint32_t sig_si,
+ uint32_t sig_uc)
+{
+
+ (*func)(sig, sig_si, sig_uc);
+ if (ucp->uc_link == NULL)
+ exit(0);
+ setcontext((const ucontext_t *)ucp->uc_link);
+ /* should never get here */
+ abort();
+ /* NOTREACHED */
+}
diff --git a/lib/libc/powerpc/gen/sigsetjmp.S b/lib/libc/powerpc/gen/sigsetjmp.S
new file mode 100644
index 000000000000..9c75f4f86dd7
--- /dev/null
+++ b/lib/libc/powerpc/gen/sigsetjmp.S
@@ -0,0 +1,142 @@
+/*-
+ * Copyright (c) 2002 Peter Grehan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/* $NetBSD: sigsetjmp.S,v 1.4 1998/10/03 12:30:38 tsubai Exp $ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * C library -- sigsetjmp, siglongjmp
+ *
+ * siglongjmp(a,v)
+ * will generate a "return(v?v:1)" from the last call to
+ * sigsetjmp(a, savemask)
+ * by restoring registers from the stack.
+ * The previous signal state is restored if savemask is non-zero
+ *
+ * jmpbuf layout:
+ * +------------+
+ * | savemask |
+ * +------------+
+ * | sig state |
+ * | |
+ * | (4 words) |
+ * | |
+ * +------------+
+ * | saved regs |
+ * | ... |
+ */
+
+
+#include <sys/syscall.h>
+
+ENTRY(sigsetjmp)
+ mr %r6,%r3
+ stw %r4,0(%r3)
+ or. %r7,%r4,%r4
+ beq 1f
+ li %r3,1 /* SIG_BLOCK, but doesn't matter */
+ /* since set == NULL */
+ li %r4,0 /* set = NULL */
+ mr %r5,%r6 /* &oset */
+ addi %r5,%r5,4
+ li %r0, SYS_sigprocmask /* sigprocmask(SIG_BLOCK, NULL, &oset)*/
+ sc /* assume no error XXX */
+1:
+ mflr %r11
+ mfcr %r12
+ mr %r10,%r1
+ mr %r9,%r2
+ stmw %r9,20(%r6)
+
+ /* FPRs */
+ stfd %f14,112+0*8(%r6)
+ stfd %f15,112+1*8(%r6)
+ stfd %f16,112+2*8(%r6)
+ stfd %f17,112+3*8(%r6)
+ stfd %f18,112+4*8(%r6)
+ stfd %f19,112+5*8(%r6)
+ stfd %f20,112+6*8(%r6)
+ stfd %f21,112+7*8(%r6)
+ stfd %f22,112+8*8(%r6)
+ stfd %f23,112+9*8(%r6)
+ stfd %f24,112+10*8(%r6)
+ stfd %f25,112+11*8(%r6)
+ stfd %f26,112+12*8(%r6)
+ stfd %f27,112+13*8(%r6)
+ stfd %f28,112+14*8(%r6)
+ stfd %f29,112+15*8(%r6)
+ stfd %f30,112+16*8(%r6)
+ stfd %f31,112+17*8(%r6)
+
+ li %r3,0
+ blr
+END(sigsetjmp)
+
+ENTRY(siglongjmp)
+ lmw %r9,20(%r3)
+
+ /* FPRs */
+ lfd %f14,112+0*8(%r3)
+ lfd %f15,112+1*8(%r3)
+ lfd %f16,112+2*8(%r3)
+ lfd %f17,112+3*8(%r3)
+ lfd %f18,112+4*8(%r3)
+ lfd %f19,112+5*8(%r3)
+ lfd %f20,112+6*8(%r3)
+ lfd %f21,112+7*8(%r3)
+ lfd %f22,112+8*8(%r3)
+ lfd %f23,112+9*8(%r3)
+ lfd %f24,112+10*8(%r3)
+ lfd %f25,112+11*8(%r3)
+ lfd %f26,112+12*8(%r3)
+ lfd %f27,112+13*8(%r3)
+ lfd %f28,112+14*8(%r3)
+ lfd %f29,112+15*8(%r3)
+ lfd %f30,112+16*8(%r3)
+ lfd %f31,112+17*8(%r3)
+
+ lwz %r7,0(%r3)
+ mr %r6,%r4
+ mtlr %r11
+ mtcr %r12
+ mr %r1,%r10
+ or. %r7,%r7,%r7
+ beq 1f
+ mr %r4,%r3
+ li %r3,3 /* SIG_SETMASK */
+ addi %r4,%r4,4 /* &set */
+ li %r5,0 /* oset = NULL */
+ li %r0,SYS_sigprocmask /* sigprocmask(SIG_SET, &set, NULL) */
+ sc /* assume no error XXX */
+1:
+ or. %r3,%r6,%r6
+ bnelr
+ li %r3,1
+ blr
+END(siglongjmp)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/powerpc/gen/syncicache.c b/lib/libc/powerpc/gen/syncicache.c
new file mode 100644
index 000000000000..aa025cca8bc6
--- /dev/null
+++ b/lib/libc/powerpc/gen/syncicache.c
@@ -0,0 +1,103 @@
+/*-
+ * Copyright (C) 1995-1997, 1999 Wolfgang Solfrank.
+ * Copyright (C) 1995-1997, 1999 TooLs GmbH.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by TooLs GmbH.
+ * 4. The name of TooLs GmbH may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $NetBSD: syncicache.c,v 1.2 1999/05/05 12:36:40 tsubai Exp $
+ */
+
+#ifndef lint
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif /* not lint */
+
+#include <sys/param.h>
+#if defined(_KERNEL) || defined(_STANDALONE)
+#include <sys/time.h>
+#include <sys/proc.h>
+#include <vm/vm.h>
+#endif
+#include <sys/sysctl.h>
+
+#include <machine/cpu.h>
+#include <machine/md_var.h>
+
+#ifdef _STANDALONE
+int cacheline_size = 32;
+#endif
+
+#if !defined(_KERNEL) && !defined(_STANDALONE)
+#include <stdlib.h>
+
+int cacheline_size = 0;
+
+static void getcachelinesize(void);
+
+static void
+getcachelinesize()
+{
+ static int cachemib[] = { CTL_MACHDEP, CPU_CACHELINE };
+ int clen;
+
+ clen = sizeof(cacheline_size);
+
+ if (sysctl(cachemib, nitems(cachemib), &cacheline_size, &clen,
+ NULL, 0) < 0 || !cacheline_size) {
+ abort();
+ }
+}
+#endif
+
+void
+__syncicache(void *from, int len)
+{
+ int l, off;
+ char *p;
+
+#if !defined(_KERNEL) && !defined(_STANDALONE)
+ if (!cacheline_size)
+ getcachelinesize();
+#endif
+
+ off = (u_int)from & (cacheline_size - 1);
+ l = len += off;
+ p = (char *)from - off;
+
+ do {
+ __asm __volatile ("dcbst 0,%0" :: "r"(p));
+ p += cacheline_size;
+ } while ((l -= cacheline_size) > 0);
+ __asm __volatile ("sync");
+ p = (char *)from - off;
+ do {
+ __asm __volatile ("icbi 0,%0" :: "r"(p));
+ p += cacheline_size;
+ } while ((len -= cacheline_size) > 0);
+ __asm __volatile ("sync; isync");
+}
+
diff --git a/lib/libc/powerpc/softfloat/milieu.h b/lib/libc/powerpc/softfloat/milieu.h
new file mode 100644
index 000000000000..e2e43b150073
--- /dev/null
+++ b/lib/libc/powerpc/softfloat/milieu.h
@@ -0,0 +1,49 @@
+/* $NetBSD: milieu.h,v 1.1 2000/12/29 20:13:54 bjh21 Exp $ */
+/* $FreeBSD$ */
+
+/*
+===============================================================================
+
+This C header file is part of the SoftFloat IEC/IEEE Floating-point
+Arithmetic Package, Release 2a.
+
+Written by John R. Hauser. This work was made possible in part by the
+International Computer Science Institute, located at Suite 600, 1947 Center
+Street, Berkeley, California 94704. Funding was partially provided by the
+National Science Foundation under grant MIP-9311980. The original version
+of this code was written as part of a project to build a fixed-point vector
+processor in collaboration with the University of California at Berkeley,
+overseen by Profs. Nelson Morgan and John Wawrzynek. More information
+is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
+arithmetic/SoftFloat.html'.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
+has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
+TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
+PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
+AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
+
+Derivative works are acceptable, even for commercial purposes, so long as
+(1) they include prominent notice that the work is derivative, and (2) they
+include prominent notice akin to these four paragraphs for those parts of
+this code that are retained.
+
+===============================================================================
+*/
+
+/*
+-------------------------------------------------------------------------------
+Include common integer types and flags.
+-------------------------------------------------------------------------------
+*/
+#include "powerpc-gcc.h"
+
+/*
+-------------------------------------------------------------------------------
+Symbolic Boolean literals.
+-------------------------------------------------------------------------------
+*/
+enum {
+ FALSE = 0,
+ TRUE = 1
+};
diff --git a/lib/libc/powerpc/softfloat/powerpc-gcc.h b/lib/libc/powerpc/softfloat/powerpc-gcc.h
new file mode 100644
index 000000000000..e2f8680dd74e
--- /dev/null
+++ b/lib/libc/powerpc/softfloat/powerpc-gcc.h
@@ -0,0 +1,92 @@
+/* $NetBSD: arm-gcc.h,v 1.2 2001/02/21 18:09:25 bjh21 Exp $ */
+/* $FreeBSD$ */
+
+/*
+-------------------------------------------------------------------------------
+One of the macros `BIGENDIAN' or `LITTLEENDIAN' must be defined.
+-------------------------------------------------------------------------------
+*/
+#define BIGENDIAN
+
+/*
+-------------------------------------------------------------------------------
+The macro `BITS64' can be defined to indicate that 64-bit integer types are
+supported by the compiler.
+-------------------------------------------------------------------------------
+*/
+#define BITS64
+
+/*
+-------------------------------------------------------------------------------
+Each of the following `typedef's defines the most convenient type that holds
+integers of at least as many bits as specified. For example, `uint8' should
+be the most convenient type that can hold unsigned integers of as many as
+8 bits. The `flag' type must be able to hold either a 0 or 1. For most
+implementations of C, `flag', `uint8', and `int8' should all be `typedef'ed
+to the same as `int'.
+-------------------------------------------------------------------------------
+*/
+typedef int flag;
+typedef unsigned int uint8;
+typedef int int8;
+typedef unsigned int uint16;
+typedef int int16;
+typedef unsigned int uint32;
+typedef signed int int32;
+#ifdef BITS64
+typedef unsigned long long int uint64;
+typedef signed long long int int64;
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Each of the following `typedef's defines a type that holds integers
+of _exactly_ the number of bits specified. For instance, for most
+implementation of C, `bits16' and `sbits16' should be `typedef'ed to
+`unsigned short int' and `signed short int' (or `short int'), respectively.
+-------------------------------------------------------------------------------
+*/
+typedef unsigned char bits8;
+typedef signed char sbits8;
+typedef unsigned short int bits16;
+typedef signed short int sbits16;
+typedef unsigned int bits32;
+typedef signed int sbits32;
+#ifdef BITS64
+typedef unsigned long long int bits64;
+typedef signed long long int sbits64;
+#endif
+
+#ifdef BITS64
+/*
+-------------------------------------------------------------------------------
+The `LIT64' macro takes as its argument a textual integer literal and
+if necessary ``marks'' the literal as having a 64-bit integer type.
+For example, the GNU C Compiler (`gcc') requires that 64-bit literals be
+appended with the letters `LL' standing for `long long', which is `gcc's
+name for the 64-bit integer type. Some compilers may allow `LIT64' to be
+defined as the identity macro: `#define LIT64( a ) a'.
+-------------------------------------------------------------------------------
+*/
+#define LIT64( a ) a##LL
+#endif
+
+/*
+-------------------------------------------------------------------------------
+The macro `INLINE' can be used before functions that should be inlined. If
+a compiler does not support explicit inlining, this macro should be defined
+to be `static'.
+-------------------------------------------------------------------------------
+*/
+#define INLINE static __inline
+
+/*
+-------------------------------------------------------------------------------
+The ARM FPA is odd in that it stores doubles high-order word first, no matter
+what the endianness of the CPU. VFP is sane.
+-------------------------------------------------------------------------------
+*/
+#if defined(SOFTFLOAT_FOR_GCC)
+#define FLOAT64_DEMANGLE(a) (a)
+#define FLOAT64_MANGLE(a) (a)
+#endif
diff --git a/lib/libc/powerpc/softfloat/softfloat.h b/lib/libc/powerpc/softfloat/softfloat.h
new file mode 100644
index 000000000000..6b9c9b06956d
--- /dev/null
+++ b/lib/libc/powerpc/softfloat/softfloat.h
@@ -0,0 +1,307 @@
+/* $NetBSD: softfloat.h,v 1.6 2002/05/12 13:12:46 bjh21 Exp $ */
+/* $FreeBSD$ */
+
+/* This is a derivative work. */
+
+/*
+===============================================================================
+
+This C header file is part of the SoftFloat IEC/IEEE Floating-point
+Arithmetic Package, Release 2a.
+
+Written by John R. Hauser. This work was made possible in part by the
+International Computer Science Institute, located at Suite 600, 1947 Center
+Street, Berkeley, California 94704. Funding was partially provided by the
+National Science Foundation under grant MIP-9311980. The original version
+of this code was written as part of a project to build a fixed-point vector
+processor in collaboration with the University of California at Berkeley,
+overseen by Profs. Nelson Morgan and John Wawrzynek. More information
+is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
+arithmetic/SoftFloat.html'.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
+has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
+TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
+PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
+AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
+
+Derivative works are acceptable, even for commercial purposes, so long as
+(1) they include prominent notice that the work is derivative, and (2) they
+include prominent notice akin to these four paragraphs for those parts of
+this code that are retained.
+
+===============================================================================
+*/
+
+/*
+-------------------------------------------------------------------------------
+The macro `FLOATX80' must be defined to enable the extended double-precision
+floating-point format `floatx80'. If this macro is not defined, the
+`floatx80' type will not be defined, and none of the functions that either
+input or output the `floatx80' type will be defined. The same applies to
+the `FLOAT128' macro and the quadruple-precision format `float128'.
+-------------------------------------------------------------------------------
+*/
+/* #define FLOATX80 */
+/* #define FLOAT128 */
+
+#include <machine/ieeefp.h>
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE floating-point types.
+-------------------------------------------------------------------------------
+*/
+typedef unsigned int float32;
+typedef unsigned long long float64;
+#ifdef FLOATX80
+typedef struct {
+ unsigned short high;
+ unsigned long long low;
+} floatx80;
+#endif
+#ifdef FLOAT128
+typedef struct {
+ unsigned long long high, low;
+} float128;
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE floating-point underflow tininess-detection mode.
+-------------------------------------------------------------------------------
+*/
+#ifndef SOFTFLOAT_FOR_GCC
+extern int8 float_detect_tininess;
+#endif
+enum {
+ float_tininess_after_rounding = 0,
+ float_tininess_before_rounding = 1
+};
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE floating-point rounding mode.
+-------------------------------------------------------------------------------
+*/
+extern fp_rnd_t float_rounding_mode;
+enum {
+ float_round_nearest_even = FP_RN,
+ float_round_to_zero = FP_RZ,
+ float_round_down = FP_RM,
+ float_round_up = FP_RP
+};
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE floating-point exception flags.
+-------------------------------------------------------------------------------
+*/
+typedef fp_except_t fp_except;
+
+extern fp_except float_exception_flags;
+extern fp_except float_exception_mask;
+enum {
+ float_flag_inexact = FP_X_IMP,
+ float_flag_underflow = FP_X_UFL,
+ float_flag_overflow = FP_X_OFL,
+ float_flag_divbyzero = FP_X_DZ,
+ float_flag_invalid = FP_X_INV
+};
+
+/*
+-------------------------------------------------------------------------------
+Routine to raise any or all of the software IEC/IEEE floating-point
+exception flags.
+-------------------------------------------------------------------------------
+*/
+void float_raise( fp_except );
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE integer-to-floating-point conversion routines.
+-------------------------------------------------------------------------------
+*/
+float32 int32_to_float32( int );
+float64 int32_to_float64( int );
+#ifdef FLOATX80
+floatx80 int32_to_floatx80( int );
+#endif
+#ifdef FLOAT128
+float128 int32_to_float128( int );
+#endif
+float32 int64_to_float32( long long );
+float64 int64_to_float64( long long );
+#ifdef FLOATX80
+floatx80 int64_to_floatx80( long long );
+#endif
+#ifdef FLOAT128
+float128 int64_to_float128( long long );
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE single-precision conversion routines.
+-------------------------------------------------------------------------------
+*/
+int float32_to_int32( float32 );
+int float32_to_int32_round_to_zero( float32 );
+unsigned int float32_to_uint32_round_to_zero( float32 );
+long long float32_to_int64( float32 );
+long long float32_to_int64_round_to_zero( float32 );
+float64 float32_to_float64( float32 );
+#ifdef FLOATX80
+floatx80 float32_to_floatx80( float32 );
+#endif
+#ifdef FLOAT128
+float128 float32_to_float128( float32 );
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE single-precision operations.
+-------------------------------------------------------------------------------
+*/
+float32 float32_round_to_int( float32 );
+float32 float32_add( float32, float32 );
+float32 float32_sub( float32, float32 );
+float32 float32_mul( float32, float32 );
+float32 float32_div( float32, float32 );
+float32 float32_rem( float32, float32 );
+float32 float32_sqrt( float32 );
+int float32_eq( float32, float32 );
+int float32_le( float32, float32 );
+int float32_lt( float32, float32 );
+int float32_eq_signaling( float32, float32 );
+int float32_le_quiet( float32, float32 );
+int float32_lt_quiet( float32, float32 );
+#ifndef SOFTFLOAT_FOR_GCC
+int float32_is_signaling_nan( float32 );
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE double-precision conversion routines.
+-------------------------------------------------------------------------------
+*/
+int float64_to_int32( float64 );
+int float64_to_int32_round_to_zero( float64 );
+unsigned int float64_to_uint32_round_to_zero( float64 );
+long long float64_to_int64( float64 );
+long long float64_to_int64_round_to_zero( float64 );
+float32 float64_to_float32( float64 );
+#ifdef FLOATX80
+floatx80 float64_to_floatx80( float64 );
+#endif
+#ifdef FLOAT128
+float128 float64_to_float128( float64 );
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE double-precision operations.
+-------------------------------------------------------------------------------
+*/
+float64 float64_round_to_int( float64 );
+float64 float64_add( float64, float64 );
+float64 float64_sub( float64, float64 );
+float64 float64_mul( float64, float64 );
+float64 float64_div( float64, float64 );
+float64 float64_rem( float64, float64 );
+float64 float64_sqrt( float64 );
+int float64_eq( float64, float64 );
+int float64_le( float64, float64 );
+int float64_lt( float64, float64 );
+int float64_eq_signaling( float64, float64 );
+int float64_le_quiet( float64, float64 );
+int float64_lt_quiet( float64, float64 );
+#ifndef SOFTFLOAT_FOR_GCC
+int float64_is_signaling_nan( float64 );
+#endif
+
+#ifdef FLOATX80
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE extended double-precision conversion routines.
+-------------------------------------------------------------------------------
+*/
+int floatx80_to_int32( floatx80 );
+int floatx80_to_int32_round_to_zero( floatx80 );
+long long floatx80_to_int64( floatx80 );
+long long floatx80_to_int64_round_to_zero( floatx80 );
+float32 floatx80_to_float32( floatx80 );
+float64 floatx80_to_float64( floatx80 );
+#ifdef FLOAT128
+float128 floatx80_to_float128( floatx80 );
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE extended double-precision rounding precision. Valid
+values are 32, 64, and 80.
+-------------------------------------------------------------------------------
+*/
+extern int floatx80_rounding_precision;
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE extended double-precision operations.
+-------------------------------------------------------------------------------
+*/
+floatx80 floatx80_round_to_int( floatx80 );
+floatx80 floatx80_add( floatx80, floatx80 );
+floatx80 floatx80_sub( floatx80, floatx80 );
+floatx80 floatx80_mul( floatx80, floatx80 );
+floatx80 floatx80_div( floatx80, floatx80 );
+floatx80 floatx80_rem( floatx80, floatx80 );
+floatx80 floatx80_sqrt( floatx80 );
+int floatx80_eq( floatx80, floatx80 );
+int floatx80_le( floatx80, floatx80 );
+int floatx80_lt( floatx80, floatx80 );
+int floatx80_eq_signaling( floatx80, floatx80 );
+int floatx80_le_quiet( floatx80, floatx80 );
+int floatx80_lt_quiet( floatx80, floatx80 );
+int floatx80_is_signaling_nan( floatx80 );
+
+#endif
+
+#ifdef FLOAT128
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE quadruple-precision conversion routines.
+-------------------------------------------------------------------------------
+*/
+int float128_to_int32( float128 );
+int float128_to_int32_round_to_zero( float128 );
+long long float128_to_int64( float128 );
+long long float128_to_int64_round_to_zero( float128 );
+float32 float128_to_float32( float128 );
+float64 float128_to_float64( float128 );
+#ifdef FLOATX80
+floatx80 float128_to_floatx80( float128 );
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE quadruple-precision operations.
+-------------------------------------------------------------------------------
+*/
+float128 float128_round_to_int( float128 );
+float128 float128_add( float128, float128 );
+float128 float128_sub( float128, float128 );
+float128 float128_mul( float128, float128 );
+float128 float128_div( float128, float128 );
+float128 float128_rem( float128, float128 );
+float128 float128_sqrt( float128 );
+int float128_eq( float128, float128 );
+int float128_le( float128, float128 );
+int float128_lt( float128, float128 );
+int float128_eq_signaling( float128, float128 );
+int float128_le_quiet( float128, float128 );
+int float128_lt_quiet( float128, float128 );
+int float128_is_signaling_nan( float128 );
+
+#endif
+
diff --git a/lib/libc/powerpc/sys/Makefile.inc b/lib/libc/powerpc/sys/Makefile.inc
new file mode 100644
index 000000000000..edb469c6fbcf
--- /dev/null
+++ b/lib/libc/powerpc/sys/Makefile.inc
@@ -0,0 +1,3 @@
+# $FreeBSD$
+
+MDASM+= brk.S cerror.S exect.S sbrk.S setlogin.S
diff --git a/lib/libc/powerpc/sys/brk.S b/lib/libc/powerpc/sys/brk.S
new file mode 100644
index 000000000000..e14be1058b51
--- /dev/null
+++ b/lib/libc/powerpc/sys/brk.S
@@ -0,0 +1,76 @@
+/*-
+ * Copyright (c) 2002 Peter Grehan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/* $NetBSD: brk.S,v 1.9 2000/06/26 06:25:43 kleink Exp $ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+ .globl HIDENAME(curbrk)
+ .globl HIDENAME(minbrk)
+ .globl CNAME(_end)
+
+ .data
+HIDENAME(minbrk):
+ .long CNAME(_end)
+
+ .text
+
+ENTRY(brk)
+#ifdef PIC
+ mflr %r10
+ bl _GLOBAL_OFFSET_TABLE_@local-4
+ mflr %r9
+ mtlr %r10
+ lwz %r5,HIDENAME(minbrk)@got(%r9)
+ lwz %r6,0(%r5)
+#else
+ lis %r5,HIDENAME(minbrk)@ha
+ lwz %r6,HIDENAME(minbrk)@l(%r5)
+#endif
+ cmplw %r6,%r3 /* if (minbrk <= r3) */
+ bgt 0f
+ mr %r6,%r3 /* r6 = r3 */
+0:
+ mr %r3,%r6 /* new break value */
+ li %r0,SYS_break
+ sc /* assume, that r5 is kept */
+ bso 1f
+#ifdef PIC
+ lwz %r7,HIDENAME(curbrk)@got(%r9)
+ stw %r6,0(%r7)
+#else
+ lis %r7,HIDENAME(curbrk)@ha /* record new break */
+ stw %r6,HIDENAME(curbrk)@l(%r7)
+#endif
+ blr /* return 0 */
+
+1:
+ b PIC_PLT(HIDENAME(cerror))
+END(brk)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/powerpc/sys/cerror.S b/lib/libc/powerpc/sys/cerror.S
new file mode 100644
index 000000000000..7667cb8361d3
--- /dev/null
+++ b/lib/libc/powerpc/sys/cerror.S
@@ -0,0 +1,57 @@
+/*-
+ * Copyright (c) 2002 Peter Grehan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/* $NetBSD: cerror.S,v 1.5 2000/01/27 14:58:48 kleink Exp $ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+ .globl HIDENAME(cerror)
+ .globl CNAME(__error)
+
+ /*
+ * The __error() function is thread aware. For non-threaded
+ * programs and the initial threaded in threaded programs,
+ * it returns a pointer to the global errno variable.
+ */
+HIDENAME(cerror):
+ mflr %r0
+ stwu %r1,-16(%r1) /* allocate new stack frame */
+ stw %r0,20(%r1) /* and save lr, r31 */
+ stw %r31,8(%r1)
+ mr %r31,%r3 /* stash errval in callee-saved register */
+ bl PIC_PLT(CNAME(__error))
+ stw %r31,0(%r3) /* store errval into &errno */
+ lwz %r0,20(%r1)
+ lwz %r31,8(%r1)
+ mtlr %r0
+ la %r1,16(%r1)
+ li %r3,-1
+ li %r4,-1
+ blr /* return to callers caller */
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/powerpc/sys/exect.S b/lib/libc/powerpc/sys/exect.S
new file mode 100644
index 000000000000..701f5b00f45c
--- /dev/null
+++ b/lib/libc/powerpc/sys/exect.S
@@ -0,0 +1,42 @@
+/*-
+ * Copyright (c) 2002 Peter Grehan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/* $NetBSD: exect.S,v 1.3 1998/05/25 15:28:03 ws Exp $ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+ENTRY(exect)
+ li %r0,SYS_execve
+ sc
+ bso 1f
+ blr
+1:
+ b PIC_PLT(HIDENAME(cerror))
+END(exect)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/powerpc/sys/sbrk.S b/lib/libc/powerpc/sys/sbrk.S
new file mode 100644
index 000000000000..f058d112e863
--- /dev/null
+++ b/lib/libc/powerpc/sys/sbrk.S
@@ -0,0 +1,73 @@
+/*-
+ * Copyright (c) 2002 Peter Grehan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/* $NetBSD: sbrk.S,v 1.8 2000/06/26 06:25:44 kleink Exp $ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+ .globl HIDENAME(curbrk)
+ .globl CNAME(_end)
+
+ .data
+HIDENAME(curbrk):
+ .long CNAME(_end)
+
+ .text
+ENTRY(sbrk)
+
+#ifdef PIC
+ mflr %r10
+ bl _GLOBAL_OFFSET_TABLE_@local-4
+ mflr %r5
+ mtlr %r10
+ lwz %r5,HIDENAME(curbrk)@got(%r5)
+ lwz %r6,0(%r5)
+#else
+ lis %r5,HIDENAME(curbrk)@ha
+ lwz %r6,HIDENAME(curbrk)@l(%r5) /* r6 = old break */
+#endif
+ cmpwi %r3,0 /* sbrk(0) - return curbrk */
+ beq 1f
+ add %r3,%r3,%r6
+ mr %r7,%r3 /* r7 = new break */
+ li %r0,SYS_break
+ sc /* break(new_break) */
+ bso 2f
+#ifdef PIC
+ stw %r7,0(%r5)
+#else
+ stw %r7,HIDENAME(curbrk)@l(%r5) /* record new break */
+#endif
+1:
+ mr %r3,%r6 /* set return value */
+ blr
+2:
+ b PIC_PLT(HIDENAME(cerror))
+END(sbrk)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/powerpc/sys/setlogin.S b/lib/libc/powerpc/sys/setlogin.S
new file mode 100644
index 000000000000..e0d6d3c012ce
--- /dev/null
+++ b/lib/libc/powerpc/sys/setlogin.S
@@ -0,0 +1,51 @@
+/*-
+ * Copyright (c) 2002 Peter Grehan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/* $NetBSD: setlogin.S,v 1.3 1998/11/24 11:14:57 tsubai Exp $ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+ .globl CNAME(_logname_valid) /* in _getlogin() */
+
+SYSCALL(setlogin)
+#ifdef PIC
+ mflr %r10
+ bl _GLOBAL_OFFSET_TABLE_@local-4
+ mflr %r4
+ lwz %r4,CNAME(_logname_valid)@got(%r4)
+ li %r5,%r0
+ stw %r5,0(%r4)
+ mtlr %r10
+#else
+ lis %r4,CNAME(_logname_valid)@ha
+ li %r5,0
+ stw %r5,CNAME(_logname_valid)@l(%r4)
+#endif
+ blr
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/powerpc64/Makefile.inc b/lib/libc/powerpc64/Makefile.inc
new file mode 100644
index 000000000000..8e9bcc52e7a0
--- /dev/null
+++ b/lib/libc/powerpc64/Makefile.inc
@@ -0,0 +1,7 @@
+# $FreeBSD$
+
+SRCS+= trivial-vdso_tc.c
+
+# Long double is 64-bits
+MDSRCS+=machdep_ldisd.c
+SYM_MAPS+=${LIBC_SRCTOP}/powerpc64/Symbol.map
diff --git a/lib/libc/powerpc64/SYS.h b/lib/libc/powerpc64/SYS.h
new file mode 100644
index 000000000000..486e71bfeae8
--- /dev/null
+++ b/lib/libc/powerpc64/SYS.h
@@ -0,0 +1,94 @@
+/*-
+ * Copyright (c) 2002 Benno Rice. All rights reserved.
+ * Copyright (c) 2002 David E. O'Brien. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $NetBSD: SYS.h,v 1.8 2002/01/14 00:55:56 thorpej Exp $
+ * $FreeBSD$
+ */
+
+#include <sys/syscall.h>
+#include <machine/asm.h>
+
+#define _SYSCALL(name) \
+ .text; \
+ .align 2; \
+ li 0,(SYS_##name); \
+ sc
+
+#define SYSCALL(name) \
+ .text; \
+ .align 2; \
+2: mflr %r0; \
+ std %r0,16(%r1); \
+ stdu %r1,-48(%r1); \
+ bl CNAME(HIDENAME(cerror)); \
+ nop; \
+ addi %r1,%r1,48; \
+ ld %r0,16(%r1); \
+ mtlr %r0; \
+ blr; \
+ENTRY(__sys_##name); \
+ WEAK_REFERENCE(__sys_##name, name); \
+ WEAK_REFERENCE(__sys_##name, _##name); \
+ _SYSCALL(name); \
+ bso 2b
+
+#define PSEUDO(name) \
+ .text; \
+ .align 2; \
+ENTRY(__sys_##name); \
+ WEAK_REFERENCE(__sys_##name, _##name); \
+ _SYSCALL(name); \
+ bnslr; \
+ mflr %r0; \
+ std %r0,16(%r1); \
+ stdu %r1,-48(%r1); \
+ bl CNAME(HIDENAME(cerror)); \
+ nop; \
+ addi %r1,%r1,48; \
+ ld %r0,16(%r1); \
+ mtlr %r0; \
+ blr;
+
+#define RSYSCALL(name) \
+ .text; \
+ .align 2; \
+ENTRY(__sys_##name); \
+ WEAK_REFERENCE(__sys_##name, name); \
+ WEAK_REFERENCE(__sys_##name, _##name); \
+ _SYSCALL(name); \
+ bnslr; \
+ \
+ mflr %r0; \
+ std %r0,16(%r1); \
+ stdu %r1,-48(%r1); \
+ bl CNAME(HIDENAME(cerror)); \
+ nop; \
+ addi %r1,%r1,48; \
+ ld %r0,16(%r1); \
+ mtlr %r0; \
+ blr;
diff --git a/lib/libc/powerpc64/Symbol.map b/lib/libc/powerpc64/Symbol.map
new file mode 100644
index 000000000000..c429e84ab5fd
--- /dev/null
+++ b/lib/libc/powerpc64/Symbol.map
@@ -0,0 +1,55 @@
+/*
+ * $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, ...).
+ */
+FBSD_1.0 {
+ /* PSEUDO syscalls */
+ _exit;
+
+ _mcount;
+ _setjmp;
+ _longjmp;
+ fabs;
+ __flt_rounds;
+ fpgetmask;
+ fpgetround;
+ fpgetsticky;
+ fpsetmask;
+ fpsetround;
+ __infinity;
+ __nan;
+ makecontext;
+ setjmp;
+ longjmp;
+ sigsetjmp;
+ siglongjmp;
+ htonl;
+ htons;
+ ntohl;
+ ntohs;
+ brk;
+ exect;
+ sbrk;
+ vfork;
+};
+
+FBSDprivate_1.0 {
+ /* PSEUDO syscalls */
+ __sys_getlogin;
+ _getlogin;
+ __sys_exit;
+
+ _set_tp;
+ _fpgetsticky;
+ __makecontext;
+ __longjmp;
+ signalcontext;
+ __signalcontext;
+ __syncicache;
+ _end;
+};
diff --git a/lib/libc/powerpc64/_fpmath.h b/lib/libc/powerpc64/_fpmath.h
new file mode 100644
index 000000000000..4b7971e4da8a
--- /dev/null
+++ b/lib/libc/powerpc64/_fpmath.h
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 2003 David Schultz <das@FreeBSD.ORG>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+union IEEEl2bits {
+ long double e;
+ struct {
+#if _BYTE_ORDER == _LITTLE_ENDIAN
+ unsigned int manl :32;
+ unsigned int manh :20;
+ unsigned int exp :11;
+ unsigned int sign :1;
+#else /* _BYTE_ORDER == _LITTLE_ENDIAN */
+ unsigned int sign :1;
+ unsigned int exp :11;
+ unsigned int manh :20;
+ unsigned int manl :32;
+#endif
+ } bits;
+};
+
+#define mask_nbit_l(u) ((void)0)
+#define LDBL_IMPLICIT_NBIT
+#define LDBL_NBIT 0
+
+#define LDBL_MANH_SIZE 20
+#define LDBL_MANL_SIZE 32
+
+#define LDBL_TO_ARRAY32(u, a) do { \
+ (a)[0] = (uint32_t)(u).bits.manl; \
+ (a)[1] = (uint32_t)(u).bits.manh; \
+} while(0)
diff --git a/lib/libc/powerpc64/arith.h b/lib/libc/powerpc64/arith.h
new file mode 100644
index 000000000000..8e2c9ec597b3
--- /dev/null
+++ b/lib/libc/powerpc64/arith.h
@@ -0,0 +1,16 @@
+/*
+ * MD header for contrib/gdtoa
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * NOTE: The definitions in this file must be correct or strtod(3) and
+ * floating point formats in printf(3) will break! The file can be
+ * generated by running contrib/gdtoa/arithchk.c on the target
+ * architecture. See contrib/gdtoa/gdtoaimp.h for details.
+ */
+
+#define IEEE_MC68k
+#define Arith_Kind_ASL 2
+#define Double_Align
diff --git a/lib/libc/powerpc64/gd_qnan.h b/lib/libc/powerpc64/gd_qnan.h
new file mode 100644
index 000000000000..d70d8c318c4c
--- /dev/null
+++ b/lib/libc/powerpc64/gd_qnan.h
@@ -0,0 +1,21 @@
+/*
+ * MD header for contrib/gdtoa
+ *
+ * This file can be generated by compiling and running contrib/gdtoa/qnan.c
+ * on the target architecture after arith.h has been generated.
+ *
+ * $FreeBSD$
+ */
+
+#define f_QNAN 0x7fc00000
+#define d_QNAN0 0x7ff80000
+#define d_QNAN1 0x0
+#define ld_QNAN0 0x7ff80000
+#define ld_QNAN1 0x0
+#define ld_QNAN2 0x0
+#define ld_QNAN3 0x0
+#define ldus_QNAN0 0x7ff8
+#define ldus_QNAN1 0x0
+#define ldus_QNAN2 0x0
+#define ldus_QNAN3 0x0
+#define ldus_QNAN4 0x0
diff --git a/lib/libc/powerpc64/gen/Makefile.inc b/lib/libc/powerpc64/gen/Makefile.inc
new file mode 100644
index 000000000000..864fb9ede4f4
--- /dev/null
+++ b/lib/libc/powerpc64/gen/Makefile.inc
@@ -0,0 +1,10 @@
+# $FreeBSD$
+
+SRCS += _ctx_start.S fabs.S flt_rounds.c fpgetmask.c fpgetround.c \
+ fpgetsticky.c fpsetmask.c fpsetround.c \
+ infinity.c ldexp.c makecontext.c _setjmp.S \
+ setjmp.S sigsetjmp.S signalcontext.c syncicache.c \
+ _set_tp.c \
+ trivial-getcontextx.c
+
+
diff --git a/lib/libc/powerpc64/gen/_ctx_start.S b/lib/libc/powerpc64/gen/_ctx_start.S
new file mode 100644
index 000000000000..17ec44e739cd
--- /dev/null
+++ b/lib/libc/powerpc64/gen/_ctx_start.S
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2004 Suleiman Souhlal
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+ #include <machine/asm.h>
+
+ __FBSDID("$FreeBSD$");
+
+ .globl CNAME(_ctx_done)
+ .globl CNAME(abort)
+
+ ENTRY(_ctx_start)
+ ld %r2,8(%r14)
+ ld %r14,0(%r14)
+ mtlr %r14
+ blrl /* branch to start function */
+ mr %r3,%r15 /* pass pointer to ucontext as argument */
+ nop
+ bl CNAME(_ctx_done) /* branch to ctxt completion func */
+ /*
+ * we should never return from the
+ * above branch.
+ */
+ nop
+ bl CNAME(abort) /* abort */
+ nop
+ END(_ctx_start)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/powerpc64/gen/_set_tp.c b/lib/libc/powerpc64/gen/_set_tp.c
new file mode 100644
index 000000000000..26009dcf97d0
--- /dev/null
+++ b/lib/libc/powerpc64/gen/_set_tp.c
@@ -0,0 +1,35 @@
+/*-
+ * Copyright (c) 2004 Doug Rabson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include "libc_private.h"
+
+void
+_set_tp(void *tpval)
+{
+
+ __asm __volatile("mr 13,%0" :: "r"((char*)tpval + 0x7010));
+}
diff --git a/lib/libc/powerpc64/gen/_setjmp.S b/lib/libc/powerpc64/gen/_setjmp.S
new file mode 100644
index 000000000000..f7689aeba350
--- /dev/null
+++ b/lib/libc/powerpc64/gen/_setjmp.S
@@ -0,0 +1,155 @@
+/*-
+ * Copyright (c) 2002 Peter Grehan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/* $NetBSD: _setjmp.S,v 1.1 1997/03/29 20:55:53 thorpej Exp $ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * C library -- _setjmp, _longjmp
+ *
+ * _longjmp(a,v)
+ * will generate a "return(v?v:1)" from the last call to
+ * _setjmp(a)
+ * by restoring registers from the stack.
+ * The previous signal state is NOT restored.
+ *
+ * jmpbuf layout:
+ * +------------+
+ * | unused |
+ * +------------+
+ * | unused |
+ * | |
+ * | (4 words) |
+ * | |
+ * +------------+
+ * | saved regs |
+ * | ... |
+ */
+
+ENTRY(_setjmp)
+ mflr %r11
+ mfcr %r12
+ mr %r10,%r1
+ mr %r9,%r2
+ std %r9,40 + 0*8(%r3)
+ stfd %f14,40 + 23*8(%r3)
+ std %r10,40 + 1*8(%r3)
+ stfd %f15,40 + 24*8(%r3)
+ std %r11,40 + 2*8(%r3)
+ stfd %f16,40 + 25*8(%r3)
+ std %r12,40 + 3*8(%r3)
+ stfd %f17,40 + 26*8(%r3)
+ std %r13,40 + 4*8(%r3)
+ stfd %f18,40 + 27*8(%r3)
+ std %r14,40 + 5*8(%r3)
+ stfd %f19,40 + 28*8(%r3)
+ std %r15,40 + 6*8(%r3)
+ stfd %f20,40 + 29*8(%r3)
+ std %r16,40 + 7*8(%r3)
+ stfd %f21,40 + 30*8(%r3)
+ std %r17,40 + 8*8(%r3)
+ stfd %f22,40 + 31*8(%r3)
+ std %r18,40 + 9*8(%r3)
+ stfd %f23,40 + 32*8(%r3)
+ std %r19,40 + 10*8(%r3)
+ stfd %f24,40 + 33*8(%r3)
+ std %r20,40 + 11*8(%r3)
+ stfd %f25,40 + 34*8(%r3)
+ std %r21,40 + 12*8(%r3)
+ stfd %f26,40 + 35*8(%r3)
+ std %r22,40 + 13*8(%r3)
+ stfd %f27,40 + 36*8(%r3)
+ std %r23,40 + 14*8(%r3)
+ stfd %f28,40 + 37*8(%r3)
+ std %r24,40 + 15*8(%r3)
+ stfd %f29,40 + 38*8(%r3)
+ std %r25,40 + 16*8(%r3)
+ stfd %f30,40 + 39*8(%r3)
+ std %r26,40 + 17*8(%r3)
+ stfd %f31,40 + 40*8(%r3)
+ std %r27,40 + 18*8(%r3)
+ std %r28,40 + 19*8(%r3)
+ std %r29,40 + 20*8(%r3)
+ std %r30,40 + 21*8(%r3)
+ std %r31,40 + 22*8(%r3)
+ li %r3,0
+ blr
+END(_setjmp)
+
+ENTRY(_longjmp)
+ ld %r9,40 + 0*8(%r3)
+ lfd %f14,40 + 23*8(%r3)
+ ld %r10,40 + 1*8(%r3)
+ lfd %f15,40 + 24*8(%r3)
+ ld %r11,40 + 2*8(%r3)
+ lfd %f16,40 + 25*8(%r3)
+ ld %r12,40 + 3*8(%r3)
+ lfd %f17,40 + 26*8(%r3)
+ ld %r14,40 + 5*8(%r3)
+ lfd %f18,40 + 27*8(%r3)
+ ld %r15,40 + 6*8(%r3)
+ lfd %f19,40 + 28*8(%r3)
+ ld %r16,40 + 7*8(%r3)
+ lfd %f20,40 + 29*8(%r3)
+ ld %r17,40 + 8*8(%r3)
+ lfd %f21,40 + 30*8(%r3)
+ ld %r18,40 + 9*8(%r3)
+ lfd %f22,40 + 31*8(%r3)
+ ld %r19,40 + 10*8(%r3)
+ lfd %f23,40 + 32*8(%r3)
+ ld %r20,40 + 11*8(%r3)
+ lfd %f24,40 + 33*8(%r3)
+ ld %r21,40 + 12*8(%r3)
+ lfd %f25,40 + 34*8(%r3)
+ ld %r22,40 + 13*8(%r3)
+ lfd %f26,40 + 35*8(%r3)
+ ld %r23,40 + 14*8(%r3)
+ lfd %f27,40 + 36*8(%r3)
+ ld %r24,40 + 15*8(%r3)
+ lfd %f28,40 + 37*8(%r3)
+ ld %r25,40 + 16*8(%r3)
+ lfd %f29,40 + 38*8(%r3)
+ ld %r26,40 + 17*8(%r3)
+ lfd %f30,40 + 39*8(%r3)
+ ld %r27,40 + 18*8(%r3)
+ lfd %f31,40 + 40*8(%r3)
+ ld %r28,40 + 19*8(%r3)
+ ld %r29,40 + 20*8(%r3)
+ ld %r30,40 + 21*8(%r3)
+ ld %r31,40 + 22*8(%r3)
+
+ mtlr %r11
+ mtcr %r12
+ mr %r2,%r9
+ mr %r1,%r10
+ or. %r3,%r4,%r4
+ 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
new file mode 100644
index 000000000000..ac083ae636ac
--- /dev/null
+++ b/lib/libc/powerpc64/gen/fabs.S
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2004 Peter Grehan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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$");
+
+/*
+ * double fabs(double)
+ */
+ENTRY(fabs)
+ fabs %f1,%f1
+ blr
+END(fabs)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/powerpc64/gen/flt_rounds.c b/lib/libc/powerpc64/gen/flt_rounds.c
new file mode 100644
index 000000000000..6294be72422e
--- /dev/null
+++ b/lib/libc/powerpc64/gen/flt_rounds.c
@@ -0,0 +1,56 @@
+/* $NetBSD: flt_rounds.c,v 1.4.10.3 2002/03/22 20:41:53 nathanw Exp $ */
+
+/*
+ * Copyright (c) 1996 Mark Brinicombe
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Mark Brinicombe
+ * for the NetBSD Project.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <machine/float.h>
+
+#ifndef _SOFT_FLOAT
+static const int map[] = {
+ 1, /* round to nearest */
+ 0, /* round to zero */
+ 2, /* round to positive infinity */
+ 3 /* round to negative infinity */
+};
+
+int
+__flt_rounds()
+{
+ uint64_t fpscr;
+
+ __asm__ __volatile("mffs %0" : "=f"(fpscr));
+ return map[(fpscr & 0x03)];
+}
+#endif
diff --git a/lib/libc/powerpc64/gen/fpgetmask.c b/lib/libc/powerpc64/gen/fpgetmask.c
new file mode 100644
index 000000000000..b67b1bcb4dc0
--- /dev/null
+++ b/lib/libc/powerpc64/gen/fpgetmask.c
@@ -0,0 +1,48 @@
+/* $NetBSD: fpgetmask.c,v 1.3 2002/01/13 21:45:47 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Dan Winship.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <ieeefp.h>
+
+#ifndef _SOFT_FLOAT
+fp_except_t
+fpgetmask()
+{
+ u_int64_t fpscr;
+
+ __asm__("mffs %0" : "=f"(fpscr));
+ return ((fp_except_t)((fpscr >> 3) & 0x1f));
+}
+#endif
diff --git a/lib/libc/powerpc64/gen/fpgetround.c b/lib/libc/powerpc64/gen/fpgetround.c
new file mode 100644
index 000000000000..097e82aa9a41
--- /dev/null
+++ b/lib/libc/powerpc64/gen/fpgetround.c
@@ -0,0 +1,48 @@
+/* $NetBSD: fpgetround.c,v 1.3 2002/01/13 21:45:47 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Dan Winship.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <ieeefp.h>
+
+#ifndef _SOFT_FLOAT
+fp_rnd_t
+fpgetround()
+{
+ u_int64_t fpscr;
+
+ __asm__("mffs %0" : "=f"(fpscr));
+ return ((fp_rnd_t)(fpscr & 0x3));
+}
+#endif
diff --git a/lib/libc/powerpc64/gen/fpgetsticky.c b/lib/libc/powerpc64/gen/fpgetsticky.c
new file mode 100644
index 000000000000..57152ac50104
--- /dev/null
+++ b/lib/libc/powerpc64/gen/fpgetsticky.c
@@ -0,0 +1,54 @@
+/* $NetBSD: fpgetsticky.c,v 1.3 2002/01/13 21:45:48 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Dan Winship.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/cdefs.h>
+
+#include "namespace.h"
+
+#include <sys/types.h>
+#include <ieeefp.h>
+
+#ifndef _SOFT_FLOAT
+#ifdef __weak_alias
+__weak_alias(fpgetsticky,_fpgetsticky)
+#endif
+
+fp_except_t
+fpgetsticky()
+{
+ u_int64_t fpscr;
+
+ __asm__ __volatile("mffs %0" : "=f"(fpscr));
+ return ((fp_except_t)((fpscr >> 25) & 0x1f));
+}
+#endif
diff --git a/lib/libc/powerpc64/gen/fpsetmask.c b/lib/libc/powerpc64/gen/fpsetmask.c
new file mode 100644
index 000000000000..81cd19e57f1b
--- /dev/null
+++ b/lib/libc/powerpc64/gen/fpsetmask.c
@@ -0,0 +1,52 @@
+/* $NetBSD: fpsetmask.c,v 1.3 2002/01/13 21:45:48 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Dan Winship.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <ieeefp.h>
+
+#ifndef _SOFT_FLOAT
+fp_except_t
+fpsetmask(fp_except_t mask)
+{
+ u_int64_t fpscr;
+ fp_rnd_t old;
+
+ __asm__("mffs %0" : "=f"(fpscr));
+ old = (fp_rnd_t)((fpscr >> 3) & 0x1f);
+ fpscr = (fpscr & 0xffffff07) | (mask << 3);
+ __asm__ __volatile("mtfsf 0xff,%0" :: "f"(fpscr));
+ return (old);
+}
+#endif
diff --git a/lib/libc/powerpc64/gen/fpsetround.c b/lib/libc/powerpc64/gen/fpsetround.c
new file mode 100644
index 000000000000..17f70a0cab64
--- /dev/null
+++ b/lib/libc/powerpc64/gen/fpsetround.c
@@ -0,0 +1,52 @@
+/* $NetBSD: fpsetround.c,v 1.3 2002/01/13 21:45:48 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Dan Winship.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <ieeefp.h>
+
+#ifndef _SOFT_FLOAT
+fp_rnd_t
+fpsetround(fp_rnd_t rnd_dir)
+{
+ u_int64_t fpscr;
+ fp_rnd_t old;
+
+ __asm__ __volatile("mffs %0" : "=f"(fpscr));
+ old = (fp_rnd_t)(fpscr & 0x3);
+ fpscr = (fpscr & 0xfffffffc) | rnd_dir;
+ __asm__ __volatile("mtfsf 0xff,%0" :: "f"(fpscr));
+ return (old);
+}
+#endif
diff --git a/lib/libc/powerpc64/gen/infinity.c b/lib/libc/powerpc64/gen/infinity.c
new file mode 100644
index 000000000000..f5324389d5b6
--- /dev/null
+++ b/lib/libc/powerpc64/gen/infinity.c
@@ -0,0 +1,30 @@
+#include <sys/cdefs.h>
+#if 0
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: infinity.c,v 1.2 1998/11/14 19:31:02 christos Exp $");
+#endif /* LIBC_SCCS and not lint */
+#endif
+__FBSDID("$FreeBSD$");
+
+/* infinity.c */
+
+#include <math.h>
+
+/* bytes for +Infinity on powerpc */
+const union __infinity_un __infinity = {
+#if BYTE_ORDER == BIG_ENDIAN
+ { 0x7f, 0xf0, 0, 0, 0, 0, 0, 0 }
+#else
+ { 0, 0, 0, 0, 0, 0, 0xf0, 0x7f }
+#endif
+};
+
+/* bytes for NaN */
+const union __nan_un __nan = {
+#if BYTE_ORDER == BIG_ENDIAN
+ {0xff, 0xc0, 0, 0}
+#else
+ { 0, 0, 0xc0, 0xff }
+#endif
+};
+
diff --git a/lib/libc/powerpc64/gen/makecontext.c b/lib/libc/powerpc64/gen/makecontext.c
new file mode 100644
index 000000000000..b01c5c1c40a7
--- /dev/null
+++ b/lib/libc/powerpc64/gen/makecontext.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2004 Suleiman Souhlal
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <ucontext.h>
+
+__weak_reference(__makecontext, makecontext);
+
+void _ctx_done(ucontext_t *ucp);
+void _ctx_start(void);
+
+void
+_ctx_done(ucontext_t *ucp)
+{
+ if (ucp->uc_link == NULL)
+ exit(0);
+ else {
+ /* invalidate context */
+ ucp->uc_mcontext.mc_len = 0;
+
+ setcontext((const ucontext_t *)ucp->uc_link);
+
+ abort(); /* should never return from above call */
+ }
+}
+
+void
+__makecontext(ucontext_t *ucp, void (*start)(void), int argc, ...)
+{
+ mcontext_t *mc;
+ char *sp;
+ va_list ap;
+ int i, regargs, stackargs;
+
+ /* Sanity checks */
+ if ((ucp == NULL) || (argc < 0) || (argc > NCARGS)
+ || (ucp->uc_stack.ss_sp == NULL)
+ || (ucp->uc_stack.ss_size < MINSIGSTKSZ)) {
+ /* invalidate context */
+ ucp->uc_mcontext.mc_len = 0;
+ return;
+ }
+
+ /*
+ * The stack must have space for the frame pointer, saved
+ * link register, overflow arguments, and be 16-byte
+ * aligned.
+ */
+ stackargs = (argc > 8) ? argc - 8 : 0;
+ sp = (char *) ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size
+ - sizeof(uintptr_t)*(stackargs + 2);
+ sp = (char *)((uintptr_t)sp & ~0x1f);
+
+ mc = &ucp->uc_mcontext;
+
+ /*
+ * Up to 8 register args. Assumes all args are 64-bit and
+ * integer only. Not sure how to cater for floating point.
+ */
+ regargs = (argc > 8) ? 8 : argc;
+ va_start(ap, argc);
+ for (i = 0; i < regargs; i++)
+ mc->mc_gpr[3 + i] = va_arg(ap, uint64_t);
+
+ /*
+ * Overflow args go onto the stack
+ */
+ if (argc > 8) {
+ uint64_t *argp;
+
+ /* Skip past frame pointer and saved LR */
+ argp = (uint64_t *)sp + 6;
+
+ for (i = 0; i < stackargs; i++)
+ *argp++ = va_arg(ap, uint64_t);
+ }
+ va_end(ap);
+
+ /*
+ * Use caller-saved regs 14/15 to hold params that _ctx_start
+ * will use to invoke the user-supplied func
+ */
+ mc->mc_srr0 = *(uintptr_t *)_ctx_start;
+ mc->mc_gpr[1] = (uintptr_t) sp; /* new stack pointer */
+ mc->mc_gpr[14] = (uintptr_t) start; /* r14 <- start */
+ mc->mc_gpr[15] = (uintptr_t) ucp; /* r15 <- ucp */
+}
diff --git a/lib/libc/powerpc64/gen/setjmp.S b/lib/libc/powerpc64/gen/setjmp.S
new file mode 100644
index 000000000000..5eb395e7c30d
--- /dev/null
+++ b/lib/libc/powerpc64/gen/setjmp.S
@@ -0,0 +1,176 @@
+/*-
+ * Copyright (c) 2002 Peter Grehan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/* $NetBSD: setjmp.S,v 1.3 1998/10/03 12:30:38 tsubai Exp $ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/syscall.h>
+
+/*
+ * C library -- setjmp, longjmp
+ *
+ * longjmp(a,v)
+ * will generate a "return(v?v:1)" from the last call to
+ * setjmp(a)
+ * by restoring registers from the stack.
+ * The previous signal state is restored.
+ *
+ * jmpbuf layout:
+ * +------------+
+ * | unused |
+ * +------------+
+ * | sig state |
+ * | |
+ * | (4 words) |
+ * | |
+ * +------------+
+ * | saved regs |
+ * | ... |
+ */
+
+ENTRY(setjmp)
+ mr %r6,%r3
+ li %r3,1 /* SIG_BLOCK, but doesn't matter */
+ /* since set == NULL */
+ li %r4,0 /* set = NULL */
+ mr %r5,%r6 /* &oset */
+ addi %r5,%r5,4
+ li %r0, SYS_sigprocmask /*sigprocmask(SIG_BLOCK, NULL, &oset)*/
+ sc /*assume no error XXX */
+ mflr %r11 /* r11 <- link reg */
+ mfcr %r12 /* r12 <- condition reg */
+ mr %r10,%r1 /* r10 <- stackptr */
+ mr %r9,%r2 /* r9 <- global ptr */
+
+ std %r9,40 + 0*8(%r6)
+ stfd %f14,40 + 23*8(%r6)
+ std %r10,40 + 1*8(%r6)
+ stfd %f15,40 + 24*8(%r6)
+ std %r11,40 + 2*8(%r6)
+ stfd %f16,40 + 25*8(%r6)
+ std %r12,40 + 3*8(%r6)
+ stfd %f17,40 + 26*8(%r6)
+ std %r13,40 + 4*8(%r6)
+ stfd %f18,40 + 27*8(%r6)
+ std %r14,40 + 5*8(%r6)
+ stfd %f19,40 + 28*8(%r6)
+ std %r15,40 + 6*8(%r6)
+ stfd %f20,40 + 29*8(%r6)
+ std %r16,40 + 7*8(%r6)
+ stfd %f21,40 + 30*8(%r6)
+ std %r17,40 + 8*8(%r6)
+ stfd %f22,40 + 31*8(%r6)
+ std %r18,40 + 9*8(%r6)
+ stfd %f23,40 + 32*8(%r6)
+ std %r19,40 + 10*8(%r6)
+ stfd %f24,40 + 33*8(%r6)
+ std %r20,40 + 11*8(%r6)
+ stfd %f25,40 + 34*8(%r6)
+ std %r21,40 + 12*8(%r6)
+ stfd %f26,40 + 35*8(%r6)
+ std %r22,40 + 13*8(%r6)
+ stfd %f27,40 + 36*8(%r6)
+ std %r23,40 + 14*8(%r6)
+ stfd %f28,40 + 37*8(%r6)
+ std %r24,40 + 15*8(%r6)
+ stfd %f29,40 + 38*8(%r6)
+ std %r25,40 + 16*8(%r6)
+ stfd %f30,40 + 39*8(%r6)
+ std %r26,40 + 17*8(%r6)
+ stfd %f31,40 + 40*8(%r6)
+ std %r27,40 + 18*8(%r6)
+ std %r28,40 + 19*8(%r6)
+ std %r29,40 + 20*8(%r6)
+ std %r30,40 + 21*8(%r6)
+ std %r31,40 + 22*8(%r6)
+
+ /* XXX Altivec regs */
+
+ li %r3,0 /* return (0) */
+ blr
+END(setjmp)
+
+ WEAK_REFERENCE(__longjmp, longjmp)
+ENTRY(__longjmp)
+ ld %r9,40 + 0*8(%r3)
+ lfd %f14,40 + 23*8(%r3)
+ ld %r10,40 + 1*8(%r3)
+ lfd %f15,40 + 24*8(%r3)
+ ld %r11,40 + 2*8(%r3)
+ lfd %f16,40 + 25*8(%r3)
+ ld %r12,40 + 3*8(%r3)
+ lfd %f17,40 + 26*8(%r3)
+ ld %r14,40 + 5*8(%r3)
+ lfd %f18,40 + 27*8(%r3)
+ ld %r15,40 + 6*8(%r3)
+ lfd %f19,40 + 28*8(%r3)
+ ld %r16,40 + 7*8(%r3)
+ lfd %f20,40 + 29*8(%r3)
+ ld %r17,40 + 8*8(%r3)
+ lfd %f21,40 + 30*8(%r3)
+ ld %r18,40 + 9*8(%r3)
+ lfd %f22,40 + 31*8(%r3)
+ ld %r19,40 + 10*8(%r3)
+ lfd %f23,40 + 32*8(%r3)
+ ld %r20,40 + 11*8(%r3)
+ lfd %f24,40 + 33*8(%r3)
+ ld %r21,40 + 12*8(%r3)
+ lfd %f25,40 + 34*8(%r3)
+ ld %r22,40 + 13*8(%r3)
+ lfd %f26,40 + 35*8(%r3)
+ ld %r23,40 + 14*8(%r3)
+ lfd %f27,40 + 36*8(%r3)
+ ld %r24,40 + 15*8(%r3)
+ lfd %f28,40 + 37*8(%r3)
+ ld %r25,40 + 16*8(%r3)
+ lfd %f29,40 + 38*8(%r3)
+ ld %r26,40 + 17*8(%r3)
+ lfd %f30,40 + 39*8(%r3)
+ ld %r27,40 + 18*8(%r3)
+ lfd %f31,40 + 40*8(%r3)
+ ld %r28,40 + 19*8(%r3)
+ ld %r29,40 + 20*8(%r3)
+ ld %r30,40 + 21*8(%r3)
+ ld %r31,40 + 22*8(%r3)
+ mr %r6,%r4 /* save val param */
+ mtlr %r11 /* r11 -> link reg */
+ mtcr %r12 /* r12 -> condition reg */
+ mr %r2,%r9 /* r9 -> global ptr */
+ mr %r1,%r10 /* r10 -> stackptr */
+ mr %r4,%r3
+ li %r3,3 /* SIG_SETMASK */
+ addi %r4,%r4,4 /* &set */
+ li %r5,0 /* oset = NULL */
+ li %r0,SYS_sigprocmask /* sigprocmask(SIG_SET, &set, NULL) */
+ sc /* assume no error XXX */
+ or. %r3,%r6,%r6
+ bnelr
+ li %r3,1
+ blr
+END(__longjmp)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/powerpc64/gen/signalcontext.c b/lib/libc/powerpc64/gen/signalcontext.c
new file mode 100644
index 000000000000..fad9ee16cca2
--- /dev/null
+++ b/lib/libc/powerpc64/gen/signalcontext.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2004 Marcel Moolenaar, Peter Grehan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/ucontext.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <strings.h>
+
+typedef void (*handler_t)(uint32_t, uint32_t, uint32_t);
+
+/* Prototypes */
+static void ctx_wrapper(ucontext_t *ucp, handler_t func, uint32_t sig,
+ uint32_t sig_si, uint32_t sig_uc);
+
+__weak_reference(__signalcontext, signalcontext);
+
+int
+__signalcontext(ucontext_t *ucp, int sig, __sighandler_t *func)
+{
+ siginfo_t *sig_si;
+ ucontext_t *sig_uc;
+ uintptr_t sp;
+
+ /* Bail out if we don't have a valid ucontext pointer. */
+ if (ucp == NULL)
+ abort();
+
+ /*
+ * Build a 16-byte-aligned signal frame
+ */
+ sp = (ucp->uc_mcontext.mc_gpr[1] - sizeof(ucontext_t)) & ~15UL;
+ sig_uc = (ucontext_t *)sp;
+ bcopy(ucp, sig_uc, sizeof(*sig_uc));
+ sp = (sp - sizeof(siginfo_t)) & ~15UL;
+ sig_si = (siginfo_t *)sp;
+ bzero(sig_si, sizeof(*sig_si));
+ sig_si->si_signo = sig;
+
+ /*
+ * Subtract 48 bytes from stack to allow for frameptr
+ */
+ sp -= 6*sizeof(uint64_t);
+ sp &= ~15UL;
+
+ /*
+ * Setup the ucontext of the signal handler.
+ */
+ bzero(&ucp->uc_mcontext, sizeof(ucp->uc_mcontext));
+ ucp->uc_link = sig_uc;
+ sigdelset(&ucp->uc_sigmask, sig);
+
+ ucp->uc_mcontext.mc_vers = _MC_VERSION;
+ ucp->uc_mcontext.mc_len = sizeof(struct __mcontext);
+ ucp->uc_mcontext.mc_srr0 = (uint64_t) ctx_wrapper;
+ ucp->uc_mcontext.mc_gpr[1] = (uint64_t) sp;
+ ucp->uc_mcontext.mc_gpr[3] = (uint64_t) func;
+ ucp->uc_mcontext.mc_gpr[4] = (uint64_t) sig;
+ ucp->uc_mcontext.mc_gpr[5] = (uint64_t) sig_si;
+ ucp->uc_mcontext.mc_gpr[6] = (uint64_t) sig_uc;
+
+ return (0);
+}
+
+static void
+ctx_wrapper(ucontext_t *ucp, handler_t func, uint32_t sig, uint32_t sig_si,
+ uint32_t sig_uc)
+{
+
+ (*func)(sig, sig_si, sig_uc);
+ if (ucp->uc_link == NULL)
+ exit(0);
+ setcontext((const ucontext_t *)ucp->uc_link);
+ /* should never get here */
+ abort();
+ /* NOTREACHED */
+}
diff --git a/lib/libc/powerpc64/gen/sigsetjmp.S b/lib/libc/powerpc64/gen/sigsetjmp.S
new file mode 100644
index 000000000000..c0648a632f1e
--- /dev/null
+++ b/lib/libc/powerpc64/gen/sigsetjmp.S
@@ -0,0 +1,183 @@
+/*-
+ * Copyright (c) 2002 Peter Grehan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/* $NetBSD: sigsetjmp.S,v 1.4 1998/10/03 12:30:38 tsubai Exp $ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * C library -- sigsetjmp, siglongjmp
+ *
+ * siglongjmp(a,v)
+ * will generate a "return(v?v:1)" from the last call to
+ * sigsetjmp(a, savemask)
+ * by restoring registers from the stack.
+ * The previous signal state is restored if savemask is non-zero
+ *
+ * jmpbuf layout:
+ * +------------+
+ * | savemask |
+ * +------------+
+ * | sig state |
+ * | |
+ * | (4 words) |
+ * | |
+ * +------------+
+ * | saved regs |
+ * | ... |
+ */
+
+
+#include <sys/syscall.h>
+
+ENTRY(sigsetjmp)
+ mr %r6,%r3
+ stw %r4,0(%r3)
+ or. %r7,%r4,%r4
+ beq 1f
+ li %r3,1 /* SIG_BLOCK, but doesn't matter */
+ /* since set == NULL */
+ li %r4,0 /* set = NULL */
+ mr %r5,%r6 /* &oset */
+ addi %r5,%r5,4
+ li %r0, SYS_sigprocmask /* sigprocmask(SIG_BLOCK, NULL, &oset)*/
+ sc /* assume no error XXX */
+1:
+ mflr %r11
+ mfcr %r12
+ mr %r10,%r1
+ mr %r9,%r2
+
+ std %r9,40 + 0*8(%r6)
+ stfd %f14,40 + 23*8(%r6)
+ std %r10,40 + 1*8(%r6)
+ stfd %f15,40 + 24*8(%r6)
+ std %r11,40 + 2*8(%r6)
+ stfd %f16,40 + 25*8(%r6)
+ std %r12,40 + 3*8(%r6)
+ stfd %f17,40 + 26*8(%r6)
+ std %r13,40 + 4*8(%r6)
+ stfd %f18,40 + 27*8(%r6)
+ std %r14,40 + 5*8(%r6)
+ stfd %f19,40 + 28*8(%r6)
+ std %r15,40 + 6*8(%r6)
+ stfd %f20,40 + 29*8(%r6)
+ std %r16,40 + 7*8(%r6)
+ stfd %f21,40 + 30*8(%r6)
+ std %r17,40 + 8*8(%r6)
+ stfd %f22,40 + 31*8(%r6)
+ std %r18,40 + 9*8(%r6)
+ stfd %f23,40 + 32*8(%r6)
+ std %r19,40 + 10*8(%r6)
+ stfd %f24,40 + 33*8(%r6)
+ std %r20,40 + 11*8(%r6)
+ stfd %f25,40 + 34*8(%r6)
+ std %r21,40 + 12*8(%r6)
+ stfd %f26,40 + 35*8(%r6)
+ std %r22,40 + 13*8(%r6)
+ stfd %f27,40 + 36*8(%r6)
+ std %r23,40 + 14*8(%r6)
+ stfd %f28,40 + 37*8(%r6)
+ std %r24,40 + 15*8(%r6)
+ stfd %f29,40 + 38*8(%r6)
+ std %r25,40 + 16*8(%r6)
+ stfd %f30,40 + 39*8(%r6)
+ std %r26,40 + 17*8(%r6)
+ stfd %f31,40 + 40*8(%r6)
+ std %r27,40 + 18*8(%r6)
+ std %r28,40 + 19*8(%r6)
+ std %r29,40 + 20*8(%r6)
+ std %r30,40 + 21*8(%r6)
+ std %r31,40 + 22*8(%r6)
+
+ li %r3,0
+ blr
+END(sigsetjmp)
+
+ENTRY(siglongjmp)
+ ld %r9,40 + 0*8(%r3)
+ lfd %f14,40 + 23*8(%r3)
+ ld %r10,40 + 1*8(%r3)
+ lfd %f15,40 + 24*8(%r3)
+ ld %r11,40 + 2*8(%r3)
+ lfd %f16,40 + 25*8(%r3)
+ ld %r12,40 + 3*8(%r3)
+ lfd %f17,40 + 26*8(%r3)
+ ld %r14,40 + 5*8(%r3)
+ lfd %f18,40 + 27*8(%r3)
+ ld %r15,40 + 6*8(%r3)
+ lfd %f19,40 + 28*8(%r3)
+ ld %r16,40 + 7*8(%r3)
+ lfd %f20,40 + 29*8(%r3)
+ ld %r17,40 + 8*8(%r3)
+ lfd %f21,40 + 30*8(%r3)
+ ld %r18,40 + 9*8(%r3)
+ lfd %f22,40 + 31*8(%r3)
+ ld %r19,40 + 10*8(%r3)
+ lfd %f23,40 + 32*8(%r3)
+ ld %r20,40 + 11*8(%r3)
+ lfd %f24,40 + 33*8(%r3)
+ ld %r21,40 + 12*8(%r3)
+ lfd %f25,40 + 34*8(%r3)
+ ld %r22,40 + 13*8(%r3)
+ lfd %f26,40 + 35*8(%r3)
+ ld %r23,40 + 14*8(%r3)
+ lfd %f27,40 + 36*8(%r3)
+ ld %r24,40 + 15*8(%r3)
+ lfd %f28,40 + 37*8(%r3)
+ ld %r25,40 + 16*8(%r3)
+ lfd %f29,40 + 38*8(%r3)
+ ld %r26,40 + 17*8(%r3)
+ lfd %f30,40 + 39*8(%r3)
+ ld %r27,40 + 18*8(%r3)
+ lfd %f31,40 + 40*8(%r3)
+ ld %r28,40 + 19*8(%r3)
+ ld %r29,40 + 20*8(%r3)
+ ld %r30,40 + 21*8(%r3)
+ ld %r31,40 + 22*8(%r3)
+
+ lwz %r7,0(%r3)
+ mr %r6,%r4
+ mtlr %r11
+ mtcr %r12
+ mr %r2,%r9
+ mr %r1,%r10
+ or. %r7,%r7,%r7
+ beq 1f
+ mr %r4,%r3
+ li %r3,3 /* SIG_SETMASK */
+ addi %r4,%r4,4 /* &set */
+ li %r5,0 /* oset = NULL */
+ li %r0,SYS_sigprocmask /* sigprocmask(SIG_SET, &set, NULL) */
+ sc /* assume no error XXX */
+1:
+ or. %r3,%r6,%r6
+ bnelr
+ li %r3,1
+ blr
+END(siglongjmp)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/powerpc64/gen/syncicache.c b/lib/libc/powerpc64/gen/syncicache.c
new file mode 100644
index 000000000000..f9cc8bcde8a0
--- /dev/null
+++ b/lib/libc/powerpc64/gen/syncicache.c
@@ -0,0 +1,103 @@
+/*-
+ * Copyright (C) 1995-1997, 1999 Wolfgang Solfrank.
+ * Copyright (C) 1995-1997, 1999 TooLs GmbH.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by TooLs GmbH.
+ * 4. The name of TooLs GmbH may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $NetBSD: syncicache.c,v 1.2 1999/05/05 12:36:40 tsubai Exp $
+ */
+
+#ifndef lint
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif /* not lint */
+
+#include <sys/param.h>
+#if defined(_KERNEL) || defined(_STANDALONE)
+#include <sys/time.h>
+#include <sys/proc.h>
+#include <vm/vm.h>
+#endif
+#include <sys/sysctl.h>
+
+#include <machine/cpu.h>
+#include <machine/md_var.h>
+
+#ifdef _STANDALONE
+int cacheline_size = 32;
+#endif
+
+#if !defined(_KERNEL) && !defined(_STANDALONE)
+#include <stdlib.h>
+
+int cacheline_size = 0;
+
+static void getcachelinesize(void);
+
+static void
+getcachelinesize()
+{
+ static int cachemib[] = { CTL_MACHDEP, CPU_CACHELINE };
+ long clen;
+
+ clen = sizeof(cacheline_size);
+
+ if (sysctl(cachemib, nitems(cachemib), &cacheline_size, &clen,
+ NULL, 0) < 0 || !cacheline_size) {
+ abort();
+ }
+}
+#endif
+
+void
+__syncicache(void *from, int len)
+{
+ off_t l, off;
+ char *p;
+
+#if !defined(_KERNEL) && !defined(_STANDALONE)
+ if (!cacheline_size)
+ getcachelinesize();
+#endif
+
+ off = (uintptr_t)from & (cacheline_size - 1);
+ l = len += off;
+ p = (char *)from - off;
+
+ do {
+ __asm __volatile ("dcbst 0,%0" :: "r"(p));
+ p += cacheline_size;
+ } while ((l -= cacheline_size) > 0);
+ __asm __volatile ("sync");
+ p = (char *)from - off;
+ do {
+ __asm __volatile ("icbi 0,%0" :: "r"(p));
+ p += cacheline_size;
+ } while ((len -= cacheline_size) > 0);
+ __asm __volatile ("sync; isync");
+}
+
diff --git a/lib/libc/powerpc64/softfloat/milieu.h b/lib/libc/powerpc64/softfloat/milieu.h
new file mode 100644
index 000000000000..e2e43b150073
--- /dev/null
+++ b/lib/libc/powerpc64/softfloat/milieu.h
@@ -0,0 +1,49 @@
+/* $NetBSD: milieu.h,v 1.1 2000/12/29 20:13:54 bjh21 Exp $ */
+/* $FreeBSD$ */
+
+/*
+===============================================================================
+
+This C header file is part of the SoftFloat IEC/IEEE Floating-point
+Arithmetic Package, Release 2a.
+
+Written by John R. Hauser. This work was made possible in part by the
+International Computer Science Institute, located at Suite 600, 1947 Center
+Street, Berkeley, California 94704. Funding was partially provided by the
+National Science Foundation under grant MIP-9311980. The original version
+of this code was written as part of a project to build a fixed-point vector
+processor in collaboration with the University of California at Berkeley,
+overseen by Profs. Nelson Morgan and John Wawrzynek. More information
+is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
+arithmetic/SoftFloat.html'.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
+has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
+TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
+PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
+AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
+
+Derivative works are acceptable, even for commercial purposes, so long as
+(1) they include prominent notice that the work is derivative, and (2) they
+include prominent notice akin to these four paragraphs for those parts of
+this code that are retained.
+
+===============================================================================
+*/
+
+/*
+-------------------------------------------------------------------------------
+Include common integer types and flags.
+-------------------------------------------------------------------------------
+*/
+#include "powerpc-gcc.h"
+
+/*
+-------------------------------------------------------------------------------
+Symbolic Boolean literals.
+-------------------------------------------------------------------------------
+*/
+enum {
+ FALSE = 0,
+ TRUE = 1
+};
diff --git a/lib/libc/powerpc64/softfloat/powerpc-gcc.h b/lib/libc/powerpc64/softfloat/powerpc-gcc.h
new file mode 100644
index 000000000000..e2f8680dd74e
--- /dev/null
+++ b/lib/libc/powerpc64/softfloat/powerpc-gcc.h
@@ -0,0 +1,92 @@
+/* $NetBSD: arm-gcc.h,v 1.2 2001/02/21 18:09:25 bjh21 Exp $ */
+/* $FreeBSD$ */
+
+/*
+-------------------------------------------------------------------------------
+One of the macros `BIGENDIAN' or `LITTLEENDIAN' must be defined.
+-------------------------------------------------------------------------------
+*/
+#define BIGENDIAN
+
+/*
+-------------------------------------------------------------------------------
+The macro `BITS64' can be defined to indicate that 64-bit integer types are
+supported by the compiler.
+-------------------------------------------------------------------------------
+*/
+#define BITS64
+
+/*
+-------------------------------------------------------------------------------
+Each of the following `typedef's defines the most convenient type that holds
+integers of at least as many bits as specified. For example, `uint8' should
+be the most convenient type that can hold unsigned integers of as many as
+8 bits. The `flag' type must be able to hold either a 0 or 1. For most
+implementations of C, `flag', `uint8', and `int8' should all be `typedef'ed
+to the same as `int'.
+-------------------------------------------------------------------------------
+*/
+typedef int flag;
+typedef unsigned int uint8;
+typedef int int8;
+typedef unsigned int uint16;
+typedef int int16;
+typedef unsigned int uint32;
+typedef signed int int32;
+#ifdef BITS64
+typedef unsigned long long int uint64;
+typedef signed long long int int64;
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Each of the following `typedef's defines a type that holds integers
+of _exactly_ the number of bits specified. For instance, for most
+implementation of C, `bits16' and `sbits16' should be `typedef'ed to
+`unsigned short int' and `signed short int' (or `short int'), respectively.
+-------------------------------------------------------------------------------
+*/
+typedef unsigned char bits8;
+typedef signed char sbits8;
+typedef unsigned short int bits16;
+typedef signed short int sbits16;
+typedef unsigned int bits32;
+typedef signed int sbits32;
+#ifdef BITS64
+typedef unsigned long long int bits64;
+typedef signed long long int sbits64;
+#endif
+
+#ifdef BITS64
+/*
+-------------------------------------------------------------------------------
+The `LIT64' macro takes as its argument a textual integer literal and
+if necessary ``marks'' the literal as having a 64-bit integer type.
+For example, the GNU C Compiler (`gcc') requires that 64-bit literals be
+appended with the letters `LL' standing for `long long', which is `gcc's
+name for the 64-bit integer type. Some compilers may allow `LIT64' to be
+defined as the identity macro: `#define LIT64( a ) a'.
+-------------------------------------------------------------------------------
+*/
+#define LIT64( a ) a##LL
+#endif
+
+/*
+-------------------------------------------------------------------------------
+The macro `INLINE' can be used before functions that should be inlined. If
+a compiler does not support explicit inlining, this macro should be defined
+to be `static'.
+-------------------------------------------------------------------------------
+*/
+#define INLINE static __inline
+
+/*
+-------------------------------------------------------------------------------
+The ARM FPA is odd in that it stores doubles high-order word first, no matter
+what the endianness of the CPU. VFP is sane.
+-------------------------------------------------------------------------------
+*/
+#if defined(SOFTFLOAT_FOR_GCC)
+#define FLOAT64_DEMANGLE(a) (a)
+#define FLOAT64_MANGLE(a) (a)
+#endif
diff --git a/lib/libc/powerpc64/softfloat/softfloat.h b/lib/libc/powerpc64/softfloat/softfloat.h
new file mode 100644
index 000000000000..6b9c9b06956d
--- /dev/null
+++ b/lib/libc/powerpc64/softfloat/softfloat.h
@@ -0,0 +1,307 @@
+/* $NetBSD: softfloat.h,v 1.6 2002/05/12 13:12:46 bjh21 Exp $ */
+/* $FreeBSD$ */
+
+/* This is a derivative work. */
+
+/*
+===============================================================================
+
+This C header file is part of the SoftFloat IEC/IEEE Floating-point
+Arithmetic Package, Release 2a.
+
+Written by John R. Hauser. This work was made possible in part by the
+International Computer Science Institute, located at Suite 600, 1947 Center
+Street, Berkeley, California 94704. Funding was partially provided by the
+National Science Foundation under grant MIP-9311980. The original version
+of this code was written as part of a project to build a fixed-point vector
+processor in collaboration with the University of California at Berkeley,
+overseen by Profs. Nelson Morgan and John Wawrzynek. More information
+is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
+arithmetic/SoftFloat.html'.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
+has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
+TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
+PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
+AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
+
+Derivative works are acceptable, even for commercial purposes, so long as
+(1) they include prominent notice that the work is derivative, and (2) they
+include prominent notice akin to these four paragraphs for those parts of
+this code that are retained.
+
+===============================================================================
+*/
+
+/*
+-------------------------------------------------------------------------------
+The macro `FLOATX80' must be defined to enable the extended double-precision
+floating-point format `floatx80'. If this macro is not defined, the
+`floatx80' type will not be defined, and none of the functions that either
+input or output the `floatx80' type will be defined. The same applies to
+the `FLOAT128' macro and the quadruple-precision format `float128'.
+-------------------------------------------------------------------------------
+*/
+/* #define FLOATX80 */
+/* #define FLOAT128 */
+
+#include <machine/ieeefp.h>
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE floating-point types.
+-------------------------------------------------------------------------------
+*/
+typedef unsigned int float32;
+typedef unsigned long long float64;
+#ifdef FLOATX80
+typedef struct {
+ unsigned short high;
+ unsigned long long low;
+} floatx80;
+#endif
+#ifdef FLOAT128
+typedef struct {
+ unsigned long long high, low;
+} float128;
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE floating-point underflow tininess-detection mode.
+-------------------------------------------------------------------------------
+*/
+#ifndef SOFTFLOAT_FOR_GCC
+extern int8 float_detect_tininess;
+#endif
+enum {
+ float_tininess_after_rounding = 0,
+ float_tininess_before_rounding = 1
+};
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE floating-point rounding mode.
+-------------------------------------------------------------------------------
+*/
+extern fp_rnd_t float_rounding_mode;
+enum {
+ float_round_nearest_even = FP_RN,
+ float_round_to_zero = FP_RZ,
+ float_round_down = FP_RM,
+ float_round_up = FP_RP
+};
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE floating-point exception flags.
+-------------------------------------------------------------------------------
+*/
+typedef fp_except_t fp_except;
+
+extern fp_except float_exception_flags;
+extern fp_except float_exception_mask;
+enum {
+ float_flag_inexact = FP_X_IMP,
+ float_flag_underflow = FP_X_UFL,
+ float_flag_overflow = FP_X_OFL,
+ float_flag_divbyzero = FP_X_DZ,
+ float_flag_invalid = FP_X_INV
+};
+
+/*
+-------------------------------------------------------------------------------
+Routine to raise any or all of the software IEC/IEEE floating-point
+exception flags.
+-------------------------------------------------------------------------------
+*/
+void float_raise( fp_except );
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE integer-to-floating-point conversion routines.
+-------------------------------------------------------------------------------
+*/
+float32 int32_to_float32( int );
+float64 int32_to_float64( int );
+#ifdef FLOATX80
+floatx80 int32_to_floatx80( int );
+#endif
+#ifdef FLOAT128
+float128 int32_to_float128( int );
+#endif
+float32 int64_to_float32( long long );
+float64 int64_to_float64( long long );
+#ifdef FLOATX80
+floatx80 int64_to_floatx80( long long );
+#endif
+#ifdef FLOAT128
+float128 int64_to_float128( long long );
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE single-precision conversion routines.
+-------------------------------------------------------------------------------
+*/
+int float32_to_int32( float32 );
+int float32_to_int32_round_to_zero( float32 );
+unsigned int float32_to_uint32_round_to_zero( float32 );
+long long float32_to_int64( float32 );
+long long float32_to_int64_round_to_zero( float32 );
+float64 float32_to_float64( float32 );
+#ifdef FLOATX80
+floatx80 float32_to_floatx80( float32 );
+#endif
+#ifdef FLOAT128
+float128 float32_to_float128( float32 );
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE single-precision operations.
+-------------------------------------------------------------------------------
+*/
+float32 float32_round_to_int( float32 );
+float32 float32_add( float32, float32 );
+float32 float32_sub( float32, float32 );
+float32 float32_mul( float32, float32 );
+float32 float32_div( float32, float32 );
+float32 float32_rem( float32, float32 );
+float32 float32_sqrt( float32 );
+int float32_eq( float32, float32 );
+int float32_le( float32, float32 );
+int float32_lt( float32, float32 );
+int float32_eq_signaling( float32, float32 );
+int float32_le_quiet( float32, float32 );
+int float32_lt_quiet( float32, float32 );
+#ifndef SOFTFLOAT_FOR_GCC
+int float32_is_signaling_nan( float32 );
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE double-precision conversion routines.
+-------------------------------------------------------------------------------
+*/
+int float64_to_int32( float64 );
+int float64_to_int32_round_to_zero( float64 );
+unsigned int float64_to_uint32_round_to_zero( float64 );
+long long float64_to_int64( float64 );
+long long float64_to_int64_round_to_zero( float64 );
+float32 float64_to_float32( float64 );
+#ifdef FLOATX80
+floatx80 float64_to_floatx80( float64 );
+#endif
+#ifdef FLOAT128
+float128 float64_to_float128( float64 );
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE double-precision operations.
+-------------------------------------------------------------------------------
+*/
+float64 float64_round_to_int( float64 );
+float64 float64_add( float64, float64 );
+float64 float64_sub( float64, float64 );
+float64 float64_mul( float64, float64 );
+float64 float64_div( float64, float64 );
+float64 float64_rem( float64, float64 );
+float64 float64_sqrt( float64 );
+int float64_eq( float64, float64 );
+int float64_le( float64, float64 );
+int float64_lt( float64, float64 );
+int float64_eq_signaling( float64, float64 );
+int float64_le_quiet( float64, float64 );
+int float64_lt_quiet( float64, float64 );
+#ifndef SOFTFLOAT_FOR_GCC
+int float64_is_signaling_nan( float64 );
+#endif
+
+#ifdef FLOATX80
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE extended double-precision conversion routines.
+-------------------------------------------------------------------------------
+*/
+int floatx80_to_int32( floatx80 );
+int floatx80_to_int32_round_to_zero( floatx80 );
+long long floatx80_to_int64( floatx80 );
+long long floatx80_to_int64_round_to_zero( floatx80 );
+float32 floatx80_to_float32( floatx80 );
+float64 floatx80_to_float64( floatx80 );
+#ifdef FLOAT128
+float128 floatx80_to_float128( floatx80 );
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE extended double-precision rounding precision. Valid
+values are 32, 64, and 80.
+-------------------------------------------------------------------------------
+*/
+extern int floatx80_rounding_precision;
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE extended double-precision operations.
+-------------------------------------------------------------------------------
+*/
+floatx80 floatx80_round_to_int( floatx80 );
+floatx80 floatx80_add( floatx80, floatx80 );
+floatx80 floatx80_sub( floatx80, floatx80 );
+floatx80 floatx80_mul( floatx80, floatx80 );
+floatx80 floatx80_div( floatx80, floatx80 );
+floatx80 floatx80_rem( floatx80, floatx80 );
+floatx80 floatx80_sqrt( floatx80 );
+int floatx80_eq( floatx80, floatx80 );
+int floatx80_le( floatx80, floatx80 );
+int floatx80_lt( floatx80, floatx80 );
+int floatx80_eq_signaling( floatx80, floatx80 );
+int floatx80_le_quiet( floatx80, floatx80 );
+int floatx80_lt_quiet( floatx80, floatx80 );
+int floatx80_is_signaling_nan( floatx80 );
+
+#endif
+
+#ifdef FLOAT128
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE quadruple-precision conversion routines.
+-------------------------------------------------------------------------------
+*/
+int float128_to_int32( float128 );
+int float128_to_int32_round_to_zero( float128 );
+long long float128_to_int64( float128 );
+long long float128_to_int64_round_to_zero( float128 );
+float32 float128_to_float32( float128 );
+float64 float128_to_float64( float128 );
+#ifdef FLOATX80
+floatx80 float128_to_floatx80( float128 );
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE quadruple-precision operations.
+-------------------------------------------------------------------------------
+*/
+float128 float128_round_to_int( float128 );
+float128 float128_add( float128, float128 );
+float128 float128_sub( float128, float128 );
+float128 float128_mul( float128, float128 );
+float128 float128_div( float128, float128 );
+float128 float128_rem( float128, float128 );
+float128 float128_sqrt( float128 );
+int float128_eq( float128, float128 );
+int float128_le( float128, float128 );
+int float128_lt( float128, float128 );
+int float128_eq_signaling( float128, float128 );
+int float128_le_quiet( float128, float128 );
+int float128_lt_quiet( float128, float128 );
+int float128_is_signaling_nan( float128 );
+
+#endif
+
diff --git a/lib/libc/powerpc64/sys/Makefile.inc b/lib/libc/powerpc64/sys/Makefile.inc
new file mode 100644
index 000000000000..edb469c6fbcf
--- /dev/null
+++ b/lib/libc/powerpc64/sys/Makefile.inc
@@ -0,0 +1,3 @@
+# $FreeBSD$
+
+MDASM+= brk.S cerror.S exect.S sbrk.S setlogin.S
diff --git a/lib/libc/powerpc64/sys/brk.S b/lib/libc/powerpc64/sys/brk.S
new file mode 100644
index 000000000000..cbcecc7abb11
--- /dev/null
+++ b/lib/libc/powerpc64/sys/brk.S
@@ -0,0 +1,74 @@
+/*-
+ * Copyright (c) 2002 Peter Grehan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/* $NetBSD: brk.S,v 1.9 2000/06/26 06:25:43 kleink Exp $ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+ .globl HIDENAME(curbrk)
+ .globl HIDENAME(minbrk)
+ .globl CNAME(_end)
+
+ .data
+ .align 3
+HIDENAME(minbrk):
+ .llong CNAME(_end)
+
+ .text
+
+ENTRY(brk)
+ addis %r6,%r2,HIDENAME(minbrk)@toc@ha
+ ld %r6,HIDENAME(minbrk)@toc@l(%r6)
+ cmpld %r6,%r3 /* if (minbrk <= r3) */
+ bgt 0f
+ mr %r6,%r3 /* r6 = r3 */
+0:
+ mr %r3,%r6 /* new break value */
+ li %r0,SYS_break
+ sc /* assume, that r5 is kept */
+ bso 1f
+
+ /* record new break */
+ addis %r7,%r2,HIDENAME(curbrk)@toc@ha
+ std %r6,HIDENAME(curbrk)@toc@l(%r7)
+
+ blr /* return 0 */
+
+1:
+ mflr %r0
+ std %r0,16(%r1)
+ stdu %r1,-48(%r1)
+ bl HIDENAME(cerror)
+ nop
+ ld %r1,0(%r1)
+ ld %r0,16(%r1)
+ mtlr %r0
+ blr
+END(brk)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/powerpc64/sys/cerror.S b/lib/libc/powerpc64/sys/cerror.S
new file mode 100644
index 000000000000..515d7e541cab
--- /dev/null
+++ b/lib/libc/powerpc64/sys/cerror.S
@@ -0,0 +1,60 @@
+/*-
+ * Copyright (c) 2002 Peter Grehan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/* $NetBSD: cerror.S,v 1.5 2000/01/27 14:58:48 kleink Exp $ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+ .globl HIDENAME(cerror)
+ .globl CNAME(__error)
+
+ /*
+ * The __error() function is thread aware. For non-threaded
+ * programs and the initial threaded in threaded programs,
+ * it returns a pointer to the global errno variable.
+ */
+ENTRY_NOPROF(HIDENAME(cerror))
+ mflr %r0
+ std %r0,16(%r1) /* save lr */
+ stdu %r1,-64(%r1) /* allocate new stack frame */
+ std %r31,48(%r1)
+
+ mr %r31,%r3 /* stash errval in callee-saved register */
+ bl CNAME(__error)
+ nop
+ stw %r31,0(%r3) /* store errval into &errno */
+
+ ld %r31,48(%r1)
+ ld %r1,0(%r1)
+ ld %r0,16(%r1)
+ mtlr %r0
+ li %r3,-1
+ li %r4,-1
+ blr
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/powerpc64/sys/exect.S b/lib/libc/powerpc64/sys/exect.S
new file mode 100644
index 000000000000..b6cda9c90773
--- /dev/null
+++ b/lib/libc/powerpc64/sys/exect.S
@@ -0,0 +1,50 @@
+/*-
+ * Copyright (c) 2002 Peter Grehan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/* $NetBSD: exect.S,v 1.3 1998/05/25 15:28:03 ws Exp $ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+ENTRY(exect)
+ li %r0,SYS_execve
+ sc
+ bso 1f
+ blr
+1:
+ mflr %r0
+ std %r0,16(%r1)
+ stdu %r1,-48(%r1)
+ bl HIDENAME(cerror)
+ nop
+ ld %r1,0(%r1)
+ ld %r0,16(%r1)
+ mtlr %r0
+ blr
+END(exect)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/powerpc64/sys/sbrk.S b/lib/libc/powerpc64/sys/sbrk.S
new file mode 100644
index 000000000000..4e3b57abf458
--- /dev/null
+++ b/lib/libc/powerpc64/sys/sbrk.S
@@ -0,0 +1,69 @@
+/*-
+ * Copyright (c) 2002 Peter Grehan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/* $NetBSD: sbrk.S,v 1.8 2000/06/26 06:25:44 kleink Exp $ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+ .globl HIDENAME(curbrk)
+ .globl CNAME(_end)
+
+ .data
+ .align 3
+HIDENAME(curbrk):
+ .llong CNAME(_end)
+
+ .text
+ENTRY(sbrk)
+ addis %r5,%r2,HIDENAME(curbrk)@toc@ha
+ addi %r5,%r5,HIDENAME(curbrk)@toc@l
+ ld %r6,0(%r5) /* r6 = old break */
+ cmpdi %r3,0 /* sbrk(0) - return curbrk */
+ beq 1f
+ add %r3,%r3,%r6
+ mr %r7,%r3 /* r7 = new break */
+ li %r0,SYS_break
+ sc /* break(new_break) */
+ bso 2f
+ std %r7,0(%r5)
+1:
+ mr %r3,%r6 /* set return value */
+ blr
+2:
+ mflr %r0
+ std %r0,16(%r1)
+ stdu %r1,-48(%r1)
+ bl HIDENAME(cerror)
+ nop
+ ld %r1,0(%r1)
+ ld %r0,16(%r1)
+ mtlr %r0
+ blr
+END(sbrk)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/powerpc64/sys/setlogin.S b/lib/libc/powerpc64/sys/setlogin.S
new file mode 100644
index 000000000000..6183407b3fe7
--- /dev/null
+++ b/lib/libc/powerpc64/sys/setlogin.S
@@ -0,0 +1,41 @@
+/*-
+ * Copyright (c) 2002 Peter Grehan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/* $NetBSD: setlogin.S,v 1.3 1998/11/24 11:14:57 tsubai Exp $ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+ .globl CNAME(_logname_valid) /* in _getlogin() */
+
+SYSCALL(setlogin)
+ addis %r4,%r2,CNAME(_logname_valid)@toc@ha
+ li %r5,0
+ stw %r5,CNAME(_logname_valid)@toc@l(%r4)
+ blr
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/powerpcspe/Makefile.inc b/lib/libc/powerpcspe/Makefile.inc
new file mode 100644
index 000000000000..3a7960ab378c
--- /dev/null
+++ b/lib/libc/powerpcspe/Makefile.inc
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+CFLAGS+= -I${LIBC_SRCTOP}/powerpc
+SRCS+= trivial-vdso_tc.c
+
+# Long double is 64-bits
+MDSRCS+=machdep_ldisd.c
+SYM_MAPS+=${LIBC_SRCTOP}/powerpc/Symbol.map
diff --git a/lib/libc/powerpcspe/gen/Makefile.inc b/lib/libc/powerpcspe/gen/Makefile.inc
new file mode 100644
index 000000000000..f96ad9fb0a6f
--- /dev/null
+++ b/lib/libc/powerpcspe/gen/Makefile.inc
@@ -0,0 +1,7 @@
+# $FreeBSD$
+
+.include "${LIBC_SRCTOP}/powerpc/gen/Makefile.common"
+
+SRCS += fabs.S flt_rounds.c fpgetmask.c fpgetround.c \
+ fpgetsticky.c fpsetmask.c fpsetround.c \
+ _setjmp.S setjmp.S sigsetjmp.S
diff --git a/lib/libc/powerpcspe/gen/_setjmp.S b/lib/libc/powerpcspe/gen/_setjmp.S
new file mode 100644
index 000000000000..0dd28fa2deb4
--- /dev/null
+++ b/lib/libc/powerpcspe/gen/_setjmp.S
@@ -0,0 +1,117 @@
+/*-
+ * Copyright (c) 2016 Justin Hibbits
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/* $NetBSD: _setjmp.S,v 1.1 1997/03/29 20:55:53 thorpej Exp $ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * C library -- _setjmp, _longjmp
+ *
+ * _longjmp(a,v)
+ * will generate a "return(v?v:1)" from the last call to
+ * _setjmp(a)
+ * by restoring registers from the stack.
+ * The previous signal state is NOT restored.
+ *
+ * jmpbuf layout:
+ * +------------+
+ * | unused |
+ * +------------+
+ * | unused |
+ * | |
+ * | (4 words) |
+ * | |
+ * +------------+
+ * | saved regs |
+ * | ... |
+ */
+
+ENTRY(_setjmp)
+ mflr %r11
+ mfcr %r12
+ evstdd %r1,24+0*8(%r3)
+ evstdd %r2,24+1*8(%r3)
+ evstdd %r11,24+2*8(%r3)
+ evstdd %r12,24+3*8(%r3)
+ evstdd %r13,24+4*8(%r3)
+ evstdd %r14,24+5*8(%r3)
+ evstdd %r15,24+6*8(%r3)
+ evstdd %r16,24+7*8(%r3)
+ evstdd %r17,24+8*8(%r3)
+ evstdd %r18,24+9*8(%r3)
+ evstdd %r19,24+10*8(%r3)
+ evstdd %r20,24+11*8(%r3)
+ evstdd %r21,24+12*8(%r3)
+ evstdd %r22,24+13*8(%r3)
+ evstdd %r23,24+14*8(%r3)
+ evstdd %r24,24+15*8(%r3)
+ evstdd %r25,24+16*8(%r3)
+ evstdd %r26,24+17*8(%r3)
+ evstdd %r27,24+18*8(%r3)
+ evstdd %r28,24+19*8(%r3)
+ evstdd %r29,24+20*8(%r3)
+ evstdd %r30,24+21*8(%r3)
+ evstdd %r31,24+22*8(%r3)
+
+ li %r3,0
+ blr
+END(_setjmp)
+
+ENTRY(_longjmp)
+ evldd %r1,24+0*8(%r3)
+ evldd %r2,24+1*8(%r3)
+ evldd %r11,24+2*8(%r3)
+ evldd %r12,24+3*8(%r3)
+ evldd %r13,24+4*8(%r3)
+ evldd %r14,24+5*8(%r3)
+ evldd %r15,24+6*8(%r3)
+ evldd %r16,24+7*8(%r3)
+ evldd %r17,24+8*8(%r3)
+ evldd %r18,24+9*8(%r3)
+ evldd %r19,24+10*8(%r3)
+ evldd %r20,24+11*8(%r3)
+ evldd %r21,24+12*8(%r3)
+ evldd %r22,24+13*8(%r3)
+ evldd %r23,24+14*8(%r3)
+ evldd %r24,24+15*8(%r3)
+ evldd %r25,24+16*8(%r3)
+ evldd %r26,24+17*8(%r3)
+ evldd %r27,24+18*8(%r3)
+ evldd %r28,24+19*8(%r3)
+ evldd %r29,24+20*8(%r3)
+ evldd %r30,24+21*8(%r3)
+ evldd %r31,24+22*8(%r3)
+
+ mtlr %r11
+ mtcr %r12
+ or. %r3,%r4,%r4
+ bnelr
+ li %r3,1
+ blr
+END(_longjmp)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/powerpcspe/gen/fabs.S b/lib/libc/powerpcspe/gen/fabs.S
new file mode 100644
index 000000000000..da806f025394
--- /dev/null
+++ b/lib/libc/powerpcspe/gen/fabs.S
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2016 Justin Hibbits
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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$");
+
+/*
+ * double fabs(double)
+ */
+ENTRY(fabs)
+ efdabs %f1,%f1
+ blr
+END(fabs)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/powerpcspe/gen/flt_rounds.c b/lib/libc/powerpcspe/gen/flt_rounds.c
new file mode 100644
index 000000000000..1334021fb7fa
--- /dev/null
+++ b/lib/libc/powerpcspe/gen/flt_rounds.c
@@ -0,0 +1,57 @@
+/* $NetBSD: flt_rounds.c,v 1.4.10.3 2002/03/22 20:41:53 nathanw Exp $ */
+
+/*
+ * Copyright (c) 2016 Justin Hibbits
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Mark Brinicombe
+ * for the NetBSD Project.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <machine/float.h>
+#include <machine/spr.h>
+
+#ifndef _SOFT_FLOAT
+static const int map[] = {
+ 1, /* round to nearest */
+ 0, /* round to zero */
+ 2, /* round to positive infinity */
+ 3 /* round to negative infinity */
+};
+
+int
+__flt_rounds()
+{
+ uint32_t fpscr;
+
+ __asm__ __volatile("mfspr %0, %1" : "=r"(fpscr) : "K"(SPR_SPEFSCR));
+ return map[(fpscr & 0x03)];
+}
+#endif
diff --git a/lib/libc/powerpcspe/gen/fpgetmask.c b/lib/libc/powerpcspe/gen/fpgetmask.c
new file mode 100644
index 000000000000..3103e05ba41d
--- /dev/null
+++ b/lib/libc/powerpcspe/gen/fpgetmask.c
@@ -0,0 +1,49 @@
+/* $NetBSD: fpgetmask.c,v 1.3 2002/01/13 21:45:47 thorpej Exp $ */
+
+/*
+ * Copyright (c) 2016 Justin Hibbits
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Dan Winship.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <machine/spr.h>
+#include <ieeefp.h>
+
+#ifndef _SOFT_FLOAT
+fp_except_t
+fpgetmask()
+{
+ uint32_t fpscr;
+
+ __asm__ __volatile("mfspr %0, %1" : "=r"(fpscr) : "K"(SPR_SPEFSCR));
+ return ((fp_except_t)((fpscr >> 3) & 0x1f));
+}
+#endif
diff --git a/lib/libc/powerpcspe/gen/fpgetround.c b/lib/libc/powerpcspe/gen/fpgetround.c
new file mode 100644
index 000000000000..7815559f7b5a
--- /dev/null
+++ b/lib/libc/powerpcspe/gen/fpgetround.c
@@ -0,0 +1,49 @@
+/* $NetBSD: fpgetround.c,v 1.3 2002/01/13 21:45:47 thorpej Exp $ */
+
+/*
+ * Copyright (c) 2016 Justin Hibbits
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Dan Winship.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <machine/spr.h>
+#include <ieeefp.h>
+
+#ifndef _SOFT_FLOAT
+fp_rnd_t
+fpgetround()
+{
+ uint32_t fpscr;
+
+ __asm__ __volatile("mfspr %0, %1" : "=r"(fpscr) : "K"(SPR_SPEFSCR));
+ return ((fp_rnd_t)(fpscr & 0x3));
+}
+#endif
diff --git a/lib/libc/powerpcspe/gen/fpgetsticky.c b/lib/libc/powerpcspe/gen/fpgetsticky.c
new file mode 100644
index 000000000000..87962637bc3c
--- /dev/null
+++ b/lib/libc/powerpcspe/gen/fpgetsticky.c
@@ -0,0 +1,55 @@
+/* $NetBSD: fpgetsticky.c,v 1.3 2002/01/13 21:45:48 thorpej Exp $ */
+
+/*
+ * Copyright (c) 2016 Justin Hibbits
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Dan Winship.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/cdefs.h>
+
+#include "namespace.h"
+
+#include <sys/types.h>
+#include <machine/spr.h>
+#include <ieeefp.h>
+
+#ifndef _SOFT_FLOAT
+#ifdef __weak_alias
+__weak_alias(fpgetsticky,_fpgetsticky)
+#endif
+
+fp_except_t
+fpgetsticky()
+{
+ uint32_t fpscr;
+
+ __asm__ __volatile("mfspr %0, %1" : "=r"(fpscr) : "K"(SPR_SPEFSCR));
+ return ((fp_except_t)((fpscr >> 25) & 0x1f));
+}
+#endif
diff --git a/lib/libc/powerpcspe/gen/fpsetmask.c b/lib/libc/powerpcspe/gen/fpsetmask.c
new file mode 100644
index 000000000000..24c0b3828b7f
--- /dev/null
+++ b/lib/libc/powerpcspe/gen/fpsetmask.c
@@ -0,0 +1,53 @@
+/* $NetBSD: fpsetmask.c,v 1.3 2002/01/13 21:45:48 thorpej Exp $ */
+
+/*
+ * Copyright (c) 2016 Justin Hibbits
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Dan Winship.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <machine/spr.h>
+#include <ieeefp.h>
+
+#ifndef _SOFT_FLOAT
+fp_except_t
+fpsetmask(fp_except_t mask)
+{
+ uint32_t fpscr;
+ fp_rnd_t old;
+
+ __asm__ __volatile("mfspr %0, %1" : "=r"(fpscr) : "K"(SPR_SPEFSCR));
+ old = (fp_rnd_t)((fpscr >> 3) & 0x1f);
+ fpscr = (fpscr & 0xffffff07) | (mask << 3);
+ __asm__ __volatile("mtspr %1,%0" :: "r"(fpscr), "K"(SPR_SPEFSCR));
+ return (old);
+}
+#endif
diff --git a/lib/libc/powerpcspe/gen/fpsetround.c b/lib/libc/powerpcspe/gen/fpsetround.c
new file mode 100644
index 000000000000..b5340a6d9ea2
--- /dev/null
+++ b/lib/libc/powerpcspe/gen/fpsetround.c
@@ -0,0 +1,53 @@
+/* $NetBSD: fpsetround.c,v 1.3 2002/01/13 21:45:48 thorpej Exp $ */
+
+/*
+ * Copyright (c) 2016 Justin Hibbits
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Dan Winship.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <machine/spr.h>
+#include <ieeefp.h>
+
+#ifndef _SOFT_FLOAT
+fp_rnd_t
+fpsetround(fp_rnd_t rnd_dir)
+{
+ uint32_t fpscr;
+ fp_rnd_t old;
+
+ __asm__ __volatile("mfspr %0, %1" : "=r"(fpscr) : "K"(SPR_SPEFSCR) );
+ old = (fp_rnd_t)(fpscr & 0x3);
+ fpscr = (fpscr & 0xfffffffc) | rnd_dir;
+ __asm__ __volatile("mtspr %1, %0" :: "r"(fpscr), "K"(SPR_SPEFSCR));
+ return (old);
+}
+#endif
diff --git a/lib/libc/powerpcspe/gen/setjmp.S b/lib/libc/powerpcspe/gen/setjmp.S
new file mode 100644
index 000000000000..7a93b2f883e8
--- /dev/null
+++ b/lib/libc/powerpcspe/gen/setjmp.S
@@ -0,0 +1,138 @@
+/*-
+ * Copyright (c) 2016 Justin Hibbits
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/* $NetBSD: setjmp.S,v 1.3 1998/10/03 12:30:38 tsubai Exp $ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/syscall.h>
+
+/*
+ * C library -- setjmp, longjmp
+ *
+ * longjmp(a,v)
+ * will generate a "return(v?v:1)" from the last call to
+ * setjmp(a)
+ * by restoring registers from the stack.
+ * The previous signal state is restored.
+ *
+ * jmpbuf layout:
+ * +------------+
+ * | unused |
+ * +------------+
+ * | sig state |
+ * | |
+ * | (4 words) |
+ * | |
+ * +------------+
+ * | saved regs |
+ * | ... |
+ */
+
+ENTRY(setjmp)
+ mr %r6,%r3
+ li %r3,1 /* SIG_BLOCK, but doesn't matter */
+ /* since set == NULL */
+ li %r4,0 /* set = NULL */
+ mr %r5,%r6 /* &oset */
+ addi %r5,%r5,4
+ li %r0, SYS_sigprocmask /*sigprocmask(SIG_BLOCK, NULL, &oset)*/
+ sc /*assume no error XXX */
+ mflr %r11 /* r11 <- link reg */
+ mfcr %r12 /* r12 <- condition reg */
+ mr %r10,%r1 /* r10 <- stackptr */
+ mr %r9,%r2 /* r9 <- global ptr */
+ evstdd %r9,24+0*8(%r6)
+ evstdd %r10,24+1*8(%r6)
+ evstdd %r11,24+2*8(%r6)
+ evstdd %r12,24+3*8(%r6)
+ evstdd %r13,24+4*8(%r6)
+ evstdd %r14,24+5*8(%r6)
+ evstdd %r15,24+6*8(%r6)
+ evstdd %r16,24+7*8(%r6)
+ evstdd %r17,24+8*8(%r6)
+ evstdd %r18,24+9*8(%r6)
+ evstdd %r19,24+10*8(%r6)
+ evstdd %r20,24+11*8(%r6)
+ evstdd %r21,24+12*8(%r6)
+ evstdd %r22,24+13*8(%r6)
+ evstdd %r23,24+14*8(%r6)
+ evstdd %r24,24+15*8(%r6)
+ evstdd %r25,24+16*8(%r6)
+ evstdd %r26,24+17*8(%r6)
+ evstdd %r27,24+18*8(%r6)
+ evstdd %r28,24+19*8(%r6)
+ evstdd %r29,24+20*8(%r6)
+ evstdd %r30,24+21*8(%r6)
+ evstdd %r31,24+22*8(%r6)
+
+ li %r3,0 /* return (0) */
+ blr
+END(setjmp)
+
+ WEAK_REFERENCE(CNAME(__longjmp), longjmp)
+ENTRY(__longjmp)
+ evldd %r9,24+0*8(%r3)
+ evldd %r10,24+1*8(%r3)
+ evldd %r11,24+2*8(%r3)
+ evldd %r12,24+3*8(%r3)
+ evldd %r13,24+4*8(%r3)
+ evldd %r14,24+5*8(%r3)
+ evldd %r15,24+6*8(%r3)
+ evldd %r16,24+7*8(%r3)
+ evldd %r17,24+8*8(%r3)
+ evldd %r18,24+9*8(%r3)
+ evldd %r19,24+10*8(%r3)
+ evldd %r20,24+11*8(%r3)
+ evldd %r21,24+12*8(%r3)
+ evldd %r22,24+13*8(%r3)
+ evldd %r23,24+14*8(%r3)
+ evldd %r24,24+15*8(%r3)
+ evldd %r25,24+16*8(%r3)
+ evldd %r26,24+17*8(%r3)
+ evldd %r27,24+18*8(%r3)
+ evldd %r28,24+19*8(%r3)
+ evldd %r29,24+20*8(%r3)
+ evldd %r30,24+21*8(%r3)
+ evldd %r31,24+22*8(%r3)
+
+ mr %r6,%r4 /* save val param */
+ mtlr %r11 /* r11 -> link reg */
+ mtcr %r12 /* r12 -> condition reg */
+ mr %r1,%r10 /* r10 -> stackptr */
+ mr %r4,%r3
+ li %r3,3 /* SIG_SETMASK */
+ addi %r4,%r4,4 /* &set */
+ li %r5,0 /* oset = NULL */
+ li %r0,SYS_sigprocmask /* sigprocmask(SIG_SET, &set, NULL) */
+ sc /* assume no error XXX */
+ or. %r3,%r6,%r6
+ bnelr
+ li %r3,1
+ blr
+END(__longjmp)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/powerpcspe/gen/sigsetjmp.S b/lib/libc/powerpcspe/gen/sigsetjmp.S
new file mode 100644
index 000000000000..0c12cc3f582b
--- /dev/null
+++ b/lib/libc/powerpcspe/gen/sigsetjmp.S
@@ -0,0 +1,150 @@
+/*-
+ * Copyright (c) 2016 Justin Hibbits
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/* $NetBSD: sigsetjmp.S,v 1.4 1998/10/03 12:30:38 tsubai Exp $ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * C library -- sigsetjmp, siglongjmp
+ *
+ * siglongjmp(a,v)
+ * will generate a "return(v?v:1)" from the last call to
+ * sigsetjmp(a, savemask)
+ * by restoring registers from the stack.
+ * The previous signal state is restored if savemask is non-zero
+ *
+ * jmpbuf layout:
+ * +------------+
+ * | savemask |
+ * +------------+
+ * | sig state |
+ * | |
+ * | (4 words) |
+ * | |
+ * +------------+
+ * | saved regs |
+ * | ... |
+ */
+
+
+#include <sys/syscall.h>
+
+ENTRY(sigsetjmp)
+ mr %r6,%r3
+ stw %r4,0(%r3)
+ or. %r7,%r4,%r4
+ beq 1f
+ li %r3,1 /* SIG_BLOCK, but doesn't matter */
+ /* since set == NULL */
+ li %r4,0 /* set = NULL */
+ mr %r5,%r6 /* &oset */
+ addi %r5,%r5,4
+ li %r0, SYS_sigprocmask /* sigprocmask(SIG_BLOCK, NULL, &oset)*/
+ sc /* assume no error XXX */
+1:
+ mflr %r11
+ mfcr %r12
+ mr %r10,%r1
+ mr %r9,%r2
+
+ /* FPRs */
+ evstdd %r9,24+0*8(%r6)
+ evstdd %r10,24+1*8(%r6)
+ evstdd %r11,24+2*8(%r6)
+ evstdd %r12,24+3*8(%r6)
+ evstdd %r13,24+4*8(%r6)
+ evstdd %r14,24+5*8(%r6)
+ evstdd %r15,24+6*8(%r6)
+ evstdd %r16,24+7*8(%r6)
+ evstdd %r17,24+8*8(%r6)
+ evstdd %r18,24+9*8(%r6)
+ evstdd %r19,24+10*8(%r6)
+ evstdd %r20,24+11*8(%r6)
+ evstdd %r21,24+12*8(%r6)
+ evstdd %r22,24+13*8(%r6)
+ evstdd %r23,24+14*8(%r6)
+ evstdd %r24,24+15*8(%r6)
+ evstdd %r25,24+16*8(%r6)
+ evstdd %r26,24+17*8(%r6)
+ evstdd %r27,24+18*8(%r6)
+ evstdd %r28,24+19*8(%r6)
+ evstdd %r29,24+20*8(%r6)
+ evstdd %r30,24+21*8(%r6)
+ evstdd %r31,24+22*8(%r6)
+
+ li %r3,0
+ blr
+END(sigsetjmp)
+
+ENTRY(siglongjmp)
+
+ /* FPRs */
+ evldd %r9,24+0*8(%r3)
+ evldd %r10,24+1*8(%r3)
+ evldd %r11,24+2*8(%r3)
+ evldd %r12,24+3*8(%r3)
+ evldd %r13,24+4*8(%r3)
+ evldd %r14,24+5*8(%r3)
+ evldd %r15,24+6*8(%r3)
+ evldd %r16,24+7*8(%r3)
+ evldd %r17,24+8*8(%r3)
+ evldd %r18,24+9*8(%r3)
+ evldd %r19,24+10*8(%r3)
+ evldd %r20,24+11*8(%r3)
+ evldd %r21,24+12*8(%r3)
+ evldd %r22,24+13*8(%r3)
+ evldd %r23,24+14*8(%r3)
+ evldd %r24,24+15*8(%r3)
+ evldd %r25,24+16*8(%r3)
+ evldd %r26,24+17*8(%r3)
+ evldd %r27,24+18*8(%r3)
+ evldd %r28,24+19*8(%r3)
+ evldd %r29,24+20*8(%r3)
+ evldd %r30,24+21*8(%r3)
+ evldd %r31,24+22*8(%r3)
+
+ lwz %r7,0(%r3)
+ mr %r6,%r4
+ mtlr %r11
+ mtcr %r12
+ mr %r1,%r10
+ or. %r7,%r7,%r7
+ beq 1f
+ mr %r4,%r3
+ li %r3,3 /* SIG_SETMASK */
+ addi %r4,%r4,4 /* &set */
+ li %r5,0 /* oset = NULL */
+ li %r0,SYS_sigprocmask /* sigprocmask(SIG_SET, &set, NULL) */
+ sc /* assume no error XXX */
+1:
+ or. %r3,%r6,%r6
+ bnelr
+ li %r3,1
+ blr
+END(siglongjmp)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/powerpcspe/softfloat/milieu.h b/lib/libc/powerpcspe/softfloat/milieu.h
new file mode 100644
index 000000000000..e2e43b150073
--- /dev/null
+++ b/lib/libc/powerpcspe/softfloat/milieu.h
@@ -0,0 +1,49 @@
+/* $NetBSD: milieu.h,v 1.1 2000/12/29 20:13:54 bjh21 Exp $ */
+/* $FreeBSD$ */
+
+/*
+===============================================================================
+
+This C header file is part of the SoftFloat IEC/IEEE Floating-point
+Arithmetic Package, Release 2a.
+
+Written by John R. Hauser. This work was made possible in part by the
+International Computer Science Institute, located at Suite 600, 1947 Center
+Street, Berkeley, California 94704. Funding was partially provided by the
+National Science Foundation under grant MIP-9311980. The original version
+of this code was written as part of a project to build a fixed-point vector
+processor in collaboration with the University of California at Berkeley,
+overseen by Profs. Nelson Morgan and John Wawrzynek. More information
+is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
+arithmetic/SoftFloat.html'.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
+has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
+TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
+PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
+AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
+
+Derivative works are acceptable, even for commercial purposes, so long as
+(1) they include prominent notice that the work is derivative, and (2) they
+include prominent notice akin to these four paragraphs for those parts of
+this code that are retained.
+
+===============================================================================
+*/
+
+/*
+-------------------------------------------------------------------------------
+Include common integer types and flags.
+-------------------------------------------------------------------------------
+*/
+#include "powerpc-gcc.h"
+
+/*
+-------------------------------------------------------------------------------
+Symbolic Boolean literals.
+-------------------------------------------------------------------------------
+*/
+enum {
+ FALSE = 0,
+ TRUE = 1
+};
diff --git a/lib/libc/powerpcspe/softfloat/powerpc-gcc.h b/lib/libc/powerpcspe/softfloat/powerpc-gcc.h
new file mode 100644
index 000000000000..e2f8680dd74e
--- /dev/null
+++ b/lib/libc/powerpcspe/softfloat/powerpc-gcc.h
@@ -0,0 +1,92 @@
+/* $NetBSD: arm-gcc.h,v 1.2 2001/02/21 18:09:25 bjh21 Exp $ */
+/* $FreeBSD$ */
+
+/*
+-------------------------------------------------------------------------------
+One of the macros `BIGENDIAN' or `LITTLEENDIAN' must be defined.
+-------------------------------------------------------------------------------
+*/
+#define BIGENDIAN
+
+/*
+-------------------------------------------------------------------------------
+The macro `BITS64' can be defined to indicate that 64-bit integer types are
+supported by the compiler.
+-------------------------------------------------------------------------------
+*/
+#define BITS64
+
+/*
+-------------------------------------------------------------------------------
+Each of the following `typedef's defines the most convenient type that holds
+integers of at least as many bits as specified. For example, `uint8' should
+be the most convenient type that can hold unsigned integers of as many as
+8 bits. The `flag' type must be able to hold either a 0 or 1. For most
+implementations of C, `flag', `uint8', and `int8' should all be `typedef'ed
+to the same as `int'.
+-------------------------------------------------------------------------------
+*/
+typedef int flag;
+typedef unsigned int uint8;
+typedef int int8;
+typedef unsigned int uint16;
+typedef int int16;
+typedef unsigned int uint32;
+typedef signed int int32;
+#ifdef BITS64
+typedef unsigned long long int uint64;
+typedef signed long long int int64;
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Each of the following `typedef's defines a type that holds integers
+of _exactly_ the number of bits specified. For instance, for most
+implementation of C, `bits16' and `sbits16' should be `typedef'ed to
+`unsigned short int' and `signed short int' (or `short int'), respectively.
+-------------------------------------------------------------------------------
+*/
+typedef unsigned char bits8;
+typedef signed char sbits8;
+typedef unsigned short int bits16;
+typedef signed short int sbits16;
+typedef unsigned int bits32;
+typedef signed int sbits32;
+#ifdef BITS64
+typedef unsigned long long int bits64;
+typedef signed long long int sbits64;
+#endif
+
+#ifdef BITS64
+/*
+-------------------------------------------------------------------------------
+The `LIT64' macro takes as its argument a textual integer literal and
+if necessary ``marks'' the literal as having a 64-bit integer type.
+For example, the GNU C Compiler (`gcc') requires that 64-bit literals be
+appended with the letters `LL' standing for `long long', which is `gcc's
+name for the 64-bit integer type. Some compilers may allow `LIT64' to be
+defined as the identity macro: `#define LIT64( a ) a'.
+-------------------------------------------------------------------------------
+*/
+#define LIT64( a ) a##LL
+#endif
+
+/*
+-------------------------------------------------------------------------------
+The macro `INLINE' can be used before functions that should be inlined. If
+a compiler does not support explicit inlining, this macro should be defined
+to be `static'.
+-------------------------------------------------------------------------------
+*/
+#define INLINE static __inline
+
+/*
+-------------------------------------------------------------------------------
+The ARM FPA is odd in that it stores doubles high-order word first, no matter
+what the endianness of the CPU. VFP is sane.
+-------------------------------------------------------------------------------
+*/
+#if defined(SOFTFLOAT_FOR_GCC)
+#define FLOAT64_DEMANGLE(a) (a)
+#define FLOAT64_MANGLE(a) (a)
+#endif
diff --git a/lib/libc/powerpcspe/softfloat/softfloat.h b/lib/libc/powerpcspe/softfloat/softfloat.h
new file mode 100644
index 000000000000..6b9c9b06956d
--- /dev/null
+++ b/lib/libc/powerpcspe/softfloat/softfloat.h
@@ -0,0 +1,307 @@
+/* $NetBSD: softfloat.h,v 1.6 2002/05/12 13:12:46 bjh21 Exp $ */
+/* $FreeBSD$ */
+
+/* This is a derivative work. */
+
+/*
+===============================================================================
+
+This C header file is part of the SoftFloat IEC/IEEE Floating-point
+Arithmetic Package, Release 2a.
+
+Written by John R. Hauser. This work was made possible in part by the
+International Computer Science Institute, located at Suite 600, 1947 Center
+Street, Berkeley, California 94704. Funding was partially provided by the
+National Science Foundation under grant MIP-9311980. The original version
+of this code was written as part of a project to build a fixed-point vector
+processor in collaboration with the University of California at Berkeley,
+overseen by Profs. Nelson Morgan and John Wawrzynek. More information
+is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
+arithmetic/SoftFloat.html'.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
+has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
+TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
+PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
+AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
+
+Derivative works are acceptable, even for commercial purposes, so long as
+(1) they include prominent notice that the work is derivative, and (2) they
+include prominent notice akin to these four paragraphs for those parts of
+this code that are retained.
+
+===============================================================================
+*/
+
+/*
+-------------------------------------------------------------------------------
+The macro `FLOATX80' must be defined to enable the extended double-precision
+floating-point format `floatx80'. If this macro is not defined, the
+`floatx80' type will not be defined, and none of the functions that either
+input or output the `floatx80' type will be defined. The same applies to
+the `FLOAT128' macro and the quadruple-precision format `float128'.
+-------------------------------------------------------------------------------
+*/
+/* #define FLOATX80 */
+/* #define FLOAT128 */
+
+#include <machine/ieeefp.h>
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE floating-point types.
+-------------------------------------------------------------------------------
+*/
+typedef unsigned int float32;
+typedef unsigned long long float64;
+#ifdef FLOATX80
+typedef struct {
+ unsigned short high;
+ unsigned long long low;
+} floatx80;
+#endif
+#ifdef FLOAT128
+typedef struct {
+ unsigned long long high, low;
+} float128;
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE floating-point underflow tininess-detection mode.
+-------------------------------------------------------------------------------
+*/
+#ifndef SOFTFLOAT_FOR_GCC
+extern int8 float_detect_tininess;
+#endif
+enum {
+ float_tininess_after_rounding = 0,
+ float_tininess_before_rounding = 1
+};
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE floating-point rounding mode.
+-------------------------------------------------------------------------------
+*/
+extern fp_rnd_t float_rounding_mode;
+enum {
+ float_round_nearest_even = FP_RN,
+ float_round_to_zero = FP_RZ,
+ float_round_down = FP_RM,
+ float_round_up = FP_RP
+};
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE floating-point exception flags.
+-------------------------------------------------------------------------------
+*/
+typedef fp_except_t fp_except;
+
+extern fp_except float_exception_flags;
+extern fp_except float_exception_mask;
+enum {
+ float_flag_inexact = FP_X_IMP,
+ float_flag_underflow = FP_X_UFL,
+ float_flag_overflow = FP_X_OFL,
+ float_flag_divbyzero = FP_X_DZ,
+ float_flag_invalid = FP_X_INV
+};
+
+/*
+-------------------------------------------------------------------------------
+Routine to raise any or all of the software IEC/IEEE floating-point
+exception flags.
+-------------------------------------------------------------------------------
+*/
+void float_raise( fp_except );
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE integer-to-floating-point conversion routines.
+-------------------------------------------------------------------------------
+*/
+float32 int32_to_float32( int );
+float64 int32_to_float64( int );
+#ifdef FLOATX80
+floatx80 int32_to_floatx80( int );
+#endif
+#ifdef FLOAT128
+float128 int32_to_float128( int );
+#endif
+float32 int64_to_float32( long long );
+float64 int64_to_float64( long long );
+#ifdef FLOATX80
+floatx80 int64_to_floatx80( long long );
+#endif
+#ifdef FLOAT128
+float128 int64_to_float128( long long );
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE single-precision conversion routines.
+-------------------------------------------------------------------------------
+*/
+int float32_to_int32( float32 );
+int float32_to_int32_round_to_zero( float32 );
+unsigned int float32_to_uint32_round_to_zero( float32 );
+long long float32_to_int64( float32 );
+long long float32_to_int64_round_to_zero( float32 );
+float64 float32_to_float64( float32 );
+#ifdef FLOATX80
+floatx80 float32_to_floatx80( float32 );
+#endif
+#ifdef FLOAT128
+float128 float32_to_float128( float32 );
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE single-precision operations.
+-------------------------------------------------------------------------------
+*/
+float32 float32_round_to_int( float32 );
+float32 float32_add( float32, float32 );
+float32 float32_sub( float32, float32 );
+float32 float32_mul( float32, float32 );
+float32 float32_div( float32, float32 );
+float32 float32_rem( float32, float32 );
+float32 float32_sqrt( float32 );
+int float32_eq( float32, float32 );
+int float32_le( float32, float32 );
+int float32_lt( float32, float32 );
+int float32_eq_signaling( float32, float32 );
+int float32_le_quiet( float32, float32 );
+int float32_lt_quiet( float32, float32 );
+#ifndef SOFTFLOAT_FOR_GCC
+int float32_is_signaling_nan( float32 );
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE double-precision conversion routines.
+-------------------------------------------------------------------------------
+*/
+int float64_to_int32( float64 );
+int float64_to_int32_round_to_zero( float64 );
+unsigned int float64_to_uint32_round_to_zero( float64 );
+long long float64_to_int64( float64 );
+long long float64_to_int64_round_to_zero( float64 );
+float32 float64_to_float32( float64 );
+#ifdef FLOATX80
+floatx80 float64_to_floatx80( float64 );
+#endif
+#ifdef FLOAT128
+float128 float64_to_float128( float64 );
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE double-precision operations.
+-------------------------------------------------------------------------------
+*/
+float64 float64_round_to_int( float64 );
+float64 float64_add( float64, float64 );
+float64 float64_sub( float64, float64 );
+float64 float64_mul( float64, float64 );
+float64 float64_div( float64, float64 );
+float64 float64_rem( float64, float64 );
+float64 float64_sqrt( float64 );
+int float64_eq( float64, float64 );
+int float64_le( float64, float64 );
+int float64_lt( float64, float64 );
+int float64_eq_signaling( float64, float64 );
+int float64_le_quiet( float64, float64 );
+int float64_lt_quiet( float64, float64 );
+#ifndef SOFTFLOAT_FOR_GCC
+int float64_is_signaling_nan( float64 );
+#endif
+
+#ifdef FLOATX80
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE extended double-precision conversion routines.
+-------------------------------------------------------------------------------
+*/
+int floatx80_to_int32( floatx80 );
+int floatx80_to_int32_round_to_zero( floatx80 );
+long long floatx80_to_int64( floatx80 );
+long long floatx80_to_int64_round_to_zero( floatx80 );
+float32 floatx80_to_float32( floatx80 );
+float64 floatx80_to_float64( floatx80 );
+#ifdef FLOAT128
+float128 floatx80_to_float128( floatx80 );
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE extended double-precision rounding precision. Valid
+values are 32, 64, and 80.
+-------------------------------------------------------------------------------
+*/
+extern int floatx80_rounding_precision;
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE extended double-precision operations.
+-------------------------------------------------------------------------------
+*/
+floatx80 floatx80_round_to_int( floatx80 );
+floatx80 floatx80_add( floatx80, floatx80 );
+floatx80 floatx80_sub( floatx80, floatx80 );
+floatx80 floatx80_mul( floatx80, floatx80 );
+floatx80 floatx80_div( floatx80, floatx80 );
+floatx80 floatx80_rem( floatx80, floatx80 );
+floatx80 floatx80_sqrt( floatx80 );
+int floatx80_eq( floatx80, floatx80 );
+int floatx80_le( floatx80, floatx80 );
+int floatx80_lt( floatx80, floatx80 );
+int floatx80_eq_signaling( floatx80, floatx80 );
+int floatx80_le_quiet( floatx80, floatx80 );
+int floatx80_lt_quiet( floatx80, floatx80 );
+int floatx80_is_signaling_nan( floatx80 );
+
+#endif
+
+#ifdef FLOAT128
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE quadruple-precision conversion routines.
+-------------------------------------------------------------------------------
+*/
+int float128_to_int32( float128 );
+int float128_to_int32_round_to_zero( float128 );
+long long float128_to_int64( float128 );
+long long float128_to_int64_round_to_zero( float128 );
+float32 float128_to_float32( float128 );
+float64 float128_to_float64( float128 );
+#ifdef FLOATX80
+floatx80 float128_to_floatx80( float128 );
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE quadruple-precision operations.
+-------------------------------------------------------------------------------
+*/
+float128 float128_round_to_int( float128 );
+float128 float128_add( float128, float128 );
+float128 float128_sub( float128, float128 );
+float128 float128_mul( float128, float128 );
+float128 float128_div( float128, float128 );
+float128 float128_rem( float128, float128 );
+float128 float128_sqrt( float128 );
+int float128_eq( float128, float128 );
+int float128_le( float128, float128 );
+int float128_lt( float128, float128 );
+int float128_eq_signaling( float128, float128 );
+int float128_le_quiet( float128, float128 );
+int float128_lt_quiet( float128, float128 );
+int float128_is_signaling_nan( float128 );
+
+#endif
+
diff --git a/lib/libc/powerpcspe/sys/Makefile.inc b/lib/libc/powerpcspe/sys/Makefile.inc
new file mode 100644
index 000000000000..7ddf4f89f05b
--- /dev/null
+++ b/lib/libc/powerpcspe/sys/Makefile.inc
@@ -0,0 +1,4 @@
+# $FreeBSD$
+
+.PATH: ${LIBC_SRCTOP}/powerpc/sys
+.sinclude "${LIBC_SRCTOP}/powerpc/sys/Makefile.inc"
diff --git a/lib/libc/quad/Makefile.inc b/lib/libc/quad/Makefile.inc
new file mode 100644
index 000000000000..94697faf2fdd
--- /dev/null
+++ b/lib/libc/quad/Makefile.inc
@@ -0,0 +1,25 @@
+# from @(#)Makefile.inc 8.1 (Berkeley) 6/4/93
+# $FreeBSD$
+
+# Quad support, if needed
+.PATH: ${LIBC_SRCTOP}/${LIBC_ARCH}/quad ${LIBC_SRCTOP}/quad
+
+.if ${LIBC_ARCH} == "i386"
+
+SRCS+= cmpdi2.c divdi3.c moddi3.c qdivrem.c ucmpdi2.c udivdi3.c umoddi3.c
+
+.elif ${LIBC_ARCH} == "arm"
+
+SRCS+= adddi3.c anddi3.c floatunsdidf.c iordi3.c lshldi3.c notdi2.c \
+ qdivrem.c subdi3.c xordi3.c
+.else
+
+SRCS+= adddi3.c anddi3.c ashldi3.c ashrdi3.c cmpdi2.c divdi3.c fixdfdi.c \
+ fixsfdi.c fixunsdfdi.c fixunssfdi.c floatdidf.c floatdisf.c \
+ floatunsdidf.c iordi3.c lshldi3.c lshrdi3.c moddi3.c muldi3.c \
+ negdi2.c notdi2.c qdivrem.c subdi3.c ucmpdi2.c udivdi3.c umoddi3.c \
+ xordi3.c
+
+.endif
+
+SYM_MAPS+=${LIBC_SRCTOP}/quad/Symbol.map
diff --git a/lib/libc/quad/Symbol.map b/lib/libc/quad/Symbol.map
new file mode 100644
index 000000000000..82ad9402a9ff
--- /dev/null
+++ b/lib/libc/quad/Symbol.map
@@ -0,0 +1,38 @@
+/*
+ * $FreeBSD$
+ */
+
+FBSD_1.0 {
+ /*
+ * These symbols really shouldn't be exported since they should
+ * be pulled from libgcc, but the build of some applications is
+ * broken and they expect to see them in libc. glibc exports
+ * them, but they do not appear to be exported in Solaris.
+ */
+ __adddi3;
+ __anddi3;
+ __ashldi3;
+ __ashrdi3;
+ __cmpdi2;
+ __divdi3;
+ __fixdfdi;
+ __fixsfdi;
+ __fixunsdfdi;
+ __fixunssfdi;
+ __floatdidf;
+ __floatdisf;
+ __floatunsdidf;
+ __iordi3;
+ __lshldi3;
+ __lshrdi3;
+ __moddi3;
+ __muldi3;
+ __negdi2;
+ __one_cmpldi2;
+ __qdivrem;
+ __subdi3;
+ __ucmpdi2;
+ __udivdi3;
+ __umoddi3;
+ __xordi3;
+};
diff --git a/lib/libc/quad/TESTS/Makefile b/lib/libc/quad/TESTS/Makefile
new file mode 100644
index 000000000000..5834f21e80d7
--- /dev/null
+++ b/lib/libc/quad/TESTS/Makefile
@@ -0,0 +1,11 @@
+# @(#)Makefile 8.1 (Berkeley) 6/4/93
+
+all: mul divrem
+
+MUL= mul.c ../muldi3.c
+mul: ${MUL}
+ gcc -g -DSPARC_XXX ${MUL} -o ${.TARGET}
+
+DIVREM= divrem.c ../qdivrem.c
+divrem: ${DIVREM}
+ gcc -g -DSPARC_XXX ${DIVREM} -o ${.TARGET}
diff --git a/lib/libc/quad/TESTS/divrem.c b/lib/libc/quad/TESTS/divrem.c
new file mode 100644
index 000000000000..a9471a2ec632
--- /dev/null
+++ b/lib/libc/quad/TESTS/divrem.c
@@ -0,0 +1,76 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1992, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)divrem.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+
+main()
+{
+ union { long long q; unsigned long v[2]; } a, b, q, r;
+ char buf[300];
+ extern long long __qdivrem(unsigned long long, unsigned long long,
+ unsigned long long *);
+
+ for (;;) {
+ printf("> ");
+ if (fgets(buf, sizeof buf, stdin) == NULL)
+ break;
+ if (sscanf(buf, "%lu:%lu %lu:%lu",
+ &a.v[0], &a.v[1], &b.v[0], &b.v[1]) != 4 &&
+ sscanf(buf, "0x%lx:%lx 0x%lx:%lx",
+ &a.v[0], &a.v[1], &b.v[0], &b.v[1]) != 4) {
+ printf("eh?\n");
+ continue;
+ }
+ q.q = __qdivrem(a.q, b.q, &r.q);
+ printf("%lx:%lx /%% %lx:%lx => q=%lx:%lx r=%lx:%lx\n",
+ a.v[0], a.v[1], b.v[0], b.v[1],
+ q.v[0], q.v[1], r.v[0], r.v[1]);
+ printf(" = %lX%08lX / %lX%08lX => %lX%08lX\n\
+ = %lX%08lX %% %lX%08lX => %lX%08lX\n",
+ a.v[0], a.v[1], b.v[0], b.v[1], q.v[0], q.v[1],
+ a.v[0], a.v[1], b.v[0], b.v[1], r.v[0], r.v[1]);
+ }
+ exit(0);
+}
diff --git a/lib/libc/quad/TESTS/mul.c b/lib/libc/quad/TESTS/mul.c
new file mode 100644
index 000000000000..ba543be0ea91
--- /dev/null
+++ b/lib/libc/quad/TESTS/mul.c
@@ -0,0 +1,72 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1992, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)mul.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+
+main()
+{
+ union { long long q; unsigned long v[2]; } a, b, m;
+ char buf[300];
+ extern long long __muldi3(long long, long long);
+
+ for (;;) {
+ printf("> ");
+ if (fgets(buf, sizeof buf, stdin) == NULL)
+ break;
+ if (sscanf(buf, "%lu:%lu %lu:%lu",
+ &a.v[0], &a.v[1], &b.v[0], &b.v[1]) != 4 &&
+ sscanf(buf, "0x%lx:%lx 0x%lx:%lx",
+ &a.v[0], &a.v[1], &b.v[0], &b.v[1]) != 4) {
+ printf("eh?\n");
+ continue;
+ }
+ m.q = __muldi3(a.q, b.q);
+ printf("%lx:%lx * %lx:%lx => %lx:%lx\n",
+ a.v[0], a.v[1], b.v[0], b.v[1], m.v[0], m.v[1]);
+ printf(" = %lX%08lX * %lX%08lX => %lX%08lX\n",
+ a.v[0], a.v[1], b.v[0], b.v[1], m.v[0], m.v[1]);
+ }
+ exit(0);
+}
diff --git a/lib/libc/quad/adddi3.c b/lib/libc/quad/adddi3.c
new file mode 100644
index 000000000000..40712216415f
--- /dev/null
+++ b/lib/libc/quad/adddi3.c
@@ -0,0 +1,58 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)adddi3.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "quad.h"
+
+/*
+ * Add two quads. This is trivial since a one-bit carry from a single
+ * u_long addition x+y occurs if and only if the sum x+y is less than
+ * either x or y (the choice to compare with x or y is arbitrary).
+ */
+quad_t
+__adddi3(a, b)
+ quad_t a, b;
+{
+ union uu aa, bb, sum;
+
+ aa.q = a;
+ bb.q = b;
+ sum.ul[L] = aa.ul[L] + bb.ul[L];
+ sum.ul[H] = aa.ul[H] + bb.ul[H] + (sum.ul[L] < bb.ul[L]);
+ return (sum.q);
+}
diff --git a/lib/libc/quad/anddi3.c b/lib/libc/quad/anddi3.c
new file mode 100644
index 000000000000..575a35ca91eb
--- /dev/null
+++ b/lib/libc/quad/anddi3.c
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)anddi3.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "quad.h"
+
+/*
+ * Return a & b, in quad.
+ */
+quad_t
+__anddi3(a, b)
+ quad_t a, b;
+{
+ union uu aa, bb;
+
+ aa.q = a;
+ bb.q = b;
+ aa.ul[0] &= bb.ul[0];
+ aa.ul[1] &= bb.ul[1];
+ return (aa.q);
+}
diff --git a/lib/libc/quad/ashldi3.c b/lib/libc/quad/ashldi3.c
new file mode 100644
index 000000000000..c2fd87428f5b
--- /dev/null
+++ b/lib/libc/quad/ashldi3.c
@@ -0,0 +1,64 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)ashldi3.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "quad.h"
+
+/*
+ * Shift a (signed) quad value left (arithmetic shift left).
+ * This is the same as logical shift left!
+ */
+quad_t
+__ashldi3(a, shift)
+ quad_t a;
+ qshift_t shift;
+{
+ union uu aa;
+
+ aa.q = a;
+ if (shift >= LONG_BITS) {
+ aa.ul[H] = shift >= QUAD_BITS ? 0 :
+ aa.ul[L] << (shift - LONG_BITS);
+ aa.ul[L] = 0;
+ } else if (shift > 0) {
+ aa.ul[H] = (aa.ul[H] << shift) |
+ (aa.ul[L] >> (LONG_BITS - shift));
+ aa.ul[L] <<= shift;
+ }
+ return (aa.q);
+}
diff --git a/lib/libc/quad/ashrdi3.c b/lib/libc/quad/ashrdi3.c
new file mode 100644
index 000000000000..b5b1efd28f99
--- /dev/null
+++ b/lib/libc/quad/ashrdi3.c
@@ -0,0 +1,73 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)ashrdi3.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "quad.h"
+
+/*
+ * Shift a (signed) quad value right (arithmetic shift right).
+ */
+quad_t
+__ashrdi3(a, shift)
+ quad_t a;
+ qshift_t shift;
+{
+ union uu aa;
+
+ aa.q = a;
+ if (shift >= LONG_BITS) {
+ long s;
+
+ /*
+ * Smear bits rightward using the machine's right-shift
+ * method, whether that is sign extension or zero fill,
+ * to get the `sign word' s. Note that shifting by
+ * LONG_BITS is undefined, so we shift (LONG_BITS-1),
+ * then 1 more, to get our answer.
+ */
+ s = (aa.sl[H] >> (LONG_BITS - 1)) >> 1;
+ aa.ul[L] = shift >= QUAD_BITS ? s :
+ aa.sl[H] >> (shift - LONG_BITS);
+ aa.ul[H] = s;
+ } else if (shift > 0) {
+ aa.ul[L] = (aa.ul[L] >> shift) |
+ (aa.ul[H] << (LONG_BITS - shift));
+ aa.sl[H] >>= shift;
+ }
+ return (aa.q);
+}
diff --git a/lib/libc/quad/cmpdi2.c b/lib/libc/quad/cmpdi2.c
new file mode 100644
index 000000000000..10cb48ca7fe5
--- /dev/null
+++ b/lib/libc/quad/cmpdi2.c
@@ -0,0 +1,57 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)cmpdi2.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "quad.h"
+
+/*
+ * Return 0, 1, or 2 as a <, =, > b respectively.
+ * Both a and b are considered signed---which means only the high word is
+ * signed.
+ */
+int
+__cmpdi2(a, b)
+ quad_t a, b;
+{
+ union uu aa, bb;
+
+ aa.q = a;
+ bb.q = b;
+ return (aa.sl[H] < bb.sl[H] ? 0 : aa.sl[H] > bb.sl[H] ? 2 :
+ aa.ul[L] < bb.ul[L] ? 0 : aa.ul[L] > bb.ul[L] ? 2 : 1);
+}
diff --git a/lib/libc/quad/divdi3.c b/lib/libc/quad/divdi3.c
new file mode 100644
index 000000000000..4142056739e6
--- /dev/null
+++ b/lib/libc/quad/divdi3.c
@@ -0,0 +1,63 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)divdi3.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "quad.h"
+
+/*
+ * Divide two signed quads.
+ * ??? if -1/2 should produce -1 on this machine, this code is wrong
+ */
+quad_t
+__divdi3(a, b)
+ quad_t a, b;
+{
+ u_quad_t ua, ub, uq;
+ int neg;
+
+ if (a < 0)
+ ua = -(u_quad_t)a, neg = 1;
+ else
+ ua = a, neg = 0;
+ if (b < 0)
+ ub = -(u_quad_t)b, neg ^= 1;
+ else
+ ub = b;
+ uq = __qdivrem(ua, ub, (u_quad_t *)0);
+ return (neg ? -uq : uq);
+}
diff --git a/lib/libc/quad/fixdfdi.c b/lib/libc/quad/fixdfdi.c
new file mode 100644
index 000000000000..2e3c18d54107
--- /dev/null
+++ b/lib/libc/quad/fixdfdi.c
@@ -0,0 +1,60 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)fixdfdi.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "quad.h"
+
+/*
+ * Convert double to (signed) quad.
+ * We clamp anything that is out of range.
+ */
+quad_t
+__fixdfdi(x)
+ double x;
+{
+ if (x < 0)
+ if (x <= QUAD_MIN)
+ return (QUAD_MIN);
+ else
+ return ((quad_t)-(u_quad_t)-x);
+ else
+ if (x >= QUAD_MAX)
+ return (QUAD_MAX);
+ else
+ return ((quad_t)(u_quad_t)x);
+}
diff --git a/lib/libc/quad/fixsfdi.c b/lib/libc/quad/fixsfdi.c
new file mode 100644
index 000000000000..15ab68b1bd51
--- /dev/null
+++ b/lib/libc/quad/fixsfdi.c
@@ -0,0 +1,61 @@
+/*-
+ * Copyright (c) 1992 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)fixsfdi.c 5.1 (Berkeley) 7/7/92";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "quad.h"
+
+/*
+ * Convert float to (signed) quad.
+ * We clamp anything that is out of range.
+ *
+ * N.B.: must use new ANSI syntax (sorry).
+ */
+long long
+__fixsfdi(float x)
+{
+ if (x < 0)
+ if (x <= QUAD_MIN)
+ return (QUAD_MIN);
+ else
+ return ((quad_t)-(u_quad_t)-x);
+ else
+ if (x >= QUAD_MAX)
+ return (QUAD_MAX);
+ else
+ return ((quad_t)(u_quad_t)x);
+}
diff --git a/lib/libc/quad/fixunsdfdi.c b/lib/libc/quad/fixunsdfdi.c
new file mode 100644
index 000000000000..7b6c05e0508d
--- /dev/null
+++ b/lib/libc/quad/fixunsdfdi.c
@@ -0,0 +1,94 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)fixunsdfdi.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "quad.h"
+
+#define ONE_FOURTH (1 << (LONG_BITS - 2))
+#define ONE_HALF (ONE_FOURTH * 2.0)
+#define ONE (ONE_FOURTH * 4.0)
+
+/*
+ * Convert double to (unsigned) quad.
+ * Not sure what to do with negative numbers---for now, anything out
+ * of range becomes UQUAD_MAX.
+ */
+u_quad_t
+__fixunsdfdi(x)
+ double x;
+{
+ double toppart;
+ union uu t;
+
+ if (x < 0)
+ return (UQUAD_MAX); /* ??? should be 0? ERANGE??? */
+#ifdef notdef /* this falls afoul of a GCC bug */
+ if (x >= UQUAD_MAX)
+ return (UQUAD_MAX);
+#else /* so we wire in 2^64-1 instead */
+ if (x >= 18446744073709551615.0)
+ return (UQUAD_MAX);
+#endif
+ /*
+ * Get the upper part of the result. Note that the divide
+ * may round up; we want to avoid this if possible, so we
+ * subtract `1/2' first.
+ */
+ toppart = (x - ONE_HALF) / ONE;
+ /*
+ * Now build a u_quad_t out of the top part. The difference
+ * between x and this is the bottom part (this may introduce
+ * a few fuzzy bits, but what the heck). With any luck this
+ * difference will be nonnegative: x should wind up in the
+ * range [0..ULONG_MAX]. For paranoia, we assume [LONG_MIN..
+ * 2*ULONG_MAX] instead.
+ */
+ t.ul[H] = (unsigned long)toppart;
+ t.ul[L] = 0;
+ x -= (double)t.uq;
+ if (x < 0) {
+ t.ul[H]--;
+ x += ULONG_MAX;
+ }
+ if (x > ULONG_MAX) {
+ t.ul[H]++;
+ x -= ULONG_MAX;
+ }
+ t.ul[L] = (u_long)x;
+ return (t.uq);
+}
diff --git a/lib/libc/quad/fixunssfdi.c b/lib/libc/quad/fixunssfdi.c
new file mode 100644
index 000000000000..9b13c792549c
--- /dev/null
+++ b/lib/libc/quad/fixunssfdi.c
@@ -0,0 +1,98 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)fixunssfdi.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "quad.h"
+
+#define ONE_FOURTH (1 << (LONG_BITS - 2))
+#define ONE_HALF (ONE_FOURTH * 2.0)
+#define ONE (ONE_FOURTH * 4.0)
+
+/*
+ * Convert float to (unsigned) quad. We do most of our work in double,
+ * out of sheer paranoia.
+ *
+ * Not sure what to do with negative numbers---for now, anything out
+ * of range becomes UQUAD_MAX.
+ *
+ * N.B.: must use new ANSI syntax (sorry).
+ */
+u_quad_t
+__fixunssfdi(float f)
+{
+ double x, toppart;
+ union uu t;
+
+ if (f < 0)
+ return (UQUAD_MAX); /* ??? should be 0? ERANGE??? */
+#ifdef notdef /* this falls afoul of a GCC bug */
+ if (f >= UQUAD_MAX)
+ return (UQUAD_MAX);
+#else /* so we wire in 2^64-1 instead */
+ if (f >= 18446744073709551615.0)
+ return (UQUAD_MAX);
+#endif
+ x = f;
+ /*
+ * Get the upper part of the result. Note that the divide
+ * may round up; we want to avoid this if possible, so we
+ * subtract `1/2' first.
+ */
+ toppart = (x - ONE_HALF) / ONE;
+ /*
+ * Now build a u_quad_t out of the top part. The difference
+ * between x and this is the bottom part (this may introduce
+ * a few fuzzy bits, but what the heck). With any luck this
+ * difference will be nonnegative: x should wind up in the
+ * range [0..ULONG_MAX]. For paranoia, we assume [LONG_MIN..
+ * 2*ULONG_MAX] instead.
+ */
+ t.ul[H] = (unsigned long)toppart;
+ t.ul[L] = 0;
+ x -= (double)t.uq;
+ if (x < 0) {
+ t.ul[H]--;
+ x += ULONG_MAX;
+ }
+ if (x > ULONG_MAX) {
+ t.ul[H]++;
+ x -= ULONG_MAX;
+ }
+ t.ul[L] = (u_long)x;
+ return (t.uq);
+}
diff --git a/lib/libc/quad/floatdidf.c b/lib/libc/quad/floatdidf.c
new file mode 100644
index 000000000000..7167715adc53
--- /dev/null
+++ b/lib/libc/quad/floatdidf.c
@@ -0,0 +1,72 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)floatdidf.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "quad.h"
+
+/*
+ * Convert (signed) quad to double.
+ */
+double
+__floatdidf(x)
+ quad_t x;
+{
+ double d;
+ union uu u;
+ int neg;
+
+ /*
+ * Get an unsigned number first, by negating if necessary.
+ */
+ if (x < 0)
+ u.q = -x, neg = 1;
+ else
+ u.q = x, neg = 0;
+
+ /*
+ * Now u.ul[H] has the factor of 2^32 (or whatever) and u.ul[L]
+ * has the units. Ideally we could just set d, add LONG_BITS to
+ * its exponent, and then add the units, but this is portable
+ * code and does not know how to get at an exponent. Machine-
+ * specific code may be able to do this more efficiently.
+ */
+ d = (double)u.ul[H] * ((1 << (LONG_BITS - 2)) * 4.0);
+ d += u.ul[L];
+
+ return (neg ? -d : d);
+}
diff --git a/lib/libc/quad/floatdisf.c b/lib/libc/quad/floatdisf.c
new file mode 100644
index 000000000000..0cf7af8bc101
--- /dev/null
+++ b/lib/libc/quad/floatdisf.c
@@ -0,0 +1,74 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)floatdisf.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "quad.h"
+
+/*
+ * Convert (signed) quad to float.
+ */
+float
+__floatdisf(x)
+ quad_t x;
+{
+ float f;
+ union uu u;
+ int neg;
+
+ /*
+ * Get an unsigned number first, by negating if necessary.
+ */
+ if (x < 0)
+ u.q = -x, neg = 1;
+ else
+ u.q = x, neg = 0;
+
+ /*
+ * Now u.ul[H] has the factor of 2^32 (or whatever) and u.ul[L]
+ * has the units. Ideally we could just set f, add LONG_BITS to
+ * its exponent, and then add the units, but this is portable
+ * code and does not know how to get at an exponent. Machine-
+ * specific code may be able to do this more efficiently.
+ *
+ * Using double here may be excessive paranoia.
+ */
+ f = (double)u.ul[H] * ((1 << (LONG_BITS - 2)) * 4.0);
+ f += u.ul[L];
+
+ return (neg ? -f : f);
+}
diff --git a/lib/libc/quad/floatunsdidf.c b/lib/libc/quad/floatunsdidf.c
new file mode 100644
index 000000000000..264cd6249637
--- /dev/null
+++ b/lib/libc/quad/floatunsdidf.c
@@ -0,0 +1,57 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)floatunsdidf.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "quad.h"
+
+/*
+ * Convert (unsigned) quad to double.
+ * This is exactly like floatdidf.c except that negatives never occur.
+ */
+double
+__floatunsdidf(x)
+ u_quad_t x;
+{
+ double d;
+ union uu u;
+
+ u.uq = x;
+ d = (double)u.ul[H] * ((1 << (LONG_BITS - 2)) * 4.0);
+ d += u.ul[L];
+ return (d);
+}
diff --git a/lib/libc/quad/iordi3.c b/lib/libc/quad/iordi3.c
new file mode 100644
index 000000000000..5f4c67c898b3
--- /dev/null
+++ b/lib/libc/quad/iordi3.c
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)iordi3.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "quad.h"
+
+/*
+ * Return a | b, in quad.
+ */
+quad_t
+__iordi3(a, b)
+ quad_t a, b;
+{
+ union uu aa, bb;
+
+ aa.q = a;
+ bb.q = b;
+ aa.ul[0] |= bb.ul[0];
+ aa.ul[1] |= bb.ul[1];
+ return (aa.q);
+}
diff --git a/lib/libc/quad/lshldi3.c b/lib/libc/quad/lshldi3.c
new file mode 100644
index 000000000000..56fb0597e366
--- /dev/null
+++ b/lib/libc/quad/lshldi3.c
@@ -0,0 +1,64 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)lshldi3.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "quad.h"
+
+/*
+ * Shift an (unsigned) quad value left (logical shift left).
+ * This is the same as arithmetic shift left!
+ */
+quad_t
+__lshldi3(a, shift)
+ quad_t a;
+ qshift_t shift;
+{
+ union uu aa;
+
+ aa.q = a;
+ if (shift >= LONG_BITS) {
+ aa.ul[H] = shift >= QUAD_BITS ? 0 :
+ aa.ul[L] << (shift - LONG_BITS);
+ aa.ul[L] = 0;
+ } else if (shift > 0) {
+ aa.ul[H] = (aa.ul[H] << shift) |
+ (aa.ul[L] >> (LONG_BITS - shift));
+ aa.ul[L] <<= shift;
+ }
+ return (aa.q);
+}
diff --git a/lib/libc/quad/lshrdi3.c b/lib/libc/quad/lshrdi3.c
new file mode 100644
index 000000000000..4fc9362b06e5
--- /dev/null
+++ b/lib/libc/quad/lshrdi3.c
@@ -0,0 +1,63 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)lshrdi3.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "quad.h"
+
+/*
+ * Shift an (unsigned) quad value right (logical shift right).
+ */
+quad_t
+__lshrdi3(a, shift)
+ quad_t a;
+ qshift_t shift;
+{
+ union uu aa;
+
+ aa.q = a;
+ if (shift >= LONG_BITS) {
+ aa.ul[L] = shift >= QUAD_BITS ? 0 :
+ aa.ul[H] >> (shift - LONG_BITS);
+ aa.ul[H] = 0;
+ } else if (shift > 0) {
+ aa.ul[L] = (aa.ul[L] >> shift) |
+ (aa.ul[H] << (LONG_BITS - shift));
+ aa.ul[H] >>= shift;
+ }
+ return (aa.q);
+}
diff --git a/lib/libc/quad/moddi3.c b/lib/libc/quad/moddi3.c
new file mode 100644
index 000000000000..9dbf1c3bce1b
--- /dev/null
+++ b/lib/libc/quad/moddi3.c
@@ -0,0 +1,65 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)moddi3.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "quad.h"
+
+/*
+ * Return remainder after dividing two signed quads.
+ *
+ * XXX
+ * If -1/2 should produce -1 on this machine, this code is wrong.
+ */
+quad_t
+__moddi3(a, b)
+ quad_t a, b;
+{
+ u_quad_t ua, ub, ur;
+ int neg;
+
+ if (a < 0)
+ ua = -(u_quad_t)a, neg = 1;
+ else
+ ua = a, neg = 0;
+ if (b < 0)
+ ub = -(u_quad_t)b;
+ else
+ ub = b;
+ (void)__qdivrem(ua, ub, &ur);
+ return (neg ? -ur : ur);
+}
diff --git a/lib/libc/quad/muldi3.c b/lib/libc/quad/muldi3.c
new file mode 100644
index 000000000000..05c84b9e0e9c
--- /dev/null
+++ b/lib/libc/quad/muldi3.c
@@ -0,0 +1,244 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)muldi3.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "quad.h"
+
+/*
+ * Multiply two quads.
+ *
+ * Our algorithm is based on the following. Split incoming quad values
+ * u and v (where u,v >= 0) into
+ *
+ * u = 2^n u1 * u0 (n = number of bits in `u_long', usu. 32)
+ *
+ * and
+ *
+ * v = 2^n v1 * v0
+ *
+ * Then
+ *
+ * uv = 2^2n u1 v1 + 2^n u1 v0 + 2^n v1 u0 + u0 v0
+ * = 2^2n u1 v1 + 2^n (u1 v0 + v1 u0) + u0 v0
+ *
+ * Now add 2^n u1 v1 to the first term and subtract it from the middle,
+ * and add 2^n u0 v0 to the last term and subtract it from the middle.
+ * This gives:
+ *
+ * uv = (2^2n + 2^n) (u1 v1) +
+ * (2^n) (u1 v0 - u1 v1 + u0 v1 - u0 v0) +
+ * (2^n + 1) (u0 v0)
+ *
+ * Factoring the middle a bit gives us:
+ *
+ * uv = (2^2n + 2^n) (u1 v1) + [u1v1 = high]
+ * (2^n) (u1 - u0) (v0 - v1) + [(u1-u0)... = mid]
+ * (2^n + 1) (u0 v0) [u0v0 = low]
+ *
+ * The terms (u1 v1), (u1 - u0) (v0 - v1), and (u0 v0) can all be done
+ * in just half the precision of the original. (Note that either or both
+ * of (u1 - u0) or (v0 - v1) may be negative.)
+ *
+ * This algorithm is from Knuth vol. 2 (2nd ed), section 4.3.3, p. 278.
+ *
+ * Since C does not give us a `long * long = quad' operator, we split
+ * our input quads into two longs, then split the two longs into two
+ * shorts. We can then calculate `short * short = long' in native
+ * arithmetic.
+ *
+ * Our product should, strictly speaking, be a `long quad', with 128
+ * bits, but we are going to discard the upper 64. In other words,
+ * we are not interested in uv, but rather in (uv mod 2^2n). This
+ * makes some of the terms above vanish, and we get:
+ *
+ * (2^n)(high) + (2^n)(mid) + (2^n + 1)(low)
+ *
+ * or
+ *
+ * (2^n)(high + mid + low) + low
+ *
+ * Furthermore, `high' and `mid' can be computed mod 2^n, as any factor
+ * of 2^n in either one will also vanish. Only `low' need be computed
+ * mod 2^2n, and only because of the final term above.
+ */
+static quad_t __lmulq(u_long, u_long);
+
+quad_t
+__muldi3(a, b)
+ quad_t a, b;
+{
+ union uu u, v, low, prod;
+ u_long high, mid, udiff, vdiff;
+ int negall, negmid;
+#define u1 u.ul[H]
+#define u0 u.ul[L]
+#define v1 v.ul[H]
+#define v0 v.ul[L]
+
+ /*
+ * Get u and v such that u, v >= 0. When this is finished,
+ * u1, u0, v1, and v0 will be directly accessible through the
+ * longword fields.
+ */
+ if (a >= 0)
+ u.q = a, negall = 0;
+ else
+ u.q = -a, negall = 1;
+ if (b >= 0)
+ v.q = b;
+ else
+ v.q = -b, negall ^= 1;
+
+ if (u1 == 0 && v1 == 0) {
+ /*
+ * An (I hope) important optimization occurs when u1 and v1
+ * are both 0. This should be common since most numbers
+ * are small. Here the product is just u0*v0.
+ */
+ prod.q = __lmulq(u0, v0);
+ } else {
+ /*
+ * Compute the three intermediate products, remembering
+ * whether the middle term is negative. We can discard
+ * any upper bits in high and mid, so we can use native
+ * u_long * u_long => u_long arithmetic.
+ */
+ low.q = __lmulq(u0, v0);
+
+ if (u1 >= u0)
+ negmid = 0, udiff = u1 - u0;
+ else
+ negmid = 1, udiff = u0 - u1;
+ if (v0 >= v1)
+ vdiff = v0 - v1;
+ else
+ vdiff = v1 - v0, negmid ^= 1;
+ mid = udiff * vdiff;
+
+ high = u1 * v1;
+
+ /*
+ * Assemble the final product.
+ */
+ prod.ul[H] = high + (negmid ? -mid : mid) + low.ul[L] +
+ low.ul[H];
+ prod.ul[L] = low.ul[L];
+ }
+ return (negall ? -prod.q : prod.q);
+#undef u1
+#undef u0
+#undef v1
+#undef v0
+}
+
+/*
+ * Multiply two 2N-bit longs to produce a 4N-bit quad, where N is half
+ * the number of bits in a long (whatever that is---the code below
+ * does not care as long as quad.h does its part of the bargain---but
+ * typically N==16).
+ *
+ * We use the same algorithm from Knuth, but this time the modulo refinement
+ * does not apply. On the other hand, since N is half the size of a long,
+ * we can get away with native multiplication---none of our input terms
+ * exceeds (ULONG_MAX >> 1).
+ *
+ * Note that, for u_long l, the quad-precision result
+ *
+ * l << N
+ *
+ * splits into high and low longs as HHALF(l) and LHUP(l) respectively.
+ */
+static quad_t
+__lmulq(u_long u, u_long v)
+{
+ u_long u1, u0, v1, v0, udiff, vdiff, high, mid, low;
+ u_long prodh, prodl, was;
+ union uu prod;
+ int neg;
+
+ u1 = HHALF(u);
+ u0 = LHALF(u);
+ v1 = HHALF(v);
+ v0 = LHALF(v);
+
+ low = u0 * v0;
+
+ /* This is the same small-number optimization as before. */
+ if (u1 == 0 && v1 == 0)
+ return (low);
+
+ if (u1 >= u0)
+ udiff = u1 - u0, neg = 0;
+ else
+ udiff = u0 - u1, neg = 1;
+ if (v0 >= v1)
+ vdiff = v0 - v1;
+ else
+ vdiff = v1 - v0, neg ^= 1;
+ mid = udiff * vdiff;
+
+ high = u1 * v1;
+
+ /* prod = (high << 2N) + (high << N); */
+ prodh = high + HHALF(high);
+ prodl = LHUP(high);
+
+ /* if (neg) prod -= mid << N; else prod += mid << N; */
+ if (neg) {
+ was = prodl;
+ prodl -= LHUP(mid);
+ prodh -= HHALF(mid) + (prodl > was);
+ } else {
+ was = prodl;
+ prodl += LHUP(mid);
+ prodh += HHALF(mid) + (prodl < was);
+ }
+
+ /* prod += low << N */
+ was = prodl;
+ prodl += LHUP(low);
+ prodh += HHALF(low) + (prodl < was);
+ /* ... + low; */
+ if ((prodl += low) < low)
+ prodh++;
+
+ /* return 4N-bit product */
+ prod.ul[H] = prodh;
+ prod.ul[L] = prodl;
+ return (prod.q);
+}
diff --git a/lib/libc/quad/negdi2.c b/lib/libc/quad/negdi2.c
new file mode 100644
index 000000000000..6af1ea902152
--- /dev/null
+++ b/lib/libc/quad/negdi2.c
@@ -0,0 +1,55 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)negdi2.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "quad.h"
+
+/*
+ * Return -a (or, equivalently, 0 - a), in quad. See subdi3.c.
+ */
+quad_t
+__negdi2(a)
+ quad_t a;
+{
+ union uu aa, res;
+
+ aa.q = a;
+ res.ul[L] = -aa.ul[L];
+ res.ul[H] = -aa.ul[H] - (res.ul[L] > 0);
+ return (res.q);
+}
diff --git a/lib/libc/quad/notdi2.c b/lib/libc/quad/notdi2.c
new file mode 100644
index 000000000000..b5480bc17dc5
--- /dev/null
+++ b/lib/libc/quad/notdi2.c
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)notdi2.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "quad.h"
+
+/*
+ * Return ~a. For some reason gcc calls this `one's complement' rather
+ * than `not'.
+ */
+quad_t
+__one_cmpldi2(a)
+ quad_t a;
+{
+ union uu aa;
+
+ aa.q = a;
+ aa.ul[0] = ~aa.ul[0];
+ aa.ul[1] = ~aa.ul[1];
+ return (aa.q);
+}
diff --git a/lib/libc/quad/qdivrem.c b/lib/libc/quad/qdivrem.c
new file mode 100644
index 000000000000..e8e3c9857e60
--- /dev/null
+++ b/lib/libc/quad/qdivrem.c
@@ -0,0 +1,277 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)qdivrem.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Multiprecision divide. This algorithm is from Knuth vol. 2 (2nd ed),
+ * section 4.3.1, pp. 257--259.
+ */
+
+#include "quad.h"
+
+#define B (1 << HALF_BITS) /* digit base */
+
+/* Combine two `digits' to make a single two-digit number. */
+#define COMBINE(a, b) (((u_long)(a) << HALF_BITS) | (b))
+
+/* select a type for digits in base B: use unsigned short if they fit */
+#if ULONG_MAX == 0xffffffff && USHRT_MAX >= 0xffff
+typedef unsigned short digit;
+#else
+typedef u_long digit;
+#endif
+
+/*
+ * Shift p[0]..p[len] left `sh' bits, ignoring any bits that
+ * `fall out' the left (there never will be any such anyway).
+ * We may assume len >= 0. NOTE THAT THIS WRITES len+1 DIGITS.
+ */
+static void
+shl(digit *p, int len, int sh)
+{
+ int i;
+
+ for (i = 0; i < len; i++)
+ p[i] = LHALF(p[i] << sh) | (p[i + 1] >> (HALF_BITS - sh));
+ p[i] = LHALF(p[i] << sh);
+}
+
+/*
+ * __qdivrem(u, v, rem) returns u/v and, optionally, sets *rem to u%v.
+ *
+ * We do this in base 2-sup-HALF_BITS, so that all intermediate products
+ * fit within u_long. As a consequence, the maximum length dividend and
+ * divisor are 4 `digits' in this base (they are shorter if they have
+ * leading zeros).
+ */
+u_quad_t
+__qdivrem(uq, vq, arq)
+ u_quad_t uq, vq, *arq;
+{
+ union uu tmp;
+ digit *u, *v, *q;
+ digit v1, v2;
+ u_long qhat, rhat, t;
+ int m, n, d, j, i;
+ digit uspace[5], vspace[5], qspace[5];
+
+ /*
+ * Take care of special cases: divide by zero, and u < v.
+ */
+ if (vq == 0) {
+ /* divide by zero. */
+ static volatile const unsigned int zero = 0;
+
+ tmp.ul[H] = tmp.ul[L] = 1 / zero;
+ if (arq)
+ *arq = uq;
+ return (tmp.q);
+ }
+ if (uq < vq) {
+ if (arq)
+ *arq = uq;
+ return (0);
+ }
+ u = &uspace[0];
+ v = &vspace[0];
+ q = &qspace[0];
+
+ /*
+ * Break dividend and divisor into digits in base B, then
+ * count leading zeros to determine m and n. When done, we
+ * will have:
+ * u = (u[1]u[2]...u[m+n]) sub B
+ * v = (v[1]v[2]...v[n]) sub B
+ * v[1] != 0
+ * 1 < n <= 4 (if n = 1, we use a different division algorithm)
+ * m >= 0 (otherwise u < v, which we already checked)
+ * m + n = 4
+ * and thus
+ * m = 4 - n <= 2
+ */
+ tmp.uq = uq;
+ u[0] = 0;
+ u[1] = HHALF(tmp.ul[H]);
+ u[2] = LHALF(tmp.ul[H]);
+ u[3] = HHALF(tmp.ul[L]);
+ u[4] = LHALF(tmp.ul[L]);
+ tmp.uq = vq;
+ v[1] = HHALF(tmp.ul[H]);
+ v[2] = LHALF(tmp.ul[H]);
+ v[3] = HHALF(tmp.ul[L]);
+ v[4] = LHALF(tmp.ul[L]);
+ for (n = 4; v[1] == 0; v++) {
+ if (--n == 1) {
+ u_long rbj; /* r*B+u[j] (not root boy jim) */
+ digit q1, q2, q3, q4;
+
+ /*
+ * Change of plan, per exercise 16.
+ * r = 0;
+ * for j = 1..4:
+ * q[j] = floor((r*B + u[j]) / v),
+ * r = (r*B + u[j]) % v;
+ * We unroll this completely here.
+ */
+ t = v[2]; /* nonzero, by definition */
+ q1 = u[1] / t;
+ rbj = COMBINE(u[1] % t, u[2]);
+ q2 = rbj / t;
+ rbj = COMBINE(rbj % t, u[3]);
+ q3 = rbj / t;
+ rbj = COMBINE(rbj % t, u[4]);
+ q4 = rbj / t;
+ if (arq)
+ *arq = rbj % t;
+ tmp.ul[H] = COMBINE(q1, q2);
+ tmp.ul[L] = COMBINE(q3, q4);
+ return (tmp.q);
+ }
+ }
+
+ /*
+ * By adjusting q once we determine m, we can guarantee that
+ * there is a complete four-digit quotient at &qspace[1] when
+ * we finally stop.
+ */
+ for (m = 4 - n; u[1] == 0; u++)
+ m--;
+ for (i = 4 - m; --i >= 0;)
+ q[i] = 0;
+ q += 4 - m;
+
+ /*
+ * Here we run Program D, translated from MIX to C and acquiring
+ * a few minor changes.
+ *
+ * D1: choose multiplier 1 << d to ensure v[1] >= B/2.
+ */
+ d = 0;
+ for (t = v[1]; t < B / 2; t <<= 1)
+ d++;
+ if (d > 0) {
+ shl(&u[0], m + n, d); /* u <<= d */
+ shl(&v[1], n - 1, d); /* v <<= d */
+ }
+ /*
+ * D2: j = 0.
+ */
+ j = 0;
+ v1 = v[1]; /* for D3 -- note that v[1..n] are constant */
+ v2 = v[2]; /* for D3 */
+ do {
+ digit uj0, uj1, uj2;
+
+ /*
+ * D3: Calculate qhat (\^q, in TeX notation).
+ * Let qhat = min((u[j]*B + u[j+1])/v[1], B-1), and
+ * let rhat = (u[j]*B + u[j+1]) mod v[1].
+ * While rhat < B and v[2]*qhat > rhat*B+u[j+2],
+ * decrement qhat and increase rhat correspondingly.
+ * Note that if rhat >= B, v[2]*qhat < rhat*B.
+ */
+ uj0 = u[j + 0]; /* for D3 only -- note that u[j+...] change */
+ uj1 = u[j + 1]; /* for D3 only */
+ uj2 = u[j + 2]; /* for D3 only */
+ if (uj0 == v1) {
+ qhat = B;
+ rhat = uj1;
+ goto qhat_too_big;
+ } else {
+ u_long n = COMBINE(uj0, uj1);
+ qhat = n / v1;
+ rhat = n % v1;
+ }
+ while (v2 * qhat > COMBINE(rhat, uj2)) {
+ qhat_too_big:
+ qhat--;
+ if ((rhat += v1) >= B)
+ break;
+ }
+ /*
+ * D4: Multiply and subtract.
+ * The variable `t' holds any borrows across the loop.
+ * We split this up so that we do not require v[0] = 0,
+ * and to eliminate a final special case.
+ */
+ for (t = 0, i = n; i > 0; i--) {
+ t = u[i + j] - v[i] * qhat - t;
+ u[i + j] = LHALF(t);
+ t = (B - HHALF(t)) & (B - 1);
+ }
+ t = u[j] - t;
+ u[j] = LHALF(t);
+ /*
+ * D5: test remainder.
+ * There is a borrow if and only if HHALF(t) is nonzero;
+ * in that (rare) case, qhat was too large (by exactly 1).
+ * Fix it by adding v[1..n] to u[j..j+n].
+ */
+ if (HHALF(t)) {
+ qhat--;
+ for (t = 0, i = n; i > 0; i--) { /* D6: add back. */
+ t += u[i + j] + v[i];
+ u[i + j] = LHALF(t);
+ t = HHALF(t);
+ }
+ u[j] = LHALF(u[j] + t);
+ }
+ q[j] = qhat;
+ } while (++j <= m); /* D7: loop on j. */
+
+ /*
+ * If caller wants the remainder, we have to calculate it as
+ * u[m..m+n] >> d (this is at most n digits and thus fits in
+ * u[m+1..m+n], but we may need more source digits).
+ */
+ if (arq) {
+ if (d) {
+ for (i = m + n; i > m; --i)
+ u[i] = (u[i] >> d) |
+ LHALF(u[i - 1] << (HALF_BITS - d));
+ u[i] = 0;
+ }
+ tmp.ul[H] = COMBINE(uspace[1], uspace[2]);
+ tmp.ul[L] = COMBINE(uspace[3], uspace[4]);
+ *arq = tmp.q;
+ }
+
+ tmp.ul[H] = COMBINE(qspace[1], qspace[2]);
+ tmp.ul[L] = COMBINE(qspace[3], qspace[4]);
+ return (tmp.q);
+}
diff --git a/lib/libc/quad/quad.h b/lib/libc/quad/quad.h
new file mode 100644
index 000000000000..d496fc6daba7
--- /dev/null
+++ b/lib/libc/quad/quad.h
@@ -0,0 +1,103 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)quad.h 8.1 (Berkeley) 6/4/93
+ * $FreeBSD$
+ */
+
+/*
+ * Quad arithmetic.
+ *
+ * This library makes the following assumptions:
+ *
+ * - The type long long (aka quad_t) exists.
+ *
+ * - A quad variable is exactly twice as long as `long'.
+ *
+ * - The machine's arithmetic is two's complement.
+ *
+ * This library can provide 128-bit arithmetic on a machine with 128-bit
+ * quads and 64-bit longs, for instance, or 96-bit arithmetic on machines
+ * with 48-bit longs.
+ */
+
+#include <sys/types.h>
+#include <limits.h>
+
+/*
+ * Depending on the desired operation, we view a `long long' (aka quad_t) in
+ * one or more of the following formats.
+ */
+union uu {
+ quad_t q; /* as a (signed) quad */
+ quad_t uq; /* as an unsigned quad */
+ long sl[2]; /* as two signed longs */
+ u_long ul[2]; /* as two unsigned longs */
+};
+
+/*
+ * Define high and low longwords.
+ */
+#define H _QUAD_HIGHWORD
+#define L _QUAD_LOWWORD
+
+/*
+ * Total number of bits in a quad_t and in the pieces that make it up.
+ * These are used for shifting, and also below for halfword extraction
+ * and assembly.
+ */
+#define QUAD_BITS (sizeof(quad_t) * CHAR_BIT)
+#define LONG_BITS (sizeof(long) * CHAR_BIT)
+#define HALF_BITS (sizeof(long) * CHAR_BIT / 2)
+
+/*
+ * Extract high and low shortwords from longword, and move low shortword of
+ * longword to upper half of long, i.e., produce the upper longword of
+ * ((quad_t)(x) << (number_of_bits_in_long/2)). (`x' must actually be u_long.)
+ *
+ * These are used in the multiply code, to split a longword into upper
+ * and lower halves, and to reassemble a product as a quad_t, shifted left
+ * (sizeof(long)*CHAR_BIT/2).
+ */
+#define HHALF(x) ((x) >> HALF_BITS)
+#define LHALF(x) ((x) & ((1 << HALF_BITS) - 1))
+#define LHUP(x) ((x) << HALF_BITS)
+
+int __cmpdi2(quad_t a, quad_t b);
+quad_t __divdi3(quad_t a, quad_t b);
+quad_t __moddi3(quad_t a, quad_t b);
+u_quad_t __qdivrem(u_quad_t u, u_quad_t v, u_quad_t *rem);
+int __ucmpdi2(u_quad_t a, u_quad_t b);
+u_quad_t __udivdi3(u_quad_t a, u_quad_t b);
+u_quad_t __umoddi3(u_quad_t a, u_quad_t b);
+
+typedef unsigned int qshift_t;
diff --git a/lib/libc/quad/subdi3.c b/lib/libc/quad/subdi3.c
new file mode 100644
index 000000000000..b31f0406e389
--- /dev/null
+++ b/lib/libc/quad/subdi3.c
@@ -0,0 +1,57 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)subdi3.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "quad.h"
+
+/*
+ * Subtract two quad values. This is trivial since a one-bit carry
+ * from a single u_long difference x-y occurs if and only if (x-y) > x.
+ */
+quad_t
+__subdi3(a, b)
+ quad_t a, b;
+{
+ union uu aa, bb, diff;
+
+ aa.q = a;
+ bb.q = b;
+ diff.ul[L] = aa.ul[L] - bb.ul[L];
+ diff.ul[H] = aa.ul[H] - bb.ul[H] - (diff.ul[L] > aa.ul[L]);
+ return (diff.q);
+}
diff --git a/lib/libc/quad/ucmpdi2.c b/lib/libc/quad/ucmpdi2.c
new file mode 100644
index 000000000000..6605896e533d
--- /dev/null
+++ b/lib/libc/quad/ucmpdi2.c
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)ucmpdi2.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "quad.h"
+
+/*
+ * Return 0, 1, or 2 as a <, =, > b respectively.
+ * Neither a nor b are considered signed.
+ */
+int
+__ucmpdi2(a, b)
+ u_quad_t a, b;
+{
+ union uu aa, bb;
+
+ aa.uq = a;
+ bb.uq = b;
+ return (aa.ul[H] < bb.ul[H] ? 0 : aa.ul[H] > bb.ul[H] ? 2 :
+ aa.ul[L] < bb.ul[L] ? 0 : aa.ul[L] > bb.ul[L] ? 2 : 1);
+}
diff --git a/lib/libc/quad/udivdi3.c b/lib/libc/quad/udivdi3.c
new file mode 100644
index 000000000000..8b5a7888faf4
--- /dev/null
+++ b/lib/libc/quad/udivdi3.c
@@ -0,0 +1,51 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)udivdi3.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "quad.h"
+
+/*
+ * Divide two unsigned quads.
+ */
+u_quad_t
+__udivdi3(a, b)
+ u_quad_t a, b;
+{
+
+ return (__qdivrem(a, b, (u_quad_t *)0));
+}
diff --git a/lib/libc/quad/umoddi3.c b/lib/libc/quad/umoddi3.c
new file mode 100644
index 000000000000..29ce2cba8819
--- /dev/null
+++ b/lib/libc/quad/umoddi3.c
@@ -0,0 +1,53 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)umoddi3.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "quad.h"
+
+/*
+ * Return remainder after dividing two unsigned quads.
+ */
+u_quad_t
+__umoddi3(a, b)
+ u_quad_t a, b;
+{
+ u_quad_t r;
+
+ (void)__qdivrem(a, b, &r);
+ return (r);
+}
diff --git a/lib/libc/quad/xordi3.c b/lib/libc/quad/xordi3.c
new file mode 100644
index 000000000000..ec7f6bd52206
--- /dev/null
+++ b/lib/libc/quad/xordi3.c
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)xordi3.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "quad.h"
+
+/*
+ * Return a ^ b, in quad.
+ */
+quad_t
+__xordi3(a, b)
+ quad_t a, b;
+{
+ union uu aa, bb;
+
+ aa.q = a;
+ bb.q = b;
+ aa.ul[0] ^= bb.ul[0];
+ aa.ul[1] ^= bb.ul[1];
+ return (aa.q);
+}
diff --git a/lib/libc/regex/COPYRIGHT b/lib/libc/regex/COPYRIGHT
new file mode 100644
index 000000000000..574f6bcec6c7
--- /dev/null
+++ b/lib/libc/regex/COPYRIGHT
@@ -0,0 +1,56 @@
+Copyright 1992, 1993, 1994 Henry Spencer. All rights reserved.
+This software is not subject to any license of the American Telephone
+and Telegraph Company or of the Regents of the University of California.
+
+Permission is granted to anyone to use this software for any purpose on
+any computer system, and to alter it and redistribute it, subject
+to the following restrictions:
+
+1. The author is not responsible for the consequences of use of this
+ software, no matter how awful, even if they arise from flaws in it.
+
+2. The origin of this software must not be misrepresented, either by
+ explicit claim or by omission. Since few users ever read sources,
+ credits must appear in the documentation.
+
+3. Altered versions must be plainly marked as such, and must not be
+ misrepresented as being the original software. Since few users
+ ever read sources, credits must appear in the documentation.
+
+4. This notice may not be removed or altered.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+/*-
+ * Copyright (c) 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)COPYRIGHT 8.1 (Berkeley) 3/16/94
+ */
diff --git a/lib/libc/regex/Makefile.inc b/lib/libc/regex/Makefile.inc
new file mode 100644
index 000000000000..4595361b2813
--- /dev/null
+++ b/lib/libc/regex/Makefile.inc
@@ -0,0 +1,17 @@
+# from @(#)Makefile.inc 8.1 (Berkeley) 6/4/93
+# $FreeBSD$
+
+# regex sources
+.PATH: ${LIBC_SRCTOP}/regex
+
+CFLAGS+=-DPOSIX_MISTAKE
+
+SRCS+= regcomp.c regerror.c regexec.c regfree.c
+
+SYM_MAPS+=${LIBC_SRCTOP}/regex/Symbol.map
+
+MAN+= regex.3
+MAN+= re_format.7
+
+MLINKS+=regex.3 regcomp.3 regex.3 regexec.3 regex.3 regerror.3
+MLINKS+=regexec.3 regfree.3
diff --git a/lib/libc/regex/Symbol.map b/lib/libc/regex/Symbol.map
new file mode 100644
index 000000000000..5821f62b6430
--- /dev/null
+++ b/lib/libc/regex/Symbol.map
@@ -0,0 +1,10 @@
+/*
+ * $FreeBSD$
+ */
+
+FBSD_1.0 {
+ regcomp;
+ regerror;
+ regexec;
+ regfree;
+};
diff --git a/lib/libc/regex/WHATSNEW b/lib/libc/regex/WHATSNEW
new file mode 100644
index 000000000000..f4301d300dd3
--- /dev/null
+++ b/lib/libc/regex/WHATSNEW
@@ -0,0 +1,94 @@
+# @(#)WHATSNEW 8.3 (Berkeley) 3/18/94
+
+New in alpha3.4: The complex bug alluded to below has been fixed (in a
+slightly kludgey temporary way that may hurt efficiency a bit; this is
+another "get it out the door for 4.4" release). The tests at the end of
+the tests file have accordingly been uncommented. The primary sign of
+the bug was that something like a?b matching ab matched b rather than ab.
+(The bug was essentially specific to this exact situation, else it would
+have shown up earlier.)
+
+New in alpha3.3: The definition of word boundaries has been altered
+slightly, to more closely match the usual programming notion that "_"
+is an alphabetic. Stuff used for pre-ANSI systems is now in a subdir,
+and the makefile no longer alludes to it in mysterious ways. The
+makefile has generally been cleaned up some. Fixes have been made
+(again!) so that the regression test will run without -DREDEBUG, at
+the cost of weaker checking. A workaround for a bug in some folks'
+<assert.h> has been added. And some more things have been added to
+tests, including a couple right at the end which are commented out
+because the code currently flunks them (complex bug; fix coming).
+Plus the usual minor cleanup.
+
+New in alpha3.2: Assorted bits of cleanup and portability improvement
+(the development base is now a BSDI system using GCC instead of an ancient
+Sun system, and the newer compiler exposed some glitches). Fix for a
+serious bug that affected REs using many [] (including REG_ICASE REs
+because of the way they are implemented), *sometimes*, depending on
+memory-allocation patterns. The header-file prototypes no longer name
+the parameters, avoiding possible name conflicts. The possibility that
+some clot has defined CHAR_MIN as (say) `-128' instead of `(-128)' is
+now handled gracefully. "uchar" is no longer used as an internal type
+name (too many people have the same idea). Still the same old lousy
+performance, alas.
+
+New in alpha3.1: Basically nothing, this release is just a bookkeeping
+convenience. Stay tuned.
+
+New in alpha3.0: Performance is no better, alas, but some fixes have been
+made and some functionality has been added. (This is basically the "get
+it out the door in time for 4.4" release.) One bug fix: regfree() didn't
+free the main internal structure (how embarrassing). It is now possible
+to put NULs in either the RE or the target string, using (resp.) a new
+REG_PEND flag and the old REG_STARTEND flag. The REG_NOSPEC flag to
+regcomp() makes all characters ordinary, so you can match a literal
+string easily (this will become more useful when performance improves!).
+There are now primitives to match beginnings and ends of words, although
+the syntax is disgusting and so is the implementation. The REG_ATOI
+debugging interface has changed a bit. And there has been considerable
+internal cleanup of various kinds.
+
+New in alpha2.3: Split change list out of README, and moved flags notes
+into Makefile. Macro-ized the name of regex(7) in regex(3), since it has
+to change for 4.4BSD. Cleanup work in engine.c, and some new regression
+tests to catch tricky cases thereof.
+
+New in alpha2.2: Out-of-date manpages updated. Regerror() acquires two
+small extensions -- REG_ITOA and REG_ATOI -- which avoid debugging kludges
+in my own test program and might be useful to others for similar purposes.
+The regression test will now compile (and run) without REDEBUG. The
+BRE \$ bug is fixed. Most uses of "uchar" are gone; it's all chars now.
+Char/uchar parameters are now written int/unsigned, to avoid possible
+portability problems with unpromoted parameters. Some unsigned casts have
+been introduced to minimize portability problems with shifting into sign
+bits.
+
+New in alpha2.1: Lots of little stuff, cleanup and fixes. The one big
+thing is that regex.h is now generated, using mkh, rather than being
+supplied in the distribution; due to circularities in dependencies,
+you have to build regex.h explicitly by "make h". The two known bugs
+have been fixed (and the regression test now checks for them), as has a
+problem with assertions not being suppressed in the absence of REDEBUG.
+No performance work yet.
+
+New in alpha2: Backslash-anything is an ordinary character, not an
+error (except, of course, for the handful of backslashed metacharacters
+in BREs), which should reduce script breakage. The regression test
+checks *where* null strings are supposed to match, and has generally
+been tightened up somewhat. Small bug fixes in parameter passing (not
+harmful, but technically errors) and some other areas. Debugging
+invoked by defining REDEBUG rather than not defining NDEBUG.
+
+New in alpha+3: full prototyping for internal routines, using a little
+helper program, mkh, which extracts prototypes given in stylized comments.
+More minor cleanup. Buglet fix: it's CHAR_BIT, not CHAR_BITS. Simple
+pre-screening of input when a literal string is known to be part of the
+RE; this does wonders for performance.
+
+New in alpha+2: minor bits of cleanup. Notably, the number "32" for the
+word width isn't hardwired into regexec.c any more, the public header
+file prototypes the functions if __STDC__ is defined, and some small typos
+in the manpages have been fixed.
+
+New in alpha+1: improvements to the manual pages, and an important
+extension, the REG_STARTEND option to regexec().
diff --git a/lib/libc/regex/cname.h b/lib/libc/regex/cname.h
new file mode 100644
index 000000000000..7087bcb565f3
--- /dev/null
+++ b/lib/libc/regex/cname.h
@@ -0,0 +1,138 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994 Henry Spencer.
+ * Copyright (c) 1992, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Henry Spencer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)cname.h 8.3 (Berkeley) 3/20/94
+ * $FreeBSD$
+ */
+
+/* character-name table */
+static struct cname {
+ char *name;
+ char code;
+} cnames[] = {
+ {"NUL", '\0'},
+ {"SOH", '\001'},
+ {"STX", '\002'},
+ {"ETX", '\003'},
+ {"EOT", '\004'},
+ {"ENQ", '\005'},
+ {"ACK", '\006'},
+ {"BEL", '\007'},
+ {"alert", '\007'},
+ {"BS", '\010'},
+ {"backspace", '\b'},
+ {"HT", '\011'},
+ {"tab", '\t'},
+ {"LF", '\012'},
+ {"newline", '\n'},
+ {"VT", '\013'},
+ {"vertical-tab", '\v'},
+ {"FF", '\014'},
+ {"form-feed", '\f'},
+ {"CR", '\015'},
+ {"carriage-return", '\r'},
+ {"SO", '\016'},
+ {"SI", '\017'},
+ {"DLE", '\020'},
+ {"DC1", '\021'},
+ {"DC2", '\022'},
+ {"DC3", '\023'},
+ {"DC4", '\024'},
+ {"NAK", '\025'},
+ {"SYN", '\026'},
+ {"ETB", '\027'},
+ {"CAN", '\030'},
+ {"EM", '\031'},
+ {"SUB", '\032'},
+ {"ESC", '\033'},
+ {"IS4", '\034'},
+ {"FS", '\034'},
+ {"IS3", '\035'},
+ {"GS", '\035'},
+ {"IS2", '\036'},
+ {"RS", '\036'},
+ {"IS1", '\037'},
+ {"US", '\037'},
+ {"space", ' '},
+ {"exclamation-mark", '!'},
+ {"quotation-mark", '"'},
+ {"number-sign", '#'},
+ {"dollar-sign", '$'},
+ {"percent-sign", '%'},
+ {"ampersand", '&'},
+ {"apostrophe", '\''},
+ {"left-parenthesis", '('},
+ {"right-parenthesis", ')'},
+ {"asterisk", '*'},
+ {"plus-sign", '+'},
+ {"comma", ','},
+ {"hyphen", '-'},
+ {"hyphen-minus", '-'},
+ {"period", '.'},
+ {"full-stop", '.'},
+ {"slash", '/'},
+ {"solidus", '/'},
+ {"zero", '0'},
+ {"one", '1'},
+ {"two", '2'},
+ {"three", '3'},
+ {"four", '4'},
+ {"five", '5'},
+ {"six", '6'},
+ {"seven", '7'},
+ {"eight", '8'},
+ {"nine", '9'},
+ {"colon", ':'},
+ {"semicolon", ';'},
+ {"less-than-sign", '<'},
+ {"equals-sign", '='},
+ {"greater-than-sign", '>'},
+ {"question-mark", '?'},
+ {"commercial-at", '@'},
+ {"left-square-bracket", '['},
+ {"backslash", '\\'},
+ {"reverse-solidus", '\\'},
+ {"right-square-bracket",']'},
+ {"circumflex", '^'},
+ {"circumflex-accent", '^'},
+ {"underscore", '_'},
+ {"low-line", '_'},
+ {"grave-accent", '`'},
+ {"left-brace", '{'},
+ {"left-curly-bracket", '{'},
+ {"vertical-line", '|'},
+ {"right-brace", '}'},
+ {"right-curly-bracket", '}'},
+ {"tilde", '~'},
+ {"DEL", '\177'},
+ {NULL, 0}
+};
diff --git a/lib/libc/regex/engine.c b/lib/libc/regex/engine.c
new file mode 100644
index 000000000000..c4cbb54d9f96
--- /dev/null
+++ b/lib/libc/regex/engine.c
@@ -0,0 +1,1183 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994 Henry Spencer.
+ * Copyright (c) 1992, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Henry Spencer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)engine.c 8.5 (Berkeley) 3/20/94
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * The matching engine and friends. This file is #included by regexec.c
+ * after suitable #defines of a variety of macros used herein, so that
+ * different state representations can be used without duplicating masses
+ * of code.
+ */
+
+#ifdef SNAMES
+#define matcher smatcher
+#define fast sfast
+#define slow sslow
+#define dissect sdissect
+#define backref sbackref
+#define step sstep
+#define print sprint
+#define at sat
+#define match smat
+#endif
+#ifdef LNAMES
+#define matcher lmatcher
+#define fast lfast
+#define slow lslow
+#define dissect ldissect
+#define backref lbackref
+#define step lstep
+#define print lprint
+#define at lat
+#define match lmat
+#endif
+#ifdef MNAMES
+#define matcher mmatcher
+#define fast mfast
+#define slow mslow
+#define dissect mdissect
+#define backref mbackref
+#define step mstep
+#define print mprint
+#define at mat
+#define match mmat
+#endif
+
+/* another structure passed up and down to avoid zillions of parameters */
+struct match {
+ struct re_guts *g;
+ int eflags;
+ regmatch_t *pmatch; /* [nsub+1] (0 element unused) */
+ const char *offp; /* offsets work from here */
+ const char *beginp; /* start of string -- virtual NUL precedes */
+ const char *endp; /* end of string -- virtual NUL here */
+ const char *coldp; /* can be no match starting before here */
+ const char **lastpos; /* [nplus+1] */
+ STATEVARS;
+ states st; /* current states */
+ states fresh; /* states for a fresh start */
+ states tmp; /* temporary */
+ states empty; /* empty set of states */
+ mbstate_t mbs; /* multibyte conversion state */
+};
+
+/* ========= begin header generated by ./mkh ========= */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* === engine.c === */
+static int matcher(struct re_guts *g, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags);
+static const char *dissect(struct match *m, const char *start, const char *stop, sopno startst, sopno stopst);
+static const char *backref(struct match *m, const char *start, const char *stop, sopno startst, sopno stopst, sopno lev, int);
+static const char *fast(struct match *m, const char *start, const char *stop, sopno startst, sopno stopst);
+static const char *slow(struct match *m, const char *start, const char *stop, sopno startst, sopno stopst);
+static states step(struct re_guts *g, sopno start, sopno stop, states bef, wint_t ch, states aft);
+#define MAX_RECURSION 100
+#define BOL (OUT-1)
+#define EOL (BOL-1)
+#define BOLEOL (BOL-2)
+#define NOTHING (BOL-3)
+#define BOW (BOL-4)
+#define EOW (BOL-5)
+#define BADCHAR (BOL-6)
+#define NONCHAR(c) ((c) <= OUT)
+#ifdef REDEBUG
+static void print(struct match *m, const char *caption, states st, int ch, FILE *d);
+#endif
+#ifdef REDEBUG
+static void at(struct match *m, const char *title, const char *start, const char *stop, sopno startst, sopno stopst);
+#endif
+#ifdef REDEBUG
+static const char *pchar(int ch);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+/* ========= end header generated by ./mkh ========= */
+
+#ifdef REDEBUG
+#define SP(t, s, c) print(m, t, s, c, stdout)
+#define AT(t, p1, p2, s1, s2) at(m, t, p1, p2, s1, s2)
+#define NOTE(str) { if (m->eflags&REG_TRACE) printf("=%s\n", (str)); }
+#else
+#define SP(t, s, c) /* nothing */
+#define AT(t, p1, p2, s1, s2) /* nothing */
+#define NOTE(s) /* nothing */
+#endif
+
+/*
+ - matcher - the actual matching engine
+ == static int matcher(struct re_guts *g, const char *string, \
+ == size_t nmatch, regmatch_t pmatch[], int eflags);
+ */
+static int /* 0 success, REG_NOMATCH failure */
+matcher(struct re_guts *g,
+ const char *string,
+ size_t nmatch,
+ regmatch_t pmatch[],
+ int eflags)
+{
+ const char *endp;
+ size_t i;
+ struct match mv;
+ struct match *m = &mv;
+ const char *dp = NULL;
+ const sopno gf = g->firststate+1; /* +1 for OEND */
+ const sopno gl = g->laststate;
+ const char *start;
+ const char *stop;
+ /* Boyer-Moore algorithms variables */
+ const char *pp;
+ int cj, mj;
+ const char *mustfirst;
+ const char *mustlast;
+ int *matchjump;
+ int *charjump;
+
+ /* simplify the situation where possible */
+ if (g->cflags&REG_NOSUB)
+ nmatch = 0;
+ if (eflags&REG_STARTEND) {
+ start = string + pmatch[0].rm_so;
+ stop = string + pmatch[0].rm_eo;
+ } else {
+ start = string;
+ stop = start + strlen(start);
+ }
+ if (stop < start)
+ return(REG_INVARG);
+
+ /* prescreening; this does wonders for this rather slow code */
+ if (g->must != NULL) {
+ if (g->charjump != NULL && g->matchjump != NULL) {
+ mustfirst = g->must;
+ mustlast = g->must + g->mlen - 1;
+ charjump = g->charjump;
+ matchjump = g->matchjump;
+ pp = mustlast;
+ for (dp = start+g->mlen-1; dp < stop;) {
+ /* Fast skip non-matches */
+ while (dp < stop && charjump[(int)*dp])
+ dp += charjump[(int)*dp];
+
+ if (dp >= stop)
+ break;
+
+ /* Greedy matcher */
+ /* We depend on not being used for
+ * for strings of length 1
+ */
+ while (*--dp == *--pp && pp != mustfirst);
+
+ if (*dp == *pp)
+ break;
+
+ /* Jump to next possible match */
+ mj = matchjump[pp - mustfirst];
+ cj = charjump[(int)*dp];
+ dp += (cj < mj ? mj : cj);
+ pp = mustlast;
+ }
+ if (pp != mustfirst)
+ return(REG_NOMATCH);
+ } else {
+ for (dp = start; dp < stop; dp++)
+ if (*dp == g->must[0] &&
+ stop - dp >= g->mlen &&
+ memcmp(dp, g->must, (size_t)g->mlen) == 0)
+ break;
+ if (dp == stop) /* we didn't find g->must */
+ return(REG_NOMATCH);
+ }
+ }
+
+ /* match struct setup */
+ m->g = g;
+ m->eflags = eflags;
+ m->pmatch = NULL;
+ m->lastpos = NULL;
+ m->offp = string;
+ m->beginp = start;
+ m->endp = stop;
+ STATESETUP(m, 4);
+ SETUP(m->st);
+ SETUP(m->fresh);
+ SETUP(m->tmp);
+ SETUP(m->empty);
+ CLEAR(m->empty);
+ ZAPSTATE(&m->mbs);
+
+ /* Adjust start according to moffset, to speed things up */
+ if (dp != NULL && g->moffset > -1)
+ start = ((dp - g->moffset) < start) ? start : dp - g->moffset;
+
+ SP("mloop", m->st, *start);
+
+ /* this loop does only one repetition except for backrefs */
+ for (;;) {
+ endp = fast(m, start, stop, gf, gl);
+ if (endp == NULL) { /* a miss */
+ if (m->pmatch != NULL)
+ free((char *)m->pmatch);
+ if (m->lastpos != NULL)
+ free((char *)m->lastpos);
+ STATETEARDOWN(m);
+ return(REG_NOMATCH);
+ }
+ if (nmatch == 0 && !g->backrefs)
+ break; /* no further info needed */
+
+ /* where? */
+ assert(m->coldp != NULL);
+ for (;;) {
+ NOTE("finding start");
+ endp = slow(m, m->coldp, stop, gf, gl);
+ if (endp != NULL)
+ break;
+ assert(m->coldp < m->endp);
+ m->coldp += XMBRTOWC(NULL, m->coldp,
+ m->endp - m->coldp, &m->mbs, 0);
+ }
+ if (nmatch == 1 && !g->backrefs)
+ break; /* no further info needed */
+
+ /* oh my, he wants the subexpressions... */
+ if (m->pmatch == NULL)
+ m->pmatch = (regmatch_t *)malloc((m->g->nsub + 1) *
+ sizeof(regmatch_t));
+ if (m->pmatch == NULL) {
+ STATETEARDOWN(m);
+ return(REG_ESPACE);
+ }
+ for (i = 1; i <= m->g->nsub; i++)
+ m->pmatch[i].rm_so = m->pmatch[i].rm_eo = -1;
+ if (!g->backrefs && !(m->eflags&REG_BACKR)) {
+ NOTE("dissecting");
+ dp = dissect(m, m->coldp, endp, gf, gl);
+ } else {
+ if (g->nplus > 0 && m->lastpos == NULL)
+ m->lastpos = malloc((g->nplus+1) *
+ sizeof(const char *));
+ if (g->nplus > 0 && m->lastpos == NULL) {
+ free(m->pmatch);
+ STATETEARDOWN(m);
+ return(REG_ESPACE);
+ }
+ NOTE("backref dissect");
+ dp = backref(m, m->coldp, endp, gf, gl, (sopno)0, 0);
+ }
+ if (dp != NULL)
+ break;
+
+ /* uh-oh... we couldn't find a subexpression-level match */
+ assert(g->backrefs); /* must be back references doing it */
+ assert(g->nplus == 0 || m->lastpos != NULL);
+ for (;;) {
+ if (dp != NULL || endp <= m->coldp)
+ break; /* defeat */
+ NOTE("backoff");
+ endp = slow(m, m->coldp, endp-1, gf, gl);
+ if (endp == NULL)
+ break; /* defeat */
+ /* try it on a shorter possibility */
+#ifndef NDEBUG
+ for (i = 1; i <= m->g->nsub; i++) {
+ assert(m->pmatch[i].rm_so == -1);
+ assert(m->pmatch[i].rm_eo == -1);
+ }
+#endif
+ NOTE("backoff dissect");
+ dp = backref(m, m->coldp, endp, gf, gl, (sopno)0, 0);
+ }
+ assert(dp == NULL || dp == endp);
+ if (dp != NULL) /* found a shorter one */
+ break;
+
+ /* despite initial appearances, there is no match here */
+ NOTE("false alarm");
+ /* recycle starting later */
+ start = m->coldp + XMBRTOWC(NULL, m->coldp,
+ stop - m->coldp, &m->mbs, 0);
+ assert(start <= stop);
+ }
+
+ /* fill in the details if requested */
+ if (nmatch > 0) {
+ pmatch[0].rm_so = m->coldp - m->offp;
+ pmatch[0].rm_eo = endp - m->offp;
+ }
+ if (nmatch > 1) {
+ assert(m->pmatch != NULL);
+ for (i = 1; i < nmatch; i++)
+ if (i <= m->g->nsub)
+ pmatch[i] = m->pmatch[i];
+ else {
+ pmatch[i].rm_so = -1;
+ pmatch[i].rm_eo = -1;
+ }
+ }
+
+ if (m->pmatch != NULL)
+ free((char *)m->pmatch);
+ if (m->lastpos != NULL)
+ free((char *)m->lastpos);
+ STATETEARDOWN(m);
+ return(0);
+}
+
+/*
+ - dissect - figure out what matched what, no back references
+ == static const char *dissect(struct match *m, const char *start, \
+ == const char *stop, sopno startst, sopno stopst);
+ */
+static const char * /* == stop (success) always */
+dissect(struct match *m,
+ const char *start,
+ const char *stop,
+ sopno startst,
+ sopno stopst)
+{
+ int i;
+ sopno ss; /* start sop of current subRE */
+ sopno es; /* end sop of current subRE */
+ const char *sp; /* start of string matched by it */
+ const char *stp; /* string matched by it cannot pass here */
+ const char *rest; /* start of rest of string */
+ const char *tail; /* string unmatched by rest of RE */
+ sopno ssub; /* start sop of subsubRE */
+ sopno esub; /* end sop of subsubRE */
+ const char *ssp; /* start of string matched by subsubRE */
+ const char *sep; /* end of string matched by subsubRE */
+ const char *oldssp; /* previous ssp */
+ const char *dp;
+
+ AT("diss", start, stop, startst, stopst);
+ sp = start;
+ for (ss = startst; ss < stopst; ss = es) {
+ /* identify end of subRE */
+ es = ss;
+ switch (OP(m->g->strip[es])) {
+ case OPLUS_:
+ case OQUEST_:
+ es += OPND(m->g->strip[es]);
+ break;
+ case OCH_:
+ while (OP(m->g->strip[es]) != O_CH)
+ es += OPND(m->g->strip[es]);
+ break;
+ }
+ es++;
+
+ /* figure out what it matched */
+ switch (OP(m->g->strip[ss])) {
+ case OEND:
+ assert(nope);
+ break;
+ case OCHAR:
+ sp += XMBRTOWC(NULL, sp, stop - start, &m->mbs, 0);
+ break;
+ case OBOL:
+ case OEOL:
+ case OBOW:
+ case OEOW:
+ break;
+ case OANY:
+ case OANYOF:
+ sp += XMBRTOWC(NULL, sp, stop - start, &m->mbs, 0);
+ break;
+ case OBACK_:
+ case O_BACK:
+ assert(nope);
+ break;
+ /* cases where length of match is hard to find */
+ case OQUEST_:
+ stp = stop;
+ for (;;) {
+ /* how long could this one be? */
+ rest = slow(m, sp, stp, ss, es);
+ assert(rest != NULL); /* it did match */
+ /* could the rest match the rest? */
+ tail = slow(m, rest, stop, es, stopst);
+ if (tail == stop)
+ break; /* yes! */
+ /* no -- try a shorter match for this one */
+ stp = rest - 1;
+ assert(stp >= sp); /* it did work */
+ }
+ ssub = ss + 1;
+ esub = es - 1;
+ /* did innards match? */
+ if (slow(m, sp, rest, ssub, esub) != NULL) {
+ dp = dissect(m, sp, rest, ssub, esub);
+ assert(dp == rest);
+ } else /* no */
+ assert(sp == rest);
+ sp = rest;
+ break;
+ case OPLUS_:
+ stp = stop;
+ for (;;) {
+ /* how long could this one be? */
+ rest = slow(m, sp, stp, ss, es);
+ assert(rest != NULL); /* it did match */
+ /* could the rest match the rest? */
+ tail = slow(m, rest, stop, es, stopst);
+ if (tail == stop)
+ break; /* yes! */
+ /* no -- try a shorter match for this one */
+ stp = rest - 1;
+ assert(stp >= sp); /* it did work */
+ }
+ ssub = ss + 1;
+ esub = es - 1;
+ ssp = sp;
+ oldssp = ssp;
+ for (;;) { /* find last match of innards */
+ sep = slow(m, ssp, rest, ssub, esub);
+ if (sep == NULL || sep == ssp)
+ break; /* failed or matched null */
+ oldssp = ssp; /* on to next try */
+ ssp = sep;
+ }
+ if (sep == NULL) {
+ /* last successful match */
+ sep = ssp;
+ ssp = oldssp;
+ }
+ assert(sep == rest); /* must exhaust substring */
+ assert(slow(m, ssp, sep, ssub, esub) == rest);
+ dp = dissect(m, ssp, sep, ssub, esub);
+ assert(dp == sep);
+ sp = rest;
+ break;
+ case OCH_:
+ stp = stop;
+ for (;;) {
+ /* how long could this one be? */
+ rest = slow(m, sp, stp, ss, es);
+ assert(rest != NULL); /* it did match */
+ /* could the rest match the rest? */
+ tail = slow(m, rest, stop, es, stopst);
+ if (tail == stop)
+ break; /* yes! */
+ /* no -- try a shorter match for this one */
+ stp = rest - 1;
+ assert(stp >= sp); /* it did work */
+ }
+ ssub = ss + 1;
+ esub = ss + OPND(m->g->strip[ss]) - 1;
+ assert(OP(m->g->strip[esub]) == OOR1);
+ for (;;) { /* find first matching branch */
+ if (slow(m, sp, rest, ssub, esub) == rest)
+ break; /* it matched all of it */
+ /* that one missed, try next one */
+ assert(OP(m->g->strip[esub]) == OOR1);
+ esub++;
+ assert(OP(m->g->strip[esub]) == OOR2);
+ ssub = esub + 1;
+ esub += OPND(m->g->strip[esub]);
+ if (OP(m->g->strip[esub]) == OOR2)
+ esub--;
+ else
+ assert(OP(m->g->strip[esub]) == O_CH);
+ }
+ dp = dissect(m, sp, rest, ssub, esub);
+ assert(dp == rest);
+ sp = rest;
+ break;
+ case O_PLUS:
+ case O_QUEST:
+ case OOR1:
+ case OOR2:
+ case O_CH:
+ assert(nope);
+ break;
+ case OLPAREN:
+ i = OPND(m->g->strip[ss]);
+ assert(0 < i && i <= m->g->nsub);
+ m->pmatch[i].rm_so = sp - m->offp;
+ break;
+ case ORPAREN:
+ i = OPND(m->g->strip[ss]);
+ assert(0 < i && i <= m->g->nsub);
+ m->pmatch[i].rm_eo = sp - m->offp;
+ break;
+ default: /* uh oh */
+ assert(nope);
+ break;
+ }
+ }
+
+ assert(sp == stop);
+ return(sp);
+}
+
+/*
+ - backref - figure out what matched what, figuring in back references
+ == static const char *backref(struct match *m, const char *start, \
+ == const char *stop, sopno startst, sopno stopst, sopno lev);
+ */
+static const char * /* == stop (success) or NULL (failure) */
+backref(struct match *m,
+ const char *start,
+ const char *stop,
+ sopno startst,
+ sopno stopst,
+ sopno lev, /* PLUS nesting level */
+ int rec)
+{
+ int i;
+ sopno ss; /* start sop of current subRE */
+ const char *sp; /* start of string matched by it */
+ sopno ssub; /* start sop of subsubRE */
+ sopno esub; /* end sop of subsubRE */
+ const char *ssp; /* start of string matched by subsubRE */
+ const char *dp;
+ size_t len;
+ int hard;
+ sop s;
+ regoff_t offsave;
+ cset *cs;
+ wint_t wc;
+
+ AT("back", start, stop, startst, stopst);
+ sp = start;
+
+ /* get as far as we can with easy stuff */
+ hard = 0;
+ for (ss = startst; !hard && ss < stopst; ss++)
+ switch (OP(s = m->g->strip[ss])) {
+ case OCHAR:
+ if (sp == stop)
+ return(NULL);
+ sp += XMBRTOWC(&wc, sp, stop - sp, &m->mbs, BADCHAR);
+ if (wc != OPND(s))
+ return(NULL);
+ break;
+ case OANY:
+ if (sp == stop)
+ return(NULL);
+ sp += XMBRTOWC(&wc, sp, stop - sp, &m->mbs, BADCHAR);
+ if (wc == BADCHAR)
+ return (NULL);
+ break;
+ case OANYOF:
+ if (sp == stop)
+ return (NULL);
+ cs = &m->g->sets[OPND(s)];
+ sp += XMBRTOWC(&wc, sp, stop - sp, &m->mbs, BADCHAR);
+ if (wc == BADCHAR || !CHIN(cs, wc))
+ return(NULL);
+ break;
+ case OBOL:
+ if ((sp == m->beginp && !(m->eflags&REG_NOTBOL)) ||
+ (sp > m->offp && sp < m->endp &&
+ *(sp-1) == '\n' && (m->g->cflags&REG_NEWLINE)))
+ { /* yes */ }
+ else
+ return(NULL);
+ break;
+ case OEOL:
+ if ( (sp == m->endp && !(m->eflags&REG_NOTEOL)) ||
+ (sp < m->endp && *sp == '\n' &&
+ (m->g->cflags&REG_NEWLINE)) )
+ { /* yes */ }
+ else
+ return(NULL);
+ break;
+ case OBOW:
+ if (sp < m->endp && ISWORD(*sp) &&
+ ((sp == m->beginp && !(m->eflags&REG_NOTBOL)) ||
+ (sp > m->offp && !ISWORD(*(sp-1)))))
+ { /* yes */ }
+ else
+ return(NULL);
+ break;
+ case OEOW:
+ if (( (sp == m->endp && !(m->eflags&REG_NOTEOL)) ||
+ (sp < m->endp && *sp == '\n' &&
+ (m->g->cflags&REG_NEWLINE)) ||
+ (sp < m->endp && !ISWORD(*sp)) ) &&
+ (sp > m->beginp && ISWORD(*(sp-1))) )
+ { /* yes */ }
+ else
+ return(NULL);
+ break;
+ case O_QUEST:
+ break;
+ case OOR1: /* matches null but needs to skip */
+ ss++;
+ s = m->g->strip[ss];
+ do {
+ assert(OP(s) == OOR2);
+ ss += OPND(s);
+ } while (OP(s = m->g->strip[ss]) != O_CH);
+ /* note that the ss++ gets us past the O_CH */
+ break;
+ default: /* have to make a choice */
+ hard = 1;
+ break;
+ }
+ if (!hard) { /* that was it! */
+ if (sp != stop)
+ return(NULL);
+ return(sp);
+ }
+ ss--; /* adjust for the for's final increment */
+
+ /* the hard stuff */
+ AT("hard", sp, stop, ss, stopst);
+ s = m->g->strip[ss];
+ switch (OP(s)) {
+ case OBACK_: /* the vilest depths */
+ i = OPND(s);
+ assert(0 < i && i <= m->g->nsub);
+ if (m->pmatch[i].rm_eo == -1)
+ return(NULL);
+ assert(m->pmatch[i].rm_so != -1);
+ len = m->pmatch[i].rm_eo - m->pmatch[i].rm_so;
+ if (len == 0 && rec++ > MAX_RECURSION)
+ return(NULL);
+ assert(stop - m->beginp >= len);
+ if (sp > stop - len)
+ return(NULL); /* not enough left to match */
+ ssp = m->offp + m->pmatch[i].rm_so;
+ if (memcmp(sp, ssp, len) != 0)
+ return(NULL);
+ while (m->g->strip[ss] != SOP(O_BACK, i))
+ ss++;
+ return(backref(m, sp+len, stop, ss+1, stopst, lev, rec));
+ case OQUEST_: /* to null or not */
+ dp = backref(m, sp, stop, ss+1, stopst, lev, rec);
+ if (dp != NULL)
+ return(dp); /* not */
+ return(backref(m, sp, stop, ss+OPND(s)+1, stopst, lev, rec));
+ case OPLUS_:
+ assert(m->lastpos != NULL);
+ assert(lev+1 <= m->g->nplus);
+ m->lastpos[lev+1] = sp;
+ return(backref(m, sp, stop, ss+1, stopst, lev+1, rec));
+ case O_PLUS:
+ if (sp == m->lastpos[lev]) /* last pass matched null */
+ return(backref(m, sp, stop, ss+1, stopst, lev-1, rec));
+ /* try another pass */
+ m->lastpos[lev] = sp;
+ dp = backref(m, sp, stop, ss-OPND(s)+1, stopst, lev, rec);
+ if (dp == NULL)
+ return(backref(m, sp, stop, ss+1, stopst, lev-1, rec));
+ else
+ return(dp);
+ case OCH_: /* find the right one, if any */
+ ssub = ss + 1;
+ esub = ss + OPND(s) - 1;
+ assert(OP(m->g->strip[esub]) == OOR1);
+ for (;;) { /* find first matching branch */
+ dp = backref(m, sp, stop, ssub, esub, lev, rec);
+ if (dp != NULL)
+ return(dp);
+ /* that one missed, try next one */
+ if (OP(m->g->strip[esub]) == O_CH)
+ return(NULL); /* there is none */
+ esub++;
+ assert(OP(m->g->strip[esub]) == OOR2);
+ ssub = esub + 1;
+ esub += OPND(m->g->strip[esub]);
+ if (OP(m->g->strip[esub]) == OOR2)
+ esub--;
+ else
+ assert(OP(m->g->strip[esub]) == O_CH);
+ }
+ /* NOTREACHED */
+ break;
+ case OLPAREN: /* must undo assignment if rest fails */
+ i = OPND(s);
+ assert(0 < i && i <= m->g->nsub);
+ offsave = m->pmatch[i].rm_so;
+ m->pmatch[i].rm_so = sp - m->offp;
+ dp = backref(m, sp, stop, ss+1, stopst, lev, rec);
+ if (dp != NULL)
+ return(dp);
+ m->pmatch[i].rm_so = offsave;
+ return(NULL);
+ case ORPAREN: /* must undo assignment if rest fails */
+ i = OPND(s);
+ assert(0 < i && i <= m->g->nsub);
+ offsave = m->pmatch[i].rm_eo;
+ m->pmatch[i].rm_eo = sp - m->offp;
+ dp = backref(m, sp, stop, ss+1, stopst, lev, rec);
+ if (dp != NULL)
+ return(dp);
+ m->pmatch[i].rm_eo = offsave;
+ return(NULL);
+ default: /* uh oh */
+ assert(nope);
+ break;
+ }
+
+ /* "can't happen" */
+ assert(nope);
+ /* NOTREACHED */
+ return "shut up gcc";
+}
+
+/*
+ - fast - step through the string at top speed
+ == static const char *fast(struct match *m, const char *start, \
+ == const char *stop, sopno startst, sopno stopst);
+ */
+static const char * /* where tentative match ended, or NULL */
+fast( struct match *m,
+ const char *start,
+ const char *stop,
+ sopno startst,
+ sopno stopst)
+{
+ states st = m->st;
+ states fresh = m->fresh;
+ states tmp = m->tmp;
+ const char *p = start;
+ wint_t c;
+ wint_t lastc; /* previous c */
+ wint_t flagch;
+ int i;
+ const char *coldp; /* last p after which no match was underway */
+ size_t clen;
+
+ CLEAR(st);
+ SET1(st, startst);
+ SP("fast", st, *p);
+ st = step(m->g, startst, stopst, st, NOTHING, st);
+ ASSIGN(fresh, st);
+ SP("start", st, *p);
+ coldp = NULL;
+ if (start == m->offp || (start == m->beginp && !(m->eflags&REG_NOTBOL)))
+ c = OUT;
+ else {
+ /*
+ * XXX Wrong if the previous character was multi-byte.
+ * Newline never is (in encodings supported by FreeBSD),
+ * so this only breaks the ISWORD tests below.
+ */
+ c = (uch)*(start - 1);
+ }
+ for (;;) {
+ /* next character */
+ lastc = c;
+ if (p == m->endp) {
+ clen = 0;
+ c = OUT;
+ } else
+ clen = XMBRTOWC(&c, p, m->endp - p, &m->mbs, BADCHAR);
+ if (EQ(st, fresh))
+ coldp = p;
+
+ /* is there an EOL and/or BOL between lastc and c? */
+ flagch = '\0';
+ i = 0;
+ if ( (lastc == '\n' && m->g->cflags&REG_NEWLINE) ||
+ (lastc == OUT && !(m->eflags&REG_NOTBOL)) ) {
+ flagch = BOL;
+ i = m->g->nbol;
+ }
+ if ( (c == '\n' && m->g->cflags&REG_NEWLINE) ||
+ (c == OUT && !(m->eflags&REG_NOTEOL)) ) {
+ flagch = (flagch == BOL) ? BOLEOL : EOL;
+ i += m->g->neol;
+ }
+ if (i != 0) {
+ for (; i > 0; i--)
+ st = step(m->g, startst, stopst, st, flagch, st);
+ SP("boleol", st, c);
+ }
+
+ /* how about a word boundary? */
+ if ( (flagch == BOL || (lastc != OUT && !ISWORD(lastc))) &&
+ (c != OUT && ISWORD(c)) ) {
+ flagch = BOW;
+ }
+ if ( (lastc != OUT && ISWORD(lastc)) &&
+ (flagch == EOL || (c != OUT && !ISWORD(c))) ) {
+ flagch = EOW;
+ }
+ if (flagch == BOW || flagch == EOW) {
+ st = step(m->g, startst, stopst, st, flagch, st);
+ SP("boweow", st, c);
+ }
+
+ /* are we done? */
+ if (ISSET(st, stopst) || p == stop || clen > stop - p)
+ break; /* NOTE BREAK OUT */
+
+ /* no, we must deal with this character */
+ ASSIGN(tmp, st);
+ ASSIGN(st, fresh);
+ assert(c != OUT);
+ st = step(m->g, startst, stopst, tmp, c, st);
+ SP("aft", st, c);
+ assert(EQ(step(m->g, startst, stopst, st, NOTHING, st), st));
+ p += clen;
+ }
+
+ assert(coldp != NULL);
+ m->coldp = coldp;
+ if (ISSET(st, stopst))
+ return(p+XMBRTOWC(NULL, p, stop - p, &m->mbs, 0));
+ else
+ return(NULL);
+}
+
+/*
+ - slow - step through the string more deliberately
+ == static const char *slow(struct match *m, const char *start, \
+ == const char *stop, sopno startst, sopno stopst);
+ */
+static const char * /* where it ended */
+slow( struct match *m,
+ const char *start,
+ const char *stop,
+ sopno startst,
+ sopno stopst)
+{
+ states st = m->st;
+ states empty = m->empty;
+ states tmp = m->tmp;
+ const char *p = start;
+ wint_t c;
+ wint_t lastc; /* previous c */
+ wint_t flagch;
+ int i;
+ const char *matchp; /* last p at which a match ended */
+ size_t clen;
+
+ AT("slow", start, stop, startst, stopst);
+ CLEAR(st);
+ SET1(st, startst);
+ SP("sstart", st, *p);
+ st = step(m->g, startst, stopst, st, NOTHING, st);
+ matchp = NULL;
+ if (start == m->offp || (start == m->beginp && !(m->eflags&REG_NOTBOL)))
+ c = OUT;
+ else {
+ /*
+ * XXX Wrong if the previous character was multi-byte.
+ * Newline never is (in encodings supported by FreeBSD),
+ * so this only breaks the ISWORD tests below.
+ */
+ c = (uch)*(start - 1);
+ }
+ for (;;) {
+ /* next character */
+ lastc = c;
+ if (p == m->endp) {
+ c = OUT;
+ clen = 0;
+ } else
+ clen = XMBRTOWC(&c, p, m->endp - p, &m->mbs, BADCHAR);
+
+ /* is there an EOL and/or BOL between lastc and c? */
+ flagch = '\0';
+ i = 0;
+ if ( (lastc == '\n' && m->g->cflags&REG_NEWLINE) ||
+ (lastc == OUT && !(m->eflags&REG_NOTBOL)) ) {
+ flagch = BOL;
+ i = m->g->nbol;
+ }
+ if ( (c == '\n' && m->g->cflags&REG_NEWLINE) ||
+ (c == OUT && !(m->eflags&REG_NOTEOL)) ) {
+ flagch = (flagch == BOL) ? BOLEOL : EOL;
+ i += m->g->neol;
+ }
+ if (i != 0) {
+ for (; i > 0; i--)
+ st = step(m->g, startst, stopst, st, flagch, st);
+ SP("sboleol", st, c);
+ }
+
+ /* how about a word boundary? */
+ if ( (flagch == BOL || (lastc != OUT && !ISWORD(lastc))) &&
+ (c != OUT && ISWORD(c)) ) {
+ flagch = BOW;
+ }
+ if ( (lastc != OUT && ISWORD(lastc)) &&
+ (flagch == EOL || (c != OUT && !ISWORD(c))) ) {
+ flagch = EOW;
+ }
+ if (flagch == BOW || flagch == EOW) {
+ st = step(m->g, startst, stopst, st, flagch, st);
+ SP("sboweow", st, c);
+ }
+
+ /* are we done? */
+ if (ISSET(st, stopst))
+ matchp = p;
+ if (EQ(st, empty) || p == stop || clen > stop - p)
+ break; /* NOTE BREAK OUT */
+
+ /* no, we must deal with this character */
+ ASSIGN(tmp, st);
+ ASSIGN(st, empty);
+ assert(c != OUT);
+ st = step(m->g, startst, stopst, tmp, c, st);
+ SP("saft", st, c);
+ assert(EQ(step(m->g, startst, stopst, st, NOTHING, st), st));
+ p += clen;
+ }
+
+ return(matchp);
+}
+
+
+/*
+ - step - map set of states reachable before char to set reachable after
+ == static states step(struct re_guts *g, sopno start, sopno stop, \
+ == states bef, int ch, states aft);
+ == #define BOL (OUT-1)
+ == #define EOL (BOL-1)
+ == #define BOLEOL (BOL-2)
+ == #define NOTHING (BOL-3)
+ == #define BOW (BOL-4)
+ == #define EOW (BOL-5)
+ == #define BADCHAR (BOL-6)
+ == #define NONCHAR(c) ((c) <= OUT)
+ */
+static states
+step(struct re_guts *g,
+ sopno start, /* start state within strip */
+ sopno stop, /* state after stop state within strip */
+ states bef, /* states reachable before */
+ wint_t ch, /* character or NONCHAR code */
+ states aft) /* states already known reachable after */
+{
+ cset *cs;
+ sop s;
+ sopno pc;
+ onestate here; /* note, macros know this name */
+ sopno look;
+ int i;
+
+ for (pc = start, INIT(here, pc); pc != stop; pc++, INC(here)) {
+ s = g->strip[pc];
+ switch (OP(s)) {
+ case OEND:
+ assert(pc == stop-1);
+ break;
+ case OCHAR:
+ /* only characters can match */
+ assert(!NONCHAR(ch) || ch != OPND(s));
+ if (ch == OPND(s))
+ FWD(aft, bef, 1);
+ break;
+ case OBOL:
+ if (ch == BOL || ch == BOLEOL)
+ FWD(aft, bef, 1);
+ break;
+ case OEOL:
+ if (ch == EOL || ch == BOLEOL)
+ FWD(aft, bef, 1);
+ break;
+ case OBOW:
+ if (ch == BOW)
+ FWD(aft, bef, 1);
+ break;
+ case OEOW:
+ if (ch == EOW)
+ FWD(aft, bef, 1);
+ break;
+ case OANY:
+ if (!NONCHAR(ch))
+ FWD(aft, bef, 1);
+ break;
+ case OANYOF:
+ cs = &g->sets[OPND(s)];
+ if (!NONCHAR(ch) && CHIN(cs, ch))
+ FWD(aft, bef, 1);
+ break;
+ case OBACK_: /* ignored here */
+ case O_BACK:
+ FWD(aft, aft, 1);
+ break;
+ case OPLUS_: /* forward, this is just an empty */
+ FWD(aft, aft, 1);
+ break;
+ case O_PLUS: /* both forward and back */
+ FWD(aft, aft, 1);
+ i = ISSETBACK(aft, OPND(s));
+ BACK(aft, aft, OPND(s));
+ if (!i && ISSETBACK(aft, OPND(s))) {
+ /* oho, must reconsider loop body */
+ pc -= OPND(s) + 1;
+ INIT(here, pc);
+ }
+ break;
+ case OQUEST_: /* two branches, both forward */
+ FWD(aft, aft, 1);
+ FWD(aft, aft, OPND(s));
+ break;
+ case O_QUEST: /* just an empty */
+ FWD(aft, aft, 1);
+ break;
+ case OLPAREN: /* not significant here */
+ case ORPAREN:
+ FWD(aft, aft, 1);
+ break;
+ case OCH_: /* mark the first two branches */
+ FWD(aft, aft, 1);
+ assert(OP(g->strip[pc+OPND(s)]) == OOR2);
+ FWD(aft, aft, OPND(s));
+ break;
+ case OOR1: /* done a branch, find the O_CH */
+ if (ISSTATEIN(aft, here)) {
+ for (look = 1;
+ OP(s = g->strip[pc+look]) != O_CH;
+ look += OPND(s))
+ assert(OP(s) == OOR2);
+ FWD(aft, aft, look + 1);
+ }
+ break;
+ case OOR2: /* propagate OCH_'s marking */
+ FWD(aft, aft, 1);
+ if (OP(g->strip[pc+OPND(s)]) != O_CH) {
+ assert(OP(g->strip[pc+OPND(s)]) == OOR2);
+ FWD(aft, aft, OPND(s));
+ }
+ break;
+ case O_CH: /* just empty */
+ FWD(aft, aft, 1);
+ break;
+ default: /* ooooops... */
+ assert(nope);
+ break;
+ }
+ }
+
+ return(aft);
+}
+
+#ifdef REDEBUG
+/*
+ - print - print a set of states
+ == #ifdef REDEBUG
+ == static void print(struct match *m, const char *caption, states st, \
+ == int ch, FILE *d);
+ == #endif
+ */
+static void
+print(struct match *m,
+ const char *caption,
+ states st,
+ int ch,
+ FILE *d)
+{
+ struct re_guts *g = m->g;
+ sopno i;
+ int first = 1;
+
+ if (!(m->eflags&REG_TRACE))
+ return;
+
+ fprintf(d, "%s", caption);
+ if (ch != '\0')
+ fprintf(d, " %s", pchar(ch));
+ for (i = 0; i < g->nstates; i++)
+ if (ISSET(st, i)) {
+ fprintf(d, "%s%d", (first) ? "\t" : ", ", i);
+ first = 0;
+ }
+ fprintf(d, "\n");
+}
+
+/*
+ - at - print current situation
+ == #ifdef REDEBUG
+ == static void at(struct match *m, const char *title, const char *start, \
+ == const char *stop, sopno startst, sopno stopst);
+ == #endif
+ */
+static void
+at( struct match *m,
+ const char *title,
+ const char *start,
+ const char *stop,
+ sopno startst,
+ sopno stopst)
+{
+ if (!(m->eflags&REG_TRACE))
+ return;
+
+ printf("%s %s-", title, pchar(*start));
+ printf("%s ", pchar(*stop));
+ printf("%ld-%ld\n", (long)startst, (long)stopst);
+}
+
+#ifndef PCHARDONE
+#define PCHARDONE /* never again */
+/*
+ - pchar - make a character printable
+ == #ifdef REDEBUG
+ == static const char *pchar(int ch);
+ == #endif
+ *
+ * Is this identical to regchar() over in debug.c? Well, yes. But a
+ * duplicate here avoids having a debugging-capable regexec.o tied to
+ * a matching debug.o, and this is convenient. It all disappears in
+ * the non-debug compilation anyway, so it doesn't matter much.
+ */
+static const char * /* -> representation */
+pchar(int ch)
+{
+ static char pbuf[10];
+
+ if (isprint((uch)ch) || ch == ' ')
+ sprintf(pbuf, "%c", ch);
+ else
+ sprintf(pbuf, "\\%o", ch);
+ return(pbuf);
+}
+#endif
+#endif
+
+#undef matcher
+#undef fast
+#undef slow
+#undef dissect
+#undef backref
+#undef step
+#undef print
+#undef at
+#undef match
diff --git a/lib/libc/regex/grot/Makefile b/lib/libc/regex/grot/Makefile
new file mode 100644
index 000000000000..d0123883cd2e
--- /dev/null
+++ b/lib/libc/regex/grot/Makefile
@@ -0,0 +1,99 @@
+# $FreeBSD$
+# You probably want to take -DREDEBUG out of CFLAGS, and put something like
+# -O in, *after* testing (-DREDEBUG strengthens testing by enabling a lot of
+# internal assertion checking). Take -Dconst= out for an ANSI compiler.
+# Do not take -DPOSIX_MISTAKE out. REGCFLAGS isn't important to you (it's
+# for my use in some special contexts).
+
+PATHS= ${LIBC_SRCTOP}/regex ${LIBC_SRCTOP}/locale ${SRCTOP}/include
+.PATH: ${PATHS}
+
+CFLAGS+= -static -DPOSIX_MISTAKE -DREDEBUG $(REGCFLAGS)
+.for incpath in ${PATHS}
+CFLAGS+= -I${incpath}
+.endfor
+
+# If you have an ANSI compiler, take -o out of MKHFLAGS. If you want
+# the Berkeley __P macro, put -b in.
+MKHFLAGS =
+
+LDFLAGS =
+
+# If you have an ANSI environment, take limits.h and stdlib.h out of
+# HMISSING and take memmove out of SRCMISSING and OBJMISSING.
+HMISSING =
+SRCMISSING = split.c
+OBJMISSING = split.o
+H = cname.h regex2.h utils.h $(HMISSING)
+REGSRC = regcomp.c regerror.c regexec.c regfree.c engine.c
+SRC = $(REGSRC) debug.c main.c $(SRCMISSING)
+
+# Internal stuff, should not need changing.
+OBJPRODN = regcomp.o regexec.o regerror.o regfree.o
+OBJS = $(OBJPRODN) debug.o main.o $(OBJMISSING)
+
+# Stuff that matters only if you're trying to lint the package.
+LINTFLAGS = -I. -Dstatic= -Dconst= -DREDEBUG
+LINTC = regcomp.c regexec.c regerror.c regfree.c debug.c main.c $(SRCMISSING)
+JUNKLINT =possible pointer alignment|null effect
+
+.SUFFIXES: .ih .h
+.c.ih:
+ sh mkh $(MKHFLAGS) -p $< >$@
+
+default: r
+
+re: $(OBJS)
+ $(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) -o $@
+
+o: $(OBJPRODN)
+
+REGEXHSRC = ../regex2.h ../reg*.c
+h: $(REGEXHSRC)
+ sh mkh $(MKHFLAGS) -i _REGEX_H_ $(REGEXHSRC) >regex.tmp
+ cmp -s regex.tmp regex.h 2>/dev/null || cp regex.tmp regex.h
+ rm -f regex.tmp
+
+regex.h: h
+
+regcomp.o regexec.o regfree.o debug.o: utils.h regex.h regex2.h
+regcomp.o: cname.h regcomp.ih
+regexec.o: engine.c engine.ih
+regerror.o: regerror.ih
+regerror.o: utils.h
+debug.o: debug.ih
+main.o: debug.ih main.ih split.ih
+split.o: split.ih
+
+r: re tests
+ ./re <tests
+ ./re -el <tests
+ ./re -er <tests
+
+ra: ./re tests
+ -./re <tests
+ -./re -el <tests
+ -./re -er <tests
+
+rx: ./re tests
+ ./re -x <tests
+ ./re -x -el <tests
+ ./re -x -er <tests
+
+t: ./re tests
+ -time ./re <tests
+ -time ./re -cs <tests
+ -time ./re -el <tests
+ -time ./re -cs -el <tests
+
+l: $(LINTC)
+ lint $(LINTFLAGS) -h $(LINTC) 2>&1 | egrep -v '$(JUNKLINT)' | tee lint
+
+clean: tidy
+ rm -f *.o *.s *.ih re
+
+tidy:
+ rm -f junk* core regex.tmp lint
+
+spotless: clean
+ rm -f regex.h
diff --git a/lib/libc/regex/grot/debug.c b/lib/libc/regex/grot/debug.c
new file mode 100644
index 000000000000..af8e4f5a1d72
--- /dev/null
+++ b/lib/libc/regex/grot/debug.c
@@ -0,0 +1,212 @@
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <regex.h>
+#include <wchar.h>
+#include <wctype.h>
+
+#include "utils.h"
+#include "regex2.h"
+#include "debug.ih"
+
+/*
+ - regprint - print a regexp for debugging
+ == void regprint(regex_t *r, FILE *d);
+ */
+void
+regprint(r, d)
+regex_t *r;
+FILE *d;
+{
+ struct re_guts *g = r->re_g;
+ int i;
+ int c;
+ int last;
+
+ fprintf(d, "%ld states", (long)g->nstates);
+ fprintf(d, ", first %ld last %ld", (long)g->firststate,
+ (long)g->laststate);
+ if (g->iflags&USEBOL)
+ fprintf(d, ", USEBOL");
+ if (g->iflags&USEEOL)
+ fprintf(d, ", USEEOL");
+ if (g->iflags&BAD)
+ fprintf(d, ", BAD");
+ if (g->nsub > 0)
+ fprintf(d, ", nsub=%ld", (long)g->nsub);
+ if (g->must != NULL)
+ fprintf(d, ", must(%ld) `%*s'", (long)g->mlen, (int)g->mlen,
+ g->must);
+ if (g->backrefs)
+ fprintf(d, ", backrefs");
+ if (g->nplus > 0)
+ fprintf(d, ", nplus %ld", (long)g->nplus);
+ fprintf(d, "\n");
+ s_print(g, d);
+}
+
+/*
+ - s_print - print the strip for debugging
+ == static void s_print(struct re_guts *g, FILE *d);
+ */
+static void
+s_print(g, d)
+struct re_guts *g;
+FILE *d;
+{
+ sop *s;
+ cset *cs;
+ int i;
+ int done = 0;
+ sop opnd;
+ int col = 0;
+ int last;
+ sopno offset = 2;
+# define GAP() { if (offset % 5 == 0) { \
+ if (col > 40) { \
+ fprintf(d, "\n\t"); \
+ col = 0; \
+ } else { \
+ fprintf(d, " "); \
+ col++; \
+ } \
+ } else \
+ col++; \
+ offset++; \
+ }
+
+ if (OP(g->strip[0]) != OEND)
+ fprintf(d, "missing initial OEND!\n");
+ for (s = &g->strip[1]; !done; s++) {
+ opnd = OPND(*s);
+ switch (OP(*s)) {
+ case OEND:
+ fprintf(d, "\n");
+ done = 1;
+ break;
+ case OCHAR:
+ if (strchr("\\|()^$.[+*?{}!<> ", (char)opnd) != NULL)
+ fprintf(d, "\\%c", (char)opnd);
+ else
+ fprintf(d, "%s", regchar((char)opnd));
+ break;
+ case OBOL:
+ fprintf(d, "^");
+ break;
+ case OEOL:
+ fprintf(d, "$");
+ break;
+ case OBOW:
+ fprintf(d, "\\{");
+ break;
+ case OEOW:
+ fprintf(d, "\\}");
+ break;
+ case OANY:
+ fprintf(d, ".");
+ break;
+ case OANYOF:
+ fprintf(d, "[(%ld)", (long)opnd);
+#if 0
+ cs = &g->sets[opnd];
+ last = -1;
+ for (i = 0; i < g->csetsize+1; i++) /* +1 flushes */
+ if (CHIN(cs, i) && i < g->csetsize) {
+ if (last < 0) {
+ fprintf(d, "%s", regchar(i));
+ last = i;
+ }
+ } else {
+ if (last >= 0) {
+ if (last != i-1)
+ fprintf(d, "-%s",
+ regchar(i-1));
+ last = -1;
+ }
+ }
+#endif
+ fprintf(d, "]");
+ break;
+ case OBACK_:
+ fprintf(d, "(\\<%ld>", (long)opnd);
+ break;
+ case O_BACK:
+ fprintf(d, "<%ld>\\)", (long)opnd);
+ break;
+ case OPLUS_:
+ fprintf(d, "(+");
+ if (OP(*(s+opnd)) != O_PLUS)
+ fprintf(d, "<%ld>", (long)opnd);
+ break;
+ case O_PLUS:
+ if (OP(*(s-opnd)) != OPLUS_)
+ fprintf(d, "<%ld>", (long)opnd);
+ fprintf(d, "+)");
+ break;
+ case OQUEST_:
+ fprintf(d, "(?");
+ if (OP(*(s+opnd)) != O_QUEST)
+ fprintf(d, "<%ld>", (long)opnd);
+ break;
+ case O_QUEST:
+ if (OP(*(s-opnd)) != OQUEST_)
+ fprintf(d, "<%ld>", (long)opnd);
+ fprintf(d, "?)");
+ break;
+ case OLPAREN:
+ fprintf(d, "((<%ld>", (long)opnd);
+ break;
+ case ORPAREN:
+ fprintf(d, "<%ld>))", (long)opnd);
+ break;
+ case OCH_:
+ fprintf(d, "<");
+ if (OP(*(s+opnd)) != OOR2)
+ fprintf(d, "<%ld>", (long)opnd);
+ break;
+ case OOR1:
+ if (OP(*(s-opnd)) != OOR1 && OP(*(s-opnd)) != OCH_)
+ fprintf(d, "<%ld>", (long)opnd);
+ fprintf(d, "|");
+ break;
+ case OOR2:
+ fprintf(d, "|");
+ if (OP(*(s+opnd)) != OOR2 && OP(*(s+opnd)) != O_CH)
+ fprintf(d, "<%ld>", (long)opnd);
+ break;
+ case O_CH:
+ if (OP(*(s-opnd)) != OOR1)
+ fprintf(d, "<%ld>", (long)opnd);
+ fprintf(d, ">");
+ break;
+ default:
+ fprintf(d, "!%ld(%ld)!", OP(*s), (long)opnd);
+ break;
+ }
+ if (!done)
+ GAP();
+ }
+}
+
+/*
+ - regchar - make a character printable
+ == static char *regchar(int ch);
+ */
+static char * /* -> representation */
+regchar(ch)
+int ch;
+{
+ static char buf[10];
+
+ if (isprint(ch) || ch == ' ')
+ sprintf(buf, "%c", ch);
+ else
+ sprintf(buf, "\\%o", ch);
+ return(buf);
+}
diff --git a/lib/libc/regex/grot/main.c b/lib/libc/regex/grot/main.c
new file mode 100644
index 000000000000..eee541bac171
--- /dev/null
+++ b/lib/libc/regex/grot/main.c
@@ -0,0 +1,494 @@
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <assert.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "debug.ih"
+#include "main.ih"
+#include "split.ih"
+
+char *progname;
+int debug = 0;
+int line = 0;
+int status = 0;
+
+int copts = REG_EXTENDED;
+int eopts = 0;
+regoff_t startoff = 0;
+regoff_t endoff = 0;
+
+
+/*
+ - main - do the simple case, hand off to regress() for regression
+ */
+int
+main(int argc, char **argv)
+{
+ regex_t re;
+# define NS 10
+ regmatch_t subs[NS];
+ char erbuf[100];
+ int err;
+ size_t len;
+ int c;
+ int errflg = 0;
+ int i;
+ extern int optind;
+ extern char *optarg;
+
+ progname = argv[0];
+
+ while ((c = getopt(argc, argv, "c:e:S:E:x")) != -1)
+ switch (c) {
+ case 'c': /* compile options */
+ copts = options('c', optarg);
+ break;
+ case 'e': /* execute options */
+ eopts = options('e', optarg);
+ break;
+ case 'S': /* start offset */
+ startoff = (regoff_t)atoi(optarg);
+ break;
+ case 'E': /* end offset */
+ endoff = (regoff_t)atoi(optarg);
+ break;
+ case 'x': /* Debugging. */
+ debug++;
+ break;
+ case '?':
+ default:
+ errflg++;
+ break;
+ }
+ if (errflg) {
+ fprintf(stderr, "usage: %s ", progname);
+ fprintf(stderr, "[-c copt][-C][-d] [re]\n");
+ exit(2);
+ }
+
+ if (optind >= argc) {
+ regress(stdin);
+ exit(status);
+ }
+
+ err = regcomp(&re, argv[optind++], copts);
+ if (err) {
+ len = regerror(err, &re, erbuf, sizeof(erbuf));
+ fprintf(stderr, "error %s, %zu/%zu `%s'\n",
+ eprint(err), len, sizeof(erbuf), erbuf);
+ exit(status);
+ }
+ regprint(&re, stdout);
+
+ if (optind >= argc) {
+ regfree(&re);
+ exit(status);
+ }
+
+ if ((eopts & REG_STARTEND) != 0) {
+ subs[0].rm_so = startoff;
+ subs[0].rm_eo = strlen(argv[optind]) - endoff;
+ }
+ err = regexec(&re, argv[optind], (size_t)NS, subs, eopts);
+ if (err) {
+ len = regerror(err, &re, erbuf, sizeof(erbuf));
+ fprintf(stderr, "error %s, %zu/%zu `%s'\n",
+ eprint(err), len, sizeof(erbuf), erbuf);
+ exit(status);
+ }
+ if ((copts & REG_NOSUB) == 0) {
+ len = (int)(subs[0].rm_eo - subs[0].rm_so);
+ if (subs[0].rm_so != -1) {
+ if (len != 0)
+ printf("match `%.*s'\n", (int)len,
+ argv[optind] + subs[0].rm_so);
+ else
+ printf("match `'@%.1s\n",
+ argv[optind] + subs[0].rm_so);
+ }
+ for (i = 1; i < NS; i++)
+ if (subs[i].rm_so != -1)
+ printf("(%d) `%.*s'\n", i,
+ (int)(subs[i].rm_eo - subs[i].rm_so),
+ argv[optind] + subs[i].rm_so);
+ }
+ exit(status);
+}
+
+/*
+ - regress - main loop of regression test
+ == void regress(FILE *in);
+ */
+void
+regress(FILE *in)
+{
+ char inbuf[1000];
+# define MAXF 10
+ char *f[MAXF];
+ int nf;
+ int i;
+ char erbuf[100];
+ size_t ne;
+ char *badpat = "invalid regular expression";
+# define SHORT 10
+ char *bpname = "REG_BADPAT";
+ regex_t re;
+
+ while (fgets(inbuf, sizeof(inbuf), in) != NULL) {
+ line++;
+ if (inbuf[0] == '#' || inbuf[0] == '\n')
+ continue; /* NOTE CONTINUE */
+ inbuf[strlen(inbuf)-1] = '\0'; /* get rid of stupid \n */
+ if (debug)
+ fprintf(stdout, "%d:\n", line);
+ nf = split(inbuf, f, MAXF, "\t\t");
+ if (nf < 3) {
+ fprintf(stderr, "bad input, line %d\n", line);
+ exit(1);
+ }
+ for (i = 0; i < nf; i++)
+ if (strcmp(f[i], "\"\"") == 0)
+ f[i] = "";
+ if (nf <= 3)
+ f[3] = NULL;
+ if (nf <= 4)
+ f[4] = NULL;
+ try(f[0], f[1], f[2], f[3], f[4], options('c', f[1]));
+ if (opt('&', f[1])) /* try with either type of RE */
+ try(f[0], f[1], f[2], f[3], f[4],
+ options('c', f[1]) &~ REG_EXTENDED);
+ }
+
+ ne = regerror(REG_BADPAT, (regex_t *)NULL, erbuf, sizeof(erbuf));
+ if (strcmp(erbuf, badpat) != 0 || ne != strlen(badpat)+1) {
+ fprintf(stderr, "end: regerror() test gave `%s' not `%s'\n",
+ erbuf, badpat);
+ status = 1;
+ }
+ ne = regerror(REG_BADPAT, (regex_t *)NULL, erbuf, (size_t)SHORT);
+ if (strncmp(erbuf, badpat, SHORT-1) != 0 || erbuf[SHORT-1] != '\0' ||
+ ne != strlen(badpat)+1) {
+ fprintf(stderr, "end: regerror() short test gave `%s' not `%.*s'\n",
+ erbuf, SHORT-1, badpat);
+ status = 1;
+ }
+ ne = regerror(REG_ITOA|REG_BADPAT, (regex_t *)NULL, erbuf, sizeof(erbuf));
+ if (strcmp(erbuf, bpname) != 0 || ne != strlen(bpname) + 1) {
+ fprintf(stderr, "end: regerror() ITOA test gave `%s' not `%s'\n",
+ erbuf, bpname);
+ status = 1;
+ }
+ re.re_endp = bpname;
+ ne = regerror(REG_ATOI, &re, erbuf, sizeof(erbuf));
+ if (atoi(erbuf) != (int)REG_BADPAT) {
+ fprintf(stderr, "end: regerror() ATOI test gave `%s' not `%ld'\n",
+ erbuf, (long)REG_BADPAT);
+ status = 1;
+ } else if (ne != strlen(erbuf) + 1) {
+ fprintf(stderr, "end: regerror() ATOI test len(`%s') = %ld\n",
+ erbuf, (long)REG_BADPAT);
+ status = 1;
+ }
+}
+
+/*
+ - try - try it, and report on problems
+ == void try(char *f0, char *f1, char *f2, char *f3, char *f4, int opts);
+ - opts: may not match f1
+ */
+void
+try(char *f0, char *f1, char *f2, char *f3, char *f4, int opts)
+{
+ regex_t re;
+# define NSUBS 10
+ regmatch_t subs[NSUBS];
+# define NSHOULD 15
+ char *should[NSHOULD];
+ char erbuf[100];
+ size_t len;
+ int err, i, nshould;
+ char *grump;
+ char *type = (opts & REG_EXTENDED) ? "ERE" : "BRE";
+ char f0copy[1000];
+ char f2copy[1000];
+
+ strcpy(f0copy, f0);
+ re.re_endp = (opts&REG_PEND) ? f0copy + strlen(f0copy) : NULL;
+ fixstr(f0copy);
+ err = regcomp(&re, f0copy, opts);
+ if (err != 0 && (!opt('C', f1) || err != efind(f2))) {
+ /* unexpected error or wrong error */
+ len = regerror(err, &re, erbuf, sizeof(erbuf));
+ fprintf(stderr, "%d: %s error %s, %zu/%zu `%s'\n",
+ line, type, eprint(err), len, sizeof(erbuf), erbuf);
+ status = 1;
+ } else if (err == 0 && opt('C', f1)) {
+ /* unexpected success */
+ fprintf(stderr, "%d: %s should have given REG_%s\n",
+ line, type, f2);
+ status = 1;
+ err = 1; /* so we won't try regexec */
+ }
+
+ if (err != 0) {
+ regfree(&re);
+ return;
+ }
+
+ strcpy(f2copy, f2);
+ fixstr(f2copy);
+
+ if (options('e', f1)&REG_STARTEND) {
+ if (strchr(f2, '(') == NULL || strchr(f2, ')') == NULL)
+ fprintf(stderr, "%d: bad STARTEND syntax\n", line);
+ subs[0].rm_so = strchr(f2, '(') - f2 + 1;
+ subs[0].rm_eo = strchr(f2, ')') - f2;
+ }
+ err = regexec(&re, f2copy, NSUBS, subs, options('e', f1));
+
+ if (err != 0 && (f3 != NULL || err != REG_NOMATCH)) {
+ /* unexpected error or wrong error */
+ len = regerror(err, &re, erbuf, sizeof(erbuf));
+ fprintf(stderr, "%d: %s exec error %s, %zu/%zu `%s'\n",
+ line, type, eprint(err), len, sizeof(erbuf), erbuf);
+ status = 1;
+ } else if (err != 0) {
+ /* nothing more to check */
+ } else if (f3 == NULL) {
+ /* unexpected success */
+ fprintf(stderr, "%d: %s exec should have failed\n",
+ line, type);
+ status = 1;
+ err = 1; /* just on principle */
+ } else if (opts&REG_NOSUB) {
+ /* nothing more to check */
+ } else if ((grump = check(f2, subs[0], f3)) != NULL) {
+ fprintf(stderr, "%d: %s %s\n", line, type, grump);
+ status = 1;
+ err = 1;
+ }
+
+ if (err != 0 || f4 == NULL) {
+ regfree(&re);
+ return;
+ }
+
+ for (i = 1; i < NSHOULD; i++)
+ should[i] = NULL;
+ nshould = split(f4, should+1, NSHOULD-1, ",");
+ if (nshould == 0) {
+ nshould = 1;
+ should[1] = "";
+ }
+ for (i = 1; i < NSUBS; i++) {
+ grump = check(f2, subs[i], should[i]);
+ if (grump != NULL) {
+ fprintf(stderr, "%d: %s $%d %s\n", line,
+ type, i, grump);
+ status = 1;
+ err = 1;
+ }
+ }
+
+ regfree(&re);
+}
+
+/*
+ - options - pick options out of a regression-test string
+ - type: 'c' - compile, 'e' - exec
+ == int options(int type, char *s);
+ */
+int
+options(int type, char *s)
+{
+ char *p;
+ int o = (type == 'c') ? copts : eopts;
+ char *legal = (type == 'c') ? "bisnmp" : "^$#tl";
+
+ for (p = s; *p != '\0'; p++)
+ if (strchr(legal, *p) != NULL)
+ switch (*p) {
+ case 'b':
+ o &= ~REG_EXTENDED;
+ break;
+ case 'i':
+ o |= REG_ICASE;
+ break;
+ case 's':
+ o |= REG_NOSUB;
+ break;
+ case 'n':
+ o |= REG_NEWLINE;
+ break;
+ case 'm':
+ o &= ~REG_EXTENDED;
+ o |= REG_NOSPEC;
+ break;
+ case 'p':
+ o |= REG_PEND;
+ break;
+ case '^':
+ o |= REG_NOTBOL;
+ break;
+ case '$':
+ o |= REG_NOTEOL;
+ break;
+ case '#':
+ o |= REG_STARTEND;
+ break;
+ case 't': /* trace */
+ o |= REG_TRACE;
+ break;
+ case 'l': /* force long representation */
+ o |= REG_LARGE;
+ break;
+ case 'r': /* force backref use */
+ o |= REG_BACKR;
+ break;
+ }
+ return(o);
+}
+
+/*
+ - opt - is a particular option in a regression string?
+ == int opt(int c, char *s);
+ */
+int /* predicate */
+opt(int c, char *s)
+{
+ return(strchr(s, c) != NULL);
+}
+
+/*
+ - fixstr - transform magic characters in strings
+ == void fixstr(char *p);
+ */
+void
+fixstr(char *p)
+{
+ if (p == NULL)
+ return;
+
+ for (; *p != '\0'; p++)
+ if (*p == 'N')
+ *p = '\n';
+ else if (*p == 'T')
+ *p = '\t';
+ else if (*p == 'S')
+ *p = ' ';
+ else if (*p == 'Z')
+ *p = '\0';
+}
+
+/*
+ - check - check a substring match
+ == char *check(char *str, regmatch_t sub, char *should);
+ */
+char * /* NULL or complaint */
+check(char *str, regmatch_t sub, char *should)
+{
+ int len;
+ int shlen;
+ char *p;
+ static char grump[500];
+ char *at = NULL;
+
+ if (should != NULL && strcmp(should, "-") == 0)
+ should = NULL;
+ if (should != NULL && should[0] == '@') {
+ at = should + 1;
+ should = "";
+ }
+
+ /* check rm_so and rm_eo for consistency */
+ if (sub.rm_so > sub.rm_eo || (sub.rm_so == -1 && sub.rm_eo != -1) ||
+ (sub.rm_so != -1 && sub.rm_eo == -1) ||
+ (sub.rm_so != -1 && sub.rm_so < 0) ||
+ (sub.rm_eo != -1 && sub.rm_eo < 0) ) {
+ sprintf(grump, "start %ld end %ld", (long)sub.rm_so,
+ (long)sub.rm_eo);
+ return(grump);
+ }
+
+ /* check for no match */
+ if (sub.rm_so == -1 && should == NULL)
+ return(NULL);
+ if (sub.rm_so == -1)
+ return("did not match");
+
+ /* check for in range */
+ if (sub.rm_eo > strlen(str)) {
+ sprintf(grump, "start %ld end %ld, past end of string",
+ (long)sub.rm_so, (long)sub.rm_eo);
+ return(grump);
+ }
+
+ len = (int)(sub.rm_eo - sub.rm_so);
+ shlen = (int)strlen(should);
+ p = str + sub.rm_so;
+
+ /* check for not supposed to match */
+ if (should == NULL) {
+ sprintf(grump, "matched `%.*s'", len, p);
+ return(grump);
+ }
+
+ /* check for wrong match */
+ if (len != shlen || strncmp(p, should, (size_t)shlen) != 0) {
+ sprintf(grump, "matched `%.*s' instead", len, p);
+ return(grump);
+ }
+ if (shlen > 0)
+ return(NULL);
+
+ /* check null match in right place */
+ if (at == NULL)
+ return(NULL);
+ shlen = strlen(at);
+ if (shlen == 0)
+ shlen = 1; /* force check for end-of-string */
+ if (strncmp(p, at, shlen) != 0) {
+ sprintf(grump, "matched null at `%.20s'", p);
+ return(grump);
+ }
+ return(NULL);
+}
+
+/*
+ - eprint - convert error number to name
+ == static char *eprint(int err);
+ */
+static char *
+eprint(int err)
+{
+ static char epbuf[100];
+ size_t len;
+
+ len = regerror(REG_ITOA|err, (regex_t *)NULL, epbuf, sizeof(epbuf));
+ assert(len <= sizeof(epbuf));
+ return(epbuf);
+}
+
+/*
+ - efind - convert error name to number
+ == static int efind(char *name);
+ */
+static int
+efind(char *name)
+{
+ static char efbuf[100];
+ size_t n;
+ regex_t re;
+
+ sprintf(efbuf, "REG_%s", name);
+ assert(strlen(efbuf) < sizeof(efbuf));
+ re.re_endp = efbuf;
+ (void) regerror(REG_ATOI, &re, efbuf, sizeof(efbuf));
+ return(atoi(efbuf));
+}
diff --git a/lib/libc/regex/grot/mkh b/lib/libc/regex/grot/mkh
new file mode 100755
index 000000000000..1deba7983d5c
--- /dev/null
+++ b/lib/libc/regex/grot/mkh
@@ -0,0 +1,77 @@
+#! /bin/sh
+# mkh - pull headers out of C source
+# $FreeBSD$
+PATH=/bin:/usr/bin ; export PATH
+
+# egrep pattern to pick out marked lines
+egrep='^ =([ ]|$)'
+
+# Sed program to process marked lines into lines for the header file.
+# The markers have already been removed. Two things are done here: removal
+# of backslashed newlines, and some fudging of comments. The first is done
+# because -o needs to have prototypes on one line to strip them down.
+# Getting comments into the output is tricky; we turn C++-style // comments
+# into /* */ comments, after altering any existing */'s to avoid trouble.
+peel=' /\\$/N
+ /\\\n[ ]*/s///g
+ /\/\//s;\*/;* /;g
+ /\/\//s;//\(.*\);/*\1 */;'
+
+for a
+do
+ case "$a" in
+ -o) # old (pre-function-prototype) compiler
+ # add code to comment out argument lists
+ peel="$peel
+ "'/^\([^#\/][^\/]*[a-zA-Z0-9_)]\)(\(.*\))/s;;\1(/*\2*/);'
+ shift
+ ;;
+ -b) # funny Berkeley __P macro
+ peel="$peel
+ "'/^\([^#\/][^\/]*[a-zA-Z0-9_)]\)(\(.*\))/s;;\1 __P((\2));'
+ shift
+ ;;
+ -s) # compiler doesn't like `static foo();'
+ # add code to get rid of the `static'
+ peel="$peel
+ "'/^static[ ][^\/]*[a-zA-Z0-9_)](.*)/s;static.;;'
+ shift
+ ;;
+ -p) # private declarations
+ egrep='^ ==([ ]|$)'
+ shift
+ ;;
+ -i) # wrap in #ifndef, argument is name
+ ifndef="$2"
+ shift ; shift
+ ;;
+ *) break
+ ;;
+ esac
+done
+
+if test " $ifndef" != " "
+then
+ echo "#ifndef $ifndef"
+ echo "#define $ifndef /* never again */"
+fi
+echo "/* ========= begin header generated by $0 ========= */"
+echo '#ifdef __cplusplus'
+echo 'extern "C" {'
+echo '#endif'
+for f
+do
+ echo
+ echo "/* === $f === */"
+ egrep "$egrep" $f | sed 's/^ ==*[ ]//;s/^ ==*$//' | sed "$peel"
+ echo
+done
+echo '#ifdef __cplusplus'
+echo '}'
+echo '#endif'
+echo "/* ========= end header generated by $0 ========= */"
+if test " $ifndef" != " "
+then
+ echo "#endif"
+fi
+exit 0
diff --git a/lib/libc/regex/grot/split.c b/lib/libc/regex/grot/split.c
new file mode 100644
index 000000000000..c5d5264ab711
--- /dev/null
+++ b/lib/libc/regex/grot/split.c
@@ -0,0 +1,316 @@
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <string.h>
+
+#include "split.ih"
+
+/*
+ - split - divide a string into fields, like awk split()
+ == int split(char *string, char *fields[], int nfields, char *sep);
+ - fields: list is not NULL-terminated
+ - nfields: number of entries available in fields[]
+ - sep: "" white, "c" single char, "ab" [ab]+
+ */
+int /* number of fields, including overflow */
+split(char *string, char *fields[], int nfields, char *sep)
+{
+ char *p = string;
+ char c; /* latest character */
+ char sepc = sep[0];
+ char sepc2;
+ int fn;
+ char **fp = fields;
+ char *sepp;
+ int trimtrail;
+
+ /* white space */
+ if (sepc == '\0') {
+ while ((c = *p++) == ' ' || c == '\t')
+ continue;
+ p--;
+ trimtrail = 1;
+ sep = " \t"; /* note, code below knows this is 2 long */
+ sepc = ' ';
+ } else
+ trimtrail = 0;
+ sepc2 = sep[1]; /* now we can safely pick this up */
+
+ /* catch empties */
+ if (*p == '\0')
+ return(0);
+
+ /* single separator */
+ if (sepc2 == '\0') {
+ fn = nfields;
+ for (;;) {
+ *fp++ = p;
+ fn--;
+ if (fn == 0)
+ break;
+ while ((c = *p++) != sepc)
+ if (c == '\0')
+ return(nfields - fn);
+ *(p-1) = '\0';
+ }
+ /* we have overflowed the fields vector -- just count them */
+ fn = nfields;
+ for (;;) {
+ while ((c = *p++) != sepc)
+ if (c == '\0')
+ return(fn);
+ fn++;
+ }
+ /* not reached */
+ }
+
+ /* two separators */
+ if (sep[2] == '\0') {
+ fn = nfields;
+ for (;;) {
+ *fp++ = p;
+ fn--;
+ while ((c = *p++) != sepc && c != sepc2)
+ if (c == '\0') {
+ if (trimtrail && **(fp-1) == '\0')
+ fn++;
+ return(nfields - fn);
+ }
+ if (fn == 0)
+ break;
+ *(p-1) = '\0';
+ while ((c = *p++) == sepc || c == sepc2)
+ continue;
+ p--;
+ }
+ /* we have overflowed the fields vector -- just count them */
+ fn = nfields;
+ while (c != '\0') {
+ while ((c = *p++) == sepc || c == sepc2)
+ continue;
+ p--;
+ fn++;
+ while ((c = *p++) != '\0' && c != sepc && c != sepc2)
+ continue;
+ }
+ /* might have to trim trailing white space */
+ if (trimtrail) {
+ p--;
+ while ((c = *--p) == sepc || c == sepc2)
+ continue;
+ p++;
+ if (*p != '\0') {
+ if (fn == nfields+1)
+ *p = '\0';
+ fn--;
+ }
+ }
+ return(fn);
+ }
+
+ /* n separators */
+ fn = 0;
+ for (;;) {
+ if (fn < nfields)
+ *fp++ = p;
+ fn++;
+ for (;;) {
+ c = *p++;
+ if (c == '\0')
+ return(fn);
+ sepp = sep;
+ while ((sepc = *sepp++) != '\0' && sepc != c)
+ continue;
+ if (sepc != '\0') /* it was a separator */
+ break;
+ }
+ if (fn < nfields)
+ *(p-1) = '\0';
+ for (;;) {
+ c = *p++;
+ sepp = sep;
+ while ((sepc = *sepp++) != '\0' && sepc != c)
+ continue;
+ if (sepc == '\0') /* it wasn't a separator */
+ break;
+ }
+ p--;
+ }
+
+ /* not reached */
+}
+
+#ifdef TEST_SPLIT
+
+
+/*
+ * test program
+ * pgm runs regression
+ * pgm sep splits stdin lines by sep
+ * pgm str sep splits str by sep
+ * pgm str sep n splits str by sep n times
+ */
+int
+main(int argc, char *argv[])
+{
+ char buf[512];
+ int n;
+# define MNF 10
+ char *fields[MNF];
+
+ if (argc > 4)
+ for (n = atoi(argv[3]); n > 0; n--) {
+ (void) strcpy(buf, argv[1]);
+ }
+ else if (argc > 3)
+ for (n = atoi(argv[3]); n > 0; n--) {
+ (void) strcpy(buf, argv[1]);
+ (void) split(buf, fields, MNF, argv[2]);
+ }
+ else if (argc > 2)
+ dosplit(argv[1], argv[2]);
+ else if (argc > 1)
+ while (fgets(buf, sizeof(buf), stdin) != NULL) {
+ buf[strlen(buf)-1] = '\0'; /* stomp newline */
+ dosplit(buf, argv[1]);
+ }
+ else
+ regress();
+
+ exit(0);
+}
+
+void
+dosplit(char *string, char *seps)
+{
+# define NF 5
+ char *fields[NF];
+ int nf;
+
+ nf = split(string, fields, NF, seps);
+ print(nf, NF, fields);
+}
+
+void
+print(int nf, int nfp, char *fields[])
+{
+ int fn;
+ int bound;
+
+ bound = (nf > nfp) ? nfp : nf;
+ printf("%d:\t", nf);
+ for (fn = 0; fn < bound; fn++)
+ printf("\"%s\"%s", fields[fn], (fn+1 < nf) ? ", " : "\n");
+}
+
+#define RNF 5 /* some table entries know this */
+struct {
+ char *str;
+ char *seps;
+ int nf;
+ char *fi[RNF];
+} tests[] = {
+ "", " ", 0, { "" },
+ " ", " ", 2, { "", "" },
+ "x", " ", 1, { "x" },
+ "xy", " ", 1, { "xy" },
+ "x y", " ", 2, { "x", "y" },
+ "abc def g ", " ", 5, { "abc", "def", "", "g", "" },
+ " a bcd", " ", 4, { "", "", "a", "bcd" },
+ "a b c d e f", " ", 6, { "a", "b", "c", "d", "e f" },
+ " a b c d ", " ", 6, { "", "a", "b", "c", "d " },
+
+ "", " _", 0, { "" },
+ " ", " _", 2, { "", "" },
+ "x", " _", 1, { "x" },
+ "x y", " _", 2, { "x", "y" },
+ "ab _ cd", " _", 2, { "ab", "cd" },
+ " a_b c ", " _", 5, { "", "a", "b", "c", "" },
+ "a b c_d e f", " _", 6, { "a", "b", "c", "d", "e f" },
+ " a b c d ", " _", 6, { "", "a", "b", "c", "d " },
+
+ "", " _~", 0, { "" },
+ " ", " _~", 2, { "", "" },
+ "x", " _~", 1, { "x" },
+ "x y", " _~", 2, { "x", "y" },
+ "ab _~ cd", " _~", 2, { "ab", "cd" },
+ " a_b c~", " _~", 5, { "", "a", "b", "c", "" },
+ "a b_c d~e f", " _~", 6, { "a", "b", "c", "d", "e f" },
+ "~a b c d ", " _~", 6, { "", "a", "b", "c", "d " },
+
+ "", " _~-", 0, { "" },
+ " ", " _~-", 2, { "", "" },
+ "x", " _~-", 1, { "x" },
+ "x y", " _~-", 2, { "x", "y" },
+ "ab _~- cd", " _~-", 2, { "ab", "cd" },
+ " a_b c~", " _~-", 5, { "", "a", "b", "c", "" },
+ "a b_c-d~e f", " _~-", 6, { "a", "b", "c", "d", "e f" },
+ "~a-b c d ", " _~-", 6, { "", "a", "b", "c", "d " },
+
+ "", " ", 0, { "" },
+ " ", " ", 2, { "", "" },
+ "x", " ", 1, { "x" },
+ "xy", " ", 1, { "xy" },
+ "x y", " ", 2, { "x", "y" },
+ "abc def g ", " ", 4, { "abc", "def", "g", "" },
+ " a bcd", " ", 3, { "", "a", "bcd" },
+ "a b c d e f", " ", 6, { "a", "b", "c", "d", "e f" },
+ " a b c d ", " ", 6, { "", "a", "b", "c", "d " },
+
+ "", "", 0, { "" },
+ " ", "", 0, { "" },
+ "x", "", 1, { "x" },
+ "xy", "", 1, { "xy" },
+ "x y", "", 2, { "x", "y" },
+ "abc def g ", "", 3, { "abc", "def", "g" },
+ "\t a bcd", "", 2, { "a", "bcd" },
+ " a \tb\t c ", "", 3, { "a", "b", "c" },
+ "a b c d e ", "", 5, { "a", "b", "c", "d", "e" },
+ "a b\tc d e f", "", 6, { "a", "b", "c", "d", "e f" },
+ " a b c d e f ", "", 6, { "a", "b", "c", "d", "e f " },
+
+ NULL, NULL, 0, { NULL },
+};
+
+void
+regress(void)
+{
+ char buf[512];
+ int n;
+ char *fields[RNF+1];
+ int nf;
+ int i;
+ int printit;
+ char *f;
+
+ for (n = 0; tests[n].str != NULL; n++) {
+ (void) strcpy(buf, tests[n].str);
+ fields[RNF] = NULL;
+ nf = split(buf, fields, RNF, tests[n].seps);
+ printit = 0;
+ if (nf != tests[n].nf) {
+ printf("split `%s' by `%s' gave %d fields, not %d\n",
+ tests[n].str, tests[n].seps, nf, tests[n].nf);
+ printit = 1;
+ } else if (fields[RNF] != NULL) {
+ printf("split() went beyond array end\n");
+ printit = 1;
+ } else {
+ for (i = 0; i < nf && i < RNF; i++) {
+ f = fields[i];
+ if (f == NULL)
+ f = "(NULL)";
+ if (strcmp(f, tests[n].fi[i]) != 0) {
+ printf("split `%s' by `%s' field %d is `%s', not `%s'\n",
+ tests[n].str, tests[n].seps,
+ i, fields[i], tests[n].fi[i]);
+ printit = 1;
+ }
+ }
+ }
+ if (printit)
+ print(nf, RNF, fields);
+ }
+}
+#endif
diff --git a/lib/libc/regex/grot/tests b/lib/libc/regex/grot/tests
new file mode 100644
index 000000000000..050e7b25ab14
--- /dev/null
+++ b/lib/libc/regex/grot/tests
@@ -0,0 +1,477 @@
+# regular expression test set
+# $FreeBSD$
+# Lines are at least three fields, separated by one or more tabs. "" stands
+# for an empty field. First field is an RE. Second field is flags. If
+# C flag given, regcomp() is expected to fail, and the third field is the
+# error name (minus the leading REG_).
+#
+# Otherwise it is expected to succeed, and the third field is the string to
+# try matching it against. If there is no fourth field, the match is
+# expected to fail. If there is a fourth field, it is the substring that
+# the RE is expected to match. If there is a fifth field, it is a comma-
+# separated list of what the subexpressions should match, with - indicating
+# no match for that one. In both the fourth and fifth fields, a (sub)field
+# starting with @ indicates that the (sub)expression is expected to match
+# a null string followed by the stuff after the @; this provides a way to
+# test where null strings match. The character `N' in REs and strings
+# is newline, `S' is space, `T' is tab, `Z' is NUL.
+#
+# The full list of flags:
+# - placeholder, does nothing
+# b RE is a BRE, not an ERE
+# & try it as both an ERE and a BRE
+# C regcomp() error expected, third field is error name
+# i REG_ICASE
+# m ("mundane") REG_NOSPEC
+# s REG_NOSUB (not really testable)
+# n REG_NEWLINE
+# ^ REG_NOTBOL
+# $ REG_NOTEOL
+# # REG_STARTEND (see below)
+# p REG_PEND
+#
+# For REG_STARTEND, the start/end offsets are those of the substring
+# enclosed in ().
+
+# basics
+a & a a
+abc & abc abc
+abc|de - abc abc
+a|b|c - abc a
+
+# parentheses and perversions thereof
+a(b)c - abc abc
+a\(b\)c b abc abc
+a( C EPAREN
+a( b a( a(
+a\( - a( a(
+a\( bC EPAREN
+a\(b bC EPAREN
+a(b C EPAREN
+a(b b a(b a(b
+# gag me with a right parenthesis -- 1003.2 goofed here (my fault, partly)
+a) - a) a)
+) - ) )
+# end gagging (in a just world, those *should* give EPAREN)
+a) b a) a)
+a\) bC EPAREN
+\) bC EPAREN
+a()b - ab ab
+a\(\)b b ab ab
+
+# anchoring and REG_NEWLINE
+^abc$ & abc abc
+a^b - a^b
+a^b b a^b a^b
+a$b - a$b
+a$b b a$b a$b
+^ & abc @abc
+$ & abc @
+^$ & "" @
+$^ - "" @
+\($\)\(^\) b "" @
+# stop retching, those are legitimate (although disgusting)
+^^ - "" @
+$$ - "" @
+b$ & abNc
+b$ &n abNc b
+^b$ & aNbNc
+^b$ &n aNbNc b
+^$ &n aNNb @Nb
+^$ n abc
+^$ n abcN @
+$^ n aNNb @Nb
+\($\)\(^\) bn aNNb @Nb
+^^ n^ aNNb @Nb
+$$ n aNNb @NN
+^a ^ a
+a$ $ a
+^a ^n aNb
+^b ^n aNb b
+a$ $n bNa
+b$ $n bNa b
+a*(^b$)c* - b b
+a*\(^b$\)c* b b b
+
+# certain syntax errors and non-errors
+| C EMPTY
+| b | |
+* C BADRPT
+* b * *
++ C BADRPT
+? C BADRPT
+"" &C EMPTY
+() - abc @abc
+\(\) b abc @abc
+a||b C EMPTY
+|ab C EMPTY
+ab| C EMPTY
+(|a)b C EMPTY
+(a|)b C EMPTY
+(*a) C BADRPT
+(+a) C BADRPT
+(?a) C BADRPT
+({1}a) C BADRPT
+\(\{1\}a\) bC BADRPT
+(a|*b) C BADRPT
+(a|+b) C BADRPT
+(a|?b) C BADRPT
+(a|{1}b) C BADRPT
+^* C BADRPT
+^* b * *
+^+ C BADRPT
+^? C BADRPT
+^{1} C BADRPT
+^\{1\} bC BADRPT
+
+# metacharacters, backslashes
+a.c & abc abc
+a[bc]d & abd abd
+a\*c & a*c a*c
+a\\b & a\b a\b
+a\\\*b & a\*b a\*b
+a\bc & abc abc
+a\ &C EESCAPE
+a\\bc & a\bc a\bc
+\{ bC BADRPT
+# trailing $ is a peculiar special case for the BRE code
+a$ & a a
+a$ & a$
+a\$ & a
+a\$ & a$ a$
+a\\$ & a
+a\\$ & a$
+a\\$ & a\$
+a\\$ & a\ a\
+
+# back references, ugh
+a\(b\)\2c bC ESUBREG
+a\(b\1\)c bC ESUBREG
+a\(b*\)c\1d b abbcbbd abbcbbd bb
+a\(b*\)c\1d b abbcbd
+a\(b*\)c\1d b abbcbbbd
+^\(.\)\1 b abc
+a\([bc]\)\1d b abcdabbd abbd b
+a\(\([bc]\)\2\)*d b abbccd abbccd
+a\(\([bc]\)\2\)*d b abbcbd
+# actually, this next one probably ought to fail, but the spec is unclear
+a\(\(b\)*\2\)*d b abbbd abbbd
+# here is a case that no NFA implementation does right
+\(ab*\)[ab]*\1 b ababaaa ababaaa a
+# check out normal matching in the presence of back refs
+\(a\)\1bcd b aabcd aabcd
+\(a\)\1bc*d b aabcd aabcd
+\(a\)\1bc*d b aabd aabd
+\(a\)\1bc*d b aabcccd aabcccd
+\(a\)\1bc*[ce]d b aabcccd aabcccd
+^\(a\)\1b\(c\)*cd$ b aabcccd aabcccd
+\(b*\)\(a*\1\)* b ab a
+\([^_]*\)\(_*\1\)* b foo_foo_bar_bar_bar_baz foo_foo foo,_foo
+\([^_]*\)\(_*\1\)* b bar_bar_bar_baz bar_bar_bar bar,_bar
+\([^_]*\)\(_*\1\)* b foo_bar_baz foo foo
+\(.*\)\1 b "" ""
+\(.*\)\1 b a ""
+\(.*\)\1 b aa aa
+\(.*\)\1 b aaa aa
+\(.*\)\1 b aaaa aaaa
+\([^_]*\)\1 b "" ""
+\([^_]*\)\1 b a ""
+\([^_]*\)\1 b aa aa
+\([^_]*\)\1 b aaa aa
+\([^_]*\)\1 b aaaa aaaa
+foo\(.*\)bar\1 b foolbarl foolbarl l
+foo\(.*\)bar\1 b foobar foobar ""
+\(\(.\)b\)*\1 b aba
+\(\(.\)b\)*\1 b abba
+\(\(.\)b\)*\1 b abbba
+\(\(.\)b\)*\1 b abbbba bbbb bb,b
+\(\(.\)b\)*\1 b abbbbba abbbbb bb,b
+\(\(.\)b\)*\1 b abbbbbba abbbbb bb,b
+\(\(.\)b\)*\1 b abbbbbbbbbbbbbba abbbbbbbbbbbbb bb,b
+\(\(.\)b\)*\1 b abbbbbbbbbbbbbbba abbbbbbbbbbbbbbb bb,b
+
+# ordinary repetitions
+ab*c & abc abc
+ab+c - abc abc
+ab?c - abc abc
+a\(*\)b b a*b a*b
+a\(**\)b b ab ab
+a\(***\)b bC BADRPT
+*a b *a *a
+**a b a a
+***a bC BADRPT
+
+# the dreaded bounded repetitions
+{ & { {
+{abc & {abc {abc
+{1 C BADRPT
+{1} C BADRPT
+a{b & a{b a{b
+a{1}b - ab ab
+a\{1\}b b ab ab
+a{1,}b - ab ab
+a\{1,\}b b ab ab
+a{1,2}b - aab aab
+a\{1,2\}b b aab aab
+a{1 C EBRACE
+a\{1 bC EBRACE
+a{1a C EBRACE
+a\{1a bC EBRACE
+a{1a} C BADBR
+a\{1a\} bC BADBR
+a{,2} - a{,2} a{,2}
+a\{,2\} bC BADBR
+a{,} - a{,} a{,}
+a\{,\} bC BADBR
+a{1,x} C BADBR
+a\{1,x\} bC BADBR
+a{1,x C EBRACE
+a\{1,x bC EBRACE
+a{300} C BADBR
+a\{300\} bC BADBR
+a{1,0} C BADBR
+a\{1,0\} bC BADBR
+ab{0,0}c - abcac ac
+ab\{0,0\}c b abcac ac
+ab{0,1}c - abcac abc
+ab\{0,1\}c b abcac abc
+ab{0,3}c - abbcac abbc
+ab\{0,3\}c b abbcac abbc
+ab{1,1}c - acabc abc
+ab\{1,1\}c b acabc abc
+ab{1,3}c - acabc abc
+ab\{1,3\}c b acabc abc
+ab{2,2}c - abcabbc abbc
+ab\{2,2\}c b abcabbc abbc
+ab{2,4}c - abcabbc abbc
+ab\{2,4\}c b abcabbc abbc
+((a{1,10}){1,10}){1,10} - a a a,a
+((a{1,10}){1,10}){1,10}bb - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaabb aaaaaaaaaaaaaaaaaaaaaaaaaaaaaabb
+
+# multiple repetitions
+a** &C BADRPT
+a++ C BADRPT
+a?? C BADRPT
+a*+ C BADRPT
+a*? C BADRPT
+a+* C BADRPT
+a+? C BADRPT
+a?* C BADRPT
+a?+ C BADRPT
+a{1}{1} C BADRPT
+a*{1} C BADRPT
+a+{1} C BADRPT
+a?{1} C BADRPT
+a{1}* C BADRPT
+a{1}+ C BADRPT
+a{1}? C BADRPT
+a*{b} - a{b} a{b}
+a\{1\}\{1\} bC BADRPT
+a*\{1\} bC BADRPT
+a\{1\}* bC BADRPT
+
+# brackets, and numerous perversions thereof
+a[b]c & abc abc
+a[ab]c & abc abc
+a[^ab]c & adc adc
+a[]b]c & a]c a]c
+a[[b]c & a[c a[c
+a[-b]c & a-c a-c
+a[^]b]c & adc adc
+a[^-b]c & adc adc
+a[b-]c & a-c a-c
+a[b &C EBRACK
+a[] &C EBRACK
+a[1-3]c & a2c a2c
+a[3-1]c &C ERANGE
+a[1-3-5]c &C ERANGE
+a[[.-.]--]c & a-c a-c
+a[1- &C ERANGE
+a[[. &C EBRACK
+a[[.x &C EBRACK
+a[[.x. &C EBRACK
+a[[.x.] &C EBRACK
+a[[.x.]] & ax ax
+a[[.x,.]] &C ECOLLATE
+a[[.one.]]b & a1b a1b
+a[[.notdef.]]b &C ECOLLATE
+a[[.].]]b & a]b a]b
+a[[:alpha:]]c & abc abc
+a[[:notdef:]]c &C ECTYPE
+a[[: &C EBRACK
+a[[:alpha &C EBRACK
+a[[:alpha:] &C EBRACK
+a[[:alpha,:] &C ECTYPE
+a[[:]:]]b &C ECTYPE
+a[[:-:]]b &C ECTYPE
+a[[:alph:]] &C ECTYPE
+a[[:alphabet:]] &C ECTYPE
+[[:alnum:]]+ - -%@a0X- a0X
+[[:alpha:]]+ - -%@aX0- aX
+[[:blank:]]+ - aSSTb SST
+[[:cntrl:]]+ - aNTb NT
+[[:digit:]]+ - a019b 019
+[[:graph:]]+ - Sa%bS a%b
+[[:lower:]]+ - AabC ab
+[[:print:]]+ - NaSbN aSb
+[[:punct:]]+ - S%-&T %-&
+[[:space:]]+ - aSNTb SNT
+[[:upper:]]+ - aBCd BC
+[[:xdigit:]]+ - p0f3Cq 0f3C
+a[[=b=]]c & abc abc
+a[[= &C EBRACK
+a[[=b &C EBRACK
+a[[=b= &C EBRACK
+a[[=b=] &C EBRACK
+a[[=b,=]] &C ECOLLATE
+a[[=one=]]b & a1b a1b
+
+# complexities
+a(((b)))c - abc abc
+a(b|(c))d - abd abd
+a(b*|c)d - abbd abbd
+# just gotta have one DFA-buster, of course
+a[ab]{20} - aaaaabaaaabaaaabaaaab aaaaabaaaabaaaabaaaab
+# and an inline expansion in case somebody gets tricky
+a[ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab] - aaaaabaaaabaaaabaaaab aaaaabaaaabaaaabaaaab
+# and in case somebody just slips in an NFA...
+a[ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab](wee|week)(knights|night) - aaaaabaaaabaaaabaaaabweeknights aaaaabaaaabaaaabaaaabweeknights
+# fish for anomalies as the number of states passes 32
+12345678901234567890123456789 - a12345678901234567890123456789b 12345678901234567890123456789
+123456789012345678901234567890 - a123456789012345678901234567890b 123456789012345678901234567890
+1234567890123456789012345678901 - a1234567890123456789012345678901b 1234567890123456789012345678901
+12345678901234567890123456789012 - a12345678901234567890123456789012b 12345678901234567890123456789012
+123456789012345678901234567890123 - a123456789012345678901234567890123b 123456789012345678901234567890123
+# and one really big one, beyond any plausible word width
+1234567890123456789012345678901234567890123456789012345678901234567890 - a1234567890123456789012345678901234567890123456789012345678901234567890b 1234567890123456789012345678901234567890123456789012345678901234567890
+# fish for problems as brackets go past 8
+[ab][cd][ef][gh][ij][kl][mn] - xacegikmoq acegikm
+[ab][cd][ef][gh][ij][kl][mn][op] - xacegikmoq acegikmo
+[ab][cd][ef][gh][ij][kl][mn][op][qr] - xacegikmoqy acegikmoq
+[ab][cd][ef][gh][ij][kl][mn][op][q] - xacegikmoqy acegikmoq
+
+# subtleties of matching
+abc & xabcy abc
+a\(b\)?c\1d b acd
+aBc i Abc Abc
+a[Bc]*d i abBCcd abBCcd
+0[[:upper:]]1 &i 0a1 0a1
+0[[:lower:]]1 &i 0A1 0A1
+a[^b]c &i abc
+a[^b]c &i aBc
+a[^b]c &i adc adc
+[a]b[c] - abc abc
+[a]b[a] - aba aba
+[abc]b[abc] - abc abc
+[abc]b[abd] - abd abd
+a(b?c)+d - accd accd
+(wee|week)(knights|night) - weeknights weeknights
+(we|wee|week|frob)(knights|night|day) - weeknights weeknights
+a[bc]d - xyzaaabcaababdacd abd
+a[ab]c - aaabc abc
+abc s abc abc
+
+# subexpressions
+a(b)(c)d - abcd abcd b,c
+a(((b)))c - abc abc b,b,b
+a(b|(c))d - abd abd b,-
+a(b*|c|e)d - abbd abbd bb
+a(b*|c|e)d - acd acd c
+a(b*|c|e)d - ad ad @d
+a(b?)c - abc abc b
+a(b?)c - ac ac @c
+a(b+)c - abc abc b
+a(b+)c - abbbc abbbc bbb
+a(b*)c - ac ac @c
+(a|ab)(bc([de]+)f|cde) - abcdef abcdef a,bcdef,de
+# the regression tester only asks for 9 subexpressions
+a(b)(c)(d)(e)(f)(g)(h)(i)(j)k - abcdefghijk abcdefghijk b,c,d,e,f,g,h,i,j
+a(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)l - abcdefghijkl abcdefghijkl b,c,d,e,f,g,h,i,j,k
+a([bc]?)c - abc abc b
+a([bc]?)c - ac ac @c
+a([bc]+)c - abc abc b
+a([bc]+)c - abcc abcc bc
+a([bc]+)bc - abcbc abcbc bc
+a(bb+|b)b - abb abb b
+a(bbb+|bb+|b)b - abb abb b
+a(bbb+|bb+|b)b - abbb abbb bb
+a(bbb+|bb+|b)bb - abbb abbb b
+(.*).* - abcdef abcdef abcdef
+(a*)* - bc @b @b
+
+# do we get the right subexpression when it is used more than once?
+a(b|c)*d - ad ad -
+a(b|c)*d - abcd abcd c
+a(b|c)+d - abd abd b
+a(b|c)+d - abcd abcd c
+a(b|c?)+d - ad ad @d
+a(b|c?)+d - abcd abcd @d
+a(b|c){0,0}d - ad ad -
+a(b|c){0,1}d - ad ad -
+a(b|c){0,1}d - abd abd b
+a(b|c){0,2}d - ad ad -
+a(b|c){0,2}d - abcd abcd c
+a(b|c){0,}d - ad ad -
+a(b|c){0,}d - abcd abcd c
+a(b|c){1,1}d - abd abd b
+a(b|c){1,1}d - acd acd c
+a(b|c){1,2}d - abd abd b
+a(b|c){1,2}d - abcd abcd c
+a(b|c){1,}d - abd abd b
+a(b|c){1,}d - abcd abcd c
+a(b|c){2,2}d - acbd acbd b
+a(b|c){2,2}d - abcd abcd c
+a(b|c){2,4}d - abcd abcd c
+a(b|c){2,4}d - abcbd abcbd b
+a(b|c){2,4}d - abcbcd abcbcd c
+a(b|c){2,}d - abcd abcd c
+a(b|c){2,}d - abcbd abcbd b
+a(b+|((c)*))+d - abd abd @d,@d,-
+a(b+|((c)*))+d - abcd abcd @d,@d,-
+
+# check out the STARTEND option
+[abc] &# a(b)c b
+[abc] &# a(d)c
+[abc] &# a(bc)d b
+[abc] &# a(dc)d c
+. &# a()c
+b.*c &# b(bc)c bc
+b.* &# b(bc)c bc
+.*c &# b(bc)c bc
+
+# plain strings, with the NOSPEC flag
+abc m abc abc
+abc m xabcy abc
+abc m xyz
+a*b m aba*b a*b
+a*b m ab
+"" mC EMPTY
+
+# cases involving NULs
+aZb & a a
+aZb &p a
+aZb &p# (aZb) aZb
+aZ*b &p# (ab) ab
+a.b &# (aZb) aZb
+a.* &# (aZb)c aZb
+
+# word boundaries (ick)
+[[:<:]]a & a a
+[[:<:]]a & ba
+[[:<:]]a & -a a
+a[[:>:]] & a a
+a[[:>:]] & ab
+a[[:>:]] & a- a
+[[:<:]]a.c[[:>:]] & axcd-dayc-dazce-abc abc
+[[:<:]]a.c[[:>:]] & axcd-dayc-dazce-abc-q abc
+[[:<:]]a.c[[:>:]] & axc-dayc-dazce-abc axc
+
+# past problems
+(A[1])|(A[2])|(A[3])|(A[4])|(A[5])|(A[6])|(A[7])|(A[8])|(A[9])|(A[A]) - A1 A1
+abcdefghijklmnop i abcdefghijklmnop abcdefghijklmnop
+abcdefghijklmnopqrstuv i abcdefghijklmnopqrstuv abcdefghijklmnopqrstuv
+(ALAK)|(ALT[AB])|(CC[123]1)|(CM[123]1)|(GAMC)|(LC[23][EO ])|(SEM[1234])|(SL[ES][12])|(SLWW)|(SLF )|(SLDT)|(VWH[12])|(WH[34][EW])|(WP1[ESN]) - CC11 CC11
+CC[13]1|a{21}[23][EO][123][Es][12]a{15}aa[34][EW]aaaaaaa[X]a - CC11 CC11
+# PR 130504
+(.|())(b) - ab ab
+(()|.)(b) - ab ab
diff --git a/lib/libc/regex/re_format.7 b/lib/libc/regex/re_format.7
new file mode 100644
index 000000000000..b3f95611c9f8
--- /dev/null
+++ b/lib/libc/regex/re_format.7
@@ -0,0 +1,492 @@
+.\" Copyright (c) 1992, 1993, 1994 Henry Spencer.
+.\" Copyright (c) 1992, 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Henry Spencer.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)re_format.7 8.3 (Berkeley) 3/20/94
+.\" $FreeBSD$
+.\"
+.Dd June 30, 2014
+.Dt RE_FORMAT 7
+.Os
+.Sh NAME
+.Nm re_format
+.Nd POSIX 1003.2 regular expressions
+.Sh DESCRIPTION
+Regular expressions
+.Pq Dq RE Ns s ,
+as defined in
+.St -p1003.2 ,
+come in two forms:
+modern REs (roughly those of
+.Xr egrep 1 ;
+1003.2 calls these
+.Dq extended
+REs)
+and obsolete REs (roughly those of
+.Xr ed 1 ;
+1003.2
+.Dq basic
+REs).
+Obsolete REs mostly exist for backward compatibility in some old programs;
+they will be discussed at the end.
+.St -p1003.2
+leaves some aspects of RE syntax and semantics open;
+`\(dd' marks decisions on these aspects that
+may not be fully portable to other
+.St -p1003.2
+implementations.
+.Pp
+A (modern) RE is one\(dd or more non-empty\(dd
+.Em branches ,
+separated by
+.Ql \&| .
+It matches anything that matches one of the branches.
+.Pp
+A branch is one\(dd or more
+.Em pieces ,
+concatenated.
+It matches a match for the first, followed by a match for the second, etc.
+.Pp
+A piece is an
+.Em atom
+possibly followed
+by a single\(dd
+.Ql \&* ,
+.Ql \&+ ,
+.Ql \&? ,
+or
+.Em bound .
+An atom followed by
+.Ql \&*
+matches a sequence of 0 or more matches of the atom.
+An atom followed by
+.Ql \&+
+matches a sequence of 1 or more matches of the atom.
+An atom followed by
+.Ql ?\&
+matches a sequence of 0 or 1 matches of the atom.
+.Pp
+A
+.Em bound
+is
+.Ql \&{
+followed by an unsigned decimal integer,
+possibly followed by
+.Ql \&,
+possibly followed by another unsigned decimal integer,
+always followed by
+.Ql \&} .
+The integers must lie between 0 and
+.Dv RE_DUP_MAX
+(255\(dd) inclusive,
+and if there are two of them, the first may not exceed the second.
+An atom followed by a bound containing one integer
+.Em i
+and no comma matches
+a sequence of exactly
+.Em i
+matches of the atom.
+An atom followed by a bound
+containing one integer
+.Em i
+and a comma matches
+a sequence of
+.Em i
+or more matches of the atom.
+An atom followed by a bound
+containing two integers
+.Em i
+and
+.Em j
+matches
+a sequence of
+.Em i
+through
+.Em j
+(inclusive) matches of the atom.
+.Pp
+An atom is a regular expression enclosed in
+.Ql ()
+(matching a match for the
+regular expression),
+an empty set of
+.Ql ()
+(matching the null string)\(dd,
+a
+.Em bracket expression
+(see below),
+.Ql .\&
+(matching any single character),
+.Ql \&^
+(matching the null string at the beginning of a line),
+.Ql \&$
+(matching the null string at the end of a line), a
+.Ql \e
+followed by one of the characters
+.Ql ^.[$()|*+?{\e
+(matching that character taken as an ordinary character),
+a
+.Ql \e
+followed by any other character\(dd
+(matching that character taken as an ordinary character,
+as if the
+.Ql \e
+had not been present\(dd),
+or a single character with no other significance (matching that character).
+A
+.Ql \&{
+followed by a character other than a digit is an ordinary
+character, not the beginning of a bound\(dd.
+It is illegal to end an RE with
+.Ql \e .
+.Pp
+A
+.Em bracket expression
+is a list of characters enclosed in
+.Ql [] .
+It normally matches any single character from the list (but see below).
+If the list begins with
+.Ql \&^ ,
+it matches any single character
+(but see below)
+.Em not
+from the rest of the list.
+If two characters in the list are separated by
+.Ql \&- ,
+this is shorthand
+for the full
+.Em range
+of characters between those two (inclusive) in the
+collating sequence,
+.No e.g. Ql [0-9]
+in ASCII matches any decimal digit.
+It is illegal\(dd for two ranges to share an
+endpoint,
+.No e.g. Ql a-c-e .
+Ranges are very collating-sequence-dependent,
+and portable programs should avoid relying on them.
+.Pp
+To include a literal
+.Ql \&]
+in the list, make it the first character
+(following a possible
+.Ql \&^ ) .
+To include a literal
+.Ql \&- ,
+make it the first or last character,
+or the second endpoint of a range.
+To use a literal
+.Ql \&-
+as the first endpoint of a range,
+enclose it in
+.Ql [.\&
+and
+.Ql .]\&
+to make it a collating element (see below).
+With the exception of these and some combinations using
+.Ql \&[
+(see next paragraphs), all other special characters, including
+.Ql \e ,
+lose their special significance within a bracket expression.
+.Pp
+Within a bracket expression, a collating element (a character,
+a multi-character sequence that collates as if it were a single character,
+or a collating-sequence name for either)
+enclosed in
+.Ql [.\&
+and
+.Ql .]\&
+stands for the
+sequence of characters of that collating element.
+The sequence is a single element of the bracket expression's list.
+A bracket expression containing a multi-character collating element
+can thus match more than one character,
+e.g.\& if the collating sequence includes a
+.Ql ch
+collating element,
+then the RE
+.Ql [[.ch.]]*c
+matches the first five characters
+of
+.Ql chchcc .
+.Pp
+Within a bracket expression, a collating element enclosed in
+.Ql [=
+and
+.Ql =]
+is an equivalence class, standing for the sequences of characters
+of all collating elements equivalent to that one, including itself.
+(If there are no other equivalent collating elements,
+the treatment is as if the enclosing delimiters were
+.Ql [.\&
+and
+.Ql .] . )
+For example, if
+.Ql x
+and
+.Ql y
+are the members of an equivalence class,
+then
+.Ql [[=x=]] ,
+.Ql [[=y=]] ,
+and
+.Ql [xy]
+are all synonymous.
+An equivalence class may not\(dd be an endpoint
+of a range.
+.Pp
+Within a bracket expression, the name of a
+.Em character class
+enclosed in
+.Ql [:
+and
+.Ql :]
+stands for the list of all characters belonging to that
+class.
+Standard character class names are:
+.Bl -column "alnum" "digit" "xdigit" -offset indent
+.It Em "alnum digit punct"
+.It Em "alpha graph space"
+.It Em "blank lower upper"
+.It Em "cntrl print xdigit"
+.El
+.Pp
+These stand for the character classes defined in
+.Xr ctype 3 .
+A locale may provide others.
+A character class may not be used as an endpoint of a range.
+.Pp
+A bracketed expression like
+.Ql [[:class:]]
+can be used to match a single character that belongs to a character
+class.
+The reverse, matching any character that does not belong to a specific
+class, the negation operator of bracket expressions may be used:
+.Ql [^[:class:]] .
+.Pp
+There are two special cases\(dd of bracket expressions:
+the bracket expressions
+.Ql [[:<:]]
+and
+.Ql [[:>:]]
+match the null string at the beginning and end of a word respectively.
+A word is defined as a sequence of word characters
+which is neither preceded nor followed by
+word characters.
+A word character is an
+.Em alnum
+character (as defined by
+.Xr ctype 3 )
+or an underscore.
+This is an extension,
+compatible with but not specified by
+.St -p1003.2 ,
+and should be used with
+caution in software intended to be portable to other systems.
+The additional word delimiters
+.Ql \e<
+and
+.Ql \e>
+are provided to ease compatibility with traditional
+.Xr svr4 4
+systems but are not portable and should be avoided.
+.Pp
+In the event that an RE could match more than one substring of a given
+string,
+the RE matches the one starting earliest in the string.
+If the RE could match more than one substring starting at that point,
+it matches the longest.
+Subexpressions also match the longest possible substrings, subject to
+the constraint that the whole match be as long as possible,
+with subexpressions starting earlier in the RE taking priority over
+ones starting later.
+Note that higher-level subexpressions thus take priority over
+their lower-level component subexpressions.
+.Pp
+Match lengths are measured in characters, not collating elements.
+A null string is considered longer than no match at all.
+For example,
+.Ql bb*
+matches the three middle characters of
+.Ql abbbc ,
+.Ql (wee|week)(knights|nights)
+matches all ten characters of
+.Ql weeknights ,
+when
+.Ql (.*).*\&
+is matched against
+.Ql abc
+the parenthesized subexpression
+matches all three characters, and
+when
+.Ql (a*)*
+is matched against
+.Ql bc
+both the whole RE and the parenthesized
+subexpression match the null string.
+.Pp
+If case-independent matching is specified,
+the effect is much as if all case distinctions had vanished from the
+alphabet.
+When an alphabetic that exists in multiple cases appears as an
+ordinary character outside a bracket expression, it is effectively
+transformed into a bracket expression containing both cases,
+.No e.g. Ql x
+becomes
+.Ql [xX] .
+When it appears inside a bracket expression, all case counterparts
+of it are added to the bracket expression, so that (e.g.)
+.Ql [x]
+becomes
+.Ql [xX]
+and
+.Ql [^x]
+becomes
+.Ql [^xX] .
+.Pp
+No particular limit is imposed on the length of REs\(dd.
+Programs intended to be portable should not employ REs longer
+than 256 bytes,
+as an implementation can refuse to accept such REs and remain
+POSIX-compliant.
+.Pp
+Obsolete
+.Pq Dq basic
+regular expressions differ in several respects.
+.Ql \&|
+is an ordinary character and there is no equivalent
+for its functionality.
+.Ql \&+
+and
+.Ql ?\&
+are ordinary characters, and their functionality
+can be expressed using bounds
+.Po
+.Ql {1,}
+or
+.Ql {0,1}
+respectively
+.Pc .
+Also note that
+.Ql x+
+in modern REs is equivalent to
+.Ql xx* .
+The delimiters for bounds are
+.Ql \e{
+and
+.Ql \e} ,
+with
+.Ql \&{
+and
+.Ql \&}
+by themselves ordinary characters.
+The parentheses for nested subexpressions are
+.Ql \e(
+and
+.Ql \e) ,
+with
+.Ql \&(
+and
+.Ql \&)
+by themselves ordinary characters.
+.Ql \&^
+is an ordinary character except at the beginning of the
+RE or\(dd the beginning of a parenthesized subexpression,
+.Ql \&$
+is an ordinary character except at the end of the
+RE or\(dd the end of a parenthesized subexpression,
+and
+.Ql \&*
+is an ordinary character if it appears at the beginning of the
+RE or the beginning of a parenthesized subexpression
+(after a possible leading
+.Ql \&^ ) .
+Finally, there is one new type of atom, a
+.Em back reference :
+.Ql \e
+followed by a non-zero decimal digit
+.Em d
+matches the same sequence of characters
+matched by the
+.Em d Ns th
+parenthesized subexpression
+(numbering subexpressions by the positions of their opening parentheses,
+left to right),
+so that (e.g.)
+.Ql \e([bc]\e)\e1
+matches
+.Ql bb
+or
+.Ql cc
+but not
+.Ql bc .
+.Sh SEE ALSO
+.Xr regex 3
+.Rs
+.%T Regular Expression Notation
+.%R IEEE Std
+.%N 1003.2
+.%P section 2.8
+.Re
+.Sh BUGS
+Having two kinds of REs is a botch.
+.Pp
+The current
+.St -p1003.2
+spec says that
+.Ql \&)
+is an ordinary character in
+the absence of an unmatched
+.Ql \&( ;
+this was an unintentional result of a wording error,
+and change is likely.
+Avoid relying on it.
+.Pp
+Back references are a dreadful botch,
+posing major problems for efficient implementations.
+They are also somewhat vaguely defined
+(does
+.Ql a\e(\e(b\e)*\e2\e)*d
+match
+.Ql abbbd ? ) .
+Avoid using them.
+.Pp
+.St -p1003.2
+specification of case-independent matching is vague.
+The
+.Dq one case implies all cases
+definition given above
+is current consensus among implementors as to the right interpretation.
+.Pp
+The syntax for word boundaries is incredibly ugly.
diff --git a/lib/libc/regex/regcomp.c b/lib/libc/regex/regcomp.c
new file mode 100644
index 000000000000..b2b12555d25e
--- /dev/null
+++ b/lib/libc/regex/regcomp.c
@@ -0,0 +1,1817 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994 Henry Spencer.
+ * Copyright (c) 1992, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Henry Spencer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)regcomp.c 8.5 (Berkeley) 3/20/94
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)regcomp.c 8.5 (Berkeley) 3/20/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <regex.h>
+#include <wchar.h>
+#include <wctype.h>
+
+#include "collate.h"
+
+#include "utils.h"
+#include "regex2.h"
+
+#include "cname.h"
+
+/*
+ * parse structure, passed up and down to avoid global variables and
+ * other clumsinesses
+ */
+struct parse {
+ char *next; /* next character in RE */
+ char *end; /* end of string (-> NUL normally) */
+ int error; /* has an error been seen? */
+ sop *strip; /* malloced strip */
+ sopno ssize; /* malloced strip size (allocated) */
+ sopno slen; /* malloced strip length (used) */
+ int ncsalloc; /* number of csets allocated */
+ struct re_guts *g;
+# define NPAREN 10 /* we need to remember () 1-9 for back refs */
+ sopno pbegin[NPAREN]; /* -> ( ([0] unused) */
+ sopno pend[NPAREN]; /* -> ) ([0] unused) */
+};
+
+/* ========= begin header generated by ./mkh ========= */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* === regcomp.c === */
+static void p_ere(struct parse *p, int stop);
+static void p_ere_exp(struct parse *p);
+static void p_str(struct parse *p);
+static void p_bre(struct parse *p, int end1, int end2);
+static int p_simp_re(struct parse *p, int starordinary);
+static int p_count(struct parse *p);
+static void p_bracket(struct parse *p);
+static void p_b_term(struct parse *p, cset *cs);
+static void p_b_cclass(struct parse *p, cset *cs);
+static void p_b_eclass(struct parse *p, cset *cs);
+static wint_t p_b_symbol(struct parse *p);
+static wint_t p_b_coll_elem(struct parse *p, wint_t endc);
+static wint_t othercase(wint_t ch);
+static void bothcases(struct parse *p, wint_t ch);
+static void ordinary(struct parse *p, wint_t ch);
+static void nonnewline(struct parse *p);
+static void repeat(struct parse *p, sopno start, int from, int to);
+static int seterr(struct parse *p, int e);
+static cset *allocset(struct parse *p);
+static void freeset(struct parse *p, cset *cs);
+static void CHadd(struct parse *p, cset *cs, wint_t ch);
+static void CHaddrange(struct parse *p, cset *cs, wint_t min, wint_t max);
+static void CHaddtype(struct parse *p, cset *cs, wctype_t wct);
+static wint_t singleton(cset *cs);
+static sopno dupl(struct parse *p, sopno start, sopno finish);
+static void doemit(struct parse *p, sop op, size_t opnd);
+static void doinsert(struct parse *p, sop op, size_t opnd, sopno pos);
+static void dofwd(struct parse *p, sopno pos, sop value);
+static int enlarge(struct parse *p, sopno size);
+static void stripsnug(struct parse *p, struct re_guts *g);
+static void findmust(struct parse *p, struct re_guts *g);
+static int altoffset(sop *scan, int offset);
+static void computejumps(struct parse *p, struct re_guts *g);
+static void computematchjumps(struct parse *p, struct re_guts *g);
+static sopno pluscount(struct parse *p, struct re_guts *g);
+static wint_t wgetnext(struct parse *p);
+
+#ifdef __cplusplus
+}
+#endif
+/* ========= end header generated by ./mkh ========= */
+
+static char nuls[10]; /* place to point scanner in event of error */
+
+/*
+ * macros for use with parse structure
+ * BEWARE: these know that the parse structure is named `p' !!!
+ */
+#define PEEK() (*p->next)
+#define PEEK2() (*(p->next+1))
+#define MORE() (p->next < p->end)
+#define MORE2() (p->next+1 < p->end)
+#define SEE(c) (MORE() && PEEK() == (c))
+#define SEETWO(a, b) (MORE() && MORE2() && PEEK() == (a) && PEEK2() == (b))
+#define EAT(c) ((SEE(c)) ? (NEXT(), 1) : 0)
+#define EATTWO(a, b) ((SEETWO(a, b)) ? (NEXT2(), 1) : 0)
+#define NEXT() (p->next++)
+#define NEXT2() (p->next += 2)
+#define NEXTn(n) (p->next += (n))
+#define GETNEXT() (*p->next++)
+#define WGETNEXT() wgetnext(p)
+#define SETERROR(e) seterr(p, (e))
+#define REQUIRE(co, e) ((co) || SETERROR(e))
+#define MUSTSEE(c, e) (REQUIRE(MORE() && PEEK() == (c), e))
+#define MUSTEAT(c, e) (REQUIRE(MORE() && GETNEXT() == (c), e))
+#define MUSTNOTSEE(c, e) (REQUIRE(!MORE() || PEEK() != (c), e))
+#define EMIT(op, sopnd) doemit(p, (sop)(op), (size_t)(sopnd))
+#define INSERT(op, pos) doinsert(p, (sop)(op), HERE()-(pos)+1, pos)
+#define AHEAD(pos) dofwd(p, pos, HERE()-(pos))
+#define ASTERN(sop, pos) EMIT(sop, HERE()-pos)
+#define HERE() (p->slen)
+#define THERE() (p->slen - 1)
+#define THERETHERE() (p->slen - 2)
+#define DROP(n) (p->slen -= (n))
+
+#ifndef NDEBUG
+static int never = 0; /* for use in asserts; shuts lint up */
+#else
+#define never 0 /* some <assert.h>s have bugs too */
+#endif
+
+/* Macro used by computejump()/computematchjump() */
+#define MIN(a,b) ((a)<(b)?(a):(b))
+
+/*
+ - regcomp - interface for parser and compilation
+ = extern int regcomp(regex_t *, const char *, int);
+ = #define REG_BASIC 0000
+ = #define REG_EXTENDED 0001
+ = #define REG_ICASE 0002
+ = #define REG_NOSUB 0004
+ = #define REG_NEWLINE 0010
+ = #define REG_NOSPEC 0020
+ = #define REG_PEND 0040
+ = #define REG_DUMP 0200
+ */
+int /* 0 success, otherwise REG_something */
+regcomp(regex_t * __restrict preg,
+ const char * __restrict pattern,
+ int cflags)
+{
+ struct parse pa;
+ struct re_guts *g;
+ struct parse *p = &pa;
+ int i;
+ size_t len;
+ size_t maxlen;
+#ifdef REDEBUG
+# define GOODFLAGS(f) (f)
+#else
+# define GOODFLAGS(f) ((f)&~REG_DUMP)
+#endif
+
+ cflags = GOODFLAGS(cflags);
+ if ((cflags&REG_EXTENDED) && (cflags&REG_NOSPEC))
+ return(REG_INVARG);
+
+ if (cflags&REG_PEND) {
+ if (preg->re_endp < pattern)
+ return(REG_INVARG);
+ len = preg->re_endp - pattern;
+ } else
+ len = strlen((char *)pattern);
+
+ /* do the mallocs early so failure handling is easy */
+ g = (struct re_guts *)malloc(sizeof(struct re_guts));
+ if (g == NULL)
+ return(REG_ESPACE);
+ /*
+ * Limit the pattern space to avoid a 32-bit overflow on buffer
+ * extension. Also avoid any signed overflow in case of conversion
+ * so make the real limit based on a 31-bit overflow.
+ *
+ * Likely not applicable on 64-bit systems but handle the case
+ * generically (who are we to stop people from using ~715MB+
+ * patterns?).
+ */
+ maxlen = ((size_t)-1 >> 1) / sizeof(sop) * 2 / 3;
+ if (len >= maxlen) {
+ free((char *)g);
+ return(REG_ESPACE);
+ }
+ p->ssize = len/(size_t)2*(size_t)3 + (size_t)1; /* ugh */
+ assert(p->ssize >= len);
+
+ p->strip = (sop *)malloc(p->ssize * sizeof(sop));
+ p->slen = 0;
+ if (p->strip == NULL) {
+ free((char *)g);
+ return(REG_ESPACE);
+ }
+
+ /* set things up */
+ p->g = g;
+ p->next = (char *)pattern; /* convenience; we do not modify it */
+ p->end = p->next + len;
+ p->error = 0;
+ p->ncsalloc = 0;
+ for (i = 0; i < NPAREN; i++) {
+ p->pbegin[i] = 0;
+ p->pend[i] = 0;
+ }
+ g->sets = NULL;
+ g->ncsets = 0;
+ g->cflags = cflags;
+ g->iflags = 0;
+ g->nbol = 0;
+ g->neol = 0;
+ g->must = NULL;
+ g->moffset = -1;
+ g->charjump = NULL;
+ g->matchjump = NULL;
+ g->mlen = 0;
+ g->nsub = 0;
+ g->backrefs = 0;
+
+ /* do it */
+ EMIT(OEND, 0);
+ g->firststate = THERE();
+ if (cflags&REG_EXTENDED)
+ p_ere(p, OUT);
+ else if (cflags&REG_NOSPEC)
+ p_str(p);
+ else
+ p_bre(p, OUT, OUT);
+ EMIT(OEND, 0);
+ g->laststate = THERE();
+
+ /* tidy up loose ends and fill things in */
+ stripsnug(p, g);
+ findmust(p, g);
+ /* only use Boyer-Moore algorithm if the pattern is bigger
+ * than three characters
+ */
+ if(g->mlen > 3) {
+ computejumps(p, g);
+ computematchjumps(p, g);
+ if(g->matchjump == NULL && g->charjump != NULL) {
+ free(g->charjump);
+ g->charjump = NULL;
+ }
+ }
+ g->nplus = pluscount(p, g);
+ g->magic = MAGIC2;
+ preg->re_nsub = g->nsub;
+ preg->re_g = g;
+ preg->re_magic = MAGIC1;
+#ifndef REDEBUG
+ /* not debugging, so can't rely on the assert() in regexec() */
+ if (g->iflags&BAD)
+ SETERROR(REG_ASSERT);
+#endif
+
+ /* win or lose, we're done */
+ if (p->error != 0) /* lose */
+ regfree(preg);
+ return(p->error);
+}
+
+/*
+ - p_ere - ERE parser top level, concatenation and alternation
+ == static void p_ere(struct parse *p, int_t stop);
+ */
+static void
+p_ere(struct parse *p,
+ int stop) /* character this ERE should end at */
+{
+ char c;
+ sopno prevback;
+ sopno prevfwd;
+ sopno conc;
+ int first = 1; /* is this the first alternative? */
+
+ for (;;) {
+ /* do a bunch of concatenated expressions */
+ conc = HERE();
+ while (MORE() && (c = PEEK()) != '|' && c != stop)
+ p_ere_exp(p);
+ (void)REQUIRE(HERE() != conc, REG_EMPTY); /* require nonempty */
+
+ if (!EAT('|'))
+ break; /* NOTE BREAK OUT */
+
+ if (first) {
+ INSERT(OCH_, conc); /* offset is wrong */
+ prevfwd = conc;
+ prevback = conc;
+ first = 0;
+ }
+ ASTERN(OOR1, prevback);
+ prevback = THERE();
+ AHEAD(prevfwd); /* fix previous offset */
+ prevfwd = HERE();
+ EMIT(OOR2, 0); /* offset is very wrong */
+ }
+
+ if (!first) { /* tail-end fixups */
+ AHEAD(prevfwd);
+ ASTERN(O_CH, prevback);
+ }
+
+ assert(!MORE() || SEE(stop));
+}
+
+/*
+ - p_ere_exp - parse one subERE, an atom possibly followed by a repetition op
+ == static void p_ere_exp(struct parse *p);
+ */
+static void
+p_ere_exp(struct parse *p)
+{
+ char c;
+ wint_t wc;
+ sopno pos;
+ int count;
+ int count2;
+ sopno subno;
+ int wascaret = 0;
+
+ assert(MORE()); /* caller should have ensured this */
+ c = GETNEXT();
+
+ pos = HERE();
+ switch (c) {
+ case '(':
+ (void)REQUIRE(MORE(), REG_EPAREN);
+ p->g->nsub++;
+ subno = p->g->nsub;
+ if (subno < NPAREN)
+ p->pbegin[subno] = HERE();
+ EMIT(OLPAREN, subno);
+ if (!SEE(')'))
+ p_ere(p, ')');
+ if (subno < NPAREN) {
+ p->pend[subno] = HERE();
+ assert(p->pend[subno] != 0);
+ }
+ EMIT(ORPAREN, subno);
+ (void)MUSTEAT(')', REG_EPAREN);
+ break;
+#ifndef POSIX_MISTAKE
+ case ')': /* happens only if no current unmatched ( */
+ /*
+ * You may ask, why the ifndef? Because I didn't notice
+ * this until slightly too late for 1003.2, and none of the
+ * other 1003.2 regular-expression reviewers noticed it at
+ * all. So an unmatched ) is legal POSIX, at least until
+ * we can get it fixed.
+ */
+ SETERROR(REG_EPAREN);
+ break;
+#endif
+ case '^':
+ EMIT(OBOL, 0);
+ p->g->iflags |= USEBOL;
+ p->g->nbol++;
+ wascaret = 1;
+ break;
+ case '$':
+ EMIT(OEOL, 0);
+ p->g->iflags |= USEEOL;
+ p->g->neol++;
+ break;
+ case '|':
+ SETERROR(REG_EMPTY);
+ break;
+ case '*':
+ case '+':
+ case '?':
+ SETERROR(REG_BADRPT);
+ break;
+ case '.':
+ if (p->g->cflags&REG_NEWLINE)
+ nonnewline(p);
+ else
+ EMIT(OANY, 0);
+ break;
+ case '[':
+ p_bracket(p);
+ break;
+ case '\\':
+ (void)REQUIRE(MORE(), REG_EESCAPE);
+ wc = WGETNEXT();
+ switch (wc) {
+ case '<':
+ EMIT(OBOW, 0);
+ break;
+ case '>':
+ EMIT(OEOW, 0);
+ break;
+ default:
+ ordinary(p, wc);
+ break;
+ }
+ break;
+ case '{': /* okay as ordinary except if digit follows */
+ (void)REQUIRE(!MORE() || !isdigit((uch)PEEK()), REG_BADRPT);
+ /* FALLTHROUGH */
+ default:
+ p->next--;
+ wc = WGETNEXT();
+ ordinary(p, wc);
+ break;
+ }
+
+ if (!MORE())
+ return;
+ c = PEEK();
+ /* we call { a repetition if followed by a digit */
+ if (!( c == '*' || c == '+' || c == '?' ||
+ (c == '{' && MORE2() && isdigit((uch)PEEK2())) ))
+ return; /* no repetition, we're done */
+ NEXT();
+
+ (void)REQUIRE(!wascaret, REG_BADRPT);
+ switch (c) {
+ case '*': /* implemented as +? */
+ /* this case does not require the (y|) trick, noKLUDGE */
+ INSERT(OPLUS_, pos);
+ ASTERN(O_PLUS, pos);
+ INSERT(OQUEST_, pos);
+ ASTERN(O_QUEST, pos);
+ break;
+ case '+':
+ INSERT(OPLUS_, pos);
+ ASTERN(O_PLUS, pos);
+ break;
+ case '?':
+ /* KLUDGE: emit y? as (y|) until subtle bug gets fixed */
+ INSERT(OCH_, pos); /* offset slightly wrong */
+ ASTERN(OOR1, pos); /* this one's right */
+ AHEAD(pos); /* fix the OCH_ */
+ EMIT(OOR2, 0); /* offset very wrong... */
+ AHEAD(THERE()); /* ...so fix it */
+ ASTERN(O_CH, THERETHERE());
+ break;
+ case '{':
+ count = p_count(p);
+ if (EAT(',')) {
+ if (isdigit((uch)PEEK())) {
+ count2 = p_count(p);
+ (void)REQUIRE(count <= count2, REG_BADBR);
+ } else /* single number with comma */
+ count2 = INFINITY;
+ } else /* just a single number */
+ count2 = count;
+ repeat(p, pos, count, count2);
+ if (!EAT('}')) { /* error heuristics */
+ while (MORE() && PEEK() != '}')
+ NEXT();
+ (void)REQUIRE(MORE(), REG_EBRACE);
+ SETERROR(REG_BADBR);
+ }
+ break;
+ }
+
+ if (!MORE())
+ return;
+ c = PEEK();
+ if (!( c == '*' || c == '+' || c == '?' ||
+ (c == '{' && MORE2() && isdigit((uch)PEEK2())) ) )
+ return;
+ SETERROR(REG_BADRPT);
+}
+
+/*
+ - p_str - string (no metacharacters) "parser"
+ == static void p_str(struct parse *p);
+ */
+static void
+p_str(struct parse *p)
+{
+ (void)REQUIRE(MORE(), REG_EMPTY);
+ while (MORE())
+ ordinary(p, WGETNEXT());
+}
+
+/*
+ - p_bre - BRE parser top level, anchoring and concatenation
+ == static void p_bre(struct parse *p, int end1, \
+ == int end2);
+ * Giving end1 as OUT essentially eliminates the end1/end2 check.
+ *
+ * This implementation is a bit of a kludge, in that a trailing $ is first
+ * taken as an ordinary character and then revised to be an anchor.
+ * The amount of lookahead needed to avoid this kludge is excessive.
+ */
+static void
+p_bre(struct parse *p,
+ int end1, /* first terminating character */
+ int end2) /* second terminating character */
+{
+ sopno start = HERE();
+ int first = 1; /* first subexpression? */
+ int wasdollar = 0;
+
+ if (EAT('^')) {
+ EMIT(OBOL, 0);
+ p->g->iflags |= USEBOL;
+ p->g->nbol++;
+ }
+ while (MORE() && !SEETWO(end1, end2)) {
+ wasdollar = p_simp_re(p, first);
+ first = 0;
+ }
+ if (wasdollar) { /* oops, that was a trailing anchor */
+ DROP(1);
+ EMIT(OEOL, 0);
+ p->g->iflags |= USEEOL;
+ p->g->neol++;
+ }
+
+ (void)REQUIRE(HERE() != start, REG_EMPTY); /* require nonempty */
+}
+
+/*
+ - p_simp_re - parse a simple RE, an atom possibly followed by a repetition
+ == static int p_simp_re(struct parse *p, int starordinary);
+ */
+static int /* was the simple RE an unbackslashed $? */
+p_simp_re(struct parse *p,
+ int starordinary) /* is a leading * an ordinary character? */
+{
+ int c;
+ int count;
+ int count2;
+ sopno pos;
+ int i;
+ wint_t wc;
+ sopno subno;
+# define BACKSL (1<<CHAR_BIT)
+
+ pos = HERE(); /* repetition op, if any, covers from here */
+
+ assert(MORE()); /* caller should have ensured this */
+ c = GETNEXT();
+ if (c == '\\') {
+ (void)REQUIRE(MORE(), REG_EESCAPE);
+ c = BACKSL | GETNEXT();
+ }
+ switch (c) {
+ case '.':
+ if (p->g->cflags&REG_NEWLINE)
+ nonnewline(p);
+ else
+ EMIT(OANY, 0);
+ break;
+ case '[':
+ p_bracket(p);
+ break;
+ case BACKSL|'<':
+ EMIT(OBOW, 0);
+ break;
+ case BACKSL|'>':
+ EMIT(OEOW, 0);
+ break;
+ case BACKSL|'{':
+ SETERROR(REG_BADRPT);
+ break;
+ case BACKSL|'(':
+ p->g->nsub++;
+ subno = p->g->nsub;
+ if (subno < NPAREN)
+ p->pbegin[subno] = HERE();
+ EMIT(OLPAREN, subno);
+ /* the MORE here is an error heuristic */
+ if (MORE() && !SEETWO('\\', ')'))
+ p_bre(p, '\\', ')');
+ if (subno < NPAREN) {
+ p->pend[subno] = HERE();
+ assert(p->pend[subno] != 0);
+ }
+ EMIT(ORPAREN, subno);
+ (void)REQUIRE(EATTWO('\\', ')'), REG_EPAREN);
+ break;
+ case BACKSL|')': /* should not get here -- must be user */
+ case BACKSL|'}':
+ SETERROR(REG_EPAREN);
+ break;
+ case BACKSL|'1':
+ case BACKSL|'2':
+ case BACKSL|'3':
+ case BACKSL|'4':
+ case BACKSL|'5':
+ case BACKSL|'6':
+ case BACKSL|'7':
+ case BACKSL|'8':
+ case BACKSL|'9':
+ i = (c&~BACKSL) - '0';
+ assert(i < NPAREN);
+ if (p->pend[i] != 0) {
+ assert(i <= p->g->nsub);
+ EMIT(OBACK_, i);
+ assert(p->pbegin[i] != 0);
+ assert(OP(p->strip[p->pbegin[i]]) == OLPAREN);
+ assert(OP(p->strip[p->pend[i]]) == ORPAREN);
+ (void) dupl(p, p->pbegin[i]+1, p->pend[i]);
+ EMIT(O_BACK, i);
+ } else
+ SETERROR(REG_ESUBREG);
+ p->g->backrefs = 1;
+ break;
+ case '*':
+ (void)REQUIRE(starordinary, REG_BADRPT);
+ /* FALLTHROUGH */
+ default:
+ p->next--;
+ wc = WGETNEXT();
+ ordinary(p, wc);
+ break;
+ }
+
+ if (EAT('*')) { /* implemented as +? */
+ /* this case does not require the (y|) trick, noKLUDGE */
+ INSERT(OPLUS_, pos);
+ ASTERN(O_PLUS, pos);
+ INSERT(OQUEST_, pos);
+ ASTERN(O_QUEST, pos);
+ } else if (EATTWO('\\', '{')) {
+ count = p_count(p);
+ if (EAT(',')) {
+ if (MORE() && isdigit((uch)PEEK())) {
+ count2 = p_count(p);
+ (void)REQUIRE(count <= count2, REG_BADBR);
+ } else /* single number with comma */
+ count2 = INFINITY;
+ } else /* just a single number */
+ count2 = count;
+ repeat(p, pos, count, count2);
+ if (!EATTWO('\\', '}')) { /* error heuristics */
+ while (MORE() && !SEETWO('\\', '}'))
+ NEXT();
+ (void)REQUIRE(MORE(), REG_EBRACE);
+ SETERROR(REG_BADBR);
+ }
+ } else if (c == '$') /* $ (but not \$) ends it */
+ return(1);
+
+ return(0);
+}
+
+/*
+ - p_count - parse a repetition count
+ == static int p_count(struct parse *p);
+ */
+static int /* the value */
+p_count(struct parse *p)
+{
+ int count = 0;
+ int ndigits = 0;
+
+ while (MORE() && isdigit((uch)PEEK()) && count <= DUPMAX) {
+ count = count*10 + (GETNEXT() - '0');
+ ndigits++;
+ }
+
+ (void)REQUIRE(ndigits > 0 && count <= DUPMAX, REG_BADBR);
+ return(count);
+}
+
+/*
+ - p_bracket - parse a bracketed character list
+ == static void p_bracket(struct parse *p);
+ */
+static void
+p_bracket(struct parse *p)
+{
+ cset *cs;
+ wint_t ch;
+
+ /* Dept of Truly Sickening Special-Case Kludges */
+ if (p->next + 5 < p->end && strncmp(p->next, "[:<:]]", 6) == 0) {
+ EMIT(OBOW, 0);
+ NEXTn(6);
+ return;
+ }
+ if (p->next + 5 < p->end && strncmp(p->next, "[:>:]]", 6) == 0) {
+ EMIT(OEOW, 0);
+ NEXTn(6);
+ return;
+ }
+
+ if ((cs = allocset(p)) == NULL)
+ return;
+
+ if (p->g->cflags&REG_ICASE)
+ cs->icase = 1;
+ if (EAT('^'))
+ cs->invert = 1;
+ if (EAT(']'))
+ CHadd(p, cs, ']');
+ else if (EAT('-'))
+ CHadd(p, cs, '-');
+ while (MORE() && PEEK() != ']' && !SEETWO('-', ']'))
+ p_b_term(p, cs);
+ if (EAT('-'))
+ CHadd(p, cs, '-');
+ (void)MUSTEAT(']', REG_EBRACK);
+
+ if (p->error != 0) /* don't mess things up further */
+ return;
+
+ if (cs->invert && p->g->cflags&REG_NEWLINE)
+ cs->bmp['\n' >> 3] |= 1 << ('\n' & 7);
+
+ if ((ch = singleton(cs)) != OUT) { /* optimize singleton sets */
+ ordinary(p, ch);
+ freeset(p, cs);
+ } else
+ EMIT(OANYOF, (int)(cs - p->g->sets));
+}
+
+/*
+ - p_b_term - parse one term of a bracketed character list
+ == static void p_b_term(struct parse *p, cset *cs);
+ */
+static void
+p_b_term(struct parse *p, cset *cs)
+{
+ char c;
+ wint_t start, finish;
+ wint_t i;
+ struct xlocale_collate *table =
+ (struct xlocale_collate*)__get_locale()->components[XLC_COLLATE];
+
+ /* classify what we've got */
+ switch ((MORE()) ? PEEK() : '\0') {
+ case '[':
+ c = (MORE2()) ? PEEK2() : '\0';
+ break;
+ case '-':
+ SETERROR(REG_ERANGE);
+ return; /* NOTE RETURN */
+ default:
+ c = '\0';
+ break;
+ }
+
+ switch (c) {
+ case ':': /* character class */
+ NEXT2();
+ (void)REQUIRE(MORE(), REG_EBRACK);
+ c = PEEK();
+ (void)REQUIRE(c != '-' && c != ']', REG_ECTYPE);
+ p_b_cclass(p, cs);
+ (void)REQUIRE(MORE(), REG_EBRACK);
+ (void)REQUIRE(EATTWO(':', ']'), REG_ECTYPE);
+ break;
+ case '=': /* equivalence class */
+ NEXT2();
+ (void)REQUIRE(MORE(), REG_EBRACK);
+ c = PEEK();
+ (void)REQUIRE(c != '-' && c != ']', REG_ECOLLATE);
+ p_b_eclass(p, cs);
+ (void)REQUIRE(MORE(), REG_EBRACK);
+ (void)REQUIRE(EATTWO('=', ']'), REG_ECOLLATE);
+ break;
+ default: /* symbol, ordinary character, or range */
+ start = p_b_symbol(p);
+ if (SEE('-') && MORE2() && PEEK2() != ']') {
+ /* range */
+ NEXT();
+ if (EAT('-'))
+ finish = '-';
+ else
+ finish = p_b_symbol(p);
+ } else
+ finish = start;
+ if (start == finish)
+ CHadd(p, cs, start);
+ else {
+ if (table->__collate_load_error || MB_CUR_MAX > 1) {
+ (void)REQUIRE(start <= finish, REG_ERANGE);
+ CHaddrange(p, cs, start, finish);
+ } else {
+ (void)REQUIRE(__wcollate_range_cmp(start, finish) <= 0, REG_ERANGE);
+ for (i = 0; i <= UCHAR_MAX; i++) {
+ if ( __wcollate_range_cmp(start, i) <= 0
+ && __wcollate_range_cmp(i, finish) <= 0
+ )
+ CHadd(p, cs, i);
+ }
+ }
+ }
+ break;
+ }
+}
+
+/*
+ - p_b_cclass - parse a character-class name and deal with it
+ == static void p_b_cclass(struct parse *p, cset *cs);
+ */
+static void
+p_b_cclass(struct parse *p, cset *cs)
+{
+ char *sp = p->next;
+ size_t len;
+ wctype_t wct;
+ char clname[16];
+
+ while (MORE() && isalpha((uch)PEEK()))
+ NEXT();
+ len = p->next - sp;
+ if (len >= sizeof(clname) - 1) {
+ SETERROR(REG_ECTYPE);
+ return;
+ }
+ memcpy(clname, sp, len);
+ clname[len] = '\0';
+ if ((wct = wctype(clname)) == 0) {
+ SETERROR(REG_ECTYPE);
+ return;
+ }
+ CHaddtype(p, cs, wct);
+}
+
+/*
+ - p_b_eclass - parse an equivalence-class name and deal with it
+ == static void p_b_eclass(struct parse *p, cset *cs);
+ *
+ * This implementation is incomplete. xxx
+ */
+static void
+p_b_eclass(struct parse *p, cset *cs)
+{
+ wint_t c;
+
+ c = p_b_coll_elem(p, '=');
+ CHadd(p, cs, c);
+}
+
+/*
+ - p_b_symbol - parse a character or [..]ed multicharacter collating symbol
+ == static wint_t p_b_symbol(struct parse *p);
+ */
+static wint_t /* value of symbol */
+p_b_symbol(struct parse *p)
+{
+ wint_t value;
+
+ (void)REQUIRE(MORE(), REG_EBRACK);
+ if (!EATTWO('[', '.'))
+ return(WGETNEXT());
+
+ /* collating symbol */
+ value = p_b_coll_elem(p, '.');
+ (void)REQUIRE(EATTWO('.', ']'), REG_ECOLLATE);
+ return(value);
+}
+
+/*
+ - p_b_coll_elem - parse a collating-element name and look it up
+ == static wint_t p_b_coll_elem(struct parse *p, wint_t endc);
+ */
+static wint_t /* value of collating element */
+p_b_coll_elem(struct parse *p,
+ wint_t endc) /* name ended by endc,']' */
+{
+ char *sp = p->next;
+ struct cname *cp;
+ int len;
+ mbstate_t mbs;
+ wchar_t wc;
+ size_t clen;
+
+ while (MORE() && !SEETWO(endc, ']'))
+ NEXT();
+ if (!MORE()) {
+ SETERROR(REG_EBRACK);
+ return(0);
+ }
+ len = p->next - sp;
+ for (cp = cnames; cp->name != NULL; cp++)
+ if (strncmp(cp->name, sp, len) == 0 && cp->name[len] == '\0')
+ return(cp->code); /* known name */
+ memset(&mbs, 0, sizeof(mbs));
+ if ((clen = mbrtowc(&wc, sp, len, &mbs)) == len)
+ return (wc); /* single character */
+ else if (clen == (size_t)-1 || clen == (size_t)-2)
+ SETERROR(REG_ILLSEQ);
+ else
+ SETERROR(REG_ECOLLATE); /* neither */
+ return(0);
+}
+
+/*
+ - othercase - return the case counterpart of an alphabetic
+ == static wint_t othercase(wint_t ch);
+ */
+static wint_t /* if no counterpart, return ch */
+othercase(wint_t ch)
+{
+ assert(iswalpha(ch));
+ if (iswupper(ch))
+ return(towlower(ch));
+ else if (iswlower(ch))
+ return(towupper(ch));
+ else /* peculiar, but could happen */
+ return(ch);
+}
+
+/*
+ - bothcases - emit a dualcase version of a two-case character
+ == static void bothcases(struct parse *p, wint_t ch);
+ *
+ * Boy, is this implementation ever a kludge...
+ */
+static void
+bothcases(struct parse *p, wint_t ch)
+{
+ char *oldnext = p->next;
+ char *oldend = p->end;
+ char bracket[3 + MB_LEN_MAX];
+ size_t n;
+ mbstate_t mbs;
+
+ assert(othercase(ch) != ch); /* p_bracket() would recurse */
+ p->next = bracket;
+ memset(&mbs, 0, sizeof(mbs));
+ n = wcrtomb(bracket, ch, &mbs);
+ assert(n != (size_t)-1);
+ bracket[n] = ']';
+ bracket[n + 1] = '\0';
+ p->end = bracket+n+1;
+ p_bracket(p);
+ assert(p->next == p->end);
+ p->next = oldnext;
+ p->end = oldend;
+}
+
+/*
+ - ordinary - emit an ordinary character
+ == static void ordinary(struct parse *p, wint_t ch);
+ */
+static void
+ordinary(struct parse *p, wint_t ch)
+{
+ cset *cs;
+
+ if ((p->g->cflags&REG_ICASE) && iswalpha(ch) && othercase(ch) != ch)
+ bothcases(p, ch);
+ else if ((ch & OPDMASK) == ch)
+ EMIT(OCHAR, ch);
+ else {
+ /*
+ * Kludge: character is too big to fit into an OCHAR operand.
+ * Emit a singleton set.
+ */
+ if ((cs = allocset(p)) == NULL)
+ return;
+ CHadd(p, cs, ch);
+ EMIT(OANYOF, (int)(cs - p->g->sets));
+ }
+}
+
+/*
+ - nonnewline - emit REG_NEWLINE version of OANY
+ == static void nonnewline(struct parse *p);
+ *
+ * Boy, is this implementation ever a kludge...
+ */
+static void
+nonnewline(struct parse *p)
+{
+ char *oldnext = p->next;
+ char *oldend = p->end;
+ char bracket[4];
+
+ p->next = bracket;
+ p->end = bracket+3;
+ bracket[0] = '^';
+ bracket[1] = '\n';
+ bracket[2] = ']';
+ bracket[3] = '\0';
+ p_bracket(p);
+ assert(p->next == bracket+3);
+ p->next = oldnext;
+ p->end = oldend;
+}
+
+/*
+ - repeat - generate code for a bounded repetition, recursively if needed
+ == static void repeat(struct parse *p, sopno start, int from, int to);
+ */
+static void
+repeat(struct parse *p,
+ sopno start, /* operand from here to end of strip */
+ int from, /* repeated from this number */
+ int to) /* to this number of times (maybe INFINITY) */
+{
+ sopno finish = HERE();
+# define N 2
+# define INF 3
+# define REP(f, t) ((f)*8 + (t))
+# define MAP(n) (((n) <= 1) ? (n) : ((n) == INFINITY) ? INF : N)
+ sopno copy;
+
+ if (p->error != 0) /* head off possible runaway recursion */
+ return;
+
+ assert(from <= to);
+
+ switch (REP(MAP(from), MAP(to))) {
+ case REP(0, 0): /* must be user doing this */
+ DROP(finish-start); /* drop the operand */
+ break;
+ case REP(0, 1): /* as x{1,1}? */
+ case REP(0, N): /* as x{1,n}? */
+ case REP(0, INF): /* as x{1,}? */
+ /* KLUDGE: emit y? as (y|) until subtle bug gets fixed */
+ INSERT(OCH_, start); /* offset is wrong... */
+ repeat(p, start+1, 1, to);
+ ASTERN(OOR1, start);
+ AHEAD(start); /* ... fix it */
+ EMIT(OOR2, 0);
+ AHEAD(THERE());
+ ASTERN(O_CH, THERETHERE());
+ break;
+ case REP(1, 1): /* trivial case */
+ /* done */
+ break;
+ case REP(1, N): /* as x?x{1,n-1} */
+ /* KLUDGE: emit y? as (y|) until subtle bug gets fixed */
+ INSERT(OCH_, start);
+ ASTERN(OOR1, start);
+ AHEAD(start);
+ EMIT(OOR2, 0); /* offset very wrong... */
+ AHEAD(THERE()); /* ...so fix it */
+ ASTERN(O_CH, THERETHERE());
+ copy = dupl(p, start+1, finish+1);
+ assert(copy == finish+4);
+ repeat(p, copy, 1, to-1);
+ break;
+ case REP(1, INF): /* as x+ */
+ INSERT(OPLUS_, start);
+ ASTERN(O_PLUS, start);
+ break;
+ case REP(N, N): /* as xx{m-1,n-1} */
+ copy = dupl(p, start, finish);
+ repeat(p, copy, from-1, to-1);
+ break;
+ case REP(N, INF): /* as xx{n-1,INF} */
+ copy = dupl(p, start, finish);
+ repeat(p, copy, from-1, to);
+ break;
+ default: /* "can't happen" */
+ SETERROR(REG_ASSERT); /* just in case */
+ break;
+ }
+}
+
+/*
+ - wgetnext - helper function for WGETNEXT() macro. Gets the next wide
+ - character from the parse struct, signals a REG_ILLSEQ error if the
+ - character can't be converted. Returns the number of bytes consumed.
+ */
+static wint_t
+wgetnext(struct parse *p)
+{
+ mbstate_t mbs;
+ wchar_t wc;
+ size_t n;
+
+ memset(&mbs, 0, sizeof(mbs));
+ n = mbrtowc(&wc, p->next, p->end - p->next, &mbs);
+ if (n == (size_t)-1 || n == (size_t)-2) {
+ SETERROR(REG_ILLSEQ);
+ return (0);
+ }
+ if (n == 0)
+ n = 1;
+ p->next += n;
+ return (wc);
+}
+
+/*
+ - seterr - set an error condition
+ == static int seterr(struct parse *p, int e);
+ */
+static int /* useless but makes type checking happy */
+seterr(struct parse *p, int e)
+{
+ if (p->error == 0) /* keep earliest error condition */
+ p->error = e;
+ p->next = nuls; /* try to bring things to a halt */
+ p->end = nuls;
+ return(0); /* make the return value well-defined */
+}
+
+/*
+ - allocset - allocate a set of characters for []
+ == static cset *allocset(struct parse *p);
+ */
+static cset *
+allocset(struct parse *p)
+{
+ cset *cs, *ncs;
+
+ ncs = realloc(p->g->sets, (p->g->ncsets + 1) * sizeof(*ncs));
+ if (ncs == NULL) {
+ SETERROR(REG_ESPACE);
+ return (NULL);
+ }
+ p->g->sets = ncs;
+ cs = &p->g->sets[p->g->ncsets++];
+ memset(cs, 0, sizeof(*cs));
+
+ return(cs);
+}
+
+/*
+ - freeset - free a now-unused set
+ == static void freeset(struct parse *p, cset *cs);
+ */
+static void
+freeset(struct parse *p, cset *cs)
+{
+ cset *top = &p->g->sets[p->g->ncsets];
+
+ free(cs->wides);
+ free(cs->ranges);
+ free(cs->types);
+ memset(cs, 0, sizeof(*cs));
+ if (cs == top-1) /* recover only the easy case */
+ p->g->ncsets--;
+}
+
+/*
+ - singleton - Determine whether a set contains only one character,
+ - returning it if so, otherwise returning OUT.
+ */
+static wint_t
+singleton(cset *cs)
+{
+ wint_t i, s, n;
+
+ for (i = n = 0; i < NC; i++)
+ if (CHIN(cs, i)) {
+ n++;
+ s = i;
+ }
+ if (n == 1)
+ return (s);
+ if (cs->nwides == 1 && cs->nranges == 0 && cs->ntypes == 0 &&
+ cs->icase == 0)
+ return (cs->wides[0]);
+ /* Don't bother handling the other cases. */
+ return (OUT);
+}
+
+/*
+ - CHadd - add character to character set.
+ */
+static void
+CHadd(struct parse *p, cset *cs, wint_t ch)
+{
+ wint_t nch, *newwides;
+ assert(ch >= 0);
+ if (ch < NC)
+ cs->bmp[ch >> 3] |= 1 << (ch & 7);
+ else {
+ newwides = realloc(cs->wides, (cs->nwides + 1) *
+ sizeof(*cs->wides));
+ if (newwides == NULL) {
+ SETERROR(REG_ESPACE);
+ return;
+ }
+ cs->wides = newwides;
+ cs->wides[cs->nwides++] = ch;
+ }
+ if (cs->icase) {
+ if ((nch = towlower(ch)) < NC)
+ cs->bmp[nch >> 3] |= 1 << (nch & 7);
+ if ((nch = towupper(ch)) < NC)
+ cs->bmp[nch >> 3] |= 1 << (nch & 7);
+ }
+}
+
+/*
+ - CHaddrange - add all characters in the range [min,max] to a character set.
+ */
+static void
+CHaddrange(struct parse *p, cset *cs, wint_t min, wint_t max)
+{
+ crange *newranges;
+
+ for (; min < NC && min <= max; min++)
+ CHadd(p, cs, min);
+ if (min >= max)
+ return;
+ newranges = realloc(cs->ranges, (cs->nranges + 1) *
+ sizeof(*cs->ranges));
+ if (newranges == NULL) {
+ SETERROR(REG_ESPACE);
+ return;
+ }
+ cs->ranges = newranges;
+ cs->ranges[cs->nranges].min = min;
+ cs->ranges[cs->nranges].max = max;
+ cs->nranges++;
+}
+
+/*
+ - CHaddtype - add all characters of a certain type to a character set.
+ */
+static void
+CHaddtype(struct parse *p, cset *cs, wctype_t wct)
+{
+ wint_t i;
+ wctype_t *newtypes;
+
+ for (i = 0; i < NC; i++)
+ if (iswctype(i, wct))
+ CHadd(p, cs, i);
+ newtypes = realloc(cs->types, (cs->ntypes + 1) *
+ sizeof(*cs->types));
+ if (newtypes == NULL) {
+ SETERROR(REG_ESPACE);
+ return;
+ }
+ cs->types = newtypes;
+ cs->types[cs->ntypes++] = wct;
+}
+
+/*
+ - dupl - emit a duplicate of a bunch of sops
+ == static sopno dupl(struct parse *p, sopno start, sopno finish);
+ */
+static sopno /* start of duplicate */
+dupl(struct parse *p,
+ sopno start, /* from here */
+ sopno finish) /* to this less one */
+{
+ sopno ret = HERE();
+ sopno len = finish - start;
+
+ assert(finish >= start);
+ if (len == 0)
+ return(ret);
+ if (!enlarge(p, p->ssize + len)) /* this many unexpected additions */
+ return(ret);
+ (void) memcpy((char *)(p->strip + p->slen),
+ (char *)(p->strip + start), (size_t)len*sizeof(sop));
+ p->slen += len;
+ return(ret);
+}
+
+/*
+ - doemit - emit a strip operator
+ == static void doemit(struct parse *p, sop op, size_t opnd);
+ *
+ * It might seem better to implement this as a macro with a function as
+ * hard-case backup, but it's just too big and messy unless there are
+ * some changes to the data structures. Maybe later.
+ */
+static void
+doemit(struct parse *p, sop op, size_t opnd)
+{
+ /* avoid making error situations worse */
+ if (p->error != 0)
+ return;
+
+ /* deal with oversize operands ("can't happen", more or less) */
+ assert(opnd < 1<<OPSHIFT);
+
+ /* deal with undersized strip */
+ if (p->slen >= p->ssize)
+ if (!enlarge(p, (p->ssize+1) / 2 * 3)) /* +50% */
+ return;
+
+ /* finally, it's all reduced to the easy case */
+ p->strip[p->slen++] = SOP(op, opnd);
+}
+
+/*
+ - doinsert - insert a sop into the strip
+ == static void doinsert(struct parse *p, sop op, size_t opnd, sopno pos);
+ */
+static void
+doinsert(struct parse *p, sop op, size_t opnd, sopno pos)
+{
+ sopno sn;
+ sop s;
+ int i;
+
+ /* avoid making error situations worse */
+ if (p->error != 0)
+ return;
+
+ sn = HERE();
+ EMIT(op, opnd); /* do checks, ensure space */
+ assert(HERE() == sn+1);
+ s = p->strip[sn];
+
+ /* adjust paren pointers */
+ assert(pos > 0);
+ for (i = 1; i < NPAREN; i++) {
+ if (p->pbegin[i] >= pos) {
+ p->pbegin[i]++;
+ }
+ if (p->pend[i] >= pos) {
+ p->pend[i]++;
+ }
+ }
+
+ memmove((char *)&p->strip[pos+1], (char *)&p->strip[pos],
+ (HERE()-pos-1)*sizeof(sop));
+ p->strip[pos] = s;
+}
+
+/*
+ - dofwd - complete a forward reference
+ == static void dofwd(struct parse *p, sopno pos, sop value);
+ */
+static void
+dofwd(struct parse *p, sopno pos, sop value)
+{
+ /* avoid making error situations worse */
+ if (p->error != 0)
+ return;
+
+ assert(value < 1<<OPSHIFT);
+ p->strip[pos] = OP(p->strip[pos]) | value;
+}
+
+/*
+ - enlarge - enlarge the strip
+ == static int enlarge(struct parse *p, sopno size);
+ */
+static int
+enlarge(struct parse *p, sopno size)
+{
+ sop *sp;
+
+ if (p->ssize >= size)
+ return 1;
+
+ sp = (sop *)realloc(p->strip, size*sizeof(sop));
+ if (sp == NULL) {
+ SETERROR(REG_ESPACE);
+ return 0;
+ }
+ p->strip = sp;
+ p->ssize = size;
+ return 1;
+}
+
+/*
+ - stripsnug - compact the strip
+ == static void stripsnug(struct parse *p, struct re_guts *g);
+ */
+static void
+stripsnug(struct parse *p, struct re_guts *g)
+{
+ g->nstates = p->slen;
+ g->strip = (sop *)realloc((char *)p->strip, p->slen * sizeof(sop));
+ if (g->strip == NULL) {
+ SETERROR(REG_ESPACE);
+ g->strip = p->strip;
+ }
+}
+
+/*
+ - findmust - fill in must and mlen with longest mandatory literal string
+ == static void findmust(struct parse *p, struct re_guts *g);
+ *
+ * This algorithm could do fancy things like analyzing the operands of |
+ * for common subsequences. Someday. This code is simple and finds most
+ * of the interesting cases.
+ *
+ * Note that must and mlen got initialized during setup.
+ */
+static void
+findmust(struct parse *p, struct re_guts *g)
+{
+ sop *scan;
+ sop *start = NULL;
+ sop *newstart = NULL;
+ sopno newlen;
+ sop s;
+ char *cp;
+ int offset;
+ char buf[MB_LEN_MAX];
+ size_t clen;
+ mbstate_t mbs;
+
+ /* avoid making error situations worse */
+ if (p->error != 0)
+ return;
+
+ /*
+ * It's not generally safe to do a ``char'' substring search on
+ * multibyte character strings, but it's safe for at least
+ * UTF-8 (see RFC 3629).
+ */
+ if (MB_CUR_MAX > 1 &&
+ strcmp(_CurrentRuneLocale->__encoding, "UTF-8") != 0)
+ return;
+
+ /* find the longest OCHAR sequence in strip */
+ newlen = 0;
+ offset = 0;
+ g->moffset = 0;
+ scan = g->strip + 1;
+ do {
+ s = *scan++;
+ switch (OP(s)) {
+ case OCHAR: /* sequence member */
+ if (newlen == 0) { /* new sequence */
+ memset(&mbs, 0, sizeof(mbs));
+ newstart = scan - 1;
+ }
+ clen = wcrtomb(buf, OPND(s), &mbs);
+ if (clen == (size_t)-1)
+ goto toohard;
+ newlen += clen;
+ break;
+ case OPLUS_: /* things that don't break one */
+ case OLPAREN:
+ case ORPAREN:
+ break;
+ case OQUEST_: /* things that must be skipped */
+ case OCH_:
+ offset = altoffset(scan, offset);
+ scan--;
+ do {
+ scan += OPND(s);
+ s = *scan;
+ /* assert() interferes w debug printouts */
+ if (OP(s) != O_QUEST && OP(s) != O_CH &&
+ OP(s) != OOR2) {
+ g->iflags |= BAD;
+ return;
+ }
+ } while (OP(s) != O_QUEST && OP(s) != O_CH);
+ /* FALLTHROUGH */
+ case OBOW: /* things that break a sequence */
+ case OEOW:
+ case OBOL:
+ case OEOL:
+ case O_QUEST:
+ case O_CH:
+ case OEND:
+ if (newlen > g->mlen) { /* ends one */
+ start = newstart;
+ g->mlen = newlen;
+ if (offset > -1) {
+ g->moffset += offset;
+ offset = newlen;
+ } else
+ g->moffset = offset;
+ } else {
+ if (offset > -1)
+ offset += newlen;
+ }
+ newlen = 0;
+ break;
+ case OANY:
+ if (newlen > g->mlen) { /* ends one */
+ start = newstart;
+ g->mlen = newlen;
+ if (offset > -1) {
+ g->moffset += offset;
+ offset = newlen;
+ } else
+ g->moffset = offset;
+ } else {
+ if (offset > -1)
+ offset += newlen;
+ }
+ if (offset > -1)
+ offset++;
+ newlen = 0;
+ break;
+ case OANYOF: /* may or may not invalidate offset */
+ /* First, everything as OANY */
+ if (newlen > g->mlen) { /* ends one */
+ start = newstart;
+ g->mlen = newlen;
+ if (offset > -1) {
+ g->moffset += offset;
+ offset = newlen;
+ } else
+ g->moffset = offset;
+ } else {
+ if (offset > -1)
+ offset += newlen;
+ }
+ if (offset > -1)
+ offset++;
+ newlen = 0;
+ break;
+ toohard:
+ default:
+ /* Anything here makes it impossible or too hard
+ * to calculate the offset -- so we give up;
+ * save the last known good offset, in case the
+ * must sequence doesn't occur later.
+ */
+ if (newlen > g->mlen) { /* ends one */
+ start = newstart;
+ g->mlen = newlen;
+ if (offset > -1)
+ g->moffset += offset;
+ else
+ g->moffset = offset;
+ }
+ offset = -1;
+ newlen = 0;
+ break;
+ }
+ } while (OP(s) != OEND);
+
+ if (g->mlen == 0) { /* there isn't one */
+ g->moffset = -1;
+ return;
+ }
+
+ /* turn it into a character string */
+ g->must = malloc((size_t)g->mlen + 1);
+ if (g->must == NULL) { /* argh; just forget it */
+ g->mlen = 0;
+ g->moffset = -1;
+ return;
+ }
+ cp = g->must;
+ scan = start;
+ memset(&mbs, 0, sizeof(mbs));
+ while (cp < g->must + g->mlen) {
+ while (OP(s = *scan++) != OCHAR)
+ continue;
+ clen = wcrtomb(cp, OPND(s), &mbs);
+ assert(clen != (size_t)-1);
+ cp += clen;
+ }
+ assert(cp == g->must + g->mlen);
+ *cp++ = '\0'; /* just on general principles */
+}
+
+/*
+ - altoffset - choose biggest offset among multiple choices
+ == static int altoffset(sop *scan, int offset);
+ *
+ * Compute, recursively if necessary, the largest offset among multiple
+ * re paths.
+ */
+static int
+altoffset(sop *scan, int offset)
+{
+ int largest;
+ int try;
+ sop s;
+
+ /* If we gave up already on offsets, return */
+ if (offset == -1)
+ return -1;
+
+ largest = 0;
+ try = 0;
+ s = *scan++;
+ while (OP(s) != O_QUEST && OP(s) != O_CH) {
+ switch (OP(s)) {
+ case OOR1:
+ if (try > largest)
+ largest = try;
+ try = 0;
+ break;
+ case OQUEST_:
+ case OCH_:
+ try = altoffset(scan, try);
+ if (try == -1)
+ return -1;
+ scan--;
+ do {
+ scan += OPND(s);
+ s = *scan;
+ if (OP(s) != O_QUEST && OP(s) != O_CH &&
+ OP(s) != OOR2)
+ return -1;
+ } while (OP(s) != O_QUEST && OP(s) != O_CH);
+ /* We must skip to the next position, or we'll
+ * leave altoffset() too early.
+ */
+ scan++;
+ break;
+ case OANYOF:
+ case OCHAR:
+ case OANY:
+ try++;
+ case OBOW:
+ case OEOW:
+ case OLPAREN:
+ case ORPAREN:
+ case OOR2:
+ break;
+ default:
+ try = -1;
+ break;
+ }
+ if (try == -1)
+ return -1;
+ s = *scan++;
+ }
+
+ if (try > largest)
+ largest = try;
+
+ return largest+offset;
+}
+
+/*
+ - computejumps - compute char jumps for BM scan
+ == static void computejumps(struct parse *p, struct re_guts *g);
+ *
+ * This algorithm assumes g->must exists and is has size greater than
+ * zero. It's based on the algorithm found on Computer Algorithms by
+ * Sara Baase.
+ *
+ * A char jump is the number of characters one needs to jump based on
+ * the value of the character from the text that was mismatched.
+ */
+static void
+computejumps(struct parse *p, struct re_guts *g)
+{
+ int ch;
+ int mindex;
+
+ /* Avoid making errors worse */
+ if (p->error != 0)
+ return;
+
+ g->charjump = (int*) malloc((NC + 1) * sizeof(int));
+ if (g->charjump == NULL) /* Not a fatal error */
+ return;
+ /* Adjust for signed chars, if necessary */
+ g->charjump = &g->charjump[-(CHAR_MIN)];
+
+ /* If the character does not exist in the pattern, the jump
+ * is equal to the number of characters in the pattern.
+ */
+ for (ch = CHAR_MIN; ch < (CHAR_MAX + 1); ch++)
+ g->charjump[ch] = g->mlen;
+
+ /* If the character does exist, compute the jump that would
+ * take us to the last character in the pattern equal to it
+ * (notice that we match right to left, so that last character
+ * is the first one that would be matched).
+ */
+ for (mindex = 0; mindex < g->mlen; mindex++)
+ g->charjump[(int)g->must[mindex]] = g->mlen - mindex - 1;
+}
+
+/*
+ - computematchjumps - compute match jumps for BM scan
+ == static void computematchjumps(struct parse *p, struct re_guts *g);
+ *
+ * This algorithm assumes g->must exists and is has size greater than
+ * zero. It's based on the algorithm found on Computer Algorithms by
+ * Sara Baase.
+ *
+ * A match jump is the number of characters one needs to advance based
+ * on the already-matched suffix.
+ * Notice that all values here are minus (g->mlen-1), because of the way
+ * the search algorithm works.
+ */
+static void
+computematchjumps(struct parse *p, struct re_guts *g)
+{
+ int mindex; /* General "must" iterator */
+ int suffix; /* Keeps track of matching suffix */
+ int ssuffix; /* Keeps track of suffixes' suffix */
+ int* pmatches; /* pmatches[k] points to the next i
+ * such that i+1...mlen is a substring
+ * of k+1...k+mlen-i-1
+ */
+
+ /* Avoid making errors worse */
+ if (p->error != 0)
+ return;
+
+ pmatches = (int*) malloc(g->mlen * sizeof(int));
+ if (pmatches == NULL) {
+ g->matchjump = NULL;
+ return;
+ }
+
+ g->matchjump = (int*) malloc(g->mlen * sizeof(int));
+ if (g->matchjump == NULL) { /* Not a fatal error */
+ free(pmatches);
+ return;
+ }
+
+ /* Set maximum possible jump for each character in the pattern */
+ for (mindex = 0; mindex < g->mlen; mindex++)
+ g->matchjump[mindex] = 2*g->mlen - mindex - 1;
+
+ /* Compute pmatches[] */
+ for (mindex = g->mlen - 1, suffix = g->mlen; mindex >= 0;
+ mindex--, suffix--) {
+ pmatches[mindex] = suffix;
+
+ /* If a mismatch is found, interrupting the substring,
+ * compute the matchjump for that position. If no
+ * mismatch is found, then a text substring mismatched
+ * against the suffix will also mismatch against the
+ * substring.
+ */
+ while (suffix < g->mlen
+ && g->must[mindex] != g->must[suffix]) {
+ g->matchjump[suffix] = MIN(g->matchjump[suffix],
+ g->mlen - mindex - 1);
+ suffix = pmatches[suffix];
+ }
+ }
+
+ /* Compute the matchjump up to the last substring found to jump
+ * to the beginning of the largest must pattern prefix matching
+ * it's own suffix.
+ */
+ for (mindex = 0; mindex <= suffix; mindex++)
+ g->matchjump[mindex] = MIN(g->matchjump[mindex],
+ g->mlen + suffix - mindex);
+
+ ssuffix = pmatches[suffix];
+ while (suffix < g->mlen) {
+ while (suffix <= ssuffix && suffix < g->mlen) {
+ g->matchjump[suffix] = MIN(g->matchjump[suffix],
+ g->mlen + ssuffix - suffix);
+ suffix++;
+ }
+ if (suffix < g->mlen)
+ ssuffix = pmatches[ssuffix];
+ }
+
+ free(pmatches);
+}
+
+/*
+ - pluscount - count + nesting
+ == static sopno pluscount(struct parse *p, struct re_guts *g);
+ */
+static sopno /* nesting depth */
+pluscount(struct parse *p, struct re_guts *g)
+{
+ sop *scan;
+ sop s;
+ sopno plusnest = 0;
+ sopno maxnest = 0;
+
+ if (p->error != 0)
+ return(0); /* there may not be an OEND */
+
+ scan = g->strip + 1;
+ do {
+ s = *scan++;
+ switch (OP(s)) {
+ case OPLUS_:
+ plusnest++;
+ break;
+ case O_PLUS:
+ if (plusnest > maxnest)
+ maxnest = plusnest;
+ plusnest--;
+ break;
+ }
+ } while (OP(s) != OEND);
+ if (plusnest != 0)
+ g->iflags |= BAD;
+ return(maxnest);
+}
diff --git a/lib/libc/regex/regerror.c b/lib/libc/regex/regerror.c
new file mode 100644
index 000000000000..b9b773cc602e
--- /dev/null
+++ b/lib/libc/regex/regerror.c
@@ -0,0 +1,174 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994 Henry Spencer.
+ * Copyright (c) 1992, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Henry Spencer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)regerror.c 8.4 (Berkeley) 3/20/94
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)regerror.c 8.4 (Berkeley) 3/20/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <regex.h>
+
+#include "utils.h"
+
+/* ========= begin header generated by ./mkh ========= */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* === regerror.c === */
+static char *regatoi(const regex_t *preg, char *localbuf);
+
+#ifdef __cplusplus
+}
+#endif
+/* ========= end header generated by ./mkh ========= */
+/*
+ = #define REG_NOMATCH 1
+ = #define REG_BADPAT 2
+ = #define REG_ECOLLATE 3
+ = #define REG_ECTYPE 4
+ = #define REG_EESCAPE 5
+ = #define REG_ESUBREG 6
+ = #define REG_EBRACK 7
+ = #define REG_EPAREN 8
+ = #define REG_EBRACE 9
+ = #define REG_BADBR 10
+ = #define REG_ERANGE 11
+ = #define REG_ESPACE 12
+ = #define REG_BADRPT 13
+ = #define REG_EMPTY 14
+ = #define REG_ASSERT 15
+ = #define REG_INVARG 16
+ = #define REG_ILLSEQ 17
+ = #define REG_ATOI 255 // convert name to number (!)
+ = #define REG_ITOA 0400 // convert number to name (!)
+ */
+static struct rerr {
+ int code;
+ char *name;
+ char *explain;
+} rerrs[] = {
+ {REG_NOMATCH, "REG_NOMATCH", "regexec() failed to match"},
+ {REG_BADPAT, "REG_BADPAT", "invalid regular expression"},
+ {REG_ECOLLATE, "REG_ECOLLATE", "invalid collating element"},
+ {REG_ECTYPE, "REG_ECTYPE", "invalid character class"},
+ {REG_EESCAPE, "REG_EESCAPE", "trailing backslash (\\)"},
+ {REG_ESUBREG, "REG_ESUBREG", "invalid backreference number"},
+ {REG_EBRACK, "REG_EBRACK", "brackets ([ ]) not balanced"},
+ {REG_EPAREN, "REG_EPAREN", "parentheses not balanced"},
+ {REG_EBRACE, "REG_EBRACE", "braces not balanced"},
+ {REG_BADBR, "REG_BADBR", "invalid repetition count(s)"},
+ {REG_ERANGE, "REG_ERANGE", "invalid character range"},
+ {REG_ESPACE, "REG_ESPACE", "out of memory"},
+ {REG_BADRPT, "REG_BADRPT", "repetition-operator operand invalid"},
+ {REG_EMPTY, "REG_EMPTY", "empty (sub)expression"},
+ {REG_ASSERT, "REG_ASSERT", "\"can't happen\" -- you found a bug"},
+ {REG_INVARG, "REG_INVARG", "invalid argument to regex routine"},
+ {REG_ILLSEQ, "REG_ILLSEQ", "illegal byte sequence"},
+ {0, "", "*** unknown regexp error code ***"}
+};
+
+/*
+ - regerror - the interface to error numbers
+ = extern size_t regerror(int, const regex_t *, char *, size_t);
+ */
+/* ARGSUSED */
+size_t
+regerror(int errcode,
+ const regex_t * __restrict preg,
+ char * __restrict errbuf,
+ size_t errbuf_size)
+{
+ struct rerr *r;
+ size_t len;
+ int target = errcode &~ REG_ITOA;
+ char *s;
+ char convbuf[50];
+
+ if (errcode == REG_ATOI)
+ s = regatoi(preg, convbuf);
+ else {
+ for (r = rerrs; r->code != 0; r++)
+ if (r->code == target)
+ break;
+
+ if (errcode&REG_ITOA) {
+ if (r->code != 0)
+ (void) strcpy(convbuf, r->name);
+ else
+ sprintf(convbuf, "REG_0x%x", target);
+ assert(strlen(convbuf) < sizeof(convbuf));
+ s = convbuf;
+ } else
+ s = r->explain;
+ }
+
+ len = strlen(s) + 1;
+ if (errbuf_size > 0) {
+ if (errbuf_size > len)
+ (void) strcpy(errbuf, s);
+ else {
+ (void) strncpy(errbuf, s, errbuf_size-1);
+ errbuf[errbuf_size-1] = '\0';
+ }
+ }
+
+ return(len);
+}
+
+/*
+ - regatoi - internal routine to implement REG_ATOI
+ == static char *regatoi(const regex_t *preg, char *localbuf);
+ */
+static char *
+regatoi(const regex_t *preg, char *localbuf)
+{
+ struct rerr *r;
+
+ for (r = rerrs; r->code != 0; r++)
+ if (strcmp(r->name, preg->re_endp) == 0)
+ break;
+ if (r->code == 0)
+ return("0");
+
+ sprintf(localbuf, "%d", r->code);
+ return(localbuf);
+}
diff --git a/lib/libc/regex/regex.3 b/lib/libc/regex/regex.3
new file mode 100644
index 000000000000..d6f6c804124b
--- /dev/null
+++ b/lib/libc/regex/regex.3
@@ -0,0 +1,755 @@
+.\" Copyright (c) 1992, 1993, 1994 Henry Spencer.
+.\" Copyright (c) 1992, 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Henry Spencer.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)regex.3 8.4 (Berkeley) 3/20/94
+.\" $FreeBSD$
+.\"
+.Dd May 25, 2016
+.Dt REGEX 3
+.Os
+.Sh NAME
+.Nm regcomp ,
+.Nm regexec ,
+.Nm regerror ,
+.Nm regfree
+.Nd regular-expression library
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In regex.h
+.Ft int
+.Fo regcomp
+.Fa "regex_t * restrict preg" "const char * restrict pattern" "int cflags"
+.Fc
+.Ft int
+.Fo regexec
+.Fa "const regex_t * restrict preg" "const char * restrict string"
+.Fa "size_t nmatch" "regmatch_t pmatch[restrict]" "int eflags"
+.Fc
+.Ft size_t
+.Fo regerror
+.Fa "int errcode" "const regex_t * restrict preg"
+.Fa "char * restrict errbuf" "size_t errbuf_size"
+.Fc
+.Ft void
+.Fn regfree "regex_t *preg"
+.Sh DESCRIPTION
+These routines implement
+.St -p1003.2
+regular expressions
+.Pq Do RE Dc Ns s ;
+see
+.Xr re_format 7 .
+The
+.Fn regcomp
+function
+compiles an RE written as a string into an internal form,
+.Fn regexec
+matches that internal form against a string and reports results,
+.Fn regerror
+transforms error codes from either into human-readable messages,
+and
+.Fn regfree
+frees any dynamically-allocated storage used by the internal form
+of an RE.
+.Pp
+The header
+.In regex.h
+declares two structure types,
+.Ft regex_t
+and
+.Ft regmatch_t ,
+the former for compiled internal forms and the latter for match reporting.
+It also declares the four functions,
+a type
+.Ft regoff_t ,
+and a number of constants with names starting with
+.Dq Dv REG_ .
+.Pp
+The
+.Fn regcomp
+function
+compiles the regular expression contained in the
+.Fa pattern
+string,
+subject to the flags in
+.Fa cflags ,
+and places the results in the
+.Ft regex_t
+structure pointed to by
+.Fa preg .
+The
+.Fa cflags
+argument
+is the bitwise OR of zero or more of the following flags:
+.Bl -tag -width REG_EXTENDED
+.It Dv REG_EXTENDED
+Compile modern
+.Pq Dq extended
+REs,
+rather than the obsolete
+.Pq Dq basic
+REs that
+are the default.
+.It Dv REG_BASIC
+This is a synonym for 0,
+provided as a counterpart to
+.Dv REG_EXTENDED
+to improve readability.
+.It Dv REG_NOSPEC
+Compile with recognition of all special characters turned off.
+All characters are thus considered ordinary,
+so the
+.Dq RE
+is a literal string.
+This is an extension,
+compatible with but not specified by
+.St -p1003.2 ,
+and should be used with
+caution in software intended to be portable to other systems.
+.Dv REG_EXTENDED
+and
+.Dv REG_NOSPEC
+may not be used
+in the same call to
+.Fn regcomp .
+.It Dv REG_ICASE
+Compile for matching that ignores upper/lower case distinctions.
+See
+.Xr re_format 7 .
+.It Dv REG_NOSUB
+Compile for matching that need only report success or failure,
+not what was matched.
+.It Dv REG_NEWLINE
+Compile for newline-sensitive matching.
+By default, newline is a completely ordinary character with no special
+meaning in either REs or strings.
+With this flag,
+.Ql [^
+bracket expressions and
+.Ql .\&
+never match newline,
+a
+.Ql ^\&
+anchor matches the null string after any newline in the string
+in addition to its normal function,
+and the
+.Ql $\&
+anchor matches the null string before any newline in the
+string in addition to its normal function.
+.It Dv REG_PEND
+The regular expression ends,
+not at the first NUL,
+but just before the character pointed to by the
+.Va re_endp
+member of the structure pointed to by
+.Fa preg .
+The
+.Va re_endp
+member is of type
+.Ft "const char *" .
+This flag permits inclusion of NULs in the RE;
+they are considered ordinary characters.
+This is an extension,
+compatible with but not specified by
+.St -p1003.2 ,
+and should be used with
+caution in software intended to be portable to other systems.
+.El
+.Pp
+When successful,
+.Fn regcomp
+returns 0 and fills in the structure pointed to by
+.Fa preg .
+One member of that structure
+(other than
+.Va re_endp )
+is publicized:
+.Va re_nsub ,
+of type
+.Ft size_t ,
+contains the number of parenthesized subexpressions within the RE
+(except that the value of this member is undefined if the
+.Dv REG_NOSUB
+flag was used).
+If
+.Fn regcomp
+fails, it returns a non-zero error code;
+see
+.Sx DIAGNOSTICS .
+.Pp
+The
+.Fn regexec
+function
+matches the compiled RE pointed to by
+.Fa preg
+against the
+.Fa string ,
+subject to the flags in
+.Fa eflags ,
+and reports results using
+.Fa nmatch ,
+.Fa pmatch ,
+and the returned value.
+The RE must have been compiled by a previous invocation of
+.Fn regcomp .
+The compiled form is not altered during execution of
+.Fn regexec ,
+so a single compiled RE can be used simultaneously by multiple threads.
+.Pp
+By default,
+the NUL-terminated string pointed to by
+.Fa string
+is considered to be the text of an entire line, minus any terminating
+newline.
+The
+.Fa eflags
+argument is the bitwise OR of zero or more of the following flags:
+.Bl -tag -width REG_STARTEND
+.It Dv REG_NOTBOL
+The first character of the string is treated as the continuation
+of a line.
+This means that the anchors
+.Ql ^\& ,
+.Ql [[:<:]] ,
+and
+.Ql \e<
+do not match before it; but see
+.Dv REG_STARTEND
+below.
+This does not affect the behavior of newlines under
+.Dv REG_NEWLINE .
+.It Dv REG_NOTEOL
+The NUL terminating
+the string
+does not end a line, so the
+.Ql $\&
+anchor does not match before it.
+This does not affect the behavior of newlines under
+.Dv REG_NEWLINE .
+.It Dv REG_STARTEND
+The string is considered to start at
+.Fa string No +
+.Fa pmatch Ns [0]. Ns Fa rm_so
+and to end before the byte located at
+.Fa string No +
+.Fa pmatch Ns [0]. Ns Fa rm_eo ,
+regardless of the value of
+.Fa nmatch .
+See below for the definition of
+.Fa pmatch
+and
+.Fa nmatch .
+This is an extension,
+compatible with but not specified by
+.St -p1003.2 ,
+and should be used with
+caution in software intended to be portable to other systems.
+.Pp
+Without
+.Dv REG_NOTBOL ,
+the position
+.Fa rm_so
+is considered the beginning of a line, such that
+.Ql ^
+matches before it, and the beginning of a word if there is a word
+character at this position, such that
+.Ql [[:<:]]
+and
+.Ql \e<
+match before it.
+.Pp
+With
+.Dv REG_NOTBOL ,
+the character at position
+.Fa rm_so
+is treated as the continuation of a line, and if
+.Fa rm_so
+is greater than 0, the preceding character is taken into consideration.
+If the preceding character is a newline and the regular expression was compiled
+with
+.Dv REG_NEWLINE ,
+.Ql ^
+matches before the string; if the preceding character is not a word character
+but the string starts with a word character,
+.Ql [[:<:]]
+and
+.Ql \e<
+match before the string.
+.El
+.Pp
+See
+.Xr re_format 7
+for a discussion of what is matched in situations where an RE or a
+portion thereof could match any of several substrings of
+.Fa string .
+.Pp
+Normally,
+.Fn regexec
+returns 0 for success and the non-zero code
+.Dv REG_NOMATCH
+for failure.
+Other non-zero error codes may be returned in exceptional situations;
+see
+.Sx DIAGNOSTICS .
+.Pp
+If
+.Dv REG_NOSUB
+was specified in the compilation of the RE,
+or if
+.Fa nmatch
+is 0,
+.Fn regexec
+ignores the
+.Fa pmatch
+argument (but see below for the case where
+.Dv REG_STARTEND
+is specified).
+Otherwise,
+.Fa pmatch
+points to an array of
+.Fa nmatch
+structures of type
+.Ft regmatch_t .
+Such a structure has at least the members
+.Va rm_so
+and
+.Va rm_eo ,
+both of type
+.Ft regoff_t
+(a signed arithmetic type at least as large as an
+.Ft off_t
+and a
+.Ft ssize_t ) ,
+containing respectively the offset of the first character of a substring
+and the offset of the first character after the end of the substring.
+Offsets are measured from the beginning of the
+.Fa string
+argument given to
+.Fn regexec .
+An empty substring is denoted by equal offsets,
+both indicating the character following the empty substring.
+.Pp
+The 0th member of the
+.Fa pmatch
+array is filled in to indicate what substring of
+.Fa string
+was matched by the entire RE.
+Remaining members report what substring was matched by parenthesized
+subexpressions within the RE;
+member
+.Va i
+reports subexpression
+.Va i ,
+with subexpressions counted (starting at 1) by the order of their opening
+parentheses in the RE, left to right.
+Unused entries in the array (corresponding either to subexpressions that
+did not participate in the match at all, or to subexpressions that do not
+exist in the RE (that is,
+.Va i
+>
+.Fa preg Ns -> Ns Va re_nsub ) )
+have both
+.Va rm_so
+and
+.Va rm_eo
+set to -1.
+If a subexpression participated in the match several times,
+the reported substring is the last one it matched.
+(Note, as an example in particular, that when the RE
+.Ql "(b*)+"
+matches
+.Ql bbb ,
+the parenthesized subexpression matches each of the three
+.So Li b Sc Ns s
+and then
+an infinite number of empty strings following the last
+.Ql b ,
+so the reported substring is one of the empties.)
+.Pp
+If
+.Dv REG_STARTEND
+is specified,
+.Fa pmatch
+must point to at least one
+.Ft regmatch_t
+(even if
+.Fa nmatch
+is 0 or
+.Dv REG_NOSUB
+was specified),
+to hold the input offsets for
+.Dv REG_STARTEND .
+Use for output is still entirely controlled by
+.Fa nmatch ;
+if
+.Fa nmatch
+is 0 or
+.Dv REG_NOSUB
+was specified,
+the value of
+.Fa pmatch Ns [0]
+will not be changed by a successful
+.Fn regexec .
+.Pp
+The
+.Fn regerror
+function
+maps a non-zero
+.Fa errcode
+from either
+.Fn regcomp
+or
+.Fn regexec
+to a human-readable, printable message.
+If
+.Fa preg
+is
+.No non\- Ns Dv NULL ,
+the error code should have arisen from use of
+the
+.Ft regex_t
+pointed to by
+.Fa preg ,
+and if the error code came from
+.Fn regcomp ,
+it should have been the result from the most recent
+.Fn regcomp
+using that
+.Ft regex_t .
+The
+.Po
+.Fn regerror
+may be able to supply a more detailed message using information
+from the
+.Ft regex_t .
+.Pc
+The
+.Fn regerror
+function
+places the NUL-terminated message into the buffer pointed to by
+.Fa errbuf ,
+limiting the length (including the NUL) to at most
+.Fa errbuf_size
+bytes.
+If the whole message will not fit,
+as much of it as will fit before the terminating NUL is supplied.
+In any case,
+the returned value is the size of buffer needed to hold the whole
+message (including terminating NUL).
+If
+.Fa errbuf_size
+is 0,
+.Fa errbuf
+is ignored but the return value is still correct.
+.Pp
+If the
+.Fa errcode
+given to
+.Fn regerror
+is first ORed with
+.Dv REG_ITOA ,
+the
+.Dq message
+that results is the printable name of the error code,
+e.g.\&
+.Dq Dv REG_NOMATCH ,
+rather than an explanation thereof.
+If
+.Fa errcode
+is
+.Dv REG_ATOI ,
+then
+.Fa preg
+shall be
+.No non\- Ns Dv NULL
+and the
+.Va re_endp
+member of the structure it points to
+must point to the printable name of an error code;
+in this case, the result in
+.Fa errbuf
+is the decimal digits of
+the numeric value of the error code
+(0 if the name is not recognized).
+.Dv REG_ITOA
+and
+.Dv REG_ATOI
+are intended primarily as debugging facilities;
+they are extensions,
+compatible with but not specified by
+.St -p1003.2 ,
+and should be used with
+caution in software intended to be portable to other systems.
+Be warned also that they are considered experimental and changes are possible.
+.Pp
+The
+.Fn regfree
+function
+frees any dynamically-allocated storage associated with the compiled RE
+pointed to by
+.Fa preg .
+The remaining
+.Ft regex_t
+is no longer a valid compiled RE
+and the effect of supplying it to
+.Fn regexec
+or
+.Fn regerror
+is undefined.
+.Pp
+None of these functions references global variables except for tables
+of constants;
+all are safe for use from multiple threads if the arguments are safe.
+.Sh IMPLEMENTATION CHOICES
+There are a number of decisions that
+.St -p1003.2
+leaves up to the implementor,
+either by explicitly saying
+.Dq undefined
+or by virtue of them being
+forbidden by the RE grammar.
+This implementation treats them as follows.
+.Pp
+See
+.Xr re_format 7
+for a discussion of the definition of case-independent matching.
+.Pp
+There is no particular limit on the length of REs,
+except insofar as memory is limited.
+Memory usage is approximately linear in RE size, and largely insensitive
+to RE complexity, except for bounded repetitions.
+See
+.Sx BUGS
+for one short RE using them
+that will run almost any system out of memory.
+.Pp
+A backslashed character other than one specifically given a magic meaning
+by
+.St -p1003.2
+(such magic meanings occur only in obsolete
+.Bq Dq basic
+REs)
+is taken as an ordinary character.
+.Pp
+Any unmatched
+.Ql [\&
+is a
+.Dv REG_EBRACK
+error.
+.Pp
+Equivalence classes cannot begin or end bracket-expression ranges.
+The endpoint of one range cannot begin another.
+.Pp
+.Dv RE_DUP_MAX ,
+the limit on repetition counts in bounded repetitions, is 255.
+.Pp
+A repetition operator
+.Ql ( ?\& ,
+.Ql *\& ,
+.Ql +\& ,
+or bounds)
+cannot follow another
+repetition operator.
+A repetition operator cannot begin an expression or subexpression
+or follow
+.Ql ^\&
+or
+.Ql |\& .
+.Pp
+.Ql |\&
+cannot appear first or last in a (sub)expression or after another
+.Ql |\& ,
+i.e., an operand of
+.Ql |\&
+cannot be an empty subexpression.
+An empty parenthesized subexpression,
+.Ql "()" ,
+is legal and matches an
+empty (sub)string.
+An empty string is not a legal RE.
+.Pp
+A
+.Ql {\&
+followed by a digit is considered the beginning of bounds for a
+bounded repetition, which must then follow the syntax for bounds.
+A
+.Ql {\&
+.Em not
+followed by a digit is considered an ordinary character.
+.Pp
+.Ql ^\&
+and
+.Ql $\&
+beginning and ending subexpressions in obsolete
+.Pq Dq basic
+REs are anchors, not ordinary characters.
+.Sh DIAGNOSTICS
+Non-zero error codes from
+.Fn regcomp
+and
+.Fn regexec
+include the following:
+.Pp
+.Bl -tag -width REG_ECOLLATE -compact
+.It Dv REG_NOMATCH
+The
+.Fn regexec
+function
+failed to match
+.It Dv REG_BADPAT
+invalid regular expression
+.It Dv REG_ECOLLATE
+invalid collating element
+.It Dv REG_ECTYPE
+invalid character class
+.It Dv REG_EESCAPE
+.Ql \e
+applied to unescapable character
+.It Dv REG_ESUBREG
+invalid backreference number
+.It Dv REG_EBRACK
+brackets
+.Ql "[ ]"
+not balanced
+.It Dv REG_EPAREN
+parentheses
+.Ql "( )"
+not balanced
+.It Dv REG_EBRACE
+braces
+.Ql "{ }"
+not balanced
+.It Dv REG_BADBR
+invalid repetition count(s) in
+.Ql "{ }"
+.It Dv REG_ERANGE
+invalid character range in
+.Ql "[ ]"
+.It Dv REG_ESPACE
+ran out of memory
+.It Dv REG_BADRPT
+.Ql ?\& ,
+.Ql *\& ,
+or
+.Ql +\&
+operand invalid
+.It Dv REG_EMPTY
+empty (sub)expression
+.It Dv REG_ASSERT
+cannot happen - you found a bug
+.It Dv REG_INVARG
+invalid argument, e.g.\& negative-length string
+.It Dv REG_ILLSEQ
+illegal byte sequence (bad multibyte character)
+.El
+.Sh SEE ALSO
+.Xr grep 1 ,
+.Xr re_format 7
+.Pp
+.St -p1003.2 ,
+sections 2.8 (Regular Expression Notation)
+and
+B.5 (C Binding for Regular Expression Matching).
+.Sh HISTORY
+Originally written by
+.An Henry Spencer .
+Altered for inclusion in the
+.Bx 4.4
+distribution.
+.Sh BUGS
+This is an alpha release with known defects.
+Please report problems.
+.Pp
+The back-reference code is subtle and doubts linger about its correctness
+in complex cases.
+.Pp
+The
+.Fn regexec
+function
+performance is poor.
+This will improve with later releases.
+The
+.Fa nmatch
+argument
+exceeding 0 is expensive;
+.Fa nmatch
+exceeding 1 is worse.
+The
+.Fn regexec
+function
+is largely insensitive to RE complexity
+.Em except
+that back
+references are massively expensive.
+RE length does matter; in particular, there is a strong speed bonus
+for keeping RE length under about 30 characters,
+with most special characters counting roughly double.
+.Pp
+The
+.Fn regcomp
+function
+implements bounded repetitions by macro expansion,
+which is costly in time and space if counts are large
+or bounded repetitions are nested.
+An RE like, say,
+.Ql "((((a{1,100}){1,100}){1,100}){1,100}){1,100}"
+will (eventually) run almost any existing machine out of swap space.
+.Pp
+There are suspected problems with response to obscure error conditions.
+Notably,
+certain kinds of internal overflow,
+produced only by truly enormous REs or by multiply nested bounded repetitions,
+are probably not handled well.
+.Pp
+Due to a mistake in
+.St -p1003.2 ,
+things like
+.Ql "a)b"
+are legal REs because
+.Ql )\&
+is
+a special character only in the presence of a previous unmatched
+.Ql (\& .
+This cannot be fixed until the spec is fixed.
+.Pp
+The standard's definition of back references is vague.
+For example, does
+.Ql "a\e(\e(b\e)*\e2\e)*d"
+match
+.Ql "abbbd" ?
+Until the standard is clarified,
+behavior in such cases should not be relied on.
+.Pp
+The implementation of word-boundary matching is a bit of a kludge,
+and bugs may lurk in combinations of word-boundary matching and anchoring.
+.Pp
+Word-boundary matching does not work properly in multibyte locales.
diff --git a/lib/libc/regex/regex2.h b/lib/libc/regex/regex2.h
new file mode 100644
index 000000000000..7aa717edc167
--- /dev/null
+++ b/lib/libc/regex/regex2.h
@@ -0,0 +1,192 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994 Henry Spencer.
+ * Copyright (c) 1992, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Henry Spencer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)regex2.h 8.4 (Berkeley) 3/20/94
+ * $FreeBSD$
+ */
+
+/*
+ * First, the stuff that ends up in the outside-world include file
+ = typedef off_t regoff_t;
+ = typedef struct {
+ = int re_magic;
+ = size_t re_nsub; // number of parenthesized subexpressions
+ = const char *re_endp; // end pointer for REG_PEND
+ = struct re_guts *re_g; // none of your business :-)
+ = } regex_t;
+ = typedef struct {
+ = regoff_t rm_so; // start of match
+ = regoff_t rm_eo; // end of match
+ = } regmatch_t;
+ */
+/*
+ * internals of regex_t
+ */
+#define MAGIC1 ((('r'^0200)<<8) | 'e')
+
+/*
+ * The internal representation is a *strip*, a sequence of
+ * operators ending with an endmarker. (Some terminology etc. is a
+ * historical relic of earlier versions which used multiple strips.)
+ * Certain oddities in the representation are there to permit running
+ * the machinery backwards; in particular, any deviation from sequential
+ * flow must be marked at both its source and its destination. Some
+ * fine points:
+ *
+ * - OPLUS_ and O_PLUS are *inside* the loop they create.
+ * - OQUEST_ and O_QUEST are *outside* the bypass they create.
+ * - OCH_ and O_CH are *outside* the multi-way branch they create, while
+ * OOR1 and OOR2 are respectively the end and the beginning of one of
+ * the branches. Note that there is an implicit OOR2 following OCH_
+ * and an implicit OOR1 preceding O_CH.
+ *
+ * In state representations, an operator's bit is on to signify a state
+ * immediately *preceding* "execution" of that operator.
+ */
+typedef unsigned long sop; /* strip operator */
+typedef long sopno;
+#define OPRMASK 0xf8000000L
+#define OPDMASK 0x07ffffffL
+#define OPSHIFT ((unsigned)27)
+#define OP(n) ((n)&OPRMASK)
+#define OPND(n) ((n)&OPDMASK)
+#define SOP(op, opnd) ((op)|(opnd))
+/* operators meaning operand */
+/* (back, fwd are offsets) */
+#define OEND (1L<<OPSHIFT) /* endmarker - */
+#define OCHAR (2L<<OPSHIFT) /* character wide character */
+#define OBOL (3L<<OPSHIFT) /* left anchor - */
+#define OEOL (4L<<OPSHIFT) /* right anchor - */
+#define OANY (5L<<OPSHIFT) /* . - */
+#define OANYOF (6L<<OPSHIFT) /* [...] set number */
+#define OBACK_ (7L<<OPSHIFT) /* begin \d paren number */
+#define O_BACK (8L<<OPSHIFT) /* end \d paren number */
+#define OPLUS_ (9L<<OPSHIFT) /* + prefix fwd to suffix */
+#define O_PLUS (10L<<OPSHIFT) /* + suffix back to prefix */
+#define OQUEST_ (11L<<OPSHIFT) /* ? prefix fwd to suffix */
+#define O_QUEST (12L<<OPSHIFT) /* ? suffix back to prefix */
+#define OLPAREN (13L<<OPSHIFT) /* ( fwd to ) */
+#define ORPAREN (14L<<OPSHIFT) /* ) back to ( */
+#define OCH_ (15L<<OPSHIFT) /* begin choice fwd to OOR2 */
+#define OOR1 (16L<<OPSHIFT) /* | pt. 1 back to OOR1 or OCH_ */
+#define OOR2 (17L<<OPSHIFT) /* | pt. 2 fwd to OOR2 or O_CH */
+#define O_CH (18L<<OPSHIFT) /* end choice back to OOR1 */
+#define OBOW (19L<<OPSHIFT) /* begin word - */
+#define OEOW (20L<<OPSHIFT) /* end word - */
+
+/*
+ * Structures for [] character-set representation.
+ */
+typedef struct {
+ wint_t min;
+ wint_t max;
+} crange;
+typedef struct {
+ unsigned char bmp[NC / 8];
+ wctype_t *types;
+ int ntypes;
+ wint_t *wides;
+ int nwides;
+ crange *ranges;
+ int nranges;
+ int invert;
+ int icase;
+} cset;
+
+static int
+CHIN1(cset *cs, wint_t ch)
+{
+ int i;
+
+ assert(ch >= 0);
+ if (ch < NC)
+ return (((cs->bmp[ch >> 3] & (1 << (ch & 7))) != 0) ^
+ cs->invert);
+ for (i = 0; i < cs->nwides; i++)
+ if (ch == cs->wides[i])
+ return (!cs->invert);
+ for (i = 0; i < cs->nranges; i++)
+ if (cs->ranges[i].min <= ch && ch <= cs->ranges[i].max)
+ return (!cs->invert);
+ for (i = 0; i < cs->ntypes; i++)
+ if (iswctype(ch, cs->types[i]))
+ return (!cs->invert);
+ return (cs->invert);
+}
+
+static __inline int
+CHIN(cset *cs, wint_t ch)
+{
+
+ assert(ch >= 0);
+ if (ch < NC)
+ return (((cs->bmp[ch >> 3] & (1 << (ch & 7))) != 0) ^
+ cs->invert);
+ else if (cs->icase)
+ return (CHIN1(cs, ch) || CHIN1(cs, towlower(ch)) ||
+ CHIN1(cs, towupper(ch)));
+ else
+ return (CHIN1(cs, ch));
+}
+
+/*
+ * main compiled-expression structure
+ */
+struct re_guts {
+ int magic;
+# define MAGIC2 ((('R'^0200)<<8)|'E')
+ sop *strip; /* malloced area for strip */
+ int ncsets; /* number of csets in use */
+ cset *sets; /* -> cset [ncsets] */
+ int cflags; /* copy of regcomp() cflags argument */
+ sopno nstates; /* = number of sops */
+ sopno firststate; /* the initial OEND (normally 0) */
+ sopno laststate; /* the final OEND */
+ int iflags; /* internal flags */
+# define USEBOL 01 /* used ^ */
+# define USEEOL 02 /* used $ */
+# define BAD 04 /* something wrong */
+ int nbol; /* number of ^ used */
+ int neol; /* number of $ used */
+ char *must; /* match must contain this string */
+ int moffset; /* latest point at which must may be located */
+ int *charjump; /* Boyer-Moore char jump table */
+ int *matchjump; /* Boyer-Moore match jump table */
+ int mlen; /* length of must */
+ size_t nsub; /* copy of re_nsub */
+ int backrefs; /* does it use back references? */
+ sopno nplus; /* how deep does it nest +s? */
+};
+
+/* misc utilities */
+#define OUT (CHAR_MIN - 1) /* a non-character value */
+#define ISWORD(c) (iswalnum((uch)(c)) || (c) == '_')
diff --git a/lib/libc/regex/regexec.c b/lib/libc/regex/regexec.c
new file mode 100644
index 000000000000..1cf87b810471
--- /dev/null
+++ b/lib/libc/regex/regexec.c
@@ -0,0 +1,233 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994 Henry Spencer.
+ * Copyright (c) 1992, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Henry Spencer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)regexec.c 8.3 (Berkeley) 3/20/94
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)regexec.c 8.3 (Berkeley) 3/20/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * the outer shell of regexec()
+ *
+ * This file includes engine.c three times, after muchos fiddling with the
+ * macros that code uses. This lets the same code operate on two different
+ * representations for state sets and characters.
+ */
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <ctype.h>
+#include <regex.h>
+#include <wchar.h>
+#include <wctype.h>
+
+#include "utils.h"
+#include "regex2.h"
+
+static int nope __unused = 0; /* for use in asserts; shuts lint up */
+
+static __inline size_t
+xmbrtowc(wint_t *wi, const char *s, size_t n, mbstate_t *mbs, wint_t dummy)
+{
+ size_t nr;
+ wchar_t wc;
+
+ nr = mbrtowc(&wc, s, n, mbs);
+ if (wi != NULL)
+ *wi = wc;
+ if (nr == 0)
+ return (1);
+ else if (nr == (size_t)-1 || nr == (size_t)-2) {
+ memset(mbs, 0, sizeof(*mbs));
+ if (wi != NULL)
+ *wi = dummy;
+ return (1);
+ } else
+ return (nr);
+}
+
+static __inline size_t
+xmbrtowc_dummy(wint_t *wi,
+ const char *s,
+ size_t n __unused,
+ mbstate_t *mbs __unused,
+ wint_t dummy __unused)
+{
+
+ if (wi != NULL)
+ *wi = (unsigned char)*s;
+ return (1);
+}
+
+/* macros for manipulating states, small version */
+#define states long
+#define states1 states /* for later use in regexec() decision */
+#define CLEAR(v) ((v) = 0)
+#define SET0(v, n) ((v) &= ~((unsigned long)1 << (n)))
+#define SET1(v, n) ((v) |= (unsigned long)1 << (n))
+#define ISSET(v, n) (((v) & ((unsigned long)1 << (n))) != 0)
+#define ASSIGN(d, s) ((d) = (s))
+#define EQ(a, b) ((a) == (b))
+#define STATEVARS long dummy /* dummy version */
+#define STATESETUP(m, n) /* nothing */
+#define STATETEARDOWN(m) /* nothing */
+#define SETUP(v) ((v) = 0)
+#define onestate long
+#define INIT(o, n) ((o) = (unsigned long)1 << (n))
+#define INC(o) ((o) <<= 1)
+#define ISSTATEIN(v, o) (((v) & (o)) != 0)
+/* some abbreviations; note that some of these know variable names! */
+/* do "if I'm here, I can also be there" etc without branches */
+#define FWD(dst, src, n) ((dst) |= ((unsigned long)(src)&(here)) << (n))
+#define BACK(dst, src, n) ((dst) |= ((unsigned long)(src)&(here)) >> (n))
+#define ISSETBACK(v, n) (((v) & ((unsigned long)here >> (n))) != 0)
+/* no multibyte support */
+#define XMBRTOWC xmbrtowc_dummy
+#define ZAPSTATE(mbs) ((void)(mbs))
+/* function names */
+#define SNAMES /* engine.c looks after details */
+
+#include "engine.c"
+
+/* now undo things */
+#undef states
+#undef CLEAR
+#undef SET0
+#undef SET1
+#undef ISSET
+#undef ASSIGN
+#undef EQ
+#undef STATEVARS
+#undef STATESETUP
+#undef STATETEARDOWN
+#undef SETUP
+#undef onestate
+#undef INIT
+#undef INC
+#undef ISSTATEIN
+#undef FWD
+#undef BACK
+#undef ISSETBACK
+#undef SNAMES
+#undef XMBRTOWC
+#undef ZAPSTATE
+
+/* macros for manipulating states, large version */
+#define states char *
+#define CLEAR(v) memset(v, 0, m->g->nstates)
+#define SET0(v, n) ((v)[n] = 0)
+#define SET1(v, n) ((v)[n] = 1)
+#define ISSET(v, n) ((v)[n])
+#define ASSIGN(d, s) memcpy(d, s, m->g->nstates)
+#define EQ(a, b) (memcmp(a, b, m->g->nstates) == 0)
+#define STATEVARS long vn; char *space
+#define STATESETUP(m, nv) { (m)->space = malloc((nv)*(m)->g->nstates); \
+ if ((m)->space == NULL) return(REG_ESPACE); \
+ (m)->vn = 0; }
+#define STATETEARDOWN(m) { free((m)->space); }
+#define SETUP(v) ((v) = &m->space[m->vn++ * m->g->nstates])
+#define onestate long
+#define INIT(o, n) ((o) = (n))
+#define INC(o) ((o)++)
+#define ISSTATEIN(v, o) ((v)[o])
+/* some abbreviations; note that some of these know variable names! */
+/* do "if I'm here, I can also be there" etc without branches */
+#define FWD(dst, src, n) ((dst)[here+(n)] |= (src)[here])
+#define BACK(dst, src, n) ((dst)[here-(n)] |= (src)[here])
+#define ISSETBACK(v, n) ((v)[here - (n)])
+/* no multibyte support */
+#define XMBRTOWC xmbrtowc_dummy
+#define ZAPSTATE(mbs) ((void)(mbs))
+/* function names */
+#define LNAMES /* flag */
+
+#include "engine.c"
+
+/* multibyte character & large states version */
+#undef LNAMES
+#undef XMBRTOWC
+#undef ZAPSTATE
+#define XMBRTOWC xmbrtowc
+#define ZAPSTATE(mbs) memset((mbs), 0, sizeof(*(mbs)))
+#define MNAMES
+
+#include "engine.c"
+
+/*
+ - regexec - interface for matching
+ = extern int regexec(const regex_t *, const char *, size_t, \
+ = regmatch_t [], int);
+ = #define REG_NOTBOL 00001
+ = #define REG_NOTEOL 00002
+ = #define REG_STARTEND 00004
+ = #define REG_TRACE 00400 // tracing of execution
+ = #define REG_LARGE 01000 // force large representation
+ = #define REG_BACKR 02000 // force use of backref code
+ *
+ * We put this here so we can exploit knowledge of the state representation
+ * when choosing which matcher to call. Also, by this point the matchers
+ * have been prototyped.
+ */
+int /* 0 success, REG_NOMATCH failure */
+regexec(const regex_t * __restrict preg,
+ const char * __restrict string,
+ size_t nmatch,
+ regmatch_t pmatch[__restrict],
+ int eflags)
+{
+ struct re_guts *g = preg->re_g;
+#ifdef REDEBUG
+# define GOODFLAGS(f) (f)
+#else
+# define GOODFLAGS(f) ((f)&(REG_NOTBOL|REG_NOTEOL|REG_STARTEND))
+#endif
+
+ if (preg->re_magic != MAGIC1 || g->magic != MAGIC2)
+ return(REG_BADPAT);
+ assert(!(g->iflags&BAD));
+ if (g->iflags&BAD) /* backstop for no-debug case */
+ return(REG_BADPAT);
+ eflags = GOODFLAGS(eflags);
+
+ if (MB_CUR_MAX > 1)
+ return(mmatcher(g, (char *)string, nmatch, pmatch, eflags));
+ else if (g->nstates <= CHAR_BIT*sizeof(states1) && !(eflags&REG_LARGE))
+ return(smatcher(g, (char *)string, nmatch, pmatch, eflags));
+ else
+ return(lmatcher(g, (char *)string, nmatch, pmatch, eflags));
+}
diff --git a/lib/libc/regex/regfree.c b/lib/libc/regex/regfree.c
new file mode 100644
index 000000000000..c979becdaf4d
--- /dev/null
+++ b/lib/libc/regex/regfree.c
@@ -0,0 +1,89 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994 Henry Spencer.
+ * Copyright (c) 1992, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Henry Spencer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)regfree.c 8.3 (Berkeley) 3/20/94
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)regfree.c 8.3 (Berkeley) 3/20/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <regex.h>
+#include <wchar.h>
+#include <wctype.h>
+
+#include "utils.h"
+#include "regex2.h"
+
+/*
+ - regfree - free everything
+ = extern void regfree(regex_t *);
+ */
+void
+regfree(regex_t *preg)
+{
+ struct re_guts *g;
+ int i;
+
+ if (preg->re_magic != MAGIC1) /* oops */
+ return; /* nice to complain, but hard */
+
+ g = preg->re_g;
+ if (g == NULL || g->magic != MAGIC2) /* oops again */
+ return;
+ preg->re_magic = 0; /* mark it invalid */
+ g->magic = 0; /* mark it invalid */
+
+ if (g->strip != NULL)
+ free((char *)g->strip);
+ if (g->sets != NULL) {
+ for (i = 0; i < g->ncsets; i++) {
+ free(g->sets[i].ranges);
+ free(g->sets[i].wides);
+ free(g->sets[i].types);
+ }
+ free((char *)g->sets);
+ }
+ if (g->must != NULL)
+ free(g->must);
+ if (g->charjump != NULL)
+ free(&g->charjump[CHAR_MIN]);
+ if (g->matchjump != NULL)
+ free(g->matchjump);
+ free((char *)g);
+}
diff --git a/lib/libc/regex/utils.h b/lib/libc/regex/utils.h
new file mode 100644
index 000000000000..3531aed232ed
--- /dev/null
+++ b/lib/libc/regex/utils.h
@@ -0,0 +1,54 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994 Henry Spencer.
+ * Copyright (c) 1992, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Henry Spencer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)utils.h 8.3 (Berkeley) 3/20/94
+ * $FreeBSD$
+ */
+
+/* utility definitions */
+#define DUPMAX _POSIX2_RE_DUP_MAX /* xxx is this right? */
+#define INFINITY (DUPMAX + 1)
+#define NC (CHAR_MAX - CHAR_MIN + 1)
+typedef unsigned char uch;
+
+/* switch off assertions (if not already off) if no REDEBUG */
+#ifndef REDEBUG
+#ifndef NDEBUG
+#define NDEBUG /* no assertions please */
+#endif
+#endif
+#include <assert.h>
+
+/* for old systems with bcopy() but no memmove() */
+#ifdef USEBCOPY
+#define memmove(d, s, c) bcopy(s, d, c)
+#endif
diff --git a/lib/libc/resolv/Makefile.inc b/lib/libc/resolv/Makefile.inc
new file mode 100644
index 000000000000..9bb7bbe46d29
--- /dev/null
+++ b/lib/libc/resolv/Makefile.inc
@@ -0,0 +1,12 @@
+# $FreeBSD$
+
+# resolv sources
+.PATH: ${LIBC_SRCTOP}/resolv
+
+SRCS+= herror.c h_errno.c mtctxres.c res_comp.c res_data.c res_debug.c \
+ res_findzonecut.c res_init.c res_mkquery.c res_mkupdate.c \
+ res_query.c res_send.c res_state.c res_update.c
+
+SYM_MAPS+= ${LIBC_SRCTOP}/resolv/Symbol.map
+
+CFLAGS+=-I${SRCTOP}/lib/libmd
diff --git a/lib/libc/resolv/Symbol.map b/lib/libc/resolv/Symbol.map
new file mode 100644
index 000000000000..170333343cf0
--- /dev/null
+++ b/lib/libc/resolv/Symbol.map
@@ -0,0 +1,112 @@
+/*
+ * $FreeBSD$
+ */
+
+FBSD_1.0 {
+ /* h_nerr; */ /* Why is this not staticized in net/herror.c? */
+ h_errlist;
+ herror;
+ hstrerror;
+ __dn_expand;
+ __dn_comp;
+ __dn_skipname;
+ __res_hnok;
+ __res_ownok;
+ __res_mailok;
+ __res_dnok;
+ __putlong;
+ __putshort;
+ _getlong;
+ _getshort;
+ dn_comp;
+ dn_expand;
+ __fp_resstat;
+ __p_query;
+ __fp_query;
+ __fp_nquery;
+ __p_cdnname;
+ __p_cdname;
+ __p_fqnname;
+ __p_fqname;
+ __p_cert_syms;
+ __p_class_syms;
+ __p_key_syms;
+ __p_rcode_syms;
+ __p_type_syms;
+ __sym_ston;
+ __sym_ntos;
+ __sym_ntop;
+ __p_rcode;
+ __p_sockun;
+ __p_type;
+ __p_section;
+ __p_class;
+ __p_option;
+ __p_time;
+ __loc_aton;
+ __loc_ntoa;
+ __dn_count_labels;
+ __p_secstodate;
+ fp_resstat;
+ p_query;
+ p_fqnname;
+ sym_ston;
+ sym_ntos;
+ sym_ntop;
+ dn_count_labels;
+ p_secstodate;
+ __res_init;
+ __res_randomid;
+ __h_errno;
+ __h_errno_set;
+ h_errno;
+ res_init;
+ __res_findzonecut2;
+ __res_freeupdrec;
+ __res_mkquery;
+ res_mkquery;
+ __res_mkupdrec;
+ __res_mkupdate;
+ __res_opt;
+ __res_getservers;
+ __res_hostalias;
+ __res_nametoclass;
+ __res_nametotype;
+ __res_nclose;
+ __res_ndestroy;
+ __res_ninit;
+ __res_nmkquery;
+ __res_nmkupdate;
+ __res_nopt;
+ __res_nquery;
+ __res_nquerydomain;
+ __res_nsearch;
+ __res_nsend;
+ __res_nupdate;
+ __res_ourserver_p;
+ __res_pquery;
+ __res_query;
+ __res_search;
+ __res_querydomain;
+ __res_setservers;
+ _res;
+ __res_state;
+ __res_vinit;
+ __hostalias;
+ res_query;
+ res_search;
+ res_querydomain;
+ __res_isourserver;
+ __res_nameinquery;
+ __res_queriesmatch;
+ __res_send;
+ __res_close;
+ _res_close;
+ res_send;
+ __res_update;
+};
+
+FBSD_1.4 {
+ __res_rndinit;
+ __res_nrandomid;
+};
diff --git a/lib/libc/resolv/h_errno.c b/lib/libc/resolv/h_errno.c
new file mode 100644
index 000000000000..8ced7081ddff
--- /dev/null
+++ b/lib/libc/resolv/h_errno.c
@@ -0,0 +1,49 @@
+/*-
+ * Copyright (c) 2006 The FreeBSD Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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 <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#undef h_errno
+extern int h_errno;
+
+int *__h_errno(void);
+void __h_errno_set(res_state res, int err);
+
+int *
+__h_errno(void)
+{
+ return (&__res_state()->res_h_errno);
+}
+
+void
+__h_errno_set(res_state res, int err)
+{
+ h_errno = res->res_h_errno = err;
+}
diff --git a/lib/libc/resolv/herror.c b/lib/libc/resolv/herror.c
new file mode 100644
index 000000000000..d1f3a25c7d7b
--- /dev/null
+++ b/lib/libc/resolv/herror.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 1987, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)herror.c 8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: herror.c,v 1.4 2005/04/27 04:56:41 sra Exp $";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "port_before.h"
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <sys/uio.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <netdb.h>
+#include <resolv.h>
+#include <string.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+#include "port_after.h"
+
+const char *h_errlist[] = {
+ "Resolver Error 0 (no error)",
+ "Unknown host", /*%< 1 HOST_NOT_FOUND */
+ "Host name lookup failure", /*%< 2 TRY_AGAIN */
+ "Unknown server error", /*%< 3 NO_RECOVERY */
+ "No address associated with name", /*%< 4 NO_ADDRESS */
+};
+const int h_nerr = { nitems(h_errlist) };
+
+#undef h_errno
+int h_errno;
+
+/*%
+ * herror --
+ * print the error indicated by the h_errno value.
+ */
+void
+herror(const char *s) {
+ struct iovec iov[4], *v = iov;
+ char *t;
+
+ if (s != NULL && *s != '\0') {
+ DE_CONST(s, t);
+ v->iov_base = t;
+ v->iov_len = strlen(t);
+ v++;
+ DE_CONST(": ", t);
+ v->iov_base = t;
+ v->iov_len = 2;
+ v++;
+ }
+ DE_CONST(hstrerror(*__h_errno()), t);
+ v->iov_base = t;
+ v->iov_len = strlen(v->iov_base);
+ v++;
+ DE_CONST("\n", t);
+ v->iov_base = t;
+ v->iov_len = 1;
+ _writev(STDERR_FILENO, iov, (v - iov) + 1);
+}
+
+/*%
+ * hstrerror --
+ * return the string associated with a given "host" errno value.
+ */
+const char *
+hstrerror(int err) {
+ if (err < 0)
+ return ("Resolver internal error");
+ else if (err < h_nerr)
+ return (h_errlist[err]);
+ return ("Unknown resolver error");
+}
+
+/*! \file */
diff --git a/lib/libc/resolv/mtctxres.c b/lib/libc/resolv/mtctxres.c
new file mode 100644
index 000000000000..c2aea381761d
--- /dev/null
+++ b/lib/libc/resolv/mtctxres.c
@@ -0,0 +1,138 @@
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <port_before.h>
+#ifdef DO_PTHREADS
+#include <pthread.h>
+#ifdef _LIBC
+#include <pthread_np.h>
+#endif
+#endif
+#include <errno.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <string.h>
+#include <resolv_mt.h>
+#include <port_after.h>
+
+#ifdef DO_PTHREADS
+static pthread_key_t key;
+static int mt_key_initialized = 0;
+
+static int __res_init_ctx(void);
+static void __res_destroy_ctx(void *);
+
+#if defined(sun) && !defined(__GNUC__)
+#pragma init (_mtctxres_init)
+#endif
+#endif
+
+static mtctxres_t sharedctx;
+
+#ifdef DO_PTHREADS
+/*
+ * Initialize the TSD key. By doing this at library load time, we're
+ * implicitly running without interference from other threads, so there's
+ * no need for locking.
+ */
+static void
+_mtctxres_init(void) {
+ int pthread_keycreate_ret;
+
+ pthread_keycreate_ret = pthread_key_create(&key, __res_destroy_ctx);
+ if (pthread_keycreate_ret == 0)
+ mt_key_initialized = 1;
+}
+#endif
+
+#ifndef _LIBC
+/*
+ * To support binaries that used the private MT-safe interface in
+ * Solaris 8, we still need to provide the __res_enable_mt()
+ * and __res_disable_mt() entry points. They're do-nothing routines.
+ */
+int
+__res_enable_mt(void) {
+ return (-1);
+}
+
+int
+__res_disable_mt(void) {
+ return (0);
+}
+#endif
+
+#ifdef DO_PTHREADS
+static int
+__res_init_ctx(void) {
+
+ mtctxres_t *mt;
+ int ret;
+
+
+ if (pthread_getspecific(key) != 0) {
+ /* Already exists */
+ return (0);
+ }
+
+ if ((mt = malloc(sizeof(mtctxres_t))) == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+
+ memset(mt, 0, sizeof (mtctxres_t));
+
+ if ((ret = pthread_setspecific(key, mt)) != 0) {
+ free(mt);
+ errno = ret;
+ return (-1);
+ }
+
+ return (0);
+}
+
+static void
+__res_destroy_ctx(void *value) {
+
+ free(value);
+}
+#endif
+
+mtctxres_t *
+___mtctxres(void) {
+#ifdef DO_PTHREADS
+ mtctxres_t *mt;
+
+#ifdef _LIBC
+ if (pthread_main_np() != 0)
+ return (&sharedctx);
+#endif
+
+ /*
+ * This if clause should only be executed if we are linking
+ * statically. When linked dynamically _mtctxres_init() should
+ * be called at binding time due the #pragma above.
+ */
+ if (!mt_key_initialized) {
+ static pthread_mutex_t keylock = PTHREAD_MUTEX_INITIALIZER;
+ if (pthread_mutex_lock(&keylock) == 0) {
+ _mtctxres_init();
+ (void) pthread_mutex_unlock(&keylock);
+ }
+ }
+
+ /*
+ * If we have already been called in this thread return the existing
+ * context. Otherwise recreat a new context and return it. If
+ * that fails return a global context.
+ */
+ if (mt_key_initialized) {
+ if (((mt = pthread_getspecific(key)) != NULL) ||
+ (__res_init_ctx() == 0 &&
+ (mt = pthread_getspecific(key)) != NULL)) {
+ return (mt);
+ }
+ }
+#endif
+ return (&sharedctx);
+}
diff --git a/lib/libc/resolv/res_comp.c b/lib/libc/resolv/res_comp.c
new file mode 100644
index 000000000000..514a524aa0d4
--- /dev/null
+++ b/lib/libc/resolv/res_comp.c
@@ -0,0 +1,276 @@
+/*
+ * Copyright (c) 1985, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)res_comp.c 8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: res_comp.c,v 1.5 2005/07/28 06:51:50 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "port_before.h"
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <ctype.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include "port_after.h"
+
+/*%
+ * Expand compressed domain name 'src' to full domain name.
+ *
+ * \li 'msg' is a pointer to the beginning of the message,
+ * \li 'eom' points to the first location after the message,
+ * \li 'dst' is a pointer to a buffer of size 'dstsiz' for the result.
+ * \li Return size of compressed name or -1 if there was an error.
+ */
+int
+dn_expand(const u_char *msg, const u_char *eom, const u_char *src,
+ char *dst, int dstsiz)
+{
+ int n = ns_name_uncompress(msg, eom, src, dst, (size_t)dstsiz);
+
+ if (n > 0 && dst[0] == '.')
+ dst[0] = '\0';
+ return (n);
+}
+
+/*%
+ * Pack domain name 'exp_dn' in presentation form into 'comp_dn'.
+ *
+ * \li Return the size of the compressed name or -1.
+ * \li 'length' is the size of the array pointed to by 'comp_dn'.
+ */
+int
+dn_comp(const char *src, u_char *dst, int dstsiz,
+ u_char **dnptrs, u_char **lastdnptr)
+{
+ return (ns_name_compress(src, dst, (size_t)dstsiz,
+ (const u_char **)dnptrs,
+ (const u_char **)lastdnptr));
+}
+
+/*%
+ * Skip over a compressed domain name. Return the size or -1.
+ */
+int
+dn_skipname(const u_char *ptr, const u_char *eom) {
+ const u_char *saveptr = ptr;
+
+ if (ns_name_skip(&ptr, eom) == -1)
+ return (-1);
+ return (ptr - saveptr);
+}
+
+/*%
+ * Verify that a domain name uses an acceptable character set.
+ *
+ * Note the conspicuous absence of ctype macros in these definitions. On
+ * non-ASCII hosts, we can't depend on string literals or ctype macros to
+ * tell us anything about network-format data. The rest of the BIND system
+ * is not careful about this, but for some reason, we're doing it right here.
+ */
+#define PERIOD 0x2e
+#define hyphenchar(c) ((c) == 0x2d)
+#define bslashchar(c) ((c) == 0x5c)
+#define underscorechar(c) ((c) == 0x5f)
+#define periodchar(c) ((c) == PERIOD)
+#define asterchar(c) ((c) == 0x2a)
+#define alphachar(c) (((c) >= 0x41 && (c) <= 0x5a) \
+ || ((c) >= 0x61 && (c) <= 0x7a))
+#define digitchar(c) ((c) >= 0x30 && (c) <= 0x39)
+
+#ifdef RES_ENFORCE_RFC1034
+#define borderchar(c) (alphachar(c) || digitchar(c))
+#else
+#define borderchar(c) (alphachar(c) || digitchar(c) || underscorechar(c))
+#endif
+#define middlechar(c) (borderchar(c) || hyphenchar(c))
+#define domainchar(c) ((c) > 0x20 && (c) < 0x7f)
+
+int
+res_hnok(const char *dn) {
+ int pch = PERIOD, ch = *dn++;
+
+ while (ch != '\0') {
+ int nch = *dn++;
+
+ if (periodchar(ch)) {
+ (void)NULL;
+ } else if (periodchar(pch)) {
+ if (!borderchar(ch))
+ return (0);
+ } else if (periodchar(nch) || nch == '\0') {
+ if (!borderchar(ch))
+ return (0);
+ } else {
+ if (!middlechar(ch))
+ return (0);
+ }
+ pch = ch, ch = nch;
+ }
+ return (1);
+}
+
+/*%
+ * hostname-like (A, MX, WKS) owners can have "*" as their first label
+ * but must otherwise be as a host name.
+ */
+int
+res_ownok(const char *dn) {
+ if (asterchar(dn[0])) {
+ if (periodchar(dn[1]))
+ return (res_hnok(dn+2));
+ if (dn[1] == '\0')
+ return (1);
+ }
+ return (res_hnok(dn));
+}
+
+/*%
+ * SOA RNAMEs and RP RNAMEs can have any printable character in their first
+ * label, but the rest of the name has to look like a host name.
+ */
+int
+res_mailok(const char *dn) {
+ int ch, escaped = 0;
+
+ /* "." is a valid missing representation */
+ if (*dn == '\0')
+ return (1);
+
+ /* otherwise <label>.<hostname> */
+ while ((ch = *dn++) != '\0') {
+ if (!domainchar(ch))
+ return (0);
+ if (!escaped && periodchar(ch))
+ break;
+ if (escaped)
+ escaped = 0;
+ else if (bslashchar(ch))
+ escaped = 1;
+ }
+ if (periodchar(ch))
+ return (res_hnok(dn));
+ return (0);
+}
+
+/*%
+ * This function is quite liberal, since RFC1034's character sets are only
+ * recommendations.
+ */
+int
+res_dnok(const char *dn) {
+ int ch;
+
+ while ((ch = *dn++) != '\0')
+ if (!domainchar(ch))
+ return (0);
+ return (1);
+}
+
+#ifdef BIND_4_COMPAT
+/*%
+ * This module must export the following externally-visible symbols:
+ * ___putlong
+ * ___putshort
+ * __getlong
+ * __getshort
+ * Note that one _ comes from C and the others come from us.
+ */
+
+#ifdef SOLARIS2
+#ifdef __putlong
+#undef __putlong
+#endif
+#ifdef __putshort
+#undef __putshort
+#endif
+#pragma weak putlong = __putlong
+#pragma weak putshort = __putshort
+#endif /* SOLARIS2 */
+
+void __putlong(u_int32_t src, u_char *dst) { ns_put32(src, dst); }
+void __putshort(u_int16_t src, u_char *dst) { ns_put16(src, dst); }
+#ifndef __ultrix__
+u_int32_t _getlong(const u_char *src) { return (ns_get32(src)); }
+u_int16_t _getshort(const u_char *src) { return (ns_get16(src)); }
+#endif /*__ultrix__*/
+#endif /*BIND_4_COMPAT*/
+
+/*
+ * Weak aliases for applications that use certain private entry points,
+ * and fail to include <resolv.h>.
+ */
+#undef dn_comp
+__weak_reference(__dn_comp, dn_comp);
+#undef dn_expand
+__weak_reference(__dn_expand, dn_expand);
+
+/*! \file */
diff --git a/lib/libc/resolv/res_data.c b/lib/libc/resolv/res_data.c
new file mode 100644
index 000000000000..6b83df23ff2a
--- /dev/null
+++ b/lib/libc/resolv/res_data.c
@@ -0,0 +1,335 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1995-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: res_data.c,v 1.7 2008/12/11 09:59:00 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "port_before.h"
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <res_update.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "port_after.h"
+
+const char *_res_opcodes[] = {
+ "QUERY",
+ "IQUERY",
+ "CQUERYM",
+ "CQUERYU", /*%< experimental */
+ "NOTIFY", /*%< experimental */
+ "UPDATE",
+ "6",
+ "7",
+ "8",
+ "9",
+ "10",
+ "11",
+ "12",
+ "13",
+ "ZONEINIT",
+ "ZONEREF",
+};
+
+#ifdef BIND_UPDATE
+const char *_res_sectioncodes[] = {
+ "ZONE",
+ "PREREQUISITES",
+ "UPDATE",
+ "ADDITIONAL",
+};
+#endif
+
+#ifndef __BIND_NOSTATIC
+
+/* Proto. */
+
+int res_ourserver_p(const res_state, const struct sockaddr_in *);
+
+__noinline int
+res_init(void) {
+ extern int __res_vinit(res_state, int);
+ res_state statp = &_res;
+
+ /*
+ * These three fields used to be statically initialized. This made
+ * it hard to use this code in a shared library. It is necessary,
+ * now that we're doing dynamic initialization here, that we preserve
+ * the old semantics: if an application modifies one of these three
+ * fields of _res before res_init() is called, res_init() will not
+ * alter them. Of course, if an application is setting them to
+ * _zero_ before calling res_init(), hoping to override what used
+ * to be the static default, we can't detect it and unexpected results
+ * will follow. Zero for any of these fields would make no sense,
+ * so one can safely assume that the applications were already getting
+ * unexpected results.
+ *
+ * _res.options is tricky since some apps were known to diddle the bits
+ * before res_init() was first called. We can't replicate that semantic
+ * with dynamic initialization (they may have turned bits off that are
+ * set in RES_DEFAULT). Our solution is to declare such applications
+ * "broken". They could fool us by setting RES_INIT but none do (yet).
+ */
+ if (!statp->retrans)
+ statp->retrans = RES_TIMEOUT;
+ if (!statp->retry)
+ statp->retry = RES_DFLRETRY;
+ if (!(statp->options & RES_INIT))
+ statp->options = RES_DEFAULT;
+
+ return (__res_vinit(statp, 1));
+}
+
+void
+p_query(const u_char *msg) {
+ fp_query(msg, stdout);
+}
+
+void
+fp_query(const u_char *msg, FILE *file) {
+ fp_nquery(msg, PACKETSZ, file);
+}
+
+void
+fp_nquery(const u_char *msg, int len, FILE *file) {
+ res_state statp = &_res;
+ if ((statp->options & RES_INIT) == 0U && res_init() == -1)
+ return;
+
+ res_pquery(statp, msg, len, file);
+}
+
+int
+res_mkquery(int op, /*!< opcode of query */
+ const char *dname, /*!< domain name */
+ int class, int type, /*!< class and type of query */
+ const u_char *data, /*!< resource record data */
+ int datalen, /*!< length of data */
+ const u_char *newrr_in, /*!< new rr for modify or append */
+ u_char *buf, /*!< buffer to put query */
+ int buflen) /*!< size of buffer */
+{
+ res_state statp = &_res;
+ if ((statp->options & RES_INIT) == 0U && res_init() == -1) {
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ return (-1);
+ }
+ return (res_nmkquery(statp, op, dname, class, type,
+ data, datalen,
+ newrr_in, buf, buflen));
+}
+
+int
+res_mkupdate(ns_updrec *rrecp_in, u_char *buf, int buflen) {
+ res_state statp = &_res;
+ if ((statp->options & RES_INIT) == 0U && res_init() == -1) {
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ return (-1);
+ }
+
+ return (res_nmkupdate(statp, rrecp_in, buf, buflen));
+}
+
+int
+res_query(const char *name, /*!< domain name */
+ int class, int type, /*!< class and type of query */
+ u_char *answer, /*!< buffer to put answer */
+ int anslen) /*!< size of answer buffer */
+{
+ res_state statp = &_res;
+ if ((statp->options & RES_INIT) == 0U && res_init() == -1) {
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ return (-1);
+ }
+ return (res_nquery(statp, name, class, type, answer, anslen));
+}
+
+#ifndef _LIBC
+void
+res_send_setqhook(res_send_qhook hook) {
+ _res.qhook = hook;
+}
+
+void
+res_send_setrhook(res_send_rhook hook) {
+ _res.rhook = hook;
+}
+#endif
+
+int
+res_isourserver(const struct sockaddr_in *inp) {
+ return (res_ourserver_p(&_res, inp));
+}
+
+int
+res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) {
+ res_state statp = &_res;
+ if ((statp->options & RES_INIT) == 0U && res_init() == -1) {
+ /* errno should have been set by res_init() in this case. */
+ return (-1);
+ }
+
+ return (res_nsend(statp, buf, buflen, ans, anssiz));
+}
+
+#ifndef _LIBC
+int
+res_sendsigned(const u_char *buf, int buflen, ns_tsig_key *key,
+ u_char *ans, int anssiz)
+{
+ res_state statp = &_res;
+ if ((statp->options & RES_INIT) == 0U && res_init() == -1) {
+ /* errno should have been set by res_init() in this case. */
+ return (-1);
+ }
+
+ return (res_nsendsigned(statp, buf, buflen, key, ans, anssiz));
+}
+#endif
+
+void
+res_close(void) {
+ res_nclose(&_res);
+}
+
+int
+res_update(ns_updrec *rrecp_in) {
+ res_state statp = &_res;
+ if ((statp->options & RES_INIT) == 0U && res_init() == -1) {
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ return (-1);
+ }
+
+ return (res_nupdate(statp, rrecp_in, NULL));
+}
+
+int
+res_search(const char *name, /*!< domain name */
+ int class, int type, /*!< class and type of query */
+ u_char *answer, /*!< buffer to put answer */
+ int anslen) /*!< size of answer */
+{
+ res_state statp = &_res;
+ if ((statp->options & RES_INIT) == 0U && res_init() == -1) {
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ return (-1);
+ }
+
+ return (res_nsearch(statp, name, class, type, answer, anslen));
+}
+
+int
+res_querydomain(const char *name,
+ const char *domain,
+ int class, int type, /*!< class and type of query */
+ u_char *answer, /*!< buffer to put answer */
+ int anslen) /*!< size of answer */
+{
+ res_state statp = &_res;
+ if ((statp->options & RES_INIT) == 0U && res_init() == -1) {
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ return (-1);
+ }
+
+ return (res_nquerydomain(statp, name, domain,
+ class, type,
+ answer, anslen));
+}
+
+u_int
+res_randomid(void) {
+ res_state statp = &_res;
+ if ((statp->options & RES_INIT) == 0U && res_init() == -1) {
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ return (-1);
+ }
+
+ return (res_nrandomid(statp));
+}
+
+int
+res_opt(int n0, u_char *buf, int buflen, int anslen)
+{
+ return (res_nopt(&_res, n0, buf, buflen, anslen));
+}
+
+const char *
+hostalias(const char *name) {
+ static char abuf[MAXDNAME];
+
+ return (res_hostalias(&_res, name, abuf, sizeof abuf));
+}
+
+#ifdef ultrix
+int
+local_hostname_length(const char *hostname) {
+ int len_host, len_domain;
+ res_state statp;
+
+ statp = &_res;
+ if (!*statp->defdname)
+ res_init();
+ len_host = strlen(hostname);
+ len_domain = strlen(statp->defdname);
+ if (len_host > len_domain &&
+ !strcasecmp(hostname + len_host - len_domain, statp->defdname) &&
+ hostname[len_host - len_domain - 1] == '.')
+ return (len_host - len_domain - 1);
+ return (0);
+}
+#endif /*ultrix*/
+
+/*
+ * Weak aliases for applications that use certain private entry points,
+ * and fail to include <resolv.h>.
+ */
+#undef res_init
+__weak_reference(__res_init, res_init);
+#undef p_query
+__weak_reference(__p_query, p_query);
+#undef res_mkquery
+__weak_reference(__res_mkquery, res_mkquery);
+#undef res_query
+__weak_reference(__res_query, res_query);
+#undef res_send
+__weak_reference(__res_send, res_send);
+#undef res_close
+__weak_reference(__res_close, _res_close);
+#undef res_search
+__weak_reference(__res_search, res_search);
+#undef res_querydomain
+__weak_reference(__res_querydomain, res_querydomain);
+
+#endif
+
+/*! \file */
diff --git a/lib/libc/resolv/res_debug.c b/lib/libc/resolv/res_debug.c
new file mode 100644
index 000000000000..2017909d88b1
--- /dev/null
+++ b/lib/libc/resolv/res_debug.c
@@ -0,0 +1,1239 @@
+/*
+ * Portions Copyright (C) 2004, 2005, 2008, 2009 Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (C) 1996-2003 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Copyright (c) 1985
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*
+ * Portions Copyright (c) 1995 by International Business Machines, Inc.
+ *
+ * International Business Machines, Inc. (hereinafter called IBM) grants
+ * permission under its copyrights to use, copy, modify, and distribute this
+ * Software with or without fee, provided that the above copyright notice and
+ * all paragraphs of this notice appear in all copies, and that the name of IBM
+ * not be used in connection with the marketing of any product incorporating
+ * the Software or modifications thereof, without specific, written prior
+ * permission.
+ *
+ * To the extent it has a right to do so, IBM grants an immunity from suit
+ * under its patents, if any, for the use, sale or manufacture of products to
+ * the extent that such products are used for performing Domain Name System
+ * dynamic updates in TCP/IP networks by means of the Software. No immunity is
+ * granted for any product per se or for any other function of any product.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
+ * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
+ * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)res_debug.c 8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: res_debug.c,v 1.19 2009/02/26 11:20:20 tbox Exp $";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "port_before.h"
+
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <math.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <resolv_mt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "port_after.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) sprintf x
+#endif
+
+extern const char *_res_opcodes[];
+extern const char *_res_sectioncodes[];
+
+/*%
+ * Print the current options.
+ */
+void
+fp_resstat(const res_state statp, FILE *file) {
+ u_long mask;
+
+ fprintf(file, ";; res options:");
+ for (mask = 1; mask != 0U; mask <<= 1)
+ if (statp->options & mask)
+ fprintf(file, " %s", p_option(mask));
+ putc('\n', file);
+}
+
+static void
+do_section(const res_state statp,
+ ns_msg *handle, ns_sect section,
+ int pflag, FILE *file)
+{
+ int n, sflag, rrnum;
+ static int buflen = 2048;
+ char *buf;
+ ns_opcode opcode;
+ ns_rr rr;
+
+ /*
+ * Print answer records.
+ */
+ sflag = (statp->pfcode & pflag);
+ if (statp->pfcode && !sflag)
+ return;
+
+ buf = malloc(buflen);
+ if (buf == NULL) {
+ fprintf(file, ";; memory allocation failure\n");
+ return;
+ }
+
+ opcode = (ns_opcode) ns_msg_getflag(*handle, ns_f_opcode);
+ rrnum = 0;
+ for (;;) {
+ if (ns_parserr(handle, section, rrnum, &rr)) {
+ if (errno != ENODEV)
+ fprintf(file, ";; ns_parserr: %s\n",
+ strerror(errno));
+ else if (rrnum > 0 && sflag != 0 &&
+ (statp->pfcode & RES_PRF_HEAD1))
+ putc('\n', file);
+ goto cleanup;
+ }
+ if (rrnum == 0 && sflag != 0 && (statp->pfcode & RES_PRF_HEAD1))
+ fprintf(file, ";; %s SECTION:\n",
+ p_section(section, opcode));
+ if (section == ns_s_qd)
+ fprintf(file, ";;\t%s, type = %s, class = %s\n",
+ ns_rr_name(rr),
+ p_type(ns_rr_type(rr)),
+ p_class(ns_rr_class(rr)));
+ else if (section == ns_s_ar && ns_rr_type(rr) == ns_t_opt) {
+ u_int16_t optcode, optlen, rdatalen = ns_rr_rdlen(rr);
+ u_int32_t ttl = ns_rr_ttl(rr);
+
+ fprintf(file,
+ "; EDNS: version: %u, udp=%u, flags=%04x\n",
+ (ttl>>16)&0xff, ns_rr_class(rr), ttl&0xffff);
+
+ while (rdatalen >= 4) {
+ const u_char *cp = ns_rr_rdata(rr);
+ int i;
+
+ GETSHORT(optcode, cp);
+ GETSHORT(optlen, cp);
+
+ if (optcode == NS_OPT_NSID) {
+ fputs("; NSID: ", file);
+ if (optlen == 0) {
+ fputs("; NSID\n", file);
+ } else {
+ fputs("; NSID: ", file);
+ for (i = 0; i < optlen; i++)
+ fprintf(file, "%02x ",
+ cp[i]);
+ fputs(" (",file);
+ for (i = 0; i < optlen; i++)
+ fprintf(file, "%c",
+ isprint(cp[i])?
+ cp[i] : '.');
+ fputs(")\n", file);
+ }
+ } else {
+ if (optlen == 0) {
+ fprintf(file, "; OPT=%u\n",
+ optcode);
+ } else {
+ fprintf(file, "; OPT=%u: ",
+ optcode);
+ for (i = 0; i < optlen; i++)
+ fprintf(file, "%02x ",
+ cp[i]);
+ fputs(" (",file);
+ for (i = 0; i < optlen; i++)
+ fprintf(file, "%c",
+ isprint(cp[i]) ?
+ cp[i] : '.');
+ fputs(")\n", file);
+ }
+ }
+ rdatalen -= 4 + optlen;
+ }
+ } else {
+ n = ns_sprintrr(handle, &rr, NULL, NULL,
+ buf, buflen);
+ if (n < 0) {
+ if (errno == ENOSPC) {
+ free(buf);
+ buf = NULL;
+ if (buflen < 131072)
+ buf = malloc(buflen += 1024);
+ if (buf == NULL) {
+ fprintf(file,
+ ";; memory allocation failure\n");
+ return;
+ }
+ continue;
+ }
+ fprintf(file, ";; ns_sprintrr: %s\n",
+ strerror(errno));
+ goto cleanup;
+ }
+ fputs(buf, file);
+ fputc('\n', file);
+ }
+ rrnum++;
+ }
+ cleanup:
+ if (buf != NULL)
+ free(buf);
+}
+
+/*%
+ * Print the contents of a query.
+ * This is intended to be primarily a debugging routine.
+ */
+void
+res_pquery(const res_state statp, const u_char *msg, int len, FILE *file) {
+ ns_msg handle;
+ int qdcount, ancount, nscount, arcount;
+ u_int opcode, rcode, id;
+
+ if (ns_initparse(msg, len, &handle) < 0) {
+ fprintf(file, ";; ns_initparse: %s\n", strerror(errno));
+ return;
+ }
+ opcode = ns_msg_getflag(handle, ns_f_opcode);
+ rcode = ns_msg_getflag(handle, ns_f_rcode);
+ id = ns_msg_id(handle);
+ qdcount = ns_msg_count(handle, ns_s_qd);
+ ancount = ns_msg_count(handle, ns_s_an);
+ nscount = ns_msg_count(handle, ns_s_ns);
+ arcount = ns_msg_count(handle, ns_s_ar);
+
+ /*
+ * Print header fields.
+ */
+ if ((!statp->pfcode) || (statp->pfcode & RES_PRF_HEADX) || rcode)
+ fprintf(file,
+ ";; ->>HEADER<<- opcode: %s, status: %s, id: %d\n",
+ _res_opcodes[opcode], p_rcode(rcode), id);
+ if ((!statp->pfcode) || (statp->pfcode & RES_PRF_HEADX))
+ putc(';', file);
+ if ((!statp->pfcode) || (statp->pfcode & RES_PRF_HEAD2)) {
+ fprintf(file, "; flags:");
+ if (ns_msg_getflag(handle, ns_f_qr))
+ fprintf(file, " qr");
+ if (ns_msg_getflag(handle, ns_f_aa))
+ fprintf(file, " aa");
+ if (ns_msg_getflag(handle, ns_f_tc))
+ fprintf(file, " tc");
+ if (ns_msg_getflag(handle, ns_f_rd))
+ fprintf(file, " rd");
+ if (ns_msg_getflag(handle, ns_f_ra))
+ fprintf(file, " ra");
+ if (ns_msg_getflag(handle, ns_f_z))
+ fprintf(file, " ??");
+ if (ns_msg_getflag(handle, ns_f_ad))
+ fprintf(file, " ad");
+ if (ns_msg_getflag(handle, ns_f_cd))
+ fprintf(file, " cd");
+ }
+ if ((!statp->pfcode) || (statp->pfcode & RES_PRF_HEAD1)) {
+ fprintf(file, "; %s: %d",
+ p_section(ns_s_qd, opcode), qdcount);
+ fprintf(file, ", %s: %d",
+ p_section(ns_s_an, opcode), ancount);
+ fprintf(file, ", %s: %d",
+ p_section(ns_s_ns, opcode), nscount);
+ fprintf(file, ", %s: %d",
+ p_section(ns_s_ar, opcode), arcount);
+ }
+ if ((!statp->pfcode) || (statp->pfcode &
+ (RES_PRF_HEADX | RES_PRF_HEAD2 | RES_PRF_HEAD1))) {
+ putc('\n',file);
+ }
+ /*
+ * Print the various sections.
+ */
+ do_section(statp, &handle, ns_s_qd, RES_PRF_QUES, file);
+ do_section(statp, &handle, ns_s_an, RES_PRF_ANS, file);
+ do_section(statp, &handle, ns_s_ns, RES_PRF_AUTH, file);
+ do_section(statp, &handle, ns_s_ar, RES_PRF_ADD, file);
+ if (qdcount == 0 && ancount == 0 &&
+ nscount == 0 && arcount == 0)
+ putc('\n', file);
+}
+
+const u_char *
+p_cdnname(const u_char *cp, const u_char *msg, int len, FILE *file) {
+ char name[MAXDNAME];
+ int n;
+
+ if ((n = dn_expand(msg, msg + len, cp, name, sizeof name)) < 0)
+ return (NULL);
+ if (name[0] == '\0')
+ putc('.', file);
+ else
+ fputs(name, file);
+ return (cp + n);
+}
+
+const u_char *
+p_cdname(const u_char *cp, const u_char *msg, FILE *file) {
+ return (p_cdnname(cp, msg, PACKETSZ, file));
+}
+
+/*%
+ * Return a fully-qualified domain name from a compressed name (with
+ length supplied). */
+
+const u_char *
+p_fqnname(const u_char *cp, const u_char *msg, int msglen, char *name,
+ int namelen)
+{
+ int n, newlen;
+
+ if ((n = dn_expand(msg, cp + msglen, cp, name, namelen)) < 0)
+ return (NULL);
+ newlen = strlen(name);
+ if (newlen == 0 || name[newlen - 1] != '.') {
+ if (newlen + 1 >= namelen) /*%< Lack space for final dot */
+ return (NULL);
+ else
+ strcpy(name + newlen, ".");
+ }
+ return (cp + n);
+}
+
+/* XXX: the rest of these functions need to become length-limited, too. */
+
+const u_char *
+p_fqname(const u_char *cp, const u_char *msg, FILE *file) {
+ char name[MAXDNAME];
+ const u_char *n;
+
+ n = p_fqnname(cp, msg, MAXCDNAME, name, sizeof name);
+ if (n == NULL)
+ return (NULL);
+ fputs(name, file);
+ return (n);
+}
+
+/*%
+ * Names of RR classes and qclasses. Classes and qclasses are the same, except
+ * that C_ANY is a qclass but not a class. (You can ask for records of class
+ * C_ANY, but you can't have any records of that class in the database.)
+ */
+const struct res_sym __p_class_syms[] = {
+ {C_IN, "IN", (char *)0},
+ {C_CHAOS, "CH", (char *)0},
+ {C_CHAOS, "CHAOS", (char *)0},
+ {C_HS, "HS", (char *)0},
+ {C_HS, "HESIOD", (char *)0},
+ {C_ANY, "ANY", (char *)0},
+ {C_NONE, "NONE", (char *)0},
+ {C_IN, (char *)0, (char *)0}
+};
+
+/*%
+ * Names of message sections.
+ */
+static const struct res_sym __p_default_section_syms[] = {
+ {ns_s_qd, "QUERY", (char *)0},
+ {ns_s_an, "ANSWER", (char *)0},
+ {ns_s_ns, "AUTHORITY", (char *)0},
+ {ns_s_ar, "ADDITIONAL", (char *)0},
+ {0, (char *)0, (char *)0}
+};
+
+static const struct res_sym __p_update_section_syms[] = {
+ {S_ZONE, "ZONE", (char *)0},
+ {S_PREREQ, "PREREQUISITE", (char *)0},
+ {S_UPDATE, "UPDATE", (char *)0},
+ {S_ADDT, "ADDITIONAL", (char *)0},
+ {0, (char *)0, (char *)0}
+};
+
+const struct res_sym __p_key_syms[] = {
+ {NS_ALG_MD5RSA, "RSA", "RSA KEY with MD5 hash"},
+ {NS_ALG_DH, "DH", "Diffie Hellman"},
+ {NS_ALG_DSA, "DSA", "Digital Signature Algorithm"},
+ {NS_ALG_EXPIRE_ONLY, "EXPIREONLY", "No algorithm"},
+ {NS_ALG_PRIVATE_OID, "PRIVATE", "Algorithm obtained from OID"},
+ {0, NULL, NULL}
+};
+
+const struct res_sym __p_cert_syms[] = {
+ {cert_t_pkix, "PKIX", "PKIX (X.509v3) Certificate"},
+ {cert_t_spki, "SPKI", "SPKI certificate"},
+ {cert_t_pgp, "PGP", "PGP certificate"},
+ {cert_t_url, "URL", "URL Private"},
+ {cert_t_oid, "OID", "OID Private"},
+ {0, NULL, NULL}
+};
+
+/*%
+ * Names of RR types and qtypes. Types and qtypes are the same, except
+ * that T_ANY is a qtype but not a type. (You can ask for records of type
+ * T_ANY, but you can't have any records of that type in the database.)
+ */
+const struct res_sym __p_type_syms[] = {
+ {ns_t_a, "A", "address"},
+ {ns_t_ns, "NS", "name server"},
+ {ns_t_md, "MD", "mail destination (deprecated)"},
+ {ns_t_mf, "MF", "mail forwarder (deprecated)"},
+ {ns_t_cname, "CNAME", "canonical name"},
+ {ns_t_soa, "SOA", "start of authority"},
+ {ns_t_mb, "MB", "mailbox"},
+ {ns_t_mg, "MG", "mail group member"},
+ {ns_t_mr, "MR", "mail rename"},
+ {ns_t_null, "NULL", "null"},
+ {ns_t_wks, "WKS", "well-known service (deprecated)"},
+ {ns_t_ptr, "PTR", "domain name pointer"},
+ {ns_t_hinfo, "HINFO", "host information"},
+ {ns_t_minfo, "MINFO", "mailbox information"},
+ {ns_t_mx, "MX", "mail exchanger"},
+ {ns_t_txt, "TXT", "text"},
+ {ns_t_rp, "RP", "responsible person"},
+ {ns_t_afsdb, "AFSDB", "DCE or AFS server"},
+ {ns_t_x25, "X25", "X25 address"},
+ {ns_t_isdn, "ISDN", "ISDN address"},
+ {ns_t_rt, "RT", "router"},
+ {ns_t_nsap, "NSAP", "nsap address"},
+ {ns_t_nsap_ptr, "NSAP_PTR", "domain name pointer"},
+ {ns_t_sig, "SIG", "signature"},
+ {ns_t_key, "KEY", "key"},
+ {ns_t_px, "PX", "mapping information"},
+ {ns_t_gpos, "GPOS", "geographical position (withdrawn)"},
+ {ns_t_aaaa, "AAAA", "IPv6 address"},
+ {ns_t_loc, "LOC", "location"},
+ {ns_t_nxt, "NXT", "next valid name (unimplemented)"},
+ {ns_t_eid, "EID", "endpoint identifier (unimplemented)"},
+ {ns_t_nimloc, "NIMLOC", "NIMROD locator (unimplemented)"},
+ {ns_t_srv, "SRV", "server selection"},
+ {ns_t_atma, "ATMA", "ATM address (unimplemented)"},
+ {ns_t_naptr, "NAPTR", "naptr"},
+ {ns_t_kx, "KX", "key exchange"},
+ {ns_t_cert, "CERT", "certificate"},
+ {ns_t_a6, "A", "IPv6 address (experminental)"},
+ {ns_t_dname, "DNAME", "non-terminal redirection"},
+ {ns_t_opt, "OPT", "opt"},
+ {ns_t_apl, "apl", "apl"},
+ {ns_t_ds, "DS", "delegation signer"},
+ {ns_t_sshfp, "SSFP", "SSH fingerprint"},
+ {ns_t_ipseckey, "IPSECKEY", "IPSEC key"},
+ {ns_t_rrsig, "RRSIG", "rrsig"},
+ {ns_t_nsec, "NSEC", "nsec"},
+ {ns_t_dnskey, "DNSKEY", "DNS key"},
+ {ns_t_dhcid, "DHCID", "dynamic host configuration identifier"},
+ {ns_t_nsec3, "NSEC3", "nsec3"},
+ {ns_t_nsec3param, "NSEC3PARAM", "NSEC3 parameters"},
+ {ns_t_hip, "HIP", "host identity protocol"},
+ {ns_t_spf, "SPF", "sender policy framework"},
+ {ns_t_tkey, "TKEY", "tkey"},
+ {ns_t_tsig, "TSIG", "transaction signature"},
+ {ns_t_ixfr, "IXFR", "incremental zone transfer"},
+ {ns_t_axfr, "AXFR", "zone transfer"},
+ {ns_t_zxfr, "ZXFR", "compressed zone transfer"},
+ {ns_t_mailb, "MAILB", "mailbox-related data (deprecated)"},
+ {ns_t_maila, "MAILA", "mail agent (deprecated)"},
+ {ns_t_naptr, "NAPTR", "URN Naming Authority"},
+ {ns_t_kx, "KX", "Key Exchange"},
+ {ns_t_cert, "CERT", "Certificate"},
+ {ns_t_a6, "A6", "IPv6 Address"},
+ {ns_t_dname, "DNAME", "dname"},
+ {ns_t_sink, "SINK", "Kitchen Sink (experimental)"},
+ {ns_t_opt, "OPT", "EDNS Options"},
+ {ns_t_any, "ANY", "\"any\""},
+ {ns_t_dlv, "DLV", "DNSSEC look-aside validation"},
+ {0, NULL, NULL}
+};
+
+/*%
+ * Names of DNS rcodes.
+ */
+const struct res_sym __p_rcode_syms[] = {
+ {ns_r_noerror, "NOERROR", "no error"},
+ {ns_r_formerr, "FORMERR", "format error"},
+ {ns_r_servfail, "SERVFAIL", "server failed"},
+ {ns_r_nxdomain, "NXDOMAIN", "no such domain name"},
+ {ns_r_notimpl, "NOTIMP", "not implemented"},
+ {ns_r_refused, "REFUSED", "refused"},
+ {ns_r_yxdomain, "YXDOMAIN", "domain name exists"},
+ {ns_r_yxrrset, "YXRRSET", "rrset exists"},
+ {ns_r_nxrrset, "NXRRSET", "rrset doesn't exist"},
+ {ns_r_notauth, "NOTAUTH", "not authoritative"},
+ {ns_r_notzone, "NOTZONE", "Not in zone"},
+ {ns_r_max, "", ""},
+ {ns_r_badsig, "BADSIG", "bad signature"},
+ {ns_r_badkey, "BADKEY", "bad key"},
+ {ns_r_badtime, "BADTIME", "bad time"},
+ {0, NULL, NULL}
+};
+
+int
+sym_ston(const struct res_sym *syms, const char *name, int *success) {
+ for ((void)NULL; syms->name != 0; syms++) {
+ if (strcasecmp (name, syms->name) == 0) {
+ if (success)
+ *success = 1;
+ return (syms->number);
+ }
+ }
+ if (success)
+ *success = 0;
+ return (syms->number); /*%< The default value. */
+}
+
+const char *
+sym_ntos(const struct res_sym *syms, int number, int *success) {
+ char *unname = sym_ntos_unname;
+
+ for ((void)NULL; syms->name != 0; syms++) {
+ if (number == syms->number) {
+ if (success)
+ *success = 1;
+ return (syms->name);
+ }
+ }
+
+ sprintf(unname, "%d", number); /*%< XXX nonreentrant */
+ if (success)
+ *success = 0;
+ return (unname);
+}
+
+const char *
+sym_ntop(const struct res_sym *syms, int number, int *success) {
+ char *unname = sym_ntop_unname;
+
+ for ((void)NULL; syms->name != 0; syms++) {
+ if (number == syms->number) {
+ if (success)
+ *success = 1;
+ return (syms->humanname);
+ }
+ }
+ sprintf(unname, "%d", number); /*%< XXX nonreentrant */
+ if (success)
+ *success = 0;
+ return (unname);
+}
+
+/*%
+ * Return a string for the type.
+ */
+const char *
+p_type(int type) {
+ int success;
+ const char *result;
+ static char typebuf[20];
+
+ result = sym_ntos(__p_type_syms, type, &success);
+ if (success)
+ return (result);
+ if (type < 0 || type > 0xffff)
+ return ("BADTYPE");
+ sprintf(typebuf, "TYPE%d", type);
+ return (typebuf);
+}
+
+/*%
+ * Return a string for the type.
+ */
+const char *
+p_section(int section, int opcode) {
+ const struct res_sym *symbols;
+
+ switch (opcode) {
+ case ns_o_update:
+ symbols = __p_update_section_syms;
+ break;
+ default:
+ symbols = __p_default_section_syms;
+ break;
+ }
+ return (sym_ntos(symbols, section, (int *)0));
+}
+
+/*%
+ * Return a mnemonic for class.
+ */
+const char *
+p_class(int class) {
+ int success;
+ const char *result;
+ static char classbuf[20];
+
+ result = sym_ntos(__p_class_syms, class, &success);
+ if (success)
+ return (result);
+ if (class < 0 || class > 0xffff)
+ return ("BADCLASS");
+ sprintf(classbuf, "CLASS%d", class);
+ return (classbuf);
+}
+
+/*%
+ * Return a mnemonic for an option
+ */
+const char *
+p_option(u_long option) {
+ char *nbuf = p_option_nbuf;
+
+ switch (option) {
+ case RES_INIT: return "init";
+ case RES_DEBUG: return "debug";
+ case RES_AAONLY: return "aaonly(unimpl)";
+ case RES_USEVC: return "usevc";
+ case RES_PRIMARY: return "primry(unimpl)";
+ case RES_IGNTC: return "igntc";
+ case RES_RECURSE: return "recurs";
+ case RES_DEFNAMES: return "defnam";
+ case RES_STAYOPEN: return "styopn";
+ case RES_DNSRCH: return "dnsrch";
+ case RES_INSECURE1: return "insecure1";
+ case RES_INSECURE2: return "insecure2";
+ case RES_NOALIASES: return "noaliases";
+ case RES_USE_INET6: return "inet6";
+#ifdef RES_USE_EDNS0 /*%< KAME extension */
+ case RES_USE_EDNS0: return "edns0";
+ case RES_NSID: return "nsid";
+#endif
+#ifdef RES_USE_DNAME
+ case RES_USE_DNAME: return "dname";
+#endif
+#ifdef RES_USE_DNSSEC
+ case RES_USE_DNSSEC: return "dnssec";
+#endif
+#ifdef RES_NOTLDQUERY
+ case RES_NOTLDQUERY: return "no-tld-query";
+#endif
+#ifdef RES_NO_NIBBLE2
+ case RES_NO_NIBBLE2: return "no-nibble2";
+#endif
+ /* XXX nonreentrant */
+ default: sprintf(nbuf, "?0x%lx?", (u_long)option);
+ return (nbuf);
+ }
+}
+
+/*%
+ * Return a mnemonic for a time to live.
+ */
+const char *
+p_time(u_int32_t value) {
+ char *nbuf = p_time_nbuf;
+
+ if (ns_format_ttl(value, nbuf, sizeof nbuf) < 0)
+ sprintf(nbuf, "%u", value);
+ return (nbuf);
+}
+
+/*%
+ * Return a string for the rcode.
+ */
+const char *
+p_rcode(int rcode) {
+ return (sym_ntos(__p_rcode_syms, rcode, (int *)0));
+}
+
+/*%
+ * Return a string for a res_sockaddr_union.
+ */
+const char *
+p_sockun(union res_sockaddr_union u, char *buf, size_t size) {
+ char ret[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:123.123.123.123"];
+
+ switch (u.sin.sin_family) {
+ case AF_INET:
+ inet_ntop(AF_INET, &u.sin.sin_addr, ret, sizeof ret);
+ break;
+#ifdef HAS_INET6_STRUCTS
+ case AF_INET6:
+ inet_ntop(AF_INET6, &u.sin6.sin6_addr, ret, sizeof ret);
+ break;
+#endif
+ default:
+ sprintf(ret, "[af%d]", u.sin.sin_family);
+ break;
+ }
+ if (size > 0U) {
+ strncpy(buf, ret, size - 1);
+ buf[size - 1] = '0';
+ }
+ return (buf);
+}
+
+/*%
+ * routines to convert between on-the-wire RR format and zone file format.
+ * Does not contain conversion to/from decimal degrees; divide or multiply
+ * by 60*60*1000 for that.
+ */
+
+static unsigned int poweroften[10] = {1, 10, 100, 1000, 10000, 100000,
+ 1000000,10000000,100000000,1000000000};
+
+/*% takes an XeY precision/size value, returns a string representation. */
+static const char *
+precsize_ntoa(u_int8_t prec)
+{
+ char *retbuf = precsize_ntoa_retbuf;
+ unsigned long val;
+ int mantissa, exponent;
+
+ mantissa = (int)((prec >> 4) & 0x0f) % 10;
+ exponent = (int)((prec >> 0) & 0x0f) % 10;
+
+ val = mantissa * poweroften[exponent];
+
+ (void) sprintf(retbuf, "%lu.%.2lu", val/100, val%100);
+ return (retbuf);
+}
+
+/*% converts ascii size/precision X * 10**Y(cm) to 0xXY. moves pointer. */
+static u_int8_t
+precsize_aton(const char **strptr) {
+ unsigned int mval = 0, cmval = 0;
+ u_int8_t retval = 0;
+ const char *cp;
+ int exponent;
+ int mantissa;
+
+ cp = *strptr;
+
+ while (isdigit((unsigned char)*cp))
+ mval = mval * 10 + (*cp++ - '0');
+
+ if (*cp == '.') { /*%< centimeters */
+ cp++;
+ if (isdigit((unsigned char)*cp)) {
+ cmval = (*cp++ - '0') * 10;
+ if (isdigit((unsigned char)*cp)) {
+ cmval += (*cp++ - '0');
+ }
+ }
+ }
+ cmval = (mval * 100) + cmval;
+
+ for (exponent = 0; exponent < 9; exponent++)
+ if (cmval < poweroften[exponent+1])
+ break;
+
+ mantissa = cmval / poweroften[exponent];
+ if (mantissa > 9)
+ mantissa = 9;
+
+ retval = (mantissa << 4) | exponent;
+
+ *strptr = cp;
+
+ return (retval);
+}
+
+/*% converts ascii lat/lon to unsigned encoded 32-bit number. moves pointer. */
+static u_int32_t
+latlon2ul(const char **latlonstrptr, int *which) {
+ const char *cp;
+ u_int32_t retval;
+ int deg = 0, min = 0, secs = 0, secsfrac = 0;
+
+ cp = *latlonstrptr;
+
+ while (isdigit((unsigned char)*cp))
+ deg = deg * 10 + (*cp++ - '0');
+
+ while (isspace((unsigned char)*cp))
+ cp++;
+
+ if (!(isdigit((unsigned char)*cp)))
+ goto fndhemi;
+
+ while (isdigit((unsigned char)*cp))
+ min = min * 10 + (*cp++ - '0');
+
+ while (isspace((unsigned char)*cp))
+ cp++;
+
+ if (!(isdigit((unsigned char)*cp)))
+ goto fndhemi;
+
+ while (isdigit((unsigned char)*cp))
+ secs = secs * 10 + (*cp++ - '0');
+
+ if (*cp == '.') { /*%< decimal seconds */
+ cp++;
+ if (isdigit((unsigned char)*cp)) {
+ secsfrac = (*cp++ - '0') * 100;
+ if (isdigit((unsigned char)*cp)) {
+ secsfrac += (*cp++ - '0') * 10;
+ if (isdigit((unsigned char)*cp)) {
+ secsfrac += (*cp++ - '0');
+ }
+ }
+ }
+ }
+
+ while (!isspace((unsigned char)*cp)) /*%< if any trailing garbage */
+ cp++;
+
+ while (isspace((unsigned char)*cp))
+ cp++;
+
+ fndhemi:
+ switch (*cp) {
+ case 'N': case 'n':
+ case 'E': case 'e':
+ retval = ((unsigned)1<<31)
+ + (((((deg * 60) + min) * 60) + secs) * 1000)
+ + secsfrac;
+ break;
+ case 'S': case 's':
+ case 'W': case 'w':
+ retval = ((unsigned)1<<31)
+ - (((((deg * 60) + min) * 60) + secs) * 1000)
+ - secsfrac;
+ break;
+ default:
+ retval = 0; /*%< invalid value -- indicates error */
+ break;
+ }
+
+ switch (*cp) {
+ case 'N': case 'n':
+ case 'S': case 's':
+ *which = 1; /*%< latitude */
+ break;
+ case 'E': case 'e':
+ case 'W': case 'w':
+ *which = 2; /*%< longitude */
+ break;
+ default:
+ *which = 0; /*%< error */
+ break;
+ }
+
+ cp++; /*%< skip the hemisphere */
+ while (!isspace((unsigned char)*cp)) /*%< if any trailing garbage */
+ cp++;
+
+ while (isspace((unsigned char)*cp)) /*%< move to next field */
+ cp++;
+
+ *latlonstrptr = cp;
+
+ return (retval);
+}
+
+/*%
+ * converts a zone file representation in a string to an RDATA on-the-wire
+ * representation. */
+int
+loc_aton(const char *ascii, u_char *binary)
+{
+ const char *cp, *maxcp;
+ u_char *bcp;
+
+ u_int32_t latit = 0, longit = 0, alt = 0;
+ u_int32_t lltemp1 = 0, lltemp2 = 0;
+ int altmeters = 0, altfrac = 0, altsign = 1;
+ u_int8_t hp = 0x16; /*%< default = 1e6 cm = 10000.00m = 10km */
+ u_int8_t vp = 0x13; /*%< default = 1e3 cm = 10.00m */
+ u_int8_t siz = 0x12; /*%< default = 1e2 cm = 1.00m */
+ int which1 = 0, which2 = 0;
+
+ cp = ascii;
+ maxcp = cp + strlen(ascii);
+
+ lltemp1 = latlon2ul(&cp, &which1);
+
+ lltemp2 = latlon2ul(&cp, &which2);
+
+ switch (which1 + which2) {
+ case 3: /*%< 1 + 2, the only valid combination */
+ if ((which1 == 1) && (which2 == 2)) { /*%< normal case */
+ latit = lltemp1;
+ longit = lltemp2;
+ } else if ((which1 == 2) && (which2 == 1)) { /*%< reversed */
+ longit = lltemp1;
+ latit = lltemp2;
+ } else { /*%< some kind of brokenness */
+ return (0);
+ }
+ break;
+ default: /*%< we didn't get one of each */
+ return (0);
+ }
+
+ /* altitude */
+ if (*cp == '-') {
+ altsign = -1;
+ cp++;
+ }
+
+ if (*cp == '+')
+ cp++;
+
+ while (isdigit((unsigned char)*cp))
+ altmeters = altmeters * 10 + (*cp++ - '0');
+
+ if (*cp == '.') { /*%< decimal meters */
+ cp++;
+ if (isdigit((unsigned char)*cp)) {
+ altfrac = (*cp++ - '0') * 10;
+ if (isdigit((unsigned char)*cp)) {
+ altfrac += (*cp++ - '0');
+ }
+ }
+ }
+
+ alt = (10000000 + (altsign * (altmeters * 100 + altfrac)));
+
+ while (!isspace((unsigned char)*cp) && (cp < maxcp)) /*%< if trailing garbage or m */
+ cp++;
+
+ while (isspace((unsigned char)*cp) && (cp < maxcp))
+ cp++;
+
+ if (cp >= maxcp)
+ goto defaults;
+
+ siz = precsize_aton(&cp);
+
+ while (!isspace((unsigned char)*cp) && (cp < maxcp)) /*%< if trailing garbage or m */
+ cp++;
+
+ while (isspace((unsigned char)*cp) && (cp < maxcp))
+ cp++;
+
+ if (cp >= maxcp)
+ goto defaults;
+
+ hp = precsize_aton(&cp);
+
+ while (!isspace((unsigned char)*cp) && (cp < maxcp)) /*%< if trailing garbage or m */
+ cp++;
+
+ while (isspace((unsigned char)*cp) && (cp < maxcp))
+ cp++;
+
+ if (cp >= maxcp)
+ goto defaults;
+
+ vp = precsize_aton(&cp);
+
+ defaults:
+
+ bcp = binary;
+ *bcp++ = (u_int8_t) 0; /*%< version byte */
+ *bcp++ = siz;
+ *bcp++ = hp;
+ *bcp++ = vp;
+ PUTLONG(latit,bcp);
+ PUTLONG(longit,bcp);
+ PUTLONG(alt,bcp);
+
+ return (16); /*%< size of RR in octets */
+}
+
+/*% takes an on-the-wire LOC RR and formats it in a human readable format. */
+const char *
+loc_ntoa(const u_char *binary, char *ascii)
+{
+ static const char *error = "?";
+ static char tmpbuf[sizeof
+"1000 60 60.000 N 1000 60 60.000 W -12345678.00m 90000000.00m 90000000.00m 90000000.00m"];
+ const u_char *cp = binary;
+
+ int latdeg, latmin, latsec, latsecfrac;
+ int longdeg, longmin, longsec, longsecfrac;
+ char northsouth, eastwest;
+ const char *altsign;
+ int altmeters, altfrac;
+
+ const u_int32_t referencealt = 100000 * 100;
+
+ int32_t latval, longval, altval;
+ u_int32_t templ;
+ u_int8_t sizeval, hpval, vpval, versionval;
+
+ char *sizestr, *hpstr, *vpstr;
+
+ versionval = *cp++;
+
+ if (ascii == NULL)
+ ascii = tmpbuf;
+
+ if (versionval) {
+ (void) sprintf(ascii, "; error: unknown LOC RR version");
+ return (ascii);
+ }
+
+ sizeval = *cp++;
+
+ hpval = *cp++;
+ vpval = *cp++;
+
+ GETLONG(templ, cp);
+ latval = (templ - ((unsigned)1<<31));
+
+ GETLONG(templ, cp);
+ longval = (templ - ((unsigned)1<<31));
+
+ GETLONG(templ, cp);
+ if (templ < referencealt) { /*%< below WGS 84 spheroid */
+ altval = referencealt - templ;
+ altsign = "-";
+ } else {
+ altval = templ - referencealt;
+ altsign = "";
+ }
+
+ if (latval < 0) {
+ northsouth = 'S';
+ latval = -latval;
+ } else
+ northsouth = 'N';
+
+ latsecfrac = latval % 1000;
+ latval = latval / 1000;
+ latsec = latval % 60;
+ latval = latval / 60;
+ latmin = latval % 60;
+ latval = latval / 60;
+ latdeg = latval;
+
+ if (longval < 0) {
+ eastwest = 'W';
+ longval = -longval;
+ } else
+ eastwest = 'E';
+
+ longsecfrac = longval % 1000;
+ longval = longval / 1000;
+ longsec = longval % 60;
+ longval = longval / 60;
+ longmin = longval % 60;
+ longval = longval / 60;
+ longdeg = longval;
+
+ altfrac = altval % 100;
+ altmeters = (altval / 100);
+
+ sizestr = strdup(precsize_ntoa(sizeval));
+ hpstr = strdup(precsize_ntoa(hpval));
+ vpstr = strdup(precsize_ntoa(vpval));
+
+ sprintf(ascii,
+ "%d %.2d %.2d.%.3d %c %d %.2d %.2d.%.3d %c %s%d.%.2dm %sm %sm %sm",
+ latdeg, latmin, latsec, latsecfrac, northsouth,
+ longdeg, longmin, longsec, longsecfrac, eastwest,
+ altsign, altmeters, altfrac,
+ (sizestr != NULL) ? sizestr : error,
+ (hpstr != NULL) ? hpstr : error,
+ (vpstr != NULL) ? vpstr : error);
+
+ if (sizestr != NULL)
+ free(sizestr);
+ if (hpstr != NULL)
+ free(hpstr);
+ if (vpstr != NULL)
+ free(vpstr);
+
+ return (ascii);
+}
+
+
+/*% Return the number of DNS hierarchy levels in the name. */
+int
+dn_count_labels(const char *name) {
+ int i, len, count;
+
+ len = strlen(name);
+ for (i = 0, count = 0; i < len; i++) {
+ /* XXX need to check for \. or use named's nlabels(). */
+ if (name[i] == '.')
+ count++;
+ }
+
+ /* don't count initial wildcard */
+ if (name[0] == '*')
+ if (count)
+ count--;
+
+ /* don't count the null label for root. */
+ /* if terminating '.' not found, must adjust */
+ /* count to include last label */
+ if (len > 0 && name[len-1] != '.')
+ count++;
+ return (count);
+}
+
+/*%
+ * Make dates expressed in seconds-since-Jan-1-1970 easy to read.
+ * SIG records are required to be printed like this, by the Secure DNS RFC.
+ */
+char *
+p_secstodate (u_long secs) {
+ char *output = p_secstodate_output;
+ time_t clock = secs;
+ struct tm *time;
+#ifdef HAVE_TIME_R
+ struct tm res;
+
+ time = gmtime_r(&clock, &res);
+#else
+ time = gmtime(&clock);
+#endif
+ time->tm_year += 1900;
+ time->tm_mon += 1;
+ sprintf(output, "%04d%02d%02d%02d%02d%02d",
+ time->tm_year, time->tm_mon, time->tm_mday,
+ time->tm_hour, time->tm_min, time->tm_sec);
+ return (output);
+}
+
+u_int16_t
+res_nametoclass(const char *buf, int *successp) {
+ unsigned long result;
+ char *endptr;
+ int success;
+
+ result = sym_ston(__p_class_syms, buf, &success);
+ if (success)
+ goto done;
+
+ if (strncasecmp(buf, "CLASS", 5) != 0 ||
+ !isdigit((unsigned char)buf[5]))
+ goto done;
+ errno = 0;
+ result = strtoul(buf + 5, &endptr, 10);
+ if (errno == 0 && *endptr == '\0' && result <= 0xffffU)
+ success = 1;
+ done:
+ if (successp)
+ *successp = success;
+ return (result);
+}
+
+u_int16_t
+res_nametotype(const char *buf, int *successp) {
+ unsigned long result;
+ char *endptr;
+ int success;
+
+ result = sym_ston(__p_type_syms, buf, &success);
+ if (success)
+ goto done;
+
+ if (strncasecmp(buf, "type", 4) != 0 ||
+ !isdigit((unsigned char)buf[4]))
+ goto done;
+ errno = 0;
+ result = strtoul(buf + 4, &endptr, 10);
+ if (errno == 0 && *endptr == '\0' && result <= 0xffffU)
+ success = 1;
+ done:
+ if (successp)
+ *successp = success;
+ return (result);
+}
+
+/*
+ * Weak aliases for applications that use certain private entry points,
+ * and fail to include <resolv.h>.
+ */
+#undef fp_resstat
+__weak_reference(__fp_resstat, fp_resstat);
+#undef p_fqnname
+__weak_reference(__p_fqnname, p_fqnname);
+#undef sym_ston
+__weak_reference(__sym_ston, sym_ston);
+#undef sym_ntos
+__weak_reference(__sym_ntos, sym_ntos);
+#undef sym_ntop
+__weak_reference(__sym_ntop, sym_ntop);
+#undef dn_count_labels
+__weak_reference(__dn_count_labels, dn_count_labels);
+#undef p_secstodate
+__weak_reference(__p_secstodate, p_secstodate);
+
+/*! \file */
diff --git a/lib/libc/resolv/res_debug.h b/lib/libc/resolv/res_debug.h
new file mode 100644
index 000000000000..c28171d7c805
--- /dev/null
+++ b/lib/libc/resolv/res_debug.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _RES_DEBUG_H_
+#define _RES_DEBUG_H_
+
+#ifndef DEBUG
+# define Dprint(cond, args) /*empty*/
+# define DprintQ(cond, args, query, size) /*empty*/
+# define Aerror(statp, file, string, error, address) /*empty*/
+# define Perror(statp, file, string, error) /*empty*/
+#else
+# define Dprint(cond, args) if (cond) {fprintf args;} else {}
+# define DprintQ(cond, args, query, size) if (cond) {\
+ fprintf args;\
+ res_pquery(statp, query, size, stdout);\
+ } else {}
+#endif
+
+#endif /* _RES_DEBUG_H_ */
+/*! \file */
diff --git a/lib/libc/resolv/res_findzonecut.c b/lib/libc/resolv/res_findzonecut.c
new file mode 100644
index 000000000000..515be11b74f3
--- /dev/null
+++ b/lib/libc/resolv/res_findzonecut.c
@@ -0,0 +1,727 @@
+#if !defined(lint) && !defined(SABER)
+static const char rcsid[] = "$Id: res_findzonecut.c,v 1.10 2005/10/11 00:10:16 marka Exp $";
+#endif /* not lint */
+
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/* Import. */
+
+#include "port_before.h"
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <netdb.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <isc/list.h>
+
+#include "port_after.h"
+
+#include <resolv.h>
+
+/* Data structures. */
+
+typedef struct rr_a {
+ LINK(struct rr_a) link;
+ union res_sockaddr_union addr;
+} rr_a;
+typedef LIST(rr_a) rrset_a;
+
+typedef struct rr_ns {
+ LINK(struct rr_ns) link;
+ const char * name;
+ unsigned int flags;
+ rrset_a addrs;
+} rr_ns;
+typedef LIST(rr_ns) rrset_ns;
+
+#define RR_NS_HAVE_V4 0x01
+#define RR_NS_HAVE_V6 0x02
+
+/* Forward. */
+
+static int satisfy(res_state, const char *, rrset_ns *,
+ union res_sockaddr_union *, int);
+static int add_addrs(res_state, rr_ns *,
+ union res_sockaddr_union *, int);
+static int get_soa(res_state, const char *, ns_class, int,
+ char *, size_t, char *, size_t,
+ rrset_ns *);
+static int get_ns(res_state, const char *, ns_class, int, rrset_ns *);
+static int get_glue(res_state, ns_class, int, rrset_ns *);
+static int save_ns(res_state, ns_msg *, ns_sect,
+ const char *, ns_class, int, rrset_ns *);
+static int save_a(res_state, ns_msg *, ns_sect,
+ const char *, ns_class, int, rr_ns *);
+static void free_nsrrset(rrset_ns *);
+static void free_nsrr(rrset_ns *, rr_ns *);
+static rr_ns * find_ns(rrset_ns *, const char *);
+static int do_query(res_state, const char *, ns_class, ns_type,
+ u_char *, ns_msg *);
+static void res_dprintf(const char *, ...) ISC_FORMAT_PRINTF(1, 2);
+
+/* Macros. */
+
+#define DPRINTF(x) do {\
+ int save_errno = errno; \
+ if ((statp->options & RES_DEBUG) != 0U) res_dprintf x; \
+ errno = save_errno; \
+ } while (0)
+
+/* Public. */
+
+/*%
+ * find enclosing zone for a <dname,class>, and some server addresses
+ *
+ * parameters:
+ *\li res - resolver context to work within (is modified)
+ *\li dname - domain name whose enclosing zone is desired
+ *\li class - class of dname (and its enclosing zone)
+ *\li zname - found zone name
+ *\li zsize - allocated size of zname
+ *\li addrs - found server addresses
+ *\li naddrs - max number of addrs
+ *
+ * return values:
+ *\li < 0 - an error occurred (check errno)
+ *\li = 0 - zname is now valid, but addrs[] wasn't changed
+ *\li > 0 - zname is now valid, and return value is number of addrs[] found
+ *
+ * notes:
+ *\li this function calls res_nsend() which means it depends on correctly
+ * functioning recursive nameservers (usually defined in /etc/resolv.conf
+ * or its local equivalent).
+ *
+ *\li we start by asking for an SOA<dname,class>. if we get one as an
+ * answer, that just means <dname,class> is a zone top, which is fine.
+ * more than likely we'll be told to go pound sand, in the form of a
+ * negative answer.
+ *
+ *\li note that we are not prepared to deal with referrals since that would
+ * only come from authority servers and our correctly functioning local
+ * recursive server would have followed the referral and got us something
+ * more definite.
+ *
+ *\li if the authority section contains an SOA, this SOA should also be the
+ * closest enclosing zone, since any intermediary zone cuts would've been
+ * returned as referrals and dealt with by our correctly functioning local
+ * recursive name server. but an SOA in the authority section should NOT
+ * match our dname (since that would have been returned in the answer
+ * section). an authority section SOA has to be "above" our dname.
+ *
+ *\li however, since authority section SOA's were once optional, it's
+ * possible that we'll have to go hunting for the enclosing SOA by
+ * ripping labels off the front of our dname -- this is known as "doing
+ * it the hard way."
+ *
+ *\li ultimately we want some server addresses, which are ideally the ones
+ * pertaining to the SOA.MNAME, but only if there is a matching NS RR.
+ * so the second phase (after we find an SOA) is to go looking for the
+ * NS RRset for that SOA's zone.
+ *
+ *\li no answer section processed by this code is allowed to contain CNAME
+ * or DNAME RR's. for the SOA query this means we strip a label and
+ * keep going. for the NS and A queries this means we just give up.
+ */
+
+#ifndef _LIBC
+int
+res_findzonecut(res_state statp, const char *dname, ns_class class, int opts,
+ char *zname, size_t zsize, struct in_addr *addrs, int naddrs)
+{
+ int result, i;
+ union res_sockaddr_union *u;
+
+
+ opts |= RES_IPV4ONLY;
+ opts &= ~RES_IPV6ONLY;
+
+ u = calloc(naddrs, sizeof(*u));
+ if (u == NULL)
+ return(-1);
+
+ result = res_findzonecut2(statp, dname, class, opts, zname, zsize,
+ u, naddrs);
+
+ for (i = 0; i < result; i++) {
+ addrs[i] = u[i].sin.sin_addr;
+ }
+ free(u);
+ return (result);
+}
+#endif
+
+int
+res_findzonecut2(res_state statp, const char *dname, ns_class class, int opts,
+ char *zname, size_t zsize, union res_sockaddr_union *addrs,
+ int naddrs)
+{
+ char mname[NS_MAXDNAME];
+ u_long save_pfcode;
+ rrset_ns nsrrs;
+ int n;
+
+ DPRINTF(("START dname='%s' class=%s, zsize=%ld, naddrs=%d",
+ dname, p_class(class), (long)zsize, naddrs));
+ save_pfcode = statp->pfcode;
+ statp->pfcode |= RES_PRF_HEAD2 | RES_PRF_HEAD1 | RES_PRF_HEADX |
+ RES_PRF_QUES | RES_PRF_ANS |
+ RES_PRF_AUTH | RES_PRF_ADD;
+ INIT_LIST(nsrrs);
+
+ DPRINTF(("get the soa, and see if it has enough glue"));
+ if ((n = get_soa(statp, dname, class, opts, zname, zsize,
+ mname, sizeof mname, &nsrrs)) < 0 ||
+ ((opts & RES_EXHAUSTIVE) == 0 &&
+ (n = satisfy(statp, mname, &nsrrs, addrs, naddrs)) > 0))
+ goto done;
+
+ DPRINTF(("get the ns rrset and see if it has enough glue"));
+ if ((n = get_ns(statp, zname, class, opts, &nsrrs)) < 0 ||
+ ((opts & RES_EXHAUSTIVE) == 0 &&
+ (n = satisfy(statp, mname, &nsrrs, addrs, naddrs)) > 0))
+ goto done;
+
+ DPRINTF(("get the missing glue and see if it's finally enough"));
+ if ((n = get_glue(statp, class, opts, &nsrrs)) >= 0)
+ n = satisfy(statp, mname, &nsrrs, addrs, naddrs);
+
+ done:
+ DPRINTF(("FINISH n=%d (%s)", n, (n < 0) ? strerror(errno) : "OK"));
+ free_nsrrset(&nsrrs);
+ statp->pfcode = save_pfcode;
+ return (n);
+}
+
+/* Private. */
+
+static int
+satisfy(res_state statp, const char *mname, rrset_ns *nsrrsp,
+ union res_sockaddr_union *addrs, int naddrs)
+{
+ rr_ns *nsrr;
+ int n, x;
+
+ n = 0;
+ nsrr = find_ns(nsrrsp, mname);
+ if (nsrr != NULL) {
+ x = add_addrs(statp, nsrr, addrs, naddrs);
+ addrs += x;
+ naddrs -= x;
+ n += x;
+ }
+ for (nsrr = HEAD(*nsrrsp);
+ nsrr != NULL && naddrs > 0;
+ nsrr = NEXT(nsrr, link))
+ if (ns_samename(nsrr->name, mname) != 1) {
+ x = add_addrs(statp, nsrr, addrs, naddrs);
+ addrs += x;
+ naddrs -= x;
+ n += x;
+ }
+ DPRINTF(("satisfy(%s): %d", mname, n));
+ return (n);
+}
+
+static int
+add_addrs(res_state statp, rr_ns *nsrr,
+ union res_sockaddr_union *addrs, int naddrs)
+{
+ rr_a *arr;
+ int n = 0;
+
+ for (arr = HEAD(nsrr->addrs); arr != NULL; arr = NEXT(arr, link)) {
+ if (naddrs <= 0)
+ return (0);
+ *addrs++ = arr->addr;
+ naddrs--;
+ n++;
+ }
+ DPRINTF(("add_addrs: %d", n));
+ return (n);
+}
+
+static int
+get_soa(res_state statp, const char *dname, ns_class class, int opts,
+ char *zname, size_t zsize, char *mname, size_t msize,
+ rrset_ns *nsrrsp)
+{
+ char tname[NS_MAXDNAME];
+ u_char *resp = NULL;
+ int n, i, ancount, nscount;
+ ns_sect sect;
+ ns_msg msg;
+ u_int rcode;
+
+ /*
+ * Find closest enclosing SOA, even if it's for the root zone.
+ */
+
+ /* First canonicalize dname (exactly one unescaped trailing "."). */
+ if (ns_makecanon(dname, tname, sizeof tname) < 0)
+ goto cleanup;
+ dname = tname;
+
+ resp = malloc(NS_MAXMSG);
+ if (resp == NULL)
+ goto cleanup;
+
+ /* Now grovel the subdomains, hunting for an SOA answer or auth. */
+ for (;;) {
+ /* Leading or inter-label '.' are skipped here. */
+ while (*dname == '.')
+ dname++;
+
+ /* Is there an SOA? */
+ n = do_query(statp, dname, class, ns_t_soa, resp, &msg);
+ if (n < 0) {
+ DPRINTF(("get_soa: do_query('%s', %s) failed (%d)",
+ dname, p_class(class), n));
+ goto cleanup;
+ }
+ if (n > 0) {
+ DPRINTF(("get_soa: CNAME or DNAME found"));
+ sect = ns_s_max, n = 0;
+ } else {
+ rcode = ns_msg_getflag(msg, ns_f_rcode);
+ ancount = ns_msg_count(msg, ns_s_an);
+ nscount = ns_msg_count(msg, ns_s_ns);
+ if (ancount > 0 && rcode == ns_r_noerror)
+ sect = ns_s_an, n = ancount;
+ else if (nscount > 0)
+ sect = ns_s_ns, n = nscount;
+ else
+ sect = ns_s_max, n = 0;
+ }
+ for (i = 0; i < n; i++) {
+ const char *t;
+ const u_char *rdata;
+ ns_rr rr;
+
+ if (ns_parserr(&msg, sect, i, &rr) < 0) {
+ DPRINTF(("get_soa: ns_parserr(%s, %d) failed",
+ p_section(sect, ns_o_query), i));
+ goto cleanup;
+ }
+ if (ns_rr_type(rr) == ns_t_cname ||
+ ns_rr_type(rr) == ns_t_dname)
+ break;
+ if (ns_rr_type(rr) != ns_t_soa ||
+ ns_rr_class(rr) != class)
+ continue;
+ t = ns_rr_name(rr);
+ switch (sect) {
+ case ns_s_an:
+ if (ns_samedomain(dname, t) == 0) {
+ DPRINTF(
+ ("get_soa: ns_samedomain('%s', '%s') == 0",
+ dname, t)
+ );
+ errno = EPROTOTYPE;
+ goto cleanup;
+ }
+ break;
+ case ns_s_ns:
+ if (ns_samename(dname, t) == 1 ||
+ ns_samedomain(dname, t) == 0) {
+ DPRINTF(
+ ("get_soa: ns_samename() || !ns_samedomain('%s', '%s')",
+ dname, t)
+ );
+ errno = EPROTOTYPE;
+ goto cleanup;
+ }
+ break;
+ default:
+ abort();
+ }
+ if (strlen(t) + 1 > zsize) {
+ DPRINTF(("get_soa: zname(%lu) too small (%lu)",
+ (unsigned long)zsize,
+ (unsigned long)strlen(t) + 1));
+ errno = EMSGSIZE;
+ goto cleanup;
+ }
+ strcpy(zname, t);
+ rdata = ns_rr_rdata(rr);
+ if (ns_name_uncompress(resp, ns_msg_end(msg), rdata,
+ mname, msize) < 0) {
+ DPRINTF(("get_soa: ns_name_uncompress failed")
+ );
+ goto cleanup;
+ }
+ if (save_ns(statp, &msg, ns_s_ns,
+ zname, class, opts, nsrrsp) < 0) {
+ DPRINTF(("get_soa: save_ns failed"));
+ goto cleanup;
+ }
+ free(resp);
+ return (0);
+ }
+
+ /* If we're out of labels, then not even "." has an SOA! */
+ if (*dname == '\0')
+ break;
+
+ /* Find label-terminating "."; top of loop will skip it. */
+ while (*dname != '.') {
+ if (*dname == '\\')
+ if (*++dname == '\0') {
+ errno = EMSGSIZE;
+ goto cleanup;
+ }
+ dname++;
+ }
+ }
+ DPRINTF(("get_soa: out of labels"));
+ errno = EDESTADDRREQ;
+ cleanup:
+ if (resp != NULL)
+ free(resp);
+ return (-1);
+}
+
+static int
+get_ns(res_state statp, const char *zname, ns_class class, int opts,
+ rrset_ns *nsrrsp)
+{
+ u_char *resp;
+ ns_msg msg;
+ int n;
+
+ resp = malloc(NS_MAXMSG);
+ if (resp == NULL)
+ return (-1);
+
+ /* Go and get the NS RRs for this zone. */
+ n = do_query(statp, zname, class, ns_t_ns, resp, &msg);
+ if (n != 0) {
+ DPRINTF(("get_ns: do_query('%s', %s) failed (%d)",
+ zname, p_class(class), n));
+ free(resp);
+ return (-1);
+ }
+
+ /* Remember the NS RRs and associated A RRs that came back. */
+ if (save_ns(statp, &msg, ns_s_an, zname, class, opts, nsrrsp) < 0) {
+ DPRINTF(("get_ns save_ns('%s', %s) failed",
+ zname, p_class(class)));
+ free(resp);
+ return (-1);
+ }
+
+ free(resp);
+ return (0);
+}
+
+static int
+get_glue(res_state statp, ns_class class, int opts, rrset_ns *nsrrsp) {
+ rr_ns *nsrr, *nsrr_n;
+ u_char *resp;
+
+ resp = malloc(NS_MAXMSG);
+ if (resp == NULL)
+ return(-1);
+
+ /* Go and get the A RRs for each empty NS RR on our list. */
+ for (nsrr = HEAD(*nsrrsp); nsrr != NULL; nsrr = nsrr_n) {
+ ns_msg msg;
+ int n;
+
+ nsrr_n = NEXT(nsrr, link);
+
+ if ((nsrr->flags & RR_NS_HAVE_V4) == 0) {
+ n = do_query(statp, nsrr->name, class, ns_t_a,
+ resp, &msg);
+ if (n < 0) {
+ DPRINTF(
+ ("get_glue: do_query('%s', %s') failed",
+ nsrr->name, p_class(class)));
+ goto cleanup;
+ }
+ if (n > 0) {
+ DPRINTF((
+ "get_glue: do_query('%s', %s') CNAME or DNAME found",
+ nsrr->name, p_class(class)));
+ }
+ if (save_a(statp, &msg, ns_s_an, nsrr->name, class,
+ opts, nsrr) < 0) {
+ DPRINTF(("get_glue: save_r('%s', %s) failed",
+ nsrr->name, p_class(class)));
+ goto cleanup;
+ }
+ }
+
+ if ((nsrr->flags & RR_NS_HAVE_V6) == 0) {
+ n = do_query(statp, nsrr->name, class, ns_t_aaaa,
+ resp, &msg);
+ if (n < 0) {
+ DPRINTF(
+ ("get_glue: do_query('%s', %s') failed",
+ nsrr->name, p_class(class)));
+ goto cleanup;
+ }
+ if (n > 0) {
+ DPRINTF((
+ "get_glue: do_query('%s', %s') CNAME or DNAME found",
+ nsrr->name, p_class(class)));
+ }
+ if (save_a(statp, &msg, ns_s_an, nsrr->name, class,
+ opts, nsrr) < 0) {
+ DPRINTF(("get_glue: save_r('%s', %s) failed",
+ nsrr->name, p_class(class)));
+ goto cleanup;
+ }
+ }
+
+ /* If it's still empty, it's just chaff. */
+ if (EMPTY(nsrr->addrs)) {
+ DPRINTF(("get_glue: removing empty '%s' NS",
+ nsrr->name));
+ free_nsrr(nsrrsp, nsrr);
+ }
+ }
+ free(resp);
+ return (0);
+
+ cleanup:
+ free(resp);
+ return (-1);
+}
+
+static int
+save_ns(res_state statp, ns_msg *msg, ns_sect sect,
+ const char *owner, ns_class class, int opts,
+ rrset_ns *nsrrsp)
+{
+ int i;
+
+ for (i = 0; i < ns_msg_count(*msg, sect); i++) {
+ char tname[MAXDNAME];
+ const u_char *rdata;
+ rr_ns *nsrr;
+ ns_rr rr;
+
+ if (ns_parserr(msg, sect, i, &rr) < 0) {
+ DPRINTF(("save_ns: ns_parserr(%s, %d) failed",
+ p_section(sect, ns_o_query), i));
+ return (-1);
+ }
+ if (ns_rr_type(rr) != ns_t_ns ||
+ ns_rr_class(rr) != class ||
+ ns_samename(ns_rr_name(rr), owner) != 1)
+ continue;
+ nsrr = find_ns(nsrrsp, ns_rr_name(rr));
+ if (nsrr == NULL) {
+ nsrr = malloc(sizeof *nsrr);
+ if (nsrr == NULL) {
+ DPRINTF(("save_ns: malloc failed"));
+ return (-1);
+ }
+ rdata = ns_rr_rdata(rr);
+ if (ns_name_uncompress(ns_msg_base(*msg),
+ ns_msg_end(*msg), rdata,
+ tname, sizeof tname) < 0) {
+ DPRINTF(("save_ns: ns_name_uncompress failed")
+ );
+ free(nsrr);
+ return (-1);
+ }
+ nsrr->name = strdup(tname);
+ if (nsrr->name == NULL) {
+ DPRINTF(("save_ns: strdup failed"));
+ free(nsrr);
+ return (-1);
+ }
+ INIT_LINK(nsrr, link);
+ INIT_LIST(nsrr->addrs);
+ nsrr->flags = 0;
+ APPEND(*nsrrsp, nsrr, link);
+ }
+ if (save_a(statp, msg, ns_s_ar,
+ nsrr->name, class, opts, nsrr) < 0) {
+ DPRINTF(("save_ns: save_r('%s', %s) failed",
+ nsrr->name, p_class(class)));
+ return (-1);
+ }
+ }
+ return (0);
+}
+
+static int
+save_a(res_state statp, ns_msg *msg, ns_sect sect,
+ const char *owner, ns_class class, int opts,
+ rr_ns *nsrr)
+{
+ int i;
+
+ for (i = 0; i < ns_msg_count(*msg, sect); i++) {
+ ns_rr rr;
+ rr_a *arr;
+
+ if (ns_parserr(msg, sect, i, &rr) < 0) {
+ DPRINTF(("save_a: ns_parserr(%s, %d) failed",
+ p_section(sect, ns_o_query), i));
+ return (-1);
+ }
+ if ((ns_rr_type(rr) != ns_t_a &&
+ ns_rr_type(rr) != ns_t_aaaa) ||
+ ns_rr_class(rr) != class ||
+ ns_samename(ns_rr_name(rr), owner) != 1 ||
+ ns_rr_rdlen(rr) != NS_INADDRSZ)
+ continue;
+ if ((opts & RES_IPV6ONLY) != 0 && ns_rr_type(rr) != ns_t_aaaa)
+ continue;
+ if ((opts & RES_IPV4ONLY) != 0 && ns_rr_type(rr) != ns_t_a)
+ continue;
+ arr = malloc(sizeof *arr);
+ if (arr == NULL) {
+ DPRINTF(("save_a: malloc failed"));
+ return (-1);
+ }
+ INIT_LINK(arr, link);
+ memset(&arr->addr, 0, sizeof(arr->addr));
+ switch (ns_rr_type(rr)) {
+ case ns_t_a:
+ arr->addr.sin.sin_family = AF_INET;
+#ifdef HAVE_SA_LEN
+ arr->addr.sin.sin_len = sizeof(arr->addr.sin);
+#endif
+ memcpy(&arr->addr.sin.sin_addr, ns_rr_rdata(rr),
+ NS_INADDRSZ);
+ arr->addr.sin.sin_port = htons(NAMESERVER_PORT);
+ nsrr->flags |= RR_NS_HAVE_V4;
+ break;
+ case ns_t_aaaa:
+ arr->addr.sin6.sin6_family = AF_INET6;
+#ifdef HAVE_SA_LEN
+ arr->addr.sin6.sin6_len = sizeof(arr->addr.sin6);
+#endif
+ memcpy(&arr->addr.sin6.sin6_addr, ns_rr_rdata(rr), 16);
+ arr->addr.sin.sin_port = htons(NAMESERVER_PORT);
+ nsrr->flags |= RR_NS_HAVE_V6;
+ break;
+ default:
+ abort();
+ }
+ APPEND(nsrr->addrs, arr, link);
+ }
+ return (0);
+}
+
+static void
+free_nsrrset(rrset_ns *nsrrsp) {
+ rr_ns *nsrr;
+
+ while ((nsrr = HEAD(*nsrrsp)) != NULL)
+ free_nsrr(nsrrsp, nsrr);
+}
+
+static void
+free_nsrr(rrset_ns *nsrrsp, rr_ns *nsrr) {
+ rr_a *arr;
+ char *tmp;
+
+ while ((arr = HEAD(nsrr->addrs)) != NULL) {
+ UNLINK(nsrr->addrs, arr, link);
+ free(arr);
+ }
+ DE_CONST(nsrr->name, tmp);
+ free(tmp);
+ UNLINK(*nsrrsp, nsrr, link);
+ free(nsrr);
+}
+
+static rr_ns *
+find_ns(rrset_ns *nsrrsp, const char *dname) {
+ rr_ns *nsrr;
+
+ for (nsrr = HEAD(*nsrrsp); nsrr != NULL; nsrr = NEXT(nsrr, link))
+ if (ns_samename(nsrr->name, dname) == 1)
+ return (nsrr);
+ return (NULL);
+}
+
+static int
+do_query(res_state statp, const char *dname, ns_class class, ns_type qtype,
+ u_char *resp, ns_msg *msg)
+{
+ u_char req[NS_PACKETSZ];
+ int i, n;
+
+ n = res_nmkquery(statp, ns_o_query, dname, class, qtype,
+ NULL, 0, NULL, req, NS_PACKETSZ);
+ if (n < 0) {
+ DPRINTF(("do_query: res_nmkquery failed"));
+ return (-1);
+ }
+ n = res_nsend(statp, req, n, resp, NS_MAXMSG);
+ if (n < 0) {
+ DPRINTF(("do_query: res_nsend failed"));
+ return (-1);
+ }
+ if (n == 0) {
+ DPRINTF(("do_query: res_nsend returned 0"));
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ if (ns_initparse(resp, n, msg) < 0) {
+ DPRINTF(("do_query: ns_initparse failed"));
+ return (-1);
+ }
+ n = 0;
+ for (i = 0; i < ns_msg_count(*msg, ns_s_an); i++) {
+ ns_rr rr;
+
+ if (ns_parserr(msg, ns_s_an, i, &rr) < 0) {
+ DPRINTF(("do_query: ns_parserr failed"));
+ return (-1);
+ }
+ n += (ns_rr_class(rr) == class &&
+ (ns_rr_type(rr) == ns_t_cname ||
+ ns_rr_type(rr) == ns_t_dname));
+ }
+ return (n);
+}
+
+static void
+res_dprintf(const char *fmt, ...) {
+ va_list ap;
+
+ va_start(ap, fmt);
+ fputs(";; res_findzonecut: ", stderr);
+ vfprintf(stderr, fmt, ap);
+ fputc('\n', stderr);
+ va_end(ap);
+}
+
+/*! \file */
diff --git a/lib/libc/resolv/res_init.c b/lib/libc/resolv/res_init.c
new file mode 100644
index 000000000000..732fb1e6646e
--- /dev/null
+++ b/lib/libc/resolv/res_init.c
@@ -0,0 +1,948 @@
+/*
+ * Copyright (c) 1985, 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)res_init.c 8.1 (Berkeley) 6/7/93";
+static const char rcsid[] = "$Id: res_init.c,v 1.26 2008/12/11 09:59:00 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "port_before.h"
+
+#include "namespace.h"
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <netdb.h>
+
+#ifndef HAVE_MD5
+# include "../dst/md5.h"
+#else
+# ifdef SOLARIS2
+# include <sys/md5.h>
+# elif _LIBC
+# include <md5.h>
+# endif
+#endif
+#ifndef _MD5_H_
+# define _MD5_H_ 1 /*%< make sure we do not include rsaref md5.h file */
+#endif
+
+#include "un-namespace.h"
+
+#include "port_after.h"
+
+/* ensure that sockaddr_in6 and IN6ADDR_ANY_INIT are declared / defined */
+#include <resolv.h>
+
+#include "res_private.h"
+
+/*% Options. Should all be left alone. */
+#define RESOLVSORT
+#ifndef DEBUG
+#define DEBUG
+#endif
+
+#ifdef SOLARIS2
+#include <sys/systeminfo.h>
+#endif
+
+static void res_setoptions(res_state, const char *, const char *);
+
+#ifdef RESOLVSORT
+static const char sort_mask[] = "/&";
+#define ISSORTMASK(ch) (strchr(sort_mask, ch) != NULL)
+static u_int32_t net_mask(struct in_addr);
+#endif
+
+#if !defined(isascii) /*%< XXX - could be a function */
+# define isascii(c) (!(c & 0200))
+#endif
+
+/*
+ * Resolver state default settings.
+ */
+
+/*%
+ * Set up default settings. If the configuration file exist, the values
+ * there will have precedence. Otherwise, the server address is set to
+ * INADDR_ANY and the default domain name comes from the gethostname().
+ *
+ * An interim version of this code (BIND 4.9, pre-4.4BSD) used 127.0.0.1
+ * rather than INADDR_ANY ("0.0.0.0") as the default name server address
+ * since it was noted that INADDR_ANY actually meant ``the first interface
+ * you "ifconfig"'d at boot time'' and if this was a SLIP or PPP interface,
+ * it had to be "up" in order for you to reach your own name server. It
+ * was later decided that since the recommended practice is to always
+ * install local static routes through 127.0.0.1 for all your network
+ * interfaces, that we could solve this problem without a code change.
+ *
+ * The configuration file should always be used, since it is the only way
+ * to specify a default domain. If you are running a server on your local
+ * machine, you should say "nameserver 0.0.0.0" or "nameserver 127.0.0.1"
+ * in the configuration file.
+ *
+ * Return 0 if completes successfully, -1 on error
+ */
+int
+res_ninit(res_state statp) {
+ extern int __res_vinit(res_state, int);
+
+ return (__res_vinit(statp, 0));
+}
+
+/*% This function has to be reachable by res_data.c but not publicly. */
+int
+__res_vinit(res_state statp, int preinit) {
+ FILE *fp;
+ char *cp, **pp;
+ int n;
+ char buf[BUFSIZ];
+ int nserv = 0; /*%< number of nameserver records read from file */
+ int haveenv = 0;
+ int havesearch = 0;
+#ifdef RESOLVSORT
+ int nsort = 0;
+ char *net;
+#endif
+ int dots;
+ union res_sockaddr_union u[2];
+ int maxns = MAXNS;
+
+ RES_SET_H_ERRNO(statp, 0);
+ if (statp->_u._ext.ext != NULL)
+ res_ndestroy(statp);
+
+ if (!preinit) {
+ statp->retrans = RES_TIMEOUT;
+ statp->retry = RES_DFLRETRY;
+ statp->options = RES_DEFAULT;
+ }
+
+ statp->_rnd = malloc(16);
+ res_rndinit(statp);
+ statp->id = res_nrandomid(statp);
+
+ memset(u, 0, sizeof(u));
+#ifdef USELOOPBACK
+ u[nserv].sin.sin_addr = inet_makeaddr(IN_LOOPBACKNET, 1);
+#else
+ u[nserv].sin.sin_addr.s_addr = INADDR_ANY;
+#endif
+ u[nserv].sin.sin_family = AF_INET;
+ u[nserv].sin.sin_port = htons(NAMESERVER_PORT);
+#ifdef HAVE_SA_LEN
+ u[nserv].sin.sin_len = sizeof(struct sockaddr_in);
+#endif
+ nserv++;
+#ifdef HAS_INET6_STRUCTS
+#ifdef USELOOPBACK
+ u[nserv].sin6.sin6_addr = in6addr_loopback;
+#else
+ u[nserv].sin6.sin6_addr = in6addr_any;
+#endif
+ u[nserv].sin6.sin6_family = AF_INET6;
+ u[nserv].sin6.sin6_port = htons(NAMESERVER_PORT);
+#ifdef HAVE_SA_LEN
+ u[nserv].sin6.sin6_len = sizeof(struct sockaddr_in6);
+#endif
+ nserv++;
+#endif
+ statp->nscount = 0;
+ statp->ndots = 1;
+ statp->pfcode = 0;
+ statp->_vcsock = -1;
+ statp->_flags = 0;
+ statp->qhook = NULL;
+ statp->rhook = NULL;
+ statp->_u._ext.nscount = 0;
+ statp->_u._ext.ext = malloc(sizeof(*statp->_u._ext.ext));
+ if (statp->_u._ext.ext != NULL) {
+ memset(statp->_u._ext.ext, 0, sizeof(*statp->_u._ext.ext));
+ statp->_u._ext.ext->nsaddrs[0].sin = statp->nsaddr;
+ strcpy(statp->_u._ext.ext->nsuffix, "ip6.arpa");
+ strcpy(statp->_u._ext.ext->nsuffix2, "ip6.int");
+ statp->_u._ext.ext->reload_period = 2;
+ } else {
+ /*
+ * Historically res_init() rarely, if at all, failed.
+ * Examples and applications exist which do not check
+ * our return code. Furthermore several applications
+ * simply call us to get the systems domainname. So
+ * rather then immediately fail here we store the
+ * failure, which is returned later, in h_errno. And
+ * prevent the collection of 'nameserver' information
+ * by setting maxns to 0. Thus applications that fail
+ * to check our return code wont be able to make
+ * queries anyhow.
+ */
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ maxns = 0;
+ }
+#ifdef RESOLVSORT
+ statp->nsort = 0;
+#endif
+ res_setservers(statp, u, nserv);
+
+#ifdef SOLARIS2
+ /*
+ * The old libresolv derived the defaultdomain from NIS/NIS+.
+ * We want to keep this behaviour
+ */
+ {
+ char buf[sizeof(statp->defdname)], *cp;
+ int ret;
+
+ if ((ret = sysinfo(SI_SRPC_DOMAIN, buf, sizeof(buf))) > 0 &&
+ (unsigned int)ret <= sizeof(buf)) {
+ if (buf[0] == '+')
+ buf[0] = '.';
+ cp = strchr(buf, '.');
+ cp = (cp == NULL) ? buf : (cp + 1);
+ strncpy(statp->defdname, cp,
+ sizeof(statp->defdname) - 1);
+ statp->defdname[sizeof(statp->defdname) - 1] = '\0';
+ }
+ }
+#endif /* SOLARIS2 */
+
+ /* Allow user to override the local domain definition */
+ if (issetugid() == 0 && (cp = getenv("LOCALDOMAIN")) != NULL) {
+ (void)strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
+ statp->defdname[sizeof(statp->defdname) - 1] = '\0';
+ haveenv++;
+
+ /*
+ * Set search list to be blank-separated strings
+ * from rest of env value. Permits users of LOCALDOMAIN
+ * to still have a search list, and anyone to set the
+ * one that they want to use as an individual (even more
+ * important now that the rfc1535 stuff restricts searches)
+ */
+ cp = statp->defdname;
+ pp = statp->dnsrch;
+ *pp++ = cp;
+ for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) {
+ if (*cp == '\n') /*%< silly backwards compat */
+ break;
+ else if (*cp == ' ' || *cp == '\t') {
+ *cp = 0;
+ n = 1;
+ } else if (n) {
+ *pp++ = cp;
+ n = 0;
+ havesearch = 1;
+ }
+ }
+ /* null terminate last domain if there are excess */
+ while (*cp != '\0' && *cp != ' ' && *cp != '\t' && *cp != '\n')
+ cp++;
+ *cp = '\0';
+ *pp++ = NULL;
+ }
+
+#define MATCH(line, name) \
+ (!strncmp(line, name, sizeof(name) - 1) && \
+ (line[sizeof(name) - 1] == ' ' || \
+ line[sizeof(name) - 1] == '\t'))
+
+ nserv = 0;
+ if ((fp = fopen(_PATH_RESCONF, "re")) != NULL) {
+ struct stat sb;
+ struct timespec now;
+
+ if (statp->_u._ext.ext != NULL) {
+ if (_fstat(fileno(fp), &sb) == 0) {
+ statp->_u._ext.ext->conf_mtim = sb.st_mtim;
+ if (clock_gettime(CLOCK_MONOTONIC_FAST, &now) == 0) {
+ statp->_u._ext.ext->conf_stat = now.tv_sec;
+ }
+ }
+ }
+
+ /* read the config file */
+ while (fgets(buf, sizeof(buf), fp) != NULL) {
+ /* skip comments */
+ if (*buf == ';' || *buf == '#')
+ continue;
+ /* read default domain name */
+ if (MATCH(buf, "domain")) {
+ if (haveenv) /*%< skip if have from environ */
+ continue;
+ cp = buf + sizeof("domain") - 1;
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ if ((*cp == '\0') || (*cp == '\n'))
+ continue;
+ strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
+ statp->defdname[sizeof(statp->defdname) - 1] = '\0';
+ if ((cp = strpbrk(statp->defdname, " \t\n")) != NULL)
+ *cp = '\0';
+ havesearch = 0;
+ continue;
+ }
+ /* set search list */
+ if (MATCH(buf, "search")) {
+ if (haveenv) /*%< skip if have from environ */
+ continue;
+ cp = buf + sizeof("search") - 1;
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ if ((*cp == '\0') || (*cp == '\n'))
+ continue;
+ strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
+ statp->defdname[sizeof(statp->defdname) - 1] = '\0';
+ if ((cp = strchr(statp->defdname, '\n')) != NULL)
+ *cp = '\0';
+ /*
+ * Set search list to be blank-separated strings
+ * on rest of line.
+ */
+ cp = statp->defdname;
+ pp = statp->dnsrch;
+ *pp++ = cp;
+ for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) {
+ if (*cp == ' ' || *cp == '\t') {
+ *cp = 0;
+ n = 1;
+ } else if (n) {
+ *pp++ = cp;
+ n = 0;
+ }
+ }
+ /* null terminate last domain if there are excess */
+ while (*cp != '\0' && *cp != ' ' && *cp != '\t')
+ cp++;
+ *cp = '\0';
+ *pp++ = NULL;
+ havesearch = 1;
+ continue;
+ }
+ /* read nameservers to query */
+ if (MATCH(buf, "nameserver") && nserv < maxns) {
+ struct addrinfo hints, *ai;
+ char sbuf[NI_MAXSERV];
+ const size_t minsiz =
+ sizeof(statp->_u._ext.ext->nsaddrs[0]);
+
+ cp = buf + sizeof("nameserver") - 1;
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ cp[strcspn(cp, ";# \t\n")] = '\0';
+ if ((*cp != '\0') && (*cp != '\n')) {
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_DGRAM; /*dummy*/
+ hints.ai_flags = AI_NUMERICHOST;
+ sprintf(sbuf, "%u", NAMESERVER_PORT);
+ if (getaddrinfo(cp, sbuf, &hints, &ai) == 0) {
+ if (ai->ai_addrlen <= minsiz) {
+ if (statp->_u._ext.ext != NULL) {
+ memcpy(&statp->_u._ext.ext->nsaddrs[nserv],
+ ai->ai_addr, ai->ai_addrlen);
+ }
+ if (ai->ai_addrlen <=
+ sizeof(statp->nsaddr_list[nserv])) {
+ memcpy(&statp->nsaddr_list[nserv],
+ ai->ai_addr, ai->ai_addrlen);
+ } else
+ statp->nsaddr_list[nserv].sin_family = 0;
+ nserv++;
+ }
+ freeaddrinfo(ai);
+ }
+ }
+ continue;
+ }
+#ifdef RESOLVSORT
+ if (MATCH(buf, "sortlist")) {
+ struct in_addr a;
+ struct in6_addr a6;
+ int m, i;
+ u_char *u;
+ struct __res_state_ext *ext = statp->_u._ext.ext;
+
+ cp = buf + sizeof("sortlist") - 1;
+ while (nsort < MAXRESOLVSORT) {
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ if (*cp == '\0' || *cp == '\n' || *cp == ';')
+ break;
+ net = cp;
+ while (*cp && !ISSORTMASK(*cp) && *cp != ';' &&
+ isascii(*cp) && !isspace((unsigned char)*cp))
+ cp++;
+ n = *cp;
+ *cp = 0;
+ if (inet_aton(net, &a)) {
+ statp->sort_list[nsort].addr = a;
+ if (ISSORTMASK(n)) {
+ *cp++ = n;
+ net = cp;
+ while (*cp && *cp != ';' &&
+ isascii(*cp) &&
+ !isspace((unsigned char)*cp))
+ cp++;
+ n = *cp;
+ *cp = 0;
+ if (inet_aton(net, &a)) {
+ statp->sort_list[nsort].mask = a.s_addr;
+ } else {
+ statp->sort_list[nsort].mask =
+ net_mask(statp->sort_list[nsort].addr);
+ }
+ } else {
+ statp->sort_list[nsort].mask =
+ net_mask(statp->sort_list[nsort].addr);
+ }
+ ext->sort_list[nsort].af = AF_INET;
+ ext->sort_list[nsort].addr.ina =
+ statp->sort_list[nsort].addr;
+ ext->sort_list[nsort].mask.ina.s_addr =
+ statp->sort_list[nsort].mask;
+ nsort++;
+ }
+ else if (inet_pton(AF_INET6, net, &a6) == 1) {
+
+ ext->sort_list[nsort].af = AF_INET6;
+ ext->sort_list[nsort].addr.in6a = a6;
+ u = (u_char *)&ext->sort_list[nsort].mask.in6a;
+ *cp++ = n;
+ net = cp;
+ while (*cp && *cp != ';' &&
+ isascii(*cp) && !isspace(*cp))
+ cp++;
+ m = n;
+ n = *cp;
+ *cp = 0;
+ switch (m) {
+ case '/':
+ m = atoi(net);
+ break;
+ case '&':
+ if (inet_pton(AF_INET6, net, u) == 1) {
+ m = -1;
+ break;
+ }
+ /*FALLTHROUGH*/
+ default:
+ m = sizeof(struct in6_addr) * CHAR_BIT;
+ break;
+ }
+ if (m >= 0) {
+ for (i = 0; i < sizeof(struct in6_addr); i++) {
+ if (m <= 0) {
+ *u = 0;
+ } else {
+ m -= CHAR_BIT;
+ *u = (u_char)~0;
+ if (m < 0)
+ *u <<= -m;
+ }
+ u++;
+ }
+ }
+ statp->sort_list[nsort].addr.s_addr =
+ (u_int32_t)0xffffffff;
+ statp->sort_list[nsort].mask =
+ (u_int32_t)0xffffffff;
+ nsort++;
+ }
+ *cp = n;
+ }
+ continue;
+ }
+#endif
+ if (MATCH(buf, "options")) {
+ res_setoptions(statp, buf + sizeof("options") - 1, "conf");
+ continue;
+ }
+ }
+ if (nserv > 0)
+ statp->nscount = nserv;
+#ifdef RESOLVSORT
+ statp->nsort = nsort;
+#endif
+ (void) fclose(fp);
+ }
+/*
+ * Last chance to get a nameserver. This should not normally
+ * be necessary
+ */
+#ifdef NO_RESOLV_CONF
+ if(nserv == 0)
+ nserv = get_nameservers(statp);
+#endif
+
+ if (statp->defdname[0] == 0 &&
+ gethostname(buf, sizeof(statp->defdname) - 1) == 0 &&
+ (cp = strchr(buf, '.')) != NULL)
+ strcpy(statp->defdname, cp + 1);
+
+ /* find components of local domain that might be searched */
+ if (havesearch == 0) {
+ pp = statp->dnsrch;
+ *pp++ = statp->defdname;
+ *pp = NULL;
+
+ dots = 0;
+ for (cp = statp->defdname; *cp; cp++)
+ dots += (*cp == '.');
+
+ cp = statp->defdname;
+ while (pp < statp->dnsrch + MAXDFLSRCH) {
+ if (dots < LOCALDOMAINPARTS)
+ break;
+ cp = strchr(cp, '.') + 1; /*%< we know there is one */
+ *pp++ = cp;
+ dots--;
+ }
+ *pp = NULL;
+#ifdef DEBUG
+ if (statp->options & RES_DEBUG) {
+ printf(";; res_init()... default dnsrch list:\n");
+ for (pp = statp->dnsrch; *pp; pp++)
+ printf(";;\t%s\n", *pp);
+ printf(";;\t..END..\n");
+ }
+#endif
+ }
+
+ if (issetugid())
+ statp->options |= RES_NOALIASES;
+ else if ((cp = getenv("RES_OPTIONS")) != NULL)
+ res_setoptions(statp, cp, "env");
+ statp->options |= RES_INIT;
+ return (statp->res_h_errno);
+}
+
+static void
+res_setoptions(res_state statp, const char *options, const char *source)
+{
+ const char *cp = options;
+ int i;
+ struct __res_state_ext *ext = statp->_u._ext.ext;
+
+#ifdef DEBUG
+ if (statp->options & RES_DEBUG)
+ printf(";; res_setoptions(\"%s\", \"%s\")...\n",
+ options, source);
+#endif
+ while (*cp) {
+ /* skip leading and inner runs of spaces */
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ /* search for and process individual options */
+ if (!strncmp(cp, "ndots:", sizeof("ndots:") - 1)) {
+ i = atoi(cp + sizeof("ndots:") - 1);
+ if (i <= RES_MAXNDOTS)
+ statp->ndots = i;
+ else
+ statp->ndots = RES_MAXNDOTS;
+#ifdef DEBUG
+ if (statp->options & RES_DEBUG)
+ printf(";;\tndots=%d\n", statp->ndots);
+#endif
+ } else if (!strncmp(cp, "timeout:", sizeof("timeout:") - 1)) {
+ i = atoi(cp + sizeof("timeout:") - 1);
+ if (i <= RES_MAXRETRANS)
+ statp->retrans = i;
+ else
+ statp->retrans = RES_MAXRETRANS;
+#ifdef DEBUG
+ if (statp->options & RES_DEBUG)
+ printf(";;\ttimeout=%d\n", statp->retrans);
+#endif
+#ifdef SOLARIS2
+ } else if (!strncmp(cp, "retrans:", sizeof("retrans:") - 1)) {
+ /*
+ * For backward compatibility, 'retrans' is
+ * supported as an alias for 'timeout', though
+ * without an imposed maximum.
+ */
+ statp->retrans = atoi(cp + sizeof("retrans:") - 1);
+ } else if (!strncmp(cp, "retry:", sizeof("retry:") - 1)){
+ /*
+ * For backward compatibility, 'retry' is
+ * supported as an alias for 'attempts', though
+ * without an imposed maximum.
+ */
+ statp->retry = atoi(cp + sizeof("retry:") - 1);
+#endif /* SOLARIS2 */
+ } else if (!strncmp(cp, "attempts:", sizeof("attempts:") - 1)){
+ i = atoi(cp + sizeof("attempts:") - 1);
+ if (i <= RES_MAXRETRY)
+ statp->retry = i;
+ else
+ statp->retry = RES_MAXRETRY;
+#ifdef DEBUG
+ if (statp->options & RES_DEBUG)
+ printf(";;\tattempts=%d\n", statp->retry);
+#endif
+ } else if (!strncmp(cp, "debug", sizeof("debug") - 1)) {
+#ifdef DEBUG
+ if (!(statp->options & RES_DEBUG)) {
+ printf(";; res_setoptions(\"%s\", \"%s\")..\n",
+ options, source);
+ statp->options |= RES_DEBUG;
+ }
+ printf(";;\tdebug\n");
+#endif
+ } else if (!strncmp(cp, "no_tld_query",
+ sizeof("no_tld_query") - 1) ||
+ !strncmp(cp, "no-tld-query",
+ sizeof("no-tld-query") - 1)) {
+ statp->options |= RES_NOTLDQUERY;
+ } else if (!strncmp(cp, "inet6", sizeof("inet6") - 1)) {
+ statp->options |= RES_USE_INET6;
+ } else if (!strncmp(cp, "insecure1", sizeof("insecure1") - 1)) {
+ statp->options |= RES_INSECURE1;
+ } else if (!strncmp(cp, "insecure2", sizeof("insecure2") - 1)) {
+ statp->options |= RES_INSECURE2;
+ } else if (!strncmp(cp, "rotate", sizeof("rotate") - 1)) {
+ statp->options |= RES_ROTATE;
+ } else if (!strncmp(cp, "no-check-names",
+ sizeof("no-check-names") - 1)) {
+ statp->options |= RES_NOCHECKNAME;
+ } else if (!strncmp(cp, "reload-period:",
+ sizeof("reload-period:") - 1)) {
+ if (ext != NULL) {
+ ext->reload_period = (u_short)
+ atoi(cp + sizeof("reload-period:") - 1);
+ }
+ }
+#ifdef RES_USE_EDNS0
+ else if (!strncmp(cp, "edns0", sizeof("edns0") - 1)) {
+ statp->options |= RES_USE_EDNS0;
+ }
+#endif
+#ifndef _LIBC
+ else if (!strncmp(cp, "dname", sizeof("dname") - 1)) {
+ statp->options |= RES_USE_DNAME;
+ }
+ else if (!strncmp(cp, "nibble:", sizeof("nibble:") - 1)) {
+ if (ext == NULL)
+ goto skip;
+ cp += sizeof("nibble:") - 1;
+ i = MIN(strcspn(cp, " \t"), sizeof(ext->nsuffix) - 1);
+ strncpy(ext->nsuffix, cp, i);
+ ext->nsuffix[i] = '\0';
+ }
+ else if (!strncmp(cp, "nibble2:", sizeof("nibble2:") - 1)) {
+ if (ext == NULL)
+ goto skip;
+ cp += sizeof("nibble2:") - 1;
+ i = MIN(strcspn(cp, " \t"), sizeof(ext->nsuffix2) - 1);
+ strncpy(ext->nsuffix2, cp, i);
+ ext->nsuffix2[i] = '\0';
+ }
+ else if (!strncmp(cp, "v6revmode:", sizeof("v6revmode:") - 1)) {
+ cp += sizeof("v6revmode:") - 1;
+ /* "nibble" and "bitstring" used to be valid */
+ if (!strncmp(cp, "single", sizeof("single") - 1)) {
+ statp->options |= RES_NO_NIBBLE2;
+ } else if (!strncmp(cp, "both", sizeof("both") - 1)) {
+ statp->options &=
+ ~RES_NO_NIBBLE2;
+ }
+ }
+#endif
+ else {
+ /* XXX - print a warning here? */
+ }
+#ifndef _LIBC
+ skip:
+#endif
+ /* skip to next run of spaces */
+ while (*cp && *cp != ' ' && *cp != '\t')
+ cp++;
+ }
+}
+
+#ifdef RESOLVSORT
+/* XXX - should really support CIDR which means explicit masks always. */
+static u_int32_t
+net_mask(struct in_addr in) /*!< XXX - should really use system's version of this */
+{
+ u_int32_t i = ntohl(in.s_addr);
+
+ if (IN_CLASSA(i))
+ return (htonl(IN_CLASSA_NET));
+ else if (IN_CLASSB(i))
+ return (htonl(IN_CLASSB_NET));
+ return (htonl(IN_CLASSC_NET));
+}
+#endif
+
+static u_char srnd[16];
+
+void
+res_rndinit(res_state statp)
+{
+ struct timeval now;
+ u_int32_t u32;
+ u_int16_t u16;
+ u_char *rnd = statp->_rnd == NULL ? srnd : statp->_rnd;
+
+ gettimeofday(&now, NULL);
+ u32 = now.tv_sec;
+ memcpy(rnd, &u32, 4);
+ u32 = now.tv_usec;
+ memcpy(rnd + 4, &u32, 4);
+ u32 += now.tv_sec;
+ memcpy(rnd + 8, &u32, 4);
+ u16 = getpid();
+ memcpy(rnd + 12, &u16, 2);
+}
+
+u_int
+res_nrandomid(res_state statp) {
+ struct timeval now;
+ u_int16_t u16;
+ MD5_CTX ctx;
+ u_char *rnd = statp->_rnd == NULL ? srnd : statp->_rnd;
+
+ gettimeofday(&now, NULL);
+ u16 = (u_int16_t) (now.tv_sec ^ now.tv_usec);
+ memcpy(rnd + 14, &u16, 2);
+#ifndef HAVE_MD5
+ MD5_Init(&ctx);
+ MD5_Update(&ctx, rnd, 16);
+ MD5_Final(rnd, &ctx);
+#else
+ MD5Init(&ctx);
+ MD5Update(&ctx, rnd, 16);
+ MD5Final(rnd, &ctx);
+#endif
+ memcpy(&u16, rnd + 14, 2);
+ return ((u_int) u16);
+}
+
+/*%
+ * This routine is for closing the socket if a virtual circuit is used and
+ * the program wants to close it. This provides support for endhostent()
+ * which expects to close the socket.
+ *
+ * This routine is not expected to be user visible.
+ */
+void
+res_nclose(res_state statp) {
+ int ns;
+
+ if (statp->_vcsock >= 0) {
+ (void) _close(statp->_vcsock);
+ statp->_vcsock = -1;
+ statp->_flags &= ~(RES_F_VC | RES_F_CONN);
+ }
+ for (ns = 0; ns < statp->_u._ext.nscount; ns++) {
+ if (statp->_u._ext.nssocks[ns] != -1) {
+ (void) _close(statp->_u._ext.nssocks[ns]);
+ statp->_u._ext.nssocks[ns] = -1;
+ }
+ }
+}
+
+void
+res_ndestroy(res_state statp) {
+ res_nclose(statp);
+ if (statp->_u._ext.ext != NULL) {
+ free(statp->_u._ext.ext);
+ statp->_u._ext.ext = NULL;
+ }
+ if (statp->_rnd != NULL) {
+ free(statp->_rnd);
+ statp->_rnd = NULL;
+ }
+ statp->options &= ~RES_INIT;
+}
+
+#ifndef _LIBC
+const char *
+res_get_nibblesuffix(res_state statp) {
+ if (statp->_u._ext.ext)
+ return (statp->_u._ext.ext->nsuffix);
+ return ("ip6.arpa");
+}
+
+const char *
+res_get_nibblesuffix2(res_state statp) {
+ if (statp->_u._ext.ext)
+ return (statp->_u._ext.ext->nsuffix2);
+ return ("ip6.int");
+}
+#endif
+
+void
+res_setservers(res_state statp, const union res_sockaddr_union *set, int cnt) {
+ int i, nserv;
+ size_t size;
+
+ /* close open servers */
+ res_nclose(statp);
+
+ /* cause rtt times to be forgotten */
+ statp->_u._ext.nscount = 0;
+
+ nserv = 0;
+ for (i = 0; i < cnt && nserv < MAXNS; i++) {
+ switch (set->sin.sin_family) {
+ case AF_INET:
+ size = sizeof(set->sin);
+ if (statp->_u._ext.ext)
+ memcpy(&statp->_u._ext.ext->nsaddrs[nserv],
+ &set->sin, size);
+ if (size <= sizeof(statp->nsaddr_list[nserv]))
+ memcpy(&statp->nsaddr_list[nserv],
+ &set->sin, size);
+ else
+ statp->nsaddr_list[nserv].sin_family = 0;
+ nserv++;
+ break;
+
+#ifdef HAS_INET6_STRUCTS
+ case AF_INET6:
+ size = sizeof(set->sin6);
+ if (statp->_u._ext.ext)
+ memcpy(&statp->_u._ext.ext->nsaddrs[nserv],
+ &set->sin6, size);
+ if (size <= sizeof(statp->nsaddr_list[nserv]))
+ memcpy(&statp->nsaddr_list[nserv],
+ &set->sin6, size);
+ else
+ statp->nsaddr_list[nserv].sin_family = 0;
+ nserv++;
+ break;
+#endif
+
+ default:
+ break;
+ }
+ set++;
+ }
+ statp->nscount = nserv;
+
+}
+
+int
+res_getservers(res_state statp, union res_sockaddr_union *set, int cnt) {
+ int i;
+ size_t size;
+ u_int16_t family;
+
+ for (i = 0; i < statp->nscount && i < cnt; i++) {
+ if (statp->_u._ext.ext)
+ family = statp->_u._ext.ext->nsaddrs[i].sin.sin_family;
+ else
+ family = statp->nsaddr_list[i].sin_family;
+
+ switch (family) {
+ case AF_INET:
+ size = sizeof(set->sin);
+ if (statp->_u._ext.ext)
+ memcpy(&set->sin,
+ &statp->_u._ext.ext->nsaddrs[i],
+ size);
+ else
+ memcpy(&set->sin, &statp->nsaddr_list[i],
+ size);
+ break;
+
+#ifdef HAS_INET6_STRUCTS
+ case AF_INET6:
+ size = sizeof(set->sin6);
+ if (statp->_u._ext.ext)
+ memcpy(&set->sin6,
+ &statp->_u._ext.ext->nsaddrs[i],
+ size);
+ else
+ memcpy(&set->sin6, &statp->nsaddr_list[i],
+ size);
+ break;
+#endif
+
+ default:
+ set->sin.sin_family = 0;
+ break;
+ }
+ set++;
+ }
+ return (statp->nscount);
+}
+
+/*! \file */
diff --git a/lib/libc/resolv/res_mkquery.c b/lib/libc/resolv/res_mkquery.c
new file mode 100644
index 000000000000..43e46c19a663
--- /dev/null
+++ b/lib/libc/resolv/res_mkquery.c
@@ -0,0 +1,305 @@
+/*
+ * Portions Copyright (C) 2004, 2005, 2008 Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (C) 1996, 1997, 1988, 1999, 2001, 2003 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Copyright (c) 1985, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)res_mkquery.c 8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: res_mkquery.c,v 1.10 2008/12/11 09:59:00 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "port_before.h"
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <string.h>
+#include "port_after.h"
+
+/* Options. Leave them on. */
+#ifndef DEBUG
+#define DEBUG
+#endif
+
+extern const char *_res_opcodes[];
+
+/*%
+ * Form all types of queries.
+ * Returns the size of the result or -1.
+ */
+int
+res_nmkquery(res_state statp,
+ int op, /*!< opcode of query */
+ const char *dname, /*!< domain name */
+ int class, int type, /*!< class and type of query */
+ const u_char *data, /*!< resource record data */
+ int datalen, /*!< length of data */
+ const u_char *newrr_in, /*!< new rr for modify or append */
+ u_char *buf, /*!< buffer to put query */
+ int buflen) /*!< size of buffer */
+{
+ HEADER *hp;
+ u_char *cp, *ep;
+ int n;
+ u_char *dnptrs[20], **dpp, **lastdnptr;
+
+ UNUSED(newrr_in);
+
+#ifdef DEBUG
+ if (statp->options & RES_DEBUG)
+ printf(";; res_nmkquery(%s, %s, %s, %s)\n",
+ _res_opcodes[op], dname, p_class(class), p_type(type));
+#endif
+ /*
+ * Initialize header fields.
+ */
+ if ((buf == NULL) || (buflen < HFIXEDSZ))
+ return (-1);
+ memset(buf, 0, HFIXEDSZ);
+ hp = (HEADER *) buf;
+ statp->id = res_nrandomid(statp);
+ hp->id = htons(statp->id);
+ hp->opcode = op;
+ hp->rd = (statp->options & RES_RECURSE) != 0U;
+ hp->rcode = NOERROR;
+ cp = buf + HFIXEDSZ;
+ ep = buf + buflen;
+ dpp = dnptrs;
+ *dpp++ = buf;
+ *dpp++ = NULL;
+ lastdnptr = dnptrs + nitems(dnptrs);
+ /*
+ * perform opcode specific processing
+ */
+ switch (op) {
+ case QUERY: /*FALLTHROUGH*/
+ case NS_NOTIFY_OP:
+ if (ep - cp < QFIXEDSZ)
+ return (-1);
+ if ((n = dn_comp(dname, cp, ep - cp - QFIXEDSZ, dnptrs,
+ lastdnptr)) < 0)
+ return (-1);
+ cp += n;
+ ns_put16(type, cp);
+ cp += INT16SZ;
+ ns_put16(class, cp);
+ cp += INT16SZ;
+ hp->qdcount = htons(1);
+ if (op == QUERY || data == NULL)
+ break;
+ /*
+ * Make an additional record for completion domain.
+ */
+ if ((ep - cp) < RRFIXEDSZ)
+ return (-1);
+ n = dn_comp((const char *)data, cp, ep - cp - RRFIXEDSZ,
+ dnptrs, lastdnptr);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ ns_put16(T_NULL, cp);
+ cp += INT16SZ;
+ ns_put16(class, cp);
+ cp += INT16SZ;
+ ns_put32(0, cp);
+ cp += INT32SZ;
+ ns_put16(0, cp);
+ cp += INT16SZ;
+ hp->arcount = htons(1);
+ break;
+
+ case IQUERY:
+ /*
+ * Initialize answer section
+ */
+ if (ep - cp < 1 + RRFIXEDSZ + datalen)
+ return (-1);
+ *cp++ = '\0'; /*%< no domain name */
+ ns_put16(type, cp);
+ cp += INT16SZ;
+ ns_put16(class, cp);
+ cp += INT16SZ;
+ ns_put32(0, cp);
+ cp += INT32SZ;
+ ns_put16(datalen, cp);
+ cp += INT16SZ;
+ if (datalen) {
+ memcpy(cp, data, datalen);
+ cp += datalen;
+ }
+ hp->ancount = htons(1);
+ break;
+
+ default:
+ return (-1);
+ }
+ return (cp - buf);
+}
+
+#ifdef RES_USE_EDNS0
+/* attach OPT pseudo-RR, as documented in RFC2671 (EDNS0). */
+
+int
+res_nopt(res_state statp,
+ int n0, /*%< current offset in buffer */
+ u_char *buf, /*%< buffer to put query */
+ int buflen, /*%< size of buffer */
+ int anslen) /*%< UDP answer buffer size */
+{
+ HEADER *hp;
+ u_char *cp, *ep;
+ u_int16_t flags = 0;
+
+#ifdef DEBUG
+ if ((statp->options & RES_DEBUG) != 0U)
+ printf(";; res_nopt()\n");
+#endif
+
+ hp = (HEADER *) buf;
+ cp = buf + n0;
+ ep = buf + buflen;
+
+ if ((ep - cp) < 1 + RRFIXEDSZ)
+ return (-1);
+
+ *cp++ = 0; /*%< "." */
+ ns_put16(ns_t_opt, cp); /*%< TYPE */
+ cp += INT16SZ;
+ if (anslen > 0xffff)
+ anslen = 0xffff; /* limit to 16bit value */
+ ns_put16(anslen & 0xffff, cp); /*%< CLASS = UDP payload size */
+ cp += INT16SZ;
+ *cp++ = NOERROR; /*%< extended RCODE */
+ *cp++ = 0; /*%< EDNS version */
+
+ if (statp->options & RES_USE_DNSSEC) {
+#ifdef DEBUG
+ if (statp->options & RES_DEBUG)
+ printf(";; res_opt()... ENDS0 DNSSEC\n");
+#endif
+ flags |= NS_OPT_DNSSEC_OK;
+ }
+ ns_put16(flags, cp);
+ cp += INT16SZ;
+
+ ns_put16(0U, cp); /*%< RDLEN */
+ cp += INT16SZ;
+
+ hp->arcount = htons(ntohs(hp->arcount) + 1);
+
+ return (cp - buf);
+}
+
+/*
+ * Construct variable data (RDATA) block for OPT psuedo-RR, append it
+ * to the buffer, then update the RDLEN field (previously set to zero by
+ * res_nopt()) with the new RDATA length.
+ */
+int
+res_nopt_rdata(res_state statp,
+ int n0, /*%< current offset in buffer */
+ u_char *buf, /*%< buffer to put query */
+ int buflen, /*%< size of buffer */
+ u_char *rdata, /*%< ptr to start of opt rdata */
+ u_short code, /*%< OPTION-CODE */
+ u_short len, /*%< OPTION-LENGTH */
+ u_char *data) /*%< OPTION_DATA */
+{
+ register u_char *cp, *ep;
+
+#ifdef DEBUG
+ if ((statp->options & RES_DEBUG) != 0U)
+ printf(";; res_nopt_rdata()\n");
+#endif
+
+ cp = buf + n0;
+ ep = buf + buflen;
+
+ if ((ep - cp) < (4 + len))
+ return (-1);
+
+ if (rdata < (buf + 2) || rdata >= ep)
+ return (-1);
+
+ ns_put16(code, cp);
+ cp += INT16SZ;
+
+ ns_put16(len, cp);
+ cp += INT16SZ;
+
+ memcpy(cp, data, len);
+ cp += len;
+
+ len = cp - rdata;
+ ns_put16(len, rdata - 2); /* Update RDLEN field */
+
+ return (cp - buf);
+}
+#endif
+
+/*! \file */
diff --git a/lib/libc/resolv/res_mkupdate.c b/lib/libc/resolv/res_mkupdate.c
new file mode 100644
index 000000000000..9a7a129ac82c
--- /dev/null
+++ b/lib/libc/resolv/res_mkupdate.c
@@ -0,0 +1,1198 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*! \file
+ * \brief
+ * Based on the Dynamic DNS reference implementation by Viraj Bais
+ * &lt;viraj_bais@ccm.fm.intel.com>
+ */
+
+#if !defined(lint) && !defined(SABER)
+static const char rcsid[] = "$Id: res_mkupdate.c,v 1.10 2008/12/11 09:59:00 marka Exp $";
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "port_before.h"
+
+#include <sys/param.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <res_update.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+
+#ifdef _LIBC
+#include <isc/list.h>
+#endif
+
+#include "port_after.h"
+
+/* Options. Leave them on. */
+#ifndef DEBUG
+#define DEBUG
+#endif
+#define MAXPORT 1024
+
+static int getnum_str(u_char **, u_char *);
+static int gethexnum_str(u_char **, u_char *);
+static int getword_str(char *, int, u_char **, u_char *);
+static int getstr_str(char *, int, u_char **, u_char *);
+
+#define ShrinkBuffer(x) if ((buflen -= x) < 0) return (-2);
+
+/* Forward. */
+
+#ifdef _LIBC
+static
+#endif
+int res_protocolnumber(const char *);
+#ifdef _LIBC
+static
+#endif
+int res_servicenumber(const char *);
+
+/*%
+ * Form update packets.
+ * Returns the size of the resulting packet if no error
+ *
+ * On error,
+ * returns
+ *\li -1 if error in reading a word/number in rdata
+ * portion for update packets
+ *\li -2 if length of buffer passed is insufficient
+ *\li -3 if zone section is not the first section in
+ * the linked list, or section order has a problem
+ *\li -4 on a number overflow
+ *\li -5 unknown operation or no records
+ */
+int
+res_nmkupdate(res_state statp, ns_updrec *rrecp_in, u_char *buf, int buflen) {
+ ns_updrec *rrecp_start = rrecp_in;
+ HEADER *hp;
+ u_char *cp, *sp2, *startp, *endp;
+ int n, i, soanum, multiline;
+ ns_updrec *rrecp;
+ struct in_addr ina;
+ struct in6_addr in6a;
+ char buf2[MAXDNAME];
+ u_char buf3[MAXDNAME];
+ int section, numrrs = 0, counts[ns_s_max];
+ u_int16_t rtype, rclass;
+ u_int32_t n1, rttl;
+ u_char *dnptrs[20], **dpp, **lastdnptr;
+#ifndef _LIBC
+ int siglen;
+#endif
+ int keylen, certlen;
+
+ /*
+ * Initialize header fields.
+ */
+ if ((buf == NULL) || (buflen < HFIXEDSZ))
+ return (-1);
+ memset(buf, 0, HFIXEDSZ);
+ hp = (HEADER *) buf;
+ statp->id = res_nrandomid(statp);
+ hp->id = htons(statp->id);
+ hp->opcode = ns_o_update;
+ hp->rcode = NOERROR;
+ cp = buf + HFIXEDSZ;
+ buflen -= HFIXEDSZ;
+ dpp = dnptrs;
+ *dpp++ = buf;
+ *dpp++ = NULL;
+ lastdnptr = dnptrs + nitems(dnptrs);
+
+ if (rrecp_start == NULL)
+ return (-5);
+ else if (rrecp_start->r_section != S_ZONE)
+ return (-3);
+
+ memset(counts, 0, sizeof counts);
+ for (rrecp = rrecp_start; rrecp; rrecp = NEXT(rrecp, r_glink)) {
+ numrrs++;
+ section = rrecp->r_section;
+ if (section < 0 || section >= ns_s_max)
+ return (-1);
+ counts[section]++;
+ for (i = section + 1; i < ns_s_max; i++)
+ if (counts[i])
+ return (-3);
+ rtype = rrecp->r_type;
+ rclass = rrecp->r_class;
+ rttl = rrecp->r_ttl;
+ /* overload class and type */
+ if (section == S_PREREQ) {
+ rttl = 0;
+ switch (rrecp->r_opcode) {
+ case YXDOMAIN:
+ rclass = C_ANY;
+ rtype = T_ANY;
+ rrecp->r_size = 0;
+ break;
+ case NXDOMAIN:
+ rclass = C_NONE;
+ rtype = T_ANY;
+ rrecp->r_size = 0;
+ break;
+ case NXRRSET:
+ rclass = C_NONE;
+ rrecp->r_size = 0;
+ break;
+ case YXRRSET:
+ if (rrecp->r_size == 0)
+ rclass = C_ANY;
+ break;
+ default:
+ fprintf(stderr,
+ "res_mkupdate: incorrect opcode: %d\n",
+ rrecp->r_opcode);
+ fflush(stderr);
+ return (-1);
+ }
+ } else if (section == S_UPDATE) {
+ switch (rrecp->r_opcode) {
+ case DELETE:
+ rclass = rrecp->r_size == 0 ? C_ANY : C_NONE;
+ break;
+ case ADD:
+ break;
+ default:
+ fprintf(stderr,
+ "res_mkupdate: incorrect opcode: %d\n",
+ rrecp->r_opcode);
+ fflush(stderr);
+ return (-1);
+ }
+ }
+
+ /*
+ * XXX appending default domain to owner name is omitted,
+ * fqdn must be provided
+ */
+ if ((n = dn_comp(rrecp->r_dname, cp, buflen, dnptrs,
+ lastdnptr)) < 0)
+ return (-1);
+ cp += n;
+ ShrinkBuffer(n + 2*INT16SZ);
+ PUTSHORT(rtype, cp);
+ PUTSHORT(rclass, cp);
+ if (section == S_ZONE) {
+ if (numrrs != 1 || rrecp->r_type != T_SOA)
+ return (-3);
+ continue;
+ }
+ ShrinkBuffer(INT32SZ + INT16SZ);
+ PUTLONG(rttl, cp);
+ sp2 = cp; /*%< save pointer to length byte */
+ cp += INT16SZ;
+ if (rrecp->r_size == 0) {
+ if (section == S_UPDATE && rclass != C_ANY)
+ return (-1);
+ else {
+ PUTSHORT(0, sp2);
+ continue;
+ }
+ }
+ startp = rrecp->r_data;
+ endp = startp + rrecp->r_size - 1;
+ /* XXX this should be done centrally. */
+ switch (rrecp->r_type) {
+ case T_A:
+ if (!getword_str(buf2, sizeof buf2, &startp, endp))
+ return (-1);
+ if (!inet_aton(buf2, &ina))
+ return (-1);
+ n1 = ntohl(ina.s_addr);
+ ShrinkBuffer(INT32SZ);
+ PUTLONG(n1, cp);
+ break;
+ case T_CNAME:
+ case T_MB:
+ case T_MG:
+ case T_MR:
+ case T_NS:
+ case T_PTR:
+ case ns_t_dname:
+ if (!getword_str(buf2, sizeof buf2, &startp, endp))
+ return (-1);
+ n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ ShrinkBuffer(n);
+ break;
+ case T_MINFO:
+ case T_SOA:
+ case T_RP:
+ for (i = 0; i < 2; i++) {
+ if (!getword_str(buf2, sizeof buf2, &startp,
+ endp))
+ return (-1);
+ n = dn_comp(buf2, cp, buflen,
+ dnptrs, lastdnptr);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ ShrinkBuffer(n);
+ }
+ if (rrecp->r_type == T_SOA) {
+ ShrinkBuffer(5 * INT32SZ);
+ while (isspace(*startp) || !*startp)
+ startp++;
+ if (*startp == '(') {
+ multiline = 1;
+ startp++;
+ } else
+ multiline = 0;
+ /* serial, refresh, retry, expire, minimum */
+ for (i = 0; i < 5; i++) {
+ soanum = getnum_str(&startp, endp);
+ if (soanum < 0)
+ return (-1);
+ PUTLONG(soanum, cp);
+ }
+ if (multiline) {
+ while (isspace(*startp) || !*startp)
+ startp++;
+ if (*startp != ')')
+ return (-1);
+ }
+ }
+ break;
+ case T_MX:
+ case T_AFSDB:
+ case T_RT:
+ n = getnum_str(&startp, endp);
+ if (n < 0)
+ return (-1);
+ ShrinkBuffer(INT16SZ);
+ PUTSHORT(n, cp);
+ if (!getword_str(buf2, sizeof buf2, &startp, endp))
+ return (-1);
+ n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ ShrinkBuffer(n);
+ break;
+ case T_SRV:
+ n = getnum_str(&startp, endp);
+ if (n < 0)
+ return (-1);
+ ShrinkBuffer(INT16SZ);
+ PUTSHORT(n, cp);
+
+ n = getnum_str(&startp, endp);
+ if (n < 0)
+ return (-1);
+ ShrinkBuffer(INT16SZ);
+ PUTSHORT(n, cp);
+
+ n = getnum_str(&startp, endp);
+ if (n < 0)
+ return (-1);
+ ShrinkBuffer(INT16SZ);
+ PUTSHORT(n, cp);
+
+ if (!getword_str(buf2, sizeof buf2, &startp, endp))
+ return (-1);
+ n = dn_comp(buf2, cp, buflen, NULL, NULL);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ ShrinkBuffer(n);
+ break;
+ case T_PX:
+ n = getnum_str(&startp, endp);
+ if (n < 0)
+ return (-1);
+ PUTSHORT(n, cp);
+ ShrinkBuffer(INT16SZ);
+ for (i = 0; i < 2; i++) {
+ if (!getword_str(buf2, sizeof buf2, &startp,
+ endp))
+ return (-1);
+ n = dn_comp(buf2, cp, buflen, dnptrs,
+ lastdnptr);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ ShrinkBuffer(n);
+ }
+ break;
+ case T_WKS: {
+ char bm[MAXPORT/8];
+ unsigned int maxbm = 0;
+
+ if (!getword_str(buf2, sizeof buf2, &startp, endp))
+ return (-1);
+ if (!inet_aton(buf2, &ina))
+ return (-1);
+ n1 = ntohl(ina.s_addr);
+ ShrinkBuffer(INT32SZ);
+ PUTLONG(n1, cp);
+
+ if (!getword_str(buf2, sizeof buf2, &startp, endp))
+ return (-1);
+ if ((i = res_protocolnumber(buf2)) < 0)
+ return (-1);
+ ShrinkBuffer(1);
+ *cp++ = i & 0xff;
+
+ for (i = 0; i < MAXPORT/8 ; i++)
+ bm[i] = 0;
+
+ while (getword_str(buf2, sizeof buf2, &startp, endp)) {
+ if ((n = res_servicenumber(buf2)) <= 0)
+ return (-1);
+
+ if (n < MAXPORT) {
+ bm[n/8] |= (0x80>>(n%8));
+ if ((unsigned)n > maxbm)
+ maxbm = n;
+ } else
+ return (-1);
+ }
+ maxbm = maxbm/8 + 1;
+ ShrinkBuffer(maxbm);
+ memcpy(cp, bm, maxbm);
+ cp += maxbm;
+ break;
+ }
+ case T_HINFO:
+ for (i = 0; i < 2; i++) {
+ if ((n = getstr_str(buf2, sizeof buf2,
+ &startp, endp)) < 0)
+ return (-1);
+ if (n > 255)
+ return (-1);
+ ShrinkBuffer(n+1);
+ *cp++ = n;
+ memcpy(cp, buf2, n);
+ cp += n;
+ }
+ break;
+ case T_TXT:
+ for (;;) {
+ if ((n = getstr_str(buf2, sizeof buf2,
+ &startp, endp)) < 0) {
+ if (cp != (sp2 + INT16SZ))
+ break;
+ return (-1);
+ }
+ if (n > 255)
+ return (-1);
+ ShrinkBuffer(n+1);
+ *cp++ = n;
+ memcpy(cp, buf2, n);
+ cp += n;
+ }
+ break;
+ case T_X25:
+ /* RFC1183 */
+ if ((n = getstr_str(buf2, sizeof buf2, &startp,
+ endp)) < 0)
+ return (-1);
+ if (n > 255)
+ return (-1);
+ ShrinkBuffer(n+1);
+ *cp++ = n;
+ memcpy(cp, buf2, n);
+ cp += n;
+ break;
+ case T_ISDN:
+ /* RFC1183 */
+ if ((n = getstr_str(buf2, sizeof buf2, &startp,
+ endp)) < 0)
+ return (-1);
+ if ((n > 255) || (n == 0))
+ return (-1);
+ ShrinkBuffer(n+1);
+ *cp++ = n;
+ memcpy(cp, buf2, n);
+ cp += n;
+ if ((n = getstr_str(buf2, sizeof buf2, &startp,
+ endp)) < 0)
+ n = 0;
+ if (n > 255)
+ return (-1);
+ ShrinkBuffer(n+1);
+ *cp++ = n;
+ memcpy(cp, buf2, n);
+ cp += n;
+ break;
+ case T_NSAP:
+ if ((n = inet_nsap_addr((char *)startp, (u_char *)buf2, sizeof(buf2))) != 0) {
+ ShrinkBuffer(n);
+ memcpy(cp, buf2, n);
+ cp += n;
+ } else {
+ return (-1);
+ }
+ break;
+ case T_LOC:
+ if ((n = loc_aton((char *)startp, (u_char *)buf2)) != 0) {
+ ShrinkBuffer(n);
+ memcpy(cp, buf2, n);
+ cp += n;
+ } else
+ return (-1);
+ break;
+ case ns_t_sig:
+#ifdef _LIBC
+ return (-1);
+#else
+ {
+ int sig_type, success, dateerror;
+ u_int32_t exptime, timesigned;
+
+ /* type */
+ if ((n = getword_str(buf2, sizeof buf2,
+ &startp, endp)) < 0)
+ return (-1);
+ sig_type = sym_ston(__p_type_syms, buf2, &success);
+ if (!success || sig_type == ns_t_any)
+ return (-1);
+ ShrinkBuffer(INT16SZ);
+ PUTSHORT(sig_type, cp);
+ /* alg */
+ n = getnum_str(&startp, endp);
+ if (n < 0)
+ return (-1);
+ ShrinkBuffer(1);
+ *cp++ = n;
+ /* labels */
+ n = getnum_str(&startp, endp);
+ if (n <= 0 || n > 255)
+ return (-1);
+ ShrinkBuffer(1);
+ *cp++ = n;
+ /* ottl & expire */
+ if (!getword_str(buf2, sizeof buf2, &startp, endp))
+ return (-1);
+ exptime = ns_datetosecs(buf2, &dateerror);
+ if (!dateerror) {
+ ShrinkBuffer(INT32SZ);
+ PUTLONG(rttl, cp);
+ }
+ else {
+ char *ulendp;
+ u_int32_t ottl;
+
+ errno = 0;
+ ottl = strtoul(buf2, &ulendp, 10);
+ if (errno != 0 ||
+ (ulendp != NULL && *ulendp != '\0'))
+ return (-1);
+ ShrinkBuffer(INT32SZ);
+ PUTLONG(ottl, cp);
+ if (!getword_str(buf2, sizeof buf2, &startp,
+ endp))
+ return (-1);
+ exptime = ns_datetosecs(buf2, &dateerror);
+ if (dateerror)
+ return (-1);
+ }
+ /* expire */
+ ShrinkBuffer(INT32SZ);
+ PUTLONG(exptime, cp);
+ /* timesigned */
+ if (!getword_str(buf2, sizeof buf2, &startp, endp))
+ return (-1);
+ timesigned = ns_datetosecs(buf2, &dateerror);
+ if (!dateerror) {
+ ShrinkBuffer(INT32SZ);
+ PUTLONG(timesigned, cp);
+ }
+ else
+ return (-1);
+ /* footprint */
+ n = getnum_str(&startp, endp);
+ if (n < 0)
+ return (-1);
+ ShrinkBuffer(INT16SZ);
+ PUTSHORT(n, cp);
+ /* signer name */
+ if (!getword_str(buf2, sizeof buf2, &startp, endp))
+ return (-1);
+ n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ ShrinkBuffer(n);
+ /* sig */
+ if ((n = getword_str(buf2, sizeof buf2,
+ &startp, endp)) < 0)
+ return (-1);
+ siglen = b64_pton(buf2, buf3, sizeof(buf3));
+ if (siglen < 0)
+ return (-1);
+ ShrinkBuffer(siglen);
+ memcpy(cp, buf3, siglen);
+ cp += siglen;
+ break;
+ }
+#endif
+ case ns_t_key:
+ /* flags */
+ n = gethexnum_str(&startp, endp);
+ if (n < 0)
+ return (-1);
+ ShrinkBuffer(INT16SZ);
+ PUTSHORT(n, cp);
+ /* proto */
+ n = getnum_str(&startp, endp);
+ if (n < 0)
+ return (-1);
+ ShrinkBuffer(1);
+ *cp++ = n;
+ /* alg */
+ n = getnum_str(&startp, endp);
+ if (n < 0)
+ return (-1);
+ ShrinkBuffer(1);
+ *cp++ = n;
+ /* key */
+ if ((n = getword_str(buf2, sizeof buf2,
+ &startp, endp)) < 0)
+ return (-1);
+ keylen = b64_pton(buf2, buf3, sizeof(buf3));
+ if (keylen < 0)
+ return (-1);
+ ShrinkBuffer(keylen);
+ memcpy(cp, buf3, keylen);
+ cp += keylen;
+ break;
+ case ns_t_nxt:
+ {
+ int success, nxt_type;
+ u_char data[32];
+ int maxtype;
+
+ /* next name */
+ if (!getword_str(buf2, sizeof buf2, &startp, endp))
+ return (-1);
+ n = dn_comp(buf2, cp, buflen, NULL, NULL);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ ShrinkBuffer(n);
+ maxtype = 0;
+ memset(data, 0, sizeof data);
+ for (;;) {
+ if (!getword_str(buf2, sizeof buf2, &startp,
+ endp))
+ break;
+ nxt_type = sym_ston(__p_type_syms, buf2,
+ &success);
+ if (!success || !ns_t_rr_p(nxt_type))
+ return (-1);
+ NS_NXT_BIT_SET(nxt_type, data);
+ if (nxt_type > maxtype)
+ maxtype = nxt_type;
+ }
+ n = maxtype/NS_NXT_BITS+1;
+ ShrinkBuffer(n);
+ memcpy(cp, data, n);
+ cp += n;
+ break;
+ }
+ case ns_t_cert:
+ /* type */
+ n = getnum_str(&startp, endp);
+ if (n < 0)
+ return (-1);
+ ShrinkBuffer(INT16SZ);
+ PUTSHORT(n, cp);
+ /* key tag */
+ n = getnum_str(&startp, endp);
+ if (n < 0)
+ return (-1);
+ ShrinkBuffer(INT16SZ);
+ PUTSHORT(n, cp);
+ /* alg */
+ n = getnum_str(&startp, endp);
+ if (n < 0)
+ return (-1);
+ ShrinkBuffer(1);
+ *cp++ = n;
+ /* cert */
+ if ((n = getword_str(buf2, sizeof buf2,
+ &startp, endp)) < 0)
+ return (-1);
+ certlen = b64_pton(buf2, buf3, sizeof(buf3));
+ if (certlen < 0)
+ return (-1);
+ ShrinkBuffer(certlen);
+ memcpy(cp, buf3, certlen);
+ cp += certlen;
+ break;
+ case ns_t_aaaa:
+ if (!getword_str(buf2, sizeof buf2, &startp, endp))
+ return (-1);
+ if (inet_pton(AF_INET6, buf2, &in6a) <= 0)
+ return (-1);
+ ShrinkBuffer(NS_IN6ADDRSZ);
+ memcpy(cp, &in6a, NS_IN6ADDRSZ);
+ cp += NS_IN6ADDRSZ;
+ break;
+ case ns_t_naptr:
+ /* Order Preference Flags Service Replacement Regexp */
+ /* Order */
+ n = getnum_str(&startp, endp);
+ if (n < 0 || n > 65535)
+ return (-1);
+ ShrinkBuffer(INT16SZ);
+ PUTSHORT(n, cp);
+ /* Preference */
+ n = getnum_str(&startp, endp);
+ if (n < 0 || n > 65535)
+ return (-1);
+ ShrinkBuffer(INT16SZ);
+ PUTSHORT(n, cp);
+ /* Flags */
+ if ((n = getstr_str(buf2, sizeof buf2,
+ &startp, endp)) < 0) {
+ return (-1);
+ }
+ if (n > 255)
+ return (-1);
+ ShrinkBuffer(n+1);
+ *cp++ = n;
+ memcpy(cp, buf2, n);
+ cp += n;
+ /* Service Classes */
+ if ((n = getstr_str(buf2, sizeof buf2,
+ &startp, endp)) < 0) {
+ return (-1);
+ }
+ if (n > 255)
+ return (-1);
+ ShrinkBuffer(n+1);
+ *cp++ = n;
+ memcpy(cp, buf2, n);
+ cp += n;
+ /* Pattern */
+ if ((n = getstr_str(buf2, sizeof buf2,
+ &startp, endp)) < 0) {
+ return (-1);
+ }
+ if (n > 255)
+ return (-1);
+ ShrinkBuffer(n+1);
+ *cp++ = n;
+ memcpy(cp, buf2, n);
+ cp += n;
+ /* Replacement */
+ if (!getword_str(buf2, sizeof buf2, &startp, endp))
+ return (-1);
+ n = dn_comp(buf2, cp, buflen, NULL, NULL);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ ShrinkBuffer(n);
+ break;
+ default:
+ return (-1);
+ } /*switch*/
+ n = (u_int16_t)((cp - sp2) - INT16SZ);
+ PUTSHORT(n, sp2);
+ } /*for*/
+
+ hp->qdcount = htons(counts[0]);
+ hp->ancount = htons(counts[1]);
+ hp->nscount = htons(counts[2]);
+ hp->arcount = htons(counts[3]);
+ return (cp - buf);
+}
+
+/*%
+ * Get a whitespace delimited word from a string (not file)
+ * into buf. modify the start pointer to point after the
+ * word in the string.
+ */
+static int
+getword_str(char *buf, int size, u_char **startpp, u_char *endp) {
+ char *cp;
+ int c;
+
+ for (cp = buf; *startpp <= endp; ) {
+ c = **startpp;
+ if (isspace(c) || c == '\0') {
+ if (cp != buf) /*%< trailing whitespace */
+ break;
+ else { /*%< leading whitespace */
+ (*startpp)++;
+ continue;
+ }
+ }
+ (*startpp)++;
+ if (cp >= buf+size-1)
+ break;
+ *cp++ = (u_char)c;
+ }
+ *cp = '\0';
+ return (cp != buf);
+}
+
+/*%
+ * get a white spae delimited string from memory. Process quoted strings
+ * and \\DDD escapes. Return length or -1 on error. Returned string may
+ * contain nulls.
+ */
+static char digits[] = "0123456789";
+static int
+getstr_str(char *buf, int size, u_char **startpp, u_char *endp) {
+ char *cp;
+ int c, c1 = 0;
+ int inquote = 0;
+ int seen_quote = 0;
+ int escape = 0;
+ int dig = 0;
+
+ for (cp = buf; *startpp <= endp; ) {
+ if ((c = **startpp) == '\0')
+ break;
+ /* leading white space */
+ if ((cp == buf) && !seen_quote && isspace(c)) {
+ (*startpp)++;
+ continue;
+ }
+
+ switch (c) {
+ case '\\':
+ if (!escape) {
+ escape = 1;
+ dig = 0;
+ c1 = 0;
+ (*startpp)++;
+ continue;
+ }
+ goto do_escape;
+ case '"':
+ if (!escape) {
+ inquote = !inquote;
+ seen_quote = 1;
+ (*startpp)++;
+ continue;
+ }
+ /* fall through */
+ default:
+ do_escape:
+ if (escape) {
+ switch (c) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ c1 = c1 * 10 +
+ (strchr(digits, c) - digits);
+
+ if (++dig == 3) {
+ c = c1 &0xff;
+ break;
+ }
+ (*startpp)++;
+ continue;
+ }
+ escape = 0;
+ } else if (!inquote && isspace(c))
+ goto done;
+ if (cp >= buf+size-1)
+ goto done;
+ *cp++ = (u_char)c;
+ (*startpp)++;
+ }
+ }
+ done:
+ *cp = '\0';
+ return ((cp == buf)? (seen_quote? 0: -1): (cp - buf));
+}
+
+/*%
+ * Get a whitespace delimited base 16 number from a string (not file) into buf
+ * update the start pointer to point after the number in the string.
+ */
+static int
+gethexnum_str(u_char **startpp, u_char *endp) {
+ int c, n;
+ int seendigit = 0;
+ int m = 0;
+
+ if (*startpp + 2 >= endp || strncasecmp((char *)*startpp, "0x", 2) != 0)
+ return getnum_str(startpp, endp);
+ (*startpp)+=2;
+ for (n = 0; *startpp <= endp; ) {
+ c = **startpp;
+ if (isspace(c) || c == '\0') {
+ if (seendigit) /*%< trailing whitespace */
+ break;
+ else { /*%< leading whitespace */
+ (*startpp)++;
+ continue;
+ }
+ }
+ if (c == ';') {
+ while ((*startpp <= endp) &&
+ ((c = **startpp) != '\n'))
+ (*startpp)++;
+ if (seendigit)
+ break;
+ continue;
+ }
+ if (!isxdigit(c)) {
+ if (c == ')' && seendigit) {
+ (*startpp)--;
+ break;
+ }
+ return (-1);
+ }
+ (*startpp)++;
+ if (isdigit(c))
+ n = n * 16 + (c - '0');
+ else
+ n = n * 16 + (tolower(c) - 'a' + 10);
+ seendigit = 1;
+ }
+ return (n + m);
+}
+
+/*%
+ * Get a whitespace delimited base 10 number from a string (not file) into buf
+ * update the start pointer to point after the number in the string.
+ */
+static int
+getnum_str(u_char **startpp, u_char *endp) {
+ int c, n;
+ int seendigit = 0;
+ int m = 0;
+
+ for (n = 0; *startpp <= endp; ) {
+ c = **startpp;
+ if (isspace(c) || c == '\0') {
+ if (seendigit) /*%< trailing whitespace */
+ break;
+ else { /*%< leading whitespace */
+ (*startpp)++;
+ continue;
+ }
+ }
+ if (c == ';') {
+ while ((*startpp <= endp) &&
+ ((c = **startpp) != '\n'))
+ (*startpp)++;
+ if (seendigit)
+ break;
+ continue;
+ }
+ if (!isdigit(c)) {
+ if (c == ')' && seendigit) {
+ (*startpp)--;
+ break;
+ }
+ return (-1);
+ }
+ (*startpp)++;
+ n = n * 10 + (c - '0');
+ seendigit = 1;
+ }
+ return (n + m);
+}
+
+/*%
+ * Allocate a resource record buffer & save rr info.
+ */
+ns_updrec *
+res_mkupdrec(int section, const char *dname,
+ u_int class, u_int type, u_long ttl) {
+ ns_updrec *rrecp = (ns_updrec *)calloc(1, sizeof(ns_updrec));
+
+ if (!rrecp || !(rrecp->r_dname = strdup(dname))) {
+ if (rrecp)
+ free((char *)rrecp);
+ return (NULL);
+ }
+ INIT_LINK(rrecp, r_link);
+ INIT_LINK(rrecp, r_glink);
+ rrecp->r_class = (ns_class)class;
+ rrecp->r_type = (ns_type)type;
+ rrecp->r_ttl = ttl;
+ rrecp->r_section = (ns_sect)section;
+ return (rrecp);
+}
+
+/*%
+ * Free a resource record buffer created by res_mkupdrec.
+ */
+void
+res_freeupdrec(ns_updrec *rrecp) {
+ /* Note: freeing r_dp is the caller's responsibility. */
+ if (rrecp->r_dname != NULL)
+ free(rrecp->r_dname);
+ free(rrecp);
+}
+
+struct valuelist {
+ struct valuelist * next;
+ struct valuelist * prev;
+ char * name;
+ char * proto;
+ int port;
+};
+static struct valuelist *servicelist, *protolist;
+
+static void
+res_buildservicelist(void) {
+ struct servent *sp;
+ struct valuelist *slp;
+
+#ifdef MAYBE_HESIOD
+ setservent(0);
+#else
+ setservent(1);
+#endif
+ while ((sp = getservent()) != NULL) {
+ slp = (struct valuelist *)malloc(sizeof(struct valuelist));
+ if (!slp)
+ break;
+ slp->name = strdup(sp->s_name);
+ slp->proto = strdup(sp->s_proto);
+ if ((slp->name == NULL) || (slp->proto == NULL)) {
+ if (slp->name) free(slp->name);
+ if (slp->proto) free(slp->proto);
+ free(slp);
+ break;
+ }
+ slp->port = ntohs((u_int16_t)sp->s_port); /*%< host byt order */
+ slp->next = servicelist;
+ slp->prev = NULL;
+ if (servicelist)
+ servicelist->prev = slp;
+ servicelist = slp;
+ }
+ endservent();
+}
+
+#ifndef _LIBC
+void
+res_destroyservicelist() {
+ struct valuelist *slp, *slp_next;
+
+ for (slp = servicelist; slp != NULL; slp = slp_next) {
+ slp_next = slp->next;
+ free(slp->name);
+ free(slp->proto);
+ free(slp);
+ }
+ servicelist = (struct valuelist *)0;
+}
+#endif
+
+#ifdef _LIBC
+static
+#endif
+void
+res_buildprotolist(void) {
+ struct protoent *pp;
+ struct valuelist *slp;
+
+#ifdef MAYBE_HESIOD
+ setprotoent(0);
+#else
+ setprotoent(1);
+#endif
+ while ((pp = getprotoent()) != NULL) {
+ slp = (struct valuelist *)malloc(sizeof(struct valuelist));
+ if (!slp)
+ break;
+ slp->name = strdup(pp->p_name);
+ if (slp->name == NULL) {
+ free(slp);
+ break;
+ }
+ slp->port = pp->p_proto; /*%< host byte order */
+ slp->next = protolist;
+ slp->prev = NULL;
+ if (protolist)
+ protolist->prev = slp;
+ protolist = slp;
+ }
+ endprotoent();
+}
+
+#ifndef _LIBC
+void
+res_destroyprotolist(void) {
+ struct valuelist *plp, *plp_next;
+
+ for (plp = protolist; plp != NULL; plp = plp_next) {
+ plp_next = plp->next;
+ free(plp->name);
+ free(plp);
+ }
+ protolist = (struct valuelist *)0;
+}
+#endif
+
+static int
+findservice(const char *s, struct valuelist **list) {
+ struct valuelist *lp = *list;
+ int n;
+
+ for (; lp != NULL; lp = lp->next)
+ if (strcasecmp(lp->name, s) == 0) {
+ if (lp != *list) {
+ lp->prev->next = lp->next;
+ if (lp->next)
+ lp->next->prev = lp->prev;
+ (*list)->prev = lp;
+ lp->next = *list;
+ *list = lp;
+ }
+ return (lp->port); /*%< host byte order */
+ }
+ if (sscanf(s, "%d", &n) != 1 || n <= 0)
+ n = -1;
+ return (n);
+}
+
+/*%
+ * Convert service name or (ascii) number to int.
+ */
+#ifdef _LIBC
+static
+#endif
+int
+res_servicenumber(const char *p) {
+ if (servicelist == (struct valuelist *)0)
+ res_buildservicelist();
+ return (findservice(p, &servicelist));
+}
+
+/*%
+ * Convert protocol name or (ascii) number to int.
+ */
+#ifdef _LIBC
+static
+#endif
+int
+res_protocolnumber(const char *p) {
+ if (protolist == (struct valuelist *)0)
+ res_buildprotolist();
+ return (findservice(p, &protolist));
+}
+
+#ifndef _LIBC
+static struct servent *
+cgetservbyport(u_int16_t port, const char *proto) { /*%< Host byte order. */
+ struct valuelist **list = &servicelist;
+ struct valuelist *lp = *list;
+ static struct servent serv;
+
+ port = ntohs(port);
+ for (; lp != NULL; lp = lp->next) {
+ if (port != (u_int16_t)lp->port) /*%< Host byte order. */
+ continue;
+ if (strcasecmp(lp->proto, proto) == 0) {
+ if (lp != *list) {
+ lp->prev->next = lp->next;
+ if (lp->next)
+ lp->next->prev = lp->prev;
+ (*list)->prev = lp;
+ lp->next = *list;
+ *list = lp;
+ }
+ serv.s_name = lp->name;
+ serv.s_port = htons((u_int16_t)lp->port);
+ serv.s_proto = lp->proto;
+ return (&serv);
+ }
+ }
+ return (0);
+}
+
+static struct protoent *
+cgetprotobynumber(int proto) { /*%< Host byte order. */
+ struct valuelist **list = &protolist;
+ struct valuelist *lp = *list;
+ static struct protoent prot;
+
+ for (; lp != NULL; lp = lp->next)
+ if (lp->port == proto) { /*%< Host byte order. */
+ if (lp != *list) {
+ lp->prev->next = lp->next;
+ if (lp->next)
+ lp->next->prev = lp->prev;
+ (*list)->prev = lp;
+ lp->next = *list;
+ *list = lp;
+ }
+ prot.p_name = lp->name;
+ prot.p_proto = lp->port; /*%< Host byte order. */
+ return (&prot);
+ }
+ return (0);
+}
+
+const char *
+res_protocolname(int num) {
+ static char number[8];
+ struct protoent *pp;
+
+ if (protolist == (struct valuelist *)0)
+ res_buildprotolist();
+ pp = cgetprotobynumber(num);
+ if (pp == NULL) {
+ (void) sprintf(number, "%d", num);
+ return (number);
+ }
+ return (pp->p_name);
+}
+
+const char *
+res_servicename(u_int16_t port, const char *proto) { /*%< Host byte order. */
+ static char number[8];
+ struct servent *ss;
+
+ if (servicelist == (struct valuelist *)0)
+ res_buildservicelist();
+ ss = cgetservbyport(htons(port), proto);
+ if (ss == NULL) {
+ (void) sprintf(number, "%d", port);
+ return (number);
+ }
+ return (ss->s_name);
+}
+#endif
diff --git a/lib/libc/resolv/res_private.h b/lib/libc/resolv/res_private.h
new file mode 100644
index 000000000000..a986e95ce2eb
--- /dev/null
+++ b/lib/libc/resolv/res_private.h
@@ -0,0 +1,27 @@
+/* $FreeBSD$ */
+
+#ifndef res_private_h
+#define res_private_h
+
+struct __res_state_ext {
+ union res_sockaddr_union nsaddrs[MAXNS];
+ struct sort_list {
+ int af;
+ union {
+ struct in_addr ina;
+ struct in6_addr in6a;
+ } addr, mask;
+ } sort_list[MAXRESOLVSORT];
+ char nsuffix[64];
+ char nsuffix2[64];
+ struct timespec conf_mtim; /* mod time of loaded resolv.conf */
+ time_t conf_stat; /* time of last stat(resolv.conf) */
+ u_short reload_period; /* seconds between stat(resolv.conf) */
+};
+
+extern int
+res_ourserver_p(const res_state statp, const struct sockaddr *sa);
+
+#endif
+
+/*! \file */
diff --git a/lib/libc/resolv/res_query.c b/lib/libc/resolv/res_query.c
new file mode 100644
index 000000000000..c3c6313730f4
--- /dev/null
+++ b/lib/libc/resolv/res_query.c
@@ -0,0 +1,490 @@
+/*
+ * Portions Copyright (C) 2004, 2005, 2008 Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (C) 1996-2001, 2003 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)res_query.c 8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: res_query.c,v 1.11 2008/11/14 02:36:51 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "port_before.h"
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "port_after.h"
+
+/* Options. Leave them on. */
+#ifndef DEBUG
+#define DEBUG
+#endif
+
+#if PACKETSZ > 1024
+#define MAXPACKET PACKETSZ
+#else
+#define MAXPACKET 1024
+#endif
+
+/*%
+ * Formulate a normal query, send, and await answer.
+ * Returned answer is placed in supplied buffer "answer".
+ * Perform preliminary check of answer, returning success only
+ * if no error is indicated and the answer count is nonzero.
+ * Return the size of the response on success, -1 on error.
+ * Error number is left in H_ERRNO.
+ *
+ * Caller must parse answer and determine whether it answers the question.
+ */
+int
+res_nquery(res_state statp,
+ const char *name, /*%< domain name */
+ int class, int type, /*%< class and type of query */
+ u_char *answer, /*%< buffer to put answer */
+ int anslen) /*%< size of answer buffer */
+{
+ u_char buf[MAXPACKET];
+ HEADER *hp = (HEADER *) answer;
+ u_int oflags;
+ u_char *rdata;
+ int n;
+
+ oflags = statp->_flags;
+
+again:
+ hp->rcode = NOERROR; /*%< default */
+#ifdef DEBUG
+ if (statp->options & RES_DEBUG)
+ printf(";; res_query(%s, %d, %d)\n", name, class, type);
+#endif
+
+ n = res_nmkquery(statp, QUERY, name, class, type, NULL, 0, NULL,
+ buf, sizeof(buf));
+#ifdef RES_USE_EDNS0
+ if (n > 0 && (statp->_flags & RES_F_EDNS0ERR) == 0 &&
+ (statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC|RES_NSID))) {
+ n = res_nopt(statp, n, buf, sizeof(buf), anslen);
+ if (n > 0 && (statp->options & RES_NSID) != 0U) {
+ rdata = &buf[n];
+ n = res_nopt_rdata(statp, n, buf, sizeof(buf), rdata,
+ NS_OPT_NSID, 0, NULL);
+ }
+ }
+#endif
+ if (n <= 0) {
+#ifdef DEBUG
+ if (statp->options & RES_DEBUG)
+ printf(";; res_query: mkquery failed\n");
+#endif
+ RES_SET_H_ERRNO(statp, NO_RECOVERY);
+ return (n);
+ }
+
+ n = res_nsend(statp, buf, n, answer, anslen);
+ if (n < 0) {
+#ifdef RES_USE_EDNS0
+ /* if the query choked with EDNS0, retry without EDNS0 */
+ if ((statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0U &&
+ ((oflags ^ statp->_flags) & RES_F_EDNS0ERR) != 0) {
+ statp->_flags |= RES_F_EDNS0ERR;
+ if (statp->options & RES_DEBUG)
+ printf(";; res_nquery: retry without EDNS0\n");
+ goto again;
+ }
+#endif
+#ifdef DEBUG
+ if (statp->options & RES_DEBUG)
+ printf(";; res_query: send error\n");
+#endif
+ RES_SET_H_ERRNO(statp, TRY_AGAIN);
+ return (n);
+ }
+
+ if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
+#ifdef DEBUG
+ if (statp->options & RES_DEBUG)
+ printf(";; rcode = (%s), counts = an:%d ns:%d ar:%d\n",
+ p_rcode(hp->rcode),
+ ntohs(hp->ancount),
+ ntohs(hp->nscount),
+ ntohs(hp->arcount));
+#endif
+ switch (hp->rcode) {
+ case NXDOMAIN:
+ RES_SET_H_ERRNO(statp, HOST_NOT_FOUND);
+ break;
+ case SERVFAIL:
+ RES_SET_H_ERRNO(statp, TRY_AGAIN);
+ break;
+ case NOERROR:
+ RES_SET_H_ERRNO(statp, NO_DATA);
+ break;
+ case FORMERR:
+ case NOTIMP:
+ case REFUSED:
+ default:
+ RES_SET_H_ERRNO(statp, NO_RECOVERY);
+ break;
+ }
+ return (-1);
+ }
+ return (n);
+}
+
+/*%
+ * Formulate a normal query, send, and retrieve answer in supplied buffer.
+ * Return the size of the response on success, -1 on error.
+ * If enabled, implement search rules until answer or unrecoverable failure
+ * is detected. Error code, if any, is left in H_ERRNO.
+ */
+int
+res_nsearch(res_state statp,
+ const char *name, /*%< domain name */
+ int class, int type, /*%< class and type of query */
+ u_char *answer, /*%< buffer to put answer */
+ int anslen) /*%< size of answer */
+{
+ const char *cp, * const *domain;
+ HEADER *hp = (HEADER *) answer;
+ char tmp[NS_MAXDNAME];
+ u_int dots;
+ int trailing_dot, ret, saved_herrno;
+ int got_nodata = 0, got_servfail = 0, root_on_list = 0;
+ int tried_as_is = 0;
+ int searched = 0;
+
+ errno = 0;
+ RES_SET_H_ERRNO(statp, HOST_NOT_FOUND); /*%< True if we never query. */
+ dots = 0;
+ for (cp = name; *cp != '\0'; cp++)
+ dots += (*cp == '.');
+ trailing_dot = 0;
+ if (cp > name && *--cp == '.')
+ trailing_dot++;
+
+ /* If there aren't any dots, it could be a user-level alias. */
+ if (!dots && (cp = res_hostalias(statp, name, tmp, sizeof tmp))!= NULL)
+ return (res_nquery(statp, cp, class, type, answer, anslen));
+
+ /*
+ * If there are enough dots in the name, let's just give it a
+ * try 'as is'. The threshold can be set with the "ndots" option.
+ * Also, query 'as is', if there is a trailing dot in the name.
+ */
+ saved_herrno = -1;
+ if (dots >= statp->ndots || trailing_dot) {
+ ret = res_nquerydomain(statp, name, NULL, class, type,
+ answer, anslen);
+ if (ret > 0 || trailing_dot)
+ return (ret);
+ if (errno == ECONNREFUSED) {
+ RES_SET_H_ERRNO(statp, TRY_AGAIN);
+ return (-1);
+ }
+ switch (statp->res_h_errno) {
+ case NO_DATA:
+ case HOST_NOT_FOUND:
+ break;
+ case TRY_AGAIN:
+ if (hp->rcode == SERVFAIL)
+ break;
+ /* FALLTHROUGH */
+ default:
+ return (-1);
+ }
+ saved_herrno = statp->res_h_errno;
+ tried_as_is++;
+ }
+
+ /*
+ * We do at least one level of search if
+ * - there is no dot and RES_DEFNAME is set, or
+ * - there is at least one dot, there is no trailing dot,
+ * and RES_DNSRCH is set.
+ */
+ if ((!dots && (statp->options & RES_DEFNAMES) != 0U) ||
+ (dots && !trailing_dot && (statp->options & RES_DNSRCH) != 0U)) {
+ int done = 0;
+
+ for (domain = (const char * const *)statp->dnsrch;
+ *domain && !done;
+ domain++) {
+ searched = 1;
+
+ if (domain[0][0] == '\0' ||
+ (domain[0][0] == '.' && domain[0][1] == '\0'))
+ root_on_list++;
+
+ if (root_on_list && tried_as_is)
+ continue;
+
+ ret = res_nquerydomain(statp, name, *domain,
+ class, type,
+ answer, anslen);
+ if (ret > 0)
+ return (ret);
+
+ /*
+ * If no server present, give up.
+ * If name isn't found in this domain,
+ * keep trying higher domains in the search list
+ * (if that's enabled).
+ * On a NO_DATA error, keep trying, otherwise
+ * a wildcard entry of another type could keep us
+ * from finding this entry higher in the domain.
+ * If we get some other error (negative answer or
+ * server failure), then stop searching up,
+ * but try the input name below in case it's
+ * fully-qualified.
+ */
+ if (errno == ECONNREFUSED) {
+ RES_SET_H_ERRNO(statp, TRY_AGAIN);
+ return (-1);
+ }
+
+ switch (statp->res_h_errno) {
+ case NO_DATA:
+ got_nodata++;
+ /* FALLTHROUGH */
+ case HOST_NOT_FOUND:
+ /* keep trying */
+ break;
+ case TRY_AGAIN:
+ /*
+ * This can occur due to a server failure
+ * (that is, all listed servers have failed),
+ * or all listed servers have timed out.
+ * ((HEADER *)answer)->rcode may not be set
+ * to SERVFAIL in the case of a timeout.
+ *
+ * Either way we must return TRY_AGAIN in
+ * order to avoid non-deterministic
+ * return codes.
+ * For example, loaded name servers or races
+ * against network startup/validation (dhcp,
+ * ppp, etc) can cause the search to timeout
+ * on one search element, e.g. 'fu.bar.com',
+ * and return a definitive failure on the
+ * next search element, e.g. 'fu.'.
+ */
+ got_servfail++;
+ if (hp->rcode == SERVFAIL) {
+ /* try next search element, if any */
+ break;
+ }
+ /* FALLTHROUGH */
+ default:
+ /* anything else implies that we're done */
+ done++;
+ }
+
+ /* if we got here for some reason other than DNSRCH,
+ * we only wanted one iteration of the loop, so stop.
+ */
+ if ((statp->options & RES_DNSRCH) == 0U)
+ done++;
+ }
+ }
+
+ switch (statp->res_h_errno) {
+ case NO_DATA:
+ case HOST_NOT_FOUND:
+ break;
+ case TRY_AGAIN:
+ if (hp->rcode == SERVFAIL)
+ break;
+ /* FALLTHROUGH */
+ default:
+ goto giveup;
+ }
+
+ /*
+ * If the query has not already been tried as is then try it
+ * unless RES_NOTLDQUERY is set and there were no dots.
+ */
+ if ((dots || !searched || (statp->options & RES_NOTLDQUERY) == 0U) &&
+ !(tried_as_is || root_on_list)) {
+ ret = res_nquerydomain(statp, name, NULL, class, type,
+ answer, anslen);
+ if (ret > 0)
+ return (ret);
+ }
+
+ /* if we got here, we didn't satisfy the search.
+ * if we did an initial full query, return that query's H_ERRNO
+ * (note that we wouldn't be here if that query had succeeded).
+ * else if we ever got a nodata, send that back as the reason.
+ * else send back meaningless H_ERRNO, that being the one from
+ * the last DNSRCH we did.
+ */
+giveup:
+ if (saved_herrno != -1)
+ RES_SET_H_ERRNO(statp, saved_herrno);
+ else if (got_nodata)
+ RES_SET_H_ERRNO(statp, NO_DATA);
+ else if (got_servfail)
+ RES_SET_H_ERRNO(statp, TRY_AGAIN);
+ return (-1);
+}
+
+/*%
+ * Perform a call on res_query on the concatenation of name and domain,
+ * removing a trailing dot from name if domain is NULL.
+ */
+int
+res_nquerydomain(res_state statp,
+ const char *name,
+ const char *domain,
+ int class, int type, /*%< class and type of query */
+ u_char *answer, /*%< buffer to put answer */
+ int anslen) /*%< size of answer */
+{
+ char nbuf[MAXDNAME];
+ const char *longname = nbuf;
+ int n, d;
+
+#ifdef DEBUG
+ if (statp->options & RES_DEBUG)
+ printf(";; res_nquerydomain(%s, %s, %d, %d)\n",
+ name, domain?domain:"<Nil>", class, type);
+#endif
+ if (domain == NULL) {
+ /*
+ * Check for trailing '.';
+ * copy without '.' if present.
+ */
+ n = strlen(name);
+ if (n >= MAXDNAME) {
+ RES_SET_H_ERRNO(statp, NO_RECOVERY);
+ return (-1);
+ }
+ n--;
+ if (n >= 0 && name[n] == '.') {
+ strncpy(nbuf, name, n);
+ nbuf[n] = '\0';
+ } else
+ longname = name;
+ } else {
+ n = strlen(name);
+ d = strlen(domain);
+ if (n + d + 1 >= MAXDNAME) {
+ RES_SET_H_ERRNO(statp, NO_RECOVERY);
+ return (-1);
+ }
+ sprintf(nbuf, "%s.%s", name, domain);
+ }
+ return (res_nquery(statp, longname, class, type, answer, anslen));
+}
+
+const char *
+res_hostalias(const res_state statp, const char *name, char *dst, size_t siz) {
+ char *file, *cp1, *cp2;
+ char buf[BUFSIZ];
+ FILE *fp;
+
+ if (statp->options & RES_NOALIASES)
+ return (NULL);
+ if (issetugid())
+ return (NULL);
+ file = getenv("HOSTALIASES");
+ if (file == NULL || (fp = fopen(file, "re")) == NULL)
+ return (NULL);
+ setbuf(fp, NULL);
+ buf[sizeof(buf) - 1] = '\0';
+ while (fgets(buf, sizeof(buf), fp)) {
+ for (cp1 = buf; *cp1 && !isspace((unsigned char)*cp1); ++cp1)
+ ;
+ if (!*cp1)
+ break;
+ *cp1 = '\0';
+ if (ns_samename(buf, name) == 1) {
+ while (isspace((unsigned char)*++cp1))
+ ;
+ if (!*cp1)
+ break;
+ for (cp2 = cp1 + 1; *cp2 &&
+ !isspace((unsigned char)*cp2); ++cp2)
+ ;
+ *cp2 = '\0';
+ strncpy(dst, cp1, siz - 1);
+ dst[siz - 1] = '\0';
+ fclose(fp);
+ return (dst);
+ }
+ }
+ fclose(fp);
+ return (NULL);
+}
+
+/*! \file */
diff --git a/lib/libc/resolv/res_send.c b/lib/libc/resolv/res_send.c
new file mode 100644
index 000000000000..e47562b0970c
--- /dev/null
+++ b/lib/libc/resolv/res_send.c
@@ -0,0 +1,1178 @@
+/*
+ * Portions Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (C) 1996-2003 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Copyright (c) 1985, 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)res_send.c 8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: res_send.c,v 1.22 2009/01/22 23:49:23 tbox Exp $";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*! \file
+ * \brief
+ * Send query to name server and wait for reply.
+ */
+
+#include "port_before.h"
+#if !defined(USE_KQUEUE) && !defined(USE_POLL)
+#include "fd_setsize.h"
+#endif
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <isc/eventlib.h>
+
+#include "port_after.h"
+
+#ifdef USE_KQUEUE
+#include <sys/event.h>
+#else
+#ifdef USE_POLL
+#ifdef HAVE_STROPTS_H
+#include <stropts.h>
+#endif
+#include <poll.h>
+#endif /* USE_POLL */
+#endif
+
+#include "un-namespace.h"
+
+/* Options. Leave them on. */
+#ifndef DEBUG
+#define DEBUG
+#endif
+#include "res_debug.h"
+#include "res_private.h"
+
+#define EXT(res) ((res)->_u._ext)
+
+#if !defined(USE_POLL) && !defined(USE_KQUEUE)
+static const int highestFD = FD_SETSIZE - 1;
+#endif
+
+/* Forward. */
+
+static int get_salen(const struct sockaddr *);
+static struct sockaddr * get_nsaddr(res_state, size_t);
+static int send_vc(res_state, const u_char *, int,
+ u_char *, int, int *, int);
+static int send_dg(res_state,
+#ifdef USE_KQUEUE
+ int kq,
+#endif
+ const u_char *, int,
+ u_char *, int, int *, int, int,
+ int *, int *);
+static void Aerror(const res_state, FILE *, const char *, int,
+ const struct sockaddr *, int);
+static void Perror(const res_state, FILE *, const char *, int);
+static int sock_eq(struct sockaddr *, struct sockaddr *);
+#if defined(NEED_PSELECT) && !defined(USE_POLL) && !defined(USE_KQUEUE)
+static int pselect(int, void *, void *, void *,
+ struct timespec *,
+ const sigset_t *);
+#endif
+void res_pquery(const res_state, const u_char *, int, FILE *);
+
+static const int niflags = NI_NUMERICHOST | NI_NUMERICSERV;
+
+/* Public. */
+
+/*%
+ * looks up "ina" in _res.ns_addr_list[]
+ *
+ * returns:
+ *\li 0 : not found
+ *\li >0 : found
+ *
+ * author:
+ *\li paul vixie, 29may94
+ */
+int
+res_ourserver_p(const res_state statp, const struct sockaddr *sa) {
+ const struct sockaddr_in *inp, *srv;
+ const struct sockaddr_in6 *in6p, *srv6;
+ int ns;
+
+ switch (sa->sa_family) {
+ case AF_INET:
+ inp = (const struct sockaddr_in *)sa;
+ for (ns = 0; ns < statp->nscount; ns++) {
+ srv = (struct sockaddr_in *)get_nsaddr(statp, ns);
+ if (srv->sin_family == inp->sin_family &&
+ srv->sin_port == inp->sin_port &&
+ (srv->sin_addr.s_addr == INADDR_ANY ||
+ srv->sin_addr.s_addr == inp->sin_addr.s_addr))
+ return (1);
+ }
+ break;
+ case AF_INET6:
+ if (EXT(statp).ext == NULL)
+ break;
+ in6p = (const struct sockaddr_in6 *)sa;
+ for (ns = 0; ns < statp->nscount; ns++) {
+ srv6 = (struct sockaddr_in6 *)get_nsaddr(statp, ns);
+ if (srv6->sin6_family == in6p->sin6_family &&
+ srv6->sin6_port == in6p->sin6_port &&
+#ifdef HAVE_SIN6_SCOPE_ID
+ (srv6->sin6_scope_id == 0 ||
+ srv6->sin6_scope_id == in6p->sin6_scope_id) &&
+#endif
+ (IN6_IS_ADDR_UNSPECIFIED(&srv6->sin6_addr) ||
+ IN6_ARE_ADDR_EQUAL(&srv6->sin6_addr, &in6p->sin6_addr)))
+ return (1);
+ }
+ break;
+ default:
+ break;
+ }
+ return (0);
+}
+
+/*%
+ * look for (name,type,class) in the query section of packet (buf,eom)
+ *
+ * requires:
+ *\li buf + HFIXEDSZ <= eom
+ *
+ * returns:
+ *\li -1 : format error
+ *\li 0 : not found
+ *\li >0 : found
+ *
+ * author:
+ *\li paul vixie, 29may94
+ */
+int
+res_nameinquery(const char *name, int type, int class,
+ const u_char *buf, const u_char *eom)
+{
+ const u_char *cp = buf + HFIXEDSZ;
+ int qdcount = ntohs(((const HEADER*)buf)->qdcount);
+
+ while (qdcount-- > 0) {
+ char tname[MAXDNAME+1];
+ int n, ttype, tclass;
+
+ n = dn_expand(buf, eom, cp, tname, sizeof tname);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ if (cp + 2 * INT16SZ > eom)
+ return (-1);
+ ttype = ns_get16(cp); cp += INT16SZ;
+ tclass = ns_get16(cp); cp += INT16SZ;
+ if (ttype == type && tclass == class &&
+ ns_samename(tname, name) == 1)
+ return (1);
+ }
+ return (0);
+}
+
+/*%
+ * is there a 1:1 mapping of (name,type,class)
+ * in (buf1,eom1) and (buf2,eom2)?
+ *
+ * returns:
+ *\li -1 : format error
+ *\li 0 : not a 1:1 mapping
+ *\li >0 : is a 1:1 mapping
+ *
+ * author:
+ *\li paul vixie, 29may94
+ */
+int
+res_queriesmatch(const u_char *buf1, const u_char *eom1,
+ const u_char *buf2, const u_char *eom2)
+{
+ const u_char *cp = buf1 + HFIXEDSZ;
+ int qdcount = ntohs(((const HEADER*)buf1)->qdcount);
+
+ if (buf1 + HFIXEDSZ > eom1 || buf2 + HFIXEDSZ > eom2)
+ return (-1);
+
+ /*
+ * Only header section present in replies to
+ * dynamic update packets.
+ */
+ if ((((const HEADER *)buf1)->opcode == ns_o_update) &&
+ (((const HEADER *)buf2)->opcode == ns_o_update))
+ return (1);
+
+ if (qdcount != ntohs(((const HEADER*)buf2)->qdcount))
+ return (0);
+ while (qdcount-- > 0) {
+ char tname[MAXDNAME+1];
+ int n, ttype, tclass;
+
+ n = dn_expand(buf1, eom1, cp, tname, sizeof tname);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ if (cp + 2 * INT16SZ > eom1)
+ return (-1);
+ ttype = ns_get16(cp); cp += INT16SZ;
+ tclass = ns_get16(cp); cp += INT16SZ;
+ if (!res_nameinquery(tname, ttype, tclass, buf2, eom2))
+ return (0);
+ }
+ return (1);
+}
+
+int
+res_nsend(res_state statp,
+ const u_char *buf, int buflen, u_char *ans, int anssiz)
+{
+ int gotsomewhere, terrno, tries, v_circuit, resplen, ns, n;
+#ifdef USE_KQUEUE
+ int kq;
+#endif
+ char abuf[NI_MAXHOST];
+
+ /* No name servers or res_init() failure */
+ if (statp->nscount == 0 || EXT(statp).ext == NULL) {
+ errno = ESRCH;
+ return (-1);
+ }
+ if (anssiz < HFIXEDSZ) {
+ errno = EINVAL;
+ return (-1);
+ }
+ DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_QUERY),
+ (stdout, ";; res_send()\n"), buf, buflen);
+ v_circuit = (statp->options & RES_USEVC) || buflen > PACKETSZ;
+ gotsomewhere = 0;
+ terrno = ETIMEDOUT;
+
+#ifdef USE_KQUEUE
+ if ((kq = kqueue()) < 0) {
+ Perror(statp, stderr, "kqueue", errno);
+ return (-1);
+ }
+#endif
+
+ /*
+ * If the ns_addr_list in the resolver context has changed, then
+ * invalidate our cached copy and the associated timing data.
+ */
+ if (EXT(statp).nscount != 0) {
+ int needclose = 0;
+ struct sockaddr_storage peer;
+ ISC_SOCKLEN_T peerlen;
+
+ if (EXT(statp).nscount != statp->nscount)
+ needclose++;
+ else
+ for (ns = 0; ns < statp->nscount; ns++) {
+ if (statp->nsaddr_list[ns].sin_family &&
+ !sock_eq((struct sockaddr *)&statp->nsaddr_list[ns],
+ (struct sockaddr *)&EXT(statp).ext->nsaddrs[ns])) {
+ needclose++;
+ break;
+ }
+
+ if (EXT(statp).nssocks[ns] == -1)
+ continue;
+ peerlen = sizeof(peer);
+ if (_getpeername(EXT(statp).nssocks[ns],
+ (struct sockaddr *)&peer, &peerlen) < 0) {
+ needclose++;
+ break;
+ }
+ if (!sock_eq((struct sockaddr *)&peer,
+ get_nsaddr(statp, ns))) {
+ needclose++;
+ break;
+ }
+ }
+ if (needclose) {
+ res_nclose(statp);
+ EXT(statp).nscount = 0;
+ }
+ }
+
+ /*
+ * Maybe initialize our private copy of the ns_addr_list.
+ */
+ if (EXT(statp).nscount == 0) {
+ for (ns = 0; ns < statp->nscount; ns++) {
+ EXT(statp).nstimes[ns] = RES_MAXTIME;
+ EXT(statp).nssocks[ns] = -1;
+ if (!statp->nsaddr_list[ns].sin_family)
+ continue;
+ EXT(statp).ext->nsaddrs[ns].sin =
+ statp->nsaddr_list[ns];
+ }
+ EXT(statp).nscount = statp->nscount;
+ }
+
+ /*
+ * Some resolvers want to even out the load on their nameservers.
+ * Note that RES_BLAST overrides RES_ROTATE.
+ */
+ if ((statp->options & RES_ROTATE) != 0U &&
+ (statp->options & RES_BLAST) == 0U) {
+ union res_sockaddr_union inu;
+ struct sockaddr_in ina;
+ int lastns = statp->nscount - 1;
+ int fd;
+ u_int16_t nstime;
+
+ if (EXT(statp).ext != NULL)
+ inu = EXT(statp).ext->nsaddrs[0];
+ ina = statp->nsaddr_list[0];
+ fd = EXT(statp).nssocks[0];
+ nstime = EXT(statp).nstimes[0];
+ for (ns = 0; ns < lastns; ns++) {
+ if (EXT(statp).ext != NULL)
+ EXT(statp).ext->nsaddrs[ns] =
+ EXT(statp).ext->nsaddrs[ns + 1];
+ statp->nsaddr_list[ns] = statp->nsaddr_list[ns + 1];
+ EXT(statp).nssocks[ns] = EXT(statp).nssocks[ns + 1];
+ EXT(statp).nstimes[ns] = EXT(statp).nstimes[ns + 1];
+ }
+ if (EXT(statp).ext != NULL)
+ EXT(statp).ext->nsaddrs[lastns] = inu;
+ statp->nsaddr_list[lastns] = ina;
+ EXT(statp).nssocks[lastns] = fd;
+ EXT(statp).nstimes[lastns] = nstime;
+ }
+
+ /*
+ * Send request, RETRY times, or until successful.
+ */
+ for (tries = 0; tries < statp->retry; tries++) {
+ for (ns = 0; ns < statp->nscount; ns++) {
+ struct sockaddr *nsap;
+ int nsaplen;
+ nsap = get_nsaddr(statp, ns);
+ nsaplen = get_salen(nsap);
+ statp->_flags &= ~RES_F_LASTMASK;
+ statp->_flags |= (ns << RES_F_LASTSHIFT);
+ same_ns:
+ if (statp->qhook) {
+ int done = 0, loops = 0;
+
+ do {
+ res_sendhookact act;
+
+ act = (*statp->qhook)(&nsap, &buf, &buflen,
+ ans, anssiz, &resplen);
+ switch (act) {
+ case res_goahead:
+ done = 1;
+ break;
+ case res_nextns:
+ res_nclose(statp);
+ goto next_ns;
+ case res_done:
+#ifdef USE_KQUEUE
+ _close(kq);
+#endif
+ return (resplen);
+ case res_modified:
+ /* give the hook another try */
+ if (++loops < 42) /*doug adams*/
+ break;
+ /*FALLTHROUGH*/
+ case res_error:
+ /*FALLTHROUGH*/
+ default:
+ goto fail;
+ }
+ } while (!done);
+ }
+
+ Dprint(((statp->options & RES_DEBUG) &&
+ getnameinfo(nsap, nsaplen, abuf, sizeof(abuf),
+ NULL, 0, niflags) == 0),
+ (stdout, ";; Querying server (# %d) address = %s\n",
+ ns + 1, abuf));
+
+
+ if (v_circuit) {
+ /* Use VC; at most one attempt per server. */
+ tries = statp->retry;
+ n = send_vc(statp, buf, buflen, ans, anssiz, &terrno,
+ ns);
+ if (n < 0)
+ goto fail;
+ if (n == 0)
+ goto next_ns;
+ resplen = n;
+ } else {
+ /* Use datagrams. */
+ n = send_dg(statp,
+#ifdef USE_KQUEUE
+ kq,
+#endif
+ buf, buflen, ans, anssiz, &terrno,
+ ns, tries, &v_circuit, &gotsomewhere);
+ if (n < 0)
+ goto fail;
+ if (n == 0)
+ goto next_ns;
+ if (v_circuit)
+ goto same_ns;
+ resplen = n;
+ }
+
+ Dprint((statp->options & RES_DEBUG) ||
+ ((statp->pfcode & RES_PRF_REPLY) &&
+ (statp->pfcode & RES_PRF_HEAD1)),
+ (stdout, ";; got answer:\n"));
+
+ DprintQ((statp->options & RES_DEBUG) ||
+ (statp->pfcode & RES_PRF_REPLY),
+ (stdout, "%s", ""),
+ ans, (resplen > anssiz) ? anssiz : resplen);
+
+ /*
+ * If we have temporarily opened a virtual circuit,
+ * or if we haven't been asked to keep a socket open,
+ * close the socket.
+ */
+ if ((v_circuit && (statp->options & RES_USEVC) == 0U) ||
+ (statp->options & RES_STAYOPEN) == 0U) {
+ res_nclose(statp);
+ }
+ if (statp->rhook) {
+ int done = 0, loops = 0;
+
+ do {
+ res_sendhookact act;
+
+ act = (*statp->rhook)(nsap, buf, buflen,
+ ans, anssiz, &resplen);
+ switch (act) {
+ case res_goahead:
+ case res_done:
+ done = 1;
+ break;
+ case res_nextns:
+ res_nclose(statp);
+ goto next_ns;
+ case res_modified:
+ /* give the hook another try */
+ if (++loops < 42) /*doug adams*/
+ break;
+ /*FALLTHROUGH*/
+ case res_error:
+ /*FALLTHROUGH*/
+ default:
+ goto fail;
+ }
+ } while (!done);
+
+ }
+#ifdef USE_KQUEUE
+ _close(kq);
+#endif
+ return (resplen);
+ next_ns: ;
+ } /*foreach ns*/
+ } /*foreach retry*/
+ res_nclose(statp);
+#ifdef USE_KQUEUE
+ _close(kq);
+#endif
+ if (!v_circuit) {
+ if (!gotsomewhere)
+ errno = ECONNREFUSED; /*%< no nameservers found */
+ else
+ errno = ETIMEDOUT; /*%< no answer obtained */
+ } else
+ errno = terrno;
+ return (-1);
+ fail:
+ res_nclose(statp);
+#ifdef USE_KQUEUE
+ _close(kq);
+#endif
+ return (-1);
+}
+
+/* Private */
+
+static int
+get_salen(const struct sockaddr *sa)
+{
+
+#ifdef HAVE_SA_LEN
+ /* There are people do not set sa_len. Be forgiving to them. */
+ if (sa->sa_len)
+ return (sa->sa_len);
+#endif
+
+ if (sa->sa_family == AF_INET)
+ return (sizeof(struct sockaddr_in));
+ else if (sa->sa_family == AF_INET6)
+ return (sizeof(struct sockaddr_in6));
+ else
+ return (0); /*%< unknown, die on connect */
+}
+
+/*%
+ * pick appropriate nsaddr_list for use. see res_init() for initialization.
+ */
+static struct sockaddr *
+get_nsaddr(res_state statp, size_t n)
+{
+
+ if (!statp->nsaddr_list[n].sin_family && EXT(statp).ext) {
+ /*
+ * - EXT(statp).ext->nsaddrs[n] holds an address that is larger
+ * than struct sockaddr, and
+ * - user code did not update statp->nsaddr_list[n].
+ */
+ return (struct sockaddr *)(void *)&EXT(statp).ext->nsaddrs[n];
+ } else {
+ /*
+ * - user code updated statp->nsaddr_list[n], or
+ * - statp->nsaddr_list[n] has the same content as
+ * EXT(statp).ext->nsaddrs[n].
+ */
+ return (struct sockaddr *)(void *)&statp->nsaddr_list[n];
+ }
+}
+
+static int
+send_vc(res_state statp,
+ const u_char *buf, int buflen, u_char *ans, int anssiz,
+ int *terrno, int ns)
+{
+ const HEADER *hp = (const HEADER *) buf;
+ HEADER *anhp = (HEADER *) ans;
+ struct sockaddr *nsap;
+ int nsaplen;
+ int truncating, connreset, resplen, n;
+ struct iovec iov[2];
+ u_short len;
+ u_char *cp;
+ void *tmp;
+#ifdef SO_NOSIGPIPE
+ int on = 1;
+#endif
+
+ nsap = get_nsaddr(statp, ns);
+ nsaplen = get_salen(nsap);
+
+ connreset = 0;
+ same_ns:
+ truncating = 0;
+
+ /* Are we still talking to whom we want to talk to? */
+ if (statp->_vcsock >= 0 && (statp->_flags & RES_F_VC) != 0) {
+ struct sockaddr_storage peer;
+ ISC_SOCKLEN_T size = sizeof peer;
+
+ if (_getpeername(statp->_vcsock,
+ (struct sockaddr *)&peer, &size) < 0 ||
+ !sock_eq((struct sockaddr *)&peer, nsap)) {
+ res_nclose(statp);
+ statp->_flags &= ~RES_F_VC;
+ }
+ }
+
+ if (statp->_vcsock < 0 || (statp->_flags & RES_F_VC) == 0) {
+ if (statp->_vcsock >= 0)
+ res_nclose(statp);
+
+ statp->_vcsock = _socket(nsap->sa_family, SOCK_STREAM |
+ SOCK_CLOEXEC, 0);
+#if !defined(USE_POLL) && !defined(USE_KQUEUE)
+ if (statp->_vcsock > highestFD) {
+ res_nclose(statp);
+ errno = ENOTSOCK;
+ }
+#endif
+ if (statp->_vcsock < 0) {
+ switch (errno) {
+ case EPROTONOSUPPORT:
+#ifdef EPFNOSUPPORT
+ case EPFNOSUPPORT:
+#endif
+ case EAFNOSUPPORT:
+ Perror(statp, stderr, "socket(vc)", errno);
+ return (0);
+ default:
+ *terrno = errno;
+ Perror(statp, stderr, "socket(vc)", errno);
+ return (-1);
+ }
+ }
+#ifdef SO_NOSIGPIPE
+ /*
+ * Disable generation of SIGPIPE when writing to a closed
+ * socket. Write should return -1 and set errno to EPIPE
+ * instead.
+ *
+ * Push on even if setsockopt(SO_NOSIGPIPE) fails.
+ */
+ (void)_setsockopt(statp->_vcsock, SOL_SOCKET, SO_NOSIGPIPE, &on,
+ sizeof(on));
+#endif
+ errno = 0;
+ if (_connect(statp->_vcsock, nsap, nsaplen) < 0) {
+ *terrno = errno;
+ Aerror(statp, stderr, "connect/vc", errno, nsap,
+ nsaplen);
+ res_nclose(statp);
+ return (0);
+ }
+ statp->_flags |= RES_F_VC;
+ }
+
+ /*
+ * Send length & message
+ */
+ ns_put16((u_short)buflen, (u_char*)&len);
+ iov[0] = evConsIovec(&len, INT16SZ);
+ DE_CONST(buf, tmp);
+ iov[1] = evConsIovec(tmp, buflen);
+ if (_writev(statp->_vcsock, iov, 2) != (INT16SZ + buflen)) {
+ *terrno = errno;
+ Perror(statp, stderr, "write failed", errno);
+ res_nclose(statp);
+ return (0);
+ }
+ /*
+ * Receive length & response
+ */
+ read_len:
+ cp = ans;
+ len = INT16SZ;
+ while ((n = _read(statp->_vcsock, (char *)cp, (int)len)) > 0) {
+ cp += n;
+ if ((len -= n) == 0)
+ break;
+ }
+ if (n <= 0) {
+ *terrno = errno;
+ Perror(statp, stderr, "read failed", errno);
+ res_nclose(statp);
+ /*
+ * A long running process might get its TCP
+ * connection reset if the remote server was
+ * restarted. Requery the server instead of
+ * trying a new one. When there is only one
+ * server, this means that a query might work
+ * instead of failing. We only allow one reset
+ * per query to prevent looping.
+ */
+ if (*terrno == ECONNRESET && !connreset) {
+ connreset = 1;
+ res_nclose(statp);
+ goto same_ns;
+ }
+ res_nclose(statp);
+ return (0);
+ }
+ resplen = ns_get16(ans);
+ if (resplen > anssiz) {
+ Dprint(statp->options & RES_DEBUG,
+ (stdout, ";; response truncated\n")
+ );
+ truncating = 1;
+ len = anssiz;
+ } else
+ len = resplen;
+ if (len < HFIXEDSZ) {
+ /*
+ * Undersized message.
+ */
+ Dprint(statp->options & RES_DEBUG,
+ (stdout, ";; undersized: %d\n", len));
+ *terrno = EMSGSIZE;
+ res_nclose(statp);
+ return (0);
+ }
+ cp = ans;
+ while (len != 0 &&
+ (n = _read(statp->_vcsock, (char *)cp, (int)len)) > 0) {
+ cp += n;
+ len -= n;
+ }
+ if (n <= 0) {
+ *terrno = errno;
+ Perror(statp, stderr, "read(vc)", errno);
+ res_nclose(statp);
+ return (0);
+ }
+ if (truncating) {
+ /*
+ * Flush rest of answer so connection stays in synch.
+ */
+ anhp->tc = 1;
+ len = resplen - anssiz;
+ while (len != 0) {
+ char junk[PACKETSZ];
+
+ n = _read(statp->_vcsock, junk,
+ (len > sizeof junk) ? sizeof junk : len);
+ if (n > 0)
+ len -= n;
+ else
+ break;
+ }
+ }
+ /*
+ * If the calling applicating has bailed out of
+ * a previous call and failed to arrange to have
+ * the circuit closed or the server has got
+ * itself confused, then drop the packet and
+ * wait for the correct one.
+ */
+ if (hp->id != anhp->id) {
+ DprintQ((statp->options & RES_DEBUG) ||
+ (statp->pfcode & RES_PRF_REPLY),
+ (stdout, ";; old answer (unexpected):\n"),
+ ans, (resplen > anssiz) ? anssiz: resplen);
+ goto read_len;
+ }
+
+ /*
+ * All is well, or the error is fatal. Signal that the
+ * next nameserver ought not be tried.
+ */
+ return (resplen);
+}
+
+static int
+send_dg(res_state statp,
+#ifdef USE_KQUEUE
+ int kq,
+#endif
+ const u_char *buf, int buflen, u_char *ans,
+ int anssiz, int *terrno, int ns, int tries, int *v_circuit,
+ int *gotsomewhere)
+{
+ const HEADER *hp = (const HEADER *) buf;
+ HEADER *anhp = (HEADER *) ans;
+ const struct sockaddr *nsap;
+ int nsaplen;
+ struct timespec now, timeout, finish;
+ struct sockaddr_storage from;
+ ISC_SOCKLEN_T fromlen;
+ int resplen, seconds, n, s;
+#ifdef USE_KQUEUE
+ struct kevent kv;
+#else
+#ifdef USE_POLL
+ int polltimeout;
+ struct pollfd pollfd;
+#else
+ fd_set dsmask;
+#endif
+#endif
+
+ nsap = get_nsaddr(statp, ns);
+ nsaplen = get_salen(nsap);
+ if (EXT(statp).nssocks[ns] == -1) {
+ EXT(statp).nssocks[ns] = _socket(nsap->sa_family,
+ SOCK_DGRAM | SOCK_CLOEXEC, 0);
+#if !defined(USE_POLL) && !defined(USE_KQUEUE)
+ if (EXT(statp).nssocks[ns] > highestFD) {
+ res_nclose(statp);
+ errno = ENOTSOCK;
+ }
+#endif
+ if (EXT(statp).nssocks[ns] < 0) {
+ switch (errno) {
+ case EPROTONOSUPPORT:
+#ifdef EPFNOSUPPORT
+ case EPFNOSUPPORT:
+#endif
+ case EAFNOSUPPORT:
+ Perror(statp, stderr, "socket(dg)", errno);
+ return (0);
+ default:
+ *terrno = errno;
+ Perror(statp, stderr, "socket(dg)", errno);
+ return (-1);
+ }
+ }
+#ifndef CANNOT_CONNECT_DGRAM
+ /*
+ * On a 4.3BSD+ machine (client and server,
+ * actually), sending to a nameserver datagram
+ * port with no nameserver will cause an
+ * ICMP port unreachable message to be returned.
+ * If our datagram socket is "connected" to the
+ * server, we get an ECONNREFUSED error on the next
+ * socket operation, and select returns if the
+ * error message is received. We can thus detect
+ * the absence of a nameserver without timing out.
+ *
+ * When the option "insecure1" is specified, we'd
+ * rather expect to see responses from an "unknown"
+ * address. In order to let the kernel accept such
+ * responses, do not connect the socket here.
+ * XXX: or do we need an explicit option to disable
+ * connecting?
+ */
+ if (!(statp->options & RES_INSECURE1) &&
+ _connect(EXT(statp).nssocks[ns], nsap, nsaplen) < 0) {
+ Aerror(statp, stderr, "connect(dg)", errno, nsap,
+ nsaplen);
+ res_nclose(statp);
+ return (0);
+ }
+#endif /* !CANNOT_CONNECT_DGRAM */
+ Dprint(statp->options & RES_DEBUG,
+ (stdout, ";; new DG socket\n"))
+ }
+ s = EXT(statp).nssocks[ns];
+#ifndef CANNOT_CONNECT_DGRAM
+ if (statp->options & RES_INSECURE1) {
+ if (_sendto(s,
+ (const char*)buf, buflen, 0, nsap, nsaplen) != buflen) {
+ Aerror(statp, stderr, "sendto", errno, nsap, nsaplen);
+ res_nclose(statp);
+ return (0);
+ }
+ } else if (send(s, (const char*)buf, buflen, 0) != buflen) {
+ Perror(statp, stderr, "send", errno);
+ res_nclose(statp);
+ return (0);
+ }
+#else /* !CANNOT_CONNECT_DGRAM */
+ if (_sendto(s, (const char*)buf, buflen, 0, nsap, nsaplen) != buflen)
+ {
+ Aerror(statp, stderr, "sendto", errno, nsap, nsaplen);
+ res_nclose(statp);
+ return (0);
+ }
+#endif /* !CANNOT_CONNECT_DGRAM */
+
+ /*
+ * Wait for reply.
+ */
+ seconds = (statp->retrans << tries);
+ if (ns > 0)
+ seconds /= statp->nscount;
+ if (seconds <= 0)
+ seconds = 1;
+ now = evNowTime();
+ timeout = evConsTime(seconds, 0);
+ finish = evAddTime(now, timeout);
+ goto nonow;
+ wait:
+ now = evNowTime();
+ nonow:
+#ifndef USE_POLL
+ if (evCmpTime(finish, now) > 0)
+ timeout = evSubTime(finish, now);
+ else
+ timeout = evConsTime(0, 0);
+#ifdef USE_KQUEUE
+ EV_SET(&kv, s, EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, 0);
+ n = _kevent(kq, &kv, 1, &kv, 1, &timeout);
+#else
+ FD_ZERO(&dsmask);
+ FD_SET(s, &dsmask);
+ n = pselect(s + 1, &dsmask, NULL, NULL, &timeout, NULL);
+#endif
+#else
+ timeout = evSubTime(finish, now);
+ if (timeout.tv_sec < 0)
+ timeout = evConsTime(0, 0);
+ polltimeout = 1000*timeout.tv_sec +
+ timeout.tv_nsec/1000000;
+ pollfd.fd = s;
+ pollfd.events = POLLRDNORM;
+ n = _poll(&pollfd, 1, polltimeout);
+#endif /* USE_POLL */
+
+ if (n == 0) {
+ Dprint(statp->options & RES_DEBUG, (stdout, ";; timeout\n"));
+ *gotsomewhere = 1;
+ return (0);
+ }
+ if (n < 0) {
+ if (errno == EINTR)
+ goto wait;
+#ifdef USE_KQUEUE
+ Perror(statp, stderr, "kevent", errno);
+#else
+#ifndef USE_POLL
+ Perror(statp, stderr, "select", errno);
+#else
+ Perror(statp, stderr, "poll", errno);
+#endif /* USE_POLL */
+#endif
+ res_nclose(statp);
+ return (0);
+ }
+#ifdef USE_KQUEUE
+ if (kv.ident != s)
+ goto wait;
+#endif
+ errno = 0;
+ fromlen = sizeof(from);
+ resplen = _recvfrom(s, (char*)ans, anssiz,0,
+ (struct sockaddr *)&from, &fromlen);
+ if (resplen <= 0) {
+ Perror(statp, stderr, "recvfrom", errno);
+ res_nclose(statp);
+ return (0);
+ }
+ *gotsomewhere = 1;
+ if (resplen < HFIXEDSZ) {
+ /*
+ * Undersized message.
+ */
+ Dprint(statp->options & RES_DEBUG,
+ (stdout, ";; undersized: %d\n",
+ resplen));
+ *terrno = EMSGSIZE;
+ res_nclose(statp);
+ return (0);
+ }
+ if (hp->id != anhp->id) {
+ /*
+ * response from old query, ignore it.
+ * XXX - potential security hazard could
+ * be detected here.
+ */
+ DprintQ((statp->options & RES_DEBUG) ||
+ (statp->pfcode & RES_PRF_REPLY),
+ (stdout, ";; old answer:\n"),
+ ans, (resplen > anssiz) ? anssiz : resplen);
+ goto wait;
+ }
+ if (!(statp->options & RES_INSECURE1) &&
+ !res_ourserver_p(statp, (struct sockaddr *)&from)) {
+ /*
+ * response from wrong server? ignore it.
+ * XXX - potential security hazard could
+ * be detected here.
+ */
+ DprintQ((statp->options & RES_DEBUG) ||
+ (statp->pfcode & RES_PRF_REPLY),
+ (stdout, ";; not our server:\n"),
+ ans, (resplen > anssiz) ? anssiz : resplen);
+ goto wait;
+ }
+#ifdef RES_USE_EDNS0
+ if (anhp->rcode == FORMERR && (statp->options & RES_USE_EDNS0) != 0U) {
+ /*
+ * Do not retry if the server do not understand EDNS0.
+ * The case has to be captured here, as FORMERR packet do not
+ * carry query section, hence res_queriesmatch() returns 0.
+ */
+ DprintQ(statp->options & RES_DEBUG,
+ (stdout, "server rejected query with EDNS0:\n"),
+ ans, (resplen > anssiz) ? anssiz : resplen);
+ /* record the error */
+ statp->_flags |= RES_F_EDNS0ERR;
+ res_nclose(statp);
+ return (0);
+ }
+#endif
+ if (!(statp->options & RES_INSECURE2) &&
+ !res_queriesmatch(buf, buf + buflen,
+ ans, ans + anssiz)) {
+ /*
+ * response contains wrong query? ignore it.
+ * XXX - potential security hazard could
+ * be detected here.
+ */
+ DprintQ((statp->options & RES_DEBUG) ||
+ (statp->pfcode & RES_PRF_REPLY),
+ (stdout, ";; wrong query name:\n"),
+ ans, (resplen > anssiz) ? anssiz : resplen);
+ goto wait;
+ }
+ if (anhp->rcode == SERVFAIL ||
+ anhp->rcode == NOTIMP ||
+ anhp->rcode == REFUSED) {
+ DprintQ(statp->options & RES_DEBUG,
+ (stdout, "server rejected query:\n"),
+ ans, (resplen > anssiz) ? anssiz : resplen);
+ res_nclose(statp);
+ /* don't retry if called from dig */
+ if (!statp->pfcode)
+ return (0);
+ }
+ if (!(statp->options & RES_IGNTC) && anhp->tc) {
+ /*
+ * To get the rest of answer,
+ * use TCP with same server.
+ */
+ Dprint(statp->options & RES_DEBUG,
+ (stdout, ";; truncated answer\n"));
+ *v_circuit = 1;
+ res_nclose(statp);
+ return (1);
+ }
+ /*
+ * All is well, or the error is fatal. Signal that the
+ * next nameserver ought not be tried.
+ */
+ return (resplen);
+}
+
+static void
+Aerror(const res_state statp, FILE *file, const char *string, int error,
+ const struct sockaddr *address, int alen)
+{
+ int save = errno;
+ char hbuf[NI_MAXHOST];
+ char sbuf[NI_MAXSERV];
+
+ if ((statp->options & RES_DEBUG) != 0U) {
+ if (getnameinfo(address, alen, hbuf, sizeof(hbuf),
+ sbuf, sizeof(sbuf), niflags)) {
+ strncpy(hbuf, "?", sizeof(hbuf) - 1);
+ hbuf[sizeof(hbuf) - 1] = '\0';
+ strncpy(sbuf, "?", sizeof(sbuf) - 1);
+ sbuf[sizeof(sbuf) - 1] = '\0';
+ }
+ fprintf(file, "res_send: %s ([%s].%s): %s\n",
+ string, hbuf, sbuf, strerror(error));
+ }
+ errno = save;
+}
+
+static void
+Perror(const res_state statp, FILE *file, const char *string, int error) {
+ int save = errno;
+
+ if ((statp->options & RES_DEBUG) != 0U)
+ fprintf(file, "res_send: %s: %s\n",
+ string, strerror(error));
+ errno = save;
+}
+
+static int
+sock_eq(struct sockaddr *a, struct sockaddr *b) {
+ struct sockaddr_in *a4, *b4;
+ struct sockaddr_in6 *a6, *b6;
+
+ if (a->sa_family != b->sa_family)
+ return 0;
+ switch (a->sa_family) {
+ case AF_INET:
+ a4 = (struct sockaddr_in *)a;
+ b4 = (struct sockaddr_in *)b;
+ return a4->sin_port == b4->sin_port &&
+ a4->sin_addr.s_addr == b4->sin_addr.s_addr;
+ case AF_INET6:
+ a6 = (struct sockaddr_in6 *)a;
+ b6 = (struct sockaddr_in6 *)b;
+ return a6->sin6_port == b6->sin6_port &&
+#ifdef HAVE_SIN6_SCOPE_ID
+ a6->sin6_scope_id == b6->sin6_scope_id &&
+#endif
+ IN6_ARE_ADDR_EQUAL(&a6->sin6_addr, &b6->sin6_addr);
+ default:
+ return 0;
+ }
+}
+
+#if defined(NEED_PSELECT) && !defined(USE_POLL) && !defined(USE_KQUEUE)
+/* XXX needs to move to the porting library. */
+static int
+pselect(int nfds, void *rfds, void *wfds, void *efds,
+ struct timespec *tsp, const sigset_t *sigmask)
+{
+ struct timeval tv, *tvp;
+ sigset_t sigs;
+ int n;
+
+ if (tsp) {
+ tvp = &tv;
+ tv = evTimeVal(*tsp);
+ } else
+ tvp = NULL;
+ if (sigmask)
+ sigprocmask(SIG_SETMASK, sigmask, &sigs);
+ n = select(nfds, rfds, wfds, efds, tvp);
+ if (sigmask)
+ sigprocmask(SIG_SETMASK, &sigs, NULL);
+ if (tsp)
+ *tsp = evTimeSpec(tv);
+ return (n);
+}
+#endif
diff --git a/lib/libc/resolv/res_state.c b/lib/libc/resolv/res_state.c
new file mode 100644
index 000000000000..6d31d9282d7a
--- /dev/null
+++ b/lib/libc/resolv/res_state.c
@@ -0,0 +1,122 @@
+/*-
+ * Copyright (c) 2006 The FreeBSD Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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/stat.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include <stdlib.h>
+
+#include "namespace.h"
+#include "reentrant.h"
+#include "un-namespace.h"
+
+#include "res_private.h"
+
+#undef _res
+
+struct __res_state _res;
+
+static thread_key_t res_key;
+static once_t res_init_once = ONCE_INITIALIZER;
+static int res_thr_keycreated = 0;
+
+static void
+free_res(void *ptr)
+{
+ res_state statp = ptr;
+
+ if (statp->_u._ext.ext != NULL)
+ res_ndestroy(statp);
+ free(statp);
+}
+
+static void
+res_keycreate(void)
+{
+ res_thr_keycreated = thr_keycreate(&res_key, free_res) == 0;
+}
+
+static res_state
+res_check_reload(res_state statp)
+{
+ struct timespec now;
+ struct stat sb;
+ struct __res_state_ext *ext;
+
+ if ((statp->options & RES_INIT) == 0) {
+ return (statp);
+ }
+
+ ext = statp->_u._ext.ext;
+ if (ext == NULL || ext->reload_period == 0) {
+ return (statp);
+ }
+
+ if (clock_gettime(CLOCK_MONOTONIC_FAST, &now) != 0 ||
+ (now.tv_sec - ext->conf_stat) < ext->reload_period) {
+ return (statp);
+ }
+
+ ext->conf_stat = now.tv_sec;
+ if (stat(_PATH_RESCONF, &sb) == 0 &&
+ (sb.st_mtim.tv_sec != ext->conf_mtim.tv_sec ||
+ sb.st_mtim.tv_nsec != ext->conf_mtim.tv_nsec)) {
+ statp->options &= ~RES_INIT;
+ }
+
+ return (statp);
+}
+
+res_state
+__res_state(void)
+{
+ res_state statp;
+
+ if (thr_main() != 0)
+ return res_check_reload(&_res);
+
+ if (thr_once(&res_init_once, res_keycreate) != 0 ||
+ !res_thr_keycreated)
+ return (&_res);
+
+ statp = thr_getspecific(res_key);
+ if (statp != NULL)
+ return res_check_reload(statp);
+ statp = calloc(1, sizeof(*statp));
+ if (statp == NULL)
+ return (&_res);
+#ifdef __BIND_RES_TEXT
+ statp->options = RES_TIMEOUT; /* Motorola, et al. */
+#endif
+ if (thr_setspecific(res_key, statp) == 0)
+ return (statp);
+ free(statp);
+ return (&_res);
+}
diff --git a/lib/libc/resolv/res_update.c b/lib/libc/resolv/res_update.c
new file mode 100644
index 000000000000..8e866e3edf8b
--- /dev/null
+++ b/lib/libc/resolv/res_update.c
@@ -0,0 +1,222 @@
+#if !defined(lint) && !defined(SABER)
+static const char rcsid[] = "$Id: res_update.c,v 1.13 2005/04/27 04:56:43 sra Exp $";
+#endif /* not lint */
+
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*! \file
+ * \brief
+ * Based on the Dynamic DNS reference implementation by Viraj Bais
+ * &lt;viraj_bais@ccm.fm.intel.com>
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "port_before.h"
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <netdb.h>
+#include <res_update.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <isc/list.h>
+#include <resolv.h>
+
+#include "port_after.h"
+#include "res_private.h"
+
+/*%
+ * Separate a linked list of records into groups so that all records
+ * in a group will belong to a single zone on the nameserver.
+ * Create a dynamic update packet for each zone and send it to the
+ * nameservers for that zone, and await answer.
+ * Abort if error occurs in updating any zone.
+ * Return the number of zones updated on success, < 0 on error.
+ *
+ * On error, caller must deal with the unsynchronized zones
+ * eg. an A record might have been successfully added to the forward
+ * zone but the corresponding PTR record would be missing if error
+ * was encountered while updating the reverse zone.
+ */
+
+struct zonegrp {
+ char z_origin[MAXDNAME];
+ ns_class z_class;
+ union res_sockaddr_union z_nsaddrs[MAXNS];
+ int z_nscount;
+ int z_flags;
+ LIST(ns_updrec) z_rrlist;
+ LINK(struct zonegrp) z_link;
+};
+
+#define ZG_F_ZONESECTADDED 0x0001
+
+/* Forward. */
+
+static void res_dprintf(const char *, ...) ISC_FORMAT_PRINTF(1, 2);
+
+/* Macros. */
+
+#define DPRINTF(x) do {\
+ int save_errno = errno; \
+ if ((statp->options & RES_DEBUG) != 0U) res_dprintf x; \
+ errno = save_errno; \
+ } while (0)
+
+/* Public. */
+
+int
+res_nupdate(res_state statp, ns_updrec *rrecp_in, ns_tsig_key *key) {
+ ns_updrec *rrecp;
+ u_char answer[PACKETSZ];
+ u_char *packet;
+ struct zonegrp *zptr, tgrp;
+ LIST(struct zonegrp) zgrps;
+ int nzones = 0, nscount = 0, n;
+ union res_sockaddr_union nsaddrs[MAXNS];
+
+ packet = malloc(NS_MAXMSG);
+ if (packet == NULL) {
+ DPRINTF(("malloc failed"));
+ return (0);
+ }
+ /* Thread all of the updates onto a list of groups. */
+ INIT_LIST(zgrps);
+ memset(&tgrp, 0, sizeof (tgrp));
+ for (rrecp = rrecp_in; rrecp;
+ rrecp = LINKED(rrecp, r_link) ? NEXT(rrecp, r_link) : NULL) {
+ int nscnt;
+ /* Find the origin for it if there is one. */
+ tgrp.z_class = rrecp->r_class;
+ nscnt = res_findzonecut2(statp, rrecp->r_dname, tgrp.z_class,
+ RES_EXHAUSTIVE, tgrp.z_origin,
+ sizeof tgrp.z_origin,
+ tgrp.z_nsaddrs, MAXNS);
+ if (nscnt <= 0) {
+ DPRINTF(("res_findzonecut failed (%d)", nscnt));
+ goto done;
+ }
+ tgrp.z_nscount = nscnt;
+ /* Find the group for it if there is one. */
+ for (zptr = HEAD(zgrps); zptr != NULL; zptr = NEXT(zptr, z_link))
+ if (ns_samename(tgrp.z_origin, zptr->z_origin) == 1 &&
+ tgrp.z_class == zptr->z_class)
+ break;
+ /* Make a group for it if there isn't one. */
+ if (zptr == NULL) {
+ zptr = malloc(sizeof *zptr);
+ if (zptr == NULL) {
+ DPRINTF(("malloc failed"));
+ goto done;
+ }
+ *zptr = tgrp;
+ zptr->z_flags = 0;
+ INIT_LINK(zptr, z_link);
+ INIT_LIST(zptr->z_rrlist);
+ APPEND(zgrps, zptr, z_link);
+ }
+ /* Thread this rrecp onto the right group. */
+ APPEND(zptr->z_rrlist, rrecp, r_glink);
+ }
+
+ for (zptr = HEAD(zgrps); zptr != NULL; zptr = NEXT(zptr, z_link)) {
+ /* Construct zone section and prepend it. */
+ rrecp = res_mkupdrec(ns_s_zn, zptr->z_origin,
+ zptr->z_class, ns_t_soa, 0);
+ if (rrecp == NULL) {
+ DPRINTF(("res_mkupdrec failed"));
+ goto done;
+ }
+ PREPEND(zptr->z_rrlist, rrecp, r_glink);
+ zptr->z_flags |= ZG_F_ZONESECTADDED;
+
+ /* Marshall the update message. */
+ n = res_nmkupdate(statp, HEAD(zptr->z_rrlist),
+ packet, NS_MAXMSG);
+ DPRINTF(("res_mkupdate -> %d", n));
+ if (n < 0)
+ goto done;
+
+ /* Temporarily replace the resolver's nameserver set. */
+ nscount = res_getservers(statp, nsaddrs, MAXNS);
+ res_setservers(statp, zptr->z_nsaddrs, zptr->z_nscount);
+
+ /* Send the update and remember the result. */
+ if (key != NULL) {
+#ifdef _LIBC
+ DPRINTF(("TSIG is not supported\n"));
+ RES_SET_H_ERRNO(statp, NO_RECOVERY);
+ goto done;
+#else
+ n = res_nsendsigned(statp, packet, n, key,
+ answer, sizeof answer);
+#endif
+ } else
+ n = res_nsend(statp, packet, n, answer, sizeof answer);
+ if (n < 0) {
+ DPRINTF(("res_nsend: send error, n=%d (%s)\n",
+ n, strerror(errno)));
+ goto done;
+ }
+ if (((HEADER *)answer)->rcode == NOERROR)
+ nzones++;
+
+ /* Restore resolver's nameserver set. */
+ res_setservers(statp, nsaddrs, nscount);
+ nscount = 0;
+ }
+ done:
+ while (!EMPTY(zgrps)) {
+ zptr = HEAD(zgrps);
+ if ((zptr->z_flags & ZG_F_ZONESECTADDED) != 0)
+ res_freeupdrec(HEAD(zptr->z_rrlist));
+ UNLINK(zgrps, zptr, z_link);
+ free(zptr);
+ }
+ if (nscount != 0)
+ res_setservers(statp, nsaddrs, nscount);
+
+ free(packet);
+ return (nzones);
+}
+
+/* Private. */
+
+static void
+res_dprintf(const char *fmt, ...) {
+ va_list ap;
+
+ va_start(ap, fmt);
+ fputs(";; res_nupdate: ", stderr);
+ vfprintf(stderr, fmt, ap);
+ fputc('\n', stderr);
+ va_end(ap);
+}
diff --git a/lib/libc/riscv/Makefile.inc b/lib/libc/riscv/Makefile.inc
new file mode 100644
index 000000000000..105839021b96
--- /dev/null
+++ b/lib/libc/riscv/Makefile.inc
@@ -0,0 +1,13 @@
+# $FreeBSD$
+#
+# Machine dependent definitions for the RISC-V architecture.
+#
+
+.if ${MACHINE_ARCH:Mriscv*sf} != ""
+CFLAGS+=-DSOFTFLOAT
+.endif
+
+# Long double is quad precision
+GDTOASRCS+=strtorQ.c
+MDSRCS+=machdep_ldisQ.c
+SYM_MAPS+=${LIBC_SRCTOP}/riscv/Symbol.map
diff --git a/lib/libc/riscv/SYS.h b/lib/libc/riscv/SYS.h
new file mode 100644
index 000000000000..abd93c91efc6
--- /dev/null
+++ b/lib/libc/riscv/SYS.h
@@ -0,0 +1,68 @@
+/*-
+ * Copyright (c) 2014 Andrew Turner
+ * Copyright (c) 2015 Ruslan Bukin <br@bsdpad.com>
+ * All rights reserved.
+ *
+ * Portions of this software were developed by SRI International and the
+ * University of Cambridge Computer Laboratory under DARPA/AFRL contract
+ * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme.
+ *
+ * Portions of this software were developed by the University of Cambridge
+ * Computer Laboratory as part of the CTSRD Project, with support from the
+ * UK Higher Education Innovation Fund (HEIF).
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/syscall.h>
+#include <machine/asm.h>
+
+#define _SYSCALL(name) \
+ li t0, SYS_ ## name; \
+ ecall
+
+#define SYSCALL(name) \
+ENTRY(__sys_##name); \
+ WEAK_REFERENCE(__sys_##name, name); \
+ WEAK_REFERENCE(__sys_##name, _##name); \
+ _SYSCALL(name); \
+ ret; \
+END(__sys_##name)
+
+#define PSEUDO(name) \
+ENTRY(__sys_##name); \
+ WEAK_REFERENCE(__sys_##name, _##name); \
+ _SYSCALL(name); \
+ bnez t0, cerror; \
+ ret; \
+END(__sys_##name)
+
+#define RSYSCALL(name) \
+ENTRY(__sys_##name); \
+ WEAK_REFERENCE(__sys_##name, name); \
+ WEAK_REFERENCE(__sys_##name, _##name); \
+ _SYSCALL(name); \
+ bnez t0, cerror; \
+ ret; \
+END(__sys_##name)
diff --git a/lib/libc/riscv/Symbol.map b/lib/libc/riscv/Symbol.map
new file mode 100644
index 000000000000..b959072e7e0c
--- /dev/null
+++ b/lib/libc/riscv/Symbol.map
@@ -0,0 +1,56 @@
+/*
+ * $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, ...).
+ */
+FBSD_1.0 {
+ /* PSEUDO syscalls */
+ _exit;
+
+ _setjmp;
+ _longjmp;
+ fabs;
+ __flt_rounds;
+ fpgetmask;
+ fpsetmask;
+ __infinity;
+ __nan;
+ setjmp;
+ longjmp;
+ sigsetjmp;
+ siglongjmp;
+ htonl;
+ htons;
+ ntohl;
+ ntohs;
+ vfork;
+ makecontext;
+};
+
+FBSDprivate_1.0 {
+ _set_tp;
+ _end;
+ __makecontext;
+
+ /* softfloat */
+ __addsf3;
+ __adddf3;
+ __subsf3;
+ __subdf3;
+ __mulsf3;
+ __muldf3;
+ __divsf3;
+ __divdf3;
+ __floatsisf;
+ __floatsidf;
+ __fixsfsi;
+ __fixdfsi;
+ __fixunssfsi;
+ __fixunsdfsi;
+ __extendsfdf2;
+ __truncdfsf2;
+};
diff --git a/lib/libc/riscv/_fpmath.h b/lib/libc/riscv/_fpmath.h
new file mode 100644
index 000000000000..5c4077cb90c5
--- /dev/null
+++ b/lib/libc/riscv/_fpmath.h
@@ -0,0 +1,71 @@
+/*-
+ * Copyright (c) 2002, 2003 David Schultz <das@FreeBSD.ORG>
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+union IEEEl2bits {
+ long double e;
+ struct {
+ unsigned long manl :64;
+ unsigned long manh :48;
+ unsigned int exp :15;
+ unsigned int sign :1;
+ } bits;
+ struct {
+ unsigned long manl :64;
+ unsigned long manh :48;
+ unsigned int expsign :16;
+ } xbits;
+};
+
+#define LDBL_NBIT 0
+#define LDBL_IMPLICIT_NBIT
+#define mask_nbit_l(u) ((void)0)
+
+#define LDBL_MANH_SIZE 20
+#define LDBL_MANL_SIZE 32
+
+#define LDBL_TO_ARRAY32(u, a) do { \
+ (a)[0] = (uint32_t)(u).bits.manl; \
+ (a)[1] = (uint32_t)(u).bits.manh; \
+} while(0)
+
+/*
+ * TODO: Due to compiler problem we are temporary using
+ * LDBL_PREC == 53. Use code below for LDBL_PREC == 113
+ */
+#if 0
+#define LDBL_MANH_SIZE 48
+#define LDBL_MANL_SIZE 64
+
+#define LDBL_TO_ARRAY32(u, a) do { \
+ (a)[0] = (uint32_t)(u).bits.manl; \
+ (a)[1] = (uint32_t)((u).bits.manl >> 32); \
+ (a)[2] = (uint32_t)(u).bits.manh; \
+ (a)[3] = (uint32_t)((u).bits.manh >> 32); \
+} while(0)
+#endif
diff --git a/lib/libc/riscv/arith.h b/lib/libc/riscv/arith.h
new file mode 100644
index 000000000000..ecb1a33fccb0
--- /dev/null
+++ b/lib/libc/riscv/arith.h
@@ -0,0 +1,19 @@
+/*
+ * MD header for contrib/gdtoa
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * NOTE: The definitions in this file must be correct or strtod(3) and
+ * floating point formats in printf(3) will break! The file can be
+ * generated by running contrib/gdtoa/arithchk.c on the target
+ * architecture. See contrib/gdtoa/gdtoaimp.h for details.
+ */
+
+#define IEEE_8087
+#define Arith_Kind_ASL 1
+#define Long int
+#define Intcast (int)(long)
+#define Double_Align
+#define X64_bit_pointers
diff --git a/lib/libc/riscv/gd_qnan.h b/lib/libc/riscv/gd_qnan.h
new file mode 100644
index 000000000000..cb375dd87173
--- /dev/null
+++ b/lib/libc/riscv/gd_qnan.h
@@ -0,0 +1,21 @@
+/*
+ * MD header for contrib/gdtoa
+ *
+ * This file can be generated by compiling and running contrib/gdtoa/qnan.c
+ * on the target architecture after arith.h has been generated.
+ *
+ * $FreeBSD$
+ */
+
+#define f_QNAN 0x7fc00000
+#define d_QNAN0 0x0
+#define d_QNAN1 0x7ff80000
+#define ld_QNAN0 0x0
+#define ld_QNAN1 0x7ff80000
+#define ld_QNAN2 0x0
+#define ld_QNAN3 0x0
+#define ldus_QNAN0 0x0
+#define ldus_QNAN1 0x0
+#define ldus_QNAN2 0x0
+#define ldus_QNAN3 0x7ff8
+#define ldus_QNAN4 0x0
diff --git a/lib/libc/riscv/gen/Makefile.inc b/lib/libc/riscv/gen/Makefile.inc
new file mode 100644
index 000000000000..6380db6c265a
--- /dev/null
+++ b/lib/libc/riscv/gen/Makefile.inc
@@ -0,0 +1,13 @@
+# $FreeBSD$
+
+SRCS+= _ctx_start.S \
+ fabs.S \
+ flt_rounds.c \
+ infinity.c \
+ ldexp.c \
+ makecontext.c \
+ _setjmp.S \
+ _set_tp.c \
+ setjmp.S \
+ sigsetjmp.S \
+ trivial-getcontextx.c
diff --git a/lib/libc/riscv/gen/_ctx_start.S b/lib/libc/riscv/gen/_ctx_start.S
new file mode 100644
index 000000000000..cda5397ac22d
--- /dev/null
+++ b/lib/libc/riscv/gen/_ctx_start.S
@@ -0,0 +1,43 @@
+/*-
+ * Copyright (c) 2015 Ruslan Bukin <br@bsdpad.com>
+ * All rights reserved.
+ *
+ * Portions of this software were developed by SRI International and the
+ * University of Cambridge Computer Laboratory under DARPA/AFRL contract
+ * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme.
+ *
+ * Portions of this software were developed by the University of Cambridge
+ * Computer Laboratory as part of the CTSRD Project, with support from the
+ * UK Higher Education Innovation Fund (HEIF).
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+ENTRY(_ctx_start)
+ jalr s0 /* Call func from makecontext */
+ mv a0, s1 /* Load ucp saved in makecontext */
+ call _C_LABEL(ctx_done)
+ call _C_LABEL(abort)
+END(_ctx_start)
diff --git a/lib/libc/riscv/gen/_set_tp.c b/lib/libc/riscv/gen/_set_tp.c
new file mode 100644
index 000000000000..a880465253a4
--- /dev/null
+++ b/lib/libc/riscv/gen/_set_tp.c
@@ -0,0 +1,50 @@
+/*-
+ * Copyright (c) 2015 Ruslan Bukin <br@bsdpad.com>
+ * All rights reserved.
+ *
+ * Portions of this software were developed by SRI International and the
+ * University of Cambridge Computer Laboratory under DARPA/AFRL contract
+ * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme.
+ *
+ * Portions of this software were developed by the University of Cambridge
+ * Computer Laboratory as part of the CTSRD Project, with support from the
+ * UK Higher Education Innovation Fund (HEIF).
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <string.h>
+#include <sys/types.h>
+
+#include <machine/sysarch.h>
+
+#include <stdlib.h>
+
+void
+_set_tp(void *tp)
+{
+
+ __asm __volatile("mv tp, %0" :: "r"((char*)tp + 0x10));
+}
diff --git a/lib/libc/riscv/gen/_setjmp.S b/lib/libc/riscv/gen/_setjmp.S
new file mode 100644
index 000000000000..4e82ae420850
--- /dev/null
+++ b/lib/libc/riscv/gen/_setjmp.S
@@ -0,0 +1,145 @@
+/*-
+ * Copyright (c) 2015-2016 Ruslan Bukin <br@bsdpad.com>
+ * All rights reserved.
+ *
+ * Portions of this software were developed by SRI International and the
+ * University of Cambridge Computer Laboratory under DARPA/AFRL contract
+ * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme.
+ *
+ * Portions of this software were developed by the University of Cambridge
+ * Computer Laboratory as part of the CTSRD Project, with support from the
+ * UK Higher Education Innovation Fund (HEIF).
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include <machine/setjmp.h>
+
+ENTRY(_setjmp)
+ /* Store the magic value and stack pointer */
+ la t0, .Lmagic
+ ld t0, 0(t0)
+ sd t0, (0 * 8)(a0)
+ sd sp, (1 * 8)(a0)
+ addi a0, a0, (2 * 8)
+
+ /* Store the general purpose registers and ra */
+ sd s0, (0 * 8)(a0)
+ sd s1, (1 * 8)(a0)
+ sd s2, (2 * 8)(a0)
+ sd s3, (3 * 8)(a0)
+ sd s4, (4 * 8)(a0)
+ sd s5, (5 * 8)(a0)
+ sd s6, (6 * 8)(a0)
+ sd s7, (7 * 8)(a0)
+ sd s8, (8 * 8)(a0)
+ sd s9, (9 * 8)(a0)
+ sd s10, (10 * 8)(a0)
+ sd s11, (11 * 8)(a0)
+ sd ra, (12 * 8)(a0)
+ addi a0, a0, (13 * 8)
+
+#if !defined(_STANDALONE) && !defined(SOFTFLOAT)
+ /* Store the fpe registers */
+ fsd fs0, (0 * 16)(a0)
+ fsd fs1, (1 * 16)(a0)
+ fsd fs2, (2 * 16)(a0)
+ fsd fs3, (3 * 16)(a0)
+ fsd fs4, (4 * 16)(a0)
+ fsd fs5, (5 * 16)(a0)
+ fsd fs6, (6 * 16)(a0)
+ fsd fs7, (7 * 16)(a0)
+ fsd fs8, (8 * 16)(a0)
+ fsd fs9, (9 * 16)(a0)
+ fsd fs10, (10 * 16)(a0)
+ fsd fs11, (11 * 16)(a0)
+ addi a0, a0, (12 * 16)
+#endif
+
+ /* Return value */
+ li a0, 0
+ ret
+ .align 3
+.Lmagic:
+ .quad _JB_MAGIC__SETJMP
+END(_setjmp)
+
+ENTRY(_longjmp)
+ /* Check the magic value */
+ ld t0, 0(a0)
+ la t1, .Lmagic
+ ld t1, 0(t1)
+ bne t0, t1, botch
+
+ /* Restore the stack pointer */
+ ld t0, 8(a0)
+ mv sp, t0
+ addi a0, a0, (2 * 8)
+
+ /* Restore the general purpose registers and ra */
+ ld s0, (0 * 8)(a0)
+ ld s1, (1 * 8)(a0)
+ ld s2, (2 * 8)(a0)
+ ld s3, (3 * 8)(a0)
+ ld s4, (4 * 8)(a0)
+ ld s5, (5 * 8)(a0)
+ ld s6, (6 * 8)(a0)
+ ld s7, (7 * 8)(a0)
+ ld s8, (8 * 8)(a0)
+ ld s9, (9 * 8)(a0)
+ ld s10, (10 * 8)(a0)
+ ld s11, (11 * 8)(a0)
+ ld ra, (12 * 8)(a0)
+ addi a0, a0, (13 * 8)
+
+#if !defined(_STANDALONE) && !defined(SOFTFLOAT)
+ /* Restore the fpe registers */
+ fld fs0, (0 * 16)(a0)
+ fld fs1, (1 * 16)(a0)
+ fld fs2, (2 * 16)(a0)
+ fld fs3, (3 * 16)(a0)
+ fld fs4, (4 * 16)(a0)
+ fld fs5, (5 * 16)(a0)
+ fld fs6, (6 * 16)(a0)
+ fld fs7, (7 * 16)(a0)
+ fld fs8, (8 * 16)(a0)
+ fld fs9, (9 * 16)(a0)
+ fld fs10, (10 * 16)(a0)
+ fld fs11, (11 * 16)(a0)
+ addi a0, a0, (12 * 16)
+#endif
+
+ /* Load the return value */
+ mv a0, a1
+ ret
+
+botch:
+#ifdef _STANDALONE
+ j botch
+#else
+ call _C_LABEL(longjmperror)
+ call _C_LABEL(abort)
+#endif
+END(_longjmp)
diff --git a/lib/libc/riscv/gen/fabs.S b/lib/libc/riscv/gen/fabs.S
new file mode 100644
index 000000000000..3fc791a452f4
--- /dev/null
+++ b/lib/libc/riscv/gen/fabs.S
@@ -0,0 +1,41 @@
+/*-
+ * Copyright (c) 2015 Ruslan Bukin <br@bsdpad.com>
+ * All rights reserved.
+ *
+ * Portions of this software were developed by SRI International and the
+ * University of Cambridge Computer Laboratory under DARPA/AFRL contract
+ * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme.
+ *
+ * Portions of this software were developed by the University of Cambridge
+ * Computer Laboratory as part of the CTSRD Project, with support from the
+ * UK Higher Education Innovation Fund (HEIF).
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+ENTRY(fabs)
+ fabs.d fa0, fa0
+ ret
+END(fabs)
diff --git a/lib/libc/riscv/gen/flt_rounds.c b/lib/libc/riscv/gen/flt_rounds.c
new file mode 100644
index 000000000000..13bb8b2a1796
--- /dev/null
+++ b/lib/libc/riscv/gen/flt_rounds.c
@@ -0,0 +1,72 @@
+/*-
+ * Copyright (c) 2015-2016 Ruslan Bukin <br@bsdpad.com>
+ * All rights reserved.
+ *
+ * Portions of this software were developed by SRI International and the
+ * University of Cambridge Computer Laboratory under DARPA/AFRL contract
+ * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme.
+ *
+ * Portions of this software were developed by the University of Cambridge
+ * Computer Laboratory as part of the CTSRD Project, with support from the
+ * UK Higher Education Innovation Fund (HEIF).
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+#include <fenv.h>
+#include <float.h>
+
+#ifdef SOFTFLOAT
+#include "softfloat-for-gcc.h"
+#include "milieu.h"
+#include "softfloat.h"
+#endif
+
+int
+__flt_rounds(void)
+{
+ uint64_t mode;
+
+#ifdef SOFTFLOAT
+ mode = __softfloat_float_rounding_mode;
+#else
+ __asm __volatile("csrr %0, fcsr" : "=r" (mode));
+#endif
+
+ switch (mode & _ROUND_MASK) {
+ case FE_TOWARDZERO:
+ return (0);
+ case FE_TONEAREST:
+ return (1);
+ case FE_UPWARD:
+ return (2);
+ case FE_DOWNWARD:
+ return (3);
+ }
+
+ return (-1);
+}
diff --git a/lib/libc/riscv/gen/infinity.c b/lib/libc/riscv/gen/infinity.c
new file mode 100644
index 000000000000..115c4702d895
--- /dev/null
+++ b/lib/libc/riscv/gen/infinity.c
@@ -0,0 +1,14 @@
+/*
+ * infinity.c
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <math.h>
+
+/* bytes for +Infinity on riscv */
+const union __infinity_un __infinity = { { 0, 0, 0, 0, 0, 0, 0xf0, 0x7f } };
+
+/* bytes for NaN */
+const union __nan_un __nan = { { 0, 0, 0xc0, 0xff } };
diff --git a/lib/libc/riscv/gen/makecontext.c b/lib/libc/riscv/gen/makecontext.c
new file mode 100644
index 000000000000..3633a5dd66e1
--- /dev/null
+++ b/lib/libc/riscv/gen/makecontext.c
@@ -0,0 +1,91 @@
+/*-
+ * Copyright (c) 2015 Ruslan Bukin <br@bsdpad.com>
+ * All rights reserved.
+ *
+ * Portions of this software were developed by SRI International and the
+ * University of Cambridge Computer Laboratory under DARPA/AFRL contract
+ * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme.
+ *
+ * Portions of this software were developed by the University of Cambridge
+ * Computer Laboratory as part of the CTSRD Project, with support from the
+ * UK Higher Education Innovation Fund (HEIF).
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+
+#include <machine/riscvreg.h>
+
+#include <inttypes.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <ucontext.h>
+
+void _ctx_start(void);
+
+void
+ctx_done(ucontext_t *ucp)
+{
+
+ if (ucp->uc_link == NULL) {
+ exit(0);
+ } else {
+ setcontext((const ucontext_t *)ucp->uc_link);
+ abort();
+ }
+}
+
+__weak_reference(__makecontext, makecontext);
+
+void
+__makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...)
+{
+ struct gpregs *gp;
+ va_list ap;
+ int i;
+
+ /* A valid context is required. */
+ if (ucp == NULL)
+ return;
+
+ if ((argc < 0) || (argc > 8))
+ return;
+
+ gp = &ucp->uc_mcontext.mc_gpregs;
+
+ va_start(ap, argc);
+ /* Pass up to eight arguments in a0-7. */
+ for (i = 0; i < argc && i < 8; i++)
+ gp->gp_a[i] = va_arg(ap, uint64_t);
+ va_end(ap);
+
+ /* Set the stack */
+ gp->gp_sp = STACKALIGN(ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size);
+ /* Arrange for return via the trampoline code. */
+ gp->gp_sepc = (__register_t)_ctx_start;
+ gp->gp_s[0] = (__register_t)func;
+ gp->gp_s[1] = (__register_t)ucp;
+}
diff --git a/lib/libc/riscv/gen/setjmp.S b/lib/libc/riscv/gen/setjmp.S
new file mode 100644
index 000000000000..9d97b51de6b6
--- /dev/null
+++ b/lib/libc/riscv/gen/setjmp.S
@@ -0,0 +1,171 @@
+/*-
+ * Copyright (c) 2015-2016 Ruslan Bukin <br@bsdpad.com>
+ * All rights reserved.
+ *
+ * Portions of this software were developed by SRI International and the
+ * University of Cambridge Computer Laboratory under DARPA/AFRL contract
+ * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme.
+ *
+ * Portions of this software were developed by the University of Cambridge
+ * Computer Laboratory as part of the CTSRD Project, with support from the
+ * UK Higher Education Innovation Fund (HEIF).
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include <machine/setjmp.h>
+
+ENTRY(setjmp)
+ addi sp, sp, -(2 * 8)
+ sd a0, 0(sp)
+ sd ra, 8(sp)
+
+ /* Store the signal mask */
+ addi a2, a0, (_JB_SIGMASK * 8) /* oset */
+ li a1, 0 /* set */
+ li a0, 1 /* SIG_BLOCK */
+ jal sigprocmask
+
+ ld a0, 0(sp)
+ ld ra, 8(sp)
+ addi sp, sp, (2 * 8)
+
+ /* Store the magic value and stack pointer */
+ la t0, .Lmagic
+ ld t0, 0(t0)
+ sd t0, (0 * 8)(a0)
+ sd sp, (1 * 8)(a0)
+ addi a0, a0, (2 * 8)
+
+ /* Store the general purpose registers and ra */
+ sd s0, (0 * 8)(a0)
+ sd s1, (1 * 8)(a0)
+ sd s2, (2 * 8)(a0)
+ sd s3, (3 * 8)(a0)
+ sd s4, (4 * 8)(a0)
+ sd s5, (5 * 8)(a0)
+ sd s6, (6 * 8)(a0)
+ sd s7, (7 * 8)(a0)
+ sd s8, (8 * 8)(a0)
+ sd s9, (9 * 8)(a0)
+ sd s10, (10 * 8)(a0)
+ sd s11, (11 * 8)(a0)
+ sd ra, (12 * 8)(a0)
+ addi a0, a0, (13 * 8)
+
+#ifndef SOFTFLOAT
+ /* Store the fpe registers */
+ fsd fs0, (0 * 16)(a0)
+ fsd fs1, (1 * 16)(a0)
+ fsd fs2, (2 * 16)(a0)
+ fsd fs3, (3 * 16)(a0)
+ fsd fs4, (4 * 16)(a0)
+ fsd fs5, (5 * 16)(a0)
+ fsd fs6, (6 * 16)(a0)
+ fsd fs7, (7 * 16)(a0)
+ fsd fs8, (8 * 16)(a0)
+ fsd fs9, (9 * 16)(a0)
+ fsd fs10, (10 * 16)(a0)
+ fsd fs11, (11 * 16)(a0)
+ addi a0, a0, (12 * 16)
+#endif
+
+ /* Return value */
+ li a0, 0
+ ret
+ .align 3
+.Lmagic:
+ .quad _JB_MAGIC_SETJMP
+END(setjmp)
+
+ENTRY(longjmp)
+ addi sp, sp, -(4 * 8)
+ sd a0, (0 * 8)(sp)
+ sd ra, (1 * 8)(sp)
+ sd a1, (2 * 8)(sp)
+
+ /* Restore the signal mask */
+ li a2, 0 /* oset */
+ addi a1, a0, (_JB_SIGMASK * 8) /* set */
+ li a0, 3 /* SIG_BLOCK */
+ jal sigprocmask
+
+ ld a1, (2 * 8)(sp)
+ ld ra, (1 * 8)(sp)
+ ld a0, (0 * 8)(sp)
+ addi sp, sp, (4 * 8)
+
+ /* Check the magic value */
+ ld t0, 0(a0)
+ la t1, .Lmagic
+ ld t1, 0(t1)
+ bne t0, t1, botch
+
+ /* Restore the stack pointer */
+ ld t0, 8(a0)
+ mv sp, t0
+ addi a0, a0, (2 * 8)
+
+ /* Restore the general purpose registers and ra */
+ ld s0, (0 * 8)(a0)
+ ld s1, (1 * 8)(a0)
+ ld s2, (2 * 8)(a0)
+ ld s3, (3 * 8)(a0)
+ ld s4, (4 * 8)(a0)
+ ld s5, (5 * 8)(a0)
+ ld s6, (6 * 8)(a0)
+ ld s7, (7 * 8)(a0)
+ ld s8, (8 * 8)(a0)
+ ld s9, (9 * 8)(a0)
+ ld s10, (10 * 8)(a0)
+ ld s11, (11 * 8)(a0)
+ ld ra, (12 * 8)(a0)
+ addi a0, a0, (13 * 8)
+
+#ifndef SOFTFLOAT
+ /* Restore the fpe registers */
+ fld fs0, (0 * 16)(a0)
+ fld fs1, (1 * 16)(a0)
+ fld fs2, (2 * 16)(a0)
+ fld fs3, (3 * 16)(a0)
+ fld fs4, (4 * 16)(a0)
+ fld fs5, (5 * 16)(a0)
+ fld fs6, (6 * 16)(a0)
+ fld fs7, (7 * 16)(a0)
+ fld fs8, (8 * 16)(a0)
+ fld fs9, (9 * 16)(a0)
+ fld fs10, (10 * 16)(a0)
+ fld fs11, (11 * 16)(a0)
+ addi a0, a0, (12 * 16)
+#endif
+
+ /* Load the return value */
+ mv a0, a1
+ ret
+
+botch:
+ call _C_LABEL(longjmperror)
+ call _C_LABEL(abort)
+END(longjmp)
diff --git a/lib/libc/riscv/gen/sigsetjmp.S b/lib/libc/riscv/gen/sigsetjmp.S
new file mode 100644
index 000000000000..5d8a94d4d952
--- /dev/null
+++ b/lib/libc/riscv/gen/sigsetjmp.S
@@ -0,0 +1,57 @@
+/*-
+ * Copyright (c) 2015 Ruslan Bukin <br@bsdpad.com>
+ * All rights reserved.
+ *
+ * Portions of this software were developed by SRI International and the
+ * University of Cambridge Computer Laboratory under DARPA/AFRL contract
+ * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme.
+ *
+ * Portions of this software were developed by the University of Cambridge
+ * Computer Laboratory as part of the CTSRD Project, with support from the
+ * UK Higher Education Innovation Fund (HEIF).
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include <machine/setjmp.h>
+
+ENTRY(sigsetjmp)
+ beqz a1, _C_LABEL(_setjmp)
+ j _C_LABEL(setjmp)
+END(sigsetjmp)
+
+ENTRY(siglongjmp)
+ /* Load the _setjmp magic */
+ ld a2, .Lmagic
+ ld a3, 0(a0)
+
+ /* Check the magic */
+ beq a2, a3, _C_LABEL(_longjmp)
+ j _C_LABEL(longjmp)
+
+ .align 3
+.Lmagic:
+ .quad _JB_MAGIC__SETJMP
+END(siglongjmp)
diff --git a/lib/libc/riscv/softfloat/milieu.h b/lib/libc/riscv/softfloat/milieu.h
new file mode 100644
index 000000000000..e97437bdc2d1
--- /dev/null
+++ b/lib/libc/riscv/softfloat/milieu.h
@@ -0,0 +1,48 @@
+/* $FreeBSD$ */
+
+/*
+===============================================================================
+
+This C header file is part of the SoftFloat IEC/IEEE Floating-point
+Arithmetic Package, Release 2a.
+
+Written by John R. Hauser. This work was made possible in part by the
+International Computer Science Institute, located at Suite 600, 1947 Center
+Street, Berkeley, California 94704. Funding was partially provided by the
+National Science Foundation under grant MIP-9311980. The original version
+of this code was written as part of a project to build a fixed-point vector
+processor in collaboration with the University of California at Berkeley,
+overseen by Profs. Nelson Morgan and John Wawrzynek. More information
+is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
+arithmetic/SoftFloat.html'.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
+has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
+TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
+PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
+AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
+
+Derivative works are acceptable, even for commercial purposes, so long as
+(1) they include prominent notice that the work is derivative, and (2) they
+include prominent notice akin to these four paragraphs for those parts of
+this code that are retained.
+
+===============================================================================
+*/
+
+/*
+-------------------------------------------------------------------------------
+Include common integer types and flags.
+-------------------------------------------------------------------------------
+*/
+#include "riscv-gcc.h"
+
+/*
+-------------------------------------------------------------------------------
+Symbolic Boolean literals.
+-------------------------------------------------------------------------------
+*/
+enum {
+ FALSE = 0,
+ TRUE = 1
+};
diff --git a/lib/libc/riscv/softfloat/riscv-gcc.h b/lib/libc/riscv/softfloat/riscv-gcc.h
new file mode 100644
index 000000000000..3fe1767e63cc
--- /dev/null
+++ b/lib/libc/riscv/softfloat/riscv-gcc.h
@@ -0,0 +1,86 @@
+/* $NetBSD: arm-gcc.h,v 1.2 2001/02/21 18:09:25 bjh21 Exp $ */
+/* $FreeBSD$ */
+
+/*
+-------------------------------------------------------------------------------
+One of the macros `BIGENDIAN' or `LITTLEENDIAN' must be defined.
+-------------------------------------------------------------------------------
+*/
+#define LITTLEENDIAN
+
+/*
+-------------------------------------------------------------------------------
+The macro `BITS64' can be defined to indicate that 64-bit integer types are
+supported by the compiler.
+-------------------------------------------------------------------------------
+*/
+#define BITS64
+
+/*
+-------------------------------------------------------------------------------
+Each of the following `typedef's defines the most convenient type that holds
+integers of at least as many bits as specified. For example, `uint8' should
+be the most convenient type that can hold unsigned integers of as many as
+8 bits. The `flag' type must be able to hold either a 0 or 1. For most
+implementations of C, `flag', `uint8', and `int8' should all be `typedef'ed
+to the same as `int'.
+-------------------------------------------------------------------------------
+*/
+typedef int flag;
+typedef int uint8;
+typedef int int8;
+typedef int uint16;
+typedef int int16;
+typedef unsigned int uint32;
+typedef signed int int32;
+#ifdef BITS64
+typedef unsigned long long int uint64;
+typedef signed long long int int64;
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Each of the following `typedef's defines a type that holds integers
+of _exactly_ the number of bits specified. For instance, for most
+implementation of C, `bits16' and `sbits16' should be `typedef'ed to
+`unsigned short int' and `signed short int' (or `short int'), respectively.
+-------------------------------------------------------------------------------
+*/
+typedef unsigned char bits8;
+typedef signed char sbits8;
+typedef unsigned short int bits16;
+typedef signed short int sbits16;
+typedef unsigned int bits32;
+typedef signed int sbits32;
+#ifdef BITS64
+typedef unsigned long long int bits64;
+typedef signed long long int sbits64;
+#endif
+
+#ifdef BITS64
+/*
+-------------------------------------------------------------------------------
+The `LIT64' macro takes as its argument a textual integer literal and
+if necessary ``marks'' the literal as having a 64-bit integer type.
+For example, the GNU C Compiler (`gcc') requires that 64-bit literals be
+appended with the letters `LL' standing for `long long', which is `gcc's
+name for the 64-bit integer type. Some compilers may allow `LIT64' to be
+defined as the identity macro: `#define LIT64( a ) a'.
+-------------------------------------------------------------------------------
+*/
+#define LIT64( a ) a##LL
+#endif
+
+/*
+-------------------------------------------------------------------------------
+The macro `INLINE' can be used before functions that should be inlined. If
+a compiler does not support explicit inlining, this macro should be defined
+to be `static'.
+-------------------------------------------------------------------------------
+*/
+#define INLINE static __inline
+
+#if defined(SOFTFLOAT_FOR_GCC)
+#define FLOAT64_DEMANGLE(a) (a)
+#define FLOAT64_MANGLE(a) (a)
+#endif
diff --git a/lib/libc/riscv/softfloat/softfloat.h b/lib/libc/riscv/softfloat/softfloat.h
new file mode 100644
index 000000000000..6aef49975a38
--- /dev/null
+++ b/lib/libc/riscv/softfloat/softfloat.h
@@ -0,0 +1,315 @@
+/* $NetBSD: softfloat.h,v 1.6 2002/05/12 13:12:46 bjh21 Exp $ */
+/* $FreeBSD$ */
+
+/* This is a derivative work. */
+
+/*
+===============================================================================
+
+This C header file is part of the SoftFloat IEC/IEEE Floating-point
+Arithmetic Package, Release 2a.
+
+Written by John R. Hauser. This work was made possible in part by the
+International Computer Science Institute, located at Suite 600, 1947 Center
+Street, Berkeley, California 94704. Funding was partially provided by the
+National Science Foundation under grant MIP-9311980. The original version
+of this code was written as part of a project to build a fixed-point vector
+processor in collaboration with the University of California at Berkeley,
+overseen by Profs. Nelson Morgan and John Wawrzynek. More information
+is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
+arithmetic/SoftFloat.html'.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
+has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
+TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
+PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
+AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
+
+Derivative works are acceptable, even for commercial purposes, so long as
+(1) they include prominent notice that the work is derivative, and (2) they
+include prominent notice akin to these four paragraphs for those parts of
+this code that are retained.
+
+===============================================================================
+*/
+
+/*
+-------------------------------------------------------------------------------
+The macro `FLOATX80' must be defined to enable the extended double-precision
+floating-point format `floatx80'. If this macro is not defined, the
+`floatx80' type will not be defined, and none of the functions that either
+input or output the `floatx80' type will be defined. The same applies to
+the `FLOAT128' macro and the quadruple-precision format `float128'.
+-------------------------------------------------------------------------------
+*/
+/* #define FLOATX80 */
+/* #define FLOAT128 */
+
+#include <fenv.h>
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE floating-point types.
+-------------------------------------------------------------------------------
+*/
+typedef unsigned int float32;
+typedef unsigned long long float64;
+#ifdef FLOATX80
+typedef struct {
+ unsigned short high;
+ unsigned long long low;
+} floatx80;
+#endif
+#ifdef FLOAT128
+typedef struct {
+ unsigned long long high, low;
+} float128;
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE floating-point underflow tininess-detection mode.
+-------------------------------------------------------------------------------
+*/
+#ifndef SOFTFLOAT_FOR_GCC
+extern int float_detect_tininess;
+#endif
+enum {
+ float_tininess_after_rounding = 0,
+ float_tininess_before_rounding = 1
+};
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE floating-point rounding mode.
+-------------------------------------------------------------------------------
+*/
+extern int float_rounding_mode;
+enum {
+ float_round_nearest_even = FE_TONEAREST,
+ float_round_to_zero = FE_TOWARDZERO,
+ float_round_down = FE_DOWNWARD,
+ float_round_up = FE_UPWARD
+};
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE floating-point exception flags.
+-------------------------------------------------------------------------------
+*/
+extern int float_exception_flags;
+extern int float_exception_mask;
+enum {
+ float_flag_inexact = FE_INEXACT,
+ float_flag_underflow = FE_UNDERFLOW,
+ float_flag_overflow = FE_OVERFLOW,
+ float_flag_divbyzero = FE_DIVBYZERO,
+ float_flag_invalid = FE_INVALID
+};
+
+/*
+-------------------------------------------------------------------------------
+Routine to raise any or all of the software IEC/IEEE floating-point
+exception flags.
+-------------------------------------------------------------------------------
+*/
+void float_raise( int );
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE integer-to-floating-point conversion routines.
+-------------------------------------------------------------------------------
+*/
+float32 int32_to_float32( int );
+float64 int32_to_float64( int );
+#ifdef FLOATX80
+floatx80 int32_to_floatx80( int );
+#endif
+#ifdef FLOAT128
+float128 int32_to_float128( int );
+#endif
+#ifndef SOFTFLOAT_FOR_GCC /* __floatdi?f is in libgcc2.c */
+float32 int64_to_float32( long long );
+float64 int64_to_float64( long long );
+#ifdef FLOATX80
+floatx80 int64_to_floatx80( long long );
+#endif
+#ifdef FLOAT128
+float128 int64_to_float128( long long );
+#endif
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE single-precision conversion routines.
+-------------------------------------------------------------------------------
+*/
+int float32_to_int32( float32 );
+int float32_to_int32_round_to_zero( float32 );
+#if defined(SOFTFLOAT_FOR_GCC) && defined(SOFTFLOAT_NEED_FIXUNS)
+unsigned int float32_to_uint32_round_to_zero( float32 );
+#endif
+#ifndef SOFTFLOAT_FOR_GCC /* __fix?fdi provided by libgcc2.c */
+long long float32_to_int64( float32 );
+long long float32_to_int64_round_to_zero( float32 );
+#endif
+float64 float32_to_float64( float32 );
+#ifdef FLOATX80
+floatx80 float32_to_floatx80( float32 );
+#endif
+#ifdef FLOAT128
+float128 float32_to_float128( float32 );
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE single-precision operations.
+-------------------------------------------------------------------------------
+*/
+float32 float32_round_to_int( float32 );
+float32 float32_add( float32, float32 );
+float32 float32_sub( float32, float32 );
+float32 float32_mul( float32, float32 );
+float32 float32_div( float32, float32 );
+float32 float32_rem( float32, float32 );
+float32 float32_sqrt( float32 );
+int float32_eq( float32, float32 );
+int float32_le( float32, float32 );
+int float32_lt( float32, float32 );
+int float32_eq_signaling( float32, float32 );
+int float32_le_quiet( float32, float32 );
+int float32_lt_quiet( float32, float32 );
+#ifndef SOFTFLOAT_FOR_GCC
+int float32_is_signaling_nan( float32 );
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE double-precision conversion routines.
+-------------------------------------------------------------------------------
+*/
+int float64_to_int32( float64 );
+int float64_to_int32_round_to_zero( float64 );
+#if defined(SOFTFLOAT_FOR_GCC) && defined(SOFTFLOAT_NEED_FIXUNS)
+unsigned int float64_to_uint32_round_to_zero( float64 );
+#endif
+#ifndef SOFTFLOAT_FOR_GCC /* __fix?fdi provided by libgcc2.c */
+long long float64_to_int64( float64 );
+long long float64_to_int64_round_to_zero( float64 );
+#endif
+float32 float64_to_float32( float64 );
+#ifdef FLOATX80
+floatx80 float64_to_floatx80( float64 );
+#endif
+#ifdef FLOAT128
+float128 float64_to_float128( float64 );
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE double-precision operations.
+-------------------------------------------------------------------------------
+*/
+float64 float64_round_to_int( float64 );
+float64 float64_add( float64, float64 );
+float64 float64_sub( float64, float64 );
+float64 float64_mul( float64, float64 );
+float64 float64_div( float64, float64 );
+float64 float64_rem( float64, float64 );
+float64 float64_sqrt( float64 );
+int float64_eq( float64, float64 );
+int float64_le( float64, float64 );
+int float64_lt( float64, float64 );
+int float64_eq_signaling( float64, float64 );
+int float64_le_quiet( float64, float64 );
+int float64_lt_quiet( float64, float64 );
+#ifndef SOFTFLOAT_FOR_GCC
+int float64_is_signaling_nan( float64 );
+#endif
+
+#ifdef FLOATX80
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE extended double-precision conversion routines.
+-------------------------------------------------------------------------------
+*/
+int floatx80_to_int32( floatx80 );
+int floatx80_to_int32_round_to_zero( floatx80 );
+long long floatx80_to_int64( floatx80 );
+long long floatx80_to_int64_round_to_zero( floatx80 );
+float32 floatx80_to_float32( floatx80 );
+float64 floatx80_to_float64( floatx80 );
+#ifdef FLOAT128
+float128 floatx80_to_float128( floatx80 );
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE extended double-precision rounding precision. Valid
+values are 32, 64, and 80.
+-------------------------------------------------------------------------------
+*/
+extern int floatx80_rounding_precision;
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE extended double-precision operations.
+-------------------------------------------------------------------------------
+*/
+floatx80 floatx80_round_to_int( floatx80 );
+floatx80 floatx80_add( floatx80, floatx80 );
+floatx80 floatx80_sub( floatx80, floatx80 );
+floatx80 floatx80_mul( floatx80, floatx80 );
+floatx80 floatx80_div( floatx80, floatx80 );
+floatx80 floatx80_rem( floatx80, floatx80 );
+floatx80 floatx80_sqrt( floatx80 );
+int floatx80_eq( floatx80, floatx80 );
+int floatx80_le( floatx80, floatx80 );
+int floatx80_lt( floatx80, floatx80 );
+int floatx80_eq_signaling( floatx80, floatx80 );
+int floatx80_le_quiet( floatx80, floatx80 );
+int floatx80_lt_quiet( floatx80, floatx80 );
+int floatx80_is_signaling_nan( floatx80 );
+
+#endif
+
+#ifdef FLOAT128
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE quadruple-precision conversion routines.
+-------------------------------------------------------------------------------
+*/
+int float128_to_int32( float128 );
+int float128_to_int32_round_to_zero( float128 );
+long long float128_to_int64( float128 );
+long long float128_to_int64_round_to_zero( float128 );
+float32 float128_to_float32( float128 );
+float64 float128_to_float64( float128 );
+#ifdef FLOATX80
+floatx80 float128_to_floatx80( float128 );
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE quadruple-precision operations.
+-------------------------------------------------------------------------------
+*/
+float128 float128_round_to_int( float128 );
+float128 float128_add( float128, float128 );
+float128 float128_sub( float128, float128 );
+float128 float128_mul( float128, float128 );
+float128 float128_div( float128, float128 );
+float128 float128_rem( float128, float128 );
+float128 float128_sqrt( float128 );
+int float128_eq( float128, float128 );
+int float128_le( float128, float128 );
+int float128_lt( float128, float128 );
+int float128_eq_signaling( float128, float128 );
+int float128_le_quiet( float128, float128 );
+int float128_lt_quiet( float128, float128 );
+int float128_is_signaling_nan( float128 );
+
+#endif
+
diff --git a/lib/libc/riscv/sys/Makefile.inc b/lib/libc/riscv/sys/Makefile.inc
new file mode 100644
index 000000000000..00f1af11df35
--- /dev/null
+++ b/lib/libc/riscv/sys/Makefile.inc
@@ -0,0 +1,13 @@
+# $FreeBSD$
+
+SRCS+= trivial-vdso_tc.c
+
+#MDASM= ptrace.S
+MDASM= cerror.S \
+ shmat.S \
+ sigreturn.S \
+ syscall.S \
+ vfork.S
+
+# Don't generate default code for these syscalls:
+NOASM+= vfork.o
diff --git a/lib/libc/riscv/sys/cerror.S b/lib/libc/riscv/sys/cerror.S
new file mode 100644
index 000000000000..117080e0b3d9
--- /dev/null
+++ b/lib/libc/riscv/sys/cerror.S
@@ -0,0 +1,50 @@
+/*-
+ * Copyright (c) 2015 Ruslan Bukin <br@bsdpad.com>
+ * All rights reserved.
+ *
+ * Portions of this software were developed by SRI International and the
+ * University of Cambridge Computer Laboratory under DARPA/AFRL contract
+ * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme.
+ *
+ * Portions of this software were developed by the University of Cambridge
+ * Computer Laboratory as part of the CTSRD Project, with support from the
+ * UK Higher Education Innovation Fund (HEIF).
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+ENTRY(cerror)
+ addi sp, sp, -16
+ sd a0, 0(sp)
+ sd ra, 8(sp)
+ call _C_LABEL(__error)
+ ld a1, 0(sp)
+ ld ra, 8(sp)
+ sw a1, 0(a0)
+ li a0, -1
+ li a1, -1
+ addi sp, sp, 16
+ ret
+END(cerror)
diff --git a/lib/libc/riscv/sys/shmat.S b/lib/libc/riscv/sys/shmat.S
new file mode 100644
index 000000000000..3a5b4bcc5353
--- /dev/null
+++ b/lib/libc/riscv/sys/shmat.S
@@ -0,0 +1,40 @@
+/*-
+ * Copyright (c) 2015 Ruslan Bukin <br@bsdpad.com>
+ * All rights reserved.
+ *
+ * Portions of this software were developed by SRI International and the
+ * University of Cambridge Computer Laboratory under DARPA/AFRL contract
+ * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme.
+ *
+ * Portions of this software were developed by the University of Cambridge
+ * Computer Laboratory as part of the CTSRD Project, with support from the
+ * UK Higher Education Innovation Fund (HEIF).
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+RSYSCALL(shmat)
diff --git a/lib/libc/riscv/sys/sigreturn.S b/lib/libc/riscv/sys/sigreturn.S
new file mode 100644
index 000000000000..dfaee7a1233a
--- /dev/null
+++ b/lib/libc/riscv/sys/sigreturn.S
@@ -0,0 +1,40 @@
+/*-
+ * Copyright (c) 2015 Ruslan Bukin <br@bsdpad.com>
+ * All rights reserved.
+ *
+ * Portions of this software were developed by SRI International and the
+ * University of Cambridge Computer Laboratory under DARPA/AFRL contract
+ * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme.
+ *
+ * Portions of this software were developed by the University of Cambridge
+ * Computer Laboratory as part of the CTSRD Project, with support from the
+ * UK Higher Education Innovation Fund (HEIF).
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+RSYSCALL(sigreturn)
diff --git a/lib/libc/riscv/sys/syscall.S b/lib/libc/riscv/sys/syscall.S
new file mode 100644
index 000000000000..8a007f8c7f17
--- /dev/null
+++ b/lib/libc/riscv/sys/syscall.S
@@ -0,0 +1,40 @@
+/*-
+ * Copyright (c) 2015 Ruslan Bukin <br@bsdpad.com>
+ * All rights reserved.
+ *
+ * Portions of this software were developed by SRI International and the
+ * University of Cambridge Computer Laboratory under DARPA/AFRL contract
+ * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme.
+ *
+ * Portions of this software were developed by the University of Cambridge
+ * Computer Laboratory as part of the CTSRD Project, with support from the
+ * UK Higher Education Innovation Fund (HEIF).
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+RSYSCALL(syscall)
diff --git a/lib/libc/riscv/sys/vfork.S b/lib/libc/riscv/sys/vfork.S
new file mode 100644
index 000000000000..a5057802b6c0
--- /dev/null
+++ b/lib/libc/riscv/sys/vfork.S
@@ -0,0 +1,51 @@
+/*-
+ * Copyright (c) 2015 Ruslan Bukin <br@bsdpad.com>
+ * All rights reserved.
+ *
+ * Portions of this software were developed by SRI International and the
+ * University of Cambridge Computer Laboratory under DARPA/AFRL contract
+ * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme.
+ *
+ * Portions of this software were developed by the University of Cambridge
+ * Computer Laboratory as part of the CTSRD Project, with support from the
+ * UK Higher Education Innovation Fund (HEIF).
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+#include "SYS.h"
+
+ENTRY(__sys_vfork)
+ WEAK_REFERENCE(__sys_vfork, vfork)
+ WEAK_REFERENCE(__sys_vfork, _vfork)
+ mv a2, ra
+
+ _SYSCALL(vfork)
+ bnez t0, cerror
+ addi a1, a1, -1
+ and a0, a0, a1
+ mv ra, a2
+
+ ret
+END(__sys_vfork)
diff --git a/lib/libc/rpc/DISCLAIMER b/lib/libc/rpc/DISCLAIMER
new file mode 100644
index 000000000000..d8dcb7ffd4a6
--- /dev/null
+++ b/lib/libc/rpc/DISCLAIMER
@@ -0,0 +1,60 @@
+/* $NetBSD: DISCLAIMER,v 1.2 1998/01/09 04:11:51 perry Exp $ */
+/* $FreeBSD$ */
+
+/*-
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*-
+ * Copyright (c) 2010, Oracle America, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ * * Neither the name of the "Oracle America, Inc." nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
diff --git a/lib/libc/rpc/Makefile.inc b/lib/libc/rpc/Makefile.inc
new file mode 100644
index 000000000000..c3e5502d68df
--- /dev/null
+++ b/lib/libc/rpc/Makefile.inc
@@ -0,0 +1,179 @@
+# @(#)Makefile 5.11 (Berkeley) 9/6/90
+# $FreeBSD$
+
+.PATH: ${LIBC_SRCTOP}/rpc ${LIBC_SRCTOP}/.
+SRCS+= auth_none.c auth_unix.c authunix_prot.c bindresvport.c clnt_bcast.c \
+ clnt_dg.c clnt_generic.c clnt_perror.c clnt_raw.c clnt_simple.c \
+ clnt_vc.c rpc_dtablesize.c getnetconfig.c getnetpath.c getrpcent.c \
+ getrpcport.c mt_misc.c pmap_clnt.c pmap_getmaps.c pmap_getport.c \
+ pmap_prot.c pmap_prot2.c pmap_rmt.c rpc_prot.c rpc_commondata.c \
+ rpc_callmsg.c rpc_generic.c rpc_soc.c rpcb_clnt.c rpcb_prot.c \
+ rpcb_st_xdr.c rpcsec_gss_stub.c svc.c svc_auth.c svc_dg.c \
+ svc_auth_unix.c svc_generic.c svc_raw.c svc_run.c svc_simple.c \
+ svc_vc.c
+
+# Secure-RPC
+SRCS+= auth_time.c auth_des.c authdes_prot.c des_crypt.c des_soft.c \
+ crypt_client.c key_call.c key_prot_xdr.c getpublickey.c \
+ svc_auth_des.c
+
+# Resolver stuff
+SRCS+= netname.c netnamer.c rpcdname.c
+
+# Misc Source
+SRCS+= rtime.c
+
+# generated sources
+SRCS+= crypt_clnt.c crypt_xdr.c crypt.h
+
+SYM_MAPS+=${LIBC_SRCTOP}/rpc/Symbol.map
+
+CFLAGS+= -DBROKEN_DES -DPORTMAP -DDES_BUILTIN
+CFLAGS+= -I${LIBC_SRCTOP}/rpc
+
+CLEANFILES+= crypt_clnt.c crypt_xdr.c crypt.h
+
+RPCDIR= ${SRCTOP}/include/rpcsvc
+RPCGEN= RPCGEN_CPP=${CPP:Q} rpcgen -C
+
+crypt_clnt.c: ${RPCDIR}/crypt.x crypt.h
+ ${RPCGEN} -l -o ${.TARGET} ${RPCDIR}/crypt.x
+
+crypt_xdr.c: ${RPCDIR}/crypt.x crypt.h
+ ${RPCGEN} -c -o ${.TARGET} ${RPCDIR}/crypt.x
+
+crypt.h: ${RPCDIR}/crypt.x
+ ${RPCGEN} -h -o ${.TARGET} ${RPCDIR}/crypt.x
+MAN+= bindresvport.3 des_crypt.3 getnetconfig.3 getnetpath.3 getrpcent.3 \
+ getrpcport.3 rpc.3 rpc_soc.3 rpc_clnt_auth.3 rpc_clnt_calls.3 \
+ rpc_clnt_create.3 rpc_svc_calls.3 rpc_svc_create.3 rpc_svc_err.3 \
+ rpc_svc_reg.3 rpc_xdr.3 rpcbind.3 publickey.3 rpc_secure.3 \
+ rtime.3
+MAN+= publickey.5 rpc.5 netconfig.5
+MLINKS+= bindresvport.3 bindresvport_sa.3 \
+ des_crypt.3 ecb_crypt.3 \
+ des_crypt.3 cbc_crypt.3 \
+ des_crypt.3 des_setparity.3 \
+ getnetconfig.3 setnetconfig.3 \
+ getnetconfig.3 getnetconfigent.3 \
+ getnetconfig.3 freenetconfigent.3 \
+ getnetconfig.3 endnetconfig.3 \
+ getnetconfig.3 nc_perror.3 \
+ getnetconfig.3 nc_sperror.3 \
+ getnetpath.3 setnetpath.3 \
+ getnetpath.3 endnetpath.3 \
+ getrpcent.3 getrpcbyname.3 \
+ getrpcent.3 getrpcbynumber.3 \
+ getrpcent.3 endrpcent.3 \
+ getrpcent.3 setrpcent.3 \
+ publickey.3 getpublickey.3 \
+ publickey.3 getsecretkey.3 \
+ rpc_clnt_auth.3 auth_destroy.3 \
+ rpc_clnt_auth.3 authnone_create.3 \
+ rpc_clnt_auth.3 authsys_create.3 \
+ rpc_clnt_auth.3 authsys_create_default.3 \
+ rpc_clnt_calls.3 clnt_call.3 \
+ rpc_clnt_calls.3 clnt_perrno.3 \
+ rpc_clnt_calls.3 clnt_perror.3 \
+ rpc_clnt_calls.3 clnt_sperrno.3 \
+ rpc_clnt_calls.3 clnt_sperror.3 \
+ rpc_clnt_calls.3 rpc_call.3 \
+ rpc_clnt_calls.3 rpc_broadcast.3 \
+ rpc_clnt_calls.3 rpc_broadcast_exp.3 \
+ rpc_clnt_calls.3 clnt_freeres.3 \
+ rpc_clnt_calls.3 clnt_geterr.3 \
+ rpc_clnt_create.3 clnt_control.3 \
+ rpc_clnt_create.3 clnt_create.3 \
+ rpc_clnt_create.3 clnt_create_timed.3 \
+ rpc_clnt_create.3 clnt_create_vers.3 \
+ rpc_clnt_create.3 clnt_create_vers_timed.3 \
+ rpc_clnt_create.3 clnt_destroy.3 \
+ rpc_clnt_create.3 clnt_pcreateerror.3 \
+ rpc_clnt_create.3 clnt_spcreateerror.3 \
+ rpc_clnt_create.3 clnt_dg_create.3 \
+ rpc_clnt_create.3 clnt_raw_create.3 \
+ rpc_clnt_create.3 clnt_tli_create.3 \
+ rpc_clnt_create.3 clnt_tp_create.3 \
+ rpc_clnt_create.3 clnt_tp_create_timed.3 \
+ rpc_clnt_create.3 clnt_vc_create.3 \
+ rpc_secure.3 authdes_create.3 \
+ rpc_secure.3 authdes_getucred.3 \
+ rpc_secure.3 getnetname.3 \
+ rpc_secure.3 host2netname.3 \
+ rpc_secure.3 key_decryptsession.3 \
+ rpc_secure.3 key_encryptsession.3 \
+ rpc_secure.3 key_gendes.3 \
+ rpc_secure.3 key_setsecret.3 \
+ rpc_secure.3 netname2host.3 \
+ rpc_secure.3 netname2user.3 \
+ rpc_secure.3 user2netname.3 \
+ rpc_svc_calls.3 svc_dg_enablecache.3 \
+ rpc_svc_calls.3 svc_exit.3 \
+ rpc_svc_calls.3 svc_freeargs.3 \
+ rpc_svc_calls.3 svc_getargs.3 \
+ rpc_svc_calls.3 svc_getreq_common.3 \
+ rpc_svc_calls.3 svc_getreq_poll.3 \
+ rpc_svc_calls.3 svc_getreqset.3 \
+ rpc_svc_calls.3 svc_getrpccaller.3 \
+ rpc_svc_calls.3 __svc_getcallercreds.3 \
+ rpc_svc_calls.3 svc_pollset.3 \
+ rpc_svc_calls.3 svc_run.3 \
+ rpc_svc_calls.3 svc_sendreply.3 \
+ rpc_svc_create.3 svc_control.3 \
+ rpc_svc_create.3 svc_create.3 \
+ rpc_svc_create.3 svc_dg_create.3 \
+ rpc_svc_create.3 svc_destroy.3 \
+ rpc_svc_create.3 svc_fd_create.3 \
+ rpc_svc_create.3 svc_raw_create.3 \
+ rpc_svc_create.3 svc_tli_create.3 \
+ rpc_svc_create.3 svc_tp_create.3 \
+ rpc_svc_create.3 svc_vc_create.3 \
+ rpc_svc_err.3 svcerr_auth.3 \
+ rpc_svc_err.3 svcerr_decode.3 \
+ rpc_svc_err.3 svcerr_noproc.3 \
+ rpc_svc_err.3 svcerr_noprog.3 \
+ rpc_svc_err.3 svcerr_progvers.3 \
+ rpc_svc_err.3 svcerr_systemerr.3 \
+ rpc_svc_err.3 svcerr_weakauth.3 \
+ rpc_svc_reg.3 rpc_reg.3 \
+ rpc_svc_reg.3 svc_reg.3 \
+ rpc_svc_reg.3 svc_unreg.3 \
+ rpc_svc_reg.3 svc_auth_reg.3 \
+ rpc_svc_reg.3 xprt_register.3 \
+ rpc_svc_reg.3 xprt_unregister.3 \
+ rpcbind.3 rpcb_getmaps.3 \
+ rpcbind.3 rpcb_getaddr.3 \
+ rpcbind.3 rpcb_gettime.3 \
+ rpcbind.3 rpcb_rmtcall.3 \
+ rpcbind.3 rpcb_set.3 \
+ rpcbind.3 rpcb_unset.3 \
+ rpc_soc.3 authunix_create.3 \
+ rpc_soc.3 authunix_create_default.3 \
+ rpc_soc.3 callrpc.3 \
+ rpc_soc.3 clnt_broadcast.3 \
+ rpc_soc.3 clntraw_create.3 \
+ rpc_soc.3 clnttcp_create.3 \
+ rpc_soc.3 clntunix_create.3 \
+ rpc_soc.3 clntudp_bufcreate.3 \
+ rpc_soc.3 clntudp_create.3 \
+ rpc_soc.3 get_myaddress.3 \
+ rpc_soc.3 pmap_getmaps.3 \
+ rpc_soc.3 pmap_getport.3 \
+ rpc_soc.3 pmap_rmtcall.3 \
+ rpc_soc.3 pmap_set.3 \
+ rpc_soc.3 pmap_unset.3 \
+ rpc_soc.3 registerrpc.3 \
+ rpc_soc.3 rpc_createerr.3 \
+ rpc_soc.3 svc_fds.3 \
+ rpc_soc.3 svc_fdset.3 \
+ rpc_soc.3 svc_getcaller.3 \
+ rpc_soc.3 svc_register.3 \
+ rpc_soc.3 svc_unregister.3 \
+ rpc_soc.3 svcfd_create.3 \
+ rpc_soc.3 svcunixfd_create.3 \
+ rpc_soc.3 svcraw_create.3 \
+ rpc_soc.3 svctcp_create.3 \
+ rpc_soc.3 svcudp_bufcreate.3 \
+ rpc_soc.3 svcunix_create.3 \
+ rpc_soc.3 xdr_pmap.3 \
+ rpc_soc.3 xdr_pmaplist.3
diff --git a/lib/libc/rpc/README b/lib/libc/rpc/README
new file mode 100644
index 000000000000..129fe0082d6d
--- /dev/null
+++ b/lib/libc/rpc/README
@@ -0,0 +1,176 @@
+$FreeBSD$
+
+PLEASE READ THE DISCLAIMER FILE. DO NOT CALL THE SUN MICROSYSTEMS SUPPORT
+LINE WITH QUESTIONS ON THIS RELEASE. THEY CANNOT ANSWER QUESTIONS ABOUT THIS
+UNSUPPORTED SOURCE RELEASE.
+
+TIRPCSRC 2.3 29 Aug 1994
+
+This distribution contains SunSoft's implementation of transport-independent
+RPC (TI-RPC), External Data Representation (XDR), and various utilities and
+documentation. These libraries and programs form the base of Open Network
+Computing (ONC), and are derived directly from the Solaris 2.3 source.
+
+Previous releases of RPC Source based on SunOS 4.x were ported to 4.2BSD and
+used Sockets as the transport interface. These versions were
+transport-specific RPC (TS-RPC).
+
+TI-RPC is an enhanced version of TS-RPC that requires the UNIX System V
+Transport Layer Interface (TLI) or an equivalent X/Open Transport Interface
+(XTI). TI-RPC is on-the-wire compatible with the TS-RPC, which is supported
+by almost 70 vendors on all major operating systems. TS-RPC source code
+(RPCSRC 4.0) remains available from several internet sites.
+
+This release is a native source release, that is, it is compatible for
+building on Solaris 2.3. This release was built on Solaris 2.3 using SunPro
+SPARCompiler 2.0.1.
+
+Solaris 2.3 is based on System V, Release 4 (SVR4), and while this release
+should be mostly compatible with other SVR4 systems, some Solaris facilities
+that are assumed may not be available. In particular, this release uses the
+Makefile format supported by SparcCompiler 2.0.1. Second, the Secure RPC
+routines use the Solaris Name Service Switch to access public-key credential
+databases. This code will need to be ported if your system does not support
+the Name Service Switch. Finally, this release uses the synchronization
+interfaces of UI Threads to make certain interfaces thread-safe. These
+interfaces are found in libthread in Solaris 2.3 and later.
+
+Applications linked with this release's librpc must link with the United
+States domestic version of libcrypt in order to resolve the cbc_crypt() and
+ecb_crypt() functions. These routines are used with Secure RPC however all
+RPC programs that link with this release's librpc will need to link with the
+domestic libcrypt. Note that the Solaris 2.3 Encryption Kit is only available
+within the United States. (PLEASE NOTE: The RPC implementation found in
+Solaris 2.3's libnsl does *not* have this requirement; linking with libcrypt
+is only a requirement for the TIRPCSRC 2.3 version of librpc.)
+
+
+DOCUMENTATION NOTE
+
+The documentation found in the doc directory are derived from the Solaris 2.3
+Network Interfaces Programming Guide. A small number of compile examples are
+given, and these use libnsl to link in the RPC library. This release builds
+the RPC library as librpc. To use this release's librpc, use the link command
+"-lrpc -lnsl -lcrypt". This links the application with TIRPCSRC 2.3's librpc
+for RPC routines, Solaris's libnsl for other networking functions, and
+libcrypt for the cbc_crypt() and ecb_crypt functions.
+
+
+WHY IS THIS RELEASE BEING DONE?
+
+This release is being distributed to make the Sun implementation of the ONC
+technologies available for reference and porting to non-Solaris platforms.
+The current release is a native source distribution, and provides services
+that are already available on Solaris 2.3 (such as the RPC headers, the RPC
+library in libnsl, rpcbind, rpcinfo, etc.). It is not our intention to
+replace these services. See the DISCLAIMER for further information about the
+legal status of this release.
+
+
+WHAT'S NEW IN THIS RELEASE: TIRPCSRC 2.3
+
+The previous release was TIRPCSRC 2.0.
+
+1. This release is based on Solaris 2.3. The previous release was
+ based on Solaris 2.0. This release contains a significant number of
+ bug fixes and other enhancements over TIRPCSRC 2.0.
+
+2. The RPC library is thread safe for all client-side interfaces
+ (clnt_create, clnt_call, etc.). The server-side interfaces
+ (svc_create, svc_run, etc.) are not thread safe in this release. The
+ server-side interfaces will be made thread safe in the next release of
+ TIRPCSRC. Please see the manual pages for details about which
+ interfaces are thread safe.
+
+3. As part of the work to make the RPC library thread-safe, rpcgen has
+ been enhanced to generate thread-safe RPC stubs (the -M option). Note
+ that this modifies the call-signature for the stub functions; the
+ procedure calling the RPC stub must now pass to the stub a pointer to
+ an allocated structure where results will be placed by the stub. See
+ the rpcgen manual page and the rpcgen Programming Guide for details.
+
+4. The Remote Asynchronous Calls (RAC) library is now included. RAC was
+ first introduced in TIRPCSRC 1.0, and was bundled with librpc. It is
+ now a separate library. The asynchronous call model that RAC provides
+ can be achieved by using threads for making client-side RPC calls.
+ The ONC Technology group recommends using threads (where possible) to
+ achieve asynchrony rather than RAC. See the rpc_rac(3n) manual page
+ for details.
+
+
+ROADMAP
+
+The directory hierarchy is as follows:
+
+ cmd/ Utilities
+ cmd/rpcgen The RPC Language compiler (for .x files)
+ cmd/rpcbind The RPC bindery and portmapper
+ cmd/rpcinfo RPC bindery query utility
+ cmd/keyserv The Secure RPC keyserver
+ cmd/demo Some simple ONC demo services
+
+ doc/ Postscript versions of ONC documentation
+
+ head/ Header files
+ head/rpcsvc RPCL (.x) specifications for various ONC services, and
+ header files.
+
+ lib/ Libraries
+ lib/librpc The RPC and XDR library
+ lib/librac The Remote Asynchronous Calls (RAC) library
+
+ man/ Manual pages for the RPC library and utilities.
+
+ uts/common/rpc RPC header files
+
+
+
+BUILD INSTRUCTIONS
+
+Prior to building the release, you must define the SRC environment variable
+to be the path to the top-level Makefile. For example, if /usr/src/tirpcsrc
+is where to top-level Makefile is located, execute this command prior to
+building the release:
+
+ setenv SRC /usr/src/tirpcsrc (csh)
+or
+ SRC=/usr/src/tirpcsrc; export SRC (sh)
+
+The sources in the lib directory depend on header files installed from head
+and uts/common/rpc, and the programs in the cmd directory depend on libraries
+from lib. Therefore, you should do a "make install" to build the release.
+
+The top-level Makefile builds the release. The "ROOT" macro defines where the
+headers and libraries are installed. The default for ROOT is "/proto". You
+may change this by either modifiying Makefile.master, or issuing the build
+command with a new definition for ROOT:
+
+ make install ROOT=/opt/onc
+
+You will of course need write privileges for the destination directory.
+The headers, libraries and executables will be built and installed under the
+ROOT.
+
+
+The demonstration services in the demo directory are not built by the
+top-level "make install" command. To build these, cd to the cmd/demo
+directory and enter "make". The four services will be built.
+RPCGEN MUST BE INSTALLED in a path that make can find. To run the
+services, rpcbind must be running, then invoke the service
+(you probably will want to put it in the background). rpcinfo can be
+used to check that the service succeeded in getting registered with
+rpcbind, and to ping the service (see rpcinfo's man page). You can
+then use the corresponding client program to exercise the service.
+
+
+BUILDING ONC APPLICATIONS
+
+See the Makefiles in the demonstration services for examples of building
+ONC applications with this release. The $(ROOT)/usr/include directory
+must be included in the compiler header file search path (-I), and the
+$(ROOT)/usr/lib directory must be included in the linker library file search
+path (-L). Also, to run executables built dynamically, the shared library
+search path (LD_LIBRARY_PATH) must also include $(ROOT)/usr/lib. In addition
+to linking in this release's librpc (via -lrpc), you must also link with
+Solaris's libnsl (-lnsl) and the US domestic version of libcrypt (-lcrypt).
+
diff --git a/lib/libc/rpc/Symbol.map b/lib/libc/rpc/Symbol.map
new file mode 100644
index 000000000000..4f356de99748
--- /dev/null
+++ b/lib/libc/rpc/Symbol.map
@@ -0,0 +1,247 @@
+/*
+ * $FreeBSD$
+ */
+
+FBSD_1.0 {
+ /* From crypt_clnt.c (generated by rpcgen - include/rpcsvc/crypt.x) */
+ des_crypt_1;
+
+ /* From crypt_xdr.c (generated by rpcgen - include/rpcsvc/crypt.x) */
+ xdr_des_dir;
+ xdr_des_mode;
+ xdr_desargs;
+ xdr_desresp;
+
+ /* From yp_xdr.c (generated by rpcgen - include/rpcsvc/yp.x) */
+ xdr_domainname;
+ xdr_keydat;
+ xdr_mapname;
+ xdr_peername;
+ xdr_valdat;
+ xdr_ypbind_binding;
+ xdr_ypbind_resp;
+ xdr_ypbind_resptype;
+ xdr_ypbind_setdom;
+ xdr_ypmap_parms;
+ xdr_ypmaplist;
+ xdr_yppush_status;
+ xdr_yppushresp_xfr;
+ xdr_ypreq_key;
+ xdr_ypreq_nokey;
+ xdr_ypreq_xfr;
+ xdr_ypreqtype;
+ xdr_yprequest;
+ xdr_ypresp_all;
+ xdr_ypresp_key_val;
+ xdr_ypresp_maplist;
+ xdr_ypresp_master;
+ xdr_ypresp_order;
+ xdr_ypresp_val;
+ xdr_ypresp_xfr;
+ xdr_ypresponse;
+ xdr_ypresptype;
+ xdr_ypstat;
+ xdr_ypxfrstat;
+
+ authdes_seccreate;
+ authdes_pk_seccreate;
+ authnone_create;
+ authunix_create;
+ authunix_create_default;
+ xdr_authdes_cred;
+ xdr_authdes_verf;
+ xdr_authunix_parms;
+ bindresvport;
+ bindresvport_sa;
+ rpc_broadcast_exp;
+ rpc_broadcast;
+ clnt_dg_create;
+ clnt_create_vers;
+ clnt_create_vers_timed;
+ clnt_create;
+ clnt_create_timed;
+ clnt_tp_create;
+ clnt_tp_create_timed;
+ clnt_tli_create;
+ clnt_sperror;
+ clnt_perror;
+ clnt_sperrno;
+ clnt_perrno;
+ clnt_spcreateerror;
+ clnt_pcreateerror;
+ clnt_raw_create;
+ rpc_call;
+ clnt_vc_create;
+ cbc_crypt;
+ ecb_crypt;
+ des_setparity;
+ setnetconfig;
+ getnetconfig;
+ endnetconfig;
+ getnetconfigent;
+ freenetconfigent;
+ nc_sperror;
+ nc_perror;
+ setnetpath;
+ getnetpath;
+ endnetpath;
+ getpublicandprivatekey;
+ getpublickey;
+ getrpcbynumber;
+ getrpcbyname;
+ setrpcent;
+ endrpcent;
+ getrpcent;
+ getrpcport;
+ key_setsecret;
+ key_secretkey_is_set;
+ key_encryptsession_pk;
+ key_decryptsession_pk;
+ key_encryptsession;
+ key_decryptsession;
+ key_gendes;
+ key_setnet;
+ key_get_conv;
+ xdr_keystatus;
+ xdr_keybuf;
+ xdr_netnamestr;
+ xdr_cryptkeyarg;
+ xdr_cryptkeyarg2;
+ xdr_cryptkeyres;
+ xdr_unixcred;
+ xdr_getcredres;
+ xdr_key_netstarg;
+ xdr_key_netstres;
+ rpc_createerr;
+ __rpc_createerr;
+ getnetname;
+ user2netname;
+ host2netname;
+ netname2user;
+ netname2host;
+ pmap_set;
+ pmap_unset;
+ pmap_getmaps;
+ pmap_getport;
+ xdr_pmap;
+ xdr_pmaplist;
+ xdr_pmaplist_ptr;
+ pmap_rmtcall;
+ xdr_rmtcall_args;
+ xdr_rmtcallres;
+ xdr_callmsg;
+ _null_auth;
+ svc_fdset;
+ svc_maxfd;
+ _rpc_dtablesize;
+ __rpc_get_t_size;
+ __rpc_getconfip;
+ __rpc_setconf;
+ __rpc_getconf;
+ __rpc_endconf;
+ rpc_nullproc;
+ __rpc_fd2sockinfo;
+ __rpc_nconf2sockinfo;
+ __rpc_nconf2fd;
+ taddr2uaddr;
+ uaddr2taddr;
+ xdr_opaque_auth;
+ xdr_des_block;
+ xdr_accepted_reply;
+ xdr_rejected_reply;
+ xdr_replymsg;
+ xdr_callhdr;
+ _seterr_reply;
+ clntudp_bufcreate;
+ clntudp_create;
+ clnttcp_create;
+ clntraw_create;
+ svctcp_create;
+ svcudp_bufcreate;
+ svcfd_create;
+ svcudp_create;
+ svcraw_create;
+ get_myaddress;
+ callrpc;
+ registerrpc;
+ clnt_broadcast;
+ authdes_create;
+ clntunix_create;
+ svcunix_create;
+ svcunixfd_create;
+ rpcb_set;
+ rpcb_unset;
+ rpcb_getaddr;
+ rpcb_getmaps;
+ rpcb_rmtcall;
+ rpcb_gettime;
+ rpcb_taddr2uaddr;
+ rpcb_uaddr2taddr;
+ xdr_rpcb;
+ xdr_rpcblist_ptr;
+ xdr_rpcblist;
+ xdr_rpcb_entry;
+ xdr_rpcb_entry_list_ptr;
+ xdr_rpcb_rmtcallargs;
+ xdr_rpcb_rmtcallres;
+ xdr_netbuf;
+ xdr_rpcbs_addrlist;
+ xdr_rpcbs_rmtcalllist;
+ xdr_rpcbs_proc;
+ xdr_rpcbs_addrlist_ptr;
+ xdr_rpcbs_rmtcalllist_ptr;
+ xdr_rpcb_stat;
+ xdr_rpcb_stat_byvers;
+ rtime;
+ xprt_register;
+ xprt_unregister;
+ svc_reg;
+ svc_unreg;
+ svc_register;
+ svc_unregister;
+ svc_sendreply;
+ svcerr_noproc;
+ svcerr_decode;
+ svcerr_systemerr;
+ svcerr_auth;
+ svcerr_weakauth;
+ svcerr_noprog;
+ svcerr_progvers;
+ svc_getreq;
+ svc_getreqset;
+ svc_getreq_common;
+ svc_getreq_poll;
+ rpc_control;
+ _authenticate;
+ _svcauth_null;
+ svc_auth_reg;
+ _svcauth_des;
+ authdes_getucred;
+ _svcauth_unix;
+ _svcauth_short;
+ svc_dg_create;
+ svc_dg_enablecache;
+ svc_create;
+ svc_tp_create;
+ svc_tli_create;
+ __rpc_rawcombuf;
+ svc_raw_create;
+ svc_run;
+ svc_exit;
+ rpc_reg;
+ svc_vc_create;
+ svc_fd_create;
+ __rpc_get_local_uid;
+};
+
+FBSDprivate_1.0 {
+ __des_crypt_LOCAL;
+ __key_encryptsession_pk_LOCAL;
+ __key_decryptsession_pk_LOCAL;
+ __key_gendes_LOCAL;
+ __svc_clean_idle;
+ __rpc_gss_unwrap;
+ __rpc_gss_unwrap_stub;
+ __rpc_gss_wrap;
+ __rpc_gss_wrap_stub;
+};
diff --git a/lib/libc/rpc/auth_des.c b/lib/libc/rpc/auth_des.c
new file mode 100644
index 000000000000..5435e7749fdf
--- /dev/null
+++ b/lib/libc/rpc/auth_des.c
@@ -0,0 +1,497 @@
+/*-
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 1988 by Sun Microsystems, Inc.
+ */
+/*
+ * auth_des.c, client-side implementation of DES authentication
+ */
+
+#include "namespace.h"
+#include "reentrant.h"
+#include <err.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/cdefs.h>
+#include <rpc/des_crypt.h>
+#include <syslog.h>
+#include <rpc/types.h>
+#include <rpc/auth.h>
+#include <rpc/auth_des.h>
+#include <rpc/clnt.h>
+#include <rpc/xdr.h>
+#include <sys/socket.h>
+#undef NIS
+#include <rpcsvc/nis.h>
+#include "un-namespace.h"
+#include "mt_misc.h"
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)auth_des.c 2.2 88/07/29 4.0 RPCSRC; from 1.9 88/02/08 SMI";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#define USEC_PER_SEC 1000000
+#define RTIME_TIMEOUT 5 /* seconds to wait for sync */
+
+#define AUTH_PRIVATE(auth) (struct ad_private *) auth->ah_private
+#define ALLOC(object_type) (object_type *) mem_alloc(sizeof(object_type))
+#define FREE(ptr, size) mem_free((char *)(ptr), (int) size)
+#define ATTEMPT(xdr_op) if (!(xdr_op)) return (FALSE)
+
+extern bool_t xdr_authdes_cred( XDR *, struct authdes_cred *);
+extern bool_t xdr_authdes_verf( XDR *, struct authdes_verf *);
+extern int key_encryptsession_pk(char *, netobj *, des_block *);
+
+extern bool_t __rpc_get_time_offset(struct timeval *, nis_server *, char *,
+ char **, char **);
+
+/*
+ * DES authenticator operations vector
+ */
+static void authdes_nextverf(AUTH *);
+static bool_t authdes_marshal(AUTH *, XDR *);
+static bool_t authdes_validate(AUTH *, struct opaque_auth *);
+static bool_t authdes_refresh(AUTH *, void *);
+static void authdes_destroy(AUTH *);
+
+static struct auth_ops *authdes_ops(void);
+
+/*
+ * This struct is pointed to by the ah_private field of an "AUTH *"
+ */
+struct ad_private {
+ char *ad_fullname; /* client's full name */
+ u_int ad_fullnamelen; /* length of name, rounded up */
+ char *ad_servername; /* server's full name */
+ u_int ad_servernamelen; /* length of name, rounded up */
+ u_int ad_window; /* client specified window */
+ bool_t ad_dosync; /* synchronize? */
+ struct netbuf ad_syncaddr; /* remote host to synch with */
+ char *ad_timehost; /* remote host to synch with */
+ struct timeval ad_timediff; /* server's time - client's time */
+ u_int ad_nickname; /* server's nickname for client */
+ struct authdes_cred ad_cred; /* storage for credential */
+ struct authdes_verf ad_verf; /* storage for verifier */
+ struct timeval ad_timestamp; /* timestamp sent */
+ des_block ad_xkey; /* encrypted conversation key */
+ u_char ad_pkey[1024]; /* Server's actual public key */
+ char *ad_netid; /* Timehost netid */
+ char *ad_uaddr; /* Timehost uaddr */
+ nis_server *ad_nis_srvr; /* NIS+ server struct */
+};
+
+AUTH *authdes_pk_seccreate(const char *, netobj *, u_int, const char *,
+ const des_block *, nis_server *);
+
+/*
+ * documented version of authdes_seccreate
+ */
+/*
+ servername: network name of server
+ win: time to live
+ timehost: optional hostname to sync with
+ ckey: optional conversation key to use
+*/
+
+AUTH *
+authdes_seccreate(const char *servername, const u_int win,
+ const char *timehost, const des_block *ckey)
+{
+ u_char pkey_data[1024];
+ netobj pkey;
+ AUTH *dummy;
+
+ if (! getpublickey(servername, (char *) pkey_data)) {
+ syslog(LOG_ERR,
+ "authdes_seccreate: no public key found for %s",
+ servername);
+ return (NULL);
+ }
+
+ pkey.n_bytes = (char *) pkey_data;
+ pkey.n_len = (u_int)strlen((char *)pkey_data) + 1;
+ dummy = authdes_pk_seccreate(servername, &pkey, win, timehost,
+ ckey, NULL);
+ return (dummy);
+}
+
+/*
+ * Slightly modified version of authdessec_create which takes the public key
+ * of the server principal as an argument. This spares us a call to
+ * getpublickey() which in the nameserver context can cause a deadlock.
+ */
+AUTH *
+authdes_pk_seccreate(const char *servername, netobj *pkey, u_int window,
+ const char *timehost, const des_block *ckey, nis_server *srvr)
+{
+ AUTH *auth;
+ struct ad_private *ad;
+ char namebuf[MAXNETNAMELEN+1];
+
+ /*
+ * Allocate everything now
+ */
+ auth = ALLOC(AUTH);
+ if (auth == NULL) {
+ syslog(LOG_ERR, "authdes_pk_seccreate: out of memory");
+ return (NULL);
+ }
+ ad = ALLOC(struct ad_private);
+ if (ad == NULL) {
+ syslog(LOG_ERR, "authdes_pk_seccreate: out of memory");
+ goto failed;
+ }
+ ad->ad_fullname = ad->ad_servername = NULL; /* Sanity reasons */
+ ad->ad_timehost = NULL;
+ ad->ad_netid = NULL;
+ ad->ad_uaddr = NULL;
+ ad->ad_nis_srvr = NULL;
+ ad->ad_timediff.tv_sec = 0;
+ ad->ad_timediff.tv_usec = 0;
+ memcpy(ad->ad_pkey, pkey->n_bytes, pkey->n_len);
+ if (!getnetname(namebuf))
+ goto failed;
+ ad->ad_fullnamelen = RNDUP((u_int) strlen(namebuf));
+ ad->ad_fullname = (char *)mem_alloc(ad->ad_fullnamelen + 1);
+ ad->ad_servernamelen = strlen(servername);
+ ad->ad_servername = (char *)mem_alloc(ad->ad_servernamelen + 1);
+
+ if (ad->ad_fullname == NULL || ad->ad_servername == NULL) {
+ syslog(LOG_ERR, "authdes_seccreate: out of memory");
+ goto failed;
+ }
+ if (timehost != NULL) {
+ ad->ad_timehost = (char *)mem_alloc(strlen(timehost) + 1);
+ if (ad->ad_timehost == NULL) {
+ syslog(LOG_ERR, "authdes_seccreate: out of memory");
+ goto failed;
+ }
+ memcpy(ad->ad_timehost, timehost, strlen(timehost) + 1);
+ ad->ad_dosync = TRUE;
+ } else if (srvr != NULL) {
+ ad->ad_nis_srvr = srvr; /* transient */
+ ad->ad_dosync = TRUE;
+ } else {
+ ad->ad_dosync = FALSE;
+ }
+ memcpy(ad->ad_fullname, namebuf, ad->ad_fullnamelen + 1);
+ memcpy(ad->ad_servername, servername, ad->ad_servernamelen + 1);
+ ad->ad_window = window;
+ if (ckey == NULL) {
+ if (key_gendes(&auth->ah_key) < 0) {
+ syslog(LOG_ERR,
+ "authdes_seccreate: keyserv(1m) is unable to generate session key");
+ goto failed;
+ }
+ } else {
+ auth->ah_key = *ckey;
+ }
+
+ /*
+ * Set up auth handle
+ */
+ auth->ah_cred.oa_flavor = AUTH_DES;
+ auth->ah_verf.oa_flavor = AUTH_DES;
+ auth->ah_ops = authdes_ops();
+ auth->ah_private = (caddr_t)ad;
+
+ if (!authdes_refresh(auth, NULL)) {
+ goto failed;
+ }
+ ad->ad_nis_srvr = NULL; /* not needed any longer */
+ return (auth);
+
+failed:
+ if (auth)
+ FREE(auth, sizeof (AUTH));
+ if (ad) {
+ if (ad->ad_fullname)
+ FREE(ad->ad_fullname, ad->ad_fullnamelen + 1);
+ if (ad->ad_servername)
+ FREE(ad->ad_servername, ad->ad_servernamelen + 1);
+ if (ad->ad_timehost)
+ FREE(ad->ad_timehost, strlen(ad->ad_timehost) + 1);
+ if (ad->ad_netid)
+ FREE(ad->ad_netid, strlen(ad->ad_netid) + 1);
+ if (ad->ad_uaddr)
+ FREE(ad->ad_uaddr, strlen(ad->ad_uaddr) + 1);
+ FREE(ad, sizeof (struct ad_private));
+ }
+ return (NULL);
+}
+
+/*
+ * Implement the five authentication operations
+ */
+
+
+/*
+ * 1. Next Verifier
+ */
+/*ARGSUSED*/
+static void
+authdes_nextverf(AUTH *auth __unused)
+{
+ /* what the heck am I supposed to do??? */
+}
+
+
+/*
+ * 2. Marshal
+ */
+static bool_t
+authdes_marshal(AUTH *auth, XDR *xdrs)
+{
+/* LINTED pointer alignment */
+ struct ad_private *ad = AUTH_PRIVATE(auth);
+ struct authdes_cred *cred = &ad->ad_cred;
+ struct authdes_verf *verf = &ad->ad_verf;
+ des_block cryptbuf[2];
+ des_block ivec;
+ int status;
+ int len;
+ rpc_inline_t *ixdr;
+
+ /*
+ * Figure out the "time", accounting for any time difference
+ * with the server if necessary.
+ */
+ (void)gettimeofday(&ad->ad_timestamp, NULL);
+ ad->ad_timestamp.tv_sec += ad->ad_timediff.tv_sec;
+ ad->ad_timestamp.tv_usec += ad->ad_timediff.tv_usec;
+ while (ad->ad_timestamp.tv_usec >= USEC_PER_SEC) {
+ ad->ad_timestamp.tv_usec -= USEC_PER_SEC;
+ ad->ad_timestamp.tv_sec++;
+ }
+
+ /*
+ * XDR the timestamp and possibly some other things, then
+ * encrypt them.
+ */
+ ixdr = (rpc_inline_t *)cryptbuf;
+ IXDR_PUT_INT32(ixdr, ad->ad_timestamp.tv_sec);
+ IXDR_PUT_INT32(ixdr, ad->ad_timestamp.tv_usec);
+ if (ad->ad_cred.adc_namekind == ADN_FULLNAME) {
+ IXDR_PUT_U_INT32(ixdr, ad->ad_window);
+ IXDR_PUT_U_INT32(ixdr, ad->ad_window - 1);
+ ivec.key.high = ivec.key.low = 0;
+ status = cbc_crypt((char *)&auth->ah_key, (char *)cryptbuf,
+ (u_int) 2 * sizeof (des_block),
+ DES_ENCRYPT | DES_HW, (char *)&ivec);
+ } else {
+ status = ecb_crypt((char *)&auth->ah_key, (char *)cryptbuf,
+ (u_int) sizeof (des_block),
+ DES_ENCRYPT | DES_HW);
+ }
+ if (DES_FAILED(status)) {
+ syslog(LOG_ERR, "authdes_marshal: DES encryption failure");
+ return (FALSE);
+ }
+ ad->ad_verf.adv_xtimestamp = cryptbuf[0];
+ if (ad->ad_cred.adc_namekind == ADN_FULLNAME) {
+ ad->ad_cred.adc_fullname.window = cryptbuf[1].key.high;
+ ad->ad_verf.adv_winverf = cryptbuf[1].key.low;
+ } else {
+ ad->ad_cred.adc_nickname = ad->ad_nickname;
+ ad->ad_verf.adv_winverf = 0;
+ }
+
+ /*
+ * Serialize the credential and verifier into opaque
+ * authentication data.
+ */
+ if (ad->ad_cred.adc_namekind == ADN_FULLNAME) {
+ len = ((1 + 1 + 2 + 1)*BYTES_PER_XDR_UNIT + ad->ad_fullnamelen);
+ } else {
+ len = (1 + 1)*BYTES_PER_XDR_UNIT;
+ }
+
+ if ((ixdr = xdr_inline(xdrs, 2*BYTES_PER_XDR_UNIT))) {
+ IXDR_PUT_INT32(ixdr, AUTH_DES);
+ IXDR_PUT_INT32(ixdr, len);
+ } else {
+ ATTEMPT(xdr_putint32(xdrs, (int *)&auth->ah_cred.oa_flavor));
+ ATTEMPT(xdr_putint32(xdrs, &len));
+ }
+ ATTEMPT(xdr_authdes_cred(xdrs, cred));
+
+ len = (2 + 1)*BYTES_PER_XDR_UNIT;
+ if ((ixdr = xdr_inline(xdrs, 2*BYTES_PER_XDR_UNIT))) {
+ IXDR_PUT_INT32(ixdr, AUTH_DES);
+ IXDR_PUT_INT32(ixdr, len);
+ } else {
+ ATTEMPT(xdr_putint32(xdrs, (int *)&auth->ah_verf.oa_flavor));
+ ATTEMPT(xdr_putint32(xdrs, &len));
+ }
+ ATTEMPT(xdr_authdes_verf(xdrs, verf));
+ return (TRUE);
+}
+
+
+/*
+ * 3. Validate
+ */
+static bool_t
+authdes_validate(AUTH *auth, struct opaque_auth *rverf)
+{
+/* LINTED pointer alignment */
+ struct ad_private *ad = AUTH_PRIVATE(auth);
+ struct authdes_verf verf;
+ int status;
+ uint32_t *ixdr;
+ des_block buf;
+
+ if (rverf->oa_length != (2 + 1) * BYTES_PER_XDR_UNIT) {
+ return (FALSE);
+ }
+/* LINTED pointer alignment */
+ ixdr = (uint32_t *)rverf->oa_base;
+ buf.key.high = (uint32_t)*ixdr++;
+ buf.key.low = (uint32_t)*ixdr++;
+ verf.adv_int_u = (uint32_t)*ixdr++;
+
+ /*
+ * Decrypt the timestamp
+ */
+ status = ecb_crypt((char *)&auth->ah_key, (char *)&buf,
+ (u_int)sizeof (des_block), DES_DECRYPT | DES_HW);
+
+ if (DES_FAILED(status)) {
+ syslog(LOG_ERR, "authdes_validate: DES decryption failure");
+ return (FALSE);
+ }
+
+ /*
+ * xdr the decrypted timestamp
+ */
+/* LINTED pointer alignment */
+ ixdr = (uint32_t *)buf.c;
+ verf.adv_timestamp.tv_sec = IXDR_GET_INT32(ixdr) + 1;
+ verf.adv_timestamp.tv_usec = IXDR_GET_INT32(ixdr);
+
+ /*
+ * validate
+ */
+ if (bcmp((char *)&ad->ad_timestamp, (char *)&verf.adv_timestamp,
+ sizeof(struct timeval)) != 0) {
+ syslog(LOG_DEBUG, "authdes_validate: verifier mismatch");
+ return (FALSE);
+ }
+
+ /*
+ * We have a nickname now, let's use it
+ */
+ ad->ad_nickname = verf.adv_nickname;
+ ad->ad_cred.adc_namekind = ADN_NICKNAME;
+ return (TRUE);
+}
+
+/*
+ * 4. Refresh
+ */
+/*ARGSUSED*/
+static bool_t
+authdes_refresh(AUTH *auth, void *dummy __unused)
+{
+/* LINTED pointer alignment */
+ struct ad_private *ad = AUTH_PRIVATE(auth);
+ struct authdes_cred *cred = &ad->ad_cred;
+ int ok;
+ netobj pkey;
+
+ if (ad->ad_dosync) {
+ ok = __rpc_get_time_offset(&ad->ad_timediff, ad->ad_nis_srvr,
+ ad->ad_timehost, &(ad->ad_uaddr),
+ &(ad->ad_netid));
+ if (! ok) {
+ /*
+ * Hope the clocks are synced!
+ */
+ ad->ad_dosync = 0;
+ syslog(LOG_DEBUG,
+ "authdes_refresh: unable to synchronize clock");
+ }
+ }
+ ad->ad_xkey = auth->ah_key;
+ pkey.n_bytes = (char *)(ad->ad_pkey);
+ pkey.n_len = (u_int)strlen((char *)ad->ad_pkey) + 1;
+ if (key_encryptsession_pk(ad->ad_servername, &pkey, &ad->ad_xkey) < 0) {
+ syslog(LOG_INFO,
+ "authdes_refresh: keyserv(1m) is unable to encrypt session key");
+ return (FALSE);
+ }
+ cred->adc_fullname.key = ad->ad_xkey;
+ cred->adc_namekind = ADN_FULLNAME;
+ cred->adc_fullname.name = ad->ad_fullname;
+ return (TRUE);
+}
+
+
+/*
+ * 5. Destroy
+ */
+static void
+authdes_destroy(AUTH *auth)
+{
+/* LINTED pointer alignment */
+ struct ad_private *ad = AUTH_PRIVATE(auth);
+
+ FREE(ad->ad_fullname, ad->ad_fullnamelen + 1);
+ FREE(ad->ad_servername, ad->ad_servernamelen + 1);
+ if (ad->ad_timehost)
+ FREE(ad->ad_timehost, strlen(ad->ad_timehost) + 1);
+ if (ad->ad_netid)
+ FREE(ad->ad_netid, strlen(ad->ad_netid) + 1);
+ if (ad->ad_uaddr)
+ FREE(ad->ad_uaddr, strlen(ad->ad_uaddr) + 1);
+ FREE(ad, sizeof (struct ad_private));
+ FREE(auth, sizeof(AUTH));
+}
+
+static struct auth_ops *
+authdes_ops(void)
+{
+ static struct auth_ops ops;
+
+ /* VARIABLES PROTECTED BY ops_lock: ops */
+
+ mutex_lock(&authdes_ops_lock);
+ if (ops.ah_nextverf == NULL) {
+ ops.ah_nextverf = authdes_nextverf;
+ ops.ah_marshal = authdes_marshal;
+ ops.ah_validate = authdes_validate;
+ ops.ah_refresh = authdes_refresh;
+ ops.ah_destroy = authdes_destroy;
+ }
+ mutex_unlock(&authdes_ops_lock);
+ return (&ops);
+}
diff --git a/lib/libc/rpc/auth_none.c b/lib/libc/rpc/auth_none.c
new file mode 100644
index 000000000000..32bebebf339d
--- /dev/null
+++ b/lib/libc/rpc/auth_none.c
@@ -0,0 +1,175 @@
+/* $NetBSD: auth_none.c,v 1.13 2000/01/22 22:19:17 mycroft Exp $ */
+
+/*-
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *sccsid2 = "@(#)auth_none.c 1.19 87/08/11 Copyr 1984 Sun Micro";
+static char *sccsid = "@(#)auth_none.c 2.1 88/07/29 4.0 RPCSRC";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * auth_none.c
+ * Creates a client authentication handle for passing "null"
+ * credentials and verifiers to remote systems.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#include "namespace.h"
+#include "reentrant.h"
+#include <assert.h>
+#include <stdlib.h>
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#include <rpc/auth.h>
+#include "un-namespace.h"
+#include "mt_misc.h"
+
+#define MAX_MARSHAL_SIZE 20
+
+/*
+ * Authenticator operations routines
+ */
+
+static bool_t authnone_marshal (AUTH *, XDR *);
+static void authnone_verf (AUTH *);
+static bool_t authnone_validate (AUTH *, struct opaque_auth *);
+static bool_t authnone_refresh (AUTH *, void *);
+static void authnone_destroy (AUTH *);
+
+extern bool_t xdr_opaque_auth(XDR *, struct opaque_auth *);
+
+static struct auth_ops *authnone_ops(void);
+
+static struct authnone_private {
+ AUTH no_client;
+ char marshalled_client[MAX_MARSHAL_SIZE];
+ u_int mcnt;
+} *authnone_private;
+
+AUTH *
+authnone_create(void)
+{
+ struct authnone_private *ap = authnone_private;
+ XDR xdr_stream;
+ XDR *xdrs;
+
+ mutex_lock(&authnone_lock);
+ if (ap == NULL) {
+ ap = calloc(1, sizeof (*ap));
+ if (ap == NULL) {
+ mutex_unlock(&authnone_lock);
+ return (0);
+ }
+ authnone_private = ap;
+ }
+ if (!ap->mcnt) {
+ ap->no_client.ah_cred = ap->no_client.ah_verf = _null_auth;
+ ap->no_client.ah_ops = authnone_ops();
+ xdrs = &xdr_stream;
+ xdrmem_create(xdrs, ap->marshalled_client,
+ (u_int)MAX_MARSHAL_SIZE, XDR_ENCODE);
+ (void)xdr_opaque_auth(xdrs, &ap->no_client.ah_cred);
+ (void)xdr_opaque_auth(xdrs, &ap->no_client.ah_verf);
+ ap->mcnt = XDR_GETPOS(xdrs);
+ XDR_DESTROY(xdrs);
+ }
+ mutex_unlock(&authnone_lock);
+ return (&ap->no_client);
+}
+
+/*ARGSUSED*/
+static bool_t
+authnone_marshal(AUTH *client, XDR *xdrs)
+{
+ struct authnone_private *ap;
+ bool_t dummy;
+
+ assert(xdrs != NULL);
+
+ ap = authnone_private;
+ if (ap == NULL) {
+ mutex_unlock(&authnone_lock);
+ return (FALSE);
+ }
+ dummy = (*xdrs->x_ops->x_putbytes)(xdrs,
+ ap->marshalled_client, ap->mcnt);
+ mutex_unlock(&authnone_lock);
+ return (dummy);
+}
+
+/* All these unused parameters are required to keep ANSI-C from grumbling */
+/*ARGSUSED*/
+static void
+authnone_verf(AUTH *client)
+{
+}
+
+/*ARGSUSED*/
+static bool_t
+authnone_validate(AUTH *client, struct opaque_auth *opaque)
+{
+
+ return (TRUE);
+}
+
+/*ARGSUSED*/
+static bool_t
+authnone_refresh(AUTH *client, void *dummy)
+{
+
+ return (FALSE);
+}
+
+/*ARGSUSED*/
+static void
+authnone_destroy(AUTH *client)
+{
+}
+
+static struct auth_ops *
+authnone_ops(void)
+{
+ static struct auth_ops ops;
+
+/* VARIABLES PROTECTED BY ops_lock: ops */
+
+ mutex_lock(&ops_lock);
+ if (ops.ah_nextverf == NULL) {
+ ops.ah_nextverf = authnone_verf;
+ ops.ah_marshal = authnone_marshal;
+ ops.ah_validate = authnone_validate;
+ ops.ah_refresh = authnone_refresh;
+ ops.ah_destroy = authnone_destroy;
+ }
+ mutex_unlock(&ops_lock);
+ return (&ops);
+}
diff --git a/lib/libc/rpc/auth_time.c b/lib/libc/rpc/auth_time.c
new file mode 100644
index 000000000000..4b714468b92e
--- /dev/null
+++ b/lib/libc/rpc/auth_time.c
@@ -0,0 +1,502 @@
+/* #pragma ident "@(#)auth_time.c 1.4 92/11/10 SMI" */
+
+/*
+ * auth_time.c
+ *
+ * This module contains the private function __rpc_get_time_offset()
+ * which will return the difference in seconds between the local system's
+ * notion of time and a remote server's notion of time. This must be
+ * possible without calling any functions that may invoke the name
+ * service. (netdir_getbyxxx, getXbyY, etc). The function is used in the
+ * synchronize call of the authdes code to synchronize clocks between
+ * NIS+ clients and their servers.
+ *
+ * Note to minimize the amount of duplicate code, portions of the
+ * synchronize() function were folded into this code, and the synchronize
+ * call becomes simply a wrapper around this function. Further, if this
+ * function is called with a timehost it *DOES* recurse to the name
+ * server so don't use it in that mode if you are doing name service code.
+ *
+ * Copyright (c) 1992 Sun Microsystems Inc.
+ * All rights reserved.
+ *
+ * Side effects :
+ * When called a client handle to a RPCBIND process is created
+ * and destroyed. Two strings "netid" and "uaddr" are malloc'd
+ * and returned. The SIGALRM processing is modified only if
+ * needed to deal with TCP connections.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <stdio.h>
+#include <syslog.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <sys/signal.h>
+#include <sys/errno.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <rpc/rpc.h>
+#include <rpc/rpc_com.h>
+#include <rpc/rpcb_prot.h>
+#undef NIS
+#include <rpcsvc/nis.h>
+#include "un-namespace.h"
+
+extern int _rpc_dtablesize( void );
+
+#ifdef TESTING
+#define msg(x) printf("ERROR: %s\n", x)
+/* #define msg(x) syslog(LOG_ERR, "%s", x) */
+#else
+#define msg(x)
+#endif
+
+static int saw_alarm = 0;
+
+static void
+alarm_hndler(int s)
+{
+ saw_alarm = 1;
+ return;
+}
+
+/*
+ * The internet time server defines the epoch to be Jan 1, 1900
+ * whereas UNIX defines it to be Jan 1, 1970. To adjust the result
+ * from internet time-service time, into UNIX time we subtract the
+ * following offset :
+ */
+#define NYEARS (1970 - 1900)
+#define TOFFSET ((u_long)60*60*24*(365*NYEARS + (NYEARS/4)))
+
+
+/*
+ * Stolen from rpc.nisd:
+ * Turn a 'universal address' into a struct sockaddr_in.
+ * Bletch.
+ */
+static int uaddr_to_sockaddr(char *uaddr, struct sockaddr_in *sin)
+{
+ unsigned char p_bytes[2];
+ int i;
+ unsigned long a[6];
+
+ i = sscanf(uaddr, "%lu.%lu.%lu.%lu.%lu.%lu", &a[0], &a[1], &a[2],
+ &a[3], &a[4], &a[5]);
+
+ if (i < 6)
+ return(1);
+
+ for (i = 0; i < 4; i++)
+ sin->sin_addr.s_addr |= (a[i] & 0x000000FF) << (8 * i);
+
+ p_bytes[0] = (unsigned char)a[4] & 0x000000FF;
+ p_bytes[1] = (unsigned char)a[5] & 0x000000FF;
+
+ sin->sin_family = AF_INET; /* always */
+ bcopy((char *)&p_bytes, (char *)&sin->sin_port, 2);
+
+ return (0);
+}
+
+/*
+ * free_eps()
+ *
+ * Free the strings that were strduped into the eps structure.
+ */
+static void
+free_eps(endpoint eps[], int num)
+{
+ int i;
+
+ for (i = 0; i < num; i++) {
+ free(eps[i].uaddr);
+ free(eps[i].proto);
+ free(eps[i].family);
+ }
+ return;
+}
+
+/*
+ * get_server()
+ *
+ * This function constructs a nis_server structure description for the
+ * indicated hostname.
+ *
+ * NOTE: There is a chance we may end up recursing here due to the
+ * fact that gethostbyname() could do an NIS search. Ideally, the
+ * NIS+ server will call __rpc_get_time_offset() with the nis_server
+ * structure already populated.
+ *
+ * host - name of the time host
+ * srv - nis_server struct to use.
+ * eps[] - array of endpoints
+ * maxep - max array size
+ */
+static nis_server *
+get_server(struct sockaddr_in *sin, char *host, nis_server *srv,
+ endpoint eps[], int maxep)
+{
+ char hname[256];
+ int num_ep = 0, i;
+ struct hostent *he;
+ struct hostent dummy;
+ char *ptr[2];
+ endpoint *ep;
+
+ if (host == NULL && sin == NULL)
+ return (NULL);
+
+ if (sin == NULL) {
+ he = gethostbyname(host);
+ if (he == NULL)
+ return(NULL);
+ } else {
+ he = &dummy;
+ ptr[0] = (char *)&sin->sin_addr.s_addr;
+ ptr[1] = NULL;
+ dummy.h_addr_list = ptr;
+ }
+
+ /*
+ * This is lame. We go around once for TCP, then again
+ * for UDP.
+ */
+ for (i = 0, ep = eps; (he->h_addr_list[i] != NULL) && (num_ep < maxep);
+ i++, ep++, num_ep++) {
+ struct in_addr *a;
+
+ a = (struct in_addr *)he->h_addr_list[i];
+ snprintf(hname, sizeof(hname), "%s.0.111", inet_ntoa(*a));
+ ep->uaddr = strdup(hname);
+ ep->family = strdup("inet");
+ ep->proto = strdup("tcp");
+ if (ep->uaddr == NULL || ep->family == NULL || ep->proto == NULL) {
+ free_eps(eps, num_ep + 1);
+ return (NULL);
+ }
+ }
+
+ for (i = 0; (he->h_addr_list[i] != NULL) && (num_ep < maxep);
+ i++, ep++, num_ep++) {
+ struct in_addr *a;
+
+ a = (struct in_addr *)he->h_addr_list[i];
+ snprintf(hname, sizeof(hname), "%s.0.111", inet_ntoa(*a));
+ ep->uaddr = strdup(hname);
+ ep->family = strdup("inet");
+ ep->proto = strdup("udp");
+ if (ep->uaddr == NULL || ep->family == NULL || ep->proto == NULL) {
+ free_eps(eps, num_ep + 1);
+ return (NULL);
+ }
+ }
+
+ srv->name = (nis_name) host;
+ srv->ep.ep_len = num_ep;
+ srv->ep.ep_val = eps;
+ srv->key_type = NIS_PK_NONE;
+ srv->pkey.n_bytes = NULL;
+ srv->pkey.n_len = 0;
+ return (srv);
+}
+
+/*
+ * __rpc_get_time_offset()
+ *
+ * This function uses a nis_server structure to contact the a remote
+ * machine (as named in that structure) and returns the offset in time
+ * between that machine and this one. This offset is returned in seconds
+ * and may be positive or negative.
+ *
+ * The first time through, a lot of fiddling is done with the netconfig
+ * stuff to find a suitable transport. The function is very aggressive
+ * about choosing UDP or at worst TCP if it can. This is because
+ * those transports support both the RCPBIND call and the internet
+ * time service.
+ *
+ * Once through, *uaddr is set to the universal address of
+ * the machine and *netid is set to the local netid for the transport
+ * that uaddr goes with. On the second call, the netconfig stuff
+ * is skipped and the uaddr/netid pair are used to fetch the netconfig
+ * structure and to then contact the machine for the time.
+ *
+ * td = "server" - "client"
+ *
+ * td - Time difference
+ * srv - NIS Server description
+ * thost - if no server, this is the timehost
+ * uaddr - known universal address
+ * netid - known network identifier
+ */
+int
+__rpc_get_time_offset(struct timeval *td, nis_server *srv, char *thost,
+ char **uaddr, struct sockaddr_in *netid)
+{
+ CLIENT *clnt; /* Client handle */
+ endpoint *ep, /* useful endpoints */
+ *useep = NULL; /* endpoint of xp */
+ char *useua = NULL; /* uaddr of selected xp */
+ int epl, i; /* counters */
+ enum clnt_stat status; /* result of clnt_call */
+ u_long thetime, delta;
+ int needfree = 0;
+ struct timeval tv;
+ int time_valid;
+ int udp_ep = -1, tcp_ep = -1;
+ int a1, a2, a3, a4;
+ char ut[64], ipuaddr[64];
+ endpoint teps[32];
+ nis_server tsrv;
+ void (*oldsig)(int) = NULL; /* old alarm handler */
+ struct sockaddr_in sin;
+ socklen_t len;
+ int s = RPC_ANYSOCK;
+ int type = 0;
+
+ td->tv_sec = 0;
+ td->tv_usec = 0;
+
+ /*
+ * First check to see if we need to find and address for this
+ * server.
+ */
+ if (*uaddr == NULL) {
+ if ((srv != NULL) && (thost != NULL)) {
+ msg("both timehost and srv pointer used!");
+ return (0);
+ }
+ if (! srv) {
+ srv = get_server(netid, thost, &tsrv, teps, 32);
+ if (srv == NULL) {
+ msg("unable to contruct server data.");
+ return (0);
+ }
+ needfree = 1; /* need to free data in endpoints */
+ }
+
+ ep = srv->ep.ep_val;
+ epl = srv->ep.ep_len;
+
+ /* Identify the TCP and UDP endpoints */
+ for (i = 0;
+ (i < epl) && ((udp_ep == -1) || (tcp_ep == -1)); i++) {
+ if (strcasecmp(ep[i].proto, "udp") == 0)
+ udp_ep = i;
+ if (strcasecmp(ep[i].proto, "tcp") == 0)
+ tcp_ep = i;
+ }
+
+ /* Check to see if it is UDP or TCP */
+ if (tcp_ep > -1) {
+ useep = &ep[tcp_ep];
+ useua = ep[tcp_ep].uaddr;
+ type = SOCK_STREAM;
+ } else if (udp_ep > -1) {
+ useep = &ep[udp_ep];
+ useua = ep[udp_ep].uaddr;
+ type = SOCK_DGRAM;
+ }
+
+ if (useep == NULL) {
+ msg("no acceptable transport endpoints.");
+ if (needfree)
+ free_eps(teps, tsrv.ep.ep_len);
+ return (0);
+ }
+ }
+
+ /*
+ * Create a sockaddr from the uaddr.
+ */
+ if (*uaddr != NULL)
+ useua = *uaddr;
+
+ /* Fixup test for NIS+ */
+ sscanf(useua, "%d.%d.%d.%d.", &a1, &a2, &a3, &a4);
+ sprintf(ipuaddr, "%d.%d.%d.%d.0.111", a1, a2, a3, a4);
+ useua = &ipuaddr[0];
+
+ bzero((char *)&sin, sizeof(sin));
+ if (uaddr_to_sockaddr(useua, &sin)) {
+ msg("unable to translate uaddr to sockaddr.");
+ if (needfree)
+ free_eps(teps, tsrv.ep.ep_len);
+ return (0);
+ }
+
+ /*
+ * Create the client handle to rpcbind. Note we always try
+ * version 3 since that is the earliest version that supports
+ * the RPCB_GETTIME call. Also it is the version that comes
+ * standard with SVR4. Since most everyone supports TCP/IP
+ * we could consider trying the rtime call first.
+ */
+ clnt = clnttcp_create(&sin, RPCBPROG, RPCBVERS, &s, 0, 0);
+ if (clnt == NULL) {
+ msg("unable to create client handle to rpcbind.");
+ if (needfree)
+ free_eps(teps, tsrv.ep.ep_len);
+ return (0);
+ }
+
+ tv.tv_sec = 5;
+ tv.tv_usec = 0;
+ time_valid = 0;
+ status = clnt_call(clnt, RPCBPROC_GETTIME, (xdrproc_t)xdr_void, NULL,
+ (xdrproc_t)xdr_u_long, &thetime, tv);
+ /*
+ * The only error we check for is anything but success. In
+ * fact we could have seen PROGMISMATCH if talking to a 4.1
+ * machine (pmap v2) or TIMEDOUT if the net was busy.
+ */
+ if (status == RPC_SUCCESS)
+ time_valid = 1;
+ else {
+ int save;
+
+ /* Blow away possible stale CLNT handle. */
+ if (clnt != NULL) {
+ clnt_destroy(clnt);
+ clnt = NULL;
+ }
+
+ /*
+ * Convert PMAP address into timeservice address
+ * We take advantage of the fact that we "know" what
+ * the universal address looks like for inet transports.
+ *
+ * We also know that the internet timeservice is always
+ * listening on port 37.
+ */
+ sscanf(useua, "%d.%d.%d.%d.", &a1, &a2, &a3, &a4);
+ sprintf(ut, "%d.%d.%d.%d.0.37", a1, a2, a3, a4);
+
+ if (uaddr_to_sockaddr(ut, &sin)) {
+ msg("cannot convert timeservice uaddr to sockaddr.");
+ goto error;
+ }
+
+ s = _socket(AF_INET, type, 0);
+ if (s == -1) {
+ msg("unable to open fd to network.");
+ goto error;
+ }
+
+ /*
+ * Now depending on whether or not we're talking to
+ * UDP we set a timeout or not.
+ */
+ if (type == SOCK_DGRAM) {
+ struct timeval timeout = { 20, 0 };
+ struct sockaddr_in from;
+ fd_set readfds;
+ int res;
+
+ if (_sendto(s, &thetime, sizeof(thetime), 0,
+ (struct sockaddr *)&sin, sizeof(sin)) == -1) {
+ msg("udp : sendto failed.");
+ goto error;
+ }
+ do {
+ FD_ZERO(&readfds);
+ FD_SET(s, &readfds);
+ res = _select(_rpc_dtablesize(), &readfds,
+ (fd_set *)NULL, (fd_set *)NULL, &timeout);
+ } while (res < 0 && errno == EINTR);
+ if (res <= 0)
+ goto error;
+ len = sizeof(from);
+ res = _recvfrom(s, (char *)&thetime, sizeof(thetime), 0,
+ (struct sockaddr *)&from, &len);
+ if (res == -1) {
+ msg("recvfrom failed on udp transport.");
+ goto error;
+ }
+ time_valid = 1;
+ } else {
+ int res;
+
+ oldsig = (void (*)(int))signal(SIGALRM, alarm_hndler);
+ saw_alarm = 0; /* global tracking the alarm */
+ alarm(20); /* only wait 20 seconds */
+ res = _connect(s, (struct sockaddr *)&sin, sizeof(sin));
+ if (res == -1) {
+ msg("failed to connect to tcp endpoint.");
+ goto error;
+ }
+ if (saw_alarm) {
+ msg("alarm caught it, must be unreachable.");
+ goto error;
+ }
+ res = _read(s, (char *)&thetime, sizeof(thetime));
+ if (res != sizeof(thetime)) {
+ if (saw_alarm)
+ msg("timed out TCP call.");
+ else
+ msg("wrong size of results returned");
+
+ goto error;
+ }
+ time_valid = 1;
+ }
+ save = errno;
+ (void)_close(s);
+ errno = save;
+ s = RPC_ANYSOCK;
+
+ if (time_valid) {
+ thetime = ntohl(thetime);
+ thetime = thetime - TOFFSET; /* adjust to UNIX time */
+ } else
+ thetime = 0;
+ }
+
+ gettimeofday(&tv, 0);
+
+error:
+ /*
+ * clean up our allocated data structures.
+ */
+
+ if (s != RPC_ANYSOCK)
+ (void)_close(s);
+
+ if (clnt != NULL)
+ clnt_destroy(clnt);
+
+ alarm(0); /* reset that alarm if its outstanding */
+ if (oldsig) {
+ signal(SIGALRM, oldsig);
+ }
+
+ /*
+ * note, don't free uaddr strings until after we've made a
+ * copy of them.
+ */
+ if (time_valid) {
+ if (*uaddr == NULL)
+ *uaddr = strdup(useua);
+
+ /* Round to the nearest second */
+ tv.tv_sec += (tv.tv_sec > 500000) ? 1 : 0;
+ delta = (thetime > tv.tv_sec) ? thetime - tv.tv_sec :
+ tv.tv_sec - thetime;
+ td->tv_sec = (thetime < tv.tv_sec) ? - delta : delta;
+ td->tv_usec = 0;
+ } else {
+ msg("unable to get the server's time.");
+ }
+
+ if (needfree)
+ free_eps(teps, tsrv.ep.ep_len);
+
+ return (time_valid);
+}
diff --git a/lib/libc/rpc/auth_unix.c b/lib/libc/rpc/auth_unix.c
new file mode 100644
index 000000000000..14043358e358
--- /dev/null
+++ b/lib/libc/rpc/auth_unix.c
@@ -0,0 +1,370 @@
+/* $NetBSD: auth_unix.c,v 1.18 2000/07/06 03:03:30 christos Exp $ */
+
+/*-
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *sccsid2 = "@(#)auth_unix.c 1.19 87/08/11 Copyr 1984 Sun Micro";
+static char *sccsid = "@(#)auth_unix.c 2.2 88/08/01 4.0 RPCSRC";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * auth_unix.c, Implements UNIX style authentication parameters.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ * The system is very weak. The client uses no encryption for it's
+ * credentials and only sends null verifiers. The server sends backs
+ * null verifiers or optionally a verifier that suggests a new short hand
+ * for the credentials.
+ *
+ */
+
+#include "namespace.h"
+#include "reentrant.h"
+#include <sys/param.h>
+
+#include <assert.h>
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#include <rpc/auth.h>
+#include <rpc/auth_unix.h>
+#include "un-namespace.h"
+#include "mt_misc.h"
+
+/* auth_unix.c */
+static void authunix_nextverf (AUTH *);
+static bool_t authunix_marshal (AUTH *, XDR *);
+static bool_t authunix_validate (AUTH *, struct opaque_auth *);
+static bool_t authunix_refresh (AUTH *, void *);
+static void authunix_destroy (AUTH *);
+static void marshal_new_auth (AUTH *);
+static struct auth_ops *authunix_ops (void);
+
+/*
+ * This struct is pointed to by the ah_private field of an auth_handle.
+ */
+struct audata {
+ struct opaque_auth au_origcred; /* original credentials */
+ struct opaque_auth au_shcred; /* short hand cred */
+ u_long au_shfaults; /* short hand cache faults */
+ char au_marshed[MAX_AUTH_BYTES];
+ u_int au_mpos; /* xdr pos at end of marshed */
+};
+#define AUTH_PRIVATE(auth) ((struct audata *)auth->ah_private)
+
+/*
+ * Create a unix style authenticator.
+ * Returns an auth handle with the given stuff in it.
+ */
+AUTH *
+authunix_create(char *machname, u_int uid, u_int gid, int len, u_int *aup_gids)
+{
+ struct authunix_parms aup;
+ char mymem[MAX_AUTH_BYTES];
+ struct timeval now;
+ XDR xdrs;
+ AUTH *auth;
+ struct audata *au;
+
+ /*
+ * Allocate and set up auth handle
+ */
+ au = NULL;
+ auth = mem_alloc(sizeof(*auth));
+#ifndef _KERNEL
+ if (auth == NULL) {
+ warnx("authunix_create: out of memory");
+ goto cleanup_authunix_create;
+ }
+#endif
+ au = mem_alloc(sizeof(*au));
+#ifndef _KERNEL
+ if (au == NULL) {
+ warnx("authunix_create: out of memory");
+ goto cleanup_authunix_create;
+ }
+#endif
+ auth->ah_ops = authunix_ops();
+ auth->ah_private = (caddr_t)au;
+ auth->ah_verf = au->au_shcred = _null_auth;
+ au->au_shfaults = 0;
+ au->au_origcred.oa_base = NULL;
+
+ /*
+ * fill in param struct from the given params
+ */
+ (void)gettimeofday(&now, NULL);
+ aup.aup_time = now.tv_sec;
+ aup.aup_machname = machname;
+ aup.aup_uid = uid;
+ aup.aup_gid = gid;
+ aup.aup_len = (u_int)len;
+ aup.aup_gids = aup_gids;
+
+ /*
+ * Serialize the parameters into origcred
+ */
+ xdrmem_create(&xdrs, mymem, MAX_AUTH_BYTES, XDR_ENCODE);
+ if (! xdr_authunix_parms(&xdrs, &aup))
+ abort();
+ au->au_origcred.oa_length = len = XDR_GETPOS(&xdrs);
+ au->au_origcred.oa_flavor = AUTH_UNIX;
+#ifdef _KERNEL
+ au->au_origcred.oa_base = mem_alloc((u_int) len);
+#else
+ if ((au->au_origcred.oa_base = mem_alloc((u_int) len)) == NULL) {
+ warnx("authunix_create: out of memory");
+ goto cleanup_authunix_create;
+ }
+#endif
+ memmove(au->au_origcred.oa_base, mymem, (size_t)len);
+
+ /*
+ * set auth handle to reflect new cred.
+ */
+ auth->ah_cred = au->au_origcred;
+ marshal_new_auth(auth);
+ return (auth);
+#ifndef _KERNEL
+ cleanup_authunix_create:
+ if (auth)
+ mem_free(auth, sizeof(*auth));
+ if (au) {
+ if (au->au_origcred.oa_base)
+ mem_free(au->au_origcred.oa_base, (u_int)len);
+ mem_free(au, sizeof(*au));
+ }
+ return (NULL);
+#endif
+}
+
+/*
+ * Returns an auth handle with parameters determined by doing lots of
+ * syscalls.
+ */
+AUTH *
+authunix_create_default(void)
+{
+ AUTH *auth;
+ int ngids;
+ long ngids_max;
+ char machname[MAXHOSTNAMELEN + 1];
+ uid_t uid;
+ gid_t gid;
+ gid_t *gids;
+
+ ngids_max = sysconf(_SC_NGROUPS_MAX) + 1;
+ gids = malloc(sizeof(gid_t) * ngids_max);
+ if (gids == NULL)
+ return (NULL);
+
+ if (gethostname(machname, sizeof machname) == -1)
+ abort();
+ machname[sizeof(machname) - 1] = 0;
+ uid = geteuid();
+ gid = getegid();
+ if ((ngids = getgroups(ngids_max, gids)) < 0)
+ abort();
+ if (ngids > NGRPS)
+ ngids = NGRPS;
+ /* XXX: interface problem; we should translate from uid_t and gid_t */
+ auth = authunix_create(machname, uid, gid, ngids, gids);
+ free(gids);
+ return (auth);
+}
+
+/*
+ * authunix operations
+ */
+
+/* ARGSUSED */
+static void
+authunix_nextverf(AUTH *auth)
+{
+ /* no action necessary */
+}
+
+static bool_t
+authunix_marshal(AUTH *auth, XDR *xdrs)
+{
+ struct audata *au;
+
+ assert(auth != NULL);
+ assert(xdrs != NULL);
+
+ au = AUTH_PRIVATE(auth);
+ return (XDR_PUTBYTES(xdrs, au->au_marshed, au->au_mpos));
+}
+
+static bool_t
+authunix_validate(AUTH *auth, struct opaque_auth *verf)
+{
+ struct audata *au;
+ XDR xdrs;
+
+ assert(auth != NULL);
+ assert(verf != NULL);
+
+ if (verf->oa_flavor == AUTH_SHORT) {
+ au = AUTH_PRIVATE(auth);
+ xdrmem_create(&xdrs, verf->oa_base, verf->oa_length,
+ XDR_DECODE);
+
+ if (au->au_shcred.oa_base != NULL) {
+ mem_free(au->au_shcred.oa_base,
+ au->au_shcred.oa_length);
+ au->au_shcred.oa_base = NULL;
+ }
+ if (xdr_opaque_auth(&xdrs, &au->au_shcred)) {
+ auth->ah_cred = au->au_shcred;
+ } else {
+ xdrs.x_op = XDR_FREE;
+ (void)xdr_opaque_auth(&xdrs, &au->au_shcred);
+ au->au_shcred.oa_base = NULL;
+ auth->ah_cred = au->au_origcred;
+ }
+ marshal_new_auth(auth);
+ }
+ return (TRUE);
+}
+
+static bool_t
+authunix_refresh(AUTH *auth, void *dummy)
+{
+ struct audata *au = AUTH_PRIVATE(auth);
+ struct authunix_parms aup;
+ struct timeval now;
+ XDR xdrs;
+ int stat;
+
+ assert(auth != NULL);
+
+ if (auth->ah_cred.oa_base == au->au_origcred.oa_base) {
+ /* there is no hope. Punt */
+ return (FALSE);
+ }
+ au->au_shfaults ++;
+
+ /* first deserialize the creds back into a struct authunix_parms */
+ aup.aup_machname = NULL;
+ aup.aup_gids = NULL;
+ xdrmem_create(&xdrs, au->au_origcred.oa_base,
+ au->au_origcred.oa_length, XDR_DECODE);
+ stat = xdr_authunix_parms(&xdrs, &aup);
+ if (! stat)
+ goto done;
+
+ /* update the time and serialize in place */
+ (void)gettimeofday(&now, NULL);
+ aup.aup_time = now.tv_sec;
+ xdrs.x_op = XDR_ENCODE;
+ XDR_SETPOS(&xdrs, 0);
+ stat = xdr_authunix_parms(&xdrs, &aup);
+ if (! stat)
+ goto done;
+ auth->ah_cred = au->au_origcred;
+ marshal_new_auth(auth);
+done:
+ /* free the struct authunix_parms created by deserializing */
+ xdrs.x_op = XDR_FREE;
+ (void)xdr_authunix_parms(&xdrs, &aup);
+ XDR_DESTROY(&xdrs);
+ return (stat);
+}
+
+static void
+authunix_destroy(AUTH *auth)
+{
+ struct audata *au;
+
+ assert(auth != NULL);
+
+ au = AUTH_PRIVATE(auth);
+ mem_free(au->au_origcred.oa_base, au->au_origcred.oa_length);
+
+ if (au->au_shcred.oa_base != NULL)
+ mem_free(au->au_shcred.oa_base, au->au_shcred.oa_length);
+
+ mem_free(auth->ah_private, sizeof(struct audata));
+
+ if (auth->ah_verf.oa_base != NULL)
+ mem_free(auth->ah_verf.oa_base, auth->ah_verf.oa_length);
+
+ mem_free(auth, sizeof(*auth));
+}
+
+/*
+ * Marshals (pre-serializes) an auth struct.
+ * sets private data, au_marshed and au_mpos
+ */
+static void
+marshal_new_auth(AUTH *auth)
+{
+ XDR xdr_stream;
+ XDR *xdrs = &xdr_stream;
+ struct audata *au;
+
+ assert(auth != NULL);
+
+ au = AUTH_PRIVATE(auth);
+ xdrmem_create(xdrs, au->au_marshed, MAX_AUTH_BYTES, XDR_ENCODE);
+ if ((! xdr_opaque_auth(xdrs, &(auth->ah_cred))) ||
+ (! xdr_opaque_auth(xdrs, &(auth->ah_verf))))
+ warnx("auth_none.c - Fatal marshalling problem");
+ else
+ au->au_mpos = XDR_GETPOS(xdrs);
+ XDR_DESTROY(xdrs);
+}
+
+static struct auth_ops *
+authunix_ops(void)
+{
+ static struct auth_ops ops;
+
+ /* VARIABLES PROTECTED BY ops_lock: ops */
+
+ mutex_lock(&ops_lock);
+ if (ops.ah_nextverf == NULL) {
+ ops.ah_nextverf = authunix_nextverf;
+ ops.ah_marshal = authunix_marshal;
+ ops.ah_validate = authunix_validate;
+ ops.ah_refresh = authunix_refresh;
+ ops.ah_destroy = authunix_destroy;
+ }
+ mutex_unlock(&ops_lock);
+ return (&ops);
+}
diff --git a/lib/libc/rpc/authdes_prot.c b/lib/libc/rpc/authdes_prot.c
new file mode 100644
index 000000000000..0d4bec06264a
--- /dev/null
+++ b/lib/libc/rpc/authdes_prot.c
@@ -0,0 +1,89 @@
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)authdes_prot.c 2.1 88/07/29 4.0 RPCSRC; from 1.6 88/02/08 SMI";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*-
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 1986-1991 by Sun Microsystems Inc.
+ */
+
+/*
+ * authdes_prot.c, XDR routines for DES authentication
+ */
+
+#include "namespace.h"
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#include <rpc/auth.h>
+#include <rpc/auth_des.h>
+#include "un-namespace.h"
+
+#define ATTEMPT(xdr_op) if (!(xdr_op)) return (FALSE)
+
+bool_t
+xdr_authdes_cred(XDR *xdrs, struct authdes_cred *cred)
+{
+ enum authdes_namekind *padc_namekind = &cred->adc_namekind;
+ /*
+ * Unrolled xdr
+ */
+ ATTEMPT(xdr_enum(xdrs, (enum_t *) padc_namekind));
+ switch (cred->adc_namekind) {
+ case ADN_FULLNAME:
+ ATTEMPT(xdr_string(xdrs, &cred->adc_fullname.name,
+ MAXNETNAMELEN));
+ ATTEMPT(xdr_opaque(xdrs, (caddr_t)&cred->adc_fullname.key,
+ sizeof(des_block)));
+ ATTEMPT(xdr_opaque(xdrs, (caddr_t)&cred->adc_fullname.window,
+ sizeof(cred->adc_fullname.window)));
+ return (TRUE);
+ case ADN_NICKNAME:
+ ATTEMPT(xdr_opaque(xdrs, (caddr_t)&cred->adc_nickname,
+ sizeof(cred->adc_nickname)));
+ return (TRUE);
+ default:
+ return (FALSE);
+ }
+}
+
+
+bool_t
+xdr_authdes_verf(XDR *xdrs, struct authdes_verf *verf)
+{
+ /*
+ * Unrolled xdr
+ */
+ ATTEMPT(xdr_opaque(xdrs, (caddr_t)&verf->adv_xtimestamp,
+ sizeof(des_block)));
+ ATTEMPT(xdr_opaque(xdrs, (caddr_t)&verf->adv_int_u,
+ sizeof(verf->adv_int_u)));
+ return (TRUE);
+}
diff --git a/lib/libc/rpc/authunix_prot.c b/lib/libc/rpc/authunix_prot.c
new file mode 100644
index 000000000000..cd6676bda2b3
--- /dev/null
+++ b/lib/libc/rpc/authunix_prot.c
@@ -0,0 +1,76 @@
+/* $NetBSD: authunix_prot.c,v 1.12 2000/01/22 22:19:17 mycroft Exp $ */
+
+/*-
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *sccsid2 = "@(#)authunix_prot.c 1.15 87/08/11 Copyr 1984 Sun Micro";
+static char *sccsid = "@(#)authunix_prot.c 2.1 88/07/29 4.0 RPCSRC";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * authunix_prot.c
+ * XDR for UNIX style authentication parameters for RPC
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#include "namespace.h"
+#include <assert.h>
+
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#include <rpc/auth.h>
+#include <rpc/auth_unix.h>
+#include "un-namespace.h"
+
+/*
+ * XDR for unix authentication parameters.
+ */
+bool_t
+xdr_authunix_parms(XDR *xdrs, struct authunix_parms *p)
+{
+ u_int **paup_gids;
+
+ assert(xdrs != NULL);
+ assert(p != NULL);
+
+ paup_gids = &p->aup_gids;
+
+ if (xdr_u_long(xdrs, &(p->aup_time)) &&
+ xdr_string(xdrs, &(p->aup_machname), MAX_MACHINE_NAME) &&
+ xdr_u_int(xdrs, &(p->aup_uid)) &&
+ xdr_u_int(xdrs, &(p->aup_gid)) &&
+ xdr_array(xdrs, (char **) paup_gids,
+ &(p->aup_len), NGRPS, sizeof(u_int), (xdrproc_t)xdr_u_int) ) {
+ return (TRUE);
+ }
+ return (FALSE);
+}
diff --git a/lib/libc/rpc/bindresvport.3 b/lib/libc/rpc/bindresvport.3
new file mode 100644
index 000000000000..28e86e5f2a6f
--- /dev/null
+++ b/lib/libc/rpc/bindresvport.3
@@ -0,0 +1,103 @@
+.\" @(#)bindresvport.3n 2.2 88/08/02 4.0 RPCSRC; from 1.7 88/03/14 SMI
+.\" $NetBSD: bindresvport.3,v 1.8 2000/07/05 15:45:33 msaitoh Exp $
+.\" $FreeBSD$
+.\"
+.Dd November 22, 1987
+.Dt BINDRESVPORT 3
+.Os
+.Sh NAME
+.Nm bindresvport ,
+.Nm bindresvport_sa
+.Nd bind a socket to a privileged IP port
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In rpc/rpc.h
+.Ft int
+.Fn bindresvport "int sd" "struct sockaddr_in *sin"
+.Ft int
+.Fn bindresvport_sa "int sd" "struct sockaddr *sa"
+.Sh DESCRIPTION
+The
+.Fn bindresvport
+and
+.Fn bindresvport_sa
+functions
+are used to bind a socket descriptor to a privileged
+.Tn IP
+port, that is, a
+port number in the range 0-1023.
+.Pp
+If
+.Fa sin
+is a pointer to a
+.Ft "struct sockaddr_in"
+then the appropriate fields in the structure should be defined.
+Note that
+.Fa sin->sin_family
+must be initialized to the address family of the socket, passed by
+.Fa sd .
+If
+.Fa sin->sin_port
+is
+.Sq 0
+then an anonymous port (in the range 600-1023) will be
+chosen, and if
+.Xr bind 2
+is successful, the
+.Fa sin->sin_port
+will be updated to contain the allocated port.
+.Pp
+If
+.Fa sin
+is the
+.Dv NULL
+pointer,
+an anonymous port will be allocated (as above).
+However, there is no way for
+.Fn bindresvport
+to return the allocated port in this case.
+.Pp
+Only root can bind to a privileged port; this call will fail for any
+other users.
+.Pp
+Function prototype of
+.Fn bindresvport
+is biased to
+.Dv AF_INET
+socket.
+The
+.Fn bindresvport_sa
+function
+acts exactly the same, with more neutral function prototype.
+Note that both functions behave exactly the same, and
+both support
+.Dv AF_INET6
+sockets as well as
+.Dv AF_INET
+sockets.
+.Sh RETURN VALUES
+.Rv -std bindresvport
+.Sh ERRORS
+.Bl -tag -width Er
+.It Bq Er EPFNOSUPPORT
+If second argument was supplied,
+and address family did not match between arguments.
+.El
+.Pp
+The
+.Fn bindresvport
+function
+may also fail and set
+.Va errno
+for any of the errors specified for the calls
+.Xr bind 2 ,
+.Xr getsockopt 2 ,
+or
+.Xr setsockopt 2 .
+.Sh SEE ALSO
+.Xr bind 2 ,
+.Xr getsockopt 2 ,
+.Xr setsockopt 2 ,
+.Xr ip 4
diff --git a/lib/libc/rpc/bindresvport.c b/lib/libc/rpc/bindresvport.c
new file mode 100644
index 000000000000..8629cba5ea39
--- /dev/null
+++ b/lib/libc/rpc/bindresvport.c
@@ -0,0 +1,156 @@
+/* $NetBSD: bindresvport.c,v 1.19 2000/07/06 03:03:59 christos Exp $ */
+
+/*-
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *sccsid2 = "from: @(#)bindresvport.c 1.8 88/02/08 SMI";
+static char *sccsid = "from: @(#)bindresvport.c 2.2 88/07/29 4.0 RPCSRC";
+#endif
+/* from: $OpenBSD: bindresvport.c,v 1.7 1996/07/30 16:25:47 downsj Exp $ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Copyright (c) 1987 by Sun Microsystems, Inc.
+ *
+ * Portions Copyright(C) 1996, Jason Downs. All rights reserved.
+ */
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <rpc/rpc.h>
+
+#include <string.h>
+#include "un-namespace.h"
+
+/*
+ * Bind a socket to a privileged IP port
+ */
+int
+bindresvport(int sd, struct sockaddr_in *sin)
+{
+ return bindresvport_sa(sd, (struct sockaddr *)sin);
+}
+
+/*
+ * Bind a socket to a privileged IP port
+ */
+int
+bindresvport_sa(int sd, struct sockaddr *sa)
+{
+ int old, error, af;
+ struct sockaddr_storage myaddr;
+ struct sockaddr_in *sin;
+#ifdef INET6
+ struct sockaddr_in6 *sin6;
+#endif
+ int proto, portrange, portlow;
+ u_int16_t *portp;
+ socklen_t salen;
+
+ if (sa == NULL) {
+ salen = sizeof(myaddr);
+ sa = (struct sockaddr *)&myaddr;
+
+ if (_getsockname(sd, sa, &salen) == -1)
+ return -1; /* errno is correctly set */
+
+ af = sa->sa_family;
+ memset(sa, 0, salen);
+ } else
+ af = sa->sa_family;
+
+ switch (af) {
+ case AF_INET:
+ proto = IPPROTO_IP;
+ portrange = IP_PORTRANGE;
+ portlow = IP_PORTRANGE_LOW;
+ sin = (struct sockaddr_in *)sa;
+ salen = sizeof(struct sockaddr_in);
+ portp = &sin->sin_port;
+ break;
+#ifdef INET6
+ case AF_INET6:
+ proto = IPPROTO_IPV6;
+ portrange = IPV6_PORTRANGE;
+ portlow = IPV6_PORTRANGE_LOW;
+ sin6 = (struct sockaddr_in6 *)sa;
+ salen = sizeof(struct sockaddr_in6);
+ portp = &sin6->sin6_port;
+ break;
+#endif
+ default:
+ errno = EPFNOSUPPORT;
+ return (-1);
+ }
+ sa->sa_family = af;
+ sa->sa_len = salen;
+
+ if (*portp == 0) {
+ socklen_t oldlen = sizeof(old);
+
+ error = _getsockopt(sd, proto, portrange, &old, &oldlen);
+ if (error < 0)
+ return (error);
+
+ error = _setsockopt(sd, proto, portrange, &portlow,
+ sizeof(portlow));
+ if (error < 0)
+ return (error);
+ }
+
+ error = _bind(sd, sa, salen);
+
+ if (*portp == 0) {
+ int saved_errno = errno;
+
+ if (error < 0) {
+ if (_setsockopt(sd, proto, portrange, &old,
+ sizeof(old)) < 0)
+ errno = saved_errno;
+ return (error);
+ }
+
+ if (sa != (struct sockaddr *)&myaddr) {
+ /* Hmm, what did the kernel assign? */
+ if (_getsockname(sd, sa, &salen) < 0)
+ errno = saved_errno;
+ return (error);
+ }
+ }
+ return (error);
+}
diff --git a/lib/libc/rpc/clnt_bcast.c b/lib/libc/rpc/clnt_bcast.c
new file mode 100644
index 000000000000..669de8aae3c9
--- /dev/null
+++ b/lib/libc/rpc/clnt_bcast.c
@@ -0,0 +1,679 @@
+/* $NetBSD: clnt_bcast.c,v 1.3 2000/07/06 03:05:20 christos Exp $ */
+
+/*-
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 1986-1991 by Sun Microsystems Inc.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+#ident "@(#)clnt_bcast.c 1.18 94/05/03 SMI"
+static char sccsid[] = "@(#)clnt_bcast.c 1.15 89/04/21 Copyr 1988 Sun Micro";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+
+/*
+ * clnt_bcast.c
+ * Client interface to broadcast service.
+ *
+ * Copyright (C) 1988, Sun Microsystems, Inc.
+ *
+ * The following is kludged-up support for simple rpc broadcasts.
+ * Someday a large, complicated system will replace these routines.
+ */
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/queue.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <ifaddrs.h>
+#include <sys/poll.h>
+#include <rpc/rpc.h>
+#ifdef PORTMAP
+#include <rpc/pmap_prot.h>
+#include <rpc/pmap_clnt.h>
+#include <rpc/pmap_rmt.h>
+#endif /* PORTMAP */
+#include <rpc/nettype.h>
+#include <arpa/inet.h>
+#ifdef RPC_DEBUG
+#include <stdio.h>
+#endif
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <err.h>
+#include <string.h>
+#include "un-namespace.h"
+
+#include "rpc_com.h"
+
+#define MAXBCAST 20 /* Max no of broadcasting transports */
+#define INITTIME 4000 /* Time to wait initially */
+#define WAITTIME 8000 /* Maximum time to wait */
+
+/*
+ * If nettype is NULL, it broadcasts on all the available
+ * datagram_n transports. May potentially lead to broadacst storms
+ * and hence should be used with caution, care and courage.
+ *
+ * The current parameter xdr packet size is limited by the max tsdu
+ * size of the transport. If the max tsdu size of any transport is
+ * smaller than the parameter xdr packet, then broadcast is not
+ * sent on that transport.
+ *
+ * Also, the packet size should be less the packet size of
+ * the data link layer (for ethernet it is 1400 bytes). There is
+ * no easy way to find out the max size of the data link layer and
+ * we are assuming that the args would be smaller than that.
+ *
+ * The result size has to be smaller than the transport tsdu size.
+ *
+ * If PORTMAP has been defined, we send two packets for UDP, one for
+ * rpcbind and one for portmap. For those machines which support
+ * both rpcbind and portmap, it will cause them to reply twice, and
+ * also here it will get two responses ... inefficient and clumsy.
+ */
+
+struct broadif {
+ int index;
+ struct sockaddr_storage broadaddr;
+ TAILQ_ENTRY(broadif) link;
+};
+
+typedef TAILQ_HEAD(, broadif) broadlist_t;
+
+int __rpc_getbroadifs(int, int, int, broadlist_t *);
+void __rpc_freebroadifs(broadlist_t *);
+int __rpc_broadenable(int, int, struct broadif *);
+
+int __rpc_lowvers = 0;
+
+int
+__rpc_getbroadifs(int af, int proto, int socktype, broadlist_t *list)
+{
+ int count = 0;
+ struct broadif *bip;
+ struct ifaddrs *ifap, *ifp;
+#ifdef INET6
+ struct sockaddr_in6 *sin6;
+#endif
+ struct sockaddr_in *sin;
+ struct addrinfo hints, *res;
+
+ if (getifaddrs(&ifp) < 0)
+ return 0;
+
+ memset(&hints, 0, sizeof hints);
+
+ hints.ai_family = af;
+ hints.ai_protocol = proto;
+ hints.ai_socktype = socktype;
+
+ if (getaddrinfo(NULL, "sunrpc", &hints, &res) != 0) {
+ freeifaddrs(ifp);
+ return 0;
+ }
+
+ for (ifap = ifp; ifap != NULL; ifap = ifap->ifa_next) {
+ if (ifap->ifa_addr->sa_family != af ||
+ !(ifap->ifa_flags & IFF_UP))
+ continue;
+ bip = (struct broadif *)malloc(sizeof *bip);
+ if (bip == NULL)
+ break;
+ bip->index = if_nametoindex(ifap->ifa_name);
+ if (
+#ifdef INET6
+ af != AF_INET6 &&
+#endif
+ (ifap->ifa_flags & IFF_BROADCAST) &&
+ ifap->ifa_broadaddr) {
+ memcpy(&bip->broadaddr, ifap->ifa_broadaddr,
+ (size_t)ifap->ifa_broadaddr->sa_len);
+ sin = (struct sockaddr_in *)(void *)&bip->broadaddr;
+ sin->sin_port =
+ ((struct sockaddr_in *)
+ (void *)res->ai_addr)->sin_port;
+ } else
+#ifdef INET6
+ if (af == AF_INET6 && (ifap->ifa_flags & IFF_MULTICAST)) {
+ sin6 = (struct sockaddr_in6 *)(void *)&bip->broadaddr;
+ inet_pton(af, RPCB_MULTICAST_ADDR, &sin6->sin6_addr);
+ sin6->sin6_family = af;
+ sin6->sin6_len = sizeof *sin6;
+ sin6->sin6_port =
+ ((struct sockaddr_in6 *)
+ (void *)res->ai_addr)->sin6_port;
+ sin6->sin6_scope_id = bip->index;
+ } else
+#endif
+ {
+ free(bip);
+ continue;
+ }
+ TAILQ_INSERT_TAIL(list, bip, link);
+ count++;
+ }
+ freeifaddrs(ifp);
+ freeaddrinfo(res);
+
+ return count;
+}
+
+void
+__rpc_freebroadifs(broadlist_t *list)
+{
+ struct broadif *bip, *next;
+
+ bip = TAILQ_FIRST(list);
+
+ while (bip != NULL) {
+ next = TAILQ_NEXT(bip, link);
+ free(bip);
+ bip = next;
+ }
+}
+
+int
+/*ARGSUSED*/
+__rpc_broadenable(int af, int s, struct broadif *bip)
+{
+ int o = 1;
+
+#if 0
+ if (af == AF_INET6) {
+ fprintf(stderr, "set v6 multicast if to %d\n", bip->index);
+ if (_setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &bip->index,
+ sizeof bip->index) < 0)
+ return -1;
+ } else
+#endif
+ if (_setsockopt(s, SOL_SOCKET, SO_BROADCAST, &o, sizeof o) < 0)
+ return -1;
+
+ return 0;
+}
+
+/*
+ * rpc_broadcast_exp()
+ *
+ * prog - program number
+ * vers - version number
+ * proc - procedure number
+ * xargs - xdr routine for args
+ * argsp - pointer to args
+ * xresults - xdr routine for results
+ * resultsp - pointer to results
+ * eachresult - call with each result obtained
+ * inittime - how long to wait initially
+ * waittime - maximum time to wait
+ * nettype - transport type
+ */
+enum clnt_stat
+rpc_broadcast_exp(rpcprog_t prog, rpcvers_t vers, rpcproc_t proc,
+ xdrproc_t xargs, caddr_t argsp, xdrproc_t xresults, caddr_t resultsp,
+ resultproc_t eachresult, int inittime, int waittime,
+ const char *nettype)
+{
+ enum clnt_stat stat = RPC_SUCCESS; /* Return status */
+ XDR xdr_stream; /* XDR stream */
+ XDR *xdrs = &xdr_stream;
+ struct rpc_msg msg; /* RPC message */
+ struct timeval t;
+ char *outbuf = NULL; /* Broadcast msg buffer */
+ char *inbuf = NULL; /* Reply buf */
+ int inlen;
+ u_int maxbufsize = 0;
+ AUTH *sys_auth = authunix_create_default();
+ u_int i;
+ void *handle;
+ char uaddress[1024]; /* A self imposed limit */
+ char *uaddrp = uaddress;
+ int pmap_reply_flag; /* reply recvd from PORTMAP */
+ /* An array of all the suitable broadcast transports */
+ struct {
+ int fd; /* File descriptor */
+ int af;
+ int proto;
+ struct netconfig *nconf; /* Netconfig structure */
+ u_int asize; /* Size of the addr buf */
+ u_int dsize; /* Size of the data buf */
+ struct sockaddr_storage raddr; /* Remote address */
+ broadlist_t nal;
+ } fdlist[MAXBCAST];
+ struct pollfd pfd[MAXBCAST];
+ size_t fdlistno = 0;
+ struct r_rpcb_rmtcallargs barg; /* Remote arguments */
+ struct r_rpcb_rmtcallres bres; /* Remote results */
+ size_t outlen;
+ struct netconfig *nconf;
+ int msec;
+ int pollretval;
+ int fds_found;
+
+#ifdef PORTMAP
+ size_t outlen_pmap = 0;
+ u_long port; /* Remote port number */
+ int pmap_flag = 0; /* UDP exists ? */
+ char *outbuf_pmap = NULL;
+ struct rmtcallargs barg_pmap; /* Remote arguments */
+ struct rmtcallres bres_pmap; /* Remote results */
+ u_int udpbufsz = 0;
+#endif /* PORTMAP */
+
+ if (sys_auth == NULL) {
+ return (RPC_SYSTEMERROR);
+ }
+ /*
+ * initialization: create a fd, a broadcast address, and send the
+ * request on the broadcast transport.
+ * Listen on all of them and on replies, call the user supplied
+ * function.
+ */
+
+ if (nettype == NULL)
+ nettype = "datagram_n";
+ if ((handle = __rpc_setconf(nettype)) == NULL) {
+ AUTH_DESTROY(sys_auth);
+ return (RPC_UNKNOWNPROTO);
+ }
+ while ((nconf = __rpc_getconf(handle)) != NULL) {
+ int fd;
+ struct __rpc_sockinfo si;
+
+ if (nconf->nc_semantics != NC_TPI_CLTS)
+ continue;
+ if (fdlistno >= MAXBCAST)
+ break; /* No more slots available */
+ if (!__rpc_nconf2sockinfo(nconf, &si))
+ continue;
+
+ TAILQ_INIT(&fdlist[fdlistno].nal);
+ if (__rpc_getbroadifs(si.si_af, si.si_proto, si.si_socktype,
+ &fdlist[fdlistno].nal) == 0)
+ continue;
+
+ fd = _socket(si.si_af, si.si_socktype, si.si_proto);
+ if (fd < 0) {
+ stat = RPC_CANTSEND;
+ continue;
+ }
+ fdlist[fdlistno].af = si.si_af;
+ fdlist[fdlistno].proto = si.si_proto;
+ fdlist[fdlistno].fd = fd;
+ fdlist[fdlistno].nconf = nconf;
+ fdlist[fdlistno].asize = __rpc_get_a_size(si.si_af);
+ pfd[fdlistno].events = POLLIN | POLLPRI |
+ POLLRDNORM | POLLRDBAND;
+ pfd[fdlistno].fd = fdlist[fdlistno].fd = fd;
+ fdlist[fdlistno].dsize = __rpc_get_t_size(si.si_af, si.si_proto,
+ 0);
+
+ if (maxbufsize <= fdlist[fdlistno].dsize)
+ maxbufsize = fdlist[fdlistno].dsize;
+
+#ifdef PORTMAP
+ if (si.si_af == AF_INET && si.si_proto == IPPROTO_UDP) {
+ udpbufsz = fdlist[fdlistno].dsize;
+ outbuf_pmap = reallocf(outbuf_pmap, udpbufsz);
+ if (outbuf_pmap == NULL) {
+ _close(fd);
+ stat = RPC_SYSTEMERROR;
+ goto done_broad;
+ }
+ pmap_flag = 1;
+ }
+#endif /* PORTMAP */
+ fdlistno++;
+ }
+
+ if (fdlistno == 0) {
+ if (stat == RPC_SUCCESS)
+ stat = RPC_UNKNOWNPROTO;
+ goto done_broad;
+ }
+ if (maxbufsize == 0) {
+ if (stat == RPC_SUCCESS)
+ stat = RPC_CANTSEND;
+ goto done_broad;
+ }
+ inbuf = malloc(maxbufsize);
+ outbuf = malloc(maxbufsize);
+ if ((inbuf == NULL) || (outbuf == NULL)) {
+ stat = RPC_SYSTEMERROR;
+ goto done_broad;
+ }
+
+ /* Serialize all the arguments which have to be sent */
+ (void) gettimeofday(&t, NULL);
+ msg.rm_xid = __RPC_GETXID(&t);
+ msg.rm_direction = CALL;
+ msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
+ msg.rm_call.cb_prog = RPCBPROG;
+ msg.rm_call.cb_vers = RPCBVERS;
+ msg.rm_call.cb_proc = RPCBPROC_CALLIT;
+ barg.prog = prog;
+ barg.vers = vers;
+ barg.proc = proc;
+ barg.args.args_val = argsp;
+ barg.xdr_args = xargs;
+ bres.addr = uaddrp;
+ bres.results.results_val = resultsp;
+ bres.xdr_res = xresults;
+ msg.rm_call.cb_cred = sys_auth->ah_cred;
+ msg.rm_call.cb_verf = sys_auth->ah_verf;
+ xdrmem_create(xdrs, outbuf, maxbufsize, XDR_ENCODE);
+ if ((!xdr_callmsg(xdrs, &msg)) ||
+ (!xdr_rpcb_rmtcallargs(xdrs,
+ (struct rpcb_rmtcallargs *)(void *)&barg))) {
+ stat = RPC_CANTENCODEARGS;
+ goto done_broad;
+ }
+ outlen = xdr_getpos(xdrs);
+ xdr_destroy(xdrs);
+
+#ifdef PORTMAP
+ /* Prepare the packet for version 2 PORTMAP */
+ if (pmap_flag) {
+ msg.rm_xid++; /* One way to distinguish */
+ msg.rm_call.cb_prog = PMAPPROG;
+ msg.rm_call.cb_vers = PMAPVERS;
+ msg.rm_call.cb_proc = PMAPPROC_CALLIT;
+ barg_pmap.prog = prog;
+ barg_pmap.vers = vers;
+ barg_pmap.proc = proc;
+ barg_pmap.args_ptr = argsp;
+ barg_pmap.xdr_args = xargs;
+ bres_pmap.port_ptr = &port;
+ bres_pmap.xdr_results = xresults;
+ bres_pmap.results_ptr = resultsp;
+ xdrmem_create(xdrs, outbuf_pmap, udpbufsz, XDR_ENCODE);
+ if ((! xdr_callmsg(xdrs, &msg)) ||
+ (! xdr_rmtcall_args(xdrs, &barg_pmap))) {
+ stat = RPC_CANTENCODEARGS;
+ goto done_broad;
+ }
+ outlen_pmap = xdr_getpos(xdrs);
+ xdr_destroy(xdrs);
+ }
+#endif /* PORTMAP */
+
+ /*
+ * Basic loop: broadcast the packets to transports which
+ * support data packets of size such that one can encode
+ * all the arguments.
+ * Wait a while for response(s).
+ * The response timeout grows larger per iteration.
+ */
+ for (msec = inittime; msec <= waittime; msec += msec) {
+ struct broadif *bip;
+
+ /* Broadcast all the packets now */
+ for (i = 0; i < fdlistno; i++) {
+ if (fdlist[i].dsize < outlen) {
+ stat = RPC_CANTSEND;
+ continue;
+ }
+ for (bip = TAILQ_FIRST(&fdlist[i].nal); bip != NULL;
+ bip = TAILQ_NEXT(bip, link)) {
+ void *addr;
+
+ addr = &bip->broadaddr;
+
+ __rpc_broadenable(fdlist[i].af, fdlist[i].fd,
+ bip);
+
+ /*
+ * Only use version 3 if lowvers is not set
+ */
+
+ if (!__rpc_lowvers)
+ if (_sendto(fdlist[i].fd, outbuf,
+ outlen, 0, (struct sockaddr*)addr,
+ (size_t)fdlist[i].asize) !=
+ outlen) {
+#ifdef RPC_DEBUG
+ perror("sendto");
+#endif
+ warnx("clnt_bcast: cannot send "
+ "broadcast packet");
+ stat = RPC_CANTSEND;
+ continue;
+ }
+#ifdef RPC_DEBUG
+ if (!__rpc_lowvers)
+ fprintf(stderr, "Broadcast packet sent "
+ "for %s\n",
+ fdlist[i].nconf->nc_netid);
+#endif
+#ifdef PORTMAP
+ /*
+ * Send the version 2 packet also
+ * for UDP/IP
+ */
+ if (pmap_flag &&
+ fdlist[i].proto == IPPROTO_UDP) {
+ if (_sendto(fdlist[i].fd, outbuf_pmap,
+ outlen_pmap, 0, addr,
+ (size_t)fdlist[i].asize) !=
+ outlen_pmap) {
+ warnx("clnt_bcast: "
+ "Cannot send broadcast packet");
+ stat = RPC_CANTSEND;
+ continue;
+ }
+ }
+#ifdef RPC_DEBUG
+ fprintf(stderr, "PMAP Broadcast packet "
+ "sent for %s\n",
+ fdlist[i].nconf->nc_netid);
+#endif
+#endif /* PORTMAP */
+ }
+ /* End for sending all packets on this transport */
+ } /* End for sending on all transports */
+
+ if (eachresult == NULL) {
+ stat = RPC_SUCCESS;
+ goto done_broad;
+ }
+
+ /*
+ * Get all the replies from these broadcast requests
+ */
+ recv_again:
+
+ switch (pollretval = _poll(pfd, fdlistno, msec)) {
+ case 0: /* timed out */
+ stat = RPC_TIMEDOUT;
+ continue;
+ case -1: /* some kind of error - we ignore it */
+ goto recv_again;
+ } /* end of poll results switch */
+
+ for (i = fds_found = 0;
+ i < fdlistno && fds_found < pollretval; i++) {
+ bool_t done = FALSE;
+
+ if (pfd[i].revents == 0)
+ continue;
+ else if (pfd[i].revents & POLLNVAL) {
+ /*
+ * Something bad has happened to this descri-
+ * ptor. We can cause _poll() to ignore
+ * it simply by using a negative fd. We do that
+ * rather than compacting the pfd[] and fdlist[]
+ * arrays.
+ */
+ pfd[i].fd = -1;
+ fds_found++;
+ continue;
+ } else
+ fds_found++;
+#ifdef RPC_DEBUG
+ fprintf(stderr, "response for %s\n",
+ fdlist[i].nconf->nc_netid);
+#endif
+ try_again:
+ inlen = _recvfrom(fdlist[i].fd, inbuf, fdlist[i].dsize,
+ 0, (struct sockaddr *)(void *)&fdlist[i].raddr,
+ &fdlist[i].asize);
+ if (inlen < 0) {
+ if (errno == EINTR)
+ goto try_again;
+ warnx("clnt_bcast: Cannot receive reply to "
+ "broadcast");
+ stat = RPC_CANTRECV;
+ continue;
+ }
+ if (inlen < sizeof (u_int32_t))
+ continue; /* Drop that and go ahead */
+ /*
+ * see if reply transaction id matches sent id.
+ * If so, decode the results. If return id is xid + 1
+ * it was a PORTMAP reply
+ */
+ if (*((u_int32_t *)(void *)(inbuf)) ==
+ *((u_int32_t *)(void *)(outbuf))) {
+ pmap_reply_flag = 0;
+ msg.acpted_rply.ar_verf = _null_auth;
+ msg.acpted_rply.ar_results.where =
+ (caddr_t)(void *)&bres;
+ msg.acpted_rply.ar_results.proc =
+ (xdrproc_t)xdr_rpcb_rmtcallres;
+#ifdef PORTMAP
+ } else if (pmap_flag &&
+ *((u_int32_t *)(void *)(inbuf)) ==
+ *((u_int32_t *)(void *)(outbuf_pmap))) {
+ pmap_reply_flag = 1;
+ msg.acpted_rply.ar_verf = _null_auth;
+ msg.acpted_rply.ar_results.where =
+ (caddr_t)(void *)&bres_pmap;
+ msg.acpted_rply.ar_results.proc =
+ (xdrproc_t)xdr_rmtcallres;
+#endif /* PORTMAP */
+ } else
+ continue;
+ xdrmem_create(xdrs, inbuf, (u_int)inlen, XDR_DECODE);
+ if (xdr_replymsg(xdrs, &msg)) {
+ if ((msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
+ (msg.acpted_rply.ar_stat == SUCCESS)) {
+ struct netbuf taddr, *np;
+ struct sockaddr_in *sin;
+
+#ifdef PORTMAP
+ if (pmap_flag && pmap_reply_flag) {
+ sin = (struct sockaddr_in *)
+ (void *)&fdlist[i].raddr;
+ sin->sin_port =
+ htons((u_short)port);
+ taddr.len = taddr.maxlen =
+ fdlist[i].raddr.ss_len;
+ taddr.buf = &fdlist[i].raddr;
+ done = (*eachresult)(resultsp,
+ &taddr, fdlist[i].nconf);
+ } else {
+#endif /* PORTMAP */
+#ifdef RPC_DEBUG
+ fprintf(stderr, "uaddr %s\n",
+ uaddrp);
+#endif
+ np = uaddr2taddr(
+ fdlist[i].nconf, uaddrp);
+ done = (*eachresult)(resultsp,
+ np, fdlist[i].nconf);
+ free(np);
+#ifdef PORTMAP
+ }
+#endif /* PORTMAP */
+ }
+ /* otherwise, we just ignore the errors ... */
+ }
+ /* else some kind of deserialization problem ... */
+
+ xdrs->x_op = XDR_FREE;
+ msg.acpted_rply.ar_results.proc = (xdrproc_t) xdr_void;
+ (void) xdr_replymsg(xdrs, &msg);
+ (void) (*xresults)(xdrs, resultsp);
+ XDR_DESTROY(xdrs);
+ if (done) {
+ stat = RPC_SUCCESS;
+ goto done_broad;
+ } else {
+ goto recv_again;
+ }
+ } /* The recv for loop */
+ } /* The giant for loop */
+
+done_broad:
+ free(inbuf);
+ free(outbuf);
+#ifdef PORTMAP
+ free(outbuf_pmap);
+#endif /* PORTMAP */
+ for (i = 0; i < fdlistno; i++) {
+ (void)_close(fdlist[i].fd);
+ __rpc_freebroadifs(&fdlist[i].nal);
+ }
+ AUTH_DESTROY(sys_auth);
+ (void) __rpc_endconf(handle);
+
+ return (stat);
+}
+
+/*
+ * rpc_broadcast()
+ *
+ * prog - program number
+ * vers - version number
+ * proc - procedure number
+ * xargs - xdr routine for args
+ * argsp - pointer to args
+ * xresults - xdr routine for results
+ * resultsp - pointer to results
+ * eachresult - call with each result obtained
+ * nettype - transport type
+ */
+enum clnt_stat
+rpc_broadcast(rpcprog_t prog, rpcvers_t vers, rpcproc_t proc, xdrproc_t xargs,
+ caddr_t argsp, xdrproc_t xresults, caddr_t resultsp,
+ resultproc_t eachresult, const char *nettype)
+{
+ enum clnt_stat dummy;
+
+ dummy = rpc_broadcast_exp(prog, vers, proc, xargs, argsp,
+ xresults, resultsp, eachresult,
+ INITTIME, WAITTIME, nettype);
+ return (dummy);
+}
diff --git a/lib/libc/rpc/clnt_dg.c b/lib/libc/rpc/clnt_dg.c
new file mode 100644
index 000000000000..39677737bf5d
--- /dev/null
+++ b/lib/libc/rpc/clnt_dg.c
@@ -0,0 +1,851 @@
+/* $NetBSD: clnt_dg.c,v 1.4 2000/07/14 08:40:41 fvdl Exp $ */
+
+/*-
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 1986-1991 by Sun Microsystems Inc.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+#ident "@(#)clnt_dg.c 1.23 94/04/22 SMI"
+static char sccsid[] = "@(#)clnt_dg.c 1.19 89/03/16 Copyr 1988 Sun Micro";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Implements a connectionless client side RPC.
+ */
+
+#include "namespace.h"
+#include "reentrant.h"
+#include <sys/types.h>
+#include <sys/event.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <arpa/inet.h>
+#include <rpc/rpc.h>
+#include <rpc/rpcsec_gss.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <unistd.h>
+#include <err.h>
+#include "un-namespace.h"
+#include "rpc_com.h"
+#include "mt_misc.h"
+
+
+#ifdef _FREEFALL_CONFIG
+/*
+ * Disable RPC exponential back-off for FreeBSD.org systems.
+ */
+#define RPC_MAX_BACKOFF 1 /* second */
+#else
+#define RPC_MAX_BACKOFF 30 /* seconds */
+#endif
+
+
+static struct clnt_ops *clnt_dg_ops(void);
+static bool_t time_not_ok(struct timeval *);
+static enum clnt_stat clnt_dg_call(CLIENT *, rpcproc_t, xdrproc_t, void *,
+ xdrproc_t, void *, struct timeval);
+static void clnt_dg_geterr(CLIENT *, struct rpc_err *);
+static bool_t clnt_dg_freeres(CLIENT *, xdrproc_t, void *);
+static void clnt_dg_abort(CLIENT *);
+static bool_t clnt_dg_control(CLIENT *, u_int, void *);
+static void clnt_dg_destroy(CLIENT *);
+
+
+
+
+/*
+ * This machinery implements per-fd locks for MT-safety. It is not
+ * sufficient to do per-CLIENT handle locks for MT-safety because a
+ * user may create more than one CLIENT handle with the same fd behind
+ * it. Therfore, we allocate an array of flags (dg_fd_locks), protected
+ * by the clnt_fd_lock mutex, and an array (dg_cv) of condition variables
+ * similarly protected. Dg_fd_lock[fd] == 1 => a call is activte on some
+ * CLIENT handle created for that fd.
+ * The current implementation holds locks across the entire RPC and reply,
+ * including retransmissions. Yes, this is silly, and as soon as this
+ * code is proven to work, this should be the first thing fixed. One step
+ * at a time.
+ */
+static int *dg_fd_locks;
+static cond_t *dg_cv;
+#define release_fd_lock(fd, mask) { \
+ mutex_lock(&clnt_fd_lock); \
+ dg_fd_locks[fd] = 0; \
+ mutex_unlock(&clnt_fd_lock); \
+ thr_sigsetmask(SIG_SETMASK, &(mask), NULL); \
+ cond_signal(&dg_cv[fd]); \
+}
+
+static const char mem_err_clnt_dg[] = "clnt_dg_create: out of memory";
+
+/* VARIABLES PROTECTED BY clnt_fd_lock: dg_fd_locks, dg_cv */
+
+#define MCALL_MSG_SIZE 24
+
+/*
+ * Private data kept per client handle
+ */
+struct cu_data {
+ int cu_fd; /* connections fd */
+ bool_t cu_closeit; /* opened by library */
+ struct sockaddr_storage cu_raddr; /* remote address */
+ int cu_rlen;
+ struct timeval cu_wait; /* retransmit interval */
+ struct timeval cu_total; /* total time for the call */
+ struct rpc_err cu_error;
+ XDR cu_outxdrs;
+ u_int cu_xdrpos;
+ u_int cu_sendsz; /* send size */
+ char cu_outhdr[MCALL_MSG_SIZE];
+ char *cu_outbuf;
+ u_int cu_recvsz; /* recv size */
+ int cu_async;
+ int cu_connect; /* Use connect(). */
+ int cu_connected; /* Have done connect(). */
+ struct kevent cu_kin;
+ int cu_kq;
+ char cu_inbuf[1];
+};
+
+/*
+ * Connection less client creation returns with client handle parameters.
+ * Default options are set, which the user can change using clnt_control().
+ * fd should be open and bound.
+ * NB: The rpch->cl_auth is initialized to null authentication.
+ * Caller may wish to set this something more useful.
+ *
+ * sendsz and recvsz are the maximum allowable packet sizes that can be
+ * sent and received. Normally they are the same, but they can be
+ * changed to improve the program efficiency and buffer allocation.
+ * If they are 0, use the transport default.
+ *
+ * If svcaddr is NULL, returns NULL.
+ *
+ * fd - open file descriptor
+ * svcaddr - servers address
+ * program - program number
+ * version - version number
+ * sendsz - buffer recv size
+ * recvsz - buffer send size
+ */
+CLIENT *
+clnt_dg_create(int fd, const struct netbuf *svcaddr, rpcprog_t program,
+ rpcvers_t version, u_int sendsz, u_int recvsz)
+{
+ CLIENT *cl = NULL; /* client handle */
+ struct cu_data *cu = NULL; /* private data */
+ struct timeval now;
+ struct rpc_msg call_msg;
+ sigset_t mask;
+ sigset_t newmask;
+ struct __rpc_sockinfo si;
+ int one = 1;
+
+ sigfillset(&newmask);
+ thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
+ mutex_lock(&clnt_fd_lock);
+ if (dg_fd_locks == (int *) NULL) {
+ int cv_allocsz;
+ size_t fd_allocsz;
+ int dtbsize = __rpc_dtbsize();
+
+ fd_allocsz = dtbsize * sizeof (int);
+ dg_fd_locks = (int *) mem_alloc(fd_allocsz);
+ if (dg_fd_locks == (int *) NULL) {
+ mutex_unlock(&clnt_fd_lock);
+ thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
+ goto err1;
+ } else
+ memset(dg_fd_locks, '\0', fd_allocsz);
+
+ cv_allocsz = dtbsize * sizeof (cond_t);
+ dg_cv = (cond_t *) mem_alloc(cv_allocsz);
+ if (dg_cv == (cond_t *) NULL) {
+ mem_free(dg_fd_locks, fd_allocsz);
+ dg_fd_locks = (int *) NULL;
+ mutex_unlock(&clnt_fd_lock);
+ thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
+ goto err1;
+ } else {
+ int i;
+
+ for (i = 0; i < dtbsize; i++)
+ cond_init(&dg_cv[i], 0, (void *) 0);
+ }
+ }
+
+ mutex_unlock(&clnt_fd_lock);
+ thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
+
+ if (svcaddr == NULL) {
+ rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
+ return (NULL);
+ }
+
+ if (!__rpc_fd2sockinfo(fd, &si)) {
+ rpc_createerr.cf_stat = RPC_TLIERROR;
+ rpc_createerr.cf_error.re_errno = 0;
+ return (NULL);
+ }
+ /*
+ * Find the receive and the send size
+ */
+ sendsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsz);
+ recvsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsz);
+ if ((sendsz == 0) || (recvsz == 0)) {
+ rpc_createerr.cf_stat = RPC_TLIERROR; /* XXX */
+ rpc_createerr.cf_error.re_errno = 0;
+ return (NULL);
+ }
+
+ if ((cl = mem_alloc(sizeof (CLIENT))) == NULL)
+ goto err1;
+ /*
+ * Should be multiple of 4 for XDR.
+ */
+ sendsz = ((sendsz + 3) / 4) * 4;
+ recvsz = ((recvsz + 3) / 4) * 4;
+ cu = mem_alloc(sizeof (*cu) + sendsz + recvsz);
+ if (cu == NULL)
+ goto err1;
+ (void) memcpy(&cu->cu_raddr, svcaddr->buf, (size_t)svcaddr->len);
+ cu->cu_rlen = svcaddr->len;
+ cu->cu_outbuf = &cu->cu_inbuf[recvsz];
+ /* Other values can also be set through clnt_control() */
+ cu->cu_wait.tv_sec = 15; /* heuristically chosen */
+ cu->cu_wait.tv_usec = 0;
+ cu->cu_total.tv_sec = -1;
+ cu->cu_total.tv_usec = -1;
+ cu->cu_sendsz = sendsz;
+ cu->cu_recvsz = recvsz;
+ cu->cu_async = FALSE;
+ cu->cu_connect = FALSE;
+ cu->cu_connected = FALSE;
+ (void) gettimeofday(&now, NULL);
+ call_msg.rm_xid = __RPC_GETXID(&now);
+ call_msg.rm_call.cb_prog = program;
+ call_msg.rm_call.cb_vers = version;
+ xdrmem_create(&(cu->cu_outxdrs), cu->cu_outhdr, MCALL_MSG_SIZE,
+ XDR_ENCODE);
+ if (! xdr_callhdr(&cu->cu_outxdrs, &call_msg)) {
+ rpc_createerr.cf_stat = RPC_CANTENCODEARGS; /* XXX */
+ rpc_createerr.cf_error.re_errno = 0;
+ goto err2;
+ }
+ cu->cu_xdrpos = XDR_GETPOS(&(cu->cu_outxdrs));
+ XDR_DESTROY(&cu->cu_outxdrs);
+ xdrmem_create(&cu->cu_outxdrs, cu->cu_outbuf, sendsz, XDR_ENCODE);
+
+ /* XXX fvdl - do we still want this? */
+#if 0
+ (void)bindresvport_sa(fd, (struct sockaddr *)svcaddr->buf);
+#endif
+ _ioctl(fd, FIONBIO, (char *)(void *)&one);
+
+ /*
+ * By default, closeit is always FALSE. It is users responsibility
+ * to do a close on it, else the user may use clnt_control
+ * to let clnt_destroy do it for him/her.
+ */
+ cu->cu_closeit = FALSE;
+ cu->cu_fd = fd;
+ cl->cl_ops = clnt_dg_ops();
+ cl->cl_private = (caddr_t)(void *)cu;
+ cl->cl_auth = authnone_create();
+ cl->cl_tp = NULL;
+ cl->cl_netid = NULL;
+ cu->cu_kq = -1;
+ EV_SET(&cu->cu_kin, cu->cu_fd, EVFILT_READ, EV_ADD, 0, 0, 0);
+ return (cl);
+err1:
+ warnx(mem_err_clnt_dg);
+ rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+ rpc_createerr.cf_error.re_errno = errno;
+err2:
+ if (cl) {
+ mem_free(cl, sizeof (CLIENT));
+ if (cu)
+ mem_free(cu, sizeof (*cu) + sendsz + recvsz);
+ }
+ return (NULL);
+}
+
+/*
+ * cl - client handle
+ * proc - procedure number
+ * xargs - xdr routine for args
+ * argsp - pointer to args
+ * xresults - xdr routine for results
+ * resultsp - pointer to results
+ * utimeout - seconds to wait before giving up
+ */
+static enum clnt_stat
+clnt_dg_call(CLIENT *cl, rpcproc_t proc, xdrproc_t xargs, void *argsp,
+ xdrproc_t xresults, void *resultsp, struct timeval utimeout)
+{
+ struct cu_data *cu = (struct cu_data *)cl->cl_private;
+ XDR *xdrs;
+ size_t outlen = 0;
+ struct rpc_msg reply_msg;
+ XDR reply_xdrs;
+ bool_t ok;
+ int nrefreshes = 2; /* number of times to refresh cred */
+ int nretries = 0; /* number of times we retransmitted */
+ struct timeval timeout;
+ struct timeval retransmit_time;
+ struct timeval next_sendtime, starttime, time_waited, tv;
+ struct timespec ts;
+ struct kevent kv;
+ struct sockaddr *sa;
+ sigset_t mask;
+ sigset_t newmask;
+ socklen_t salen;
+ ssize_t recvlen = 0;
+ int kin_len, n, rpc_lock_value;
+ u_int32_t xid;
+
+ outlen = 0;
+ sigfillset(&newmask);
+ thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
+ mutex_lock(&clnt_fd_lock);
+ while (dg_fd_locks[cu->cu_fd])
+ cond_wait(&dg_cv[cu->cu_fd], &clnt_fd_lock);
+ if (__isthreaded)
+ rpc_lock_value = 1;
+ else
+ rpc_lock_value = 0;
+ dg_fd_locks[cu->cu_fd] = rpc_lock_value;
+ mutex_unlock(&clnt_fd_lock);
+ if (cu->cu_total.tv_usec == -1) {
+ timeout = utimeout; /* use supplied timeout */
+ } else {
+ timeout = cu->cu_total; /* use default timeout */
+ }
+
+ if (cu->cu_connect && !cu->cu_connected) {
+ if (_connect(cu->cu_fd, (struct sockaddr *)&cu->cu_raddr,
+ cu->cu_rlen) < 0) {
+ cu->cu_error.re_errno = errno;
+ cu->cu_error.re_status = RPC_CANTSEND;
+ goto out;
+ }
+ cu->cu_connected = 1;
+ }
+ if (cu->cu_connected) {
+ sa = NULL;
+ salen = 0;
+ } else {
+ sa = (struct sockaddr *)&cu->cu_raddr;
+ salen = cu->cu_rlen;
+ }
+ time_waited.tv_sec = 0;
+ time_waited.tv_usec = 0;
+ retransmit_time = next_sendtime = cu->cu_wait;
+ gettimeofday(&starttime, NULL);
+
+ /* Clean up in case the last call ended in a longjmp(3) call. */
+ if (cu->cu_kq >= 0)
+ _close(cu->cu_kq);
+ if ((cu->cu_kq = kqueue()) < 0) {
+ cu->cu_error.re_errno = errno;
+ cu->cu_error.re_status = RPC_CANTSEND;
+ goto out;
+ }
+ kin_len = 1;
+
+call_again:
+ if (cu->cu_async == TRUE && xargs == NULL)
+ goto get_reply;
+ /*
+ * the transaction is the first thing in the out buffer
+ * XXX Yes, and it's in network byte order, so we should to
+ * be careful when we increment it, shouldn't we.
+ */
+ xid = ntohl(*(u_int32_t *)(void *)(cu->cu_outhdr));
+ xid++;
+ *(u_int32_t *)(void *)(cu->cu_outhdr) = htonl(xid);
+call_again_same_xid:
+ xdrs = &(cu->cu_outxdrs);
+ xdrs->x_op = XDR_ENCODE;
+ XDR_SETPOS(xdrs, 0);
+
+ if (cl->cl_auth->ah_cred.oa_flavor != RPCSEC_GSS) {
+ if ((! XDR_PUTBYTES(xdrs, cu->cu_outhdr, cu->cu_xdrpos)) ||
+ (! XDR_PUTINT32(xdrs, &proc)) ||
+ (! AUTH_MARSHALL(cl->cl_auth, xdrs)) ||
+ (! (*xargs)(xdrs, argsp))) {
+ cu->cu_error.re_status = RPC_CANTENCODEARGS;
+ goto out;
+ }
+ } else {
+ *(uint32_t *) &cu->cu_outhdr[cu->cu_xdrpos] = htonl(proc);
+ if (!__rpc_gss_wrap(cl->cl_auth, cu->cu_outhdr,
+ cu->cu_xdrpos + sizeof(uint32_t),
+ xdrs, xargs, argsp)) {
+ cu->cu_error.re_status = RPC_CANTENCODEARGS;
+ goto out;
+ }
+ }
+ outlen = (size_t)XDR_GETPOS(xdrs);
+
+send_again:
+ if (_sendto(cu->cu_fd, cu->cu_outbuf, outlen, 0, sa, salen) != outlen) {
+ cu->cu_error.re_errno = errno;
+ cu->cu_error.re_status = RPC_CANTSEND;
+ goto out;
+ }
+
+ /*
+ * Hack to provide rpc-based message passing
+ */
+ if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
+ cu->cu_error.re_status = RPC_TIMEDOUT;
+ goto out;
+ }
+
+get_reply:
+
+ /*
+ * sub-optimal code appears here because we have
+ * some clock time to spare while the packets are in flight.
+ * (We assume that this is actually only executed once.)
+ */
+ reply_msg.acpted_rply.ar_verf = _null_auth;
+ if (cl->cl_auth->ah_cred.oa_flavor != RPCSEC_GSS) {
+ reply_msg.acpted_rply.ar_results.where = resultsp;
+ reply_msg.acpted_rply.ar_results.proc = xresults;
+ } else {
+ reply_msg.acpted_rply.ar_results.where = NULL;
+ reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
+ }
+
+ for (;;) {
+ /* Decide how long to wait. */
+ if (timercmp(&next_sendtime, &timeout, <))
+ timersub(&next_sendtime, &time_waited, &tv);
+ else
+ timersub(&timeout, &time_waited, &tv);
+ if (tv.tv_sec < 0 || tv.tv_usec < 0)
+ tv.tv_sec = tv.tv_usec = 0;
+ TIMEVAL_TO_TIMESPEC(&tv, &ts);
+
+ n = _kevent(cu->cu_kq, &cu->cu_kin, kin_len, &kv, 1, &ts);
+ /* We don't need to register the event again. */
+ kin_len = 0;
+
+ if (n == 1) {
+ if (kv.flags & EV_ERROR) {
+ cu->cu_error.re_errno = kv.data;
+ cu->cu_error.re_status = RPC_CANTRECV;
+ goto out;
+ }
+ /* We have some data now */
+ do {
+ recvlen = _recvfrom(cu->cu_fd, cu->cu_inbuf,
+ cu->cu_recvsz, 0, NULL, NULL);
+ } while (recvlen < 0 && errno == EINTR);
+ if (recvlen < 0 && errno != EWOULDBLOCK) {
+ cu->cu_error.re_errno = errno;
+ cu->cu_error.re_status = RPC_CANTRECV;
+ goto out;
+ }
+ if (recvlen >= sizeof(u_int32_t) &&
+ (cu->cu_async == TRUE ||
+ *((u_int32_t *)(void *)(cu->cu_inbuf)) ==
+ *((u_int32_t *)(void *)(cu->cu_outbuf)))) {
+ /* We now assume we have the proper reply. */
+ break;
+ }
+ }
+ if (n == -1 && errno != EINTR) {
+ cu->cu_error.re_errno = errno;
+ cu->cu_error.re_status = RPC_CANTRECV;
+ goto out;
+ }
+ gettimeofday(&tv, NULL);
+ timersub(&tv, &starttime, &time_waited);
+
+ /* Check for timeout. */
+ if (timercmp(&time_waited, &timeout, >)) {
+ cu->cu_error.re_status = RPC_TIMEDOUT;
+ goto out;
+ }
+
+ /* Retransmit if necessary. */
+ if (timercmp(&time_waited, &next_sendtime, >)) {
+ /* update retransmit_time */
+ if (retransmit_time.tv_sec < RPC_MAX_BACKOFF)
+ timeradd(&retransmit_time, &retransmit_time,
+ &retransmit_time);
+ timeradd(&next_sendtime, &retransmit_time,
+ &next_sendtime);
+ nretries++;
+
+ /*
+ * When retransmitting a RPCSEC_GSS message,
+ * we must use a new sequence number (handled
+ * by __rpc_gss_wrap above).
+ */
+ if (cl->cl_auth->ah_cred.oa_flavor != RPCSEC_GSS)
+ goto send_again;
+ else
+ goto call_again_same_xid;
+ }
+ }
+
+ /*
+ * now decode and validate the response
+ */
+
+ xdrmem_create(&reply_xdrs, cu->cu_inbuf, (u_int)recvlen, XDR_DECODE);
+ ok = xdr_replymsg(&reply_xdrs, &reply_msg);
+ /* XDR_DESTROY(&reply_xdrs); save a few cycles on noop destroy */
+ if (ok) {
+ if ((reply_msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
+ (reply_msg.acpted_rply.ar_stat == SUCCESS))
+ cu->cu_error.re_status = RPC_SUCCESS;
+ else
+ _seterr_reply(&reply_msg, &(cu->cu_error));
+
+ if (cu->cu_error.re_status == RPC_SUCCESS) {
+ if (! AUTH_VALIDATE(cl->cl_auth,
+ &reply_msg.acpted_rply.ar_verf)) {
+ if (nretries &&
+ cl->cl_auth->ah_cred.oa_flavor
+ == RPCSEC_GSS)
+ /*
+ * If we retransmitted, its
+ * possible that we will
+ * receive a reply for one of
+ * the earlier transmissions
+ * (which will use an older
+ * RPCSEC_GSS sequence
+ * number). In this case, just
+ * go back and listen for a
+ * new reply. We could keep a
+ * record of all the seq
+ * numbers we have transmitted
+ * so far so that we could
+ * accept a reply for any of
+ * them here.
+ */
+ goto get_reply;
+ cu->cu_error.re_status = RPC_AUTHERROR;
+ cu->cu_error.re_why = AUTH_INVALIDRESP;
+ } else {
+ if (cl->cl_auth->ah_cred.oa_flavor
+ == RPCSEC_GSS) {
+ if (!__rpc_gss_unwrap(cl->cl_auth,
+ &reply_xdrs, xresults,
+ resultsp))
+ cu->cu_error.re_status =
+ RPC_CANTDECODERES;
+ }
+ }
+ if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) {
+ xdrs->x_op = XDR_FREE;
+ (void) xdr_opaque_auth(xdrs,
+ &(reply_msg.acpted_rply.ar_verf));
+ }
+ } /* end successful completion */
+ /*
+ * If unsuccessful AND error is an authentication error
+ * then refresh credentials and try again, else break
+ */
+ else if (cu->cu_error.re_status == RPC_AUTHERROR)
+ /* maybe our credentials need to be refreshed ... */
+ if (nrefreshes > 0 &&
+ AUTH_REFRESH(cl->cl_auth, &reply_msg)) {
+ nrefreshes--;
+ goto call_again;
+ }
+ /* end of unsuccessful completion */
+ } /* end of valid reply message */
+ else {
+ cu->cu_error.re_status = RPC_CANTDECODERES;
+
+ }
+out:
+ if (cu->cu_kq >= 0)
+ _close(cu->cu_kq);
+ cu->cu_kq = -1;
+ release_fd_lock(cu->cu_fd, mask);
+ return (cu->cu_error.re_status);
+}
+
+static void
+clnt_dg_geterr(CLIENT *cl, struct rpc_err *errp)
+{
+ struct cu_data *cu = (struct cu_data *)cl->cl_private;
+
+ *errp = cu->cu_error;
+}
+
+static bool_t
+clnt_dg_freeres(CLIENT *cl, xdrproc_t xdr_res, void *res_ptr)
+{
+ struct cu_data *cu = (struct cu_data *)cl->cl_private;
+ XDR *xdrs = &(cu->cu_outxdrs);
+ bool_t dummy;
+ sigset_t mask;
+ sigset_t newmask;
+
+ sigfillset(&newmask);
+ thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
+ mutex_lock(&clnt_fd_lock);
+ while (dg_fd_locks[cu->cu_fd])
+ cond_wait(&dg_cv[cu->cu_fd], &clnt_fd_lock);
+ xdrs->x_op = XDR_FREE;
+ dummy = (*xdr_res)(xdrs, res_ptr);
+ mutex_unlock(&clnt_fd_lock);
+ thr_sigsetmask(SIG_SETMASK, &mask, NULL);
+ cond_signal(&dg_cv[cu->cu_fd]);
+ return (dummy);
+}
+
+/*ARGSUSED*/
+static void
+clnt_dg_abort(CLIENT *h)
+{
+}
+
+static bool_t
+clnt_dg_control(CLIENT *cl, u_int request, void *info)
+{
+ struct cu_data *cu = (struct cu_data *)cl->cl_private;
+ struct netbuf *addr;
+ sigset_t mask;
+ sigset_t newmask;
+ int rpc_lock_value;
+
+ sigfillset(&newmask);
+ thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
+ mutex_lock(&clnt_fd_lock);
+ while (dg_fd_locks[cu->cu_fd])
+ cond_wait(&dg_cv[cu->cu_fd], &clnt_fd_lock);
+ if (__isthreaded)
+ rpc_lock_value = 1;
+ else
+ rpc_lock_value = 0;
+ dg_fd_locks[cu->cu_fd] = rpc_lock_value;
+ mutex_unlock(&clnt_fd_lock);
+ switch (request) {
+ case CLSET_FD_CLOSE:
+ cu->cu_closeit = TRUE;
+ release_fd_lock(cu->cu_fd, mask);
+ return (TRUE);
+ case CLSET_FD_NCLOSE:
+ cu->cu_closeit = FALSE;
+ release_fd_lock(cu->cu_fd, mask);
+ return (TRUE);
+ }
+
+ /* for other requests which use info */
+ if (info == NULL) {
+ release_fd_lock(cu->cu_fd, mask);
+ return (FALSE);
+ }
+ switch (request) {
+ case CLSET_TIMEOUT:
+ if (time_not_ok((struct timeval *)info)) {
+ release_fd_lock(cu->cu_fd, mask);
+ return (FALSE);
+ }
+ cu->cu_total = *(struct timeval *)info;
+ break;
+ case CLGET_TIMEOUT:
+ *(struct timeval *)info = cu->cu_total;
+ break;
+ case CLGET_SERVER_ADDR: /* Give him the fd address */
+ /* Now obsolete. Only for backward compatibility */
+ (void) memcpy(info, &cu->cu_raddr, (size_t)cu->cu_rlen);
+ break;
+ case CLSET_RETRY_TIMEOUT:
+ if (time_not_ok((struct timeval *)info)) {
+ release_fd_lock(cu->cu_fd, mask);
+ return (FALSE);
+ }
+ cu->cu_wait = *(struct timeval *)info;
+ break;
+ case CLGET_RETRY_TIMEOUT:
+ *(struct timeval *)info = cu->cu_wait;
+ break;
+ case CLGET_FD:
+ *(int *)info = cu->cu_fd;
+ break;
+ case CLGET_SVC_ADDR:
+ addr = (struct netbuf *)info;
+ addr->buf = &cu->cu_raddr;
+ addr->len = cu->cu_rlen;
+ addr->maxlen = sizeof cu->cu_raddr;
+ break;
+ case CLSET_SVC_ADDR: /* set to new address */
+ addr = (struct netbuf *)info;
+ if (addr->len < sizeof cu->cu_raddr) {
+ release_fd_lock(cu->cu_fd, mask);
+ return (FALSE);
+ }
+ (void) memcpy(&cu->cu_raddr, addr->buf, addr->len);
+ cu->cu_rlen = addr->len;
+ break;
+ case CLGET_XID:
+ /*
+ * use the knowledge that xid is the
+ * first element in the call structure *.
+ * This will get the xid of the PREVIOUS call
+ */
+ *(u_int32_t *)info =
+ ntohl(*(u_int32_t *)(void *)cu->cu_outhdr);
+ break;
+
+ case CLSET_XID:
+ /* This will set the xid of the NEXT call */
+ *(u_int32_t *)(void *)cu->cu_outhdr =
+ htonl(*(u_int32_t *)info - 1);
+ /* decrement by 1 as clnt_dg_call() increments once */
+ break;
+
+ case CLGET_VERS:
+ /*
+ * This RELIES on the information that, in the call body,
+ * the version number field is the fifth field from the
+ * beginning of the RPC header. MUST be changed if the
+ * call_struct is changed
+ */
+ *(u_int32_t *)info =
+ ntohl(*(u_int32_t *)(void *)(cu->cu_outhdr +
+ 4 * BYTES_PER_XDR_UNIT));
+ break;
+
+ case CLSET_VERS:
+ *(u_int32_t *)(void *)(cu->cu_outhdr + 4 * BYTES_PER_XDR_UNIT)
+ = htonl(*(u_int32_t *)info);
+ break;
+
+ case CLGET_PROG:
+ /*
+ * This RELIES on the information that, in the call body,
+ * the program number field is the fourth field from the
+ * beginning of the RPC header. MUST be changed if the
+ * call_struct is changed
+ */
+ *(u_int32_t *)info =
+ ntohl(*(u_int32_t *)(void *)(cu->cu_outhdr +
+ 3 * BYTES_PER_XDR_UNIT));
+ break;
+
+ case CLSET_PROG:
+ *(u_int32_t *)(void *)(cu->cu_outhdr + 3 * BYTES_PER_XDR_UNIT)
+ = htonl(*(u_int32_t *)info);
+ break;
+ case CLSET_ASYNC:
+ cu->cu_async = *(int *)info;
+ break;
+ case CLSET_CONNECT:
+ cu->cu_connect = *(int *)info;
+ break;
+ default:
+ release_fd_lock(cu->cu_fd, mask);
+ return (FALSE);
+ }
+ release_fd_lock(cu->cu_fd, mask);
+ return (TRUE);
+}
+
+static void
+clnt_dg_destroy(CLIENT *cl)
+{
+ struct cu_data *cu = (struct cu_data *)cl->cl_private;
+ int cu_fd = cu->cu_fd;
+ sigset_t mask;
+ sigset_t newmask;
+
+ sigfillset(&newmask);
+ thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
+ mutex_lock(&clnt_fd_lock);
+ while (dg_fd_locks[cu_fd])
+ cond_wait(&dg_cv[cu_fd], &clnt_fd_lock);
+ if (cu->cu_closeit)
+ (void)_close(cu_fd);
+ if (cu->cu_kq >= 0)
+ _close(cu->cu_kq);
+ XDR_DESTROY(&(cu->cu_outxdrs));
+ mem_free(cu, (sizeof (*cu) + cu->cu_sendsz + cu->cu_recvsz));
+ if (cl->cl_netid && cl->cl_netid[0])
+ mem_free(cl->cl_netid, strlen(cl->cl_netid) +1);
+ if (cl->cl_tp && cl->cl_tp[0])
+ mem_free(cl->cl_tp, strlen(cl->cl_tp) +1);
+ mem_free(cl, sizeof (CLIENT));
+ mutex_unlock(&clnt_fd_lock);
+ thr_sigsetmask(SIG_SETMASK, &mask, NULL);
+ cond_signal(&dg_cv[cu_fd]);
+}
+
+static struct clnt_ops *
+clnt_dg_ops(void)
+{
+ static struct clnt_ops ops;
+ sigset_t mask;
+ sigset_t newmask;
+
+/* VARIABLES PROTECTED BY ops_lock: ops */
+
+ sigfillset(&newmask);
+ thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
+ mutex_lock(&ops_lock);
+ if (ops.cl_call == NULL) {
+ ops.cl_call = clnt_dg_call;
+ ops.cl_abort = clnt_dg_abort;
+ ops.cl_geterr = clnt_dg_geterr;
+ ops.cl_freeres = clnt_dg_freeres;
+ ops.cl_destroy = clnt_dg_destroy;
+ ops.cl_control = clnt_dg_control;
+ }
+ mutex_unlock(&ops_lock);
+ thr_sigsetmask(SIG_SETMASK, &mask, NULL);
+ return (&ops);
+}
+
+/*
+ * Make sure that the time is not garbage. -1 value is allowed.
+ */
+static bool_t
+time_not_ok(struct timeval *t)
+{
+ return (t->tv_sec < -1 || t->tv_sec > 100000000 ||
+ t->tv_usec < -1 || t->tv_usec > 1000000);
+}
+
diff --git a/lib/libc/rpc/clnt_generic.c b/lib/libc/rpc/clnt_generic.c
new file mode 100644
index 000000000000..0dea81d52eb5
--- /dev/null
+++ b/lib/libc/rpc/clnt_generic.c
@@ -0,0 +1,448 @@
+/* $NetBSD: clnt_generic.c,v 1.18 2000/07/06 03:10:34 christos Exp $ */
+
+/*-
+ * Copyright (c) 2010, Oracle America, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of the "Oracle America, Inc." nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* #ident "@(#)clnt_generic.c 1.40 99/04/21 SMI" */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *sccsid2 = "from: @(#)clnt_generic.c 1.4 87/08/11 (C) 1987 SMI";
+static char *sccsid = "from: @(#)clnt_generic.c 2.2 88/08/01 4.0 RPCSRC";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Copyright (c) 1986-1996,1998 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+#include "namespace.h"
+#include "reentrant.h"
+#include <sys/types.h>
+#include <sys/fcntl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <stdio.h>
+#include <errno.h>
+#include <netdb.h>
+#include <syslog.h>
+#include <rpc/rpc.h>
+#include <rpc/nettype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "un-namespace.h"
+#include "rpc_com.h"
+
+extern bool_t __rpc_is_local_host(const char *);
+int __rpc_raise_fd(int);
+
+#ifndef NETIDLEN
+#define NETIDLEN 32
+#endif
+
+
+/*
+ * Generic client creation with version checking the value of
+ * vers_out is set to the highest server supported value
+ * vers_low <= vers_out <= vers_high AND an error results
+ * if this can not be done.
+ *
+ * It calls clnt_create_vers_timed() with a NULL value for the timeout
+ * pointer, which indicates that the default timeout should be used.
+ */
+CLIENT *
+clnt_create_vers(const char *hostname, rpcprog_t prog, rpcvers_t *vers_out,
+ rpcvers_t vers_low, rpcvers_t vers_high, const char *nettype)
+{
+
+ return (clnt_create_vers_timed(hostname, prog, vers_out, vers_low,
+ vers_high, nettype, NULL));
+}
+
+/*
+ * This the routine has the same definition as clnt_create_vers(),
+ * except it takes an additional timeout parameter - a pointer to
+ * a timeval structure. A NULL value for the pointer indicates
+ * that the default timeout value should be used.
+ */
+CLIENT *
+clnt_create_vers_timed(const char *hostname, rpcprog_t prog,
+ rpcvers_t *vers_out, rpcvers_t vers_low, rpcvers_t vers_high,
+ const char *nettype, const struct timeval *tp)
+{
+ CLIENT *clnt;
+ struct timeval to;
+ enum clnt_stat rpc_stat;
+ struct rpc_err rpcerr;
+
+ clnt = clnt_create_timed(hostname, prog, vers_high, nettype, tp);
+ if (clnt == NULL) {
+ return (NULL);
+ }
+ to.tv_sec = 10;
+ to.tv_usec = 0;
+ rpc_stat = clnt_call(clnt, NULLPROC, (xdrproc_t)xdr_void,
+ (char *)NULL, (xdrproc_t)xdr_void, (char *)NULL, to);
+ if (rpc_stat == RPC_SUCCESS) {
+ *vers_out = vers_high;
+ return (clnt);
+ }
+ while (rpc_stat == RPC_PROGVERSMISMATCH && vers_high > vers_low) {
+ unsigned int minvers, maxvers;
+
+ clnt_geterr(clnt, &rpcerr);
+ minvers = rpcerr.re_vers.low;
+ maxvers = rpcerr.re_vers.high;
+ if (maxvers < vers_high)
+ vers_high = maxvers;
+ else
+ vers_high--;
+ if (minvers > vers_low)
+ vers_low = minvers;
+ if (vers_low > vers_high) {
+ goto error;
+ }
+ CLNT_CONTROL(clnt, CLSET_VERS, (char *)&vers_high);
+ rpc_stat = clnt_call(clnt, NULLPROC, (xdrproc_t)xdr_void,
+ (char *)NULL, (xdrproc_t)xdr_void,
+ (char *)NULL, to);
+ if (rpc_stat == RPC_SUCCESS) {
+ *vers_out = vers_high;
+ return (clnt);
+ }
+ }
+ clnt_geterr(clnt, &rpcerr);
+
+error:
+ rpc_createerr.cf_stat = rpc_stat;
+ rpc_createerr.cf_error = rpcerr;
+ clnt_destroy(clnt);
+ return (NULL);
+}
+
+/*
+ * Top level client creation routine.
+ * Generic client creation: takes (servers name, program-number, nettype) and
+ * returns client handle. Default options are set, which the user can
+ * change using the rpc equivalent of _ioctl()'s.
+ *
+ * It tries for all the netids in that particular class of netid until
+ * it succeeds.
+ * XXX The error message in the case of failure will be the one
+ * pertaining to the last create error.
+ *
+ * It calls clnt_create_timed() with the default timeout.
+ */
+CLIENT *
+clnt_create(const char *hostname, rpcprog_t prog, rpcvers_t vers,
+ const char *nettype)
+{
+
+ return (clnt_create_timed(hostname, prog, vers, nettype, NULL));
+}
+
+/*
+ * This the routine has the same definition as clnt_create(),
+ * except it takes an additional timeout parameter - a pointer to
+ * a timeval structure. A NULL value for the pointer indicates
+ * that the default timeout value should be used.
+ *
+ * This function calls clnt_tp_create_timed().
+ */
+CLIENT *
+clnt_create_timed(const char *hostname, rpcprog_t prog, rpcvers_t vers,
+ const char *netclass, const struct timeval *tp)
+{
+ struct netconfig *nconf;
+ CLIENT *clnt = NULL;
+ void *handle;
+ enum clnt_stat save_cf_stat = RPC_SUCCESS;
+ struct rpc_err save_cf_error;
+ char nettype_array[NETIDLEN];
+ char *nettype = &nettype_array[0];
+
+ if (netclass == NULL)
+ nettype = NULL;
+ else {
+ size_t len = strlen(netclass);
+ if (len >= sizeof (nettype_array)) {
+ rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
+ return (NULL);
+ }
+ strcpy(nettype, netclass);
+ }
+
+ if ((handle = __rpc_setconf((char *)nettype)) == NULL) {
+ rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
+ return (NULL);
+ }
+ rpc_createerr.cf_stat = RPC_SUCCESS;
+ while (clnt == NULL) {
+ if ((nconf = __rpc_getconf(handle)) == NULL) {
+ if (rpc_createerr.cf_stat == RPC_SUCCESS)
+ rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
+ break;
+ }
+#ifdef CLNT_DEBUG
+ printf("trying netid %s\n", nconf->nc_netid);
+#endif
+ clnt = clnt_tp_create_timed(hostname, prog, vers, nconf, tp);
+ if (clnt)
+ break;
+ else
+ /*
+ * Since we didn't get a name-to-address
+ * translation failure here, we remember
+ * this particular error. The object of
+ * this is to enable us to return to the
+ * caller a more-specific error than the
+ * unhelpful ``Name to address translation
+ * failed'' which might well occur if we
+ * merely returned the last error (because
+ * the local loopbacks are typically the
+ * last ones in /etc/netconfig and the most
+ * likely to be unable to translate a host
+ * name). We also check for a more
+ * meaningful error than ``unknown host
+ * name'' for the same reasons.
+ */
+ if (rpc_createerr.cf_stat != RPC_N2AXLATEFAILURE &&
+ rpc_createerr.cf_stat != RPC_UNKNOWNHOST) {
+ save_cf_stat = rpc_createerr.cf_stat;
+ save_cf_error = rpc_createerr.cf_error;
+ }
+ }
+
+ /*
+ * Attempt to return an error more specific than ``Name to address
+ * translation failed'' or ``unknown host name''
+ */
+ if ((rpc_createerr.cf_stat == RPC_N2AXLATEFAILURE ||
+ rpc_createerr.cf_stat == RPC_UNKNOWNHOST) &&
+ (save_cf_stat != RPC_SUCCESS)) {
+ rpc_createerr.cf_stat = save_cf_stat;
+ rpc_createerr.cf_error = save_cf_error;
+ }
+ __rpc_endconf(handle);
+ return (clnt);
+}
+
+/*
+ * Generic client creation: takes (servers name, program-number, netconf) and
+ * returns client handle. Default options are set, which the user can
+ * change using the rpc equivalent of _ioctl()'s : clnt_control()
+ * It finds out the server address from rpcbind and calls clnt_tli_create().
+ *
+ * It calls clnt_tp_create_timed() with the default timeout.
+ */
+CLIENT *
+clnt_tp_create(const char *hostname, rpcprog_t prog, rpcvers_t vers,
+ const struct netconfig *nconf)
+{
+
+ return (clnt_tp_create_timed(hostname, prog, vers, nconf, NULL));
+}
+
+/*
+ * This has the same definition as clnt_tp_create(), except it
+ * takes an additional parameter - a pointer to a timeval structure.
+ * A NULL value for the timeout pointer indicates that the default
+ * value for the timeout should be used.
+ */
+CLIENT *
+clnt_tp_create_timed(const char *hostname, rpcprog_t prog, rpcvers_t vers,
+ const struct netconfig *nconf, const struct timeval *tp)
+{
+ struct netbuf *svcaddr; /* servers address */
+ CLIENT *cl = NULL; /* client handle */
+
+ if (nconf == NULL) {
+ rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
+ return (NULL);
+ }
+
+ /*
+ * Get the address of the server
+ */
+ if ((svcaddr = __rpcb_findaddr_timed(prog, vers,
+ (struct netconfig *)nconf, (char *)hostname,
+ &cl, (struct timeval *)tp)) == NULL) {
+ /* appropriate error number is set by rpcbind libraries */
+ return (NULL);
+ }
+ if (cl == NULL) {
+ cl = clnt_tli_create(RPC_ANYFD, nconf, svcaddr,
+ prog, vers, 0, 0);
+ } else {
+ /* Reuse the CLIENT handle and change the appropriate fields */
+ if (CLNT_CONTROL(cl, CLSET_SVC_ADDR, (void *)svcaddr) == TRUE) {
+ if (cl->cl_netid == NULL)
+ cl->cl_netid = strdup(nconf->nc_netid);
+ if (cl->cl_tp == NULL)
+ cl->cl_tp = strdup(nconf->nc_device);
+ (void) CLNT_CONTROL(cl, CLSET_PROG, (void *)&prog);
+ (void) CLNT_CONTROL(cl, CLSET_VERS, (void *)&vers);
+ } else {
+ CLNT_DESTROY(cl);
+ cl = clnt_tli_create(RPC_ANYFD, nconf, svcaddr,
+ prog, vers, 0, 0);
+ }
+ }
+ free(svcaddr->buf);
+ free(svcaddr);
+ return (cl);
+}
+
+/*
+ * Generic client creation: returns client handle.
+ * Default options are set, which the user can
+ * change using the rpc equivalent of _ioctl()'s : clnt_control().
+ * If fd is RPC_ANYFD, it will be opened using nconf.
+ * It will be bound if not so.
+ * If sizes are 0; appropriate defaults will be chosen.
+ */
+CLIENT *
+clnt_tli_create(int fd, const struct netconfig *nconf,
+ struct netbuf *svcaddr, rpcprog_t prog, rpcvers_t vers,
+ uint sendsz, uint recvsz)
+{
+ CLIENT *cl; /* client handle */
+ bool_t madefd = FALSE; /* whether fd opened here */
+ long servtype;
+ int one = 1;
+ struct __rpc_sockinfo si;
+ extern int __rpc_minfd;
+
+ if (fd == RPC_ANYFD) {
+ if (nconf == NULL) {
+ rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
+ return (NULL);
+ }
+
+ fd = __rpc_nconf2fd(nconf);
+
+ if (fd == -1)
+ goto err;
+ if (fd < __rpc_minfd)
+ fd = __rpc_raise_fd(fd);
+ madefd = TRUE;
+ servtype = nconf->nc_semantics;
+ if (!__rpc_fd2sockinfo(fd, &si))
+ goto err;
+ bindresvport(fd, NULL);
+ } else {
+ if (!__rpc_fd2sockinfo(fd, &si))
+ goto err;
+ servtype = __rpc_socktype2seman(si.si_socktype);
+ if (servtype == -1) {
+ rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
+ return (NULL);
+ }
+ }
+
+ if (si.si_af != ((struct sockaddr *)svcaddr->buf)->sa_family) {
+ rpc_createerr.cf_stat = RPC_UNKNOWNHOST; /* XXX */
+ goto err1;
+ }
+
+ switch (servtype) {
+ case NC_TPI_COTS:
+ cl = clnt_vc_create(fd, svcaddr, prog, vers, sendsz, recvsz);
+ break;
+ case NC_TPI_COTS_ORD:
+ if (nconf && ((strcmp(nconf->nc_protofmly, "inet") == 0))) {
+ _setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one,
+ sizeof (one));
+ }
+ cl = clnt_vc_create(fd, svcaddr, prog, vers, sendsz, recvsz);
+ break;
+ case NC_TPI_CLTS:
+ cl = clnt_dg_create(fd, svcaddr, prog, vers, sendsz, recvsz);
+ break;
+ default:
+ goto err;
+ }
+
+ if (cl == NULL)
+ goto err1; /* borrow errors from clnt_dg/vc creates */
+ if (nconf) {
+ cl->cl_netid = strdup(nconf->nc_netid);
+ cl->cl_tp = strdup(nconf->nc_device);
+ } else {
+ cl->cl_netid = "";
+ cl->cl_tp = "";
+ }
+ if (madefd) {
+ (void) CLNT_CONTROL(cl, CLSET_FD_CLOSE, NULL);
+/* (void) CLNT_CONTROL(cl, CLSET_POP_TIMOD, NULL); */
+ }
+
+ return (cl);
+
+err:
+ rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+ rpc_createerr.cf_error.re_errno = errno;
+err1: if (madefd)
+ (void)_close(fd);
+ return (NULL);
+}
+
+/*
+ * To avoid conflicts with the "magic" file descriptors (0, 1, and 2),
+ * we try to not use them. The __rpc_raise_fd() routine will dup
+ * a descriptor to a higher value. If we fail to do it, we continue
+ * to use the old one (and hope for the best).
+ */
+int __rpc_minfd = 3;
+
+int
+__rpc_raise_fd(int fd)
+{
+ int nfd;
+
+ if (fd >= __rpc_minfd)
+ return (fd);
+
+ if ((nfd = _fcntl(fd, F_DUPFD, __rpc_minfd)) == -1)
+ return (fd);
+
+ if (_fsync(nfd) == -1) {
+ _close(nfd);
+ return (fd);
+ }
+
+ if (_close(fd) == -1) {
+ /* this is okay, we will syslog an error, then use the new fd */
+ (void) syslog(LOG_ERR,
+ "could not close() fd %d; mem & fd leak", fd);
+ }
+
+ return (nfd);
+}
diff --git a/lib/libc/rpc/clnt_perror.c b/lib/libc/rpc/clnt_perror.c
new file mode 100644
index 000000000000..d674fbb3847f
--- /dev/null
+++ b/lib/libc/rpc/clnt_perror.c
@@ -0,0 +1,323 @@
+/* $NetBSD: clnt_perror.c,v 1.24 2000/06/02 23:11:07 fvdl Exp $ */
+
+
+/*-
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *sccsid2 = "@(#)clnt_perror.c 1.15 87/10/07 Copyr 1984 Sun Micro";
+static char *sccsid = "@(#)clnt_perror.c 2.1 88/07/29 4.0 RPCSRC";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * clnt_perror.c
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ */
+#include "namespace.h"
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <rpc/rpc.h>
+#include <rpc/types.h>
+#include <rpc/auth.h>
+#include <rpc/clnt.h>
+#include "un-namespace.h"
+
+static char *buf;
+
+static char *_buf(void);
+static char *auth_errmsg(enum auth_stat);
+#define CLNT_PERROR_BUFLEN 256
+
+static char *
+_buf(void)
+{
+
+ if (buf == NULL)
+ buf = malloc(CLNT_PERROR_BUFLEN);
+ return (buf);
+}
+
+/*
+ * Print reply error info
+ */
+char *
+clnt_sperror(CLIENT *rpch, const char *s)
+{
+ struct rpc_err e;
+ char *err;
+ char *str;
+ char *strstart;
+ size_t len, i;
+
+ assert(rpch != NULL);
+ assert(s != NULL);
+
+ str = _buf(); /* side effect: sets CLNT_PERROR_BUFLEN */
+ if (str == NULL)
+ return (0);
+ len = CLNT_PERROR_BUFLEN;
+ strstart = str;
+ CLNT_GETERR(rpch, &e);
+
+ if ((i = snprintf(str, len, "%s: ", s)) > 0) {
+ str += i;
+ len -= i;
+ }
+
+ (void)strncpy(str, clnt_sperrno(e.re_status), len - 1);
+ i = strlen(str);
+ str += i;
+ len -= i;
+
+ switch (e.re_status) {
+ case RPC_SUCCESS:
+ case RPC_CANTENCODEARGS:
+ case RPC_CANTDECODERES:
+ case RPC_TIMEDOUT:
+ case RPC_PROGUNAVAIL:
+ case RPC_PROCUNAVAIL:
+ case RPC_CANTDECODEARGS:
+ case RPC_SYSTEMERROR:
+ case RPC_UNKNOWNHOST:
+ case RPC_UNKNOWNPROTO:
+ case RPC_PMAPFAILURE:
+ case RPC_PROGNOTREGISTERED:
+ case RPC_FAILED:
+ break;
+
+ case RPC_CANTSEND:
+ case RPC_CANTRECV:
+ i = snprintf(str, len, "; errno = %s", strerror(e.re_errno));
+ if (i > 0) {
+ str += i;
+ len -= i;
+ }
+ break;
+
+ case RPC_VERSMISMATCH:
+ i = snprintf(str, len, "; low version = %u, high version = %u",
+ e.re_vers.low, e.re_vers.high);
+ if (i > 0) {
+ str += i;
+ len -= i;
+ }
+ break;
+
+ case RPC_AUTHERROR:
+ err = auth_errmsg(e.re_why);
+ i = snprintf(str, len, "; why = ");
+ if (i > 0) {
+ str += i;
+ len -= i;
+ }
+ if (err != NULL) {
+ i = snprintf(str, len, "%s",err);
+ } else {
+ i = snprintf(str, len,
+ "(unknown authentication error - %d)",
+ (int) e.re_why);
+ }
+ if (i > 0) {
+ str += i;
+ len -= i;
+ }
+ break;
+
+ case RPC_PROGVERSMISMATCH:
+ i = snprintf(str, len, "; low version = %u, high version = %u",
+ e.re_vers.low, e.re_vers.high);
+ if (i > 0) {
+ str += i;
+ len -= i;
+ }
+ break;
+
+ default: /* unknown */
+ i = snprintf(str, len, "; s1 = %u, s2 = %u",
+ e.re_lb.s1, e.re_lb.s2);
+ if (i > 0) {
+ str += i;
+ len -= i;
+ }
+ break;
+ }
+ strstart[CLNT_PERROR_BUFLEN-1] = '\0';
+ return(strstart) ;
+}
+
+void
+clnt_perror(CLIENT *rpch, const char *s)
+{
+
+ assert(rpch != NULL);
+ assert(s != NULL);
+
+ (void) fprintf(stderr, "%s\n", clnt_sperror(rpch,s));
+}
+
+static const char *const rpc_errlist[] = {
+ "RPC: Success", /* 0 - RPC_SUCCESS */
+ "RPC: Can't encode arguments", /* 1 - RPC_CANTENCODEARGS */
+ "RPC: Can't decode result", /* 2 - RPC_CANTDECODERES */
+ "RPC: Unable to send", /* 3 - RPC_CANTSEND */
+ "RPC: Unable to receive", /* 4 - RPC_CANTRECV */
+ "RPC: Timed out", /* 5 - RPC_TIMEDOUT */
+ "RPC: Incompatible versions of RPC", /* 6 - RPC_VERSMISMATCH */
+ "RPC: Authentication error", /* 7 - RPC_AUTHERROR */
+ "RPC: Program unavailable", /* 8 - RPC_PROGUNAVAIL */
+ "RPC: Program/version mismatch", /* 9 - RPC_PROGVERSMISMATCH */
+ "RPC: Procedure unavailable", /* 10 - RPC_PROCUNAVAIL */
+ "RPC: Server can't decode arguments", /* 11 - RPC_CANTDECODEARGS */
+ "RPC: Remote system error", /* 12 - RPC_SYSTEMERROR */
+ "RPC: Unknown host", /* 13 - RPC_UNKNOWNHOST */
+ "RPC: Port mapper failure", /* 14 - RPC_PMAPFAILURE */
+ "RPC: Program not registered", /* 15 - RPC_PROGNOTREGISTERED */
+ "RPC: Failed (unspecified error)", /* 16 - RPC_FAILED */
+ "RPC: Unknown protocol" /* 17 - RPC_UNKNOWNPROTO */
+};
+
+
+/*
+ * This interface for use by clntrpc
+ */
+char *
+clnt_sperrno(enum clnt_stat stat)
+{
+ unsigned int errnum = stat;
+
+ if (errnum < (sizeof(rpc_errlist)/sizeof(rpc_errlist[0])))
+ /* LINTED interface problem */
+ return (char *)rpc_errlist[errnum];
+
+ return ("RPC: (unknown error code)");
+}
+
+void
+clnt_perrno(enum clnt_stat num)
+{
+ (void) fprintf(stderr, "%s\n", clnt_sperrno(num));
+}
+
+
+char *
+clnt_spcreateerror(const char *s)
+{
+ char *str;
+ size_t len, i;
+
+ assert(s != NULL);
+
+ str = _buf(); /* side effect: sets CLNT_PERROR_BUFLEN */
+ if (str == NULL)
+ return(0);
+ len = CLNT_PERROR_BUFLEN;
+ i = snprintf(str, len, "%s: ", s);
+ if (i > 0)
+ len -= i;
+ (void)strncat(str, clnt_sperrno(rpc_createerr.cf_stat), len - 1);
+ switch (rpc_createerr.cf_stat) {
+ case RPC_PMAPFAILURE:
+ (void) strncat(str, " - ", len - 1);
+ (void) strncat(str,
+ clnt_sperrno(rpc_createerr.cf_error.re_status), len - 4);
+ break;
+
+ case RPC_SYSTEMERROR:
+ (void)strncat(str, " - ", len - 1);
+ (void)strncat(str, strerror(rpc_createerr.cf_error.re_errno),
+ len - 4);
+ break;
+
+ case RPC_CANTSEND:
+ case RPC_CANTDECODERES:
+ case RPC_CANTENCODEARGS:
+ case RPC_SUCCESS:
+ case RPC_UNKNOWNPROTO:
+ case RPC_PROGNOTREGISTERED:
+ case RPC_FAILED:
+ case RPC_UNKNOWNHOST:
+ case RPC_CANTDECODEARGS:
+ case RPC_PROCUNAVAIL:
+ case RPC_PROGVERSMISMATCH:
+ case RPC_PROGUNAVAIL:
+ case RPC_AUTHERROR:
+ case RPC_VERSMISMATCH:
+ case RPC_TIMEDOUT:
+ case RPC_CANTRECV:
+ default:
+ break;
+ }
+ str[CLNT_PERROR_BUFLEN-1] = '\0';
+ return (str);
+}
+
+void
+clnt_pcreateerror(const char *s)
+{
+
+ assert(s != NULL);
+
+ (void) fprintf(stderr, "%s\n", clnt_spcreateerror(s));
+}
+
+static const char *const auth_errlist[] = {
+ "Authentication OK", /* 0 - AUTH_OK */
+ "Invalid client credential", /* 1 - AUTH_BADCRED */
+ "Server rejected credential", /* 2 - AUTH_REJECTEDCRED */
+ "Invalid client verifier", /* 3 - AUTH_BADVERF */
+ "Server rejected verifier", /* 4 - AUTH_REJECTEDVERF */
+ "Client credential too weak", /* 5 - AUTH_TOOWEAK */
+ "Invalid server verifier", /* 6 - AUTH_INVALIDRESP */
+ "Failed (unspecified error)", /* 7 - AUTH_FAILED */
+ "Kerberos generic error", /* 8 - AUTH_KERB_GENERIC*/
+ "Kerberos credential expired", /* 9 - AUTH_TIMEEXPIRE */
+ "Bad kerberos ticket file", /* 10 - AUTH_TKT_FILE */
+ "Can't decode kerberos authenticator", /* 11 - AUTH_DECODE */
+ "Address wrong in kerberos ticket", /* 12 - AUTH_NET_ADDR */
+ "GSS-API crediential problem", /* 13 - RPCSEC_GSS_CREDPROBLEM */
+ "GSS-API context problem" /* 14 - RPCSEC_GSS_CTXPROBLEM */
+};
+
+static char *
+auth_errmsg(enum auth_stat stat)
+{
+ unsigned int errnum = stat;
+
+ if (errnum < (sizeof(auth_errlist)/sizeof(auth_errlist[0])))
+ /* LINTED interface problem */
+ return (char *)auth_errlist[errnum];
+
+ return(NULL);
+}
diff --git a/lib/libc/rpc/clnt_raw.c b/lib/libc/rpc/clnt_raw.c
new file mode 100644
index 000000000000..ad641127ff8a
--- /dev/null
+++ b/lib/libc/rpc/clnt_raw.c
@@ -0,0 +1,296 @@
+/* $NetBSD: clnt_raw.c,v 1.20 2000/12/10 04:12:03 christos Exp $ */
+
+/*-
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *sccsid2 = "@(#)clnt_raw.c 1.22 87/08/11 Copyr 1984 Sun Micro";
+static char *sccsid = "@(#)clnt_raw.c 2.2 88/08/01 4.0 RPCSRC";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * clnt_raw.c
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ * Memory based rpc for simple testing and timing.
+ * Interface to create an rpc client and server in the same process.
+ * This lets us similate rpc and get round trip overhead, without
+ * any interference from the kernel.
+ */
+
+#include "namespace.h"
+#include "reentrant.h"
+#include <assert.h>
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <rpc/rpc.h>
+#include <rpc/raw.h>
+#include "un-namespace.h"
+#include "mt_misc.h"
+
+#define MCALL_MSG_SIZE 24
+
+/*
+ * This is the "network" we will be moving stuff over.
+ */
+static struct clntraw_private {
+ CLIENT client_object;
+ XDR xdr_stream;
+ char *_raw_buf;
+ union {
+ struct rpc_msg mashl_rpcmsg;
+ char mashl_callmsg[MCALL_MSG_SIZE];
+ } u;
+ u_int mcnt;
+} *clntraw_private;
+
+static enum clnt_stat clnt_raw_call(CLIENT *, rpcproc_t, xdrproc_t, void *,
+ xdrproc_t, void *, struct timeval);
+static void clnt_raw_geterr(CLIENT *, struct rpc_err *);
+static bool_t clnt_raw_freeres(CLIENT *, xdrproc_t, void *);
+static void clnt_raw_abort(CLIENT *);
+static bool_t clnt_raw_control(CLIENT *, u_int, void *);
+static void clnt_raw_destroy(CLIENT *);
+static struct clnt_ops *clnt_raw_ops(void);
+
+/*
+ * Create a client handle for memory based rpc.
+ */
+CLIENT *
+clnt_raw_create(rpcprog_t prog, rpcvers_t vers)
+{
+ struct clntraw_private *clp;
+ struct rpc_msg call_msg;
+ XDR *xdrs;
+ CLIENT *client;
+
+ mutex_lock(&clntraw_lock);
+ if ((clp = clntraw_private) == NULL) {
+ clp = (struct clntraw_private *)calloc(1, sizeof (*clp));
+ if (clp == NULL) {
+ mutex_unlock(&clntraw_lock);
+ return NULL;
+ }
+ if (__rpc_rawcombuf == NULL)
+ __rpc_rawcombuf =
+ (char *)calloc(UDPMSGSIZE, sizeof (char));
+ clp->_raw_buf = __rpc_rawcombuf;
+ clntraw_private = clp;
+ }
+ xdrs = &clp->xdr_stream;
+ client = &clp->client_object;
+
+ /*
+ * pre-serialize the static part of the call msg and stash it away
+ */
+ call_msg.rm_direction = CALL;
+ call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
+ /* XXX: prog and vers have been long historically :-( */
+ call_msg.rm_call.cb_prog = (u_int32_t)prog;
+ call_msg.rm_call.cb_vers = (u_int32_t)vers;
+ xdrmem_create(xdrs, clp->u.mashl_callmsg, MCALL_MSG_SIZE, XDR_ENCODE);
+ if (! xdr_callhdr(xdrs, &call_msg))
+ warnx("clntraw_create - Fatal header serialization error.");
+ clp->mcnt = XDR_GETPOS(xdrs);
+ XDR_DESTROY(xdrs);
+
+ /*
+ * Set xdrmem for client/server shared buffer
+ */
+ xdrmem_create(xdrs, clp->_raw_buf, UDPMSGSIZE, XDR_FREE);
+
+ /*
+ * create client handle
+ */
+ client->cl_ops = clnt_raw_ops();
+ client->cl_auth = authnone_create();
+ mutex_unlock(&clntraw_lock);
+ return (client);
+}
+
+/* ARGSUSED */
+static enum clnt_stat
+clnt_raw_call(CLIENT *h, rpcproc_t proc, xdrproc_t xargs, void *argsp,
+ xdrproc_t xresults, void *resultsp, struct timeval timeout)
+{
+ struct clntraw_private *clp = clntraw_private;
+ XDR *xdrs = &clp->xdr_stream;
+ struct rpc_msg msg;
+ enum clnt_stat status;
+ struct rpc_err error;
+
+ assert(h != NULL);
+
+ mutex_lock(&clntraw_lock);
+ if (clp == NULL) {
+ mutex_unlock(&clntraw_lock);
+ return (RPC_FAILED);
+ }
+ mutex_unlock(&clntraw_lock);
+
+call_again:
+ /*
+ * send request
+ */
+ xdrs->x_op = XDR_ENCODE;
+ XDR_SETPOS(xdrs, 0);
+ clp->u.mashl_rpcmsg.rm_xid ++ ;
+ if ((! XDR_PUTBYTES(xdrs, clp->u.mashl_callmsg, clp->mcnt)) ||
+ (! XDR_PUTINT32(xdrs, &proc)) ||
+ (! AUTH_MARSHALL(h->cl_auth, xdrs)) ||
+ (! (*xargs)(xdrs, argsp))) {
+ return (RPC_CANTENCODEARGS);
+ }
+ (void)XDR_GETPOS(xdrs); /* called just to cause overhead */
+
+ /*
+ * We have to call server input routine here because this is
+ * all going on in one process. Yuk.
+ */
+ svc_getreq_common(FD_SETSIZE);
+
+ /*
+ * get results
+ */
+ xdrs->x_op = XDR_DECODE;
+ XDR_SETPOS(xdrs, 0);
+ msg.acpted_rply.ar_verf = _null_auth;
+ msg.acpted_rply.ar_results.where = resultsp;
+ msg.acpted_rply.ar_results.proc = xresults;
+ if (! xdr_replymsg(xdrs, &msg)) {
+ /*
+ * It's possible for xdr_replymsg() to fail partway
+ * through its attempt to decode the result from the
+ * server. If this happens, it will leave the reply
+ * structure partially populated with dynamically
+ * allocated memory. (This can happen if someone uses
+ * clntudp_bufcreate() to create a CLIENT handle and
+ * specifies a receive buffer size that is too small.)
+ * This memory must be free()ed to avoid a leak.
+ */
+ int op = xdrs->x_op;
+ xdrs->x_op = XDR_FREE;
+ xdr_replymsg(xdrs, &msg);
+ xdrs->x_op = op;
+ return (RPC_CANTDECODERES);
+ }
+ _seterr_reply(&msg, &error);
+ status = error.re_status;
+
+ if (status == RPC_SUCCESS) {
+ if (! AUTH_VALIDATE(h->cl_auth, &msg.acpted_rply.ar_verf)) {
+ status = RPC_AUTHERROR;
+ }
+ } /* end successful completion */
+ else {
+ if (AUTH_REFRESH(h->cl_auth, &msg))
+ goto call_again;
+ } /* end of unsuccessful completion */
+
+ if (status == RPC_SUCCESS) {
+ if (! AUTH_VALIDATE(h->cl_auth, &msg.acpted_rply.ar_verf)) {
+ status = RPC_AUTHERROR;
+ }
+ if (msg.acpted_rply.ar_verf.oa_base != NULL) {
+ xdrs->x_op = XDR_FREE;
+ (void)xdr_opaque_auth(xdrs, &(msg.acpted_rply.ar_verf));
+ }
+ }
+
+ return (status);
+}
+
+/*ARGSUSED*/
+static void
+clnt_raw_geterr(CLIENT *cl, struct rpc_err *err)
+{
+}
+
+
+/* ARGSUSED */
+static bool_t
+clnt_raw_freeres(CLIENT *cl, xdrproc_t xdr_res, void *res_ptr)
+{
+ struct clntraw_private *clp = clntraw_private;
+ XDR *xdrs = &clp->xdr_stream;
+ bool_t rval;
+
+ mutex_lock(&clntraw_lock);
+ if (clp == NULL) {
+ rval = (bool_t) RPC_FAILED;
+ mutex_unlock(&clntraw_lock);
+ return (rval);
+ }
+ mutex_unlock(&clntraw_lock);
+ xdrs->x_op = XDR_FREE;
+ return ((*xdr_res)(xdrs, res_ptr));
+}
+
+/*ARGSUSED*/
+static void
+clnt_raw_abort(CLIENT *cl)
+{
+}
+
+/*ARGSUSED*/
+static bool_t
+clnt_raw_control(CLIENT *cl, u_int ui, void *str)
+{
+ return (FALSE);
+}
+
+/*ARGSUSED*/
+static void
+clnt_raw_destroy(CLIENT *cl)
+{
+}
+
+static struct clnt_ops *
+clnt_raw_ops(void)
+{
+ static struct clnt_ops ops;
+
+ /* VARIABLES PROTECTED BY ops_lock: ops */
+
+ mutex_lock(&ops_lock);
+ if (ops.cl_call == NULL) {
+ ops.cl_call = clnt_raw_call;
+ ops.cl_abort = clnt_raw_abort;
+ ops.cl_geterr = clnt_raw_geterr;
+ ops.cl_freeres = clnt_raw_freeres;
+ ops.cl_destroy = clnt_raw_destroy;
+ ops.cl_control = clnt_raw_control;
+ }
+ mutex_unlock(&ops_lock);
+ return (&ops);
+}
diff --git a/lib/libc/rpc/clnt_simple.c b/lib/libc/rpc/clnt_simple.c
new file mode 100644
index 000000000000..4fc374ad6a33
--- /dev/null
+++ b/lib/libc/rpc/clnt_simple.c
@@ -0,0 +1,207 @@
+/* $NetBSD: clnt_simple.c,v 1.21 2000/07/06 03:10:34 christos Exp $ */
+
+/*-
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 1986-1991 by Sun Microsystems Inc.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *sccsid2 = "from: @(#)clnt_simple.c 1.35 87/08/11 Copyr 1984 Sun Micro";
+static char *sccsid = "from: @(#)clnt_simple.c 2.2 88/08/01 4.0 RPCSRC";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * clnt_simple.c
+ * Simplified front end to client rpc.
+ *
+ */
+
+#include "namespace.h"
+#include "reentrant.h"
+#include <sys/param.h>
+#include <stdio.h>
+#include <errno.h>
+#include <rpc/rpc.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include "un-namespace.h"
+#include "mt_misc.h"
+
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 64
+#endif
+
+#ifndef NETIDLEN
+#define NETIDLEN 32
+#endif
+
+struct rpc_call_private {
+ int valid; /* Is this entry valid ? */
+ CLIENT *client; /* Client handle */
+ pid_t pid; /* process-id at moment of creation */
+ rpcprog_t prognum; /* Program */
+ rpcvers_t versnum; /* Version */
+ char host[MAXHOSTNAMELEN]; /* Servers host */
+ char nettype[NETIDLEN]; /* Network type */
+};
+static struct rpc_call_private *rpc_call_private_main;
+static thread_key_t rpc_call_key;
+static once_t rpc_call_once = ONCE_INITIALIZER;
+static int rpc_call_key_error;
+
+static void rpc_call_key_init(void);
+static void rpc_call_destroy(void *);
+
+static void
+rpc_call_destroy(void *vp)
+{
+ struct rpc_call_private *rcp = (struct rpc_call_private *)vp;
+
+ if (rcp) {
+ if (rcp->client)
+ CLNT_DESTROY(rcp->client);
+ free(rcp);
+ }
+}
+
+static void
+rpc_call_key_init(void)
+{
+
+ rpc_call_key_error = thr_keycreate(&rpc_call_key, rpc_call_destroy);
+}
+
+/*
+ * This is the simplified interface to the client rpc layer.
+ * The client handle is not destroyed here and is reused for
+ * the future calls to same prog, vers, host and nettype combination.
+ *
+ * The total time available is 25 seconds.
+ *
+ * host - host name
+ * prognum - program number
+ * versnum - version number
+ * procnum - procedure number
+ * inproc, outproc - in/out XDR procedures
+ * in, out - recv/send data
+ * nettype - nettype
+ */
+enum clnt_stat
+rpc_call(const char *host, const rpcprog_t prognum, const rpcvers_t versnum,
+ const rpcproc_t procnum, const xdrproc_t inproc, const char *in,
+ const xdrproc_t outproc, char *out, const char *nettype)
+{
+ struct rpc_call_private *rcp = (struct rpc_call_private *) 0;
+ enum clnt_stat clnt_stat;
+ struct timeval timeout, tottimeout;
+ int main_thread = 1;
+
+ if ((main_thread = thr_main())) {
+ rcp = rpc_call_private_main;
+ } else {
+ if (thr_once(&rpc_call_once, rpc_call_key_init) != 0 ||
+ rpc_call_key_error != 0) {
+ rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+ rpc_createerr.cf_error.re_errno = rpc_call_key_error;
+ return (rpc_createerr.cf_stat);
+ }
+ rcp = (struct rpc_call_private *)thr_getspecific(rpc_call_key);
+ }
+ if (rcp == NULL) {
+ rcp = malloc(sizeof (*rcp));
+ if (rcp == NULL) {
+ rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+ rpc_createerr.cf_error.re_errno = errno;
+ return (rpc_createerr.cf_stat);
+ }
+ if (main_thread)
+ rpc_call_private_main = rcp;
+ else
+ thr_setspecific(rpc_call_key, (void *) rcp);
+ rcp->valid = 0;
+ rcp->client = NULL;
+ }
+ if ((nettype == NULL) || (nettype[0] == 0))
+ nettype = "netpath";
+ if (!(rcp->valid && rcp->pid == getpid() &&
+ (rcp->prognum == prognum) &&
+ (rcp->versnum == versnum) &&
+ (!strcmp(rcp->host, host)) &&
+ (!strcmp(rcp->nettype, nettype)))) {
+ int fd;
+
+ rcp->valid = 0;
+ if (rcp->client)
+ CLNT_DESTROY(rcp->client);
+ /*
+ * Using the first successful transport for that type
+ */
+ rcp->client = clnt_create(host, prognum, versnum, nettype);
+ rcp->pid = getpid();
+ if (rcp->client == NULL) {
+ return (rpc_createerr.cf_stat);
+ }
+ /*
+ * Set time outs for connectionless case. Do it
+ * unconditionally. Faster than doing a t_getinfo()
+ * and then doing the right thing.
+ */
+ timeout.tv_usec = 0;
+ timeout.tv_sec = 5;
+ (void) CLNT_CONTROL(rcp->client,
+ CLSET_RETRY_TIMEOUT, (char *)(void *)&timeout);
+ if (CLNT_CONTROL(rcp->client, CLGET_FD, (char *)(void *)&fd))
+ _fcntl(fd, F_SETFD, 1); /* make it "close on exec" */
+ rcp->prognum = prognum;
+ rcp->versnum = versnum;
+ if ((strlen(host) < (size_t)MAXHOSTNAMELEN) &&
+ (strlen(nettype) < (size_t)NETIDLEN)) {
+ (void) strcpy(rcp->host, host);
+ (void) strcpy(rcp->nettype, nettype);
+ rcp->valid = 1;
+ } else {
+ rcp->valid = 0;
+ }
+ } /* else reuse old client */
+ tottimeout.tv_sec = 25;
+ tottimeout.tv_usec = 0;
+ /*LINTED const castaway*/
+ clnt_stat = CLNT_CALL(rcp->client, procnum, inproc, (char *) in,
+ outproc, out, tottimeout);
+ /*
+ * if call failed, empty cache
+ */
+ if (clnt_stat != RPC_SUCCESS)
+ rcp->valid = 0;
+ return (clnt_stat);
+}
diff --git a/lib/libc/rpc/clnt_vc.c b/lib/libc/rpc/clnt_vc.c
new file mode 100644
index 000000000000..1bc15008b149
--- /dev/null
+++ b/lib/libc/rpc/clnt_vc.c
@@ -0,0 +1,847 @@
+/* $NetBSD: clnt_vc.c,v 1.4 2000/07/14 08:40:42 fvdl Exp $ */
+
+/*-
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *sccsid2 = "@(#)clnt_tcp.c 1.37 87/10/05 Copyr 1984 Sun Micro";
+static char *sccsid = "@(#)clnt_tcp.c 2.2 88/08/01 4.0 RPCSRC";
+static char sccsid3[] = "@(#)clnt_vc.c 1.19 89/03/16 Copyr 1988 Sun Micro";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * clnt_tcp.c, Implements a TCP/IP based, client side RPC.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ * TCP based RPC supports 'batched calls'.
+ * A sequence of calls may be batched-up in a send buffer. The rpc call
+ * return immediately to the client even though the call was not necessarily
+ * sent. The batching occurs if the results' xdr routine is NULL (0) AND
+ * the rpc timeout value is zero (see clnt.h, rpc).
+ *
+ * Clients should NOT casually batch calls that in fact return results; that is,
+ * the server side should be aware that a call is batched and not produce any
+ * return message. Batched calls that produce many result messages can
+ * deadlock (netlock) the client and the server....
+ *
+ * Now go hang yourself.
+ */
+
+#include "namespace.h"
+#include "reentrant.h"
+#include <sys/types.h>
+#include <sys/poll.h>
+#include <sys/syslog.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/uio.h>
+
+#include <arpa/inet.h>
+#include <assert.h>
+#include <err.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include <rpc/rpc.h>
+#include <rpc/rpcsec_gss.h>
+#include "un-namespace.h"
+#include "rpc_com.h"
+#include "mt_misc.h"
+
+#define MCALL_MSG_SIZE 24
+
+struct cmessage {
+ struct cmsghdr cmsg;
+ struct cmsgcred cmcred;
+};
+
+static enum clnt_stat clnt_vc_call(CLIENT *, rpcproc_t, xdrproc_t, void *,
+ xdrproc_t, void *, struct timeval);
+static void clnt_vc_geterr(CLIENT *, struct rpc_err *);
+static bool_t clnt_vc_freeres(CLIENT *, xdrproc_t, void *);
+static void clnt_vc_abort(CLIENT *);
+static bool_t clnt_vc_control(CLIENT *, u_int, void *);
+static void clnt_vc_destroy(CLIENT *);
+static struct clnt_ops *clnt_vc_ops(void);
+static bool_t time_not_ok(struct timeval *);
+static int read_vc(void *, void *, int);
+static int write_vc(void *, void *, int);
+static int __msgwrite(int, void *, size_t);
+static int __msgread(int, void *, size_t);
+
+struct ct_data {
+ int ct_fd; /* connection's fd */
+ bool_t ct_closeit; /* close it on destroy */
+ struct timeval ct_wait; /* wait interval in milliseconds */
+ bool_t ct_waitset; /* wait set by clnt_control? */
+ struct netbuf ct_addr; /* remote addr */
+ struct rpc_err ct_error;
+ union {
+ char ct_mcallc[MCALL_MSG_SIZE]; /* marshalled callmsg */
+ u_int32_t ct_mcalli;
+ } ct_u;
+ u_int ct_mpos; /* pos after marshal */
+ XDR ct_xdrs; /* XDR stream */
+};
+
+/*
+ * This machinery implements per-fd locks for MT-safety. It is not
+ * sufficient to do per-CLIENT handle locks for MT-safety because a
+ * user may create more than one CLIENT handle with the same fd behind
+ * it. Therfore, we allocate an array of flags (vc_fd_locks), protected
+ * by the clnt_fd_lock mutex, and an array (vc_cv) of condition variables
+ * similarly protected. Vc_fd_lock[fd] == 1 => a call is activte on some
+ * CLIENT handle created for that fd.
+ * The current implementation holds locks across the entire RPC and reply.
+ * Yes, this is silly, and as soon as this code is proven to work, this
+ * should be the first thing fixed. One step at a time.
+ */
+static int *vc_fd_locks;
+static cond_t *vc_cv;
+#define release_fd_lock(fd, mask) { \
+ mutex_lock(&clnt_fd_lock); \
+ vc_fd_locks[fd] = 0; \
+ mutex_unlock(&clnt_fd_lock); \
+ thr_sigsetmask(SIG_SETMASK, &(mask), (sigset_t *) NULL); \
+ cond_signal(&vc_cv[fd]); \
+}
+
+static const char clnt_vc_errstr[] = "%s : %s";
+static const char clnt_vc_str[] = "clnt_vc_create";
+static const char __no_mem_str[] = "out of memory";
+
+/*
+ * Create a client handle for a connection.
+ * Default options are set, which the user can change using clnt_control()'s.
+ * The rpc/vc package does buffering similar to stdio, so the client
+ * must pick send and receive buffer sizes, 0 => use the default.
+ * NB: fd is copied into a private area.
+ * NB: The rpch->cl_auth is set null authentication. Caller may wish to
+ * set this something more useful.
+ *
+ * fd should be an open socket
+ *
+ * fd - open file descriptor
+ * raddr - servers address
+ * prog - program number
+ * vers - version number
+ * sendsz - buffer send size
+ * recvsz - buffer recv size
+ */
+CLIENT *
+clnt_vc_create(int fd, const struct netbuf *raddr, const rpcprog_t prog,
+ const rpcvers_t vers, u_int sendsz, u_int recvsz)
+{
+ CLIENT *cl; /* client handle */
+ struct ct_data *ct = NULL; /* client handle */
+ struct timeval now;
+ struct rpc_msg call_msg;
+ static u_int32_t disrupt;
+ sigset_t mask;
+ sigset_t newmask;
+ struct sockaddr_storage ss;
+ socklen_t slen;
+ struct __rpc_sockinfo si;
+
+ if (disrupt == 0)
+ disrupt = (u_int32_t)(long)raddr;
+
+ cl = (CLIENT *)mem_alloc(sizeof (*cl));
+ ct = (struct ct_data *)mem_alloc(sizeof (*ct));
+ if ((cl == (CLIENT *)NULL) || (ct == (struct ct_data *)NULL)) {
+ (void) syslog(LOG_ERR, clnt_vc_errstr,
+ clnt_vc_str, __no_mem_str);
+ rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+ rpc_createerr.cf_error.re_errno = errno;
+ goto err;
+ }
+ ct->ct_addr.buf = NULL;
+ sigfillset(&newmask);
+ thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
+ mutex_lock(&clnt_fd_lock);
+ if (vc_fd_locks == (int *) NULL) {
+ int cv_allocsz, fd_allocsz;
+ int dtbsize = __rpc_dtbsize();
+
+ fd_allocsz = dtbsize * sizeof (int);
+ vc_fd_locks = (int *) mem_alloc(fd_allocsz);
+ if (vc_fd_locks == (int *) NULL) {
+ mutex_unlock(&clnt_fd_lock);
+ thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
+ goto err;
+ } else
+ memset(vc_fd_locks, '\0', fd_allocsz);
+
+ assert(vc_cv == (cond_t *) NULL);
+ cv_allocsz = dtbsize * sizeof (cond_t);
+ vc_cv = (cond_t *) mem_alloc(cv_allocsz);
+ if (vc_cv == (cond_t *) NULL) {
+ mem_free(vc_fd_locks, fd_allocsz);
+ vc_fd_locks = (int *) NULL;
+ mutex_unlock(&clnt_fd_lock);
+ thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
+ goto err;
+ } else {
+ int i;
+
+ for (i = 0; i < dtbsize; i++)
+ cond_init(&vc_cv[i], 0, (void *) 0);
+ }
+ } else
+ assert(vc_cv != (cond_t *) NULL);
+
+ /*
+ * XXX - fvdl connecting while holding a mutex?
+ */
+ slen = sizeof ss;
+ if (_getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) {
+ if (errno != ENOTCONN) {
+ rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+ rpc_createerr.cf_error.re_errno = errno;
+ mutex_unlock(&clnt_fd_lock);
+ thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
+ goto err;
+ }
+ if (_connect(fd, (struct sockaddr *)raddr->buf, raddr->len) < 0){
+ rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+ rpc_createerr.cf_error.re_errno = errno;
+ mutex_unlock(&clnt_fd_lock);
+ thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
+ goto err;
+ }
+ }
+ mutex_unlock(&clnt_fd_lock);
+ thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
+ if (!__rpc_fd2sockinfo(fd, &si))
+ goto err;
+
+ ct->ct_closeit = FALSE;
+
+ /*
+ * Set up private data struct
+ */
+ ct->ct_fd = fd;
+ ct->ct_wait.tv_usec = 0;
+ ct->ct_waitset = FALSE;
+ ct->ct_addr.buf = malloc(raddr->maxlen);
+ if (ct->ct_addr.buf == NULL)
+ goto err;
+ memcpy(ct->ct_addr.buf, raddr->buf, raddr->len);
+ ct->ct_addr.len = raddr->len;
+ ct->ct_addr.maxlen = raddr->maxlen;
+
+ /*
+ * Initialize call message
+ */
+ (void)gettimeofday(&now, NULL);
+ call_msg.rm_xid = ((u_int32_t)++disrupt) ^ __RPC_GETXID(&now);
+ call_msg.rm_direction = CALL;
+ call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
+ call_msg.rm_call.cb_prog = (u_int32_t)prog;
+ call_msg.rm_call.cb_vers = (u_int32_t)vers;
+
+ /*
+ * pre-serialize the static part of the call msg and stash it away
+ */
+ xdrmem_create(&(ct->ct_xdrs), ct->ct_u.ct_mcallc, MCALL_MSG_SIZE,
+ XDR_ENCODE);
+ if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) {
+ if (ct->ct_closeit) {
+ (void)_close(fd);
+ }
+ goto err;
+ }
+ ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs));
+ XDR_DESTROY(&(ct->ct_xdrs));
+ assert(ct->ct_mpos + sizeof(uint32_t) <= MCALL_MSG_SIZE);
+
+ /*
+ * Create a client handle which uses xdrrec for serialization
+ * and authnone for authentication.
+ */
+ cl->cl_ops = clnt_vc_ops();
+ cl->cl_private = ct;
+ cl->cl_auth = authnone_create();
+ sendsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsz);
+ recvsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsz);
+ xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz,
+ cl->cl_private, read_vc, write_vc);
+ return (cl);
+
+err:
+ if (ct) {
+ if (ct->ct_addr.len)
+ mem_free(ct->ct_addr.buf, ct->ct_addr.len);
+ mem_free(ct, sizeof (struct ct_data));
+ }
+ if (cl)
+ mem_free(cl, sizeof (CLIENT));
+ return ((CLIENT *)NULL);
+}
+
+static enum clnt_stat
+clnt_vc_call(CLIENT *cl, rpcproc_t proc, xdrproc_t xdr_args, void *args_ptr,
+ xdrproc_t xdr_results, void *results_ptr, struct timeval timeout)
+{
+ struct ct_data *ct = (struct ct_data *) cl->cl_private;
+ XDR *xdrs = &(ct->ct_xdrs);
+ struct rpc_msg reply_msg;
+ u_int32_t x_id;
+ u_int32_t *msg_x_id = &ct->ct_u.ct_mcalli; /* yuk */
+ bool_t shipnow;
+ int refreshes = 2;
+ sigset_t mask, newmask;
+ int rpc_lock_value;
+ bool_t reply_stat;
+
+ assert(cl != NULL);
+
+ sigfillset(&newmask);
+ thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
+ mutex_lock(&clnt_fd_lock);
+ while (vc_fd_locks[ct->ct_fd])
+ cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock);
+ if (__isthreaded)
+ rpc_lock_value = 1;
+ else
+ rpc_lock_value = 0;
+ vc_fd_locks[ct->ct_fd] = rpc_lock_value;
+ mutex_unlock(&clnt_fd_lock);
+ if (!ct->ct_waitset) {
+ /* If time is not within limits, we ignore it. */
+ if (time_not_ok(&timeout) == FALSE)
+ ct->ct_wait = timeout;
+ }
+
+ shipnow =
+ (xdr_results == NULL && timeout.tv_sec == 0
+ && timeout.tv_usec == 0) ? FALSE : TRUE;
+
+call_again:
+ xdrs->x_op = XDR_ENCODE;
+ ct->ct_error.re_status = RPC_SUCCESS;
+ x_id = ntohl(--(*msg_x_id));
+
+ if (cl->cl_auth->ah_cred.oa_flavor != RPCSEC_GSS) {
+ if ((! XDR_PUTBYTES(xdrs, ct->ct_u.ct_mcallc, ct->ct_mpos)) ||
+ (! XDR_PUTINT32(xdrs, &proc)) ||
+ (! AUTH_MARSHALL(cl->cl_auth, xdrs)) ||
+ (! (*xdr_args)(xdrs, args_ptr))) {
+ if (ct->ct_error.re_status == RPC_SUCCESS)
+ ct->ct_error.re_status = RPC_CANTENCODEARGS;
+ (void)xdrrec_endofrecord(xdrs, TRUE);
+ release_fd_lock(ct->ct_fd, mask);
+ return (ct->ct_error.re_status);
+ }
+ } else {
+ *(uint32_t *) &ct->ct_u.ct_mcallc[ct->ct_mpos] = htonl(proc);
+ if (! __rpc_gss_wrap(cl->cl_auth, ct->ct_u.ct_mcallc,
+ ct->ct_mpos + sizeof(uint32_t),
+ xdrs, xdr_args, args_ptr)) {
+ if (ct->ct_error.re_status == RPC_SUCCESS)
+ ct->ct_error.re_status = RPC_CANTENCODEARGS;
+ (void)xdrrec_endofrecord(xdrs, TRUE);
+ release_fd_lock(ct->ct_fd, mask);
+ return (ct->ct_error.re_status);
+ }
+ }
+ if (! xdrrec_endofrecord(xdrs, shipnow)) {
+ release_fd_lock(ct->ct_fd, mask);
+ return (ct->ct_error.re_status = RPC_CANTSEND);
+ }
+ if (! shipnow) {
+ release_fd_lock(ct->ct_fd, mask);
+ return (RPC_SUCCESS);
+ }
+ /*
+ * Hack to provide rpc-based message passing
+ */
+ if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
+ release_fd_lock(ct->ct_fd, mask);
+ return(ct->ct_error.re_status = RPC_TIMEDOUT);
+ }
+
+
+ /*
+ * Keep receiving until we get a valid transaction id
+ */
+ xdrs->x_op = XDR_DECODE;
+ while (TRUE) {
+ reply_msg.acpted_rply.ar_verf = _null_auth;
+ reply_msg.acpted_rply.ar_results.where = NULL;
+ reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
+ if (! xdrrec_skiprecord(xdrs)) {
+ release_fd_lock(ct->ct_fd, mask);
+ return (ct->ct_error.re_status);
+ }
+ /* now decode and validate the response header */
+ if (! xdr_replymsg(xdrs, &reply_msg)) {
+ if (ct->ct_error.re_status == RPC_SUCCESS)
+ continue;
+ release_fd_lock(ct->ct_fd, mask);
+ return (ct->ct_error.re_status);
+ }
+ if (reply_msg.rm_xid == x_id)
+ break;
+ }
+
+ /*
+ * process header
+ */
+ _seterr_reply(&reply_msg, &(ct->ct_error));
+ if (ct->ct_error.re_status == RPC_SUCCESS) {
+ if (! AUTH_VALIDATE(cl->cl_auth,
+ &reply_msg.acpted_rply.ar_verf)) {
+ ct->ct_error.re_status = RPC_AUTHERROR;
+ ct->ct_error.re_why = AUTH_INVALIDRESP;
+ } else {
+ if (cl->cl_auth->ah_cred.oa_flavor != RPCSEC_GSS) {
+ reply_stat = (*xdr_results)(xdrs, results_ptr);
+ } else {
+ reply_stat = __rpc_gss_unwrap(cl->cl_auth,
+ xdrs, xdr_results, results_ptr);
+ }
+ if (! reply_stat) {
+ if (ct->ct_error.re_status == RPC_SUCCESS)
+ ct->ct_error.re_status =
+ RPC_CANTDECODERES;
+ }
+ }
+ /* free verifier ... */
+ if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) {
+ xdrs->x_op = XDR_FREE;
+ (void)xdr_opaque_auth(xdrs,
+ &(reply_msg.acpted_rply.ar_verf));
+ }
+ } /* end successful completion */
+ else {
+ /* maybe our credentials need to be refreshed ... */
+ if (refreshes-- && AUTH_REFRESH(cl->cl_auth, &reply_msg))
+ goto call_again;
+ } /* end of unsuccessful completion */
+ release_fd_lock(ct->ct_fd, mask);
+ return (ct->ct_error.re_status);
+}
+
+static void
+clnt_vc_geterr(CLIENT *cl, struct rpc_err *errp)
+{
+ struct ct_data *ct;
+
+ assert(cl != NULL);
+ assert(errp != NULL);
+
+ ct = (struct ct_data *) cl->cl_private;
+ *errp = ct->ct_error;
+}
+
+static bool_t
+clnt_vc_freeres(CLIENT *cl, xdrproc_t xdr_res, void *res_ptr)
+{
+ struct ct_data *ct;
+ XDR *xdrs;
+ bool_t dummy;
+ sigset_t mask;
+ sigset_t newmask;
+
+ assert(cl != NULL);
+
+ ct = (struct ct_data *)cl->cl_private;
+ xdrs = &(ct->ct_xdrs);
+
+ sigfillset(&newmask);
+ thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
+ mutex_lock(&clnt_fd_lock);
+ while (vc_fd_locks[ct->ct_fd])
+ cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock);
+ xdrs->x_op = XDR_FREE;
+ dummy = (*xdr_res)(xdrs, res_ptr);
+ mutex_unlock(&clnt_fd_lock);
+ thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
+ cond_signal(&vc_cv[ct->ct_fd]);
+
+ return dummy;
+}
+
+/*ARGSUSED*/
+static void
+clnt_vc_abort(CLIENT *cl)
+{
+}
+
+static __inline void
+htonlp(void *dst, const void *src, uint32_t incr)
+{
+ /* We are aligned, so we think */
+ *(uint32_t *)dst = htonl(*(const uint32_t *)src + incr);
+}
+
+static __inline void
+ntohlp(void *dst, const void *src)
+{
+ /* We are aligned, so we think */
+ *(uint32_t *)dst = htonl(*(const uint32_t *)src);
+}
+
+static bool_t
+clnt_vc_control(CLIENT *cl, u_int request, void *info)
+{
+ struct ct_data *ct;
+ void *infop = info;
+ sigset_t mask;
+ sigset_t newmask;
+ int rpc_lock_value;
+
+ assert(cl != NULL);
+
+ ct = (struct ct_data *)cl->cl_private;
+
+ sigfillset(&newmask);
+ thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
+ mutex_lock(&clnt_fd_lock);
+ while (vc_fd_locks[ct->ct_fd])
+ cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock);
+ if (__isthreaded)
+ rpc_lock_value = 1;
+ else
+ rpc_lock_value = 0;
+ vc_fd_locks[ct->ct_fd] = rpc_lock_value;
+ mutex_unlock(&clnt_fd_lock);
+
+ switch (request) {
+ case CLSET_FD_CLOSE:
+ ct->ct_closeit = TRUE;
+ release_fd_lock(ct->ct_fd, mask);
+ return (TRUE);
+ case CLSET_FD_NCLOSE:
+ ct->ct_closeit = FALSE;
+ release_fd_lock(ct->ct_fd, mask);
+ return (TRUE);
+ default:
+ break;
+ }
+
+ /* for other requests which use info */
+ if (info == NULL) {
+ release_fd_lock(ct->ct_fd, mask);
+ return (FALSE);
+ }
+ switch (request) {
+ case CLSET_TIMEOUT:
+ if (time_not_ok((struct timeval *)info)) {
+ release_fd_lock(ct->ct_fd, mask);
+ return (FALSE);
+ }
+ ct->ct_wait = *(struct timeval *)infop;
+ ct->ct_waitset = TRUE;
+ break;
+ case CLGET_TIMEOUT:
+ *(struct timeval *)infop = ct->ct_wait;
+ break;
+ case CLGET_SERVER_ADDR:
+ (void) memcpy(info, ct->ct_addr.buf, (size_t)ct->ct_addr.len);
+ break;
+ case CLGET_FD:
+ *(int *)info = ct->ct_fd;
+ break;
+ case CLGET_SVC_ADDR:
+ /* The caller should not free this memory area */
+ *(struct netbuf *)info = ct->ct_addr;
+ break;
+ case CLSET_SVC_ADDR: /* set to new address */
+ release_fd_lock(ct->ct_fd, mask);
+ return (FALSE);
+ case CLGET_XID:
+ /*
+ * use the knowledge that xid is the
+ * first element in the call structure
+ * This will get the xid of the PREVIOUS call
+ */
+ ntohlp(info, &ct->ct_u.ct_mcalli);
+ break;
+ case CLSET_XID:
+ /* This will set the xid of the NEXT call */
+ /* increment by 1 as clnt_vc_call() decrements once */
+ htonlp(&ct->ct_u.ct_mcalli, info, 1);
+ break;
+ case CLGET_VERS:
+ /*
+ * This RELIES on the information that, in the call body,
+ * the version number field is the fifth field from the
+ * beginning of the RPC header. MUST be changed if the
+ * call_struct is changed
+ */
+ ntohlp(info, ct->ct_u.ct_mcallc + 4 * BYTES_PER_XDR_UNIT);
+ break;
+
+ case CLSET_VERS:
+ htonlp(ct->ct_u.ct_mcallc + 4 * BYTES_PER_XDR_UNIT, info, 0);
+ break;
+
+ case CLGET_PROG:
+ /*
+ * This RELIES on the information that, in the call body,
+ * the program number field is the fourth field from the
+ * beginning of the RPC header. MUST be changed if the
+ * call_struct is changed
+ */
+ ntohlp(info, ct->ct_u.ct_mcallc + 3 * BYTES_PER_XDR_UNIT);
+ break;
+
+ case CLSET_PROG:
+ htonlp(ct->ct_u.ct_mcallc + 3 * BYTES_PER_XDR_UNIT, info, 0);
+ break;
+
+ default:
+ release_fd_lock(ct->ct_fd, mask);
+ return (FALSE);
+ }
+ release_fd_lock(ct->ct_fd, mask);
+ return (TRUE);
+}
+
+
+static void
+clnt_vc_destroy(CLIENT *cl)
+{
+ struct ct_data *ct = (struct ct_data *) cl->cl_private;
+ int ct_fd = ct->ct_fd;
+ sigset_t mask;
+ sigset_t newmask;
+
+ assert(cl != NULL);
+
+ ct = (struct ct_data *) cl->cl_private;
+
+ sigfillset(&newmask);
+ thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
+ mutex_lock(&clnt_fd_lock);
+ while (vc_fd_locks[ct_fd])
+ cond_wait(&vc_cv[ct_fd], &clnt_fd_lock);
+ if (ct->ct_closeit && ct->ct_fd != -1) {
+ (void)_close(ct->ct_fd);
+ }
+ XDR_DESTROY(&(ct->ct_xdrs));
+ free(ct->ct_addr.buf);
+ mem_free(ct, sizeof(struct ct_data));
+ if (cl->cl_netid && cl->cl_netid[0])
+ mem_free(cl->cl_netid, strlen(cl->cl_netid) +1);
+ if (cl->cl_tp && cl->cl_tp[0])
+ mem_free(cl->cl_tp, strlen(cl->cl_tp) +1);
+ mem_free(cl, sizeof(CLIENT));
+ mutex_unlock(&clnt_fd_lock);
+ thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
+ cond_signal(&vc_cv[ct_fd]);
+}
+
+/*
+ * Interface between xdr serializer and tcp connection.
+ * Behaves like the system calls, read & write, but keeps some error state
+ * around for the rpc level.
+ */
+static int
+read_vc(void *ctp, void *buf, int len)
+{
+ struct sockaddr sa;
+ socklen_t sal;
+ struct ct_data *ct = (struct ct_data *)ctp;
+ struct pollfd fd;
+ int milliseconds = (int)((ct->ct_wait.tv_sec * 1000) +
+ (ct->ct_wait.tv_usec / 1000));
+
+ if (len == 0)
+ return (0);
+ fd.fd = ct->ct_fd;
+ fd.events = POLLIN;
+ for (;;) {
+ switch (_poll(&fd, 1, milliseconds)) {
+ case 0:
+ ct->ct_error.re_status = RPC_TIMEDOUT;
+ return (-1);
+
+ case -1:
+ if (errno == EINTR)
+ continue;
+ ct->ct_error.re_status = RPC_CANTRECV;
+ ct->ct_error.re_errno = errno;
+ return (-1);
+ }
+ break;
+ }
+
+ sal = sizeof(sa);
+ if ((_getpeername(ct->ct_fd, &sa, &sal) == 0) &&
+ (sa.sa_family == AF_LOCAL)) {
+ len = __msgread(ct->ct_fd, buf, (size_t)len);
+ } else {
+ len = _read(ct->ct_fd, buf, (size_t)len);
+ }
+
+ switch (len) {
+ case 0:
+ /* premature eof */
+ ct->ct_error.re_errno = ECONNRESET;
+ ct->ct_error.re_status = RPC_CANTRECV;
+ len = -1; /* it's really an error */
+ break;
+
+ case -1:
+ ct->ct_error.re_errno = errno;
+ ct->ct_error.re_status = RPC_CANTRECV;
+ break;
+ }
+ return (len);
+}
+
+static int
+write_vc(void *ctp, void *buf, int len)
+{
+ struct sockaddr sa;
+ socklen_t sal;
+ struct ct_data *ct = (struct ct_data *)ctp;
+ int i, cnt;
+
+ sal = sizeof(sa);
+ if ((_getpeername(ct->ct_fd, &sa, &sal) == 0) &&
+ (sa.sa_family == AF_LOCAL)) {
+ for (cnt = len; cnt > 0; cnt -= i, buf = (char *)buf + i) {
+ if ((i = __msgwrite(ct->ct_fd, buf,
+ (size_t)cnt)) == -1) {
+ ct->ct_error.re_errno = errno;
+ ct->ct_error.re_status = RPC_CANTSEND;
+ return (-1);
+ }
+ }
+ } else {
+ for (cnt = len; cnt > 0; cnt -= i, buf = (char *)buf + i) {
+ if ((i = _write(ct->ct_fd, buf, (size_t)cnt)) == -1) {
+ ct->ct_error.re_errno = errno;
+ ct->ct_error.re_status = RPC_CANTSEND;
+ return (-1);
+ }
+ }
+ }
+ return (len);
+}
+
+static struct clnt_ops *
+clnt_vc_ops(void)
+{
+ static struct clnt_ops ops;
+ sigset_t mask, newmask;
+
+ /* VARIABLES PROTECTED BY ops_lock: ops */
+
+ sigfillset(&newmask);
+ thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
+ mutex_lock(&ops_lock);
+ if (ops.cl_call == NULL) {
+ ops.cl_call = clnt_vc_call;
+ ops.cl_abort = clnt_vc_abort;
+ ops.cl_geterr = clnt_vc_geterr;
+ ops.cl_freeres = clnt_vc_freeres;
+ ops.cl_destroy = clnt_vc_destroy;
+ ops.cl_control = clnt_vc_control;
+ }
+ mutex_unlock(&ops_lock);
+ thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
+ return (&ops);
+}
+
+/*
+ * Make sure that the time is not garbage. -1 value is disallowed.
+ * Note this is different from time_not_ok in clnt_dg.c
+ */
+static bool_t
+time_not_ok(struct timeval *t)
+{
+ return (t->tv_sec <= -1 || t->tv_sec > 100000000 ||
+ t->tv_usec <= -1 || t->tv_usec > 1000000);
+}
+
+static int
+__msgread(int sock, void *buf, size_t cnt)
+{
+ struct iovec iov[1];
+ struct msghdr msg;
+ union {
+ struct cmsghdr cmsg;
+ char control[CMSG_SPACE(sizeof(struct cmsgcred))];
+ } cm;
+
+ bzero((char *)&cm, sizeof(cm));
+ iov[0].iov_base = buf;
+ iov[0].iov_len = cnt;
+
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 1;
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_control = (caddr_t)&cm;
+ msg.msg_controllen = CMSG_SPACE(sizeof(struct cmsgcred));
+ msg.msg_flags = 0;
+
+ return(_recvmsg(sock, &msg, 0));
+}
+
+static int
+__msgwrite(int sock, void *buf, size_t cnt)
+{
+ struct iovec iov[1];
+ struct msghdr msg;
+ union {
+ struct cmsghdr cmsg;
+ char control[CMSG_SPACE(sizeof(struct cmsgcred))];
+ } cm;
+
+ bzero((char *)&cm, sizeof(cm));
+ iov[0].iov_base = buf;
+ iov[0].iov_len = cnt;
+
+ cm.cmsg.cmsg_type = SCM_CREDS;
+ cm.cmsg.cmsg_level = SOL_SOCKET;
+ cm.cmsg.cmsg_len = CMSG_LEN(sizeof(struct cmsgcred));
+
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 1;
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_control = (caddr_t)&cm;
+ msg.msg_controllen = CMSG_SPACE(sizeof(struct cmsgcred));
+ msg.msg_flags = 0;
+
+ return(_sendmsg(sock, &msg, 0));
+}
diff --git a/lib/libc/rpc/crypt_client.c b/lib/libc/rpc/crypt_client.c
new file mode 100644
index 000000000000..b7f0d1fff48c
--- /dev/null
+++ b/lib/libc/rpc/crypt_client.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 1996
+ * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <err.h>
+#include <sys/types.h>
+#include <rpc/des_crypt.h>
+#include <rpc/des.h>
+#include <string.h>
+#include <rpcsvc/crypt.h>
+#include "un-namespace.h"
+
+int
+_des_crypt_call(char *buf, int len, struct desparams *dparms)
+{
+ CLIENT *clnt;
+ desresp *result_1;
+ desargs des_crypt_1_arg;
+ struct netconfig *nconf;
+ void *localhandle;
+ int stat;
+
+ nconf = NULL;
+ localhandle = setnetconfig();
+ while ((nconf = getnetconfig(localhandle)) != NULL) {
+ if (nconf->nc_protofmly != NULL &&
+ strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0)
+ break;
+ }
+ if (nconf == NULL) {
+ warnx("getnetconfig: %s", nc_sperror());
+ endnetconfig(localhandle);
+ return(DESERR_HWERROR);
+ }
+ clnt = clnt_tp_create(NULL, CRYPT_PROG, CRYPT_VERS, nconf);
+ if (clnt == (CLIENT *) NULL) {
+ endnetconfig(localhandle);
+ return(DESERR_HWERROR);
+ }
+ endnetconfig(localhandle);
+
+ des_crypt_1_arg.desbuf.desbuf_len = len;
+ des_crypt_1_arg.desbuf.desbuf_val = buf;
+ des_crypt_1_arg.des_dir = (dparms->des_dir == ENCRYPT) ? ENCRYPT_DES : DECRYPT_DES;
+ des_crypt_1_arg.des_mode = (dparms->des_mode == CBC) ? CBC_DES : ECB_DES;
+ bcopy(dparms->des_ivec, des_crypt_1_arg.des_ivec, 8);
+ bcopy(dparms->des_key, des_crypt_1_arg.des_key, 8);
+
+ result_1 = des_crypt_1(&des_crypt_1_arg, clnt);
+ if (result_1 == (desresp *) NULL) {
+ clnt_destroy(clnt);
+ return(DESERR_HWERROR);
+ }
+
+ stat = result_1->stat;
+
+ if (result_1->stat == DESERR_NONE ||
+ result_1->stat == DESERR_NOHWDEVICE) {
+ bcopy(result_1->desbuf.desbuf_val, buf, len);
+ bcopy(result_1->des_ivec, dparms->des_ivec, 8);
+ }
+
+ clnt_freeres(clnt, (xdrproc_t)xdr_desresp, result_1);
+ clnt_destroy(clnt);
+
+ return(stat);
+}
diff --git a/lib/libc/rpc/des_crypt.3 b/lib/libc/rpc/des_crypt.3
new file mode 100644
index 000000000000..b40a62c4ae29
--- /dev/null
+++ b/lib/libc/rpc/des_crypt.3
@@ -0,0 +1,130 @@
+.\" @(#)des_crypt.3 2.1 88/08/11 4.0 RPCSRC; from 1.16 88/03/02 SMI;
+.\" $FreeBSD$
+.\"
+.Dd October 6, 1987
+.Dt DES_CRYPT 3
+.Os
+.Sh NAME
+.Nm des_crypt , ecb_crypt , cbc_crypt , des_setparity
+.Nd "fast DES encryption"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In rpc/des_crypt.h
+.Ft int
+.Fn ecb_crypt "char *key" "char *data" "unsigned datalen" "unsigned mode"
+.Ft int
+.Fn cbc_crypt "char *key" "char *data" "unsigned datalen" "unsigned mode" "char *ivec"
+.Ft void
+.Fn des_setparity "char *key"
+.Sh DESCRIPTION
+The
+.Fn ecb_crypt
+and
+.Fn cbc_crypt
+functions
+implement the
+.Tn NBS
+.Tn DES
+(Data Encryption Standard).
+These routines are faster and more general purpose than
+.Xr crypt 3 .
+They also are able to utilize
+.Tn DES
+hardware if it is available.
+The
+.Fn ecb_crypt
+function
+encrypts in
+.Tn ECB
+(Electronic Code Book)
+mode, which encrypts blocks of data independently.
+The
+.Fn cbc_crypt
+function
+encrypts in
+.Tn CBC
+(Cipher Block Chaining)
+mode, which chains together
+successive blocks.
+.Tn CBC
+mode protects against insertions, deletions and
+substitutions of blocks.
+Also, regularities in the clear text will
+not appear in the cipher text.
+.Pp
+Here is how to use these routines.
+The first argument,
+.Fa key ,
+is the 8-byte encryption key with parity.
+To set the key's parity, which for
+.Tn DES
+is in the low bit of each byte, use
+.Fn des_setparity .
+The second argument,
+.Fa data ,
+contains the data to be encrypted or decrypted.
+The
+third argument,
+.Fa datalen ,
+is the length in bytes of
+.Fa data ,
+which must be a multiple of 8.
+The fourth argument,
+.Fa mode ,
+is formed by
+.Em OR Ns 'ing
+together some things.
+For the encryption direction
+.Em OR
+in either
+.Dv DES_ENCRYPT
+or
+.Dv DES_DECRYPT .
+For software versus hardware
+encryption,
+.Em OR
+in either
+.Dv DES_HW
+or
+.Dv DES_SW .
+If
+.Dv DES_HW
+is specified, and there is no hardware, then the encryption is performed
+in software and the routine returns
+.Er DESERR_NOHWDEVICE .
+For
+.Fn cbc_crypt ,
+the
+.Fa ivec
+argument
+is the 8-byte initialization
+vector for the chaining.
+It is updated to the next initialization
+vector upon return.
+.Sh ERRORS
+.Bl -tag -width [DESERR_NOHWDEVICE] -compact
+.It Bq Er DESERR_NONE
+No error.
+.It Bq Er DESERR_NOHWDEVICE
+Encryption succeeded, but done in software instead of the requested hardware.
+.It Bq Er DESERR_HWERR
+An error occurred in the hardware or driver.
+.It Bq Er DESERR_BADPARAM
+Bad argument to routine.
+.El
+.Pp
+Given a result status
+.Va stat ,
+the macro
+.Fn DES_FAILED stat
+is false only for the first two statuses.
+.Sh SEE ALSO
+.\" .Xr des 1 ,
+.Xr crypt 3
+.Sh RESTRICTIONS
+These routines are not available in RPCSRC 4.0.
+This information is provided to describe the
+.Tn DES
+interface expected by
+Secure RPC.
diff --git a/lib/libc/rpc/des_crypt.c b/lib/libc/rpc/des_crypt.c
new file mode 100644
index 000000000000..236e9ed87ff3
--- /dev/null
+++ b/lib/libc/rpc/des_crypt.c
@@ -0,0 +1,140 @@
+/*-
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * des_crypt.c, DES encryption library routines
+ * Copyright (C) 1986, Sun Microsystems, Inc.
+ */
+
+#include <sys/types.h>
+#include <rpc/des_crypt.h>
+#include <rpc/des.h>
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)des_crypt.c 2.2 88/08/10 4.0 RPCSRC; from 1.13 88/02/08 SMI";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+static int common_crypt( char *, char *, unsigned, unsigned, struct desparams * );
+int (*__des_crypt_LOCAL)(char *, unsigned, struct desparams *) = 0;
+extern int _des_crypt_call(char *, int, struct desparams *);
+/*
+ * Copy 8 bytes
+ */
+#define COPY8(src, dst) { \
+ char *a = (char *) dst; \
+ char *b = (char *) src; \
+ *a++ = *b++; *a++ = *b++; *a++ = *b++; *a++ = *b++; \
+ *a++ = *b++; *a++ = *b++; *a++ = *b++; *a++ = *b++; \
+}
+
+/*
+ * Copy multiple of 8 bytes
+ */
+#define DESCOPY(src, dst, len) { \
+ char *a = (char *) dst; \
+ char *b = (char *) src; \
+ int i; \
+ for (i = (int) len; i > 0; i -= 8) { \
+ *a++ = *b++; *a++ = *b++; *a++ = *b++; *a++ = *b++; \
+ *a++ = *b++; *a++ = *b++; *a++ = *b++; *a++ = *b++; \
+ } \
+}
+
+/*
+ * CBC mode encryption
+ */
+int
+cbc_crypt(char *key, char *buf, unsigned len, unsigned mode, char *ivec)
+{
+ int err;
+ struct desparams dp;
+
+#ifdef BROKEN_DES
+ dp.UDES.UDES_buf = buf;
+ dp.des_mode = ECB;
+#else
+ dp.des_mode = CBC;
+#endif
+ COPY8(ivec, dp.des_ivec);
+ err = common_crypt(key, buf, len, mode, &dp);
+ COPY8(dp.des_ivec, ivec);
+ return(err);
+}
+
+
+/*
+ * ECB mode encryption
+ */
+int
+ecb_crypt(char *key, char *buf, unsigned len, unsigned mode)
+{
+ struct desparams dp;
+
+#ifdef BROKEN_DES
+ dp.UDES.UDES_buf = buf;
+ dp.des_mode = CBC;
+#else
+ dp.des_mode = ECB;
+#endif
+ return(common_crypt(key, buf, len, mode, &dp));
+}
+
+
+
+/*
+ * Common code to cbc_crypt() & ecb_crypt()
+ */
+static int
+common_crypt(char *key, char *buf, unsigned len, unsigned mode,
+ struct desparams *desp)
+{
+ int desdev;
+
+ if ((len % 8) != 0 || len > DES_MAXDATA) {
+ return(DESERR_BADPARAM);
+ }
+ desp->des_dir =
+ ((mode & DES_DIRMASK) == DES_ENCRYPT) ? ENCRYPT : DECRYPT;
+
+ desdev = mode & DES_DEVMASK;
+ COPY8(key, desp->des_key);
+ /*
+ * software
+ */
+ if (__des_crypt_LOCAL != NULL) {
+ if (!__des_crypt_LOCAL(buf, len, desp)) {
+ return (DESERR_HWERROR);
+ }
+ } else {
+ if (!_des_crypt_call(buf, len, desp)) {
+ return (DESERR_HWERROR);
+ }
+ }
+ return(desdev == DES_SW ? DESERR_NONE : DESERR_NOHWDEVICE);
+}
diff --git a/lib/libc/rpc/des_soft.c b/lib/libc/rpc/des_soft.c
new file mode 100644
index 000000000000..5eb99151c0e0
--- /dev/null
+++ b/lib/libc/rpc/des_soft.c
@@ -0,0 +1,69 @@
+/*-
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)des_soft.c 2.2 88/08/10 4.0 RPCSRC; from 1.13 88/02/08 SMI";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Table giving odd parity in the low bit for ASCII characters
+ */
+static char partab[128] = {
+ 0x01, 0x01, 0x02, 0x02, 0x04, 0x04, 0x07, 0x07,
+ 0x08, 0x08, 0x0b, 0x0b, 0x0d, 0x0d, 0x0e, 0x0e,
+ 0x10, 0x10, 0x13, 0x13, 0x15, 0x15, 0x16, 0x16,
+ 0x19, 0x19, 0x1a, 0x1a, 0x1c, 0x1c, 0x1f, 0x1f,
+ 0x20, 0x20, 0x23, 0x23, 0x25, 0x25, 0x26, 0x26,
+ 0x29, 0x29, 0x2a, 0x2a, 0x2c, 0x2c, 0x2f, 0x2f,
+ 0x31, 0x31, 0x32, 0x32, 0x34, 0x34, 0x37, 0x37,
+ 0x38, 0x38, 0x3b, 0x3b, 0x3d, 0x3d, 0x3e, 0x3e,
+ 0x40, 0x40, 0x43, 0x43, 0x45, 0x45, 0x46, 0x46,
+ 0x49, 0x49, 0x4a, 0x4a, 0x4c, 0x4c, 0x4f, 0x4f,
+ 0x51, 0x51, 0x52, 0x52, 0x54, 0x54, 0x57, 0x57,
+ 0x58, 0x58, 0x5b, 0x5b, 0x5d, 0x5d, 0x5e, 0x5e,
+ 0x61, 0x61, 0x62, 0x62, 0x64, 0x64, 0x67, 0x67,
+ 0x68, 0x68, 0x6b, 0x6b, 0x6d, 0x6d, 0x6e, 0x6e,
+ 0x70, 0x70, 0x73, 0x73, 0x75, 0x75, 0x76, 0x76,
+ 0x79, 0x79, 0x7a, 0x7a, 0x7c, 0x7c, 0x7f, 0x7f,
+};
+
+/*
+ * Add odd parity to low bit of 8 byte key
+ */
+void
+des_setparity(char *p)
+{
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ *p = partab[*p & 0x7f];
+ p++;
+ }
+}
diff --git a/lib/libc/rpc/getnetconfig.3 b/lib/libc/rpc/getnetconfig.3
new file mode 100644
index 000000000000..e67b9bbb75c9
--- /dev/null
+++ b/lib/libc/rpc/getnetconfig.3
@@ -0,0 +1,222 @@
+.\" @(#)getnetconfig.3n 1.28 93/06/02 SMI; from SVr4
+.\" $NetBSD: getnetconfig.3,v 1.1 2000/06/02 23:11:11 fvdl Exp $
+.\" $FreeBSD$
+.\" Copyright 1989 AT&T
+.Dd April 22, 2000
+.Dt GETNETCONFIG 3
+.Os
+.Sh NAME
+.Nm getnetconfig ,
+.Nm setnetconfig ,
+.Nm endnetconfig ,
+.Nm getnetconfigent ,
+.Nm freenetconfigent ,
+.Nm nc_perror ,
+.Nm nc_sperror
+.Nd get network configuration database entry
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In netconfig.h
+.Ft "struct netconfig *"
+.Fn getnetconfig "void *handlep"
+.Ft "void *"
+.Fn setnetconfig "void"
+.Ft int
+.Fn endnetconfig "void *handlep"
+.Ft "struct netconfig *"
+.Fn getnetconfigent "const char *netid"
+.Ft void
+.Fn freenetconfigent "struct netconfig *netconfigp"
+.Ft void
+.Fn nc_perror "const char *msg"
+.Ft "char *"
+.Fn nc_sperror "void"
+.Sh DESCRIPTION
+The library routines described on this page
+provide the application access to
+the system network configuration database,
+.Pa /etc/netconfig .
+The
+.Fn getnetconfig
+function
+returns a pointer to the
+current entry in the
+netconfig
+database, formatted as a
+.Ft "struct netconfig" .
+Successive calls will return successive netconfig
+entries in the netconfig database.
+The
+.Fn getnetconfig
+function
+can be used to search the entire netconfig
+file.
+The
+.Fn getnetconfig
+function
+returns
+.Dv NULL
+at the end of the file.
+The
+.Fa handlep
+argument
+is the handle obtained through
+.Fn setnetconfig .
+.Pp
+A call to
+.Fn setnetconfig
+has the effect of
+.Dq binding
+to or
+.Dq rewinding
+the netconfig database.
+The
+.Fn setnetconfig
+function
+must be called before the first call to
+.Fn getnetconfig
+and may be called at any other time.
+The
+.Fn setnetconfig
+function
+need not be called before a call to
+.Fn getnetconfigent .
+The
+.Fn setnetconfig
+function
+returns a unique handle to be used by
+.Fn getnetconfig .
+.Pp
+The
+.Fn endnetconfig
+function
+should be called when processing is complete to release resources for reuse.
+The
+.Fa handlep
+argument
+is the handle obtained through
+.Fn setnetconfig .
+Programmers should be aware, however, that the last call to
+.Fn endnetconfig
+frees all memory allocated by
+.Fn getnetconfig
+for the
+.Ft "struct netconfig"
+data structure.
+The
+.Fn endnetconfig
+function
+may not be called before
+.Fn setnetconfig .
+.Pp
+The
+.Fn getnetconfigent
+function
+returns a pointer
+to the netconfig structure corresponding
+to
+.Fa netid .
+It returns
+.Dv NULL
+if
+.Fa netid
+is invalid
+(that is, does not name an entry in the netconfig database).
+.Pp
+The
+.Fn freenetconfigent
+function
+frees the netconfig structure pointed to by
+.Fa netconfigp
+(previously returned by
+.Fn getnetconfigent ) .
+.Pp
+The
+.Fn nc_perror
+function
+prints a message to the standard error indicating why any of the
+above routines failed.
+The message is prepended with the string
+.Fa msg
+and a colon.
+A newline character is appended at the end of the message.
+.Pp
+The
+.Fn nc_sperror
+function
+is similar to
+.Fn nc_perror
+but instead of sending the message
+to the standard error, will return a pointer to a string that
+contains the error message.
+.Pp
+The
+.Fn nc_perror
+and
+.Fn nc_sperror
+functions
+can also be used with the
+.Ev NETPATH
+access routines defined in
+.Xr getnetpath 3 .
+.Sh RETURN VALUES
+The
+.Fn setnetconfig
+function
+returns a unique handle to be used by
+.Fn getnetconfig .
+In the case of an error,
+.Fn setnetconfig
+returns
+.Dv NULL
+and
+.Fn nc_perror
+or
+.Fn nc_sperror
+can be used to print the reason for failure.
+.Pp
+The
+.Fn getnetconfig
+function
+returns a pointer to the current entry in the netconfig
+database, formatted as a
+.Ft "struct netconfig" .
+The
+.Fn getnetconfig
+function
+returns
+.Dv NULL
+at the end of the file, or upon failure.
+.Pp
+The
+.Fn endnetconfig
+function
+returns 0 on success and \-1 on failure
+(for example, if
+.Fn setnetconfig
+was not called previously).
+.Pp
+On success,
+.Fn getnetconfigent
+returns a pointer to the
+.Ft "struct netconfig"
+structure corresponding to
+.Fa netid ;
+otherwise it returns
+.Dv NULL .
+.Pp
+The
+.Fn nc_sperror
+function
+returns a pointer to a buffer which contains the error message string.
+This buffer is overwritten on each call.
+In multithreaded applications, this buffer is
+implemented as thread-specific data.
+.Sh FILES
+.Bl -tag -width /etc/netconfig -compact
+.It Pa /etc/netconfig
+.El
+.Sh SEE ALSO
+.Xr getnetpath 3 ,
+.Xr netconfig 5
diff --git a/lib/libc/rpc/getnetconfig.c b/lib/libc/rpc/getnetconfig.c
new file mode 100644
index 000000000000..6d504c5f55ff
--- /dev/null
+++ b/lib/libc/rpc/getnetconfig.c
@@ -0,0 +1,734 @@
+/* $NetBSD: getnetconfig.c,v 1.3 2000/07/06 03:10:34 christos Exp $ */
+
+/*-
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)getnetconfig.c 1.12 91/12/19 SMI";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Copyright (c) 1989 by Sun Microsystems, Inc.
+ */
+
+#include "namespace.h"
+#include "reentrant.h"
+#include <stdio.h>
+#include <errno.h>
+#include <netconfig.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <rpc/rpc.h>
+#include <unistd.h>
+#include "un-namespace.h"
+#include "rpc_com.h"
+
+/*
+ * The five library routines in this file provide application access to the
+ * system network configuration database, /etc/netconfig. In addition to the
+ * netconfig database and the routines for accessing it, the environment
+ * variable NETPATH and its corresponding routines in getnetpath.c may also be
+ * used to specify the network transport to be used.
+ */
+
+
+/*
+ * netconfig errors
+ */
+
+#define NC_NONETCONFIG ENOENT
+#define NC_NOMEM ENOMEM
+#define NC_NOTINIT EINVAL /* setnetconfig was not called first */
+#define NC_BADFILE EBADF /* format for netconfig file is bad */
+#define NC_NOTFOUND ENOPROTOOPT /* specified netid was not found */
+
+/*
+ * semantics as strings (should be in netconfig.h)
+ */
+#define NC_TPI_CLTS_S "tpi_clts"
+#define NC_TPI_COTS_S "tpi_cots"
+#define NC_TPI_COTS_ORD_S "tpi_cots_ord"
+#define NC_TPI_RAW_S "tpi_raw"
+
+/*
+ * flags as characters (also should be in netconfig.h)
+ */
+#define NC_NOFLAG_C '-'
+#define NC_VISIBLE_C 'v'
+#define NC_BROADCAST_C 'b'
+
+/*
+ * Character used to indicate there is no name-to-address lookup library
+ */
+#define NC_NOLOOKUP "-"
+
+static const char * const _nc_errors[] = {
+ "Netconfig database not found",
+ "Not enough memory",
+ "Not initialized",
+ "Netconfig database has invalid format",
+ "Netid not found in netconfig database"
+};
+
+struct netconfig_info {
+ int eof; /* all entries has been read */
+ int ref; /* # of times setnetconfig() has been called */
+ struct netconfig_list *head; /* head of the list */
+ struct netconfig_list *tail; /* last of the list */
+};
+
+struct netconfig_list {
+ char *linep; /* hold line read from netconfig */
+ struct netconfig *ncp;
+ struct netconfig_list *next;
+};
+
+struct netconfig_vars {
+ int valid; /* token that indicates a valid netconfig_vars */
+ int flag; /* first time flag */
+ struct netconfig_list *nc_configs; /* pointer to the current netconfig entry */
+};
+
+#define NC_VALID 0xfeed
+#define NC_STORAGE 0xf00d
+#define NC_INVALID 0
+
+
+static int *__nc_error(void);
+static int parse_ncp(char *, struct netconfig *);
+static struct netconfig *dup_ncp(struct netconfig *);
+
+
+static FILE *nc_file; /* for netconfig db */
+static mutex_t nc_file_lock = MUTEX_INITIALIZER;
+
+static struct netconfig_info ni = { 0, 0, NULL, NULL};
+static mutex_t ni_lock = MUTEX_INITIALIZER;
+
+static thread_key_t nc_key;
+static once_t nc_once = ONCE_INITIALIZER;
+static int nc_key_error;
+
+static void
+nc_key_init(void)
+{
+
+ nc_key_error = thr_keycreate(&nc_key, free);
+}
+
+#define MAXNETCONFIGLINE 1000
+
+static int *
+__nc_error(void)
+{
+ static int nc_error = 0;
+ int *nc_addr;
+
+ /*
+ * Use the static `nc_error' if we are the main thread
+ * (including non-threaded programs), or if an allocation
+ * fails.
+ */
+ if (thr_main())
+ return (&nc_error);
+ if (thr_once(&nc_once, nc_key_init) != 0 || nc_key_error != 0)
+ return (&nc_error);
+ if ((nc_addr = (int *)thr_getspecific(nc_key)) == NULL) {
+ nc_addr = (int *)malloc(sizeof (int));
+ if (thr_setspecific(nc_key, (void *) nc_addr) != 0) {
+ free(nc_addr);
+ return (&nc_error);
+ }
+ *nc_addr = 0;
+ }
+ return (nc_addr);
+}
+
+#define nc_error (*(__nc_error()))
+/*
+ * A call to setnetconfig() establishes a /etc/netconfig "session". A session
+ * "handle" is returned on a successful call. At the start of a session (after
+ * a call to setnetconfig()) searches through the /etc/netconfig database will
+ * proceed from the start of the file. The session handle must be passed to
+ * getnetconfig() to parse the file. Each call to getnetconfig() using the
+ * current handle will process one subsequent entry in /etc/netconfig.
+ * setnetconfig() must be called before the first call to getnetconfig().
+ * (Handles are used to allow for nested calls to setnetpath()).
+ *
+ * A new session is established with each call to setnetconfig(), with a new
+ * handle being returned on each call. Previously established sessions remain
+ * active until endnetconfig() is called with that session's handle as an
+ * argument.
+ *
+ * setnetconfig() need *not* be called before a call to getnetconfigent().
+ * setnetconfig() returns a NULL pointer on failure (for example, if
+ * the netconfig database is not present).
+ */
+void *
+setnetconfig(void)
+{
+ struct netconfig_vars *nc_vars;
+
+ if ((nc_vars = (struct netconfig_vars *)malloc(sizeof
+ (struct netconfig_vars))) == NULL) {
+ return(NULL);
+ }
+
+ /*
+ * For multiple calls, i.e. nc_file is not NULL, we just return the
+ * handle without reopening the netconfig db.
+ */
+ mutex_lock(&ni_lock);
+ ni.ref++;
+ mutex_unlock(&ni_lock);
+
+ mutex_lock(&nc_file_lock);
+ if ((nc_file != NULL) || (nc_file = fopen(NETCONFIG, "r")) != NULL) {
+ nc_vars->valid = NC_VALID;
+ nc_vars->flag = 0;
+ nc_vars->nc_configs = ni.head;
+ mutex_unlock(&nc_file_lock);
+ return ((void *)nc_vars);
+ }
+ mutex_unlock(&nc_file_lock);
+
+ mutex_lock(&ni_lock);
+ ni.ref--;
+ mutex_unlock(&ni_lock);
+
+ nc_error = NC_NONETCONFIG;
+ free(nc_vars);
+ return (NULL);
+}
+
+
+/*
+ * When first called, getnetconfig() returns a pointer to the first entry in
+ * the netconfig database, formatted as a struct netconfig. On each subsequent
+ * call, getnetconfig() returns a pointer to the next entry in the database.
+ * getnetconfig() can thus be used to search the entire netconfig file.
+ * getnetconfig() returns NULL at end of file.
+ */
+
+struct netconfig *
+getnetconfig(void *handlep)
+{
+ struct netconfig_vars *ncp = (struct netconfig_vars *)handlep;
+ char *stringp; /* tmp string pointer */
+ struct netconfig_list *list;
+ struct netconfig *np;
+ struct netconfig *result;
+
+ /*
+ * Verify that handle is valid
+ */
+ mutex_lock(&nc_file_lock);
+ if (ncp == NULL || nc_file == NULL) {
+ nc_error = NC_NOTINIT;
+ mutex_unlock(&nc_file_lock);
+ return (NULL);
+ }
+ mutex_unlock(&nc_file_lock);
+
+ switch (ncp->valid) {
+ case NC_VALID:
+ /*
+ * If entry has already been read into the list,
+ * we return the entry in the linked list.
+ * If this is the first time call, check if there are any entries in
+ * linked list. If no entries, we need to read the netconfig db.
+ * If we have been here and the next entry is there, we just return
+ * it.
+ */
+ if (ncp->flag == 0) { /* first time */
+ ncp->flag = 1;
+ mutex_lock(&ni_lock);
+ ncp->nc_configs = ni.head;
+ mutex_unlock(&ni_lock);
+ if (ncp->nc_configs != NULL) /* entry already exist */
+ return(ncp->nc_configs->ncp);
+ }
+ else if (ncp->nc_configs != NULL && ncp->nc_configs->next != NULL) {
+ ncp->nc_configs = ncp->nc_configs->next;
+ return(ncp->nc_configs->ncp);
+ }
+
+ /*
+ * If we cannot find the entry in the list and is end of file,
+ * we give up.
+ */
+ mutex_lock(&ni_lock);
+ if (ni.eof == 1) {
+ mutex_unlock(&ni_lock);
+ return(NULL);
+ }
+ mutex_unlock(&ni_lock);
+
+ break;
+ default:
+ nc_error = NC_NOTINIT;
+ return (NULL);
+ }
+
+ stringp = (char *) malloc(MAXNETCONFIGLINE);
+ if (stringp == NULL)
+ return (NULL);
+
+#ifdef MEM_CHK
+ if (malloc_verify() == 0) {
+ fprintf(stderr, "memory heap corrupted in getnetconfig\n");
+ exit(1);
+ }
+#endif
+
+ /*
+ * Read a line from netconfig file.
+ */
+ mutex_lock(&nc_file_lock);
+ do {
+ if (fgets(stringp, MAXNETCONFIGLINE, nc_file) == NULL) {
+ free(stringp);
+ mutex_lock(&ni_lock);
+ ni.eof = 1;
+ mutex_unlock(&ni_lock);
+ mutex_unlock(&nc_file_lock);
+ return (NULL);
+ }
+ } while (*stringp == '#');
+ mutex_unlock(&nc_file_lock);
+
+ list = (struct netconfig_list *) malloc(sizeof (struct netconfig_list));
+ if (list == NULL) {
+ free(stringp);
+ return(NULL);
+ }
+ np = (struct netconfig *) malloc(sizeof (struct netconfig));
+ if (np == NULL) {
+ free(stringp);
+ free(list);
+ return(NULL);
+ }
+ list->ncp = np;
+ list->next = NULL;
+ list->ncp->nc_lookups = NULL;
+ list->linep = stringp;
+ if (parse_ncp(stringp, list->ncp) == -1) {
+ free(stringp);
+ free(np);
+ free(list);
+ return (NULL);
+ }
+ else {
+ /*
+ * If this is the first entry that's been read, it is the head of
+ * the list. If not, put the entry at the end of the list.
+ * Reposition the current pointer of the handle to the last entry
+ * in the list.
+ */
+ mutex_lock(&ni_lock);
+ if (ni.head == NULL) { /* first entry */
+ ni.head = ni.tail = list;
+ }
+ else {
+ ni.tail->next = list;
+ ni.tail = ni.tail->next;
+ }
+ ncp->nc_configs = ni.tail;
+ result = ni.tail->ncp;
+ mutex_unlock(&ni_lock);
+ return(result);
+ }
+}
+
+/*
+ * endnetconfig() may be called to "unbind" or "close" the netconfig database
+ * when processing is complete, releasing resources for reuse. endnetconfig()
+ * may not be called before setnetconfig(). endnetconfig() returns 0 on
+ * success and -1 on failure (for example, if setnetconfig() was not called
+ * previously).
+ */
+int
+endnetconfig(void *handlep)
+{
+ struct netconfig_vars *nc_handlep = (struct netconfig_vars *)handlep;
+
+ struct netconfig_list *q, *p;
+
+ /*
+ * Verify that handle is valid
+ */
+ if (nc_handlep == NULL || (nc_handlep->valid != NC_VALID &&
+ nc_handlep->valid != NC_STORAGE)) {
+ nc_error = NC_NOTINIT;
+ return (-1);
+ }
+
+ /*
+ * Return 0 if anyone still needs it.
+ */
+ nc_handlep->valid = NC_INVALID;
+ nc_handlep->flag = 0;
+ nc_handlep->nc_configs = NULL;
+ mutex_lock(&ni_lock);
+ if (--ni.ref > 0) {
+ mutex_unlock(&ni_lock);
+ free(nc_handlep);
+ return(0);
+ }
+
+ /*
+ * No one needs these entries anymore, then frees them.
+ * Make sure all info in netconfig_info structure has been reinitialized.
+ */
+ q = ni.head;
+ ni.eof = ni.ref = 0;
+ ni.head = NULL;
+ ni.tail = NULL;
+ mutex_unlock(&ni_lock);
+
+ while (q != NULL) {
+ p = q->next;
+ free(q->ncp->nc_lookups);
+ free(q->ncp);
+ free(q->linep);
+ free(q);
+ q = p;
+ }
+ free(nc_handlep);
+
+ mutex_lock(&nc_file_lock);
+ fclose(nc_file);
+ nc_file = NULL;
+ mutex_unlock(&nc_file_lock);
+
+ return (0);
+}
+
+/*
+ * getnetconfigent(netid) returns a pointer to the struct netconfig structure
+ * corresponding to netid. It returns NULL if netid is invalid (that is, does
+ * not name an entry in the netconfig database). It returns NULL and sets
+ * errno in case of failure (for example, if the netconfig database cannot be
+ * opened).
+ */
+
+struct netconfig *
+getnetconfigent(const char *netid)
+{
+ FILE *file; /* NETCONFIG db's file pointer */
+ char *linep; /* holds current netconfig line */
+ char *stringp; /* temporary string pointer */
+ struct netconfig *ncp = NULL; /* returned value */
+ struct netconfig_list *list; /* pointer to cache list */
+
+ nc_error = NC_NOTFOUND; /* default error. */
+ if (netid == NULL || strlen(netid) == 0) {
+ return (NULL);
+ }
+
+ /*
+ * Look up table if the entries have already been read and parsed in
+ * getnetconfig(), then copy this entry into a buffer and return it.
+ * If we cannot find the entry in the current list and there are more
+ * entries in the netconfig db that has not been read, we then read the
+ * db and try find the match netid.
+ * If all the netconfig db has been read and placed into the list and
+ * there is no match for the netid, return NULL.
+ */
+ mutex_lock(&ni_lock);
+ if (ni.head != NULL) {
+ for (list = ni.head; list; list = list->next) {
+ if (strcmp(list->ncp->nc_netid, netid) == 0) {
+ mutex_unlock(&ni_lock);
+ return(dup_ncp(list->ncp));
+ }
+ }
+ if (ni.eof == 1) { /* that's all the entries */
+ mutex_unlock(&ni_lock);
+ return(NULL);
+ }
+ }
+ mutex_unlock(&ni_lock);
+
+
+ if ((file = fopen(NETCONFIG, "r")) == NULL) {
+ nc_error = NC_NONETCONFIG;
+ return (NULL);
+ }
+
+ if ((linep = malloc(MAXNETCONFIGLINE)) == NULL) {
+ fclose(file);
+ nc_error = NC_NOMEM;
+ return (NULL);
+ }
+ do {
+ ptrdiff_t len;
+ char *tmpp; /* tmp string pointer */
+
+ do {
+ if ((stringp = fgets(linep, MAXNETCONFIGLINE, file)) == NULL) {
+ break;
+ }
+ } while (*stringp == '#');
+ if (stringp == NULL) { /* eof */
+ break;
+ }
+ if ((tmpp = strpbrk(stringp, "\t ")) == NULL) { /* can't parse file */
+ nc_error = NC_BADFILE;
+ break;
+ }
+ if (strlen(netid) == (size_t) (len = tmpp - stringp) && /* a match */
+ strncmp(stringp, netid, (size_t)len) == 0) {
+ if ((ncp = (struct netconfig *)
+ malloc(sizeof (struct netconfig))) == NULL) {
+ break;
+ }
+ ncp->nc_lookups = NULL;
+ if (parse_ncp(linep, ncp) == -1) {
+ free(ncp);
+ ncp = NULL;
+ }
+ break;
+ }
+ } while (stringp != NULL);
+ if (ncp == NULL) {
+ free(linep);
+ }
+ fclose(file);
+ return(ncp);
+}
+
+/*
+ * freenetconfigent(netconfigp) frees the netconfig structure pointed to by
+ * netconfigp (previously returned by getnetconfigent()).
+ */
+
+void
+freenetconfigent(struct netconfig *netconfigp)
+{
+ if (netconfigp != NULL) {
+ free(netconfigp->nc_netid); /* holds all netconfigp's strings */
+ free(netconfigp->nc_lookups);
+ free(netconfigp);
+ }
+ return;
+}
+
+/*
+ * Parse line and stuff it in a struct netconfig
+ * Typical line might look like:
+ * udp tpi_cots vb inet udp /dev/udp /usr/lib/ip.so,/usr/local/ip.so
+ *
+ * We return -1 if any of the tokens don't parse, or malloc fails.
+ *
+ * Note that we modify stringp (putting NULLs after tokens) and
+ * we set the ncp's string field pointers to point to these tokens within
+ * stringp.
+ *
+ * stringp - string to parse
+ * ncp - where to put results
+ */
+
+static int
+parse_ncp(char *stringp, struct netconfig *ncp)
+{
+ char *tokenp; /* for processing tokens */
+ char *lasts;
+ char **nc_lookups;
+
+ nc_error = NC_BADFILE; /* nearly anything that breaks is for this reason */
+ stringp[strlen(stringp)-1] = '\0'; /* get rid of newline */
+ /* netid */
+ if ((ncp->nc_netid = strtok_r(stringp, "\t ", &lasts)) == NULL) {
+ return (-1);
+ }
+
+ /* semantics */
+ if ((tokenp = strtok_r(NULL, "\t ", &lasts)) == NULL) {
+ return (-1);
+ }
+ if (strcmp(tokenp, NC_TPI_COTS_ORD_S) == 0)
+ ncp->nc_semantics = NC_TPI_COTS_ORD;
+ else if (strcmp(tokenp, NC_TPI_COTS_S) == 0)
+ ncp->nc_semantics = NC_TPI_COTS;
+ else if (strcmp(tokenp, NC_TPI_CLTS_S) == 0)
+ ncp->nc_semantics = NC_TPI_CLTS;
+ else if (strcmp(tokenp, NC_TPI_RAW_S) == 0)
+ ncp->nc_semantics = NC_TPI_RAW;
+ else
+ return (-1);
+
+ /* flags */
+ if ((tokenp = strtok_r(NULL, "\t ", &lasts)) == NULL) {
+ return (-1);
+ }
+ for (ncp->nc_flag = NC_NOFLAG; *tokenp != '\0';
+ tokenp++) {
+ switch (*tokenp) {
+ case NC_NOFLAG_C:
+ break;
+ case NC_VISIBLE_C:
+ ncp->nc_flag |= NC_VISIBLE;
+ break;
+ case NC_BROADCAST_C:
+ ncp->nc_flag |= NC_BROADCAST;
+ break;
+ default:
+ return (-1);
+ }
+ }
+ /* protocol family */
+ if ((ncp->nc_protofmly = strtok_r(NULL, "\t ", &lasts)) == NULL) {
+ return (-1);
+ }
+ /* protocol name */
+ if ((ncp->nc_proto = strtok_r(NULL, "\t ", &lasts)) == NULL) {
+ return (-1);
+ }
+ /* network device */
+ if ((ncp->nc_device = strtok_r(NULL, "\t ", &lasts)) == NULL) {
+ return (-1);
+ }
+ if ((tokenp = strtok_r(NULL, "\t ", &lasts)) == NULL) {
+ return (-1);
+ }
+ if (strcmp(tokenp, NC_NOLOOKUP) == 0) {
+ ncp->nc_nlookups = 0;
+ ncp->nc_lookups = NULL;
+ } else {
+ char *cp; /* tmp string */
+
+ free(ncp->nc_lookups); /* from last visit */
+ ncp->nc_lookups = NULL;
+ ncp->nc_nlookups = 0;
+ while ((cp = tokenp) != NULL) {
+ if ((nc_lookups = realloc(ncp->nc_lookups,
+ (ncp->nc_nlookups + 1) * sizeof *ncp->nc_lookups)) == NULL) {
+ free(ncp->nc_lookups);
+ ncp->nc_lookups = NULL;
+ return (-1);
+ }
+ tokenp = _get_next_token(cp, ',');
+ ncp->nc_lookups = nc_lookups;
+ ncp->nc_lookups[ncp->nc_nlookups++] = cp;
+ }
+ }
+ return (0);
+}
+
+
+/*
+ * Returns a string describing the reason for failure.
+ */
+char *
+nc_sperror(void)
+{
+ const char *message;
+
+ switch(nc_error) {
+ case NC_NONETCONFIG:
+ message = _nc_errors[0];
+ break;
+ case NC_NOMEM:
+ message = _nc_errors[1];
+ break;
+ case NC_NOTINIT:
+ message = _nc_errors[2];
+ break;
+ case NC_BADFILE:
+ message = _nc_errors[3];
+ break;
+ case NC_NOTFOUND:
+ message = _nc_errors[4];
+ break;
+ default:
+ message = "Unknown network selection error";
+ }
+ /* LINTED const castaway */
+ return ((char *)message);
+}
+
+/*
+ * Prints a message onto standard error describing the reason for failure.
+ */
+void
+nc_perror(const char *s)
+{
+ fprintf(stderr, "%s: %s\n", s, nc_sperror());
+}
+
+/*
+ * Duplicates the matched netconfig buffer.
+ */
+static struct netconfig *
+dup_ncp(struct netconfig *ncp)
+{
+ struct netconfig *p;
+ char *tmp, *tmp2;
+ u_int i;
+
+ if ((tmp=malloc(MAXNETCONFIGLINE)) == NULL)
+ return(NULL);
+ if ((p=(struct netconfig *)malloc(sizeof(struct netconfig))) == NULL) {
+ free(tmp);
+ return(NULL);
+ }
+ tmp2 = tmp;
+ /*
+ * First we dup all the data from matched netconfig buffer. Then we
+ * adjust some of the member pointer to a pre-allocated buffer where
+ * contains part of the data.
+ * To follow the convention used in parse_ncp(), we store all the
+ * necessary information in the pre-allocated buffer and let each
+ * of the netconfig char pointer member point to the right address
+ * in the buffer.
+ */
+ *p = *ncp;
+ p->nc_netid = (char *)strcpy(tmp,ncp->nc_netid);
+ tmp = strchr(tmp, '\0') + 1;
+ p->nc_protofmly = (char *)strcpy(tmp,ncp->nc_protofmly);
+ tmp = strchr(tmp, '\0') + 1;
+ p->nc_proto = (char *)strcpy(tmp,ncp->nc_proto);
+ tmp = strchr(tmp, '\0') + 1;
+ p->nc_device = (char *)strcpy(tmp,ncp->nc_device);
+ p->nc_lookups = (char **)malloc((size_t)(p->nc_nlookups+1) * sizeof(char *));
+ if (p->nc_lookups == NULL) {
+ free(p->nc_netid);
+ free(p);
+ free(tmp2);
+ return(NULL);
+ }
+ for (i=0; i < p->nc_nlookups; i++) {
+ tmp = strchr(tmp, '\0') + 1;
+ p->nc_lookups[i] = (char *)strcpy(tmp,ncp->nc_lookups[i]);
+ }
+ return(p);
+}
diff --git a/lib/libc/rpc/getnetpath.3 b/lib/libc/rpc/getnetpath.3
new file mode 100644
index 000000000000..5dfe68ad6ec9
--- /dev/null
+++ b/lib/libc/rpc/getnetpath.3
@@ -0,0 +1,170 @@
+.\" @(#)getnetpath.3n 1.26 93/05/07 SMI; from SVr4
+.\" $NetBSD: getnetpath.3,v 1.1 2000/06/02 23:11:11 fvdl Exp $
+.\" $FreeBSD$
+.\" Copyright 1989 AT&T
+.Dd April 22, 2000
+.Dt GETNETPATH 3
+.Os
+.Sh NAME
+.Nm getnetpath ,
+.Nm setnetpath ,
+.Nm endnetpath
+.Nd get
+.Pa /etc/netconfig
+entry corresponding to
+.Ev NETPATH
+component
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In netconfig.h
+.Ft "struct netconfig *"
+.Fn getnetpath "void *handlep"
+.Ft "void *"
+.Fn setnetpath "void"
+.Ft int
+.Fn endnetpath "void *handlep"
+.Sh DESCRIPTION
+The routines described in this page provide the application access to the system
+network configuration database,
+.Pa /etc/netconfig ,
+as it is
+.Dq filtered
+by the
+.Ev NETPATH
+environment variable (see
+.Xr environ 7 ) .
+See
+.Xr getnetconfig 3
+for other routines that also access the
+network configuration database directly.
+The
+.Ev NETPATH
+variable is a list of colon-separated network identifiers.
+.Pp
+The
+.Fn getnetpath
+function
+returns a pointer to the
+netconfig database entry corresponding to the first valid
+.Ev NETPATH
+component.
+The netconfig entry is formatted as a
+.Ft "struct netconfig" .
+On each subsequent call,
+.Fn getnetpath
+returns a pointer to the netconfig entry that corresponds to the next
+valid
+.Ev NETPATH
+component.
+The
+.Fn getnetpath
+function
+can thus be used to search the netconfig database for all networks
+included in the
+.Ev NETPATH
+variable.
+When
+.Ev NETPATH
+has been exhausted,
+.Fn getnetpath
+returns
+.Dv NULL .
+.Pp
+A call to
+.Fn setnetpath
+.Dq binds
+to or
+.Dq rewinds
+.Ev NETPATH .
+The
+.Fn setnetpath
+function
+must be called before the first call to
+.Fn getnetpath
+and may be called at any other time.
+It returns a handle that is used by
+.Fn getnetpath .
+.Pp
+The
+.Fn getnetpath
+function
+silently ignores invalid
+.Ev NETPATH
+components.
+A
+.Ev NETPATH
+component is invalid if there is no corresponding
+entry in the netconfig database.
+.Pp
+If the
+.Ev NETPATH
+variable is unset,
+.Fn getnetpath
+behaves as if
+.Ev NETPATH
+were set to the sequence of
+.Dq default
+or
+.Dq visible
+networks in the netconfig database, in the
+order in which they are listed.
+.\"This proviso holds also for this
+.\"whole manpage.
+.Pp
+The
+.Fn endnetpath
+function
+may be called to
+.Dq unbind
+from
+.Ev NETPATH
+when processing is complete, releasing resources for reuse.
+Programmers should be aware, however, that
+.Fn endnetpath
+frees all memory allocated by
+.Fn getnetpath
+for the struct netconfig data structure.
+.Sh RETURN VALUES
+The
+.Fn setnetpath
+function
+returns a handle that is used by
+.Fn getnetpath .
+In case of an error,
+.Fn setnetpath
+returns
+.Dv NULL .
+.Pp
+The
+.Fn endnetpath
+function
+returns 0 on success and \-1 on failure
+(for example, if
+.Fn setnetpath
+was not called previously).
+The
+.Fn nc_perror
+or
+.Fn nc_sperror
+function
+can be used to print out the reason for failure.
+See
+.Xr getnetconfig 3 .
+.Pp
+When first called,
+.Fn getnetpath
+returns a pointer to the netconfig database entry corresponding to the first
+valid
+.Ev NETPATH
+component.
+When
+.Ev NETPATH
+has been exhausted,
+.Fn getnetpath
+returns
+.Dv NULL .
+.Sh SEE ALSO
+.Xr getnetconfig 3 ,
+.Xr netconfig 5 ,
+.Xr environ 7
diff --git a/lib/libc/rpc/getnetpath.c b/lib/libc/rpc/getnetpath.c
new file mode 100644
index 000000000000..8d311369f52a
--- /dev/null
+++ b/lib/libc/rpc/getnetpath.c
@@ -0,0 +1,271 @@
+/* $NetBSD: getnetpath.c,v 1.3 2000/07/06 03:10:34 christos Exp $ */
+
+/*-
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)getnetpath.c 1.11 91/12/19 SMI";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Copyright (c) 1989 by Sun Microsystems, Inc.
+ */
+
+#include "namespace.h"
+#include <stdio.h>
+#include <errno.h>
+#include <netconfig.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include "un-namespace.h"
+
+/*
+ * internal structure to keep track of a netpath "session"
+ */
+struct netpath_chain {
+ struct netconfig *ncp; /* an nconf entry */
+ struct netpath_chain *nchain_next; /* next nconf entry allocated */
+};
+
+
+struct netpath_vars {
+ int valid; /* token that indicates a valid netpath_vars */
+ void *nc_handlep; /* handle for current netconfig "session" */
+ char *netpath; /* pointer to current view-point in NETPATH */
+ char *netpath_start; /* pointer to start of our copy of NETPATH */
+ struct netpath_chain *ncp_list; /* list of nconfs allocated this session*/
+};
+
+#define NP_VALID 0xf00d
+#define NP_INVALID 0
+
+char *_get_next_token(char *, int);
+
+
+/*
+ * A call to setnetpath() establishes a NETPATH "session". setnetpath()
+ * must be called before the first call to getnetpath(). A "handle" is
+ * returned to distinguish the session; this handle should be passed
+ * subsequently to getnetpath(). (Handles are used to allow for nested calls
+ * to setnetpath()).
+ * If setnetpath() is unable to establish a session (due to lack of memory
+ * resources, or the absence of the /etc/netconfig file), a NULL pointer is
+ * returned.
+ */
+
+void *
+setnetpath(void)
+{
+
+ struct netpath_vars *np_sessionp; /* this session's variables */
+ char *npp; /* NETPATH env variable */
+
+#ifdef MEM_CHK
+ malloc_debug(1);
+#endif
+
+ if ((np_sessionp =
+ (struct netpath_vars *)malloc(sizeof (struct netpath_vars))) == NULL) {
+ return (NULL);
+ }
+ if ((np_sessionp->nc_handlep = setnetconfig()) == NULL) {
+ syslog (LOG_ERR, "rpc: failed to open " NETCONFIG);
+ goto failed;
+ }
+ np_sessionp->valid = NP_VALID;
+ np_sessionp->ncp_list = NULL;
+ if ((npp = getenv(NETPATH)) == NULL) {
+ np_sessionp->netpath = NULL;
+ } else {
+ (void) endnetconfig(np_sessionp->nc_handlep);/* won't need nc session*/
+ np_sessionp->nc_handlep = NULL;
+ if ((np_sessionp->netpath = malloc(strlen(npp)+1)) == NULL)
+ goto failed;
+ else {
+ (void) strcpy(np_sessionp->netpath, npp);
+ }
+ }
+ np_sessionp->netpath_start = np_sessionp->netpath;
+ return ((void *)np_sessionp);
+
+failed:
+ free(np_sessionp);
+ return (NULL);
+}
+
+/*
+ * When first called, getnetpath() returns a pointer to the netconfig
+ * database entry corresponding to the first valid NETPATH component. The
+ * netconfig entry is formatted as a struct netconfig.
+ * On each subsequent call, getnetpath returns a pointer to the netconfig
+ * entry that corresponds to the next valid NETPATH component. getnetpath
+ * can thus be used to search the netconfig database for all networks
+ * included in the NETPATH variable.
+ * When NETPATH has been exhausted, getnetpath() returns NULL. It returns
+ * NULL and sets errno in case of an error (e.g., setnetpath was not called
+ * previously).
+ * getnetpath() silently ignores invalid NETPATH components. A NETPATH
+ * compnent is invalid if there is no corresponding entry in the netconfig
+ * database.
+ * If the NETPATH variable is unset, getnetpath() behaves as if NETPATH
+ * were set to the sequence of default or visible networks in the netconfig
+ * database, in the order in which they are listed.
+ */
+
+struct netconfig *
+getnetpath(void *handlep)
+{
+ struct netpath_vars *np_sessionp = (struct netpath_vars *)handlep;
+ struct netconfig *ncp = NULL; /* temp. holds a netconfig session */
+ struct netpath_chain *chainp; /* holds chain of ncp's we alloc */
+ char *npp; /* holds current NETPATH */
+
+ if (np_sessionp == NULL || np_sessionp->valid != NP_VALID) {
+ errno = EINVAL;
+ return (NULL);
+ }
+ if (np_sessionp->netpath_start == NULL) { /* NETPATH was not set */
+ do { /* select next visible network */
+ if (np_sessionp->nc_handlep == NULL) {
+ np_sessionp->nc_handlep = setnetconfig();
+ if (np_sessionp->nc_handlep == NULL)
+ syslog (LOG_ERR, "rpc: failed to open " NETCONFIG);
+ }
+ if ((ncp = getnetconfig(np_sessionp->nc_handlep)) == NULL) {
+ return(NULL);
+ }
+ } while ((ncp->nc_flag & NC_VISIBLE) == 0);
+ return (ncp);
+ }
+ /*
+ * Find first valid network ID in netpath.
+ */
+ while ((npp = np_sessionp->netpath) != NULL && strlen(npp) != 0) {
+ np_sessionp->netpath = _get_next_token(npp, ':');
+ /*
+ * npp is a network identifier.
+ */
+ if ((ncp = getnetconfigent(npp)) != NULL) {
+ chainp = (struct netpath_chain *) /* cobble alloc chain entry */
+ malloc(sizeof (struct netpath_chain));
+ chainp->ncp = ncp;
+ chainp->nchain_next = NULL;
+ if (np_sessionp->ncp_list == NULL) {
+ np_sessionp->ncp_list = chainp;
+ } else {
+ np_sessionp->ncp_list->nchain_next = chainp;
+ }
+ return (ncp);
+ }
+ /* couldn't find this token in the database; go to next one. */
+ }
+ return (NULL);
+}
+
+/*
+ * endnetpath() may be called to unbind NETPATH when processing is complete,
+ * releasing resources for reuse. It returns 0 on success and -1 on failure
+ * (e.g. if setnetpath() was not called previously.
+ */
+int
+endnetpath(void *handlep)
+{
+ struct netpath_vars *np_sessionp = (struct netpath_vars *)handlep;
+ struct netpath_chain *chainp, *lastp;
+
+ if (np_sessionp == NULL || np_sessionp->valid != NP_VALID) {
+ errno = EINVAL;
+ return (-1);
+ }
+ if (np_sessionp->nc_handlep != NULL)
+ endnetconfig(np_sessionp->nc_handlep);
+ if (np_sessionp->netpath_start != NULL)
+ free(np_sessionp->netpath_start);
+ for (chainp = np_sessionp->ncp_list; chainp != NULL;
+ lastp=chainp, chainp=chainp->nchain_next, free(lastp)) {
+ freenetconfigent(chainp->ncp);
+ }
+ free(np_sessionp);
+#ifdef MEM_CHK
+ if (malloc_verify() == 0) {
+ fprintf(stderr, "memory heap corrupted in endnetpath\n");
+ exit(1);
+ }
+#endif
+ return (0);
+}
+
+
+
+/*
+ * Returns pointer to the rest-of-the-string after the current token.
+ * The token itself starts at arg, and we null terminate it. We return NULL
+ * if either the arg is empty, or if this is the last token.
+ *
+ * npp - string
+ * token - char to parse string for
+ */
+char *
+_get_next_token(char *npp, int token)
+{
+ char *cp; /* char pointer */
+ char *np; /* netpath pointer */
+ char *ep; /* escape pointer */
+
+ if ((cp = strchr(npp, token)) == NULL) {
+ return (NULL);
+ }
+ /*
+ * did find a token, but it might be escaped.
+ */
+ if ((cp > npp) && (cp[-1] == '\\')) {
+ /* if slash was also escaped, carry on, otherwise find next token */
+ if ((cp > npp + 1) && (cp[-2] != '\\')) {
+ /* shift r-o-s onto the escaped token */
+ strcpy(&cp[-1], cp); /* XXX: overlapping string copy */
+ /*
+ * Do a recursive call.
+ * We don't know how many escaped tokens there might be.
+ */
+ return (_get_next_token(cp, token));
+ }
+ }
+
+ *cp++ = '\0'; /* null-terminate token */
+ /* get rid of any backslash escapes */
+ ep = npp;
+ while ((np = strchr(ep, '\\')) != NULL) {
+ if (np[1] == '\\')
+ np++;
+ strcpy(np, (ep = &np[1])); /* XXX: overlapping string copy */
+ }
+ return (cp); /* return ptr to r-o-s */
+}
diff --git a/lib/libc/rpc/getpublickey.c b/lib/libc/rpc/getpublickey.c
new file mode 100644
index 000000000000..4c806856629b
--- /dev/null
+++ b/lib/libc/rpc/getpublickey.c
@@ -0,0 +1,171 @@
+/*-
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)publickey.c 1.10 91/03/11 Copyr 1986 Sun Micro";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * publickey.c
+ * Copyright (C) 1986, Sun Microsystems, Inc.
+ */
+
+/*
+ * Public key lookup routines
+ */
+#include "namespace.h"
+#include <stdio.h>
+#include <pwd.h>
+#include <rpc/rpc.h>
+#include <rpc/key_prot.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+#include <string.h>
+#include <stdlib.h>
+#include "un-namespace.h"
+
+#define PKFILE "/etc/publickey"
+
+/*
+ * Hack to let ypserv/rpc.nisd use AUTH_DES.
+ */
+int (*__getpublickey_LOCAL)(const char *, char *) = 0;
+
+/*
+ * Get somebody's public key
+ */
+static int
+__getpublickey_real(const char *netname, char *publickey)
+{
+ char lookup[3 * HEXKEYBYTES];
+ char *p;
+
+ if (publickey == NULL)
+ return (0);
+ if (!getpublicandprivatekey(netname, lookup))
+ return (0);
+ p = strchr(lookup, ':');
+ if (p == NULL) {
+ return (0);
+ }
+ *p = '\0';
+ (void) strncpy(publickey, lookup, HEXKEYBYTES);
+ publickey[HEXKEYBYTES] = '\0';
+ return (1);
+}
+
+/*
+ * reads the file /etc/publickey looking for a + to optionally go to the
+ * yellow pages
+ */
+
+int
+getpublicandprivatekey(const char *key, char *ret)
+{
+ char buf[1024]; /* big enough */
+ char *res;
+ FILE *fd;
+ char *mkey;
+ char *mval;
+
+ fd = fopen(PKFILE, "r");
+ if (fd == NULL)
+ return (0);
+ for (;;) {
+ res = fgets(buf, sizeof(buf), fd);
+ if (res == NULL) {
+ fclose(fd);
+ return (0);
+ }
+ if (res[0] == '#')
+ continue;
+ else if (res[0] == '+') {
+#ifdef YP
+ char *PKMAP = "publickey.byname";
+ char *lookup;
+ char *domain;
+ int err;
+ int len;
+
+ err = yp_get_default_domain(&domain);
+ if (err) {
+ continue;
+ }
+ lookup = NULL;
+ err = yp_match(domain, PKMAP, key, strlen(key), &lookup, &len);
+ if (err) {
+#ifdef DEBUG
+ fprintf(stderr, "match failed error %d\n", err);
+#endif
+ continue;
+ }
+ lookup[len] = 0;
+ strcpy(ret, lookup);
+ fclose(fd);
+ free(lookup);
+ return (2);
+#else /* YP */
+#ifdef DEBUG
+ fprintf(stderr,
+"Bad record in %s '+' -- NIS not supported in this library copy\n", PKFILE);
+#endif /* DEBUG */
+ continue;
+#endif /* YP */
+ } else {
+ mkey = strsep(&res, "\t ");
+ if (mkey == NULL) {
+ fprintf(stderr,
+ "Bad record in %s -- %s", PKFILE, buf);
+ continue;
+ }
+ do {
+ mval = strsep(&res, " \t#\n");
+ } while (mval != NULL && !*mval);
+ if (mval == NULL) {
+ fprintf(stderr,
+ "Bad record in %s val problem - %s", PKFILE, buf);
+ continue;
+ }
+ if (strcmp(mkey, key) == 0) {
+ strcpy(ret, mval);
+ fclose(fd);
+ return (1);
+ }
+ }
+ }
+}
+
+int getpublickey(const char *netname, char *publickey)
+{
+ if (__getpublickey_LOCAL != NULL)
+ return(__getpublickey_LOCAL(netname, publickey));
+ else
+ return(__getpublickey_real(netname, publickey));
+}
diff --git a/lib/libc/rpc/getrpcent.3 b/lib/libc/rpc/getrpcent.3
new file mode 100644
index 000000000000..e36d31c4a7ba
--- /dev/null
+++ b/lib/libc/rpc/getrpcent.3
@@ -0,0 +1,109 @@
+.\" @(#)getrpcent.3n 2.2 88/08/02 4.0 RPCSRC; from 1.11 88/03/14 SMI
+.\" $NetBSD: getrpcent.3,v 1.6 1998/02/05 18:49:06 perry Exp $
+.\" $FreeBSD$
+.\"
+.Dd February 26, 2016
+.Dt GETRPCENT 3
+.Os
+.Sh NAME
+.Nm getrpcent ,
+.Nm getrpcbyname ,
+.Nm getrpcbynumber ,
+.Nm endrpcent ,
+.Nm setrpcent
+.Nd get RPC entry
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In rpc/rpc.h
+.Ft struct rpcent *
+.Fn getrpcent void
+.Ft struct rpcent *
+.Fn getrpcbyname "const char *name"
+.Ft struct rpcent *
+.Fn getrpcbynumber "int number"
+.Ft void
+.Fn setrpcent "int stayopen"
+.Ft void
+.Fn endrpcent void
+.Sh DESCRIPTION
+The
+.Fn getrpcent ,
+.Fn getrpcbyname ,
+and
+.Fn getrpcbynumber
+functions
+each return a pointer to an object with the
+following structure
+containing the broken-out
+fields of a line in the rpc program number data base,
+.Pa /etc/rpc :
+.Bd -literal
+struct rpcent {
+ char *r_name; /* name of server for this rpc program */
+ char **r_aliases; /* alias list */
+ long r_number; /* rpc program number */
+};
+.Ed
+.Pp
+The members of this structure are:
+.Bl -tag -width r_aliases -offset indent
+.It Va r_name
+The name of the server for this rpc program.
+.It Va r_aliases
+A zero terminated list of alternate names for the rpc program.
+.It Va r_number
+The rpc program number for this service.
+.El
+.Pp
+The
+.Fn getrpcent
+function
+reads the next line of the file, opening the file if necessary.
+.Pp
+The
+.Fn setrpcent
+function
+opens and rewinds the file.
+If the
+.Fa stayopen
+flag is non-zero,
+the net data base will not be closed after each call to
+.Fn getrpcent
+(either directly, or indirectly through one of
+the other
+.Dq getrpc
+calls).
+.Pp
+The
+.Fn endrpcent
+function
+closes the file.
+.Pp
+The
+.Fn getrpcbyname
+and
+.Fn getrpcbynumber
+functions
+sequentially search from the beginning
+of the file until a matching rpc program name or
+program number is found, or until end-of-file is encountered.
+.Sh FILES
+.Bl -tag -width /etc/rpc -compact
+.It Pa /etc/rpc
+.El
+.Sh DIAGNOSTICS
+A
+.Dv NULL
+pointer is returned on
+.Dv EOF
+or error.
+.Sh SEE ALSO
+.Xr rpc 5 ,
+.Xr rpcinfo 8 ,
+.Xr ypserv 8
+.Sh BUGS
+All information
+is contained in a static area
+so it must be copied if it is
+to be saved.
diff --git a/lib/libc/rpc/getrpcent.c b/lib/libc/rpc/getrpcent.c
new file mode 100644
index 000000000000..e705af831d07
--- /dev/null
+++ b/lib/libc/rpc/getrpcent.c
@@ -0,0 +1,1047 @@
+/* $NetBSD: getrpcent.c,v 1.17 2000/01/22 22:19:17 mycroft Exp $ */
+
+/*-
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *sccsid = "@(#)getrpcent.c 1.14 91/03/11 Copyr 1984 Sun Micro";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Copyright (c) 1984 by Sun Microsystems, Inc.
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <assert.h>
+#include <errno.h>
+#include <nsswitch.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <rpc/rpc.h>
+#ifdef YP
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+#endif
+#include <unistd.h>
+#include "namespace.h"
+#include "reentrant.h"
+#include "un-namespace.h"
+#include "libc_private.h"
+#include "nss_tls.h"
+#ifdef NS_CACHING
+#include "nscache.h"
+#endif
+
+#define RPCDB "/etc/rpc"
+
+/* nsswitch declarations */
+enum constants
+{
+ SETRPCENT = 1,
+ ENDRPCENT = 2,
+ RPCENT_STORAGE_INITIAL = 1 << 10, /* 1 KByte */
+ RPCENT_STORAGE_MAX = 1 << 20, /* 1 MByte */
+};
+
+static const ns_src defaultsrc[] = {
+ { NSSRC_FILES, NS_SUCCESS },
+#ifdef YP
+ { NSSRC_NIS, NS_SUCCESS },
+#endif
+ { NULL, 0 }
+};
+
+/* files backend declarations */
+struct files_state {
+ FILE *fp;
+ int stayopen;
+};
+
+static int files_rpcent(void *, void *, va_list);
+static int files_setrpcent(void *, void *, va_list);
+
+static void files_endstate(void *);
+NSS_TLS_HANDLING(files);
+
+/* nis backend declarations */
+#ifdef YP
+struct nis_state {
+ char domain[MAXHOSTNAMELEN];
+ char *current;
+ int currentlen;
+ int stepping;
+ int no_name_map;
+};
+
+static int nis_rpcent(void *, void *, va_list);
+static int nis_setrpcent(void *, void *, va_list);
+
+static void nis_endstate(void *);
+NSS_TLS_HANDLING(nis);
+#endif
+
+/* get** wrappers for get**_r functions declarations */
+struct rpcent_state {
+ struct rpcent rpc;
+ char *buffer;
+ size_t bufsize;
+};
+static void rpcent_endstate(void *);
+NSS_TLS_HANDLING(rpcent);
+
+union key {
+ const char *name;
+ int number;
+};
+
+static int wrap_getrpcbyname_r(union key, struct rpcent *, char *,
+ size_t, struct rpcent **);
+static int wrap_getrpcbynumber_r(union key, struct rpcent *, char *,
+ size_t, struct rpcent **);
+static int wrap_getrpcent_r(union key, struct rpcent *, char *,
+ size_t, struct rpcent **);
+static struct rpcent *getrpc(int (*fn)(union key, struct rpcent *, char *,
+ size_t, struct rpcent **), union key);
+
+#ifdef NS_CACHING
+static int rpc_id_func(char *, size_t *, va_list, void *);
+static int rpc_marshal_func(char *, size_t *, void *, va_list, void *);
+static int rpc_unmarshal_func(char *, size_t, void *, va_list, void *);
+#endif
+
+static int
+rpcent_unpack(char *p, struct rpcent *rpc, char **r_aliases,
+ size_t aliases_size, int *errnop)
+{
+ char *cp, **q;
+
+ assert(p != NULL);
+
+ if (*p == '#')
+ return (-1);
+ cp = strpbrk(p, "#\n");
+ if (cp == NULL)
+ return (-1);
+ *cp = '\0';
+ cp = strpbrk(p, " \t");
+ if (cp == NULL)
+ return (-1);
+ *cp++ = '\0';
+ /* THIS STUFF IS INTERNET SPECIFIC */
+ rpc->r_name = p;
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ rpc->r_number = atoi(cp);
+ q = rpc->r_aliases = r_aliases;
+ cp = strpbrk(cp, " \t");
+ if (cp != NULL)
+ *cp++ = '\0';
+ while (cp && *cp) {
+ if (*cp == ' ' || *cp == '\t') {
+ cp++;
+ continue;
+ }
+ if (q < &(r_aliases[aliases_size - 1]))
+ *q++ = cp;
+ else {
+ *errnop = ERANGE;
+ return -1;
+ }
+
+ cp = strpbrk(cp, " \t");
+ if (cp != NULL)
+ *cp++ = '\0';
+ }
+ *q = NULL;
+ return 0;
+}
+
+/* files backend implementation */
+static void
+files_endstate(void *p)
+{
+ FILE * f;
+
+ if (p == NULL)
+ return;
+
+ f = ((struct files_state *)p)->fp;
+ if (f != NULL)
+ fclose(f);
+
+ free(p);
+}
+
+static int
+files_rpcent(void *retval, void *mdata, va_list ap)
+{
+ char *name;
+ int number;
+ struct rpcent *rpc;
+ char *buffer;
+ size_t bufsize;
+ int *errnop;
+
+ char *line;
+ size_t linesize;
+ char **aliases;
+ int aliases_size;
+ char **rp;
+
+ struct files_state *st;
+ int rv;
+ int stayopen;
+ enum nss_lookup_type how;
+
+ how = (enum nss_lookup_type)mdata;
+ switch (how)
+ {
+ case nss_lt_name:
+ name = va_arg(ap, char *);
+ break;
+ case nss_lt_id:
+ number = va_arg(ap, int);
+ break;
+ case nss_lt_all:
+ break;
+ default:
+ return (NS_NOTFOUND);
+ }
+
+ rpc = va_arg(ap, struct rpcent *);
+ buffer = va_arg(ap, char *);
+ bufsize = va_arg(ap, size_t);
+ errnop = va_arg(ap, int *);
+
+ *errnop = files_getstate(&st);
+ if (*errnop != 0)
+ return (NS_UNAVAIL);
+
+ if (st->fp == NULL && (st->fp = fopen(RPCDB, "r")) == NULL) {
+ *errnop = errno;
+ return (NS_UNAVAIL);
+ }
+
+ if (how == nss_lt_all)
+ stayopen = 1;
+ else {
+ rewind(st->fp);
+ stayopen = st->stayopen;
+ }
+
+ do {
+ if ((line = fgetln(st->fp, &linesize)) == NULL) {
+ *errnop = errno;
+ rv = NS_RETURN;
+ break;
+ }
+
+ if (bufsize <= linesize + _ALIGNBYTES + sizeof(char *)) {
+ *errnop = ERANGE;
+ rv = NS_RETURN;
+ break;
+ }
+
+ aliases = (char **)_ALIGN(&buffer[linesize+1]);
+ aliases_size = (buffer + bufsize -
+ (char *)aliases)/sizeof(char *);
+ if (aliases_size < 1) {
+ *errnop = ERANGE;
+ rv = NS_RETURN;
+ break;
+ }
+
+ memcpy(buffer, line, linesize);
+ buffer[linesize] = '\0';
+
+ rv = rpcent_unpack(buffer, rpc, aliases, aliases_size, errnop);
+ if (rv != 0) {
+ if (*errnop == 0) {
+ rv = NS_NOTFOUND;
+ continue;
+ }
+ else {
+ rv = NS_RETURN;
+ break;
+ }
+ }
+
+ switch (how)
+ {
+ case nss_lt_name:
+ if (strcmp(rpc->r_name, name) == 0)
+ goto done;
+ for (rp = rpc->r_aliases; *rp != NULL; rp++) {
+ if (strcmp(*rp, name) == 0)
+ goto done;
+ }
+ rv = NS_NOTFOUND;
+ continue;
+done:
+ rv = NS_SUCCESS;
+ break;
+ case nss_lt_id:
+ rv = (rpc->r_number == number) ? NS_SUCCESS :
+ NS_NOTFOUND;
+ break;
+ case nss_lt_all:
+ rv = NS_SUCCESS;
+ break;
+ }
+
+ } while (!(rv & NS_TERMINATE));
+
+ if (!stayopen && st->fp!=NULL) {
+ fclose(st->fp);
+ st->fp = NULL;
+ }
+
+ if ((rv == NS_SUCCESS) && (retval != NULL))
+ *((struct rpcent **)retval) = rpc;
+
+ return (rv);
+}
+
+static int
+files_setrpcent(void *retval, void *mdata, va_list ap)
+{
+ struct files_state *st;
+ int rv;
+ int f;
+
+ rv = files_getstate(&st);
+ if (rv != 0)
+ return (NS_UNAVAIL);
+
+ switch ((enum constants)mdata)
+ {
+ case SETRPCENT:
+ f = va_arg(ap,int);
+ if (st->fp == NULL)
+ st->fp = fopen(RPCDB, "r");
+ else
+ rewind(st->fp);
+ st->stayopen |= f;
+ break;
+ case ENDRPCENT:
+ if (st->fp != NULL) {
+ fclose(st->fp);
+ st->fp = NULL;
+ }
+ st->stayopen = 0;
+ break;
+ default:
+ break;
+ }
+
+ return (NS_UNAVAIL);
+}
+
+/* nis backend implementation */
+#ifdef YP
+static void
+nis_endstate(void *p)
+{
+ if (p == NULL)
+ return;
+
+ free(((struct nis_state *)p)->current);
+ free(p);
+}
+
+static int
+nis_rpcent(void *retval, void *mdata, va_list ap)
+{
+ char *name;
+ int number;
+ struct rpcent *rpc;
+ char *buffer;
+ size_t bufsize;
+ int *errnop;
+
+ char **rp;
+ char **aliases;
+ int aliases_size;
+
+ char *lastkey;
+ char *resultbuf;
+ int resultbuflen;
+ char buf[YPMAXRECORD + 2];
+
+ struct nis_state *st;
+ int rv;
+ enum nss_lookup_type how;
+ int no_name_active;
+
+ how = (enum nss_lookup_type)mdata;
+ switch (how)
+ {
+ case nss_lt_name:
+ name = va_arg(ap, char *);
+ break;
+ case nss_lt_id:
+ number = va_arg(ap, int);
+ break;
+ case nss_lt_all:
+ break;
+ default:
+ return (NS_NOTFOUND);
+ }
+
+ rpc = va_arg(ap, struct rpcent *);
+ buffer = va_arg(ap, char *);
+ bufsize = va_arg(ap, size_t);
+ errnop = va_arg(ap, int *);
+
+ *errnop = nis_getstate(&st);
+ if (*errnop != 0)
+ return (NS_UNAVAIL);
+
+ if (st->domain[0] == '\0') {
+ if (getdomainname(st->domain, sizeof(st->domain)) != 0) {
+ *errnop = errno;
+ return (NS_UNAVAIL);
+ }
+ }
+
+ no_name_active = 0;
+ do {
+ switch (how)
+ {
+ case nss_lt_name:
+ if (!st->no_name_map)
+ {
+ snprintf(buf, sizeof buf, "%s", name);
+ rv = yp_match(st->domain, "rpc.byname", buf,
+ strlen(buf), &resultbuf, &resultbuflen);
+
+ switch (rv) {
+ case 0:
+ break;
+ case YPERR_MAP:
+ st->stepping = 0;
+ no_name_active = 1;
+ how = nss_lt_all;
+
+ rv = NS_NOTFOUND;
+ continue;
+ default:
+ rv = NS_NOTFOUND;
+ goto fin;
+ }
+ } else {
+ st->stepping = 0;
+ no_name_active = 1;
+ how = nss_lt_all;
+
+ rv = NS_NOTFOUND;
+ continue;
+ }
+ break;
+ case nss_lt_id:
+ snprintf(buf, sizeof buf, "%d", number);
+ if (yp_match(st->domain, "rpc.bynumber", buf,
+ strlen(buf), &resultbuf, &resultbuflen)) {
+ rv = NS_NOTFOUND;
+ goto fin;
+ }
+ break;
+ case nss_lt_all:
+ if (!st->stepping) {
+ rv = yp_first(st->domain, "rpc.bynumber",
+ &st->current,
+ &st->currentlen, &resultbuf,
+ &resultbuflen);
+ if (rv) {
+ rv = NS_NOTFOUND;
+ goto fin;
+ }
+ st->stepping = 1;
+ } else {
+ lastkey = st->current;
+ rv = yp_next(st->domain, "rpc.bynumber",
+ st->current,
+ st->currentlen, &st->current,
+ &st->currentlen,
+ &resultbuf, &resultbuflen);
+ free(lastkey);
+ if (rv) {
+ st->stepping = 0;
+ rv = NS_NOTFOUND;
+ goto fin;
+ }
+ }
+ break;
+ }
+
+ /* we need a room for additional \n symbol */
+ if (bufsize <= resultbuflen + 1 + _ALIGNBYTES +
+ sizeof(char *)) {
+ *errnop = ERANGE;
+ rv = NS_RETURN;
+ free(resultbuf);
+ break;
+ }
+
+ aliases=(char **)_ALIGN(&buffer[resultbuflen+2]);
+ aliases_size = (buffer + bufsize - (char *)aliases) /
+ sizeof(char *);
+ if (aliases_size < 1) {
+ *errnop = ERANGE;
+ rv = NS_RETURN;
+ free(resultbuf);
+ break;
+ }
+
+ /*
+ * rpcent_unpack expects lines terminated with \n -- make it happy
+ */
+ memcpy(buffer, resultbuf, resultbuflen);
+ buffer[resultbuflen] = '\n';
+ buffer[resultbuflen+1] = '\0';
+ free(resultbuf);
+
+ if (rpcent_unpack(buffer, rpc, aliases, aliases_size,
+ errnop) != 0) {
+ if (*errnop == 0)
+ rv = NS_NOTFOUND;
+ else
+ rv = NS_RETURN;
+ } else {
+ if ((how == nss_lt_all) && (no_name_active != 0)) {
+ if (strcmp(rpc->r_name, name) == 0)
+ goto done;
+ for (rp = rpc->r_aliases; *rp != NULL; rp++) {
+ if (strcmp(*rp, name) == 0)
+ goto done;
+ }
+ rv = NS_NOTFOUND;
+ continue;
+done:
+ rv = NS_SUCCESS;
+ } else
+ rv = NS_SUCCESS;
+ }
+
+ } while (!(rv & NS_TERMINATE) && (how == nss_lt_all));
+
+fin:
+ if ((rv == NS_SUCCESS) && (retval != NULL))
+ *((struct rpcent **)retval) = rpc;
+
+ return (rv);
+}
+
+static int
+nis_setrpcent(void *retval, void *mdata, va_list ap)
+{
+ struct nis_state *st;
+ int rv;
+
+ rv = nis_getstate(&st);
+ if (rv != 0)
+ return (NS_UNAVAIL);
+
+ switch ((enum constants)mdata)
+ {
+ case SETRPCENT:
+ case ENDRPCENT:
+ free(st->current);
+ st->current = NULL;
+ st->stepping = 0;
+ break;
+ default:
+ break;
+ }
+
+ return (NS_UNAVAIL);
+}
+#endif
+
+#ifdef NS_CACHING
+static int
+rpc_id_func(char *buffer, size_t *buffer_size, va_list ap, void *cache_mdata)
+{
+ char *name;
+ int rpc;
+
+ size_t desired_size, size;
+ enum nss_lookup_type lookup_type;
+ int res = NS_UNAVAIL;
+
+ lookup_type = (enum nss_lookup_type)cache_mdata;
+ switch (lookup_type) {
+ case nss_lt_name:
+ name = va_arg(ap, char *);
+
+ size = strlen(name);
+ desired_size = sizeof(enum nss_lookup_type) + size + 1;
+ if (desired_size > *buffer_size) {
+ res = NS_RETURN;
+ goto fin;
+ }
+
+ memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type));
+ memcpy(buffer + sizeof(enum nss_lookup_type), name, size + 1);
+
+ res = NS_SUCCESS;
+ break;
+ case nss_lt_id:
+ rpc = va_arg(ap, int);
+
+ desired_size = sizeof(enum nss_lookup_type) + sizeof(int);
+ if (desired_size > *buffer_size) {
+ res = NS_RETURN;
+ goto fin;
+ }
+
+ memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type));
+ memcpy(buffer + sizeof(enum nss_lookup_type), &rpc,
+ sizeof(int));
+
+ res = NS_SUCCESS;
+ break;
+ default:
+ /* should be unreachable */
+ return (NS_UNAVAIL);
+ }
+
+fin:
+ *buffer_size = desired_size;
+ return (res);
+}
+
+static int
+rpc_marshal_func(char *buffer, size_t *buffer_size, void *retval, va_list ap,
+ void *cache_mdata)
+{
+ char *name;
+ int num;
+ struct rpcent *rpc;
+ char *orig_buf;
+ size_t orig_buf_size;
+
+ struct rpcent new_rpc;
+ size_t desired_size, size, aliases_size;
+ char *p;
+ char **alias;
+
+ switch ((enum nss_lookup_type)cache_mdata) {
+ case nss_lt_name:
+ name = va_arg(ap, char *);
+ break;
+ case nss_lt_id:
+ num = va_arg(ap, int);
+ break;
+ case nss_lt_all:
+ break;
+ default:
+ /* should be unreachable */
+ return (NS_UNAVAIL);
+ }
+
+ rpc = va_arg(ap, struct rpcent *);
+ orig_buf = va_arg(ap, char *);
+ orig_buf_size = va_arg(ap, size_t);
+
+ desired_size = _ALIGNBYTES + sizeof(struct rpcent) + sizeof(char *);
+ if (rpc->r_name != NULL)
+ desired_size += strlen(rpc->r_name) + 1;
+
+ if (rpc->r_aliases != NULL) {
+ aliases_size = 0;
+ for (alias = rpc->r_aliases; *alias; ++alias) {
+ desired_size += strlen(*alias) + 1;
+ ++aliases_size;
+ }
+
+ desired_size += _ALIGNBYTES + (aliases_size + 1) *
+ sizeof(char *);
+ }
+
+ if (*buffer_size < desired_size) {
+ /* this assignment is here for future use */
+ *buffer_size = desired_size;
+ return (NS_RETURN);
+ }
+
+ new_rpc = *rpc;
+
+ *buffer_size = desired_size;
+ memset(buffer, 0, desired_size);
+ p = buffer + sizeof(struct rpcent) + sizeof(char *);
+ memcpy(buffer + sizeof(struct rpcent), &p, sizeof(char *));
+ p = (char *)_ALIGN(p);
+
+ if (new_rpc.r_name != NULL) {
+ size = strlen(new_rpc.r_name);
+ memcpy(p, new_rpc.r_name, size);
+ new_rpc.r_name = p;
+ p += size + 1;
+ }
+
+ if (new_rpc.r_aliases != NULL) {
+ p = (char *)_ALIGN(p);
+ memcpy(p, new_rpc.r_aliases, sizeof(char *) * aliases_size);
+ new_rpc.r_aliases = (char **)p;
+ p += sizeof(char *) * (aliases_size + 1);
+
+ for (alias = new_rpc.r_aliases; *alias; ++alias) {
+ size = strlen(*alias);
+ memcpy(p, *alias, size);
+ *alias = p;
+ p += size + 1;
+ }
+ }
+
+ memcpy(buffer, &new_rpc, sizeof(struct rpcent));
+ return (NS_SUCCESS);
+}
+
+static int
+rpc_unmarshal_func(char *buffer, size_t buffer_size, void *retval, va_list ap,
+ void *cache_mdata)
+{
+ char *name;
+ int num;
+ struct rpcent *rpc;
+ char *orig_buf;
+ size_t orig_buf_size;
+ int *ret_errno;
+
+ char *p;
+ char **alias;
+
+ switch ((enum nss_lookup_type)cache_mdata) {
+ case nss_lt_name:
+ name = va_arg(ap, char *);
+ break;
+ case nss_lt_id:
+ num = va_arg(ap, int);
+ break;
+ case nss_lt_all:
+ break;
+ default:
+ /* should be unreachable */
+ return (NS_UNAVAIL);
+ }
+
+ rpc = va_arg(ap, struct rpcent *);
+ orig_buf = va_arg(ap, char *);
+ orig_buf_size = va_arg(ap, size_t);
+ ret_errno = va_arg(ap, int *);
+
+ if (orig_buf_size <
+ buffer_size - sizeof(struct rpcent) - sizeof(char *)) {
+ *ret_errno = ERANGE;
+ return (NS_RETURN);
+ }
+
+ memcpy(rpc, buffer, sizeof(struct rpcent));
+ memcpy(&p, buffer + sizeof(struct rpcent), sizeof(char *));
+
+ orig_buf = (char *)_ALIGN(orig_buf);
+ memcpy(orig_buf, buffer + sizeof(struct rpcent) + sizeof(char *) +
+ _ALIGN(p) - (size_t)p,
+ buffer_size - sizeof(struct rpcent) - sizeof(char *) -
+ _ALIGN(p) + (size_t)p);
+ p = (char *)_ALIGN(p);
+
+ NS_APPLY_OFFSET(rpc->r_name, orig_buf, p, char *);
+ if (rpc->r_aliases != NULL) {
+ NS_APPLY_OFFSET(rpc->r_aliases, orig_buf, p, char **);
+
+ for (alias = rpc->r_aliases ; *alias; ++alias)
+ NS_APPLY_OFFSET(*alias, orig_buf, p, char *);
+ }
+
+ if (retval != NULL)
+ *((struct rpcent **)retval) = rpc;
+
+ return (NS_SUCCESS);
+}
+
+NSS_MP_CACHE_HANDLING(rpc);
+#endif /* NS_CACHING */
+
+
+/* get**_r functions implementation */
+static int
+getrpcbyname_r(const char *name, struct rpcent *rpc, char *buffer,
+ size_t bufsize, struct rpcent **result)
+{
+#ifdef NS_CACHING
+ static const nss_cache_info cache_info =
+ NS_COMMON_CACHE_INFO_INITIALIZER(
+ rpc, (void *)nss_lt_name,
+ rpc_id_func, rpc_marshal_func, rpc_unmarshal_func);
+#endif
+ static const ns_dtab dtab[] = {
+ { NSSRC_FILES, files_rpcent, (void *)nss_lt_name },
+#ifdef YP
+ { NSSRC_NIS, nis_rpcent, (void *)nss_lt_name },
+#endif
+#ifdef NS_CACHING
+ NS_CACHE_CB(&cache_info)
+#endif
+ { NULL, NULL, NULL }
+ };
+ int rv, ret_errno;
+
+ ret_errno = 0;
+ *result = NULL;
+ rv = nsdispatch(result, dtab, NSDB_RPC, "getrpcbyname_r", defaultsrc,
+ name, rpc, buffer, bufsize, &ret_errno);
+
+ if (rv == NS_SUCCESS)
+ return (0);
+ else
+ return (ret_errno);
+}
+
+static int
+getrpcbynumber_r(int number, struct rpcent *rpc, char *buffer,
+ size_t bufsize, struct rpcent **result)
+{
+#ifdef NS_CACHING
+ static const nss_cache_info cache_info =
+ NS_COMMON_CACHE_INFO_INITIALIZER(
+ rpc, (void *)nss_lt_id,
+ rpc_id_func, rpc_marshal_func, rpc_unmarshal_func);
+#endif
+ static const ns_dtab dtab[] = {
+ { NSSRC_FILES, files_rpcent, (void *)nss_lt_id },
+#ifdef YP
+ { NSSRC_NIS, nis_rpcent, (void *)nss_lt_id },
+#endif
+#ifdef NS_CACHING
+ NS_CACHE_CB(&cache_info)
+#endif
+ { NULL, NULL, NULL }
+ };
+ int rv, ret_errno;
+
+ ret_errno = 0;
+ *result = NULL;
+ rv = nsdispatch(result, dtab, NSDB_RPC, "getrpcbynumber_r", defaultsrc,
+ number, rpc, buffer, bufsize, &ret_errno);
+
+ if (rv == NS_SUCCESS)
+ return (0);
+ else
+ return (ret_errno);
+}
+
+static int
+getrpcent_r(struct rpcent *rpc, char *buffer, size_t bufsize,
+ struct rpcent **result)
+{
+#ifdef NS_CACHING
+ static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
+ rpc, (void *)nss_lt_all,
+ rpc_marshal_func, rpc_unmarshal_func);
+#endif
+ static const ns_dtab dtab[] = {
+ { NSSRC_FILES, files_rpcent, (void *)nss_lt_all },
+#ifdef YP
+ { NSSRC_NIS, nis_rpcent, (void *)nss_lt_all },
+#endif
+#ifdef NS_CACHING
+ NS_CACHE_CB(&cache_info)
+#endif
+ { NULL, NULL, NULL }
+ };
+ int rv, ret_errno;
+
+ ret_errno = 0;
+ *result = NULL;
+ rv = nsdispatch(result, dtab, NSDB_RPC, "getrpcent_r", defaultsrc,
+ rpc, buffer, bufsize, &ret_errno);
+
+ if (rv == NS_SUCCESS)
+ return (0);
+ else
+ return (ret_errno);
+}
+
+/* get** wrappers for get**_r functions implementation */
+static void
+rpcent_endstate(void *p)
+{
+ if (p == NULL)
+ return;
+
+ free(((struct rpcent_state *)p)->buffer);
+ free(p);
+}
+
+static int
+wrap_getrpcbyname_r(union key key, struct rpcent *rpc, char *buffer,
+ size_t bufsize, struct rpcent **res)
+{
+ return (getrpcbyname_r(key.name, rpc, buffer, bufsize, res));
+}
+
+static int
+wrap_getrpcbynumber_r(union key key, struct rpcent *rpc, char *buffer,
+ size_t bufsize, struct rpcent **res)
+{
+ return (getrpcbynumber_r(key.number, rpc, buffer, bufsize, res));
+}
+
+static int
+wrap_getrpcent_r(union key key __unused, struct rpcent *rpc, char *buffer,
+ size_t bufsize, struct rpcent **res)
+{
+ return (getrpcent_r(rpc, buffer, bufsize, res));
+}
+
+static struct rpcent *
+getrpc(int (*fn)(union key, struct rpcent *, char *, size_t, struct rpcent **),
+ union key key)
+{
+ int rv;
+ struct rpcent *res;
+ struct rpcent_state * st;
+
+ rv=rpcent_getstate(&st);
+ if (rv != 0) {
+ errno = rv;
+ return NULL;
+ }
+
+ if (st->buffer == NULL) {
+ st->buffer = malloc(RPCENT_STORAGE_INITIAL);
+ if (st->buffer == NULL)
+ return (NULL);
+ st->bufsize = RPCENT_STORAGE_INITIAL;
+ }
+ do {
+ rv = fn(key, &st->rpc, st->buffer, st->bufsize, &res);
+ if (res == NULL && rv == ERANGE) {
+ free(st->buffer);
+ if ((st->bufsize << 1) > RPCENT_STORAGE_MAX) {
+ st->buffer = NULL;
+ errno = ERANGE;
+ return (NULL);
+ }
+ st->bufsize <<= 1;
+ st->buffer = malloc(st->bufsize);
+ if (st->buffer == NULL)
+ return (NULL);
+ }
+ } while (res == NULL && rv == ERANGE);
+ if (rv != 0)
+ errno = rv;
+
+ return (res);
+}
+
+struct rpcent *
+getrpcbyname(const char *name)
+{
+ union key key;
+
+ key.name = name;
+
+ return (getrpc(wrap_getrpcbyname_r, key));
+}
+
+struct rpcent *
+getrpcbynumber(int number)
+{
+ union key key;
+
+ key.number = number;
+
+ return (getrpc(wrap_getrpcbynumber_r, key));
+}
+
+struct rpcent *
+getrpcent(void)
+{
+ union key key;
+
+ key.number = 0; /* not used */
+
+ return (getrpc(wrap_getrpcent_r, key));
+}
+
+void
+setrpcent(int stayopen)
+{
+#ifdef NS_CACHING
+ static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
+ rpc, (void *)nss_lt_all,
+ NULL, NULL);
+#endif
+
+ static const ns_dtab dtab[] = {
+ { NSSRC_FILES, files_setrpcent, (void *)SETRPCENT },
+#ifdef YP
+ { NSSRC_NIS, nis_setrpcent, (void *)SETRPCENT },
+#endif
+#ifdef NS_CACHING
+ NS_CACHE_CB(&cache_info)
+#endif
+ { NULL, NULL, NULL }
+ };
+
+ (void)nsdispatch(NULL, dtab, NSDB_RPC, "setrpcent", defaultsrc,
+ stayopen);
+}
+
+void
+endrpcent(void)
+{
+#ifdef NS_CACHING
+ static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
+ rpc, (void *)nss_lt_all,
+ NULL, NULL);
+#endif
+
+ static const ns_dtab dtab[] = {
+ { NSSRC_FILES, files_setrpcent, (void *)ENDRPCENT },
+#ifdef YP
+ { NSSRC_NIS, nis_setrpcent, (void *)ENDRPCENT },
+#endif
+#ifdef NS_CACHING
+ NS_CACHE_CB(&cache_info)
+#endif
+ { NULL, NULL, NULL }
+ };
+
+ (void)nsdispatch(NULL, dtab, NSDB_RPC, "endrpcent", defaultsrc);
+}
diff --git a/lib/libc/rpc/getrpcport.3 b/lib/libc/rpc/getrpcport.3
new file mode 100644
index 000000000000..6e1f199e7b3c
--- /dev/null
+++ b/lib/libc/rpc/getrpcport.3
@@ -0,0 +1,36 @@
+.\" @(#)getrpcport.3r 2.2 88/08/02 4.0 RPCSRC; from 1.12 88/02/26 SMI
+.\" $FreeBSD$
+.\"
+.Dd October 6, 1987
+.Dt GETRPCPORT 3
+.Os
+.Sh NAME
+.Nm getrpcport
+.Nd get RPC port number
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.Ft int
+.Fn getrpcport "char *host" "int prognum" "int versnum" "int proto"
+.Sh DESCRIPTION
+The
+.Fn getrpcport
+function
+returns the port number for version
+.Fa versnum
+of the RPC program
+.Fa prognum
+running on
+.Fa host
+and using protocol
+.Fa proto .
+It returns 0 if it cannot contact the portmapper, or if
+.Fa prognum
+is not registered.
+If
+.Fa prognum
+is registered but not with version
+.Fa versnum ,
+it will still return a port number (for some version of the program)
+indicating that the program is indeed registered.
+The version mismatch will be detected upon the first call to the service.
diff --git a/lib/libc/rpc/getrpcport.c b/lib/libc/rpc/getrpcport.c
new file mode 100644
index 000000000000..b365678a7ace
--- /dev/null
+++ b/lib/libc/rpc/getrpcport.c
@@ -0,0 +1,75 @@
+/* $NetBSD: getrpcport.c,v 1.16 2000/01/22 22:19:18 mycroft Exp $ */
+
+/*-
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *sccsid2 = "@(#)getrpcport.c 1.3 87/08/11 SMI";
+static char *sccsid = "@(#)getrpcport.c 2.1 88/07/29 4.0 RPCSRC";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Copyright (c) 1985 by Sun Microsystems, Inc.
+ */
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <assert.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <rpc/rpc.h>
+#include <rpc/pmap_clnt.h>
+#include "un-namespace.h"
+
+int
+getrpcport(char *host, int prognum, int versnum, int proto)
+{
+ struct sockaddr_in addr;
+ struct hostent *hp;
+
+ assert(host != NULL);
+
+ if ((hp = gethostbyname(host)) == NULL)
+ return (0);
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_len = sizeof(struct sockaddr_in);
+ addr.sin_family = AF_INET;
+ addr.sin_port = 0;
+ if (hp->h_length > addr.sin_len)
+ hp->h_length = addr.sin_len;
+ memcpy(&addr.sin_addr.s_addr, hp->h_addr, (size_t)hp->h_length);
+ /* Inconsistent interfaces need casts! :-( */
+ return (pmap_getport(&addr, (u_long)prognum, (u_long)versnum,
+ (u_int)proto));
+}
diff --git a/lib/libc/rpc/key_call.c b/lib/libc/rpc/key_call.c
new file mode 100644
index 000000000000..b9bc77a7fd49
--- /dev/null
+++ b/lib/libc/rpc/key_call.c
@@ -0,0 +1,459 @@
+/*-
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 1986-1991 by Sun Microsystems Inc.
+ */
+
+#ident "@(#)key_call.c 1.25 94/04/24 SMI"
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * key_call.c, Interface to keyserver
+ *
+ * setsecretkey(key) - set your secret key
+ * encryptsessionkey(agent, deskey) - encrypt a session key to talk to agent
+ * decryptsessionkey(agent, deskey) - decrypt ditto
+ * gendeskey(deskey) - generate a secure des key
+ */
+
+#include "namespace.h"
+#include "reentrant.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <rpc/rpc.h>
+#include <rpc/auth.h>
+#include <rpc/auth_unix.h>
+#include <rpc/key_prot.h>
+#include <string.h>
+#include <netconfig.h>
+#include <sys/utsname.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <sys/fcntl.h>
+#include "un-namespace.h"
+#include "mt_misc.h"
+
+
+#define KEY_TIMEOUT 5 /* per-try timeout in seconds */
+#define KEY_NRETRY 12 /* number of retries */
+
+#ifdef DEBUG
+#define debug(msg) (void) fprintf(stderr, "%s\n", msg);
+#else
+#define debug(msg)
+#endif /* DEBUG */
+
+/*
+ * Hack to allow the keyserver to use AUTH_DES (for authenticated
+ * NIS+ calls, for example). The only functions that get called
+ * are key_encryptsession_pk, key_decryptsession_pk, and key_gendes.
+ *
+ * The approach is to have the keyserver fill in pointers to local
+ * implementations of these functions, and to call those in key_call().
+ */
+
+cryptkeyres *(*__key_encryptsession_pk_LOCAL)(uid_t, void *arg) = 0;
+cryptkeyres *(*__key_decryptsession_pk_LOCAL)(uid_t, void *arg) = 0;
+des_block *(*__key_gendes_LOCAL)(uid_t, void *) = 0;
+
+static int key_call( u_long, xdrproc_t, void *, xdrproc_t, void *);
+
+int
+key_setsecret(const char *secretkey)
+{
+ keystatus status;
+
+ if (!key_call((u_long) KEY_SET, (xdrproc_t)xdr_keybuf,
+ (void *)secretkey,
+ (xdrproc_t)xdr_keystatus, &status)) {
+ return (-1);
+ }
+ if (status != KEY_SUCCESS) {
+ debug("set status is nonzero");
+ return (-1);
+ }
+ return (0);
+}
+
+
+/* key_secretkey_is_set() returns 1 if the keyserver has a secret key
+ * stored for the caller's effective uid; it returns 0 otherwise
+ *
+ * N.B.: The KEY_NET_GET key call is undocumented. Applications shouldn't
+ * be using it, because it allows them to get the user's secret key.
+ */
+
+int
+key_secretkey_is_set(void)
+{
+ struct key_netstres kres;
+
+ memset((void*)&kres, 0, sizeof (kres));
+ if (key_call((u_long) KEY_NET_GET, (xdrproc_t)xdr_void, NULL,
+ (xdrproc_t)xdr_key_netstres, &kres) &&
+ (kres.status == KEY_SUCCESS) &&
+ (kres.key_netstres_u.knet.st_priv_key[0] != 0)) {
+ /* avoid leaving secret key in memory */
+ memset(kres.key_netstres_u.knet.st_priv_key, 0, HEXKEYBYTES);
+ return (1);
+ }
+ return (0);
+}
+
+int
+key_encryptsession_pk(char *remotename, netobj *remotekey, des_block *deskey)
+{
+ cryptkeyarg2 arg;
+ cryptkeyres res;
+
+ arg.remotename = remotename;
+ arg.remotekey = *remotekey;
+ arg.deskey = *deskey;
+ if (!key_call((u_long)KEY_ENCRYPT_PK, (xdrproc_t)xdr_cryptkeyarg2, &arg,
+ (xdrproc_t)xdr_cryptkeyres, &res)) {
+ return (-1);
+ }
+ if (res.status != KEY_SUCCESS) {
+ debug("encrypt status is nonzero");
+ return (-1);
+ }
+ *deskey = res.cryptkeyres_u.deskey;
+ return (0);
+}
+
+int
+key_decryptsession_pk(char *remotename, netobj *remotekey, des_block *deskey)
+{
+ cryptkeyarg2 arg;
+ cryptkeyres res;
+
+ arg.remotename = remotename;
+ arg.remotekey = *remotekey;
+ arg.deskey = *deskey;
+ if (!key_call((u_long)KEY_DECRYPT_PK, (xdrproc_t)xdr_cryptkeyarg2, &arg,
+ (xdrproc_t)xdr_cryptkeyres, &res)) {
+ return (-1);
+ }
+ if (res.status != KEY_SUCCESS) {
+ debug("decrypt status is nonzero");
+ return (-1);
+ }
+ *deskey = res.cryptkeyres_u.deskey;
+ return (0);
+}
+
+int
+key_encryptsession(const char *remotename, des_block *deskey)
+{
+ cryptkeyarg arg;
+ cryptkeyres res;
+
+ arg.remotename = (char *) remotename;
+ arg.deskey = *deskey;
+ if (!key_call((u_long)KEY_ENCRYPT, (xdrproc_t)xdr_cryptkeyarg, &arg,
+ (xdrproc_t)xdr_cryptkeyres, &res)) {
+ return (-1);
+ }
+ if (res.status != KEY_SUCCESS) {
+ debug("encrypt status is nonzero");
+ return (-1);
+ }
+ *deskey = res.cryptkeyres_u.deskey;
+ return (0);
+}
+
+int
+key_decryptsession(const char *remotename, des_block *deskey)
+{
+ cryptkeyarg arg;
+ cryptkeyres res;
+
+ arg.remotename = (char *) remotename;
+ arg.deskey = *deskey;
+ if (!key_call((u_long)KEY_DECRYPT, (xdrproc_t)xdr_cryptkeyarg, &arg,
+ (xdrproc_t)xdr_cryptkeyres, &res)) {
+ return (-1);
+ }
+ if (res.status != KEY_SUCCESS) {
+ debug("decrypt status is nonzero");
+ return (-1);
+ }
+ *deskey = res.cryptkeyres_u.deskey;
+ return (0);
+}
+
+int
+key_gendes(des_block *key)
+{
+ if (!key_call((u_long)KEY_GEN, (xdrproc_t)xdr_void, NULL,
+ (xdrproc_t)xdr_des_block, key)) {
+ return (-1);
+ }
+ return (0);
+}
+
+int
+key_setnet(struct key_netstarg *arg)
+{
+ keystatus status;
+
+
+ if (!key_call((u_long) KEY_NET_PUT, (xdrproc_t)xdr_key_netstarg, arg,
+ (xdrproc_t)xdr_keystatus, &status)){
+ return (-1);
+ }
+
+ if (status != KEY_SUCCESS) {
+ debug("key_setnet status is nonzero");
+ return (-1);
+ }
+ return (1);
+}
+
+
+int
+key_get_conv(char *pkey, des_block *deskey)
+{
+ cryptkeyres res;
+
+ if (!key_call((u_long) KEY_GET_CONV, (xdrproc_t)xdr_keybuf, pkey,
+ (xdrproc_t)xdr_cryptkeyres, &res)) {
+ return (-1);
+ }
+ if (res.status != KEY_SUCCESS) {
+ debug("get_conv status is nonzero");
+ return (-1);
+ }
+ *deskey = res.cryptkeyres_u.deskey;
+ return (0);
+}
+
+struct key_call_private {
+ CLIENT *client; /* Client handle */
+ pid_t pid; /* process-id at moment of creation */
+ uid_t uid; /* user-id at last authorization */
+};
+static struct key_call_private *key_call_private_main = NULL;
+static thread_key_t key_call_key;
+static once_t key_call_once = ONCE_INITIALIZER;
+static int key_call_key_error;
+
+static void
+key_call_destroy(void *vp)
+{
+ struct key_call_private *kcp = (struct key_call_private *)vp;
+
+ if (kcp) {
+ if (kcp->client)
+ clnt_destroy(kcp->client);
+ free(kcp);
+ }
+}
+
+static void
+key_call_init(void)
+{
+
+ key_call_key_error = thr_keycreate(&key_call_key, key_call_destroy);
+}
+
+/*
+ * Keep the handle cached. This call may be made quite often.
+ */
+static CLIENT *
+getkeyserv_handle(int vers)
+{
+ void *localhandle;
+ struct netconfig *nconf;
+ struct netconfig *tpconf;
+ struct key_call_private *kcp;
+ struct timeval wait_time;
+ struct utsname u;
+ int main_thread;
+ int fd;
+
+#define TOTAL_TIMEOUT 30 /* total timeout talking to keyserver */
+#define TOTAL_TRIES 5 /* Number of tries */
+
+ if ((main_thread = thr_main())) {
+ kcp = key_call_private_main;
+ } else {
+ if (thr_once(&key_call_once, key_call_init) != 0 ||
+ key_call_key_error != 0)
+ return ((CLIENT *) NULL);
+ kcp = (struct key_call_private *)thr_getspecific(key_call_key);
+ }
+ if (kcp == (struct key_call_private *)NULL) {
+ kcp = (struct key_call_private *)malloc(sizeof (*kcp));
+ if (kcp == (struct key_call_private *)NULL) {
+ return ((CLIENT *) NULL);
+ }
+ if (main_thread)
+ key_call_private_main = kcp;
+ else
+ thr_setspecific(key_call_key, (void *) kcp);
+ kcp->client = NULL;
+ }
+
+ /* if pid has changed, destroy client and rebuild */
+ if (kcp->client != NULL && kcp->pid != getpid()) {
+ clnt_destroy(kcp->client);
+ kcp->client = NULL;
+ }
+
+ if (kcp->client != NULL) {
+ /* if uid has changed, build client handle again */
+ if (kcp->uid != geteuid()) {
+ kcp->uid = geteuid();
+ auth_destroy(kcp->client->cl_auth);
+ kcp->client->cl_auth =
+ authsys_create("", kcp->uid, 0, 0, NULL);
+ if (kcp->client->cl_auth == NULL) {
+ clnt_destroy(kcp->client);
+ kcp->client = NULL;
+ return ((CLIENT *) NULL);
+ }
+ }
+ /* Change the version number to the new one */
+ clnt_control(kcp->client, CLSET_VERS, (void *)&vers);
+ return (kcp->client);
+ }
+ if (!(localhandle = setnetconfig())) {
+ return ((CLIENT *) NULL);
+ }
+ tpconf = NULL;
+#if defined(__FreeBSD__)
+ if (uname(&u) == -1)
+#else
+#if defined(i386)
+ if (_nuname(&u) == -1)
+#elif defined(sparc)
+ if (_uname(&u) == -1)
+#else
+#error Unknown architecture!
+#endif
+#endif
+ {
+ endnetconfig(localhandle);
+ return ((CLIENT *) NULL);
+ }
+ while ((nconf = getnetconfig(localhandle)) != NULL) {
+ if (strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) {
+ /*
+ * We use COTS_ORD here so that the caller can
+ * find out immediately if the server is dead.
+ */
+ if (nconf->nc_semantics == NC_TPI_COTS_ORD) {
+ kcp->client = clnt_tp_create(u.nodename,
+ KEY_PROG, vers, nconf);
+ if (kcp->client)
+ break;
+ } else {
+ tpconf = nconf;
+ }
+ }
+ }
+ if ((kcp->client == (CLIENT *) NULL) && (tpconf))
+ /* Now, try the CLTS or COTS loopback transport */
+ kcp->client = clnt_tp_create(u.nodename,
+ KEY_PROG, vers, tpconf);
+ endnetconfig(localhandle);
+
+ if (kcp->client == (CLIENT *) NULL) {
+ return ((CLIENT *) NULL);
+ }
+ kcp->uid = geteuid();
+ kcp->pid = getpid();
+ kcp->client->cl_auth = authsys_create("", kcp->uid, 0, 0, NULL);
+ if (kcp->client->cl_auth == NULL) {
+ clnt_destroy(kcp->client);
+ kcp->client = NULL;
+ return ((CLIENT *) NULL);
+ }
+
+ wait_time.tv_sec = TOTAL_TIMEOUT/TOTAL_TRIES;
+ wait_time.tv_usec = 0;
+ (void) clnt_control(kcp->client, CLSET_RETRY_TIMEOUT,
+ (char *)&wait_time);
+ if (clnt_control(kcp->client, CLGET_FD, (char *)&fd))
+ _fcntl(fd, F_SETFD, 1); /* make it "close on exec" */
+
+ return (kcp->client);
+}
+
+/* returns 0 on failure, 1 on success */
+
+static int
+key_call(u_long proc, xdrproc_t xdr_arg, void *arg, xdrproc_t xdr_rslt,
+ void *rslt)
+{
+ CLIENT *clnt;
+ struct timeval wait_time;
+
+ if (proc == KEY_ENCRYPT_PK && __key_encryptsession_pk_LOCAL) {
+ cryptkeyres *res;
+ res = (*__key_encryptsession_pk_LOCAL)(geteuid(), arg);
+ *(cryptkeyres*)rslt = *res;
+ return (1);
+ } else if (proc == KEY_DECRYPT_PK && __key_decryptsession_pk_LOCAL) {
+ cryptkeyres *res;
+ res = (*__key_decryptsession_pk_LOCAL)(geteuid(), arg);
+ *(cryptkeyres*)rslt = *res;
+ return (1);
+ } else if (proc == KEY_GEN && __key_gendes_LOCAL) {
+ des_block *res;
+ res = (*__key_gendes_LOCAL)(geteuid(), 0);
+ *(des_block*)rslt = *res;
+ return (1);
+ }
+
+ if ((proc == KEY_ENCRYPT_PK) || (proc == KEY_DECRYPT_PK) ||
+ (proc == KEY_NET_GET) || (proc == KEY_NET_PUT) ||
+ (proc == KEY_GET_CONV))
+ clnt = getkeyserv_handle(2); /* talk to version 2 */
+ else
+ clnt = getkeyserv_handle(1); /* talk to version 1 */
+
+ if (clnt == NULL) {
+ return (0);
+ }
+
+ wait_time.tv_sec = TOTAL_TIMEOUT;
+ wait_time.tv_usec = 0;
+
+ if (clnt_call(clnt, proc, xdr_arg, arg, xdr_rslt, rslt,
+ wait_time) == RPC_SUCCESS) {
+ return (1);
+ } else {
+ return (0);
+ }
+}
diff --git a/lib/libc/rpc/key_prot_xdr.c b/lib/libc/rpc/key_prot_xdr.c
new file mode 100644
index 000000000000..19a2f6c188d5
--- /dev/null
+++ b/lib/libc/rpc/key_prot_xdr.c
@@ -0,0 +1,177 @@
+/*
+ * Please do not edit this file.
+ * It was generated using rpcgen.
+ */
+
+#include "namespace.h"
+#include <rpc/key_prot.h>
+#include "un-namespace.h"
+/*-
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/* Copyright (c) 1990, 1991 Sun Microsystems, Inc. */
+
+/* #pragma ident "@(#)key_prot.x 1.7 94/04/29 SMI" */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Compiled from key_prot.x using rpcgen.
+ * DO NOT EDIT THIS FILE!
+ * This is NOT source code!
+ */
+
+bool_t
+xdr_keystatus(register XDR *xdrs, keystatus *objp)
+{
+
+ if (!xdr_enum(xdrs, (enum_t *)objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_keybuf(register XDR *xdrs, keybuf objp)
+{
+
+ if (!xdr_opaque(xdrs, objp, HEXKEYBYTES))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_netnamestr(register XDR *xdrs, netnamestr *objp)
+{
+
+ if (!xdr_string(xdrs, objp, MAXNETNAMELEN))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_cryptkeyarg(register XDR *xdrs, cryptkeyarg *objp)
+{
+
+ if (!xdr_netnamestr(xdrs, &objp->remotename))
+ return (FALSE);
+ if (!xdr_des_block(xdrs, &objp->deskey))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_cryptkeyarg2(register XDR *xdrs, cryptkeyarg2 *objp)
+{
+
+ if (!xdr_netnamestr(xdrs, &objp->remotename))
+ return (FALSE);
+ if (!xdr_netobj(xdrs, &objp->remotekey))
+ return (FALSE);
+ if (!xdr_des_block(xdrs, &objp->deskey))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_cryptkeyres(register XDR *xdrs, cryptkeyres *objp)
+{
+
+ if (!xdr_keystatus(xdrs, &objp->status))
+ return (FALSE);
+ switch (objp->status) {
+ case KEY_SUCCESS:
+ if (!xdr_des_block(xdrs, &objp->cryptkeyres_u.deskey))
+ return (FALSE);
+ break;
+ default:
+ break;
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_unixcred(register XDR *xdrs, unixcred *objp)
+{
+ u_int **pgids_val;
+
+ if (!xdr_u_int(xdrs, &objp->uid))
+ return (FALSE);
+ if (!xdr_u_int(xdrs, &objp->gid))
+ return (FALSE);
+ pgids_val = &objp->gids.gids_val;
+ if (!xdr_array(xdrs, (char **) pgids_val, (u_int *) &objp->gids.gids_len, MAXGIDS,
+ sizeof (u_int), (xdrproc_t) xdr_u_int))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_getcredres(register XDR *xdrs, getcredres *objp)
+{
+
+ if (!xdr_keystatus(xdrs, &objp->status))
+ return (FALSE);
+ switch (objp->status) {
+ case KEY_SUCCESS:
+ if (!xdr_unixcred(xdrs, &objp->getcredres_u.cred))
+ return (FALSE);
+ break;
+ default:
+ break;
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_key_netstarg(register XDR *xdrs, key_netstarg *objp)
+{
+
+ if (!xdr_keybuf(xdrs, objp->st_priv_key))
+ return (FALSE);
+ if (!xdr_keybuf(xdrs, objp->st_pub_key))
+ return (FALSE);
+ if (!xdr_netnamestr(xdrs, &objp->st_netname))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_key_netstres(register XDR *xdrs, key_netstres *objp)
+{
+
+ if (!xdr_keystatus(xdrs, &objp->status))
+ return (FALSE);
+ switch (objp->status) {
+ case KEY_SUCCESS:
+ if (!xdr_key_netstarg(xdrs, &objp->key_netstres_u.knet))
+ return (FALSE);
+ break;
+ default:
+ break;
+ }
+ return (TRUE);
+}
diff --git a/lib/libc/rpc/mt_misc.c b/lib/libc/rpc/mt_misc.c
new file mode 100644
index 000000000000..a1b8057bef80
--- /dev/null
+++ b/lib/libc/rpc/mt_misc.c
@@ -0,0 +1,116 @@
+/* $NetBSD: mt_misc.c,v 1.1 2000/06/02 23:11:11 fvdl Exp $ */
+
+/* #pragma ident "@(#)mt_misc.c 1.24 93/04/29 SMI" */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include "reentrant.h"
+#include <rpc/rpc.h>
+#include <sys/time.h>
+#include <stdlib.h>
+#include <string.h>
+#include "un-namespace.h"
+#include "mt_misc.h"
+
+/* Take these objects out of the application namespace. */
+#define svc_lock __svc_lock
+#define svc_fd_lock __svc_fd_lock
+#define rpcbaddr_cache_lock __rpcbaddr_cache_lock
+#define authdes_ops_lock __authdes_ops_lock
+#define authnone_lock __authnone_lock
+#define authsvc_lock __authsvc_lock
+#define clnt_fd_lock __clnt_fd_lock
+#define clntraw_lock __clntraw_lock
+#define dupreq_lock __dupreq_lock
+#define loopnconf_lock __loopnconf_lock
+#define ops_lock __ops_lock
+#define proglst_lock __proglst_lock
+#define rpcsoc_lock __rpcsoc_lock
+#define svcraw_lock __svcraw_lock
+#define xprtlist_lock __xprtlist_lock
+
+/* protects the services list (svc.c) */
+pthread_rwlock_t svc_lock = PTHREAD_RWLOCK_INITIALIZER;
+
+/* protects svc_fdset and the xports[] array */
+pthread_rwlock_t svc_fd_lock = PTHREAD_RWLOCK_INITIALIZER;
+
+/* protects the RPCBIND address cache */
+pthread_rwlock_t rpcbaddr_cache_lock = PTHREAD_RWLOCK_INITIALIZER;
+
+/* serializes authdes ops initializations */
+pthread_mutex_t authdes_ops_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/* protects des stats list */
+pthread_mutex_t svcauthdesstats_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/* auth_none.c serialization */
+pthread_mutex_t authnone_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/* protects the Auths list (svc_auth.c) */
+pthread_mutex_t authsvc_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/* protects client-side fd lock array */
+pthread_mutex_t clnt_fd_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/* clnt_raw.c serialization */
+pthread_mutex_t clntraw_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/* dupreq variables (svc_dg.c) */
+pthread_mutex_t dupreq_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/* loopnconf (rpcb_clnt.c) */
+pthread_mutex_t loopnconf_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/* serializes ops initializations */
+pthread_mutex_t ops_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/* protects proglst list (svc_simple.c) */
+pthread_mutex_t proglst_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/* serializes clnt_com_create() (rpc_soc.c) */
+pthread_mutex_t rpcsoc_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/* svc_raw.c serialization */
+pthread_mutex_t svcraw_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/* xprtlist (svc_generic.c) */
+pthread_mutex_t xprtlist_lock = PTHREAD_MUTEX_INITIALIZER;
+
+#undef rpc_createerr
+
+struct rpc_createerr rpc_createerr;
+static thread_key_t rce_key;
+static once_t rce_once = ONCE_INITIALIZER;
+static int rce_key_error;
+
+static void
+rce_key_init(void)
+{
+
+ rce_key_error = thr_keycreate(&rce_key, free);
+}
+
+struct rpc_createerr *
+__rpc_createerr(void)
+{
+ struct rpc_createerr *rce_addr = NULL;
+
+ if (thr_main())
+ return (&rpc_createerr);
+ if (thr_once(&rce_once, rce_key_init) != 0 || rce_key_error != 0)
+ return (&rpc_createerr);
+ rce_addr = (struct rpc_createerr *)thr_getspecific(rce_key);
+ if (!rce_addr) {
+ rce_addr = (struct rpc_createerr *)
+ malloc(sizeof (struct rpc_createerr));
+ if (thr_setspecific(rce_key, (void *) rce_addr) != 0) {
+ free(rce_addr);
+ return (&rpc_createerr);
+ }
+ memset(rce_addr, 0, sizeof (struct rpc_createerr));
+ return (rce_addr);
+ }
+ return (rce_addr);
+}
diff --git a/lib/libc/rpc/mt_misc.h b/lib/libc/rpc/mt_misc.h
new file mode 100644
index 000000000000..9cc2349c126e
--- /dev/null
+++ b/lib/libc/rpc/mt_misc.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2006 The FreeBSD Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _MT_MISC_H
+#define _MT_MISC_H
+
+/* Take these locks out of the application namespace. */
+#define svc_lock __svc_lock
+#define svc_fd_lock __svc_fd_lock
+#define rpcbaddr_cache_lock __rpcbaddr_cache_lock
+#define authdes_ops_lock __authdes_ops_lock
+#define authnone_lock __authnone_lock
+#define authsvc_lock __authsvc_lock
+#define clnt_fd_lock __clnt_fd_lock
+#define clntraw_lock __clntraw_lock
+#define dupreq_lock __dupreq_lock
+#define loopnconf_lock __loopnconf_lock
+#define ops_lock __ops_lock
+#define proglst_lock __proglst_lock
+#define rpcsoc_lock __rpcsoc_lock
+#define svcraw_lock __svcraw_lock
+#define xprtlist_lock __xprtlist_lock
+
+extern pthread_rwlock_t svc_lock;
+extern pthread_rwlock_t svc_fd_lock;
+extern pthread_rwlock_t rpcbaddr_cache_lock;
+extern pthread_mutex_t authdes_ops_lock;
+extern pthread_mutex_t svcauthdesstats_lock;
+extern pthread_mutex_t authnone_lock;
+extern pthread_mutex_t authsvc_lock;
+extern pthread_mutex_t clnt_fd_lock;
+extern pthread_mutex_t clntraw_lock;
+extern pthread_mutex_t dupreq_lock;
+extern pthread_mutex_t loopnconf_lock;
+extern pthread_mutex_t ops_lock;
+extern pthread_mutex_t proglst_lock;
+extern pthread_mutex_t rpcsoc_lock;
+extern pthread_mutex_t svcraw_lock;
+extern pthread_mutex_t tsd_lock;
+extern pthread_mutex_t xprtlist_lock;
+
+#endif
diff --git a/lib/libc/rpc/netconfig.5 b/lib/libc/rpc/netconfig.5
new file mode 100644
index 000000000000..edd2f63a0f53
--- /dev/null
+++ b/lib/libc/rpc/netconfig.5
@@ -0,0 +1,132 @@
+.\" $NetBSD: netconfig.5,v 1.2 2000/11/08 13:18:28 lukem Exp $
+.\" $NetBSD: netconfig.5,v 1.2 2000/11/08 13:18:28 lukem Exp $
+.\" $FreeBSD$
+.Dd November 17, 2000
+.Dt NETCONFIG 5
+.Os
+.Sh NAME
+.Nm netconfig
+.Nd network configuration data base
+.Sh SYNOPSIS
+.Pa /etc/netconfig
+.Sh DESCRIPTION
+The
+.Nm
+file defines a list of
+.Dq transport names ,
+describing their semantics and protocol.
+In
+.Fx ,
+this file is only used by the RPC library code.
+.Pp
+Entries have the following format:
+.Pp
+.Ar network_id semantics flags family protoname device libraries
+.Pp
+Entries consist of the following fields:
+.Bl -tag -width network_id
+.It Ar network_id
+The name of the transport described.
+.It Ar semantics
+Describes the semantics of the transport.
+This can be one of:
+.Bl -tag -width tpi_cots_ord -offset indent
+.It Sy tpi_clts
+Connectionless transport.
+.It Sy tpi_cots
+Connection-oriented transport
+.It Sy tpi_cots_ord
+Connection-oriented, ordered transport.
+.It Sy tpi_raw
+A raw connection.
+.El
+.It Ar flags
+This field is either blank (specified by
+.Dq Li - ) ,
+or contains one or more of the following characters:
+.Bl -tag -width b -offset indent
+.It Sy b
+The network represented by this entry is broadcast capable.
+This flag is meaningless in
+.Fx .
+.It Sy v
+The entry may be returned by the
+.Xr getnetpath 3
+function.
+.El
+.It Ar family
+The protocol family of the transport.
+This is currently one of:
+.Bl -tag -width loopback -offset indent
+.It Sy inet6
+The IPv6
+.Pq Dv PF_INET6
+family of protocols.
+.It Sy inet
+The IPv4
+.Pq Dv PF_INET
+family of protocols.
+.It Sy loopback
+The
+.Dv PF_LOCAL
+protocol family.
+.El
+.It Ar protoname
+The name of the protocol used for this transport.
+Can currently be either
+.Sy udp ,
+.Sy tcp
+or empty.
+.It Ar device
+This field is always empty in
+.Fx .
+.It Ar libraries
+This field is always empty in
+.Fx .
+.El
+.Pp
+The order of entries in this file will determine which transport will
+be preferred by the RPC library code, given a match on a specified
+network type.
+For example, if a sample network config file would look like this:
+.Bd -literal -offset indent
+udp6 tpi_clts v inet6 udp - -
+tcp6 tpi_cots_ord v inet6 tcp - -
+udp tpi_clts v inet udp - -
+tcp tpi_cots_ord v inet tcp - -
+rawip tpi_raw - inet - - -
+local tpi_cots_ord - loopback - - -
+.Ed
+.Pp
+then using the network type
+.Sy udp
+in calls to the RPC library function (see
+.Xr rpc 3 )
+will make the code first try
+.Sy udp6 ,
+and then
+.Sy udp .
+.Pp
+.Xr getnetconfig 3
+and associated functions will parse this file and return structures of
+the following format:
+.Bd -literal
+struct netconfig {
+ char *nc_netid; /* Network ID */
+ unsigned long nc_semantics; /* Semantics */
+ unsigned long nc_flag; /* Flags */
+ char *nc_protofmly; /* Protocol family */
+ char *nc_proto; /* Protocol name */
+ char *nc_device; /* Network device pathname (unused) */
+ unsigned long nc_nlookups; /* Number of lookup libs (unused) */
+ char **nc_lookups; /* Names of the libraries (unused) */
+ unsigned long nc_unused[9]; /* reserved */
+};
+.Ed
+.Sh FILES
+.Bl -tag -width /etc/netconfig -compact
+.It Pa /etc/netconfig
+.El
+.Sh SEE ALSO
+.Xr getnetconfig 3 ,
+.Xr getnetpath 3
diff --git a/lib/libc/rpc/netname.c b/lib/libc/rpc/netname.c
new file mode 100644
index 000000000000..77b522b6ac93
--- /dev/null
+++ b/lib/libc/rpc/netname.c
@@ -0,0 +1,141 @@
+/*-
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)netname.c 1.8 91/03/11 Copyr 1986 Sun Micro";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * netname utility routines
+ * convert from unix names to network names and vice-versa
+ * This module is operating system dependent!
+ * What we define here will work with any unix system that has adopted
+ * the sun NIS domain architecture.
+ */
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <rpc/rpc.h>
+#include <rpc/rpc_com.h>
+#ifdef YP
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+#endif
+#include <ctype.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 256
+#endif
+
+#define TYPE_BIT(type) (sizeof (type) * CHAR_BIT)
+
+#define TYPE_SIGNED(type) (((type) -1) < 0)
+
+/*
+** 302 / 1000 is log10(2.0) rounded up.
+** Subtract one for the sign bit if the type is signed;
+** add one for integer division truncation;
+** add one more for a minus sign if the type is signed.
+*/
+#define INT_STRLEN_MAXIMUM(type) \
+ ((TYPE_BIT(type) - TYPE_SIGNED(type)) * 302 / 1000 + 1 + TYPE_SIGNED(type))
+
+static char *OPSYS = "unix";
+
+/*
+ * Figure out my fully qualified network name
+ */
+int
+getnetname(char name[MAXNETNAMELEN+1])
+{
+ uid_t uid;
+
+ uid = geteuid();
+ if (uid == 0) {
+ return (host2netname(name, (char *) NULL, (char *) NULL));
+ } else {
+ return (user2netname(name, uid, (char *) NULL));
+ }
+}
+
+
+/*
+ * Convert unix cred to network-name
+ */
+int
+user2netname(char netname[MAXNETNAMELEN + 1], const uid_t uid, const char *domain)
+{
+ char *dfltdom;
+
+ if (domain == NULL) {
+ if (__rpc_get_default_domain(&dfltdom) != 0) {
+ return (0);
+ }
+ domain = dfltdom;
+ }
+ if (strlen(domain) + 1 + INT_STRLEN_MAXIMUM(u_long) + 1 + strlen(OPSYS) > MAXNETNAMELEN) {
+ return (0);
+ }
+ (void) sprintf(netname, "%s.%ld@%s", OPSYS, (u_long)uid, domain);
+ return (1);
+}
+
+
+/*
+ * Convert host to network-name
+ */
+int
+host2netname(char netname[MAXNETNAMELEN + 1], const char *host, const char *domain)
+{
+ char *dfltdom;
+ char hostname[MAXHOSTNAMELEN+1];
+
+ if (domain == NULL) {
+ if (__rpc_get_default_domain(&dfltdom) != 0) {
+ return (0);
+ }
+ domain = dfltdom;
+ }
+ if (host == NULL) {
+ (void) gethostname(hostname, sizeof(hostname));
+ host = hostname;
+ }
+ if (strlen(domain) + 1 + strlen(host) + 1 + strlen(OPSYS) > MAXNETNAMELEN) {
+ return (0);
+ }
+ (void) sprintf(netname, "%s.%s@%s", OPSYS, host, domain);
+ return (1);
+}
diff --git a/lib/libc/rpc/netnamer.c b/lib/libc/rpc/netnamer.c
new file mode 100644
index 000000000000..c29f271d6792
--- /dev/null
+++ b/lib/libc/rpc/netnamer.c
@@ -0,0 +1,323 @@
+/*-
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)netnamer.c 1.13 91/03/11 Copyr 1986 Sun Micro";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * netname utility routines convert from unix names to network names and
+ * vice-versa This module is operating system dependent! What we define here
+ * will work with any unix system that has adopted the sun NIS domain
+ * architecture.
+ */
+#include "namespace.h"
+#include <sys/param.h>
+#include <rpc/rpc.h>
+#include <rpc/rpc_com.h>
+#ifdef YP
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+#endif
+#include <ctype.h>
+#include <stdio.h>
+#include <grp.h>
+#include <pwd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+static char *OPSYS = "unix";
+#ifdef YP
+static char *NETID = "netid.byname";
+#endif
+static char *NETIDFILE = "/etc/netid";
+
+static int getnetid( char *, char * );
+static int _getgroups( char *, gid_t * );
+
+/*
+ * Convert network-name into unix credential
+ */
+int
+netname2user(char netname[MAXNETNAMELEN + 1], uid_t *uidp, gid_t *gidp,
+ int *gidlenp, gid_t *gidlist)
+{
+ char *p;
+ int gidlen;
+ uid_t uid;
+ long luid;
+ struct passwd *pwd;
+ char val[1024];
+ char *val1, *val2;
+ char *domain;
+ int vallen;
+ int err;
+
+ if (getnetid(netname, val)) {
+ char *res = val;
+
+ p = strsep(&res, ":");
+ if (p == NULL)
+ return (0);
+ *uidp = (uid_t) atol(p);
+ p = strsep(&res, "\n,");
+ if (p == NULL) {
+ return (0);
+ }
+ *gidp = (gid_t) atol(p);
+ for (gidlen = 0; gidlen < NGRPS; gidlen++) {
+ p = strsep(&res, "\n,");
+ if (p == NULL)
+ break;
+ gidlist[gidlen] = (gid_t) atol(p);
+ }
+ *gidlenp = gidlen;
+
+ return (1);
+ }
+ val1 = strchr(netname, '.');
+ if (val1 == NULL)
+ return (0);
+ if (strncmp(netname, OPSYS, (val1-netname)))
+ return (0);
+ val1++;
+ val2 = strchr(val1, '@');
+ if (val2 == NULL)
+ return (0);
+ vallen = val2 - val1;
+ if (vallen > (1024 - 1))
+ vallen = 1024 - 1;
+ (void) strncpy(val, val1, 1024);
+ val[vallen] = 0;
+
+ err = __rpc_get_default_domain(&domain); /* change to rpc */
+ if (err)
+ return (0);
+
+ if (strcmp(val2 + 1, domain))
+ return (0); /* wrong domain */
+
+ if (sscanf(val, "%ld", &luid) != 1)
+ return (0);
+ uid = luid;
+
+ /* use initgroups method */
+ pwd = getpwuid(uid);
+ if (pwd == NULL)
+ return (0);
+ *uidp = pwd->pw_uid;
+ *gidp = pwd->pw_gid;
+ *gidlenp = _getgroups(pwd->pw_name, gidlist);
+ return (1);
+}
+
+/*
+ * initgroups
+ */
+
+static int
+_getgroups(char *uname, gid_t groups[NGRPS])
+{
+ gid_t ngroups = 0;
+ struct group *grp;
+ int i;
+ int j;
+ int filter;
+
+ setgrent();
+ while ((grp = getgrent())) {
+ for (i = 0; grp->gr_mem[i]; i++)
+ if (!strcmp(grp->gr_mem[i], uname)) {
+ if (ngroups == NGRPS) {
+#ifdef DEBUG
+ fprintf(stderr,
+ "initgroups: %s is in too many groups\n", uname);
+#endif
+ goto toomany;
+ }
+ /* filter out duplicate group entries */
+ filter = 0;
+ for (j = 0; j < ngroups; j++)
+ if (groups[j] == grp->gr_gid) {
+ filter++;
+ break;
+ }
+ if (!filter)
+ groups[ngroups++] = grp->gr_gid;
+ }
+ }
+toomany:
+ endgrent();
+ return (ngroups);
+}
+
+/*
+ * Convert network-name to hostname
+ */
+int
+netname2host(char netname[MAXNETNAMELEN + 1], char *hostname, int hostlen)
+{
+ int err;
+ char valbuf[1024];
+ char *val;
+ char *val2;
+ int vallen;
+ char *domain;
+
+ if (getnetid(netname, valbuf)) {
+ val = valbuf;
+ if ((*val == '0') && (val[1] == ':')) {
+ (void) strncpy(hostname, val + 2, hostlen);
+ return (1);
+ }
+ }
+ val = strchr(netname, '.');
+ if (val == NULL)
+ return (0);
+ if (strncmp(netname, OPSYS, (val - netname)))
+ return (0);
+ val++;
+ val2 = strchr(val, '@');
+ if (val2 == NULL)
+ return (0);
+ vallen = val2 - val;
+ if (vallen > (hostlen - 1))
+ vallen = hostlen - 1;
+ (void) strncpy(hostname, val, vallen);
+ hostname[vallen] = 0;
+
+ err = __rpc_get_default_domain(&domain); /* change to rpc */
+ if (err)
+ return (0);
+
+ if (strcmp(val2 + 1, domain))
+ return (0); /* wrong domain */
+ else
+ return (1);
+}
+
+/*
+ * reads the file /etc/netid looking for a + to optionally go to the
+ * network information service.
+ */
+int
+getnetid(char *key, char *ret)
+{
+ char buf[1024]; /* big enough */
+ char *res;
+ char *mkey;
+ char *mval;
+ FILE *fd;
+#ifdef YP
+ char *domain;
+ int err;
+ char *lookup;
+ int len;
+#endif
+ int rv;
+
+ rv = 0;
+
+ fd = fopen(NETIDFILE, "r");
+ if (fd == NULL) {
+#ifdef YP
+ res = "+";
+ goto getnetidyp;
+#else
+ return (0);
+#endif
+ }
+ while (fd != NULL) {
+ res = fgets(buf, sizeof(buf), fd);
+ if (res == NULL) {
+ rv = 0;
+ goto done;
+ }
+ if (res[0] == '#')
+ continue;
+ else if (res[0] == '+') {
+#ifdef YP
+ getnetidyp:
+ err = yp_get_default_domain(&domain);
+ if (err) {
+ continue;
+ }
+ lookup = NULL;
+ err = yp_match(domain, NETID, key,
+ strlen(key), &lookup, &len);
+ if (err) {
+#ifdef DEBUG
+ fprintf(stderr, "match failed error %d\n", err);
+#endif
+ continue;
+ }
+ lookup[len] = 0;
+ strcpy(ret, lookup);
+ free(lookup);
+ rv = 2;
+ goto done;
+#else /* YP */
+#ifdef DEBUG
+ fprintf(stderr,
+"Bad record in %s '+' -- NIS not supported in this library copy\n",
+ NETIDFILE);
+#endif
+ continue;
+#endif /* YP */
+ } else {
+ mkey = strsep(&res, "\t ");
+ if (mkey == NULL) {
+ fprintf(stderr,
+ "Bad record in %s -- %s", NETIDFILE, buf);
+ continue;
+ }
+ do {
+ mval = strsep(&res, " \t#\n");
+ } while (mval != NULL && !*mval);
+ if (mval == NULL) {
+ fprintf(stderr,
+ "Bad record in %s val problem - %s", NETIDFILE, buf);
+ continue;
+ }
+ if (strcmp(mkey, key) == 0) {
+ strcpy(ret, mval);
+ rv = 1;
+ goto done;
+ }
+ }
+ }
+
+done:
+ if (fd != NULL)
+ fclose(fd);
+ return (rv);
+}
diff --git a/lib/libc/rpc/pmap_clnt.c b/lib/libc/rpc/pmap_clnt.c
new file mode 100644
index 000000000000..702d58d5bf40
--- /dev/null
+++ b/lib/libc/rpc/pmap_clnt.c
@@ -0,0 +1,119 @@
+/* $NetBSD: pmap_clnt.c,v 1.16 2000/07/06 03:10:34 christos Exp $ */
+
+/*-
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *sccsid2 = "@(#)pmap_clnt.c 1.37 87/08/11 Copyr 1984 Sun Micro";
+static char *sccsid = "@(#)pmap_clnt.c 2.2 88/08/01 4.0 RPCSRC";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * pmap_clnt.c
+ * Client interface to pmap rpc service.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <rpc/rpc.h>
+#include <rpc/pmap_prot.h>
+#include <rpc/pmap_clnt.h>
+#include <rpc/nettype.h>
+#include <netinet/in.h>
+#include "un-namespace.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "rpc_com.h"
+
+bool_t
+pmap_set(u_long program, u_long version, int protocol, int port)
+{
+ bool_t rslt;
+ struct netbuf *na;
+ struct netconfig *nconf;
+ char buf[32];
+
+ if ((protocol != IPPROTO_UDP) && (protocol != IPPROTO_TCP)) {
+ return (FALSE);
+ }
+ nconf = __rpc_getconfip(protocol == IPPROTO_UDP ? "udp" : "tcp");
+ if (nconf == NULL) {
+ return (FALSE);
+ }
+ snprintf(buf, sizeof buf, "0.0.0.0.%d.%d",
+ (((u_int32_t)port) >> 8) & 0xff, port & 0xff);
+ na = uaddr2taddr(nconf, buf);
+ if (na == NULL) {
+ freenetconfigent(nconf);
+ return (FALSE);
+ }
+ rslt = rpcb_set((rpcprog_t)program, (rpcvers_t)version, nconf, na);
+ free(na);
+ freenetconfigent(nconf);
+ return (rslt);
+}
+
+/*
+ * Remove the mapping between program, version and port.
+ * Calls the pmap service remotely to do the un-mapping.
+ */
+bool_t
+pmap_unset(u_long program, u_long version)
+{
+ struct netconfig *nconf;
+ bool_t udp_rslt = FALSE;
+ bool_t tcp_rslt = FALSE;
+
+ nconf = __rpc_getconfip("udp");
+ if (nconf != NULL) {
+ udp_rslt = rpcb_unset((rpcprog_t)program, (rpcvers_t)version,
+ nconf);
+ freenetconfigent(nconf);
+ }
+ nconf = __rpc_getconfip("tcp");
+ if (nconf != NULL) {
+ tcp_rslt = rpcb_unset((rpcprog_t)program, (rpcvers_t)version,
+ nconf);
+ freenetconfigent(nconf);
+ }
+ /*
+ * XXX: The call may still succeed even if only one of the
+ * calls succeeded. This was the best that could be
+ * done for backward compatibility.
+ */
+ return (tcp_rslt || udp_rslt);
+}
diff --git a/lib/libc/rpc/pmap_getmaps.c b/lib/libc/rpc/pmap_getmaps.c
new file mode 100644
index 000000000000..1049005cfddf
--- /dev/null
+++ b/lib/libc/rpc/pmap_getmaps.c
@@ -0,0 +1,98 @@
+/* $NetBSD: pmap_getmaps.c,v 1.16 2000/07/06 03:10:34 christos Exp $ */
+
+/*-
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *sccsid2 = "@(#)pmap_getmaps.c 1.10 87/08/11 Copyr 1984 Sun Micro";
+static char *sccsid = "@(#)pmap_getmaps.c 2.2 88/08/01 4.0 RPCSRC";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * pmap_getmap.c
+ * Client interface to pmap rpc service.
+ * contains pmap_getmaps, which is only tcp service involved
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+
+#include <arpa/inet.h>
+#include <net/if.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <rpc/rpc.h>
+#include <rpc/pmap_prot.h>
+#include <rpc/pmap_clnt.h>
+#include "un-namespace.h"
+
+#define NAMELEN 255
+#define MAX_BROADCAST_SIZE 1400
+
+/*
+ * Get a copy of the current port maps.
+ * Calls the pmap service remotely to do get the maps.
+ */
+struct pmaplist *
+pmap_getmaps(struct sockaddr_in *address)
+{
+ struct pmaplist *head = NULL;
+ int sock = -1;
+ struct timeval minutetimeout;
+ CLIENT *client;
+
+ assert(address != NULL);
+
+ minutetimeout.tv_sec = 60;
+ minutetimeout.tv_usec = 0;
+ address->sin_port = htons(PMAPPORT);
+ client = clnttcp_create(address, PMAPPROG,
+ PMAPVERS, &sock, 50, 500);
+ if (client != NULL) {
+ if (CLNT_CALL(client, (rpcproc_t)PMAPPROC_DUMP,
+ (xdrproc_t)xdr_void, NULL,
+ (xdrproc_t)xdr_pmaplist, &head, minutetimeout) !=
+ RPC_SUCCESS) {
+ clnt_perror(client, "pmap_getmaps rpc problem");
+ }
+ CLNT_DESTROY(client);
+ }
+ address->sin_port = 0;
+ return (head);
+}
diff --git a/lib/libc/rpc/pmap_getport.c b/lib/libc/rpc/pmap_getport.c
new file mode 100644
index 000000000000..c1e0c7a4b88d
--- /dev/null
+++ b/lib/libc/rpc/pmap_getport.c
@@ -0,0 +1,100 @@
+/* $NetBSD: pmap_getport.c,v 1.16 2000/07/06 03:10:34 christos Exp $ */
+
+/*-
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *sccsid2 = "from: @(#)pmap_getport.c 1.9 87/08/11 Copyr 1984 Sun Micro";
+static char *sccsid = "from: @(#)pmap_getport.c 2.2 88/08/01 4.0 RPCSRC";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * pmap_getport.c
+ * Client interface to pmap rpc service.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <arpa/inet.h>
+#include <net/if.h>
+
+#include <assert.h>
+#include <unistd.h>
+
+#include <rpc/rpc.h>
+#include <rpc/pmap_prot.h>
+#include <rpc/pmap_clnt.h>
+#include "un-namespace.h"
+
+static const struct timeval timeout = { 5, 0 };
+static const struct timeval tottimeout = { 60, 0 };
+
+/*
+ * Find the mapped port for program,version.
+ * Calls the pmap service remotely to do the lookup.
+ * Returns 0 if no map exists.
+ */
+u_short
+pmap_getport(struct sockaddr_in *address, u_long program, u_long version,
+ u_int protocol)
+{
+ u_short port = 0;
+ int sock = -1;
+ CLIENT *client;
+ struct pmap parms;
+
+ assert(address != NULL);
+
+ address->sin_port = htons(PMAPPORT);
+ client = clntudp_bufcreate(address, PMAPPROG,
+ PMAPVERS, timeout, &sock, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
+ if (client != NULL) {
+ parms.pm_prog = program;
+ parms.pm_vers = version;
+ parms.pm_prot = protocol;
+ parms.pm_port = 0; /* not needed or used */
+ if (CLNT_CALL(client, (rpcproc_t)PMAPPROC_GETPORT,
+ (xdrproc_t)xdr_pmap,
+ &parms, (xdrproc_t)xdr_u_short, &port, tottimeout) !=
+ RPC_SUCCESS){
+ rpc_createerr.cf_stat = RPC_PMAPFAILURE;
+ clnt_geterr(client, &rpc_createerr.cf_error);
+ } else if (port == 0) {
+ rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
+ }
+ CLNT_DESTROY(client);
+ }
+ address->sin_port = 0;
+ return (port);
+}
diff --git a/lib/libc/rpc/pmap_prot.c b/lib/libc/rpc/pmap_prot.c
new file mode 100644
index 000000000000..bf0167235bf5
--- /dev/null
+++ b/lib/libc/rpc/pmap_prot.c
@@ -0,0 +1,66 @@
+/* $NetBSD: pmap_prot.c,v 1.10 2000/01/22 22:19:18 mycroft Exp $ */
+
+/*-
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *sccsid2 = "@(#)pmap_prot.c 1.17 87/08/11 Copyr 1984 Sun Micro";
+static char *sccsid = "@(#)pmap_prot.c 2.1 88/07/29 4.0 RPCSRC";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * pmap_prot.c
+ * Protocol for the local binder service, or pmap.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#include "namespace.h"
+#include <assert.h>
+
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#include <rpc/pmap_prot.h>
+#include "un-namespace.h"
+
+
+bool_t
+xdr_pmap(XDR *xdrs, struct pmap *regs)
+{
+
+ assert(xdrs != NULL);
+ assert(regs != NULL);
+
+ if (xdr_u_long(xdrs, &regs->pm_prog) &&
+ xdr_u_long(xdrs, &regs->pm_vers) &&
+ xdr_u_long(xdrs, &regs->pm_prot))
+ return (xdr_u_long(xdrs, &regs->pm_port));
+ return (FALSE);
+}
diff --git a/lib/libc/rpc/pmap_prot2.c b/lib/libc/rpc/pmap_prot2.c
new file mode 100644
index 000000000000..f892afbc9bd7
--- /dev/null
+++ b/lib/libc/rpc/pmap_prot2.c
@@ -0,0 +1,138 @@
+/* $NetBSD: pmap_prot2.c,v 1.14 2000/07/06 03:10:34 christos Exp $ */
+
+/*-
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *sccsid2 = "@(#)pmap_prot2.c 1.3 87/08/11 Copyr 1984 Sun Micro";
+static char *sccsid = "@(#)pmap_prot2.c 2.1 88/07/29 4.0 RPCSRC";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * pmap_prot2.c
+ * Protocol for the local binder service, or pmap.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#include "namespace.h"
+#include <assert.h>
+
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#include <rpc/pmap_prot.h>
+#include "un-namespace.h"
+
+
+/*
+ * What is going on with linked lists? (!)
+ * First recall the link list declaration from pmap_prot.h:
+ *
+ * struct pmaplist {
+ * struct pmap pml_map;
+ * struct pmaplist *pml_map;
+ * };
+ *
+ * Compare that declaration with a corresponding xdr declaration that
+ * is (a) pointer-less, and (b) recursive:
+ *
+ * typedef union switch (bool_t) {
+ *
+ * case TRUE: struct {
+ * struct pmap;
+ * pmaplist_t foo;
+ * };
+ *
+ * case FALSE: struct {};
+ * } pmaplist_t;
+ *
+ * Notice that the xdr declaration has no nxt pointer while
+ * the C declaration has no bool_t variable. The bool_t can be
+ * interpreted as ``more data follows me''; if FALSE then nothing
+ * follows this bool_t; if TRUE then the bool_t is followed by
+ * an actual struct pmap, and then (recursively) by the
+ * xdr union, pamplist_t.
+ *
+ * This could be implemented via the xdr_union primitive, though this
+ * would cause a one recursive call per element in the list. Rather than do
+ * that we can ``unwind'' the recursion
+ * into a while loop and do the union arms in-place.
+ *
+ * The head of the list is what the C programmer wishes to past around
+ * the net, yet is the data that the pointer points to which is interesting;
+ * this sounds like a job for xdr_reference!
+ */
+bool_t
+xdr_pmaplist(XDR *xdrs, struct pmaplist **rp)
+{
+ /*
+ * more_elements is pre-computed in case the direction is
+ * XDR_ENCODE or XDR_FREE. more_elements is overwritten by
+ * xdr_bool when the direction is XDR_DECODE.
+ */
+ bool_t more_elements;
+ int freeing;
+ struct pmaplist **next = NULL; /* pacify gcc */
+
+ assert(xdrs != NULL);
+ assert(rp != NULL);
+
+ freeing = (xdrs->x_op == XDR_FREE);
+
+ for (;;) {
+ more_elements = (bool_t)(*rp != NULL);
+ if (! xdr_bool(xdrs, &more_elements))
+ return (FALSE);
+ if (! more_elements)
+ return (TRUE); /* we are done */
+ /*
+ * the unfortunate side effect of non-recursion is that in
+ * the case of freeing we must remember the next object
+ * before we free the current object ...
+ */
+ if (freeing)
+ next = &((*rp)->pml_next);
+ if (! xdr_reference(xdrs, (caddr_t *)rp,
+ (u_int)sizeof(struct pmaplist), (xdrproc_t)xdr_pmap))
+ return (FALSE);
+ rp = (freeing) ? next : &((*rp)->pml_next);
+ }
+}
+
+
+/*
+ * xdr_pmaplist_ptr() is specified to take a PMAPLIST *, but is identical in
+ * functionality to xdr_pmaplist().
+ */
+bool_t
+xdr_pmaplist_ptr(XDR *xdrs, struct pmaplist *rp)
+{
+ return xdr_pmaplist(xdrs, (struct pmaplist **)(void *)rp);
+}
diff --git a/lib/libc/rpc/pmap_rmt.c b/lib/libc/rpc/pmap_rmt.c
new file mode 100644
index 000000000000..124120498dcb
--- /dev/null
+++ b/lib/libc/rpc/pmap_rmt.c
@@ -0,0 +1,166 @@
+/* $NetBSD: pmap_rmt.c,v 1.29 2000/07/06 03:10:34 christos Exp $ */
+
+/*-
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *sccsid2 = "@(#)pmap_rmt.c 1.21 87/08/27 Copyr 1984 Sun Micro";
+static char *sccsid = "@(#)pmap_rmt.c 2.2 88/08/01 4.0 RPCSRC";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * pmap_rmt.c
+ * Client interface to pmap rpc service.
+ * remote call and broadcast service
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/poll.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <assert.h>
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <rpc/rpc.h>
+#include <rpc/pmap_prot.h>
+#include <rpc/pmap_clnt.h>
+#include <rpc/pmap_rmt.h>
+#include "un-namespace.h"
+
+static const struct timeval timeout = { 3, 0 };
+
+/*
+ * pmapper remote-call-service interface.
+ * This routine is used to call the pmapper remote call service
+ * which will look up a service program in the port maps, and then
+ * remotely call that routine with the given parameters. This allows
+ * programs to do a lookup and call in one step.
+*/
+enum clnt_stat
+pmap_rmtcall(struct sockaddr_in *addr, u_long prog, u_long vers, u_long proc,
+ xdrproc_t xdrargs, caddr_t argsp, xdrproc_t xdrres, caddr_t resp,
+ struct timeval tout, u_long *port_ptr)
+{
+ int sock = -1;
+ CLIENT *client;
+ struct rmtcallargs a;
+ struct rmtcallres r;
+ enum clnt_stat stat;
+
+ assert(addr != NULL);
+ assert(port_ptr != NULL);
+
+ addr->sin_port = htons(PMAPPORT);
+ client = clntudp_create(addr, PMAPPROG, PMAPVERS, timeout, &sock);
+ if (client != NULL) {
+ a.prog = prog;
+ a.vers = vers;
+ a.proc = proc;
+ a.args_ptr = argsp;
+ a.xdr_args = xdrargs;
+ r.port_ptr = port_ptr;
+ r.results_ptr = resp;
+ r.xdr_results = xdrres;
+ stat = CLNT_CALL(client, (rpcproc_t)PMAPPROC_CALLIT,
+ (xdrproc_t)xdr_rmtcall_args, &a, (xdrproc_t)xdr_rmtcallres,
+ &r, tout);
+ CLNT_DESTROY(client);
+ } else {
+ stat = RPC_FAILED;
+ }
+ addr->sin_port = 0;
+ return (stat);
+}
+
+
+/*
+ * XDR remote call arguments
+ * written for XDR_ENCODE direction only
+ */
+bool_t
+xdr_rmtcall_args(XDR *xdrs, struct rmtcallargs *cap)
+{
+ u_int lenposition, argposition, position;
+
+ assert(xdrs != NULL);
+ assert(cap != NULL);
+
+ if (xdr_u_long(xdrs, &(cap->prog)) &&
+ xdr_u_long(xdrs, &(cap->vers)) &&
+ xdr_u_long(xdrs, &(cap->proc))) {
+ lenposition = XDR_GETPOS(xdrs);
+ if (! xdr_u_long(xdrs, &(cap->arglen)))
+ return (FALSE);
+ argposition = XDR_GETPOS(xdrs);
+ if (! (*(cap->xdr_args))(xdrs, cap->args_ptr))
+ return (FALSE);
+ position = XDR_GETPOS(xdrs);
+ cap->arglen = (u_long)position - (u_long)argposition;
+ XDR_SETPOS(xdrs, lenposition);
+ if (! xdr_u_long(xdrs, &(cap->arglen)))
+ return (FALSE);
+ XDR_SETPOS(xdrs, position);
+ return (TRUE);
+ }
+ return (FALSE);
+}
+
+/*
+ * XDR remote call results
+ * written for XDR_DECODE direction only
+ */
+bool_t
+xdr_rmtcallres(XDR *xdrs, struct rmtcallres *crp)
+{
+ caddr_t port_ptr;
+
+ assert(xdrs != NULL);
+ assert(crp != NULL);
+
+ port_ptr = (caddr_t)(void *)crp->port_ptr;
+ if (xdr_reference(xdrs, &port_ptr, sizeof (u_long),
+ (xdrproc_t)xdr_u_long) && xdr_u_long(xdrs, &crp->resultslen)) {
+ crp->port_ptr = (u_long *)(void *)port_ptr;
+ return ((*(crp->xdr_results))(xdrs, crp->results_ptr));
+ }
+ return (FALSE);
+}
diff --git a/lib/libc/rpc/publickey.3 b/lib/libc/rpc/publickey.3
new file mode 100644
index 000000000000..ff8a615a28df
--- /dev/null
+++ b/lib/libc/rpc/publickey.3
@@ -0,0 +1,53 @@
+.\" @(#)publickey.3r 2.1 88/08/07 4.0 RPCSRC
+.\" $FreeBSD$
+.\"
+.Dd October 6, 1987
+.Dt PUBLICKEY 3
+.Os
+.Sh NAME
+.Nm publickey , getpublickey , getsecretkey
+.Nd "get public or secret key"
+.Sh LIBRARY
+.Lb librpcsvc
+.Sh SYNOPSIS
+.In rpc/rpc.h
+.In rpc/key_prot.h
+.Ft int
+.Fo getpublickey
+.Fa "const char netname[MAXNETNAMELEN+1]"
+.Fa "char publickey[HEXKEYBYTES+1]"
+.Fc
+.Ft int
+.Fo getsecretkey
+.Fa "char netname[MAXNETNAMELEN+1]"
+.Fa "char secretkey[HEXKEYBYTES+1]"
+.Fa "char *passwd"
+.Fc
+.Sh DESCRIPTION
+These routines are used to get public and secret keys from the
+.Tn YP
+database.
+The
+.Fn getsecretkey
+function
+has an extra argument,
+.Fa passwd ,
+which is used to decrypt the encrypted secret key stored in the database.
+Both routines return 1 if they are successful in finding the key, 0 otherwise.
+The keys are returned as
+.Dv NUL Ns \-terminated ,
+hexadecimal strings.
+If the password supplied to
+.Fn getsecretkey
+fails to decrypt the secret key, the routine will return 1 but the
+.Fa secretkey
+argument will be a
+.Dv NUL
+string
+.Pq Dq .
+.Sh SEE ALSO
+.Xr publickey 5
+.Pp
+.%T "RPC Programmer's Manual"
+in
+.Pa /usr/share/doc/psd/23.rpc .
diff --git a/lib/libc/rpc/publickey.5 b/lib/libc/rpc/publickey.5
new file mode 100644
index 000000000000..71f4ef6aca40
--- /dev/null
+++ b/lib/libc/rpc/publickey.5
@@ -0,0 +1,42 @@
+.\" $FreeBSD$
+.\" @(#)publickey.5 2.1 88/08/07 4.0 RPCSRC; from 1.6 88/02/29 SMI;
+.Dd October 19, 1987
+.Dt PUBLICKEY 5
+.Os
+.Sh NAME
+.Nm publickey
+.Nd "public key database"
+.Sh SYNOPSIS
+.Pa /etc/publickey
+.Sh DESCRIPTION
+.Pa /etc/publickey
+is the public key database used for secure
+RPC (Remote Procedure Calls).
+Each entry in
+the database consists of a network user
+name (which may either refer to
+a user or a hostname), followed by the user's
+public key (in hex
+notation), a colon, and then the user's
+secret key encrypted with
+its login password (also in hex notation).
+.Pp
+This file is altered either by the user through the
+.Xr chkey 1
+command or by the system administrator through the
+.Xr newkey 8
+command.
+The file
+.Pa /etc/publickey
+should only contain data on the
+.Tn NIS
+master machine, where it
+is converted into the
+.Tn NIS
+database
+.Pa publickey.byname .
+.Sh SEE ALSO
+.Xr chkey 1 ,
+.Xr publickey 3 ,
+.Xr newkey 8 ,
+.Xr ypupdated 8
diff --git a/lib/libc/rpc/rpc.3 b/lib/libc/rpc/rpc.3
new file mode 100644
index 000000000000..988b5f1ec233
--- /dev/null
+++ b/lib/libc/rpc/rpc.3
@@ -0,0 +1,517 @@
+.\" @(#)rpc.3n 1.31 93/08/31 SMI; from SVr4
+.\" Copyright 1989 AT&T
+.\" $NetBSD: rpc.3,v 1.10 2000/06/02 23:11:12 fvdl Exp $
+.\" $FreeBSD$
+.Dd May 7, 1993
+.Dt RPC 3
+.Os
+.Sh NAME
+.Nm rpc
+.Nd library routines for remote procedure calls
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In rpc/rpc.h
+.In netconfig.h
+.Sh DESCRIPTION
+These
+routines allow C language programs to make procedure
+calls on other machines across a network.
+First, the client sends a request to the server.
+On receipt of the request, the server calls a dispatch routine
+to perform the requested service, and then sends back a reply.
+.Pp
+All
+RPC routines require the header
+.In rpc/rpc.h .
+Routines that take a
+.Vt "struct netconfig"
+also require that
+.In netconfig.h
+be included.
+.Sh Nettype
+Some of the high-level
+RPC interface routines take a
+.Fa nettype
+string as one of the arguments
+(for example,
+.Fn clnt_create ,
+.Fn svc_create ,
+.Fn rpc_reg ,
+.Fn rpc_call ) .
+This string defines a class of transports which can be used
+for a particular application.
+.Pp
+The
+.Fa nettype
+argument
+can be one of the following:
+.Bl -tag -width datagram_v
+.It netpath
+Choose from the transports which have been
+indicated by their token names in the
+.Ev NETPATH
+environment variable.
+.Ev NETPATH
+is unset or
+.Dv NULL ,
+it defaults to
+.Qq visible .
+.Qq netpath
+is the default
+.Fa nettype .
+.It visible
+Choose the transports which have the visible flag (v)
+set in the
+.Pa /etc/netconfig
+file.
+.It circuit_v
+This is same as
+.Qq visible
+except that it chooses only the connection oriented transports
+(semantics
+.Qq tpi_cots
+or
+.Qq tpi_cots_ord )
+from the entries in the
+.Pa /etc/netconfig
+file.
+.It datagram_v
+This is same as
+.Qq visible
+except that it chooses only the connectionless datagram transports
+(semantics
+.Qq tpi_clts )
+from the entries in the
+.Pa /etc/netconfig
+file.
+.It circuit_n
+This is same as
+.Qq netpath
+except that it chooses only the connection oriented datagram transports
+(semantics
+.Qq tpi_cots
+or
+.Qq tpi_cots_ord ) .
+.It datagram_n
+This is same as
+.Qq netpath
+except that it chooses only the connectionless datagram transports
+(semantics
+.Qq tpi_clts ) .
+.It udp
+This refers to Internet UDP, both version 4 and 6.
+.It tcp
+This refers to Internet TCP, both version 4 and 6.
+.El
+.Pp
+If
+.Fa nettype
+is
+.Dv NULL ,
+it defaults to
+.Qq netpath .
+The transports are tried in left to right order in the
+.Ev NETPATH
+variable or in top to down order in the
+.Pa /etc/netconfig
+file.
+.Sh Derived Types
+The derived types used in the RPC interfaces are defined as follows:
+.Bd -literal
+ typedef uint32_t rpcprog_t;
+ typedef uint32_t rpcvers_t;
+ typedef uint32_t rpcproc_t;
+ typedef uint32_t rpcprot_t;
+ typedef uint32_t rpcport_t;
+ typedef int32_t rpc_inline_t;
+.Ed
+.Sh "Data Structures"
+Some of the data structures used by the
+RPC package are shown below.
+.Sh "The AUTH Structure"
+.Bd -literal
+/*
+ * Authentication info. Opaque to client.
+ */
+struct opaque_auth {
+ enum_t oa_flavor; /* flavor of auth */
+ caddr_t oa_base; /* address of more auth stuff */
+ u_int oa_length; /* not to exceed MAX_AUTH_BYTES */
+};
+
+/*
+ * Auth handle, interface to client side authenticators.
+ */
+typedef struct {
+ struct opaque_auth ah_cred;
+ struct opaque_auth ah_verf;
+ struct auth_ops {
+ void (*ah_nextverf)(\|);
+ int (*ah_marshal)(\|); /* nextverf & serialize */
+ int (*ah_validate)(\|); /* validate verifier */
+ int (*ah_refresh)(\|); /* refresh credentials */
+ void (*ah_destroy)(\|); /* destroy this structure */
+ } *ah_ops;
+ caddr_t ah_private;
+} AUTH;
+.Ed
+.Sh "The CLIENT Structure"
+.Bd -literal
+/*
+ * Client rpc handle.
+ * Created by individual implementations.
+ * Client is responsible for initializing auth.
+ */
+
+typedef struct {
+ AUTH *cl_auth; /* authenticator */
+ struct clnt_ops {
+ enum clnt_stat (*cl_call)(); /* call remote procedure */
+ void (*cl_abort)(); /* abort a call */
+ void (*cl_geterr)(); /* get specific error code */
+ bool_t (*cl_freeres)(); /* frees results */
+ void (*cl_destroy)(); /* destroy this structure */
+ bool_t (*cl_control)(); /* the ioctl() of rpc */
+ } *cl_ops;
+ caddr_t cl_private; /* private stuff */
+ char *cl_netid; /* network identifier */
+ char *cl_tp; /* device name */
+} CLIENT;
+.Ed
+.Sh "The SVCXPRT structure"
+.Bd -literal
+enum xprt_stat {
+ XPRT_DIED,
+ XPRT_MOREREQS,
+ XPRT_IDLE
+};
+
+/*
+ * Server side transport handle
+ */
+typedef struct {
+ int xp_fd; /* file descriptor for the server handle */
+ u_short xp_port; /* obsolete */
+ const struct xp_ops {
+ bool_t (*xp_recv)(); /* receive incoming requests */
+ enum xprt_stat (*xp_stat)(); /* get transport status */
+ bool_t (*xp_getargs)(); /* get arguments */
+ bool_t (*xp_reply)(); /* send reply */
+ bool_t (*xp_freeargs)(); /* free mem allocated for args */
+ void (*xp_destroy)(); /* destroy this struct */
+ } *xp_ops;
+ int xp_addrlen; /* length of remote addr. Obsolete */
+ struct sockaddr_in xp_raddr; /* Obsolete */
+ const struct xp_ops2 {
+ bool_t (*xp_control)(); /* catch-all function */
+ } *xp_ops2;
+ char *xp_tp; /* transport provider device name */
+ char *xp_netid; /* network identifier */
+ struct netbuf xp_ltaddr; /* local transport address */
+ struct netbuf xp_rtaddr; /* remote transport address */
+ struct opaque_auth xp_verf; /* raw response verifier */
+ caddr_t xp_p1; /* private: for use by svc ops */
+ caddr_t xp_p2; /* private: for use by svc ops */
+ caddr_t xp_p3; /* private: for use by svc lib */
+ int xp_type /* transport type */
+} SVCXPRT;
+.Ed
+.Sh "The svc_reg structure"
+.Bd -literal
+struct svc_req {
+ rpcprog_t rq_prog; /* service program number */
+ rpcvers_t rq_vers; /* service protocol version */
+ rpcproc_t rq_proc; /* the desired procedure */
+ struct opaque_auth rq_cred; /* raw creds from the wire */
+ caddr_t rq_clntcred; /* read only cooked cred */
+ SVCXPRT *rq_xprt; /* associated transport */
+};
+.Ed
+.Sh "The XDR structure"
+.Bd -literal
+/*
+ * XDR operations.
+ * XDR_ENCODE causes the type to be encoded into the stream.
+ * XDR_DECODE causes the type to be extracted from the stream.
+ * XDR_FREE can be used to release the space allocated by an XDR_DECODE
+ * request.
+ */
+enum xdr_op {
+ XDR_ENCODE=0,
+ XDR_DECODE=1,
+ XDR_FREE=2
+};
+/*
+ * This is the number of bytes per unit of external data.
+ */
+#define BYTES_PER_XDR_UNIT (4)
+#define RNDUP(x) ((((x) + BYTES_PER_XDR_UNIT - 1) /
+ BYTES_PER_XDR_UNIT) \e * BYTES_PER_XDR_UNIT)
+
+/*
+ * A xdrproc_t exists for each data type which is to be encoded or
+ * decoded. The second argument to the xdrproc_t is a pointer to
+ * an opaque pointer. The opaque pointer generally points to a
+ * structure of the data type to be decoded. If this points to 0,
+ * then the type routines should allocate dynamic storage of the
+ * appropriate size and return it.
+ * bool_t (*xdrproc_t)(XDR *, caddr_t *);
+ */
+typedef bool_t (*xdrproc_t)();
+
+/*
+ * The XDR handle.
+ * Contains operation which is being applied to the stream,
+ * an operations vector for the particular implementation
+ */
+typedef struct {
+ enum xdr_op x_op; /* operation; fast additional param */
+ struct xdr_ops {
+ bool_t (*x_getlong)(); /* get a long from underlying stream */
+ bool_t (*x_putlong)(); /* put a long to underlying stream */
+ bool_t (*x_getbytes)(); /* get bytes from underlying stream */
+ bool_t (*x_putbytes)(); /* put bytes to underlying stream */
+ u_int (*x_getpostn)(); /* returns bytes off from beginning */
+ bool_t (*x_setpostn)(); /* lets you reposition the stream */
+ long * (*x_inline)(); /* buf quick ptr to buffered data */
+ void (*x_destroy)(); /* free privates of this xdr_stream */
+ } *x_ops;
+ caddr_t x_public; /* users' data */
+ caddr_t x_private; /* pointer to private data */
+ caddr_t x_base; /* private used for position info */
+ u_int x_handy; /* extra private word */
+} XDR;
+
+/*
+ * The netbuf structure. This structure is defined in <xti.h> on SysV
+ * systems, but NetBSD / FreeBSD do not use XTI.
+ *
+ * Usually, buf will point to a struct sockaddr, and len and maxlen
+ * will contain the length and maximum length of that socket address,
+ * respectively.
+ */
+struct netbuf {
+ unsigned int maxlen;
+ unsigned int len;
+ void *buf;
+};
+
+/*
+ * The format of the address and options arguments of the XTI t_bind call.
+ * Only provided for compatibility, it should not be used other than
+ * as an argument to svc_tli_create().
+ */
+
+struct t_bind {
+ struct netbuf addr;
+ unsigned int qlen;
+};
+.Ed
+.Sh "Index to Routines"
+The following table lists RPC routines and the manual reference
+pages on which they are described:
+.Pp
+.Bl -tag -width "authunix_create_default()" -compact
+.It Em "RPC Routine"
+.Em "Manual Reference Page"
+.Pp
+.It Fn auth_destroy
+.Xr rpc_clnt_auth 3
+.It Fn authdes_create
+.Xr rpc_soc 3
+.It Fn authnone_create
+.Xr rpc_clnt_auth 3
+.It Fn authsys_create
+.Xr rpc_clnt_auth 3
+.It Fn authsys_create_default
+.Xr rpc_clnt_auth 3
+.It Fn authunix_create
+.Xr rpc_soc 3
+.It Fn authunix_create_default
+.Xr rpc_soc 3
+.It Fn callrpc
+.Xr rpc_soc 3
+.It Fn clnt_broadcast
+.Xr rpc_soc 3
+.It Fn clnt_call
+.Xr rpc_clnt_calls 3
+.It Fn clnt_control
+.Xr rpc_clnt_create 3
+.It Fn clnt_create
+.Xr rpc_clnt_create 3
+.It Fn clnt_create_timed
+.Xr rpc_clnt_create 3
+.It Fn clnt_create_vers
+.Xr rpc_clnt_create 3
+.It Fn clnt_create_vers_timed
+.Xr rpc_clnt_create 3
+.It Fn clnt_destroy
+.Xr rpc_clnt_create 3
+.It Fn clnt_dg_create
+.Xr rpc_clnt_create 3
+.It Fn clnt_freeres
+.Xr rpc_clnt_calls 3
+.It Fn clnt_geterr
+.Xr rpc_clnt_calls 3
+.It Fn clnt_pcreateerror
+.Xr rpc_clnt_create 3
+.It Fn clnt_perrno
+.Xr rpc_clnt_calls 3
+.It Fn clnt_perror
+.Xr rpc_clnt_calls 3
+.It Fn clnt_raw_create
+.Xr rpc_clnt_create 3
+.It Fn clnt_spcreateerror
+.Xr rpc_clnt_create 3
+.It Fn clnt_sperrno
+.Xr rpc_clnt_calls 3
+.It Fn clnt_sperror
+.Xr rpc_clnt_calls 3
+.It Fn clnt_tli_create
+.Xr rpc_clnt_create 3
+.It Fn clnt_tp_create
+.Xr rpc_clnt_create 3
+.It Fn clnt_tp_create_timed
+.Xr rpc_clnt_create 3
+.It Fn clnt_udpcreate
+.Xr rpc_soc 3
+.It Fn clnt_vc_create
+.Xr rpc_clnt_create 3
+.It Fn clntraw_create
+.Xr rpc_soc 3
+.It Fn clnttcp_create
+.Xr rpc_soc 3
+.It Fn clntudp_bufcreate
+.Xr rpc_soc 3
+.It Fn get_myaddress
+.Xr rpc_soc 3
+.It Fn pmap_getmaps
+.Xr rpc_soc 3
+.It Fn pmap_getport
+.Xr rpc_soc 3
+.It Fn pmap_rmtcall
+.Xr rpc_soc 3
+.It Fn pmap_set
+.Xr rpc_soc 3
+.It Fn pmap_unset
+.Xr rpc_soc 3
+.It Fn registerrpc
+.Xr rpc_soc 3
+.It Fn rpc_broadcast
+.Xr rpc_clnt_calls 3
+.It Fn rpc_broadcast_exp
+.Xr rpc_clnt_calls 3
+.It Fn rpc_call
+.Xr rpc_clnt_calls 3
+.It Fn rpc_reg
+.Xr rpc_svc_calls 3
+.It Fn svc_create
+.Xr rpc_svc_create 3
+.It Fn svc_destroy
+.Xr rpc_svc_create 3
+.It Fn svc_dg_create
+.Xr rpc_svc_create 3
+.It Fn svc_dg_enablecache
+.Xr rpc_svc_calls 3
+.It Fn svc_fd_create
+.Xr rpc_svc_create 3
+.It Fn svc_fds
+.Xr rpc_soc 3
+.It Fn svc_freeargs
+.Xr rpc_svc_reg 3
+.It Fn svc_getargs
+.Xr rpc_svc_reg 3
+.It Fn svc_getcaller
+.Xr rpc_soc 3
+.It Fn svc_getreq
+.Xr rpc_soc 3
+.It Fn svc_getreqset
+.Xr rpc_svc_calls 3
+.It Fn svc_getrpccaller
+.Xr rpc_svc_calls 3
+.It Fn svc_kerb_reg
+.Xr kerberos_rpc 3
+.It Fn svc_raw_create
+.Xr rpc_svc_create 3
+.It Fn svc_reg
+.Xr rpc_svc_calls 3
+.It Fn svc_register
+.Xr rpc_soc 3
+.It Fn svc_run
+.Xr rpc_svc_reg 3
+.It Fn svc_sendreply
+.Xr rpc_svc_reg 3
+.It Fn svc_tli_create
+.Xr rpc_svc_create 3
+.It Fn svc_tp_create
+.Xr rpc_svc_create 3
+.It Fn svc_unreg
+.Xr rpc_svc_calls 3
+.It Fn svc_unregister
+.Xr rpc_soc 3
+.It Fn svc_vc_create
+.Xr rpc_svc_create 3
+.It Fn svcerr_auth
+.Xr rpc_svc_err 3
+.It Fn svcerr_decode
+.Xr rpc_svc_err 3
+.It Fn svcerr_noproc
+.Xr rpc_svc_err 3
+.It Fn svcerr_noprog
+.Xr rpc_svc_err 3
+.It Fn svcerr_progvers
+.Xr rpc_svc_err 3
+.It Fn svcerr_systemerr
+.Xr rpc_svc_err 3
+.It Fn svcerr_weakauth
+.Xr rpc_svc_err 3
+.It Fn svcfd_create
+.Xr rpc_soc 3
+.It Fn svcraw_create
+.Xr rpc_soc 3
+.It Fn svctcp_create
+.Xr rpc_soc 3
+.It Fn svcudp_bufcreate
+.Xr rpc_soc 3
+.It Fn svcudp_create
+.Xr rpc_soc 3
+.It Fn xdr_accepted_reply
+.Xr rpc_xdr 3
+.It Fn xdr_authsys_parms
+.Xr rpc_xdr 3
+.It Fn xdr_authunix_parms
+.Xr rpc_soc 3
+.It Fn xdr_callhdr
+.Xr rpc_xdr 3
+.It Fn xdr_callmsg
+.Xr rpc_xdr 3
+.It Fn xdr_opaque_auth
+.Xr rpc_xdr 3
+.It Fn xdr_rejected_reply
+.Xr rpc_xdr 3
+.It Fn xdr_replymsg
+.Xr rpc_xdr 3
+.It Fn xprt_register
+.Xr rpc_svc_calls 3
+.It Fn xprt_unregister
+.Xr rpc_svc_calls 3
+.El
+.Sh FILES
+.Bl -tag -width /etc/netconfig
+.It Pa /etc/netconfig
+.El
+.Sh SEE ALSO
+.Xr getnetconfig 3 ,
+.Xr getnetpath 3 ,
+.Xr rpc_clnt_auth 3 ,
+.Xr rpc_clnt_calls 3 ,
+.Xr rpc_clnt_create 3 ,
+.Xr rpc_svc_calls 3 ,
+.Xr rpc_svc_create 3 ,
+.Xr rpc_svc_err 3 ,
+.Xr rpc_svc_reg 3 ,
+.Xr rpc_xdr 3 ,
+.Xr rpcbind 3 ,
+.Xr xdr 3 ,
+.Xr netconfig 5
diff --git a/lib/libc/rpc/rpc.5 b/lib/libc/rpc/rpc.5
new file mode 100644
index 000000000000..398d9aa4b420
--- /dev/null
+++ b/lib/libc/rpc/rpc.5
@@ -0,0 +1,59 @@
+.\" $NetBSD: rpc.5,v 1.3 2000/06/15 20:05:54 fvdl Exp $
+.\" $FreeBSD$
+.\" @(#)rpc.4 1.17 93/08/30 SMI; from SVr4
+.\" Copyright 1989 AT&T
+.Dd December 10, 1991
+.Dt RPC 5
+.Os
+.Sh NAME
+.Nm rpc
+.Nd rpc program number data base
+.Sh SYNOPSIS
+.Pa /etc/rpc
+.Sh DESCRIPTION
+The
+.Nm
+file contains user readable names that
+can be used in place of RPC program numbers.
+For each RPC program a single line should be present
+with the following information:
+.Pp
+.Bl -enum -compact
+.It
+name of the RPC program
+.It
+RPC program number
+.It
+aliases
+.El
+.Pp
+Items are separated by any number of blanks and/or
+tab characters.
+A hash
+.Pq Dq Li #
+indicates the beginning of a comment; characters up to the end of
+the line are not interpreted by routines which search the file.
+.Sh FILES
+.Bl -tag -width /etc/nsswitch.conf -compact
+.It Pa /etc/nsswitch.conf
+.El
+.Sh EXAMPLES
+Below is an example of an RPC database:
+.Bd -literal
+#
+# rpc
+#
+rpcbind 100000 portmap sunrpc portmapper
+rusersd 100002 rusers
+nfs 100003 nfsprog
+mountd 100005 mount showmount
+walld 100008 rwall shutdown
+sprayd 100012 spray
+llockmgr 100020
+nlockmgr 100021
+status 100024
+bootparam 100026
+keyserv 100029 keyserver
+.Ed
+.Sh SEE ALSO
+.Xr getrpcent 3
diff --git a/lib/libc/rpc/rpc_callmsg.c b/lib/libc/rpc/rpc_callmsg.c
new file mode 100644
index 000000000000..4063e8bf895d
--- /dev/null
+++ b/lib/libc/rpc/rpc_callmsg.c
@@ -0,0 +1,204 @@
+/* $NetBSD: rpc_callmsg.c,v 1.16 2000/07/14 08:40:42 fvdl Exp $ */
+
+/*-
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *sccsid2 = "@(#)rpc_callmsg.c 1.4 87/08/11 Copyr 1984 Sun Micro";
+static char *sccsid = "@(#)rpc_callmsg.c 2.1 88/07/29 4.0 RPCSRC";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * rpc_callmsg.c
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ */
+
+#include "namespace.h"
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <rpc/rpc.h>
+#include "un-namespace.h"
+
+/*
+ * XDR a call message
+ */
+bool_t
+xdr_callmsg(XDR *xdrs, struct rpc_msg *cmsg)
+{
+ enum msg_type *prm_direction;
+ int32_t *buf;
+ struct opaque_auth *oa;
+
+ assert(xdrs != NULL);
+ assert(cmsg != NULL);
+
+ if (xdrs->x_op == XDR_ENCODE) {
+ if (cmsg->rm_call.cb_cred.oa_length > MAX_AUTH_BYTES) {
+ return (FALSE);
+ }
+ if (cmsg->rm_call.cb_verf.oa_length > MAX_AUTH_BYTES) {
+ return (FALSE);
+ }
+ buf = XDR_INLINE(xdrs, 8 * BYTES_PER_XDR_UNIT
+ + RNDUP(cmsg->rm_call.cb_cred.oa_length)
+ + 2 * BYTES_PER_XDR_UNIT
+ + RNDUP(cmsg->rm_call.cb_verf.oa_length));
+ if (buf != NULL) {
+ IXDR_PUT_INT32(buf, cmsg->rm_xid);
+ IXDR_PUT_ENUM(buf, cmsg->rm_direction);
+ if (cmsg->rm_direction != CALL) {
+ return (FALSE);
+ }
+ IXDR_PUT_INT32(buf, cmsg->rm_call.cb_rpcvers);
+ if (cmsg->rm_call.cb_rpcvers != RPC_MSG_VERSION) {
+ return (FALSE);
+ }
+ IXDR_PUT_INT32(buf, cmsg->rm_call.cb_prog);
+ IXDR_PUT_INT32(buf, cmsg->rm_call.cb_vers);
+ IXDR_PUT_INT32(buf, cmsg->rm_call.cb_proc);
+ oa = &cmsg->rm_call.cb_cred;
+ IXDR_PUT_ENUM(buf, oa->oa_flavor);
+ IXDR_PUT_INT32(buf, oa->oa_length);
+ if (oa->oa_length) {
+ memmove(buf, oa->oa_base, oa->oa_length);
+ buf += RNDUP(oa->oa_length) / sizeof (int32_t);
+ }
+ oa = &cmsg->rm_call.cb_verf;
+ IXDR_PUT_ENUM(buf, oa->oa_flavor);
+ IXDR_PUT_INT32(buf, oa->oa_length);
+ if (oa->oa_length) {
+ memmove(buf, oa->oa_base, oa->oa_length);
+ /* no real need....
+ buf += RNDUP(oa->oa_length) / sizeof (int32_t);
+ */
+ }
+ return (TRUE);
+ }
+ }
+ if (xdrs->x_op == XDR_DECODE) {
+ buf = XDR_INLINE(xdrs, 8 * BYTES_PER_XDR_UNIT);
+ if (buf != NULL) {
+ cmsg->rm_xid = IXDR_GET_U_INT32(buf);
+ cmsg->rm_direction = IXDR_GET_ENUM(buf, enum msg_type);
+ if (cmsg->rm_direction != CALL) {
+ return (FALSE);
+ }
+ cmsg->rm_call.cb_rpcvers = IXDR_GET_U_INT32(buf);
+ if (cmsg->rm_call.cb_rpcvers != RPC_MSG_VERSION) {
+ return (FALSE);
+ }
+ cmsg->rm_call.cb_prog = IXDR_GET_U_INT32(buf);
+ cmsg->rm_call.cb_vers = IXDR_GET_U_INT32(buf);
+ cmsg->rm_call.cb_proc = IXDR_GET_U_INT32(buf);
+ oa = &cmsg->rm_call.cb_cred;
+ oa->oa_flavor = IXDR_GET_ENUM(buf, enum_t);
+ oa->oa_length = (u_int)IXDR_GET_U_INT32(buf);
+ if (oa->oa_length) {
+ if (oa->oa_length > MAX_AUTH_BYTES) {
+ return (FALSE);
+ }
+ if (oa->oa_base == NULL) {
+ oa->oa_base = (caddr_t)
+ mem_alloc(oa->oa_length);
+ if (oa->oa_base == NULL)
+ return (FALSE);
+ }
+ buf = XDR_INLINE(xdrs, RNDUP(oa->oa_length));
+ if (buf == NULL) {
+ if (xdr_opaque(xdrs, oa->oa_base,
+ oa->oa_length) == FALSE) {
+ return (FALSE);
+ }
+ } else {
+ memmove(oa->oa_base, buf,
+ oa->oa_length);
+ /* no real need....
+ buf += RNDUP(oa->oa_length) /
+ sizeof (int32_t);
+ */
+ }
+ }
+ oa = &cmsg->rm_call.cb_verf;
+ buf = XDR_INLINE(xdrs, 2 * BYTES_PER_XDR_UNIT);
+ if (buf == NULL) {
+ if (xdr_enum(xdrs, &oa->oa_flavor) == FALSE ||
+ xdr_u_int(xdrs, &oa->oa_length) == FALSE) {
+ return (FALSE);
+ }
+ } else {
+ oa->oa_flavor = IXDR_GET_ENUM(buf, enum_t);
+ oa->oa_length = (u_int)IXDR_GET_U_INT32(buf);
+ }
+ if (oa->oa_length) {
+ if (oa->oa_length > MAX_AUTH_BYTES) {
+ return (FALSE);
+ }
+ if (oa->oa_base == NULL) {
+ oa->oa_base = (caddr_t)
+ mem_alloc(oa->oa_length);
+ if (oa->oa_base == NULL)
+ return (FALSE);
+ }
+ buf = XDR_INLINE(xdrs, RNDUP(oa->oa_length));
+ if (buf == NULL) {
+ if (xdr_opaque(xdrs, oa->oa_base,
+ oa->oa_length) == FALSE) {
+ return (FALSE);
+ }
+ } else {
+ memmove(oa->oa_base, buf,
+ oa->oa_length);
+ /* no real need...
+ buf += RNDUP(oa->oa_length) /
+ sizeof (int32_t);
+ */
+ }
+ }
+ return (TRUE);
+ }
+ }
+ prm_direction = &cmsg->rm_direction;
+ if (
+ xdr_u_int32_t(xdrs, &(cmsg->rm_xid)) &&
+ xdr_enum(xdrs, (enum_t *) prm_direction) &&
+ (cmsg->rm_direction == CALL) &&
+ xdr_rpcvers(xdrs, &(cmsg->rm_call.cb_rpcvers)) &&
+ (cmsg->rm_call.cb_rpcvers == RPC_MSG_VERSION) &&
+ xdr_rpcprog(xdrs, &(cmsg->rm_call.cb_prog)) &&
+ xdr_rpcvers(xdrs, &(cmsg->rm_call.cb_vers)) &&
+ xdr_rpcproc(xdrs, &(cmsg->rm_call.cb_proc)) &&
+ xdr_opaque_auth(xdrs, &(cmsg->rm_call.cb_cred)) )
+ return (xdr_opaque_auth(xdrs, &(cmsg->rm_call.cb_verf)));
+ return (FALSE);
+}
diff --git a/lib/libc/rpc/rpc_clnt_auth.3 b/lib/libc/rpc/rpc_clnt_auth.3
new file mode 100644
index 000000000000..863707e3da5e
--- /dev/null
+++ b/lib/libc/rpc/rpc_clnt_auth.3
@@ -0,0 +1,96 @@
+.\" @(#)rpc_clnt_auth.3n 1.21 93/05/07 SMI; from SVr4
+.\" Copyright 1989 AT&T
+.\" @(#)rpc_clnt_auth 1.4 89/07/20 SMI;
+.\" Copyright (c) 1988 Sun Microsystems, Inc. - All Rights Reserved.
+.\" $NetBSD: rpc_clnt_auth.3,v 1.1 2000/06/03 09:29:50 fvdl Exp $
+.\" $FreeBSD$
+.Dd May 7, 1993
+.Dt RPC_CLNT_AUTH 3
+.Os
+.Sh NAME
+.Nm auth_destroy ,
+.Nm authnone_create ,
+.Nm authsys_create ,
+.Nm authsys_create_default
+.Nd library routines for client side remote procedure call authentication
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In rpc/rpc.h
+.Ft "void"
+.Fn auth_destroy "AUTH *auth"
+.Ft "AUTH *"
+.Fn authnone_create "void"
+.Ft "AUTH *"
+.Fn authsys_create "const char *host" "const uid_t uid" "const gid_t gid" "const int len" "const gid_t *aup_gids"
+.Ft "AUTH *"
+.Fn authsys_create_default "void"
+.Sh DESCRIPTION
+These routines are part of the
+RPC library that allows C language programs to make procedure
+calls on other machines across the network,
+with desired authentication.
+.Pp
+These routines are normally called after creating the
+.Vt CLIENT
+handle.
+The
+.Va cl_auth
+field of the
+.Vt CLIENT
+structure should be initialized by the
+.Vt AUTH
+structure returned by some of the following routines.
+The client's authentication information
+is passed to the server when the
+RPC
+call is made.
+.Pp
+Only the
+.Dv NULL
+and the
+.Dv SYS
+style of authentication is discussed here.
+.Sh Routines
+.Bl -tag -width authsys_create_default()
+.It Fn auth_destroy
+A function macro that destroys the authentication
+information associated with
+.Fa auth .
+Destruction usually involves deallocation
+of private data structures.
+The use of
+.Fa auth
+is undefined after calling
+.Fn auth_destroy .
+.It Fn authnone_create
+Create and return an RPC
+authentication handle that passes nonusable
+authentication information with each remote procedure call.
+This is the default authentication used by RPC.
+.It Fn authsys_create
+Create and return an RPC authentication handle that contains
+.Dv AUTH_SYS
+authentication information.
+The
+.Fa host
+argument
+is the name of the machine on which the information was
+created;
+.Fa uid
+is the user's user ID;
+.Fa gid
+is the user's current group ID;
+.Fa len
+and
+.Fa aup_gids
+refer to a counted array of groups to which the user belongs.
+.It Fn authsys_create_default
+Call
+.Fn authsys_create
+with the appropriate arguments.
+.El
+.Sh SEE ALSO
+.Xr rpc 3 ,
+.Xr rpc_clnt_calls 3 ,
+.Xr rpc_clnt_create 3
diff --git a/lib/libc/rpc/rpc_clnt_calls.3 b/lib/libc/rpc/rpc_clnt_calls.3
new file mode 100644
index 000000000000..213a7d184811
--- /dev/null
+++ b/lib/libc/rpc/rpc_clnt_calls.3
@@ -0,0 +1,316 @@
+.\" @(#)rpc_clnt_calls.3n 1.30 93/08/31 SMI; from SVr4
+.\" Copyright 1989 AT&T
+.\" @(#)rpc_clnt_calls 1.4 89/07/20 SMI;
+.\" Copyright (c) 1988 Sun Microsystems, Inc. - All Rights Reserved.
+.\" $FreeBSD$
+.Dd May 7, 1993
+.Dt RPC_CLNT_CALLS 3
+.Os
+.Sh NAME
+.Nm rpc_clnt_calls ,
+.Nm clnt_call ,
+.Nm clnt_freeres ,
+.Nm clnt_geterr ,
+.Nm clnt_perrno ,
+.Nm clnt_perror ,
+.Nm clnt_sperrno ,
+.Nm clnt_sperror ,
+.Nm rpc_broadcast ,
+.Nm rpc_broadcast_exp ,
+.Nm rpc_call
+.Nd library routines for client side calls
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In rpc/rpc.h
+.Ft "enum clnt_stat"
+.Fn clnt_call "CLIENT *clnt" "const rpcproc_t procnum" "const xdrproc_t inproc" "const caddr_t in" "const xdrproc_t outproc" "caddr_t out" "const struct timeval tout"
+.Ft bool_t
+.Fn clnt_freeres "CLIENT *clnt" "const xdrproc_t outproc" "caddr_t out"
+.Ft void
+.Fn clnt_geterr "const CLIENT * clnt" "struct rpc_err * errp"
+.Ft void
+.Fn clnt_perrno "const enum clnt_stat stat"
+.Ft void
+.Fn clnt_perror "CLIENT *clnt" "const char *s"
+.Ft "char *"
+.Fn clnt_sperrno "const enum clnt_stat stat"
+.Ft "char *"
+.Fn clnt_sperror "CLIENT *clnt" "const char * s"
+.Ft "enum clnt_stat"
+.Fo rpc_broadcast
+.Fa "const rpcprog_t prognum" "const rpcvers_t versnum"
+.Fa "const rpcproc_t procnum" "const xdrproc_t inproc"
+.Fa "const caddr_t in" "const xdrproc_t outproc" "caddr_t out"
+.Fa "const resultproc_t eachresult" "const char *nettype"
+.Fc
+.Ft "enum clnt_stat"
+.Fo rpc_broadcast_exp
+.Fa "const rpcprog_t prognum" "const rpcvers_t versnum"
+.Fa "const rpcproc_t procnum" "const xdrproc_t xargs"
+.Fa "caddr_t argsp" "const xdrproc_t xresults"
+.Fa "caddr_t resultsp" "const resultproc_t eachresult"
+.Fa "const int inittime" "const int waittime"
+.Fa "const char * nettype"
+.Fc
+.Ft "enum clnt_stat"
+.Fo rpc_call
+.Fa "const char *host" "const rpcprog_t prognum"
+.Fa "const rpcvers_t versnum" "const rpcproc_t procnum"
+.Fa "const xdrproc_t inproc" "const char *in"
+.Fa "const xdrproc_t outproc" "char *out" "const char *nettype"
+.Fc
+.Sh DESCRIPTION
+RPC library routines allow C language programs to make procedure
+calls on other machines across the network.
+First, the client calls a procedure to send a request to the server.
+Upon receipt of the request, the server calls a dispatch routine
+to perform the requested service, and then sends back a reply.
+.Pp
+The
+.Fn clnt_call ,
+.Fn rpc_call ,
+and
+.Fn rpc_broadcast
+routines handle the client side of the procedure call.
+The remaining routines deal with error handling in the case of errors.
+.Pp
+Some of the routines take a
+.Vt CLIENT
+handle as one of the arguments.
+A
+.Vt CLIENT
+handle can be created by an RPC creation routine such as
+.Fn clnt_create
+(see
+.Xr rpc_clnt_create 3 ) .
+.Pp
+These routines are safe for use in multithreaded applications.
+.Vt CLIENT
+handles can be shared between threads, however in this implementation
+requests by different threads are serialized (that is, the first request will
+receive its results before the second request is sent).
+.Sh Routines
+See
+.Xr rpc 3
+for the definition of the
+.Vt CLIENT
+data structure.
+.Bl -tag -width XXXXX
+.It Fn clnt_call
+A function macro that calls the remote procedure
+.Fa procnum
+associated with the client handle,
+.Fa clnt ,
+which is obtained with an RPC
+client creation routine such as
+.Fn clnt_create
+(see
+.Xr rpc_clnt_create 3 ) .
+The
+.Fa inproc
+argument
+is the XDR function used to encode the procedure's arguments, and
+.Fa outproc
+is the XDR function used to decode the procedure's results;
+.Fa in
+is the address of the procedure's argument(s), and
+.Fa out
+is the address of where to place the result(s).
+The
+.Fa tout
+argument
+is the time allowed for results to be returned, which is overridden by
+a time-out set explicitly through
+.Fn clnt_control ,
+see
+.Xr rpc_clnt_create 3 .
+If the remote call succeeds, the status returned is
+.Dv RPC_SUCCESS ,
+otherwise an appropriate status is returned.
+.It Fn clnt_freeres
+A function macro that frees any data allocated by the
+RPC/XDR system when it decoded the results of an RPC call.
+The
+.Fa out
+argument
+is the address of the results, and
+.Fa outproc
+is the XDR routine describing the results.
+This routine returns 1 if the results were successfully freed,
+and 0 otherwise.
+.It Fn clnt_geterr
+A function macro that copies the error structure out of the client
+handle to the structure at address
+.Fa errp .
+.It Fn clnt_perrno
+Print a message to standard error corresponding
+to the condition indicated by
+.Fa stat .
+A newline is appended.
+Normally used after a procedure call fails for a routine
+for which a client handle is not needed, for instance
+.Fn rpc_call .
+.It Fn clnt_perror
+Print a message to the standard error indicating why an
+RPC call failed;
+.Fa clnt
+is the handle used to do the call.
+The message is prepended with string
+.Fa s
+and a colon.
+A newline is appended.
+Normally used after a remote procedure call fails
+for a routine which requires a client handle,
+for instance
+.Fn clnt_call .
+.It Fn clnt_sperrno
+Take the same arguments as
+.Fn clnt_perrno ,
+but instead of sending a message to the standard error
+indicating why an RPC
+call failed, return a pointer to a string which contains the message.
+The
+.Fn clnt_sperrno
+function
+is normally used instead of
+.Fn clnt_perrno
+when the program does not have a standard error (as a program
+running as a server quite likely does not), or if the programmer
+does not want the message to be output with
+.Fn printf
+(see
+.Xr printf 3 ) ,
+or if a message format different than that supported by
+.Fn clnt_perrno
+is to be used.
+Note:
+unlike
+.Fn clnt_sperror
+and
+.Fn clnt_spcreateerror
+(see
+.Xr rpc_clnt_create 3 ) ,
+.Fn clnt_sperrno
+does not return pointer to static data so the
+result will not get overwritten on each call.
+.It Fn clnt_sperror
+Like
+.Fn clnt_perror ,
+except that (like
+.Fn clnt_sperrno )
+it returns a string instead of printing to standard error.
+However,
+.Fn clnt_sperror
+does not append a newline at the end of the message.
+Warning:
+returns pointer to a buffer that is overwritten
+on each call.
+.It Fn rpc_broadcast
+Like
+.Fn rpc_call ,
+except the call message is broadcast to
+all the connectionless transports specified by
+.Fa nettype .
+If
+.Fa nettype
+is
+.Dv NULL ,
+it defaults to
+.Qq netpath .
+Each time it receives a response,
+this routine calls
+.Fn eachresult ,
+whose form is:
+.Ft bool_t
+.Fn eachresult "caddr_t out" "const struct netbuf * addr" "const struct netconfig * netconf"
+where
+.Fa out
+is the same as
+.Fa out
+passed to
+.Fn rpc_broadcast ,
+except that the remote procedure's output is decoded there;
+.Fa addr
+points to the address of the machine that sent the results, and
+.Fa netconf
+is the netconfig structure of the transport on which the remote
+server responded.
+If
+.Fn eachresult
+returns 0,
+.Fn rpc_broadcast
+waits for more replies;
+otherwise it returns with appropriate status.
+Warning:
+broadcast file descriptors are limited in size to the
+maximum transfer size of that transport.
+For Ethernet, this value is 1500 bytes.
+The
+.Fn rpc_broadcast
+function
+uses
+.Dv AUTH_SYS
+credentials by default (see
+.Xr rpc_clnt_auth 3 ) .
+.It Fn rpc_broadcast_exp
+Like
+.Fn rpc_broadcast ,
+except that the initial timeout,
+.Fa inittime
+and the maximum timeout,
+.Fa waittime
+are specified in milliseconds.
+The
+.Fa inittime
+argument
+is the initial time that
+.Fn rpc_broadcast_exp
+waits before resending the request.
+After the first resend, the re-transmission interval
+increases exponentially until it exceeds
+.Fa waittime .
+.It Fn rpc_call
+Call the remote procedure associated with
+.Fa prognum ,
+.Fa versnum ,
+and
+.Fa procnum
+on the machine,
+.Fa host .
+The
+.Fa inproc
+argument
+is used to encode the procedure's arguments, and
+.Fa outproc
+is used to decode the procedure's results;
+.Fa in
+is the address of the procedure's argument(s), and
+.Fa out
+is the address of where to place the result(s).
+The
+.Fa nettype
+argument
+can be any of the values listed on
+.Xr rpc 3 .
+This routine returns
+.Dv RPC_SUCCESS
+if it succeeds,
+or an appropriate status is returned.
+Use the
+.Fn clnt_perrno
+routine to translate failure status into error messages.
+Warning:
+.Fn rpc_call
+uses the first available transport belonging
+to the class
+.Fa nettype ,
+on which it can create a connection.
+You do not have control of timeouts or authentication
+using this routine.
+.El
+.Sh SEE ALSO
+.Xr printf 3 ,
+.Xr rpc 3 ,
+.Xr rpc_clnt_auth 3 ,
+.Xr rpc_clnt_create 3
diff --git a/lib/libc/rpc/rpc_clnt_create.3 b/lib/libc/rpc/rpc_clnt_create.3
new file mode 100644
index 000000000000..079c9eb729bf
--- /dev/null
+++ b/lib/libc/rpc/rpc_clnt_create.3
@@ -0,0 +1,514 @@
+.\" @(#)rpc_clnt_create.3n 1.36 93/08/31 SMI; from SVr4
+.\" Copyright 1989 AT&T
+.\" @(#)rpc_clnt_create 1.5 89/07/24 SMI;
+.\" Copyright (c) 1988 Sun Microsystems, Inc. - All Rights Reserved.
+.\" $NetBSD: rpc_clnt_create.3,v 1.2 2000/06/20 00:53:08 fvdl Exp $
+.\" $FreeBSD$
+.Dd May 7, 1993
+.Dt RPC_CLNT_CREATE 3
+.Os
+.Sh NAME
+.Nm rpc_clnt_create ,
+.Nm clnt_control ,
+.Nm clnt_create ,
+.Nm clnt_create_timed ,
+.Nm clnt_create_vers ,
+.Nm clnt_create_vers_timed ,
+.Nm clnt_destroy ,
+.Nm clnt_dg_create ,
+.Nm clnt_pcreateerror ,
+.Nm clnt_raw_create ,
+.Nm clnt_spcreateerror ,
+.Nm clnt_tli_create ,
+.Nm clnt_tp_create ,
+.Nm clnt_tp_create_timed ,
+.Nm clnt_vc_create ,
+.Nm rpc_createerr
+.Nd "library routines for dealing with creation and manipulation of"
+.Vt CLIENT
+handles
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In rpc/rpc.h
+.Ft bool_t
+.Fn clnt_control "CLIENT *clnt" "const u_int req" "char *info"
+.Ft "CLIENT *"
+.Fn clnt_create "const char * host" "const rpcprog_t prognum" "const rpcvers_t versnum" "const char *nettype"
+.Ft "CLIENT *"
+.Fn clnt_create_timed "const char * host" "const rpcprog_t prognum" "const rpcvers_t versnum" "const char *nettype" "const struct timeval *timeout"
+.Ft "CLIENT *"
+.Fn clnt_create_vers "const char * host" "const rpcprog_t prognum" "rpcvers_t *vers_outp" "const rpcvers_t vers_low" "const rpcvers_t vers_high" "const char *nettype"
+.Ft "CLIENT *"
+.Fn clnt_create_vers_timed "const char * host" "const rpcprog_t prognum" "rpcvers_t *vers_outp" "const rpcvers_t vers_low" "const rpcvers_t vers_high" "const char *nettype" "const struct timeval *timeout"
+.Ft void
+.Fn clnt_destroy "CLIENT *clnt"
+.Ft "CLIENT *"
+.Fn clnt_dg_create "const int fildes" "const struct netbuf *svcaddr" "const rpcprog_t prognum" "const rpcvers_t versnum" "const u_int sendsz" "const u_int recvsz"
+.Ft void
+.Fn clnt_pcreateerror "const char *s"
+.Ft "char *"
+.Fn clnt_spcreateerror "const char *s"
+.Ft "CLIENT *"
+.Fn clnt_raw_create "const rpcprog_t prognum" "const rpcvers_t versnum"
+.Ft "CLIENT *"
+.Fn clnt_tli_create "const int fildes" "const struct netconfig *netconf" "struct netbuf *svcaddr" "const rpcprog_t prognum" "const rpcvers_t versnum" "const u_int sendsz" "const u_int recvsz"
+.Ft "CLIENT *"
+.Fn clnt_tp_create "const char * host" "const rpcprog_t prognum" "const rpcvers_t versnum" "const struct netconfig *netconf"
+.Ft "CLIENT *"
+.Fn clnt_tp_create_timed "const char * host" "const rpcprog_t prognum" "const rpcvers_t versnum" "const struct netconfig *netconf" "const struct timeval *timeout"
+.Ft "CLIENT *"
+.Fn clnt_vc_create "const int fildes" "const struct netbuf *svcaddr" "const rpcprog_t prognum" "const rpcvers_t versnum" "u_int sendsz" "u_int recvsz"
+.Sh DESCRIPTION
+RPC library routines allow C language programs to make procedure
+calls on other machines across the network.
+First a
+.Vt CLIENT
+handle is created and then the client calls a procedure to send a
+request to the server.
+On receipt of the request, the server calls a dispatch routine
+to perform the requested service, and then sends a reply.
+.Sh Routines
+.Bl -tag -width YYYYYYY
+.It Fn clnt_control
+A function macro to change or retrieve various information
+about a client object.
+The
+.Fa req
+argument
+indicates the type of operation, and
+.Fa info
+is a pointer to the information.
+For both connectionless and connection-oriented transports,
+the supported values of
+.Fa req
+and their argument types and what they do are:
+.Bl -column "CLSET_FD_NCLOSE" "struct timeval *" "set total timeout"
+.It Dv CLSET_TIMEOUT Ta "struct timeval *" Ta "set total timeout"
+.It Dv CLGET_TIMEOUT Ta "struct timeval *" Ta "get total timeout"
+.El
+.Pp
+Note:
+if you set the timeout using
+.Fn clnt_control ,
+the timeout argument passed by
+.Fn clnt_call
+is ignored in all subsequent calls.
+.Pp
+Note:
+If you set the timeout value to 0,
+.Fn clnt_control
+immediately returns an error
+.Pq Dv RPC_TIMEDOUT .
+Set the timeout argument to 0 for batching calls.
+.Bl -column CLSET_FD_NCLOSE "struct timeval *"
+.It Dv CLGET_SVC_ADDR Ta "struct netbuf *" Ta "get servers address"
+.It Dv CLGET_FD Ta "int *" Ta "get fd from handle"
+.It Dv CLSET_FD_CLOSE Ta "void" Ta "close fd on destroy"
+.It Dv CLSET_FD_NCLOSE Ta void Ta "do not close fd on destroy"
+.It Dv CLGET_VERS Ta "uint32_t *" Ta "get RPC program version"
+.It Dv CLSET_VERS Ta "uint32_t *" Ta "set RPC program version"
+.It Dv CLGET_XID Ta "uint32_t *" Ta "get XID of previous call"
+.It Dv CLSET_XID Ta "uint32_t *" Ta "set XID of next call"
+.El
+.Pp
+The following operations are valid for connectionless transports only:
+.Bl -column CLSET_RETRY_TIMEOUT "struct timeval *" "set total timeout"
+.It Dv CLSET_RETRY_TIMEOUT Ta "struct timeval *" Ta "set the retry timeout"
+.It Dv CLGET_RETRY_TIMEOUT Ta "struct timeval *" Ta "get the retry timeout"
+.It Dv CLSET_CONNECT Ta Vt "int *" Ta use Xr connect 2
+.El
+.Pp
+The retry timeout is the time that RPC
+waits for the server to reply before retransmitting the request.
+The
+.Fn clnt_control
+function
+returns
+.Dv TRUE
+on success and
+.Dv FALSE
+on failure.
+.It Fn clnt_create
+Generic client creation routine for program
+.Fa prognum
+and version
+.Fa versnum .
+The
+.Fa host
+argument
+identifies the name of the remote host where the server
+is located.
+The
+.Fa nettype
+argument
+indicates the class of transport protocol to use.
+The transports are tried in left to right order in
+.Ev NETPATH
+environment variable or in top to bottom order in
+the netconfig database.
+The
+.Fn clnt_create
+function
+tries all the transports of the
+.Fa nettype
+class available from the
+.Ev NETPATH
+environment variable and the netconfig database,
+and chooses the first successful one.
+A default timeout is set and can be modified using
+.Fn clnt_control .
+This routine returns
+.Dv NULL
+if it fails.
+The
+.Fn clnt_pcreateerror
+routine can be used to print the reason for failure.
+.Pp
+Note:
+.Fn clnt_create
+returns a valid client handle even
+if the particular version number supplied to
+.Fn clnt_create
+is not registered with the
+.Xr rpcbind 8
+service.
+This mismatch will be discovered by a
+.Fn clnt_call
+later (see
+.Xr rpc_clnt_calls 3 ) .
+.It Fn clnt_create_timed
+Generic client creation routine which is similar to
+.Fn clnt_create
+but which also has the additional argument
+.Fa timeout
+that specifies the maximum amount of time allowed for
+each transport class tried.
+In all other respects, the
+.Fn clnt_create_timed
+call behaves exactly like the
+.Fn clnt_create
+call.
+.It Fn clnt_create_vers
+Generic client creation routine which is similar to
+.Fn clnt_create
+but which also checks for the
+version availability.
+The
+.Fa host
+argument
+identifies the name of the remote host where the server
+is located.
+The
+.Fa nettype
+argument
+indicates the class transport protocols to be used.
+If the routine is successful it returns a client handle created for
+the highest version between
+.Fa vers_low
+and
+.Fa vers_high
+that is supported by the server.
+The
+.Fa vers_outp
+argument
+is set to this value.
+That is, after a successful return
+.Fa vers_low
+<=
+.Fa *vers_outp
+<=
+.Fa vers_high .
+If no version between
+.Fa vers_low
+and
+.Fa vers_high
+is supported by the server then the routine fails and returns
+.Dv NULL .
+A default timeout is set and can be modified using
+.Fn clnt_control .
+This routine returns
+.Dv NULL
+if it fails.
+The
+.Fn clnt_pcreateerror
+routine can be used to print the reason for failure.
+Note:
+.Fn clnt_create
+returns a valid client handle even
+if the particular version number supplied to
+.Fn clnt_create
+is not registered with the
+.Xr rpcbind 8
+service.
+This mismatch will be discovered by a
+.Fn clnt_call
+later (see
+.Xr rpc_clnt_calls 3 ) .
+However,
+.Fn clnt_create_vers
+does this for you and returns a valid handle
+only if a version within
+the range supplied is supported by the server.
+.It Fn clnt_create_vers_timed
+Generic client creation routine which is similar to
+.Fn clnt_create_vers
+but which also has the additional argument
+.Fa timeout
+that specifies the maximum amount of time allowed for
+each transport class tried.
+In all other respects, the
+.Fn clnt_create_vers_timed
+call behaves exactly like the
+.Fn clnt_create_vers
+call.
+.It Fn clnt_destroy
+A function macro that destroys the client's RPC handle.
+Destruction usually involves deallocation
+of private data structures, including
+.Fa clnt
+itself.
+Use of
+.Fa clnt
+is undefined after calling
+.Fn clnt_destroy .
+If the RPC library opened the associated file descriptor, or
+.Dv CLSET_FD_CLOSE
+was set using
+.Fn clnt_control ,
+the file descriptor will be closed.
+The caller should call
+.Fn auth_destroy "clnt->cl_auth"
+(before calling
+.Fn clnt_destroy )
+to destroy the associated
+.Vt AUTH
+structure (see
+.Xr rpc_clnt_auth 3 ) .
+.It Fn clnt_dg_create
+This routine creates an RPC client for the remote program
+.Fa prognum
+and version
+.Fa versnum ;
+the client uses a connectionless transport.
+The remote program is located at address
+.Fa svcaddr .
+The
+.Fa fildes
+argument
+is an open and bound file descriptor.
+This routine will resend the call message in intervals of
+15 seconds until a response is received or until the
+call times out.
+The total time for the call to time out is specified by
+.Fn clnt_call
+(see
+.Fn clnt_call
+in
+.Xr rpc_clnt_calls 3 ) .
+The retry time out and the total time out periods can
+be changed using
+.Fn clnt_control .
+The user may set the size of the send and receive
+buffers with the
+.Fa sendsz
+and
+.Fa recvsz
+arguments;
+values of 0 choose suitable defaults.
+This routine returns
+.Dv NULL
+if it fails.
+.It Fn clnt_pcreateerror
+Print a message to standard error indicating
+why a client RPC handle could not be created.
+The message is prepended with the string
+.Fa s
+and a colon, and appended with a newline.
+.It Fn clnt_spcreateerror
+Like
+.Fn clnt_pcreateerror ,
+except that it returns a string
+instead of printing to the standard error.
+A newline is not appended to the message in this case.
+Warning:
+returns a pointer to a buffer that is overwritten
+on each call.
+.It Fn clnt_raw_create
+This routine creates an RPC
+client handle for the remote program
+.Fa prognum
+and version
+.Fa versnum .
+The transport used to pass messages to the service is
+a buffer within the process's address space,
+so the corresponding RPC
+server should live in the same address space;
+(see
+.Fn svc_raw_create
+in
+.Xr rpc_svc_create 3 ) .
+This allows simulation of RPC and measurement of
+RPC overheads, such as round trip times,
+without any kernel or networking interference.
+This routine returns
+.Dv NULL
+if it fails.
+The
+.Fn clnt_raw_create
+function
+should be called after
+.Fn svc_raw_create .
+.It Fn clnt_tli_create
+This routine creates an RPC
+client handle for the remote program
+.Fa prognum
+and version
+.Fa versnum .
+The remote program is located at address
+.Fa svcaddr .
+If
+.Fa svcaddr
+is
+.Dv NULL
+and it is connection-oriented, it is assumed that the file descriptor
+is connected.
+For connectionless transports, if
+.Fa svcaddr
+is
+.Dv NULL ,
+.Dv RPC_UNKNOWNADDR
+error is set.
+The
+.Fa fildes
+argument
+is a file descriptor which may be open, bound and connected.
+If it is
+.Dv RPC_ANYFD ,
+it opens a file descriptor on the transport specified by
+.Fa netconf .
+If
+.Fa fildes
+is
+.Dv RPC_ANYFD
+and
+.Fa netconf
+is
+.Dv NULL ,
+a
+.Dv RPC_UNKNOWNPROTO
+error is set.
+If
+.Fa fildes
+is unbound, then it will attempt to bind the descriptor.
+The user may specify the size of the buffers with the
+.Fa sendsz
+and
+.Fa recvsz
+arguments;
+values of 0 choose suitable defaults.
+Depending upon the type of the transport (connection-oriented
+or connectionless),
+.Fn clnt_tli_create
+calls appropriate client creation routines.
+This routine returns
+.Dv NULL
+if it fails.
+The
+.Fn clnt_pcreateerror
+routine can be used to print the reason for failure.
+The remote rpcbind
+service (see
+.Xr rpcbind 8 )
+is not consulted for the address of the remote
+service.
+.It Fn clnt_tp_create
+Like
+.Fn clnt_create
+except
+.Fn clnt_tp_create
+tries only one transport specified through
+.Fa netconf .
+The
+.Fn clnt_tp_create
+function
+creates a client handle for the program
+.Fa prognum ,
+the version
+.Fa versnum ,
+and for the transport specified by
+.Fa netconf .
+Default options are set,
+which can be changed using
+.Fn clnt_control
+calls.
+The remote rpcbind service on the host
+.Fa host
+is consulted for the address of the remote service.
+This routine returns
+.Dv NULL
+if it fails.
+The
+.Fn clnt_pcreateerror
+routine can be used to print the reason for failure.
+.It Fn clnt_tp_create_timed
+Like
+.Fn clnt_tp_create
+except
+.Fn clnt_tp_create_timed
+has the extra argument
+.Fa timeout
+which specifies the maximum time allowed for
+the creation attempt to succeed.
+In all other respects, the
+.Fn clnt_tp_create_timed
+call behaves exactly like the
+.Fn clnt_tp_create
+call.
+.It Fn clnt_vc_create
+This routine creates an RPC
+client for the remote program
+.Fa prognum
+and version
+.Fa versnum ;
+the client uses a connection-oriented transport.
+The remote program is located at address
+.Fa svcaddr .
+The
+.Fa fildes
+argument
+is an open and bound file descriptor.
+The user may specify the size of the send and receive buffers
+with the
+.Fa sendsz
+and
+.Fa recvsz
+arguments;
+values of 0 choose suitable defaults.
+This routine returns
+.Dv NULL
+if it fails.
+The address
+.Fa svcaddr
+should not be
+.Dv NULL
+and should point to the actual address of the remote program.
+The
+.Fn clnt_vc_create
+function
+does not consult the remote rpcbind service for this information.
+.It Xo
+.Vt "struct rpc_createerr" Va rpc_createerr ;
+.Xc
+A global variable whose value is set by any RPC
+client handle creation routine
+that fails.
+It is used by the routine
+.Fn clnt_pcreateerror
+to print the reason for the failure.
+.El
+.Sh SEE ALSO
+.Xr rpc 3 ,
+.Xr rpc_clnt_auth 3 ,
+.Xr rpc_clnt_calls 3 ,
+.Xr rpcbind 8
diff --git a/lib/libc/rpc/rpc_com.h b/lib/libc/rpc/rpc_com.h
new file mode 100644
index 000000000000..bfa6a0bca882
--- /dev/null
+++ b/lib/libc/rpc/rpc_com.h
@@ -0,0 +1,94 @@
+/* $NetBSD: rpc_com.h,v 1.3 2000/12/10 04:10:08 christos Exp $ */
+
+/*-
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+/*
+ * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc.
+ */
+
+/*
+ * rpc_com.h, Common definitions for both the server and client side.
+ * All for the topmost layer of rpc
+ *
+ * In Sun's tirpc distribution, this was installed as <rpc/rpc_com.h>,
+ * but as it contains only non-exported interfaces, it was moved here.
+ */
+
+#ifndef _RPC_RPCCOM_H
+#define _RPC_RPCCOM_H
+
+#include <sys/cdefs.h>
+
+/* #pragma ident "@(#)rpc_com.h 1.11 93/07/05 SMI" */
+
+/*
+ * The max size of the transport, if the size cannot be determined
+ * by other means.
+ */
+#define RPC_MAXDATASIZE 9000
+#define RPC_MAXADDRSIZE 1024
+
+#define __RPC_GETXID(now) ((u_int32_t)getpid() ^ (u_int32_t)(now)->tv_sec ^ \
+ (u_int32_t)(now)->tv_usec)
+
+__BEGIN_DECLS
+extern u_int __rpc_get_a_size(int);
+extern int __rpc_dtbsize(void);
+extern struct netconfig * __rpcgettp(int);
+extern int __rpc_get_default_domain(char **);
+
+char *__rpc_taddr2uaddr_af(int, const struct netbuf *);
+struct netbuf *__rpc_uaddr2taddr_af(int, const char *);
+int __rpc_fixup_addr(struct netbuf *, const struct netbuf *);
+int __rpc_sockinfo2netid(struct __rpc_sockinfo *, const char **);
+int __rpc_seman2socktype(int);
+int __rpc_socktype2seman(int);
+void *rpc_nullproc(CLIENT *);
+int __rpc_sockisbound(int);
+
+struct netbuf *__rpcb_findaddr_timed(rpcprog_t, rpcvers_t,
+ const struct netconfig *, const char *host, CLIENT **clpp,
+ struct timeval *tp);
+
+bool_t __rpc_control(int,void *);
+
+char *_get_next_token(char *, int);
+
+bool_t __svc_clean_idle(fd_set *, int, bool_t);
+bool_t __xdrrec_setnonblock(XDR *, int);
+bool_t __xdrrec_getrec(XDR *, enum xprt_stat *, bool_t);
+void __xprt_unregister_unlocked(SVCXPRT *);
+
+extern SVCXPRT **__svc_xports;
+extern int __svc_maxrec;
+
+__END_DECLS
+
+#endif /* _RPC_RPCCOM_H */
diff --git a/lib/libc/rpc/rpc_commondata.c b/lib/libc/rpc/rpc_commondata.c
new file mode 100644
index 000000000000..e63538d20c47
--- /dev/null
+++ b/lib/libc/rpc/rpc_commondata.c
@@ -0,0 +1,47 @@
+/* $NetBSD: rpc_commondata.c,v 1.7 2000/06/02 23:11:13 fvdl Exp $ */
+
+/*-
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *sccsid = "@(#)rpc_commondata.c 2.1 88/07/29 4.0 RPCSRC";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <rpc/rpc.h>
+#include "un-namespace.h"
+
+/*
+ * This file should only contain common data (global data) that is exported
+ * by public interfaces
+ */
+struct opaque_auth _null_auth;
+fd_set svc_fdset;
+int svc_maxfd = -1;
diff --git a/lib/libc/rpc/rpc_dtablesize.c b/lib/libc/rpc/rpc_dtablesize.c
new file mode 100644
index 000000000000..4bcb71f5c94d
--- /dev/null
+++ b/lib/libc/rpc/rpc_dtablesize.c
@@ -0,0 +1,66 @@
+/* $NetBSD: rpc_dtablesize.c,v 1.14 1998/11/15 17:32:43 christos Exp $ */
+
+/*-
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *sccsid2 = "@(#)rpc_dtablesize.c 1.2 87/08/11 Copyr 1987 Sun Micro";
+static char *sccsid = "@(#)rpc_dtablesize.c 2.1 88/07/29 4.0 RPCSRC";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <unistd.h>
+#include "un-namespace.h"
+
+int _rpc_dtablesize(void); /* XXX */
+
+/*
+ * Cache the result of getdtablesize(), so we don't have to do an
+ * expensive system call every time.
+ */
+/*
+ * XXX In FreeBSD 2.x, you can have the maximum number of open file
+ * descriptors be greater than FD_SETSIZE (which us 256 by default).
+ *
+ * Since old programs tend to use this call to determine the first arg
+ * for _select(), having this return > FD_SETSIZE is a Bad Idea(TM)!
+ */
+int
+_rpc_dtablesize(void)
+{
+ static int size;
+
+ if (size == 0) {
+ size = getdtablesize();
+ if (size > FD_SETSIZE)
+ size = FD_SETSIZE;
+ }
+ return (size);
+}
diff --git a/lib/libc/rpc/rpc_generic.c b/lib/libc/rpc/rpc_generic.c
new file mode 100644
index 000000000000..619fbf17bc52
--- /dev/null
+++ b/lib/libc/rpc/rpc_generic.c
@@ -0,0 +1,836 @@
+/* $NetBSD: rpc_generic.c,v 1.4 2000/09/28 09:07:04 kleink Exp $ */
+
+/*-
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 1986-1991 by Sun Microsystems Inc.
+ */
+
+/* #pragma ident "@(#)rpc_generic.c 1.17 94/04/24 SMI" */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * rpc_generic.c, Miscl routines for RPC.
+ *
+ */
+
+#include "namespace.h"
+#include "reentrant.h"
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/un.h>
+#include <sys/resource.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <rpc/rpc.h>
+#include <ctype.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <netdb.h>
+#include <netconfig.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <rpc/nettype.h>
+#include "un-namespace.h"
+#include "rpc_com.h"
+#include "mt_misc.h"
+
+struct handle {
+ NCONF_HANDLE *nhandle;
+ int nflag; /* Whether NETPATH or NETCONFIG */
+ int nettype;
+};
+
+static const struct _rpcnettype {
+ const char *name;
+ const int type;
+} _rpctypelist[] = {
+ { "netpath", _RPC_NETPATH },
+ { "visible", _RPC_VISIBLE },
+ { "circuit_v", _RPC_CIRCUIT_V },
+ { "datagram_v", _RPC_DATAGRAM_V },
+ { "circuit_n", _RPC_CIRCUIT_N },
+ { "datagram_n", _RPC_DATAGRAM_N },
+ { "tcp", _RPC_TCP },
+ { "udp", _RPC_UDP },
+ { 0, _RPC_NONE }
+};
+
+struct netid_af {
+ const char *netid;
+ int af;
+ int protocol;
+};
+
+static const struct netid_af na_cvt[] = {
+ { "udp", AF_INET, IPPROTO_UDP },
+ { "tcp", AF_INET, IPPROTO_TCP },
+#ifdef INET6
+ { "udp6", AF_INET6, IPPROTO_UDP },
+ { "tcp6", AF_INET6, IPPROTO_TCP },
+#endif
+ { "local", AF_LOCAL, 0 }
+};
+
+#if 0
+static char *strlocase(char *);
+#endif
+static int getnettype(const char *);
+
+/*
+ * Cache the result of getrlimit(), so we don't have to do an
+ * expensive call every time.
+ */
+int
+__rpc_dtbsize(void)
+{
+ static int tbsize;
+ struct rlimit rl;
+
+ if (tbsize) {
+ return (tbsize);
+ }
+ if (getrlimit(RLIMIT_NOFILE, &rl) == 0) {
+ return (tbsize = (int)rl.rlim_max);
+ }
+ /*
+ * Something wrong. I'll try to save face by returning a
+ * pessimistic number.
+ */
+ return (32);
+}
+
+
+/*
+ * Find the appropriate buffer size
+ *
+ * size - Size requested
+ */
+u_int
+/*ARGSUSED*/
+__rpc_get_t_size(int af, int proto, int size)
+{
+ int maxsize, defsize;
+
+ maxsize = 256 * 1024; /* XXX */
+ switch (proto) {
+ case IPPROTO_TCP:
+ defsize = 64 * 1024; /* XXX */
+ break;
+ case IPPROTO_UDP:
+ defsize = UDPMSGSIZE;
+ break;
+ default:
+ defsize = RPC_MAXDATASIZE;
+ break;
+ }
+ if (size == 0)
+ return defsize;
+
+ /* Check whether the value is within the upper max limit */
+ return (size > maxsize ? (u_int)maxsize : (u_int)size);
+}
+
+/*
+ * Find the appropriate address buffer size
+ */
+u_int
+__rpc_get_a_size(int af)
+{
+ switch (af) {
+ case AF_INET:
+ return sizeof (struct sockaddr_in);
+#ifdef INET6
+ case AF_INET6:
+ return sizeof (struct sockaddr_in6);
+#endif
+ case AF_LOCAL:
+ return sizeof (struct sockaddr_un);
+ default:
+ break;
+ }
+ return ((u_int)RPC_MAXADDRSIZE);
+}
+
+#if 0
+static char *
+strlocase(char *p)
+{
+ char *t = p;
+
+ for (; *p; p++)
+ if (isupper(*p))
+ *p = tolower(*p);
+ return (t);
+}
+#endif
+
+/*
+ * Returns the type of the network as defined in <rpc/nettype.h>
+ * If nettype is NULL, it defaults to NETPATH.
+ */
+static int
+getnettype(const char *nettype)
+{
+ int i;
+
+ if ((nettype == NULL) || (nettype[0] == 0)) {
+ return (_RPC_NETPATH); /* Default */
+ }
+
+#if 0
+ nettype = strlocase(nettype);
+#endif
+ for (i = 0; _rpctypelist[i].name; i++)
+ if (strcasecmp(nettype, _rpctypelist[i].name) == 0) {
+ return (_rpctypelist[i].type);
+ }
+ return (_rpctypelist[i].type);
+}
+
+static thread_key_t tcp_key, udp_key;
+static once_t keys_once = ONCE_INITIALIZER;
+static int tcp_key_error, udp_key_error;
+
+static void
+keys_init(void)
+{
+
+ tcp_key_error = thr_keycreate(&tcp_key, free);
+ udp_key_error = thr_keycreate(&udp_key, free);
+}
+
+/*
+ * For the given nettype (tcp or udp only), return the first structure found.
+ * This should be freed by calling freenetconfigent()
+ */
+struct netconfig *
+__rpc_getconfip(const char *nettype)
+{
+ char *netid;
+ char *netid_tcp = (char *) NULL;
+ char *netid_udp = (char *) NULL;
+ static char *netid_tcp_main;
+ static char *netid_udp_main;
+ struct netconfig *dummy;
+ int main_thread;
+
+ if ((main_thread = thr_main())) {
+ netid_udp = netid_udp_main;
+ netid_tcp = netid_tcp_main;
+ } else {
+ if (thr_once(&keys_once, keys_init) != 0 ||
+ tcp_key_error != 0 || udp_key_error != 0)
+ return (NULL);
+ netid_tcp = (char *)thr_getspecific(tcp_key);
+ netid_udp = (char *)thr_getspecific(udp_key);
+ }
+ if (!netid_udp && !netid_tcp) {
+ struct netconfig *nconf;
+ void *confighandle;
+
+ if (!(confighandle = setnetconfig())) {
+ syslog (LOG_ERR, "rpc: failed to open " NETCONFIG);
+ return (NULL);
+ }
+ while ((nconf = getnetconfig(confighandle)) != NULL) {
+ if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
+ if (strcmp(nconf->nc_proto, NC_TCP) == 0 &&
+ netid_tcp == NULL) {
+ netid_tcp = strdup(nconf->nc_netid);
+ if (main_thread)
+ netid_tcp_main = netid_tcp;
+ else
+ thr_setspecific(tcp_key,
+ (void *) netid_tcp);
+ } else
+ if (strcmp(nconf->nc_proto, NC_UDP) == 0 &&
+ netid_udp == NULL) {
+ netid_udp = strdup(nconf->nc_netid);
+ if (main_thread)
+ netid_udp_main = netid_udp;
+ else
+ thr_setspecific(udp_key,
+ (void *) netid_udp);
+ }
+ }
+ }
+ endnetconfig(confighandle);
+ }
+ if (strcmp(nettype, "udp") == 0)
+ netid = netid_udp;
+ else if (strcmp(nettype, "tcp") == 0)
+ netid = netid_tcp;
+ else {
+ return (NULL);
+ }
+ if ((netid == NULL) || (netid[0] == 0)) {
+ return (NULL);
+ }
+ dummy = getnetconfigent(netid);
+ return (dummy);
+}
+
+/*
+ * Returns the type of the nettype, which should then be used with
+ * __rpc_getconf().
+ */
+void *
+__rpc_setconf(const char *nettype)
+{
+ struct handle *handle;
+
+ handle = (struct handle *) malloc(sizeof (struct handle));
+ if (handle == NULL) {
+ return (NULL);
+ }
+ switch (handle->nettype = getnettype(nettype)) {
+ case _RPC_NETPATH:
+ case _RPC_CIRCUIT_N:
+ case _RPC_DATAGRAM_N:
+ if (!(handle->nhandle = setnetpath()))
+ goto failed;
+ handle->nflag = TRUE;
+ break;
+ case _RPC_VISIBLE:
+ case _RPC_CIRCUIT_V:
+ case _RPC_DATAGRAM_V:
+ case _RPC_TCP:
+ case _RPC_UDP:
+ if (!(handle->nhandle = setnetconfig())) {
+ syslog (LOG_ERR, "rpc: failed to open " NETCONFIG);
+ goto failed;
+ }
+ handle->nflag = FALSE;
+ break;
+ default:
+ goto failed;
+ }
+
+ return (handle);
+
+failed:
+ free(handle);
+ return (NULL);
+}
+
+/*
+ * Returns the next netconfig struct for the given "net" type.
+ * __rpc_setconf() should have been called previously.
+ */
+struct netconfig *
+__rpc_getconf(void *vhandle)
+{
+ struct handle *handle;
+ struct netconfig *nconf;
+
+ handle = (struct handle *)vhandle;
+ if (handle == NULL) {
+ return (NULL);
+ }
+ for (;;) {
+ if (handle->nflag)
+ nconf = getnetpath(handle->nhandle);
+ else
+ nconf = getnetconfig(handle->nhandle);
+ if (nconf == NULL)
+ break;
+ if ((nconf->nc_semantics != NC_TPI_CLTS) &&
+ (nconf->nc_semantics != NC_TPI_COTS) &&
+ (nconf->nc_semantics != NC_TPI_COTS_ORD))
+ continue;
+ switch (handle->nettype) {
+ case _RPC_VISIBLE:
+ if (!(nconf->nc_flag & NC_VISIBLE))
+ continue;
+ /* FALLTHROUGH */
+ case _RPC_NETPATH: /* Be happy */
+ break;
+ case _RPC_CIRCUIT_V:
+ if (!(nconf->nc_flag & NC_VISIBLE))
+ continue;
+ /* FALLTHROUGH */
+ case _RPC_CIRCUIT_N:
+ if ((nconf->nc_semantics != NC_TPI_COTS) &&
+ (nconf->nc_semantics != NC_TPI_COTS_ORD))
+ continue;
+ break;
+ case _RPC_DATAGRAM_V:
+ if (!(nconf->nc_flag & NC_VISIBLE))
+ continue;
+ /* FALLTHROUGH */
+ case _RPC_DATAGRAM_N:
+ if (nconf->nc_semantics != NC_TPI_CLTS)
+ continue;
+ break;
+ case _RPC_TCP:
+ if (((nconf->nc_semantics != NC_TPI_COTS) &&
+ (nconf->nc_semantics != NC_TPI_COTS_ORD)) ||
+ (strcmp(nconf->nc_protofmly, NC_INET)
+#ifdef INET6
+ && strcmp(nconf->nc_protofmly, NC_INET6))
+#else
+ )
+#endif
+ ||
+ strcmp(nconf->nc_proto, NC_TCP))
+ continue;
+ break;
+ case _RPC_UDP:
+ if ((nconf->nc_semantics != NC_TPI_CLTS) ||
+ (strcmp(nconf->nc_protofmly, NC_INET)
+#ifdef INET6
+ && strcmp(nconf->nc_protofmly, NC_INET6))
+#else
+ )
+#endif
+ ||
+ strcmp(nconf->nc_proto, NC_UDP))
+ continue;
+ break;
+ }
+ break;
+ }
+ return (nconf);
+}
+
+void
+__rpc_endconf(void *vhandle)
+{
+ struct handle *handle;
+
+ handle = (struct handle *) vhandle;
+ if (handle == NULL) {
+ return;
+ }
+ if (handle->nflag) {
+ endnetpath(handle->nhandle);
+ } else {
+ endnetconfig(handle->nhandle);
+ }
+ free(handle);
+}
+
+/*
+ * Used to ping the NULL procedure for clnt handle.
+ * Returns NULL if fails, else a non-NULL pointer.
+ */
+void *
+rpc_nullproc(CLIENT *clnt)
+{
+ struct timeval TIMEOUT = {25, 0};
+
+ if (clnt_call(clnt, NULLPROC, (xdrproc_t) xdr_void, NULL,
+ (xdrproc_t) xdr_void, NULL, TIMEOUT) != RPC_SUCCESS) {
+ return (NULL);
+ }
+ return ((void *) clnt);
+}
+
+/*
+ * Try all possible transports until
+ * one succeeds in finding the netconf for the given fd.
+ */
+struct netconfig *
+__rpcgettp(int fd)
+{
+ const char *netid;
+ struct __rpc_sockinfo si;
+
+ if (!__rpc_fd2sockinfo(fd, &si))
+ return NULL;
+
+ if (!__rpc_sockinfo2netid(&si, &netid))
+ return NULL;
+
+ /*LINTED const castaway*/
+ return getnetconfigent((char *)netid);
+}
+
+int
+__rpc_fd2sockinfo(int fd, struct __rpc_sockinfo *sip)
+{
+ socklen_t len;
+ int type, proto;
+ struct sockaddr_storage ss;
+
+ len = sizeof ss;
+ if (_getsockname(fd, (struct sockaddr *)(void *)&ss, &len) < 0)
+ return 0;
+ sip->si_alen = len;
+
+ len = sizeof type;
+ if (_getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &len) < 0)
+ return 0;
+
+ /* XXX */
+ if (ss.ss_family != AF_LOCAL) {
+ if (type == SOCK_STREAM)
+ proto = IPPROTO_TCP;
+ else if (type == SOCK_DGRAM)
+ proto = IPPROTO_UDP;
+ else
+ return 0;
+ } else
+ proto = 0;
+
+ sip->si_af = ss.ss_family;
+ sip->si_proto = proto;
+ sip->si_socktype = type;
+
+ return 1;
+}
+
+/*
+ * Linear search, but the number of entries is small.
+ */
+int
+__rpc_nconf2sockinfo(const struct netconfig *nconf, struct __rpc_sockinfo *sip)
+{
+ int i;
+
+ for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++)
+ if (strcmp(na_cvt[i].netid, nconf->nc_netid) == 0 || (
+ strcmp(nconf->nc_netid, "unix") == 0 &&
+ strcmp(na_cvt[i].netid, "local") == 0)) {
+ sip->si_af = na_cvt[i].af;
+ sip->si_proto = na_cvt[i].protocol;
+ sip->si_socktype =
+ __rpc_seman2socktype((int)nconf->nc_semantics);
+ if (sip->si_socktype == -1)
+ return 0;
+ sip->si_alen = __rpc_get_a_size(sip->si_af);
+ return 1;
+ }
+
+ return 0;
+}
+
+int
+__rpc_nconf2fd(const struct netconfig *nconf)
+{
+ struct __rpc_sockinfo si;
+
+ if (!__rpc_nconf2sockinfo(nconf, &si))
+ return 0;
+
+ return _socket(si.si_af, si.si_socktype, si.si_proto);
+}
+
+int
+__rpc_sockinfo2netid(struct __rpc_sockinfo *sip, const char **netid)
+{
+ int i;
+ struct netconfig *nconf;
+
+ nconf = getnetconfigent("local");
+
+ for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++) {
+ if (na_cvt[i].af == sip->si_af &&
+ na_cvt[i].protocol == sip->si_proto) {
+ if (strcmp(na_cvt[i].netid, "local") == 0 && nconf == NULL) {
+ if (netid)
+ *netid = "unix";
+ } else {
+ if (netid)
+ *netid = na_cvt[i].netid;
+ }
+ if (nconf != NULL)
+ freenetconfigent(nconf);
+ return 1;
+ }
+ }
+ if (nconf != NULL)
+ freenetconfigent(nconf);
+
+ return 0;
+}
+
+char *
+taddr2uaddr(const struct netconfig *nconf, const struct netbuf *nbuf)
+{
+ struct __rpc_sockinfo si;
+
+ if (!__rpc_nconf2sockinfo(nconf, &si))
+ return NULL;
+ return __rpc_taddr2uaddr_af(si.si_af, nbuf);
+}
+
+struct netbuf *
+uaddr2taddr(const struct netconfig *nconf, const char *uaddr)
+{
+ struct __rpc_sockinfo si;
+
+ if (!__rpc_nconf2sockinfo(nconf, &si))
+ return NULL;
+ return __rpc_uaddr2taddr_af(si.si_af, uaddr);
+}
+
+char *
+__rpc_taddr2uaddr_af(int af, const struct netbuf *nbuf)
+{
+ char *ret;
+ struct sockaddr_in *sin;
+ struct sockaddr_un *sun;
+ char namebuf[INET_ADDRSTRLEN];
+#ifdef INET6
+ struct sockaddr_in6 *sin6;
+ char namebuf6[INET6_ADDRSTRLEN];
+#endif
+ u_int16_t port;
+
+ switch (af) {
+ case AF_INET:
+ sin = nbuf->buf;
+ if (inet_ntop(af, &sin->sin_addr, namebuf, sizeof namebuf)
+ == NULL)
+ return NULL;
+ port = ntohs(sin->sin_port);
+ if (asprintf(&ret, "%s.%u.%u", namebuf, ((u_int32_t)port) >> 8,
+ port & 0xff) < 0)
+ return NULL;
+ break;
+#ifdef INET6
+ case AF_INET6:
+ sin6 = nbuf->buf;
+ if (inet_ntop(af, &sin6->sin6_addr, namebuf6, sizeof namebuf6)
+ == NULL)
+ return NULL;
+ port = ntohs(sin6->sin6_port);
+ if (asprintf(&ret, "%s.%u.%u", namebuf6, ((u_int32_t)port) >> 8,
+ port & 0xff) < 0)
+ return NULL;
+ break;
+#endif
+ case AF_LOCAL:
+ sun = nbuf->buf;
+ if (asprintf(&ret, "%.*s", (int)(sun->sun_len -
+ offsetof(struct sockaddr_un, sun_path)),
+ sun->sun_path) < 0)
+ return (NULL);
+ break;
+ default:
+ return NULL;
+ }
+
+ return ret;
+}
+
+struct netbuf *
+__rpc_uaddr2taddr_af(int af, const char *uaddr)
+{
+ struct netbuf *ret = NULL;
+ char *addrstr, *p;
+ unsigned port, portlo, porthi;
+ struct sockaddr_in *sin;
+#ifdef INET6
+ struct sockaddr_in6 *sin6;
+#endif
+ struct sockaddr_un *sun;
+
+ port = 0;
+ sin = NULL;
+ addrstr = strdup(uaddr);
+ if (addrstr == NULL)
+ return NULL;
+
+ /*
+ * AF_LOCAL addresses are expected to be absolute
+ * pathnames, anything else will be AF_INET or AF_INET6.
+ */
+ if (*addrstr != '/') {
+ p = strrchr(addrstr, '.');
+ if (p == NULL)
+ goto out;
+ portlo = (unsigned)atoi(p + 1);
+ *p = '\0';
+
+ p = strrchr(addrstr, '.');
+ if (p == NULL)
+ goto out;
+ porthi = (unsigned)atoi(p + 1);
+ *p = '\0';
+ port = (porthi << 8) | portlo;
+ }
+
+ ret = (struct netbuf *)malloc(sizeof *ret);
+ if (ret == NULL)
+ goto out;
+
+ switch (af) {
+ case AF_INET:
+ sin = (struct sockaddr_in *)malloc(sizeof *sin);
+ if (sin == NULL)
+ goto out;
+ memset(sin, 0, sizeof *sin);
+ sin->sin_family = AF_INET;
+ sin->sin_port = htons(port);
+ if (inet_pton(AF_INET, addrstr, &sin->sin_addr) <= 0) {
+ free(sin);
+ free(ret);
+ ret = NULL;
+ goto out;
+ }
+ sin->sin_len = ret->maxlen = ret->len = sizeof *sin;
+ ret->buf = sin;
+ break;
+#ifdef INET6
+ case AF_INET6:
+ sin6 = (struct sockaddr_in6 *)malloc(sizeof *sin6);
+ if (sin6 == NULL)
+ goto out;
+ memset(sin6, 0, sizeof *sin6);
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_port = htons(port);
+ if (inet_pton(AF_INET6, addrstr, &sin6->sin6_addr) <= 0) {
+ free(sin6);
+ free(ret);
+ ret = NULL;
+ goto out;
+ }
+ sin6->sin6_len = ret->maxlen = ret->len = sizeof *sin6;
+ ret->buf = sin6;
+ break;
+#endif
+ case AF_LOCAL:
+ sun = (struct sockaddr_un *)malloc(sizeof *sun);
+ if (sun == NULL)
+ goto out;
+ memset(sun, 0, sizeof *sun);
+ sun->sun_family = AF_LOCAL;
+ strncpy(sun->sun_path, addrstr, sizeof(sun->sun_path) - 1);
+ ret->len = ret->maxlen = sun->sun_len = SUN_LEN(sun);
+ ret->buf = sun;
+ break;
+ default:
+ break;
+ }
+out:
+ free(addrstr);
+ return ret;
+}
+
+int
+__rpc_seman2socktype(int semantics)
+{
+ switch (semantics) {
+ case NC_TPI_CLTS:
+ return SOCK_DGRAM;
+ case NC_TPI_COTS_ORD:
+ return SOCK_STREAM;
+ case NC_TPI_RAW:
+ return SOCK_RAW;
+ default:
+ break;
+ }
+
+ return -1;
+}
+
+int
+__rpc_socktype2seman(int socktype)
+{
+ switch (socktype) {
+ case SOCK_DGRAM:
+ return NC_TPI_CLTS;
+ case SOCK_STREAM:
+ return NC_TPI_COTS_ORD;
+ case SOCK_RAW:
+ return NC_TPI_RAW;
+ default:
+ break;
+ }
+
+ return -1;
+}
+
+/*
+ * XXXX - IPv6 scope IDs can't be handled in universal addresses.
+ * Here, we compare the original server address to that of the RPC
+ * service we just received back from a call to rpcbind on the remote
+ * machine. If they are both "link local" or "site local", copy
+ * the scope id of the server address over to the service address.
+ */
+int
+__rpc_fixup_addr(struct netbuf *new, const struct netbuf *svc)
+{
+#ifdef INET6
+ struct sockaddr *sa_new, *sa_svc;
+ struct sockaddr_in6 *sin6_new, *sin6_svc;
+
+ sa_svc = (struct sockaddr *)svc->buf;
+ sa_new = (struct sockaddr *)new->buf;
+
+ if (sa_new->sa_family == sa_svc->sa_family &&
+ sa_new->sa_family == AF_INET6) {
+ sin6_new = (struct sockaddr_in6 *)new->buf;
+ sin6_svc = (struct sockaddr_in6 *)svc->buf;
+
+ if ((IN6_IS_ADDR_LINKLOCAL(&sin6_new->sin6_addr) &&
+ IN6_IS_ADDR_LINKLOCAL(&sin6_svc->sin6_addr)) ||
+ (IN6_IS_ADDR_SITELOCAL(&sin6_new->sin6_addr) &&
+ IN6_IS_ADDR_SITELOCAL(&sin6_svc->sin6_addr))) {
+ sin6_new->sin6_scope_id = sin6_svc->sin6_scope_id;
+ }
+ }
+#endif
+ return 1;
+}
+
+int
+__rpc_sockisbound(int fd)
+{
+ struct sockaddr_storage ss;
+ socklen_t slen;
+
+ slen = sizeof (struct sockaddr_storage);
+ if (_getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0)
+ return 0;
+
+ switch (ss.ss_family) {
+ case AF_INET:
+ return (((struct sockaddr_in *)
+ (void *)&ss)->sin_port != 0);
+#ifdef INET6
+ case AF_INET6:
+ return (((struct sockaddr_in6 *)
+ (void *)&ss)->sin6_port != 0);
+#endif
+ case AF_LOCAL:
+ /* XXX check this */
+ return (((struct sockaddr_un *)
+ (void *)&ss)->sun_path[0] != '\0');
+ default:
+ break;
+ }
+
+ return 0;
+}
diff --git a/lib/libc/rpc/rpc_prot.c b/lib/libc/rpc/rpc_prot.c
new file mode 100644
index 000000000000..50d11ccc8735
--- /dev/null
+++ b/lib/libc/rpc/rpc_prot.c
@@ -0,0 +1,353 @@
+/* $NetBSD: rpc_prot.c,v 1.16 2000/06/02 23:11:13 fvdl Exp $ */
+
+/*-
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *sccsid2 = "@(#)rpc_prot.c 1.36 87/08/11 Copyr 1984 Sun Micro";
+static char *sccsid = "@(#)rpc_prot.c 2.3 88/08/07 4.0 RPCSRC";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * rpc_prot.c
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ * This set of routines implements the rpc message definition,
+ * its serializer and some common rpc utility routines.
+ * The routines are meant for various implementations of rpc -
+ * they are NOT for the rpc client or rpc service implementations!
+ * Because authentication stuff is easy and is part of rpc, the opaque
+ * routines are also in this program.
+ */
+
+#include "namespace.h"
+#include <sys/param.h>
+
+#include <assert.h>
+
+#include <rpc/rpc.h>
+#include "un-namespace.h"
+
+static void accepted(enum accept_stat, struct rpc_err *);
+static void rejected(enum reject_stat, struct rpc_err *);
+
+/* * * * * * * * * * * * * * XDR Authentication * * * * * * * * * * * */
+
+extern struct opaque_auth _null_auth;
+
+/*
+ * XDR an opaque authentication struct
+ * (see auth.h)
+ */
+bool_t
+xdr_opaque_auth(XDR *xdrs, struct opaque_auth *ap)
+{
+
+ assert(xdrs != NULL);
+ assert(ap != NULL);
+
+ if (xdr_enum(xdrs, &(ap->oa_flavor)))
+ return (xdr_bytes(xdrs, &ap->oa_base,
+ &ap->oa_length, MAX_AUTH_BYTES));
+ return (FALSE);
+}
+
+/*
+ * XDR a DES block
+ */
+bool_t
+xdr_des_block(XDR *xdrs, des_block *blkp)
+{
+
+ assert(xdrs != NULL);
+ assert(blkp != NULL);
+
+ return (xdr_opaque(xdrs, (caddr_t)(void *)blkp, sizeof(des_block)));
+}
+
+/* * * * * * * * * * * * * * XDR RPC MESSAGE * * * * * * * * * * * * * * * */
+
+/*
+ * XDR the MSG_ACCEPTED part of a reply message union
+ */
+bool_t
+xdr_accepted_reply(XDR *xdrs, struct accepted_reply *ar)
+{
+ enum accept_stat *par_stat;
+
+ assert(xdrs != NULL);
+ assert(ar != NULL);
+
+ par_stat = &ar->ar_stat;
+
+ /* personalized union, rather than calling xdr_union */
+ if (! xdr_opaque_auth(xdrs, &(ar->ar_verf)))
+ return (FALSE);
+ if (! xdr_enum(xdrs, (enum_t *) par_stat))
+ return (FALSE);
+ switch (ar->ar_stat) {
+
+ case SUCCESS:
+ return ((*(ar->ar_results.proc))(xdrs, ar->ar_results.where));
+
+ case PROG_MISMATCH:
+ if (!xdr_rpcvers(xdrs, &(ar->ar_vers.low)))
+ return (FALSE);
+ return (xdr_rpcvers(xdrs, &(ar->ar_vers.high)));
+
+ case GARBAGE_ARGS:
+ case SYSTEM_ERR:
+ case PROC_UNAVAIL:
+ case PROG_UNAVAIL:
+ break;
+ }
+ return (TRUE); /* TRUE => open ended set of problems */
+}
+
+/*
+ * XDR the MSG_DENIED part of a reply message union
+ */
+bool_t
+xdr_rejected_reply(XDR *xdrs, struct rejected_reply *rr)
+{
+ enum reject_stat *prj_stat;
+ enum auth_stat *prj_why;
+
+ assert(xdrs != NULL);
+ assert(rr != NULL);
+
+ prj_stat = &rr->rj_stat;
+
+ /* personalized union, rather than calling xdr_union */
+ if (! xdr_enum(xdrs, (enum_t *) prj_stat))
+ return (FALSE);
+ switch (rr->rj_stat) {
+
+ case RPC_MISMATCH:
+ if (! xdr_rpcvers(xdrs, &(rr->rj_vers.low)))
+ return (FALSE);
+ return (xdr_rpcvers(xdrs, &(rr->rj_vers.high)));
+
+ case AUTH_ERROR:
+ prj_why = &rr->rj_why;
+ return (xdr_enum(xdrs, (enum_t *) prj_why));
+ }
+ /* NOTREACHED */
+ assert(0);
+ return (FALSE);
+}
+
+static const struct xdr_discrim reply_dscrm[3] = {
+ { (int)MSG_ACCEPTED, (xdrproc_t)xdr_accepted_reply },
+ { (int)MSG_DENIED, (xdrproc_t)xdr_rejected_reply },
+ { __dontcare__, NULL_xdrproc_t } };
+
+/*
+ * XDR a reply message
+ */
+bool_t
+xdr_replymsg(XDR *xdrs, struct rpc_msg *rmsg)
+{
+ enum msg_type *prm_direction;
+ enum reply_stat *prp_stat;
+
+ assert(xdrs != NULL);
+ assert(rmsg != NULL);
+
+ prm_direction = &rmsg->rm_direction;
+ prp_stat = &rmsg->rm_reply.rp_stat;
+
+ if (
+ xdr_u_int32_t(xdrs, &(rmsg->rm_xid)) &&
+ xdr_enum(xdrs, (enum_t *) prm_direction) &&
+ (rmsg->rm_direction == REPLY) )
+ return (xdr_union(xdrs, (enum_t *) prp_stat,
+ (caddr_t)(void *)&(rmsg->rm_reply.ru), reply_dscrm,
+ NULL_xdrproc_t));
+ return (FALSE);
+}
+
+
+/*
+ * Serializes the "static part" of a call message header.
+ * The fields include: rm_xid, rm_direction, rpcvers, prog, and vers.
+ * The rm_xid is not really static, but the user can easily munge on the fly.
+ */
+bool_t
+xdr_callhdr(XDR *xdrs, struct rpc_msg *cmsg)
+{
+ enum msg_type *prm_direction;
+
+ assert(xdrs != NULL);
+ assert(cmsg != NULL);
+
+ prm_direction = &cmsg->rm_direction;
+
+ cmsg->rm_direction = CALL;
+ cmsg->rm_call.cb_rpcvers = RPC_MSG_VERSION;
+ if (
+ (xdrs->x_op == XDR_ENCODE) &&
+ xdr_u_int32_t(xdrs, &(cmsg->rm_xid)) &&
+ xdr_enum(xdrs, (enum_t *) prm_direction) &&
+ xdr_rpcvers(xdrs, &(cmsg->rm_call.cb_rpcvers)) &&
+ xdr_rpcprog(xdrs, &(cmsg->rm_call.cb_prog)) )
+ return (xdr_u_int32_t(xdrs, &(cmsg->rm_call.cb_vers)));
+ return (FALSE);
+}
+
+/* ************************** Client utility routine ************* */
+
+static void
+accepted(enum accept_stat acpt_stat, struct rpc_err *error)
+{
+
+ assert(error != NULL);
+
+ switch (acpt_stat) {
+
+ case PROG_UNAVAIL:
+ error->re_status = RPC_PROGUNAVAIL;
+ return;
+
+ case PROG_MISMATCH:
+ error->re_status = RPC_PROGVERSMISMATCH;
+ return;
+
+ case PROC_UNAVAIL:
+ error->re_status = RPC_PROCUNAVAIL;
+ return;
+
+ case GARBAGE_ARGS:
+ error->re_status = RPC_CANTDECODEARGS;
+ return;
+
+ case SYSTEM_ERR:
+ error->re_status = RPC_SYSTEMERROR;
+ return;
+
+ case SUCCESS:
+ error->re_status = RPC_SUCCESS;
+ return;
+ }
+ /* NOTREACHED */
+ /* something's wrong, but we don't know what ... */
+ error->re_status = RPC_FAILED;
+ error->re_lb.s1 = (int32_t)MSG_ACCEPTED;
+ error->re_lb.s2 = (int32_t)acpt_stat;
+}
+
+static void
+rejected(enum reject_stat rjct_stat, struct rpc_err *error)
+{
+
+ assert(error != NULL);
+
+ switch (rjct_stat) {
+ case RPC_MISMATCH:
+ error->re_status = RPC_VERSMISMATCH;
+ return;
+
+ case AUTH_ERROR:
+ error->re_status = RPC_AUTHERROR;
+ return;
+ }
+ /* something's wrong, but we don't know what ... */
+ /* NOTREACHED */
+ error->re_status = RPC_FAILED;
+ error->re_lb.s1 = (int32_t)MSG_DENIED;
+ error->re_lb.s2 = (int32_t)rjct_stat;
+}
+
+/*
+ * given a reply message, fills in the error
+ */
+void
+_seterr_reply(struct rpc_msg *msg, struct rpc_err *error)
+{
+
+ assert(msg != NULL);
+ assert(error != NULL);
+
+ /* optimized for normal, SUCCESSful case */
+ switch (msg->rm_reply.rp_stat) {
+
+ case MSG_ACCEPTED:
+ if (msg->acpted_rply.ar_stat == SUCCESS) {
+ error->re_status = RPC_SUCCESS;
+ return;
+ }
+ accepted(msg->acpted_rply.ar_stat, error);
+ break;
+
+ case MSG_DENIED:
+ rejected(msg->rjcted_rply.rj_stat, error);
+ break;
+
+ default:
+ error->re_status = RPC_FAILED;
+ error->re_lb.s1 = (int32_t)(msg->rm_reply.rp_stat);
+ break;
+ }
+ switch (error->re_status) {
+
+ case RPC_VERSMISMATCH:
+ error->re_vers.low = msg->rjcted_rply.rj_vers.low;
+ error->re_vers.high = msg->rjcted_rply.rj_vers.high;
+ break;
+
+ case RPC_AUTHERROR:
+ error->re_why = msg->rjcted_rply.rj_why;
+ break;
+
+ case RPC_PROGVERSMISMATCH:
+ error->re_vers.low = msg->acpted_rply.ar_vers.low;
+ error->re_vers.high = msg->acpted_rply.ar_vers.high;
+ break;
+
+ case RPC_FAILED:
+ case RPC_SUCCESS:
+ case RPC_PROGNOTREGISTERED:
+ case RPC_PMAPFAILURE:
+ case RPC_UNKNOWNPROTO:
+ case RPC_UNKNOWNHOST:
+ case RPC_SYSTEMERROR:
+ case RPC_CANTDECODEARGS:
+ case RPC_PROCUNAVAIL:
+ case RPC_PROGUNAVAIL:
+ case RPC_TIMEDOUT:
+ case RPC_CANTRECV:
+ case RPC_CANTSEND:
+ case RPC_CANTDECODERES:
+ case RPC_CANTENCODEARGS:
+ default:
+ break;
+ }
+}
diff --git a/lib/libc/rpc/rpc_secure.3 b/lib/libc/rpc/rpc_secure.3
new file mode 100644
index 000000000000..07c6314c9402
--- /dev/null
+++ b/lib/libc/rpc/rpc_secure.3
@@ -0,0 +1,287 @@
+.\" @(#)rpc_secure.3n 2.1 88/08/08 4.0 RPCSRC; from 1.19 88/06/24 SMI
+.\" $FreeBSD$
+.\"
+.Dd February 16, 1988
+.Dt RPC 3
+.Os
+.Sh NAME
+.Nm rpc_secure
+.Nd library routines for secure remote procedure calls
+.Sh SYNOPSIS
+.In rpc/rpc.h
+.Ft AUTH *
+.Fo authdes_create
+.Fa "char *name"
+.Fa "unsigned window"
+.Fa "struct sockaddr *addr"
+.Fa "des_block *ckey"
+.Fc
+.Ft int
+.Fn authdes_getucred "struct authdes_cred *adc" "uid_t *uid" "gid_t *gid" "int *grouplen" "gid_t *groups"
+.Ft int
+.Fn getnetname "char *name"
+.Ft int
+.Fn host2netname "char *name" "const char *host" "const char *domain"
+.Ft int
+.Fn key_decryptsession "const char *remotename" "des_block *deskey"
+.Ft int
+.Fn key_encryptsession "const char *remotename" "des_block *deskey"
+.Ft int
+.Fn key_gendes "des_block *deskey"
+.Ft int
+.Fn key_setsecret "const char *key"
+.Ft int
+.Fn netname2host "char *name" "char *host" "int hostlen"
+.Ft int
+.Fn netname2user "char *name" "uid_t *uidp" "gid_t *gidp" "int *gidlenp" "gid_t *gidlist"
+.Ft int
+.Fn user2netname "char *name" "const uid_t uid" "const char *domain"
+.Sh DESCRIPTION
+These routines are part of the
+.Tn RPC
+library.
+They implement
+.Tn DES
+Authentication.
+See
+.Xr rpc 3
+for further details about
+.Tn RPC .
+.Pp
+The
+.Fn authdes_create
+is the first of two routines which interface to the
+.Tn RPC
+secure authentication system, known as
+.Tn DES
+authentication.
+The second is
+.Fn authdes_getucred ,
+below.
+.Pp
+Note: the keyserver daemon
+.Xr keyserv 8
+must be running for the
+.Tn DES
+authentication system to work.
+.Pp
+The
+.Fn authdes_create
+function,
+used on the client side, returns an authentication handle that
+will enable the use of the secure authentication system.
+The first argument
+.Fa name
+is the network name, or
+.Fa netname ,
+of the owner of the server process.
+This field usually
+represents a
+.Fa hostname
+derived from the utility routine
+.Fn host2netname ,
+but could also represent a user name using
+.Fn user2netname .
+The second field is window on the validity of
+the client credential, given in seconds.
+A small
+window is more secure than a large one, but choosing
+too small of a window will increase the frequency of
+resynchronizations because of clock drift.
+The third
+argument
+.Fa addr
+is optional.
+If it is
+.Dv NULL ,
+then the authentication system will assume
+that the local clock is always in sync with the server's
+clock, and will not attempt resynchronizations.
+If an address
+is supplied, however, then the system will use the address
+for consulting the remote time service whenever
+resynchronization
+is required.
+This argument is usually the
+address of the
+.Tn RPC
+server itself.
+The final argument
+.Fa ckey
+is also optional.
+If it is
+.Dv NULL ,
+then the authentication system will
+generate a random
+.Tn DES
+key to be used for the encryption of credentials.
+If it is supplied, however, then it will be used instead.
+.Pp
+The
+.Fn authdes_getucred
+function,
+the second of the two
+.Tn DES
+authentication routines,
+is used on the server side for converting a
+.Tn DES
+credential, which is
+operating system independent, into a
+.Ux
+credential.
+This routine differs from utility routine
+.Fn netname2user
+in that
+.Fn authdes_getucred
+pulls its information from a cache, and does not have to do a
+Yellow Pages lookup every time it is called to get its information.
+.Pp
+The
+.Fn getnetname
+function
+installs the unique, operating-system independent netname of
+the
+caller in the fixed-length array
+.Fa name .
+Returns
+.Dv TRUE
+if it succeeds and
+.Dv FALSE
+if it fails.
+.Pp
+The
+.Fn host2netname
+function
+converts from a domain-specific hostname to an
+operating-system independent netname.
+Returns
+.Dv TRUE
+if it succeeds and
+.Dv FALSE
+if it fails.
+Inverse of
+.Fn netname2host .
+.Pp
+The
+.Fn key_decryptsession
+function
+is an interface to the keyserver daemon, which is associated
+with
+.Tn RPC Ns 's
+secure authentication system
+.Tn ( DES
+authentication).
+User programs rarely need to call it, or its associated routines
+.Fn key_encryptsession ,
+.Fn key_gendes
+and
+.Fn key_setsecret .
+System commands such as
+.Xr login 1
+and the
+.Tn RPC
+library are the main clients of these four routines.
+.Pp
+The
+.Fn key_decryptsession
+function
+takes a server netname and a
+.Tn DES
+key, and decrypts the key by
+using the public key of the server and the secret key
+associated with the effective uid of the calling process.
+It
+is the inverse of
+.Fn key_encryptsession .
+.Pp
+The
+.Fn key_encryptsession
+function
+is a keyserver interface routine.
+It
+takes a server netname and a des key, and encrypts
+it using the public key of the server and the secret key
+associated with the effective uid of the calling process.
+It
+is the inverse of
+.Fn key_decryptsession .
+.Pp
+The
+.Fn key_gendes
+function
+is a keyserver interface routine.
+It
+is used to ask the keyserver for a secure conversation key.
+Choosing one
+.Qq random
+is usually not good enough,
+because
+the common ways of choosing random numbers, such as using the
+current time, are very easy to guess.
+.Pp
+The
+.Fn key_setsecret
+function
+is a keyserver interface routine.
+It is used to set the key for
+the effective
+.Fa uid
+of the calling process.
+.Pp
+The
+.Fn netname2host
+function
+converts from an operating-system independent netname to a
+domain-specific hostname.
+Returns
+.Dv TRUE
+if it succeeds and
+.Dv FALSE
+if it fails.
+Inverse of
+.Fn host2netname .
+.Pp
+The
+.Fn netname2user
+function
+converts from an operating-system independent netname to a
+domain-specific user ID.
+Returns
+.Dv TRUE
+if it succeeds and
+.Dv FALSE
+if it fails.
+Inverse of
+.Fn user2netname .
+.Pp
+The
+.Fn user2netname
+function
+converts from a domain-specific username to an operating-system
+independent netname.
+Returns
+.Dv TRUE
+if it succeeds and
+.Dv FALSE
+if it fails.
+Inverse of
+.Fn netname2user .
+.Sh SEE ALSO
+.Xr rpc 3 ,
+.Xr xdr 3 ,
+.Xr keyserv 8
+.Pp
+The following manuals:
+.Rs
+.%B Remote Procedure Calls: Protocol Specification
+.Re
+.Rs
+.%B Remote Procedure Call Programming Guide
+.Re
+.Rs
+.%B Rpcgen Programming Guide
+.Re
+.Rs
+.%B RPC: Remote Procedure Call Protocol Specification
+.%O RFC1050, Sun Microsystems Inc., USC-ISI
+.Re
diff --git a/lib/libc/rpc/rpc_soc.3 b/lib/libc/rpc/rpc_soc.3
new file mode 100644
index 000000000000..1af57280916f
--- /dev/null
+++ b/lib/libc/rpc/rpc_soc.3
@@ -0,0 +1,1721 @@
+.\" @(#)rpc.3n 2.4 88/08/08 4.0 RPCSRC; from 1.19 88/06/24 SMI
+.\" $NetBSD: rpc_soc.3,v 1.2 2000/06/07 13:39:43 simonb Exp $
+.\" $FreeBSD$
+.\"
+.Dd February 16, 1988
+.Dt RPC_SOC 3
+.Os
+.Sh NAME
+.Nm rpc_soc ,
+.Nm auth_destroy ,
+.Nm authnone_create ,
+.Nm authunix_create ,
+.Nm authunix_create_default ,
+.Nm callrpc ,
+.Nm clnt_broadcast ,
+.Nm clnt_call ,
+.Nm clnt_control ,
+.Nm clnt_create ,
+.Nm clnt_destroy ,
+.Nm clnt_freeres ,
+.Nm clnt_geterr ,
+.Nm clnt_pcreateerror ,
+.Nm clnt_perrno ,
+.Nm clnt_perror ,
+.Nm clnt_spcreateerror ,
+.Nm clnt_sperrno ,
+.Nm clnt_sperror ,
+.Nm clntraw_create ,
+.Nm clnttcp_create ,
+.Nm clntudp_bufcreate ,
+.Nm clntudp_create ,
+.Nm clntunix_create ,
+.Nm get_myaddress ,
+.Nm pmap_getmaps ,
+.Nm pmap_getport ,
+.Nm pmap_rmtcall ,
+.Nm pmap_set ,
+.Nm pmap_unset ,
+.Nm registerrpc ,
+.Nm rpc_createerr ,
+.Nm svc_destroy ,
+.Nm svc_fds ,
+.Nm svc_fdset ,
+.Nm svc_getargs ,
+.Nm svc_getcaller ,
+.Nm svc_getreq ,
+.Nm svc_getreqset ,
+.Nm svc_register ,
+.Nm svc_run ,
+.Nm svc_sendreply ,
+.Nm svc_unregister ,
+.Nm svcerr_auth ,
+.Nm svcerr_decode ,
+.Nm svcerr_noproc ,
+.Nm svcerr_noprog ,
+.Nm svcerr_progvers ,
+.Nm svcerr_systemerr ,
+.Nm svcerr_weakauth ,
+.Nm svcfd_create ,
+.Nm svcunixfd_create ,
+.Nm svcraw_create ,
+.Nm svcunix_create ,
+.Nm xdr_accepted_reply ,
+.Nm xdr_authunix_parms ,
+.Nm xdr_callhdr ,
+.Nm xdr_callmsg ,
+.Nm xdr_opaque_auth ,
+.Nm xdr_pmap ,
+.Nm xdr_pmaplist ,
+.Nm xdr_rejected_reply ,
+.Nm xdr_replymsg ,
+.Nm xprt_register ,
+.Nm xprt_unregister
+.Nd "library routines for remote procedure calls"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In rpc/rpc.h
+.Pp
+See
+.Sx DESCRIPTION
+for function declarations.
+.Sh DESCRIPTION
+.Bf -symbolic
+The
+.Fn svc_*
+and
+.Fn clnt_*
+functions described in this page are the old, TS-RPC
+interface to the XDR and RPC library, and exist for backward compatibility.
+The new interface is described in the pages
+referenced from
+.Xr rpc 3 .
+.Ef
+.Pp
+These routines allow C programs to make procedure
+calls on other machines across the network.
+First, the client calls a procedure to send a
+data packet to the server.
+Upon receipt of the packet, the server calls a dispatch routine
+to perform the requested service, and then sends back a
+reply.
+Finally, the procedure call returns to the client.
+.Pp
+Routines that are used for Secure
+.Tn RPC ( DES
+authentication) are described in
+.Xr rpc_secure 3 .
+Secure
+.Tn RPC
+can be used only if
+.Tn DES
+encryption is available.
+.Pp
+.Bl -tag -width indent -compact
+.It Xo
+.Ft void
+.Xc
+.It Xo
+.Fn auth_destroy "AUTH *auth"
+.Xc
+.Pp
+A macro that destroys the authentication information associated with
+.Fa auth .
+Destruction usually involves deallocation of private data
+structures.
+The use of
+.Fa auth
+is undefined after calling
+.Fn auth_destroy .
+.Pp
+.It Xo
+.Ft "AUTH *"
+.Xc
+.It Xo
+.Fn authnone_create
+.Xc
+.Pp
+Create and return an
+.Tn RPC
+authentication handle that passes nonusable authentication
+information with each remote procedure call.
+This is the
+default authentication used by
+.Tn RPC .
+.Pp
+.It Xo
+.Ft "AUTH *"
+.Xc
+.It Xo
+.Fn authunix_create "char *host" "u_int uid" "u_int gid" "int len" "u_int *aup_gids"
+.Xc
+.Pp
+Create and return an
+.Tn RPC
+authentication handle that contains
+.Ux
+authentication information.
+The
+.Fa host
+argument
+is the name of the machine on which the information was
+created;
+.Fa uid
+is the user's user ID;
+.Fa gid
+is the user's current group ID;
+.Fa len
+and
+.Fa aup_gids
+refer to a counted array of groups to which the user belongs.
+It is easy to impersonate a user.
+.Pp
+.It Xo
+.Ft "AUTH *"
+.Xc
+.It Xo
+.Fn authunix_create_default
+.Xc
+.Pp
+Calls
+.Fn authunix_create
+with the appropriate arguments.
+.Pp
+.It Xo
+.Ft int
+.Fo callrpc
+.Fa "char *host"
+.Fa "u_long prognum"
+.Fa "u_long versnum"
+.Fa "u_long procnum"
+.Fa "xdrproc_t inproc"
+.Fa "void *in"
+.Fa "xdrproc_t outproc"
+.Fa "void *out"
+.Fc
+.Xc
+.Pp
+Call the remote procedure associated with
+.Fa prognum ,
+.Fa versnum ,
+and
+.Fa procnum
+on the machine
+.Fa host .
+The
+.Fa in
+argument
+is the address of the procedure's argument(s), and
+.Fa out
+is the address of where to place the result(s);
+.Fa inproc
+is used to encode the procedure's arguments, and
+.Fa outproc
+is used to decode the procedure's results.
+This routine returns zero if it succeeds, or the value of
+.Vt "enum clnt_stat"
+cast to an integer if it fails.
+The routine
+.Fn clnt_perrno
+is handy for translating failure statuses into messages.
+.Pp
+Warning: calling remote procedures with this routine
+uses
+.Tn UDP/IP
+as a transport; see
+.Fn clntudp_create
+for restrictions.
+You do not have control of timeouts or authentication using
+this routine.
+.Pp
+.It Xo
+.Ft "enum clnt_stat"
+.Xc
+.It Xo
+.Fo clnt_broadcast
+.Fa "u_long prognum"
+.Fa "u_long versnum"
+.Fa "u_long procnum"
+.Fa "xdrproc_t inproc"
+.Fa "char *in"
+.Fa "xdrproc_t outproc"
+.Fa "char *out"
+.Fa "bool_t (*eachresult)(caddr_t, struct sockaddr_in *)"
+.Fc
+.Xc
+.Pp
+Like
+.Fn callrpc ,
+except the call message is broadcast to all locally
+connected broadcast nets.
+Each time it receives a
+response, this routine calls
+.Fn eachresult ,
+whose form is:
+.Bd -ragged -offset indent
+.Ft bool_t
+.Fn eachresult "caddr_t out" "struct sockaddr_in *addr"
+.Ed
+.Pp
+where
+.Fa out
+is the same as
+.Fa out
+passed to
+.Fn clnt_broadcast ,
+except that the remote procedure's output is decoded there;
+.Fa addr
+points to the address of the machine that sent the results.
+If
+.Fn eachresult
+returns zero,
+.Fn clnt_broadcast
+waits for more replies; otherwise it returns with appropriate
+status.
+.Pp
+Warning: broadcast sockets are limited in size to the
+maximum transfer unit of the data link.
+For ethernet,
+this value is 1500 bytes.
+.Pp
+.It Xo
+.Ft "enum clnt_stat"
+.Xc
+.It Xo
+.Fo clnt_call
+.Fa "CLIENT *clnt"
+.Fa "u_long procnum"
+.Fa "xdrproc_t inproc"
+.Fa "char *in"
+.Fa "xdrproc_t outproc"
+.Fa "char *out"
+.Fa "struct timeval tout"
+.Fc
+.Xc
+.Pp
+A macro that calls the remote procedure
+.Fa procnum
+associated with the client handle,
+.Fa clnt ,
+which is obtained with an
+.Tn RPC
+client creation routine such as
+.Fn clnt_create .
+The
+.Fa in
+argument
+is the address of the procedure's argument(s), and
+.Fa out
+is the address of where to place the result(s);
+.Fa inproc
+is used to encode the procedure's arguments, and
+.Fa outproc
+is used to decode the procedure's results;
+.Fa tout
+is the time allowed for results to come back.
+.Pp
+.It Xo
+.Ft void
+.Fn clnt_destroy "CLIENT *clnt"
+.Xc
+.Pp
+A macro that destroys the client's
+.Tn RPC
+handle.
+Destruction usually involves deallocation
+of private data structures, including
+.Fa clnt
+itself.
+Use of
+.Fa clnt
+is undefined after calling
+.Fn clnt_destroy .
+If the
+.Tn RPC
+library opened the associated socket, it will close it also.
+Otherwise, the socket remains open.
+.Pp
+.It Xo
+.Ft CLIENT *
+.Xc
+.It Xo
+.Fn clnt_create "char *host" "u_long prog" "u_long vers" "char *proto"
+.Xc
+.Pp
+Generic client creation routine.
+The
+.Fa host
+argument
+identifies the name of the remote host where the server
+is located.
+The
+.Fa proto
+argument
+indicates which kind of transport protocol to use.
+The
+currently supported values for this field are
+.Qq Li udp
+and
+.Qq Li tcp .
+Default timeouts are set, but can be modified using
+.Fn clnt_control .
+.Pp
+Warning: Using
+.Tn UDP
+has its shortcomings.
+Since
+.Tn UDP Ns \-based
+.Tn RPC
+messages can only hold up to 8 Kbytes of encoded data,
+this transport cannot be used for procedures that take
+large arguments or return huge results.
+.Pp
+.It Xo
+.Ft bool_t
+.Xc
+.It Xo
+.Fn clnt_control "CLIENT *cl" "u_int req" "char *info"
+.Xc
+.Pp
+A macro used to change or retrieve various information
+about a client object.
+The
+.Fa req
+argument
+indicates the type of operation, and
+.Fa info
+is a pointer to the information.
+For both
+.Tn UDP
+and
+.Tn TCP ,
+the supported values of
+.Fa req
+and their argument types and what they do are:
+.Bl -column "CLSET_RETRY_TIMEOUT" "struct sockaddr_in"
+.It Dv CLSET_TIMEOUT Ta
+.Vt "struct timeval" Ta "set total timeout"
+.It Dv CLGET_TIMEOUT Ta
+.Vt "struct timeval" Ta "get total timeout"
+.El
+.Pp
+Note: if you set the timeout using
+.Fn clnt_control ,
+the timeout argument passed to
+.Fn clnt_call
+will be ignored in all future calls.
+.Bl -column "CLSET_RETRY_TIMEOUT" "struct sockaddr_in"
+.It Dv CLGET_SERVER_ADDR Ta
+.Vt "struct sockaddr_in" Ta "get server's address"
+.El
+.Pp
+The following operations are valid for
+.Tn UDP
+only:
+.Bl -column "CLSET_RETRY_TIMEOUT" "struct sockaddr_in"
+.It Dv CLSET_RETRY_TIMEOUT Ta
+.Vt "struct timeval" Ta "set the retry timeout"
+.It Dv CLGET_RETRY_TIMEOUT Ta
+.Vt "struct timeval" Ta "get the retry timeout"
+.El
+.Pp
+The retry timeout is the time that
+.Tn "UDP RPC"
+waits for the server to reply before
+retransmitting the request.
+.Pp
+.It Xo
+.Ft bool_t
+.Fn clnt_freeres "CLIENT *clnt" "xdrproc_t outproc" "char *out"
+.Xc
+.Pp
+A macro that frees any data allocated by the
+.Tn RPC/XDR
+system when it decoded the results of an
+.Tn RPC
+call.
+The
+.Fa out
+argument
+is the address of the results, and
+.Fa outproc
+is the
+.Tn XDR
+routine describing the results.
+This routine returns one if the results were successfully
+freed,
+and zero otherwise.
+.Pp
+.It Xo
+.Ft void
+.Xc
+.It Xo
+.Fn clnt_geterr "CLIENT *clnt" "struct rpc_err *errp"
+.Xc
+.Pp
+A macro that copies the error structure out of the client
+handle
+to the structure at address
+.Fa errp .
+.Pp
+.It Xo
+.Ft void
+.Xc
+.It Xo
+.Fn clnt_pcreateerror "char *s"
+.Xc
+.Pp
+prints a message to standard error indicating
+why a client
+.Tn RPC
+handle could not be created.
+The message is prepended with string
+.Fa s
+and a colon.
+A newline is appended at the end of the message.
+Used when a
+.Fn clnt_create ,
+.Fn clntraw_create ,
+.Fn clnttcp_create ,
+or
+.Fn clntudp_create
+call fails.
+.Pp
+.It Xo
+.Ft void
+.Xc
+.It Xo
+.Fn clnt_perrno "enum clnt_stat stat"
+.Xc
+.Pp
+Print a message to standard error corresponding
+to the condition indicated by
+.Fa stat .
+A newline is appended at the end of the message.
+Used after
+.Fn callrpc .
+.Pp
+.It Xo
+.Ft void
+.Fn clnt_perror "CLIENT *clnt" "char *s"
+.Xc
+.Pp
+Print a message to standard error indicating why an
+.Tn RPC
+call failed;
+.Fa clnt
+is the handle used to do the call.
+The message is prepended with string
+.Fa s
+and a colon.
+A newline is appended at the end of the message.
+Used after
+.Fn clnt_call .
+.Pp
+.It Xo
+.Ft "char *"
+.Xc
+.It Xo
+.Fn clnt_spcreateerror "char *s"
+.Xc
+.Pp
+Like
+.Fn clnt_pcreateerror ,
+except that it returns a string
+instead of printing to the standard error.
+.Pp
+Bugs: returns pointer to static data that is overwritten
+on each call.
+.Pp
+.It Xo
+.Ft "char *"
+.Xc
+.It Xo
+.Fn clnt_sperrno "enum clnt_stat stat"
+.Xc
+.Pp
+Take the same arguments as
+.Fn clnt_perrno ,
+but instead of sending a message to the standard error
+indicating why an
+.Tn RPC
+call failed, return a pointer to a string which contains
+the message.
+.Pp
+The
+.Fn clnt_sperrno
+function
+is used instead of
+.Fn clnt_perrno
+if the program does not have a standard error (as a program
+running as a server quite likely does not), or if the
+programmer
+does not want the message to be output with
+.Fn printf ,
+or if a message format different from that supported by
+.Fn clnt_perrno
+is to be used.
+.Pp
+Note: unlike
+.Fn clnt_sperror
+and
+.Fn clnt_spcreateerror ,
+.Fn clnt_sperrno
+returns pointer to static data, but the
+result will not get overwritten on each call.
+.Pp
+.It Xo
+.Ft "char *"
+.Xc
+.It Xo
+.Fn clnt_sperror "CLIENT *rpch" "char *s"
+.Xc
+.Pp
+Like
+.Fn clnt_perror ,
+except that (like
+.Fn clnt_sperrno )
+it returns a string instead of printing to standard error.
+.Pp
+Bugs: returns pointer to static data that is overwritten
+on each call.
+.Pp
+.It Xo
+.Ft "CLIENT *"
+.Xc
+.It Xo
+.Fn clntraw_create "u_long prognum" "u_long versnum"
+.Xc
+.Pp
+This routine creates a toy
+.Tn RPC
+client for the remote program
+.Fa prognum ,
+version
+.Fa versnum .
+The transport used to pass messages to the service is
+actually a buffer within the process's address space, so the
+corresponding
+.Tn RPC
+server should live in the same address space; see
+.Fn svcraw_create .
+This allows simulation of
+.Tn RPC
+and acquisition of
+.Tn RPC
+overheads, such as round trip times, without any
+kernel interference.
+This routine returns
+.Dv NULL
+if it fails.
+.Pp
+.It Xo
+.Ft "CLIENT *"
+.Xc
+.It Xo
+.Fo clnttcp_create
+.Fa "struct sockaddr_in *addr"
+.Fa "u_long prognum"
+.Fa "u_long versnum"
+.Fa "int *sockp"
+.Fa "u_int sendsz"
+.Fa "u_int recvsz"
+.Fc
+.Xc
+.Pp
+This routine creates an
+.Tn RPC
+client for the remote program
+.Fa prognum ,
+version
+.Fa versnum ;
+the client uses
+.Tn TCP/IP
+as a transport.
+The remote program is located at Internet
+address
+.Fa addr .
+If
+.Fa addr\->sin_port
+is zero, then it is set to the actual port that the remote
+program is listening on (the remote
+.Xr rpcbind 8
+service is consulted for this information).
+The
+.Fa sockp
+argument
+is a socket; if it is
+.Dv RPC_ANYSOCK ,
+then this routine opens a new one and sets
+.Fa sockp .
+Since
+.Tn TCP Ns \-based
+.Tn RPC
+uses buffered
+.Tn I/O ,
+the user may specify the size of the send and receive buffers
+with the
+.Fa sendsz
+and
+.Fa recvsz
+arguments;
+values of zero choose suitable defaults.
+This routine returns
+.Dv NULL
+if it fails.
+.Pp
+.It Xo
+.Ft "CLIENT *"
+.Xc
+.It Xo
+.Fo clntudp_create
+.Fa "struct sockaddr_in *addr"
+.Fa "u_long prognum"
+.Fa "u_long versnum"
+.Fa "struct timeval wait"
+.Fa "int *sockp"
+.Fc
+.Xc
+.Pp
+This routine creates an
+.Tn RPC
+client for the remote program
+.Fa prognum ,
+version
+.Fa versnum ;
+the client uses
+.Tn UDP/IP
+as a transport.
+The remote program is located at Internet
+address
+.Fa addr .
+If
+.Fa addr\->sin_port
+is zero, then it is set to actual port that the remote
+program is listening on (the remote
+.Xr rpcbind 8
+service is consulted for this information).
+The
+.Fa sockp
+argument
+is a socket; if it is
+.Dv RPC_ANYSOCK ,
+then this routine opens a new one and sets
+.Fa sockp .
+The
+.Tn UDP
+transport resends the call message in intervals of
+.Fa wait
+time until a response is received or until the call times
+out.
+The total time for the call to time out is specified by
+.Fn clnt_call .
+.Pp
+Warning: since
+.Tn UDP Ns \-based
+.Tn RPC
+messages can only hold up to 8 Kbytes
+of encoded data, this transport cannot be used for procedures
+that take large arguments or return huge results.
+.Pp
+.It Xo
+.Ft "CLIENT *"
+.Xc
+.It Xo
+.Fo clntudp_bufcreate
+.Fa "struct sockaddr_in *addr"
+.Fa "u_long prognum"
+.Fa "u_long versnum"
+.Fa "struct timeval wait"
+.Fa "int *sockp"
+.Fa "unsigned int sendsize"
+.Fa "unsigned int recosize"
+.Fc
+.Xc
+.Pp
+This routine creates an
+.Tn RPC
+client for the remote program
+.Fa prognum ,
+on
+.Fa versnum ;
+the client uses
+.Tn UDP/IP
+as a transport.
+The remote program is located at Internet
+address
+.Fa addr .
+If
+.Fa addr\->sin_port
+is zero, then it is set to actual port that the remote
+program is listening on (the remote
+.Xr rpcbind 8
+service is consulted for this information).
+The
+.Fa sockp
+argument
+is a socket; if it is
+.Dv RPC_ANYSOCK ,
+then this routine opens a new one and sets
+.Fa sockp .
+The
+.Tn UDP
+transport resends the call message in intervals of
+.Fa wait
+time until a response is received or until the call times
+out.
+The total time for the call to time out is specified by
+.Fn clnt_call .
+.Pp
+This allows the user to specify the maximum packet size
+for sending and receiving
+.Tn UDP Ns \-based
+.Tn RPC
+messages.
+.Pp
+.It Xo
+.Ft "CLIENT *"
+.Xc
+.It Xo
+.Fo clntunix_create
+.Fa "struct sockaddr_un *raddr"
+.Fa "u_long prognum"
+.Fa "u_long versnum"
+.Fa "int *sockp"
+.Fa "u_int sendsz"
+.Fa "u_int recvsz"
+.Fc
+.Xc
+.Pp
+This routine creates an
+.Tn RPC
+client for the local
+program
+.Fa prognum ,
+version
+.Fa versnum ;
+the client uses
+.Ux Ns -domain
+sockets as a transport.
+The local program is located at the
+.Fa *raddr .
+The
+.Fa sockp
+argument
+is a socket; if it is
+.Dv RPC_ANYSOCK ,
+then this routine opens a new one and sets
+.Fa sockp .
+Since
+.Ux Ns -based
+.Tn RPC
+uses buffered
+.Tn I/O ,
+the user may specify the size of the send and receive buffers
+with the
+.Fa sendsz
+and
+.Fa recvsz
+arguments;
+values of zero choose suitable defaults.
+This routine returns
+.Dv NULL
+if it fails.
+.Pp
+.It Xo
+.Ft int
+.Xc
+.It Xo
+.Fn get_myaddress "struct sockaddr_in *addr"
+.Xc
+.Pp
+Stuff the machine's
+.Tn IP
+address into
+.Fa addr ,
+without consulting the library routines that deal with
+.Pa /etc/hosts .
+The port number is always set to
+.Fn htons PMAPPORT .
+Returns zero on success, non-zero on failure.
+.Pp
+.It Xo
+.Ft "struct pmaplist *"
+.Xc
+.It Xo
+.Fn pmap_getmaps "struct sockaddr_in *addr"
+.Xc
+.Pp
+A user interface to the
+.Xr rpcbind 8
+service, which returns a list of the current
+.Tn RPC
+program\-to\-port mappings
+on the host located at
+.Tn IP
+address
+.Fa addr .
+This routine can return
+.Dv NULL .
+The command
+.Dq Nm rpcinfo Fl p
+uses this routine.
+.Pp
+.It Xo
+.Ft u_short
+.Xc
+.It Xo
+.Fo pmap_getport
+.Fa "struct sockaddr_in *addr"
+.Fa "u_long prognum"
+.Fa "u_long versnum"
+.Fa "u_long protocol"
+.Fc
+.Xc
+.Pp
+A user interface to the
+.Xr rpcbind 8
+service, which returns the port number
+on which waits a service that supports program number
+.Fa prognum ,
+version
+.Fa versnum ,
+and speaks the transport protocol associated with
+.Fa protocol .
+The value of
+.Fa protocol
+is most likely
+.Dv IPPROTO_UDP
+or
+.Dv IPPROTO_TCP .
+A return value of zero means that the mapping does not exist
+or that
+the
+.Tn RPC
+system failed to contact the remote
+.Xr rpcbind 8
+service.
+In the latter case, the global variable
+.Va rpc_createerr
+contains the
+.Tn RPC
+status.
+.Pp
+.It Xo
+.Ft "enum clnt_stat"
+.Xc
+.It Xo
+.Fo pmap_rmtcall
+.Fa "struct sockaddr_in *addr"
+.Fa "u_long prognum"
+.Fa "u_long versnum"
+.Fa "u_long procnum"
+.Fa "xdrproc_t inproc"
+.Fa "char *in"
+.Fa "xdrproc_t outproc"
+.Fa "char *out"
+.Fa "struct timeval tout"
+.Fa "u_long *portp"
+.Fc
+.Xc
+.Pp
+A user interface to the
+.Xr rpcbind 8
+service, which instructs
+.Xr rpcbind 8
+on the host at
+.Tn IP
+address
+.Fa addr
+to make an
+.Tn RPC
+call on your behalf to a procedure on that host.
+The
+.Fa portp
+argument
+will be modified to the program's port number if the
+procedure
+succeeds.
+The definitions of other arguments are discussed
+in
+.Fn callrpc
+and
+.Fn clnt_call .
+This procedure should be used for a
+.Dq ping
+and nothing
+else.
+See also
+.Fn clnt_broadcast .
+.Pp
+.It Xo
+.Ft bool_t
+.Fn pmap_set "u_long prognum" "u_long versnum" "u_long protocol" "u_short port"
+.Xc
+.Pp
+A user interface to the
+.Xr rpcbind 8
+service, which establishes a mapping between the triple
+.Pq Fa prognum , versnum , protocol
+and
+.Fa port
+on the machine's
+.Xr rpcbind 8
+service.
+The value of
+.Fa protocol
+is most likely
+.Dv IPPROTO_UDP
+or
+.Dv IPPROTO_TCP .
+This routine returns one if it succeeds, zero otherwise.
+Automatically done by
+.Fn svc_register .
+.Pp
+.It Xo
+.Ft bool_t
+.Fn pmap_unset "u_long prognum" "u_long versnum"
+.Xc
+.Pp
+A user interface to the
+.Xr rpcbind 8
+service, which destroys all mapping between the triple
+.Pq Fa prognum , versnum , *
+and
+.Fa ports
+on the machine's
+.Xr rpcbind 8
+service.
+This routine returns one if it succeeds, zero
+otherwise.
+.Pp
+.It Xo
+.Ft bool_t
+.Fo registerrpc
+.Fa "u_long prognum"
+.Fa "u_long versnum"
+.Fa "u_long procnum"
+.Fa "char *(*procname)(void)"
+.Fa "xdrproc_t inproc"
+.Fa "xdrproc_t outproc"
+.Fc
+.Xc
+.Pp
+Register procedure
+.Fa procname
+with the
+.Tn RPC
+service package.
+If a request arrives for program
+.Fa prognum ,
+version
+.Fa versnum ,
+and procedure
+.Fa procnum ,
+.Fa procname
+is called with a pointer to its argument(s);
+.Fa progname
+should return a pointer to its static result(s);
+.Fa inproc
+is used to decode the arguments while
+.Fa outproc
+is used to encode the results.
+This routine returns zero if the registration succeeded, \-1
+otherwise.
+.Pp
+Warning: remote procedures registered in this form
+are accessed using the
+.Tn UDP/IP
+transport; see
+.Fn svcudp_create
+for restrictions.
+.Pp
+.It Xo
+.Vt "struct rpc_createerr" rpc_createerr ;
+.Xc
+.Pp
+A global variable whose value is set by any
+.Tn RPC
+client creation routine
+that does not succeed.
+Use the routine
+.Fn clnt_pcreateerror
+to print the reason why.
+.Pp
+.It Xo
+.Ft bool_t
+.Fn svc_destroy "SVCXPRT * xprt"
+.Xc
+.Pp
+A macro that destroys the
+.Tn RPC
+service transport handle,
+.Fa xprt .
+Destruction usually involves deallocation
+of private data structures, including
+.Fa xprt
+itself.
+Use of
+.Fa xprt
+is undefined after calling this routine.
+.Pp
+.It Xo
+.Vt fd_set svc_fdset ;
+.Xc
+.Pp
+A global variable reflecting the
+.Tn RPC
+service side's
+read file descriptor bit mask; it is suitable as a template argument
+to the
+.Xr select 2
+system call.
+This is only of interest
+if a service implementor does not call
+.Fn svc_run ,
+but rather does his own asynchronous event processing.
+This variable is read\-only (do not pass its address to
+.Xr select 2 ! ) ,
+yet it may change after calls to
+.Fn svc_getreqset
+or any creation routines.
+As well, note that if the process has descriptor limits
+which are extended beyond
+.Dv FD_SETSIZE ,
+this variable will only be usable for the first
+.Dv FD_SETSIZE
+descriptors.
+.Pp
+.It Xo
+.Vt int svc_fds ;
+.Xc
+.Pp
+Similar to
+.Va svc_fdset ,
+but limited to 32 descriptors.
+This
+interface is obsoleted by
+.Va svc_fdset .
+.Pp
+.It Xo
+.Ft bool_t
+.Fn svc_freeargs "SVCXPRT *xprt" "xdrproc_t inproc" "char *in"
+.Xc
+.Pp
+A macro that frees any data allocated by the
+.Tn RPC/XDR
+system when it decoded the arguments to a service procedure
+using
+.Fn svc_getargs .
+This routine returns 1 if the results were successfully
+freed,
+and zero otherwise.
+.Pp
+.It Xo
+.Ft bool_t
+.Fn svc_getargs "SVCXPRT *xprt" "xdrproc_t inproc" "char *in"
+.Xc
+.Pp
+A macro that decodes the arguments of an
+.Tn RPC
+request
+associated with the
+.Tn RPC
+service transport handle,
+.Fa xprt .
+The
+.Fa in
+argument
+is the address where the arguments will be placed;
+.Fa inproc
+is the
+.Tn XDR
+routine used to decode the arguments.
+This routine returns one if decoding succeeds, and zero
+otherwise.
+.Pp
+.It Xo
+.Ft "struct sockaddr_in *"
+.Xc
+.It Xo
+.Fn svc_getcaller "SVCXPRT *xprt"
+.Xc
+.Pp
+The approved way of getting the network address of the caller
+of a procedure associated with the
+.Tn RPC
+service transport handle,
+.Fa xprt .
+.Pp
+.It Xo
+.Ft void
+.Fn svc_getreqset "fd_set *rdfds"
+.Xc
+.Pp
+This routine is only of interest if a service implementor
+does not call
+.Fn svc_run ,
+but instead implements custom asynchronous event processing.
+It is called when the
+.Xr select 2
+system call has determined that an
+.Tn RPC
+request has arrived on some
+.Tn RPC
+socket(s);
+.Fa rdfds
+is the resultant read file descriptor bit mask.
+The routine returns when all sockets associated with the
+value of
+.Fa rdfds
+have been serviced.
+.Pp
+.It Xo
+.Ft void
+.Fn svc_getreq "int rdfds"
+.Xc
+.Pp
+Similar to
+.Fn svc_getreqset ,
+but limited to 32 descriptors.
+This interface is obsoleted by
+.Fn svc_getreqset .
+.Pp
+.It Xo
+.Ft bool_t
+.Fo svc_register
+.Fa "SVCXPRT *xprt"
+.Fa "u_long prognum"
+.Fa "u_long versnum"
+.Fa "void (*dispatch)(struct svc_req *, SVCXPRT *)"
+.Fa "int protocol"
+.Fc
+.Xc
+.Pp
+Associates
+.Fa prognum
+and
+.Fa versnum
+with the service dispatch procedure,
+.Fn dispatch .
+If
+.Fa protocol
+is zero, the service is not registered with the
+.Xr rpcbind 8
+service.
+If
+.Fa protocol
+is non-zero, then a mapping of the triple
+.Pq Fa prognum , versnum , protocol
+to
+.Fa xprt\->xp_port
+is established with the local
+.Xr rpcbind 8
+service (generally
+.Fa protocol
+is zero,
+.Dv IPPROTO_UDP
+or
+.Dv IPPROTO_TCP ) .
+The procedure
+.Fn dispatch
+has the following form:
+.Bd -ragged -offset indent
+.Ft bool_t
+.Fn dispatch "struct svc_req *request" "SVCXPRT *xprt"
+.Ed
+.Pp
+The
+.Fn svc_register
+routine returns one if it succeeds, and zero otherwise.
+.Pp
+.It Xo
+.Fn svc_run
+.Xc
+.Pp
+This routine never returns.
+It waits for
+.Tn RPC
+requests to arrive, and calls the appropriate service
+procedure using
+.Fn svc_getreq
+when one arrives.
+This procedure is usually waiting for a
+.Xr select 2
+system call to return.
+.Pp
+.It Xo
+.Ft bool_t
+.Fn svc_sendreply "SVCXPRT *xprt" "xdrproc_t outproc" "char *out"
+.Xc
+.Pp
+Called by an
+.Tn RPC
+service's dispatch routine to send the results of a
+remote procedure call.
+The
+.Fa xprt
+argument
+is the request's associated transport handle;
+.Fa outproc
+is the
+.Tn XDR
+routine which is used to encode the results; and
+.Fa out
+is the address of the results.
+This routine returns one if it succeeds, zero otherwise.
+.Pp
+.It Xo
+.Ft void
+.Xc
+.It Xo
+.Fn svc_unregister "u_long prognum" "u_long versnum"
+.Xc
+.Pp
+Remove all mapping of the double
+.Pq Fa prognum , versnum
+to dispatch routines, and of the triple
+.Pq Fa prognum , versnum , *
+to port number.
+.Pp
+.It Xo
+.Ft void
+.Xc
+.It Xo
+.Fn svcerr_auth "SVCXPRT *xprt" "enum auth_stat why"
+.Xc
+.Pp
+Called by a service dispatch routine that refuses to perform
+a remote procedure call due to an authentication error.
+.Pp
+.It Xo
+.Ft void
+.Xc
+.It Xo
+.Fn svcerr_decode "SVCXPRT *xprt"
+.Xc
+.Pp
+Called by a service dispatch routine that cannot successfully
+decode its arguments.
+See also
+.Fn svc_getargs .
+.Pp
+.It Xo
+.Ft void
+.Xc
+.It Xo
+.Fn svcerr_noproc "SVCXPRT *xprt"
+.Xc
+.Pp
+Called by a service dispatch routine that does not implement
+the procedure number that the caller requests.
+.Pp
+.It Xo
+.Ft void
+.Xc
+.It Xo
+.Fn svcerr_noprog "SVCXPRT *xprt"
+.Xc
+.Pp
+Called when the desired program is not registered with the
+.Tn RPC
+package.
+Service implementors usually do not need this routine.
+.Pp
+.It Xo
+.Ft void
+.Xc
+.It Xo
+.Fn svcerr_progvers "SVCXPRT *xprt" "u_long low_vers" "u_long high_vers"
+.Xc
+.Pp
+Called when the desired version of a program is not registered
+with the
+.Tn RPC
+package.
+Service implementors usually do not need this routine.
+.Pp
+.It Xo
+.Ft void
+.Xc
+.It Xo
+.Fn svcerr_systemerr "SVCXPRT *xprt"
+.Xc
+.Pp
+Called by a service dispatch routine when it detects a system
+error
+not covered by any particular protocol.
+For example, if a service can no longer allocate storage,
+it may call this routine.
+.Pp
+.It Xo
+.Ft void
+.Xc
+.It Xo
+.Fn svcerr_weakauth "SVCXPRT *xprt"
+.Xc
+.Pp
+Called by a service dispatch routine that refuses to perform
+a remote procedure call due to insufficient
+authentication arguments.
+The routine calls
+.Fn svcerr_auth xprt AUTH_TOOWEAK .
+.Pp
+.It Xo
+.Ft "SVCXPRT *"
+.Xc
+.It Xo
+.Fn svcraw_create void
+.Xc
+.Pp
+This routine creates a toy
+.Tn RPC
+service transport, to which it returns a pointer.
+The transport
+is really a buffer within the process's address space,
+so the corresponding
+.Tn RPC
+client should live in the same
+address space;
+see
+.Fn clntraw_create .
+This routine allows simulation of
+.Tn RPC
+and acquisition of
+.Tn RPC
+overheads (such as round trip times), without any kernel
+interference.
+This routine returns
+.Dv NULL
+if it fails.
+.Pp
+.It Xo
+.Ft "SVCXPRT *"
+.Xc
+.It Xo
+.Fn svctcp_create "int sock" "u_int send_buf_size" "u_int recv_buf_size"
+.Xc
+.Pp
+This routine creates a
+.Tn TCP/IP Ns \-based
+.Tn RPC
+service transport, to which it returns a pointer.
+The transport is associated with the socket
+.Fa sock ,
+which may be
+.Dv RPC_ANYSOCK ,
+in which case a new socket is created.
+If the socket is not bound to a local
+.Tn TCP
+port, then this routine binds it to an arbitrary port.
+Upon completion,
+.Fa xprt\->xp_fd
+is the transport's socket descriptor, and
+.Fa xprt\->xp_port
+is the transport's port number.
+This routine returns
+.Dv NULL
+if it fails.
+Since
+.Tn TCP Ns \-based
+.Tn RPC
+uses buffered
+.Tn I/O ,
+users may specify the size of buffers; values of zero
+choose suitable defaults.
+.Pp
+.It Xo
+.Ft "SVCXPRT *"
+.Xc
+.It Xo
+.Fn svcunix_create "int sock" "u_int send_buf_size" "u_int recv_buf_size" "char *path"
+.Xc
+.Pp
+This routine creates a
+.Ux Ns -based
+.Tn RPC
+service transport, to which it returns a pointer.
+The transport is associated with the socket
+.Fa sock ,
+which may be
+.Dv RPC_ANYSOCK ,
+in which case a new socket is created.
+The
+.Fa *path
+argument
+is a variable-length file system pathname of
+at most 104 characters.
+This file is
+.Em not
+removed when the socket is closed.
+The
+.Xr unlink 2
+system call must be used to remove the file.
+Upon completion,
+.Fa xprt\->xp_fd
+is the transport's socket descriptor.
+This routine returns
+.Dv NULL
+if it fails.
+Since
+.Ux Ns -based
+.Tn RPC
+uses buffered
+.Tn I/O ,
+users may specify the size of buffers; values of zero
+choose suitable defaults.
+.Pp
+.It Xo
+.Ft "SVCXPRT *"
+.Xc
+.It Xo
+.Fn svcunixfd_create "int fd" "u_int sendsize" "u_int recvsize"
+.Xc
+.Pp
+Create a service on top of any open descriptor.
+The
+.Fa sendsize
+and
+.Fa recvsize
+arguments
+indicate sizes for the send and receive buffers.
+If they are
+zero, a reasonable default is chosen.
+.Pp
+.It Xo
+.Ft "SVCXPRT *"
+.Xc
+.It Xo
+.Fn svcfd_create "int fd" "u_int sendsize" "u_int recvsize"
+.Xc
+.Pp
+Create a service on top of any open descriptor.
+Typically,
+this
+descriptor is a connected socket for a stream protocol such
+as
+.Tn TCP .
+The
+.Fa sendsize
+and
+.Fa recvsize
+arguments
+indicate sizes for the send and receive buffers.
+If they are
+zero, a reasonable default is chosen.
+.Pp
+.It Xo
+.Ft "SVCXPRT *"
+.Xc
+.It Xo
+.Fn svcudp_bufcreate "int sock" "u_int sendsize" "u_int recvsize"
+.Xc
+.Pp
+This routine creates a
+.Tn UDP/IP Ns \-based
+.Tn RPC
+service transport, to which it returns a pointer.
+The transport is associated with the socket
+.Fa sock ,
+which may be
+.Dv RPC_ANYSOCK ,
+in which case a new socket is created.
+If the socket is not bound to a local
+.Tn UDP
+port, then this routine binds it to an arbitrary port.
+Upon
+completion,
+.Fa xprt\->xp_fd
+is the transport's socket descriptor, and
+.Fa xprt\->xp_port
+is the transport's port number.
+This routine returns
+.Dv NULL
+if it fails.
+.Pp
+This allows the user to specify the maximum packet size for sending and
+receiving
+.Tn UDP Ns \-based
+.Tn RPC
+messages.
+.Pp
+.It Xo
+.Ft bool_t
+.Fn xdr_accepted_reply "XDR *xdrs" "struct accepted_reply *ar"
+.Xc
+.Pp
+Used for encoding
+.Tn RPC
+reply messages.
+This routine is useful for users who
+wish to generate
+.Tn RPC Ns \-style
+messages without using the
+.Tn RPC
+package.
+.Pp
+.It Xo
+.Ft bool_t
+.Fn xdr_authunix_parms "XDR *xdrs" "struct authunix_parms *aupp"
+.Xc
+.Pp
+Used for describing
+.Ux
+credentials.
+This routine is useful for users
+who wish to generate these credentials without using the
+.Tn RPC
+authentication package.
+.Pp
+.It Xo
+.Ft void
+.Xc
+.It Xo
+.Ft bool_t
+.Fn xdr_callhdr "XDR *xdrs" "struct rpc_msg *chdr"
+.Xc
+.Pp
+Used for describing
+.Tn RPC
+call header messages.
+This routine is useful for users who wish to generate
+.Tn RPC Ns \-style
+messages without using the
+.Tn RPC
+package.
+.Pp
+.It Xo
+.Ft bool_t
+.Fn xdr_callmsg "XDR *xdrs" "struct rpc_msg *cmsg"
+.Xc
+.Pp
+Used for describing
+.Tn RPC
+call messages.
+This routine is useful for users who wish to generate
+.Tn RPC Ns \-style
+messages without using the
+.Tn RPC
+package.
+.Pp
+.It Xo
+.Ft bool_t
+.Fn xdr_opaque_auth "XDR *xdrs" "struct opaque_auth *ap"
+.Xc
+.Pp
+Used for describing
+.Tn RPC
+authentication information messages.
+This routine is useful for users who wish to generate
+.Tn RPC Ns \-style
+messages without using the
+.Tn RPC
+package.
+.Pp
+.It Xo
+.Vt struct pmap ;
+.Xc
+.It Xo
+.Ft bool_t
+.Fn xdr_pmap "XDR *xdrs" "struct pmap *regs"
+.Xc
+.Pp
+Used for describing arguments to various
+.Xr rpcbind 8
+procedures, externally.
+This routine is useful for users who wish to generate
+these arguments without using the
+.Fn pmap_*
+interface.
+.Pp
+.It Xo
+.Ft bool_t
+.Fn xdr_pmaplist "XDR *xdrs" "struct pmaplist **rp"
+.Xc
+.Pp
+Used for describing a list of port mappings, externally.
+This routine is useful for users who wish to generate
+these arguments without using the
+.Fn pmap_*
+interface.
+.Pp
+.It Xo
+.Ft bool_t
+.Fn xdr_rejected_reply "XDR *xdrs" "struct rejected_reply *rr"
+.Xc
+.Pp
+Used for describing
+.Tn RPC
+reply messages.
+This routine is useful for users who wish to generate
+.Tn RPC Ns \-style
+messages without using the
+.Tn RPC
+package.
+.Pp
+.It Xo
+.Ft bool_t
+.Fn xdr_replymsg "XDR *xdrs" "struct rpc_msg *rmsg"
+.Xc
+.Pp
+Used for describing
+.Tn RPC
+reply messages.
+This routine is useful for users who wish to generate
+.Tn RPC
+style messages without using the
+.Tn RPC
+package.
+.Pp
+.It Xo
+.Ft void
+.Xc
+.It Xo
+.Fn xprt_register "SVCXPRT *xprt"
+.Xc
+.Pp
+After
+.Tn RPC
+service transport handles are created,
+they should register themselves with the
+.Tn RPC
+service package.
+This routine modifies the global variable
+.Va svc_fds .
+Service implementors usually do not need this routine.
+.Pp
+.It Xo
+.Ft void
+.Xc
+.It Xo
+.Fn xprt_unregister "SVCXPRT *xprt"
+.Xc
+.Pp
+Before an
+.Tn RPC
+service transport handle is destroyed,
+it should unregister itself with the
+.Tn RPC
+service package.
+This routine modifies the global variable
+.Va svc_fds .
+Service implementors usually do not need this routine.
+.El
+.Sh SEE ALSO
+.Xr rpc_secure 3 ,
+.Xr xdr 3
+.Rs
+.%T "Remote Procedure Calls: Protocol Specification"
+.Re
+.Rs
+.%T "Remote Procedure Call Programming Guide"
+.Re
+.Rs
+.%T "rpcgen Programming Guide"
+.Re
+.Rs
+.%T "RPC: Remote Procedure Call Protocol Specification"
+.%O RFC1050
+.%Q "Sun Microsystems, Inc., USC-ISI"
+.Re
diff --git a/lib/libc/rpc/rpc_soc.c b/lib/libc/rpc/rpc_soc.c
new file mode 100644
index 000000000000..64516a9fe806
--- /dev/null
+++ b/lib/libc/rpc/rpc_soc.c
@@ -0,0 +1,533 @@
+/* $NetBSD: rpc_soc.c,v 1.6 2000/07/06 03:10:35 christos Exp $ */
+
+/*-
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* #ident "@(#)rpc_soc.c 1.17 94/04/24 SMI" */
+
+/*
+ * Copyright (c) 1986-1991 by Sun Microsystems Inc.
+ * In addition, portions of such source code were derived from Berkeley
+ * 4.3 BSD under license from the Regents of the University of
+ * California.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)rpc_soc.c 1.41 89/05/02 Copyr 1988 Sun Micro";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifdef PORTMAP
+/*
+ * rpc_soc.c
+ *
+ * The backward compatibility routines for the earlier implementation
+ * of RPC, where the only transports supported were tcp/ip and udp/ip.
+ * Based on berkeley socket abstraction, now implemented on the top
+ * of TLI/Streams
+ */
+
+#include "namespace.h"
+#include "reentrant.h"
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <stdio.h>
+#include <rpc/rpc.h>
+#include <rpc/pmap_clnt.h>
+#include <rpc/pmap_prot.h>
+#include <rpc/nettype.h>
+#include <syslog.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <errno.h>
+#include <syslog.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+#include "rpc_com.h"
+#include "mt_misc.h"
+
+static CLIENT *clnt_com_create(struct sockaddr_in *, rpcprog_t, rpcvers_t,
+ int *, u_int, u_int, char *);
+static SVCXPRT *svc_com_create(int, u_int, u_int, char *);
+static bool_t rpc_wrap_bcast(char *, struct netbuf *, struct netconfig *);
+
+/* XXX */
+#define IN4_LOCALHOST_STRING "127.0.0.1"
+#define IN6_LOCALHOST_STRING "::1"
+
+/*
+ * A common clnt create routine
+ */
+static CLIENT *
+clnt_com_create(struct sockaddr_in *raddr, rpcprog_t prog, rpcvers_t vers, int *sockp,
+ u_int sendsz, u_int recvsz, char *tp)
+{
+ CLIENT *cl;
+ int madefd = FALSE;
+ int fd = *sockp;
+ struct netconfig *nconf;
+ struct netbuf bindaddr;
+
+ mutex_lock(&rpcsoc_lock);
+ if ((nconf = __rpc_getconfip(tp)) == NULL) {
+ rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
+ mutex_unlock(&rpcsoc_lock);
+ return (NULL);
+ }
+ if (fd == RPC_ANYSOCK) {
+ fd = __rpc_nconf2fd(nconf);
+ if (fd == -1)
+ goto syserror;
+ madefd = TRUE;
+ }
+
+ if (raddr->sin_port == 0) {
+ u_int proto;
+ u_short sport;
+
+ mutex_unlock(&rpcsoc_lock); /* pmap_getport is recursive */
+ proto = strcmp(tp, "udp") == 0 ? IPPROTO_UDP : IPPROTO_TCP;
+ sport = pmap_getport(raddr, (u_long)prog, (u_long)vers,
+ proto);
+ if (sport == 0) {
+ goto err;
+ }
+ raddr->sin_port = htons(sport);
+ mutex_lock(&rpcsoc_lock); /* pmap_getport is recursive */
+ }
+
+ /* Transform sockaddr_in to netbuf */
+ bindaddr.maxlen = bindaddr.len = sizeof (struct sockaddr_in);
+ bindaddr.buf = raddr;
+
+ bindresvport(fd, NULL);
+ cl = clnt_tli_create(fd, nconf, &bindaddr, prog, vers,
+ sendsz, recvsz);
+ if (cl) {
+ if (madefd == TRUE) {
+ /*
+ * The fd should be closed while destroying the handle.
+ */
+ (void) CLNT_CONTROL(cl, CLSET_FD_CLOSE, NULL);
+ *sockp = fd;
+ }
+ (void) freenetconfigent(nconf);
+ mutex_unlock(&rpcsoc_lock);
+ return (cl);
+ }
+ goto err;
+
+syserror:
+ rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+ rpc_createerr.cf_error.re_errno = errno;
+
+err: if (madefd == TRUE)
+ (void)_close(fd);
+ (void) freenetconfigent(nconf);
+ mutex_unlock(&rpcsoc_lock);
+ return (NULL);
+}
+
+CLIENT *
+clntudp_bufcreate(struct sockaddr_in *raddr, u_long prog, u_long vers,
+ struct timeval wait, int *sockp, u_int sendsz, u_int recvsz)
+{
+ CLIENT *cl;
+
+ cl = clnt_com_create(raddr, (rpcprog_t)prog, (rpcvers_t)vers, sockp,
+ sendsz, recvsz, "udp");
+ if (cl == NULL) {
+ return (NULL);
+ }
+ (void) CLNT_CONTROL(cl, CLSET_RETRY_TIMEOUT, &wait);
+ return (cl);
+}
+
+CLIENT *
+clntudp_create(struct sockaddr_in *raddr, u_long program, u_long version,
+ struct timeval wait, int *sockp)
+{
+
+ return clntudp_bufcreate(raddr, program, version, wait, sockp,
+ UDPMSGSIZE, UDPMSGSIZE);
+}
+
+CLIENT *
+clnttcp_create(struct sockaddr_in *raddr, u_long prog, u_long vers, int *sockp,
+ u_int sendsz, u_int recvsz)
+{
+
+ return clnt_com_create(raddr, (rpcprog_t)prog, (rpcvers_t)vers, sockp,
+ sendsz, recvsz, "tcp");
+}
+
+CLIENT *
+clntraw_create(u_long prog, u_long vers)
+{
+
+ return clnt_raw_create((rpcprog_t)prog, (rpcvers_t)vers);
+}
+
+/*
+ * A common server create routine
+ */
+static SVCXPRT *
+svc_com_create(int fd, u_int sendsize, u_int recvsize, char *netid)
+{
+ struct netconfig *nconf;
+ SVCXPRT *svc;
+ int madefd = FALSE;
+ int port;
+ struct sockaddr_in sin;
+
+ if ((nconf = __rpc_getconfip(netid)) == NULL) {
+ (void) syslog(LOG_ERR, "Could not get %s transport", netid);
+ return (NULL);
+ }
+ if (fd == RPC_ANYSOCK) {
+ fd = __rpc_nconf2fd(nconf);
+ if (fd == -1) {
+ (void) freenetconfigent(nconf);
+ (void) syslog(LOG_ERR,
+ "svc%s_create: could not open connection", netid);
+ return (NULL);
+ }
+ madefd = TRUE;
+ }
+
+ memset(&sin, 0, sizeof sin);
+ sin.sin_family = AF_INET;
+ bindresvport(fd, &sin);
+ _listen(fd, SOMAXCONN);
+ svc = svc_tli_create(fd, nconf, NULL, sendsize, recvsize);
+ (void) freenetconfigent(nconf);
+ if (svc == NULL) {
+ if (madefd)
+ (void)_close(fd);
+ return (NULL);
+ }
+ port = (((struct sockaddr_in *)svc->xp_ltaddr.buf)->sin_port);
+ svc->xp_port = ntohs(port);
+ return (svc);
+}
+
+SVCXPRT *
+svctcp_create(int fd, u_int sendsize, u_int recvsize)
+{
+
+ return svc_com_create(fd, sendsize, recvsize, "tcp");
+}
+
+SVCXPRT *
+svcudp_bufcreate(int fd, u_int sendsz, u_int recvsz)
+{
+
+ return svc_com_create(fd, sendsz, recvsz, "udp");
+}
+
+SVCXPRT *
+svcfd_create(int fd, u_int sendsize, u_int recvsize)
+{
+
+ return svc_fd_create(fd, sendsize, recvsize);
+}
+
+
+SVCXPRT *
+svcudp_create(int fd)
+{
+
+ return svc_com_create(fd, UDPMSGSIZE, UDPMSGSIZE, "udp");
+}
+
+SVCXPRT *
+svcraw_create(void)
+{
+
+ return svc_raw_create();
+}
+
+int
+get_myaddress(struct sockaddr_in *addr)
+{
+
+ memset((void *) addr, 0, sizeof(*addr));
+ addr->sin_family = AF_INET;
+ addr->sin_port = htons(PMAPPORT);
+ addr->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ return (0);
+}
+
+/*
+ * For connectionless "udp" transport. Obsoleted by rpc_call().
+ */
+int
+callrpc(const char *host, int prognum, int versnum, int procnum,
+ xdrproc_t inproc, void *in, xdrproc_t outproc, void *out)
+{
+
+ return (int)rpc_call(host, (rpcprog_t)prognum, (rpcvers_t)versnum,
+ (rpcproc_t)procnum, inproc, in, outproc, out, "udp");
+}
+
+/*
+ * For connectionless kind of transport. Obsoleted by rpc_reg()
+ */
+int
+registerrpc(int prognum, int versnum, int procnum,
+ char *(*progname)(char [UDPMSGSIZE]),
+ xdrproc_t inproc, xdrproc_t outproc)
+{
+
+ return rpc_reg((rpcprog_t)prognum, (rpcvers_t)versnum,
+ (rpcproc_t)procnum, progname, inproc, outproc, "udp");
+}
+
+/*
+ * All the following clnt_broadcast stuff is convulated; it supports
+ * the earlier calling style of the callback function
+ */
+static thread_key_t clnt_broadcast_key;
+static resultproc_t clnt_broadcast_result_main;
+static once_t clnt_broadcast_once = ONCE_INITIALIZER;
+
+static void
+clnt_broadcast_key_init(void)
+{
+
+ thr_keycreate(&clnt_broadcast_key, free);
+}
+
+/*
+ * Need to translate the netbuf address into sockaddr_in address.
+ * Dont care about netid here.
+ */
+/* ARGSUSED */
+static bool_t
+rpc_wrap_bcast(char *resultp, struct netbuf *addr, struct netconfig *nconf)
+/*
+ * char *resultp; // results of the call
+ * struct netbuf *addr; // address of the guy who responded
+ * struct netconfig *nconf; // Netconf of the transport
+ */
+{
+ resultproc_t clnt_broadcast_result;
+
+ if (strcmp(nconf->nc_netid, "udp"))
+ return (FALSE);
+ if (thr_main())
+ clnt_broadcast_result = clnt_broadcast_result_main;
+ else
+ clnt_broadcast_result = (resultproc_t)thr_getspecific(clnt_broadcast_key);
+ return (*clnt_broadcast_result)(resultp,
+ (struct sockaddr_in *)addr->buf);
+}
+
+/*
+ * Broadcasts on UDP transport. Obsoleted by rpc_broadcast().
+ */
+enum clnt_stat
+clnt_broadcast(u_long prog, u_long vers, u_long proc, xdrproc_t xargs,
+ void *argsp, xdrproc_t xresults, void *resultsp, resultproc_t eachresult)
+/*
+ * u_long prog; // program number
+ * u_long vers; // version number
+ * u_long proc; // procedure number
+ * xdrproc_t xargs; // xdr routine for args
+ * void *argsp; // pointer to args
+ * xdrproc_t xresults; // xdr routine for results
+ * void *resultsp; // pointer to results
+ * resultproc_t eachresult; // call with each result obtained
+ */
+{
+
+ if (thr_main())
+ clnt_broadcast_result_main = eachresult;
+ else {
+ thr_once(&clnt_broadcast_once, clnt_broadcast_key_init);
+ thr_setspecific(clnt_broadcast_key, (void *) eachresult);
+ }
+ return rpc_broadcast((rpcprog_t)prog, (rpcvers_t)vers,
+ (rpcproc_t)proc, xargs, argsp, xresults, resultsp,
+ (resultproc_t) rpc_wrap_bcast, "udp");
+}
+
+/*
+ * Create the client des authentication object. Obsoleted by
+ * authdes_seccreate().
+ */
+AUTH *
+authdes_create(char *servername, u_int window, struct sockaddr *syncaddr,
+ des_block *ckey)
+/*
+ * char *servername; // network name of server
+ * u_int window; // time to live
+ * struct sockaddr *syncaddr; // optional hostaddr to sync with
+ * des_block *ckey; // optional conversation key to use
+ */
+{
+ AUTH *dummy;
+ AUTH *nauth;
+ char hostname[NI_MAXHOST];
+
+ if (syncaddr) {
+ /*
+ * Change addr to hostname, because that is the way
+ * new interface takes it.
+ */
+ if (getnameinfo(syncaddr, syncaddr->sa_len, hostname,
+ sizeof hostname, NULL, 0, 0) != 0)
+ goto fallback;
+
+ nauth = authdes_seccreate(servername, window, hostname, ckey);
+ return (nauth);
+ }
+fallback:
+ dummy = authdes_seccreate(servername, window, NULL, ckey);
+ return (dummy);
+}
+
+/*
+ * Create a client handle for a unix connection. Obsoleted by clnt_vc_create()
+ */
+CLIENT *
+clntunix_create(struct sockaddr_un *raddr, u_long prog, u_long vers, int *sockp,
+ u_int sendsz, u_int recvsz)
+{
+ struct netbuf *svcaddr;
+ CLIENT *cl;
+ int len;
+
+ cl = NULL;
+ svcaddr = NULL;
+ if ((raddr->sun_len == 0) ||
+ ((svcaddr = malloc(sizeof(struct netbuf))) == NULL ) ||
+ ((svcaddr->buf = malloc(sizeof(struct sockaddr_un))) == NULL)) {
+ free(svcaddr);
+ rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+ rpc_createerr.cf_error.re_errno = errno;
+ return(cl);
+ }
+ if (*sockp < 0) {
+ *sockp = _socket(AF_LOCAL, SOCK_STREAM, 0);
+ len = raddr->sun_len = SUN_LEN(raddr);
+ if ((*sockp < 0) || (_connect(*sockp,
+ (struct sockaddr *)raddr, len) < 0)) {
+ rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+ rpc_createerr.cf_error.re_errno = errno;
+ if (*sockp != -1)
+ (void)_close(*sockp);
+ goto done;
+ }
+ }
+ svcaddr->buf = raddr;
+ svcaddr->len = raddr->sun_len;
+ svcaddr->maxlen = sizeof (struct sockaddr_un);
+ cl = clnt_vc_create(*sockp, svcaddr, prog,
+ vers, sendsz, recvsz);
+done:
+ free(svcaddr->buf);
+ free(svcaddr);
+ return(cl);
+}
+
+/*
+ * Creates, registers, and returns a (rpc) unix based transporter.
+ * Obsoleted by svc_vc_create().
+ */
+SVCXPRT *
+svcunix_create(int sock, u_int sendsize, u_int recvsize, char *path)
+{
+ struct netconfig *nconf;
+ void *localhandle;
+ struct sockaddr_un sun;
+ struct sockaddr *sa;
+ struct t_bind taddr;
+ SVCXPRT *xprt;
+ int addrlen;
+
+ xprt = (SVCXPRT *)NULL;
+ localhandle = setnetconfig();
+ while ((nconf = getnetconfig(localhandle)) != NULL) {
+ if (nconf->nc_protofmly != NULL &&
+ strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0)
+ break;
+ }
+ if (nconf == NULL)
+ goto done;
+
+ if ((sock = __rpc_nconf2fd(nconf)) < 0)
+ goto done;
+
+ memset(&sun, 0, sizeof sun);
+ sun.sun_family = AF_LOCAL;
+ if (strlcpy(sun.sun_path, path, sizeof(sun.sun_path)) >=
+ sizeof(sun.sun_path))
+ goto done;
+ sun.sun_len = SUN_LEN(&sun);
+ addrlen = sizeof (struct sockaddr_un);
+ sa = (struct sockaddr *)&sun;
+
+ if (_bind(sock, sa, addrlen) < 0)
+ goto done;
+
+ taddr.addr.len = taddr.addr.maxlen = addrlen;
+ taddr.addr.buf = malloc(addrlen);
+ if (taddr.addr.buf == NULL)
+ goto done;
+ memcpy(taddr.addr.buf, sa, addrlen);
+
+ if (nconf->nc_semantics != NC_TPI_CLTS) {
+ if (_listen(sock, SOMAXCONN) < 0) {
+ free(taddr.addr.buf);
+ goto done;
+ }
+ }
+
+ xprt = (SVCXPRT *)svc_tli_create(sock, nconf, &taddr, sendsize, recvsize);
+
+done:
+ endnetconfig(localhandle);
+ return(xprt);
+}
+
+/*
+ * Like svunix_create(), except the routine takes any *open* UNIX file
+ * descriptor as its first input. Obsoleted by svc_fd_create();
+ */
+SVCXPRT *
+svcunixfd_create(int fd, u_int sendsize, u_int recvsize)
+{
+ return (svc_fd_create(fd, sendsize, recvsize));
+}
+
+#endif /* PORTMAP */
diff --git a/lib/libc/rpc/rpc_svc_calls.3 b/lib/libc/rpc/rpc_svc_calls.3
new file mode 100644
index 000000000000..873296210cb4
--- /dev/null
+++ b/lib/libc/rpc/rpc_svc_calls.3
@@ -0,0 +1,267 @@
+.\" @(#)rpc_svc_calls.3n 1.28 93/05/10 SMI; from SVr4
+.\" Copyright 1989 AT&T
+.\" @(#)rpc_svc_calls 1.5 89/07/25 SMI;
+.\" Copyright (c) 1988 Sun Microsystems, Inc. - All Rights Reserved.
+.\" $NetBSD: rpc_svc_calls.3,v 1.1 2000/06/02 23:11:13 fvdl Exp $
+.\" $FreeBSD$
+.Dd May 3, 1993
+.Dt RPC_SVC_CALLS 3
+.Os
+.Sh NAME
+.Nm svc_dg_enablecache ,
+.Nm svc_exit ,
+.Nm svc_fdset ,
+.Nm svc_freeargs ,
+.Nm svc_getargs ,
+.Nm svc_getreq_common ,
+.Nm svc_getreq_poll ,
+.Nm svc_getreqset ,
+.Nm svc_getrpccaller ,
+.Nm svc_pollset ,
+.Nm svc_run ,
+.Nm svc_sendreply
+.Nd library routines for RPC servers
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In rpc/rpc.h
+.Ft int
+.Fn svc_dg_enablecache "SVCXPRT *xprt" "const unsigned cache_size"
+.Ft void
+.Fn svc_exit "void"
+.Ft bool_t
+.Fn svc_freeargs "const SVCXPRT *xprt" "const xdrproc_t inproc" "caddr_t in"
+.Ft bool_t
+.Fn svc_getargs "const SVCXPRT *xprt" "const xdrproc_t inproc" "caddr_t in"
+.Ft void
+.Fn svc_getreq_common "const int fd"
+.Ft void
+.Fn svc_getreq_poll "struct pollfd *pfdp" "const int pollretval"
+.Ft void
+.Fn svc_getreqset "fd_set * rdfds"
+.Ft "struct netbuf *"
+.Fn svc_getrpccaller "const SVCXPRT *xprt"
+.Ft "struct cmsgcred *"
+.Fn __svc_getcallercreds "const SVCXPRT *xprt"
+.Vt struct pollfd svc_pollset[FD_SETSIZE];
+.Ft void
+.Fn svc_run "void"
+.Ft bool_t
+.Fn svc_sendreply "SVCXPRT *xprt" "xdrproc_t outproc" "void *out"
+.Sh DESCRIPTION
+These routines are part of the
+RPC
+library which allows C language programs to make procedure
+calls on other machines across the network.
+.Pp
+These routines are associated with the server side of the
+RPC mechanism.
+Some of them are called by the server side dispatch function,
+while others
+(such as
+.Fn svc_run )
+are called when the server is initiated.
+.\" .Pp
+.\" In the current implementation, the service transport handle,
+.\" .Dv SVCXPRT ,
+.\" contains a single data area for decoding arguments and encoding results.
+.\" Therefore, this structure cannot be freely shared between threads that call
+.\" functions that do this.
+.\" Routines on this page that are affected by this
+.\" restriction are marked as unsafe for MT applications.
+.Sh Routines
+See
+.Xr rpc 3
+for the definition of the
+.Vt SVCXPRT
+data structure.
+.Bl -tag -width __svc_getcallercreds()
+.It Fn svc_dg_enablecache
+This function allocates a duplicate request cache for the
+service endpoint
+.Fa xprt ,
+large enough to hold
+.Fa cache_size
+entries.
+Once enabled, there is no way to disable caching.
+This routine returns 0 if space necessary for a cache of the given size
+was successfully allocated, and 1 otherwise.
+.It Fn svc_exit
+This function, when called by any of the RPC server procedure or
+otherwise, causes
+.Fn svc_run
+to return.
+.Pp
+As currently implemented,
+.Fn svc_exit
+zeroes the
+.Va svc_fdset
+global variable.
+If RPC server activity is to be resumed,
+services must be reregistered with the RPC library
+either through one of the
+.Xr rpc_svc_create 3
+functions, or using
+.Fn xprt_register .
+The
+.Fn svc_exit
+function
+has global scope and ends all RPC server activity.
+.It Xo
+.Vt fd_set Va svc_fdset
+.Xc
+A global variable reflecting the
+RPC server's read file descriptor bit mask; it is suitable as an argument
+to the
+.Xr select 2
+system call.
+This is only of interest
+if service implementors do not call
+.Fn svc_run ,
+but rather do their own asynchronous event processing.
+This variable is read-only (do not pass its address to
+.Xr select 2 ! ) ,
+yet it may change after calls to
+.Fn svc_getreqset
+or any creation routines.
+.It Fn svc_freeargs
+A function macro that frees any data allocated by the
+RPC/XDR system when it decoded the arguments to a service procedure
+using
+.Fn svc_getargs .
+This routine returns
+.Dv TRUE
+if the results were successfully
+freed, and
+.Dv FALSE
+otherwise.
+.It Fn svc_getargs
+A function macro that decodes the arguments of an
+RPC request associated with the RPC
+service transport handle
+.Fa xprt .
+The
+.Fa in
+argument
+is the address where the arguments will be placed;
+.Fa inproc
+is the XDR
+routine used to decode the arguments.
+This routine returns
+.Dv TRUE
+if decoding succeeds, and
+.Dv FALSE
+otherwise.
+.It Fn svc_getreq_common
+This routine is called to handle a request on the given
+file descriptor.
+.It Fn svc_getreq_poll
+This routine is only of interest if a service implementor
+does not call
+.Fn svc_run ,
+but instead implements custom asynchronous event processing.
+It is called when
+.Xr poll 2
+has determined that an RPC request has arrived on some RPC
+file descriptors;
+.Fa pollretval
+is the return value from
+.Xr poll 2
+and
+.Fa pfdp
+is the array of
+.Vt pollfd
+structures on which the
+.Xr poll 2
+was done.
+It is assumed to be an array large enough to
+contain the maximal number of descriptors allowed.
+.It Fn svc_getreqset
+This routine is only of interest if a service implementor
+does not call
+.Fn svc_run ,
+but instead implements custom asynchronous event processing.
+It is called when
+.Xr poll 2
+has determined that an RPC
+request has arrived on some RPC file descriptors;
+.Fa rdfds
+is the resultant read file descriptor bit mask.
+The routine returns when all file descriptors
+associated with the value of
+.Fa rdfds
+have been serviced.
+.It Fn svc_getrpccaller
+The approved way of getting the network address of the caller
+of a procedure associated with the
+RPC service transport handle
+.Fa xprt .
+.It Fn __svc_getcallercreds
+.Em Warning :
+this macro is specific to
+.Fx
+and thus not portable.
+This macro returns a pointer to a
+.Vt cmsgcred
+structure, defined in
+.In sys/socket.h ,
+identifying the calling client.
+This only works if the client is
+calling the server over an
+.Dv AF_LOCAL
+socket.
+.It Xo
+.Vt struct pollfd Va svc_pollset[FD_SETSIZE] ;
+.Xc
+.Va svc_pollset
+is an array of
+.Vt pollfd
+structures derived from
+.Va svc_fdset[] .
+It is suitable as an argument to the
+.Xr poll 2
+system call.
+The derivation of
+.Va svc_pollset
+from
+.Va svc_fdset
+is made in the current implementation in
+.Fn svc_run .
+Service implementors who do not call
+.Fn svc_run
+and who wish to use this array must perform this derivation themselves.
+.It Fn svc_run
+This routine never returns.
+It waits for RPC
+requests to arrive, and calls the appropriate service
+procedure using
+.Fn svc_getreq_poll
+when one arrives.
+This procedure is usually waiting for the
+.Xr poll 2
+system call to return.
+.It Fn svc_sendreply
+Called by an RPC service's dispatch routine to send the results of a
+remote procedure call.
+The
+.Fa xprt
+argument
+is the request's associated transport handle;
+.Fa outproc
+is the XDR
+routine which is used to encode the results; and
+.Fa out
+is the address of the results.
+This routine returns
+.Dv TRUE
+if it succeeds,
+.Dv FALSE
+otherwise.
+.El
+.Sh SEE ALSO
+.Xr poll 2 ,
+.Xr select 2 ,
+.Xr rpc 3 ,
+.Xr rpc_svc_create 3 ,
+.Xr rpc_svc_err 3 ,
+.Xr rpc_svc_reg 3
diff --git a/lib/libc/rpc/rpc_svc_create.3 b/lib/libc/rpc/rpc_svc_create.3
new file mode 100644
index 000000000000..4016a6c36b03
--- /dev/null
+++ b/lib/libc/rpc/rpc_svc_create.3
@@ -0,0 +1,337 @@
+.\" @(#)rpc_svc_create.3n 1.26 93/08/26 SMI; from SVr4
+.\" Copyright 1989 AT&T
+.\" @(#)rpc_svc_create 1.3 89/06/28 SMI;
+.\" Copyright (c) 1988 Sun Microsystems, Inc. - All Rights Reserved.
+.\" $FreeBSD$
+.Dd May 3, 1993
+.Dt RPC_SVC_CREATE 3
+.Os
+.Sh NAME
+.Nm rpc_svc_create ,
+.Nm svc_control ,
+.Nm svc_create ,
+.Nm svc_destroy ,
+.Nm svc_dg_create ,
+.Nm svc_fd_create ,
+.Nm svc_raw_create ,
+.Nm svc_tli_create ,
+.Nm svc_tp_create ,
+.Nm svc_vc_create
+.Nd library routines for the creation of server handles
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In rpc/rpc.h
+.Ft bool_t
+.Fn svc_control "SVCXPRT *svc" "const u_int req" "void *info"
+.Ft int
+.Fn svc_create "void (*dispatch)(struct svc_req *, SVCXPRT *)" "const rpcprog_t prognum" "const rpcvers_t versnum" "const char *nettype"
+.Ft SVCXPRT *
+.Fn svc_dg_create "const int fildes" "const u_int sendsz" "const u_int recvsz"
+.Ft void
+.Fn svc_destroy "SVCXPRT *xprt"
+.Ft "SVCXPRT *"
+.Fn svc_fd_create "const int fildes" "const u_int sendsz" "const u_int recvsz"
+.Ft "SVCXPRT *"
+.Fn svc_raw_create "void"
+.Ft "SVCXPRT *"
+.Fn svc_tli_create "const int fildes" "const struct netconfig *netconf" "const struct t_bind *bindaddr" "const u_int sendsz" "const u_int recvsz"
+.Ft "SVCXPRT *"
+.Fn svc_tp_create "void (*dispatch)(struct svc_req *, SVCXPRT *)" "const rpcprog_t prognum" "const rpcvers_t versnum" "const struct netconfig *netconf"
+.Ft "SVCXPRT *"
+.Fn svc_vc_create "const int fildes" "const u_int sendsz" "const u_int recvsz"
+.Sh DESCRIPTION
+These routines are part of the RPC
+library which allows C language programs to make procedure
+calls on servers across the network.
+These routines deal with the creation of service handles.
+Once the handle is created, the server can be invoked by calling
+.Fn svc_run .
+.Sh Routines
+See
+.Xr rpc 3
+for the definition of the
+.Vt SVCXPRT
+data structure.
+.Bl -tag -width XXXXX
+.It Fn svc_control
+A function to change or retrieve various information
+about a service object.
+The
+.Fa req
+argument
+indicates the type of operation and
+.Fa info
+is a pointer to the information.
+The supported values of
+.Fa req ,
+their argument types, and what they do are:
+.Bl -tag -width SVCGET_XID
+.It Dv SVCGET_VERSQUIET
+If a request is received for a program number
+served by this server but the version number
+is outside the range registered with the server,
+an
+.Dv RPC_PROGVERSMISMATCH
+error will normally
+be returned.
+The
+.Fa info
+argument
+should be a pointer to an
+integer.
+Upon successful completion of the
+.Dv SVCGET_VERSQUIET
+request,
+.Fa *info
+contains an
+integer which describes the server's current
+behavior: 0 indicates normal server behavior
+(that is, an
+.Dv RPC_PROGVERSMISMATCH
+error
+will be returned); 1 indicates that the out of
+range request will be silently ignored.
+.It Dv SVCSET_VERSQUIET
+If a request is received for a program number
+served by this server but the version number
+is outside the range registered with the server,
+an
+.Dv RPC_PROGVERSMISMATCH
+error will normally
+be returned.
+It is sometimes desirable to
+change this behavior.
+The
+.Fa info
+argument
+should be a
+pointer to an integer which is either 0
+(indicating normal server behavior - an
+.Dv RPC_PROGVERSMISMATCH
+error will be returned),
+or 1 (indicating that the out of range request
+should be silently ignored).
+.El
+.It Fn svc_create
+The
+.Fn svc_create
+function
+creates server handles for all the transports
+belonging to the class
+.Fa nettype .
+The
+.Fa nettype
+argument
+defines a class of transports which can be used
+for a particular application.
+The transports are tried in left to right order in
+.Ev NETPATH
+variable or in top to bottom order in the netconfig database.
+If
+.Fa nettype
+is
+.Dv NULL ,
+it defaults to
+.Qq netpath .
+.Pp
+The
+.Fn svc_create
+function
+registers itself with the rpcbind
+service (see
+.Xr rpcbind 8 ) .
+The
+.Fa dispatch
+function
+is called when there is a remote procedure call for the given
+.Fa prognum
+and
+.Fa versnum ;
+this requires calling
+.Fn svc_run
+(see
+.Fn svc_run
+in
+.Xr rpc_svc_reg 3 ) .
+If
+.Fn svc_create
+succeeds, it returns the number of server
+handles it created,
+otherwise it returns 0 and an error message is logged.
+.It Fn svc_destroy
+A function macro that destroys the RPC
+service handle
+.Fa xprt .
+Destruction usually involves deallocation
+of private data structures,
+including
+.Fa xprt
+itself.
+Use of
+.Fa xprt
+is undefined after calling this routine.
+.It Fn svc_dg_create
+This routine creates a connectionless RPC
+service handle, and returns a pointer to it.
+This routine returns
+.Dv NULL
+if it fails, and an error message is logged.
+The
+.Fa sendsz
+and
+.Fa recvsz
+arguments
+are arguments used to specify the size of the buffers.
+If they are 0, suitable defaults are chosen.
+The file descriptor
+.Fa fildes
+should be open and bound.
+The server is not registered with
+.Xr rpcbind 8 .
+.Pp
+Warning:
+since connectionless-based RPC
+messages can only hold limited amount of encoded data,
+this transport cannot be used for procedures
+that take large arguments or return huge results.
+.It Fn svc_fd_create
+This routine creates a service on top of an open and bound file descriptor,
+and returns the handle to it.
+Typically, this descriptor is a connected file descriptor for a
+connection-oriented transport.
+The
+.Fa sendsz
+and
+.Fa recvsz
+arguments
+indicate sizes for the send and receive buffers.
+If they are 0, reasonable defaults are chosen.
+This routine returns
+.Dv NULL
+if it fails, and an error message is logged.
+.It Fn svc_raw_create
+This routine creates an RPC
+service handle and returns a pointer to it.
+The transport is really a buffer within the process's
+address space, so the corresponding RPC
+client should live in the same address space;
+(see
+.Fn clnt_raw_create
+in
+.Xr rpc_clnt_create 3 ) .
+This routine allows simulation of RPC and acquisition of
+RPC overheads (such as round trip times),
+without any kernel and networking interference.
+This routine returns
+.Dv NULL
+if it fails, and an error message is logged.
+.Pp
+Note:
+.Fn svc_run
+should not be called when the raw interface is being used.
+.It Fn svc_tli_create
+This routine creates an RPC
+server handle, and returns a pointer to it.
+The
+.Fa fildes
+argument
+is the file descriptor on which the service is listening.
+If
+.Fa fildes
+is
+.Dv RPC_ANYFD ,
+it opens a file descriptor on the transport specified by
+.Fa netconf .
+If the file descriptor is unbound and
+.Fa bindaddr
+is not
+.Dv NULL ,
+.Fa fildes
+is bound to the address specified by
+.Fa bindaddr ,
+otherwise
+.Fa fildes
+is bound to a default address chosen by the transport.
+.Pp
+Note: the
+.Vt t_bind
+structure comes from the TLI/XTI SysV interface, which
+.Nx
+does not use.
+The structure is defined in
+.In rpc/types.h
+for compatibility as:
+.Bd -literal
+struct t_bind {
+ struct netbuf addr; /* network address, see rpc(3) */
+ unsigned int qlen; /* queue length (for listen(2)) */
+};
+.Ed
+.Pp
+In the case where the default address is chosen,
+the number of outstanding connect requests is set to 8
+for connection-oriented transports.
+The user may specify the size of the send and receive buffers
+with the arguments
+.Fa sendsz
+and
+.Fa recvsz ;
+values of 0 choose suitable defaults.
+This routine returns
+.Dv NULL
+if it fails,
+and an error message is logged.
+The server is not registered with the
+.Xr rpcbind 8
+service.
+.It Fn svc_tp_create
+The
+.Fn svc_tp_create
+function
+creates a server handle for the network
+specified by
+.Fa netconf ,
+and registers itself with the rpcbind service.
+The
+.Fa dispatch
+function
+is called when there is a remote procedure call
+for the given
+.Fa prognum
+and
+.Fa versnum ;
+this requires calling
+.Fn svc_run .
+The
+.Fn svc_tp_create
+function
+returns the service handle if it succeeds,
+otherwise a
+.Dv NULL
+is returned and an error message is logged.
+.It Fn svc_vc_create
+This routine creates a connection-oriented RPC
+service and returns a pointer to it.
+This routine returns
+.Dv NULL
+if it fails, and an error message is logged.
+The users may specify the size of the send and receive buffers
+with the arguments
+.Fa sendsz
+and
+.Fa recvsz ;
+values of 0 choose suitable defaults.
+The file descriptor
+.Fa fildes
+should be open and bound.
+The server is not registered with the
+.Xr rpcbind 8
+service.
+.El
+.Sh SEE ALSO
+.Xr rpc 3 ,
+.Xr rpc_svc_calls 3 ,
+.Xr rpc_svc_err 3 ,
+.Xr rpc_svc_reg 3 ,
+.Xr rpcbind 8
diff --git a/lib/libc/rpc/rpc_svc_err.3 b/lib/libc/rpc/rpc_svc_err.3
new file mode 100644
index 000000000000..7a6b1f132f4c
--- /dev/null
+++ b/lib/libc/rpc/rpc_svc_err.3
@@ -0,0 +1,97 @@
+.\" @(#)rpc_svc_err.3n 1.23 93/08/31 SMI; from SVr4
+.\" Copyright 1989 AT&T
+.\" @(#)rpc_svc_err 1.4 89/06/28 SMI;
+.\" Copyright (c) 1988 Sun Microsystems, Inc. - All Rights Reserved.
+.\" $NetBSD: rpc_svc_err.3,v 1.1 2000/06/02 23:11:14 fvdl Exp $
+.\" $FreeBSD$
+.Dd May 3, 1993
+.Dt RPC_SVC_ERR 3
+.Os
+.Sh NAME
+.Nm rpc_svc_err ,
+.Nm svcerr_auth ,
+.Nm svcerr_decode ,
+.Nm svcerr_noproc ,
+.Nm svcerr_noprog ,
+.Nm svcerr_progvers ,
+.Nm svcerr_systemerr ,
+.Nm svcerr_weakauth
+.Nd library routines for server side remote procedure call errors
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In rpc/rpc.h
+.Ft void
+.Fn svcerr_auth "SVCXPRT *xprt" "enum auth_stat why"
+.Ft void
+.Fn svcerr_decode "SVCXPRT *xprt"
+.Ft void
+.Fn svcerr_noproc "SVCXPRT *xprt"
+.Ft void
+.Fn svcerr_noprog "SVCXPRT *xprt"
+.Ft void
+.Fn svcerr_progvers "SVCXPRT *xprt" "rpcvers_t low_vers" "rpcvers_t high_vers"
+.Ft void
+.Fn svcerr_systemerr "SVCXPRT *xprt"
+.Ft void
+.Fn svcerr_weakauth "SVCXPRT *xprt"
+.Sh DESCRIPTION
+These routines are part of the RPC
+library which allows C language programs to make procedure
+calls on other machines across the network.
+.Pp
+These routines can be called by the server side
+dispatch function if there is any error in the
+transaction with the client.
+.Sh Routines
+See
+.Xr rpc 3
+for the definition of the
+.Vt SVCXPRT
+data structure.
+.Bl -tag -width XXXXX
+.It Fn svcerr_auth
+Called by a service dispatch routine that refuses to perform
+a remote procedure call due to an authentication error.
+.It Fn svcerr_decode
+Called by a service dispatch routine that cannot successfully
+decode the remote arguments
+(see
+.Fn svc_getargs
+in
+.Xr rpc_svc_reg 3 ) .
+.It Fn svcerr_noproc
+Called by a service dispatch routine that does not implement
+the procedure number that the caller requests.
+.It Fn svcerr_noprog
+Called when the desired program is not registered with the
+RPC package.
+Service implementors usually do not need this routine.
+.It Fn svcerr_progvers
+Called when the desired version of a program is not registered with the
+RPC package.
+The
+.Fa low_vers
+argument
+is the lowest version number,
+and
+.Fa high_vers
+is the highest version number.
+Service implementors usually do not need this routine.
+.It Fn svcerr_systemerr
+Called by a service dispatch routine when it detects a system
+error not covered by any particular protocol.
+For example, if a service can no longer allocate storage,
+it may call this routine.
+.It Fn svcerr_weakauth
+Called by a service dispatch routine that refuses to perform
+a remote procedure call due to insufficient (but correct)
+authentication arguments.
+The routine calls
+.Fn svcerr_auth "xprt" "AUTH_TOOWEAK" .
+.El
+.Sh SEE ALSO
+.Xr rpc 3 ,
+.Xr rpc_svc_calls 3 ,
+.Xr rpc_svc_create 3 ,
+.Xr rpc_svc_reg 3
diff --git a/lib/libc/rpc/rpc_svc_reg.3 b/lib/libc/rpc/rpc_svc_reg.3
new file mode 100644
index 000000000000..81a749a107e4
--- /dev/null
+++ b/lib/libc/rpc/rpc_svc_reg.3
@@ -0,0 +1,183 @@
+.\" @(#)rpc_svc_reg.3n 1.32 93/08/31 SMI; from SVr4
+.\" Copyright 1989 AT&T
+.\" @(#)rpc_svc_call 1.6 89/07/20 SMI;
+.\" Copyright (c) 1988 Sun Microsystems, Inc. - All Rights Reserved.
+.\" $NetBSD: rpc_svc_reg.3,v 1.1 2000/06/02 23:11:14 fvdl Exp $
+.\" $FreeBSD$
+.Dd May 3, 1993
+.Dt RPC_SVC_REG 3
+.Os
+.Sh NAME
+.Nm rpc_svc_reg ,
+.Nm rpc_reg ,
+.Nm svc_reg ,
+.Nm svc_unreg ,
+.Nm svc_auth_reg ,
+.Nm xprt_register ,
+.Nm xprt_unregister
+.Nd library routines for registering servers
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In rpc/rpc.h
+.Ft int
+.Fn rpc_reg "rpcprog_t prognum" "rpcvers_t versnum" "rpcproc_t procnum" "char *(*procname)()" "xdrproc_t inproc" "xdrproc_t outproc" "char *nettype"
+.Ft bool_t
+.Fn svc_reg "SVCXPRT *xprt" "const rpcprog_t prognum" "const rpcvers_t versnum" "void (*dispatch)(struct svc_req *, SVCXPRT *)" "const struct netconfig *netconf"
+.Ft void
+.Fn svc_unreg "const rpcprog_t prognum" "const rpcvers_t versnum"
+.Ft int
+.Fn svc_auth_reg "int cred_flavor" "enum auth_stat (*handler)(struct svc_req *, struct rpc_msg *)"
+.Ft void
+.Fn xprt_register "SVCXPRT *xprt"
+.Ft void
+.Fn xprt_unregister "SVCXPRT *xprt"
+.Sh DESCRIPTION
+These routines are a part of the RPC
+library which allows the RPC
+servers to register themselves with rpcbind
+(see
+.Xr rpcbind 8 ) ,
+and associate the given program and version
+number with the dispatch function.
+When the RPC server receives a RPC request, the library invokes the
+dispatch routine with the appropriate arguments.
+.Sh Routines
+See
+.Xr rpc 3
+for the definition of the
+.Vt SVCXPRT
+data structure.
+.Bl -tag -width XXXXX
+.It Fn rpc_reg
+Register program
+.Fa prognum ,
+procedure
+.Fa procname ,
+and version
+.Fa versnum
+with the RPC
+service package.
+If a request arrives for program
+.Fa prognum ,
+version
+.Fa versnum ,
+and procedure
+.Fa procnum ,
+.Fa procname
+is called with a pointer to its argument(s);
+.Fa procname
+should return a pointer to its static result(s);
+.Fa inproc
+is the XDR function used to decode the arguments while
+.Fa outproc
+is the XDR function used to encode the results.
+Procedures are registered on all available transports of the class
+.Fa nettype .
+See
+.Xr rpc 3 .
+This routine returns 0 if the registration succeeded,
+\-1 otherwise.
+.It Fn svc_reg
+Associates
+.Fa prognum
+and
+.Fa versnum
+with the service dispatch procedure,
+.Fa dispatch .
+If
+.Fa netconf
+is
+.Dv NULL ,
+the service is not registered with the
+.Xr rpcbind 8
+service.
+If
+.Fa netconf
+is non-zero,
+then a mapping of the triple
+.Bq Fa prognum , versnum , netconf->nc_netid
+to
+.Fa xprt->xp_ltaddr
+is established with the local rpcbind
+service.
+.Pp
+The
+.Fn svc_reg
+routine returns 1 if it succeeds,
+and 0 otherwise.
+.It Fn svc_unreg
+Remove from the rpcbind
+service, all mappings of the triple
+.Bq Fa prognum , versnum , No all-transports
+to network address
+and all mappings within the RPC service package
+of the double
+.Bq Fa prognum , versnum
+to dispatch routines.
+.It Fn svc_auth_reg
+Registers the service authentication routine
+.Fa handler
+with the dispatch mechanism so that it can be
+invoked to authenticate RPC requests received
+with authentication type
+.Fa cred_flavor .
+This interface allows developers to add new authentication
+types to their RPC applications without needing to modify
+the libraries.
+Service implementors usually do not need this routine.
+.Pp
+Typical service application would call
+.Fn svc_auth_reg
+after registering the service and prior to calling
+.Fn svc_run .
+When needed to process an RPC credential of type
+.Fa cred_flavor ,
+the
+.Fa handler
+procedure will be called with two arguments,
+.Fa "struct svc_req *rqst"
+and
+.Fa "struct rpc_msg *msg" ,
+and is expected to return a valid
+.Vt "enum auth_stat"
+value.
+There is no provision to change or delete an authentication handler
+once registered.
+.Pp
+The
+.Fn svc_auth_reg
+routine returns 0 if the registration is successful,
+1 if
+.Fa cred_flavor
+already has an authentication handler registered for it,
+and \-1 otherwise.
+.It Fn xprt_register
+After RPC service transport handle
+.Fa xprt
+is created, it is registered with the RPC
+service package.
+This routine modifies the global variable
+.Va svc_fdset
+(see
+.Xr rpc_svc_calls 3 ) .
+Service implementors usually do not need this routine.
+.It Fn xprt_unregister
+Before an RPC service transport handle
+.Fa xprt
+is destroyed, it unregisters itself with the
+RPC service package.
+This routine modifies the global variable
+.Va svc_fdset
+(see
+.Xr rpc_svc_calls 3 ) .
+Service implementors usually do not need this routine.
+.El
+.Sh SEE ALSO
+.Xr select 2 ,
+.Xr rpc 3 ,
+.Xr rpc_svc_calls 3 ,
+.Xr rpc_svc_create 3 ,
+.Xr rpc_svc_err 3 ,
+.Xr rpcbind 3 ,
+.Xr rpcbind 8
diff --git a/lib/libc/rpc/rpc_xdr.3 b/lib/libc/rpc/rpc_xdr.3
new file mode 100644
index 000000000000..62754fe7e285
--- /dev/null
+++ b/lib/libc/rpc/rpc_xdr.3
@@ -0,0 +1,101 @@
+.\" @(#)rpc_xdr.3n 1.24 93/08/31 SMI; from SVr4
+.\" Copyright 1989 AT&T
+.\" @(#)rpc_xdr.new 1.1 89/04/06 SMI;
+.\" Copyright (c) 1988 Sun Microsystems, Inc. - All Rights Reserved.
+.\" $FreeBSD$
+.Dd May 3, 1993
+.Dt RPC_XDR 3
+.Os
+.Sh NAME
+.Nm xdr_accepted_reply ,
+.Nm xdr_authsys_parms ,
+.Nm xdr_callhdr ,
+.Nm xdr_callmsg ,
+.Nm xdr_opaque_auth ,
+.Nm xdr_rejected_reply ,
+.Nm xdr_replymsg
+.Nd XDR library routines for remote procedure calls
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In rpc/rpc.h
+.Ft bool_t
+.Fn xdr_accepted_reply "XDR *xdrs" "struct accepted_reply *ar"
+.Ft bool_t
+.Fn xdr_authsys_parms "XDR *xdrs" "struct authsys_parms *aupp"
+.Ft bool_t
+.Fn xdr_callhdr "XDR *xdrs" "struct rpc_msg *chdr"
+.Ft bool_t
+.Fn xdr_callmsg "XDR *xdrs" "struct rpc_msg *cmsg"
+.Ft bool_t
+.Fn xdr_opaque_auth "XDR *xdrs" "struct opaque_auth *ap"
+.Ft bool_t
+.Fn xdr_rejected_reply "XDR *xdrs" "struct rejected_reply *rr"
+.Ft bool_t
+.Fn xdr_replymsg "XDR *xdrs" "struct rpc_msg *rmsg"
+.Sh DESCRIPTION
+These routines are used for describing the
+RPC messages in XDR language.
+They should normally be used by those who do not
+want to use the RPC
+package directly.
+These routines return
+.Dv TRUE
+if they succeed,
+.Dv FALSE
+otherwise.
+.Sh Routines
+See
+.Xr rpc 3
+for the definition of the
+.Vt XDR
+data structure.
+.Bl -tag -width XXXXX
+.It Fn xdr_accepted_reply
+Used to translate between RPC
+reply messages and their external representation.
+It includes the status of the RPC
+call in the XDR language format.
+In the case of success, it also includes the call results.
+.It Fn xdr_authsys_parms
+Used for describing
+.Ux
+operating system credentials.
+It includes machine-name, uid, gid list, etc.
+.It Fn xdr_callhdr
+Used for describing
+RPC
+call header messages.
+It encodes the static part of the call message header in the
+XDR language format.
+It includes information such as transaction
+ID, RPC version number, program and version number.
+.It Fn xdr_callmsg
+Used for describing
+RPC call messages.
+This includes all the RPC
+call information such as transaction
+ID, RPC version number, program number, version number,
+authentication information, etc.
+This is normally used by servers to determine information about the client
+RPC call.
+.It Fn xdr_opaque_auth
+Used for describing RPC
+opaque authentication information messages.
+.It Fn xdr_rejected_reply
+Used for describing RPC reply messages.
+It encodes the rejected RPC message in the XDR language format.
+The message could be rejected either because of version
+number mis-match or because of authentication errors.
+.It Fn xdr_replymsg
+Used for describing RPC
+reply messages.
+It translates between the
+RPC reply message and its external representation.
+This reply could be either an acceptance,
+rejection or
+.Dv NULL .
+.El
+.Sh SEE ALSO
+.Xr rpc 3 ,
+.Xr xdr 3
diff --git a/lib/libc/rpc/rpcb_clnt.c b/lib/libc/rpc/rpcb_clnt.c
new file mode 100644
index 000000000000..f9d89c1ae814
--- /dev/null
+++ b/lib/libc/rpc/rpcb_clnt.c
@@ -0,0 +1,1303 @@
+/* $NetBSD: rpcb_clnt.c,v 1.6 2000/07/16 06:41:43 itojun Exp $ */
+
+/*-
+ * Copyright (c) 2010, Oracle America, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of the "Oracle America, Inc." nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* #ident "@(#)rpcb_clnt.c 1.27 94/04/24 SMI" */
+
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)rpcb_clnt.c 1.30 89/06/21 Copyr 1988 Sun Micro";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * rpcb_clnt.c
+ * interface to rpcbind rpc service.
+ */
+
+#include "namespace.h"
+#include "reentrant.h"
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/utsname.h>
+#include <rpc/rpc.h>
+#include <rpc/rpcb_prot.h>
+#include <rpc/nettype.h>
+#include <netconfig.h>
+#ifdef PORTMAP
+#include <netinet/in.h> /* FOR IPPROTO_TCP/UDP definitions */
+#include <rpc/pmap_prot.h>
+#endif /* PORTMAP */
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <syslog.h>
+#include "un-namespace.h"
+
+#include "rpc_com.h"
+#include "mt_misc.h"
+
+static struct timeval tottimeout = { 60, 0 };
+static const struct timeval rmttimeout = { 3, 0 };
+static struct timeval rpcbrmttime = { 15, 0 };
+
+extern bool_t xdr_wrapstring(XDR *, char **);
+
+static const char nullstring[] = "\000";
+
+#define CACHESIZE 6
+
+struct address_cache {
+ char *ac_host;
+ char *ac_netid;
+ char *ac_uaddr;
+ struct netbuf *ac_taddr;
+ struct address_cache *ac_next;
+};
+
+static struct address_cache *front;
+static int cachesize;
+
+#define CLCR_GET_RPCB_TIMEOUT 1
+#define CLCR_SET_RPCB_TIMEOUT 2
+
+
+extern int __rpc_lowvers;
+
+static struct address_cache *check_cache(const char *, const char *);
+static void delete_cache(struct netbuf *);
+static void add_cache(const char *, const char *, struct netbuf *, char *);
+static CLIENT *getclnthandle(const char *, const struct netconfig *, char **);
+static CLIENT *local_rpcb(void);
+static struct netbuf *got_entry(rpcb_entry_list_ptr, const struct netconfig *);
+
+/*
+ * This routine adjusts the timeout used for calls to the remote rpcbind.
+ * Also, this routine can be used to set the use of portmapper version 2
+ * only when doing rpc_broadcasts
+ * These are private routines that may not be provided in future releases.
+ */
+bool_t
+__rpc_control(int request, void *info)
+{
+ switch (request) {
+ case CLCR_GET_RPCB_TIMEOUT:
+ *(struct timeval *)info = tottimeout;
+ break;
+ case CLCR_SET_RPCB_TIMEOUT:
+ tottimeout = *(struct timeval *)info;
+ break;
+ case CLCR_SET_LOWVERS:
+ __rpc_lowvers = *(int *)info;
+ break;
+ case CLCR_GET_LOWVERS:
+ *(int *)info = __rpc_lowvers;
+ break;
+ default:
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+/*
+ * It might seem that a reader/writer lock would be more reasonable here.
+ * However because getclnthandle(), the only user of the cache functions,
+ * may do a delete_cache() operation if a check_cache() fails to return an
+ * address useful to clnt_tli_create(), we may as well use a mutex.
+ */
+/*
+ * As it turns out, if the cache lock is *not* a reader/writer lock, we will
+ * block all clnt_create's if we are trying to connect to a host that's down,
+ * since the lock will be held all during that time.
+ */
+
+/*
+ * The routines check_cache(), add_cache(), delete_cache() manage the
+ * cache of rpcbind addresses for (host, netid).
+ */
+
+static struct address_cache *
+check_cache(const char *host, const char *netid)
+{
+ struct address_cache *cptr;
+
+ /* READ LOCK HELD ON ENTRY: rpcbaddr_cache_lock */
+
+ for (cptr = front; cptr != NULL; cptr = cptr->ac_next) {
+ if (!strcmp(cptr->ac_host, host) &&
+ !strcmp(cptr->ac_netid, netid)) {
+#ifdef ND_DEBUG
+ fprintf(stderr, "Found cache entry for %s: %s\n",
+ host, netid);
+#endif
+ return (cptr);
+ }
+ }
+ return ((struct address_cache *) NULL);
+}
+
+static void
+delete_cache(struct netbuf *addr)
+{
+ struct address_cache *cptr, *prevptr = NULL;
+
+ /* WRITE LOCK HELD ON ENTRY: rpcbaddr_cache_lock */
+ for (cptr = front; cptr != NULL; cptr = cptr->ac_next) {
+ if (!memcmp(cptr->ac_taddr->buf, addr->buf, addr->len)) {
+ free(cptr->ac_host);
+ free(cptr->ac_netid);
+ free(cptr->ac_taddr->buf);
+ free(cptr->ac_taddr);
+ free(cptr->ac_uaddr);
+ if (prevptr)
+ prevptr->ac_next = cptr->ac_next;
+ else
+ front = cptr->ac_next;
+ free(cptr);
+ cachesize--;
+ break;
+ }
+ prevptr = cptr;
+ }
+}
+
+static void
+add_cache(const char *host, const char *netid, struct netbuf *taddr,
+ char *uaddr)
+{
+ struct address_cache *ad_cache, *cptr, *prevptr;
+
+ ad_cache = (struct address_cache *)
+ malloc(sizeof (struct address_cache));
+ if (!ad_cache) {
+ return;
+ }
+ ad_cache->ac_host = strdup(host);
+ ad_cache->ac_netid = strdup(netid);
+ ad_cache->ac_uaddr = uaddr ? strdup(uaddr) : NULL;
+ ad_cache->ac_taddr = (struct netbuf *)malloc(sizeof (struct netbuf));
+ if (!ad_cache->ac_host || !ad_cache->ac_netid || !ad_cache->ac_taddr ||
+ (uaddr && !ad_cache->ac_uaddr)) {
+ goto out;
+ }
+ ad_cache->ac_taddr->len = ad_cache->ac_taddr->maxlen = taddr->len;
+ ad_cache->ac_taddr->buf = (char *) malloc(taddr->len);
+ if (ad_cache->ac_taddr->buf == NULL) {
+out:
+ free(ad_cache->ac_host);
+ free(ad_cache->ac_netid);
+ free(ad_cache->ac_uaddr);
+ free(ad_cache->ac_taddr);
+ free(ad_cache);
+ return;
+ }
+ memcpy(ad_cache->ac_taddr->buf, taddr->buf, taddr->len);
+#ifdef ND_DEBUG
+ fprintf(stderr, "Added to cache: %s : %s\n", host, netid);
+#endif
+
+/* VARIABLES PROTECTED BY rpcbaddr_cache_lock: cptr */
+
+ rwlock_wrlock(&rpcbaddr_cache_lock);
+ if (cachesize < CACHESIZE) {
+ ad_cache->ac_next = front;
+ front = ad_cache;
+ cachesize++;
+ } else {
+ /* Free the last entry */
+ cptr = front;
+ prevptr = NULL;
+ while (cptr->ac_next) {
+ prevptr = cptr;
+ cptr = cptr->ac_next;
+ }
+
+#ifdef ND_DEBUG
+ fprintf(stderr, "Deleted from cache: %s : %s\n",
+ cptr->ac_host, cptr->ac_netid);
+#endif
+ free(cptr->ac_host);
+ free(cptr->ac_netid);
+ free(cptr->ac_taddr->buf);
+ free(cptr->ac_taddr);
+ free(cptr->ac_uaddr);
+
+ if (prevptr) {
+ prevptr->ac_next = NULL;
+ ad_cache->ac_next = front;
+ front = ad_cache;
+ } else {
+ front = ad_cache;
+ ad_cache->ac_next = NULL;
+ }
+ free(cptr);
+ }
+ rwlock_unlock(&rpcbaddr_cache_lock);
+}
+
+/*
+ * This routine will return a client handle that is connected to the
+ * rpcbind. If targaddr is non-NULL, the "universal address" of the
+ * host will be stored in *targaddr; the caller is responsible for
+ * freeing this string.
+ * On error, returns NULL and free's everything.
+ */
+static CLIENT *
+getclnthandle(const char *host, const struct netconfig *nconf, char **targaddr)
+{
+ CLIENT *client;
+ struct netbuf *addr, taddr;
+ struct netbuf addr_to_delete;
+ struct __rpc_sockinfo si;
+ struct addrinfo hints, *res, *tres;
+ struct address_cache *ad_cache;
+ char *tmpaddr;
+
+/* VARIABLES PROTECTED BY rpcbaddr_cache_lock: ad_cache */
+
+ /* Get the address of the rpcbind. Check cache first */
+ client = NULL;
+ addr_to_delete.len = 0;
+ rwlock_rdlock(&rpcbaddr_cache_lock);
+ ad_cache = NULL;
+ if (host != NULL)
+ ad_cache = check_cache(host, nconf->nc_netid);
+ if (ad_cache != NULL) {
+ addr = ad_cache->ac_taddr;
+ client = clnt_tli_create(RPC_ANYFD, nconf, addr,
+ (rpcprog_t)RPCBPROG, (rpcvers_t)RPCBVERS4, 0, 0);
+ if (client != NULL) {
+ if (targaddr)
+ *targaddr = strdup(ad_cache->ac_uaddr);
+ rwlock_unlock(&rpcbaddr_cache_lock);
+ return (client);
+ }
+ addr_to_delete.len = addr->len;
+ addr_to_delete.buf = (char *)malloc(addr->len);
+ if (addr_to_delete.buf == NULL) {
+ addr_to_delete.len = 0;
+ } else {
+ memcpy(addr_to_delete.buf, addr->buf, addr->len);
+ }
+ }
+ rwlock_unlock(&rpcbaddr_cache_lock);
+ if (addr_to_delete.len != 0) {
+ /*
+ * Assume this may be due to cache data being
+ * outdated
+ */
+ rwlock_wrlock(&rpcbaddr_cache_lock);
+ delete_cache(&addr_to_delete);
+ rwlock_unlock(&rpcbaddr_cache_lock);
+ free(addr_to_delete.buf);
+ }
+ if (!__rpc_nconf2sockinfo(nconf, &si)) {
+ rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
+ return NULL;
+ }
+
+ memset(&hints, 0, sizeof hints);
+ hints.ai_family = si.si_af;
+ hints.ai_socktype = si.si_socktype;
+ hints.ai_protocol = si.si_proto;
+
+#ifdef CLNT_DEBUG
+ printf("trying netid %s family %d proto %d socktype %d\n",
+ nconf->nc_netid, si.si_af, si.si_proto, si.si_socktype);
+#endif
+
+ if (nconf->nc_protofmly != NULL && strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) {
+ client = local_rpcb();
+ if (! client) {
+#ifdef ND_DEBUG
+ clnt_pcreateerror("rpcbind clnt interface");
+#endif
+ return (NULL);
+ } else {
+ struct sockaddr_un sun;
+ if (targaddr) {
+ *targaddr = malloc(sizeof(sun.sun_path));
+ if (*targaddr == NULL) {
+ CLNT_DESTROY(client);
+ return (NULL);
+ }
+ strncpy(*targaddr, _PATH_RPCBINDSOCK,
+ sizeof(sun.sun_path));
+ }
+ return (client);
+ }
+ } else {
+ if (getaddrinfo(host, "sunrpc", &hints, &res) != 0) {
+ rpc_createerr.cf_stat = RPC_UNKNOWNHOST;
+ return NULL;
+ }
+ }
+
+ for (tres = res; tres != NULL; tres = tres->ai_next) {
+ taddr.buf = tres->ai_addr;
+ taddr.len = taddr.maxlen = tres->ai_addrlen;
+
+#ifdef ND_DEBUG
+ {
+ char *ua;
+
+ ua = taddr2uaddr(nconf, &taddr);
+ fprintf(stderr, "Got it [%s]\n", ua);
+ free(ua);
+ }
+#endif
+
+#ifdef ND_DEBUG
+ {
+ int i;
+
+ fprintf(stderr, "\tnetbuf len = %d, maxlen = %d\n",
+ taddr.len, taddr.maxlen);
+ fprintf(stderr, "\tAddress is ");
+ for (i = 0; i < taddr.len; i++)
+ fprintf(stderr, "%u.", ((char *)(taddr.buf))[i]);
+ fprintf(stderr, "\n");
+ }
+#endif
+ client = clnt_tli_create(RPC_ANYFD, nconf, &taddr,
+ (rpcprog_t)RPCBPROG, (rpcvers_t)RPCBVERS4, 0, 0);
+#ifdef ND_DEBUG
+ if (! client) {
+ clnt_pcreateerror("rpcbind clnt interface");
+ }
+#endif
+
+ if (client) {
+ tmpaddr = targaddr ? taddr2uaddr(nconf, &taddr) : NULL;
+ add_cache(host, nconf->nc_netid, &taddr, tmpaddr);
+ if (targaddr)
+ *targaddr = tmpaddr;
+ break;
+ }
+ }
+ if (res)
+ freeaddrinfo(res);
+ return (client);
+}
+
+/* XXX */
+#define IN4_LOCALHOST_STRING "127.0.0.1"
+#define IN6_LOCALHOST_STRING "::1"
+
+/*
+ * This routine will return a client handle that is connected to the local
+ * rpcbind. Returns NULL on error and free's everything.
+ */
+static CLIENT *
+local_rpcb(void)
+{
+ CLIENT *client;
+ static struct netconfig *loopnconf;
+ static char *hostname;
+ int sock;
+ size_t tsize;
+ struct netbuf nbuf;
+ struct sockaddr_un sun;
+
+ /*
+ * Try connecting to the local rpcbind through a local socket
+ * first. If this doesn't work, try all transports defined in
+ * the netconfig file.
+ */
+ memset(&sun, 0, sizeof sun);
+ sock = _socket(AF_LOCAL, SOCK_STREAM, 0);
+ if (sock < 0)
+ goto try_nconf;
+ sun.sun_family = AF_LOCAL;
+ strcpy(sun.sun_path, _PATH_RPCBINDSOCK);
+ nbuf.len = sun.sun_len = SUN_LEN(&sun);
+ nbuf.maxlen = sizeof (struct sockaddr_un);
+ nbuf.buf = &sun;
+
+ tsize = __rpc_get_t_size(AF_LOCAL, 0, 0);
+ client = clnt_vc_create(sock, &nbuf, (rpcprog_t)RPCBPROG,
+ (rpcvers_t)RPCBVERS, tsize, tsize);
+
+ if (client != NULL) {
+ /* Mark the socket to be closed in destructor */
+ (void) CLNT_CONTROL(client, CLSET_FD_CLOSE, NULL);
+ return client;
+ }
+
+ /* Nobody needs this socket anymore; free the descriptor. */
+ _close(sock);
+
+try_nconf:
+
+/* VARIABLES PROTECTED BY loopnconf_lock: loopnconf */
+ mutex_lock(&loopnconf_lock);
+ if (loopnconf == NULL) {
+ struct netconfig *nconf, *tmpnconf = NULL;
+ void *nc_handle;
+ int fd;
+
+ nc_handle = setnetconfig();
+ if (nc_handle == NULL) {
+ /* fails to open netconfig file */
+ syslog (LOG_ERR, "rpc: failed to open " NETCONFIG);
+ rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
+ mutex_unlock(&loopnconf_lock);
+ return (NULL);
+ }
+ while ((nconf = getnetconfig(nc_handle)) != NULL) {
+#ifdef INET6
+ if ((strcmp(nconf->nc_protofmly, NC_INET6) == 0 ||
+#else
+ if ((
+#endif
+ strcmp(nconf->nc_protofmly, NC_INET) == 0) &&
+ (nconf->nc_semantics == NC_TPI_COTS ||
+ nconf->nc_semantics == NC_TPI_COTS_ORD)) {
+ fd = __rpc_nconf2fd(nconf);
+ /*
+ * Can't create a socket, assume that
+ * this family isn't configured in the kernel.
+ */
+ if (fd < 0)
+ continue;
+ _close(fd);
+ tmpnconf = nconf;
+ if (!strcmp(nconf->nc_protofmly, NC_INET))
+ hostname = IN4_LOCALHOST_STRING;
+ else
+ hostname = IN6_LOCALHOST_STRING;
+ }
+ }
+ endnetconfig(nc_handle);
+ if (tmpnconf == NULL) {
+ rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
+ mutex_unlock(&loopnconf_lock);
+ return (NULL);
+ }
+ loopnconf = getnetconfigent(tmpnconf->nc_netid);
+ /* loopnconf is never freed */
+ }
+ mutex_unlock(&loopnconf_lock);
+ client = getclnthandle(hostname, loopnconf, NULL);
+ return (client);
+}
+
+/*
+ * Set a mapping between program, version and address.
+ * Calls the rpcbind service to do the mapping.
+ *
+ * nconf - Network structure of transport
+ * address - Services netconfig address
+ */
+bool_t
+rpcb_set(rpcprog_t program, rpcvers_t version, const struct netconfig *nconf,
+ const struct netbuf *address)
+{
+ CLIENT *client;
+ bool_t rslt = FALSE;
+ RPCB parms;
+ char uidbuf[32];
+
+ /* parameter checking */
+ if (nconf == NULL) {
+ rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
+ return (FALSE);
+ }
+ if (address == NULL) {
+ rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
+ return (FALSE);
+ }
+ client = local_rpcb();
+ if (! client) {
+ return (FALSE);
+ }
+
+ /* convert to universal */
+ /*LINTED const castaway*/
+ parms.r_addr = taddr2uaddr((struct netconfig *) nconf,
+ (struct netbuf *)address);
+ if (!parms.r_addr) {
+ CLNT_DESTROY(client);
+ rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
+ return (FALSE); /* no universal address */
+ }
+ parms.r_prog = program;
+ parms.r_vers = version;
+ parms.r_netid = nconf->nc_netid;
+ /*
+ * Though uid is not being used directly, we still send it for
+ * completeness. For non-unix platforms, perhaps some other
+ * string or an empty string can be sent.
+ */
+ (void) snprintf(uidbuf, sizeof uidbuf, "%d", geteuid());
+ parms.r_owner = uidbuf;
+
+ CLNT_CALL(client, (rpcproc_t)RPCBPROC_SET, (xdrproc_t) xdr_rpcb,
+ (char *)(void *)&parms, (xdrproc_t) xdr_bool,
+ (char *)(void *)&rslt, tottimeout);
+
+ CLNT_DESTROY(client);
+ free(parms.r_addr);
+ return (rslt);
+}
+
+/*
+ * Remove the mapping between program, version and netbuf address.
+ * Calls the rpcbind service to do the un-mapping.
+ * If netbuf is NULL, unset for all the transports, otherwise unset
+ * only for the given transport.
+ */
+bool_t
+rpcb_unset(rpcprog_t program, rpcvers_t version, const struct netconfig *nconf)
+{
+ CLIENT *client;
+ bool_t rslt = FALSE;
+ RPCB parms;
+ char uidbuf[32];
+
+ client = local_rpcb();
+ if (! client) {
+ return (FALSE);
+ }
+
+ parms.r_prog = program;
+ parms.r_vers = version;
+ if (nconf)
+ parms.r_netid = nconf->nc_netid;
+ else {
+ /*LINTED const castaway*/
+ parms.r_netid = (char *) &nullstring[0]; /* unsets all */
+ }
+ /*LINTED const castaway*/
+ parms.r_addr = (char *) &nullstring[0];
+ (void) snprintf(uidbuf, sizeof uidbuf, "%d", geteuid());
+ parms.r_owner = uidbuf;
+
+ CLNT_CALL(client, (rpcproc_t)RPCBPROC_UNSET, (xdrproc_t) xdr_rpcb,
+ (char *)(void *)&parms, (xdrproc_t) xdr_bool,
+ (char *)(void *)&rslt, tottimeout);
+
+ CLNT_DESTROY(client);
+ return (rslt);
+}
+
+/*
+ * From the merged list, find the appropriate entry
+ */
+static struct netbuf *
+got_entry(rpcb_entry_list_ptr relp, const struct netconfig *nconf)
+{
+ struct netbuf *na = NULL;
+ rpcb_entry_list_ptr sp;
+ rpcb_entry *rmap;
+
+ for (sp = relp; sp != NULL; sp = sp->rpcb_entry_next) {
+ rmap = &sp->rpcb_entry_map;
+ if ((strcmp(nconf->nc_proto, rmap->r_nc_proto) == 0) &&
+ (strcmp(nconf->nc_protofmly, rmap->r_nc_protofmly) == 0) &&
+ (nconf->nc_semantics == rmap->r_nc_semantics) &&
+ (rmap->r_maddr != NULL) && (rmap->r_maddr[0] != 0)) {
+ na = uaddr2taddr(nconf, rmap->r_maddr);
+#ifdef ND_DEBUG
+ fprintf(stderr, "\tRemote address is [%s].\n",
+ rmap->r_maddr);
+ if (!na)
+ fprintf(stderr,
+ "\tCouldn't resolve remote address!\n");
+#endif
+ break;
+ }
+ }
+ return (na);
+}
+
+/*
+ * Quick check to see if rpcbind is up. Tries to connect over
+ * local transport.
+ */
+static bool_t
+__rpcbind_is_up(void)
+{
+ struct netconfig *nconf;
+ struct sockaddr_un sun;
+ void *localhandle;
+ int sock;
+
+ nconf = NULL;
+ localhandle = setnetconfig();
+ while ((nconf = getnetconfig(localhandle)) != NULL) {
+ if (nconf->nc_protofmly != NULL &&
+ strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0)
+ break;
+ }
+ endnetconfig(localhandle);
+
+ if (nconf == NULL)
+ return (FALSE);
+
+ memset(&sun, 0, sizeof sun);
+ sock = _socket(AF_LOCAL, SOCK_STREAM, 0);
+ if (sock < 0)
+ return (FALSE);
+ sun.sun_family = AF_LOCAL;
+ strncpy(sun.sun_path, _PATH_RPCBINDSOCK, sizeof(sun.sun_path));
+ sun.sun_len = SUN_LEN(&sun);
+
+ if (_connect(sock, (struct sockaddr *)&sun, sun.sun_len) < 0) {
+ _close(sock);
+ return (FALSE);
+ }
+
+ _close(sock);
+ return (TRUE);
+}
+
+/*
+ * An internal function which optimizes rpcb_getaddr function. It also
+ * returns the client handle that it uses to contact the remote rpcbind.
+ *
+ * The algorithm used: If the transports is TCP or UDP, it first tries
+ * version 2 (portmap), 4 and then 3 (svr4). This order should be
+ * changed in the next OS release to 4, 2 and 3. We are assuming that by
+ * that time, version 4 would be available on many machines on the network.
+ * With this algorithm, we get performance as well as a plan for
+ * obsoleting version 2.
+ *
+ * For all other transports, the algorithm remains as 4 and then 3.
+ *
+ * XXX: Due to some problems with t_connect(), we do not reuse the same client
+ * handle for COTS cases and hence in these cases we do not return the
+ * client handle. This code will change if t_connect() ever
+ * starts working properly. Also look under clnt_vc.c.
+ */
+struct netbuf *
+__rpcb_findaddr_timed(rpcprog_t program, rpcvers_t version,
+ const struct netconfig *nconf, const char *host,
+ CLIENT **clpp, struct timeval *tp)
+{
+ static bool_t check_rpcbind = TRUE;
+ CLIENT *client = NULL;
+ RPCB parms;
+ enum clnt_stat clnt_st;
+ char *ua = NULL;
+ rpcvers_t vers;
+ struct netbuf *address = NULL;
+ rpcvers_t start_vers = RPCBVERS4;
+ struct netbuf servaddr;
+
+ /* parameter checking */
+ if (nconf == NULL) {
+ rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
+ return (NULL);
+ }
+
+ parms.r_addr = NULL;
+
+ /*
+ * Use default total timeout if no timeout is specified.
+ */
+ if (tp == NULL)
+ tp = &tottimeout;
+
+#ifdef PORTMAP
+ /* Try version 2 for TCP or UDP */
+ if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
+ u_short port = 0;
+ struct netbuf remote;
+ rpcvers_t pmapvers = 2;
+ struct pmap pmapparms;
+
+ /*
+ * Try UDP only - there are some portmappers out
+ * there that use UDP only.
+ */
+ if (strcmp(nconf->nc_proto, NC_TCP) == 0) {
+ struct netconfig *newnconf;
+
+ if ((newnconf = getnetconfigent("udp")) == NULL) {
+ rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
+ return (NULL);
+ }
+ client = getclnthandle(host, newnconf, &parms.r_addr);
+ freenetconfigent(newnconf);
+ } else {
+ client = getclnthandle(host, nconf, &parms.r_addr);
+ }
+ if (client == NULL)
+ return (NULL);
+
+ /*
+ * Set version and retry timeout.
+ */
+ CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)&rpcbrmttime);
+ CLNT_CONTROL(client, CLSET_VERS, (char *)&pmapvers);
+
+ pmapparms.pm_prog = program;
+ pmapparms.pm_vers = version;
+ pmapparms.pm_prot = strcmp(nconf->nc_proto, NC_TCP) ?
+ IPPROTO_UDP : IPPROTO_TCP;
+ pmapparms.pm_port = 0; /* not needed */
+ clnt_st = CLNT_CALL(client, (rpcproc_t)PMAPPROC_GETPORT,
+ (xdrproc_t) xdr_pmap, (caddr_t)(void *)&pmapparms,
+ (xdrproc_t) xdr_u_short, (caddr_t)(void *)&port,
+ *tp);
+ if (clnt_st != RPC_SUCCESS) {
+ if ((clnt_st == RPC_PROGVERSMISMATCH) ||
+ (clnt_st == RPC_PROGUNAVAIL))
+ goto try_rpcbind; /* Try different versions */
+ rpc_createerr.cf_stat = RPC_PMAPFAILURE;
+ clnt_geterr(client, &rpc_createerr.cf_error);
+ goto error;
+ } else if (port == 0) {
+ address = NULL;
+ rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
+ goto error;
+ }
+ port = htons(port);
+ CLNT_CONTROL(client, CLGET_SVC_ADDR, (char *)&remote);
+ if (((address = (struct netbuf *)
+ malloc(sizeof (struct netbuf))) == NULL) ||
+ ((address->buf = (char *)
+ malloc(remote.len)) == NULL)) {
+ rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+ clnt_geterr(client, &rpc_createerr.cf_error);
+ free(address);
+ address = NULL;
+ goto error;
+ }
+ memcpy(address->buf, remote.buf, remote.len);
+ memcpy(&((char *)address->buf)[sizeof (short)],
+ (char *)(void *)&port, sizeof (short));
+ address->len = address->maxlen = remote.len;
+ goto done;
+ }
+#endif /* PORTMAP */
+
+try_rpcbind:
+ /*
+ * Check if rpcbind is up. This prevents needless delays when
+ * accessing applications such as the keyserver while booting
+ * disklessly.
+ */
+ if (check_rpcbind && strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) {
+ if (!__rpcbind_is_up()) {
+ rpc_createerr.cf_stat = RPC_PMAPFAILURE;
+ rpc_createerr.cf_error.re_errno = 0;
+ goto error;
+ }
+ check_rpcbind = FALSE;
+ }
+
+ /*
+ * Now we try version 4 and then 3.
+ * We also send the remote system the address we used to
+ * contact it in case it can help to connect back with us
+ */
+ parms.r_prog = program;
+ parms.r_vers = version;
+ /*LINTED const castaway*/
+ parms.r_owner = (char *) &nullstring[0]; /* not needed; */
+ /* just for xdring */
+ parms.r_netid = nconf->nc_netid; /* not really needed */
+
+ /*
+ * If a COTS transport is being used, try getting address via CLTS
+ * transport. This works only with version 4.
+ */
+ if (nconf->nc_semantics == NC_TPI_COTS_ORD ||
+ nconf->nc_semantics == NC_TPI_COTS) {
+
+ void *handle;
+ struct netconfig *nconf_clts;
+ rpcb_entry_list_ptr relp = NULL;
+
+ if (client == NULL) {
+ /* This did not go through the above PORTMAP/TCP code */
+ if ((handle = __rpc_setconf("datagram_v")) != NULL) {
+ while ((nconf_clts = __rpc_getconf(handle))
+ != NULL) {
+ if (strcmp(nconf_clts->nc_protofmly,
+ nconf->nc_protofmly) != 0) {
+ continue;
+ }
+ client = getclnthandle(host, nconf_clts,
+ &parms.r_addr);
+ break;
+ }
+ __rpc_endconf(handle);
+ }
+ if (client == NULL)
+ goto regular_rpcbind; /* Go the regular way */
+ } else {
+ /* This is a UDP PORTMAP handle. Change to version 4 */
+ vers = RPCBVERS4;
+ CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers);
+ }
+ /*
+ * We also send the remote system the address we used to
+ * contact it in case it can help it connect back with us
+ */
+ if (parms.r_addr == NULL) {
+ /*LINTED const castaway*/
+ parms.r_addr = (char *) &nullstring[0]; /* for XDRing */
+ }
+
+ CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)&rpcbrmttime);
+
+ clnt_st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETADDRLIST,
+ (xdrproc_t) xdr_rpcb, (char *)(void *)&parms,
+ (xdrproc_t) xdr_rpcb_entry_list_ptr,
+ (char *)(void *)&relp, *tp);
+ if (clnt_st == RPC_SUCCESS) {
+ if ((address = got_entry(relp, nconf)) != NULL) {
+ xdr_free((xdrproc_t) xdr_rpcb_entry_list_ptr,
+ (char *)(void *)&relp);
+ CLNT_CONTROL(client, CLGET_SVC_ADDR,
+ (char *)(void *)&servaddr);
+ __rpc_fixup_addr(address, &servaddr);
+ goto done;
+ }
+ /* Entry not found for this transport */
+ xdr_free((xdrproc_t) xdr_rpcb_entry_list_ptr,
+ (char *)(void *)&relp);
+ /*
+ * XXX: should have perhaps returned with error but
+ * since the remote machine might not always be able
+ * to send the address on all transports, we try the
+ * regular way with regular_rpcbind
+ */
+ goto regular_rpcbind;
+ } else if ((clnt_st == RPC_PROGVERSMISMATCH) ||
+ (clnt_st == RPC_PROGUNAVAIL)) {
+ start_vers = RPCBVERS; /* Try version 3 now */
+ goto regular_rpcbind; /* Try different versions */
+ } else {
+ rpc_createerr.cf_stat = RPC_PMAPFAILURE;
+ clnt_geterr(client, &rpc_createerr.cf_error);
+ goto error;
+ }
+ }
+
+regular_rpcbind:
+
+ /* Now the same transport is to be used to get the address */
+ if (client && ((nconf->nc_semantics == NC_TPI_COTS_ORD) ||
+ (nconf->nc_semantics == NC_TPI_COTS))) {
+ /* A CLTS type of client - destroy it */
+ CLNT_DESTROY(client);
+ client = NULL;
+ }
+
+ if (client == NULL) {
+ client = getclnthandle(host, nconf, &parms.r_addr);
+ if (client == NULL) {
+ goto error;
+ }
+ }
+ if (parms.r_addr == NULL) {
+ /*LINTED const castaway*/
+ parms.r_addr = (char *) &nullstring[0];
+ }
+
+ /* First try from start_vers and then version 3 (RPCBVERS) */
+
+ CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *) &rpcbrmttime);
+ for (vers = start_vers; vers >= RPCBVERS; vers--) {
+ /* Set the version */
+ CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers);
+ clnt_st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETADDR,
+ (xdrproc_t) xdr_rpcb, (char *)(void *)&parms,
+ (xdrproc_t) xdr_wrapstring, (char *)(void *) &ua, *tp);
+ if (clnt_st == RPC_SUCCESS) {
+ if ((ua == NULL) || (ua[0] == 0)) {
+ /* address unknown */
+ rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
+ goto error;
+ }
+ address = uaddr2taddr(nconf, ua);
+#ifdef ND_DEBUG
+ fprintf(stderr, "\tRemote address is [%s]\n", ua);
+ if (!address)
+ fprintf(stderr,
+ "\tCouldn't resolve remote address!\n");
+#endif
+ xdr_free((xdrproc_t)xdr_wrapstring,
+ (char *)(void *)&ua);
+
+ if (! address) {
+ /* We don't know about your universal address */
+ rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
+ goto error;
+ }
+ CLNT_CONTROL(client, CLGET_SVC_ADDR,
+ (char *)(void *)&servaddr);
+ __rpc_fixup_addr(address, &servaddr);
+ goto done;
+ } else if (clnt_st == RPC_PROGVERSMISMATCH) {
+ struct rpc_err rpcerr;
+
+ clnt_geterr(client, &rpcerr);
+ if (rpcerr.re_vers.low > RPCBVERS4)
+ goto error; /* a new version, can't handle */
+ } else if (clnt_st != RPC_PROGUNAVAIL) {
+ /* Cant handle this error */
+ rpc_createerr.cf_stat = clnt_st;
+ clnt_geterr(client, &rpc_createerr.cf_error);
+ goto error;
+ }
+ }
+
+error:
+ if (client) {
+ CLNT_DESTROY(client);
+ client = NULL;
+ }
+done:
+ if (nconf->nc_semantics != NC_TPI_CLTS) {
+ /* This client is the connectionless one */
+ if (client) {
+ CLNT_DESTROY(client);
+ client = NULL;
+ }
+ }
+ if (clpp) {
+ *clpp = client;
+ } else if (client) {
+ CLNT_DESTROY(client);
+ }
+ if (parms.r_addr != NULL && parms.r_addr != nullstring)
+ free(parms.r_addr);
+ return (address);
+}
+
+
+/*
+ * Find the mapped address for program, version.
+ * Calls the rpcbind service remotely to do the lookup.
+ * Uses the transport specified in nconf.
+ * Returns FALSE (0) if no map exists, else returns 1.
+ *
+ * Assuming that the address is all properly allocated
+ */
+bool_t
+rpcb_getaddr(rpcprog_t program, rpcvers_t version, const struct netconfig *nconf,
+ struct netbuf *address, const char *host)
+{
+ struct netbuf *na;
+
+ if ((na = __rpcb_findaddr_timed(program, version,
+ (struct netconfig *) nconf, (char *) host,
+ (CLIENT **) NULL, (struct timeval *) NULL)) == NULL)
+ return (FALSE);
+
+ if (na->len > address->maxlen) {
+ /* Too long address */
+ free(na->buf);
+ free(na);
+ rpc_createerr.cf_stat = RPC_FAILED;
+ return (FALSE);
+ }
+ memcpy(address->buf, na->buf, (size_t)na->len);
+ address->len = na->len;
+ free(na->buf);
+ free(na);
+ return (TRUE);
+}
+
+/*
+ * Get a copy of the current maps.
+ * Calls the rpcbind service remotely to get the maps.
+ *
+ * It returns only a list of the services
+ * It returns NULL on failure.
+ */
+rpcblist *
+rpcb_getmaps(const struct netconfig *nconf, const char *host)
+{
+ rpcblist_ptr head = NULL;
+ CLIENT *client;
+ enum clnt_stat clnt_st;
+ rpcvers_t vers = 0;
+
+ client = getclnthandle(host, nconf, NULL);
+ if (client == NULL) {
+ return (head);
+ }
+ clnt_st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_DUMP,
+ (xdrproc_t) xdr_void, NULL, (xdrproc_t) xdr_rpcblist_ptr,
+ (char *)(void *)&head, tottimeout);
+ if (clnt_st == RPC_SUCCESS)
+ goto done;
+
+ if ((clnt_st != RPC_PROGVERSMISMATCH) &&
+ (clnt_st != RPC_PROGUNAVAIL)) {
+ rpc_createerr.cf_stat = RPC_RPCBFAILURE;
+ clnt_geterr(client, &rpc_createerr.cf_error);
+ goto done;
+ }
+
+ /* fall back to earlier version */
+ CLNT_CONTROL(client, CLGET_VERS, (char *)(void *)&vers);
+ if (vers == RPCBVERS4) {
+ vers = RPCBVERS;
+ CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers);
+ if (CLNT_CALL(client, (rpcproc_t)RPCBPROC_DUMP,
+ (xdrproc_t) xdr_void, NULL, (xdrproc_t) xdr_rpcblist_ptr,
+ (char *)(void *)&head, tottimeout) == RPC_SUCCESS)
+ goto done;
+ }
+ rpc_createerr.cf_stat = RPC_RPCBFAILURE;
+ clnt_geterr(client, &rpc_createerr.cf_error);
+
+done:
+ CLNT_DESTROY(client);
+ return (head);
+}
+
+/*
+ * rpcbinder remote-call-service interface.
+ * This routine is used to call the rpcbind remote call service
+ * which will look up a service program in the address maps, and then
+ * remotely call that routine with the given parameters. This allows
+ * programs to do a lookup and call in one step.
+ *
+ * nconf -Netconfig structure
+ * host - Remote host name
+ * proc - Remote proc identifiers
+ * xdrargs, xdrres; XDR routines
+ * argsp, resp - Argument and Result
+ * tout - Timeout value for this call
+ * addr_ptr - Preallocated netbuf address
+ */
+enum clnt_stat
+rpcb_rmtcall(const struct netconfig *nconf, const char *host, rpcprog_t prog,
+ rpcvers_t vers, rpcproc_t proc, xdrproc_t xdrargs, caddr_t argsp,
+ xdrproc_t xdrres, caddr_t resp, struct timeval tout,
+ const struct netbuf *addr_ptr)
+{
+ CLIENT *client;
+ enum clnt_stat stat;
+ struct r_rpcb_rmtcallargs a;
+ struct r_rpcb_rmtcallres r;
+ rpcvers_t rpcb_vers;
+
+ stat = 0;
+ client = getclnthandle(host, nconf, NULL);
+ if (client == NULL) {
+ return (RPC_FAILED);
+ }
+ /*LINTED const castaway*/
+ CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)(void *)&rmttimeout);
+ a.prog = prog;
+ a.vers = vers;
+ a.proc = proc;
+ a.args.args_val = argsp;
+ a.xdr_args = xdrargs;
+ r.addr = NULL;
+ r.results.results_val = resp;
+ r.xdr_res = xdrres;
+
+ for (rpcb_vers = RPCBVERS4; rpcb_vers >= RPCBVERS; rpcb_vers--) {
+ CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&rpcb_vers);
+ stat = CLNT_CALL(client, (rpcproc_t)RPCBPROC_CALLIT,
+ (xdrproc_t) xdr_rpcb_rmtcallargs, (char *)(void *)&a,
+ (xdrproc_t) xdr_rpcb_rmtcallres, (char *)(void *)&r, tout);
+ if ((stat == RPC_SUCCESS) && (addr_ptr != NULL)) {
+ struct netbuf *na;
+ /*LINTED const castaway*/
+ na = uaddr2taddr((struct netconfig *) nconf, r.addr);
+ if (!na) {
+ stat = RPC_N2AXLATEFAILURE;
+ /*LINTED const castaway*/
+ ((struct netbuf *) addr_ptr)->len = 0;
+ goto error;
+ }
+ if (na->len > addr_ptr->maxlen) {
+ /* Too long address */
+ stat = RPC_FAILED; /* XXX A better error no */
+ free(na->buf);
+ free(na);
+ /*LINTED const castaway*/
+ ((struct netbuf *) addr_ptr)->len = 0;
+ goto error;
+ }
+ memcpy(addr_ptr->buf, na->buf, (size_t)na->len);
+ /*LINTED const castaway*/
+ ((struct netbuf *)addr_ptr)->len = na->len;
+ free(na->buf);
+ free(na);
+ break;
+ } else if ((stat != RPC_PROGVERSMISMATCH) &&
+ (stat != RPC_PROGUNAVAIL)) {
+ goto error;
+ }
+ }
+error:
+ CLNT_DESTROY(client);
+ if (r.addr)
+ xdr_free((xdrproc_t) xdr_wrapstring, (char *)(void *)&r.addr);
+ return (stat);
+}
+
+/*
+ * Gets the time on the remote host.
+ * Returns 1 if succeeds else 0.
+ */
+bool_t
+rpcb_gettime(const char *host, time_t *timep)
+{
+ CLIENT *client = NULL;
+ void *handle;
+ struct netconfig *nconf;
+ rpcvers_t vers;
+ enum clnt_stat st;
+
+
+ if ((host == NULL) || (host[0] == 0)) {
+ time(timep);
+ return (TRUE);
+ }
+
+ if ((handle = __rpc_setconf("netpath")) == NULL) {
+ rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
+ return (FALSE);
+ }
+ rpc_createerr.cf_stat = RPC_SUCCESS;
+ while (client == NULL) {
+ if ((nconf = __rpc_getconf(handle)) == NULL) {
+ if (rpc_createerr.cf_stat == RPC_SUCCESS)
+ rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
+ break;
+ }
+ client = getclnthandle(host, nconf, NULL);
+ if (client)
+ break;
+ }
+ __rpc_endconf(handle);
+ if (client == (CLIENT *) NULL) {
+ return (FALSE);
+ }
+
+ st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETTIME,
+ (xdrproc_t) xdr_void, NULL,
+ (xdrproc_t) xdr_int, (char *)(void *)timep, tottimeout);
+
+ if ((st == RPC_PROGVERSMISMATCH) || (st == RPC_PROGUNAVAIL)) {
+ CLNT_CONTROL(client, CLGET_VERS, (char *)(void *)&vers);
+ if (vers == RPCBVERS4) {
+ /* fall back to earlier version */
+ vers = RPCBVERS;
+ CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers);
+ st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETTIME,
+ (xdrproc_t) xdr_void, NULL,
+ (xdrproc_t) xdr_int, (char *)(void *)timep,
+ tottimeout);
+ }
+ }
+ CLNT_DESTROY(client);
+ return (st == RPC_SUCCESS? TRUE: FALSE);
+}
+
+/*
+ * Converts taddr to universal address. This routine should never
+ * really be called because local n2a libraries are always provided.
+ */
+char *
+rpcb_taddr2uaddr(struct netconfig *nconf, struct netbuf *taddr)
+{
+ CLIENT *client;
+ char *uaddr = NULL;
+
+
+ /* parameter checking */
+ if (nconf == NULL) {
+ rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
+ return (NULL);
+ }
+ if (taddr == NULL) {
+ rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
+ return (NULL);
+ }
+ client = local_rpcb();
+ if (! client) {
+ return (NULL);
+ }
+
+ CLNT_CALL(client, (rpcproc_t)RPCBPROC_TADDR2UADDR,
+ (xdrproc_t) xdr_netbuf, (char *)(void *)taddr,
+ (xdrproc_t) xdr_wrapstring, (char *)(void *)&uaddr, tottimeout);
+ CLNT_DESTROY(client);
+ return (uaddr);
+}
+
+/*
+ * Converts universal address to netbuf. This routine should never
+ * really be called because local n2a libraries are always provided.
+ */
+struct netbuf *
+rpcb_uaddr2taddr(struct netconfig *nconf, char *uaddr)
+{
+ CLIENT *client;
+ struct netbuf *taddr;
+
+
+ /* parameter checking */
+ if (nconf == NULL) {
+ rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
+ return (NULL);
+ }
+ if (uaddr == NULL) {
+ rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
+ return (NULL);
+ }
+ client = local_rpcb();
+ if (! client) {
+ return (NULL);
+ }
+
+ taddr = (struct netbuf *)calloc(1, sizeof (struct netbuf));
+ if (taddr == NULL) {
+ CLNT_DESTROY(client);
+ return (NULL);
+ }
+ if (CLNT_CALL(client, (rpcproc_t)RPCBPROC_UADDR2TADDR,
+ (xdrproc_t) xdr_wrapstring, (char *)(void *)&uaddr,
+ (xdrproc_t) xdr_netbuf, (char *)(void *)taddr,
+ tottimeout) != RPC_SUCCESS) {
+ free(taddr);
+ taddr = NULL;
+ }
+ CLNT_DESTROY(client);
+ return (taddr);
+}
diff --git a/lib/libc/rpc/rpcb_prot.c b/lib/libc/rpc/rpcb_prot.c
new file mode 100644
index 000000000000..c462e192cf03
--- /dev/null
+++ b/lib/libc/rpc/rpcb_prot.c
@@ -0,0 +1,315 @@
+/* $NetBSD: rpcb_prot.c,v 1.3 2000/07/14 08:40:42 fvdl Exp $ */
+
+/*-
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 1986-1991 by Sun Microsystems Inc.
+ */
+
+/* #ident "@(#)rpcb_prot.c 1.13 94/04/24 SMI" */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)rpcb_prot.c 1.9 89/04/21 Copyr 1984 Sun Micro";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * rpcb_prot.c
+ * XDR routines for the rpcbinder version 3.
+ *
+ * Copyright (C) 1984, 1988, Sun Microsystems, Inc.
+ */
+
+#include "namespace.h"
+#include <rpc/rpc.h>
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#include <rpc/rpcb_prot.h>
+#include "un-namespace.h"
+
+bool_t
+xdr_rpcb(XDR *xdrs, RPCB *objp)
+{
+ if (!xdr_rpcprog(xdrs, &objp->r_prog)) {
+ return (FALSE);
+ }
+ if (!xdr_rpcvers(xdrs, &objp->r_vers)) {
+ return (FALSE);
+ }
+ if (!xdr_string(xdrs, &objp->r_netid, (u_int)~0)) {
+ return (FALSE);
+ }
+ if (!xdr_string(xdrs, &objp->r_addr, (u_int)~0)) {
+ return (FALSE);
+ }
+ if (!xdr_string(xdrs, &objp->r_owner, (u_int)~0)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+/*
+ * rpcblist_ptr implements a linked list. The RPCL definition from
+ * rpcb_prot.x is:
+ *
+ * struct rpcblist {
+ * rpcb rpcb_map;
+ * struct rpcblist *rpcb_next;
+ * };
+ * typedef rpcblist *rpcblist_ptr;
+ *
+ * Recall that "pointers" in XDR are encoded as a boolean, indicating whether
+ * there's any data behind the pointer, followed by the data (if any exists).
+ * The boolean can be interpreted as ``more data follows me''; if FALSE then
+ * nothing follows the boolean; if TRUE then the boolean is followed by an
+ * actual struct rpcb, and another rpcblist_ptr (declared in RPCL as "struct
+ * rpcblist *").
+ *
+ * This could be implemented via the xdr_pointer type, though this would
+ * result in one recursive call per element in the list. Rather than do that
+ * we can ``unwind'' the recursion into a while loop and use xdr_reference to
+ * serialize the rpcb elements.
+ */
+
+bool_t
+xdr_rpcblist_ptr(XDR *xdrs, rpcblist_ptr *rp)
+{
+ /*
+ * more_elements is pre-computed in case the direction is
+ * XDR_ENCODE or XDR_FREE. more_elements is overwritten by
+ * xdr_bool when the direction is XDR_DECODE.
+ */
+ bool_t more_elements;
+ int freeing = (xdrs->x_op == XDR_FREE);
+ rpcblist_ptr next;
+ rpcblist_ptr next_copy;
+
+ next = NULL;
+ for (;;) {
+ more_elements = (bool_t)(*rp != NULL);
+ if (! xdr_bool(xdrs, &more_elements)) {
+ return (FALSE);
+ }
+ if (! more_elements) {
+ return (TRUE); /* we are done */
+ }
+ /*
+ * the unfortunate side effect of non-recursion is that in
+ * the case of freeing we must remember the next object
+ * before we free the current object ...
+ */
+ if (freeing && *rp)
+ next = (*rp)->rpcb_next;
+ if (! xdr_reference(xdrs, (caddr_t *)rp,
+ (u_int)sizeof (rpcblist), (xdrproc_t)xdr_rpcb)) {
+ return (FALSE);
+ }
+ if (freeing) {
+ next_copy = next;
+ rp = &next_copy;
+ /*
+ * Note that in the subsequent iteration, next_copy
+ * gets nulled out by the xdr_reference
+ * but next itself survives.
+ */
+ } else if (*rp) {
+ rp = &((*rp)->rpcb_next);
+ }
+ }
+ /*NOTREACHED*/
+}
+
+/*
+ * xdr_rpcblist() is specified to take a RPCBLIST **, but is identical in
+ * functionality to xdr_rpcblist_ptr().
+ */
+bool_t
+xdr_rpcblist(XDR *xdrs, RPCBLIST **rp)
+{
+ bool_t dummy;
+
+ dummy = xdr_rpcblist_ptr(xdrs, (rpcblist_ptr *)rp);
+ return (dummy);
+}
+
+
+bool_t
+xdr_rpcb_entry(XDR *xdrs, rpcb_entry *objp)
+{
+ if (!xdr_string(xdrs, &objp->r_maddr, (u_int)~0)) {
+ return (FALSE);
+ }
+ if (!xdr_string(xdrs, &objp->r_nc_netid, (u_int)~0)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int32_t(xdrs, &objp->r_nc_semantics)) {
+ return (FALSE);
+ }
+ if (!xdr_string(xdrs, &objp->r_nc_protofmly, (u_int)~0)) {
+ return (FALSE);
+ }
+ if (!xdr_string(xdrs, &objp->r_nc_proto, (u_int)~0)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_rpcb_entry_list_ptr(XDR *xdrs, rpcb_entry_list_ptr *rp)
+{
+ /*
+ * more_elements is pre-computed in case the direction is
+ * XDR_ENCODE or XDR_FREE. more_elements is overwritten by
+ * xdr_bool when the direction is XDR_DECODE.
+ */
+ bool_t more_elements;
+ int freeing = (xdrs->x_op == XDR_FREE);
+ rpcb_entry_list_ptr next;
+ rpcb_entry_list_ptr next_copy;
+
+ next = NULL;
+ for (;;) {
+ more_elements = (bool_t)(*rp != NULL);
+ if (! xdr_bool(xdrs, &more_elements)) {
+ return (FALSE);
+ }
+ if (! more_elements) {
+ return (TRUE); /* we are done */
+ }
+ /*
+ * the unfortunate side effect of non-recursion is that in
+ * the case of freeing we must remember the next object
+ * before we free the current object ...
+ */
+ if (freeing && *rp)
+ next = (*rp)->rpcb_entry_next;
+ if (! xdr_reference(xdrs, (caddr_t *)rp,
+ (u_int)sizeof (rpcb_entry_list),
+ (xdrproc_t)xdr_rpcb_entry)) {
+ return (FALSE);
+ }
+ if (freeing) {
+ next_copy = next;
+ rp = &next_copy;
+ /*
+ * Note that in the subsequent iteration, next_copy
+ * gets nulled out by the xdr_reference
+ * but next itself survives.
+ */
+ } else if (*rp) {
+ rp = &((*rp)->rpcb_entry_next);
+ }
+ }
+ /*NOTREACHED*/
+}
+
+/*
+ * XDR remote call arguments
+ * written for XDR_ENCODE direction only
+ */
+bool_t
+xdr_rpcb_rmtcallargs(XDR *xdrs, struct rpcb_rmtcallargs *p)
+{
+ struct r_rpcb_rmtcallargs *objp =
+ (struct r_rpcb_rmtcallargs *)(void *)p;
+ u_int lenposition, argposition, position;
+ int32_t *buf;
+
+ buf = XDR_INLINE(xdrs, 3 * BYTES_PER_XDR_UNIT);
+ if (buf == NULL) {
+ if (!xdr_rpcprog(xdrs, &objp->prog)) {
+ return (FALSE);
+ }
+ if (!xdr_rpcvers(xdrs, &objp->vers)) {
+ return (FALSE);
+ }
+ if (!xdr_rpcproc(xdrs, &objp->proc)) {
+ return (FALSE);
+ }
+ } else {
+ IXDR_PUT_U_INT32(buf, objp->prog);
+ IXDR_PUT_U_INT32(buf, objp->vers);
+ IXDR_PUT_U_INT32(buf, objp->proc);
+ }
+
+ /*
+ * All the jugglery for just getting the size of the arguments
+ */
+ lenposition = XDR_GETPOS(xdrs);
+ if (! xdr_u_int(xdrs, &(objp->args.args_len))) {
+ return (FALSE);
+ }
+ argposition = XDR_GETPOS(xdrs);
+ if (! (*objp->xdr_args)(xdrs, objp->args.args_val)) {
+ return (FALSE);
+ }
+ position = XDR_GETPOS(xdrs);
+ objp->args.args_len = (u_int)((u_long)position - (u_long)argposition);
+ XDR_SETPOS(xdrs, lenposition);
+ if (! xdr_u_int(xdrs, &(objp->args.args_len))) {
+ return (FALSE);
+ }
+ XDR_SETPOS(xdrs, position);
+ return (TRUE);
+}
+
+/*
+ * XDR remote call results
+ * written for XDR_DECODE direction only
+ */
+bool_t
+xdr_rpcb_rmtcallres(XDR *xdrs, struct rpcb_rmtcallres *p)
+{
+ bool_t dummy;
+ struct r_rpcb_rmtcallres *objp = (struct r_rpcb_rmtcallres *)(void *)p;
+
+ if (!xdr_string(xdrs, &objp->addr, (u_int)~0)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int(xdrs, &objp->results.results_len)) {
+ return (FALSE);
+ }
+ dummy = (*(objp->xdr_res))(xdrs, objp->results.results_val);
+ return (dummy);
+}
+
+bool_t
+xdr_netbuf(XDR *xdrs, struct netbuf *objp)
+{
+ bool_t dummy;
+ void **pp;
+
+ if (!xdr_u_int32_t(xdrs, (u_int32_t *) &objp->maxlen)) {
+ return (FALSE);
+ }
+ pp = &objp->buf;
+ dummy = xdr_bytes(xdrs, (char **) pp,
+ (u_int *)&(objp->len), objp->maxlen);
+ return (dummy);
+}
diff --git a/lib/libc/rpc/rpcb_st_xdr.c b/lib/libc/rpc/rpcb_st_xdr.c
new file mode 100644
index 000000000000..9abc0286f109
--- /dev/null
+++ b/lib/libc/rpc/rpcb_st_xdr.c
@@ -0,0 +1,260 @@
+/* $NetBSD: rpcb_st_xdr.c,v 1.3 2000/07/14 08:40:42 fvdl Exp $ */
+
+/*-
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright 1991 Sun Microsystems, Inc.
+ * rpcb_stat_xdr.c
+ */
+
+/*
+ * This file was generated from rpcb_prot.x, but includes only those
+ * routines used with the rpcbind stats facility.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <rpc/rpc.h>
+#include "un-namespace.h"
+
+/* Link list of all the stats about getport and getaddr */
+
+bool_t
+xdr_rpcbs_addrlist(XDR *xdrs, rpcbs_addrlist *objp)
+{
+ struct rpcbs_addrlist **pnext;
+
+ if (!xdr_rpcprog(xdrs, &objp->prog)) {
+ return (FALSE);
+ }
+ if (!xdr_rpcvers(xdrs, &objp->vers)) {
+ return (FALSE);
+ }
+ if (!xdr_int(xdrs, &objp->success)) {
+ return (FALSE);
+ }
+ if (!xdr_int(xdrs, &objp->failure)) {
+ return (FALSE);
+ }
+ if (!xdr_string(xdrs, &objp->netid, (u_int)~0)) {
+ return (FALSE);
+ }
+
+ pnext = &objp->next;
+
+ if (!xdr_pointer(xdrs, (char **) pnext,
+ sizeof (rpcbs_addrlist),
+ (xdrproc_t)xdr_rpcbs_addrlist)) {
+ return (FALSE);
+ }
+
+ return (TRUE);
+}
+
+/* Link list of all the stats about rmtcall */
+
+bool_t
+xdr_rpcbs_rmtcalllist(XDR *xdrs, rpcbs_rmtcalllist *objp)
+{
+ int32_t *buf;
+ struct rpcbs_rmtcalllist **pnext;
+
+ if (xdrs->x_op == XDR_ENCODE) {
+ buf = XDR_INLINE(xdrs, 6 * BYTES_PER_XDR_UNIT);
+ if (buf == NULL) {
+ if (!xdr_rpcprog(xdrs, &objp->prog)) {
+ return (FALSE);
+ }
+ if (!xdr_rpcvers(xdrs, &objp->vers)) {
+ return (FALSE);
+ }
+ if (!xdr_rpcproc(xdrs, &objp->proc)) {
+ return (FALSE);
+ }
+ if (!xdr_int(xdrs, &objp->success)) {
+ return (FALSE);
+ }
+ if (!xdr_int(xdrs, &objp->failure)) {
+ return (FALSE);
+ }
+ if (!xdr_int(xdrs, &objp->indirect)) {
+ return (FALSE);
+ }
+ } else {
+ IXDR_PUT_U_INT32(buf, objp->prog);
+ IXDR_PUT_U_INT32(buf, objp->vers);
+ IXDR_PUT_U_INT32(buf, objp->proc);
+ IXDR_PUT_INT32(buf, objp->success);
+ IXDR_PUT_INT32(buf, objp->failure);
+ IXDR_PUT_INT32(buf, objp->indirect);
+ }
+ if (!xdr_string(xdrs, &objp->netid, (u_int)~0)) {
+ return (FALSE);
+ }
+ pnext = &objp->next;
+ if (!xdr_pointer(xdrs, (char **) pnext,
+ sizeof (rpcbs_rmtcalllist),
+ (xdrproc_t)xdr_rpcbs_rmtcalllist)) {
+ return (FALSE);
+ }
+ return (TRUE);
+ } else if (xdrs->x_op == XDR_DECODE) {
+ buf = XDR_INLINE(xdrs, 6 * BYTES_PER_XDR_UNIT);
+ if (buf == NULL) {
+ if (!xdr_rpcprog(xdrs, &objp->prog)) {
+ return (FALSE);
+ }
+ if (!xdr_rpcvers(xdrs, &objp->vers)) {
+ return (FALSE);
+ }
+ if (!xdr_rpcproc(xdrs, &objp->proc)) {
+ return (FALSE);
+ }
+ if (!xdr_int(xdrs, &objp->success)) {
+ return (FALSE);
+ }
+ if (!xdr_int(xdrs, &objp->failure)) {
+ return (FALSE);
+ }
+ if (!xdr_int(xdrs, &objp->indirect)) {
+ return (FALSE);
+ }
+ } else {
+ objp->prog = (rpcprog_t)IXDR_GET_U_INT32(buf);
+ objp->vers = (rpcvers_t)IXDR_GET_U_INT32(buf);
+ objp->proc = (rpcproc_t)IXDR_GET_U_INT32(buf);
+ objp->success = (int)IXDR_GET_INT32(buf);
+ objp->failure = (int)IXDR_GET_INT32(buf);
+ objp->indirect = (int)IXDR_GET_INT32(buf);
+ }
+ if (!xdr_string(xdrs, &objp->netid, (u_int)~0)) {
+ return (FALSE);
+ }
+ if (!xdr_pointer(xdrs, (char **) pnext,
+ sizeof (rpcbs_rmtcalllist),
+ (xdrproc_t)xdr_rpcbs_rmtcalllist)) {
+ return (FALSE);
+ }
+ return (TRUE);
+ }
+ if (!xdr_rpcprog(xdrs, &objp->prog)) {
+ return (FALSE);
+ }
+ if (!xdr_rpcvers(xdrs, &objp->vers)) {
+ return (FALSE);
+ }
+ if (!xdr_rpcproc(xdrs, &objp->proc)) {
+ return (FALSE);
+ }
+ if (!xdr_int(xdrs, &objp->success)) {
+ return (FALSE);
+ }
+ if (!xdr_int(xdrs, &objp->failure)) {
+ return (FALSE);
+ }
+ if (!xdr_int(xdrs, &objp->indirect)) {
+ return (FALSE);
+ }
+ if (!xdr_string(xdrs, &objp->netid, (u_int)~0)) {
+ return (FALSE);
+ }
+ if (!xdr_pointer(xdrs, (char **) pnext,
+ sizeof (rpcbs_rmtcalllist),
+ (xdrproc_t)xdr_rpcbs_rmtcalllist)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_rpcbs_proc(XDR *xdrs, rpcbs_proc objp)
+{
+ if (!xdr_vector(xdrs, (char *)(void *)objp, RPCBSTAT_HIGHPROC,
+ sizeof (int), (xdrproc_t)xdr_int)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_rpcbs_addrlist_ptr(XDR *xdrs, rpcbs_addrlist_ptr *objp)
+{
+ if (!xdr_pointer(xdrs, (char **)objp, sizeof (rpcbs_addrlist),
+ (xdrproc_t)xdr_rpcbs_addrlist)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_rpcbs_rmtcalllist_ptr(XDR *xdrs, rpcbs_rmtcalllist_ptr *objp)
+{
+ if (!xdr_pointer(xdrs, (char **)objp, sizeof (rpcbs_rmtcalllist),
+ (xdrproc_t)xdr_rpcbs_rmtcalllist)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_rpcb_stat(XDR *xdrs, rpcb_stat *objp)
+{
+
+ if (!xdr_rpcbs_proc(xdrs, objp->info)) {
+ return (FALSE);
+ }
+ if (!xdr_int(xdrs, &objp->setinfo)) {
+ return (FALSE);
+ }
+ if (!xdr_int(xdrs, &objp->unsetinfo)) {
+ return (FALSE);
+ }
+ if (!xdr_rpcbs_addrlist_ptr(xdrs, &objp->addrinfo)) {
+ return (FALSE);
+ }
+ if (!xdr_rpcbs_rmtcalllist_ptr(xdrs, &objp->rmtinfo)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+/*
+ * One rpcb_stat structure is returned for each version of rpcbind
+ * being monitored.
+ */
+bool_t
+xdr_rpcb_stat_byvers(XDR *xdrs, rpcb_stat_byvers objp)
+{
+ if (!xdr_vector(xdrs, (char *)(void *)objp, RPCBVERS_STAT,
+ sizeof (rpcb_stat), (xdrproc_t)xdr_rpcb_stat)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
diff --git a/lib/libc/rpc/rpcbind.3 b/lib/libc/rpc/rpcbind.3
new file mode 100644
index 000000000000..3bf8be9ffa90
--- /dev/null
+++ b/lib/libc/rpc/rpcbind.3
@@ -0,0 +1,194 @@
+.\" @(#)rpcbind.3n 1.25 93/05/07 SMI; from SVr4
+.\" Copyright 1989 AT&T
+.\" Copyright (c) 1988 Sun Microsystem's, Inc. - All Right's Reserved.
+.\" $NetBSD: rpcbind.3,v 1.2 2000/06/03 18:47:28 fvdl Exp $
+.\" $FreeBSD$
+.Dd May 7, 1993
+.Dt RPCBIND 3
+.Os
+.Sh NAME
+.Nm rpcb_getmaps ,
+.Nm rpcb_getaddr ,
+.Nm rpcb_gettime ,
+.Nm rpcb_rmtcall ,
+.Nm rpcb_set ,
+.Nm rpcb_unset
+.Nd library routines for RPC bind service
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In rpc/rpc.h
+.Ft "rpcblist *"
+.Fn rpcb_getmaps "const struct netconfig *netconf" "const char *host"
+.Ft bool_t
+.Fn rpcb_getaddr "const rpcprog_t prognum" "const rpcvers_t versnum" "const struct netconfig *netconf" "struct netbuf *svcaddr" "const char *host"
+.Ft bool_t
+.Fn rpcb_gettime "const char *host" "time_t * timep"
+.Ft "enum clnt_stat"
+.Fn rpcb_rmtcall "const struct netconfig *netconf" "const char *host" "const rpcprog_t prognum" "const rpcvers_t versnum" "const rpcproc_t procnum" "const xdrproc_t inproc" "const caddr_t in" "const xdrproc_t outproc" "const caddr_t out" "const struct timeval tout" "const struct netbuf *svcaddr"
+.Ft bool_t
+.Fn rpcb_set "const rpcprog_t prognum" "const rpcvers_t versnum" "const struct netconfig *netconf" "const struct netbuf *svcaddr"
+.Ft bool_t
+.Fn rpcb_unset "const rpcprog_t prognum" "const rpcvers_t versnum" "const struct netconfig *netconf"
+.Sh DESCRIPTION
+These routines allow client C programs to make procedure
+calls to the RPC binder service.
+(see
+.Xr rpcbind 8 )
+maintains a list of mappings between programs
+and their universal addresses.
+.Sh Routines
+.Bl -tag -width XXXXX
+.It Fn rpcb_getmaps
+An interface to the rpcbind service,
+which returns a list of the current
+RPC program-to-address mappings on
+.Fa host .
+It uses the transport specified through
+.Fa netconf
+to contact the remote rpcbind
+service on
+.Fa host .
+This routine will return
+.Dv NULL ,
+if the remote rpcbind could not be contacted.
+.It Fn rpcb_getaddr
+An interface to the rpcbind
+service, which finds the address of the service on
+.Fa host
+that is registered with program number
+.Fa prognum ,
+version
+.Fa versnum ,
+and speaks the transport protocol associated with
+.Fa netconf .
+The address found is returned in
+.Fa svcaddr .
+The
+.Fa svcaddr
+argument
+should be preallocated.
+This routine returns
+.Dv TRUE
+if it succeeds.
+A return value of
+.Dv FALSE
+means that the mapping does not exist
+or that the RPC
+system failed to contact the remote
+rpcbind service.
+In the latter case, the global variable
+.Va rpc_createerr
+(see
+.Xr rpc_clnt_create 3 )
+contains the
+RPC status.
+.It Fn rpcb_gettime
+This routine returns the time on
+.Fa host
+in
+.Fa timep .
+If
+.Fa host
+is
+.Dv NULL ,
+.Fn rpcb_gettime
+returns the time on its own machine.
+This routine returns
+.Dv TRUE
+if it succeeds,
+.Dv FALSE
+if it fails.
+The
+.Fn rpcb_gettime
+function
+can be used to synchronize the time between the
+client and the remote server.
+.It Fn rpcb_rmtcall
+An interface to the rpcbind service, which instructs
+rpcbind on
+.Fa host
+to make an RPC
+call on your behalf to a procedure on that host.
+The
+.Fn netconfig
+structure should correspond to a connectionless transport.
+The
+.Fa svcaddr
+argument
+will be modified to the server's address if the procedure succeeds
+(see
+.Fn rpc_call
+and
+.Fn clnt_call
+in
+.Xr rpc_clnt_calls 3
+for the definitions of other arguments).
+.Pp
+This procedure should normally be used for a
+.Dq ping
+and nothing else.
+This routine allows programs to do lookup and call, all in one step.
+.Pp
+Note: Even if the server is not running
+.Fn rpcb_rmtcall
+does not return any error messages to the caller.
+In such a case, the caller times out.
+.Pp
+Note:
+.Fn rpcb_rmtcall
+is only available for connectionless transports.
+.It Fn rpcb_set
+An interface to the rpcbind
+service, which establishes a mapping between the triple
+.Bq Fa prognum , versnum , netconf->nc_netid
+and
+.Fa svcaddr
+on the machine's rpcbind
+service.
+The value of
+.Fa nc_netid
+must correspond to a network identifier that is defined by the
+netconfig database.
+This routine returns
+.Dv TRUE
+if it succeeds,
+.Dv FALSE
+otherwise.
+(See also
+.Fn svc_reg
+in
+.Xr rpc_svc_calls 3 . )
+If there already exists such an entry with rpcbind,
+.Fn rpcb_set
+will fail.
+.It Fn rpcb_unset
+An interface to the rpcbind
+service, which destroys the mapping between the triple
+.Bq Fa prognum , versnum , netconf->nc_netid
+and the address on the machine's rpcbind
+service.
+If
+.Fa netconf
+is
+.Dv NULL ,
+.Fn rpcb_unset
+destroys all mapping between the triple
+.Bq Fa prognum , versnum , No all-transports
+and the addresses on the machine's rpcbind service.
+This routine returns
+.Dv TRUE
+if it succeeds,
+.Dv FALSE
+otherwise.
+Only the owner of the service or the super-user can destroy the mapping.
+(See also
+.Fn svc_unreg
+in
+.Xr rpc_svc_calls 3 . )
+.El
+.Sh SEE ALSO
+.Xr rpc_clnt_calls 3 ,
+.Xr rpc_svc_calls 3 ,
+.Xr rpcbind 8 ,
+.Xr rpcinfo 8
diff --git a/lib/libc/rpc/rpcdname.c b/lib/libc/rpc/rpcdname.c
new file mode 100644
index 000000000000..08b5d7d49fc5
--- /dev/null
+++ b/lib/libc/rpc/rpcdname.c
@@ -0,0 +1,79 @@
+/*-
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)rpcdname.c 1.7 91/03/11 Copyr 1989 Sun Micro";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * rpcdname.c
+ * Gets the default domain name
+ */
+
+#include "namespace.h"
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include "un-namespace.h"
+
+static char *default_domain;
+
+static char *
+get_default_domain(void)
+{
+ char temp[256];
+
+ if (default_domain != NULL)
+ return (default_domain);
+ if (getdomainname(temp, sizeof(temp)) < 0)
+ return (0);
+ if ((int) strlen(temp) > 0) {
+ default_domain = malloc((strlen(temp) + (unsigned)1));
+ if (default_domain == NULL)
+ return (0);
+ (void) strcpy(default_domain, temp);
+ return (default_domain);
+ }
+ return (0);
+}
+
+/*
+ * This is a wrapper for the system call getdomainname which returns a
+ * ypclnt.h error code in the failure case. It also checks to see that
+ * the domain name is non-null, knowing that the null string is going to
+ * get rejected elsewhere in the NIS client package.
+ */
+int
+__rpc_get_default_domain(char **domain)
+{
+ if ((*domain = get_default_domain()) != NULL)
+ return (0);
+ return (-1);
+}
diff --git a/lib/libc/rpc/rpcsec_gss_stub.c b/lib/libc/rpc/rpcsec_gss_stub.c
new file mode 100644
index 000000000000..55eb1065c0b0
--- /dev/null
+++ b/lib/libc/rpc/rpcsec_gss_stub.c
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 2006 Doug Rabson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <rpc/rpc.h>
+#include <rpc/rpcsec_gss.h>
+
+bool_t
+__rpc_gss_wrap_stub(AUTH *auth, void *header, size_t headerlen, XDR* xdrs,
+ xdrproc_t xdr_args, void *args_ptr)
+{
+
+ return (FALSE);
+}
+
+bool_t
+__rpc_gss_unwrap_stub(AUTH *auth, XDR* xdrs, xdrproc_t xdr_args, void *args_ptr)
+{
+
+ return (FALSE);
+}
+
+__weak_reference(__rpc_gss_wrap_stub, __rpc_gss_wrap);
+__weak_reference(__rpc_gss_unwrap_stub, __rpc_gss_unwrap);
diff --git a/lib/libc/rpc/rtime.3 b/lib/libc/rpc/rtime.3
new file mode 100644
index 000000000000..028d2beade14
--- /dev/null
+++ b/lib/libc/rpc/rtime.3
@@ -0,0 +1,50 @@
+.\" @(#)rtime.3n 2.1 88/08/08 4.0 RPCSRC; from 1.5 88/02/08 SMI
+.\" $FreeBSD$
+.\"
+.Dd November 22, 1987
+.Dt RTIME 3
+.Os
+.Sh NAME
+.Nm rtime
+.Nd "get remote time"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/time.h
+.In netinet/in.h
+.Ft int
+.Fo rtime
+.Fa "struct sockaddr_in *addrp"
+.Fa "struct timeval *timep"
+.Fa "struct timeval *timeout"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn rtime
+function
+consults the Internet Time Server at the address pointed to by
+.Fa addrp
+and returns the remote time in the
+.Vt timeval
+struct pointed to by
+.Fa timep .
+Normally, the
+.Tn UDP
+protocol is used when consulting the Time Server.
+The
+.Fa timeout
+argument specifies how long the
+routine should wait before giving
+up when waiting for a reply.
+If
+.Fa timeout
+is specified as
+.Dv NULL ,
+however, the routine will instead use
+.Tn TCP
+and block until a reply is received from the time server.
+.Sh RETURN VALUES
+.Rv -std rtime
+.Sh SEE ALSO
+.Xr timed 8
diff --git a/lib/libc/rpc/rtime.c b/lib/libc/rpc/rtime.c
new file mode 100644
index 000000000000..7c40c36ce374
--- /dev/null
+++ b/lib/libc/rpc/rtime.c
@@ -0,0 +1,156 @@
+/*-
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 1988 by Sun Microsystems, Inc.
+
+ */
+
+/*
+ * rtime - get time from remote machine
+ *
+ * gets time, obtaining value from host
+ * on the udp/time socket. Since timeserver returns
+ * with time of day in seconds since Jan 1, 1900, must
+ * subtract seconds before Jan 1, 1970 to get
+ * what unix uses.
+ */
+#include "namespace.h"
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <netdb.h>
+#include "un-namespace.h"
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)rtime.c 2.2 88/08/10 4.0 RPCSRC; from 1.8 88/02/08 SMI";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+extern int _rpc_dtablesize( void );
+
+#define NYEARS (unsigned long)(1970 - 1900)
+#define TOFFSET (unsigned long)(60*60*24*(365*NYEARS + (NYEARS/4)))
+
+static void do_close( int );
+
+int
+rtime(struct sockaddr_in *addrp, struct timeval *timep,
+ struct timeval *timeout)
+{
+ int s;
+ fd_set readfds;
+ int res;
+ unsigned long thetime;
+ struct sockaddr_in from;
+ socklen_t fromlen;
+ int type;
+ struct servent *serv;
+
+ if (timeout == NULL) {
+ type = SOCK_STREAM;
+ } else {
+ type = SOCK_DGRAM;
+ }
+ s = _socket(AF_INET, type, 0);
+ if (s < 0) {
+ return(-1);
+ }
+ addrp->sin_family = AF_INET;
+
+ /* TCP and UDP port are the same in this case */
+ if ((serv = getservbyname("time", "tcp")) == NULL) {
+ return(-1);
+ }
+
+ addrp->sin_port = serv->s_port;
+
+ if (type == SOCK_DGRAM) {
+ res = _sendto(s, (char *)&thetime, sizeof(thetime), 0,
+ (struct sockaddr *)addrp, sizeof(*addrp));
+ if (res < 0) {
+ do_close(s);
+ return(-1);
+ }
+ do {
+ FD_ZERO(&readfds);
+ FD_SET(s, &readfds);
+ res = _select(_rpc_dtablesize(), &readfds,
+ (fd_set *)NULL, (fd_set *)NULL, timeout);
+ } while (res < 0 && errno == EINTR);
+ if (res <= 0) {
+ if (res == 0) {
+ errno = ETIMEDOUT;
+ }
+ do_close(s);
+ return(-1);
+ }
+ fromlen = sizeof(from);
+ res = _recvfrom(s, (char *)&thetime, sizeof(thetime), 0,
+ (struct sockaddr *)&from, &fromlen);
+ do_close(s);
+ if (res < 0) {
+ return(-1);
+ }
+ } else {
+ if (_connect(s, (struct sockaddr *)addrp, sizeof(*addrp)) < 0) {
+ do_close(s);
+ return(-1);
+ }
+ res = _read(s, (char *)&thetime, sizeof(thetime));
+ do_close(s);
+ if (res < 0) {
+ return(-1);
+ }
+ }
+ if (res != sizeof(thetime)) {
+ errno = EIO;
+ return(-1);
+ }
+ thetime = ntohl(thetime);
+ timep->tv_sec = thetime - TOFFSET;
+ timep->tv_usec = 0;
+ return(0);
+}
+
+static void
+do_close(int s)
+{
+ int save;
+
+ save = errno;
+ (void)_close(s);
+ errno = save;
+}
diff --git a/lib/libc/rpc/svc.c b/lib/libc/rpc/svc.c
new file mode 100644
index 000000000000..507d2e2774b6
--- /dev/null
+++ b/lib/libc/rpc/svc.c
@@ -0,0 +1,759 @@
+/* $NetBSD: svc.c,v 1.21 2000/07/06 03:10:35 christos Exp $ */
+
+/*-
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *sccsid2 = "@(#)svc.c 1.44 88/02/08 Copyr 1984 Sun Micro";
+static char *sccsid = "@(#)svc.c 2.4 88/08/11 4.0 RPCSRC";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * svc.c, Server-side remote procedure call interface.
+ *
+ * There are two sets of procedures here. The xprt routines are
+ * for handling transport handles. The svc routines handle the
+ * list of service routines.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#include "namespace.h"
+#include "reentrant.h"
+#include <sys/types.h>
+#include <sys/poll.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <rpc/rpc.h>
+#ifdef PORTMAP
+#include <rpc/pmap_clnt.h>
+#endif /* PORTMAP */
+#include "un-namespace.h"
+
+#include "rpc_com.h"
+#include "mt_misc.h"
+
+#define RQCRED_SIZE 400 /* this size is excessive */
+
+#define SVC_VERSQUIET 0x0001 /* keep quiet about vers mismatch */
+#define version_keepquiet(xp) (SVC_EXT(xp)->xp_flags & SVC_VERSQUIET)
+
+#define max(a, b) (a > b ? a : b)
+
+/*
+ * The services list
+ * Each entry represents a set of procedures (an rpc program).
+ * The dispatch routine takes request structs and runs the
+ * appropriate procedure.
+ */
+static struct svc_callout {
+ struct svc_callout *sc_next;
+ rpcprog_t sc_prog;
+ rpcvers_t sc_vers;
+ char *sc_netid;
+ void (*sc_dispatch)(struct svc_req *, SVCXPRT *);
+} *svc_head;
+
+SVCXPRT **__svc_xports;
+int __svc_maxrec;
+
+static struct svc_callout *svc_find(rpcprog_t, rpcvers_t,
+ struct svc_callout **, char *);
+static void __xprt_do_unregister (SVCXPRT *xprt, bool_t dolock);
+
+/* *************** SVCXPRT related stuff **************** */
+
+/*
+ * Activate a transport handle.
+ */
+void
+xprt_register(SVCXPRT *xprt)
+{
+ int sock;
+
+ assert(xprt != NULL);
+
+ sock = xprt->xp_fd;
+
+ rwlock_wrlock(&svc_fd_lock);
+ if (__svc_xports == NULL) {
+ __svc_xports = (SVCXPRT **)
+ mem_alloc(FD_SETSIZE * sizeof(SVCXPRT *));
+ if (__svc_xports == NULL) {
+ rwlock_unlock(&svc_fd_lock);
+ return;
+ }
+ memset(__svc_xports, '\0', FD_SETSIZE * sizeof(SVCXPRT *));
+ }
+ if (sock < FD_SETSIZE) {
+ __svc_xports[sock] = xprt;
+ FD_SET(sock, &svc_fdset);
+ svc_maxfd = max(svc_maxfd, sock);
+ }
+ rwlock_unlock(&svc_fd_lock);
+}
+
+void
+xprt_unregister(SVCXPRT *xprt)
+{
+ __xprt_do_unregister(xprt, TRUE);
+}
+
+void
+__xprt_unregister_unlocked(SVCXPRT *xprt)
+{
+ __xprt_do_unregister(xprt, FALSE);
+}
+
+/*
+ * De-activate a transport handle.
+ */
+static void
+__xprt_do_unregister(SVCXPRT *xprt, bool_t dolock)
+{
+ int sock;
+
+ assert(xprt != NULL);
+
+ sock = xprt->xp_fd;
+
+ if (dolock)
+ rwlock_wrlock(&svc_fd_lock);
+ if ((sock < FD_SETSIZE) && (__svc_xports[sock] == xprt)) {
+ __svc_xports[sock] = NULL;
+ FD_CLR(sock, &svc_fdset);
+ if (sock >= svc_maxfd) {
+ for (svc_maxfd--; svc_maxfd>=0; svc_maxfd--)
+ if (__svc_xports[svc_maxfd])
+ break;
+ }
+ }
+ if (dolock)
+ rwlock_unlock(&svc_fd_lock);
+}
+
+/*
+ * Add a service program to the callout list.
+ * The dispatch routine will be called when a rpc request for this
+ * program number comes in.
+ */
+bool_t
+svc_reg(SVCXPRT *xprt, const rpcprog_t prog, const rpcvers_t vers,
+ void (*dispatch)(struct svc_req *, SVCXPRT *),
+ const struct netconfig *nconf)
+{
+ bool_t dummy;
+ struct svc_callout *prev;
+ struct svc_callout *s;
+ struct netconfig *tnconf;
+ char *netid = NULL;
+ int flag = 0;
+
+/* VARIABLES PROTECTED BY svc_lock: s, prev, svc_head */
+
+ if (xprt->xp_netid) {
+ netid = strdup(xprt->xp_netid);
+ flag = 1;
+ } else if (nconf && nconf->nc_netid) {
+ netid = strdup(nconf->nc_netid);
+ flag = 1;
+ } else if ((tnconf = __rpcgettp(xprt->xp_fd)) != NULL) {
+ netid = strdup(tnconf->nc_netid);
+ flag = 1;
+ freenetconfigent(tnconf);
+ } /* must have been created with svc_raw_create */
+ if ((netid == NULL) && (flag == 1)) {
+ return (FALSE);
+ }
+
+ rwlock_wrlock(&svc_lock);
+ if ((s = svc_find(prog, vers, &prev, netid)) != NULL) {
+ free(netid);
+ if (s->sc_dispatch == dispatch)
+ goto rpcb_it; /* he is registering another xptr */
+ rwlock_unlock(&svc_lock);
+ return (FALSE);
+ }
+ s = mem_alloc(sizeof (struct svc_callout));
+ if (s == NULL) {
+ free(netid);
+ rwlock_unlock(&svc_lock);
+ return (FALSE);
+ }
+
+ s->sc_prog = prog;
+ s->sc_vers = vers;
+ s->sc_dispatch = dispatch;
+ s->sc_netid = netid;
+ s->sc_next = svc_head;
+ svc_head = s;
+
+ if ((xprt->xp_netid == NULL) && (flag == 1) && netid)
+ ((SVCXPRT *) xprt)->xp_netid = strdup(netid);
+
+rpcb_it:
+ rwlock_unlock(&svc_lock);
+ /* now register the information with the local binder service */
+ if (nconf) {
+ /*LINTED const castaway*/
+ dummy = rpcb_set(prog, vers, (struct netconfig *) nconf,
+ &((SVCXPRT *) xprt)->xp_ltaddr);
+ return (dummy);
+ }
+ return (TRUE);
+}
+
+/*
+ * Remove a service program from the callout list.
+ */
+void
+svc_unreg(const rpcprog_t prog, const rpcvers_t vers)
+{
+ struct svc_callout *prev;
+ struct svc_callout *s;
+
+ /* unregister the information anyway */
+ (void) rpcb_unset(prog, vers, NULL);
+ rwlock_wrlock(&svc_lock);
+ while ((s = svc_find(prog, vers, &prev, NULL)) != NULL) {
+ if (prev == NULL) {
+ svc_head = s->sc_next;
+ } else {
+ prev->sc_next = s->sc_next;
+ }
+ s->sc_next = NULL;
+ if (s->sc_netid)
+ mem_free(s->sc_netid, sizeof (s->sc_netid) + 1);
+ mem_free(s, sizeof (struct svc_callout));
+ }
+ rwlock_unlock(&svc_lock);
+}
+
+/* ********************** CALLOUT list related stuff ************* */
+
+#ifdef PORTMAP
+/*
+ * Add a service program to the callout list.
+ * The dispatch routine will be called when a rpc request for this
+ * program number comes in.
+ */
+bool_t
+svc_register(SVCXPRT *xprt, u_long prog, u_long vers,
+ void (*dispatch)(struct svc_req *, SVCXPRT *),
+ int protocol)
+{
+ struct svc_callout *prev;
+ struct svc_callout *s;
+
+ assert(xprt != NULL);
+ assert(dispatch != NULL);
+
+ if ((s = svc_find((rpcprog_t)prog, (rpcvers_t)vers, &prev, NULL)) !=
+ NULL) {
+ if (s->sc_dispatch == dispatch)
+ goto pmap_it; /* he is registering another xptr */
+ return (FALSE);
+ }
+ s = mem_alloc(sizeof(struct svc_callout));
+ if (s == NULL) {
+ return (FALSE);
+ }
+ s->sc_prog = (rpcprog_t)prog;
+ s->sc_vers = (rpcvers_t)vers;
+ s->sc_dispatch = dispatch;
+ s->sc_next = svc_head;
+ svc_head = s;
+pmap_it:
+ /* now register the information with the local binder service */
+ if (protocol) {
+ return (pmap_set(prog, vers, protocol, xprt->xp_port));
+ }
+ return (TRUE);
+}
+
+/*
+ * Remove a service program from the callout list.
+ */
+void
+svc_unregister(u_long prog, u_long vers)
+{
+ struct svc_callout *prev;
+ struct svc_callout *s;
+
+ if ((s = svc_find((rpcprog_t)prog, (rpcvers_t)vers, &prev, NULL)) ==
+ NULL)
+ return;
+ if (prev == NULL) {
+ svc_head = s->sc_next;
+ } else {
+ prev->sc_next = s->sc_next;
+ }
+ s->sc_next = NULL;
+ mem_free(s, sizeof(struct svc_callout));
+ /* now unregister the information with the local binder service */
+ (void)pmap_unset(prog, vers);
+}
+#endif /* PORTMAP */
+
+/*
+ * Search the callout list for a program number, return the callout
+ * struct.
+ */
+static struct svc_callout *
+svc_find(rpcprog_t prog, rpcvers_t vers, struct svc_callout **prev,
+ char *netid)
+{
+ struct svc_callout *s, *p;
+
+ assert(prev != NULL);
+
+ p = NULL;
+ for (s = svc_head; s != NULL; s = s->sc_next) {
+ if (((s->sc_prog == prog) && (s->sc_vers == vers)) &&
+ ((netid == NULL) || (s->sc_netid == NULL) ||
+ (strcmp(netid, s->sc_netid) == 0)))
+ break;
+ p = s;
+ }
+ *prev = p;
+ return (s);
+}
+
+/* ******************* REPLY GENERATION ROUTINES ************ */
+
+/*
+ * Send a reply to an rpc request
+ */
+bool_t
+svc_sendreply(SVCXPRT *xprt, xdrproc_t xdr_results,
+ void * xdr_location)
+{
+ struct rpc_msg rply;
+
+ assert(xprt != NULL);
+
+ rply.rm_direction = REPLY;
+ rply.rm_reply.rp_stat = MSG_ACCEPTED;
+ rply.acpted_rply.ar_verf = xprt->xp_verf;
+ rply.acpted_rply.ar_stat = SUCCESS;
+ rply.acpted_rply.ar_results.where = xdr_location;
+ rply.acpted_rply.ar_results.proc = xdr_results;
+ return (SVC_REPLY(xprt, &rply));
+}
+
+/*
+ * No procedure error reply
+ */
+void
+svcerr_noproc(SVCXPRT *xprt)
+{
+ struct rpc_msg rply;
+
+ assert(xprt != NULL);
+
+ rply.rm_direction = REPLY;
+ rply.rm_reply.rp_stat = MSG_ACCEPTED;
+ rply.acpted_rply.ar_verf = xprt->xp_verf;
+ rply.acpted_rply.ar_stat = PROC_UNAVAIL;
+ SVC_REPLY(xprt, &rply);
+}
+
+/*
+ * Can't decode args error reply
+ */
+void
+svcerr_decode(SVCXPRT *xprt)
+{
+ struct rpc_msg rply;
+
+ assert(xprt != NULL);
+
+ rply.rm_direction = REPLY;
+ rply.rm_reply.rp_stat = MSG_ACCEPTED;
+ rply.acpted_rply.ar_verf = xprt->xp_verf;
+ rply.acpted_rply.ar_stat = GARBAGE_ARGS;
+ SVC_REPLY(xprt, &rply);
+}
+
+/*
+ * Some system error
+ */
+void
+svcerr_systemerr(SVCXPRT *xprt)
+{
+ struct rpc_msg rply;
+
+ assert(xprt != NULL);
+
+ rply.rm_direction = REPLY;
+ rply.rm_reply.rp_stat = MSG_ACCEPTED;
+ rply.acpted_rply.ar_verf = xprt->xp_verf;
+ rply.acpted_rply.ar_stat = SYSTEM_ERR;
+ SVC_REPLY(xprt, &rply);
+}
+
+#if 0
+/*
+ * Tell RPC package to not complain about version errors to the client. This
+ * is useful when revving broadcast protocols that sit on a fixed address.
+ * There is really one (or should be only one) example of this kind of
+ * protocol: the portmapper (or rpc binder).
+ */
+void
+__svc_versquiet_on(SVCXPRT *xprt)
+{
+
+ SVC_EXT(xprt)->xp_flags |= SVC_VERSQUIET;
+}
+
+void
+__svc_versquiet_off(SVCXPRT *xprt)
+{
+
+ SVC_EXT(xprt)->xp_flags &= ~SVC_VERSQUIET;
+}
+
+void
+svc_versquiet(SVCXPRT *xprt)
+{
+ __svc_versquiet_on(xprt);
+}
+
+int
+__svc_versquiet_get(SVCXPRT *xprt)
+{
+
+ return (SVC_EXT(xprt)->xp_flags & SVC_VERSQUIET);
+}
+#endif
+
+/*
+ * Authentication error reply
+ */
+void
+svcerr_auth(SVCXPRT *xprt, enum auth_stat why)
+{
+ struct rpc_msg rply;
+
+ assert(xprt != NULL);
+
+ rply.rm_direction = REPLY;
+ rply.rm_reply.rp_stat = MSG_DENIED;
+ rply.rjcted_rply.rj_stat = AUTH_ERROR;
+ rply.rjcted_rply.rj_why = why;
+ SVC_REPLY(xprt, &rply);
+}
+
+/*
+ * Auth too weak error reply
+ */
+void
+svcerr_weakauth(SVCXPRT *xprt)
+{
+
+ assert(xprt != NULL);
+
+ svcerr_auth(xprt, AUTH_TOOWEAK);
+}
+
+/*
+ * Program unavailable error reply
+ */
+void
+svcerr_noprog(SVCXPRT *xprt)
+{
+ struct rpc_msg rply;
+
+ assert(xprt != NULL);
+
+ rply.rm_direction = REPLY;
+ rply.rm_reply.rp_stat = MSG_ACCEPTED;
+ rply.acpted_rply.ar_verf = xprt->xp_verf;
+ rply.acpted_rply.ar_stat = PROG_UNAVAIL;
+ SVC_REPLY(xprt, &rply);
+}
+
+/*
+ * Program version mismatch error reply
+ */
+void
+svcerr_progvers(SVCXPRT *xprt, rpcvers_t low_vers, rpcvers_t high_vers)
+{
+ struct rpc_msg rply;
+
+ assert(xprt != NULL);
+
+ rply.rm_direction = REPLY;
+ rply.rm_reply.rp_stat = MSG_ACCEPTED;
+ rply.acpted_rply.ar_verf = xprt->xp_verf;
+ rply.acpted_rply.ar_stat = PROG_MISMATCH;
+ rply.acpted_rply.ar_vers.low = (u_int32_t)low_vers;
+ rply.acpted_rply.ar_vers.high = (u_int32_t)high_vers;
+ SVC_REPLY(xprt, &rply);
+}
+
+/*
+ * Allocate a new server transport structure. All fields are
+ * initialized to zero and xp_p3 is initialized to point at an
+ * extension structure to hold various flags and authentication
+ * parameters.
+ */
+SVCXPRT *
+svc_xprt_alloc(void)
+{
+ SVCXPRT *xprt;
+ SVCXPRT_EXT *ext;
+
+ xprt = mem_alloc(sizeof(SVCXPRT));
+ if (xprt == NULL)
+ return (NULL);
+ memset(xprt, 0, sizeof(SVCXPRT));
+ ext = mem_alloc(sizeof(SVCXPRT_EXT));
+ if (ext == NULL) {
+ mem_free(xprt, sizeof(SVCXPRT));
+ return (NULL);
+ }
+ memset(ext, 0, sizeof(SVCXPRT_EXT));
+ xprt->xp_p3 = ext;
+ ext->xp_auth.svc_ah_ops = &svc_auth_null_ops;
+
+ return (xprt);
+}
+
+/*
+ * Free a server transport structure.
+ */
+void
+svc_xprt_free(SVCXPRT *xprt)
+{
+
+ mem_free(xprt->xp_p3, sizeof(SVCXPRT_EXT));
+ mem_free(xprt, sizeof(SVCXPRT));
+}
+
+/* ******************* SERVER INPUT STUFF ******************* */
+
+/*
+ * Get server side input from some transport.
+ *
+ * Statement of authentication parameters management:
+ * This function owns and manages all authentication parameters, specifically
+ * the "raw" parameters (msg.rm_call.cb_cred and msg.rm_call.cb_verf) and
+ * the "cooked" credentials (rqst->rq_clntcred).
+ * However, this function does not know the structure of the cooked
+ * credentials, so it make the following assumptions:
+ * a) the structure is contiguous (no pointers), and
+ * b) the cred structure size does not exceed RQCRED_SIZE bytes.
+ * In all events, all three parameters are freed upon exit from this routine.
+ * The storage is trivially management on the call stack in user land, but
+ * is mallocated in kernel land.
+ */
+
+void
+svc_getreq(int rdfds)
+{
+ fd_set readfds;
+
+ FD_ZERO(&readfds);
+ readfds.fds_bits[0] = rdfds;
+ svc_getreqset(&readfds);
+}
+
+void
+svc_getreqset(fd_set *readfds)
+{
+ int bit, fd;
+ fd_mask mask, *maskp;
+ int sock;
+
+ assert(readfds != NULL);
+
+ maskp = readfds->fds_bits;
+ for (sock = 0; sock < FD_SETSIZE; sock += NFDBITS) {
+ for (mask = *maskp++; (bit = ffsl(mask)) != 0;
+ mask ^= (1ul << (bit - 1))) {
+ /* sock has input waiting */
+ fd = sock + bit - 1;
+ svc_getreq_common(fd);
+ }
+ }
+}
+
+void
+svc_getreq_common(int fd)
+{
+ SVCXPRT *xprt;
+ struct svc_req r;
+ struct rpc_msg msg;
+ int prog_found;
+ rpcvers_t low_vers;
+ rpcvers_t high_vers;
+ enum xprt_stat stat;
+ char cred_area[2*MAX_AUTH_BYTES + RQCRED_SIZE];
+
+ msg.rm_call.cb_cred.oa_base = cred_area;
+ msg.rm_call.cb_verf.oa_base = &(cred_area[MAX_AUTH_BYTES]);
+ r.rq_clntcred = &(cred_area[2*MAX_AUTH_BYTES]);
+
+ rwlock_rdlock(&svc_fd_lock);
+ xprt = __svc_xports[fd];
+ rwlock_unlock(&svc_fd_lock);
+ if (xprt == NULL)
+ /* But do we control sock? */
+ return;
+ /* now receive msgs from xprtprt (support batch calls) */
+ do {
+ if (SVC_RECV(xprt, &msg)) {
+
+ /* now find the exported program and call it */
+ struct svc_callout *s;
+ enum auth_stat why;
+
+ r.rq_xprt = xprt;
+ r.rq_prog = msg.rm_call.cb_prog;
+ r.rq_vers = msg.rm_call.cb_vers;
+ r.rq_proc = msg.rm_call.cb_proc;
+ r.rq_cred = msg.rm_call.cb_cred;
+ /* first authenticate the message */
+ if ((why = _authenticate(&r, &msg)) != AUTH_OK) {
+ /*
+ * RPCSEC_GSS uses this return code
+ * for requests that form part of its
+ * context establishment protocol and
+ * should not be dispatched to the
+ * application.
+ */
+ if (why != RPCSEC_GSS_NODISPATCH)
+ svcerr_auth(xprt, why);
+ goto call_done;
+ }
+ /* now match message with a registered service*/
+ prog_found = FALSE;
+ low_vers = (rpcvers_t) -1L;
+ high_vers = (rpcvers_t) 0L;
+ for (s = svc_head; s != NULL; s = s->sc_next) {
+ if (s->sc_prog == r.rq_prog) {
+ if (s->sc_vers == r.rq_vers) {
+ (*s->sc_dispatch)(&r, xprt);
+ goto call_done;
+ } /* found correct version */
+ prog_found = TRUE;
+ if (s->sc_vers < low_vers)
+ low_vers = s->sc_vers;
+ if (s->sc_vers > high_vers)
+ high_vers = s->sc_vers;
+ } /* found correct program */
+ }
+ /*
+ * if we got here, the program or version
+ * is not served ...
+ */
+ if (prog_found)
+ svcerr_progvers(xprt, low_vers, high_vers);
+ else
+ svcerr_noprog(xprt);
+ /* Fall through to ... */
+ }
+ /*
+ * Check if the xprt has been disconnected in a
+ * recursive call in the service dispatch routine.
+ * If so, then break.
+ */
+ rwlock_rdlock(&svc_fd_lock);
+ if (xprt != __svc_xports[fd]) {
+ rwlock_unlock(&svc_fd_lock);
+ break;
+ }
+ rwlock_unlock(&svc_fd_lock);
+call_done:
+ if ((stat = SVC_STAT(xprt)) == XPRT_DIED){
+ SVC_DESTROY(xprt);
+ break;
+ }
+ } while (stat == XPRT_MOREREQS);
+}
+
+
+void
+svc_getreq_poll(struct pollfd *pfdp, int pollretval)
+{
+ int i;
+ int fds_found;
+
+ for (i = fds_found = 0; fds_found < pollretval; i++) {
+ struct pollfd *p = &pfdp[i];
+
+ if (p->revents) {
+ /* fd has input waiting */
+ fds_found++;
+ /*
+ * We assume that this function is only called
+ * via someone _select()ing from svc_fdset or
+ * _poll()ing from svc_pollset[]. Thus it's safe
+ * to handle the POLLNVAL event by simply turning
+ * the corresponding bit off in svc_fdset. The
+ * svc_pollset[] array is derived from svc_fdset
+ * and so will also be updated eventually.
+ *
+ * XXX Should we do an xprt_unregister() instead?
+ */
+ if (p->revents & POLLNVAL) {
+ rwlock_wrlock(&svc_fd_lock);
+ FD_CLR(p->fd, &svc_fdset);
+ rwlock_unlock(&svc_fd_lock);
+ } else
+ svc_getreq_common(p->fd);
+ }
+ }
+}
+
+bool_t
+rpc_control(int what, void *arg)
+{
+ int val;
+
+ switch (what) {
+ case RPC_SVC_CONNMAXREC_SET:
+ val = *(int *)arg;
+ if (val <= 0)
+ return FALSE;
+ __svc_maxrec = val;
+ return TRUE;
+ case RPC_SVC_CONNMAXREC_GET:
+ *(int *)arg = __svc_maxrec;
+ return TRUE;
+ default:
+ break;
+ }
+ return FALSE;
+}
diff --git a/lib/libc/rpc/svc_auth.c b/lib/libc/rpc/svc_auth.c
new file mode 100644
index 000000000000..58435af0c13b
--- /dev/null
+++ b/lib/libc/rpc/svc_auth.c
@@ -0,0 +1,224 @@
+/* $NetBSD: svc_auth.c,v 1.12 2000/07/06 03:10:35 christos Exp $ */
+
+/*-
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 1986-1991 by Sun Microsystems Inc.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+#ident "@(#)svc_auth.c 1.16 94/04/24 SMI"
+static char sccsid[] = "@(#)svc_auth.c 1.26 89/02/07 Copyr 1984 Sun Micro";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * svc_auth.c, Server-side rpc authenticator interface.
+ *
+ */
+
+#include "namespace.h"
+#include "reentrant.h"
+#include <sys/types.h>
+#include <rpc/rpc.h>
+#include <stdlib.h>
+#include "un-namespace.h"
+#include "mt_misc.h"
+
+/*
+ * svcauthsw is the bdevsw of server side authentication.
+ *
+ * Server side authenticators are called from authenticate by
+ * using the client auth struct flavor field to index into svcauthsw.
+ * The server auth flavors must implement a routine that looks
+ * like:
+ *
+ * enum auth_stat
+ * flavorx_auth(rqst, msg)
+ * struct svc_req *rqst;
+ * struct rpc_msg *msg;
+ *
+ */
+
+/* declarations to allow servers to specify new authentication flavors */
+struct authsvc {
+ int flavor;
+ enum auth_stat (*handler)(struct svc_req *, struct rpc_msg *);
+ struct authsvc *next;
+};
+static struct authsvc *Auths = NULL;
+
+struct svc_auth_ops svc_auth_null_ops;
+
+/*
+ * The call rpc message, msg has been obtained from the wire. The msg contains
+ * the raw form of credentials and verifiers. authenticate returns AUTH_OK
+ * if the msg is successfully authenticated. If AUTH_OK then the routine also
+ * does the following things:
+ * set rqst->rq_xprt->verf to the appropriate response verifier;
+ * sets rqst->rq_client_cred to the "cooked" form of the credentials.
+ *
+ * NB: rqst->rq_cxprt->verf must be pre-alloctaed;
+ * its length is set appropriately.
+ *
+ * The caller still owns and is responsible for msg->u.cmb.cred and
+ * msg->u.cmb.verf. The authentication system retains ownership of
+ * rqst->rq_client_cred, the cooked credentials.
+ *
+ * There is an assumption that any flavour less than AUTH_NULL is
+ * invalid.
+ */
+enum auth_stat
+_authenticate(struct svc_req *rqst, struct rpc_msg *msg)
+{
+ int cred_flavor;
+ struct authsvc *asp;
+ enum auth_stat dummy;
+
+/* VARIABLES PROTECTED BY authsvc_lock: asp, Auths */
+
+ rqst->rq_cred = msg->rm_call.cb_cred;
+ SVC_AUTH(rqst->rq_xprt).svc_ah_ops = &svc_auth_null_ops;
+ SVC_AUTH(rqst->rq_xprt).svc_ah_private = NULL;
+ rqst->rq_xprt->xp_verf.oa_flavor = _null_auth.oa_flavor;
+ rqst->rq_xprt->xp_verf.oa_length = 0;
+ cred_flavor = rqst->rq_cred.oa_flavor;
+ switch (cred_flavor) {
+ case AUTH_NULL:
+ dummy = _svcauth_null(rqst, msg);
+ return (dummy);
+ case AUTH_SYS:
+ dummy = _svcauth_unix(rqst, msg);
+ return (dummy);
+ case AUTH_SHORT:
+ dummy = _svcauth_short(rqst, msg);
+ return (dummy);
+#ifdef DES_BUILTIN
+ case AUTH_DES:
+ dummy = _svcauth_des(rqst, msg);
+ return (dummy);
+#endif
+ default:
+ break;
+ }
+
+ /* flavor doesn't match any of the builtin types, so try new ones */
+ mutex_lock(&authsvc_lock);
+ for (asp = Auths; asp; asp = asp->next) {
+ if (asp->flavor == cred_flavor) {
+ enum auth_stat as;
+
+ as = (*asp->handler)(rqst, msg);
+ mutex_unlock(&authsvc_lock);
+ return (as);
+ }
+ }
+ mutex_unlock(&authsvc_lock);
+
+ return (AUTH_REJECTEDCRED);
+}
+
+/*
+ * A set of null auth methods used by any authentication protocols
+ * that don't need to inspect or modify the message body.
+ */
+static bool_t
+svcauth_null_wrap(SVCAUTH *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr)
+{
+
+ return (xdr_func(xdrs, xdr_ptr));
+}
+
+struct svc_auth_ops svc_auth_null_ops = {
+ svcauth_null_wrap,
+ svcauth_null_wrap,
+};
+
+/*ARGSUSED*/
+enum auth_stat
+_svcauth_null(struct svc_req *rqst, struct rpc_msg *msg)
+{
+ return (AUTH_OK);
+}
+
+/*
+ * Allow the rpc service to register new authentication types that it is
+ * prepared to handle. When an authentication flavor is registered,
+ * the flavor is checked against already registered values. If not
+ * registered, then a new Auths entry is added on the list.
+ *
+ * There is no provision to delete a registration once registered.
+ *
+ * This routine returns:
+ * 0 if registration successful
+ * 1 if flavor already registered
+ * -1 if can't register (errno set)
+ */
+
+int
+svc_auth_reg(int cred_flavor,
+ enum auth_stat (*handler)(struct svc_req *, struct rpc_msg *))
+{
+ struct authsvc *asp;
+
+ switch (cred_flavor) {
+ case AUTH_NULL:
+ case AUTH_SYS:
+ case AUTH_SHORT:
+#ifdef DES_BUILTIN
+ case AUTH_DES:
+#endif
+ /* already registered */
+ return (1);
+
+ default:
+ mutex_lock(&authsvc_lock);
+ for (asp = Auths; asp; asp = asp->next) {
+ if (asp->flavor == cred_flavor) {
+ /* already registered */
+ mutex_unlock(&authsvc_lock);
+ return (1);
+ }
+ }
+
+ /* this is a new one, so go ahead and register it */
+ asp = mem_alloc(sizeof (*asp));
+ if (asp == NULL) {
+ mutex_unlock(&authsvc_lock);
+ return (-1);
+ }
+ asp->flavor = cred_flavor;
+ asp->handler = handler;
+ asp->next = Auths;
+ Auths = asp;
+ mutex_unlock(&authsvc_lock);
+ break;
+ }
+ return (0);
+}
diff --git a/lib/libc/rpc/svc_auth_des.c b/lib/libc/rpc/svc_auth_des.c
new file mode 100644
index 000000000000..7a24c06e34e0
--- /dev/null
+++ b/lib/libc/rpc/svc_auth_des.c
@@ -0,0 +1,526 @@
+
+/*
+ * Copyright (c) 1988 by Sun Microsystems, Inc.
+ */
+
+/*-
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * svcauth_des.c, server-side des authentication
+ *
+ * We insure for the service the following:
+ * (1) The timestamp microseconds do not exceed 1 million.
+ * (2) The timestamp plus the window is less than the current time.
+ * (3) The timestamp is not less than the one previously
+ * seen in the current session.
+ *
+ * It is up to the server to determine if the window size is
+ * too small .
+ *
+ */
+
+#include "namespace.h"
+#include "reentrant.h"
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <rpc/des_crypt.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#include <rpc/auth.h>
+#include <rpc/auth_des.h>
+#include <rpc/svc.h>
+#include <rpc/rpc_msg.h>
+#include <rpc/svc_auth.h>
+#include "libc_private.h"
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)svcauth_des.c 2.3 89/07/11 4.0 RPCSRC; from 1.15 88/02/08 SMI";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+extern int key_decryptsession_pk(const char *, netobj *, des_block *);
+
+#define debug(msg) printf("svcauth_des: %s\n", msg)
+
+#define USEC_PER_SEC ((u_long) 1000000L)
+#define BEFORE(t1, t2) timercmp(t1, t2, <)
+
+/*
+ * LRU cache of conversation keys and some other useful items.
+ */
+#define AUTHDES_CACHESZ 64
+struct cache_entry {
+ des_block key; /* conversation key */
+ char *rname; /* client's name */
+ u_int window; /* credential lifetime window */
+ struct timeval laststamp; /* detect replays of creds */
+ char *localcred; /* generic local credential */
+};
+static struct cache_entry *authdes_cache/* [AUTHDES_CACHESZ] */;
+static short *authdes_lru/* [AUTHDES_CACHESZ] */;
+
+static void cache_init(void); /* initialize the cache */
+static short cache_spot(des_block *, char *, struct timeval *); /* find an entry in the cache */
+static void cache_ref(short sid); /* note that sid was ref'd */
+
+static void invalidate(char *); /* invalidate entry in cache */
+
+/*
+ * cache statistics
+ */
+static struct {
+ u_long ncachehits; /* times cache hit, and is not replay */
+ u_long ncachereplays; /* times cache hit, and is replay */
+ u_long ncachemisses; /* times cache missed */
+} svcauthdes_stats;
+
+/*
+ * Service side authenticator for AUTH_DES
+ */
+enum auth_stat
+_svcauth_des(struct svc_req *rqst, struct rpc_msg *msg)
+{
+
+ long *ixdr;
+ des_block cryptbuf[2];
+ struct authdes_cred *cred;
+ struct authdes_verf verf;
+ int status;
+ struct cache_entry *entry;
+ short sid = 0;
+ des_block *sessionkey;
+ des_block ivec;
+ u_int window;
+ struct timeval timestamp;
+ u_long namelen;
+ struct area {
+ struct authdes_cred area_cred;
+ char area_netname[MAXNETNAMELEN+1];
+ } *area;
+
+ if (authdes_cache == NULL) {
+ cache_init();
+ }
+
+ area = (struct area *)rqst->rq_clntcred;
+ cred = (struct authdes_cred *)&area->area_cred;
+
+ /*
+ * Get the credential
+ */
+ ixdr = (long *)msg->rm_call.cb_cred.oa_base;
+ cred->adc_namekind = IXDR_GET_ENUM(ixdr, enum authdes_namekind);
+ switch (cred->adc_namekind) {
+ case ADN_FULLNAME:
+ namelen = IXDR_GET_U_LONG(ixdr);
+ if (namelen > MAXNETNAMELEN) {
+ return (AUTH_BADCRED);
+ }
+ cred->adc_fullname.name = area->area_netname;
+ bcopy((char *)ixdr, cred->adc_fullname.name,
+ (u_int)namelen);
+ cred->adc_fullname.name[namelen] = 0;
+ ixdr += (RNDUP(namelen) / BYTES_PER_XDR_UNIT);
+ cred->adc_fullname.key.key.high = (u_long)*ixdr++;
+ cred->adc_fullname.key.key.low = (u_long)*ixdr++;
+ cred->adc_fullname.window = (u_long)*ixdr++;
+ break;
+ case ADN_NICKNAME:
+ cred->adc_nickname = (u_long)*ixdr++;
+ break;
+ default:
+ return (AUTH_BADCRED);
+ }
+
+ /*
+ * Get the verifier
+ */
+ ixdr = (long *)msg->rm_call.cb_verf.oa_base;
+ verf.adv_xtimestamp.key.high = (u_long)*ixdr++;
+ verf.adv_xtimestamp.key.low = (u_long)*ixdr++;
+ verf.adv_int_u = (u_long)*ixdr++;
+
+
+ /*
+ * Get the conversation key
+ */
+ if (cred->adc_namekind == ADN_FULLNAME) {
+ netobj pkey;
+ char pkey_data[1024];
+
+ sessionkey = &cred->adc_fullname.key;
+ if (! getpublickey(cred->adc_fullname.name, pkey_data)) {
+ debug("getpublickey");
+ return(AUTH_BADCRED);
+ }
+ pkey.n_bytes = pkey_data;
+ pkey.n_len = strlen(pkey_data) + 1;
+ if (key_decryptsession_pk(cred->adc_fullname.name, &pkey,
+ sessionkey) < 0) {
+ debug("decryptsessionkey");
+ return (AUTH_BADCRED); /* key not found */
+ }
+ } else { /* ADN_NICKNAME */
+ sid = (short)cred->adc_nickname;
+ if (sid < 0 || sid >= AUTHDES_CACHESZ) {
+ debug("bad nickname");
+ return (AUTH_BADCRED); /* garbled credential */
+ }
+ sessionkey = &authdes_cache[sid].key;
+ }
+
+
+ /*
+ * Decrypt the timestamp
+ */
+ cryptbuf[0] = verf.adv_xtimestamp;
+ if (cred->adc_namekind == ADN_FULLNAME) {
+ cryptbuf[1].key.high = cred->adc_fullname.window;
+ cryptbuf[1].key.low = verf.adv_winverf;
+ ivec.key.high = ivec.key.low = 0;
+ status = cbc_crypt((char *)sessionkey, (char *)cryptbuf,
+ 2*sizeof(des_block), DES_DECRYPT | DES_HW,
+ (char *)&ivec);
+ } else {
+ status = ecb_crypt((char *)sessionkey, (char *)cryptbuf,
+ sizeof(des_block), DES_DECRYPT | DES_HW);
+ }
+ if (DES_FAILED(status)) {
+ debug("decryption failure");
+ return (AUTH_FAILED); /* system error */
+ }
+
+ /*
+ * XDR the decrypted timestamp
+ */
+ ixdr = (long *)cryptbuf;
+ timestamp.tv_sec = IXDR_GET_LONG(ixdr);
+ timestamp.tv_usec = IXDR_GET_LONG(ixdr);
+
+ /*
+ * Check for valid credentials and verifiers.
+ * They could be invalid because the key was flushed
+ * out of the cache, and so a new session should begin.
+ * Be sure and send AUTH_REJECTED{CRED, VERF} if this is the case.
+ */
+ {
+ struct timeval current;
+ int nick;
+ int winverf;
+
+ if (cred->adc_namekind == ADN_FULLNAME) {
+ window = IXDR_GET_U_LONG(ixdr);
+ winverf = IXDR_GET_U_LONG(ixdr);
+ if (winverf != window - 1) {
+ debug("window verifier mismatch");
+ return (AUTH_BADCRED); /* garbled credential */
+ }
+ sid = cache_spot(sessionkey, cred->adc_fullname.name,
+ &timestamp);
+ if (sid < 0) {
+ debug("replayed credential");
+ return (AUTH_REJECTEDCRED); /* replay */
+ }
+ nick = 0;
+ } else { /* ADN_NICKNAME */
+ window = authdes_cache[sid].window;
+ nick = 1;
+ }
+
+ if ((u_long)timestamp.tv_usec >= USEC_PER_SEC) {
+ debug("invalid usecs");
+ /* cached out (bad key), or garbled verifier */
+ return (nick ? AUTH_REJECTEDVERF : AUTH_BADVERF);
+ }
+ if (nick && BEFORE(&timestamp,
+ &authdes_cache[sid].laststamp)) {
+ debug("timestamp before last seen");
+ return (AUTH_REJECTEDVERF); /* replay */
+ }
+ (void)gettimeofday(&current, NULL);
+ current.tv_sec -= window; /* allow for expiration */
+ if (!BEFORE(&current, &timestamp)) {
+ debug("timestamp expired");
+ /* replay, or garbled credential */
+ return (nick ? AUTH_REJECTEDVERF : AUTH_BADCRED);
+ }
+ }
+
+ /*
+ * Set up the reply verifier
+ */
+ verf.adv_nickname = (u_long)sid;
+
+ /*
+ * xdr the timestamp before encrypting
+ */
+ ixdr = (long *)cryptbuf;
+ IXDR_PUT_LONG(ixdr, timestamp.tv_sec - 1);
+ IXDR_PUT_LONG(ixdr, timestamp.tv_usec);
+
+ /*
+ * encrypt the timestamp
+ */
+ status = ecb_crypt((char *)sessionkey, (char *)cryptbuf,
+ sizeof(des_block), DES_ENCRYPT | DES_HW);
+ if (DES_FAILED(status)) {
+ debug("encryption failure");
+ return (AUTH_FAILED); /* system error */
+ }
+ verf.adv_xtimestamp = cryptbuf[0];
+
+ /*
+ * Serialize the reply verifier, and update rqst
+ */
+ ixdr = (long *)msg->rm_call.cb_verf.oa_base;
+ *ixdr++ = (long)verf.adv_xtimestamp.key.high;
+ *ixdr++ = (long)verf.adv_xtimestamp.key.low;
+ *ixdr++ = (long)verf.adv_int_u;
+
+ rqst->rq_xprt->xp_verf.oa_flavor = AUTH_DES;
+ rqst->rq_xprt->xp_verf.oa_base = msg->rm_call.cb_verf.oa_base;
+ rqst->rq_xprt->xp_verf.oa_length =
+ (char *)ixdr - msg->rm_call.cb_verf.oa_base;
+
+ /*
+ * We succeeded, commit the data to the cache now and
+ * finish cooking the credential.
+ */
+ entry = &authdes_cache[sid];
+ entry->laststamp = timestamp;
+ cache_ref(sid);
+ if (cred->adc_namekind == ADN_FULLNAME) {
+ cred->adc_fullname.window = window;
+ cred->adc_nickname = (u_long)sid; /* save nickname */
+ if (entry->rname != NULL) {
+ mem_free(entry->rname, strlen(entry->rname) + 1);
+ }
+ entry->rname = (char *)mem_alloc((u_int)strlen(cred->adc_fullname.name)
+ + 1);
+ if (entry->rname != NULL) {
+ (void) strcpy(entry->rname, cred->adc_fullname.name);
+ } else {
+ debug("out of memory");
+ }
+ entry->key = *sessionkey;
+ entry->window = window;
+ invalidate(entry->localcred); /* mark any cached cred invalid */
+ } else { /* ADN_NICKNAME */
+ /*
+ * nicknames are cooked into fullnames
+ */
+ cred->adc_namekind = ADN_FULLNAME;
+ cred->adc_fullname.name = entry->rname;
+ cred->adc_fullname.key = entry->key;
+ cred->adc_fullname.window = entry->window;
+ }
+ return (AUTH_OK); /* we made it!*/
+}
+
+
+/*
+ * Initialize the cache
+ */
+static void
+cache_init(void)
+{
+ int i;
+
+ authdes_cache = (struct cache_entry *)
+ mem_alloc(sizeof(struct cache_entry) * AUTHDES_CACHESZ);
+ bzero((char *)authdes_cache,
+ sizeof(struct cache_entry) * AUTHDES_CACHESZ);
+
+ authdes_lru = (short *)mem_alloc(sizeof(short) * AUTHDES_CACHESZ);
+ /*
+ * Initialize the lru list
+ */
+ for (i = 0; i < AUTHDES_CACHESZ; i++) {
+ authdes_lru[i] = i;
+ }
+}
+
+
+/*
+ * Find the lru victim
+ */
+static short
+cache_victim(void)
+{
+ return (authdes_lru[AUTHDES_CACHESZ-1]);
+}
+
+/*
+ * Note that sid was referenced
+ */
+static void
+cache_ref(short sid)
+{
+ int i;
+ short curr;
+ short prev;
+
+ prev = authdes_lru[0];
+ authdes_lru[0] = sid;
+ for (i = 1; prev != sid; i++) {
+ curr = authdes_lru[i];
+ authdes_lru[i] = prev;
+ prev = curr;
+ }
+}
+
+
+/*
+ * Find a spot in the cache for a credential containing
+ * the items given. Return -1 if a replay is detected, otherwise
+ * return the spot in the cache.
+ */
+static short
+cache_spot(des_block *key, char *name, struct timeval *timestamp)
+{
+ struct cache_entry *cp;
+ int i;
+ u_long hi;
+
+ hi = key->key.high;
+ for (cp = authdes_cache, i = 0; i < AUTHDES_CACHESZ; i++, cp++) {
+ if (cp->key.key.high == hi &&
+ cp->key.key.low == key->key.low &&
+ cp->rname != NULL &&
+ bcmp(cp->rname, name, strlen(name) + 1) == 0) {
+ if (BEFORE(timestamp, &cp->laststamp)) {
+ svcauthdes_stats.ncachereplays++;
+ return (-1); /* replay */
+ }
+ svcauthdes_stats.ncachehits++;
+ return (i); /* refresh */
+ }
+ }
+ svcauthdes_stats.ncachemisses++;
+ return (cache_victim()); /* new credential */
+}
+
+
+#if (defined(sun) || defined(vax) || defined(__FreeBSD__))
+/*
+ * Local credential handling stuff.
+ * NOTE: bsd unix dependent.
+ * Other operating systems should put something else here.
+ */
+#define UNKNOWN -2 /* grouplen, if cached cred is unknown user */
+#define INVALID -1 /* grouplen, if cache entry is invalid */
+
+struct bsdcred {
+ uid_t uid; /* cached uid */
+ gid_t gid; /* cached gid */
+ int grouplen; /* length of cached groups */
+ gid_t groups[NGRPS]; /* cached groups */
+};
+
+/*
+ * Map a des credential into a unix cred.
+ * We cache the credential here so the application does
+ * not have to make an rpc call every time to interpret
+ * the credential.
+ */
+int
+authdes_getucred(struct authdes_cred *adc, uid_t *uid, gid_t *gid,
+ int *grouplen, gid_t *groups)
+{
+ unsigned sid;
+ int i;
+ uid_t i_uid;
+ gid_t i_gid;
+ int i_grouplen;
+ struct bsdcred *cred;
+
+ sid = adc->adc_nickname;
+ if (sid >= AUTHDES_CACHESZ) {
+ debug("invalid nickname");
+ return (0);
+ }
+ cred = (struct bsdcred *)authdes_cache[sid].localcred;
+ if (cred == NULL) {
+ cred = (struct bsdcred *)mem_alloc(sizeof(struct bsdcred));
+ authdes_cache[sid].localcred = (char *)cred;
+ cred->grouplen = INVALID;
+ }
+ if (cred->grouplen == INVALID) {
+ /*
+ * not in cache: lookup
+ */
+ if (!netname2user(adc->adc_fullname.name, &i_uid, &i_gid,
+ &i_grouplen, groups))
+ {
+ debug("unknown netname");
+ cred->grouplen = UNKNOWN; /* mark as lookup up, but not found */
+ return (0);
+ }
+ debug("missed ucred cache");
+ *uid = cred->uid = i_uid;
+ *gid = cred->gid = i_gid;
+ *grouplen = cred->grouplen = i_grouplen;
+ for (i = i_grouplen - 1; i >= 0; i--) {
+ cred->groups[i] = groups[i]; /* int to short */
+ }
+ return (1);
+ } else if (cred->grouplen == UNKNOWN) {
+ /*
+ * Already lookup up, but no match found
+ */
+ return (0);
+ }
+
+ /*
+ * cached credentials
+ */
+ *uid = cred->uid;
+ *gid = cred->gid;
+ *grouplen = cred->grouplen;
+ for (i = cred->grouplen - 1; i >= 0; i--) {
+ groups[i] = cred->groups[i]; /* short to int */
+ }
+ return (1);
+}
+
+static void
+invalidate(char *cred)
+{
+ if (cred == NULL) {
+ return;
+ }
+ ((struct bsdcred *)cred)->grouplen = INVALID;
+}
+#endif
+
diff --git a/lib/libc/rpc/svc_auth_unix.c b/lib/libc/rpc/svc_auth_unix.c
new file mode 100644
index 000000000000..8e5118356dcd
--- /dev/null
+++ b/lib/libc/rpc/svc_auth_unix.c
@@ -0,0 +1,151 @@
+/*-
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *sccsid2 = "@(#)svc_auth_unix.c 1.28 88/02/08 Copyr 1984 Sun Micro";
+static char *sccsid = "@(#)svc_auth_unix.c 2.3 88/08/01 4.0 RPCSRC";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * svc_auth_unix.c
+ * Handles UNIX flavor authentication parameters on the service side of rpc.
+ * There are two svc auth implementations here: AUTH_UNIX and AUTH_SHORT.
+ * _svcauth_unix does full blown unix style uid,gid+gids auth,
+ * _svcauth_short uses a shorthand auth to index into a cache of longhand auths.
+ * Note: the shorthand has been gutted for efficiency.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#include "namespace.h"
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <rpc/rpc.h>
+#include "un-namespace.h"
+
+/*
+ * Unix longhand authenticator
+ */
+enum auth_stat
+_svcauth_unix(struct svc_req *rqst, struct rpc_msg *msg)
+{
+ enum auth_stat stat;
+ XDR xdrs;
+ struct authunix_parms *aup;
+ int32_t *buf;
+ struct area {
+ struct authunix_parms area_aup;
+ char area_machname[MAX_MACHINE_NAME+1];
+ u_int area_gids[NGRPS];
+ } *area;
+ u_int auth_len;
+ size_t str_len, gid_len;
+ u_int i;
+
+ assert(rqst != NULL);
+ assert(msg != NULL);
+
+ area = (struct area *) rqst->rq_clntcred;
+ aup = &area->area_aup;
+ aup->aup_machname = area->area_machname;
+ aup->aup_gids = area->area_gids;
+ auth_len = (u_int)msg->rm_call.cb_cred.oa_length;
+ xdrmem_create(&xdrs, msg->rm_call.cb_cred.oa_base, auth_len,XDR_DECODE);
+ buf = XDR_INLINE(&xdrs, auth_len);
+ if (buf != NULL) {
+ aup->aup_time = IXDR_GET_INT32(buf);
+ str_len = (size_t)IXDR_GET_U_INT32(buf);
+ if (str_len > MAX_MACHINE_NAME) {
+ stat = AUTH_BADCRED;
+ goto done;
+ }
+ memmove(aup->aup_machname, buf, str_len);
+ aup->aup_machname[str_len] = 0;
+ str_len = RNDUP(str_len);
+ buf += str_len / sizeof (int32_t);
+ aup->aup_uid = (int)IXDR_GET_INT32(buf);
+ aup->aup_gid = (int)IXDR_GET_INT32(buf);
+ gid_len = (size_t)IXDR_GET_U_INT32(buf);
+ if (gid_len > NGRPS) {
+ stat = AUTH_BADCRED;
+ goto done;
+ }
+ aup->aup_len = gid_len;
+ for (i = 0; i < gid_len; i++) {
+ aup->aup_gids[i] = (int)IXDR_GET_INT32(buf);
+ }
+ /*
+ * five is the smallest unix credentials structure -
+ * timestamp, hostname len (0), uid, gid, and gids len (0).
+ */
+ if ((5 + gid_len) * BYTES_PER_XDR_UNIT + str_len > auth_len) {
+ (void) printf("bad auth_len gid %ld str %ld auth %u\n",
+ (long)gid_len, (long)str_len, auth_len);
+ stat = AUTH_BADCRED;
+ goto done;
+ }
+ } else if (! xdr_authunix_parms(&xdrs, aup)) {
+ xdrs.x_op = XDR_FREE;
+ (void)xdr_authunix_parms(&xdrs, aup);
+ stat = AUTH_BADCRED;
+ goto done;
+ }
+
+ /* get the verifier */
+ if ((u_int)msg->rm_call.cb_verf.oa_length) {
+ rqst->rq_xprt->xp_verf.oa_flavor =
+ msg->rm_call.cb_verf.oa_flavor;
+ rqst->rq_xprt->xp_verf.oa_base =
+ msg->rm_call.cb_verf.oa_base;
+ rqst->rq_xprt->xp_verf.oa_length =
+ msg->rm_call.cb_verf.oa_length;
+ } else {
+ rqst->rq_xprt->xp_verf.oa_flavor = AUTH_NULL;
+ rqst->rq_xprt->xp_verf.oa_length = 0;
+ }
+ stat = AUTH_OK;
+done:
+ XDR_DESTROY(&xdrs);
+ return (stat);
+}
+
+
+/*
+ * Shorthand unix authenticator
+ * Looks up longhand in a cache.
+ */
+/*ARGSUSED*/
+enum auth_stat
+_svcauth_short(struct svc_req *rqst, struct rpc_msg *msg)
+{
+ return (AUTH_REJECTEDCRED);
+}
diff --git a/lib/libc/rpc/svc_dg.c b/lib/libc/rpc/svc_dg.c
new file mode 100644
index 000000000000..5d9baaa81f66
--- /dev/null
+++ b/lib/libc/rpc/svc_dg.c
@@ -0,0 +1,710 @@
+/* $NetBSD: svc_dg.c,v 1.4 2000/07/06 03:10:35 christos Exp $ */
+
+/*-
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 1986-1991 by Sun Microsystems Inc.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+#ident "@(#)svc_dg.c 1.17 94/04/24 SMI"
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * svc_dg.c, Server side for connectionless RPC.
+ *
+ * Does some caching in the hopes of achieving execute-at-most-once semantics.
+ */
+
+#include "namespace.h"
+#include "reentrant.h"
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <rpc/rpc.h>
+#include <rpc/svc_dg.h>
+#include <assert.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef RPC_CACHE_DEBUG
+#include <netconfig.h>
+#include <netdir.h>
+#endif
+#include <err.h>
+#include "un-namespace.h"
+
+#include "rpc_com.h"
+#include "mt_misc.h"
+
+#define su_data(xprt) ((struct svc_dg_data *)(xprt->xp_p2))
+#define rpc_buffer(xprt) ((xprt)->xp_p1)
+
+#ifndef MAX
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+#endif
+
+static void svc_dg_ops(SVCXPRT *);
+static enum xprt_stat svc_dg_stat(SVCXPRT *);
+static bool_t svc_dg_recv(SVCXPRT *, struct rpc_msg *);
+static bool_t svc_dg_reply(SVCXPRT *, struct rpc_msg *);
+static bool_t svc_dg_getargs(SVCXPRT *, xdrproc_t, void *);
+static bool_t svc_dg_freeargs(SVCXPRT *, xdrproc_t, void *);
+static void svc_dg_destroy(SVCXPRT *);
+static bool_t svc_dg_control(SVCXPRT *, const u_int, void *);
+static int cache_get(SVCXPRT *, struct rpc_msg *, char **, size_t *);
+static void cache_set(SVCXPRT *, size_t);
+int svc_dg_enablecache(SVCXPRT *, u_int);
+
+/*
+ * Usage:
+ * xprt = svc_dg_create(sock, sendsize, recvsize);
+ * Does other connectionless specific initializations.
+ * Once *xprt is initialized, it is registered.
+ * see (svc.h, xprt_register). If recvsize or sendsize are 0 suitable
+ * system defaults are chosen.
+ * The routines returns NULL if a problem occurred.
+ */
+static const char svc_dg_str[] = "svc_dg_create: %s";
+static const char svc_dg_err1[] = "could not get transport information";
+static const char svc_dg_err2[] = "transport does not support data transfer";
+static const char svc_dg_err3[] = "getsockname failed";
+static const char svc_dg_err4[] = "cannot set IP_RECVDSTADDR";
+static const char __no_mem_str[] = "out of memory";
+
+SVCXPRT *
+svc_dg_create(int fd, u_int sendsize, u_int recvsize)
+{
+ SVCXPRT *xprt;
+ struct svc_dg_data *su = NULL;
+ struct __rpc_sockinfo si;
+ struct sockaddr_storage ss;
+ socklen_t slen;
+
+ if (!__rpc_fd2sockinfo(fd, &si)) {
+ warnx(svc_dg_str, svc_dg_err1);
+ return (NULL);
+ }
+ /*
+ * Find the receive and the send size
+ */
+ sendsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsize);
+ recvsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsize);
+ if ((sendsize == 0) || (recvsize == 0)) {
+ warnx(svc_dg_str, svc_dg_err2);
+ return (NULL);
+ }
+
+ xprt = svc_xprt_alloc();
+ if (xprt == NULL)
+ goto freedata;
+
+ su = mem_alloc(sizeof (*su));
+ if (su == NULL)
+ goto freedata;
+ su->su_iosz = ((MAX(sendsize, recvsize) + 3) / 4) * 4;
+ if ((rpc_buffer(xprt) = mem_alloc(su->su_iosz)) == NULL)
+ goto freedata;
+ xdrmem_create(&(su->su_xdrs), rpc_buffer(xprt), su->su_iosz,
+ XDR_DECODE);
+ su->su_cache = NULL;
+ xprt->xp_fd = fd;
+ xprt->xp_p2 = su;
+ xprt->xp_verf.oa_base = su->su_verfbody;
+ svc_dg_ops(xprt);
+ xprt->xp_rtaddr.maxlen = sizeof (struct sockaddr_storage);
+
+ slen = sizeof ss;
+ if (_getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) {
+ warnx(svc_dg_str, svc_dg_err3);
+ goto freedata_nowarn;
+ }
+ xprt->xp_ltaddr.buf = mem_alloc(sizeof (struct sockaddr_storage));
+ xprt->xp_ltaddr.maxlen = sizeof (struct sockaddr_storage);
+ xprt->xp_ltaddr.len = slen;
+ memcpy(xprt->xp_ltaddr.buf, &ss, slen);
+
+ if (ss.ss_family == AF_INET) {
+ struct sockaddr_in *sin;
+ static const int true_value = 1;
+
+ sin = (struct sockaddr_in *)(void *)&ss;
+ if (sin->sin_addr.s_addr == INADDR_ANY) {
+ su->su_srcaddr.buf = mem_alloc(sizeof (ss));
+ su->su_srcaddr.maxlen = sizeof (ss);
+
+ if (_setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR,
+ &true_value, sizeof(true_value))) {
+ warnx(svc_dg_str, svc_dg_err4);
+ goto freedata_nowarn;
+ }
+ }
+ }
+
+ xprt_register(xprt);
+ return (xprt);
+freedata:
+ (void) warnx(svc_dg_str, __no_mem_str);
+freedata_nowarn:
+ if (xprt) {
+ if (su)
+ (void) mem_free(su, sizeof (*su));
+ svc_xprt_free(xprt);
+ }
+ return (NULL);
+}
+
+/*ARGSUSED*/
+static enum xprt_stat
+svc_dg_stat(SVCXPRT *xprt)
+{
+ return (XPRT_IDLE);
+}
+
+static int
+svc_dg_recvfrom(int fd, char *buf, int buflen,
+ struct sockaddr *raddr, socklen_t *raddrlen,
+ struct sockaddr *laddr, socklen_t *laddrlen)
+{
+ struct msghdr msg;
+ struct iovec msg_iov[1];
+ struct sockaddr_in *lin = (struct sockaddr_in *)laddr;
+ int rlen;
+ bool_t have_lin = FALSE;
+ char tmp[CMSG_LEN(sizeof(*lin))];
+ struct cmsghdr *cmsg;
+
+ memset((char *)&msg, 0, sizeof(msg));
+ msg_iov[0].iov_base = buf;
+ msg_iov[0].iov_len = buflen;
+ msg.msg_iov = msg_iov;
+ msg.msg_iovlen = 1;
+ msg.msg_namelen = *raddrlen;
+ msg.msg_name = (char *)raddr;
+ if (laddr != NULL) {
+ msg.msg_control = (caddr_t)tmp;
+ msg.msg_controllen = CMSG_LEN(sizeof(*lin));
+ }
+ rlen = _recvmsg(fd, &msg, 0);
+ if (rlen >= 0)
+ *raddrlen = msg.msg_namelen;
+
+ if (rlen == -1 || laddr == NULL ||
+ msg.msg_controllen < sizeof(struct cmsghdr) ||
+ msg.msg_flags & MSG_CTRUNC)
+ return rlen;
+
+ for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
+ cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+ if (cmsg->cmsg_level == IPPROTO_IP &&
+ cmsg->cmsg_type == IP_RECVDSTADDR) {
+ have_lin = TRUE;
+ memcpy(&lin->sin_addr,
+ (struct in_addr *)CMSG_DATA(cmsg),
+ sizeof(struct in_addr));
+ break;
+ }
+ }
+
+ lin->sin_family = AF_INET;
+ lin->sin_port = 0;
+ *laddrlen = sizeof(struct sockaddr_in);
+
+ if (!have_lin)
+ lin->sin_addr.s_addr = INADDR_ANY;
+
+ return rlen;
+}
+
+static bool_t
+svc_dg_recv(SVCXPRT *xprt, struct rpc_msg *msg)
+{
+ struct svc_dg_data *su = su_data(xprt);
+ XDR *xdrs = &(su->su_xdrs);
+ char *reply;
+ struct sockaddr_storage ss;
+ socklen_t alen;
+ size_t replylen;
+ ssize_t rlen;
+
+again:
+ alen = sizeof (struct sockaddr_storage);
+ rlen = svc_dg_recvfrom(xprt->xp_fd, rpc_buffer(xprt), su->su_iosz,
+ (struct sockaddr *)(void *)&ss, &alen,
+ (struct sockaddr *)su->su_srcaddr.buf, &su->su_srcaddr.len);
+ if (rlen == -1 && errno == EINTR)
+ goto again;
+ if (rlen == -1 || (rlen < (ssize_t)(4 * sizeof (u_int32_t))))
+ return (FALSE);
+ if (xprt->xp_rtaddr.len < alen) {
+ if (xprt->xp_rtaddr.len != 0)
+ mem_free(xprt->xp_rtaddr.buf, xprt->xp_rtaddr.len);
+ xprt->xp_rtaddr.buf = mem_alloc(alen);
+ xprt->xp_rtaddr.len = alen;
+ }
+ memcpy(xprt->xp_rtaddr.buf, &ss, alen);
+#ifdef PORTMAP
+ if (ss.ss_family == AF_INET) {
+ xprt->xp_raddr = *(struct sockaddr_in *)xprt->xp_rtaddr.buf;
+ xprt->xp_addrlen = sizeof (struct sockaddr_in);
+ }
+#endif /* PORTMAP */
+ xdrs->x_op = XDR_DECODE;
+ XDR_SETPOS(xdrs, 0);
+ if (! xdr_callmsg(xdrs, msg)) {
+ return (FALSE);
+ }
+ su->su_xid = msg->rm_xid;
+ if (su->su_cache != NULL) {
+ if (cache_get(xprt, msg, &reply, &replylen)) {
+ (void)_sendto(xprt->xp_fd, reply, replylen, 0,
+ (struct sockaddr *)(void *)&ss, alen);
+ return (FALSE);
+ }
+ }
+ return (TRUE);
+}
+
+static int
+svc_dg_sendto(int fd, char *buf, int buflen,
+ const struct sockaddr *raddr, socklen_t raddrlen,
+ const struct sockaddr *laddr, socklen_t laddrlen)
+{
+ struct msghdr msg;
+ struct iovec msg_iov[1];
+ struct sockaddr_in *laddr_in = (struct sockaddr_in *)laddr;
+ struct in_addr *lin = &laddr_in->sin_addr;
+ char tmp[CMSG_SPACE(sizeof(*lin))];
+ struct cmsghdr *cmsg;
+
+ memset((char *)&msg, 0, sizeof(msg));
+ msg_iov[0].iov_base = buf;
+ msg_iov[0].iov_len = buflen;
+ msg.msg_iov = msg_iov;
+ msg.msg_iovlen = 1;
+ msg.msg_namelen = raddrlen;
+ msg.msg_name = (char *)raddr;
+
+ if (laddr != NULL && laddr->sa_family == AF_INET &&
+ lin->s_addr != INADDR_ANY) {
+ msg.msg_control = (caddr_t)tmp;
+ msg.msg_controllen = CMSG_LEN(sizeof(*lin));
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_len = CMSG_LEN(sizeof(*lin));
+ cmsg->cmsg_level = IPPROTO_IP;
+ cmsg->cmsg_type = IP_SENDSRCADDR;
+ memcpy(CMSG_DATA(cmsg), lin, sizeof(*lin));
+ }
+
+ return _sendmsg(fd, &msg, 0);
+}
+
+static bool_t
+svc_dg_reply(SVCXPRT *xprt, struct rpc_msg *msg)
+{
+ struct svc_dg_data *su = su_data(xprt);
+ XDR *xdrs = &(su->su_xdrs);
+ bool_t stat = TRUE;
+ size_t slen;
+ xdrproc_t xdr_proc;
+ caddr_t xdr_where;
+
+ xdrs->x_op = XDR_ENCODE;
+ XDR_SETPOS(xdrs, 0);
+ msg->rm_xid = su->su_xid;
+ if (msg->rm_reply.rp_stat == MSG_ACCEPTED &&
+ msg->rm_reply.rp_acpt.ar_stat == SUCCESS) {
+ xdr_proc = msg->acpted_rply.ar_results.proc;
+ xdr_where = msg->acpted_rply.ar_results.where;
+ msg->acpted_rply.ar_results.proc = (xdrproc_t) xdr_void;
+ msg->acpted_rply.ar_results.where = NULL;
+
+ if (!xdr_replymsg(xdrs, msg) ||
+ !SVCAUTH_WRAP(&SVC_AUTH(xprt), xdrs, xdr_proc, xdr_where))
+ stat = FALSE;
+ } else {
+ stat = xdr_replymsg(xdrs, msg);
+ }
+ if (stat) {
+ slen = XDR_GETPOS(xdrs);
+ if (svc_dg_sendto(xprt->xp_fd, rpc_buffer(xprt), slen,
+ (struct sockaddr *)xprt->xp_rtaddr.buf,
+ (socklen_t)xprt->xp_rtaddr.len,
+ (struct sockaddr *)su->su_srcaddr.buf,
+ (socklen_t)su->su_srcaddr.len) == (ssize_t) slen) {
+ stat = TRUE;
+ if (su->su_cache)
+ cache_set(xprt, slen);
+ }
+ }
+ return (stat);
+}
+
+static bool_t
+svc_dg_getargs(SVCXPRT *xprt, xdrproc_t xdr_args, void *args_ptr)
+{
+ struct svc_dg_data *su;
+
+ assert(xprt != NULL);
+ su = su_data(xprt);
+ return (SVCAUTH_UNWRAP(&SVC_AUTH(xprt),
+ &su->su_xdrs, xdr_args, args_ptr));
+}
+
+static bool_t
+svc_dg_freeargs(SVCXPRT *xprt, xdrproc_t xdr_args, void *args_ptr)
+{
+ XDR *xdrs = &(su_data(xprt)->su_xdrs);
+
+ xdrs->x_op = XDR_FREE;
+ return (*xdr_args)(xdrs, args_ptr);
+}
+
+static void
+svc_dg_destroy(SVCXPRT *xprt)
+{
+ struct svc_dg_data *su = su_data(xprt);
+
+ xprt_unregister(xprt);
+ if (xprt->xp_fd != -1)
+ (void)_close(xprt->xp_fd);
+ XDR_DESTROY(&(su->su_xdrs));
+ (void) mem_free(rpc_buffer(xprt), su->su_iosz);
+ if (su->su_srcaddr.buf)
+ (void) mem_free(su->su_srcaddr.buf, su->su_srcaddr.maxlen);
+ (void) mem_free(su, sizeof (*su));
+ if (xprt->xp_rtaddr.buf)
+ (void) mem_free(xprt->xp_rtaddr.buf, xprt->xp_rtaddr.maxlen);
+ if (xprt->xp_ltaddr.buf)
+ (void) mem_free(xprt->xp_ltaddr.buf, xprt->xp_ltaddr.maxlen);
+ free(xprt->xp_tp);
+ svc_xprt_free(xprt);
+}
+
+static bool_t
+/*ARGSUSED*/
+svc_dg_control(SVCXPRT *xprt, const u_int rq, void *in)
+{
+ return (FALSE);
+}
+
+static void
+svc_dg_ops(SVCXPRT *xprt)
+{
+ static struct xp_ops ops;
+ static struct xp_ops2 ops2;
+
+/* VARIABLES PROTECTED BY ops_lock: ops */
+
+ mutex_lock(&ops_lock);
+ if (ops.xp_recv == NULL) {
+ ops.xp_recv = svc_dg_recv;
+ ops.xp_stat = svc_dg_stat;
+ ops.xp_getargs = svc_dg_getargs;
+ ops.xp_reply = svc_dg_reply;
+ ops.xp_freeargs = svc_dg_freeargs;
+ ops.xp_destroy = svc_dg_destroy;
+ ops2.xp_control = svc_dg_control;
+ }
+ xprt->xp_ops = &ops;
+ xprt->xp_ops2 = &ops2;
+ mutex_unlock(&ops_lock);
+}
+
+/* The CACHING COMPONENT */
+
+/*
+ * Could have been a separate file, but some part of it depends upon the
+ * private structure of the client handle.
+ *
+ * Fifo cache for cl server
+ * Copies pointers to reply buffers into fifo cache
+ * Buffers are sent again if retransmissions are detected.
+ */
+
+#define SPARSENESS 4 /* 75% sparse */
+
+#define ALLOC(type, size) \
+ (type *) mem_alloc((sizeof (type) * (size)))
+
+#define MEMZERO(addr, type, size) \
+ (void) memset((void *) (addr), 0, sizeof (type) * (int) (size))
+
+#define FREE(addr, type, size) \
+ mem_free((addr), (sizeof (type) * (size)))
+
+/*
+ * An entry in the cache
+ */
+typedef struct cache_node *cache_ptr;
+struct cache_node {
+ /*
+ * Index into cache is xid, proc, vers, prog and address
+ */
+ u_int32_t cache_xid;
+ rpcproc_t cache_proc;
+ rpcvers_t cache_vers;
+ rpcprog_t cache_prog;
+ struct netbuf cache_addr;
+ /*
+ * The cached reply and length
+ */
+ char *cache_reply;
+ size_t cache_replylen;
+ /*
+ * Next node on the list, if there is a collision
+ */
+ cache_ptr cache_next;
+};
+
+/*
+ * The entire cache
+ */
+struct cl_cache {
+ u_int uc_size; /* size of cache */
+ cache_ptr *uc_entries; /* hash table of entries in cache */
+ cache_ptr *uc_fifo; /* fifo list of entries in cache */
+ u_int uc_nextvictim; /* points to next victim in fifo list */
+ rpcprog_t uc_prog; /* saved program number */
+ rpcvers_t uc_vers; /* saved version number */
+ rpcproc_t uc_proc; /* saved procedure number */
+};
+
+
+/*
+ * the hashing function
+ */
+#define CACHE_LOC(transp, xid) \
+ (xid % (SPARSENESS * ((struct cl_cache *) \
+ su_data(transp)->su_cache)->uc_size))
+
+/*
+ * Enable use of the cache. Returns 1 on success, 0 on failure.
+ * Note: there is no disable.
+ */
+static const char cache_enable_str[] = "svc_enablecache: %s %s";
+static const char alloc_err[] = "could not allocate cache ";
+static const char enable_err[] = "cache already enabled";
+
+int
+svc_dg_enablecache(SVCXPRT *transp, u_int size)
+{
+ struct svc_dg_data *su = su_data(transp);
+ struct cl_cache *uc;
+
+ mutex_lock(&dupreq_lock);
+ if (su->su_cache != NULL) {
+ (void) warnx(cache_enable_str, enable_err, " ");
+ mutex_unlock(&dupreq_lock);
+ return (0);
+ }
+ uc = ALLOC(struct cl_cache, 1);
+ if (uc == NULL) {
+ warnx(cache_enable_str, alloc_err, " ");
+ mutex_unlock(&dupreq_lock);
+ return (0);
+ }
+ uc->uc_size = size;
+ uc->uc_nextvictim = 0;
+ uc->uc_entries = ALLOC(cache_ptr, size * SPARSENESS);
+ if (uc->uc_entries == NULL) {
+ warnx(cache_enable_str, alloc_err, "data");
+ FREE(uc, struct cl_cache, 1);
+ mutex_unlock(&dupreq_lock);
+ return (0);
+ }
+ MEMZERO(uc->uc_entries, cache_ptr, size * SPARSENESS);
+ uc->uc_fifo = ALLOC(cache_ptr, size);
+ if (uc->uc_fifo == NULL) {
+ warnx(cache_enable_str, alloc_err, "fifo");
+ FREE(uc->uc_entries, cache_ptr, size * SPARSENESS);
+ FREE(uc, struct cl_cache, 1);
+ mutex_unlock(&dupreq_lock);
+ return (0);
+ }
+ MEMZERO(uc->uc_fifo, cache_ptr, size);
+ su->su_cache = (char *)(void *)uc;
+ mutex_unlock(&dupreq_lock);
+ return (1);
+}
+
+/*
+ * Set an entry in the cache. It assumes that the uc entry is set from
+ * the earlier call to cache_get() for the same procedure. This will always
+ * happen because cache_get() is calle by svc_dg_recv and cache_set() is called
+ * by svc_dg_reply(). All this hoopla because the right RPC parameters are
+ * not available at svc_dg_reply time.
+ */
+
+static const char cache_set_str[] = "cache_set: %s";
+static const char cache_set_err1[] = "victim not found";
+static const char cache_set_err2[] = "victim alloc failed";
+static const char cache_set_err3[] = "could not allocate new rpc buffer";
+
+static void
+cache_set(SVCXPRT *xprt, size_t replylen)
+{
+ cache_ptr victim;
+ cache_ptr *vicp;
+ struct svc_dg_data *su = su_data(xprt);
+ struct cl_cache *uc = (struct cl_cache *) su->su_cache;
+ u_int loc;
+ char *newbuf;
+#ifdef RPC_CACHE_DEBUG
+ struct netconfig *nconf;
+ char *uaddr;
+#endif
+
+ mutex_lock(&dupreq_lock);
+ /*
+ * Find space for the new entry, either by
+ * reusing an old entry, or by mallocing a new one
+ */
+ victim = uc->uc_fifo[uc->uc_nextvictim];
+ if (victim != NULL) {
+ loc = CACHE_LOC(xprt, victim->cache_xid);
+ for (vicp = &uc->uc_entries[loc];
+ *vicp != NULL && *vicp != victim;
+ vicp = &(*vicp)->cache_next)
+ ;
+ if (*vicp == NULL) {
+ warnx(cache_set_str, cache_set_err1);
+ mutex_unlock(&dupreq_lock);
+ return;
+ }
+ *vicp = victim->cache_next; /* remove from cache */
+ newbuf = victim->cache_reply;
+ } else {
+ victim = ALLOC(struct cache_node, 1);
+ if (victim == NULL) {
+ warnx(cache_set_str, cache_set_err2);
+ mutex_unlock(&dupreq_lock);
+ return;
+ }
+ newbuf = mem_alloc(su->su_iosz);
+ if (newbuf == NULL) {
+ warnx(cache_set_str, cache_set_err3);
+ FREE(victim, struct cache_node, 1);
+ mutex_unlock(&dupreq_lock);
+ return;
+ }
+ }
+
+ /*
+ * Store it away
+ */
+#ifdef RPC_CACHE_DEBUG
+ if (nconf = getnetconfigent(xprt->xp_netid)) {
+ uaddr = taddr2uaddr(nconf, &xprt->xp_rtaddr);
+ freenetconfigent(nconf);
+ printf(
+ "cache set for xid= %x prog=%d vers=%d proc=%d for rmtaddr=%s\n",
+ su->su_xid, uc->uc_prog, uc->uc_vers,
+ uc->uc_proc, uaddr);
+ free(uaddr);
+ }
+#endif
+ victim->cache_replylen = replylen;
+ victim->cache_reply = rpc_buffer(xprt);
+ rpc_buffer(xprt) = newbuf;
+ xdrmem_create(&(su->su_xdrs), rpc_buffer(xprt),
+ su->su_iosz, XDR_ENCODE);
+ victim->cache_xid = su->su_xid;
+ victim->cache_proc = uc->uc_proc;
+ victim->cache_vers = uc->uc_vers;
+ victim->cache_prog = uc->uc_prog;
+ victim->cache_addr = xprt->xp_rtaddr;
+ victim->cache_addr.buf = ALLOC(char, xprt->xp_rtaddr.len);
+ (void) memcpy(victim->cache_addr.buf, xprt->xp_rtaddr.buf,
+ (size_t)xprt->xp_rtaddr.len);
+ loc = CACHE_LOC(xprt, victim->cache_xid);
+ victim->cache_next = uc->uc_entries[loc];
+ uc->uc_entries[loc] = victim;
+ uc->uc_fifo[uc->uc_nextvictim++] = victim;
+ uc->uc_nextvictim %= uc->uc_size;
+ mutex_unlock(&dupreq_lock);
+}
+
+/*
+ * Try to get an entry from the cache
+ * return 1 if found, 0 if not found and set the stage for cache_set()
+ */
+static int
+cache_get(SVCXPRT *xprt, struct rpc_msg *msg, char **replyp, size_t *replylenp)
+{
+ u_int loc;
+ cache_ptr ent;
+ struct svc_dg_data *su = su_data(xprt);
+ struct cl_cache *uc = (struct cl_cache *) su->su_cache;
+#ifdef RPC_CACHE_DEBUG
+ struct netconfig *nconf;
+ char *uaddr;
+#endif
+
+ mutex_lock(&dupreq_lock);
+ loc = CACHE_LOC(xprt, su->su_xid);
+ for (ent = uc->uc_entries[loc]; ent != NULL; ent = ent->cache_next) {
+ if (ent->cache_xid == su->su_xid &&
+ ent->cache_proc == msg->rm_call.cb_proc &&
+ ent->cache_vers == msg->rm_call.cb_vers &&
+ ent->cache_prog == msg->rm_call.cb_prog &&
+ ent->cache_addr.len == xprt->xp_rtaddr.len &&
+ (memcmp(ent->cache_addr.buf, xprt->xp_rtaddr.buf,
+ xprt->xp_rtaddr.len) == 0)) {
+#ifdef RPC_CACHE_DEBUG
+ if (nconf = getnetconfigent(xprt->xp_netid)) {
+ uaddr = taddr2uaddr(nconf, &xprt->xp_rtaddr);
+ freenetconfigent(nconf);
+ printf(
+ "cache entry found for xid=%x prog=%d vers=%d proc=%d for rmtaddr=%s\n",
+ su->su_xid, msg->rm_call.cb_prog,
+ msg->rm_call.cb_vers,
+ msg->rm_call.cb_proc, uaddr);
+ free(uaddr);
+ }
+#endif
+ *replyp = ent->cache_reply;
+ *replylenp = ent->cache_replylen;
+ mutex_unlock(&dupreq_lock);
+ return (1);
+ }
+ }
+ /*
+ * Failed to find entry
+ * Remember a few things so we can do a set later
+ */
+ uc->uc_proc = msg->rm_call.cb_proc;
+ uc->uc_vers = msg->rm_call.cb_vers;
+ uc->uc_prog = msg->rm_call.cb_prog;
+ mutex_unlock(&dupreq_lock);
+ return (0);
+}
diff --git a/lib/libc/rpc/svc_generic.c b/lib/libc/rpc/svc_generic.c
new file mode 100644
index 000000000000..00bbc5a755fc
--- /dev/null
+++ b/lib/libc/rpc/svc_generic.c
@@ -0,0 +1,316 @@
+/* $NetBSD: svc_generic.c,v 1.3 2000/07/06 03:10:35 christos Exp $ */
+
+/*-
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 1986-1991 by Sun Microsystems Inc.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+#ident "@(#)svc_generic.c 1.19 94/04/24 SMI"
+static char sccsid[] = "@(#)svc_generic.c 1.21 89/02/28 Copyr 1988 Sun Micro";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * svc_generic.c, Server side for RPC.
+ *
+ */
+
+#include "namespace.h"
+#include "reentrant.h"
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <rpc/rpc.h>
+#include <rpc/nettype.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <err.h>
+#include "un-namespace.h"
+
+#include "rpc_com.h"
+#include "mt_misc.h"
+
+extern int __svc_vc_setflag(SVCXPRT *, int);
+
+/*
+ * The highest level interface for server creation.
+ * It tries for all the nettokens in that particular class of token
+ * and returns the number of handles it can create and/or find.
+ *
+ * It creates a link list of all the handles it could create.
+ * If svc_create() is called multiple times, it uses the handle
+ * created earlier instead of creating a new handle every time.
+ *
+ * prognum - Program number
+ * versnum - Version number
+ * nettype - Networktype token
+ */
+int
+svc_create(void (*dispatch)(struct svc_req *, SVCXPRT *),
+ rpcprog_t prognum, rpcvers_t versnum, const char *nettype)
+{
+ struct xlist {
+ SVCXPRT *xprt; /* Server handle */
+ struct xlist *next; /* Next item */
+ } *l;
+ static struct xlist *xprtlist; /* A link list of all the handles */
+ int num = 0;
+ SVCXPRT *xprt;
+ struct netconfig *nconf;
+ void *handle;
+
+/* VARIABLES PROTECTED BY xprtlist_lock: xprtlist */
+
+ if ((handle = __rpc_setconf(nettype)) == NULL) {
+ warnx("svc_create: unknown protocol");
+ return (0);
+ }
+ while ((nconf = __rpc_getconf(handle)) != NULL) {
+ mutex_lock(&xprtlist_lock);
+ for (l = xprtlist; l; l = l->next) {
+ if (strcmp(l->xprt->xp_netid, nconf->nc_netid) == 0) {
+ /* Found an old one, use it */
+ (void) rpcb_unset(prognum, versnum, nconf);
+ if (svc_reg(l->xprt, prognum, versnum,
+ dispatch, nconf) == FALSE)
+ warnx(
+ "svc_create: could not register prog %u vers %u on %s",
+ (unsigned)prognum, (unsigned)versnum,
+ nconf->nc_netid);
+ else
+ num++;
+ break;
+ }
+ }
+ if (l == NULL) {
+ /* It was not found. Now create a new one */
+ xprt = svc_tp_create(dispatch, prognum, versnum, nconf);
+ if (xprt) {
+ l = (struct xlist *)malloc(sizeof (*l));
+ if (l == NULL) {
+ warnx("svc_create: no memory");
+ mutex_unlock(&xprtlist_lock);
+ num = 0;
+ goto done;
+ }
+ l->xprt = xprt;
+ l->next = xprtlist;
+ xprtlist = l;
+ num++;
+ }
+ }
+ mutex_unlock(&xprtlist_lock);
+ }
+done:
+ __rpc_endconf(handle);
+ /*
+ * In case of num == 0; the error messages are generated by the
+ * underlying layers; and hence not needed here.
+ */
+ return (num);
+}
+
+/*
+ * The high level interface to svc_tli_create().
+ * It tries to create a server for "nconf" and registers the service
+ * with the rpcbind. It calls svc_tli_create();
+ *
+ * prognum - Program number
+ * versnum - Version number
+ * ncofn - Netconfig structure for the network
+ */
+SVCXPRT *
+svc_tp_create(void (*dispatch)(struct svc_req *, SVCXPRT *),
+ rpcprog_t prognum, rpcvers_t versnum, const struct netconfig *nconf)
+{
+ SVCXPRT *xprt;
+
+ if (nconf == NULL) {
+ warnx(
+ "svc_tp_create: invalid netconfig structure for prog %u vers %u",
+ (unsigned)prognum, (unsigned)versnum);
+ return (NULL);
+ }
+ xprt = svc_tli_create(RPC_ANYFD, nconf, NULL, 0, 0);
+ if (xprt == NULL) {
+ return (NULL);
+ }
+ /*LINTED const castaway*/
+ (void) rpcb_unset(prognum, versnum, (struct netconfig *) nconf);
+ if (svc_reg(xprt, prognum, versnum, dispatch, nconf) == FALSE) {
+ warnx(
+ "svc_tp_create: Could not register prog %u vers %u on %s",
+ (unsigned)prognum, (unsigned)versnum,
+ nconf->nc_netid);
+ SVC_DESTROY(xprt);
+ return (NULL);
+ }
+ return (xprt);
+}
+
+/*
+ * If fd is RPC_ANYFD, then it opens a fd for the given transport
+ * provider (nconf cannot be NULL then). If the t_state is T_UNBND and
+ * bindaddr is NON-NULL, it performs a t_bind using the bindaddr. For
+ * NULL bindadr and Connection oriented transports, the value of qlen
+ * is set to 8.
+ *
+ * If sendsz or recvsz are zero, their default values are chosen.
+ *
+ * fd - Connection end point
+ * nconf - Netconfig struct for nettoken
+ * bindaddr - Local bind address
+ * sendsz - Max sendsize
+ * recvxz - Max recvsize
+ */
+SVCXPRT *
+svc_tli_create(int fd, const struct netconfig *nconf,
+ const struct t_bind *bindaddr, u_int sendsz, u_int recvsz)
+{
+ SVCXPRT *xprt = NULL; /* service handle */
+ bool_t madefd = FALSE; /* whether fd opened here */
+ struct __rpc_sockinfo si;
+ struct sockaddr_storage ss;
+ socklen_t slen;
+
+ if (fd == RPC_ANYFD) {
+ if (nconf == NULL) {
+ warnx("svc_tli_create: invalid netconfig");
+ return (NULL);
+ }
+ fd = __rpc_nconf2fd(nconf);
+ if (fd == -1) {
+ warnx(
+ "svc_tli_create: could not open connection for %s",
+ nconf->nc_netid);
+ return (NULL);
+ }
+ __rpc_nconf2sockinfo(nconf, &si);
+ madefd = TRUE;
+ } else {
+ /*
+ * It is an open descriptor. Get the transport info.
+ */
+ if (!__rpc_fd2sockinfo(fd, &si)) {
+ warnx(
+ "svc_tli_create: could not get transport information");
+ return (NULL);
+ }
+ }
+
+ /*
+ * If the fd is unbound, try to bind it.
+ */
+ if (madefd || !__rpc_sockisbound(fd)) {
+ if (bindaddr == NULL) {
+ if (bindresvport(fd, NULL) < 0) {
+ memset(&ss, 0, sizeof ss);
+ ss.ss_family = si.si_af;
+ ss.ss_len = si.si_alen;
+ if (_bind(fd, (struct sockaddr *)(void *)&ss,
+ (socklen_t)si.si_alen) < 0) {
+ warnx(
+ "svc_tli_create: could not bind to anonymous port");
+ goto freedata;
+ }
+ }
+ _listen(fd, SOMAXCONN);
+ } else {
+ if (_bind(fd,
+ (struct sockaddr *)bindaddr->addr.buf,
+ (socklen_t)si.si_alen) < 0) {
+ warnx(
+ "svc_tli_create: could not bind to requested address");
+ goto freedata;
+ }
+ _listen(fd, (int)bindaddr->qlen);
+ }
+
+ }
+ /*
+ * call transport specific function.
+ */
+ switch (si.si_socktype) {
+ case SOCK_STREAM:
+ slen = sizeof ss;
+ if (_getpeername(fd, (struct sockaddr *)(void *)&ss, &slen)
+ == 0) {
+ /* accepted socket */
+ xprt = svc_fd_create(fd, sendsz, recvsz);
+ } else
+ xprt = svc_vc_create(fd, sendsz, recvsz);
+ if (!nconf || !xprt)
+ break;
+#if 0
+ /* XXX fvdl */
+ if (strcmp(nconf->nc_protofmly, "inet") == 0 ||
+ strcmp(nconf->nc_protofmly, "inet6") == 0)
+ (void) __svc_vc_setflag(xprt, TRUE);
+#endif
+ break;
+ case SOCK_DGRAM:
+ xprt = svc_dg_create(fd, sendsz, recvsz);
+ break;
+ default:
+ warnx("svc_tli_create: bad service type");
+ goto freedata;
+ }
+
+ if (xprt == NULL)
+ /*
+ * The error messages here are spitted out by the lower layers:
+ * svc_vc_create(), svc_fd_create() and svc_dg_create().
+ */
+ goto freedata;
+
+ /* Fill in type of service */
+ xprt->xp_type = __rpc_socktype2seman(si.si_socktype);
+
+ if (nconf) {
+ xprt->xp_netid = strdup(nconf->nc_netid);
+ xprt->xp_tp = strdup(nconf->nc_device);
+ }
+ return (xprt);
+
+freedata:
+ if (madefd)
+ (void)_close(fd);
+ if (xprt) {
+ if (!madefd) /* so that svc_destroy doesnt close fd */
+ xprt->xp_fd = RPC_ANYFD;
+ SVC_DESTROY(xprt);
+ }
+ return (NULL);
+}
diff --git a/lib/libc/rpc/svc_raw.c b/lib/libc/rpc/svc_raw.c
new file mode 100644
index 000000000000..91593350453c
--- /dev/null
+++ b/lib/libc/rpc/svc_raw.c
@@ -0,0 +1,269 @@
+/* $NetBSD: svc_raw.c,v 1.14 2000/07/06 03:10:35 christos Exp $ */
+
+/*-
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 1986-1991 by Sun Microsystems Inc.
+ */
+
+/* #ident "@(#)svc_raw.c 1.16 94/04/24 SMI" */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)svc_raw.c 1.25 89/01/31 Copyr 1984 Sun Micro";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * svc_raw.c, This a toy for simple testing and timing.
+ * Interface to create an rpc client and server in the same UNIX process.
+ * This lets us similate rpc and get rpc (round trip) overhead, without
+ * any interference from the kernel.
+ *
+ */
+
+#include "namespace.h"
+#include "reentrant.h"
+#include <rpc/rpc.h>
+#include <sys/types.h>
+#include <rpc/raw.h>
+#include <stdlib.h>
+#include "un-namespace.h"
+#include "mt_misc.h"
+
+#ifndef UDPMSGSIZE
+#define UDPMSGSIZE 8800
+#endif
+
+/*
+ * This is the "network" that we will be moving data over
+ */
+static struct svc_raw_private {
+ char *raw_buf; /* should be shared with the cl handle */
+ SVCXPRT *server;
+ XDR xdr_stream;
+ char verf_body[MAX_AUTH_BYTES];
+} *svc_raw_private;
+
+static enum xprt_stat svc_raw_stat(SVCXPRT *);
+static bool_t svc_raw_recv(SVCXPRT *, struct rpc_msg *);
+static bool_t svc_raw_reply(SVCXPRT *, struct rpc_msg *);
+static bool_t svc_raw_getargs(SVCXPRT *, xdrproc_t, void *);
+static bool_t svc_raw_freeargs(SVCXPRT *, xdrproc_t, void *);
+static void svc_raw_destroy(SVCXPRT *);
+static void svc_raw_ops(SVCXPRT *);
+static bool_t svc_raw_control(SVCXPRT *, const u_int, void *);
+
+char *__rpc_rawcombuf = NULL;
+
+SVCXPRT *
+svc_raw_create(void)
+{
+ struct svc_raw_private *srp;
+/* VARIABLES PROTECTED BY svcraw_lock: svc_raw_private, srp */
+
+ mutex_lock(&svcraw_lock);
+ srp = svc_raw_private;
+ if (srp == NULL) {
+ srp = (struct svc_raw_private *)calloc(1, sizeof (*srp));
+ if (srp == NULL) {
+ mutex_unlock(&svcraw_lock);
+ return (NULL);
+ }
+ if (__rpc_rawcombuf == NULL) {
+ __rpc_rawcombuf = calloc(UDPMSGSIZE, sizeof (char));
+ if (__rpc_rawcombuf == NULL) {
+ free(srp);
+ mutex_unlock(&svcraw_lock);
+ return (NULL);
+ }
+ }
+ srp->raw_buf = __rpc_rawcombuf; /* Share it with the client */
+ srp->server = svc_xprt_alloc();
+ if (srp->server == NULL) {
+ free(__rpc_rawcombuf);
+ free(srp);
+ mutex_unlock(&svcraw_lock);
+ return (NULL);
+ }
+ svc_raw_private = srp;
+ }
+ srp->server->xp_fd = FD_SETSIZE;
+ srp->server->xp_port = 0;
+ svc_raw_ops(srp->server);
+ srp->server->xp_verf.oa_base = srp->verf_body;
+ xdrmem_create(&srp->xdr_stream, srp->raw_buf, UDPMSGSIZE, XDR_DECODE);
+ xprt_register(srp->server);
+ mutex_unlock(&svcraw_lock);
+ return (srp->server);
+}
+
+/*ARGSUSED*/
+static enum xprt_stat
+svc_raw_stat(SVCXPRT *xprt)
+{
+ return (XPRT_IDLE);
+}
+
+/*ARGSUSED*/
+static bool_t
+svc_raw_recv(SVCXPRT *xprt, struct rpc_msg *msg)
+{
+ struct svc_raw_private *srp;
+ XDR *xdrs;
+
+ mutex_lock(&svcraw_lock);
+ srp = svc_raw_private;
+ if (srp == NULL) {
+ mutex_unlock(&svcraw_lock);
+ return (FALSE);
+ }
+ mutex_unlock(&svcraw_lock);
+
+ xdrs = &srp->xdr_stream;
+ xdrs->x_op = XDR_DECODE;
+ (void) XDR_SETPOS(xdrs, 0);
+ if (! xdr_callmsg(xdrs, msg)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+/*ARGSUSED*/
+static bool_t
+svc_raw_reply(SVCXPRT *xprt, struct rpc_msg *msg)
+{
+ struct svc_raw_private *srp;
+ XDR *xdrs;
+ bool_t stat;
+ xdrproc_t xdr_proc;
+ caddr_t xdr_where;
+
+ mutex_lock(&svcraw_lock);
+ srp = svc_raw_private;
+ if (srp == NULL) {
+ mutex_unlock(&svcraw_lock);
+ return (FALSE);
+ }
+ mutex_unlock(&svcraw_lock);
+
+ xdrs = &srp->xdr_stream;
+ xdrs->x_op = XDR_ENCODE;
+ (void) XDR_SETPOS(xdrs, 0);
+ if (msg->rm_reply.rp_stat == MSG_ACCEPTED &&
+ msg->rm_reply.rp_acpt.ar_stat == SUCCESS) {
+ xdr_proc = msg->acpted_rply.ar_results.proc;
+ xdr_where = msg->acpted_rply.ar_results.where;
+ msg->acpted_rply.ar_results.proc = (xdrproc_t) xdr_void;
+ msg->acpted_rply.ar_results.where = NULL;
+
+ stat = xdr_replymsg(xdrs, msg) &&
+ SVCAUTH_WRAP(&SVC_AUTH(xprt), xdrs, xdr_proc, xdr_where);
+ } else {
+ stat = xdr_replymsg(xdrs, msg);
+ }
+ if (!stat) {
+ return (FALSE);
+ }
+ (void) XDR_GETPOS(xdrs); /* called just for overhead */
+ return (TRUE);
+}
+
+/*ARGSUSED*/
+static bool_t
+svc_raw_getargs(SVCXPRT *xprt, xdrproc_t xdr_args, void *args_ptr)
+{
+ struct svc_raw_private *srp;
+
+ mutex_lock(&svcraw_lock);
+ srp = svc_raw_private;
+ if (srp == NULL) {
+ mutex_unlock(&svcraw_lock);
+ return (FALSE);
+ }
+ mutex_unlock(&svcraw_lock);
+
+ return (SVCAUTH_UNWRAP(&SVC_AUTH(xprt), &srp->xdr_stream,
+ xdr_args, args_ptr));
+}
+
+/*ARGSUSED*/
+static bool_t
+svc_raw_freeargs(SVCXPRT *xprt, xdrproc_t xdr_args, void *args_ptr)
+{
+ struct svc_raw_private *srp;
+ XDR *xdrs;
+
+ mutex_lock(&svcraw_lock);
+ srp = svc_raw_private;
+ if (srp == NULL) {
+ mutex_unlock(&svcraw_lock);
+ return (FALSE);
+ }
+ mutex_unlock(&svcraw_lock);
+
+ xdrs = &srp->xdr_stream;
+ xdrs->x_op = XDR_FREE;
+ return (*xdr_args)(xdrs, args_ptr);
+}
+
+/*ARGSUSED*/
+static void
+svc_raw_destroy(SVCXPRT *xprt)
+{
+}
+
+/*ARGSUSED*/
+static bool_t
+svc_raw_control(SVCXPRT *xprt, const u_int rq, void *in)
+{
+ return (FALSE);
+}
+
+static void
+svc_raw_ops(SVCXPRT *xprt)
+{
+ static struct xp_ops ops;
+ static struct xp_ops2 ops2;
+
+/* VARIABLES PROTECTED BY ops_lock: ops */
+
+ mutex_lock(&ops_lock);
+ if (ops.xp_recv == NULL) {
+ ops.xp_recv = svc_raw_recv;
+ ops.xp_stat = svc_raw_stat;
+ ops.xp_getargs = svc_raw_getargs;
+ ops.xp_reply = svc_raw_reply;
+ ops.xp_freeargs = svc_raw_freeargs;
+ ops.xp_destroy = svc_raw_destroy;
+ ops2.xp_control = svc_raw_control;
+ }
+ xprt->xp_ops = &ops;
+ xprt->xp_ops2 = &ops2;
+ mutex_unlock(&ops_lock);
+}
diff --git a/lib/libc/rpc/svc_run.c b/lib/libc/rpc/svc_run.c
new file mode 100644
index 000000000000..9b0089b3dd3f
--- /dev/null
+++ b/lib/libc/rpc/svc_run.c
@@ -0,0 +1,97 @@
+/* $NetBSD: svc_run.c,v 1.17 2000/07/06 03:10:35 christos Exp $ */
+
+/*-
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *sccsid2 = "from: @(#)svc_run.c 1.1 87/10/13 Copyr 1984 Sun Micro";
+static char *sccsid = "from: @(#)svc_run.c 2.1 88/07/29 4.0 RPCSRC";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * This is the rpc server side idle loop
+ * Wait for input, call server program.
+ */
+#include "namespace.h"
+#include "reentrant.h"
+#include <err.h>
+#include <errno.h>
+#include <rpc/rpc.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+#include <rpc/rpc.h>
+#include "rpc_com.h"
+#include "mt_misc.h"
+
+void
+svc_run(void)
+{
+ fd_set readfds, cleanfds;
+ struct timeval timeout;
+
+ timeout.tv_sec = 30;
+ timeout.tv_usec = 0;
+
+ for (;;) {
+ rwlock_rdlock(&svc_fd_lock);
+ readfds = svc_fdset;
+ cleanfds = svc_fdset;
+ rwlock_unlock(&svc_fd_lock);
+ switch (_select(svc_maxfd+1, &readfds, NULL, NULL, &timeout)) {
+ case -1:
+ FD_ZERO(&readfds);
+ if (errno == EINTR) {
+ continue;
+ }
+ _warn("svc_run: - select failed");
+ return;
+ case 0:
+ __svc_clean_idle(&cleanfds, 30, FALSE);
+ continue;
+ default:
+ svc_getreqset(&readfds);
+ }
+ }
+}
+
+/*
+ * This function causes svc_run() to exit by telling it that it has no
+ * more work to do.
+ */
+void
+svc_exit(void)
+{
+ rwlock_wrlock(&svc_fd_lock);
+ FD_ZERO(&svc_fdset);
+ rwlock_unlock(&svc_fd_lock);
+}
diff --git a/lib/libc/rpc/svc_simple.c b/lib/libc/rpc/svc_simple.c
new file mode 100644
index 000000000000..46ada7747659
--- /dev/null
+++ b/lib/libc/rpc/svc_simple.c
@@ -0,0 +1,310 @@
+/* $NetBSD: svc_simple.c,v 1.20 2000/07/06 03:10:35 christos Exp $ */
+
+/*-
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 1986-1991 by Sun Microsystems Inc.
+ */
+
+/* #pragma ident "@(#)svc_simple.c 1.18 94/04/24 SMI" */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * svc_simple.c
+ * Simplified front end to rpc.
+ */
+
+/*
+ * This interface creates a virtual listener for all the services
+ * started through rpc_reg(). It listens on the same endpoint for
+ * all the services and then executes the corresponding service
+ * for the given prognum and procnum.
+ */
+
+#include "namespace.h"
+#include "reentrant.h"
+#include <sys/types.h>
+#include <rpc/rpc.h>
+#include <rpc/nettype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <err.h>
+#include "un-namespace.h"
+
+#include "rpc_com.h"
+#include "mt_misc.h"
+
+static void universal(struct svc_req *, SVCXPRT *);
+
+static struct proglst {
+ char *(*p_progname)(char *);
+ rpcprog_t p_prognum;
+ rpcvers_t p_versnum;
+ rpcproc_t p_procnum;
+ SVCXPRT *p_transp;
+ char *p_netid;
+ char *p_xdrbuf;
+ int p_recvsz;
+ xdrproc_t p_inproc, p_outproc;
+ struct proglst *p_nxt;
+} *proglst;
+
+static const char rpc_reg_err[] = "%s: %s";
+static const char rpc_reg_msg[] = "rpc_reg: ";
+static const char __reg_err1[] = "can't find appropriate transport";
+static const char __reg_err2[] = "can't get protocol info";
+static const char __reg_err3[] = "unsupported transport size";
+static const char __no_mem_str[] = "out of memory";
+
+/*
+ * For simplified, easy to use kind of rpc interfaces.
+ * nettype indicates the type of transport on which the service will be
+ * listening. Used for conservation of the system resource. Only one
+ * handle is created for all the services (actually one of each netid)
+ * and same xdrbuf is used for same netid. The size of the arguments
+ * is also limited by the recvsize for that transport, even if it is
+ * a COTS transport. This may be wrong, but for cases like these, they
+ * should not use the simplified interfaces like this.
+ *
+ * prognum - program number
+ * versnum - version number
+ * procnum - procedure number
+ * progname - Server routine
+ * inproc, outproc - in/out XDR procedures
+ * nettype - nettype
+ */
+int
+rpc_reg(rpcprog_t prognum, rpcvers_t versnum, rpcproc_t procnum,
+ char *(*progname)(char *), xdrproc_t inproc, xdrproc_t outproc,
+ char *nettype)
+{
+ struct netconfig *nconf;
+ int done = FALSE;
+ void *handle;
+
+
+ if (procnum == NULLPROC) {
+ warnx("%s can't reassign procedure number %u", rpc_reg_msg,
+ NULLPROC);
+ return (-1);
+ }
+
+ if (nettype == NULL)
+ nettype = "netpath"; /* The default behavior */
+ if ((handle = __rpc_setconf(nettype)) == NULL) {
+ warnx(rpc_reg_err, rpc_reg_msg, __reg_err1);
+ return (-1);
+ }
+/* VARIABLES PROTECTED BY proglst_lock: proglst */
+ mutex_lock(&proglst_lock);
+ while ((nconf = __rpc_getconf(handle)) != NULL) {
+ struct proglst *pl;
+ SVCXPRT *svcxprt;
+ int madenow;
+ u_int recvsz;
+ char *xdrbuf;
+ char *netid;
+
+ madenow = FALSE;
+ svcxprt = NULL;
+ recvsz = 0;
+ xdrbuf = netid = NULL;
+ for (pl = proglst; pl; pl = pl->p_nxt) {
+ if (strcmp(pl->p_netid, nconf->nc_netid) == 0) {
+ svcxprt = pl->p_transp;
+ xdrbuf = pl->p_xdrbuf;
+ recvsz = pl->p_recvsz;
+ netid = pl->p_netid;
+ break;
+ }
+ }
+
+ if (svcxprt == NULL) {
+ struct __rpc_sockinfo si;
+
+ svcxprt = svc_tli_create(RPC_ANYFD, nconf, NULL, 0, 0);
+ if (svcxprt == NULL)
+ continue;
+ if (!__rpc_fd2sockinfo(svcxprt->xp_fd, &si)) {
+ warnx(rpc_reg_err, rpc_reg_msg, __reg_err2);
+ SVC_DESTROY(svcxprt);
+ continue;
+ }
+ recvsz = __rpc_get_t_size(si.si_af, si.si_proto, 0);
+ if (recvsz == 0) {
+ warnx(rpc_reg_err, rpc_reg_msg, __reg_err3);
+ SVC_DESTROY(svcxprt);
+ continue;
+ }
+ if (((xdrbuf = malloc((unsigned)recvsz)) == NULL) ||
+ ((netid = strdup(nconf->nc_netid)) == NULL)) {
+ warnx(rpc_reg_err, rpc_reg_msg, __no_mem_str);
+ free(xdrbuf);
+ free(netid);
+ SVC_DESTROY(svcxprt);
+ break;
+ }
+ madenow = TRUE;
+ }
+ /*
+ * Check if this (program, version, netid) had already been
+ * registered. The check may save a few RPC calls to rpcbind
+ */
+ for (pl = proglst; pl; pl = pl->p_nxt)
+ if ((pl->p_prognum == prognum) &&
+ (pl->p_versnum == versnum) &&
+ (strcmp(pl->p_netid, netid) == 0))
+ break;
+ if (pl == NULL) { /* Not yet */
+ (void) rpcb_unset(prognum, versnum, nconf);
+ } else {
+ /* so that svc_reg does not call rpcb_set() */
+ nconf = NULL;
+ }
+
+ if (!svc_reg(svcxprt, prognum, versnum, universal, nconf)) {
+ warnx("%s couldn't register prog %u vers %u for %s",
+ rpc_reg_msg, (unsigned)prognum,
+ (unsigned)versnum, netid);
+ if (madenow) {
+ SVC_DESTROY(svcxprt);
+ free(xdrbuf);
+ free(netid);
+ }
+ continue;
+ }
+
+ pl = malloc(sizeof (struct proglst));
+ if (pl == NULL) {
+ warnx(rpc_reg_err, rpc_reg_msg, __no_mem_str);
+ if (madenow) {
+ SVC_DESTROY(svcxprt);
+ free(xdrbuf);
+ free(netid);
+ }
+ break;
+ }
+ pl->p_progname = progname;
+ pl->p_prognum = prognum;
+ pl->p_versnum = versnum;
+ pl->p_procnum = procnum;
+ pl->p_inproc = inproc;
+ pl->p_outproc = outproc;
+ pl->p_transp = svcxprt;
+ pl->p_xdrbuf = xdrbuf;
+ pl->p_recvsz = recvsz;
+ pl->p_netid = netid;
+ pl->p_nxt = proglst;
+ proglst = pl;
+ done = TRUE;
+ }
+ __rpc_endconf(handle);
+ mutex_unlock(&proglst_lock);
+
+ if (done == FALSE) {
+ warnx("%s can't find suitable transport for %s",
+ rpc_reg_msg, nettype);
+ return (-1);
+ }
+ return (0);
+}
+
+/*
+ * The universal handler for the services registered using registerrpc.
+ * It handles both the connectionless and the connection oriented cases.
+ */
+
+static void
+universal(struct svc_req *rqstp, SVCXPRT *transp)
+{
+ rpcprog_t prog;
+ rpcvers_t vers;
+ rpcproc_t proc;
+ char *outdata;
+ char *xdrbuf;
+ struct proglst *pl;
+
+ /*
+ * enforce "procnum 0 is echo" convention
+ */
+ if (rqstp->rq_proc == NULLPROC) {
+ if (svc_sendreply(transp, (xdrproc_t) xdr_void, NULL) ==
+ FALSE) {
+ warnx("svc_sendreply failed");
+ }
+ return;
+ }
+ prog = rqstp->rq_prog;
+ vers = rqstp->rq_vers;
+ proc = rqstp->rq_proc;
+ mutex_lock(&proglst_lock);
+ for (pl = proglst; pl; pl = pl->p_nxt)
+ if (pl->p_prognum == prog && pl->p_procnum == proc &&
+ pl->p_versnum == vers &&
+ (strcmp(pl->p_netid, transp->xp_netid) == 0)) {
+ /* decode arguments into a CLEAN buffer */
+ xdrbuf = pl->p_xdrbuf;
+ /* Zero the arguments: reqd ! */
+ (void) memset(xdrbuf, 0, (size_t)pl->p_recvsz);
+ /*
+ * Assuming that sizeof (xdrbuf) would be enough
+ * for the arguments; if not then the program
+ * may bomb. BEWARE!
+ */
+ if (!svc_getargs(transp, pl->p_inproc, xdrbuf)) {
+ svcerr_decode(transp);
+ mutex_unlock(&proglst_lock);
+ return;
+ }
+ outdata = (*(pl->p_progname))(xdrbuf);
+ if (outdata == NULL &&
+ pl->p_outproc != (xdrproc_t) xdr_void){
+ /* there was an error */
+ mutex_unlock(&proglst_lock);
+ return;
+ }
+ if (!svc_sendreply(transp, pl->p_outproc, outdata)) {
+ warnx(
+ "rpc: rpc_reg trouble replying to prog %u vers %u",
+ (unsigned)prog, (unsigned)vers);
+ mutex_unlock(&proglst_lock);
+ return;
+ }
+ /* free the decoded arguments */
+ (void)svc_freeargs(transp, pl->p_inproc, xdrbuf);
+ mutex_unlock(&proglst_lock);
+ return;
+ }
+ mutex_unlock(&proglst_lock);
+ /* This should never happen */
+ warnx("rpc: rpc_reg: never registered prog %u vers %u",
+ (unsigned)prog, (unsigned)vers);
+ return;
+}
diff --git a/lib/libc/rpc/svc_vc.c b/lib/libc/rpc/svc_vc.c
new file mode 100644
index 000000000000..a35ee6281d77
--- /dev/null
+++ b/lib/libc/rpc/svc_vc.c
@@ -0,0 +1,782 @@
+/* $NetBSD: svc_vc.c,v 1.7 2000/08/03 00:01:53 fvdl Exp $ */
+
+/*-
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *sccsid2 = "@(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro";
+static char *sccsid = "@(#)svc_tcp.c 2.2 88/08/01 4.0 RPCSRC";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * svc_vc.c, Server side for Connection Oriented based RPC.
+ *
+ * Actually implements two flavors of transporter -
+ * a tcp rendezvouser (a listner and connection establisher)
+ * and a record/tcp stream.
+ */
+
+#include "namespace.h"
+#include "reentrant.h"
+#include <sys/param.h>
+#include <sys/poll.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/time.h>
+#include <sys/uio.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+
+#include <assert.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <rpc/rpc.h>
+
+#include "rpc_com.h"
+#include "mt_misc.h"
+#include "un-namespace.h"
+
+static SVCXPRT *makefd_xprt(int, u_int, u_int);
+static bool_t rendezvous_request(SVCXPRT *, struct rpc_msg *);
+static enum xprt_stat rendezvous_stat(SVCXPRT *);
+static void svc_vc_destroy(SVCXPRT *);
+static void __svc_vc_dodestroy (SVCXPRT *);
+static int read_vc(void *, void *, int);
+static int write_vc(void *, void *, int);
+static enum xprt_stat svc_vc_stat(SVCXPRT *);
+static bool_t svc_vc_recv(SVCXPRT *, struct rpc_msg *);
+static bool_t svc_vc_getargs(SVCXPRT *, xdrproc_t, void *);
+static bool_t svc_vc_freeargs(SVCXPRT *, xdrproc_t, void *);
+static bool_t svc_vc_reply(SVCXPRT *, struct rpc_msg *);
+static void svc_vc_rendezvous_ops(SVCXPRT *);
+static void svc_vc_ops(SVCXPRT *);
+static bool_t svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in);
+static bool_t svc_vc_rendezvous_control (SVCXPRT *xprt, const u_int rq,
+ void *in);
+
+struct cf_rendezvous { /* kept in xprt->xp_p1 for rendezvouser */
+ u_int sendsize;
+ u_int recvsize;
+ int maxrec;
+};
+
+struct cf_conn { /* kept in xprt->xp_p1 for actual connection */
+ enum xprt_stat strm_stat;
+ u_int32_t x_id;
+ XDR xdrs;
+ char verf_body[MAX_AUTH_BYTES];
+ u_int sendsize;
+ u_int recvsize;
+ int maxrec;
+ bool_t nonblock;
+ struct timeval last_recv_time;
+};
+
+/*
+ * Usage:
+ * xprt = svc_vc_create(sock, send_buf_size, recv_buf_size);
+ *
+ * Creates, registers, and returns a (rpc) tcp based transporter.
+ * Once *xprt is initialized, it is registered as a transporter
+ * see (svc.h, xprt_register). This routine returns
+ * a NULL if a problem occurred.
+ *
+ * The filedescriptor passed in is expected to refer to a bound, but
+ * not yet connected socket.
+ *
+ * Since streams do buffered io similar to stdio, the caller can specify
+ * how big the send and receive buffers are via the second and third parms;
+ * 0 => use the system default.
+ */
+SVCXPRT *
+svc_vc_create(int fd, u_int sendsize, u_int recvsize)
+{
+ SVCXPRT *xprt = NULL;
+ struct cf_rendezvous *r = NULL;
+ struct __rpc_sockinfo si;
+ struct sockaddr_storage sslocal;
+ socklen_t slen;
+
+ if (!__rpc_fd2sockinfo(fd, &si))
+ return NULL;
+
+ r = mem_alloc(sizeof(*r));
+ if (r == NULL) {
+ warnx("svc_vc_create: out of memory");
+ goto cleanup_svc_vc_create;
+ }
+ r->sendsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsize);
+ r->recvsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsize);
+ r->maxrec = __svc_maxrec;
+ xprt = svc_xprt_alloc();
+ if (xprt == NULL) {
+ warnx("svc_vc_create: out of memory");
+ goto cleanup_svc_vc_create;
+ }
+ xprt->xp_p1 = r;
+ xprt->xp_verf = _null_auth;
+ svc_vc_rendezvous_ops(xprt);
+ xprt->xp_port = (u_short)-1; /* It is the rendezvouser */
+ xprt->xp_fd = fd;
+
+ slen = sizeof (struct sockaddr_storage);
+ if (_getsockname(fd, (struct sockaddr *)(void *)&sslocal, &slen) < 0) {
+ warnx("svc_vc_create: could not retrieve local addr");
+ goto cleanup_svc_vc_create;
+ }
+
+ xprt->xp_ltaddr.maxlen = xprt->xp_ltaddr.len = sslocal.ss_len;
+ xprt->xp_ltaddr.buf = mem_alloc((size_t)sslocal.ss_len);
+ if (xprt->xp_ltaddr.buf == NULL) {
+ warnx("svc_vc_create: no mem for local addr");
+ goto cleanup_svc_vc_create;
+ }
+ memcpy(xprt->xp_ltaddr.buf, &sslocal, (size_t)sslocal.ss_len);
+
+ xprt->xp_rtaddr.maxlen = sizeof (struct sockaddr_storage);
+ xprt_register(xprt);
+ return (xprt);
+cleanup_svc_vc_create:
+ if (xprt)
+ mem_free(xprt, sizeof(*xprt));
+ if (r != NULL)
+ mem_free(r, sizeof(*r));
+ return (NULL);
+}
+
+/*
+ * Like svtcp_create(), except the routine takes any *open* UNIX file
+ * descriptor as its first input.
+ */
+SVCXPRT *
+svc_fd_create(int fd, u_int sendsize, u_int recvsize)
+{
+ struct sockaddr_storage ss;
+ socklen_t slen;
+ SVCXPRT *ret;
+
+ assert(fd != -1);
+
+ ret = makefd_xprt(fd, sendsize, recvsize);
+ if (ret == NULL)
+ return NULL;
+
+ slen = sizeof (struct sockaddr_storage);
+ if (_getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) {
+ warnx("svc_fd_create: could not retrieve local addr");
+ goto freedata;
+ }
+ ret->xp_ltaddr.maxlen = ret->xp_ltaddr.len = ss.ss_len;
+ ret->xp_ltaddr.buf = mem_alloc((size_t)ss.ss_len);
+ if (ret->xp_ltaddr.buf == NULL) {
+ warnx("svc_fd_create: no mem for local addr");
+ goto freedata;
+ }
+ memcpy(ret->xp_ltaddr.buf, &ss, (size_t)ss.ss_len);
+
+ slen = sizeof (struct sockaddr_storage);
+ if (_getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) {
+ warnx("svc_fd_create: could not retrieve remote addr");
+ goto freedata;
+ }
+ ret->xp_rtaddr.maxlen = ret->xp_rtaddr.len = ss.ss_len;
+ ret->xp_rtaddr.buf = mem_alloc((size_t)ss.ss_len);
+ if (ret->xp_rtaddr.buf == NULL) {
+ warnx("svc_fd_create: no mem for local addr");
+ goto freedata;
+ }
+ memcpy(ret->xp_rtaddr.buf, &ss, (size_t)ss.ss_len);
+#ifdef PORTMAP
+ if (ss.ss_family == AF_INET || ss.ss_family == AF_LOCAL) {
+ ret->xp_raddr = *(struct sockaddr_in *)ret->xp_rtaddr.buf;
+ ret->xp_addrlen = sizeof (struct sockaddr_in);
+ }
+#endif /* PORTMAP */
+
+ return ret;
+
+freedata:
+ if (ret->xp_ltaddr.buf != NULL)
+ mem_free(ret->xp_ltaddr.buf, rep->xp_ltaddr.maxlen);
+
+ return NULL;
+}
+
+static SVCXPRT *
+makefd_xprt(int fd, u_int sendsize, u_int recvsize)
+{
+ SVCXPRT *xprt;
+ struct cf_conn *cd;
+ const char *netid;
+ struct __rpc_sockinfo si;
+
+ assert(fd != -1);
+
+ xprt = svc_xprt_alloc();
+ if (xprt == NULL) {
+ warnx("svc_vc: makefd_xprt: out of memory");
+ goto done;
+ }
+ cd = mem_alloc(sizeof(struct cf_conn));
+ if (cd == NULL) {
+ warnx("svc_tcp: makefd_xprt: out of memory");
+ svc_xprt_free(xprt);
+ xprt = NULL;
+ goto done;
+ }
+ cd->strm_stat = XPRT_IDLE;
+ xdrrec_create(&(cd->xdrs), sendsize, recvsize,
+ xprt, read_vc, write_vc);
+ xprt->xp_p1 = cd;
+ xprt->xp_verf.oa_base = cd->verf_body;
+ svc_vc_ops(xprt); /* truly deals with calls */
+ xprt->xp_port = 0; /* this is a connection, not a rendezvouser */
+ xprt->xp_fd = fd;
+ if (__rpc_fd2sockinfo(fd, &si) && __rpc_sockinfo2netid(&si, &netid))
+ xprt->xp_netid = strdup(netid);
+
+ xprt_register(xprt);
+done:
+ return (xprt);
+}
+
+/*ARGSUSED*/
+static bool_t
+rendezvous_request(SVCXPRT *xprt, struct rpc_msg *msg)
+{
+ int sock, flags;
+ struct cf_rendezvous *r;
+ struct cf_conn *cd;
+ struct sockaddr_storage addr, sslocal;
+ socklen_t len, slen;
+ struct __rpc_sockinfo si;
+ SVCXPRT *newxprt;
+ fd_set cleanfds;
+
+ assert(xprt != NULL);
+ assert(msg != NULL);
+
+ r = (struct cf_rendezvous *)xprt->xp_p1;
+again:
+ len = sizeof addr;
+ if ((sock = _accept(xprt->xp_fd, (struct sockaddr *)(void *)&addr,
+ &len)) < 0) {
+ if (errno == EINTR)
+ goto again;
+ /*
+ * Clean out the most idle file descriptor when we're
+ * running out.
+ */
+ if (errno == EMFILE || errno == ENFILE) {
+ cleanfds = svc_fdset;
+ __svc_clean_idle(&cleanfds, 0, FALSE);
+ goto again;
+ }
+ return (FALSE);
+ }
+ /*
+ * make a new transporter (re-uses xprt)
+ */
+ newxprt = makefd_xprt(sock, r->sendsize, r->recvsize);
+ newxprt->xp_rtaddr.buf = mem_alloc(len);
+ if (newxprt->xp_rtaddr.buf == NULL)
+ return (FALSE);
+ memcpy(newxprt->xp_rtaddr.buf, &addr, len);
+ newxprt->xp_rtaddr.len = len;
+#ifdef PORTMAP
+ if (addr.ss_family == AF_INET || addr.ss_family == AF_LOCAL) {
+ newxprt->xp_raddr = *(struct sockaddr_in *)newxprt->xp_rtaddr.buf;
+ newxprt->xp_addrlen = sizeof (struct sockaddr_in);
+ }
+#endif /* PORTMAP */
+ if (__rpc_fd2sockinfo(sock, &si) && si.si_proto == IPPROTO_TCP) {
+ len = 1;
+ /* XXX fvdl - is this useful? */
+ _setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &len, sizeof (len));
+ }
+
+ cd = (struct cf_conn *)newxprt->xp_p1;
+
+ cd->recvsize = r->recvsize;
+ cd->sendsize = r->sendsize;
+ cd->maxrec = r->maxrec;
+
+ if (cd->maxrec != 0) {
+ flags = _fcntl(sock, F_GETFL, 0);
+ if (flags == -1)
+ return (FALSE);
+ if (_fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1)
+ return (FALSE);
+ if (cd->recvsize > cd->maxrec)
+ cd->recvsize = cd->maxrec;
+ cd->nonblock = TRUE;
+ __xdrrec_setnonblock(&cd->xdrs, cd->maxrec);
+ } else
+ cd->nonblock = FALSE;
+ slen = sizeof(struct sockaddr_storage);
+ if(_getsockname(sock, (struct sockaddr *)(void *)&sslocal, &slen) < 0) {
+ warnx("svc_vc_create: could not retrieve local addr");
+ newxprt->xp_ltaddr.maxlen = newxprt->xp_ltaddr.len = 0;
+ } else {
+ newxprt->xp_ltaddr.maxlen = newxprt->xp_ltaddr.len = sslocal.ss_len;
+ newxprt->xp_ltaddr.buf = mem_alloc((size_t)sslocal.ss_len);
+ if (newxprt->xp_ltaddr.buf == NULL) {
+ warnx("svc_vc_create: no mem for local addr");
+ newxprt->xp_ltaddr.maxlen = newxprt->xp_ltaddr.len = 0;
+ } else {
+ memcpy(newxprt->xp_ltaddr.buf, &sslocal, (size_t)sslocal.ss_len);
+ }
+ }
+
+ gettimeofday(&cd->last_recv_time, NULL);
+
+ return (FALSE); /* there is never an rpc msg to be processed */
+}
+
+/*ARGSUSED*/
+static enum xprt_stat
+rendezvous_stat(SVCXPRT *xprt)
+{
+
+ return (XPRT_IDLE);
+}
+
+static void
+svc_vc_destroy(SVCXPRT *xprt)
+{
+ assert(xprt != NULL);
+
+ xprt_unregister(xprt);
+ __svc_vc_dodestroy(xprt);
+}
+
+static void
+__svc_vc_dodestroy(SVCXPRT *xprt)
+{
+ struct cf_conn *cd;
+ struct cf_rendezvous *r;
+
+ cd = (struct cf_conn *)xprt->xp_p1;
+
+ if (xprt->xp_fd != RPC_ANYFD)
+ (void)_close(xprt->xp_fd);
+ if (xprt->xp_port != 0) {
+ /* a rendezvouser socket */
+ r = (struct cf_rendezvous *)xprt->xp_p1;
+ mem_free(r, sizeof (struct cf_rendezvous));
+ xprt->xp_port = 0;
+ } else {
+ /* an actual connection socket */
+ XDR_DESTROY(&(cd->xdrs));
+ mem_free(cd, sizeof(struct cf_conn));
+ }
+ if (xprt->xp_rtaddr.buf)
+ mem_free(xprt->xp_rtaddr.buf, xprt->xp_rtaddr.maxlen);
+ if (xprt->xp_ltaddr.buf)
+ mem_free(xprt->xp_ltaddr.buf, xprt->xp_ltaddr.maxlen);
+ free(xprt->xp_tp);
+ free(xprt->xp_netid);
+ svc_xprt_free(xprt);
+}
+
+/*ARGSUSED*/
+static bool_t
+svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in)
+{
+ return (FALSE);
+}
+
+static bool_t
+svc_vc_rendezvous_control(SVCXPRT *xprt, const u_int rq, void *in)
+{
+ struct cf_rendezvous *cfp;
+
+ cfp = (struct cf_rendezvous *)xprt->xp_p1;
+ if (cfp == NULL)
+ return (FALSE);
+ switch (rq) {
+ case SVCGET_CONNMAXREC:
+ *(int *)in = cfp->maxrec;
+ break;
+ case SVCSET_CONNMAXREC:
+ cfp->maxrec = *(int *)in;
+ break;
+ default:
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+/*
+ * reads data from the tcp or uip connection.
+ * any error is fatal and the connection is closed.
+ * (And a read of zero bytes is a half closed stream => error.)
+ * All read operations timeout after 35 seconds. A timeout is
+ * fatal for the connection.
+ */
+static int
+read_vc(void *xprtp, void *buf, int len)
+{
+ SVCXPRT *xprt;
+ int sock;
+ int milliseconds = 35 * 1000;
+ struct pollfd pollfd;
+ struct cf_conn *cfp;
+
+ xprt = (SVCXPRT *)xprtp;
+ assert(xprt != NULL);
+
+ sock = xprt->xp_fd;
+
+ cfp = (struct cf_conn *)xprt->xp_p1;
+
+ if (cfp->nonblock) {
+ len = _read(sock, buf, (size_t)len);
+ if (len < 0) {
+ if (errno == EAGAIN)
+ len = 0;
+ else
+ goto fatal_err;
+ }
+ if (len != 0)
+ gettimeofday(&cfp->last_recv_time, NULL);
+ return len;
+ }
+
+ do {
+ pollfd.fd = sock;
+ pollfd.events = POLLIN;
+ pollfd.revents = 0;
+ switch (_poll(&pollfd, 1, milliseconds)) {
+ case -1:
+ if (errno == EINTR)
+ continue;
+ /*FALLTHROUGH*/
+ case 0:
+ goto fatal_err;
+
+ default:
+ break;
+ }
+ } while ((pollfd.revents & POLLIN) == 0);
+
+ if ((len = _read(sock, buf, (size_t)len)) > 0) {
+ gettimeofday(&cfp->last_recv_time, NULL);
+ return (len);
+ }
+
+fatal_err:
+ ((struct cf_conn *)(xprt->xp_p1))->strm_stat = XPRT_DIED;
+ return (-1);
+}
+
+/*
+ * writes data to the tcp connection.
+ * Any error is fatal and the connection is closed.
+ */
+static int
+write_vc(void *xprtp, void *buf, int len)
+{
+ SVCXPRT *xprt;
+ int i, cnt;
+ struct cf_conn *cd;
+ struct timeval tv0, tv1;
+
+ xprt = (SVCXPRT *)xprtp;
+ assert(xprt != NULL);
+
+ cd = (struct cf_conn *)xprt->xp_p1;
+
+ if (cd->nonblock)
+ gettimeofday(&tv0, NULL);
+
+ for (cnt = len; cnt > 0; cnt -= i, buf = (char *)buf + i) {
+ i = _write(xprt->xp_fd, buf, (size_t)cnt);
+ if (i < 0) {
+ if (errno != EAGAIN || !cd->nonblock) {
+ cd->strm_stat = XPRT_DIED;
+ return (-1);
+ }
+ if (cd->nonblock) {
+ /*
+ * For non-blocking connections, do not
+ * take more than 2 seconds writing the
+ * data out.
+ *
+ * XXX 2 is an arbitrary amount.
+ */
+ gettimeofday(&tv1, NULL);
+ if (tv1.tv_sec - tv0.tv_sec >= 2) {
+ cd->strm_stat = XPRT_DIED;
+ return (-1);
+ }
+ }
+ i = 0;
+ }
+ }
+
+ return (len);
+}
+
+static enum xprt_stat
+svc_vc_stat(SVCXPRT *xprt)
+{
+ struct cf_conn *cd;
+
+ assert(xprt != NULL);
+
+ cd = (struct cf_conn *)(xprt->xp_p1);
+
+ if (cd->strm_stat == XPRT_DIED)
+ return (XPRT_DIED);
+ if (! xdrrec_eof(&(cd->xdrs)))
+ return (XPRT_MOREREQS);
+ return (XPRT_IDLE);
+}
+
+static bool_t
+svc_vc_recv(SVCXPRT *xprt, struct rpc_msg *msg)
+{
+ struct cf_conn *cd;
+ XDR *xdrs;
+
+ assert(xprt != NULL);
+ assert(msg != NULL);
+
+ cd = (struct cf_conn *)(xprt->xp_p1);
+ xdrs = &(cd->xdrs);
+
+ if (cd->nonblock) {
+ if (!__xdrrec_getrec(xdrs, &cd->strm_stat, TRUE))
+ return FALSE;
+ } else {
+ (void)xdrrec_skiprecord(xdrs);
+ }
+
+ xdrs->x_op = XDR_DECODE;
+ if (xdr_callmsg(xdrs, msg)) {
+ cd->x_id = msg->rm_xid;
+ return (TRUE);
+ }
+ cd->strm_stat = XPRT_DIED;
+ return (FALSE);
+}
+
+static bool_t
+svc_vc_getargs(SVCXPRT *xprt, xdrproc_t xdr_args, void *args_ptr)
+{
+ struct cf_conn *cd;
+
+ assert(xprt != NULL);
+ cd = (struct cf_conn *)(xprt->xp_p1);
+ return (SVCAUTH_UNWRAP(&SVC_AUTH(xprt),
+ &cd->xdrs, xdr_args, args_ptr));
+}
+
+static bool_t
+svc_vc_freeargs(SVCXPRT *xprt, xdrproc_t xdr_args, void *args_ptr)
+{
+ XDR *xdrs;
+
+ assert(xprt != NULL);
+ /* args_ptr may be NULL */
+
+ xdrs = &(((struct cf_conn *)(xprt->xp_p1))->xdrs);
+
+ xdrs->x_op = XDR_FREE;
+ return ((*xdr_args)(xdrs, args_ptr));
+}
+
+static bool_t
+svc_vc_reply(SVCXPRT *xprt, struct rpc_msg *msg)
+{
+ struct cf_conn *cd;
+ XDR *xdrs;
+ bool_t rstat;
+ xdrproc_t xdr_proc;
+ caddr_t xdr_where;
+ u_int pos;
+
+ assert(xprt != NULL);
+ assert(msg != NULL);
+
+ cd = (struct cf_conn *)(xprt->xp_p1);
+ xdrs = &(cd->xdrs);
+
+ xdrs->x_op = XDR_ENCODE;
+ msg->rm_xid = cd->x_id;
+ rstat = TRUE;
+ if (msg->rm_reply.rp_stat == MSG_ACCEPTED &&
+ msg->rm_reply.rp_acpt.ar_stat == SUCCESS) {
+ xdr_proc = msg->acpted_rply.ar_results.proc;
+ xdr_where = msg->acpted_rply.ar_results.where;
+ msg->acpted_rply.ar_results.proc = (xdrproc_t) xdr_void;
+ msg->acpted_rply.ar_results.where = NULL;
+
+ pos = XDR_GETPOS(xdrs);
+ if (!xdr_replymsg(xdrs, msg) ||
+ !SVCAUTH_WRAP(&SVC_AUTH(xprt), xdrs, xdr_proc, xdr_where)) {
+ XDR_SETPOS(xdrs, pos);
+ rstat = FALSE;
+ }
+ } else {
+ rstat = xdr_replymsg(xdrs, msg);
+ }
+
+ if (rstat)
+ (void)xdrrec_endofrecord(xdrs, TRUE);
+
+ return (rstat);
+}
+
+static void
+svc_vc_ops(SVCXPRT *xprt)
+{
+ static struct xp_ops ops;
+ static struct xp_ops2 ops2;
+
+/* VARIABLES PROTECTED BY ops_lock: ops, ops2 */
+
+ mutex_lock(&ops_lock);
+ if (ops.xp_recv == NULL) {
+ ops.xp_recv = svc_vc_recv;
+ ops.xp_stat = svc_vc_stat;
+ ops.xp_getargs = svc_vc_getargs;
+ ops.xp_reply = svc_vc_reply;
+ ops.xp_freeargs = svc_vc_freeargs;
+ ops.xp_destroy = svc_vc_destroy;
+ ops2.xp_control = svc_vc_control;
+ }
+ xprt->xp_ops = &ops;
+ xprt->xp_ops2 = &ops2;
+ mutex_unlock(&ops_lock);
+}
+
+static void
+svc_vc_rendezvous_ops(SVCXPRT *xprt)
+{
+ static struct xp_ops ops;
+ static struct xp_ops2 ops2;
+
+ mutex_lock(&ops_lock);
+ if (ops.xp_recv == NULL) {
+ ops.xp_recv = rendezvous_request;
+ ops.xp_stat = rendezvous_stat;
+ ops.xp_getargs =
+ (bool_t (*)(SVCXPRT *, xdrproc_t, void *))abort;
+ ops.xp_reply =
+ (bool_t (*)(SVCXPRT *, struct rpc_msg *))abort;
+ ops.xp_freeargs =
+ (bool_t (*)(SVCXPRT *, xdrproc_t, void *))abort;
+ ops.xp_destroy = svc_vc_destroy;
+ ops2.xp_control = svc_vc_rendezvous_control;
+ }
+ xprt->xp_ops = &ops;
+ xprt->xp_ops2 = &ops2;
+ mutex_unlock(&ops_lock);
+}
+
+/*
+ * Get the effective UID of the sending process. Used by rpcbind, keyserv
+ * and rpc.yppasswdd on AF_LOCAL.
+ */
+int
+__rpc_get_local_uid(SVCXPRT *transp, uid_t *uid) {
+ int sock, ret;
+ gid_t egid;
+ uid_t euid;
+ struct sockaddr *sa;
+
+ sock = transp->xp_fd;
+ sa = (struct sockaddr *)transp->xp_rtaddr.buf;
+ if (sa->sa_family == AF_LOCAL) {
+ ret = getpeereid(sock, &euid, &egid);
+ if (ret == 0)
+ *uid = euid;
+ return (ret);
+ } else
+ return (-1);
+}
+
+/*
+ * Destroy xprts that have not have had any activity in 'timeout' seconds.
+ * If 'cleanblock' is true, blocking connections (the default) are also
+ * cleaned. If timeout is 0, the least active connection is picked.
+ */
+bool_t
+__svc_clean_idle(fd_set *fds, int timeout, bool_t cleanblock)
+{
+ int i, ncleaned;
+ SVCXPRT *xprt, *least_active;
+ struct timeval tv, tdiff, tmax;
+ struct cf_conn *cd;
+
+ gettimeofday(&tv, NULL);
+ tmax.tv_sec = tmax.tv_usec = 0;
+ least_active = NULL;
+ rwlock_wrlock(&svc_fd_lock);
+ for (i = ncleaned = 0; i <= svc_maxfd; i++) {
+ if (FD_ISSET(i, fds)) {
+ xprt = __svc_xports[i];
+ if (xprt == NULL || xprt->xp_ops == NULL ||
+ xprt->xp_ops->xp_recv != svc_vc_recv)
+ continue;
+ cd = (struct cf_conn *)xprt->xp_p1;
+ if (!cleanblock && !cd->nonblock)
+ continue;
+ if (timeout == 0) {
+ timersub(&tv, &cd->last_recv_time, &tdiff);
+ if (timercmp(&tdiff, &tmax, >)) {
+ tmax = tdiff;
+ least_active = xprt;
+ }
+ continue;
+ }
+ if (tv.tv_sec - cd->last_recv_time.tv_sec > timeout) {
+ __xprt_unregister_unlocked(xprt);
+ __svc_vc_dodestroy(xprt);
+ ncleaned++;
+ }
+ }
+ }
+ if (timeout == 0 && least_active != NULL) {
+ __xprt_unregister_unlocked(least_active);
+ __svc_vc_dodestroy(least_active);
+ ncleaned++;
+ }
+ rwlock_unlock(&svc_fd_lock);
+ return ncleaned > 0 ? TRUE : FALSE;
+}
diff --git a/lib/libc/secure/Makefile.inc b/lib/libc/secure/Makefile.inc
new file mode 100644
index 000000000000..e2e75c70603b
--- /dev/null
+++ b/lib/libc/secure/Makefile.inc
@@ -0,0 +1,13 @@
+# $FreeBSD$
+#
+# libc sources related to security
+
+.PATH: ${LIBC_SRCTOP}/secure
+
+# Sources common to both syscall interfaces:
+SRCS+= stack_protector.c
+.if ${MK_SYMVER} == yes
+SRCS+= stack_protector_compat.c
+.endif
+
+SYM_MAPS+= ${LIBC_SRCTOP}/secure/Symbol.map
diff --git a/lib/libc/secure/Symbol.map b/lib/libc/secure/Symbol.map
new file mode 100644
index 000000000000..aaa76c17291a
--- /dev/null
+++ b/lib/libc/secure/Symbol.map
@@ -0,0 +1,9 @@
+/*
+ * $FreeBSD$
+ */
+
+FBSD_1.0 {
+ __chk_fail;
+ __stack_chk_fail;
+ __stack_chk_guard;
+};
diff --git a/lib/libc/secure/stack_protector.c b/lib/libc/secure/stack_protector.c
new file mode 100644
index 000000000000..d55813e00f1d
--- /dev/null
+++ b/lib/libc/secure/stack_protector.c
@@ -0,0 +1,116 @@
+/* $NetBSD: stack_protector.c,v 1.4 2006/11/22 17:23:25 christos Exp $ */
+/* $OpenBSD: stack_protector.c,v 1.10 2006/03/31 05:34:44 deraadt Exp $ */
+/*
+ * Copyright (c) 2002 Hiroaki Etoh, Federico G. Schwindt, and Miodrag Vallat.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <errno.h>
+#include <link.h>
+#include <signal.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include "libc_private.h"
+
+extern int __sysctl(const int *name, u_int namelen, void *oldp,
+ size_t *oldlenp, void *newp, size_t newlen);
+
+long __stack_chk_guard[8] = {0, 0, 0, 0, 0, 0, 0, 0};
+static void __guard_setup(void) __attribute__((__constructor__, __used__));
+static void __fail(const char *);
+void __stack_chk_fail(void);
+void __chk_fail(void);
+
+/*LINTED used*/
+static void
+__guard_setup(void)
+{
+ static const int mib[2] = { CTL_KERN, KERN_ARND };
+ size_t len;
+ int error;
+
+ if (__stack_chk_guard[0] != 0)
+ return;
+ error = _elf_aux_info(AT_CANARY, __stack_chk_guard,
+ sizeof(__stack_chk_guard));
+ if (error == 0 && __stack_chk_guard[0] != 0)
+ return;
+
+ len = sizeof(__stack_chk_guard);
+ if (__sysctl(mib, nitems(mib), __stack_chk_guard, &len, NULL, 0) ==
+ -1 || len != sizeof(__stack_chk_guard)) {
+ /* If sysctl was unsuccessful, use the "terminator canary". */
+ ((unsigned char *)(void *)__stack_chk_guard)[0] = 0;
+ ((unsigned char *)(void *)__stack_chk_guard)[1] = 0;
+ ((unsigned char *)(void *)__stack_chk_guard)[2] = '\n';
+ ((unsigned char *)(void *)__stack_chk_guard)[3] = 255;
+ }
+}
+
+/*ARGSUSED*/
+static void
+__fail(const char *msg)
+{
+ struct sigaction sa;
+ sigset_t mask;
+
+ /* Immediately block all signal handlers from running code */
+ (void)sigfillset(&mask);
+ (void)sigdelset(&mask, SIGABRT);
+ (void)sigprocmask(SIG_BLOCK, &mask, NULL);
+
+ /* This may fail on a chroot jail... */
+ syslog(LOG_CRIT, "%s", msg);
+
+ (void)memset(&sa, 0, sizeof(sa));
+ (void)sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0;
+ sa.sa_handler = SIG_DFL;
+ (void)sigaction(SIGABRT, &sa, NULL);
+ (void)kill(getpid(), SIGABRT);
+ _exit(127);
+}
+
+void
+__stack_chk_fail(void)
+{
+ __fail("stack overflow detected; terminated");
+}
+
+void
+__chk_fail(void)
+{
+ __fail("buffer overflow detected; terminated");
+}
+
+#ifndef PIC
+__weak_reference(__stack_chk_fail, __stack_chk_fail_local);
+#endif
diff --git a/lib/libc/secure/stack_protector_compat.c b/lib/libc/secure/stack_protector_compat.c
new file mode 100644
index 000000000000..cacb863e75e6
--- /dev/null
+++ b/lib/libc/secure/stack_protector_compat.c
@@ -0,0 +1,20 @@
+/*
+ * Written by Alexander Kabaev <kan@FreeBSD.org>
+ * The file is in public domain.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+void __stack_chk_fail(void);
+
+#ifdef PIC
+void
+__stack_chk_fail_local_hidden(void)
+{
+
+ __stack_chk_fail();
+}
+
+__sym_compat(__stack_chk_fail_local, __stack_chk_fail_local_hidden, FBSD_1.0);
+#endif
diff --git a/lib/libc/softfloat/Makefile.inc b/lib/libc/softfloat/Makefile.inc
new file mode 100644
index 000000000000..fa0ee9d2977f
--- /dev/null
+++ b/lib/libc/softfloat/Makefile.inc
@@ -0,0 +1,35 @@
+# $NetBSD: Makefile.inc,v 1.10 2011/07/04 02:53:15 mrg Exp $
+# $FreeBSD$
+
+SOFTFLOAT_BITS?=64
+.PATH: ${LIBC_ARCH}/softfloat \
+ ${LIBC_SRCTOP}/softfloat/bits${SOFTFLOAT_BITS} \
+ ${LIBC_SRCTOP}/softfloat
+
+CFLAGS+= -I${LIBC_SRCTOP}/${LIBC_ARCH}/softfloat \
+ -I${LIBC_SRCTOP}/softfloat
+CFLAGS+= -DSOFTFLOAT_FOR_GCC
+
+SRCS+= softfloat.c
+
+# Deprecated FPU control interface
+.if ${LIBC_ARCH} != "riscv"
+SRCS+= fpgetround.c fpsetround.c fpgetmask.c fpsetmask.c \
+ fpgetsticky.c
+.endif
+
+SRCS+= eqsf2.c nesf2.c gtsf2.c gesf2.c ltsf2.c lesf2.c negsf2.c \
+ eqdf2.c nedf2.c gtdf2.c gedf2.c ltdf2.c ledf2.c negdf2.c \
+ unordsf2.c unorddf2.c
+
+.if defined(SOFTFLOAT_128)
+CFLAGS+= -DFLOAT128
+SRCS+= eqtf2.c netf2.c gttf2.c getf2.c lttf2.c letf2.c negtf2.c
+.endif
+
+.if defined(SOFTFLOAT_X80)
+CFLAGS+= -DFLOATX80
+SRCS+= nexf2.c gtxf2.c gexf2.c negxf2.c
+.endif
+
+SYM_MAPS+= ${LIBC_SRCTOP}/softfloat/Symbol.map
diff --git a/lib/libc/softfloat/README.NetBSD b/lib/libc/softfloat/README.NetBSD
new file mode 100644
index 000000000000..c6ca7a8753cc
--- /dev/null
+++ b/lib/libc/softfloat/README.NetBSD
@@ -0,0 +1,9 @@
+$NetBSD: README.NetBSD,v 1.2 2002/05/21 23:51:05 bjh21 Exp $
+$FreeBSD$
+
+This is a modified version of part of John Hauser's SoftFloat 2a package.
+This version has been heavily modified to support its use with GCC to
+implement built-in floating-point operations, but compiling
+softfloat.c without SOFTFLOAT_FOR_GCC defined should get you the same
+results as from the original.
+
diff --git a/lib/libc/softfloat/README.txt b/lib/libc/softfloat/README.txt
new file mode 100644
index 000000000000..fe28ccc294fb
--- /dev/null
+++ b/lib/libc/softfloat/README.txt
@@ -0,0 +1,40 @@
+$NetBSD: README.txt,v 1.1 2000/06/06 08:15:02 bjh21 Exp $
+$FreeBSD$
+
+Package Overview for SoftFloat Release 2a
+
+John R. Hauser
+1998 December 13
+
+
+SoftFloat is a software implementation of floating-point that conforms to
+the IEC/IEEE Standard for Binary Floating-Point Arithmetic. SoftFloat is
+distributed in the form of C source code. Compiling the SoftFloat sources
+generates two things:
+
+-- A SoftFloat object file (typically `softfloat.o') containing the complete
+ set of IEC/IEEE floating-point routines.
+
+-- A `timesoftfloat' program for evaluating the speed of the SoftFloat
+ routines. (The SoftFloat module is linked into this program.)
+
+The SoftFloat package is documented in four text files:
+
+ softfloat.txt Documentation for using the SoftFloat functions.
+ softfloat-source.txt Documentation for compiling SoftFloat.
+ softfloat-history.txt History of major changes to SoftFloat.
+ timesoftfloat.txt Documentation for using `timesoftfloat'.
+
+Other files in the package comprise the source code for SoftFloat.
+
+Please be aware that some work is involved in porting this software to other
+targets. It is not just a matter of getting `make' to complete without
+error messages. I would have written the code that way if I could, but
+there are fundamental differences between systems that I can't make go away.
+You should not attempt to compile SoftFloat without first reading both
+`softfloat.txt' and `softfloat-source.txt'.
+
+At the time of this writing, the most up-to-date information about
+SoftFloat and the latest release can be found at the Web page `http://
+HTTP.CS.Berkeley.EDU/~jhauser/arithmetic/SoftFloat.html'.
+
diff --git a/lib/libc/softfloat/Symbol.map b/lib/libc/softfloat/Symbol.map
new file mode 100644
index 000000000000..9c9662a71d38
--- /dev/null
+++ b/lib/libc/softfloat/Symbol.map
@@ -0,0 +1,41 @@
+/*
+ * $FreeBSD$
+ */
+
+FBSD_1.0 {
+ _fpgetmask;
+ fpgetmask;
+ _fpgetround;
+ fpgetround;
+ _fpgetsticky;
+ fpgetsticky;
+ _fpsetmask;
+ fpsetmask;
+ _fpsetround;
+ fpsetround;
+ _fpsetsticky;
+ fpsetsticky;
+};
+
+FBSDprivate_1.0 {
+ __softfloat_float_exception_flags;
+ __softfloat_float_exception_mask;
+ __softfloat_float_rounding_mode;
+ __softfloat_float_raise;
+ __eqdf2;
+ __eqsf2;
+ __gedf2;
+ __gesf2;
+ __gtdf2;
+ __gtsf2;
+ __ledf2;
+ __lesf2;
+ __ltdf2;
+ __ltsf2;
+ __nedf2;
+ __negdf2;
+ __negsf2;
+ __nesf2;
+ __unorddf2;
+ __unordsf2;
+};
diff --git a/lib/libc/softfloat/bits32/softfloat-macros b/lib/libc/softfloat/bits32/softfloat-macros
new file mode 100644
index 000000000000..db4e038eb0b7
--- /dev/null
+++ b/lib/libc/softfloat/bits32/softfloat-macros
@@ -0,0 +1,649 @@
+/* $FreeBSD$ */
+
+/*
+===============================================================================
+
+This C source fragment is part of the SoftFloat IEC/IEEE Floating-point
+Arithmetic Package, Release 2a.
+
+Written by John R. Hauser. This work was made possible in part by the
+International Computer Science Institute, located at Suite 600, 1947 Center
+Street, Berkeley, California 94704. Funding was partially provided by the
+National Science Foundation under grant MIP-9311980. The original version
+of this code was written as part of a project to build a fixed-point vector
+processor in collaboration with the University of California at Berkeley,
+overseen by Profs. Nelson Morgan and John Wawrzynek. More information
+is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
+arithmetic/SoftFloat.html'.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
+has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
+TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
+PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
+AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
+
+Derivative works are acceptable, even for commercial purposes, so long as
+(1) they include prominent notice that the work is derivative, and (2) they
+include prominent notice akin to these four paragraphs for those parts of
+this code that are retained.
+
+===============================================================================
+*/
+
+/*
+-------------------------------------------------------------------------------
+Shifts `a' right by the number of bits given in `count'. If any nonzero
+bits are shifted off, they are ``jammed'' into the least significant bit of
+the result by setting the least significant bit to 1. The value of `count'
+can be arbitrarily large; in particular, if `count' is greater than 32, the
+result will be either 0 or 1, depending on whether `a' is zero or nonzero.
+The result is stored in the location pointed to by `zPtr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void shift32RightJamming( bits32 a, int16 count, bits32 *zPtr )
+{
+ bits32 z;
+
+ if ( count == 0 ) {
+ z = a;
+ }
+ else if ( count < 32 ) {
+ z = ( a>>count ) | ( ( a<<( ( - count ) & 31 ) ) != 0 );
+ }
+ else {
+ z = ( a != 0 );
+ }
+ *zPtr = z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Shifts the 64-bit value formed by concatenating `a0' and `a1' right by the
+number of bits given in `count'. Any bits shifted off are lost. The value
+of `count' can be arbitrarily large; in particular, if `count' is greater
+than 64, the result will be 0. The result is broken into two 32-bit pieces
+which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ shift64Right(
+ bits32 a0, bits32 a1, int16 count, bits32 *z0Ptr, bits32 *z1Ptr )
+{
+ bits32 z0, z1;
+ int8 negCount = ( - count ) & 31;
+
+ if ( count == 0 ) {
+ z1 = a1;
+ z0 = a0;
+ }
+ else if ( count < 32 ) {
+ z1 = ( a0<<negCount ) | ( a1>>count );
+ z0 = a0>>count;
+ }
+ else {
+ z1 = ( count < 64 ) ? ( a0>>( count & 31 ) ) : 0;
+ z0 = 0;
+ }
+ *z1Ptr = z1;
+ *z0Ptr = z0;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Shifts the 64-bit value formed by concatenating `a0' and `a1' right by the
+number of bits given in `count'. If any nonzero bits are shifted off, they
+are ``jammed'' into the least significant bit of the result by setting the
+least significant bit to 1. The value of `count' can be arbitrarily large;
+in particular, if `count' is greater than 64, the result will be either 0
+or 1, depending on whether the concatenation of `a0' and `a1' is zero or
+nonzero. The result is broken into two 32-bit pieces which are stored at
+the locations pointed to by `z0Ptr' and `z1Ptr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ shift64RightJamming(
+ bits32 a0, bits32 a1, int16 count, bits32 *z0Ptr, bits32 *z1Ptr )
+{
+ bits32 z0, z1;
+ int8 negCount = ( - count ) & 31;
+
+ if ( count == 0 ) {
+ z1 = a1;
+ z0 = a0;
+ }
+ else if ( count < 32 ) {
+ z1 = ( a0<<negCount ) | ( a1>>count ) | ( ( a1<<negCount ) != 0 );
+ z0 = a0>>count;
+ }
+ else {
+ if ( count == 32 ) {
+ z1 = a0 | ( a1 != 0 );
+ }
+ else if ( count < 64 ) {
+ z1 = ( a0>>( count & 31 ) ) | ( ( ( a0<<negCount ) | a1 ) != 0 );
+ }
+ else {
+ z1 = ( ( a0 | a1 ) != 0 );
+ }
+ z0 = 0;
+ }
+ *z1Ptr = z1;
+ *z0Ptr = z0;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Shifts the 96-bit value formed by concatenating `a0', `a1', and `a2' right
+by 32 _plus_ the number of bits given in `count'. The shifted result is
+at most 64 nonzero bits; these are broken into two 32-bit pieces which are
+stored at the locations pointed to by `z0Ptr' and `z1Ptr'. The bits shifted
+off form a third 32-bit result as follows: The _last_ bit shifted off is
+the most-significant bit of the extra result, and the other 31 bits of the
+extra result are all zero if and only if _all_but_the_last_ bits shifted off
+were all zero. This extra result is stored in the location pointed to by
+`z2Ptr'. The value of `count' can be arbitrarily large.
+ (This routine makes more sense if `a0', `a1', and `a2' are considered
+to form a fixed-point value with binary point between `a1' and `a2'. This
+fixed-point value is shifted right by the number of bits given in `count',
+and the integer part of the result is returned at the locations pointed to
+by `z0Ptr' and `z1Ptr'. The fractional part of the result may be slightly
+corrupted as described above, and is returned at the location pointed to by
+`z2Ptr'.)
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ shift64ExtraRightJamming(
+ bits32 a0,
+ bits32 a1,
+ bits32 a2,
+ int16 count,
+ bits32 *z0Ptr,
+ bits32 *z1Ptr,
+ bits32 *z2Ptr
+ )
+{
+ bits32 z0, z1, z2;
+ int8 negCount = ( - count ) & 31;
+
+ if ( count == 0 ) {
+ z2 = a2;
+ z1 = a1;
+ z0 = a0;
+ }
+ else {
+ if ( count < 32 ) {
+ z2 = a1<<negCount;
+ z1 = ( a0<<negCount ) | ( a1>>count );
+ z0 = a0>>count;
+ }
+ else {
+ if ( count == 32 ) {
+ z2 = a1;
+ z1 = a0;
+ }
+ else {
+ a2 |= a1;
+ if ( count < 64 ) {
+ z2 = a0<<negCount;
+ z1 = a0>>( count & 31 );
+ }
+ else {
+ z2 = ( count == 64 ) ? a0 : ( a0 != 0 );
+ z1 = 0;
+ }
+ }
+ z0 = 0;
+ }
+ z2 |= ( a2 != 0 );
+ }
+ *z2Ptr = z2;
+ *z1Ptr = z1;
+ *z0Ptr = z0;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Shifts the 64-bit value formed by concatenating `a0' and `a1' left by the
+number of bits given in `count'. Any bits shifted off are lost. The value
+of `count' must be less than 32. The result is broken into two 32-bit
+pieces which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ shortShift64Left(
+ bits32 a0, bits32 a1, int16 count, bits32 *z0Ptr, bits32 *z1Ptr )
+{
+
+ *z1Ptr = a1<<count;
+ *z0Ptr =
+ ( count == 0 ) ? a0 : ( a0<<count ) | ( a1>>( ( - count ) & 31 ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Shifts the 96-bit value formed by concatenating `a0', `a1', and `a2' left
+by the number of bits given in `count'. Any bits shifted off are lost.
+The value of `count' must be less than 32. The result is broken into three
+32-bit pieces which are stored at the locations pointed to by `z0Ptr',
+`z1Ptr', and `z2Ptr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ shortShift96Left(
+ bits32 a0,
+ bits32 a1,
+ bits32 a2,
+ int16 count,
+ bits32 *z0Ptr,
+ bits32 *z1Ptr,
+ bits32 *z2Ptr
+ )
+{
+ bits32 z0, z1, z2;
+ int8 negCount;
+
+ z2 = a2<<count;
+ z1 = a1<<count;
+ z0 = a0<<count;
+ if ( 0 < count ) {
+ negCount = ( ( - count ) & 31 );
+ z1 |= a2>>negCount;
+ z0 |= a1>>negCount;
+ }
+ *z2Ptr = z2;
+ *z1Ptr = z1;
+ *z0Ptr = z0;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Adds the 64-bit value formed by concatenating `a0' and `a1' to the 64-bit
+value formed by concatenating `b0' and `b1'. Addition is modulo 2^64, so
+any carry out is lost. The result is broken into two 32-bit pieces which
+are stored at the locations pointed to by `z0Ptr' and `z1Ptr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ add64(
+ bits32 a0, bits32 a1, bits32 b0, bits32 b1, bits32 *z0Ptr, bits32 *z1Ptr )
+{
+ bits32 z1;
+
+ z1 = a1 + b1;
+ *z1Ptr = z1;
+ *z0Ptr = a0 + b0 + ( z1 < a1 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Adds the 96-bit value formed by concatenating `a0', `a1', and `a2' to the
+96-bit value formed by concatenating `b0', `b1', and `b2'. Addition is
+modulo 2^96, so any carry out is lost. The result is broken into three
+32-bit pieces which are stored at the locations pointed to by `z0Ptr',
+`z1Ptr', and `z2Ptr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ add96(
+ bits32 a0,
+ bits32 a1,
+ bits32 a2,
+ bits32 b0,
+ bits32 b1,
+ bits32 b2,
+ bits32 *z0Ptr,
+ bits32 *z1Ptr,
+ bits32 *z2Ptr
+ )
+{
+ bits32 z0, z1, z2;
+ int8 carry0, carry1;
+
+ z2 = a2 + b2;
+ carry1 = ( z2 < a2 );
+ z1 = a1 + b1;
+ carry0 = ( z1 < a1 );
+ z0 = a0 + b0;
+ z1 += carry1;
+ z0 += ( z1 < (bits32)carry1 );
+ z0 += carry0;
+ *z2Ptr = z2;
+ *z1Ptr = z1;
+ *z0Ptr = z0;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Subtracts the 64-bit value formed by concatenating `b0' and `b1' from the
+64-bit value formed by concatenating `a0' and `a1'. Subtraction is modulo
+2^64, so any borrow out (carry out) is lost. The result is broken into two
+32-bit pieces which are stored at the locations pointed to by `z0Ptr' and
+`z1Ptr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ sub64(
+ bits32 a0, bits32 a1, bits32 b0, bits32 b1, bits32 *z0Ptr, bits32 *z1Ptr )
+{
+
+ *z1Ptr = a1 - b1;
+ *z0Ptr = a0 - b0 - ( a1 < b1 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Subtracts the 96-bit value formed by concatenating `b0', `b1', and `b2' from
+the 96-bit value formed by concatenating `a0', `a1', and `a2'. Subtraction
+is modulo 2^96, so any borrow out (carry out) is lost. The result is broken
+into three 32-bit pieces which are stored at the locations pointed to by
+`z0Ptr', `z1Ptr', and `z2Ptr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ sub96(
+ bits32 a0,
+ bits32 a1,
+ bits32 a2,
+ bits32 b0,
+ bits32 b1,
+ bits32 b2,
+ bits32 *z0Ptr,
+ bits32 *z1Ptr,
+ bits32 *z2Ptr
+ )
+{
+ bits32 z0, z1, z2;
+ int8 borrow0, borrow1;
+
+ z2 = a2 - b2;
+ borrow1 = ( a2 < b2 );
+ z1 = a1 - b1;
+ borrow0 = ( a1 < b1 );
+ z0 = a0 - b0;
+ z0 -= ( z1 < (bits32)borrow1 );
+ z1 -= borrow1;
+ z0 -= borrow0;
+ *z2Ptr = z2;
+ *z1Ptr = z1;
+ *z0Ptr = z0;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Multiplies `a' by `b' to obtain a 64-bit product. The product is broken
+into two 32-bit pieces which are stored at the locations pointed to by
+`z0Ptr' and `z1Ptr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void mul32To64( bits32 a, bits32 b, bits32 *z0Ptr, bits32 *z1Ptr )
+{
+ bits16 aHigh, aLow, bHigh, bLow;
+ bits32 z0, zMiddleA, zMiddleB, z1;
+
+ aLow = a;
+ aHigh = a>>16;
+ bLow = b;
+ bHigh = b>>16;
+ z1 = ( (bits32) aLow ) * bLow;
+ zMiddleA = ( (bits32) aLow ) * bHigh;
+ zMiddleB = ( (bits32) aHigh ) * bLow;
+ z0 = ( (bits32) aHigh ) * bHigh;
+ zMiddleA += zMiddleB;
+ z0 += ( ( (bits32) ( zMiddleA < zMiddleB ) )<<16 ) + ( zMiddleA>>16 );
+ zMiddleA <<= 16;
+ z1 += zMiddleA;
+ z0 += ( z1 < zMiddleA );
+ *z1Ptr = z1;
+ *z0Ptr = z0;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Multiplies the 64-bit value formed by concatenating `a0' and `a1' by `b'
+to obtain a 96-bit product. The product is broken into three 32-bit pieces
+which are stored at the locations pointed to by `z0Ptr', `z1Ptr', and
+`z2Ptr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ mul64By32To96(
+ bits32 a0,
+ bits32 a1,
+ bits32 b,
+ bits32 *z0Ptr,
+ bits32 *z1Ptr,
+ bits32 *z2Ptr
+ )
+{
+ bits32 z0, z1, z2, more1;
+
+ mul32To64( a1, b, &z1, &z2 );
+ mul32To64( a0, b, &z0, &more1 );
+ add64( z0, more1, 0, z1, &z0, &z1 );
+ *z2Ptr = z2;
+ *z1Ptr = z1;
+ *z0Ptr = z0;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Multiplies the 64-bit value formed by concatenating `a0' and `a1' to the
+64-bit value formed by concatenating `b0' and `b1' to obtain a 128-bit
+product. The product is broken into four 32-bit pieces which are stored at
+the locations pointed to by `z0Ptr', `z1Ptr', `z2Ptr', and `z3Ptr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ mul64To128(
+ bits32 a0,
+ bits32 a1,
+ bits32 b0,
+ bits32 b1,
+ bits32 *z0Ptr,
+ bits32 *z1Ptr,
+ bits32 *z2Ptr,
+ bits32 *z3Ptr
+ )
+{
+ bits32 z0, z1, z2, z3;
+ bits32 more1, more2;
+
+ mul32To64( a1, b1, &z2, &z3 );
+ mul32To64( a1, b0, &z1, &more2 );
+ add64( z1, more2, 0, z2, &z1, &z2 );
+ mul32To64( a0, b0, &z0, &more1 );
+ add64( z0, more1, 0, z1, &z0, &z1 );
+ mul32To64( a0, b1, &more1, &more2 );
+ add64( more1, more2, 0, z2, &more1, &z2 );
+ add64( z0, z1, 0, more1, &z0, &z1 );
+ *z3Ptr = z3;
+ *z2Ptr = z2;
+ *z1Ptr = z1;
+ *z0Ptr = z0;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns an approximation to the 32-bit integer quotient obtained by dividing
+`b' into the 64-bit value formed by concatenating `a0' and `a1'. The
+divisor `b' must be at least 2^31. If q is the exact quotient truncated
+toward zero, the approximation returned lies between q and q + 2 inclusive.
+If the exact quotient q is larger than 32 bits, the maximum positive 32-bit
+unsigned integer is returned.
+-------------------------------------------------------------------------------
+*/
+static bits32 estimateDiv64To32( bits32 a0, bits32 a1, bits32 b )
+{
+ bits32 b0, b1;
+ bits32 rem0, rem1, term0, term1;
+ bits32 z;
+
+ if ( b <= a0 ) return 0xFFFFFFFF;
+ b0 = b>>16;
+ z = ( b0<<16 <= a0 ) ? 0xFFFF0000 : ( a0 / b0 )<<16;
+ mul32To64( b, z, &term0, &term1 );
+ sub64( a0, a1, term0, term1, &rem0, &rem1 );
+ while ( ( (sbits32) rem0 ) < 0 ) {
+ z -= 0x10000;
+ b1 = b<<16;
+ add64( rem0, rem1, b0, b1, &rem0, &rem1 );
+ }
+ rem0 = ( rem0<<16 ) | ( rem1>>16 );
+ z |= ( b0<<16 <= rem0 ) ? 0xFFFF : rem0 / b0;
+ return z;
+
+}
+
+#ifndef SOFTFLOAT_FOR_GCC
+/*
+-------------------------------------------------------------------------------
+Returns an approximation to the square root of the 32-bit significand given
+by `a'. Considered as an integer, `a' must be at least 2^31. If bit 0 of
+`aExp' (the least significant bit) is 1, the integer returned approximates
+2^31*sqrt(`a'/2^31), where `a' is considered an integer. If bit 0 of `aExp'
+is 0, the integer returned approximates 2^31*sqrt(`a'/2^30). In either
+case, the approximation returned lies strictly within +/-2 of the exact
+value.
+-------------------------------------------------------------------------------
+*/
+static bits32 estimateSqrt32( int16 aExp, bits32 a )
+{
+ static const bits16 sqrtOddAdjustments[] = {
+ 0x0004, 0x0022, 0x005D, 0x00B1, 0x011D, 0x019F, 0x0236, 0x02E0,
+ 0x039C, 0x0468, 0x0545, 0x0631, 0x072B, 0x0832, 0x0946, 0x0A67
+ };
+ static const bits16 sqrtEvenAdjustments[] = {
+ 0x0A2D, 0x08AF, 0x075A, 0x0629, 0x051A, 0x0429, 0x0356, 0x029E,
+ 0x0200, 0x0179, 0x0109, 0x00AF, 0x0068, 0x0034, 0x0012, 0x0002
+ };
+ int8 index;
+ bits32 z;
+
+ index = ( a>>27 ) & 15;
+ if ( aExp & 1 ) {
+ z = 0x4000 + ( a>>17 ) - sqrtOddAdjustments[ index ];
+ z = ( ( a / z )<<14 ) + ( z<<15 );
+ a >>= 1;
+ }
+ else {
+ z = 0x8000 + ( a>>17 ) - sqrtEvenAdjustments[ index ];
+ z = a / z + z;
+ z = ( 0x20000 <= z ) ? 0xFFFF8000 : ( z<<15 );
+ if ( z <= a ) return (bits32) ( ( (sbits32) a )>>1 );
+ }
+ return ( ( estimateDiv64To32( a, 0, z ) )>>1 ) + ( z>>1 );
+
+}
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Returns the number of leading 0 bits before the most-significant 1 bit of
+`a'. If `a' is zero, 32 is returned.
+-------------------------------------------------------------------------------
+*/
+static int8 countLeadingZeros32( bits32 a )
+{
+ static const int8 countLeadingZerosHigh[] = {
+ 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+ int8 shiftCount;
+
+ shiftCount = 0;
+ if ( a < 0x10000 ) {
+ shiftCount += 16;
+ a <<= 16;
+ }
+ if ( a < 0x1000000 ) {
+ shiftCount += 8;
+ a <<= 8;
+ }
+ shiftCount += countLeadingZerosHigh[ a>>24 ];
+ return shiftCount;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the 64-bit value formed by concatenating `a0' and `a1' is
+equal to the 64-bit value formed by concatenating `b0' and `b1'. Otherwise,
+returns 0.
+-------------------------------------------------------------------------------
+*/
+INLINE flag eq64( bits32 a0, bits32 a1, bits32 b0, bits32 b1 )
+{
+
+ return ( a0 == b0 ) && ( a1 == b1 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the 64-bit value formed by concatenating `a0' and `a1' is less
+than or equal to the 64-bit value formed by concatenating `b0' and `b1'.
+Otherwise, returns 0.
+-------------------------------------------------------------------------------
+*/
+INLINE flag le64( bits32 a0, bits32 a1, bits32 b0, bits32 b1 )
+{
+
+ return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 <= b1 ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the 64-bit value formed by concatenating `a0' and `a1' is less
+than the 64-bit value formed by concatenating `b0' and `b1'. Otherwise,
+returns 0.
+-------------------------------------------------------------------------------
+*/
+INLINE flag lt64( bits32 a0, bits32 a1, bits32 b0, bits32 b1 )
+{
+
+ return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 < b1 ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the 64-bit value formed by concatenating `a0' and `a1' is not
+equal to the 64-bit value formed by concatenating `b0' and `b1'. Otherwise,
+returns 0.
+-------------------------------------------------------------------------------
+*/
+INLINE flag ne64( bits32 a0, bits32 a1, bits32 b0, bits32 b1 )
+{
+
+ return ( a0 != b0 ) || ( a1 != b1 );
+
+}
+
diff --git a/lib/libc/softfloat/bits32/softfloat.c b/lib/libc/softfloat/bits32/softfloat.c
new file mode 100644
index 000000000000..ad7c016bf043
--- /dev/null
+++ b/lib/libc/softfloat/bits32/softfloat.c
@@ -0,0 +1,2347 @@
+/* $NetBSD: softfloat.c,v 1.1 2002/05/21 23:51:07 bjh21 Exp $ */
+
+/*
+ * This version hacked for use with gcc -msoft-float by bjh21.
+ * (Mostly a case of #ifdefing out things GCC doesn't need or provides
+ * itself).
+ */
+
+/*
+ * Things you may want to define:
+ *
+ * SOFTFLOAT_FOR_GCC - build only those functions necessary for GCC (with
+ * -msoft-float) to work. Include "softfloat-for-gcc.h" to get them
+ * properly renamed.
+ */
+
+/*
+ * This differs from the standard bits32/softfloat.c in that float64
+ * is defined to be a 64-bit integer rather than a structure. The
+ * structure is float64s, with translation between the two going via
+ * float64u.
+ */
+
+/*
+===============================================================================
+
+This C source file is part of the SoftFloat IEC/IEEE Floating-Point
+Arithmetic Package, Release 2a.
+
+Written by John R. Hauser. This work was made possible in part by the
+International Computer Science Institute, located at Suite 600, 1947 Center
+Street, Berkeley, California 94704. Funding was partially provided by the
+National Science Foundation under grant MIP-9311980. The original version
+of this code was written as part of a project to build a fixed-point vector
+processor in collaboration with the University of California at Berkeley,
+overseen by Profs. Nelson Morgan and John Wawrzynek. More information
+is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
+arithmetic/SoftFloat.html'.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
+has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
+TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
+PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
+AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
+
+Derivative works are acceptable, even for commercial purposes, so long as
+(1) they include prominent notice that the work is derivative, and (2) they
+include prominent notice akin to these four paragraphs for those parts of
+this code that are retained.
+
+===============================================================================
+*/
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifdef SOFTFLOAT_FOR_GCC
+#include "softfloat-for-gcc.h"
+#endif
+
+#include "milieu.h"
+#include "softfloat.h"
+
+/*
+ * Conversions between floats as stored in memory and floats as
+ * SoftFloat uses them
+ */
+#ifndef FLOAT64_DEMANGLE
+#define FLOAT64_DEMANGLE(a) (a)
+#endif
+#ifndef FLOAT64_MANGLE
+#define FLOAT64_MANGLE(a) (a)
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Floating-point rounding mode and exception flags.
+-------------------------------------------------------------------------------
+*/
+int float_rounding_mode = float_round_nearest_even;
+int float_exception_flags = 0;
+
+/*
+-------------------------------------------------------------------------------
+Primitive arithmetic functions, including multi-word arithmetic, and
+division and square root approximations. (Can be specialized to target if
+desired.)
+-------------------------------------------------------------------------------
+*/
+#include "softfloat-macros"
+
+/*
+-------------------------------------------------------------------------------
+Functions and definitions to determine: (1) whether tininess for underflow
+is detected before or after rounding by default, (2) what (if anything)
+happens when exceptions are raised, (3) how signaling NaNs are distinguished
+from quiet NaNs, (4) the default generated quiet NaNs, and (4) how NaNs
+are propagated from function inputs to output. These details are target-
+specific.
+-------------------------------------------------------------------------------
+*/
+#include "softfloat-specialize"
+
+/*
+-------------------------------------------------------------------------------
+Returns the fraction bits of the single-precision floating-point value `a'.
+-------------------------------------------------------------------------------
+*/
+INLINE bits32 extractFloat32Frac( float32 a )
+{
+
+ return a & 0x007FFFFF;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the exponent bits of the single-precision floating-point value `a'.
+-------------------------------------------------------------------------------
+*/
+INLINE int16 extractFloat32Exp( float32 a )
+{
+
+ return ( a>>23 ) & 0xFF;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the sign bit of the single-precision floating-point value `a'.
+-------------------------------------------------------------------------------
+*/
+INLINE flag extractFloat32Sign( float32 a )
+{
+
+ return a>>31;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Normalizes the subnormal single-precision floating-point value represented
+by the denormalized significand `aSig'. The normalized exponent and
+significand are stored at the locations pointed to by `zExpPtr' and
+`zSigPtr', respectively.
+-------------------------------------------------------------------------------
+*/
+static void
+ normalizeFloat32Subnormal( bits32 aSig, int16 *zExpPtr, bits32 *zSigPtr )
+{
+ int8 shiftCount;
+
+ shiftCount = countLeadingZeros32( aSig ) - 8;
+ *zSigPtr = aSig<<shiftCount;
+ *zExpPtr = 1 - shiftCount;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Packs the sign `zSign', exponent `zExp', and significand `zSig' into a
+single-precision floating-point value, returning the result. After being
+shifted into the proper positions, the three fields are simply added
+together to form the result. This means that any integer portion of `zSig'
+will be added into the exponent. Since a properly normalized significand
+will have an integer portion equal to 1, the `zExp' input should be 1 less
+than the desired result exponent whenever `zSig' is a complete, normalized
+significand.
+-------------------------------------------------------------------------------
+*/
+INLINE float32 packFloat32( flag zSign, int16 zExp, bits32 zSig )
+{
+
+ return ( ( (bits32) zSign )<<31 ) + ( ( (bits32) zExp )<<23 ) + zSig;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Takes an abstract floating-point value having sign `zSign', exponent `zExp',
+and significand `zSig', and returns the proper single-precision floating-
+point value corresponding to the abstract input. Ordinarily, the abstract
+value is simply rounded and packed into the single-precision format, with
+the inexact exception raised if the abstract input cannot be represented
+exactly. However, if the abstract value is too large, the overflow and
+inexact exceptions are raised and an infinity or maximal finite value is
+returned. If the abstract value is too small, the input value is rounded to
+a subnormal number, and the underflow and inexact exceptions are raised if
+the abstract input cannot be represented exactly as a subnormal single-
+precision floating-point number.
+ The input significand `zSig' has its binary point between bits 30
+and 29, which is 7 bits to the left of the usual location. This shifted
+significand must be normalized or smaller. If `zSig' is not normalized,
+`zExp' must be 0; in that case, the result returned is a subnormal number,
+and it must not require rounding. In the usual case that `zSig' is
+normalized, `zExp' must be 1 less than the ``true'' floating-point exponent.
+The handling of underflow and overflow follows the IEC/IEEE Standard for
+Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+static float32 roundAndPackFloat32( flag zSign, int16 zExp, bits32 zSig )
+{
+ int8 roundingMode;
+ flag roundNearestEven;
+ int8 roundIncrement, roundBits;
+ flag isTiny;
+
+ roundingMode = float_rounding_mode;
+ roundNearestEven = roundingMode == float_round_nearest_even;
+ roundIncrement = 0x40;
+ if ( ! roundNearestEven ) {
+ if ( roundingMode == float_round_to_zero ) {
+ roundIncrement = 0;
+ }
+ else {
+ roundIncrement = 0x7F;
+ if ( zSign ) {
+ if ( roundingMode == float_round_up ) roundIncrement = 0;
+ }
+ else {
+ if ( roundingMode == float_round_down ) roundIncrement = 0;
+ }
+ }
+ }
+ roundBits = zSig & 0x7F;
+ if ( 0xFD <= (bits16) zExp ) {
+ if ( ( 0xFD < zExp )
+ || ( ( zExp == 0xFD )
+ && ( (sbits32) ( zSig + roundIncrement ) < 0 ) )
+ ) {
+ float_raise( float_flag_overflow | float_flag_inexact );
+ return packFloat32( zSign, 0xFF, 0 ) - ( roundIncrement == 0 );
+ }
+ if ( zExp < 0 ) {
+ isTiny =
+ ( float_detect_tininess == float_tininess_before_rounding )
+ || ( zExp < -1 )
+ || ( zSig + roundIncrement < 0x80000000 );
+ shift32RightJamming( zSig, - zExp, &zSig );
+ zExp = 0;
+ roundBits = zSig & 0x7F;
+ if ( isTiny && roundBits ) float_raise( float_flag_underflow );
+ }
+ }
+ if ( roundBits ) float_exception_flags |= float_flag_inexact;
+ zSig = ( zSig + roundIncrement )>>7;
+ zSig &= ~ ( ( ( roundBits ^ 0x40 ) == 0 ) & roundNearestEven );
+ if ( zSig == 0 ) zExp = 0;
+ return packFloat32( zSign, zExp, zSig );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Takes an abstract floating-point value having sign `zSign', exponent `zExp',
+and significand `zSig', and returns the proper single-precision floating-
+point value corresponding to the abstract input. This routine is just like
+`roundAndPackFloat32' except that `zSig' does not have to be normalized.
+Bit 31 of `zSig' must be zero, and `zExp' must be 1 less than the ``true''
+floating-point exponent.
+-------------------------------------------------------------------------------
+*/
+static float32
+ normalizeRoundAndPackFloat32( flag zSign, int16 zExp, bits32 zSig )
+{
+ int8 shiftCount;
+
+ shiftCount = countLeadingZeros32( zSig ) - 1;
+ return roundAndPackFloat32( zSign, zExp - shiftCount, zSig<<shiftCount );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the least-significant 32 fraction bits of the double-precision
+floating-point value `a'.
+-------------------------------------------------------------------------------
+*/
+INLINE bits32 extractFloat64Frac1( float64 a )
+{
+
+ return FLOAT64_DEMANGLE(a) & LIT64( 0x00000000FFFFFFFF );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the most-significant 20 fraction bits of the double-precision
+floating-point value `a'.
+-------------------------------------------------------------------------------
+*/
+INLINE bits32 extractFloat64Frac0( float64 a )
+{
+
+ return ( FLOAT64_DEMANGLE(a)>>32 ) & 0x000FFFFF;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the exponent bits of the double-precision floating-point value `a'.
+-------------------------------------------------------------------------------
+*/
+INLINE int16 extractFloat64Exp( float64 a )
+{
+
+ return ( FLOAT64_DEMANGLE(a)>>52 ) & 0x7FF;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the sign bit of the double-precision floating-point value `a'.
+-------------------------------------------------------------------------------
+*/
+INLINE flag extractFloat64Sign( float64 a )
+{
+
+ return FLOAT64_DEMANGLE(a)>>63;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Normalizes the subnormal double-precision floating-point value represented
+by the denormalized significand formed by the concatenation of `aSig0' and
+`aSig1'. The normalized exponent is stored at the location pointed to by
+`zExpPtr'. The most significant 21 bits of the normalized significand are
+stored at the location pointed to by `zSig0Ptr', and the least significant
+32 bits of the normalized significand are stored at the location pointed to
+by `zSig1Ptr'.
+-------------------------------------------------------------------------------
+*/
+static void
+ normalizeFloat64Subnormal(
+ bits32 aSig0,
+ bits32 aSig1,
+ int16 *zExpPtr,
+ bits32 *zSig0Ptr,
+ bits32 *zSig1Ptr
+ )
+{
+ int8 shiftCount;
+
+ if ( aSig0 == 0 ) {
+ shiftCount = countLeadingZeros32( aSig1 ) - 11;
+ if ( shiftCount < 0 ) {
+ *zSig0Ptr = aSig1>>( - shiftCount );
+ *zSig1Ptr = aSig1<<( shiftCount & 31 );
+ }
+ else {
+ *zSig0Ptr = aSig1<<shiftCount;
+ *zSig1Ptr = 0;
+ }
+ *zExpPtr = - shiftCount - 31;
+ }
+ else {
+ shiftCount = countLeadingZeros32( aSig0 ) - 11;
+ shortShift64Left( aSig0, aSig1, shiftCount, zSig0Ptr, zSig1Ptr );
+ *zExpPtr = 1 - shiftCount;
+ }
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Packs the sign `zSign', the exponent `zExp', and the significand formed by
+the concatenation of `zSig0' and `zSig1' into a double-precision floating-
+point value, returning the result. After being shifted into the proper
+positions, the three fields `zSign', `zExp', and `zSig0' are simply added
+together to form the most significant 32 bits of the result. This means
+that any integer portion of `zSig0' will be added into the exponent. Since
+a properly normalized significand will have an integer portion equal to 1,
+the `zExp' input should be 1 less than the desired result exponent whenever
+`zSig0' and `zSig1' concatenated form a complete, normalized significand.
+-------------------------------------------------------------------------------
+*/
+INLINE float64
+ packFloat64( flag zSign, int16 zExp, bits32 zSig0, bits32 zSig1 )
+{
+
+ return FLOAT64_MANGLE( ( ( (bits64) zSign )<<63 ) +
+ ( ( (bits64) zExp )<<52 ) +
+ ( ( (bits64) zSig0 )<<32 ) + zSig1 );
+
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Takes an abstract floating-point value having sign `zSign', exponent `zExp',
+and extended significand formed by the concatenation of `zSig0', `zSig1',
+and `zSig2', and returns the proper double-precision floating-point value
+corresponding to the abstract input. Ordinarily, the abstract value is
+simply rounded and packed into the double-precision format, with the inexact
+exception raised if the abstract input cannot be represented exactly.
+However, if the abstract value is too large, the overflow and inexact
+exceptions are raised and an infinity or maximal finite value is returned.
+If the abstract value is too small, the input value is rounded to a
+subnormal number, and the underflow and inexact exceptions are raised if the
+abstract input cannot be represented exactly as a subnormal double-precision
+floating-point number.
+ The input significand must be normalized or smaller. If the input
+significand is not normalized, `zExp' must be 0; in that case, the result
+returned is a subnormal number, and it must not require rounding. In the
+usual case that the input significand is normalized, `zExp' must be 1 less
+than the ``true'' floating-point exponent. The handling of underflow and
+overflow follows the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+static float64
+ roundAndPackFloat64(
+ flag zSign, int16 zExp, bits32 zSig0, bits32 zSig1, bits32 zSig2 )
+{
+ int8 roundingMode;
+ flag roundNearestEven, increment, isTiny;
+
+ roundingMode = float_rounding_mode;
+ roundNearestEven = ( roundingMode == float_round_nearest_even );
+ increment = ( (sbits32) zSig2 < 0 );
+ if ( ! roundNearestEven ) {
+ if ( roundingMode == float_round_to_zero ) {
+ increment = 0;
+ }
+ else {
+ if ( zSign ) {
+ increment = ( roundingMode == float_round_down ) && zSig2;
+ }
+ else {
+ increment = ( roundingMode == float_round_up ) && zSig2;
+ }
+ }
+ }
+ if ( 0x7FD <= (bits16) zExp ) {
+ if ( ( 0x7FD < zExp )
+ || ( ( zExp == 0x7FD )
+ && eq64( 0x001FFFFF, 0xFFFFFFFF, zSig0, zSig1 )
+ && increment
+ )
+ ) {
+ float_raise( float_flag_overflow | float_flag_inexact );
+ if ( ( roundingMode == float_round_to_zero )
+ || ( zSign && ( roundingMode == float_round_up ) )
+ || ( ! zSign && ( roundingMode == float_round_down ) )
+ ) {
+ return packFloat64( zSign, 0x7FE, 0x000FFFFF, 0xFFFFFFFF );
+ }
+ return packFloat64( zSign, 0x7FF, 0, 0 );
+ }
+ if ( zExp < 0 ) {
+ isTiny =
+ ( float_detect_tininess == float_tininess_before_rounding )
+ || ( zExp < -1 )
+ || ! increment
+ || lt64( zSig0, zSig1, 0x001FFFFF, 0xFFFFFFFF );
+ shift64ExtraRightJamming(
+ zSig0, zSig1, zSig2, - zExp, &zSig0, &zSig1, &zSig2 );
+ zExp = 0;
+ if ( isTiny && zSig2 ) float_raise( float_flag_underflow );
+ if ( roundNearestEven ) {
+ increment = ( (sbits32) zSig2 < 0 );
+ }
+ else {
+ if ( zSign ) {
+ increment = ( roundingMode == float_round_down ) && zSig2;
+ }
+ else {
+ increment = ( roundingMode == float_round_up ) && zSig2;
+ }
+ }
+ }
+ }
+ if ( zSig2 ) float_exception_flags |= float_flag_inexact;
+ if ( increment ) {
+ add64( zSig0, zSig1, 0, 1, &zSig0, &zSig1 );
+ zSig1 &= ~ ( ( zSig2 + zSig2 == 0 ) & roundNearestEven );
+ }
+ else {
+ if ( ( zSig0 | zSig1 ) == 0 ) zExp = 0;
+ }
+ return packFloat64( zSign, zExp, zSig0, zSig1 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Takes an abstract floating-point value having sign `zSign', exponent `zExp',
+and significand formed by the concatenation of `zSig0' and `zSig1', and
+returns the proper double-precision floating-point value corresponding
+to the abstract input. This routine is just like `roundAndPackFloat64'
+except that the input significand has fewer bits and does not have to be
+normalized. In all cases, `zExp' must be 1 less than the ``true'' floating-
+point exponent.
+-------------------------------------------------------------------------------
+*/
+static float64
+ normalizeRoundAndPackFloat64(
+ flag zSign, int16 zExp, bits32 zSig0, bits32 zSig1 )
+{
+ int8 shiftCount;
+ bits32 zSig2;
+
+ if ( zSig0 == 0 ) {
+ zSig0 = zSig1;
+ zSig1 = 0;
+ zExp -= 32;
+ }
+ shiftCount = countLeadingZeros32( zSig0 ) - 11;
+ if ( 0 <= shiftCount ) {
+ zSig2 = 0;
+ shortShift64Left( zSig0, zSig1, shiftCount, &zSig0, &zSig1 );
+ }
+ else {
+ shift64ExtraRightJamming(
+ zSig0, zSig1, 0, - shiftCount, &zSig0, &zSig1, &zSig2 );
+ }
+ zExp -= shiftCount;
+ return roundAndPackFloat64( zSign, zExp, zSig0, zSig1, zSig2 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the 32-bit two's complement integer `a' to
+the single-precision floating-point format. The conversion is performed
+according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float32 int32_to_float32( int32 a )
+{
+ flag zSign;
+
+ if ( a == 0 ) return 0;
+ if ( a == (sbits32) 0x80000000 ) return packFloat32( 1, 0x9E, 0 );
+ zSign = ( a < 0 );
+ return normalizeRoundAndPackFloat32( zSign, 0x9C, zSign ? - a : a );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the 32-bit two's complement integer `a' to
+the double-precision floating-point format. The conversion is performed
+according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float64 int32_to_float64( int32 a )
+{
+ flag zSign;
+ bits32 absA;
+ int8 shiftCount;
+ bits32 zSig0, zSig1;
+
+ if ( a == 0 ) return packFloat64( 0, 0, 0, 0 );
+ zSign = ( a < 0 );
+ absA = zSign ? - a : a;
+ shiftCount = countLeadingZeros32( absA ) - 11;
+ if ( 0 <= shiftCount ) {
+ zSig0 = absA<<shiftCount;
+ zSig1 = 0;
+ }
+ else {
+ shift64Right( absA, 0, - shiftCount, &zSig0, &zSig1 );
+ }
+ return packFloat64( zSign, 0x412 - shiftCount, zSig0, zSig1 );
+
+}
+
+#ifndef SOFTFLOAT_FOR_GCC
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the single-precision floating-point value
+`a' to the 32-bit two's complement integer format. The conversion is
+performed according to the IEC/IEEE Standard for Binary Floating-Point
+Arithmetic---which means in particular that the conversion is rounded
+according to the current rounding mode. If `a' is a NaN, the largest
+positive integer is returned. Otherwise, if the conversion overflows, the
+largest integer with the same sign as `a' is returned.
+-------------------------------------------------------------------------------
+*/
+int32 float32_to_int32( float32 a )
+{
+ flag aSign;
+ int16 aExp, shiftCount;
+ bits32 aSig, aSigExtra;
+ int32 z;
+ int8 roundingMode;
+
+ aSig = extractFloat32Frac( a );
+ aExp = extractFloat32Exp( a );
+ aSign = extractFloat32Sign( a );
+ shiftCount = aExp - 0x96;
+ if ( 0 <= shiftCount ) {
+ if ( 0x9E <= aExp ) {
+ if ( a != 0xCF000000 ) {
+ float_raise( float_flag_invalid );
+ if ( ! aSign || ( ( aExp == 0xFF ) && aSig ) ) {
+ return 0x7FFFFFFF;
+ }
+ }
+ return (sbits32) 0x80000000;
+ }
+ z = ( aSig | 0x00800000 )<<shiftCount;
+ if ( aSign ) z = - z;
+ }
+ else {
+ if ( aExp < 0x7E ) {
+ aSigExtra = aExp | aSig;
+ z = 0;
+ }
+ else {
+ aSig |= 0x00800000;
+ aSigExtra = aSig<<( shiftCount & 31 );
+ z = aSig>>( - shiftCount );
+ }
+ if ( aSigExtra ) float_exception_flags |= float_flag_inexact;
+ roundingMode = float_rounding_mode;
+ if ( roundingMode == float_round_nearest_even ) {
+ if ( (sbits32) aSigExtra < 0 ) {
+ ++z;
+ if ( (bits32) ( aSigExtra<<1 ) == 0 ) z &= ~1;
+ }
+ if ( aSign ) z = - z;
+ }
+ else {
+ aSigExtra = ( aSigExtra != 0 );
+ if ( aSign ) {
+ z += ( roundingMode == float_round_down ) & aSigExtra;
+ z = - z;
+ }
+ else {
+ z += ( roundingMode == float_round_up ) & aSigExtra;
+ }
+ }
+ }
+ return z;
+
+}
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the single-precision floating-point value
+`a' to the 32-bit two's complement integer format. The conversion is
+performed according to the IEC/IEEE Standard for Binary Floating-Point
+Arithmetic, except that the conversion is always rounded toward zero.
+If `a' is a NaN, the largest positive integer is returned. Otherwise, if
+the conversion overflows, the largest integer with the same sign as `a' is
+returned.
+-------------------------------------------------------------------------------
+*/
+int32 float32_to_int32_round_to_zero( float32 a )
+{
+ flag aSign;
+ int16 aExp, shiftCount;
+ bits32 aSig;
+ int32 z;
+
+ aSig = extractFloat32Frac( a );
+ aExp = extractFloat32Exp( a );
+ aSign = extractFloat32Sign( a );
+ shiftCount = aExp - 0x9E;
+ if ( 0 <= shiftCount ) {
+ if ( a != 0xCF000000 ) {
+ float_raise( float_flag_invalid );
+ if ( ! aSign || ( ( aExp == 0xFF ) && aSig ) ) return 0x7FFFFFFF;
+ }
+ return (sbits32) 0x80000000;
+ }
+ else if ( aExp <= 0x7E ) {
+ if ( aExp | aSig ) float_exception_flags |= float_flag_inexact;
+ return 0;
+ }
+ aSig = ( aSig | 0x00800000 )<<8;
+ z = aSig>>( - shiftCount );
+ if ( (bits32) ( aSig<<( shiftCount & 31 ) ) ) {
+ float_exception_flags |= float_flag_inexact;
+ }
+ if ( aSign ) z = - z;
+ return z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the single-precision floating-point value
+`a' to the double-precision floating-point format. The conversion is
+performed according to the IEC/IEEE Standard for Binary Floating-Point
+Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float64 float32_to_float64( float32 a )
+{
+ flag aSign;
+ int16 aExp;
+ bits32 aSig, zSig0, zSig1;
+
+ aSig = extractFloat32Frac( a );
+ aExp = extractFloat32Exp( a );
+ aSign = extractFloat32Sign( a );
+ if ( aExp == 0xFF ) {
+ if ( aSig ) return commonNaNToFloat64( float32ToCommonNaN( a ) );
+ return packFloat64( aSign, 0x7FF, 0, 0 );
+ }
+ if ( aExp == 0 ) {
+ if ( aSig == 0 ) return packFloat64( aSign, 0, 0, 0 );
+ normalizeFloat32Subnormal( aSig, &aExp, &aSig );
+ --aExp;
+ }
+ shift64Right( aSig, 0, 3, &zSig0, &zSig1 );
+ return packFloat64( aSign, aExp + 0x380, zSig0, zSig1 );
+
+}
+
+#ifndef SOFTFLOAT_FOR_GCC
+/*
+-------------------------------------------------------------------------------
+Rounds the single-precision floating-point value `a' to an integer,
+and returns the result as a single-precision floating-point value. The
+operation is performed according to the IEC/IEEE Standard for Binary
+Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float32 float32_round_to_int( float32 a )
+{
+ flag aSign;
+ int16 aExp;
+ bits32 lastBitMask, roundBitsMask;
+ int8 roundingMode;
+ float32 z;
+
+ aExp = extractFloat32Exp( a );
+ if ( 0x96 <= aExp ) {
+ if ( ( aExp == 0xFF ) && extractFloat32Frac( a ) ) {
+ return propagateFloat32NaN( a, a );
+ }
+ return a;
+ }
+ if ( aExp <= 0x7E ) {
+ if ( (bits32) ( a<<1 ) == 0 ) return a;
+ float_exception_flags |= float_flag_inexact;
+ aSign = extractFloat32Sign( a );
+ switch ( float_rounding_mode ) {
+ case float_round_nearest_even:
+ if ( ( aExp == 0x7E ) && extractFloat32Frac( a ) ) {
+ return packFloat32( aSign, 0x7F, 0 );
+ }
+ break;
+ case float_round_to_zero:
+ break;
+ case float_round_down:
+ return aSign ? 0xBF800000 : 0;
+ case float_round_up:
+ return aSign ? 0x80000000 : 0x3F800000;
+ }
+ return packFloat32( aSign, 0, 0 );
+ }
+ lastBitMask = 1;
+ lastBitMask <<= 0x96 - aExp;
+ roundBitsMask = lastBitMask - 1;
+ z = a;
+ roundingMode = float_rounding_mode;
+ if ( roundingMode == float_round_nearest_even ) {
+ z += lastBitMask>>1;
+ if ( ( z & roundBitsMask ) == 0 ) z &= ~ lastBitMask;
+ }
+ else if ( roundingMode != float_round_to_zero ) {
+ if ( extractFloat32Sign( z ) ^ ( roundingMode == float_round_up ) ) {
+ z += roundBitsMask;
+ }
+ }
+ z &= ~ roundBitsMask;
+ if ( z != a ) float_exception_flags |= float_flag_inexact;
+ return z;
+
+}
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of adding the absolute values of the single-precision
+floating-point values `a' and `b'. If `zSign' is 1, the sum is negated
+before being returned. `zSign' is ignored if the result is a NaN.
+The addition is performed according to the IEC/IEEE Standard for Binary
+Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+static float32 addFloat32Sigs( float32 a, float32 b, flag zSign )
+{
+ int16 aExp, bExp, zExp;
+ bits32 aSig, bSig, zSig;
+ int16 expDiff;
+
+ aSig = extractFloat32Frac( a );
+ aExp = extractFloat32Exp( a );
+ bSig = extractFloat32Frac( b );
+ bExp = extractFloat32Exp( b );
+ expDiff = aExp - bExp;
+ aSig <<= 6;
+ bSig <<= 6;
+ if ( 0 < expDiff ) {
+ if ( aExp == 0xFF ) {
+ if ( aSig ) return propagateFloat32NaN( a, b );
+ return a;
+ }
+ if ( bExp == 0 ) {
+ --expDiff;
+ }
+ else {
+ bSig |= 0x20000000;
+ }
+ shift32RightJamming( bSig, expDiff, &bSig );
+ zExp = aExp;
+ }
+ else if ( expDiff < 0 ) {
+ if ( bExp == 0xFF ) {
+ if ( bSig ) return propagateFloat32NaN( a, b );
+ return packFloat32( zSign, 0xFF, 0 );
+ }
+ if ( aExp == 0 ) {
+ ++expDiff;
+ }
+ else {
+ aSig |= 0x20000000;
+ }
+ shift32RightJamming( aSig, - expDiff, &aSig );
+ zExp = bExp;
+ }
+ else {
+ if ( aExp == 0xFF ) {
+ if ( aSig | bSig ) return propagateFloat32NaN( a, b );
+ return a;
+ }
+ if ( aExp == 0 ) return packFloat32( zSign, 0, ( aSig + bSig )>>6 );
+ zSig = 0x40000000 + aSig + bSig;
+ zExp = aExp;
+ goto roundAndPack;
+ }
+ aSig |= 0x20000000;
+ zSig = ( aSig + bSig )<<1;
+ --zExp;
+ if ( (sbits32) zSig < 0 ) {
+ zSig = aSig + bSig;
+ ++zExp;
+ }
+ roundAndPack:
+ return roundAndPackFloat32( zSign, zExp, zSig );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of subtracting the absolute values of the single-
+precision floating-point values `a' and `b'. If `zSign' is 1, the
+difference is negated before being returned. `zSign' is ignored if the
+result is a NaN. The subtraction is performed according to the IEC/IEEE
+Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+static float32 subFloat32Sigs( float32 a, float32 b, flag zSign )
+{
+ int16 aExp, bExp, zExp;
+ bits32 aSig, bSig, zSig;
+ int16 expDiff;
+
+ aSig = extractFloat32Frac( a );
+ aExp = extractFloat32Exp( a );
+ bSig = extractFloat32Frac( b );
+ bExp = extractFloat32Exp( b );
+ expDiff = aExp - bExp;
+ aSig <<= 7;
+ bSig <<= 7;
+ if ( 0 < expDiff ) goto aExpBigger;
+ if ( expDiff < 0 ) goto bExpBigger;
+ if ( aExp == 0xFF ) {
+ if ( aSig | bSig ) return propagateFloat32NaN( a, b );
+ float_raise( float_flag_invalid );
+ return float32_default_nan;
+ }
+ if ( aExp == 0 ) {
+ aExp = 1;
+ bExp = 1;
+ }
+ if ( bSig < aSig ) goto aBigger;
+ if ( aSig < bSig ) goto bBigger;
+ return packFloat32( float_rounding_mode == float_round_down, 0, 0 );
+ bExpBigger:
+ if ( bExp == 0xFF ) {
+ if ( bSig ) return propagateFloat32NaN( a, b );
+ return packFloat32( zSign ^ 1, 0xFF, 0 );
+ }
+ if ( aExp == 0 ) {
+ ++expDiff;
+ }
+ else {
+ aSig |= 0x40000000;
+ }
+ shift32RightJamming( aSig, - expDiff, &aSig );
+ bSig |= 0x40000000;
+ bBigger:
+ zSig = bSig - aSig;
+ zExp = bExp;
+ zSign ^= 1;
+ goto normalizeRoundAndPack;
+ aExpBigger:
+ if ( aExp == 0xFF ) {
+ if ( aSig ) return propagateFloat32NaN( a, b );
+ return a;
+ }
+ if ( bExp == 0 ) {
+ --expDiff;
+ }
+ else {
+ bSig |= 0x40000000;
+ }
+ shift32RightJamming( bSig, expDiff, &bSig );
+ aSig |= 0x40000000;
+ aBigger:
+ zSig = aSig - bSig;
+ zExp = aExp;
+ normalizeRoundAndPack:
+ --zExp;
+ return normalizeRoundAndPackFloat32( zSign, zExp, zSig );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of adding the single-precision floating-point values `a'
+and `b'. The operation is performed according to the IEC/IEEE Standard for
+Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float32 float32_add( float32 a, float32 b )
+{
+ flag aSign, bSign;
+
+ aSign = extractFloat32Sign( a );
+ bSign = extractFloat32Sign( b );
+ if ( aSign == bSign ) {
+ return addFloat32Sigs( a, b, aSign );
+ }
+ else {
+ return subFloat32Sigs( a, b, aSign );
+ }
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of subtracting the single-precision floating-point values
+`a' and `b'. The operation is performed according to the IEC/IEEE Standard
+for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float32 float32_sub( float32 a, float32 b )
+{
+ flag aSign, bSign;
+
+ aSign = extractFloat32Sign( a );
+ bSign = extractFloat32Sign( b );
+ if ( aSign == bSign ) {
+ return subFloat32Sigs( a, b, aSign );
+ }
+ else {
+ return addFloat32Sigs( a, b, aSign );
+ }
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of multiplying the single-precision floating-point values
+`a' and `b'. The operation is performed according to the IEC/IEEE Standard
+for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float32 float32_mul( float32 a, float32 b )
+{
+ flag aSign, bSign, zSign;
+ int16 aExp, bExp, zExp;
+ bits32 aSig, bSig, zSig0, zSig1;
+
+ aSig = extractFloat32Frac( a );
+ aExp = extractFloat32Exp( a );
+ aSign = extractFloat32Sign( a );
+ bSig = extractFloat32Frac( b );
+ bExp = extractFloat32Exp( b );
+ bSign = extractFloat32Sign( b );
+ zSign = aSign ^ bSign;
+ if ( aExp == 0xFF ) {
+ if ( aSig || ( ( bExp == 0xFF ) && bSig ) ) {
+ return propagateFloat32NaN( a, b );
+ }
+ if ( ( bExp | bSig ) == 0 ) {
+ float_raise( float_flag_invalid );
+ return float32_default_nan;
+ }
+ return packFloat32( zSign, 0xFF, 0 );
+ }
+ if ( bExp == 0xFF ) {
+ if ( bSig ) return propagateFloat32NaN( a, b );
+ if ( ( aExp | aSig ) == 0 ) {
+ float_raise( float_flag_invalid );
+ return float32_default_nan;
+ }
+ return packFloat32( zSign, 0xFF, 0 );
+ }
+ if ( aExp == 0 ) {
+ if ( aSig == 0 ) return packFloat32( zSign, 0, 0 );
+ normalizeFloat32Subnormal( aSig, &aExp, &aSig );
+ }
+ if ( bExp == 0 ) {
+ if ( bSig == 0 ) return packFloat32( zSign, 0, 0 );
+ normalizeFloat32Subnormal( bSig, &bExp, &bSig );
+ }
+ zExp = aExp + bExp - 0x7F;
+ aSig = ( aSig | 0x00800000 )<<7;
+ bSig = ( bSig | 0x00800000 )<<8;
+ mul32To64( aSig, bSig, &zSig0, &zSig1 );
+ zSig0 |= ( zSig1 != 0 );
+ if ( 0 <= (sbits32) ( zSig0<<1 ) ) {
+ zSig0 <<= 1;
+ --zExp;
+ }
+ return roundAndPackFloat32( zSign, zExp, zSig0 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of dividing the single-precision floating-point value `a'
+by the corresponding value `b'. The operation is performed according to the
+IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float32 float32_div( float32 a, float32 b )
+{
+ flag aSign, bSign, zSign;
+ int16 aExp, bExp, zExp;
+ bits32 aSig, bSig, zSig, rem0, rem1, term0, term1;
+
+ aSig = extractFloat32Frac( a );
+ aExp = extractFloat32Exp( a );
+ aSign = extractFloat32Sign( a );
+ bSig = extractFloat32Frac( b );
+ bExp = extractFloat32Exp( b );
+ bSign = extractFloat32Sign( b );
+ zSign = aSign ^ bSign;
+ if ( aExp == 0xFF ) {
+ if ( aSig ) return propagateFloat32NaN( a, b );
+ if ( bExp == 0xFF ) {
+ if ( bSig ) return propagateFloat32NaN( a, b );
+ float_raise( float_flag_invalid );
+ return float32_default_nan;
+ }
+ return packFloat32( zSign, 0xFF, 0 );
+ }
+ if ( bExp == 0xFF ) {
+ if ( bSig ) return propagateFloat32NaN( a, b );
+ return packFloat32( zSign, 0, 0 );
+ }
+ if ( bExp == 0 ) {
+ if ( bSig == 0 ) {
+ if ( ( aExp | aSig ) == 0 ) {
+ float_raise( float_flag_invalid );
+ return float32_default_nan;
+ }
+ float_raise( float_flag_divbyzero );
+ return packFloat32( zSign, 0xFF, 0 );
+ }
+ normalizeFloat32Subnormal( bSig, &bExp, &bSig );
+ }
+ if ( aExp == 0 ) {
+ if ( aSig == 0 ) return packFloat32( zSign, 0, 0 );
+ normalizeFloat32Subnormal( aSig, &aExp, &aSig );
+ }
+ zExp = aExp - bExp + 0x7D;
+ aSig = ( aSig | 0x00800000 )<<7;
+ bSig = ( bSig | 0x00800000 )<<8;
+ if ( bSig <= ( aSig + aSig ) ) {
+ aSig >>= 1;
+ ++zExp;
+ }
+ zSig = estimateDiv64To32( aSig, 0, bSig );
+ if ( ( zSig & 0x3F ) <= 2 ) {
+ mul32To64( bSig, zSig, &term0, &term1 );
+ sub64( aSig, 0, term0, term1, &rem0, &rem1 );
+ while ( (sbits32) rem0 < 0 ) {
+ --zSig;
+ add64( rem0, rem1, 0, bSig, &rem0, &rem1 );
+ }
+ zSig |= ( rem1 != 0 );
+ }
+ return roundAndPackFloat32( zSign, zExp, zSig );
+
+}
+
+#ifndef SOFTFLOAT_FOR_GCC
+/*
+-------------------------------------------------------------------------------
+Returns the remainder of the single-precision floating-point value `a'
+with respect to the corresponding value `b'. The operation is performed
+according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float32 float32_rem( float32 a, float32 b )
+{
+ flag aSign, bSign, zSign;
+ int16 aExp, bExp, expDiff;
+ bits32 aSig, bSig, q, allZero, alternateASig;
+ sbits32 sigMean;
+
+ aSig = extractFloat32Frac( a );
+ aExp = extractFloat32Exp( a );
+ aSign = extractFloat32Sign( a );
+ bSig = extractFloat32Frac( b );
+ bExp = extractFloat32Exp( b );
+ bSign = extractFloat32Sign( b );
+ if ( aExp == 0xFF ) {
+ if ( aSig || ( ( bExp == 0xFF ) && bSig ) ) {
+ return propagateFloat32NaN( a, b );
+ }
+ float_raise( float_flag_invalid );
+ return float32_default_nan;
+ }
+ if ( bExp == 0xFF ) {
+ if ( bSig ) return propagateFloat32NaN( a, b );
+ return a;
+ }
+ if ( bExp == 0 ) {
+ if ( bSig == 0 ) {
+ float_raise( float_flag_invalid );
+ return float32_default_nan;
+ }
+ normalizeFloat32Subnormal( bSig, &bExp, &bSig );
+ }
+ if ( aExp == 0 ) {
+ if ( aSig == 0 ) return a;
+ normalizeFloat32Subnormal( aSig, &aExp, &aSig );
+ }
+ expDiff = aExp - bExp;
+ aSig = ( aSig | 0x00800000 )<<8;
+ bSig = ( bSig | 0x00800000 )<<8;
+ if ( expDiff < 0 ) {
+ if ( expDiff < -1 ) return a;
+ aSig >>= 1;
+ }
+ q = ( bSig <= aSig );
+ if ( q ) aSig -= bSig;
+ expDiff -= 32;
+ while ( 0 < expDiff ) {
+ q = estimateDiv64To32( aSig, 0, bSig );
+ q = ( 2 < q ) ? q - 2 : 0;
+ aSig = - ( ( bSig>>2 ) * q );
+ expDiff -= 30;
+ }
+ expDiff += 32;
+ if ( 0 < expDiff ) {
+ q = estimateDiv64To32( aSig, 0, bSig );
+ q = ( 2 < q ) ? q - 2 : 0;
+ q >>= 32 - expDiff;
+ bSig >>= 2;
+ aSig = ( ( aSig>>1 )<<( expDiff - 1 ) ) - bSig * q;
+ }
+ else {
+ aSig >>= 2;
+ bSig >>= 2;
+ }
+ do {
+ alternateASig = aSig;
+ ++q;
+ aSig -= bSig;
+ } while ( 0 <= (sbits32) aSig );
+ sigMean = aSig + alternateASig;
+ if ( ( sigMean < 0 ) || ( ( sigMean == 0 ) && ( q & 1 ) ) ) {
+ aSig = alternateASig;
+ }
+ zSign = ( (sbits32) aSig < 0 );
+ if ( zSign ) aSig = - aSig;
+ return normalizeRoundAndPackFloat32( aSign ^ zSign, bExp, aSig );
+
+}
+#endif
+
+#ifndef SOFTFLOAT_FOR_GCC
+/*
+-------------------------------------------------------------------------------
+Returns the square root of the single-precision floating-point value `a'.
+The operation is performed according to the IEC/IEEE Standard for Binary
+Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float32 float32_sqrt( float32 a )
+{
+ flag aSign;
+ int16 aExp, zExp;
+ bits32 aSig, zSig, rem0, rem1, term0, term1;
+
+ aSig = extractFloat32Frac( a );
+ aExp = extractFloat32Exp( a );
+ aSign = extractFloat32Sign( a );
+ if ( aExp == 0xFF ) {
+ if ( aSig ) return propagateFloat32NaN( a, 0 );
+ if ( ! aSign ) return a;
+ float_raise( float_flag_invalid );
+ return float32_default_nan;
+ }
+ if ( aSign ) {
+ if ( ( aExp | aSig ) == 0 ) return a;
+ float_raise( float_flag_invalid );
+ return float32_default_nan;
+ }
+ if ( aExp == 0 ) {
+ if ( aSig == 0 ) return 0;
+ normalizeFloat32Subnormal( aSig, &aExp, &aSig );
+ }
+ zExp = ( ( aExp - 0x7F )>>1 ) + 0x7E;
+ aSig = ( aSig | 0x00800000 )<<8;
+ zSig = estimateSqrt32( aExp, aSig ) + 2;
+ if ( ( zSig & 0x7F ) <= 5 ) {
+ if ( zSig < 2 ) {
+ zSig = 0x7FFFFFFF;
+ goto roundAndPack;
+ }
+ else {
+ aSig >>= aExp & 1;
+ mul32To64( zSig, zSig, &term0, &term1 );
+ sub64( aSig, 0, term0, term1, &rem0, &rem1 );
+ while ( (sbits32) rem0 < 0 ) {
+ --zSig;
+ shortShift64Left( 0, zSig, 1, &term0, &term1 );
+ term1 |= 1;
+ add64( rem0, rem1, term0, term1, &rem0, &rem1 );
+ }
+ zSig |= ( ( rem0 | rem1 ) != 0 );
+ }
+ }
+ shift32RightJamming( zSig, 1, &zSig );
+ roundAndPack:
+ return roundAndPackFloat32( 0, zExp, zSig );
+
+}
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the single-precision floating-point value `a' is equal to
+the corresponding value `b', and 0 otherwise. The comparison is performed
+according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float32_eq( float32 a, float32 b )
+{
+
+ if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
+ || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
+ ) {
+ if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) {
+ float_raise( float_flag_invalid );
+ }
+ return 0;
+ }
+ return ( a == b ) || ( (bits32) ( ( a | b )<<1 ) == 0 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the single-precision floating-point value `a' is less than
+or equal to the corresponding value `b', and 0 otherwise. The comparison
+is performed according to the IEC/IEEE Standard for Binary Floating-Point
+Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float32_le( float32 a, float32 b )
+{
+ flag aSign, bSign;
+
+ if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
+ || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
+ ) {
+ float_raise( float_flag_invalid );
+ return 0;
+ }
+ aSign = extractFloat32Sign( a );
+ bSign = extractFloat32Sign( b );
+ if ( aSign != bSign ) return aSign || ( (bits32) ( ( a | b )<<1 ) == 0 );
+ return ( a == b ) || ( aSign ^ ( a < b ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the single-precision floating-point value `a' is less than
+the corresponding value `b', and 0 otherwise. The comparison is performed
+according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float32_lt( float32 a, float32 b )
+{
+ flag aSign, bSign;
+
+ if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
+ || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
+ ) {
+ float_raise( float_flag_invalid );
+ return 0;
+ }
+ aSign = extractFloat32Sign( a );
+ bSign = extractFloat32Sign( b );
+ if ( aSign != bSign ) return aSign && ( (bits32) ( ( a | b )<<1 ) != 0 );
+ return ( a != b ) && ( aSign ^ ( a < b ) );
+
+}
+
+#ifndef SOFTFLOAT_FOR_GCC /* Not needed */
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the single-precision floating-point value `a' is equal to
+the corresponding value `b', and 0 otherwise. The invalid exception is
+raised if either operand is a NaN. Otherwise, the comparison is performed
+according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float32_eq_signaling( float32 a, float32 b )
+{
+
+ if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
+ || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
+ ) {
+ float_raise( float_flag_invalid );
+ return 0;
+ }
+ return ( a == b ) || ( (bits32) ( ( a | b )<<1 ) == 0 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the single-precision floating-point value `a' is less than or
+equal to the corresponding value `b', and 0 otherwise. Quiet NaNs do not
+cause an exception. Otherwise, the comparison is performed according to the
+IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float32_le_quiet( float32 a, float32 b )
+{
+ flag aSign, bSign;
+ int16 aExp, bExp;
+
+ if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
+ || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
+ ) {
+ if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) {
+ float_raise( float_flag_invalid );
+ }
+ return 0;
+ }
+ aSign = extractFloat32Sign( a );
+ bSign = extractFloat32Sign( b );
+ if ( aSign != bSign ) return aSign || ( (bits32) ( ( a | b )<<1 ) == 0 );
+ return ( a == b ) || ( aSign ^ ( a < b ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the single-precision floating-point value `a' is less than
+the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an
+exception. Otherwise, the comparison is performed according to the IEC/IEEE
+Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float32_lt_quiet( float32 a, float32 b )
+{
+ flag aSign, bSign;
+
+ if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
+ || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
+ ) {
+ if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) {
+ float_raise( float_flag_invalid );
+ }
+ return 0;
+ }
+ aSign = extractFloat32Sign( a );
+ bSign = extractFloat32Sign( b );
+ if ( aSign != bSign ) return aSign && ( (bits32) ( ( a | b )<<1 ) != 0 );
+ return ( a != b ) && ( aSign ^ ( a < b ) );
+
+}
+#endif /* !SOFTFLOAT_FOR_GCC */
+
+#ifndef SOFTFLOAT_FOR_GCC /* Not needed */
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the double-precision floating-point value
+`a' to the 32-bit two's complement integer format. The conversion is
+performed according to the IEC/IEEE Standard for Binary Floating-Point
+Arithmetic---which means in particular that the conversion is rounded
+according to the current rounding mode. If `a' is a NaN, the largest
+positive integer is returned. Otherwise, if the conversion overflows, the
+largest integer with the same sign as `a' is returned.
+-------------------------------------------------------------------------------
+*/
+int32 float64_to_int32( float64 a )
+{
+ flag aSign;
+ int16 aExp, shiftCount;
+ bits32 aSig0, aSig1, absZ, aSigExtra;
+ int32 z;
+ int8 roundingMode;
+
+ aSig1 = extractFloat64Frac1( a );
+ aSig0 = extractFloat64Frac0( a );
+ aExp = extractFloat64Exp( a );
+ aSign = extractFloat64Sign( a );
+ shiftCount = aExp - 0x413;
+ if ( 0 <= shiftCount ) {
+ if ( 0x41E < aExp ) {
+ if ( ( aExp == 0x7FF ) && ( aSig0 | aSig1 ) ) aSign = 0;
+ goto invalid;
+ }
+ shortShift64Left(
+ aSig0 | 0x00100000, aSig1, shiftCount, &absZ, &aSigExtra );
+ if ( 0x80000000 < absZ ) goto invalid;
+ }
+ else {
+ aSig1 = ( aSig1 != 0 );
+ if ( aExp < 0x3FE ) {
+ aSigExtra = aExp | aSig0 | aSig1;
+ absZ = 0;
+ }
+ else {
+ aSig0 |= 0x00100000;
+ aSigExtra = ( aSig0<<( shiftCount & 31 ) ) | aSig1;
+ absZ = aSig0>>( - shiftCount );
+ }
+ }
+ roundingMode = float_rounding_mode;
+ if ( roundingMode == float_round_nearest_even ) {
+ if ( (sbits32) aSigExtra < 0 ) {
+ ++absZ;
+ if ( (bits32) ( aSigExtra<<1 ) == 0 ) absZ &= ~1;
+ }
+ z = aSign ? - absZ : absZ;
+ }
+ else {
+ aSigExtra = ( aSigExtra != 0 );
+ if ( aSign ) {
+ z = - ( absZ
+ + ( ( roundingMode == float_round_down ) & aSigExtra ) );
+ }
+ else {
+ z = absZ + ( ( roundingMode == float_round_up ) & aSigExtra );
+ }
+ }
+ if ( ( aSign ^ ( z < 0 ) ) && z ) {
+ invalid:
+ float_raise( float_flag_invalid );
+ return aSign ? (sbits32) 0x80000000 : 0x7FFFFFFF;
+ }
+ if ( aSigExtra ) float_exception_flags |= float_flag_inexact;
+ return z;
+
+}
+#endif /* !SOFTFLOAT_FOR_GCC */
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the double-precision floating-point value
+`a' to the 32-bit two's complement integer format. The conversion is
+performed according to the IEC/IEEE Standard for Binary Floating-Point
+Arithmetic, except that the conversion is always rounded toward zero.
+If `a' is a NaN, the largest positive integer is returned. Otherwise, if
+the conversion overflows, the largest integer with the same sign as `a' is
+returned.
+-------------------------------------------------------------------------------
+*/
+int32 float64_to_int32_round_to_zero( float64 a )
+{
+ flag aSign;
+ int16 aExp, shiftCount;
+ bits32 aSig0, aSig1, absZ, aSigExtra;
+ int32 z;
+
+ aSig1 = extractFloat64Frac1( a );
+ aSig0 = extractFloat64Frac0( a );
+ aExp = extractFloat64Exp( a );
+ aSign = extractFloat64Sign( a );
+ shiftCount = aExp - 0x413;
+ if ( 0 <= shiftCount ) {
+ if ( 0x41E < aExp ) {
+ if ( ( aExp == 0x7FF ) && ( aSig0 | aSig1 ) ) aSign = 0;
+ goto invalid;
+ }
+ shortShift64Left(
+ aSig0 | 0x00100000, aSig1, shiftCount, &absZ, &aSigExtra );
+ }
+ else {
+ if ( aExp < 0x3FF ) {
+ if ( aExp | aSig0 | aSig1 ) {
+ float_exception_flags |= float_flag_inexact;
+ }
+ return 0;
+ }
+ aSig0 |= 0x00100000;
+ aSigExtra = ( aSig0<<( shiftCount & 31 ) ) | aSig1;
+ absZ = aSig0>>( - shiftCount );
+ }
+ z = aSign ? - absZ : absZ;
+ if ( ( aSign ^ ( z < 0 ) ) && z ) {
+ invalid:
+ float_raise( float_flag_invalid );
+ return aSign ? (sbits32) 0x80000000 : 0x7FFFFFFF;
+ }
+ if ( aSigExtra ) float_exception_flags |= float_flag_inexact;
+ return z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the double-precision floating-point value
+`a' to the single-precision floating-point format. The conversion is
+performed according to the IEC/IEEE Standard for Binary Floating-Point
+Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float32 float64_to_float32( float64 a )
+{
+ flag aSign;
+ int16 aExp;
+ bits32 aSig0, aSig1, zSig;
+ bits32 allZero;
+
+ aSig1 = extractFloat64Frac1( a );
+ aSig0 = extractFloat64Frac0( a );
+ aExp = extractFloat64Exp( a );
+ aSign = extractFloat64Sign( a );
+ if ( aExp == 0x7FF ) {
+ if ( aSig0 | aSig1 ) {
+ return commonNaNToFloat32( float64ToCommonNaN( a ) );
+ }
+ return packFloat32( aSign, 0xFF, 0 );
+ }
+ shift64RightJamming( aSig0, aSig1, 22, &allZero, &zSig );
+ if ( aExp ) zSig |= 0x40000000;
+ return roundAndPackFloat32( aSign, aExp - 0x381, zSig );
+
+}
+
+#ifndef SOFTFLOAT_FOR_GCC
+/*
+-------------------------------------------------------------------------------
+Rounds the double-precision floating-point value `a' to an integer,
+and returns the result as a double-precision floating-point value. The
+operation is performed according to the IEC/IEEE Standard for Binary
+Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float64 float64_round_to_int( float64 a )
+{
+ flag aSign;
+ int16 aExp;
+ bits32 lastBitMask, roundBitsMask;
+ int8 roundingMode;
+ float64 z;
+
+ aExp = extractFloat64Exp( a );
+ if ( 0x413 <= aExp ) {
+ if ( 0x433 <= aExp ) {
+ if ( ( aExp == 0x7FF )
+ && ( extractFloat64Frac0( a ) | extractFloat64Frac1( a ) ) ) {
+ return propagateFloat64NaN( a, a );
+ }
+ return a;
+ }
+ lastBitMask = 1;
+ lastBitMask = ( lastBitMask<<( 0x432 - aExp ) )<<1;
+ roundBitsMask = lastBitMask - 1;
+ z = a;
+ roundingMode = float_rounding_mode;
+ if ( roundingMode == float_round_nearest_even ) {
+ if ( lastBitMask ) {
+ add64( z.high, z.low, 0, lastBitMask>>1, &z.high, &z.low );
+ if ( ( z.low & roundBitsMask ) == 0 ) z.low &= ~ lastBitMask;
+ }
+ else {
+ if ( (sbits32) z.low < 0 ) {
+ ++z.high;
+ if ( (bits32) ( z.low<<1 ) == 0 ) z.high &= ~1;
+ }
+ }
+ }
+ else if ( roundingMode != float_round_to_zero ) {
+ if ( extractFloat64Sign( z )
+ ^ ( roundingMode == float_round_up ) ) {
+ add64( z.high, z.low, 0, roundBitsMask, &z.high, &z.low );
+ }
+ }
+ z.low &= ~ roundBitsMask;
+ }
+ else {
+ if ( aExp <= 0x3FE ) {
+ if ( ( ( (bits32) ( a.high<<1 ) ) | a.low ) == 0 ) return a;
+ float_exception_flags |= float_flag_inexact;
+ aSign = extractFloat64Sign( a );
+ switch ( float_rounding_mode ) {
+ case float_round_nearest_even:
+ if ( ( aExp == 0x3FE )
+ && ( extractFloat64Frac0( a ) | extractFloat64Frac1( a ) )
+ ) {
+ return packFloat64( aSign, 0x3FF, 0, 0 );
+ }
+ break;
+ case float_round_down:
+ return
+ aSign ? packFloat64( 1, 0x3FF, 0, 0 )
+ : packFloat64( 0, 0, 0, 0 );
+ case float_round_up:
+ return
+ aSign ? packFloat64( 1, 0, 0, 0 )
+ : packFloat64( 0, 0x3FF, 0, 0 );
+ }
+ return packFloat64( aSign, 0, 0, 0 );
+ }
+ lastBitMask = 1;
+ lastBitMask <<= 0x413 - aExp;
+ roundBitsMask = lastBitMask - 1;
+ z.low = 0;
+ z.high = a.high;
+ roundingMode = float_rounding_mode;
+ if ( roundingMode == float_round_nearest_even ) {
+ z.high += lastBitMask>>1;
+ if ( ( ( z.high & roundBitsMask ) | a.low ) == 0 ) {
+ z.high &= ~ lastBitMask;
+ }
+ }
+ else if ( roundingMode != float_round_to_zero ) {
+ if ( extractFloat64Sign( z )
+ ^ ( roundingMode == float_round_up ) ) {
+ z.high |= ( a.low != 0 );
+ z.high += roundBitsMask;
+ }
+ }
+ z.high &= ~ roundBitsMask;
+ }
+ if ( ( z.low != a.low ) || ( z.high != a.high ) ) {
+ float_exception_flags |= float_flag_inexact;
+ }
+ return z;
+
+}
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of adding the absolute values of the double-precision
+floating-point values `a' and `b'. If `zSign' is 1, the sum is negated
+before being returned. `zSign' is ignored if the result is a NaN.
+The addition is performed according to the IEC/IEEE Standard for Binary
+Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+static float64 addFloat64Sigs( float64 a, float64 b, flag zSign )
+{
+ int16 aExp, bExp, zExp;
+ bits32 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2;
+ int16 expDiff;
+
+ aSig1 = extractFloat64Frac1( a );
+ aSig0 = extractFloat64Frac0( a );
+ aExp = extractFloat64Exp( a );
+ bSig1 = extractFloat64Frac1( b );
+ bSig0 = extractFloat64Frac0( b );
+ bExp = extractFloat64Exp( b );
+ expDiff = aExp - bExp;
+ if ( 0 < expDiff ) {
+ if ( aExp == 0x7FF ) {
+ if ( aSig0 | aSig1 ) return propagateFloat64NaN( a, b );
+ return a;
+ }
+ if ( bExp == 0 ) {
+ --expDiff;
+ }
+ else {
+ bSig0 |= 0x00100000;
+ }
+ shift64ExtraRightJamming(
+ bSig0, bSig1, 0, expDiff, &bSig0, &bSig1, &zSig2 );
+ zExp = aExp;
+ }
+ else if ( expDiff < 0 ) {
+ if ( bExp == 0x7FF ) {
+ if ( bSig0 | bSig1 ) return propagateFloat64NaN( a, b );
+ return packFloat64( zSign, 0x7FF, 0, 0 );
+ }
+ if ( aExp == 0 ) {
+ ++expDiff;
+ }
+ else {
+ aSig0 |= 0x00100000;
+ }
+ shift64ExtraRightJamming(
+ aSig0, aSig1, 0, - expDiff, &aSig0, &aSig1, &zSig2 );
+ zExp = bExp;
+ }
+ else {
+ if ( aExp == 0x7FF ) {
+ if ( aSig0 | aSig1 | bSig0 | bSig1 ) {
+ return propagateFloat64NaN( a, b );
+ }
+ return a;
+ }
+ add64( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 );
+ if ( aExp == 0 ) return packFloat64( zSign, 0, zSig0, zSig1 );
+ zSig2 = 0;
+ zSig0 |= 0x00200000;
+ zExp = aExp;
+ goto shiftRight1;
+ }
+ aSig0 |= 0x00100000;
+ add64( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 );
+ --zExp;
+ if ( zSig0 < 0x00200000 ) goto roundAndPack;
+ ++zExp;
+ shiftRight1:
+ shift64ExtraRightJamming( zSig0, zSig1, zSig2, 1, &zSig0, &zSig1, &zSig2 );
+ roundAndPack:
+ return roundAndPackFloat64( zSign, zExp, zSig0, zSig1, zSig2 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of subtracting the absolute values of the double-
+precision floating-point values `a' and `b'. If `zSign' is 1, the
+difference is negated before being returned. `zSign' is ignored if the
+result is a NaN. The subtraction is performed according to the IEC/IEEE
+Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+static float64 subFloat64Sigs( float64 a, float64 b, flag zSign )
+{
+ int16 aExp, bExp, zExp;
+ bits32 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1;
+ int16 expDiff;
+
+ aSig1 = extractFloat64Frac1( a );
+ aSig0 = extractFloat64Frac0( a );
+ aExp = extractFloat64Exp( a );
+ bSig1 = extractFloat64Frac1( b );
+ bSig0 = extractFloat64Frac0( b );
+ bExp = extractFloat64Exp( b );
+ expDiff = aExp - bExp;
+ shortShift64Left( aSig0, aSig1, 10, &aSig0, &aSig1 );
+ shortShift64Left( bSig0, bSig1, 10, &bSig0, &bSig1 );
+ if ( 0 < expDiff ) goto aExpBigger;
+ if ( expDiff < 0 ) goto bExpBigger;
+ if ( aExp == 0x7FF ) {
+ if ( aSig0 | aSig1 | bSig0 | bSig1 ) {
+ return propagateFloat64NaN( a, b );
+ }
+ float_raise( float_flag_invalid );
+ return float64_default_nan;
+ }
+ if ( aExp == 0 ) {
+ aExp = 1;
+ bExp = 1;
+ }
+ if ( bSig0 < aSig0 ) goto aBigger;
+ if ( aSig0 < bSig0 ) goto bBigger;
+ if ( bSig1 < aSig1 ) goto aBigger;
+ if ( aSig1 < bSig1 ) goto bBigger;
+ return packFloat64( float_rounding_mode == float_round_down, 0, 0, 0 );
+ bExpBigger:
+ if ( bExp == 0x7FF ) {
+ if ( bSig0 | bSig1 ) return propagateFloat64NaN( a, b );
+ return packFloat64( zSign ^ 1, 0x7FF, 0, 0 );
+ }
+ if ( aExp == 0 ) {
+ ++expDiff;
+ }
+ else {
+ aSig0 |= 0x40000000;
+ }
+ shift64RightJamming( aSig0, aSig1, - expDiff, &aSig0, &aSig1 );
+ bSig0 |= 0x40000000;
+ bBigger:
+ sub64( bSig0, bSig1, aSig0, aSig1, &zSig0, &zSig1 );
+ zExp = bExp;
+ zSign ^= 1;
+ goto normalizeRoundAndPack;
+ aExpBigger:
+ if ( aExp == 0x7FF ) {
+ if ( aSig0 | aSig1 ) return propagateFloat64NaN( a, b );
+ return a;
+ }
+ if ( bExp == 0 ) {
+ --expDiff;
+ }
+ else {
+ bSig0 |= 0x40000000;
+ }
+ shift64RightJamming( bSig0, bSig1, expDiff, &bSig0, &bSig1 );
+ aSig0 |= 0x40000000;
+ aBigger:
+ sub64( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 );
+ zExp = aExp;
+ normalizeRoundAndPack:
+ --zExp;
+ return normalizeRoundAndPackFloat64( zSign, zExp - 10, zSig0, zSig1 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of adding the double-precision floating-point values `a'
+and `b'. The operation is performed according to the IEC/IEEE Standard for
+Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float64 float64_add( float64 a, float64 b )
+{
+ flag aSign, bSign;
+
+ aSign = extractFloat64Sign( a );
+ bSign = extractFloat64Sign( b );
+ if ( aSign == bSign ) {
+ return addFloat64Sigs( a, b, aSign );
+ }
+ else {
+ return subFloat64Sigs( a, b, aSign );
+ }
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of subtracting the double-precision floating-point values
+`a' and `b'. The operation is performed according to the IEC/IEEE Standard
+for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float64 float64_sub( float64 a, float64 b )
+{
+ flag aSign, bSign;
+
+ aSign = extractFloat64Sign( a );
+ bSign = extractFloat64Sign( b );
+ if ( aSign == bSign ) {
+ return subFloat64Sigs( a, b, aSign );
+ }
+ else {
+ return addFloat64Sigs( a, b, aSign );
+ }
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of multiplying the double-precision floating-point values
+`a' and `b'. The operation is performed according to the IEC/IEEE Standard
+for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float64 float64_mul( float64 a, float64 b )
+{
+ flag aSign, bSign, zSign;
+ int16 aExp, bExp, zExp;
+ bits32 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2, zSig3;
+
+ aSig1 = extractFloat64Frac1( a );
+ aSig0 = extractFloat64Frac0( a );
+ aExp = extractFloat64Exp( a );
+ aSign = extractFloat64Sign( a );
+ bSig1 = extractFloat64Frac1( b );
+ bSig0 = extractFloat64Frac0( b );
+ bExp = extractFloat64Exp( b );
+ bSign = extractFloat64Sign( b );
+ zSign = aSign ^ bSign;
+ if ( aExp == 0x7FF ) {
+ if ( ( aSig0 | aSig1 )
+ || ( ( bExp == 0x7FF ) && ( bSig0 | bSig1 ) ) ) {
+ return propagateFloat64NaN( a, b );
+ }
+ if ( ( bExp | bSig0 | bSig1 ) == 0 ) goto invalid;
+ return packFloat64( zSign, 0x7FF, 0, 0 );
+ }
+ if ( bExp == 0x7FF ) {
+ if ( bSig0 | bSig1 ) return propagateFloat64NaN( a, b );
+ if ( ( aExp | aSig0 | aSig1 ) == 0 ) {
+ invalid:
+ float_raise( float_flag_invalid );
+ return float64_default_nan;
+ }
+ return packFloat64( zSign, 0x7FF, 0, 0 );
+ }
+ if ( aExp == 0 ) {
+ if ( ( aSig0 | aSig1 ) == 0 ) return packFloat64( zSign, 0, 0, 0 );
+ normalizeFloat64Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 );
+ }
+ if ( bExp == 0 ) {
+ if ( ( bSig0 | bSig1 ) == 0 ) return packFloat64( zSign, 0, 0, 0 );
+ normalizeFloat64Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 );
+ }
+ zExp = aExp + bExp - 0x400;
+ aSig0 |= 0x00100000;
+ shortShift64Left( bSig0, bSig1, 12, &bSig0, &bSig1 );
+ mul64To128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1, &zSig2, &zSig3 );
+ add64( zSig0, zSig1, aSig0, aSig1, &zSig0, &zSig1 );
+ zSig2 |= ( zSig3 != 0 );
+ if ( 0x00200000 <= zSig0 ) {
+ shift64ExtraRightJamming(
+ zSig0, zSig1, zSig2, 1, &zSig0, &zSig1, &zSig2 );
+ ++zExp;
+ }
+ return roundAndPackFloat64( zSign, zExp, zSig0, zSig1, zSig2 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of dividing the double-precision floating-point value `a'
+by the corresponding value `b'. The operation is performed according to the
+IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float64 float64_div( float64 a, float64 b )
+{
+ flag aSign, bSign, zSign;
+ int16 aExp, bExp, zExp;
+ bits32 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2;
+ bits32 rem0, rem1, rem2, rem3, term0, term1, term2, term3;
+
+ aSig1 = extractFloat64Frac1( a );
+ aSig0 = extractFloat64Frac0( a );
+ aExp = extractFloat64Exp( a );
+ aSign = extractFloat64Sign( a );
+ bSig1 = extractFloat64Frac1( b );
+ bSig0 = extractFloat64Frac0( b );
+ bExp = extractFloat64Exp( b );
+ bSign = extractFloat64Sign( b );
+ zSign = aSign ^ bSign;
+ if ( aExp == 0x7FF ) {
+ if ( aSig0 | aSig1 ) return propagateFloat64NaN( a, b );
+ if ( bExp == 0x7FF ) {
+ if ( bSig0 | bSig1 ) return propagateFloat64NaN( a, b );
+ goto invalid;
+ }
+ return packFloat64( zSign, 0x7FF, 0, 0 );
+ }
+ if ( bExp == 0x7FF ) {
+ if ( bSig0 | bSig1 ) return propagateFloat64NaN( a, b );
+ return packFloat64( zSign, 0, 0, 0 );
+ }
+ if ( bExp == 0 ) {
+ if ( ( bSig0 | bSig1 ) == 0 ) {
+ if ( ( aExp | aSig0 | aSig1 ) == 0 ) {
+ invalid:
+ float_raise( float_flag_invalid );
+ return float64_default_nan;
+ }
+ float_raise( float_flag_divbyzero );
+ return packFloat64( zSign, 0x7FF, 0, 0 );
+ }
+ normalizeFloat64Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 );
+ }
+ if ( aExp == 0 ) {
+ if ( ( aSig0 | aSig1 ) == 0 ) return packFloat64( zSign, 0, 0, 0 );
+ normalizeFloat64Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 );
+ }
+ zExp = aExp - bExp + 0x3FD;
+ shortShift64Left( aSig0 | 0x00100000, aSig1, 11, &aSig0, &aSig1 );
+ shortShift64Left( bSig0 | 0x00100000, bSig1, 11, &bSig0, &bSig1 );
+ if ( le64( bSig0, bSig1, aSig0, aSig1 ) ) {
+ shift64Right( aSig0, aSig1, 1, &aSig0, &aSig1 );
+ ++zExp;
+ }
+ zSig0 = estimateDiv64To32( aSig0, aSig1, bSig0 );
+ mul64By32To96( bSig0, bSig1, zSig0, &term0, &term1, &term2 );
+ sub96( aSig0, aSig1, 0, term0, term1, term2, &rem0, &rem1, &rem2 );
+ while ( (sbits32) rem0 < 0 ) {
+ --zSig0;
+ add96( rem0, rem1, rem2, 0, bSig0, bSig1, &rem0, &rem1, &rem2 );
+ }
+ zSig1 = estimateDiv64To32( rem1, rem2, bSig0 );
+ if ( ( zSig1 & 0x3FF ) <= 4 ) {
+ mul64By32To96( bSig0, bSig1, zSig1, &term1, &term2, &term3 );
+ sub96( rem1, rem2, 0, term1, term2, term3, &rem1, &rem2, &rem3 );
+ while ( (sbits32) rem1 < 0 ) {
+ --zSig1;
+ add96( rem1, rem2, rem3, 0, bSig0, bSig1, &rem1, &rem2, &rem3 );
+ }
+ zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 );
+ }
+ shift64ExtraRightJamming( zSig0, zSig1, 0, 11, &zSig0, &zSig1, &zSig2 );
+ return roundAndPackFloat64( zSign, zExp, zSig0, zSig1, zSig2 );
+
+}
+
+#ifndef SOFTFLOAT_FOR_GCC
+/*
+-------------------------------------------------------------------------------
+Returns the remainder of the double-precision floating-point value `a'
+with respect to the corresponding value `b'. The operation is performed
+according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float64 float64_rem( float64 a, float64 b )
+{
+ flag aSign, bSign, zSign;
+ int16 aExp, bExp, expDiff;
+ bits32 aSig0, aSig1, bSig0, bSig1, q, term0, term1, term2;
+ bits32 allZero, alternateASig0, alternateASig1, sigMean1;
+ sbits32 sigMean0;
+ float64 z;
+
+ aSig1 = extractFloat64Frac1( a );
+ aSig0 = extractFloat64Frac0( a );
+ aExp = extractFloat64Exp( a );
+ aSign = extractFloat64Sign( a );
+ bSig1 = extractFloat64Frac1( b );
+ bSig0 = extractFloat64Frac0( b );
+ bExp = extractFloat64Exp( b );
+ bSign = extractFloat64Sign( b );
+ if ( aExp == 0x7FF ) {
+ if ( ( aSig0 | aSig1 )
+ || ( ( bExp == 0x7FF ) && ( bSig0 | bSig1 ) ) ) {
+ return propagateFloat64NaN( a, b );
+ }
+ goto invalid;
+ }
+ if ( bExp == 0x7FF ) {
+ if ( bSig0 | bSig1 ) return propagateFloat64NaN( a, b );
+ return a;
+ }
+ if ( bExp == 0 ) {
+ if ( ( bSig0 | bSig1 ) == 0 ) {
+ invalid:
+ float_raise( float_flag_invalid );
+ return float64_default_nan;
+ }
+ normalizeFloat64Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 );
+ }
+ if ( aExp == 0 ) {
+ if ( ( aSig0 | aSig1 ) == 0 ) return a;
+ normalizeFloat64Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 );
+ }
+ expDiff = aExp - bExp;
+ if ( expDiff < -1 ) return a;
+ shortShift64Left(
+ aSig0 | 0x00100000, aSig1, 11 - ( expDiff < 0 ), &aSig0, &aSig1 );
+ shortShift64Left( bSig0 | 0x00100000, bSig1, 11, &bSig0, &bSig1 );
+ q = le64( bSig0, bSig1, aSig0, aSig1 );
+ if ( q ) sub64( aSig0, aSig1, bSig0, bSig1, &aSig0, &aSig1 );
+ expDiff -= 32;
+ while ( 0 < expDiff ) {
+ q = estimateDiv64To32( aSig0, aSig1, bSig0 );
+ q = ( 4 < q ) ? q - 4 : 0;
+ mul64By32To96( bSig0, bSig1, q, &term0, &term1, &term2 );
+ shortShift96Left( term0, term1, term2, 29, &term1, &term2, &allZero );
+ shortShift64Left( aSig0, aSig1, 29, &aSig0, &allZero );
+ sub64( aSig0, 0, term1, term2, &aSig0, &aSig1 );
+ expDiff -= 29;
+ }
+ if ( -32 < expDiff ) {
+ q = estimateDiv64To32( aSig0, aSig1, bSig0 );
+ q = ( 4 < q ) ? q - 4 : 0;
+ q >>= - expDiff;
+ shift64Right( bSig0, bSig1, 8, &bSig0, &bSig1 );
+ expDiff += 24;
+ if ( expDiff < 0 ) {
+ shift64Right( aSig0, aSig1, - expDiff, &aSig0, &aSig1 );
+ }
+ else {
+ shortShift64Left( aSig0, aSig1, expDiff, &aSig0, &aSig1 );
+ }
+ mul64By32To96( bSig0, bSig1, q, &term0, &term1, &term2 );
+ sub64( aSig0, aSig1, term1, term2, &aSig0, &aSig1 );
+ }
+ else {
+ shift64Right( aSig0, aSig1, 8, &aSig0, &aSig1 );
+ shift64Right( bSig0, bSig1, 8, &bSig0, &bSig1 );
+ }
+ do {
+ alternateASig0 = aSig0;
+ alternateASig1 = aSig1;
+ ++q;
+ sub64( aSig0, aSig1, bSig0, bSig1, &aSig0, &aSig1 );
+ } while ( 0 <= (sbits32) aSig0 );
+ add64(
+ aSig0, aSig1, alternateASig0, alternateASig1, &sigMean0, &sigMean1 );
+ if ( ( sigMean0 < 0 )
+ || ( ( ( sigMean0 | sigMean1 ) == 0 ) && ( q & 1 ) ) ) {
+ aSig0 = alternateASig0;
+ aSig1 = alternateASig1;
+ }
+ zSign = ( (sbits32) aSig0 < 0 );
+ if ( zSign ) sub64( 0, 0, aSig0, aSig1, &aSig0, &aSig1 );
+ return
+ normalizeRoundAndPackFloat64( aSign ^ zSign, bExp - 4, aSig0, aSig1 );
+
+}
+#endif
+
+#ifndef SOFTFLOAT_FOR_GCC
+/*
+-------------------------------------------------------------------------------
+Returns the square root of the double-precision floating-point value `a'.
+The operation is performed according to the IEC/IEEE Standard for Binary
+Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float64 float64_sqrt( float64 a )
+{
+ flag aSign;
+ int16 aExp, zExp;
+ bits32 aSig0, aSig1, zSig0, zSig1, zSig2, doubleZSig0;
+ bits32 rem0, rem1, rem2, rem3, term0, term1, term2, term3;
+ float64 z;
+
+ aSig1 = extractFloat64Frac1( a );
+ aSig0 = extractFloat64Frac0( a );
+ aExp = extractFloat64Exp( a );
+ aSign = extractFloat64Sign( a );
+ if ( aExp == 0x7FF ) {
+ if ( aSig0 | aSig1 ) return propagateFloat64NaN( a, a );
+ if ( ! aSign ) return a;
+ goto invalid;
+ }
+ if ( aSign ) {
+ if ( ( aExp | aSig0 | aSig1 ) == 0 ) return a;
+ invalid:
+ float_raise( float_flag_invalid );
+ return float64_default_nan;
+ }
+ if ( aExp == 0 ) {
+ if ( ( aSig0 | aSig1 ) == 0 ) return packFloat64( 0, 0, 0, 0 );
+ normalizeFloat64Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 );
+ }
+ zExp = ( ( aExp - 0x3FF )>>1 ) + 0x3FE;
+ aSig0 |= 0x00100000;
+ shortShift64Left( aSig0, aSig1, 11, &term0, &term1 );
+ zSig0 = ( estimateSqrt32( aExp, term0 )>>1 ) + 1;
+ if ( zSig0 == 0 ) zSig0 = 0x7FFFFFFF;
+ doubleZSig0 = zSig0 + zSig0;
+ shortShift64Left( aSig0, aSig1, 9 - ( aExp & 1 ), &aSig0, &aSig1 );
+ mul32To64( zSig0, zSig0, &term0, &term1 );
+ sub64( aSig0, aSig1, term0, term1, &rem0, &rem1 );
+ while ( (sbits32) rem0 < 0 ) {
+ --zSig0;
+ doubleZSig0 -= 2;
+ add64( rem0, rem1, 0, doubleZSig0 | 1, &rem0, &rem1 );
+ }
+ zSig1 = estimateDiv64To32( rem1, 0, doubleZSig0 );
+ if ( ( zSig1 & 0x1FF ) <= 5 ) {
+ if ( zSig1 == 0 ) zSig1 = 1;
+ mul32To64( doubleZSig0, zSig1, &term1, &term2 );
+ sub64( rem1, 0, term1, term2, &rem1, &rem2 );
+ mul32To64( zSig1, zSig1, &term2, &term3 );
+ sub96( rem1, rem2, 0, 0, term2, term3, &rem1, &rem2, &rem3 );
+ while ( (sbits32) rem1 < 0 ) {
+ --zSig1;
+ shortShift64Left( 0, zSig1, 1, &term2, &term3 );
+ term3 |= 1;
+ term2 |= doubleZSig0;
+ add96( rem1, rem2, rem3, 0, term2, term3, &rem1, &rem2, &rem3 );
+ }
+ zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 );
+ }
+ shift64ExtraRightJamming( zSig0, zSig1, 0, 10, &zSig0, &zSig1, &zSig2 );
+ return roundAndPackFloat64( 0, zExp, zSig0, zSig1, zSig2 );
+
+}
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the double-precision floating-point value `a' is equal to
+the corresponding value `b', and 0 otherwise. The comparison is performed
+according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float64_eq( float64 a, float64 b )
+{
+
+ if ( ( ( extractFloat64Exp( a ) == 0x7FF )
+ && ( extractFloat64Frac0( a ) | extractFloat64Frac1( a ) ) )
+ || ( ( extractFloat64Exp( b ) == 0x7FF )
+ && ( extractFloat64Frac0( b ) | extractFloat64Frac1( b ) ) )
+ ) {
+ if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) {
+ float_raise( float_flag_invalid );
+ }
+ return 0;
+ }
+ return ( a == b ) ||
+ ( (bits64) ( ( FLOAT64_DEMANGLE(a) | FLOAT64_DEMANGLE(b) )<<1 ) == 0 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the double-precision floating-point value `a' is less than
+or equal to the corresponding value `b', and 0 otherwise. The comparison
+is performed according to the IEC/IEEE Standard for Binary Floating-Point
+Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float64_le( float64 a, float64 b )
+{
+ flag aSign, bSign;
+
+ if ( ( ( extractFloat64Exp( a ) == 0x7FF )
+ && ( extractFloat64Frac0( a ) | extractFloat64Frac1( a ) ) )
+ || ( ( extractFloat64Exp( b ) == 0x7FF )
+ && ( extractFloat64Frac0( b ) | extractFloat64Frac1( b ) ) )
+ ) {
+ float_raise( float_flag_invalid );
+ return 0;
+ }
+ aSign = extractFloat64Sign( a );
+ bSign = extractFloat64Sign( b );
+ if ( aSign != bSign )
+ return aSign ||
+ ( (bits64) ( ( FLOAT64_DEMANGLE(a) | FLOAT64_DEMANGLE(b) )<<1 ) ==
+ 0 );
+ return ( a == b ) ||
+ ( aSign ^ ( FLOAT64_DEMANGLE(a) < FLOAT64_DEMANGLE(b) ) );
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the double-precision floating-point value `a' is less than
+the corresponding value `b', and 0 otherwise. The comparison is performed
+according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float64_lt( float64 a, float64 b )
+{
+ flag aSign, bSign;
+
+ if ( ( ( extractFloat64Exp( a ) == 0x7FF )
+ && ( extractFloat64Frac0( a ) | extractFloat64Frac1( a ) ) )
+ || ( ( extractFloat64Exp( b ) == 0x7FF )
+ && ( extractFloat64Frac0( b ) | extractFloat64Frac1( b ) ) )
+ ) {
+ float_raise( float_flag_invalid );
+ return 0;
+ }
+ aSign = extractFloat64Sign( a );
+ bSign = extractFloat64Sign( b );
+ if ( aSign != bSign )
+ return aSign &&
+ ( (bits64) ( ( FLOAT64_DEMANGLE(a) | FLOAT64_DEMANGLE(b) )<<1 ) !=
+ 0 );
+ return ( a != b ) &&
+ ( aSign ^ ( FLOAT64_DEMANGLE(a) < FLOAT64_DEMANGLE(b) ) );
+
+}
+
+#ifndef SOFTFLOAT_FOR_GCC
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the double-precision floating-point value `a' is equal to
+the corresponding value `b', and 0 otherwise. The invalid exception is
+raised if either operand is a NaN. Otherwise, the comparison is performed
+according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float64_eq_signaling( float64 a, float64 b )
+{
+
+ if ( ( ( extractFloat64Exp( a ) == 0x7FF )
+ && ( extractFloat64Frac0( a ) | extractFloat64Frac1( a ) ) )
+ || ( ( extractFloat64Exp( b ) == 0x7FF )
+ && ( extractFloat64Frac0( b ) | extractFloat64Frac1( b ) ) )
+ ) {
+ float_raise( float_flag_invalid );
+ return 0;
+ }
+ return ( a == b ) || ( (bits64) ( ( a | b )<<1 ) == 0 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the double-precision floating-point value `a' is less than or
+equal to the corresponding value `b', and 0 otherwise. Quiet NaNs do not
+cause an exception. Otherwise, the comparison is performed according to the
+IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float64_le_quiet( float64 a, float64 b )
+{
+ flag aSign, bSign;
+
+ if ( ( ( extractFloat64Exp( a ) == 0x7FF )
+ && ( extractFloat64Frac0( a ) | extractFloat64Frac1( a ) ) )
+ || ( ( extractFloat64Exp( b ) == 0x7FF )
+ && ( extractFloat64Frac0( b ) | extractFloat64Frac1( b ) ) )
+ ) {
+ if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) {
+ float_raise( float_flag_invalid );
+ }
+ return 0;
+ }
+ aSign = extractFloat64Sign( a );
+ bSign = extractFloat64Sign( b );
+ if ( aSign != bSign ) return aSign || ( (bits64) ( ( a | b )<<1 ) == 0 );
+ return ( a == b ) || ( aSign ^ ( a < b ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the double-precision floating-point value `a' is less than
+the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an
+exception. Otherwise, the comparison is performed according to the IEC/IEEE
+Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float64_lt_quiet( float64 a, float64 b )
+{
+ flag aSign, bSign;
+
+ if ( ( ( extractFloat64Exp( a ) == 0x7FF )
+ && ( extractFloat64Frac0( a ) | extractFloat64Frac1( a ) ) )
+ || ( ( extractFloat64Exp( b ) == 0x7FF )
+ && ( extractFloat64Frac0( b ) | extractFloat64Frac1( b ) ) )
+ ) {
+ if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) {
+ float_raise( float_flag_invalid );
+ }
+ return 0;
+ }
+ aSign = extractFloat64Sign( a );
+ bSign = extractFloat64Sign( b );
+ if ( aSign != bSign ) return aSign && ( (bits64) ( ( a | b )<<1 ) != 0 );
+ return ( a != b ) && ( aSign ^ ( a < b ) );
+
+}
+
+#endif
diff --git a/lib/libc/softfloat/bits64/softfloat-macros b/lib/libc/softfloat/bits64/softfloat-macros
new file mode 100644
index 000000000000..f4647def2bd4
--- /dev/null
+++ b/lib/libc/softfloat/bits64/softfloat-macros
@@ -0,0 +1,746 @@
+/* $NetBSD: softfloat-macros,v 1.2 2009/02/16 10:23:35 tron Exp $ */
+/* $FreeBSD$ */
+
+/*
+===============================================================================
+
+This C source fragment is part of the SoftFloat IEC/IEEE Floating-point
+Arithmetic Package, Release 2a.
+
+Written by John R. Hauser. This work was made possible in part by the
+International Computer Science Institute, located at Suite 600, 1947 Center
+Street, Berkeley, California 94704. Funding was partially provided by the
+National Science Foundation under grant MIP-9311980. The original version
+of this code was written as part of a project to build a fixed-point vector
+processor in collaboration with the University of California at Berkeley,
+overseen by Profs. Nelson Morgan and John Wawrzynek. More information
+is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
+arithmetic/SoftFloat.html'.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
+has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
+TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
+PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
+AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
+
+Derivative works are acceptable, even for commercial purposes, so long as
+(1) they include prominent notice that the work is derivative, and (2) they
+include prominent notice akin to these four paragraphs for those parts of
+this code that are retained.
+
+===============================================================================
+*/
+
+/*
+-------------------------------------------------------------------------------
+Shifts `a' right by the number of bits given in `count'. If any nonzero
+bits are shifted off, they are ``jammed'' into the least significant bit of
+the result by setting the least significant bit to 1. The value of `count'
+can be arbitrarily large; in particular, if `count' is greater than 32, the
+result will be either 0 or 1, depending on whether `a' is zero or nonzero.
+The result is stored in the location pointed to by `zPtr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void shift32RightJamming( bits32 a, int16 count, bits32 *zPtr )
+{
+ bits32 z;
+
+ if ( count == 0 ) {
+ z = a;
+ }
+ else if ( count < 32 ) {
+ z = ( a>>count ) | ( ( a<<( ( - count ) & 31 ) ) != 0 );
+ }
+ else {
+ z = ( a != 0 );
+ }
+ *zPtr = z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Shifts `a' right by the number of bits given in `count'. If any nonzero
+bits are shifted off, they are ``jammed'' into the least significant bit of
+the result by setting the least significant bit to 1. The value of `count'
+can be arbitrarily large; in particular, if `count' is greater than 64, the
+result will be either 0 or 1, depending on whether `a' is zero or nonzero.
+The result is stored in the location pointed to by `zPtr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void shift64RightJamming( bits64 a, int16 count, bits64 *zPtr )
+{
+ bits64 z;
+
+ if ( count == 0 ) {
+ z = a;
+ }
+ else if ( count < 64 ) {
+ z = ( a>>count ) | ( ( a<<( ( - count ) & 63 ) ) != 0 );
+ }
+ else {
+ z = ( a != 0 );
+ }
+ *zPtr = z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Shifts the 128-bit value formed by concatenating `a0' and `a1' right by 64
+_plus_ the number of bits given in `count'. The shifted result is at most
+64 nonzero bits; this is stored at the location pointed to by `z0Ptr'. The
+bits shifted off form a second 64-bit result as follows: The _last_ bit
+shifted off is the most-significant bit of the extra result, and the other
+63 bits of the extra result are all zero if and only if _all_but_the_last_
+bits shifted off were all zero. This extra result is stored in the location
+pointed to by `z1Ptr'. The value of `count' can be arbitrarily large.
+ (This routine makes more sense if `a0' and `a1' are considered to form a
+fixed-point value with binary point between `a0' and `a1'. This fixed-point
+value is shifted right by the number of bits given in `count', and the
+integer part of the result is returned at the location pointed to by
+`z0Ptr'. The fractional part of the result may be slightly corrupted as
+described above, and is returned at the location pointed to by `z1Ptr'.)
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ shift64ExtraRightJamming(
+ bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr )
+{
+ bits64 z0, z1;
+ int8 negCount = ( - count ) & 63;
+
+ if ( count == 0 ) {
+ z1 = a1;
+ z0 = a0;
+ }
+ else if ( count < 64 ) {
+ z1 = ( a0<<negCount ) | ( a1 != 0 );
+ z0 = a0>>count;
+ }
+ else {
+ if ( count == 64 ) {
+ z1 = a0 | ( a1 != 0 );
+ }
+ else {
+ z1 = ( ( a0 | a1 ) != 0 );
+ }
+ z0 = 0;
+ }
+ *z1Ptr = z1;
+ *z0Ptr = z0;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Shifts the 128-bit value formed by concatenating `a0' and `a1' right by the
+number of bits given in `count'. Any bits shifted off are lost. The value
+of `count' can be arbitrarily large; in particular, if `count' is greater
+than 128, the result will be 0. The result is broken into two 64-bit pieces
+which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ shift128Right(
+ bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr )
+{
+ bits64 z0, z1;
+ int8 negCount = ( - count ) & 63;
+
+ if ( count == 0 ) {
+ z1 = a1;
+ z0 = a0;
+ }
+ else if ( count < 64 ) {
+ z1 = ( a0<<negCount ) | ( a1>>count );
+ z0 = a0>>count;
+ }
+ else {
+ z1 = ( count < 64 ) ? ( a0>>( count & 63 ) ) : 0;
+ z0 = 0;
+ }
+ *z1Ptr = z1;
+ *z0Ptr = z0;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Shifts the 128-bit value formed by concatenating `a0' and `a1' right by the
+number of bits given in `count'. If any nonzero bits are shifted off, they
+are ``jammed'' into the least significant bit of the result by setting the
+least significant bit to 1. The value of `count' can be arbitrarily large;
+in particular, if `count' is greater than 128, the result will be either
+0 or 1, depending on whether the concatenation of `a0' and `a1' is zero or
+nonzero. The result is broken into two 64-bit pieces which are stored at
+the locations pointed to by `z0Ptr' and `z1Ptr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ shift128RightJamming(
+ bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr )
+{
+ bits64 z0, z1;
+ int8 negCount = ( - count ) & 63;
+
+ if ( count == 0 ) {
+ z1 = a1;
+ z0 = a0;
+ }
+ else if ( count < 64 ) {
+ z1 = ( a0<<negCount ) | ( a1>>count ) | ( ( a1<<negCount ) != 0 );
+ z0 = a0>>count;
+ }
+ else {
+ if ( count == 64 ) {
+ z1 = a0 | ( a1 != 0 );
+ }
+ else if ( count < 128 ) {
+ z1 = ( a0>>( count & 63 ) ) | ( ( ( a0<<negCount ) | a1 ) != 0 );
+ }
+ else {
+ z1 = ( ( a0 | a1 ) != 0 );
+ }
+ z0 = 0;
+ }
+ *z1Ptr = z1;
+ *z0Ptr = z0;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Shifts the 192-bit value formed by concatenating `a0', `a1', and `a2' right
+by 64 _plus_ the number of bits given in `count'. The shifted result is
+at most 128 nonzero bits; these are broken into two 64-bit pieces which are
+stored at the locations pointed to by `z0Ptr' and `z1Ptr'. The bits shifted
+off form a third 64-bit result as follows: The _last_ bit shifted off is
+the most-significant bit of the extra result, and the other 63 bits of the
+extra result are all zero if and only if _all_but_the_last_ bits shifted off
+were all zero. This extra result is stored in the location pointed to by
+`z2Ptr'. The value of `count' can be arbitrarily large.
+ (This routine makes more sense if `a0', `a1', and `a2' are considered
+to form a fixed-point value with binary point between `a1' and `a2'. This
+fixed-point value is shifted right by the number of bits given in `count',
+and the integer part of the result is returned at the locations pointed to
+by `z0Ptr' and `z1Ptr'. The fractional part of the result may be slightly
+corrupted as described above, and is returned at the location pointed to by
+`z2Ptr'.)
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ shift128ExtraRightJamming(
+ bits64 a0,
+ bits64 a1,
+ bits64 a2,
+ int16 count,
+ bits64 *z0Ptr,
+ bits64 *z1Ptr,
+ bits64 *z2Ptr
+ )
+{
+ bits64 z0, z1, z2;
+ int8 negCount = ( - count ) & 63;
+
+ if ( count == 0 ) {
+ z2 = a2;
+ z1 = a1;
+ z0 = a0;
+ }
+ else {
+ if ( count < 64 ) {
+ z2 = a1<<negCount;
+ z1 = ( a0<<negCount ) | ( a1>>count );
+ z0 = a0>>count;
+ }
+ else {
+ if ( count == 64 ) {
+ z2 = a1;
+ z1 = a0;
+ }
+ else {
+ a2 |= a1;
+ if ( count < 128 ) {
+ z2 = a0<<negCount;
+ z1 = a0>>( count & 63 );
+ }
+ else {
+ z2 = ( count == 128 ) ? a0 : ( a0 != 0 );
+ z1 = 0;
+ }
+ }
+ z0 = 0;
+ }
+ z2 |= ( a2 != 0 );
+ }
+ *z2Ptr = z2;
+ *z1Ptr = z1;
+ *z0Ptr = z0;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Shifts the 128-bit value formed by concatenating `a0' and `a1' left by the
+number of bits given in `count'. Any bits shifted off are lost. The value
+of `count' must be less than 64. The result is broken into two 64-bit
+pieces which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ shortShift128Left(
+ bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr )
+{
+
+ *z1Ptr = a1<<count;
+ *z0Ptr =
+ ( count == 0 ) ? a0 : ( a0<<count ) | ( a1>>( ( - count ) & 63 ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Shifts the 192-bit value formed by concatenating `a0', `a1', and `a2' left
+by the number of bits given in `count'. Any bits shifted off are lost.
+The value of `count' must be less than 64. The result is broken into three
+64-bit pieces which are stored at the locations pointed to by `z0Ptr',
+`z1Ptr', and `z2Ptr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ shortShift192Left(
+ bits64 a0,
+ bits64 a1,
+ bits64 a2,
+ int16 count,
+ bits64 *z0Ptr,
+ bits64 *z1Ptr,
+ bits64 *z2Ptr
+ )
+{
+ bits64 z0, z1, z2;
+ int8 negCount;
+
+ z2 = a2<<count;
+ z1 = a1<<count;
+ z0 = a0<<count;
+ if ( 0 < count ) {
+ negCount = ( ( - count ) & 63 );
+ z1 |= a2>>negCount;
+ z0 |= a1>>negCount;
+ }
+ *z2Ptr = z2;
+ *z1Ptr = z1;
+ *z0Ptr = z0;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Adds the 128-bit value formed by concatenating `a0' and `a1' to the 128-bit
+value formed by concatenating `b0' and `b1'. Addition is modulo 2^128, so
+any carry out is lost. The result is broken into two 64-bit pieces which
+are stored at the locations pointed to by `z0Ptr' and `z1Ptr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ add128(
+ bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 *z0Ptr, bits64 *z1Ptr )
+{
+ bits64 z1;
+
+ z1 = a1 + b1;
+ *z1Ptr = z1;
+ *z0Ptr = a0 + b0 + ( z1 < a1 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Adds the 192-bit value formed by concatenating `a0', `a1', and `a2' to the
+192-bit value formed by concatenating `b0', `b1', and `b2'. Addition is
+modulo 2^192, so any carry out is lost. The result is broken into three
+64-bit pieces which are stored at the locations pointed to by `z0Ptr',
+`z1Ptr', and `z2Ptr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ add192(
+ bits64 a0,
+ bits64 a1,
+ bits64 a2,
+ bits64 b0,
+ bits64 b1,
+ bits64 b2,
+ bits64 *z0Ptr,
+ bits64 *z1Ptr,
+ bits64 *z2Ptr
+ )
+{
+ bits64 z0, z1, z2;
+ int8 carry0, carry1;
+
+ z2 = a2 + b2;
+ carry1 = ( z2 < a2 );
+ z1 = a1 + b1;
+ carry0 = ( z1 < a1 );
+ z0 = a0 + b0;
+ z1 += carry1;
+ z0 += ( z1 < (bits64)carry1 );
+ z0 += carry0;
+ *z2Ptr = z2;
+ *z1Ptr = z1;
+ *z0Ptr = z0;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Subtracts the 128-bit value formed by concatenating `b0' and `b1' from the
+128-bit value formed by concatenating `a0' and `a1'. Subtraction is modulo
+2^128, so any borrow out (carry out) is lost. The result is broken into two
+64-bit pieces which are stored at the locations pointed to by `z0Ptr' and
+`z1Ptr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ sub128(
+ bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 *z0Ptr, bits64 *z1Ptr )
+{
+
+ *z1Ptr = a1 - b1;
+ *z0Ptr = a0 - b0 - ( a1 < b1 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Subtracts the 192-bit value formed by concatenating `b0', `b1', and `b2'
+from the 192-bit value formed by concatenating `a0', `a1', and `a2'.
+Subtraction is modulo 2^192, so any borrow out (carry out) is lost. The
+result is broken into three 64-bit pieces which are stored at the locations
+pointed to by `z0Ptr', `z1Ptr', and `z2Ptr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ sub192(
+ bits64 a0,
+ bits64 a1,
+ bits64 a2,
+ bits64 b0,
+ bits64 b1,
+ bits64 b2,
+ bits64 *z0Ptr,
+ bits64 *z1Ptr,
+ bits64 *z2Ptr
+ )
+{
+ bits64 z0, z1, z2;
+ int8 borrow0, borrow1;
+
+ z2 = a2 - b2;
+ borrow1 = ( a2 < b2 );
+ z1 = a1 - b1;
+ borrow0 = ( a1 < b1 );
+ z0 = a0 - b0;
+ z0 -= ( z1 < (bits64)borrow1 );
+ z1 -= borrow1;
+ z0 -= borrow0;
+ *z2Ptr = z2;
+ *z1Ptr = z1;
+ *z0Ptr = z0;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Multiplies `a' by `b' to obtain a 128-bit product. The product is broken
+into two 64-bit pieces which are stored at the locations pointed to by
+`z0Ptr' and `z1Ptr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void mul64To128( bits64 a, bits64 b, bits64 *z0Ptr, bits64 *z1Ptr )
+{
+ bits32 aHigh, aLow, bHigh, bLow;
+ bits64 z0, zMiddleA, zMiddleB, z1;
+
+ aLow = a;
+ aHigh = a>>32;
+ bLow = b;
+ bHigh = b>>32;
+ z1 = ( (bits64) aLow ) * bLow;
+ zMiddleA = ( (bits64) aLow ) * bHigh;
+ zMiddleB = ( (bits64) aHigh ) * bLow;
+ z0 = ( (bits64) aHigh ) * bHigh;
+ zMiddleA += zMiddleB;
+ z0 += ( ( (bits64) ( zMiddleA < zMiddleB ) )<<32 ) + ( zMiddleA>>32 );
+ zMiddleA <<= 32;
+ z1 += zMiddleA;
+ z0 += ( z1 < zMiddleA );
+ *z1Ptr = z1;
+ *z0Ptr = z0;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Multiplies the 128-bit value formed by concatenating `a0' and `a1' by
+`b' to obtain a 192-bit product. The product is broken into three 64-bit
+pieces which are stored at the locations pointed to by `z0Ptr', `z1Ptr', and
+`z2Ptr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ mul128By64To192(
+ bits64 a0,
+ bits64 a1,
+ bits64 b,
+ bits64 *z0Ptr,
+ bits64 *z1Ptr,
+ bits64 *z2Ptr
+ )
+{
+ bits64 z0, z1, z2, more1;
+
+ mul64To128( a1, b, &z1, &z2 );
+ mul64To128( a0, b, &z0, &more1 );
+ add128( z0, more1, 0, z1, &z0, &z1 );
+ *z2Ptr = z2;
+ *z1Ptr = z1;
+ *z0Ptr = z0;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Multiplies the 128-bit value formed by concatenating `a0' and `a1' to the
+128-bit value formed by concatenating `b0' and `b1' to obtain a 256-bit
+product. The product is broken into four 64-bit pieces which are stored at
+the locations pointed to by `z0Ptr', `z1Ptr', `z2Ptr', and `z3Ptr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ mul128To256(
+ bits64 a0,
+ bits64 a1,
+ bits64 b0,
+ bits64 b1,
+ bits64 *z0Ptr,
+ bits64 *z1Ptr,
+ bits64 *z2Ptr,
+ bits64 *z3Ptr
+ )
+{
+ bits64 z0, z1, z2, z3;
+ bits64 more1, more2;
+
+ mul64To128( a1, b1, &z2, &z3 );
+ mul64To128( a1, b0, &z1, &more2 );
+ add128( z1, more2, 0, z2, &z1, &z2 );
+ mul64To128( a0, b0, &z0, &more1 );
+ add128( z0, more1, 0, z1, &z0, &z1 );
+ mul64To128( a0, b1, &more1, &more2 );
+ add128( more1, more2, 0, z2, &more1, &z2 );
+ add128( z0, z1, 0, more1, &z0, &z1 );
+ *z3Ptr = z3;
+ *z2Ptr = z2;
+ *z1Ptr = z1;
+ *z0Ptr = z0;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns an approximation to the 64-bit integer quotient obtained by dividing
+`b' into the 128-bit value formed by concatenating `a0' and `a1'. The
+divisor `b' must be at least 2^63. If q is the exact quotient truncated
+toward zero, the approximation returned lies between q and q + 2 inclusive.
+If the exact quotient q is larger than 64 bits, the maximum positive 64-bit
+unsigned integer is returned.
+-------------------------------------------------------------------------------
+*/
+static bits64 estimateDiv128To64( bits64 a0, bits64 a1, bits64 b )
+{
+ bits64 b0, b1;
+ bits64 rem0, rem1, term0, term1;
+ bits64 z;
+
+ if ( b <= a0 ) return LIT64( 0xFFFFFFFFFFFFFFFF );
+ b0 = b>>32;
+ z = ( b0<<32 <= a0 ) ? LIT64( 0xFFFFFFFF00000000 ) : ( a0 / b0 )<<32;
+ mul64To128( b, z, &term0, &term1 );
+ sub128( a0, a1, term0, term1, &rem0, &rem1 );
+ while ( ( (sbits64) rem0 ) < 0 ) {
+ z -= LIT64( 0x100000000 );
+ b1 = b<<32;
+ add128( rem0, rem1, b0, b1, &rem0, &rem1 );
+ }
+ rem0 = ( rem0<<32 ) | ( rem1>>32 );
+ z |= ( b0<<32 <= rem0 ) ? 0xFFFFFFFF : rem0 / b0;
+ return z;
+
+}
+
+#if !defined(SOFTFLOAT_FOR_GCC) || defined(FLOATX80) || defined(FLOAT128)
+/*
+-------------------------------------------------------------------------------
+Returns an approximation to the square root of the 32-bit significand given
+by `a'. Considered as an integer, `a' must be at least 2^31. If bit 0 of
+`aExp' (the least significant bit) is 1, the integer returned approximates
+2^31*sqrt(`a'/2^31), where `a' is considered an integer. If bit 0 of `aExp'
+is 0, the integer returned approximates 2^31*sqrt(`a'/2^30). In either
+case, the approximation returned lies strictly within +/-2 of the exact
+value.
+-------------------------------------------------------------------------------
+*/
+static bits32 estimateSqrt32( int16 aExp, bits32 a )
+{
+ static const bits16 sqrtOddAdjustments[] = {
+ 0x0004, 0x0022, 0x005D, 0x00B1, 0x011D, 0x019F, 0x0236, 0x02E0,
+ 0x039C, 0x0468, 0x0545, 0x0631, 0x072B, 0x0832, 0x0946, 0x0A67
+ };
+ static const bits16 sqrtEvenAdjustments[] = {
+ 0x0A2D, 0x08AF, 0x075A, 0x0629, 0x051A, 0x0429, 0x0356, 0x029E,
+ 0x0200, 0x0179, 0x0109, 0x00AF, 0x0068, 0x0034, 0x0012, 0x0002
+ };
+ int8 idx;
+ bits32 z;
+
+ idx = ( a>>27 ) & 15;
+ if ( aExp & 1 ) {
+ z = 0x4000 + ( a>>17 ) - sqrtOddAdjustments[ idx ];
+ z = ( ( a / z )<<14 ) + ( z<<15 );
+ a >>= 1;
+ }
+ else {
+ z = 0x8000 + ( a>>17 ) - sqrtEvenAdjustments[ idx ];
+ z = a / z + z;
+ z = ( 0x20000 <= z ) ? 0xFFFF8000 : ( z<<15 );
+ if ( z <= a ) return (bits32) ( ( (sbits32) a )>>1 );
+ }
+ return ( (bits32) ( ( ( (bits64) a )<<31 ) / z ) ) + ( z>>1 );
+
+}
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Returns the number of leading 0 bits before the most-significant 1 bit of
+`a'. If `a' is zero, 32 is returned.
+-------------------------------------------------------------------------------
+*/
+static int8 countLeadingZeros32( bits32 a )
+{
+ static const int8 countLeadingZerosHigh[] = {
+ 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+ int8 shiftCount;
+
+ shiftCount = 0;
+ if ( a < 0x10000 ) {
+ shiftCount += 16;
+ a <<= 16;
+ }
+ if ( a < 0x1000000 ) {
+ shiftCount += 8;
+ a <<= 8;
+ }
+ shiftCount += countLeadingZerosHigh[ a>>24 ];
+ return shiftCount;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the number of leading 0 bits before the most-significant 1 bit of
+`a'. If `a' is zero, 64 is returned.
+-------------------------------------------------------------------------------
+*/
+static int8 countLeadingZeros64( bits64 a )
+{
+ int8 shiftCount;
+
+ shiftCount = 0;
+ if ( a < ( (bits64) 1 )<<32 ) {
+ shiftCount += 32;
+ }
+ else {
+ a >>= 32;
+ }
+ shiftCount += countLeadingZeros32( a );
+ return shiftCount;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the 128-bit value formed by concatenating `a0' and `a1'
+is equal to the 128-bit value formed by concatenating `b0' and `b1'.
+Otherwise, returns 0.
+-------------------------------------------------------------------------------
+*/
+INLINE flag eq128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 )
+{
+
+ return ( a0 == b0 ) && ( a1 == b1 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is less
+than or equal to the 128-bit value formed by concatenating `b0' and `b1'.
+Otherwise, returns 0.
+-------------------------------------------------------------------------------
+*/
+INLINE flag le128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 )
+{
+
+ return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 <= b1 ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is less
+than the 128-bit value formed by concatenating `b0' and `b1'. Otherwise,
+returns 0.
+-------------------------------------------------------------------------------
+*/
+INLINE flag lt128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 )
+{
+
+ return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 < b1 ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is
+not equal to the 128-bit value formed by concatenating `b0' and `b1'.
+Otherwise, returns 0.
+-------------------------------------------------------------------------------
+*/
+INLINE flag ne128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 )
+{
+
+ return ( a0 != b0 ) || ( a1 != b1 );
+
+}
+
diff --git a/lib/libc/softfloat/bits64/softfloat.c b/lib/libc/softfloat/bits64/softfloat.c
new file mode 100644
index 000000000000..79993fb207f5
--- /dev/null
+++ b/lib/libc/softfloat/bits64/softfloat.c
@@ -0,0 +1,5599 @@
+/* $NetBSD: softfloat.c,v 1.8 2011/07/10 04:52:23 matt Exp $ */
+
+/*
+ * This version hacked for use with gcc -msoft-float by bjh21.
+ * (Mostly a case of #ifdefing out things GCC doesn't need or provides
+ * itself).
+ */
+
+/*
+ * Things you may want to define:
+ *
+ * SOFTFLOAT_FOR_GCC - build only those functions necessary for GCC (with
+ * -msoft-float) to work. Include "softfloat-for-gcc.h" to get them
+ * properly renamed.
+ */
+
+/*
+===============================================================================
+
+This C source file is part of the SoftFloat IEC/IEEE Floating-point
+Arithmetic Package, Release 2a.
+
+Written by John R. Hauser. This work was made possible in part by the
+International Computer Science Institute, located at Suite 600, 1947 Center
+Street, Berkeley, California 94704. Funding was partially provided by the
+National Science Foundation under grant MIP-9311980. The original version
+of this code was written as part of a project to build a fixed-point vector
+processor in collaboration with the University of California at Berkeley,
+overseen by Profs. Nelson Morgan and John Wawrzynek. More information
+is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
+arithmetic/SoftFloat.html'.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
+has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
+TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
+PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
+AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
+
+Derivative works are acceptable, even for commercial purposes, so long as
+(1) they include prominent notice that the work is derivative, and (2) they
+include prominent notice akin to these four paragraphs for those parts of
+this code that are retained.
+
+===============================================================================
+*/
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifdef SOFTFLOAT_FOR_GCC
+#include "softfloat-for-gcc.h"
+#endif
+
+#include "milieu.h"
+#include "softfloat.h"
+
+/*
+ * Conversions between floats as stored in memory and floats as
+ * SoftFloat uses them
+ */
+#ifndef FLOAT64_DEMANGLE
+#define FLOAT64_DEMANGLE(a) (a)
+#endif
+#ifndef FLOAT64_MANGLE
+#define FLOAT64_MANGLE(a) (a)
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Floating-point rounding mode, extended double-precision rounding precision,
+and exception flags.
+-------------------------------------------------------------------------------
+*/
+int float_rounding_mode = float_round_nearest_even;
+int float_exception_flags = 0;
+#ifdef FLOATX80
+int8 floatx80_rounding_precision = 80;
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Primitive arithmetic functions, including multi-word arithmetic, and
+division and square root approximations. (Can be specialized to target if
+desired.)
+-------------------------------------------------------------------------------
+*/
+#include "softfloat-macros"
+
+/*
+-------------------------------------------------------------------------------
+Functions and definitions to determine: (1) whether tininess for underflow
+is detected before or after rounding by default, (2) what (if anything)
+happens when exceptions are raised, (3) how signaling NaNs are distinguished
+from quiet NaNs, (4) the default generated quiet NaNs, and (5) how NaNs
+are propagated from function inputs to output. These details are target-
+specific.
+-------------------------------------------------------------------------------
+*/
+#include "softfloat-specialize"
+
+#if !defined(SOFTFLOAT_FOR_GCC) || defined(FLOATX80) || defined(FLOAT128)
+/*
+-------------------------------------------------------------------------------
+Takes a 64-bit fixed-point value `absZ' with binary point between bits 6
+and 7, and returns the properly rounded 32-bit integer corresponding to the
+input. If `zSign' is 1, the input is negated before being converted to an
+integer. Bit 63 of `absZ' must be zero. Ordinarily, the fixed-point input
+is simply rounded to an integer, with the inexact exception raised if the
+input cannot be represented exactly as an integer. However, if the fixed-
+point input is too large, the invalid exception is raised and the largest
+positive or negative integer is returned.
+-------------------------------------------------------------------------------
+*/
+static int32 roundAndPackInt32( flag zSign, bits64 absZ )
+{
+ int8 roundingMode;
+ flag roundNearestEven;
+ int8 roundIncrement, roundBits;
+ int32 z;
+
+ roundingMode = float_rounding_mode;
+ roundNearestEven = ( roundingMode == float_round_nearest_even );
+ roundIncrement = 0x40;
+ if ( ! roundNearestEven ) {
+ if ( roundingMode == float_round_to_zero ) {
+ roundIncrement = 0;
+ }
+ else {
+ roundIncrement = 0x7F;
+ if ( zSign ) {
+ if ( roundingMode == float_round_up ) roundIncrement = 0;
+ }
+ else {
+ if ( roundingMode == float_round_down ) roundIncrement = 0;
+ }
+ }
+ }
+ roundBits = absZ & 0x7F;
+ absZ = ( absZ + roundIncrement )>>7;
+ absZ &= ~ ( ( ( roundBits ^ 0x40 ) == 0 ) & roundNearestEven );
+ z = absZ;
+ if ( zSign ) z = - z;
+ if ( ( absZ>>32 ) || ( z && ( ( z < 0 ) ^ zSign ) ) ) {
+ float_raise( float_flag_invalid );
+ return zSign ? (sbits32) 0x80000000 : 0x7FFFFFFF;
+ }
+ if ( roundBits ) float_exception_flags |= float_flag_inexact;
+ return z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Takes the 128-bit fixed-point value formed by concatenating `absZ0' and
+`absZ1', with binary point between bits 63 and 64 (between the input words),
+and returns the properly rounded 64-bit integer corresponding to the input.
+If `zSign' is 1, the input is negated before being converted to an integer.
+Ordinarily, the fixed-point input is simply rounded to an integer, with
+the inexact exception raised if the input cannot be represented exactly as
+an integer. However, if the fixed-point input is too large, the invalid
+exception is raised and the largest positive or negative integer is
+returned.
+-------------------------------------------------------------------------------
+*/
+static int64 roundAndPackInt64( flag zSign, bits64 absZ0, bits64 absZ1 )
+{
+ int8 roundingMode;
+ flag roundNearestEven, increment;
+ int64 z;
+
+ roundingMode = float_rounding_mode;
+ roundNearestEven = ( roundingMode == float_round_nearest_even );
+ increment = ( (sbits64) absZ1 < 0 );
+ if ( ! roundNearestEven ) {
+ if ( roundingMode == float_round_to_zero ) {
+ increment = 0;
+ }
+ else {
+ if ( zSign ) {
+ increment = ( roundingMode == float_round_down ) && absZ1;
+ }
+ else {
+ increment = ( roundingMode == float_round_up ) && absZ1;
+ }
+ }
+ }
+ if ( increment ) {
+ ++absZ0;
+ if ( absZ0 == 0 ) goto overflow;
+ absZ0 &= ~ ( ( (bits64) ( absZ1<<1 ) == 0 ) & roundNearestEven );
+ }
+ z = absZ0;
+ if ( zSign ) z = - z;
+ if ( z && ( ( z < 0 ) ^ zSign ) ) {
+ overflow:
+ float_raise( float_flag_invalid );
+ return
+ zSign ? (sbits64) LIT64( 0x8000000000000000 )
+ : LIT64( 0x7FFFFFFFFFFFFFFF );
+ }
+ if ( absZ1 ) float_exception_flags |= float_flag_inexact;
+ return z;
+
+}
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Returns the fraction bits of the single-precision floating-point value `a'.
+-------------------------------------------------------------------------------
+*/
+INLINE bits32 extractFloat32Frac( float32 a )
+{
+
+ return a & 0x007FFFFF;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the exponent bits of the single-precision floating-point value `a'.
+-------------------------------------------------------------------------------
+*/
+INLINE int16 extractFloat32Exp( float32 a )
+{
+
+ return ( a>>23 ) & 0xFF;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the sign bit of the single-precision floating-point value `a'.
+-------------------------------------------------------------------------------
+*/
+INLINE flag extractFloat32Sign( float32 a )
+{
+
+ return a>>31;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Normalizes the subnormal single-precision floating-point value represented
+by the denormalized significand `aSig'. The normalized exponent and
+significand are stored at the locations pointed to by `zExpPtr' and
+`zSigPtr', respectively.
+-------------------------------------------------------------------------------
+*/
+static void
+ normalizeFloat32Subnormal( bits32 aSig, int16 *zExpPtr, bits32 *zSigPtr )
+{
+ int8 shiftCount;
+
+ shiftCount = countLeadingZeros32( aSig ) - 8;
+ *zSigPtr = aSig<<shiftCount;
+ *zExpPtr = 1 - shiftCount;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Packs the sign `zSign', exponent `zExp', and significand `zSig' into a
+single-precision floating-point value, returning the result. After being
+shifted into the proper positions, the three fields are simply added
+together to form the result. This means that any integer portion of `zSig'
+will be added into the exponent. Since a properly normalized significand
+will have an integer portion equal to 1, the `zExp' input should be 1 less
+than the desired result exponent whenever `zSig' is a complete, normalized
+significand.
+-------------------------------------------------------------------------------
+*/
+INLINE float32 packFloat32( flag zSign, int16 zExp, bits32 zSig )
+{
+
+ return ( ( (bits32) zSign )<<31 ) + ( ( (bits32) zExp )<<23 ) + zSig;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Takes an abstract floating-point value having sign `zSign', exponent `zExp',
+and significand `zSig', and returns the proper single-precision floating-
+point value corresponding to the abstract input. Ordinarily, the abstract
+value is simply rounded and packed into the single-precision format, with
+the inexact exception raised if the abstract input cannot be represented
+exactly. However, if the abstract value is too large, the overflow and
+inexact exceptions are raised and an infinity or maximal finite value is
+returned. If the abstract value is too small, the input value is rounded to
+a subnormal number, and the underflow and inexact exceptions are raised if
+the abstract input cannot be represented exactly as a subnormal single-
+precision floating-point number.
+ The input significand `zSig' has its binary point between bits 30
+and 29, which is 7 bits to the left of the usual location. This shifted
+significand must be normalized or smaller. If `zSig' is not normalized,
+`zExp' must be 0; in that case, the result returned is a subnormal number,
+and it must not require rounding. In the usual case that `zSig' is
+normalized, `zExp' must be 1 less than the ``true'' floating-point exponent.
+The handling of underflow and overflow follows the IEC/IEEE Standard for
+Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+static float32 roundAndPackFloat32( flag zSign, int16 zExp, bits32 zSig )
+{
+ int8 roundingMode;
+ flag roundNearestEven;
+ int8 roundIncrement, roundBits;
+ flag isTiny;
+
+ roundingMode = float_rounding_mode;
+ roundNearestEven = ( roundingMode == float_round_nearest_even );
+ roundIncrement = 0x40;
+ if ( ! roundNearestEven ) {
+ if ( roundingMode == float_round_to_zero ) {
+ roundIncrement = 0;
+ }
+ else {
+ roundIncrement = 0x7F;
+ if ( zSign ) {
+ if ( roundingMode == float_round_up ) roundIncrement = 0;
+ }
+ else {
+ if ( roundingMode == float_round_down ) roundIncrement = 0;
+ }
+ }
+ }
+ roundBits = zSig & 0x7F;
+ if ( 0xFD <= (bits16) zExp ) {
+ if ( ( 0xFD < zExp )
+ || ( ( zExp == 0xFD )
+ && ( (sbits32) ( zSig + roundIncrement ) < 0 ) )
+ ) {
+ float_raise( float_flag_overflow | float_flag_inexact );
+ return packFloat32( zSign, 0xFF, 0 ) - ( roundIncrement == 0 );
+ }
+ if ( zExp < 0 ) {
+ isTiny =
+ ( float_detect_tininess == float_tininess_before_rounding )
+ || ( zExp < -1 )
+ || ( zSig + roundIncrement < 0x80000000 );
+ shift32RightJamming( zSig, - zExp, &zSig );
+ zExp = 0;
+ roundBits = zSig & 0x7F;
+ if ( isTiny && roundBits ) float_raise( float_flag_underflow );
+ }
+ }
+ if ( roundBits ) float_exception_flags |= float_flag_inexact;
+ zSig = ( zSig + roundIncrement )>>7;
+ zSig &= ~ ( ( ( roundBits ^ 0x40 ) == 0 ) & roundNearestEven );
+ if ( zSig == 0 ) zExp = 0;
+ return packFloat32( zSign, zExp, zSig );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Takes an abstract floating-point value having sign `zSign', exponent `zExp',
+and significand `zSig', and returns the proper single-precision floating-
+point value corresponding to the abstract input. This routine is just like
+`roundAndPackFloat32' except that `zSig' does not have to be normalized.
+Bit 31 of `zSig' must be zero, and `zExp' must be 1 less than the ``true''
+floating-point exponent.
+-------------------------------------------------------------------------------
+*/
+static float32
+ normalizeRoundAndPackFloat32( flag zSign, int16 zExp, bits32 zSig )
+{
+ int8 shiftCount;
+
+ shiftCount = countLeadingZeros32( zSig ) - 1;
+ return roundAndPackFloat32( zSign, zExp - shiftCount, zSig<<shiftCount );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the fraction bits of the double-precision floating-point value `a'.
+-------------------------------------------------------------------------------
+*/
+INLINE bits64 extractFloat64Frac( float64 a )
+{
+
+ return FLOAT64_DEMANGLE(a) & LIT64( 0x000FFFFFFFFFFFFF );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the exponent bits of the double-precision floating-point value `a'.
+-------------------------------------------------------------------------------
+*/
+INLINE int16 extractFloat64Exp( float64 a )
+{
+
+ return ( FLOAT64_DEMANGLE(a)>>52 ) & 0x7FF;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the sign bit of the double-precision floating-point value `a'.
+-------------------------------------------------------------------------------
+*/
+INLINE flag extractFloat64Sign( float64 a )
+{
+
+ return FLOAT64_DEMANGLE(a)>>63;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Normalizes the subnormal double-precision floating-point value represented
+by the denormalized significand `aSig'. The normalized exponent and
+significand are stored at the locations pointed to by `zExpPtr' and
+`zSigPtr', respectively.
+-------------------------------------------------------------------------------
+*/
+static void
+ normalizeFloat64Subnormal( bits64 aSig, int16 *zExpPtr, bits64 *zSigPtr )
+{
+ int8 shiftCount;
+
+ shiftCount = countLeadingZeros64( aSig ) - 11;
+ *zSigPtr = aSig<<shiftCount;
+ *zExpPtr = 1 - shiftCount;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Packs the sign `zSign', exponent `zExp', and significand `zSig' into a
+double-precision floating-point value, returning the result. After being
+shifted into the proper positions, the three fields are simply added
+together to form the result. This means that any integer portion of `zSig'
+will be added into the exponent. Since a properly normalized significand
+will have an integer portion equal to 1, the `zExp' input should be 1 less
+than the desired result exponent whenever `zSig' is a complete, normalized
+significand.
+-------------------------------------------------------------------------------
+*/
+INLINE float64 packFloat64( flag zSign, int16 zExp, bits64 zSig )
+{
+
+ return FLOAT64_MANGLE( ( ( (bits64) zSign )<<63 ) +
+ ( ( (bits64) zExp )<<52 ) + zSig );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Takes an abstract floating-point value having sign `zSign', exponent `zExp',
+and significand `zSig', and returns the proper double-precision floating-
+point value corresponding to the abstract input. Ordinarily, the abstract
+value is simply rounded and packed into the double-precision format, with
+the inexact exception raised if the abstract input cannot be represented
+exactly. However, if the abstract value is too large, the overflow and
+inexact exceptions are raised and an infinity or maximal finite value is
+returned. If the abstract value is too small, the input value is rounded to
+a subnormal number, and the underflow and inexact exceptions are raised if
+the abstract input cannot be represented exactly as a subnormal double-
+precision floating-point number.
+ The input significand `zSig' has its binary point between bits 62
+and 61, which is 10 bits to the left of the usual location. This shifted
+significand must be normalized or smaller. If `zSig' is not normalized,
+`zExp' must be 0; in that case, the result returned is a subnormal number,
+and it must not require rounding. In the usual case that `zSig' is
+normalized, `zExp' must be 1 less than the ``true'' floating-point exponent.
+The handling of underflow and overflow follows the IEC/IEEE Standard for
+Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+static float64 roundAndPackFloat64( flag zSign, int16 zExp, bits64 zSig )
+{
+ int8 roundingMode;
+ flag roundNearestEven;
+ int16 roundIncrement, roundBits;
+ flag isTiny;
+
+ roundingMode = float_rounding_mode;
+ roundNearestEven = ( roundingMode == float_round_nearest_even );
+ roundIncrement = 0x200;
+ if ( ! roundNearestEven ) {
+ if ( roundingMode == float_round_to_zero ) {
+ roundIncrement = 0;
+ }
+ else {
+ roundIncrement = 0x3FF;
+ if ( zSign ) {
+ if ( roundingMode == float_round_up ) roundIncrement = 0;
+ }
+ else {
+ if ( roundingMode == float_round_down ) roundIncrement = 0;
+ }
+ }
+ }
+ roundBits = zSig & 0x3FF;
+ if ( 0x7FD <= (bits16) zExp ) {
+ if ( ( 0x7FD < zExp )
+ || ( ( zExp == 0x7FD )
+ && ( (sbits64) ( zSig + roundIncrement ) < 0 ) )
+ ) {
+ float_raise( float_flag_overflow | float_flag_inexact );
+ return FLOAT64_MANGLE(
+ FLOAT64_DEMANGLE(packFloat64( zSign, 0x7FF, 0 )) -
+ ( roundIncrement == 0 ));
+ }
+ if ( zExp < 0 ) {
+ isTiny =
+ ( float_detect_tininess == float_tininess_before_rounding )
+ || ( zExp < -1 )
+ || ( zSig + roundIncrement < LIT64( 0x8000000000000000 ) );
+ shift64RightJamming( zSig, - zExp, &zSig );
+ zExp = 0;
+ roundBits = zSig & 0x3FF;
+ if ( isTiny && roundBits ) float_raise( float_flag_underflow );
+ }
+ }
+ if ( roundBits ) float_exception_flags |= float_flag_inexact;
+ zSig = ( zSig + roundIncrement )>>10;
+ zSig &= ~ ( ( ( roundBits ^ 0x200 ) == 0 ) & roundNearestEven );
+ if ( zSig == 0 ) zExp = 0;
+ return packFloat64( zSign, zExp, zSig );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Takes an abstract floating-point value having sign `zSign', exponent `zExp',
+and significand `zSig', and returns the proper double-precision floating-
+point value corresponding to the abstract input. This routine is just like
+`roundAndPackFloat64' except that `zSig' does not have to be normalized.
+Bit 63 of `zSig' must be zero, and `zExp' must be 1 less than the ``true''
+floating-point exponent.
+-------------------------------------------------------------------------------
+*/
+static float64
+ normalizeRoundAndPackFloat64( flag zSign, int16 zExp, bits64 zSig )
+{
+ int8 shiftCount;
+
+ shiftCount = countLeadingZeros64( zSig ) - 1;
+ return roundAndPackFloat64( zSign, zExp - shiftCount, zSig<<shiftCount );
+
+}
+
+#ifdef FLOATX80
+
+/*
+-------------------------------------------------------------------------------
+Returns the fraction bits of the extended double-precision floating-point
+value `a'.
+-------------------------------------------------------------------------------
+*/
+INLINE bits64 extractFloatx80Frac( floatx80 a )
+{
+
+ return a.low;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the exponent bits of the extended double-precision floating-point
+value `a'.
+-------------------------------------------------------------------------------
+*/
+INLINE int32 extractFloatx80Exp( floatx80 a )
+{
+
+ return a.high & 0x7FFF;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the sign bit of the extended double-precision floating-point value
+`a'.
+-------------------------------------------------------------------------------
+*/
+INLINE flag extractFloatx80Sign( floatx80 a )
+{
+
+ return a.high>>15;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Normalizes the subnormal extended double-precision floating-point value
+represented by the denormalized significand `aSig'. The normalized exponent
+and significand are stored at the locations pointed to by `zExpPtr' and
+`zSigPtr', respectively.
+-------------------------------------------------------------------------------
+*/
+static void
+ normalizeFloatx80Subnormal( bits64 aSig, int32 *zExpPtr, bits64 *zSigPtr )
+{
+ int8 shiftCount;
+
+ shiftCount = countLeadingZeros64( aSig );
+ *zSigPtr = aSig<<shiftCount;
+ *zExpPtr = 1 - shiftCount;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Packs the sign `zSign', exponent `zExp', and significand `zSig' into an
+extended double-precision floating-point value, returning the result.
+-------------------------------------------------------------------------------
+*/
+INLINE floatx80 packFloatx80( flag zSign, int32 zExp, bits64 zSig )
+{
+ floatx80 z;
+
+ z.low = zSig;
+ z.high = ( ( (bits16) zSign )<<15 ) + zExp;
+ return z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Takes an abstract floating-point value having sign `zSign', exponent `zExp',
+and extended significand formed by the concatenation of `zSig0' and `zSig1',
+and returns the proper extended double-precision floating-point value
+corresponding to the abstract input. Ordinarily, the abstract value is
+rounded and packed into the extended double-precision format, with the
+inexact exception raised if the abstract input cannot be represented
+exactly. However, if the abstract value is too large, the overflow and
+inexact exceptions are raised and an infinity or maximal finite value is
+returned. If the abstract value is too small, the input value is rounded to
+a subnormal number, and the underflow and inexact exceptions are raised if
+the abstract input cannot be represented exactly as a subnormal extended
+double-precision floating-point number.
+ If `roundingPrecision' is 32 or 64, the result is rounded to the same
+number of bits as single or double precision, respectively. Otherwise, the
+result is rounded to the full precision of the extended double-precision
+format.
+ The input significand must be normalized or smaller. If the input
+significand is not normalized, `zExp' must be 0; in that case, the result
+returned is a subnormal number, and it must not require rounding. The
+handling of underflow and overflow follows the IEC/IEEE Standard for Binary
+Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+static floatx80
+ roundAndPackFloatx80(
+ int8 roundingPrecision, flag zSign, int32 zExp, bits64 zSig0, bits64 zSig1
+ )
+{
+ int8 roundingMode;
+ flag roundNearestEven, increment, isTiny;
+ int64 roundIncrement, roundMask, roundBits;
+
+ roundingMode = float_rounding_mode;
+ roundNearestEven = ( roundingMode == float_round_nearest_even );
+ if ( roundingPrecision == 80 ) goto precision80;
+ if ( roundingPrecision == 64 ) {
+ roundIncrement = LIT64( 0x0000000000000400 );
+ roundMask = LIT64( 0x00000000000007FF );
+ }
+ else if ( roundingPrecision == 32 ) {
+ roundIncrement = LIT64( 0x0000008000000000 );
+ roundMask = LIT64( 0x000000FFFFFFFFFF );
+ }
+ else {
+ goto precision80;
+ }
+ zSig0 |= ( zSig1 != 0 );
+ if ( ! roundNearestEven ) {
+ if ( roundingMode == float_round_to_zero ) {
+ roundIncrement = 0;
+ }
+ else {
+ roundIncrement = roundMask;
+ if ( zSign ) {
+ if ( roundingMode == float_round_up ) roundIncrement = 0;
+ }
+ else {
+ if ( roundingMode == float_round_down ) roundIncrement = 0;
+ }
+ }
+ }
+ roundBits = zSig0 & roundMask;
+ if ( 0x7FFD <= (bits32) ( zExp - 1 ) ) {
+ if ( ( 0x7FFE < zExp )
+ || ( ( zExp == 0x7FFE ) && ( zSig0 + roundIncrement < zSig0 ) )
+ ) {
+ goto overflow;
+ }
+ if ( zExp <= 0 ) {
+ isTiny =
+ ( float_detect_tininess == float_tininess_before_rounding )
+ || ( zExp < 0 )
+ || ( zSig0 <= zSig0 + roundIncrement );
+ shift64RightJamming( zSig0, 1 - zExp, &zSig0 );
+ zExp = 0;
+ roundBits = zSig0 & roundMask;
+ if ( isTiny && roundBits ) float_raise( float_flag_underflow );
+ if ( roundBits ) float_exception_flags |= float_flag_inexact;
+ zSig0 += roundIncrement;
+ if ( (sbits64) zSig0 < 0 ) zExp = 1;
+ roundIncrement = roundMask + 1;
+ if ( roundNearestEven && ( roundBits<<1 == roundIncrement ) ) {
+ roundMask |= roundIncrement;
+ }
+ zSig0 &= ~ roundMask;
+ return packFloatx80( zSign, zExp, zSig0 );
+ }
+ }
+ if ( roundBits ) float_exception_flags |= float_flag_inexact;
+ zSig0 += roundIncrement;
+ if ( zSig0 < roundIncrement ) {
+ ++zExp;
+ zSig0 = LIT64( 0x8000000000000000 );
+ }
+ roundIncrement = roundMask + 1;
+ if ( roundNearestEven && ( roundBits<<1 == roundIncrement ) ) {
+ roundMask |= roundIncrement;
+ }
+ zSig0 &= ~ roundMask;
+ if ( zSig0 == 0 ) zExp = 0;
+ return packFloatx80( zSign, zExp, zSig0 );
+ precision80:
+ increment = ( (sbits64) zSig1 < 0 );
+ if ( ! roundNearestEven ) {
+ if ( roundingMode == float_round_to_zero ) {
+ increment = 0;
+ }
+ else {
+ if ( zSign ) {
+ increment = ( roundingMode == float_round_down ) && zSig1;
+ }
+ else {
+ increment = ( roundingMode == float_round_up ) && zSig1;
+ }
+ }
+ }
+ if ( 0x7FFD <= (bits32) ( zExp - 1 ) ) {
+ if ( ( 0x7FFE < zExp )
+ || ( ( zExp == 0x7FFE )
+ && ( zSig0 == LIT64( 0xFFFFFFFFFFFFFFFF ) )
+ && increment
+ )
+ ) {
+ roundMask = 0;
+ overflow:
+ float_raise( float_flag_overflow | float_flag_inexact );
+ if ( ( roundingMode == float_round_to_zero )
+ || ( zSign && ( roundingMode == float_round_up ) )
+ || ( ! zSign && ( roundingMode == float_round_down ) )
+ ) {
+ return packFloatx80( zSign, 0x7FFE, ~ roundMask );
+ }
+ return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
+ }
+ if ( zExp <= 0 ) {
+ isTiny =
+ ( float_detect_tininess == float_tininess_before_rounding )
+ || ( zExp < 0 )
+ || ! increment
+ || ( zSig0 < LIT64( 0xFFFFFFFFFFFFFFFF ) );
+ shift64ExtraRightJamming( zSig0, zSig1, 1 - zExp, &zSig0, &zSig1 );
+ zExp = 0;
+ if ( isTiny && zSig1 ) float_raise( float_flag_underflow );
+ if ( zSig1 ) float_exception_flags |= float_flag_inexact;
+ if ( roundNearestEven ) {
+ increment = ( (sbits64) zSig1 < 0 );
+ }
+ else {
+ if ( zSign ) {
+ increment = ( roundingMode == float_round_down ) && zSig1;
+ }
+ else {
+ increment = ( roundingMode == float_round_up ) && zSig1;
+ }
+ }
+ if ( increment ) {
+ ++zSig0;
+ zSig0 &=
+ ~ ( ( (bits64) ( zSig1<<1 ) == 0 ) & roundNearestEven );
+ if ( (sbits64) zSig0 < 0 ) zExp = 1;
+ }
+ return packFloatx80( zSign, zExp, zSig0 );
+ }
+ }
+ if ( zSig1 ) float_exception_flags |= float_flag_inexact;
+ if ( increment ) {
+ ++zSig0;
+ if ( zSig0 == 0 ) {
+ ++zExp;
+ zSig0 = LIT64( 0x8000000000000000 );
+ }
+ else {
+ zSig0 &= ~ ( ( (bits64) ( zSig1<<1 ) == 0 ) & roundNearestEven );
+ }
+ }
+ else {
+ if ( zSig0 == 0 ) zExp = 0;
+ }
+ return packFloatx80( zSign, zExp, zSig0 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Takes an abstract floating-point value having sign `zSign', exponent
+`zExp', and significand formed by the concatenation of `zSig0' and `zSig1',
+and returns the proper extended double-precision floating-point value
+corresponding to the abstract input. This routine is just like
+`roundAndPackFloatx80' except that the input significand does not have to be
+normalized.
+-------------------------------------------------------------------------------
+*/
+static floatx80
+ normalizeRoundAndPackFloatx80(
+ int8 roundingPrecision, flag zSign, int32 zExp, bits64 zSig0, bits64 zSig1
+ )
+{
+ int8 shiftCount;
+
+ if ( zSig0 == 0 ) {
+ zSig0 = zSig1;
+ zSig1 = 0;
+ zExp -= 64;
+ }
+ shiftCount = countLeadingZeros64( zSig0 );
+ shortShift128Left( zSig0, zSig1, shiftCount, &zSig0, &zSig1 );
+ zExp -= shiftCount;
+ return
+ roundAndPackFloatx80( roundingPrecision, zSign, zExp, zSig0, zSig1 );
+
+}
+
+#endif
+
+#ifdef FLOAT128
+
+/*
+-------------------------------------------------------------------------------
+Returns the least-significant 64 fraction bits of the quadruple-precision
+floating-point value `a'.
+-------------------------------------------------------------------------------
+*/
+INLINE bits64 extractFloat128Frac1( float128 a )
+{
+
+ return a.low;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the most-significant 48 fraction bits of the quadruple-precision
+floating-point value `a'.
+-------------------------------------------------------------------------------
+*/
+INLINE bits64 extractFloat128Frac0( float128 a )
+{
+
+ return a.high & LIT64( 0x0000FFFFFFFFFFFF );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the exponent bits of the quadruple-precision floating-point value
+`a'.
+-------------------------------------------------------------------------------
+*/
+INLINE int32 extractFloat128Exp( float128 a )
+{
+
+ return ( a.high>>48 ) & 0x7FFF;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the sign bit of the quadruple-precision floating-point value `a'.
+-------------------------------------------------------------------------------
+*/
+INLINE flag extractFloat128Sign( float128 a )
+{
+
+ return a.high>>63;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Normalizes the subnormal quadruple-precision floating-point value
+represented by the denormalized significand formed by the concatenation of
+`aSig0' and `aSig1'. The normalized exponent is stored at the location
+pointed to by `zExpPtr'. The most significant 49 bits of the normalized
+significand are stored at the location pointed to by `zSig0Ptr', and the
+least significant 64 bits of the normalized significand are stored at the
+location pointed to by `zSig1Ptr'.
+-------------------------------------------------------------------------------
+*/
+static void
+ normalizeFloat128Subnormal(
+ bits64 aSig0,
+ bits64 aSig1,
+ int32 *zExpPtr,
+ bits64 *zSig0Ptr,
+ bits64 *zSig1Ptr
+ )
+{
+ int8 shiftCount;
+
+ if ( aSig0 == 0 ) {
+ shiftCount = countLeadingZeros64( aSig1 ) - 15;
+ if ( shiftCount < 0 ) {
+ *zSig0Ptr = aSig1>>( - shiftCount );
+ *zSig1Ptr = aSig1<<( shiftCount & 63 );
+ }
+ else {
+ *zSig0Ptr = aSig1<<shiftCount;
+ *zSig1Ptr = 0;
+ }
+ *zExpPtr = - shiftCount - 63;
+ }
+ else {
+ shiftCount = countLeadingZeros64( aSig0 ) - 15;
+ shortShift128Left( aSig0, aSig1, shiftCount, zSig0Ptr, zSig1Ptr );
+ *zExpPtr = 1 - shiftCount;
+ }
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Packs the sign `zSign', the exponent `zExp', and the significand formed
+by the concatenation of `zSig0' and `zSig1' into a quadruple-precision
+floating-point value, returning the result. After being shifted into the
+proper positions, the three fields `zSign', `zExp', and `zSig0' are simply
+added together to form the most significant 32 bits of the result. This
+means that any integer portion of `zSig0' will be added into the exponent.
+Since a properly normalized significand will have an integer portion equal
+to 1, the `zExp' input should be 1 less than the desired result exponent
+whenever `zSig0' and `zSig1' concatenated form a complete, normalized
+significand.
+-------------------------------------------------------------------------------
+*/
+INLINE float128
+ packFloat128( flag zSign, int32 zExp, bits64 zSig0, bits64 zSig1 )
+{
+ float128 z;
+
+ z.low = zSig1;
+ z.high = ( ( (bits64) zSign )<<63 ) + ( ( (bits64) zExp )<<48 ) + zSig0;
+ return z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Takes an abstract floating-point value having sign `zSign', exponent `zExp',
+and extended significand formed by the concatenation of `zSig0', `zSig1',
+and `zSig2', and returns the proper quadruple-precision floating-point value
+corresponding to the abstract input. Ordinarily, the abstract value is
+simply rounded and packed into the quadruple-precision format, with the
+inexact exception raised if the abstract input cannot be represented
+exactly. However, if the abstract value is too large, the overflow and
+inexact exceptions are raised and an infinity or maximal finite value is
+returned. If the abstract value is too small, the input value is rounded to
+a subnormal number, and the underflow and inexact exceptions are raised if
+the abstract input cannot be represented exactly as a subnormal quadruple-
+precision floating-point number.
+ The input significand must be normalized or smaller. If the input
+significand is not normalized, `zExp' must be 0; in that case, the result
+returned is a subnormal number, and it must not require rounding. In the
+usual case that the input significand is normalized, `zExp' must be 1 less
+than the ``true'' floating-point exponent. The handling of underflow and
+overflow follows the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+static float128
+ roundAndPackFloat128(
+ flag zSign, int32 zExp, bits64 zSig0, bits64 zSig1, bits64 zSig2 )
+{
+ int8 roundingMode;
+ flag roundNearestEven, increment, isTiny;
+
+ roundingMode = float_rounding_mode;
+ roundNearestEven = ( roundingMode == float_round_nearest_even );
+ increment = ( (sbits64) zSig2 < 0 );
+ if ( ! roundNearestEven ) {
+ if ( roundingMode == float_round_to_zero ) {
+ increment = 0;
+ }
+ else {
+ if ( zSign ) {
+ increment = ( roundingMode == float_round_down ) && zSig2;
+ }
+ else {
+ increment = ( roundingMode == float_round_up ) && zSig2;
+ }
+ }
+ }
+ if ( 0x7FFD <= (bits32) zExp ) {
+ if ( ( 0x7FFD < zExp )
+ || ( ( zExp == 0x7FFD )
+ && eq128(
+ LIT64( 0x0001FFFFFFFFFFFF ),
+ LIT64( 0xFFFFFFFFFFFFFFFF ),
+ zSig0,
+ zSig1
+ )
+ && increment
+ )
+ ) {
+ float_raise( float_flag_overflow | float_flag_inexact );
+ if ( ( roundingMode == float_round_to_zero )
+ || ( zSign && ( roundingMode == float_round_up ) )
+ || ( ! zSign && ( roundingMode == float_round_down ) )
+ ) {
+ return
+ packFloat128(
+ zSign,
+ 0x7FFE,
+ LIT64( 0x0000FFFFFFFFFFFF ),
+ LIT64( 0xFFFFFFFFFFFFFFFF )
+ );
+ }
+ return packFloat128( zSign, 0x7FFF, 0, 0 );
+ }
+ if ( zExp < 0 ) {
+ isTiny =
+ ( float_detect_tininess == float_tininess_before_rounding )
+ || ( zExp < -1 )
+ || ! increment
+ || lt128(
+ zSig0,
+ zSig1,
+ LIT64( 0x0001FFFFFFFFFFFF ),
+ LIT64( 0xFFFFFFFFFFFFFFFF )
+ );
+ shift128ExtraRightJamming(
+ zSig0, zSig1, zSig2, - zExp, &zSig0, &zSig1, &zSig2 );
+ zExp = 0;
+ if ( isTiny && zSig2 ) float_raise( float_flag_underflow );
+ if ( roundNearestEven ) {
+ increment = ( (sbits64) zSig2 < 0 );
+ }
+ else {
+ if ( zSign ) {
+ increment = ( roundingMode == float_round_down ) && zSig2;
+ }
+ else {
+ increment = ( roundingMode == float_round_up ) && zSig2;
+ }
+ }
+ }
+ }
+ if ( zSig2 ) float_exception_flags |= float_flag_inexact;
+ if ( increment ) {
+ add128( zSig0, zSig1, 0, 1, &zSig0, &zSig1 );
+ zSig1 &= ~ ( ( zSig2 + zSig2 == 0 ) & roundNearestEven );
+ }
+ else {
+ if ( ( zSig0 | zSig1 ) == 0 ) zExp = 0;
+ }
+ return packFloat128( zSign, zExp, zSig0, zSig1 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Takes an abstract floating-point value having sign `zSign', exponent `zExp',
+and significand formed by the concatenation of `zSig0' and `zSig1', and
+returns the proper quadruple-precision floating-point value corresponding
+to the abstract input. This routine is just like `roundAndPackFloat128'
+except that the input significand has fewer bits and does not have to be
+normalized. In all cases, `zExp' must be 1 less than the ``true'' floating-
+point exponent.
+-------------------------------------------------------------------------------
+*/
+static float128
+ normalizeRoundAndPackFloat128(
+ flag zSign, int32 zExp, bits64 zSig0, bits64 zSig1 )
+{
+ int8 shiftCount;
+ bits64 zSig2;
+
+ if ( zSig0 == 0 ) {
+ zSig0 = zSig1;
+ zSig1 = 0;
+ zExp -= 64;
+ }
+ shiftCount = countLeadingZeros64( zSig0 ) - 15;
+ if ( 0 <= shiftCount ) {
+ zSig2 = 0;
+ shortShift128Left( zSig0, zSig1, shiftCount, &zSig0, &zSig1 );
+ }
+ else {
+ shift128ExtraRightJamming(
+ zSig0, zSig1, 0, - shiftCount, &zSig0, &zSig1, &zSig2 );
+ }
+ zExp -= shiftCount;
+ return roundAndPackFloat128( zSign, zExp, zSig0, zSig1, zSig2 );
+
+}
+
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the 32-bit two's complement integer `a'
+to the single-precision floating-point format. The conversion is performed
+according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float32 int32_to_float32( int32 a )
+{
+ flag zSign;
+
+ if ( a == 0 ) return 0;
+ if ( a == (sbits32) 0x80000000 ) return packFloat32( 1, 0x9E, 0 );
+ zSign = ( a < 0 );
+ return normalizeRoundAndPackFloat32( zSign, 0x9C, zSign ? - a : a );
+
+}
+
+#ifndef SOFTFLOAT_FOR_GCC /* __floatunsisf is in libgcc */
+float32 uint32_to_float32( uint32 a )
+{
+ if ( a == 0 ) return 0;
+ if ( a & (bits32) 0x80000000 )
+ return normalizeRoundAndPackFloat32( 0, 0x9D, a >> 1 );
+ return normalizeRoundAndPackFloat32( 0, 0x9C, a );
+}
+#endif
+
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the 32-bit two's complement integer `a'
+to the double-precision floating-point format. The conversion is performed
+according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float64 int32_to_float64( int32 a )
+{
+ flag zSign;
+ uint32 absA;
+ int8 shiftCount;
+ bits64 zSig;
+
+ if ( a == 0 ) return 0;
+ zSign = ( a < 0 );
+ absA = zSign ? - a : a;
+ shiftCount = countLeadingZeros32( absA ) + 21;
+ zSig = absA;
+ return packFloat64( zSign, 0x432 - shiftCount, zSig<<shiftCount );
+
+}
+
+#ifndef SOFTFLOAT_FOR_GCC /* __floatunsidf is in libgcc */
+float64 uint32_to_float64( uint32 a )
+{
+ int8 shiftCount;
+ bits64 zSig = a;
+
+ if ( a == 0 ) return 0;
+ shiftCount = countLeadingZeros32( a ) + 21;
+ return packFloat64( 0, 0x432 - shiftCount, zSig<<shiftCount );
+
+}
+#endif
+
+#ifdef FLOATX80
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the 32-bit two's complement integer `a'
+to the extended double-precision floating-point format. The conversion
+is performed according to the IEC/IEEE Standard for Binary Floating-Point
+Arithmetic.
+-------------------------------------------------------------------------------
+*/
+floatx80 int32_to_floatx80( int32 a )
+{
+ flag zSign;
+ uint32 absA;
+ int8 shiftCount;
+ bits64 zSig;
+
+ if ( a == 0 ) return packFloatx80( 0, 0, 0 );
+ zSign = ( a < 0 );
+ absA = zSign ? - a : a;
+ shiftCount = countLeadingZeros32( absA ) + 32;
+ zSig = absA;
+ return packFloatx80( zSign, 0x403E - shiftCount, zSig<<shiftCount );
+
+}
+
+floatx80 uint32_to_floatx80( uint32 a )
+{
+ int8 shiftCount;
+ bits64 zSig = a;
+
+ if ( a == 0 ) return packFloatx80( 0, 0, 0 );
+ shiftCount = countLeadingZeros32( a ) + 32;
+ return packFloatx80( 0, 0x403E - shiftCount, zSig<<shiftCount );
+
+}
+
+#endif
+
+#ifdef FLOAT128
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the 32-bit two's complement integer `a' to
+the quadruple-precision floating-point format. The conversion is performed
+according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float128 int32_to_float128( int32 a )
+{
+ flag zSign;
+ uint32 absA;
+ int8 shiftCount;
+ bits64 zSig0;
+
+ if ( a == 0 ) return packFloat128( 0, 0, 0, 0 );
+ zSign = ( a < 0 );
+ absA = zSign ? - a : a;
+ shiftCount = countLeadingZeros32( absA ) + 17;
+ zSig0 = absA;
+ return packFloat128( zSign, 0x402E - shiftCount, zSig0<<shiftCount, 0 );
+
+}
+
+float128 uint32_to_float128( uint32 a )
+{
+ int8 shiftCount;
+ bits64 zSig0 = a;
+
+ if ( a == 0 ) return packFloat128( 0, 0, 0, 0 );
+ shiftCount = countLeadingZeros32( a ) + 17;
+ return packFloat128( 0, 0x402E - shiftCount, zSig0<<shiftCount, 0 );
+
+}
+
+#endif
+
+#ifndef SOFTFLOAT_FOR_GCC /* __floatdi?f is in libgcc2.c */
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the 64-bit two's complement integer `a'
+to the single-precision floating-point format. The conversion is performed
+according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float32 int64_to_float32( int64 a )
+{
+ flag zSign;
+ uint64 absA;
+ int8 shiftCount;
+
+ if ( a == 0 ) return 0;
+ zSign = ( a < 0 );
+ absA = zSign ? - a : a;
+ shiftCount = countLeadingZeros64( absA ) - 40;
+ if ( 0 <= shiftCount ) {
+ return packFloat32( zSign, 0x95 - shiftCount, absA<<shiftCount );
+ }
+ else {
+ shiftCount += 7;
+ if ( shiftCount < 0 ) {
+ shift64RightJamming( absA, - shiftCount, &absA );
+ }
+ else {
+ absA <<= shiftCount;
+ }
+ return roundAndPackFloat32( zSign, 0x9C - shiftCount, absA );
+ }
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the 64-bit two's complement integer `a'
+to the double-precision floating-point format. The conversion is performed
+according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float64 int64_to_float64( int64 a )
+{
+ flag zSign;
+
+ if ( a == 0 ) return 0;
+ if ( a == (sbits64) LIT64( 0x8000000000000000 ) ) {
+ return packFloat64( 1, 0x43E, 0 );
+ }
+ zSign = ( a < 0 );
+ return normalizeRoundAndPackFloat64( zSign, 0x43C, zSign ? - a : a );
+
+}
+
+#ifdef FLOATX80
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the 64-bit two's complement integer `a'
+to the extended double-precision floating-point format. The conversion
+is performed according to the IEC/IEEE Standard for Binary Floating-Point
+Arithmetic.
+-------------------------------------------------------------------------------
+*/
+floatx80 int64_to_floatx80( int64 a )
+{
+ flag zSign;
+ uint64 absA;
+ int8 shiftCount;
+
+ if ( a == 0 ) return packFloatx80( 0, 0, 0 );
+ zSign = ( a < 0 );
+ absA = zSign ? - a : a;
+ shiftCount = countLeadingZeros64( absA );
+ return packFloatx80( zSign, 0x403E - shiftCount, absA<<shiftCount );
+
+}
+
+#endif
+
+#endif /* !SOFTFLOAT_FOR_GCC */
+
+#ifdef FLOAT128
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the 64-bit two's complement integer `a' to
+the quadruple-precision floating-point format. The conversion is performed
+according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float128 int64_to_float128( int64 a )
+{
+ flag zSign;
+ uint64 absA;
+ int8 shiftCount;
+ int32 zExp;
+ bits64 zSig0, zSig1;
+
+ if ( a == 0 ) return packFloat128( 0, 0, 0, 0 );
+ zSign = ( a < 0 );
+ absA = zSign ? - a : a;
+ shiftCount = countLeadingZeros64( absA ) + 49;
+ zExp = 0x406E - shiftCount;
+ if ( 64 <= shiftCount ) {
+ zSig1 = 0;
+ zSig0 = absA;
+ shiftCount -= 64;
+ }
+ else {
+ zSig1 = absA;
+ zSig0 = 0;
+ }
+ shortShift128Left( zSig0, zSig1, shiftCount, &zSig0, &zSig1 );
+ return packFloat128( zSign, zExp, zSig0, zSig1 );
+
+}
+
+#endif
+
+#ifndef SOFTFLOAT_FOR_GCC /* Not needed */
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the single-precision floating-point value
+`a' to the 32-bit two's complement integer format. The conversion is
+performed according to the IEC/IEEE Standard for Binary Floating-Point
+Arithmetic---which means in particular that the conversion is rounded
+according to the current rounding mode. If `a' is a NaN, the largest
+positive integer is returned. Otherwise, if the conversion overflows, the
+largest integer with the same sign as `a' is returned.
+-------------------------------------------------------------------------------
+*/
+int32 float32_to_int32( float32 a )
+{
+ flag aSign;
+ int16 aExp, shiftCount;
+ bits32 aSig;
+ bits64 aSig64;
+
+ aSig = extractFloat32Frac( a );
+ aExp = extractFloat32Exp( a );
+ aSign = extractFloat32Sign( a );
+ if ( ( aExp == 0xFF ) && aSig ) aSign = 0;
+ if ( aExp ) aSig |= 0x00800000;
+ shiftCount = 0xAF - aExp;
+ aSig64 = aSig;
+ aSig64 <<= 32;
+ if ( 0 < shiftCount ) shift64RightJamming( aSig64, shiftCount, &aSig64 );
+ return roundAndPackInt32( aSign, aSig64 );
+
+}
+#endif /* !SOFTFLOAT_FOR_GCC */
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the single-precision floating-point value
+`a' to the 32-bit two's complement integer format. The conversion is
+performed according to the IEC/IEEE Standard for Binary Floating-Point
+Arithmetic, except that the conversion is always rounded toward zero.
+If `a' is a NaN, the largest positive integer is returned. Otherwise, if
+the conversion overflows, the largest integer with the same sign as `a' is
+returned.
+-------------------------------------------------------------------------------
+*/
+int32 float32_to_int32_round_to_zero( float32 a )
+{
+ flag aSign;
+ int16 aExp, shiftCount;
+ bits32 aSig;
+ int32 z;
+
+ aSig = extractFloat32Frac( a );
+ aExp = extractFloat32Exp( a );
+ aSign = extractFloat32Sign( a );
+ shiftCount = aExp - 0x9E;
+ if ( 0 <= shiftCount ) {
+ if ( a != 0xCF000000 ) {
+ float_raise( float_flag_invalid );
+ if ( ! aSign || ( ( aExp == 0xFF ) && aSig ) ) return 0x7FFFFFFF;
+ }
+ return (sbits32) 0x80000000;
+ }
+ else if ( aExp <= 0x7E ) {
+ if ( aExp | aSig ) float_exception_flags |= float_flag_inexact;
+ return 0;
+ }
+ aSig = ( aSig | 0x00800000 )<<8;
+ z = aSig>>( - shiftCount );
+ if ( (bits32) ( aSig<<( shiftCount & 31 ) ) ) {
+ float_exception_flags |= float_flag_inexact;
+ }
+ if ( aSign ) z = - z;
+ return z;
+
+}
+
+#ifndef SOFTFLOAT_FOR_GCC /* __fix?fdi provided by libgcc2.c */
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the single-precision floating-point value
+`a' to the 64-bit two's complement integer format. The conversion is
+performed according to the IEC/IEEE Standard for Binary Floating-Point
+Arithmetic---which means in particular that the conversion is rounded
+according to the current rounding mode. If `a' is a NaN, the largest
+positive integer is returned. Otherwise, if the conversion overflows, the
+largest integer with the same sign as `a' is returned.
+-------------------------------------------------------------------------------
+*/
+int64 float32_to_int64( float32 a )
+{
+ flag aSign;
+ int16 aExp, shiftCount;
+ bits32 aSig;
+ bits64 aSig64, aSigExtra;
+
+ aSig = extractFloat32Frac( a );
+ aExp = extractFloat32Exp( a );
+ aSign = extractFloat32Sign( a );
+ shiftCount = 0xBE - aExp;
+ if ( shiftCount < 0 ) {
+ float_raise( float_flag_invalid );
+ if ( ! aSign || ( ( aExp == 0xFF ) && aSig ) ) {
+ return LIT64( 0x7FFFFFFFFFFFFFFF );
+ }
+ return (sbits64) LIT64( 0x8000000000000000 );
+ }
+ if ( aExp ) aSig |= 0x00800000;
+ aSig64 = aSig;
+ aSig64 <<= 40;
+ shift64ExtraRightJamming( aSig64, 0, shiftCount, &aSig64, &aSigExtra );
+ return roundAndPackInt64( aSign, aSig64, aSigExtra );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the single-precision floating-point value
+`a' to the 64-bit two's complement integer format. The conversion is
+performed according to the IEC/IEEE Standard for Binary Floating-Point
+Arithmetic, except that the conversion is always rounded toward zero. If
+`a' is a NaN, the largest positive integer is returned. Otherwise, if the
+conversion overflows, the largest integer with the same sign as `a' is
+returned.
+-------------------------------------------------------------------------------
+*/
+int64 float32_to_int64_round_to_zero( float32 a )
+{
+ flag aSign;
+ int16 aExp, shiftCount;
+ bits32 aSig;
+ bits64 aSig64;
+ int64 z;
+
+ aSig = extractFloat32Frac( a );
+ aExp = extractFloat32Exp( a );
+ aSign = extractFloat32Sign( a );
+ shiftCount = aExp - 0xBE;
+ if ( 0 <= shiftCount ) {
+ if ( a != 0xDF000000 ) {
+ float_raise( float_flag_invalid );
+ if ( ! aSign || ( ( aExp == 0xFF ) && aSig ) ) {
+ return LIT64( 0x7FFFFFFFFFFFFFFF );
+ }
+ }
+ return (sbits64) LIT64( 0x8000000000000000 );
+ }
+ else if ( aExp <= 0x7E ) {
+ if ( aExp | aSig ) float_exception_flags |= float_flag_inexact;
+ return 0;
+ }
+ aSig64 = aSig | 0x00800000;
+ aSig64 <<= 40;
+ z = aSig64>>( - shiftCount );
+ if ( (bits64) ( aSig64<<( shiftCount & 63 ) ) ) {
+ float_exception_flags |= float_flag_inexact;
+ }
+ if ( aSign ) z = - z;
+ return z;
+
+}
+#endif /* !SOFTFLOAT_FOR_GCC */
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the single-precision floating-point value
+`a' to the double-precision floating-point format. The conversion is
+performed according to the IEC/IEEE Standard for Binary Floating-Point
+Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float64 float32_to_float64( float32 a )
+{
+ flag aSign;
+ int16 aExp;
+ bits32 aSig;
+
+ aSig = extractFloat32Frac( a );
+ aExp = extractFloat32Exp( a );
+ aSign = extractFloat32Sign( a );
+ if ( aExp == 0xFF ) {
+ if ( aSig ) return commonNaNToFloat64( float32ToCommonNaN( a ) );
+ return packFloat64( aSign, 0x7FF, 0 );
+ }
+ if ( aExp == 0 ) {
+ if ( aSig == 0 ) return packFloat64( aSign, 0, 0 );
+ normalizeFloat32Subnormal( aSig, &aExp, &aSig );
+ --aExp;
+ }
+ return packFloat64( aSign, aExp + 0x380, ( (bits64) aSig )<<29 );
+
+}
+
+#ifdef FLOATX80
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the single-precision floating-point value
+`a' to the extended double-precision floating-point format. The conversion
+is performed according to the IEC/IEEE Standard for Binary Floating-Point
+Arithmetic.
+-------------------------------------------------------------------------------
+*/
+floatx80 float32_to_floatx80( float32 a )
+{
+ flag aSign;
+ int16 aExp;
+ bits32 aSig;
+
+ aSig = extractFloat32Frac( a );
+ aExp = extractFloat32Exp( a );
+ aSign = extractFloat32Sign( a );
+ if ( aExp == 0xFF ) {
+ if ( aSig ) return commonNaNToFloatx80( float32ToCommonNaN( a ) );
+ return packFloatx80( aSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
+ }
+ if ( aExp == 0 ) {
+ if ( aSig == 0 ) return packFloatx80( aSign, 0, 0 );
+ normalizeFloat32Subnormal( aSig, &aExp, &aSig );
+ }
+ aSig |= 0x00800000;
+ return packFloatx80( aSign, aExp + 0x3F80, ( (bits64) aSig )<<40 );
+
+}
+
+#endif
+
+#ifdef FLOAT128
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the single-precision floating-point value
+`a' to the double-precision floating-point format. The conversion is
+performed according to the IEC/IEEE Standard for Binary Floating-Point
+Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float128 float32_to_float128( float32 a )
+{
+ flag aSign;
+ int16 aExp;
+ bits32 aSig;
+
+ aSig = extractFloat32Frac( a );
+ aExp = extractFloat32Exp( a );
+ aSign = extractFloat32Sign( a );
+ if ( aExp == 0xFF ) {
+ if ( aSig ) return commonNaNToFloat128( float32ToCommonNaN( a ) );
+ return packFloat128( aSign, 0x7FFF, 0, 0 );
+ }
+ if ( aExp == 0 ) {
+ if ( aSig == 0 ) return packFloat128( aSign, 0, 0, 0 );
+ normalizeFloat32Subnormal( aSig, &aExp, &aSig );
+ --aExp;
+ }
+ return packFloat128( aSign, aExp + 0x3F80, ( (bits64) aSig )<<25, 0 );
+
+}
+
+#endif
+
+#ifndef SOFTFLOAT_FOR_GCC /* Not needed */
+/*
+-------------------------------------------------------------------------------
+Rounds the single-precision floating-point value `a' to an integer, and
+returns the result as a single-precision floating-point value. The
+operation is performed according to the IEC/IEEE Standard for Binary
+Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float32 float32_round_to_int( float32 a )
+{
+ flag aSign;
+ int16 aExp;
+ bits32 lastBitMask, roundBitsMask;
+ int8 roundingMode;
+ float32 z;
+
+ aExp = extractFloat32Exp( a );
+ if ( 0x96 <= aExp ) {
+ if ( ( aExp == 0xFF ) && extractFloat32Frac( a ) ) {
+ return propagateFloat32NaN( a, a );
+ }
+ return a;
+ }
+ if ( aExp <= 0x7E ) {
+ if ( (bits32) ( a<<1 ) == 0 ) return a;
+ float_exception_flags |= float_flag_inexact;
+ aSign = extractFloat32Sign( a );
+ switch ( float_rounding_mode ) {
+ case float_round_nearest_even:
+ if ( ( aExp == 0x7E ) && extractFloat32Frac( a ) ) {
+ return packFloat32( aSign, 0x7F, 0 );
+ }
+ break;
+ case float_round_to_zero:
+ break;
+ case float_round_down:
+ return aSign ? 0xBF800000 : 0;
+ case float_round_up:
+ return aSign ? 0x80000000 : 0x3F800000;
+ }
+ return packFloat32( aSign, 0, 0 );
+ }
+ lastBitMask = 1;
+ lastBitMask <<= 0x96 - aExp;
+ roundBitsMask = lastBitMask - 1;
+ z = a;
+ roundingMode = float_rounding_mode;
+ if ( roundingMode == float_round_nearest_even ) {
+ z += lastBitMask>>1;
+ if ( ( z & roundBitsMask ) == 0 ) z &= ~ lastBitMask;
+ }
+ else if ( roundingMode != float_round_to_zero ) {
+ if ( extractFloat32Sign( z ) ^ ( roundingMode == float_round_up ) ) {
+ z += roundBitsMask;
+ }
+ }
+ z &= ~ roundBitsMask;
+ if ( z != a ) float_exception_flags |= float_flag_inexact;
+ return z;
+
+}
+#endif /* !SOFTFLOAT_FOR_GCC */
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of adding the absolute values of the single-precision
+floating-point values `a' and `b'. If `zSign' is 1, the sum is negated
+before being returned. `zSign' is ignored if the result is a NaN.
+The addition is performed according to the IEC/IEEE Standard for Binary
+Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+static float32 addFloat32Sigs( float32 a, float32 b, flag zSign )
+{
+ int16 aExp, bExp, zExp;
+ bits32 aSig, bSig, zSig;
+ int16 expDiff;
+
+ aSig = extractFloat32Frac( a );
+ aExp = extractFloat32Exp( a );
+ bSig = extractFloat32Frac( b );
+ bExp = extractFloat32Exp( b );
+ expDiff = aExp - bExp;
+ aSig <<= 6;
+ bSig <<= 6;
+ if ( 0 < expDiff ) {
+ if ( aExp == 0xFF ) {
+ if ( aSig ) return propagateFloat32NaN( a, b );
+ return a;
+ }
+ if ( bExp == 0 ) {
+ --expDiff;
+ }
+ else {
+ bSig |= 0x20000000;
+ }
+ shift32RightJamming( bSig, expDiff, &bSig );
+ zExp = aExp;
+ }
+ else if ( expDiff < 0 ) {
+ if ( bExp == 0xFF ) {
+ if ( bSig ) return propagateFloat32NaN( a, b );
+ return packFloat32( zSign, 0xFF, 0 );
+ }
+ if ( aExp == 0 ) {
+ ++expDiff;
+ }
+ else {
+ aSig |= 0x20000000;
+ }
+ shift32RightJamming( aSig, - expDiff, &aSig );
+ zExp = bExp;
+ }
+ else {
+ if ( aExp == 0xFF ) {
+ if ( aSig | bSig ) return propagateFloat32NaN( a, b );
+ return a;
+ }
+ if ( aExp == 0 ) return packFloat32( zSign, 0, ( aSig + bSig )>>6 );
+ zSig = 0x40000000 + aSig + bSig;
+ zExp = aExp;
+ goto roundAndPack;
+ }
+ aSig |= 0x20000000;
+ zSig = ( aSig + bSig )<<1;
+ --zExp;
+ if ( (sbits32) zSig < 0 ) {
+ zSig = aSig + bSig;
+ ++zExp;
+ }
+ roundAndPack:
+ return roundAndPackFloat32( zSign, zExp, zSig );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of subtracting the absolute values of the single-
+precision floating-point values `a' and `b'. If `zSign' is 1, the
+difference is negated before being returned. `zSign' is ignored if the
+result is a NaN. The subtraction is performed according to the IEC/IEEE
+Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+static float32 subFloat32Sigs( float32 a, float32 b, flag zSign )
+{
+ int16 aExp, bExp, zExp;
+ bits32 aSig, bSig, zSig;
+ int16 expDiff;
+
+ aSig = extractFloat32Frac( a );
+ aExp = extractFloat32Exp( a );
+ bSig = extractFloat32Frac( b );
+ bExp = extractFloat32Exp( b );
+ expDiff = aExp - bExp;
+ aSig <<= 7;
+ bSig <<= 7;
+ if ( 0 < expDiff ) goto aExpBigger;
+ if ( expDiff < 0 ) goto bExpBigger;
+ if ( aExp == 0xFF ) {
+ if ( aSig | bSig ) return propagateFloat32NaN( a, b );
+ float_raise( float_flag_invalid );
+ return float32_default_nan;
+ }
+ if ( aExp == 0 ) {
+ aExp = 1;
+ bExp = 1;
+ }
+ if ( bSig < aSig ) goto aBigger;
+ if ( aSig < bSig ) goto bBigger;
+ return packFloat32( float_rounding_mode == float_round_down, 0, 0 );
+ bExpBigger:
+ if ( bExp == 0xFF ) {
+ if ( bSig ) return propagateFloat32NaN( a, b );
+ return packFloat32( zSign ^ 1, 0xFF, 0 );
+ }
+ if ( aExp == 0 ) {
+ ++expDiff;
+ }
+ else {
+ aSig |= 0x40000000;
+ }
+ shift32RightJamming( aSig, - expDiff, &aSig );
+ bSig |= 0x40000000;
+ bBigger:
+ zSig = bSig - aSig;
+ zExp = bExp;
+ zSign ^= 1;
+ goto normalizeRoundAndPack;
+ aExpBigger:
+ if ( aExp == 0xFF ) {
+ if ( aSig ) return propagateFloat32NaN( a, b );
+ return a;
+ }
+ if ( bExp == 0 ) {
+ --expDiff;
+ }
+ else {
+ bSig |= 0x40000000;
+ }
+ shift32RightJamming( bSig, expDiff, &bSig );
+ aSig |= 0x40000000;
+ aBigger:
+ zSig = aSig - bSig;
+ zExp = aExp;
+ normalizeRoundAndPack:
+ --zExp;
+ return normalizeRoundAndPackFloat32( zSign, zExp, zSig );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of adding the single-precision floating-point values `a'
+and `b'. The operation is performed according to the IEC/IEEE Standard for
+Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float32 float32_add( float32 a, float32 b )
+{
+ flag aSign, bSign;
+
+ aSign = extractFloat32Sign( a );
+ bSign = extractFloat32Sign( b );
+ if ( aSign == bSign ) {
+ return addFloat32Sigs( a, b, aSign );
+ }
+ else {
+ return subFloat32Sigs( a, b, aSign );
+ }
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of subtracting the single-precision floating-point values
+`a' and `b'. The operation is performed according to the IEC/IEEE Standard
+for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float32 float32_sub( float32 a, float32 b )
+{
+ flag aSign, bSign;
+
+ aSign = extractFloat32Sign( a );
+ bSign = extractFloat32Sign( b );
+ if ( aSign == bSign ) {
+ return subFloat32Sigs( a, b, aSign );
+ }
+ else {
+ return addFloat32Sigs( a, b, aSign );
+ }
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of multiplying the single-precision floating-point values
+`a' and `b'. The operation is performed according to the IEC/IEEE Standard
+for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float32 float32_mul( float32 a, float32 b )
+{
+ flag aSign, bSign, zSign;
+ int16 aExp, bExp, zExp;
+ bits32 aSig, bSig;
+ bits64 zSig64;
+ bits32 zSig;
+
+ aSig = extractFloat32Frac( a );
+ aExp = extractFloat32Exp( a );
+ aSign = extractFloat32Sign( a );
+ bSig = extractFloat32Frac( b );
+ bExp = extractFloat32Exp( b );
+ bSign = extractFloat32Sign( b );
+ zSign = aSign ^ bSign;
+ if ( aExp == 0xFF ) {
+ if ( aSig || ( ( bExp == 0xFF ) && bSig ) ) {
+ return propagateFloat32NaN( a, b );
+ }
+ if ( ( bExp | bSig ) == 0 ) {
+ float_raise( float_flag_invalid );
+ return float32_default_nan;
+ }
+ return packFloat32( zSign, 0xFF, 0 );
+ }
+ if ( bExp == 0xFF ) {
+ if ( bSig ) return propagateFloat32NaN( a, b );
+ if ( ( aExp | aSig ) == 0 ) {
+ float_raise( float_flag_invalid );
+ return float32_default_nan;
+ }
+ return packFloat32( zSign, 0xFF, 0 );
+ }
+ if ( aExp == 0 ) {
+ if ( aSig == 0 ) return packFloat32( zSign, 0, 0 );
+ normalizeFloat32Subnormal( aSig, &aExp, &aSig );
+ }
+ if ( bExp == 0 ) {
+ if ( bSig == 0 ) return packFloat32( zSign, 0, 0 );
+ normalizeFloat32Subnormal( bSig, &bExp, &bSig );
+ }
+ zExp = aExp + bExp - 0x7F;
+ aSig = ( aSig | 0x00800000 )<<7;
+ bSig = ( bSig | 0x00800000 )<<8;
+ shift64RightJamming( ( (bits64) aSig ) * bSig, 32, &zSig64 );
+ zSig = zSig64;
+ if ( 0 <= (sbits32) ( zSig<<1 ) ) {
+ zSig <<= 1;
+ --zExp;
+ }
+ return roundAndPackFloat32( zSign, zExp, zSig );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of dividing the single-precision floating-point value `a'
+by the corresponding value `b'. The operation is performed according to the
+IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float32 float32_div( float32 a, float32 b )
+{
+ flag aSign, bSign, zSign;
+ int16 aExp, bExp, zExp;
+ bits32 aSig, bSig, zSig;
+
+ aSig = extractFloat32Frac( a );
+ aExp = extractFloat32Exp( a );
+ aSign = extractFloat32Sign( a );
+ bSig = extractFloat32Frac( b );
+ bExp = extractFloat32Exp( b );
+ bSign = extractFloat32Sign( b );
+ zSign = aSign ^ bSign;
+ if ( aExp == 0xFF ) {
+ if ( aSig ) return propagateFloat32NaN( a, b );
+ if ( bExp == 0xFF ) {
+ if ( bSig ) return propagateFloat32NaN( a, b );
+ float_raise( float_flag_invalid );
+ return float32_default_nan;
+ }
+ return packFloat32( zSign, 0xFF, 0 );
+ }
+ if ( bExp == 0xFF ) {
+ if ( bSig ) return propagateFloat32NaN( a, b );
+ return packFloat32( zSign, 0, 0 );
+ }
+ if ( bExp == 0 ) {
+ if ( bSig == 0 ) {
+ if ( ( aExp | aSig ) == 0 ) {
+ float_raise( float_flag_invalid );
+ return float32_default_nan;
+ }
+ float_raise( float_flag_divbyzero );
+ return packFloat32( zSign, 0xFF, 0 );
+ }
+ normalizeFloat32Subnormal( bSig, &bExp, &bSig );
+ }
+ if ( aExp == 0 ) {
+ if ( aSig == 0 ) return packFloat32( zSign, 0, 0 );
+ normalizeFloat32Subnormal( aSig, &aExp, &aSig );
+ }
+ zExp = aExp - bExp + 0x7D;
+ aSig = ( aSig | 0x00800000 )<<7;
+ bSig = ( bSig | 0x00800000 )<<8;
+ if ( bSig <= ( aSig + aSig ) ) {
+ aSig >>= 1;
+ ++zExp;
+ }
+ zSig = ( ( (bits64) aSig )<<32 ) / bSig;
+ if ( ( zSig & 0x3F ) == 0 ) {
+ zSig |= ( (bits64) bSig * zSig != ( (bits64) aSig )<<32 );
+ }
+ return roundAndPackFloat32( zSign, zExp, zSig );
+
+}
+
+#ifndef SOFTFLOAT_FOR_GCC /* Not needed */
+/*
+-------------------------------------------------------------------------------
+Returns the remainder of the single-precision floating-point value `a'
+with respect to the corresponding value `b'. The operation is performed
+according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float32 float32_rem( float32 a, float32 b )
+{
+ flag aSign, bSign, zSign;
+ int16 aExp, bExp, expDiff;
+ bits32 aSig, bSig;
+ bits32 q;
+ bits64 aSig64, bSig64, q64;
+ bits32 alternateASig;
+ sbits32 sigMean;
+
+ aSig = extractFloat32Frac( a );
+ aExp = extractFloat32Exp( a );
+ aSign = extractFloat32Sign( a );
+ bSig = extractFloat32Frac( b );
+ bExp = extractFloat32Exp( b );
+ bSign = extractFloat32Sign( b );
+ if ( aExp == 0xFF ) {
+ if ( aSig || ( ( bExp == 0xFF ) && bSig ) ) {
+ return propagateFloat32NaN( a, b );
+ }
+ float_raise( float_flag_invalid );
+ return float32_default_nan;
+ }
+ if ( bExp == 0xFF ) {
+ if ( bSig ) return propagateFloat32NaN( a, b );
+ return a;
+ }
+ if ( bExp == 0 ) {
+ if ( bSig == 0 ) {
+ float_raise( float_flag_invalid );
+ return float32_default_nan;
+ }
+ normalizeFloat32Subnormal( bSig, &bExp, &bSig );
+ }
+ if ( aExp == 0 ) {
+ if ( aSig == 0 ) return a;
+ normalizeFloat32Subnormal( aSig, &aExp, &aSig );
+ }
+ expDiff = aExp - bExp;
+ aSig |= 0x00800000;
+ bSig |= 0x00800000;
+ if ( expDiff < 32 ) {
+ aSig <<= 8;
+ bSig <<= 8;
+ if ( expDiff < 0 ) {
+ if ( expDiff < -1 ) return a;
+ aSig >>= 1;
+ }
+ q = ( bSig <= aSig );
+ if ( q ) aSig -= bSig;
+ if ( 0 < expDiff ) {
+ q = ( ( (bits64) aSig )<<32 ) / bSig;
+ q >>= 32 - expDiff;
+ bSig >>= 2;
+ aSig = ( ( aSig>>1 )<<( expDiff - 1 ) ) - bSig * q;
+ }
+ else {
+ aSig >>= 2;
+ bSig >>= 2;
+ }
+ }
+ else {
+ if ( bSig <= aSig ) aSig -= bSig;
+ aSig64 = ( (bits64) aSig )<<40;
+ bSig64 = ( (bits64) bSig )<<40;
+ expDiff -= 64;
+ while ( 0 < expDiff ) {
+ q64 = estimateDiv128To64( aSig64, 0, bSig64 );
+ q64 = ( 2 < q64 ) ? q64 - 2 : 0;
+ aSig64 = - ( ( bSig * q64 )<<38 );
+ expDiff -= 62;
+ }
+ expDiff += 64;
+ q64 = estimateDiv128To64( aSig64, 0, bSig64 );
+ q64 = ( 2 < q64 ) ? q64 - 2 : 0;
+ q = q64>>( 64 - expDiff );
+ bSig <<= 6;
+ aSig = ( ( aSig64>>33 )<<( expDiff - 1 ) ) - bSig * q;
+ }
+ do {
+ alternateASig = aSig;
+ ++q;
+ aSig -= bSig;
+ } while ( 0 <= (sbits32) aSig );
+ sigMean = aSig + alternateASig;
+ if ( ( sigMean < 0 ) || ( ( sigMean == 0 ) && ( q & 1 ) ) ) {
+ aSig = alternateASig;
+ }
+ zSign = ( (sbits32) aSig < 0 );
+ if ( zSign ) aSig = - aSig;
+ return normalizeRoundAndPackFloat32( aSign ^ zSign, bExp, aSig );
+
+}
+#endif /* !SOFTFLOAT_FOR_GCC */
+
+#ifndef SOFTFLOAT_FOR_GCC /* Not needed */
+/*
+-------------------------------------------------------------------------------
+Returns the square root of the single-precision floating-point value `a'.
+The operation is performed according to the IEC/IEEE Standard for Binary
+Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float32 float32_sqrt( float32 a )
+{
+ flag aSign;
+ int16 aExp, zExp;
+ bits32 aSig, zSig;
+ bits64 rem, term;
+
+ aSig = extractFloat32Frac( a );
+ aExp = extractFloat32Exp( a );
+ aSign = extractFloat32Sign( a );
+ if ( aExp == 0xFF ) {
+ if ( aSig ) return propagateFloat32NaN( a, 0 );
+ if ( ! aSign ) return a;
+ float_raise( float_flag_invalid );
+ return float32_default_nan;
+ }
+ if ( aSign ) {
+ if ( ( aExp | aSig ) == 0 ) return a;
+ float_raise( float_flag_invalid );
+ return float32_default_nan;
+ }
+ if ( aExp == 0 ) {
+ if ( aSig == 0 ) return 0;
+ normalizeFloat32Subnormal( aSig, &aExp, &aSig );
+ }
+ zExp = ( ( aExp - 0x7F )>>1 ) + 0x7E;
+ aSig = ( aSig | 0x00800000 )<<8;
+ zSig = estimateSqrt32( aExp, aSig ) + 2;
+ if ( ( zSig & 0x7F ) <= 5 ) {
+ if ( zSig < 2 ) {
+ zSig = 0x7FFFFFFF;
+ goto roundAndPack;
+ }
+ aSig >>= aExp & 1;
+ term = ( (bits64) zSig ) * zSig;
+ rem = ( ( (bits64) aSig )<<32 ) - term;
+ while ( (sbits64) rem < 0 ) {
+ --zSig;
+ rem += ( ( (bits64) zSig )<<1 ) | 1;
+ }
+ zSig |= ( rem != 0 );
+ }
+ shift32RightJamming( zSig, 1, &zSig );
+ roundAndPack:
+ return roundAndPackFloat32( 0, zExp, zSig );
+
+}
+#endif /* !SOFTFLOAT_FOR_GCC */
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the single-precision floating-point value `a' is equal to
+the corresponding value `b', and 0 otherwise. The comparison is performed
+according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float32_eq( float32 a, float32 b )
+{
+
+ if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
+ || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
+ ) {
+ if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) {
+ float_raise( float_flag_invalid );
+ }
+ return 0;
+ }
+ return ( a == b ) || ( (bits32) ( ( a | b )<<1 ) == 0 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the single-precision floating-point value `a' is less than
+or equal to the corresponding value `b', and 0 otherwise. The comparison
+is performed according to the IEC/IEEE Standard for Binary Floating-Point
+Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float32_le( float32 a, float32 b )
+{
+ flag aSign, bSign;
+
+ if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
+ || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
+ ) {
+ float_raise( float_flag_invalid );
+ return 0;
+ }
+ aSign = extractFloat32Sign( a );
+ bSign = extractFloat32Sign( b );
+ if ( aSign != bSign ) return aSign || ( (bits32) ( ( a | b )<<1 ) == 0 );
+ return ( a == b ) || ( aSign ^ ( a < b ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the single-precision floating-point value `a' is less than
+the corresponding value `b', and 0 otherwise. The comparison is performed
+according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float32_lt( float32 a, float32 b )
+{
+ flag aSign, bSign;
+
+ if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
+ || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
+ ) {
+ float_raise( float_flag_invalid );
+ return 0;
+ }
+ aSign = extractFloat32Sign( a );
+ bSign = extractFloat32Sign( b );
+ if ( aSign != bSign ) return aSign && ( (bits32) ( ( a | b )<<1 ) != 0 );
+ return ( a != b ) && ( aSign ^ ( a < b ) );
+
+}
+
+#ifndef SOFTFLOAT_FOR_GCC /* Not needed */
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the single-precision floating-point value `a' is equal to
+the corresponding value `b', and 0 otherwise. The invalid exception is
+raised if either operand is a NaN. Otherwise, the comparison is performed
+according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float32_eq_signaling( float32 a, float32 b )
+{
+
+ if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
+ || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
+ ) {
+ float_raise( float_flag_invalid );
+ return 0;
+ }
+ return ( a == b ) || ( (bits32) ( ( a | b )<<1 ) == 0 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the single-precision floating-point value `a' is less than or
+equal to the corresponding value `b', and 0 otherwise. Quiet NaNs do not
+cause an exception. Otherwise, the comparison is performed according to the
+IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float32_le_quiet( float32 a, float32 b )
+{
+ flag aSign, bSign;
+
+ if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
+ || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
+ ) {
+ if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) {
+ float_raise( float_flag_invalid );
+ }
+ return 0;
+ }
+ aSign = extractFloat32Sign( a );
+ bSign = extractFloat32Sign( b );
+ if ( aSign != bSign ) return aSign || ( (bits32) ( ( a | b )<<1 ) == 0 );
+ return ( a == b ) || ( aSign ^ ( a < b ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the single-precision floating-point value `a' is less than
+the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an
+exception. Otherwise, the comparison is performed according to the IEC/IEEE
+Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float32_lt_quiet( float32 a, float32 b )
+{
+ flag aSign, bSign;
+
+ if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
+ || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
+ ) {
+ if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) {
+ float_raise( float_flag_invalid );
+ }
+ return 0;
+ }
+ aSign = extractFloat32Sign( a );
+ bSign = extractFloat32Sign( b );
+ if ( aSign != bSign ) return aSign && ( (bits32) ( ( a | b )<<1 ) != 0 );
+ return ( a != b ) && ( aSign ^ ( a < b ) );
+
+}
+#endif /* !SOFTFLOAT_FOR_GCC */
+
+#ifndef SOFTFLOAT_FOR_GCC /* Not needed */
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the double-precision floating-point value
+`a' to the 32-bit two's complement integer format. The conversion is
+performed according to the IEC/IEEE Standard for Binary Floating-Point
+Arithmetic---which means in particular that the conversion is rounded
+according to the current rounding mode. If `a' is a NaN, the largest
+positive integer is returned. Otherwise, if the conversion overflows, the
+largest integer with the same sign as `a' is returned.
+-------------------------------------------------------------------------------
+*/
+int32 float64_to_int32( float64 a )
+{
+ flag aSign;
+ int16 aExp, shiftCount;
+ bits64 aSig;
+
+ aSig = extractFloat64Frac( a );
+ aExp = extractFloat64Exp( a );
+ aSign = extractFloat64Sign( a );
+ if ( ( aExp == 0x7FF ) && aSig ) aSign = 0;
+ if ( aExp ) aSig |= LIT64( 0x0010000000000000 );
+ shiftCount = 0x42C - aExp;
+ if ( 0 < shiftCount ) shift64RightJamming( aSig, shiftCount, &aSig );
+ return roundAndPackInt32( aSign, aSig );
+
+}
+#endif /* !SOFTFLOAT_FOR_GCC */
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the double-precision floating-point value
+`a' to the 32-bit two's complement integer format. The conversion is
+performed according to the IEC/IEEE Standard for Binary Floating-Point
+Arithmetic, except that the conversion is always rounded toward zero.
+If `a' is a NaN, the largest positive integer is returned. Otherwise, if
+the conversion overflows, the largest integer with the same sign as `a' is
+returned.
+-------------------------------------------------------------------------------
+*/
+int32 float64_to_int32_round_to_zero( float64 a )
+{
+ flag aSign;
+ int16 aExp, shiftCount;
+ bits64 aSig, savedASig;
+ int32 z;
+
+ aSig = extractFloat64Frac( a );
+ aExp = extractFloat64Exp( a );
+ aSign = extractFloat64Sign( a );
+ if ( 0x41E < aExp ) {
+ if ( ( aExp == 0x7FF ) && aSig ) aSign = 0;
+ goto invalid;
+ }
+ else if ( aExp < 0x3FF ) {
+ if ( aExp || aSig ) float_exception_flags |= float_flag_inexact;
+ return 0;
+ }
+ aSig |= LIT64( 0x0010000000000000 );
+ shiftCount = 0x433 - aExp;
+ savedASig = aSig;
+ aSig >>= shiftCount;
+ z = aSig;
+ if ( aSign ) z = - z;
+ if ( ( z < 0 ) ^ aSign ) {
+ invalid:
+ float_raise( float_flag_invalid );
+ return aSign ? (sbits32) 0x80000000 : 0x7FFFFFFF;
+ }
+ if ( ( aSig<<shiftCount ) != savedASig ) {
+ float_exception_flags |= float_flag_inexact;
+ }
+ return z;
+
+}
+
+#ifndef SOFTFLOAT_FOR_GCC /* Not needed */
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the double-precision floating-point value
+`a' to the 64-bit two's complement integer format. The conversion is
+performed according to the IEC/IEEE Standard for Binary Floating-Point
+Arithmetic---which means in particular that the conversion is rounded
+according to the current rounding mode. If `a' is a NaN, the largest
+positive integer is returned. Otherwise, if the conversion overflows, the
+largest integer with the same sign as `a' is returned.
+-------------------------------------------------------------------------------
+*/
+int64 float64_to_int64( float64 a )
+{
+ flag aSign;
+ int16 aExp, shiftCount;
+ bits64 aSig, aSigExtra;
+
+ aSig = extractFloat64Frac( a );
+ aExp = extractFloat64Exp( a );
+ aSign = extractFloat64Sign( a );
+ if ( aExp ) aSig |= LIT64( 0x0010000000000000 );
+ shiftCount = 0x433 - aExp;
+ if ( shiftCount <= 0 ) {
+ if ( 0x43E < aExp ) {
+ float_raise( float_flag_invalid );
+ if ( ! aSign
+ || ( ( aExp == 0x7FF )
+ && ( aSig != LIT64( 0x0010000000000000 ) ) )
+ ) {
+ return LIT64( 0x7FFFFFFFFFFFFFFF );
+ }
+ return (sbits64) LIT64( 0x8000000000000000 );
+ }
+ aSigExtra = 0;
+ aSig <<= - shiftCount;
+ }
+ else {
+ shift64ExtraRightJamming( aSig, 0, shiftCount, &aSig, &aSigExtra );
+ }
+ return roundAndPackInt64( aSign, aSig, aSigExtra );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the double-precision floating-point value
+`a' to the 64-bit two's complement integer format. The conversion is
+performed according to the IEC/IEEE Standard for Binary Floating-Point
+Arithmetic, except that the conversion is always rounded toward zero.
+If `a' is a NaN, the largest positive integer is returned. Otherwise, if
+the conversion overflows, the largest integer with the same sign as `a' is
+returned.
+-------------------------------------------------------------------------------
+*/
+int64 float64_to_int64_round_to_zero( float64 a )
+{
+ flag aSign;
+ int16 aExp, shiftCount;
+ bits64 aSig;
+ int64 z;
+
+ aSig = extractFloat64Frac( a );
+ aExp = extractFloat64Exp( a );
+ aSign = extractFloat64Sign( a );
+ if ( aExp ) aSig |= LIT64( 0x0010000000000000 );
+ shiftCount = aExp - 0x433;
+ if ( 0 <= shiftCount ) {
+ if ( 0x43E <= aExp ) {
+ if ( a != LIT64( 0xC3E0000000000000 ) ) {
+ float_raise( float_flag_invalid );
+ if ( ! aSign
+ || ( ( aExp == 0x7FF )
+ && ( aSig != LIT64( 0x0010000000000000 ) ) )
+ ) {
+ return LIT64( 0x7FFFFFFFFFFFFFFF );
+ }
+ }
+ return (sbits64) LIT64( 0x8000000000000000 );
+ }
+ z = aSig<<shiftCount;
+ }
+ else {
+ if ( aExp < 0x3FE ) {
+ if ( aExp | aSig ) float_exception_flags |= float_flag_inexact;
+ return 0;
+ }
+ z = aSig>>( - shiftCount );
+ if ( (bits64) ( aSig<<( shiftCount & 63 ) ) ) {
+ float_exception_flags |= float_flag_inexact;
+ }
+ }
+ if ( aSign ) z = - z;
+ return z;
+
+}
+#endif /* !SOFTFLOAT_FOR_GCC */
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the double-precision floating-point value
+`a' to the single-precision floating-point format. The conversion is
+performed according to the IEC/IEEE Standard for Binary Floating-Point
+Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float32 float64_to_float32( float64 a )
+{
+ flag aSign;
+ int16 aExp;
+ bits64 aSig;
+ bits32 zSig;
+
+ aSig = extractFloat64Frac( a );
+ aExp = extractFloat64Exp( a );
+ aSign = extractFloat64Sign( a );
+ if ( aExp == 0x7FF ) {
+ if ( aSig ) return commonNaNToFloat32( float64ToCommonNaN( a ) );
+ return packFloat32( aSign, 0xFF, 0 );
+ }
+ shift64RightJamming( aSig, 22, &aSig );
+ zSig = aSig;
+ if ( aExp || zSig ) {
+ zSig |= 0x40000000;
+ aExp -= 0x381;
+ }
+ return roundAndPackFloat32( aSign, aExp, zSig );
+
+}
+
+#ifdef FLOATX80
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the double-precision floating-point value
+`a' to the extended double-precision floating-point format. The conversion
+is performed according to the IEC/IEEE Standard for Binary Floating-Point
+Arithmetic.
+-------------------------------------------------------------------------------
+*/
+floatx80 float64_to_floatx80( float64 a )
+{
+ flag aSign;
+ int16 aExp;
+ bits64 aSig;
+
+ aSig = extractFloat64Frac( a );
+ aExp = extractFloat64Exp( a );
+ aSign = extractFloat64Sign( a );
+ if ( aExp == 0x7FF ) {
+ if ( aSig ) return commonNaNToFloatx80( float64ToCommonNaN( a ) );
+ return packFloatx80( aSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
+ }
+ if ( aExp == 0 ) {
+ if ( aSig == 0 ) return packFloatx80( aSign, 0, 0 );
+ normalizeFloat64Subnormal( aSig, &aExp, &aSig );
+ }
+ return
+ packFloatx80(
+ aSign, aExp + 0x3C00, ( aSig | LIT64( 0x0010000000000000 ) )<<11 );
+
+}
+
+#endif
+
+#ifdef FLOAT128
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the double-precision floating-point value
+`a' to the quadruple-precision floating-point format. The conversion is
+performed according to the IEC/IEEE Standard for Binary Floating-Point
+Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float128 float64_to_float128( float64 a )
+{
+ flag aSign;
+ int16 aExp;
+ bits64 aSig, zSig0, zSig1;
+
+ aSig = extractFloat64Frac( a );
+ aExp = extractFloat64Exp( a );
+ aSign = extractFloat64Sign( a );
+ if ( aExp == 0x7FF ) {
+ if ( aSig ) return commonNaNToFloat128( float64ToCommonNaN( a ) );
+ return packFloat128( aSign, 0x7FFF, 0, 0 );
+ }
+ if ( aExp == 0 ) {
+ if ( aSig == 0 ) return packFloat128( aSign, 0, 0, 0 );
+ normalizeFloat64Subnormal( aSig, &aExp, &aSig );
+ --aExp;
+ }
+ shift128Right( aSig, 0, 4, &zSig0, &zSig1 );
+ return packFloat128( aSign, aExp + 0x3C00, zSig0, zSig1 );
+
+}
+
+#endif
+
+#ifndef SOFTFLOAT_FOR_GCC
+/*
+-------------------------------------------------------------------------------
+Rounds the double-precision floating-point value `a' to an integer, and
+returns the result as a double-precision floating-point value. The
+operation is performed according to the IEC/IEEE Standard for Binary
+Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float64 float64_round_to_int( float64 a )
+{
+ flag aSign;
+ int16 aExp;
+ bits64 lastBitMask, roundBitsMask;
+ int8 roundingMode;
+ float64 z;
+
+ aExp = extractFloat64Exp( a );
+ if ( 0x433 <= aExp ) {
+ if ( ( aExp == 0x7FF ) && extractFloat64Frac( a ) ) {
+ return propagateFloat64NaN( a, a );
+ }
+ return a;
+ }
+ if ( aExp < 0x3FF ) {
+ if ( (bits64) ( a<<1 ) == 0 ) return a;
+ float_exception_flags |= float_flag_inexact;
+ aSign = extractFloat64Sign( a );
+ switch ( float_rounding_mode ) {
+ case float_round_nearest_even:
+ if ( ( aExp == 0x3FE ) && extractFloat64Frac( a ) ) {
+ return packFloat64( aSign, 0x3FF, 0 );
+ }
+ break;
+ case float_round_to_zero:
+ break;
+ case float_round_down:
+ return aSign ? LIT64( 0xBFF0000000000000 ) : 0;
+ case float_round_up:
+ return
+ aSign ? LIT64( 0x8000000000000000 ) : LIT64( 0x3FF0000000000000 );
+ }
+ return packFloat64( aSign, 0, 0 );
+ }
+ lastBitMask = 1;
+ lastBitMask <<= 0x433 - aExp;
+ roundBitsMask = lastBitMask - 1;
+ z = a;
+ roundingMode = float_rounding_mode;
+ if ( roundingMode == float_round_nearest_even ) {
+ z += lastBitMask>>1;
+ if ( ( z & roundBitsMask ) == 0 ) z &= ~ lastBitMask;
+ }
+ else if ( roundingMode != float_round_to_zero ) {
+ if ( extractFloat64Sign( z ) ^ ( roundingMode == float_round_up ) ) {
+ z += roundBitsMask;
+ }
+ }
+ z &= ~ roundBitsMask;
+ if ( z != a ) float_exception_flags |= float_flag_inexact;
+ return z;
+
+}
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of adding the absolute values of the double-precision
+floating-point values `a' and `b'. If `zSign' is 1, the sum is negated
+before being returned. `zSign' is ignored if the result is a NaN.
+The addition is performed according to the IEC/IEEE Standard for Binary
+Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+static float64 addFloat64Sigs( float64 a, float64 b, flag zSign )
+{
+ int16 aExp, bExp, zExp;
+ bits64 aSig, bSig, zSig;
+ int16 expDiff;
+
+ aSig = extractFloat64Frac( a );
+ aExp = extractFloat64Exp( a );
+ bSig = extractFloat64Frac( b );
+ bExp = extractFloat64Exp( b );
+ expDiff = aExp - bExp;
+ aSig <<= 9;
+ bSig <<= 9;
+ if ( 0 < expDiff ) {
+ if ( aExp == 0x7FF ) {
+ if ( aSig ) return propagateFloat64NaN( a, b );
+ return a;
+ }
+ if ( bExp == 0 ) {
+ --expDiff;
+ }
+ else {
+ bSig |= LIT64( 0x2000000000000000 );
+ }
+ shift64RightJamming( bSig, expDiff, &bSig );
+ zExp = aExp;
+ }
+ else if ( expDiff < 0 ) {
+ if ( bExp == 0x7FF ) {
+ if ( bSig ) return propagateFloat64NaN( a, b );
+ return packFloat64( zSign, 0x7FF, 0 );
+ }
+ if ( aExp == 0 ) {
+ ++expDiff;
+ }
+ else {
+ aSig |= LIT64( 0x2000000000000000 );
+ }
+ shift64RightJamming( aSig, - expDiff, &aSig );
+ zExp = bExp;
+ }
+ else {
+ if ( aExp == 0x7FF ) {
+ if ( aSig | bSig ) return propagateFloat64NaN( a, b );
+ return a;
+ }
+ if ( aExp == 0 ) return packFloat64( zSign, 0, ( aSig + bSig )>>9 );
+ zSig = LIT64( 0x4000000000000000 ) + aSig + bSig;
+ zExp = aExp;
+ goto roundAndPack;
+ }
+ aSig |= LIT64( 0x2000000000000000 );
+ zSig = ( aSig + bSig )<<1;
+ --zExp;
+ if ( (sbits64) zSig < 0 ) {
+ zSig = aSig + bSig;
+ ++zExp;
+ }
+ roundAndPack:
+ return roundAndPackFloat64( zSign, zExp, zSig );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of subtracting the absolute values of the double-
+precision floating-point values `a' and `b'. If `zSign' is 1, the
+difference is negated before being returned. `zSign' is ignored if the
+result is a NaN. The subtraction is performed according to the IEC/IEEE
+Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+static float64 subFloat64Sigs( float64 a, float64 b, flag zSign )
+{
+ int16 aExp, bExp, zExp;
+ bits64 aSig, bSig, zSig;
+ int16 expDiff;
+
+ aSig = extractFloat64Frac( a );
+ aExp = extractFloat64Exp( a );
+ bSig = extractFloat64Frac( b );
+ bExp = extractFloat64Exp( b );
+ expDiff = aExp - bExp;
+ aSig <<= 10;
+ bSig <<= 10;
+ if ( 0 < expDiff ) goto aExpBigger;
+ if ( expDiff < 0 ) goto bExpBigger;
+ if ( aExp == 0x7FF ) {
+ if ( aSig | bSig ) return propagateFloat64NaN( a, b );
+ float_raise( float_flag_invalid );
+ return float64_default_nan;
+ }
+ if ( aExp == 0 ) {
+ aExp = 1;
+ bExp = 1;
+ }
+ if ( bSig < aSig ) goto aBigger;
+ if ( aSig < bSig ) goto bBigger;
+ return packFloat64( float_rounding_mode == float_round_down, 0, 0 );
+ bExpBigger:
+ if ( bExp == 0x7FF ) {
+ if ( bSig ) return propagateFloat64NaN( a, b );
+ return packFloat64( zSign ^ 1, 0x7FF, 0 );
+ }
+ if ( aExp == 0 ) {
+ ++expDiff;
+ }
+ else {
+ aSig |= LIT64( 0x4000000000000000 );
+ }
+ shift64RightJamming( aSig, - expDiff, &aSig );
+ bSig |= LIT64( 0x4000000000000000 );
+ bBigger:
+ zSig = bSig - aSig;
+ zExp = bExp;
+ zSign ^= 1;
+ goto normalizeRoundAndPack;
+ aExpBigger:
+ if ( aExp == 0x7FF ) {
+ if ( aSig ) return propagateFloat64NaN( a, b );
+ return a;
+ }
+ if ( bExp == 0 ) {
+ --expDiff;
+ }
+ else {
+ bSig |= LIT64( 0x4000000000000000 );
+ }
+ shift64RightJamming( bSig, expDiff, &bSig );
+ aSig |= LIT64( 0x4000000000000000 );
+ aBigger:
+ zSig = aSig - bSig;
+ zExp = aExp;
+ normalizeRoundAndPack:
+ --zExp;
+ return normalizeRoundAndPackFloat64( zSign, zExp, zSig );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of adding the double-precision floating-point values `a'
+and `b'. The operation is performed according to the IEC/IEEE Standard for
+Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float64 float64_add( float64 a, float64 b )
+{
+ flag aSign, bSign;
+
+ aSign = extractFloat64Sign( a );
+ bSign = extractFloat64Sign( b );
+ if ( aSign == bSign ) {
+ return addFloat64Sigs( a, b, aSign );
+ }
+ else {
+ return subFloat64Sigs( a, b, aSign );
+ }
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of subtracting the double-precision floating-point values
+`a' and `b'. The operation is performed according to the IEC/IEEE Standard
+for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float64 float64_sub( float64 a, float64 b )
+{
+ flag aSign, bSign;
+
+ aSign = extractFloat64Sign( a );
+ bSign = extractFloat64Sign( b );
+ if ( aSign == bSign ) {
+ return subFloat64Sigs( a, b, aSign );
+ }
+ else {
+ return addFloat64Sigs( a, b, aSign );
+ }
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of multiplying the double-precision floating-point values
+`a' and `b'. The operation is performed according to the IEC/IEEE Standard
+for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float64 float64_mul( float64 a, float64 b )
+{
+ flag aSign, bSign, zSign;
+ int16 aExp, bExp, zExp;
+ bits64 aSig, bSig, zSig0, zSig1;
+
+ aSig = extractFloat64Frac( a );
+ aExp = extractFloat64Exp( a );
+ aSign = extractFloat64Sign( a );
+ bSig = extractFloat64Frac( b );
+ bExp = extractFloat64Exp( b );
+ bSign = extractFloat64Sign( b );
+ zSign = aSign ^ bSign;
+ if ( aExp == 0x7FF ) {
+ if ( aSig || ( ( bExp == 0x7FF ) && bSig ) ) {
+ return propagateFloat64NaN( a, b );
+ }
+ if ( ( bExp | bSig ) == 0 ) {
+ float_raise( float_flag_invalid );
+ return float64_default_nan;
+ }
+ return packFloat64( zSign, 0x7FF, 0 );
+ }
+ if ( bExp == 0x7FF ) {
+ if ( bSig ) return propagateFloat64NaN( a, b );
+ if ( ( aExp | aSig ) == 0 ) {
+ float_raise( float_flag_invalid );
+ return float64_default_nan;
+ }
+ return packFloat64( zSign, 0x7FF, 0 );
+ }
+ if ( aExp == 0 ) {
+ if ( aSig == 0 ) return packFloat64( zSign, 0, 0 );
+ normalizeFloat64Subnormal( aSig, &aExp, &aSig );
+ }
+ if ( bExp == 0 ) {
+ if ( bSig == 0 ) return packFloat64( zSign, 0, 0 );
+ normalizeFloat64Subnormal( bSig, &bExp, &bSig );
+ }
+ zExp = aExp + bExp - 0x3FF;
+ aSig = ( aSig | LIT64( 0x0010000000000000 ) )<<10;
+ bSig = ( bSig | LIT64( 0x0010000000000000 ) )<<11;
+ mul64To128( aSig, bSig, &zSig0, &zSig1 );
+ zSig0 |= ( zSig1 != 0 );
+ if ( 0 <= (sbits64) ( zSig0<<1 ) ) {
+ zSig0 <<= 1;
+ --zExp;
+ }
+ return roundAndPackFloat64( zSign, zExp, zSig0 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of dividing the double-precision floating-point value `a'
+by the corresponding value `b'. The operation is performed according to
+the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float64 float64_div( float64 a, float64 b )
+{
+ flag aSign, bSign, zSign;
+ int16 aExp, bExp, zExp;
+ bits64 aSig, bSig, zSig;
+ bits64 rem0, rem1;
+ bits64 term0, term1;
+
+ aSig = extractFloat64Frac( a );
+ aExp = extractFloat64Exp( a );
+ aSign = extractFloat64Sign( a );
+ bSig = extractFloat64Frac( b );
+ bExp = extractFloat64Exp( b );
+ bSign = extractFloat64Sign( b );
+ zSign = aSign ^ bSign;
+ if ( aExp == 0x7FF ) {
+ if ( aSig ) return propagateFloat64NaN( a, b );
+ if ( bExp == 0x7FF ) {
+ if ( bSig ) return propagateFloat64NaN( a, b );
+ float_raise( float_flag_invalid );
+ return float64_default_nan;
+ }
+ return packFloat64( zSign, 0x7FF, 0 );
+ }
+ if ( bExp == 0x7FF ) {
+ if ( bSig ) return propagateFloat64NaN( a, b );
+ return packFloat64( zSign, 0, 0 );
+ }
+ if ( bExp == 0 ) {
+ if ( bSig == 0 ) {
+ if ( ( aExp | aSig ) == 0 ) {
+ float_raise( float_flag_invalid );
+ return float64_default_nan;
+ }
+ float_raise( float_flag_divbyzero );
+ return packFloat64( zSign, 0x7FF, 0 );
+ }
+ normalizeFloat64Subnormal( bSig, &bExp, &bSig );
+ }
+ if ( aExp == 0 ) {
+ if ( aSig == 0 ) return packFloat64( zSign, 0, 0 );
+ normalizeFloat64Subnormal( aSig, &aExp, &aSig );
+ }
+ zExp = aExp - bExp + 0x3FD;
+ aSig = ( aSig | LIT64( 0x0010000000000000 ) )<<10;
+ bSig = ( bSig | LIT64( 0x0010000000000000 ) )<<11;
+ if ( bSig <= ( aSig + aSig ) ) {
+ aSig >>= 1;
+ ++zExp;
+ }
+ zSig = estimateDiv128To64( aSig, 0, bSig );
+ if ( ( zSig & 0x1FF ) <= 2 ) {
+ mul64To128( bSig, zSig, &term0, &term1 );
+ sub128( aSig, 0, term0, term1, &rem0, &rem1 );
+ while ( (sbits64) rem0 < 0 ) {
+ --zSig;
+ add128( rem0, rem1, 0, bSig, &rem0, &rem1 );
+ }
+ zSig |= ( rem1 != 0 );
+ }
+ return roundAndPackFloat64( zSign, zExp, zSig );
+
+}
+
+#ifndef SOFTFLOAT_FOR_GCC
+/*
+-------------------------------------------------------------------------------
+Returns the remainder of the double-precision floating-point value `a'
+with respect to the corresponding value `b'. The operation is performed
+according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float64 float64_rem( float64 a, float64 b )
+{
+ flag aSign, bSign, zSign;
+ int16 aExp, bExp, expDiff;
+ bits64 aSig, bSig;
+ bits64 q, alternateASig;
+ sbits64 sigMean;
+
+ aSig = extractFloat64Frac( a );
+ aExp = extractFloat64Exp( a );
+ aSign = extractFloat64Sign( a );
+ bSig = extractFloat64Frac( b );
+ bExp = extractFloat64Exp( b );
+ bSign = extractFloat64Sign( b );
+ if ( aExp == 0x7FF ) {
+ if ( aSig || ( ( bExp == 0x7FF ) && bSig ) ) {
+ return propagateFloat64NaN( a, b );
+ }
+ float_raise( float_flag_invalid );
+ return float64_default_nan;
+ }
+ if ( bExp == 0x7FF ) {
+ if ( bSig ) return propagateFloat64NaN( a, b );
+ return a;
+ }
+ if ( bExp == 0 ) {
+ if ( bSig == 0 ) {
+ float_raise( float_flag_invalid );
+ return float64_default_nan;
+ }
+ normalizeFloat64Subnormal( bSig, &bExp, &bSig );
+ }
+ if ( aExp == 0 ) {
+ if ( aSig == 0 ) return a;
+ normalizeFloat64Subnormal( aSig, &aExp, &aSig );
+ }
+ expDiff = aExp - bExp;
+ aSig = ( aSig | LIT64( 0x0010000000000000 ) )<<11;
+ bSig = ( bSig | LIT64( 0x0010000000000000 ) )<<11;
+ if ( expDiff < 0 ) {
+ if ( expDiff < -1 ) return a;
+ aSig >>= 1;
+ }
+ q = ( bSig <= aSig );
+ if ( q ) aSig -= bSig;
+ expDiff -= 64;
+ while ( 0 < expDiff ) {
+ q = estimateDiv128To64( aSig, 0, bSig );
+ q = ( 2 < q ) ? q - 2 : 0;
+ aSig = - ( ( bSig>>2 ) * q );
+ expDiff -= 62;
+ }
+ expDiff += 64;
+ if ( 0 < expDiff ) {
+ q = estimateDiv128To64( aSig, 0, bSig );
+ q = ( 2 < q ) ? q - 2 : 0;
+ q >>= 64 - expDiff;
+ bSig >>= 2;
+ aSig = ( ( aSig>>1 )<<( expDiff - 1 ) ) - bSig * q;
+ }
+ else {
+ aSig >>= 2;
+ bSig >>= 2;
+ }
+ do {
+ alternateASig = aSig;
+ ++q;
+ aSig -= bSig;
+ } while ( 0 <= (sbits64) aSig );
+ sigMean = aSig + alternateASig;
+ if ( ( sigMean < 0 ) || ( ( sigMean == 0 ) && ( q & 1 ) ) ) {
+ aSig = alternateASig;
+ }
+ zSign = ( (sbits64) aSig < 0 );
+ if ( zSign ) aSig = - aSig;
+ return normalizeRoundAndPackFloat64( aSign ^ zSign, bExp, aSig );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the square root of the double-precision floating-point value `a'.
+The operation is performed according to the IEC/IEEE Standard for Binary
+Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float64 float64_sqrt( float64 a )
+{
+ flag aSign;
+ int16 aExp, zExp;
+ bits64 aSig, zSig, doubleZSig;
+ bits64 rem0, rem1, term0, term1;
+
+ aSig = extractFloat64Frac( a );
+ aExp = extractFloat64Exp( a );
+ aSign = extractFloat64Sign( a );
+ if ( aExp == 0x7FF ) {
+ if ( aSig ) return propagateFloat64NaN( a, a );
+ if ( ! aSign ) return a;
+ float_raise( float_flag_invalid );
+ return float64_default_nan;
+ }
+ if ( aSign ) {
+ if ( ( aExp | aSig ) == 0 ) return a;
+ float_raise( float_flag_invalid );
+ return float64_default_nan;
+ }
+ if ( aExp == 0 ) {
+ if ( aSig == 0 ) return 0;
+ normalizeFloat64Subnormal( aSig, &aExp, &aSig );
+ }
+ zExp = ( ( aExp - 0x3FF )>>1 ) + 0x3FE;
+ aSig |= LIT64( 0x0010000000000000 );
+ zSig = estimateSqrt32( aExp, aSig>>21 );
+ aSig <<= 9 - ( aExp & 1 );
+ zSig = estimateDiv128To64( aSig, 0, zSig<<32 ) + ( zSig<<30 );
+ if ( ( zSig & 0x1FF ) <= 5 ) {
+ doubleZSig = zSig<<1;
+ mul64To128( zSig, zSig, &term0, &term1 );
+ sub128( aSig, 0, term0, term1, &rem0, &rem1 );
+ while ( (sbits64) rem0 < 0 ) {
+ --zSig;
+ doubleZSig -= 2;
+ add128( rem0, rem1, zSig>>63, doubleZSig | 1, &rem0, &rem1 );
+ }
+ zSig |= ( ( rem0 | rem1 ) != 0 );
+ }
+ return roundAndPackFloat64( 0, zExp, zSig );
+
+}
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the double-precision floating-point value `a' is equal to the
+corresponding value `b', and 0 otherwise. The comparison is performed
+according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float64_eq( float64 a, float64 b )
+{
+
+ if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
+ || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
+ ) {
+ if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) {
+ float_raise( float_flag_invalid );
+ }
+ return 0;
+ }
+ return ( a == b ) ||
+ ( (bits64) ( ( FLOAT64_DEMANGLE(a) | FLOAT64_DEMANGLE(b) )<<1 ) == 0 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the double-precision floating-point value `a' is less than or
+equal to the corresponding value `b', and 0 otherwise. The comparison is
+performed according to the IEC/IEEE Standard for Binary Floating-Point
+Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float64_le( float64 a, float64 b )
+{
+ flag aSign, bSign;
+
+ if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
+ || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
+ ) {
+ float_raise( float_flag_invalid );
+ return 0;
+ }
+ aSign = extractFloat64Sign( a );
+ bSign = extractFloat64Sign( b );
+ if ( aSign != bSign )
+ return aSign ||
+ ( (bits64) ( ( FLOAT64_DEMANGLE(a) | FLOAT64_DEMANGLE(b) )<<1 ) ==
+ 0 );
+ return ( a == b ) ||
+ ( aSign ^ ( FLOAT64_DEMANGLE(a) < FLOAT64_DEMANGLE(b) ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the double-precision floating-point value `a' is less than
+the corresponding value `b', and 0 otherwise. The comparison is performed
+according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float64_lt( float64 a, float64 b )
+{
+ flag aSign, bSign;
+
+ if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
+ || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
+ ) {
+ float_raise( float_flag_invalid );
+ return 0;
+ }
+ aSign = extractFloat64Sign( a );
+ bSign = extractFloat64Sign( b );
+ if ( aSign != bSign )
+ return aSign &&
+ ( (bits64) ( ( FLOAT64_DEMANGLE(a) | FLOAT64_DEMANGLE(b) )<<1 ) !=
+ 0 );
+ return ( a != b ) &&
+ ( aSign ^ ( FLOAT64_DEMANGLE(a) < FLOAT64_DEMANGLE(b) ) );
+
+}
+
+#ifndef SOFTFLOAT_FOR_GCC
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the double-precision floating-point value `a' is equal to the
+corresponding value `b', and 0 otherwise. The invalid exception is raised
+if either operand is a NaN. Otherwise, the comparison is performed
+according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float64_eq_signaling( float64 a, float64 b )
+{
+
+ if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
+ || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
+ ) {
+ float_raise( float_flag_invalid );
+ return 0;
+ }
+ return ( a == b ) || ( (bits64) ( ( a | b )<<1 ) == 0 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the double-precision floating-point value `a' is less than or
+equal to the corresponding value `b', and 0 otherwise. Quiet NaNs do not
+cause an exception. Otherwise, the comparison is performed according to the
+IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float64_le_quiet( float64 a, float64 b )
+{
+ flag aSign, bSign;
+
+ if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
+ || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
+ ) {
+ if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) {
+ float_raise( float_flag_invalid );
+ }
+ return 0;
+ }
+ aSign = extractFloat64Sign( a );
+ bSign = extractFloat64Sign( b );
+ if ( aSign != bSign ) return aSign || ( (bits64) ( ( a | b )<<1 ) == 0 );
+ return ( a == b ) || ( aSign ^ ( a < b ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the double-precision floating-point value `a' is less than
+the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an
+exception. Otherwise, the comparison is performed according to the IEC/IEEE
+Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float64_lt_quiet( float64 a, float64 b )
+{
+ flag aSign, bSign;
+
+ if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
+ || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
+ ) {
+ if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) {
+ float_raise( float_flag_invalid );
+ }
+ return 0;
+ }
+ aSign = extractFloat64Sign( a );
+ bSign = extractFloat64Sign( b );
+ if ( aSign != bSign ) return aSign && ( (bits64) ( ( a | b )<<1 ) != 0 );
+ return ( a != b ) && ( aSign ^ ( a < b ) );
+
+}
+#endif
+
+#ifdef FLOATX80
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the extended double-precision floating-
+point value `a' to the 32-bit two's complement integer format. The
+conversion is performed according to the IEC/IEEE Standard for Binary
+Floating-Point Arithmetic---which means in particular that the conversion
+is rounded according to the current rounding mode. If `a' is a NaN, the
+largest positive integer is returned. Otherwise, if the conversion
+overflows, the largest integer with the same sign as `a' is returned.
+-------------------------------------------------------------------------------
+*/
+int32 floatx80_to_int32( floatx80 a )
+{
+ flag aSign;
+ int32 aExp, shiftCount;
+ bits64 aSig;
+
+ aSig = extractFloatx80Frac( a );
+ aExp = extractFloatx80Exp( a );
+ aSign = extractFloatx80Sign( a );
+ if ( ( aExp == 0x7FFF ) && (bits64) ( aSig<<1 ) ) aSign = 0;
+ shiftCount = 0x4037 - aExp;
+ if ( shiftCount <= 0 ) shiftCount = 1;
+ shift64RightJamming( aSig, shiftCount, &aSig );
+ return roundAndPackInt32( aSign, aSig );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the extended double-precision floating-
+point value `a' to the 32-bit two's complement integer format. The
+conversion is performed according to the IEC/IEEE Standard for Binary
+Floating-Point Arithmetic, except that the conversion is always rounded
+toward zero. If `a' is a NaN, the largest positive integer is returned.
+Otherwise, if the conversion overflows, the largest integer with the same
+sign as `a' is returned.
+-------------------------------------------------------------------------------
+*/
+int32 floatx80_to_int32_round_to_zero( floatx80 a )
+{
+ flag aSign;
+ int32 aExp, shiftCount;
+ bits64 aSig, savedASig;
+ int32 z;
+
+ aSig = extractFloatx80Frac( a );
+ aExp = extractFloatx80Exp( a );
+ aSign = extractFloatx80Sign( a );
+ if ( 0x401E < aExp ) {
+ if ( ( aExp == 0x7FFF ) && (bits64) ( aSig<<1 ) ) aSign = 0;
+ goto invalid;
+ }
+ else if ( aExp < 0x3FFF ) {
+ if ( aExp || aSig ) float_exception_flags |= float_flag_inexact;
+ return 0;
+ }
+ shiftCount = 0x403E - aExp;
+ savedASig = aSig;
+ aSig >>= shiftCount;
+ z = aSig;
+ if ( aSign ) z = - z;
+ if ( ( z < 0 ) ^ aSign ) {
+ invalid:
+ float_raise( float_flag_invalid );
+ return aSign ? (sbits32) 0x80000000 : 0x7FFFFFFF;
+ }
+ if ( ( aSig<<shiftCount ) != savedASig ) {
+ float_exception_flags |= float_flag_inexact;
+ }
+ return z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the extended double-precision floating-
+point value `a' to the 64-bit two's complement integer format. The
+conversion is performed according to the IEC/IEEE Standard for Binary
+Floating-Point Arithmetic---which means in particular that the conversion
+is rounded according to the current rounding mode. If `a' is a NaN,
+the largest positive integer is returned. Otherwise, if the conversion
+overflows, the largest integer with the same sign as `a' is returned.
+-------------------------------------------------------------------------------
+*/
+int64 floatx80_to_int64( floatx80 a )
+{
+ flag aSign;
+ int32 aExp, shiftCount;
+ bits64 aSig, aSigExtra;
+
+ aSig = extractFloatx80Frac( a );
+ aExp = extractFloatx80Exp( a );
+ aSign = extractFloatx80Sign( a );
+ shiftCount = 0x403E - aExp;
+ if ( shiftCount <= 0 ) {
+ if ( shiftCount ) {
+ float_raise( float_flag_invalid );
+ if ( ! aSign
+ || ( ( aExp == 0x7FFF )
+ && ( aSig != LIT64( 0x8000000000000000 ) ) )
+ ) {
+ return LIT64( 0x7FFFFFFFFFFFFFFF );
+ }
+ return (sbits64) LIT64( 0x8000000000000000 );
+ }
+ aSigExtra = 0;
+ }
+ else {
+ shift64ExtraRightJamming( aSig, 0, shiftCount, &aSig, &aSigExtra );
+ }
+ return roundAndPackInt64( aSign, aSig, aSigExtra );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the extended double-precision floating-
+point value `a' to the 64-bit two's complement integer format. The
+conversion is performed according to the IEC/IEEE Standard for Binary
+Floating-Point Arithmetic, except that the conversion is always rounded
+toward zero. If `a' is a NaN, the largest positive integer is returned.
+Otherwise, if the conversion overflows, the largest integer with the same
+sign as `a' is returned.
+-------------------------------------------------------------------------------
+*/
+int64 floatx80_to_int64_round_to_zero( floatx80 a )
+{
+ flag aSign;
+ int32 aExp, shiftCount;
+ bits64 aSig;
+ int64 z;
+
+ aSig = extractFloatx80Frac( a );
+ aExp = extractFloatx80Exp( a );
+ aSign = extractFloatx80Sign( a );
+ shiftCount = aExp - 0x403E;
+ if ( 0 <= shiftCount ) {
+ aSig &= LIT64( 0x7FFFFFFFFFFFFFFF );
+ if ( ( a.high != 0xC03E ) || aSig ) {
+ float_raise( float_flag_invalid );
+ if ( ! aSign || ( ( aExp == 0x7FFF ) && aSig ) ) {
+ return LIT64( 0x7FFFFFFFFFFFFFFF );
+ }
+ }
+ return (sbits64) LIT64( 0x8000000000000000 );
+ }
+ else if ( aExp < 0x3FFF ) {
+ if ( aExp | aSig ) float_exception_flags |= float_flag_inexact;
+ return 0;
+ }
+ z = aSig>>( - shiftCount );
+ if ( (bits64) ( aSig<<( shiftCount & 63 ) ) ) {
+ float_exception_flags |= float_flag_inexact;
+ }
+ if ( aSign ) z = - z;
+ return z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the extended double-precision floating-
+point value `a' to the single-precision floating-point format. The
+conversion is performed according to the IEC/IEEE Standard for Binary
+Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float32 floatx80_to_float32( floatx80 a )
+{
+ flag aSign;
+ int32 aExp;
+ bits64 aSig;
+
+ aSig = extractFloatx80Frac( a );
+ aExp = extractFloatx80Exp( a );
+ aSign = extractFloatx80Sign( a );
+ if ( aExp == 0x7FFF ) {
+ if ( (bits64) ( aSig<<1 ) ) {
+ return commonNaNToFloat32( floatx80ToCommonNaN( a ) );
+ }
+ return packFloat32( aSign, 0xFF, 0 );
+ }
+ shift64RightJamming( aSig, 33, &aSig );
+ if ( aExp || aSig ) aExp -= 0x3F81;
+ return roundAndPackFloat32( aSign, aExp, aSig );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the extended double-precision floating-
+point value `a' to the double-precision floating-point format. The
+conversion is performed according to the IEC/IEEE Standard for Binary
+Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float64 floatx80_to_float64( floatx80 a )
+{
+ flag aSign;
+ int32 aExp;
+ bits64 aSig, zSig;
+
+ aSig = extractFloatx80Frac( a );
+ aExp = extractFloatx80Exp( a );
+ aSign = extractFloatx80Sign( a );
+ if ( aExp == 0x7FFF ) {
+ if ( (bits64) ( aSig<<1 ) ) {
+ return commonNaNToFloat64( floatx80ToCommonNaN( a ) );
+ }
+ return packFloat64( aSign, 0x7FF, 0 );
+ }
+ shift64RightJamming( aSig, 1, &zSig );
+ if ( aExp || aSig ) aExp -= 0x3C01;
+ return roundAndPackFloat64( aSign, aExp, zSig );
+
+}
+
+#ifdef FLOAT128
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the extended double-precision floating-
+point value `a' to the quadruple-precision floating-point format. The
+conversion is performed according to the IEC/IEEE Standard for Binary
+Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float128 floatx80_to_float128( floatx80 a )
+{
+ flag aSign;
+ int16 aExp;
+ bits64 aSig, zSig0, zSig1;
+
+ aSig = extractFloatx80Frac( a );
+ aExp = extractFloatx80Exp( a );
+ aSign = extractFloatx80Sign( a );
+ if ( ( aExp == 0x7FFF ) && (bits64) ( aSig<<1 ) ) {
+ return commonNaNToFloat128( floatx80ToCommonNaN( a ) );
+ }
+ shift128Right( aSig<<1, 0, 16, &zSig0, &zSig1 );
+ return packFloat128( aSign, aExp, zSig0, zSig1 );
+
+}
+
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Rounds the extended double-precision floating-point value `a' to an integer,
+and returns the result as an extended quadruple-precision floating-point
+value. The operation is performed according to the IEC/IEEE Standard for
+Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+floatx80 floatx80_round_to_int( floatx80 a )
+{
+ flag aSign;
+ int32 aExp;
+ bits64 lastBitMask, roundBitsMask;
+ int8 roundingMode;
+ floatx80 z;
+
+ aExp = extractFloatx80Exp( a );
+ if ( 0x403E <= aExp ) {
+ if ( ( aExp == 0x7FFF ) && (bits64) ( extractFloatx80Frac( a )<<1 ) ) {
+ return propagateFloatx80NaN( a, a );
+ }
+ return a;
+ }
+ if ( aExp < 0x3FFF ) {
+ if ( ( aExp == 0 )
+ && ( (bits64) ( extractFloatx80Frac( a )<<1 ) == 0 ) ) {
+ return a;
+ }
+ float_exception_flags |= float_flag_inexact;
+ aSign = extractFloatx80Sign( a );
+ switch ( float_rounding_mode ) {
+ case float_round_nearest_even:
+ if ( ( aExp == 0x3FFE ) && (bits64) ( extractFloatx80Frac( a )<<1 )
+ ) {
+ return
+ packFloatx80( aSign, 0x3FFF, LIT64( 0x8000000000000000 ) );
+ }
+ break;
+ case float_round_to_zero:
+ break;
+ case float_round_down:
+ return
+ aSign ?
+ packFloatx80( 1, 0x3FFF, LIT64( 0x8000000000000000 ) )
+ : packFloatx80( 0, 0, 0 );
+ case float_round_up:
+ return
+ aSign ? packFloatx80( 1, 0, 0 )
+ : packFloatx80( 0, 0x3FFF, LIT64( 0x8000000000000000 ) );
+ }
+ return packFloatx80( aSign, 0, 0 );
+ }
+ lastBitMask = 1;
+ lastBitMask <<= 0x403E - aExp;
+ roundBitsMask = lastBitMask - 1;
+ z = a;
+ roundingMode = float_rounding_mode;
+ if ( roundingMode == float_round_nearest_even ) {
+ z.low += lastBitMask>>1;
+ if ( ( z.low & roundBitsMask ) == 0 ) z.low &= ~ lastBitMask;
+ }
+ else if ( roundingMode != float_round_to_zero ) {
+ if ( extractFloatx80Sign( z ) ^ ( roundingMode == float_round_up ) ) {
+ z.low += roundBitsMask;
+ }
+ }
+ z.low &= ~ roundBitsMask;
+ if ( z.low == 0 ) {
+ ++z.high;
+ z.low = LIT64( 0x8000000000000000 );
+ }
+ if ( z.low != a.low ) float_exception_flags |= float_flag_inexact;
+ return z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of adding the absolute values of the extended double-
+precision floating-point values `a' and `b'. If `zSign' is 1, the sum is
+negated before being returned. `zSign' is ignored if the result is a NaN.
+The addition is performed according to the IEC/IEEE Standard for Binary
+Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+static floatx80 addFloatx80Sigs( floatx80 a, floatx80 b, flag zSign )
+{
+ int32 aExp, bExp, zExp;
+ bits64 aSig, bSig, zSig0, zSig1;
+ int32 expDiff;
+
+ aSig = extractFloatx80Frac( a );
+ aExp = extractFloatx80Exp( a );
+ bSig = extractFloatx80Frac( b );
+ bExp = extractFloatx80Exp( b );
+ expDiff = aExp - bExp;
+ if ( 0 < expDiff ) {
+ if ( aExp == 0x7FFF ) {
+ if ( (bits64) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b );
+ return a;
+ }
+ if ( bExp == 0 ) --expDiff;
+ shift64ExtraRightJamming( bSig, 0, expDiff, &bSig, &zSig1 );
+ zExp = aExp;
+ }
+ else if ( expDiff < 0 ) {
+ if ( bExp == 0x7FFF ) {
+ if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b );
+ return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
+ }
+ if ( aExp == 0 ) ++expDiff;
+ shift64ExtraRightJamming( aSig, 0, - expDiff, &aSig, &zSig1 );
+ zExp = bExp;
+ }
+ else {
+ if ( aExp == 0x7FFF ) {
+ if ( (bits64) ( ( aSig | bSig )<<1 ) ) {
+ return propagateFloatx80NaN( a, b );
+ }
+ return a;
+ }
+ zSig1 = 0;
+ zSig0 = aSig + bSig;
+ if ( aExp == 0 ) {
+ normalizeFloatx80Subnormal( zSig0, &zExp, &zSig0 );
+ goto roundAndPack;
+ }
+ zExp = aExp;
+ goto shiftRight1;
+ }
+ zSig0 = aSig + bSig;
+ if ( (sbits64) zSig0 < 0 ) goto roundAndPack;
+ shiftRight1:
+ shift64ExtraRightJamming( zSig0, zSig1, 1, &zSig0, &zSig1 );
+ zSig0 |= LIT64( 0x8000000000000000 );
+ ++zExp;
+ roundAndPack:
+ return
+ roundAndPackFloatx80(
+ floatx80_rounding_precision, zSign, zExp, zSig0, zSig1 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of subtracting the absolute values of the extended
+double-precision floating-point values `a' and `b'. If `zSign' is 1, the
+difference is negated before being returned. `zSign' is ignored if the
+result is a NaN. The subtraction is performed according to the IEC/IEEE
+Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+static floatx80 subFloatx80Sigs( floatx80 a, floatx80 b, flag zSign )
+{
+ int32 aExp, bExp, zExp;
+ bits64 aSig, bSig, zSig0, zSig1;
+ int32 expDiff;
+ floatx80 z;
+
+ aSig = extractFloatx80Frac( a );
+ aExp = extractFloatx80Exp( a );
+ bSig = extractFloatx80Frac( b );
+ bExp = extractFloatx80Exp( b );
+ expDiff = aExp - bExp;
+ if ( 0 < expDiff ) goto aExpBigger;
+ if ( expDiff < 0 ) goto bExpBigger;
+ if ( aExp == 0x7FFF ) {
+ if ( (bits64) ( ( aSig | bSig )<<1 ) ) {
+ return propagateFloatx80NaN( a, b );
+ }
+ float_raise( float_flag_invalid );
+ z.low = floatx80_default_nan_low;
+ z.high = floatx80_default_nan_high;
+ return z;
+ }
+ if ( aExp == 0 ) {
+ aExp = 1;
+ bExp = 1;
+ }
+ zSig1 = 0;
+ if ( bSig < aSig ) goto aBigger;
+ if ( aSig < bSig ) goto bBigger;
+ return packFloatx80( float_rounding_mode == float_round_down, 0, 0 );
+ bExpBigger:
+ if ( bExp == 0x7FFF ) {
+ if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b );
+ return packFloatx80( zSign ^ 1, 0x7FFF, LIT64( 0x8000000000000000 ) );
+ }
+ if ( aExp == 0 ) ++expDiff;
+ shift128RightJamming( aSig, 0, - expDiff, &aSig, &zSig1 );
+ bBigger:
+ sub128( bSig, 0, aSig, zSig1, &zSig0, &zSig1 );
+ zExp = bExp;
+ zSign ^= 1;
+ goto normalizeRoundAndPack;
+ aExpBigger:
+ if ( aExp == 0x7FFF ) {
+ if ( (bits64) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b );
+ return a;
+ }
+ if ( bExp == 0 ) --expDiff;
+ shift128RightJamming( bSig, 0, expDiff, &bSig, &zSig1 );
+ aBigger:
+ sub128( aSig, 0, bSig, zSig1, &zSig0, &zSig1 );
+ zExp = aExp;
+ normalizeRoundAndPack:
+ return
+ normalizeRoundAndPackFloatx80(
+ floatx80_rounding_precision, zSign, zExp, zSig0, zSig1 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of adding the extended double-precision floating-point
+values `a' and `b'. The operation is performed according to the IEC/IEEE
+Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+floatx80 floatx80_add( floatx80 a, floatx80 b )
+{
+ flag aSign, bSign;
+
+ aSign = extractFloatx80Sign( a );
+ bSign = extractFloatx80Sign( b );
+ if ( aSign == bSign ) {
+ return addFloatx80Sigs( a, b, aSign );
+ }
+ else {
+ return subFloatx80Sigs( a, b, aSign );
+ }
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of subtracting the extended double-precision floating-
+point values `a' and `b'. The operation is performed according to the
+IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+floatx80 floatx80_sub( floatx80 a, floatx80 b )
+{
+ flag aSign, bSign;
+
+ aSign = extractFloatx80Sign( a );
+ bSign = extractFloatx80Sign( b );
+ if ( aSign == bSign ) {
+ return subFloatx80Sigs( a, b, aSign );
+ }
+ else {
+ return addFloatx80Sigs( a, b, aSign );
+ }
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of multiplying the extended double-precision floating-
+point values `a' and `b'. The operation is performed according to the
+IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+floatx80 floatx80_mul( floatx80 a, floatx80 b )
+{
+ flag aSign, bSign, zSign;
+ int32 aExp, bExp, zExp;
+ bits64 aSig, bSig, zSig0, zSig1;
+ floatx80 z;
+
+ aSig = extractFloatx80Frac( a );
+ aExp = extractFloatx80Exp( a );
+ aSign = extractFloatx80Sign( a );
+ bSig = extractFloatx80Frac( b );
+ bExp = extractFloatx80Exp( b );
+ bSign = extractFloatx80Sign( b );
+ zSign = aSign ^ bSign;
+ if ( aExp == 0x7FFF ) {
+ if ( (bits64) ( aSig<<1 )
+ || ( ( bExp == 0x7FFF ) && (bits64) ( bSig<<1 ) ) ) {
+ return propagateFloatx80NaN( a, b );
+ }
+ if ( ( bExp | bSig ) == 0 ) goto invalid;
+ return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
+ }
+ if ( bExp == 0x7FFF ) {
+ if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b );
+ if ( ( aExp | aSig ) == 0 ) {
+ invalid:
+ float_raise( float_flag_invalid );
+ z.low = floatx80_default_nan_low;
+ z.high = floatx80_default_nan_high;
+ return z;
+ }
+ return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
+ }
+ if ( aExp == 0 ) {
+ if ( aSig == 0 ) return packFloatx80( zSign, 0, 0 );
+ normalizeFloatx80Subnormal( aSig, &aExp, &aSig );
+ }
+ if ( bExp == 0 ) {
+ if ( bSig == 0 ) return packFloatx80( zSign, 0, 0 );
+ normalizeFloatx80Subnormal( bSig, &bExp, &bSig );
+ }
+ zExp = aExp + bExp - 0x3FFE;
+ mul64To128( aSig, bSig, &zSig0, &zSig1 );
+ if ( 0 < (sbits64) zSig0 ) {
+ shortShift128Left( zSig0, zSig1, 1, &zSig0, &zSig1 );
+ --zExp;
+ }
+ return
+ roundAndPackFloatx80(
+ floatx80_rounding_precision, zSign, zExp, zSig0, zSig1 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of dividing the extended double-precision floating-point
+value `a' by the corresponding value `b'. The operation is performed
+according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+floatx80 floatx80_div( floatx80 a, floatx80 b )
+{
+ flag aSign, bSign, zSign;
+ int32 aExp, bExp, zExp;
+ bits64 aSig, bSig, zSig0, zSig1;
+ bits64 rem0, rem1, rem2, term0, term1, term2;
+ floatx80 z;
+
+ aSig = extractFloatx80Frac( a );
+ aExp = extractFloatx80Exp( a );
+ aSign = extractFloatx80Sign( a );
+ bSig = extractFloatx80Frac( b );
+ bExp = extractFloatx80Exp( b );
+ bSign = extractFloatx80Sign( b );
+ zSign = aSign ^ bSign;
+ if ( aExp == 0x7FFF ) {
+ if ( (bits64) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b );
+ if ( bExp == 0x7FFF ) {
+ if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b );
+ goto invalid;
+ }
+ return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
+ }
+ if ( bExp == 0x7FFF ) {
+ if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b );
+ return packFloatx80( zSign, 0, 0 );
+ }
+ if ( bExp == 0 ) {
+ if ( bSig == 0 ) {
+ if ( ( aExp | aSig ) == 0 ) {
+ invalid:
+ float_raise( float_flag_invalid );
+ z.low = floatx80_default_nan_low;
+ z.high = floatx80_default_nan_high;
+ return z;
+ }
+ float_raise( float_flag_divbyzero );
+ return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
+ }
+ normalizeFloatx80Subnormal( bSig, &bExp, &bSig );
+ }
+ if ( aExp == 0 ) {
+ if ( aSig == 0 ) return packFloatx80( zSign, 0, 0 );
+ normalizeFloatx80Subnormal( aSig, &aExp, &aSig );
+ }
+ zExp = aExp - bExp + 0x3FFE;
+ rem1 = 0;
+ if ( bSig <= aSig ) {
+ shift128Right( aSig, 0, 1, &aSig, &rem1 );
+ ++zExp;
+ }
+ zSig0 = estimateDiv128To64( aSig, rem1, bSig );
+ mul64To128( bSig, zSig0, &term0, &term1 );
+ sub128( aSig, rem1, term0, term1, &rem0, &rem1 );
+ while ( (sbits64) rem0 < 0 ) {
+ --zSig0;
+ add128( rem0, rem1, 0, bSig, &rem0, &rem1 );
+ }
+ zSig1 = estimateDiv128To64( rem1, 0, bSig );
+ if ( (bits64) ( zSig1<<1 ) <= 8 ) {
+ mul64To128( bSig, zSig1, &term1, &term2 );
+ sub128( rem1, 0, term1, term2, &rem1, &rem2 );
+ while ( (sbits64) rem1 < 0 ) {
+ --zSig1;
+ add128( rem1, rem2, 0, bSig, &rem1, &rem2 );
+ }
+ zSig1 |= ( ( rem1 | rem2 ) != 0 );
+ }
+ return
+ roundAndPackFloatx80(
+ floatx80_rounding_precision, zSign, zExp, zSig0, zSig1 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the remainder of the extended double-precision floating-point value
+`a' with respect to the corresponding value `b'. The operation is performed
+according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+floatx80 floatx80_rem( floatx80 a, floatx80 b )
+{
+ flag aSign, bSign, zSign;
+ int32 aExp, bExp, expDiff;
+ bits64 aSig0, aSig1, bSig;
+ bits64 q, term0, term1, alternateASig0, alternateASig1;
+ floatx80 z;
+
+ aSig0 = extractFloatx80Frac( a );
+ aExp = extractFloatx80Exp( a );
+ aSign = extractFloatx80Sign( a );
+ bSig = extractFloatx80Frac( b );
+ bExp = extractFloatx80Exp( b );
+ bSign = extractFloatx80Sign( b );
+ if ( aExp == 0x7FFF ) {
+ if ( (bits64) ( aSig0<<1 )
+ || ( ( bExp == 0x7FFF ) && (bits64) ( bSig<<1 ) ) ) {
+ return propagateFloatx80NaN( a, b );
+ }
+ goto invalid;
+ }
+ if ( bExp == 0x7FFF ) {
+ if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b );
+ return a;
+ }
+ if ( bExp == 0 ) {
+ if ( bSig == 0 ) {
+ invalid:
+ float_raise( float_flag_invalid );
+ z.low = floatx80_default_nan_low;
+ z.high = floatx80_default_nan_high;
+ return z;
+ }
+ normalizeFloatx80Subnormal( bSig, &bExp, &bSig );
+ }
+ if ( aExp == 0 ) {
+ if ( (bits64) ( aSig0<<1 ) == 0 ) return a;
+ normalizeFloatx80Subnormal( aSig0, &aExp, &aSig0 );
+ }
+ bSig |= LIT64( 0x8000000000000000 );
+ zSign = aSign;
+ expDiff = aExp - bExp;
+ aSig1 = 0;
+ if ( expDiff < 0 ) {
+ if ( expDiff < -1 ) return a;
+ shift128Right( aSig0, 0, 1, &aSig0, &aSig1 );
+ expDiff = 0;
+ }
+ q = ( bSig <= aSig0 );
+ if ( q ) aSig0 -= bSig;
+ expDiff -= 64;
+ while ( 0 < expDiff ) {
+ q = estimateDiv128To64( aSig0, aSig1, bSig );
+ q = ( 2 < q ) ? q - 2 : 0;
+ mul64To128( bSig, q, &term0, &term1 );
+ sub128( aSig0, aSig1, term0, term1, &aSig0, &aSig1 );
+ shortShift128Left( aSig0, aSig1, 62, &aSig0, &aSig1 );
+ expDiff -= 62;
+ }
+ expDiff += 64;
+ if ( 0 < expDiff ) {
+ q = estimateDiv128To64( aSig0, aSig1, bSig );
+ q = ( 2 < q ) ? q - 2 : 0;
+ q >>= 64 - expDiff;
+ mul64To128( bSig, q<<( 64 - expDiff ), &term0, &term1 );
+ sub128( aSig0, aSig1, term0, term1, &aSig0, &aSig1 );
+ shortShift128Left( 0, bSig, 64 - expDiff, &term0, &term1 );
+ while ( le128( term0, term1, aSig0, aSig1 ) ) {
+ ++q;
+ sub128( aSig0, aSig1, term0, term1, &aSig0, &aSig1 );
+ }
+ }
+ else {
+ term1 = 0;
+ term0 = bSig;
+ }
+ sub128( term0, term1, aSig0, aSig1, &alternateASig0, &alternateASig1 );
+ if ( lt128( alternateASig0, alternateASig1, aSig0, aSig1 )
+ || ( eq128( alternateASig0, alternateASig1, aSig0, aSig1 )
+ && ( q & 1 ) )
+ ) {
+ aSig0 = alternateASig0;
+ aSig1 = alternateASig1;
+ zSign = ! zSign;
+ }
+ return
+ normalizeRoundAndPackFloatx80(
+ 80, zSign, bExp + expDiff, aSig0, aSig1 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the square root of the extended double-precision floating-point
+value `a'. The operation is performed according to the IEC/IEEE Standard
+for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+floatx80 floatx80_sqrt( floatx80 a )
+{
+ flag aSign;
+ int32 aExp, zExp;
+ bits64 aSig0, aSig1, zSig0, zSig1, doubleZSig0;
+ bits64 rem0, rem1, rem2, rem3, term0, term1, term2, term3;
+ floatx80 z;
+
+ aSig0 = extractFloatx80Frac( a );
+ aExp = extractFloatx80Exp( a );
+ aSign = extractFloatx80Sign( a );
+ if ( aExp == 0x7FFF ) {
+ if ( (bits64) ( aSig0<<1 ) ) return propagateFloatx80NaN( a, a );
+ if ( ! aSign ) return a;
+ goto invalid;
+ }
+ if ( aSign ) {
+ if ( ( aExp | aSig0 ) == 0 ) return a;
+ invalid:
+ float_raise( float_flag_invalid );
+ z.low = floatx80_default_nan_low;
+ z.high = floatx80_default_nan_high;
+ return z;
+ }
+ if ( aExp == 0 ) {
+ if ( aSig0 == 0 ) return packFloatx80( 0, 0, 0 );
+ normalizeFloatx80Subnormal( aSig0, &aExp, &aSig0 );
+ }
+ zExp = ( ( aExp - 0x3FFF )>>1 ) + 0x3FFF;
+ zSig0 = estimateSqrt32( aExp, aSig0>>32 );
+ shift128Right( aSig0, 0, 2 + ( aExp & 1 ), &aSig0, &aSig1 );
+ zSig0 = estimateDiv128To64( aSig0, aSig1, zSig0<<32 ) + ( zSig0<<30 );
+ doubleZSig0 = zSig0<<1;
+ mul64To128( zSig0, zSig0, &term0, &term1 );
+ sub128( aSig0, aSig1, term0, term1, &rem0, &rem1 );
+ while ( (sbits64) rem0 < 0 ) {
+ --zSig0;
+ doubleZSig0 -= 2;
+ add128( rem0, rem1, zSig0>>63, doubleZSig0 | 1, &rem0, &rem1 );
+ }
+ zSig1 = estimateDiv128To64( rem1, 0, doubleZSig0 );
+ if ( ( zSig1 & LIT64( 0x3FFFFFFFFFFFFFFF ) ) <= 5 ) {
+ if ( zSig1 == 0 ) zSig1 = 1;
+ mul64To128( doubleZSig0, zSig1, &term1, &term2 );
+ sub128( rem1, 0, term1, term2, &rem1, &rem2 );
+ mul64To128( zSig1, zSig1, &term2, &term3 );
+ sub192( rem1, rem2, 0, 0, term2, term3, &rem1, &rem2, &rem3 );
+ while ( (sbits64) rem1 < 0 ) {
+ --zSig1;
+ shortShift128Left( 0, zSig1, 1, &term2, &term3 );
+ term3 |= 1;
+ term2 |= doubleZSig0;
+ add192( rem1, rem2, rem3, 0, term2, term3, &rem1, &rem2, &rem3 );
+ }
+ zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 );
+ }
+ shortShift128Left( 0, zSig1, 1, &zSig0, &zSig1 );
+ zSig0 |= doubleZSig0;
+ return
+ roundAndPackFloatx80(
+ floatx80_rounding_precision, 0, zExp, zSig0, zSig1 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the extended double-precision floating-point value `a' is
+equal to the corresponding value `b', and 0 otherwise. The comparison is
+performed according to the IEC/IEEE Standard for Binary Floating-Point
+Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag floatx80_eq( floatx80 a, floatx80 b )
+{
+
+ if ( ( ( extractFloatx80Exp( a ) == 0x7FFF )
+ && (bits64) ( extractFloatx80Frac( a )<<1 ) )
+ || ( ( extractFloatx80Exp( b ) == 0x7FFF )
+ && (bits64) ( extractFloatx80Frac( b )<<1 ) )
+ ) {
+ if ( floatx80_is_signaling_nan( a )
+ || floatx80_is_signaling_nan( b ) ) {
+ float_raise( float_flag_invalid );
+ }
+ return 0;
+ }
+ return
+ ( a.low == b.low )
+ && ( ( a.high == b.high )
+ || ( ( a.low == 0 )
+ && ( (bits16) ( ( a.high | b.high )<<1 ) == 0 ) )
+ );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the extended double-precision floating-point value `a' is
+less than or equal to the corresponding value `b', and 0 otherwise. The
+comparison is performed according to the IEC/IEEE Standard for Binary
+Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag floatx80_le( floatx80 a, floatx80 b )
+{
+ flag aSign, bSign;
+
+ if ( ( ( extractFloatx80Exp( a ) == 0x7FFF )
+ && (bits64) ( extractFloatx80Frac( a )<<1 ) )
+ || ( ( extractFloatx80Exp( b ) == 0x7FFF )
+ && (bits64) ( extractFloatx80Frac( b )<<1 ) )
+ ) {
+ float_raise( float_flag_invalid );
+ return 0;
+ }
+ aSign = extractFloatx80Sign( a );
+ bSign = extractFloatx80Sign( b );
+ if ( aSign != bSign ) {
+ return
+ aSign
+ || ( ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
+ == 0 );
+ }
+ return
+ aSign ? le128( b.high, b.low, a.high, a.low )
+ : le128( a.high, a.low, b.high, b.low );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the extended double-precision floating-point value `a' is
+less than the corresponding value `b', and 0 otherwise. The comparison
+is performed according to the IEC/IEEE Standard for Binary Floating-Point
+Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag floatx80_lt( floatx80 a, floatx80 b )
+{
+ flag aSign, bSign;
+
+ if ( ( ( extractFloatx80Exp( a ) == 0x7FFF )
+ && (bits64) ( extractFloatx80Frac( a )<<1 ) )
+ || ( ( extractFloatx80Exp( b ) == 0x7FFF )
+ && (bits64) ( extractFloatx80Frac( b )<<1 ) )
+ ) {
+ float_raise( float_flag_invalid );
+ return 0;
+ }
+ aSign = extractFloatx80Sign( a );
+ bSign = extractFloatx80Sign( b );
+ if ( aSign != bSign ) {
+ return
+ aSign
+ && ( ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
+ != 0 );
+ }
+ return
+ aSign ? lt128( b.high, b.low, a.high, a.low )
+ : lt128( a.high, a.low, b.high, b.low );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the extended double-precision floating-point value `a' is equal
+to the corresponding value `b', and 0 otherwise. The invalid exception is
+raised if either operand is a NaN. Otherwise, the comparison is performed
+according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag floatx80_eq_signaling( floatx80 a, floatx80 b )
+{
+
+ if ( ( ( extractFloatx80Exp( a ) == 0x7FFF )
+ && (bits64) ( extractFloatx80Frac( a )<<1 ) )
+ || ( ( extractFloatx80Exp( b ) == 0x7FFF )
+ && (bits64) ( extractFloatx80Frac( b )<<1 ) )
+ ) {
+ float_raise( float_flag_invalid );
+ return 0;
+ }
+ return
+ ( a.low == b.low )
+ && ( ( a.high == b.high )
+ || ( ( a.low == 0 )
+ && ( (bits16) ( ( a.high | b.high )<<1 ) == 0 ) )
+ );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the extended double-precision floating-point value `a' is less
+than or equal to the corresponding value `b', and 0 otherwise. Quiet NaNs
+do not cause an exception. Otherwise, the comparison is performed according
+to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag floatx80_le_quiet( floatx80 a, floatx80 b )
+{
+ flag aSign, bSign;
+
+ if ( ( ( extractFloatx80Exp( a ) == 0x7FFF )
+ && (bits64) ( extractFloatx80Frac( a )<<1 ) )
+ || ( ( extractFloatx80Exp( b ) == 0x7FFF )
+ && (bits64) ( extractFloatx80Frac( b )<<1 ) )
+ ) {
+ if ( floatx80_is_signaling_nan( a )
+ || floatx80_is_signaling_nan( b ) ) {
+ float_raise( float_flag_invalid );
+ }
+ return 0;
+ }
+ aSign = extractFloatx80Sign( a );
+ bSign = extractFloatx80Sign( b );
+ if ( aSign != bSign ) {
+ return
+ aSign
+ || ( ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
+ == 0 );
+ }
+ return
+ aSign ? le128( b.high, b.low, a.high, a.low )
+ : le128( a.high, a.low, b.high, b.low );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the extended double-precision floating-point value `a' is less
+than the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause
+an exception. Otherwise, the comparison is performed according to the
+IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag floatx80_lt_quiet( floatx80 a, floatx80 b )
+{
+ flag aSign, bSign;
+
+ if ( ( ( extractFloatx80Exp( a ) == 0x7FFF )
+ && (bits64) ( extractFloatx80Frac( a )<<1 ) )
+ || ( ( extractFloatx80Exp( b ) == 0x7FFF )
+ && (bits64) ( extractFloatx80Frac( b )<<1 ) )
+ ) {
+ if ( floatx80_is_signaling_nan( a )
+ || floatx80_is_signaling_nan( b ) ) {
+ float_raise( float_flag_invalid );
+ }
+ return 0;
+ }
+ aSign = extractFloatx80Sign( a );
+ bSign = extractFloatx80Sign( b );
+ if ( aSign != bSign ) {
+ return
+ aSign
+ && ( ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
+ != 0 );
+ }
+ return
+ aSign ? lt128( b.high, b.low, a.high, a.low )
+ : lt128( a.high, a.low, b.high, b.low );
+
+}
+
+#endif
+
+#ifdef FLOAT128
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the quadruple-precision floating-point
+value `a' to the 32-bit two's complement integer format. The conversion
+is performed according to the IEC/IEEE Standard for Binary Floating-Point
+Arithmetic---which means in particular that the conversion is rounded
+according to the current rounding mode. If `a' is a NaN, the largest
+positive integer is returned. Otherwise, if the conversion overflows, the
+largest integer with the same sign as `a' is returned.
+-------------------------------------------------------------------------------
+*/
+int32 float128_to_int32( float128 a )
+{
+ flag aSign;
+ int32 aExp, shiftCount;
+ bits64 aSig0, aSig1;
+
+ aSig1 = extractFloat128Frac1( a );
+ aSig0 = extractFloat128Frac0( a );
+ aExp = extractFloat128Exp( a );
+ aSign = extractFloat128Sign( a );
+ if ( ( aExp == 0x7FFF ) && ( aSig0 | aSig1 ) ) aSign = 0;
+ if ( aExp ) aSig0 |= LIT64( 0x0001000000000000 );
+ aSig0 |= ( aSig1 != 0 );
+ shiftCount = 0x4028 - aExp;
+ if ( 0 < shiftCount ) shift64RightJamming( aSig0, shiftCount, &aSig0 );
+ return roundAndPackInt32( aSign, aSig0 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the quadruple-precision floating-point
+value `a' to the 32-bit two's complement integer format. The conversion
+is performed according to the IEC/IEEE Standard for Binary Floating-Point
+Arithmetic, except that the conversion is always rounded toward zero. If
+`a' is a NaN, the largest positive integer is returned. Otherwise, if the
+conversion overflows, the largest integer with the same sign as `a' is
+returned.
+-------------------------------------------------------------------------------
+*/
+int32 float128_to_int32_round_to_zero( float128 a )
+{
+ flag aSign;
+ int32 aExp, shiftCount;
+ bits64 aSig0, aSig1, savedASig;
+ int32 z;
+
+ aSig1 = extractFloat128Frac1( a );
+ aSig0 = extractFloat128Frac0( a );
+ aExp = extractFloat128Exp( a );
+ aSign = extractFloat128Sign( a );
+ aSig0 |= ( aSig1 != 0 );
+ if ( 0x401E < aExp ) {
+ if ( ( aExp == 0x7FFF ) && aSig0 ) aSign = 0;
+ goto invalid;
+ }
+ else if ( aExp < 0x3FFF ) {
+ if ( aExp || aSig0 ) float_exception_flags |= float_flag_inexact;
+ return 0;
+ }
+ aSig0 |= LIT64( 0x0001000000000000 );
+ shiftCount = 0x402F - aExp;
+ savedASig = aSig0;
+ aSig0 >>= shiftCount;
+ z = aSig0;
+ if ( aSign ) z = - z;
+ if ( ( z < 0 ) ^ aSign ) {
+ invalid:
+ float_raise( float_flag_invalid );
+ return aSign ? (sbits32) 0x80000000 : 0x7FFFFFFF;
+ }
+ if ( ( aSig0<<shiftCount ) != savedASig ) {
+ float_exception_flags |= float_flag_inexact;
+ }
+ return z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the quadruple-precision floating-point
+value `a' to the 64-bit two's complement integer format. The conversion
+is performed according to the IEC/IEEE Standard for Binary Floating-Point
+Arithmetic---which means in particular that the conversion is rounded
+according to the current rounding mode. If `a' is a NaN, the largest
+positive integer is returned. Otherwise, if the conversion overflows, the
+largest integer with the same sign as `a' is returned.
+-------------------------------------------------------------------------------
+*/
+int64 float128_to_int64( float128 a )
+{
+ flag aSign;
+ int32 aExp, shiftCount;
+ bits64 aSig0, aSig1;
+
+ aSig1 = extractFloat128Frac1( a );
+ aSig0 = extractFloat128Frac0( a );
+ aExp = extractFloat128Exp( a );
+ aSign = extractFloat128Sign( a );
+ if ( aExp ) aSig0 |= LIT64( 0x0001000000000000 );
+ shiftCount = 0x402F - aExp;
+ if ( shiftCount <= 0 ) {
+ if ( 0x403E < aExp ) {
+ float_raise( float_flag_invalid );
+ if ( ! aSign
+ || ( ( aExp == 0x7FFF )
+ && ( aSig1 || ( aSig0 != LIT64( 0x0001000000000000 ) ) )
+ )
+ ) {
+ return LIT64( 0x7FFFFFFFFFFFFFFF );
+ }
+ return (sbits64) LIT64( 0x8000000000000000 );
+ }
+ shortShift128Left( aSig0, aSig1, - shiftCount, &aSig0, &aSig1 );
+ }
+ else {
+ shift64ExtraRightJamming( aSig0, aSig1, shiftCount, &aSig0, &aSig1 );
+ }
+ return roundAndPackInt64( aSign, aSig0, aSig1 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the quadruple-precision floating-point
+value `a' to the 64-bit two's complement integer format. The conversion
+is performed according to the IEC/IEEE Standard for Binary Floating-Point
+Arithmetic, except that the conversion is always rounded toward zero.
+If `a' is a NaN, the largest positive integer is returned. Otherwise, if
+the conversion overflows, the largest integer with the same sign as `a' is
+returned.
+-------------------------------------------------------------------------------
+*/
+int64 float128_to_int64_round_to_zero( float128 a )
+{
+ flag aSign;
+ int32 aExp, shiftCount;
+ bits64 aSig0, aSig1;
+ int64 z;
+
+ aSig1 = extractFloat128Frac1( a );
+ aSig0 = extractFloat128Frac0( a );
+ aExp = extractFloat128Exp( a );
+ aSign = extractFloat128Sign( a );
+ if ( aExp ) aSig0 |= LIT64( 0x0001000000000000 );
+ shiftCount = aExp - 0x402F;
+ if ( 0 < shiftCount ) {
+ if ( 0x403E <= aExp ) {
+ aSig0 &= LIT64( 0x0000FFFFFFFFFFFF );
+ if ( ( a.high == LIT64( 0xC03E000000000000 ) )
+ && ( aSig1 < LIT64( 0x0002000000000000 ) ) ) {
+ if ( aSig1 ) float_exception_flags |= float_flag_inexact;
+ }
+ else {
+ float_raise( float_flag_invalid );
+ if ( ! aSign || ( ( aExp == 0x7FFF ) && ( aSig0 | aSig1 ) ) ) {
+ return LIT64( 0x7FFFFFFFFFFFFFFF );
+ }
+ }
+ return (sbits64) LIT64( 0x8000000000000000 );
+ }
+ z = ( aSig0<<shiftCount ) | ( aSig1>>( ( - shiftCount ) & 63 ) );
+ if ( (bits64) ( aSig1<<shiftCount ) ) {
+ float_exception_flags |= float_flag_inexact;
+ }
+ }
+ else {
+ if ( aExp < 0x3FFF ) {
+ if ( aExp | aSig0 | aSig1 ) {
+ float_exception_flags |= float_flag_inexact;
+ }
+ return 0;
+ }
+ z = aSig0>>( - shiftCount );
+ if ( aSig1
+ || ( shiftCount && (bits64) ( aSig0<<( shiftCount & 63 ) ) ) ) {
+ float_exception_flags |= float_flag_inexact;
+ }
+ }
+ if ( aSign ) z = - z;
+ return z;
+
+}
+
+#if (defined(SOFTFLOATSPARC64_FOR_GCC) || defined(SOFTFLOAT_FOR_GCC)) \
+ && defined(SOFTFLOAT_NEED_FIXUNS)
+/*
+ * just like above - but do not care for overflow of signed results
+ */
+uint64 float128_to_uint64_round_to_zero( float128 a )
+{
+ flag aSign;
+ int32 aExp, shiftCount;
+ bits64 aSig0, aSig1;
+ uint64 z;
+
+ aSig1 = extractFloat128Frac1( a );
+ aSig0 = extractFloat128Frac0( a );
+ aExp = extractFloat128Exp( a );
+ aSign = extractFloat128Sign( a );
+ if ( aExp ) aSig0 |= LIT64( 0x0001000000000000 );
+ shiftCount = aExp - 0x402F;
+ if ( 0 < shiftCount ) {
+ if ( 0x403F <= aExp ) {
+ aSig0 &= LIT64( 0x0000FFFFFFFFFFFF );
+ if ( ( a.high == LIT64( 0xC03E000000000000 ) )
+ && ( aSig1 < LIT64( 0x0002000000000000 ) ) ) {
+ if ( aSig1 ) float_exception_flags |= float_flag_inexact;
+ }
+ else {
+ float_raise( float_flag_invalid );
+ }
+ return LIT64( 0xFFFFFFFFFFFFFFFF );
+ }
+ z = ( aSig0<<shiftCount ) | ( aSig1>>( ( - shiftCount ) & 63 ) );
+ if ( (bits64) ( aSig1<<shiftCount ) ) {
+ float_exception_flags |= float_flag_inexact;
+ }
+ }
+ else {
+ if ( aExp < 0x3FFF ) {
+ if ( aExp | aSig0 | aSig1 ) {
+ float_exception_flags |= float_flag_inexact;
+ }
+ return 0;
+ }
+ z = aSig0>>( - shiftCount );
+ if (aSig1 || ( shiftCount && (bits64) ( aSig0<<( shiftCount & 63 ) ) ) ) {
+ float_exception_flags |= float_flag_inexact;
+ }
+ }
+ if ( aSign ) z = - z;
+ return z;
+
+}
+#endif /* (SOFTFLOATSPARC64_FOR_GCC || SOFTFLOAT_FOR_GCC) && SOFTFLOAT_NEED_FIXUNS */
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the quadruple-precision floating-point
+value `a' to the single-precision floating-point format. The conversion
+is performed according to the IEC/IEEE Standard for Binary Floating-Point
+Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float32 float128_to_float32( float128 a )
+{
+ flag aSign;
+ int32 aExp;
+ bits64 aSig0, aSig1;
+ bits32 zSig;
+
+ aSig1 = extractFloat128Frac1( a );
+ aSig0 = extractFloat128Frac0( a );
+ aExp = extractFloat128Exp( a );
+ aSign = extractFloat128Sign( a );
+ if ( aExp == 0x7FFF ) {
+ if ( aSig0 | aSig1 ) {
+ return commonNaNToFloat32( float128ToCommonNaN( a ) );
+ }
+ return packFloat32( aSign, 0xFF, 0 );
+ }
+ aSig0 |= ( aSig1 != 0 );
+ shift64RightJamming( aSig0, 18, &aSig0 );
+ zSig = aSig0;
+ if ( aExp || zSig ) {
+ zSig |= 0x40000000;
+ aExp -= 0x3F81;
+ }
+ return roundAndPackFloat32( aSign, aExp, zSig );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the quadruple-precision floating-point
+value `a' to the double-precision floating-point format. The conversion
+is performed according to the IEC/IEEE Standard for Binary Floating-Point
+Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float64 float128_to_float64( float128 a )
+{
+ flag aSign;
+ int32 aExp;
+ bits64 aSig0, aSig1;
+
+ aSig1 = extractFloat128Frac1( a );
+ aSig0 = extractFloat128Frac0( a );
+ aExp = extractFloat128Exp( a );
+ aSign = extractFloat128Sign( a );
+ if ( aExp == 0x7FFF ) {
+ if ( aSig0 | aSig1 ) {
+ return commonNaNToFloat64( float128ToCommonNaN( a ) );
+ }
+ return packFloat64( aSign, 0x7FF, 0 );
+ }
+ shortShift128Left( aSig0, aSig1, 14, &aSig0, &aSig1 );
+ aSig0 |= ( aSig1 != 0 );
+ if ( aExp || aSig0 ) {
+ aSig0 |= LIT64( 0x4000000000000000 );
+ aExp -= 0x3C01;
+ }
+ return roundAndPackFloat64( aSign, aExp, aSig0 );
+
+}
+
+#ifdef FLOATX80
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the quadruple-precision floating-point
+value `a' to the extended double-precision floating-point format. The
+conversion is performed according to the IEC/IEEE Standard for Binary
+Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+floatx80 float128_to_floatx80( float128 a )
+{
+ flag aSign;
+ int32 aExp;
+ bits64 aSig0, aSig1;
+
+ aSig1 = extractFloat128Frac1( a );
+ aSig0 = extractFloat128Frac0( a );
+ aExp = extractFloat128Exp( a );
+ aSign = extractFloat128Sign( a );
+ if ( aExp == 0x7FFF ) {
+ if ( aSig0 | aSig1 ) {
+ return commonNaNToFloatx80( float128ToCommonNaN( a ) );
+ }
+ return packFloatx80( aSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
+ }
+ if ( aExp == 0 ) {
+ if ( ( aSig0 | aSig1 ) == 0 ) return packFloatx80( aSign, 0, 0 );
+ normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 );
+ }
+ else {
+ aSig0 |= LIT64( 0x0001000000000000 );
+ }
+ shortShift128Left( aSig0, aSig1, 15, &aSig0, &aSig1 );
+ return roundAndPackFloatx80( 80, aSign, aExp, aSig0, aSig1 );
+
+}
+
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Rounds the quadruple-precision floating-point value `a' to an integer, and
+returns the result as a quadruple-precision floating-point value. The
+operation is performed according to the IEC/IEEE Standard for Binary
+Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float128 float128_round_to_int( float128 a )
+{
+ flag aSign;
+ int32 aExp;
+ bits64 lastBitMask, roundBitsMask;
+ int8 roundingMode;
+ float128 z;
+
+ aExp = extractFloat128Exp( a );
+ if ( 0x402F <= aExp ) {
+ if ( 0x406F <= aExp ) {
+ if ( ( aExp == 0x7FFF )
+ && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) )
+ ) {
+ return propagateFloat128NaN( a, a );
+ }
+ return a;
+ }
+ lastBitMask = 1;
+ lastBitMask = ( lastBitMask<<( 0x406E - aExp ) )<<1;
+ roundBitsMask = lastBitMask - 1;
+ z = a;
+ roundingMode = float_rounding_mode;
+ if ( roundingMode == float_round_nearest_even ) {
+ if ( lastBitMask ) {
+ add128( z.high, z.low, 0, lastBitMask>>1, &z.high, &z.low );
+ if ( ( z.low & roundBitsMask ) == 0 ) z.low &= ~ lastBitMask;
+ }
+ else {
+ if ( (sbits64) z.low < 0 ) {
+ ++z.high;
+ if ( (bits64) ( z.low<<1 ) == 0 ) z.high &= ~1;
+ }
+ }
+ }
+ else if ( roundingMode != float_round_to_zero ) {
+ if ( extractFloat128Sign( z )
+ ^ ( roundingMode == float_round_up ) ) {
+ add128( z.high, z.low, 0, roundBitsMask, &z.high, &z.low );
+ }
+ }
+ z.low &= ~ roundBitsMask;
+ }
+ else {
+ if ( aExp < 0x3FFF ) {
+ if ( ( ( (bits64) ( a.high<<1 ) ) | a.low ) == 0 ) return a;
+ float_exception_flags |= float_flag_inexact;
+ aSign = extractFloat128Sign( a );
+ switch ( float_rounding_mode ) {
+ case float_round_nearest_even:
+ if ( ( aExp == 0x3FFE )
+ && ( extractFloat128Frac0( a )
+ | extractFloat128Frac1( a ) )
+ ) {
+ return packFloat128( aSign, 0x3FFF, 0, 0 );
+ }
+ break;
+ case float_round_to_zero:
+ break;
+ case float_round_down:
+ return
+ aSign ? packFloat128( 1, 0x3FFF, 0, 0 )
+ : packFloat128( 0, 0, 0, 0 );
+ case float_round_up:
+ return
+ aSign ? packFloat128( 1, 0, 0, 0 )
+ : packFloat128( 0, 0x3FFF, 0, 0 );
+ }
+ return packFloat128( aSign, 0, 0, 0 );
+ }
+ lastBitMask = 1;
+ lastBitMask <<= 0x402F - aExp;
+ roundBitsMask = lastBitMask - 1;
+ z.low = 0;
+ z.high = a.high;
+ roundingMode = float_rounding_mode;
+ if ( roundingMode == float_round_nearest_even ) {
+ z.high += lastBitMask>>1;
+ if ( ( ( z.high & roundBitsMask ) | a.low ) == 0 ) {
+ z.high &= ~ lastBitMask;
+ }
+ }
+ else if ( roundingMode != float_round_to_zero ) {
+ if ( extractFloat128Sign( z )
+ ^ ( roundingMode == float_round_up ) ) {
+ z.high |= ( a.low != 0 );
+ z.high += roundBitsMask;
+ }
+ }
+ z.high &= ~ roundBitsMask;
+ }
+ if ( ( z.low != a.low ) || ( z.high != a.high ) ) {
+ float_exception_flags |= float_flag_inexact;
+ }
+ return z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of adding the absolute values of the quadruple-precision
+floating-point values `a' and `b'. If `zSign' is 1, the sum is negated
+before being returned. `zSign' is ignored if the result is a NaN.
+The addition is performed according to the IEC/IEEE Standard for Binary
+Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+static float128 addFloat128Sigs( float128 a, float128 b, flag zSign )
+{
+ int32 aExp, bExp, zExp;
+ bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2;
+ int32 expDiff;
+
+ aSig1 = extractFloat128Frac1( a );
+ aSig0 = extractFloat128Frac0( a );
+ aExp = extractFloat128Exp( a );
+ bSig1 = extractFloat128Frac1( b );
+ bSig0 = extractFloat128Frac0( b );
+ bExp = extractFloat128Exp( b );
+ expDiff = aExp - bExp;
+ if ( 0 < expDiff ) {
+ if ( aExp == 0x7FFF ) {
+ if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, b );
+ return a;
+ }
+ if ( bExp == 0 ) {
+ --expDiff;
+ }
+ else {
+ bSig0 |= LIT64( 0x0001000000000000 );
+ }
+ shift128ExtraRightJamming(
+ bSig0, bSig1, 0, expDiff, &bSig0, &bSig1, &zSig2 );
+ zExp = aExp;
+ }
+ else if ( expDiff < 0 ) {
+ if ( bExp == 0x7FFF ) {
+ if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b );
+ return packFloat128( zSign, 0x7FFF, 0, 0 );
+ }
+ if ( aExp == 0 ) {
+ ++expDiff;
+ }
+ else {
+ aSig0 |= LIT64( 0x0001000000000000 );
+ }
+ shift128ExtraRightJamming(
+ aSig0, aSig1, 0, - expDiff, &aSig0, &aSig1, &zSig2 );
+ zExp = bExp;
+ }
+ else {
+ if ( aExp == 0x7FFF ) {
+ if ( aSig0 | aSig1 | bSig0 | bSig1 ) {
+ return propagateFloat128NaN( a, b );
+ }
+ return a;
+ }
+ add128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 );
+ if ( aExp == 0 ) return packFloat128( zSign, 0, zSig0, zSig1 );
+ zSig2 = 0;
+ zSig0 |= LIT64( 0x0002000000000000 );
+ zExp = aExp;
+ goto shiftRight1;
+ }
+ aSig0 |= LIT64( 0x0001000000000000 );
+ add128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 );
+ --zExp;
+ if ( zSig0 < LIT64( 0x0002000000000000 ) ) goto roundAndPack;
+ ++zExp;
+ shiftRight1:
+ shift128ExtraRightJamming(
+ zSig0, zSig1, zSig2, 1, &zSig0, &zSig1, &zSig2 );
+ roundAndPack:
+ return roundAndPackFloat128( zSign, zExp, zSig0, zSig1, zSig2 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of subtracting the absolute values of the quadruple-
+precision floating-point values `a' and `b'. If `zSign' is 1, the
+difference is negated before being returned. `zSign' is ignored if the
+result is a NaN. The subtraction is performed according to the IEC/IEEE
+Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+static float128 subFloat128Sigs( float128 a, float128 b, flag zSign )
+{
+ int32 aExp, bExp, zExp;
+ bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1;
+ int32 expDiff;
+ float128 z;
+
+ aSig1 = extractFloat128Frac1( a );
+ aSig0 = extractFloat128Frac0( a );
+ aExp = extractFloat128Exp( a );
+ bSig1 = extractFloat128Frac1( b );
+ bSig0 = extractFloat128Frac0( b );
+ bExp = extractFloat128Exp( b );
+ expDiff = aExp - bExp;
+ shortShift128Left( aSig0, aSig1, 14, &aSig0, &aSig1 );
+ shortShift128Left( bSig0, bSig1, 14, &bSig0, &bSig1 );
+ if ( 0 < expDiff ) goto aExpBigger;
+ if ( expDiff < 0 ) goto bExpBigger;
+ if ( aExp == 0x7FFF ) {
+ if ( aSig0 | aSig1 | bSig0 | bSig1 ) {
+ return propagateFloat128NaN( a, b );
+ }
+ float_raise( float_flag_invalid );
+ z.low = float128_default_nan_low;
+ z.high = float128_default_nan_high;
+ return z;
+ }
+ if ( aExp == 0 ) {
+ aExp = 1;
+ bExp = 1;
+ }
+ if ( bSig0 < aSig0 ) goto aBigger;
+ if ( aSig0 < bSig0 ) goto bBigger;
+ if ( bSig1 < aSig1 ) goto aBigger;
+ if ( aSig1 < bSig1 ) goto bBigger;
+ return packFloat128( float_rounding_mode == float_round_down, 0, 0, 0 );
+ bExpBigger:
+ if ( bExp == 0x7FFF ) {
+ if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b );
+ return packFloat128( zSign ^ 1, 0x7FFF, 0, 0 );
+ }
+ if ( aExp == 0 ) {
+ ++expDiff;
+ }
+ else {
+ aSig0 |= LIT64( 0x4000000000000000 );
+ }
+ shift128RightJamming( aSig0, aSig1, - expDiff, &aSig0, &aSig1 );
+ bSig0 |= LIT64( 0x4000000000000000 );
+ bBigger:
+ sub128( bSig0, bSig1, aSig0, aSig1, &zSig0, &zSig1 );
+ zExp = bExp;
+ zSign ^= 1;
+ goto normalizeRoundAndPack;
+ aExpBigger:
+ if ( aExp == 0x7FFF ) {
+ if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, b );
+ return a;
+ }
+ if ( bExp == 0 ) {
+ --expDiff;
+ }
+ else {
+ bSig0 |= LIT64( 0x4000000000000000 );
+ }
+ shift128RightJamming( bSig0, bSig1, expDiff, &bSig0, &bSig1 );
+ aSig0 |= LIT64( 0x4000000000000000 );
+ aBigger:
+ sub128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 );
+ zExp = aExp;
+ normalizeRoundAndPack:
+ --zExp;
+ return normalizeRoundAndPackFloat128( zSign, zExp - 14, zSig0, zSig1 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of adding the quadruple-precision floating-point values
+`a' and `b'. The operation is performed according to the IEC/IEEE Standard
+for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float128 float128_add( float128 a, float128 b )
+{
+ flag aSign, bSign;
+
+ aSign = extractFloat128Sign( a );
+ bSign = extractFloat128Sign( b );
+ if ( aSign == bSign ) {
+ return addFloat128Sigs( a, b, aSign );
+ }
+ else {
+ return subFloat128Sigs( a, b, aSign );
+ }
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of subtracting the quadruple-precision floating-point
+values `a' and `b'. The operation is performed according to the IEC/IEEE
+Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float128 float128_sub( float128 a, float128 b )
+{
+ flag aSign, bSign;
+
+ aSign = extractFloat128Sign( a );
+ bSign = extractFloat128Sign( b );
+ if ( aSign == bSign ) {
+ return subFloat128Sigs( a, b, aSign );
+ }
+ else {
+ return addFloat128Sigs( a, b, aSign );
+ }
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of multiplying the quadruple-precision floating-point
+values `a' and `b'. The operation is performed according to the IEC/IEEE
+Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float128 float128_mul( float128 a, float128 b )
+{
+ flag aSign, bSign, zSign;
+ int32 aExp, bExp, zExp;
+ bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2, zSig3;
+ float128 z;
+
+ aSig1 = extractFloat128Frac1( a );
+ aSig0 = extractFloat128Frac0( a );
+ aExp = extractFloat128Exp( a );
+ aSign = extractFloat128Sign( a );
+ bSig1 = extractFloat128Frac1( b );
+ bSig0 = extractFloat128Frac0( b );
+ bExp = extractFloat128Exp( b );
+ bSign = extractFloat128Sign( b );
+ zSign = aSign ^ bSign;
+ if ( aExp == 0x7FFF ) {
+ if ( ( aSig0 | aSig1 )
+ || ( ( bExp == 0x7FFF ) && ( bSig0 | bSig1 ) ) ) {
+ return propagateFloat128NaN( a, b );
+ }
+ if ( ( bExp | bSig0 | bSig1 ) == 0 ) goto invalid;
+ return packFloat128( zSign, 0x7FFF, 0, 0 );
+ }
+ if ( bExp == 0x7FFF ) {
+ if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b );
+ if ( ( aExp | aSig0 | aSig1 ) == 0 ) {
+ invalid:
+ float_raise( float_flag_invalid );
+ z.low = float128_default_nan_low;
+ z.high = float128_default_nan_high;
+ return z;
+ }
+ return packFloat128( zSign, 0x7FFF, 0, 0 );
+ }
+ if ( aExp == 0 ) {
+ if ( ( aSig0 | aSig1 ) == 0 ) return packFloat128( zSign, 0, 0, 0 );
+ normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 );
+ }
+ if ( bExp == 0 ) {
+ if ( ( bSig0 | bSig1 ) == 0 ) return packFloat128( zSign, 0, 0, 0 );
+ normalizeFloat128Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 );
+ }
+ zExp = aExp + bExp - 0x4000;
+ aSig0 |= LIT64( 0x0001000000000000 );
+ shortShift128Left( bSig0, bSig1, 16, &bSig0, &bSig1 );
+ mul128To256( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1, &zSig2, &zSig3 );
+ add128( zSig0, zSig1, aSig0, aSig1, &zSig0, &zSig1 );
+ zSig2 |= ( zSig3 != 0 );
+ if ( LIT64( 0x0002000000000000 ) <= zSig0 ) {
+ shift128ExtraRightJamming(
+ zSig0, zSig1, zSig2, 1, &zSig0, &zSig1, &zSig2 );
+ ++zExp;
+ }
+ return roundAndPackFloat128( zSign, zExp, zSig0, zSig1, zSig2 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of dividing the quadruple-precision floating-point value
+`a' by the corresponding value `b'. The operation is performed according to
+the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float128 float128_div( float128 a, float128 b )
+{
+ flag aSign, bSign, zSign;
+ int32 aExp, bExp, zExp;
+ bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2;
+ bits64 rem0, rem1, rem2, rem3, term0, term1, term2, term3;
+ float128 z;
+
+ aSig1 = extractFloat128Frac1( a );
+ aSig0 = extractFloat128Frac0( a );
+ aExp = extractFloat128Exp( a );
+ aSign = extractFloat128Sign( a );
+ bSig1 = extractFloat128Frac1( b );
+ bSig0 = extractFloat128Frac0( b );
+ bExp = extractFloat128Exp( b );
+ bSign = extractFloat128Sign( b );
+ zSign = aSign ^ bSign;
+ if ( aExp == 0x7FFF ) {
+ if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, b );
+ if ( bExp == 0x7FFF ) {
+ if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b );
+ goto invalid;
+ }
+ return packFloat128( zSign, 0x7FFF, 0, 0 );
+ }
+ if ( bExp == 0x7FFF ) {
+ if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b );
+ return packFloat128( zSign, 0, 0, 0 );
+ }
+ if ( bExp == 0 ) {
+ if ( ( bSig0 | bSig1 ) == 0 ) {
+ if ( ( aExp | aSig0 | aSig1 ) == 0 ) {
+ invalid:
+ float_raise( float_flag_invalid );
+ z.low = float128_default_nan_low;
+ z.high = float128_default_nan_high;
+ return z;
+ }
+ float_raise( float_flag_divbyzero );
+ return packFloat128( zSign, 0x7FFF, 0, 0 );
+ }
+ normalizeFloat128Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 );
+ }
+ if ( aExp == 0 ) {
+ if ( ( aSig0 | aSig1 ) == 0 ) return packFloat128( zSign, 0, 0, 0 );
+ normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 );
+ }
+ zExp = aExp - bExp + 0x3FFD;
+ shortShift128Left(
+ aSig0 | LIT64( 0x0001000000000000 ), aSig1, 15, &aSig0, &aSig1 );
+ shortShift128Left(
+ bSig0 | LIT64( 0x0001000000000000 ), bSig1, 15, &bSig0, &bSig1 );
+ if ( le128( bSig0, bSig1, aSig0, aSig1 ) ) {
+ shift128Right( aSig0, aSig1, 1, &aSig0, &aSig1 );
+ ++zExp;
+ }
+ zSig0 = estimateDiv128To64( aSig0, aSig1, bSig0 );
+ mul128By64To192( bSig0, bSig1, zSig0, &term0, &term1, &term2 );
+ sub192( aSig0, aSig1, 0, term0, term1, term2, &rem0, &rem1, &rem2 );
+ while ( (sbits64) rem0 < 0 ) {
+ --zSig0;
+ add192( rem0, rem1, rem2, 0, bSig0, bSig1, &rem0, &rem1, &rem2 );
+ }
+ zSig1 = estimateDiv128To64( rem1, rem2, bSig0 );
+ if ( ( zSig1 & 0x3FFF ) <= 4 ) {
+ mul128By64To192( bSig0, bSig1, zSig1, &term1, &term2, &term3 );
+ sub192( rem1, rem2, 0, term1, term2, term3, &rem1, &rem2, &rem3 );
+ while ( (sbits64) rem1 < 0 ) {
+ --zSig1;
+ add192( rem1, rem2, rem3, 0, bSig0, bSig1, &rem1, &rem2, &rem3 );
+ }
+ zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 );
+ }
+ shift128ExtraRightJamming( zSig0, zSig1, 0, 15, &zSig0, &zSig1, &zSig2 );
+ return roundAndPackFloat128( zSign, zExp, zSig0, zSig1, zSig2 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the remainder of the quadruple-precision floating-point value `a'
+with respect to the corresponding value `b'. The operation is performed
+according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float128 float128_rem( float128 a, float128 b )
+{
+ flag aSign, bSign, zSign;
+ int32 aExp, bExp, expDiff;
+ bits64 aSig0, aSig1, bSig0, bSig1, q, term0, term1, term2;
+ bits64 allZero, alternateASig0, alternateASig1, sigMean1;
+ sbits64 sigMean0;
+ float128 z;
+
+ aSig1 = extractFloat128Frac1( a );
+ aSig0 = extractFloat128Frac0( a );
+ aExp = extractFloat128Exp( a );
+ aSign = extractFloat128Sign( a );
+ bSig1 = extractFloat128Frac1( b );
+ bSig0 = extractFloat128Frac0( b );
+ bExp = extractFloat128Exp( b );
+ bSign = extractFloat128Sign( b );
+ if ( aExp == 0x7FFF ) {
+ if ( ( aSig0 | aSig1 )
+ || ( ( bExp == 0x7FFF ) && ( bSig0 | bSig1 ) ) ) {
+ return propagateFloat128NaN( a, b );
+ }
+ goto invalid;
+ }
+ if ( bExp == 0x7FFF ) {
+ if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b );
+ return a;
+ }
+ if ( bExp == 0 ) {
+ if ( ( bSig0 | bSig1 ) == 0 ) {
+ invalid:
+ float_raise( float_flag_invalid );
+ z.low = float128_default_nan_low;
+ z.high = float128_default_nan_high;
+ return z;
+ }
+ normalizeFloat128Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 );
+ }
+ if ( aExp == 0 ) {
+ if ( ( aSig0 | aSig1 ) == 0 ) return a;
+ normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 );
+ }
+ expDiff = aExp - bExp;
+ if ( expDiff < -1 ) return a;
+ shortShift128Left(
+ aSig0 | LIT64( 0x0001000000000000 ),
+ aSig1,
+ 15 - ( expDiff < 0 ),
+ &aSig0,
+ &aSig1
+ );
+ shortShift128Left(
+ bSig0 | LIT64( 0x0001000000000000 ), bSig1, 15, &bSig0, &bSig1 );
+ q = le128( bSig0, bSig1, aSig0, aSig1 );
+ if ( q ) sub128( aSig0, aSig1, bSig0, bSig1, &aSig0, &aSig1 );
+ expDiff -= 64;
+ while ( 0 < expDiff ) {
+ q = estimateDiv128To64( aSig0, aSig1, bSig0 );
+ q = ( 4 < q ) ? q - 4 : 0;
+ mul128By64To192( bSig0, bSig1, q, &term0, &term1, &term2 );
+ shortShift192Left( term0, term1, term2, 61, &term1, &term2, &allZero );
+ shortShift128Left( aSig0, aSig1, 61, &aSig0, &allZero );
+ sub128( aSig0, 0, term1, term2, &aSig0, &aSig1 );
+ expDiff -= 61;
+ }
+ if ( -64 < expDiff ) {
+ q = estimateDiv128To64( aSig0, aSig1, bSig0 );
+ q = ( 4 < q ) ? q - 4 : 0;
+ q >>= - expDiff;
+ shift128Right( bSig0, bSig1, 12, &bSig0, &bSig1 );
+ expDiff += 52;
+ if ( expDiff < 0 ) {
+ shift128Right( aSig0, aSig1, - expDiff, &aSig0, &aSig1 );
+ }
+ else {
+ shortShift128Left( aSig0, aSig1, expDiff, &aSig0, &aSig1 );
+ }
+ mul128By64To192( bSig0, bSig1, q, &term0, &term1, &term2 );
+ sub128( aSig0, aSig1, term1, term2, &aSig0, &aSig1 );
+ }
+ else {
+ shift128Right( aSig0, aSig1, 12, &aSig0, &aSig1 );
+ shift128Right( bSig0, bSig1, 12, &bSig0, &bSig1 );
+ }
+ do {
+ alternateASig0 = aSig0;
+ alternateASig1 = aSig1;
+ ++q;
+ sub128( aSig0, aSig1, bSig0, bSig1, &aSig0, &aSig1 );
+ } while ( 0 <= (sbits64) aSig0 );
+ add128(
+ aSig0, aSig1, alternateASig0, alternateASig1, (bits64 *)&sigMean0, &sigMean1 );
+ if ( ( sigMean0 < 0 )
+ || ( ( ( sigMean0 | sigMean1 ) == 0 ) && ( q & 1 ) ) ) {
+ aSig0 = alternateASig0;
+ aSig1 = alternateASig1;
+ }
+ zSign = ( (sbits64) aSig0 < 0 );
+ if ( zSign ) sub128( 0, 0, aSig0, aSig1, &aSig0, &aSig1 );
+ return
+ normalizeRoundAndPackFloat128( aSign ^ zSign, bExp - 4, aSig0, aSig1 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the square root of the quadruple-precision floating-point value `a'.
+The operation is performed according to the IEC/IEEE Standard for Binary
+Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float128 float128_sqrt( float128 a )
+{
+ flag aSign;
+ int32 aExp, zExp;
+ bits64 aSig0, aSig1, zSig0, zSig1, zSig2, doubleZSig0;
+ bits64 rem0, rem1, rem2, rem3, term0, term1, term2, term3;
+ float128 z;
+
+ aSig1 = extractFloat128Frac1( a );
+ aSig0 = extractFloat128Frac0( a );
+ aExp = extractFloat128Exp( a );
+ aSign = extractFloat128Sign( a );
+ if ( aExp == 0x7FFF ) {
+ if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, a );
+ if ( ! aSign ) return a;
+ goto invalid;
+ }
+ if ( aSign ) {
+ if ( ( aExp | aSig0 | aSig1 ) == 0 ) return a;
+ invalid:
+ float_raise( float_flag_invalid );
+ z.low = float128_default_nan_low;
+ z.high = float128_default_nan_high;
+ return z;
+ }
+ if ( aExp == 0 ) {
+ if ( ( aSig0 | aSig1 ) == 0 ) return packFloat128( 0, 0, 0, 0 );
+ normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 );
+ }
+ zExp = ( ( aExp - 0x3FFF )>>1 ) + 0x3FFE;
+ aSig0 |= LIT64( 0x0001000000000000 );
+ zSig0 = estimateSqrt32( aExp, aSig0>>17 );
+ shortShift128Left( aSig0, aSig1, 13 - ( aExp & 1 ), &aSig0, &aSig1 );
+ zSig0 = estimateDiv128To64( aSig0, aSig1, zSig0<<32 ) + ( zSig0<<30 );
+ doubleZSig0 = zSig0<<1;
+ mul64To128( zSig0, zSig0, &term0, &term1 );
+ sub128( aSig0, aSig1, term0, term1, &rem0, &rem1 );
+ while ( (sbits64) rem0 < 0 ) {
+ --zSig0;
+ doubleZSig0 -= 2;
+ add128( rem0, rem1, zSig0>>63, doubleZSig0 | 1, &rem0, &rem1 );
+ }
+ zSig1 = estimateDiv128To64( rem1, 0, doubleZSig0 );
+ if ( ( zSig1 & 0x1FFF ) <= 5 ) {
+ if ( zSig1 == 0 ) zSig1 = 1;
+ mul64To128( doubleZSig0, zSig1, &term1, &term2 );
+ sub128( rem1, 0, term1, term2, &rem1, &rem2 );
+ mul64To128( zSig1, zSig1, &term2, &term3 );
+ sub192( rem1, rem2, 0, 0, term2, term3, &rem1, &rem2, &rem3 );
+ while ( (sbits64) rem1 < 0 ) {
+ --zSig1;
+ shortShift128Left( 0, zSig1, 1, &term2, &term3 );
+ term3 |= 1;
+ term2 |= doubleZSig0;
+ add192( rem1, rem2, rem3, 0, term2, term3, &rem1, &rem2, &rem3 );
+ }
+ zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 );
+ }
+ shift128ExtraRightJamming( zSig0, zSig1, 0, 14, &zSig0, &zSig1, &zSig2 );
+ return roundAndPackFloat128( 0, zExp, zSig0, zSig1, zSig2 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the quadruple-precision floating-point value `a' is equal to
+the corresponding value `b', and 0 otherwise. The comparison is performed
+according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float128_eq( float128 a, float128 b )
+{
+
+ if ( ( ( extractFloat128Exp( a ) == 0x7FFF )
+ && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) )
+ || ( ( extractFloat128Exp( b ) == 0x7FFF )
+ && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
+ ) {
+ if ( float128_is_signaling_nan( a )
+ || float128_is_signaling_nan( b ) ) {
+ float_raise( float_flag_invalid );
+ }
+ return 0;
+ }
+ return
+ ( a.low == b.low )
+ && ( ( a.high == b.high )
+ || ( ( a.low == 0 )
+ && ( (bits64) ( ( a.high | b.high )<<1 ) == 0 ) )
+ );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the quadruple-precision floating-point value `a' is less than
+or equal to the corresponding value `b', and 0 otherwise. The comparison
+is performed according to the IEC/IEEE Standard for Binary Floating-Point
+Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float128_le( float128 a, float128 b )
+{
+ flag aSign, bSign;
+
+ if ( ( ( extractFloat128Exp( a ) == 0x7FFF )
+ && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) )
+ || ( ( extractFloat128Exp( b ) == 0x7FFF )
+ && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
+ ) {
+ float_raise( float_flag_invalid );
+ return 0;
+ }
+ aSign = extractFloat128Sign( a );
+ bSign = extractFloat128Sign( b );
+ if ( aSign != bSign ) {
+ return
+ aSign
+ || ( ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
+ == 0 );
+ }
+ return
+ aSign ? le128( b.high, b.low, a.high, a.low )
+ : le128( a.high, a.low, b.high, b.low );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the quadruple-precision floating-point value `a' is less than
+the corresponding value `b', and 0 otherwise. The comparison is performed
+according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float128_lt( float128 a, float128 b )
+{
+ flag aSign, bSign;
+
+ if ( ( ( extractFloat128Exp( a ) == 0x7FFF )
+ && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) )
+ || ( ( extractFloat128Exp( b ) == 0x7FFF )
+ && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
+ ) {
+ float_raise( float_flag_invalid );
+ return 0;
+ }
+ aSign = extractFloat128Sign( a );
+ bSign = extractFloat128Sign( b );
+ if ( aSign != bSign ) {
+ return
+ aSign
+ && ( ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
+ != 0 );
+ }
+ return
+ aSign ? lt128( b.high, b.low, a.high, a.low )
+ : lt128( a.high, a.low, b.high, b.low );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the quadruple-precision floating-point value `a' is equal to
+the corresponding value `b', and 0 otherwise. The invalid exception is
+raised if either operand is a NaN. Otherwise, the comparison is performed
+according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float128_eq_signaling( float128 a, float128 b )
+{
+
+ if ( ( ( extractFloat128Exp( a ) == 0x7FFF )
+ && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) )
+ || ( ( extractFloat128Exp( b ) == 0x7FFF )
+ && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
+ ) {
+ float_raise( float_flag_invalid );
+ return 0;
+ }
+ return
+ ( a.low == b.low )
+ && ( ( a.high == b.high )
+ || ( ( a.low == 0 )
+ && ( (bits64) ( ( a.high | b.high )<<1 ) == 0 ) )
+ );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the quadruple-precision floating-point value `a' is less than
+or equal to the corresponding value `b', and 0 otherwise. Quiet NaNs do not
+cause an exception. Otherwise, the comparison is performed according to the
+IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float128_le_quiet( float128 a, float128 b )
+{
+ flag aSign, bSign;
+
+ if ( ( ( extractFloat128Exp( a ) == 0x7FFF )
+ && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) )
+ || ( ( extractFloat128Exp( b ) == 0x7FFF )
+ && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
+ ) {
+ if ( float128_is_signaling_nan( a )
+ || float128_is_signaling_nan( b ) ) {
+ float_raise( float_flag_invalid );
+ }
+ return 0;
+ }
+ aSign = extractFloat128Sign( a );
+ bSign = extractFloat128Sign( b );
+ if ( aSign != bSign ) {
+ return
+ aSign
+ || ( ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
+ == 0 );
+ }
+ return
+ aSign ? le128( b.high, b.low, a.high, a.low )
+ : le128( a.high, a.low, b.high, b.low );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the quadruple-precision floating-point value `a' is less than
+the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an
+exception. Otherwise, the comparison is performed according to the IEC/IEEE
+Standard for Binary Floating-Point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float128_lt_quiet( float128 a, float128 b )
+{
+ flag aSign, bSign;
+
+ if ( ( ( extractFloat128Exp( a ) == 0x7FFF )
+ && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) )
+ || ( ( extractFloat128Exp( b ) == 0x7FFF )
+ && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
+ ) {
+ if ( float128_is_signaling_nan( a )
+ || float128_is_signaling_nan( b ) ) {
+ float_raise( float_flag_invalid );
+ }
+ return 0;
+ }
+ aSign = extractFloat128Sign( a );
+ bSign = extractFloat128Sign( b );
+ if ( aSign != bSign ) {
+ return
+ aSign
+ && ( ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
+ != 0 );
+ }
+ return
+ aSign ? lt128( b.high, b.low, a.high, a.low )
+ : lt128( a.high, a.low, b.high, b.low );
+
+}
+
+#endif
+
+
+#if defined(SOFTFLOAT_FOR_GCC) && defined(SOFTFLOAT_NEED_FIXUNS)
+
+/*
+ * These two routines are not part of the original softfloat distribution.
+ *
+ * They are based on the corresponding conversions to integer but return
+ * unsigned numbers instead since these functions are required by GCC.
+ *
+ * Added by Mark Brinicombe <mark@NetBSD.org> 27/09/97
+ *
+ * float64 version overhauled for SoftFloat 2a [bjh21 2000-07-15]
+ */
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the double-precision floating-point value
+`a' to the 32-bit unsigned integer format. The conversion is
+performed according to the IEC/IEEE Standard for Binary Floating-point
+Arithmetic, except that the conversion is always rounded toward zero. If
+`a' is a NaN, the largest positive integer is returned. If the conversion
+overflows, the largest integer positive is returned.
+-------------------------------------------------------------------------------
+*/
+uint32 float64_to_uint32_round_to_zero( float64 a )
+{
+ flag aSign;
+ int16 aExp, shiftCount;
+ bits64 aSig, savedASig;
+ uint32 z;
+
+ aSig = extractFloat64Frac( a );
+ aExp = extractFloat64Exp( a );
+ aSign = extractFloat64Sign( a );
+
+ if (aSign) {
+ float_raise( float_flag_invalid );
+ return(0);
+ }
+
+ if ( 0x41E < aExp ) {
+ float_raise( float_flag_invalid );
+ return 0xffffffff;
+ }
+ else if ( aExp < 0x3FF ) {
+ if ( aExp || aSig ) float_exception_flags |= float_flag_inexact;
+ return 0;
+ }
+ aSig |= LIT64( 0x0010000000000000 );
+ shiftCount = 0x433 - aExp;
+ savedASig = aSig;
+ aSig >>= shiftCount;
+ z = aSig;
+ if ( ( aSig<<shiftCount ) != savedASig ) {
+ float_exception_flags |= float_flag_inexact;
+ }
+ return z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the single-precision floating-point value
+`a' to the 32-bit unsigned integer format. The conversion is
+performed according to the IEC/IEEE Standard for Binary Floating-point
+Arithmetic, except that the conversion is always rounded toward zero. If
+`a' is a NaN, the largest positive integer is returned. If the conversion
+overflows, the largest positive integer is returned.
+-------------------------------------------------------------------------------
+*/
+uint32 float32_to_uint32_round_to_zero( float32 a )
+{
+ flag aSign;
+ int16 aExp, shiftCount;
+ bits32 aSig;
+ uint32 z;
+
+ aSig = extractFloat32Frac( a );
+ aExp = extractFloat32Exp( a );
+ aSign = extractFloat32Sign( a );
+ shiftCount = aExp - 0x9E;
+
+ if (aSign) {
+ float_raise( float_flag_invalid );
+ return(0);
+ }
+ if ( 0 < shiftCount ) {
+ float_raise( float_flag_invalid );
+ return 0xFFFFFFFF;
+ }
+ else if ( aExp <= 0x7E ) {
+ if ( aExp | aSig ) float_exception_flags |= float_flag_inexact;
+ return 0;
+ }
+ aSig = ( aSig | 0x800000 )<<8;
+ z = aSig>>( - shiftCount );
+ if ( aSig<<( shiftCount & 31 ) ) {
+ float_exception_flags |= float_flag_inexact;
+ }
+ return z;
+
+}
+
+#endif
diff --git a/lib/libc/softfloat/eqdf2.c b/lib/libc/softfloat/eqdf2.c
new file mode 100644
index 000000000000..68bb55c30e2c
--- /dev/null
+++ b/lib/libc/softfloat/eqdf2.c
@@ -0,0 +1,22 @@
+/* $NetBSD: eqdf2.c,v 1.1 2000/06/06 08:15:02 bjh21 Exp $ */
+
+/*
+ * Written by Ben Harris, 2000. This file is in the Public Domain.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "softfloat-for-gcc.h"
+#include "milieu.h"
+#include "softfloat.h"
+
+flag __eqdf2(float64, float64);
+
+flag
+__eqdf2(float64 a, float64 b)
+{
+
+ /* libgcc1.c says !(a == b) */
+ return !float64_eq(a, b);
+}
diff --git a/lib/libc/softfloat/eqsf2.c b/lib/libc/softfloat/eqsf2.c
new file mode 100644
index 000000000000..d45b806cc9f3
--- /dev/null
+++ b/lib/libc/softfloat/eqsf2.c
@@ -0,0 +1,22 @@
+/* $NetBSD: eqsf2.c,v 1.1 2000/06/06 08:15:03 bjh21 Exp $ */
+
+/*
+ * Written by Ben Harris, 2000. This file is in the Public Domain.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "softfloat-for-gcc.h"
+#include "milieu.h"
+#include "softfloat.h"
+
+flag __eqsf2(float32, float32);
+
+flag
+__eqsf2(float32 a, float32 b)
+{
+
+ /* libgcc1.c says !(a == b) */
+ return !float32_eq(a, b);
+}
diff --git a/lib/libc/softfloat/eqtf2.c b/lib/libc/softfloat/eqtf2.c
new file mode 100644
index 000000000000..1839404e1b1a
--- /dev/null
+++ b/lib/libc/softfloat/eqtf2.c
@@ -0,0 +1,24 @@
+/* $NetBSD: eqtf2.c,v 1.1 2011/01/17 10:08:35 matt Exp $ */
+
+/*
+ * Written by Matt Thomas, 2011. This file is in the Public Domain.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "softfloat-for-gcc.h"
+#include "milieu.h"
+#include "softfloat.h"
+
+#ifdef FLOAT128
+flag __eqtf2(float128, float128);
+
+flag
+__eqtf2(float128 a, float128 b)
+{
+
+ /* libgcc1.c says !(a == b) */
+ return !float128_eq(a, b);
+}
+#endif /* FLOAT128 */
diff --git a/lib/libc/softfloat/fpgetmask.c b/lib/libc/softfloat/fpgetmask.c
new file mode 100644
index 000000000000..20c6928a3e55
--- /dev/null
+++ b/lib/libc/softfloat/fpgetmask.c
@@ -0,0 +1,53 @@
+/* $NetBSD: fpgetmask.c,v 1.4 2008/04/28 20:23:00 martin Exp $ */
+
+/*-
+ * Copyright (c) 1997 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Neil A. Carson and Mark Brinicombe
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+
+#include <ieeefp.h>
+#ifdef SOFTFLOAT_FOR_GCC
+#include "softfloat-for-gcc.h"
+#endif
+#include "milieu.h"
+#include "softfloat.h"
+
+#ifdef __weak_alias
+__weak_alias(fpgetmask,_fpgetmask)
+#endif
+
+fp_except
+fpgetmask(void)
+{
+
+ return float_exception_mask;
+}
diff --git a/lib/libc/softfloat/fpgetround.c b/lib/libc/softfloat/fpgetround.c
new file mode 100644
index 000000000000..6ff1ffdb6f22
--- /dev/null
+++ b/lib/libc/softfloat/fpgetround.c
@@ -0,0 +1,53 @@
+/* $NetBSD: fpgetround.c,v 1.3 2008/04/28 20:23:00 martin Exp $ */
+
+/*-
+ * Copyright (c) 1997 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Neil A. Carson and Mark Brinicombe
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+
+#include <ieeefp.h>
+#ifdef SOFTFLOAT_FOR_GCC
+#include "softfloat-for-gcc.h"
+#endif
+#include "milieu.h"
+#include "softfloat.h"
+
+#ifdef __weak_alias
+__weak_alias(fpgetround,_fpgetround)
+#endif
+
+fp_rnd_t
+fpgetround(void)
+{
+
+ return float_rounding_mode;
+}
diff --git a/lib/libc/softfloat/fpgetsticky.c b/lib/libc/softfloat/fpgetsticky.c
new file mode 100644
index 000000000000..f7ef466ba297
--- /dev/null
+++ b/lib/libc/softfloat/fpgetsticky.c
@@ -0,0 +1,53 @@
+/* $NetBSD: fpgetsticky.c,v 1.3 2008/04/28 20:23:00 martin Exp $ */
+
+/*-
+ * Copyright (c) 1997 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Neil A. Carson and Mark Brinicombe
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+
+#include <ieeefp.h>
+#ifdef SOFTFLOAT_FOR_GCC
+#include "softfloat-for-gcc.h"
+#endif
+#include "milieu.h"
+#include "softfloat.h"
+
+#ifdef __weak_alias
+__weak_alias(fpgetsticky,_fpgetsticky)
+#endif
+
+fp_except
+fpgetsticky(void)
+{
+
+ return float_exception_flags;
+}
diff --git a/lib/libc/softfloat/fpsetmask.c b/lib/libc/softfloat/fpsetmask.c
new file mode 100644
index 000000000000..47dcc95e85dc
--- /dev/null
+++ b/lib/libc/softfloat/fpsetmask.c
@@ -0,0 +1,56 @@
+/* $NetBSD: fpsetmask.c,v 1.4 2008/04/28 20:23:00 martin Exp $ */
+
+/*-
+ * Copyright (c) 1997 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Neil A. Carson and Mark Brinicombe
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+
+#include <ieeefp.h>
+#ifdef SOFTFLOAT_FOR_GCC
+#include "softfloat-for-gcc.h"
+#endif
+#include "milieu.h"
+#include "softfloat.h"
+
+#ifdef __weak_alias
+__weak_alias(fpsetmask,_fpsetmask)
+#endif
+
+fp_except
+fpsetmask(fp_except mask)
+{
+ fp_except old;
+
+ old = float_exception_mask;
+ float_exception_mask = mask;
+ return old;
+}
diff --git a/lib/libc/softfloat/fpsetround.c b/lib/libc/softfloat/fpsetround.c
new file mode 100644
index 000000000000..ecdb6adf8ca7
--- /dev/null
+++ b/lib/libc/softfloat/fpsetround.c
@@ -0,0 +1,56 @@
+/* $NetBSD: fpsetround.c,v 1.3 2008/04/28 20:23:00 martin Exp $ */
+
+/*-
+ * Copyright (c) 1997 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Neil A. Carson and Mark Brinicombe
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+
+#include <ieeefp.h>
+#ifdef SOFTFLOAT_FOR_GCC
+#include "softfloat-for-gcc.h"
+#endif
+#include "milieu.h"
+#include "softfloat.h"
+
+#ifdef __weak_alias
+__weak_alias(fpsetround,_fpsetround)
+#endif
+
+fp_rnd_t
+fpsetround(fp_rnd_t rnd_dir)
+{
+ fp_rnd_t old;
+
+ old = float_rounding_mode;
+ float_rounding_mode = rnd_dir;
+ return old;
+}
diff --git a/lib/libc/softfloat/fpsetsticky.c b/lib/libc/softfloat/fpsetsticky.c
new file mode 100644
index 000000000000..526b19faf0cf
--- /dev/null
+++ b/lib/libc/softfloat/fpsetsticky.c
@@ -0,0 +1,56 @@
+/* $NetBSD: fpsetsticky.c,v 1.3 2008/04/28 20:23:00 martin Exp $ */
+
+/*-
+ * Copyright (c) 1997 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Neil A. Carson and Mark Brinicombe
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+
+#include <ieeefp.h>
+#ifdef SOFTFLOAT_FOR_GCC
+#include "softfloat-for-gcc.h"
+#endif
+#include "milieu.h"
+#include "softfloat.h"
+
+#ifdef __weak_alias
+__weak_alias(fpsetsticky,_fpsetsticky)
+#endif
+
+fp_except
+fpsetsticky(fp_except except)
+{
+ fp_except old;
+
+ old = float_exception_flags;
+ float_exception_flags = except;
+ return old;
+}
diff --git a/lib/libc/softfloat/gedf2.c b/lib/libc/softfloat/gedf2.c
new file mode 100644
index 000000000000..76e25de58a64
--- /dev/null
+++ b/lib/libc/softfloat/gedf2.c
@@ -0,0 +1,22 @@
+/* $NetBSD: gedf2.c,v 1.1 2000/06/06 08:15:05 bjh21 Exp $ */
+
+/*
+ * Written by Ben Harris, 2000. This file is in the Public Domain.
+ */
+
+#include "softfloat-for-gcc.h"
+#include "milieu.h"
+#include "softfloat.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+flag __gedf2(float64, float64);
+
+flag
+__gedf2(float64 a, float64 b)
+{
+
+ /* libgcc1.c says (a >= b) - 1 */
+ return float64_le(b, a) - 1;
+}
diff --git a/lib/libc/softfloat/gesf2.c b/lib/libc/softfloat/gesf2.c
new file mode 100644
index 000000000000..b22e13afb63d
--- /dev/null
+++ b/lib/libc/softfloat/gesf2.c
@@ -0,0 +1,22 @@
+/* $NetBSD: gesf2.c,v 1.1 2000/06/06 08:15:05 bjh21 Exp $ */
+
+/*
+ * Written by Ben Harris, 2000. This file is in the Public Domain.
+ */
+
+#include "softfloat-for-gcc.h"
+#include "milieu.h"
+#include "softfloat.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+flag __gesf2(float32, float32);
+
+flag
+__gesf2(float32 a, float32 b)
+{
+
+ /* libgcc1.c says (a >= b) - 1 */
+ return float32_le(b, a) - 1;
+}
diff --git a/lib/libc/softfloat/getf2.c b/lib/libc/softfloat/getf2.c
new file mode 100644
index 000000000000..8639c4d3916a
--- /dev/null
+++ b/lib/libc/softfloat/getf2.c
@@ -0,0 +1,26 @@
+/* $NetBSD: getf2.c,v 1.1 2011/01/17 10:08:35 matt Exp $ */
+
+/*
+ * Written by Matt Thomas, 2011. This file is in the Public Domain.
+ */
+
+#include "softfloat-for-gcc.h"
+#include "milieu.h"
+#include "softfloat.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifdef FLOAT128
+
+flag __getf2(float128, float128);
+
+flag
+__getf2(float128 a, float128 b)
+{
+
+ /* libgcc1.c says (a >= b) - 1 */
+ return float128_le(b, a) - 1;
+}
+
+#endif /* FLOAT128 */
diff --git a/lib/libc/softfloat/gexf2.c b/lib/libc/softfloat/gexf2.c
new file mode 100644
index 000000000000..70cf1c32d7ec
--- /dev/null
+++ b/lib/libc/softfloat/gexf2.c
@@ -0,0 +1,25 @@
+/* $NetBSD: gexf2.c,v 1.2 2004/09/27 10:16:24 he Exp $ */
+
+/*
+ * Written by Ben Harris, 2000. This file is in the Public Domain.
+ */
+
+#include "softfloat-for-gcc.h"
+#include "milieu.h"
+#include "softfloat.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifdef FLOATX80
+
+flag __gexf2(floatx80, floatx80);
+
+flag
+__gexf2(floatx80 a, floatx80 b)
+{
+
+ /* libgcc1.c says (a >= b) - 1 */
+ return floatx80_le(b, a) - 1;
+}
+#endif /* FLOATX80 */
diff --git a/lib/libc/softfloat/gtdf2.c b/lib/libc/softfloat/gtdf2.c
new file mode 100644
index 000000000000..ff5764a519c6
--- /dev/null
+++ b/lib/libc/softfloat/gtdf2.c
@@ -0,0 +1,22 @@
+/* $NetBSD: gtdf2.c,v 1.1 2000/06/06 08:15:05 bjh21 Exp $ */
+
+/*
+ * Written by Ben Harris, 2000. This file is in the Public Domain.
+ */
+
+#include "softfloat-for-gcc.h"
+#include "milieu.h"
+#include "softfloat.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+flag __gtdf2(float64, float64);
+
+flag
+__gtdf2(float64 a, float64 b)
+{
+
+ /* libgcc1.c says a > b */
+ return float64_lt(b, a);
+}
diff --git a/lib/libc/softfloat/gtsf2.c b/lib/libc/softfloat/gtsf2.c
new file mode 100644
index 000000000000..8e7e7a9371c1
--- /dev/null
+++ b/lib/libc/softfloat/gtsf2.c
@@ -0,0 +1,22 @@
+/* $NetBSD: gtsf2.c,v 1.1 2000/06/06 08:15:06 bjh21 Exp $ */
+
+/*
+ * Written by Ben Harris, 2000. This file is in the Public Domain.
+ */
+
+#include "softfloat-for-gcc.h"
+#include "milieu.h"
+#include "softfloat.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+flag __gtsf2(float32, float32);
+
+flag
+__gtsf2(float32 a, float32 b)
+{
+
+ /* libgcc1.c says a > b */
+ return float32_lt(b, a);
+}
diff --git a/lib/libc/softfloat/gttf2.c b/lib/libc/softfloat/gttf2.c
new file mode 100644
index 000000000000..519ea845f00c
--- /dev/null
+++ b/lib/libc/softfloat/gttf2.c
@@ -0,0 +1,26 @@
+/* $NetBSD: gttf2.c,v 1.1 2011/01/17 10:08:35 matt Exp $ */
+
+/*
+ * Written by Matt Thomas, 2011. This file is in the Public Domain.
+ */
+
+#include "softfloat-for-gcc.h"
+#include "milieu.h"
+#include "softfloat.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifdef FLOAT128
+
+flag __gttf2(float128, float128);
+
+flag
+__gttf2(float128 a, float128 b)
+{
+
+ /* libgcc1.c says a > b */
+ return float128_lt(b, a);
+}
+
+#endif /* FLOAT128 */
diff --git a/lib/libc/softfloat/gtxf2.c b/lib/libc/softfloat/gtxf2.c
new file mode 100644
index 000000000000..fe8be52e7e2d
--- /dev/null
+++ b/lib/libc/softfloat/gtxf2.c
@@ -0,0 +1,25 @@
+/* $NetBSD: gtxf2.c,v 1.2 2004/09/27 10:16:24 he Exp $ */
+
+/*
+ * Written by Ben Harris, 2000. This file is in the Public Domain.
+ */
+
+#include "softfloat-for-gcc.h"
+#include "milieu.h"
+#include "softfloat.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifdef FLOATX80
+
+flag __gtxf2(floatx80, floatx80);
+
+flag
+__gtxf2(floatx80 a, floatx80 b)
+{
+
+ /* libgcc1.c says a > b */
+ return floatx80_lt(b, a);
+}
+#endif /* FLOATX80 */
diff --git a/lib/libc/softfloat/ledf2.c b/lib/libc/softfloat/ledf2.c
new file mode 100644
index 000000000000..7d3e8fb54855
--- /dev/null
+++ b/lib/libc/softfloat/ledf2.c
@@ -0,0 +1,22 @@
+/* $NetBSD: ledf2.c,v 1.1 2000/06/06 08:15:06 bjh21 Exp $ */
+
+/*
+ * Written by Ben Harris, 2000. This file is in the Public Domain.
+ */
+
+#include "softfloat-for-gcc.h"
+#include "milieu.h"
+#include "softfloat.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+flag __ledf2(float64, float64);
+
+flag
+__ledf2(float64 a, float64 b)
+{
+
+ /* libgcc1.c says 1 - (a <= b) */
+ return 1 - float64_le(a, b);
+}
diff --git a/lib/libc/softfloat/lesf2.c b/lib/libc/softfloat/lesf2.c
new file mode 100644
index 000000000000..6fa13e5e2467
--- /dev/null
+++ b/lib/libc/softfloat/lesf2.c
@@ -0,0 +1,22 @@
+/* $NetBSD: lesf2.c,v 1.1 2000/06/06 08:15:06 bjh21 Exp $ */
+
+/*
+ * Written by Ben Harris, 2000. This file is in the Public Domain.
+ */
+
+#include "softfloat-for-gcc.h"
+#include "milieu.h"
+#include "softfloat.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+flag __lesf2(float32, float32);
+
+flag
+__lesf2(float32 a, float32 b)
+{
+
+ /* libgcc1.c says 1 - (a <= b) */
+ return 1 - float32_le(a, b);
+}
diff --git a/lib/libc/softfloat/letf2.c b/lib/libc/softfloat/letf2.c
new file mode 100644
index 000000000000..e9a18f8d5e5d
--- /dev/null
+++ b/lib/libc/softfloat/letf2.c
@@ -0,0 +1,26 @@
+/* $NetBSD: letf2.c,v 1.1 2011/01/17 10:08:35 matt Exp $ */
+
+/*
+ * Written by Matt Thomas, 2011. This file is in the Public Domain.
+ */
+
+#include "softfloat-for-gcc.h"
+#include "milieu.h"
+#include "softfloat.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifdef FLOAT128
+
+flag __letf2(float128, float128);
+
+flag
+__letf2(float128 a, float128 b)
+{
+
+ /* libgcc1.c says 1 - (a <= b) */
+ return 1 - float128_le(a, b);
+}
+
+#endif /* FLOAT128 */
diff --git a/lib/libc/softfloat/ltdf2.c b/lib/libc/softfloat/ltdf2.c
new file mode 100644
index 000000000000..b8c668ccc01d
--- /dev/null
+++ b/lib/libc/softfloat/ltdf2.c
@@ -0,0 +1,22 @@
+/* $NetBSD: ltdf2.c,v 1.1 2000/06/06 08:15:06 bjh21 Exp $ */
+
+/*
+ * Written by Ben Harris, 2000. This file is in the Public Domain.
+ */
+
+#include "softfloat-for-gcc.h"
+#include "milieu.h"
+#include "softfloat.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+flag __ltdf2(float64, float64);
+
+flag
+__ltdf2(float64 a, float64 b)
+{
+
+ /* libgcc1.c says -(a < b) */
+ return -float64_lt(a, b);
+}
diff --git a/lib/libc/softfloat/ltsf2.c b/lib/libc/softfloat/ltsf2.c
new file mode 100644
index 000000000000..8a1e8fa9e50b
--- /dev/null
+++ b/lib/libc/softfloat/ltsf2.c
@@ -0,0 +1,22 @@
+/* $NetBSD: ltsf2.c,v 1.1 2000/06/06 08:15:06 bjh21 Exp $ */
+
+/*
+ * Written by Ben Harris, 2000. This file is in the Public Domain.
+ */
+
+#include "softfloat-for-gcc.h"
+#include "milieu.h"
+#include "softfloat.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+flag __ltsf2(float32, float32);
+
+flag
+__ltsf2(float32 a, float32 b)
+{
+
+ /* libgcc1.c says -(a < b) */
+ return -float32_lt(a, b);
+}
diff --git a/lib/libc/softfloat/lttf2.c b/lib/libc/softfloat/lttf2.c
new file mode 100644
index 000000000000..13c01b19528d
--- /dev/null
+++ b/lib/libc/softfloat/lttf2.c
@@ -0,0 +1,26 @@
+/* $NetBSD: lttf2.c,v 1.1 2011/01/17 10:08:35 matt Exp $ */
+
+/*
+ * Written by Matt Thomas, 2011. This file is in the Public Domain.
+ */
+
+#include "softfloat-for-gcc.h"
+#include "milieu.h"
+#include "softfloat.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifdef FLOAT128
+
+flag __lttf2(float128, float128);
+
+flag
+__lttf2(float128 a, float128 b)
+{
+
+ /* libgcc1.c says -(a < b) */
+ return -float128_lt(a, b);
+}
+
+#endif /* FLOAT128 */
diff --git a/lib/libc/softfloat/nedf2.c b/lib/libc/softfloat/nedf2.c
new file mode 100644
index 000000000000..61f50443c9c5
--- /dev/null
+++ b/lib/libc/softfloat/nedf2.c
@@ -0,0 +1,22 @@
+/* $NetBSD: nedf2.c,v 1.1 2000/06/06 08:15:07 bjh21 Exp $ */
+
+/*
+ * Written by Ben Harris, 2000. This file is in the Public Domain.
+ */
+
+#include "softfloat-for-gcc.h"
+#include "milieu.h"
+#include "softfloat.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+flag __nedf2(float64, float64);
+
+flag
+__nedf2(float64 a, float64 b)
+{
+
+ /* libgcc1.c says a != b */
+ return !float64_eq(a, b);
+}
diff --git a/lib/libc/softfloat/negdf2.c b/lib/libc/softfloat/negdf2.c
new file mode 100644
index 000000000000..2485d586c475
--- /dev/null
+++ b/lib/libc/softfloat/negdf2.c
@@ -0,0 +1,22 @@
+/* $NetBSD: negdf2.c,v 1.1 2000/06/06 08:15:07 bjh21 Exp $ */
+
+/*
+ * Written by Ben Harris, 2000. This file is in the Public Domain.
+ */
+
+#include "softfloat-for-gcc.h"
+#include "milieu.h"
+#include "softfloat.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+float64 __negdf2(float64);
+
+float64
+__negdf2(float64 a)
+{
+
+ /* libgcc1.c says -a */
+ return a ^ FLOAT64_MANGLE(0x8000000000000000ULL);
+}
diff --git a/lib/libc/softfloat/negsf2.c b/lib/libc/softfloat/negsf2.c
new file mode 100644
index 000000000000..78f6c6bd5f1f
--- /dev/null
+++ b/lib/libc/softfloat/negsf2.c
@@ -0,0 +1,22 @@
+/* $NetBSD: negsf2.c,v 1.1 2000/06/06 08:15:07 bjh21 Exp $ */
+
+/*
+ * Written by Ben Harris, 2000. This file is in the Public Domain.
+ */
+
+#include "softfloat-for-gcc.h"
+#include "milieu.h"
+#include "softfloat.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+float32 __negsf2(float32);
+
+float32
+__negsf2(float32 a)
+{
+
+ /* libgcc1.c says INTIFY(-a) */
+ return a ^ 0x80000000;
+}
diff --git a/lib/libc/softfloat/negtf2.c b/lib/libc/softfloat/negtf2.c
new file mode 100644
index 000000000000..5be582dd8937
--- /dev/null
+++ b/lib/libc/softfloat/negtf2.c
@@ -0,0 +1,27 @@
+/* $NetBSD: negtf2.c,v 1.1 2011/01/17 10:08:35 matt Exp $ */
+
+/*
+ * Written by Matt Thomas, 2011. This file is in the Public Domain.
+ */
+
+#include "softfloat-for-gcc.h"
+#include "milieu.h"
+#include "softfloat.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifdef FLOAT128
+
+float128 __negtf2(float128);
+
+float128
+__negtf2(float128 a)
+{
+
+ /* libgcc1.c says -a */
+ a.high ^= FLOAT64_MANGLE(0x8000000000000000ULL);
+ return a;
+}
+
+#endif /* FLOAT128 */
diff --git a/lib/libc/softfloat/negxf2.c b/lib/libc/softfloat/negxf2.c
new file mode 100644
index 000000000000..0e2d08b25a67
--- /dev/null
+++ b/lib/libc/softfloat/negxf2.c
@@ -0,0 +1,25 @@
+/* $NetBSD: negxf2.c,v 1.2 2004/09/27 10:16:24 he Exp $ */
+
+/*
+ * Written by Ben Harris, 2000. This file is in the Public Domain.
+ */
+
+#include "softfloat-for-gcc.h"
+#include "milieu.h"
+#include "softfloat.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifdef FLOATX80
+
+floatx80 __negxf2(floatx80);
+
+floatx80
+__negxf2(floatx80 a)
+{
+
+ /* libgcc1.c says -a */
+ return __mulxf3(a,__floatsixf(-1));
+}
+#endif /* FLOATX80 */
diff --git a/lib/libc/softfloat/nesf2.c b/lib/libc/softfloat/nesf2.c
new file mode 100644
index 000000000000..b8317cbf8dd8
--- /dev/null
+++ b/lib/libc/softfloat/nesf2.c
@@ -0,0 +1,22 @@
+/* $NetBSD: nesf2.c,v 1.1 2000/06/06 08:15:07 bjh21 Exp $ */
+
+/*
+ * Written by Ben Harris, 2000. This file is in the Public Domain.
+ */
+
+#include "softfloat-for-gcc.h"
+#include "milieu.h"
+#include "softfloat.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+flag __nesf2(float32, float32);
+
+flag
+__nesf2(float32 a, float32 b)
+{
+
+ /* libgcc1.c says a != b */
+ return !float32_eq(a, b);
+}
diff --git a/lib/libc/softfloat/netf2.c b/lib/libc/softfloat/netf2.c
new file mode 100644
index 000000000000..26e17cd1f52d
--- /dev/null
+++ b/lib/libc/softfloat/netf2.c
@@ -0,0 +1,26 @@
+/* $NetBSD: netf2.c,v 1.1 2011/01/17 10:08:35 matt Exp $ */
+
+/*
+ * Written by Matt Thomas, 2011. This file is in the Public Domain.
+ */
+
+#include "softfloat-for-gcc.h"
+#include "milieu.h"
+#include "softfloat.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifdef FLOAT128
+
+flag __netf2(float128, float128);
+
+flag
+__netf2(float128 a, float128 b)
+{
+
+ /* libgcc1.c says a != b */
+ return !float128_eq(a, b);
+}
+
+#endif /* FLOAT128 */
diff --git a/lib/libc/softfloat/nexf2.c b/lib/libc/softfloat/nexf2.c
new file mode 100644
index 000000000000..153a70392d16
--- /dev/null
+++ b/lib/libc/softfloat/nexf2.c
@@ -0,0 +1,25 @@
+/* $NetBSD: nexf2.c,v 1.2 2004/09/27 10:16:24 he Exp $ */
+
+/*
+ * Written by Ben Harris, 2000. This file is in the Public Domain.
+ */
+
+#include "softfloat-for-gcc.h"
+#include "milieu.h"
+#include "softfloat.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifdef FLOATX80
+
+flag __nexf2(floatx80, floatx80);
+
+flag
+__nexf2(floatx80 a, floatx80 b)
+{
+
+ /* libgcc1.c says a != b */
+ return !floatx80_eq(a, b);
+}
+#endif /* FLOATX80 */
diff --git a/lib/libc/softfloat/softfloat-for-gcc.h b/lib/libc/softfloat/softfloat-for-gcc.h
new file mode 100644
index 000000000000..cf17e56768a9
--- /dev/null
+++ b/lib/libc/softfloat/softfloat-for-gcc.h
@@ -0,0 +1,169 @@
+/* $NetBSD: softfloat-for-gcc.h,v 1.8 2009/12/14 01:07:42 matt Exp $ */
+/* $FreeBSD$ */
+
+/*
+ * Move private identifiers with external linkage into implementation
+ * namespace. -- Klaus Klein <kleink@NetBSD.org>, May 5, 1999
+ */
+#define float_exception_flags __softfloat_float_exception_flags
+#define float_exception_mask __softfloat_float_exception_mask
+#define float_rounding_mode __softfloat_float_rounding_mode
+#define float_raise __softfloat_float_raise
+/* The following batch are called by GCC through wrappers */
+#define float32_eq __softfloat_float32_eq
+#define float32_le __softfloat_float32_le
+#define float32_lt __softfloat_float32_lt
+#define float64_eq __softfloat_float64_eq
+#define float64_le __softfloat_float64_le
+#define float64_lt __softfloat_float64_lt
+#define float128_eq __softfloat_float128_eq
+#define float128_le __softfloat_float128_le
+#define float128_lt __softfloat_float128_lt
+
+/*
+ * Macros to define functions with the GCC expected names
+ */
+
+#define float32_add __addsf3
+#define float64_add __adddf3
+#define floatx80_add __addxf3
+#define float128_add __addtf3
+
+#define float32_sub __subsf3
+#define float64_sub __subdf3
+#define floatx80_sub __subxf3
+#define float128_sub __subtf3
+
+#define float32_mul __mulsf3
+#define float64_mul __muldf3
+#define floatx80_mul __mulxf3
+#define float128_mul __multf3
+
+#define float32_div __divsf3
+#define float64_div __divdf3
+#define floatx80_div __divxf3
+#define float128_div __divtf3
+
+#if 0
+#define float32_neg __negsf2
+#define float64_neg __negdf2
+#define floatx80_neg __negxf2
+#define float128_neg __negtf2
+#endif
+
+#define int32_to_float32 __floatsisf
+#define int32_to_float64 __floatsidf
+#define int32_to_floatx80 __floatsixf
+#define int32_to_float128 __floatsitf
+
+#define int64_to_float32 __floatdisf
+#define int64_to_float64 __floatdidf
+#define int64_to_floatx80 __floatdixf
+#define int64_to_float128 __floatditf
+
+#define int128_to_float32 __floattisf
+#define int128_to_float64 __floattidf
+#define int128_to_floatx80 __floattixf
+#define int128_to_float128 __floattitf
+
+#define uint32_to_float32 __floatunsisf
+#define uint32_to_float64 __floatunsidf
+#define uint32_to_floatx80 __floatunsixf
+#define uint32_to_float128 __floatunsitf
+
+#define uint64_to_float32 __floatundisf
+#define uint64_to_float64 __floatundidf
+#define uint64_to_floatx80 __floatundixf
+#define uint64_to_float128 __floatunditf
+
+#define uint128_to_float32 __floatuntisf
+#define uint128_to_float64 __floatuntidf
+#define uint128_to_floatx80 __floatuntixf
+#define uint128_to_float128 __floatuntitf
+
+#define float32_to_int32_round_to_zero __fixsfsi
+#define float64_to_int32_round_to_zero __fixdfsi
+#define floatx80_to_int32_round_to_zero __fixxfsi
+#define float128_to_int32_round_to_zero __fixtfsi
+
+#define float32_to_int64_round_to_zero __fixsfdi
+#define float64_to_int64_round_to_zero __fixdfdi
+#define floatx80_to_int64_round_to_zero __fixxfdi
+#define float128_to_int64_round_to_zero __fixtfdi
+
+#define float32_to_int128_round_to_zero __fixsfti
+#define float64_to_int128_round_to_zero __fixdfti
+#define floatx80_to_int128_round_to_zero __fixxfti
+#define float128_to_int128_round_to_zero __fixtfti
+
+#define float32_to_uint32_round_to_zero __fixunssfsi
+#define float64_to_uint32_round_to_zero __fixunsdfsi
+#define floatx80_to_uint32_round_to_zero __fixunsxfsi
+#define float128_to_uint32_round_to_zero __fixunstfsi
+
+#define float32_to_uint64_round_to_zero __fixunssfdi
+#define float64_to_uint64_round_to_zero __fixunsdfdi
+#define floatx80_to_uint64_round_to_zero __fixunsxfdi
+#define float128_to_uint64_round_to_zero __fixunstfdi
+
+#define float32_to_uint128_round_to_zero __fixunssfti
+#define float64_to_uint128_round_to_zero __fixunsdfti
+#define floatx80_to_uint128_round_to_zero __fixunsxfti
+#define float128_to_uint128_round_to_zero __fixunstfti
+
+#define float32_to_float64 __extendsfdf2
+#define float32_to_floatx80 __extendsfxf2
+#define float32_to_float128 __extendsftf2
+#define float64_to_floatx80 __extenddfxf2
+#define float64_to_float128 __extenddftf2
+
+#define float128_to_float64 __trunctfdf2
+#define floatx80_to_float64 __truncxfdf2
+#define float128_to_float32 __trunctfsf2
+#define floatx80_to_float32 __truncxfsf2
+#define float64_to_float32 __truncdfsf2
+
+#if 0
+#define float32_cmp __cmpsf2
+#define float32_unord __unordsf2
+#define float32_eq __eqsf2
+#define float32_ne __nesf2
+#define float32_ge __gesf2
+#define float32_lt __ltsf2
+#define float32_le __lesf2
+#define float32_gt __gtsf2
+#endif
+
+#if 0
+#define float64_cmp __cmpdf2
+#define float64_unord __unorddf2
+#define float64_eq __eqdf2
+#define float64_ne __nedf2
+#define float64_ge __gedf2
+#define float64_lt __ltdf2
+#define float64_le __ledf2
+#define float64_gt __gtdf2
+#endif
+
+/* XXX not in libgcc */
+#if 1
+#define floatx80_cmp __cmpxf2
+#define floatx80_unord __unordxf2
+#define floatx80_eq __eqxf2
+#define floatx80_ne __nexf2
+#define floatx80_ge __gexf2
+#define floatx80_lt __ltxf2
+#define floatx80_le __lexf2
+#define floatx80_gt __gtxf2
+#endif
+
+#if 0
+#define float128_cmp __cmptf2
+#define float128_unord __unordtf2
+#define float128_eq __eqtf2
+#define float128_ne __netf2
+#define float128_ge __getf2
+#define float128_lt __lttf2
+#define float128_le __letf2
+#define float128_gt __gttf2
+#endif
diff --git a/lib/libc/softfloat/softfloat-history.txt b/lib/libc/softfloat/softfloat-history.txt
new file mode 100644
index 000000000000..d8c98db56ed4
--- /dev/null
+++ b/lib/libc/softfloat/softfloat-history.txt
@@ -0,0 +1,53 @@
+$NetBSD: softfloat-history.txt,v 1.1 2000/06/06 08:15:08 bjh21 Exp $
+$FreeBSD$
+
+History of Major Changes to SoftFloat, up to Release 2a
+
+John R. Hauser
+1998 December 16
+
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Release 2a (1998 December)
+
+-- Added functions to convert between 64-bit integers (int64) and all
+ supported floating-point formats.
+
+-- Fixed a bug in all 64-bit-version square root functions except
+ `float32_sqrt' that caused the result sometimes to be off by 1 unit in
+ the last place (1 ulp) from what it should be. (Bug discovered by Paul
+ Donahue.)
+
+-- Improved the makefiles.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Release 2 (1997 June)
+
+-- Created the 64-bit (bits64) version, adding the floatx80 and float128
+ formats.
+
+-- Changed the source directory structure, splitting the sources into a
+ `bits32' and a `bits64' version. Renamed `environment.h' to `milieu.h'
+ (to avoid confusion with environment variables).
+
+-- Fixed a small error that caused `float64_round_to_int' often to round the
+ wrong way in nearest/even mode when the operand was between 2^20 and 2^21
+ and halfway between two integers.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Release 1a (1996 July)
+
+-- Corrected a mistake that caused borderline underflow cases not to raise
+ the underflow flag when they should have. (Problem reported by Doug
+ Priest.)
+
+-- Added the `float_detect_tininess' variable to control whether tininess is
+ detected before or after rounding.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Release 1 (1996 July)
+
+-- Original release.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
diff --git a/lib/libc/softfloat/softfloat-source.txt b/lib/libc/softfloat/softfloat-source.txt
new file mode 100644
index 000000000000..2a15f2add95b
--- /dev/null
+++ b/lib/libc/softfloat/softfloat-source.txt
@@ -0,0 +1,384 @@
+$NetBSD: softfloat-source.txt,v 1.2 2006/11/24 19:46:58 christos Exp $
+$FreeBSD$
+
+SoftFloat Release 2a Source Documentation
+
+John R. Hauser
+1998 December 14
+
+
+-------------------------------------------------------------------------------
+Introduction
+
+SoftFloat is a software implementation of floating-point that conforms to
+the IEC/IEEE Standard for Binary Floating-Point Arithmetic. SoftFloat can
+support four floating-point formats: single precision, double precision,
+extended double precision, and quadruple precision. All operations required
+by the IEEE Standard are implemented, except for conversions to and from
+decimal. SoftFloat is distributed in the form of C source code, so a
+C compiler is needed to compile the code. Support for the extended double-
+precision and quadruple-precision formats is dependent on the C compiler
+implementing a 64-bit integer type.
+
+This document gives information needed for compiling and/or porting
+SoftFloat.
+
+The source code for SoftFloat is intended to be relatively machine-
+independent and should be compilable using any ISO/ANSI C compiler. At the
+time of this writing, SoftFloat has been successfully compiled with the GNU
+C Compiler (`gcc') for several platforms.
+
+
+-------------------------------------------------------------------------------
+Limitations
+
+SoftFloat as written requires an ISO/ANSI-style C compiler. No attempt has
+been made to accommodate compilers that are not ISO-conformant. Older ``K&R-
+style'' compilers are not adequate for compiling SoftFloat. All testing I
+have done so far has been with the GNU C Compiler. Compilation with other
+compilers should be possible but has not been tested.
+
+The SoftFloat sources assume that source code file names can be longer than
+8 characters. In order to compile under an MS-DOS-type system, many of the
+source files will need to be renamed, and the source and makefiles edited
+appropriately. Once compiled, the SoftFloat binary does not depend on the
+existence of long file names.
+
+The underlying machine is assumed to be binary with a word size that is a
+power of 2. Bytes are 8 bits. Support for the extended double-precision
+and quadruple-precision formats depends on the C compiler implementing
+a 64-bit integer type. If the largest integer type supported by the
+C compiler is 32 bits, SoftFloat is limited to the single- and double-
+precision formats.
+
+
+-------------------------------------------------------------------------------
+Contents
+
+ Introduction
+ Limitations
+ Contents
+ Legal Notice
+ SoftFloat Source Directory Structure
+ SoftFloat Source Files
+ processors/*.h
+ softfloat/bits*/*/softfloat.h
+ softfloat/bits*/*/milieu.h
+ softfloat/bits*/*/softfloat-specialize
+ softfloat/bits*/softfloat-macros
+ softfloat/bits*/softfloat.c
+ Steps to Creating a `softfloat.o'
+ Making `softfloat.o' a Library
+ Testing SoftFloat
+ Timing SoftFloat
+ Compiler Options and Efficiency
+ Processor-Specific Optimization of `softfloat.c' Using `softfloat-macros'
+ Contact Information
+
+
+
+-------------------------------------------------------------------------------
+Legal Notice
+
+SoftFloat was written by John R. Hauser. This work was made possible in
+part by the International Computer Science Institute, located at Suite 600,
+1947 Center Street, Berkeley, California 94704. Funding was partially
+provided by the National Science Foundation under grant MIP-9311980. The
+original version of this code was written as part of a project to build
+a fixed-point vector processor in collaboration with the University of
+California at Berkeley, overseen by Profs. Nelson Morgan and John Wawrzynek.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
+has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
+TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
+PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
+AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
+
+
+-------------------------------------------------------------------------------
+SoftFloat Source Directory Structure
+
+Because SoftFloat is targeted to multiple platforms, its source code
+is slightly scattered between target-specific and target-independent
+directories and files. The directory structure is as follows:
+
+ processors
+ softfloat
+ bits64
+ templates
+ 386-Win32-gcc
+ SPARC-Solaris-gcc
+ bits32
+ templates
+ 386-Win32-gcc
+ SPARC-Solaris-gcc
+
+The two topmost directories and their contents are:
+
+ softfloat - Most of the source code needed for SoftFloat.
+ processors - Target-specific header files that are not specific to
+ SoftFloat.
+
+The `softfloat' directory is further split into two parts:
+
+ bits64 - SoftFloat implementation using 64-bit integers.
+ bits32 - SoftFloat implementation using only 32-bit integers.
+
+Within these directories are subdirectories for each of the targeted
+platforms. The SoftFloat source code is distributed with targets
+`386-Win32-gcc' and `SPARC-Solaris-gcc' (and perhaps others) already
+prepared for both the 32-bit and 64-bit implementations. Source files that
+are not within these target-specific subdirectories are intended to be
+target-independent.
+
+The naming convention used for the target-specific directories is
+`<processor>-<executable-type>-<compiler>'. The names of the supplied
+target directories should be interpreted as follows:
+
+ <processor>:
+ 386 - Intel 386-compatible processor.
+ SPARC - SPARC processor (as used by Sun machines).
+ <executable-type>:
+ Win32 - Microsoft Win32 executable.
+ Solaris - Sun Solaris executable.
+ <compiler>:
+ gcc - GNU C Compiler.
+
+You do not need to maintain this convention if you do not want to.
+
+Alongside the supplied target-specific directories is a `templates'
+directory containing a set of ``generic'' target-specific source files. A
+new target directory can be created by copying the `templates' directory and
+editing the files inside. (Complete instructions for porting SoftFloat to a
+new target are in the section _Steps_to_Creating_a_`softfloat.o'_.) Note
+that the `templates' directory will not work as a target directory without
+some editing. To avoid confusion, it would be wise to refrain from editing
+the files inside `templates' directly.
+
+
+-------------------------------------------------------------------------------
+SoftFloat Source Files
+
+The purpose of each source file is described below. In the following,
+the `*' symbol is used in place of the name of a specific target, such as
+`386-Win32-gcc' or `SPARC-Solaris-gcc', or in place of some other text, as
+in `bits*' for either `bits32' or `bits64'.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+processors/*.h
+
+The target-specific `processors' header file defines integer types
+of various sizes, and also defines certain C preprocessor macros that
+characterize the target. The two examples supplied are `386-gcc.h' and
+`SPARC-gcc.h'. The naming convention used for processor header files is
+`<processor>-<compiler>.h'.
+
+If 64-bit integers are supported by the compiler, the macro name `BITS64'
+should be defined here along with the corresponding 64-bit integer
+types. In addition, the function-like macro `LIT64' must be defined for
+constructing 64-bit integer literals (constants). The `LIT64' macro is used
+consistently in the SoftFloat code to annotate 64-bit literals.
+
+If `BITS64' is not defined, only the 32-bit version of SoftFloat can be
+compiled. If `BITS64' _is_ defined, either can be compiled.
+
+If an inlining attribute (such as an `inline' keyword) is provided by the
+compiler, the macro `INLINE' should be defined to the appropriate keyword.
+If not, `INLINE' can be set to the keyword `static'. The `INLINE' macro
+appears in the SoftFloat source code before every function that should
+be inlined by the compiler. SoftFloat depends on inlining to obtain
+good speed. Even if inlining cannot be forced with a language keyword,
+the compiler may still be able to perform inlining on its own as an
+optimization. If a command-line option is needed to convince the compiler
+to perform this optimization, this should be assured in the makefile. (See
+the section _Compiler_Options_and_Efficiency_ below.)
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+softfloat/bits*/*/softfloat.h
+
+The target-specific `softfloat.h' header file defines the SoftFloat
+interface as seen by clients.
+
+Unlike the actual function definitions in `softfloat.c', the declarations
+in `softfloat.h' do not use any of the types defined by the `processors'
+header file. This is done so that clients will not have to include the
+`processors' header file in order to use SoftFloat. Nevertheless, the
+target-specific declarations in `softfloat.h' must match what `softfloat.c'
+expects. For example, if `int32' is defined as `int' in the `processors'
+header file, then in `softfloat.h' the output of `float32_to_int32' should
+be stated as `int', although in `softfloat.c' it is given in target-
+independent form as `int32'.
+
+For the `bits64' implementation of SoftFloat, the macro names `FLOATX80' and
+`FLOAT128' must be defined in order for the extended double-precision and
+quadruple-precision formats to be enabled in the code. Conversely, either
+or both of the extended formats can be disabled by simply removing the
+`#define' of the respective macro. When an extended format is not enabled,
+none of the functions that either input or output the format are defined,
+and no space is taken up in `softfloat.o' by such functions. There is no
+provision for disabling the usual single- and double-precision formats.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+softfloat/bits*/*/milieu.h
+
+The target-specific `milieu.h' header file provides declarations that are
+needed to compile SoftFloat. In addition, deviations from ISO/ANSI C by
+the compiler (such as names not properly declared in system header files)
+are corrected in this header if possible.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+softfloat/bits*/*/softfloat-specialize
+
+This target-specific C source fragment defines:
+
+-- whether tininess for underflow is detected before or after rounding by
+ default;
+-- what (if anything) special happens when exceptions are raised;
+-- how signaling NaNs are distinguished from quiet NaNs;
+-- the default generated quiet NaNs; and
+-- how NaNs are propagated from function inputs to output.
+
+These details are not decided by the IEC/IEEE Standard. This fragment is
+included verbatim within `softfloat.c' when SoftFloat is compiled.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+softfloat/bits*/softfloat-macros
+
+This target-independent C source fragment defines a number of arithmetic
+functions used as primitives within the `softfloat.c' source. Most of the
+functions defined here are intended to be inlined for efficiency. This
+fragment is included verbatim within `softfloat.c' when SoftFloat is
+compiled.
+
+Target-specific variations on this file are possible. See the section
+_Processor-Specific_Optimization_of_`softfloat.c'_Using_`softfloat-macros'_
+below.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+softfloat/bits*/softfloat.c
+
+The target-independent `softfloat.c' source file contains the body of the
+SoftFloat implementation.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+The inclusion of the files above within each other (using `#include') can be
+shown graphically as follows:
+
+ softfloat/bits*/softfloat.c
+ softfloat/bits*/*/milieu.h
+ processors/*.h
+ softfloat/bits*/*/softfloat.h
+ softfloat/bits*/*/softfloat-specialize
+ softfloat/bits*/softfloat-macros
+
+Note in particular that `softfloat.c' does not include the `processors'
+header file directly. Rather, `softfloat.c' includes the target-specific
+`milieu.h' header file, which in turn includes the processor header file.
+
+
+-------------------------------------------------------------------------------
+Steps to Creating a `softfloat.o'
+
+Porting and/or compiling SoftFloat involves the following steps:
+
+1. If one does not already exist, create an appropriate `.h' file in the
+ `processors' directory.
+
+2. If `BITS64' is defined in the `processors' header file, choose whether
+ to compile the 32-bit or 64-bit implementation of SoftFloat. If
+ `BITS64' is not defined, your only choice is the 32-bit implementation.
+ The remaining steps occur within either the `bits32' or `bits64'
+ subdirectories.
+
+3. If one does not already exist, create an appropriate target-specific
+ subdirectory by copying the given `templates' directory.
+
+4. In the target-specific subdirectory, edit the files `softfloat-specialize'
+ and `softfloat.h' to define the desired exception handling functions
+ and mode control values. In the `softfloat.h' header file, ensure also
+ that all declarations give the proper target-specific type (such as
+ `int' or `long') corresponding to the target-independent type used in
+ `softfloat.c' (such as `int32'). None of the type names declared in the
+ `processors' header file should appear in `softfloat.h'.
+
+5. In the target-specific subdirectory, edit the files `milieu.h' and
+ `Makefile' to reflect the current environment.
+
+6. In the target-specific subdirectory, execute `make'.
+
+For the targets that are supplied, if the expected compiler is available
+(usually `gcc'), it should only be necessary to execute `make' in the
+target-specific subdirectory.
+
+
+-------------------------------------------------------------------------------
+Making `softfloat.o' a Library
+
+SoftFloat is not made into a software library by the supplied makefile.
+If desired, `softfloat.o' can easily be put into its own library (in Unix,
+`softfloat.a') using the usual system tool (in Unix, `ar').
+
+
+-------------------------------------------------------------------------------
+Testing SoftFloat
+
+SoftFloat can be tested using the `testsoftfloat' program by the same
+author. The `testsoftfloat' program is part of the TestFloat package
+available at the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/arithmetic/
+TestFloat.html'.
+
+
+-------------------------------------------------------------------------------
+Timing SoftFloat
+
+A program called `timesoftfloat' for timing the SoftFloat functions is
+included with the SoftFloat source code. Compiling `timesoftfloat' should
+pose no difficulties once `softfloat.o' exists. The supplied makefile
+will create a `timesoftfloat' executable by default after generating
+`softfloat.o'. See `timesoftfloat.txt' for documentation about using
+`timesoftfloat'.
+
+
+-------------------------------------------------------------------------------
+Compiler Options and Efficiency
+
+In order to get good speed with SoftFloat, it is important that the compiler
+inline the routines that have been marked `INLINE' in the code. Even if
+inlining cannot be forced by an appropriate definition of the `INLINE'
+macro, the compiler may still be able to perform inlining on its own as
+an optimization. In that case, the makefile should be edited to give the
+compiler whatever option is required to cause it to inline small functions.
+
+The ability of the processor to do fast shifts has been assumed. Efficiency
+will not be as good on processors for which this is not the case (such as
+the original Motorola 68000 or Intel 8086 processors).
+
+
+-------------------------------------------------------------------------------
+Processor-Specific Optimization of `softfloat.c' Using `softfloat-macros'
+
+The `softfloat-macros' source fragment defines arithmetic functions used
+as primitives by `softfloat.c'. This file has been written in a target-
+independent form. For a given target, it may be possible to improve on
+these functions using target-specific and/or non-ISO-C features (such
+as `asm' statements). For example, one of the ``macro'' functions takes
+two word-size integers and returns their full product in two words.
+This operation can be done directly in hardware on many processors; but
+because it is not available through standard C, the function defined in
+`softfloat-macros' uses four multiplies to achieve the same result.
+
+To address these shortcomings, a customized version of `softfloat-macros'
+can be created in any of the target-specific subdirectories. A simple
+modification to the target's makefile should be sufficient to ensure that
+the custom version is used instead of the generic one.
+
+
+-------------------------------------------------------------------------------
+Contact Information
+
+At the time of this writing, the most up-to-date information about
+SoftFloat and the latest release can be found at the Web page `http://
+HTTP.CS.Berkeley.EDU/~jhauser/arithmetic/SoftFloat.html'.
+
+
diff --git a/lib/libc/softfloat/softfloat-specialize b/lib/libc/softfloat/softfloat-specialize
new file mode 100644
index 000000000000..b5eb8c34cdc8
--- /dev/null
+++ b/lib/libc/softfloat/softfloat-specialize
@@ -0,0 +1,521 @@
+/* $NetBSD: softfloat-specialize,v 1.6 2011/03/06 10:27:37 martin Exp $ */
+/* $FreeBSD$ */
+
+/* This is a derivative work. */
+
+/*
+===============================================================================
+
+This C source fragment is part of the SoftFloat IEC/IEEE Floating-point
+Arithmetic Package, Release 2a.
+
+Written by John R. Hauser. This work was made possible in part by the
+International Computer Science Institute, located at Suite 600, 1947 Center
+Street, Berkeley, California 94704. Funding was partially provided by the
+National Science Foundation under grant MIP-9311980. The original version
+of this code was written as part of a project to build a fixed-point vector
+processor in collaboration with the University of California at Berkeley,
+overseen by Profs. Nelson Morgan and John Wawrzynek. More information
+is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
+arithmetic/SoftFloat.html'.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
+has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
+TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
+PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
+AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
+
+Derivative works are acceptable, even for commercial purposes, so long as
+(1) they include prominent notice that the work is derivative, and (2) they
+include prominent notice akin to these four paragraphs for those parts of
+this code that are retained.
+
+===============================================================================
+*/
+
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+
+/*
+-------------------------------------------------------------------------------
+Underflow tininess-detection mode, statically initialized to default value.
+(The declaration in `softfloat.h' must match the `int8' type here.)
+-------------------------------------------------------------------------------
+*/
+#ifdef SOFTFLOAT_FOR_GCC
+static
+#endif
+#ifdef __sparc64__
+int8 float_detect_tininess = float_tininess_before_rounding;
+#else
+int8 float_detect_tininess = float_tininess_after_rounding;
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Raises the exceptions specified by `flags'. Floating-point traps can be
+defined here if desired. It is currently not possible for such a trap to
+substitute a result value. If traps are not implemented, this routine
+should be simply `float_exception_flags |= flags;'.
+-------------------------------------------------------------------------------
+*/
+#ifdef SOFTFLOAT_FOR_GCC
+#define float_exception_mask __softfloat_float_exception_mask
+#endif
+int float_exception_mask = 0;
+void float_raise( int flags )
+{
+
+ float_exception_flags |= flags;
+
+ if ( flags & float_exception_mask ) {
+#if 0
+ siginfo_t info;
+ memset(&info, 0, sizeof info);
+ info.si_signo = SIGFPE;
+ info.si_pid = getpid();
+ info.si_uid = geteuid();
+ if (flags & float_flag_underflow)
+ info.si_code = FPE_FLTUND;
+ else if (flags & float_flag_overflow)
+ info.si_code = FPE_FLTOVF;
+ else if (flags & float_flag_divbyzero)
+ info.si_code = FPE_FLTDIV;
+ else if (flags & float_flag_invalid)
+ info.si_code = FPE_FLTINV;
+ else if (flags & float_flag_inexact)
+ info.si_code = FPE_FLTRES;
+ sigqueueinfo(getpid(), &info);
+#else
+ raise( SIGFPE );
+#endif
+ }
+}
+#undef float_exception_mask
+
+/*
+-------------------------------------------------------------------------------
+Internal canonical NaN format.
+-------------------------------------------------------------------------------
+*/
+typedef struct {
+ flag sign;
+ bits64 high, low;
+} commonNaNT;
+
+/*
+-------------------------------------------------------------------------------
+The pattern for a default generated single-precision NaN.
+-------------------------------------------------------------------------------
+*/
+#define float32_default_nan 0xFFFFFFFF
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the single-precision floating-point value `a' is a NaN;
+otherwise returns 0.
+-------------------------------------------------------------------------------
+*/
+#ifdef SOFTFLOAT_FOR_GCC
+static
+#endif
+flag float32_is_nan( float32 a )
+{
+
+ return ( 0xFF000000 < (bits32) ( a<<1 ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the single-precision floating-point value `a' is a signaling
+NaN; otherwise returns 0.
+-------------------------------------------------------------------------------
+*/
+#if defined(SOFTFLOAT_FOR_GCC) && !defined(SOFTFLOATSPARC64_FOR_GCC) && \
+ !defined(SOFTFLOAT_M68K_FOR_GCC)
+static
+#endif
+flag float32_is_signaling_nan( float32 a )
+{
+
+ return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the single-precision floating-point NaN
+`a' to the canonical NaN format. If `a' is a signaling NaN, the invalid
+exception is raised.
+-------------------------------------------------------------------------------
+*/
+static commonNaNT float32ToCommonNaN( float32 a )
+{
+ commonNaNT z;
+
+ if ( float32_is_signaling_nan( a ) ) float_raise( float_flag_invalid );
+ z.sign = a>>31;
+ z.low = 0;
+ z.high = ( (bits64) a )<<41;
+ return z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the canonical NaN `a' to the single-
+precision floating-point format.
+-------------------------------------------------------------------------------
+*/
+static float32 commonNaNToFloat32( commonNaNT a )
+{
+
+ return ( ( (bits32) a.sign )<<31 ) | 0x7FC00000 | ( a.high>>41 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Takes two single-precision floating-point values `a' and `b', one of which
+is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a
+signaling NaN, the invalid exception is raised.
+-------------------------------------------------------------------------------
+*/
+static float32 propagateFloat32NaN( float32 a, float32 b )
+{
+ flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
+
+ aIsNaN = float32_is_nan( a );
+ aIsSignalingNaN = float32_is_signaling_nan( a );
+ bIsNaN = float32_is_nan( b );
+ bIsSignalingNaN = float32_is_signaling_nan( b );
+ a |= 0x00400000;
+ b |= 0x00400000;
+ if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid );
+ if ( aIsNaN ) {
+ return ( aIsSignalingNaN & bIsNaN ) ? b : a;
+ }
+ else {
+ return b;
+ }
+
+}
+
+/*
+-------------------------------------------------------------------------------
+The pattern for a default generated double-precision NaN.
+-------------------------------------------------------------------------------
+*/
+#define float64_default_nan LIT64( 0xFFFFFFFFFFFFFFFF )
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the double-precision floating-point value `a' is a NaN;
+otherwise returns 0.
+-------------------------------------------------------------------------------
+*/
+#ifdef SOFTFLOAT_FOR_GCC
+static
+#endif
+flag float64_is_nan( float64 a )
+{
+
+ return ( LIT64( 0xFFE0000000000000 ) <
+ (bits64) ( FLOAT64_DEMANGLE(a)<<1 ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the double-precision floating-point value `a' is a signaling
+NaN; otherwise returns 0.
+-------------------------------------------------------------------------------
+*/
+#if defined(SOFTFLOAT_FOR_GCC) && !defined(SOFTFLOATSPARC64_FOR_GCC) && \
+ !defined(SOFTFLOATM68K_FOR_GCC)
+static
+#endif
+flag float64_is_signaling_nan( float64 a )
+{
+
+ return
+ ( ( ( FLOAT64_DEMANGLE(a)>>51 ) & 0xFFF ) == 0xFFE )
+ && ( FLOAT64_DEMANGLE(a) & LIT64( 0x0007FFFFFFFFFFFF ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the double-precision floating-point NaN
+`a' to the canonical NaN format. If `a' is a signaling NaN, the invalid
+exception is raised.
+-------------------------------------------------------------------------------
+*/
+static commonNaNT float64ToCommonNaN( float64 a )
+{
+ commonNaNT z;
+
+ if ( float64_is_signaling_nan( a ) ) float_raise( float_flag_invalid );
+ z.sign = FLOAT64_DEMANGLE(a)>>63;
+ z.low = 0;
+ z.high = FLOAT64_DEMANGLE(a)<<12;
+ return z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the canonical NaN `a' to the double-
+precision floating-point format.
+-------------------------------------------------------------------------------
+*/
+static float64 commonNaNToFloat64( commonNaNT a )
+{
+
+ return FLOAT64_MANGLE(
+ ( ( (bits64) a.sign )<<63 )
+ | LIT64( 0x7FF8000000000000 )
+ | ( a.high>>12 ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Takes two double-precision floating-point values `a' and `b', one of which
+is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a
+signaling NaN, the invalid exception is raised.
+-------------------------------------------------------------------------------
+*/
+static float64 propagateFloat64NaN( float64 a, float64 b )
+{
+ flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
+
+ aIsNaN = float64_is_nan( a );
+ aIsSignalingNaN = float64_is_signaling_nan( a );
+ bIsNaN = float64_is_nan( b );
+ bIsSignalingNaN = float64_is_signaling_nan( b );
+ a |= FLOAT64_MANGLE(LIT64( 0x0008000000000000 ));
+ b |= FLOAT64_MANGLE(LIT64( 0x0008000000000000 ));
+ if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid );
+ if ( aIsNaN ) {
+ return ( aIsSignalingNaN & bIsNaN ) ? b : a;
+ }
+ else {
+ return b;
+ }
+
+}
+
+#ifdef FLOATX80
+
+/*
+-------------------------------------------------------------------------------
+The pattern for a default generated extended double-precision NaN. The
+`high' and `low' values hold the most- and least-significant bits,
+respectively.
+-------------------------------------------------------------------------------
+*/
+#define floatx80_default_nan_high 0xFFFF
+#define floatx80_default_nan_low LIT64( 0xFFFFFFFFFFFFFFFF )
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the extended double-precision floating-point value `a' is a
+NaN; otherwise returns 0.
+-------------------------------------------------------------------------------
+*/
+flag floatx80_is_nan( floatx80 a )
+{
+
+ return ( ( a.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( a.low<<1 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the extended double-precision floating-point value `a' is a
+signaling NaN; otherwise returns 0.
+-------------------------------------------------------------------------------
+*/
+flag floatx80_is_signaling_nan( floatx80 a )
+{
+ bits64 aLow;
+
+ aLow = a.low & ~ LIT64( 0x4000000000000000 );
+ return
+ ( ( a.high & 0x7FFF ) == 0x7FFF )
+ && (bits64) ( aLow<<1 )
+ && ( a.low == aLow );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the extended double-precision floating-
+point NaN `a' to the canonical NaN format. If `a' is a signaling NaN, the
+invalid exception is raised.
+-------------------------------------------------------------------------------
+*/
+static commonNaNT floatx80ToCommonNaN( floatx80 a )
+{
+ commonNaNT z;
+
+ if ( floatx80_is_signaling_nan( a ) ) float_raise( float_flag_invalid );
+ z.sign = a.high>>15;
+ z.low = 0;
+ z.high = a.low<<1;
+ return z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the canonical NaN `a' to the extended
+double-precision floating-point format.
+-------------------------------------------------------------------------------
+*/
+static floatx80 commonNaNToFloatx80( commonNaNT a )
+{
+ floatx80 z;
+
+ z.low = LIT64( 0xC000000000000000 ) | ( a.high>>1 );
+ z.high = ( ( (bits16) a.sign )<<15 ) | 0x7FFF;
+ return z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Takes two extended double-precision floating-point values `a' and `b', one
+of which is a NaN, and returns the appropriate NaN result. If either `a' or
+`b' is a signaling NaN, the invalid exception is raised.
+-------------------------------------------------------------------------------
+*/
+static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b )
+{
+ flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
+
+ aIsNaN = floatx80_is_nan( a );
+ aIsSignalingNaN = floatx80_is_signaling_nan( a );
+ bIsNaN = floatx80_is_nan( b );
+ bIsSignalingNaN = floatx80_is_signaling_nan( b );
+ a.low |= LIT64( 0xC000000000000000 );
+ b.low |= LIT64( 0xC000000000000000 );
+ if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid );
+ if ( aIsNaN ) {
+ return ( aIsSignalingNaN & bIsNaN ) ? b : a;
+ }
+ else {
+ return b;
+ }
+
+}
+
+#endif
+
+#ifdef FLOAT128
+
+/*
+-------------------------------------------------------------------------------
+The pattern for a default generated quadruple-precision NaN. The `high' and
+`low' values hold the most- and least-significant bits, respectively.
+-------------------------------------------------------------------------------
+*/
+#define float128_default_nan_high LIT64( 0xFFFFFFFFFFFFFFFF )
+#define float128_default_nan_low LIT64( 0xFFFFFFFFFFFFFFFF )
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the quadruple-precision floating-point value `a' is a NaN;
+otherwise returns 0.
+-------------------------------------------------------------------------------
+*/
+flag float128_is_nan( float128 a )
+{
+
+ return
+ ( LIT64( 0xFFFE000000000000 ) <= (bits64) ( a.high<<1 ) )
+ && ( a.low || ( a.high & LIT64( 0x0000FFFFFFFFFFFF ) ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the quadruple-precision floating-point value `a' is a
+signaling NaN; otherwise returns 0.
+-------------------------------------------------------------------------------
+*/
+flag float128_is_signaling_nan( float128 a )
+{
+
+ return
+ ( ( ( a.high>>47 ) & 0xFFFF ) == 0xFFFE )
+ && ( a.low || ( a.high & LIT64( 0x00007FFFFFFFFFFF ) ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the quadruple-precision floating-point NaN
+`a' to the canonical NaN format. If `a' is a signaling NaN, the invalid
+exception is raised.
+-------------------------------------------------------------------------------
+*/
+static commonNaNT float128ToCommonNaN( float128 a )
+{
+ commonNaNT z;
+
+ if ( float128_is_signaling_nan( a ) ) float_raise( float_flag_invalid );
+ z.sign = a.high>>63;
+ shortShift128Left( a.high, a.low, 16, &z.high, &z.low );
+ return z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the canonical NaN `a' to the quadruple-
+precision floating-point format.
+-------------------------------------------------------------------------------
+*/
+static float128 commonNaNToFloat128( commonNaNT a )
+{
+ float128 z;
+
+ shift128Right( a.high, a.low, 16, &z.high, &z.low );
+ z.high |= ( ( (bits64) a.sign )<<63 ) | LIT64( 0x7FFF800000000000 );
+ return z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Takes two quadruple-precision floating-point values `a' and `b', one of
+which is a NaN, and returns the appropriate NaN result. If either `a' or
+`b' is a signaling NaN, the invalid exception is raised.
+-------------------------------------------------------------------------------
+*/
+static float128 propagateFloat128NaN( float128 a, float128 b )
+{
+ flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
+
+ aIsNaN = float128_is_nan( a );
+ aIsSignalingNaN = float128_is_signaling_nan( a );
+ bIsNaN = float128_is_nan( b );
+ bIsSignalingNaN = float128_is_signaling_nan( b );
+ a.high |= LIT64( 0x0000800000000000 );
+ b.high |= LIT64( 0x0000800000000000 );
+ if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid );
+ if ( aIsNaN ) {
+ return ( aIsSignalingNaN & bIsNaN ) ? b : a;
+ }
+ else {
+ return b;
+ }
+
+}
+
+#endif
+
diff --git a/lib/libc/softfloat/softfloat.txt b/lib/libc/softfloat/softfloat.txt
new file mode 100644
index 000000000000..414506f7fef2
--- /dev/null
+++ b/lib/libc/softfloat/softfloat.txt
@@ -0,0 +1,373 @@
+$NetBSD: softfloat.txt,v 1.2 2006/11/24 19:46:58 christos Exp $
+$FreeBSD$
+
+SoftFloat Release 2a General Documentation
+
+John R. Hauser
+1998 December 13
+
+
+-------------------------------------------------------------------------------
+Introduction
+
+SoftFloat is a software implementation of floating-point that conforms to
+the IEC/IEEE Standard for Binary Floating-Point Arithmetic. As many as four
+formats are supported: single precision, double precision, extended double
+precision, and quadruple precision. All operations required by the standard
+are implemented, except for conversions to and from decimal.
+
+This document gives information about the types defined and the routines
+implemented by SoftFloat. It does not attempt to define or explain the
+IEC/IEEE Floating-Point Standard. Details about the standard are available
+elsewhere.
+
+
+-------------------------------------------------------------------------------
+Limitations
+
+SoftFloat is written in C and is designed to work with other C code. The
+SoftFloat header files assume an ISO/ANSI-style C compiler. No attempt
+has been made to accommodate compilers that are not ISO-conformant. In
+particular, the distributed header files will not be acceptable to any
+compiler that does not recognize function prototypes.
+
+Support for the extended double-precision and quadruple-precision formats
+depends on a C compiler that implements 64-bit integer arithmetic. If the
+largest integer format supported by the C compiler is 32 bits, SoftFloat is
+limited to only single and double precisions. When that is the case, all
+references in this document to the extended double precision, quadruple
+precision, and 64-bit integers should be ignored.
+
+
+-------------------------------------------------------------------------------
+Contents
+
+ Introduction
+ Limitations
+ Contents
+ Legal Notice
+ Types and Functions
+ Rounding Modes
+ Extended Double-Precision Rounding Precision
+ Exceptions and Exception Flags
+ Function Details
+ Conversion Functions
+ Standard Arithmetic Functions
+ Remainder Functions
+ Round-to-Integer Functions
+ Comparison Functions
+ Signaling NaN Test Functions
+ Raise-Exception Function
+ Contact Information
+
+
+
+-------------------------------------------------------------------------------
+Legal Notice
+
+SoftFloat was written by John R. Hauser. This work was made possible in
+part by the International Computer Science Institute, located at Suite 600,
+1947 Center Street, Berkeley, California 94704. Funding was partially
+provided by the National Science Foundation under grant MIP-9311980. The
+original version of this code was written as part of a project to build
+a fixed-point vector processor in collaboration with the University of
+California at Berkeley, overseen by Profs. Nelson Morgan and John Wawrzynek.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
+has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
+TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
+PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
+AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
+
+
+-------------------------------------------------------------------------------
+Types and Functions
+
+When 64-bit integers are supported by the compiler, the `softfloat.h' header
+file defines four types: `float32' (single precision), `float64' (double
+precision), `floatx80' (extended double precision), and `float128'
+(quadruple precision). The `float32' and `float64' types are defined in
+terms of 32-bit and 64-bit integer types, respectively, while the `float128'
+type is defined as a structure of two 64-bit integers, taking into account
+the byte order of the particular machine being used. The `floatx80' type
+is defined as a structure containing one 16-bit and one 64-bit integer, with
+the machine's byte order again determining the order of the `high' and `low'
+fields.
+
+When 64-bit integers are _not_ supported by the compiler, the `softfloat.h'
+header file defines only two types: `float32' and `float64'. Because
+ISO/ANSI C guarantees at least one built-in integer type of 32 bits,
+the `float32' type is identified with an appropriate integer type. The
+`float64' type is defined as a structure of two 32-bit integers, with the
+machine's byte order determining the order of the fields.
+
+In either case, the types in `softfloat.h' are defined such that if a system
+implements the usual C `float' and `double' types according to the IEC/IEEE
+Standard, then the `float32' and `float64' types should be indistinguishable
+in memory from the native `float' and `double' types. (On the other hand,
+when `float32' or `float64' values are placed in processor registers by
+the compiler, the type of registers used may differ from those used for the
+native `float' and `double' types.)
+
+SoftFloat implements the following arithmetic operations:
+
+-- Conversions among all the floating-point formats, and also between
+ integers (32-bit and 64-bit) and any of the floating-point formats.
+
+-- The usual add, subtract, multiply, divide, and square root operations
+ for all floating-point formats.
+
+-- For each format, the floating-point remainder operation defined by the
+ IEC/IEEE Standard.
+
+-- For each floating-point format, a ``round to integer'' operation that
+ rounds to the nearest integer value in the same format. (The floating-
+ point formats can hold integer values, of course.)
+
+-- Comparisons between two values in the same floating-point format.
+
+The only functions required by the IEC/IEEE Standard that are not provided
+are conversions to and from decimal.
+
+
+-------------------------------------------------------------------------------
+Rounding Modes
+
+All four rounding modes prescribed by the IEC/IEEE Standard are implemented
+for all operations that require rounding. The rounding mode is selected
+by the global variable `float_rounding_mode'. This variable may be set
+to one of the values `float_round_nearest_even', `float_round_to_zero',
+`float_round_down', or `float_round_up'. The rounding mode is initialized
+to nearest/even.
+
+
+-------------------------------------------------------------------------------
+Extended Double-Precision Rounding Precision
+
+For extended double precision (`floatx80') only, the rounding precision
+of the standard arithmetic operations is controlled by the global variable
+`floatx80_rounding_precision'. The operations affected are:
+
+ floatx80_add floatx80_sub floatx80_mul floatx80_div floatx80_sqrt
+
+When `floatx80_rounding_precision' is set to its default value of 80, these
+operations are rounded (as usual) to the full precision of the extended
+double-precision format. Setting `floatx80_rounding_precision' to 32
+or to 64 causes the operations listed to be rounded to reduced precision
+equivalent to single precision (`float32') or to double precision
+(`float64'), respectively. When rounding to reduced precision, additional
+bits in the result significand beyond the rounding point are set to zero.
+The consequences of setting `floatx80_rounding_precision' to a value other
+than 32, 64, or 80 is not specified. Operations other than the ones listed
+above are not affected by `floatx80_rounding_precision'.
+
+
+-------------------------------------------------------------------------------
+Exceptions and Exception Flags
+
+All five exception flags required by the IEC/IEEE Standard are
+implemented. Each flag is stored as a unique bit in the global variable
+`float_exception_flags'. The positions of the exception flag bits within
+this variable are determined by the bit masks `float_flag_inexact',
+`float_flag_underflow', `float_flag_overflow', `float_flag_divbyzero', and
+`float_flag_invalid'. The exception flags variable is initialized to all 0,
+meaning no exceptions.
+
+An individual exception flag can be cleared with the statement
+
+ float_exception_flags &= ~ float_flag_<exception>;
+
+where `<exception>' is the appropriate name. To raise a floating-point
+exception, the SoftFloat function `float_raise' should be used (see below).
+
+In the terminology of the IEC/IEEE Standard, SoftFloat can detect tininess
+for underflow either before or after rounding. The choice is made by
+the global variable `float_detect_tininess', which can be set to either
+`float_tininess_before_rounding' or `float_tininess_after_rounding'.
+Detecting tininess after rounding is better because it results in fewer
+spurious underflow signals. The other option is provided for compatibility
+with some systems. Like most systems, SoftFloat always detects loss of
+accuracy for underflow as an inexact result.
+
+
+-------------------------------------------------------------------------------
+Function Details
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Conversion Functions
+
+All conversions among the floating-point formats are supported, as are all
+conversions between a floating-point format and 32-bit and 64-bit signed
+integers. The complete set of conversion functions is:
+
+ int32_to_float32 int64_to_float32
+ int32_to_float64 int64_to_float32
+ int32_to_floatx80 int64_to_floatx80
+ int32_to_float128 int64_to_float128
+
+ float32_to_int32 float32_to_int64
+ float32_to_int32 float64_to_int64
+ floatx80_to_int32 floatx80_to_int64
+ float128_to_int32 float128_to_int64
+
+ float32_to_float64 float32_to_floatx80 float32_to_float128
+ float64_to_float32 float64_to_floatx80 float64_to_float128
+ floatx80_to_float32 floatx80_to_float64 floatx80_to_float128
+ float128_to_float32 float128_to_float64 float128_to_floatx80
+
+Each conversion function takes one operand of the appropriate type and
+returns one result. Conversions from a smaller to a larger floating-point
+format are always exact and so require no rounding. Conversions from 32-bit
+integers to double precision and larger formats are also exact, and likewise
+for conversions from 64-bit integers to extended double and quadruple
+precisions.
+
+Conversions from floating-point to integer raise the invalid exception if
+the source value cannot be rounded to a representable integer of the desired
+size (32 or 64 bits). If the floating-point operand is a NaN, the largest
+positive integer is returned. Otherwise, if the conversion overflows, the
+largest integer with the same sign as the operand is returned.
+
+On conversions to integer, if the floating-point operand is not already an
+integer value, the operand is rounded according to the current rounding
+mode as specified by `float_rounding_mode'. Because C (and perhaps other
+languages) require that conversions to integers be rounded toward zero, the
+following functions are provided for improved speed and convenience:
+
+ float32_to_int32_round_to_zero float32_to_int64_round_to_zero
+ float64_to_int32_round_to_zero float64_to_int64_round_to_zero
+ floatx80_to_int32_round_to_zero floatx80_to_int64_round_to_zero
+ float128_to_int32_round_to_zero float128_to_int64_round_to_zero
+
+These variant functions ignore `float_rounding_mode' and always round toward
+zero.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Standard Arithmetic Functions
+
+The following standard arithmetic functions are provided:
+
+ float32_add float32_sub float32_mul float32_div float32_sqrt
+ float64_add float64_sub float64_mul float64_div float64_sqrt
+ floatx80_add floatx80_sub floatx80_mul floatx80_div floatx80_sqrt
+ float128_add float128_sub float128_mul float128_div float128_sqrt
+
+Each function takes two operands, except for `sqrt' which takes only one.
+The operands and result are all of the same type.
+
+Rounding of the extended double-precision (`floatx80') functions is affected
+by the `floatx80_rounding_precision' variable, as explained above in the
+section _Extended_Double-Precision_Rounding_Precision_.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Remainder Functions
+
+For each format, SoftFloat implements the remainder function according to
+the IEC/IEEE Standard. The remainder functions are:
+
+ float32_rem
+ float64_rem
+ floatx80_rem
+ float128_rem
+
+Each remainder function takes two operands. The operands and result are all
+of the same type. Given operands x and y, the remainder functions return
+the value x - n*y, where n is the integer closest to x/y. If x/y is exactly
+halfway between two integers, n is the even integer closest to x/y. The
+remainder functions are always exact and so require no rounding.
+
+Depending on the relative magnitudes of the operands, the remainder
+functions can take considerably longer to execute than the other SoftFloat
+functions. This is inherent in the remainder operation itself and is not a
+flaw in the SoftFloat implementation.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Round-to-Integer Functions
+
+For each format, SoftFloat implements the round-to-integer function
+specified by the IEC/IEEE Standard. The functions are:
+
+ float32_round_to_int
+ float64_round_to_int
+ floatx80_round_to_int
+ float128_round_to_int
+
+Each function takes a single floating-point operand and returns a result of
+the same type. (Note that the result is not an integer type.) The operand
+is rounded to an exact integer according to the current rounding mode, and
+the resulting integer value is returned in the same floating-point format.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Comparison Functions
+
+The following floating-point comparison functions are provided:
+
+ float32_eq float32_le float32_lt
+ float64_eq float64_le float64_lt
+ floatx80_eq floatx80_le floatx80_lt
+ float128_eq float128_le float128_lt
+
+Each function takes two operands of the same type and returns a 1 or 0
+representing either _true_ or _false_. The abbreviation `eq' stands for
+``equal'' (=); `le' stands for ``less than or equal'' (<=); and `lt' stands
+for ``less than'' (<).
+
+The standard greater-than (>), greater-than-or-equal (>=), and not-equal
+(!=) functions are easily obtained using the functions provided. The
+not-equal function is just the logical complement of the equal function.
+The greater-than-or-equal function is identical to the less-than-or-equal
+function with the operands reversed; and the greater-than function can be
+obtained from the less-than function in the same way.
+
+The IEC/IEEE Standard specifies that the less-than-or-equal and less-than
+functions raise the invalid exception if either input is any kind of NaN.
+The equal functions, on the other hand, are defined not to raise the invalid
+exception on quiet NaNs. For completeness, SoftFloat provides the following
+additional functions:
+
+ float32_eq_signaling float32_le_quiet float32_lt_quiet
+ float64_eq_signaling float64_le_quiet float64_lt_quiet
+ floatx80_eq_signaling floatx80_le_quiet floatx80_lt_quiet
+ float128_eq_signaling float128_le_quiet float128_lt_quiet
+
+The `signaling' equal functions are identical to the standard functions
+except that the invalid exception is raised for any NaN input. Likewise,
+the `quiet' comparison functions are identical to their counterparts except
+that the invalid exception is not raised for quiet NaNs.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Signaling NaN Test Functions
+
+The following functions test whether a floating-point value is a signaling
+NaN:
+
+ float32_is_signaling_nan
+ float64_is_signaling_nan
+ floatx80_is_signaling_nan
+ float128_is_signaling_nan
+
+The functions take one operand and return 1 if the operand is a signaling
+NaN and 0 otherwise.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Raise-Exception Function
+
+SoftFloat provides a function for raising floating-point exceptions:
+
+ float_raise
+
+The function takes a mask indicating the set of exceptions to raise. No
+result is returned. In addition to setting the specified exception flags,
+this function may cause a trap or abort appropriate for the current system.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+
+-------------------------------------------------------------------------------
+Contact Information
+
+At the time of this writing, the most up-to-date information about
+SoftFloat and the latest release can be found at the Web page `http://
+HTTP.CS.Berkeley.EDU/~jhauser/arithmetic/SoftFloat.html'.
+
+
diff --git a/lib/libc/softfloat/templates/milieu.h b/lib/libc/softfloat/templates/milieu.h
new file mode 100644
index 000000000000..b7bd8e5f5f41
--- /dev/null
+++ b/lib/libc/softfloat/templates/milieu.h
@@ -0,0 +1,49 @@
+/* $FreeBSD$ */
+
+/*
+===============================================================================
+
+This C header file is part of the SoftFloat IEC/IEEE Floating-point
+Arithmetic Package, Release 2a.
+
+Written by John R. Hauser. This work was made possible in part by the
+International Computer Science Institute, located at Suite 600, 1947 Center
+Street, Berkeley, California 94704. Funding was partially provided by the
+National Science Foundation under grant MIP-9311980. The original version
+of this code was written as part of a project to build a fixed-point vector
+processor in collaboration with the University of California at Berkeley,
+overseen by Profs. Nelson Morgan and John Wawrzynek. More information
+is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
+arithmetic/SoftFloat.html'.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
+has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
+TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
+PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
+AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
+
+Derivative works are acceptable, even for commercial purposes, so long as
+(1) they include prominent notice that the work is derivative, and (2) they
+include prominent notice akin to these four paragraphs for those parts of
+this code that are retained.
+
+===============================================================================
+*/
+
+/*
+-------------------------------------------------------------------------------
+Include common integer types and flags.
+-------------------------------------------------------------------------------
+*/
+#include "../../../processors/!!!processor.h"
+
+/*
+-------------------------------------------------------------------------------
+Symbolic Boolean literals.
+-------------------------------------------------------------------------------
+*/
+enum {
+ FALSE = 0,
+ TRUE = 1
+};
+
diff --git a/lib/libc/softfloat/templates/softfloat-specialize b/lib/libc/softfloat/templates/softfloat-specialize
new file mode 100644
index 000000000000..a1dc4de86a53
--- /dev/null
+++ b/lib/libc/softfloat/templates/softfloat-specialize
@@ -0,0 +1,465 @@
+/* $FreeBSD$ */
+
+/*
+===============================================================================
+
+This C source fragment is part of the SoftFloat IEC/IEEE Floating-point
+Arithmetic Package, Release 2a.
+
+Written by John R. Hauser. This work was made possible in part by the
+International Computer Science Institute, located at Suite 600, 1947 Center
+Street, Berkeley, California 94704. Funding was partially provided by the
+National Science Foundation under grant MIP-9311980. The original version
+of this code was written as part of a project to build a fixed-point vector
+processor in collaboration with the University of California at Berkeley,
+overseen by Profs. Nelson Morgan and John Wawrzynek. More information
+is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
+arithmetic/SoftFloat.html'.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
+has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
+TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
+PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
+AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
+
+Derivative works are acceptable, even for commercial purposes, so long as
+(1) they include prominent notice that the work is derivative, and (2) they
+include prominent notice akin to these four paragraphs for those parts of
+this code that are retained.
+
+===============================================================================
+*/
+
+/*
+-------------------------------------------------------------------------------
+Underflow tininess-detection mode, statically initialized to default value.
+(The declaration in `softfloat.h' must match the `int8' type here.)
+-------------------------------------------------------------------------------
+*/
+int8 float_detect_tininess = float_tininess_after_rounding;
+
+/*
+-------------------------------------------------------------------------------
+Raises the exceptions specified by `flags'. Floating-point traps can be
+defined here if desired. It is currently not possible for such a trap to
+substitute a result value. If traps are not implemented, this routine
+should be simply `float_exception_flags |= flags;'.
+-------------------------------------------------------------------------------
+*/
+void float_raise( int8 flags )
+{
+
+ float_exception_flags |= flags;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Internal canonical NaN format.
+-------------------------------------------------------------------------------
+*/
+typedef struct {
+ flag sign;
+ bits64 high, low;
+} commonNaNT;
+
+/*
+-------------------------------------------------------------------------------
+The pattern for a default generated single-precision NaN.
+-------------------------------------------------------------------------------
+*/
+#define float32_default_nan 0xFFFFFFFF
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the single-precision floating-point value `a' is a NaN;
+otherwise returns 0.
+-------------------------------------------------------------------------------
+*/
+flag float32_is_nan( float32 a )
+{
+
+ return ( 0xFF000000 < (bits32) ( a<<1 ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the single-precision floating-point value `a' is a signaling
+NaN; otherwise returns 0.
+-------------------------------------------------------------------------------
+*/
+flag float32_is_signaling_nan( float32 a )
+{
+
+ return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the single-precision floating-point NaN
+`a' to the canonical NaN format. If `a' is a signaling NaN, the invalid
+exception is raised.
+-------------------------------------------------------------------------------
+*/
+static commonNaNT float32ToCommonNaN( float32 a )
+{
+ commonNaNT z;
+
+ if ( float32_is_signaling_nan( a ) ) float_raise( float_flag_invalid );
+ z.sign = a>>31;
+ z.low = 0;
+ z.high = ( (bits64) a )<<41;
+ return z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the canonical NaN `a' to the single-
+precision floating-point format.
+-------------------------------------------------------------------------------
+*/
+static float32 commonNaNToFloat32( commonNaNT a )
+{
+
+ return ( ( (bits32) a.sign )<<31 ) | 0x7FC00000 | ( a.high>>41 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Takes two single-precision floating-point values `a' and `b', one of which
+is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a
+signaling NaN, the invalid exception is raised.
+-------------------------------------------------------------------------------
+*/
+static float32 propagateFloat32NaN( float32 a, float32 b )
+{
+ flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
+
+ aIsNaN = float32_is_nan( a );
+ aIsSignalingNaN = float32_is_signaling_nan( a );
+ bIsNaN = float32_is_nan( b );
+ bIsSignalingNaN = float32_is_signaling_nan( b );
+ a |= 0x00400000;
+ b |= 0x00400000;
+ if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid );
+ if ( aIsNaN ) {
+ return ( aIsSignalingNaN & bIsNaN ) ? b : a;
+ }
+ else {
+ return b;
+ }
+
+}
+
+/*
+-------------------------------------------------------------------------------
+The pattern for a default generated double-precision NaN.
+-------------------------------------------------------------------------------
+*/
+#define float64_default_nan LIT64( 0xFFFFFFFFFFFFFFFF )
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the double-precision floating-point value `a' is a NaN;
+otherwise returns 0.
+-------------------------------------------------------------------------------
+*/
+flag float64_is_nan( float64 a )
+{
+
+ return ( LIT64( 0xFFE0000000000000 ) < (bits64) ( a<<1 ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the double-precision floating-point value `a' is a signaling
+NaN; otherwise returns 0.
+-------------------------------------------------------------------------------
+*/
+flag float64_is_signaling_nan( float64 a )
+{
+
+ return
+ ( ( ( a>>51 ) & 0xFFF ) == 0xFFE )
+ && ( a & LIT64( 0x0007FFFFFFFFFFFF ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the double-precision floating-point NaN
+`a' to the canonical NaN format. If `a' is a signaling NaN, the invalid
+exception is raised.
+-------------------------------------------------------------------------------
+*/
+static commonNaNT float64ToCommonNaN( float64 a )
+{
+ commonNaNT z;
+
+ if ( float64_is_signaling_nan( a ) ) float_raise( float_flag_invalid );
+ z.sign = a>>63;
+ z.low = 0;
+ z.high = a<<12;
+ return z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the canonical NaN `a' to the double-
+precision floating-point format.
+-------------------------------------------------------------------------------
+*/
+static float64 commonNaNToFloat64( commonNaNT a )
+{
+
+ return
+ ( ( (bits64) a.sign )<<63 )
+ | LIT64( 0x7FF8000000000000 )
+ | ( a.high>>12 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Takes two double-precision floating-point values `a' and `b', one of which
+is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a
+signaling NaN, the invalid exception is raised.
+-------------------------------------------------------------------------------
+*/
+static float64 propagateFloat64NaN( float64 a, float64 b )
+{
+ flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
+
+ aIsNaN = float64_is_nan( a );
+ aIsSignalingNaN = float64_is_signaling_nan( a );
+ bIsNaN = float64_is_nan( b );
+ bIsSignalingNaN = float64_is_signaling_nan( b );
+ a |= LIT64( 0x0008000000000000 );
+ b |= LIT64( 0x0008000000000000 );
+ if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid );
+ if ( aIsNaN ) {
+ return ( aIsSignalingNaN & bIsNaN ) ? b : a;
+ }
+ else {
+ return b;
+ }
+
+}
+
+#ifdef FLOATX80
+
+/*
+-------------------------------------------------------------------------------
+The pattern for a default generated extended double-precision NaN. The
+`high' and `low' values hold the most- and least-significant bits,
+respectively.
+-------------------------------------------------------------------------------
+*/
+#define floatx80_default_nan_high 0xFFFF
+#define floatx80_default_nan_low LIT64( 0xFFFFFFFFFFFFFFFF )
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the extended double-precision floating-point value `a' is a
+NaN; otherwise returns 0.
+-------------------------------------------------------------------------------
+*/
+flag floatx80_is_nan( floatx80 a )
+{
+
+ return ( ( a.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( a.low<<1 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the extended double-precision floating-point value `a' is a
+signaling NaN; otherwise returns 0.
+-------------------------------------------------------------------------------
+*/
+flag floatx80_is_signaling_nan( floatx80 a )
+{
+ bits64 aLow;
+
+ aLow = a.low & ~ LIT64( 0x4000000000000000 );
+ return
+ ( ( a.high & 0x7FFF ) == 0x7FFF )
+ && (bits64) ( aLow<<1 )
+ && ( a.low == aLow );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the extended double-precision floating-
+point NaN `a' to the canonical NaN format. If `a' is a signaling NaN, the
+invalid exception is raised.
+-------------------------------------------------------------------------------
+*/
+static commonNaNT floatx80ToCommonNaN( floatx80 a )
+{
+ commonNaNT z;
+
+ if ( floatx80_is_signaling_nan( a ) ) float_raise( float_flag_invalid );
+ z.sign = a.high>>15;
+ z.low = 0;
+ z.high = a.low<<1;
+ return z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the canonical NaN `a' to the extended
+double-precision floating-point format.
+-------------------------------------------------------------------------------
+*/
+static floatx80 commonNaNToFloatx80( commonNaNT a )
+{
+ floatx80 z;
+
+ z.low = LIT64( 0xC000000000000000 ) | ( a.high>>1 );
+ z.high = ( ( (bits16) a.sign )<<15 ) | 0x7FFF;
+ return z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Takes two extended double-precision floating-point values `a' and `b', one
+of which is a NaN, and returns the appropriate NaN result. If either `a' or
+`b' is a signaling NaN, the invalid exception is raised.
+-------------------------------------------------------------------------------
+*/
+static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b )
+{
+ flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
+
+ aIsNaN = floatx80_is_nan( a );
+ aIsSignalingNaN = floatx80_is_signaling_nan( a );
+ bIsNaN = floatx80_is_nan( b );
+ bIsSignalingNaN = floatx80_is_signaling_nan( b );
+ a.low |= LIT64( 0xC000000000000000 );
+ b.low |= LIT64( 0xC000000000000000 );
+ if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid );
+ if ( aIsNaN ) {
+ return ( aIsSignalingNaN & bIsNaN ) ? b : a;
+ }
+ else {
+ return b;
+ }
+
+}
+
+#endif
+
+#ifdef FLOAT128
+
+/*
+-------------------------------------------------------------------------------
+The pattern for a default generated quadruple-precision NaN. The `high' and
+`low' values hold the most- and least-significant bits, respectively.
+-------------------------------------------------------------------------------
+*/
+#define float128_default_nan_high LIT64( 0xFFFFFFFFFFFFFFFF )
+#define float128_default_nan_low LIT64( 0xFFFFFFFFFFFFFFFF )
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the quadruple-precision floating-point value `a' is a NaN;
+otherwise returns 0.
+-------------------------------------------------------------------------------
+*/
+flag float128_is_nan( float128 a )
+{
+
+ return
+ ( LIT64( 0xFFFE000000000000 ) <= (bits64) ( a.high<<1 ) )
+ && ( a.low || ( a.high & LIT64( 0x0000FFFFFFFFFFFF ) ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the quadruple-precision floating-point value `a' is a
+signaling NaN; otherwise returns 0.
+-------------------------------------------------------------------------------
+*/
+flag float128_is_signaling_nan( float128 a )
+{
+
+ return
+ ( ( ( a.high>>47 ) & 0xFFFF ) == 0xFFFE )
+ && ( a.low || ( a.high & LIT64( 0x00007FFFFFFFFFFF ) ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the quadruple-precision floating-point NaN
+`a' to the canonical NaN format. If `a' is a signaling NaN, the invalid
+exception is raised.
+-------------------------------------------------------------------------------
+*/
+static commonNaNT float128ToCommonNaN( float128 a )
+{
+ commonNaNT z;
+
+ if ( float128_is_signaling_nan( a ) ) float_raise( float_flag_invalid );
+ z.sign = a.high>>63;
+ shortShift128Left( a.high, a.low, 16, &z.high, &z.low );
+ return z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the canonical NaN `a' to the quadruple-
+precision floating-point format.
+-------------------------------------------------------------------------------
+*/
+static float128 commonNaNToFloat128( commonNaNT a )
+{
+ float128 z;
+
+ shift128Right( a.high, a.low, 16, &z.high, &z.low );
+ z.high |= ( ( (bits64) a.sign )<<63 ) | LIT64( 0x7FFF800000000000 );
+ return z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Takes two quadruple-precision floating-point values `a' and `b', one of
+which is a NaN, and returns the appropriate NaN result. If either `a' or
+`b' is a signaling NaN, the invalid exception is raised.
+-------------------------------------------------------------------------------
+*/
+static float128 propagateFloat128NaN( float128 a, float128 b )
+{
+ flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
+
+ aIsNaN = float128_is_nan( a );
+ aIsSignalingNaN = float128_is_signaling_nan( a );
+ bIsNaN = float128_is_nan( b );
+ bIsSignalingNaN = float128_is_signaling_nan( b );
+ a.high |= LIT64( 0x0000800000000000 );
+ b.high |= LIT64( 0x0000800000000000 );
+ if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid );
+ if ( aIsNaN ) {
+ return ( aIsSignalingNaN & bIsNaN ) ? b : a;
+ }
+ else {
+ return b;
+ }
+
+}
+
+#endif
+
diff --git a/lib/libc/softfloat/templates/softfloat.h b/lib/libc/softfloat/templates/softfloat.h
new file mode 100644
index 000000000000..070aab231c60
--- /dev/null
+++ b/lib/libc/softfloat/templates/softfloat.h
@@ -0,0 +1,291 @@
+/* $FreeBSD$ */
+
+/*
+===============================================================================
+
+This C header file is part of the SoftFloat IEC/IEEE Floating-point
+Arithmetic Package, Release 2a.
+
+Written by John R. Hauser. This work was made possible in part by the
+International Computer Science Institute, located at Suite 600, 1947 Center
+Street, Berkeley, California 94704. Funding was partially provided by the
+National Science Foundation under grant MIP-9311980. The original version
+of this code was written as part of a project to build a fixed-point vector
+processor in collaboration with the University of California at Berkeley,
+overseen by Profs. Nelson Morgan and John Wawrzynek. More information
+is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
+arithmetic/SoftFloat.html'.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
+has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
+TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
+PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
+AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
+
+Derivative works are acceptable, even for commercial purposes, so long as
+(1) they include prominent notice that the work is derivative, and (2) they
+include prominent notice akin to these four paragraphs for those parts of
+this code that are retained.
+
+===============================================================================
+*/
+
+/*
+-------------------------------------------------------------------------------
+The macro `FLOATX80' must be defined to enable the extended double-precision
+floating-point format `floatx80'. If this macro is not defined, the
+`floatx80' type will not be defined, and none of the functions that either
+input or output the `floatx80' type will be defined. The same applies to
+the `FLOAT128' macro and the quadruple-precision format `float128'.
+-------------------------------------------------------------------------------
+*/
+#define FLOATX80
+#define FLOAT128
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE floating-point types.
+-------------------------------------------------------------------------------
+*/
+typedef !!!bits32 float32;
+typedef !!!bits64 float64;
+#ifdef FLOATX80
+typedef struct {
+ !!!bits16 high;
+ !!!bits64 low;
+} floatx80;
+#endif
+#ifdef FLOAT128
+typedef struct {
+ !!!bits64 high, low;
+} float128;
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE floating-point underflow tininess-detection mode.
+-------------------------------------------------------------------------------
+*/
+extern !!!int8 float_detect_tininess;
+enum {
+ float_tininess_after_rounding = 0,
+ float_tininess_before_rounding = 1
+};
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE floating-point rounding mode.
+-------------------------------------------------------------------------------
+*/
+extern !!!int8 float_rounding_mode;
+enum {
+ float_round_nearest_even = 0,
+ float_round_to_zero = 1,
+ float_round_down = 2,
+ float_round_up = 3
+};
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE floating-point exception flags.
+-------------------------------------------------------------------------------
+*/
+extern !!!int8 float_exception_flags;
+enum {
+ float_flag_inexact = 1,
+ float_flag_underflow = 2,
+ float_flag_overflow = 4,
+ float_flag_divbyzero = 8,
+ float_flag_invalid = 16
+};
+
+/*
+-------------------------------------------------------------------------------
+Routine to raise any or all of the software IEC/IEEE floating-point
+exception flags.
+-------------------------------------------------------------------------------
+*/
+void float_raise( !!!int8 );
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE integer-to-floating-point conversion routines.
+-------------------------------------------------------------------------------
+*/
+float32 int32_to_float32( !!!int32 );
+float64 int32_to_float64( !!!int32 );
+#ifdef FLOATX80
+floatx80 int32_to_floatx80( !!!int32 );
+#endif
+#ifdef FLOAT128
+float128 int32_to_float128( !!!int32 );
+#endif
+float32 int64_to_float32( !!!int64 );
+float64 int64_to_float64( !!!int64 );
+#ifdef FLOATX80
+floatx80 int64_to_floatx80( !!!int64 );
+#endif
+#ifdef FLOAT128
+float128 int64_to_float128( !!!int64 );
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE single-precision conversion routines.
+-------------------------------------------------------------------------------
+*/
+!!!int32 float32_to_int32( float32 );
+!!!int32 float32_to_int32_round_to_zero( float32 );
+!!!int64 float32_to_int64( float32 );
+!!!int64 float32_to_int64_round_to_zero( float32 );
+float64 float32_to_float64( float32 );
+#ifdef FLOATX80
+floatx80 float32_to_floatx80( float32 );
+#endif
+#ifdef FLOAT128
+float128 float32_to_float128( float32 );
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE single-precision operations.
+-------------------------------------------------------------------------------
+*/
+float32 float32_round_to_int( float32 );
+float32 float32_add( float32, float32 );
+float32 float32_sub( float32, float32 );
+float32 float32_mul( float32, float32 );
+float32 float32_div( float32, float32 );
+float32 float32_rem( float32, float32 );
+float32 float32_sqrt( float32 );
+!!!flag float32_eq( float32, float32 );
+!!!flag float32_le( float32, float32 );
+!!!flag float32_lt( float32, float32 );
+!!!flag float32_eq_signaling( float32, float32 );
+!!!flag float32_le_quiet( float32, float32 );
+!!!flag float32_lt_quiet( float32, float32 );
+!!!flag float32_is_signaling_nan( float32 );
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE double-precision conversion routines.
+-------------------------------------------------------------------------------
+*/
+!!!int32 float64_to_int32( float64 );
+!!!int32 float64_to_int32_round_to_zero( float64 );
+!!!int64 float64_to_int64( float64 );
+!!!int64 float64_to_int64_round_to_zero( float64 );
+float32 float64_to_float32( float64 );
+#ifdef FLOATX80
+floatx80 float64_to_floatx80( float64 );
+#endif
+#ifdef FLOAT128
+float128 float64_to_float128( float64 );
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE double-precision operations.
+-------------------------------------------------------------------------------
+*/
+float64 float64_round_to_int( float64 );
+float64 float64_add( float64, float64 );
+float64 float64_sub( float64, float64 );
+float64 float64_mul( float64, float64 );
+float64 float64_div( float64, float64 );
+float64 float64_rem( float64, float64 );
+float64 float64_sqrt( float64 );
+!!!flag float64_eq( float64, float64 );
+!!!flag float64_le( float64, float64 );
+!!!flag float64_lt( float64, float64 );
+!!!flag float64_eq_signaling( float64, float64 );
+!!!flag float64_le_quiet( float64, float64 );
+!!!flag float64_lt_quiet( float64, float64 );
+!!!flag float64_is_signaling_nan( float64 );
+
+#ifdef FLOATX80
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE extended double-precision conversion routines.
+-------------------------------------------------------------------------------
+*/
+!!!int32 floatx80_to_int32( floatx80 );
+!!!int32 floatx80_to_int32_round_to_zero( floatx80 );
+!!!int64 floatx80_to_int64( floatx80 );
+!!!int64 floatx80_to_int64_round_to_zero( floatx80 );
+float32 floatx80_to_float32( floatx80 );
+float64 floatx80_to_float64( floatx80 );
+#ifdef FLOAT128
+float128 floatx80_to_float128( floatx80 );
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE extended double-precision rounding precision. Valid
+values are 32, 64, and 80.
+-------------------------------------------------------------------------------
+*/
+extern !!!int8 floatx80_rounding_precision;
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE extended double-precision operations.
+-------------------------------------------------------------------------------
+*/
+floatx80 floatx80_round_to_int( floatx80 );
+floatx80 floatx80_add( floatx80, floatx80 );
+floatx80 floatx80_sub( floatx80, floatx80 );
+floatx80 floatx80_mul( floatx80, floatx80 );
+floatx80 floatx80_div( floatx80, floatx80 );
+floatx80 floatx80_rem( floatx80, floatx80 );
+floatx80 floatx80_sqrt( floatx80 );
+!!!flag floatx80_eq( floatx80, floatx80 );
+!!!flag floatx80_le( floatx80, floatx80 );
+!!!flag floatx80_lt( floatx80, floatx80 );
+!!!flag floatx80_eq_signaling( floatx80, floatx80 );
+!!!flag floatx80_le_quiet( floatx80, floatx80 );
+!!!flag floatx80_lt_quiet( floatx80, floatx80 );
+!!!flag floatx80_is_signaling_nan( floatx80 );
+
+#endif
+
+#ifdef FLOAT128
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE quadruple-precision conversion routines.
+-------------------------------------------------------------------------------
+*/
+!!!int32 float128_to_int32( float128 );
+!!!int32 float128_to_int32_round_to_zero( float128 );
+!!!int64 float128_to_int64( float128 );
+!!!int64 float128_to_int64_round_to_zero( float128 );
+float32 float128_to_float32( float128 );
+float64 float128_to_float64( float128 );
+#ifdef FLOATX80
+floatx80 float128_to_floatx80( float128 );
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE quadruple-precision operations.
+-------------------------------------------------------------------------------
+*/
+float128 float128_round_to_int( float128 );
+float128 float128_add( float128, float128 );
+float128 float128_sub( float128, float128 );
+float128 float128_mul( float128, float128 );
+float128 float128_div( float128, float128 );
+float128 float128_rem( float128, float128 );
+float128 float128_sqrt( float128 );
+!!!flag float128_eq( float128, float128 );
+!!!flag float128_le( float128, float128 );
+!!!flag float128_lt( float128, float128 );
+!!!flag float128_eq_signaling( float128, float128 );
+!!!flag float128_le_quiet( float128, float128 );
+!!!flag float128_lt_quiet( float128, float128 );
+!!!flag float128_is_signaling_nan( float128 );
+
+#endif
+
diff --git a/lib/libc/softfloat/timesoftfloat.c b/lib/libc/softfloat/timesoftfloat.c
new file mode 100644
index 000000000000..b97c8b0f0d00
--- /dev/null
+++ b/lib/libc/softfloat/timesoftfloat.c
@@ -0,0 +1,2639 @@
+/* $NetBSD: timesoftfloat.c,v 1.1 2000/06/06 08:15:11 bjh21 Exp $ */
+
+/*
+===============================================================================
+
+This C source file is part of the SoftFloat IEC/IEEE Floating-point
+Arithmetic Package, Release 2a.
+
+Written by John R. Hauser. This work was made possible in part by the
+International Computer Science Institute, located at Suite 600, 1947 Center
+Street, Berkeley, California 94704. Funding was partially provided by the
+National Science Foundation under grant MIP-9311980. The original version
+of this code was written as part of a project to build a fixed-point vector
+processor in collaboration with the University of California at Berkeley,
+overseen by Profs. Nelson Morgan and John Wawrzynek. More information
+is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
+arithmetic/SoftFloat.html'.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
+has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
+TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
+PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
+AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
+
+Derivative works are acceptable, even for commercial purposes, so long as
+(1) they include prominent notice that the work is derivative, and (2) they
+include prominent notice akin to these four paragraphs for those parts of
+this code that are retained.
+
+===============================================================================
+*/
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdio.h>
+#include <time.h>
+#include "milieu.h"
+#include "softfloat.h"
+
+enum {
+ minIterations = 1000
+};
+
+static void fail( const char *message, ... )
+{
+ va_list varArgs;
+
+ fputs( "timesoftfloat: ", stderr );
+ va_start( varArgs, message );
+ vfprintf( stderr, message, varArgs );
+ va_end( varArgs );
+ fputs( ".\n", stderr );
+ exit( EXIT_FAILURE );
+
+}
+
+static char *functionName;
+static char *roundingPrecisionName, *roundingModeName, *tininessModeName;
+
+static void reportTime( int32 count, long clocks )
+{
+
+ printf(
+ "%8.1f kops/s: %s",
+ ( count / ( ( (float) clocks ) / CLOCKS_PER_SEC ) ) / 1000,
+ functionName
+ );
+ if ( roundingModeName ) {
+ if ( roundingPrecisionName ) {
+ fputs( ", precision ", stdout );
+ fputs( roundingPrecisionName, stdout );
+ }
+ fputs( ", rounding ", stdout );
+ fputs( roundingModeName, stdout );
+ if ( tininessModeName ) {
+ fputs( ", tininess ", stdout );
+ fputs( tininessModeName, stdout );
+ fputs( " rounding", stdout );
+ }
+ }
+ fputc( '\n', stdout );
+
+}
+
+enum {
+ numInputs_int32 = 32
+};
+
+static const int32 inputs_int32[ numInputs_int32 ] = {
+ 0xFFFFBB79, 0x405CF80F, 0x00000000, 0xFFFFFD04,
+ 0xFFF20002, 0x0C8EF795, 0xF00011FF, 0x000006CA,
+ 0x00009BFE, 0xFF4862E3, 0x9FFFEFFE, 0xFFFFFFB7,
+ 0x0BFF7FFF, 0x0000F37A, 0x0011DFFE, 0x00000006,
+ 0xFFF02006, 0xFFFFF7D1, 0x10200003, 0xDE8DF765,
+ 0x00003E02, 0x000019E8, 0x0008FFFE, 0xFFFFFB5C,
+ 0xFFDF7FFE, 0x07C42FBF, 0x0FFFE3FF, 0x040B9F13,
+ 0xBFFFFFF8, 0x0001BF56, 0x000017F6, 0x000A908A
+};
+
+static void time_a_int32_z_float32( float32 function( int32 ) )
+{
+ clock_t startClock, endClock;
+ int32 count, i;
+ int8 inputNum;
+
+ count = 0;
+ inputNum = 0;
+ startClock = clock();
+ do {
+ for ( i = minIterations; i; --i ) {
+ function( inputs_int32[ inputNum ] );
+ inputNum = ( inputNum + 1 ) & ( numInputs_int32 - 1 );
+ }
+ count += minIterations;
+ } while ( clock() - startClock < CLOCKS_PER_SEC );
+ inputNum = 0;
+ startClock = clock();
+ for ( i = count; i; --i ) {
+ function( inputs_int32[ inputNum ] );
+ inputNum = ( inputNum + 1 ) & ( numInputs_int32 - 1 );
+ }
+ endClock = clock();
+ reportTime( count, endClock - startClock );
+
+}
+
+static void time_a_int32_z_float64( float64 function( int32 ) )
+{
+ clock_t startClock, endClock;
+ int32 count, i;
+ int8 inputNum;
+
+ count = 0;
+ inputNum = 0;
+ startClock = clock();
+ do {
+ for ( i = minIterations; i; --i ) {
+ function( inputs_int32[ inputNum ] );
+ inputNum = ( inputNum + 1 ) & ( numInputs_int32 - 1 );
+ }
+ count += minIterations;
+ } while ( clock() - startClock < CLOCKS_PER_SEC );
+ inputNum = 0;
+ startClock = clock();
+ for ( i = count; i; --i ) {
+ function( inputs_int32[ inputNum ] );
+ inputNum = ( inputNum + 1 ) & ( numInputs_int32 - 1 );
+ }
+ endClock = clock();
+ reportTime( count, endClock - startClock );
+
+}
+
+#ifdef FLOATX80
+
+static void time_a_int32_z_floatx80( floatx80 function( int32 ) )
+{
+ clock_t startClock, endClock;
+ int32 count, i;
+ int8 inputNum;
+
+ count = 0;
+ inputNum = 0;
+ startClock = clock();
+ do {
+ for ( i = minIterations; i; --i ) {
+ function( inputs_int32[ inputNum ] );
+ inputNum = ( inputNum + 1 ) & ( numInputs_int32 - 1 );
+ }
+ count += minIterations;
+ } while ( clock() - startClock < CLOCKS_PER_SEC );
+ inputNum = 0;
+ startClock = clock();
+ for ( i = count; i; --i ) {
+ function( inputs_int32[ inputNum ] );
+ inputNum = ( inputNum + 1 ) & ( numInputs_int32 - 1 );
+ }
+ endClock = clock();
+ reportTime( count, endClock - startClock );
+
+}
+
+#endif
+
+#ifdef FLOAT128
+
+static void time_a_int32_z_float128( float128 function( int32 ) )
+{
+ clock_t startClock, endClock;
+ int32 count, i;
+ int8 inputNum;
+
+ count = 0;
+ inputNum = 0;
+ startClock = clock();
+ do {
+ for ( i = minIterations; i; --i ) {
+ function( inputs_int32[ inputNum ] );
+ inputNum = ( inputNum + 1 ) & ( numInputs_int32 - 1 );
+ }
+ count += minIterations;
+ } while ( clock() - startClock < CLOCKS_PER_SEC );
+ inputNum = 0;
+ startClock = clock();
+ for ( i = count; i; --i ) {
+ function( inputs_int32[ inputNum ] );
+ inputNum = ( inputNum + 1 ) & ( numInputs_int32 - 1 );
+ }
+ endClock = clock();
+ reportTime( count, endClock - startClock );
+
+}
+
+#endif
+
+enum {
+ numInputs_int64 = 32
+};
+
+static const int64 inputs_int64[ numInputs_int64 ] = {
+ LIT64( 0xFBFFC3FFFFFFFFFF ),
+ LIT64( 0x0000000003C589BC ),
+ LIT64( 0x00000000400013FE ),
+ LIT64( 0x0000000000186171 ),
+ LIT64( 0xFFFFFFFFFFFEFBFA ),
+ LIT64( 0xFFFFFD79E6DFFC73 ),
+ LIT64( 0x0000000010001DFF ),
+ LIT64( 0xDD1A0F0C78513710 ),
+ LIT64( 0xFFFF83FFFFFEFFFE ),
+ LIT64( 0x00756EBD1AD0C1C7 ),
+ LIT64( 0x0003FDFFFFFFFFBE ),
+ LIT64( 0x0007D0FB2C2CA951 ),
+ LIT64( 0x0007FC0007FFFFFE ),
+ LIT64( 0x0000001F942B18BB ),
+ LIT64( 0x0000080101FFFFFE ),
+ LIT64( 0xFFFFFFFFFFFF0978 ),
+ LIT64( 0x000000000008BFFF ),
+ LIT64( 0x0000000006F5AF08 ),
+ LIT64( 0xFFDEFF7FFFFFFFFE ),
+ LIT64( 0x0000000000000003 ),
+ LIT64( 0x3FFFFFFFFF80007D ),
+ LIT64( 0x0000000000000078 ),
+ LIT64( 0xFFF80000007FDFFD ),
+ LIT64( 0x1BBC775B78016AB0 ),
+ LIT64( 0xFFF9001FFFFFFFFE ),
+ LIT64( 0xFFFD4767AB98E43F ),
+ LIT64( 0xFFFFFEFFFE00001E ),
+ LIT64( 0xFFFFFFFFFFF04EFD ),
+ LIT64( 0x07FFFFFFFFFFF7FF ),
+ LIT64( 0xFFFC9EAA38F89050 ),
+ LIT64( 0x00000020FBFFFFFE ),
+ LIT64( 0x0000099AE6455357 )
+};
+
+static void time_a_int64_z_float32( float32 function( int64 ) )
+{
+ clock_t startClock, endClock;
+ int32 count, i;
+ int8 inputNum;
+
+ count = 0;
+ inputNum = 0;
+ startClock = clock();
+ do {
+ for ( i = minIterations; i; --i ) {
+ function( inputs_int64[ inputNum ] );
+ inputNum = ( inputNum + 1 ) & ( numInputs_int64 - 1 );
+ }
+ count += minIterations;
+ } while ( clock() - startClock < CLOCKS_PER_SEC );
+ inputNum = 0;
+ startClock = clock();
+ for ( i = count; i; --i ) {
+ function( inputs_int64[ inputNum ] );
+ inputNum = ( inputNum + 1 ) & ( numInputs_int64 - 1 );
+ }
+ endClock = clock();
+ reportTime( count, endClock - startClock );
+
+}
+
+static void time_a_int64_z_float64( float64 function( int64 ) )
+{
+ clock_t startClock, endClock;
+ int32 count, i;
+ int8 inputNum;
+
+ count = 0;
+ inputNum = 0;
+ startClock = clock();
+ do {
+ for ( i = minIterations; i; --i ) {
+ function( inputs_int64[ inputNum ] );
+ inputNum = ( inputNum + 1 ) & ( numInputs_int64 - 1 );
+ }
+ count += minIterations;
+ } while ( clock() - startClock < CLOCKS_PER_SEC );
+ inputNum = 0;
+ startClock = clock();
+ for ( i = count; i; --i ) {
+ function( inputs_int64[ inputNum ] );
+ inputNum = ( inputNum + 1 ) & ( numInputs_int64 - 1 );
+ }
+ endClock = clock();
+ reportTime( count, endClock - startClock );
+
+}
+
+#ifdef FLOATX80
+
+static void time_a_int64_z_floatx80( floatx80 function( int64 ) )
+{
+ clock_t startClock, endClock;
+ int32 count, i;
+ int8 inputNum;
+
+ count = 0;
+ inputNum = 0;
+ startClock = clock();
+ do {
+ for ( i = minIterations; i; --i ) {
+ function( inputs_int64[ inputNum ] );
+ inputNum = ( inputNum + 1 ) & ( numInputs_int64 - 1 );
+ }
+ count += minIterations;
+ } while ( clock() - startClock < CLOCKS_PER_SEC );
+ inputNum = 0;
+ startClock = clock();
+ for ( i = count; i; --i ) {
+ function( inputs_int64[ inputNum ] );
+ inputNum = ( inputNum + 1 ) & ( numInputs_int64 - 1 );
+ }
+ endClock = clock();
+ reportTime( count, endClock - startClock );
+
+}
+
+#endif
+
+#ifdef FLOAT128
+
+static void time_a_int64_z_float128( float128 function( int64 ) )
+{
+ clock_t startClock, endClock;
+ int32 count, i;
+ int8 inputNum;
+
+ count = 0;
+ inputNum = 0;
+ startClock = clock();
+ do {
+ for ( i = minIterations; i; --i ) {
+ function( inputs_int64[ inputNum ] );
+ inputNum = ( inputNum + 1 ) & ( numInputs_int64 - 1 );
+ }
+ count += minIterations;
+ } while ( clock() - startClock < CLOCKS_PER_SEC );
+ inputNum = 0;
+ startClock = clock();
+ for ( i = count; i; --i ) {
+ function( inputs_int64[ inputNum ] );
+ inputNum = ( inputNum + 1 ) & ( numInputs_int64 - 1 );
+ }
+ endClock = clock();
+ reportTime( count, endClock - startClock );
+
+}
+
+#endif
+
+enum {
+ numInputs_float32 = 32
+};
+
+static const float32 inputs_float32[ numInputs_float32 ] = {
+ 0x4EFA0000, 0xC1D0B328, 0x80000000, 0x3E69A31E,
+ 0xAF803EFF, 0x3F800000, 0x17BF8000, 0xE74A301A,
+ 0x4E010003, 0x7EE3C75D, 0xBD803FE0, 0xBFFEFF00,
+ 0x7981F800, 0x431FFFFC, 0xC100C000, 0x3D87EFFF,
+ 0x4103FEFE, 0xBC000007, 0xBF01F7FF, 0x4E6C6B5C,
+ 0xC187FFFE, 0xC58B9F13, 0x4F88007F, 0xDF004007,
+ 0xB7FFD7FE, 0x7E8001FB, 0x46EFFBFF, 0x31C10000,
+ 0xDB428661, 0x33F89B1F, 0xA3BFEFFF, 0x537BFFBE
+};
+
+static void time_a_float32_z_int32( int32 function( float32 ) )
+{
+ clock_t startClock, endClock;
+ int32 count, i;
+ int8 inputNum;
+
+ count = 0;
+ inputNum = 0;
+ startClock = clock();
+ do {
+ for ( i = minIterations; i; --i ) {
+ function( inputs_float32[ inputNum ] );
+ inputNum = ( inputNum + 1 ) & ( numInputs_float32 - 1 );
+ }
+ count += minIterations;
+ } while ( clock() - startClock < CLOCKS_PER_SEC );
+ inputNum = 0;
+ startClock = clock();
+ for ( i = count; i; --i ) {
+ function( inputs_float32[ inputNum ] );
+ inputNum = ( inputNum + 1 ) & ( numInputs_float32 - 1 );
+ }
+ endClock = clock();
+ reportTime( count, endClock - startClock );
+
+}
+
+static void time_a_float32_z_int64( int64 function( float32 ) )
+{
+ clock_t startClock, endClock;
+ int32 count, i;
+ int8 inputNum;
+
+ count = 0;
+ inputNum = 0;
+ startClock = clock();
+ do {
+ for ( i = minIterations; i; --i ) {
+ function( inputs_float32[ inputNum ] );
+ inputNum = ( inputNum + 1 ) & ( numInputs_float32 - 1 );
+ }
+ count += minIterations;
+ } while ( clock() - startClock < CLOCKS_PER_SEC );
+ inputNum = 0;
+ startClock = clock();
+ for ( i = count; i; --i ) {
+ function( inputs_float32[ inputNum ] );
+ inputNum = ( inputNum + 1 ) & ( numInputs_float32 - 1 );
+ }
+ endClock = clock();
+ reportTime( count, endClock - startClock );
+
+}
+
+static void time_a_float32_z_float64( float64 function( float32 ) )
+{
+ clock_t startClock, endClock;
+ int32 count, i;
+ int8 inputNum;
+
+ count = 0;
+ inputNum = 0;
+ startClock = clock();
+ do {
+ for ( i = minIterations; i; --i ) {
+ function( inputs_float32[ inputNum ] );
+ inputNum = ( inputNum + 1 ) & ( numInputs_float32 - 1 );
+ }
+ count += minIterations;
+ } while ( clock() - startClock < CLOCKS_PER_SEC );
+ inputNum = 0;
+ startClock = clock();
+ for ( i = count; i; --i ) {
+ function( inputs_float32[ inputNum ] );
+ inputNum = ( inputNum + 1 ) & ( numInputs_float32 - 1 );
+ }
+ endClock = clock();
+ reportTime( count, endClock - startClock );
+
+}
+
+#ifdef FLOATX80
+
+static void time_a_float32_z_floatx80( floatx80 function( float32 ) )
+{
+ clock_t startClock, endClock;
+ int32 count, i;
+ int8 inputNum;
+
+ count = 0;
+ inputNum = 0;
+ startClock = clock();
+ do {
+ for ( i = minIterations; i; --i ) {
+ function( inputs_float32[ inputNum ] );
+ inputNum = ( inputNum + 1 ) & ( numInputs_float32 - 1 );
+ }
+ count += minIterations;
+ } while ( clock() - startClock < CLOCKS_PER_SEC );
+ inputNum = 0;
+ startClock = clock();
+ for ( i = count; i; --i ) {
+ function( inputs_float32[ inputNum ] );
+ inputNum = ( inputNum + 1 ) & ( numInputs_float32 - 1 );
+ }
+ endClock = clock();
+ reportTime( count, endClock - startClock );
+
+}
+
+#endif
+
+#ifdef FLOAT128
+
+static void time_a_float32_z_float128( float128 function( float32 ) )
+{
+ clock_t startClock, endClock;
+ int32 count, i;
+ int8 inputNum;
+
+ count = 0;
+ inputNum = 0;
+ startClock = clock();
+ do {
+ for ( i = minIterations; i; --i ) {
+ function( inputs_float32[ inputNum ] );
+ inputNum = ( inputNum + 1 ) & ( numInputs_float32 - 1 );
+ }
+ count += minIterations;
+ } while ( clock() - startClock < CLOCKS_PER_SEC );
+ inputNum = 0;
+ startClock = clock();
+ for ( i = count; i; --i ) {
+ function( inputs_float32[ inputNum ] );
+ inputNum = ( inputNum + 1 ) & ( numInputs_float32 - 1 );
+ }
+ endClock = clock();
+ reportTime( count, endClock - startClock );
+
+}
+
+#endif
+
+static void time_az_float32( float32 function( float32 ) )
+{
+ clock_t startClock, endClock;
+ int32 count, i;
+ int8 inputNum;
+
+ count = 0;
+ inputNum = 0;
+ startClock = clock();
+ do {
+ for ( i = minIterations; i; --i ) {
+ function( inputs_float32[ inputNum ] );
+ inputNum = ( inputNum + 1 ) & ( numInputs_float32 - 1 );
+ }
+ count += minIterations;
+ } while ( clock() - startClock < CLOCKS_PER_SEC );
+ inputNum = 0;
+ startClock = clock();
+ for ( i = count; i; --i ) {
+ function( inputs_float32[ inputNum ] );
+ inputNum = ( inputNum + 1 ) & ( numInputs_float32 - 1 );
+ }
+ endClock = clock();
+ reportTime( count, endClock - startClock );
+
+}
+
+static void time_ab_float32_z_flag( flag function( float32, float32 ) )
+{
+ clock_t startClock, endClock;
+ int32 count, i;
+ int8 inputNumA, inputNumB;
+
+ count = 0;
+ inputNumA = 0;
+ inputNumB = 0;
+ startClock = clock();
+ do {
+ for ( i = minIterations; i; --i ) {
+ function(
+ inputs_float32[ inputNumA ], inputs_float32[ inputNumB ] );
+ inputNumA = ( inputNumA + 1 ) & ( numInputs_float32 - 1 );
+ if ( inputNumA == 0 ) ++inputNumB;
+ inputNumB = ( inputNumB + 1 ) & ( numInputs_float32 - 1 );
+ }
+ count += minIterations;
+ } while ( clock() - startClock < CLOCKS_PER_SEC );
+ inputNumA = 0;
+ inputNumB = 0;
+ startClock = clock();
+ for ( i = count; i; --i ) {
+ function(
+ inputs_float32[ inputNumA ], inputs_float32[ inputNumB ] );
+ inputNumA = ( inputNumA + 1 ) & ( numInputs_float32 - 1 );
+ if ( inputNumA == 0 ) ++inputNumB;
+ inputNumB = ( inputNumB + 1 ) & ( numInputs_float32 - 1 );
+ }
+ endClock = clock();
+ reportTime( count, endClock - startClock );
+
+}
+
+static void time_abz_float32( float32 function( float32, float32 ) )
+{
+ clock_t startClock, endClock;
+ int32 count, i;
+ int8 inputNumA, inputNumB;
+
+ count = 0;
+ inputNumA = 0;
+ inputNumB = 0;
+ startClock = clock();
+ do {
+ for ( i = minIterations; i; --i ) {
+ function(
+ inputs_float32[ inputNumA ], inputs_float32[ inputNumB ] );
+ inputNumA = ( inputNumA + 1 ) & ( numInputs_float32 - 1 );
+ if ( inputNumA == 0 ) ++inputNumB;
+ inputNumB = ( inputNumB + 1 ) & ( numInputs_float32 - 1 );
+ }
+ count += minIterations;
+ } while ( clock() - startClock < CLOCKS_PER_SEC );
+ inputNumA = 0;
+ inputNumB = 0;
+ startClock = clock();
+ for ( i = count; i; --i ) {
+ function(
+ inputs_float32[ inputNumA ], inputs_float32[ inputNumB ] );
+ inputNumA = ( inputNumA + 1 ) & ( numInputs_float32 - 1 );
+ if ( inputNumA == 0 ) ++inputNumB;
+ inputNumB = ( inputNumB + 1 ) & ( numInputs_float32 - 1 );
+ }
+ endClock = clock();
+ reportTime( count, endClock - startClock );
+
+}
+
+static const float32 inputs_float32_pos[ numInputs_float32 ] = {
+ 0x4EFA0000, 0x41D0B328, 0x00000000, 0x3E69A31E,
+ 0x2F803EFF, 0x3F800000, 0x17BF8000, 0x674A301A,
+ 0x4E010003, 0x7EE3C75D, 0x3D803FE0, 0x3FFEFF00,
+ 0x7981F800, 0x431FFFFC, 0x4100C000, 0x3D87EFFF,
+ 0x4103FEFE, 0x3C000007, 0x3F01F7FF, 0x4E6C6B5C,
+ 0x4187FFFE, 0x458B9F13, 0x4F88007F, 0x5F004007,
+ 0x37FFD7FE, 0x7E8001FB, 0x46EFFBFF, 0x31C10000,
+ 0x5B428661, 0x33F89B1F, 0x23BFEFFF, 0x537BFFBE
+};
+
+static void time_az_float32_pos( float32 function( float32 ) )
+{
+ clock_t startClock, endClock;
+ int32 count, i;
+ int8 inputNum;
+
+ count = 0;
+ inputNum = 0;
+ startClock = clock();
+ do {
+ for ( i = minIterations; i; --i ) {
+ function( inputs_float32_pos[ inputNum ] );
+ inputNum = ( inputNum + 1 ) & ( numInputs_float32 - 1 );
+ }
+ count += minIterations;
+ } while ( clock() - startClock < CLOCKS_PER_SEC );
+ inputNum = 0;
+ startClock = clock();
+ for ( i = count; i; --i ) {
+ function( inputs_float32_pos[ inputNum ] );
+ inputNum = ( inputNum + 1 ) & ( numInputs_float32 - 1 );
+ }
+ endClock = clock();
+ reportTime( count, endClock - startClock );
+
+}
+
+enum {
+ numInputs_float64 = 32
+};
+
+static const float64 inputs_float64[ numInputs_float64 ] = {
+ LIT64( 0x422FFFC008000000 ),
+ LIT64( 0xB7E0000480000000 ),
+ LIT64( 0xF3FD2546120B7935 ),
+ LIT64( 0x3FF0000000000000 ),
+ LIT64( 0xCE07F766F09588D6 ),
+ LIT64( 0x8000000000000000 ),
+ LIT64( 0x3FCE000400000000 ),
+ LIT64( 0x8313B60F0032BED8 ),
+ LIT64( 0xC1EFFFFFC0002000 ),
+ LIT64( 0x3FB3C75D224F2B0F ),
+ LIT64( 0x7FD00000004000FF ),
+ LIT64( 0xA12FFF8000001FFF ),
+ LIT64( 0x3EE0000000FE0000 ),
+ LIT64( 0x0010000080000004 ),
+ LIT64( 0x41CFFFFE00000020 ),
+ LIT64( 0x40303FFFFFFFFFFD ),
+ LIT64( 0x3FD000003FEFFFFF ),
+ LIT64( 0xBFD0000010000000 ),
+ LIT64( 0xB7FC6B5C16CA55CF ),
+ LIT64( 0x413EEB940B9D1301 ),
+ LIT64( 0xC7E00200001FFFFF ),
+ LIT64( 0x47F00021FFFFFFFE ),
+ LIT64( 0xBFFFFFFFF80000FF ),
+ LIT64( 0xC07FFFFFE00FFFFF ),
+ LIT64( 0x001497A63740C5E8 ),
+ LIT64( 0xC4BFFFE0001FFFFF ),
+ LIT64( 0x96FFDFFEFFFFFFFF ),
+ LIT64( 0x403FC000000001FE ),
+ LIT64( 0xFFD00000000001F6 ),
+ LIT64( 0x0640400002000000 ),
+ LIT64( 0x479CEE1E4F789FE0 ),
+ LIT64( 0xC237FFFFFFFFFDFE )
+};
+
+static void time_a_float64_z_int32( int32 function( float64 ) )
+{
+ clock_t startClock, endClock;
+ int32 count, i;
+ int8 inputNum;
+
+ count = 0;
+ inputNum = 0;
+ startClock = clock();
+ do {
+ for ( i = minIterations; i; --i ) {
+ function( inputs_float64[ inputNum ] );
+ inputNum = ( inputNum + 1 ) & ( numInputs_float64 - 1 );
+ }
+ count += minIterations;
+ } while ( clock() - startClock < CLOCKS_PER_SEC );
+ inputNum = 0;
+ startClock = clock();
+ for ( i = count; i; --i ) {
+ function( inputs_float64[ inputNum ] );
+ inputNum = ( inputNum + 1 ) & ( numInputs_float64 - 1 );
+ }
+ endClock = clock();
+ reportTime( count, endClock - startClock );
+
+}
+
+static void time_a_float64_z_int64( int64 function( float64 ) )
+{
+ clock_t startClock, endClock;
+ int32 count, i;
+ int8 inputNum;
+
+ count = 0;
+ inputNum = 0;
+ startClock = clock();
+ do {
+ for ( i = minIterations; i; --i ) {
+ function( inputs_float64[ inputNum ] );
+ inputNum = ( inputNum + 1 ) & ( numInputs_float64 - 1 );
+ }
+ count += minIterations;
+ } while ( clock() - startClock < CLOCKS_PER_SEC );
+ inputNum = 0;
+ startClock = clock();
+ for ( i = count; i; --i ) {
+ function( inputs_float64[ inputNum ] );
+ inputNum = ( inputNum + 1 ) & ( numInputs_float64 - 1 );
+ }
+ endClock = clock();
+ reportTime( count, endClock - startClock );
+
+}
+
+static void time_a_float64_z_float32( float32 function( float64 ) )
+{
+ clock_t startClock, endClock;
+ int32 count, i;
+ int8 inputNum;
+
+ count = 0;
+ inputNum = 0;
+ startClock = clock();
+ do {
+ for ( i = minIterations; i; --i ) {
+ function( inputs_float64[ inputNum ] );
+ inputNum = ( inputNum + 1 ) & ( numInputs_float64 - 1 );
+ }
+ count += minIterations;
+ } while ( clock() - startClock < CLOCKS_PER_SEC );
+ inputNum = 0;
+ startClock = clock();
+ for ( i = count; i; --i ) {
+ function( inputs_float64[ inputNum ] );
+ inputNum = ( inputNum + 1 ) & ( numInputs_float64 - 1 );
+ }
+ endClock = clock();
+ reportTime( count, endClock - startClock );
+
+}
+
+#ifdef FLOATX80
+
+static void time_a_float64_z_floatx80( floatx80 function( float64 ) )
+{
+ clock_t startClock, endClock;
+ int32 count, i;
+ int8 inputNum;
+
+ count = 0;
+ inputNum = 0;
+ startClock = clock();
+ do {
+ for ( i = minIterations; i; --i ) {
+ function( inputs_float64[ inputNum ] );
+ inputNum = ( inputNum + 1 ) & ( numInputs_float64 - 1 );
+ }
+ count += minIterations;
+ } while ( clock() - startClock < CLOCKS_PER_SEC );
+ inputNum = 0;
+ startClock = clock();
+ for ( i = count; i; --i ) {
+ function( inputs_float64[ inputNum ] );
+ inputNum = ( inputNum + 1 ) & ( numInputs_float64 - 1 );
+ }
+ endClock = clock();
+ reportTime( count, endClock - startClock );
+
+}
+
+#endif
+
+#ifdef FLOAT128
+
+static void time_a_float64_z_float128( float128 function( float64 ) )
+{
+ clock_t startClock, endClock;
+ int32 count, i;
+ int8 inputNum;
+
+ count = 0;
+ inputNum = 0;
+ startClock = clock();
+ do {
+ for ( i = minIterations; i; --i ) {
+ function( inputs_float64[ inputNum ] );
+ inputNum = ( inputNum + 1 ) & ( numInputs_float64 - 1 );
+ }
+ count += minIterations;
+ } while ( clock() - startClock < CLOCKS_PER_SEC );
+ inputNum = 0;
+ startClock = clock();
+ for ( i = count; i; --i ) {
+ function( inputs_float64[ inputNum ] );
+ inputNum = ( inputNum + 1 ) & ( numInputs_float64 - 1 );
+ }
+ endClock = clock();
+ reportTime( count, endClock - startClock );
+
+}
+
+#endif
+
+static void time_az_float64( float64 function( float64 ) )
+{
+ clock_t startClock, endClock;
+ int32 count, i;
+ int8 inputNum;
+
+ count = 0;
+ inputNum = 0;
+ startClock = clock();
+ do {
+ for ( i = minIterations; i; --i ) {
+ function( inputs_float64[ inputNum ] );
+ inputNum = ( inputNum + 1 ) & ( numInputs_float64 - 1 );
+ }
+ count += minIterations;
+ } while ( clock() - startClock < CLOCKS_PER_SEC );
+ inputNum = 0;
+ startClock = clock();
+ for ( i = count; i; --i ) {
+ function( inputs_float64[ inputNum ] );
+ inputNum = ( inputNum + 1 ) & ( numInputs_float64 - 1 );
+ }
+ endClock = clock();
+ reportTime( count, endClock - startClock );
+
+}
+
+static void time_ab_float64_z_flag( flag function( float64, float64 ) )
+{
+ clock_t startClock, endClock;
+ int32 count, i;
+ int8 inputNumA, inputNumB;
+
+ count = 0;
+ inputNumA = 0;
+ inputNumB = 0;
+ startClock = clock();
+ do {
+ for ( i = minIterations; i; --i ) {
+ function(
+ inputs_float64[ inputNumA ], inputs_float64[ inputNumB ] );
+ inputNumA = ( inputNumA + 1 ) & ( numInputs_float64 - 1 );
+ if ( inputNumA == 0 ) ++inputNumB;
+ inputNumB = ( inputNumB + 1 ) & ( numInputs_float64 - 1 );
+ }
+ count += minIterations;
+ } while ( clock() - startClock < CLOCKS_PER_SEC );
+ inputNumA = 0;
+ inputNumB = 0;
+ startClock = clock();
+ for ( i = count; i; --i ) {
+ function(
+ inputs_float64[ inputNumA ], inputs_float64[ inputNumB ] );
+ inputNumA = ( inputNumA + 1 ) & ( numInputs_float64 - 1 );
+ if ( inputNumA == 0 ) ++inputNumB;
+ inputNumB = ( inputNumB + 1 ) & ( numInputs_float64 - 1 );
+ }
+ endClock = clock();
+ reportTime( count, endClock - startClock );
+
+}
+
+static void time_abz_float64( float64 function( float64, float64 ) )
+{
+ clock_t startClock, endClock;
+ int32 count, i;
+ int8 inputNumA, inputNumB;
+
+ count = 0;
+ inputNumA = 0;
+ inputNumB = 0;
+ startClock = clock();
+ do {
+ for ( i = minIterations; i; --i ) {
+ function(
+ inputs_float64[ inputNumA ], inputs_float64[ inputNumB ] );
+ inputNumA = ( inputNumA + 1 ) & ( numInputs_float64 - 1 );
+ if ( inputNumA == 0 ) ++inputNumB;
+ inputNumB = ( inputNumB + 1 ) & ( numInputs_float64 - 1 );
+ }
+ count += minIterations;
+ } while ( clock() - startClock < CLOCKS_PER_SEC );
+ inputNumA = 0;
+ inputNumB = 0;
+ startClock = clock();
+ for ( i = count; i; --i ) {
+ function(
+ inputs_float64[ inputNumA ], inputs_float64[ inputNumB ] );
+ inputNumA = ( inputNumA + 1 ) & ( numInputs_float64 - 1 );
+ if ( inputNumA == 0 ) ++inputNumB;
+ inputNumB = ( inputNumB + 1 ) & ( numInputs_float64 - 1 );
+ }
+ endClock = clock();
+ reportTime( count, endClock - startClock );
+
+}
+
+static const float64 inputs_float64_pos[ numInputs_float64 ] = {
+ LIT64( 0x422FFFC008000000 ),
+ LIT64( 0x37E0000480000000 ),
+ LIT64( 0x73FD2546120B7935 ),
+ LIT64( 0x3FF0000000000000 ),
+ LIT64( 0x4E07F766F09588D6 ),
+ LIT64( 0x0000000000000000 ),
+ LIT64( 0x3FCE000400000000 ),
+ LIT64( 0x0313B60F0032BED8 ),
+ LIT64( 0x41EFFFFFC0002000 ),
+ LIT64( 0x3FB3C75D224F2B0F ),
+ LIT64( 0x7FD00000004000FF ),
+ LIT64( 0x212FFF8000001FFF ),
+ LIT64( 0x3EE0000000FE0000 ),
+ LIT64( 0x0010000080000004 ),
+ LIT64( 0x41CFFFFE00000020 ),
+ LIT64( 0x40303FFFFFFFFFFD ),
+ LIT64( 0x3FD000003FEFFFFF ),
+ LIT64( 0x3FD0000010000000 ),
+ LIT64( 0x37FC6B5C16CA55CF ),
+ LIT64( 0x413EEB940B9D1301 ),
+ LIT64( 0x47E00200001FFFFF ),
+ LIT64( 0x47F00021FFFFFFFE ),
+ LIT64( 0x3FFFFFFFF80000FF ),
+ LIT64( 0x407FFFFFE00FFFFF ),
+ LIT64( 0x001497A63740C5E8 ),
+ LIT64( 0x44BFFFE0001FFFFF ),
+ LIT64( 0x16FFDFFEFFFFFFFF ),
+ LIT64( 0x403FC000000001FE ),
+ LIT64( 0x7FD00000000001F6 ),
+ LIT64( 0x0640400002000000 ),
+ LIT64( 0x479CEE1E4F789FE0 ),
+ LIT64( 0x4237FFFFFFFFFDFE )
+};
+
+static void time_az_float64_pos( float64 function( float64 ) )
+{
+ clock_t startClock, endClock;
+ int32 count, i;
+ int8 inputNum;
+
+ count = 0;
+ inputNum = 0;
+ startClock = clock();
+ do {
+ for ( i = minIterations; i; --i ) {
+ function( inputs_float64_pos[ inputNum ] );
+ inputNum = ( inputNum + 1 ) & ( numInputs_float64 - 1 );
+ }
+ count += minIterations;
+ } while ( clock() - startClock < CLOCKS_PER_SEC );
+ inputNum = 0;
+ startClock = clock();
+ for ( i = count; i; --i ) {
+ function( inputs_float64_pos[ inputNum ] );
+ inputNum = ( inputNum + 1 ) & ( numInputs_float64 - 1 );
+ }
+ endClock = clock();
+ reportTime( count, endClock - startClock );
+
+}
+
+#ifdef FLOATX80
+
+enum {
+ numInputs_floatx80 = 32
+};
+
+static const struct {
+ bits16 high;
+ bits64 low;
+} inputs_floatx80[ numInputs_floatx80 ] = {
+ { 0xC03F, LIT64( 0xA9BE15A19C1E8B62 ) },
+ { 0x8000, LIT64( 0x0000000000000000 ) },
+ { 0x75A8, LIT64( 0xE59591E4788957A5 ) },
+ { 0xBFFF, LIT64( 0xFFF0000000000040 ) },
+ { 0x0CD8, LIT64( 0xFC000000000007FE ) },
+ { 0x43BA, LIT64( 0x99A4000000000000 ) },
+ { 0x3FFF, LIT64( 0x8000000000000000 ) },
+ { 0x4081, LIT64( 0x94FBF1BCEB5545F0 ) },
+ { 0x403E, LIT64( 0xFFF0000000002000 ) },
+ { 0x3FFE, LIT64( 0xC860E3C75D224F28 ) },
+ { 0x407E, LIT64( 0xFC00000FFFFFFFFE ) },
+ { 0x737A, LIT64( 0x800000007FFDFFFE ) },
+ { 0x4044, LIT64( 0xFFFFFF80000FFFFF ) },
+ { 0xBBFE, LIT64( 0x8000040000001FFE ) },
+ { 0xC002, LIT64( 0xFF80000000000020 ) },
+ { 0xDE8D, LIT64( 0xFFFFFFFFFFE00004 ) },
+ { 0xC004, LIT64( 0x8000000000003FFB ) },
+ { 0x407F, LIT64( 0x800000000003FFFE ) },
+ { 0xC000, LIT64( 0xA459EE6A5C16CA55 ) },
+ { 0x8003, LIT64( 0xC42CBF7399AEEB94 ) },
+ { 0xBF7F, LIT64( 0xF800000000000006 ) },
+ { 0xC07F, LIT64( 0xBF56BE8871F28FEA ) },
+ { 0xC07E, LIT64( 0xFFFF77FFFFFFFFFE ) },
+ { 0xADC9, LIT64( 0x8000000FFFFFFFDE ) },
+ { 0xC001, LIT64( 0xEFF7FFFFFFFFFFFF ) },
+ { 0x4001, LIT64( 0xBE84F30125C497A6 ) },
+ { 0xC06B, LIT64( 0xEFFFFFFFFFFFFFFF ) },
+ { 0x4080, LIT64( 0xFFFFFFFFBFFFFFFF ) },
+ { 0x87E9, LIT64( 0x81FFFFFFFFFFFBFF ) },
+ { 0xA63F, LIT64( 0x801FFFFFFEFFFFFE ) },
+ { 0x403C, LIT64( 0x801FFFFFFFF7FFFF ) },
+ { 0x4018, LIT64( 0x8000000000080003 ) }
+};
+
+static void time_a_floatx80_z_int32( int32 function( floatx80 ) )
+{
+ clock_t startClock, endClock;
+ int32 count, i;
+ int8 inputNum;
+ floatx80 a;
+
+ count = 0;
+ inputNum = 0;
+ startClock = clock();
+ do {
+ for ( i = minIterations; i; --i ) {
+ a.low = inputs_floatx80[ inputNum ].low;
+ a.high = inputs_floatx80[ inputNum ].high;
+ function( a );
+ inputNum = ( inputNum + 1 ) & ( numInputs_floatx80 - 1 );
+ }
+ count += minIterations;
+ } while ( clock() - startClock < CLOCKS_PER_SEC );
+ inputNum = 0;
+ startClock = clock();
+ for ( i = count; i; --i ) {
+ a.low = inputs_floatx80[ inputNum ].low;
+ a.high = inputs_floatx80[ inputNum ].high;
+ function( a );
+ inputNum = ( inputNum + 1 ) & ( numInputs_floatx80 - 1 );
+ }
+ endClock = clock();
+ reportTime( count, endClock - startClock );
+
+}
+
+static void time_a_floatx80_z_int64( int64 function( floatx80 ) )
+{
+ clock_t startClock, endClock;
+ int32 count, i;
+ int8 inputNum;
+ floatx80 a;
+
+ count = 0;
+ inputNum = 0;
+ startClock = clock();
+ do {
+ for ( i = minIterations; i; --i ) {
+ a.low = inputs_floatx80[ inputNum ].low;
+ a.high = inputs_floatx80[ inputNum ].high;
+ function( a );
+ inputNum = ( inputNum + 1 ) & ( numInputs_floatx80 - 1 );
+ }
+ count += minIterations;
+ } while ( clock() - startClock < CLOCKS_PER_SEC );
+ inputNum = 0;
+ startClock = clock();
+ for ( i = count; i; --i ) {
+ a.low = inputs_floatx80[ inputNum ].low;
+ a.high = inputs_floatx80[ inputNum ].high;
+ function( a );
+ inputNum = ( inputNum + 1 ) & ( numInputs_floatx80 - 1 );
+ }
+ endClock = clock();
+ reportTime( count, endClock - startClock );
+
+}
+
+static void time_a_floatx80_z_float32( float32 function( floatx80 ) )
+{
+ clock_t startClock, endClock;
+ int32 count, i;
+ int8 inputNum;
+ floatx80 a;
+
+ count = 0;
+ inputNum = 0;
+ startClock = clock();
+ do {
+ for ( i = minIterations; i; --i ) {
+ a.low = inputs_floatx80[ inputNum ].low;
+ a.high = inputs_floatx80[ inputNum ].high;
+ function( a );
+ inputNum = ( inputNum + 1 ) & ( numInputs_floatx80 - 1 );
+ }
+ count += minIterations;
+ } while ( clock() - startClock < CLOCKS_PER_SEC );
+ inputNum = 0;
+ startClock = clock();
+ for ( i = count; i; --i ) {
+ a.low = inputs_floatx80[ inputNum ].low;
+ a.high = inputs_floatx80[ inputNum ].high;
+ function( a );
+ inputNum = ( inputNum + 1 ) & ( numInputs_floatx80 - 1 );
+ }
+ endClock = clock();
+ reportTime( count, endClock - startClock );
+
+}
+
+static void time_a_floatx80_z_float64( float64 function( floatx80 ) )
+{
+ clock_t startClock, endClock;
+ int32 count, i;
+ int8 inputNum;
+ floatx80 a;
+
+ count = 0;
+ inputNum = 0;
+ startClock = clock();
+ do {
+ for ( i = minIterations; i; --i ) {
+ a.low = inputs_floatx80[ inputNum ].low;
+ a.high = inputs_floatx80[ inputNum ].high;
+ function( a );
+ inputNum = ( inputNum + 1 ) & ( numInputs_floatx80 - 1 );
+ }
+ count += minIterations;
+ } while ( clock() - startClock < CLOCKS_PER_SEC );
+ inputNum = 0;
+ startClock = clock();
+ for ( i = count; i; --i ) {
+ a.low = inputs_floatx80[ inputNum ].low;
+ a.high = inputs_floatx80[ inputNum ].high;
+ function( a );
+ inputNum = ( inputNum + 1 ) & ( numInputs_floatx80 - 1 );
+ }
+ endClock = clock();
+ reportTime( count, endClock - startClock );
+
+}
+
+#ifdef FLOAT128
+
+static void time_a_floatx80_z_float128( float128 function( floatx80 ) )
+{
+ clock_t startClock, endClock;
+ int32 count, i;
+ int8 inputNum;
+ floatx80 a;
+
+ count = 0;
+ inputNum = 0;
+ startClock = clock();
+ do {
+ for ( i = minIterations; i; --i ) {
+ a.low = inputs_floatx80[ inputNum ].low;
+ a.high = inputs_floatx80[ inputNum ].high;
+ function( a );
+ inputNum = ( inputNum + 1 ) & ( numInputs_floatx80 - 1 );
+ }
+ count += minIterations;
+ } while ( clock() - startClock < CLOCKS_PER_SEC );
+ inputNum = 0;
+ startClock = clock();
+ for ( i = count; i; --i ) {
+ a.low = inputs_floatx80[ inputNum ].low;
+ a.high = inputs_floatx80[ inputNum ].high;
+ function( a );
+ inputNum = ( inputNum + 1 ) & ( numInputs_floatx80 - 1 );
+ }
+ endClock = clock();
+ reportTime( count, endClock - startClock );
+
+}
+
+#endif
+
+static void time_az_floatx80( floatx80 function( floatx80 ) )
+{
+ clock_t startClock, endClock;
+ int32 count, i;
+ int8 inputNum;
+ floatx80 a;
+
+ count = 0;
+ inputNum = 0;
+ startClock = clock();
+ do {
+ for ( i = minIterations; i; --i ) {
+ a.low = inputs_floatx80[ inputNum ].low;
+ a.high = inputs_floatx80[ inputNum ].high;
+ function( a );
+ inputNum = ( inputNum + 1 ) & ( numInputs_floatx80 - 1 );
+ }
+ count += minIterations;
+ } while ( clock() - startClock < CLOCKS_PER_SEC );
+ inputNum = 0;
+ startClock = clock();
+ for ( i = count; i; --i ) {
+ a.low = inputs_floatx80[ inputNum ].low;
+ a.high = inputs_floatx80[ inputNum ].high;
+ function( a );
+ inputNum = ( inputNum + 1 ) & ( numInputs_floatx80 - 1 );
+ }
+ endClock = clock();
+ reportTime( count, endClock - startClock );
+
+}
+
+static void time_ab_floatx80_z_flag( flag function( floatx80, floatx80 ) )
+{
+ clock_t startClock, endClock;
+ int32 count, i;
+ int8 inputNumA, inputNumB;
+ floatx80 a, b;
+
+ count = 0;
+ inputNumA = 0;
+ inputNumB = 0;
+ startClock = clock();
+ do {
+ for ( i = minIterations; i; --i ) {
+ a.low = inputs_floatx80[ inputNumA ].low;
+ a.high = inputs_floatx80[ inputNumA ].high;
+ b.low = inputs_floatx80[ inputNumB ].low;
+ b.high = inputs_floatx80[ inputNumB ].high;
+ function( a, b );
+ inputNumA = ( inputNumA + 1 ) & ( numInputs_floatx80 - 1 );
+ if ( inputNumA == 0 ) ++inputNumB;
+ inputNumB = ( inputNumB + 1 ) & ( numInputs_floatx80 - 1 );
+ }
+ count += minIterations;
+ } while ( clock() - startClock < CLOCKS_PER_SEC );
+ inputNumA = 0;
+ inputNumB = 0;
+ startClock = clock();
+ for ( i = count; i; --i ) {
+ a.low = inputs_floatx80[ inputNumA ].low;
+ a.high = inputs_floatx80[ inputNumA ].high;
+ b.low = inputs_floatx80[ inputNumB ].low;
+ b.high = inputs_floatx80[ inputNumB ].high;
+ function( a, b );
+ inputNumA = ( inputNumA + 1 ) & ( numInputs_floatx80 - 1 );
+ if ( inputNumA == 0 ) ++inputNumB;
+ inputNumB = ( inputNumB + 1 ) & ( numInputs_floatx80 - 1 );
+ }
+ endClock = clock();
+ reportTime( count, endClock - startClock );
+
+}
+
+static void time_abz_floatx80( floatx80 function( floatx80, floatx80 ) )
+{
+ clock_t startClock, endClock;
+ int32 count, i;
+ int8 inputNumA, inputNumB;
+ floatx80 a, b;
+
+ count = 0;
+ inputNumA = 0;
+ inputNumB = 0;
+ startClock = clock();
+ do {
+ for ( i = minIterations; i; --i ) {
+ a.low = inputs_floatx80[ inputNumA ].low;
+ a.high = inputs_floatx80[ inputNumA ].high;
+ b.low = inputs_floatx80[ inputNumB ].low;
+ b.high = inputs_floatx80[ inputNumB ].high;
+ function( a, b );
+ inputNumA = ( inputNumA + 1 ) & ( numInputs_floatx80 - 1 );
+ if ( inputNumA == 0 ) ++inputNumB;
+ inputNumB = ( inputNumB + 1 ) & ( numInputs_floatx80 - 1 );
+ }
+ count += minIterations;
+ } while ( clock() - startClock < CLOCKS_PER_SEC );
+ inputNumA = 0;
+ inputNumB = 0;
+ startClock = clock();
+ for ( i = count; i; --i ) {
+ a.low = inputs_floatx80[ inputNumA ].low;
+ a.high = inputs_floatx80[ inputNumA ].high;
+ b.low = inputs_floatx80[ inputNumB ].low;
+ b.high = inputs_floatx80[ inputNumB ].high;
+ function( a, b );
+ inputNumA = ( inputNumA + 1 ) & ( numInputs_floatx80 - 1 );
+ if ( inputNumA == 0 ) ++inputNumB;
+ inputNumB = ( inputNumB + 1 ) & ( numInputs_floatx80 - 1 );
+ }
+ endClock = clock();
+ reportTime( count, endClock - startClock );
+
+}
+
+static const struct {
+ bits16 high;
+ bits64 low;
+} inputs_floatx80_pos[ numInputs_floatx80 ] = {
+ { 0x403F, LIT64( 0xA9BE15A19C1E8B62 ) },
+ { 0x0000, LIT64( 0x0000000000000000 ) },
+ { 0x75A8, LIT64( 0xE59591E4788957A5 ) },
+ { 0x3FFF, LIT64( 0xFFF0000000000040 ) },
+ { 0x0CD8, LIT64( 0xFC000000000007FE ) },
+ { 0x43BA, LIT64( 0x99A4000000000000 ) },
+ { 0x3FFF, LIT64( 0x8000000000000000 ) },
+ { 0x4081, LIT64( 0x94FBF1BCEB5545F0 ) },
+ { 0x403E, LIT64( 0xFFF0000000002000 ) },
+ { 0x3FFE, LIT64( 0xC860E3C75D224F28 ) },
+ { 0x407E, LIT64( 0xFC00000FFFFFFFFE ) },
+ { 0x737A, LIT64( 0x800000007FFDFFFE ) },
+ { 0x4044, LIT64( 0xFFFFFF80000FFFFF ) },
+ { 0x3BFE, LIT64( 0x8000040000001FFE ) },
+ { 0x4002, LIT64( 0xFF80000000000020 ) },
+ { 0x5E8D, LIT64( 0xFFFFFFFFFFE00004 ) },
+ { 0x4004, LIT64( 0x8000000000003FFB ) },
+ { 0x407F, LIT64( 0x800000000003FFFE ) },
+ { 0x4000, LIT64( 0xA459EE6A5C16CA55 ) },
+ { 0x0003, LIT64( 0xC42CBF7399AEEB94 ) },
+ { 0x3F7F, LIT64( 0xF800000000000006 ) },
+ { 0x407F, LIT64( 0xBF56BE8871F28FEA ) },
+ { 0x407E, LIT64( 0xFFFF77FFFFFFFFFE ) },
+ { 0x2DC9, LIT64( 0x8000000FFFFFFFDE ) },
+ { 0x4001, LIT64( 0xEFF7FFFFFFFFFFFF ) },
+ { 0x4001, LIT64( 0xBE84F30125C497A6 ) },
+ { 0x406B, LIT64( 0xEFFFFFFFFFFFFFFF ) },
+ { 0x4080, LIT64( 0xFFFFFFFFBFFFFFFF ) },
+ { 0x07E9, LIT64( 0x81FFFFFFFFFFFBFF ) },
+ { 0x263F, LIT64( 0x801FFFFFFEFFFFFE ) },
+ { 0x403C, LIT64( 0x801FFFFFFFF7FFFF ) },
+ { 0x4018, LIT64( 0x8000000000080003 ) }
+};
+
+static void time_az_floatx80_pos( floatx80 function( floatx80 ) )
+{
+ clock_t startClock, endClock;
+ int32 count, i;
+ int8 inputNum;
+ floatx80 a;
+
+ count = 0;
+ inputNum = 0;
+ startClock = clock();
+ do {
+ for ( i = minIterations; i; --i ) {
+ a.low = inputs_floatx80_pos[ inputNum ].low;
+ a.high = inputs_floatx80_pos[ inputNum ].high;
+ function( a );
+ inputNum = ( inputNum + 1 ) & ( numInputs_floatx80 - 1 );
+ }
+ count += minIterations;
+ } while ( clock() - startClock < CLOCKS_PER_SEC );
+ inputNum = 0;
+ startClock = clock();
+ for ( i = count; i; --i ) {
+ a.low = inputs_floatx80_pos[ inputNum ].low;
+ a.high = inputs_floatx80_pos[ inputNum ].high;
+ function( a );
+ inputNum = ( inputNum + 1 ) & ( numInputs_floatx80 - 1 );
+ }
+ endClock = clock();
+ reportTime( count, endClock - startClock );
+
+}
+
+#endif
+
+#ifdef FLOAT128
+
+enum {
+ numInputs_float128 = 32
+};
+
+static const struct {
+ bits64 high, low;
+} inputs_float128[ numInputs_float128 ] = {
+ { LIT64( 0x3FDA200000100000 ), LIT64( 0x0000000000000000 ) },
+ { LIT64( 0x3FFF000000000000 ), LIT64( 0x0000000000000000 ) },
+ { LIT64( 0x85F14776190C8306 ), LIT64( 0xD8715F4E3D54BB92 ) },
+ { LIT64( 0xF2B00000007FFFFF ), LIT64( 0xFFFFFFFFFFF7FFFF ) },
+ { LIT64( 0x8000000000000000 ), LIT64( 0x0000000000000000 ) },
+ { LIT64( 0xBFFFFFFFFFE00000 ), LIT64( 0x0000008000000000 ) },
+ { LIT64( 0x407F1719CE722F3E ), LIT64( 0xDA6B3FE5FF29425B ) },
+ { LIT64( 0x43FFFF8000000000 ), LIT64( 0x0000000000400000 ) },
+ { LIT64( 0x401E000000000100 ), LIT64( 0x0000000000002000 ) },
+ { LIT64( 0x3FFED71DACDA8E47 ), LIT64( 0x4860E3C75D224F28 ) },
+ { LIT64( 0xBF7ECFC1E90647D1 ), LIT64( 0x7A124FE55623EE44 ) },
+ { LIT64( 0x0DF7007FFFFFFFFF ), LIT64( 0xFFFFFFFFEFFFFFFF ) },
+ { LIT64( 0x3FE5FFEFFFFFFFFF ), LIT64( 0xFFFFFFFFFFFFEFFF ) },
+ { LIT64( 0x403FFFFFFFFFFFFF ), LIT64( 0xFFFFFFFFFFFFFBFE ) },
+ { LIT64( 0xBFFB2FBF7399AFEB ), LIT64( 0xA459EE6A5C16CA55 ) },
+ { LIT64( 0xBDB8FFFFFFFFFFFC ), LIT64( 0x0000000000000400 ) },
+ { LIT64( 0x3FC8FFDFFFFFFFFF ), LIT64( 0xFFFFFFFFF0000000 ) },
+ { LIT64( 0x3FFBFFFFFFDFFFFF ), LIT64( 0xFFF8000000000000 ) },
+ { LIT64( 0x407043C11737BE84 ), LIT64( 0xDDD58212ADC937F4 ) },
+ { LIT64( 0x8001000000000000 ), LIT64( 0x0000001000000001 ) },
+ { LIT64( 0xC036FFFFFFFFFFFF ), LIT64( 0xFE40000000000000 ) },
+ { LIT64( 0x4002FFFFFE000002 ), LIT64( 0x0000000000000000 ) },
+ { LIT64( 0x4000C3FEDE897773 ), LIT64( 0x326AC4FD8EFBE6DC ) },
+ { LIT64( 0xBFFF0000000FFFFF ), LIT64( 0xFFFFFE0000000000 ) },
+ { LIT64( 0x62C3E502146E426D ), LIT64( 0x43F3CAA0DC7DF1A0 ) },
+ { LIT64( 0xB5CBD32E52BB570E ), LIT64( 0xBCC477CB11C6236C ) },
+ { LIT64( 0xE228FFFFFFC00000 ), LIT64( 0x0000000000000000 ) },
+ { LIT64( 0x3F80000000000000 ), LIT64( 0x0000000080000008 ) },
+ { LIT64( 0xC1AFFFDFFFFFFFFF ), LIT64( 0xFFFC000000000000 ) },
+ { LIT64( 0xC96F000000000000 ), LIT64( 0x00000001FFFBFFFF ) },
+ { LIT64( 0x3DE09BFE7923A338 ), LIT64( 0xBCC8FBBD7CEC1F4F ) },
+ { LIT64( 0x401CFFFFFFFFFFFF ), LIT64( 0xFFFFFFFEFFFFFF80 ) }
+};
+
+static void time_a_float128_z_int32( int32 function( float128 ) )
+{
+ clock_t startClock, endClock;
+ int32 count, i;
+ int8 inputNum;
+ float128 a;
+
+ count = 0;
+ inputNum = 0;
+ startClock = clock();
+ do {
+ for ( i = minIterations; i; --i ) {
+ a.low = inputs_float128[ inputNum ].low;
+ a.high = inputs_float128[ inputNum ].high;
+ function( a );
+ inputNum = ( inputNum + 1 ) & ( numInputs_float128 - 1 );
+ }
+ count += minIterations;
+ } while ( clock() - startClock < CLOCKS_PER_SEC );
+ inputNum = 0;
+ startClock = clock();
+ for ( i = count; i; --i ) {
+ a.low = inputs_float128[ inputNum ].low;
+ a.high = inputs_float128[ inputNum ].high;
+ function( a );
+ inputNum = ( inputNum + 1 ) & ( numInputs_float128 - 1 );
+ }
+ endClock = clock();
+ reportTime( count, endClock - startClock );
+
+}
+
+static void time_a_float128_z_int64( int64 function( float128 ) )
+{
+ clock_t startClock, endClock;
+ int32 count, i;
+ int8 inputNum;
+ float128 a;
+
+ count = 0;
+ inputNum = 0;
+ startClock = clock();
+ do {
+ for ( i = minIterations; i; --i ) {
+ a.low = inputs_float128[ inputNum ].low;
+ a.high = inputs_float128[ inputNum ].high;
+ function( a );
+ inputNum = ( inputNum + 1 ) & ( numInputs_float128 - 1 );
+ }
+ count += minIterations;
+ } while ( clock() - startClock < CLOCKS_PER_SEC );
+ inputNum = 0;
+ startClock = clock();
+ for ( i = count; i; --i ) {
+ a.low = inputs_float128[ inputNum ].low;
+ a.high = inputs_float128[ inputNum ].high;
+ function( a );
+ inputNum = ( inputNum + 1 ) & ( numInputs_float128 - 1 );
+ }
+ endClock = clock();
+ reportTime( count, endClock - startClock );
+
+}
+
+static void time_a_float128_z_float32( float32 function( float128 ) )
+{
+ clock_t startClock, endClock;
+ int32 count, i;
+ int8 inputNum;
+ float128 a;
+
+ count = 0;
+ inputNum = 0;
+ startClock = clock();
+ do {
+ for ( i = minIterations; i; --i ) {
+ a.low = inputs_float128[ inputNum ].low;
+ a.high = inputs_float128[ inputNum ].high;
+ function( a );
+ inputNum = ( inputNum + 1 ) & ( numInputs_float128 - 1 );
+ }
+ count += minIterations;
+ } while ( clock() - startClock < CLOCKS_PER_SEC );
+ inputNum = 0;
+ startClock = clock();
+ for ( i = count; i; --i ) {
+ a.low = inputs_float128[ inputNum ].low;
+ a.high = inputs_float128[ inputNum ].high;
+ function( a );
+ inputNum = ( inputNum + 1 ) & ( numInputs_float128 - 1 );
+ }
+ endClock = clock();
+ reportTime( count, endClock - startClock );
+
+}
+
+static void time_a_float128_z_float64( float64 function( float128 ) )
+{
+ clock_t startClock, endClock;
+ int32 count, i;
+ int8 inputNum;
+ float128 a;
+
+ count = 0;
+ inputNum = 0;
+ startClock = clock();
+ do {
+ for ( i = minIterations; i; --i ) {
+ a.low = inputs_float128[ inputNum ].low;
+ a.high = inputs_float128[ inputNum ].high;
+ function( a );
+ inputNum = ( inputNum + 1 ) & ( numInputs_float128 - 1 );
+ }
+ count += minIterations;
+ } while ( clock() - startClock < CLOCKS_PER_SEC );
+ inputNum = 0;
+ startClock = clock();
+ for ( i = count; i; --i ) {
+ a.low = inputs_float128[ inputNum ].low;
+ a.high = inputs_float128[ inputNum ].high;
+ function( a );
+ inputNum = ( inputNum + 1 ) & ( numInputs_float128 - 1 );
+ }
+ endClock = clock();
+ reportTime( count, endClock - startClock );
+
+}
+
+#ifdef FLOATX80
+
+static void time_a_float128_z_floatx80( floatx80 function( float128 ) )
+{
+ clock_t startClock, endClock;
+ int32 count, i;
+ int8 inputNum;
+ float128 a;
+
+ count = 0;
+ inputNum = 0;
+ startClock = clock();
+ do {
+ for ( i = minIterations; i; --i ) {
+ a.low = inputs_float128[ inputNum ].low;
+ a.high = inputs_float128[ inputNum ].high;
+ function( a );
+ inputNum = ( inputNum + 1 ) & ( numInputs_float128 - 1 );
+ }
+ count += minIterations;
+ } while ( clock() - startClock < CLOCKS_PER_SEC );
+ inputNum = 0;
+ startClock = clock();
+ for ( i = count; i; --i ) {
+ a.low = inputs_float128[ inputNum ].low;
+ a.high = inputs_float128[ inputNum ].high;
+ function( a );
+ inputNum = ( inputNum + 1 ) & ( numInputs_float128 - 1 );
+ }
+ endClock = clock();
+ reportTime( count, endClock - startClock );
+
+}
+
+#endif
+
+static void time_az_float128( float128 function( float128 ) )
+{
+ clock_t startClock, endClock;
+ int32 count, i;
+ int8 inputNum;
+ float128 a;
+
+ count = 0;
+ inputNum = 0;
+ startClock = clock();
+ do {
+ for ( i = minIterations; i; --i ) {
+ a.low = inputs_float128[ inputNum ].low;
+ a.high = inputs_float128[ inputNum ].high;
+ function( a );
+ inputNum = ( inputNum + 1 ) & ( numInputs_float128 - 1 );
+ }
+ count += minIterations;
+ } while ( clock() - startClock < CLOCKS_PER_SEC );
+ inputNum = 0;
+ startClock = clock();
+ for ( i = count; i; --i ) {
+ a.low = inputs_float128[ inputNum ].low;
+ a.high = inputs_float128[ inputNum ].high;
+ function( a );
+ inputNum = ( inputNum + 1 ) & ( numInputs_float128 - 1 );
+ }
+ endClock = clock();
+ reportTime( count, endClock - startClock );
+
+}
+
+static void time_ab_float128_z_flag( flag function( float128, float128 ) )
+{
+ clock_t startClock, endClock;
+ int32 count, i;
+ int8 inputNumA, inputNumB;
+ float128 a, b;
+
+ count = 0;
+ inputNumA = 0;
+ inputNumB = 0;
+ startClock = clock();
+ do {
+ for ( i = minIterations; i; --i ) {
+ a.low = inputs_float128[ inputNumA ].low;
+ a.high = inputs_float128[ inputNumA ].high;
+ b.low = inputs_float128[ inputNumB ].low;
+ b.high = inputs_float128[ inputNumB ].high;
+ function( a, b );
+ inputNumA = ( inputNumA + 1 ) & ( numInputs_float128 - 1 );
+ if ( inputNumA == 0 ) ++inputNumB;
+ inputNumB = ( inputNumB + 1 ) & ( numInputs_float128 - 1 );
+ }
+ count += minIterations;
+ } while ( clock() - startClock < CLOCKS_PER_SEC );
+ inputNumA = 0;
+ inputNumB = 0;
+ startClock = clock();
+ for ( i = count; i; --i ) {
+ a.low = inputs_float128[ inputNumA ].low;
+ a.high = inputs_float128[ inputNumA ].high;
+ b.low = inputs_float128[ inputNumB ].low;
+ b.high = inputs_float128[ inputNumB ].high;
+ function( a, b );
+ inputNumA = ( inputNumA + 1 ) & ( numInputs_float128 - 1 );
+ if ( inputNumA == 0 ) ++inputNumB;
+ inputNumB = ( inputNumB + 1 ) & ( numInputs_float128 - 1 );
+ }
+ endClock = clock();
+ reportTime( count, endClock - startClock );
+
+}
+
+static void time_abz_float128( float128 function( float128, float128 ) )
+{
+ clock_t startClock, endClock;
+ int32 count, i;
+ int8 inputNumA, inputNumB;
+ float128 a, b;
+
+ count = 0;
+ inputNumA = 0;
+ inputNumB = 0;
+ startClock = clock();
+ do {
+ for ( i = minIterations; i; --i ) {
+ a.low = inputs_float128[ inputNumA ].low;
+ a.high = inputs_float128[ inputNumA ].high;
+ b.low = inputs_float128[ inputNumB ].low;
+ b.high = inputs_float128[ inputNumB ].high;
+ function( a, b );
+ inputNumA = ( inputNumA + 1 ) & ( numInputs_float128 - 1 );
+ if ( inputNumA == 0 ) ++inputNumB;
+ inputNumB = ( inputNumB + 1 ) & ( numInputs_float128 - 1 );
+ }
+ count += minIterations;
+ } while ( clock() - startClock < CLOCKS_PER_SEC );
+ inputNumA = 0;
+ inputNumB = 0;
+ startClock = clock();
+ for ( i = count; i; --i ) {
+ a.low = inputs_float128[ inputNumA ].low;
+ a.high = inputs_float128[ inputNumA ].high;
+ b.low = inputs_float128[ inputNumB ].low;
+ b.high = inputs_float128[ inputNumB ].high;
+ function( a, b );
+ inputNumA = ( inputNumA + 1 ) & ( numInputs_float128 - 1 );
+ if ( inputNumA == 0 ) ++inputNumB;
+ inputNumB = ( inputNumB + 1 ) & ( numInputs_float128 - 1 );
+ }
+ endClock = clock();
+ reportTime( count, endClock - startClock );
+
+}
+
+static const struct {
+ bits64 high, low;
+} inputs_float128_pos[ numInputs_float128 ] = {
+ { LIT64( 0x3FDA200000100000 ), LIT64( 0x0000000000000000 ) },
+ { LIT64( 0x3FFF000000000000 ), LIT64( 0x0000000000000000 ) },
+ { LIT64( 0x05F14776190C8306 ), LIT64( 0xD8715F4E3D54BB92 ) },
+ { LIT64( 0x72B00000007FFFFF ), LIT64( 0xFFFFFFFFFFF7FFFF ) },
+ { LIT64( 0x0000000000000000 ), LIT64( 0x0000000000000000 ) },
+ { LIT64( 0x3FFFFFFFFFE00000 ), LIT64( 0x0000008000000000 ) },
+ { LIT64( 0x407F1719CE722F3E ), LIT64( 0xDA6B3FE5FF29425B ) },
+ { LIT64( 0x43FFFF8000000000 ), LIT64( 0x0000000000400000 ) },
+ { LIT64( 0x401E000000000100 ), LIT64( 0x0000000000002000 ) },
+ { LIT64( 0x3FFED71DACDA8E47 ), LIT64( 0x4860E3C75D224F28 ) },
+ { LIT64( 0x3F7ECFC1E90647D1 ), LIT64( 0x7A124FE55623EE44 ) },
+ { LIT64( 0x0DF7007FFFFFFFFF ), LIT64( 0xFFFFFFFFEFFFFFFF ) },
+ { LIT64( 0x3FE5FFEFFFFFFFFF ), LIT64( 0xFFFFFFFFFFFFEFFF ) },
+ { LIT64( 0x403FFFFFFFFFFFFF ), LIT64( 0xFFFFFFFFFFFFFBFE ) },
+ { LIT64( 0x3FFB2FBF7399AFEB ), LIT64( 0xA459EE6A5C16CA55 ) },
+ { LIT64( 0x3DB8FFFFFFFFFFFC ), LIT64( 0x0000000000000400 ) },
+ { LIT64( 0x3FC8FFDFFFFFFFFF ), LIT64( 0xFFFFFFFFF0000000 ) },
+ { LIT64( 0x3FFBFFFFFFDFFFFF ), LIT64( 0xFFF8000000000000 ) },
+ { LIT64( 0x407043C11737BE84 ), LIT64( 0xDDD58212ADC937F4 ) },
+ { LIT64( 0x0001000000000000 ), LIT64( 0x0000001000000001 ) },
+ { LIT64( 0x4036FFFFFFFFFFFF ), LIT64( 0xFE40000000000000 ) },
+ { LIT64( 0x4002FFFFFE000002 ), LIT64( 0x0000000000000000 ) },
+ { LIT64( 0x4000C3FEDE897773 ), LIT64( 0x326AC4FD8EFBE6DC ) },
+ { LIT64( 0x3FFF0000000FFFFF ), LIT64( 0xFFFFFE0000000000 ) },
+ { LIT64( 0x62C3E502146E426D ), LIT64( 0x43F3CAA0DC7DF1A0 ) },
+ { LIT64( 0x35CBD32E52BB570E ), LIT64( 0xBCC477CB11C6236C ) },
+ { LIT64( 0x6228FFFFFFC00000 ), LIT64( 0x0000000000000000 ) },
+ { LIT64( 0x3F80000000000000 ), LIT64( 0x0000000080000008 ) },
+ { LIT64( 0x41AFFFDFFFFFFFFF ), LIT64( 0xFFFC000000000000 ) },
+ { LIT64( 0x496F000000000000 ), LIT64( 0x00000001FFFBFFFF ) },
+ { LIT64( 0x3DE09BFE7923A338 ), LIT64( 0xBCC8FBBD7CEC1F4F ) },
+ { LIT64( 0x401CFFFFFFFFFFFF ), LIT64( 0xFFFFFFFEFFFFFF80 ) }
+};
+
+static void time_az_float128_pos( float128 function( float128 ) )
+{
+ clock_t startClock, endClock;
+ int32 count, i;
+ int8 inputNum;
+ float128 a;
+
+ count = 0;
+ inputNum = 0;
+ startClock = clock();
+ do {
+ for ( i = minIterations; i; --i ) {
+ a.low = inputs_float128_pos[ inputNum ].low;
+ a.high = inputs_float128_pos[ inputNum ].high;
+ function( a );
+ inputNum = ( inputNum + 1 ) & ( numInputs_float128 - 1 );
+ }
+ count += minIterations;
+ } while ( clock() - startClock < CLOCKS_PER_SEC );
+ inputNum = 0;
+ startClock = clock();
+ for ( i = count; i; --i ) {
+ a.low = inputs_float128_pos[ inputNum ].low;
+ a.high = inputs_float128_pos[ inputNum ].high;
+ function( a );
+ inputNum = ( inputNum + 1 ) & ( numInputs_float128 - 1 );
+ }
+ endClock = clock();
+ reportTime( count, endClock - startClock );
+
+}
+
+#endif
+
+enum {
+ INT32_TO_FLOAT32 = 1,
+ INT32_TO_FLOAT64,
+#ifdef FLOATX80
+ INT32_TO_FLOATX80,
+#endif
+#ifdef FLOAT128
+ INT32_TO_FLOAT128,
+#endif
+ INT64_TO_FLOAT32,
+ INT64_TO_FLOAT64,
+#ifdef FLOATX80
+ INT64_TO_FLOATX80,
+#endif
+#ifdef FLOAT128
+ INT64_TO_FLOAT128,
+#endif
+ FLOAT32_TO_INT32,
+ FLOAT32_TO_INT32_ROUND_TO_ZERO,
+ FLOAT32_TO_INT64,
+ FLOAT32_TO_INT64_ROUND_TO_ZERO,
+ FLOAT32_TO_FLOAT64,
+#ifdef FLOATX80
+ FLOAT32_TO_FLOATX80,
+#endif
+#ifdef FLOAT128
+ FLOAT32_TO_FLOAT128,
+#endif
+ FLOAT32_ROUND_TO_INT,
+ FLOAT32_ADD,
+ FLOAT32_SUB,
+ FLOAT32_MUL,
+ FLOAT32_DIV,
+ FLOAT32_REM,
+ FLOAT32_SQRT,
+ FLOAT32_EQ,
+ FLOAT32_LE,
+ FLOAT32_LT,
+ FLOAT32_EQ_SIGNALING,
+ FLOAT32_LE_QUIET,
+ FLOAT32_LT_QUIET,
+ FLOAT64_TO_INT32,
+ FLOAT64_TO_INT32_ROUND_TO_ZERO,
+ FLOAT64_TO_INT64,
+ FLOAT64_TO_INT64_ROUND_TO_ZERO,
+ FLOAT64_TO_FLOAT32,
+#ifdef FLOATX80
+ FLOAT64_TO_FLOATX80,
+#endif
+#ifdef FLOAT128
+ FLOAT64_TO_FLOAT128,
+#endif
+ FLOAT64_ROUND_TO_INT,
+ FLOAT64_ADD,
+ FLOAT64_SUB,
+ FLOAT64_MUL,
+ FLOAT64_DIV,
+ FLOAT64_REM,
+ FLOAT64_SQRT,
+ FLOAT64_EQ,
+ FLOAT64_LE,
+ FLOAT64_LT,
+ FLOAT64_EQ_SIGNALING,
+ FLOAT64_LE_QUIET,
+ FLOAT64_LT_QUIET,
+#ifdef FLOATX80
+ FLOATX80_TO_INT32,
+ FLOATX80_TO_INT32_ROUND_TO_ZERO,
+ FLOATX80_TO_INT64,
+ FLOATX80_TO_INT64_ROUND_TO_ZERO,
+ FLOATX80_TO_FLOAT32,
+ FLOATX80_TO_FLOAT64,
+#ifdef FLOAT128
+ FLOATX80_TO_FLOAT128,
+#endif
+ FLOATX80_ROUND_TO_INT,
+ FLOATX80_ADD,
+ FLOATX80_SUB,
+ FLOATX80_MUL,
+ FLOATX80_DIV,
+ FLOATX80_REM,
+ FLOATX80_SQRT,
+ FLOATX80_EQ,
+ FLOATX80_LE,
+ FLOATX80_LT,
+ FLOATX80_EQ_SIGNALING,
+ FLOATX80_LE_QUIET,
+ FLOATX80_LT_QUIET,
+#endif
+#ifdef FLOAT128
+ FLOAT128_TO_INT32,
+ FLOAT128_TO_INT32_ROUND_TO_ZERO,
+ FLOAT128_TO_INT64,
+ FLOAT128_TO_INT64_ROUND_TO_ZERO,
+ FLOAT128_TO_FLOAT32,
+ FLOAT128_TO_FLOAT64,
+#ifdef FLOATX80
+ FLOAT128_TO_FLOATX80,
+#endif
+ FLOAT128_ROUND_TO_INT,
+ FLOAT128_ADD,
+ FLOAT128_SUB,
+ FLOAT128_MUL,
+ FLOAT128_DIV,
+ FLOAT128_REM,
+ FLOAT128_SQRT,
+ FLOAT128_EQ,
+ FLOAT128_LE,
+ FLOAT128_LT,
+ FLOAT128_EQ_SIGNALING,
+ FLOAT128_LE_QUIET,
+ FLOAT128_LT_QUIET,
+#endif
+ NUM_FUNCTIONS
+};
+
+static struct {
+ char *name;
+ int8 numInputs;
+ flag roundingPrecision, roundingMode;
+ flag tininessMode, tininessModeAtReducedPrecision;
+} functions[ NUM_FUNCTIONS ] = {
+ { 0, 0, 0, 0, 0, 0 },
+ { "int32_to_float32", 1, FALSE, TRUE, FALSE, FALSE },
+ { "int32_to_float64", 1, FALSE, FALSE, FALSE, FALSE },
+#ifdef FLOATX80
+ { "int32_to_floatx80", 1, FALSE, FALSE, FALSE, FALSE },
+#endif
+#ifdef FLOAT128
+ { "int32_to_float128", 1, FALSE, FALSE, FALSE, FALSE },
+#endif
+ { "int64_to_float32", 1, FALSE, TRUE, FALSE, FALSE },
+ { "int64_to_float64", 1, FALSE, TRUE, FALSE, FALSE },
+#ifdef FLOATX80
+ { "int64_to_floatx80", 1, FALSE, FALSE, FALSE, FALSE },
+#endif
+#ifdef FLOAT128
+ { "int64_to_float128", 1, FALSE, FALSE, FALSE, FALSE },
+#endif
+ { "float32_to_int32", 1, FALSE, TRUE, FALSE, FALSE },
+ { "float32_to_int32_round_to_zero", 1, FALSE, FALSE, FALSE, FALSE },
+ { "float32_to_int64", 1, FALSE, TRUE, FALSE, FALSE },
+ { "float32_to_int64_round_to_zero", 1, FALSE, FALSE, FALSE, FALSE },
+ { "float32_to_float64", 1, FALSE, FALSE, FALSE, FALSE },
+#ifdef FLOATX80
+ { "float32_to_floatx80", 1, FALSE, FALSE, FALSE, FALSE },
+#endif
+#ifdef FLOAT128
+ { "float32_to_float128", 1, FALSE, FALSE, FALSE, FALSE },
+#endif
+ { "float32_round_to_int", 1, FALSE, TRUE, FALSE, FALSE },
+ { "float32_add", 2, FALSE, TRUE, FALSE, FALSE },
+ { "float32_sub", 2, FALSE, TRUE, FALSE, FALSE },
+ { "float32_mul", 2, FALSE, TRUE, TRUE, FALSE },
+ { "float32_div", 2, FALSE, TRUE, FALSE, FALSE },
+ { "float32_rem", 2, FALSE, FALSE, FALSE, FALSE },
+ { "float32_sqrt", 1, FALSE, TRUE, FALSE, FALSE },
+ { "float32_eq", 2, FALSE, FALSE, FALSE, FALSE },
+ { "float32_le", 2, FALSE, FALSE, FALSE, FALSE },
+ { "float32_lt", 2, FALSE, FALSE, FALSE, FALSE },
+ { "float32_eq_signaling", 2, FALSE, FALSE, FALSE, FALSE },
+ { "float32_le_quiet", 2, FALSE, FALSE, FALSE, FALSE },
+ { "float32_lt_quiet", 2, FALSE, FALSE, FALSE, FALSE },
+ { "float64_to_int32", 1, FALSE, TRUE, FALSE, FALSE },
+ { "float64_to_int32_round_to_zero", 1, FALSE, FALSE, FALSE, FALSE },
+ { "float64_to_int64", 1, FALSE, TRUE, FALSE, FALSE },
+ { "float64_to_int64_round_to_zero", 1, FALSE, FALSE, FALSE, FALSE },
+ { "float64_to_float32", 1, FALSE, TRUE, TRUE, FALSE },
+#ifdef FLOATX80
+ { "float64_to_floatx80", 1, FALSE, FALSE, FALSE, FALSE },
+#endif
+#ifdef FLOAT128
+ { "float64_to_float128", 1, FALSE, FALSE, FALSE, FALSE },
+#endif
+ { "float64_round_to_int", 1, FALSE, TRUE, FALSE, FALSE },
+ { "float64_add", 2, FALSE, TRUE, FALSE, FALSE },
+ { "float64_sub", 2, FALSE, TRUE, FALSE, FALSE },
+ { "float64_mul", 2, FALSE, TRUE, TRUE, FALSE },
+ { "float64_div", 2, FALSE, TRUE, FALSE, FALSE },
+ { "float64_rem", 2, FALSE, FALSE, FALSE, FALSE },
+ { "float64_sqrt", 1, FALSE, TRUE, FALSE, FALSE },
+ { "float64_eq", 2, FALSE, FALSE, FALSE, FALSE },
+ { "float64_le", 2, FALSE, FALSE, FALSE, FALSE },
+ { "float64_lt", 2, FALSE, FALSE, FALSE, FALSE },
+ { "float64_eq_signaling", 2, FALSE, FALSE, FALSE, FALSE },
+ { "float64_le_quiet", 2, FALSE, FALSE, FALSE, FALSE },
+ { "float64_lt_quiet", 2, FALSE, FALSE, FALSE, FALSE },
+#ifdef FLOATX80
+ { "floatx80_to_int32", 1, FALSE, TRUE, FALSE, FALSE },
+ { "floatx80_to_int32_round_to_zero", 1, FALSE, FALSE, FALSE, FALSE },
+ { "floatx80_to_int64", 1, FALSE, TRUE, FALSE, FALSE },
+ { "floatx80_to_int64_round_to_zero", 1, FALSE, FALSE, FALSE, FALSE },
+ { "floatx80_to_float32", 1, FALSE, TRUE, TRUE, FALSE },
+ { "floatx80_to_float64", 1, FALSE, TRUE, TRUE, FALSE },
+#ifdef FLOAT128
+ { "floatx80_to_float128", 1, FALSE, FALSE, FALSE, FALSE },
+#endif
+ { "floatx80_round_to_int", 1, FALSE, TRUE, FALSE, FALSE },
+ { "floatx80_add", 2, TRUE, TRUE, FALSE, TRUE },
+ { "floatx80_sub", 2, TRUE, TRUE, FALSE, TRUE },
+ { "floatx80_mul", 2, TRUE, TRUE, TRUE, TRUE },
+ { "floatx80_div", 2, TRUE, TRUE, FALSE, TRUE },
+ { "floatx80_rem", 2, FALSE, FALSE, FALSE, FALSE },
+ { "floatx80_sqrt", 1, TRUE, TRUE, FALSE, FALSE },
+ { "floatx80_eq", 2, FALSE, FALSE, FALSE, FALSE },
+ { "floatx80_le", 2, FALSE, FALSE, FALSE, FALSE },
+ { "floatx80_lt", 2, FALSE, FALSE, FALSE, FALSE },
+ { "floatx80_eq_signaling", 2, FALSE, FALSE, FALSE, FALSE },
+ { "floatx80_le_quiet", 2, FALSE, FALSE, FALSE, FALSE },
+ { "floatx80_lt_quiet", 2, FALSE, FALSE, FALSE, FALSE },
+#endif
+#ifdef FLOAT128
+ { "float128_to_int32", 1, FALSE, TRUE, FALSE, FALSE },
+ { "float128_to_int32_round_to_zero", 1, FALSE, FALSE, FALSE, FALSE },
+ { "float128_to_int64", 1, FALSE, TRUE, FALSE, FALSE },
+ { "float128_to_int64_round_to_zero", 1, FALSE, FALSE, FALSE, FALSE },
+ { "float128_to_float32", 1, FALSE, TRUE, TRUE, FALSE },
+ { "float128_to_float64", 1, FALSE, TRUE, TRUE, FALSE },
+#ifdef FLOATX80
+ { "float128_to_floatx80", 1, FALSE, TRUE, TRUE, FALSE },
+#endif
+ { "float128_round_to_int", 1, FALSE, TRUE, FALSE, FALSE },
+ { "float128_add", 2, FALSE, TRUE, FALSE, FALSE },
+ { "float128_sub", 2, FALSE, TRUE, FALSE, FALSE },
+ { "float128_mul", 2, FALSE, TRUE, TRUE, FALSE },
+ { "float128_div", 2, FALSE, TRUE, FALSE, FALSE },
+ { "float128_rem", 2, FALSE, FALSE, FALSE, FALSE },
+ { "float128_sqrt", 1, FALSE, TRUE, FALSE, FALSE },
+ { "float128_eq", 2, FALSE, FALSE, FALSE, FALSE },
+ { "float128_le", 2, FALSE, FALSE, FALSE, FALSE },
+ { "float128_lt", 2, FALSE, FALSE, FALSE, FALSE },
+ { "float128_eq_signaling", 2, FALSE, FALSE, FALSE, FALSE },
+ { "float128_le_quiet", 2, FALSE, FALSE, FALSE, FALSE },
+ { "float128_lt_quiet", 2, FALSE, FALSE, FALSE, FALSE },
+#endif
+};
+
+enum {
+ ROUND_NEAREST_EVEN = 1,
+ ROUND_TO_ZERO,
+ ROUND_DOWN,
+ ROUND_UP,
+ NUM_ROUNDINGMODES
+};
+enum {
+ TININESS_BEFORE_ROUNDING = 1,
+ TININESS_AFTER_ROUNDING,
+ NUM_TININESSMODES
+};
+
+static void
+ timeFunctionVariety(
+ uint8 functionCode,
+ int8 roundingPrecision,
+ int8 roundingMode,
+ int8 tininessMode
+ )
+{
+ uint8 roundingCode;
+ int8 tininessCode;
+
+ functionName = functions[ functionCode ].name;
+ if ( roundingPrecision == 32 ) {
+ roundingPrecisionName = "32";
+ }
+ else if ( roundingPrecision == 64 ) {
+ roundingPrecisionName = "64";
+ }
+ else if ( roundingPrecision == 80 ) {
+ roundingPrecisionName = "80";
+ }
+ else {
+ roundingPrecisionName = NULL;
+ }
+#ifdef FLOATX80
+ floatx80_rounding_precision = roundingPrecision;
+#endif
+ switch ( roundingMode ) {
+ case 0:
+ roundingModeName = NULL;
+ roundingCode = float_round_nearest_even;
+ break;
+ case ROUND_NEAREST_EVEN:
+ roundingModeName = "nearest_even";
+ roundingCode = float_round_nearest_even;
+ break;
+ case ROUND_TO_ZERO:
+ roundingModeName = "to_zero";
+ roundingCode = float_round_to_zero;
+ break;
+ case ROUND_DOWN:
+ roundingModeName = "down";
+ roundingCode = float_round_down;
+ break;
+ case ROUND_UP:
+ roundingModeName = "up";
+ roundingCode = float_round_up;
+ break;
+ }
+ float_rounding_mode = roundingCode;
+ switch ( tininessMode ) {
+ case 0:
+ tininessModeName = NULL;
+ tininessCode = float_tininess_after_rounding;
+ break;
+ case TININESS_BEFORE_ROUNDING:
+ tininessModeName = "before";
+ tininessCode = float_tininess_before_rounding;
+ break;
+ case TININESS_AFTER_ROUNDING:
+ tininessModeName = "after";
+ tininessCode = float_tininess_after_rounding;
+ break;
+ }
+ float_detect_tininess = tininessCode;
+ switch ( functionCode ) {
+ case INT32_TO_FLOAT32:
+ time_a_int32_z_float32( int32_to_float32 );
+ break;
+ case INT32_TO_FLOAT64:
+ time_a_int32_z_float64( int32_to_float64 );
+ break;
+#ifdef FLOATX80
+ case INT32_TO_FLOATX80:
+ time_a_int32_z_floatx80( int32_to_floatx80 );
+ break;
+#endif
+#ifdef FLOAT128
+ case INT32_TO_FLOAT128:
+ time_a_int32_z_float128( int32_to_float128 );
+ break;
+#endif
+ case INT64_TO_FLOAT32:
+ time_a_int64_z_float32( int64_to_float32 );
+ break;
+ case INT64_TO_FLOAT64:
+ time_a_int64_z_float64( int64_to_float64 );
+ break;
+#ifdef FLOATX80
+ case INT64_TO_FLOATX80:
+ time_a_int64_z_floatx80( int64_to_floatx80 );
+ break;
+#endif
+#ifdef FLOAT128
+ case INT64_TO_FLOAT128:
+ time_a_int64_z_float128( int64_to_float128 );
+ break;
+#endif
+ case FLOAT32_TO_INT32:
+ time_a_float32_z_int32( float32_to_int32 );
+ break;
+ case FLOAT32_TO_INT32_ROUND_TO_ZERO:
+ time_a_float32_z_int32( float32_to_int32_round_to_zero );
+ break;
+ case FLOAT32_TO_INT64:
+ time_a_float32_z_int64( float32_to_int64 );
+ break;
+ case FLOAT32_TO_INT64_ROUND_TO_ZERO:
+ time_a_float32_z_int64( float32_to_int64_round_to_zero );
+ break;
+ case FLOAT32_TO_FLOAT64:
+ time_a_float32_z_float64( float32_to_float64 );
+ break;
+#ifdef FLOATX80
+ case FLOAT32_TO_FLOATX80:
+ time_a_float32_z_floatx80( float32_to_floatx80 );
+ break;
+#endif
+#ifdef FLOAT128
+ case FLOAT32_TO_FLOAT128:
+ time_a_float32_z_float128( float32_to_float128 );
+ break;
+#endif
+ case FLOAT32_ROUND_TO_INT:
+ time_az_float32( float32_round_to_int );
+ break;
+ case FLOAT32_ADD:
+ time_abz_float32( float32_add );
+ break;
+ case FLOAT32_SUB:
+ time_abz_float32( float32_sub );
+ break;
+ case FLOAT32_MUL:
+ time_abz_float32( float32_mul );
+ break;
+ case FLOAT32_DIV:
+ time_abz_float32( float32_div );
+ break;
+ case FLOAT32_REM:
+ time_abz_float32( float32_rem );
+ break;
+ case FLOAT32_SQRT:
+ time_az_float32_pos( float32_sqrt );
+ break;
+ case FLOAT32_EQ:
+ time_ab_float32_z_flag( float32_eq );
+ break;
+ case FLOAT32_LE:
+ time_ab_float32_z_flag( float32_le );
+ break;
+ case FLOAT32_LT:
+ time_ab_float32_z_flag( float32_lt );
+ break;
+ case FLOAT32_EQ_SIGNALING:
+ time_ab_float32_z_flag( float32_eq_signaling );
+ break;
+ case FLOAT32_LE_QUIET:
+ time_ab_float32_z_flag( float32_le_quiet );
+ break;
+ case FLOAT32_LT_QUIET:
+ time_ab_float32_z_flag( float32_lt_quiet );
+ break;
+ case FLOAT64_TO_INT32:
+ time_a_float64_z_int32( float64_to_int32 );
+ break;
+ case FLOAT64_TO_INT32_ROUND_TO_ZERO:
+ time_a_float64_z_int32( float64_to_int32_round_to_zero );
+ break;
+ case FLOAT64_TO_INT64:
+ time_a_float64_z_int64( float64_to_int64 );
+ break;
+ case FLOAT64_TO_INT64_ROUND_TO_ZERO:
+ time_a_float64_z_int64( float64_to_int64_round_to_zero );
+ break;
+ case FLOAT64_TO_FLOAT32:
+ time_a_float64_z_float32( float64_to_float32 );
+ break;
+#ifdef FLOATX80
+ case FLOAT64_TO_FLOATX80:
+ time_a_float64_z_floatx80( float64_to_floatx80 );
+ break;
+#endif
+#ifdef FLOAT128
+ case FLOAT64_TO_FLOAT128:
+ time_a_float64_z_float128( float64_to_float128 );
+ break;
+#endif
+ case FLOAT64_ROUND_TO_INT:
+ time_az_float64( float64_round_to_int );
+ break;
+ case FLOAT64_ADD:
+ time_abz_float64( float64_add );
+ break;
+ case FLOAT64_SUB:
+ time_abz_float64( float64_sub );
+ break;
+ case FLOAT64_MUL:
+ time_abz_float64( float64_mul );
+ break;
+ case FLOAT64_DIV:
+ time_abz_float64( float64_div );
+ break;
+ case FLOAT64_REM:
+ time_abz_float64( float64_rem );
+ break;
+ case FLOAT64_SQRT:
+ time_az_float64_pos( float64_sqrt );
+ break;
+ case FLOAT64_EQ:
+ time_ab_float64_z_flag( float64_eq );
+ break;
+ case FLOAT64_LE:
+ time_ab_float64_z_flag( float64_le );
+ break;
+ case FLOAT64_LT:
+ time_ab_float64_z_flag( float64_lt );
+ break;
+ case FLOAT64_EQ_SIGNALING:
+ time_ab_float64_z_flag( float64_eq_signaling );
+ break;
+ case FLOAT64_LE_QUIET:
+ time_ab_float64_z_flag( float64_le_quiet );
+ break;
+ case FLOAT64_LT_QUIET:
+ time_ab_float64_z_flag( float64_lt_quiet );
+ break;
+#ifdef FLOATX80
+ case FLOATX80_TO_INT32:
+ time_a_floatx80_z_int32( floatx80_to_int32 );
+ break;
+ case FLOATX80_TO_INT32_ROUND_TO_ZERO:
+ time_a_floatx80_z_int32( floatx80_to_int32_round_to_zero );
+ break;
+ case FLOATX80_TO_INT64:
+ time_a_floatx80_z_int64( floatx80_to_int64 );
+ break;
+ case FLOATX80_TO_INT64_ROUND_TO_ZERO:
+ time_a_floatx80_z_int64( floatx80_to_int64_round_to_zero );
+ break;
+ case FLOATX80_TO_FLOAT32:
+ time_a_floatx80_z_float32( floatx80_to_float32 );
+ break;
+ case FLOATX80_TO_FLOAT64:
+ time_a_floatx80_z_float64( floatx80_to_float64 );
+ break;
+#ifdef FLOAT128
+ case FLOATX80_TO_FLOAT128:
+ time_a_floatx80_z_float128( floatx80_to_float128 );
+ break;
+#endif
+ case FLOATX80_ROUND_TO_INT:
+ time_az_floatx80( floatx80_round_to_int );
+ break;
+ case FLOATX80_ADD:
+ time_abz_floatx80( floatx80_add );
+ break;
+ case FLOATX80_SUB:
+ time_abz_floatx80( floatx80_sub );
+ break;
+ case FLOATX80_MUL:
+ time_abz_floatx80( floatx80_mul );
+ break;
+ case FLOATX80_DIV:
+ time_abz_floatx80( floatx80_div );
+ break;
+ case FLOATX80_REM:
+ time_abz_floatx80( floatx80_rem );
+ break;
+ case FLOATX80_SQRT:
+ time_az_floatx80_pos( floatx80_sqrt );
+ break;
+ case FLOATX80_EQ:
+ time_ab_floatx80_z_flag( floatx80_eq );
+ break;
+ case FLOATX80_LE:
+ time_ab_floatx80_z_flag( floatx80_le );
+ break;
+ case FLOATX80_LT:
+ time_ab_floatx80_z_flag( floatx80_lt );
+ break;
+ case FLOATX80_EQ_SIGNALING:
+ time_ab_floatx80_z_flag( floatx80_eq_signaling );
+ break;
+ case FLOATX80_LE_QUIET:
+ time_ab_floatx80_z_flag( floatx80_le_quiet );
+ break;
+ case FLOATX80_LT_QUIET:
+ time_ab_floatx80_z_flag( floatx80_lt_quiet );
+ break;
+#endif
+#ifdef FLOAT128
+ case FLOAT128_TO_INT32:
+ time_a_float128_z_int32( float128_to_int32 );
+ break;
+ case FLOAT128_TO_INT32_ROUND_TO_ZERO:
+ time_a_float128_z_int32( float128_to_int32_round_to_zero );
+ break;
+ case FLOAT128_TO_INT64:
+ time_a_float128_z_int64( float128_to_int64 );
+ break;
+ case FLOAT128_TO_INT64_ROUND_TO_ZERO:
+ time_a_float128_z_int64( float128_to_int64_round_to_zero );
+ break;
+ case FLOAT128_TO_FLOAT32:
+ time_a_float128_z_float32( float128_to_float32 );
+ break;
+ case FLOAT128_TO_FLOAT64:
+ time_a_float128_z_float64( float128_to_float64 );
+ break;
+#ifdef FLOATX80
+ case FLOAT128_TO_FLOATX80:
+ time_a_float128_z_floatx80( float128_to_floatx80 );
+ break;
+#endif
+ case FLOAT128_ROUND_TO_INT:
+ time_az_float128( float128_round_to_int );
+ break;
+ case FLOAT128_ADD:
+ time_abz_float128( float128_add );
+ break;
+ case FLOAT128_SUB:
+ time_abz_float128( float128_sub );
+ break;
+ case FLOAT128_MUL:
+ time_abz_float128( float128_mul );
+ break;
+ case FLOAT128_DIV:
+ time_abz_float128( float128_div );
+ break;
+ case FLOAT128_REM:
+ time_abz_float128( float128_rem );
+ break;
+ case FLOAT128_SQRT:
+ time_az_float128_pos( float128_sqrt );
+ break;
+ case FLOAT128_EQ:
+ time_ab_float128_z_flag( float128_eq );
+ break;
+ case FLOAT128_LE:
+ time_ab_float128_z_flag( float128_le );
+ break;
+ case FLOAT128_LT:
+ time_ab_float128_z_flag( float128_lt );
+ break;
+ case FLOAT128_EQ_SIGNALING:
+ time_ab_float128_z_flag( float128_eq_signaling );
+ break;
+ case FLOAT128_LE_QUIET:
+ time_ab_float128_z_flag( float128_le_quiet );
+ break;
+ case FLOAT128_LT_QUIET:
+ time_ab_float128_z_flag( float128_lt_quiet );
+ break;
+#endif
+ }
+
+}
+
+static void
+ timeFunction(
+ uint8 functionCode,
+ int8 roundingPrecisionIn,
+ int8 roundingModeIn,
+ int8 tininessModeIn
+ )
+{
+ int8 roundingPrecision, roundingMode, tininessMode;
+
+ roundingPrecision = 32;
+ for (;;) {
+ if ( ! functions[ functionCode ].roundingPrecision ) {
+ roundingPrecision = 0;
+ }
+ else if ( roundingPrecisionIn ) {
+ roundingPrecision = roundingPrecisionIn;
+ }
+ for ( roundingMode = 1;
+ roundingMode < NUM_ROUNDINGMODES;
+ ++roundingMode
+ ) {
+ if ( ! functions[ functionCode ].roundingMode ) {
+ roundingMode = 0;
+ }
+ else if ( roundingModeIn ) {
+ roundingMode = roundingModeIn;
+ }
+ for ( tininessMode = 1;
+ tininessMode < NUM_TININESSMODES;
+ ++tininessMode
+ ) {
+ if ( ( roundingPrecision == 32 )
+ || ( roundingPrecision == 64 ) ) {
+ if ( ! functions[ functionCode ]
+ .tininessModeAtReducedPrecision
+ ) {
+ tininessMode = 0;
+ }
+ else if ( tininessModeIn ) {
+ tininessMode = tininessModeIn;
+ }
+ }
+ else {
+ if ( ! functions[ functionCode ].tininessMode ) {
+ tininessMode = 0;
+ }
+ else if ( tininessModeIn ) {
+ tininessMode = tininessModeIn;
+ }
+ }
+ timeFunctionVariety(
+ functionCode, roundingPrecision, roundingMode, tininessMode
+ );
+ if ( tininessModeIn || ! tininessMode ) break;
+ }
+ if ( roundingModeIn || ! roundingMode ) break;
+ }
+ if ( roundingPrecisionIn || ! roundingPrecision ) break;
+ if ( roundingPrecision == 80 ) {
+ break;
+ }
+ else if ( roundingPrecision == 64 ) {
+ roundingPrecision = 80;
+ }
+ else if ( roundingPrecision == 32 ) {
+ roundingPrecision = 64;
+ }
+ }
+
+}
+
+main( int argc, char **argv )
+{
+ char *argPtr;
+ flag functionArgument;
+ uint8 functionCode;
+ int8 operands, roundingPrecision, roundingMode, tininessMode;
+
+ if ( argc <= 1 ) goto writeHelpMessage;
+ functionArgument = FALSE;
+ functionCode = 0;
+ operands = 0;
+ roundingPrecision = 0;
+ roundingMode = 0;
+ tininessMode = 0;
+ --argc;
+ ++argv;
+ while ( argc && ( argPtr = argv[ 0 ] ) ) {
+ if ( argPtr[ 0 ] == '-' ) ++argPtr;
+ if ( strcmp( argPtr, "help" ) == 0 ) {
+ writeHelpMessage:
+ fputs(
+"timesoftfloat [<option>...] <function>\n"
+" <option>: (* is default)\n"
+" -help --Write this message and exit.\n"
+#ifdef FLOATX80
+" -precision32 --Only time rounding precision equivalent to float32.\n"
+" -precision64 --Only time rounding precision equivalent to float64.\n"
+" -precision80 --Only time maximum rounding precision.\n"
+#endif
+" -nearesteven --Only time rounding to nearest/even.\n"
+" -tozero --Only time rounding to zero.\n"
+" -down --Only time rounding down.\n"
+" -up --Only time rounding up.\n"
+" -tininessbefore --Only time underflow tininess before rounding.\n"
+" -tininessafter --Only time underflow tininess after rounding.\n"
+" <function>:\n"
+" int32_to_<float> <float>_add <float>_eq\n"
+" <float>_to_int32 <float>_sub <float>_le\n"
+" <float>_to_int32_round_to_zero <float>_mul <float>_lt\n"
+" int64_to_<float> <float>_div <float>_eq_signaling\n"
+" <float>_to_int64 <float>_rem <float>_le_quiet\n"
+" <float>_to_int64_round_to_zero <float>_lt_quiet\n"
+" <float>_to_<float>\n"
+" <float>_round_to_int\n"
+" <float>_sqrt\n"
+" -all1 --All 1-operand functions.\n"
+" -all2 --All 2-operand functions.\n"
+" -all --All functions.\n"
+" <float>:\n"
+" float32 --Single precision.\n"
+" float64 --Double precision.\n"
+#ifdef FLOATX80
+" floatx80 --Extended double precision.\n"
+#endif
+#ifdef FLOAT128
+" float128 --Quadruple precision.\n"
+#endif
+ ,
+ stdout
+ );
+ return EXIT_SUCCESS;
+ }
+#ifdef FLOATX80
+ else if ( strcmp( argPtr, "precision32" ) == 0 ) {
+ roundingPrecision = 32;
+ }
+ else if ( strcmp( argPtr, "precision64" ) == 0 ) {
+ roundingPrecision = 64;
+ }
+ else if ( strcmp( argPtr, "precision80" ) == 0 ) {
+ roundingPrecision = 80;
+ }
+#endif
+ else if ( ( strcmp( argPtr, "nearesteven" ) == 0 )
+ || ( strcmp( argPtr, "nearest_even" ) == 0 ) ) {
+ roundingMode = ROUND_NEAREST_EVEN;
+ }
+ else if ( ( strcmp( argPtr, "tozero" ) == 0 )
+ || ( strcmp( argPtr, "to_zero" ) == 0 ) ) {
+ roundingMode = ROUND_TO_ZERO;
+ }
+ else if ( strcmp( argPtr, "down" ) == 0 ) {
+ roundingMode = ROUND_DOWN;
+ }
+ else if ( strcmp( argPtr, "up" ) == 0 ) {
+ roundingMode = ROUND_UP;
+ }
+ else if ( strcmp( argPtr, "tininessbefore" ) == 0 ) {
+ tininessMode = TININESS_BEFORE_ROUNDING;
+ }
+ else if ( strcmp( argPtr, "tininessafter" ) == 0 ) {
+ tininessMode = TININESS_AFTER_ROUNDING;
+ }
+ else if ( strcmp( argPtr, "all1" ) == 0 ) {
+ functionArgument = TRUE;
+ functionCode = 0;
+ operands = 1;
+ }
+ else if ( strcmp( argPtr, "all2" ) == 0 ) {
+ functionArgument = TRUE;
+ functionCode = 0;
+ operands = 2;
+ }
+ else if ( strcmp( argPtr, "all" ) == 0 ) {
+ functionArgument = TRUE;
+ functionCode = 0;
+ operands = 0;
+ }
+ else {
+ for ( functionCode = 1;
+ functionCode < NUM_FUNCTIONS;
+ ++functionCode
+ ) {
+ if ( strcmp( argPtr, functions[ functionCode ].name ) == 0 ) {
+ break;
+ }
+ }
+ if ( functionCode == NUM_FUNCTIONS ) {
+ fail( "Invalid option or function `%s'", argv[ 0 ] );
+ }
+ functionArgument = TRUE;
+ }
+ --argc;
+ ++argv;
+ }
+ if ( ! functionArgument ) fail( "Function argument required" );
+ if ( functionCode ) {
+ timeFunction(
+ functionCode, roundingPrecision, roundingMode, tininessMode );
+ }
+ else if ( operands == 1 ) {
+ for ( functionCode = 1; functionCode < NUM_FUNCTIONS; ++functionCode
+ ) {
+ if ( functions[ functionCode ].numInputs == 1 ) {
+ timeFunction(
+ functionCode, roundingPrecision, roundingMode, tininessMode
+ );
+ }
+ }
+ }
+ else if ( operands == 2 ) {
+ for ( functionCode = 1; functionCode < NUM_FUNCTIONS; ++functionCode
+ ) {
+ if ( functions[ functionCode ].numInputs == 2 ) {
+ timeFunction(
+ functionCode, roundingPrecision, roundingMode, tininessMode
+ );
+ }
+ }
+ }
+ else {
+ for ( functionCode = 1; functionCode < NUM_FUNCTIONS; ++functionCode
+ ) {
+ timeFunction(
+ functionCode, roundingPrecision, roundingMode, tininessMode );
+ }
+ }
+ return EXIT_SUCCESS;
+
+}
+
diff --git a/lib/libc/softfloat/timesoftfloat.txt b/lib/libc/softfloat/timesoftfloat.txt
new file mode 100644
index 000000000000..addc64740c6d
--- /dev/null
+++ b/lib/libc/softfloat/timesoftfloat.txt
@@ -0,0 +1,150 @@
+$NetBSD: timesoftfloat.txt,v 1.1 2000/06/06 08:15:11 bjh21 Exp $
+$FreeBSD$
+
+Documentation for the `timesoftfloat' Program of SoftFloat Release 2a
+
+John R. Hauser
+1998 December 14
+
+
+-------------------------------------------------------------------------------
+Introduction
+
+The `timesoftfloat' program evaluates the speed of SoftFloat's floating-
+point routines. Each routine can be evaluated for every relevant rounding
+mode, tininess mode, and/or rounding precision.
+
+
+-------------------------------------------------------------------------------
+Contents
+
+ Introduction
+ Contents
+ Legal Notice
+ Executing `timesoftfloat'
+ Options
+ -help
+ -precision32, -precision64, -precision80
+ -nearesteven, -tozero, -down, -up
+ -tininessbefore, -tininessafter
+ Function Sets
+
+
+
+-------------------------------------------------------------------------------
+Legal Notice
+
+The `timesoftfloat' program was written by John R. Hauser.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
+has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
+TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
+PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
+AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
+
+
+-------------------------------------------------------------------------------
+Executing `timesoftfloat'
+
+The `timesoftfloat' program is intended to be invoked from a command line
+interpreter as follows:
+
+ timesoftfloat [<option>...] <function>
+
+Here square brackets ([]) indicate optional items, while angled brackets
+(<>) denote parameters to be filled in. The `<function>' argument is
+the name of the SoftFloat routine to evaluate, such as `float32_add' or
+`float64_to_int32'. The allowed options are detailed in the next section,
+_Options_. If `timesoftfloat' is executed without any arguments, a summary
+of usage is written. It is also possible to evaluate all machine functions
+in a single invocation as explained in the section _Function_Sets_ later in
+this document.
+
+Ordinarily, a function's speed will be evaulated separately for each of
+the four rounding modes, one after the other. If the rounding mode is not
+supposed to have any affect on the results of a function--for instance,
+some operations do not require rounding--only the nearest/even rounding mode
+is timed. In the same way, if a function is affected by the way in which
+underflow tininess is detected, `timesoftfloat' times the function both with
+tininess detected before rounding and after rounding. For extended double-
+precision operations affected by rounding precision control, `timesoftfloat'
+also times the function for all three rounding precision modes, one after
+the other. Evaluation of a function can be limited to a single rounding
+mode, a single tininess mode, and/or a single rounding precision with
+appropriate options (see _Options_).
+
+For each function and mode evaluated, `timesoftfloat' reports the speed of
+the function in kops/s, or ``thousands of operations per second''. This
+unit of measure differs from the traditional MFLOPS (``millions of floating-
+point operations per second'') only in being a factor of 1000 smaller.
+(1000 kops/s is exactly 1 MFLOPS.) Speeds are reported in thousands instead
+of millions because software floating-point often executes at less than
+1 MFLOPS.
+
+The speeds reported by `timesoftfloat' may be affected somewhat by other
+programs executing at the same time as `timesoftfloat'.
+
+Note that the remainder operations (`float32_rem', `float64_rem',
+`floatx80_rem' and `float128_rem') will be markedly slower than other
+operations, particularly for extended double precision (`floatx80') and
+quadruple precision (`float128'). This is inherent to the remainder
+function itself and is not a failing of the SoftFloat implementation.
+
+
+-------------------------------------------------------------------------------
+Options
+
+The `timesoftfloat' program accepts several command options. If mutually
+contradictory options are given, the last one has priority.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+-help
+
+The `-help' option causes a summary of program usage to be written, after
+which the program exits.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+-precision32, -precision64, -precision80
+
+For extended double-precision functions affected by rounding precision
+control, the `-precision32' option restricts evaluation to only the cases
+in which rounding precision is equivalent to single precision. The other
+rounding precision options are not timed. Likewise, the `-precision64'
+and `-precision80' options fix the rounding precision equivalent to double
+precision or extended double precision, respectively. These options are
+ignored for functions not affected by rounding precision control.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+-nearesteven, -tozero, -down, -up
+
+The `-nearesteven' option restricts evaluation to only the cases in which
+the rounding mode is nearest/even. The other rounding mode options are not
+timed. Likewise, `-tozero' forces rounding to zero; `-down' forces rounding
+down; and `-up' forces rounding up. These options are ignored for functions
+that are exact and thus do not round.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+-tininessbefore, -tininessafter
+
+The `-tininessbefore' option restricts evaluation to only the cases
+detecting underflow tininess before rounding. Tininess after rounding
+is not timed. Likewise, `-tininessafter' forces underflow tininess to be
+detected after rounding only. These options are ignored for functions not
+affected by the way in which underflow tininess is detected.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+
+-------------------------------------------------------------------------------
+Function Sets
+
+Just as `timesoftfloat' can test an operation for all four rounding modes in
+sequence, multiple operations can also be tested with a single invocation.
+Three sets are recognized: `-all1', `-all2', and `-all'. The set `-all1'
+comprises all one-operand functions; `-all2' is all two-operand functions;
+and `-all' is all functions. A function set can be used in place of a
+function name in the command line, as in
+
+ timesoftfloat [<option>...] -all
+
+
diff --git a/lib/libc/softfloat/unorddf2.c b/lib/libc/softfloat/unorddf2.c
new file mode 100644
index 000000000000..2986c8281475
--- /dev/null
+++ b/lib/libc/softfloat/unorddf2.c
@@ -0,0 +1,26 @@
+/* $NetBSD: unorddf2.c,v 1.1 2003/05/06 08:58:19 rearnsha Exp $ */
+
+/*
+ * Written by Richard Earnshaw, 2003. This file is in the Public Domain.
+ */
+
+#include "softfloat-for-gcc.h"
+#include "milieu.h"
+#include "softfloat.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+flag __unorddf2(float64, float64);
+
+flag
+__unorddf2(float64 a, float64 b)
+{
+ /*
+ * The comparison is unordered if either input is a NaN.
+ * Test for this by comparing each operand with itself.
+ * We must perform both comparisons to correctly check for
+ * signalling NaNs.
+ */
+ return 1 ^ (float64_eq(a, a) & float64_eq(b, b));
+}
diff --git a/lib/libc/softfloat/unordsf2.c b/lib/libc/softfloat/unordsf2.c
new file mode 100644
index 000000000000..e2f4c8f0947c
--- /dev/null
+++ b/lib/libc/softfloat/unordsf2.c
@@ -0,0 +1,26 @@
+/* $NetBSD: unordsf2.c,v 1.1 2003/05/06 08:58:20 rearnsha Exp $ */
+
+/*
+ * Written by Richard Earnshaw, 2003. This file is in the Public Domain.
+ */
+
+#include "softfloat-for-gcc.h"
+#include "milieu.h"
+#include "softfloat.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+flag __unordsf2(float32, float32);
+
+flag
+__unordsf2(float32 a, float32 b)
+{
+ /*
+ * The comparison is unordered if either input is a NaN.
+ * Test for this by comparing each operand with itself.
+ * We must perform both comparisons to correctly check for
+ * signalling NaNs.
+ */
+ return 1 ^ (float32_eq(a, a) & float32_eq(b, b));
+}
diff --git a/lib/libc/sparc64/Makefile.inc b/lib/libc/sparc64/Makefile.inc
new file mode 100644
index 000000000000..74fb7cd05911
--- /dev/null
+++ b/lib/libc/sparc64/Makefile.inc
@@ -0,0 +1,13 @@
+# $FreeBSD$
+#
+# Machine dependent definitions for the ultra sparc architecture.
+#
+
+.include "fpu/Makefile.inc"
+
+SRCS+= trivial-vdso_tc.c
+
+# Long double is quad precision
+GDTOASRCS+=strtorQ.c
+MDSRCS+=machdep_ldisQ.c
+SYM_MAPS+=${LIBC_SRCTOP}/sparc64/Symbol.map
diff --git a/lib/libc/sparc64/SYS.h b/lib/libc/sparc64/SYS.h
new file mode 100644
index 000000000000..0bc7840d9452
--- /dev/null
+++ b/lib/libc/sparc64/SYS.h
@@ -0,0 +1,85 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)SYS.h 5.5 (Berkeley) 5/7/91
+ * from: FreeBSD: src/lib/libc/i386/SYS.h,v 1.20 2001/01/29
+ * $FreeBSD$
+ */
+
+#include <sys/syscall.h>
+
+#include <machine/asm.h>
+#include <machine/utrap.h>
+
+#define ERROR() \
+ mov %o7, %g1 ; \
+ call HIDENAME(cerror) ; \
+ mov %g1, %o7
+
+#define _SYSENTRY(x) \
+ENTRY(__CONCAT(__sys_,x)) ; \
+ .weak CNAME(x) ; \
+ .type CNAME(x),@function ; \
+ .set CNAME(x),CNAME(__CONCAT(__sys_,x)) ; \
+ .weak CNAME(__CONCAT(_,x)) ; \
+ .type CNAME(__CONCAT(_,x)), @function ; \
+ .set CNAME(__CONCAT(_,x)),CNAME(__CONCAT(__sys_,x))
+
+#define _SYSEND(x) \
+ .size CNAME(__CONCAT(__sys_,x)), . - CNAME(__CONCAT(__sys_,x)) ; \
+ .size CNAME(__CONCAT(_,x)), . - CNAME(__CONCAT(__sys_,x)) ; \
+ .size CNAME(__CONCAT(,x)), . - CNAME(__CONCAT(__sys_,x))
+
+#define _SYSCALL(x) \
+ mov __CONCAT(SYS_,x), %g1 ; \
+ ta %xcc, ST_SYSCALL ; \
+ bcc,a,pt %xcc, 1f ; \
+ nop ; \
+ ERROR() ; \
+1:
+
+#define RSYSCALL(x) \
+_SYSENTRY(x) ; \
+ _SYSCALL(x) ; \
+ retl ; \
+ nop ; \
+ _SYSEND(x)
+
+#define PSEUDO(x) \
+ENTRY(__CONCAT(__sys_,x)) ; \
+ .weak CNAME(__CONCAT(_,x)) ; \
+ .type CNAME(__CONCAT(_,x)),@function ; \
+ .set CNAME(__CONCAT(_,x)),CNAME(__CONCAT(__sys_,x)) ; \
+ _SYSCALL(x) ; \
+ retl ; \
+ nop ; \
+ .size CNAME(__CONCAT(__sys_,x)), . - CNAME(__CONCAT(__sys_,x)) ; \
+ .size CNAME(__CONCAT(_,x)), . - CNAME(__CONCAT(__sys_,x))
diff --git a/lib/libc/sparc64/Symbol.map b/lib/libc/sparc64/Symbol.map
new file mode 100644
index 000000000000..1dc3d150ab3d
--- /dev/null
+++ b/lib/libc/sparc64/Symbol.map
@@ -0,0 +1,95 @@
+/*
+ * $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, ...).
+ */
+FBSD_1.0 {
+ /* PSEUDO syscalls */
+ _exit;
+
+ _mcount;
+ _setjmp;
+ _longjmp;
+ fabs;
+ __flt_rounds;
+ fpgetmask;
+ fpgetround;
+ fpgetsticky;
+ fpsetmask;
+ fpsetround;
+ __infinity;
+ __nan;
+ makecontext;
+ setjmp;
+ longjmp;
+ sigsetjmp;
+ siglongjmp;
+ htonl;
+ htons;
+ ntohl;
+ ntohs;
+ brk;
+ exect;
+ sbrk;
+ vfork;
+
+ /* SCD libc 64 psABI */
+ _Qp_sqrt;
+ _Qp_add;
+ _Qp_div;
+ _Qp_mul;
+ _Qp_sub;
+ _Qp_dtoq;
+ _Qp_itoq;
+ _Qp_stoq;
+ _Qp_xtoq;
+ _Qp_uitoq;
+ _Qp_uxtoq;
+ _Qp_qtod;
+ _Qp_qtoi;
+ _Qp_qtos;
+ _Qp_qtox;
+ _Qp_qtoui;
+ _Qp_qtoux;
+ _Qp_feq;
+ _Qp_fge;
+ _Qp_fgt;
+ _Qp_fle;
+ _Qp_flt;
+ _Qp_fne;
+ _Qp_cmp;
+ _Qp_cmpe;
+ __dtoul;
+ __sparc_utrap_install;
+};
+
+FBSDprivate_1.0 {
+ /* PSEUDO syscalls */
+ __sys_getlogin;
+ _getlogin;
+ __sys_exit;
+
+ _set_tp;
+ ___longjmp;
+ __makecontext;
+ __longjmp;
+ signalcontext;
+ __signalcontext;
+ __siglongjmp;
+ __sys_brk;
+ _brk;
+ __sys_exect;
+ _exect;
+ _end;
+ __sys_sbrk;
+ _sbrk;
+ __sys_vfork;
+ _vfork;
+
+ /* used in src/lib/csu/sparc64/crt1.c */
+ __sparc_utrap_setup;
+};
diff --git a/lib/libc/sparc64/_fpmath.h b/lib/libc/sparc64/_fpmath.h
new file mode 100644
index 000000000000..f3238150ad80
--- /dev/null
+++ b/lib/libc/sparc64/_fpmath.h
@@ -0,0 +1,57 @@
+/*-
+ * Copyright (c) 2003 Mike Barcroft <mike@FreeBSD.org>
+ * Copyright (c) 2002, 2003 David Schultz <das@FreeBSD.ORG>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+union IEEEl2bits {
+ long double e;
+ struct {
+ unsigned int sign :1;
+ unsigned int exp :15;
+ unsigned long manh :48;
+ unsigned long manl :64;
+ } bits;
+ struct {
+ unsigned int expsign :16;
+ unsigned long manh :48;
+ unsigned long manl :64;
+ } xbits;
+};
+
+#define mask_nbit_l(u) ((void)0)
+#define LDBL_IMPLICIT_NBIT
+#define LDBL_NBIT 0
+
+#define LDBL_MANH_SIZE 48
+#define LDBL_MANL_SIZE 64
+
+#define LDBL_TO_ARRAY32(u, a) do { \
+ (a)[0] = (uint32_t)(u).bits.manl; \
+ (a)[1] = (uint32_t)((u).bits.manl >> 32); \
+ (a)[2] = (uint32_t)(u).bits.manh; \
+ (a)[3] = (uint32_t)((u).bits.manh >> 32); \
+} while(0)
diff --git a/lib/libc/sparc64/arith.h b/lib/libc/sparc64/arith.h
new file mode 100644
index 000000000000..3c35b80f35c3
--- /dev/null
+++ b/lib/libc/sparc64/arith.h
@@ -0,0 +1,19 @@
+/*
+ * MD header for contrib/gdtoa
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * NOTE: The definitions in this file must be correct or strtod(3) and
+ * floating point formats in printf(3) will break! The file can be
+ * generated by running contrib/gdtoa/arithchk.c on the target
+ * architecture. See contrib/gdtoa/gdtoaimp.h for details.
+ */
+
+#define IEEE_MC68k
+#define Arith_Kind_ASL 2
+#define Long int
+#define Intcast (int)(long)
+#define Double_Align
+#define X64_bit_pointers
diff --git a/lib/libc/sparc64/fpu/Makefile.inc b/lib/libc/sparc64/fpu/Makefile.inc
new file mode 100644
index 000000000000..6aaf583007f5
--- /dev/null
+++ b/lib/libc/sparc64/fpu/Makefile.inc
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+.PATH: ${LIBC_SRCTOP}/sparc64/fpu
+
+CFLAGS+= -I${LIBC_SRCTOP}/sparc64/sys
+
+SRCS+= fpu.c fpu_add.c fpu_compare.c fpu_div.c fpu_explode.c fpu_implode.c \
+ fpu_mul.c fpu_qp.c fpu_reg.S fpu_sqrt.c fpu_subr.c
diff --git a/lib/libc/sparc64/fpu/fpu.c b/lib/libc/sparc64/fpu/fpu.c
new file mode 100644
index 000000000000..e01701cde00c
--- /dev/null
+++ b/lib/libc/sparc64/fpu/fpu.c
@@ -0,0 +1,461 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*-
+ * Copyright 2001 by Thomas Moestl <tmm@FreeBSD.org>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @(#)fpu.c 8.1 (Berkeley) 6/11/93
+ * $NetBSD: fpu.c,v 1.11 2000/12/06 01:47:50 mrg Exp $
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+
+#include "namespace.h"
+#include <errno.h>
+#include <signal.h>
+#ifdef FPU_DEBUG
+#include <stdio.h>
+#endif
+#include <stdlib.h>
+#include <unistd.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+
+#include <machine/fp.h>
+#include <machine/frame.h>
+#include <machine/fsr.h>
+#include <machine/instr.h>
+#include <machine/pcb.h>
+#include <machine/tstate.h>
+
+#include "__sparc_utrap_private.h"
+#include "fpu_emu.h"
+#include "fpu_extern.h"
+
+/*
+ * Translate current exceptions into `first' exception. The
+ * bits go the wrong way for ffs() (0x10 is most important, etc).
+ * There are only 5, so do it the obvious way.
+ */
+#define X1(x) x
+#define X2(x) x,x
+#define X4(x) x,x,x,x
+#define X8(x) X4(x),X4(x)
+#define X16(x) X8(x),X8(x)
+
+static const char cx_to_trapx[] = {
+ X1(FSR_NX),
+ X2(FSR_DZ),
+ X4(FSR_UF),
+ X8(FSR_OF),
+ X16(FSR_NV)
+};
+
+#ifdef FPU_DEBUG
+#ifdef FPU_DEBUG_MASK
+int __fpe_debug = FPU_DEBUG_MASK;
+#else
+int __fpe_debug = 0;
+#endif
+#endif /* FPU_DEBUG */
+
+static int __fpu_execute(struct utrapframe *, struct fpemu *, u_int32_t,
+ u_long);
+
+/*
+ * Need to use an fpstate on the stack; we could switch, so we cannot safely
+ * modify the pcb one, it might get overwritten.
+ */
+int
+__fpu_exception(struct utrapframe *uf)
+{
+ struct fpemu fe;
+ u_long fsr, tstate;
+ u_int insn;
+ int sig;
+
+ fsr = uf->uf_fsr;
+
+ switch (FSR_GET_FTT(fsr)) {
+ case FSR_FTT_NONE:
+ __utrap_write("lost FPU trap type\n");
+ return (0);
+ case FSR_FTT_IEEE:
+ return (SIGFPE);
+ case FSR_FTT_SEQERR:
+ __utrap_write("FPU sequence error\n");
+ return (SIGFPE);
+ case FSR_FTT_HWERR:
+ __utrap_write("FPU hardware error\n");
+ return (SIGFPE);
+ case FSR_FTT_UNFIN:
+ case FSR_FTT_UNIMP:
+ break;
+ default:
+ __utrap_write("unknown FPU error\n");
+ return (SIGFPE);
+ }
+
+ fe.fe_fsr = fsr & ~FSR_FTT_MASK;
+ insn = *(u_int32_t *)uf->uf_pc;
+ if (IF_OP(insn) != IOP_MISC || (IF_F3_OP3(insn) != INS2_FPop1 &&
+ IF_F3_OP3(insn) != INS2_FPop2))
+ __utrap_panic("bogus FP fault");
+ tstate = uf->uf_state;
+ sig = __fpu_execute(uf, &fe, insn, tstate);
+ if (sig != 0)
+ return (sig);
+ __asm __volatile("ldx %0, %%fsr" : : "m" (fe.fe_fsr));
+ return (0);
+}
+
+#ifdef FPU_DEBUG
+/*
+ * Dump a `fpn' structure.
+ */
+void
+__fpu_dumpfpn(struct fpn *fp)
+{
+ static const char *const class[] = {
+ "SNAN", "QNAN", "ZERO", "NUM", "INF"
+ };
+
+ printf("%s %c.%x %x %x %xE%d", class[fp->fp_class + 2],
+ fp->fp_sign ? '-' : ' ',
+ fp->fp_mant[0], fp->fp_mant[1],
+ fp->fp_mant[2], fp->fp_mant[3],
+ fp->fp_exp);
+}
+#endif
+
+static const int opmask[] = {0, 0, 1, 3, 1};
+
+/* Decode 5 bit register field depending on the type. */
+#define RN_DECODE(tp, rn) \
+ ((tp) >= FTYPE_DBL ? INSFPdq_RN(rn) & ~opmask[tp] : (rn))
+
+/*
+ * Helper for forming the below case statements. Build only the op3 and opf
+ * field of the instruction, these are the only ones that need to match.
+ */
+#define FOP(op3, opf) \
+ ((op3) << IF_F3_OP3_SHIFT | (opf) << IF_F3_OPF_SHIFT)
+
+/*
+ * Implement a move operation for all supported operand types. The additional
+ * nand and xor parameters will be applied to the upper 32 bit word of the
+ * source operand. This allows to implement fabs and fneg (for fp operands
+ * only!) using this functions, too, by passing (1U << 31) for one of the
+ * parameters, and 0 for the other.
+ */
+static void
+__fpu_mov(struct fpemu *fe, int type, int rd, int rs2, u_int32_t nand,
+ u_int32_t xor)
+{
+
+ if (type == FTYPE_INT || type == FTYPE_SNG)
+ __fpu_setreg(rd, (__fpu_getreg(rs2) & ~nand) ^ xor);
+ else {
+ /*
+ * Need to use the double versions to be able to access
+ * the upper 32 fp registers.
+ */
+ __fpu_setreg64(rd, (__fpu_getreg64(rs2) &
+ ~((u_int64_t)nand << 32)) ^ ((u_int64_t)xor << 32));
+ if (type == FTYPE_EXT)
+ __fpu_setreg64(rd + 2, __fpu_getreg64(rs2 + 2));
+ }
+}
+
+static __inline void
+__fpu_ccmov(struct fpemu *fe, int type, int rd, int rs2,
+ u_int32_t insn, int fcc)
+{
+
+ if (IF_F4_COND(insn) == fcc)
+ __fpu_mov(fe, type, rd, rs2, 0, 0);
+}
+
+static int
+__fpu_cmpck(struct fpemu *fe)
+{
+ u_long fsr;
+ int cx;
+
+ /*
+ * The only possible exception here is NV; catch it
+ * early and get out, as there is no result register.
+ */
+ cx = fe->fe_cx;
+ fsr = fe->fe_fsr | (cx << FSR_CEXC_SHIFT);
+ if (cx != 0) {
+ if (fsr & (FSR_NV << FSR_TEM_SHIFT)) {
+ fe->fe_fsr = (fsr & ~FSR_FTT_MASK) |
+ FSR_FTT(FSR_FTT_IEEE);
+ return (SIGFPE);
+ }
+ fsr |= FSR_NV << FSR_AEXC_SHIFT;
+ }
+ fe->fe_fsr = fsr;
+ return (0);
+}
+
+/*
+ * Execute an FPU instruction (one that runs entirely in the FPU; not
+ * FBfcc or STF, for instance). On return, fe->fe_fs->fs_fsr will be
+ * modified to reflect the setting the hardware would have left.
+ *
+ * Note that we do not catch all illegal opcodes, so you can, for instance,
+ * multiply two integers this way.
+ */
+static int
+__fpu_execute(struct utrapframe *uf, struct fpemu *fe, u_int32_t insn,
+ u_long tstate)
+{
+ struct fpn *fp;
+ int opf, rs1, rs2, rd, type, mask, cx, cond __unused;
+ u_long reg, fsr;
+ u_int space[4];
+
+ /*
+ * `Decode' and execute instruction. Start with no exceptions.
+ * The type of almost any OPF opcode is in the bottom two bits, so we
+ * squish them out here.
+ */
+ opf = insn & (IF_MASK(IF_F3_OP3_SHIFT, IF_F3_OP3_BITS) |
+ IF_MASK(IF_F3_OPF_SHIFT + 2, IF_F3_OPF_BITS - 2));
+ type = IF_F3_OPF(insn) & 3;
+ rs1 = RN_DECODE(type, IF_F3_RS1(insn));
+ rs2 = RN_DECODE(type, IF_F3_RS2(insn));
+ rd = RN_DECODE(type, IF_F3_RD(insn));
+ cond = 0;
+#ifdef notdef
+ if ((rs1 | rs2 | rd) & opmask[type])
+ return (SIGILL);
+#endif
+ fsr = fe->fe_fsr;
+ fe->fe_fsr &= ~FSR_CEXC_MASK;
+ fe->fe_cx = 0;
+ switch (opf) {
+ case FOP(INS2_FPop2, INSFP2_FMOV_CC(IFCC_FCC(0))):
+ __fpu_ccmov(fe, type, rd, rs2, insn, FSR_GET_FCC0(fsr));
+ return (0);
+ case FOP(INS2_FPop2, INSFP2_FMOV_CC(IFCC_FCC(1))):
+ __fpu_ccmov(fe, type, rd, rs2, insn, FSR_GET_FCC1(fsr));
+ return (0);
+ case FOP(INS2_FPop2, INSFP2_FMOV_CC(IFCC_FCC(2))):
+ __fpu_ccmov(fe, type, rd, rs2, insn, FSR_GET_FCC2(fsr));
+ return (0);
+ case FOP(INS2_FPop2, INSFP2_FMOV_CC(IFCC_FCC(3))):
+ __fpu_ccmov(fe, type, rd, rs2, insn, FSR_GET_FCC3(fsr));
+ return (0);
+ case FOP(INS2_FPop2, INSFP2_FMOV_CC(IFCC_ICC)):
+ __fpu_ccmov(fe, type, rd, rs2, insn,
+ (tstate & TSTATE_ICC_MASK) >> TSTATE_ICC_SHIFT);
+ return (0);
+ case FOP(INS2_FPop2, INSFP2_FMOV_CC(IFCC_XCC)):
+ __fpu_ccmov(fe, type, rd, rs2, insn,
+ (tstate & TSTATE_XCC_MASK) >> (TSTATE_XCC_SHIFT));
+ return (0);
+ case FOP(INS2_FPop2, INSFP2_FMOV_RC(IRCOND_Z)):
+ reg = __emul_fetch_reg(uf, IF_F4_RS1(insn));
+ if (reg == 0)
+ __fpu_mov(fe, type, rd, rs2, 0, 0);
+ return (0);
+ case FOP(INS2_FPop2, INSFP2_FMOV_RC(IRCOND_LEZ)):
+ reg = __emul_fetch_reg(uf, IF_F4_RS1(insn));
+ if (reg <= 0)
+ __fpu_mov(fe, type, rd, rs2, 0, 0);
+ return (0);
+ case FOP(INS2_FPop2, INSFP2_FMOV_RC(IRCOND_LZ)):
+ reg = __emul_fetch_reg(uf, IF_F4_RS1(insn));
+ if (reg < 0)
+ __fpu_mov(fe, type, rd, rs2, 0, 0);
+ return (0);
+ case FOP(INS2_FPop2, INSFP2_FMOV_RC(IRCOND_NZ)):
+ reg = __emul_fetch_reg(uf, IF_F4_RS1(insn));
+ if (reg != 0)
+ __fpu_mov(fe, type, rd, rs2, 0, 0);
+ return (0);
+ case FOP(INS2_FPop2, INSFP2_FMOV_RC(IRCOND_GZ)):
+ reg = __emul_fetch_reg(uf, IF_F4_RS1(insn));
+ if (reg > 0)
+ __fpu_mov(fe, type, rd, rs2, 0, 0);
+ return (0);
+ case FOP(INS2_FPop2, INSFP2_FMOV_RC(IRCOND_GEZ)):
+ reg = __emul_fetch_reg(uf, IF_F4_RS1(insn));
+ if (reg >= 0)
+ __fpu_mov(fe, type, rd, rs2, 0, 0);
+ return (0);
+ case FOP(INS2_FPop2, INSFP2_FCMP):
+ __fpu_explode(fe, &fe->fe_f1, type, rs1);
+ __fpu_explode(fe, &fe->fe_f2, type, rs2);
+ __fpu_compare(fe, 0, IF_F3_CC(insn));
+ return (__fpu_cmpck(fe));
+ case FOP(INS2_FPop2, INSFP2_FCMPE):
+ __fpu_explode(fe, &fe->fe_f1, type, rs1);
+ __fpu_explode(fe, &fe->fe_f2, type, rs2);
+ __fpu_compare(fe, 1, IF_F3_CC(insn));
+ return (__fpu_cmpck(fe));
+ case FOP(INS2_FPop1, INSFP1_FMOV):
+ __fpu_mov(fe, type, rd, rs2, 0, 0);
+ return (0);
+ case FOP(INS2_FPop1, INSFP1_FNEG):
+ __fpu_mov(fe, type, rd, rs2, 0, (1U << 31));
+ return (0);
+ case FOP(INS2_FPop1, INSFP1_FABS):
+ __fpu_mov(fe, type, rd, rs2, (1U << 31), 0);
+ return (0);
+ case FOP(INS2_FPop1, INSFP1_FSQRT):
+ __fpu_explode(fe, &fe->fe_f1, type, rs2);
+ fp = __fpu_sqrt(fe);
+ break;
+ case FOP(INS2_FPop1, INSFP1_FADD):
+ __fpu_explode(fe, &fe->fe_f1, type, rs1);
+ __fpu_explode(fe, &fe->fe_f2, type, rs2);
+ fp = __fpu_add(fe);
+ break;
+ case FOP(INS2_FPop1, INSFP1_FSUB):
+ __fpu_explode(fe, &fe->fe_f1, type, rs1);
+ __fpu_explode(fe, &fe->fe_f2, type, rs2);
+ fp = __fpu_sub(fe);
+ break;
+ case FOP(INS2_FPop1, INSFP1_FMUL):
+ __fpu_explode(fe, &fe->fe_f1, type, rs1);
+ __fpu_explode(fe, &fe->fe_f2, type, rs2);
+ fp = __fpu_mul(fe);
+ break;
+ case FOP(INS2_FPop1, INSFP1_FDIV):
+ __fpu_explode(fe, &fe->fe_f1, type, rs1);
+ __fpu_explode(fe, &fe->fe_f2, type, rs2);
+ fp = __fpu_div(fe);
+ break;
+ case FOP(INS2_FPop1, INSFP1_FsMULd):
+ case FOP(INS2_FPop1, INSFP1_FdMULq):
+ if (type == FTYPE_EXT)
+ return (SIGILL);
+ __fpu_explode(fe, &fe->fe_f1, type, rs1);
+ __fpu_explode(fe, &fe->fe_f2, type, rs2);
+ type++; /* single to double, or double to quad */
+ /*
+ * Recalculate rd (the old type applied for the source regs
+ * only, the target one has a different size).
+ */
+ rd = RN_DECODE(type, IF_F3_RD(insn));
+ fp = __fpu_mul(fe);
+ break;
+ case FOP(INS2_FPop1, INSFP1_FxTOs):
+ case FOP(INS2_FPop1, INSFP1_FxTOd):
+ case FOP(INS2_FPop1, INSFP1_FxTOq):
+ type = FTYPE_LNG;
+ rs2 = RN_DECODE(type, IF_F3_RS2(insn));
+ __fpu_explode(fe, fp = &fe->fe_f1, type, rs2);
+ /* sneaky; depends on instruction encoding */
+ type = (IF_F3_OPF(insn) >> 2) & 3;
+ rd = RN_DECODE(type, IF_F3_RD(insn));
+ break;
+ case FOP(INS2_FPop1, INSFP1_FTOx):
+ __fpu_explode(fe, fp = &fe->fe_f1, type, rs2);
+ type = FTYPE_LNG;
+ rd = RN_DECODE(type, IF_F3_RD(insn));
+ break;
+ case FOP(INS2_FPop1, INSFP1_FTOs):
+ case FOP(INS2_FPop1, INSFP1_FTOd):
+ case FOP(INS2_FPop1, INSFP1_FTOq):
+ case FOP(INS2_FPop1, INSFP1_FTOi):
+ __fpu_explode(fe, fp = &fe->fe_f1, type, rs2);
+ /* sneaky; depends on instruction encoding */
+ type = (IF_F3_OPF(insn) >> 2) & 3;
+ rd = RN_DECODE(type, IF_F3_RD(insn));
+ break;
+ default:
+ return (SIGILL);
+ }
+
+ /*
+ * ALU operation is complete. Collapse the result and then check
+ * for exceptions. If we got any, and they are enabled, do not
+ * alter the destination register, just stop with an exception.
+ * Otherwise set new current exceptions and accrue.
+ */
+ __fpu_implode(fe, fp, type, space);
+ cx = fe->fe_cx;
+ if (cx != 0) {
+ mask = (fsr >> FSR_TEM_SHIFT) & FSR_TEM_MASK;
+ if (cx & mask) {
+ /* not accrued??? */
+ fsr = (fsr & ~FSR_FTT_MASK) |
+ FSR_FTT(FSR_FTT_IEEE) |
+ FSR_CEXC(cx_to_trapx[(cx & mask) - 1]);
+ return (SIGFPE);
+ }
+ fsr |= (cx << FSR_CEXC_SHIFT) | (cx << FSR_AEXC_SHIFT);
+ }
+ fe->fe_fsr = fsr;
+ if (type == FTYPE_INT || type == FTYPE_SNG)
+ __fpu_setreg(rd, space[0]);
+ else {
+ __fpu_setreg64(rd, ((u_int64_t)space[0] << 32) | space[1]);
+ if (type == FTYPE_EXT)
+ __fpu_setreg64(rd + 2,
+ ((u_int64_t)space[2] << 32) | space[3]);
+ }
+ return (0); /* success */
+}
diff --git a/lib/libc/sparc64/fpu/fpu_add.c b/lib/libc/sparc64/fpu/fpu_add.c
new file mode 100644
index 000000000000..af493cd5a3e6
--- /dev/null
+++ b/lib/libc/sparc64/fpu/fpu_add.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)fpu_add.c 8.1 (Berkeley) 6/11/93
+ * $NetBSD: fpu_add.c,v 1.3 1996/03/14 19:41:52 christos Exp $
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Perform an FPU add (return x + y).
+ *
+ * To subtract, negate y and call add.
+ */
+
+#include <sys/param.h>
+
+#include <machine/frame.h>
+#include <machine/fp.h>
+#include <machine/fsr.h>
+#include <machine/instr.h>
+
+#include "fpu_arith.h"
+#include "fpu_emu.h"
+#include "fpu_extern.h"
+#include "__sparc_utrap_private.h"
+
+struct fpn *
+__fpu_add(fe)
+ struct fpemu *fe;
+{
+ struct fpn *x = &fe->fe_f1, *y = &fe->fe_f2, *r;
+ u_int r0, r1, r2, r3;
+ int rd;
+
+ /*
+ * Put the `heavier' operand on the right (see fpu_emu.h).
+ * Then we will have one of the following cases, taken in the
+ * following order:
+ *
+ * - y = NaN. Implied: if only one is a signalling NaN, y is.
+ * The result is y.
+ * - y = Inf. Implied: x != NaN (is 0, number, or Inf: the NaN
+ * case was taken care of earlier).
+ * If x = -y, the result is NaN. Otherwise the result
+ * is y (an Inf of whichever sign).
+ * - y is 0. Implied: x = 0.
+ * If x and y differ in sign (one positive, one negative),
+ * the result is +0 except when rounding to -Inf. If same:
+ * +0 + +0 = +0; -0 + -0 = -0.
+ * - x is 0. Implied: y != 0.
+ * Result is y.
+ * - other. Implied: both x and y are numbers.
+ * Do addition a la Hennessey & Patterson.
+ */
+ ORDER(x, y);
+ if (ISNAN(y))
+ return (y);
+ if (ISINF(y)) {
+ if (ISINF(x) && x->fp_sign != y->fp_sign)
+ return (__fpu_newnan(fe));
+ return (y);
+ }
+ rd = FSR_GET_RD(fe->fe_fsr);
+ if (ISZERO(y)) {
+ if (rd != FSR_RD_NINF) /* only -0 + -0 gives -0 */
+ y->fp_sign &= x->fp_sign;
+ else /* any -0 operand gives -0 */
+ y->fp_sign |= x->fp_sign;
+ return (y);
+ }
+ if (ISZERO(x))
+ return (y);
+ /*
+ * We really have two numbers to add, although their signs may
+ * differ. Make the exponents match, by shifting the smaller
+ * number right (e.g., 1.011 => 0.1011) and increasing its
+ * exponent (2^3 => 2^4). Note that we do not alter the exponents
+ * of x and y here.
+ */
+ r = &fe->fe_f3;
+ r->fp_class = FPC_NUM;
+ if (x->fp_exp == y->fp_exp) {
+ r->fp_exp = x->fp_exp;
+ r->fp_sticky = 0;
+ } else {
+ if (x->fp_exp < y->fp_exp) {
+ /*
+ * Try to avoid subtract case iii (see below).
+ * This also guarantees that x->fp_sticky = 0.
+ */
+ SWAP(x, y);
+ }
+ /* now x->fp_exp > y->fp_exp */
+ r->fp_exp = x->fp_exp;
+ r->fp_sticky = __fpu_shr(y, x->fp_exp - y->fp_exp);
+ }
+ r->fp_sign = x->fp_sign;
+ if (x->fp_sign == y->fp_sign) {
+ FPU_DECL_CARRY
+
+ /*
+ * The signs match, so we simply add the numbers. The result
+ * may be `supernormal' (as big as 1.111...1 + 1.111...1, or
+ * 11.111...0). If so, a single bit shift-right will fix it
+ * (but remember to adjust the exponent).
+ */
+ /* r->fp_mant = x->fp_mant + y->fp_mant */
+ FPU_ADDS(r->fp_mant[3], x->fp_mant[3], y->fp_mant[3]);
+ FPU_ADDCS(r->fp_mant[2], x->fp_mant[2], y->fp_mant[2]);
+ FPU_ADDCS(r->fp_mant[1], x->fp_mant[1], y->fp_mant[1]);
+ FPU_ADDC(r0, x->fp_mant[0], y->fp_mant[0]);
+ if ((r->fp_mant[0] = r0) >= FP_2) {
+ (void) __fpu_shr(r, 1);
+ r->fp_exp++;
+ }
+ } else {
+ FPU_DECL_CARRY
+
+ /*
+ * The signs differ, so things are rather more difficult.
+ * H&P would have us negate the negative operand and add;
+ * this is the same as subtracting the negative operand.
+ * This is quite a headache. Instead, we will subtract
+ * y from x, regardless of whether y itself is the negative
+ * operand. When this is done one of three conditions will
+ * hold, depending on the magnitudes of x and y:
+ * case i) |x| > |y|. The result is just x - y,
+ * with x's sign, but it may need to be normalized.
+ * case ii) |x| = |y|. The result is 0 (maybe -0)
+ * so must be fixed up.
+ * case iii) |x| < |y|. We goofed; the result should
+ * be (y - x), with the same sign as y.
+ * We could compare |x| and |y| here and avoid case iii,
+ * but that would take just as much work as the subtract.
+ * We can tell case iii has occurred by an overflow.
+ *
+ * N.B.: since x->fp_exp >= y->fp_exp, x->fp_sticky = 0.
+ */
+ /* r->fp_mant = x->fp_mant - y->fp_mant */
+ FPU_SET_CARRY(y->fp_sticky);
+ FPU_SUBCS(r3, x->fp_mant[3], y->fp_mant[3]);
+ FPU_SUBCS(r2, x->fp_mant[2], y->fp_mant[2]);
+ FPU_SUBCS(r1, x->fp_mant[1], y->fp_mant[1]);
+ FPU_SUBC(r0, x->fp_mant[0], y->fp_mant[0]);
+ if (r0 < FP_2) {
+ /* cases i and ii */
+ if ((r0 | r1 | r2 | r3) == 0) {
+ /* case ii */
+ r->fp_class = FPC_ZERO;
+ r->fp_sign = rd == FSR_RD_NINF;
+ return (r);
+ }
+ } else {
+ /*
+ * Oops, case iii. This can only occur when the
+ * exponents were equal, in which case neither
+ * x nor y have sticky bits set. Flip the sign
+ * (to y's sign) and negate the result to get y - x.
+ */
+#ifdef DIAGNOSTIC
+ if (x->fp_exp != y->fp_exp || r->fp_sticky)
+ __utrap_panic("fpu_add");
+#endif
+ r->fp_sign = y->fp_sign;
+ FPU_SUBS(r3, 0, r3);
+ FPU_SUBCS(r2, 0, r2);
+ FPU_SUBCS(r1, 0, r1);
+ FPU_SUBC(r0, 0, r0);
+ }
+ r->fp_mant[3] = r3;
+ r->fp_mant[2] = r2;
+ r->fp_mant[1] = r1;
+ r->fp_mant[0] = r0;
+ if (r0 < FP_1)
+ __fpu_norm(r);
+ }
+ return (r);
+}
diff --git a/lib/libc/sparc64/fpu/fpu_arith.h b/lib/libc/sparc64/fpu/fpu_arith.h
new file mode 100644
index 000000000000..292cd708a55f
--- /dev/null
+++ b/lib/libc/sparc64/fpu/fpu_arith.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)fpu_arith.h 8.1 (Berkeley) 6/11/93
+ * $NetBSD: fpu_arith.h,v 1.3 2000/07/24 04:11:03 mycroft Exp $
+ * $FreeBSD$
+ */
+
+/*
+ * Extended-precision arithmetic.
+ *
+ * We hold the notion of a `carry register', which may or may not be a
+ * machine carry bit or register. On the SPARC, it is just the machine's
+ * carry bit.
+ *
+ * In the worst case, you can compute the carry from x+y as
+ * (unsigned)(x + y) < (unsigned)x
+ * and from x+y+c as
+ * ((unsigned)(x + y + c) <= (unsigned)x && (y|c) != 0)
+ * for example.
+ */
+
+/* set up for extended-precision arithemtic */
+#define FPU_DECL_CARRY
+
+/*
+ * We have three kinds of add:
+ * add with carry: r = x + y + c
+ * add (ignoring current carry) and set carry: c'r = x + y + 0
+ * add with carry and set carry: c'r = x + y + c
+ * The macros use `C' for `use carry' and `S' for `set carry'.
+ * Note that the state of the carry is undefined after ADDC and SUBC,
+ * so if all you have for these is `add with carry and set carry',
+ * that is OK.
+ *
+ * The same goes for subtract, except that we compute x - y - c.
+ *
+ * Finally, we have a way to get the carry into a `regular' variable,
+ * or set it from a value. SET_CARRY turns 0 into no-carry, nonzero
+ * into carry; GET_CARRY sets its argument to 0 or 1.
+ */
+#define FPU_ADDC(r, x, y) \
+ __asm __volatile("addx %1,%2,%0" : "=r"(r) : "r"(x), "r"(y))
+#define FPU_ADDS(r, x, y) \
+ __asm __volatile("addcc %1,%2,%0" : "=r"(r) : "r"(x), "r"(y))
+#define FPU_ADDCS(r, x, y) \
+ __asm __volatile("addxcc %1,%2,%0" : "=r"(r) : "r"(x), "r"(y))
+#define FPU_SUBC(r, x, y) \
+ __asm __volatile("subx %1,%2,%0" : "=r"(r) : "r"(x), "r"(y))
+#define FPU_SUBS(r, x, y) \
+ __asm __volatile("subcc %1,%2,%0" : "=r"(r) : "r"(x), "r"(y))
+#define FPU_SUBCS(r, x, y) \
+ __asm __volatile("subxcc %1,%2,%0" : "=r"(r) : "r"(x), "r"(y))
+
+#define FPU_GET_CARRY(r) __asm __volatile("addx %%g0,%%g0,%0" : "=r"(r))
+#define FPU_SET_CARRY(v) __asm __volatile("addcc %0,-1,%%g0" : : "r"(v))
+
+#define FPU_SHL1_BY_ADD /* shift left 1 faster by ADDC than (a<<1)|(b>>31) */
diff --git a/lib/libc/sparc64/fpu/fpu_compare.c b/lib/libc/sparc64/fpu/fpu_compare.c
new file mode 100644
index 000000000000..84b00bf964ee
--- /dev/null
+++ b/lib/libc/sparc64/fpu/fpu_compare.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)fpu_compare.c 8.1 (Berkeley) 6/11/93
+ * $NetBSD: fpu_compare.c,v 1.3 2001/08/26 05:46:31 eeh Exp $
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * CMP and CMPE instructions.
+ *
+ * These rely on the fact that our internal wide format is achieved by
+ * adding zero bits to the end of narrower mantissas.
+ */
+
+#include <sys/types.h>
+
+#include <machine/frame.h>
+#include <machine/fp.h>
+#include <machine/fsr.h>
+
+#include "fpu_arith.h"
+#include "fpu_emu.h"
+#include "fpu_extern.h"
+
+static u_long fcc_nmask[] = {
+ ~FSR_FCC0_MASK,
+ ~FSR_FCC1_MASK,
+ ~FSR_FCC2_MASK,
+ ~FSR_FCC3_MASK
+};
+
+/* XXX: we don't use the FSR_FCCx macros here; it's much easier this way. */
+static int fcc_shift[] = {
+ FSR_FCC0_SHIFT,
+ FSR_FCC1_SHIFT,
+ FSR_FCC2_SHIFT,
+ FSR_FCC3_SHIFT
+};
+
+/*
+ * Perform a compare instruction (with or without unordered exception).
+ * This updates the fcc field in the fsr.
+ *
+ * If either operand is NaN, the result is unordered. For cmpe, this
+ * causes an NV exception. Everything else is ordered:
+ * |Inf| > |numbers| > |0|.
+ * We already arranged for fp_class(Inf) > fp_class(numbers) > fp_class(0),
+ * so we get this directly. Note, however, that two zeros compare equal
+ * regardless of sign, while everything else depends on sign.
+ *
+ * Incidentally, two Infs of the same sign compare equal (per the 80387
+ * manual---it would be nice if the SPARC documentation were more
+ * complete).
+ */
+void
+__fpu_compare(struct fpemu *fe, int cmpe, int fcc)
+{
+ struct fpn *a, *b;
+ int cc;
+ FPU_DECL_CARRY
+
+ a = &fe->fe_f1;
+ b = &fe->fe_f2;
+
+ if (ISNAN(a) || ISNAN(b)) {
+ /*
+ * In any case, we already got an exception for signalling
+ * NaNs; here we may replace that one with an identical
+ * exception, but so what?.
+ */
+ if (cmpe)
+ fe->fe_cx = FSR_NV;
+ cc = FSR_CC_UO;
+ goto done;
+ }
+
+ /*
+ * Must handle both-zero early to avoid sign goofs. Otherwise,
+ * at most one is 0, and if the signs differ we are done.
+ */
+ if (ISZERO(a) && ISZERO(b)) {
+ cc = FSR_CC_EQ;
+ goto done;
+ }
+ if (a->fp_sign) { /* a < 0 (or -0) */
+ if (!b->fp_sign) { /* b >= 0 (or if a = -0, b > 0) */
+ cc = FSR_CC_LT;
+ goto done;
+ }
+ } else { /* a > 0 (or +0) */
+ if (b->fp_sign) { /* b <= -0 (or if a = +0, b < 0) */
+ cc = FSR_CC_GT;
+ goto done;
+ }
+ }
+
+ /*
+ * Now the signs are the same (but may both be negative). All
+ * we have left are these cases:
+ *
+ * |a| < |b| [classes or values differ]
+ * |a| > |b| [classes or values differ]
+ * |a| == |b| [classes and values identical]
+ *
+ * We define `diff' here to expand these as:
+ *
+ * |a| < |b|, a,b >= 0: a < b => FSR_CC_LT
+ * |a| < |b|, a,b < 0: a > b => FSR_CC_GT
+ * |a| > |b|, a,b >= 0: a > b => FSR_CC_GT
+ * |a| > |b|, a,b < 0: a < b => FSR_CC_LT
+ */
+#define opposite_cc(cc) ((cc) == FSR_CC_LT ? FSR_CC_GT : FSR_CC_LT)
+#define diff(magnitude) (a->fp_sign ? opposite_cc(magnitude) : (magnitude))
+ if (a->fp_class < b->fp_class) { /* |a| < |b| */
+ cc = diff(FSR_CC_LT);
+ goto done;
+ }
+ if (a->fp_class > b->fp_class) { /* |a| > |b| */
+ cc = diff(FSR_CC_GT);
+ goto done;
+ }
+ /* now none can be 0: only Inf and numbers remain */
+ if (ISINF(a)) { /* |Inf| = |Inf| */
+ cc = FSR_CC_EQ;
+ goto done;
+ }
+ /*
+ * Only numbers remain. To compare two numbers in magnitude, we
+ * simply subtract them.
+ */
+ a = __fpu_sub(fe);
+ if (a->fp_class == FPC_ZERO)
+ cc = FSR_CC_EQ;
+ else
+ cc = diff(FSR_CC_GT);
+
+done:
+ fe->fe_fsr = (fe->fe_fsr & fcc_nmask[fcc]) |
+ ((u_long)cc << fcc_shift[fcc]);
+}
diff --git a/lib/libc/sparc64/fpu/fpu_div.c b/lib/libc/sparc64/fpu/fpu_div.c
new file mode 100644
index 000000000000..4748daf40bc4
--- /dev/null
+++ b/lib/libc/sparc64/fpu/fpu_div.c
@@ -0,0 +1,270 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)fpu_div.c 8.1 (Berkeley) 6/11/93
+ * $NetBSD: fpu_div.c,v 1.2 1994/11/20 20:52:38 deraadt Exp $
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Perform an FPU divide (return x / y).
+ */
+
+#include <sys/types.h>
+
+#include <machine/frame.h>
+#include <machine/fp.h>
+#include <machine/fsr.h>
+
+#include "fpu_arith.h"
+#include "fpu_emu.h"
+#include "fpu_extern.h"
+
+/*
+ * Division of normal numbers is done as follows:
+ *
+ * x and y are floating point numbers, i.e., in the form 1.bbbb * 2^e.
+ * If X and Y are the mantissas (1.bbbb's), the quotient is then:
+ *
+ * q = (X / Y) * 2^((x exponent) - (y exponent))
+ *
+ * Since X and Y are both in [1.0,2.0), the quotient's mantissa (X / Y)
+ * will be in [0.5,2.0). Moreover, it will be less than 1.0 if and only
+ * if X < Y. In that case, it will have to be shifted left one bit to
+ * become a normal number, and the exponent decremented. Thus, the
+ * desired exponent is:
+ *
+ * left_shift = x->fp_mant < y->fp_mant;
+ * result_exp = x->fp_exp - y->fp_exp - left_shift;
+ *
+ * The quotient mantissa X/Y can then be computed one bit at a time
+ * using the following algorithm:
+ *
+ * Q = 0; -- Initial quotient.
+ * R = X; -- Initial remainder,
+ * if (left_shift) -- but fixed up in advance.
+ * R *= 2;
+ * for (bit = FP_NMANT; --bit >= 0; R *= 2) {
+ * if (R >= Y) {
+ * Q |= 1 << bit;
+ * R -= Y;
+ * }
+ * }
+ *
+ * The subtraction R -= Y always removes the uppermost bit from R (and
+ * can sometimes remove additional lower-order 1 bits); this proof is
+ * left to the reader.
+ *
+ * This loop correctly calculates the guard and round bits since they are
+ * included in the expanded internal representation. The sticky bit
+ * is to be set if and only if any other bits beyond guard and round
+ * would be set. From the above it is obvious that this is true if and
+ * only if the remainder R is nonzero when the loop terminates.
+ *
+ * Examining the loop above, we can see that the quotient Q is built
+ * one bit at a time ``from the top down''. This means that we can
+ * dispense with the multi-word arithmetic and just build it one word
+ * at a time, writing each result word when it is done.
+ *
+ * Furthermore, since X and Y are both in [1.0,2.0), we know that,
+ * initially, R >= Y. (Recall that, if X < Y, R is set to X * 2 and
+ * is therefore at in [2.0,4.0).) Thus Q is sure to have bit FP_NMANT-1
+ * set, and R can be set initially to either X - Y (when X >= Y) or
+ * 2X - Y (when X < Y). In addition, comparing R and Y is difficult,
+ * so we will simply calculate R - Y and see if that underflows.
+ * This leads to the following revised version of the algorithm:
+ *
+ * R = X;
+ * bit = FP_1;
+ * D = R - Y;
+ * if (D >= 0) {
+ * result_exp = x->fp_exp - y->fp_exp;
+ * R = D;
+ * q = bit;
+ * bit >>= 1;
+ * } else {
+ * result_exp = x->fp_exp - y->fp_exp - 1;
+ * q = 0;
+ * }
+ * R <<= 1;
+ * do {
+ * D = R - Y;
+ * if (D >= 0) {
+ * q |= bit;
+ * R = D;
+ * }
+ * R <<= 1;
+ * } while ((bit >>= 1) != 0);
+ * Q[0] = q;
+ * for (i = 1; i < 4; i++) {
+ * q = 0, bit = 1 << 31;
+ * do {
+ * D = R - Y;
+ * if (D >= 0) {
+ * q |= bit;
+ * R = D;
+ * }
+ * R <<= 1;
+ * } while ((bit >>= 1) != 0);
+ * Q[i] = q;
+ * }
+ *
+ * This can be refined just a bit further by moving the `R <<= 1'
+ * calculations to the front of the do-loops and eliding the first one.
+ * The process can be terminated immediately whenever R becomes 0, but
+ * this is relatively rare, and we do not bother.
+ */
+
+struct fpn *
+__fpu_div(fe)
+ struct fpemu *fe;
+{
+ struct fpn *x = &fe->fe_f1, *y = &fe->fe_f2;
+ u_int q, bit;
+ u_int r0, r1, r2, r3, d0, d1, d2, d3, y0, y1, y2, y3;
+ FPU_DECL_CARRY
+
+ /*
+ * Since divide is not commutative, we cannot just use ORDER.
+ * Check either operand for NaN first; if there is at least one,
+ * order the signalling one (if only one) onto the right, then
+ * return it. Otherwise we have the following cases:
+ *
+ * Inf / Inf = NaN, plus NV exception
+ * Inf / num = Inf [i.e., return x #]
+ * Inf / 0 = Inf [i.e., return x #]
+ * 0 / Inf = 0 [i.e., return x #]
+ * 0 / num = 0 [i.e., return x #]
+ * 0 / 0 = NaN, plus NV exception
+ * num / Inf = 0 #
+ * num / num = num (do the divide)
+ * num / 0 = Inf #, plus DZ exception
+ *
+ * # Sign of result is XOR of operand signs.
+ */
+ if (ISNAN(x) || ISNAN(y)) {
+ ORDER(x, y);
+ return (y);
+ }
+ if (ISINF(x) || ISZERO(x)) {
+ if (x->fp_class == y->fp_class)
+ return (__fpu_newnan(fe));
+ x->fp_sign ^= y->fp_sign;
+ return (x);
+ }
+
+ x->fp_sign ^= y->fp_sign;
+ if (ISINF(y)) {
+ x->fp_class = FPC_ZERO;
+ return (x);
+ }
+ if (ISZERO(y)) {
+ fe->fe_cx = FSR_DZ;
+ x->fp_class = FPC_INF;
+ return (x);
+ }
+
+ /*
+ * Macros for the divide. See comments at top for algorithm.
+ * Note that we expand R, D, and Y here.
+ */
+
+#define SUBTRACT /* D = R - Y */ \
+ FPU_SUBS(d3, r3, y3); FPU_SUBCS(d2, r2, y2); \
+ FPU_SUBCS(d1, r1, y1); FPU_SUBC(d0, r0, y0)
+
+#define NONNEGATIVE /* D >= 0 */ \
+ ((int)d0 >= 0)
+
+#ifdef FPU_SHL1_BY_ADD
+#define SHL1 /* R <<= 1 */ \
+ FPU_ADDS(r3, r3, r3); FPU_ADDCS(r2, r2, r2); \
+ FPU_ADDCS(r1, r1, r1); FPU_ADDC(r0, r0, r0)
+#else
+#define SHL1 \
+ r0 = (r0 << 1) | (r1 >> 31), r1 = (r1 << 1) | (r2 >> 31), \
+ r2 = (r2 << 1) | (r3 >> 31), r3 <<= 1
+#endif
+
+#define LOOP /* do ... while (bit >>= 1) */ \
+ do { \
+ SHL1; \
+ SUBTRACT; \
+ if (NONNEGATIVE) { \
+ q |= bit; \
+ r0 = d0, r1 = d1, r2 = d2, r3 = d3; \
+ } \
+ } while ((bit >>= 1) != 0)
+
+#define WORD(r, i) /* calculate r->fp_mant[i] */ \
+ q = 0; \
+ bit = 1 << 31; \
+ LOOP; \
+ (x)->fp_mant[i] = q
+
+ /* Setup. Note that we put our result in x. */
+ r0 = x->fp_mant[0];
+ r1 = x->fp_mant[1];
+ r2 = x->fp_mant[2];
+ r3 = x->fp_mant[3];
+ y0 = y->fp_mant[0];
+ y1 = y->fp_mant[1];
+ y2 = y->fp_mant[2];
+ y3 = y->fp_mant[3];
+
+ bit = FP_1;
+ SUBTRACT;
+ if (NONNEGATIVE) {
+ x->fp_exp -= y->fp_exp;
+ r0 = d0, r1 = d1, r2 = d2, r3 = d3;
+ q = bit;
+ bit >>= 1;
+ } else {
+ x->fp_exp -= y->fp_exp + 1;
+ q = 0;
+ }
+ LOOP;
+ x->fp_mant[0] = q;
+ WORD(x, 1);
+ WORD(x, 2);
+ WORD(x, 3);
+ x->fp_sticky = r0 | r1 | r2 | r3;
+
+ return (x);
+}
diff --git a/lib/libc/sparc64/fpu/fpu_emu.h b/lib/libc/sparc64/fpu/fpu_emu.h
new file mode 100644
index 000000000000..0822de89e143
--- /dev/null
+++ b/lib/libc/sparc64/fpu/fpu_emu.h
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)fpu_emu.h 8.1 (Berkeley) 6/11/93
+ * $NetBSD: fpu_emu.h,v 1.4 2000/08/03 18:32:07 eeh Exp $
+ * $FreeBSD$
+ */
+
+/*
+ * Floating point emulator (tailored for SPARC, but structurally
+ * machine-independent).
+ *
+ * Floating point numbers are carried around internally in an `expanded'
+ * or `unpacked' form consisting of:
+ * - sign
+ * - unbiased exponent
+ * - mantissa (`1.' + 112-bit fraction + guard + round)
+ * - sticky bit
+ * Any implied `1' bit is inserted, giving a 113-bit mantissa that is
+ * always nonzero. Additional low-order `guard' and `round' bits are
+ * scrunched in, making the entire mantissa 115 bits long. This is divided
+ * into four 32-bit words, with `spare' bits left over in the upper part
+ * of the top word (the high bits of fp_mant[0]). An internal `exploded'
+ * number is thus kept within the half-open interval [1.0,2.0) (but see
+ * the `number classes' below). This holds even for denormalized numbers:
+ * when we explode an external denorm, we normalize it, introducing low-order
+ * zero bits, so that the rest of the code always sees normalized values.
+ *
+ * Note that a number of our algorithms use the `spare' bits at the top.
+ * The most demanding algorithm---the one for sqrt---depends on two such
+ * bits, so that it can represent values up to (but not including) 8.0,
+ * and then it needs a carry on top of that, so that we need three `spares'.
+ *
+ * The sticky-word is 32 bits so that we can use `OR' operators to goosh
+ * whole words from the mantissa into it.
+ *
+ * All operations are done in this internal extended precision. According
+ * to Hennesey & Patterson, Appendix A, rounding can be repeated---that is,
+ * it is OK to do a+b in extended precision and then round the result to
+ * single precision---provided single, double, and extended precisions are
+ * `far enough apart' (they always are), but we will try to avoid any such
+ * extra work where possible.
+ */
+
+#ifndef _SPARC64_FPU_FPU_EMU_H_
+#define _SPARC64_FPU_FPU_EMU_H_
+
+#include "fpu_reg.h"
+
+struct fpn {
+ int fp_class; /* see below */
+ int fp_sign; /* 0 => positive, 1 => negative */
+ int fp_exp; /* exponent (unbiased) */
+ int fp_sticky; /* nonzero bits lost at right end */
+ u_int fp_mant[4]; /* 115-bit mantissa */
+};
+
+#define FP_NMANT 115 /* total bits in mantissa (incl g,r) */
+#define FP_NG 2 /* number of low-order guard bits */
+#define FP_LG ((FP_NMANT - 1) & 31) /* log2(1.0) for fp_mant[0] */
+#define FP_LG2 ((FP_NMANT - 1) & 63) /* log2(1.0) for fp_mant[0] and fp_mant[1] */
+#define FP_QUIETBIT (1 << (FP_LG - 1)) /* Quiet bit in NaNs (0.5) */
+#define FP_1 (1 << FP_LG) /* 1.0 in fp_mant[0] */
+#define FP_2 (1 << (FP_LG + 1)) /* 2.0 in fp_mant[0] */
+
+/*
+ * Number classes. Since zero, Inf, and NaN cannot be represented using
+ * the above layout, we distinguish these from other numbers via a class.
+ * In addition, to make computation easier and to follow Appendix N of
+ * the SPARC Version 8 standard, we give each kind of NaN a separate class.
+ */
+#define FPC_SNAN -2 /* signalling NaN (sign irrelevant) */
+#define FPC_QNAN -1 /* quiet NaN (sign irrelevant) */
+#define FPC_ZERO 0 /* zero (sign matters) */
+#define FPC_NUM 1 /* number (sign matters) */
+#define FPC_INF 2 /* infinity (sign matters) */
+
+#define ISNAN(fp) ((fp)->fp_class < 0)
+#define ISZERO(fp) ((fp)->fp_class == 0)
+#define ISINF(fp) ((fp)->fp_class == FPC_INF)
+
+/*
+ * ORDER(x,y) `sorts' a pair of `fpn *'s so that the right operand (y) points
+ * to the `more significant' operand for our purposes. Appendix N says that
+ * the result of a computation involving two numbers are:
+ *
+ * If both are SNaN: operand 2, converted to Quiet
+ * If only one is SNaN: the SNaN operand, converted to Quiet
+ * If both are QNaN: operand 2
+ * If only one is QNaN: the QNaN operand
+ *
+ * In addition, in operations with an Inf operand, the result is usually
+ * Inf. The class numbers are carefully arranged so that if
+ * (unsigned)class(op1) > (unsigned)class(op2)
+ * then op1 is the one we want; otherwise op2 is the one we want.
+ */
+#define ORDER(x, y) { \
+ if ((u_int)(x)->fp_class > (u_int)(y)->fp_class) \
+ SWAP(x, y); \
+}
+#define SWAP(x, y) { \
+ register struct fpn *swap; \
+ swap = (x), (x) = (y), (y) = swap; \
+}
+
+/*
+ * Floating point operand types. FTYPE_LNG is syntethic (it does not occur in
+ * instructions).
+ */
+#define FTYPE_INT INSFP_i
+#define FTYPE_SNG INSFP_s
+#define FTYPE_DBL INSFP_d
+#define FTYPE_EXT INSFP_q
+#define FTYPE_LNG 4
+
+/*
+ * Emulator state.
+ */
+struct fpemu {
+ u_long fe_fsr; /* fsr copy (modified during op) */
+ int fe_cx; /* exceptions */
+ int pad; /* align access to following fields */
+ struct fpn fe_f1; /* operand 1 */
+ struct fpn fe_f2; /* operand 2, if required */
+ struct fpn fe_f3; /* available storage for result */
+};
+
+/*
+ * Arithmetic functions.
+ * Each of these may modify its inputs (f1,f2) and/or the temporary.
+ * Each returns a pointer to the result and/or sets exceptions.
+ */
+#define __fpu_sub(fe) (ISNAN(&(fe)->fe_f2) ? 0 : ((fe)->fe_f2.fp_sign ^= 1), \
+ __fpu_add(fe))
+
+#ifdef FPU_DEBUG
+#define FPE_INSN 0x1
+#define FPE_REG 0x2
+extern int __fpe_debug;
+void __fpu_dumpfpn(struct fpn *);
+#define DPRINTF(x, y) if (__fpe_debug & (x)) printf y
+#define DUMPFPN(x, f) if (__fpe_debug & (x)) __fpu_dumpfpn((f))
+#else
+#define DPRINTF(x, y)
+#define DUMPFPN(x, f)
+#endif
+
+#endif /* !_SPARC64_FPU_FPU_EXTERN_H_ */
diff --git a/lib/libc/sparc64/fpu/fpu_explode.c b/lib/libc/sparc64/fpu/fpu_explode.c
new file mode 100644
index 000000000000..474e0dfc7d63
--- /dev/null
+++ b/lib/libc/sparc64/fpu/fpu_explode.c
@@ -0,0 +1,324 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)fpu_explode.c 8.1 (Berkeley) 6/11/93
+ * $NetBSD: fpu_explode.c,v 1.5 2000/08/03 18:32:08 eeh Exp $
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * FPU subroutines: `explode' the machine's `packed binary' format numbers
+ * into our internal format.
+ */
+
+#include <sys/param.h>
+
+#ifdef FPU_DEBUG
+#include <stdio.h>
+#endif
+
+#include <machine/frame.h>
+#include <machine/fp.h>
+#include <machine/fsr.h>
+#include <machine/ieee.h>
+#include <machine/instr.h>
+
+#include "fpu_arith.h"
+#include "fpu_emu.h"
+#include "fpu_extern.h"
+#include "__sparc_utrap_private.h"
+
+/*
+ * N.B.: in all of the following, we assume the FP format is
+ *
+ * ---------------------------
+ * | s | exponent | fraction |
+ * ---------------------------
+ *
+ * (which represents -1**s * 1.fraction * 2**exponent), so that the
+ * sign bit is way at the top (bit 31), the exponent is next, and
+ * then the remaining bits mark the fraction. A zero exponent means
+ * zero or denormalized (0.fraction rather than 1.fraction), and the
+ * maximum possible exponent, 2bias+1, signals inf (fraction==0) or NaN.
+ *
+ * Since the sign bit is always the topmost bit---this holds even for
+ * integers---we set that outside all the *tof functions. Each function
+ * returns the class code for the new number (but note that we use
+ * FPC_QNAN for all NaNs; fpu_explode will fix this if appropriate).
+ */
+
+/*
+ * int -> fpn.
+ */
+int
+__fpu_itof(fp, i)
+ struct fpn *fp;
+ u_int i;
+{
+
+ if (i == 0)
+ return (FPC_ZERO);
+ /*
+ * The value FP_1 represents 2^FP_LG, so set the exponent
+ * there and let normalization fix it up. Convert negative
+ * numbers to sign-and-magnitude. Note that this relies on
+ * fpu_norm()'s handling of `supernormals'; see fpu_subr.c.
+ */
+ fp->fp_exp = FP_LG;
+ /*
+ * The sign bit decides whether i should be interpreted as
+ * a signed or unsigned entity.
+ */
+ if (fp->fp_sign && (int)i < 0)
+ fp->fp_mant[0] = -i;
+ else
+ fp->fp_mant[0] = i;
+ fp->fp_mant[1] = 0;
+ fp->fp_mant[2] = 0;
+ fp->fp_mant[3] = 0;
+ __fpu_norm(fp);
+ return (FPC_NUM);
+}
+
+/*
+ * 64-bit int -> fpn.
+ */
+int
+__fpu_xtof(fp, i)
+ struct fpn *fp;
+ u_int64_t i;
+{
+
+ if (i == 0)
+ return (FPC_ZERO);
+ /*
+ * The value FP_1 represents 2^FP_LG, so set the exponent
+ * there and let normalization fix it up. Convert negative
+ * numbers to sign-and-magnitude. Note that this relies on
+ * fpu_norm()'s handling of `supernormals'; see fpu_subr.c.
+ */
+ fp->fp_exp = FP_LG2;
+ /*
+ * The sign bit decides whether i should be interpreted as
+ * a signed or unsigned entity.
+ */
+ if (fp->fp_sign && (int64_t)i < 0)
+ *((int64_t *)fp->fp_mant) = -i;
+ else
+ *((int64_t *)fp->fp_mant) = i;
+ fp->fp_mant[2] = 0;
+ fp->fp_mant[3] = 0;
+ __fpu_norm(fp);
+ return (FPC_NUM);
+}
+
+#define mask(nbits) ((1L << (nbits)) - 1)
+
+/*
+ * All external floating formats convert to internal in the same manner,
+ * as defined here. Note that only normals get an implied 1.0 inserted.
+ */
+#define FP_TOF(exp, expbias, allfrac, f0, f1, f2, f3) \
+ if (exp == 0) { \
+ if (allfrac == 0) \
+ return (FPC_ZERO); \
+ fp->fp_exp = 1 - expbias; \
+ fp->fp_mant[0] = f0; \
+ fp->fp_mant[1] = f1; \
+ fp->fp_mant[2] = f2; \
+ fp->fp_mant[3] = f3; \
+ __fpu_norm(fp); \
+ return (FPC_NUM); \
+ } \
+ if (exp == (2 * expbias + 1)) { \
+ if (allfrac == 0) \
+ return (FPC_INF); \
+ fp->fp_mant[0] = f0; \
+ fp->fp_mant[1] = f1; \
+ fp->fp_mant[2] = f2; \
+ fp->fp_mant[3] = f3; \
+ return (FPC_QNAN); \
+ } \
+ fp->fp_exp = exp - expbias; \
+ fp->fp_mant[0] = FP_1 | f0; \
+ fp->fp_mant[1] = f1; \
+ fp->fp_mant[2] = f2; \
+ fp->fp_mant[3] = f3; \
+ return (FPC_NUM)
+
+/*
+ * 32-bit single precision -> fpn.
+ * We assume a single occupies at most (64-FP_LG) bits in the internal
+ * format: i.e., needs at most fp_mant[0] and fp_mant[1].
+ */
+int
+__fpu_stof(fp, i)
+ struct fpn *fp;
+ u_int i;
+{
+ int exp;
+ u_int frac, f0, f1;
+#define SNG_SHIFT (SNG_FRACBITS - FP_LG)
+
+ exp = (i >> (32 - 1 - SNG_EXPBITS)) & mask(SNG_EXPBITS);
+ frac = i & mask(SNG_FRACBITS);
+ f0 = frac >> SNG_SHIFT;
+ f1 = frac << (32 - SNG_SHIFT);
+ FP_TOF(exp, SNG_EXP_BIAS, frac, f0, f1, 0, 0);
+}
+
+/*
+ * 64-bit double -> fpn.
+ * We assume this uses at most (96-FP_LG) bits.
+ */
+int
+__fpu_dtof(fp, i, j)
+ struct fpn *fp;
+ u_int i, j;
+{
+ int exp;
+ u_int frac, f0, f1, f2;
+#define DBL_SHIFT (DBL_FRACBITS - 32 - FP_LG)
+
+ exp = (i >> (32 - 1 - DBL_EXPBITS)) & mask(DBL_EXPBITS);
+ frac = i & mask(DBL_FRACBITS - 32);
+ f0 = frac >> DBL_SHIFT;
+ f1 = (frac << (32 - DBL_SHIFT)) | (j >> DBL_SHIFT);
+ f2 = j << (32 - DBL_SHIFT);
+ frac |= j;
+ FP_TOF(exp, DBL_EXP_BIAS, frac, f0, f1, f2, 0);
+}
+
+/*
+ * 128-bit extended -> fpn.
+ */
+int
+__fpu_qtof(fp, i, j, k, l)
+ struct fpn *fp;
+ u_int i, j, k, l;
+{
+ int exp;
+ u_int frac, f0, f1, f2, f3;
+#define EXT_SHIFT (-(EXT_FRACBITS - 3 * 32 - FP_LG)) /* left shift! */
+
+ /*
+ * Note that ext and fpn `line up', hence no shifting needed.
+ */
+ exp = (i >> (32 - 1 - EXT_EXPBITS)) & mask(EXT_EXPBITS);
+ frac = i & mask(EXT_FRACBITS - 3 * 32);
+ f0 = (frac << EXT_SHIFT) | (j >> (32 - EXT_SHIFT));
+ f1 = (j << EXT_SHIFT) | (k >> (32 - EXT_SHIFT));
+ f2 = (k << EXT_SHIFT) | (l >> (32 - EXT_SHIFT));
+ f3 = l << EXT_SHIFT;
+ frac |= j | k | l;
+ FP_TOF(exp, EXT_EXP_BIAS, frac, f0, f1, f2, f3);
+}
+
+/*
+ * Explode the contents of a / regpair / regquad.
+ * If the input is a signalling NaN, an NV (invalid) exception
+ * will be set. (Note that nothing but NV can occur until ALU
+ * operations are performed.)
+ */
+void
+__fpu_explode(fe, fp, type, reg)
+ struct fpemu *fe;
+ struct fpn *fp;
+ int type, reg;
+{
+ u_int64_t l0, l1;
+ u_int32_t s;
+
+ if (type == FTYPE_LNG || type == FTYPE_DBL || type == FTYPE_EXT) {
+ l0 = __fpu_getreg64(reg & ~1);
+ fp->fp_sign = l0 >> 63;
+ } else {
+ s = __fpu_getreg(reg);
+ fp->fp_sign = s >> 31;
+ }
+ fp->fp_sticky = 0;
+ switch (type) {
+ case FTYPE_LNG:
+ s = __fpu_xtof(fp, l0);
+ break;
+
+ case FTYPE_INT:
+ s = __fpu_itof(fp, s);
+ break;
+
+ case FTYPE_SNG:
+ s = __fpu_stof(fp, s);
+ break;
+
+ case FTYPE_DBL:
+ s = __fpu_dtof(fp, l0 >> 32, l0 & 0xffffffff);
+ break;
+
+ case FTYPE_EXT:
+ l1 = __fpu_getreg64((reg & ~1) + 2);
+ s = __fpu_qtof(fp, l0 >> 32, l0 & 0xffffffff, l1 >> 32,
+ l1 & 0xffffffff);
+ break;
+
+ default:
+ __utrap_panic("fpu_explode");
+ }
+
+ if (s == FPC_QNAN && (fp->fp_mant[0] & FP_QUIETBIT) == 0) {
+ /*
+ * Input is a signalling NaN. All operations that return
+ * an input NaN operand put it through a ``NaN conversion'',
+ * which basically just means ``turn on the quiet bit''.
+ * We do this here so that all NaNs internally look quiet
+ * (we can tell signalling ones by their class).
+ */
+ fp->fp_mant[0] |= FP_QUIETBIT;
+ fe->fe_cx = FSR_NV; /* assert invalid operand */
+ s = FPC_SNAN;
+ }
+ fp->fp_class = s;
+ DPRINTF(FPE_REG, ("fpu_explode: %%%c%d => ", (type == FTYPE_LNG) ? 'x' :
+ ((type == FTYPE_INT) ? 'i' :
+ ((type == FTYPE_SNG) ? 's' :
+ ((type == FTYPE_DBL) ? 'd' :
+ ((type == FTYPE_EXT) ? 'q' : '?')))),
+ reg));
+ DUMPFPN(FPE_REG, fp);
+ DPRINTF(FPE_REG, ("\n"));
+}
diff --git a/lib/libc/sparc64/fpu/fpu_extern.h b/lib/libc/sparc64/fpu/fpu_extern.h
new file mode 100644
index 000000000000..a5fb9428d077
--- /dev/null
+++ b/lib/libc/sparc64/fpu/fpu_extern.h
@@ -0,0 +1,85 @@
+/*-
+ * Copyright (c) 1995 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $NetBSD: fpu_extern.h,v 1.4 2000/08/03 18:32:08 eeh Exp $
+ * $FreeBSD$
+ */
+
+#ifndef _SPARC64_FPU_FPU_EXTERN_H_
+#define _SPARC64_FPU_FPU_EXTERN_H_
+
+struct utrapframe;
+struct fpemu;
+struct fpn;
+
+/* fpu.c */
+int __fpu_exception(struct utrapframe *tf);
+
+/* fpu_add.c */
+struct fpn *__fpu_add(struct fpemu *);
+
+/* fpu_compare.c */
+void __fpu_compare(struct fpemu *, int, int);
+
+/* fpu_div.c */
+struct fpn *__fpu_div(struct fpemu *);
+
+/* fpu_explode.c */
+int __fpu_itof(struct fpn *, u_int);
+int __fpu_xtof(struct fpn *, u_int64_t);
+int __fpu_stof(struct fpn *, u_int);
+int __fpu_dtof(struct fpn *, u_int, u_int);
+int __fpu_qtof(struct fpn *, u_int, u_int, u_int, u_int);
+void __fpu_explode(struct fpemu *, struct fpn *, int, int);
+
+/* fpu_implode.c */
+u_int __fpu_ftoi(struct fpemu *, struct fpn *);
+u_int __fpu_ftox(struct fpemu *, struct fpn *, u_int *);
+u_int __fpu_ftos(struct fpemu *, struct fpn *);
+u_int __fpu_ftod(struct fpemu *, struct fpn *, u_int *);
+u_int __fpu_ftoq(struct fpemu *, struct fpn *, u_int *);
+void __fpu_implode(struct fpemu *, struct fpn *, int, u_int *);
+
+/* fpu_mul.c */
+struct fpn *__fpu_mul(struct fpemu *);
+
+/* fpu_sqrt.c */
+struct fpn *__fpu_sqrt(struct fpemu *);
+
+/* fpu_subr.c */
+/*
+ * Shift a number right some number of bits, taking care of round/sticky.
+ * Note that the result is probably not a well-formed number (it will lack
+ * the normal 1-bit mant[0]&FP_1).
+ */
+int __fpu_shr(register struct fpn *, register int);
+void __fpu_norm(register struct fpn *);
+/* Build a new Quiet NaN (sign=0, frac=all 1's). */
+struct fpn *__fpu_newnan(register struct fpemu *);
+
+#endif /* !_SPARC64_FPU_FPU_EXTERN_H_ */
diff --git a/lib/libc/sparc64/fpu/fpu_implode.c b/lib/libc/sparc64/fpu/fpu_implode.c
new file mode 100644
index 000000000000..2a2a9d0be744
--- /dev/null
+++ b/lib/libc/sparc64/fpu/fpu_implode.c
@@ -0,0 +1,542 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)fpu_implode.c 8.1 (Berkeley) 6/11/93
+ * $NetBSD: fpu_implode.c,v 1.8 2001/08/26 05:44:46 eeh Exp $
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * FPU subroutines: `implode' internal format numbers into the machine's
+ * `packed binary' format.
+ */
+
+#include <sys/param.h>
+
+#ifdef FPU_DEBUG
+#include <stdio.h>
+#endif
+
+#include <machine/frame.h>
+#include <machine/fp.h>
+#include <machine/fsr.h>
+#include <machine/ieee.h>
+#include <machine/instr.h>
+
+#include "fpu_arith.h"
+#include "fpu_emu.h"
+#include "fpu_extern.h"
+#include "__sparc_utrap_private.h"
+
+static int fpround(struct fpemu *, struct fpn *);
+static int toinf(struct fpemu *, int);
+
+/*
+ * Round a number (algorithm from Motorola MC68882 manual, modified for
+ * our internal format). Set inexact exception if rounding is required.
+ * Return true iff we rounded up.
+ *
+ * After rounding, we discard the guard and round bits by shifting right
+ * 2 bits (a la fpu_shr(), but we do not bother with fp->fp_sticky).
+ * This saves effort later.
+ *
+ * Note that we may leave the value 2.0 in fp->fp_mant; it is the caller's
+ * responsibility to fix this if necessary.
+ */
+static int
+fpround(struct fpemu *fe, struct fpn *fp)
+{
+ u_int m0, m1, m2, m3;
+ int gr, s;
+
+ m0 = fp->fp_mant[0];
+ m1 = fp->fp_mant[1];
+ m2 = fp->fp_mant[2];
+ m3 = fp->fp_mant[3];
+ gr = m3 & 3;
+ s = fp->fp_sticky;
+
+ /* mant >>= FP_NG */
+ m3 = (m3 >> FP_NG) | (m2 << (32 - FP_NG));
+ m2 = (m2 >> FP_NG) | (m1 << (32 - FP_NG));
+ m1 = (m1 >> FP_NG) | (m0 << (32 - FP_NG));
+ m0 >>= FP_NG;
+
+ if ((gr | s) == 0) /* result is exact: no rounding needed */
+ goto rounddown;
+
+ fe->fe_cx |= FSR_NX; /* inexact */
+
+ /* Go to rounddown to round down; break to round up. */
+ switch (FSR_GET_RD(fe->fe_fsr)) {
+ case FSR_RD_N:
+ default:
+ /*
+ * Round only if guard is set (gr & 2). If guard is set,
+ * but round & sticky both clear, then we want to round
+ * but have a tie, so round to even, i.e., add 1 iff odd.
+ */
+ if ((gr & 2) == 0)
+ goto rounddown;
+ if ((gr & 1) || fp->fp_sticky || (m3 & 1))
+ break;
+ goto rounddown;
+
+ case FSR_RD_Z:
+ /* Round towards zero, i.e., down. */
+ goto rounddown;
+
+ case FSR_RD_NINF:
+ /* Round towards -Inf: up if negative, down if positive. */
+ if (fp->fp_sign)
+ break;
+ goto rounddown;
+
+ case FSR_RD_PINF:
+ /* Round towards +Inf: up if positive, down otherwise. */
+ if (!fp->fp_sign)
+ break;
+ goto rounddown;
+ }
+
+ /* Bump low bit of mantissa, with carry. */
+ FPU_ADDS(m3, m3, 1);
+ FPU_ADDCS(m2, m2, 0);
+ FPU_ADDCS(m1, m1, 0);
+ FPU_ADDC(m0, m0, 0);
+ fp->fp_mant[0] = m0;
+ fp->fp_mant[1] = m1;
+ fp->fp_mant[2] = m2;
+ fp->fp_mant[3] = m3;
+ return (1);
+
+rounddown:
+ fp->fp_mant[0] = m0;
+ fp->fp_mant[1] = m1;
+ fp->fp_mant[2] = m2;
+ fp->fp_mant[3] = m3;
+ return (0);
+}
+
+/*
+ * For overflow: return true if overflow is to go to +/-Inf, according
+ * to the sign of the overflowing result. If false, overflow is to go
+ * to the largest magnitude value instead.
+ */
+static int
+toinf(struct fpemu *fe, int sign)
+{
+ int inf;
+
+ /* look at rounding direction */
+ switch (FSR_GET_RD(fe->fe_fsr)) {
+ default:
+ case FSR_RD_N: /* the nearest value is always Inf */
+ inf = 1;
+ break;
+
+ case FSR_RD_Z: /* toward 0 => never towards Inf */
+ inf = 0;
+ break;
+
+ case FSR_RD_PINF: /* toward +Inf iff positive */
+ inf = sign == 0;
+ break;
+
+ case FSR_RD_NINF: /* toward -Inf iff negative */
+ inf = sign;
+ break;
+ }
+ return (inf);
+}
+
+/*
+ * fpn -> int (int value returned as return value).
+ *
+ * N.B.: this conversion always rounds towards zero (this is a peculiarity
+ * of the SPARC instruction set).
+ */
+u_int
+__fpu_ftoi(fe, fp)
+ struct fpemu *fe;
+ struct fpn *fp;
+{
+ u_int i;
+ int sign, exp;
+
+ sign = fp->fp_sign;
+ switch (fp->fp_class) {
+ case FPC_ZERO:
+ return (0);
+
+ case FPC_NUM:
+ /*
+ * If exp >= 2^32, overflow. Otherwise shift value right
+ * into last mantissa word (this will not exceed 0xffffffff),
+ * shifting any guard and round bits out into the sticky
+ * bit. Then ``round'' towards zero, i.e., just set an
+ * inexact exception if sticky is set (see round()).
+ * If the result is > 0x80000000, or is positive and equals
+ * 0x80000000, overflow; otherwise the last fraction word
+ * is the result.
+ */
+ if ((exp = fp->fp_exp) >= 32)
+ break;
+ /* NB: the following includes exp < 0 cases */
+ if (__fpu_shr(fp, FP_NMANT - 1 - exp) != 0)
+ fe->fe_cx |= FSR_NX;
+ i = fp->fp_mant[3];
+ if (i >= ((u_int)0x80000000 + sign))
+ break;
+ return (sign ? -i : i);
+
+ default: /* Inf, qNaN, sNaN */
+ break;
+ }
+ /* overflow: replace any inexact exception with invalid */
+ fe->fe_cx = (fe->fe_cx & ~FSR_NX) | FSR_NV;
+ return (0x7fffffff + sign);
+}
+
+/*
+ * fpn -> extended int (high bits of int value returned as return value).
+ *
+ * N.B.: this conversion always rounds towards zero (this is a peculiarity
+ * of the SPARC instruction set).
+ */
+u_int
+__fpu_ftox(fe, fp, res)
+ struct fpemu *fe;
+ struct fpn *fp;
+ u_int *res;
+{
+ u_int64_t i;
+ int sign, exp;
+
+ sign = fp->fp_sign;
+ switch (fp->fp_class) {
+ case FPC_ZERO:
+ i = 0;
+ goto done;
+
+ case FPC_NUM:
+ /*
+ * If exp >= 2^64, overflow. Otherwise shift value
+ * right into last mantissa word (this will not exceed
+ * 0xffffffffffffffff), shifting any guard and round
+ * bits out into the sticky bit. Then ``round'' towards
+ * zero, i.e., just set an inexact exception if sticky
+ * is set (see round()).
+ * If the result is > 0x8000000000000000, or is positive
+ * and equals 0x8000000000000000, overflow; otherwise
+ * the last fraction word is the result.
+ */
+ if ((exp = fp->fp_exp) >= 64)
+ break;
+ /* NB: the following includes exp < 0 cases */
+ if (__fpu_shr(fp, FP_NMANT - 1 - exp) != 0)
+ fe->fe_cx |= FSR_NX;
+ i = ((u_int64_t)fp->fp_mant[2]<<32)|fp->fp_mant[3];
+ if (i >= ((u_int64_t)0x8000000000000000LL + sign))
+ break;
+ if (sign)
+ i = -i;
+ goto done;
+
+ default: /* Inf, qNaN, sNaN */
+ break;
+ }
+ /* overflow: replace any inexact exception with invalid */
+ fe->fe_cx = (fe->fe_cx & ~FSR_NX) | FSR_NV;
+ i = 0x7fffffffffffffffLL + sign;
+done:
+ res[1] = i & 0xffffffff;
+ return (i >> 32);
+}
+
+/*
+ * fpn -> single (32 bit single returned as return value).
+ * We assume <= 29 bits in a single-precision fraction (1.f part).
+ */
+u_int
+__fpu_ftos(fe, fp)
+ struct fpemu *fe;
+ struct fpn *fp;
+{
+ u_int sign = fp->fp_sign << 31;
+ int exp;
+
+#define SNG_EXP(e) ((e) << SNG_FRACBITS) /* makes e an exponent */
+#define SNG_MASK (SNG_EXP(1) - 1) /* mask for fraction */
+
+ /* Take care of non-numbers first. */
+ if (ISNAN(fp)) {
+ /*
+ * Preserve upper bits of NaN, per SPARC V8 appendix N.
+ * Note that fp->fp_mant[0] has the quiet bit set,
+ * even if it is classified as a signalling NaN.
+ */
+ (void) __fpu_shr(fp, FP_NMANT - 1 - SNG_FRACBITS);
+ exp = SNG_EXP_INFNAN;
+ goto done;
+ }
+ if (ISINF(fp))
+ return (sign | SNG_EXP(SNG_EXP_INFNAN));
+ if (ISZERO(fp))
+ return (sign);
+
+ /*
+ * Normals (including subnormals). Drop all the fraction bits
+ * (including the explicit ``implied'' 1 bit) down into the
+ * single-precision range. If the number is subnormal, move
+ * the ``implied'' 1 into the explicit range as well, and shift
+ * right to introduce leading zeroes. Rounding then acts
+ * differently for normals and subnormals: the largest subnormal
+ * may round to the smallest normal (1.0 x 2^minexp), or may
+ * remain subnormal. A number that is subnormal before rounding
+ * will signal an underflow if the result is inexact or if underflow
+ * traps are enabled.
+ *
+ * Rounding a normal, on the other hand, always produces another
+ * normal (although either way the result might be too big for
+ * single precision, and cause an overflow). If rounding a
+ * normal produces 2.0 in the fraction, we need not adjust that
+ * fraction at all, since both 1.0 and 2.0 are zero under the
+ * fraction mask.
+ *
+ * Note that the guard and round bits vanish from the number after
+ * rounding.
+ */
+ if ((exp = fp->fp_exp + SNG_EXP_BIAS) <= 0) { /* subnormal */
+ /* -NG for g,r; -SNG_FRACBITS-exp for fraction */
+ (void) __fpu_shr(fp, FP_NMANT - FP_NG - SNG_FRACBITS - exp);
+ if (fpround(fe, fp) && fp->fp_mant[3] == SNG_EXP(1)) {
+ fe->fe_cx |= FSR_UF;
+ return (sign | SNG_EXP(1) | 0);
+ }
+ if ((fe->fe_cx & FSR_NX) ||
+ (fe->fe_fsr & (FSR_UF << FSR_TEM_SHIFT)))
+ fe->fe_cx |= FSR_UF;
+ return (sign | SNG_EXP(0) | fp->fp_mant[3]);
+ }
+ /* -FP_NG for g,r; -1 for implied 1; -SNG_FRACBITS for fraction */
+ (void) __fpu_shr(fp, FP_NMANT - FP_NG - 1 - SNG_FRACBITS);
+#ifdef DIAGNOSTIC
+ if ((fp->fp_mant[3] & SNG_EXP(1 << FP_NG)) == 0)
+ __utrap_panic("fpu_ftos");
+#endif
+ if (fpround(fe, fp) && fp->fp_mant[3] == SNG_EXP(2))
+ exp++;
+ if (exp >= SNG_EXP_INFNAN) {
+ /* overflow to inf or to max single */
+ fe->fe_cx |= FSR_OF | FSR_NX;
+ if (toinf(fe, sign))
+ return (sign | SNG_EXP(SNG_EXP_INFNAN));
+ return (sign | SNG_EXP(SNG_EXP_INFNAN - 1) | SNG_MASK);
+ }
+done:
+ /* phew, made it */
+ return (sign | SNG_EXP(exp) | (fp->fp_mant[3] & SNG_MASK));
+}
+
+/*
+ * fpn -> double (32 bit high-order result returned; 32-bit low order result
+ * left in res[1]). Assumes <= 61 bits in double precision fraction.
+ *
+ * This code mimics fpu_ftos; see it for comments.
+ */
+u_int
+__fpu_ftod(fe, fp, res)
+ struct fpemu *fe;
+ struct fpn *fp;
+ u_int *res;
+{
+ u_int sign = fp->fp_sign << 31;
+ int exp;
+
+#define DBL_EXP(e) ((e) << (DBL_FRACBITS & 31))
+#define DBL_MASK (DBL_EXP(1) - 1)
+
+ if (ISNAN(fp)) {
+ (void) __fpu_shr(fp, FP_NMANT - 1 - DBL_FRACBITS);
+ exp = DBL_EXP_INFNAN;
+ goto done;
+ }
+ if (ISINF(fp)) {
+ sign |= DBL_EXP(DBL_EXP_INFNAN);
+ goto zero;
+ }
+ if (ISZERO(fp)) {
+zero: res[1] = 0;
+ return (sign);
+ }
+
+ if ((exp = fp->fp_exp + DBL_EXP_BIAS) <= 0) {
+ (void) __fpu_shr(fp, FP_NMANT - FP_NG - DBL_FRACBITS - exp);
+ if (fpround(fe, fp) && fp->fp_mant[2] == DBL_EXP(1)) {
+ fe->fe_cx |= FSR_UF;
+ res[1] = 0;
+ return (sign | DBL_EXP(1) | 0);
+ }
+ if ((fe->fe_cx & FSR_NX) ||
+ (fe->fe_fsr & (FSR_UF << FSR_TEM_SHIFT)))
+ fe->fe_cx |= FSR_UF;
+ exp = 0;
+ goto done;
+ }
+ (void) __fpu_shr(fp, FP_NMANT - FP_NG - 1 - DBL_FRACBITS);
+ if (fpround(fe, fp) && fp->fp_mant[2] == DBL_EXP(2))
+ exp++;
+ if (exp >= DBL_EXP_INFNAN) {
+ fe->fe_cx |= FSR_OF | FSR_NX;
+ if (toinf(fe, sign)) {
+ res[1] = 0;
+ return (sign | DBL_EXP(DBL_EXP_INFNAN) | 0);
+ }
+ res[1] = ~0;
+ return (sign | DBL_EXP(DBL_EXP_INFNAN - 1) | DBL_MASK);
+ }
+done:
+ res[1] = fp->fp_mant[3];
+ return (sign | DBL_EXP(exp) | (fp->fp_mant[2] & DBL_MASK));
+}
+
+/*
+ * fpn -> extended (32 bit high-order result returned; low-order fraction
+ * words left in res[1]..res[3]). Like ftod, which is like ftos ... but
+ * our internal format *is* extended precision, plus 2 bits for guard/round,
+ * so we can avoid a small bit of work.
+ */
+u_int
+__fpu_ftoq(fe, fp, res)
+ struct fpemu *fe;
+ struct fpn *fp;
+ u_int *res;
+{
+ u_int sign = fp->fp_sign << 31;
+ int exp;
+
+#define EXT_EXP(e) ((e) << (EXT_FRACBITS & 31))
+#define EXT_MASK (EXT_EXP(1) - 1)
+
+ if (ISNAN(fp)) {
+ (void) __fpu_shr(fp, 2); /* since we are not rounding */
+ exp = EXT_EXP_INFNAN;
+ goto done;
+ }
+ if (ISINF(fp)) {
+ sign |= EXT_EXP(EXT_EXP_INFNAN);
+ goto zero;
+ }
+ if (ISZERO(fp)) {
+zero: res[1] = res[2] = res[3] = 0;
+ return (sign);
+ }
+
+ if ((exp = fp->fp_exp + EXT_EXP_BIAS) <= 0) {
+ (void) __fpu_shr(fp, FP_NMANT - FP_NG - EXT_FRACBITS - exp);
+ if (fpround(fe, fp) && fp->fp_mant[0] == EXT_EXP(1)) {
+ fe->fe_cx |= FSR_UF;
+ res[1] = res[2] = res[3] = 0;
+ return (sign | EXT_EXP(1) | 0);
+ }
+ if ((fe->fe_cx & FSR_NX) ||
+ (fe->fe_fsr & (FSR_UF << FSR_TEM_SHIFT)))
+ fe->fe_cx |= FSR_UF;
+ exp = 0;
+ goto done;
+ }
+ /* Since internal == extended, no need to shift here. */
+ if (fpround(fe, fp) && fp->fp_mant[0] == EXT_EXP(2))
+ exp++;
+ if (exp >= EXT_EXP_INFNAN) {
+ fe->fe_cx |= FSR_OF | FSR_NX;
+ if (toinf(fe, sign)) {
+ res[1] = res[2] = res[3] = 0;
+ return (sign | EXT_EXP(EXT_EXP_INFNAN) | 0);
+ }
+ res[1] = res[2] = res[3] = ~0;
+ return (sign | EXT_EXP(EXT_EXP_INFNAN - 1) | EXT_MASK);
+ }
+done:
+ res[1] = fp->fp_mant[1];
+ res[2] = fp->fp_mant[2];
+ res[3] = fp->fp_mant[3];
+ return (sign | EXT_EXP(exp) | (fp->fp_mant[0] & EXT_MASK));
+}
+
+/*
+ * Implode an fpn, writing the result into the given space.
+ */
+void
+__fpu_implode(fe, fp, type, space)
+ struct fpemu *fe;
+ struct fpn *fp;
+ int type;
+ u_int *space;
+{
+
+ switch (type) {
+ case FTYPE_LNG:
+ space[0] = __fpu_ftox(fe, fp, space);
+ break;
+
+ case FTYPE_INT:
+ space[0] = __fpu_ftoi(fe, fp);
+ break;
+
+ case FTYPE_SNG:
+ space[0] = __fpu_ftos(fe, fp);
+ break;
+
+ case FTYPE_DBL:
+ space[0] = __fpu_ftod(fe, fp, space);
+ break;
+
+ case FTYPE_EXT:
+ /* funky rounding precision options ?? */
+ space[0] = __fpu_ftoq(fe, fp, space);
+ break;
+
+ default:
+ __utrap_panic("fpu_implode");
+ }
+ DPRINTF(FPE_REG, ("fpu_implode: %x %x %x %x\n",
+ space[0], space[1], space[2], space[3]));
+}
diff --git a/lib/libc/sparc64/fpu/fpu_mul.c b/lib/libc/sparc64/fpu/fpu_mul.c
new file mode 100644
index 000000000000..3fe27c4e9113
--- /dev/null
+++ b/lib/libc/sparc64/fpu/fpu_mul.c
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)fpu_mul.c 8.1 (Berkeley) 6/11/93
+ * $NetBSD: fpu_mul.c,v 1.2 1994/11/20 20:52:44 deraadt Exp $
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Perform an FPU multiply (return x * y).
+ */
+
+#include <sys/types.h>
+
+#include <machine/frame.h>
+#include <machine/fp.h>
+
+#include "fpu_arith.h"
+#include "fpu_emu.h"
+#include "fpu_extern.h"
+
+/*
+ * The multiplication algorithm for normal numbers is as follows:
+ *
+ * The fraction of the product is built in the usual stepwise fashion.
+ * Each step consists of shifting the accumulator right one bit
+ * (maintaining any guard bits) and, if the next bit in y is set,
+ * adding the multiplicand (x) to the accumulator. Then, in any case,
+ * we advance one bit leftward in y. Algorithmically:
+ *
+ * A = 0;
+ * for (bit = 0; bit < FP_NMANT; bit++) {
+ * sticky |= A & 1, A >>= 1;
+ * if (Y & (1 << bit))
+ * A += X;
+ * }
+ *
+ * (X and Y here represent the mantissas of x and y respectively.)
+ * The resultant accumulator (A) is the product's mantissa. It may
+ * be as large as 11.11111... in binary and hence may need to be
+ * shifted right, but at most one bit.
+ *
+ * Since we do not have efficient multiword arithmetic, we code the
+ * accumulator as four separate words, just like any other mantissa.
+ * We use local `register' variables in the hope that this is faster
+ * than memory. We keep x->fp_mant in locals for the same reason.
+ *
+ * In the algorithm above, the bits in y are inspected one at a time.
+ * We will pick them up 32 at a time and then deal with those 32, one
+ * at a time. Note, however, that we know several things about y:
+ *
+ * - the guard and round bits at the bottom are sure to be zero;
+ *
+ * - often many low bits are zero (y is often from a single or double
+ * precision source);
+ *
+ * - bit FP_NMANT-1 is set, and FP_1*2 fits in a word.
+ *
+ * We can also test for 32-zero-bits swiftly. In this case, the center
+ * part of the loop---setting sticky, shifting A, and not adding---will
+ * run 32 times without adding X to A. We can do a 32-bit shift faster
+ * by simply moving words. Since zeros are common, we optimize this case.
+ * Furthermore, since A is initially zero, we can omit the shift as well
+ * until we reach a nonzero word.
+ */
+struct fpn *
+__fpu_mul(fe)
+ struct fpemu *fe;
+{
+ struct fpn *x = &fe->fe_f1, *y = &fe->fe_f2;
+ u_int a3, a2, a1, a0, x3, x2, x1, x0, bit, m;
+ int sticky;
+ FPU_DECL_CARRY
+
+ /*
+ * Put the `heavier' operand on the right (see fpu_emu.h).
+ * Then we will have one of the following cases, taken in the
+ * following order:
+ *
+ * - y = NaN. Implied: if only one is a signalling NaN, y is.
+ * The result is y.
+ * - y = Inf. Implied: x != NaN (is 0, number, or Inf: the NaN
+ * case was taken care of earlier).
+ * If x = 0, the result is NaN. Otherwise the result
+ * is y, with its sign reversed if x is negative.
+ * - x = 0. Implied: y is 0 or number.
+ * The result is 0 (with XORed sign as usual).
+ * - other. Implied: both x and y are numbers.
+ * The result is x * y (XOR sign, multiply bits, add exponents).
+ */
+ ORDER(x, y);
+ if (ISNAN(y))
+ return (y);
+ if (ISINF(y)) {
+ if (ISZERO(x))
+ return (__fpu_newnan(fe));
+ y->fp_sign ^= x->fp_sign;
+ return (y);
+ }
+ if (ISZERO(x)) {
+ x->fp_sign ^= y->fp_sign;
+ return (x);
+ }
+
+ /*
+ * Setup. In the code below, the mask `m' will hold the current
+ * mantissa byte from y. The variable `bit' denotes the bit
+ * within m. We also define some macros to deal with everything.
+ */
+ x3 = x->fp_mant[3];
+ x2 = x->fp_mant[2];
+ x1 = x->fp_mant[1];
+ x0 = x->fp_mant[0];
+ sticky = a3 = a2 = a1 = a0 = 0;
+
+#define ADD /* A += X */ \
+ FPU_ADDS(a3, a3, x3); \
+ FPU_ADDCS(a2, a2, x2); \
+ FPU_ADDCS(a1, a1, x1); \
+ FPU_ADDC(a0, a0, x0)
+
+#define SHR1 /* A >>= 1, with sticky */ \
+ sticky |= a3 & 1, a3 = (a3 >> 1) | (a2 << 31), \
+ a2 = (a2 >> 1) | (a1 << 31), a1 = (a1 >> 1) | (a0 << 31), a0 >>= 1
+
+#define SHR32 /* A >>= 32, with sticky */ \
+ sticky |= a3, a3 = a2, a2 = a1, a1 = a0, a0 = 0
+
+#define STEP /* each 1-bit step of the multiplication */ \
+ SHR1; if (bit & m) { ADD; }; bit <<= 1
+
+ /*
+ * We are ready to begin. The multiply loop runs once for each
+ * of the four 32-bit words. Some words, however, are special.
+ * As noted above, the low order bits of Y are often zero. Even
+ * if not, the first loop can certainly skip the guard bits.
+ * The last word of y has its highest 1-bit in position FP_NMANT-1,
+ * so we stop the loop when we move past that bit.
+ */
+ if ((m = y->fp_mant[3]) == 0) {
+ /* SHR32; */ /* unneeded since A==0 */
+ } else {
+ bit = 1 << FP_NG;
+ do {
+ STEP;
+ } while (bit != 0);
+ }
+ if ((m = y->fp_mant[2]) == 0) {
+ SHR32;
+ } else {
+ bit = 1;
+ do {
+ STEP;
+ } while (bit != 0);
+ }
+ if ((m = y->fp_mant[1]) == 0) {
+ SHR32;
+ } else {
+ bit = 1;
+ do {
+ STEP;
+ } while (bit != 0);
+ }
+ m = y->fp_mant[0]; /* definitely != 0 */
+ bit = 1;
+ do {
+ STEP;
+ } while (bit <= m);
+
+ /*
+ * Done with mantissa calculation. Get exponent and handle
+ * 11.111...1 case, then put result in place. We reuse x since
+ * it already has the right class (FP_NUM).
+ */
+ m = x->fp_exp + y->fp_exp;
+ if (a0 >= FP_2) {
+ SHR1;
+ m++;
+ }
+ x->fp_sign ^= y->fp_sign;
+ x->fp_exp = m;
+ x->fp_sticky = sticky;
+ x->fp_mant[3] = a3;
+ x->fp_mant[2] = a2;
+ x->fp_mant[1] = a1;
+ x->fp_mant[0] = a0;
+ return (x);
+}
diff --git a/lib/libc/sparc64/fpu/fpu_qp.c b/lib/libc/sparc64/fpu/fpu_qp.c
new file mode 100644
index 000000000000..8578e013b48d
--- /dev/null
+++ b/lib/libc/sparc64/fpu/fpu_qp.c
@@ -0,0 +1,163 @@
+/*-
+ * Copyright (c) 2002 Jake Burkholder.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 <machine/fsr.h>
+
+#include "fpu_emu.h"
+#include "fpu_extern.h"
+
+#define _QP_OP(op) \
+void _Qp_ ## op(u_int *c, u_int *a, u_int *b); \
+void \
+_Qp_ ## op(u_int *c, u_int *a, u_int *b) \
+{ \
+ struct fpemu fe; \
+ struct fpn *r; \
+ __asm __volatile("stx %%fsr, %0" : "=m" (fe.fe_fsr) :); \
+ fe.fe_cx = 0; \
+ fe.fe_f1.fp_sign = a[0] >> 31; \
+ fe.fe_f1.fp_sticky = 0; \
+ fe.fe_f1.fp_class = __fpu_qtof(&fe.fe_f1, a[0], a[1], a[2], a[3]); \
+ fe.fe_f2.fp_sign = b[0] >> 31; \
+ fe.fe_f2.fp_sticky = 0; \
+ fe.fe_f2.fp_class = __fpu_qtof(&fe.fe_f2, b[0], b[1], b[2], b[3]); \
+ r = __fpu_ ## op(&fe); \
+ c[0] = __fpu_ftoq(&fe, r, c); \
+ fe.fe_fsr |= fe.fe_cx << FSR_AEXC_SHIFT; \
+ __asm __volatile("ldx %0, %%fsr" : : "m" (fe.fe_fsr)); \
+}
+
+#define _QP_TTOQ(qname, fname, ntype, signpos, atype, ...) \
+void _Qp_ ## qname ## toq(u_int *c, ntype n); \
+void \
+_Qp_ ## qname ## toq(u_int *c, ntype n) \
+{ \
+ struct fpemu fe; \
+ union { atype a[2]; ntype n; } u = { .n = n }; \
+ __asm __volatile("stx %%fsr, %0" : "=m" (fe.fe_fsr) :); \
+ fe.fe_cx = 0; \
+ fe.fe_f1.fp_sign = (signpos >= 0) ? u.a[0] >> signpos : 0; \
+ fe.fe_f1.fp_sticky = 0; \
+ fe.fe_f1.fp_class = __fpu_ ## fname ## tof(&fe.fe_f1, __VA_ARGS__); \
+ c[0] = __fpu_ftoq(&fe, &fe.fe_f1, c); \
+ fe.fe_fsr |= fe.fe_cx << FSR_AEXC_SHIFT; \
+ __asm __volatile("ldx %0, %%fsr" : : "m" (fe.fe_fsr)); \
+}
+
+#define _QP_QTOT(qname, fname, type, ...) \
+type _Qp_qto ## qname(u_int *c); \
+type \
+_Qp_qto ## qname(u_int *c) \
+{ \
+ struct fpemu fe; \
+ union { u_int a; type n; } u; \
+ __asm __volatile("stx %%fsr, %0" : "=m" (fe.fe_fsr) :); \
+ fe.fe_cx = 0; \
+ fe.fe_f1.fp_sign = c[0] >> 31; \
+ fe.fe_f1.fp_sticky = 0; \
+ fe.fe_f1.fp_class = __fpu_qtof(&fe.fe_f1, c[0], c[1], c[2], c[3]); \
+ u.a = __fpu_fto ## fname(&fe, &fe.fe_f1, ## __VA_ARGS__); \
+ fe.fe_fsr |= fe.fe_cx << FSR_AEXC_SHIFT; \
+ __asm __volatile("ldx %0, %%fsr" : : "m" (fe.fe_fsr)); \
+ return (u.n); \
+}
+
+#define FCC_EQ(fcc) ((fcc) == FSR_CC_EQ)
+#define FCC_GE(fcc) ((fcc) == FSR_CC_EQ || (fcc) == FSR_CC_GT)
+#define FCC_GT(fcc) ((fcc) == FSR_CC_GT)
+#define FCC_LE(fcc) ((fcc) == FSR_CC_EQ || (fcc) == FSR_CC_LT)
+#define FCC_LT(fcc) ((fcc) == FSR_CC_LT)
+#define FCC_NE(fcc) ((fcc) != FSR_CC_EQ)
+#define FCC_ID(fcc) (fcc)
+
+#define _QP_CMP(name, cmpe, test) \
+int _Qp_ ## name(u_int *a, u_int *b) ; \
+int \
+_Qp_ ## name(u_int *a, u_int *b) \
+{ \
+ struct fpemu fe; \
+ __asm __volatile("stx %%fsr, %0" : "=m" (fe.fe_fsr) :); \
+ fe.fe_cx = 0; \
+ fe.fe_f1.fp_sign = a[0] >> 31; \
+ fe.fe_f1.fp_sticky = 0; \
+ fe.fe_f1.fp_class = __fpu_qtof(&fe.fe_f1, a[0], a[1], a[2], a[3]); \
+ fe.fe_f2.fp_sign = b[0] >> 31; \
+ fe.fe_f2.fp_sticky = 0; \
+ fe.fe_f2.fp_class = __fpu_qtof(&fe.fe_f2, b[0], b[1], b[2], b[3]); \
+ __fpu_compare(&fe, cmpe, 0); \
+ fe.fe_fsr |= fe.fe_cx << FSR_AEXC_SHIFT; \
+ __asm __volatile("ldx %0, %%fsr" : : "m" (fe.fe_fsr)); \
+ return (test(FSR_GET_FCC0(fe.fe_fsr))); \
+}
+
+void _Qp_sqrt(u_int *c, u_int *a);
+void
+_Qp_sqrt(u_int *c, u_int *a)
+{
+ struct fpemu fe;
+ struct fpn *r;
+ __asm __volatile("stx %%fsr, %0" : "=m" (fe.fe_fsr) :);
+ fe.fe_cx = 0;
+ fe.fe_f1.fp_sign = a[0] >> 31;
+ fe.fe_f1.fp_sticky = 0;
+ fe.fe_f1.fp_class = __fpu_qtof(&fe.fe_f1, a[0], a[1], a[2], a[3]);
+ r = __fpu_sqrt(&fe);
+ c[0] = __fpu_ftoq(&fe, r, c);
+ fe.fe_fsr |= fe.fe_cx << FSR_AEXC_SHIFT;
+ __asm __volatile("ldx %0, %%fsr" : : "m" (fe.fe_fsr));
+}
+
+_QP_OP(add)
+_QP_OP(div)
+_QP_OP(mul)
+_QP_OP(sub)
+
+_QP_TTOQ(d, d, double, 31, u_int, u.a[0], u.a[1])
+_QP_TTOQ(i, i, int, 31, u_int, u.a[0])
+_QP_TTOQ(s, s, float, 31, u_int, u.a[0])
+_QP_TTOQ(x, x, long, 63, u_long, u.a[0])
+_QP_TTOQ(ui, i, u_int, -1, u_int, u.a[0])
+_QP_TTOQ(ux, x, u_long, -1, u_long, u.a[0])
+
+_QP_QTOT(d, d, double, &u.a)
+_QP_QTOT(i, i, int)
+_QP_QTOT(s, s, float)
+_QP_QTOT(x, x, long, &u.a)
+_QP_QTOT(ui, i, u_int)
+_QP_QTOT(ux, x, u_long, &u.a)
+
+_QP_CMP(feq, 0, FCC_EQ)
+_QP_CMP(fge, 1, FCC_GE)
+_QP_CMP(fgt, 1, FCC_GT)
+_QP_CMP(fle, 1, FCC_LE)
+_QP_CMP(flt, 1, FCC_LT)
+_QP_CMP(fne, 0, FCC_NE)
+_QP_CMP(cmp, 0, FCC_ID)
+_QP_CMP(cmpe, 1, FCC_ID)
diff --git a/lib/libc/sparc64/fpu/fpu_reg.S b/lib/libc/sparc64/fpu/fpu_reg.S
new file mode 100644
index 000000000000..781b4fec8f9c
--- /dev/null
+++ b/lib/libc/sparc64/fpu/fpu_reg.S
@@ -0,0 +1,194 @@
+/*-
+ * Copyright (c) 2002 by Thomas Moestl <tmm@FreeBSD.org>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING 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 arrays of leaf functions to load/store fp registers to memory. See
+ * fpu_reg.h for the definitions to use this from C code. The function sizes
+ * defines there must be kept in sync with this file!
+ */
+
+.macro ld32 reg
+ retl
+ ld [%o0], %f\reg
+.endm
+
+.macro st32 reg
+ retl
+ st %f\reg, [%o0]
+.endm
+
+.macro ld64 reg
+ retl
+ ldd [%o0], %f\reg
+.endm
+
+.macro st64 reg
+ retl
+ std %f\reg, [%o0]
+.endm
+
+/* The actual function arrays. */
+ .globl __fpu_ld32
+__fpu_ld32:
+ ld32 0
+ ld32 1
+ ld32 2
+ ld32 3
+ ld32 4
+ ld32 5
+ ld32 6
+ ld32 7
+ ld32 8
+ ld32 9
+ ld32 10
+ ld32 11
+ ld32 12
+ ld32 13
+ ld32 14
+ ld32 15
+ ld32 16
+ ld32 17
+ ld32 18
+ ld32 19
+ ld32 20
+ ld32 21
+ ld32 22
+ ld32 23
+ ld32 24
+ ld32 25
+ ld32 26
+ ld32 27
+ ld32 28
+ ld32 29
+ ld32 30
+ ld32 31
+
+ .globl __fpu_st32
+__fpu_st32:
+ st32 0
+ st32 1
+ st32 2
+ st32 3
+ st32 4
+ st32 5
+ st32 6
+ st32 7
+ st32 8
+ st32 9
+ st32 10
+ st32 11
+ st32 12
+ st32 13
+ st32 14
+ st32 15
+ st32 16
+ st32 17
+ st32 18
+ st32 19
+ st32 20
+ st32 21
+ st32 22
+ st32 23
+ st32 24
+ st32 25
+ st32 26
+ st32 27
+ st32 28
+ st32 29
+ st32 30
+ st32 31
+
+ .globl __fpu_ld64
+__fpu_ld64:
+ ld64 0
+ ld64 2
+ ld64 4
+ ld64 6
+ ld64 8
+ ld64 10
+ ld64 12
+ ld64 14
+ ld64 16
+ ld64 18
+ ld64 20
+ ld64 22
+ ld64 24
+ ld64 26
+ ld64 28
+ ld64 30
+ ld64 32
+ ld64 34
+ ld64 36
+ ld64 38
+ ld64 40
+ ld64 42
+ ld64 44
+ ld64 46
+ ld64 48
+ ld64 50
+ ld64 52
+ ld64 54
+ ld64 56
+ ld64 58
+ ld64 60
+ ld64 62
+
+ .globl __fpu_st64
+__fpu_st64:
+ st64 0
+ st64 2
+ st64 4
+ st64 6
+ st64 8
+ st64 10
+ st64 12
+ st64 14
+ st64 16
+ st64 18
+ st64 20
+ st64 22
+ st64 24
+ st64 26
+ st64 28
+ st64 30
+ st64 32
+ st64 34
+ st64 36
+ st64 38
+ st64 40
+ st64 42
+ st64 44
+ st64 46
+ st64 48
+ st64 50
+ st64 52
+ st64 54
+ st64 56
+ st64 58
+ st64 60
+ st64 62
diff --git a/lib/libc/sparc64/fpu/fpu_reg.h b/lib/libc/sparc64/fpu/fpu_reg.h
new file mode 100644
index 000000000000..8798d6046137
--- /dev/null
+++ b/lib/libc/sparc64/fpu/fpu_reg.h
@@ -0,0 +1,88 @@
+/*-
+ * Copyright (c) 2002 by Thomas Moestl <tmm@FreeBSD.org>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (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 _LIBC_SPARC64_FPU_FPU_REG_H_
+#define _LIBC_SPARC64_FPU_FPU_REG_H_
+
+/*
+ * These are not really of type char[]. They are are arrays of functions defined
+ * in fpu_reg.S; each array member loads/stores a certain fpu register of the
+ * given size.
+ */
+extern char __fpu_ld32[];
+extern char __fpu_st32[];
+extern char __fpu_ld64[];
+extern char __fpu_st64[];
+
+/* Size of the functions in the arrays. */
+#define FPU_LD32_SZ 8
+#define FPU_ST32_SZ 8
+#define FPU_LD64_SZ 8
+#define FPU_ST64_SZ 8
+
+/* Typedefs for convenient casts in the functions below. */
+typedef void (fp_ldst32_fn)(u_int32_t *);
+typedef void (fp_ldst64_fn)(u_int64_t *);
+
+/*
+ * These are the functions that are actually used in the fpu emulation code to
+ * access the fp registers. They are usually not used more than once, so
+ * caching needs not be done here.
+ */
+static __inline u_int32_t
+__fpu_getreg(int r)
+{
+ u_int32_t rv;
+
+ ((fp_ldst32_fn *)&__fpu_st32[r * FPU_ST32_SZ])(&rv);
+ return (rv);
+}
+
+static __inline u_int64_t
+__fpu_getreg64(int r)
+{
+ u_int64_t rv;
+
+ ((fp_ldst64_fn *)&__fpu_st64[(r >> 1) * FPU_ST64_SZ])(&rv);
+ return (rv);
+}
+
+static __inline void
+__fpu_setreg(int r, u_int32_t v)
+{
+
+ ((fp_ldst32_fn *)&__fpu_ld32[r * FPU_LD32_SZ])(&v);
+}
+
+static __inline void
+__fpu_setreg64(int r, u_int64_t v)
+{
+
+ ((fp_ldst64_fn *)&__fpu_ld64[(r >> 1) * FPU_LD64_SZ])(&v);
+}
+
+#endif /* _LIBC_SPARC64_FPU_FPU_REG_H_ */
diff --git a/lib/libc/sparc64/fpu/fpu_sqrt.c b/lib/libc/sparc64/fpu/fpu_sqrt.c
new file mode 100644
index 000000000000..52290f2b90c4
--- /dev/null
+++ b/lib/libc/sparc64/fpu/fpu_sqrt.c
@@ -0,0 +1,397 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)fpu_sqrt.c 8.1 (Berkeley) 6/11/93
+ * $NetBSD: fpu_sqrt.c,v 1.2 1994/11/20 20:52:46 deraadt Exp $
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Perform an FPU square root (return sqrt(x)).
+ */
+
+#include <sys/types.h>
+
+#include <machine/frame.h>
+#include <machine/fp.h>
+
+#include "fpu_arith.h"
+#include "fpu_emu.h"
+#include "fpu_extern.h"
+
+/*
+ * Our task is to calculate the square root of a floating point number x0.
+ * This number x normally has the form:
+ *
+ * exp
+ * x = mant * 2 (where 1 <= mant < 2 and exp is an integer)
+ *
+ * This can be left as it stands, or the mantissa can be doubled and the
+ * exponent decremented:
+ *
+ * exp-1
+ * x = (2 * mant) * 2 (where 2 <= 2 * mant < 4)
+ *
+ * If the exponent `exp' is even, the square root of the number is best
+ * handled using the first form, and is by definition equal to:
+ *
+ * exp/2
+ * sqrt(x) = sqrt(mant) * 2
+ *
+ * If exp is odd, on the other hand, it is convenient to use the second
+ * form, giving:
+ *
+ * (exp-1)/2
+ * sqrt(x) = sqrt(2 * mant) * 2
+ *
+ * In the first case, we have
+ *
+ * 1 <= mant < 2
+ *
+ * and therefore
+ *
+ * sqrt(1) <= sqrt(mant) < sqrt(2)
+ *
+ * while in the second case we have
+ *
+ * 2 <= 2*mant < 4
+ *
+ * and therefore
+ *
+ * sqrt(2) <= sqrt(2*mant) < sqrt(4)
+ *
+ * so that in any case, we are sure that
+ *
+ * sqrt(1) <= sqrt(n * mant) < sqrt(4), n = 1 or 2
+ *
+ * or
+ *
+ * 1 <= sqrt(n * mant) < 2, n = 1 or 2.
+ *
+ * This root is therefore a properly formed mantissa for a floating
+ * point number. The exponent of sqrt(x) is either exp/2 or (exp-1)/2
+ * as above. This leaves us with the problem of finding the square root
+ * of a fixed-point number in the range [1..4).
+ *
+ * Though it may not be instantly obvious, the following square root
+ * algorithm works for any integer x of an even number of bits, provided
+ * that no overflows occur:
+ *
+ * let q = 0
+ * for k = NBITS-1 to 0 step -1 do -- for each digit in the answer...
+ * x *= 2 -- multiply by radix, for next digit
+ * if x >= 2q + 2^k then -- if adding 2^k does not
+ * x -= 2q + 2^k -- exceed the correct root,
+ * q += 2^k -- add 2^k and adjust x
+ * fi
+ * done
+ * sqrt = q / 2^(NBITS/2) -- (and any remainder is in x)
+ *
+ * If NBITS is odd (so that k is initially even), we can just add another
+ * zero bit at the top of x. Doing so means that q is not going to acquire
+ * a 1 bit in the first trip around the loop (since x0 < 2^NBITS). If the
+ * final value in x is not needed, or can be off by a factor of 2, this is
+ * equivalant to moving the `x *= 2' step to the bottom of the loop:
+ *
+ * for k = NBITS-1 to 0 step -1 do if ... fi; x *= 2; done
+ *
+ * and the result q will then be sqrt(x0) * 2^floor(NBITS / 2).
+ * (Since the algorithm is destructive on x, we will call x's initial
+ * value, for which q is some power of two times its square root, x0.)
+ *
+ * If we insert a loop invariant y = 2q, we can then rewrite this using
+ * C notation as:
+ *
+ * q = y = 0; x = x0;
+ * for (k = NBITS; --k >= 0;) {
+ * #if (NBITS is even)
+ * x *= 2;
+ * #endif
+ * t = y + (1 << k);
+ * if (x >= t) {
+ * x -= t;
+ * q += 1 << k;
+ * y += 1 << (k + 1);
+ * }
+ * #if (NBITS is odd)
+ * x *= 2;
+ * #endif
+ * }
+ *
+ * If x0 is fixed point, rather than an integer, we can simply alter the
+ * scale factor between q and sqrt(x0). As it happens, we can easily arrange
+ * for the scale factor to be 2**0 or 1, so that sqrt(x0) == q.
+ *
+ * In our case, however, x0 (and therefore x, y, q, and t) are multiword
+ * integers, which adds some complication. But note that q is built one
+ * bit at a time, from the top down, and is not used itself in the loop
+ * (we use 2q as held in y instead). This means we can build our answer
+ * in an integer, one word at a time, which saves a bit of work. Also,
+ * since 1 << k is always a `new' bit in q, 1 << k and 1 << (k+1) are
+ * `new' bits in y and we can set them with an `or' operation rather than
+ * a full-blown multiword add.
+ *
+ * We are almost done, except for one snag. We must prove that none of our
+ * intermediate calculations can overflow. We know that x0 is in [1..4)
+ * and therefore the square root in q will be in [1..2), but what about x,
+ * y, and t?
+ *
+ * We know that y = 2q at the beginning of each loop. (The relation only
+ * fails temporarily while y and q are being updated.) Since q < 2, y < 4.
+ * The sum in t can, in our case, be as much as y+(1<<1) = y+2 < 6, and.
+ * Furthermore, we can prove with a bit of work that x never exceeds y by
+ * more than 2, so that even after doubling, 0 <= x < 8. (This is left as
+ * an exercise to the reader, mostly because I have become tired of working
+ * on this comment.)
+ *
+ * If our floating point mantissas (which are of the form 1.frac) occupy
+ * B+1 bits, our largest intermediary needs at most B+3 bits, or two extra.
+ * In fact, we want even one more bit (for a carry, to avoid compares), or
+ * three extra. There is a comment in fpu_emu.h reminding maintainers of
+ * this, so we have some justification in assuming it.
+ */
+struct fpn *
+__fpu_sqrt(fe)
+ struct fpemu *fe;
+{
+ struct fpn *x = &fe->fe_f1;
+ u_int bit, q, tt;
+ u_int x0, x1, x2, x3;
+ u_int y0, y1, y2, y3;
+ u_int d0, d1, d2, d3;
+ int e;
+
+ /*
+ * Take care of special cases first. In order:
+ *
+ * sqrt(NaN) = NaN
+ * sqrt(+0) = +0
+ * sqrt(-0) = -0
+ * sqrt(x < 0) = NaN (including sqrt(-Inf))
+ * sqrt(+Inf) = +Inf
+ *
+ * Then all that remains are numbers with mantissas in [1..2).
+ */
+ if (ISNAN(x) || ISZERO(x))
+ return (x);
+ if (x->fp_sign)
+ return (__fpu_newnan(fe));
+ if (ISINF(x))
+ return (x);
+
+ /*
+ * Calculate result exponent. As noted above, this may involve
+ * doubling the mantissa. We will also need to double x each
+ * time around the loop, so we define a macro for this here, and
+ * we break out the multiword mantissa.
+ */
+#ifdef FPU_SHL1_BY_ADD
+#define DOUBLE_X { \
+ FPU_ADDS(x3, x3, x3); FPU_ADDCS(x2, x2, x2); \
+ FPU_ADDCS(x1, x1, x1); FPU_ADDC(x0, x0, x0); \
+}
+#else
+#define DOUBLE_X { \
+ x0 = (x0 << 1) | (x1 >> 31); x1 = (x1 << 1) | (x2 >> 31); \
+ x2 = (x2 << 1) | (x3 >> 31); x3 <<= 1; \
+}
+#endif
+#if (FP_NMANT & 1) != 0
+# define ODD_DOUBLE DOUBLE_X
+# define EVEN_DOUBLE /* nothing */
+#else
+# define ODD_DOUBLE /* nothing */
+# define EVEN_DOUBLE DOUBLE_X
+#endif
+ x0 = x->fp_mant[0];
+ x1 = x->fp_mant[1];
+ x2 = x->fp_mant[2];
+ x3 = x->fp_mant[3];
+ e = x->fp_exp;
+ if (e & 1) /* exponent is odd; use sqrt(2mant) */
+ DOUBLE_X;
+ /* THE FOLLOWING ASSUMES THAT RIGHT SHIFT DOES SIGN EXTENSION */
+ x->fp_exp = e >> 1; /* calculates (e&1 ? (e-1)/2 : e/2 */
+
+ /*
+ * Now calculate the mantissa root. Since x is now in [1..4),
+ * we know that the first trip around the loop will definitely
+ * set the top bit in q, so we can do that manually and start
+ * the loop at the next bit down instead. We must be sure to
+ * double x correctly while doing the `known q=1.0'.
+ *
+ * We do this one mantissa-word at a time, as noted above, to
+ * save work. To avoid `(1U << 31) << 1', we also do the top bit
+ * outside of each per-word loop.
+ *
+ * The calculation `t = y + bit' breaks down into `t0 = y0, ...,
+ * t3 = y3, t? |= bit' for the appropriate word. Since the bit
+ * is always a `new' one, this means that three of the `t?'s are
+ * just the corresponding `y?'; we use `#define's here for this.
+ * The variable `tt' holds the actual `t?' variable.
+ */
+
+ /* calculate q0 */
+#define t0 tt
+ bit = FP_1;
+ EVEN_DOUBLE;
+ /* if (x >= (t0 = y0 | bit)) { */ /* always true */
+ q = bit;
+ x0 -= bit;
+ y0 = bit << 1;
+ /* } */
+ ODD_DOUBLE;
+ while ((bit >>= 1) != 0) { /* for remaining bits in q0 */
+ EVEN_DOUBLE;
+ t0 = y0 | bit; /* t = y + bit */
+ if (x0 >= t0) { /* if x >= t then */
+ x0 -= t0; /* x -= t */
+ q |= bit; /* q += bit */
+ y0 |= bit << 1; /* y += bit << 1 */
+ }
+ ODD_DOUBLE;
+ }
+ x->fp_mant[0] = q;
+#undef t0
+
+ /* calculate q1. note (y0&1)==0. */
+#define t0 y0
+#define t1 tt
+ q = 0;
+ y1 = 0;
+ bit = 1 << 31;
+ EVEN_DOUBLE;
+ t1 = bit;
+ FPU_SUBS(d1, x1, t1);
+ FPU_SUBC(d0, x0, t0); /* d = x - t */
+ if ((int)d0 >= 0) { /* if d >= 0 (i.e., x >= t) then */
+ x0 = d0, x1 = d1; /* x -= t */
+ q = bit; /* q += bit */
+ y0 |= 1; /* y += bit << 1 */
+ }
+ ODD_DOUBLE;
+ while ((bit >>= 1) != 0) { /* for remaining bits in q1 */
+ EVEN_DOUBLE; /* as before */
+ t1 = y1 | bit;
+ FPU_SUBS(d1, x1, t1);
+ FPU_SUBC(d0, x0, t0);
+ if ((int)d0 >= 0) {
+ x0 = d0, x1 = d1;
+ q |= bit;
+ y1 |= bit << 1;
+ }
+ ODD_DOUBLE;
+ }
+ x->fp_mant[1] = q;
+#undef t1
+
+ /* calculate q2. note (y1&1)==0; y0 (aka t0) is fixed. */
+#define t1 y1
+#define t2 tt
+ q = 0;
+ y2 = 0;
+ bit = 1 << 31;
+ EVEN_DOUBLE;
+ t2 = bit;
+ FPU_SUBS(d2, x2, t2);
+ FPU_SUBCS(d1, x1, t1);
+ FPU_SUBC(d0, x0, t0);
+ if ((int)d0 >= 0) {
+ x0 = d0, x1 = d1, x2 = d2;
+ q = bit;
+ y1 |= 1; /* now t1, y1 are set in concrete */
+ }
+ ODD_DOUBLE;
+ while ((bit >>= 1) != 0) {
+ EVEN_DOUBLE;
+ t2 = y2 | bit;
+ FPU_SUBS(d2, x2, t2);
+ FPU_SUBCS(d1, x1, t1);
+ FPU_SUBC(d0, x0, t0);
+ if ((int)d0 >= 0) {
+ x0 = d0, x1 = d1, x2 = d2;
+ q |= bit;
+ y2 |= bit << 1;
+ }
+ ODD_DOUBLE;
+ }
+ x->fp_mant[2] = q;
+#undef t2
+
+ /* calculate q3. y0, t0, y1, t1 all fixed; y2, t2, almost done. */
+#define t2 y2
+#define t3 tt
+ q = 0;
+ y3 = 0;
+ bit = 1 << 31;
+ EVEN_DOUBLE;
+ t3 = bit;
+ FPU_SUBS(d3, x3, t3);
+ FPU_SUBCS(d2, x2, t2);
+ FPU_SUBCS(d1, x1, t1);
+ FPU_SUBC(d0, x0, t0);
+ if ((int)d0 >= 0) {
+ x0 = d0, x1 = d1, x2 = d2; x3 = d3;
+ q = bit;
+ y2 |= 1;
+ }
+ ODD_DOUBLE;
+ while ((bit >>= 1) != 0) {
+ EVEN_DOUBLE;
+ t3 = y3 | bit;
+ FPU_SUBS(d3, x3, t3);
+ FPU_SUBCS(d2, x2, t2);
+ FPU_SUBCS(d1, x1, t1);
+ FPU_SUBC(d0, x0, t0);
+ if ((int)d0 >= 0) {
+ x0 = d0, x1 = d1, x2 = d2; x3 = d3;
+ q |= bit;
+ y3 |= bit << 1;
+ }
+ ODD_DOUBLE;
+ }
+ x->fp_mant[3] = q;
+
+ /*
+ * The result, which includes guard and round bits, is exact iff
+ * x is now zero; any nonzero bits in x represent sticky bits.
+ */
+ x->fp_sticky = x0 | x1 | x2 | x3;
+ return (x);
+}
diff --git a/lib/libc/sparc64/fpu/fpu_subr.c b/lib/libc/sparc64/fpu/fpu_subr.c
new file mode 100644
index 000000000000..074e959984ff
--- /dev/null
+++ b/lib/libc/sparc64/fpu/fpu_subr.c
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)fpu_subr.c 8.1 (Berkeley) 6/11/93
+ * $NetBSD: fpu_subr.c,v 1.3 1996/03/14 19:42:01 christos Exp $
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * FPU subroutines.
+ */
+
+#include <sys/param.h>
+
+#include <machine/frame.h>
+#include <machine/fp.h>
+#include <machine/fsr.h>
+#include <machine/instr.h>
+
+#include "fpu_arith.h"
+#include "fpu_emu.h"
+#include "fpu_extern.h"
+#include "__sparc_utrap_private.h"
+
+/*
+ * Shift the given number right rsh bits. Any bits that `fall off' will get
+ * shoved into the sticky field; we return the resulting sticky. Note that
+ * shifting NaNs is legal (this will never shift all bits out); a NaN's
+ * sticky field is ignored anyway.
+ */
+int
+__fpu_shr(struct fpn *fp, int rsh)
+{
+ u_int m0, m1, m2, m3, s;
+ int lsh;
+
+#ifdef DIAGNOSTIC
+ if (rsh <= 0 || (fp->fp_class != FPC_NUM && !ISNAN(fp)))
+ __utrap_panic("fpu_rightshift 1");
+#endif
+
+ m0 = fp->fp_mant[0];
+ m1 = fp->fp_mant[1];
+ m2 = fp->fp_mant[2];
+ m3 = fp->fp_mant[3];
+
+ /* If shifting all the bits out, take a shortcut. */
+ if (rsh >= FP_NMANT) {
+#ifdef DIAGNOSTIC
+ if ((m0 | m1 | m2 | m3) == 0)
+ __utrap_panic("fpu_rightshift 2");
+#endif
+ fp->fp_mant[0] = 0;
+ fp->fp_mant[1] = 0;
+ fp->fp_mant[2] = 0;
+ fp->fp_mant[3] = 0;
+#ifdef notdef
+ if ((m0 | m1 | m2 | m3) == 0)
+ fp->fp_class = FPC_ZERO;
+ else
+#endif
+ fp->fp_sticky = 1;
+ return (1);
+ }
+
+ /* Squish out full words. */
+ s = fp->fp_sticky;
+ if (rsh >= 32 * 3) {
+ s |= m3 | m2 | m1;
+ m3 = m0, m2 = 0, m1 = 0, m0 = 0;
+ } else if (rsh >= 32 * 2) {
+ s |= m3 | m2;
+ m3 = m1, m2 = m0, m1 = 0, m0 = 0;
+ } else if (rsh >= 32) {
+ s |= m3;
+ m3 = m2, m2 = m1, m1 = m0, m0 = 0;
+ }
+
+ /* Handle any remaining partial word. */
+ if ((rsh &= 31) != 0) {
+ lsh = 32 - rsh;
+ s |= m3 << lsh;
+ m3 = (m3 >> rsh) | (m2 << lsh);
+ m2 = (m2 >> rsh) | (m1 << lsh);
+ m1 = (m1 >> rsh) | (m0 << lsh);
+ m0 >>= rsh;
+ }
+ fp->fp_mant[0] = m0;
+ fp->fp_mant[1] = m1;
+ fp->fp_mant[2] = m2;
+ fp->fp_mant[3] = m3;
+ fp->fp_sticky = s;
+ return (s);
+}
+
+/*
+ * Force a number to be normal, i.e., make its fraction have all zero
+ * bits before FP_1, then FP_1, then all 1 bits. This is used for denorms
+ * and (sometimes) for intermediate results.
+ *
+ * Internally, this may use a `supernormal' -- a number whose fp_mant
+ * is greater than or equal to 2.0 -- so as a side effect you can hand it
+ * a supernormal and it will fix it (provided fp->fp_mant[3] == 0).
+ */
+void
+__fpu_norm(struct fpn *fp)
+{
+ u_int m0, m1, m2, m3, top, sup, nrm;
+ int lsh, rsh, exp;
+
+ exp = fp->fp_exp;
+ m0 = fp->fp_mant[0];
+ m1 = fp->fp_mant[1];
+ m2 = fp->fp_mant[2];
+ m3 = fp->fp_mant[3];
+
+ /* Handle severe subnormals with 32-bit moves. */
+ if (m0 == 0) {
+ if (m1)
+ m0 = m1, m1 = m2, m2 = m3, m3 = 0, exp -= 32;
+ else if (m2)
+ m0 = m2, m1 = m3, m2 = 0, m3 = 0, exp -= 2 * 32;
+ else if (m3)
+ m0 = m3, m1 = 0, m2 = 0, m3 = 0, exp -= 3 * 32;
+ else {
+ fp->fp_class = FPC_ZERO;
+ return;
+ }
+ }
+
+ /* Now fix any supernormal or remaining subnormal. */
+ nrm = FP_1;
+ sup = nrm << 1;
+ if (m0 >= sup) {
+ /*
+ * We have a supernormal number. We need to shift it right.
+ * We may assume m3==0.
+ */
+ for (rsh = 1, top = m0 >> 1; top >= sup; rsh++) /* XXX slow */
+ top >>= 1;
+ exp += rsh;
+ lsh = 32 - rsh;
+ m3 = m2 << lsh;
+ m2 = (m2 >> rsh) | (m1 << lsh);
+ m1 = (m1 >> rsh) | (m0 << lsh);
+ m0 = top;
+ } else if (m0 < nrm) {
+ /*
+ * We have a regular denorm (a subnormal number), and need
+ * to shift it left.
+ */
+ for (lsh = 1, top = m0 << 1; top < nrm; lsh++) /* XXX slow */
+ top <<= 1;
+ exp -= lsh;
+ rsh = 32 - lsh;
+ m0 = top | (m1 >> rsh);
+ m1 = (m1 << lsh) | (m2 >> rsh);
+ m2 = (m2 << lsh) | (m3 >> rsh);
+ m3 <<= lsh;
+ }
+
+ fp->fp_exp = exp;
+ fp->fp_mant[0] = m0;
+ fp->fp_mant[1] = m1;
+ fp->fp_mant[2] = m2;
+ fp->fp_mant[3] = m3;
+}
+
+/*
+ * Concoct a `fresh' Quiet NaN per Appendix N.
+ * As a side effect, we set NV (invalid) for the current exceptions.
+ */
+struct fpn *
+__fpu_newnan(struct fpemu *fe)
+{
+ struct fpn *fp;
+
+ fe->fe_cx = FSR_NV;
+ fp = &fe->fe_f3;
+ fp->fp_class = FPC_QNAN;
+ fp->fp_sign = 0;
+ fp->fp_mant[0] = FP_1 - 1;
+ fp->fp_mant[1] = fp->fp_mant[2] = fp->fp_mant[3] = ~0;
+ return (fp);
+}
diff --git a/lib/libc/sparc64/gd_qnan.h b/lib/libc/sparc64/gd_qnan.h
new file mode 100644
index 000000000000..7c9f92943416
--- /dev/null
+++ b/lib/libc/sparc64/gd_qnan.h
@@ -0,0 +1,21 @@
+/*
+ * MD header for contrib/gdtoa
+ *
+ * This file can be generated by compiling and running contrib/gdtoa/qnan.c
+ * on the target architecture after arith.h has been generated.
+ *
+ * $FreeBSD$
+ */
+
+#define f_QNAN 0x7fc00000
+#define d_QNAN0 0x7ff80000
+#define d_QNAN1 0x00000000
+#define ld_QNAN0 0x7fff8000
+#define ld_QNAN1 0x00000000
+#define ld_QNAN2 0x00000000
+#define ld_QNAN3 0x00000000
+#define ldus_QNAN0 0x7fff
+#define ldus_QNAN1 0x8000
+#define ldus_QNAN2 0x0000
+#define ldus_QNAN3 0x0000
+#define ldus_QNAN4 0x0000
diff --git a/lib/libc/sparc64/gen/Makefile.inc b/lib/libc/sparc64/gen/Makefile.inc
new file mode 100644
index 000000000000..5442a33fdb18
--- /dev/null
+++ b/lib/libc/sparc64/gen/Makefile.inc
@@ -0,0 +1,7 @@
+# $FreeBSD$
+
+SRCS+= _ctx_start.S _setjmp.S fabs.S fixunsdfsi.S flt_rounds.c fpgetmask.c \
+ fpgetround.c fpgetsticky.c fpsetmask.c fpsetround.c \
+ infinity.c ldexp.c makecontext.c \
+ signalcontext.c setjmp.S sigsetjmp.S _set_tp.c \
+ trivial-getcontextx.c
diff --git a/lib/libc/sparc64/gen/_ctx_start.S b/lib/libc/sparc64/gen/_ctx_start.S
new file mode 100644
index 000000000000..4ba3fd80624b
--- /dev/null
+++ b/lib/libc/sparc64/gen/_ctx_start.S
@@ -0,0 +1,36 @@
+/*-
+ * Copyright (c) 2003 Jake Burkholder.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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$");
+
+ENTRY(_ctx_start)
+ call %g1
+ mov %g2, %l0
+ call _ctx_done
+ mov %l0, %o0
+ illtrap
+END(_ctx_start)
diff --git a/lib/libc/sparc64/gen/_set_tp.c b/lib/libc/sparc64/gen/_set_tp.c
new file mode 100644
index 000000000000..7632951c4b8c
--- /dev/null
+++ b/lib/libc/sparc64/gen/_set_tp.c
@@ -0,0 +1,35 @@
+/*-
+ * Copyright (c) 2004 Doug Rabson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include "libc_private.h"
+
+void
+_set_tp(void *tpval)
+{
+
+ __asm __volatile("mov %0, %%g7" : : "r" (tpval));
+}
diff --git a/lib/libc/sparc64/gen/_setjmp.S b/lib/libc/sparc64/gen/_setjmp.S
new file mode 100644
index 000000000000..724c2c0148c0
--- /dev/null
+++ b/lib/libc/sparc64/gen/_setjmp.S
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: Header: _setjmp.s,v 1.1 91/07/06 16:45:53 torek Exp
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+ .asciz "@(#)_setjmp.s 8.1 (Berkeley) 6/4/93"
+#if 0
+ RCSID("$NetBSD: _setjmp.S,v 1.4 1998/10/08 02:27:59 eeh Exp $")
+#endif
+#endif /* LIBC_SCCS and not lint */
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "assym.s"
+
+ .register %g2,#ignore
+ .register %g3,#ignore
+
+/*
+ * C library -- _setjmp, _longjmp
+ *
+ * _longjmp(a,v)
+ * will generate a "return(v?v:1)" from
+ * the last call to
+ * _setjmp(a)
+ * by restoring the previous context.
+ * The previous signal state is NOT restored.
+ */
+
+ENTRY(_setjmp)
+ stx %sp, [%o0 + _JB_SP]
+ stx %o7, [%o0 + _JB_PC]
+ retl
+ clr %o0
+END(_setjmp)
+
+ .weak CNAME(_longjmp)
+ .set CNAME(_longjmp),CNAME(___longjmp)
+ENTRY(___longjmp)
+ save %sp, -CCFSZ, %sp
+ flushw
+ ldx [%i0 + _JB_SP], %fp
+ ldx [%i0 + _JB_PC], %i7
+ mov 1, %i0
+ movrnz %i1, %i1, %i0
+ ret
+ restore
+END(___longjmp)
diff --git a/lib/libc/sparc64/gen/assym.s b/lib/libc/sparc64/gen/assym.s
new file mode 100644
index 000000000000..7b205db2b690
--- /dev/null
+++ b/lib/libc/sparc64/gen/assym.s
@@ -0,0 +1,18 @@
+/*
+ * Offsets into into structures used from asm. Must be kept in sync with
+ * appropriate headers.
+ *
+ * $FreeBSD$
+ */
+
+#define _JB_FP 0x0
+#define _JB_PC 0x8
+#define _JB_SP 0x10
+#define _JB_SIGMASK 0x18
+#define _JB_SIGFLAG 0x28
+
+#define SIG_BLOCK 1
+#define SIG_SETMASK 3
+
+#define FSR_RD_MASK 0xc0000000
+#define FSR_RD_RD_Z 0x40000000
diff --git a/lib/libc/sparc64/gen/fabs.S b/lib/libc/sparc64/gen/fabs.S
new file mode 100644
index 000000000000..bbc744af8a8b
--- /dev/null
+++ b/lib/libc/sparc64/gen/fabs.S
@@ -0,0 +1,35 @@
+/*-
+ * Copyright (c) 2002 by Thomas Moestl <tmm@FreeBSD.org>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING 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$");
+
+/*
+ * double fabs(double);
+ */
+ENTRY(fabs)
+ retl
+ fabsd %f0, %f0
+END(fabs)
diff --git a/lib/libc/sparc64/gen/fixunsdfsi.S b/lib/libc/sparc64/gen/fixunsdfsi.S
new file mode 100644
index 000000000000..77c3059b0103
--- /dev/null
+++ b/lib/libc/sparc64/gen/fixunsdfsi.S
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: Header: fixunsdfsi.s,v 1.3 91/10/08 00:03:15 torek Exp
+ */
+
+#include <machine/asm.h>
+
+#if defined(LIBC_SCCS) && !defined(lint)
+ .asciz "@(#)fixunsdfsi.s 8.1 (Berkeley) 6/4/93"
+#if 0
+ RCSID("$NetBSD: fixunsdfsi.S,v 1.3 2000/07/25 04:26:12 mycroft Exp $")
+#endif
+#endif /* LIBC_SCCS and not lint */
+__FBSDID("$FreeBSD$");
+
+/*
+ * Convert double to unsigned integer (for gcc).
+ *
+ * I have made the output for NaN agree with the Sun compiler, not
+ * that it really matters, by using `fbul,a'.
+ */
+
+
+ .align 8
+.Lbig:
+ .word 0x43e00000 ! .double 2^63
+ .word 0 ! (who me, not trust the assembler?)
+
+/*
+ * Same as above but to unsigned long
+ */
+ENTRY(__dtoul)
+ PIC_PROLOGUE(%o4, %o5)
+ sub %sp, 16, %sp
+ std %f2, [%sp + CCFSZ + SPOFF + 8]
+ SET(.Lbig, %o5, %o3)
+ ldd [%o3], %f2
+ fcmped %f0, %f2 ! d < 2^63, or NaN, or -Inf?
+ fbul,a 1f ! if so, use fdtox to convert to long
+ fdtox %f0, %f0 ! (this includes negatives!)
+
+ ! d does not fit in a long, so subtract 2^63, convert,
+ ! and add 2^63 again (sigh). Just hope the intermediate
+ ! fits (if not, the result is undefined anyway).
+
+ fsubd %f0, %f2, %f0 ! d -= 2^63
+ fdtox %f0, %f0 ! convert to long
+ std %f0, [%sp + CCFSZ + SPOFF] ! move into return reg
+ ldx [%sp + CCFSZ + SPOFF], %o0
+ sethi %hi(0x80000000), %o1
+ sllx %o1, 32, %o1
+ add %o0, %o1, %o0 ! add 2^63
+ ldd [%sp + CCFSZ + SPOFF + 8], %f2
+ retl
+ add %sp, 16, %sp
+
+1:
+ std %f0, [%sp + CCFSZ + SPOFF] ! return result
+ ldx [%sp + CCFSZ + SPOFF], %o0
+ ldd [%sp + CCFSZ + SPOFF + 8], %f2
+ retl
+ add %sp, 16, %sp
+END(__dtoul)
diff --git a/lib/libc/sparc64/gen/flt_rounds.c b/lib/libc/sparc64/gen/flt_rounds.c
new file mode 100644
index 000000000000..706ef5a0dc6a
--- /dev/null
+++ b/lib/libc/sparc64/gen/flt_rounds.c
@@ -0,0 +1,26 @@
+/*
+ * Written by J.T. Conklin, Apr 10, 1995
+ * Public domain.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <machine/float.h>
+
+static const int map[] = {
+ 1, /* round to nearest */
+ 0, /* round to zero */
+ 2, /* round to positive infinity */
+ 3 /* round to negative infinity */
+};
+
+int
+__flt_rounds()
+{
+ int x;
+
+ __asm("st %%fsr,%0" : "=m" (*&x));
+ return map[(x >> 30) & 0x03];
+}
diff --git a/lib/libc/sparc64/gen/fpgetmask.c b/lib/libc/sparc64/gen/fpgetmask.c
new file mode 100644
index 000000000000..05b151af0d10
--- /dev/null
+++ b/lib/libc/sparc64/gen/fpgetmask.c
@@ -0,0 +1,22 @@
+/* $NetBSD: fpgetmask.c,v 1.2 2002/01/13 21:45:50 thorpej Exp $ */
+
+/*
+ * Written by J.T. Conklin, Apr 10, 1995
+ * Public domain.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+
+#include <machine/fsr.h>
+#include <ieeefp.h>
+
+fp_except_t
+fpgetmask()
+{
+ unsigned int x;
+
+ __asm__("st %%fsr,%0" : "=m" (x));
+ return (FSR_GET_TEM(x));
+}
diff --git a/lib/libc/sparc64/gen/fpgetround.c b/lib/libc/sparc64/gen/fpgetround.c
new file mode 100644
index 000000000000..dbc90d728bd1
--- /dev/null
+++ b/lib/libc/sparc64/gen/fpgetround.c
@@ -0,0 +1,21 @@
+/* $NetBSD: fpgetround.c,v 1.2 2002/01/13 21:45:50 thorpej Exp $ */
+
+/*
+ * Written by J.T. Conklin, Apr 10, 1995
+ * Public domain.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <machine/fsr.h>
+#include <ieeefp.h>
+
+fp_rnd_t
+fpgetround()
+{
+ unsigned int x;
+
+ __asm__("st %%fsr,%0" : "=m" (x));
+ return ((fp_rnd_t)FSR_GET_RD(x));
+}
diff --git a/lib/libc/sparc64/gen/fpgetsticky.c b/lib/libc/sparc64/gen/fpgetsticky.c
new file mode 100644
index 000000000000..274566acd48a
--- /dev/null
+++ b/lib/libc/sparc64/gen/fpgetsticky.c
@@ -0,0 +1,21 @@
+/* $NetBSD: fpgetsticky.c,v 1.2 2002/01/13 21:45:50 thorpej Exp $ */
+
+/*
+ * Written by J.T. Conklin, Apr 10, 1995
+ * Public domain.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <machine/fsr.h>
+#include <ieeefp.h>
+
+fp_except_t
+fpgetsticky()
+{
+ unsigned int x;
+
+ __asm__("st %%fsr,%0" : "=m" (x));
+ return (FSR_GET_AEXC(x));
+}
diff --git a/lib/libc/sparc64/gen/fpsetmask.c b/lib/libc/sparc64/gen/fpsetmask.c
new file mode 100644
index 000000000000..9aefb137837a
--- /dev/null
+++ b/lib/libc/sparc64/gen/fpsetmask.c
@@ -0,0 +1,28 @@
+/*
+ * Written by J.T. Conklin, Apr 10, 1995
+ * Public domain.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <machine/fsr.h>
+#include <ieeefp.h>
+
+fp_except_t
+fpsetmask(mask)
+ fp_except_t mask;
+{
+ fp_except_t old;
+ fp_except_t new;
+
+ __asm__("st %%fsr,%0" : "=m" (old));
+
+ new = old;
+ new &= ~FSR_TEM_MASK;
+ new |= FSR_TEM(mask & FSR_EXC_MASK);
+
+ __asm__("ld %0,%%fsr" : : "m" (new));
+
+ return (FSR_GET_TEM(old));
+}
diff --git a/lib/libc/sparc64/gen/fpsetround.c b/lib/libc/sparc64/gen/fpsetround.c
new file mode 100644
index 000000000000..1e27f596c16c
--- /dev/null
+++ b/lib/libc/sparc64/gen/fpsetround.c
@@ -0,0 +1,30 @@
+/* $NetBSD: fpsetround.c,v 1.2 2002/01/13 21:45:51 thorpej Exp $ */
+
+/*
+ * Written by J.T. Conklin, Apr 10, 1995
+ * Public domain.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <machine/fsr.h>
+#include <ieeefp.h>
+
+fp_rnd_t
+fpsetround(rnd_dir)
+ fp_rnd_t rnd_dir;
+{
+ unsigned int old;
+ unsigned int new;
+
+ __asm__("st %%fsr,%0" : "=m" (old));
+
+ new = old;
+ new &= ~FSR_RD_MASK;
+ new |= FSR_RD((unsigned int)rnd_dir & 0x03);
+
+ __asm__("ld %0,%%fsr" : : "m" (new));
+
+ return ((fp_rnd_t)FSR_GET_RD(old));
+}
diff --git a/lib/libc/sparc64/gen/infinity.c b/lib/libc/sparc64/gen/infinity.c
new file mode 100644
index 000000000000..6d0d9344b190
--- /dev/null
+++ b/lib/libc/sparc64/gen/infinity.c
@@ -0,0 +1,17 @@
+#include <sys/cdefs.h>
+#if 0
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: infinity.c,v 1.2 1998/11/14 19:31:02 christos Exp $");
+#endif /* LIBC_SCCS and not lint */
+#endif
+__FBSDID("$FreeBSD$");
+
+/* infinity.c */
+
+#include <math.h>
+
+/* bytes for +Infinity on a sparc */
+const union __infinity_un __infinity = { { 0x7f, 0xf0, 0, 0, 0, 0, 0, 0 } };
+
+/* bytes for NaN */
+const union __nan_un __nan = { { 0xff, 0xc0, 0, 0 } };
diff --git a/lib/libc/sparc64/gen/makecontext.c b/lib/libc/sparc64/gen/makecontext.c
new file mode 100644
index 000000000000..42bcc8803060
--- /dev/null
+++ b/lib/libc/sparc64/gen/makecontext.c
@@ -0,0 +1,89 @@
+/*-
+ * Copyright (c) 2003 Jake Burkholder.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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/signal.h>
+#include <sys/ucontext.h>
+
+#include <machine/frame.h>
+#include <machine/tstate.h>
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+__weak_reference(__makecontext, makecontext);
+
+void _ctx_done(ucontext_t *ucp);
+void _ctx_start(void);
+
+void
+__makecontext(ucontext_t *ucp, void (*start)(void), int argc, ...)
+{
+ mcontext_t *mc;
+ uint64_t sp;
+ va_list ap;
+ int i;
+
+ mc = &ucp->uc_mcontext;
+ if (ucp == NULL ||
+ (mc->_mc_flags & ((1L << _MC_VERSION_BITS) - 1)) != _MC_VERSION)
+ return;
+ if ((argc < 0) || (argc > 6) ||
+ (ucp->uc_stack.ss_sp == NULL) ||
+ (ucp->uc_stack.ss_size < MINSIGSTKSZ)) {
+ mc->_mc_flags = 0;
+ return;
+ }
+ mc = &ucp->uc_mcontext;
+ sp = (uint64_t)ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size;
+ va_start(ap, argc);
+ for (i = 0; i < argc; i++)
+ mc->mc_out[i] = va_arg(ap, uint64_t);
+ va_end(ap);
+ mc->mc_global[1] = (uint64_t)start;
+ mc->mc_global[2] = (uint64_t)ucp;
+ mc->mc_out[6] = sp - SPOFF - sizeof(struct frame);
+ mc->_mc_tnpc = (uint64_t)_ctx_start + 4;
+ mc->_mc_tpc = (uint64_t)_ctx_start;
+}
+
+void
+_ctx_done(ucontext_t *ucp)
+{
+
+ if (ucp->uc_link == NULL)
+ exit(0);
+ else {
+ ucp->uc_mcontext._mc_flags = 0;
+ setcontext((const ucontext_t *)ucp->uc_link);
+ abort();
+ }
+}
diff --git a/lib/libc/sparc64/gen/setjmp.S b/lib/libc/sparc64/gen/setjmp.S
new file mode 100644
index 000000000000..8161b7ae48f9
--- /dev/null
+++ b/lib/libc/sparc64/gen/setjmp.S
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: Header: _setjmp.s,v 1.1 91/07/06 16:45:53 torek Exp
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+ .asciz "@(#)_setjmp.s 8.1 (Berkeley) 6/4/93"
+#if 0
+ RCSID("$NetBSD: _setjmp.S,v 1.4 1998/10/08 02:27:59 eeh Exp $")
+#endif
+#endif /* LIBC_SCCS and not lint */
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "assym.s"
+
+ .register %g2,#ignore
+ .register %g3,#ignore
+
+/*
+ * C library -- setjmp, longjmp
+ *
+ * longjmp(a,v)
+ * will generate a "return(v?v:1)" from
+ * the last call to
+ * setjmp(a)
+ * by restoring the previous context.
+ */
+
+ENTRY(setjmp)
+ save %sp, -CCFSZ, %sp
+ mov SIG_BLOCK, %o0
+ clr %o1
+ call CNAME(sigprocmask)
+ add %i0, _JB_SIGMASK, %o2
+ restore
+ stx %sp, [%o0 + _JB_SP]
+ stx %o7, [%o0 + _JB_PC]
+ retl
+ clr %o0
+END(setjmp)
+
+ .weak CNAME(longjmp)
+ .set CNAME(longjmp),CNAME(__longjmp)
+ENTRY(__longjmp)
+ save %sp, -CCFSZ, %sp
+ flushw
+ mov SIG_SETMASK, %o0
+ add %i0, _JB_SIGMASK, %o1
+ call CNAME(sigprocmask)
+ clr %o2
+ ldx [%i0 + _JB_SP], %fp
+ ldx [%i0 + _JB_PC], %i7
+ mov 1, %i0
+ movrnz %i1, %i1, %i0
+ ret
+ restore
+END(__longjmp)
diff --git a/lib/libc/sparc64/gen/signalcontext.c b/lib/libc/sparc64/gen/signalcontext.c
new file mode 100644
index 000000000000..159184513807
--- /dev/null
+++ b/lib/libc/sparc64/gen/signalcontext.c
@@ -0,0 +1,77 @@
+/*-
+ * Copyright (c) 2003 Jake Burkholder.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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/ucontext.h>
+
+#include <machine/frame.h>
+#include <machine/sigframe.h>
+
+#include <errno.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+
+__weak_reference(__signalcontext, signalcontext);
+
+extern void _ctx_start(void);
+
+int
+__signalcontext(ucontext_t *ucp, int sig, __sighandler_t *func)
+{
+ struct sigframe *sfp;
+ struct frame *fp;
+ mcontext_t *mc;
+
+ mc = &ucp->uc_mcontext;
+ sfp = (struct sigframe *)(mc->_mc_sp + SPOFF) - 1;
+ fp = (struct frame *)sfp - 1;
+
+ bzero(fp, sizeof(*fp));
+
+ bzero(sfp, sizeof(*sfp));
+ bcopy(ucp, &sfp->sf_uc, sizeof(*ucp));
+ sfp->sf_si.si_signo = sig;
+
+ mc->mc_global[1] = (uint64_t)func;
+ mc->mc_global[2] = (uint64_t)ucp;
+ mc->mc_out[0] = sig;
+ mc->mc_out[1] = (uint64_t)&sfp->sf_si;
+ mc->mc_out[2] = (uint64_t)&sfp->sf_uc;
+ mc->mc_out[6] = (uint64_t)fp - SPOFF;
+ mc->_mc_tnpc = (uint64_t)_ctx_start + 4;
+ mc->_mc_tpc = (uint64_t)_ctx_start;
+
+ ucp->uc_link = &sfp->sf_uc;
+ sigdelset(&ucp->uc_sigmask, sig);
+
+ return (0);
+}
diff --git a/lib/libc/sparc64/gen/sigsetjmp.S b/lib/libc/sparc64/gen/sigsetjmp.S
new file mode 100644
index 000000000000..4e4456648c66
--- /dev/null
+++ b/lib/libc/sparc64/gen/sigsetjmp.S
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 1995 Paul Kranenburg
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Paul Kranenburg.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "assym.s"
+
+ENTRY(sigsetjmp)
+ PIC_PROLOGUE(%o3, %o2)
+ SET(CNAME(setjmp), %o2, %o3)
+ SET(CNAME(_setjmp), %o2, %o4)
+ movrnz %o1, %o3, %o4
+ jmp %o4
+ stx %o1, [%o0 + _JB_SIGFLAG]
+END(sigsetjmp)
+
+ .weak CNAME(siglongjmp);
+ .set CNAME(siglongjmp),CNAME(__siglongjmp);
+ENTRY(__siglongjmp)
+ PIC_PROLOGUE(%o3, %o2)
+ SET(CNAME(longjmp), %o2, %o3)
+ SET(CNAME(_longjmp), %o2, %o4)
+ ldx [%o0 + _JB_SIGFLAG], %o2
+ movrnz %o2, %o3, %o4
+ jmp %o4
+ nop
+END(__siglongjmp)
diff --git a/lib/libc/sparc64/string/Makefile.inc b/lib/libc/sparc64/string/Makefile.inc
new file mode 100644
index 000000000000..e8c0da7a1d7e
--- /dev/null
+++ b/lib/libc/sparc64/string/Makefile.inc
@@ -0,0 +1 @@
+# $FreeBSD$
diff --git a/lib/libc/sparc64/sys/Makefile.inc b/lib/libc/sparc64/sys/Makefile.inc
new file mode 100644
index 000000000000..65e1353cb6ac
--- /dev/null
+++ b/lib/libc/sparc64/sys/Makefile.inc
@@ -0,0 +1,15 @@
+# $FreeBSD$
+
+SRCS+= __sparc_sigtramp_setup.c \
+ __sparc_utrap.c \
+ __sparc_utrap_align.c \
+ __sparc_utrap_emul.c \
+ __sparc_utrap_fp_disabled.S \
+ __sparc_utrap_gen.S \
+ __sparc_utrap_install.c \
+ __sparc_utrap_setup.c \
+ sigcode.S
+
+CFLAGS+= -I${LIBC_SRCTOP}/sparc64/fpu
+
+MDASM+= brk.S cerror.S exect.S sbrk.S setlogin.S sigaction1.S
diff --git a/lib/libc/sparc64/sys/__sparc_sigtramp_setup.c b/lib/libc/sparc64/sys/__sparc_sigtramp_setup.c
new file mode 100644
index 000000000000..4475c6d4632a
--- /dev/null
+++ b/lib/libc/sparc64/sys/__sparc_sigtramp_setup.c
@@ -0,0 +1,46 @@
+/*-
+ * Copyright (c) 2002 Jake Burkholder.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 <machine/utrap.h>
+#include <machine/sysarch.h>
+
+#include <stdlib.h>
+
+extern char __sigtramp[];
+
+static const struct sparc_sigtramp_install_args sia = { __sigtramp, NULL };
+
+void
+__sparc_sigtramp_setup(void)
+{
+
+ sysarch(SPARC_SIGTRAMP_INSTALL, (void *)&sia);
+}
diff --git a/lib/libc/sparc64/sys/__sparc_utrap.c b/lib/libc/sparc64/sys/__sparc_utrap.c
new file mode 100644
index 000000000000..7a5dafa5aeb5
--- /dev/null
+++ b/lib/libc/sparc64/sys/__sparc_utrap.c
@@ -0,0 +1,141 @@
+/*-
+ * Copyright (c) 2001 Jake Burkholder.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 <machine/utrap.h>
+#include <machine/sysarch.h>
+
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "fpu_extern.h"
+#include "__sparc_utrap_private.h"
+
+extern ssize_t __sys_write(int, const void *, size_t);
+extern int __sys_kill(pid_t, int);
+extern pid_t __sys_getpid(void);
+
+static const char *utrap_msg[] = {
+ "reserved",
+ "instruction access exception",
+ "instruction access error",
+ "instruction access protection",
+ "illtrap instruction",
+ "illegal instruction",
+ "privileged opcode",
+ "floating point disabled",
+ "floating point exception ieee 754",
+ "floating point exception other",
+ "tag overflow",
+ "division by zero",
+ "data access exception",
+ "data access error",
+ "data access protection",
+ "memory address not aligned",
+ "privileged action",
+ "async data error",
+ "trap instruction 16",
+ "trap instruction 17",
+ "trap instruction 18",
+ "trap instruction 19",
+ "trap instruction 20",
+ "trap instruction 21",
+ "trap instruction 22",
+ "trap instruction 23",
+ "trap instruction 24",
+ "trap instruction 25",
+ "trap instruction 26",
+ "trap instruction 27",
+ "trap instruction 28",
+ "trap instruction 29",
+ "trap instruction 30",
+ "trap instruction 31",
+};
+
+void
+__sparc_utrap(struct utrapframe *uf)
+{
+ int sig;
+
+ switch (uf->uf_type) {
+ case UT_FP_EXCEPTION_IEEE_754:
+ case UT_FP_EXCEPTION_OTHER:
+ sig = __fpu_exception(uf);
+ break;
+ case UT_ILLEGAL_INSTRUCTION:
+ sig = __emul_insn(uf);
+ break;
+ case UT_MEM_ADDRESS_NOT_ALIGNED:
+ sig = __unaligned_fixup(uf);
+ break;
+ default:
+ break;
+ }
+ if (sig) {
+ __utrap_write("__sparc_utrap: fatal ");
+ __utrap_write(utrap_msg[uf->uf_type]);
+ __utrap_write("\n");
+ __utrap_kill_self(sig);
+ }
+ UF_DONE(uf);
+}
+
+void
+__utrap_write(const char *str)
+{
+ int berrno;
+
+ berrno = errno;
+ __sys_write(STDERR_FILENO, str, strlen(str));
+ errno = berrno;
+}
+
+void
+__utrap_kill_self(int sig)
+{
+ int berrno;
+
+ berrno = errno;
+ __sys_kill(__sys_getpid(), sig);
+ errno = berrno;
+}
+
+void
+__utrap_panic(const char *msg)
+{
+
+ __utrap_write(msg);
+ __utrap_write("\n");
+ __utrap_kill_self(SIGKILL);
+}
diff --git a/lib/libc/sparc64/sys/__sparc_utrap_align.c b/lib/libc/sparc64/sys/__sparc_utrap_align.c
new file mode 100644
index 000000000000..9b59826263cd
--- /dev/null
+++ b/lib/libc/sparc64/sys/__sparc_utrap_align.c
@@ -0,0 +1,117 @@
+/*-
+ * Copyright (c) 2002 Jake Burkholder.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list 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 OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 <machine/cpufunc.h>
+#include <machine/instr.h>
+
+#include <signal.h>
+
+#include "__sparc_utrap_private.h"
+
+static u_long
+__unaligned_load(u_char *p, int size)
+{
+ u_long val;
+ int i;
+
+ val = 0;
+ for (i = 0; i < size; i++)
+ val = (val << 8) | p[i];
+ return (val);
+}
+
+static void
+__unaligned_store(u_char *p, u_long val, int size)
+{
+ int i;
+
+ for (i = 0; i < size; i++)
+ p[i] = val >> ((size - i - 1) * 8);
+}
+
+int
+__unaligned_fixup(struct utrapframe *uf)
+{
+ u_char *addr;
+ u_long val;
+ u_int insn;
+ int sig;
+
+ sig = 0;
+ addr = (u_char *)uf->uf_sfar;
+ insn = *(u_int *)uf->uf_pc;
+ flushw();
+ switch (IF_OP(insn)) {
+ case IOP_LDST:
+ switch (IF_F3_OP3(insn)) {
+ case INS3_LDUH:
+ val = __unaligned_load(addr, 2);
+ __emul_store_reg(uf, IF_F3_RD(insn), val);
+ break;
+ case INS3_LDUW:
+ val = __unaligned_load(addr, 4);
+ __emul_store_reg(uf, IF_F3_RD(insn), val);
+ break;
+ case INS3_LDX:
+ val = __unaligned_load(addr, 8);
+ __emul_store_reg(uf, IF_F3_RD(insn), val);
+ break;
+ case INS3_LDSH:
+ val = __unaligned_load(addr, 2);
+ __emul_store_reg(uf, IF_F3_RD(insn),
+ IF_SEXT(val, 16));
+ break;
+ case INS3_LDSW:
+ val = __unaligned_load(addr, 4);
+ __emul_store_reg(uf, IF_F3_RD(insn),
+ IF_SEXT(val, 32));
+ break;
+ case INS3_STH:
+ val = __emul_fetch_reg(uf, IF_F3_RD(insn));
+ __unaligned_store(addr, val, 2);
+ break;
+ case INS3_STW:
+ val = __emul_fetch_reg(uf, IF_F3_RD(insn));
+ __unaligned_store(addr, val, 4);
+ break;
+ case INS3_STX:
+ val = __emul_fetch_reg(uf, IF_F3_RD(insn));
+ __unaligned_store(addr, val, 8);
+ break;
+ default:
+ sig = SIGILL;
+ break;
+ }
+ break;
+ default:
+ sig = SIGILL;
+ break;
+ }
+ return (sig);
+}
diff --git a/lib/libc/sparc64/sys/__sparc_utrap_emul.c b/lib/libc/sparc64/sys/__sparc_utrap_emul.c
new file mode 100644
index 000000000000..6c6dd1b9b97a
--- /dev/null
+++ b/lib/libc/sparc64/sys/__sparc_utrap_emul.c
@@ -0,0 +1,155 @@
+/*-
+ * Copyright (c) 2001 by Thomas Moestl <tmm@FreeBSD.org>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 <machine/cpufunc.h>
+#include <machine/frame.h>
+#include <machine/instr.h>
+
+#include <signal.h>
+
+#include "__sparc_utrap_private.h"
+#include "fpu_reg.h"
+
+int
+__emul_insn(struct utrapframe *uf)
+{
+ u_long reg, res;
+ u_long *addr;
+ u_int insn;
+ int sig;
+ int rd;
+ int i;
+
+ sig = 0;
+ insn = *(u_int *)uf->uf_pc;
+ flushw();
+ switch (IF_OP(insn)) {
+ case IOP_MISC:
+ switch (IF_F3_OP3(insn)) {
+ case INS2_POPC:
+ if (IF_F3_RS1(insn) != 0) {
+ sig = SIGILL;
+ break;
+ }
+ reg = __emul_f3_op2(uf, insn);
+ for (i = 0; i < 64; i++)
+ res += (reg >> i) & 1;
+ __emul_store_reg(uf, IF_F3_RD(insn), res);
+ break;
+ default:
+ sig = SIGILL;
+ break;
+ }
+ break;
+ case IOP_LDST:
+ switch (IF_F3_OP3(insn)) {
+ case INS3_LDQF:
+ rd = INSFPdq_RN(IF_F3_RD(insn));
+ addr = (u_long *)__emul_f3_memop_addr(uf, insn);
+ __fpu_setreg64(rd, addr[0]);
+ __fpu_setreg64(rd + 2, addr[1]);
+ break;
+ case INS3_STQF:
+ rd = INSFPdq_RN(IF_F3_RD(insn));
+ addr = (u_long *)__emul_f3_memop_addr(uf, insn);
+ addr[0] = __fpu_getreg64(rd);
+ addr[1] = __fpu_getreg64(rd + 2);
+ break;
+ default:
+ sig = SIGILL;
+ break;
+ }
+ break;
+ default:
+ sig = SIGILL;
+ break;
+ }
+ return (sig);
+}
+
+u_long
+__emul_fetch_reg(struct utrapframe *uf, int reg)
+{
+ struct frame *frm;
+
+ if (reg == IREG_G0)
+ return (0);
+ else if (reg < IREG_O0) /* global */
+ return (uf->uf_global[reg]);
+ else if (reg < IREG_L0) /* out */
+ return (uf->uf_out[reg - IREG_O0]);
+ else { /* local, in */
+ /*
+ * The in registers are immediately after the locals in
+ * the frame.
+ */
+ frm = (struct frame *)(uf->uf_out[6] + SPOFF);
+ return (frm->fr_local[reg - IREG_L0]);
+ }
+}
+
+void
+__emul_store_reg(struct utrapframe *uf, int reg, u_long val)
+{
+ struct frame *frm;
+
+ if (reg == IREG_G0)
+ return;
+ if (reg < IREG_O0) /* global */
+ uf->uf_global[reg] = val;
+ else if (reg < IREG_L0) /* out */
+ uf->uf_out[reg - IREG_O0] = val;
+ else {
+ /*
+ * The in registers are immediately after the locals in
+ * the frame.
+ */
+ frm = (struct frame *)(uf->uf_out[6] + SPOFF);
+ frm->fr_local[reg - IREG_L0] = val;
+ }
+}
+
+u_long
+__emul_f3_op2(struct utrapframe *uf, u_int insn)
+{
+
+ if (IF_F3_I(insn) != 0)
+ return (IF_SIMM(insn, 13));
+ else
+ return (__emul_fetch_reg(uf, IF_F3_RS2(insn)));
+}
+
+u_long
+__emul_f3_memop_addr(struct utrapframe *uf, u_int insn)
+{
+ u_long addr;
+
+ addr = __emul_f3_op2(uf, insn) + __emul_fetch_reg(uf, IF_F3_RS1(insn));
+ return (addr);
+}
diff --git a/lib/libc/sparc64/sys/__sparc_utrap_fp_disabled.S b/lib/libc/sparc64/sys/__sparc_utrap_fp_disabled.S
new file mode 100644
index 000000000000..502f81a22510
--- /dev/null
+++ b/lib/libc/sparc64/sys/__sparc_utrap_fp_disabled.S
@@ -0,0 +1,36 @@
+/*-
+ * Copyright (c) 2001 Jake Burkholder.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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$");
+
+#include <machine/utrap.h>
+
+ENTRY(__sparc_utrap_fp_disabled)
+ ta %xcc, ST_FP_RESTORE
+ jmpl %l6, %g0
+ return %l7
+END(__sparc_utrap_fp_disabled)
diff --git a/lib/libc/sparc64/sys/__sparc_utrap_gen.S b/lib/libc/sparc64/sys/__sparc_utrap_gen.S
new file mode 100644
index 000000000000..6f6f0e3d2c57
--- /dev/null
+++ b/lib/libc/sparc64/sys/__sparc_utrap_gen.S
@@ -0,0 +1,107 @@
+/*-
+ * Copyright (c) 2001 Jake Burkholder.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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$");
+
+ .register %g2, #ignore
+ .register %g3, #ignore
+ .register %g6, #ignore
+ .register %g7, #ignore
+
+#include <machine/tstate.h>
+#include <machine/utrap.h>
+
+#include "assym.s"
+
+ENTRY(__sparc_utrap_gen)
+ sub %sp, UF_SIZEOF, %sp
+
+ stx %o0, [%sp + SPOFF + CCFSZ + UF_TYPE]
+ stx %o3, [%sp + SPOFF + CCFSZ + UF_TAR]
+ stx %o4, [%sp + SPOFF + CCFSZ + UF_SFAR]
+ stx %o5, [%sp + SPOFF + CCFSZ + UF_SFSR]
+
+ stx %l4, [%sp + SPOFF + CCFSZ + UF_FSR]
+ stx %l5, [%sp + SPOFF + CCFSZ + UF_STATE]
+ stx %l6, [%sp + SPOFF + CCFSZ + UF_PC]
+ stx %l7, [%sp + SPOFF + CCFSZ + UF_NPC]
+
+ stx %g1, [%sp + SPOFF + CCFSZ + UF_G1]
+ stx %g2, [%sp + SPOFF + CCFSZ + UF_G2]
+ stx %g3, [%sp + SPOFF + CCFSZ + UF_G3]
+ stx %g4, [%sp + SPOFF + CCFSZ + UF_G4]
+ stx %g5, [%sp + SPOFF + CCFSZ + UF_G5]
+ stx %g6, [%sp + SPOFF + CCFSZ + UF_G6]
+ stx %g7, [%sp + SPOFF + CCFSZ + UF_G7]
+
+ stx %i0, [%sp + SPOFF + CCFSZ + UF_O0]
+ stx %i1, [%sp + SPOFF + CCFSZ + UF_O1]
+ stx %i2, [%sp + SPOFF + CCFSZ + UF_O2]
+ stx %i3, [%sp + SPOFF + CCFSZ + UF_O3]
+ stx %i4, [%sp + SPOFF + CCFSZ + UF_O4]
+ stx %i5, [%sp + SPOFF + CCFSZ + UF_O5]
+ stx %i6, [%sp + SPOFF + CCFSZ + UF_O6]
+ stx %i7, [%sp + SPOFF + CCFSZ + UF_O7]
+
+ rd %y, %l6
+
+ call __sparc_utrap
+ add %sp, SPOFF + CCFSZ, %o0
+
+ wr %l6, 0, %y
+
+ ldx [%sp + SPOFF + CCFSZ + UF_G1], %g1
+ ldx [%sp + SPOFF + CCFSZ + UF_G2], %g2
+ ldx [%sp + SPOFF + CCFSZ + UF_G3], %g3
+ ldx [%sp + SPOFF + CCFSZ + UF_G4], %g4
+ ldx [%sp + SPOFF + CCFSZ + UF_G5], %g5
+ ldx [%sp + SPOFF + CCFSZ + UF_G6], %g6
+ ldx [%sp + SPOFF + CCFSZ + UF_G7], %g7
+
+ ldx [%sp + SPOFF + CCFSZ + UF_O0], %i0
+ ldx [%sp + SPOFF + CCFSZ + UF_O1], %i1
+ ldx [%sp + SPOFF + CCFSZ + UF_O2], %i2
+ ldx [%sp + SPOFF + CCFSZ + UF_O3], %i3
+ ldx [%sp + SPOFF + CCFSZ + UF_O4], %i4
+ ldx [%sp + SPOFF + CCFSZ + UF_O5], %i5
+ ldx [%sp + SPOFF + CCFSZ + UF_O6], %i6
+ ldx [%sp + SPOFF + CCFSZ + UF_O7], %i7
+
+ ldx [%sp + SPOFF + CCFSZ + UF_STATE], %l5
+ ! Restore %asi and %ccr from the passed tstate
+ srlx %l5, TSTATE_CCR_SHIFT, %l4
+ and %l4, CCR_MASK, %l4
+ wr %l4, 0, %ccr
+ srlx %l5, TSTATE_ASI_SHIFT, %l4
+ and %l4, ASI_MASK, %l4
+ wr %l4, 0, %asi
+ ldx [%sp + SPOFF + CCFSZ + UF_PC], %l6
+ ldx [%sp + SPOFF + CCFSZ + UF_NPC], %l7
+
+ jmpl %l6, %g0
+ return %l7
+END(__sparc_utrap_gen)
diff --git a/lib/libc/sparc64/sys/__sparc_utrap_install.c b/lib/libc/sparc64/sys/__sparc_utrap_install.c
new file mode 100644
index 000000000000..7b1a5e7a0226
--- /dev/null
+++ b/lib/libc/sparc64/sys/__sparc_utrap_install.c
@@ -0,0 +1,49 @@
+/*-
+ * Copyright (c) 2001 Jake Burkholder.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 <machine/utrap.h>
+#include <machine/sysarch.h>
+
+int
+__sparc_utrap_install(utrap_entry_t type, utrap_handler_t new_precise,
+ utrap_handler_t new_deferred, utrap_handler_t *old_precise,
+ utrap_handler_t *old_deferred)
+{
+ struct sparc_utrap_install_args uia;
+ struct sparc_utrap_args ua[1];
+
+ ua[0].type = type;
+ ua[0].new_precise = new_precise;
+ ua[0].new_deferred = new_deferred;
+ ua[0].old_precise = old_precise;
+ ua[0].old_deferred = old_deferred;
+ uia.num = 1;
+ uia.handlers = ua;
+ return (sysarch(SPARC_UTRAP_INSTALL, &uia));
+}
diff --git a/lib/libc/sparc64/sys/__sparc_utrap_private.h b/lib/libc/sparc64/sys/__sparc_utrap_private.h
new file mode 100644
index 000000000000..8b9ae9eefc96
--- /dev/null
+++ b/lib/libc/sparc64/sys/__sparc_utrap_private.h
@@ -0,0 +1,66 @@
+/*-
+ * Copyright (c) 2001 Jake Burkholder.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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 ___SPARC_UTRAP_PRIVATE_H_
+#define ___SPARC_UTRAP_PRIVATE_H_
+
+#define UF_DONE(uf) do { \
+ uf->uf_pc = uf->uf_npc; \
+ uf->uf_npc = uf->uf_pc + 4; \
+} while (0)
+
+struct utrapframe {
+ u_long uf_global[8];
+ u_long uf_out[8];
+ u_long uf_pc;
+ u_long uf_npc;
+ u_long uf_sfar;
+ u_long uf_sfsr;
+ u_long uf_tar;
+ u_long uf_type;
+ u_long uf_state;
+ u_long uf_fsr;
+};
+
+extern char __sparc_utrap_fp_disabled[];
+extern char __sparc_utrap_gen[];
+
+int __emul_insn(struct utrapframe *uf);
+u_long __emul_fetch_reg(struct utrapframe *uf, int reg);
+void __emul_store_reg(struct utrapframe *uf, int reg, u_long val);
+u_long __emul_f3_op2(struct utrapframe *uf, u_int insn);
+u_long __emul_f3_memop_addr(struct utrapframe *uf, u_int insn);
+int __unaligned_fixup(struct utrapframe *uf);
+
+void __sparc_utrap(struct utrapframe *);
+
+void __utrap_write(const char *);
+void __utrap_kill_self(int);
+void __utrap_panic(const char *);
+
+#endif
diff --git a/lib/libc/sparc64/sys/__sparc_utrap_setup.c b/lib/libc/sparc64/sys/__sparc_utrap_setup.c
new file mode 100644
index 000000000000..2524f44b8031
--- /dev/null
+++ b/lib/libc/sparc64/sys/__sparc_utrap_setup.c
@@ -0,0 +1,58 @@
+/*-
+ * Copyright (c) 2001 Jake Burkholder.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 <machine/utrap.h>
+#include <machine/sysarch.h>
+
+#include <stdlib.h>
+
+#include "__sparc_utrap_private.h"
+
+static const struct sparc_utrap_args ua[] = {
+ { UT_FP_DISABLED, __sparc_utrap_fp_disabled, NULL, NULL, NULL },
+ { UT_FP_EXCEPTION_IEEE_754, __sparc_utrap_gen, NULL, NULL, NULL },
+ { UT_FP_EXCEPTION_OTHER, __sparc_utrap_gen, NULL, NULL, NULL },
+ { UT_ILLEGAL_INSTRUCTION, __sparc_utrap_gen, NULL, NULL, NULL },
+ { UT_MEM_ADDRESS_NOT_ALIGNED, __sparc_utrap_gen, NULL, NULL, NULL },
+};
+
+static const struct sparc_utrap_install_args uia[] = {
+ { sizeof (ua) / sizeof (*ua), ua }
+};
+
+void __sparc_utrap_setup(void) __attribute__((constructor));
+
+void
+__sparc_utrap_setup(void)
+{
+
+ sysarch(SPARC_UTRAP_INSTALL, (void *)&uia);
+}
diff --git a/lib/libc/sparc64/sys/assym.s b/lib/libc/sparc64/sys/assym.s
new file mode 100644
index 000000000000..2e799f6566b8
--- /dev/null
+++ b/lib/libc/sparc64/sys/assym.s
@@ -0,0 +1,39 @@
+/*
+ * Offsets into structures used from asm. Must be kept in sync with
+ * appropriate headers.
+ *
+ * $FreeBSD$
+ */
+
+#define FPRS_FEF 0x4
+
+#define CCR_MASK 0xff
+#define ASI_MASK 0xff
+
+#define UF_G0 0x0
+#define UF_G1 0x8
+#define UF_G2 0x10
+#define UF_G3 0x18
+#define UF_G4 0x20
+#define UF_G5 0x28
+#define UF_G6 0x30
+#define UF_G7 0x38
+#define UF_O0 0x40
+#define UF_O1 0x48
+#define UF_O2 0x50
+#define UF_O3 0x58
+#define UF_O4 0x60
+#define UF_O5 0x68
+#define UF_O6 0x70
+#define UF_O7 0x78
+#define UF_PC 0x80
+#define UF_NPC 0x88
+#define UF_SFAR 0x90
+#define UF_SFSR 0x98
+#define UF_TAR 0xa0
+#define UF_TYPE 0xa8
+#define UF_STATE 0xb0
+#define UF_FSR 0xb8
+#define UF_SIZEOF 0xc0
+
+#define SF_UC 0x0
diff --git a/lib/libc/sparc64/sys/brk.S b/lib/libc/sparc64/sys/brk.S
new file mode 100644
index 000000000000..0167c4ee1e54
--- /dev/null
+++ b/lib/libc/sparc64/sys/brk.S
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: Header: brk.s,v 1.3 92/06/25 12:56:05 mccanne Exp
+ */
+
+#if defined(SYSLIBC_SCCS) && !defined(lint)
+ .asciz "@(#)brk.s 8.1 (Berkeley) 6/4/93"
+#if 0
+ RCSID("$NetBSD: brk.S,v 1.9 2000/07/25 20:15:40 mycroft Exp $")
+#endif
+#endif /* SYSLIBC_SCCS and not lint */
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+ .globl HIDENAME(curbrk)
+ .globl HIDENAME(minbrk)
+
+_SYSENTRY(brk)
+ PIC_PROLOGUE(%o3, %o2)
+ SET(HIDENAME(minbrk), %o2, %o3)
+ ldx [%o3], %o4
+ cmp %o4, %o0
+ movg %xcc, %o4, %o0
+ mov %o0, %o4
+ mov SYS_break, %g1
+ ta %xcc, ST_SYSCALL
+ bcc,a,pt %xcc, 1f
+ nop
+ ERROR()
+1: SET(HIDENAME(curbrk), %o2, %o3)
+ retl
+ stx %o4, [%o3]
+_SYSEND(brk)
diff --git a/lib/libc/sparc64/sys/cerror.S b/lib/libc/sparc64/sys/cerror.S
new file mode 100644
index 000000000000..9f903ea9a428
--- /dev/null
+++ b/lib/libc/sparc64/sys/cerror.S
@@ -0,0 +1,59 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: FreeBSD: src/lib/libc/i386/sys/cerror.S,v 1.11 2001/08/13
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+ .text
+ .align 16
+ .globl HIDENAME(cerror)
+ .type HIDENAME(cerror),@function
+
+ /*
+ * The __error() function is thread aware. For non-threaded
+ * programs and the initial threaded in threaded programs,
+ * it returns a pointer to the global errno variable.
+ */
+ .globl CNAME(__error)
+HIDENAME(cerror):
+ save %sp, -CCFSZ, %sp
+ call CNAME(__error)
+ nop
+ stw %i0, [%o0]
+ mov -1, %i0
+ ret
+ restore %g0, -1, %o1
+END(HIDENAME(cerror))
diff --git a/lib/libc/sparc64/sys/exect.S b/lib/libc/sparc64/sys/exect.S
new file mode 100644
index 000000000000..f6af2230c0be
--- /dev/null
+++ b/lib/libc/sparc64/sys/exect.S
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: Header: exect.s,v 1.1 91/07/06 13:05:57 torek Exp
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+ .asciz "@(#)exect.s 8.1 (Berkeley) 6/4/93"
+#if 0
+ RCSID("$NetBSD: exect.S,v 1.1 1998/09/11 04:56:34 eeh Exp $")
+#endif
+#endif /* LIBC_SCCS and not lint */
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+_SYSENTRY(exect)
+ mov SYS_execve, %g1
+ ta %xcc, ST_SYSCALL
+ ERROR()
+_SYSEND(exect)
diff --git a/lib/libc/sparc64/sys/sbrk.S b/lib/libc/sparc64/sys/sbrk.S
new file mode 100644
index 000000000000..c8c6e97eeb13
--- /dev/null
+++ b/lib/libc/sparc64/sys/sbrk.S
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: Header: brk.s,v 1.3 92/06/25 12:56:05 mccanne Exp
+ */
+
+#if defined(SYSLIBC_SCCS) && !defined(lint)
+ .asciz "@(#)sbrk.s 8.1 (Berkeley) 6/4/93"
+#if 0
+ RCSID("$NetBSD: sbrk.S,v 1.7 2000/07/25 15:14:46 mycroft Exp $")
+#endif
+#endif /* SYSLIBC_SCCS and not lint */
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+ .data
+ .globl HIDENAME(curbrk)
+ .globl HIDENAME(minbrk)
+ .type HIDENAME(curbrk),@object
+ .type HIDENAME(minbrk),@object
+ .align 8
+HIDENAME(curbrk):
+ .xword CNAME(_end)
+HIDENAME(minbrk):
+ .xword CNAME(_end)
+
+_SYSENTRY(sbrk)
+ PIC_PROLOGUE(%o3, %o2)
+ SET(HIDENAME(curbrk), %o2, %o3)
+ ldx [%o3], %o4
+ add %o4, %o0, %o5
+ mov %o5, %o0
+ mov SYS_break, %g1
+ ta %xcc, ST_SYSCALL
+ bcc,a,pt %xcc, 1f
+ mov %o4, %o0
+ ERROR()
+1: retl
+ stx %o5, [%o3]
+_SYSEND(sbrk)
diff --git a/lib/libc/sparc64/sys/setlogin.S b/lib/libc/sparc64/sys/setlogin.S
new file mode 100644
index 000000000000..d7595cf9a07a
--- /dev/null
+++ b/lib/libc/sparc64/sys/setlogin.S
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: Header: setlogin.s,v 1.1 91/07/06 13:06:00 torek Exp
+ */
+
+#if defined(SYSLIBC_SCCS) && !defined(lint)
+ .asciz "@(#)setlogin.s 8.1 (Berkeley) 6/4/93"
+#if 0
+ RCSID("$NetBSD: setlogin.S,v 1.3 2000/07/21 03:14:15 eeh Exp $")
+#endif
+#endif /* SYSLIBC_SCCS and not lint */
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#include "SYS.h"
+
+ .globl CNAME(_logname_valid) /* in _getlogin() */
+
+_SYSENTRY(setlogin)
+ _SYSCALL(setlogin)
+ PIC_PROLOGUE(%o3, %o2)
+ SET(CNAME(_logname_valid), %o2, %o3)
+ retl
+ stw %g0, [%o3]
+_SYSEND(setlogin)
diff --git a/lib/libc/sparc64/sys/sigaction1.S b/lib/libc/sparc64/sys/sigaction1.S
new file mode 100644
index 000000000000..219a238cdb2a
--- /dev/null
+++ b/lib/libc/sparc64/sys/sigaction1.S
@@ -0,0 +1,50 @@
+/*-
+ * Copyright (c) 2002 Jake Burkholder.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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$");
+
+#include "SYS.h"
+
+ WEAK_REFERENCE(__sys_sigaction, _sigaction)
+ENTRY(__sys_sigaction)
+ PIC_PROLOGUE(%o3, %o4)
+ SET(sigcode_installed, %o4, %o3)
+ lduw [%o3], %o4
+ brnz,a,pt %o4, 1f
+ nop
+ save %sp, -CCFSZ, %sp
+ call __sparc_sigtramp_setup
+ nop
+ restore
+ mov 1, %o4
+ stw %o4, [%o3]
+1: _SYSCALL(sigaction)
+ retl
+ nop
+END(__sys_sigaction)
+
+ .comm sigcode_installed, 4, 4
diff --git a/lib/libc/sparc64/sys/sigcode.S b/lib/libc/sparc64/sys/sigcode.S
new file mode 100644
index 000000000000..be3cb451a8b3
--- /dev/null
+++ b/lib/libc/sparc64/sys/sigcode.S
@@ -0,0 +1,40 @@
+/*-
+ * Copyright (c) 2002 Jake Burkholder.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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$");
+
+#include "assym.s"
+
+ENTRY(__sigtramp)
+ call %o4
+ nop
+ call sigreturn
+ add %sp, SPOFF + CCFSZ + SF_UC, %o0
+ call exit
+ mov 1, %o0
+ illtrap
+END(__sigtramp)
diff --git a/lib/libc/stdio/Makefile.inc b/lib/libc/stdio/Makefile.inc
new file mode 100644
index 000000000000..332e7764bc0e
--- /dev/null
+++ b/lib/libc/stdio/Makefile.inc
@@ -0,0 +1,87 @@
+# @(#)Makefile.inc 8.3 (Berkeley) 4/17/94
+# $FreeBSD$
+
+# stdio sources
+.PATH: ${LIBC_SRCTOP}/stdio
+
+SRCS+= _flock_stub.c asprintf.c clrerr.c dprintf.c \
+ fclose.c fcloseall.c fdopen.c \
+ feof.c ferror.c fflush.c fgetc.c fgetln.c fgetpos.c fgets.c fgetwc.c \
+ fgetwln.c fgetws.c \
+ fileno.c findfp.c flags.c fmemopen.c fopen.c \
+ fopencookie.c fprintf.c fpurge.c \
+ fputc.c fputs.c \
+ fputwc.c fputws.c fread.c freopen.c fscanf.c fseek.c fsetpos.c \
+ ftell.c funopen.c fvwrite.c fwalk.c fwide.c fwprintf.c fwscanf.c \
+ fwrite.c getc.c getchar.c getdelim.c getline.c \
+ gets.c getw.c getwc.c getwchar.c makebuf.c mktemp.c \
+ open_memstream.c open_wmemstream.c \
+ perror.c printf.c printf-pos.c putc.c putchar.c \
+ puts.c putw.c putwc.c putwchar.c \
+ refill.c remove.c rewind.c rget.c scanf.c setbuf.c setbuffer.c \
+ setvbuf.c snprintf.c sprintf.c sscanf.c stdio.c swprintf.c swscanf.c \
+ tempnam.c tmpfile.c \
+ tmpnam.c ungetc.c ungetwc.c vasprintf.c vdprintf.c vfprintf.c \
+ vfscanf.c \
+ vfwprintf.c vfwscanf.c vprintf.c vscanf.c vsnprintf.c vsprintf.c \
+ vsscanf.c \
+ vswprintf.c vswscanf.c vwprintf.c vwscanf.c wbuf.c wprintf.c wscanf.c \
+ wsetup.c
+
+SRCS+= xprintf.c xprintf_float.c xprintf_int.c xprintf_str.c
+SRCS+= xprintf_errno.c xprintf_hexdump.c xprintf_quote.c
+SRCS+= xprintf_time.c xprintf_vis.c
+
+SYM_MAPS+= ${LIBC_SRCTOP}/stdio/Symbol.map
+
+MAN+= fclose.3 ferror.3 fflush.3 fgetln.3 fgets.3 fgetwln.3 fgetws.3 \
+ flockfile.3 \
+ fopen.3 fopencookie.3 fputs.3 \
+ fputws.3 fread.3 fseek.3 funopen.3 fwide.3 getc.3 \
+ getline.3 getwc.3 mktemp.3 open_memstream.3 \
+ printf.3 printf_l.3 putc.3 putwc.3 remove.3 scanf.3 scanf_l.3 setbuf.3 \
+ stdio.3 tmpnam.3 \
+ ungetc.3 ungetwc.3 wprintf.3 wscanf.3
+
+MLINKS+=fclose.3 fcloseall.3 fclose.3 fdclose.3
+MLINKS+=ferror.3 ferror_unlocked.3 \
+ ferror.3 clearerr.3 ferror.3 clearerr_unlocked.3 \
+ ferror.3 feof.3 ferror.3 feof_unlocked.3 \
+ ferror.3 fileno.3 ferror.3 fileno_unlocked.3
+MLINKS+=fflush.3 fpurge.3
+MLINKS+=fgets.3 gets.3
+MLINKS+=flockfile.3 ftrylockfile.3 flockfile.3 funlockfile.3
+MLINKS+=fopen.3 fdopen.3 fopen.3 freopen.3 fopen.3 fmemopen.3
+MLINKS+=fputs.3 puts.3
+MLINKS+=fread.3 fwrite.3
+MLINKS+=fseek.3 fgetpos.3 fseek.3 fseeko.3 fseek.3 fsetpos.3 fseek.3 ftell.3 \
+ fseek.3 ftello.3 fseek.3 rewind.3
+MLINKS+=funopen.3 fropen.3 funopen.3 fwopen.3
+MLINKS+=getc.3 fgetc.3 getc.3 getc_unlocked.3 getc.3 getchar.3 \
+ getc.3 getchar_unlocked.3 getc.3 getw.3
+MLINKS+=getline.3 getdelim.3
+MLINKS+=getwc.3 fgetwc.3 getwc.3 getwchar.3
+MLINKS+=mktemp.3 mkdtemp.3 mktemp.3 mkstemp.3 mktemp.3 mkstemps.3 \
+ mktemp.3 mkostemp.3 mktemp.3 mkostemps.3
+MLINKS+=open_memstream.3 open_wmemstream.3
+MLINKS+=printf.3 asprintf.3 printf.3 dprintf.3 printf.3 fprintf.3 \
+ printf.3 snprintf.3 printf.3 sprintf.3 \
+ printf.3 vasprintf.3 printf.3 vdprintf.3 \
+ printf.3 vfprintf.3 printf.3 vprintf.3 printf.3 vsnprintf.3 \
+ printf.3 vsprintf.3
+MLINKS+=printf_l.3 asprintf_l.3 printf_l.3 fprintf_l.3 printf_l.3 snprintf_l.3 \
+ printf_l.3 sprintf_l.3 printf_l.3 vasprintf_l.3 printf_l.3 vfprintf_l.3 \
+ printf_l.3 vprintf_l.3 printf_l.3 vsnprintf_l.3 printf_l.3 vsprintf_l.3
+MLINKS+=putc.3 fputc.3 putc.3 putc_unlocked.3 putc.3 putchar.3 \
+ putc.3 putchar_unlocked.3 putc.3 putw.3
+MLINKS+=putwc.3 fputwc.3 putwc.3 putwchar.3
+MLINKS+=scanf.3 fscanf.3 scanf.3 sscanf.3 scanf.3 vfscanf.3 scanf.3 vscanf.3 \
+ scanf.3 vsscanf.3
+MLINKS+=scanf_l.3 fscanf_l.3 scanf_l.3 sscanf_l.3 scanf_l.3 vfscanf_l.3 \
+ scanf_l.3 vscanf_l.3 scanf_l.3 vsscanf_l.3
+MLINKS+=setbuf.3 setbuffer.3 setbuf.3 setlinebuf.3 setbuf.3 setvbuf.3
+MLINKS+=tmpnam.3 tempnam.3 tmpnam.3 tmpfile.3
+MLINKS+=wprintf.3 fwprintf.3 wprintf.3 swprintf.3 \
+ wprintf.3 vwprintf.3 wprintf.3 vfwprintf.3 wprintf.3 vswprintf.3
+MLINKS+=wscanf.3 fwscanf.3 wscanf.3 swscanf.3 wscanf.3 vwscanf.3 \
+ wscanf.3 vswscanf.3 wscanf.3 vfwscanf.3
diff --git a/lib/libc/stdio/Symbol.map b/lib/libc/stdio/Symbol.map
new file mode 100644
index 000000000000..92aefa0f09b9
--- /dev/null
+++ b/lib/libc/stdio/Symbol.map
@@ -0,0 +1,208 @@
+/*
+ * $FreeBSD$
+ */
+
+FBSD_1.0 {
+ flockfile;
+ ftrylockfile;
+ funlockfile;
+ asprintf;
+ clearerr;
+ fclose;
+ fcloseall;
+ fdopen;
+ feof;
+ ferror;
+ fflush;
+ fgetc;
+ fgetln;
+ fgetpos;
+ fgets;
+ fgetwc;
+ fgetwln;
+ fgetws;
+ fileno;
+ __sF;
+ __stdinp;
+ __stdoutp;
+ __stderrp;
+ f_prealloc; /* deprecated??? */
+ fopen;
+ fprintf;
+ fpurge;
+ fputc;
+ fputs;
+ fputwc;
+ fputws;
+ fread;
+ freopen;
+ fscanf;
+ fseek;
+ fseeko;
+ fsetpos;
+ ftell;
+ ftello;
+ funopen;
+ fwide;
+ fwprintf;
+ fwrite;
+ fwscanf;
+ getc;
+ getchar;
+ gets;
+ getw;
+ getwc;
+ getwchar;
+ mkstemps;
+ mkstemp;
+ mkdtemp;
+ mktemp;
+ perror;
+ printf;
+ putc;
+ putchar;
+ puts;
+ putw;
+ putwc;
+ putwchar;
+ remove;
+ rewind;
+ __srget;
+ scanf;
+ setbuf;
+ setbuffer;
+ setlinebuf;
+ setvbuf;
+ snprintf;
+ sprintf;
+ sscanf;
+ swprintf;
+ swscanf;
+ tempnam;
+ tmpfile;
+ tmpnam;
+ ungetc;
+ ungetwc;
+ getchar_unlocked;
+ getc_unlocked;
+ putchar_unlocked;
+ putc_unlocked;
+ feof_unlocked;
+ ferror_unlocked;
+ clearerr_unlocked;
+ fileno_unlocked;
+ vasprintf;
+ vfprintf;
+ vfscanf;
+ vfwprintf;
+ vfwscanf;
+ vprintf;
+ vscanf;
+ vsnprintf;
+ vsprintf;
+ vsscanf;
+ vswprintf;
+ vswscanf;
+ vwprintf;
+ vwscanf;
+ __swbuf;
+ wprintf;
+ wscanf;
+};
+
+FBSD_1.1 {
+ dprintf;
+ getdelim;
+ getline;
+ vdprintf;
+};
+
+FBSD_1.3 {
+ asprintf_l;
+ fprintf_l;
+ fwprintf_l;
+ printf_l;
+ snprintf_l;
+ sprintf_l;
+ swprintf_l;
+ vasprintf_l;
+ vfprintf_l;
+ vfwprintf_l;
+ vprintf_l;
+ vsnprintf_l;
+ vsprintf_l;
+ vswprintf_l;
+ vwprintf_l;
+ wprintf_l;
+ fgetwc_l;
+ fputwc_l;
+ ungetwc_l;
+ vfwscanf_l;
+ vswscanf_l;
+ fscanf_l;
+ fwscanf_l;
+ scanf_l;
+ sscanf_l;
+ swscanf_l;
+ vfscanf_l;
+ vscanf_l;
+ vsscanf_l;
+ vwscanf_l;
+ wscanf_l;
+ fgetws_l;
+ fputws_l;
+ getwc_l;
+ getwchar_l;
+ putwc_l;
+ putwchar_l;
+ fmemopen;
+ open_memstream;
+ open_wmemstream;
+ mkostemp;
+ mkostemps;
+};
+
+FBSD_1.4 {
+ fdclose;
+ fopencookie;
+};
+
+FBSDprivate_1.0 {
+ _flockfile;
+ _flockfile_debug_stub;
+ _flockfile_debug;
+ _ftrylockfile;
+ _funlockfile;
+ __vfscanf;
+
+ /*
+ * xprintf support
+ */
+ __use_xprintf;
+ __lowercase_hex;
+ __uppercase_hex;
+ __printf_flush;
+ __printf_puts;
+ __printf_pad;
+ __printf_out;
+ __xvprintf;
+ register_printf_function;
+ register_printf_render;
+ register_printf_render_std;
+ __printf_arginfo_float;
+ __printf_render_float;
+ __printf_arginfo_hexdump;
+ __printf_render_hexdump;
+ __printf_arginfo_int;
+ __printf_render_int;
+ __printf_arginfo_ptr;
+ __printf_render_ptr;
+ __printf_arginfo_str;
+ __printf_render_str;
+ __printf_arginfo_chr;
+ __printf_render_chr;
+ __printf_arginfo_time;
+ __printf_render_time;
+ __printf_arginfo_vis;
+ __printf_render_vis;
+};
diff --git a/lib/libc/stdio/_flock_stub.c b/lib/libc/stdio/_flock_stub.c
new file mode 100644
index 000000000000..f53df35da078
--- /dev/null
+++ b/lib/libc/stdio/_flock_stub.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 1998 John Birrell <jb@cimlogic.com.au>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * POSIX stdio FILE locking functions. These assume that the locking
+ * is only required at FILE structure level, not at file descriptor
+ * level too.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include "un-namespace.h"
+
+#include "local.h"
+
+
+/*
+ * Weak symbols for externally visible functions in this file:
+ */
+__weak_reference(_flockfile, flockfile);
+__weak_reference(_flockfile_debug_stub, _flockfile_debug);
+__weak_reference(_ftrylockfile, ftrylockfile);
+__weak_reference(_funlockfile, funlockfile);
+
+void _flockfile_debug_stub(FILE *, char *, int);
+int _ftrylockfile(FILE *);
+
+void
+_flockfile(FILE *fp)
+{
+ pthread_t curthread = _pthread_self();
+
+ if (fp->_fl_owner == curthread)
+ fp->_fl_count++;
+ else {
+ /*
+ * Make sure this mutex is treated as a private
+ * internal mutex:
+ */
+ _pthread_mutex_lock(&fp->_fl_mutex);
+ fp->_fl_owner = curthread;
+ fp->_fl_count = 1;
+ }
+}
+
+/*
+ * This can be overriden by the threads library if it is linked in.
+ */
+void
+_flockfile_debug_stub(FILE *fp, char *fname, int lineno)
+{
+ _flockfile(fp);
+}
+
+int
+_ftrylockfile(FILE *fp)
+{
+ pthread_t curthread = _pthread_self();
+ int ret = 0;
+
+ if (fp->_fl_owner == curthread)
+ fp->_fl_count++;
+ /*
+ * Make sure this mutex is treated as a private
+ * internal mutex:
+ */
+ else if (_pthread_mutex_trylock(&fp->_fl_mutex) == 0) {
+ fp->_fl_owner = curthread;
+ fp->_fl_count = 1;
+ }
+ else
+ ret = -1;
+ return (ret);
+}
+
+void
+_funlockfile(FILE *fp)
+{
+ pthread_t curthread = _pthread_self();
+
+ /*
+ * Check if this file is owned by the current thread:
+ */
+ if (fp->_fl_owner == curthread) {
+ /*
+ * Check if this thread has locked the FILE
+ * more than once:
+ */
+ if (fp->_fl_count > 1)
+ /*
+ * Decrement the count of the number of
+ * times the running thread has locked this
+ * file:
+ */
+ fp->_fl_count--;
+ else {
+ /*
+ * The running thread will release the
+ * lock now:
+ */
+ fp->_fl_count = 0;
+ fp->_fl_owner = NULL;
+ _pthread_mutex_unlock(&fp->_fl_mutex);
+ }
+ }
+}
diff --git a/lib/libc/stdio/asprintf.c b/lib/libc/stdio/asprintf.c
new file mode 100644
index 000000000000..242127f36025
--- /dev/null
+++ b/lib/libc/stdio/asprintf.c
@@ -0,0 +1,67 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <xlocale.h>
+
+int
+asprintf(char ** __restrict s, char const * __restrict fmt, ...)
+{
+ int ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ ret = vasprintf(s, fmt, ap);
+ va_end(ap);
+ return (ret);
+}
+int
+asprintf_l(char ** __restrict s, locale_t locale, char const * __restrict fmt,
+ ...)
+{
+ int ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ ret = vasprintf_l(s, locale, fmt, ap);
+ va_end(ap);
+ return (ret);
+}
diff --git a/lib/libc/stdio/clrerr.c b/lib/libc/stdio/clrerr.c
new file mode 100644
index 000000000000..f161a6e1e802
--- /dev/null
+++ b/lib/libc/stdio/clrerr.c
@@ -0,0 +1,60 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)clrerr.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <stdio.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+
+#undef clearerr
+#undef clearerr_unlocked
+
+void
+clearerr(FILE *fp)
+{
+ FLOCKFILE(fp);
+ __sclearerr(fp);
+ FUNLOCKFILE(fp);
+}
+
+void
+clearerr_unlocked(FILE *fp)
+{
+
+ __sclearerr(fp);
+}
diff --git a/lib/libc/stdio/dprintf.c b/lib/libc/stdio/dprintf.c
new file mode 100644
index 000000000000..2eb6abba7978
--- /dev/null
+++ b/lib/libc/stdio/dprintf.c
@@ -0,0 +1,45 @@
+/*-
+ * Copyright (c) 2009 David Schultz <das@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <stdarg.h>
+#include <stdio.h>
+#include "un-namespace.h"
+
+int
+dprintf(int fd, const char * __restrict fmt, ...)
+{
+ va_list ap;
+ int ret;
+
+ va_start(ap, fmt);
+ ret = vdprintf(fd, fmt, ap);
+ va_end(ap);
+ return (ret);
+}
diff --git a/lib/libc/stdio/fclose.3 b/lib/libc/stdio/fclose.3
new file mode 100644
index 000000000000..596ee3db0e6b
--- /dev/null
+++ b/lib/libc/stdio/fclose.3
@@ -0,0 +1,161 @@
+.\" Copyright (c) 1990, 1991, 1993 The Regents of the University of California.
+.\" Copyright (c) 2015 Mariusz Zaborski <oshogbo@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek and the American National Standards Committee X3,
+.\" on Information Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)fclose.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd July 4, 2015
+.Dt FCLOSE 3
+.Os
+.Sh NAME
+.Nm fclose ,
+.Nm fdclose ,
+.Nm fcloseall
+.Nd close a stream
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdio.h
+.Ft int
+.Fn fclose "FILE *stream"
+.Ft int
+.Fn fdclose "FILE *stream" "int *fdp"
+.Ft void
+.Fn fcloseall void
+.Sh DESCRIPTION
+The
+.Fn fclose
+function
+dissociates the named
+.Fa stream
+from its underlying file or set of functions.
+If the stream was being used for output, any buffered data is written
+first, using
+.Xr fflush 3 .
+.Pp
+The
+.Fn fdclose
+function is equivalent to
+.Fn fclose
+except that it does not close the underlying file descriptor.
+If
+.Fa fdp
+is not
+.Dv NULL ,
+the file descriptor will be written to it.
+If the
+.Fa fdp
+argument will be different then NULL the file descriptor will be returned in it,
+If the stream does not have an associated file descriptor,
+.Fa fdp
+will be set to -1.
+This type of stream is created with functions such as
+.Xr fmemopen 3 ,
+.Xr funopen 3 ,
+or
+.Xr open_memstream 3 .
+.Pp
+The
+.Fn fcloseall
+function calls
+.Fn fclose
+on all open streams.
+.Sh RETURN VALUES
+.Fn fcloseall
+does not return a value.
+.Pp
+Upon successful completion the
+.Fn fclose
+and
+.Fn fdclose
+functions return 0.
+Otherwise,
+.Dv EOF
+is returned and the global variable
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+.Fn fdclose
+fails if:
+.Bl -tag -width Er
+.It Bq Er EOPNOTSUPP
+The stream does not have an associated file descriptor.
+.El
+.Pp
+The
+.Fn fclose
+and
+.Fn fdclose
+functions may also fail and set
+.Va errno
+for any of the errors specified for
+.Xr fflush 3 .
+.Pp
+The
+.Fn fclose
+function may also fail and set errno for any of the errors specified for
+.Xr close 2 .
+.Sh NOTES
+The
+.Fn fclose
+and
+.Fn fdclose
+functions do not handle NULL arguments in the
+.Fa stream
+variable; this will result in a segmentation violation.
+This is intentional.
+It makes it easier to make sure programs written under
+.Fx
+are bug free.
+This behaviour is an implementation detail, and programs should not
+rely upon it.
+.Sh SEE ALSO
+.Xr close 2 ,
+.Xr fflush 3 ,
+.Xr fopen 3 ,
+.Xr setbuf 3
+.Sh STANDARDS
+The
+.Fn fclose
+function
+conforms to
+.St -isoC .
+.Sh HISTORY
+The
+.Fn fcloseall
+function first appeared in
+.Fx 7.0 .
+.Pp
+The
+.Fn fdclose
+function first appeared in
+.Fx 11.0 .
diff --git a/lib/libc/stdio/fclose.c b/lib/libc/stdio/fclose.c
new file mode 100644
index 000000000000..24b9b90af985
--- /dev/null
+++ b/lib/libc/stdio/fclose.c
@@ -0,0 +1,138 @@
+/*-
+ * Copyright (c) 1990, 1993 The Regents of the University of California.
+ * Copyright (c) 2013 Mariusz Zaborski <oshogbo@FreeBSD.org>
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)fclose.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "un-namespace.h"
+#include <spinlock.h>
+#include "libc_private.h"
+#include "local.h"
+
+static int
+cleanfile(FILE *fp, bool c)
+{
+ int r;
+
+ r = fp->_flags & __SWR ? __sflush(fp) : 0;
+ if (c) {
+ if (fp->_close != NULL && (*fp->_close)(fp->_cookie) < 0)
+ r = EOF;
+ }
+
+ if (fp->_flags & __SMBF)
+ free((char *)fp->_bf._base);
+ if (HASUB(fp))
+ FREEUB(fp);
+ if (HASLB(fp))
+ FREELB(fp);
+ fp->_file = -1;
+ fp->_r = fp->_w = 0; /* Mess up if reaccessed. */
+
+ /*
+ * Lock the spinlock used to protect __sglue list walk in
+ * __sfp(). The __sfp() uses fp->_flags == 0 test as an
+ * indication of the unused FILE.
+ *
+ * Taking the lock prevents possible compiler or processor
+ * reordering of the writes performed before the final _flags
+ * cleanup, making sure that we are done with the FILE before
+ * it is considered available.
+ */
+ STDIO_THREAD_LOCK();
+ fp->_flags = 0; /* Release this FILE for reuse. */
+ STDIO_THREAD_UNLOCK();
+
+ return (r);
+}
+
+int
+fdclose(FILE *fp, int *fdp)
+{
+ int r, err;
+
+ if (fdp != NULL)
+ *fdp = -1;
+
+ if (fp->_flags == 0) { /* not open! */
+ errno = EBADF;
+ return (EOF);
+ }
+
+ FLOCKFILE(fp);
+ r = 0;
+ if (fp->_close != __sclose) {
+ r = EOF;
+ errno = EOPNOTSUPP;
+ } else if (fp->_file < 0) {
+ r = EOF;
+ errno = EBADF;
+ }
+ if (r == EOF) {
+ err = errno;
+ (void)cleanfile(fp, true);
+ errno = err;
+ } else {
+ if (fdp != NULL)
+ *fdp = fp->_file;
+ r = cleanfile(fp, false);
+ }
+ FUNLOCKFILE(fp);
+
+ return (r);
+}
+
+int
+fclose(FILE *fp)
+{
+ int r;
+
+ if (fp->_flags == 0) { /* not open! */
+ errno = EBADF;
+ return (EOF);
+ }
+
+ FLOCKFILE(fp);
+ r = cleanfile(fp, true);
+ FUNLOCKFILE(fp);
+
+ return (r);
+}
diff --git a/lib/libc/stdio/fcloseall.c b/lib/libc/stdio/fcloseall.c
new file mode 100644
index 000000000000..8ee9a6227b79
--- /dev/null
+++ b/lib/libc/stdio/fcloseall.c
@@ -0,0 +1,39 @@
+/*-
+ * Copyright (C) 2006 Daniel M. Eischen. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include "local.h"
+
+__weak_reference(__fcloseall, fcloseall);
+
+void
+__fcloseall(void)
+{
+
+ (void)_fwalk(fclose);
+}
diff --git a/lib/libc/stdio/fdopen.c b/lib/libc/stdio/fdopen.c
new file mode 100644
index 000000000000..fbe37e881428
--- /dev/null
+++ b/lib/libc/stdio/fdopen.c
@@ -0,0 +1,105 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)fdopen.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <limits.h>
+#include "un-namespace.h"
+#include "local.h"
+
+FILE *
+fdopen(int fd, const char *mode)
+{
+ FILE *fp;
+ int flags, oflags, fdflags, tmp;
+
+ /*
+ * File descriptors are a full int, but _file is only a short.
+ * If we get a valid file descriptor that is greater than
+ * SHRT_MAX, then the fd will get sign-extended into an
+ * invalid file descriptor. Handle this case by failing the
+ * open.
+ */
+ if (fd > SHRT_MAX) {
+ errno = EMFILE;
+ return (NULL);
+ }
+
+ if ((flags = __sflags(mode, &oflags)) == 0)
+ return (NULL);
+
+ /* Make sure the mode the user wants is a subset of the actual mode. */
+ if ((fdflags = _fcntl(fd, F_GETFL, 0)) < 0)
+ return (NULL);
+ /* Work around incorrect O_ACCMODE. */
+ tmp = fdflags & (O_ACCMODE | O_EXEC);
+ if (tmp != O_RDWR && (tmp != (oflags & O_ACCMODE))) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ if ((fp = __sfp()) == NULL)
+ return (NULL);
+
+ if ((oflags & O_CLOEXEC) && _fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) {
+ fp->_flags = 0;
+ return (NULL);
+ }
+
+ fp->_flags = flags;
+ /*
+ * If opened for appending, but underlying descriptor does not have
+ * O_APPEND bit set, assert __SAPP so that __swrite() caller
+ * will _sseek() to the end before write.
+ */
+ if (fdflags & O_APPEND)
+ fp->_flags2 |= __S2OAP;
+ else if (oflags & O_APPEND)
+ fp->_flags |= __SAPP;
+ fp->_file = fd;
+ fp->_cookie = fp;
+ fp->_read = __sread;
+ fp->_write = __swrite;
+ fp->_seek = __sseek;
+ fp->_close = __sclose;
+ return (fp);
+}
diff --git a/lib/libc/stdio/feof.c b/lib/libc/stdio/feof.c
new file mode 100644
index 000000000000..b970248a3128
--- /dev/null
+++ b/lib/libc/stdio/feof.c
@@ -0,0 +1,63 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)feof.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <stdio.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+
+#undef feof
+#undef feof_unlocked
+
+int
+feof(FILE *fp)
+{
+ int ret;
+
+ FLOCKFILE(fp);
+ ret= __sfeof(fp);
+ FUNLOCKFILE(fp);
+ return (ret);
+}
+
+int
+feof_unlocked(FILE *fp)
+{
+
+ return (__sfeof(fp));
+}
diff --git a/lib/libc/stdio/ferror.3 b/lib/libc/stdio/ferror.3
new file mode 100644
index 000000000000..043b6883ac67
--- /dev/null
+++ b/lib/libc/stdio/ferror.3
@@ -0,0 +1,131 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek and the American National Standards Committee X3,
+.\" on Information Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)ferror.3 8.2 (Berkeley) 4/19/94
+.\" $FreeBSD$
+.\"
+.Dd January 28, 2009
+.Dt FERROR 3
+.Os
+.Sh NAME
+.Nm clearerr ,
+.Nm clearerr_unlocked ,
+.Nm feof ,
+.Nm feof_unlocked ,
+.Nm ferror ,
+.Nm ferror_unlocked ,
+.Nm fileno ,
+.Nm fileno_unlocked
+.Nd check and reset stream status
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdio.h
+.Ft void
+.Fn clearerr "FILE *stream"
+.Ft void
+.Fn clearerr_unlocked "FILE *stream"
+.Ft int
+.Fn feof "FILE *stream"
+.Ft int
+.Fn feof_unlocked "FILE *stream"
+.Ft int
+.Fn ferror "FILE *stream"
+.Ft int
+.Fn ferror_unlocked "FILE *stream"
+.Ft int
+.Fn fileno "FILE *stream"
+.Ft int
+.Fn fileno_unlocked "FILE *stream"
+.Sh DESCRIPTION
+The function
+.Fn clearerr
+clears the end-of-file and error indicators for the stream pointed
+to by
+.Fa stream .
+.Pp
+The function
+.Fn feof
+tests the end-of-file indicator for the stream pointed to by
+.Fa stream ,
+returning non-zero if it is set.
+The end-of-file indicator may be cleared by explicitly calling
+.Fn clearerr ,
+or as a side-effect of other operations, e.g.\&
+.Fn fseek .
+.Pp
+The function
+.Fn ferror
+tests the error indicator for the stream pointed to by
+.Fa stream ,
+returning non-zero if it is set.
+.Pp
+The function
+.Fn fileno
+examines the argument
+.Fa stream
+and returns its integer descriptor.
+.Pp
+The
+.Fn clearerr_unlocked ,
+.Fn feof_unlocked ,
+.Fn ferror_unlocked ,
+and
+.Fn fileno_unlocked
+functions are equivalent to
+.Fn clearerr ,
+.Fn feof ,
+.Fn ferror ,
+and
+.Fn fileno
+respectively, except that the caller is responsible for locking the stream
+with
+.Xr flockfile 3
+before calling them.
+These functions may be used to avoid the overhead of locking the stream
+and to prevent races when multiple threads are operating on the same stream.
+.Sh ERRORS
+These functions should not fail and do not set the external
+variable
+.Va errno .
+.Sh SEE ALSO
+.Xr open 2 ,
+.Xr fdopen 3 ,
+.Xr flockfile 3 ,
+.Xr stdio 3
+.Sh STANDARDS
+The functions
+.Fn clearerr ,
+.Fn feof ,
+and
+.Fn ferror
+conform to
+.St -isoC .
diff --git a/lib/libc/stdio/ferror.c b/lib/libc/stdio/ferror.c
new file mode 100644
index 000000000000..7e0f8f957165
--- /dev/null
+++ b/lib/libc/stdio/ferror.c
@@ -0,0 +1,63 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)ferror.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <stdio.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+
+#undef ferror
+#undef ferror_unlocked
+
+int
+ferror(FILE *fp)
+{
+ int ret;
+
+ FLOCKFILE(fp);
+ ret = __sferror(fp);
+ FUNLOCKFILE(fp);
+ return (ret);
+}
+
+int
+ferror_unlocked(FILE *fp)
+{
+
+ return (__sferror(fp));
+}
diff --git a/lib/libc/stdio/fflush.3 b/lib/libc/stdio/fflush.3
new file mode 100644
index 000000000000..1c04103a7161
--- /dev/null
+++ b/lib/libc/stdio/fflush.3
@@ -0,0 +1,111 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek and the American National Standards Committee X3,
+.\" on Information Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)fflush.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt FFLUSH 3
+.Os
+.Sh NAME
+.Nm fflush ,
+.Nm fpurge
+.Nd flush a stream
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdio.h
+.Ft int
+.Fn fflush "FILE *stream"
+.Ft int
+.Fn fpurge "FILE *stream"
+.Sh DESCRIPTION
+The function
+.Fn fflush
+forces a write of all buffered data for the given output or update
+.Fa stream
+via the stream's underlying write function.
+The open status of the stream is unaffected.
+.Pp
+If the
+.Fa stream
+argument is
+.Dv NULL ,
+.Fn fflush
+flushes
+.Em all
+open output streams.
+.Pp
+The function
+.Fn fpurge
+erases any input or output buffered in the given
+.Fa stream .
+For output streams this discards any unwritten output.
+For input streams this discards any input read from the underlying object
+but not yet obtained via
+.Xr getc 3 ;
+this includes any text pushed back via
+.Xr ungetc 3 .
+.Sh RETURN VALUES
+Upon successful completion 0 is returned.
+Otherwise,
+.Dv EOF
+is returned and the global variable
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa stream
+argument
+is not an open stream, or, in the case of
+.Fn fflush ,
+not a stream open for writing.
+.El
+.Pp
+The function
+.Fn fflush
+may also fail and set
+.Va errno
+for any of the errors specified for the routine
+.Xr write 2 .
+.Sh SEE ALSO
+.Xr write 2 ,
+.Xr fclose 3 ,
+.Xr fopen 3 ,
+.Xr setbuf 3
+.Sh STANDARDS
+The
+.Fn fflush
+function
+conforms to
+.St -isoC .
diff --git a/lib/libc/stdio/fflush.c b/lib/libc/stdio/fflush.c
new file mode 100644
index 000000000000..123167a09129
--- /dev/null
+++ b/lib/libc/stdio/fflush.c
@@ -0,0 +1,150 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)fflush.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <errno.h>
+#include <stdio.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+#include "local.h"
+
+static int sflush_locked(FILE *);
+
+/*
+ * Flush a single file, or (if fp is NULL) all files.
+ * MT-safe version
+ */
+int
+fflush(FILE *fp)
+{
+ int retval;
+
+ if (fp == NULL)
+ return (_fwalk(sflush_locked));
+ FLOCKFILE(fp);
+
+ /*
+ * There is disagreement about the correct behaviour of fflush()
+ * when passed a file which is not open for writing. According to
+ * the ISO C standard, the behaviour is undefined.
+ * Under linux, such an fflush returns success and has no effect;
+ * under Windows, such an fflush is documented as behaving instead
+ * as fpurge().
+ * Given that applications may be written with the expectation of
+ * either of these two behaviours, the only safe (non-astonishing)
+ * option is to return EBADF and ask that applications be fixed.
+ * SUSv3 now requires that fflush() returns success on a read-only
+ * stream.
+ *
+ */
+ if ((fp->_flags & (__SWR | __SRW)) == 0)
+ retval = 0;
+ else
+ retval = __sflush(fp);
+ FUNLOCKFILE(fp);
+ return (retval);
+}
+
+/*
+ * Flush a single file, or (if fp is NULL) all files.
+ * Non-MT-safe version
+ */
+int
+__fflush(FILE *fp)
+{
+ int retval;
+
+ if (fp == NULL)
+ return (_fwalk(sflush_locked));
+ if ((fp->_flags & (__SWR | __SRW)) == 0)
+ retval = 0;
+ else
+ retval = __sflush(fp);
+ return (retval);
+}
+
+int
+__sflush(FILE *fp)
+{
+ unsigned char *p;
+ int n, t;
+
+ t = fp->_flags;
+ if ((t & __SWR) == 0)
+ return (0);
+
+ if ((p = fp->_bf._base) == NULL)
+ return (0);
+
+ n = fp->_p - p; /* write this much */
+
+ /*
+ * Set these immediately to avoid problems with longjmp and to allow
+ * exchange buffering (via setvbuf) in user write function.
+ */
+ fp->_p = p;
+ fp->_w = t & (__SLBF|__SNBF) ? 0 : fp->_bf._size;
+
+ for (; n > 0; n -= t, p += t) {
+ t = _swrite(fp, (char *)p, n);
+ if (t <= 0) {
+ /* Reset _p and _w. */
+ if (p > fp->_p) {
+ /* Some was written. */
+ memmove(fp->_p, p, n);
+ fp->_p += n;
+ if ((fp->_flags & (__SLBF | __SNBF)) == 0)
+ fp->_w -= n;
+ }
+ fp->_flags |= __SERR;
+ return (EOF);
+ }
+ }
+ return (0);
+}
+
+static int
+sflush_locked(FILE *fp)
+{
+ int ret;
+
+ FLOCKFILE(fp);
+ ret = __sflush(fp);
+ FUNLOCKFILE(fp);
+ return (ret);
+}
diff --git a/lib/libc/stdio/fgetc.c b/lib/libc/stdio/fgetc.c
new file mode 100644
index 000000000000..2ee4d7a78cb5
--- /dev/null
+++ b/lib/libc/stdio/fgetc.c
@@ -0,0 +1,55 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)fgetc.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <stdio.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+#include "local.h"
+
+int
+fgetc(FILE *fp)
+{
+ int retval;
+ FLOCKFILE(fp);
+ /* Orientation set by __sgetc() when buffer is empty. */
+ /* ORIENT(fp, -1); */
+ retval = __sgetc(fp);
+ FUNLOCKFILE(fp);
+ return (retval);
+}
diff --git a/lib/libc/stdio/fgetln.3 b/lib/libc/stdio/fgetln.3
new file mode 100644
index 000000000000..7d4b89a5a06f
--- /dev/null
+++ b/lib/libc/stdio/fgetln.3
@@ -0,0 +1,128 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)fgetln.3 8.3 (Berkeley) 4/19/94
+.\" $FreeBSD$
+.\"
+.Dd February 15, 2016
+.Dt FGETLN 3
+.Os
+.Sh NAME
+.Nm fgetln
+.Nd get a line from a stream
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdio.h
+.Ft char *
+.Fn fgetln "FILE *stream" "size_t *len"
+.Sh DESCRIPTION
+The
+.Fn fgetln
+function
+returns a pointer to the next line from the stream referenced by
+.Fa stream .
+This line is
+.Em not
+a C string as it does not end with a terminating
+.Dv NUL
+character.
+The length of the line, including the final newline,
+is stored in the memory location to which
+.Fa len
+points.
+(Note, however, that if the line is the last
+in a file that does not end in a newline,
+the returned text will not contain a newline.)
+.Sh RETURN VALUES
+Upon successful completion a pointer is returned;
+this pointer becomes invalid after the next
+.Tn I/O
+operation on
+.Fa stream
+(whether successful or not)
+or as soon as the stream is closed.
+Otherwise,
+.Dv NULL
+is returned.
+The
+.Fn fgetln
+function
+does not distinguish between end-of-file and error; the routines
+.Xr feof 3
+and
+.Xr ferror 3
+must be used
+to determine which occurred.
+If an error occurs, the global variable
+.Va errno
+is set to indicate the error.
+The end-of-file condition is remembered, even on a terminal, and all
+subsequent attempts to read will return
+.Dv NULL
+until the condition is
+cleared with
+.Xr clearerr 3 .
+.Pp
+The text to which the returned pointer points may be modified,
+provided that no changes are made beyond the returned size.
+These changes are lost as soon as the pointer becomes invalid.
+.Sh ERRORS
+.Bl -tag -width Er
+.It Bq Er EBADF
+The argument
+.Fa stream
+is not a stream open for reading.
+.It Bq Er ENOMEM
+The internal line buffer could not be expanded due to lack of available memory,
+or because it would need to expand beyond INT_MAX in size.
+.El
+.Pp
+The
+.Fn fgetln
+function
+may also fail and set
+.Va errno
+for any of the errors specified for the routines
+.Xr fflush 3 ,
+.Xr malloc 3 ,
+.Xr read 2 ,
+.Xr stat 2 ,
+or
+.Xr realloc 3 .
+.Sh SEE ALSO
+.Xr ferror 3 ,
+.Xr fgets 3 ,
+.Xr fgetwln 3 ,
+.Xr fopen 3 ,
+.Xr getline 3 ,
+.Xr putc 3
+.Sh HISTORY
+The
+.Fn fgetln
+function first appeared in
+.Bx 4.4 .
diff --git a/lib/libc/stdio/fgetln.c b/lib/libc/stdio/fgetln.c
new file mode 100644
index 000000000000..c8e30ee2bf65
--- /dev/null
+++ b/lib/libc/stdio/fgetln.c
@@ -0,0 +1,174 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)fgetln.c 8.2 (Berkeley) 1/2/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+#include "local.h"
+
+/*
+ * Expand the line buffer. Return -1 on error.
+#ifdef notdef
+ * The `new size' does not account for a terminating '\0',
+ * so we add 1 here.
+#endif
+ */
+int
+__slbexpand(FILE *fp, size_t newsize)
+{
+ void *p;
+
+#ifdef notdef
+ ++newsize;
+#endif
+ if (fp->_lb._size >= newsize)
+ return (0);
+ if (newsize > INT_MAX) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ if ((p = realloc(fp->_lb._base, newsize)) == NULL)
+ return (-1);
+ fp->_lb._base = p;
+ fp->_lb._size = newsize;
+ return (0);
+}
+
+/*
+ * Get an input line. The returned pointer often (but not always)
+ * points into a stdio buffer. Fgetln does not alter the text of
+ * the returned line (which is thus not a C string because it will
+ * not necessarily end with '\0'), but does allow callers to modify
+ * it if they wish. Thus, we set __SMOD in case the caller does.
+ */
+char *
+fgetln(FILE *fp, size_t *lenp)
+{
+ unsigned char *p;
+ size_t len;
+ size_t off;
+
+ FLOCKFILE(fp);
+ ORIENT(fp, -1);
+ /* make sure there is input */
+ if (fp->_r <= 0 && __srefill(fp)) {
+ *lenp = 0;
+ FUNLOCKFILE(fp);
+ return (NULL);
+ }
+
+ /* look for a newline in the input */
+ if ((p = memchr((void *)fp->_p, '\n', (size_t)fp->_r)) != NULL) {
+ char *ret;
+
+ /*
+ * Found one. Flag buffer as modified to keep fseek from
+ * `optimising' a backward seek, in case the user stomps on
+ * the text.
+ */
+ p++; /* advance over it */
+ ret = (char *)fp->_p;
+ *lenp = len = p - fp->_p;
+ fp->_flags |= __SMOD;
+ fp->_r -= len;
+ fp->_p = p;
+ FUNLOCKFILE(fp);
+ return (ret);
+ }
+
+ /*
+ * We have to copy the current buffered data to the line buffer.
+ * As a bonus, though, we can leave off the __SMOD.
+ *
+ * OPTIMISTIC is length that we (optimistically) expect will
+ * accommodate the `rest' of the string, on each trip through the
+ * loop below.
+ */
+#define OPTIMISTIC 80
+
+ for (len = fp->_r, off = 0;; len += fp->_r) {
+ size_t diff;
+
+ /*
+ * Make sure there is room for more bytes. Copy data from
+ * file buffer to line buffer, refill file and look for
+ * newline. The loop stops only when we find a newline.
+ */
+ if (__slbexpand(fp, len + OPTIMISTIC))
+ goto error;
+ (void)memcpy((void *)(fp->_lb._base + off), (void *)fp->_p,
+ len - off);
+ off = len;
+ if (__srefill(fp)) {
+ if (__sfeof(fp))
+ break;
+ goto error;
+ }
+ if ((p = memchr((void *)fp->_p, '\n', (size_t)fp->_r)) == NULL)
+ continue;
+
+ /* got it: finish up the line (like code above) */
+ p++;
+ diff = p - fp->_p;
+ len += diff;
+ if (__slbexpand(fp, len))
+ goto error;
+ (void)memcpy((void *)(fp->_lb._base + off), (void *)fp->_p,
+ diff);
+ fp->_r -= diff;
+ fp->_p = p;
+ break;
+ }
+ *lenp = len;
+#ifdef notdef
+ fp->_lb._base[len] = '\0';
+#endif
+ FUNLOCKFILE(fp);
+ return ((char *)fp->_lb._base);
+
+error:
+ *lenp = 0; /* ??? */
+ fp->_flags |= __SERR;
+ FUNLOCKFILE(fp);
+ return (NULL); /* ??? */
+}
diff --git a/lib/libc/stdio/fgetpos.c b/lib/libc/stdio/fgetpos.c
new file mode 100644
index 000000000000..f161f4325fd3
--- /dev/null
+++ b/lib/libc/stdio/fgetpos.c
@@ -0,0 +1,51 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)fgetpos.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+
+int
+fgetpos(FILE * __restrict fp, fpos_t * __restrict pos)
+{
+ /*
+ * ftello is thread-safe; no need to lock fp.
+ */
+ if ((*pos = ftello(fp)) == (fpos_t)-1)
+ return (-1);
+ else
+ return (0);
+}
diff --git a/lib/libc/stdio/fgets.3 b/lib/libc/stdio/fgets.3
new file mode 100644
index 000000000000..278e18c4bb8c
--- /dev/null
+++ b/lib/libc/stdio/fgets.3
@@ -0,0 +1,156 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek and the American National Standards Committee X3,
+.\" on Information Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)fgets.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd May 5, 2012
+.Dt FGETS 3
+.Os
+.Sh NAME
+.Nm fgets ,
+.Nm gets
+.Nd get a line from a stream
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdio.h
+.Ft char *
+.Fn fgets "char * restrict str" "int size" "FILE * restrict stream"
+.Ft char *
+.Fn gets "char *str"
+.Sh DESCRIPTION
+The
+.Fn fgets
+function
+reads at most one less than the number of characters specified by
+.Fa size
+from the given
+.Fa stream
+and stores them in the string
+.Fa str .
+Reading stops when a newline character is found,
+at end-of-file or error.
+The newline, if any, is retained.
+If any characters are read and there is no error, a
+.Ql \e0
+character is appended to end the string.
+.Pp
+The
+.Fn gets
+function
+is equivalent to
+.Fn fgets
+with an infinite
+.Fa size
+and a
+.Fa stream
+of
+.Dv stdin ,
+except that the newline character (if any) is not stored in the string.
+It is the caller's responsibility to ensure that the input line,
+if any, is sufficiently short to fit in the string.
+.Sh RETURN VALUES
+Upon successful completion,
+.Fn fgets
+and
+.Fn gets
+return
+a pointer to the string.
+If end-of-file occurs before any characters are read,
+they return
+.Dv NULL
+and the buffer contents remain unchanged.
+If an error occurs,
+they return
+.Dv NULL
+and the buffer contents are indeterminate.
+The
+.Fn fgets
+and
+.Fn gets
+functions
+do not distinguish between end-of-file and error, and callers must use
+.Xr feof 3
+and
+.Xr ferror 3
+to determine which occurred.
+.Sh ERRORS
+.Bl -tag -width Er
+.It Bq Er EBADF
+The given
+.Fa stream
+is not a readable stream.
+.El
+.Pp
+The function
+.Fn fgets
+may also fail and set
+.Va errno
+for any of the errors specified for the routines
+.Xr fflush 3 ,
+.Xr fstat 2 ,
+.Xr read 2 ,
+or
+.Xr malloc 3 .
+.Pp
+The function
+.Fn gets
+may also fail and set
+.Va errno
+for any of the errors specified for the routine
+.Xr getchar 3 .
+.Sh SEE ALSO
+.Xr feof 3 ,
+.Xr ferror 3 ,
+.Xr fgetln 3 ,
+.Xr fgetws 3 ,
+.Xr getline 3
+.Sh STANDARDS
+The functions
+.Fn fgets
+and
+.Fn gets
+conform to
+.St -isoC-99 .
+.Sh SECURITY CONSIDERATIONS
+The
+.Fn gets
+function cannot be used securely.
+Because of its lack of bounds checking,
+and the inability for the calling program
+to reliably determine the length of the next incoming line,
+the use of this function enables malicious users
+to arbitrarily change a running program's functionality through
+a buffer overflow attack.
+It is strongly suggested that the
+.Fn fgets
+function be used in all cases.
diff --git a/lib/libc/stdio/fgets.c b/lib/libc/stdio/fgets.c
new file mode 100644
index 000000000000..a2e39ed3b337
--- /dev/null
+++ b/lib/libc/stdio/fgets.c
@@ -0,0 +1,115 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)fgets.c 8.2 (Berkeley) 12/22/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include "un-namespace.h"
+#include "local.h"
+#include "libc_private.h"
+
+/*
+ * Read at most n-1 characters from the given file.
+ * Stop when a newline has been read, or the count runs out.
+ * Return first argument, or NULL if no characters were read.
+ */
+char *
+fgets(char * __restrict buf, int n, FILE * __restrict fp)
+{
+ size_t len;
+ char *s;
+ unsigned char *p, *t;
+
+ FLOCKFILE(fp);
+ ORIENT(fp, -1);
+
+ if (n <= 0) { /* sanity check */
+ fp->_flags |= __SERR;
+ errno = EINVAL;
+ FUNLOCKFILE(fp);
+ return (NULL);
+ }
+
+ s = buf;
+ n--; /* leave space for NUL */
+ while (n != 0) {
+ /*
+ * If the buffer is empty, refill it.
+ */
+ if ((len = fp->_r) <= 0) {
+ if (__srefill(fp)) {
+ /* EOF/error: stop with partial or no line */
+ if (!__sfeof(fp) || s == buf) {
+ FUNLOCKFILE(fp);
+ return (NULL);
+ }
+ break;
+ }
+ len = fp->_r;
+ }
+ p = fp->_p;
+
+ /*
+ * Scan through at most n bytes of the current buffer,
+ * looking for '\n'. If found, copy up to and including
+ * newline, and stop. Otherwise, copy entire chunk
+ * and loop.
+ */
+ if (len > n)
+ len = n;
+ t = memchr((void *)p, '\n', len);
+ if (t != NULL) {
+ len = ++t - p;
+ fp->_r -= len;
+ fp->_p = t;
+ (void)memcpy((void *)s, (void *)p, len);
+ s[len] = 0;
+ FUNLOCKFILE(fp);
+ return (buf);
+ }
+ fp->_r -= len;
+ fp->_p += len;
+ (void)memcpy((void *)s, (void *)p, len);
+ s += len;
+ n -= len;
+ }
+ *s = 0;
+ FUNLOCKFILE(fp);
+ return (buf);
+}
diff --git a/lib/libc/stdio/fgetwc.c b/lib/libc/stdio/fgetwc.c
new file mode 100644
index 000000000000..3074d441f9f6
--- /dev/null
+++ b/lib/libc/stdio/fgetwc.c
@@ -0,0 +1,109 @@
+/*-
+ * Copyright (c) 2002-2004 Tim J. Robbins.
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 "namespace.h"
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+#include "local.h"
+#include "mblocal.h"
+#include "xlocale_private.h"
+
+/*
+ * MT-safe version.
+ */
+wint_t
+fgetwc_l(FILE *fp, locale_t locale)
+{
+ wint_t r;
+ FIX_LOCALE(locale);
+
+ FLOCKFILE(fp);
+ ORIENT(fp, 1);
+ r = __fgetwc(fp, locale);
+ FUNLOCKFILE(fp);
+
+ return (r);
+}
+
+wint_t
+fgetwc(FILE *fp)
+{
+ return fgetwc_l(fp, __get_locale());
+}
+
+/*
+ * Internal (non-MPSAFE) version of fgetwc(). This version takes an
+ * mbstate_t argument specifying the initial conversion state. For
+ * wide streams, this should always be fp->_mbstate. On return, *nread
+ * is set to the number of bytes read.
+ */
+wint_t
+__fgetwc_mbs(FILE *fp, mbstate_t *mbs, int *nread, locale_t locale)
+{
+ wchar_t wc;
+ size_t nconv;
+ struct xlocale_ctype *l = XLOCALE_CTYPE(locale);
+
+ *nread = 0;
+ if (fp->_r <= 0 && __srefill(fp))
+ return (WEOF);
+ do {
+ nconv = l->__mbrtowc(&wc, fp->_p, fp->_r, mbs);
+ if (nconv == (size_t)-1) {
+ fp->_flags |= __SERR;
+ return (WEOF);
+ } else if (nconv == (size_t)-2)
+ continue;
+ else if (nconv == 0) {
+ fp->_p++;
+ fp->_r--;
+ (*nread)++;
+ return (L'\0');
+ } else {
+ fp->_p += nconv;
+ fp->_r -= nconv;
+ *nread += nconv;
+ return (wc);
+ }
+ } while (__srefill(fp) == 0);
+ if (__sfeof(fp)) {
+ fp->_flags |= __SERR;
+ errno = EILSEQ;
+ }
+ return (WEOF);
+}
diff --git a/lib/libc/stdio/fgetwln.3 b/lib/libc/stdio/fgetwln.3
new file mode 100644
index 000000000000..b1594e26c8b5
--- /dev/null
+++ b/lib/libc/stdio/fgetwln.3
@@ -0,0 +1,116 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)fgetln.3 8.3 (Berkeley) 4/19/94
+.\" $FreeBSD$
+.\"
+.Dd July 16, 2004
+.Dt FGETWLN 3
+.Os
+.Sh NAME
+.Nm fgetwln
+.Nd get a line of wide characters from a stream
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdio.h
+.In wchar.h
+.Ft wchar_t *
+.Fn fgetwln "FILE * restrict stream" "size_t * restrict len"
+.Sh DESCRIPTION
+The
+.Fn fgetwln
+function
+returns a pointer to the next line from the stream referenced by
+.Fa stream .
+This line is
+.Em not
+a standard wide character string as it does not end with a terminating
+null wide character.
+The length of the line, including the final newline,
+is stored in the memory location to which
+.Fa len
+points.
+(Note, however, that if the line is the last
+in a file that does not end in a newline,
+the returned text will not contain a newline.)
+.Sh RETURN VALUES
+Upon successful completion a pointer is returned;
+this pointer becomes invalid after the next
+.Tn I/O
+operation on
+.Fa stream
+(whether successful or not)
+or as soon as the stream is closed.
+Otherwise,
+.Dv NULL
+is returned.
+The
+.Fn fgetwln
+function
+does not distinguish between end-of-file and error; the routines
+.Xr feof 3
+and
+.Xr ferror 3
+must be used
+to determine which occurred.
+If an error occurs, the global variable
+.Va errno
+is set to indicate the error.
+The end-of-file condition is remembered, even on a terminal, and all
+subsequent attempts to read will return
+.Dv NULL
+until the condition is
+cleared with
+.Xr clearerr 3 .
+.Pp
+The text to which the returned pointer points may be modified,
+provided that no changes are made beyond the returned size.
+These changes are lost as soon as the pointer becomes invalid.
+.Sh ERRORS
+.Bl -tag -width Er
+.It Bq Er EBADF
+The argument
+.Fa stream
+is not a stream open for reading.
+.El
+.Pp
+The
+.Fn fgetwln
+function
+may also fail and set
+.Va errno
+for any of the errors specified for the routines
+.Xr mbrtowc 3 ,
+.Xr realloc 3 ,
+or
+.Xr read 2 .
+.Sh SEE ALSO
+.Xr ferror 3 ,
+.Xr fgetln 3 ,
+.Xr fgetws 3 ,
+.Xr fopen 3
diff --git a/lib/libc/stdio/fgetwln.c b/lib/libc/stdio/fgetwln.c
new file mode 100644
index 000000000000..037657c224b0
--- /dev/null
+++ b/lib/libc/stdio/fgetwln.c
@@ -0,0 +1,94 @@
+/*-
+ * Copyright (c) 2002-2004 Tim J. Robbins.
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 "namespace.h"
+#include <stdio.h>
+#include <wchar.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+#include "local.h"
+#include "xlocale_private.h"
+
+wchar_t *fgetwln_l(FILE * __restrict, size_t *, locale_t);
+
+wchar_t *
+fgetwln_l(FILE * __restrict fp, size_t *lenp, locale_t locale)
+{
+ wint_t wc;
+ size_t len;
+ int savserr;
+
+ FIX_LOCALE(locale);
+
+ FLOCKFILE(fp);
+ ORIENT(fp, 1);
+
+ savserr = fp->_flags & __SERR;
+ fp->_flags &= ~__SERR;
+
+ len = 0;
+ while ((wc = __fgetwc(fp, locale)) != WEOF) {
+#define GROW 512
+ if (len * sizeof(wchar_t) >= fp->_lb._size &&
+ __slbexpand(fp, (len + GROW) * sizeof(wchar_t))) {
+ fp->_flags |= __SERR;
+ goto error;
+ }
+ *((wchar_t *)fp->_lb._base + len++) = wc;
+ if (wc == L'\n')
+ break;
+ }
+ /* fgetwc(3) may set both __SEOF and __SERR at once. */
+ if (__sferror(fp))
+ goto error;
+
+ fp->_flags |= savserr;
+ if (len == 0)
+ goto error;
+
+ FUNLOCKFILE(fp);
+ *lenp = len;
+ return ((wchar_t *)fp->_lb._base);
+
+error:
+ FUNLOCKFILE(fp);
+ *lenp = 0;
+ return (NULL);
+}
+
+wchar_t *
+fgetwln(FILE * __restrict fp, size_t *lenp)
+{
+ return fgetwln_l(fp, lenp, __get_locale());
+}
diff --git a/lib/libc/stdio/fgetws.3 b/lib/libc/stdio/fgetws.3
new file mode 100644
index 000000000000..5397a100aec1
--- /dev/null
+++ b/lib/libc/stdio/fgetws.3
@@ -0,0 +1,121 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek and the American National Standards Committee X3,
+.\" on Information Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)fgets.3 8.1 (Berkeley) 6/4/93
+.\" FreeBSD: src/lib/libc/stdio/fgets.3,v 1.16 2002/05/31 05:01:17 archie Exp
+.\" $FreeBSD$
+.\"
+.Dd August 6, 2002
+.Dt FGETWS 3
+.Os
+.Sh NAME
+.Nm fgetws
+.Nd get a line of wide characters from a stream
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdio.h
+.In wchar.h
+.Ft "wchar_t *"
+.Fn fgetws "wchar_t * restrict ws" "int n" "FILE * restrict fp"
+.Sh DESCRIPTION
+The
+.Fn fgetws
+function
+reads at most one less than the number of characters specified by
+.Fa n
+from the given
+.Fa fp
+and stores them in the wide character string
+.Fa ws .
+Reading stops when a newline character is found,
+at end-of-file or error.
+The newline, if any, is retained.
+If any characters are read and there is no error, a
+.Ql \e0
+character is appended to end the string.
+.Sh RETURN VALUES
+Upon successful completion,
+.Fn fgetws
+returns
+.Fa ws .
+If end-of-file occurs before any characters are read,
+.Fn fgetws
+returns
+.Dv NULL
+and the buffer contents remain unchanged.
+If an error occurs,
+.Fn fgetws
+returns
+.Dv NULL
+and the buffer contents are indeterminate.
+The
+.Fn fgetws
+function
+does not distinguish between end-of-file and error, and callers must use
+.Xr feof 3
+and
+.Xr ferror 3
+to determine which occurred.
+.Sh ERRORS
+The
+.Fn fgetws
+function will fail if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The given
+.Fa fp
+argument is not a readable stream.
+.It Bq Er EILSEQ
+The data obtained from the input stream does not form a valid
+multibyte character.
+.El
+.Pp
+The function
+.Fn fgetws
+may also fail and set
+.Va errno
+for any of the errors specified for the routines
+.Xr fflush 3 ,
+.Xr fstat 2 ,
+.Xr read 2 ,
+or
+.Xr malloc 3 .
+.Sh SEE ALSO
+.Xr feof 3 ,
+.Xr ferror 3 ,
+.Xr fgets 3
+.Sh STANDARDS
+The
+.Fn fgetws
+function
+conforms to
+.St -p1003.1-2001 .
diff --git a/lib/libc/stdio/fgetws.c b/lib/libc/stdio/fgetws.c
new file mode 100644
index 000000000000..8513a372835b
--- /dev/null
+++ b/lib/libc/stdio/fgetws.c
@@ -0,0 +1,128 @@
+/*-
+ * Copyright (c) 2002-2004 Tim J. Robbins.
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 "namespace.h"
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <wchar.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+#include "local.h"
+#include "mblocal.h"
+
+wchar_t *
+fgetws_l(wchar_t * __restrict ws, int n, FILE * __restrict fp, locale_t locale)
+{
+ int sret;
+ wchar_t *wsp;
+ size_t nconv;
+ const char *src;
+ unsigned char *nl;
+ FIX_LOCALE(locale);
+ struct xlocale_ctype *l = XLOCALE_CTYPE(locale);
+
+ FLOCKFILE(fp);
+ ORIENT(fp, 1);
+
+ if (n <= 0) {
+ fp->_flags |= __SERR;
+ errno = EINVAL;
+ goto error;
+ }
+
+ wsp = ws;
+ if (n == 1)
+ goto ok;
+
+ if (fp->_r <= 0 && __srefill(fp))
+ /* EOF or ferror */
+ goto error;
+
+ sret = 0;
+ do {
+ src = fp->_p;
+ nl = memchr(fp->_p, '\n', fp->_r);
+ nconv = l->__mbsnrtowcs(wsp, &src,
+ nl != NULL ? (nl - fp->_p + 1) : fp->_r,
+ n - 1, &fp->_mbstate);
+ if (nconv == (size_t)-1) {
+ /* Conversion error */
+ fp->_flags |= __SERR;
+ goto error;
+ }
+ if (src == NULL) {
+ /*
+ * We hit a null byte. Increment the character count,
+ * since mbsnrtowcs()'s return value doesn't include
+ * the terminating null, then resume conversion
+ * after the null.
+ */
+ nconv++;
+ src = memchr(fp->_p, '\0', fp->_r);
+ src++;
+ }
+ fp->_r -= (unsigned char *)src - fp->_p;
+ fp->_p = (unsigned char *)src;
+ n -= nconv;
+ wsp += nconv;
+ } while ((wsp == ws || wsp[-1] != L'\n') && n > 1 && (fp->_r > 0 ||
+ (sret = __srefill(fp)) == 0));
+ if (sret && !__sfeof(fp))
+ /* ferror */
+ goto error;
+ if (!l->__mbsinit(&fp->_mbstate)) {
+ /* Incomplete character */
+ fp->_flags |= __SERR;
+ errno = EILSEQ;
+ goto error;
+ }
+ if (wsp == ws)
+ /* EOF */
+ goto error;
+ok:
+ *wsp = L'\0';
+ FUNLOCKFILE(fp);
+ return (ws);
+
+error:
+ FUNLOCKFILE(fp);
+ return (NULL);
+}
+
+wchar_t *
+fgetws(wchar_t * __restrict ws, int n, FILE * __restrict fp)
+{
+ return fgetws_l(ws, n, fp, __get_locale());
+}
diff --git a/lib/libc/stdio/fileno.c b/lib/libc/stdio/fileno.c
new file mode 100644
index 000000000000..3ac183010ef6
--- /dev/null
+++ b/lib/libc/stdio/fileno.c
@@ -0,0 +1,64 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)fileno.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <stdio.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+
+#undef fileno
+#undef fileno_unlocked
+
+int
+fileno(FILE *fp)
+{
+ int fd;
+
+ FLOCKFILE(fp);
+ fd = __sfileno(fp);
+ FUNLOCKFILE(fp);
+
+ return (fd);
+}
+
+int
+fileno_unlocked(FILE *fp)
+{
+
+ return (__sfileno(fp));
+}
diff --git a/lib/libc/stdio/findfp.c b/lib/libc/stdio/findfp.c
new file mode 100644
index 000000000000..5e1f06924ac8
--- /dev/null
+++ b/lib/libc/stdio/findfp.c
@@ -0,0 +1,219 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)findfp.c 8.2 (Berkeley) 1/4/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <machine/atomic.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <spinlock.h>
+
+#include "libc_private.h"
+#include "local.h"
+#include "glue.h"
+
+int __sdidinit;
+
+#define NDYNAMIC 10 /* add ten more whenever necessary */
+
+#define std(flags, file) { \
+ ._flags = (flags), \
+ ._file = (file), \
+ ._cookie = __sF + (file), \
+ ._close = __sclose, \
+ ._read = __sread, \
+ ._seek = __sseek, \
+ ._write = __swrite, \
+ ._fl_mutex = PTHREAD_MUTEX_INITIALIZER, \
+}
+ /* the usual - (stdin + stdout + stderr) */
+static FILE usual[FOPEN_MAX - 3];
+static struct glue uglue = { NULL, FOPEN_MAX - 3, usual };
+
+static FILE __sF[3] = {
+ std(__SRD, STDIN_FILENO),
+ std(__SWR, STDOUT_FILENO),
+ std(__SWR|__SNBF, STDERR_FILENO)
+};
+
+FILE *__stdinp = &__sF[0];
+FILE *__stdoutp = &__sF[1];
+FILE *__stderrp = &__sF[2];
+
+struct glue __sglue = { &uglue, 3, __sF };
+static struct glue *lastglue = &uglue;
+
+static struct glue * moreglue(int);
+
+spinlock_t __stdio_thread_lock = _SPINLOCK_INITIALIZER;
+
+#if NOT_YET
+#define SET_GLUE_PTR(ptr, val) atomic_set_rel_ptr(&(ptr), (uintptr_t)(val))
+#else
+#define SET_GLUE_PTR(ptr, val) ptr = val
+#endif
+
+static struct glue *
+moreglue(int n)
+{
+ struct glue *g;
+ static FILE empty = { ._fl_mutex = PTHREAD_MUTEX_INITIALIZER };
+ FILE *p;
+ size_t align;
+
+ align = __alignof__(FILE);
+ g = (struct glue *)malloc(sizeof(*g) + align + n * sizeof(FILE));
+ if (g == NULL)
+ return (NULL);
+ p = (FILE *)roundup((uintptr_t)(g + 1), align);
+ g->next = NULL;
+ g->niobs = n;
+ g->iobs = p;
+ while (--n >= 0)
+ *p++ = empty;
+ return (g);
+}
+
+/*
+ * Find a free FILE for fopen et al.
+ */
+FILE *
+__sfp(void)
+{
+ FILE *fp;
+ int n;
+ struct glue *g;
+
+ if (!__sdidinit)
+ __sinit();
+ /*
+ * The list must be locked because a FILE may be updated.
+ */
+ STDIO_THREAD_LOCK();
+ for (g = &__sglue; g != NULL; g = g->next) {
+ for (fp = g->iobs, n = g->niobs; --n >= 0; fp++)
+ if (fp->_flags == 0)
+ goto found;
+ }
+ STDIO_THREAD_UNLOCK(); /* don't hold lock while malloc()ing. */
+ if ((g = moreglue(NDYNAMIC)) == NULL)
+ return (NULL);
+ STDIO_THREAD_LOCK(); /* reacquire the lock */
+ SET_GLUE_PTR(lastglue->next, g); /* atomically append glue to list */
+ lastglue = g; /* not atomic; only accessed when locked */
+ fp = g->iobs;
+found:
+ fp->_flags = 1; /* reserve this slot; caller sets real flags */
+ STDIO_THREAD_UNLOCK();
+ fp->_p = NULL; /* no current pointer */
+ fp->_w = 0; /* nothing to read or write */
+ fp->_r = 0;
+ fp->_bf._base = NULL; /* no buffer */
+ fp->_bf._size = 0;
+ fp->_lbfsize = 0; /* not line buffered */
+ fp->_file = -1; /* no file */
+/* fp->_cookie = <any>; */ /* caller sets cookie, _read/_write etc */
+ fp->_ub._base = NULL; /* no ungetc buffer */
+ fp->_ub._size = 0;
+ fp->_lb._base = NULL; /* no line buffer */
+ fp->_lb._size = 0;
+/* fp->_fl_mutex = NULL; */ /* once set always set (reused) */
+ fp->_orientation = 0;
+ memset(&fp->_mbstate, 0, sizeof(mbstate_t));
+ fp->_flags2 = 0;
+ return (fp);
+}
+
+/*
+ * XXX. Force immediate allocation of internal memory. Not used by stdio,
+ * but documented historically for certain applications. Bad applications.
+ */
+__warn_references(f_prealloc,
+ "warning: this program uses f_prealloc(), which is not recommended.");
+void f_prealloc(void);
+
+void
+f_prealloc(void)
+{
+ struct glue *g;
+ int n;
+
+ n = getdtablesize() - FOPEN_MAX + 20; /* 20 for slop. */
+ /*
+ * It should be safe to walk the list without locking it;
+ * new nodes are only added to the end and none are ever
+ * removed.
+ */
+ for (g = &__sglue; (n -= g->niobs) > 0 && g->next; g = g->next)
+ /* void */;
+ if ((n > 0) && ((g = moreglue(n)) != NULL)) {
+ STDIO_THREAD_LOCK();
+ SET_GLUE_PTR(lastglue->next, g);
+ lastglue = g;
+ STDIO_THREAD_UNLOCK();
+ }
+}
+
+/*
+ * exit() calls _cleanup() through *__cleanup, set whenever we
+ * open or buffer a file. This chicanery is done so that programs
+ * that do not use stdio need not link it all in.
+ *
+ * The name `_cleanup' is, alas, fairly well known outside stdio.
+ */
+void
+_cleanup(void)
+{
+ /* (void) _fwalk(fclose); */
+ (void) _fwalk(__sflush); /* `cheating' */
+}
+
+/*
+ * __sinit() is called whenever stdio's internal variables must be set up.
+ */
+void
+__sinit(void)
+{
+
+ /* Make sure we clean up on exit. */
+ __cleanup = _cleanup; /* conservative */
+ __sdidinit = 1;
+}
diff --git a/lib/libc/stdio/flags.c b/lib/libc/stdio/flags.c
new file mode 100644
index 000000000000..9eed6d7dc8c7
--- /dev/null
+++ b/lib/libc/stdio/flags.c
@@ -0,0 +1,117 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)flags.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/file.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include "local.h"
+
+/*
+ * Return the (stdio) flags for a given mode. Store the flags
+ * to be passed to an _open() syscall through *optr.
+ * Return 0 on error.
+ */
+int
+__sflags(const char *mode, int *optr)
+{
+ int ret, m, o, known;
+
+ switch (*mode++) {
+
+ case 'r': /* open for reading */
+ ret = __SRD;
+ m = O_RDONLY;
+ o = 0;
+ break;
+
+ case 'w': /* open for writing */
+ ret = __SWR;
+ m = O_WRONLY;
+ o = O_CREAT | O_TRUNC;
+ break;
+
+ case 'a': /* open for appending */
+ ret = __SWR;
+ m = O_WRONLY;
+ o = O_CREAT | O_APPEND;
+ break;
+
+ default: /* illegal mode */
+ errno = EINVAL;
+ return (0);
+ }
+
+ do {
+ known = 1;
+ switch (*mode++) {
+ case 'b':
+ /* 'b' (binary) is ignored */
+ break;
+ case '+':
+ /* [rwa][b]\+ means read and write */
+ ret = __SRW;
+ m = O_RDWR;
+ break;
+ case 'x':
+ /* 'x' means exclusive (fail if the file exists) */
+ o |= O_EXCL;
+ break;
+ case 'e':
+ /* set close-on-exec */
+ o |= O_CLOEXEC;
+ break;
+ case 'v':
+ /* verify */
+ o |= O_VERIFY;
+ break;
+ default:
+ known = 0;
+ break;
+ }
+ } while (known);
+
+ if ((o & O_EXCL) != 0 && m == O_RDONLY) {
+ errno = EINVAL;
+ return (0);
+ }
+
+ *optr = m | o;
+ return (ret);
+}
diff --git a/lib/libc/stdio/floatio.h b/lib/libc/stdio/floatio.h
new file mode 100644
index 000000000000..09d24b85aac8
--- /dev/null
+++ b/lib/libc/stdio/floatio.h
@@ -0,0 +1,54 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)floatio.h 8.1 (Berkeley) 6/4/93
+ * $FreeBSD$
+ */
+
+/*
+ * Floating point scanf/printf (input/output) definitions.
+ */
+
+/*
+ * MAXEXPDIG is the maximum number of decimal digits needed to store a
+ * floating point exponent in the largest supported format. It should
+ * be ceil(log10(LDBL_MAX_10_EXP)) or, if hexadecimal floating point
+ * conversions are supported, ceil(log10(LDBL_MAX_EXP)). But since it
+ * is presently never greater than 5 in practice, we fudge it.
+ */
+#define MAXEXPDIG 6
+#if LDBL_MAX_EXP > 999999
+#error "floating point buffers too small"
+#endif
+
+char *__hdtoa(double, const char *, int, int *, int *, char **);
+char *__hldtoa(long double, const char *, int, int *, int *, char **);
+char *__ldtoa(long double *, int, int, int *, int *, char **);
diff --git a/lib/libc/stdio/flockfile.3 b/lib/libc/stdio/flockfile.3
new file mode 100644
index 000000000000..a895a0aae045
--- /dev/null
+++ b/lib/libc/stdio/flockfile.3
@@ -0,0 +1,104 @@
+.\" Copyright (c) 2003 Tim J. Robbins
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd January 10, 2003
+.Dt FLOCKFILE 3
+.Os
+.Sh NAME
+.Nm flockfile ,
+.Nm ftrylockfile ,
+.Nm funlockfile
+.Nd "stdio locking functions"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdio.h
+.Ft void
+.Fn flockfile "FILE *stream"
+.Ft int
+.Fn ftrylockfile "FILE *stream"
+.Ft void
+.Fn funlockfile "FILE *stream"
+.Sh DESCRIPTION
+These functions provide explicit application-level locking of stdio streams.
+They can be used to avoid output from multiple threads being interspersed,
+input being dispersed among multiple readers, and to avoid the overhead
+of locking the stream for each operation.
+.Pp
+The
+.Fn flockfile
+function acquires an exclusive lock on the specified stream.
+If another thread has already locked the stream,
+.Fn flockfile
+will block until the lock is released.
+.Pp
+The
+.Fn ftrylockfile
+function is a non-blocking version of
+.Fn flockfile ;
+if the lock cannot be acquired immediately,
+.Fn ftrylockfile
+returns non-zero instead of blocking.
+.Pp
+The
+.Fn funlockfile
+function releases the lock on a stream acquired by an earlier call to
+.Fn flockfile
+or
+.Fn ftrylockfile .
+.Pp
+These functions behave as if there is a lock count associated
+with each stream.
+Each time
+.Fn flockfile
+is called on the stream, the count is incremented,
+and each time
+.Fn funlockfile
+is called on the stream, the count is decremented.
+The lock is only actually released when the count reaches zero.
+.Sh RETURN VALUES
+The
+.Fn flockfile
+and
+.Fn funlockfile
+functions return no value.
+.Pp
+The
+.Fn ftrylockfile
+function
+returns zero if the stream was successfully locked,
+non-zero otherwise.
+.Sh SEE ALSO
+.Xr getc_unlocked 3 ,
+.Xr putc_unlocked 3
+.Sh STANDARDS
+The
+.Fn flockfile ,
+.Fn ftrylockfile
+and
+.Fn funlockfile
+functions conform to
+.St -p1003.1-2001 .
diff --git a/lib/libc/stdio/fmemopen.c b/lib/libc/stdio/fmemopen.c
new file mode 100644
index 000000000000..bcf187d20029
--- /dev/null
+++ b/lib/libc/stdio/fmemopen.c
@@ -0,0 +1,262 @@
+/*-
+ * Copyright (C) 2013 Pietro Cerutti <gahr@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include "local.h"
+
+struct fmemopen_cookie
+{
+ char *buf; /* pointer to the memory region */
+ bool own; /* did we allocate the buffer ourselves? */
+ char bin; /* is this a binary buffer? */
+ size_t size; /* buffer length in bytes */
+ size_t len; /* data length in bytes */
+ size_t off; /* current offset into the buffer */
+};
+
+static int fmemopen_read(void *cookie, char *buf, int nbytes);
+static int fmemopen_write(void *cookie, const char *buf, int nbytes);
+static fpos_t fmemopen_seek(void *cookie, fpos_t offset, int whence);
+static int fmemopen_close(void *cookie);
+
+FILE *
+fmemopen(void * __restrict buf, size_t size, const char * __restrict mode)
+{
+ struct fmemopen_cookie *ck;
+ FILE *f;
+ int flags, rc;
+
+ /*
+ * POSIX says we shall return EINVAL if size is 0.
+ */
+ if (size == 0) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ /*
+ * Retrieve the flags as used by open(2) from the mode argument, and
+ * validate them.
+ */
+ rc = __sflags(mode, &flags);
+ if (rc == 0) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ /*
+ * There's no point in requiring an automatically allocated buffer
+ * in write-only mode.
+ */
+ if (!(flags & O_RDWR) && buf == NULL) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ ck = malloc(sizeof(struct fmemopen_cookie));
+ if (ck == NULL) {
+ return (NULL);
+ }
+
+ ck->off = 0;
+ ck->size = size;
+
+ /* Check whether we have to allocate the buffer ourselves. */
+ ck->own = ((ck->buf = buf) == NULL);
+ if (ck->own) {
+ ck->buf = malloc(size);
+ if (ck->buf == NULL) {
+ free(ck);
+ return (NULL);
+ }
+ }
+
+ /*
+ * POSIX distinguishes between w+ and r+, in that w+ is supposed to
+ * truncate the buffer.
+ */
+ if (ck->own || mode[0] == 'w') {
+ ck->buf[0] = '\0';
+ }
+
+ /* Check for binary mode. */
+ ck->bin = strchr(mode, 'b') != NULL;
+
+ /*
+ * The size of the current buffer contents is set depending on the
+ * mode:
+ *
+ * for append (text-mode), the position of the first NULL byte, or the
+ * size of the buffer if none is found
+ *
+ * for append (binary-mode), the size of the buffer
+ *
+ * for read, the size of the buffer
+ *
+ * for write, 0
+ */
+ switch (mode[0]) {
+ case 'a':
+ ck->off = ck->len = strnlen(ck->buf, ck->size);
+ break;
+ case 'r':
+ ck->len = size;
+ break;
+ case 'w':
+ ck->len = 0;
+ break;
+ }
+
+ f = funopen(ck,
+ flags & O_WRONLY ? NULL : fmemopen_read,
+ flags & O_RDONLY ? NULL : fmemopen_write,
+ fmemopen_seek, fmemopen_close);
+
+ if (f == NULL) {
+ if (ck->own)
+ free(ck->buf);
+ free(ck);
+ return (NULL);
+ }
+
+ if (mode[0] == 'a')
+ f->_flags |= __SAPP;
+
+ /*
+ * Turn off buffering, so a write past the end of the buffer
+ * correctly returns a short object count.
+ */
+ setvbuf(f, NULL, _IONBF, 0);
+
+ return (f);
+}
+
+static int
+fmemopen_read(void *cookie, char *buf, int nbytes)
+{
+ struct fmemopen_cookie *ck = cookie;
+
+ if (nbytes > ck->len - ck->off)
+ nbytes = ck->len - ck->off;
+
+ if (nbytes == 0)
+ return (0);
+
+ memcpy(buf, ck->buf + ck->off, nbytes);
+
+ ck->off += nbytes;
+
+ return (nbytes);
+}
+
+static int
+fmemopen_write(void *cookie, const char *buf, int nbytes)
+{
+ struct fmemopen_cookie *ck = cookie;
+
+ if (nbytes > ck->size - ck->off)
+ nbytes = ck->size - ck->off;
+
+ if (nbytes == 0)
+ return (0);
+
+ memcpy(ck->buf + ck->off, buf, nbytes);
+
+ ck->off += nbytes;
+
+ if (ck->off > ck->len)
+ ck->len = ck->off;
+
+ /*
+ * We append a NULL byte if all these conditions are met:
+ * - the buffer is not binary
+ * - the buffer is not full
+ * - the data just written doesn't already end with a NULL byte
+ */
+ if (!ck->bin && ck->off < ck->size && ck->buf[ck->off - 1] != '\0')
+ ck->buf[ck->off] = '\0';
+
+ return (nbytes);
+}
+
+static fpos_t
+fmemopen_seek(void *cookie, fpos_t offset, int whence)
+{
+ struct fmemopen_cookie *ck = cookie;
+
+
+ switch (whence) {
+ case SEEK_SET:
+ if (offset > ck->size) {
+ errno = EINVAL;
+ return (-1);
+ }
+ ck->off = offset;
+ break;
+
+ case SEEK_CUR:
+ if (ck->off + offset > ck->size) {
+ errno = EINVAL;
+ return (-1);
+ }
+ ck->off += offset;
+ break;
+
+ case SEEK_END:
+ if (offset > 0 || -offset > ck->len) {
+ errno = EINVAL;
+ return (-1);
+ }
+ ck->off = ck->len + offset;
+ break;
+
+ default:
+ errno = EINVAL;
+ return (-1);
+ }
+
+ return (ck->off);
+}
+
+static int
+fmemopen_close(void *cookie)
+{
+ struct fmemopen_cookie *ck = cookie;
+
+ if (ck->own)
+ free(ck->buf);
+
+ free(ck);
+
+ return (0);
+}
diff --git a/lib/libc/stdio/fopen.3 b/lib/libc/stdio/fopen.3
new file mode 100644
index 000000000000..f25e6df17cf8
--- /dev/null
+++ b/lib/libc/stdio/fopen.3
@@ -0,0 +1,353 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek and the American National Standards Committee X3,
+.\" on Information Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)fopen.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd January 30, 2013
+.Dt FOPEN 3
+.Os
+.Sh NAME
+.Nm fopen ,
+.Nm fdopen ,
+.Nm freopen ,
+.Nm fmemopen
+.Nd stream open functions
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdio.h
+.Ft FILE *
+.Fn fopen "const char * restrict path" "const char * restrict mode"
+.Ft FILE *
+.Fn fdopen "int fildes" "const char *mode"
+.Ft FILE *
+.Fn freopen "const char *path" "const char *mode" "FILE *stream"
+.Ft FILE *
+.Fn fmemopen "void *restrict *buf" "size_t size" "const char * restrict mode"
+.Sh DESCRIPTION
+The
+.Fn fopen
+function
+opens the file whose name is the string pointed to by
+.Fa path
+and associates a stream with it.
+.Pp
+The argument
+.Fa mode
+points to a string beginning with one of the following letters:
+.Bl -tag -width indent
+.It Dq Li r
+Open for reading.
+The stream is positioned at the beginning of the file.
+Fail if the file does not exist.
+.It Dq Li w
+Open for writing.
+The stream is positioned at the beginning of the file.
+Create the file if it does not exist.
+.It Dq Li a
+Open for writing.
+The stream is positioned at the end of the file.
+Subsequent writes to the file will always end up at the then current
+end of file, irrespective of any intervening
+.Xr fseek 3
+or similar.
+Create the file if it does not exist.
+.El
+.Pp
+An optional
+.Dq Li +
+following
+.Dq Li r ,
+.Dq Li w ,
+or
+.Dq Li a
+opens the file for both reading and writing.
+An optional
+.Dq Li x
+following
+.Dq Li w
+or
+.Dq Li w+
+causes the
+.Fn fopen
+call to fail if the file already exists.
+An optional
+.Dq Li e
+following the above
+causes the
+.Fn fopen
+call to set the
+.Dv FD_CLOEXEC
+flag on the underlying file descriptor.
+.Pp
+The
+.Fa mode
+string can also include the letter
+.Dq Li b
+after either the
+.Dq Li +
+or the first letter.
+This is strictly for compatibility with
+.St -isoC
+and has effect only for
+.Fn fmemopen
+; otherwise
+.Dq Li b
+is ignored.
+.Pp
+Any created files will have mode
+.Do Dv S_IRUSR
+\&|
+.Dv S_IWUSR
+\&|
+.Dv S_IRGRP
+\&|
+.Dv S_IWGRP
+\&|
+.Dv S_IROTH
+\&|
+.Dv S_IWOTH Dc
+.Pq Li 0666 ,
+as modified by the process'
+umask value (see
+.Xr umask 2 ) .
+.Pp
+Reads and writes may be intermixed on read/write streams in any order,
+and do not require an intermediate seek as in previous versions of
+.Em stdio .
+This is not portable to other systems, however;
+.Tn ANSI C
+requires that
+a file positioning function intervene between output and input, unless
+an input operation encounters end-of-file.
+.Pp
+The
+.Fn fdopen
+function associates a stream with the existing file descriptor,
+.Fa fildes .
+The mode
+of the stream must be compatible with the mode of the file descriptor.
+The
+.Dq Li x
+mode option is ignored.
+If the
+.Dq Li e
+mode option is present, the
+.Dv FD_CLOEXEC
+flag is set, otherwise it remains unchanged.
+When the stream is closed via
+.Xr fclose 3 ,
+.Fa fildes
+is closed also.
+.Pp
+The
+.Fn freopen
+function
+opens the file whose name is the string pointed to by
+.Fa path
+and associates the stream pointed to by
+.Fa stream
+with it.
+The original stream (if it exists) is closed.
+The
+.Fa mode
+argument is used just as in the
+.Fn fopen
+function.
+.Pp
+If the
+.Fa path
+argument is
+.Dv NULL ,
+.Fn freopen
+attempts to re-open the file associated with
+.Fa stream
+with a new mode.
+The new mode must be compatible with the mode that the stream was originally
+opened with:
+Streams open for reading can only be re-opened for reading,
+streams open for writing can only be re-opened for writing,
+and streams open for reading and writing can be re-opened in any mode.
+The
+.Dq Li x
+mode option is not meaningful in this context.
+.Pp
+The primary use of the
+.Fn freopen
+function
+is to change the file associated with a
+standard text stream
+.Dv ( stderr , stdin ,
+or
+.Dv stdout ) .
+.Pp
+The
+.Fn fmemopen
+function
+associates the buffer given by the
+.Fa buf
+and
+.Fa size
+arguments with a stream.
+The
+.Fa buf
+argument is either a null pointer or point to a buffer that
+is at least
+.Fa size
+bytes long.
+If a null pointer is specified as the
+.Fa buf
+argument,
+.Fn fmemopen
+allocates
+.Fa size
+bytes of memory. This buffer is automatically freed when the
+stream is closed. Buffers can be opened in text-mode (default) or binary-mode
+(if
+.Dq Li b
+is present in the second or third position of the
+.Fa mode
+argument). Buffers opened in text-mode make sure that writes are terminated with
+a NULL byte, if the last write hasn't filled up the whole buffer. Buffers
+opened in binary-mode never append a NULL byte.
+.Sh RETURN VALUES
+Upon successful completion
+.Fn fopen ,
+.Fn fdopen
+and
+.Fn freopen
+return a
+.Tn FILE
+pointer.
+Otherwise,
+.Dv NULL
+is returned and the global variable
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa mode
+argument
+to
+.Fn fopen ,
+.Fn fdopen ,
+.Fn freopen ,
+or
+.Fn fmemopen
+was invalid.
+.El
+.Pp
+The
+.Fn fopen ,
+.Fn fdopen ,
+.Fn freopen
+and
+.Fn fmemopen
+functions
+may also fail and set
+.Va errno
+for any of the errors specified for the routine
+.Xr malloc 3 .
+.Pp
+The
+.Fn fopen
+function
+may also fail and set
+.Va errno
+for any of the errors specified for the routine
+.Xr open 2 .
+.Pp
+The
+.Fn fdopen
+function
+may also fail and set
+.Va errno
+for any of the errors specified for the routine
+.Xr fcntl 2 .
+.Pp
+The
+.Fn freopen
+function
+may also fail and set
+.Va errno
+for any of the errors specified for the routines
+.Xr open 2 ,
+.Xr fclose 3
+and
+.Xr fflush 3 .
+.Pp
+The
+.Fn fmemopen
+function
+may also fail and set
+.Va errno
+if the
+.Fa size
+argument is 0.
+.Sh SEE ALSO
+.Xr open 2 ,
+.Xr fclose 3 ,
+.Xr fileno 3 ,
+.Xr fseek 3 ,
+.Xr funopen 3
+.Sh STANDARDS
+The
+.Fn fopen
+and
+.Fn freopen
+functions
+conform to
+.St -isoC ,
+with the exception of the
+.Dq Li x
+mode option which conforms to
+.St -isoC-2011 .
+The
+.Fn fdopen
+function
+conforms to
+.St -p1003.1-88 .
+The
+.Dq Li e
+mode option does not conform to any standard
+but is also supported by glibc.
+The
+.Fn fmemopen
+function
+conforms to
+.St -p1003.1-2008 .
+The
+.Dq Li b
+mode does not conform to any standard
+but is also supported by glibc.
diff --git a/lib/libc/stdio/fopen.c b/lib/libc/stdio/fopen.c
new file mode 100644
index 000000000000..9ab61ba157a4
--- /dev/null
+++ b/lib/libc/stdio/fopen.c
@@ -0,0 +1,99 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)fopen.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <limits.h>
+#include "un-namespace.h"
+
+#include "local.h"
+
+FILE *
+fopen(const char * __restrict file, const char * __restrict mode)
+{
+ FILE *fp;
+ int f;
+ int flags, oflags;
+
+ if ((flags = __sflags(mode, &oflags)) == 0)
+ return (NULL);
+ if ((fp = __sfp()) == NULL)
+ return (NULL);
+ if ((f = _open(file, oflags, DEFFILEMODE)) < 0) {
+ fp->_flags = 0; /* release */
+ return (NULL);
+ }
+ /*
+ * File descriptors are a full int, but _file is only a short.
+ * If we get a valid file descriptor that is greater than
+ * SHRT_MAX, then the fd will get sign-extended into an
+ * invalid file descriptor. Handle this case by failing the
+ * open.
+ */
+ if (f > SHRT_MAX) {
+ fp->_flags = 0; /* release */
+ _close(f);
+ errno = EMFILE;
+ return (NULL);
+ }
+ fp->_file = f;
+ fp->_flags = flags;
+ fp->_cookie = fp;
+ fp->_read = __sread;
+ fp->_write = __swrite;
+ fp->_seek = __sseek;
+ fp->_close = __sclose;
+ /*
+ * When opening in append mode, even though we use O_APPEND,
+ * we need to seek to the end so that ftell() gets the right
+ * answer. If the user then alters the seek pointer, or
+ * the file extends, this will fail, but there is not much
+ * we can do about this. (We could set __SAPP and check in
+ * fseek and ftell.)
+ */
+ if (oflags & O_APPEND) {
+ fp->_flags2 |= __S2OAP;
+ (void)_sseek(fp, (fpos_t)0, SEEK_END);
+ }
+ return (fp);
+}
diff --git a/lib/libc/stdio/fopencookie.3 b/lib/libc/stdio/fopencookie.3
new file mode 100644
index 000000000000..4903e915a422
--- /dev/null
+++ b/lib/libc/stdio/fopencookie.3
@@ -0,0 +1,156 @@
+.\" Copyright (c) 2016, EMC / Isilon Storage Division
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
+.\" IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+.\" THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+.\" CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+.\" EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+.\" PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+.\" OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+.\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd May 9, 2016
+.Dt FOPENCOOKIE 3
+.Os
+.Sh NAME
+.Nm fopencookie
+.Nd open a stream
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdio.h
+.Ft typedef ssize_t
+.Fn (cookie_read_function_t) "void *cookie" "char *buf" "size_t size"
+.Ft typedef ssize_t
+.Fn (cookie_write_function_t) "void *cookie" "const char *buf" "size_t size"
+.Ft typedef int
+.Fn (cookie_seek_function_t) "void *cookie" "off64_t *offset" "int whence"
+.Ft typedef int
+.Fn (cookie_close_function_t) "void *cookie"
+.Bd -literal
+typedef struct {
+ cookie_read_function_t *read;
+ cookie_write_function_t *write;
+ cookie_seek_function_t *seek;
+ cookie_close_function_t *close;
+} cookie_io_functions_t;
+.Ed
+.Ft FILE *
+.Fn fopencookie "void *cookie" "const char *mode" "cookie_io_functions_t io_funcs"
+.Sh DESCRIPTION
+The
+.Nm
+function
+associates a stream with up to four
+.Dq Tn I/O No functions .
+These
+.Tn I/O
+functions will be used to read, write, seek and
+close the new stream.
+.Pp
+In general, omitting a function means that any attempt to perform the
+associated operation on the resulting stream will fail.
+If the write function is omitted, data written to the stream is discarded.
+If the close function is omitted, closing the stream will flush
+any buffered output and then succeed.
+.Pp
+The calling conventions of
+.Fa read ,
+.Fa write ,
+and
+.Fa close
+must match those, respectively, of
+.Xr read 2 ,
+.Xr write 2 ,
+and
+.Xr close 2
+with the single exception that they are passed the
+.Fa cookie
+argument specified to
+.Nm
+in place of the traditional file descriptor argument.
+The
+.Fa seek
+function updates the current stream offset using
+.Fa *offset
+and
+.Fa whence .
+If
+.Fa *offset
+is non-NULL, it updates
+.Fa *offset
+with the current stream offset.
+.Pp
+.Nm
+is implemented as a thin shim around the
+.Xr funopen 3
+interface.
+Limitations, possibilities, and requirements of that interface apply to
+.Nm .
+.Sh RETURN VALUES
+Upon successful completion,
+.Nm
+returns a
+.Dv FILE
+pointer.
+Otherwise,
+.Dv NULL
+is returned and the global variable
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+.Bl -tag -width Er
+.It Bq Er EINVAL
+A bogus
+.Fa mode
+was provided to
+.Nm .
+.It Bq Er ENOMEM
+The
+.Nm
+function
+may fail and set
+.Va errno
+for any of the errors
+specified for the
+.Xr malloc 3
+routine.
+.El
+.Sh SEE ALSO
+.Xr fcntl 2 ,
+.Xr open 2 ,
+.Xr fclose 3 ,
+.Xr fopen 3 ,
+.Xr fseek 3 ,
+.Xr funopen 3
+.Sh HISTORY
+The
+.Fn funopen
+functions first appeared in
+.Bx 4.4 .
+The
+.Nm
+function first appeared in
+.Fx 11 .
+.Sh BUGS
+The
+.Nm
+function is a nonstandard glibc extension and may not be portable to systems
+other than
+.Fx
+and Linux.
diff --git a/lib/libc/stdio/fopencookie.c b/lib/libc/stdio/fopencookie.c
new file mode 100644
index 000000000000..6dc39538df86
--- /dev/null
+++ b/lib/libc/stdio/fopencookie.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2016, EMC / Isilon Storage Division
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
+ * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/fcntl.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "local.h"
+
+struct fopencookie_thunk {
+ void *foc_cookie;
+ cookie_io_functions_t foc_io;
+};
+
+static int _fopencookie_read(void *, char *, int);
+static int _fopencookie_write(void *, const char *, int);
+static fpos_t _fopencookie_seek(void *, fpos_t, int);
+static int _fopencookie_close(void *);
+
+FILE *
+fopencookie(void *cookie, const char *mode, cookie_io_functions_t io_funcs)
+{
+ int (*readfn)(void *, char *, int);
+ int (*writefn)(void *, const char *, int);
+ struct fopencookie_thunk *thunk;
+ FILE *fp;
+ int flags, oflags;
+
+ if ((flags = __sflags(mode, &oflags)) == 0)
+ return (NULL);
+
+ thunk = malloc(sizeof(*thunk));
+ if (thunk == NULL)
+ return (NULL);
+
+ thunk->foc_cookie = cookie;
+ thunk->foc_io = io_funcs;
+
+ readfn = _fopencookie_read;
+ writefn = _fopencookie_write;
+ if (flags == __SWR)
+ readfn = NULL;
+ else if (flags == __SRD)
+ writefn = NULL;
+
+ fp = funopen(thunk, readfn, writefn, _fopencookie_seek,
+ _fopencookie_close);
+ if (fp == NULL) {
+ free(thunk);
+ return (NULL);
+ }
+
+ if ((oflags & O_APPEND) != 0)
+ fp->_flags |= __SAPP;
+
+ return (fp);
+}
+
+static int
+_fopencookie_read(void *cookie, char *buf, int size)
+{
+ struct fopencookie_thunk *thunk;
+
+ thunk = cookie;
+
+ /* Reads from a stream with NULL read return EOF. */
+ if (thunk->foc_io.read == NULL)
+ return (0);
+
+ return ((int)thunk->foc_io.read(thunk->foc_cookie, buf, (size_t)size));
+}
+
+static int
+_fopencookie_write(void *cookie, const char *buf, int size)
+{
+ struct fopencookie_thunk *thunk;
+
+ thunk = cookie;
+
+ /* Writes to a stream with NULL write discard data. */
+ if (thunk->foc_io.write == NULL)
+ return (size);
+
+ return ((int)thunk->foc_io.write(thunk->foc_cookie, buf,
+ (size_t)size));
+}
+
+static fpos_t
+_fopencookie_seek(void *cookie, fpos_t offset, int whence)
+{
+ struct fopencookie_thunk *thunk;
+ off64_t off64;
+ int res;
+
+ switch (whence) {
+ case SEEK_SET:
+ case SEEK_CUR:
+ case SEEK_END:
+ break;
+ default:
+ /* fopencookie(3) only allows these three seek modes. */
+ errno = EINVAL;
+ return (-1);
+ }
+
+ thunk = cookie;
+
+ /*
+ * If seek is NULL, it is not possible to perform seek operations on
+ * the stream.
+ */
+ if (thunk->foc_io.seek == NULL) {
+ errno = ENOTSUP;
+ return (-1);
+ }
+
+ off64 = (off64_t)offset;
+ res = thunk->foc_io.seek(thunk->foc_cookie, &off64, whence);
+ if (res < 0)
+ return (res);
+
+ return ((fpos_t)off64);
+}
+
+static int
+_fopencookie_close(void *cookie)
+{
+ struct fopencookie_thunk *thunk;
+ int ret, serrno;
+
+ ret = 0;
+ thunk = cookie;
+ if (thunk->foc_io.close != NULL)
+ ret = thunk->foc_io.close(thunk->foc_cookie);
+
+ serrno = errno;
+ free(thunk);
+ errno = serrno;
+ return (ret);
+}
diff --git a/lib/libc/stdio/fprintf.c b/lib/libc/stdio/fprintf.c
new file mode 100644
index 000000000000..739e1f555e09
--- /dev/null
+++ b/lib/libc/stdio/fprintf.c
@@ -0,0 +1,70 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)fprintf.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <stdarg.h>
+#include "xlocale_private.h"
+
+int
+fprintf(FILE * __restrict fp, const char * __restrict fmt, ...)
+{
+ int ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ ret = vfprintf_l(fp, __get_locale(), fmt, ap);
+ va_end(ap);
+ return (ret);
+}
+int
+fprintf_l(FILE * __restrict fp, locale_t locale, const char * __restrict fmt, ...)
+{
+ int ret;
+ va_list ap;
+ FIX_LOCALE(locale);
+
+ va_start(ap, fmt);
+ ret = vfprintf_l(fp, locale, fmt, ap);
+ va_end(ap);
+ return (ret);
+}
diff --git a/lib/libc/stdio/fpurge.c b/lib/libc/stdio/fpurge.c
new file mode 100644
index 000000000000..f205bdfc3bf5
--- /dev/null
+++ b/lib/libc/stdio/fpurge.c
@@ -0,0 +1,69 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)fpurge.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "un-namespace.h"
+#include "local.h"
+#include "libc_private.h"
+
+/*
+ * fpurge: like fflush, but without writing anything: leave the
+ * given FILE's buffer empty.
+ */
+int
+fpurge(FILE *fp)
+{
+ int retval;
+ FLOCKFILE(fp);
+ if (!fp->_flags) {
+ errno = EBADF;
+ retval = EOF;
+ } else {
+ if (HASUB(fp))
+ FREEUB(fp);
+ fp->_p = fp->_bf._base;
+ fp->_r = 0;
+ fp->_w = fp->_flags & (__SLBF|__SNBF|__SRD) ? 0 : fp->_bf._size;
+ retval = 0;
+ }
+ FUNLOCKFILE(fp);
+ return (retval);
+}
diff --git a/lib/libc/stdio/fputc.c b/lib/libc/stdio/fputc.c
new file mode 100644
index 000000000000..3b6101f92f4d
--- /dev/null
+++ b/lib/libc/stdio/fputc.c
@@ -0,0 +1,55 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)fputc.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <stdio.h>
+#include "un-namespace.h"
+#include "local.h"
+#include "libc_private.h"
+
+int
+fputc(int c, FILE *fp)
+{
+ int retval;
+ FLOCKFILE(fp);
+ /* Orientation set by __sputc() when buffer is full. */
+ /* ORIENT(fp, -1); */
+ retval = __sputc(c, fp);
+ FUNLOCKFILE(fp);
+ return (retval);
+}
diff --git a/lib/libc/stdio/fputs.3 b/lib/libc/stdio/fputs.3
new file mode 100644
index 000000000000..8e8bbd185d04
--- /dev/null
+++ b/lib/libc/stdio/fputs.3
@@ -0,0 +1,104 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek and the American National Standards Committee X3,
+.\" on Information Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)fputs.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt FPUTS 3
+.Os
+.Sh NAME
+.Nm fputs ,
+.Nm puts
+.Nd output a line to a stream
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdio.h
+.Ft int
+.Fn fputs "const char *str" "FILE *stream"
+.Ft int
+.Fn puts "const char *str"
+.Sh DESCRIPTION
+The function
+.Fn fputs
+writes the string pointed to by
+.Fa str
+to the stream pointed to by
+.Fa stream .
+.\" The terminating
+.\" .Dv NUL
+.\" character is not written.
+.Pp
+The function
+.Fn puts
+writes the string
+.Fa str ,
+and a terminating newline character,
+to the stream
+.Dv stdout .
+.Sh RETURN VALUES
+The functions
+.Fn fputs
+and
+.Fn puts
+return a nonnegative integer on success and
+.Dv EOF
+on error.
+.Sh ERRORS
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa stream
+argument
+is not a writable stream.
+.El
+.Pp
+The functions
+.Fn fputs
+and
+.Fn puts
+may also fail and set
+.Va errno
+for any of the errors specified for the routines
+.Xr write 2 .
+.Sh SEE ALSO
+.Xr ferror 3 ,
+.Xr fputws 3 ,
+.Xr putc 3 ,
+.Xr stdio 3
+.Sh STANDARDS
+The functions
+.Fn fputs
+and
+.Fn puts
+conform to
+.St -isoC .
diff --git a/lib/libc/stdio/fputs.c b/lib/libc/stdio/fputs.c
new file mode 100644
index 000000000000..1f9795a493fa
--- /dev/null
+++ b/lib/libc/stdio/fputs.c
@@ -0,0 +1,69 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)fputs.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include "un-namespace.h"
+#include "fvwrite.h"
+#include "libc_private.h"
+#include "local.h"
+
+/*
+ * Write the given string to the given file.
+ */
+int
+fputs(const char * __restrict s, FILE * __restrict fp)
+{
+ int retval;
+ struct __suio uio;
+ struct __siov iov;
+
+ iov.iov_base = (void *)s;
+ uio.uio_resid = iov.iov_len = strlen(s);
+ uio.uio_iov = &iov;
+ uio.uio_iovcnt = 1;
+ FLOCKFILE(fp);
+ ORIENT(fp, -1);
+ retval = __sfvwrite(fp, &uio);
+ FUNLOCKFILE(fp);
+ if (retval == 0)
+ return (iov.iov_len > INT_MAX ? INT_MAX : iov.iov_len);
+ return (retval);
+}
diff --git a/lib/libc/stdio/fputwc.c b/lib/libc/stdio/fputwc.c
new file mode 100644
index 000000000000..7f0c9109b087
--- /dev/null
+++ b/lib/libc/stdio/fputwc.c
@@ -0,0 +1,88 @@
+/*-
+ * Copyright (c) 2002-2004 Tim J. Robbins.
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 "namespace.h"
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+#include "local.h"
+#include "mblocal.h"
+
+/*
+ * Non-MT-safe version.
+ */
+wint_t
+__fputwc(wchar_t wc, FILE *fp, locale_t locale)
+{
+ char buf[MB_LEN_MAX];
+ size_t i, len;
+ struct xlocale_ctype *l = XLOCALE_CTYPE(locale);
+
+ if ((len = l->__wcrtomb(buf, wc, &fp->_mbstate)) == (size_t)-1) {
+ fp->_flags |= __SERR;
+ return (WEOF);
+ }
+
+ for (i = 0; i < len; i++)
+ if (__sputc((unsigned char)buf[i], fp) == EOF)
+ return (WEOF);
+
+ return ((wint_t)wc);
+}
+
+/*
+ * MT-safe version.
+ */
+wint_t
+fputwc_l(wchar_t wc, FILE *fp, locale_t locale)
+{
+ wint_t r;
+ FIX_LOCALE(locale);
+
+ FLOCKFILE(fp);
+ ORIENT(fp, 1);
+ r = __fputwc(wc, fp, locale);
+ FUNLOCKFILE(fp);
+
+ return (r);
+}
+wint_t
+fputwc(wchar_t wc, FILE *fp)
+{
+ return fputwc_l(wc, fp, __get_locale());
+}
diff --git a/lib/libc/stdio/fputws.3 b/lib/libc/stdio/fputws.3
new file mode 100644
index 000000000000..ff6205752d33
--- /dev/null
+++ b/lib/libc/stdio/fputws.3
@@ -0,0 +1,88 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek and the American National Standards Committee X3,
+.\" on Information Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)fputs.3 8.1 (Berkeley) 6/4/93
+.\" FreeBSD: src/lib/libc/stdio/fputs.3,v 1.8 2001/10/01 16:08:59 ru Exp
+.\" $FreeBSD$
+.\"
+.Dd August 6, 2002
+.Dt FPUTWS 3
+.Os
+.Sh NAME
+.Nm fputws
+.Nd output a line of wide characters to a stream
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdio.h
+.In wchar.h
+.Ft int
+.Fn fputws "const wchar_t * restrict ws" "FILE * restrict fp"
+.Sh DESCRIPTION
+The
+.Fn fputws
+function writes the wide character string pointed to by
+.Fa ws
+to the stream pointed to by
+.Fa fp .
+.Sh RETURN VALUES
+The
+.Fn fputws
+function
+returns 0 on success and \-1 on error.
+.Sh ERRORS
+The
+.Fn fputws
+function will fail if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa fp
+argument supplied
+is not a writable stream.
+.El
+.Pp
+The
+.Fn fputws
+function may also fail and set
+.Va errno
+for any of the errors specified for the routine
+.Xr write 2 .
+.Sh SEE ALSO
+.Xr ferror 3 ,
+.Xr fputs 3 ,
+.Xr putwc 3 ,
+.Xr stdio 3
+.Sh STANDARDS
+The
+.Fn fputws
+function conforms to
+.St -p1003.1-2001 .
diff --git a/lib/libc/stdio/fputws.c b/lib/libc/stdio/fputws.c
new file mode 100644
index 000000000000..41530673c007
--- /dev/null
+++ b/lib/libc/stdio/fputws.c
@@ -0,0 +1,86 @@
+/*-
+ * Copyright (c) 2002-2004 Tim J. Robbins.
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 "namespace.h"
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <wchar.h>
+#include "un-namespace.h"
+#include "fvwrite.h"
+#include "libc_private.h"
+#include "local.h"
+#include "mblocal.h"
+
+int
+fputws_l(const wchar_t * __restrict ws, FILE * __restrict fp, locale_t locale)
+{
+ size_t nbytes;
+ char buf[BUFSIZ];
+ struct __suio uio;
+ struct __siov iov;
+ const wchar_t *wsp;
+ FIX_LOCALE(locale);
+ struct xlocale_ctype *l = XLOCALE_CTYPE(locale);
+
+ FLOCKFILE(fp);
+ ORIENT(fp, 1);
+ if (prepwrite(fp) != 0)
+ goto error;
+ uio.uio_iov = &iov;
+ uio.uio_iovcnt = 1;
+ iov.iov_base = buf;
+ wsp = ws;
+ do {
+ nbytes = l->__wcsnrtombs(buf, &wsp, SIZE_T_MAX, sizeof(buf),
+ &fp->_mbstate);
+ if (nbytes == (size_t)-1)
+ goto error;
+ uio.uio_resid = iov.iov_len = nbytes;
+ if (__sfvwrite(fp, &uio) != 0)
+ goto error;
+ } while (wsp != NULL);
+ FUNLOCKFILE(fp);
+ return (0);
+
+error:
+ FUNLOCKFILE(fp);
+ return (-1);
+}
+
+int
+fputws(const wchar_t * __restrict ws, FILE * __restrict fp)
+{
+ return fputws_l(ws, fp, __get_locale());
+}
diff --git a/lib/libc/stdio/fread.3 b/lib/libc/stdio/fread.3
new file mode 100644
index 000000000000..14541bb89f66
--- /dev/null
+++ b/lib/libc/stdio/fread.3
@@ -0,0 +1,105 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek and the American National Standards Committee X3,
+.\" on Information Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)fread.3 8.2 (Berkeley) 3/8/94
+.\" $FreeBSD$
+.\"
+.Dd March 8, 1994
+.Dt FREAD 3
+.Os
+.Sh NAME
+.Nm fread ,
+.Nm fwrite
+.Nd binary stream input/output
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdio.h
+.Ft size_t
+.Fn fread "void * restrict ptr" "size_t size" "size_t nmemb" "FILE * restrict stream"
+.Ft size_t
+.Fn fwrite "const void * restrict ptr" "size_t size" "size_t nmemb" "FILE * restrict stream"
+.Sh DESCRIPTION
+The function
+.Fn fread
+reads
+.Fa nmemb
+objects, each
+.Fa size
+bytes long, from the stream pointed to by
+.Fa stream ,
+storing them at the location given by
+.Fa ptr .
+.Pp
+The function
+.Fn fwrite
+writes
+.Fa nmemb
+objects, each
+.Fa size
+bytes long, to the stream pointed to by
+.Fa stream ,
+obtaining them from the location given by
+.Fa ptr .
+.Sh RETURN VALUES
+The functions
+.Fn fread
+and
+.Fn fwrite
+advance the file position indicator for the stream
+by the number of bytes read or written.
+They return the number of objects read or written.
+If an error occurs, or the end-of-file is reached,
+the return value is a short object count (or zero).
+.Pp
+The function
+.Fn fread
+does not distinguish between end-of-file and error, and callers
+must use
+.Xr feof 3
+and
+.Xr ferror 3
+to determine which occurred.
+The function
+.Fn fwrite
+returns a value less than
+.Fa nmemb
+only if a write error has occurred.
+.Sh SEE ALSO
+.Xr read 2 ,
+.Xr write 2
+.Sh STANDARDS
+The functions
+.Fn fread
+and
+.Fn fwrite
+conform to
+.St -isoC .
diff --git a/lib/libc/stdio/fread.c b/lib/libc/stdio/fread.c
new file mode 100644
index 000000000000..c24df9914b48
--- /dev/null
+++ b/lib/libc/stdio/fread.c
@@ -0,0 +1,115 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)fread.c 8.2 (Berkeley) 12/11/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include "un-namespace.h"
+#include "local.h"
+#include "libc_private.h"
+
+/*
+ * MT-safe version
+ */
+
+size_t
+fread(void * __restrict buf, size_t size, size_t count, FILE * __restrict fp)
+{
+ size_t ret;
+
+ FLOCKFILE(fp);
+ ret = __fread(buf, size, count, fp);
+ FUNLOCKFILE(fp);
+ return (ret);
+}
+
+size_t
+__fread(void * __restrict buf, size_t size, size_t count, FILE * __restrict fp)
+{
+ size_t resid;
+ char *p;
+ int r;
+ size_t total;
+
+ /*
+ * ANSI and SUSv2 require a return value of 0 if size or count are 0.
+ */
+ if ((count == 0) || (size == 0))
+ return (0);
+
+ /*
+ * Check for integer overflow. As an optimization, first check that
+ * at least one of {count, size} is at least 2^16, since if both
+ * values are less than that, their product can't possible overflow
+ * (size_t is always at least 32 bits on FreeBSD).
+ */
+ if (((count | size) > 0xFFFF) &&
+ (count > SIZE_MAX / size)) {
+ errno = EINVAL;
+ fp->_flags |= __SERR;
+ return (0);
+ }
+
+ /*
+ * Compute the (now required to not overflow) number of bytes to
+ * read and actually do the work.
+ */
+ resid = count * size;
+ ORIENT(fp, -1);
+ if (fp->_r < 0)
+ fp->_r = 0;
+ total = resid;
+ p = buf;
+ while (resid > (r = fp->_r)) {
+ (void)memcpy((void *)p, (void *)fp->_p, (size_t)r);
+ fp->_p += r;
+ /* fp->_r = 0 ... done in __srefill */
+ p += r;
+ resid -= r;
+ if (__srefill(fp)) {
+ /* no more input: return partial result */
+ return ((total - resid) / size);
+ }
+ }
+ (void)memcpy((void *)p, (void *)fp->_p, resid);
+ fp->_r -= resid;
+ fp->_p += resid;
+ return (count);
+}
diff --git a/lib/libc/stdio/freopen.c b/lib/libc/stdio/freopen.c
new file mode 100644
index 000000000000..e0104c88eef6
--- /dev/null
+++ b/lib/libc/stdio/freopen.c
@@ -0,0 +1,250 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)freopen.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <limits.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+#include "local.h"
+
+/*
+ * Re-direct an existing, open (probably) file to some other file.
+ * ANSI is written such that the original file gets closed if at
+ * all possible, no matter what.
+ */
+FILE *
+freopen(const char * __restrict file, const char * __restrict mode,
+ FILE * __restrict fp)
+{
+ int f;
+ int dflags, flags, isopen, oflags, sverrno, wantfd;
+
+ if ((flags = __sflags(mode, &oflags)) == 0) {
+ sverrno = errno;
+ (void) fclose(fp);
+ errno = sverrno;
+ return (NULL);
+ }
+
+ FLOCKFILE(fp);
+
+ if (!__sdidinit)
+ __sinit();
+
+ /*
+ * If the filename is a NULL pointer, the caller is asking us to
+ * re-open the same file with a different mode. We allow this only
+ * if the modes are compatible.
+ */
+ if (file == NULL) {
+ /* See comment below regarding freopen() of closed files. */
+ if (fp->_flags == 0) {
+ FUNLOCKFILE(fp);
+ errno = EINVAL;
+ return (NULL);
+ }
+ if ((dflags = _fcntl(fp->_file, F_GETFL)) < 0) {
+ sverrno = errno;
+ fclose(fp);
+ FUNLOCKFILE(fp);
+ errno = sverrno;
+ return (NULL);
+ }
+ /* Work around incorrect O_ACCMODE. */
+ if ((dflags & O_ACCMODE) != O_RDWR &&
+ (dflags & (O_ACCMODE | O_EXEC)) != (oflags & O_ACCMODE)) {
+ fclose(fp);
+ FUNLOCKFILE(fp);
+ errno = EBADF;
+ return (NULL);
+ }
+ if (fp->_flags & __SWR)
+ (void) __sflush(fp);
+ if ((oflags ^ dflags) & O_APPEND) {
+ dflags &= ~O_APPEND;
+ dflags |= oflags & O_APPEND;
+ if (_fcntl(fp->_file, F_SETFL, dflags) < 0) {
+ sverrno = errno;
+ fclose(fp);
+ FUNLOCKFILE(fp);
+ errno = sverrno;
+ return (NULL);
+ }
+ }
+ if (oflags & O_TRUNC)
+ (void) ftruncate(fp->_file, (off_t)0);
+ if (!(oflags & O_APPEND))
+ (void) _sseek(fp, (fpos_t)0, SEEK_SET);
+ if (oflags & O_CLOEXEC)
+ (void) _fcntl(fp->_file, F_SETFD, FD_CLOEXEC);
+ f = fp->_file;
+ isopen = 0;
+ wantfd = -1;
+ goto finish;
+ }
+
+ /*
+ * There are actually programs that depend on being able to "freopen"
+ * descriptors that weren't originally open. Keep this from breaking.
+ * Remember whether the stream was open to begin with, and which file
+ * descriptor (if any) was associated with it. If it was attached to
+ * a descriptor, defer closing it; freopen("/dev/stdin", "r", stdin)
+ * should work. This is unnecessary if it was not a Unix file.
+ */
+ if (fp->_flags == 0) {
+ fp->_flags = __SEOF; /* hold on to it */
+ isopen = 0;
+ wantfd = -1;
+ } else {
+ /* flush the stream; ANSI doesn't require this. */
+ if (fp->_flags & __SWR)
+ (void) __sflush(fp);
+ /* if close is NULL, closing is a no-op, hence pointless */
+ isopen = fp->_close != NULL;
+ if ((wantfd = fp->_file) < 0 && isopen) {
+ (void) (*fp->_close)(fp->_cookie);
+ isopen = 0;
+ }
+ }
+
+ /* Get a new descriptor to refer to the new file. */
+ f = _open(file, oflags, DEFFILEMODE);
+ /* If out of fd's close the old one and try again. */
+ if (f < 0 && isopen && wantfd > STDERR_FILENO &&
+ (errno == ENFILE || errno == EMFILE)) {
+ (void) (*fp->_close)(fp->_cookie);
+ isopen = 0;
+ wantfd = -1;
+ f = _open(file, oflags, DEFFILEMODE);
+ }
+ sverrno = errno;
+
+finish:
+ /*
+ * Finish closing fp. Even if the open succeeded above, we cannot
+ * keep fp->_base: it may be the wrong size. This loses the effect
+ * of any setbuffer calls, but stdio has always done this before.
+ *
+ * Leave the existing file descriptor open until dup2() is called
+ * below to avoid races where a concurrent open() in another thread
+ * could claim the existing descriptor.
+ */
+ if (fp->_flags & __SMBF)
+ free((char *)fp->_bf._base);
+ fp->_w = 0;
+ fp->_r = 0;
+ fp->_p = NULL;
+ fp->_bf._base = NULL;
+ fp->_bf._size = 0;
+ fp->_lbfsize = 0;
+ if (HASUB(fp))
+ FREEUB(fp);
+ fp->_ub._size = 0;
+ if (HASLB(fp))
+ FREELB(fp);
+ fp->_lb._size = 0;
+ fp->_orientation = 0;
+ memset(&fp->_mbstate, 0, sizeof(mbstate_t));
+ fp->_flags2 = 0;
+
+ if (f < 0) { /* did not get it after all */
+ if (isopen)
+ (void) (*fp->_close)(fp->_cookie);
+ fp->_flags = 0; /* set it free */
+ FUNLOCKFILE(fp);
+ errno = sverrno; /* restore in case _close clobbered */
+ return (NULL);
+ }
+
+ /*
+ * If reopening something that was open before on a real file, try
+ * to maintain the descriptor. Various C library routines (perror)
+ * assume stderr is always fd STDERR_FILENO, even if being freopen'd.
+ */
+ if (wantfd >= 0) {
+ if ((oflags & O_CLOEXEC ? _fcntl(f, F_DUP2FD_CLOEXEC, wantfd) :
+ _dup2(f, wantfd)) >= 0) {
+ (void)_close(f);
+ f = wantfd;
+ } else
+ (void)_close(fp->_file);
+ }
+
+ /*
+ * File descriptors are a full int, but _file is only a short.
+ * If we get a valid file descriptor that is greater than
+ * SHRT_MAX, then the fd will get sign-extended into an
+ * invalid file descriptor. Handle this case by failing the
+ * open.
+ */
+ if (f > SHRT_MAX) {
+ fp->_flags = 0; /* set it free */
+ FUNLOCKFILE(fp);
+ errno = EMFILE;
+ return (NULL);
+ }
+
+ fp->_flags = flags;
+ fp->_file = f;
+ fp->_cookie = fp;
+ fp->_read = __sread;
+ fp->_write = __swrite;
+ fp->_seek = __sseek;
+ fp->_close = __sclose;
+ /*
+ * When opening in append mode, even though we use O_APPEND,
+ * we need to seek to the end so that ftell() gets the right
+ * answer. If the user then alters the seek pointer, or
+ * the file extends, this will fail, but there is not much
+ * we can do about this. (We could set __SAPP and check in
+ * fseek and ftell.)
+ */
+ if (oflags & O_APPEND) {
+ fp->_flags2 |= __S2OAP;
+ (void) _sseek(fp, (fpos_t)0, SEEK_END);
+ }
+ FUNLOCKFILE(fp);
+ return (fp);
+}
diff --git a/lib/libc/stdio/fscanf.c b/lib/libc/stdio/fscanf.c
new file mode 100644
index 000000000000..014f09415048
--- /dev/null
+++ b/lib/libc/stdio/fscanf.c
@@ -0,0 +1,78 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)fscanf.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <stdio.h>
+#include <stdarg.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+#include "local.h"
+#include "xlocale_private.h"
+
+int
+fscanf(FILE * __restrict fp, char const * __restrict fmt, ...)
+{
+ int ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ FLOCKFILE(fp);
+ ret = __svfscanf(fp, __get_locale(), fmt, ap);
+ va_end(ap);
+ FUNLOCKFILE(fp);
+ return (ret);
+}
+int
+fscanf_l(FILE * __restrict fp, locale_t locale, char const * __restrict fmt, ...)
+{
+ int ret;
+ va_list ap;
+ FIX_LOCALE(locale);
+
+ va_start(ap, fmt);
+ FLOCKFILE(fp);
+ ret = __svfscanf(fp, locale, fmt, ap);
+ va_end(ap);
+ FUNLOCKFILE(fp);
+ return (ret);
+}
diff --git a/lib/libc/stdio/fseek.3 b/lib/libc/stdio/fseek.3
new file mode 100644
index 000000000000..3f45e3145709
--- /dev/null
+++ b/lib/libc/stdio/fseek.3
@@ -0,0 +1,269 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek and the American National Standards Committee X3,
+.\" on Information Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)fseek.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd March 19, 2004
+.Dt FSEEK 3
+.Os
+.Sh NAME
+.Nm fgetpos ,
+.Nm fseek ,
+.Nm fseeko ,
+.Nm fsetpos ,
+.Nm ftell ,
+.Nm ftello ,
+.Nm rewind
+.Nd reposition a stream
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdio.h
+.Ft int
+.Fn fseek "FILE *stream" "long offset" "int whence"
+.Ft long
+.Fn ftell "FILE *stream"
+.Ft void
+.Fn rewind "FILE *stream"
+.Ft int
+.Fn fgetpos "FILE * restrict stream" "fpos_t * restrict pos"
+.Ft int
+.Fn fsetpos "FILE *stream" "const fpos_t *pos"
+.In sys/types.h
+.Ft int
+.Fn fseeko "FILE *stream" "off_t offset" "int whence"
+.Ft off_t
+.Fn ftello "FILE *stream"
+.Sh DESCRIPTION
+The
+.Fn fseek
+function sets the file position indicator for the stream pointed
+to by
+.Fa stream .
+The new position, measured in bytes, is obtained by adding
+.Fa offset
+bytes to the position specified by
+.Fa whence .
+If
+.Fa whence
+is set to
+.Dv SEEK_SET ,
+.Dv SEEK_CUR ,
+or
+.Dv SEEK_END ,
+the offset is relative to the
+start of the file, the current position indicator, or end-of-file,
+respectively.
+A successful call to the
+.Fn fseek
+function clears the end-of-file indicator for the stream and undoes
+any effects of the
+.Xr ungetc 3
+and
+.Xr ungetwc 3
+functions on the same stream.
+.Pp
+The
+.Fn ftell
+function
+obtains the current value of the file position indicator for the
+stream pointed to by
+.Fa stream .
+.Pp
+The
+.Fn rewind
+function sets the file position indicator for the stream pointed
+to by
+.Fa stream
+to the beginning of the file.
+It is equivalent to:
+.Pp
+.Dl (void)fseek(stream, 0L, SEEK_SET)
+.Pp
+except that the error indicator for the stream is also cleared
+(see
+.Xr clearerr 3 ) .
+.Pp
+Since
+.Fn rewind
+does not return a value,
+an application wishing to detect errors should clear
+.Va errno ,
+then call
+.Fn rewind ,
+and if
+.Va errno
+is non-zero, assume an error has occurred.
+.Pp
+The
+.Fn fseeko
+function is identical to
+.Fn fseek ,
+except it takes an
+.Fa off_t
+argument
+instead of a
+.Fa long .
+Likewise, the
+.Fn ftello
+function is identical to
+.Fn ftell ,
+except it returns an
+.Fa off_t .
+.Pp
+The
+.Fn fgetpos
+and
+.Fn fsetpos
+functions
+are alternate interfaces for retrieving and setting the current position in
+the file, similar to
+.Fn ftell
+and
+.Fn fseek ,
+except that the current position is stored in an opaque object of
+type
+.Vt fpos_t
+pointed to by
+.Fa pos .
+These functions provide a portable way to seek to offsets larger than
+those that can be represented by a
+.Vt long int .
+They may also store additional state information in the
+.Vt fpos_t
+object to facilitate seeking within files containing multibyte
+characters with state-dependent encodings.
+Although
+.Vt fpos_t
+has traditionally been an integral type,
+applications cannot assume that it is;
+in particular, they must not perform arithmetic on objects
+of this type.
+.Pp
+If the stream is a wide character stream (see
+.Xr fwide 3 ) ,
+the position specified by the combination of
+.Fa offset
+and
+.Fa whence
+must contain the first byte of a multibyte sequence.
+.Sh RETURN VALUES
+The
+.Fn rewind
+function
+returns no value.
+.Pp
+.Rv -std fgetpos fseek fseeko fsetpos
+.Pp
+Upon successful completion,
+.Fn ftell
+and
+.Fn ftello
+return the current offset.
+Otherwise, \-1 is returned and the global variable
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa stream
+argument
+is not a seekable stream.
+.It Bq Er EINVAL
+The
+.Fa whence
+argument is invalid or
+the resulting file-position
+indicator would be set to a negative value.
+.It Bq Er EOVERFLOW
+The resulting file offset would be a value which
+cannot be represented correctly in an object of type
+.Fa off_t
+for
+.Fn fseeko
+and
+.Fn ftello
+or
+.Fa long
+for
+.Fn fseek
+and
+.Fn ftell .
+.It Bq Er ESPIPE
+The file descriptor underlying stream is associated with a pipe or FIFO
+or file-position indicator value is unspecified
+(see
+.Xr ungetc 3 ) .
+.El
+.Pp
+The functions
+.Fn fgetpos ,
+.Fn fseek ,
+.Fn fseeko ,
+.Fn fsetpos ,
+.Fn ftell ,
+.Fn ftello ,
+and
+.Fn rewind
+may also fail and set
+.Va errno
+for any of the errors specified for the routines
+.Xr fflush 3 ,
+.Xr fstat 2 ,
+.Xr lseek 2 ,
+and
+.Xr malloc 3 .
+.Sh SEE ALSO
+.Xr lseek 2 ,
+.Xr clearerr 3 ,
+.Xr fwide 3 ,
+.Xr ungetc 3 ,
+.Xr ungetwc 3
+.Sh STANDARDS
+The
+.Fn fgetpos ,
+.Fn fsetpos ,
+.Fn fseek ,
+.Fn ftell ,
+and
+.Fn rewind
+functions
+conform to
+.St -isoC .
+.Pp
+The
+.Fn fseeko
+and
+.Fn ftello
+functions conform to
+.St -p1003.1-2001 .
diff --git a/lib/libc/stdio/fseek.c b/lib/libc/stdio/fseek.c
new file mode 100644
index 000000000000..2897eebf9c88
--- /dev/null
+++ b/lib/libc/stdio/fseek.c
@@ -0,0 +1,301 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)fseek.c 8.3 (Berkeley) 1/2/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "un-namespace.h"
+#include "local.h"
+#include "libc_private.h"
+
+#define POS_ERR (-(fpos_t)1)
+
+int
+fseek(FILE *fp, long offset, int whence)
+{
+ int ret;
+ int serrno = errno;
+
+ /* make sure stdio is set up */
+ if (!__sdidinit)
+ __sinit();
+
+ FLOCKFILE(fp);
+ ret = _fseeko(fp, (off_t)offset, whence, 1);
+ FUNLOCKFILE(fp);
+ if (ret == 0)
+ errno = serrno;
+ return (ret);
+}
+
+int
+fseeko(FILE *fp, off_t offset, int whence)
+{
+ int ret;
+ int serrno = errno;
+
+ /* make sure stdio is set up */
+ if (!__sdidinit)
+ __sinit();
+
+ FLOCKFILE(fp);
+ ret = _fseeko(fp, offset, whence, 0);
+ FUNLOCKFILE(fp);
+ if (ret == 0)
+ errno = serrno;
+ return (ret);
+}
+
+/*
+ * Seek the given file to the given offset.
+ * `Whence' must be one of the three SEEK_* macros.
+ */
+int
+_fseeko(FILE *fp, off_t offset, int whence, int ltest)
+{
+ fpos_t (*seekfn)(void *, fpos_t, int);
+ fpos_t target, curoff, ret;
+ size_t n;
+ struct stat st;
+ int havepos;
+
+ /*
+ * Have to be able to seek.
+ */
+ if ((seekfn = fp->_seek) == NULL) {
+ errno = ESPIPE; /* historic practice */
+ return (-1);
+ }
+
+ /*
+ * Change any SEEK_CUR to SEEK_SET, and check `whence' argument.
+ * After this, whence is either SEEK_SET or SEEK_END.
+ */
+ switch (whence) {
+
+ case SEEK_CUR:
+ /*
+ * In order to seek relative to the current stream offset,
+ * we have to first find the current stream offset via
+ * ftell (see ftell for details).
+ */
+ if (_ftello(fp, &curoff))
+ return (-1);
+ if (curoff < 0) {
+ /* Unspecified position because of ungetc() at 0 */
+ errno = ESPIPE;
+ return (-1);
+ }
+ if (offset > 0 && curoff > OFF_MAX - offset) {
+ errno = EOVERFLOW;
+ return (-1);
+ }
+ offset += curoff;
+ if (offset < 0) {
+ errno = EINVAL;
+ return (-1);
+ }
+ if (ltest && offset > LONG_MAX) {
+ errno = EOVERFLOW;
+ return (-1);
+ }
+ whence = SEEK_SET;
+ havepos = 1;
+ break;
+
+ case SEEK_SET:
+ if (offset < 0) {
+ errno = EINVAL;
+ return (-1);
+ }
+ case SEEK_END:
+ curoff = 0; /* XXX just to keep gcc quiet */
+ havepos = 0;
+ break;
+
+ default:
+ errno = EINVAL;
+ return (-1);
+ }
+
+ /*
+ * Can only optimise if:
+ * reading (and not reading-and-writing);
+ * not unbuffered; and
+ * this is a `regular' Unix file (and hence seekfn==__sseek).
+ * We must check __NBF first, because it is possible to have __NBF
+ * and __SOPT both set.
+ */
+ if (fp->_bf._base == NULL)
+ __smakebuf(fp);
+ if (fp->_flags & (__SWR | __SRW | __SNBF | __SNPT))
+ goto dumb;
+ if ((fp->_flags & __SOPT) == 0) {
+ if (seekfn != __sseek ||
+ fp->_file < 0 || _fstat(fp->_file, &st) ||
+ (st.st_mode & S_IFMT) != S_IFREG) {
+ fp->_flags |= __SNPT;
+ goto dumb;
+ }
+ fp->_blksize = st.st_blksize;
+ fp->_flags |= __SOPT;
+ }
+
+ /*
+ * We are reading; we can try to optimise.
+ * Figure out where we are going and where we are now.
+ */
+ if (whence == SEEK_SET)
+ target = offset;
+ else {
+ if (_fstat(fp->_file, &st))
+ goto dumb;
+ if (offset > 0 && st.st_size > OFF_MAX - offset) {
+ errno = EOVERFLOW;
+ return (-1);
+ }
+ target = st.st_size + offset;
+ if ((off_t)target < 0) {
+ errno = EINVAL;
+ return (-1);
+ }
+ if (ltest && (off_t)target > LONG_MAX) {
+ errno = EOVERFLOW;
+ return (-1);
+ }
+ }
+
+ if (!havepos && _ftello(fp, &curoff))
+ goto dumb;
+
+ /*
+ * (If the buffer was modified, we have to
+ * skip this; see fgetln.c.)
+ */
+ if (fp->_flags & __SMOD)
+ goto abspos;
+
+ /*
+ * Compute the number of bytes in the input buffer (pretending
+ * that any ungetc() input has been discarded). Adjust current
+ * offset backwards by this count so that it represents the
+ * file offset for the first byte in the current input buffer.
+ */
+ if (HASUB(fp)) {
+ curoff += fp->_r; /* kill off ungetc */
+ n = fp->_up - fp->_bf._base;
+ curoff -= n;
+ n += fp->_ur;
+ } else {
+ n = fp->_p - fp->_bf._base;
+ curoff -= n;
+ n += fp->_r;
+ }
+
+ /*
+ * If the target offset is within the current buffer,
+ * simply adjust the pointers, clear EOF, undo ungetc(),
+ * and return.
+ */
+ if (target >= curoff && target < curoff + n) {
+ size_t o = target - curoff;
+
+ fp->_p = fp->_bf._base + o;
+ fp->_r = n - o;
+ if (HASUB(fp))
+ FREEUB(fp);
+ fp->_flags &= ~__SEOF;
+ memset(&fp->_mbstate, 0, sizeof(mbstate_t));
+ return (0);
+ }
+
+abspos:
+ /*
+ * The place we want to get to is not within the current buffer,
+ * but we can still be kind to the kernel copyout mechanism.
+ * By aligning the file offset to a block boundary, we can let
+ * the kernel use the VM hardware to map pages instead of
+ * copying bytes laboriously. Using a block boundary also
+ * ensures that we only read one block, rather than two.
+ */
+ curoff = target & ~(fp->_blksize - 1);
+ if (_sseek(fp, curoff, SEEK_SET) == POS_ERR)
+ goto dumb;
+ fp->_r = 0;
+ fp->_p = fp->_bf._base;
+ if (HASUB(fp))
+ FREEUB(fp);
+ n = target - curoff;
+ if (n) {
+ if (__srefill(fp) || fp->_r < n)
+ goto dumb;
+ fp->_p += n;
+ fp->_r -= n;
+ }
+ fp->_flags &= ~__SEOF;
+ memset(&fp->_mbstate, 0, sizeof(mbstate_t));
+ return (0);
+
+ /*
+ * We get here if we cannot optimise the seek ... just
+ * do it. Allow the seek function to change fp->_bf._base.
+ */
+dumb:
+ if (__sflush(fp) ||
+ (ret = _sseek(fp, (fpos_t)offset, whence)) == POS_ERR)
+ return (-1);
+ if (ltest && ret > LONG_MAX) {
+ fp->_flags |= __SERR;
+ errno = EOVERFLOW;
+ return (-1);
+ }
+ /* success: clear EOF indicator and discard ungetc() data */
+ if (HASUB(fp))
+ FREEUB(fp);
+ fp->_p = fp->_bf._base;
+ fp->_r = 0;
+ /* fp->_w = 0; */ /* unnecessary (I think...) */
+ fp->_flags &= ~__SEOF;
+ memset(&fp->_mbstate, 0, sizeof(mbstate_t));
+ return (0);
+}
diff --git a/lib/libc/stdio/fsetpos.c b/lib/libc/stdio/fsetpos.c
new file mode 100644
index 000000000000..c6b8b785918d
--- /dev/null
+++ b/lib/libc/stdio/fsetpos.c
@@ -0,0 +1,49 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)fsetpos.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <stdio.h>
+
+/*
+ * fsetpos: like fseek.
+ */
+int
+fsetpos(FILE *iop, const fpos_t *pos)
+{
+ return (fseeko(iop, (off_t)*pos, SEEK_SET));
+}
diff --git a/lib/libc/stdio/ftell.c b/lib/libc/stdio/ftell.c
new file mode 100644
index 000000000000..fc792af5fa22
--- /dev/null
+++ b/lib/libc/stdio/ftell.c
@@ -0,0 +1,141 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)ftell.c 8.2 (Berkeley) 5/4/95";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include "un-namespace.h"
+#include "local.h"
+#include "libc_private.h"
+
+/*
+ * standard ftell function.
+ */
+long
+ftell(FILE *fp)
+{
+ off_t rv;
+
+ rv = ftello(fp);
+ if (rv > LONG_MAX) {
+ errno = EOVERFLOW;
+ return (-1);
+ }
+ return (rv);
+}
+
+/*
+ * ftello: return current offset.
+ */
+off_t
+ftello(FILE *fp)
+{
+ fpos_t rv;
+ int ret;
+
+ FLOCKFILE(fp);
+ ret = _ftello(fp, &rv);
+ FUNLOCKFILE(fp);
+ if (ret)
+ return (-1);
+ if (rv < 0) { /* Unspecified value because of ungetc() at 0 */
+ errno = ESPIPE;
+ return (-1);
+ }
+ return (rv);
+}
+
+int
+_ftello(FILE *fp, fpos_t *offset)
+{
+ fpos_t pos;
+ size_t n;
+
+ if (fp->_seek == NULL) {
+ errno = ESPIPE; /* historic practice */
+ return (1);
+ }
+
+ /*
+ * Find offset of underlying I/O object, then
+ * adjust for buffered bytes.
+ */
+ if (!(fp->_flags & __SRD) && (fp->_flags & __SWR) &&
+ fp->_p != NULL && fp->_p - fp->_bf._base > 0 &&
+ ((fp->_flags & __SAPP) || (fp->_flags2 & __S2OAP))) {
+ pos = _sseek(fp, (fpos_t)0, SEEK_END);
+ if (pos == -1)
+ return (1);
+ } else if (fp->_flags & __SOFF)
+ pos = fp->_offset;
+ else {
+ pos = _sseek(fp, (fpos_t)0, SEEK_CUR);
+ if (pos == -1)
+ return (1);
+ }
+ if (fp->_flags & __SRD) {
+ /*
+ * Reading. Any unread characters (including
+ * those from ungetc) cause the position to be
+ * smaller than that in the underlying object.
+ */
+ if ((pos -= (HASUB(fp) ? fp->_ur : fp->_r)) < 0) {
+ fp->_flags |= __SERR;
+ errno = EIO;
+ return (1);
+ }
+ if (HASUB(fp))
+ pos -= fp->_r; /* Can be negative at this point. */
+ } else if ((fp->_flags & __SWR) && fp->_p != NULL &&
+ (n = fp->_p - fp->_bf._base) > 0) {
+ /*
+ * Writing. Any buffered characters cause the
+ * position to be greater than that in the
+ * underlying object.
+ */
+ if (pos > OFF_MAX - n) {
+ errno = EOVERFLOW;
+ return (1);
+ }
+ pos += n;
+ }
+ *offset = pos;
+ return (0);
+}
diff --git a/lib/libc/stdio/funopen.3 b/lib/libc/stdio/funopen.3
new file mode 100644
index 000000000000..4cad63dccb80
--- /dev/null
+++ b/lib/libc/stdio/funopen.3
@@ -0,0 +1,177 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek.
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)funopen.3 8.1 (Berkeley) 6/9/93
+.\" $FreeBSD$
+.\"
+.Dd May 9, 2016
+.Dt FUNOPEN 3
+.Os
+.Sh NAME
+.Nm funopen ,
+.Nm fropen ,
+.Nm fwopen
+.Nd open a stream
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdio.h
+.Ft FILE *
+.Fn funopen "const void *cookie" "int (*readfn)(void *, char *, int)" "int (*writefn)(void *, const char *, int)" "fpos_t (*seekfn)(void *, fpos_t, int)" "int (*closefn)(void *)"
+.Ft FILE *
+.Fn fropen "void *cookie" "int (*readfn)(void *, char *, int)"
+.Ft FILE *
+.Fn fwopen "void *cookie" "int (*writefn)(void *, const char *, int)"
+.Sh DESCRIPTION
+The
+.Fn funopen
+function
+associates a stream with up to four
+.Dq Tn I/O No functions .
+Either
+.Fa readfn
+or
+.Fa writefn
+must be specified;
+the others can be given as an appropriately-typed
+.Dv NULL
+pointer.
+These
+.Tn I/O
+functions will be used to read, write, seek and
+close the new stream.
+.Pp
+In general, omitting a function means that any attempt to perform the
+associated operation on the resulting stream will fail.
+If the close function is omitted, closing the stream will flush
+any buffered output and then succeed.
+.Pp
+The calling conventions of
+.Fa readfn ,
+.Fa writefn ,
+.Fa seekfn
+and
+.Fa closefn
+must match those, respectively, of
+.Xr read 2 ,
+.Xr write 2 ,
+.Xr lseek 2 ,
+and
+.Xr close 2
+with the single exception that they are passed the
+.Fa cookie
+argument specified to
+.Fn funopen
+in place of the traditional file descriptor argument.
+.Pp
+Read and write
+.Tn I/O
+functions are allowed to change the underlying buffer
+on fully buffered or line buffered streams by calling
+.Xr setvbuf 3 .
+They are also not required to completely fill or empty the buffer.
+They are not, however, allowed to change streams from unbuffered to buffered
+or to change the state of the line buffering flag.
+They must also be prepared to have read or write calls occur on buffers other
+than the one most recently specified.
+.Pp
+All user
+.Tn I/O
+functions can report an error by returning \-1.
+Additionally, all of the functions should set the external variable
+.Va errno
+appropriately if an error occurs.
+.Pp
+An error on
+.Fn closefn
+does not keep the stream open.
+.Pp
+As a convenience, the include file
+.In stdio.h
+defines the macros
+.Fn fropen
+and
+.Fn fwopen
+as calls to
+.Fn funopen
+with only a read or write function specified.
+.Sh RETURN VALUES
+Upon successful completion,
+.Fn funopen
+returns a
+.Dv FILE
+pointer.
+Otherwise,
+.Dv NULL
+is returned and the global variable
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fn funopen
+function
+was called without either a read or write function.
+The
+.Fn funopen
+function
+may also fail and set
+.Va errno
+for any of the errors
+specified for the routine
+.Xr malloc 3 .
+.El
+.Sh SEE ALSO
+.Xr fcntl 2 ,
+.Xr open 2 ,
+.Xr fclose 3 ,
+.Xr fopen 3 ,
+.Xr fopencookie 3 ,
+.Xr fseek 3 ,
+.Xr setbuf 3
+.Sh HISTORY
+The
+.Fn funopen
+functions first appeared in
+.Bx 4.4 .
+.Sh BUGS
+The
+.Fn funopen
+function
+may not be portable to systems other than
+.Bx .
+.Pp
+The
+.Fn funopen
+interface erroneously assumes that
+.Vt fpos_t
+is an integral type; see
+.Xr fseek 3
+for a discussion of this issue.
diff --git a/lib/libc/stdio/funopen.c b/lib/libc/stdio/funopen.c
new file mode 100644
index 000000000000..983fe5011902
--- /dev/null
+++ b/lib/libc/stdio/funopen.c
@@ -0,0 +1,76 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)funopen.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <errno.h>
+
+#include "local.h"
+
+FILE *
+funopen(const void *cookie,
+ int (*readfn)(void *, char *, int),
+ int (*writefn)(void *, const char *, int),
+ fpos_t (*seekfn)(void *, fpos_t, int),
+ int (*closefn)(void *))
+{
+ FILE *fp;
+ int flags;
+
+ if (readfn == NULL) {
+ if (writefn == NULL) { /* illegal */
+ errno = EINVAL;
+ return (NULL);
+ } else
+ flags = __SWR; /* write only */
+ } else {
+ if (writefn == NULL)
+ flags = __SRD; /* read only */
+ else
+ flags = __SRW; /* read-write */
+ }
+ if ((fp = __sfp()) == NULL)
+ return (NULL);
+ fp->_flags = flags;
+ fp->_file = -1;
+ fp->_cookie = (void *)cookie;
+ fp->_read = readfn;
+ fp->_write = writefn;
+ fp->_seek = seekfn;
+ fp->_close = closefn;
+ return (fp);
+}
diff --git a/lib/libc/stdio/fvwrite.c b/lib/libc/stdio/fvwrite.c
new file mode 100644
index 000000000000..1a28b6a79c01
--- /dev/null
+++ b/lib/libc/stdio/fvwrite.c
@@ -0,0 +1,205 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)fvwrite.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "local.h"
+#include "fvwrite.h"
+
+/*
+ * Write some memory regions. Return zero on success, EOF on error.
+ *
+ * This routine is large and unsightly, but most of the ugliness due
+ * to the three different kinds of output buffering is handled here.
+ */
+int
+__sfvwrite(FILE *fp, struct __suio *uio)
+{
+ size_t len;
+ char *p;
+ struct __siov *iov;
+ int w, s;
+ char *nl;
+ int nlknown, nldist;
+
+ if (uio->uio_resid == 0)
+ return (0);
+ /* make sure we can write */
+ if (prepwrite(fp) != 0)
+ return (EOF);
+
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#define COPY(n) (void)memcpy((void *)fp->_p, (void *)p, (size_t)(n))
+
+ iov = uio->uio_iov;
+ p = iov->iov_base;
+ len = iov->iov_len;
+ iov++;
+#define GETIOV(extra_work) \
+ while (len == 0) { \
+ extra_work; \
+ p = iov->iov_base; \
+ len = iov->iov_len; \
+ iov++; \
+ }
+ if (fp->_flags & __SNBF) {
+ /*
+ * Unbuffered: write up to BUFSIZ bytes at a time.
+ */
+ do {
+ GETIOV(;);
+ w = _swrite(fp, p, MIN(len, BUFSIZ));
+ if (w <= 0)
+ goto err;
+ p += w;
+ len -= w;
+ } while ((uio->uio_resid -= w) != 0);
+ } else if ((fp->_flags & __SLBF) == 0) {
+ /*
+ * Fully buffered: fill partially full buffer, if any,
+ * and then flush. If there is no partial buffer, write
+ * one _bf._size byte chunk directly (without copying).
+ *
+ * String output is a special case: write as many bytes
+ * as fit, but pretend we wrote everything. This makes
+ * snprintf() return the number of bytes needed, rather
+ * than the number used, and avoids its write function
+ * (so that the write function can be invalid).
+ */
+ do {
+ GETIOV(;);
+ if ((fp->_flags & (__SALC | __SSTR)) ==
+ (__SALC | __SSTR) && fp->_w < len) {
+ size_t blen = fp->_p - fp->_bf._base;
+
+ /*
+ * Alloc an extra 128 bytes (+ 1 for NULL)
+ * so we don't call realloc(3) so often.
+ */
+ fp->_w = len + 128;
+ fp->_bf._size = blen + len + 128;
+ fp->_bf._base =
+ reallocf(fp->_bf._base, fp->_bf._size + 1);
+ if (fp->_bf._base == NULL)
+ goto err;
+ fp->_p = fp->_bf._base + blen;
+ }
+ w = fp->_w;
+ if (fp->_flags & __SSTR) {
+ if (len < w)
+ w = len;
+ if (w > 0) {
+ COPY(w); /* copy MIN(fp->_w,len), */
+ fp->_w -= w;
+ fp->_p += w;
+ }
+ w = len; /* but pretend copied all */
+ } else if (fp->_p > fp->_bf._base && len > w) {
+ /* fill and flush */
+ COPY(w);
+ /* fp->_w -= w; */ /* unneeded */
+ fp->_p += w;
+ if (__fflush(fp))
+ goto err;
+ } else if (len >= (w = fp->_bf._size)) {
+ /* write directly */
+ w = _swrite(fp, p, w);
+ if (w <= 0)
+ goto err;
+ } else {
+ /* fill and done */
+ w = len;
+ COPY(w);
+ fp->_w -= w;
+ fp->_p += w;
+ }
+ p += w;
+ len -= w;
+ } while ((uio->uio_resid -= w) != 0);
+ } else {
+ /*
+ * Line buffered: like fully buffered, but we
+ * must check for newlines. Compute the distance
+ * to the first newline (including the newline),
+ * or `infinity' if there is none, then pretend
+ * that the amount to write is MIN(len,nldist).
+ */
+ nlknown = 0;
+ nldist = 0; /* XXX just to keep gcc happy */
+ do {
+ GETIOV(nlknown = 0);
+ if (!nlknown) {
+ nl = memchr((void *)p, '\n', len);
+ nldist = nl ? nl + 1 - p : len + 1;
+ nlknown = 1;
+ }
+ s = MIN(len, nldist);
+ w = fp->_w + fp->_bf._size;
+ if (fp->_p > fp->_bf._base && s > w) {
+ COPY(w);
+ /* fp->_w -= w; */
+ fp->_p += w;
+ if (__fflush(fp))
+ goto err;
+ } else if (s >= (w = fp->_bf._size)) {
+ w = _swrite(fp, p, w);
+ if (w <= 0)
+ goto err;
+ } else {
+ w = s;
+ COPY(w);
+ fp->_w -= w;
+ fp->_p += w;
+ }
+ if ((nldist -= w) == 0) {
+ /* copied the newline: flush and forget */
+ if (__fflush(fp))
+ goto err;
+ nlknown = 0;
+ }
+ p += w;
+ len -= w;
+ } while ((uio->uio_resid -= w) != 0);
+ }
+ return (0);
+
+err:
+ fp->_flags |= __SERR;
+ return (EOF);
+}
diff --git a/lib/libc/stdio/fvwrite.h b/lib/libc/stdio/fvwrite.h
new file mode 100644
index 000000000000..a4da7434f0bf
--- /dev/null
+++ b/lib/libc/stdio/fvwrite.h
@@ -0,0 +1,49 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)fvwrite.h 8.1 (Berkeley) 6/4/93
+ * $FreeBSD$
+ */
+
+/*
+ * I/O descriptors for __sfvwrite().
+ */
+struct __siov {
+ void *iov_base;
+ size_t iov_len;
+};
+struct __suio {
+ struct __siov *uio_iov;
+ int uio_iovcnt;
+ int uio_resid;
+};
+
+extern int __sfvwrite(FILE *, struct __suio *);
diff --git a/lib/libc/stdio/fwalk.c b/lib/libc/stdio/fwalk.c
new file mode 100644
index 000000000000..151837b29025
--- /dev/null
+++ b/lib/libc/stdio/fwalk.c
@@ -0,0 +1,65 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)fwalk.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <stdio.h>
+#include "local.h"
+#include "glue.h"
+
+int
+_fwalk(int (*function)(FILE *))
+{
+ FILE *fp;
+ int n, ret;
+ struct glue *g;
+
+ ret = 0;
+ /*
+ * It should be safe to walk the list without locking it;
+ * new nodes are only added to the end and none are ever
+ * removed.
+ *
+ * Avoid locking this list while walking it or else you will
+ * introduce a potential deadlock in [at least] refill.c.
+ */
+ for (g = &__sglue; g != NULL; g = g->next)
+ for (fp = g->iobs, n = g->niobs; --n >= 0; fp++)
+ if ((fp->_flags != 0) && ((fp->_flags & __SIGN) == 0))
+ ret |= (*function)(fp);
+ return (ret);
+}
diff --git a/lib/libc/stdio/fwide.3 b/lib/libc/stdio/fwide.3
new file mode 100644
index 000000000000..6ff8d9264995
--- /dev/null
+++ b/lib/libc/stdio/fwide.3
@@ -0,0 +1,97 @@
+.\" $NetBSD: fwide.3,v 1.3 2002/02/07 07:00:25 ross Exp $
+.\"
+.\" Copyright (c)2001 Citrus Project,
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Citrus: xpg4dl/FreeBSD/lib/libc/stdio/fwide.3,v 1.2 2001/12/07 04:47:08 yamt Exp $
+.\" $FreeBSD$
+.\"
+.Dd October 24, 2001
+.Dt FWIDE 3
+.Os
+.Sh NAME
+.Nm fwide
+.Nd get/set orientation of a stream
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdio.h
+.In wchar.h
+.Ft int
+.Fn fwide "FILE *stream" "int mode"
+.Sh DESCRIPTION
+The
+.Fn fwide
+function
+determines the orientation of the stream pointed at by
+.Fa stream .
+.Pp
+If the orientation of
+.Fa stream
+has already been determined,
+.Fn fwide
+leaves it unchanged.
+Otherwise,
+.Fn fwide
+sets the orientation of
+.Fa stream
+according to
+.Fa mode .
+.Pp
+If
+.Fa mode
+is less than zero,
+.Fa stream
+is set to byte-oriented.
+If it is greater than zero,
+.Fa stream
+is set to wide-oriented.
+Otherwise,
+.Fa mode
+is zero, and
+.Fa stream
+is unchanged.
+.Sh RETURN VALUES
+The
+.Fn fwide
+function
+returns a value according to orientation after the call of
+.Fn fwide ;
+a value less than zero if byte-oriented, a value greater than zero
+if wide-oriented, and zero if the stream has no orientation.
+.Sh SEE ALSO
+.Xr ferror 3 ,
+.Xr fgetc 3 ,
+.Xr fgetwc 3 ,
+.Xr fopen 3 ,
+.Xr fputc 3 ,
+.Xr fputwc 3 ,
+.Xr freopen 3 ,
+.Xr stdio 3
+.Sh STANDARDS
+The
+.Fn fwide
+function
+conforms to
+.St -isoC-99 .
diff --git a/lib/libc/stdio/fwide.c b/lib/libc/stdio/fwide.c
new file mode 100644
index 000000000000..c94ffe63a1bc
--- /dev/null
+++ b/lib/libc/stdio/fwide.c
@@ -0,0 +1,51 @@
+/*-
+ * Copyright (c) 2002 Tim J. Robbins.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <errno.h>
+#include <stdio.h>
+#include <wchar.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+#include "local.h"
+
+int
+fwide(FILE *fp, int mode)
+{
+ int m;
+
+ FLOCKFILE(fp);
+ /* Only change the orientation if the stream is not oriented yet. */
+ if (mode != 0 && fp->_orientation == 0)
+ fp->_orientation = mode > 0 ? 1 : -1;
+ m = fp->_orientation;
+ FUNLOCKFILE(fp);
+
+ return (m);
+}
diff --git a/lib/libc/stdio/fwprintf.c b/lib/libc/stdio/fwprintf.c
new file mode 100644
index 000000000000..f4342ab6c4e3
--- /dev/null
+++ b/lib/libc/stdio/fwprintf.c
@@ -0,0 +1,63 @@
+/*-
+ * Copyright (c) 2002 Tim J. Robbins
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 <stdarg.h>
+#include <stdio.h>
+#include <wchar.h>
+#include <xlocale.h>
+
+int
+fwprintf(FILE * __restrict fp, const wchar_t * __restrict fmt, ...)
+{
+ int ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ ret = vfwprintf(fp, fmt, ap);
+ va_end(ap);
+
+ return (ret);
+}
+int
+fwprintf_l(FILE * __restrict fp, locale_t locale, const wchar_t * __restrict fmt, ...)
+{
+ int ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ ret = vfwprintf_l(fp, locale, fmt, ap);
+ va_end(ap);
+
+ return (ret);
+}
diff --git a/lib/libc/stdio/fwrite.c b/lib/libc/stdio/fwrite.c
new file mode 100644
index 000000000000..5b57fab0b9e1
--- /dev/null
+++ b/lib/libc/stdio/fwrite.c
@@ -0,0 +1,96 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)fwrite.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include "un-namespace.h"
+#include "local.h"
+#include "fvwrite.h"
+#include "libc_private.h"
+
+/*
+ * Write `count' objects (each size `size') from memory to the given file.
+ * Return the number of whole objects written.
+ */
+size_t
+fwrite(const void * __restrict buf, size_t size, size_t count, FILE * __restrict fp)
+{
+ size_t n;
+ struct __suio uio;
+ struct __siov iov;
+
+ /*
+ * ANSI and SUSv2 require a return value of 0 if size or count are 0.
+ */
+ if ((count == 0) || (size == 0))
+ return (0);
+
+ /*
+ * Check for integer overflow. As an optimization, first check that
+ * at least one of {count, size} is at least 2^16, since if both
+ * values are less than that, their product can't possibly overflow
+ * (size_t is always at least 32 bits on FreeBSD).
+ */
+ if (((count | size) > 0xFFFF) &&
+ (count > SIZE_MAX / size)) {
+ errno = EINVAL;
+ fp->_flags |= __SERR;
+ return (0);
+ }
+
+ n = count * size;
+
+ iov.iov_base = (void *)buf;
+ uio.uio_resid = iov.iov_len = n;
+ uio.uio_iov = &iov;
+ uio.uio_iovcnt = 1;
+
+ FLOCKFILE(fp);
+ ORIENT(fp, -1);
+ /*
+ * The usual case is success (__sfvwrite returns 0);
+ * skip the divide if this happens, since divides are
+ * generally slow and since this occurs whenever size==0.
+ */
+ if (__sfvwrite(fp, &uio) != 0)
+ count = (n - uio.uio_resid) / size;
+ FUNLOCKFILE(fp);
+ return (count);
+}
diff --git a/lib/libc/stdio/fwscanf.c b/lib/libc/stdio/fwscanf.c
new file mode 100644
index 000000000000..175607747d65
--- /dev/null
+++ b/lib/libc/stdio/fwscanf.c
@@ -0,0 +1,63 @@
+/*-
+ * Copyright (c) 2002 Tim J. Robbins
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 <stdarg.h>
+#include <stdio.h>
+#include <wchar.h>
+#include <xlocale.h>
+
+int
+fwscanf(FILE * __restrict fp, const wchar_t * __restrict fmt, ...)
+{
+ va_list ap;
+ int r;
+
+ va_start(ap, fmt);
+ r = vfwscanf(fp, fmt, ap);
+ va_end(ap);
+
+ return (r);
+}
+int
+fwscanf_l(FILE * __restrict fp, locale_t locale, const wchar_t * __restrict fmt, ...)
+{
+ va_list ap;
+ int r;
+
+ va_start(ap, fmt);
+ r = vfwscanf_l(fp, locale, fmt, ap);
+ va_end(ap);
+
+ return (r);
+}
diff --git a/lib/libc/stdio/getc.3 b/lib/libc/stdio/getc.3
new file mode 100644
index 000000000000..d0f3c15f0728
--- /dev/null
+++ b/lib/libc/stdio/getc.3
@@ -0,0 +1,169 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek and the American National Standards Committee X3,
+.\" on Information Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)getc.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd January 10, 2003
+.Dt GETC 3
+.Os
+.Sh NAME
+.Nm fgetc ,
+.Nm getc ,
+.Nm getc_unlocked ,
+.Nm getchar ,
+.Nm getchar_unlocked ,
+.Nm getw
+.Nd get next character or word from input stream
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdio.h
+.Ft int
+.Fn fgetc "FILE *stream"
+.Ft int
+.Fn getc "FILE *stream"
+.Ft int
+.Fn getc_unlocked "FILE *stream"
+.Ft int
+.Fn getchar void
+.Ft int
+.Fn getchar_unlocked void
+.Ft int
+.Fn getw "FILE *stream"
+.Sh DESCRIPTION
+The
+.Fn fgetc
+function
+obtains the next input character (if present) from the stream pointed at by
+.Fa stream ,
+or the next character pushed back on the stream via
+.Xr ungetc 3 .
+.Pp
+The
+.Fn getc
+function
+acts essentially identically to
+.Fn fgetc ,
+but is a macro that expands in-line.
+.Pp
+The
+.Fn getchar
+function
+is equivalent to
+.Fn getc stdin .
+.Pp
+The
+.Fn getw
+function
+obtains the next
+.Vt int
+(if present)
+from the stream pointed at by
+.Fa stream .
+.Pp
+The
+.Fn getc_unlocked
+and
+.Fn getchar_unlocked
+functions are equivalent to
+.Fn getc
+and
+.Fn getchar
+respectively,
+except that the caller is responsible for locking the stream
+with
+.Xr flockfile 3
+before calling them.
+These functions may be used to avoid the overhead of locking the stream
+for each character, and to avoid input being dispersed among multiple
+threads reading from the same stream.
+.Sh RETURN VALUES
+If successful, these routines return the next requested object
+from the
+.Fa stream .
+Character values are returned as an
+.Vt "unsigned char"
+converted to an
+.Vt int .
+If the stream is at end-of-file or a read error occurs,
+the routines return
+.Dv EOF .
+The routines
+.Xr feof 3
+and
+.Xr ferror 3
+must be used to distinguish between end-of-file and error.
+If an error occurs, the global variable
+.Va errno
+is set to indicate the error.
+The end-of-file condition is remembered, even on a terminal, and all
+subsequent attempts to read will return
+.Dv EOF
+until the condition is cleared with
+.Xr clearerr 3 .
+.Sh SEE ALSO
+.Xr ferror 3 ,
+.Xr flockfile 3 ,
+.Xr fopen 3 ,
+.Xr fread 3 ,
+.Xr getwc 3 ,
+.Xr putc 3 ,
+.Xr ungetc 3
+.Sh STANDARDS
+The
+.Fn fgetc ,
+.Fn getc ,
+and
+.Fn getchar
+functions
+conform to
+.St -isoC .
+The
+.Fn getc_unlocked
+and
+.Fn getchar_unlocked
+functions conform to
+.St -p1003.1-2001 .
+.Sh BUGS
+Since
+.Dv EOF
+is a valid integer value,
+.Xr feof 3
+and
+.Xr ferror 3
+must be used to check for failure after calling
+.Fn getw .
+The size and byte order of an
+.Vt int
+varies from one machine to another, and
+.Fn getw
+is not recommended for portable applications.
diff --git a/lib/libc/stdio/getc.c b/lib/libc/stdio/getc.c
new file mode 100644
index 000000000000..4963c8ce68e7
--- /dev/null
+++ b/lib/libc/stdio/getc.c
@@ -0,0 +1,65 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)getc.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <stdio.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+#include "local.h"
+
+#undef getc
+#undef getc_unlocked
+
+int
+getc(FILE *fp)
+{
+ int retval;
+ FLOCKFILE(fp);
+ /* Orientation set by __sgetc() when buffer is empty. */
+ /* ORIENT(fp, -1); */
+ retval = __sgetc(fp);
+ FUNLOCKFILE(fp);
+ return (retval);
+}
+
+int
+getc_unlocked(FILE *fp)
+{
+
+ return (__sgetc(fp));
+}
diff --git a/lib/libc/stdio/getchar.c b/lib/libc/stdio/getchar.c
new file mode 100644
index 000000000000..2815072f866e
--- /dev/null
+++ b/lib/libc/stdio/getchar.c
@@ -0,0 +1,68 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)getchar.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * A subroutine version of the macro getchar.
+ */
+#include "namespace.h"
+#include <stdio.h>
+#include "un-namespace.h"
+#include "local.h"
+#include "libc_private.h"
+
+#undef getchar
+#undef getchar_unlocked
+
+int
+getchar(void)
+{
+ int retval;
+ FLOCKFILE(stdin);
+ /* Orientation set by __sgetc() when buffer is empty. */
+ /* ORIENT(stdin, -1); */
+ retval = __sgetc(stdin);
+ FUNLOCKFILE(stdin);
+ return (retval);
+}
+
+int
+getchar_unlocked(void)
+{
+
+ return (__sgetc(stdin));
+}
diff --git a/lib/libc/stdio/getdelim.c b/lib/libc/stdio/getdelim.c
new file mode 100644
index 000000000000..7e0b2e2b6edb
--- /dev/null
+++ b/lib/libc/stdio/getdelim.c
@@ -0,0 +1,160 @@
+/*-
+ * Copyright (c) 2009 David Schultz <das@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "un-namespace.h"
+
+#include "libc_private.h"
+#include "local.h"
+
+static inline size_t
+p2roundup(size_t n)
+{
+
+ if (!powerof2(n)) {
+ n--;
+ n |= n >> 1;
+ n |= n >> 2;
+ n |= n >> 4;
+ n |= n >> 8;
+ n |= n >> 16;
+#if SIZE_T_MAX > 0xffffffffU
+ n |= n >> 32;
+#endif
+ n++;
+ }
+ return (n);
+}
+
+/*
+ * Expand *linep to hold len bytes (up to SSIZE_MAX + 1).
+ */
+static inline int
+expandtofit(char ** __restrict linep, size_t len, size_t * __restrict capp)
+{
+ char *newline;
+ size_t newcap;
+
+ if (len > (size_t)SSIZE_MAX + 1) {
+ errno = EOVERFLOW;
+ return (-1);
+ }
+ if (len > *capp) {
+ if (len == (size_t)SSIZE_MAX + 1) /* avoid overflow */
+ newcap = (size_t)SSIZE_MAX + 1;
+ else
+ newcap = p2roundup(len);
+ newline = realloc(*linep, newcap);
+ if (newline == NULL)
+ return (-1);
+ *capp = newcap;
+ *linep = newline;
+ }
+ return (0);
+}
+
+/*
+ * Append the src buffer to the *dstp buffer. The buffers are of
+ * length srclen and *dstlenp, respectively, and dst has space for
+ * *dstlenp bytes. After the call, *dstlenp and *dstcapp are updated
+ * appropriately, and *dstp is reallocated if needed. Returns 0 on
+ * success, -1 on allocation failure.
+ */
+static int
+sappend(char ** __restrict dstp, size_t * __restrict dstlenp,
+ size_t * __restrict dstcapp, char * __restrict src, size_t srclen)
+{
+
+ /* ensure room for srclen + dstlen + terminating NUL */
+ if (expandtofit(dstp, srclen + *dstlenp + 1, dstcapp))
+ return (-1);
+ memcpy(*dstp + *dstlenp, src, srclen);
+ *dstlenp += srclen;
+ return (0);
+}
+
+ssize_t
+getdelim(char ** __restrict linep, size_t * __restrict linecapp, int delim,
+ FILE * __restrict fp)
+{
+ u_char *endp;
+ size_t linelen;
+
+ FLOCKFILE(fp);
+ ORIENT(fp, -1);
+
+ if (linep == NULL || linecapp == NULL) {
+ errno = EINVAL;
+ goto error;
+ }
+
+ if (*linep == NULL)
+ *linecapp = 0;
+
+ if (fp->_r <= 0 && __srefill(fp)) {
+ /* If fp is at EOF already, we just need space for the NUL. */
+ if (!__sfeof(fp) || expandtofit(linep, 1, linecapp))
+ goto error;
+ FUNLOCKFILE(fp);
+ (*linep)[0] = '\0';
+ return (-1);
+ }
+
+ linelen = 0;
+ while ((endp = memchr(fp->_p, delim, fp->_r)) == NULL) {
+ if (sappend(linep, &linelen, linecapp, fp->_p, fp->_r))
+ goto error;
+ if (__srefill(fp)) {
+ if (!__sfeof(fp))
+ goto error;
+ goto done; /* hit EOF */
+ }
+ }
+ endp++; /* snarf the delimiter, too */
+ if (sappend(linep, &linelen, linecapp, fp->_p, endp - fp->_p))
+ goto error;
+ fp->_r -= endp - fp->_p;
+ fp->_p = endp;
+done:
+ /* Invariant: *linep has space for at least linelen+1 bytes. */
+ (*linep)[linelen] = '\0';
+ FUNLOCKFILE(fp);
+ return (linelen);
+
+error:
+ fp->_flags |= __SERR;
+ FUNLOCKFILE(fp);
+ return (-1);
+}
diff --git a/lib/libc/stdio/getline.3 b/lib/libc/stdio/getline.3
new file mode 100644
index 000000000000..0b8bf634a7c8
--- /dev/null
+++ b/lib/libc/stdio/getline.3
@@ -0,0 +1,137 @@
+.\" Copyright (c) 2009 David Schultz <das@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd July 30, 2016
+.Dt GETLINE 3
+.Os
+.Sh NAME
+.Nm getdelim ,
+.Nm getline
+.Nd get a line from a stream
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdio.h
+.Ft ssize_t
+.Fn getdelim "char ** restrict linep" "size_t * restrict linecapp" "int delimiter" " FILE * restrict stream"
+.Ft ssize_t
+.Fn getline "char ** restrict linep" "size_t * restrict linecapp" " FILE * restrict stream"
+.Sh DESCRIPTION
+The
+.Fn getdelim
+function reads a line from
+.Fa stream ,
+delimited by the character
+.Fa delimiter .
+The
+.Fn getline
+function is equivalent to
+.Fn getdelim
+with the newline character as the delimiter.
+The delimiter character is included as part of the line, unless
+the end of the file is reached.
+.Pp
+The caller may provide a pointer to a malloced buffer for the line in
+.Fa *linep ,
+and the capacity of that buffer in
+.Fa *linecapp .
+These functions expand the buffer as needed, as if via
+.Fn realloc .
+If
+.Fa linep
+points to a
+.Dv NULL
+pointer, a new buffer will be allocated.
+In either case,
+.Fa *linep
+and
+.Fa *linecapp
+will be updated accordingly.
+.Sh RETURN VALUES
+The
+.Fn getdelim
+and
+.Fn getline
+functions return the number of characters stored in the buffer, excluding the
+terminating
+.Dv NUL
+character.
+The value \-1 is returned if an error occurs, or if end-of-file is reached.
+.Sh EXAMPLES
+The following code fragment reads lines from a file and
+writes them to standard output.
+The
+.Fn fwrite
+function is used in case the line contains embedded
+.Dv NUL
+characters.
+.Bd -literal -offset indent
+char *line = NULL;
+size_t linecap = 0;
+ssize_t linelen;
+while ((linelen = getline(&line, &linecap, fp)) > 0)
+ fwrite(line, linelen, 1, stdout);
+free(line);
+.Ed
+.Sh ERRORS
+These functions may fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Either
+.Fa linep
+or
+.Fa linecapp
+is
+.Dv NULL .
+.It Bq Er EOVERFLOW
+No delimiter was found in the first
+.Dv SSIZE_MAX
+characters.
+.El
+.Pp
+These functions may also fail due to any of the errors specified for
+.Fn fgets
+and
+.Fn malloc .
+.Sh SEE ALSO
+.Xr fgetln 3 ,
+.Xr fgets 3 ,
+.Xr malloc 3
+.Sh STANDARDS
+The
+.Fn getdelim
+and
+.Fn getline
+functions conform to
+.St -p1003.1-2008 .
+.Sh HISTORY
+These routines first appeared in
+.Fx 8.0 .
+.Sh BUGS
+There are no wide character versions of
+.Fn getdelim
+or
+.Fn getline .
diff --git a/lib/libc/stdio/getline.c b/lib/libc/stdio/getline.c
new file mode 100644
index 000000000000..773b8f082983
--- /dev/null
+++ b/lib/libc/stdio/getline.c
@@ -0,0 +1,38 @@
+/*-
+ * Copyright (c) 2009 David Schultz <das@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+
+ssize_t
+getline(char ** __restrict linep, size_t * __restrict linecapp,
+ FILE * __restrict fp)
+{
+
+ return (getdelim(linep, linecapp, '\n', fp));
+}
diff --git a/lib/libc/stdio/gets.c b/lib/libc/stdio/gets.c
new file mode 100644
index 000000000000..c9438515323a
--- /dev/null
+++ b/lib/libc/stdio/gets.c
@@ -0,0 +1,76 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)gets.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/cdefs.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+#include "local.h"
+
+__warn_references(gets, "warning: this program uses gets(), which is unsafe.");
+
+char *
+gets(char *buf)
+{
+ int c;
+ char *s;
+ static int warned;
+ static const char w[] =
+ "warning: this program uses gets(), which is unsafe.\n";
+
+ FLOCKFILE(stdin);
+ ORIENT(stdin, -1);
+ if (!warned) {
+ (void) _write(STDERR_FILENO, w, sizeof(w) - 1);
+ warned = 1;
+ }
+ for (s = buf; (c = __sgetc(stdin)) != '\n';)
+ if (c == EOF)
+ if (s == buf) {
+ FUNLOCKFILE(stdin);
+ return (NULL);
+ } else
+ break;
+ else
+ *s++ = c;
+ *s = 0;
+ FUNLOCKFILE(stdin);
+ return (buf);
+}
diff --git a/lib/libc/stdio/getw.c b/lib/libc/stdio/getw.c
new file mode 100644
index 000000000000..ed0313eb60c2
--- /dev/null
+++ b/lib/libc/stdio/getw.c
@@ -0,0 +1,47 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)getw.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+
+int
+getw(FILE *fp)
+{
+ int x;
+
+ return (fread((void *)&x, sizeof(x), 1, fp) == 1 ? x : EOF);
+}
diff --git a/lib/libc/stdio/getwc.3 b/lib/libc/stdio/getwc.3
new file mode 100644
index 000000000000..bc4218a5bd7d
--- /dev/null
+++ b/lib/libc/stdio/getwc.3
@@ -0,0 +1,114 @@
+.\" $NetBSD: getwc.3,v 1.3 2002/02/07 07:00:26 ross Exp $
+.\"
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek and the American National Standards Committee X3,
+.\" on Information Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)getc.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd March 3, 2004
+.Dt GETWC 3
+.Os
+.Sh NAME
+.Nm fgetwc ,
+.Nm getwc ,
+.Nm getwchar
+.Nd get next wide character from input stream
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdio.h
+.In wchar.h
+.Ft wint_t
+.Fn fgetwc "FILE *stream"
+.Ft wint_t
+.Fn getwc "FILE *stream"
+.Ft wint_t
+.Fn getwchar void
+.Sh DESCRIPTION
+The
+.Fn fgetwc
+function
+obtains the next input wide character (if present) from the stream pointed at by
+.Fa stream ,
+or the next character pushed back on the stream via
+.Xr ungetwc 3 .
+.Pp
+The
+.Fn getwc
+function
+acts essentially identically to
+.Fn fgetwc .
+.Pp
+The
+.Fn getwchar
+function
+is equivalent to
+.Fn getwc
+with the argument
+.Dv stdin .
+.Sh RETURN VALUES
+If successful, these routines return the next wide character
+from the
+.Fa stream .
+If the stream is at end-of-file or a read error occurs,
+the routines return
+.Dv WEOF .
+The routines
+.Xr feof 3
+and
+.Xr ferror 3
+must be used to distinguish between end-of-file and error.
+If an error occurs, the global variable
+.Va errno
+is set to indicate the error.
+The end-of-file condition is remembered, even on a terminal, and all
+subsequent attempts to read will return
+.Dv WEOF
+until the condition is cleared with
+.Xr clearerr 3 .
+.Sh SEE ALSO
+.Xr ferror 3 ,
+.Xr fopen 3 ,
+.Xr fread 3 ,
+.Xr getc 3 ,
+.Xr putwc 3 ,
+.Xr stdio 3 ,
+.Xr ungetwc 3
+.Sh STANDARDS
+The
+.Fn fgetwc ,
+.Fn getwc
+and
+.Fn getwchar
+functions
+conform to
+.St -isoC-99 .
diff --git a/lib/libc/stdio/getwc.c b/lib/libc/stdio/getwc.c
new file mode 100644
index 000000000000..666350bba923
--- /dev/null
+++ b/lib/libc/stdio/getwc.c
@@ -0,0 +1,60 @@
+/*-
+ * Copyright (c) 2002 Tim J. Robbins.
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 "namespace.h"
+#include <stdio.h>
+#include <wchar.h>
+#include <xlocale.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+#include "local.h"
+
+#undef getwc
+
+/*
+ * Synonym for fgetwc(). The only difference is that getwc(), if it is a
+ * macro, may evaluate `fp' more than once.
+ */
+wint_t
+getwc(FILE *fp)
+{
+
+ return (fgetwc(fp));
+}
+wint_t
+getwc_l(FILE *fp, locale_t locale)
+{
+
+ return (fgetwc_l(fp, locale));
+}
diff --git a/lib/libc/stdio/getwchar.c b/lib/libc/stdio/getwchar.c
new file mode 100644
index 000000000000..bc3b8a64c662
--- /dev/null
+++ b/lib/libc/stdio/getwchar.c
@@ -0,0 +1,57 @@
+/*-
+ * Copyright (c) 2002 Tim J. Robbins.
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 "namespace.h"
+#include <stdio.h>
+#include <wchar.h>
+#include <xlocale.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+#include "local.h"
+
+#undef getwchar
+
+/*
+ * Synonym for fgetwc(stdin).
+ */
+wint_t
+getwchar(void)
+{
+ return (fgetwc(stdin));
+}
+wint_t
+getwchar_l(locale_t locale)
+{
+ return (fgetwc_l(stdin, locale));
+}
diff --git a/lib/libc/stdio/glue.h b/lib/libc/stdio/glue.h
new file mode 100644
index 000000000000..1fef1404663a
--- /dev/null
+++ b/lib/libc/stdio/glue.h
@@ -0,0 +1,45 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)glue.h 8.1 (Berkeley) 6/4/93
+ * $FreeBSD$
+ */
+
+/*
+ * The first few FILEs are statically allocated; others are dynamically
+ * allocated and linked in via this glue structure.
+ */
+struct glue {
+ struct glue *next;
+ int niobs;
+ FILE *iobs;
+};
+extern struct glue __sglue;
diff --git a/lib/libc/stdio/local.h b/lib/libc/stdio/local.h
new file mode 100644
index 000000000000..7168f6264d73
--- /dev/null
+++ b/lib/libc/stdio/local.h
@@ -0,0 +1,140 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)local.h 8.3 (Berkeley) 7/3/94
+ * $FreeBSD$
+ */
+
+#include <sys/types.h> /* for off_t */
+#include <pthread.h>
+#include <string.h>
+#include <wchar.h>
+#include <locale.h>
+
+/*
+ * Information local to this implementation of stdio,
+ * in particular, macros and private variables.
+ */
+
+extern int _sread(FILE *, char *, int);
+extern int _swrite(FILE *, char const *, int);
+extern fpos_t _sseek(FILE *, fpos_t, int);
+extern int _ftello(FILE *, fpos_t *);
+extern int _fseeko(FILE *, off_t, int, int);
+extern int __fflush(FILE *fp);
+extern void __fcloseall(void);
+extern wint_t __fgetwc_mbs(FILE *, mbstate_t *, int *, locale_t);
+extern wint_t __fputwc(wchar_t, FILE *, locale_t);
+extern int __sflush(FILE *);
+extern FILE *__sfp(void);
+extern int __slbexpand(FILE *, size_t);
+extern int __srefill(FILE *);
+extern int __sread(void *, char *, int);
+extern int __swrite(void *, char const *, int);
+extern fpos_t __sseek(void *, fpos_t, int);
+extern int __sclose(void *);
+extern void __sinit(void);
+extern void _cleanup(void);
+extern void __smakebuf(FILE *);
+extern int __swhatbuf(FILE *, size_t *, int *);
+extern int _fwalk(int (*)(FILE *));
+extern int __svfscanf(FILE *, locale_t, const char *, __va_list);
+extern int __swsetup(FILE *);
+extern int __sflags(const char *, int *);
+extern int __ungetc(int, FILE *);
+extern wint_t __ungetwc(wint_t, FILE *, locale_t);
+extern int __vfprintf(FILE *, locale_t, const char *, __va_list);
+extern int __vfscanf(FILE *, const char *, __va_list);
+extern int __vfwprintf(FILE *, locale_t, const wchar_t *, __va_list);
+extern int __vfwscanf(FILE * __restrict, locale_t, const wchar_t * __restrict,
+ __va_list);
+extern size_t __fread(void * __restrict buf, size_t size, size_t count,
+ FILE * __restrict fp);
+extern int __sdidinit;
+
+static inline wint_t
+__fgetwc(FILE *fp, locale_t locale)
+{
+ int nread;
+
+ return (__fgetwc_mbs(fp, &fp->_mbstate, &nread, locale));
+}
+
+/*
+ * Prepare the given FILE for writing, and return 0 iff it
+ * can be written now. Otherwise, return EOF and set errno.
+ */
+#define prepwrite(fp) \
+ ((((fp)->_flags & __SWR) == 0 || \
+ ((fp)->_bf._base == NULL && ((fp)->_flags & __SSTR) == 0)) && \
+ __swsetup(fp))
+
+/*
+ * Test whether the given stdio file has an active ungetc buffer;
+ * release such a buffer, without restoring ordinary unread data.
+ */
+#define HASUB(fp) ((fp)->_ub._base != NULL)
+#define FREEUB(fp) { \
+ if ((fp)->_ub._base != (fp)->_ubuf) \
+ free((char *)(fp)->_ub._base); \
+ (fp)->_ub._base = NULL; \
+}
+
+/*
+ * test for an fgetln() buffer.
+ */
+#define HASLB(fp) ((fp)->_lb._base != NULL)
+#define FREELB(fp) { \
+ free((char *)(fp)->_lb._base); \
+ (fp)->_lb._base = NULL; \
+}
+
+/*
+ * Structure initializations for 'fake' FILE objects.
+ */
+#define FAKE_FILE { \
+ ._file = -1, \
+ ._fl_mutex = PTHREAD_MUTEX_INITIALIZER, \
+}
+
+/*
+ * Set the orientation for a stream. If o > 0, the stream has wide-
+ * orientation. If o < 0, the stream has byte-orientation.
+ */
+#define ORIENT(fp, o) do { \
+ if ((fp)->_orientation == 0) \
+ (fp)->_orientation = (o); \
+} while (0)
diff --git a/lib/libc/stdio/makebuf.c b/lib/libc/stdio/makebuf.c
new file mode 100644
index 000000000000..a92087e0eae7
--- /dev/null
+++ b/lib/libc/stdio/makebuf.c
@@ -0,0 +1,116 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)makebuf.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "un-namespace.h"
+
+#include "libc_private.h"
+#include "local.h"
+
+/*
+ * Allocate a file buffer, or switch to unbuffered I/O.
+ * Per the ANSI C standard, ALL tty devices default to line buffered.
+ *
+ * As a side effect, we set __SOPT or __SNPT (en/dis-able fseek
+ * optimisation) right after the _fstat() that finds the buffer size.
+ */
+void
+__smakebuf(FILE *fp)
+{
+ void *p;
+ int flags;
+ size_t size;
+ int couldbetty;
+
+ if (fp->_flags & __SNBF) {
+ fp->_bf._base = fp->_p = fp->_nbuf;
+ fp->_bf._size = 1;
+ return;
+ }
+ flags = __swhatbuf(fp, &size, &couldbetty);
+ if ((p = malloc(size)) == NULL) {
+ fp->_flags |= __SNBF;
+ fp->_bf._base = fp->_p = fp->_nbuf;
+ fp->_bf._size = 1;
+ return;
+ }
+ __cleanup = _cleanup;
+ flags |= __SMBF;
+ fp->_bf._base = fp->_p = p;
+ fp->_bf._size = size;
+ if (couldbetty && isatty(fp->_file))
+ flags |= __SLBF;
+ fp->_flags |= flags;
+}
+
+/*
+ * Internal routine to determine `proper' buffering for a file.
+ */
+int
+__swhatbuf(FILE *fp, size_t *bufsize, int *couldbetty)
+{
+ struct stat st;
+
+ if (fp->_file < 0 || _fstat(fp->_file, &st) < 0) {
+ *couldbetty = 0;
+ *bufsize = BUFSIZ;
+ return (__SNPT);
+ }
+
+ /* could be a tty iff it is a character device */
+ *couldbetty = (st.st_mode & S_IFMT) == S_IFCHR;
+ if (st.st_blksize <= 0) {
+ *bufsize = BUFSIZ;
+ return (__SNPT);
+ }
+
+ /*
+ * Optimise fseek() only if it is a regular file. (The test for
+ * __sseek is mainly paranoia.) It is safe to set _blksize
+ * unconditionally; it will only be used if __SOPT is also set.
+ */
+ *bufsize = st.st_blksize;
+ fp->_blksize = st.st_blksize;
+ return ((st.st_mode & S_IFMT) == S_IFREG && fp->_seek == __sseek ?
+ __SOPT : __SNPT);
+}
diff --git a/lib/libc/stdio/mktemp.3 b/lib/libc/stdio/mktemp.3
new file mode 100644
index 000000000000..816a6b6fcd08
--- /dev/null
+++ b/lib/libc/stdio/mktemp.3
@@ -0,0 +1,326 @@
+.\" Copyright (c) 1989, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)mktemp.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd August 8, 2013
+.Dt MKTEMP 3
+.Os
+.Sh NAME
+.Nm mktemp
+.Nd make temporary file name (unique)
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft char *
+.Fn mktemp "char *template"
+.Ft int
+.Fn mkstemp "char *template"
+.Ft int
+.Fn mkostemp "char *template" "int oflags"
+.Ft int
+.Fn mkostemps "char *template" "int suffixlen" "int oflags"
+.Ft char *
+.Fn mkdtemp "char *template"
+.In unistd.h
+.Ft int
+.Fn mkstemps "char *template" "int suffixlen"
+.Sh DESCRIPTION
+The
+.Fn mktemp
+function
+takes the given file name template and overwrites a portion of it
+to create a file name.
+This file name is guaranteed not to exist at the time of function invocation
+and is suitable for use
+by the application.
+The template may be any file name with some number of
+.Ql X Ns s
+appended
+to it, for example
+.Pa /tmp/temp.XXXXXX .
+The trailing
+.Ql X Ns s
+are replaced with a
+unique alphanumeric combination.
+The number of unique file names
+.Fn mktemp
+can return depends on the number of
+.Ql X Ns s
+provided; six
+.Ql X Ns s
+will
+result in
+.Fn mktemp
+selecting one of 56800235584 (62 ** 6) possible temporary file names.
+.Pp
+The
+.Fn mkstemp
+function
+makes the same replacement to the template and creates the template file,
+mode 0600, returning a file descriptor opened for reading and writing.
+This avoids the race between testing for a file's existence and opening it
+for use.
+.Pp
+The
+.Fn mkostemp
+function
+is like
+.Fn mkstemp
+but allows specifying additional
+.Xr open 2
+flags (defined in
+.In fcntl.h ) .
+The permitted flags are
+.Dv O_APPEND ,
+.Dv O_DIRECT ,
+.Dv O_SHLOCK ,
+.Dv O_EXLOCK ,
+.Dv O_SYNC
+and
+.Dv O_CLOEXEC .
+.Pp
+The
+.Fn mkstemps
+and
+.Fn mkostemps
+functions act the same as
+.Fn mkstemp
+and
+.Fn mkostemp
+respectively,
+except they permit a suffix to exist in the template.
+The template should be of the form
+.Pa /tmp/tmpXXXXXXsuffix .
+The
+.Fn mkstemps
+and
+.Fn mkostemps
+function
+are told the length of the suffix string.
+.Pp
+The
+.Fn mkdtemp
+function makes the same replacement to the template as in
+.Fn mktemp
+and creates the template directory, mode 0700.
+.Sh RETURN VALUES
+The
+.Fn mktemp
+and
+.Fn mkdtemp
+functions return a pointer to the template on success and
+.Dv NULL
+on failure.
+The
+.Fn mkstemp ,
+.Fn mkostemp
+.Fn mkstemps
+and
+.Fn mkostemps
+functions
+return \-1 if no suitable file could be created.
+If either call fails an error code is placed in the global variable
+.Va errno .
+.Sh ERRORS
+The
+.Fn mkstemp ,
+.Fn mkostemp ,
+.Fn mkstemps ,
+.Fn mkostemps
+and
+.Fn mkdtemp
+functions
+may set
+.Va errno
+to one of the following values:
+.Bl -tag -width Er
+.It Bq Er ENOTDIR
+The pathname portion of the template is not an existing directory.
+.El
+.Pp
+The
+.Fn mkostemp
+and
+.Fn mkostemps
+functions
+may also set
+.Va errno
+to the following value:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa oflags
+argument is invalid.
+.El
+.Pp
+The
+.Fn mkstemp ,
+.Fn mkostemp ,
+.Fn mkstemps ,
+.Fn mkostemps
+and
+.Fn mkdtemp
+functions
+may also set
+.Va errno
+to any value specified by the
+.Xr stat 2
+function.
+.Pp
+The
+.Fn mkstemp ,
+.Fn mkostemp ,
+.Fn mkstemps
+and
+.Fn mkostemps
+functions
+may also set
+.Va errno
+to any value specified by the
+.Xr open 2
+function.
+.Pp
+The
+.Fn mkdtemp
+function
+may also set
+.Va errno
+to any value specified by the
+.Xr mkdir 2
+function.
+.Sh NOTES
+A common problem that results in a core dump is that the programmer
+passes in a read-only string to
+.Fn mktemp ,
+.Fn mkstemp ,
+.Fn mkstemps
+or
+.Fn mkdtemp .
+This is common with programs that were developed before
+.St -isoC
+compilers were common.
+For example, calling
+.Fn mkstemp
+with an argument of
+.Qq /tmp/tempfile.XXXXXX
+will result in a core dump due to
+.Fn mkstemp
+attempting to modify the string constant that was given.
+.Pp
+The
+.Fn mkdtemp ,
+.Fn mkstemp
+and
+.Fn mktemp
+function prototypes are also available from
+.In unistd.h .
+.Sh SEE ALSO
+.Xr chmod 2 ,
+.Xr getpid 2 ,
+.Xr mkdir 2 ,
+.Xr open 2 ,
+.Xr stat 2
+.Sh STANDARDS
+The
+.Fn mkstemp
+and
+.Fn mkdtemp
+functions are expected to conform to
+.St -p1003.1-2008 .
+The
+.Fn mktemp
+function is expected to conform to
+.St -p1003.1-2001
+and is not specified by
+.St -p1003.1-2008 .
+The
+.Fn mkostemp ,
+.Fn mkstemps
+and
+.Fn mkostemps
+functions do not conform to any standard.
+.Sh HISTORY
+A
+.Fn mktemp
+function appeared in
+.At v7 .
+The
+.Fn mkstemp
+function appeared in
+.Bx 4.4 .
+The
+.Fn mkdtemp
+function first appeared in
+.Ox 2.2 ,
+and later in
+.Fx 3.2 .
+The
+.Fn mkstemps
+function first appeared in
+.Ox 2.4 ,
+and later in
+.Fx 3.4 .
+The
+.Fn mkostemp
+and
+.Fn mkostemps
+functions appeared in
+.Fx 10.0 .
+.Sh BUGS
+This family of functions produces filenames which can be guessed,
+though the risk is minimized when large numbers of
+.Ql X Ns s
+are used to
+increase the number of possible temporary filenames.
+This makes the race in
+.Fn mktemp ,
+between testing for a file's existence (in the
+.Fn mktemp
+function call)
+and opening it for use
+(later in the user application)
+particularly dangerous from a security perspective.
+Whenever it is possible,
+.Fn mkstemp
+or
+.Fn mkostemp
+should be used instead, since it does not have the race condition.
+If
+.Fn mkstemp
+cannot be used, the filename created by
+.Fn mktemp
+should be created using the
+.Dv O_EXCL
+flag to
+.Xr open 2
+and the return status of the call should be tested for failure.
+This will ensure that the program does not continue blindly
+in the event that an attacker has already created the file
+with the intention of manipulating or reading its contents.
diff --git a/lib/libc/stdio/mktemp.c b/lib/libc/stdio/mktemp.c
new file mode 100644
index 000000000000..6fc552a18b2f
--- /dev/null
+++ b/lib/libc/stdio/mktemp.c
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 1987, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)mktemp.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+char *_mktemp(char *);
+
+static int _gettemp(char *, int *, int, int, int);
+
+static const unsigned char padchar[] =
+"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+int
+mkostemps(char *path, int slen, int oflags)
+{
+ int fd;
+
+ return (_gettemp(path, &fd, 0, slen, oflags) ? fd : -1);
+}
+
+int
+mkstemps(char *path, int slen)
+{
+ int fd;
+
+ return (_gettemp(path, &fd, 0, slen, 0) ? fd : -1);
+}
+
+int
+mkostemp(char *path, int oflags)
+{
+ int fd;
+
+ return (_gettemp(path, &fd, 0, 0, oflags) ? fd : -1);
+}
+
+int
+mkstemp(char *path)
+{
+ int fd;
+
+ return (_gettemp(path, &fd, 0, 0, 0) ? fd : -1);
+}
+
+char *
+mkdtemp(char *path)
+{
+ return (_gettemp(path, (int *)NULL, 1, 0, 0) ? path : (char *)NULL);
+}
+
+char *
+_mktemp(char *path)
+{
+ return (_gettemp(path, (int *)NULL, 0, 0, 0) ? path : (char *)NULL);
+}
+
+__warn_references(mktemp,
+ "warning: mktemp() possibly used unsafely; consider using mkstemp()");
+
+char *
+mktemp(char *path)
+{
+ return (_mktemp(path));
+}
+
+static int
+_gettemp(char *path, int *doopen, int domkdir, int slen, int oflags)
+{
+ char *start, *trv, *suffp, *carryp;
+ char *pad;
+ struct stat sbuf;
+ int rval;
+ uint32_t rand;
+ char carrybuf[MAXPATHLEN];
+
+ if ((doopen != NULL && domkdir) || slen < 0 ||
+ (oflags & ~(O_APPEND | O_DIRECT | O_SHLOCK | O_EXLOCK | O_SYNC |
+ O_CLOEXEC)) != 0) {
+ errno = EINVAL;
+ return (0);
+ }
+
+ for (trv = path; *trv != '\0'; ++trv)
+ ;
+ if (trv - path >= MAXPATHLEN) {
+ errno = ENAMETOOLONG;
+ return (0);
+ }
+ trv -= slen;
+ suffp = trv;
+ --trv;
+ if (trv < path || NULL != strchr(suffp, '/')) {
+ errno = EINVAL;
+ return (0);
+ }
+
+ /* Fill space with random characters */
+ while (trv >= path && *trv == 'X') {
+ rand = arc4random_uniform(sizeof(padchar) - 1);
+ *trv-- = padchar[rand];
+ }
+ start = trv + 1;
+
+ /* save first combination of random characters */
+ memcpy(carrybuf, start, suffp - start);
+
+ /*
+ * check the target directory.
+ */
+ if (doopen != NULL || domkdir) {
+ for (; trv > path; --trv) {
+ if (*trv == '/') {
+ *trv = '\0';
+ rval = stat(path, &sbuf);
+ *trv = '/';
+ if (rval != 0)
+ return (0);
+ if (!S_ISDIR(sbuf.st_mode)) {
+ errno = ENOTDIR;
+ return (0);
+ }
+ break;
+ }
+ }
+ }
+
+ for (;;) {
+ if (doopen) {
+ if ((*doopen =
+ _open(path, O_CREAT|O_EXCL|O_RDWR|oflags, 0600)) >=
+ 0)
+ return (1);
+ if (errno != EEXIST)
+ return (0);
+ } else if (domkdir) {
+ if (mkdir(path, 0700) == 0)
+ return (1);
+ if (errno != EEXIST)
+ return (0);
+ } else if (lstat(path, &sbuf))
+ return (errno == ENOENT);
+
+ /* If we have a collision, cycle through the space of filenames */
+ for (trv = start, carryp = carrybuf;;) {
+ /* have we tried all possible permutations? */
+ if (trv == suffp)
+ return (0); /* yes - exit with EEXIST */
+ pad = strchr(padchar, *trv);
+ if (pad == NULL) {
+ /* this should never happen */
+ errno = EIO;
+ return (0);
+ }
+ /* increment character */
+ *trv = (*++pad == '\0') ? padchar[0] : *pad;
+ /* carry to next position? */
+ if (*trv == *carryp) {
+ /* increment position and loop */
+ ++trv;
+ ++carryp;
+ } else {
+ /* try with new name */
+ break;
+ }
+ }
+ }
+ /*NOTREACHED*/
+}
diff --git a/lib/libc/stdio/open_memstream.3 b/lib/libc/stdio/open_memstream.3
new file mode 100644
index 000000000000..8e2c1e9e057f
--- /dev/null
+++ b/lib/libc/stdio/open_memstream.3
@@ -0,0 +1,155 @@
+.\" Copyright (c) 2013 Hudson River Trading LLC
+.\" Written by: John H. Baldwin <jhb@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd August 1, 2015
+.Dt OPEN_MEMSTREAM 3
+.Os
+.Sh NAME
+.Nm open_memstream ,
+.Nm open_wmemstream
+.Nd dynamic memory buffer stream open functions
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdio.h
+.Ft FILE *
+.Fn open_memstream "char **bufp" "size_t *sizep"
+.In wchar.h
+.Ft FILE *
+.Fn open_wmemstream "wchar_t **bufp" "size_t *sizep"
+.Sh DESCRIPTION
+The
+.Fn open_memstream
+and
+.Fn open_wmemstream
+functions create a write-only, seekable stream backed by a dynamically
+allocated memory buffer.
+The
+.Fn open_memstream
+function creates a byte-oriented stream,
+while the
+.Fn open_wmemstream
+function creates a wide-oriented stream.
+.Pp
+Each stream maintains a current position and size.
+Initially,
+the position and size are set to zero.
+Each write begins at the current position and advances it the number of
+successfully written bytes for
+.Fn open_memstream
+or wide characters for
+.Fn open_wmemstream .
+If a write moves the current position beyond the length of the buffer,
+the length of the buffer is extended and a null character is appended to the
+buffer.
+.Pp
+A stream's buffer always contains a null character at the end of the buffer
+that is not included in the current length.
+.Pp
+If a stream's current position is moved beyond the current length via a
+seek operation and a write is performed,
+the characters between the current length and the current position are filled
+with null characters before the write is performed.
+.Pp
+After a successful call to
+.Xr fclose 3
+or
+.Xr fflush 3 ,
+the pointer referenced by
+.Fa bufp
+will contain the start of the memory buffer and the variable referenced by
+.Fa sizep
+will contain the smaller of the current position and the current buffer length.
+.Pp
+After a successful call to
+.Xr fflush 3 ,
+the pointer referenced by
+.Fa bufp
+and the variable referenced by
+.Fa sizep
+are only valid until the next write operation or a call to
+.Xr fclose 3 .
+.Pp
+Once a stream is closed,
+the allocated buffer referenced by
+.Fa bufp
+should be released via a call to
+.Xr free 3
+when it is no longer needed.
+.Sh IMPLEMENTATION NOTES
+Internally all I/O streams are effectively byte-oriented,
+so using wide-oriented operations to write to a stream opened via
+.Fn open_wmemstream
+results in wide characters being expanded to a stream of multibyte characters
+in stdio's internal buffers.
+These multibyte characters are then converted back to wide characters when
+written into the stream.
+As a result,
+the wide-oriented streams maintain an internal multibyte character conversion
+state that is cleared on any seek opertion that changes the current position.
+This should have no effect as long as wide-oriented output operations are used
+on a wide-oriented stream.
+.Sh RETURN VALUES
+Upon successful completion,
+.Fn open_memstream
+and
+.Fn open_wmemstream
+return a
+.Tn FILE
+pointer.
+Otherwise,
+.Dv NULL
+is returned and the global variable
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa bufp
+or
+.Fa sizep
+argument was
+.Dv NULL .
+.It Bq Er ENOMEM
+Memory for the stream or buffer could not be allocated.
+.El
+.Sh SEE ALSO
+.Xr fclose 3 ,
+.Xr fflush 3 ,
+.Xr fopen 3 ,
+.Xr free 3 ,
+.Xr fseek 3 ,
+.Xr stdio 3 ,
+.Xr sbuf 9
+.Sh STANDARDS
+The
+.Fn open_memstream
+and
+.Fn open_wmemstream
+functions conform to
+.St -p1003.1-2008 .
diff --git a/lib/libc/stdio/open_memstream.c b/lib/libc/stdio/open_memstream.c
new file mode 100644
index 000000000000..a7e0bae9ca3a
--- /dev/null
+++ b/lib/libc/stdio/open_memstream.c
@@ -0,0 +1,212 @@
+/*-
+ * Copyright (c) 2013 Hudson River Trading LLC
+ * Written by: John H. Baldwin <jhb@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#ifdef DEBUG
+#include <stdint.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include "un-namespace.h"
+
+/* XXX: There is no FPOS_MAX. This assumes fpos_t is an off_t. */
+#define FPOS_MAX OFF_MAX
+
+struct memstream {
+ char **bufp;
+ size_t *sizep;
+ ssize_t len;
+ fpos_t offset;
+};
+
+static int
+memstream_grow(struct memstream *ms, fpos_t newoff)
+{
+ char *buf;
+ ssize_t newsize;
+
+ if (newoff < 0 || newoff >= SSIZE_MAX)
+ newsize = SSIZE_MAX - 1;
+ else
+ newsize = newoff;
+ if (newsize > ms->len) {
+ buf = realloc(*ms->bufp, newsize + 1);
+ if (buf != NULL) {
+#ifdef DEBUG
+ fprintf(stderr, "MS: %p growing from %zd to %zd\n",
+ ms, ms->len, newsize);
+#endif
+ memset(buf + ms->len + 1, 0, newsize - ms->len);
+ *ms->bufp = buf;
+ ms->len = newsize;
+ return (1);
+ }
+ return (0);
+ }
+ return (1);
+}
+
+static void
+memstream_update(struct memstream *ms)
+{
+
+ assert(ms->len >= 0 && ms->offset >= 0);
+ *ms->sizep = ms->len < ms->offset ? ms->len : ms->offset;
+}
+
+static int
+memstream_write(void *cookie, const char *buf, int len)
+{
+ struct memstream *ms;
+ ssize_t tocopy;
+
+ ms = cookie;
+ if (!memstream_grow(ms, ms->offset + len))
+ return (-1);
+ tocopy = ms->len - ms->offset;
+ if (len < tocopy)
+ tocopy = len;
+ memcpy(*ms->bufp + ms->offset, buf, tocopy);
+ ms->offset += tocopy;
+ memstream_update(ms);
+#ifdef DEBUG
+ fprintf(stderr, "MS: write(%p, %d) = %zd\n", ms, len, tocopy);
+#endif
+ return (tocopy);
+}
+
+static fpos_t
+memstream_seek(void *cookie, fpos_t pos, int whence)
+{
+ struct memstream *ms;
+#ifdef DEBUG
+ fpos_t old;
+#endif
+
+ ms = cookie;
+#ifdef DEBUG
+ old = ms->offset;
+#endif
+ switch (whence) {
+ case SEEK_SET:
+ /* _fseeko() checks for negative offsets. */
+ assert(pos >= 0);
+ ms->offset = pos;
+ break;
+ case SEEK_CUR:
+ /* This is only called by _ftello(). */
+ assert(pos == 0);
+ break;
+ case SEEK_END:
+ if (pos < 0) {
+ if (pos + ms->len < 0) {
+#ifdef DEBUG
+ fprintf(stderr,
+ "MS: bad SEEK_END: pos %jd, len %zd\n",
+ (intmax_t)pos, ms->len);
+#endif
+ errno = EINVAL;
+ return (-1);
+ }
+ } else {
+ if (FPOS_MAX - ms->len < pos) {
+#ifdef DEBUG
+ fprintf(stderr,
+ "MS: bad SEEK_END: pos %jd, len %zd\n",
+ (intmax_t)pos, ms->len);
+#endif
+ errno = EOVERFLOW;
+ return (-1);
+ }
+ }
+ ms->offset = ms->len + pos;
+ break;
+ }
+ memstream_update(ms);
+#ifdef DEBUG
+ fprintf(stderr, "MS: seek(%p, %jd, %d) %jd -> %jd\n", ms, (intmax_t)pos,
+ whence, (intmax_t)old, (intmax_t)ms->offset);
+#endif
+ return (ms->offset);
+}
+
+static int
+memstream_close(void *cookie)
+{
+
+ free(cookie);
+ return (0);
+}
+
+FILE *
+open_memstream(char **bufp, size_t *sizep)
+{
+ struct memstream *ms;
+ int save_errno;
+ FILE *fp;
+
+ if (bufp == NULL || sizep == NULL) {
+ errno = EINVAL;
+ return (NULL);
+ }
+ *bufp = calloc(1, 1);
+ if (*bufp == NULL)
+ return (NULL);
+ ms = malloc(sizeof(*ms));
+ if (ms == NULL) {
+ save_errno = errno;
+ free(*bufp);
+ *bufp = NULL;
+ errno = save_errno;
+ return (NULL);
+ }
+ ms->bufp = bufp;
+ ms->sizep = sizep;
+ ms->len = 0;
+ ms->offset = 0;
+ memstream_update(ms);
+ fp = funopen(ms, NULL, memstream_write, memstream_seek,
+ memstream_close);
+ if (fp == NULL) {
+ save_errno = errno;
+ free(ms);
+ free(*bufp);
+ *bufp = NULL;
+ errno = save_errno;
+ return (NULL);
+ }
+ fwide(fp, -1);
+ return (fp);
+}
diff --git a/lib/libc/stdio/open_wmemstream.c b/lib/libc/stdio/open_wmemstream.c
new file mode 100644
index 000000000000..3e8713f6b803
--- /dev/null
+++ b/lib/libc/stdio/open_wmemstream.c
@@ -0,0 +1,274 @@
+/*-
+ * Copyright (c) 2013 Hudson River Trading LLC
+ * Written by: John H. Baldwin <jhb@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#ifdef DEBUG
+#include <stdint.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include "un-namespace.h"
+
+/* XXX: There is no FPOS_MAX. This assumes fpos_t is an off_t. */
+#define FPOS_MAX OFF_MAX
+
+struct wmemstream {
+ wchar_t **bufp;
+ size_t *sizep;
+ ssize_t len;
+ fpos_t offset;
+ mbstate_t mbstate;
+};
+
+static int
+wmemstream_grow(struct wmemstream *ms, fpos_t newoff)
+{
+ wchar_t *buf;
+ ssize_t newsize;
+
+ if (newoff < 0 || newoff >= SSIZE_MAX / sizeof(wchar_t))
+ newsize = SSIZE_MAX / sizeof(wchar_t) - 1;
+ else
+ newsize = newoff;
+ if (newsize > ms->len) {
+ buf = realloc(*ms->bufp, (newsize + 1) * sizeof(wchar_t));
+ if (buf != NULL) {
+#ifdef DEBUG
+ fprintf(stderr, "WMS: %p growing from %zd to %zd\n",
+ ms, ms->len, newsize);
+#endif
+ wmemset(buf + ms->len + 1, 0, newsize - ms->len);
+ *ms->bufp = buf;
+ ms->len = newsize;
+ return (1);
+ }
+ return (0);
+ }
+ return (1);
+}
+
+static void
+wmemstream_update(struct wmemstream *ms)
+{
+
+ assert(ms->len >= 0 && ms->offset >= 0);
+ *ms->sizep = ms->len < ms->offset ? ms->len : ms->offset;
+}
+
+/*
+ * Based on a starting multibyte state and an input buffer, determine
+ * how many wchar_t's would be output. This doesn't use mbsnrtowcs()
+ * so that it can handle embedded null characters.
+ */
+static size_t
+wbuflen(const mbstate_t *state, const char *buf, int len)
+{
+ mbstate_t lenstate;
+ size_t charlen, count;
+
+ count = 0;
+ lenstate = *state;
+ while (len > 0) {
+ charlen = mbrlen(buf, len, &lenstate);
+ if (charlen == (size_t)-1)
+ return (-1);
+ if (charlen == (size_t)-2)
+ break;
+ if (charlen == 0)
+ /* XXX: Not sure how else to handle this. */
+ charlen = 1;
+ len -= charlen;
+ buf += charlen;
+ count++;
+ }
+ return (count);
+}
+
+static int
+wmemstream_write(void *cookie, const char *buf, int len)
+{
+ struct wmemstream *ms;
+ ssize_t consumed, wlen;
+ size_t charlen;
+
+ ms = cookie;
+ wlen = wbuflen(&ms->mbstate, buf, len);
+ if (wlen < 0) {
+ errno = EILSEQ;
+ return (-1);
+ }
+ if (!wmemstream_grow(ms, ms->offset + wlen))
+ return (-1);
+
+ /*
+ * This copies characters one at a time rather than using
+ * mbsnrtowcs() so it can properly handle embedded null
+ * characters.
+ */
+ consumed = 0;
+ while (len > 0 && ms->offset < ms->len) {
+ charlen = mbrtowc(*ms->bufp + ms->offset, buf, len,
+ &ms->mbstate);
+ if (charlen == (size_t)-1) {
+ if (consumed == 0) {
+ errno = EILSEQ;
+ return (-1);
+ }
+ /* Treat it as a successful short write. */
+ break;
+ }
+ if (charlen == 0)
+ /* XXX: Not sure how else to handle this. */
+ charlen = 1;
+ if (charlen == (size_t)-2) {
+ consumed += len;
+ len = 0;
+ } else {
+ consumed += charlen;
+ buf += charlen;
+ len -= charlen;
+ ms->offset++;
+ }
+ }
+ wmemstream_update(ms);
+#ifdef DEBUG
+ fprintf(stderr, "WMS: write(%p, %d) = %zd\n", ms, len, consumed);
+#endif
+ return (consumed);
+}
+
+static fpos_t
+wmemstream_seek(void *cookie, fpos_t pos, int whence)
+{
+ struct wmemstream *ms;
+ fpos_t old;
+
+ ms = cookie;
+ old = ms->offset;
+ switch (whence) {
+ case SEEK_SET:
+ /* _fseeko() checks for negative offsets. */
+ assert(pos >= 0);
+ ms->offset = pos;
+ break;
+ case SEEK_CUR:
+ /* This is only called by _ftello(). */
+ assert(pos == 0);
+ break;
+ case SEEK_END:
+ if (pos < 0) {
+ if (pos + ms->len < 0) {
+#ifdef DEBUG
+ fprintf(stderr,
+ "WMS: bad SEEK_END: pos %jd, len %zd\n",
+ (intmax_t)pos, ms->len);
+#endif
+ errno = EINVAL;
+ return (-1);
+ }
+ } else {
+ if (FPOS_MAX - ms->len < pos) {
+#ifdef DEBUG
+ fprintf(stderr,
+ "WMS: bad SEEK_END: pos %jd, len %zd\n",
+ (intmax_t)pos, ms->len);
+#endif
+ errno = EOVERFLOW;
+ return (-1);
+ }
+ }
+ ms->offset = ms->len + pos;
+ break;
+ }
+ /* Reset the multibyte state if a seek changes the position. */
+ if (ms->offset != old)
+ memset(&ms->mbstate, 0, sizeof(ms->mbstate));
+ wmemstream_update(ms);
+#ifdef DEBUG
+ fprintf(stderr, "WMS: seek(%p, %jd, %d) %jd -> %jd\n", ms,
+ (intmax_t)pos, whence, (intmax_t)old, (intmax_t)ms->offset);
+#endif
+ return (ms->offset);
+}
+
+static int
+wmemstream_close(void *cookie)
+{
+
+ free(cookie);
+ return (0);
+}
+
+FILE *
+open_wmemstream(wchar_t **bufp, size_t *sizep)
+{
+ struct wmemstream *ms;
+ int save_errno;
+ FILE *fp;
+
+ if (bufp == NULL || sizep == NULL) {
+ errno = EINVAL;
+ return (NULL);
+ }
+ *bufp = calloc(1, sizeof(wchar_t));
+ if (*bufp == NULL)
+ return (NULL);
+ ms = malloc(sizeof(*ms));
+ if (ms == NULL) {
+ save_errno = errno;
+ free(*bufp);
+ *bufp = NULL;
+ errno = save_errno;
+ return (NULL);
+ }
+ ms->bufp = bufp;
+ ms->sizep = sizep;
+ ms->len = 0;
+ ms->offset = 0;
+ memset(&ms->mbstate, 0, sizeof(mbstate_t));
+ wmemstream_update(ms);
+ fp = funopen(ms, NULL, wmemstream_write, wmemstream_seek,
+ wmemstream_close);
+ if (fp == NULL) {
+ save_errno = errno;
+ free(ms);
+ free(*bufp);
+ *bufp = NULL;
+ errno = save_errno;
+ return (NULL);
+ }
+ fwide(fp, 1);
+ return (fp);
+}
diff --git a/lib/libc/stdio/perror.c b/lib/libc/stdio/perror.c
new file mode 100644
index 000000000000..89c079818fb7
--- /dev/null
+++ b/lib/libc/stdio/perror.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)perror.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+#include "local.h"
+
+void
+perror(const char *s)
+{
+ char msgbuf[NL_TEXTMAX];
+ struct iovec *v;
+ struct iovec iov[4];
+
+ v = iov;
+ if (s != NULL && *s != '\0') {
+ v->iov_base = (char *)s;
+ v->iov_len = strlen(s);
+ v++;
+ v->iov_base = ": ";
+ v->iov_len = 2;
+ v++;
+ }
+ strerror_r(errno, msgbuf, sizeof(msgbuf));
+ v->iov_base = msgbuf;
+ v->iov_len = strlen(v->iov_base);
+ v++;
+ v->iov_base = "\n";
+ v->iov_len = 1;
+ FLOCKFILE(stderr);
+ __sflush(stderr);
+ (void)_writev(stderr->_file, iov, (v - iov) + 1);
+ stderr->_flags &= ~__SOFF;
+ FUNLOCKFILE(stderr);
+}
diff --git a/lib/libc/stdio/printf-pos.c b/lib/libc/stdio/printf-pos.c
new file mode 100644
index 000000000000..9c38c2add343
--- /dev/null
+++ b/lib/libc/stdio/printf-pos.c
@@ -0,0 +1,773 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)vfprintf.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * This is the code responsible for handling positional arguments
+ * (%m$ and %m$.n$) for vfprintf() and vfwprintf().
+ */
+
+#include "namespace.h"
+#include <sys/types.h>
+
+#include <limits.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+
+#include "un-namespace.h"
+#include "printflocal.h"
+
+#ifdef NL_ARGMAX
+#define MAX_POSARG NL_ARGMAX
+#else
+#define MAX_POSARG 65536
+#endif
+
+/*
+ * Type ids for argument type table.
+ */
+enum typeid {
+ T_UNUSED, TP_SHORT, T_INT, T_U_INT, TP_INT,
+ T_LONG, T_U_LONG, TP_LONG, T_LLONG, T_U_LLONG, TP_LLONG,
+ T_PTRDIFFT, TP_PTRDIFFT, T_SSIZET, T_SIZET, TP_SSIZET,
+ T_INTMAXT, T_UINTMAXT, TP_INTMAXT, TP_VOID, TP_CHAR, TP_SCHAR,
+ T_DOUBLE, T_LONG_DOUBLE, T_WINT, TP_WCHAR
+};
+
+/* An expandable array of types. */
+struct typetable {
+ enum typeid *table; /* table of types */
+ enum typeid stattable[STATIC_ARG_TBL_SIZE];
+ u_int tablesize; /* current size of type table */
+ u_int tablemax; /* largest used index in table */
+ u_int nextarg; /* 1-based argument index */
+};
+
+static int __grow_type_table(struct typetable *);
+static void build_arg_table (struct typetable *, va_list, union arg **);
+
+/*
+ * Initialize a struct typetable.
+ */
+static inline void
+inittypes(struct typetable *types)
+{
+ u_int n;
+
+ types->table = types->stattable;
+ types->tablesize = STATIC_ARG_TBL_SIZE;
+ types->tablemax = 0;
+ types->nextarg = 1;
+ for (n = 0; n < STATIC_ARG_TBL_SIZE; n++)
+ types->table[n] = T_UNUSED;
+}
+
+/*
+ * struct typetable destructor.
+ */
+static inline void
+freetypes(struct typetable *types)
+{
+
+ if (types->table != types->stattable)
+ free (types->table);
+}
+
+/*
+ * Ensure that there is space to add a new argument type to the type table.
+ * Expand the table if necessary. Returns 0 on success.
+ */
+static inline int
+_ensurespace(struct typetable *types)
+{
+
+ if (types->nextarg >= types->tablesize) {
+ if (__grow_type_table(types))
+ return (-1);
+ }
+ if (types->nextarg > types->tablemax)
+ types->tablemax = types->nextarg;
+ return (0);
+}
+
+/*
+ * Add an argument type to the table, expanding if necessary.
+ * Returns 0 on success.
+ */
+static inline int
+addtype(struct typetable *types, enum typeid type)
+{
+
+ if (_ensurespace(types))
+ return (-1);
+ types->table[types->nextarg++] = type;
+ return (0);
+}
+
+static inline int
+addsarg(struct typetable *types, int flags)
+{
+
+ if (_ensurespace(types))
+ return (-1);
+ if (flags & INTMAXT)
+ types->table[types->nextarg++] = T_INTMAXT;
+ else if (flags & SIZET)
+ types->table[types->nextarg++] = T_SSIZET;
+ else if (flags & PTRDIFFT)
+ types->table[types->nextarg++] = T_PTRDIFFT;
+ else if (flags & LLONGINT)
+ types->table[types->nextarg++] = T_LLONG;
+ else if (flags & LONGINT)
+ types->table[types->nextarg++] = T_LONG;
+ else
+ types->table[types->nextarg++] = T_INT;
+ return (0);
+}
+
+static inline int
+adduarg(struct typetable *types, int flags)
+{
+
+ if (_ensurespace(types))
+ return (-1);
+ if (flags & INTMAXT)
+ types->table[types->nextarg++] = T_UINTMAXT;
+ else if (flags & SIZET)
+ types->table[types->nextarg++] = T_SIZET;
+ else if (flags & PTRDIFFT)
+ types->table[types->nextarg++] = T_SIZET;
+ else if (flags & LLONGINT)
+ types->table[types->nextarg++] = T_U_LLONG;
+ else if (flags & LONGINT)
+ types->table[types->nextarg++] = T_U_LONG;
+ else
+ types->table[types->nextarg++] = T_U_INT;
+ return (0);
+}
+
+/*
+ * Add * arguments to the type array.
+ */
+static inline int
+addaster(struct typetable *types, char **fmtp)
+{
+ char *cp;
+ u_int n2;
+
+ n2 = 0;
+ cp = *fmtp;
+ while (is_digit(*cp)) {
+ n2 = 10 * n2 + to_digit(*cp);
+ cp++;
+ }
+ if (*cp == '$') {
+ u_int hold = types->nextarg;
+ types->nextarg = n2;
+ if (addtype(types, T_INT))
+ return (-1);
+ types->nextarg = hold;
+ *fmtp = ++cp;
+ } else {
+ if (addtype(types, T_INT))
+ return (-1);
+ }
+ return (0);
+}
+
+static inline int
+addwaster(struct typetable *types, wchar_t **fmtp)
+{
+ wchar_t *cp;
+ u_int n2;
+
+ n2 = 0;
+ cp = *fmtp;
+ while (is_digit(*cp)) {
+ n2 = 10 * n2 + to_digit(*cp);
+ cp++;
+ }
+ if (*cp == '$') {
+ u_int hold = types->nextarg;
+ types->nextarg = n2;
+ if (addtype(types, T_INT))
+ return (-1);
+ types->nextarg = hold;
+ *fmtp = ++cp;
+ } else {
+ if (addtype(types, T_INT))
+ return (-1);
+ }
+ return (0);
+}
+
+/*
+ * Find all arguments when a positional parameter is encountered. Returns a
+ * table, indexed by argument number, of pointers to each arguments. The
+ * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries.
+ * It will be replaces with a malloc-ed one if it overflows.
+ * Returns 0 on success. On failure, returns nonzero and sets errno.
+ */
+int
+__find_arguments (const char *fmt0, va_list ap, union arg **argtable)
+{
+ char *fmt; /* format string */
+ int ch; /* character from fmt */
+ u_int n; /* handy integer (short term usage) */
+ int error;
+ int flags; /* flags as above */
+ struct typetable types; /* table of types */
+
+ fmt = (char *)fmt0;
+ inittypes(&types);
+ error = 0;
+
+ /*
+ * Scan the format for conversions (`%' character).
+ */
+ for (;;) {
+ while ((ch = *fmt) != '\0' && ch != '%')
+ fmt++;
+ if (ch == '\0')
+ goto done;
+ fmt++; /* skip over '%' */
+
+ flags = 0;
+
+rflag: ch = *fmt++;
+reswitch: switch (ch) {
+ case ' ':
+ case '#':
+ goto rflag;
+ case '*':
+ if ((error = addaster(&types, &fmt)))
+ goto error;
+ goto rflag;
+ case '-':
+ case '+':
+ case '\'':
+ goto rflag;
+ case '.':
+ if ((ch = *fmt++) == '*') {
+ if ((error = addaster(&types, &fmt)))
+ goto error;
+ goto rflag;
+ }
+ while (is_digit(ch)) {
+ ch = *fmt++;
+ }
+ goto reswitch;
+ case '0':
+ goto rflag;
+ case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ n = 0;
+ do {
+ n = 10 * n + to_digit(ch);
+ /* Detect overflow */
+ if (n > MAX_POSARG) {
+ error = -1;
+ goto error;
+ }
+ ch = *fmt++;
+ } while (is_digit(ch));
+ if (ch == '$') {
+ types.nextarg = n;
+ goto rflag;
+ }
+ goto reswitch;
+#ifndef NO_FLOATING_POINT
+ case 'L':
+ flags |= LONGDBL;
+ goto rflag;
+#endif
+ case 'h':
+ if (flags & SHORTINT) {
+ flags &= ~SHORTINT;
+ flags |= CHARINT;
+ } else
+ flags |= SHORTINT;
+ goto rflag;
+ case 'j':
+ flags |= INTMAXT;
+ goto rflag;
+ case 'l':
+ if (flags & LONGINT) {
+ flags &= ~LONGINT;
+ flags |= LLONGINT;
+ } else
+ flags |= LONGINT;
+ goto rflag;
+ case 'q':
+ flags |= LLONGINT; /* not necessarily */
+ goto rflag;
+ case 't':
+ flags |= PTRDIFFT;
+ goto rflag;
+ case 'z':
+ flags |= SIZET;
+ goto rflag;
+ case 'C':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 'c':
+ error = addtype(&types,
+ (flags & LONGINT) ? T_WINT : T_INT);
+ if (error)
+ goto error;
+ break;
+ case 'D':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 'd':
+ case 'i':
+ if ((error = addsarg(&types, flags)))
+ goto error;
+ break;
+#ifndef NO_FLOATING_POINT
+ case 'a':
+ case 'A':
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'g':
+ case 'G':
+ error = addtype(&types,
+ (flags & LONGDBL) ? T_LONG_DOUBLE : T_DOUBLE);
+ if (error)
+ goto error;
+ break;
+#endif /* !NO_FLOATING_POINT */
+ case 'n':
+ if (flags & INTMAXT)
+ error = addtype(&types, TP_INTMAXT);
+ else if (flags & PTRDIFFT)
+ error = addtype(&types, TP_PTRDIFFT);
+ else if (flags & SIZET)
+ error = addtype(&types, TP_SSIZET);
+ else if (flags & LLONGINT)
+ error = addtype(&types, TP_LLONG);
+ else if (flags & LONGINT)
+ error = addtype(&types, TP_LONG);
+ else if (flags & SHORTINT)
+ error = addtype(&types, TP_SHORT);
+ else if (flags & CHARINT)
+ error = addtype(&types, TP_SCHAR);
+ else
+ error = addtype(&types, TP_INT);
+ if (error)
+ goto error;
+ continue; /* no output */
+ case 'O':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 'o':
+ if ((error = adduarg(&types, flags)))
+ goto error;
+ break;
+ case 'p':
+ if ((error = addtype(&types, TP_VOID)))
+ goto error;
+ break;
+ case 'S':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 's':
+ error = addtype(&types,
+ (flags & LONGINT) ? TP_WCHAR : TP_CHAR);
+ if (error)
+ goto error;
+ break;
+ case 'U':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 'u':
+ case 'X':
+ case 'x':
+ if ((error = adduarg(&types, flags)))
+ goto error;
+ break;
+ default: /* "%?" prints ?, unless ? is NUL */
+ if (ch == '\0')
+ goto done;
+ break;
+ }
+ }
+done:
+ build_arg_table(&types, ap, argtable);
+error:
+ freetypes(&types);
+ return (error || *argtable == NULL);
+}
+
+/* wchar version of __find_arguments. */
+int
+__find_warguments (const wchar_t *fmt0, va_list ap, union arg **argtable)
+{
+ wchar_t *fmt; /* format string */
+ wchar_t ch; /* character from fmt */
+ u_int n; /* handy integer (short term usage) */
+ int error;
+ int flags; /* flags as above */
+ struct typetable types; /* table of types */
+
+ fmt = (wchar_t *)fmt0;
+ inittypes(&types);
+ error = 0;
+
+ /*
+ * Scan the format for conversions (`%' character).
+ */
+ for (;;) {
+ while ((ch = *fmt) != '\0' && ch != '%')
+ fmt++;
+ if (ch == '\0')
+ goto done;
+ fmt++; /* skip over '%' */
+
+ flags = 0;
+
+rflag: ch = *fmt++;
+reswitch: switch (ch) {
+ case ' ':
+ case '#':
+ goto rflag;
+ case '*':
+ if ((error = addwaster(&types, &fmt)))
+ goto error;
+ goto rflag;
+ case '-':
+ case '+':
+ case '\'':
+ goto rflag;
+ case '.':
+ if ((ch = *fmt++) == '*') {
+ if ((error = addwaster(&types, &fmt)))
+ goto error;
+ goto rflag;
+ }
+ while (is_digit(ch)) {
+ ch = *fmt++;
+ }
+ goto reswitch;
+ case '0':
+ goto rflag;
+ case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ n = 0;
+ do {
+ n = 10 * n + to_digit(ch);
+ /* Detect overflow */
+ if (n > MAX_POSARG) {
+ error = -1;
+ goto error;
+ }
+ ch = *fmt++;
+ } while (is_digit(ch));
+ if (ch == '$') {
+ types.nextarg = n;
+ goto rflag;
+ }
+ goto reswitch;
+#ifndef NO_FLOATING_POINT
+ case 'L':
+ flags |= LONGDBL;
+ goto rflag;
+#endif
+ case 'h':
+ if (flags & SHORTINT) {
+ flags &= ~SHORTINT;
+ flags |= CHARINT;
+ } else
+ flags |= SHORTINT;
+ goto rflag;
+ case 'j':
+ flags |= INTMAXT;
+ goto rflag;
+ case 'l':
+ if (flags & LONGINT) {
+ flags &= ~LONGINT;
+ flags |= LLONGINT;
+ } else
+ flags |= LONGINT;
+ goto rflag;
+ case 'q':
+ flags |= LLONGINT; /* not necessarily */
+ goto rflag;
+ case 't':
+ flags |= PTRDIFFT;
+ goto rflag;
+ case 'z':
+ flags |= SIZET;
+ goto rflag;
+ case 'C':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 'c':
+ error = addtype(&types,
+ (flags & LONGINT) ? T_WINT : T_INT);
+ if (error)
+ goto error;
+ break;
+ case 'D':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 'd':
+ case 'i':
+ if ((error = addsarg(&types, flags)))
+ goto error;
+ break;
+#ifndef NO_FLOATING_POINT
+ case 'a':
+ case 'A':
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'g':
+ case 'G':
+ error = addtype(&types,
+ (flags & LONGDBL) ? T_LONG_DOUBLE : T_DOUBLE);
+ if (error)
+ goto error;
+ break;
+#endif /* !NO_FLOATING_POINT */
+ case 'n':
+ if (flags & INTMAXT)
+ error = addtype(&types, TP_INTMAXT);
+ else if (flags & PTRDIFFT)
+ error = addtype(&types, TP_PTRDIFFT);
+ else if (flags & SIZET)
+ error = addtype(&types, TP_SSIZET);
+ else if (flags & LLONGINT)
+ error = addtype(&types, TP_LLONG);
+ else if (flags & LONGINT)
+ error = addtype(&types, TP_LONG);
+ else if (flags & SHORTINT)
+ error = addtype(&types, TP_SHORT);
+ else if (flags & CHARINT)
+ error = addtype(&types, TP_SCHAR);
+ else
+ error = addtype(&types, TP_INT);
+ if (error)
+ goto error;
+ continue; /* no output */
+ case 'O':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 'o':
+ if ((error = adduarg(&types, flags)))
+ goto error;
+ break;
+ case 'p':
+ if ((error = addtype(&types, TP_VOID)))
+ goto error;
+ break;
+ case 'S':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 's':
+ error = addtype(&types,
+ (flags & LONGINT) ? TP_WCHAR : TP_CHAR);
+ if (error)
+ goto error;
+ break;
+ case 'U':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 'u':
+ case 'X':
+ case 'x':
+ if ((error = adduarg(&types, flags)))
+ goto error;
+ break;
+ default: /* "%?" prints ?, unless ? is NUL */
+ if (ch == '\0')
+ goto done;
+ break;
+ }
+ }
+done:
+ build_arg_table(&types, ap, argtable);
+error:
+ freetypes(&types);
+ return (error || *argtable == NULL);
+}
+
+/*
+ * Increase the size of the type table. Returns 0 on success.
+ */
+static int
+__grow_type_table(struct typetable *types)
+{
+ enum typeid *const oldtable = types->table;
+ const int oldsize = types->tablesize;
+ enum typeid *newtable;
+ u_int n, newsize = oldsize * 2;
+
+ /* Detect overflow */
+ if (types->nextarg > NL_ARGMAX)
+ return (-1);
+
+ if (newsize < types->nextarg + 1)
+ newsize = types->nextarg + 1;
+ if (oldsize == STATIC_ARG_TBL_SIZE) {
+ if ((newtable = malloc(newsize * sizeof(enum typeid))) == NULL)
+ return (-1);
+ bcopy(oldtable, newtable, oldsize * sizeof(enum typeid));
+ } else {
+ newtable = realloc(oldtable, newsize * sizeof(enum typeid));
+ if (newtable == NULL)
+ return (-1);
+ }
+ for (n = oldsize; n < newsize; n++)
+ newtable[n] = T_UNUSED;
+
+ types->table = newtable;
+ types->tablesize = newsize;
+
+ return (0);
+}
+
+/*
+ * Build the argument table from the completed type table.
+ * On malloc failure, *argtable is set to NULL.
+ */
+static void
+build_arg_table(struct typetable *types, va_list ap, union arg **argtable)
+{
+ u_int n;
+
+ if (types->tablemax >= STATIC_ARG_TBL_SIZE) {
+ *argtable = (union arg *)
+ malloc (sizeof (union arg) * (types->tablemax + 1));
+ if (*argtable == NULL)
+ return;
+ }
+
+ (*argtable) [0].intarg = 0;
+ for (n = 1; n <= types->tablemax; n++) {
+ switch (types->table[n]) {
+ case T_UNUSED: /* whoops! */
+ (*argtable) [n].intarg = va_arg (ap, int);
+ break;
+ case TP_SCHAR:
+ (*argtable) [n].pschararg = va_arg (ap, signed char *);
+ break;
+ case TP_SHORT:
+ (*argtable) [n].pshortarg = va_arg (ap, short *);
+ break;
+ case T_INT:
+ (*argtable) [n].intarg = va_arg (ap, int);
+ break;
+ case T_U_INT:
+ (*argtable) [n].uintarg = va_arg (ap, unsigned int);
+ break;
+ case TP_INT:
+ (*argtable) [n].pintarg = va_arg (ap, int *);
+ break;
+ case T_LONG:
+ (*argtable) [n].longarg = va_arg (ap, long);
+ break;
+ case T_U_LONG:
+ (*argtable) [n].ulongarg = va_arg (ap, unsigned long);
+ break;
+ case TP_LONG:
+ (*argtable) [n].plongarg = va_arg (ap, long *);
+ break;
+ case T_LLONG:
+ (*argtable) [n].longlongarg = va_arg (ap, long long);
+ break;
+ case T_U_LLONG:
+ (*argtable) [n].ulonglongarg = va_arg (ap, unsigned long long);
+ break;
+ case TP_LLONG:
+ (*argtable) [n].plonglongarg = va_arg (ap, long long *);
+ break;
+ case T_PTRDIFFT:
+ (*argtable) [n].ptrdiffarg = va_arg (ap, ptrdiff_t);
+ break;
+ case TP_PTRDIFFT:
+ (*argtable) [n].pptrdiffarg = va_arg (ap, ptrdiff_t *);
+ break;
+ case T_SIZET:
+ (*argtable) [n].sizearg = va_arg (ap, size_t);
+ break;
+ case T_SSIZET:
+ (*argtable) [n].sizearg = va_arg (ap, ssize_t);
+ break;
+ case TP_SSIZET:
+ (*argtable) [n].pssizearg = va_arg (ap, ssize_t *);
+ break;
+ case T_INTMAXT:
+ (*argtable) [n].intmaxarg = va_arg (ap, intmax_t);
+ break;
+ case T_UINTMAXT:
+ (*argtable) [n].uintmaxarg = va_arg (ap, uintmax_t);
+ break;
+ case TP_INTMAXT:
+ (*argtable) [n].pintmaxarg = va_arg (ap, intmax_t *);
+ break;
+ case T_DOUBLE:
+#ifndef NO_FLOATING_POINT
+ (*argtable) [n].doublearg = va_arg (ap, double);
+#endif
+ break;
+ case T_LONG_DOUBLE:
+#ifndef NO_FLOATING_POINT
+ (*argtable) [n].longdoublearg = va_arg (ap, long double);
+#endif
+ break;
+ case TP_CHAR:
+ (*argtable) [n].pchararg = va_arg (ap, char *);
+ break;
+ case TP_VOID:
+ (*argtable) [n].pvoidarg = va_arg (ap, void *);
+ break;
+ case T_WINT:
+ (*argtable) [n].wintarg = va_arg (ap, wint_t);
+ break;
+ case TP_WCHAR:
+ (*argtable) [n].pwchararg = va_arg (ap, wchar_t *);
+ break;
+ }
+ }
+}
diff --git a/lib/libc/stdio/printf.3 b/lib/libc/stdio/printf.3
new file mode 100644
index 000000000000..2c844c9efd5f
--- /dev/null
+++ b/lib/libc/stdio/printf.3
@@ -0,0 +1,891 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek and the American National Standards Committee X3,
+.\" on Information Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)printf.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd July 30, 2016
+.Dt PRINTF 3
+.Os
+.Sh NAME
+.Nm printf , fprintf , sprintf , snprintf , asprintf , dprintf ,
+.Nm vprintf , vfprintf, vsprintf , vsnprintf , vasprintf, vdprintf
+.Nd formatted output conversion
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdio.h
+.Ft int
+.Fn printf "const char * restrict format" ...
+.Ft int
+.Fn fprintf "FILE * restrict stream" "const char * restrict format" ...
+.Ft int
+.Fn sprintf "char * restrict str" "const char * restrict format" ...
+.Ft int
+.Fn snprintf "char * restrict str" "size_t size" "const char * restrict format" ...
+.Ft int
+.Fn asprintf "char **ret" "const char *format" ...
+.Ft int
+.Fn dprintf "int fd" "const char * restrict format" ...
+.In stdarg.h
+.Ft int
+.Fn vprintf "const char * restrict format" "va_list ap"
+.Ft int
+.Fn vfprintf "FILE * restrict stream" "const char * restrict format" "va_list ap"
+.Ft int
+.Fn vsprintf "char * restrict str" "const char * restrict format" "va_list ap"
+.Ft int
+.Fn vsnprintf "char * restrict str" "size_t size" "const char * restrict format" "va_list ap"
+.Ft int
+.Fn vasprintf "char **ret" "const char *format" "va_list ap"
+.Ft int
+.Fn vdprintf "int fd" "const char * restrict format" "va_list ap"
+.Sh DESCRIPTION
+The
+.Fn printf
+family of functions produces output according to a
+.Fa format
+as described below.
+The
+.Fn printf
+and
+.Fn vprintf
+functions
+write output to
+.Dv stdout ,
+the standard output stream;
+.Fn fprintf
+and
+.Fn vfprintf
+write output to the given output
+.Fa stream ;
+.Fn dprintf
+and
+.Fn vdprintf
+write output to the given file descriptor;
+.Fn sprintf ,
+.Fn snprintf ,
+.Fn vsprintf ,
+and
+.Fn vsnprintf
+write to the character string
+.Fa str ;
+and
+.Fn asprintf
+and
+.Fn vasprintf
+dynamically allocate a new string with
+.Xr malloc 3 .
+.Pp
+These functions write the output under the control of a
+.Fa format
+string that specifies how subsequent arguments
+(or arguments accessed via the variable-length argument facilities of
+.Xr stdarg 3 )
+are converted for output.
+.Pp
+The
+.Fn asprintf
+and
+.Fn vasprintf
+functions
+set
+.Fa *ret
+to be a pointer to a buffer sufficiently large to hold the formatted string.
+This pointer should be passed to
+.Xr free 3
+to release the allocated storage when it is no longer needed.
+If sufficient space cannot be allocated,
+.Fn asprintf
+and
+.Fn vasprintf
+will return \-1 and set
+.Fa ret
+to be a
+.Dv NULL
+pointer.
+.Pp
+The
+.Fn snprintf
+and
+.Fn vsnprintf
+functions
+will write at most
+.Fa size Ns \-1
+of the characters printed into the output string
+(the
+.Fa size Ns 'th
+character then gets the terminating
+.Ql \e0 ) ;
+if the return value is greater than or equal to the
+.Fa size
+argument, the string was too short
+and some of the printed characters were discarded.
+The output is always null-terminated, unless
+.Fa size
+is 0.
+.Pp
+The
+.Fn sprintf
+and
+.Fn vsprintf
+functions
+effectively assume a
+.Fa size
+of
+.Dv INT_MAX + 1.
+.Pp
+The format string is composed of zero or more directives:
+ordinary
+.\" multibyte
+characters (not
+.Cm % ) ,
+which are copied unchanged to the output stream;
+and conversion specifications, each of which results
+in fetching zero or more subsequent arguments.
+Each conversion specification is introduced by
+the
+.Cm %
+character.
+The arguments must correspond properly (after type promotion)
+with the conversion specifier.
+After the
+.Cm % ,
+the following appear in sequence:
+.Bl -bullet
+.It
+An optional field, consisting of a decimal digit string followed by a
+.Cm $ ,
+specifying the next argument to access.
+If this field is not provided, the argument following the last
+argument accessed will be used.
+Arguments are numbered starting at
+.Cm 1 .
+If unaccessed arguments in the format string are interspersed with ones that
+are accessed the results will be indeterminate.
+.It
+Zero or more of the following flags:
+.Bl -tag -width ".So \ Sc (space)"
+.It Sq Cm #
+The value should be converted to an
+.Dq alternate form .
+For
+.Cm c , d , i , n , p , s ,
+and
+.Cm u
+conversions, this option has no effect.
+For
+.Cm o
+conversions, the precision of the number is increased to force the first
+character of the output string to a zero.
+For
+.Cm x
+and
+.Cm X
+conversions, a non-zero result has the string
+.Ql 0x
+(or
+.Ql 0X
+for
+.Cm X
+conversions) prepended to it.
+For
+.Cm a , A , e , E , f , F , g ,
+and
+.Cm G
+conversions, the result will always contain a decimal point, even if no
+digits follow it (normally, a decimal point appears in the results of
+those conversions only if a digit follows).
+For
+.Cm g
+and
+.Cm G
+conversions, trailing zeros are not removed from the result as they
+would otherwise be.
+.It So Cm 0 Sc (zero)
+Zero padding.
+For all conversions except
+.Cm n ,
+the converted value is padded on the left with zeros rather than blanks.
+If a precision is given with a numeric conversion
+.Cm ( d , i , o , u , i , x ,
+and
+.Cm X ) ,
+the
+.Cm 0
+flag is ignored.
+.It Sq Cm \-
+A negative field width flag;
+the converted value is to be left adjusted on the field boundary.
+Except for
+.Cm n
+conversions, the converted value is padded on the right with blanks,
+rather than on the left with blanks or zeros.
+A
+.Cm \-
+overrides a
+.Cm 0
+if both are given.
+.It So "\ " Sc (space)
+A blank should be left before a positive number
+produced by a signed conversion
+.Cm ( a , A , d , e , E , f , F , g , G ,
+or
+.Cm i ) .
+.It Sq Cm +
+A sign must always be placed before a
+number produced by a signed conversion.
+A
+.Cm +
+overrides a space if both are used.
+.It So "'" Sc (apostrophe)
+Decimal conversions
+.Cm ( d , u ,
+or
+.Cm i )
+or the integral portion of a floating point conversion
+.Cm ( f
+or
+.Cm F )
+should be grouped and separated by thousands using
+the non-monetary separator returned by
+.Xr localeconv 3 .
+.El
+.It
+An optional decimal digit string specifying a minimum field width.
+If the converted value has fewer characters than the field width, it will
+be padded with spaces on the left (or right, if the left-adjustment
+flag has been given) to fill out
+the field width.
+.It
+An optional precision, in the form of a period
+.Cm \&.
+followed by an
+optional digit string.
+If the digit string is omitted, the precision is taken as zero.
+This gives the minimum number of digits to appear for
+.Cm d , i , o , u , x ,
+and
+.Cm X
+conversions, the number of digits to appear after the decimal-point for
+.Cm a , A , e , E , f ,
+and
+.Cm F
+conversions, the maximum number of significant digits for
+.Cm g
+and
+.Cm G
+conversions, or the maximum number of characters to be printed from a
+string for
+.Cm s
+conversions.
+.It
+An optional length modifier, that specifies the size of the argument.
+The following length modifiers are valid for the
+.Cm d , i , n , o , u , x ,
+or
+.Cm X
+conversion:
+.Bl -column ".Cm q Em (deprecated)" ".Vt signed char" ".Vt unsigned long long" ".Vt long long *"
+.It Sy Modifier Ta Cm d , i Ta Cm o , u , x , X Ta Cm n
+.It Cm hh Ta Vt "signed char" Ta Vt "unsigned char" Ta Vt "signed char *"
+.It Cm h Ta Vt short Ta Vt "unsigned short" Ta Vt "short *"
+.It Cm l No (ell) Ta Vt long Ta Vt "unsigned long" Ta Vt "long *"
+.It Cm ll No (ell ell) Ta Vt "long long" Ta Vt "unsigned long long" Ta Vt "long long *"
+.It Cm j Ta Vt intmax_t Ta Vt uintmax_t Ta Vt "intmax_t *"
+.It Cm t Ta Vt ptrdiff_t Ta (see note) Ta Vt "ptrdiff_t *"
+.It Cm z Ta (see note) Ta Vt size_t Ta (see note)
+.It Cm q Em (deprecated) Ta Vt quad_t Ta Vt u_quad_t Ta Vt "quad_t *"
+.El
+.Pp
+Note:
+the
+.Cm t
+modifier, when applied to a
+.Cm o , u , x ,
+or
+.Cm X
+conversion, indicates that the argument is of an unsigned type
+equivalent in size to a
+.Vt ptrdiff_t .
+The
+.Cm z
+modifier, when applied to a
+.Cm d
+or
+.Cm i
+conversion, indicates that the argument is of a signed type equivalent in
+size to a
+.Vt size_t .
+Similarly, when applied to an
+.Cm n
+conversion, it indicates that the argument is a pointer to a signed type
+equivalent in size to a
+.Vt size_t .
+.Pp
+The following length modifier is valid for the
+.Cm a , A , e , E , f , F , g ,
+or
+.Cm G
+conversion:
+.Bl -column ".Sy Modifier" ".Cm a , A , e , E , f , F , g , G"
+.It Sy Modifier Ta Cm a , A , e , E , f , F , g , G
+.It Cm l No (ell) Ta Vt double
+(ignored, same behavior as without it)
+.It Cm L Ta Vt "long double"
+.El
+.Pp
+The following length modifier is valid for the
+.Cm c
+or
+.Cm s
+conversion:
+.Bl -column ".Sy Modifier" ".Vt wint_t" ".Vt wchar_t *"
+.It Sy Modifier Ta Cm c Ta Cm s
+.It Cm l No (ell) Ta Vt wint_t Ta Vt "wchar_t *"
+.El
+.It
+A character that specifies the type of conversion to be applied.
+.El
+.Pp
+A field width or precision, or both, may be indicated by
+an asterisk
+.Ql *
+or an asterisk followed by one or more decimal digits and a
+.Ql $
+instead of a
+digit string.
+In this case, an
+.Vt int
+argument supplies the field width or precision.
+A negative field width is treated as a left adjustment flag followed by a
+positive field width; a negative precision is treated as though it were
+missing.
+If a single format directive mixes positional
+.Pq Li nn$
+and non-positional arguments, the results are undefined.
+.Pp
+The conversion specifiers and their meanings are:
+.Bl -tag -width ".Cm diouxX"
+.It Cm diouxX
+The
+.Vt int
+(or appropriate variant) argument is converted to signed decimal
+.Cm ( d
+and
+.Cm i ) ,
+unsigned octal
+.Pq Cm o ,
+unsigned decimal
+.Pq Cm u ,
+or unsigned hexadecimal
+.Cm ( x
+and
+.Cm X )
+notation.
+The letters
+.Dq Li abcdef
+are used for
+.Cm x
+conversions; the letters
+.Dq Li ABCDEF
+are used for
+.Cm X
+conversions.
+The precision, if any, gives the minimum number of digits that must
+appear; if the converted value requires fewer digits, it is padded on
+the left with zeros.
+.It Cm DOU
+The
+.Vt "long int"
+argument is converted to signed decimal, unsigned octal, or unsigned
+decimal, as if the format had been
+.Cm ld , lo ,
+or
+.Cm lu
+respectively.
+These conversion characters are deprecated, and will eventually disappear.
+.It Cm eE
+The
+.Vt double
+argument is rounded and converted in the style
+.Sm off
+.Oo \- Oc Ar d Li \&. Ar ddd Li e \(+- Ar dd
+.Sm on
+where there is one digit before the
+decimal-point character
+and the number of digits after it is equal to the precision;
+if the precision is missing,
+it is taken as 6; if the precision is
+zero, no decimal-point character appears.
+An
+.Cm E
+conversion uses the letter
+.Ql E
+(rather than
+.Ql e )
+to introduce the exponent.
+The exponent always contains at least two digits; if the value is zero,
+the exponent is 00.
+.Pp
+For
+.Cm a , A , e , E , f , F , g ,
+and
+.Cm G
+conversions, positive and negative infinity are represented as
+.Li inf
+and
+.Li -inf
+respectively when using the lowercase conversion character, and
+.Li INF
+and
+.Li -INF
+respectively when using the uppercase conversion character.
+Similarly, NaN is represented as
+.Li nan
+when using the lowercase conversion, and
+.Li NAN
+when using the uppercase conversion.
+.It Cm fF
+The
+.Vt double
+argument is rounded and converted to decimal notation in the style
+.Sm off
+.Oo \- Oc Ar ddd Li \&. Ar ddd ,
+.Sm on
+where the number of digits after the decimal-point character
+is equal to the precision specification.
+If the precision is missing, it is taken as 6; if the precision is
+explicitly zero, no decimal-point character appears.
+If a decimal point appears, at least one digit appears before it.
+.It Cm gG
+The
+.Vt double
+argument is converted in style
+.Cm f
+or
+.Cm e
+(or
+.Cm F
+or
+.Cm E
+for
+.Cm G
+conversions).
+The precision specifies the number of significant digits.
+If the precision is missing, 6 digits are given; if the precision is zero,
+it is treated as 1.
+Style
+.Cm e
+is used if the exponent from its conversion is less than \-4 or greater than
+or equal to the precision.
+Trailing zeros are removed from the fractional part of the result; a
+decimal point appears only if it is followed by at least one digit.
+.It Cm aA
+The
+.Vt double
+argument is rounded and converted to hexadecimal notation in the style
+.Sm off
+.Oo \- Oc Li 0x Ar h Li \&. Ar hhhp Oo \(+- Oc Ar d ,
+.Sm on
+where the number of digits after the hexadecimal-point character
+is equal to the precision specification.
+If the precision is missing, it is taken as enough to represent
+the floating-point number exactly, and no rounding occurs.
+If the precision is zero, no hexadecimal-point character appears.
+The
+.Cm p
+is a literal character
+.Ql p ,
+and the exponent consists of a positive or negative sign
+followed by a decimal number representing an exponent of 2.
+The
+.Cm A
+conversion uses the prefix
+.Dq Li 0X
+(rather than
+.Dq Li 0x ) ,
+the letters
+.Dq Li ABCDEF
+(rather than
+.Dq Li abcdef )
+to represent the hex digits, and the letter
+.Ql P
+(rather than
+.Ql p )
+to separate the mantissa and exponent.
+.Pp
+Note that there may be multiple valid ways to represent floating-point
+numbers in this hexadecimal format.
+For example,
+.Li 0x1.92p+1 , 0x3.24p+0 , 0x6.48p-1 ,
+and
+.Li 0xc.9p-2
+are all equivalent.
+.Fx 8.0
+and later always prints finite non-zero numbers using
+.Ql 1
+as the digit before the hexadecimal point.
+Zeroes are always represented with a mantissa of 0 (preceded by a
+.Ql -
+if appropriate) and an exponent of
+.Li +0 .
+.It Cm C
+Treated as
+.Cm c
+with the
+.Cm l
+(ell) modifier.
+.It Cm c
+The
+.Vt int
+argument is converted to an
+.Vt "unsigned char" ,
+and the resulting character is written.
+.Pp
+If the
+.Cm l
+(ell) modifier is used, the
+.Vt wint_t
+argument shall be converted to a
+.Vt wchar_t ,
+and the (potentially multi-byte) sequence representing the
+single wide character is written, including any shift sequences.
+If a shift sequence is used, the shift state is also restored
+to the original state after the character.
+.It Cm S
+Treated as
+.Cm s
+with the
+.Cm l
+(ell) modifier.
+.It Cm s
+The
+.Vt "char *"
+argument is expected to be a pointer to an array of character type (pointer
+to a string).
+Characters from the array are written up to (but not including)
+a terminating
+.Dv NUL
+character;
+if a precision is specified, no more than the number specified are
+written.
+If a precision is given, no null character
+need be present; if the precision is not specified, or is greater than
+the size of the array, the array must contain a terminating
+.Dv NUL
+character.
+.Pp
+If the
+.Cm l
+(ell) modifier is used, the
+.Vt "wchar_t *"
+argument is expected to be a pointer to an array of wide characters
+(pointer to a wide string).
+For each wide character in the string, the (potentially multi-byte)
+sequence representing the
+wide character is written, including any shift sequences.
+If any shift sequence is used, the shift state is also restored
+to the original state after the string.
+Wide characters from the array are written up to (but not including)
+a terminating wide
+.Dv NUL
+character;
+if a precision is specified, no more than the number of bytes specified are
+written (including shift sequences).
+Partial characters are never written.
+If a precision is given, no null character
+need be present; if the precision is not specified, or is greater than
+the number of bytes required to render the multibyte representation of
+the string, the array must contain a terminating wide
+.Dv NUL
+character.
+.It Cm p
+The
+.Vt "void *"
+pointer argument is printed in hexadecimal (as if by
+.Ql %#x
+or
+.Ql %#lx ) .
+.It Cm n
+The number of characters written so far is stored into the
+integer indicated by the
+.Vt "int *"
+(or variant) pointer argument.
+No argument is converted.
+.It Cm %
+A
+.Ql %
+is written.
+No argument is converted.
+The complete conversion specification
+is
+.Ql %% .
+.El
+.Pp
+The decimal point
+character is defined in the program's locale (category
+.Dv LC_NUMERIC ) .
+.Pp
+In no case does a non-existent or small field width cause truncation of
+a numeric field; if the result of a conversion is wider than the field
+width, the
+field is expanded to contain the conversion result.
+.Sh RETURN VALUES
+These functions return the number of characters printed
+(not including the trailing
+.Ql \e0
+used to end output to strings),
+except for
+.Fn snprintf
+and
+.Fn vsnprintf ,
+which return the number of characters that would have been printed if the
+.Fa size
+were unlimited
+(again, not including the final
+.Ql \e0 ) .
+These functions return a negative value if an error occurs.
+.Sh EXAMPLES
+To print a date and time in the form
+.Dq Li "Sunday, July 3, 10:02" ,
+where
+.Fa weekday
+and
+.Fa month
+are pointers to strings:
+.Bd -literal -offset indent
+#include <stdio.h>
+fprintf(stdout, "%s, %s %d, %.2d:%.2d\en",
+ weekday, month, day, hour, min);
+.Ed
+.Pp
+To print \*(Pi
+to five decimal places:
+.Bd -literal -offset indent
+#include <math.h>
+#include <stdio.h>
+fprintf(stdout, "pi = %.5f\en", 4 * atan(1.0));
+.Ed
+.Pp
+To allocate a 128 byte string and print into it:
+.Bd -literal -offset indent
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+char *newfmt(const char *fmt, ...)
+{
+ char *p;
+ va_list ap;
+ if ((p = malloc(128)) == NULL)
+ return (NULL);
+ va_start(ap, fmt);
+ (void) vsnprintf(p, 128, fmt, ap);
+ va_end(ap);
+ return (p);
+}
+.Ed
+.Sh COMPATIBILITY
+The conversion formats
+.Cm \&%D , \&%O ,
+and
+.Cm \&%U
+are not standard and
+are provided only for backward compatibility.
+The effect of padding the
+.Cm %p
+format with zeros (either by the
+.Cm 0
+flag or by specifying a precision), and the benign effect (i.e., none)
+of the
+.Cm #
+flag on
+.Cm %n
+and
+.Cm %p
+conversions, as well as other
+nonsensical combinations such as
+.Cm %Ld ,
+are not standard; such combinations
+should be avoided.
+.Sh ERRORS
+In addition to the errors documented for the
+.Xr write 2
+system call, the
+.Fn printf
+family of functions may fail if:
+.Bl -tag -width Er
+.It Bq Er EILSEQ
+An invalid wide character code was encountered.
+.It Bq Er ENOMEM
+Insufficient storage space is available.
+.It Bq Er EOVERFLOW
+The
+.Fa size
+argument exceeds
+.Dv INT_MAX + 1 ,
+or the return value would be too large to be represented by an
+.Vt int .
+.El
+.Sh SEE ALSO
+.Xr printf 1 ,
+.Xr fmtcheck 3 ,
+.Xr scanf 3 ,
+.Xr setlocale 3 ,
+.Xr wprintf 3
+.Sh STANDARDS
+Subject to the caveats noted in the
+.Sx BUGS
+section below, the
+.Fn fprintf ,
+.Fn printf ,
+.Fn sprintf ,
+.Fn vprintf ,
+.Fn vfprintf ,
+and
+.Fn vsprintf
+functions
+conform to
+.St -ansiC
+and
+.St -isoC-99 .
+With the same reservation, the
+.Fn snprintf
+and
+.Fn vsnprintf
+functions conform to
+.St -isoC-99 ,
+while
+.Fn dprintf
+and
+.Fn vdprintf
+conform to
+.St -p1003.1-2008 .
+.Sh HISTORY
+The functions
+.Fn asprintf
+and
+.Fn vasprintf
+first appeared in the
+.Tn GNU C
+library.
+These were implemented by
+.An Peter Wemm Aq Mt peter@FreeBSD.org
+in
+.Fx 2.2 ,
+but were later replaced with a different implementation
+from
+.Ox 2.3
+by
+.An Todd C. Miller Aq Mt Todd.Miller@courtesan.com .
+The
+.Fn dprintf
+and
+.Fn vdprintf
+functions were added in
+.Fx 8.0 .
+.Sh BUGS
+The
+.Nm
+family of functions do not correctly handle multibyte characters in the
+.Fa format
+argument.
+.Sh SECURITY CONSIDERATIONS
+The
+.Fn sprintf
+and
+.Fn vsprintf
+functions are easily misused in a manner which enables malicious users
+to arbitrarily change a running program's functionality through
+a buffer overflow attack.
+Because
+.Fn sprintf
+and
+.Fn vsprintf
+assume an infinitely long string,
+callers must be careful not to overflow the actual space;
+this is often hard to assure.
+For safety, programmers should use the
+.Fn snprintf
+interface instead.
+For example:
+.Bd -literal
+void
+foo(const char *arbitrary_string, const char *and_another)
+{
+ char onstack[8];
+
+#ifdef BAD
+ /*
+ * This first sprintf is bad behavior. Do not use sprintf!
+ */
+ sprintf(onstack, "%s, %s", arbitrary_string, and_another);
+#else
+ /*
+ * The following two lines demonstrate better use of
+ * snprintf().
+ */
+ snprintf(onstack, sizeof(onstack), "%s, %s", arbitrary_string,
+ and_another);
+#endif
+}
+.Ed
+.Pp
+The
+.Fn printf
+and
+.Fn sprintf
+family of functions are also easily misused in a manner
+allowing malicious users to arbitrarily change a running program's
+functionality by either causing the program
+to print potentially sensitive data
+.Dq "left on the stack" ,
+or causing it to generate a memory fault or bus error
+by dereferencing an invalid pointer.
+.Pp
+.Cm %n
+can be used to write arbitrary data to potentially carefully-selected
+addresses.
+Programmers are therefore strongly advised to never pass untrusted strings
+as the
+.Fa format
+argument, as an attacker can put format specifiers in the string
+to mangle your stack,
+leading to a possible security hole.
+This holds true even if the string was built using a function like
+.Fn snprintf ,
+as the resulting string may still contain user-supplied conversion specifiers
+for later interpolation by
+.Fn printf .
+.Pp
+Always use the proper secure idiom:
+.Pp
+.Dl "snprintf(buffer, sizeof(buffer), \*q%s\*q, string);"
diff --git a/lib/libc/stdio/printf.c b/lib/libc/stdio/printf.c
new file mode 100644
index 000000000000..83147b2314c1
--- /dev/null
+++ b/lib/libc/stdio/printf.c
@@ -0,0 +1,69 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)printf.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <xlocale.h>
+
+int
+printf(char const * __restrict fmt, ...)
+{
+ int ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ ret = vfprintf(stdout, fmt, ap);
+ va_end(ap);
+ return (ret);
+}
+int
+printf_l(locale_t locale, char const * __restrict fmt, ...)
+{
+ int ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ ret = vfprintf_l(stdout, locale, fmt, ap);
+ va_end(ap);
+ return (ret);
+}
diff --git a/lib/libc/stdio/printf_l.3 b/lib/libc/stdio/printf_l.3
new file mode 100644
index 000000000000..312d110c2975
--- /dev/null
+++ b/lib/libc/stdio/printf_l.3
@@ -0,0 +1,81 @@
+.\" Copyright (c) 2012 Isabell Long <issyl0@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 April 7, 2012
+.Dt PRINTF_L 3
+.Os
+.Sh NAME
+.Nm printf_l ,
+.Nm asprintf_l ,
+.Nm fprintf_l ,
+.Nm snprintf_l ,
+.Nm sprintf_l ,
+.Nm vasprintf_l ,
+.Nm vfprintf_l ,
+.Nm vprintf_l ,
+.Nm vsnprintf_l ,
+.Nm vsprintf_l
+.Nd formatted output conversion
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdio.h
+.In xlocale.h
+.Ft int
+.Fn printf_l "locale_t loc" "const char * restrict format" "..."
+.Ft int
+.Fn asprintf_l "char **ret" "locale_t loc" "const char * format" "..."
+.Ft int
+.Fn fprintf_l "FILE * restrict stream" "locale_t loc" "const char * restrict format" "..."
+.Ft int
+.Fn snprintf_l "char * restrict str" "size_t size" "locale_t loc" "const char * restrict format" "..."
+.Ft int
+.Fn sprintf_l "char * restrict str" "locale_t loc" "const char * restrict format" "..."
+.Ft int
+.Fn vasprintf_l "char **ret" "locale_t loc" "const char *format" "va_list ap"
+.Ft int
+.Fn vfprintf_l "FILE * restrict stream" "locale_t loc" "const char * restrict format" "va_list ap"
+.Ft int
+.Fn vprintf_l "locale_t loc" "const char * restrict format" "va_list ap"
+.Ft int
+.Fn vsnprintf_l "char * restrict str" "size_t size" "locale_t loc" "const char * restrict format" "va_list ap"
+.Ft int
+.Fn vsprintf_l "char * restrict str" "locale_t loc" "const char * restrict format" "va_list ap"
+.Sh DESCRIPTION
+The above functions are used to convert formatted output in the locale
+.Fa loc .
+They behave in the same way as the versions without the _l suffix, but use
+the specified locale rather than the global or per-thread locale.
+See the specific manual pages for more information.
+.Sh SEE ALSO
+.Xr printf 3 ,
+.Xr xlocale 3
+.Sh STANDARDS
+These functions do not conform to any specific standard so they should be
+considered as non-portable local extensions.
+.Sh HISTORY
+These functions first appeared in Darwin and were first implemented in
+.Fx 9.1 .
diff --git a/lib/libc/stdio/printfcommon.h b/lib/libc/stdio/printfcommon.h
new file mode 100644
index 000000000000..97acc5398ac3
--- /dev/null
+++ b/lib/libc/stdio/printfcommon.h
@@ -0,0 +1,307 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * This file defines common routines used by both printf and wprintf.
+ * You must define CHAR to either char or wchar_t prior to including this.
+ */
+
+
+#ifndef NO_FLOATING_POINT
+
+#define dtoa __dtoa
+#define freedtoa __freedtoa
+
+#include <float.h>
+#include <math.h>
+#include "floatio.h"
+#include "gdtoa.h"
+
+#define DEFPREC 6
+
+static int exponent(CHAR *, int, CHAR);
+
+#endif /* !NO_FLOATING_POINT */
+
+static CHAR *__ujtoa(uintmax_t, CHAR *, int, int, const char *);
+static CHAR *__ultoa(u_long, CHAR *, int, int, const char *);
+
+#define NIOV 8
+struct io_state {
+ FILE *fp;
+ struct __suio uio; /* output information: summary */
+ struct __siov iov[NIOV];/* ... and individual io vectors */
+};
+
+static inline void
+io_init(struct io_state *iop, FILE *fp)
+{
+
+ iop->uio.uio_iov = iop->iov;
+ iop->uio.uio_resid = 0;
+ iop->uio.uio_iovcnt = 0;
+ iop->fp = fp;
+}
+
+/*
+ * WARNING: The buffer passed to io_print() is not copied immediately; it must
+ * remain valid until io_flush() is called.
+ */
+static inline int
+io_print(struct io_state *iop, const CHAR * __restrict ptr, int len, locale_t locale)
+{
+
+ iop->iov[iop->uio.uio_iovcnt].iov_base = (char *)ptr;
+ iop->iov[iop->uio.uio_iovcnt].iov_len = len;
+ iop->uio.uio_resid += len;
+ if (++iop->uio.uio_iovcnt >= NIOV)
+ return (__sprint(iop->fp, &iop->uio, locale));
+ else
+ return (0);
+}
+
+/*
+ * Choose PADSIZE to trade efficiency vs. size. If larger printf
+ * fields occur frequently, increase PADSIZE and make the initialisers
+ * below longer.
+ */
+#define PADSIZE 16 /* pad chunk size */
+static const CHAR blanks[PADSIZE] =
+{' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
+static const CHAR zeroes[PADSIZE] =
+{'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
+
+/*
+ * Pad with blanks or zeroes. 'with' should point to either the blanks array
+ * or the zeroes array.
+ */
+static inline int
+io_pad(struct io_state *iop, int howmany, const CHAR * __restrict with,
+ locale_t locale)
+{
+ int n;
+
+ while (howmany > 0) {
+ n = (howmany >= PADSIZE) ? PADSIZE : howmany;
+ if (io_print(iop, with, n, locale))
+ return (-1);
+ howmany -= n;
+ }
+ return (0);
+}
+
+/*
+ * Print exactly len characters of the string spanning p to ep, truncating
+ * or padding with 'with' as necessary.
+ */
+static inline int
+io_printandpad(struct io_state *iop, const CHAR *p, const CHAR *ep,
+ int len, const CHAR * __restrict with, locale_t locale)
+{
+ int p_len;
+
+ p_len = ep - p;
+ if (p_len > len)
+ p_len = len;
+ if (p_len > 0) {
+ if (io_print(iop, p, p_len, locale))
+ return (-1);
+ } else {
+ p_len = 0;
+ }
+ return (io_pad(iop, len - p_len, with, locale));
+}
+
+static inline int
+io_flush(struct io_state *iop, locale_t locale)
+{
+
+ return (__sprint(iop->fp, &iop->uio, locale));
+}
+
+/*
+ * Convert an unsigned long to ASCII for printf purposes, returning
+ * a pointer to the first character of the string representation.
+ * Octal numbers can be forced to have a leading zero; hex numbers
+ * use the given digits.
+ */
+static CHAR *
+__ultoa(u_long val, CHAR *endp, int base, int octzero, const char *xdigs)
+{
+ CHAR *cp = endp;
+ long sval;
+
+ /*
+ * Handle the three cases separately, in the hope of getting
+ * better/faster code.
+ */
+ switch (base) {
+ case 10:
+ if (val < 10) { /* many numbers are 1 digit */
+ *--cp = to_char(val);
+ return (cp);
+ }
+ /*
+ * On many machines, unsigned arithmetic is harder than
+ * signed arithmetic, so we do at most one unsigned mod and
+ * divide; this is sufficient to reduce the range of
+ * the incoming value to where signed arithmetic works.
+ */
+ if (val > LONG_MAX) {
+ *--cp = to_char(val % 10);
+ sval = val / 10;
+ } else
+ sval = val;
+ do {
+ *--cp = to_char(sval % 10);
+ sval /= 10;
+ } while (sval != 0);
+ break;
+
+ case 8:
+ do {
+ *--cp = to_char(val & 7);
+ val >>= 3;
+ } while (val);
+ if (octzero && *cp != '0')
+ *--cp = '0';
+ break;
+
+ case 16:
+ do {
+ *--cp = xdigs[val & 15];
+ val >>= 4;
+ } while (val);
+ break;
+
+ default: /* oops */
+ abort();
+ }
+ return (cp);
+}
+
+/* Identical to __ultoa, but for intmax_t. */
+static CHAR *
+__ujtoa(uintmax_t val, CHAR *endp, int base, int octzero, const char *xdigs)
+{
+ CHAR *cp = endp;
+ intmax_t sval;
+
+ /* quick test for small values; __ultoa is typically much faster */
+ /* (perhaps instead we should run until small, then call __ultoa?) */
+ if (val <= ULONG_MAX)
+ return (__ultoa((u_long)val, endp, base, octzero, xdigs));
+ switch (base) {
+ case 10:
+ if (val < 10) {
+ *--cp = to_char(val % 10);
+ return (cp);
+ }
+ if (val > INTMAX_MAX) {
+ *--cp = to_char(val % 10);
+ sval = val / 10;
+ } else
+ sval = val;
+ do {
+ *--cp = to_char(sval % 10);
+ sval /= 10;
+ } while (sval != 0);
+ break;
+
+ case 8:
+ do {
+ *--cp = to_char(val & 7);
+ val >>= 3;
+ } while (val);
+ if (octzero && *cp != '0')
+ *--cp = '0';
+ break;
+
+ case 16:
+ do {
+ *--cp = xdigs[val & 15];
+ val >>= 4;
+ } while (val);
+ break;
+
+ default:
+ abort();
+ }
+ return (cp);
+}
+
+#ifndef NO_FLOATING_POINT
+
+static int
+exponent(CHAR *p0, int exp, CHAR fmtch)
+{
+ CHAR *p, *t;
+ CHAR expbuf[MAXEXPDIG];
+
+ p = p0;
+ *p++ = fmtch;
+ if (exp < 0) {
+ exp = -exp;
+ *p++ = '-';
+ }
+ else
+ *p++ = '+';
+ t = expbuf + MAXEXPDIG;
+ if (exp > 9) {
+ do {
+ *--t = to_char(exp % 10);
+ } while ((exp /= 10) > 9);
+ *--t = to_char(exp);
+ for (; t < expbuf + MAXEXPDIG; *p++ = *t++);
+ }
+ else {
+ /*
+ * Exponents for decimal floating point conversions
+ * (%[eEgG]) must be at least two characters long,
+ * whereas exponents for hexadecimal conversions can
+ * be only one character long.
+ */
+ if (fmtch == 'e' || fmtch == 'E')
+ *p++ = '0';
+ *p++ = to_char(exp);
+ }
+ return (p - p0);
+}
+
+#endif /* !NO_FLOATING_POINT */
diff --git a/lib/libc/stdio/printflocal.h b/lib/libc/stdio/printflocal.h
new file mode 100644
index 000000000000..3cef7bd02cdd
--- /dev/null
+++ b/lib/libc/stdio/printflocal.h
@@ -0,0 +1,94 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Flags used during conversion.
+ */
+#define ALT 0x001 /* alternate form */
+#define LADJUST 0x004 /* left adjustment */
+#define LONGDBL 0x008 /* long double */
+#define LONGINT 0x010 /* long integer */
+#define LLONGINT 0x020 /* long long integer */
+#define SHORTINT 0x040 /* short integer */
+#define ZEROPAD 0x080 /* zero (as opposed to blank) pad */
+#define FPT 0x100 /* Floating point number */
+#define GROUPING 0x200 /* use grouping ("'" flag) */
+ /* C99 additional size modifiers: */
+#define SIZET 0x400 /* size_t */
+#define PTRDIFFT 0x800 /* ptrdiff_t */
+#define INTMAXT 0x1000 /* intmax_t */
+#define CHARINT 0x2000 /* print char using int format */
+
+/*
+ * Macros for converting digits to letters and vice versa
+ */
+#define to_digit(c) ((c) - '0')
+#define is_digit(c) ((unsigned)to_digit(c) <= 9)
+#define to_char(n) ((n) + '0')
+
+/* Size of the static argument table. */
+#define STATIC_ARG_TBL_SIZE 8
+
+union arg {
+ int intarg;
+ u_int uintarg;
+ long longarg;
+ u_long ulongarg;
+ long long longlongarg;
+ unsigned long long ulonglongarg;
+ ptrdiff_t ptrdiffarg;
+ size_t sizearg;
+ intmax_t intmaxarg;
+ uintmax_t uintmaxarg;
+ void *pvoidarg;
+ char *pchararg;
+ signed char *pschararg;
+ short *pshortarg;
+ int *pintarg;
+ long *plongarg;
+ long long *plonglongarg;
+ ptrdiff_t *pptrdiffarg;
+ ssize_t *pssizearg;
+ intmax_t *pintmaxarg;
+#ifndef NO_FLOATING_POINT
+ double doublearg;
+ long double longdoublearg;
+#endif
+ wint_t wintarg;
+ wchar_t *pwchararg;
+};
+
+/* Handle positional parameters. */
+int __find_arguments(const char *, va_list, union arg **);
+int __find_warguments(const wchar_t *, va_list, union arg **);
diff --git a/lib/libc/stdio/putc.3 b/lib/libc/stdio/putc.3
new file mode 100644
index 000000000000..a9fea5e63102
--- /dev/null
+++ b/lib/libc/stdio/putc.3
@@ -0,0 +1,165 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek and the American National Standards Committee X3,
+.\" on Information Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)putc.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd January 10, 2003
+.Dt PUTC 3
+.Os
+.Sh NAME
+.Nm fputc ,
+.Nm putc ,
+.Nm putc_unlocked ,
+.Nm putchar ,
+.Nm putchar_unlocked ,
+.Nm putw
+.Nd output a character or word to a stream
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdio.h
+.Ft int
+.Fn fputc "int c" "FILE *stream"
+.Ft int
+.Fn putc "int c" "FILE *stream"
+.Ft int
+.Fn putc_unlocked "int c" "FILE *stream"
+.Ft int
+.Fn putchar "int c"
+.Ft int
+.Fn putchar_unlocked "int c"
+.Ft int
+.Fn putw "int w" "FILE *stream"
+.Sh DESCRIPTION
+The
+.Fn fputc
+function
+writes the character
+.Fa c
+(converted to an ``unsigned char'')
+to the output stream pointed to by
+.Fa stream .
+.Pp
+The
+.Fn putc
+macro acts essentially identically to
+.Fn fputc ,
+but is a macro that expands in-line.
+It may evaluate
+.Fa stream
+more than once, so arguments given to
+.Fn putc
+should not be expressions with potential side effects.
+.Pp
+The
+.Fn putchar
+function
+is identical to
+.Fn putc
+with an output stream of
+.Dv stdout .
+.Pp
+The
+.Fn putw
+function
+writes the specified
+.Vt int
+to the named output
+.Fa stream .
+.Pp
+The
+.Fn putc_unlocked
+and
+.Fn putchar_unlocked
+functions are equivalent to
+.Fn putc
+and
+.Fn putchar
+respectively,
+except that the caller is responsible for locking the stream
+with
+.Xr flockfile 3
+before calling them.
+These functions may be used to avoid the overhead of locking the stream
+for each character, and to avoid output being interspersed from multiple
+threads writing to the same stream.
+.Sh RETURN VALUES
+The functions,
+.Fn fputc ,
+.Fn putc ,
+.Fn putchar ,
+.Fn putc_unlocked
+and
+.Fn putchar_unlocked
+return the character written.
+If an error occurs, the value
+.Dv EOF
+is returned.
+The
+.Fn putw
+function
+returns 0 on success;
+.Dv EOF
+is returned if
+a write error occurs,
+or if an attempt is made to write a read-only stream.
+.Sh SEE ALSO
+.Xr ferror 3 ,
+.Xr flockfile 3 ,
+.Xr fopen 3 ,
+.Xr getc 3 ,
+.Xr putwc 3 ,
+.Xr stdio 3
+.Sh STANDARDS
+The functions
+.Fn fputc ,
+.Fn putc ,
+and
+.Fn putchar ,
+conform to
+.St -isoC .
+The
+.Fn putc_unlocked
+and
+.Fn putchar_unlocked
+functions conform to
+.St -p1003.1-2001 .
+A function
+.Fn putw
+function appeared in
+.At v6 .
+.Sh BUGS
+The size and byte order of an
+.Vt int
+varies from one machine to another, and
+.Fn putw
+is not recommended for portable applications.
diff --git a/lib/libc/stdio/putc.c b/lib/libc/stdio/putc.c
new file mode 100644
index 000000000000..aaffece49d76
--- /dev/null
+++ b/lib/libc/stdio/putc.c
@@ -0,0 +1,65 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)putc.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <stdio.h>
+#include "un-namespace.h"
+#include "local.h"
+#include "libc_private.h"
+
+#undef putc
+#undef putc_unlocked
+
+int
+putc(int c, FILE *fp)
+{
+ int retval;
+ FLOCKFILE(fp);
+ /* Orientation set by __sputc() when buffer is full. */
+ /* ORIENT(fp, -1); */
+ retval = __sputc(c, fp);
+ FUNLOCKFILE(fp);
+ return (retval);
+}
+
+int
+putc_unlocked(int ch, FILE *fp)
+{
+
+ return (__sputc(ch, fp));
+}
diff --git a/lib/libc/stdio/putchar.c b/lib/libc/stdio/putchar.c
new file mode 100644
index 000000000000..756155902f29
--- /dev/null
+++ b/lib/libc/stdio/putchar.c
@@ -0,0 +1,70 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)putchar.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <stdio.h>
+#include "un-namespace.h"
+#include "local.h"
+#include "libc_private.h"
+
+#undef putchar
+#undef putchar_unlocked
+
+/*
+ * A subroutine version of the macro putchar
+ */
+int
+putchar(int c)
+{
+ int retval;
+ FILE *so = stdout;
+
+ FLOCKFILE(so);
+ /* Orientation set by __sputc() when buffer is full. */
+ /* ORIENT(so, -1); */
+ retval = __sputc(c, so);
+ FUNLOCKFILE(so);
+ return (retval);
+}
+
+int
+putchar_unlocked(int ch)
+{
+
+ return (__sputc(ch, stdout));
+}
diff --git a/lib/libc/stdio/puts.c b/lib/libc/stdio/puts.c
new file mode 100644
index 000000000000..124afc73d600
--- /dev/null
+++ b/lib/libc/stdio/puts.c
@@ -0,0 +1,70 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)puts.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <stdio.h>
+#include <string.h>
+#include "un-namespace.h"
+#include "fvwrite.h"
+#include "libc_private.h"
+#include "local.h"
+
+/*
+ * Write the given string to stdout, appending a newline.
+ */
+int
+puts(char const *s)
+{
+ int retval;
+ size_t c;
+ struct __suio uio;
+ struct __siov iov[2];
+
+ iov[0].iov_base = (void *)s;
+ iov[0].iov_len = c = strlen(s);
+ iov[1].iov_base = "\n";
+ iov[1].iov_len = 1;
+ uio.uio_resid = c + 1;
+ uio.uio_iov = &iov[0];
+ uio.uio_iovcnt = 2;
+ FLOCKFILE(stdout);
+ ORIENT(stdout, -1);
+ retval = __sfvwrite(stdout, &uio) ? EOF : '\n';
+ FUNLOCKFILE(stdout);
+ return (retval);
+}
diff --git a/lib/libc/stdio/putw.c b/lib/libc/stdio/putw.c
new file mode 100644
index 000000000000..ecd5d095de5e
--- /dev/null
+++ b/lib/libc/stdio/putw.c
@@ -0,0 +1,60 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)putw.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <stdio.h>
+#include "un-namespace.h"
+#include "fvwrite.h"
+#include "libc_private.h"
+
+int
+putw(int w, FILE *fp)
+{
+ int retval;
+ struct __suio uio;
+ struct __siov iov;
+
+ iov.iov_base = &w;
+ uio.uio_resid = iov.iov_len = sizeof(w);
+ uio.uio_iov = &iov;
+ uio.uio_iovcnt = 1;
+ FLOCKFILE(fp);
+ retval = __sfvwrite(fp, &uio);
+ FUNLOCKFILE(fp);
+ return (retval);
+}
diff --git a/lib/libc/stdio/putwc.3 b/lib/libc/stdio/putwc.3
new file mode 100644
index 000000000000..a661c77894a8
--- /dev/null
+++ b/lib/libc/stdio/putwc.3
@@ -0,0 +1,103 @@
+.\" $NetBSD: putwc.3,v 1.2 2002/02/07 07:00:26 ross Exp $
+.\"
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek and the American National Standards Committee X3,
+.\" on Information Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)putc.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd March 3, 2004
+.Dt PUTWC 3
+.Os
+.Sh NAME
+.Nm fputwc ,
+.Nm putwc ,
+.Nm putwchar
+.Nd output a wide character to a stream
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdio.h
+.In wchar.h
+.Ft wint_t
+.Fn fputwc "wchar_t wc" "FILE *stream"
+.Ft wint_t
+.Fn putwc "wchar_t wc" "FILE *stream"
+.Ft wint_t
+.Fn putwchar "wchar_t wc"
+.Sh DESCRIPTION
+The
+.Fn fputwc
+function
+writes the wide character
+.Fa wc
+to the output stream pointed to by
+.Fa stream .
+.Pp
+The
+.Fn putwc
+function
+acts essentially identically to
+.Fn fputwc .
+.Pp
+The
+.Fn putwchar
+function
+is identical to
+.Fn putwc
+with an output stream of
+.Dv stdout .
+.Sh RETURN VALUES
+The
+.Fn fputwc ,
+.Fn putwc ,
+and
+.Fn putwchar
+functions
+return the wide character written.
+If an error occurs, the value
+.Dv WEOF
+is returned.
+.Sh SEE ALSO
+.Xr ferror 3 ,
+.Xr fopen 3 ,
+.Xr getwc 3 ,
+.Xr putc 3 ,
+.Xr stdio 3
+.Sh STANDARDS
+The
+.Fn fputwc ,
+.Fn putwc ,
+and
+.Fn putwchar
+functions
+conform to
+.St -isoC-99 .
diff --git a/lib/libc/stdio/putwc.c b/lib/libc/stdio/putwc.c
new file mode 100644
index 000000000000..56acf5081c1c
--- /dev/null
+++ b/lib/libc/stdio/putwc.c
@@ -0,0 +1,59 @@
+/*-
+ * Copyright (c) 2002 Tim J. Robbins.
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 "namespace.h"
+#include <stdio.h>
+#include <wchar.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+#include "local.h"
+#include "xlocale_private.h"
+
+#undef putwc
+
+/*
+ * Synonym for fputwc(). The only difference is that putwc(), if it is a
+ * macro, may evaluate `fp' more than once.
+ */
+wint_t
+putwc_l(wchar_t wc, FILE *fp, locale_t locale)
+{
+ FIX_LOCALE(locale);
+ return (fputwc_l(wc, fp, locale));
+}
+wint_t
+putwc(wchar_t wc, FILE *fp)
+{
+ return putwc_l(wc, fp, __get_locale());
+}
diff --git a/lib/libc/stdio/putwchar.c b/lib/libc/stdio/putwchar.c
new file mode 100644
index 000000000000..8673bd5065fa
--- /dev/null
+++ b/lib/libc/stdio/putwchar.c
@@ -0,0 +1,58 @@
+/*-
+ * Copyright (c) 2002 Tim J. Robbins.
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 "namespace.h"
+#include <stdio.h>
+#include <wchar.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+#include "local.h"
+#include "xlocale_private.h"
+
+#undef putwchar
+
+/*
+ * Synonym for fputwc(wc, stdout).
+ */
+wint_t
+putwchar_l(wchar_t wc, locale_t locale)
+{
+ FIX_LOCALE(locale);
+ return (fputwc_l(wc, stdout, locale));
+}
+wint_t
+putwchar(wchar_t wc)
+{
+ return putwchar_l(wc, __get_locale());
+}
diff --git a/lib/libc/stdio/refill.c b/lib/libc/stdio/refill.c
new file mode 100644
index 000000000000..71eb2e53dab6
--- /dev/null
+++ b/lib/libc/stdio/refill.c
@@ -0,0 +1,146 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)refill.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "un-namespace.h"
+
+#include "libc_private.h"
+#include "local.h"
+
+static int lflush(FILE *);
+
+static int
+lflush(FILE *fp)
+{
+ int ret = 0;
+
+ if ((fp->_flags & (__SLBF|__SWR)) == (__SLBF|__SWR)) {
+ FLOCKFILE(fp);
+ ret = __sflush(fp);
+ FUNLOCKFILE(fp);
+ }
+ return (ret);
+}
+
+/*
+ * Refill a stdio buffer.
+ * Return EOF on eof or error, 0 otherwise.
+ */
+int
+__srefill(FILE *fp)
+{
+
+ /* make sure stdio is set up */
+ if (!__sdidinit)
+ __sinit();
+
+ ORIENT(fp, -1);
+
+ fp->_r = 0; /* largely a convenience for callers */
+
+ /* SysV does not make this test; take it out for compatibility */
+ if (fp->_flags & __SEOF)
+ return (EOF);
+
+ /* if not already reading, have to be reading and writing */
+ if ((fp->_flags & __SRD) == 0) {
+ if ((fp->_flags & __SRW) == 0) {
+ errno = EBADF;
+ fp->_flags |= __SERR;
+ return (EOF);
+ }
+ /* switch to reading */
+ if (fp->_flags & __SWR) {
+ if (__sflush(fp))
+ return (EOF);
+ fp->_flags &= ~__SWR;
+ fp->_w = 0;
+ fp->_lbfsize = 0;
+ }
+ fp->_flags |= __SRD;
+ } else {
+ /*
+ * We were reading. If there is an ungetc buffer,
+ * we must have been reading from that. Drop it,
+ * restoring the previous buffer (if any). If there
+ * is anything in that buffer, return.
+ */
+ if (HASUB(fp)) {
+ FREEUB(fp);
+ if ((fp->_r = fp->_ur) != 0) {
+ fp->_p = fp->_up;
+ return (0);
+ }
+ }
+ }
+
+ if (fp->_bf._base == NULL)
+ __smakebuf(fp);
+
+ /*
+ * Before reading from a line buffered or unbuffered file,
+ * flush all line buffered output files, per the ANSI C
+ * standard.
+ */
+ if (fp->_flags & (__SLBF|__SNBF)) {
+ /* Ignore this file in _fwalk to avoid potential deadlock. */
+ fp->_flags |= __SIGN;
+ (void) _fwalk(lflush);
+ fp->_flags &= ~__SIGN;
+
+ /* Now flush this file without locking it. */
+ if ((fp->_flags & (__SLBF|__SWR)) == (__SLBF|__SWR))
+ __sflush(fp);
+ }
+ fp->_p = fp->_bf._base;
+ fp->_r = _sread(fp, (char *)fp->_p, fp->_bf._size);
+ fp->_flags &= ~__SMOD; /* buffer contents are again pristine */
+ if (fp->_r <= 0) {
+ if (fp->_r == 0)
+ fp->_flags |= __SEOF;
+ else {
+ fp->_r = 0;
+ fp->_flags |= __SERR;
+ }
+ return (EOF);
+ }
+ return (0);
+}
diff --git a/lib/libc/stdio/remove.3 b/lib/libc/stdio/remove.3
new file mode 100644
index 000000000000..e7a57fe1fe8b
--- /dev/null
+++ b/lib/libc/stdio/remove.3
@@ -0,0 +1,83 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek and the American National Standards Committee X3,
+.\" on Information Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)remove.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt REMOVE 3
+.Os
+.Sh NAME
+.Nm remove
+.Nd remove directory entry
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdio.h
+.Ft int
+.Fn remove "const char *path"
+.Sh DESCRIPTION
+The
+.Fn remove
+function removes the file or directory specified by
+.Fa path .
+.Pp
+If
+.Fa path
+specifies a directory,
+.Fn remove "path"
+is the equivalent of
+.Fn rmdir "path" .
+Otherwise, it is the equivalent of
+.Fn unlink "path" .
+.Sh RETURN VALUES
+.Rv -std remove
+.Sh ERRORS
+The
+.Fn remove
+function
+may fail and set
+.Va errno
+for any of the errors specified for the routines
+.Xr lstat 2 ,
+.Xr rmdir 2
+or
+.Xr unlink 2 .
+.Sh SEE ALSO
+.Xr rmdir 2 ,
+.Xr unlink 2
+.Sh STANDARDS
+The
+.Fn remove
+function conforms to
+.St -isoC
+and
+.St -xpg4.2 .
diff --git a/lib/libc/stdio/remove.c b/lib/libc/stdio/remove.c
new file mode 100644
index 000000000000..2e984baf9360
--- /dev/null
+++ b/lib/libc/stdio/remove.c
@@ -0,0 +1,54 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)remove.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdio.h>
+
+int
+remove(const char *file)
+{
+ struct stat sb;
+
+ if (lstat(file, &sb) < 0)
+ return (-1);
+ if (S_ISDIR(sb.st_mode))
+ return (rmdir(file));
+ return (unlink(file));
+}
diff --git a/lib/libc/stdio/rewind.c b/lib/libc/stdio/rewind.c
new file mode 100644
index 000000000000..133e3f43dd0c
--- /dev/null
+++ b/lib/libc/stdio/rewind.c
@@ -0,0 +1,60 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)rewind.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <errno.h>
+#include <stdio.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+#include "local.h"
+
+void
+rewind(FILE *fp)
+{
+ int serrno = errno;
+
+ /* make sure stdio is set up */
+ if (!__sdidinit)
+ __sinit();
+
+ FLOCKFILE(fp);
+ if (_fseeko(fp, (off_t)0, SEEK_SET, 1) == 0)
+ errno = serrno;
+ clearerr_unlocked(fp); /* POSIX: clear stdio error regardless */
+ FUNLOCKFILE(fp);
+}
diff --git a/lib/libc/stdio/rget.c b/lib/libc/stdio/rget.c
new file mode 100644
index 000000000000..bdc0311674e1
--- /dev/null
+++ b/lib/libc/stdio/rget.c
@@ -0,0 +1,55 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)rget.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include "local.h"
+
+/*
+ * Handle getc() when the buffer ran out:
+ * Refill, then return the first character
+ * in the newly-filled buffer.
+ */
+int
+__srget(FILE *fp)
+{
+ if (__srefill(fp) == 0) {
+ fp->_r--;
+ return (*fp->_p++);
+ }
+ return (EOF);
+}
diff --git a/lib/libc/stdio/scanf.3 b/lib/libc/stdio/scanf.3
new file mode 100644
index 000000000000..8a8666ccfaa0
--- /dev/null
+++ b/lib/libc/stdio/scanf.3
@@ -0,0 +1,513 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek and the American National Standards Committee X3,
+.\" on Information Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)scanf.3 8.2 (Berkeley) 12/11/93
+.\" $FreeBSD$
+.\"
+.Dd January 4, 2003
+.Dt SCANF 3
+.Os
+.Sh NAME
+.Nm scanf ,
+.Nm fscanf ,
+.Nm sscanf ,
+.Nm vscanf ,
+.Nm vsscanf ,
+.Nm vfscanf
+.Nd input format conversion
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdio.h
+.Ft int
+.Fn scanf "const char * restrict format" ...
+.Ft int
+.Fn fscanf "FILE * restrict stream" "const char * restrict format" ...
+.Ft int
+.Fn sscanf "const char * restrict str" "const char * restrict format" ...
+.In stdarg.h
+.Ft int
+.Fn vscanf "const char * restrict format" "va_list ap"
+.Ft int
+.Fn vsscanf "const char * restrict str" "const char * restrict format" "va_list ap"
+.Ft int
+.Fn vfscanf "FILE * restrict stream" "const char * restrict format" "va_list ap"
+.Sh DESCRIPTION
+The
+.Fn scanf
+family of functions scans input according to a
+.Fa format
+as described below.
+This format may contain
+.Em conversion specifiers ;
+the results from such conversions, if any,
+are stored through the
+.Em pointer
+arguments.
+The
+.Fn scanf
+function
+reads input from the standard input stream
+.Dv stdin ,
+.Fn fscanf
+reads input from the stream pointer
+.Fa stream ,
+and
+.Fn sscanf
+reads its input from the character string pointed to by
+.Fa str .
+The
+.Fn vfscanf
+function
+is analogous to
+.Xr vfprintf 3
+and reads input from the stream pointer
+.Fa stream
+using a variable argument list of pointers (see
+.Xr stdarg 3 ) .
+The
+.Fn vscanf
+function scans a variable argument list from the standard input and
+the
+.Fn vsscanf
+function scans it from a string;
+these are analogous to
+the
+.Fn vprintf
+and
+.Fn vsprintf
+functions respectively.
+Each successive
+.Em pointer
+argument must correspond properly with
+each successive conversion specifier
+(but see the
+.Cm *
+conversion below).
+All conversions are introduced by the
+.Cm %
+(percent sign) character.
+The
+.Fa format
+string
+may also contain other characters.
+White space (such as blanks, tabs, or newlines) in the
+.Fa format
+string match any amount of white space, including none, in the input.
+Everything else
+matches only itself.
+Scanning stops
+when an input character does not match such a format character.
+Scanning also stops
+when an input conversion cannot be made (see below).
+.Sh CONVERSIONS
+Following the
+.Cm %
+character introducing a conversion
+there may be a number of
+.Em flag
+characters, as follows:
+.Bl -tag -width ".Cm l No (ell)"
+.It Cm *
+Suppresses assignment.
+The conversion that follows occurs as usual, but no pointer is used;
+the result of the conversion is simply discarded.
+.It Cm hh
+Indicates that the conversion will be one of
+.Cm dioux
+or
+.Cm n
+and the next pointer is a pointer to a
+.Vt char
+(rather than
+.Vt int ) .
+.It Cm h
+Indicates that the conversion will be one of
+.Cm dioux
+or
+.Cm n
+and the next pointer is a pointer to a
+.Vt "short int"
+(rather than
+.Vt int ) .
+.It Cm l No (ell)
+Indicates that the conversion will be one of
+.Cm dioux
+or
+.Cm n
+and the next pointer is a pointer to a
+.Vt "long int"
+(rather than
+.Vt int ) ,
+that the conversion will be one of
+.Cm a , e , f ,
+or
+.Cm g
+and the next pointer is a pointer to
+.Vt double
+(rather than
+.Vt float ) ,
+or that the conversion will be one of
+.Cm c ,
+.Cm s
+or
+.Cm \&[
+and the next pointer is a pointer to an array of
+.Vt wchar_t
+(rather than
+.Vt char ) .
+.It Cm ll No (ell ell)
+Indicates that the conversion will be one of
+.Cm dioux
+or
+.Cm n
+and the next pointer is a pointer to a
+.Vt "long long int"
+(rather than
+.Vt int ) .
+.It Cm L
+Indicates that the conversion will be one of
+.Cm a , e , f ,
+or
+.Cm g
+and the next pointer is a pointer to
+.Vt "long double" .
+.It Cm j
+Indicates that the conversion will be one of
+.Cm dioux
+or
+.Cm n
+and the next pointer is a pointer to a
+.Vt intmax_t
+(rather than
+.Vt int ) .
+.It Cm t
+Indicates that the conversion will be one of
+.Cm dioux
+or
+.Cm n
+and the next pointer is a pointer to a
+.Vt ptrdiff_t
+(rather than
+.Vt int ) .
+.It Cm z
+Indicates that the conversion will be one of
+.Cm dioux
+or
+.Cm n
+and the next pointer is a pointer to a
+.Vt size_t
+(rather than
+.Vt int ) .
+.It Cm q
+(deprecated.)
+Indicates that the conversion will be one of
+.Cm dioux
+or
+.Cm n
+and the next pointer is a pointer to a
+.Vt "long long int"
+(rather than
+.Vt int ) .
+.El
+.Pp
+In addition to these flags,
+there may be an optional maximum field width,
+expressed as a decimal integer,
+between the
+.Cm %
+and the conversion.
+If no width is given,
+a default of
+.Dq infinity
+is used (with one exception, below);
+otherwise at most this many bytes are scanned
+in processing the conversion.
+In the case of the
+.Cm lc ,
+.Cm ls
+and
+.Cm l[
+conversions, the field width specifies the maximum number
+of multibyte characters that will be scanned.
+Before conversion begins,
+most conversions skip white space;
+this white space is not counted against the field width.
+.Pp
+The following conversions are available:
+.Bl -tag -width XXXX
+.It Cm %
+Matches a literal
+.Ql % .
+That is,
+.Dq Li %%
+in the format string
+matches a single input
+.Ql %
+character.
+No conversion is done, and assignment does not occur.
+.It Cm d
+Matches an optionally signed decimal integer;
+the next pointer must be a pointer to
+.Vt int .
+.It Cm i
+Matches an optionally signed integer;
+the next pointer must be a pointer to
+.Vt int .
+The integer is read in base 16 if it begins
+with
+.Ql 0x
+or
+.Ql 0X ,
+in base 8 if it begins with
+.Ql 0 ,
+and in base 10 otherwise.
+Only characters that correspond to the base are used.
+.It Cm o
+Matches an octal integer;
+the next pointer must be a pointer to
+.Vt "unsigned int" .
+.It Cm u
+Matches an optionally signed decimal integer;
+the next pointer must be a pointer to
+.Vt "unsigned int" .
+.It Cm x , X
+Matches an optionally signed hexadecimal integer;
+the next pointer must be a pointer to
+.Vt "unsigned int" .
+.It Cm a , A , e , E , f , F , g , G
+Matches a floating-point number in the style of
+.Xr strtod 3 .
+The next pointer must be a pointer to
+.Vt float
+(unless
+.Cm l
+or
+.Cm L
+is specified.)
+.It Cm s
+Matches a sequence of non-white-space characters;
+the next pointer must be a pointer to
+.Vt char ,
+and the array must be large enough to accept all the sequence and the
+terminating
+.Dv NUL
+character.
+The input string stops at white space
+or at the maximum field width, whichever occurs first.
+.Pp
+If an
+.Cm l
+qualifier is present, the next pointer must be a pointer to
+.Vt wchar_t ,
+into which the input will be placed after conversion by
+.Xr mbrtowc 3 .
+.It Cm S
+The same as
+.Cm ls .
+.It Cm c
+Matches a sequence of
+.Em width
+count
+characters (default 1);
+the next pointer must be a pointer to
+.Vt char ,
+and there must be enough room for all the characters
+(no terminating
+.Dv NUL
+is added).
+The usual skip of leading white space is suppressed.
+To skip white space first, use an explicit space in the format.
+.Pp
+If an
+.Cm l
+qualifier is present, the next pointer must be a pointer to
+.Vt wchar_t ,
+into which the input will be placed after conversion by
+.Xr mbrtowc 3 .
+.It Cm C
+The same as
+.Cm lc .
+.It Cm \&[
+Matches a nonempty sequence of characters from the specified set
+of accepted characters;
+the next pointer must be a pointer to
+.Vt char ,
+and there must be enough room for all the characters in the string,
+plus a terminating
+.Dv NUL
+character.
+The usual skip of leading white space is suppressed.
+The string is to be made up of characters in
+(or not in)
+a particular set;
+the set is defined by the characters between the open bracket
+.Cm \&[
+character
+and a close bracket
+.Cm \&]
+character.
+The set
+.Em excludes
+those characters
+if the first character after the open bracket is a circumflex
+.Cm ^ .
+To include a close bracket in the set,
+make it the first character after the open bracket
+or the circumflex;
+any other position will end the set.
+The hyphen character
+.Cm -
+is also special;
+when placed between two other characters,
+it adds all intervening characters to the set.
+To include a hyphen,
+make it the last character before the final close bracket.
+For instance,
+.Ql [^]0-9-]
+means the set
+.Dq "everything except close bracket, zero through nine, and hyphen" .
+The string ends with the appearance of a character not in the
+(or, with a circumflex, in) set
+or when the field width runs out.
+.Pp
+If an
+.Cm l
+qualifier is present, the next pointer must be a pointer to
+.Vt wchar_t ,
+into which the input will be placed after conversion by
+.Xr mbrtowc 3 .
+.It Cm p
+Matches a pointer value (as printed by
+.Ql %p
+in
+.Xr printf 3 ) ;
+the next pointer must be a pointer to
+.Vt void .
+.It Cm n
+Nothing is expected;
+instead, the number of characters consumed thus far from the input
+is stored through the next pointer,
+which must be a pointer to
+.Vt int .
+This is
+.Em not
+a conversion, although it can be suppressed with the
+.Cm *
+flag.
+.El
+.Pp
+The decimal point
+character is defined in the program's locale (category
+.Dv LC_NUMERIC ) .
+.Pp
+For backwards compatibility, a
+.Dq conversion
+of
+.Ql %\e0
+causes an immediate return of
+.Dv EOF .
+.Sh RETURN VALUES
+These
+functions
+return
+the number of input items assigned, which can be fewer than provided
+for, or even zero, in the event of a matching failure.
+Zero
+indicates that, while there was input available,
+no conversions were assigned;
+typically this is due to an invalid input character,
+such as an alphabetic character for a
+.Ql %d
+conversion.
+The value
+.Dv EOF
+is returned if an input failure occurs before any conversion such as an
+end-of-file occurs.
+If an error or end-of-file occurs after conversion
+has begun,
+the number of conversions which were successfully completed is returned.
+.Sh SEE ALSO
+.Xr getc 3 ,
+.Xr mbrtowc 3 ,
+.Xr printf 3 ,
+.Xr strtod 3 ,
+.Xr strtol 3 ,
+.Xr strtoul 3 ,
+.Xr wscanf 3
+.Sh STANDARDS
+The functions
+.Fn fscanf ,
+.Fn scanf ,
+.Fn sscanf ,
+.Fn vfscanf ,
+.Fn vscanf
+and
+.Fn vsscanf
+conform to
+.St -isoC-99 .
+.Sh BUGS
+Earlier implementations of
+.Nm
+treated
+.Cm \&%D , \&%E , \&%F , \&%O
+and
+.Cm \&%X
+as their lowercase equivalents with an
+.Cm l
+modifier.
+In addition,
+.Nm
+treated an unknown conversion character as
+.Cm \&%d
+or
+.Cm \&%D ,
+depending on its case.
+This functionality has been removed.
+.Pp
+Numerical strings are truncated to 512 characters; for example,
+.Cm %f
+and
+.Cm %d
+are implicitly
+.Cm %512f
+and
+.Cm %512d .
+.Pp
+The
+.Cm %n$
+modifiers for positional arguments are not implemented.
+.Pp
+The
+.Nm
+family of functions do not correctly handle multibyte characters in the
+.Fa format
+argument.
diff --git a/lib/libc/stdio/scanf.c b/lib/libc/stdio/scanf.c
new file mode 100644
index 000000000000..e377724ac5be
--- /dev/null
+++ b/lib/libc/stdio/scanf.c
@@ -0,0 +1,78 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)scanf.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <stdio.h>
+#include <stdarg.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+#include "local.h"
+#include "xlocale_private.h"
+
+int
+scanf(char const * __restrict fmt, ...)
+{
+ int ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ FLOCKFILE(stdin);
+ ret = __svfscanf(stdin, __get_locale(), fmt, ap);
+ FUNLOCKFILE(stdin);
+ va_end(ap);
+ return (ret);
+}
+int
+scanf_l(locale_t locale, char const * __restrict fmt, ...)
+{
+ int ret;
+ va_list ap;
+ FIX_LOCALE(locale);
+
+ va_start(ap, fmt);
+ FLOCKFILE(stdin);
+ ret = __svfscanf(stdin, locale, fmt, ap);
+ FUNLOCKFILE(stdin);
+ va_end(ap);
+ return (ret);
+}
diff --git a/lib/libc/stdio/scanf_l.3 b/lib/libc/stdio/scanf_l.3
new file mode 100644
index 000000000000..35a82418ec51
--- /dev/null
+++ b/lib/libc/stdio/scanf_l.3
@@ -0,0 +1,71 @@
+.\" Copyright (c) 2012 Isabell Long <issyl0@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 April 8, 2012
+.Dt SCANF_L 3
+.Os
+.Sh NAME
+.Nm scanf_l ,
+.Nm fscanf_l ,
+.Nm sscanf_l ,
+.Nm vfscanf_l ,
+.Nm vscanf_l ,
+.Nm vsscanf_l
+.Nd input format conversion
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdio.h
+.In xlocale.h
+.Ft int
+.Fn scanf_l "locale_t loc" "const char * restrict format" "..."
+.Ft int
+.Fn fscanf_l "FILE * restrict stream" "locale_t loc" "const char * restrict format" "..."
+.Ft int
+.Fn sscanf_l "const char * restrict str" "locale_t loc" "const char * restrict format" "..."
+.Ft int
+.Fn vfscanf_l "FILE * restrict stream" "locale_t loc" "const char * restrict format" "va_list ap"
+.Ft int
+.Fn vscanf_l "locale_t loc" "const char * restrict format" "va_list ap"
+.Ft int
+.Fn vsscanf_l "const char * restrict str" "locale_t loc" "const char * restrict format" "va_list ap"
+.Sh DESCRIPTION
+The above functions scan input according to a specified
+.Fa format
+in the locale
+.Fa loc .
+They behave in the same way as the versions without the _l suffix, but use
+the specific locale rather than the global or per-thread locale.
+See the specific manual pages for more information.
+.Sh SEE ALSO
+.Xr scanf 3 ,
+.Xr xlocale 3
+.Sh STANDARDS
+These functions do not conform to any specific standard so they should be
+considered as non-portable local extensions.
+.Sh HISTORY
+These functions first appeared in Darwin and were first implemented in
+.Fx 9.1 .
diff --git a/lib/libc/stdio/setbuf.3 b/lib/libc/stdio/setbuf.3
new file mode 100644
index 000000000000..d1ae70b03345
--- /dev/null
+++ b/lib/libc/stdio/setbuf.3
@@ -0,0 +1,200 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)setbuf.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd February 18, 2013
+.Dt SETBUF 3
+.Os
+.Sh NAME
+.Nm setbuf ,
+.Nm setbuffer ,
+.Nm setlinebuf ,
+.Nm setvbuf
+.Nd stream buffering operations
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdio.h
+.Ft void
+.Fn setbuf "FILE * restrict stream" "char * restrict buf"
+.Ft void
+.Fn setbuffer "FILE *stream" "char *buf" "int size"
+.Ft int
+.Fn setlinebuf "FILE *stream"
+.Ft int
+.Fn setvbuf "FILE * restrict stream" "char * restrict buf" "int mode" "size_t size"
+.Sh DESCRIPTION
+The three types of buffering available are unbuffered, block buffered,
+and line buffered.
+When an output stream is unbuffered, information appears on the
+destination file or terminal as soon as written;
+when it is block buffered many characters are saved up and written as a block;
+when it is line buffered characters are saved up until a newline is
+output or input is read from any stream attached to a terminal device
+(typically
+.Dv stdin ) .
+The function
+.Xr fflush 3
+may be used to force the block out early.
+(See
+.Xr fclose 3 . )
+.Pp
+Normally all files are block buffered.
+When the first
+.Tn I/O
+operation occurs on a file,
+.Xr malloc 3
+is called,
+and an optimally-sized buffer is obtained.
+If a stream refers to a terminal
+(as
+.Dv stdout
+normally does) it is line buffered.
+The standard error stream
+.Dv stderr
+is always unbuffered.
+Note that these defaults may be altered using the
+.Xr stdbuf 1
+utility.
+.Pp
+The
+.Fn setvbuf
+function
+may be used to alter the buffering behavior of a stream.
+The
+.Fa mode
+argument must be one of the following three macros:
+.Bl -tag -width _IOFBF -offset indent
+.It Dv _IONBF
+unbuffered
+.It Dv _IOLBF
+line buffered
+.It Dv _IOFBF
+fully buffered
+.El
+.Pp
+The
+.Fa size
+argument may be given as zero
+to obtain deferred optimal-size buffer allocation as usual.
+If it is not zero,
+then except for unbuffered files, the
+.Fa buf
+argument should point to a buffer at least
+.Fa size
+bytes long;
+this buffer will be used instead of the current buffer.
+If
+.Fa buf
+is not
+.Dv NULL ,
+it is the caller's responsibility to
+.Xr free 3
+this buffer after closing the stream.
+(If the
+.Fa size
+argument
+is not zero but
+.Fa buf
+is
+.Dv NULL ,
+a buffer of the given size will be allocated immediately,
+and released on close.
+This is an extension to ANSI C;
+portable code should use a size of 0 with any
+.Dv NULL
+buffer.)
+.Pp
+The
+.Fn setvbuf
+function may be used at any time,
+but may have peculiar side effects
+(such as discarding input or flushing output)
+if the stream is ``active''.
+Portable applications should call it only once on any given stream,
+and before any
+.Tn I/O
+is performed.
+.Pp
+The other three calls are, in effect, simply aliases for calls to
+.Fn setvbuf .
+Except for the lack of a return value, the
+.Fn setbuf
+function is exactly equivalent to the call
+.Pp
+.Dl "setvbuf(stream, buf, buf ? _IOFBF : _IONBF, BUFSIZ);"
+.Pp
+The
+.Fn setbuffer
+function
+is the same, except that the size of the buffer is up to the caller,
+rather than being determined by the default
+.Dv BUFSIZ .
+The
+.Fn setlinebuf
+function
+is exactly equivalent to the call:
+.Pp
+.Dl "setvbuf(stream, (char *)NULL, _IOLBF, 0);"
+.Sh RETURN VALUES
+The
+.Fn setvbuf
+function returns 0 on success, or
+.Dv EOF
+if the request cannot be honored
+(note that the stream is still functional in this case).
+.Pp
+The
+.Fn setlinebuf
+function returns what the equivalent
+.Fn setvbuf
+would have returned.
+.Sh SEE ALSO
+.Xr stdbuf 1 ,
+.Xr fclose 3 ,
+.Xr fopen 3 ,
+.Xr fread 3 ,
+.Xr malloc 3 ,
+.Xr printf 3 ,
+.Xr puts 3
+.Sh STANDARDS
+The
+.Fn setbuf
+and
+.Fn setvbuf
+functions
+conform to
+.St -isoC .
+.Sh BUGS
+.Fn setbuf
+usually uses a suboptimal buffer size and should be avoided.
diff --git a/lib/libc/stdio/setbuf.c b/lib/libc/stdio/setbuf.c
new file mode 100644
index 000000000000..5c65f976c9de
--- /dev/null
+++ b/lib/libc/stdio/setbuf.c
@@ -0,0 +1,46 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)setbuf.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include "local.h"
+
+void
+setbuf(FILE * __restrict fp, char * __restrict buf)
+{
+ (void) setvbuf(fp, buf, buf ? _IOFBF : _IONBF, BUFSIZ);
+}
diff --git a/lib/libc/stdio/setbuffer.c b/lib/libc/stdio/setbuffer.c
new file mode 100644
index 000000000000..af5eb3cabf6e
--- /dev/null
+++ b/lib/libc/stdio/setbuffer.c
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)setbuffer.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+
+void
+setbuffer(FILE *fp, char *buf, int size)
+{
+
+ (void)setvbuf(fp, buf, buf ? _IOFBF : _IONBF, (size_t)size);
+}
+
+/*
+ * set line buffering
+ */
+int
+setlinebuf(FILE *fp)
+{
+
+ return (setvbuf(fp, (char *)NULL, _IOLBF, (size_t)0));
+}
diff --git a/lib/libc/stdio/setvbuf.c b/lib/libc/stdio/setvbuf.c
new file mode 100644
index 000000000000..d39696058616
--- /dev/null
+++ b/lib/libc/stdio/setvbuf.c
@@ -0,0 +1,161 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)setvbuf.c 8.2 (Berkeley) 11/16/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include "un-namespace.h"
+#include "local.h"
+#include "libc_private.h"
+
+/*
+ * Set one of the three kinds of buffering, optionally including
+ * a buffer.
+ */
+int
+setvbuf(FILE * __restrict fp, char * __restrict buf, int mode, size_t size)
+{
+ int ret, flags;
+ size_t iosize;
+ int ttyflag;
+
+ /*
+ * Verify arguments. The `int' limit on `size' is due to this
+ * particular implementation. Note, buf and size are ignored
+ * when setting _IONBF.
+ */
+ if (mode != _IONBF)
+ if ((mode != _IOFBF && mode != _IOLBF) || (int)size < 0)
+ return (EOF);
+
+ FLOCKFILE(fp);
+ /*
+ * Write current buffer, if any. Discard unread input (including
+ * ungetc data), cancel line buffering, and free old buffer if
+ * malloc()ed. We also clear any eof condition, as if this were
+ * a seek.
+ */
+ ret = 0;
+ (void)__sflush(fp);
+ if (HASUB(fp))
+ FREEUB(fp);
+ fp->_r = fp->_lbfsize = 0;
+ flags = fp->_flags;
+ if (flags & __SMBF)
+ free((void *)fp->_bf._base);
+ flags &= ~(__SLBF | __SNBF | __SMBF | __SOPT | __SOFF | __SNPT | __SEOF);
+
+ /* If setting unbuffered mode, skip all the hard work. */
+ if (mode == _IONBF)
+ goto nbf;
+
+ /*
+ * Find optimal I/O size for seek optimization. This also returns
+ * a `tty flag' to suggest that we check isatty(fd), but we do not
+ * care since our caller told us how to buffer.
+ */
+ flags |= __swhatbuf(fp, &iosize, &ttyflag);
+ if (size == 0) {
+ buf = NULL; /* force local allocation */
+ size = iosize;
+ }
+
+ /* Allocate buffer if needed. */
+ if (buf == NULL) {
+ if ((buf = malloc(size)) == NULL) {
+ /*
+ * Unable to honor user's request. We will return
+ * failure, but try again with file system size.
+ */
+ ret = EOF;
+ if (size != iosize) {
+ size = iosize;
+ buf = malloc(size);
+ }
+ }
+ if (buf == NULL) {
+ /* No luck; switch to unbuffered I/O. */
+nbf:
+ fp->_flags = flags | __SNBF;
+ fp->_w = 0;
+ fp->_bf._base = fp->_p = fp->_nbuf;
+ fp->_bf._size = 1;
+ FUNLOCKFILE(fp);
+ return (ret);
+ }
+ flags |= __SMBF;
+ }
+
+ /*
+ * Kill any seek optimization if the buffer is not the
+ * right size.
+ *
+ * SHOULD WE ALLOW MULTIPLES HERE (i.e., ok iff (size % iosize) == 0)?
+ */
+ if (size != iosize)
+ flags |= __SNPT;
+
+ /*
+ * Fix up the FILE fields, and set __cleanup for output flush on
+ * exit (since we are buffered in some way).
+ */
+ if (mode == _IOLBF)
+ flags |= __SLBF;
+ fp->_flags = flags;
+ fp->_bf._base = fp->_p = (unsigned char *)buf;
+ fp->_bf._size = size;
+ /* fp->_lbfsize is still 0 */
+ if (flags & __SWR) {
+ /*
+ * Begin or continue writing: see __swsetup(). Note
+ * that __SNBF is impossible (it was handled earlier).
+ */
+ if (flags & __SLBF) {
+ fp->_w = 0;
+ fp->_lbfsize = -fp->_bf._size;
+ } else
+ fp->_w = size;
+ } else {
+ /* begin/continue reading, or stay in intermediate state */
+ fp->_w = 0;
+ }
+ __cleanup = _cleanup;
+
+ FUNLOCKFILE(fp);
+ return (ret);
+}
diff --git a/lib/libc/stdio/snprintf.c b/lib/libc/stdio/snprintf.c
new file mode 100644
index 000000000000..e2dd2ddd6c0c
--- /dev/null
+++ b/lib/libc/stdio/snprintf.c
@@ -0,0 +1,105 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)snprintf.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include "xlocale_private.h"
+
+#include "local.h"
+
+int
+snprintf(char * __restrict str, size_t n, char const * __restrict fmt, ...)
+{
+ size_t on;
+ int ret;
+ va_list ap;
+ FILE f = FAKE_FILE;
+
+ on = n;
+ if (n != 0)
+ n--;
+ if (n > INT_MAX) {
+ errno = EOVERFLOW;
+ *str = '\0';
+ return (EOF);
+ }
+ va_start(ap, fmt);
+ f._flags = __SWR | __SSTR;
+ f._bf._base = f._p = (unsigned char *)str;
+ f._bf._size = f._w = n;
+ ret = __vfprintf(&f, __get_locale(), fmt, ap);
+ if (on > 0)
+ *f._p = '\0';
+ va_end(ap);
+ return (ret);
+}
+int
+snprintf_l(char * __restrict str, size_t n, locale_t locale,
+ char const * __restrict fmt, ...)
+{
+ size_t on;
+ int ret;
+ va_list ap;
+ FILE f = FAKE_FILE;
+ FIX_LOCALE(locale);
+
+ on = n;
+ if (n != 0)
+ n--;
+ if (n > INT_MAX) {
+ errno = EOVERFLOW;
+ *str = '\0';
+ return (EOF);
+ }
+ va_start(ap, fmt);
+ f._flags = __SWR | __SSTR;
+ f._bf._base = f._p = (unsigned char *)str;
+ f._bf._size = f._w = n;
+ ret = __vfprintf(&f, locale, fmt, ap);
+ if (on > 0)
+ *f._p = '\0';
+ va_end(ap);
+ return (ret);
+}
diff --git a/lib/libc/stdio/sprintf.c b/lib/libc/stdio/sprintf.c
new file mode 100644
index 000000000000..0f38d15cd2ce
--- /dev/null
+++ b/lib/libc/stdio/sprintf.c
@@ -0,0 +1,73 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)sprintf.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <limits.h>
+#include "local.h"
+#include "xlocale_private.h"
+
+int
+sprintf(char * __restrict str, char const * __restrict fmt, ...)
+{
+ int ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ ret = vsprintf(str, fmt, ap);
+ va_end(ap);
+ return (ret);
+}
+int
+sprintf_l(char * __restrict str, locale_t locale, char const * __restrict fmt,
+ ...)
+{
+ int ret;
+ va_list ap;
+ FIX_LOCALE(locale);
+
+ va_start(ap, fmt);
+ ret = vsprintf_l(str, locale, fmt, ap);
+ va_end(ap);
+ return (ret);
+}
diff --git a/lib/libc/stdio/sscanf.c b/lib/libc/stdio/sscanf.c
new file mode 100644
index 000000000000..ae79451a47fc
--- /dev/null
+++ b/lib/libc/stdio/sscanf.c
@@ -0,0 +1,72 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)sscanf.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <xlocale.h>
+#include "local.h"
+
+int
+sscanf(const char * __restrict str, char const * __restrict fmt, ...)
+{
+ int ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ ret = vsscanf(str, fmt, ap);
+ va_end(ap);
+ return (ret);
+}
+int
+sscanf_l(const char * __restrict str, locale_t locale,
+ char const * __restrict fmt, ...)
+{
+ int ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ ret = vsscanf_l(str, locale, fmt, ap);
+ va_end(ap);
+ return (ret);
+}
diff --git a/lib/libc/stdio/stdio.3 b/lib/libc/stdio/stdio.3
new file mode 100644
index 000000000000..53320b5d7a25
--- /dev/null
+++ b/lib/libc/stdio/stdio.3
@@ -0,0 +1,333 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)stdio.3 8.7 (Berkeley) 4/19/94
+.\" $FreeBSD$
+.\"
+.Dd March 3, 2009
+.Dt STDIO 3
+.Os
+.Sh NAME
+.Nm stdio
+.Nd standard input/output library functions
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdio.h
+.Vt FILE *stdin ;
+.Vt FILE *stdout ;
+.Vt FILE *stderr ;
+.Sh DESCRIPTION
+The standard
+.Tn I/O
+library provides a simple and efficient buffered stream
+.Tn I/O
+interface.
+Input and output is mapped into logical data streams
+and the physical
+.Tn I/O
+characteristics are concealed.
+The functions and macros are listed
+below; more information is available from the individual man pages.
+.Pp
+A stream is associated with an external file (which may be a physical
+device) by
+.Em opening
+a file, which may involve creating a new file.
+Creating an
+existing file causes its former contents to be discarded.
+If a file can support positioning requests (such as a disk file, as opposed
+to a terminal) then a
+.Em file position indicator
+associated with the stream is positioned at the start of the file (byte
+zero), unless the file is opened with append mode.
+If append mode
+is used, the position indicator will be placed at the end-of-file.
+The position indicator is maintained by subsequent reads, writes
+and positioning requests.
+All input occurs as if the characters
+were read by successive calls to the
+.Xr fgetc 3
+function; all output takes place as if all characters were
+written by successive calls to the
+.Xr fputc 3
+function.
+.Pp
+A file is disassociated from a stream by
+.Em closing
+the file.
+Output streams are flushed (any unwritten buffer contents are transferred
+to the host environment) before the stream is disassociated from the file.
+The value of a pointer to a
+.Dv FILE
+object is indeterminate (garbage) after a file is closed.
+.Pp
+A file may be subsequently reopened, by the same or another program
+execution, and its contents reclaimed or modified (if it can be repositioned
+at the start).
+If the main function returns to its original caller, or
+the
+.Xr exit 3
+function is called, all open files are closed (hence all output
+streams are flushed) before program termination.
+Other methods
+of program termination may not close files properly and hence
+buffered output may be lost.
+In particular,
+.Xr _exit 2
+does not flush stdio files.
+Neither does an exit due to a signal.
+Buffers are flushed by
+.Xr abort 3
+as required by POSIX, although previous implementations did not.
+.Pp
+This implementation makes no distinction between
+.Dq text
+and
+.Dq binary
+streams.
+In effect, all streams are binary.
+No translation is performed and no extra padding appears on any stream.
+.Pp
+At program startup, three streams are predefined and need not be
+opened explicitly:
+.Bl -bullet -compact -offset indent
+.It
+.Em standard input
+(for reading conventional input),
+.It
+.Em standard output
+(for writing conventional output), and
+.It
+.Em standard error
+(for writing diagnostic output).
+.El
+These streams are abbreviated
+.Dv stdin , stdout
+and
+.Dv stderr .
+Initially, the standard error stream
+is unbuffered; the standard input and output streams are
+fully buffered if and only if the streams do not refer to
+an interactive or
+.Dq terminal
+device, as determined by the
+.Xr isatty 3
+function.
+In fact,
+.Em all
+freshly-opened streams that refer to terminal devices
+default to line buffering, and
+pending output to such streams is written automatically
+whenever such an input stream is read.
+Note that this applies only to
+.Dq "true reads" ;
+if the read request can be satisfied by existing buffered data,
+no automatic flush will occur.
+In these cases,
+or when a large amount of computation is done after printing
+part of a line on an output terminal, it is necessary to
+.Xr fflush 3
+the standard output before going off and computing so that the output
+will appear.
+Alternatively, these defaults may be modified via the
+.Xr setvbuf 3
+function.
+.Pp
+The
+.Nm
+library is a part of the library
+.Nm libc
+and routines are automatically loaded as needed by the C compiler.
+The
+.Tn SYNOPSIS
+sections of the following manual pages indicate which include files
+are to be used, what the compiler declaration for the function
+looks like and which external variables are of interest.
+.Pp
+The following are defined as macros;
+these names may not be re-used
+without first removing their current definitions with
+.Ic #undef :
+.Dv BUFSIZ ,
+.Dv EOF ,
+.Dv FILENAME_MAX ,
+.Dv FOPEN_MAX ,
+.Dv L_ctermid ,
+.Dv L_cuserid ,
+.Dv L_tmpnam ,
+.Dv NULL ,
+.Dv P_tmpdir ,
+.Dv SEEK_CUR ,
+.Dv SEEK_END ,
+.Dv SEEK_SET ,
+.Dv TMP_MAX ,
+.Dv clearerr ,
+.Dv clearerr_unlocked ,
+.Dv feof ,
+.Dv feof_unlocked ,
+.Dv ferror ,
+.Dv ferror_unlocked ,
+.Dv fileno ,
+.Dv fileno_unlocked ,
+.Dv fropen ,
+.Dv fwopen ,
+.Dv getc ,
+.Dv getc_unlocked ,
+.Dv getchar ,
+.Dv getchar_unlocked ,
+.Dv putc ,
+.Dv putc_unlocked ,
+.Dv putchar ,
+.Dv putchar_unlocked ,
+.Dv stderr ,
+.Dv stdin
+and
+.Dv stdout .
+Function versions of the macro functions
+.Dv clearerr ,
+.Dv clearerr_unlocked ,
+.Dv feof ,
+.Dv feof_unlocked ,
+.Dv ferror ,
+.Dv ferror_unlocked ,
+.Dv fileno ,
+.Dv fileno_unlocked ,
+.Dv getc ,
+.Dv getc_unlocked ,
+.Dv getchar ,
+.Dv getchar_unlocked ,
+.Dv putc ,
+.Dv putc_unlocked ,
+.Dv putchar ,
+and
+.Dv putchar_unlocked
+exist and will be used if the macro
+definitions are explicitly removed.
+.Sh SEE ALSO
+.Xr close 2 ,
+.Xr open 2 ,
+.Xr read 2 ,
+.Xr write 2
+.Sh STANDARDS
+The
+.Nm
+library conforms to
+.St -isoC-99 .
+.Sh LIST OF FUNCTIONS
+.Bl -column "Description"
+.It Sy "Function Description"
+.It "asprintf formatted output conversion"
+.It "clearerr check and reset stream status"
+.It "dprintf formatted output conversion"
+.It "fclose close a stream"
+.It "fdopen stream open functions"
+.It "feof check and reset stream status"
+.It "ferror check and reset stream status"
+.It "fflush flush a stream"
+.It "fgetc get next character or word from input stream"
+.It "fgetln get a line from a stream"
+.It "fgetpos reposition a stream"
+.It "fgets get a line from a stream"
+.It "fgetwc get next wide character from input stream"
+.It "fgetws get a line of wide characters from a stream"
+.It "fileno check and reset stream status"
+.It "fopen stream open functions"
+.It "fprintf formatted output conversion"
+.It "fpurge flush a stream"
+.It "fputc output a character or word to a stream"
+.It "fputs output a line to a stream"
+.It "fputwc output a wide character to a stream"
+.It "fputws output a line of wide characters to a stream"
+.It "fread binary stream input/output"
+.It "freopen stream open functions"
+.It "fropen open a stream"
+.It "fscanf input format conversion"
+.It "fseek reposition a stream"
+.It "fsetpos reposition a stream"
+.It "ftell reposition a stream"
+.It "funopen open a stream"
+.It "fwide set/get orientation of stream"
+.It "fwopen open a stream"
+.It "fwprintf formatted wide character output conversion"
+.It "fwrite binary stream input/output"
+.It "getc get next character or word from input stream"
+.It "getchar get next character or word from input stream"
+.It "getdelim get a line from a stream"
+.It "getline get a line from a stream"
+.It "gets get a line from a stream"
+.It "getw get next character or word from input stream"
+.It "getwc get next wide character from input stream"
+.It "getwchar get next wide character from input stream"
+.It "mkdtemp create unique temporary directory"
+.It "mkstemp create unique temporary file"
+.It "mktemp create unique temporary file"
+.It "perror system error messages"
+.It "printf formatted output conversion"
+.It "putc output a character or word to a stream"
+.It "putchar output a character or word to a stream"
+.It "puts output a line to a stream"
+.It "putw output a character or word to a stream"
+.It "putwc output a wide character to a stream"
+.It "putwchar output a wide character to a stream"
+.It "remove remove directory entry"
+.It "rewind reposition a stream"
+.It "scanf input format conversion"
+.It "setbuf stream buffering operations"
+.It "setbuffer stream buffering operations"
+.It "setlinebuf stream buffering operations"
+.It "setvbuf stream buffering operations"
+.It "snprintf formatted output conversion"
+.It "sprintf formatted output conversion"
+.It "sscanf input format conversion"
+.It "strerror system error messages"
+.It "swprintf formatted wide character output conversion"
+.It "sys_errlist system error messages"
+.It "sys_nerr system error messages"
+.It "tempnam temporary file routines"
+.It "tmpfile temporary file routines"
+.It "tmpnam temporary file routines"
+.It "ungetc un-get character from input stream"
+.It "ungetwc un-get wide character from input stream"
+.It "vasprintf formatted output conversion"
+.It "vdprintf formatted output conversion"
+.It "vfprintf formatted output conversion"
+.It "vfscanf input format conversion"
+.It "vfwprintf formatted wide character output conversion"
+.It "vprintf formatted output conversion"
+.It "vscanf input format conversion"
+.It "vsnprintf formatted output conversion"
+.It "vsprintf formatted output conversion"
+.It "vsscanf input format conversion"
+.It "vswprintf formatted wide character output conversion"
+.It "vwprintf formatted wide character output conversion"
+.It "wprintf formatted wide character output conversion"
+.El
+.Sh BUGS
+The standard buffered functions do not interact well with certain other
+library and system functions, especially
+.Xr vfork 2 .
diff --git a/lib/libc/stdio/stdio.c b/lib/libc/stdio/stdio.c
new file mode 100644
index 000000000000..5d6fb9ac5644
--- /dev/null
+++ b/lib/libc/stdio/stdio.c
@@ -0,0 +1,168 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)stdio.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "un-namespace.h"
+#include "local.h"
+
+/*
+ * Small standard I/O/seek/close functions.
+ */
+int
+__sread(void *cookie, char *buf, int n)
+{
+ FILE *fp = cookie;
+
+ return(_read(fp->_file, buf, (size_t)n));
+}
+
+int
+__swrite(void *cookie, char const *buf, int n)
+{
+ FILE *fp = cookie;
+
+ return (_write(fp->_file, buf, (size_t)n));
+}
+
+fpos_t
+__sseek(void *cookie, fpos_t offset, int whence)
+{
+ FILE *fp = cookie;
+
+ return (lseek(fp->_file, (off_t)offset, whence));
+}
+
+int
+__sclose(void *cookie)
+{
+
+ return (_close(((FILE *)cookie)->_file));
+}
+
+/*
+ * Higher level wrappers.
+ */
+int
+_sread(FILE *fp, char *buf, int n)
+{
+ int ret;
+
+ ret = (*fp->_read)(fp->_cookie, buf, n);
+ if (ret > 0) {
+ if (fp->_flags & __SOFF) {
+ if (fp->_offset <= OFF_MAX - ret)
+ fp->_offset += ret;
+ else
+ fp->_flags &= ~__SOFF;
+ }
+ } else if (ret < 0)
+ fp->_flags &= ~__SOFF;
+ return (ret);
+}
+
+int
+_swrite(FILE *fp, char const *buf, int n)
+{
+ int ret;
+ int serrno;
+
+ if (fp->_flags & __SAPP) {
+ serrno = errno;
+ if (_sseek(fp, (fpos_t)0, SEEK_END) == -1 &&
+ (fp->_flags & __SOPT))
+ return (-1);
+ errno = serrno;
+ }
+ ret = (*fp->_write)(fp->_cookie, buf, n);
+ /* __SOFF removed even on success in case O_APPEND mode is set. */
+ if (ret >= 0) {
+ if ((fp->_flags & __SOFF) && !(fp->_flags2 & __S2OAP) &&
+ fp->_offset <= OFF_MAX - ret)
+ fp->_offset += ret;
+ else
+ fp->_flags &= ~__SOFF;
+
+ } else if (ret < 0)
+ fp->_flags &= ~__SOFF;
+ return (ret);
+}
+
+fpos_t
+_sseek(FILE *fp, fpos_t offset, int whence)
+{
+ fpos_t ret;
+ int serrno, errret;
+
+ serrno = errno;
+ errno = 0;
+ ret = (*fp->_seek)(fp->_cookie, offset, whence);
+ errret = errno;
+ if (errno == 0)
+ errno = serrno;
+ /*
+ * Disallow negative seeks per POSIX.
+ * It is needed here to help upper level caller
+ * in the cases it can't detect.
+ */
+ if (ret < 0) {
+ if (errret == 0) {
+ if (offset != 0 || whence != SEEK_CUR) {
+ if (HASUB(fp))
+ FREEUB(fp);
+ fp->_p = fp->_bf._base;
+ fp->_r = 0;
+ fp->_flags &= ~__SEOF;
+ }
+ fp->_flags |= __SERR;
+ errno = EINVAL;
+ } else if (errret == ESPIPE)
+ fp->_flags &= ~__SAPP;
+ fp->_flags &= ~__SOFF;
+ ret = -1;
+ } else if (fp->_flags & __SOPT) {
+ fp->_flags |= __SOFF;
+ fp->_offset = ret;
+ }
+ return (ret);
+}
diff --git a/lib/libc/stdio/swprintf.c b/lib/libc/stdio/swprintf.c
new file mode 100644
index 000000000000..1f6ecc65a8ad
--- /dev/null
+++ b/lib/libc/stdio/swprintf.c
@@ -0,0 +1,64 @@
+/*-
+ * Copyright (c) 2002 Tim J. Robbins
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 <stdarg.h>
+#include <stdio.h>
+#include <wchar.h>
+#include <xlocale.h>
+
+int
+swprintf(wchar_t * __restrict s, size_t n, const wchar_t * __restrict fmt, ...)
+{
+ int ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ ret = vswprintf(s, n, fmt, ap);
+ va_end(ap);
+
+ return (ret);
+}
+int
+swprintf_l(wchar_t * __restrict s, size_t n, locale_t locale,
+ const wchar_t * __restrict fmt, ...)
+{
+ int ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ ret = vswprintf_l(s, n, locale, fmt, ap);
+ va_end(ap);
+
+ return (ret);
+}
diff --git a/lib/libc/stdio/swscanf.c b/lib/libc/stdio/swscanf.c
new file mode 100644
index 000000000000..c305ac15d943
--- /dev/null
+++ b/lib/libc/stdio/swscanf.c
@@ -0,0 +1,64 @@
+/*-
+ * Copyright (c) 2002 Tim J. Robbins
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 <stdarg.h>
+#include <stdio.h>
+#include <wchar.h>
+#include <xlocale.h>
+
+int
+swscanf(const wchar_t * __restrict str, const wchar_t * __restrict fmt, ...)
+{
+ va_list ap;
+ int r;
+
+ va_start(ap, fmt);
+ r = vswscanf(str, fmt, ap);
+ va_end(ap);
+
+ return (r);
+}
+int
+swscanf_l(const wchar_t * __restrict str, locale_t locale,
+ const wchar_t * __restrict fmt, ...)
+{
+ va_list ap;
+ int r;
+
+ va_start(ap, fmt);
+ r = vswscanf_l(str, locale, fmt, ap);
+ va_end(ap);
+
+ return (r);
+}
diff --git a/lib/libc/stdio/tempnam.c b/lib/libc/stdio/tempnam.c
new file mode 100644
index 000000000000..e15746f31a4d
--- /dev/null
+++ b/lib/libc/stdio/tempnam.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)tempnam.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <paths.h>
+
+__warn_references(tempnam,
+ "warning: tempnam() possibly used unsafely; consider using mkstemp()");
+
+extern char *_mktemp(char *);
+
+char *
+tempnam(const char *dir, const char *pfx)
+{
+ int sverrno;
+ char *f, *name;
+
+ if (!(name = malloc(MAXPATHLEN)))
+ return(NULL);
+
+ if (!pfx)
+ pfx = "tmp.";
+
+ if (issetugid() == 0 && (f = getenv("TMPDIR"))) {
+ (void)snprintf(name, MAXPATHLEN, "%s%s%sXXXXXX", f,
+ *(f + strlen(f) - 1) == '/'? "": "/", pfx);
+ if ((f = _mktemp(name)))
+ return(f);
+ }
+
+ if ((f = (char *)dir)) {
+ (void)snprintf(name, MAXPATHLEN, "%s%s%sXXXXXX", f,
+ *(f + strlen(f) - 1) == '/'? "": "/", pfx);
+ if ((f = _mktemp(name)))
+ return(f);
+ }
+
+ f = P_tmpdir;
+ (void)snprintf(name, MAXPATHLEN, "%s%sXXXXXX", f, pfx);
+ if ((f = _mktemp(name)))
+ return(f);
+
+ f = _PATH_TMP;
+ (void)snprintf(name, MAXPATHLEN, "%s%sXXXXXX", f, pfx);
+ if ((f = _mktemp(name)))
+ return(f);
+
+ sverrno = errno;
+ free(name);
+ errno = sverrno;
+ return(NULL);
+}
diff --git a/lib/libc/stdio/tmpfile.c b/lib/libc/stdio/tmpfile.c
new file mode 100644
index 000000000000..e5a2be1d97be
--- /dev/null
+++ b/lib/libc/stdio/tmpfile.c
@@ -0,0 +1,93 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)tmpfile.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <signal.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <paths.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+
+FILE *
+tmpfile(void)
+{
+ sigset_t set, oset;
+ FILE *fp;
+ int fd, sverrno;
+#define TRAILER "tmp.XXXXXX"
+ char *buf;
+ const char *tmpdir;
+
+ tmpdir = NULL;
+ if (issetugid() == 0)
+ tmpdir = getenv("TMPDIR");
+ if (tmpdir == NULL)
+ tmpdir = _PATH_TMP;
+
+ (void)asprintf(&buf, "%s%s%s", tmpdir,
+ (tmpdir[strlen(tmpdir) - 1] == '/') ? "" : "/", TRAILER);
+ if (buf == NULL)
+ return (NULL);
+
+ sigfillset(&set);
+ (void)__libc_sigprocmask(SIG_BLOCK, &set, &oset);
+
+ fd = mkstemp(buf);
+ if (fd != -1)
+ (void)unlink(buf);
+
+ free(buf);
+
+ (void)__libc_sigprocmask(SIG_SETMASK, &oset, NULL);
+
+ if (fd == -1)
+ return (NULL);
+
+ if ((fp = fdopen(fd, "w+")) == NULL) {
+ sverrno = errno;
+ (void)_close(fd);
+ errno = sverrno;
+ return (NULL);
+ }
+ return (fp);
+}
diff --git a/lib/libc/stdio/tmpnam.3 b/lib/libc/stdio/tmpnam.3
new file mode 100644
index 000000000000..c54ec2718aa7
--- /dev/null
+++ b/lib/libc/stdio/tmpnam.3
@@ -0,0 +1,246 @@
+.\" Copyright (c) 1988, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)tmpnam.3 8.2 (Berkeley) 11/17/93
+.\" $FreeBSD$
+.\"
+.Dd March 18, 2007
+.Dt TMPFILE 3
+.Os
+.Sh NAME
+.Nm tempnam ,
+.Nm tmpfile ,
+.Nm tmpnam
+.Nd temporary file routines
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdio.h
+.Ft FILE *
+.Fn tmpfile void
+.Ft char *
+.Fn tmpnam "char *str"
+.Ft char *
+.Fn tempnam "const char *tmpdir" "const char *prefix"
+.Sh DESCRIPTION
+The
+.Fn tmpfile
+function
+returns a pointer to a stream associated with a file descriptor returned
+by the routine
+.Xr mkstemp 3 .
+The created file is unlinked before
+.Fn tmpfile
+returns, causing the file to be automatically deleted when the last
+reference to it is closed.
+The file is opened with the access value
+.Ql w+ .
+The file is created in the directory determined by the environment variable
+.Ev TMPDIR
+if set.
+The default location if
+.Ev TMPDIR
+is not set is
+.Pa /tmp .
+.Pp
+The
+.Fn tmpnam
+function
+returns a pointer to a file name, in the
+.Dv P_tmpdir
+directory, which
+did not reference an existing file at some indeterminate point in the
+past.
+.Dv P_tmpdir
+is defined in the include file
+.In stdio.h .
+If the argument
+.Fa str
+is
+.Pf non- Dv NULL ,
+the file name is copied to the buffer it references.
+Otherwise, the file name is copied to a static buffer.
+In either case,
+.Fn tmpnam
+returns a pointer to the file name.
+.Pp
+The buffer referenced by
+.Fa str
+is expected to be at least
+.Dv L_tmpnam
+bytes in length.
+.Dv L_tmpnam
+is defined in the include file
+.In stdio.h .
+.Pp
+The
+.Fn tempnam
+function
+is similar to
+.Fn tmpnam ,
+but provides the ability to specify the directory which will
+contain the temporary file and the file name prefix.
+.Pp
+The environment variable
+.Ev TMPDIR
+(if set), the argument
+.Fa tmpdir
+(if
+.Pf non- Dv NULL ) ,
+the directory
+.Dv P_tmpdir ,
+and the directory
+.Pa /tmp
+are tried, in the listed order, as directories in which to store the
+temporary file.
+.Pp
+The argument
+.Fa prefix ,
+if
+.Pf non- Dv NULL ,
+is used to specify a file name prefix, which will be the
+first part of the created file name.
+The
+.Fn tempnam
+function
+allocates memory in which to store the file name; the returned pointer
+may be used as a subsequent argument to
+.Xr free 3 .
+.Sh RETURN VALUES
+The
+.Fn tmpfile
+function
+returns a pointer to an open file stream on success, and a
+.Dv NULL
+pointer
+on error.
+.Pp
+The
+.Fn tmpnam
+and
+.Fn tempfile
+functions
+return a pointer to a file name on success, and a
+.Dv NULL
+pointer
+on error.
+.Sh ENVIRONMENT
+.Bl -tag -width Ds
+.It Ev TMPDIR
+.Pf [ Fn tempnam
+only]
+If set,
+the directory in which the temporary file is stored.
+.Ev TMPDIR
+is ignored for processes
+for which
+.Xr issetugid 2
+is true.
+.El
+.Sh COMPATIBILITY
+These interfaces are provided from System V and
+.Tn ANSI
+compatibility only.
+.Pp
+Most historic implementations of these functions provide
+only a limited number of possible temporary file names
+(usually 26)
+before file names will start being recycled.
+System V implementations of these functions
+(and of
+.Xr mktemp 3 )
+use the
+.Xr access 2
+system call to determine whether or not the temporary file
+may be created.
+This has obvious ramifications for setuid or setgid programs,
+complicating the portable use of these interfaces in such programs.
+.Pp
+The
+.Fn tmpfile
+interface should not be used in software expected to be used on other systems
+if there is any possibility that the user does not wish the temporary file to
+be publicly readable and writable.
+.Sh ERRORS
+The
+.Fn tmpfile
+function
+may fail and set the global variable
+.Va errno
+for any of the errors specified for the library functions
+.Xr fdopen 3
+or
+.Xr mkstemp 3 .
+.Pp
+The
+.Fn tmpnam
+function
+may fail and set
+.Va errno
+for any of the errors specified for the library function
+.Xr mktemp 3 .
+.Pp
+The
+.Fn tempnam
+function
+may fail and set
+.Va errno
+for any of the errors specified for the library functions
+.Xr malloc 3
+or
+.Xr mktemp 3 .
+.Sh SEE ALSO
+.Xr mkstemp 3 ,
+.Xr mktemp 3
+.Sh STANDARDS
+The
+.Fn tmpfile
+and
+.Fn tmpnam
+functions
+conform to
+.St -isoC .
+.Sh SECURITY CONSIDERATIONS
+The
+.Fn tmpnam
+and
+.Fn tempnam
+functions are susceptible to a race condition
+occurring between the selection of the file name
+and the creation of the file,
+which allows malicious users
+to potentially overwrite arbitrary files in the system,
+depending on the level of privilege of the running program.
+Additionally, there is no means by which
+file permissions may be specified.
+It is strongly suggested that
+.Xr mkstemp 3
+be used in place of these functions.
diff --git a/lib/libc/stdio/tmpnam.c b/lib/libc/stdio/tmpnam.c
new file mode 100644
index 000000000000..ce32dcc28149
--- /dev/null
+++ b/lib/libc/stdio/tmpnam.c
@@ -0,0 +1,60 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)tmpnam.c 8.3 (Berkeley) 3/28/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+#include <stdio.h>
+#include <unistd.h>
+
+__warn_references(tmpnam,
+ "warning: tmpnam() possibly used unsafely; consider using mkstemp()");
+
+extern char *_mktemp(char *);
+
+char *
+tmpnam(char *s)
+{
+ static u_long tmpcount;
+ static char buf[L_tmpnam];
+
+ if (s == NULL)
+ s = buf;
+ (void)snprintf(s, L_tmpnam, "%stmp.%lu.XXXXXX", P_tmpdir, tmpcount);
+ ++tmpcount;
+ return (_mktemp(s));
+}
diff --git a/lib/libc/stdio/ungetc.3 b/lib/libc/stdio/ungetc.3
new file mode 100644
index 000000000000..86566b3765a4
--- /dev/null
+++ b/lib/libc/stdio/ungetc.3
@@ -0,0 +1,98 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek and the American National Standards Committee X3,
+.\" on Information Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)ungetc.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt UNGETC 3
+.Os
+.Sh NAME
+.Nm ungetc
+.Nd un-get character from input stream
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdio.h
+.Ft int
+.Fn ungetc "int c" "FILE *stream"
+.Sh DESCRIPTION
+The
+.Fn ungetc
+function pushes the character
+.Fa c
+(converted to an unsigned char)
+back onto the input stream pointed to by
+.Fa stream .
+The pushed-back characters will be returned by subsequent reads on the
+stream (in reverse order).
+A successful intervening call,
+using the same stream,
+to one of the file positioning functions
+.Xr ( fseek 3 ,
+.Xr fsetpos 3 ,
+or
+.Xr rewind 3 )
+will discard the pushed back characters.
+.Pp
+One character of push-back is guaranteed,
+but as long as there is sufficient memory,
+an effectively infinite amount of pushback is allowed.
+.Pp
+If a character is successfully pushed-back,
+the end-of-file indicator for the stream is cleared.
+The file-position indicator is decremented
+by each successful call to
+.Fn ungetc ;
+if its value was 0 before a call, its value is unspecified after
+the call.
+.Sh RETURN VALUES
+The
+.Fn ungetc
+function returns the character pushed-back after the conversion,
+or
+.Dv EOF
+if the operation fails.
+If the value of the argument
+.Fa c
+character equals
+.Dv EOF ,
+the operation will fail and the stream will remain unchanged.
+.Sh SEE ALSO
+.Xr fseek 3 ,
+.Xr getc 3 ,
+.Xr setvbuf 3 ,
+.Xr ungetwc 3
+.Sh STANDARDS
+The
+.Fn ungetc
+function conforms to
+.St -isoC .
diff --git a/lib/libc/stdio/ungetc.c b/lib/libc/stdio/ungetc.c
new file mode 100644
index 000000000000..1695af772daa
--- /dev/null
+++ b/lib/libc/stdio/ungetc.c
@@ -0,0 +1,168 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)ungetc.c 8.2 (Berkeley) 11/3/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "un-namespace.h"
+#include "local.h"
+#include "libc_private.h"
+
+static int __submore(FILE *);
+
+/*
+ * Expand the ungetc buffer `in place'. That is, adjust fp->_p when
+ * the buffer moves, so that it points the same distance from the end,
+ * and move the bytes in the buffer around as necessary so that they
+ * are all at the end (stack-style).
+ */
+static int
+__submore(FILE *fp)
+{
+ int i;
+ unsigned char *p;
+
+ if (fp->_ub._base == fp->_ubuf) {
+ /*
+ * Get a new buffer (rather than expanding the old one).
+ */
+ if ((p = malloc((size_t)BUFSIZ)) == NULL)
+ return (EOF);
+ fp->_ub._base = p;
+ fp->_ub._size = BUFSIZ;
+ p += BUFSIZ - sizeof(fp->_ubuf);
+ for (i = sizeof(fp->_ubuf); --i >= 0;)
+ p[i] = fp->_ubuf[i];
+ fp->_p = p;
+ return (0);
+ }
+ i = fp->_ub._size;
+ p = realloc(fp->_ub._base, (size_t)(i << 1));
+ if (p == NULL)
+ return (EOF);
+ /* no overlap (hence can use memcpy) because we doubled the size */
+ (void)memcpy((void *)(p + i), (void *)p, (size_t)i);
+ fp->_p = p + i;
+ fp->_ub._base = p;
+ fp->_ub._size = i << 1;
+ return (0);
+}
+
+/*
+ * MT-safe version
+ */
+int
+ungetc(int c, FILE *fp)
+{
+ int ret;
+
+ if (!__sdidinit)
+ __sinit();
+ FLOCKFILE(fp);
+ ORIENT(fp, -1);
+ ret = __ungetc(c, fp);
+ FUNLOCKFILE(fp);
+ return (ret);
+}
+
+/*
+ * Non-MT-safe version
+ */
+int
+__ungetc(int c, FILE *fp)
+{
+
+ if (c == EOF)
+ return (EOF);
+ if ((fp->_flags & __SRD) == 0) {
+ /*
+ * Not already reading: no good unless reading-and-writing.
+ * Otherwise, flush any current write stuff.
+ */
+ if ((fp->_flags & __SRW) == 0)
+ return (EOF);
+ if (fp->_flags & __SWR) {
+ if (__sflush(fp))
+ return (EOF);
+ fp->_flags &= ~__SWR;
+ fp->_w = 0;
+ fp->_lbfsize = 0;
+ }
+ fp->_flags |= __SRD;
+ }
+ c = (unsigned char)c;
+
+ /*
+ * If we are in the middle of ungetc'ing, just continue.
+ * This may require expanding the current ungetc buffer.
+ */
+ if (HASUB(fp)) {
+ if (fp->_r >= fp->_ub._size && __submore(fp))
+ return (EOF);
+ *--fp->_p = c;
+ fp->_r++;
+ return (c);
+ }
+ fp->_flags &= ~__SEOF;
+
+ /*
+ * If we can handle this by simply backing up, do so,
+ * but never replace the original character.
+ * (This makes sscanf() work when scanning `const' data.)
+ */
+ if (fp->_bf._base != NULL && fp->_p > fp->_bf._base &&
+ fp->_p[-1] == c) {
+ fp->_p--;
+ fp->_r++;
+ return (c);
+ }
+
+ /*
+ * Create an ungetc buffer.
+ * Initially, we will use the `reserve' buffer.
+ */
+ fp->_ur = fp->_r;
+ fp->_up = fp->_p;
+ fp->_ub._base = fp->_ubuf;
+ fp->_ub._size = sizeof(fp->_ubuf);
+ fp->_ubuf[sizeof(fp->_ubuf) - 1] = c;
+ fp->_p = &fp->_ubuf[sizeof(fp->_ubuf) - 1];
+ fp->_r = 1;
+ return (c);
+}
diff --git a/lib/libc/stdio/ungetwc.3 b/lib/libc/stdio/ungetwc.3
new file mode 100644
index 000000000000..2cdfbe9f3978
--- /dev/null
+++ b/lib/libc/stdio/ungetwc.3
@@ -0,0 +1,95 @@
+.\" $NetBSD: ungetwc.3,v 1.3 2002/02/07 07:00:27 ross Exp $
+.\"
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek and the American National Standards Committee X3,
+.\" on Information Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)ungetc.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd March 3, 2004
+.Dt UNGETWC 3
+.Os
+.Sh NAME
+.Nm ungetwc
+.Nd un-get wide character from input stream
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdio.h
+.In wchar.h
+.Ft wint_t
+.Fn ungetwc "wint_t wc" "FILE *stream"
+.Sh DESCRIPTION
+The
+.Fn ungetwc
+function pushes the wide character
+.Fa wc
+(converted to an
+.Vt wchar_t )
+back onto the input stream pointed to by
+.Fa stream .
+The pushed-backed wide characters will be returned by subsequent reads on the
+stream (in reverse order).
+A successful intervening call, using the same stream, to one of the file
+positioning functions
+.Xr fseek 3 ,
+.Xr fsetpos 3 ,
+or
+.Xr rewind 3
+will discard the pushed back wide characters.
+.Pp
+One wide character of push-back is guaranteed,
+but as long as there is
+sufficient memory, an effectively infinite amount of pushback is allowed.
+.Pp
+If a character is successfully pushed-back,
+the end-of-file indicator for the stream is cleared.
+.Sh RETURN VALUES
+The
+.Fn ungetwc
+function
+returns
+the wide character pushed-back after the conversion, or
+.Dv WEOF
+if the operation fails.
+If the value of the argument
+.Fa c
+character equals
+.Dv WEOF ,
+the operation will fail and the stream will remain unchanged.
+.Sh SEE ALSO
+.Xr fseek 3 ,
+.Xr getwc 3
+.Sh STANDARDS
+The
+.Fn ungetwc
+function conforms to
+.St -isoC-99 .
diff --git a/lib/libc/stdio/ungetwc.c b/lib/libc/stdio/ungetwc.c
new file mode 100644
index 000000000000..78bc38d954a0
--- /dev/null
+++ b/lib/libc/stdio/ungetwc.c
@@ -0,0 +1,90 @@
+/*-
+ * Copyright (c) 2002-2004 Tim J. Robbins.
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 "namespace.h"
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+#include "local.h"
+#include "mblocal.h"
+#include "xlocale_private.h"
+
+/*
+ * Non-MT-safe version.
+ */
+wint_t
+__ungetwc(wint_t wc, FILE *fp, locale_t locale)
+{
+ char buf[MB_LEN_MAX];
+ size_t len;
+ struct xlocale_ctype *l = XLOCALE_CTYPE(locale);
+
+ if (wc == WEOF)
+ return (WEOF);
+ if ((len = l->__wcrtomb(buf, wc, &fp->_mbstate)) == (size_t)-1) {
+ fp->_flags |= __SERR;
+ return (WEOF);
+ }
+ while (len-- != 0)
+ if (__ungetc((unsigned char)buf[len], fp) == EOF)
+ return (WEOF);
+
+ return (wc);
+}
+
+/*
+ * MT-safe version.
+ */
+wint_t
+ungetwc_l(wint_t wc, FILE *fp, locale_t locale)
+{
+ wint_t r;
+ FIX_LOCALE(locale);
+
+ FLOCKFILE(fp);
+ ORIENT(fp, 1);
+ r = __ungetwc(wc, fp, locale);
+ FUNLOCKFILE(fp);
+
+ return (r);
+}
+wint_t
+ungetwc(wint_t wc, FILE *fp)
+{
+ return ungetwc_l(wc, fp, __get_locale());
+}
diff --git a/lib/libc/stdio/vasprintf.c b/lib/libc/stdio/vasprintf.c
new file mode 100644
index 000000000000..8feb23da758e
--- /dev/null
+++ b/lib/libc/stdio/vasprintf.c
@@ -0,0 +1,74 @@
+/* $OpenBSD: vasprintf.c,v 1.4 1998/06/21 22:13:47 millert Exp $ */
+
+/*
+ * Copyright (c) 1997 Todd C. Miller <Todd.Miller@courtesan.com>
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include "xlocale_private.h"
+#include "local.h"
+
+int
+vasprintf_l(char **str, locale_t locale, const char *fmt, __va_list ap)
+{
+ FILE f = FAKE_FILE;
+ int ret;
+ FIX_LOCALE(locale);
+
+ f._flags = __SWR | __SSTR | __SALC;
+ f._bf._base = f._p = malloc(128);
+ if (f._bf._base == NULL) {
+ *str = NULL;
+ errno = ENOMEM;
+ return (-1);
+ }
+ f._bf._size = f._w = 127; /* Leave room for the NUL */
+ ret = __vfprintf(&f, locale, fmt, ap);
+ if (ret < 0) {
+ free(f._bf._base);
+ *str = NULL;
+ errno = ENOMEM;
+ return (-1);
+ }
+ *f._p = '\0';
+ *str = (char *)f._bf._base;
+ return (ret);
+}
+int
+vasprintf(char **str, const char *fmt, __va_list ap)
+{
+ return vasprintf_l(str, __get_locale(), fmt, ap);
+}
diff --git a/lib/libc/stdio/vdprintf.c b/lib/libc/stdio/vdprintf.c
new file mode 100644
index 000000000000..454b0f9fdba7
--- /dev/null
+++ b/lib/libc/stdio/vdprintf.c
@@ -0,0 +1,70 @@
+/*-
+ * Copyright (c) 2009 David Schultz <das@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 "namespace.h"
+#include <errno.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include "un-namespace.h"
+
+#include "local.h"
+#include "xlocale_private.h"
+
+int
+vdprintf(int fd, const char * __restrict fmt, va_list ap)
+{
+ FILE f = FAKE_FILE;
+ unsigned char buf[BUFSIZ];
+ int ret;
+
+ if (fd > SHRT_MAX) {
+ errno = EMFILE;
+ return (EOF);
+ }
+
+ f._p = buf;
+ f._w = sizeof(buf);
+ f._flags = __SWR;
+ f._file = fd;
+ f._cookie = &f;
+ f._write = __swrite;
+ f._bf._base = buf;
+ f._bf._size = sizeof(buf);
+
+ if ((ret = __vfprintf(&f, __get_locale(), fmt, ap)) < 0)
+ return (ret);
+
+ return (__fflush(&f) ? EOF : ret);
+}
diff --git a/lib/libc/stdio/vfprintf.c b/lib/libc/stdio/vfprintf.c
new file mode 100644
index 000000000000..bf45bfb421ed
--- /dev/null
+++ b/lib/libc/stdio/vfprintf.c
@@ -0,0 +1,1045 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)vfprintf.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Actual printf innards.
+ *
+ * This code is large and complicated...
+ */
+
+#include "namespace.h"
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <locale.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <printf.h>
+
+#include <stdarg.h>
+#include "xlocale_private.h"
+#include "un-namespace.h"
+
+#include "libc_private.h"
+#include "local.h"
+#include "fvwrite.h"
+#include "printflocal.h"
+
+static int __sprint(FILE *, struct __suio *, locale_t);
+static int __sbprintf(FILE *, locale_t, const char *, va_list) __printflike(3, 0)
+ __noinline;
+static char *__wcsconv(wchar_t *, int);
+
+#define CHAR char
+#include "printfcommon.h"
+
+struct grouping_state {
+ char *thousands_sep; /* locale-specific thousands separator */
+ int thousep_len; /* length of thousands_sep */
+ const char *grouping; /* locale-specific numeric grouping rules */
+ int lead; /* sig figs before decimal or group sep */
+ int nseps; /* number of group separators with ' */
+ int nrepeats; /* number of repeats of the last group */
+};
+
+/*
+ * Initialize the thousands' grouping state in preparation to print a
+ * number with ndigits digits. This routine returns the total number
+ * of bytes that will be needed.
+ */
+static int
+grouping_init(struct grouping_state *gs, int ndigits, locale_t loc)
+{
+ struct lconv *locale;
+
+ locale = localeconv_l(loc);
+ gs->grouping = locale->grouping;
+ gs->thousands_sep = locale->thousands_sep;
+ gs->thousep_len = strlen(gs->thousands_sep);
+
+ gs->nseps = gs->nrepeats = 0;
+ gs->lead = ndigits;
+ while (*gs->grouping != CHAR_MAX) {
+ if (gs->lead <= *gs->grouping)
+ break;
+ gs->lead -= *gs->grouping;
+ if (*(gs->grouping+1)) {
+ gs->nseps++;
+ gs->grouping++;
+ } else
+ gs->nrepeats++;
+ }
+ return ((gs->nseps + gs->nrepeats) * gs->thousep_len);
+}
+
+/*
+ * Print a number with thousands' separators.
+ */
+static int
+grouping_print(struct grouping_state *gs, struct io_state *iop,
+ const CHAR *cp, const CHAR *ep, locale_t locale)
+{
+ const CHAR *cp0 = cp;
+
+ if (io_printandpad(iop, cp, ep, gs->lead, zeroes, locale))
+ return (-1);
+ cp += gs->lead;
+ while (gs->nseps > 0 || gs->nrepeats > 0) {
+ if (gs->nrepeats > 0)
+ gs->nrepeats--;
+ else {
+ gs->grouping--;
+ gs->nseps--;
+ }
+ if (io_print(iop, gs->thousands_sep, gs->thousep_len, locale))
+ return (-1);
+ if (io_printandpad(iop, cp, ep, *gs->grouping, zeroes, locale))
+ return (-1);
+ cp += *gs->grouping;
+ }
+ if (cp > ep)
+ cp = ep;
+ return (cp - cp0);
+}
+
+/*
+ * Flush out all the vectors defined by the given uio,
+ * then reset it so that it can be reused.
+ */
+static int
+__sprint(FILE *fp, struct __suio *uio, locale_t locale)
+{
+ int err;
+
+ if (uio->uio_resid == 0) {
+ uio->uio_iovcnt = 0;
+ return (0);
+ }
+ err = __sfvwrite(fp, uio);
+ uio->uio_resid = 0;
+ uio->uio_iovcnt = 0;
+ return (err);
+}
+
+/*
+ * Helper function for `fprintf to unbuffered unix file': creates a
+ * temporary buffer. We only work on write-only files; this avoids
+ * worries about ungetc buffers and so forth.
+ */
+static int
+__sbprintf(FILE *fp, locale_t locale, const char *fmt, va_list ap)
+{
+ int ret;
+ FILE fake = FAKE_FILE;
+ unsigned char buf[BUFSIZ];
+
+ /* XXX This is probably not needed. */
+ if (prepwrite(fp) != 0)
+ return (EOF);
+
+ /* copy the important variables */
+ fake._flags = fp->_flags & ~__SNBF;
+ fake._file = fp->_file;
+ fake._cookie = fp->_cookie;
+ fake._write = fp->_write;
+ fake._orientation = fp->_orientation;
+ fake._mbstate = fp->_mbstate;
+
+ /* set up the buffer */
+ fake._bf._base = fake._p = buf;
+ fake._bf._size = fake._w = sizeof(buf);
+ fake._lbfsize = 0; /* not actually used, but Just In Case */
+
+ /* do the work, then copy any error status */
+ ret = __vfprintf(&fake, locale, fmt, ap);
+ if (ret >= 0 && __fflush(&fake))
+ ret = EOF;
+ if (fake._flags & __SERR)
+ fp->_flags |= __SERR;
+ return (ret);
+}
+
+/*
+ * Convert a wide character string argument for the %ls format to a multibyte
+ * string representation. If not -1, prec specifies the maximum number of
+ * bytes to output, and also means that we can't assume that the wide char.
+ * string ends is null-terminated.
+ */
+static char *
+__wcsconv(wchar_t *wcsarg, int prec)
+{
+ static const mbstate_t initial;
+ mbstate_t mbs;
+ char buf[MB_LEN_MAX];
+ wchar_t *p;
+ char *convbuf;
+ size_t clen, nbytes;
+
+ /* Allocate space for the maximum number of bytes we could output. */
+ if (prec < 0) {
+ p = wcsarg;
+ mbs = initial;
+ nbytes = wcsrtombs(NULL, (const wchar_t **)&p, 0, &mbs);
+ if (nbytes == (size_t)-1)
+ return (NULL);
+ } else {
+ /*
+ * Optimisation: if the output precision is small enough,
+ * just allocate enough memory for the maximum instead of
+ * scanning the string.
+ */
+ if (prec < 128)
+ nbytes = prec;
+ else {
+ nbytes = 0;
+ p = wcsarg;
+ mbs = initial;
+ for (;;) {
+ clen = wcrtomb(buf, *p++, &mbs);
+ if (clen == 0 || clen == (size_t)-1 ||
+ nbytes + clen > prec)
+ break;
+ nbytes += clen;
+ }
+ }
+ }
+ if ((convbuf = malloc(nbytes + 1)) == NULL)
+ return (NULL);
+
+ /* Fill the output buffer. */
+ p = wcsarg;
+ mbs = initial;
+ if ((nbytes = wcsrtombs(convbuf, (const wchar_t **)&p,
+ nbytes, &mbs)) == (size_t)-1) {
+ free(convbuf);
+ return (NULL);
+ }
+ convbuf[nbytes] = '\0';
+ return (convbuf);
+}
+
+/*
+ * MT-safe version
+ */
+int
+vfprintf_l(FILE * __restrict fp, locale_t locale, const char * __restrict fmt0,
+ va_list ap)
+{
+ int ret;
+ FIX_LOCALE(locale);
+
+ FLOCKFILE(fp);
+ /* optimise fprintf(stderr) (and other unbuffered Unix files) */
+ if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
+ fp->_file >= 0)
+ ret = __sbprintf(fp, locale, fmt0, ap);
+ else
+ ret = __vfprintf(fp, locale, fmt0, ap);
+ FUNLOCKFILE(fp);
+ return (ret);
+}
+int
+vfprintf(FILE * __restrict fp, const char * __restrict fmt0, va_list ap)
+{
+ return vfprintf_l(fp, __get_locale(), fmt0, ap);
+}
+
+/*
+ * The size of the buffer we use as scratch space for integer
+ * conversions, among other things. We need enough space to
+ * write a uintmax_t in octal (plus one byte).
+ */
+#if UINTMAX_MAX <= UINT64_MAX
+#define BUF 32
+#else
+#error "BUF must be large enough to format a uintmax_t"
+#endif
+
+/*
+ * Non-MT-safe version
+ */
+int
+__vfprintf(FILE *fp, locale_t locale, const char *fmt0, va_list ap)
+{
+ char *fmt; /* format string */
+ int ch; /* character from fmt */
+ int n, n2; /* handy integer (short term usage) */
+ char *cp; /* handy char pointer (short term usage) */
+ int flags; /* flags as above */
+ int ret; /* return value accumulator */
+ int width; /* width from format (%8d), or 0 */
+ int prec; /* precision from format; <0 for N/A */
+ char sign; /* sign prefix (' ', '+', '-', or \0) */
+ struct grouping_state gs; /* thousands' grouping info */
+
+#ifndef NO_FLOATING_POINT
+ /*
+ * We can decompose the printed representation of floating
+ * point numbers into several parts, some of which may be empty:
+ *
+ * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ
+ * A B ---C--- D E F
+ *
+ * A: 'sign' holds this value if present; '\0' otherwise
+ * B: ox[1] holds the 'x' or 'X'; '\0' if not hexadecimal
+ * C: cp points to the string MMMNNN. Leading and trailing
+ * zeros are not in the string and must be added.
+ * D: expchar holds this character; '\0' if no exponent, e.g. %f
+ * F: at least two digits for decimal, at least one digit for hex
+ */
+ char *decimal_point; /* locale specific decimal point */
+ int decpt_len; /* length of decimal_point */
+ int signflag; /* true if float is negative */
+ union { /* floating point arguments %[aAeEfFgG] */
+ double dbl;
+ long double ldbl;
+ } fparg;
+ int expt; /* integer value of exponent */
+ char expchar; /* exponent character: [eEpP\0] */
+ char *dtoaend; /* pointer to end of converted digits */
+ int expsize; /* character count for expstr */
+ int ndig; /* actual number of digits returned by dtoa */
+ char expstr[MAXEXPDIG+2]; /* buffer for exponent string: e+ZZZ */
+ char *dtoaresult; /* buffer allocated by dtoa */
+#endif
+ u_long ulval; /* integer arguments %[diouxX] */
+ uintmax_t ujval; /* %j, %ll, %q, %t, %z integers */
+ int base; /* base for [diouxX] conversion */
+ int dprec; /* a copy of prec if [diouxX], 0 otherwise */
+ int realsz; /* field size expanded by dprec, sign, etc */
+ int size; /* size of converted field or string */
+ int prsize; /* max size of printed field */
+ const char *xdigs; /* digits for %[xX] conversion */
+ struct io_state io; /* I/O buffering state */
+ char buf[BUF]; /* buffer with space for digits of uintmax_t */
+ char ox[2]; /* space for 0x; ox[1] is either x, X, or \0 */
+ union arg *argtable; /* args, built due to positional arg */
+ union arg statargtable [STATIC_ARG_TBL_SIZE];
+ int nextarg; /* 1-based argument index */
+ va_list orgap; /* original argument pointer */
+ char *convbuf; /* wide to multibyte conversion result */
+ int savserr;
+
+ static const char xdigs_lower[16] = "0123456789abcdef";
+ static const char xdigs_upper[16] = "0123456789ABCDEF";
+
+ /* BEWARE, these `goto error' on error. */
+#define PRINT(ptr, len) { \
+ if (io_print(&io, (ptr), (len), locale)) \
+ goto error; \
+}
+#define PAD(howmany, with) { \
+ if (io_pad(&io, (howmany), (with), locale)) \
+ goto error; \
+}
+#define PRINTANDPAD(p, ep, len, with) { \
+ if (io_printandpad(&io, (p), (ep), (len), (with), locale)) \
+ goto error; \
+}
+#define FLUSH() { \
+ if (io_flush(&io, locale)) \
+ goto error; \
+}
+
+ /*
+ * Get the argument indexed by nextarg. If the argument table is
+ * built, use it to get the argument. If its not, get the next
+ * argument (and arguments must be gotten sequentially).
+ */
+#define GETARG(type) \
+ ((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : \
+ (nextarg++, va_arg(ap, type)))
+
+ /*
+ * To extend shorts properly, we need both signed and unsigned
+ * argument extraction methods.
+ */
+#define SARG() \
+ (flags&LONGINT ? GETARG(long) : \
+ flags&SHORTINT ? (long)(short)GETARG(int) : \
+ flags&CHARINT ? (long)(signed char)GETARG(int) : \
+ (long)GETARG(int))
+#define UARG() \
+ (flags&LONGINT ? GETARG(u_long) : \
+ flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \
+ flags&CHARINT ? (u_long)(u_char)GETARG(int) : \
+ (u_long)GETARG(u_int))
+#define INTMAX_SIZE (INTMAXT|SIZET|PTRDIFFT|LLONGINT)
+#define SJARG() \
+ (flags&INTMAXT ? GETARG(intmax_t) : \
+ flags&SIZET ? (intmax_t)GETARG(ssize_t) : \
+ flags&PTRDIFFT ? (intmax_t)GETARG(ptrdiff_t) : \
+ (intmax_t)GETARG(long long))
+#define UJARG() \
+ (flags&INTMAXT ? GETARG(uintmax_t) : \
+ flags&SIZET ? (uintmax_t)GETARG(size_t) : \
+ flags&PTRDIFFT ? (uintmax_t)GETARG(ptrdiff_t) : \
+ (uintmax_t)GETARG(unsigned long long))
+
+ /*
+ * Get * arguments, including the form *nn$. Preserve the nextarg
+ * that the argument can be gotten once the type is determined.
+ */
+#define GETASTER(val) \
+ n2 = 0; \
+ cp = fmt; \
+ while (is_digit(*cp)) { \
+ n2 = 10 * n2 + to_digit(*cp); \
+ cp++; \
+ } \
+ if (*cp == '$') { \
+ int hold = nextarg; \
+ if (argtable == NULL) { \
+ argtable = statargtable; \
+ if (__find_arguments (fmt0, orgap, &argtable)) { \
+ ret = EOF; \
+ goto error; \
+ } \
+ } \
+ nextarg = n2; \
+ val = GETARG (int); \
+ nextarg = hold; \
+ fmt = ++cp; \
+ } else { \
+ val = GETARG (int); \
+ }
+
+ if (__use_xprintf == 0 && getenv("USE_XPRINTF"))
+ __use_xprintf = 1;
+ if (__use_xprintf > 0)
+ return (__xvprintf(fp, fmt0, ap));
+
+ /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
+ if (prepwrite(fp) != 0) {
+ errno = EBADF;
+ return (EOF);
+ }
+
+ savserr = fp->_flags & __SERR;
+ fp->_flags &= ~__SERR;
+
+ convbuf = NULL;
+ fmt = (char *)fmt0;
+ argtable = NULL;
+ nextarg = 1;
+ va_copy(orgap, ap);
+ io_init(&io, fp);
+ ret = 0;
+#ifndef NO_FLOATING_POINT
+ dtoaresult = NULL;
+ decimal_point = localeconv_l(locale)->decimal_point;
+ /* The overwhelmingly common case is decpt_len == 1. */
+ decpt_len = (decimal_point[1] == '\0' ? 1 : strlen(decimal_point));
+#endif
+
+ /*
+ * Scan the format for conversions (`%' character).
+ */
+ for (;;) {
+ for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
+ /* void */;
+ if ((n = fmt - cp) != 0) {
+ if ((unsigned)ret + n > INT_MAX) {
+ ret = EOF;
+ errno = EOVERFLOW;
+ goto error;
+ }
+ PRINT(cp, n);
+ ret += n;
+ }
+ if (ch == '\0')
+ goto done;
+ fmt++; /* skip over '%' */
+
+ flags = 0;
+ dprec = 0;
+ width = 0;
+ prec = -1;
+ gs.grouping = NULL;
+ sign = '\0';
+ ox[1] = '\0';
+
+rflag: ch = *fmt++;
+reswitch: switch (ch) {
+ case ' ':
+ /*-
+ * ``If the space and + flags both appear, the space
+ * flag will be ignored.''
+ * -- ANSI X3J11
+ */
+ if (!sign)
+ sign = ' ';
+ goto rflag;
+ case '#':
+ flags |= ALT;
+ goto rflag;
+ case '*':
+ /*-
+ * ``A negative field width argument is taken as a
+ * - flag followed by a positive field width.''
+ * -- ANSI X3J11
+ * They don't exclude field widths read from args.
+ */
+ GETASTER (width);
+ if (width >= 0)
+ goto rflag;
+ width = -width;
+ /* FALLTHROUGH */
+ case '-':
+ flags |= LADJUST;
+ goto rflag;
+ case '+':
+ sign = '+';
+ goto rflag;
+ case '\'':
+ flags |= GROUPING;
+ goto rflag;
+ case '.':
+ if ((ch = *fmt++) == '*') {
+ GETASTER (prec);
+ goto rflag;
+ }
+ prec = 0;
+ while (is_digit(ch)) {
+ prec = 10 * prec + to_digit(ch);
+ ch = *fmt++;
+ }
+ goto reswitch;
+ case '0':
+ /*-
+ * ``Note that 0 is taken as a flag, not as the
+ * beginning of a field width.''
+ * -- ANSI X3J11
+ */
+ flags |= ZEROPAD;
+ goto rflag;
+ case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ n = 0;
+ do {
+ n = 10 * n + to_digit(ch);
+ ch = *fmt++;
+ } while (is_digit(ch));
+ if (ch == '$') {
+ nextarg = n;
+ if (argtable == NULL) {
+ argtable = statargtable;
+ if (__find_arguments (fmt0, orgap,
+ &argtable)) {
+ ret = EOF;
+ goto error;
+ }
+ }
+ goto rflag;
+ }
+ width = n;
+ goto reswitch;
+#ifndef NO_FLOATING_POINT
+ case 'L':
+ flags |= LONGDBL;
+ goto rflag;
+#endif
+ case 'h':
+ if (flags & SHORTINT) {
+ flags &= ~SHORTINT;
+ flags |= CHARINT;
+ } else
+ flags |= SHORTINT;
+ goto rflag;
+ case 'j':
+ flags |= INTMAXT;
+ goto rflag;
+ case 'l':
+ if (flags & LONGINT) {
+ flags &= ~LONGINT;
+ flags |= LLONGINT;
+ } else
+ flags |= LONGINT;
+ goto rflag;
+ case 'q':
+ flags |= LLONGINT; /* not necessarily */
+ goto rflag;
+ case 't':
+ flags |= PTRDIFFT;
+ goto rflag;
+ case 'z':
+ flags |= SIZET;
+ goto rflag;
+ case 'C':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 'c':
+ if (flags & LONGINT) {
+ static const mbstate_t initial;
+ mbstate_t mbs;
+ size_t mbseqlen;
+
+ mbs = initial;
+ mbseqlen = wcrtomb(cp = buf,
+ (wchar_t)GETARG(wint_t), &mbs);
+ if (mbseqlen == (size_t)-1) {
+ fp->_flags |= __SERR;
+ goto error;
+ }
+ size = (int)mbseqlen;
+ } else {
+ *(cp = buf) = GETARG(int);
+ size = 1;
+ }
+ sign = '\0';
+ break;
+ case 'D':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 'd':
+ case 'i':
+ if (flags & INTMAX_SIZE) {
+ ujval = SJARG();
+ if ((intmax_t)ujval < 0) {
+ ujval = -ujval;
+ sign = '-';
+ }
+ } else {
+ ulval = SARG();
+ if ((long)ulval < 0) {
+ ulval = -ulval;
+ sign = '-';
+ }
+ }
+ base = 10;
+ goto number;
+#ifndef NO_FLOATING_POINT
+ case 'a':
+ case 'A':
+ if (ch == 'a') {
+ ox[1] = 'x';
+ xdigs = xdigs_lower;
+ expchar = 'p';
+ } else {
+ ox[1] = 'X';
+ xdigs = xdigs_upper;
+ expchar = 'P';
+ }
+ if (prec >= 0)
+ prec++;
+ if (dtoaresult != NULL)
+ freedtoa(dtoaresult);
+ if (flags & LONGDBL) {
+ fparg.ldbl = GETARG(long double);
+ dtoaresult = cp =
+ __hldtoa(fparg.ldbl, xdigs, prec,
+ &expt, &signflag, &dtoaend);
+ } else {
+ fparg.dbl = GETARG(double);
+ dtoaresult = cp =
+ __hdtoa(fparg.dbl, xdigs, prec,
+ &expt, &signflag, &dtoaend);
+ }
+ if (prec < 0)
+ prec = dtoaend - cp;
+ if (expt == INT_MAX)
+ ox[1] = '\0';
+ goto fp_common;
+ case 'e':
+ case 'E':
+ expchar = ch;
+ if (prec < 0) /* account for digit before decpt */
+ prec = DEFPREC + 1;
+ else
+ prec++;
+ goto fp_begin;
+ case 'f':
+ case 'F':
+ expchar = '\0';
+ goto fp_begin;
+ case 'g':
+ case 'G':
+ expchar = ch - ('g' - 'e');
+ if (prec == 0)
+ prec = 1;
+fp_begin:
+ if (prec < 0)
+ prec = DEFPREC;
+ if (dtoaresult != NULL)
+ freedtoa(dtoaresult);
+ if (flags & LONGDBL) {
+ fparg.ldbl = GETARG(long double);
+ dtoaresult = cp =
+ __ldtoa(&fparg.ldbl, expchar ? 2 : 3, prec,
+ &expt, &signflag, &dtoaend);
+ } else {
+ fparg.dbl = GETARG(double);
+ dtoaresult = cp =
+ dtoa(fparg.dbl, expchar ? 2 : 3, prec,
+ &expt, &signflag, &dtoaend);
+ if (expt == 9999)
+ expt = INT_MAX;
+ }
+fp_common:
+ if (signflag)
+ sign = '-';
+ if (expt == INT_MAX) { /* inf or nan */
+ if (*cp == 'N') {
+ cp = (ch >= 'a') ? "nan" : "NAN";
+ sign = '\0';
+ } else
+ cp = (ch >= 'a') ? "inf" : "INF";
+ size = 3;
+ flags &= ~ZEROPAD;
+ break;
+ }
+ flags |= FPT;
+ ndig = dtoaend - cp;
+ if (ch == 'g' || ch == 'G') {
+ if (expt > -4 && expt <= prec) {
+ /* Make %[gG] smell like %[fF] */
+ expchar = '\0';
+ if (flags & ALT)
+ prec -= expt;
+ else
+ prec = ndig - expt;
+ if (prec < 0)
+ prec = 0;
+ } else {
+ /*
+ * Make %[gG] smell like %[eE], but
+ * trim trailing zeroes if no # flag.
+ */
+ if (!(flags & ALT))
+ prec = ndig;
+ }
+ }
+ if (expchar) {
+ expsize = exponent(expstr, expt - 1, expchar);
+ size = expsize + prec;
+ if (prec > 1 || flags & ALT)
+ size += decpt_len;
+ } else {
+ /* space for digits before decimal point */
+ if (expt > 0)
+ size = expt;
+ else /* "0" */
+ size = 1;
+ /* space for decimal pt and following digits */
+ if (prec || flags & ALT)
+ size += prec + decpt_len;
+ if ((flags & GROUPING) && expt > 0)
+ size += grouping_init(&gs, expt, locale);
+ }
+ break;
+#endif /* !NO_FLOATING_POINT */
+ case 'n':
+ /*
+ * Assignment-like behavior is specified if the
+ * value overflows or is otherwise unrepresentable.
+ * C99 says to use `signed char' for %hhn conversions.
+ */
+ if (flags & LLONGINT)
+ *GETARG(long long *) = ret;
+ else if (flags & SIZET)
+ *GETARG(ssize_t *) = (ssize_t)ret;
+ else if (flags & PTRDIFFT)
+ *GETARG(ptrdiff_t *) = ret;
+ else if (flags & INTMAXT)
+ *GETARG(intmax_t *) = ret;
+ else if (flags & LONGINT)
+ *GETARG(long *) = ret;
+ else if (flags & SHORTINT)
+ *GETARG(short *) = ret;
+ else if (flags & CHARINT)
+ *GETARG(signed char *) = ret;
+ else
+ *GETARG(int *) = ret;
+ continue; /* no output */
+ case 'O':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 'o':
+ if (flags & INTMAX_SIZE)
+ ujval = UJARG();
+ else
+ ulval = UARG();
+ base = 8;
+ goto nosign;
+ case 'p':
+ /*-
+ * ``The argument shall be a pointer to void. The
+ * value of the pointer is converted to a sequence
+ * of printable characters, in an implementation-
+ * defined manner.''
+ * -- ANSI X3J11
+ */
+ ujval = (uintmax_t)(uintptr_t)GETARG(void *);
+ base = 16;
+ xdigs = xdigs_lower;
+ flags = flags | INTMAXT;
+ ox[1] = 'x';
+ goto nosign;
+ case 'S':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 's':
+ if (flags & LONGINT) {
+ wchar_t *wcp;
+
+ if (convbuf != NULL)
+ free(convbuf);
+ if ((wcp = GETARG(wchar_t *)) == NULL)
+ cp = "(null)";
+ else {
+ convbuf = __wcsconv(wcp, prec);
+ if (convbuf == NULL) {
+ fp->_flags |= __SERR;
+ goto error;
+ }
+ cp = convbuf;
+ }
+ } else if ((cp = GETARG(char *)) == NULL)
+ cp = "(null)";
+ size = (prec >= 0) ? strnlen(cp, prec) : strlen(cp);
+ sign = '\0';
+ break;
+ case 'U':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 'u':
+ if (flags & INTMAX_SIZE)
+ ujval = UJARG();
+ else
+ ulval = UARG();
+ base = 10;
+ goto nosign;
+ case 'X':
+ xdigs = xdigs_upper;
+ goto hex;
+ case 'x':
+ xdigs = xdigs_lower;
+hex:
+ if (flags & INTMAX_SIZE)
+ ujval = UJARG();
+ else
+ ulval = UARG();
+ base = 16;
+ /* leading 0x/X only if non-zero */
+ if (flags & ALT &&
+ (flags & INTMAX_SIZE ? ujval != 0 : ulval != 0))
+ ox[1] = ch;
+
+ flags &= ~GROUPING;
+ /* unsigned conversions */
+nosign: sign = '\0';
+ /*-
+ * ``... diouXx conversions ... if a precision is
+ * specified, the 0 flag will be ignored.''
+ * -- ANSI X3J11
+ */
+number: if ((dprec = prec) >= 0)
+ flags &= ~ZEROPAD;
+
+ /*-
+ * ``The result of converting a zero value with an
+ * explicit precision of zero is no characters.''
+ * -- ANSI X3J11
+ *
+ * ``The C Standard is clear enough as is. The call
+ * printf("%#.0o", 0) should print 0.''
+ * -- Defect Report #151
+ */
+ cp = buf + BUF;
+ if (flags & INTMAX_SIZE) {
+ if (ujval != 0 || prec != 0 ||
+ (flags & ALT && base == 8))
+ cp = __ujtoa(ujval, cp, base,
+ flags & ALT, xdigs);
+ } else {
+ if (ulval != 0 || prec != 0 ||
+ (flags & ALT && base == 8))
+ cp = __ultoa(ulval, cp, base,
+ flags & ALT, xdigs);
+ }
+ size = buf + BUF - cp;
+ if (size > BUF) /* should never happen */
+ abort();
+ if ((flags & GROUPING) && size != 0)
+ size += grouping_init(&gs, size, locale);
+ break;
+ default: /* "%?" prints ?, unless ? is NUL */
+ if (ch == '\0')
+ goto done;
+ /* pretend it was %c with argument ch */
+ cp = buf;
+ *cp = ch;
+ size = 1;
+ sign = '\0';
+ break;
+ }
+
+ /*
+ * All reasonable formats wind up here. At this point, `cp'
+ * points to a string which (if not flags&LADJUST) should be
+ * padded out to `width' places. If flags&ZEROPAD, it should
+ * first be prefixed by any sign or other prefix; otherwise,
+ * it should be blank padded before the prefix is emitted.
+ * After any left-hand padding and prefixing, emit zeroes
+ * required by a decimal [diouxX] precision, then print the
+ * string proper, then emit zeroes required by any leftover
+ * floating precision; finally, if LADJUST, pad with blanks.
+ *
+ * Compute actual size, so we know how much to pad.
+ * size excludes decimal prec; realsz includes it.
+ */
+ realsz = dprec > size ? dprec : size;
+ if (sign)
+ realsz++;
+ if (ox[1])
+ realsz += 2;
+
+ prsize = width > realsz ? width : realsz;
+ if ((unsigned)ret + prsize > INT_MAX) {
+ ret = EOF;
+ errno = EOVERFLOW;
+ goto error;
+ }
+
+ /* right-adjusting blank padding */
+ if ((flags & (LADJUST|ZEROPAD)) == 0)
+ PAD(width - realsz, blanks);
+
+ /* prefix */
+ if (sign)
+ PRINT(&sign, 1);
+
+ if (ox[1]) { /* ox[1] is either x, X, or \0 */
+ ox[0] = '0';
+ PRINT(ox, 2);
+ }
+
+ /* right-adjusting zero padding */
+ if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
+ PAD(width - realsz, zeroes);
+
+ /* the string or number proper */
+#ifndef NO_FLOATING_POINT
+ if ((flags & FPT) == 0) {
+#endif
+ /* leading zeroes from decimal precision */
+ PAD(dprec - size, zeroes);
+ if (gs.grouping) {
+ if (grouping_print(&gs, &io, cp, buf+BUF, locale) < 0)
+ goto error;
+ } else {
+ PRINT(cp, size);
+ }
+#ifndef NO_FLOATING_POINT
+ } else { /* glue together f_p fragments */
+ if (!expchar) { /* %[fF] or sufficiently short %[gG] */
+ if (expt <= 0) {
+ PRINT(zeroes, 1);
+ if (prec || flags & ALT)
+ PRINT(decimal_point,decpt_len);
+ PAD(-expt, zeroes);
+ /* already handled initial 0's */
+ prec += expt;
+ } else {
+ if (gs.grouping) {
+ n = grouping_print(&gs, &io,
+ cp, dtoaend, locale);
+ if (n < 0)
+ goto error;
+ cp += n;
+ } else {
+ PRINTANDPAD(cp, dtoaend,
+ expt, zeroes);
+ cp += expt;
+ }
+ if (prec || flags & ALT)
+ PRINT(decimal_point,decpt_len);
+ }
+ PRINTANDPAD(cp, dtoaend, prec, zeroes);
+ } else { /* %[eE] or sufficiently long %[gG] */
+ if (prec > 1 || flags & ALT) {
+ PRINT(cp++, 1);
+ PRINT(decimal_point, decpt_len);
+ PRINT(cp, ndig-1);
+ PAD(prec - ndig, zeroes);
+ } else /* XeYYY */
+ PRINT(cp, 1);
+ PRINT(expstr, expsize);
+ }
+ }
+#endif
+ /* left-adjusting padding (always blank) */
+ if (flags & LADJUST)
+ PAD(width - realsz, blanks);
+
+ /* finally, adjust ret */
+ ret += prsize;
+
+ FLUSH(); /* copy out the I/O vectors */
+ }
+done:
+ FLUSH();
+error:
+ va_end(orgap);
+#ifndef NO_FLOATING_POINT
+ if (dtoaresult != NULL)
+ freedtoa(dtoaresult);
+#endif
+ if (convbuf != NULL)
+ free(convbuf);
+ if (__sferror(fp))
+ ret = EOF;
+ else
+ fp->_flags |= savserr;
+ if ((argtable != NULL) && (argtable != statargtable))
+ free (argtable);
+ return (ret);
+ /* NOTREACHED */
+}
+
diff --git a/lib/libc/stdio/vfscanf.c b/lib/libc/stdio/vfscanf.c
new file mode 100644
index 000000000000..e49a9e1ed134
--- /dev/null
+++ b/lib/libc/stdio/vfscanf.c
@@ -0,0 +1,1092 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)vfscanf.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <ctype.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include <string.h>
+#include <wchar.h>
+#include <wctype.h>
+#include "un-namespace.h"
+
+#include "collate.h"
+#include "libc_private.h"
+#include "local.h"
+#include "xlocale_private.h"
+
+#ifndef NO_FLOATING_POINT
+#include <locale.h>
+#endif
+
+#define BUF 513 /* Maximum length of numeric string. */
+
+/*
+ * Flags used during conversion.
+ */
+#define LONG 0x01 /* l: long or double */
+#define LONGDBL 0x02 /* L: long double */
+#define SHORT 0x04 /* h: short */
+#define SUPPRESS 0x08 /* *: suppress assignment */
+#define POINTER 0x10 /* p: void * (as hex) */
+#define NOSKIP 0x20 /* [ or c: do not skip blanks */
+#define LONGLONG 0x400 /* ll: long long (+ deprecated q: quad) */
+#define INTMAXT 0x800 /* j: intmax_t */
+#define PTRDIFFT 0x1000 /* t: ptrdiff_t */
+#define SIZET 0x2000 /* z: size_t */
+#define SHORTSHORT 0x4000 /* hh: char */
+#define UNSIGNED 0x8000 /* %[oupxX] conversions */
+
+/*
+ * The following are used in integral conversions only:
+ * SIGNOK, NDIGITS, PFXOK, and NZDIGITS
+ */
+#define SIGNOK 0x40 /* +/- is (still) legal */
+#define NDIGITS 0x80 /* no digits detected */
+#define PFXOK 0x100 /* 0x prefix is (still) legal */
+#define NZDIGITS 0x200 /* no zero digits detected */
+#define HAVESIGN 0x10000 /* sign detected */
+
+/*
+ * Conversion types.
+ */
+#define CT_CHAR 0 /* %c conversion */
+#define CT_CCL 1 /* %[...] conversion */
+#define CT_STRING 2 /* %s conversion */
+#define CT_INT 3 /* %[dioupxX] conversion */
+#define CT_FLOAT 4 /* %[efgEFG] conversion */
+
+static const u_char *__sccl(char *, const u_char *);
+#ifndef NO_FLOATING_POINT
+static int parsefloat(FILE *, char *, char *, locale_t);
+#endif
+
+__weak_reference(__vfscanf, vfscanf);
+
+/*
+ * Conversion functions are passed a pointer to this object instead of
+ * a real parameter to indicate that the assignment-suppression (*)
+ * flag was specified. We could use a NULL pointer to indicate this,
+ * but that would mask bugs in applications that call scanf() with a
+ * NULL pointer.
+ */
+static const int suppress;
+#define SUPPRESS_PTR ((void *)&suppress)
+
+static const mbstate_t initial_mbs;
+
+/*
+ * The following conversion functions return the number of characters consumed,
+ * or -1 on input failure. Character class conversion returns 0 on match
+ * failure.
+ */
+
+static __inline int
+convert_char(FILE *fp, char * p, int width)
+{
+ int n;
+
+ if (p == SUPPRESS_PTR) {
+ size_t sum = 0;
+ for (;;) {
+ if ((n = fp->_r) < width) {
+ sum += n;
+ width -= n;
+ fp->_p += n;
+ if (__srefill(fp)) {
+ if (sum == 0)
+ return (-1);
+ break;
+ }
+ } else {
+ sum += width;
+ fp->_r -= width;
+ fp->_p += width;
+ break;
+ }
+ }
+ return (sum);
+ } else {
+ size_t r = __fread(p, 1, width, fp);
+
+ if (r == 0)
+ return (-1);
+ return (r);
+ }
+}
+
+static __inline int
+convert_wchar(FILE *fp, wchar_t *wcp, int width, locale_t locale)
+{
+ mbstate_t mbs;
+ int n, nread;
+ wint_t wi;
+
+ mbs = initial_mbs;
+ n = 0;
+ while (width-- != 0 &&
+ (wi = __fgetwc_mbs(fp, &mbs, &nread, locale)) != WEOF) {
+ if (wcp != SUPPRESS_PTR)
+ *wcp++ = (wchar_t)wi;
+ n += nread;
+ }
+ if (n == 0)
+ return (-1);
+ return (n);
+}
+
+static __inline int
+convert_ccl(FILE *fp, char * p, int width, const char *ccltab)
+{
+ char *p0;
+ int n;
+
+ if (p == SUPPRESS_PTR) {
+ n = 0;
+ while (ccltab[*fp->_p]) {
+ n++, fp->_r--, fp->_p++;
+ if (--width == 0)
+ break;
+ if (fp->_r <= 0 && __srefill(fp)) {
+ if (n == 0)
+ return (-1);
+ break;
+ }
+ }
+ } else {
+ p0 = p;
+ while (ccltab[*fp->_p]) {
+ fp->_r--;
+ *p++ = *fp->_p++;
+ if (--width == 0)
+ break;
+ if (fp->_r <= 0 && __srefill(fp)) {
+ if (p == p0)
+ return (-1);
+ break;
+ }
+ }
+ n = p - p0;
+ if (n == 0)
+ return (0);
+ *p = 0;
+ }
+ return (n);
+}
+
+static __inline int
+convert_wccl(FILE *fp, wchar_t *wcp, int width, const char *ccltab,
+ locale_t locale)
+{
+ mbstate_t mbs;
+ wint_t wi;
+ int n, nread;
+
+ mbs = initial_mbs;
+ n = 0;
+ if (wcp == SUPPRESS_PTR) {
+ while ((wi = __fgetwc_mbs(fp, &mbs, &nread, locale)) != WEOF &&
+ width-- != 0 && ccltab[wctob(wi)])
+ n += nread;
+ if (wi != WEOF)
+ __ungetwc(wi, fp, __get_locale());
+ } else {
+ while ((wi = __fgetwc_mbs(fp, &mbs, &nread, locale)) != WEOF &&
+ width-- != 0 && ccltab[wctob(wi)]) {
+ *wcp++ = (wchar_t)wi;
+ n += nread;
+ }
+ if (wi != WEOF)
+ __ungetwc(wi, fp, __get_locale());
+ if (n == 0)
+ return (0);
+ *wcp = 0;
+ }
+ return (n);
+}
+
+static __inline int
+convert_string(FILE *fp, char * p, int width)
+{
+ char *p0;
+ int n;
+
+ if (p == SUPPRESS_PTR) {
+ n = 0;
+ while (!isspace(*fp->_p)) {
+ n++, fp->_r--, fp->_p++;
+ if (--width == 0)
+ break;
+ if (fp->_r <= 0 && __srefill(fp))
+ break;
+ }
+ } else {
+ p0 = p;
+ while (!isspace(*fp->_p)) {
+ fp->_r--;
+ *p++ = *fp->_p++;
+ if (--width == 0)
+ break;
+ if (fp->_r <= 0 && __srefill(fp))
+ break;
+ }
+ *p = 0;
+ n = p - p0;
+ }
+ return (n);
+}
+
+static __inline int
+convert_wstring(FILE *fp, wchar_t *wcp, int width, locale_t locale)
+{
+ mbstate_t mbs;
+ wint_t wi;
+ int n, nread;
+
+ mbs = initial_mbs;
+ n = 0;
+ if (wcp == SUPPRESS_PTR) {
+ while ((wi = __fgetwc_mbs(fp, &mbs, &nread, locale)) != WEOF &&
+ width-- != 0 && !iswspace(wi))
+ n += nread;
+ if (wi != WEOF)
+ __ungetwc(wi, fp, __get_locale());
+ } else {
+ while ((wi = __fgetwc_mbs(fp, &mbs, &nread, locale)) != WEOF &&
+ width-- != 0 && !iswspace(wi)) {
+ *wcp++ = (wchar_t)wi;
+ n += nread;
+ }
+ if (wi != WEOF)
+ __ungetwc(wi, fp, __get_locale());
+ *wcp = '\0';
+ }
+ return (n);
+}
+
+/*
+ * Read an integer, storing it in buf. The only relevant bit in the
+ * flags argument is PFXOK.
+ *
+ * Return 0 on a match failure, and the number of characters read
+ * otherwise.
+ */
+static __inline int
+parseint(FILE *fp, char * __restrict buf, int width, int base, int flags)
+{
+ /* `basefix' is used to avoid `if' tests */
+ static const short basefix[17] =
+ { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
+ char *p;
+ int c;
+
+ flags |= SIGNOK | NDIGITS | NZDIGITS;
+ for (p = buf; width; width--) {
+ c = *fp->_p;
+ /*
+ * Switch on the character; `goto ok' if we accept it
+ * as a part of number.
+ */
+ switch (c) {
+
+ /*
+ * The digit 0 is always legal, but is special. For
+ * %i conversions, if no digits (zero or nonzero) have
+ * been scanned (only signs), we will have base==0.
+ * In that case, we should set it to 8 and enable 0x
+ * prefixing. Also, if we have not scanned zero
+ * digits before this, do not turn off prefixing
+ * (someone else will turn it off if we have scanned
+ * any nonzero digits).
+ */
+ case '0':
+ if (base == 0) {
+ base = 8;
+ flags |= PFXOK;
+ }
+ if (flags & NZDIGITS)
+ flags &= ~(SIGNOK|NZDIGITS|NDIGITS);
+ else
+ flags &= ~(SIGNOK|PFXOK|NDIGITS);
+ goto ok;
+
+ /* 1 through 7 always legal */
+ case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ base = basefix[base];
+ flags &= ~(SIGNOK | PFXOK | NDIGITS);
+ goto ok;
+
+ /* digits 8 and 9 ok iff decimal or hex */
+ case '8': case '9':
+ base = basefix[base];
+ if (base <= 8)
+ break; /* not legal here */
+ flags &= ~(SIGNOK | PFXOK | NDIGITS);
+ goto ok;
+
+ /* letters ok iff hex */
+ case 'A': case 'B': case 'C':
+ case 'D': case 'E': case 'F':
+ case 'a': case 'b': case 'c':
+ case 'd': case 'e': case 'f':
+ /* no need to fix base here */
+ if (base <= 10)
+ break; /* not legal here */
+ flags &= ~(SIGNOK | PFXOK | NDIGITS);
+ goto ok;
+
+ /* sign ok only as first character */
+ case '+': case '-':
+ if (flags & SIGNOK) {
+ flags &= ~SIGNOK;
+ flags |= HAVESIGN;
+ goto ok;
+ }
+ break;
+
+ /*
+ * x ok iff flag still set & 2nd char (or 3rd char if
+ * we have a sign).
+ */
+ case 'x': case 'X':
+ if (flags & PFXOK && p ==
+ buf + 1 + !!(flags & HAVESIGN)) {
+ base = 16; /* if %i */
+ flags &= ~PFXOK;
+ goto ok;
+ }
+ break;
+ }
+
+ /*
+ * If we got here, c is not a legal character for a
+ * number. Stop accumulating digits.
+ */
+ break;
+ ok:
+ /*
+ * c is legal: store it and look at the next.
+ */
+ *p++ = c;
+ if (--fp->_r > 0)
+ fp->_p++;
+ else if (__srefill(fp))
+ break; /* EOF */
+ }
+ /*
+ * If we had only a sign, it is no good; push back the sign.
+ * If the number ends in `x', it was [sign] '0' 'x', so push
+ * back the x and treat it as [sign] '0'.
+ */
+ if (flags & NDIGITS) {
+ if (p > buf)
+ (void) __ungetc(*(u_char *)--p, fp);
+ return (0);
+ }
+ c = ((u_char *)p)[-1];
+ if (c == 'x' || c == 'X') {
+ --p;
+ (void) __ungetc(c, fp);
+ }
+ return (p - buf);
+}
+
+/*
+ * __vfscanf - MT-safe version
+ */
+int
+__vfscanf(FILE *fp, char const *fmt0, va_list ap)
+{
+ int ret;
+
+ FLOCKFILE(fp);
+ ret = __svfscanf(fp, __get_locale(), fmt0, ap);
+ FUNLOCKFILE(fp);
+ return (ret);
+}
+int
+vfscanf_l(FILE *fp, locale_t locale, char const *fmt0, va_list ap)
+{
+ int ret;
+ FIX_LOCALE(locale);
+
+ FLOCKFILE(fp);
+ ret = __svfscanf(fp, locale, fmt0, ap);
+ FUNLOCKFILE(fp);
+ return (ret);
+}
+
+/*
+ * __svfscanf - non-MT-safe version of __vfscanf
+ */
+int
+__svfscanf(FILE *fp, locale_t locale, const char *fmt0, va_list ap)
+{
+#define GETARG(type) ((flags & SUPPRESS) ? SUPPRESS_PTR : va_arg(ap, type))
+ const u_char *fmt = (const u_char *)fmt0;
+ int c; /* character from format, or conversion */
+ size_t width; /* field width, or 0 */
+ int flags; /* flags as defined above */
+ int nassigned; /* number of fields assigned */
+ int nconversions; /* number of conversions */
+ int nr; /* characters read by the current conversion */
+ int nread; /* number of characters consumed from fp */
+ int base; /* base argument to conversion function */
+ char ccltab[256]; /* character class table for %[...] */
+ char buf[BUF]; /* buffer for numeric conversions */
+
+ ORIENT(fp, -1);
+
+ nassigned = 0;
+ nconversions = 0;
+ nread = 0;
+ for (;;) {
+ c = *fmt++;
+ if (c == 0)
+ return (nassigned);
+ if (isspace(c)) {
+ while ((fp->_r > 0 || __srefill(fp) == 0) && isspace(*fp->_p))
+ nread++, fp->_r--, fp->_p++;
+ continue;
+ }
+ if (c != '%')
+ goto literal;
+ width = 0;
+ flags = 0;
+ /*
+ * switch on the format. continue if done;
+ * break once format type is derived.
+ */
+again: c = *fmt++;
+ switch (c) {
+ case '%':
+literal:
+ if (fp->_r <= 0 && __srefill(fp))
+ goto input_failure;
+ if (*fp->_p != c)
+ goto match_failure;
+ fp->_r--, fp->_p++;
+ nread++;
+ continue;
+
+ case '*':
+ flags |= SUPPRESS;
+ goto again;
+ case 'j':
+ flags |= INTMAXT;
+ goto again;
+ case 'l':
+ if (flags & LONG) {
+ flags &= ~LONG;
+ flags |= LONGLONG;
+ } else
+ flags |= LONG;
+ goto again;
+ case 'q':
+ flags |= LONGLONG; /* not quite */
+ goto again;
+ case 't':
+ flags |= PTRDIFFT;
+ goto again;
+ case 'z':
+ flags |= SIZET;
+ goto again;
+ case 'L':
+ flags |= LONGDBL;
+ goto again;
+ case 'h':
+ if (flags & SHORT) {
+ flags &= ~SHORT;
+ flags |= SHORTSHORT;
+ } else
+ flags |= SHORT;
+ goto again;
+
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ width = width * 10 + c - '0';
+ goto again;
+
+ /*
+ * Conversions.
+ */
+ case 'd':
+ c = CT_INT;
+ base = 10;
+ break;
+
+ case 'i':
+ c = CT_INT;
+ base = 0;
+ break;
+
+ case 'o':
+ c = CT_INT;
+ flags |= UNSIGNED;
+ base = 8;
+ break;
+
+ case 'u':
+ c = CT_INT;
+ flags |= UNSIGNED;
+ base = 10;
+ break;
+
+ case 'X':
+ case 'x':
+ flags |= PFXOK; /* enable 0x prefixing */
+ c = CT_INT;
+ flags |= UNSIGNED;
+ base = 16;
+ break;
+
+#ifndef NO_FLOATING_POINT
+ case 'A': case 'E': case 'F': case 'G':
+ case 'a': case 'e': case 'f': case 'g':
+ c = CT_FLOAT;
+ break;
+#endif
+
+ case 'S':
+ flags |= LONG;
+ /* FALLTHROUGH */
+ case 's':
+ c = CT_STRING;
+ break;
+
+ case '[':
+ fmt = __sccl(ccltab, fmt);
+ flags |= NOSKIP;
+ c = CT_CCL;
+ break;
+
+ case 'C':
+ flags |= LONG;
+ /* FALLTHROUGH */
+ case 'c':
+ flags |= NOSKIP;
+ c = CT_CHAR;
+ break;
+
+ case 'p': /* pointer format is like hex */
+ flags |= POINTER | PFXOK;
+ c = CT_INT; /* assumes sizeof(uintmax_t) */
+ flags |= UNSIGNED; /* >= sizeof(uintptr_t) */
+ base = 16;
+ break;
+
+ case 'n':
+ if (flags & SUPPRESS) /* ??? */
+ continue;
+ if (flags & SHORTSHORT)
+ *va_arg(ap, char *) = nread;
+ else if (flags & SHORT)
+ *va_arg(ap, short *) = nread;
+ else if (flags & LONG)
+ *va_arg(ap, long *) = nread;
+ else if (flags & LONGLONG)
+ *va_arg(ap, long long *) = nread;
+ else if (flags & INTMAXT)
+ *va_arg(ap, intmax_t *) = nread;
+ else if (flags & SIZET)
+ *va_arg(ap, size_t *) = nread;
+ else if (flags & PTRDIFFT)
+ *va_arg(ap, ptrdiff_t *) = nread;
+ else
+ *va_arg(ap, int *) = nread;
+ continue;
+
+ default:
+ goto match_failure;
+
+ /*
+ * Disgusting backwards compatibility hack. XXX
+ */
+ case '\0': /* compat */
+ return (EOF);
+ }
+
+ /*
+ * We have a conversion that requires input.
+ */
+ if (fp->_r <= 0 && __srefill(fp))
+ goto input_failure;
+
+ /*
+ * Consume leading white space, except for formats
+ * that suppress this.
+ */
+ if ((flags & NOSKIP) == 0) {
+ while (isspace(*fp->_p)) {
+ nread++;
+ if (--fp->_r > 0)
+ fp->_p++;
+ else if (__srefill(fp))
+ goto input_failure;
+ }
+ /*
+ * Note that there is at least one character in
+ * the buffer, so conversions that do not set NOSKIP
+ * ca no longer result in an input failure.
+ */
+ }
+
+ /*
+ * Do the conversion.
+ */
+ switch (c) {
+
+ case CT_CHAR:
+ /* scan arbitrary characters (sets NOSKIP) */
+ if (width == 0)
+ width = 1;
+ if (flags & LONG) {
+ nr = convert_wchar(fp, GETARG(wchar_t *),
+ width, locale);
+ } else {
+ nr = convert_char(fp, GETARG(char *), width);
+ }
+ if (nr < 0)
+ goto input_failure;
+ break;
+
+ case CT_CCL:
+ /* scan a (nonempty) character class (sets NOSKIP) */
+ if (width == 0)
+ width = (size_t)~0; /* `infinity' */
+ if (flags & LONG) {
+ nr = convert_wccl(fp, GETARG(wchar_t *), width,
+ ccltab, locale);
+ } else {
+ nr = convert_ccl(fp, GETARG(char *), width,
+ ccltab);
+ }
+ if (nr <= 0) {
+ if (nr < 0)
+ goto input_failure;
+ else /* nr == 0 */
+ goto match_failure;
+ }
+ break;
+
+ case CT_STRING:
+ /* like CCL, but zero-length string OK, & no NOSKIP */
+ if (width == 0)
+ width = (size_t)~0;
+ if (flags & LONG) {
+ nr = convert_wstring(fp, GETARG(wchar_t *),
+ width, locale);
+ } else {
+ nr = convert_string(fp, GETARG(char *), width);
+ }
+ if (nr < 0)
+ goto input_failure;
+ break;
+
+ case CT_INT:
+ /* scan an integer as if by the conversion function */
+#ifdef hardway
+ if (width == 0 || width > sizeof(buf) - 1)
+ width = sizeof(buf) - 1;
+#else
+ /* size_t is unsigned, hence this optimisation */
+ if (--width > sizeof(buf) - 2)
+ width = sizeof(buf) - 2;
+ width++;
+#endif
+ nr = parseint(fp, buf, width, base, flags);
+ if (nr == 0)
+ goto match_failure;
+ if ((flags & SUPPRESS) == 0) {
+ uintmax_t res;
+
+ buf[nr] = '\0';
+ if ((flags & UNSIGNED) == 0)
+ res = strtoimax_l(buf, (char **)NULL, base, locale);
+ else
+ res = strtoumax_l(buf, (char **)NULL, base, locale);
+ if (flags & POINTER)
+ *va_arg(ap, void **) =
+ (void *)(uintptr_t)res;
+ else if (flags & SHORTSHORT)
+ *va_arg(ap, char *) = res;
+ else if (flags & SHORT)
+ *va_arg(ap, short *) = res;
+ else if (flags & LONG)
+ *va_arg(ap, long *) = res;
+ else if (flags & LONGLONG)
+ *va_arg(ap, long long *) = res;
+ else if (flags & INTMAXT)
+ *va_arg(ap, intmax_t *) = res;
+ else if (flags & PTRDIFFT)
+ *va_arg(ap, ptrdiff_t *) = res;
+ else if (flags & SIZET)
+ *va_arg(ap, size_t *) = res;
+ else
+ *va_arg(ap, int *) = res;
+ }
+ break;
+
+#ifndef NO_FLOATING_POINT
+ case CT_FLOAT:
+ /* scan a floating point number as if by strtod */
+ if (width == 0 || width > sizeof(buf) - 1)
+ width = sizeof(buf) - 1;
+ nr = parsefloat(fp, buf, buf + width, locale);
+ if (nr == 0)
+ goto match_failure;
+ if ((flags & SUPPRESS) == 0) {
+ if (flags & LONGDBL) {
+ long double res = strtold_l(buf, NULL,
+ locale);
+ *va_arg(ap, long double *) = res;
+ } else if (flags & LONG) {
+ double res = strtod_l(buf, NULL,
+ locale);
+ *va_arg(ap, double *) = res;
+ } else {
+ float res = strtof_l(buf, NULL, locale);
+ *va_arg(ap, float *) = res;
+ }
+ }
+ break;
+#endif /* !NO_FLOATING_POINT */
+ }
+ if (!(flags & SUPPRESS))
+ nassigned++;
+ nread += nr;
+ nconversions++;
+ }
+input_failure:
+ return (nconversions != 0 ? nassigned : EOF);
+match_failure:
+ return (nassigned);
+}
+
+/*
+ * Fill in the given table from the scanset at the given format
+ * (just after `['). Return a pointer to the character past the
+ * closing `]'. The table has a 1 wherever characters should be
+ * considered part of the scanset.
+ */
+static const u_char *
+__sccl(char *tab, const u_char *fmt)
+{
+ int c, n, v, i;
+ struct xlocale_collate *table =
+ (struct xlocale_collate*)__get_locale()->components[XLC_COLLATE];
+
+ /* first `clear' the whole table */
+ c = *fmt++; /* first char hat => negated scanset */
+ if (c == '^') {
+ v = 1; /* default => accept */
+ c = *fmt++; /* get new first char */
+ } else
+ v = 0; /* default => reject */
+
+ /* XXX: Will not work if sizeof(tab*) > sizeof(char) */
+ (void) memset(tab, v, 256);
+
+ if (c == 0)
+ return (fmt - 1);/* format ended before closing ] */
+
+ /*
+ * Now set the entries corresponding to the actual scanset
+ * to the opposite of the above.
+ *
+ * The first character may be ']' (or '-') without being special;
+ * the last character may be '-'.
+ */
+ v = 1 - v;
+ for (;;) {
+ tab[c] = v; /* take character c */
+doswitch:
+ n = *fmt++; /* and examine the next */
+ switch (n) {
+
+ case 0: /* format ended too soon */
+ return (fmt - 1);
+
+ case '-':
+ /*
+ * A scanset of the form
+ * [01+-]
+ * is defined as `the digit 0, the digit 1,
+ * the character +, the character -', but
+ * the effect of a scanset such as
+ * [a-zA-Z0-9]
+ * is implementation defined. The V7 Unix
+ * scanf treats `a-z' as `the letters a through
+ * z', but treats `a-a' as `the letter a, the
+ * character -, and the letter a'.
+ *
+ * For compatibility, the `-' is not considered
+ * to define a range if the character following
+ * it is either a close bracket (required by ANSI)
+ * or is not numerically greater than the character
+ * we just stored in the table (c).
+ */
+ n = *fmt;
+ if (n == ']'
+ || (table->__collate_load_error ? n < c :
+ __collate_range_cmp(n, c) < 0
+ )
+ ) {
+ c = '-';
+ break; /* resume the for(;;) */
+ }
+ fmt++;
+ /* fill in the range */
+ if (table->__collate_load_error) {
+ do {
+ tab[++c] = v;
+ } while (c < n);
+ } else {
+ for (i = 0; i < 256; i ++)
+ if (__collate_range_cmp(c, i) <= 0 &&
+ __collate_range_cmp(i, n) <= 0
+ )
+ tab[i] = v;
+ }
+#if 1 /* XXX another disgusting compatibility hack */
+ c = n;
+ /*
+ * Alas, the V7 Unix scanf also treats formats
+ * such as [a-c-e] as `the letters a through e'.
+ * This too is permitted by the standard....
+ */
+ goto doswitch;
+#else
+ c = *fmt++;
+ if (c == 0)
+ return (fmt - 1);
+ if (c == ']')
+ return (fmt);
+#endif
+ break;
+
+ case ']': /* end of scanset */
+ return (fmt);
+
+ default: /* just another character */
+ c = n;
+ break;
+ }
+ }
+ /* NOTREACHED */
+}
+
+#ifndef NO_FLOATING_POINT
+static int
+parsefloat(FILE *fp, char *buf, char *end, locale_t locale)
+{
+ char *commit, *p;
+ int infnanpos = 0, decptpos = 0;
+ enum {
+ S_START, S_GOTSIGN, S_INF, S_NAN, S_DONE, S_MAYBEHEX,
+ S_DIGITS, S_DECPT, S_FRAC, S_EXP, S_EXPDIGITS
+ } state = S_START;
+ unsigned char c;
+ const char *decpt = localeconv_l(locale)->decimal_point;
+ _Bool gotmantdig = 0, ishex = 0;
+
+ /*
+ * We set commit = p whenever the string we have read so far
+ * constitutes a valid representation of a floating point
+ * number by itself. At some point, the parse will complete
+ * or fail, and we will ungetc() back to the last commit point.
+ * To ensure that the file offset gets updated properly, it is
+ * always necessary to read at least one character that doesn't
+ * match; thus, we can't short-circuit "infinity" or "nan(...)".
+ */
+ commit = buf - 1;
+ for (p = buf; p < end; ) {
+ c = *fp->_p;
+reswitch:
+ switch (state) {
+ case S_START:
+ state = S_GOTSIGN;
+ if (c == '-' || c == '+')
+ break;
+ else
+ goto reswitch;
+ case S_GOTSIGN:
+ switch (c) {
+ case '0':
+ state = S_MAYBEHEX;
+ commit = p;
+ break;
+ case 'I':
+ case 'i':
+ state = S_INF;
+ break;
+ case 'N':
+ case 'n':
+ state = S_NAN;
+ break;
+ default:
+ state = S_DIGITS;
+ goto reswitch;
+ }
+ break;
+ case S_INF:
+ if (infnanpos > 6 ||
+ (c != "nfinity"[infnanpos] &&
+ c != "NFINITY"[infnanpos]))
+ goto parsedone;
+ if (infnanpos == 1 || infnanpos == 6)
+ commit = p; /* inf or infinity */
+ infnanpos++;
+ break;
+ case S_NAN:
+ switch (infnanpos) {
+ case 0:
+ if (c != 'A' && c != 'a')
+ goto parsedone;
+ break;
+ case 1:
+ if (c != 'N' && c != 'n')
+ goto parsedone;
+ else
+ commit = p;
+ break;
+ case 2:
+ if (c != '(')
+ goto parsedone;
+ break;
+ default:
+ if (c == ')') {
+ commit = p;
+ state = S_DONE;
+ } else if (!isalnum(c) && c != '_')
+ goto parsedone;
+ break;
+ }
+ infnanpos++;
+ break;
+ case S_DONE:
+ goto parsedone;
+ case S_MAYBEHEX:
+ state = S_DIGITS;
+ if (c == 'X' || c == 'x') {
+ ishex = 1;
+ break;
+ } else { /* we saw a '0', but no 'x' */
+ gotmantdig = 1;
+ goto reswitch;
+ }
+ case S_DIGITS:
+ if ((ishex && isxdigit(c)) || isdigit(c)) {
+ gotmantdig = 1;
+ commit = p;
+ break;
+ } else {
+ state = S_DECPT;
+ goto reswitch;
+ }
+ case S_DECPT:
+ if (c == decpt[decptpos]) {
+ if (decpt[++decptpos] == '\0') {
+ /* We read the complete decpt seq. */
+ state = S_FRAC;
+ if (gotmantdig)
+ commit = p;
+ }
+ break;
+ } else if (!decptpos) {
+ /* We didn't read any decpt characters. */
+ state = S_FRAC;
+ goto reswitch;
+ } else {
+ /*
+ * We read part of a multibyte decimal point,
+ * but the rest is invalid, so bail.
+ */
+ goto parsedone;
+ }
+ case S_FRAC:
+ if (((c == 'E' || c == 'e') && !ishex) ||
+ ((c == 'P' || c == 'p') && ishex)) {
+ if (!gotmantdig)
+ goto parsedone;
+ else
+ state = S_EXP;
+ } else if ((ishex && isxdigit(c)) || isdigit(c)) {
+ commit = p;
+ gotmantdig = 1;
+ } else
+ goto parsedone;
+ break;
+ case S_EXP:
+ state = S_EXPDIGITS;
+ if (c == '-' || c == '+')
+ break;
+ else
+ goto reswitch;
+ case S_EXPDIGITS:
+ if (isdigit(c))
+ commit = p;
+ else
+ goto parsedone;
+ break;
+ default:
+ abort();
+ }
+ *p++ = c;
+ if (--fp->_r > 0)
+ fp->_p++;
+ else if (__srefill(fp))
+ break; /* EOF */
+ }
+
+parsedone:
+ while (commit < --p)
+ __ungetc(*(u_char *)p, fp);
+ *++commit = '\0';
+ return (commit - buf);
+}
+#endif
diff --git a/lib/libc/stdio/vfwprintf.c b/lib/libc/stdio/vfwprintf.c
new file mode 100644
index 000000000000..9a5381d54b9b
--- /dev/null
+++ b/lib/libc/stdio/vfwprintf.c
@@ -0,0 +1,1109 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)vfprintf.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Actual wprintf innards.
+ *
+ * Avoid making gratuitous changes to this source file; it should be kept
+ * as close as possible to vfprintf.c for ease of maintenance.
+ */
+
+#include "namespace.h"
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <locale.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <wctype.h>
+#include "un-namespace.h"
+
+#include "libc_private.h"
+#include "local.h"
+#include "fvwrite.h"
+#include "printflocal.h"
+#include "xlocale_private.h"
+
+static int __sprint(FILE *, struct __suio *, locale_t);
+static int __sbprintf(FILE *, locale_t, const wchar_t *, va_list) __noinline;
+static wint_t __xfputwc(wchar_t, FILE *, locale_t);
+static wchar_t *__mbsconv(char *, int);
+
+#define CHAR wchar_t
+#include "printfcommon.h"
+
+struct grouping_state {
+ wchar_t thousands_sep; /* locale-specific thousands separator */
+ const char *grouping; /* locale-specific numeric grouping rules */
+ int lead; /* sig figs before decimal or group sep */
+ int nseps; /* number of group separators with ' */
+ int nrepeats; /* number of repeats of the last group */
+};
+
+static const mbstate_t initial_mbs;
+
+static inline wchar_t
+get_decpt(locale_t locale)
+{
+ mbstate_t mbs;
+ wchar_t decpt;
+ int nconv;
+
+ mbs = initial_mbs;
+ nconv = mbrtowc(&decpt, localeconv_l(locale)->decimal_point, MB_CUR_MAX, &mbs);
+ if (nconv == (size_t)-1 || nconv == (size_t)-2)
+ decpt = '.'; /* failsafe */
+ return (decpt);
+}
+
+static inline wchar_t
+get_thousep(locale_t locale)
+{
+ mbstate_t mbs;
+ wchar_t thousep;
+ int nconv;
+
+ mbs = initial_mbs;
+ nconv = mbrtowc(&thousep, localeconv_l(locale)->thousands_sep,
+ MB_CUR_MAX, &mbs);
+ if (nconv == (size_t)-1 || nconv == (size_t)-2)
+ thousep = '\0'; /* failsafe */
+ return (thousep);
+}
+
+/*
+ * Initialize the thousands' grouping state in preparation to print a
+ * number with ndigits digits. This routine returns the total number
+ * of wide characters that will be printed.
+ */
+static int
+grouping_init(struct grouping_state *gs, int ndigits, locale_t locale)
+{
+
+ gs->grouping = localeconv_l(locale)->grouping;
+ gs->thousands_sep = get_thousep(locale);
+
+ gs->nseps = gs->nrepeats = 0;
+ gs->lead = ndigits;
+ while (*gs->grouping != CHAR_MAX) {
+ if (gs->lead <= *gs->grouping)
+ break;
+ gs->lead -= *gs->grouping;
+ if (*(gs->grouping+1)) {
+ gs->nseps++;
+ gs->grouping++;
+ } else
+ gs->nrepeats++;
+ }
+ return (gs->nseps + gs->nrepeats);
+}
+
+/*
+ * Print a number with thousands' separators.
+ */
+static int
+grouping_print(struct grouping_state *gs, struct io_state *iop,
+ const CHAR *cp, const CHAR *ep, locale_t locale)
+{
+ const CHAR *cp0 = cp;
+
+ if (io_printandpad(iop, cp, ep, gs->lead, zeroes, locale))
+ return (-1);
+ cp += gs->lead;
+ while (gs->nseps > 0 || gs->nrepeats > 0) {
+ if (gs->nrepeats > 0)
+ gs->nrepeats--;
+ else {
+ gs->grouping--;
+ gs->nseps--;
+ }
+ if (io_print(iop, &gs->thousands_sep, 1, locale))
+ return (-1);
+ if (io_printandpad(iop, cp, ep, *gs->grouping, zeroes, locale))
+ return (-1);
+ cp += *gs->grouping;
+ }
+ if (cp > ep)
+ cp = ep;
+ return (cp - cp0);
+}
+
+
+/*
+ * Flush out all the vectors defined by the given uio,
+ * then reset it so that it can be reused.
+ *
+ * XXX The fact that we do this a character at a time and convert to a
+ * multibyte character sequence even if the destination is a wide
+ * string eclipses the benefits of buffering.
+ */
+static int
+__sprint(FILE *fp, struct __suio *uio, locale_t locale)
+{
+ struct __siov *iov;
+ wchar_t *p;
+ int i, len;
+
+ iov = uio->uio_iov;
+ for (; uio->uio_resid != 0; uio->uio_resid -= len, iov++) {
+ p = (wchar_t *)iov->iov_base;
+ len = iov->iov_len;
+ for (i = 0; i < len; i++) {
+ if (__xfputwc(p[i], fp, locale) == WEOF)
+ return (-1);
+ }
+ }
+ uio->uio_iovcnt = 0;
+ return (0);
+}
+
+/*
+ * Helper function for `fprintf to unbuffered unix file': creates a
+ * temporary buffer. We only work on write-only files; this avoids
+ * worries about ungetc buffers and so forth.
+ */
+static int
+__sbprintf(FILE *fp, locale_t locale, const wchar_t *fmt, va_list ap)
+{
+ int ret;
+ FILE fake;
+ unsigned char buf[BUFSIZ];
+
+ /* XXX This is probably not needed. */
+ if (prepwrite(fp) != 0)
+ return (EOF);
+
+ /* copy the important variables */
+ fake._flags = fp->_flags & ~__SNBF;
+ fake._file = fp->_file;
+ fake._cookie = fp->_cookie;
+ fake._write = fp->_write;
+ fake._orientation = fp->_orientation;
+ fake._mbstate = fp->_mbstate;
+
+ /* set up the buffer */
+ fake._bf._base = fake._p = buf;
+ fake._bf._size = fake._w = sizeof(buf);
+ fake._lbfsize = 0; /* not actually used, but Just In Case */
+
+ /* do the work, then copy any error status */
+ ret = __vfwprintf(&fake, locale, fmt, ap);
+ if (ret >= 0 && __fflush(&fake))
+ ret = WEOF;
+ if (fake._flags & __SERR)
+ fp->_flags |= __SERR;
+ return (ret);
+}
+
+/*
+ * Like __fputwc, but handles fake string (__SSTR) files properly.
+ * File must already be locked.
+ */
+static wint_t
+__xfputwc(wchar_t wc, FILE *fp, locale_t locale)
+{
+ mbstate_t mbs;
+ char buf[MB_LEN_MAX];
+ struct __suio uio;
+ struct __siov iov;
+ size_t len;
+
+ if ((fp->_flags & __SSTR) == 0)
+ return (__fputwc(wc, fp, locale));
+
+ mbs = initial_mbs;
+ if ((len = wcrtomb(buf, wc, &mbs)) == (size_t)-1) {
+ fp->_flags |= __SERR;
+ return (WEOF);
+ }
+ uio.uio_iov = &iov;
+ uio.uio_resid = len;
+ uio.uio_iovcnt = 1;
+ iov.iov_base = buf;
+ iov.iov_len = len;
+ return (__sfvwrite(fp, &uio) != EOF ? (wint_t)wc : WEOF);
+}
+
+/*
+ * Convert a multibyte character string argument for the %s format to a wide
+ * string representation. ``prec'' specifies the maximum number of bytes
+ * to output. If ``prec'' is greater than or equal to zero, we can't assume
+ * that the multibyte char. string ends in a null character.
+ */
+static wchar_t *
+__mbsconv(char *mbsarg, int prec)
+{
+ mbstate_t mbs;
+ wchar_t *convbuf, *wcp;
+ const char *p;
+ size_t insize, nchars, nconv;
+
+ if (mbsarg == NULL)
+ return (NULL);
+
+ /*
+ * Supplied argument is a multibyte string; convert it to wide
+ * characters first.
+ */
+ if (prec >= 0) {
+ /*
+ * String is not guaranteed to be NUL-terminated. Find the
+ * number of characters to print.
+ */
+ p = mbsarg;
+ insize = nchars = nconv = 0;
+ mbs = initial_mbs;
+ while (nchars != (size_t)prec) {
+ nconv = mbrlen(p, MB_CUR_MAX, &mbs);
+ if (nconv == 0 || nconv == (size_t)-1 ||
+ nconv == (size_t)-2)
+ break;
+ p += nconv;
+ nchars++;
+ insize += nconv;
+ }
+ if (nconv == (size_t)-1 || nconv == (size_t)-2)
+ return (NULL);
+ } else {
+ insize = strlen(mbsarg);
+ nconv = 0;
+ }
+
+ /*
+ * Allocate buffer for the result and perform the conversion,
+ * converting at most `size' bytes of the input multibyte string to
+ * wide characters for printing.
+ */
+ convbuf = malloc((insize + 1) * sizeof(*convbuf));
+ if (convbuf == NULL)
+ return (NULL);
+ wcp = convbuf;
+ p = mbsarg;
+ mbs = initial_mbs;
+ while (insize != 0) {
+ nconv = mbrtowc(wcp, p, insize, &mbs);
+ if (nconv == 0 || nconv == (size_t)-1 || nconv == (size_t)-2)
+ break;
+ wcp++;
+ p += nconv;
+ insize -= nconv;
+ }
+ if (nconv == (size_t)-1 || nconv == (size_t)-2) {
+ free(convbuf);
+ return (NULL);
+ }
+ *wcp = L'\0';
+
+ return (convbuf);
+}
+
+/*
+ * MT-safe version
+ */
+int
+vfwprintf_l(FILE * __restrict fp, locale_t locale,
+ const wchar_t * __restrict fmt0, va_list ap)
+
+{
+ int ret;
+ FIX_LOCALE(locale);
+ FLOCKFILE(fp);
+ /* optimise fprintf(stderr) (and other unbuffered Unix files) */
+ if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
+ fp->_file >= 0)
+ ret = __sbprintf(fp, locale, fmt0, ap);
+ else
+ ret = __vfwprintf(fp, locale, fmt0, ap);
+ FUNLOCKFILE(fp);
+ return (ret);
+}
+int
+vfwprintf(FILE * __restrict fp, const wchar_t * __restrict fmt0, va_list ap)
+{
+ return vfwprintf_l(fp, __get_locale(), fmt0, ap);
+}
+
+/*
+ * The size of the buffer we use as scratch space for integer
+ * conversions, among other things. We need enough space to
+ * write a uintmax_t in octal (plus one byte).
+ */
+#if UINTMAX_MAX <= UINT64_MAX
+#define BUF 32
+#else
+#error "BUF must be large enough to format a uintmax_t"
+#endif
+
+/*
+ * Non-MT-safe version
+ */
+int
+__vfwprintf(FILE *fp, locale_t locale, const wchar_t *fmt0, va_list ap)
+{
+ wchar_t *fmt; /* format string */
+ wchar_t ch; /* character from fmt */
+ int n, n2; /* handy integer (short term usage) */
+ wchar_t *cp; /* handy char pointer (short term usage) */
+ int flags; /* flags as above */
+ int ret; /* return value accumulator */
+ int width; /* width from format (%8d), or 0 */
+ int prec; /* precision from format; <0 for N/A */
+ wchar_t sign; /* sign prefix (' ', '+', '-', or \0) */
+ struct grouping_state gs; /* thousands' grouping info */
+#ifndef NO_FLOATING_POINT
+ /*
+ * We can decompose the printed representation of floating
+ * point numbers into several parts, some of which may be empty:
+ *
+ * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ
+ * A B ---C--- D E F
+ *
+ * A: 'sign' holds this value if present; '\0' otherwise
+ * B: ox[1] holds the 'x' or 'X'; '\0' if not hexadecimal
+ * C: cp points to the string MMMNNN. Leading and trailing
+ * zeros are not in the string and must be added.
+ * D: expchar holds this character; '\0' if no exponent, e.g. %f
+ * F: at least two digits for decimal, at least one digit for hex
+ */
+ wchar_t decimal_point; /* locale specific decimal point */
+ int signflag; /* true if float is negative */
+ union { /* floating point arguments %[aAeEfFgG] */
+ double dbl;
+ long double ldbl;
+ } fparg;
+ int expt; /* integer value of exponent */
+ char expchar; /* exponent character: [eEpP\0] */
+ char *dtoaend; /* pointer to end of converted digits */
+ int expsize; /* character count for expstr */
+ int ndig; /* actual number of digits returned by dtoa */
+ wchar_t expstr[MAXEXPDIG+2]; /* buffer for exponent string: e+ZZZ */
+ char *dtoaresult; /* buffer allocated by dtoa */
+#endif
+ u_long ulval; /* integer arguments %[diouxX] */
+ uintmax_t ujval; /* %j, %ll, %q, %t, %z integers */
+ int base; /* base for [diouxX] conversion */
+ int dprec; /* a copy of prec if [diouxX], 0 otherwise */
+ int realsz; /* field size expanded by dprec, sign, etc */
+ int size; /* size of converted field or string */
+ int prsize; /* max size of printed field */
+ const char *xdigs; /* digits for [xX] conversion */
+ struct io_state io; /* I/O buffering state */
+ wchar_t buf[BUF]; /* buffer with space for digits of uintmax_t */
+ wchar_t ox[2]; /* space for 0x hex-prefix */
+ union arg *argtable; /* args, built due to positional arg */
+ union arg statargtable [STATIC_ARG_TBL_SIZE];
+ int nextarg; /* 1-based argument index */
+ va_list orgap; /* original argument pointer */
+ wchar_t *convbuf; /* multibyte to wide conversion result */
+ int savserr;
+
+ static const char xdigs_lower[16] = "0123456789abcdef";
+ static const char xdigs_upper[16] = "0123456789ABCDEF";
+
+ /* BEWARE, these `goto error' on error. */
+#define PRINT(ptr, len) do { \
+ if (io_print(&io, (ptr), (len), locale)) \
+ goto error; \
+} while (0)
+#define PAD(howmany, with) { \
+ if (io_pad(&io, (howmany), (with), locale)) \
+ goto error; \
+}
+#define PRINTANDPAD(p, ep, len, with) { \
+ if (io_printandpad(&io, (p), (ep), (len), (with), locale)) \
+ goto error; \
+}
+#define FLUSH() { \
+ if (io_flush(&io, locale)) \
+ goto error; \
+}
+
+ /*
+ * Get the argument indexed by nextarg. If the argument table is
+ * built, use it to get the argument. If its not, get the next
+ * argument (and arguments must be gotten sequentially).
+ */
+#define GETARG(type) \
+ ((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : \
+ (nextarg++, va_arg(ap, type)))
+
+ /*
+ * To extend shorts properly, we need both signed and unsigned
+ * argument extraction methods.
+ */
+#define SARG() \
+ (flags&LONGINT ? GETARG(long) : \
+ flags&SHORTINT ? (long)(short)GETARG(int) : \
+ flags&CHARINT ? (long)(signed char)GETARG(int) : \
+ (long)GETARG(int))
+#define UARG() \
+ (flags&LONGINT ? GETARG(u_long) : \
+ flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \
+ flags&CHARINT ? (u_long)(u_char)GETARG(int) : \
+ (u_long)GETARG(u_int))
+#define INTMAX_SIZE (INTMAXT|SIZET|PTRDIFFT|LLONGINT)
+#define SJARG() \
+ (flags&INTMAXT ? GETARG(intmax_t) : \
+ flags&SIZET ? (intmax_t)GETARG(ssize_t) : \
+ flags&PTRDIFFT ? (intmax_t)GETARG(ptrdiff_t) : \
+ (intmax_t)GETARG(long long))
+#define UJARG() \
+ (flags&INTMAXT ? GETARG(uintmax_t) : \
+ flags&SIZET ? (uintmax_t)GETARG(size_t) : \
+ flags&PTRDIFFT ? (uintmax_t)GETARG(ptrdiff_t) : \
+ (uintmax_t)GETARG(unsigned long long))
+
+ /*
+ * Get * arguments, including the form *nn$. Preserve the nextarg
+ * that the argument can be gotten once the type is determined.
+ */
+#define GETASTER(val) \
+ n2 = 0; \
+ cp = fmt; \
+ while (is_digit(*cp)) { \
+ n2 = 10 * n2 + to_digit(*cp); \
+ cp++; \
+ } \
+ if (*cp == '$') { \
+ int hold = nextarg; \
+ if (argtable == NULL) { \
+ argtable = statargtable; \
+ if (__find_warguments (fmt0, orgap, &argtable)) { \
+ ret = EOF; \
+ goto error; \
+ } \
+ } \
+ nextarg = n2; \
+ val = GETARG (int); \
+ nextarg = hold; \
+ fmt = ++cp; \
+ } else { \
+ val = GETARG (int); \
+ }
+
+
+ /* sorry, fwprintf(read_only_file, L"") returns WEOF, not 0 */
+ if (prepwrite(fp) != 0) {
+ errno = EBADF;
+ return (EOF);
+ }
+
+ savserr = fp->_flags & __SERR;
+ fp->_flags &= ~__SERR;
+
+ convbuf = NULL;
+ fmt = (wchar_t *)fmt0;
+ argtable = NULL;
+ nextarg = 1;
+ va_copy(orgap, ap);
+ io_init(&io, fp);
+ ret = 0;
+#ifndef NO_FLOATING_POINT
+ decimal_point = get_decpt(locale);
+#endif
+
+ /*
+ * Scan the format for conversions (`%' character).
+ */
+ for (;;) {
+ for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
+ /* void */;
+ if ((n = fmt - cp) != 0) {
+ if ((unsigned)ret + n > INT_MAX) {
+ ret = EOF;
+ errno = EOVERFLOW;
+ goto error;
+ }
+ PRINT(cp, n);
+ ret += n;
+ }
+ if (ch == '\0')
+ goto done;
+ fmt++; /* skip over '%' */
+
+ flags = 0;
+ dprec = 0;
+ width = 0;
+ prec = -1;
+ gs.grouping = NULL;
+ sign = '\0';
+ ox[1] = '\0';
+
+rflag: ch = *fmt++;
+reswitch: switch (ch) {
+ case ' ':
+ /*-
+ * ``If the space and + flags both appear, the space
+ * flag will be ignored.''
+ * -- ANSI X3J11
+ */
+ if (!sign)
+ sign = ' ';
+ goto rflag;
+ case '#':
+ flags |= ALT;
+ goto rflag;
+ case '*':
+ /*-
+ * ``A negative field width argument is taken as a
+ * - flag followed by a positive field width.''
+ * -- ANSI X3J11
+ * They don't exclude field widths read from args.
+ */
+ GETASTER (width);
+ if (width >= 0)
+ goto rflag;
+ width = -width;
+ /* FALLTHROUGH */
+ case '-':
+ flags |= LADJUST;
+ goto rflag;
+ case '+':
+ sign = '+';
+ goto rflag;
+ case '\'':
+ flags |= GROUPING;
+ goto rflag;
+ case '.':
+ if ((ch = *fmt++) == '*') {
+ GETASTER (prec);
+ goto rflag;
+ }
+ prec = 0;
+ while (is_digit(ch)) {
+ prec = 10 * prec + to_digit(ch);
+ ch = *fmt++;
+ }
+ goto reswitch;
+ case '0':
+ /*-
+ * ``Note that 0 is taken as a flag, not as the
+ * beginning of a field width.''
+ * -- ANSI X3J11
+ */
+ flags |= ZEROPAD;
+ goto rflag;
+ case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ n = 0;
+ do {
+ n = 10 * n + to_digit(ch);
+ ch = *fmt++;
+ } while (is_digit(ch));
+ if (ch == '$') {
+ nextarg = n;
+ if (argtable == NULL) {
+ argtable = statargtable;
+ if (__find_warguments (fmt0, orgap,
+ &argtable)) {
+ ret = EOF;
+ goto error;
+ }
+ }
+ goto rflag;
+ }
+ width = n;
+ goto reswitch;
+#ifndef NO_FLOATING_POINT
+ case 'L':
+ flags |= LONGDBL;
+ goto rflag;
+#endif
+ case 'h':
+ if (flags & SHORTINT) {
+ flags &= ~SHORTINT;
+ flags |= CHARINT;
+ } else
+ flags |= SHORTINT;
+ goto rflag;
+ case 'j':
+ flags |= INTMAXT;
+ goto rflag;
+ case 'l':
+ if (flags & LONGINT) {
+ flags &= ~LONGINT;
+ flags |= LLONGINT;
+ } else
+ flags |= LONGINT;
+ goto rflag;
+ case 'q':
+ flags |= LLONGINT; /* not necessarily */
+ goto rflag;
+ case 't':
+ flags |= PTRDIFFT;
+ goto rflag;
+ case 'z':
+ flags |= SIZET;
+ goto rflag;
+ case 'C':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 'c':
+ if (flags & LONGINT)
+ *(cp = buf) = (wchar_t)GETARG(wint_t);
+ else
+ *(cp = buf) = (wchar_t)btowc(GETARG(int));
+ size = 1;
+ sign = '\0';
+ break;
+ case 'D':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 'd':
+ case 'i':
+ if (flags & INTMAX_SIZE) {
+ ujval = SJARG();
+ if ((intmax_t)ujval < 0) {
+ ujval = -ujval;
+ sign = '-';
+ }
+ } else {
+ ulval = SARG();
+ if ((long)ulval < 0) {
+ ulval = -ulval;
+ sign = '-';
+ }
+ }
+ base = 10;
+ goto number;
+#ifndef NO_FLOATING_POINT
+ case 'a':
+ case 'A':
+ if (ch == 'a') {
+ ox[1] = 'x';
+ xdigs = xdigs_lower;
+ expchar = 'p';
+ } else {
+ ox[1] = 'X';
+ xdigs = xdigs_upper;
+ expchar = 'P';
+ }
+ if (prec >= 0)
+ prec++;
+ if (flags & LONGDBL) {
+ fparg.ldbl = GETARG(long double);
+ dtoaresult =
+ __hldtoa(fparg.ldbl, xdigs, prec,
+ &expt, &signflag, &dtoaend);
+ } else {
+ fparg.dbl = GETARG(double);
+ dtoaresult =
+ __hdtoa(fparg.dbl, xdigs, prec,
+ &expt, &signflag, &dtoaend);
+ }
+ if (prec < 0)
+ prec = dtoaend - dtoaresult;
+ if (expt == INT_MAX)
+ ox[1] = '\0';
+ if (convbuf != NULL)
+ free(convbuf);
+ ndig = dtoaend - dtoaresult;
+ cp = convbuf = __mbsconv(dtoaresult, -1);
+ freedtoa(dtoaresult);
+ goto fp_common;
+ case 'e':
+ case 'E':
+ expchar = ch;
+ if (prec < 0) /* account for digit before decpt */
+ prec = DEFPREC + 1;
+ else
+ prec++;
+ goto fp_begin;
+ case 'f':
+ case 'F':
+ expchar = '\0';
+ goto fp_begin;
+ case 'g':
+ case 'G':
+ expchar = ch - ('g' - 'e');
+ if (prec == 0)
+ prec = 1;
+fp_begin:
+ if (prec < 0)
+ prec = DEFPREC;
+ if (convbuf != NULL)
+ free(convbuf);
+ if (flags & LONGDBL) {
+ fparg.ldbl = GETARG(long double);
+ dtoaresult =
+ __ldtoa(&fparg.ldbl, expchar ? 2 : 3, prec,
+ &expt, &signflag, &dtoaend);
+ } else {
+ fparg.dbl = GETARG(double);
+ dtoaresult =
+ dtoa(fparg.dbl, expchar ? 2 : 3, prec,
+ &expt, &signflag, &dtoaend);
+ if (expt == 9999)
+ expt = INT_MAX;
+ }
+ ndig = dtoaend - dtoaresult;
+ cp = convbuf = __mbsconv(dtoaresult, -1);
+ freedtoa(dtoaresult);
+fp_common:
+ if (signflag)
+ sign = '-';
+ if (expt == INT_MAX) { /* inf or nan */
+ if (*cp == 'N') {
+ cp = (ch >= 'a') ? L"nan" : L"NAN";
+ sign = '\0';
+ } else
+ cp = (ch >= 'a') ? L"inf" : L"INF";
+ size = 3;
+ flags &= ~ZEROPAD;
+ break;
+ }
+ flags |= FPT;
+ if (ch == 'g' || ch == 'G') {
+ if (expt > -4 && expt <= prec) {
+ /* Make %[gG] smell like %[fF] */
+ expchar = '\0';
+ if (flags & ALT)
+ prec -= expt;
+ else
+ prec = ndig - expt;
+ if (prec < 0)
+ prec = 0;
+ } else {
+ /*
+ * Make %[gG] smell like %[eE], but
+ * trim trailing zeroes if no # flag.
+ */
+ if (!(flags & ALT))
+ prec = ndig;
+ }
+ }
+ if (expchar) {
+ expsize = exponent(expstr, expt - 1, expchar);
+ size = expsize + prec;
+ if (prec > 1 || flags & ALT)
+ ++size;
+ } else {
+ /* space for digits before decimal point */
+ if (expt > 0)
+ size = expt;
+ else /* "0" */
+ size = 1;
+ /* space for decimal pt and following digits */
+ if (prec || flags & ALT)
+ size += prec + 1;
+ if ((flags & GROUPING) && expt > 0)
+ size += grouping_init(&gs, expt, locale);
+ }
+ break;
+#endif /* !NO_FLOATING_POINT */
+ case 'n':
+ /*
+ * Assignment-like behavior is specified if the
+ * value overflows or is otherwise unrepresentable.
+ * C99 says to use `signed char' for %hhn conversions.
+ */
+ if (flags & LLONGINT)
+ *GETARG(long long *) = ret;
+ else if (flags & SIZET)
+ *GETARG(ssize_t *) = (ssize_t)ret;
+ else if (flags & PTRDIFFT)
+ *GETARG(ptrdiff_t *) = ret;
+ else if (flags & INTMAXT)
+ *GETARG(intmax_t *) = ret;
+ else if (flags & LONGINT)
+ *GETARG(long *) = ret;
+ else if (flags & SHORTINT)
+ *GETARG(short *) = ret;
+ else if (flags & CHARINT)
+ *GETARG(signed char *) = ret;
+ else
+ *GETARG(int *) = ret;
+ continue; /* no output */
+ case 'O':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 'o':
+ if (flags & INTMAX_SIZE)
+ ujval = UJARG();
+ else
+ ulval = UARG();
+ base = 8;
+ goto nosign;
+ case 'p':
+ /*-
+ * ``The argument shall be a pointer to void. The
+ * value of the pointer is converted to a sequence
+ * of printable characters, in an implementation-
+ * defined manner.''
+ * -- ANSI X3J11
+ */
+ ujval = (uintmax_t)(uintptr_t)GETARG(void *);
+ base = 16;
+ xdigs = xdigs_lower;
+ flags = flags | INTMAXT;
+ ox[1] = 'x';
+ goto nosign;
+ case 'S':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 's':
+ if (flags & LONGINT) {
+ if ((cp = GETARG(wchar_t *)) == NULL)
+ cp = L"(null)";
+ } else {
+ char *mbp;
+
+ if (convbuf != NULL)
+ free(convbuf);
+ if ((mbp = GETARG(char *)) == NULL)
+ cp = L"(null)";
+ else {
+ convbuf = __mbsconv(mbp, prec);
+ if (convbuf == NULL) {
+ fp->_flags |= __SERR;
+ goto error;
+ }
+ cp = convbuf;
+ }
+ }
+ size = (prec >= 0) ? wcsnlen(cp, prec) : wcslen(cp);
+ sign = '\0';
+ break;
+ case 'U':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 'u':
+ if (flags & INTMAX_SIZE)
+ ujval = UJARG();
+ else
+ ulval = UARG();
+ base = 10;
+ goto nosign;
+ case 'X':
+ xdigs = xdigs_upper;
+ goto hex;
+ case 'x':
+ xdigs = xdigs_lower;
+hex:
+ if (flags & INTMAX_SIZE)
+ ujval = UJARG();
+ else
+ ulval = UARG();
+ base = 16;
+ /* leading 0x/X only if non-zero */
+ if (flags & ALT &&
+ (flags & INTMAX_SIZE ? ujval != 0 : ulval != 0))
+ ox[1] = ch;
+
+ flags &= ~GROUPING;
+ /* unsigned conversions */
+nosign: sign = '\0';
+ /*-
+ * ``... diouXx conversions ... if a precision is
+ * specified, the 0 flag will be ignored.''
+ * -- ANSI X3J11
+ */
+number: if ((dprec = prec) >= 0)
+ flags &= ~ZEROPAD;
+
+ /*-
+ * ``The result of converting a zero value with an
+ * explicit precision of zero is no characters.''
+ * -- ANSI X3J11
+ *
+ * ``The C Standard is clear enough as is. The call
+ * printf("%#.0o", 0) should print 0.''
+ * -- Defect Report #151
+ */
+ cp = buf + BUF;
+ if (flags & INTMAX_SIZE) {
+ if (ujval != 0 || prec != 0 ||
+ (flags & ALT && base == 8))
+ cp = __ujtoa(ujval, cp, base,
+ flags & ALT, xdigs);
+ } else {
+ if (ulval != 0 || prec != 0 ||
+ (flags & ALT && base == 8))
+ cp = __ultoa(ulval, cp, base,
+ flags & ALT, xdigs);
+ }
+ size = buf + BUF - cp;
+ if (size > BUF) /* should never happen */
+ abort();
+ if ((flags & GROUPING) && size != 0)
+ size += grouping_init(&gs, size, locale);
+ break;
+ default: /* "%?" prints ?, unless ? is NUL */
+ if (ch == '\0')
+ goto done;
+ /* pretend it was %c with argument ch */
+ cp = buf;
+ *cp = ch;
+ size = 1;
+ sign = '\0';
+ break;
+ }
+
+ /*
+ * All reasonable formats wind up here. At this point, `cp'
+ * points to a string which (if not flags&LADJUST) should be
+ * padded out to `width' places. If flags&ZEROPAD, it should
+ * first be prefixed by any sign or other prefix; otherwise,
+ * it should be blank padded before the prefix is emitted.
+ * After any left-hand padding and prefixing, emit zeroes
+ * required by a decimal [diouxX] precision, then print the
+ * string proper, then emit zeroes required by any leftover
+ * floating precision; finally, if LADJUST, pad with blanks.
+ *
+ * Compute actual size, so we know how much to pad.
+ * size excludes decimal prec; realsz includes it.
+ */
+ realsz = dprec > size ? dprec : size;
+ if (sign)
+ realsz++;
+ if (ox[1])
+ realsz += 2;
+
+ prsize = width > realsz ? width : realsz;
+ if ((unsigned)ret + prsize > INT_MAX) {
+ ret = EOF;
+ errno = EOVERFLOW;
+ goto error;
+ }
+
+ /* right-adjusting blank padding */
+ if ((flags & (LADJUST|ZEROPAD)) == 0)
+ PAD(width - realsz, blanks);
+
+ /* prefix */
+ if (sign)
+ PRINT(&sign, 1);
+
+ if (ox[1]) { /* ox[1] is either x, X, or \0 */
+ ox[0] = '0';
+ PRINT(ox, 2);
+ }
+
+ /* right-adjusting zero padding */
+ if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
+ PAD(width - realsz, zeroes);
+
+ /* the string or number proper */
+#ifndef NO_FLOATING_POINT
+ if ((flags & FPT) == 0) {
+#endif
+ /* leading zeroes from decimal precision */
+ PAD(dprec - size, zeroes);
+ if (gs.grouping) {
+ if (grouping_print(&gs, &io, cp, buf+BUF, locale) < 0)
+ goto error;
+ } else {
+ PRINT(cp, size);
+ }
+#ifndef NO_FLOATING_POINT
+ } else { /* glue together f_p fragments */
+ if (!expchar) { /* %[fF] or sufficiently short %[gG] */
+ if (expt <= 0) {
+ PRINT(zeroes, 1);
+ if (prec || flags & ALT)
+ PRINT(&decimal_point, 1);
+ PAD(-expt, zeroes);
+ /* already handled initial 0's */
+ prec += expt;
+ } else {
+ if (gs.grouping) {
+ n = grouping_print(&gs, &io,
+ cp, convbuf + ndig, locale);
+ if (n < 0)
+ goto error;
+ cp += n;
+ } else {
+ PRINTANDPAD(cp, convbuf + ndig,
+ expt, zeroes);
+ cp += expt;
+ }
+ if (prec || flags & ALT)
+ PRINT(&decimal_point, 1);
+ }
+ PRINTANDPAD(cp, convbuf + ndig, prec, zeroes);
+ } else { /* %[eE] or sufficiently long %[gG] */
+ if (prec > 1 || flags & ALT) {
+ buf[0] = *cp++;
+ buf[1] = decimal_point;
+ PRINT(buf, 2);
+ PRINT(cp, ndig-1);
+ PAD(prec - ndig, zeroes);
+ } else /* XeYYY */
+ PRINT(cp, 1);
+ PRINT(expstr, expsize);
+ }
+ }
+#endif
+ /* left-adjusting padding (always blank) */
+ if (flags & LADJUST)
+ PAD(width - realsz, blanks);
+
+ /* finally, adjust ret */
+ ret += prsize;
+
+ FLUSH(); /* copy out the I/O vectors */
+ }
+done:
+ FLUSH();
+error:
+ va_end(orgap);
+ if (convbuf != NULL)
+ free(convbuf);
+ if (__sferror(fp))
+ ret = EOF;
+ else
+ fp->_flags |= savserr;
+ if ((argtable != NULL) && (argtable != statargtable))
+ free (argtable);
+ return (ret);
+ /* NOTREACHED */
+}
diff --git a/lib/libc/stdio/vfwscanf.c b/lib/libc/stdio/vfwscanf.c
new file mode 100644
index 000000000000..63b5dd1be28a
--- /dev/null
+++ b/lib/libc/stdio/vfwscanf.c
@@ -0,0 +1,948 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)vfscanf.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <ctype.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include <string.h>
+#include <wchar.h>
+#include <wctype.h>
+#include "un-namespace.h"
+
+#include "libc_private.h"
+#include "local.h"
+#include "xlocale_private.h"
+
+#define BUF 513 /* Maximum length of numeric string. */
+
+/*
+ * Flags used during conversion.
+ */
+#define LONG 0x01 /* l: long or double */
+#define LONGDBL 0x02 /* L: long double */
+#define SHORT 0x04 /* h: short */
+#define SUPPRESS 0x08 /* *: suppress assignment */
+#define POINTER 0x10 /* p: void * (as hex) */
+#define NOSKIP 0x20 /* [ or c: do not skip blanks */
+#define LONGLONG 0x400 /* ll: long long (+ deprecated q: quad) */
+#define INTMAXT 0x800 /* j: intmax_t */
+#define PTRDIFFT 0x1000 /* t: ptrdiff_t */
+#define SIZET 0x2000 /* z: size_t */
+#define SHORTSHORT 0x4000 /* hh: char */
+#define UNSIGNED 0x8000 /* %[oupxX] conversions */
+
+/*
+ * The following are used in integral conversions only:
+ * SIGNOK, NDIGITS, PFXOK, and NZDIGITS
+ */
+#define SIGNOK 0x40 /* +/- is (still) legal */
+#define NDIGITS 0x80 /* no digits detected */
+#define PFXOK 0x100 /* 0x prefix is (still) legal */
+#define NZDIGITS 0x200 /* no zero digits detected */
+#define HAVESIGN 0x10000 /* sign detected */
+
+/*
+ * Conversion types.
+ */
+#define CT_CHAR 0 /* %c conversion */
+#define CT_CCL 1 /* %[...] conversion */
+#define CT_STRING 2 /* %s conversion */
+#define CT_INT 3 /* %[dioupxX] conversion */
+#define CT_FLOAT 4 /* %[efgEFG] conversion */
+
+#ifndef NO_FLOATING_POINT
+static int parsefloat(FILE *, wchar_t *, wchar_t *, locale_t);
+#endif
+
+struct ccl {
+ const wchar_t *start; /* character class start */
+ const wchar_t *end; /* character class end */
+ int compl; /* ccl is complemented? */
+};
+
+static __inline int
+inccl(const struct ccl *ccl, wint_t wi)
+{
+
+ if (ccl->compl) {
+ return (wmemchr(ccl->start, wi, ccl->end - ccl->start)
+ == NULL);
+ } else {
+ return (wmemchr(ccl->start, wi, ccl->end - ccl->start) != NULL);
+ }
+}
+
+/*
+ * Conversion functions are passed a pointer to this object instead of
+ * a real parameter to indicate that the assignment-suppression (*)
+ * flag was specified. We could use a NULL pointer to indicate this,
+ * but that would mask bugs in applications that call scanf() with a
+ * NULL pointer.
+ */
+static const int suppress;
+#define SUPPRESS_PTR ((void *)&suppress)
+
+static const mbstate_t initial_mbs;
+
+/*
+ * The following conversion functions return the number of characters consumed,
+ * or -1 on input failure. Character class conversion returns 0 on match
+ * failure.
+ */
+
+static __inline int
+convert_char(FILE *fp, char * mbp, int width, locale_t locale)
+{
+ mbstate_t mbs;
+ size_t nconv;
+ wint_t wi;
+ int n;
+
+ n = 0;
+ mbs = initial_mbs;
+ while (width-- != 0 && (wi = __fgetwc(fp, locale)) != WEOF) {
+ if (mbp != SUPPRESS_PTR) {
+ nconv = wcrtomb(mbp, wi, &mbs);
+ if (nconv == (size_t)-1)
+ return (-1);
+ mbp += nconv;
+ }
+ n++;
+ }
+ if (n == 0)
+ return (-1);
+ return (n);
+}
+
+static __inline int
+convert_wchar(FILE *fp, wchar_t *wcp, int width, locale_t locale)
+{
+ wint_t wi;
+ int n;
+
+ n = 0;
+ while (width-- != 0 && (wi = __fgetwc(fp, locale)) != WEOF) {
+ if (wcp != SUPPRESS_PTR)
+ *wcp++ = (wchar_t)wi;
+ n++;
+ }
+ if (n == 0)
+ return (-1);
+ return (n);
+}
+
+static __inline int
+convert_ccl(FILE *fp, char * mbp, int width, const struct ccl *ccl,
+ locale_t locale)
+{
+ mbstate_t mbs;
+ size_t nconv;
+ wint_t wi;
+ int n;
+
+ n = 0;
+ mbs = initial_mbs;
+ while ((wi = __fgetwc(fp, locale)) != WEOF &&
+ width-- != 0 && inccl(ccl, wi)) {
+ if (mbp != SUPPRESS_PTR) {
+ nconv = wcrtomb(mbp, wi, &mbs);
+ if (nconv == (size_t)-1)
+ return (-1);
+ mbp += nconv;
+ }
+ n++;
+ }
+ if (wi != WEOF)
+ __ungetwc(wi, fp, locale);
+ if (mbp != SUPPRESS_PTR)
+ *mbp = 0;
+ return (n);
+}
+
+static __inline int
+convert_wccl(FILE *fp, wchar_t *wcp, int width, const struct ccl *ccl,
+ locale_t locale)
+{
+ wchar_t *wcp0;
+ wint_t wi;
+ int n;
+
+ if (wcp == SUPPRESS_PTR) {
+ n = 0;
+ while ((wi = __fgetwc(fp, locale)) != WEOF &&
+ width-- != 0 && inccl(ccl, wi))
+ n++;
+ if (wi != WEOF)
+ __ungetwc(wi, fp, locale);
+ } else {
+ wcp0 = wcp;
+ while ((wi = __fgetwc(fp, locale)) != WEOF &&
+ width-- != 0 && inccl(ccl, wi))
+ *wcp++ = (wchar_t)wi;
+ if (wi != WEOF)
+ __ungetwc(wi, fp, locale);
+ n = wcp - wcp0;
+ if (n == 0)
+ return (0);
+ *wcp = 0;
+ }
+ return (n);
+}
+
+static __inline int
+convert_string(FILE *fp, char * mbp, int width, locale_t locale)
+{
+ mbstate_t mbs;
+ size_t nconv;
+ wint_t wi;
+ int nread;
+
+ mbs = initial_mbs;
+ nread = 0;
+ while ((wi = __fgetwc(fp, locale)) != WEOF && width-- != 0 &&
+ !iswspace(wi)) {
+ if (mbp != SUPPRESS_PTR) {
+ nconv = wcrtomb(mbp, wi, &mbs);
+ if (nconv == (size_t)-1)
+ return (-1);
+ mbp += nconv;
+ }
+ nread++;
+ }
+ if (wi != WEOF)
+ __ungetwc(wi, fp, locale);
+ if (mbp != SUPPRESS_PTR)
+ *mbp = 0;
+ return (nread);
+}
+
+static __inline int
+convert_wstring(FILE *fp, wchar_t *wcp, int width, locale_t locale)
+{
+ wchar_t *wcp0;
+ wint_t wi;
+ int nread;
+
+ nread = 0;
+ if (wcp == SUPPRESS_PTR) {
+ while ((wi = __fgetwc(fp, locale)) != WEOF &&
+ width-- != 0 && !iswspace(wi))
+ nread++;
+ if (wi != WEOF)
+ __ungetwc(wi, fp, locale);
+ } else {
+ wcp0 = wcp;
+ while ((wi = __fgetwc(fp, locale)) != WEOF &&
+ width-- != 0 && !iswspace(wi)) {
+ *wcp++ = (wchar_t)wi;
+ nread++;
+ }
+ if (wi != WEOF)
+ __ungetwc(wi, fp, locale);
+ *wcp = '\0';
+ }
+ return (nread);
+}
+
+/*
+ * Read an integer, storing it in buf. The only relevant bit in the
+ * flags argument is PFXOK.
+ *
+ * Return 0 on a match failure, and the number of characters read
+ * otherwise.
+ */
+static __inline int
+parseint(FILE *fp, wchar_t *buf, int width, int base, int flags,
+ locale_t locale)
+{
+ /* `basefix' is used to avoid `if' tests */
+ static const short basefix[17] =
+ { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
+ wchar_t *wcp;
+ int c;
+
+ flags |= SIGNOK | NDIGITS | NZDIGITS;
+ for (wcp = buf; width; width--) {
+ c = __fgetwc(fp, locale);
+ /*
+ * Switch on the character; `goto ok' if we accept it
+ * as a part of number.
+ */
+ switch (c) {
+
+ /*
+ * The digit 0 is always legal, but is special. For
+ * %i conversions, if no digits (zero or nonzero) have
+ * been scanned (only signs), we will have base==0.
+ * In that case, we should set it to 8 and enable 0x
+ * prefixing. Also, if we have not scanned zero
+ * digits before this, do not turn off prefixing
+ * (someone else will turn it off if we have scanned
+ * any nonzero digits).
+ */
+ case '0':
+ if (base == 0) {
+ base = 8;
+ flags |= PFXOK;
+ }
+ if (flags & NZDIGITS)
+ flags &= ~(SIGNOK|NZDIGITS|NDIGITS);
+ else
+ flags &= ~(SIGNOK|PFXOK|NDIGITS);
+ goto ok;
+
+ /* 1 through 7 always legal */
+ case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ base = basefix[base];
+ flags &= ~(SIGNOK | PFXOK | NDIGITS);
+ goto ok;
+
+ /* digits 8 and 9 ok iff decimal or hex */
+ case '8': case '9':
+ base = basefix[base];
+ if (base <= 8)
+ break; /* not legal here */
+ flags &= ~(SIGNOK | PFXOK | NDIGITS);
+ goto ok;
+
+ /* letters ok iff hex */
+ case 'A': case 'B': case 'C':
+ case 'D': case 'E': case 'F':
+ case 'a': case 'b': case 'c':
+ case 'd': case 'e': case 'f':
+ /* no need to fix base here */
+ if (base <= 10)
+ break; /* not legal here */
+ flags &= ~(SIGNOK | PFXOK | NDIGITS);
+ goto ok;
+
+ /* sign ok only as first character */
+ case '+': case '-':
+ if (flags & SIGNOK) {
+ flags &= ~SIGNOK;
+ flags |= HAVESIGN;
+ goto ok;
+ }
+ break;
+
+ /*
+ * x ok iff flag still set & 2nd char (or 3rd char if
+ * we have a sign).
+ */
+ case 'x': case 'X':
+ if (flags & PFXOK && wcp ==
+ buf + 1 + !!(flags & HAVESIGN)) {
+ base = 16; /* if %i */
+ flags &= ~PFXOK;
+ goto ok;
+ }
+ break;
+ }
+
+ /*
+ * If we got here, c is not a legal character for a
+ * number. Stop accumulating digits.
+ */
+ if (c != WEOF)
+ __ungetwc(c, fp, locale);
+ break;
+ ok:
+ /*
+ * c is legal: store it and look at the next.
+ */
+ *wcp++ = (wchar_t)c;
+ }
+ /*
+ * If we had only a sign, it is no good; push back the sign.
+ * If the number ends in `x', it was [sign] '0' 'x', so push
+ * back the x and treat it as [sign] '0'.
+ */
+ if (flags & NDIGITS) {
+ if (wcp > buf)
+ __ungetwc(*--wcp, fp, locale);
+ return (0);
+ }
+ c = wcp[-1];
+ if (c == 'x' || c == 'X') {
+ --wcp;
+ __ungetwc(c, fp, locale);
+ }
+ return (wcp - buf);
+}
+
+/*
+ * MT-safe version.
+ */
+int
+vfwscanf_l(FILE * __restrict fp, locale_t locale,
+ const wchar_t * __restrict fmt, va_list ap)
+{
+ int ret;
+ FIX_LOCALE(locale);
+
+ FLOCKFILE(fp);
+ ORIENT(fp, 1);
+ ret = __vfwscanf(fp, locale, fmt, ap);
+ FUNLOCKFILE(fp);
+ return (ret);
+}
+int
+vfwscanf(FILE * __restrict fp, const wchar_t * __restrict fmt, va_list ap)
+{
+ return vfwscanf_l(fp, __get_locale(), fmt, ap);
+}
+
+/*
+ * Non-MT-safe version.
+ */
+int
+__vfwscanf(FILE * __restrict fp, locale_t locale,
+ const wchar_t * __restrict fmt, va_list ap)
+{
+#define GETARG(type) ((flags & SUPPRESS) ? SUPPRESS_PTR : va_arg(ap, type))
+ wint_t c; /* character from format, or conversion */
+ size_t width; /* field width, or 0 */
+ int flags; /* flags as defined above */
+ int nassigned; /* number of fields assigned */
+ int nconversions; /* number of conversions */
+ int nr; /* characters read by the current conversion */
+ int nread; /* number of characters consumed from fp */
+ int base; /* base argument to conversion function */
+ struct ccl ccl; /* character class info */
+ wchar_t buf[BUF]; /* buffer for numeric conversions */
+ wint_t wi; /* handy wint_t */
+
+ nassigned = 0;
+ nconversions = 0;
+ nread = 0;
+ ccl.start = ccl.end = NULL;
+ for (;;) {
+ c = *fmt++;
+ if (c == 0)
+ return (nassigned);
+ if (iswspace(c)) {
+ while ((c = __fgetwc(fp, locale)) != WEOF &&
+ iswspace_l(c, locale))
+ nread++;
+ if (c != WEOF)
+ __ungetwc(c, fp, locale);
+ continue;
+ }
+ if (c != '%')
+ goto literal;
+ width = 0;
+ flags = 0;
+ /*
+ * switch on the format. continue if done;
+ * break once format type is derived.
+ */
+again: c = *fmt++;
+ switch (c) {
+ case '%':
+literal:
+ if ((wi = __fgetwc(fp, locale)) == WEOF)
+ goto input_failure;
+ if (wi != c) {
+ __ungetwc(wi, fp, locale);
+ goto input_failure;
+ }
+ nread++;
+ continue;
+
+ case '*':
+ flags |= SUPPRESS;
+ goto again;
+ case 'j':
+ flags |= INTMAXT;
+ goto again;
+ case 'l':
+ if (flags & LONG) {
+ flags &= ~LONG;
+ flags |= LONGLONG;
+ } else
+ flags |= LONG;
+ goto again;
+ case 'q':
+ flags |= LONGLONG; /* not quite */
+ goto again;
+ case 't':
+ flags |= PTRDIFFT;
+ goto again;
+ case 'z':
+ flags |= SIZET;
+ goto again;
+ case 'L':
+ flags |= LONGDBL;
+ goto again;
+ case 'h':
+ if (flags & SHORT) {
+ flags &= ~SHORT;
+ flags |= SHORTSHORT;
+ } else
+ flags |= SHORT;
+ goto again;
+
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ width = width * 10 + c - '0';
+ goto again;
+
+ /*
+ * Conversions.
+ */
+ case 'd':
+ c = CT_INT;
+ base = 10;
+ break;
+
+ case 'i':
+ c = CT_INT;
+ base = 0;
+ break;
+
+ case 'o':
+ c = CT_INT;
+ flags |= UNSIGNED;
+ base = 8;
+ break;
+
+ case 'u':
+ c = CT_INT;
+ flags |= UNSIGNED;
+ base = 10;
+ break;
+
+ case 'X':
+ case 'x':
+ flags |= PFXOK; /* enable 0x prefixing */
+ c = CT_INT;
+ flags |= UNSIGNED;
+ base = 16;
+ break;
+
+#ifndef NO_FLOATING_POINT
+ case 'A': case 'E': case 'F': case 'G':
+ case 'a': case 'e': case 'f': case 'g':
+ c = CT_FLOAT;
+ break;
+#endif
+
+ case 'S':
+ flags |= LONG;
+ /* FALLTHROUGH */
+ case 's':
+ c = CT_STRING;
+ break;
+
+ case '[':
+ ccl.start = fmt;
+ if (*fmt == '^') {
+ ccl.compl = 1;
+ fmt++;
+ } else
+ ccl.compl = 0;
+ if (*fmt == ']')
+ fmt++;
+ while (*fmt != '\0' && *fmt != ']')
+ fmt++;
+ ccl.end = fmt;
+ fmt++;
+ flags |= NOSKIP;
+ c = CT_CCL;
+ break;
+
+ case 'C':
+ flags |= LONG;
+ /* FALLTHROUGH */
+ case 'c':
+ flags |= NOSKIP;
+ c = CT_CHAR;
+ break;
+
+ case 'p': /* pointer format is like hex */
+ flags |= POINTER | PFXOK;
+ c = CT_INT; /* assumes sizeof(uintmax_t) */
+ flags |= UNSIGNED; /* >= sizeof(uintptr_t) */
+ base = 16;
+ break;
+
+ case 'n':
+ if (flags & SUPPRESS) /* ??? */
+ continue;
+ if (flags & SHORTSHORT)
+ *va_arg(ap, char *) = nread;
+ else if (flags & SHORT)
+ *va_arg(ap, short *) = nread;
+ else if (flags & LONG)
+ *va_arg(ap, long *) = nread;
+ else if (flags & LONGLONG)
+ *va_arg(ap, long long *) = nread;
+ else if (flags & INTMAXT)
+ *va_arg(ap, intmax_t *) = nread;
+ else if (flags & SIZET)
+ *va_arg(ap, size_t *) = nread;
+ else if (flags & PTRDIFFT)
+ *va_arg(ap, ptrdiff_t *) = nread;
+ else
+ *va_arg(ap, int *) = nread;
+ continue;
+
+ default:
+ goto match_failure;
+
+ /*
+ * Disgusting backwards compatibility hack. XXX
+ */
+ case '\0': /* compat */
+ return (EOF);
+ }
+
+ /*
+ * Consume leading white space, except for formats
+ * that suppress this.
+ */
+ if ((flags & NOSKIP) == 0) {
+ while ((wi = __fgetwc(fp, locale)) != WEOF && iswspace(wi))
+ nread++;
+ if (wi == WEOF)
+ goto input_failure;
+ __ungetwc(wi, fp, locale);
+ }
+
+ /*
+ * Do the conversion.
+ */
+ switch (c) {
+
+ case CT_CHAR:
+ /* scan arbitrary characters (sets NOSKIP) */
+ if (width == 0)
+ width = 1;
+ if (flags & LONG) {
+ nr = convert_wchar(fp, GETARG(wchar_t *), width,
+ locale);
+ } else {
+ nr = convert_char(fp, GETARG(char *), width,
+ locale);
+ }
+ if (nr < 0)
+ goto input_failure;
+ break;
+
+ case CT_CCL:
+ /* scan a (nonempty) character class (sets NOSKIP) */
+ if (width == 0)
+ width = (size_t)~0; /* `infinity' */
+ /* take only those things in the class */
+ if (flags & LONG) {
+ nr = convert_wccl(fp, GETARG(wchar_t *), width,
+ &ccl, locale);
+ } else {
+ nr = convert_ccl(fp, GETARG(char *), width,
+ &ccl, locale);
+ }
+ if (nr <= 0) {
+ if (nr < 0)
+ goto input_failure;
+ else /* nr == 0 */
+ goto match_failure;
+ }
+ break;
+
+ case CT_STRING:
+ /* like CCL, but zero-length string OK, & no NOSKIP */
+ if (width == 0)
+ width = (size_t)~0;
+ if (flags & LONG) {
+ nr = convert_wstring(fp, GETARG(wchar_t *),
+ width, locale);
+ } else {
+ nr = convert_string(fp, GETARG(char *), width,
+ locale);
+ }
+ if (nr < 0)
+ goto input_failure;
+ break;
+
+ case CT_INT:
+ /* scan an integer as if by the conversion function */
+ if (width == 0 || width > sizeof(buf) /
+ sizeof(*buf) - 1)
+ width = sizeof(buf) / sizeof(*buf) - 1;
+
+ nr = parseint(fp, buf, width, base, flags, locale);
+ if (nr == 0)
+ goto match_failure;
+ if ((flags & SUPPRESS) == 0) {
+ uintmax_t res;
+
+ buf[nr] = L'\0';
+ if ((flags & UNSIGNED) == 0)
+ res = wcstoimax(buf, NULL, base);
+ else
+ res = wcstoumax(buf, NULL, base);
+ if (flags & POINTER)
+ *va_arg(ap, void **) =
+ (void *)(uintptr_t)res;
+ else if (flags & SHORTSHORT)
+ *va_arg(ap, char *) = res;
+ else if (flags & SHORT)
+ *va_arg(ap, short *) = res;
+ else if (flags & LONG)
+ *va_arg(ap, long *) = res;
+ else if (flags & LONGLONG)
+ *va_arg(ap, long long *) = res;
+ else if (flags & INTMAXT)
+ *va_arg(ap, intmax_t *) = res;
+ else if (flags & PTRDIFFT)
+ *va_arg(ap, ptrdiff_t *) = res;
+ else if (flags & SIZET)
+ *va_arg(ap, size_t *) = res;
+ else
+ *va_arg(ap, int *) = res;
+ }
+ break;
+
+#ifndef NO_FLOATING_POINT
+ case CT_FLOAT:
+ /* scan a floating point number as if by strtod */
+ if (width == 0 || width > sizeof(buf) /
+ sizeof(*buf) - 1)
+ width = sizeof(buf) / sizeof(*buf) - 1;
+ nr = parsefloat(fp, buf, buf + width, locale);
+ if (nr == 0)
+ goto match_failure;
+ if ((flags & SUPPRESS) == 0) {
+ if (flags & LONGDBL) {
+ long double res = wcstold(buf, NULL);
+ *va_arg(ap, long double *) = res;
+ } else if (flags & LONG) {
+ double res = wcstod(buf, NULL);
+ *va_arg(ap, double *) = res;
+ } else {
+ float res = wcstof(buf, NULL);
+ *va_arg(ap, float *) = res;
+ }
+ }
+ break;
+#endif /* !NO_FLOATING_POINT */
+ }
+ if (!(flags & SUPPRESS))
+ nassigned++;
+ nread += nr;
+ nconversions++;
+ }
+input_failure:
+ return (nconversions != 0 ? nassigned : EOF);
+match_failure:
+ return (nassigned);
+}
+
+#ifndef NO_FLOATING_POINT
+static int
+parsefloat(FILE *fp, wchar_t *buf, wchar_t *end, locale_t locale)
+{
+ mbstate_t mbs;
+ size_t nconv;
+ wchar_t *commit, *p;
+ int infnanpos = 0;
+ enum {
+ S_START, S_GOTSIGN, S_INF, S_NAN, S_DONE, S_MAYBEHEX,
+ S_DIGITS, S_FRAC, S_EXP, S_EXPDIGITS
+ } state = S_START;
+ wchar_t c;
+ wchar_t decpt;
+ _Bool gotmantdig = 0, ishex = 0;
+
+ mbs = initial_mbs;
+ nconv = mbrtowc(&decpt, localeconv()->decimal_point, MB_CUR_MAX, &mbs);
+ if (nconv == (size_t)-1 || nconv == (size_t)-2)
+ decpt = '.'; /* failsafe */
+
+ /*
+ * We set commit = p whenever the string we have read so far
+ * constitutes a valid representation of a floating point
+ * number by itself. At some point, the parse will complete
+ * or fail, and we will ungetc() back to the last commit point.
+ * To ensure that the file offset gets updated properly, it is
+ * always necessary to read at least one character that doesn't
+ * match; thus, we can't short-circuit "infinity" or "nan(...)".
+ */
+ commit = buf - 1;
+ c = WEOF;
+ for (p = buf; p < end; ) {
+ if ((c = __fgetwc(fp, locale)) == WEOF)
+ break;
+reswitch:
+ switch (state) {
+ case S_START:
+ state = S_GOTSIGN;
+ if (c == '-' || c == '+')
+ break;
+ else
+ goto reswitch;
+ case S_GOTSIGN:
+ switch (c) {
+ case '0':
+ state = S_MAYBEHEX;
+ commit = p;
+ break;
+ case 'I':
+ case 'i':
+ state = S_INF;
+ break;
+ case 'N':
+ case 'n':
+ state = S_NAN;
+ break;
+ default:
+ state = S_DIGITS;
+ goto reswitch;
+ }
+ break;
+ case S_INF:
+ if (infnanpos > 6 ||
+ (c != "nfinity"[infnanpos] &&
+ c != "NFINITY"[infnanpos]))
+ goto parsedone;
+ if (infnanpos == 1 || infnanpos == 6)
+ commit = p; /* inf or infinity */
+ infnanpos++;
+ break;
+ case S_NAN:
+ switch (infnanpos) {
+ case 0:
+ if (c != 'A' && c != 'a')
+ goto parsedone;
+ break;
+ case 1:
+ if (c != 'N' && c != 'n')
+ goto parsedone;
+ else
+ commit = p;
+ break;
+ case 2:
+ if (c != '(')
+ goto parsedone;
+ break;
+ default:
+ if (c == ')') {
+ commit = p;
+ state = S_DONE;
+ } else if (!iswalnum(c) && c != '_')
+ goto parsedone;
+ break;
+ }
+ infnanpos++;
+ break;
+ case S_DONE:
+ goto parsedone;
+ case S_MAYBEHEX:
+ state = S_DIGITS;
+ if (c == 'X' || c == 'x') {
+ ishex = 1;
+ break;
+ } else { /* we saw a '0', but no 'x' */
+ gotmantdig = 1;
+ goto reswitch;
+ }
+ case S_DIGITS:
+ if ((ishex && iswxdigit(c)) || iswdigit(c))
+ gotmantdig = 1;
+ else {
+ state = S_FRAC;
+ if (c != decpt)
+ goto reswitch;
+ }
+ if (gotmantdig)
+ commit = p;
+ break;
+ case S_FRAC:
+ if (((c == 'E' || c == 'e') && !ishex) ||
+ ((c == 'P' || c == 'p') && ishex)) {
+ if (!gotmantdig)
+ goto parsedone;
+ else
+ state = S_EXP;
+ } else if ((ishex && iswxdigit(c)) || iswdigit(c)) {
+ commit = p;
+ gotmantdig = 1;
+ } else
+ goto parsedone;
+ break;
+ case S_EXP:
+ state = S_EXPDIGITS;
+ if (c == '-' || c == '+')
+ break;
+ else
+ goto reswitch;
+ case S_EXPDIGITS:
+ if (iswdigit(c))
+ commit = p;
+ else
+ goto parsedone;
+ break;
+ default:
+ abort();
+ }
+ *p++ = c;
+ c = WEOF;
+ }
+
+parsedone:
+ if (c != WEOF)
+ __ungetwc(c, fp, locale);
+ while (commit < --p)
+ __ungetwc(*p, fp, locale);
+ *++commit = '\0';
+ return (commit - buf);
+}
+#endif
diff --git a/lib/libc/stdio/vprintf.c b/lib/libc/stdio/vprintf.c
new file mode 100644
index 000000000000..f98f1107c872
--- /dev/null
+++ b/lib/libc/stdio/vprintf.c
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)vprintf.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <xlocale.h>
+
+int
+vprintf(const char * __restrict fmt, __va_list ap)
+{
+ return (vfprintf(stdout, fmt, ap));
+}
+int
+vprintf_l(locale_t locale, const char * __restrict fmt, __va_list ap)
+{
+ return (vfprintf_l(stdout, locale, fmt, ap));
+}
diff --git a/lib/libc/stdio/vscanf.c b/lib/libc/stdio/vscanf.c
new file mode 100644
index 000000000000..8729c9ca6ba8
--- /dev/null
+++ b/lib/libc/stdio/vscanf.c
@@ -0,0 +1,66 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Donn Seeley at UUNET Technologies, Inc.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)vscanf.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <stdio.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+#include "local.h"
+#include "xlocale_private.h"
+
+int
+vscanf_l(locale_t locale, const char * __restrict fmt, __va_list ap)
+{
+ int retval;
+ FIX_LOCALE(locale);
+
+ FLOCKFILE(stdin);
+ retval = __svfscanf(stdin, locale, fmt, ap);
+ FUNLOCKFILE(stdin);
+ return (retval);
+}
+int
+vscanf(const char * __restrict fmt, __va_list ap)
+{
+ return vscanf_l(__get_locale(), fmt, ap);
+}
diff --git a/lib/libc/stdio/vsnprintf.c b/lib/libc/stdio/vsnprintf.c
new file mode 100644
index 000000000000..8d13a5041cd3
--- /dev/null
+++ b/lib/libc/stdio/vsnprintf.c
@@ -0,0 +1,88 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)vsnprintf.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include "local.h"
+#include "xlocale_private.h"
+
+int
+vsnprintf_l(char * __restrict str, size_t n, locale_t locale,
+ const char * __restrict fmt, __va_list ap)
+{
+ size_t on;
+ int ret;
+ char dummy[2];
+ FILE f = FAKE_FILE;
+ FIX_LOCALE(locale);
+
+ on = n;
+ if (n != 0)
+ n--;
+ if (n > INT_MAX) {
+ errno = EOVERFLOW;
+ *str = '\0';
+ return (EOF);
+ }
+ /* Stdio internals do not deal correctly with zero length buffer */
+ if (n == 0) {
+ if (on > 0)
+ *str = '\0';
+ str = dummy;
+ n = 1;
+ }
+ f._flags = __SWR | __SSTR;
+ f._bf._base = f._p = (unsigned char *)str;
+ f._bf._size = f._w = n;
+ ret = __vfprintf(&f, locale, fmt, ap);
+ if (on > 0)
+ *f._p = '\0';
+ return (ret);
+}
+int
+vsnprintf(char * __restrict str, size_t n, const char * __restrict fmt,
+ __va_list ap)
+{
+ return vsnprintf_l(str, n, __get_locale(), fmt, ap);
+}
diff --git a/lib/libc/stdio/vsprintf.c b/lib/libc/stdio/vsprintf.c
new file mode 100644
index 000000000000..906a74c24b38
--- /dev/null
+++ b/lib/libc/stdio/vsprintf.c
@@ -0,0 +1,68 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)vsprintf.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <limits.h>
+#include "local.h"
+#include "xlocale_private.h"
+
+int
+vsprintf_l(char * __restrict str, locale_t locale,
+ const char * __restrict fmt, __va_list ap)
+{
+ int ret;
+ FILE f = FAKE_FILE;
+ FIX_LOCALE(locale);
+
+ f._flags = __SWR | __SSTR;
+ f._bf._base = f._p = (unsigned char *)str;
+ f._bf._size = f._w = INT_MAX;
+ ret = __vfprintf(&f, locale, fmt, ap);
+ *f._p = 0;
+ return (ret);
+}
+int
+vsprintf(char * __restrict str, const char * __restrict fmt, __va_list ap)
+{
+ return vsprintf_l(str, __get_locale(), fmt, ap);
+}
diff --git a/lib/libc/stdio/vsscanf.c b/lib/libc/stdio/vsscanf.c
new file mode 100644
index 000000000000..4328fc15bfad
--- /dev/null
+++ b/lib/libc/stdio/vsscanf.c
@@ -0,0 +1,78 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Donn Seeley at UUNET Technologies, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)vsscanf.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <string.h>
+#include "local.h"
+#include "xlocale_private.h"
+
+static int
+eofread(void *, char *, int);
+
+/* ARGSUSED */
+static int
+eofread(void *cookie, char *buf, int len)
+{
+
+ return (0);
+}
+
+int
+vsscanf_l(const char * __restrict str, locale_t locale,
+ const char * __restrict fmt, __va_list ap)
+{
+ FILE f = FAKE_FILE;
+ FIX_LOCALE(locale);
+
+ f._flags = __SRD;
+ f._bf._base = f._p = (unsigned char *)str;
+ f._bf._size = f._r = strlen(str);
+ f._read = eofread;
+ return (__svfscanf(&f, locale, fmt, ap));
+}
+int
+vsscanf(const char * __restrict str, const char * __restrict fmt,
+ __va_list ap)
+{
+ return vsscanf_l(str, __get_locale(), fmt, ap);
+}
diff --git a/lib/libc/stdio/vswprintf.c b/lib/libc/stdio/vswprintf.c
new file mode 100644
index 000000000000..2585888cfbca
--- /dev/null
+++ b/lib/libc/stdio/vswprintf.c
@@ -0,0 +1,114 @@
+/* $OpenBSD: vasprintf.c,v 1.4 1998/06/21 22:13:47 millert Exp $ */
+
+/*
+ * Copyright (c) 1997 Todd C. Miller <Todd.Miller@courtesan.com>
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#if 0
+__FBSDID("FreeBSD: src/lib/libc/stdio/vasprintf.c,v 1.16 2002/08/21 16:19:57 mike Exp ");
+#endif
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include "local.h"
+#include "xlocale_private.h"
+
+int
+vswprintf_l(wchar_t * __restrict s, size_t n, locale_t locale,
+ const wchar_t * __restrict fmt, __va_list ap)
+{
+ static const mbstate_t initial;
+ mbstate_t mbs;
+ FILE f = FAKE_FILE;
+ char *mbp;
+ int ret, sverrno;
+ size_t nwc;
+ FIX_LOCALE(locale);
+
+ if (n == 0) {
+ errno = EINVAL;
+ return (-1);
+ }
+ if (n - 1 > INT_MAX) {
+ errno = EOVERFLOW;
+ *s = L'\0';
+ return (-1);
+ }
+
+ f._flags = __SWR | __SSTR | __SALC;
+ f._bf._base = f._p = (unsigned char *)malloc(128);
+ if (f._bf._base == NULL) {
+ errno = ENOMEM;
+ *s = L'\0';
+ return (-1);
+ }
+ f._bf._size = f._w = 127; /* Leave room for the NUL */
+ ret = __vfwprintf(&f, locale, fmt, ap);
+ if (ret < 0) {
+ sverrno = errno;
+ free(f._bf._base);
+ errno = sverrno;
+ *s = L'\0';
+ return (-1);
+ }
+ *f._p = '\0';
+ mbp = f._bf._base;
+ /*
+ * XXX Undo the conversion from wide characters to multibyte that
+ * fputwc() did in __vfwprintf().
+ */
+ mbs = initial;
+ nwc = mbsrtowcs_l(s, (const char **)&mbp, n, &mbs, locale);
+ free(f._bf._base);
+ if (nwc == (size_t)-1) {
+ errno = EILSEQ;
+ *s = L'\0';
+ return (-1);
+ }
+ if (nwc == n) {
+ s[n - 1] = L'\0';
+ errno = EOVERFLOW;
+ return (-1);
+ }
+
+ return (ret);
+}
+int
+vswprintf(wchar_t * __restrict s, size_t n, const wchar_t * __restrict fmt,
+ __va_list ap)
+{
+ return vswprintf_l(s, n, __get_locale(), fmt, ap);
+}
diff --git a/lib/libc/stdio/vswscanf.c b/lib/libc/stdio/vswscanf.c
new file mode 100644
index 000000000000..c4a10379c2fc
--- /dev/null
+++ b/lib/libc/stdio/vswscanf.c
@@ -0,0 +1,104 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Donn Seeley at UUNET Technologies, Inc.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#if 0
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)vsscanf.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+__FBSDID("FreeBSD: src/lib/libc/stdio/vsscanf.c,v 1.11 2002/08/21 16:19:57 mike Exp ");
+#endif
+__FBSDID("$FreeBSD$");
+
+#include <limits.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include "local.h"
+#include "xlocale_private.h"
+
+static int eofread(void *, char *, int);
+
+static int
+eofread(void *cookie, char *buf, int len)
+{
+
+ return (0);
+}
+
+int
+vswscanf_l(const wchar_t * __restrict str, locale_t locale,
+ const wchar_t * __restrict fmt, va_list ap)
+{
+ static const mbstate_t initial;
+ mbstate_t mbs;
+ FILE f = FAKE_FILE;
+ char *mbstr;
+ size_t mlen;
+ int r;
+ const wchar_t *strp;
+ FIX_LOCALE(locale);
+
+ /*
+ * XXX Convert the wide character string to multibyte, which
+ * __vfwscanf() will convert back to wide characters.
+ */
+ if ((mbstr = malloc(wcslen(str) * MB_CUR_MAX + 1)) == NULL)
+ return (EOF);
+ mbs = initial;
+ strp = str;
+ if ((mlen = wcsrtombs_l(mbstr, &strp, SIZE_T_MAX, &mbs, locale)) == (size_t)-1) {
+ free(mbstr);
+ return (EOF);
+ }
+ f._flags = __SRD;
+ f._bf._base = f._p = (unsigned char *)mbstr;
+ f._bf._size = f._r = mlen;
+ f._read = eofread;
+ r = __vfwscanf(&f, locale, fmt, ap);
+ free(mbstr);
+
+ return (r);
+}
+int
+vswscanf(const wchar_t * __restrict str, const wchar_t * __restrict fmt,
+ va_list ap)
+{
+ return vswscanf_l(str, __get_locale(), fmt, ap);
+}
diff --git a/lib/libc/stdio/vwprintf.c b/lib/libc/stdio/vwprintf.c
new file mode 100644
index 000000000000..e09a30eccca5
--- /dev/null
+++ b/lib/libc/stdio/vwprintf.c
@@ -0,0 +1,49 @@
+/*-
+ * Copyright (c) 2002 Tim J. Robbins
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 <stdarg.h>
+#include <stdio.h>
+#include <wchar.h>
+#include <xlocale.h>
+
+int
+vwprintf(const wchar_t * __restrict fmt, va_list ap)
+{
+ return (vfwprintf(stdout, fmt, ap));
+}
+int
+vwprintf_l(locale_t locale, const wchar_t * __restrict fmt, va_list ap)
+{
+ return (vfwprintf_l(stdout, locale, fmt, ap));
+}
diff --git a/lib/libc/stdio/vwscanf.c b/lib/libc/stdio/vwscanf.c
new file mode 100644
index 000000000000..730beeef7f20
--- /dev/null
+++ b/lib/libc/stdio/vwscanf.c
@@ -0,0 +1,49 @@
+/*-
+ * Copyright (c) 2002 Tim J. Robbins
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 <stdarg.h>
+#include <stdio.h>
+#include <wchar.h>
+#include <xlocale.h>
+
+int
+vwscanf(const wchar_t * __restrict fmt, va_list ap)
+{
+ return (vfwscanf(stdin, fmt, ap));
+}
+int
+vwscanf_l(locale_t locale, const wchar_t * __restrict fmt, va_list ap)
+{
+ return (vfwscanf_l(stdin, locale, fmt, ap));
+}
diff --git a/lib/libc/stdio/wbuf.c b/lib/libc/stdio/wbuf.c
new file mode 100644
index 000000000000..5bc3c4dc3e77
--- /dev/null
+++ b/lib/libc/stdio/wbuf.c
@@ -0,0 +1,92 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)wbuf.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <stdio.h>
+#include "local.h"
+
+/*
+ * Write the given character into the (probably full) buffer for
+ * the given file. Flush the buffer out if it is or becomes full,
+ * or if c=='\n' and the file is line buffered.
+ *
+ * Non-MT-safe
+ */
+int
+__swbuf(int c, FILE *fp)
+{
+ int n;
+
+ /*
+ * In case we cannot write, or longjmp takes us out early,
+ * make sure _w is 0 (if fully- or un-buffered) or -_bf._size
+ * (if line buffered) so that we will get called again.
+ * If we did not do this, a sufficient number of putc()
+ * calls might wrap _w from negative to positive.
+ */
+ fp->_w = fp->_lbfsize;
+ if (prepwrite(fp) != 0) {
+ errno = EBADF;
+ return (EOF);
+ }
+ c = (unsigned char)c;
+
+ ORIENT(fp, -1);
+
+ /*
+ * If it is completely full, flush it out. Then, in any case,
+ * stuff c into the buffer. If this causes the buffer to fill
+ * completely, or if c is '\n' and the file is line buffered,
+ * flush it (perhaps a second time). The second flush will always
+ * happen on unbuffered streams, where _bf._size==1; fflush()
+ * guarantees that putc() will always call wbuf() by setting _w
+ * to 0, so we need not do anything else.
+ */
+ n = fp->_p - fp->_bf._base;
+ if (n >= fp->_bf._size) {
+ if (__fflush(fp))
+ return (EOF);
+ n = 0;
+ }
+ fp->_w--;
+ *fp->_p++ = c;
+ if (++n == fp->_bf._size || (fp->_flags & __SLBF && c == '\n'))
+ if (__fflush(fp))
+ return (EOF);
+ return (c);
+}
diff --git a/lib/libc/stdio/wprintf.3 b/lib/libc/stdio/wprintf.3
new file mode 100644
index 000000000000..fecb5867b164
--- /dev/null
+++ b/lib/libc/stdio/wprintf.3
@@ -0,0 +1,618 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek and the American National Standards Committee X3,
+.\" on Information Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)printf.3 8.1 (Berkeley) 6/4/93
+.\" FreeBSD: src/lib/libc/stdio/printf.3,v 1.47 2002/09/06 11:23:55 tjr Exp
+.\" $FreeBSD$
+.\"
+.Dd July 5, 2003
+.Dt WPRINTF 3
+.Os
+.Sh NAME
+.Nm wprintf , fwprintf , swprintf ,
+.Nm vwprintf , vfwprintf , vswprintf
+.Nd formatted wide character output conversion
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdio.h
+.In wchar.h
+.Ft int
+.Fn fwprintf "FILE * restrict stream" "const wchar_t * restrict format" ...
+.Ft int
+.Fn swprintf "wchar_t * restrict ws" "size_t n" "const wchar_t * restrict format" ...
+.Ft int
+.Fn wprintf "const wchar_t * restrict format" ...
+.In stdarg.h
+.Ft int
+.Fn vfwprintf "FILE * restrict stream" "const wchar_t * restrict" "va_list ap"
+.Ft int
+.Fn vswprintf "wchar_t * restrict ws" "size_t n" "const wchar_t *restrict format" "va_list ap"
+.Ft int
+.Fn vwprintf "const wchar_t * restrict format" "va_list ap"
+.Sh DESCRIPTION
+The
+.Fn wprintf
+family of functions produces output according to a
+.Fa format
+as described below.
+The
+.Fn wprintf
+and
+.Fn vwprintf
+functions
+write output to
+.Dv stdout ,
+the standard output stream;
+.Fn fwprintf
+and
+.Fn vfwprintf
+write output to the given output
+.Fa stream ;
+.Fn swprintf
+and
+.Fn vswprintf
+write to the wide character string
+.Fa ws .
+.Pp
+These functions write the output under the control of a
+.Fa format
+string that specifies how subsequent arguments
+(or arguments accessed via the variable-length argument facilities of
+.Xr stdarg 3 )
+are converted for output.
+.Pp
+These functions return the number of characters printed
+(not including the trailing
+.Ql \e0
+used to end output to strings).
+.Pp
+The
+.Fn swprintf
+and
+.Fn vswprintf
+functions will fail if
+.Fa n
+or more wide characters were requested to be written,
+.Pp
+The format string is composed of zero or more directives:
+ordinary
+characters (not
+.Cm % ) ,
+which are copied unchanged to the output stream;
+and conversion specifications, each of which results
+in fetching zero or more subsequent arguments.
+Each conversion specification is introduced by
+the
+.Cm %
+character.
+The arguments must correspond properly (after type promotion)
+with the conversion specifier.
+After the
+.Cm % ,
+the following appear in sequence:
+.Bl -bullet
+.It
+An optional field, consisting of a decimal digit string followed by a
+.Cm $ ,
+specifying the next argument to access.
+If this field is not provided, the argument following the last
+argument accessed will be used.
+Arguments are numbered starting at
+.Cm 1 .
+If unaccessed arguments in the format string are interspersed with ones that
+are accessed the results will be indeterminate.
+.It
+Zero or more of the following flags:
+.Bl -tag -width ".So \ Sc (space)"
+.It Sq Cm #
+The value should be converted to an
+.Dq alternate form .
+For
+.Cm c , d , i , n , p , s ,
+and
+.Cm u
+conversions, this option has no effect.
+For
+.Cm o
+conversions, the precision of the number is increased to force the first
+character of the output string to a zero (except if a zero value is printed
+with an explicit precision of zero).
+For
+.Cm x
+and
+.Cm X
+conversions, a non-zero result has the string
+.Ql 0x
+(or
+.Ql 0X
+for
+.Cm X
+conversions) prepended to it.
+For
+.Cm a , A , e , E , f , F , g ,
+and
+.Cm G
+conversions, the result will always contain a decimal point, even if no
+digits follow it (normally, a decimal point appears in the results of
+those conversions only if a digit follows).
+For
+.Cm g
+and
+.Cm G
+conversions, trailing zeros are not removed from the result as they
+would otherwise be.
+.It So Cm 0 Sc (zero)
+Zero padding.
+For all conversions except
+.Cm n ,
+the converted value is padded on the left with zeros rather than blanks.
+If a precision is given with a numeric conversion
+.Cm ( d , i , o , u , i , x ,
+and
+.Cm X ) ,
+the
+.Cm 0
+flag is ignored.
+.It Sq Cm \-
+A negative field width flag;
+the converted value is to be left adjusted on the field boundary.
+Except for
+.Cm n
+conversions, the converted value is padded on the right with blanks,
+rather than on the left with blanks or zeros.
+A
+.Cm \-
+overrides a
+.Cm 0
+if both are given.
+.It So "\ " Sc (space)
+A blank should be left before a positive number
+produced by a signed conversion
+.Cm ( a , A , d , e , E , f , F , g , G ,
+or
+.Cm i ) .
+.It Sq Cm +
+A sign must always be placed before a
+number produced by a signed conversion.
+A
+.Cm +
+overrides a space if both are used.
+.It Sq Cm '
+Decimal conversions
+.Cm ( d , u ,
+or
+.Cm i )
+or the integral portion of a floating point conversion
+.Cm ( f
+or
+.Cm F )
+should be grouped and separated by thousands using
+the non-monetary separator returned by
+.Xr localeconv 3 .
+.El
+.It
+An optional decimal digit string specifying a minimum field width.
+If the converted value has fewer characters than the field width, it will
+be padded with spaces on the left (or right, if the left-adjustment
+flag has been given) to fill out
+the field width.
+.It
+An optional precision, in the form of a period
+.Cm \&.
+followed by an
+optional digit string.
+If the digit string is omitted, the precision is taken as zero.
+This gives the minimum number of digits to appear for
+.Cm d , i , o , u , x ,
+and
+.Cm X
+conversions, the number of digits to appear after the decimal-point for
+.Cm a , A , e , E , f ,
+and
+.Cm F
+conversions, the maximum number of significant digits for
+.Cm g
+and
+.Cm G
+conversions, or the maximum number of characters to be printed from a
+string for
+.Cm s
+conversions.
+.It
+An optional length modifier, that specifies the size of the argument.
+The following length modifiers are valid for the
+.Cm d , i , n , o , u , x ,
+or
+.Cm X
+conversion:
+.Bl -column ".Cm q Em (deprecated)" ".Vt signed char" ".Vt unsigned long long" ".Vt long long *"
+.It Sy Modifier Ta Cm d , i Ta Cm o , u , x , X Ta Cm n
+.It Cm hh Ta Vt "signed char" Ta Vt "unsigned char" Ta Vt "signed char *"
+.It Cm h Ta Vt short Ta Vt "unsigned short" Ta Vt "short *"
+.It Cm l No (ell) Ta Vt long Ta Vt "unsigned long" Ta Vt "long *"
+.It Cm ll No (ell ell) Ta Vt "long long" Ta Vt "unsigned long long" Ta Vt "long long *"
+.It Cm j Ta Vt intmax_t Ta Vt uintmax_t Ta Vt "intmax_t *"
+.It Cm t Ta Vt ptrdiff_t Ta (see note) Ta Vt "ptrdiff_t *"
+.It Cm z Ta (see note) Ta Vt size_t Ta (see note)
+.It Cm q Em (deprecated) Ta Vt quad_t Ta Vt u_quad_t Ta Vt "quad_t *"
+.El
+.Pp
+Note:
+the
+.Cm t
+modifier, when applied to a
+.Cm o , u , x ,
+or
+.Cm X
+conversion, indicates that the argument is of an unsigned type
+equivalent in size to a
+.Vt ptrdiff_t .
+The
+.Cm z
+modifier, when applied to a
+.Cm d
+or
+.Cm i
+conversion, indicates that the argument is of a signed type equivalent in
+size to a
+.Vt size_t .
+Similarly, when applied to an
+.Cm n
+conversion, it indicates that the argument is a pointer to a signed type
+equivalent in size to a
+.Vt size_t .
+.Pp
+The following length modifier is valid for the
+.Cm a , A , e , E , f , F , g ,
+or
+.Cm G
+conversion:
+.Bl -column ".Sy Modifier" ".Cm a , A , e , E , f , F , g , G"
+.It Sy Modifier Ta Cm a , A , e , E , f , F , g , G
+.It Cm L Ta Vt "long double"
+.El
+.Pp
+The following length modifier is valid for the
+.Cm c
+or
+.Cm s
+conversion:
+.Bl -column ".Sy Modifier" ".Vt wint_t" ".Vt wchar_t *"
+.It Sy Modifier Ta Cm c Ta Cm s
+.It Cm l No (ell) Ta Vt wint_t Ta Vt "wchar_t *"
+.El
+.It
+A character that specifies the type of conversion to be applied.
+.El
+.Pp
+A field width or precision, or both, may be indicated by
+an asterisk
+.Ql *
+or an asterisk followed by one or more decimal digits and a
+.Ql $
+instead of a
+digit string.
+In this case, an
+.Vt int
+argument supplies the field width or precision.
+A negative field width is treated as a left adjustment flag followed by a
+positive field width; a negative precision is treated as though it were
+missing.
+If a single format directive mixes positional
+.Pq Li nn$
+and non-positional arguments, the results are undefined.
+.Pp
+The conversion specifiers and their meanings are:
+.Bl -tag -width ".Cm diouxX"
+.It Cm diouxX
+The
+.Vt int
+(or appropriate variant) argument is converted to signed decimal
+.Cm ( d
+and
+.Cm i ) ,
+unsigned octal
+.Pq Cm o ,
+unsigned decimal
+.Pq Cm u ,
+or unsigned hexadecimal
+.Cm ( x
+and
+.Cm X )
+notation.
+The letters
+.Dq Li abcdef
+are used for
+.Cm x
+conversions; the letters
+.Dq Li ABCDEF
+are used for
+.Cm X
+conversions.
+The precision, if any, gives the minimum number of digits that must
+appear; if the converted value requires fewer digits, it is padded on
+the left with zeros.
+.It Cm DOU
+The
+.Vt "long int"
+argument is converted to signed decimal, unsigned octal, or unsigned
+decimal, as if the format had been
+.Cm ld , lo ,
+or
+.Cm lu
+respectively.
+These conversion characters are deprecated, and will eventually disappear.
+.It Cm eE
+The
+.Vt double
+argument is rounded and converted in the style
+.Sm off
+.Oo \- Oc Ar d Li \&. Ar ddd Li e \(+- Ar dd
+.Sm on
+where there is one digit before the
+decimal-point character
+and the number of digits after it is equal to the precision;
+if the precision is missing,
+it is taken as 6; if the precision is
+zero, no decimal-point character appears.
+An
+.Cm E
+conversion uses the letter
+.Ql E
+(rather than
+.Ql e )
+to introduce the exponent.
+The exponent always contains at least two digits; if the value is zero,
+the exponent is 00.
+.Pp
+For
+.Cm a , A , e , E , f , F , g ,
+and
+.Cm G
+conversions, positive and negative infinity are represented as
+.Li inf
+and
+.Li -inf
+respectively when using the lowercase conversion character, and
+.Li INF
+and
+.Li -INF
+respectively when using the uppercase conversion character.
+Similarly, NaN is represented as
+.Li nan
+when using the lowercase conversion, and
+.Li NAN
+when using the uppercase conversion.
+.It Cm fF
+The
+.Vt double
+argument is rounded and converted to decimal notation in the style
+.Sm off
+.Oo \- Oc Ar ddd Li \&. Ar ddd ,
+.Sm on
+where the number of digits after the decimal-point character
+is equal to the precision specification.
+If the precision is missing, it is taken as 6; if the precision is
+explicitly zero, no decimal-point character appears.
+If a decimal point appears, at least one digit appears before it.
+.It Cm gG
+The
+.Vt double
+argument is converted in style
+.Cm f
+or
+.Cm e
+(or
+.Cm F
+or
+.Cm E
+for
+.Cm G
+conversions).
+The precision specifies the number of significant digits.
+If the precision is missing, 6 digits are given; if the precision is zero,
+it is treated as 1.
+Style
+.Cm e
+is used if the exponent from its conversion is less than \-4 or greater than
+or equal to the precision.
+Trailing zeros are removed from the fractional part of the result; a
+decimal point appears only if it is followed by at least one digit.
+.It Cm aA
+The
+.Vt double
+argument is converted to hexadecimal notation in the style
+.Sm off
+.Oo \- Oc Li 0x Ar h Li \&. Ar hhhp Oo \(+- Oc Ar d ,
+.Sm on
+where the number of digits after the hexadecimal-point character
+is equal to the precision specification.
+If the precision is missing, it is taken as enough to exactly
+represent the floating-point number; if the precision is
+explicitly zero, no hexadecimal-point character appears.
+This is an exact conversion of the mantissa+exponent internal
+floating point representation; the
+.Sm off
+.Oo \- Oc Li 0x Ar h Li \&. Ar hhh
+.Sm on
+portion represents exactly the mantissa; only denormalized
+mantissas have a zero value to the left of the hexadecimal
+point.
+The
+.Cm p
+is a literal character
+.Ql p ;
+the exponent is preceded by a positive or negative sign
+and is represented in decimal, using only enough characters
+to represent the exponent.
+The
+.Cm A
+conversion uses the prefix
+.Dq Li 0X
+(rather than
+.Dq Li 0x ) ,
+the letters
+.Dq Li ABCDEF
+(rather than
+.Dq Li abcdef )
+to represent the hex digits, and the letter
+.Ql P
+(rather than
+.Ql p )
+to separate the mantissa and exponent.
+.It Cm C
+Treated as
+.Cm c
+with the
+.Cm l
+(ell) modifier.
+.It Cm c
+The
+.Vt int
+argument is converted to an
+.Vt "unsigned char" ,
+then to a
+.Vt wchar_t
+as if by
+.Xr btowc 3 ,
+and the resulting character is written.
+.Pp
+If the
+.Cm l
+(ell) modifier is used, the
+.Vt wint_t
+argument is converted to a
+.Vt wchar_t
+and written.
+.It Cm S
+Treated as
+.Cm s
+with the
+.Cm l
+(ell) modifier.
+.It Cm s
+The
+.Vt "char *"
+argument is expected to be a pointer to an array of character type (pointer
+to a string) containing a multibyte sequence.
+Characters from the array are converted to wide characters and written up to
+(but not including)
+a terminating
+.Dv NUL
+character;
+if a precision is specified, no more than the number specified are
+written.
+If a precision is given, no null character
+need be present; if the precision is not specified, or is greater than
+the size of the array, the array must contain a terminating
+.Dv NUL
+character.
+.Pp
+If the
+.Cm l
+(ell) modifier is used, the
+.Vt "wchar_t *"
+argument is expected to be a pointer to an array of wide characters
+(pointer to a wide string).
+Each wide character in the string
+is written.
+Wide characters from the array are written up to (but not including)
+a terminating wide
+.Dv NUL
+character;
+if a precision is specified, no more than the number specified are
+written (including shift sequences).
+If a precision is given, no null character
+need be present; if the precision is not specified, or is greater than
+the number of characters in
+the string, the array must contain a terminating wide
+.Dv NUL
+character.
+.It Cm p
+The
+.Vt "void *"
+pointer argument is printed in hexadecimal (as if by
+.Ql %#x
+or
+.Ql %#lx ) .
+.It Cm n
+The number of characters written so far is stored into the
+integer indicated by the
+.Vt "int *"
+(or variant) pointer argument.
+No argument is converted.
+.It Cm %
+A
+.Ql %
+is written.
+No argument is converted.
+The complete conversion specification
+is
+.Ql %% .
+.El
+.Pp
+The decimal point
+character is defined in the program's locale (category
+.Dv LC_NUMERIC ) .
+.Pp
+In no case does a non-existent or small field width cause truncation of
+a numeric field; if the result of a conversion is wider than the field
+width, the
+field is expanded to contain the conversion result.
+.Sh SEE ALSO
+.Xr btowc 3 ,
+.Xr fputws 3 ,
+.Xr printf 3 ,
+.Xr putwc 3 ,
+.Xr setlocale 3 ,
+.Xr wcsrtombs 3 ,
+.Xr wscanf 3
+.Sh STANDARDS
+Subject to the caveats noted in the
+.Sx BUGS
+section
+of
+.Xr printf 3 ,
+the
+.Fn wprintf ,
+.Fn fwprintf ,
+.Fn swprintf ,
+.Fn vwprintf ,
+.Fn vfwprintf
+and
+.Fn vswprintf
+functions
+conform to
+.St -isoC-99 .
+.Sh SECURITY CONSIDERATIONS
+Refer to
+.Xr printf 3 .
diff --git a/lib/libc/stdio/wprintf.c b/lib/libc/stdio/wprintf.c
new file mode 100644
index 000000000000..fdffa8614634
--- /dev/null
+++ b/lib/libc/stdio/wprintf.c
@@ -0,0 +1,63 @@
+/*-
+ * Copyright (c) 2002 Tim J. Robbins
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 <stdarg.h>
+#include <stdio.h>
+#include <wchar.h>
+#include <xlocale.h>
+
+int
+wprintf(const wchar_t * __restrict fmt, ...)
+{
+ int ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ ret = vfwprintf(stdout, fmt, ap);
+ va_end(ap);
+
+ return (ret);
+}
+int
+wprintf_l(locale_t locale, const wchar_t * __restrict fmt, ...)
+{
+ int ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ ret = vfwprintf_l(stdout, locale, fmt, ap);
+ va_end(ap);
+
+ return (ret);
+}
diff --git a/lib/libc/stdio/wscanf.3 b/lib/libc/stdio/wscanf.3
new file mode 100644
index 000000000000..1dda777f1b5d
--- /dev/null
+++ b/lib/libc/stdio/wscanf.3
@@ -0,0 +1,479 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek and the American National Standards Committee X3,
+.\" on Information Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)scanf.3 8.2 (Berkeley) 12/11/93
+.\" FreeBSD: src/lib/libc/stdio/scanf.3,v 1.24 2003/06/28 09:03:25 das Exp
+.\" $FreeBSD$
+.\"
+.Dd July 5, 2003
+.Dt WSCANF 3
+.Os
+.Sh NAME
+.Nm wscanf ,
+.Nm fwscanf ,
+.Nm swscanf ,
+.Nm vwscanf ,
+.Nm vswscanf ,
+.Nm vfwscanf
+.Nd wide character input format conversion
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdio.h
+.In wchar.h
+.Ft int
+.Fn wscanf "const wchar_t * restrict format" ...
+.Ft int
+.Fn fwscanf "FILE * restrict stream" "const wchar_t * restrict format" ...
+.Ft int
+.Fn swscanf "const wchar_t * restrict str" "const wchar_t * restrict format" ...
+.In stdarg.h
+.Ft int
+.Fn vwscanf "const wchar_t * restrict format" "va_list ap"
+.Ft int
+.Fn vswscanf "const wchar_t * restrict str" "const wchar_t * restrict format" "va_list ap"
+.Ft int
+.Fn vfwscanf "FILE * restrict stream" "const wchar_t * restrict format" "va_list ap"
+.Sh DESCRIPTION
+The
+.Fn wscanf
+family of functions scans input according to a
+.Fa format
+as described below.
+This format may contain
+.Em conversion specifiers ;
+the results from such conversions, if any,
+are stored through the
+.Em pointer
+arguments.
+The
+.Fn wscanf
+function
+reads input from the standard input stream
+.Dv stdin ,
+.Fn fwscanf
+reads input from the stream pointer
+.Fa stream ,
+and
+.Fn swscanf
+reads its input from the wide character string pointed to by
+.Fa str .
+The
+.Fn vfwscanf
+function
+is analogous to
+.Xr vfwprintf 3
+and reads input from the stream pointer
+.Fa stream
+using a variable argument list of pointers (see
+.Xr stdarg 3 ) .
+The
+.Fn vwscanf
+function scans a variable argument list from the standard input and
+the
+.Fn vswscanf
+function scans it from a wide character string;
+these are analogous to
+the
+.Fn vwprintf
+and
+.Fn vswprintf
+functions respectively.
+Each successive
+.Em pointer
+argument must correspond properly with
+each successive conversion specifier
+(but see the
+.Cm *
+conversion below).
+All conversions are introduced by the
+.Cm %
+(percent sign) character.
+The
+.Fa format
+string
+may also contain other characters.
+White space (such as blanks, tabs, or newlines) in the
+.Fa format
+string match any amount of white space, including none, in the input.
+Everything else
+matches only itself.
+Scanning stops
+when an input character does not match such a format character.
+Scanning also stops
+when an input conversion cannot be made (see below).
+.Sh CONVERSIONS
+Following the
+.Cm %
+character introducing a conversion
+there may be a number of
+.Em flag
+characters, as follows:
+.Bl -tag -width ".Cm l No (ell)"
+.It Cm *
+Suppresses assignment.
+The conversion that follows occurs as usual, but no pointer is used;
+the result of the conversion is simply discarded.
+.It Cm hh
+Indicates that the conversion will be one of
+.Cm dioux
+or
+.Cm n
+and the next pointer is a pointer to a
+.Vt char
+(rather than
+.Vt int ) .
+.It Cm h
+Indicates that the conversion will be one of
+.Cm dioux
+or
+.Cm n
+and the next pointer is a pointer to a
+.Vt "short int"
+(rather than
+.Vt int ) .
+.It Cm l No (ell)
+Indicates that the conversion will be one of
+.Cm dioux
+or
+.Cm n
+and the next pointer is a pointer to a
+.Vt "long int"
+(rather than
+.Vt int ) ,
+that the conversion will be one of
+.Cm a , e , f ,
+or
+.Cm g
+and the next pointer is a pointer to
+.Vt double
+(rather than
+.Vt float ) ,
+or that the conversion will be one of
+.Cm c
+or
+.Cm s
+and the next pointer is a pointer to an array of
+.Vt wchar_t
+(rather than
+.Vt char ) .
+.It Cm ll No (ell ell)
+Indicates that the conversion will be one of
+.Cm dioux
+or
+.Cm n
+and the next pointer is a pointer to a
+.Vt "long long int"
+(rather than
+.Vt int ) .
+.It Cm L
+Indicates that the conversion will be one of
+.Cm a , e , f ,
+or
+.Cm g
+and the next pointer is a pointer to
+.Vt "long double" .
+.It Cm j
+Indicates that the conversion will be one of
+.Cm dioux
+or
+.Cm n
+and the next pointer is a pointer to a
+.Vt intmax_t
+(rather than
+.Vt int ) .
+.It Cm t
+Indicates that the conversion will be one of
+.Cm dioux
+or
+.Cm n
+and the next pointer is a pointer to a
+.Vt ptrdiff_t
+(rather than
+.Vt int ) .
+.It Cm z
+Indicates that the conversion will be one of
+.Cm dioux
+or
+.Cm n
+and the next pointer is a pointer to a
+.Vt size_t
+(rather than
+.Vt int ) .
+.It Cm q
+(deprecated.)
+Indicates that the conversion will be one of
+.Cm dioux
+or
+.Cm n
+and the next pointer is a pointer to a
+.Vt "long long int"
+(rather than
+.Vt int ) .
+.El
+.Pp
+In addition to these flags,
+there may be an optional maximum field width,
+expressed as a decimal integer,
+between the
+.Cm %
+and the conversion.
+If no width is given,
+a default of
+.Dq infinity
+is used (with one exception, below);
+otherwise at most this many characters are scanned
+in processing the conversion.
+Before conversion begins,
+most conversions skip white space;
+this white space is not counted against the field width.
+.Pp
+The following conversions are available:
+.Bl -tag -width XXXX
+.It Cm %
+Matches a literal
+.Ql % .
+That is,
+.Dq Li %%
+in the format string
+matches a single input
+.Ql %
+character.
+No conversion is done, and assignment does not occur.
+.It Cm d
+Matches an optionally signed decimal integer;
+the next pointer must be a pointer to
+.Vt int .
+.It Cm i
+Matches an optionally signed integer;
+the next pointer must be a pointer to
+.Vt int .
+The integer is read in base 16 if it begins
+with
+.Ql 0x
+or
+.Ql 0X ,
+in base 8 if it begins with
+.Ql 0 ,
+and in base 10 otherwise.
+Only characters that correspond to the base are used.
+.It Cm o
+Matches an octal integer;
+the next pointer must be a pointer to
+.Vt "unsigned int" .
+.It Cm u
+Matches an optionally signed decimal integer;
+the next pointer must be a pointer to
+.Vt "unsigned int" .
+.It Cm x , X
+Matches an optionally signed hexadecimal integer;
+the next pointer must be a pointer to
+.Vt "unsigned int" .
+.It Cm a , A , e , E , f , F , g , G
+Matches a floating-point number in the style of
+.Xr wcstod 3 .
+The next pointer must be a pointer to
+.Vt float
+(unless
+.Cm l
+or
+.Cm L
+is specified.)
+.It Cm s
+Matches a sequence of non-white-space wide characters;
+the next pointer must be a pointer to
+.Vt char ,
+and the array must be large enough to accept the multibyte representation
+of all the sequence and the
+terminating
+.Dv NUL
+character.
+The input string stops at white space
+or at the maximum field width, whichever occurs first.
+.Pp
+If an
+.Cm l
+qualifier is present, the next pointer must be a pointer to
+.Vt wchar_t ,
+into which the input will be placed.
+.It Cm S
+The same as
+.Cm ls .
+.It Cm c
+Matches a sequence of
+.Em width
+count
+wide characters (default 1);
+the next pointer must be a pointer to
+.Vt char ,
+and there must be enough room for the multibyte representation
+of all the characters
+(no terminating
+.Dv NUL
+is added).
+The usual skip of leading white space is suppressed.
+To skip white space first, use an explicit space in the format.
+.Pp
+If an
+.Cm l
+qualifier is present, the next pointer must be a pointer to
+.Vt wchar_t ,
+into which the input will be placed.
+.It Cm C
+The same as
+.Cm lc .
+.It Cm \&[
+Matches a nonempty sequence of characters from the specified set
+of accepted characters;
+the next pointer must be a pointer to
+.Vt char ,
+and there must be enough room for the multibyte representation of
+all the characters in the string,
+plus a terminating
+.Dv NUL
+character.
+The usual skip of leading white space is suppressed.
+The string is to be made up of characters in
+(or not in)
+a particular set;
+the set is defined by the characters between the open bracket
+.Cm \&[
+character
+and a close bracket
+.Cm \&]
+character.
+The set
+.Em excludes
+those characters
+if the first character after the open bracket is a circumflex
+.Cm ^ .
+To include a close bracket in the set,
+make it the first character after the open bracket
+or the circumflex;
+any other position will end the set.
+To include a hyphen in the set,
+make it the last character before the final close bracket;
+some implementations of
+.Fn wscanf
+use
+.Dq Li A-Z
+to represent the range of characters between
+.Ql A
+and
+.Ql Z .
+The string ends with the appearance of a character not in the
+(or, with a circumflex, in) set
+or when the field width runs out.
+.Pp
+If an
+.Cm l
+qualifier is present, the next pointer must be a pointer to
+.Vt wchar_t ,
+into which the input will be placed.
+.It Cm p
+Matches a pointer value (as printed by
+.Ql %p
+in
+.Xr wprintf 3 ) ;
+the next pointer must be a pointer to
+.Vt void .
+.It Cm n
+Nothing is expected;
+instead, the number of characters consumed thus far from the input
+is stored through the next pointer,
+which must be a pointer to
+.Vt int .
+This is
+.Em not
+a conversion, although it can be suppressed with the
+.Cm *
+flag.
+.El
+.Pp
+The decimal point
+character is defined in the program's locale (category
+.Dv LC_NUMERIC ) .
+.Pp
+For backwards compatibility, a
+.Dq conversion
+of
+.Ql %\e0
+causes an immediate return of
+.Dv EOF .
+.Sh RETURN VALUES
+These
+functions
+return
+the number of input items assigned, which can be fewer than provided
+for, or even zero, in the event of a matching failure.
+Zero
+indicates that, while there was input available,
+no conversions were assigned;
+typically this is due to an invalid input character,
+such as an alphabetic character for a
+.Ql %d
+conversion.
+The value
+.Dv EOF
+is returned if an input failure occurs before any conversion such as an
+end-of-file occurs.
+If an error or end-of-file occurs after conversion
+has begun,
+the number of conversions which were successfully completed is returned.
+.Sh SEE ALSO
+.Xr fgetwc 3 ,
+.Xr scanf 3 ,
+.Xr wcrtomb 3 ,
+.Xr wcstod 3 ,
+.Xr wcstol 3 ,
+.Xr wcstoul 3 ,
+.Xr wprintf 3
+.Sh STANDARDS
+The
+.Fn fwscanf ,
+.Fn wscanf ,
+.Fn swscanf ,
+.Fn vfwscanf ,
+.Fn vwscanf
+and
+.Fn vswscanf
+functions
+conform to
+.St -isoC-99 .
+.Sh BUGS
+In addition to the bugs documented in
+.Xr scanf 3 ,
+.Fn wscanf
+does not support the
+.Dq Li A-Z
+notation for specifying character ranges with the character
+class conversion
+.Pq Sq Cm %[ .
diff --git a/lib/libc/stdio/wscanf.c b/lib/libc/stdio/wscanf.c
new file mode 100644
index 000000000000..22ce9bd1f89b
--- /dev/null
+++ b/lib/libc/stdio/wscanf.c
@@ -0,0 +1,63 @@
+/*-
+ * Copyright (c) 2002 Tim J. Robbins
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 <stdarg.h>
+#include <stdio.h>
+#include <wchar.h>
+#include <xlocale.h>
+
+int
+wscanf(const wchar_t * __restrict fmt, ...)
+{
+ va_list ap;
+ int r;
+
+ va_start(ap, fmt);
+ r = vfwscanf(stdin, fmt, ap);
+ va_end(ap);
+
+ return (r);
+}
+int
+wscanf_l(locale_t locale, const wchar_t * __restrict fmt, ...)
+{
+ va_list ap;
+ int r;
+
+ va_start(ap, fmt);
+ r = vfwscanf_l(stdin, locale, fmt, ap);
+ va_end(ap);
+
+ return (r);
+}
diff --git a/lib/libc/stdio/wsetup.c b/lib/libc/stdio/wsetup.c
new file mode 100644
index 000000000000..70f8247c076b
--- /dev/null
+++ b/lib/libc/stdio/wsetup.c
@@ -0,0 +1,92 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)wsetup.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "local.h"
+
+/*
+ * Various output routines call wsetup to be sure it is safe to write,
+ * because either _flags does not include __SWR, or _buf is NULL.
+ * _wsetup returns 0 if OK to write; otherwise, it returns EOF and sets errno.
+ */
+int
+__swsetup(FILE *fp)
+{
+ /* make sure stdio is set up */
+ if (!__sdidinit)
+ __sinit();
+
+ /*
+ * If we are not writing, we had better be reading and writing.
+ */
+ if ((fp->_flags & __SWR) == 0) {
+ if ((fp->_flags & __SRW) == 0) {
+ errno = EBADF;
+ fp->_flags |= __SERR;
+ return (EOF);
+ }
+ if (fp->_flags & __SRD) {
+ /* clobber any ungetc data */
+ if (HASUB(fp))
+ FREEUB(fp);
+ fp->_flags &= ~(__SRD|__SEOF);
+ fp->_r = 0;
+ fp->_p = fp->_bf._base;
+ }
+ fp->_flags |= __SWR;
+ }
+
+ /*
+ * Make a buffer if necessary, then set _w.
+ */
+ if (fp->_bf._base == NULL)
+ __smakebuf(fp);
+ if (fp->_flags & __SLBF) {
+ /*
+ * It is line buffered, so make _lbfsize be -_bufsize
+ * for the putc() macro. We will change _lbfsize back
+ * to 0 whenever we turn off __SWR.
+ */
+ fp->_w = 0;
+ fp->_lbfsize = -fp->_bf._size;
+ } else
+ fp->_w = fp->_flags & __SNBF ? 0 : fp->_bf._size;
+ return (0);
+}
diff --git a/lib/libc/stdio/xprintf.c b/lib/libc/stdio/xprintf.c
new file mode 100644
index 000000000000..b00b4cb3e430
--- /dev/null
+++ b/lib/libc/stdio/xprintf.c
@@ -0,0 +1,690 @@
+/*-
+ * Copyright (c) 2005 Poul-Henning Kamp
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include "namespace.h"
+#include <err.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <locale.h>
+#include <stdint.h>
+#include <assert.h>
+#include <stdarg.h>
+#include <namespace.h>
+#include <string.h>
+#include <wchar.h>
+#include "un-namespace.h"
+
+#include "local.h"
+#include "printf.h"
+#include "fvwrite.h"
+
+int __use_xprintf = -1;
+
+/* private stuff -----------------------------------------------------*/
+
+union arg {
+ int intarg;
+ long longarg;
+ intmax_t intmaxarg;
+#ifndef NO_FLOATING_POINT
+ double doublearg;
+ long double longdoublearg;
+#endif
+ wint_t wintarg;
+ char *pchararg;
+ wchar_t *pwchararg;
+ void *pvoidarg;
+};
+
+/*
+ * Macros for converting digits to letters and vice versa
+ */
+#define to_digit(c) ((c) - '0')
+#define is_digit(c) (((unsigned)to_digit(c)) <= 9)
+
+/* various globals ---------------------------------------------------*/
+
+const char __lowercase_hex[17] = "0123456789abcdef?"; /*lint !e784 */
+const char __uppercase_hex[17] = "0123456789ABCDEF?"; /*lint !e784 */
+
+#define PADSIZE 16
+static char blanks[PADSIZE] =
+ {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
+static char zeroes[PADSIZE] =
+ {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
+
+/* printing and padding functions ------------------------------------*/
+
+#define NIOV 8
+
+struct __printf_io {
+ FILE *fp;
+ struct __suio uio;
+ struct __siov iov[NIOV];
+ struct __siov *iovp;
+};
+
+static void
+__printf_init(struct __printf_io *io)
+{
+
+ io->uio.uio_iov = io->iovp = &io->iov[0];
+ io->uio.uio_resid = 0;
+ io->uio.uio_iovcnt = 0;
+}
+
+void
+__printf_flush(struct __printf_io *io)
+{
+
+ __sfvwrite(io->fp, &io->uio);
+ __printf_init(io);
+}
+
+int
+__printf_puts(struct __printf_io *io, const void *ptr, int len)
+{
+
+
+ if (io->fp->_flags & __SERR)
+ return (0);
+ if (len == 0)
+ return (0);
+ io->iovp->iov_base = __DECONST(void *, ptr);
+ io->iovp->iov_len = len;
+ io->uio.uio_resid += len;
+ io->iovp++;
+ io->uio.uio_iovcnt++;
+ if (io->uio.uio_iovcnt >= NIOV)
+ __printf_flush(io);
+ return (len);
+}
+
+int
+__printf_pad(struct __printf_io *io, int howmany, int zero)
+{
+ int n;
+ const char *with;
+ int ret = 0;
+
+ if (zero)
+ with = zeroes;
+ else
+ with = blanks;
+
+ if ((n = (howmany)) > 0) {
+ while (n > PADSIZE) {
+ ret += __printf_puts(io, with, PADSIZE);
+ n -= PADSIZE;
+ }
+ ret += __printf_puts(io, with, n);
+ }
+ return (ret);
+}
+
+int
+__printf_out(struct __printf_io *io, const struct printf_info *pi, const void *ptr, int len)
+{
+ int ret = 0;
+
+ if ((!pi->left) && pi->width > len)
+ ret += __printf_pad(io, pi->width - len, pi->pad == '0');
+ ret += __printf_puts(io, ptr, len);
+ if (pi->left && pi->width > len)
+ ret += __printf_pad(io, pi->width - len, pi->pad == '0');
+ return (ret);
+}
+
+
+/* percent handling -------------------------------------------------*/
+
+static int
+__printf_arginfo_pct(const struct printf_info *pi __unused, size_t n __unused, int *argt __unused)
+{
+
+ return (0);
+}
+
+static int
+__printf_render_pct(struct __printf_io *io, const struct printf_info *pi __unused, const void *const *arg __unused)
+{
+
+ return (__printf_puts(io, "%", 1));
+}
+
+/* 'n' ---------------------------------------------------------------*/
+
+static int
+__printf_arginfo_n(const struct printf_info *pi, size_t n, int *argt)
+{
+
+ assert(n >= 1);
+ argt[0] = PA_POINTER;
+ return (1);
+}
+
+/*
+ * This is a printf_render so that all output has been flushed before it
+ * gets called.
+ */
+
+static int
+__printf_render_n(FILE *io __unused, const struct printf_info *pi, const void *const *arg)
+{
+
+ if (pi->is_char)
+ **((signed char **)arg[0]) = (signed char)pi->sofar;
+ else if (pi->is_short)
+ **((short **)arg[0]) = (short)pi->sofar;
+ else if (pi->is_long)
+ **((long **)arg[0]) = pi->sofar;
+ else if (pi->is_long_double)
+ **((long long **)arg[0]) = pi->sofar;
+ else if (pi->is_intmax)
+ **((intmax_t **)arg[0]) = pi->sofar;
+ else if (pi->is_ptrdiff)
+ **((ptrdiff_t **)arg[0]) = pi->sofar;
+ else if (pi->is_quad)
+ **((quad_t **)arg[0]) = pi->sofar;
+ else if (pi->is_size)
+ **((size_t **)arg[0]) = pi->sofar;
+ else
+ **((int **)arg[0]) = pi->sofar;
+
+ return (0);
+}
+
+/* table -------------------------------------------------------------*/
+
+/*lint -esym(785, printf_tbl) */
+static struct {
+ printf_arginfo_function *arginfo;
+ printf_function *gnurender;
+ printf_render *render;
+} printf_tbl[256] = {
+ ['%'] = { __printf_arginfo_pct, NULL, __printf_render_pct },
+ ['A'] = { __printf_arginfo_float, NULL, __printf_render_float },
+ ['C'] = { __printf_arginfo_chr, NULL, __printf_render_chr },
+ ['E'] = { __printf_arginfo_float, NULL, __printf_render_float },
+ ['F'] = { __printf_arginfo_float, NULL, __printf_render_float },
+ ['G'] = { __printf_arginfo_float, NULL, __printf_render_float },
+ ['S'] = { __printf_arginfo_str, NULL, __printf_render_str },
+ ['X'] = { __printf_arginfo_int, NULL, __printf_render_int },
+ ['a'] = { __printf_arginfo_float, NULL, __printf_render_float },
+ ['c'] = { __printf_arginfo_chr, NULL, __printf_render_chr },
+ ['d'] = { __printf_arginfo_int, NULL, __printf_render_int },
+ ['e'] = { __printf_arginfo_float, NULL, __printf_render_float },
+ ['f'] = { __printf_arginfo_float, NULL, __printf_render_float },
+ ['g'] = { __printf_arginfo_float, NULL, __printf_render_float },
+ ['i'] = { __printf_arginfo_int, NULL, __printf_render_int },
+ ['n'] = { __printf_arginfo_n, __printf_render_n, NULL },
+ ['o'] = { __printf_arginfo_int, NULL, __printf_render_int },
+ ['p'] = { __printf_arginfo_ptr, NULL, __printf_render_ptr },
+ ['q'] = { __printf_arginfo_int, NULL, __printf_render_int },
+ ['s'] = { __printf_arginfo_str, NULL, __printf_render_str },
+ ['u'] = { __printf_arginfo_int, NULL, __printf_render_int },
+ ['x'] = { __printf_arginfo_int, NULL, __printf_render_int },
+};
+
+
+static int
+__v2printf(FILE *fp, const char *fmt0, unsigned pct, va_list ap)
+{
+ struct printf_info *pi, *pil;
+ const char *fmt;
+ int ch;
+ struct printf_info pia[pct + 10];
+ int argt[pct + 10];
+ union arg args[pct + 10];
+ int nextarg;
+ int maxarg;
+ int ret = 0;
+ int n;
+ struct __printf_io io;
+
+ __printf_init(&io);
+ io.fp = fp;
+
+ fmt = fmt0;
+ maxarg = 0;
+ nextarg = 1;
+ memset(argt, 0, sizeof argt);
+ for (pi = pia; ; pi++) {
+ memset(pi, 0, sizeof *pi);
+ pil = pi;
+ if (*fmt == '\0')
+ break;
+ pil = pi + 1;
+ pi->prec = -1;
+ pi->pad = ' ';
+ pi->begin = pi->end = fmt;
+ while (*fmt != '\0' && *fmt != '%')
+ pi->end = ++fmt;
+ if (*fmt == '\0')
+ break;
+ fmt++;
+ for (;;) {
+ pi->spec = *fmt;
+ switch (pi->spec) {
+ case ' ':
+ /*-
+ * ``If the space and + flags both appear, the space
+ * flag will be ignored.''
+ * -- ANSI X3J11
+ */
+ if (pi->showsign == 0)
+ pi->showsign = ' ';
+ fmt++;
+ continue;
+ case '#':
+ pi->alt = 1;
+ fmt++;
+ continue;
+ case '.':
+ pi->prec = 0;
+ fmt++;
+ if (*fmt == '*') {
+ fmt++;
+ pi->get_prec = nextarg;
+ argt[nextarg++] = PA_INT;
+ continue;
+ }
+ while (*fmt != '\0' && is_digit(*fmt)) {
+ pi->prec *= 10;
+ pi->prec += to_digit(*fmt);
+ fmt++;
+ }
+ continue;
+ case '-':
+ pi->left = 1;
+ fmt++;
+ continue;
+ case '+':
+ pi->showsign = '+';
+ fmt++;
+ continue;
+ case '*':
+ fmt++;
+ pi->get_width = nextarg;
+ argt[nextarg++] = PA_INT;
+ continue;
+ case '%':
+ fmt++;
+ break;
+ case '\'':
+ pi->group = 1;
+ fmt++;
+ continue;
+ case '0':
+ /*-
+ * ``Note that 0 is taken as a flag, not as the
+ * beginning of a field width.''
+ * -- ANSI X3J11
+ */
+ pi->pad = '0';
+ fmt++;
+ continue;
+ case '1': case '2': case '3':
+ case '4': case '5': case '6':
+ case '7': case '8': case '9':
+ n = 0;
+ while (*fmt != '\0' && is_digit(*fmt)) {
+ n *= 10;
+ n += to_digit(*fmt);
+ fmt++;
+ }
+ if (*fmt == '$') {
+ if (nextarg > maxarg)
+ maxarg = nextarg;
+ nextarg = n;
+ fmt++;
+ } else
+ pi->width = n;
+ continue;
+ case 'D':
+ case 'O':
+ case 'U':
+ pi->spec += ('a' - 'A');
+ pi->is_intmax = 0;
+ if (pi->is_long_double || pi->is_quad) {
+ pi->is_long = 0;
+ pi->is_long_double = 1;
+ } else {
+ pi->is_long = 1;
+ pi->is_long_double = 0;
+ }
+ fmt++;
+ break;
+ case 'j':
+ pi->is_intmax = 1;
+ fmt++;
+ continue;
+ case 'q':
+ pi->is_long = 0;
+ pi->is_quad = 1;
+ fmt++;
+ continue;
+ case 'L':
+ pi->is_long_double = 1;
+ fmt++;
+ continue;
+ case 'h':
+ fmt++;
+ if (*fmt == 'h') {
+ fmt++;
+ pi->is_char = 1;
+ } else {
+ pi->is_short = 1;
+ }
+ continue;
+ case 'l':
+ fmt++;
+ if (*fmt == 'l') {
+ fmt++;
+ pi->is_long_double = 1;
+ pi->is_quad = 0;
+ } else {
+ pi->is_quad = 0;
+ pi->is_long = 1;
+ }
+ continue;
+ case 't':
+ pi->is_ptrdiff = 1;
+ fmt++;
+ continue;
+ case 'z':
+ pi->is_size = 1;
+ fmt++;
+ continue;
+ default:
+ fmt++;
+ break;
+ }
+ if (printf_tbl[pi->spec].arginfo == NULL)
+ errx(1, "arginfo[%c] = NULL", pi->spec);
+ ch = printf_tbl[pi->spec].arginfo(
+ pi, __PRINTFMAXARG, &argt[nextarg]);
+ if (ch > 0)
+ pi->arg[0] = &args[nextarg];
+ if (ch > 1)
+ pi->arg[1] = &args[nextarg + 1];
+ nextarg += ch;
+ break;
+ }
+ }
+ if (nextarg > maxarg)
+ maxarg = nextarg;
+#if 0
+ fprintf(stderr, "fmt0 <%s>\n", fmt0);
+ fprintf(stderr, "pil %p\n", pil);
+#endif
+ for (ch = 1; ch < maxarg; ch++) {
+#if 0
+ fprintf(stderr, "arg %d %x\n", ch, argt[ch]);
+#endif
+ switch(argt[ch]) {
+ case PA_CHAR:
+ args[ch].intarg = (char)va_arg (ap, int);
+ break;
+ case PA_INT:
+ args[ch].intarg = va_arg (ap, int);
+ break;
+ case PA_INT | PA_FLAG_SHORT:
+ args[ch].intarg = (short)va_arg (ap, int);
+ break;
+ case PA_INT | PA_FLAG_LONG:
+ args[ch].longarg = va_arg (ap, long);
+ break;
+ case PA_INT | PA_FLAG_INTMAX:
+ args[ch].intmaxarg = va_arg (ap, intmax_t);
+ break;
+ case PA_INT | PA_FLAG_QUAD:
+ args[ch].intmaxarg = va_arg (ap, quad_t);
+ break;
+ case PA_INT | PA_FLAG_LONG_LONG:
+ args[ch].intmaxarg = va_arg (ap, long long);
+ break;
+ case PA_INT | PA_FLAG_SIZE:
+ args[ch].intmaxarg = va_arg (ap, size_t);
+ break;
+ case PA_INT | PA_FLAG_PTRDIFF:
+ args[ch].intmaxarg = va_arg (ap, ptrdiff_t);
+ break;
+ case PA_WCHAR:
+ args[ch].wintarg = va_arg (ap, wint_t);
+ break;
+ case PA_POINTER:
+ args[ch].pvoidarg = va_arg (ap, void *);
+ break;
+ case PA_STRING:
+ args[ch].pchararg = va_arg (ap, char *);
+ break;
+ case PA_WSTRING:
+ args[ch].pwchararg = va_arg (ap, wchar_t *);
+ break;
+ case PA_DOUBLE:
+#ifndef NO_FLOATING_POINT
+ args[ch].doublearg = va_arg (ap, double);
+#endif
+ break;
+ case PA_DOUBLE | PA_FLAG_LONG_DOUBLE:
+#ifndef NO_FLOATING_POINT
+ args[ch].longdoublearg = va_arg (ap, long double);
+#endif
+ break;
+ default:
+ errx(1, "argtype = %x (fmt = \"%s\")\n",
+ argt[ch], fmt0);
+ }
+ }
+ for (pi = pia; pi < pil; pi++) {
+#if 0
+ fprintf(stderr, "pi %p", pi);
+ fprintf(stderr, " spec '%c'", pi->spec);
+ fprintf(stderr, " args %d",
+ ((uintptr_t)pi->arg[0] - (uintptr_t)args) / sizeof args[0]);
+ if (pi->width) fprintf(stderr, " width %d", pi->width);
+ if (pi->pad) fprintf(stderr, " pad 0x%x", pi->pad);
+ if (pi->left) fprintf(stderr, " left");
+ if (pi->showsign) fprintf(stderr, " showsign");
+ if (pi->prec != -1) fprintf(stderr, " prec %d", pi->prec);
+ if (pi->is_char) fprintf(stderr, " char");
+ if (pi->is_short) fprintf(stderr, " short");
+ if (pi->is_long) fprintf(stderr, " long");
+ if (pi->is_long_double) fprintf(stderr, " long_double");
+ fprintf(stderr, "\n");
+ fprintf(stderr, "\t\"%.*s\"\n", pi->end - pi->begin, pi->begin);
+#endif
+ if (pi->get_width) {
+ pi->width = args[pi->get_width].intarg;
+ /*-
+ * ``A negative field width argument is taken as a
+ * - flag followed by a positive field width.''
+ * -- ANSI X3J11
+ * They don't exclude field widths read from args.
+ */
+ if (pi->width < 0) {
+ pi->left = 1;
+ pi->width = -pi->width;
+ }
+ }
+ if (pi->get_prec)
+ pi->prec = args[pi->get_prec].intarg;
+ ret += __printf_puts(&io, pi->begin, pi->end - pi->begin);
+ if (printf_tbl[pi->spec].gnurender != NULL) {
+ __printf_flush(&io);
+ pi->sofar = ret;
+ ret += printf_tbl[pi->spec].gnurender(
+ fp, pi, (const void *)pi->arg);
+ } else if (printf_tbl[pi->spec].render != NULL) {
+ pi->sofar = ret;
+ n = printf_tbl[pi->spec].render(
+ &io, pi, (const void *)pi->arg);
+ if (n < 0)
+ io.fp->_flags |= __SERR;
+ else
+ ret += n;
+ } else if (pi->begin == pi->end)
+ errx(1, "render[%c] = NULL", *fmt);
+ }
+ __printf_flush(&io);
+ return (ret);
+}
+
+extern int __fflush(FILE *fp);
+
+/*
+ * Helper function for `fprintf to unbuffered unix file': creates a
+ * temporary buffer. We only work on write-only files; this avoids
+ * worries about ungetc buffers and so forth.
+ */
+static int
+__v3printf(FILE *fp, const char *fmt, int pct, va_list ap)
+{
+ int ret;
+ FILE fake = FAKE_FILE;
+ unsigned char buf[BUFSIZ];
+
+ /* copy the important variables */
+ fake._flags = fp->_flags & ~__SNBF;
+ fake._file = fp->_file;
+ fake._cookie = fp->_cookie;
+ fake._write = fp->_write;
+ fake._orientation = fp->_orientation;
+ fake._mbstate = fp->_mbstate;
+
+ /* set up the buffer */
+ fake._bf._base = fake._p = buf;
+ fake._bf._size = fake._w = sizeof(buf);
+ fake._lbfsize = 0; /* not actually used, but Just In Case */
+
+ /* do the work, then copy any error status */
+ ret = __v2printf(&fake, fmt, pct, ap);
+ if (ret >= 0 && __fflush(&fake))
+ ret = EOF;
+ if (fake._flags & __SERR)
+ fp->_flags |= __SERR;
+ return (ret);
+}
+
+int
+__xvprintf(FILE *fp, const char *fmt0, va_list ap)
+{
+ unsigned u;
+ const char *p;
+
+ /* Count number of '%' signs handling double '%' signs */
+ for (p = fmt0, u = 0; *p; p++) {
+ if (*p != '%')
+ continue;
+ u++;
+ if (p[1] == '%')
+ p++;
+ }
+
+ /* optimise fprintf(stderr) (and other unbuffered Unix files) */
+ if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
+ fp->_file >= 0)
+ return (__v3printf(fp, fmt0, u, ap));
+ else
+ return (__v2printf(fp, fmt0, u, ap));
+}
+
+/* extending ---------------------------------------------------------*/
+
+int
+register_printf_function(int spec, printf_function *render, printf_arginfo_function *arginfo)
+{
+
+ if (spec > 255 || spec < 0)
+ return (-1);
+ printf_tbl[spec].gnurender = render;
+ printf_tbl[spec].arginfo = arginfo;
+ __use_xprintf = 1;
+ return (0);
+}
+
+int
+register_printf_render(int spec, printf_render *render, printf_arginfo_function *arginfo)
+{
+
+ if (spec > 255 || spec < 0)
+ return (-1);
+ printf_tbl[spec].render = render;
+ printf_tbl[spec].arginfo = arginfo;
+ __use_xprintf = 1;
+ return (0);
+}
+
+int
+register_printf_render_std(const char *specs)
+{
+
+ for (; *specs != '\0'; specs++) {
+ switch (*specs) {
+ case 'H':
+ register_printf_render(*specs,
+ __printf_render_hexdump,
+ __printf_arginfo_hexdump);
+ break;
+ case 'M':
+ register_printf_render(*specs,
+ __printf_render_errno,
+ __printf_arginfo_errno);
+ break;
+ case 'Q':
+ register_printf_render(*specs,
+ __printf_render_quote,
+ __printf_arginfo_quote);
+ break;
+ case 'T':
+ register_printf_render(*specs,
+ __printf_render_time,
+ __printf_arginfo_time);
+ break;
+ case 'V':
+ register_printf_render(*specs,
+ __printf_render_vis,
+ __printf_arginfo_vis);
+ break;
+ default:
+ return (-1);
+ }
+ }
+ return (0);
+}
+
diff --git a/lib/libc/stdio/xprintf_errno.c b/lib/libc/stdio/xprintf_errno.c
new file mode 100644
index 000000000000..3c831d129388
--- /dev/null
+++ b/lib/libc/stdio/xprintf_errno.c
@@ -0,0 +1,66 @@
+/*-
+ * Copyright (c) 2005 Poul-Henning Kamp
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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 <namespace.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include <vis.h>
+#include <assert.h>
+#include <sys/time.h>
+#include "errlst.h"
+#include "printf.h"
+
+int
+__printf_arginfo_errno(const struct printf_info *pi __unused, size_t n, int *argt)
+{
+
+ assert(n >= 1);
+ argt[0] = PA_INT;
+ return (1);
+}
+
+int
+__printf_render_errno(struct __printf_io *io, const struct printf_info *pi __unused, const void *const *arg)
+{
+ int ret, error;
+ char buf[64];
+ const char *p;
+
+ ret = 0;
+ error = *((const int *)arg[0]);
+ if (error >= 0 && error < __hidden_sys_nerr) {
+ p = strerror(error);
+ return (__printf_out(io, pi, p, strlen(p)));
+ }
+ sprintf(buf, "errno=%d/0x%x", error, error);
+ ret += __printf_out(io, pi, buf, strlen(buf));
+ __printf_flush(io);
+ return(ret);
+}
diff --git a/lib/libc/stdio/xprintf_float.c b/lib/libc/stdio/xprintf_float.c
new file mode 100644
index 000000000000..ad17eb272032
--- /dev/null
+++ b/lib/libc/stdio/xprintf_float.c
@@ -0,0 +1,422 @@
+/*-
+ * Copyright (c) 2005 Poul-Henning Kamp
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <namespace.h>
+#include <stdio.h>
+#include <wchar.h>
+#include <assert.h>
+#include <locale.h>
+#include <limits.h>
+
+#define dtoa __dtoa
+#define freedtoa __freedtoa
+
+#include <float.h>
+#include <math.h>
+#include "gdtoa.h"
+#include "floatio.h"
+#include "printf.h"
+#include <un-namespace.h>
+
+/*
+ * The size of the buffer we use as scratch space for integer
+ * conversions, among other things. Technically, we would need the
+ * most space for base 10 conversions with thousands' grouping
+ * characters between each pair of digits. 100 bytes is a
+ * conservative overestimate even for a 128-bit uintmax_t.
+ */
+#define BUF 100
+
+#define DEFPREC 6 /* Default FP precision */
+
+
+/* various globals ---------------------------------------------------*/
+
+
+/* padding function---------------------------------------------------*/
+
+#define PRINTANDPAD(p, ep, len, with) do { \
+ n2 = (ep) - (p); \
+ if (n2 > (len)) \
+ n2 = (len); \
+ if (n2 > 0) \
+ ret += __printf_puts(io, (p), n2); \
+ ret += __printf_pad(io, (len) - (n2 > 0 ? n2 : 0), (with)); \
+} while(0)
+
+/* misc --------------------------------------------------------------*/
+
+#define to_char(n) ((n) + '0')
+
+static int
+exponent(char *p0, int expo, int fmtch)
+{
+ char *p, *t;
+ char expbuf[MAXEXPDIG];
+
+ p = p0;
+ *p++ = fmtch;
+ if (expo < 0) {
+ expo = -expo;
+ *p++ = '-';
+ }
+ else
+ *p++ = '+';
+ t = expbuf + MAXEXPDIG;
+ if (expo > 9) {
+ do {
+ *--t = to_char(expo % 10);
+ } while ((expo /= 10) > 9);
+ *--t = to_char(expo);
+ for (; t < expbuf + MAXEXPDIG; *p++ = *t++)
+ ;
+ }
+ else {
+ /*
+ * Exponents for decimal floating point conversions
+ * (%[eEgG]) must be at least two characters long,
+ * whereas exponents for hexadecimal conversions can
+ * be only one character long.
+ */
+ if (fmtch == 'e' || fmtch == 'E')
+ *p++ = '0';
+ *p++ = to_char(expo);
+ }
+ return (p - p0);
+}
+
+/* 'f' ---------------------------------------------------------------*/
+
+int
+__printf_arginfo_float(const struct printf_info *pi, size_t n, int *argt)
+{
+ assert (n > 0);
+ argt[0] = PA_DOUBLE;
+ if (pi->is_long_double)
+ argt[0] |= PA_FLAG_LONG_DOUBLE;
+ return (1);
+}
+
+/*
+ * We can decompose the printed representation of floating
+ * point numbers into several parts, some of which may be empty:
+ *
+ * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ
+ * A B ---C--- D E F
+ *
+ * A: 'sign' holds this value if present; '\0' otherwise
+ * B: ox[1] holds the 'x' or 'X'; '\0' if not hexadecimal
+ * C: cp points to the string MMMNNN. Leading and trailing
+ * zeros are not in the string and must be added.
+ * D: expchar holds this character; '\0' if no exponent, e.g. %f
+ * F: at least two digits for decimal, at least one digit for hex
+ */
+
+int
+__printf_render_float(struct __printf_io *io, const struct printf_info *pi, const void *const *arg)
+{
+ int prec; /* precision from format; <0 for N/A */
+ char *dtoaresult; /* buffer allocated by dtoa */
+ char expchar; /* exponent character: [eEpP\0] */
+ char *cp;
+ int expt; /* integer value of exponent */
+ int signflag; /* true if float is negative */
+ char *dtoaend; /* pointer to end of converted digits */
+ char sign; /* sign prefix (' ', '+', '-', or \0) */
+ int size; /* size of converted field or string */
+ int ndig; /* actual number of digits returned by dtoa */
+ int expsize; /* character count for expstr */
+ char expstr[MAXEXPDIG+2]; /* buffer for exponent string: e+ZZZ */
+ int nseps; /* number of group separators with ' */
+ int nrepeats; /* number of repeats of the last group */
+ const char *grouping; /* locale specific numeric grouping rules */
+ int lead; /* sig figs before decimal or group sep */
+ long double ld;
+ double d;
+ int realsz; /* field size expanded by dprec, sign, etc */
+ int dprec; /* a copy of prec if [diouxX], 0 otherwise */
+ char ox[2]; /* space for 0x; ox[1] is either x, X, or \0 */
+ int ret; /* return value accumulator */
+ char *decimal_point; /* locale specific decimal point */
+ int n2; /* XXX: for PRINTANDPAD */
+ char thousands_sep; /* locale specific thousands separator */
+ char buf[BUF]; /* buffer with space for digits of uintmax_t */
+ const char *xdigs;
+ int flag;
+
+ prec = pi->prec;
+ ox[1] = '\0';
+ sign = pi->showsign;
+ flag = 0;
+ ret = 0;
+
+ thousands_sep = *(localeconv()->thousands_sep);
+ grouping = NULL;
+ if (pi->alt)
+ grouping = localeconv()->grouping;
+ decimal_point = localeconv()->decimal_point;
+ dprec = -1;
+
+ switch(pi->spec) {
+ case 'a':
+ case 'A':
+ if (pi->spec == 'a') {
+ ox[1] = 'x';
+ xdigs = __lowercase_hex;
+ expchar = 'p';
+ } else {
+ ox[1] = 'X';
+ xdigs = __uppercase_hex;
+ expchar = 'P';
+ }
+ if (prec >= 0)
+ prec++;
+ if (pi->is_long_double) {
+ ld = *((long double *)arg[0]);
+ dtoaresult = cp =
+ __hldtoa(ld, xdigs, prec,
+ &expt, &signflag, &dtoaend);
+ } else {
+ d = *((double *)arg[0]);
+ dtoaresult = cp =
+ __hdtoa(d, xdigs, prec,
+ &expt, &signflag, &dtoaend);
+ }
+ if (prec < 0)
+ prec = dtoaend - cp;
+ if (expt == INT_MAX)
+ ox[1] = '\0';
+ goto fp_common;
+ case 'e':
+ case 'E':
+ expchar = pi->spec;
+ if (prec < 0) /* account for digit before decpt */
+ prec = DEFPREC + 1;
+ else
+ prec++;
+ break;
+ case 'f':
+ case 'F':
+ expchar = '\0';
+ break;
+ case 'g':
+ case 'G':
+ expchar = pi->spec - ('g' - 'e');
+ if (prec == 0)
+ prec = 1;
+ break;
+ default:
+ assert(pi->spec == 'f');
+ }
+
+ if (prec < 0)
+ prec = DEFPREC;
+ if (pi->is_long_double) {
+ ld = *((long double *)arg[0]);
+ dtoaresult = cp =
+ __ldtoa(&ld, expchar ? 2 : 3, prec,
+ &expt, &signflag, &dtoaend);
+ } else {
+ d = *((double *)arg[0]);
+ dtoaresult = cp =
+ dtoa(d, expchar ? 2 : 3, prec,
+ &expt, &signflag, &dtoaend);
+ if (expt == 9999)
+ expt = INT_MAX;
+ }
+fp_common:
+ if (signflag)
+ sign = '-';
+ if (expt == INT_MAX) { /* inf or nan */
+ if (*cp == 'N') {
+ cp = (pi->spec >= 'a') ? "nan" : "NAN";
+ sign = '\0';
+ } else
+ cp = (pi->spec >= 'a') ? "inf" : "INF";
+ size = 3;
+ flag = 1;
+ goto here;
+ }
+ ndig = dtoaend - cp;
+ if (pi->spec == 'g' || pi->spec == 'G') {
+ if (expt > -4 && expt <= prec) {
+ /* Make %[gG] smell like %[fF] */
+ expchar = '\0';
+ if (pi->alt)
+ prec -= expt;
+ else
+ prec = ndig - expt;
+ if (prec < 0)
+ prec = 0;
+ } else {
+ /*
+ * Make %[gG] smell like %[eE], but
+ * trim trailing zeroes if no # flag.
+ */
+ if (!pi->alt)
+ prec = ndig;
+ }
+ }
+ if (expchar) {
+ expsize = exponent(expstr, expt - 1, expchar);
+ size = expsize + prec;
+ if (prec > 1 || pi->alt)
+ ++size;
+ } else {
+ /* space for digits before decimal point */
+ if (expt > 0)
+ size = expt;
+ else /* "0" */
+ size = 1;
+ /* space for decimal pt and following digits */
+ if (prec || pi->alt)
+ size += prec + 1;
+ if (grouping && expt > 0) {
+ /* space for thousands' grouping */
+ nseps = nrepeats = 0;
+ lead = expt;
+ while (*grouping != CHAR_MAX) {
+ if (lead <= *grouping)
+ break;
+ lead -= *grouping;
+ if (*(grouping+1)) {
+ nseps++;
+ grouping++;
+ } else
+ nrepeats++;
+ }
+ size += nseps + nrepeats;
+ } else
+ lead = expt;
+ }
+
+here:
+ /*
+ * All reasonable formats wind up here. At this point, `cp'
+ * points to a string which (if not flags&LADJUST) should be
+ * padded out to `width' places. If flags&ZEROPAD, it should
+ * first be prefixed by any sign or other prefix; otherwise,
+ * it should be blank padded before the prefix is emitted.
+ * After any left-hand padding and prefixing, emit zeroes
+ * required by a decimal [diouxX] precision, then print the
+ * string proper, then emit zeroes required by any leftover
+ * floating precision; finally, if LADJUST, pad with blanks.
+ *
+ * Compute actual size, so we know how much to pad.
+ * size excludes decimal prec; realsz includes it.
+ */
+ realsz = dprec > size ? dprec : size;
+ if (sign)
+ realsz++;
+ if (ox[1])
+ realsz += 2;
+
+ /* right-adjusting blank padding */
+ if (pi->pad != '0' && pi->left == 0)
+ ret += __printf_pad(io, pi->width - realsz, 0);
+
+ /* prefix */
+ if (sign)
+ ret += __printf_puts(io, &sign, 1);
+
+ if (ox[1]) { /* ox[1] is either x, X, or \0 */
+ ox[0] = '0';
+ ret += __printf_puts(io, ox, 2);
+ }
+
+ /* right-adjusting zero padding */
+ if (pi->pad == '0' && pi->left == 0)
+ ret += __printf_pad(io, pi->width - realsz, 1);
+
+ /* leading zeroes from decimal precision */
+ ret += __printf_pad(io, dprec - size, 1);
+
+ if (flag)
+ ret += __printf_puts(io, cp, size);
+ else {
+ /* glue together f_p fragments */
+ if (!expchar) { /* %[fF] or sufficiently short %[gG] */
+ if (expt <= 0) {
+ ret += __printf_puts(io, "0", 1);
+ if (prec || pi->alt)
+ ret += __printf_puts(io, decimal_point, 1);
+ ret += __printf_pad(io, -expt, 1);
+ /* already handled initial 0's */
+ prec += expt;
+ } else {
+ PRINTANDPAD(cp, dtoaend, lead, 1);
+ cp += lead;
+ if (grouping) {
+ while (nseps>0 || nrepeats>0) {
+ if (nrepeats > 0)
+ nrepeats--;
+ else {
+ grouping--;
+ nseps--;
+ }
+ ret += __printf_puts(io, &thousands_sep, 1);
+ PRINTANDPAD(cp,dtoaend,
+ *grouping, 1);
+ cp += *grouping;
+ }
+ if (cp > dtoaend)
+ cp = dtoaend;
+ }
+ if (prec || pi->alt)
+ ret += __printf_puts(io, decimal_point,1);
+ }
+ PRINTANDPAD(cp, dtoaend, prec, 1);
+ } else { /* %[eE] or sufficiently long %[gG] */
+ if (prec > 1 || pi->alt) {
+ buf[0] = *cp++;
+ buf[1] = *decimal_point;
+ ret += __printf_puts(io, buf, 2);
+ ret += __printf_puts(io, cp, ndig-1);
+ ret += __printf_pad(io, prec - ndig, 1);
+ } else /* XeYYY */
+ ret += __printf_puts(io, cp, 1);
+ ret += __printf_puts(io, expstr, expsize);
+ }
+ }
+ /* left-adjusting padding (always blank) */
+ if (pi->left)
+ ret += __printf_pad(io, pi->width - realsz, 0);
+
+ __printf_flush(io);
+ if (dtoaresult != NULL)
+ freedtoa(dtoaresult);
+
+ return (ret);
+}
diff --git a/lib/libc/stdio/xprintf_hexdump.c b/lib/libc/stdio/xprintf_hexdump.c
new file mode 100644
index 000000000000..a2956ba27b65
--- /dev/null
+++ b/lib/libc/stdio/xprintf_hexdump.c
@@ -0,0 +1,97 @@
+/*-
+ * Copyright (c) 2005 Poul-Henning Kamp
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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 <namespace.h>
+#include <stdio.h>
+#include <wchar.h>
+#include <stdint.h>
+#include <assert.h>
+#include <sys/time.h>
+#include "printf.h"
+
+int
+__printf_arginfo_hexdump(const struct printf_info *pi, size_t n, int *argt)
+{
+
+ assert(n >= 2);
+ argt[0] = PA_POINTER;
+ argt[1] = PA_INT;
+ return (2);
+}
+
+int
+__printf_render_hexdump(struct __printf_io *io, const struct printf_info *pi, const void *const *arg)
+{
+ unsigned char *p;
+ unsigned u, l, j, a;
+ char buf[100], *q;
+ int ret;
+
+ if (pi->width > 0 && pi->width < 16)
+ l = pi->width;
+ else
+ l = 16;
+ p = *((unsigned char **)arg[0]);
+ u = *((unsigned *)arg[1]);
+
+ ret = 0;
+ a = 0;
+ while (u > 0) {
+ q = buf;
+ if (pi->showsign)
+ q += sprintf(q, " %04x", a);
+ for (j = 0; j < l && j < u; j++)
+ q += sprintf(q, " %02x", p[j]);
+ if (pi->alt) {
+ for (; j < l; j++)
+ q += sprintf(q, " ");
+ q += sprintf(q, " |");
+ for (j = 0; j < l && j < u; j++) {
+ if (p[j] < ' ' || p[j] > '~')
+ *q++ = '.';
+ else
+ *q++ = p[j];
+ }
+ for (; j < l; j++)
+ *q++ = ' ';
+ *q++ = '|';
+ }
+ if (l < u)
+ j = l;
+ else
+ j = u;
+ p += j;
+ u -= j;
+ a += j;
+ if (u > 0)
+ *q++ = '\n';
+ ret += __printf_puts(io, buf + 1, q - (buf + 1));
+ __printf_flush(io);
+ }
+ return (ret);
+}
diff --git a/lib/libc/stdio/xprintf_int.c b/lib/libc/stdio/xprintf_int.c
new file mode 100644
index 000000000000..f006b54d51cb
--- /dev/null
+++ b/lib/libc/stdio/xprintf_int.c
@@ -0,0 +1,471 @@
+/*-
+ * Copyright (c) 2005 Poul-Henning Kamp
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <namespace.h>
+#include <err.h>
+#include <sys/types.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <limits.h>
+#include <locale.h>
+#include <stdint.h>
+#include <assert.h>
+#include <namespace.h>
+#include <string.h>
+#include <wchar.h>
+#include <un-namespace.h>
+
+#include "printf.h"
+
+/* private stuff -----------------------------------------------------*/
+
+union arg {
+ int intarg;
+ u_int uintarg;
+ long longarg;
+ u_long ulongarg;
+ intmax_t intmaxarg;
+ uintmax_t uintmaxarg;
+};
+
+/*
+ * Macros for converting digits to letters and vice versa
+ */
+#define to_char(n) ((n) + '0')
+
+/* various globals ---------------------------------------------------*/
+
+/*
+ * The size of the buffer we use for integer conversions.
+ * Technically, we would need the most space for base 10
+ * conversions with thousands' grouping characters between
+ * each pair of digits: 60 digits for 128 bit intmax_t.
+ * Use a bit more for better alignment of stuff.
+ */
+#define BUF 64
+
+/* misc --------------------------------------------------------------*/
+
+/*
+ * Convert an unsigned long to ASCII for printf purposes, returning
+ * a pointer to the first character of the string representation.
+ * Octal numbers can be forced to have a leading zero; hex numbers
+ * use the given digits.
+ */
+static char *
+__ultoa(u_long val, char *endp, int base, const char *xdigs,
+ int needgrp, char thousep, const char *grp)
+{
+ char *cp = endp;
+ long sval;
+ int ndig;
+
+ /*
+ * Handle the three cases separately, in the hope of getting
+ * better/faster code.
+ */
+ switch (base) {
+ case 10:
+ if (val < 10) { /* many numbers are 1 digit */
+ *--cp = to_char(val);
+ return (cp);
+ }
+ ndig = 0;
+ /*
+ * On many machines, unsigned arithmetic is harder than
+ * signed arithmetic, so we do at most one unsigned mod and
+ * divide; this is sufficient to reduce the range of
+ * the incoming value to where signed arithmetic works.
+ */
+ if (val > LONG_MAX) {
+ *--cp = to_char(val % 10);
+ ndig++;
+ sval = val / 10;
+ } else
+ sval = val;
+ do {
+ *--cp = to_char(sval % 10);
+ ndig++;
+ /*
+ * If (*grp == CHAR_MAX) then no more grouping
+ * should be performed.
+ */
+ if (needgrp && ndig == *grp && *grp != CHAR_MAX
+ && sval > 9) {
+ *--cp = thousep;
+ ndig = 0;
+ /*
+ * If (*(grp+1) == '\0') then we have to
+ * use *grp character (last grouping rule)
+ * for all next cases
+ */
+ if (*(grp+1) != '\0')
+ grp++;
+ }
+ sval /= 10;
+ } while (sval != 0);
+ break;
+
+ case 8:
+ do {
+ *--cp = to_char(val & 7);
+ val >>= 3;
+ } while (val);
+ break;
+
+ case 16:
+ do {
+ *--cp = xdigs[val & 15];
+ val >>= 4;
+ } while (val);
+ break;
+
+ default: /* oops */
+ assert(base == 16);
+ }
+ return (cp);
+}
+
+
+/* Identical to __ultoa, but for intmax_t. */
+static char *
+__ujtoa(uintmax_t val, char *endp, int base, const char *xdigs,
+ int needgrp, char thousep, const char *grp)
+{
+ char *cp = endp;
+ intmax_t sval;
+ int ndig;
+
+ switch (base) {
+ case 10:
+ if (val < 10) {
+ *--cp = to_char(val % 10);
+ return (cp);
+ }
+ ndig = 0;
+ if (val > INTMAX_MAX) {
+ *--cp = to_char(val % 10);
+ ndig++;
+ sval = val / 10;
+ } else
+ sval = val;
+ do {
+ *--cp = to_char(sval % 10);
+ ndig++;
+ /*
+ * If (*grp == CHAR_MAX) then no more grouping
+ * should be performed.
+ */
+ if (needgrp && *grp != CHAR_MAX && ndig == *grp
+ && sval > 9) {
+ *--cp = thousep;
+ ndig = 0;
+ /*
+ * If (*(grp+1) == '\0') then we have to
+ * use *grp character (last grouping rule)
+ * for all next cases
+ */
+ if (*(grp+1) != '\0')
+ grp++;
+ }
+ sval /= 10;
+ } while (sval != 0);
+ break;
+
+ case 8:
+ do {
+ *--cp = to_char(val & 7);
+ val >>= 3;
+ } while (val);
+ break;
+
+ case 16:
+ do {
+ *--cp = xdigs[val & 15];
+ val >>= 4;
+ } while (val);
+ break;
+
+ default:
+ abort();
+ }
+ return (cp);
+}
+
+
+/* 'd' ---------------------------------------------------------------*/
+
+int
+__printf_arginfo_int(const struct printf_info *pi, size_t n, int *argt)
+{
+ assert (n > 0);
+ argt[0] = PA_INT;
+ if (pi->is_ptrdiff)
+ argt[0] |= PA_FLAG_PTRDIFF;
+ else if (pi->is_size)
+ argt[0] |= PA_FLAG_SIZE;
+ else if (pi->is_long)
+ argt[0] |= PA_FLAG_LONG;
+ else if (pi->is_intmax)
+ argt[0] |= PA_FLAG_INTMAX;
+ else if (pi->is_quad)
+ argt[0] |= PA_FLAG_QUAD;
+ else if (pi->is_long_double)
+ argt[0] |= PA_FLAG_LONG_LONG;
+ else if (pi->is_short)
+ argt[0] |= PA_FLAG_SHORT;
+ else if (pi->is_char)
+ argt[0] = PA_CHAR;
+ return (1);
+}
+
+int
+__printf_render_int(struct __printf_io *io, const struct printf_info *pi, const void *const *arg)
+{
+ const union arg *argp;
+ char buf[BUF];
+ char *p, *pe;
+ char ns, l;
+ int rdx, sign, zext, ngrp;
+ const char *nalt, *digit;
+ char thousands_sep; /* locale specific thousands separator */
+ const char *grouping; /* locale specific numeric grouping rules */
+ uintmax_t uu;
+ int ret;
+
+ ret = 0;
+ nalt = NULL;
+ digit = __lowercase_hex;
+ ns = '\0';
+ pe = buf + sizeof buf - 1;
+
+ if (pi->group) {
+ thousands_sep = *(localeconv()->thousands_sep);
+ grouping = localeconv()->grouping;
+ ngrp = 1;
+ } else {
+ thousands_sep = 0;
+ grouping = NULL;
+ ngrp = 0;
+ }
+
+ switch(pi->spec) {
+ case 'd':
+ case 'i':
+ rdx = 10;
+ sign = 1;
+ break;
+ case 'X':
+ digit = __uppercase_hex;
+ /*FALLTHOUGH*/
+ case 'x':
+ rdx = 16;
+ sign = 0;
+ break;
+ case 'u':
+ case 'U':
+ rdx = 10;
+ sign = 0;
+ break;
+ case 'o':
+ case 'O':
+ rdx = 8;
+ sign = 0;
+ break;
+ default:
+ fprintf(stderr, "pi->spec = '%c'\n", pi->spec);
+ assert(1 == 0);
+ }
+ argp = arg[0];
+
+ if (sign)
+ ns = pi->showsign;
+
+ if (pi->is_long_double || pi->is_quad || pi->is_intmax ||
+ pi->is_size || pi->is_ptrdiff) {
+ if (sign && argp->intmaxarg < 0) {
+ uu = -argp->intmaxarg;
+ ns = '-';
+ } else
+ uu = argp->uintmaxarg;
+ } else if (pi->is_long) {
+ if (sign && argp->longarg < 0) {
+ uu = (u_long)-argp->longarg;
+ ns = '-';
+ } else
+ uu = argp->ulongarg;
+ } else if (pi->is_short) {
+ if (sign && (short)argp->intarg < 0) {
+ uu = -(short)argp->intarg;
+ ns = '-';
+ } else
+ uu = (unsigned short)argp->uintarg;
+ } else if (pi->is_char) {
+ if (sign && (signed char)argp->intarg < 0) {
+ uu = -(signed char)argp->intarg;
+ ns = '-';
+ } else
+ uu = (unsigned char)argp->uintarg;
+ } else {
+ if (sign && argp->intarg < 0) {
+ uu = (unsigned)-argp->intarg;
+ ns = '-';
+ } else
+ uu = argp->uintarg;
+ }
+ if (uu <= ULONG_MAX)
+ p = __ultoa(uu, pe, rdx, digit, ngrp, thousands_sep, grouping);
+ else
+ p = __ujtoa(uu, pe, rdx, digit, ngrp, thousands_sep, grouping);
+
+ l = 0;
+ if (uu == 0) {
+ /*-
+ * ``The result of converting a zero value with an
+ * explicit precision of zero is no characters.''
+ * -- ANSI X3J11
+ *
+ * ``The C Standard is clear enough as is. The call
+ * printf("%#.0o", 0) should print 0.''
+ * -- Defect Report #151
+ */
+ ;
+ if (pi->prec == 0 && !(pi->alt && rdx == 8))
+ p = pe;
+ } else if (pi->alt) {
+ if (rdx == 8)
+ *--p = '0';
+ if (rdx == 16) {
+ if (pi->spec == 'x')
+ nalt = "0x";
+ else
+ nalt = "0X";
+ l += 2;
+ }
+ }
+ l += pe - p;
+ if (ns)
+ l++;
+
+ /*-
+ * ``... diouXx conversions ... if a precision is
+ * specified, the 0 flag will be ignored.''
+ * -- ANSI X3J11
+ */
+ if (pi->prec > (pe - p))
+ zext = pi->prec - (pe - p);
+ else if (pi->prec != -1)
+ zext = 0;
+ else if (pi->pad == '0' && pi->width > l && !pi->left)
+ zext = pi->width - l;
+ else
+ zext = 0;
+
+ l += zext;
+
+ while (zext > 0 && p > buf) {
+ *--p = '0';
+ zext--;
+ }
+
+ if (l < BUF) {
+ if (ns) {
+ *--p = ns;
+ } else if (nalt != NULL) {
+ *--p = nalt[1];
+ *--p = nalt[0];
+ }
+ if (pi->width > (pe - p) && !pi->left) {
+ l = pi->width - (pe - p);
+ while (l > 0 && p > buf) {
+ *--p = ' ';
+ l--;
+ }
+ if (l)
+ ret += __printf_pad(io, l, 0);
+ }
+ } else {
+ if (!pi->left && pi->width > l)
+ ret += __printf_pad(io, pi->width - l, 0);
+ if (ns != '\0')
+ ret += __printf_puts(io, &ns, 1);
+ else if (nalt != NULL)
+ ret += __printf_puts(io, nalt, 2);
+ if (zext > 0)
+ ret += __printf_pad(io, zext, 1);
+ }
+
+ ret += __printf_puts(io, p, pe - p);
+ if (pi->width > ret && pi->left)
+ ret += __printf_pad(io, pi->width - ret, 0);
+ __printf_flush(io);
+ return (ret);
+}
+
+/* 'p' ---------------------------------------------------------------*/
+
+int
+__printf_arginfo_ptr(const struct printf_info *pi __unused, size_t n, int *argt)
+{
+
+ assert (n > 0);
+ argt[0] = PA_POINTER;
+ return (1);
+}
+
+int
+__printf_render_ptr(struct __printf_io *io, const struct printf_info *pi, const void *const *arg)
+{
+ struct printf_info p2;
+ uintmax_t u;
+ const void *p;
+
+ /*-
+ * ``The argument shall be a pointer to void. The
+ * value of the pointer is converted to a sequence
+ * of printable characters, in an implementation-
+ * defined manner.''
+ * -- ANSI X3J11
+ */
+ u = (uintmax_t)(uintptr_t) *((void **)arg[0]);
+ p2 = *pi;
+
+ p2.spec = 'x';
+ p2.alt = 1;
+ p2.is_long_double = 1;
+ p = &u;
+ return (__printf_render_int(io, &p2, &p));
+}
diff --git a/lib/libc/stdio/xprintf_quote.c b/lib/libc/stdio/xprintf_quote.c
new file mode 100644
index 000000000000..0edcd30e9c55
--- /dev/null
+++ b/lib/libc/stdio/xprintf_quote.c
@@ -0,0 +1,98 @@
+/*-
+ * Copyright (c) 2005 Poul-Henning Kamp
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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 <namespace.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <wchar.h>
+#include <vis.h>
+#include <assert.h>
+#include <sys/time.h>
+#include "printf.h"
+
+int
+__printf_arginfo_quote(const struct printf_info *pi __unused, size_t n, int *argt)
+{
+
+ assert(n >= 1);
+ argt[0] = PA_POINTER;
+ return (1);
+}
+
+int
+__printf_render_quote(struct __printf_io *io, const struct printf_info *pi __unused, const void *const *arg)
+{
+ const char *str, *p, *t, *o;
+ char r[5];
+ int i, ret;
+
+ str = *((const char *const *)arg[0]);
+ if (str == NULL)
+ return (__printf_out(io, pi, "\"(null)\"", 8));
+ if (*str == '\0')
+ return (__printf_out(io, pi, "\"\"", 2));
+
+ for (i = 0, p = str; *p; p++)
+ if (isspace(*p) || *p == '\\' || *p == '"')
+ i++;
+ if (!i)
+ return (__printf_out(io, pi, str, strlen(str)));
+
+ ret = __printf_out(io, pi, "\"", 1);
+ for (t = p = str; *p; p++) {
+ o = NULL;
+ if (*p == '\\')
+ o = "\\\\";
+ else if (*p == '\n')
+ o = "\\n";
+ else if (*p == '\r')
+ o = "\\r";
+ else if (*p == '\t')
+ o = "\\t";
+ else if (*p == ' ')
+ o = " ";
+ else if (*p == '"')
+ o = "\\\"";
+ else if (isspace(*p)) {
+ sprintf(r, "\\%03o", *p);
+ o = r;
+ } else
+ continue;
+ if (p != t)
+ ret += __printf_out(io, pi, t, p - t);
+ ret += __printf_out(io, pi, o, strlen(o));
+ t = p + 1;
+ }
+ if (p != t)
+ ret += __printf_out(io, pi, t, p - t);
+ ret += __printf_out(io, pi, "\"", 1);
+ __printf_flush(io);
+ return(ret);
+}
diff --git a/lib/libc/stdio/xprintf_str.c b/lib/libc/stdio/xprintf_str.c
new file mode 100644
index 000000000000..d46fa85841aa
--- /dev/null
+++ b/lib/libc/stdio/xprintf_str.c
@@ -0,0 +1,187 @@
+/*-
+ * Copyright (c) 2005 Poul-Henning Kamp
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <namespace.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <stdint.h>
+#include <assert.h>
+#include <wchar.h>
+#include "printf.h"
+
+/*
+ * Convert a wide character string argument for the %ls format to a multibyte
+ * string representation. If not -1, prec specifies the maximum number of
+ * bytes to output, and also means that we can't assume that the wide char.
+ * string ends is null-terminated.
+ */
+static char *
+__wcsconv(wchar_t *wcsarg, int prec)
+{
+ static const mbstate_t initial;
+ mbstate_t mbs;
+ char buf[MB_LEN_MAX];
+ wchar_t *p;
+ char *convbuf;
+ size_t clen, nbytes;
+
+ /* Allocate space for the maximum number of bytes we could output. */
+ if (prec < 0) {
+ p = wcsarg;
+ mbs = initial;
+ nbytes = wcsrtombs(NULL, (const wchar_t **)&p, 0, &mbs);
+ if (nbytes == (size_t)-1)
+ return (NULL);
+ } else {
+ /*
+ * Optimisation: if the output precision is small enough,
+ * just allocate enough memory for the maximum instead of
+ * scanning the string.
+ */
+ if (prec < 128)
+ nbytes = prec;
+ else {
+ nbytes = 0;
+ p = wcsarg;
+ mbs = initial;
+ for (;;) {
+ clen = wcrtomb(buf, *p++, &mbs);
+ if (clen == 0 || clen == (size_t)-1 ||
+ (int)(nbytes + clen) > prec)
+ break;
+ nbytes += clen;
+ }
+ }
+ }
+ if ((convbuf = malloc(nbytes + 1)) == NULL)
+ return (NULL);
+
+ /* Fill the output buffer. */
+ p = wcsarg;
+ mbs = initial;
+ if ((nbytes = wcsrtombs(convbuf, (const wchar_t **)&p,
+ nbytes, &mbs)) == (size_t)-1) {
+ free(convbuf);
+ return (NULL);
+ }
+ convbuf[nbytes] = '\0';
+ return (convbuf);
+}
+
+
+/* 's' ---------------------------------------------------------------*/
+
+int
+__printf_arginfo_str(const struct printf_info *pi, size_t n, int *argt)
+{
+
+ assert (n > 0);
+ if (pi->is_long || pi->spec == 'C')
+ argt[0] = PA_WSTRING;
+ else
+ argt[0] = PA_STRING;
+ return (1);
+}
+
+int
+__printf_render_str(struct __printf_io *io, const struct printf_info *pi, const void *const *arg)
+{
+ const char *p;
+ wchar_t *wcp;
+ char *convbuf;
+ int l;
+
+ if (pi->is_long || pi->spec == 'S') {
+ wcp = *((wint_t **)arg[0]);
+ if (wcp == NULL)
+ return (__printf_out(io, pi, "(null)", 6));
+ convbuf = __wcsconv(wcp, pi->prec);
+ if (convbuf == NULL)
+ return (-1);
+ l = __printf_out(io, pi, convbuf, strlen(convbuf));
+ free(convbuf);
+ return (l);
+ }
+ p = *((char **)arg[0]);
+ if (p == NULL)
+ return (__printf_out(io, pi, "(null)", 6));
+ l = strlen(p);
+ if (pi->prec >= 0 && pi->prec < l)
+ l = pi->prec;
+ return (__printf_out(io, pi, p, l));
+}
+
+/* 'c' ---------------------------------------------------------------*/
+
+int
+__printf_arginfo_chr(const struct printf_info *pi, size_t n, int *argt)
+{
+
+ assert (n > 0);
+ if (pi->is_long || pi->spec == 'C')
+ argt[0] = PA_WCHAR;
+ else
+ argt[0] = PA_INT;
+ return (1);
+}
+
+int
+__printf_render_chr(struct __printf_io *io, const struct printf_info *pi, const void *const *arg)
+{
+ int i;
+ wint_t ii;
+ unsigned char c;
+ static const mbstate_t initial; /* XXX: this is bogus! */
+ mbstate_t mbs;
+ size_t mbseqlen;
+ char buf[MB_CUR_MAX];
+
+ if (pi->is_long || pi->spec == 'C') {
+ ii = *((wint_t *)arg[0]);
+
+ mbs = initial;
+ mbseqlen = wcrtomb(buf, (wchar_t)ii, &mbs);
+ if (mbseqlen == (size_t) -1)
+ return (-1);
+ return (__printf_out(io, pi, buf, mbseqlen));
+ }
+ i = *((int *)arg[0]);
+ c = i;
+ i = __printf_out(io, pi, &c, 1);
+ __printf_flush(io);
+ return (i);
+}
diff --git a/lib/libc/stdio/xprintf_time.c b/lib/libc/stdio/xprintf_time.c
new file mode 100644
index 000000000000..debfac579fa6
--- /dev/null
+++ b/lib/libc/stdio/xprintf_time.c
@@ -0,0 +1,122 @@
+/*-
+ * Copyright (c) 2005 Poul-Henning Kamp
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <namespace.h>
+#include <stdio.h>
+#include <wchar.h>
+#include <stdint.h>
+#include <assert.h>
+#include <sys/time.h>
+#include "printf.h"
+
+int
+__printf_arginfo_time(const struct printf_info *pi, size_t n, int *argt)
+{
+
+ assert(n >= 1);
+ argt[0] = PA_POINTER;
+ return (1);
+}
+#define MINUTE 60
+#define HOUR (60 * MINUTE)
+#define DAY (24 * HOUR)
+#define YEAR (365 * DAY)
+
+int
+__printf_render_time(struct __printf_io *io, const struct printf_info *pi, const void *const *arg)
+{
+ char buf[100];
+ char *p;
+ struct timeval *tv;
+ struct timespec *ts;
+ time_t *tp;
+ intmax_t t, tx;
+ int i, prec, nsec, ret;
+
+ if (pi->is_long) {
+ tv = *((struct timeval **)arg[0]);
+ t = tv->tv_sec;
+ nsec = tv->tv_usec * 1000;
+ prec = 6;
+ } else if (pi->is_long_double) {
+ ts = *((struct timespec **)arg[0]);
+ t = ts->tv_sec;
+ nsec = ts->tv_nsec;
+ prec = 9;
+ } else {
+ tp = *((time_t **)arg[0]);
+ t = *tp;
+ nsec = 0;
+ prec = 0;
+ }
+ if (pi->is_long || pi->is_long_double) {
+ if (pi->prec >= 0)
+ prec = pi->prec;
+ if (prec == 0)
+ nsec = 0;
+ }
+
+ p = buf;
+ if (pi->alt) {
+ tx = t;
+ if (t >= YEAR) {
+ p += sprintf(p, "%jdy", t / YEAR);
+ t %= YEAR;
+ }
+ if (tx >= DAY && (t != 0 || prec != 0)) {
+ p += sprintf(p, "%jdd", t / DAY);
+ t %= DAY;
+ }
+ if (tx >= HOUR && (t != 0 || prec != 0)) {
+ p += sprintf(p, "%jdh", t / HOUR);
+ t %= HOUR;
+ }
+ if (tx >= MINUTE && (t != 0 || prec != 0)) {
+ p += sprintf(p, "%jdm", t / MINUTE);
+ t %= MINUTE;
+ }
+ if (t != 0 || tx == 0 || prec != 0)
+ p += sprintf(p, "%jds", t);
+ } else {
+ p += sprintf(p, "%jd", (intmax_t)t);
+ }
+ if (prec != 0) {
+ for (i = prec; i < 9; i++)
+ nsec /= 10;
+ p += sprintf(p, ".%.*d", prec, nsec);
+ }
+ ret = __printf_out(io, pi, buf, p - buf);
+ __printf_flush(io);
+ return (ret);
+}
diff --git a/lib/libc/stdio/xprintf_vis.c b/lib/libc/stdio/xprintf_vis.c
new file mode 100644
index 000000000000..819f09ff1d8f
--- /dev/null
+++ b/lib/libc/stdio/xprintf_vis.c
@@ -0,0 +1,78 @@
+/*-
+ * Copyright (c) 2005 Poul-Henning Kamp
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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 <namespace.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include <vis.h>
+#include <assert.h>
+#include <sys/time.h>
+#include "printf.h"
+
+int
+__printf_arginfo_vis(const struct printf_info *pi, size_t n, int *argt)
+{
+
+ assert(n >= 1);
+ argt[0] = PA_POINTER;
+ return (1);
+}
+
+int
+__printf_render_vis(struct __printf_io *io, const struct printf_info *pi, const void *const *arg)
+{
+ char *p, *buf;
+ unsigned l;
+ int ret;
+
+ ret = 0;
+ p = *((char **)arg[0]);
+ if (p == NULL)
+ return (__printf_out(io, pi, "(null)", 6));
+ if (pi->prec >= 0)
+ l = pi->prec;
+ else
+ l = strlen(p);
+ buf = malloc(l * 4 + 1);
+ if (buf == NULL)
+ return (-1);
+ if (pi->showsign)
+ ret = strvisx(buf, p, l, VIS_WHITE | VIS_HTTPSTYLE);
+ else if (pi->pad == '0')
+ ret = strvisx(buf, p, l, VIS_WHITE | VIS_OCTAL);
+ else if (pi->alt)
+ ret = strvisx(buf, p, l, VIS_WHITE);
+ else
+ ret = strvisx(buf, p, l, VIS_WHITE | VIS_CSTYLE | VIS_OCTAL);
+ ret += __printf_out(io, pi, buf, ret);
+ __printf_flush(io);
+ free(buf);
+ return(ret);
+}
diff --git a/lib/libc/stdlib/Makefile.inc b/lib/libc/stdlib/Makefile.inc
new file mode 100644
index 000000000000..00f90e2f81e0
--- /dev/null
+++ b/lib/libc/stdlib/Makefile.inc
@@ -0,0 +1,62 @@
+# from @(#)Makefile.inc 8.3 (Berkeley) 2/4/95
+# $FreeBSD$
+
+# machine-independent stdlib sources
+.PATH: ${LIBC_SRCTOP}/${LIBC_ARCH}/stdlib ${LIBC_SRCTOP}/stdlib
+
+MISRCS+=C99_Exit.c a64l.c abort.c abs.c atexit.c atof.c atoi.c atol.c atoll.c \
+ bsearch.c \
+ cxa_thread_atexit.c cxa_thread_atexit_impl.c \
+ div.c exit.c getenv.c getopt.c getopt_long.c \
+ getsubopt.c hcreate.c hcreate_r.c hdestroy_r.c heapsort.c heapsort_b.c \
+ hsearch_r.c imaxabs.c imaxdiv.c \
+ insque.c l64a.c labs.c ldiv.c llabs.c lldiv.c lsearch.c \
+ merge.c mergesort_b.c ptsname.c qsort.c qsort_r.c quick_exit.c \
+ radixsort.c rand.c \
+ random.c reallocarray.c reallocf.c realpath.c remque.c strfmon.c \
+ strtoimax.c \
+ strtol.c strtoll.c strtoq.c strtoul.c strtonum.c strtoull.c \
+ strtoumax.c strtouq.c system.c tdelete.c tfind.c tsearch.c twalk.c
+
+# Work around an issue on case-insensitive file systems.
+# libc has both _Exit.c and _exit.s and they both yield
+# _exit.o (case insensitively speaking).
+CLEANFILES+=C99_Exit.c
+C99_Exit.c: ${LIBC_SRCTOP}/stdlib/_Exit.c .NOMETA
+ ln -sf ${.ALLSRC} ${.TARGET}
+
+SYM_MAPS+= ${LIBC_SRCTOP}/stdlib/Symbol.map
+
+# machine-dependent stdlib sources
+.sinclude "${LIBC_SRCTOP}/${LIBC_ARCH}/stdlib/Makefile.inc"
+
+MAN+= a64l.3 abort.3 abs.3 alloca.3 atexit.3 atof.3 \
+ atoi.3 atol.3 at_quick_exit.3 bsearch.3 \
+ div.3 exit.3 getenv.3 getopt.3 getopt_long.3 getsubopt.3 \
+ hcreate.3 imaxabs.3 imaxdiv.3 insque.3 labs.3 ldiv.3 llabs.3 lldiv.3 \
+ lsearch.3 memory.3 ptsname.3 qsort.3 \
+ quick_exit.3 \
+ radixsort.3 rand.3 random.3 reallocarray.3 reallocf.3 \
+ realpath.3 strfmon.3 strtod.3 strtol.3 strtonum.3 strtoul.3 system.3 \
+ tsearch.3
+
+MLINKS+=a64l.3 l64a.3 a64l.3 l64a_r.3
+MLINKS+=atol.3 atoll.3
+MLINKS+=exit.3 _Exit.3
+MLINKS+=getenv.3 putenv.3 getenv.3 setenv.3 getenv.3 unsetenv.3
+MLINKS+=getopt_long.3 getopt_long_only.3
+MLINKS+=hcreate.3 hdestroy.3 hcreate.3 hsearch.3
+MLINKS+=hcreate.3 hcreate_r.3 hcreate.3 hdestroy_r.3 hcreate.3 hsearch_r.3
+MLINKS+=insque.3 remque.3
+MLINKS+=lsearch.3 lfind.3
+MLINKS+=ptsname.3 grantpt.3 ptsname.3 unlockpt.3
+MLINKS+=qsort.3 heapsort.3 qsort.3 mergesort.3 qsort.3 qsort_r.3
+MLINKS+=rand.3 rand_r.3 rand.3 srand.3 rand.3 sranddev.3
+MLINKS+=random.3 initstate.3 random.3 setstate.3 random.3 srandom.3 \
+ random.3 srandomdev.3
+MLINKS+=radixsort.3 sradixsort.3
+MLINKS+=strfmon.3 strfmon_l.3
+MLINKS+=strtod.3 strtof.3 strtod.3 strtold.3
+MLINKS+=strtol.3 strtoll.3 strtol.3 strtoq.3 strtol.3 strtoimax.3
+MLINKS+=strtoul.3 strtoull.3 strtoul.3 strtouq.3 strtoul.3 strtoumax.3
+MLINKS+=tsearch.3 tdelete.3 tsearch.3 tfind.3 tsearch.3 twalk.3
diff --git a/lib/libc/stdlib/Symbol.map b/lib/libc/stdlib/Symbol.map
new file mode 100644
index 000000000000..a239a42018d6
--- /dev/null
+++ b/lib/libc/stdlib/Symbol.map
@@ -0,0 +1,129 @@
+/*
+ * $FreeBSD$
+ */
+
+FBSD_1.0 {
+ _Exit;
+ a64l;
+ abort;
+ abs;
+ atexit;
+ __cxa_atexit;
+ __cxa_finalize;
+ atof;
+ atoi;
+ atol;
+ atoll;
+ bsearch;
+ div;
+ __isthreaded;
+ exit;
+ getenv;
+ opterr;
+ optind;
+ optopt;
+ optreset;
+ optarg;
+ getopt;
+ getopt_long;
+ getopt_long_only;
+ suboptarg;
+ getsubopt;
+ grantpt;
+ ptsname;
+ unlockpt;
+ hcreate;
+ hdestroy;
+ hsearch;
+ heapsort;
+ imaxabs;
+ imaxdiv;
+ insque;
+ l64a;
+ l64a_r;
+ labs;
+ ldiv;
+ llabs;
+ lldiv;
+ lsearch;
+ lfind;
+ mergesort;
+ putenv;
+ qsort_r;
+ qsort;
+ radixsort;
+ sradixsort;
+ rand_r;
+ rand;
+ srand;
+ sranddev;
+ srandom;
+ srandomdev;
+ initstate;
+ setstate;
+ random;
+ reallocf;
+ realpath;
+ remque;
+ setenv;
+ unsetenv;
+ strfmon;
+ strtoimax;
+ strtol;
+ strtoll;
+ strtonum;
+ strtoq;
+ strtoul;
+ strtoull;
+ strtoumax;
+ strtouq;
+ system;
+ tdelete;
+ tfind;
+ tsearch;
+ twalk;
+};
+
+FBSD_1.3 {
+ at_quick_exit;
+ atof_l;
+ atoi_l;
+ atol_l;
+ atoll_l;
+ quick_exit;
+ strtod_l;
+ strtof_l;
+ strtoimax_l;
+ strtol_l;
+ strtold_l;
+ strtoll_l;
+ strtoq_l;
+ strtoul_l;
+ strtoull_l;
+ strtoumax_l;
+ strtouq_l;
+};
+
+FBSD_1.4 {
+ atexit_b;
+ bsearch_b;
+ heapsort_b;
+ mergesort_b;
+ qsort_b;
+ hcreate_r;
+ hdestroy_r;
+ hsearch_r;
+ reallocarray;
+};
+
+FBSD_1.5 {
+ __cxa_thread_atexit;
+ __cxa_thread_atexit_impl;
+};
+
+FBSDprivate_1.0 {
+ __system;
+ _system;
+ __libc_system;
+ __cxa_thread_call_dtors;
+};
diff --git a/lib/libc/stdlib/_Exit.c b/lib/libc/stdlib/_Exit.c
new file mode 100644
index 000000000000..e7f0f5104f93
--- /dev/null
+++ b/lib/libc/stdlib/_Exit.c
@@ -0,0 +1,22 @@
+/*
+ * This file is in the public domain. Written by Garrett A. Wollman,
+ * 2002-09-07.
+ *
+ * $FreeBSD$
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+
+/*
+ * ISO C99 added this function to provide for Standard C applications
+ * which needed something like POSIX _exit(). A new interface was created
+ * in case it turned out that _exit() was insufficient to meet the
+ * requirements of ISO C. (That's probably not the case, but here
+ * is where you would put the extra code if it were.)
+ */
+void
+_Exit(int code)
+{
+ _exit(code);
+}
diff --git a/lib/libc/stdlib/a64l.3 b/lib/libc/stdlib/a64l.3
new file mode 100644
index 000000000000..eadc2f393460
--- /dev/null
+++ b/lib/libc/stdlib/a64l.3
@@ -0,0 +1,187 @@
+.\" Copyright (c) 2005 Tom Rhodes
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" Portions of this text are reprinted and reproduced in electronic form
+.\" from IEEE Std 1003.1, 2004 Edition, Standard for Information Technology --
+.\" Portable Operating System Interface (POSIX), The Open Group Base
+.\" Specifications Issue 6, Copyright (C) 2001-2004 by the Institute of
+.\" Electrical and Electronics Engineers, Inc and The Open Group. In the
+.\" event of any discrepancy between this version and the original IEEE and
+.\" The Open Group Standard, the original IEEE and The Open Group Standard is
+.\" the referee document. The original Standard can be obtained online at
+.\" http://www.opengroup.org/unix/online.html.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd November 20, 2005
+.Dt A64L 3
+.Os
+.Sh NAME
+.Nm a64l ,
+.Nm l64a ,
+.Nm l64a_r
+.Nd "convert between a long integer and a base-64 ASCII string"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft long
+.Fn a64l "const char *s"
+.Ft char *
+.Fn l64a "long int l"
+.Ft int
+.Fn l64a_r "long int l" "char *buffer" "int buflen"
+.Sh DESCRIPTION
+These functions are used to maintain numbers stored in radix-64
+.Tn ASCII
+characters.
+This is a notation by which 32-bit integers can be represented by
+up to six characters; each character represents a digit in
+radix-64 notation.
+If the type long contains more than 32 bits, only the low-order
+32 bits are used for these operations.
+.Pp
+The characters used to represent
+.Dq digits
+are
+.Ql .\&
+for 0,
+.Ql /
+for 1,
+.Ql 0
+-
+.Ql 9
+for 2 - 11,
+.Ql A
+-
+.Ql Z
+for 12 - 37, and
+.Ql a
+-
+.Ql z
+for 38 - 63.
+.Pp
+The
+.Fn a64l
+function takes a pointer to a radix-64 representation, in which the first
+digit is the least significant, and returns a corresponding
+.Vt long
+value.
+If the string pointed to by
+.Fa s
+contains more than six characters,
+.Fn a64l
+uses the first six.
+If the first six characters of the string contain a null terminator,
+.Fn a64l
+uses only characters preceding the null terminator.
+The
+.Fn a64l
+function scans the character string from left to right with the least
+significant digit on the left, decoding each character as a 6-bit
+radix-64 number.
+If the type long contains more than 32 bits, the resulting value is
+sign-extended.
+The behavior of
+.Fn a64l
+is unspecified if
+.Fa s
+is a null pointer or the string pointed to by
+.Fa s
+was not generated by a previous call to
+.Fn l64a .
+.Pp
+The
+.Fn l64a
+function takes a
+.Vt long
+argument and returns a pointer to the corresponding
+radix-64 representation.
+The behavior of
+.Fn l64a
+is unspecified if value is negative.
+.Pp
+The value returned by
+.Fn l64a
+is a pointer into a static buffer.
+Subsequent calls to
+.Fn l64a
+may overwrite the buffer.
+.Pp
+The
+.Fn l64a_r
+function performs a conversion identical to that of
+.Fn l64a
+and stores the resulting representation in the memory area pointed to by
+.Fa buffer ,
+consuming at most
+.Fa buflen
+characters including the terminating
+.Dv NUL
+character.
+.Sh RETURN VALUES
+On successful completion,
+.Fn a64l
+returns the
+.Vt long
+value resulting from conversion of the input string.
+If a string pointed to by
+.Fa s
+is an empty string,
+.Fn a64l
+returns 0.
+.Pp
+The
+.Fn l64a
+function returns a pointer to the radix-64 representation.
+If value is 0,
+.Fn l64a
+returns a pointer to an empty string.
+.Sh SEE ALSO
+.Xr strtoul 3
+.Sh HISTORY
+The
+.Fn a64l ,
+.Fn l64a ,
+and
+.Fn l64a_r
+functions are derived from
+.Nx
+with modifications.
+They appeared in
+.Fx 6.1 .
+.Sh AUTHORS
+The
+.Fn a64l ,
+.Fn l64a ,
+and
+.Fn l64a_r
+functions
+were added to
+.Fx
+by
+.An Tom Rhodes Aq Mt trhodes@FreeBSD.org .
+Almost all of this manual page came from the
+.Tn POSIX
+standard.
diff --git a/lib/libc/stdlib/a64l.c b/lib/libc/stdlib/a64l.c
new file mode 100644
index 000000000000..a130dcb24bf5
--- /dev/null
+++ b/lib/libc/stdlib/a64l.c
@@ -0,0 +1,46 @@
+/*-
+ * Written by J.T. Conklin <jtc@netbsd.org>.
+ * Public domain.
+ */
+
+#if 0
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: a64l.c,v 1.8 2000/01/22 22:19:19 mycroft Exp $");
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdlib.h>
+#include <inttypes.h>
+
+#define ADOT 46 /* ASCII '.' */
+#define ASLASH 47 /* ASCII '/' */
+#define A0 48 /* ASCII '0' */
+#define AA 65 /* ASCII 'A' */
+#define Aa 97 /* ASCII 'a' */
+
+long
+a64l(const char *s)
+{
+ long shift;
+ int digit, i, value;
+
+ value = 0;
+ shift = 0;
+ for (i = 0; *s != '\0' && i < 6; i++, s++) {
+ if (*s <= ASLASH)
+ digit = *s - ASLASH + 1;
+ else if (*s <= A0 + 9)
+ digit = *s - A0 + 2;
+ else if (*s <= AA + 25)
+ digit = *s - AA + 12;
+ else
+ digit = *s - Aa + 38;
+
+ value |= digit << shift;
+ shift += 6;
+ }
+ return (value);
+}
diff --git a/lib/libc/stdlib/abort.3 b/lib/libc/stdlib/abort.3
new file mode 100644
index 000000000000..e177137849a1
--- /dev/null
+++ b/lib/libc/stdlib/abort.3
@@ -0,0 +1,79 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)abort.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt ABORT 3
+.Os
+.Sh NAME
+.Nm abort
+.Nd cause abnormal program termination
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft void
+.Fn abort void
+.Sh DESCRIPTION
+The
+.Fn abort
+function causes abnormal program termination to occur, unless the
+signal
+.Dv SIGABRT
+is being caught and the signal handler does not return.
+.Pp
+Any open streams are flushed and closed.
+.Sh IMPLEMENTATION NOTES
+The
+.Fn abort
+function is thread-safe.
+It is unknown if it is async-cancel-safe.
+.Sh RETURN VALUES
+The
+.Fn abort
+function
+never returns.
+.Sh SEE ALSO
+.Xr sigaction 2 ,
+.Xr exit 3
+.Sh STANDARDS
+The
+.Fn abort
+function
+conforms to
+.St -p1003.1-90 .
+The
+.Fn abort
+function also conforms to
+.St -isoC-99
+with the implementation specific details as noted above.
diff --git a/lib/libc/stdlib/abort.c b/lib/libc/stdlib/abort.c
new file mode 100644
index 000000000000..2335c400da77
--- /dev/null
+++ b/lib/libc/stdlib/abort.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 1985, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)abort.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <signal.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <pthread.h>
+#include "un-namespace.h"
+
+#include "libc_private.h"
+
+void
+abort(void)
+{
+ struct sigaction act;
+
+ /*
+ * POSIX requires we flush stdio buffers on abort.
+ * XXX ISO C requires that abort() be async-signal-safe.
+ */
+ if (__cleanup)
+ (*__cleanup)();
+
+ sigfillset(&act.sa_mask);
+ /*
+ * Don't block SIGABRT to give any handler a chance; we ignore
+ * any errors -- ISO C doesn't allow abort to return anyway.
+ */
+ sigdelset(&act.sa_mask, SIGABRT);
+ (void)__libc_sigprocmask(SIG_SETMASK, &act.sa_mask, NULL);
+ (void)raise(SIGABRT);
+
+ /*
+ * If SIGABRT was ignored, or caught and the handler returns, do
+ * it again, only harder.
+ */
+ act.sa_handler = SIG_DFL;
+ act.sa_flags = 0;
+ sigfillset(&act.sa_mask);
+ (void)__libc_sigaction(SIGABRT, &act, NULL);
+ sigdelset(&act.sa_mask, SIGABRT);
+ (void)__libc_sigprocmask(SIG_SETMASK, &act.sa_mask, NULL);
+ (void)raise(SIGABRT);
+ exit(1);
+}
diff --git a/lib/libc/stdlib/abs.3 b/lib/libc/stdlib/abs.3
new file mode 100644
index 000000000000..eca85e1e7a59
--- /dev/null
+++ b/lib/libc/stdlib/abs.3
@@ -0,0 +1,75 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)abs.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd November 14, 2001
+.Dt ABS 3
+.Os
+.Sh NAME
+.Nm abs
+.Nd integer absolute value function
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft int
+.Fn abs "int j"
+.Sh DESCRIPTION
+The
+.Fn abs
+function
+computes
+the absolute value of the integer
+.Fa j .
+.Sh RETURN VALUES
+The
+.Fn abs
+function
+returns
+the absolute value.
+.Sh SEE ALSO
+.Xr cabs 3 ,
+.Xr fabs 3 ,
+.Xr floor 3 ,
+.Xr hypot 3 ,
+.Xr imaxabs 3 ,
+.Xr labs 3 ,
+.Xr llabs 3 ,
+.Xr math 3
+.Sh STANDARDS
+The
+.Fn abs
+function conforms to
+.St -isoC-99 .
+.Sh BUGS
+The absolute value of the most negative integer remains negative.
diff --git a/lib/libc/stdlib/abs.c b/lib/libc/stdlib/abs.c
new file mode 100644
index 000000000000..367b114f745d
--- /dev/null
+++ b/lib/libc/stdlib/abs.c
@@ -0,0 +1,42 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)abs.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdlib.h>
+
+int
+abs(int j)
+{
+ return(j < 0 ? -j : j);
+}
diff --git a/lib/libc/stdlib/alloca.3 b/lib/libc/stdlib/alloca.3
new file mode 100644
index 000000000000..38f5aee3a797
--- /dev/null
+++ b/lib/libc/stdlib/alloca.3
@@ -0,0 +1,88 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)alloca.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd September 5, 2006
+.Dt ALLOCA 3
+.Os
+.Sh NAME
+.Nm alloca
+.Nd memory allocator
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft void *
+.Fn alloca "size_t size"
+.Sh DESCRIPTION
+The
+.Fn alloca
+function
+allocates
+.Fa size
+bytes of space in the stack frame of the caller.
+This temporary space is automatically freed on
+return.
+.Sh RETURN VALUES
+The
+.Fn alloca
+function returns a pointer to the beginning of the allocated space.
+.Sh SEE ALSO
+.Xr brk 2 ,
+.Xr calloc 3 ,
+.Xr getpagesize 3 ,
+.Xr malloc 3 ,
+.Xr realloc 3
+.Sh HISTORY
+The
+.Fn alloca
+function appeared in
+.At 32v .
+.\" .Bx ?? .
+.\" The function appeared in 32v, pwb and pwb.2 and in 3bsd 4bsd
+.\" The first man page (or link to a man page that I can find at the
+.\" moment is 4.3...
+.Sh BUGS
+The
+.Fn alloca
+function
+is machine and compiler dependent;
+its use is discouraged.
+.Pp
+The
+.Fn alloca
+function is slightly unsafe because it cannot ensure that the pointer
+returned points to a valid and usable block of memory.
+The allocation made may exceed the bounds of the stack, or even go
+further into other objects in memory, and
+.Fn alloca
+cannot determine such an error.
+Avoid
+.Fn alloca
+with large unbounded allocations.
diff --git a/lib/libc/stdlib/at_quick_exit.3 b/lib/libc/stdlib/at_quick_exit.3
new file mode 100644
index 000000000000..c43015402582
--- /dev/null
+++ b/lib/libc/stdlib/at_quick_exit.3
@@ -0,0 +1,62 @@
+.\" Copyright (c) 2011 David Chisnall
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd December 7, 2011
+.Dt AT_QUICK_EXIT 3
+.Os
+.Sh NAME
+.Nm at_quick_exit
+.Nd registers a cleanup function to run on quick exit
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft int
+.Fn at_quick_exit "void (*func)(void)"
+.Sh DESCRIPTION
+The
+.Fn at_quick_exit
+function registers a cleanup function to be called when the program exits as a
+result of calling
+.Xr quick_exit 3 .
+The cleanup functions are called in the reverse order and will not be called if
+the program exits by calling
+.Xr exit 3 ,
+.Xr _Exit 3 ,
+or
+.Xr abort 3 .
+.Sh RETURN VALUES
+The
+.Fn at_quick_exit
+function returns the value 0 if successful and a non-zero value on failure.
+.Sh SEE ALSO
+.Xr exit 3 ,
+.Xr quick_exit 3
+.Sh STANDARDS
+The
+.Fn at_quick_exit
+function conforms to
+.St -isoC-2011 .
diff --git a/lib/libc/stdlib/atexit.3 b/lib/libc/stdlib/atexit.3
new file mode 100644
index 000000000000..3cdc59fed862
--- /dev/null
+++ b/lib/libc/stdlib/atexit.3
@@ -0,0 +1,103 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek and the American National Standards Committee X3,
+.\" on Information Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)atexit.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd September 6, 2002
+.Dt ATEXIT 3
+.Os
+.Sh NAME
+.Nm atexit
+.Nd register a function to be called on exit
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft int
+.Fn atexit "void (*function)(void)"
+.Ft int
+.Fn atexit_b "void (^function)(void)"
+.Sh DESCRIPTION
+The
+.Fn atexit
+function
+registers the given
+.Fa function
+to be called at program exit, whether via
+.Xr exit 3
+or via return from the program's
+.Fn main .
+Functions so registered are called in reverse order;
+no arguments are passed.
+.Pp
+These functions must not call
+.Fn exit ;
+if it should be necessary to terminate the process while in such a
+function, the
+.Xr _exit 2
+function should be used.
+(Alternatively, the function may cause abnormal
+process termination, for example by calling
+.Xr abort 3 . )
+.Pp
+At least 32 functions can always be registered,
+and more are allowed as long as sufficient memory can be allocated.
+.Pp
+The
+.Fn atexit_b
+function behaves identically to
+.Fn atexit ,
+except that it takes a block, rather than a function pointer.
+.\" XXX {ATEXIT_MAX} is not implemented yet
+.Sh RETURN VALUES
+.Rv -std atexit
+.Sh ERRORS
+.Bl -tag -width Er
+.It Bq Er ENOMEM
+No memory was available to add the function to the list.
+The existing list of functions is unmodified.
+.It Bq Er ENOSYS
+The
+.Fn atexit_b
+function was called by a program that did not supply a
+.Fn _Block_copy
+implementation.
+.El
+.Sh SEE ALSO
+.Xr at_quick_exit 3 ,
+.Xr exit 3
+.Sh STANDARDS
+The
+.Fn atexit
+function
+conforms to
+.St -isoC .
diff --git a/lib/libc/stdlib/atexit.c b/lib/libc/stdlib/atexit.c
new file mode 100644
index 000000000000..eda57032f670
--- /dev/null
+++ b/lib/libc/stdlib/atexit.c
@@ -0,0 +1,247 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)atexit.c 8.2 (Berkeley) 7/3/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <errno.h>
+#include <link.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pthread.h>
+#include "atexit.h"
+#include "un-namespace.h"
+#include "block_abi.h"
+
+#include "libc_private.h"
+
+/**
+ * The _Block_copy() function is provided by the block runtime.
+ */
+__attribute__((weak)) void*
+_Block_copy(void*);
+
+#define ATEXIT_FN_EMPTY 0
+#define ATEXIT_FN_STD 1
+#define ATEXIT_FN_CXA 2
+
+static pthread_mutex_t atexit_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+#define _MUTEX_LOCK(x) if (__isthreaded) _pthread_mutex_lock(x)
+#define _MUTEX_UNLOCK(x) if (__isthreaded) _pthread_mutex_unlock(x)
+#define _MUTEX_DESTROY(x) if (__isthreaded) _pthread_mutex_destroy(x)
+
+struct atexit {
+ struct atexit *next; /* next in list */
+ int ind; /* next index in this table */
+ struct atexit_fn {
+ int fn_type; /* ATEXIT_? from above */
+ union {
+ void (*std_func)(void);
+ void (*cxa_func)(void *);
+ } fn_ptr; /* function pointer */
+ void *fn_arg; /* argument for CXA callback */
+ void *fn_dso; /* shared module handle */
+ } fns[ATEXIT_SIZE]; /* the table itself */
+};
+
+static struct atexit *__atexit; /* points to head of LIFO stack */
+typedef DECLARE_BLOCK(void, atexit_block, void);
+
+int atexit_b(atexit_block);
+int __cxa_atexit(void (*)(void *), void *, void *);
+
+/*
+ * Register the function described by 'fptr' to be called at application
+ * exit or owning shared object unload time. This is a helper function
+ * for atexit and __cxa_atexit.
+ */
+static int
+atexit_register(struct atexit_fn *fptr)
+{
+ static struct atexit __atexit0; /* one guaranteed table */
+ struct atexit *p;
+
+ _MUTEX_LOCK(&atexit_mutex);
+ if ((p = __atexit) == NULL)
+ __atexit = p = &__atexit0;
+ else while (p->ind >= ATEXIT_SIZE) {
+ struct atexit *old__atexit;
+ old__atexit = __atexit;
+ _MUTEX_UNLOCK(&atexit_mutex);
+ if ((p = (struct atexit *)malloc(sizeof(*p))) == NULL)
+ return (-1);
+ _MUTEX_LOCK(&atexit_mutex);
+ if (old__atexit != __atexit) {
+ /* Lost race, retry operation */
+ _MUTEX_UNLOCK(&atexit_mutex);
+ free(p);
+ _MUTEX_LOCK(&atexit_mutex);
+ p = __atexit;
+ continue;
+ }
+ p->ind = 0;
+ p->next = __atexit;
+ __atexit = p;
+ }
+ p->fns[p->ind++] = *fptr;
+ _MUTEX_UNLOCK(&atexit_mutex);
+ return 0;
+}
+
+/*
+ * Register a function to be performed at exit.
+ */
+int
+atexit(void (*func)(void))
+{
+ struct atexit_fn fn;
+ int error;
+
+ fn.fn_type = ATEXIT_FN_STD;
+ fn.fn_ptr.std_func = func;
+ fn.fn_arg = NULL;
+ fn.fn_dso = NULL;
+
+ error = atexit_register(&fn);
+ return (error);
+}
+
+/**
+ * Register a block to be performed at exit.
+ */
+int
+atexit_b(atexit_block func)
+{
+ struct atexit_fn fn;
+ int error;
+ if (_Block_copy == 0) {
+ errno = ENOSYS;
+ return -1;
+ }
+ func = _Block_copy(func);
+
+ // Blocks are not C++ destructors, but they have the same signature (a
+ // single void* parameter), so we can pretend that they are.
+ fn.fn_type = ATEXIT_FN_CXA;
+ fn.fn_ptr.cxa_func = (void(*)(void*))GET_BLOCK_FUNCTION(func);
+ fn.fn_arg = func;
+ fn.fn_dso = NULL;
+
+ error = atexit_register(&fn);
+ return (error);
+}
+
+/*
+ * Register a function to be performed at exit or when an shared object
+ * with given dso handle is unloaded dynamically.
+ */
+int
+__cxa_atexit(void (*func)(void *), void *arg, void *dso)
+{
+ struct atexit_fn fn;
+ int error;
+
+ fn.fn_type = ATEXIT_FN_CXA;
+ fn.fn_ptr.cxa_func = func;
+ fn.fn_arg = arg;
+ fn.fn_dso = dso;
+
+ error = atexit_register(&fn);
+ return (error);
+}
+
+#pragma weak __pthread_cxa_finalize
+void __pthread_cxa_finalize(const struct dl_phdr_info *);
+
+static int global_exit;
+
+/*
+ * Call all handlers registered with __cxa_atexit for the shared
+ * object owning 'dso'. Note: if 'dso' is NULL, then all remaining
+ * handlers are called.
+ */
+void
+__cxa_finalize(void *dso)
+{
+ struct dl_phdr_info phdr_info;
+ struct atexit *p;
+ struct atexit_fn fn;
+ int n, has_phdr;
+
+ if (dso != NULL) {
+ has_phdr = _rtld_addr_phdr(dso, &phdr_info);
+ } else {
+ has_phdr = 0;
+ global_exit = 1;
+ }
+
+ _MUTEX_LOCK(&atexit_mutex);
+ for (p = __atexit; p; p = p->next) {
+ for (n = p->ind; --n >= 0;) {
+ if (p->fns[n].fn_type == ATEXIT_FN_EMPTY)
+ continue; /* already been called */
+ fn = p->fns[n];
+ if (dso != NULL && dso != fn.fn_dso) {
+ /* wrong DSO ? */
+ if (!has_phdr || global_exit ||
+ !__elf_phdr_match_addr(&phdr_info,
+ fn.fn_ptr.cxa_func))
+ continue;
+ }
+ /*
+ Mark entry to indicate that this particular handler
+ has already been called.
+ */
+ p->fns[n].fn_type = ATEXIT_FN_EMPTY;
+ _MUTEX_UNLOCK(&atexit_mutex);
+
+ /* Call the function of correct type. */
+ if (fn.fn_type == ATEXIT_FN_CXA)
+ fn.fn_ptr.cxa_func(fn.fn_arg);
+ else if (fn.fn_type == ATEXIT_FN_STD)
+ fn.fn_ptr.std_func();
+ _MUTEX_LOCK(&atexit_mutex);
+ }
+ }
+ _MUTEX_UNLOCK(&atexit_mutex);
+ if (dso == NULL)
+ _MUTEX_DESTROY(&atexit_mutex);
+
+ if (has_phdr && !global_exit && &__pthread_cxa_finalize != NULL)
+ __pthread_cxa_finalize(&phdr_info);
+}
diff --git a/lib/libc/stdlib/atexit.h b/lib/libc/stdlib/atexit.h
new file mode 100644
index 000000000000..29610676edaa
--- /dev/null
+++ b/lib/libc/stdlib/atexit.h
@@ -0,0 +1,36 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)atexit.h 8.2 (Berkeley) 7/3/94
+ * $FreeBSD$
+ */
+
+/* must be at least 32 to guarantee ANSI conformance */
+#define ATEXIT_SIZE 32
+
+void __cxa_finalize(void *dso);
diff --git a/lib/libc/stdlib/atof.3 b/lib/libc/stdlib/atof.3
new file mode 100644
index 000000000000..b02cf0277656
--- /dev/null
+++ b/lib/libc/stdlib/atof.3
@@ -0,0 +1,95 @@
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)atof.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt ATOF 3
+.Os
+.Sh NAME
+.Nm atof
+.Nd convert
+.Tn ASCII
+string to double
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft double
+.Fn atof "const char *nptr"
+.Sh DESCRIPTION
+The
+.Fn atof
+function converts the initial portion of the string pointed to by
+.Fa nptr
+to
+.Vt double
+representation.
+.Pp
+It is equivalent to:
+.Bd -literal -offset indent
+strtod(nptr, (char **)NULL);
+.Ed
+.Pp
+The decimal point
+character is defined in the program's locale (category
+.Dv LC_NUMERIC ) .
+.Sh IMPLEMENTATION NOTES
+The
+.Fn atof
+function is not thread-safe and also not async-cancel-safe.
+.Pp
+The
+.Fn atof
+function has been deprecated by
+.Fn strtod
+and should not be used in new code.
+.Sh ERRORS
+The function
+.Fn atof
+need not affect the value of
+.Va errno
+on an error.
+.Sh SEE ALSO
+.Xr atoi 3 ,
+.Xr atol 3 ,
+.Xr strtod 3 ,
+.Xr strtol 3 ,
+.Xr strtoul 3
+.Sh STANDARDS
+The
+.Fn atof
+function conforms to
+.St -p1003.1-90 ,
+.St -isoC ,
+and
+.St -isoC-99 .
diff --git a/lib/libc/stdlib/atof.c b/lib/libc/stdlib/atof.c
new file mode 100644
index 000000000000..0458eb968331
--- /dev/null
+++ b/lib/libc/stdlib/atof.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)atof.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdlib.h>
+#include <xlocale.h>
+
+double
+atof(const char *ascii)
+{
+ return strtod(ascii, (char **)NULL);
+}
+
+double
+atof_l(const char *ascii, locale_t locale)
+{
+ return strtod_l(ascii, (char **)NULL, locale);
+}
diff --git a/lib/libc/stdlib/atoi.3 b/lib/libc/stdlib/atoi.3
new file mode 100644
index 000000000000..025019f4bfea
--- /dev/null
+++ b/lib/libc/stdlib/atoi.3
@@ -0,0 +1,87 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)atoi.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt ATOI 3
+.Os
+.Sh NAME
+.Nm atoi
+.Nd convert
+.Tn ASCII
+string to integer
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft int
+.Fn atoi "const char *nptr"
+.Sh DESCRIPTION
+The
+.Fn atoi
+function converts the initial portion of the string pointed to by
+.Fa nptr
+to
+.Vt int
+representation.
+.Pp
+It is equivalent to:
+.Bd -literal -offset indent
+(int)strtol(nptr, (char **)NULL, 10);
+.Ed
+.Pp
+The
+.Fn atoi
+function has been deprecated by
+.Fn strtol
+and should not be used in new code.
+.Sh ERRORS
+The function
+.Fn atoi
+need not affect the value of
+.Va errno
+on an error.
+.Sh SEE ALSO
+.Xr atof 3 ,
+.Xr atol 3 ,
+.Xr strtod 3 ,
+.Xr strtol 3 ,
+.Xr strtoul 3
+.Sh STANDARDS
+The
+.Fn atoi
+function conforms to
+.St -p1003.1-90 ,
+.St -isoC ,
+and
+.St -isoC-99 .
diff --git a/lib/libc/stdlib/atoi.c b/lib/libc/stdlib/atoi.c
new file mode 100644
index 000000000000..9f92fcdad4be
--- /dev/null
+++ b/lib/libc/stdlib/atoi.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)atoi.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdlib.h>
+#include <xlocale.h>
+
+int
+atoi(const char *str)
+{
+ return (int)strtol(str, (char **)NULL, 10);
+}
+
+int
+atoi_l(const char *str, locale_t locale)
+{
+ return (int)strtol_l(str, (char **)NULL, 10, locale);
+}
diff --git a/lib/libc/stdlib/atol.3 b/lib/libc/stdlib/atol.3
new file mode 100644
index 000000000000..e2ac0e54a35c
--- /dev/null
+++ b/lib/libc/stdlib/atol.3
@@ -0,0 +1,135 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)atol.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd May 14, 2013
+.Dt ATOL 3
+.Os
+.Sh NAME
+.Nm atol , atoll
+.Nd convert
+.Tn ASCII
+string to
+.Vt long
+or
+.Vt "long long"
+integer
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft long
+.Fn atol "const char *nptr"
+.Ft "long long"
+.Fn atoll "const char *nptr"
+.Sh DESCRIPTION
+The
+.Fn atol
+function converts the initial portion of the string pointed to by
+.Fa nptr
+to
+.Vt long
+integer
+representation.
+.Pp
+It is equivalent to:
+.Pp
+.Dl "strtol(nptr, (char **)NULL, 10);"
+.Pp
+The
+.Fn atoll
+function converts the initial portion of the string pointed to by
+.Fa nptr
+to
+.Vt "long long"
+integer
+representation.
+.Pp
+It is equivalent to:
+.Pp
+.Dl "strtoll(nptr, (char **)NULL, 10);"
+.Sh COMPATIBILITY
+The
+.Fx
+implementations of the
+.Fn atol
+and
+.Fn atoll
+functions are thin wrappers around
+.Fn strtol
+and
+.Fn strtoll
+respectively, so these functions will affect the value of
+.Va errno
+in the same way that the
+.Fn strtol
+and
+.Fn strtoll
+functions are able to.
+This behavior of
+.Fn atol
+and
+.Fn atoll
+is not required by
+.St -isoC
+or
+.St -isoC-99 ,
+but it is allowed by all of
+.St -isoC , St -isoC-99
+and
+.St -p1003.1-2001 .
+.Sh ERRORS
+The functions
+.Fn atol
+and
+.Fn atoll
+may affect the value of
+.Va errno
+on an error.
+.Sh SEE ALSO
+.Xr atof 3 ,
+.Xr atoi 3 ,
+.Xr strtod 3 ,
+.Xr strtol 3 ,
+.Xr strtoul 3
+.Sh STANDARDS
+The
+.Fn atol
+function
+conforms to
+.St -isoC .
+The
+.Fn atoll
+function
+conforms to
+.St -isoC-99 .
diff --git a/lib/libc/stdlib/atol.c b/lib/libc/stdlib/atol.c
new file mode 100644
index 000000000000..bd8ef07c544d
--- /dev/null
+++ b/lib/libc/stdlib/atol.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)atol.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdlib.h>
+#include <xlocale.h>
+
+long
+atol(const char *str)
+{
+ return strtol(str, (char **)NULL, 10);
+}
+
+long
+atol_l(const char *str, locale_t locale)
+{
+ return strtol_l(str, (char **)NULL, 10, locale);
+}
diff --git a/lib/libc/stdlib/atoll.c b/lib/libc/stdlib/atoll.c
new file mode 100644
index 000000000000..093fde5d9f91
--- /dev/null
+++ b/lib/libc/stdlib/atoll.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdlib.h>
+#include <xlocale.h>
+
+long long
+atoll(const char *str)
+{
+ return strtoll(str, (char **)NULL, 10);
+}
+
+long long
+atoll_l(const char *str, locale_t locale)
+{
+ return strtoll_l(str, (char **)NULL, 10, locale);
+}
diff --git a/lib/libc/stdlib/bsearch.3 b/lib/libc/stdlib/bsearch.3
new file mode 100644
index 000000000000..2fdf2c4842c0
--- /dev/null
+++ b/lib/libc/stdlib/bsearch.3
@@ -0,0 +1,95 @@
+.\" Copyright (c) 1990, 1991, 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)bsearch.3 8.3 (Berkeley) 4/19/94
+.\" $FreeBSD$
+.\"
+.Dd February 22, 2013
+.Dt BSEARCH 3
+.Os
+.Sh NAME
+.Nm bsearch
+.Nd binary search of a sorted table
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft void *
+.Fn bsearch "const void *key" "const void *base" "size_t nmemb" "size_t size" "int (*compar) (const void *, const void *)"
+.Sh DESCRIPTION
+The
+.Fn bsearch
+function searches an array of
+.Fa nmemb
+objects, the initial member of which is
+pointed to by
+.Fa base ,
+for a member that matches the object pointed to by
+.Fa key .
+The size of each member of the array is specified by
+.Fa size .
+.Pp
+The contents of the array should be in ascending sorted order according
+to the comparison function referenced by
+.Fa compar .
+The
+.Fa compar
+routine
+is expected to have
+two arguments which point to the
+.Fa key
+object and to an array member, in that order, and should return an integer
+less than, equal to, or greater than zero if the
+.Fa key
+object is found, respectively, to be less than, to match, or be
+greater than the array member.
+See the
+.Fa int_compare
+sample function in
+.Xr qsort 3
+for a comparison function that is also compatible with
+.Fn bsearch .
+.Sh RETURN VALUES
+The
+.Fn bsearch
+function returns a pointer to a matching member of the array, or a null
+pointer if no match is found.
+If two members compare as equal, which member is matched is unspecified.
+.Sh SEE ALSO
+.Xr db 3 ,
+.Xr lsearch 3 ,
+.Xr qsort 3
+.\" .Xr tsearch 3
+.Sh STANDARDS
+The
+.Fn bsearch
+function conforms to
+.St -isoC .
diff --git a/lib/libc/stdlib/bsearch.c b/lib/libc/stdlib/bsearch.c
new file mode 100644
index 000000000000..8303f971b562
--- /dev/null
+++ b/lib/libc/stdlib/bsearch.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)bsearch.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#ifdef I_AM_BSEARCH_B
+#include "block_abi.h"
+#define COMPAR(x,y) CALL_BLOCK(compar, x, y)
+#else
+#define COMPAR(x,y) compar(x, y)
+#endif
+
+/*
+ * Perform a binary search.
+ *
+ * The code below is a bit sneaky. After a comparison fails, we
+ * divide the work in half by moving either left or right. If lim
+ * is odd, moving left simply involves halving lim: e.g., when lim
+ * is 5 we look at item 2, so we change lim to 2 so that we will
+ * look at items 0 & 1. If lim is even, the same applies. If lim
+ * is odd, moving right again involes halving lim, this time moving
+ * the base up one item past p: e.g., when lim is 5 we change base
+ * to item 3 and make lim 2 so that we will look at items 3 and 4.
+ * If lim is even, however, we have to shrink it by one before
+ * halving: e.g., when lim is 4, we still looked at item 2, so we
+ * have to make lim 3, then halve, obtaining 1, so that we will only
+ * look at item 3.
+ */
+#ifdef I_AM_BSEARCH_B
+void *
+bsearch_b(const void *key, const void *base0, size_t nmemb, size_t size,
+ DECLARE_BLOCK(int, compar, const void *, const void *))
+#else
+void *
+bsearch(const void *key, const void *base0, size_t nmemb, size_t size,
+ int (*compar)(const void *, const void *))
+#endif
+{
+ const char *base = base0;
+ size_t lim;
+ int cmp;
+ const void *p;
+
+ for (lim = nmemb; lim != 0; lim >>= 1) {
+ p = base + (lim >> 1) * size;
+ cmp = COMPAR(key, p);
+ if (cmp == 0)
+ return ((void *)p);
+ if (cmp > 0) { /* key > p: move right */
+ base = (char *)p + size;
+ lim--;
+ } /* else move left */
+ }
+ return (NULL);
+}
diff --git a/lib/libc/stdlib/bsearch_b.c b/lib/libc/stdlib/bsearch_b.c
new file mode 100644
index 000000000000..393feba946ea
--- /dev/null
+++ b/lib/libc/stdlib/bsearch_b.c
@@ -0,0 +1,29 @@
+/*-
+ * Copyright (c) 2014 David Chisnall
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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$
+ */
+#define I_AM_BSEARCH_B
+#include "bsearch.c"
diff --git a/lib/libc/stdlib/cxa_thread_atexit.c b/lib/libc/stdlib/cxa_thread_atexit.c
new file mode 100644
index 000000000000..6f03ef0d3235
--- /dev/null
+++ b/lib/libc/stdlib/cxa_thread_atexit.c
@@ -0,0 +1,40 @@
+/*-
+ * Copyright (c) 2017 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Konstantin Belousov
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "libc_private.h"
+
+int
+__cxa_thread_atexit(void (*dtor_func)(void *), void *obj, void *dso_symbol)
+{
+
+ return (__cxa_thread_atexit_hidden(dtor_func, obj, dso_symbol));
+}
diff --git a/lib/libc/stdlib/cxa_thread_atexit_impl.c b/lib/libc/stdlib/cxa_thread_atexit_impl.c
new file mode 100644
index 000000000000..0f0a7a314fa9
--- /dev/null
+++ b/lib/libc/stdlib/cxa_thread_atexit_impl.c
@@ -0,0 +1,153 @@
+/*-
+ * Copyright (c) 2016 Mahdi Mokhtari <mokhi64@gmail.com>
+ * Copyright (c) 2016, 2017 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Konstantin Belousov
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/queue.h>
+#include "namespace.h"
+#include <errno.h>
+#include <link.h>
+#include <pthread.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+
+/*
+ * C++11 introduces the thread_local scope (like __thread with some
+ * additions). As a key-feature it should support non-trivial
+ * destructors, registered with __cxa_thread_atexit() to be executed
+ * at the thread termination.
+ *
+ * The implemention keeps a _Thread_local list of destructors per each
+ * thread, and calls __cxa_thread_call_dtors() on each thread's exit
+ * to do cleanup. For a thread calling exit(3), in particular, for
+ * the initial thread returning from main(), we call
+ * __cxa_thread_call_dtors() inside exit().
+ *
+ * It could be possible that a dynamically loaded library, use
+ * thread_local variable but is dlclose()'d before thread exit. The
+ * destructor of this variable will then try to access the address,
+ * for calling it but it's unloaded, so it'll crash. We're using
+ * __elf_phdr_match_addr() to detect and prevent such cases and so
+ * prevent the crash.
+ */
+
+#define CXA_DTORS_ITERATIONS 4
+
+struct cxa_thread_dtor {
+ void *obj;
+ void (*func)(void *);
+ void *dso;
+ LIST_ENTRY(cxa_thread_dtor) entry;
+};
+static _Thread_local LIST_HEAD(dtor_list, cxa_thread_dtor) dtors =
+ LIST_HEAD_INITIALIZER(dtors);
+
+int
+__cxa_thread_atexit_impl(void (*dtor_func)(void *), void *obj,
+ void *dso_symbol)
+{
+
+ return (__cxa_thread_atexit_hidden(dtor_func, obj, dso_symbol));
+}
+
+int
+__cxa_thread_atexit_hidden(void (*dtor_func)(void *), void *obj,
+ void *dso_symbol)
+{
+ struct cxa_thread_dtor *new_dtor;
+
+ new_dtor = malloc(sizeof(*new_dtor));
+ if (new_dtor == NULL) {
+ errno = ENOMEM; /* forcibly override malloc(3) error */
+ return (-1);
+ }
+
+ new_dtor->obj = obj;
+ new_dtor->func = dtor_func;
+ new_dtor->dso = dso_symbol;
+ LIST_INSERT_HEAD(&dtors, new_dtor, entry);
+ return (0);
+}
+
+static void
+walk_cb_call(struct cxa_thread_dtor *dtor)
+{
+ struct dl_phdr_info phdr_info;
+
+ if (_rtld_addr_phdr(dtor->dso, &phdr_info) &&
+ __elf_phdr_match_addr(&phdr_info, dtor->func))
+ dtor->func(dtor->obj);
+ else
+ fprintf(stderr, "__cxa_thread_call_dtors: dtr %p from "
+ "unloaded dso, skipping\n", (void *)(dtor->func));
+}
+
+static void
+walk_cb_nocall(struct cxa_thread_dtor *dtor __unused)
+{
+}
+
+static void
+cxa_thread_walk(void (*cb)(struct cxa_thread_dtor *))
+{
+ struct cxa_thread_dtor *dtor, *tdtor;
+
+ LIST_FOREACH_SAFE(dtor, &dtors, entry, tdtor) {
+ LIST_REMOVE(dtor, entry);
+ cb(dtor);
+ free(dtor);
+ }
+}
+
+/*
+ * This is the callback function we use to call destructors, once for
+ * each thread. It is called in exit(3) in libc/stdlib/exit.c and
+ * before exit_thread() in libthr/thread/thr_exit.c.
+ */
+void
+__cxa_thread_call_dtors(void)
+{
+ int i;
+
+ for (i = 0; i < CXA_DTORS_ITERATIONS && !LIST_EMPTY(&dtors); i++)
+ cxa_thread_walk(walk_cb_call);
+
+ if (!LIST_EMPTY(&dtors)) {
+ fprintf(stderr, "Thread %p is exiting with more "
+ "thread-specific dtors created after %d iterations "
+ "of destructor calls\n",
+ _pthread_self(), i);
+ cxa_thread_walk(walk_cb_nocall);
+ }
+}
diff --git a/lib/libc/stdlib/div.3 b/lib/libc/stdlib/div.3
new file mode 100644
index 000000000000..ddd92a008790
--- /dev/null
+++ b/lib/libc/stdlib/div.3
@@ -0,0 +1,68 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek.
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)div.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd November 14, 2001
+.Dt DIV 3
+.Os
+.Sh NAME
+.Nm div
+.Nd return quotient and remainder from division
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft div_t
+.Fn div "int num" "int denom"
+.Sh DESCRIPTION
+The
+.Fn div
+function
+computes the value
+.Fa num/denom
+and returns the quotient and remainder in a structure named
+.Fa div_t
+that contains two
+.Vt int
+members named
+.Va quot
+and
+.Va rem .
+.Sh SEE ALSO
+.Xr imaxdiv 3 ,
+.Xr ldiv 3 ,
+.Xr lldiv 3
+.Sh STANDARDS
+The
+.Fn div
+function
+conforms to
+.St -isoC-99 .
diff --git a/lib/libc/stdlib/div.c b/lib/libc/stdlib/div.c
new file mode 100644
index 000000000000..0bafbe607037
--- /dev/null
+++ b/lib/libc/stdlib/div.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)div.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdlib.h> /* div_t */
+
+div_t
+div(num, denom)
+ int num, denom;
+{
+ div_t r;
+
+ r.quot = num / denom;
+ r.rem = num % denom;
+#if !defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L)
+ /*
+ * The ANSI standard says that |r.quot| <= |n/d|, where
+ * n/d is to be computed in infinite precision. In other
+ * words, we should always truncate the quotient towards
+ * 0, never -infinity.
+ *
+ * Machine division and remainer may work either way when
+ * one or both of n or d is negative. If only one is
+ * negative and r.quot has been truncated towards -inf,
+ * r.rem will have the same sign as denom and the opposite
+ * sign of num; if both are negative and r.quot has been
+ * truncated towards -inf, r.rem will be positive (will
+ * have the opposite sign of num). These are considered
+ * `wrong'.
+ *
+ * If both are num and denom are positive, r will always
+ * be positive.
+ *
+ * This all boils down to:
+ * if num >= 0, but r.rem < 0, we got the wrong answer.
+ * In that case, to get the right answer, add 1 to r.quot and
+ * subtract denom from r.rem.
+ */
+ if (num >= 0 && r.rem < 0) {
+ r.quot++;
+ r.rem -= denom;
+ }
+#endif
+ return (r);
+}
diff --git a/lib/libc/stdlib/exit.3 b/lib/libc/stdlib/exit.3
new file mode 100644
index 000000000000..7d657c922ce9
--- /dev/null
+++ b/lib/libc/stdlib/exit.3
@@ -0,0 +1,132 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)exit.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd September 9, 2002
+.Dt EXIT 3
+.Os
+.Sh NAME
+.Nm exit , _Exit
+.Nd perform normal program termination
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft void
+.Fn exit "int status"
+.Ft void
+.Fn _Exit "int status"
+.Sh DESCRIPTION
+The
+.Fn exit
+and
+.Fn _Exit
+functions terminate a process.
+.Pp
+Before termination,
+.Fn exit
+performs the following functions in the order listed:
+.Bl -enum -offset indent
+.It
+Call the functions registered with the
+.Xr atexit 3
+function, in the reverse order of their registration.
+.It
+Flush all open output streams.
+.It
+Close all open streams.
+.It
+Unlink all files created with the
+.Xr tmpfile 3
+function.
+.El
+.Pp
+The
+.Fn _Exit
+function terminates without calling the functions registered with the
+.Xr atexit 3
+function, and may or may not perform the other actions listed.
+Both functions make the low-order eight bits of the
+.Fa status
+argument available to a parent process which has called a
+.Xr wait 2 Ns -family
+function.
+.Pp
+The C Standard
+.Pq St -isoC-99
+defines the values
+.Li 0 ,
+.Dv EXIT_SUCCESS ,
+and
+.Dv EXIT_FAILURE
+as possible values of
+.Fa status .
+Cooperating processes may use other values;
+in a program which might be called by a mail transfer agent, the
+values described in
+.Xr sysexits 3
+may be used to provide more information to the parent process.
+.Pp
+Note that
+.Fn exit
+does nothing to prevent bottomless recursion should a function registered
+using
+.Xr atexit 3
+itself call
+.Fn exit .
+Such functions must call
+.Fn _Exit
+instead (although this has other effects as well which may not be desired).
+.Sh RETURN VALUES
+The
+.Fn exit
+and
+.Fn _Exit
+functions
+never return.
+.Sh SEE ALSO
+.Xr _exit 2 ,
+.Xr wait 2 ,
+.Xr at_quick_exit 3 ,
+.Xr atexit 3 ,
+.Xr intro 3 ,
+.Xr quick_exit 3 ,
+.Xr sysexits 3 ,
+.Xr tmpfile 3
+.Sh STANDARDS
+The
+.Fn exit
+and
+.Fn _Exit
+functions conform to
+.St -isoC-99 .
diff --git a/lib/libc/stdlib/exit.c b/lib/libc/stdlib/exit.c
new file mode 100644
index 000000000000..521d05a554b1
--- /dev/null
+++ b/lib/libc/stdlib/exit.c
@@ -0,0 +1,76 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)exit.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <stdlib.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+#include "atexit.h"
+#include "libc_private.h"
+
+void (*__cleanup)(void);
+
+/*
+ * This variable is zero until a process has created a thread.
+ * It is used to avoid calling locking functions in libc when they
+ * are not required. By default, libc is intended to be(come)
+ * thread-safe, but without a (significant) penalty to non-threaded
+ * processes.
+ */
+int __isthreaded = 0;
+
+/*
+ * Exit, flushing stdio buffers if necessary.
+ */
+void
+exit(int status)
+{
+ /* Ensure that the auto-initialization routine is linked in: */
+ extern int _thread_autoinit_dummy_decl;
+
+ _thread_autoinit_dummy_decl = 1;
+
+ /*
+ * We're dealing with cleaning up thread_local destructors in the case of
+ * the process termination through main() exit.
+ * Other cases are handled elsewhere.
+ */
+ __cxa_thread_call_dtors();
+ __cxa_finalize(NULL);
+ if (__cleanup)
+ (*__cleanup)();
+ _exit(status);
+}
diff --git a/lib/libc/stdlib/getenv.3 b/lib/libc/stdlib/getenv.3
new file mode 100644
index 000000000000..e662b86d214b
--- /dev/null
+++ b/lib/libc/stdlib/getenv.3
@@ -0,0 +1,230 @@
+.\" Copyright (c) 1988, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)getenv.3 8.2 (Berkeley) 12/11/93
+.\" $FreeBSD$
+.\"
+.Dd June 20, 2007
+.Dt GETENV 3
+.Os
+.Sh NAME
+.Nm getenv ,
+.Nm putenv ,
+.Nm setenv ,
+.Nm unsetenv
+.Nd environment variable functions
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft char *
+.Fn getenv "const char *name"
+.Ft int
+.Fn setenv "const char *name" "const char *value" "int overwrite"
+.Ft int
+.Fn putenv "char *string"
+.Ft int
+.Fn unsetenv "const char *name"
+.Sh DESCRIPTION
+These functions set, unset and fetch environment variables from the
+host
+.Em environment list .
+.Pp
+The
+.Fn getenv
+function obtains the current value of the environment variable,
+.Fa name .
+The application should not modify the string pointed
+to by the
+.Fn getenv
+function.
+.Pp
+The
+.Fn setenv
+function inserts or resets the environment variable
+.Fa name
+in the current environment list.
+If the variable
+.Fa name
+does not exist in the list,
+it is inserted with the given
+.Fa value .
+If the variable does exist, the argument
+.Fa overwrite
+is tested; if
+.Fa overwrite
+is zero, the
+variable is not reset, otherwise it is reset
+to the given
+.Fa value .
+.Pp
+The
+.Fn putenv
+function takes an argument of the form ``name=value'' and
+puts it directly into the current environment,
+so altering the argument shall change the environment.
+If the variable
+.Fa name
+does not exist in the list,
+it is inserted with the given
+.Fa value .
+If the variable
+.Fa name
+does exist, it is reset to the given
+.Fa value .
+.Pp
+The
+.Fn unsetenv
+function
+deletes all instances of the variable name pointed to by
+.Fa name
+from the list.
+.Pp
+If corruption (e.g., a name without a value) is detected while making a copy of
+environ for internal usage, then
+.Fn setenv ,
+.Fn unsetenv
+and
+.Fn putenv
+will output a warning to stderr about the issue, drop the corrupt entry and
+complete the task without error.
+.Sh RETURN VALUES
+The
+.Fn getenv
+function returns the value of the environment variable as a
+.Dv NUL Ns
+-terminated string.
+If the variable
+.Fa name
+is not in the current environment,
+.Dv NULL
+is returned.
+.Pp
+.Rv -std setenv putenv unsetenv
+.Sh ERRORS
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The function
+.Fn getenv ,
+.Fn setenv
+or
+.Fn unsetenv
+failed because the
+.Fa name
+is a
+.Dv NULL
+pointer, points to an empty string, or points to a string containing an
+.Dq Li \&=
+character.
+.Pp
+The function
+.Fn putenv
+failed because
+.Fa string
+is a
+.Dv NULL
+pointer,
+.Fa string
+is without an
+.Dq Li \&=
+character or
+.Dq Li \&=
+is the first character in
+.Fa string .
+This does not follow the
+.Tn POSIX
+specification.
+.It Bq Er ENOMEM
+The function
+.Fn setenv ,
+.Fn unsetenv
+or
+.Fn putenv
+failed because they were unable to allocate memory for the environment.
+.El
+.Sh SEE ALSO
+.Xr csh 1 ,
+.Xr sh 1 ,
+.Xr execve 2 ,
+.Xr environ 7
+.Sh STANDARDS
+The
+.Fn getenv
+function conforms to
+.St -isoC .
+The
+.Fn setenv ,
+.Fn putenv
+and
+.Fn unsetenv
+functions conforms to
+.St -p1003.1-2001 .
+.Sh HISTORY
+The functions
+.Fn setenv
+and
+.Fn unsetenv
+appeared in
+.At v7 .
+The
+.Fn putenv
+function appeared in
+.Bx 4.3 Reno .
+.Pp
+Until
+.Fx 7.0 ,
+.Fn putenv
+would make a copy of
+.Fa string
+and insert it into the environment using
+.Fn setenv .
+This was changed to use
+.Fa string
+as the memory location of the ``name=value'' pair to follow the
+.Tn POSIX
+specification.
+.Sh BUGS
+Successive calls to
+.Fn setenv
+that assign a larger-sized
+.Fa value
+than any previous value to the same
+.Fa name
+will result in a memory leak.
+The
+.Fx
+semantics for this function
+(namely, that the contents of
+.Fa value
+are copied and that old values remain accessible indefinitely) make this
+bug unavoidable.
+Future versions may eliminate one or both of these
+semantic guarantees in order to fix the bug.
diff --git a/lib/libc/stdlib/getenv.c b/lib/libc/stdlib/getenv.c
new file mode 100644
index 000000000000..845110388a20
--- /dev/null
+++ b/lib/libc/stdlib/getenv.c
@@ -0,0 +1,691 @@
+/*-
+ * Copyright (c) 2007-2009 Sean C. Farley <scf@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer,
+ * without modification, immediately at the beginning of the file.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+
+static const char CorruptEnvFindMsg[] = "environment corrupt; unable to find ";
+static const char CorruptEnvValueMsg[] =
+ "environment corrupt; missing value for ";
+
+
+/*
+ * Standard environ. environ variable is exposed to entire process.
+ *
+ * origEnviron: Upon cleanup on unloading of library or failure, this
+ * allows environ to return to as it was before.
+ * environSize: Number of variables environ can hold. Can only
+ * increase.
+ * intEnviron: Internally-built environ. Exposed via environ during
+ * (re)builds of the environment.
+ */
+extern char **environ;
+static char **origEnviron;
+static char **intEnviron = NULL;
+static int environSize = 0;
+
+/*
+ * Array of environment variables built from environ. Each element records:
+ * name: Pointer to name=value string
+ * name length: Length of name not counting '=' character
+ * value: Pointer to value within same string as name
+ * value size: Size (not length) of space for value not counting the
+ * nul character
+ * active state: true/false value to signify whether variable is active.
+ * Useful since multiple variables with the same name can
+ * co-exist. At most, one variable can be active at any
+ * one time.
+ * putenv: Created from putenv() call. This memory must not be
+ * reused.
+ */
+static struct envVars {
+ size_t nameLen;
+ size_t valueSize;
+ char *name;
+ char *value;
+ bool active;
+ bool putenv;
+} *envVars = NULL;
+
+/*
+ * Environment array information.
+ *
+ * envActive: Number of active variables in array.
+ * envVarsSize: Size of array.
+ * envVarsTotal: Number of total variables in array (active or not).
+ */
+static int envActive = 0;
+static int envVarsSize = 0;
+static int envVarsTotal = 0;
+
+
+/* Deinitialization of new environment. */
+static void __attribute__ ((destructor)) __clean_env_destructor(void);
+
+
+/*
+ * A simple version of warnx() to avoid the bloat of including stdio in static
+ * binaries.
+ */
+static void
+__env_warnx(const char *msg, const char *name, size_t nameLen)
+{
+ static const char nl[] = "\n";
+ static const char progSep[] = ": ";
+
+ _write(STDERR_FILENO, _getprogname(), strlen(_getprogname()));
+ _write(STDERR_FILENO, progSep, sizeof(progSep) - 1);
+ _write(STDERR_FILENO, msg, strlen(msg));
+ _write(STDERR_FILENO, name, nameLen);
+ _write(STDERR_FILENO, nl, sizeof(nl) - 1);
+
+ return;
+}
+
+
+/*
+ * Inline strlen() for performance. Also, perform check for an equals sign.
+ * Cheaper here than peforming a strchr() later.
+ */
+static inline size_t
+__strleneq(const char *str)
+{
+ const char *s;
+
+ for (s = str; *s != '\0'; ++s)
+ if (*s == '=')
+ return (0);
+
+ return (s - str);
+}
+
+
+/*
+ * Comparison of an environment name=value to a name.
+ */
+static inline bool
+strncmpeq(const char *nameValue, const char *name, size_t nameLen)
+{
+ if (strncmp(nameValue, name, nameLen) == 0 && nameValue[nameLen] == '=')
+ return (true);
+
+ return (false);
+}
+
+
+/*
+ * Using environment, returns pointer to value associated with name, if any,
+ * else NULL. If the onlyActive flag is set to true, only variables that are
+ * active are returned else all are.
+ */
+static inline char *
+__findenv(const char *name, size_t nameLen, int *envNdx, bool onlyActive)
+{
+ int ndx;
+
+ /*
+ * Find environment variable from end of array (more likely to be
+ * active). A variable created by putenv is always active, or it is not
+ * tracked in the array.
+ */
+ for (ndx = *envNdx; ndx >= 0; ndx--)
+ if (envVars[ndx].putenv) {
+ if (strncmpeq(envVars[ndx].name, name, nameLen)) {
+ *envNdx = ndx;
+ return (envVars[ndx].name + nameLen +
+ sizeof ("=") - 1);
+ }
+ } else if ((!onlyActive || envVars[ndx].active) &&
+ (envVars[ndx].nameLen == nameLen &&
+ strncmpeq(envVars[ndx].name, name, nameLen))) {
+ *envNdx = ndx;
+ return (envVars[ndx].value);
+ }
+
+ return (NULL);
+}
+
+
+/*
+ * Using environ, returns pointer to value associated with name, if any, else
+ * NULL. Used on the original environ passed into the program.
+ */
+static char *
+__findenv_environ(const char *name, size_t nameLen)
+{
+ int envNdx;
+
+ /* Find variable within environ. */
+ for (envNdx = 0; environ[envNdx] != NULL; envNdx++)
+ if (strncmpeq(environ[envNdx], name, nameLen))
+ return (&(environ[envNdx][nameLen + sizeof("=") - 1]));
+
+ return (NULL);
+}
+
+
+/*
+ * Remove variable added by putenv() from variable tracking array.
+ */
+static void
+__remove_putenv(int envNdx)
+{
+ envVarsTotal--;
+ if (envVarsTotal > envNdx)
+ memmove(&(envVars[envNdx]), &(envVars[envNdx + 1]),
+ (envVarsTotal - envNdx) * sizeof (*envVars));
+ memset(&(envVars[envVarsTotal]), 0, sizeof (*envVars));
+
+ return;
+}
+
+
+/*
+ * Deallocate the environment built from environ as well as environ then set
+ * both to NULL. Eases debugging of memory leaks.
+ */
+static void
+__clean_env(bool freeVars)
+{
+ int envNdx;
+
+ /* Deallocate environment and environ if created by *env(). */
+ if (envVars != NULL) {
+ for (envNdx = envVarsTotal - 1; envNdx >= 0; envNdx--)
+ /* Free variables or deactivate them. */
+ if (envVars[envNdx].putenv) {
+ if (!freeVars)
+ __remove_putenv(envNdx);
+ } else {
+ if (freeVars)
+ free(envVars[envNdx].name);
+ else
+ envVars[envNdx].active = false;
+ }
+ if (freeVars) {
+ free(envVars);
+ envVars = NULL;
+ } else
+ envActive = 0;
+
+ /* Restore original environ if it has not updated by program. */
+ if (origEnviron != NULL) {
+ if (environ == intEnviron)
+ environ = origEnviron;
+ free(intEnviron);
+ intEnviron = NULL;
+ environSize = 0;
+ }
+ }
+
+ return;
+}
+
+
+/*
+ * Using the environment, rebuild the environ array for use by other C library
+ * calls that depend upon it.
+ */
+static int
+__rebuild_environ(int newEnvironSize)
+{
+ char **tmpEnviron;
+ int envNdx;
+ int environNdx;
+ int tmpEnvironSize;
+
+ /* Resize environ. */
+ if (newEnvironSize > environSize) {
+ tmpEnvironSize = newEnvironSize * 2;
+ tmpEnviron = realloc(intEnviron, sizeof (*intEnviron) *
+ (tmpEnvironSize + 1));
+ if (tmpEnviron == NULL)
+ return (-1);
+ environSize = tmpEnvironSize;
+ intEnviron = tmpEnviron;
+ }
+ envActive = newEnvironSize;
+
+ /* Assign active variables to environ. */
+ for (envNdx = envVarsTotal - 1, environNdx = 0; envNdx >= 0; envNdx--)
+ if (envVars[envNdx].active)
+ intEnviron[environNdx++] = envVars[envNdx].name;
+ intEnviron[environNdx] = NULL;
+
+ /* Always set environ which may have been replaced by program. */
+ environ = intEnviron;
+
+ return (0);
+}
+
+
+/*
+ * Enlarge new environment.
+ */
+static inline bool
+__enlarge_env(void)
+{
+ int newEnvVarsSize;
+ struct envVars *tmpEnvVars;
+
+ envVarsTotal++;
+ if (envVarsTotal > envVarsSize) {
+ newEnvVarsSize = envVarsTotal * 2;
+ tmpEnvVars = realloc(envVars, sizeof (*envVars) *
+ newEnvVarsSize);
+ if (tmpEnvVars == NULL) {
+ envVarsTotal--;
+ return (false);
+ }
+ envVarsSize = newEnvVarsSize;
+ envVars = tmpEnvVars;
+ }
+
+ return (true);
+}
+
+
+/*
+ * Using environ, build an environment for use by standard C library calls.
+ */
+static int
+__build_env(void)
+{
+ char **env;
+ int activeNdx;
+ int envNdx;
+ int savedErrno;
+ size_t nameLen;
+
+ /* Check for non-existant environment. */
+ if (environ == NULL || environ[0] == NULL)
+ return (0);
+
+ /* Count environment variables. */
+ for (env = environ, envVarsTotal = 0; *env != NULL; env++)
+ envVarsTotal++;
+ envVarsSize = envVarsTotal * 2;
+
+ /* Create new environment. */
+ envVars = calloc(1, sizeof (*envVars) * envVarsSize);
+ if (envVars == NULL)
+ goto Failure;
+
+ /* Copy environ values and keep track of them. */
+ for (envNdx = envVarsTotal - 1; envNdx >= 0; envNdx--) {
+ envVars[envNdx].putenv = false;
+ envVars[envNdx].name =
+ strdup(environ[envVarsTotal - envNdx - 1]);
+ if (envVars[envNdx].name == NULL)
+ goto Failure;
+ envVars[envNdx].value = strchr(envVars[envNdx].name, '=');
+ if (envVars[envNdx].value != NULL) {
+ envVars[envNdx].value++;
+ envVars[envNdx].valueSize =
+ strlen(envVars[envNdx].value);
+ } else {
+ __env_warnx(CorruptEnvValueMsg, envVars[envNdx].name,
+ strlen(envVars[envNdx].name));
+ errno = EFAULT;
+ goto Failure;
+ }
+
+ /*
+ * Find most current version of variable to make active. This
+ * will prevent multiple active variables from being created
+ * during this initialization phase.
+ */
+ nameLen = envVars[envNdx].value - envVars[envNdx].name - 1;
+ envVars[envNdx].nameLen = nameLen;
+ activeNdx = envVarsTotal - 1;
+ if (__findenv(envVars[envNdx].name, nameLen, &activeNdx,
+ false) == NULL) {
+ __env_warnx(CorruptEnvFindMsg, envVars[envNdx].name,
+ nameLen);
+ errno = EFAULT;
+ goto Failure;
+ }
+ envVars[activeNdx].active = true;
+ }
+
+ /* Create a new environ. */
+ origEnviron = environ;
+ environ = NULL;
+ if (__rebuild_environ(envVarsTotal) == 0)
+ return (0);
+
+Failure:
+ savedErrno = errno;
+ __clean_env(true);
+ errno = savedErrno;
+
+ return (-1);
+}
+
+
+/*
+ * Destructor function with default argument to __clean_env().
+ */
+static void
+__clean_env_destructor(void)
+{
+ __clean_env(true);
+
+ return;
+}
+
+
+/*
+ * Returns the value of a variable or NULL if none are found.
+ */
+char *
+getenv(const char *name)
+{
+ int envNdx;
+ size_t nameLen;
+
+ /* Check for malformed name. */
+ if (name == NULL || (nameLen = __strleneq(name)) == 0) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ /*
+ * Variable search order:
+ * 1. Check for an empty environ. This allows an application to clear
+ * the environment.
+ * 2. Search the external environ array.
+ * 3. Search the internal environment.
+ *
+ * Since malloc() depends upon getenv(), getenv() must never cause the
+ * internal environment storage to be generated.
+ */
+ if (environ == NULL || environ[0] == NULL)
+ return (NULL);
+ else if (envVars == NULL || environ != intEnviron)
+ return (__findenv_environ(name, nameLen));
+ else {
+ envNdx = envVarsTotal - 1;
+ return (__findenv(name, nameLen, &envNdx, true));
+ }
+}
+
+
+/*
+ * Set the value of a variable. Older settings are labeled as inactive. If an
+ * older setting has enough room to store the new value, it will be reused. No
+ * previous variables are ever freed here to avoid causing a segmentation fault
+ * in a user's code.
+ *
+ * The variables nameLen and valueLen are passed into here to allow the caller
+ * to calculate the length by means besides just strlen().
+ */
+static int
+__setenv(const char *name, size_t nameLen, const char *value, int overwrite)
+{
+ bool reuse;
+ char *env;
+ int envNdx;
+ int newEnvActive;
+ size_t valueLen;
+
+ /* Find existing environment variable large enough to use. */
+ envNdx = envVarsTotal - 1;
+ newEnvActive = envActive;
+ valueLen = strlen(value);
+ reuse = false;
+ if (__findenv(name, nameLen, &envNdx, false) != NULL) {
+ /* Deactivate entry if overwrite is allowed. */
+ if (envVars[envNdx].active) {
+ if (overwrite == 0)
+ return (0);
+ envVars[envNdx].active = false;
+ newEnvActive--;
+ }
+
+ /* putenv() created variable cannot be reused. */
+ if (envVars[envNdx].putenv)
+ __remove_putenv(envNdx);
+
+ /* Entry is large enough to reuse. */
+ else if (envVars[envNdx].valueSize >= valueLen)
+ reuse = true;
+ }
+
+ /* Create new variable if none was found of sufficient size. */
+ if (! reuse) {
+ /* Enlarge environment. */
+ envNdx = envVarsTotal;
+ if (!__enlarge_env())
+ return (-1);
+
+ /* Create environment entry. */
+ envVars[envNdx].name = malloc(nameLen + sizeof ("=") +
+ valueLen);
+ if (envVars[envNdx].name == NULL) {
+ envVarsTotal--;
+ return (-1);
+ }
+ envVars[envNdx].nameLen = nameLen;
+ envVars[envNdx].valueSize = valueLen;
+
+ /* Save name of name/value pair. */
+ env = stpncpy(envVars[envNdx].name, name, nameLen);
+ *env++ = '=';
+ }
+ else
+ env = envVars[envNdx].value;
+
+ /* Save value of name/value pair. */
+ strcpy(env, value);
+ envVars[envNdx].value = env;
+ envVars[envNdx].active = true;
+ newEnvActive++;
+
+ /* No need to rebuild environ if an active variable was reused. */
+ if (reuse && newEnvActive == envActive)
+ return (0);
+ else
+ return (__rebuild_environ(newEnvActive));
+}
+
+
+/*
+ * If the program attempts to replace the array of environment variables
+ * (environ) environ or sets the first varible to NULL, then deactivate all
+ * variables and merge in the new list from environ.
+ */
+static int
+__merge_environ(void)
+{
+ char **env;
+ char *equals;
+
+ /*
+ * Internally-built environ has been replaced or cleared (detected by
+ * using the count of active variables against a NULL as the first value
+ * in environ). Clean up everything.
+ */
+ if (intEnviron != NULL && (environ != intEnviron || (envActive > 0 &&
+ environ[0] == NULL))) {
+ /* Deactivate all environment variables. */
+ if (envActive > 0) {
+ origEnviron = NULL;
+ __clean_env(false);
+ }
+
+ /*
+ * Insert new environ into existing, yet deactivated,
+ * environment array.
+ */
+ origEnviron = environ;
+ if (origEnviron != NULL)
+ for (env = origEnviron; *env != NULL; env++) {
+ if ((equals = strchr(*env, '=')) == NULL) {
+ __env_warnx(CorruptEnvValueMsg, *env,
+ strlen(*env));
+ errno = EFAULT;
+ return (-1);
+ }
+ if (__setenv(*env, equals - *env, equals + 1,
+ 1) == -1)
+ return (-1);
+ }
+ }
+
+ return (0);
+}
+
+
+/*
+ * The exposed setenv() that peforms a few tests before calling the function
+ * (__setenv()) that does the actual work of inserting a variable into the
+ * environment.
+ */
+int
+setenv(const char *name, const char *value, int overwrite)
+{
+ size_t nameLen;
+
+ /* Check for malformed name. */
+ if (name == NULL || (nameLen = __strleneq(name)) == 0) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ /* Initialize environment. */
+ if (__merge_environ() == -1 || (envVars == NULL && __build_env() == -1))
+ return (-1);
+
+ return (__setenv(name, nameLen, value, overwrite));
+}
+
+
+/*
+ * Insert a "name=value" string into the environment. Special settings must be
+ * made to keep setenv() from reusing this memory block and unsetenv() from
+ * allowing it to be tracked.
+ */
+int
+putenv(char *string)
+{
+ char *equals;
+ int envNdx;
+ int newEnvActive;
+ size_t nameLen;
+
+ /* Check for malformed argument. */
+ if (string == NULL || (equals = strchr(string, '=')) == NULL ||
+ (nameLen = equals - string) == 0) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ /* Initialize environment. */
+ if (__merge_environ() == -1 || (envVars == NULL && __build_env() == -1))
+ return (-1);
+
+ /* Deactivate previous environment variable. */
+ envNdx = envVarsTotal - 1;
+ newEnvActive = envActive;
+ if (__findenv(string, nameLen, &envNdx, true) != NULL) {
+ /* Reuse previous putenv slot. */
+ if (envVars[envNdx].putenv) {
+ envVars[envNdx].name = string;
+ return (__rebuild_environ(envActive));
+ } else {
+ newEnvActive--;
+ envVars[envNdx].active = false;
+ }
+ }
+
+ /* Enlarge environment. */
+ envNdx = envVarsTotal;
+ if (!__enlarge_env())
+ return (-1);
+
+ /* Create environment entry. */
+ envVars[envNdx].name = string;
+ envVars[envNdx].nameLen = -1;
+ envVars[envNdx].value = NULL;
+ envVars[envNdx].valueSize = -1;
+ envVars[envNdx].putenv = true;
+ envVars[envNdx].active = true;
+ newEnvActive++;
+
+ return (__rebuild_environ(newEnvActive));
+}
+
+
+/*
+ * Unset variable with the same name by flagging it as inactive. No variable is
+ * ever freed.
+ */
+int
+unsetenv(const char *name)
+{
+ int envNdx;
+ size_t nameLen;
+ int newEnvActive;
+
+ /* Check for malformed name. */
+ if (name == NULL || (nameLen = __strleneq(name)) == 0) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ /* Initialize environment. */
+ if (__merge_environ() == -1 || (envVars == NULL && __build_env() == -1))
+ return (-1);
+
+ /* Deactivate specified variable. */
+ /* Remove all occurrences. */
+ envNdx = envVarsTotal - 1;
+ newEnvActive = envActive;
+ while (__findenv(name, nameLen, &envNdx, true) != NULL) {
+ envVars[envNdx].active = false;
+ if (envVars[envNdx].putenv)
+ __remove_putenv(envNdx);
+ envNdx--;
+ newEnvActive--;
+ }
+ if (newEnvActive != envActive)
+ __rebuild_environ(newEnvActive);
+
+ return (0);
+}
diff --git a/lib/libc/stdlib/getopt.3 b/lib/libc/stdlib/getopt.3
new file mode 100644
index 000000000000..6e04e1704712
--- /dev/null
+++ b/lib/libc/stdlib/getopt.3
@@ -0,0 +1,317 @@
+.\" $NetBSD: getopt.3,v 1.34 2014/06/05 22:09:50 wiz Exp $
+.\"
+.\" Copyright (c) 1988, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)getopt.3 8.5 (Berkeley) 4/27/95
+.\" $FreeBSD$
+.\"
+.Dd June 5, 2014
+.Dt GETOPT 3
+.Os
+.Sh NAME
+.Nm getopt
+.Nd get option character from command line argument list
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Vt extern char *optarg ;
+.Vt extern int optind ;
+.Vt extern int optopt ;
+.Vt extern int opterr ;
+.Vt extern int optreset ;
+.Ft int
+.Fn getopt "int argc" "char * const argv[]" "const char *optstring"
+.Sh DESCRIPTION
+The
+.Fn getopt
+function incrementally parses a command line argument list
+.Fa argv
+and returns the next
+.Em known
+option character.
+An option character is
+.Em known
+if it has been specified in the string of accepted option characters,
+.Fa optstring .
+.Pp
+The option string
+.Fa optstring
+may contain the following elements: individual characters, and
+characters followed by a colon to indicate an option argument
+is to follow.
+If an individual character is followed by two colons, then the
+option argument is optional;
+.Va optarg
+is set to the rest of the current
+.Va argv
+word, or
+.Dv NULL
+if there were no more characters in the current word.
+This is a
+.Tn GNU
+extension.
+For example, an option string
+.Li \&"x"
+recognizes an option
+.Dq Fl x ,
+and an option string
+.Li \&"x:"
+recognizes an option and argument
+.Dq Fl x Ar argument .
+It does not matter to
+.Fn getopt
+if a following argument has leading white space.
+.Pp
+On return from
+.Fn getopt ,
+.Va optarg
+points to an option argument, if it is anticipated,
+and the variable
+.Va optind
+contains the index to the next
+.Fa argv
+argument for a subsequent call
+to
+.Fn getopt .
+The variable
+.Va optopt
+saves the last
+.Em known
+option character returned by
+.Fn getopt .
+.Pp
+The variables
+.Va opterr
+and
+.Va optind
+are both initialized to 1.
+The
+.Va optind
+variable may be set to another value before a set of calls to
+.Fn getopt
+in order to skip over more or less argv entries.
+.Pp
+In order to use
+.Fn getopt
+to evaluate multiple sets of arguments, or to evaluate a single set of
+arguments multiple times,
+the variable
+.Va optreset
+must be set to 1 before the second and each additional set of calls to
+.Fn getopt ,
+and the variable
+.Va optind
+must be reinitialized.
+.Pp
+The
+.Fn getopt
+function returns \-1 when the argument list is exhausted.
+The interpretation of options in the argument list may be cancelled
+by the option
+.Ql --
+(double dash) which causes
+.Fn getopt
+to signal the end of argument processing and return \-1.
+When all options have been processed (i.e., up to the first non-option
+argument),
+.Fn getopt
+returns \-1.
+.Sh RETURN VALUES
+The
+.Fn getopt
+function returns the next known option character in
+.Fa optstring .
+If
+.Fn getopt
+encounters a character not found in
+.Fa optstring
+or if it detects a missing option argument,
+it returns
+.Ql \&?
+(question mark).
+If
+.Fa optstring
+has a leading
+.Ql \&:
+then a missing option argument causes
+.Ql \&:
+to be returned instead of
+.Ql \&? .
+In either case, the variable
+.Va optopt
+is set to the character that caused the error.
+The
+.Fn getopt
+function returns \-1 when the argument list is exhausted.
+.Sh EXAMPLES
+.Bd -literal -compact
+#include <unistd.h>
+int bflag, ch, fd;
+
+bflag = 0;
+while ((ch = getopt(argc, argv, "bf:")) != -1) {
+ switch (ch) {
+ case 'b':
+ bflag = 1;
+ break;
+ case 'f':
+ if ((fd = open(optarg, O_RDONLY, 0)) \*[Lt] 0) {
+ (void)fprintf(stderr,
+ "myname: %s: %s\en", optarg, strerror(errno));
+ exit(1);
+ }
+ break;
+ case '?':
+ default:
+ usage();
+ }
+}
+argc -= optind;
+argv += optind;
+.Ed
+.Sh DIAGNOSTICS
+If the
+.Fn getopt
+function encounters a character not found in the string
+.Fa optstring
+or detects
+a missing option argument it writes an error message to the
+.Dv stderr
+and returns
+.Ql \&? .
+Setting
+.Va opterr
+to a zero will disable these error messages.
+If
+.Fa optstring
+has a leading
+.Ql \&:
+then a missing option argument causes a
+.Ql \&:
+to be returned in addition to suppressing any error messages.
+.Pp
+Option arguments are allowed to begin with
+.Dq Li \- ;
+this is reasonable but reduces the amount of error checking possible.
+.Sh SEE ALSO
+.Xr getopt 1 ,
+.Xr getopt_long 3 ,
+.Xr getsubopt 3
+.Sh STANDARDS
+The
+.Va optreset
+variable was added to make it possible to call the
+.Fn getopt
+function multiple times.
+This is an extension to the
+.St -p1003.2
+specification.
+.Sh HISTORY
+The
+.Fn getopt
+function appeared in
+.Bx 4.3 .
+.Sh BUGS
+The
+.Fn getopt
+function was once specified to return
+.Dv EOF
+instead of \-1.
+This was changed by
+.St -p1003.2-92
+to decouple
+.Fn getopt
+from
+.In stdio.h .
+.Pp
+A single dash
+.Dq Li -
+may be specified as a character in
+.Fa optstring ,
+however it should
+.Em never
+have an argument associated with it.
+This allows
+.Fn getopt
+to be used with programs that expect
+.Dq Li -
+as an option flag.
+This practice is wrong, and should not be used in any current development.
+It is provided for backward compatibility
+.Em only .
+Care should be taken not to use
+.Ql \&-
+as the first character in
+.Fa optstring
+to avoid a semantic conflict with
+.Tn GNU
+.Fn getopt ,
+which assigns different meaning to an
+.Fa optstring
+that begins with a
+.Ql \&- .
+By default, a single dash causes
+.Fn getopt
+to return \-1.
+.Pp
+It is also possible to handle digits as option letters.
+This allows
+.Fn getopt
+to be used with programs that expect a number
+.Pq Dq Li \&-\&3
+as an option.
+This practice is wrong, and should not be used in any current development.
+It is provided for backward compatibility
+.Em only .
+The following code fragment works in most cases.
+.Bd -literal -offset indent
+int ch;
+long length;
+char *p, *ep;
+
+while ((ch = getopt(argc, argv, "0123456789")) != -1)
+ switch (ch) {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ p = argv[optind - 1];
+ if (p[0] == '-' \*[Am]\*[Am] p[1] == ch \*[Am]\*[Am] !p[2]) {
+ length = ch - '0';
+ ep = "";
+ } else if (argv[optind] \*[Am]\*[Am] argv[optind][1] == ch) {
+ length = strtol((p = argv[optind] + 1),
+ \*[Am]ep, 10);
+ optind++;
+ optreset = 1;
+ } else
+ usage();
+ if (*ep != '\e0')
+ errx(EX_USAGE, "illegal number -- %s", p);
+ break;
+ }
+.Ed
diff --git a/lib/libc/stdlib/getopt.c b/lib/libc/stdlib/getopt.c
new file mode 100644
index 000000000000..3929b321dca9
--- /dev/null
+++ b/lib/libc/stdlib/getopt.c
@@ -0,0 +1,138 @@
+/* $NetBSD: getopt.c,v 1.29 2014/06/05 22:00:22 christos Exp $ */
+
+/*
+ * Copyright (c) 1987, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)getopt.c 8.3 (Berkeley) 4/27/95";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+#include "libc_private.h"
+
+int opterr = 1, /* if error message should be printed */
+ optind = 1, /* index into parent argv vector */
+ optopt, /* character checked for validity */
+ optreset; /* reset getopt */
+char *optarg; /* argument associated with option */
+
+#define BADCH (int)'?'
+#define BADARG (int)':'
+#define EMSG ""
+
+/*
+ * getopt --
+ * Parse argc/argv argument vector.
+ */
+int
+getopt(int nargc, char * const nargv[], const char *ostr)
+{
+ static char *place = EMSG; /* option letter processing */
+ char *oli; /* option letter list index */
+
+ if (optreset || *place == 0) { /* update scanning pointer */
+ optreset = 0;
+ place = nargv[optind];
+ if (optind >= nargc || *place++ != '-') {
+ /* Argument is absent or is not an option */
+ place = EMSG;
+ return (-1);
+ }
+ optopt = *place++;
+ if (optopt == '-' && *place == 0) {
+ /* "--" => end of options */
+ ++optind;
+ place = EMSG;
+ return (-1);
+ }
+ if (optopt == 0) {
+ /* Solitary '-', treat as a '-' option
+ if the program (eg su) is looking for it. */
+ place = EMSG;
+ if (strchr(ostr, '-') == NULL)
+ return (-1);
+ optopt = '-';
+ }
+ } else
+ optopt = *place++;
+
+ /* See if option letter is one the caller wanted... */
+ if (optopt == ':' || (oli = strchr(ostr, optopt)) == NULL) {
+ if (*place == 0)
+ ++optind;
+ if (opterr && *ostr != ':')
+ (void)fprintf(stderr,
+ "%s: illegal option -- %c\n", _getprogname(),
+ optopt);
+ return (BADCH);
+ }
+
+ /* Does this option need an argument? */
+ if (oli[1] != ':') {
+ /* don't need argument */
+ optarg = NULL;
+ if (*place == 0)
+ ++optind;
+ } else {
+ /* Option-argument is either the rest of this argument or the
+ entire next argument. */
+ if (*place)
+ optarg = place;
+ else if (oli[2] == ':')
+ /*
+ * GNU Extension, for optional arguments if the rest of
+ * the argument is empty, we return NULL
+ */
+ optarg = NULL;
+ else if (nargc > ++optind)
+ optarg = nargv[optind];
+ else {
+ /* option-argument absent */
+ place = EMSG;
+ if (*ostr == ':')
+ return (BADARG);
+ if (opterr)
+ (void)fprintf(stderr,
+ "%s: option requires an argument -- %c\n",
+ _getprogname(), optopt);
+ return (BADCH);
+ }
+ place = EMSG;
+ ++optind;
+ }
+ return (optopt); /* return option letter */
+}
diff --git a/lib/libc/stdlib/getopt_long.3 b/lib/libc/stdlib/getopt_long.3
new file mode 100644
index 000000000000..69047162c556
--- /dev/null
+++ b/lib/libc/stdlib/getopt_long.3
@@ -0,0 +1,507 @@
+.\" $OpenBSD: getopt_long.3,v 1.10 2004/01/06 23:44:28 fgsch Exp $
+.\" $NetBSD: getopt_long.3,v 1.14 2003/08/07 16:43:40 agc Exp $
+.\"
+.\" Copyright (c) 1988, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)getopt.3 8.5 (Berkeley) 4/27/95
+.\" $FreeBSD$
+.\"
+.Dd December 25, 2011
+.Dt GETOPT_LONG 3
+.Os
+.Sh NAME
+.Nm getopt_long ,
+.Nm getopt_long_only
+.Nd get long options from command line argument list
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In getopt.h
+.Vt extern char *optarg ;
+.Vt extern int optind ;
+.Vt extern int optopt ;
+.Vt extern int opterr ;
+.Vt extern int optreset ;
+.Ft int
+.Fo getopt_long
+.Fa "int argc" "char * const *argv" "const char *optstring"
+.Fa "const struct option *longopts" "int *longindex"
+.Fc
+.Ft int
+.Fo getopt_long_only
+.Fa "int argc" "char * const *argv" "const char *optstring"
+.Fa "const struct option *longopts" "int *longindex"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn getopt_long
+function is similar to
+.Xr getopt 3
+but it accepts options in two forms: words and characters.
+The
+.Fn getopt_long
+function provides a superset of the functionality of
+.Xr getopt 3 .
+The
+.Fn getopt_long
+function
+can be used in two ways.
+In the first way, every long option understood
+by the program has a corresponding short option, and the option
+structure is only used to translate from long options to short
+options.
+When used in this fashion,
+.Fn getopt_long
+behaves identically to
+.Xr getopt 3 .
+This is a good way to add long option processing to an existing program
+with the minimum of rewriting.
+.Pp
+In the second mechanism, a long option sets a flag in the
+.Vt option
+structure passed, or will store a pointer to the command line argument
+in the
+.Vt option
+structure passed to it for options that take arguments.
+Additionally,
+the long option's argument may be specified as a single argument with
+an equal sign, e.g.,
+.Pp
+.Dl "myprogram --myoption=somevalue"
+.Pp
+When a long option is processed, the call to
+.Fn getopt_long
+will return 0.
+For this reason, long option processing without
+shortcuts is not backwards compatible with
+.Xr getopt 3 .
+.Pp
+It is possible to combine these methods, providing for long options
+processing with short option equivalents for some options.
+Less
+frequently used options would be processed as long options only.
+.Pp
+The
+.Fn getopt_long
+call requires a structure to be initialized describing the long
+options.
+The structure is:
+.Bd -literal -offset indent
+struct option {
+ char *name;
+ int has_arg;
+ int *flag;
+ int val;
+};
+.Ed
+.Pp
+The
+.Va name
+field should contain the option name without the leading double dash.
+.Pp
+The
+.Va has_arg
+field should be one of:
+.Pp
+.Bl -tag -width ".Dv optional_argument" -offset indent -compact
+.It Dv no_argument
+no argument to the option is expected
+.It Dv required_argument
+an argument to the option is required
+.It Dv optional_argument
+an argument to the option may be presented
+.El
+.Pp
+If
+.Va flag
+is not
+.Dv NULL ,
+then the integer pointed to by it will be set to the
+value in the
+.Va val
+field.
+If the
+.Va flag
+field is
+.Dv NULL ,
+then the
+.Va val
+field will be returned.
+Setting
+.Va flag
+to
+.Dv NULL
+and setting
+.Va val
+to the corresponding short option will make this function act just
+like
+.Xr getopt 3 .
+.Pp
+If the
+.Fa longindex
+field is not
+.Dv NULL ,
+then the integer pointed to by it will be set to the index of the long
+option relative to
+.Fa longopts .
+.Pp
+The last element of the
+.Fa longopts
+array has to be filled with zeroes.
+.Pp
+The
+.Fn getopt_long_only
+function behaves identically to
+.Fn getopt_long
+with the exception that long options may start with
+.Ql -
+in addition to
+.Ql -- .
+If an option starting with
+.Ql -
+does not match a long option but does match a single-character option,
+the single-character option is returned.
+.Sh RETURN VALUES
+If the
+.Fa flag
+field in
+.Vt "struct option"
+is
+.Dv NULL ,
+.Fn getopt_long
+and
+.Fn getopt_long_only
+return the value specified in the
+.Fa val
+field, which is usually just the corresponding short option.
+If
+.Fa flag
+is not
+.Dv NULL ,
+these functions return 0 and store
+.Fa val
+in the location pointed to by
+.Fa flag .
+These functions return
+.Ql \&:
+if there was a missing option argument,
+.Ql \&?
+if the user specified an unknown or ambiguous option, and
+\-1 when the argument list has been exhausted.
+.Sh ENVIRONMENT
+.Bl -tag -width ".Ev POSIXLY_CORRECT"
+.It Ev POSIXLY_CORRECT
+If set, option processing stops when the first non-option is found and
+a leading
+.Ql -
+or
+.Ql +
+in the
+.Fa optstring
+is ignored.
+.El
+.Sh EXAMPLES
+.Bd -literal -compact
+int bflag, ch, fd;
+int daggerset;
+
+/* options descriptor */
+static struct option longopts[] = {
+ { "buffy", no_argument, NULL, 'b' },
+ { "fluoride", required_argument, NULL, 'f' },
+ { "daggerset", no_argument, \*[Am]daggerset, 1 },
+ { NULL, 0, NULL, 0 }
+};
+
+bflag = 0;
+while ((ch = getopt_long(argc, argv, "bf:", longopts, NULL)) != -1) {
+ switch (ch) {
+ case 'b':
+ bflag = 1;
+ break;
+ case 'f':
+ if ((fd = open(optarg, O_RDONLY, 0)) == -1)
+ err(1, "unable to open %s", optarg);
+ break;
+ case 0:
+ if (daggerset) {
+ fprintf(stderr,"Buffy will use her dagger to "
+ "apply fluoride to dracula's teeth\en");
+ }
+ break;
+ default:
+ usage();
+ }
+}
+argc -= optind;
+argv += optind;
+.Ed
+.Sh IMPLEMENTATION DIFFERENCES
+This section describes differences to the
+.Tn GNU
+implementation
+found in glibc-2.1.3:
+.Bl -bullet
+.\" .It
+.\" Handling of
+.\" .Ql -
+.\" as first char of option string in presence of
+.\" environment variable
+.\" .Ev POSIXLY_CORRECT :
+.\" .Bl -tag -width ".Bx"
+.\" .It Tn GNU
+.\" ignores
+.\" .Ev POSIXLY_CORRECT
+.\" and returns non-options as
+.\" arguments to option '\e1'.
+.\" .It Bx
+.\" honors
+.\" .Ev POSIXLY_CORRECT
+.\" and stops at the first non-option.
+.\" .El
+.\" .It
+.\" Handling of
+.\" .Ql -
+.\" within the option string (not the first character):
+.\" .Bl -tag -width ".Bx"
+.\" .It Tn GNU
+.\" treats a
+.\" .Ql -
+.\" on the command line as a non-argument.
+.\" .It Bx
+.\" a
+.\" .Ql -
+.\" within the option string matches a
+.\" .Ql -
+.\" (single dash) on the command line.
+.\" This functionality is provided for backward compatibility with
+.\" programs, such as
+.\" .Xr su 1 ,
+.\" that use
+.\" .Ql -
+.\" as an option flag.
+.\" This practice is wrong, and should not be used in any current development.
+.\" .El
+.\" .It
+.\" Handling of
+.\" .Ql ::
+.\" in options string in presence of
+.\" .Ev POSIXLY_CORRECT :
+.\" .Bl -tag -width ".Bx"
+.\" .It Both
+.\" .Tn GNU
+.\" and
+.\" .Bx
+.\" ignore
+.\" .Ev POSIXLY_CORRECT
+.\" here and take
+.\" .Ql ::
+.\" to
+.\" mean the preceding option takes an optional argument.
+.\" .El
+.\" .It
+.\" Return value in case of missing argument if first character
+.\" (after
+.\" .Ql +
+.\" or
+.\" .Ql - )
+.\" in option string is not
+.\" .Ql \&: :
+.\" .Bl -tag -width ".Bx"
+.\" .It Tn GNU
+.\" returns
+.\" .Ql \&?
+.\" .It Bx
+.\" returns
+.\" .Ql \&:
+.\" (since
+.\" .Bx Ns 's
+.\" .Fn getopt
+.\" does).
+.\" .El
+.\" .It
+.\" Handling of
+.\" .Ql --a
+.\" in getopt:
+.\" .Bl -tag -width ".Bx"
+.\" .It Tn GNU
+.\" parses this as option
+.\" .Ql - ,
+.\" option
+.\" .Ql a .
+.\" .It Bx
+.\" parses this as
+.\" .Ql -- ,
+.\" and returns \-1 (ignoring the
+.\" .Ql a ) .
+.\" (Because the original
+.\" .Fn getopt
+.\" does.)
+.\" .El
+.It
+Setting of
+.Va optopt
+for long options with
+.Va flag
+!=
+.Dv NULL :
+.Bl -tag -width ".Bx"
+.It Tn GNU
+sets
+.Va optopt
+to
+.Va val .
+.It Bx
+sets
+.Va optopt
+to 0 (since
+.Va val
+would never be returned).
+.El
+.\" .It
+.\" Handling of
+.\" .Ql -W
+.\" with
+.\" .Ql W;
+.\" in option string in
+.\" .Fn getopt
+.\" (not
+.\" .Fn getopt_long ) :
+.\" .Bl -tag -width ".Bx"
+.\" .It Tn GNU
+.\" causes a segfault.
+.\" .It Bx
+.\" no special handling is done;
+.\" .Ql W;
+.\" is interpreted as two separate options, neither of which take an argument.
+.\" .El
+.It
+Setting of
+.Va optarg
+for long options without an argument that are
+invoked via
+.Ql -W
+.Ql ( W;
+in option string):
+.Bl -tag -width ".Bx"
+.It Tn GNU
+sets
+.Va optarg
+to the option name (the argument of
+.Ql -W ) .
+.It Bx
+sets
+.Va optarg
+to
+.Dv NULL
+(the argument of the long option).
+.El
+.It
+Handling of
+.Ql -W
+with an argument that is not (a prefix to) a known
+long option
+.Ql ( W;
+in option string):
+.Bl -tag -width ".Bx"
+.It Tn GNU
+returns
+.Ql -W
+with
+.Va optarg
+set to the unknown option.
+.It Bx
+treats this as an error (unknown option) and returns
+.Ql \&?
+with
+.Va optopt
+set to 0 and
+.Va optarg
+set to
+.Dv NULL
+(as
+.Tn GNU Ns 's
+man page documents).
+.El
+.\" .It
+.\" The error messages are different.
+.It
+.Bx
+does not permute the argument vector at the same points in
+the calling sequence as
+.Tn GNU
+does.
+The aspects normally used by
+the caller (ordering after \-1 is returned, value of
+.Va optind
+relative
+to current positions) are the same, though.
+(We do fewer variable swaps.)
+.El
+.Sh SEE ALSO
+.Xr getopt 3
+.Sh HISTORY
+The
+.Fn getopt_long
+and
+.Fn getopt_long_only
+functions first appeared in the
+.Tn GNU
+libiberty library.
+The first
+.Bx
+implementation of
+.Fn getopt_long
+appeared in
+.Nx 1.5 ,
+the first
+.Bx
+implementation of
+.Fn getopt_long_only
+in
+.Ox 3.3 .
+.Fx
+first included
+.Fn getopt_long
+in
+.Fx 5.0 ,
+.Fn getopt_long_only
+in
+.Fx 5.2 .
+.Sh BUGS
+The
+.Fa argv
+argument is not really
+.Vt const
+as its elements may be permuted (unless
+.Ev POSIXLY_CORRECT
+is set).
+.Pp
+The implementation can completely replace
+.Xr getopt 3 ,
+but right now we are using separate code.
diff --git a/lib/libc/stdlib/getopt_long.c b/lib/libc/stdlib/getopt_long.c
new file mode 100644
index 000000000000..9534a2aff67e
--- /dev/null
+++ b/lib/libc/stdlib/getopt_long.c
@@ -0,0 +1,612 @@
+/* $OpenBSD: getopt_long.c,v 1.26 2013/06/08 22:47:56 millert Exp $ */
+/* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */
+
+/*
+ * Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F39502-99-1-0512.
+ */
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Dieter Baron and Thomas Klausner.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if 0
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *rcsid = "$OpenBSD: getopt_long.c,v 1.16 2004/02/04 18:17:25 millert Exp $";
+#endif /* LIBC_SCCS and not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <err.h>
+#include <errno.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define GNU_COMPATIBLE /* Be more compatible, configure's use us! */
+
+#if 0 /* we prefer to keep our getopt(3) */
+#define REPLACE_GETOPT /* use this getopt as the system getopt(3) */
+#endif
+
+#ifdef REPLACE_GETOPT
+int opterr = 1; /* if error message should be printed */
+int optind = 1; /* index into parent argv vector */
+int optopt = '?'; /* character checked for validity */
+int optreset; /* reset getopt */
+char *optarg; /* argument associated with option */
+#endif
+
+#define PRINT_ERROR ((opterr) && (*options != ':'))
+
+#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */
+#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */
+#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */
+
+/* return values */
+#define BADCH (int)'?'
+#define BADARG ((*options == ':') ? (int)':' : (int)'?')
+#define INORDER (int)1
+
+#define EMSG ""
+
+#ifdef GNU_COMPATIBLE
+#define NO_PREFIX (-1)
+#define D_PREFIX 0
+#define DD_PREFIX 1
+#define W_PREFIX 2
+#endif
+
+static int getopt_internal(int, char * const *, const char *,
+ const struct option *, int *, int);
+static int parse_long_options(char * const *, const char *,
+ const struct option *, int *, int, int);
+static int gcd(int, int);
+static void permute_args(int, int, int, char * const *);
+
+static char *place = EMSG; /* option letter processing */
+
+/* XXX: set optreset to 1 rather than these two */
+static int nonopt_start = -1; /* first non option argument (for permute) */
+static int nonopt_end = -1; /* first option after non options (for permute) */
+
+/* Error messages */
+static const char recargchar[] = "option requires an argument -- %c";
+static const char illoptchar[] = "illegal option -- %c"; /* From P1003.2 */
+#ifdef GNU_COMPATIBLE
+static int dash_prefix = NO_PREFIX;
+static const char gnuoptchar[] = "invalid option -- %c";
+
+static const char recargstring[] = "option `%s%s' requires an argument";
+static const char ambig[] = "option `%s%.*s' is ambiguous";
+static const char noarg[] = "option `%s%.*s' doesn't allow an argument";
+static const char illoptstring[] = "unrecognized option `%s%s'";
+#else
+static const char recargstring[] = "option requires an argument -- %s";
+static const char ambig[] = "ambiguous option -- %.*s";
+static const char noarg[] = "option doesn't take an argument -- %.*s";
+static const char illoptstring[] = "unknown option -- %s";
+#endif
+
+/*
+ * Compute the greatest common divisor of a and b.
+ */
+static int
+gcd(int a, int b)
+{
+ int c;
+
+ c = a % b;
+ while (c != 0) {
+ a = b;
+ b = c;
+ c = a % b;
+ }
+
+ return (b);
+}
+
+/*
+ * Exchange the block from nonopt_start to nonopt_end with the block
+ * from nonopt_end to opt_end (keeping the same order of arguments
+ * in each block).
+ */
+static void
+permute_args(int panonopt_start, int panonopt_end, int opt_end,
+ char * const *nargv)
+{
+ int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
+ char *swap;
+
+ /*
+ * compute lengths of blocks and number and size of cycles
+ */
+ nnonopts = panonopt_end - panonopt_start;
+ nopts = opt_end - panonopt_end;
+ ncycle = gcd(nnonopts, nopts);
+ cyclelen = (opt_end - panonopt_start) / ncycle;
+
+ for (i = 0; i < ncycle; i++) {
+ cstart = panonopt_end+i;
+ pos = cstart;
+ for (j = 0; j < cyclelen; j++) {
+ if (pos >= panonopt_end)
+ pos -= nnonopts;
+ else
+ pos += nopts;
+ swap = nargv[pos];
+ /* LINTED const cast */
+ ((char **) nargv)[pos] = nargv[cstart];
+ /* LINTED const cast */
+ ((char **)nargv)[cstart] = swap;
+ }
+ }
+}
+
+/*
+ * parse_long_options --
+ * Parse long options in argc/argv argument vector.
+ * Returns -1 if short_too is set and the option does not match long_options.
+ */
+static int
+parse_long_options(char * const *nargv, const char *options,
+ const struct option *long_options, int *idx, int short_too, int flags)
+{
+ char *current_argv, *has_equal;
+#ifdef GNU_COMPATIBLE
+ char *current_dash;
+#endif
+ size_t current_argv_len;
+ int i, match, exact_match, second_partial_match;
+
+ current_argv = place;
+#ifdef GNU_COMPATIBLE
+ switch (dash_prefix) {
+ case D_PREFIX:
+ current_dash = "-";
+ break;
+ case DD_PREFIX:
+ current_dash = "--";
+ break;
+ case W_PREFIX:
+ current_dash = "-W ";
+ break;
+ default:
+ current_dash = "";
+ break;
+ }
+#endif
+ match = -1;
+ exact_match = 0;
+ second_partial_match = 0;
+
+ optind++;
+
+ if ((has_equal = strchr(current_argv, '=')) != NULL) {
+ /* argument found (--option=arg) */
+ current_argv_len = has_equal - current_argv;
+ has_equal++;
+ } else
+ current_argv_len = strlen(current_argv);
+
+ for (i = 0; long_options[i].name; i++) {
+ /* find matching long option */
+ if (strncmp(current_argv, long_options[i].name,
+ current_argv_len))
+ continue;
+
+ if (strlen(long_options[i].name) == current_argv_len) {
+ /* exact match */
+ match = i;
+ exact_match = 1;
+ break;
+ }
+ /*
+ * If this is a known short option, don't allow
+ * a partial match of a single character.
+ */
+ if (short_too && current_argv_len == 1)
+ continue;
+
+ if (match == -1) /* first partial match */
+ match = i;
+ else if ((flags & FLAG_LONGONLY) ||
+ long_options[i].has_arg !=
+ long_options[match].has_arg ||
+ long_options[i].flag != long_options[match].flag ||
+ long_options[i].val != long_options[match].val)
+ second_partial_match = 1;
+ }
+ if (!exact_match && second_partial_match) {
+ /* ambiguous abbreviation */
+ if (PRINT_ERROR)
+ warnx(ambig,
+#ifdef GNU_COMPATIBLE
+ current_dash,
+#endif
+ (int)current_argv_len,
+ current_argv);
+ optopt = 0;
+ return (BADCH);
+ }
+ if (match != -1) { /* option found */
+ if (long_options[match].has_arg == no_argument
+ && has_equal) {
+ if (PRINT_ERROR)
+ warnx(noarg,
+#ifdef GNU_COMPATIBLE
+ current_dash,
+#endif
+ (int)current_argv_len,
+ current_argv);
+ /*
+ * XXX: GNU sets optopt to val regardless of flag
+ */
+ if (long_options[match].flag == NULL)
+ optopt = long_options[match].val;
+ else
+ optopt = 0;
+#ifdef GNU_COMPATIBLE
+ return (BADCH);
+#else
+ return (BADARG);
+#endif
+ }
+ if (long_options[match].has_arg == required_argument ||
+ long_options[match].has_arg == optional_argument) {
+ if (has_equal)
+ optarg = has_equal;
+ else if (long_options[match].has_arg ==
+ required_argument) {
+ /*
+ * optional argument doesn't use next nargv
+ */
+ optarg = nargv[optind++];
+ }
+ }
+ if ((long_options[match].has_arg == required_argument)
+ && (optarg == NULL)) {
+ /*
+ * Missing argument; leading ':' indicates no error
+ * should be generated.
+ */
+ if (PRINT_ERROR)
+ warnx(recargstring,
+#ifdef GNU_COMPATIBLE
+ current_dash,
+#endif
+ current_argv);
+ /*
+ * XXX: GNU sets optopt to val regardless of flag
+ */
+ if (long_options[match].flag == NULL)
+ optopt = long_options[match].val;
+ else
+ optopt = 0;
+ --optind;
+ return (BADARG);
+ }
+ } else { /* unknown option */
+ if (short_too) {
+ --optind;
+ return (-1);
+ }
+ if (PRINT_ERROR)
+ warnx(illoptstring,
+#ifdef GNU_COMPATIBLE
+ current_dash,
+#endif
+ current_argv);
+ optopt = 0;
+ return (BADCH);
+ }
+ if (idx)
+ *idx = match;
+ if (long_options[match].flag) {
+ *long_options[match].flag = long_options[match].val;
+ return (0);
+ } else
+ return (long_options[match].val);
+}
+
+/*
+ * getopt_internal --
+ * Parse argc/argv argument vector. Called by user level routines.
+ */
+static int
+getopt_internal(int nargc, char * const *nargv, const char *options,
+ const struct option *long_options, int *idx, int flags)
+{
+ char *oli; /* option letter list index */
+ int optchar, short_too;
+ static int posixly_correct = -1;
+
+ if (options == NULL)
+ return (-1);
+
+ /*
+ * XXX Some GNU programs (like cvs) set optind to 0 instead of
+ * XXX using optreset. Work around this braindamage.
+ */
+ if (optind == 0)
+ optind = optreset = 1;
+
+ /*
+ * Disable GNU extensions if POSIXLY_CORRECT is set or options
+ * string begins with a '+'.
+ */
+ if (posixly_correct == -1 || optreset)
+ posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
+ if (*options == '-')
+ flags |= FLAG_ALLARGS;
+ else if (posixly_correct || *options == '+')
+ flags &= ~FLAG_PERMUTE;
+ if (*options == '+' || *options == '-')
+ options++;
+
+ optarg = NULL;
+ if (optreset)
+ nonopt_start = nonopt_end = -1;
+start:
+ if (optreset || !*place) { /* update scanning pointer */
+ optreset = 0;
+ if (optind >= nargc) { /* end of argument vector */
+ place = EMSG;
+ if (nonopt_end != -1) {
+ /* do permutation, if we have to */
+ permute_args(nonopt_start, nonopt_end,
+ optind, nargv);
+ optind -= nonopt_end - nonopt_start;
+ }
+ else if (nonopt_start != -1) {
+ /*
+ * If we skipped non-options, set optind
+ * to the first of them.
+ */
+ optind = nonopt_start;
+ }
+ nonopt_start = nonopt_end = -1;
+ return (-1);
+ }
+ if (*(place = nargv[optind]) != '-' ||
+#ifdef GNU_COMPATIBLE
+ place[1] == '\0') {
+#else
+ (place[1] == '\0' && strchr(options, '-') == NULL)) {
+#endif
+ place = EMSG; /* found non-option */
+ if (flags & FLAG_ALLARGS) {
+ /*
+ * GNU extension:
+ * return non-option as argument to option 1
+ */
+ optarg = nargv[optind++];
+ return (INORDER);
+ }
+ if (!(flags & FLAG_PERMUTE)) {
+ /*
+ * If no permutation wanted, stop parsing
+ * at first non-option.
+ */
+ return (-1);
+ }
+ /* do permutation */
+ if (nonopt_start == -1)
+ nonopt_start = optind;
+ else if (nonopt_end != -1) {
+ permute_args(nonopt_start, nonopt_end,
+ optind, nargv);
+ nonopt_start = optind -
+ (nonopt_end - nonopt_start);
+ nonopt_end = -1;
+ }
+ optind++;
+ /* process next argument */
+ goto start;
+ }
+ if (nonopt_start != -1 && nonopt_end == -1)
+ nonopt_end = optind;
+
+ /*
+ * If we have "-" do nothing, if "--" we are done.
+ */
+ if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
+ optind++;
+ place = EMSG;
+ /*
+ * We found an option (--), so if we skipped
+ * non-options, we have to permute.
+ */
+ if (nonopt_end != -1) {
+ permute_args(nonopt_start, nonopt_end,
+ optind, nargv);
+ optind -= nonopt_end - nonopt_start;
+ }
+ nonopt_start = nonopt_end = -1;
+ return (-1);
+ }
+ }
+
+ /*
+ * Check long options if:
+ * 1) we were passed some
+ * 2) the arg is not just "-"
+ * 3) either the arg starts with -- we are getopt_long_only()
+ */
+ if (long_options != NULL && place != nargv[optind] &&
+ (*place == '-' || (flags & FLAG_LONGONLY))) {
+ short_too = 0;
+#ifdef GNU_COMPATIBLE
+ dash_prefix = D_PREFIX;
+#endif
+ if (*place == '-') {
+ place++; /* --foo long option */
+#ifdef GNU_COMPATIBLE
+ dash_prefix = DD_PREFIX;
+#endif
+ } else if (*place != ':' && strchr(options, *place) != NULL)
+ short_too = 1; /* could be short option too */
+
+ optchar = parse_long_options(nargv, options, long_options,
+ idx, short_too, flags);
+ if (optchar != -1) {
+ place = EMSG;
+ return (optchar);
+ }
+ }
+
+ if ((optchar = (int)*place++) == (int)':' ||
+ (optchar == (int)'-' && *place != '\0') ||
+ (oli = strchr(options, optchar)) == NULL) {
+ /*
+ * If the user specified "-" and '-' isn't listed in
+ * options, return -1 (non-option) as per POSIX.
+ * Otherwise, it is an unknown option character (or ':').
+ */
+ if (optchar == (int)'-' && *place == '\0')
+ return (-1);
+ if (!*place)
+ ++optind;
+#ifdef GNU_COMPATIBLE
+ if (PRINT_ERROR)
+ warnx(posixly_correct ? illoptchar : gnuoptchar,
+ optchar);
+#else
+ if (PRINT_ERROR)
+ warnx(illoptchar, optchar);
+#endif
+ optopt = optchar;
+ return (BADCH);
+ }
+ if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
+ /* -W long-option */
+ if (*place) /* no space */
+ /* NOTHING */;
+ else if (++optind >= nargc) { /* no arg */
+ place = EMSG;
+ if (PRINT_ERROR)
+ warnx(recargchar, optchar);
+ optopt = optchar;
+ return (BADARG);
+ } else /* white space */
+ place = nargv[optind];
+#ifdef GNU_COMPATIBLE
+ dash_prefix = W_PREFIX;
+#endif
+ optchar = parse_long_options(nargv, options, long_options,
+ idx, 0, flags);
+ place = EMSG;
+ return (optchar);
+ }
+ if (*++oli != ':') { /* doesn't take argument */
+ if (!*place)
+ ++optind;
+ } else { /* takes (optional) argument */
+ optarg = NULL;
+ if (*place) /* no white space */
+ optarg = place;
+ else if (oli[1] != ':') { /* arg not optional */
+ if (++optind >= nargc) { /* no arg */
+ place = EMSG;
+ if (PRINT_ERROR)
+ warnx(recargchar, optchar);
+ optopt = optchar;
+ return (BADARG);
+ } else
+ optarg = nargv[optind];
+ }
+ place = EMSG;
+ ++optind;
+ }
+ /* dump back option letter */
+ return (optchar);
+}
+
+#ifdef REPLACE_GETOPT
+/*
+ * getopt --
+ * Parse argc/argv argument vector.
+ *
+ * [eventually this will replace the BSD getopt]
+ */
+int
+getopt(int nargc, char * const *nargv, const char *options)
+{
+
+ /*
+ * We don't pass FLAG_PERMUTE to getopt_internal() since
+ * the BSD getopt(3) (unlike GNU) has never done this.
+ *
+ * Furthermore, since many privileged programs call getopt()
+ * before dropping privileges it makes sense to keep things
+ * as simple (and bug-free) as possible.
+ */
+ return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));
+}
+#endif /* REPLACE_GETOPT */
+
+/*
+ * getopt_long --
+ * Parse argc/argv argument vector.
+ */
+int
+getopt_long(int nargc, char * const *nargv, const char *options,
+ const struct option *long_options, int *idx)
+{
+
+ return (getopt_internal(nargc, nargv, options, long_options, idx,
+ FLAG_PERMUTE));
+}
+
+/*
+ * getopt_long_only --
+ * Parse argc/argv argument vector.
+ */
+int
+getopt_long_only(int nargc, char * const *nargv, const char *options,
+ const struct option *long_options, int *idx)
+{
+
+ return (getopt_internal(nargc, nargv, options, long_options, idx,
+ FLAG_PERMUTE|FLAG_LONGONLY));
+}
diff --git a/lib/libc/stdlib/getsubopt.3 b/lib/libc/stdlib/getsubopt.3
new file mode 100644
index 000000000000..43ea2c2a9e2c
--- /dev/null
+++ b/lib/libc/stdlib/getsubopt.3
@@ -0,0 +1,147 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)getsubopt.3 8.1 (Berkeley) 6/9/93
+.\" $FreeBSD$
+.\"
+.Dd December 25, 2011
+.Dt GETSUBOPT 3
+.Os
+.Sh NAME
+.Nm getsubopt
+.Nd get sub options from an argument
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Vt extern char *suboptarg ;
+.Ft int
+.Fn getsubopt "char **optionp" "char * const *tokens" "char **valuep"
+.Sh DESCRIPTION
+The
+.Fn getsubopt
+function
+parses a string containing tokens delimited by one or more tab, space or
+comma
+.Pq Ql \&,
+characters.
+It is intended for use in parsing groups of option arguments provided
+as part of a utility command line.
+.Pp
+The argument
+.Fa optionp
+is a pointer to a pointer to the string.
+The argument
+.Fa tokens
+is a pointer to a
+.Dv NULL Ns -terminated
+array of pointers to strings.
+.Pp
+The
+.Fn getsubopt
+function
+returns the zero-based offset of the pointer in the
+.Fa tokens
+array referencing a string which matches the first token
+in the string, or, \-1 if the string contains no tokens or
+.Fa tokens
+does not contain a matching string.
+.Pp
+If the token is of the form ``name=value'', the location referenced by
+.Fa valuep
+will be set to point to the start of the ``value'' portion of the token.
+.Pp
+On return from
+.Fn getsubopt ,
+.Fa optionp
+will be set to point to the start of the next token in the string,
+or the null at the end of the string if no more tokens are present.
+The external variable
+.Fa suboptarg
+will be set to point to the start of the current token, or
+.Dv NULL
+if no
+tokens were present.
+The argument
+.Fa valuep
+will be set to point to the ``value'' portion of the token, or
+.Dv NULL
+if no ``value'' portion was present.
+.Sh EXAMPLES
+.Bd -literal -compact
+char *tokens[] = {
+ #define ONE 0
+ "one",
+ #define TWO 1
+ "two",
+ NULL
+};
+
+\&...
+
+extern char *optarg, *suboptarg;
+char *options, *value;
+
+while ((ch = getopt(argc, argv, "ab:")) != \-1) {
+ switch(ch) {
+ case 'a':
+ /* process ``a'' option */
+ break;
+ case 'b':
+ options = optarg;
+ while (*options) {
+ switch(getsubopt(&options, tokens, &value)) {
+ case ONE:
+ /* process ``one'' sub option */
+ break;
+ case TWO:
+ /* process ``two'' sub option */
+ if (!value)
+ error("no value for two");
+ i = atoi(value);
+ break;
+ case \-1:
+ if (suboptarg)
+ error("illegal sub option %s",
+ suboptarg);
+ else
+ error("missing sub option");
+ break;
+ }
+ }
+ break;
+ }
+}
+.Ed
+.Sh SEE ALSO
+.Xr getopt 3 ,
+.Xr strsep 3
+.Sh HISTORY
+The
+.Fn getsubopt
+function first appeared in
+.Bx 4.4 .
diff --git a/lib/libc/stdlib/getsubopt.c b/lib/libc/stdlib/getsubopt.c
new file mode 100644
index 000000000000..d2db9916d8d8
--- /dev/null
+++ b/lib/libc/stdlib/getsubopt.c
@@ -0,0 +1,95 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)getsubopt.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * The SVID interface to getsubopt provides no way of figuring out which
+ * part of the suboptions list wasn't matched. This makes error messages
+ * tricky... The extern variable suboptarg is a pointer to the token
+ * which didn't match.
+ */
+char *suboptarg;
+
+int
+getsubopt(char **optionp, char * const *tokens, char **valuep)
+{
+ int cnt;
+ char *p;
+
+ suboptarg = *valuep = NULL;
+
+ if (!optionp || !*optionp)
+ return(-1);
+
+ /* skip leading white-space, commas */
+ for (p = *optionp; *p && (*p == ',' || *p == ' ' || *p == '\t'); ++p);
+
+ if (!*p) {
+ *optionp = p;
+ return(-1);
+ }
+
+ /* save the start of the token, and skip the rest of the token. */
+ for (suboptarg = p;
+ *++p && *p != ',' && *p != '=' && *p != ' ' && *p != '\t';);
+
+ if (*p) {
+ /*
+ * If there's an equals sign, set the value pointer, and
+ * skip over the value part of the token. Terminate the
+ * token.
+ */
+ if (*p == '=') {
+ *p = '\0';
+ for (*valuep = ++p;
+ *p && *p != ',' && *p != ' ' && *p != '\t'; ++p);
+ if (*p)
+ *p++ = '\0';
+ } else
+ *p++ = '\0';
+ /* Skip any whitespace or commas after this token. */
+ for (; *p && (*p == ',' || *p == ' ' || *p == '\t'); ++p);
+ }
+
+ /* set optionp for next round. */
+ *optionp = p;
+
+ for (cnt = 0; *tokens; ++tokens, ++cnt)
+ if (!strcmp(suboptarg, *tokens))
+ return(cnt);
+ return(-1);
+}
diff --git a/lib/libc/stdlib/hcreate.3 b/lib/libc/stdlib/hcreate.3
new file mode 100644
index 000000000000..57091570dcb6
--- /dev/null
+++ b/lib/libc/stdlib/hcreate.3
@@ -0,0 +1,325 @@
+.\"-
+.\" Copyright (c) 1999 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Klaus Klein.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd December 26, 2015
+.Dt HCREATE 3
+.Os
+.Sh NAME
+.Nm hcreate ,
+.Nm hcreate_r ,
+.Nm hdestroy ,
+.Nm hdestroy_r ,
+.Nm hsearch ,
+.Nm hsearch_r
+.Nd manage hash search table
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In search.h
+.Ft int
+.Fn hcreate "size_t nel"
+.Ft int
+.Fn hcreate_r "size_t nel" "struct hsearch_data *table"
+.Ft void
+.Fn hdestroy "void"
+.Ft void
+.Fn hdestroy_r "struct hsearch_data *table"
+.Ft ENTRY *
+.Fn hsearch "ENTRY item" "ACTION action"
+.Ft int
+.Fn hsearch_r "ENTRY item" "ACTION action" "ENTRY ** itemp" "struct hsearch_data *table"
+.Sh DESCRIPTION
+The
+.Fn hcreate ,
+.Fn hcreate_r ,
+.Fn hdestroy ,
+.Fn hdestroy_r
+.Fn hsearch ,
+and
+.Fn hsearch_r
+functions manage hash search tables.
+.Pp
+The
+.Fn hcreate
+function allocates sufficient space for the table, and the application should
+ensure it is called before
+.Fn hsearch
+is used.
+The
+.Fa nel
+argument is an estimate of the maximum
+number of entries that the table should contain.
+As this implementation resizes the hash table dynamically,
+this argument is ignored.
+.Pp
+The
+.Fn hdestroy
+function disposes of the search table, and may be followed by another call to
+.Fn hcreate .
+After the call to
+.Fn hdestroy ,
+the data can no longer be considered accessible.
+The
+.Fn hdestroy
+function calls
+.Xr free 3
+for each comparison key in the search table
+but not the data item associated with the key.
+.Pp
+The
+.Fn hsearch
+function is a hash-table search routine.
+It returns a pointer into a hash table
+indicating the location at which an entry can be found.
+The
+.Fa item
+argument is a structure of type
+.Vt ENTRY
+(defined in the
+.In search.h
+header) that contains two pointers:
+.Fa item.key
+points to the comparison key (a
+.Vt "char *" ) ,
+and
+.Fa item.data
+(a
+.Vt "void *" )
+points to any other data to be associated with
+that key.
+The comparison function used by
+.Fn hsearch
+is
+.Xr strcmp 3 .
+The
+.Fa action
+argument is a
+member of an enumeration type
+.Vt ACTION
+indicating the disposition of the entry if it cannot be
+found in the table.
+.Dv ENTER
+indicates that the
+.Fa item
+should be inserted in the table at an
+appropriate point.
+.Dv FIND
+indicates that no entry should be made.
+Unsuccessful resolution is
+indicated by the return of a
+.Dv NULL
+pointer.
+.Pp
+The comparison key (passed to
+.Fn hsearch
+as
+.Fa item.key )
+must be allocated using
+.Xr malloc 3
+if
+.Fa action
+is
+.Dv ENTER
+and
+.Fn hdestroy
+is called.
+.Pp
+The
+.Fn hcreate_r ,
+.Fn hdestroy_r ,
+and
+.Fn hsearch_r
+functions are re-entrant versions of the above functions that can
+operate on a table supplied by the user.
+The
+.Fn hsearch_r
+function returns
+.Dv 0
+if the action is
+.Dv ENTER
+and the element cannot be created,
+.Dv 1
+otherwise.
+If the element exists or can be created, it will be placed in
+.Fa itemp ,
+otherwise
+.Fa itemp
+will be set to
+.Dv NULL .
+.Sh RETURN VALUES
+The
+.Fn hcreate
+and
+.Fn hcreate_r
+functions return 0 if the table creation failed and the global variable
+.Va errno
+is set to indicate the error;
+otherwise, a non-zero value is returned.
+.Pp
+The
+.Fn hdestroy
+and
+.Fn hdestroy_r
+functions return no value.
+.Pp
+The
+.Fn hsearch
+and
+.Fn hsearch_r
+functions return a
+.Dv NULL
+pointer if either the
+.Fa action
+is
+.Dv FIND
+and the
+.Fa item
+could not be found or the
+.Fa action
+is
+.Dv ENTER
+and the table is full.
+.Sh EXAMPLES
+The following example reads in strings followed by two numbers
+and stores them in a hash table, discarding duplicates.
+It then reads in strings and finds the matching entry in the hash
+table and prints it out.
+.Bd -literal
+#include <stdio.h>
+#include <search.h>
+#include <string.h>
+#include <stdlib.h>
+
+struct info { /* This is the info stored in the table */
+ int age, room; /* other than the key. */
+};
+
+#define NUM_EMPL 5000 /* # of elements in search table. */
+
+int
+main(void)
+{
+ char str[BUFSIZ]; /* Space to read string */
+ struct info info_space[NUM_EMPL]; /* Space to store employee info. */
+ struct info *info_ptr = info_space; /* Next space in info_space. */
+ ENTRY item;
+ ENTRY *found_item; /* Name to look for in table. */
+ char name_to_find[30];
+ int i = 0;
+
+ /* Create table; no error checking is performed. */
+ (void) hcreate(NUM_EMPL);
+
+ while (scanf("%s%d%d", str, &info_ptr->age,
+ &info_ptr->room) != EOF && i++ < NUM_EMPL) {
+ /* Put information in structure, and structure in item. */
+ item.key = strdup(str);
+ item.data = info_ptr;
+ info_ptr++;
+ /* Put item into table. */
+ (void) hsearch(item, ENTER);
+ }
+
+ /* Access table. */
+ item.key = name_to_find;
+ while (scanf("%s", item.key) != EOF) {
+ if ((found_item = hsearch(item, FIND)) != NULL) {
+ /* If item is in the table. */
+ (void)printf("found %s, age = %d, room = %d\en",
+ found_item->key,
+ ((struct info *)found_item->data)->age,
+ ((struct info *)found_item->data)->room);
+ } else
+ (void)printf("no such employee %s\en", name_to_find);
+ }
+ hdestroy();
+ return 0;
+}
+.Ed
+.Sh ERRORS
+The
+.Fn hcreate
+.Fn hcreate_r ,
+.Fn hsearch
+and
+.Fn hsearch_r
+functions will fail if:
+.Bl -tag -width Er
+.It Bq Er ENOMEM
+Insufficient memory is available.
+.El
+.Pp
+The
+.Fn hsearch
+and
+.Fn hsearch_r
+functions will also fail if the action is
+.Dv SEARCH
+and the element is not found:
+.Bl -tag -width Er
+.It Bq Er ESRCH
+The
+.Fa item
+given is not found.
+.El
+.Sh SEE ALSO
+.Xr bsearch 3 ,
+.Xr lsearch 3 ,
+.Xr malloc 3 ,
+.Xr strcmp 3 ,
+.Xr tsearch 3
+.Sh STANDARDS
+The
+.Fn hcreate ,
+.Fn hdestroy ,
+and
+.Fn hsearch
+functions conform to
+.St -xpg4.2 .
+.Sh HISTORY
+The
+.Fn hcreate ,
+.Fn hdestroy ,
+and
+.Fn hsearch
+functions first appeared in
+.At V .
+The
+.Fn hcreate_r ,
+.Fn hdestroy_r
+and
+.Fn hsearch_r
+functions are
+.Tn GNU
+extensions.
+.Sh BUGS
+The original,
+.Pf non- Tn GNU
+interface permits the use of only one hash table at a time.
diff --git a/lib/libc/stdlib/hcreate.c b/lib/libc/stdlib/hcreate.c
new file mode 100644
index 000000000000..2d5d943a4d82
--- /dev/null
+++ b/lib/libc/stdlib/hcreate.c
@@ -0,0 +1,73 @@
+/*-
+ * Copyright (c) 2015 Nuxi, https://nuxi.nl/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <search.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+/*
+ * Thread unsafe interface: use a single process-wide hash table and
+ * forward calls to *_r() functions.
+ */
+
+static struct hsearch_data global_hashtable;
+static bool global_hashtable_initialized = false;
+
+int
+hcreate(size_t nel)
+{
+
+ return (1);
+}
+
+void
+hdestroy(void)
+{
+
+ /* Destroy global hash table if present. */
+ if (global_hashtable_initialized) {
+ hdestroy_r(&global_hashtable);
+ global_hashtable_initialized = false;
+ }
+}
+
+ENTRY *
+hsearch(ENTRY item, ACTION action)
+{
+ ENTRY *retval;
+
+ /* Create global hash table if needed. */
+ if (!global_hashtable_initialized) {
+ if (hcreate_r(0, &global_hashtable) == 0)
+ return (NULL);
+ global_hashtable_initialized = true;
+ }
+ if (hsearch_r(item, action, &retval, &global_hashtable) == 0)
+ return (NULL);
+ return (retval);
+}
diff --git a/lib/libc/stdlib/hcreate_r.c b/lib/libc/stdlib/hcreate_r.c
new file mode 100644
index 000000000000..83e322a5621b
--- /dev/null
+++ b/lib/libc/stdlib/hcreate_r.c
@@ -0,0 +1,63 @@
+/*-
+ * Copyright (c) 2015 Nuxi, https://nuxi.nl/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <search.h>
+#include <stdlib.h>
+
+#include "hsearch.h"
+
+int
+hcreate_r(size_t nel, struct hsearch_data *htab)
+{
+ struct __hsearch *hsearch;
+
+ /*
+ * Allocate a hash table object. Ignore the provided hint and start
+ * off with a table of sixteen entries. In most cases this hint is
+ * just a wild guess. Resizing the table dynamically if the use
+ * increases a threshold does not affect the worst-case running time.
+ */
+ hsearch = malloc(sizeof(*hsearch));
+ if (hsearch == NULL)
+ return 0;
+ hsearch->entries = calloc(16, sizeof(ENTRY));
+ if (hsearch->entries == NULL) {
+ free(hsearch);
+ return 0;
+ }
+
+ /*
+ * Pick a random initialization for the FNV-1a hashing. This makes it
+ * hard to come up with a fixed set of keys to force hash collisions.
+ */
+ arc4random_buf(&hsearch->offset_basis, sizeof(hsearch->offset_basis));
+ hsearch->index_mask = 0xf;
+ hsearch->entries_used = 0;
+ htab->__hsearch = hsearch;
+ return 1;
+}
diff --git a/lib/libc/stdlib/hdestroy_r.c b/lib/libc/stdlib/hdestroy_r.c
new file mode 100644
index 000000000000..890bd0858e1d
--- /dev/null
+++ b/lib/libc/stdlib/hdestroy_r.c
@@ -0,0 +1,43 @@
+/*-
+ * Copyright (c) 2015 Nuxi, https://nuxi.nl/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <search.h>
+#include <stdlib.h>
+
+#include "hsearch.h"
+
+void
+hdestroy_r(struct hsearch_data *htab)
+{
+ struct __hsearch *hsearch;
+
+ /* Free hash table object and its entries. */
+ hsearch = htab->__hsearch;
+ free(hsearch->entries);
+ free(hsearch);
+}
diff --git a/lib/libc/stdlib/heapsort.c b/lib/libc/stdlib/heapsort.c
new file mode 100644
index 000000000000..db0a95384655
--- /dev/null
+++ b/lib/libc/stdlib/heapsort.c
@@ -0,0 +1,200 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 2014 David T. Chisnall
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ronnie Kon at Mindcraft Inc., Kevin Lew and Elmer Yglesias.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)heapsort.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+#ifdef I_AM_HEAPSORT_B
+#include "block_abi.h"
+#define COMPAR(x, y) CALL_BLOCK(compar, x, y)
+typedef DECLARE_BLOCK(int, heapsort_block, const void *, const void *);
+#else
+#define COMPAR(x, y) compar(x, y)
+#endif
+
+/*
+ * Swap two areas of size number of bytes. Although qsort(3) permits random
+ * blocks of memory to be sorted, sorting pointers is almost certainly the
+ * common case (and, were it not, could easily be made so). Regardless, it
+ * isn't worth optimizing; the SWAP's get sped up by the cache, and pointer
+ * arithmetic gets lost in the time required for comparison function calls.
+ */
+#define SWAP(a, b, count, size, tmp) { \
+ count = size; \
+ do { \
+ tmp = *a; \
+ *a++ = *b; \
+ *b++ = tmp; \
+ } while (--count); \
+}
+
+/* Copy one block of size size to another. */
+#define COPY(a, b, count, size, tmp1, tmp2) { \
+ count = size; \
+ tmp1 = a; \
+ tmp2 = b; \
+ do { \
+ *tmp1++ = *tmp2++; \
+ } while (--count); \
+}
+
+/*
+ * Build the list into a heap, where a heap is defined such that for
+ * the records K1 ... KN, Kj/2 >= Kj for 1 <= j/2 <= j <= N.
+ *
+ * There two cases. If j == nmemb, select largest of Ki and Kj. If
+ * j < nmemb, select largest of Ki, Kj and Kj+1.
+ */
+#define CREATE(initval, nmemb, par_i, child_i, par, child, size, count, tmp) { \
+ for (par_i = initval; (child_i = par_i * 2) <= nmemb; \
+ par_i = child_i) { \
+ child = base + child_i * size; \
+ if (child_i < nmemb && COMPAR(child, child + size) < 0) { \
+ child += size; \
+ ++child_i; \
+ } \
+ par = base + par_i * size; \
+ if (COMPAR(child, par) <= 0) \
+ break; \
+ SWAP(par, child, count, size, tmp); \
+ } \
+}
+
+/*
+ * Select the top of the heap and 'heapify'. Since by far the most expensive
+ * action is the call to the compar function, a considerable optimization
+ * in the average case can be achieved due to the fact that k, the displaced
+ * elememt, is usually quite small, so it would be preferable to first
+ * heapify, always maintaining the invariant that the larger child is copied
+ * over its parent's record.
+ *
+ * Then, starting from the *bottom* of the heap, finding k's correct place,
+ * again maintianing the invariant. As a result of the invariant no element
+ * is 'lost' when k is assigned its correct place in the heap.
+ *
+ * The time savings from this optimization are on the order of 15-20% for the
+ * average case. See Knuth, Vol. 3, page 158, problem 18.
+ *
+ * XXX Don't break the #define SELECT line, below. Reiser cpp gets upset.
+ */
+#define SELECT(par_i, child_i, nmemb, par, child, size, k, count, tmp1, tmp2) { \
+ for (par_i = 1; (child_i = par_i * 2) <= nmemb; par_i = child_i) { \
+ child = base + child_i * size; \
+ if (child_i < nmemb && COMPAR(child, child + size) < 0) { \
+ child += size; \
+ ++child_i; \
+ } \
+ par = base + par_i * size; \
+ COPY(par, child, count, size, tmp1, tmp2); \
+ } \
+ for (;;) { \
+ child_i = par_i; \
+ par_i = child_i / 2; \
+ child = base + child_i * size; \
+ par = base + par_i * size; \
+ if (child_i == 1 || COMPAR(k, par) < 0) { \
+ COPY(child, k, count, size, tmp1, tmp2); \
+ break; \
+ } \
+ COPY(child, par, count, size, tmp1, tmp2); \
+ } \
+}
+
+#ifdef I_AM_HEAPSORT_B
+int heapsort_b(void *, size_t, size_t, heapsort_block);
+#else
+int heapsort(void *, size_t, size_t,
+ int (*)(const void *, const void *));
+#endif
+/*
+ * Heapsort -- Knuth, Vol. 3, page 145. Runs in O (N lg N), both average
+ * and worst. While heapsort is faster than the worst case of quicksort,
+ * the BSD quicksort does median selection so that the chance of finding
+ * a data set that will trigger the worst case is nonexistent. Heapsort's
+ * only advantage over quicksort is that it requires little additional memory.
+ */
+#ifdef I_AM_HEAPSORT_B
+int
+heapsort_b(void *vbase, size_t nmemb, size_t size, heapsort_block compar)
+#else
+int
+heapsort(void *vbase, size_t nmemb, size_t size,
+ int (*compar)(const void *, const void *))
+#endif
+{
+ size_t cnt, i, j, l;
+ char tmp, *tmp1, *tmp2;
+ char *base, *k, *p, *t;
+
+ if (nmemb <= 1)
+ return (0);
+
+ if (!size) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if ((k = malloc(size)) == NULL)
+ return (-1);
+
+ /*
+ * Items are numbered from 1 to nmemb, so offset from size bytes
+ * below the starting address.
+ */
+ base = (char *)vbase - size;
+
+ for (l = nmemb / 2 + 1; --l;)
+ CREATE(l, nmemb, i, j, t, p, size, cnt, tmp);
+
+ /*
+ * For each element of the heap, save the largest element into its
+ * final slot, save the displaced element (k), then recreate the
+ * heap.
+ */
+ while (nmemb > 1) {
+ COPY(k, base + nmemb * size, cnt, size, tmp1, tmp2);
+ COPY(base + nmemb * size, base + size, cnt, size, tmp1, tmp2);
+ --nmemb;
+ SELECT(i, j, nmemb, t, p, size, k, cnt, tmp1, tmp2);
+ }
+ free(k);
+ return (0);
+}
diff --git a/lib/libc/stdlib/heapsort_b.c b/lib/libc/stdlib/heapsort_b.c
new file mode 100644
index 000000000000..b1814bc2e0df
--- /dev/null
+++ b/lib/libc/stdlib/heapsort_b.c
@@ -0,0 +1,29 @@
+/*-
+ * Copyright (c) 2014 David Chisnall
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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$
+ */
+#define I_AM_HEAPSORT_B
+#include "heapsort.c"
diff --git a/lib/libc/stdlib/hsearch.h b/lib/libc/stdlib/hsearch.h
new file mode 100644
index 000000000000..649933d05e67
--- /dev/null
+++ b/lib/libc/stdlib/hsearch.h
@@ -0,0 +1,40 @@
+/*-
+ * Copyright (c) 2015 Nuxi, https://nuxi.nl/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef HSEARCH_H
+#define HSEARCH_H
+
+#include <search.h>
+
+struct __hsearch {
+ size_t offset_basis; /* Initial value for FNV-1a hashing. */
+ size_t index_mask; /* Bitmask for indexing the table. */
+ size_t entries_used; /* Number of entries currently used. */
+ ENTRY *entries; /* Hash table entries. */
+};
+
+#endif
diff --git a/lib/libc/stdlib/hsearch_r.c b/lib/libc/stdlib/hsearch_r.c
new file mode 100644
index 000000000000..2fb599186d75
--- /dev/null
+++ b/lib/libc/stdlib/hsearch_r.c
@@ -0,0 +1,150 @@
+/*-
+ * Copyright (c) 2015 Nuxi, https://nuxi.nl/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <limits.h>
+#include <search.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "hsearch.h"
+
+/*
+ * Look up an unused entry in the hash table for a given hash. For this
+ * implementation we use quadratic probing. Quadratic probing has the
+ * advantage of preventing primary clustering.
+ */
+static ENTRY *
+hsearch_lookup_free(struct __hsearch *hsearch, size_t hash)
+{
+ size_t index, i;
+
+ for (index = hash, i = 0;; index += ++i) {
+ ENTRY *entry = &hsearch->entries[index & hsearch->index_mask];
+ if (entry->key == NULL)
+ return (entry);
+ }
+}
+
+/*
+ * Computes an FNV-1a hash of the key. Depending on the pointer size, this
+ * either uses the 32- or 64-bit FNV prime.
+ */
+static size_t
+hsearch_hash(size_t offset_basis, const char *str)
+{
+ size_t hash;
+
+ hash = offset_basis;
+ while (*str != '\0') {
+ hash ^= (uint8_t)*str++;
+ if (sizeof(size_t) * CHAR_BIT <= 32)
+ hash *= UINT32_C(16777619);
+ else
+ hash *= UINT64_C(1099511628211);
+ }
+ return (hash);
+}
+
+int
+hsearch_r(ENTRY item, ACTION action, ENTRY **retval, struct hsearch_data *htab)
+{
+ struct __hsearch *hsearch;
+ ENTRY *entry, *old_entries, *new_entries;
+ size_t hash, index, i, old_hash, old_count, new_count;
+
+ hsearch = htab->__hsearch;
+ hash = hsearch_hash(hsearch->offset_basis, item.key);
+
+ /*
+ * Search the hash table for an existing entry for this key.
+ * Stop searching if we run into an unused hash table entry.
+ */
+ for (index = hash, i = 0;; index += ++i) {
+ entry = &hsearch->entries[index & hsearch->index_mask];
+ if (entry->key == NULL)
+ break;
+ if (strcmp(entry->key, item.key) == 0) {
+ *retval = entry;
+ return (1);
+ }
+ }
+
+ /* Only perform the insertion if action is set to ENTER. */
+ if (action == FIND) {
+ errno = ESRCH;
+ return (0);
+ }
+
+ if (hsearch->entries_used * 2 >= hsearch->index_mask) {
+ /* Preserve the old hash table entries. */
+ old_count = hsearch->index_mask + 1;
+ old_entries = hsearch->entries;
+
+ /*
+ * Allocate and install a new table if insertion would
+ * yield a hash table that is more than 50% used. By
+ * using 50% as a threshold, a lookup will only take up
+ * to two steps on average.
+ */
+ new_count = (hsearch->index_mask + 1) * 2;
+ new_entries = calloc(new_count, sizeof(ENTRY));
+ if (new_entries == NULL)
+ return (0);
+ hsearch->entries = new_entries;
+ hsearch->index_mask = new_count - 1;
+
+ /* Copy over the entries from the old table to the new table. */
+ for (i = 0; i < old_count; ++i) {
+ entry = &old_entries[i];
+ if (entry->key != NULL) {
+ old_hash = hsearch_hash(hsearch->offset_basis,
+ entry->key);
+ *hsearch_lookup_free(hsearch, old_hash) =
+ *entry;
+ }
+ }
+
+ /* Destroy the old hash table entries. */
+ free(old_entries);
+
+ /*
+ * Perform a new lookup for a free table entry, so that
+ * we insert the entry into the new hash table.
+ */
+ hsearch = htab->__hsearch;
+ entry = hsearch_lookup_free(hsearch, hash);
+ }
+
+ /* Insert the new entry into the hash table. */
+ *entry = item;
+ ++hsearch->entries_used;
+ *retval = entry;
+ return (1);
+}
diff --git a/lib/libc/stdlib/imaxabs.3 b/lib/libc/stdlib/imaxabs.3
new file mode 100644
index 000000000000..430f873280f5
--- /dev/null
+++ b/lib/libc/stdlib/imaxabs.3
@@ -0,0 +1,62 @@
+.\" Copyright (c) 2001 Mike Barcroft <mike@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd November 14, 2001
+.Dt IMAXABS 3
+.Os
+.Sh NAME
+.Nm imaxabs
+.Nd returns absolute value
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In inttypes.h
+.Ft intmax_t
+.Fn imaxabs "intmax_t j"
+.Sh DESCRIPTION
+The
+.Fn imaxabs
+function returns the absolute value of
+.Fa j .
+.Sh SEE ALSO
+.Xr abs 3 ,
+.Xr fabs 3 ,
+.Xr hypot 3 ,
+.Xr labs 3 ,
+.Xr llabs 3 ,
+.Xr math 3
+.Sh STANDARDS
+The
+.Fn imaxabs
+function conforms to
+.St -isoC-99 .
+.Sh HISTORY
+The
+.Fn imaxabs
+function first appeared in
+.Fx 5.0 .
+.Sh BUGS
+The absolute value of the most negative integer remains negative.
diff --git a/lib/libc/stdlib/imaxabs.c b/lib/libc/stdlib/imaxabs.c
new file mode 100644
index 000000000000..35e3dee79d36
--- /dev/null
+++ b/lib/libc/stdlib/imaxabs.c
@@ -0,0 +1,36 @@
+/*-
+ * Copyright (c) 2001 Mike Barcroft <mike@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <inttypes.h>
+
+intmax_t
+imaxabs(intmax_t j)
+{
+ return (j < 0 ? -j : j);
+}
diff --git a/lib/libc/stdlib/imaxdiv.3 b/lib/libc/stdlib/imaxdiv.3
new file mode 100644
index 000000000000..0ee0971a81be
--- /dev/null
+++ b/lib/libc/stdlib/imaxdiv.3
@@ -0,0 +1,73 @@
+.\" Copyright (c) 2001 Mike Barcroft <mike@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd November 14, 2001
+.Dt IMAXDIV 3
+.Os
+.Sh NAME
+.Nm imaxdiv
+.Nd returns quotient and remainder
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In inttypes.h
+.Ft imaxdiv_t
+.Fn imaxdiv "intmax_t numer" "intmax_t denom"
+.Sh DESCRIPTION
+The
+.Fn imaxdiv
+function computes the value of
+.Fa numer
+divided by
+.Fa denom
+and returns the stored result in the form of the
+.Vt imaxdiv_t
+type.
+.Pp
+The
+.Vt imaxdiv_t
+type is defined as:
+.Bd -literal -offset indent
+typedef struct {
+ intmax_t quot; /* Quotient. */
+ intmax_t rem; /* Remainder. */
+} imaxdiv_t;
+.Ed
+.Sh SEE ALSO
+.Xr div 3 ,
+.Xr ldiv 3 ,
+.Xr lldiv 3 ,
+.Xr math 3
+.Sh STANDARDS
+The
+.Fn imaxdiv
+function conforms to
+.St -isoC-99 .
+.Sh HISTORY
+The
+.Fn imaxdiv
+function first appeared in
+.Fx 5.0 .
diff --git a/lib/libc/stdlib/imaxdiv.c b/lib/libc/stdlib/imaxdiv.c
new file mode 100644
index 000000000000..adcab0b14dbb
--- /dev/null
+++ b/lib/libc/stdlib/imaxdiv.c
@@ -0,0 +1,47 @@
+/*-
+ * Copyright (c) 2001 Mike Barcroft <mike@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <inttypes.h>
+
+/* See comments in div.c for implementation details. */
+imaxdiv_t
+imaxdiv(intmax_t numer, intmax_t denom)
+{
+ imaxdiv_t retval;
+
+ retval.quot = numer / denom;
+ retval.rem = numer % denom;
+#if !defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L)
+ if (numer >= 0 && retval.rem < 0) {
+ retval.quot++;
+ retval.rem -= denom;
+ }
+#endif
+ return (retval);
+}
diff --git a/lib/libc/stdlib/insque.3 b/lib/libc/stdlib/insque.3
new file mode 100644
index 000000000000..a54434c6d316
--- /dev/null
+++ b/lib/libc/stdlib/insque.3
@@ -0,0 +1,61 @@
+.\"
+.\" Initial implementation:
+.\" Copyright (c) 2002 Robert Drehmel
+.\" All rights reserved.
+.\"
+.\" As long as the above copyright statement and this notice remain
+.\" unchanged, you can do what ever you want with this file.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd October 10, 2002
+.Dt INSQUE 3
+.Os
+.Sh NAME
+.Nm insque ,
+.Nm remque
+.Nd doubly-linked list management
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In search.h
+.Ft void
+.Fn insque "void *element1" "void *pred"
+.Ft void
+.Fn remque "void *element"
+.Sh DESCRIPTION
+The
+.Fn insque
+and
+.Fn remque
+functions encapsulate the ever-repeating task of doing insertion and
+removal operations on doubly linked lists.
+The functions expect their
+arguments to point to a structure whose first and second members are
+pointers to the next and previous element, respectively.
+The
+.Fn insque
+function also allows the
+.Fa pred
+argument to be a
+.Dv NULL
+pointer for the initialization of a new list's
+head element.
+.Sh STANDARDS
+The
+.Fn insque
+and
+.Fn remque
+functions conform to
+.St -p1003.1-2001 .
+.Sh HISTORY
+The
+.Fn insque
+and
+.Fn remque
+functions appeared in
+.Bx 4.2 .
+In
+.Fx 5.0 ,
+they reappeared conforming to
+.St -p1003.1-2001 .
diff --git a/lib/libc/stdlib/insque.c b/lib/libc/stdlib/insque.c
new file mode 100644
index 000000000000..388e4d592617
--- /dev/null
+++ b/lib/libc/stdlib/insque.c
@@ -0,0 +1,47 @@
+/*
+ * Initial implementation:
+ * Copyright (c) 2002 Robert Drehmel
+ * All rights reserved.
+ *
+ * As long as the above copyright statement and this notice remain
+ * unchanged, you can do what ever you want with this file.
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#define _SEARCH_PRIVATE
+#include <search.h>
+#ifdef DEBUG
+#include <stdio.h>
+#else
+#include <stdlib.h> /* for NULL */
+#endif
+
+void
+insque(void *element, void *pred)
+{
+ struct que_elem *prev, *next, *elem;
+
+ elem = (struct que_elem *)element;
+ prev = (struct que_elem *)pred;
+
+ if (prev == NULL) {
+ elem->prev = elem->next = NULL;
+ return;
+ }
+
+ next = prev->next;
+ if (next != NULL) {
+#ifdef DEBUG
+ if (next->prev != prev) {
+ fprintf(stderr, "insque: Inconsistency detected:"
+ " next(%p)->prev(%p) != prev(%p)\n",
+ next, next->prev, prev);
+ }
+#endif
+ next->prev = elem;
+ }
+ prev->next = elem;
+ elem->prev = prev;
+ elem->next = next;
+}
diff --git a/lib/libc/stdlib/jemalloc/Makefile.inc b/lib/libc/stdlib/jemalloc/Makefile.inc
new file mode 100644
index 000000000000..f491e95759d1
--- /dev/null
+++ b/lib/libc/stdlib/jemalloc/Makefile.inc
@@ -0,0 +1,49 @@
+# $FreeBSD$
+
+.PATH: ${LIBC_SRCTOP}/stdlib/jemalloc
+
+JEMALLOCSRCS:= jemalloc.c arena.c atomic.c base.c bitmap.c chunk.c \
+ chunk_dss.c chunk_mmap.c ckh.c ctl.c extent.c hash.c huge.c mb.c \
+ mutex.c nstime.c pages.c prng.c prof.c quarantine.c rtree.c spin.c \
+ stats.c tcache.c ticker.c tsd.c util.c witness.c
+
+SYM_MAPS+=${LIBC_SRCTOP}/stdlib/jemalloc/Symbol.map
+
+CFLAGS+=-I${SRCTOP}/contrib/jemalloc/include
+
+.for src in ${JEMALLOCSRCS}
+MISRCS+=jemalloc_${src}
+CLEANFILES+=jemalloc_${src}
+jemalloc_${src}: ${SRCTOP}/contrib/jemalloc/src/${src} .NOMETA
+ ln -sf ${.ALLSRC} ${.TARGET}
+.endfor
+
+MAN+=jemalloc.3
+CLEANFILES+=jemalloc.3
+jemalloc.3: ${SRCTOP}/contrib/jemalloc/doc/jemalloc.3 .NOMETA
+ ln -sf ${.ALLSRC} ${.TARGET}
+
+MLINKS+= \
+ jemalloc.3 malloc.3 \
+ jemalloc.3 calloc.3 \
+ jemalloc.3 posix_memalign.3 \
+ jemalloc.3 aligned_alloc.3 \
+ jemalloc.3 realloc.3 \
+ jemalloc.3 free.3 \
+ jemalloc.3 malloc_usable_size.3 \
+ jemalloc.3 malloc_stats_print.3 \
+ jemalloc.3 mallctl.3 \
+ jemalloc.3 mallctlnametomib.3 \
+ jemalloc.3 mallctlbymib.3 \
+ jemalloc.3 mallocx.3 \
+ jemalloc.3 rallocx.3 \
+ jemalloc.3 xallocx.3 \
+ jemalloc.3 sallocx.3 \
+ jemalloc.3 dallocx.3 \
+ jemalloc.3 sdallocx.3 \
+ jemalloc.3 nallocx.3 \
+ jemalloc.3 malloc.conf.5
+
+.if defined(MALLOC_PRODUCTION)
+CFLAGS+= -DMALLOC_PRODUCTION
+.endif
diff --git a/lib/libc/stdlib/jemalloc/Symbol.map b/lib/libc/stdlib/jemalloc/Symbol.map
new file mode 100644
index 000000000000..087ca53ff75f
--- /dev/null
+++ b/lib/libc/stdlib/jemalloc/Symbol.map
@@ -0,0 +1,69 @@
+/*
+ * $FreeBSD$
+ */
+
+FBSD_1.0 {
+ _malloc_options;
+ _malloc_message;
+ malloc;
+ posix_memalign;
+ calloc;
+ realloc;
+ free;
+ malloc_usable_size;
+};
+
+FBSD_1.3 {
+ malloc_conf;
+ malloc_message;
+ aligned_alloc;
+ malloc_stats_print;
+ mallctl;
+ mallctlnametomib;
+ mallctlbymib;
+ mallocx;
+ rallocx;
+ xallocx;
+ sallocx;
+ dallocx;
+ nallocx;
+ allocm;
+ rallocm;
+ sallocm;
+ dallocm;
+ nallocm;
+ __malloc;
+ __calloc;
+ __realloc;
+ __free;
+ __posix_memalign;
+ __malloc_usable_size;
+ __mallocx;
+ __rallocx;
+ __xallocx;
+ __sallocx;
+ __dallocx;
+ __nallocx;
+ __allocm;
+ __rallocm;
+ __sallocm;
+ __dallocm;
+ __nallocm;
+};
+
+FBSD_1.4 {
+ sdallocx;
+ __sdallocx;
+ __aligned_alloc;
+ __malloc_stats_print;
+ __mallctl;
+ __mallctlnametomib;
+ __mallctlbymib;
+};
+
+FBSDprivate_1.0 {
+ _malloc_thread_cleanup;
+ _malloc_prefork;
+ _malloc_postfork;
+ _malloc_first_thread;
+};
diff --git a/lib/libc/stdlib/l64a.c b/lib/libc/stdlib/l64a.c
new file mode 100644
index 000000000000..c281d7d823c3
--- /dev/null
+++ b/lib/libc/stdlib/l64a.c
@@ -0,0 +1,44 @@
+/*
+ * Written by J.T. Conklin <jtc@NetBSD.org>.
+ * Public domain.
+ */
+
+#if 0
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: l64a.c,v 1.13 2003/07/26 19:24:54 salo Exp $");
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdint.h>
+#include <stdlib.h>
+
+char *
+l64a(long value)
+{
+ static char buf[7];
+
+ (void)l64a_r(value, buf, sizeof(buf));
+ return (buf);
+}
+
+int
+l64a_r(long value, char *buffer, int buflen)
+{
+ static const char chars[] =
+ "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+ uint32_t v;
+
+ v = value;
+ while (buflen-- > 0) {
+ if (v == 0) {
+ *buffer = '\0';
+ return (0);
+ }
+ *buffer++ = chars[v & 0x3f];
+ v >>= 6;
+ }
+ return (-1);
+}
diff --git a/lib/libc/stdlib/labs.3 b/lib/libc/stdlib/labs.3
new file mode 100644
index 000000000000..bbd32124f476
--- /dev/null
+++ b/lib/libc/stdlib/labs.3
@@ -0,0 +1,67 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)labs.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd November 14, 2001
+.Dt LABS 3
+.Os
+.Sh NAME
+.Nm labs
+.Nd return the absolute value of a long integer
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft long
+.Fn labs "long j"
+.Sh DESCRIPTION
+The
+.Fn labs
+function
+returns the absolute value of the long integer
+.Fa j .
+.Sh SEE ALSO
+.Xr abs 3 ,
+.Xr cabs 3 ,
+.Xr floor 3 ,
+.Xr imaxabs 3 ,
+.Xr llabs 3 ,
+.Xr math 3
+.Sh STANDARDS
+The
+.Fn labs
+function
+conforms to
+.St -isoC .
+.Sh BUGS
+The absolute value of the most negative integer remains negative.
diff --git a/lib/libc/stdlib/labs.c b/lib/libc/stdlib/labs.c
new file mode 100644
index 000000000000..ef068826c2f3
--- /dev/null
+++ b/lib/libc/stdlib/labs.c
@@ -0,0 +1,42 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)labs.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdlib.h>
+
+long
+labs(long j)
+{
+ return(j < 0 ? -j : j);
+}
diff --git a/lib/libc/stdlib/ldiv.3 b/lib/libc/stdlib/ldiv.3
new file mode 100644
index 000000000000..ce4d01771b11
--- /dev/null
+++ b/lib/libc/stdlib/ldiv.3
@@ -0,0 +1,71 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek and the American National Standards Committee X3,
+.\" on Information Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)ldiv.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd November 14, 2001
+.Dt LDIV 3
+.Os
+.Sh NAME
+.Nm ldiv
+.Nd return quotient and remainder from division
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft ldiv_t
+.Fn ldiv "long num" "long denom"
+.Sh DESCRIPTION
+The
+.Fn ldiv
+function
+computes the value
+.Fa num Ns / Ns Fa denom
+and returns the quotient and remainder in a structure named
+.Vt ldiv_t
+that contains two
+.Vt long
+members named
+.Va quot
+and
+.Va rem .
+.Sh SEE ALSO
+.Xr div 3 ,
+.Xr imaxdiv 3 ,
+.Xr lldiv 3 ,
+.Xr math 3
+.Sh STANDARDS
+The
+.Fn ldiv
+function
+conforms to
+.St -isoC-99 .
diff --git a/lib/libc/stdlib/ldiv.c b/lib/libc/stdlib/ldiv.c
new file mode 100644
index 000000000000..745c5667e6a4
--- /dev/null
+++ b/lib/libc/stdlib/ldiv.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)ldiv.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdlib.h> /* ldiv_t */
+
+ldiv_t
+ldiv(num, denom)
+ long num, denom;
+{
+ ldiv_t r;
+
+ /* see div.c for comments */
+
+ r.quot = num / denom;
+ r.rem = num % denom;
+#if !defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L)
+ if (num >= 0 && r.rem < 0) {
+ r.quot++;
+ r.rem -= denom;
+ }
+#endif
+ return (r);
+}
diff --git a/lib/libc/stdlib/llabs.3 b/lib/libc/stdlib/llabs.3
new file mode 100644
index 000000000000..8c031a940d6f
--- /dev/null
+++ b/lib/libc/stdlib/llabs.3
@@ -0,0 +1,62 @@
+.\" Copyright (c) 2001 Mike Barcroft <mike@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd November 14, 2001
+.Dt LLABS 3
+.Os
+.Sh NAME
+.Nm llabs
+.Nd returns absolute value
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft "long long"
+.Fn llabs "long long j"
+.Sh DESCRIPTION
+The
+.Fn llabs
+function returns the absolute value of
+.Fa j .
+.Sh SEE ALSO
+.Xr abs 3 ,
+.Xr fabs 3 ,
+.Xr hypot 3 ,
+.Xr imaxabs 3 ,
+.Xr labs 3 ,
+.Xr math 3
+.Sh STANDARDS
+The
+.Fn llabs
+function conforms to
+.St -isoC-99 .
+.Sh HISTORY
+The
+.Fn llabs
+function first appeared in
+.Fx 5.0 .
+.Sh BUGS
+The absolute value of the most negative integer remains negative.
diff --git a/lib/libc/stdlib/llabs.c b/lib/libc/stdlib/llabs.c
new file mode 100644
index 000000000000..2bfbada80d93
--- /dev/null
+++ b/lib/libc/stdlib/llabs.c
@@ -0,0 +1,36 @@
+/*-
+ * Copyright (c) 2001 Mike Barcroft <mike@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdlib.h>
+
+long long
+llabs(long long j)
+{
+ return (j < 0 ? -j : j);
+}
diff --git a/lib/libc/stdlib/lldiv.3 b/lib/libc/stdlib/lldiv.3
new file mode 100644
index 000000000000..976a997b9cc8
--- /dev/null
+++ b/lib/libc/stdlib/lldiv.3
@@ -0,0 +1,73 @@
+.\" Copyright (c) 2001 Mike Barcroft <mike@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd November 14, 2001
+.Dt LLDIV 3
+.Os
+.Sh NAME
+.Nm lldiv
+.Nd returns quotient and remainder
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft lldiv_t
+.Fn lldiv "long long numer" "long long denom"
+.Sh DESCRIPTION
+The
+.Fn lldiv
+function computes the value of
+.Fa numer
+divided by
+.Fa denom
+and returns the stored result in the form of the
+.Vt lldiv_t
+type.
+.Pp
+The
+.Vt lldiv_t
+type is defined as:
+.Bd -literal -offset indent
+typedef struct {
+ long long quot; /* Quotient. */
+ long long rem; /* Remainder. */
+} lldiv_t;
+.Ed
+.Sh SEE ALSO
+.Xr div 3 ,
+.Xr imaxdiv 3 ,
+.Xr ldiv 3 ,
+.Xr math 3
+.Sh STANDARDS
+The
+.Fn lldiv
+function conforms to
+.St -isoC-99 .
+.Sh HISTORY
+The
+.Fn lldiv
+function first appeared in
+.Fx 5.0 .
diff --git a/lib/libc/stdlib/lldiv.c b/lib/libc/stdlib/lldiv.c
new file mode 100644
index 000000000000..197b48f3f51e
--- /dev/null
+++ b/lib/libc/stdlib/lldiv.c
@@ -0,0 +1,47 @@
+/*-
+ * Copyright (c) 2001 Mike Barcroft <mike@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdlib.h>
+
+/* See comments in div.c for implementation details. */
+lldiv_t
+lldiv(long long numer, long long denom)
+{
+ lldiv_t retval;
+
+ retval.quot = numer / denom;
+ retval.rem = numer % denom;
+#if !defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L)
+ if (numer >= 0 && retval.rem < 0) {
+ retval.quot++;
+ retval.rem -= denom;
+ }
+#endif
+ return (retval);
+}
diff --git a/lib/libc/stdlib/lsearch.3 b/lib/libc/stdlib/lsearch.3
new file mode 100644
index 000000000000..f2f0105d608b
--- /dev/null
+++ b/lib/libc/stdlib/lsearch.3
@@ -0,0 +1,146 @@
+.\"
+.\" Initial implementation:
+.\" Copyright (c) 2002 Robert Drehmel
+.\" All rights reserved.
+.\"
+.\" As long as the above copyright statement and this notice remain
+.\" unchanged, you can do what ever you want with this file.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd April 17, 2016
+.Dt LSEARCH 3
+.Os
+.Sh NAME
+.Nm lsearch ,
+.Nm lfind
+.Nd linear search and append
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In search.h
+.Ft "void *"
+.Fo lsearch
+.Fa "const void *key" "void *base" "size_t *nelp" "size_t width"
+.Fa "int \*[lp]*compar\*[rp]\*[lp]const void *, const void *\*[rp]"
+.Fc
+.Ft "void *"
+.Fo lfind
+.Fa "const void *key" "const void *base" "size_t *nelp" "size_t width"
+.Fa "int \*[lp]*compar\*[rp]\*[lp]const void *, const void *\*[rp]"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn lsearch
+and
+.Fn lfind
+functions walk linearly through an array and compare each element with
+the one to be sought using a supplied comparison function.
+.Pp
+The
+.Fa key
+argument
+points to an element that matches the one that is searched.
+The array's address in memory is denoted by the
+.Fa base
+argument.
+The width of one element (i.e., the size as returned by
+.Fn sizeof )
+is passed as the
+.Fa width
+argument.
+The number of valid elements contained in the array (not the number of
+elements the array has space reserved for) is given in the integer pointed
+to by
+.Fa nelp .
+The
+.Fa compar
+argument points to a function which compares its two arguments and returns
+zero if they are matching, and non-zero otherwise.
+.Pp
+If no matching element was found in the array,
+.Fn lsearch
+copies
+.Fa key
+into the position after the last element and increments the
+integer pointed to by
+.Fa nelp .
+.Sh RETURN VALUES
+The
+.Fn lsearch
+and
+.Fn lfind
+functions
+return a pointer to the first element found.
+If no element was found,
+.Fn lsearch
+returns a pointer to the newly added element, whereas
+.Fn lfind
+returns
+.Dv NULL .
+Both functions return
+.Dv NULL
+if an error occurs.
+.Sh EXAMPLES
+.Bd -literal
+#include <search.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static int
+element_compare(const void *p1, const void *p2)
+{
+ int left = *(const int *)p1;
+ int right = *(const int *)p2;
+
+ return (left - right);
+}
+
+int
+main(int argc, char **argv)
+{
+ const int array[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ size_t element_size = sizeof(array[0]);
+ size_t array_size = sizeof(array) / element_size;
+ int key;
+ void *element;
+
+ printf("Enter a number: ");
+ if (scanf("%d", &key) != 1) {
+ printf("Bad input\en");
+ return (EXIT_FAILURE);
+ }
+
+ element = lfind(&key, array, &array_size, element_size,
+ element_compare);
+
+ if (element != NULL)
+ printf("Element found: %d\en", *(int *)element);
+ else
+ printf("Element not found\en");
+
+ return (EXIT_SUCCESS);
+}
+.Ed
+.Sh SEE ALSO
+.Xr bsearch 3 ,
+.Xr hsearch 3 ,
+.Xr tsearch 3
+.Sh STANDARDS
+The
+.Fn lsearch
+and
+.Fn lfind
+functions conform to
+.St -p1003.1-2001 .
+.Sh HISTORY
+The
+.Fn lsearch
+and
+.Fn lfind
+functions appeared in
+.Bx 4.2 .
+In
+.Fx 5.0 ,
+they reappeared conforming to
+.St -p1003.1-2001 .
diff --git a/lib/libc/stdlib/lsearch.c b/lib/libc/stdlib/lsearch.c
new file mode 100644
index 000000000000..9e9cdbaf619d
--- /dev/null
+++ b/lib/libc/stdlib/lsearch.c
@@ -0,0 +1,60 @@
+/*
+ * Initial implementation:
+ * Copyright (c) 2002 Robert Drehmel
+ * All rights reserved.
+ *
+ * As long as the above copyright statement and this notice remain
+ * unchanged, you can do what ever you want with this file.
+ */
+#include <sys/types.h>
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#define _SEARCH_PRIVATE
+#include <search.h>
+#include <stdint.h> /* for uint8_t */
+#include <stdlib.h> /* for NULL */
+#include <string.h> /* for memcpy() prototype */
+
+static void *lwork(const void *, const void *, size_t *, size_t,
+ int (*)(const void *, const void *), int);
+
+void *lsearch(const void *key, void *base, size_t *nelp, size_t width,
+ int (*compar)(const void *, const void *))
+{
+
+ return (lwork(key, base, nelp, width, compar, 1));
+}
+
+void *lfind(const void *key, const void *base, size_t *nelp, size_t width,
+ int (*compar)(const void *, const void *))
+{
+
+ return (lwork(key, base, nelp, width, compar, 0));
+}
+
+static void *
+lwork(const void *key, const void *base, size_t *nelp, size_t width,
+ int (*compar)(const void *, const void *), int addelem)
+{
+ uint8_t *ep, *endp;
+
+ ep = __DECONST(uint8_t *, base);
+ for (endp = (uint8_t *)(ep + width * *nelp); ep < endp; ep += width) {
+ if (compar(key, ep) == 0)
+ return (ep);
+ }
+
+ /* lfind() shall return when the key was not found. */
+ if (!addelem)
+ return (NULL);
+
+ /*
+ * lsearch() adds the key to the end of the table and increments
+ * the number of elements.
+ */
+ memcpy(endp, key, width);
+ ++*nelp;
+
+ return (endp);
+}
diff --git a/lib/libc/stdlib/memory.3 b/lib/libc/stdlib/memory.3
new file mode 100644
index 000000000000..b78ddae8aab0
--- /dev/null
+++ b/lib/libc/stdlib/memory.3
@@ -0,0 +1,77 @@
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)memory.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt MEMORY 3
+.Os
+.Sh NAME
+.Nm malloc ,
+.Nm free ,
+.Nm realloc ,
+.Nm calloc ,
+.Nm alloca ,
+.Nm mmap
+.Nd general memory allocation operations
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft void *
+.Fn malloc "size_t size"
+.Ft void
+.Fn free "void *ptr"
+.Ft void *
+.Fn realloc "void *ptr" "size_t size"
+.Ft void *
+.Fn calloc "size_t nelem" "size_t elsize"
+.Ft void *
+.Fn alloca "size_t size"
+.In sys/types.h
+.In sys/mman.h
+.Ft void *
+.Fn mmap "void * addr" "size_t len" "int prot" "int flags" "int fd" "off_t offset"
+.Sh DESCRIPTION
+These functions allocate and free memory for the calling process.
+They are described in the
+individual manual pages.
+.Sh SEE ALSO
+.Xr mmap 2 ,
+.Xr alloca 3 ,
+.Xr calloc 3 ,
+.Xr free 3 ,
+.Xr malloc 3 ,
+.Xr realloc 3
+.Sh STANDARDS
+These functions, with the exception of
+.Fn alloca
+and
+.Fn mmap
+conform to
+.St -isoC .
diff --git a/lib/libc/stdlib/merge.c b/lib/libc/stdlib/merge.c
new file mode 100644
index 000000000000..55b3a0c4fae1
--- /dev/null
+++ b/lib/libc/stdlib/merge.c
@@ -0,0 +1,359 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Peter McIlroy.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)merge.c 8.2 (Berkeley) 2/14/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Hybrid exponential search/linear search merge sort with hybrid
+ * natural/pairwise first pass. Requires about .3% more comparisons
+ * for random data than LSMS with pairwise first pass alone.
+ * It works for objects as small as two bytes.
+ */
+
+#define NATURAL
+#define THRESHOLD 16 /* Best choice for natural merge cut-off. */
+
+/* #define NATURAL to get hybrid natural merge.
+ * (The default is pairwise merging.)
+ */
+
+#include <sys/types.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef I_AM_MERGESORT_B
+#include "block_abi.h"
+#define DECLARE_CMP DECLARE_BLOCK(int, cmp, const void *, const void *)
+typedef DECLARE_BLOCK(int, cmp_t, const void *, const void *);
+#define CMP(x, y) CALL_BLOCK(cmp, x, y)
+#else
+typedef int (*cmp_t)(const void *, const void *);
+#define CMP(x, y) cmp(x, y)
+#endif
+
+static void setup(u_char *, u_char *, size_t, size_t, cmp_t);
+static void insertionsort(u_char *, size_t, size_t, cmp_t);
+
+#define ISIZE sizeof(int)
+#define PSIZE sizeof(u_char *)
+#define ICOPY_LIST(src, dst, last) \
+ do \
+ *(int*)dst = *(int*)src, src += ISIZE, dst += ISIZE; \
+ while(src < last)
+#define ICOPY_ELT(src, dst, i) \
+ do \
+ *(int*) dst = *(int*) src, src += ISIZE, dst += ISIZE; \
+ while (i -= ISIZE)
+
+#define CCOPY_LIST(src, dst, last) \
+ do \
+ *dst++ = *src++; \
+ while (src < last)
+#define CCOPY_ELT(src, dst, i) \
+ do \
+ *dst++ = *src++; \
+ while (i -= 1)
+
+/*
+ * Find the next possible pointer head. (Trickery for forcing an array
+ * to do double duty as a linked list when objects do not align with word
+ * boundaries.
+ */
+/* Assumption: PSIZE is a power of 2. */
+#define EVAL(p) (u_char **) \
+ ((u_char *)0 + \
+ (((u_char *)p + PSIZE - 1 - (u_char *) 0) & ~(PSIZE - 1)))
+
+#ifdef I_AM_MERGESORT_B
+int mergesort_b(void *, size_t, size_t, cmp_t);
+#else
+int mergesort(void *, size_t, size_t, cmp_t);
+#endif
+
+/*
+ * Arguments are as for qsort.
+ */
+int
+#ifdef I_AM_MERGESORT_B
+mergesort_b(void *base, size_t nmemb, size_t size, cmp_t cmp)
+#else
+mergesort(void *base, size_t nmemb, size_t size, cmp_t cmp)
+#endif
+{
+ size_t i;
+ int sense;
+ int big, iflag;
+ u_char *f1, *f2, *t, *b, *tp2, *q, *l1, *l2;
+ u_char *list2, *list1, *p2, *p, *last, **p1;
+
+ if (size < PSIZE / 2) { /* Pointers must fit into 2 * size. */
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (nmemb == 0)
+ return (0);
+
+ /*
+ * XXX
+ * Stupid subtraction for the Cray.
+ */
+ iflag = 0;
+ if (!(size % ISIZE) && !(((char *)base - (char *)0) % ISIZE))
+ iflag = 1;
+
+ if ((list2 = malloc(nmemb * size + PSIZE)) == NULL)
+ return (-1);
+
+ list1 = base;
+ setup(list1, list2, nmemb, size, cmp);
+ last = list2 + nmemb * size;
+ i = big = 0;
+ while (*EVAL(list2) != last) {
+ l2 = list1;
+ p1 = EVAL(list1);
+ for (tp2 = p2 = list2; p2 != last; p1 = EVAL(l2)) {
+ p2 = *EVAL(p2);
+ f1 = l2;
+ f2 = l1 = list1 + (p2 - list2);
+ if (p2 != last)
+ p2 = *EVAL(p2);
+ l2 = list1 + (p2 - list2);
+ while (f1 < l1 && f2 < l2) {
+ if (CMP(f1, f2) <= 0) {
+ q = f2;
+ b = f1, t = l1;
+ sense = -1;
+ } else {
+ q = f1;
+ b = f2, t = l2;
+ sense = 0;
+ }
+ if (!big) { /* here i = 0 */
+ while ((b += size) < t && CMP(q, b) >sense)
+ if (++i == 6) {
+ big = 1;
+ goto EXPONENTIAL;
+ }
+ } else {
+EXPONENTIAL: for (i = size; ; i <<= 1)
+ if ((p = (b + i)) >= t) {
+ if ((p = t - size) > b &&
+ CMP(q, p) <= sense)
+ t = p;
+ else
+ b = p;
+ break;
+ } else if (CMP(q, p) <= sense) {
+ t = p;
+ if (i == size)
+ big = 0;
+ goto FASTCASE;
+ } else
+ b = p;
+ while (t > b+size) {
+ i = (((t - b) / size) >> 1) * size;
+ if (CMP(q, p = b + i) <= sense)
+ t = p;
+ else
+ b = p;
+ }
+ goto COPY;
+FASTCASE: while (i > size)
+ if (CMP(q,
+ p = b + (i >>= 1)) <= sense)
+ t = p;
+ else
+ b = p;
+COPY: b = t;
+ }
+ i = size;
+ if (q == f1) {
+ if (iflag) {
+ ICOPY_LIST(f2, tp2, b);
+ ICOPY_ELT(f1, tp2, i);
+ } else {
+ CCOPY_LIST(f2, tp2, b);
+ CCOPY_ELT(f1, tp2, i);
+ }
+ } else {
+ if (iflag) {
+ ICOPY_LIST(f1, tp2, b);
+ ICOPY_ELT(f2, tp2, i);
+ } else {
+ CCOPY_LIST(f1, tp2, b);
+ CCOPY_ELT(f2, tp2, i);
+ }
+ }
+ }
+ if (f2 < l2) {
+ if (iflag)
+ ICOPY_LIST(f2, tp2, l2);
+ else
+ CCOPY_LIST(f2, tp2, l2);
+ } else if (f1 < l1) {
+ if (iflag)
+ ICOPY_LIST(f1, tp2, l1);
+ else
+ CCOPY_LIST(f1, tp2, l1);
+ }
+ *p1 = l2;
+ }
+ tp2 = list1; /* swap list1, list2 */
+ list1 = list2;
+ list2 = tp2;
+ last = list2 + nmemb*size;
+ }
+ if (base == list2) {
+ memmove(list2, list1, nmemb*size);
+ list2 = list1;
+ }
+ free(list2);
+ return (0);
+}
+
+#define swap(a, b) { \
+ s = b; \
+ i = size; \
+ do { \
+ tmp = *a; *a++ = *s; *s++ = tmp; \
+ } while (--i); \
+ a -= size; \
+ }
+#define reverse(bot, top) { \
+ s = top; \
+ do { \
+ i = size; \
+ do { \
+ tmp = *bot; *bot++ = *s; *s++ = tmp; \
+ } while (--i); \
+ s -= size2; \
+ } while(bot < s); \
+}
+
+/*
+ * Optional hybrid natural/pairwise first pass. Eats up list1 in runs of
+ * increasing order, list2 in a corresponding linked list. Checks for runs
+ * when THRESHOLD/2 pairs compare with same sense. (Only used when NATURAL
+ * is defined. Otherwise simple pairwise merging is used.)
+ */
+void
+setup(u_char *list1, u_char *list2, size_t n, size_t size, cmp_t cmp)
+{
+ int i, length, size2, tmp, sense;
+ u_char *f1, *f2, *s, *l2, *last, *p2;
+
+ size2 = size*2;
+ if (n <= 5) {
+ insertionsort(list1, n, size, cmp);
+ *EVAL(list2) = (u_char*) list2 + n*size;
+ return;
+ }
+ /*
+ * Avoid running pointers out of bounds; limit n to evens
+ * for simplicity.
+ */
+ i = 4 + (n & 1);
+ insertionsort(list1 + (n - i) * size, i, size, cmp);
+ last = list1 + size * (n - i);
+ *EVAL(list2 + (last - list1)) = list2 + n * size;
+
+#ifdef NATURAL
+ p2 = list2;
+ f1 = list1;
+ sense = (CMP(f1, f1 + size) > 0);
+ for (; f1 < last; sense = !sense) {
+ length = 2;
+ /* Find pairs with same sense. */
+ for (f2 = f1 + size2; f2 < last; f2 += size2) {
+ if ((CMP(f2, f2+ size) > 0) != sense)
+ break;
+ length += 2;
+ }
+ if (length < THRESHOLD) { /* Pairwise merge */
+ do {
+ p2 = *EVAL(p2) = f1 + size2 - list1 + list2;
+ if (sense > 0)
+ swap (f1, f1 + size);
+ } while ((f1 += size2) < f2);
+ } else { /* Natural merge */
+ l2 = f2;
+ for (f2 = f1 + size2; f2 < l2; f2 += size2) {
+ if ((CMP(f2-size, f2) > 0) != sense) {
+ p2 = *EVAL(p2) = f2 - list1 + list2;
+ if (sense > 0)
+ reverse(f1, f2-size);
+ f1 = f2;
+ }
+ }
+ if (sense > 0)
+ reverse (f1, f2-size);
+ f1 = f2;
+ if (f2 < last || CMP(f2 - size, f2) > 0)
+ p2 = *EVAL(p2) = f2 - list1 + list2;
+ else
+ p2 = *EVAL(p2) = list2 + n*size;
+ }
+ }
+#else /* pairwise merge only. */
+ for (f1 = list1, p2 = list2; f1 < last; f1 += size2) {
+ p2 = *EVAL(p2) = p2 + size2;
+ if (CMP (f1, f1 + size) > 0)
+ swap(f1, f1 + size);
+ }
+#endif /* NATURAL */
+}
+
+/*
+ * This is to avoid out-of-bounds addresses in sorting the
+ * last 4 elements.
+ */
+static void
+insertionsort(u_char *a, size_t n, size_t size, cmp_t cmp)
+{
+ u_char *ai, *s, *t, *u, tmp;
+ int i;
+
+ for (ai = a+size; --n >= 1; ai += size)
+ for (t = ai; t > a; t -= size) {
+ u = t - size;
+ if (CMP(u, t) <= 0)
+ break;
+ swap(u, t);
+ }
+}
diff --git a/lib/libc/stdlib/mergesort_b.c b/lib/libc/stdlib/mergesort_b.c
new file mode 100644
index 000000000000..acf5987ddefc
--- /dev/null
+++ b/lib/libc/stdlib/mergesort_b.c
@@ -0,0 +1,29 @@
+/*-
+ * Copyright (c) 2014 David Chisnall
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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$
+ */
+#define I_AM_MERGESORT_B
+#include "merge.c"
diff --git a/lib/libc/stdlib/ptsname.3 b/lib/libc/stdlib/ptsname.3
new file mode 100644
index 000000000000..8e8ec07d1e53
--- /dev/null
+++ b/lib/libc/stdlib/ptsname.3
@@ -0,0 +1,161 @@
+.\"
+.\" Copyright (c) 2002 The FreeBSD Project, Inc.
+.\" All rights reserved.
+.\"
+.\" This software includes code contributed to the FreeBSD Project
+.\" by Ryan Younce of North Carolina State University.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the FreeBSD Project nor the names of its
+.\" contributors may be used to endorse or promote products derived from
+.\" this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE FREEBSD PROJECT AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+.\" PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FREEBSD PROJECT
+.\" OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+.\" TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+.\" PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+.\" LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (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 August 20, 2008
+.Dt PTSNAME 3
+.Os
+.Sh NAME
+.Nm grantpt ,
+.Nm ptsname ,
+.Nm unlockpt
+.Nd pseudo-terminal access functions
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft int
+.Fn grantpt "int fildes"
+.Ft "char *"
+.Fn ptsname "int fildes"
+.Ft int
+.Fn unlockpt "int fildes"
+.Sh DESCRIPTION
+The
+.Fn grantpt ,
+.Fn ptsname ,
+and
+.Fn unlockpt
+functions allow access to pseudo-terminal devices.
+These three functions accept a file descriptor that references the
+master half of a pseudo-terminal pair.
+This file descriptor is created with
+.Xr posix_openpt 2 .
+.Pp
+The
+.Fn grantpt
+function is used to establish ownership and permissions
+of the slave device counterpart to the master device
+specified with
+.Fa fildes .
+The slave device's ownership is set to the real user ID
+of the calling process, and the permissions are set to
+user readable-writable and group writable.
+The group owner of the slave device is also set to the
+group
+.Dq Li tty .
+.Pp
+The
+.Fn ptsname
+function returns the full pathname of the slave device
+counterpart to the master device specified with
+.Fa fildes .
+This value can be used
+to subsequently open the appropriate slave after
+.Xr posix_openpt 2
+and
+.Fn grantpt
+have been called.
+.Pp
+The
+.Fn unlockpt
+function clears the lock held on the pseudo-terminal pair
+for the master device specified with
+.Fa fildes .
+.Sh RETURN VALUES
+.Rv -std grantpt unlockpt
+.Pp
+The
+.Fn ptsname
+function returns a pointer to the name
+of the slave device on success; otherwise a
+.Dv NULL
+pointer is returned.
+.Sh ERRORS
+The
+.Fn grantpt ,
+.Fn ptsname
+and
+.Fn unlockpt
+functions may fail and set
+.Va errno
+to:
+.Bl -tag -width Er
+.It Bq Er EBADF
+.Fa fildes
+is not a valid open file descriptor.
+.It Bq Er EINVAL
+.Fa fildes
+is not a master pseudo-terminal device.
+.El
+.Pp
+In addition, the
+.Fn grantpt
+function may set
+.Va errno
+to:
+.Bl -tag -width Er
+.It Bq Er EACCES
+The slave pseudo-terminal device could not be accessed.
+.El
+.Sh SEE ALSO
+.Xr posix_openpt 2 ,
+.Xr pts 4 ,
+.Xr tty 4
+.Sh STANDARDS
+The
+.Fn ptsname
+function conforms to
+.St -p1003.1-2008 .
+.Pp
+This implementation of
+.Fn grantpt
+and
+.Fn unlockpt
+does not conform to
+.St -p1003.1-2008 ,
+because it depends on
+.Xr posix_openpt 2
+to create the pseudo-terminal device with proper permissions in place.
+It only validates whether
+.Fa fildes
+is a valid pseudo-terminal master device.
+Future revisions of the specification will likely allow this behaviour,
+as stated by the Austin Group.
+.Sh HISTORY
+The
+.Fn grantpt ,
+.Fn ptsname
+and
+.Fn unlockpt
+functions appeared in
+.Fx 5.0 .
diff --git a/lib/libc/stdlib/ptsname.c b/lib/libc/stdlib/ptsname.c
new file mode 100644
index 000000000000..3e4d4c096ef5
--- /dev/null
+++ b/lib/libc/stdlib/ptsname.c
@@ -0,0 +1,91 @@
+/*-
+ * Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Portions of this software were developed under sponsorship from Snow
+ * B.V., the Netherlands.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__FBSDID("$FreeBSD$");
+#endif /* not lint */
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <sys/ioctl.h>
+
+#include <errno.h>
+#include <paths.h>
+#include <stdlib.h>
+#include "un-namespace.h"
+
+/*
+ * __isptmaster(): return whether the file descriptor refers to a
+ * pseudo-terminal master device.
+ */
+static int
+__isptmaster(int fildes)
+{
+
+ if (_ioctl(fildes, TIOCPTMASTER) == 0)
+ return (0);
+
+ if (errno != EBADF)
+ errno = EINVAL;
+
+ return (-1);
+}
+
+/*
+ * In our implementation, grantpt() and unlockpt() don't actually have
+ * any use, because PTY's are created on the fly and already have proper
+ * permissions upon creation.
+ *
+ * Just make sure `fildes' actually points to a real PTY master device.
+ */
+__strong_reference(__isptmaster, grantpt);
+__strong_reference(__isptmaster, unlockpt);
+
+/*
+ * ptsname(): return the pathname of the slave pseudo-terminal device
+ * associated with the specified master.
+ */
+char *
+ptsname(int fildes)
+{
+ static char pt_slave[sizeof _PATH_DEV + SPECNAMELEN] = _PATH_DEV;
+ char *ret = NULL;
+
+ /* Make sure fildes points to a master device. */
+ if (__isptmaster(fildes) != 0)
+ goto done;
+
+ if (fdevname_r(fildes, pt_slave + (sizeof _PATH_DEV - 1),
+ sizeof pt_slave - (sizeof _PATH_DEV - 1)) != NULL)
+ ret = pt_slave;
+
+done:
+ return (ret);
+}
diff --git a/lib/libc/stdlib/qsort.3 b/lib/libc/stdlib/qsort.3
new file mode 100644
index 000000000000..af885ee5f762
--- /dev/null
+++ b/lib/libc/stdlib/qsort.3
@@ -0,0 +1,366 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)qsort.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd February 20, 2013
+.Dt QSORT 3
+.Os
+.Sh NAME
+.Nm qsort , qsort_b , qsort_r , heapsort , heapsort_b , mergesort, mergesort_b
+.Nd sort functions
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft void
+.Fo qsort
+.Fa "void *base"
+.Fa "size_t nmemb"
+.Fa "size_t size"
+.Fa "int \*[lp]*compar\*[rp]\*[lp]const void *, const void *\*[rp]"
+.Fc
+.Ft void
+.Fo qsort_b
+.Fa "void *base"
+.Fa "size_t nmemb"
+.Fa "size_t size"
+.Fa "int \*[lp]^compar\*[rp]\*[lp]const void *, const void *\*[rp]"
+.Fc
+.Ft void
+.Fo qsort_r
+.Fa "void *base"
+.Fa "size_t nmemb"
+.Fa "size_t size"
+.Fa "void *thunk"
+.Fa "int \*[lp]*compar\*[rp]\*[lp]void *, const void *, const void *\*[rp]"
+.Fc
+.Ft int
+.Fo heapsort
+.Fa "void *base"
+.Fa "size_t nmemb"
+.Fa "size_t size"
+.Fa "int \*[lp]*compar\*[rp]\*[lp]const void *, const void *\*[rp]"
+.Fc
+.Ft int
+.Fo heapsort_b
+.Fa "void *base"
+.Fa "size_t nmemb"
+.Fa "size_t size"
+.Fa "int \*[lp]^compar\*[rp]\*[lp]const void *, const void *\*[rp]"
+.Fc
+.Ft int
+.Fo mergesort
+.Fa "void *base"
+.Fa "size_t nmemb"
+.Fa "size_t size"
+.Fa "int \*[lp]*compar\*[rp]\*[lp]const void *, const void *\*[rp]"
+.Fc
+.Ft int
+.Fo mergesort_b
+.Fa "void *base"
+.Fa "size_t nmemb"
+.Fa "size_t size"
+.Fa "int \*[lp]^compar\*[rp]\*[lp]const void *, const void *\*[rp]"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn qsort
+function is a modified partition-exchange sort, or quicksort.
+The
+.Fn heapsort
+function is a modified selection sort.
+The
+.Fn mergesort
+function is a modified merge sort with exponential search
+intended for sorting data with pre-existing order.
+.Pp
+The
+.Fn qsort
+and
+.Fn heapsort
+functions sort an array of
+.Fa nmemb
+objects, the initial member of which is pointed to by
+.Fa base .
+The size of each object is specified by
+.Fa size .
+The
+.Fn mergesort
+function
+behaves similarly, but
+.Em requires
+that
+.Fa size
+be greater than
+.Dq "sizeof(void *) / 2" .
+.Pp
+The contents of the array
+.Fa base
+are sorted in ascending order according to
+a comparison function pointed to by
+.Fa compar ,
+which requires two arguments pointing to the objects being
+compared.
+.Pp
+The comparison function must return an integer less than, equal to, or
+greater than zero if the first argument is considered to be respectively
+less than, equal to, or greater than the second.
+.Pp
+The
+.Fn qsort_r
+function behaves identically to
+.Fn qsort ,
+except that it takes an additional argument,
+.Fa thunk ,
+which is passed unchanged as the first argument to function pointed to
+.Fa compar .
+This allows the comparison function to access additional
+data without using global variables, and thus
+.Fn qsort_r
+is suitable for use in functions which must be reentrant.
+The
+.Fn qsort_b
+function behaves identically to
+.Fn qsort ,
+except that it takes a block, rather than a function pointer.
+.Pp
+The algorithms implemented by
+.Fn qsort ,
+.Fn qsort_r ,
+and
+.Fn heapsort
+are
+.Em not
+stable, that is, if two members compare as equal, their order in
+the sorted array is undefined.
+The
+.Fn heapsort_b
+function behaves identically to
+.Fn heapsort ,
+except that it takes a block, rather than a function pointer.
+The
+.Fn mergesort
+algorithm is stable.
+The
+.Fn mergesort_b
+function behaves identically to
+.Fn mergesort ,
+except that it takes a block, rather than a function pointer.
+.Pp
+The
+.Fn qsort
+and
+.Fn qsort_r
+functions are an implementation of C.A.R.
+Hoare's
+.Dq quicksort
+algorithm,
+a variant of partition-exchange sorting; in particular, see
+.An D.E. Knuth Ns 's
+.%T "Algorithm Q" .
+.Sy Quicksort
+takes O N lg N average time.
+This implementation uses median selection to avoid its
+O N**2 worst-case behavior.
+.Pp
+The
+.Fn heapsort
+function is an implementation of
+.An "J.W.J. William" Ns 's
+.Dq heapsort
+algorithm,
+a variant of selection sorting; in particular, see
+.An "D.E. Knuth" Ns 's
+.%T "Algorithm H" .
+.Sy Heapsort
+takes O N lg N worst-case time.
+Its
+.Em only
+advantage over
+.Fn qsort
+is that it uses almost no additional memory; while
+.Fn qsort
+does not allocate memory, it is implemented using recursion.
+.Pp
+The function
+.Fn mergesort
+requires additional memory of size
+.Fa nmemb *
+.Fa size
+bytes; it should be used only when space is not at a premium.
+The
+.Fn mergesort
+function
+is optimized for data with pre-existing order; its worst case
+time is O N lg N; its best case is O N.
+.Pp
+Normally,
+.Fn qsort
+is faster than
+.Fn mergesort
+is faster than
+.Fn heapsort .
+Memory availability and pre-existing order in the data can make this
+untrue.
+.Sh RETURN VALUES
+The
+.Fn qsort
+and
+.Fn qsort_r
+functions
+return no value.
+.Pp
+.Rv -std heapsort mergesort
+.Sh EXAMPLES
+A sample program that sorts an array of
+.Vt int
+values in place using
+.Fn qsort ,
+and then prints the sorted array to standard output is:
+.Bd -literal
+#include <stdio.h>
+#include <stdlib.h>
+
+/*
+ * Custom comparison function that compares 'int' values through pointers
+ * passed by qsort(3).
+ */
+static int
+int_compare(const void *p1, const void *p2)
+{
+ int left = *(const int *)p1;
+ int right = *(const int *)p2;
+
+ return ((left > right) - (left < right));
+}
+
+/*
+ * Sort an array of 'int' values and print it to standard output.
+ */
+int
+main(void)
+{
+ int int_array[] = { 4, 5, 9, 3, 0, 1, 7, 2, 8, 6 };
+ size_t array_size = sizeof(int_array) / sizeof(int_array[0]);
+ size_t k;
+
+ qsort(&int_array, array_size, sizeof(int_array[0]), int_compare);
+ for (k = 0; k < array_size; k++)
+ printf(" %d", int_array[k]);
+ puts("");
+ return (EXIT_SUCCESS);
+}
+.Ed
+.Sh COMPATIBILITY
+Previous versions of
+.Fn qsort
+did not permit the comparison routine itself to call
+.Fn qsort 3 .
+This is no longer true.
+.Sh ERRORS
+The
+.Fn heapsort
+and
+.Fn mergesort
+functions succeed unless:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa size
+argument is zero, or,
+the
+.Fa size
+argument to
+.Fn mergesort
+is less than
+.Dq "sizeof(void *) / 2" .
+.It Bq Er ENOMEM
+The
+.Fn heapsort
+or
+.Fn mergesort
+functions
+were unable to allocate memory.
+.El
+.Sh SEE ALSO
+.Xr sort 1 ,
+.Xr radixsort 3
+.Rs
+.%A Hoare, C.A.R.
+.%D 1962
+.%T "Quicksort"
+.%J "The Computer Journal"
+.%V 5:1
+.%P pp. 10-15
+.Re
+.Rs
+.%A Williams, J.W.J
+.%D 1964
+.%T "Heapsort"
+.%J "Communications of the ACM"
+.%V 7:1
+.%P pp. 347-348
+.Re
+.Rs
+.%A Knuth, D.E.
+.%D 1968
+.%B "The Art of Computer Programming"
+.%V Vol. 3
+.%T "Sorting and Searching"
+.%P pp. 114-123, 145-149
+.Re
+.Rs
+.%A McIlroy, P.M.
+.%T "Optimistic Sorting and Information Theoretic Complexity"
+.%J "Fourth Annual ACM-SIAM Symposium on Discrete Algorithms"
+.%V January 1992
+.Re
+.Rs
+.%A Bentley, J.L.
+.%A McIlroy, M.D.
+.%T "Engineering a Sort Function"
+.%J "Software--Practice and Experience"
+.%V Vol. 23(11)
+.%P pp. 1249-1265
+.%D November\ 1993
+.Re
+.Sh STANDARDS
+The
+.Fn qsort
+function
+conforms to
+.St -isoC .
+.Sh HISTORY
+The variants of these functions that take blocks as arguments first appeared in
+Mac OS X.
+This implementation was created by David Chisnall.
diff --git a/lib/libc/stdlib/qsort.c b/lib/libc/stdlib/qsort.c
new file mode 100644
index 000000000000..08816887cf79
--- /dev/null
+++ b/lib/libc/stdlib/qsort.c
@@ -0,0 +1,202 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)qsort.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdlib.h>
+
+#ifdef I_AM_QSORT_R
+typedef int cmp_t(void *, const void *, const void *);
+#else
+typedef int cmp_t(const void *, const void *);
+#endif
+static inline char *med3(char *, char *, char *, cmp_t *, void *);
+static inline void swapfunc(char *, char *, int, int, int);
+
+#define MIN(a, b) ((a) < (b) ? a : b)
+
+/*
+ * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
+ */
+#define swapcode(TYPE, parmi, parmj, n) { \
+ long i = (n) / sizeof (TYPE); \
+ TYPE *pi = (TYPE *) (parmi); \
+ TYPE *pj = (TYPE *) (parmj); \
+ do { \
+ TYPE t = *pi; \
+ *pi++ = *pj; \
+ *pj++ = t; \
+ } while (--i > 0); \
+}
+
+#define SWAPINIT(TYPE, a, es) swaptype_ ## TYPE = \
+ ((char *)a - (char *)0) % sizeof(TYPE) || \
+ es % sizeof(TYPE) ? 2 : es == sizeof(TYPE) ? 0 : 1;
+
+static inline void
+swapfunc( char *a, char *b, int n, int swaptype_long, int swaptype_int)
+{
+ if (swaptype_long <= 1)
+ swapcode(long, a, b, n)
+ else if (swaptype_int <= 1)
+ swapcode(int, a, b, n)
+ else
+ swapcode(char, a, b, n)
+}
+
+#define swap(a, b) \
+ if (swaptype_long == 0) { \
+ long t = *(long *)(a); \
+ *(long *)(a) = *(long *)(b); \
+ *(long *)(b) = t; \
+ } else if (swaptype_int == 0) { \
+ int t = *(int *)(a); \
+ *(int *)(a) = *(int *)(b); \
+ *(int *)(b) = t; \
+ } else \
+ swapfunc(a, b, es, swaptype_long, swaptype_int)
+
+#define vecswap(a, b, n) \
+ if ((n) > 0) swapfunc(a, b, n, swaptype_long, swaptype_int)
+
+#ifdef I_AM_QSORT_R
+#define CMP(t, x, y) (cmp((t), (x), (y)))
+#else
+#define CMP(t, x, y) (cmp((x), (y)))
+#endif
+
+static inline char *
+med3(char *a, char *b, char *c, cmp_t *cmp, void *thunk
+#ifndef I_AM_QSORT_R
+__unused
+#endif
+)
+{
+ return CMP(thunk, a, b) < 0 ?
+ (CMP(thunk, b, c) < 0 ? b : (CMP(thunk, a, c) < 0 ? c : a ))
+ :(CMP(thunk, b, c) > 0 ? b : (CMP(thunk, a, c) < 0 ? a : c ));
+}
+
+#ifdef I_AM_QSORT_R
+void
+qsort_r(void *a, size_t n, size_t es, void *thunk, cmp_t *cmp)
+#else
+#define thunk NULL
+void
+qsort(void *a, size_t n, size_t es, cmp_t *cmp)
+#endif
+{
+ char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
+ size_t d, r;
+ int cmp_result;
+ int swaptype_long, swaptype_int, swap_cnt;
+
+loop: SWAPINIT(long, a, es);
+ SWAPINIT(int, a, es);
+ swap_cnt = 0;
+ if (n < 7) {
+ for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
+ for (pl = pm;
+ pl > (char *)a && CMP(thunk, pl - es, pl) > 0;
+ pl -= es)
+ swap(pl, pl - es);
+ return;
+ }
+ pm = (char *)a + (n / 2) * es;
+ if (n > 7) {
+ pl = a;
+ pn = (char *)a + (n - 1) * es;
+ if (n > 40) {
+ d = (n / 8) * es;
+ pl = med3(pl, pl + d, pl + 2 * d, cmp, thunk);
+ pm = med3(pm - d, pm, pm + d, cmp, thunk);
+ pn = med3(pn - 2 * d, pn - d, pn, cmp, thunk);
+ }
+ pm = med3(pl, pm, pn, cmp, thunk);
+ }
+ swap(a, pm);
+ pa = pb = (char *)a + es;
+
+ pc = pd = (char *)a + (n - 1) * es;
+ for (;;) {
+ while (pb <= pc && (cmp_result = CMP(thunk, pb, a)) <= 0) {
+ if (cmp_result == 0) {
+ swap_cnt = 1;
+ swap(pa, pb);
+ pa += es;
+ }
+ pb += es;
+ }
+ while (pb <= pc && (cmp_result = CMP(thunk, pc, a)) >= 0) {
+ if (cmp_result == 0) {
+ swap_cnt = 1;
+ swap(pc, pd);
+ pd -= es;
+ }
+ pc -= es;
+ }
+ if (pb > pc)
+ break;
+ swap(pb, pc);
+ swap_cnt = 1;
+ pb += es;
+ pc -= es;
+ }
+ if (swap_cnt == 0) { /* Switch to insertion sort */
+ for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
+ for (pl = pm;
+ pl > (char *)a && CMP(thunk, pl - es, pl) > 0;
+ pl -= es)
+ swap(pl, pl - es);
+ return;
+ }
+
+ pn = (char *)a + n * es;
+ r = MIN(pa - (char *)a, pb - pa);
+ vecswap(a, pb - r, r);
+ r = MIN(pd - pc, pn - pd - es);
+ vecswap(pb, pn - r, r);
+ if ((r = pb - pa) > es)
+#ifdef I_AM_QSORT_R
+ qsort_r(a, r / es, es, thunk, cmp);
+#else
+ qsort(a, r / es, es, cmp);
+#endif
+ if ((r = pd - pc) > es) {
+ /* Iterate rather than recurse to save stack space */
+ a = pn - r;
+ n = r / es;
+ goto loop;
+ }
+/* qsort(pn - r, r / es, es, cmp);*/
+}
diff --git a/lib/libc/stdlib/qsort_r.c b/lib/libc/stdlib/qsort_r.c
new file mode 100644
index 000000000000..f489d31c2335
--- /dev/null
+++ b/lib/libc/stdlib/qsort_r.c
@@ -0,0 +1,19 @@
+/*
+ * This file is in the public domain. Originally written by Garrett
+ * A. Wollman.
+ *
+ * $FreeBSD$
+ */
+#include "block_abi.h"
+#define I_AM_QSORT_R
+#include "qsort.c"
+
+typedef DECLARE_BLOCK(int, qsort_block, const void *, const void *);
+
+void
+qsort_b(void *base, size_t nel, size_t width, qsort_block compar)
+{
+ qsort_r(base, nel, width, compar,
+ (int (*)(void *, const void *, const void *))
+ GET_BLOCK_FUNCTION(compar));
+}
diff --git a/lib/libc/stdlib/quick_exit.3 b/lib/libc/stdlib/quick_exit.3
new file mode 100644
index 000000000000..7bbd2f3d53b7
--- /dev/null
+++ b/lib/libc/stdlib/quick_exit.3
@@ -0,0 +1,58 @@
+.\" Copyright (c) 2011 David Chisnall
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd December 13, 2014
+.Dt QUICK_EXIT 3
+.Os
+.Sh NAME
+.Nm quick_exit
+.Nd exits a program quickly, running minimal cleanup
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft _Noreturn void
+.Fn quick_exit "int status"
+.Sh DESCRIPTION
+The
+.Fn quick_exit
+function exits the program quickly calling any cleanup functions registered
+with
+.Xr at_quick_exit 3
+but not any C++ destructors or cleanup code registered with
+.Xr atexit 3 .
+.Sh RETURN VALUES
+The
+.Fn quick_exit
+function does not return.
+.Sh SEE ALSO
+.Xr at_quick_exit 3 ,
+.Xr exit 3
+.Sh STANDARDS
+The
+.Fn quick_exit
+function conforms to
+.St -isoC-2011 .
diff --git a/lib/libc/stdlib/quick_exit.c b/lib/libc/stdlib/quick_exit.c
new file mode 100644
index 000000000000..ef8cdb1b401a
--- /dev/null
+++ b/lib/libc/stdlib/quick_exit.c
@@ -0,0 +1,80 @@
+/*-
+ * Copyright (c) 2011 David Chisnall
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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 <stdlib.h>
+#include <pthread.h>
+
+/**
+ * Linked list of quick exit handlers. This is simpler than the atexit()
+ * version, because it is not required to support C++ destructors or
+ * DSO-specific cleanups.
+ */
+struct quick_exit_handler {
+ struct quick_exit_handler *next;
+ void (*cleanup)(void);
+};
+
+/**
+ * Lock protecting the handlers list.
+ */
+static pthread_mutex_t atexit_mutex = PTHREAD_MUTEX_INITIALIZER;
+/**
+ * Stack of cleanup handlers. These will be invoked in reverse order when
+ */
+static struct quick_exit_handler *handlers;
+
+int
+at_quick_exit(void (*func)(void))
+{
+ struct quick_exit_handler *h;
+
+ h = malloc(sizeof(*h));
+
+ if (NULL == h)
+ return (1);
+ h->cleanup = func;
+ pthread_mutex_lock(&atexit_mutex);
+ h->next = handlers;
+ handlers = h;
+ pthread_mutex_unlock(&atexit_mutex);
+ return (0);
+}
+
+void
+quick_exit(int status)
+{
+ struct quick_exit_handler *h;
+
+ /*
+ * XXX: The C++ spec requires us to call std::terminate if there is an
+ * exception here.
+ */
+ for (h = handlers; NULL != h; h = h->next)
+ h->cleanup();
+ _Exit(status);
+}
diff --git a/lib/libc/stdlib/radixsort.3 b/lib/libc/stdlib/radixsort.3
new file mode 100644
index 000000000000..5b85bf85f81c
--- /dev/null
+++ b/lib/libc/stdlib/radixsort.3
@@ -0,0 +1,160 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)radixsort.3 8.2 (Berkeley) 1/27/94
+.\" $FreeBSD$
+.\"
+.Dd January 27, 1994
+.Dt RADIXSORT 3
+.Os
+.Sh NAME
+.Nm radixsort , sradixsort
+.Nd radix sort
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In limits.h
+.In stdlib.h
+.Ft int
+.Fn radixsort "const unsigned char **base" "int nmemb" "const unsigned char *table" "unsigned endbyte"
+.Ft int
+.Fn sradixsort "const unsigned char **base" "int nmemb" "const unsigned char *table" "unsigned endbyte"
+.Sh DESCRIPTION
+The
+.Fn radixsort
+and
+.Fn sradixsort
+functions
+are implementations of radix sort.
+.Pp
+These functions sort an array of pointers to byte strings, the initial
+member of which is referenced by
+.Fa base .
+The byte strings may contain any values; the end of each string
+is denoted by the user-specified value
+.Fa endbyte .
+.Pp
+Applications may specify a sort order by providing the
+.Fa table
+argument.
+If
+.Pf non- Dv NULL ,
+.Fa table
+must reference an array of
+.Dv UCHAR_MAX
++ 1 bytes which contains the sort
+weight of each possible byte value.
+The end-of-string byte must have a sort weight of 0 or 255
+(for sorting in reverse order).
+More than one byte may have the same sort weight.
+The
+.Fa table
+argument
+is useful for applications which wish to sort different characters
+equally, for example, providing a table with the same weights
+for A-Z as for a-z will result in a case-insensitive sort.
+If
+.Fa table
+is NULL, the contents of the array are sorted in ascending order
+according to the
+.Tn ASCII
+order of the byte strings they reference and
+.Fa endbyte
+has a sorting weight of 0.
+.Pp
+The
+.Fn sradixsort
+function is stable, that is, if two elements compare as equal, their
+order in the sorted array is unchanged.
+The
+.Fn sradixsort
+function uses additional memory sufficient to hold
+.Fa nmemb
+pointers.
+.Pp
+The
+.Fn radixsort
+function is not stable, but uses no additional memory.
+.Pp
+These functions are variants of most-significant-byte radix sorting; in
+particular, see
+.An "D.E. Knuth" Ns 's
+.%T "Algorithm R"
+and section 5.2.5, exercise 10.
+They take linear time relative to the number of bytes in the strings.
+.Sh RETURN VALUES
+.Rv -std radixsort
+.Sh ERRORS
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The value of the
+.Fa endbyte
+element of
+.Fa table
+is not 0 or 255.
+.El
+.Pp
+Additionally, the
+.Fn sradixsort
+function
+may fail and set
+.Va errno
+for any of the errors specified for the library routine
+.Xr malloc 3 .
+.Sh SEE ALSO
+.Xr sort 1 ,
+.Xr qsort 3
+.Pp
+.Rs
+.%A Knuth, D.E.
+.%D 1968
+.%B "The Art of Computer Programming"
+.%T "Sorting and Searching"
+.%V Vol. 3
+.%P pp. 170-178
+.Re
+.Rs
+.%A Paige, R.
+.%D 1987
+.%T "Three Partition Refinement Algorithms"
+.%J "SIAM J. Comput."
+.%V Vol. 16
+.%N No. 6
+.Re
+.Rs
+.%A McIlroy, P.
+.%D 1993
+.%B "Engineering Radix Sort"
+.%T "Computing Systems"
+.%V Vol. 6:1
+.%P pp. 5-27
+.Re
+.Sh HISTORY
+The
+.Fn radixsort
+function first appeared in
+.Bx 4.4 .
diff --git a/lib/libc/stdlib/radixsort.c b/lib/libc/stdlib/radixsort.c
new file mode 100644
index 000000000000..205f7765a444
--- /dev/null
+++ b/lib/libc/stdlib/radixsort.c
@@ -0,0 +1,311 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Peter McIlroy and by Dan Bernstein at New York University,
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)radixsort.c 8.2 (Berkeley) 4/28/95";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Radixsort routines.
+ *
+ * Program r_sort_a() is unstable but uses O(logN) extra memory for a stack.
+ * Use radixsort(a, n, trace, endchar) for this case.
+ *
+ * For stable sorting (using N extra pointers) use sradixsort(), which calls
+ * r_sort_b().
+ *
+ * For a description of this code, see D. McIlroy, P. McIlroy, K. Bostic,
+ * "Engineering Radix Sort".
+ */
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <errno.h>
+
+typedef struct {
+ const u_char **sa;
+ int sn, si;
+} stack;
+
+static inline void simplesort
+(const u_char **, int, int, const u_char *, u_int);
+static void r_sort_a(const u_char **, int, int, const u_char *, u_int);
+static void r_sort_b(const u_char **, const u_char **, int, int,
+ const u_char *, u_int);
+
+#define THRESHOLD 20 /* Divert to simplesort(). */
+#define SIZE 512 /* Default stack size. */
+
+#define SETUP { \
+ if (tab == NULL) { \
+ tr = tr0; \
+ for (c = 0; c < endch; c++) \
+ tr0[c] = c + 1; \
+ tr0[c] = 0; \
+ for (c++; c < 256; c++) \
+ tr0[c] = c; \
+ endch = 0; \
+ } else { \
+ endch = tab[endch]; \
+ tr = tab; \
+ if (endch != 0 && endch != 255) { \
+ errno = EINVAL; \
+ return (-1); \
+ } \
+ } \
+}
+
+int
+radixsort(const u_char **a, int n, const u_char *tab, u_int endch)
+{
+ const u_char *tr;
+ int c;
+ u_char tr0[256];
+
+ SETUP;
+ r_sort_a(a, n, 0, tr, endch);
+ return (0);
+}
+
+int
+sradixsort(const u_char **a, int n, const u_char *tab, u_int endch)
+{
+ const u_char *tr, **ta;
+ int c;
+ u_char tr0[256];
+
+ SETUP;
+ if (n < THRESHOLD)
+ simplesort(a, n, 0, tr, endch);
+ else {
+ if ((ta = malloc(n * sizeof(a))) == NULL)
+ return (-1);
+ r_sort_b(a, ta, n, 0, tr, endch);
+ free(ta);
+ }
+ return (0);
+}
+
+#define empty(s) (s >= sp)
+#define pop(a, n, i) a = (--sp)->sa, n = sp->sn, i = sp->si
+#define push(a, n, i) sp->sa = a, sp->sn = n, (sp++)->si = i
+#define swap(a, b, t) t = a, a = b, b = t
+
+/* Unstable, in-place sort. */
+static void
+r_sort_a(const u_char **a, int n, int i, const u_char *tr, u_int endch)
+{
+ static int count[256], nc, bmin;
+ int c;
+ const u_char **ak, *r;
+ stack s[SIZE], *sp, *sp0, *sp1, temp;
+ int *cp, bigc;
+ const u_char **an, *t, **aj, **top[256];
+
+ /* Set up stack. */
+ sp = s;
+ push(a, n, i);
+ while (!empty(s)) {
+ pop(a, n, i);
+ if (n < THRESHOLD) {
+ simplesort(a, n, i, tr, endch);
+ continue;
+ }
+ an = a + n;
+
+ /* Make character histogram. */
+ if (nc == 0) {
+ bmin = 255; /* First occupied bin, excluding eos. */
+ for (ak = a; ak < an;) {
+ c = tr[(*ak++)[i]];
+ if (++count[c] == 1 && c != endch) {
+ if (c < bmin)
+ bmin = c;
+ nc++;
+ }
+ }
+ if (sp + nc > s + SIZE) { /* Get more stack. */
+ r_sort_a(a, n, i, tr, endch);
+ continue;
+ }
+ }
+
+ /*
+ * Special case: if all strings have the same
+ * character at position i, move on to the next
+ * character.
+ */
+ if (nc == 1 && count[bmin] == n) {
+ push(a, n, i+1);
+ nc = count[bmin] = 0;
+ continue;
+ }
+
+ /*
+ * Set top[]; push incompletely sorted bins onto stack.
+ * top[] = pointers to last out-of-place element in bins.
+ * count[] = counts of elements in bins.
+ * Before permuting: top[c-1] + count[c] = top[c];
+ * during deal: top[c] counts down to top[c-1].
+ */
+ sp0 = sp1 = sp; /* Stack position of biggest bin. */
+ bigc = 2; /* Size of biggest bin. */
+ if (endch == 0) /* Special case: set top[eos]. */
+ top[0] = ak = a + count[0];
+ else {
+ ak = a;
+ top[255] = an;
+ }
+ for (cp = count + bmin; nc > 0; cp++) {
+ while (*cp == 0) /* Find next non-empty pile. */
+ cp++;
+ if (*cp > 1) {
+ if (*cp > bigc) {
+ bigc = *cp;
+ sp1 = sp;
+ }
+ push(ak, *cp, i+1);
+ }
+ top[cp-count] = ak += *cp;
+ nc--;
+ }
+ swap(*sp0, *sp1, temp); /* Play it safe -- biggest bin last. */
+
+ /*
+ * Permute misplacements home. Already home: everything
+ * before aj, and in bin[c], items from top[c] on.
+ * Inner loop:
+ * r = next element to put in place;
+ * ak = top[r[i]] = location to put the next element.
+ * aj = bottom of 1st disordered bin.
+ * Outer loop:
+ * Once the 1st disordered bin is done, ie. aj >= ak,
+ * aj<-aj + count[c] connects the bins in a linked list;
+ * reset count[c].
+ */
+ for (aj = a; aj < an; *aj = r, aj += count[c], count[c] = 0)
+ for (r = *aj; aj < (ak = --top[c = tr[r[i]]]);)
+ swap(*ak, r, t);
+ }
+}
+
+/* Stable sort, requiring additional memory. */
+static void
+r_sort_b(const u_char **a, const u_char **ta, int n, int i, const u_char *tr,
+ u_int endch)
+{
+ static int count[256], nc, bmin;
+ int c;
+ const u_char **ak, **ai;
+ stack s[512], *sp, *sp0, *sp1, temp;
+ const u_char **top[256];
+ int *cp, bigc;
+
+ sp = s;
+ push(a, n, i);
+ while (!empty(s)) {
+ pop(a, n, i);
+ if (n < THRESHOLD) {
+ simplesort(a, n, i, tr, endch);
+ continue;
+ }
+
+ if (nc == 0) {
+ bmin = 255;
+ for (ak = a + n; --ak >= a;) {
+ c = tr[(*ak)[i]];
+ if (++count[c] == 1 && c != endch) {
+ if (c < bmin)
+ bmin = c;
+ nc++;
+ }
+ }
+ if (sp + nc > s + SIZE) {
+ r_sort_b(a, ta, n, i, tr, endch);
+ continue;
+ }
+ }
+
+ sp0 = sp1 = sp;
+ bigc = 2;
+ if (endch == 0) {
+ top[0] = ak = a + count[0];
+ count[0] = 0;
+ } else {
+ ak = a;
+ top[255] = a + n;
+ count[255] = 0;
+ }
+ for (cp = count + bmin; nc > 0; cp++) {
+ while (*cp == 0)
+ cp++;
+ if ((c = *cp) > 1) {
+ if (c > bigc) {
+ bigc = c;
+ sp1 = sp;
+ }
+ push(ak, c, i+1);
+ }
+ top[cp-count] = ak += c;
+ *cp = 0; /* Reset count[]. */
+ nc--;
+ }
+ swap(*sp0, *sp1, temp);
+
+ for (ak = ta + n, ai = a+n; ak > ta;) /* Copy to temp. */
+ *--ak = *--ai;
+ for (ak = ta+n; --ak >= ta;) /* Deal to piles. */
+ *--top[tr[(*ak)[i]]] = *ak;
+ }
+}
+
+/* insertion sort */
+static inline void
+simplesort(const u_char **a, int n, int b, const u_char *tr, u_int endch)
+{
+ u_char ch;
+ const u_char **ak, **ai, *s, *t;
+
+ for (ak = a+1; --n >= 1; ak++)
+ for (ai = ak; ai > a; ai--) {
+ for (s = ai[0] + b, t = ai[-1] + b;
+ (ch = tr[*s]) != endch; s++, t++)
+ if (ch != tr[*t])
+ break;
+ if (ch >= tr[*t])
+ break;
+ swap(ai[0], ai[-1], s);
+ }
+}
diff --git a/lib/libc/stdlib/rand.3 b/lib/libc/stdlib/rand.3
new file mode 100644
index 000000000000..a8c4a4cb5686
--- /dev/null
+++ b/lib/libc/stdlib/rand.3
@@ -0,0 +1,125 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)rand.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd April 2, 2013
+.Dt RAND 3
+.Os
+.Sh NAME
+.Nm rand ,
+.Nm srand ,
+.Nm sranddev ,
+.Nm rand_r
+.Nd bad random number generator
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft void
+.Fn srand "unsigned seed"
+.Ft void
+.Fn sranddev void
+.Ft int
+.Fn rand void
+.Ft int
+.Fn rand_r "unsigned *ctx"
+.Sh DESCRIPTION
+.Bf -symbolic
+The functions described in this manual page are not cryptographically
+secure.
+Cryptographic applications should use
+.Xr arc4random 3
+instead.
+.Ef
+.Pp
+These interfaces are obsoleted by
+.Xr random 3 .
+.Pp
+The
+.Fn rand
+function computes a sequence of pseudo-random integers in the range
+of 0 to
+.Dv RAND_MAX
+(as defined by the header file
+.In stdlib.h ) .
+.Pp
+The
+.Fn srand
+function sets its argument
+.Fa seed
+as the seed for a new sequence of
+pseudo-random numbers to be returned by
+.Fn rand .
+These sequences are repeatable by calling
+.Fn srand
+with the same seed value.
+.Pp
+If no
+.Fa seed
+value is provided, the functions are automatically
+seeded with a value of 1.
+.Pp
+The
+.Fn sranddev
+function initializes a seed using pseudo-random numbers obtained from the kernel.
+.Pp
+The
+.Fn rand_r
+function
+provides the same functionality as
+.Fn rand .
+A pointer to the context value
+.Fa ctx
+must be supplied by the caller.
+.Pp
+For better generator quality, use
+.Xr random 3
+or
+.Xr lrand48 3 .
+.Sh SEE ALSO
+.Xr arc4random 3 ,
+.Xr lrand48 3 ,
+.Xr random 3 ,
+.Xr random 4
+.Sh STANDARDS
+The
+.Fn rand
+and
+.Fn srand
+functions
+conform to
+.St -isoC .
+.Pp
+The
+.Fn rand_r
+function is as proposed in the POSIX.4a Draft #6 document.
diff --git a/lib/libc/stdlib/rand.c b/lib/libc/stdlib/rand.c
new file mode 100644
index 000000000000..2e0456a9edc3
--- /dev/null
+++ b/lib/libc/stdlib/rand.c
@@ -0,0 +1,151 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Posix rand_r function added May 1999 by Wes Peters <wes@softweyr.com>.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)rand.c 8.1 (Berkeley) 6/14/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <stdlib.h>
+#include "un-namespace.h"
+
+#ifdef TEST
+#include <stdio.h>
+#endif /* TEST */
+
+static int
+do_rand(unsigned long *ctx)
+{
+/*
+ * Compute x = (7^5 * x) mod (2^31 - 1)
+ * without overflowing 31 bits:
+ * (2^31 - 1) = 127773 * (7^5) + 2836
+ * From "Random number generators: good ones are hard to find",
+ * Park and Miller, Communications of the ACM, vol. 31, no. 10,
+ * October 1988, p. 1195.
+ */
+ long hi, lo, x;
+
+ /* Transform to [1, 0x7ffffffe] range. */
+ x = (*ctx % 0x7ffffffe) + 1;
+ hi = x / 127773;
+ lo = x % 127773;
+ x = 16807 * lo - 2836 * hi;
+ if (x < 0)
+ x += 0x7fffffff;
+ /* Transform to [0, 0x7ffffffd] range. */
+ x--;
+ *ctx = x;
+ return (x);
+}
+
+
+int
+rand_r(unsigned *ctx)
+{
+ u_long val;
+ int r;
+
+ val = *ctx;
+ r = do_rand(&val);
+ *ctx = (unsigned)val;
+ return (r);
+}
+
+
+static u_long next = 1;
+
+int
+rand(void)
+{
+ return (do_rand(&next));
+}
+
+void
+srand(unsigned seed)
+{
+ next = seed;
+}
+
+
+/*
+ * sranddev:
+ *
+ * Many programs choose the seed value in a totally predictable manner.
+ * This often causes problems. We seed the generator using pseudo-random
+ * data from the kernel.
+ */
+void
+sranddev(void)
+{
+ int mib[2];
+ size_t len;
+
+ len = sizeof(next);
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_ARND;
+ sysctl(mib, 2, (void *)&next, &len, NULL, 0);
+}
+
+
+#ifdef TEST
+
+main()
+{
+ int i;
+ unsigned myseed;
+
+ printf("seeding rand with 0x19610910: \n");
+ srand(0x19610910);
+
+ printf("generating three pseudo-random numbers:\n");
+ for (i = 0; i < 3; i++)
+ {
+ printf("next random number = %d\n", rand());
+ }
+
+ printf("generating the same sequence with rand_r:\n");
+ myseed = 0x19610910;
+ for (i = 0; i < 3; i++)
+ {
+ printf("next random number = %d\n", rand_r(&myseed));
+ }
+
+ return 0;
+}
+
+#endif /* TEST */
+
diff --git a/lib/libc/stdlib/random.3 b/lib/libc/stdlib/random.3
new file mode 100644
index 000000000000..4a0932509a33
--- /dev/null
+++ b/lib/libc/stdlib/random.3
@@ -0,0 +1,197 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)random.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd July 26, 2016
+.Dt RANDOM 3
+.Os
+.Sh NAME
+.Nm random ,
+.Nm srandom ,
+.Nm srandomdev ,
+.Nm initstate ,
+.Nm setstate
+.Nd better random number generator; routines for changing generators
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft long
+.Fn random void
+.Ft void
+.Fn srandom "unsigned int seed"
+.Ft void
+.Fn srandomdev void
+.Ft char *
+.Fn initstate "unsigned int seed" "char *state" "size_t n"
+.Ft char *
+.Fn setstate "char *state"
+.Sh DESCRIPTION
+.Bf -symbolic
+The functions described in this manual page are not secure.
+Applications which require unpredictable random numbers should use
+.Xr arc4random 3
+instead.
+.Ef
+.Pp
+The
+.Fn random
+function
+uses a non-linear additive feedback random number generator employing a
+default table of size 31 long integers to return successive pseudo-random
+numbers in the range from 0 to
+.if t 2\u\s731\s10\d\(mi1.
+.if n (2**31)\(mi1.
+The period of this random number generator is very large, approximately
+.if t 16\(mu(2\u\s731\s10\d\(mi1).
+.if n 16*((2**31)\(mi1).
+.Pp
+The
+.Fn random
+and
+.Fn srandom
+functions have (almost) the same calling sequence and initialization properties as the
+.Xr rand 3
+and
+.Xr srand 3
+functions.
+The difference is that
+.Xr rand 3
+produces a much less random sequence \(em in fact, the low dozen bits
+generated by rand go through a cyclic pattern.
+All the bits generated by
+.Fn random
+are usable.
+For example,
+.Sq Li random()&01
+will produce a random binary
+value.
+.Pp
+Like
+.Xr rand 3 ,
+.Fn random
+will by default produce a sequence of numbers that can be duplicated
+by calling
+.Fn srandom
+with
+.Ql 1
+as the seed.
+.Pp
+The
+.Fn srandomdev
+routine initializes a state array using
+pseudo-random numbers obtained from the kernel.
+Note that this particular seeding
+procedure can generate states which are impossible to reproduce by
+calling
+.Fn srandom
+with any value, since the succeeding terms in the
+state buffer are no longer derived from the LC algorithm applied to
+a fixed seed.
+.Pp
+The
+.Fn initstate
+routine allows a state array, passed in as an argument, to be initialized
+for future use.
+The size of the state array (in bytes) is used by
+.Fn initstate
+to decide how sophisticated a random number generator it should use \(em the
+more state, the better the random numbers will be.
+(Current "optimal" values for the amount of state information are
+8, 32, 64, 128, and 256 bytes; other amounts will be rounded down to
+the nearest known amount.
+Using less than 8 bytes will cause an error.)
+The seed for the initialization (which specifies a starting point for
+the random number sequence, and provides for restarting at the same
+point) is also an argument.
+The
+.Fn initstate
+function
+returns a pointer to the previous state information array.
+.Pp
+Once a state has been initialized, the
+.Fn setstate
+routine provides for rapid switching between states.
+The
+.Fn setstate
+function
+returns a pointer to the previous state array; its
+argument state array is used for further random number generation
+until the next call to
+.Fn initstate
+or
+.Fn setstate .
+.Pp
+Once a state array has been initialized, it may be restarted at a
+different point either by calling
+.Fn initstate
+(with the desired seed, the state array, and its size) or by calling
+both
+.Fn setstate
+(with the state array) and
+.Fn srandom
+(with the desired seed).
+The advantage of calling both
+.Fn setstate
+and
+.Fn srandom
+is that the size of the state array does not have to be remembered after
+it is initialized.
+.Pp
+With 256 bytes of state information, the period of the random number
+generator is greater than
+.if t 2\u\s769\s10\d,
+.if n 2**69
+which should be sufficient for most purposes.
+.Sh DIAGNOSTICS
+If
+.Fn initstate
+is called with less than 8 bytes of state information, or if
+.Fn setstate
+detects that the state information has been garbled,
+NULL is returned.
+.Sh SEE ALSO
+.Xr arc4random 3 ,
+.Xr lrand48 3 ,
+.Xr rand 3 ,
+.Xr random 4
+.Sh HISTORY
+These
+functions appeared in
+.Bx 4.2 .
+.Sh AUTHORS
+.An Earl T. Cohen
+.Sh BUGS
+About 2/3 the speed of
+.Xr rand 3 .
+.Pp
+The historical implementation used to have a very weak seeding; the
+random sequence did not vary much with the seed.
+The current implementation employs a better pseudo-random number
+generator for the initial state calculation.
diff --git a/lib/libc/stdlib/random.c b/lib/libc/stdlib/random.c
new file mode 100644
index 000000000000..48b120578698
--- /dev/null
+++ b/lib/libc/stdlib/random.c
@@ -0,0 +1,453 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)random.c 8.2 (Berkeley) 5/19/95";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include "un-namespace.h"
+
+/*
+ * random.c:
+ *
+ * An improved random number generation package. In addition to the standard
+ * rand()/srand() like interface, this package also has a special state info
+ * interface. The initstate() routine is called with a seed, an array of
+ * bytes, and a count of how many bytes are being passed in; this array is
+ * then initialized to contain information for random number generation with
+ * that much state information. Good sizes for the amount of state
+ * information are 32, 64, 128, and 256 bytes. The state can be switched by
+ * calling the setstate() routine with the same array as was initiallized
+ * with initstate(). By default, the package runs with 128 bytes of state
+ * information and generates far better random numbers than a linear
+ * congruential generator. If the amount of state information is less than
+ * 32 bytes, a simple linear congruential R.N.G. is used.
+ *
+ * Internally, the state information is treated as an array of uint32_t's; the
+ * zeroeth element of the array is the type of R.N.G. being used (small
+ * integer); the remainder of the array is the state information for the
+ * R.N.G. Thus, 32 bytes of state information will give 7 ints worth of
+ * state information, which will allow a degree seven polynomial. (Note:
+ * the zeroeth word of state information also has some other information
+ * stored in it -- see setstate() for details).
+ *
+ * The random number generation technique is a linear feedback shift register
+ * approach, employing trinomials (since there are fewer terms to sum up that
+ * way). In this approach, the least significant bit of all the numbers in
+ * the state table will act as a linear feedback shift register, and will
+ * have period 2^deg - 1 (where deg is the degree of the polynomial being
+ * used, assuming that the polynomial is irreducible and primitive). The
+ * higher order bits will have longer periods, since their values are also
+ * influenced by pseudo-random carries out of the lower bits. The total
+ * period of the generator is approximately deg*(2**deg - 1); thus doubling
+ * the amount of state information has a vast influence on the period of the
+ * generator. Note: the deg*(2**deg - 1) is an approximation only good for
+ * large deg, when the period of the shift is the dominant factor.
+ * With deg equal to seven, the period is actually much longer than the
+ * 7*(2**7 - 1) predicted by this formula.
+ *
+ * Modified 28 December 1994 by Jacob S. Rosenberg.
+ * The following changes have been made:
+ * All references to the type u_int have been changed to unsigned long.
+ * All references to type int have been changed to type long. Other
+ * cleanups have been made as well. A warning for both initstate and
+ * setstate has been inserted to the effect that on Sparc platforms
+ * the 'arg_state' variable must be forced to begin on word boundaries.
+ * This can be easily done by casting a long integer array to char *.
+ * The overall logic has been left STRICTLY alone. This software was
+ * tested on both a VAX and Sun SpacsStation with exactly the same
+ * results. The new version and the original give IDENTICAL results.
+ * The new version is somewhat faster than the original. As the
+ * documentation says: "By default, the package runs with 128 bytes of
+ * state information and generates far better random numbers than a linear
+ * congruential generator. If the amount of state information is less than
+ * 32 bytes, a simple linear congruential R.N.G. is used." For a buffer of
+ * 128 bytes, this new version runs about 19 percent faster and for a 16
+ * byte buffer it is about 5 percent faster.
+ */
+
+/*
+ * For each of the currently supported random number generators, we have a
+ * break value on the amount of state information (you need at least this
+ * many bytes of state info to support this random number generator), a degree
+ * for the polynomial (actually a trinomial) that the R.N.G. is based on, and
+ * the separation between the two lower order coefficients of the trinomial.
+ */
+#define TYPE_0 0 /* linear congruential */
+#define BREAK_0 8
+#define DEG_0 0
+#define SEP_0 0
+
+#define TYPE_1 1 /* x**7 + x**3 + 1 */
+#define BREAK_1 32
+#define DEG_1 7
+#define SEP_1 3
+
+#define TYPE_2 2 /* x**15 + x + 1 */
+#define BREAK_2 64
+#define DEG_2 15
+#define SEP_2 1
+
+#define TYPE_3 3 /* x**31 + x**3 + 1 */
+#define BREAK_3 128
+#define DEG_3 31
+#define SEP_3 3
+
+#define TYPE_4 4 /* x**63 + x + 1 */
+#define BREAK_4 256
+#define DEG_4 63
+#define SEP_4 1
+
+/*
+ * Array versions of the above information to make code run faster --
+ * relies on fact that TYPE_i == i.
+ */
+#define MAX_TYPES 5 /* max number of types above */
+
+#define NSHUFF 50 /* to drop some "seed -> 1st value" linearity */
+
+static const int degrees[MAX_TYPES] = { DEG_0, DEG_1, DEG_2, DEG_3, DEG_4 };
+static const int seps [MAX_TYPES] = { SEP_0, SEP_1, SEP_2, SEP_3, SEP_4 };
+
+/*
+ * Initially, everything is set up as if from:
+ *
+ * initstate(1, randtbl, 128);
+ *
+ * Note that this initialization takes advantage of the fact that srandom()
+ * advances the front and rear pointers 10*rand_deg times, and hence the
+ * rear pointer which starts at 0 will also end up at zero; thus the zeroeth
+ * element of the state information, which contains info about the current
+ * position of the rear pointer is just
+ *
+ * MAX_TYPES * (rptr - state) + TYPE_3 == TYPE_3.
+ */
+
+static uint32_t randtbl[DEG_3 + 1] = {
+ TYPE_3,
+ 0x2cf41758, 0x27bb3711, 0x4916d4d1, 0x7b02f59f, 0x9b8e28eb, 0xc0e80269,
+ 0x696f5c16, 0x878f1ff5, 0x52d9c07f, 0x916a06cd, 0xb50b3a20, 0x2776970a,
+ 0xee4eb2a6, 0xe94640ec, 0xb1d65612, 0x9d1ed968, 0x1043f6b7, 0xa3432a76,
+ 0x17eacbb9, 0x3c09e2eb, 0x4f8c2b3, 0x708a1f57, 0xee341814, 0x95d0e4d2,
+ 0xb06f216c, 0x8bd2e72e, 0x8f7c38d7, 0xcfc6a8fc, 0x2a59495, 0xa20d2a69,
+ 0xe29d12d1
+};
+
+/*
+ * fptr and rptr are two pointers into the state info, a front and a rear
+ * pointer. These two pointers are always rand_sep places aparts, as they
+ * cycle cyclically through the state information. (Yes, this does mean we
+ * could get away with just one pointer, but the code for random() is more
+ * efficient this way). The pointers are left positioned as they would be
+ * from the call
+ *
+ * initstate(1, randtbl, 128);
+ *
+ * (The position of the rear pointer, rptr, is really 0 (as explained above
+ * in the initialization of randtbl) because the state table pointer is set
+ * to point to randtbl[1] (as explained below).
+ */
+static uint32_t *fptr = &randtbl[SEP_3 + 1];
+static uint32_t *rptr = &randtbl[1];
+
+/*
+ * The following things are the pointer to the state information table, the
+ * type of the current generator, the degree of the current polynomial being
+ * used, and the separation between the two pointers. Note that for efficiency
+ * of random(), we remember the first location of the state information, not
+ * the zeroeth. Hence it is valid to access state[-1], which is used to
+ * store the type of the R.N.G. Also, we remember the last location, since
+ * this is more efficient than indexing every time to find the address of
+ * the last element to see if the front and rear pointers have wrapped.
+ */
+static uint32_t *state = &randtbl[1];
+static int rand_type = TYPE_3;
+static int rand_deg = DEG_3;
+static int rand_sep = SEP_3;
+static uint32_t *end_ptr = &randtbl[DEG_3 + 1];
+
+static inline uint32_t
+good_rand(uint32_t ctx)
+{
+/*
+ * Compute x = (7^5 * x) mod (2^31 - 1)
+ * wihout overflowing 31 bits:
+ * (2^31 - 1) = 127773 * (7^5) + 2836
+ * From "Random number generators: good ones are hard to find",
+ * Park and Miller, Communications of the ACM, vol. 31, no. 10,
+ * October 1988, p. 1195.
+ */
+ int32_t hi, lo, x;
+
+ /* Transform to [1, 0x7ffffffe] range. */
+ x = (ctx % 0x7ffffffe) + 1;
+ hi = x / 127773;
+ lo = x % 127773;
+ x = 16807 * lo - 2836 * hi;
+ if (x < 0)
+ x += 0x7fffffff;
+ /* Transform to [0, 0x7ffffffd] range. */
+ return (x - 1);
+}
+
+/*
+ * srandom:
+ *
+ * Initialize the random number generator based on the given seed. If the
+ * type is the trivial no-state-information type, just remember the seed.
+ * Otherwise, initializes state[] based on the given "seed" via a linear
+ * congruential generator. Then, the pointers are set to known locations
+ * that are exactly rand_sep places apart. Lastly, it cycles the state
+ * information a given number of times to get rid of any initial dependencies
+ * introduced by the L.C.R.N.G. Note that the initialization of randtbl[]
+ * for default usage relies on values produced by this routine.
+ */
+void
+srandom(unsigned int x)
+{
+ int i, lim;
+
+ state[0] = (uint32_t)x;
+ if (rand_type == TYPE_0)
+ lim = NSHUFF;
+ else {
+ for (i = 1; i < rand_deg; i++)
+ state[i] = good_rand(state[i - 1]);
+ fptr = &state[rand_sep];
+ rptr = &state[0];
+ lim = 10 * rand_deg;
+ }
+ for (i = 0; i < lim; i++)
+ (void)random();
+}
+
+/*
+ * srandomdev:
+ *
+ * Many programs choose the seed value in a totally predictable manner.
+ * This often causes problems. We seed the generator using pseudo-random
+ * data from the kernel.
+ *
+ * Note that this particular seeding procedure can generate states
+ * which are impossible to reproduce by calling srandom() with any
+ * value, since the succeeding terms in the state buffer are no longer
+ * derived from the LC algorithm applied to a fixed seed.
+ */
+void
+srandomdev(void)
+{
+ int mib[2];
+ size_t expected, len;
+
+ if (rand_type == TYPE_0)
+ expected = len = sizeof(state[0]);
+ else
+ expected = len = rand_deg * sizeof(state[0]);
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_ARND;
+ if (sysctl(mib, 2, state, &len, NULL, 0) == -1 || len != expected) {
+ /*
+ * The sysctl cannot fail. If it does fail on some FreeBSD
+ * derivative or after some future change, just abort so that
+ * the problem will be found and fixed. abort is not normally
+ * suitable for a library but makes sense here.
+ */
+ abort();
+ }
+
+ if (rand_type != TYPE_0) {
+ fptr = &state[rand_sep];
+ rptr = &state[0];
+ }
+}
+
+/*
+ * initstate:
+ *
+ * Initialize the state information in the given array of n bytes for future
+ * random number generation. Based on the number of bytes we are given, and
+ * the break values for the different R.N.G.'s, we choose the best (largest)
+ * one we can and set things up for it. srandom() is then called to
+ * initialize the state information.
+ *
+ * Note that on return from srandom(), we set state[-1] to be the type
+ * multiplexed with the current value of the rear pointer; this is so
+ * successive calls to initstate() won't lose this information and will be
+ * able to restart with setstate().
+ *
+ * Note: the first thing we do is save the current state, if any, just like
+ * setstate() so that it doesn't matter when initstate is called.
+ *
+ * Returns a pointer to the old state.
+ *
+ * Note: The Sparc platform requires that arg_state begin on an int
+ * word boundary; otherwise a bus error will occur. Even so, lint will
+ * complain about mis-alignment, but you should disregard these messages.
+ */
+char *
+initstate(unsigned int seed, char *arg_state, size_t n)
+{
+ char *ostate = (char *)(&state[-1]);
+ uint32_t *int_arg_state = (uint32_t *)arg_state;
+
+ if (n < BREAK_0)
+ return (NULL);
+ if (rand_type == TYPE_0)
+ state[-1] = rand_type;
+ else
+ state[-1] = MAX_TYPES * (rptr - state) + rand_type;
+ if (n < BREAK_1) {
+ rand_type = TYPE_0;
+ rand_deg = DEG_0;
+ rand_sep = SEP_0;
+ } else if (n < BREAK_2) {
+ rand_type = TYPE_1;
+ rand_deg = DEG_1;
+ rand_sep = SEP_1;
+ } else if (n < BREAK_3) {
+ rand_type = TYPE_2;
+ rand_deg = DEG_2;
+ rand_sep = SEP_2;
+ } else if (n < BREAK_4) {
+ rand_type = TYPE_3;
+ rand_deg = DEG_3;
+ rand_sep = SEP_3;
+ } else {
+ rand_type = TYPE_4;
+ rand_deg = DEG_4;
+ rand_sep = SEP_4;
+ }
+ state = int_arg_state + 1; /* first location */
+ end_ptr = &state[rand_deg]; /* must set end_ptr before srandom */
+ srandom(seed);
+ if (rand_type == TYPE_0)
+ int_arg_state[0] = rand_type;
+ else
+ int_arg_state[0] = MAX_TYPES * (rptr - state) + rand_type;
+ return (ostate);
+}
+
+/*
+ * setstate:
+ *
+ * Restore the state from the given state array.
+ *
+ * Note: it is important that we also remember the locations of the pointers
+ * in the current state information, and restore the locations of the pointers
+ * from the old state information. This is done by multiplexing the pointer
+ * location into the zeroeth word of the state information.
+ *
+ * Note that due to the order in which things are done, it is OK to call
+ * setstate() with the same state as the current state.
+ *
+ * Returns a pointer to the old state information.
+ *
+ * Note: The Sparc platform requires that arg_state begin on an int
+ * word boundary; otherwise a bus error will occur. Even so, lint will
+ * complain about mis-alignment, but you should disregard these messages.
+ */
+char *
+setstate(char *arg_state)
+{
+ uint32_t *new_state = (uint32_t *)arg_state;
+ uint32_t type = new_state[0] % MAX_TYPES;
+ uint32_t rear = new_state[0] / MAX_TYPES;
+ char *ostate = (char *)(&state[-1]);
+
+ if (type != TYPE_0 && rear >= degrees[type])
+ return (NULL);
+ if (rand_type == TYPE_0)
+ state[-1] = rand_type;
+ else
+ state[-1] = MAX_TYPES * (rptr - state) + rand_type;
+ rand_type = type;
+ rand_deg = degrees[type];
+ rand_sep = seps[type];
+ state = new_state + 1;
+ if (rand_type != TYPE_0) {
+ rptr = &state[rear];
+ fptr = &state[(rear + rand_sep) % rand_deg];
+ }
+ end_ptr = &state[rand_deg]; /* set end_ptr too */
+ return (ostate);
+}
+
+/*
+ * random:
+ *
+ * If we are using the trivial TYPE_0 R.N.G., just do the old linear
+ * congruential bit. Otherwise, we do our fancy trinomial stuff, which is
+ * the same in all the other cases due to all the global variables that have
+ * been set up. The basic operation is to add the number at the rear pointer
+ * into the one at the front pointer. Then both pointers are advanced to
+ * the next location cyclically in the table. The value returned is the sum
+ * generated, reduced to 31 bits by throwing away the "least random" low bit.
+ *
+ * Note: the code takes advantage of the fact that both the front and
+ * rear pointers can't wrap on the same call by not testing the rear
+ * pointer if the front one has wrapped.
+ *
+ * Returns a 31-bit random number.
+ */
+long
+random(void)
+{
+ uint32_t i;
+ uint32_t *f, *r;
+
+ if (rand_type == TYPE_0) {
+ i = state[0];
+ state[0] = i = good_rand(i);
+ } else {
+ /*
+ * Use local variables rather than static variables for speed.
+ */
+ f = fptr; r = rptr;
+ *f += *r;
+ i = *f >> 1; /* chucking least random bit */
+ if (++f >= end_ptr) {
+ f = state;
+ ++r;
+ }
+ else if (++r >= end_ptr) {
+ r = state;
+ }
+
+ fptr = f; rptr = r;
+ }
+ return ((long)i);
+}
diff --git a/lib/libc/stdlib/reallocarray.3 b/lib/libc/stdlib/reallocarray.3
new file mode 100644
index 000000000000..8e714f4daecc
--- /dev/null
+++ b/lib/libc/stdlib/reallocarray.3
@@ -0,0 +1,142 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd May 1, 2015
+.Dt REALLOCARRAY 3
+.Os
+.Sh NAME
+.Nm reallocarray
+.Nd memory reallocation function
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft void *
+.Fn reallocarray "void *ptr" "size_t nmemb" "size_t size"
+.Sh DESCRIPTION
+The
+.Fn reallocarray
+function is similar to the
+.Fn realloc
+function
+except it operates on
+.Fa nmemb
+members of size
+.Fa size
+and checks for integer overflow in the calculation
+.Fa nmemb
+*
+.Fa size .
+.Sh RETURN VALUES
+The
+.Fn reallocarray
+function returns a pointer to the allocated space; otherwise, a
+.Dv NULL
+pointer is returned and
+.Va errno
+is set to
+.Er ENOMEM .
+.Sh EXAMPLES
+Consider
+.Fn reallocarray
+when there is multiplication in the
+.Fa size
+argument of
+.Fn malloc
+or
+.Fn realloc .
+For example, avoid this common idiom as it may lead to integer overflow:
+.Bd -literal -offset indent
+if ((p = malloc(num * size)) == NULL)
+ err(1, "malloc");
+.Ed
+.Pp
+A drop-in replacement is the
+.Ox
+extension
+.Fn reallocarray :
+.Bd -literal -offset indent
+if ((p = reallocarray(NULL, num, size)) == NULL)
+ err(1, "reallocarray");
+.Ed
+.Pp
+When using
+.Fn realloc ,
+be careful to avoid the following idiom:
+.Bd -literal -offset indent
+size += 50;
+if ((p = realloc(p, size)) == NULL)
+ return (NULL);
+.Ed
+.Pp
+Do not adjust the variable describing how much memory has been allocated
+until the allocation has been successful.
+This can cause aberrant program behavior if the incorrect size value is used.
+In most cases, the above sample will also result in a leak of memory.
+As stated earlier, a return value of
+.Dv NULL
+indicates that the old object still remains allocated.
+Better code looks like this:
+.Bd -literal -offset indent
+newsize = size + 50;
+if ((newp = realloc(p, newsize)) == NULL) {
+ free(p);
+ p = NULL;
+ size = 0;
+ return (NULL);
+}
+p = newp;
+size = newsize;
+.Ed
+.Pp
+As with
+.Fn malloc ,
+it is important to ensure the new size value will not overflow;
+i.e. avoid allocations like the following:
+.Bd -literal -offset indent
+if ((newp = realloc(p, num * size)) == NULL) {
+ ...
+.Ed
+.Pp
+Instead, use
+.Fn reallocarray :
+.Bd -literal -offset indent
+if ((newp = reallocarray(p, num, size)) == NULL) {
+ ...
+.Ed
+.Sh SEE ALSO
+.Xr realloc 3
+.Sh HISTORY
+The
+.Fn reallocarray
+function first appeared in
+.Ox 5.6
+and
+.Fx 11.0 .
diff --git a/lib/libc/stdlib/reallocarray.c b/lib/libc/stdlib/reallocarray.c
new file mode 100644
index 000000000000..e1e9b7c16fff
--- /dev/null
+++ b/lib/libc/stdlib/reallocarray.c
@@ -0,0 +1,42 @@
+/* $OpenBSD: reallocarray.c,v 1.2 2014/12/08 03:45:00 bcook Exp $ */
+/*
+ * Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+/*
+ * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
+ * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
+ */
+#define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4))
+
+void *
+reallocarray(void *optr, size_t nmemb, size_t size)
+{
+
+ if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
+ nmemb > 0 && SIZE_MAX / nmemb < size) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ return (realloc(optr, size * nmemb));
+}
diff --git a/lib/libc/stdlib/reallocf.3 b/lib/libc/stdlib/reallocf.3
new file mode 100644
index 000000000000..cc9ef3d8f41e
--- /dev/null
+++ b/lib/libc/stdlib/reallocf.3
@@ -0,0 +1,82 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)malloc.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd January 31, 2010
+.Dt MALLOC 3
+.Os
+.Sh NAME
+.Nm reallocf
+.Nd memory reallocation function
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft void *
+.Fn reallocf "void *ptr" "size_t size"
+.Sh DESCRIPTION
+The
+.Fn reallocf
+function is identical to the
+.Fn realloc
+function, except that it
+will free the passed pointer when the requested memory cannot be allocated.
+This is a
+.Fx
+specific API designed to ease the problems with traditional coding styles
+for
+.Fn realloc
+causing memory leaks in libraries.
+.Sh RETURN VALUES
+The
+.Fn reallocf
+function returns a pointer, possibly identical to
+.Fa ptr ,
+to the allocated memory
+if successful; otherwise a
+.Dv NULL
+pointer is returned, and
+.Va errno
+is set to
+.Er ENOMEM
+if the error was the result of an allocation failure.
+The
+.Fn reallocf
+function deletes the original buffer when an error occurs.
+.Sh SEE ALSO
+.Xr realloc 3
+.Sh HISTORY
+The
+.Fn reallocf
+function first appeared in
+.Fx 3.0 .
diff --git a/lib/libc/stdlib/reallocf.c b/lib/libc/stdlib/reallocf.c
new file mode 100644
index 000000000000..a85b5a3c036b
--- /dev/null
+++ b/lib/libc/stdlib/reallocf.c
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 1998, M. Warner Losh <imp@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 <stdlib.h>
+
+void *
+reallocf(void *ptr, size_t size)
+{
+ void *nptr;
+
+ nptr = realloc(ptr, size);
+
+ /*
+ * When the System V compatibility option (malloc "V" flag) is
+ * in effect, realloc(ptr, 0) frees the memory and returns NULL.
+ * So, to avoid double free, call free() only when size != 0.
+ * realloc(ptr, 0) can't fail when ptr != NULL.
+ */
+ if (!nptr && ptr && size != 0)
+ free(ptr);
+ return (nptr);
+}
diff --git a/lib/libc/stdlib/realpath.3 b/lib/libc/stdlib/realpath.3
new file mode 100644
index 000000000000..c0a5770ac83f
--- /dev/null
+++ b/lib/libc/stdlib/realpath.3
@@ -0,0 +1,135 @@
+.\" Copyright (c) 1994
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Jan-Simon Pendry.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)realpath.3 8.2 (Berkeley) 2/16/94
+.\" $FreeBSD$
+.\"
+.Dd May 11, 2012
+.Dt REALPATH 3
+.Os
+.Sh NAME
+.Nm realpath
+.Nd returns the canonicalized absolute pathname
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft "char *"
+.Fn realpath "const char * restrict pathname" "char * restrict resolved_path"
+.Sh DESCRIPTION
+The
+.Fn realpath
+function resolves all symbolic links, extra
+.Dq /
+characters and references to
+.Pa /./
+and
+.Pa /../
+in
+.Fa pathname ,
+and copies the resulting absolute pathname into
+the memory pointed to by
+.Fa resolved_path .
+The
+.Fa resolved_path
+argument
+.Em must
+point to a buffer capable of storing at least
+.Dv PATH_MAX
+characters, or be
+.Dv NULL .
+.Pp
+The
+.Fn realpath
+function will resolve both absolute and relative paths
+and return the absolute pathname corresponding to
+.Fa pathname .
+All components of
+.Fa pathname
+must exist when
+.Fn realpath
+is called, and all but the last component must name either directories or
+symlinks pointing to the directories.
+.Sh "RETURN VALUES"
+The
+.Fn realpath
+function returns
+.Fa resolved_path
+on success.
+If the function was supplied
+.Dv NULL
+as
+.Fa resolved_path ,
+and operation did not cause errors, the returned value is
+a null-terminated string in a buffer allocated by a call to
+.Fn malloc 3 .
+If an error occurs,
+.Fn realpath
+returns
+.Dv NULL ,
+and if
+.Fa resolved_path
+is not
+.Dv NULL ,
+the array that it points to contains the pathname which caused the problem.
+.Sh ERRORS
+The function
+.Fn realpath
+may fail and set the external variable
+.Va errno
+for any of the errors specified for the library functions
+.Xr lstat 2 ,
+.Xr readlink 2
+and
+.Xr getcwd 3 .
+.Sh SEE ALSO
+.Xr getcwd 3
+.\" .Sh STANDARDS
+.\" The
+.\" .Fn realpath
+.\" function conforms to
+.\" .St -p1003.1-2001 .
+.Sh HISTORY
+The
+.Fn realpath
+function first appeared in
+.Bx 4.4 .
+.Sh CAVEATS
+This implementation of
+.Fn realpath
+differs slightly from the Solaris implementation.
+The
+.Bx 4.4
+version always returns absolute pathnames,
+whereas the Solaris implementation will,
+under certain circumstances, return a relative
+.Fa resolved_path
+when given a relative
+.Fa pathname .
diff --git a/lib/libc/stdlib/realpath.c b/lib/libc/stdlib/realpath.c
new file mode 100644
index 000000000000..c4bd953e928b
--- /dev/null
+++ b/lib/libc/stdlib/realpath.c
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 2003 Constantin S. Svintsoff <kostik@iclub.nsu.ru>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The names of the authors may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)realpath.c 8.1 (Berkeley) 2/16/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+/*
+ * Find the real name of path, by removing all ".", ".." and symlink
+ * components. Returns (resolved) on success, or (NULL) on failure,
+ * in which case the path which caused trouble is left in (resolved).
+ */
+char *
+realpath(const char * __restrict path, char * __restrict resolved)
+{
+ struct stat sb;
+ char *p, *q, *s;
+ size_t left_len, resolved_len;
+ unsigned symlinks;
+ int m, slen;
+ char left[PATH_MAX], next_token[PATH_MAX], symlink[PATH_MAX];
+
+ if (path == NULL) {
+ errno = EINVAL;
+ return (NULL);
+ }
+ if (path[0] == '\0') {
+ errno = ENOENT;
+ return (NULL);
+ }
+ if (resolved == NULL) {
+ resolved = malloc(PATH_MAX);
+ if (resolved == NULL)
+ return (NULL);
+ m = 1;
+ } else
+ m = 0;
+ symlinks = 0;
+ if (path[0] == '/') {
+ resolved[0] = '/';
+ resolved[1] = '\0';
+ if (path[1] == '\0')
+ return (resolved);
+ resolved_len = 1;
+ left_len = strlcpy(left, path + 1, sizeof(left));
+ } else {
+ if (getcwd(resolved, PATH_MAX) == NULL) {
+ if (m)
+ free(resolved);
+ else {
+ resolved[0] = '.';
+ resolved[1] = '\0';
+ }
+ return (NULL);
+ }
+ resolved_len = strlen(resolved);
+ left_len = strlcpy(left, path, sizeof(left));
+ }
+ if (left_len >= sizeof(left) || resolved_len >= PATH_MAX) {
+ if (m)
+ free(resolved);
+ errno = ENAMETOOLONG;
+ return (NULL);
+ }
+
+ /*
+ * Iterate over path components in `left'.
+ */
+ while (left_len != 0) {
+ /*
+ * Extract the next path component and adjust `left'
+ * and its length.
+ */
+ p = strchr(left, '/');
+ s = p ? p : left + left_len;
+ if (s - left >= sizeof(next_token)) {
+ if (m)
+ free(resolved);
+ errno = ENAMETOOLONG;
+ return (NULL);
+ }
+ memcpy(next_token, left, s - left);
+ next_token[s - left] = '\0';
+ left_len -= s - left;
+ if (p != NULL)
+ memmove(left, s + 1, left_len + 1);
+ if (resolved[resolved_len - 1] != '/') {
+ if (resolved_len + 1 >= PATH_MAX) {
+ if (m)
+ free(resolved);
+ errno = ENAMETOOLONG;
+ return (NULL);
+ }
+ resolved[resolved_len++] = '/';
+ resolved[resolved_len] = '\0';
+ }
+ if (next_token[0] == '\0') {
+ /* Handle consequential slashes. */
+ continue;
+ }
+ else if (strcmp(next_token, ".") == 0)
+ continue;
+ else if (strcmp(next_token, "..") == 0) {
+ /*
+ * Strip the last path component except when we have
+ * single "/"
+ */
+ if (resolved_len > 1) {
+ resolved[resolved_len - 1] = '\0';
+ q = strrchr(resolved, '/') + 1;
+ *q = '\0';
+ resolved_len = q - resolved;
+ }
+ continue;
+ }
+
+ /*
+ * Append the next path component and lstat() it.
+ */
+ resolved_len = strlcat(resolved, next_token, PATH_MAX);
+ if (resolved_len >= PATH_MAX) {
+ if (m)
+ free(resolved);
+ errno = ENAMETOOLONG;
+ return (NULL);
+ }
+ if (lstat(resolved, &sb) != 0) {
+ if (m)
+ free(resolved);
+ return (NULL);
+ }
+ if (S_ISLNK(sb.st_mode)) {
+ if (symlinks++ > MAXSYMLINKS) {
+ if (m)
+ free(resolved);
+ errno = ELOOP;
+ return (NULL);
+ }
+ slen = readlink(resolved, symlink, sizeof(symlink) - 1);
+ if (slen < 0) {
+ if (m)
+ free(resolved);
+ return (NULL);
+ }
+ symlink[slen] = '\0';
+ if (symlink[0] == '/') {
+ resolved[1] = 0;
+ resolved_len = 1;
+ } else if (resolved_len > 1) {
+ /* Strip the last path component. */
+ resolved[resolved_len - 1] = '\0';
+ q = strrchr(resolved, '/') + 1;
+ *q = '\0';
+ resolved_len = q - resolved;
+ }
+
+ /*
+ * If there are any path components left, then
+ * append them to symlink. The result is placed
+ * in `left'.
+ */
+ if (p != NULL) {
+ if (symlink[slen - 1] != '/') {
+ if (slen + 1 >= sizeof(symlink)) {
+ if (m)
+ free(resolved);
+ errno = ENAMETOOLONG;
+ return (NULL);
+ }
+ symlink[slen] = '/';
+ symlink[slen + 1] = 0;
+ }
+ left_len = strlcat(symlink, left,
+ sizeof(symlink));
+ if (left_len >= sizeof(left)) {
+ if (m)
+ free(resolved);
+ errno = ENAMETOOLONG;
+ return (NULL);
+ }
+ }
+ left_len = strlcpy(left, symlink, sizeof(left));
+ } else if (!S_ISDIR(sb.st_mode) && p != NULL) {
+ if (m)
+ free(resolved);
+ errno = ENOTDIR;
+ return (NULL);
+ }
+ }
+
+ /*
+ * Remove trailing slash except when the resolved pathname
+ * is a single "/".
+ */
+ if (resolved_len > 1 && resolved[resolved_len - 1] == '/')
+ resolved[resolved_len - 1] = '\0';
+ return (resolved);
+}
diff --git a/lib/libc/stdlib/remque.c b/lib/libc/stdlib/remque.c
new file mode 100644
index 000000000000..0a2f28f77c7c
--- /dev/null
+++ b/lib/libc/stdlib/remque.c
@@ -0,0 +1,30 @@
+/*
+ * Initial implementation:
+ * Copyright (c) 2002 Robert Drehmel
+ * All rights reserved.
+ *
+ * As long as the above copyright statement and this notice remain
+ * unchanged, you can do what ever you want with this file.
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#define _SEARCH_PRIVATE
+#include <search.h>
+#include <stdlib.h> /* for NULL */
+
+void
+remque(void *element)
+{
+ struct que_elem *prev, *next, *elem;
+
+ elem = (struct que_elem *)element;
+
+ prev = elem->prev;
+ next = elem->next;
+
+ if (prev != NULL)
+ prev->next = next;
+ if (next != NULL)
+ next->prev = prev;
+}
diff --git a/lib/libc/stdlib/strfmon.3 b/lib/libc/stdlib/strfmon.3
new file mode 100644
index 000000000000..47f7131b677c
--- /dev/null
+++ b/lib/libc/stdlib/strfmon.3
@@ -0,0 +1,184 @@
+.\" Copyright (c) 2001 Jeroen Ruigrok van der Werven <asmodai@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 REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd June 25, 2012
+.Dt STRFMON 3
+.Os
+.Sh NAME
+.Nm strfmon
+.Nd convert monetary value to string
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In monetary.h
+.Ft ssize_t
+.Fn strfmon "char * restrict s" "size_t maxsize" "const char * restrict format" "..."
+.Ft ssize_t
+.Fn strfmon_l "char * restrict s" "size_t maxsize" "locale_t loc" "const char * restrict format" "..."
+.Sh DESCRIPTION
+The
+.Fn strfmon
+function places characters into the array pointed to by
+.Fa s
+as controlled by the string pointed to by
+.Fa format .
+No more than
+.Fa maxsize
+bytes are placed into the array.
+.Pp
+The
+.Fn strfmon_l
+function does the same as
+.Fn strfmon
+but takes an explicit locale rather than using the current locale.
+.Pp
+The format string is composed of zero or more directives:
+ordinary characters (not
+.Cm % ) ,
+which are copied unchanged to the output stream; and conversion
+specifications, each of which results in fetching zero or more subsequent
+arguments.
+Each conversion specification is introduced by the
+.Cm %
+character.
+After the
+.Cm % ,
+the following appear in sequence:
+.Bl -bullet
+.It
+Zero or more of the following flags:
+.Bl -tag -width "XXX"
+.It Cm = Ns Ar f
+A
+.Sq Cm =
+character followed by another character
+.Ar f
+which is used as the numeric fill character.
+.It Cm ^
+Do not use grouping characters, regardless of the current locale default.
+.It Cm +
+Represent positive values by prefixing them with a positive sign,
+and negative values by prefixing them with a negative sign.
+This is the default.
+.It Cm \&(
+Enclose negative values in parentheses.
+.It Cm \&!
+Do not include a currency symbol in the output.
+.It Cm \-
+Left justify the result.
+Only valid when a field width is specified.
+.El
+.It
+An optional minimum field width as a decimal number.
+By default, there is no minimum width.
+.It
+A
+.Sq Cm #
+sign followed by a decimal number specifying the maximum
+expected number of digits after the radix character.
+.It
+A
+.Sq Cm \&.
+character followed by a decimal number specifying the number
+the number of digits after the radix character.
+.It
+One of the following conversion specifiers:
+.Bl -tag -width "XXX"
+.It Cm i
+The
+.Vt double
+argument is formatted as an international monetary amount.
+.It Cm n
+The
+.Vt double
+argument is formatted as a national monetary amount.
+.It Cm %
+A
+.Sq Li %
+character is written.
+.El
+.El
+.Sh RETURN VALUES
+If the total number of resulting bytes including the terminating
+.Dv NUL
+byte is not more than
+.Fa maxsize ,
+.Fn strfmon
+returns the number of bytes placed into the array pointed to by
+.Fa s ,
+not including the terminating
+.Dv NUL
+byte.
+Otherwise, \-1 is returned,
+the contents of the array are indeterminate,
+and
+.Va errno
+is set to indicate the error.
+.Pp
+The
+.Fn strfmon_l
+function returns the same values as
+.Fn strfmon .
+.Sh ERRORS
+The
+.Fn strfmon
+function will fail if:
+.Bl -tag -width Er
+.It Bq Er E2BIG
+Conversion stopped due to lack of space in the buffer.
+.It Bq Er EINVAL
+The format string is invalid.
+.It Bq Er ENOMEM
+Not enough memory for temporary buffers.
+.El
+.Sh SEE ALSO
+.Xr localeconv 3
+.Sh STANDARDS
+The
+.Fn strfmon
+function
+conforms to
+.St -p1003.1-2001 .
+The
+.Fn strfmon_l
+function conforms to
+.St -p1003.1-2008 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Fn strfmon
+function was implemented by
+.An Alexey Zelkin Aq Mt phantom@FreeBSD.org .
+.Pp
+This manual page was written by
+.An Jeroen Ruigrok van der Werven Aq Mt asmodai@FreeBSD.org
+based on the standards' text.
+.Sh BUGS
+The
+.Fn strfmon
+function does not correctly handle multibyte characters in the
+.Fa format
+argument.
diff --git a/lib/libc/stdlib/strfmon.c b/lib/libc/stdlib/strfmon.c
new file mode 100644
index 000000000000..af038fe17caf
--- /dev/null
+++ b/lib/libc/stdlib/strfmon.c
@@ -0,0 +1,641 @@
+/*-
+ * Copyright (c) 2001 Alexey Zelkin <phantom@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 <limits.h>
+#include <locale.h>
+#include <monetary.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "xlocale_private.h"
+
+/* internal flags */
+#define NEED_GROUPING 0x01 /* print digits grouped (default) */
+#define SIGN_POSN_USED 0x02 /* '+' or '(' usage flag */
+#define LOCALE_POSN 0x04 /* use locale defined +/- (default) */
+#define PARENTH_POSN 0x08 /* enclose negative amount in () */
+#define SUPRESS_CURR_SYMBOL 0x10 /* suppress the currency from output */
+#define LEFT_JUSTIFY 0x20 /* left justify */
+#define USE_INTL_CURRENCY 0x40 /* use international currency symbol */
+#define IS_NEGATIVE 0x80 /* is argument value negative ? */
+
+/* internal macros */
+#define PRINT(CH) do { \
+ if (dst >= s + maxsize) \
+ goto e2big_error; \
+ *dst++ = CH; \
+} while (0)
+
+#define PRINTS(STR) do { \
+ char *tmps = STR; \
+ while (*tmps != '\0') \
+ PRINT(*tmps++); \
+} while (0)
+
+#define GET_NUMBER(VAR) do { \
+ VAR = 0; \
+ while (isdigit((unsigned char)*fmt)) { \
+ if (VAR > INT_MAX / 10) \
+ goto e2big_error; \
+ VAR *= 10; \
+ VAR += *fmt - '0'; \
+ if (VAR < 0) \
+ goto e2big_error; \
+ fmt++; \
+ } \
+} while (0)
+
+#define GRPCPY(howmany) do { \
+ int i = howmany; \
+ while (i-- > 0) { \
+ avalue_size--; \
+ *--bufend = *(avalue+avalue_size+padded); \
+ } \
+} while (0)
+
+#define GRPSEP do { \
+ *--bufend = thousands_sep; \
+ groups++; \
+} while (0)
+
+static void __setup_vars(int, char *, char *, char *, char **);
+static int __calc_left_pad(int, char *);
+static char *__format_grouped_double(double, int *, int, int, int);
+
+static ssize_t
+vstrfmon_l(char * __restrict s, size_t maxsize, locale_t loc,
+ const char * __restrict format, va_list ap)
+{
+ char *dst; /* output destination pointer */
+ const char *fmt; /* current format poistion pointer */
+ struct lconv *lc; /* pointer to lconv structure */
+ char *asciivalue; /* formatted double pointer */
+
+ int flags; /* formatting options */
+ int pad_char; /* padding character */
+ int pad_size; /* pad size */
+ int width; /* field width */
+ int left_prec; /* left precision */
+ int right_prec; /* right precision */
+ double value; /* just value */
+ char space_char = ' '; /* space after currency */
+
+ char cs_precedes, /* values gathered from struct lconv */
+ sep_by_space,
+ sign_posn,
+ *signstr,
+ *currency_symbol;
+
+ char *tmpptr; /* temporary vars */
+ int sverrno;
+ FIX_LOCALE(loc);
+
+
+ lc = localeconv_l(loc);
+ dst = s;
+ fmt = format;
+ asciivalue = NULL;
+ currency_symbol = NULL;
+ pad_size = 0;
+
+ while (*fmt) {
+ /* pass nonformating characters AS IS */
+ if (*fmt != '%')
+ goto literal;
+
+ /* '%' found ! */
+
+ /* "%%" mean just '%' */
+ if (*(fmt+1) == '%') {
+ fmt++;
+ literal:
+ PRINT(*fmt++);
+ continue;
+ }
+
+ /* set up initial values */
+ flags = (NEED_GROUPING|LOCALE_POSN);
+ pad_char = ' '; /* padding character is "space" */
+ left_prec = -1; /* no left precision specified */
+ right_prec = -1; /* no right precision specified */
+ width = -1; /* no width specified */
+ value = 0; /* we have no value to print now */
+
+ /* Flags */
+ while (1) {
+ switch (*++fmt) {
+ case '=': /* fill character */
+ pad_char = *++fmt;
+ if (pad_char == '\0')
+ goto format_error;
+ continue;
+ case '^': /* not group currency */
+ flags &= ~(NEED_GROUPING);
+ continue;
+ case '+': /* use locale defined signs */
+ if (flags & SIGN_POSN_USED)
+ goto format_error;
+ flags |= (SIGN_POSN_USED|LOCALE_POSN);
+ continue;
+ case '(': /* enclose negatives with () */
+ if (flags & SIGN_POSN_USED)
+ goto format_error;
+ flags |= (SIGN_POSN_USED|PARENTH_POSN);
+ continue;
+ case '!': /* suppress currency symbol */
+ flags |= SUPRESS_CURR_SYMBOL;
+ continue;
+ case '-': /* alignment (left) */
+ flags |= LEFT_JUSTIFY;
+ continue;
+ default:
+ break;
+ }
+ break;
+ }
+
+ /* field Width */
+ if (isdigit((unsigned char)*fmt)) {
+ GET_NUMBER(width);
+ /* Do we have enough space to put number with
+ * required width ?
+ */
+ if ((unsigned int)width >= maxsize - (dst - s))
+ goto e2big_error;
+ }
+
+ /* Left precision */
+ if (*fmt == '#') {
+ if (!isdigit((unsigned char)*++fmt))
+ goto format_error;
+ GET_NUMBER(left_prec);
+ if ((unsigned int)left_prec >= maxsize - (dst - s))
+ goto e2big_error;
+ }
+
+ /* Right precision */
+ if (*fmt == '.') {
+ if (!isdigit((unsigned char)*++fmt))
+ goto format_error;
+ GET_NUMBER(right_prec);
+ if ((unsigned int)right_prec >= maxsize - (dst - s) -
+ left_prec)
+ goto e2big_error;
+ }
+
+ /* Conversion Characters */
+ switch (*fmt++) {
+ case 'i': /* use internaltion currency format */
+ flags |= USE_INTL_CURRENCY;
+ break;
+ case 'n': /* use national currency format */
+ flags &= ~(USE_INTL_CURRENCY);
+ break;
+ default: /* required character is missing or
+ premature EOS */
+ goto format_error;
+ }
+
+ if (currency_symbol != NULL)
+ free(currency_symbol);
+ if (flags & USE_INTL_CURRENCY) {
+ currency_symbol = strdup(lc->int_curr_symbol);
+ if (currency_symbol != NULL)
+ space_char = *(currency_symbol+3);
+ } else
+ currency_symbol = strdup(lc->currency_symbol);
+
+ if (currency_symbol == NULL)
+ goto end_error; /* ENOMEM. */
+
+ /* value itself */
+ value = va_arg(ap, double);
+
+ /* detect sign */
+ if (value < 0) {
+ flags |= IS_NEGATIVE;
+ value = -value;
+ }
+
+ /* fill left_prec with amount of padding chars */
+ if (left_prec >= 0) {
+ pad_size = __calc_left_pad((flags ^ IS_NEGATIVE),
+ currency_symbol) -
+ __calc_left_pad(flags, currency_symbol);
+ if (pad_size < 0)
+ pad_size = 0;
+ }
+
+ if (asciivalue != NULL)
+ free(asciivalue);
+ asciivalue = __format_grouped_double(value, &flags,
+ left_prec, right_prec, pad_char);
+ if (asciivalue == NULL)
+ goto end_error; /* errno already set */
+ /* to ENOMEM by malloc() */
+
+ /* set some variables for later use */
+ __setup_vars(flags, &cs_precedes, &sep_by_space,
+ &sign_posn, &signstr);
+
+ /*
+ * Description of some LC_MONETARY's values:
+ *
+ * p_cs_precedes & n_cs_precedes
+ *
+ * = 1 - $currency_symbol precedes the value
+ * for a monetary quantity with a non-negative value
+ * = 0 - symbol succeeds the value
+ *
+ * p_sep_by_space & n_sep_by_space
+ *
+ * = 0 - no space separates $currency_symbol
+ * from the value for a monetary quantity with a
+ * non-negative value
+ * = 1 - space separates the symbol from the value
+ * = 2 - space separates the symbol and the sign string,
+ * if adjacent.
+ *
+ * p_sign_posn & n_sign_posn
+ *
+ * = 0 - parentheses enclose the quantity and the
+ * $currency_symbol
+ * = 1 - the sign string precedes the quantity and the
+ * $currency_symbol
+ * = 2 - the sign string succeeds the quantity and the
+ * $currency_symbol
+ * = 3 - the sign string precedes the $currency_symbol
+ * = 4 - the sign string succeeds the $currency_symbol
+ *
+ */
+
+ tmpptr = dst;
+
+ while (pad_size-- > 0)
+ PRINT(' ');
+
+ if (sign_posn == 0 && (flags & IS_NEGATIVE))
+ PRINT('(');
+
+ if (cs_precedes == 1) {
+ if (sign_posn == 1 || sign_posn == 3) {
+ PRINTS(signstr);
+ if (sep_by_space == 2) /* XXX: ? */
+ PRINT(' ');
+ }
+
+ if (!(flags & SUPRESS_CURR_SYMBOL)) {
+ PRINTS(currency_symbol);
+
+ if (sign_posn == 4) {
+ if (sep_by_space == 2)
+ PRINT(space_char);
+ PRINTS(signstr);
+ if (sep_by_space == 1)
+ PRINT(' ');
+ } else if (sep_by_space == 1)
+ PRINT(space_char);
+ }
+ } else if (sign_posn == 1)
+ PRINTS(signstr);
+
+ PRINTS(asciivalue);
+
+ if (cs_precedes == 0) {
+ if (sign_posn == 3) {
+ if (sep_by_space == 1)
+ PRINT(' ');
+ PRINTS(signstr);
+ }
+
+ if (!(flags & SUPRESS_CURR_SYMBOL)) {
+ if ((sign_posn == 3 && sep_by_space == 2)
+ || (sep_by_space == 1
+ && (sign_posn == 0
+ || sign_posn == 1
+ || sign_posn == 2
+ || sign_posn == 4)))
+ PRINT(space_char);
+ PRINTS(currency_symbol); /* XXX: len */
+ if (sign_posn == 4) {
+ if (sep_by_space == 2)
+ PRINT(' ');
+ PRINTS(signstr);
+ }
+ }
+ }
+
+ if (sign_posn == 2) {
+ if (sep_by_space == 2)
+ PRINT(' ');
+ PRINTS(signstr);
+ }
+
+ if (sign_posn == 0 && (flags & IS_NEGATIVE))
+ PRINT(')');
+
+ if (dst - tmpptr < width) {
+ if (flags & LEFT_JUSTIFY) {
+ while (dst - tmpptr < width)
+ PRINT(' ');
+ } else {
+ pad_size = dst-tmpptr;
+ memmove(tmpptr + width-pad_size, tmpptr,
+ pad_size);
+ memset(tmpptr, ' ', width-pad_size);
+ dst += width-pad_size;
+ }
+ }
+ }
+
+ PRINT('\0');
+ free(asciivalue);
+ free(currency_symbol);
+ return (dst - s - 1); /* return size of put data except trailing '\0' */
+
+e2big_error:
+ errno = E2BIG;
+ goto end_error;
+
+format_error:
+ errno = EINVAL;
+
+end_error:
+ sverrno = errno;
+ if (asciivalue != NULL)
+ free(asciivalue);
+ if (currency_symbol != NULL)
+ free(currency_symbol);
+ errno = sverrno;
+ return (-1);
+}
+ssize_t
+strfmon_l(char * __restrict s, size_t maxsize, locale_t loc, const char * __restrict format,
+ ...)
+{
+ size_t ret;
+ va_list ap;
+ va_start(ap, format);
+ ret = vstrfmon_l(s, maxsize, loc, format, ap);
+ va_end(ap);
+ return ret;
+}
+
+ssize_t
+strfmon(char * __restrict s, size_t maxsize, const char * __restrict format,
+ ...)
+{
+ size_t ret;
+ va_list ap;
+ va_start(ap, format);
+ ret = vstrfmon_l(s, maxsize, __get_locale(), format, ap);
+ va_end(ap);
+ return ret;
+}
+
+
+static void
+__setup_vars(int flags, char *cs_precedes, char *sep_by_space,
+ char *sign_posn, char **signstr) {
+
+ struct lconv *lc = localeconv();
+
+ if ((flags & IS_NEGATIVE) && (flags & USE_INTL_CURRENCY)) {
+ *cs_precedes = lc->int_n_cs_precedes;
+ *sep_by_space = lc->int_n_sep_by_space;
+ *sign_posn = (flags & PARENTH_POSN) ? 0 : lc->int_n_sign_posn;
+ *signstr = (lc->negative_sign[0] == '\0') ? "-"
+ : lc->negative_sign;
+ } else if (flags & USE_INTL_CURRENCY) {
+ *cs_precedes = lc->int_p_cs_precedes;
+ *sep_by_space = lc->int_p_sep_by_space;
+ *sign_posn = (flags & PARENTH_POSN) ? 0 : lc->int_p_sign_posn;
+ *signstr = lc->positive_sign;
+ } else if (flags & IS_NEGATIVE) {
+ *cs_precedes = lc->n_cs_precedes;
+ *sep_by_space = lc->n_sep_by_space;
+ *sign_posn = (flags & PARENTH_POSN) ? 0 : lc->n_sign_posn;
+ *signstr = (lc->negative_sign[0] == '\0') ? "-"
+ : lc->negative_sign;
+ } else {
+ *cs_precedes = lc->p_cs_precedes;
+ *sep_by_space = lc->p_sep_by_space;
+ *sign_posn = (flags & PARENTH_POSN) ? 0 : lc->p_sign_posn;
+ *signstr = lc->positive_sign;
+ }
+
+ /* Set defult values for unspecified information. */
+ if (*cs_precedes != 0)
+ *cs_precedes = 1;
+ if (*sep_by_space == CHAR_MAX)
+ *sep_by_space = 0;
+ if (*sign_posn == CHAR_MAX)
+ *sign_posn = 0;
+}
+
+static int
+__calc_left_pad(int flags, char *cur_symb) {
+
+ char cs_precedes, sep_by_space, sign_posn, *signstr;
+ int left_chars = 0;
+
+ __setup_vars(flags, &cs_precedes, &sep_by_space, &sign_posn, &signstr);
+
+ if (cs_precedes != 0) {
+ left_chars += strlen(cur_symb);
+ if (sep_by_space != 0)
+ left_chars++;
+ }
+
+ switch (sign_posn) {
+ case 1:
+ left_chars += strlen(signstr);
+ break;
+ case 3:
+ case 4:
+ if (cs_precedes != 0)
+ left_chars += strlen(signstr);
+ }
+ return (left_chars);
+}
+
+static int
+get_groups(int size, char *grouping) {
+
+ int chars = 0;
+
+ if (*grouping == CHAR_MAX || *grouping <= 0) /* no grouping ? */
+ return (0);
+
+ while (size > (int)*grouping) {
+ chars++;
+ size -= (int)*grouping++;
+ /* no more grouping ? */
+ if (*grouping == CHAR_MAX)
+ break;
+ /* rest grouping with same value ? */
+ if (*grouping == 0) {
+ chars += (size - 1) / *(grouping - 1);
+ break;
+ }
+ }
+ return (chars);
+}
+
+/* convert double to ASCII */
+static char *
+__format_grouped_double(double value, int *flags,
+ int left_prec, int right_prec, int pad_char) {
+
+ char *rslt;
+ char *avalue;
+ int avalue_size;
+
+ size_t bufsize;
+ char *bufend;
+
+ int padded;
+
+ struct lconv *lc = localeconv();
+ char *grouping;
+ char decimal_point;
+ char thousands_sep;
+
+ int groups = 0;
+
+ grouping = lc->mon_grouping;
+ decimal_point = *lc->mon_decimal_point;
+ if (decimal_point == '\0')
+ decimal_point = *lc->decimal_point;
+ thousands_sep = *lc->mon_thousands_sep;
+ if (thousands_sep == '\0')
+ thousands_sep = *lc->thousands_sep;
+
+ /* fill left_prec with default value */
+ if (left_prec == -1)
+ left_prec = 0;
+
+ /* fill right_prec with default value */
+ if (right_prec == -1) {
+ if (*flags & USE_INTL_CURRENCY)
+ right_prec = lc->int_frac_digits;
+ else
+ right_prec = lc->frac_digits;
+
+ if (right_prec == CHAR_MAX) /* POSIX locale ? */
+ right_prec = 2;
+ }
+
+ if (*flags & NEED_GROUPING)
+ left_prec += get_groups(left_prec, grouping);
+
+ /* convert to string */
+ avalue_size = asprintf(&avalue, "%*.*f", left_prec + right_prec + 1,
+ right_prec, value);
+ if (avalue_size < 0)
+ return (NULL);
+
+ /* make sure that we've enough space for result string */
+ bufsize = avalue_size * 2 + 1;
+ rslt = calloc(1, bufsize);
+ if (rslt == NULL) {
+ free(avalue);
+ return (NULL);
+ }
+ bufend = rslt + bufsize - 1; /* reserve space for trailing '\0' */
+
+ /* skip spaces at beginning */
+ padded = 0;
+ while (avalue[padded] == ' ') {
+ padded++;
+ avalue_size--;
+ }
+
+ if (right_prec > 0) {
+ bufend -= right_prec;
+ memcpy(bufend, avalue + avalue_size+padded-right_prec,
+ right_prec);
+ *--bufend = decimal_point;
+ avalue_size -= (right_prec + 1);
+ }
+
+ if ((*flags & NEED_GROUPING) &&
+ thousands_sep != '\0' && /* XXX: need investigation */
+ *grouping != CHAR_MAX &&
+ *grouping > 0) {
+ while (avalue_size > (int)*grouping) {
+ GRPCPY(*grouping);
+ GRPSEP;
+ grouping++;
+
+ /* no more grouping ? */
+ if (*grouping == CHAR_MAX)
+ break;
+
+ /* rest grouping with same value ? */
+ if (*grouping == 0) {
+ grouping--;
+ while (avalue_size > *grouping) {
+ GRPCPY(*grouping);
+ GRPSEP;
+ }
+ }
+ }
+ if (avalue_size != 0)
+ GRPCPY(avalue_size);
+ padded -= groups;
+
+ } else {
+ bufend -= avalue_size;
+ memcpy(bufend, avalue+padded, avalue_size);
+ if (right_prec == 0)
+ padded--; /* decrease assumed $decimal_point */
+ }
+
+ /* do padding with pad_char */
+ if (padded > 0) {
+ bufend -= padded;
+ memset(bufend, pad_char, padded);
+ }
+
+ bufsize = bufsize - (bufend - rslt) + 1;
+ memmove(rslt, bufend, bufsize);
+ free(avalue);
+ return (rslt);
+}
diff --git a/lib/libc/stdlib/strtod.3 b/lib/libc/stdlib/strtod.3
new file mode 100644
index 000000000000..549c640f8358
--- /dev/null
+++ b/lib/libc/stdlib/strtod.3
@@ -0,0 +1,198 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)strtod.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd May 11, 2010
+.Dt STRTOD 3
+.Os
+.Sh NAME
+.Nm strtod , strtof , strtold
+.Nd convert
+.Tn ASCII
+string to floating point
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft double
+.Fn strtod "const char * restrict nptr" "char ** restrict endptr"
+.Ft float
+.Fn strtof "const char * restrict nptr" "char ** restrict endptr"
+.Ft "long double"
+.Fn strtold "const char * restrict nptr" "char ** restrict endptr"
+.Sh DESCRIPTION
+These conversion
+functions convert the initial portion of the string
+pointed to by
+.Fa nptr
+to
+.Vt double ,
+.Vt float ,
+and
+.Vt "long double"
+representation, respectively.
+.Pp
+The expected form of the string is an optional plus (``+'') or minus
+sign (``\-'') followed by either:
+.Bl -bullet
+.It
+a decimal significand consisting of a sequence of decimal digits
+optionally containing a decimal-point character, or
+.It
+a hexadecimal significand consisting of a ``0X'' or ``0x'' followed
+by a sequence of hexadecimal digits optionally containing a
+decimal-point character.
+.El
+.Pp
+In both cases, the significand may be optionally followed by an
+exponent.
+An exponent consists of an ``E'' or ``e'' (for decimal
+constants) or a ``P'' or ``p'' (for hexadecimal constants),
+followed by an optional plus or minus sign, followed by a
+sequence of decimal digits.
+For decimal constants, the exponent indicates the power of 10 by
+which the significand should be scaled.
+For hexadecimal constants, the scaling is instead done by powers
+of 2.
+.Pp
+Alternatively, if the portion of the string following the optional
+plus or minus sign begins with
+.Dq INFINITY
+or
+.Dq NAN ,
+ignoring case, it is interpreted as an infinity or a quiet \*(Na,
+respectively.
+The syntax
+.Dq Xo Pf NAN( Ar "s" ) Xc ,
+where
+.Ar s
+is an alphanumeric string, produces the same value as the call
+.Fo nan
+.Qq Ar s Ns
+.Fc
+(respectively,
+.Fo nanf
+.Qq Ar s Ns
+.Fc
+and
+.Fo nanl
+.Qq Ar s Ns
+.Fc . )
+.Pp
+In any of the above cases, leading white-space characters in the
+string (as defined by the
+.Xr isspace 3
+function) are skipped.
+The decimal point
+character is defined in the program's locale (category
+.Dv LC_NUMERIC ) .
+.Sh RETURN VALUES
+The
+.Fn strtod ,
+.Fn strtof ,
+and
+.Fn strtold
+functions return the converted value, if any.
+.Pp
+If
+.Fa endptr
+is not
+.Dv NULL ,
+a pointer to the character after the last character used
+in the conversion is stored in the location referenced by
+.Fa endptr .
+.Pp
+If no conversion is performed, zero is returned and the value of
+.Fa nptr
+is stored in the location referenced by
+.Fa endptr .
+.Pp
+If the correct value would cause overflow, plus or minus
+.Dv HUGE_VAL ,
+.Dv HUGE_VALF ,
+or
+.Dv HUGE_VALL
+is returned (according to the sign and type of the return value), and
+.Er ERANGE
+is stored in
+.Va errno .
+If the correct value would cause underflow, zero is
+returned and
+.Er ERANGE
+is stored in
+.Va errno .
+.Sh ERRORS
+.Bl -tag -width Er
+.It Bq Er ERANGE
+Overflow or underflow occurred.
+.El
+.Sh SEE ALSO
+.Xr atof 3 ,
+.Xr atoi 3 ,
+.Xr atol 3 ,
+.Xr nan 3 ,
+.Xr strtol 3 ,
+.Xr strtoul 3 ,
+.Xr wcstod 3
+.Sh STANDARDS
+The
+.Fn strtod
+function
+conforms to
+.St -isoC-99 .
+.Sh AUTHORS
+The author of this software is
+.An David M. Gay .
+.Bd -literal
+Copyright (c) 1998 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+.Ed
diff --git a/lib/libc/stdlib/strtoimax.c b/lib/libc/stdlib/strtoimax.c
new file mode 100644
index 000000000000..72903e8df00e
--- /dev/null
+++ b/lib/libc/stdlib/strtoimax.c
@@ -0,0 +1,153 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "from @(#)strtol.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include "xlocale_private.h"
+
+/*
+ * Convert a string to an intmax_t integer.
+ *
+ * Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+intmax_t
+strtoimax_l(const char * __restrict nptr, char ** __restrict endptr, int base,
+ locale_t locale)
+{
+ const char *s;
+ uintmax_t acc;
+ char c;
+ uintmax_t cutoff;
+ int neg, any, cutlim;
+ FIX_LOCALE(locale);
+
+ /*
+ * Skip white space and pick up leading +/- sign if any.
+ * If base is 0, allow 0x for hex and 0 for octal, else
+ * assume decimal; if base is already 16, allow 0x.
+ */
+ s = nptr;
+ do {
+ c = *s++;
+ } while (isspace_l((unsigned char)c, locale));
+ if (c == '-') {
+ neg = 1;
+ c = *s++;
+ } else {
+ neg = 0;
+ if (c == '+')
+ c = *s++;
+ }
+ if ((base == 0 || base == 16) &&
+ c == '0' && (*s == 'x' || *s == 'X') &&
+ ((s[1] >= '0' && s[1] <= '9') ||
+ (s[1] >= 'A' && s[1] <= 'F') ||
+ (s[1] >= 'a' && s[1] <= 'f'))) {
+ c = s[1];
+ s += 2;
+ base = 16;
+ }
+ if (base == 0)
+ base = c == '0' ? 8 : 10;
+ acc = any = 0;
+ if (base < 2 || base > 36)
+ goto noconv;
+
+ /*
+ * Compute the cutoff value between legal numbers and illegal
+ * numbers. That is the largest legal value, divided by the
+ * base. An input number that is greater than this value, if
+ * followed by a legal input character, is too big. One that
+ * is equal to this value may be valid or not; the limit
+ * between valid and invalid numbers is then based on the last
+ * digit. For instance, if the range for intmax_t is
+ * [-9223372036854775808..9223372036854775807] and the input base
+ * is 10, cutoff will be set to 922337203685477580 and cutlim to
+ * either 7 (neg==0) or 8 (neg==1), meaning that if we have
+ * accumulated a value > 922337203685477580, or equal but the
+ * next digit is > 7 (or 8), the number is too big, and we will
+ * return a range error.
+ *
+ * Set 'any' if any `digits' consumed; make it negative to indicate
+ * overflow.
+ */
+ cutoff = neg ? (uintmax_t)-(INTMAX_MIN + INTMAX_MAX) + INTMAX_MAX
+ : INTMAX_MAX;
+ cutlim = cutoff % base;
+ cutoff /= base;
+ for ( ; ; c = *s++) {
+ if (c >= '0' && c <= '9')
+ c -= '0';
+ else if (c >= 'A' && c <= 'Z')
+ c -= 'A' - 10;
+ else if (c >= 'a' && c <= 'z')
+ c -= 'a' - 10;
+ else
+ break;
+ if (c >= base)
+ break;
+ if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
+ any = -1;
+ else {
+ any = 1;
+ acc *= base;
+ acc += c;
+ }
+ }
+ if (any < 0) {
+ acc = neg ? INTMAX_MIN : INTMAX_MAX;
+ errno = ERANGE;
+ } else if (!any) {
+noconv:
+ errno = EINVAL;
+ } else if (neg)
+ acc = -acc;
+ if (endptr != NULL)
+ *endptr = (char *)(any ? s - 1 : nptr);
+ return (acc);
+}
+intmax_t
+strtoimax(const char * __restrict nptr, char ** __restrict endptr, int base)
+{
+ return strtoimax_l(nptr, endptr, base, __get_locale());
+}
diff --git a/lib/libc/stdlib/strtol.3 b/lib/libc/stdlib/strtol.3
new file mode 100644
index 000000000000..3b7af7d30f01
--- /dev/null
+++ b/lib/libc/stdlib/strtol.3
@@ -0,0 +1,222 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek and the American National Standards Committee X3,
+.\" on Information Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)strtol.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd November 28, 2001
+.Dt STRTOL 3
+.Os
+.Sh NAME
+.Nm strtol , strtoll , strtoimax , strtoq
+.Nd "convert a string value to a"
+.Vt long , "long long" , intmax_t
+or
+.Vt quad_t
+integer
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.In limits.h
+.Ft long
+.Fn strtol "const char * restrict nptr" "char ** restrict endptr" "int base"
+.Ft long long
+.Fn strtoll "const char * restrict nptr" "char ** restrict endptr" "int base"
+.In inttypes.h
+.Ft intmax_t
+.Fn strtoimax "const char * restrict nptr" "char ** restrict endptr" "int base"
+.In sys/types.h
+.In stdlib.h
+.In limits.h
+.Ft quad_t
+.Fn strtoq "const char *nptr" "char **endptr" "int base"
+.Sh DESCRIPTION
+The
+.Fn strtol
+function
+converts the string in
+.Fa nptr
+to a
+.Vt long
+value.
+The
+.Fn strtoll
+function
+converts the string in
+.Fa nptr
+to a
+.Vt "long long"
+value.
+The
+.Fn strtoimax
+function
+converts the string in
+.Fa nptr
+to an
+.Vt intmax_t
+value.
+The
+.Fn strtoq
+function
+converts the string in
+.Fa nptr
+to a
+.Vt quad_t
+value.
+The conversion is done according to the given
+.Fa base ,
+which must be between 2 and 36 inclusive,
+or be the special value 0.
+.Pp
+The string may begin with an arbitrary amount of white space
+(as determined by
+.Xr isspace 3 )
+followed by a single optional
+.Ql +
+or
+.Ql -
+sign.
+If
+.Fa base
+is zero or 16,
+the string may then include a
+.Dq Li 0x
+prefix,
+and the number will be read in base 16; otherwise, a zero
+.Fa base
+is taken as 10 (decimal) unless the next character is
+.Ql 0 ,
+in which case it is taken as 8 (octal).
+.Pp
+The remainder of the string is converted to a
+.Vt long , "long long" , intmax_t
+or
+.Vt quad_t
+value in the obvious manner,
+stopping at the first character which is not a valid digit
+in the given base.
+(In bases above 10, the letter
+.Ql A
+in either upper or lower case
+represents 10,
+.Ql B
+represents 11, and so forth, with
+.Ql Z
+representing 35.)
+.Pp
+If
+.Fa endptr
+is not
+.Dv NULL ,
+.Fn strtol
+stores the address of the first invalid character in
+.Fa *endptr .
+If there were no digits at all, however,
+.Fn strtol
+stores the original value of
+.Fa nptr
+in
+.Fa *endptr .
+(Thus, if
+.Fa *nptr
+is not
+.Ql \e0
+but
+.Fa **endptr
+is
+.Ql \e0
+on return, the entire string was valid.)
+.Sh RETURN VALUES
+The
+.Fn strtol ,
+.Fn strtoll ,
+.Fn strtoimax
+and
+.Fn strtoq
+functions
+return the result of the conversion,
+unless the value would underflow or overflow.
+If no conversion could be performed, 0 is returned and
+the global variable
+.Va errno
+is set to
+.Er EINVAL
+(the last feature is not portable across all platforms).
+If an overflow or underflow occurs,
+.Va errno
+is set to
+.Er ERANGE
+and the function return value is clamped according
+to the following table.
+.Bl -column -offset indent ".Fn strtoimax" ".Sy underflow" ".Sy overflow"
+.It Sy Function Ta Sy underflow Ta Sy overflow
+.It Fn strtol Ta Dv LONG_MIN Ta Dv LONG_MAX
+.It Fn strtoll Ta Dv LLONG_MIN Ta Dv LLONG_MAX
+.It Fn strtoimax Ta Dv INTMAX_MIN Ta Dv INTMAX_MAX
+.It Fn strtoq Ta Dv LLONG_MIN Ta Dv LLONG_MAX
+.El
+.Sh ERRORS
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The value of
+.Fa base
+is not supported or
+no conversion could be performed
+(the last feature is not portable across all platforms).
+.It Bq Er ERANGE
+The given string was out of range; the value converted has been clamped.
+.El
+.Sh SEE ALSO
+.Xr atof 3 ,
+.Xr atoi 3 ,
+.Xr atol 3 ,
+.Xr strtod 3 ,
+.Xr strtonum 3 ,
+.Xr strtoul 3 ,
+.Xr wcstol 3
+.Sh STANDARDS
+The
+.Fn strtol
+function
+conforms to
+.St -isoC .
+The
+.Fn strtoll
+and
+.Fn strtoimax
+functions
+conform to
+.St -isoC-99 .
+The
+.Bx
+.Fn strtoq
+function is deprecated.
diff --git a/lib/libc/stdlib/strtol.c b/lib/libc/stdlib/strtol.c
new file mode 100644
index 000000000000..e0c9978458e3
--- /dev/null
+++ b/lib/libc/stdlib/strtol.c
@@ -0,0 +1,158 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strtol.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <limits.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+#include "xlocale_private.h"
+
+
+/*
+ * Convert a string to a long integer.
+ *
+ * Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+long
+strtol_l(const char * __restrict nptr, char ** __restrict endptr, int base,
+ locale_t locale)
+{
+ const char *s;
+ unsigned long acc;
+ char c;
+ unsigned long cutoff;
+ int neg, any, cutlim;
+ FIX_LOCALE(locale);
+
+ /*
+ * Skip white space and pick up leading +/- sign if any.
+ * If base is 0, allow 0x for hex and 0 for octal, else
+ * assume decimal; if base is already 16, allow 0x.
+ */
+ s = nptr;
+ do {
+ c = *s++;
+ } while (isspace_l((unsigned char)c, locale));
+ if (c == '-') {
+ neg = 1;
+ c = *s++;
+ } else {
+ neg = 0;
+ if (c == '+')
+ c = *s++;
+ }
+ if ((base == 0 || base == 16) &&
+ c == '0' && (*s == 'x' || *s == 'X') &&
+ ((s[1] >= '0' && s[1] <= '9') ||
+ (s[1] >= 'A' && s[1] <= 'F') ||
+ (s[1] >= 'a' && s[1] <= 'f'))) {
+ c = s[1];
+ s += 2;
+ base = 16;
+ }
+ if (base == 0)
+ base = c == '0' ? 8 : 10;
+ acc = any = 0;
+ if (base < 2 || base > 36)
+ goto noconv;
+
+ /*
+ * Compute the cutoff value between legal numbers and illegal
+ * numbers. That is the largest legal value, divided by the
+ * base. An input number that is greater than this value, if
+ * followed by a legal input character, is too big. One that
+ * is equal to this value may be valid or not; the limit
+ * between valid and invalid numbers is then based on the last
+ * digit. For instance, if the range for longs is
+ * [-2147483648..2147483647] and the input base is 10,
+ * cutoff will be set to 214748364 and cutlim to either
+ * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
+ * a value > 214748364, or equal but the next digit is > 7 (or 8),
+ * the number is too big, and we will return a range error.
+ *
+ * Set 'any' if any `digits' consumed; make it negative to indicate
+ * overflow.
+ */
+ cutoff = neg ? (unsigned long)-(LONG_MIN + LONG_MAX) + LONG_MAX
+ : LONG_MAX;
+ cutlim = cutoff % base;
+ cutoff /= base;
+ for ( ; ; c = *s++) {
+ if (c >= '0' && c <= '9')
+ c -= '0';
+ else if (c >= 'A' && c <= 'Z')
+ c -= 'A' - 10;
+ else if (c >= 'a' && c <= 'z')
+ c -= 'a' - 10;
+ else
+ break;
+ if (c >= base)
+ break;
+ if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
+ any = -1;
+ else {
+ any = 1;
+ acc *= base;
+ acc += c;
+ }
+ }
+ if (any < 0) {
+ acc = neg ? LONG_MIN : LONG_MAX;
+ errno = ERANGE;
+ } else if (!any) {
+noconv:
+ errno = EINVAL;
+ } else if (neg)
+ acc = -acc;
+ if (endptr != NULL)
+ *endptr = (char *)(any ? s - 1 : nptr);
+ return (acc);
+}
+long
+strtol(const char * __restrict nptr, char ** __restrict endptr, int base)
+{
+ return strtol_l(nptr, endptr, base, __get_locale());
+}
+long double
+strtold(const char * __restrict nptr, char ** __restrict endptr)
+{
+ return strtold_l(nptr, endptr, __get_locale());
+}
diff --git a/lib/libc/stdlib/strtoll.c b/lib/libc/stdlib/strtoll.c
new file mode 100644
index 000000000000..16a8196a3562
--- /dev/null
+++ b/lib/libc/stdlib/strtoll.c
@@ -0,0 +1,153 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strtoq.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <limits.h>
+#include <errno.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include "xlocale_private.h"
+
+/*
+ * Convert a string to a long long integer.
+ *
+ * Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+long long
+strtoll_l(const char * __restrict nptr, char ** __restrict endptr, int base,
+ locale_t locale)
+{
+ const char *s;
+ unsigned long long acc;
+ char c;
+ unsigned long long cutoff;
+ int neg, any, cutlim;
+ FIX_LOCALE(locale);
+
+ /*
+ * Skip white space and pick up leading +/- sign if any.
+ * If base is 0, allow 0x for hex and 0 for octal, else
+ * assume decimal; if base is already 16, allow 0x.
+ */
+ s = nptr;
+ do {
+ c = *s++;
+ } while (isspace_l((unsigned char)c, locale));
+ if (c == '-') {
+ neg = 1;
+ c = *s++;
+ } else {
+ neg = 0;
+ if (c == '+')
+ c = *s++;
+ }
+ if ((base == 0 || base == 16) &&
+ c == '0' && (*s == 'x' || *s == 'X') &&
+ ((s[1] >= '0' && s[1] <= '9') ||
+ (s[1] >= 'A' && s[1] <= 'F') ||
+ (s[1] >= 'a' && s[1] <= 'f'))) {
+ c = s[1];
+ s += 2;
+ base = 16;
+ }
+ if (base == 0)
+ base = c == '0' ? 8 : 10;
+ acc = any = 0;
+ if (base < 2 || base > 36)
+ goto noconv;
+
+ /*
+ * Compute the cutoff value between legal numbers and illegal
+ * numbers. That is the largest legal value, divided by the
+ * base. An input number that is greater than this value, if
+ * followed by a legal input character, is too big. One that
+ * is equal to this value may be valid or not; the limit
+ * between valid and invalid numbers is then based on the last
+ * digit. For instance, if the range for quads is
+ * [-9223372036854775808..9223372036854775807] and the input base
+ * is 10, cutoff will be set to 922337203685477580 and cutlim to
+ * either 7 (neg==0) or 8 (neg==1), meaning that if we have
+ * accumulated a value > 922337203685477580, or equal but the
+ * next digit is > 7 (or 8), the number is too big, and we will
+ * return a range error.
+ *
+ * Set 'any' if any `digits' consumed; make it negative to indicate
+ * overflow.
+ */
+ cutoff = neg ? (unsigned long long)-(LLONG_MIN + LLONG_MAX) + LLONG_MAX
+ : LLONG_MAX;
+ cutlim = cutoff % base;
+ cutoff /= base;
+ for ( ; ; c = *s++) {
+ if (c >= '0' && c <= '9')
+ c -= '0';
+ else if (c >= 'A' && c <= 'Z')
+ c -= 'A' - 10;
+ else if (c >= 'a' && c <= 'z')
+ c -= 'a' - 10;
+ else
+ break;
+ if (c >= base)
+ break;
+ if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
+ any = -1;
+ else {
+ any = 1;
+ acc *= base;
+ acc += c;
+ }
+ }
+ if (any < 0) {
+ acc = neg ? LLONG_MIN : LLONG_MAX;
+ errno = ERANGE;
+ } else if (!any) {
+noconv:
+ errno = EINVAL;
+ } else if (neg)
+ acc = -acc;
+ if (endptr != NULL)
+ *endptr = (char *)(any ? s - 1 : nptr);
+ return (acc);
+}
+long long
+strtoll(const char * __restrict nptr, char ** __restrict endptr, int base)
+{
+ return strtoll_l(nptr, endptr, base, __get_locale());
+}
diff --git a/lib/libc/stdlib/strtonum.3 b/lib/libc/stdlib/strtonum.3
new file mode 100644
index 000000000000..ed2699559bee
--- /dev/null
+++ b/lib/libc/stdlib/strtonum.3
@@ -0,0 +1,155 @@
+.\" Copyright (c) 2004 Ted Unangst
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.\" $OpenBSD: strtonum.3,v 1.13 2006/04/25 05:15:42 tedu Exp $
+.\" $FreeBSD$
+.\"
+.Dd April 29, 2004
+.Dt STRTONUM 3
+.Os
+.Sh NAME
+.Nm strtonum
+.Nd "reliably convert string value to an integer"
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft long long
+.Fo strtonum
+.Fa "const char *nptr"
+.Fa "long long minval"
+.Fa "long long maxval"
+.Fa "const char **errstr"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn strtonum
+function converts the string in
+.Fa nptr
+to a
+.Vt "long long"
+value.
+The
+.Fn strtonum
+function was designed to facilitate safe, robust programming
+and overcome the shortcomings of the
+.Xr atoi 3
+and
+.Xr strtol 3
+family of interfaces.
+.Pp
+The string may begin with an arbitrary amount of whitespace
+(as determined by
+.Xr isspace 3 )
+followed by a single optional
+.Ql +
+or
+.Ql -
+sign.
+.Pp
+The remainder of the string is converted to a
+.Vt "long long"
+value according to base 10.
+.Pp
+The value obtained is then checked against the provided
+.Fa minval
+and
+.Fa maxval
+bounds.
+If
+.Fa errstr
+is non-null,
+.Fn strtonum
+stores an error string in
+.Fa *errstr
+indicating the failure.
+.Sh RETURN VALUES
+The
+.Fn strtonum
+function returns the result of the conversion,
+unless the value would exceed the provided bounds or is invalid.
+On error, 0 is returned,
+.Va errno
+is set, and
+.Fa errstr
+will point to an error message.
+On success,
+.Fa *errstr
+will be set to
+.Dv NULL ;
+this fact can be used to differentiate
+a successful return of 0 from an error.
+.Sh EXAMPLES
+Using
+.Fn strtonum
+correctly is meant to be simpler than the alternative functions.
+.Bd -literal -offset indent
+int iterations;
+const char *errstr;
+
+iterations = strtonum(optarg, 1, 64, &errstr);
+if (errstr != NULL)
+ errx(1, "number of iterations is %s: %s", errstr, optarg);
+.Ed
+.Pp
+The above example will guarantee that the value of iterations is between
+1 and 64 (inclusive).
+.Sh ERRORS
+.Bl -tag -width Er
+.It Bq Er ERANGE
+The given string was out of range.
+.It Bq Er EINVAL
+The given string did not consist solely of digit characters.
+.It Bq Er EINVAL
+The supplied
+.Fa minval
+was larger than
+.Fa maxval .
+.El
+.Pp
+If an error occurs,
+.Fa errstr
+will be set to one of the following strings:
+.Pp
+.Bl -tag -width ".Li too large" -compact
+.It Li "too large"
+The result was larger than the provided maximum value.
+.It Li "too small"
+The result was smaller than the provided minimum value.
+.It Li invalid
+The string did not consist solely of digit characters.
+.El
+.Sh SEE ALSO
+.Xr atof 3 ,
+.Xr atoi 3 ,
+.Xr atol 3 ,
+.Xr atoll 3 ,
+.Xr sscanf 3 ,
+.Xr strtod 3 ,
+.Xr strtol 3 ,
+.Xr strtoul 3
+.Sh STANDARDS
+The
+.Fn strtonum
+function is a
+.Bx
+extension.
+The existing alternatives, such as
+.Xr atoi 3
+and
+.Xr strtol 3 ,
+are either impossible or difficult to use safely.
+.Sh HISTORY
+The
+.Fn strtonum
+function first appeared in
+.Ox 3.6 .
diff --git a/lib/libc/stdlib/strtonum.c b/lib/libc/stdlib/strtonum.c
new file mode 100644
index 000000000000..aa433d835b36
--- /dev/null
+++ b/lib/libc/stdlib/strtonum.c
@@ -0,0 +1,68 @@
+/*-
+ * Copyright (c) 2004 Ted Unangst and Todd Miller
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $OpenBSD: strtonum.c,v 1.7 2013/04/17 18:40:58 tedu Exp $
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#define INVALID 1
+#define TOOSMALL 2
+#define TOOLARGE 3
+
+long long
+strtonum(const char *numstr, long long minval, long long maxval,
+ const char **errstrp)
+{
+ long long ll = 0;
+ int error = 0;
+ char *ep;
+ struct errval {
+ const char *errstr;
+ int err;
+ } ev[4] = {
+ { NULL, 0 },
+ { "invalid", EINVAL },
+ { "too small", ERANGE },
+ { "too large", ERANGE },
+ };
+
+ ev[0].err = errno;
+ errno = 0;
+ if (minval > maxval) {
+ error = INVALID;
+ } else {
+ ll = strtoll(numstr, &ep, 10);
+ if (errno == EINVAL || numstr == ep || *ep != '\0')
+ error = INVALID;
+ else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval)
+ error = TOOSMALL;
+ else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval)
+ error = TOOLARGE;
+ }
+ if (errstrp != NULL)
+ *errstrp = ev[error].errstr;
+ errno = ev[error].err;
+ if (error)
+ ll = 0;
+
+ return (ll);
+}
diff --git a/lib/libc/stdlib/strtoq.c b/lib/libc/stdlib/strtoq.c
new file mode 100644
index 000000000000..7bc1c80a3a32
--- /dev/null
+++ b/lib/libc/stdlib/strtoq.c
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strtoq.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+#include <stdlib.h>
+
+/*
+ * Convert a string to a quad integer.
+ */
+quad_t
+strtoq(const char *nptr, char **endptr, int base)
+{
+
+ return strtoll(nptr, endptr, base);
+}
diff --git a/lib/libc/stdlib/strtoul.3 b/lib/libc/stdlib/strtoul.3
new file mode 100644
index 000000000000..6d269656ddf6
--- /dev/null
+++ b/lib/libc/stdlib/strtoul.3
@@ -0,0 +1,224 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek and the American National Standards Committee X3,
+.\" on Information Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)strtoul.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd November 28, 2001
+.Dt STRTOUL 3
+.Os
+.Sh NAME
+.Nm strtoul , strtoull , strtoumax , strtouq
+.Nd "convert a string to an"
+.Vt "unsigned long" , "unsigned long long" , uintmax_t ,
+or
+.Vt u_quad_t
+integer
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.In limits.h
+.Ft "unsigned long"
+.Fn strtoul "const char * restrict nptr" "char ** restrict endptr" "int base"
+.Ft "unsigned long long"
+.Fn strtoull "const char * restrict nptr" "char ** restrict endptr" "int base"
+.In inttypes.h
+.Ft uintmax_t
+.Fn strtoumax "const char * restrict nptr" "char ** restrict endptr" "int base"
+.In sys/types.h
+.In stdlib.h
+.In limits.h
+.Ft u_quad_t
+.Fn strtouq "const char *nptr" "char **endptr" "int base"
+.Sh DESCRIPTION
+The
+.Fn strtoul
+function
+converts the string in
+.Fa nptr
+to an
+.Vt "unsigned long"
+value.
+The
+.Fn strtoull
+function
+converts the string in
+.Fa nptr
+to an
+.Vt "unsigned long long"
+value.
+The
+.Fn strtoumax
+function
+converts the string in
+.Fa nptr
+to an
+.Vt uintmax_t
+value.
+The
+.Fn strtouq
+function
+converts the string in
+.Fa nptr
+to a
+.Vt u_quad_t
+value.
+The conversion is done according to the given
+.Fa base ,
+which must be between 2 and 36 inclusive,
+or be the special value 0.
+.Pp
+The string may begin with an arbitrary amount of white space
+(as determined by
+.Xr isspace 3 )
+followed by a single optional
+.Ql +
+or
+.Ql -
+sign.
+If
+.Fa base
+is zero or 16,
+the string may then include a
+.Dq Li 0x
+prefix,
+and the number will be read in base 16; otherwise, a zero
+.Fa base
+is taken as 10 (decimal) unless the next character is
+.Ql 0 ,
+in which case it is taken as 8 (octal).
+.Pp
+The remainder of the string is converted to an
+.Vt "unsigned long"
+value in the obvious manner,
+stopping at the end of the string
+or at the first character that does not produce a valid digit
+in the given base.
+(In bases above 10, the letter
+.Ql A
+in either upper or lower case
+represents 10,
+.Ql B
+represents 11, and so forth, with
+.Ql Z
+representing 35.)
+.Pp
+If
+.Fa endptr
+is not
+.Dv NULL ,
+.Fn strtoul
+stores the address of the first invalid character in
+.Fa *endptr .
+If there were no digits at all, however,
+.Fn strtoul
+stores the original value of
+.Fa nptr
+in
+.Fa *endptr .
+(Thus, if
+.Fa *nptr
+is not
+.Ql \e0
+but
+.Fa **endptr
+is
+.Ql \e0
+on return, the entire string was valid.)
+.Sh RETURN VALUES
+The
+.Fn strtoul ,
+.Fn strtoull ,
+.Fn strtoumax
+and
+.Fn strtouq
+functions
+return either the result of the conversion
+or, if there was a leading minus sign,
+the negation of the result of the conversion,
+unless the original (non-negated) value would overflow;
+in the latter case,
+.Fn strtoul
+returns
+.Dv ULONG_MAX ,
+.Fn strtoull
+returns
+.Dv ULLONG_MAX ,
+.Fn strtoumax
+returns
+.Dv UINTMAX_MAX ,
+and
+.Fn strtouq
+returns
+.Dv ULLONG_MAX .
+In all cases,
+.Va errno
+is set to
+.Er ERANGE .
+If no conversion could be performed, 0 is returned and
+the global variable
+.Va errno
+is set to
+.Er EINVAL
+(the last feature is not portable across all platforms).
+.Sh ERRORS
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The value of
+.Fa base
+is not supported or
+no conversion could be performed
+(the last feature is not portable across all platforms).
+.It Bq Er ERANGE
+The given string was out of range; the value converted has been clamped.
+.El
+.Sh SEE ALSO
+.Xr strtol 3 ,
+.Xr strtonum 3 ,
+.Xr wcstoul 3
+.Sh STANDARDS
+The
+.Fn strtoul
+function
+conforms to
+.St -isoC .
+The
+.Fn strtoull
+and
+.Fn strtoumax
+functions
+conform to
+.St -isoC-99 .
+The
+.Bx
+.Fn strtouq
+function is deprecated.
diff --git a/lib/libc/stdlib/strtoul.c b/lib/libc/stdlib/strtoul.c
new file mode 100644
index 000000000000..ed58dd8ae662
--- /dev/null
+++ b/lib/libc/stdlib/strtoul.c
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strtoul.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <limits.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+#include "xlocale_private.h"
+
+/*
+ * Convert a string to an unsigned long integer.
+ *
+ * Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+unsigned long
+strtoul_l(const char * __restrict nptr, char ** __restrict endptr, int base, locale_t locale)
+{
+ const char *s;
+ unsigned long acc;
+ char c;
+ unsigned long cutoff;
+ int neg, any, cutlim;
+ FIX_LOCALE(locale);
+
+ /*
+ * See strtol for comments as to the logic used.
+ */
+ s = nptr;
+ do {
+ c = *s++;
+ } while (isspace_l((unsigned char)c, locale));
+ if (c == '-') {
+ neg = 1;
+ c = *s++;
+ } else {
+ neg = 0;
+ if (c == '+')
+ c = *s++;
+ }
+ if ((base == 0 || base == 16) &&
+ c == '0' && (*s == 'x' || *s == 'X') &&
+ ((s[1] >= '0' && s[1] <= '9') ||
+ (s[1] >= 'A' && s[1] <= 'F') ||
+ (s[1] >= 'a' && s[1] <= 'f'))) {
+ c = s[1];
+ s += 2;
+ base = 16;
+ }
+ if (base == 0)
+ base = c == '0' ? 8 : 10;
+ acc = any = 0;
+ if (base < 2 || base > 36)
+ goto noconv;
+
+ cutoff = ULONG_MAX / base;
+ cutlim = ULONG_MAX % base;
+ for ( ; ; c = *s++) {
+ if (c >= '0' && c <= '9')
+ c -= '0';
+ else if (c >= 'A' && c <= 'Z')
+ c -= 'A' - 10;
+ else if (c >= 'a' && c <= 'z')
+ c -= 'a' - 10;
+ else
+ break;
+ if (c >= base)
+ break;
+ if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
+ any = -1;
+ else {
+ any = 1;
+ acc *= base;
+ acc += c;
+ }
+ }
+ if (any < 0) {
+ acc = ULONG_MAX;
+ errno = ERANGE;
+ } else if (!any) {
+noconv:
+ errno = EINVAL;
+ } else if (neg)
+ acc = -acc;
+ if (endptr != NULL)
+ *endptr = (char *)(any ? s - 1 : nptr);
+ return (acc);
+}
+unsigned long
+strtoul(const char * __restrict nptr, char ** __restrict endptr, int base)
+{
+ return strtoul_l(nptr, endptr, base, __get_locale());
+}
diff --git a/lib/libc/stdlib/strtoull.c b/lib/libc/stdlib/strtoull.c
new file mode 100644
index 000000000000..dc40e0e98919
--- /dev/null
+++ b/lib/libc/stdlib/strtoull.c
@@ -0,0 +1,131 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strtouq.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <limits.h>
+#include <errno.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include "xlocale_private.h"
+
+/*
+ * Convert a string to an unsigned long long integer.
+ *
+ * Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+unsigned long long
+strtoull_l(const char * __restrict nptr, char ** __restrict endptr, int base,
+ locale_t locale)
+{
+ const char *s;
+ unsigned long long acc;
+ char c;
+ unsigned long long cutoff;
+ int neg, any, cutlim;
+ FIX_LOCALE(locale);
+
+ /*
+ * See strtoq for comments as to the logic used.
+ */
+ s = nptr;
+ do {
+ c = *s++;
+ } while (isspace_l((unsigned char)c, locale));
+ if (c == '-') {
+ neg = 1;
+ c = *s++;
+ } else {
+ neg = 0;
+ if (c == '+')
+ c = *s++;
+ }
+ if ((base == 0 || base == 16) &&
+ c == '0' && (*s == 'x' || *s == 'X') &&
+ ((s[1] >= '0' && s[1] <= '9') ||
+ (s[1] >= 'A' && s[1] <= 'F') ||
+ (s[1] >= 'a' && s[1] <= 'f'))) {
+ c = s[1];
+ s += 2;
+ base = 16;
+ }
+ if (base == 0)
+ base = c == '0' ? 8 : 10;
+ acc = any = 0;
+ if (base < 2 || base > 36)
+ goto noconv;
+
+ cutoff = ULLONG_MAX / base;
+ cutlim = ULLONG_MAX % base;
+ for ( ; ; c = *s++) {
+ if (c >= '0' && c <= '9')
+ c -= '0';
+ else if (c >= 'A' && c <= 'Z')
+ c -= 'A' - 10;
+ else if (c >= 'a' && c <= 'z')
+ c -= 'a' - 10;
+ else
+ break;
+ if (c >= base)
+ break;
+ if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
+ any = -1;
+ else {
+ any = 1;
+ acc *= base;
+ acc += c;
+ }
+ }
+ if (any < 0) {
+ acc = ULLONG_MAX;
+ errno = ERANGE;
+ } else if (!any) {
+noconv:
+ errno = EINVAL;
+ } else if (neg)
+ acc = -acc;
+ if (endptr != NULL)
+ *endptr = (char *)(any ? s - 1 : nptr);
+ return (acc);
+}
+unsigned long long
+strtoull(const char * __restrict nptr, char ** __restrict endptr, int base)
+{
+ return strtoull_l(nptr, endptr, base, __get_locale());
+}
diff --git a/lib/libc/stdlib/strtoumax.c b/lib/libc/stdlib/strtoumax.c
new file mode 100644
index 000000000000..769967727ac5
--- /dev/null
+++ b/lib/libc/stdlib/strtoumax.c
@@ -0,0 +1,131 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "from @(#)strtoul.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include "xlocale_private.h"
+
+/*
+ * Convert a string to a uintmax_t integer.
+ *
+ * Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+uintmax_t
+strtoumax_l(const char * __restrict nptr, char ** __restrict endptr, int base,
+ locale_t locale)
+{
+ const char *s;
+ uintmax_t acc;
+ char c;
+ uintmax_t cutoff;
+ int neg, any, cutlim;
+ FIX_LOCALE(locale);
+
+ /*
+ * See strtoimax for comments as to the logic used.
+ */
+ s = nptr;
+ do {
+ c = *s++;
+ } while (isspace_l((unsigned char)c, locale));
+ if (c == '-') {
+ neg = 1;
+ c = *s++;
+ } else {
+ neg = 0;
+ if (c == '+')
+ c = *s++;
+ }
+ if ((base == 0 || base == 16) &&
+ c == '0' && (*s == 'x' || *s == 'X') &&
+ ((s[1] >= '0' && s[1] <= '9') ||
+ (s[1] >= 'A' && s[1] <= 'F') ||
+ (s[1] >= 'a' && s[1] <= 'f'))) {
+ c = s[1];
+ s += 2;
+ base = 16;
+ }
+ if (base == 0)
+ base = c == '0' ? 8 : 10;
+ acc = any = 0;
+ if (base < 2 || base > 36)
+ goto noconv;
+
+ cutoff = UINTMAX_MAX / base;
+ cutlim = UINTMAX_MAX % base;
+ for ( ; ; c = *s++) {
+ if (c >= '0' && c <= '9')
+ c -= '0';
+ else if (c >= 'A' && c <= 'Z')
+ c -= 'A' - 10;
+ else if (c >= 'a' && c <= 'z')
+ c -= 'a' - 10;
+ else
+ break;
+ if (c >= base)
+ break;
+ if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
+ any = -1;
+ else {
+ any = 1;
+ acc *= base;
+ acc += c;
+ }
+ }
+ if (any < 0) {
+ acc = UINTMAX_MAX;
+ errno = ERANGE;
+ } else if (!any) {
+noconv:
+ errno = EINVAL;
+ } else if (neg)
+ acc = -acc;
+ if (endptr != NULL)
+ *endptr = (char *)(any ? s - 1 : nptr);
+ return (acc);
+}
+uintmax_t
+strtoumax(const char * __restrict nptr, char ** __restrict endptr, int base)
+{
+ return strtoumax_l(nptr, endptr, base, __get_locale());
+}
diff --git a/lib/libc/stdlib/strtouq.c b/lib/libc/stdlib/strtouq.c
new file mode 100644
index 000000000000..9371680b9721
--- /dev/null
+++ b/lib/libc/stdlib/strtouq.c
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strtouq.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+#include <stdlib.h>
+
+/*
+ * Convert a string to an unsigned quad integer.
+ */
+u_quad_t
+strtouq(const char *nptr, char **endptr, int base)
+{
+
+ return strtoull(nptr, endptr, base);
+}
diff --git a/lib/libc/stdlib/system.3 b/lib/libc/stdlib/system.3
new file mode 100644
index 000000000000..4fd61bcda233
--- /dev/null
+++ b/lib/libc/stdlib/system.3
@@ -0,0 +1,111 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)system.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd July 25, 2015
+.Dt SYSTEM 3
+.Os
+.Sh NAME
+.Nm system
+.Nd pass a command to the shell
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft int
+.Fn system "const char *string"
+.Sh DESCRIPTION
+The
+.Fn system
+function
+hands the argument
+.Fa string
+to the command interpreter
+.Xr sh 1 .
+The calling process waits for the shell
+to finish executing the command,
+ignoring
+.Dv SIGINT
+and
+.Dv SIGQUIT ,
+and blocking
+.Dv SIGCHLD .
+.Pp
+If
+.Fa string
+is a
+.Dv NULL
+pointer,
+.Fn system
+will return non-zero if the command interpreter
+.Xr sh 1
+is available, and zero if it is not.
+.Sh RETURN VALUES
+The
+.Fn system
+function
+returns the exit status of the shell as returned by
+.Xr waitpid 2 ,
+or \-1 if an error occurred when invoking
+.Xr fork 2
+or
+.Xr waitpid 2 .
+A return value of 127 means the execution of the shell
+failed.
+.Sh SEE ALSO
+.Xr sh 1 ,
+.Xr execve 2 ,
+.Xr fork 2 ,
+.Xr waitpid 2 ,
+.Xr popen 3 ,
+.Xr posix_spawn 3
+.Sh STANDARDS
+The
+.Fn system
+function
+conforms to
+.St -isoC
+and is expected to be
+.St -p1003.2
+compatible.
+.Sh SECURITY CONSIDERATIONS
+The
+.Fn system
+function is easily misused in a manner that enables a malicious
+user to run arbitrary command,
+because all meta-characters supported by
+.Xr sh 1
+would be honored.
+User supplied parameters should always be carefully santized
+before they appear in
+.Fa string.
diff --git a/lib/libc/stdlib/system.c b/lib/libc/stdlib/system.c
new file mode 100644
index 000000000000..2b298e45a6d6
--- /dev/null
+++ b/lib/libc/stdlib/system.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)system.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <unistd.h>
+#include <paths.h>
+#include <errno.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+
+#pragma weak system
+int
+system(const char *command)
+{
+
+ return (((int (*)(const char *))
+ __libc_interposing[INTERPOS_system])(command));
+}
+
+int
+__libc_system(const char *command)
+{
+ pid_t pid, savedpid;
+ int pstat;
+ struct sigaction ign, intact, quitact;
+ sigset_t newsigblock, oldsigblock;
+
+ if (!command) /* just checking... */
+ return(1);
+
+ (void)sigemptyset(&newsigblock);
+ (void)sigaddset(&newsigblock, SIGCHLD);
+ (void)sigaddset(&newsigblock, SIGINT);
+ (void)sigaddset(&newsigblock, SIGQUIT);
+ (void)__libc_sigprocmask(SIG_BLOCK, &newsigblock, &oldsigblock);
+ switch(pid = vfork()) {
+ /*
+ * In the child, use unwrapped syscalls. libthr is in
+ * undefined state after vfork().
+ */
+ case -1: /* error */
+ (void)__libc_sigprocmask(SIG_SETMASK, &oldsigblock, NULL);
+ return (-1);
+ case 0: /* child */
+ /*
+ * Restore original signal dispositions and exec the command.
+ */
+ (void)__sys_sigprocmask(SIG_SETMASK, &oldsigblock, NULL);
+ execl(_PATH_BSHELL, "sh", "-c", command, (char *)NULL);
+ _exit(127);
+ }
+ /*
+ * If we are running means that the child has either completed
+ * its execve, or has failed.
+ * Block SIGINT/QUIT because sh -c handles it and wait for
+ * it to clean up.
+ */
+ memset(&ign, 0, sizeof(ign));
+ ign.sa_handler = SIG_IGN;
+ (void)sigemptyset(&ign.sa_mask);
+ (void)__libc_sigaction(SIGINT, &ign, &intact);
+ (void)__libc_sigaction(SIGQUIT, &ign, &quitact);
+ savedpid = pid;
+ do {
+ pid = _wait4(savedpid, &pstat, 0, (struct rusage *)0);
+ } while (pid == -1 && errno == EINTR);
+ (void)__libc_sigaction(SIGINT, &intact, NULL);
+ (void)__libc_sigaction(SIGQUIT, &quitact, NULL);
+ (void)__libc_sigprocmask(SIG_SETMASK, &oldsigblock, NULL);
+ return (pid == -1 ? -1 : pstat);
+}
+
+__weak_reference(__libc_system, __system);
+__weak_reference(__libc_system, _system);
diff --git a/lib/libc/stdlib/tdelete.c b/lib/libc/stdlib/tdelete.c
new file mode 100644
index 000000000000..38b2bd739170
--- /dev/null
+++ b/lib/libc/stdlib/tdelete.c
@@ -0,0 +1,208 @@
+/*-
+ * Copyright (c) 2015 Nuxi, https://nuxi.nl/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#define _SEARCH_PRIVATE
+#include <search.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include "tsearch_path.h"
+
+/*
+ * Makes a step to the left along the binary search tree. This step is
+ * also saved, so it can be replayed while rebalancing.
+*/
+#define GO_LEFT() do { \
+ if ((*leaf)->balance == 0 || \
+ ((*leaf)->balance < 0 && (*leaf)->rlink->balance == 0)) { \
+ /* \
+ * If we reach a node that is balanced, or has a child \
+ * in the opposite direction that is balanced, we know \
+ * that we won't need to perform any rotations above \
+ * this point. In this case rotations are always \
+ * capable of keeping the subtree in balance. Make \
+ * this the root node and reset the path. \
+ */ \
+ rootp = leaf; \
+ path_init(&path); \
+ } \
+ path_taking_left(&path); \
+ leaf = &(*leaf)->llink; \
+} while (0)
+
+/* Makes a step to the right along the binary search tree. */
+#define GO_RIGHT() do { \
+ if ((*leaf)->balance == 0 || \
+ ((*leaf)->balance > 0 && (*leaf)->llink->balance == 0)) { \
+ rootp = leaf; \
+ path_init(&path); \
+ } \
+ path_taking_right(&path); \
+ leaf = &(*leaf)->rlink; \
+} while (0)
+
+void *
+tdelete(const void *restrict key, posix_tnode **restrict rootp,
+ int (*compar)(const void *, const void *))
+{
+ struct path path;
+ posix_tnode **leaf, *old, **n, *x, *y, *z, *result;
+ int cmp;
+
+ /* POSIX requires that tdelete() returns NULL if rootp is NULL. */
+ if (rootp == NULL)
+ return (NULL);
+
+ /*
+ * Find the leaf that needs to be removed. Return if we cannot
+ * find an existing entry. Keep track of the path that is taken
+ * to get to the node, as we will need it to adjust the
+ * balances.
+ */
+ result = (posix_tnode *)1;
+ path_init(&path);
+ leaf = rootp;
+ for (;;) {
+ if (*leaf == NULL)
+ return (NULL);
+ cmp = compar(key, (*leaf)->key);
+ if (cmp < 0) {
+ result = *leaf;
+ GO_LEFT();
+ } else if (cmp > 0) {
+ result = *leaf;
+ GO_RIGHT();
+ } else {
+ break;
+ }
+ }
+
+ /* Found a matching key in the tree. Remove the node. */
+ if ((*leaf)->llink == NULL) {
+ /* Node has no left children. Replace by its right subtree. */
+ old = *leaf;
+ *leaf = old->rlink;
+ free(old);
+ } else {
+ /*
+ * Node has left children. Replace this node's key by
+ * its predecessor's and remove that node instead.
+ */
+ void **keyp = &(*leaf)->key;
+ GO_LEFT();
+ while ((*leaf)->rlink != NULL)
+ GO_RIGHT();
+ old = *leaf;
+ *keyp = old->key;
+ *leaf = old->llink;
+ free(old);
+ }
+
+ /*
+ * Walk along the same path a second time and adjust the
+ * balances. Though this code looks similar to the rebalancing
+ * performed in tsearch(), it is not identical. We now also need
+ * to consider the case of outward imbalance in the right-right
+ * and left-left case that only exists when deleting. Hence the
+ * duplication of code.
+ */
+ for (n = rootp; n != leaf;) {
+ if (path_took_left(&path)) {
+ x = *n;
+ if (x->balance < 0) {
+ y = x->rlink;
+ if (y->balance > 0) {
+ /* Right-left case. */
+ z = y->llink;
+ x->rlink = z->llink;
+ z->llink = x;
+ y->llink = z->rlink;
+ z->rlink = y;
+ *n = z;
+
+ x->balance = z->balance < 0 ? 1 : 0;
+ y->balance = z->balance > 0 ? -1 : 0;
+ z->balance = 0;
+ } else {
+ /* Right-right case. */
+ x->rlink = y->llink;
+ y->llink = x;
+ *n = y;
+
+ if (y->balance < 0) {
+ x->balance = 0;
+ y->balance = 0;
+ } else {
+ x->balance = -1;
+ y->balance = 1;
+ }
+ }
+ } else {
+ --x->balance;
+ }
+ n = &x->llink;
+ } else {
+ x = *n;
+ if (x->balance > 0) {
+ y = x->llink;
+ if (y->balance < 0) {
+ /* Left-right case. */
+ z = y->rlink;
+ y->rlink = z->llink;
+ z->llink = y;
+ x->llink = z->rlink;
+ z->rlink = x;
+ *n = z;
+
+ x->balance = z->balance > 0 ? -1 : 0;
+ y->balance = z->balance < 0 ? 1 : 0;
+ z->balance = 0;
+ } else {
+ /* Left-left case. */
+ x->llink = y->rlink;
+ y->rlink = x;
+ *n = y;
+
+ if (y->balance > 0) {
+ x->balance = 0;
+ y->balance = 0;
+ } else {
+ x->balance = 1;
+ y->balance = -1;
+ }
+ }
+ } else {
+ ++x->balance;
+ }
+ n = &x->rlink;
+ }
+ }
+
+ /* Return the parent of the old entry. */
+ return (result);
+}
diff --git a/lib/libc/stdlib/tfind.c b/lib/libc/stdlib/tfind.c
new file mode 100644
index 000000000000..afcbc16cd2d4
--- /dev/null
+++ b/lib/libc/stdlib/tfind.c
@@ -0,0 +1,48 @@
+/* $NetBSD: tfind.c,v 1.2 1999/09/16 11:45:37 lukem Exp $ */
+
+/*
+ * Tree search generalized from Knuth (6.2.2) Algorithm T just like
+ * the AT&T man page says.
+ *
+ * Written by reading the System V Interface Definition, not the code.
+ *
+ * Totally public domain.
+ */
+
+#include <sys/cdefs.h>
+#if 0
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: tfind.c,v 1.2 1999/09/16 11:45:37 lukem Exp $");
+#endif /* LIBC_SCCS and not lint */
+#endif
+__FBSDID("$FreeBSD$");
+
+#define _SEARCH_PRIVATE
+#include <stdlib.h>
+#include <search.h>
+
+/*
+ * find a node, or return 0
+ *
+ * vkey - key to be found
+ * vrootp - address of the tree root
+ */
+posix_tnode *
+tfind(const void *vkey, posix_tnode * const *rootp,
+ int (*compar)(const void *, const void *))
+{
+
+ if (rootp == NULL)
+ return NULL;
+
+ while (*rootp != NULL) { /* T1: */
+ int r;
+
+ if ((r = (*compar)(vkey, (*rootp)->key)) == 0) /* T2: */
+ return *rootp; /* key found */
+ rootp = (r < 0) ?
+ &(*rootp)->llink : /* T3: follow left branch */
+ &(*rootp)->rlink; /* T4: follow right branch */
+ }
+ return NULL;
+}
diff --git a/lib/libc/stdlib/tsearch.3 b/lib/libc/stdlib/tsearch.3
new file mode 100644
index 000000000000..493eff25deda
--- /dev/null
+++ b/lib/libc/stdlib/tsearch.3
@@ -0,0 +1,151 @@
+.\" $NetBSD$
+.\" Copyright (c) 1997 Todd C. Miller <Todd.Miller@courtesan.com>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+.\" AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+.\" THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+.\" EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+.\" PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+.\" OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+.\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" OpenBSD: tsearch.3,v 1.2 1998/06/21 22:13:49 millert Exp
+.\" $FreeBSD$
+.\"
+.Dd October 9, 2016
+.Dt TSEARCH 3
+.Os
+.Sh NAME
+.Nm tsearch , tfind , tdelete , twalk
+.Nd manipulate binary search trees
+.Sh SYNOPSIS
+.In search.h
+.Ft void *
+.Fn tdelete "const void * restrict key" "posix_tnode ** restrict rootp" "int (*compar) (const void *, const void *)"
+.Ft posix_tnode *
+.Fn tfind "const void *key" "posix_tnode * const *rootp" "int (*compar) (const void *, const void *)"
+.Ft posix_tnode *
+.Fn tsearch "const void *key" "posix_tnode **rootp" "int (*compar) (const void *, const void *)"
+.Ft void
+.Fn twalk "const posix_tnode *root" "void (*action) (const posix_tnode *, VISIT, int)"
+.Sh DESCRIPTION
+The
+.Fn tdelete ,
+.Fn tfind ,
+.Fn tsearch ,
+and
+.Fn twalk
+functions manage binary search trees.
+This implementation uses a balanced AVL tree,
+which due to its strong theoretical limit on the height of the tree has
+the advantage of calling the comparison function relatively
+infrequently.
+.Pp
+The comparison function passed in by
+the user has the same style of return values as
+.Xr strcmp 3 .
+.Pp
+The
+.Fn tfind
+function
+searches for the datum matched by the argument
+.Fa key
+in the binary tree rooted at
+.Fa rootp ,
+returning a pointer to the datum if it is found and NULL
+if it is not.
+.Pp
+The
+.Fn tsearch
+function
+is identical to
+.Fn tfind
+except that if no match is found,
+.Fa key
+is inserted into the tree and a pointer to it is returned.
+If
+.Fa rootp
+points to a NULL value a new binary search tree is created.
+.Pp
+The
+.Fn tdelete
+function
+deletes a node from the specified binary search tree and returns
+a pointer to the parent of the node to be deleted.
+It takes the same arguments as
+.Fn tfind
+and
+.Fn tsearch .
+If the node to be deleted is the root of the binary search tree,
+.Fa rootp
+will be adjusted.
+.Pp
+The
+.Fn twalk
+function
+walks the binary search tree rooted in
+.Fa root
+and calls the function
+.Fa action
+on each node.
+The
+.Fa action
+function
+is called with three arguments: a pointer to the current node,
+a value from the enum
+.Sy "typedef enum { preorder, postorder, endorder, leaf } VISIT;"
+specifying the traversal type, and a node level (where level
+zero is the root of the tree).
+.Sh RETURN VALUES
+The
+.Fn tsearch
+function returns NULL if allocation of a new node fails (usually
+due to a lack of free memory).
+.Pp
+The
+.Fn tfind ,
+.Fn tsearch ,
+and
+.Fn tdelete
+functions
+return NULL if
+.Fa rootp
+is NULL or the datum cannot be found.
+.Pp
+The
+.Fn twalk
+function returns no value.
+.Sh SEE ALSO
+.Xr bsearch 3 ,
+.Xr hsearch 3 ,
+.Xr lsearch 3
+.Sh STANDARDS
+These functions conform to
+.St -p1003.1-2008 .
+.Pp
+The
+.Fa posix_tnode
+type is not part of
+.St -p1003.1-2008 ,
+but is expected to be standardized by future versions of the standard.
+It is defined as
+.Fa void
+for source-level compatibility.
+Using
+.Fa posix_tnode
+makes distinguishing between nodes and keys easier.
diff --git a/lib/libc/stdlib/tsearch.c b/lib/libc/stdlib/tsearch.c
new file mode 100644
index 000000000000..a15c2c20517b
--- /dev/null
+++ b/lib/libc/stdlib/tsearch.c
@@ -0,0 +1,197 @@
+/*-
+ * Copyright (c) 2015 Nuxi, https://nuxi.nl/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#define _SEARCH_PRIVATE
+#include <search.h>
+#include <stdlib.h>
+
+#include "tsearch_path.h"
+
+posix_tnode *
+tsearch(const void *key, posix_tnode **rootp,
+ int (*compar)(const void *, const void *))
+{
+ struct path path;
+ posix_tnode **leaf, *result, *n, *x, *y, *z;
+ int cmp;
+
+ /* POSIX requires that tsearch() returns NULL if rootp is NULL. */
+ if (rootp == NULL)
+ return (NULL);
+
+ /*
+ * Find the leaf where the new key needs to be inserted. Return
+ * if we've found an existing entry. Keep track of the path that
+ * is taken to get to the node, as we will need it to adjust the
+ * balances.
+ */
+ path_init(&path);
+ leaf = rootp;
+ while (*leaf != NULL) {
+ if ((*leaf)->balance != 0) {
+ /*
+ * If we reach a node that has a non-zero
+ * balance on the way, we know that we won't
+ * need to perform any rotations above this
+ * point. In this case rotations are always
+ * capable of keeping the subtree in balance.
+ * Make this the root node and reset the path.
+ */
+ rootp = leaf;
+ path_init(&path);
+ }
+ cmp = compar(key, (*leaf)->key);
+ if (cmp < 0) {
+ path_taking_left(&path);
+ leaf = &(*leaf)->llink;
+ } else if (cmp > 0) {
+ path_taking_right(&path);
+ leaf = &(*leaf)->rlink;
+ } else {
+ return (*leaf);
+ }
+ }
+
+ /* Did not find a matching key in the tree. Insert a new node. */
+ result = *leaf = malloc(sizeof(**leaf));
+ if (result == NULL)
+ return (NULL);
+ result->key = (void *)key;
+ result->llink = NULL;
+ result->rlink = NULL;
+ result->balance = 0;
+
+ /*
+ * Walk along the same path a second time and adjust the
+ * balances. Except for the first node, all of these nodes must
+ * have a balance of zero, meaning that these nodes will not get
+ * out of balance.
+ */
+ for (n = *rootp; n != *leaf;) {
+ if (path_took_left(&path)) {
+ n->balance += 1;
+ n = n->llink;
+ } else {
+ n->balance -= 1;
+ n = n->rlink;
+ }
+ }
+
+ /*
+ * Adjusting the balances may have pushed the balance of the
+ * root node out of range. Perform a rotation to bring the
+ * balance back in range.
+ */
+ x = *rootp;
+ if (x->balance > 1) {
+ y = x->llink;
+ if (y->balance < 0) {
+ /*
+ * Left-right case.
+ *
+ * x
+ * / \ z
+ * y D / \
+ * / \ --> y x
+ * A z /| |\
+ * / \ A B C D
+ * B C
+ */
+ z = y->rlink;
+ y->rlink = z->llink;
+ z->llink = y;
+ x->llink = z->rlink;
+ z->rlink = x;
+ *rootp = z;
+
+ x->balance = z->balance > 0 ? -1 : 0;
+ y->balance = z->balance < 0 ? 1 : 0;
+ z->balance = 0;
+ } else {
+ /*
+ * Left-left case.
+ *
+ * x y
+ * / \ / \
+ * y C --> A x
+ * / \ / \
+ * A B B C
+ */
+ x->llink = y->rlink;
+ y->rlink = x;
+ *rootp = y;
+
+ x->balance = 0;
+ y->balance = 0;
+ }
+ } else if (x->balance < -1) {
+ y = x->rlink;
+ if (y->balance > 0) {
+ /*
+ * Right-left case.
+ *
+ * x
+ * / \ z
+ * A y / \
+ * / \ --> x y
+ * z D /| |\
+ * / \ A B C D
+ * B C
+ */
+ posix_tnode *z = y->llink;
+ x->rlink = z->llink;
+ z->llink = x;
+ y->llink = z->rlink;
+ z->rlink = y;
+ *rootp = z;
+
+ x->balance = z->balance < 0 ? 1 : 0;
+ y->balance = z->balance > 0 ? -1 : 0;
+ z->balance = 0;
+ } else {
+ /*
+ * Right-right case.
+ *
+ * x y
+ * / \ / \
+ * A y --> x C
+ * / \ / \
+ * B C A B
+ */
+ x->rlink = y->llink;
+ y->llink = x;
+ *rootp = y;
+
+ x->balance = 0;
+ y->balance = 0;
+ }
+ }
+
+ /* Return the new entry. */
+ return (result);
+}
diff --git a/lib/libc/stdlib/tsearch_path.h b/lib/libc/stdlib/tsearch_path.h
new file mode 100644
index 000000000000..934c91f73f56
--- /dev/null
+++ b/lib/libc/stdlib/tsearch_path.h
@@ -0,0 +1,97 @@
+/*-
+ * Copyright (c) 2015 Nuxi, https://nuxi.nl/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef TSEARCH_PATH_H
+#define TSEARCH_PATH_H
+
+#include <limits.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+/*
+ * Bookkeeping for storing a path in a balanced binary search tree from
+ * the root to a leaf node.
+ *
+ * For an AVL tree we know that its maximum height of a tree is bounded
+ * by approximately 1.44 * log2(n) - 0.328. Given that the number of
+ * entries of the tree is constrained by the size of the address space,
+ * two uintptr_t's provide sufficient space to store the path from the
+ * root to any leaf.
+ */
+struct path {
+ uintptr_t steps[2];
+ unsigned int nsteps;
+};
+
+/* Initializes the path structure with a zero-length path. */
+static inline void
+path_init(struct path *p)
+{
+
+ p->nsteps = 0;
+}
+
+#define STEPS_BIT (sizeof(uintptr_t) * CHAR_BIT)
+
+/* Pushes a step to the left to the end of the path. */
+static inline void
+path_taking_left(struct path *p)
+{
+
+ p->steps[p->nsteps / STEPS_BIT] |=
+ (uintptr_t)1 << (p->nsteps % STEPS_BIT);
+ ++p->nsteps;
+}
+
+/* Pushes a step to the right to the end of the path. */
+static inline void
+path_taking_right(struct path *p)
+{
+
+ p->steps[p->nsteps / STEPS_BIT] &=
+ ~((uintptr_t)1 << (p->nsteps % STEPS_BIT));
+ ++p->nsteps;
+}
+
+/*
+ * Pops the first step from the path and returns whether it was a step
+ * to the left.
+ */
+static inline bool
+path_took_left(struct path *p)
+{
+ bool result;
+
+ result = p->steps[0] & 0x1;
+ p->steps[0] = (p->steps[0] >> 1) | (p->steps[1] << (STEPS_BIT - 1));
+ p->steps[1] >>= 1;
+ return (result);
+}
+
+#undef STEPS_BIT
+
+#endif
diff --git a/lib/libc/stdlib/twalk.c b/lib/libc/stdlib/twalk.c
new file mode 100644
index 000000000000..4f999b4c0a48
--- /dev/null
+++ b/lib/libc/stdlib/twalk.c
@@ -0,0 +1,50 @@
+/* $NetBSD: twalk.c,v 1.4 2012/03/20 16:38:45 matt Exp $ */
+
+/*
+ * Tree search generalized from Knuth (6.2.2) Algorithm T just like
+ * the AT&T man page says.
+ *
+ * Written by reading the System V Interface Definition, not the code.
+ *
+ * Totally public domain.
+ */
+
+#include <sys/cdefs.h>
+#if 0
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: twalk.c,v 1.4 2012/03/20 16:38:45 matt Exp $");
+#endif /* LIBC_SCCS and not lint */
+#endif
+__FBSDID("$FreeBSD$");
+
+#define _SEARCH_PRIVATE
+#include <search.h>
+#include <stdlib.h>
+
+typedef void (*cmp_fn_t)(const posix_tnode *, VISIT, int);
+
+/* Walk the nodes of a tree */
+static void
+trecurse(const posix_tnode *root, cmp_fn_t action, int level)
+{
+
+ if (root->llink == NULL && root->rlink == NULL)
+ (*action)(root, leaf, level);
+ else {
+ (*action)(root, preorder, level);
+ if (root->llink != NULL)
+ trecurse(root->llink, action, level + 1);
+ (*action)(root, postorder, level);
+ if (root->rlink != NULL)
+ trecurse(root->rlink, action, level + 1);
+ (*action)(root, endorder, level);
+ }
+}
+
+/* Walk the nodes of a tree */
+void
+twalk(const posix_tnode *vroot, cmp_fn_t action)
+{
+ if (vroot != NULL && action != NULL)
+ trecurse(vroot, action, 0);
+}
diff --git a/lib/libc/stdtime/Makefile.inc b/lib/libc/stdtime/Makefile.inc
new file mode 100644
index 000000000000..fb0d2b934148
--- /dev/null
+++ b/lib/libc/stdtime/Makefile.inc
@@ -0,0 +1,24 @@
+# Makefile.inc,v 1.2 1994/09/13 21:26:01 wollman Exp
+# $FreeBSD$
+
+.PATH: ${LIBC_SRCTOP}/stdtime ${SRCTOP}/contrib/tzcode/stdtime
+
+SRCS+= asctime.c difftime.c localtime.c strftime.c strptime.c timelocal.c \
+ time32.c
+
+SYM_MAPS+= ${LIBC_SRCTOP}/stdtime/Symbol.map
+
+CFLAGS+= -I${SRCTOP}/contrib/tzcode/stdtime -I${LIBC_SRCTOP}/stdtime
+
+CFLAGS.localtime.c= -fwrapv
+
+MAN+= ctime.3 strftime.3 strptime.3 time2posix.3
+MAN+= tzfile.5
+
+MLINKS+=ctime.3 asctime.3 ctime.3 difftime.3 ctime.3 gmtime.3 \
+ ctime.3 localtime.3 ctime.3 mktime.3 ctime.3 timegm.3 \
+ ctime.3 ctime_r.3 ctime.3 localtime_r.3 ctime.3 gmtime_r.3 \
+ ctime.3 asctime_r.3
+MLINKS+=strftime.3 strftime_l.3
+MLINKS+=strptime.3 strptime_l.3
+MLINKS+=time2posix.3 posix2time.3
diff --git a/lib/libc/stdtime/Symbol.map b/lib/libc/stdtime/Symbol.map
new file mode 100644
index 000000000000..3bee3735f7e6
--- /dev/null
+++ b/lib/libc/stdtime/Symbol.map
@@ -0,0 +1,35 @@
+/*
+ * $FreeBSD$
+ */
+
+FBSD_1.0 {
+ _time32_to_time;
+ _time_to_time32;
+ _time64_to_time;
+ _time_to_time64;
+ _time_to_long;
+ _long_to_time;
+ _time_to_int;
+ _int_to_time;
+ strptime;
+ strftime;
+ tzname;
+ tzsetwall;
+ tzset;
+ localtime;
+ localtime_r;
+ gmtime;
+ gmtime_r;
+ offtime;
+ ctime;
+ ctime_r;
+ mktime;
+ timelocal;
+ timegm;
+ timeoff;
+ time2posix;
+ posix2time;
+ difftime;
+ asctime_r;
+ asctime;
+};
diff --git a/lib/libc/stdtime/strftime.3 b/lib/libc/stdtime/strftime.3
new file mode 100644
index 000000000000..5847a6b7267d
--- /dev/null
+++ b/lib/libc/stdtime/strftime.3
@@ -0,0 +1,289 @@
+.\" Copyright (c) 1989, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)strftime.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 25, 2012
+.Dt STRFTIME 3
+.Os
+.Sh NAME
+.Nm strftime
+.Nd format date and time
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In time.h
+.Ft size_t
+.Fo strftime
+.Fa "char * restrict buf"
+.Fa "size_t maxsize"
+.Fa "const char * restrict format"
+.Fa "const struct tm * restrict timeptr"
+.Fc
+.Ft size_t
+.Fn strftime_l "char *restrict buf" "size_t maxsize" "const char * restrict format" "const struct tm *restrict timeptr" "locale_t loc"
+.Sh DESCRIPTION
+The
+.Fn strftime
+function formats the information from
+.Fa timeptr
+into the buffer
+.Fa buf
+according to the string pointed to by
+.Fa format .
+The function
+.Fn strftime_l
+does the same as
+.Fn strftime
+but takes an explicit locale rather than using the current locale.
+.Pp
+The
+.Fa format
+string consists of zero or more conversion specifications and
+ordinary characters.
+All ordinary characters are copied directly into the buffer.
+A conversion specification consists of a percent sign
+.Dq Ql %
+and one other character.
+.Pp
+No more than
+.Fa maxsize
+characters will be placed into the array.
+If the total number of resulting characters, including the terminating
+NUL character, is not more than
+.Fa maxsize ,
+.Fn strftime
+returns the number of characters in the array, not counting the
+terminating NUL.
+Otherwise, zero is returned and the buffer contents are indeterminate.
+.Pp
+The conversion specifications are copied to the buffer after expansion
+as follows:-
+.Bl -tag -width "xxxx"
+.It Cm \&%A
+is replaced by national representation of the full weekday name.
+.It Cm %a
+is replaced by national representation of
+the abbreviated weekday name.
+.It Cm \&%B
+is replaced by national representation of the full month name.
+.It Cm %b
+is replaced by national representation of
+the abbreviated month name.
+.It Cm \&%C
+is replaced by (year / 100) as decimal number; single
+digits are preceded by a zero.
+.It Cm %c
+is replaced by national representation of time and date.
+.It Cm \&%D
+is equivalent to
+.Dq Li %m/%d/%y .
+.It Cm %d
+is replaced by the day of the month as a decimal number (01-31).
+.It Cm %E* %O*
+POSIX locale extensions.
+The sequences
+%Ec %EC %Ex %EX %Ey %EY
+%Od %Oe %OH %OI %Om %OM
+%OS %Ou %OU %OV %Ow %OW %Oy
+are supposed to provide alternate
+representations.
+.Pp
+Additionally %OB implemented
+to represent alternative months names
+(used standalone, without day mentioned).
+.It Cm %e
+is replaced by the day of the month as a decimal number (1-31); single
+digits are preceded by a blank.
+.It Cm \&%F
+is equivalent to
+.Dq Li %Y-%m-%d .
+.It Cm \&%G
+is replaced by a year as a decimal number with century.
+This year is the one that contains the greater part of
+the week (Monday as the first day of the week).
+.It Cm %g
+is replaced by the same year as in
+.Dq Li %G ,
+but as a decimal number without century (00-99).
+.It Cm \&%H
+is replaced by the hour (24-hour clock) as a decimal number (00-23).
+.It Cm %h
+the same as
+.Cm %b .
+.It Cm \&%I
+is replaced by the hour (12-hour clock) as a decimal number (01-12).
+.It Cm %j
+is replaced by the day of the year as a decimal number (001-366).
+.It Cm %k
+is replaced by the hour (24-hour clock) as a decimal number (0-23);
+single digits are preceded by a blank.
+.It Cm %l
+is replaced by the hour (12-hour clock) as a decimal number (1-12);
+single digits are preceded by a blank.
+.It Cm \&%M
+is replaced by the minute as a decimal number (00-59).
+.It Cm %m
+is replaced by the month as a decimal number (01-12).
+.It Cm %n
+is replaced by a newline.
+.It Cm %O*
+the same as
+.Cm %E* .
+.It Cm %p
+is replaced by national representation of either
+"ante meridiem" (a.m.)
+or
+"post meridiem" (p.m.)
+as appropriate.
+.It Cm \&%R
+is equivalent to
+.Dq Li %H:%M .
+.It Cm %r
+is equivalent to
+.Dq Li %I:%M:%S %p .
+.It Cm \&%S
+is replaced by the second as a decimal number (00-60).
+.It Cm %s
+is replaced by the number of seconds since the Epoch, UTC (see
+.Xr mktime 3 ) .
+.It Cm \&%T
+is equivalent to
+.Dq Li %H:%M:%S .
+.It Cm %t
+is replaced by a tab.
+.It Cm \&%U
+is replaced by the week number of the year (Sunday as the first day of
+the week) as a decimal number (00-53).
+.It Cm %u
+is replaced by the weekday (Monday as the first day of the week)
+as a decimal number (1-7).
+.It Cm \&%V
+is replaced by the week number of the year (Monday as the first day of
+the week) as a decimal number (01-53).
+If the week containing January
+1 has four or more days in the new year, then it is week 1; otherwise
+it is the last week of the previous year, and the next week is week 1.
+.It Cm %v
+is equivalent to
+.Dq Li %e-%b-%Y .
+.It Cm \&%W
+is replaced by the week number of the year (Monday as the first day of
+the week) as a decimal number (00-53).
+.It Cm %w
+is replaced by the weekday (Sunday as the first day of the week)
+as a decimal number (0-6).
+.It Cm \&%X
+is replaced by national representation of the time.
+.It Cm %x
+is replaced by national representation of the date.
+.It Cm \&%Y
+is replaced by the year with century as a decimal number.
+.It Cm %y
+is replaced by the year without century as a decimal number (00-99).
+.It Cm \&%Z
+is replaced by the time zone name.
+.It Cm %z
+is replaced by the time zone offset from UTC; a leading plus sign stands for
+east of UTC, a minus sign for west of UTC, hours and minutes follow
+with two digits each and no delimiter between them (common form for
+RFC 822 date headers).
+.It Cm %+
+is replaced by national representation of the date and time
+(the format is similar to that produced by
+.Xr date 1 ) .
+.It Cm %-*
+GNU libc extension.
+Do not do any padding when performing numerical outputs.
+.It Cm %_*
+GNU libc extension.
+Explicitly specify space for padding.
+.It Cm %0*
+GNU libc extension.
+Explicitly specify zero for padding.
+.It Cm %%
+is replaced by
+.Ql % .
+.El
+.Sh SEE ALSO
+.Xr date 1 ,
+.Xr printf 1 ,
+.Xr ctime 3 ,
+.Xr printf 3 ,
+.Xr strptime 3 ,
+.Xr wcsftime 3
+.Sh STANDARDS
+The
+.Fn strftime
+function
+conforms to
+.St -isoC
+with a lot of extensions including
+.Ql \&%C ,
+.Ql \&%D ,
+.Ql %E* ,
+.Ql %e ,
+.Ql %G ,
+.Ql %g ,
+.Ql %h ,
+.Ql %k ,
+.Ql %l ,
+.Ql %n ,
+.Ql %O* ,
+.Ql \&%R ,
+.Ql %r ,
+.Ql %s ,
+.Ql \&%T ,
+.Ql %t ,
+.Ql %u ,
+.Ql \&%V ,
+.Ql %z ,
+.Ql %+ .
+.Pp
+The peculiar week number and year in the replacements of
+.Ql %G ,
+.Ql %g
+and
+.Ql \&%V
+are defined in ISO 8601: 1988.
+The
+.Fn strftime_l
+function conforms to
+.St -p1003.1-2008 .
+.Sh BUGS
+There is no conversion specification for the phase of the moon.
+.Pp
+The
+.Fn strftime
+function does not correctly handle multibyte characters in the
+.Fa format
+argument.
diff --git a/lib/libc/stdtime/strftime.c b/lib/libc/stdtime/strftime.c
new file mode 100644
index 000000000000..838ebdde3e5b
--- /dev/null
+++ b/lib/libc/stdtime/strftime.c
@@ -0,0 +1,642 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+#ifndef NOID
+static const char elsieid[] = "@(#)strftime.3 8.3";
+/*
+ * Based on the UCB version with the ID appearing below.
+ * This is ANSIish only when "multibyte character == plain character".
+ */
+#endif /* !defined NOID */
+#endif /* !defined lint */
+
+#include "namespace.h"
+#include "private.h"
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)strftime.c 5.4 (Berkeley) 3/14/89";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "tzfile.h"
+#include <fcntl.h>
+#include <sys/stat.h>
+#include "un-namespace.h"
+#include "timelocal.h"
+
+static char * _add(const char *, char *, const char *);
+static char * _conv(int, const char *, char *, const char *, locale_t);
+static char * _fmt(const char *, const struct tm *, char *, const char *,
+ int *, locale_t);
+static char * _yconv(int, int, int, int, char *, const char *, locale_t);
+
+extern char * tzname[];
+
+#ifndef YEAR_2000_NAME
+#define YEAR_2000_NAME "CHECK_STRFTIME_FORMATS_FOR_TWO_DIGIT_YEARS"
+#endif /* !defined YEAR_2000_NAME */
+
+#define IN_NONE 0
+#define IN_SOME 1
+#define IN_THIS 2
+#define IN_ALL 3
+
+#define PAD_DEFAULT 0
+#define PAD_LESS 1
+#define PAD_SPACE 2
+#define PAD_ZERO 3
+
+static const char fmt_padding[][4][5] = {
+ /* DEFAULT, LESS, SPACE, ZERO */
+#define PAD_FMT_MONTHDAY 0
+#define PAD_FMT_HMS 0
+#define PAD_FMT_CENTURY 0
+#define PAD_FMT_SHORTYEAR 0
+#define PAD_FMT_MONTH 0
+#define PAD_FMT_WEEKOFYEAR 0
+#define PAD_FMT_DAYOFMONTH 0
+ { "%02d", "%d", "%2d", "%02d" },
+#define PAD_FMT_SDAYOFMONTH 1
+#define PAD_FMT_SHMS 1
+ { "%2d", "%d", "%2d", "%02d" },
+#define PAD_FMT_DAYOFYEAR 2
+ { "%03d", "%d", "%3d", "%03d" },
+#define PAD_FMT_YEAR 3
+ { "%04d", "%d", "%4d", "%04d" }
+};
+
+size_t
+strftime_l(char * __restrict s, size_t maxsize, const char * __restrict format,
+ const struct tm * __restrict t, locale_t loc)
+{
+ char * p;
+ int warn;
+ FIX_LOCALE(loc);
+
+ tzset();
+ warn = IN_NONE;
+ p = _fmt(((format == NULL) ? "%c" : format), t, s, s + maxsize, &warn, loc);
+#ifndef NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU
+ if (warn != IN_NONE && getenv(YEAR_2000_NAME) != NULL) {
+ (void) fprintf_l(stderr, loc, "\n");
+ if (format == NULL)
+ (void) fputs("NULL strftime format ", stderr);
+ else (void) fprintf_l(stderr, loc, "strftime format \"%s\" ",
+ format);
+ (void) fputs("yields only two digits of years in ", stderr);
+ if (warn == IN_SOME)
+ (void) fputs("some locales", stderr);
+ else if (warn == IN_THIS)
+ (void) fputs("the current locale", stderr);
+ else (void) fputs("all locales", stderr);
+ (void) fputs("\n", stderr);
+ }
+#endif /* !defined NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU */
+ if (p == s + maxsize)
+ return (0);
+ *p = '\0';
+ return p - s;
+}
+
+size_t
+strftime(char * __restrict s, size_t maxsize, const char * __restrict format,
+ const struct tm * __restrict t)
+{
+ return strftime_l(s, maxsize, format, t, __get_locale());
+}
+
+static char *
+_fmt(const char *format, const struct tm * const t, char *pt,
+ const char * const ptlim, int *warnp, locale_t loc)
+{
+ int Ealternative, Oalternative, PadIndex;
+ struct lc_time_T *tptr = __get_current_time_locale(loc);
+
+ for ( ; *format; ++format) {
+ if (*format == '%') {
+ Ealternative = 0;
+ Oalternative = 0;
+ PadIndex = PAD_DEFAULT;
+label:
+ switch (*++format) {
+ case '\0':
+ --format;
+ break;
+ case 'A':
+ pt = _add((t->tm_wday < 0 ||
+ t->tm_wday >= DAYSPERWEEK) ?
+ "?" : tptr->weekday[t->tm_wday],
+ pt, ptlim);
+ continue;
+ case 'a':
+ pt = _add((t->tm_wday < 0 ||
+ t->tm_wday >= DAYSPERWEEK) ?
+ "?" : tptr->wday[t->tm_wday],
+ pt, ptlim);
+ continue;
+ case 'B':
+ pt = _add((t->tm_mon < 0 ||
+ t->tm_mon >= MONSPERYEAR) ?
+ "?" : (Oalternative ? tptr->alt_month :
+ tptr->month)[t->tm_mon],
+ pt, ptlim);
+ continue;
+ case 'b':
+ case 'h':
+ pt = _add((t->tm_mon < 0 ||
+ t->tm_mon >= MONSPERYEAR) ?
+ "?" : tptr->mon[t->tm_mon],
+ pt, ptlim);
+ continue;
+ case 'C':
+ /*
+ * %C used to do a...
+ * _fmt("%a %b %e %X %Y", t);
+ * ...whereas now POSIX 1003.2 calls for
+ * something completely different.
+ * (ado, 1993-05-24)
+ */
+ pt = _yconv(t->tm_year, TM_YEAR_BASE, 1, 0,
+ pt, ptlim, loc);
+ continue;
+ case 'c':
+ {
+ int warn2 = IN_SOME;
+
+ pt = _fmt(tptr->c_fmt, t, pt, ptlim, &warn2, loc);
+ if (warn2 == IN_ALL)
+ warn2 = IN_THIS;
+ if (warn2 > *warnp)
+ *warnp = warn2;
+ }
+ continue;
+ case 'D':
+ pt = _fmt("%m/%d/%y", t, pt, ptlim, warnp, loc);
+ continue;
+ case 'd':
+ pt = _conv(t->tm_mday,
+ fmt_padding[PAD_FMT_DAYOFMONTH][PadIndex],
+ pt, ptlim, loc);
+ continue;
+ case 'E':
+ if (Ealternative || Oalternative)
+ break;
+ Ealternative++;
+ goto label;
+ case 'O':
+ /*
+ * C99 locale modifiers.
+ * The sequences
+ * %Ec %EC %Ex %EX %Ey %EY
+ * %Od %oe %OH %OI %Om %OM
+ * %OS %Ou %OU %OV %Ow %OW %Oy
+ * are supposed to provide alternate
+ * representations.
+ *
+ * FreeBSD extension
+ * %OB
+ */
+ if (Ealternative || Oalternative)
+ break;
+ Oalternative++;
+ goto label;
+ case 'e':
+ pt = _conv(t->tm_mday,
+ fmt_padding[PAD_FMT_SDAYOFMONTH][PadIndex],
+ pt, ptlim, loc);
+ continue;
+ case 'F':
+ pt = _fmt("%Y-%m-%d", t, pt, ptlim, warnp, loc);
+ continue;
+ case 'H':
+ pt = _conv(t->tm_hour, fmt_padding[PAD_FMT_HMS][PadIndex],
+ pt, ptlim, loc);
+ continue;
+ case 'I':
+ pt = _conv((t->tm_hour % 12) ?
+ (t->tm_hour % 12) : 12,
+ fmt_padding[PAD_FMT_HMS][PadIndex],
+ pt, ptlim, loc);
+ continue;
+ case 'j':
+ pt = _conv(t->tm_yday + 1,
+ fmt_padding[PAD_FMT_DAYOFYEAR][PadIndex],
+ pt, ptlim, loc);
+ continue;
+ case 'k':
+ /*
+ * This used to be...
+ * _conv(t->tm_hour % 12 ?
+ * t->tm_hour % 12 : 12, 2, ' ');
+ * ...and has been changed to the below to
+ * match SunOS 4.1.1 and Arnold Robbins'
+ * strftime version 3.0. That is, "%k" and
+ * "%l" have been swapped.
+ * (ado, 1993-05-24)
+ */
+ pt = _conv(t->tm_hour, fmt_padding[PAD_FMT_SHMS][PadIndex],
+ pt, ptlim, loc);
+ continue;
+#ifdef KITCHEN_SINK
+ case 'K':
+ /*
+ ** After all this time, still unclaimed!
+ */
+ pt = _add("kitchen sink", pt, ptlim);
+ continue;
+#endif /* defined KITCHEN_SINK */
+ case 'l':
+ /*
+ * This used to be...
+ * _conv(t->tm_hour, 2, ' ');
+ * ...and has been changed to the below to
+ * match SunOS 4.1.1 and Arnold Robbin's
+ * strftime version 3.0. That is, "%k" and
+ * "%l" have been swapped.
+ * (ado, 1993-05-24)
+ */
+ pt = _conv((t->tm_hour % 12) ?
+ (t->tm_hour % 12) : 12,
+ fmt_padding[PAD_FMT_SHMS][PadIndex],
+ pt, ptlim, loc);
+ continue;
+ case 'M':
+ pt = _conv(t->tm_min, fmt_padding[PAD_FMT_HMS][PadIndex],
+ pt, ptlim, loc);
+ continue;
+ case 'm':
+ pt = _conv(t->tm_mon + 1,
+ fmt_padding[PAD_FMT_MONTH][PadIndex],
+ pt, ptlim, loc);
+ continue;
+ case 'n':
+ pt = _add("\n", pt, ptlim);
+ continue;
+ case 'p':
+ pt = _add((t->tm_hour >= (HOURSPERDAY / 2)) ?
+ tptr->pm : tptr->am,
+ pt, ptlim);
+ continue;
+ case 'R':
+ pt = _fmt("%H:%M", t, pt, ptlim, warnp, loc);
+ continue;
+ case 'r':
+ pt = _fmt(tptr->ampm_fmt, t, pt, ptlim,
+ warnp, loc);
+ continue;
+ case 'S':
+ pt = _conv(t->tm_sec, fmt_padding[PAD_FMT_HMS][PadIndex],
+ pt, ptlim, loc);
+ continue;
+ case 's':
+ {
+ struct tm tm;
+ char buf[INT_STRLEN_MAXIMUM(
+ time_t) + 1];
+ time_t mkt;
+
+ tm = *t;
+ mkt = mktime(&tm);
+ if (TYPE_SIGNED(time_t))
+ (void) sprintf_l(buf, loc, "%ld",
+ (long) mkt);
+ else (void) sprintf_l(buf, loc, "%lu",
+ (unsigned long) mkt);
+ pt = _add(buf, pt, ptlim);
+ }
+ continue;
+ case 'T':
+ pt = _fmt("%H:%M:%S", t, pt, ptlim, warnp, loc);
+ continue;
+ case 't':
+ pt = _add("\t", pt, ptlim);
+ continue;
+ case 'U':
+ pt = _conv((t->tm_yday + DAYSPERWEEK -
+ t->tm_wday) / DAYSPERWEEK,
+ fmt_padding[PAD_FMT_WEEKOFYEAR][PadIndex],
+ pt, ptlim, loc);
+ continue;
+ case 'u':
+ /*
+ * From Arnold Robbins' strftime version 3.0:
+ * "ISO 8601: Weekday as a decimal number
+ * [1 (Monday) - 7]"
+ * (ado, 1993-05-24)
+ */
+ pt = _conv((t->tm_wday == 0) ?
+ DAYSPERWEEK : t->tm_wday,
+ "%d", pt, ptlim, loc);
+ continue;
+ case 'V': /* ISO 8601 week number */
+ case 'G': /* ISO 8601 year (four digits) */
+ case 'g': /* ISO 8601 year (two digits) */
+/*
+ * From Arnold Robbins' strftime version 3.0: "the week number of the
+ * year (the first Monday as the first day of week 1) as a decimal number
+ * (01-53)."
+ * (ado, 1993-05-24)
+ *
+ * From "http://www.ft.uni-erlangen.de/~mskuhn/iso-time.html" by Markus Kuhn:
+ * "Week 01 of a year is per definition the first week which has the
+ * Thursday in this year, which is equivalent to the week which contains
+ * the fourth day of January. In other words, the first week of a new year
+ * is the week which has the majority of its days in the new year. Week 01
+ * might also contain days from the previous year and the week before week
+ * 01 of a year is the last week (52 or 53) of the previous year even if
+ * it contains days from the new year. A week starts with Monday (day 1)
+ * and ends with Sunday (day 7). For example, the first week of the year
+ * 1997 lasts from 1996-12-30 to 1997-01-05..."
+ * (ado, 1996-01-02)
+ */
+ {
+ int year;
+ int base;
+ int yday;
+ int wday;
+ int w;
+
+ year = t->tm_year;
+ base = TM_YEAR_BASE;
+ yday = t->tm_yday;
+ wday = t->tm_wday;
+ for ( ; ; ) {
+ int len;
+ int bot;
+ int top;
+
+ len = isleap_sum(year, base) ?
+ DAYSPERLYEAR :
+ DAYSPERNYEAR;
+ /*
+ * What yday (-3 ... 3) does
+ * the ISO year begin on?
+ */
+ bot = ((yday + 11 - wday) %
+ DAYSPERWEEK) - 3;
+ /*
+ * What yday does the NEXT
+ * ISO year begin on?
+ */
+ top = bot -
+ (len % DAYSPERWEEK);
+ if (top < -3)
+ top += DAYSPERWEEK;
+ top += len;
+ if (yday >= top) {
+ ++base;
+ w = 1;
+ break;
+ }
+ if (yday >= bot) {
+ w = 1 + ((yday - bot) /
+ DAYSPERWEEK);
+ break;
+ }
+ --base;
+ yday += isleap_sum(year, base) ?
+ DAYSPERLYEAR :
+ DAYSPERNYEAR;
+ }
+#ifdef XPG4_1994_04_09
+ if ((w == 52 &&
+ t->tm_mon == TM_JANUARY) ||
+ (w == 1 &&
+ t->tm_mon == TM_DECEMBER))
+ w = 53;
+#endif /* defined XPG4_1994_04_09 */
+ if (*format == 'V')
+ pt = _conv(w, fmt_padding[PAD_FMT_WEEKOFYEAR][PadIndex],
+ pt, ptlim, loc);
+ else if (*format == 'g') {
+ *warnp = IN_ALL;
+ pt = _yconv(year, base, 0, 1,
+ pt, ptlim, loc);
+ } else pt = _yconv(year, base, 1, 1,
+ pt, ptlim, loc);
+ }
+ continue;
+ case 'v':
+ /*
+ * From Arnold Robbins' strftime version 3.0:
+ * "date as dd-bbb-YYYY"
+ * (ado, 1993-05-24)
+ */
+ pt = _fmt("%e-%b-%Y", t, pt, ptlim, warnp, loc);
+ continue;
+ case 'W':
+ pt = _conv((t->tm_yday + DAYSPERWEEK -
+ (t->tm_wday ?
+ (t->tm_wday - 1) :
+ (DAYSPERWEEK - 1))) / DAYSPERWEEK,
+ fmt_padding[PAD_FMT_WEEKOFYEAR][PadIndex],
+ pt, ptlim, loc);
+ continue;
+ case 'w':
+ pt = _conv(t->tm_wday, "%d", pt, ptlim, loc);
+ continue;
+ case 'X':
+ pt = _fmt(tptr->X_fmt, t, pt, ptlim, warnp, loc);
+ continue;
+ case 'x':
+ {
+ int warn2 = IN_SOME;
+
+ pt = _fmt(tptr->x_fmt, t, pt, ptlim, &warn2, loc);
+ if (warn2 == IN_ALL)
+ warn2 = IN_THIS;
+ if (warn2 > *warnp)
+ *warnp = warn2;
+ }
+ continue;
+ case 'y':
+ *warnp = IN_ALL;
+ pt = _yconv(t->tm_year, TM_YEAR_BASE, 0, 1,
+ pt, ptlim, loc);
+ continue;
+ case 'Y':
+ pt = _yconv(t->tm_year, TM_YEAR_BASE, 1, 1,
+ pt, ptlim, loc);
+ continue;
+ case 'Z':
+#ifdef TM_ZONE
+ if (t->TM_ZONE != NULL)
+ pt = _add(t->TM_ZONE, pt, ptlim);
+ else
+#endif /* defined TM_ZONE */
+ if (t->tm_isdst >= 0)
+ pt = _add(tzname[t->tm_isdst != 0],
+ pt, ptlim);
+ /*
+ * C99 says that %Z must be replaced by the
+ * empty string if the time zone is not
+ * determinable.
+ */
+ continue;
+ case 'z':
+ {
+ int diff;
+ char const * sign;
+
+ if (t->tm_isdst < 0)
+ continue;
+#ifdef TM_GMTOFF
+ diff = t->TM_GMTOFF;
+#else /* !defined TM_GMTOFF */
+ /*
+ * C99 says that the UTC offset must
+ * be computed by looking only at
+ * tm_isdst. This requirement is
+ * incorrect, since it means the code
+ * must rely on magic (in this case
+ * altzone and timezone), and the
+ * magic might not have the correct
+ * offset. Doing things correctly is
+ * tricky and requires disobeying C99;
+ * see GNU C strftime for details.
+ * For now, punt and conform to the
+ * standard, even though it's incorrect.
+ *
+ * C99 says that %z must be replaced by the
+ * empty string if the time zone is not
+ * determinable, so output nothing if the
+ * appropriate variables are not available.
+ */
+ if (t->tm_isdst == 0)
+#ifdef USG_COMPAT
+ diff = -timezone;
+#else /* !defined USG_COMPAT */
+ continue;
+#endif /* !defined USG_COMPAT */
+ else
+#ifdef ALTZONE
+ diff = -altzone;
+#else /* !defined ALTZONE */
+ continue;
+#endif /* !defined ALTZONE */
+#endif /* !defined TM_GMTOFF */
+ if (diff < 0) {
+ sign = "-";
+ diff = -diff;
+ } else
+ sign = "+";
+ pt = _add(sign, pt, ptlim);
+ diff /= SECSPERMIN;
+ diff = (diff / MINSPERHOUR) * 100 +
+ (diff % MINSPERHOUR);
+ pt = _conv(diff,
+ fmt_padding[PAD_FMT_YEAR][PadIndex],
+ pt, ptlim, loc);
+ }
+ continue;
+ case '+':
+ pt = _fmt(tptr->date_fmt, t, pt, ptlim,
+ warnp, loc);
+ continue;
+ case '-':
+ if (PadIndex != PAD_DEFAULT)
+ break;
+ PadIndex = PAD_LESS;
+ goto label;
+ case '_':
+ if (PadIndex != PAD_DEFAULT)
+ break;
+ PadIndex = PAD_SPACE;
+ goto label;
+ case '0':
+ if (PadIndex != PAD_DEFAULT)
+ break;
+ PadIndex = PAD_ZERO;
+ goto label;
+ case '%':
+ /*
+ * X311J/88-090 (4.12.3.5): if conversion char is
+ * undefined, behavior is undefined. Print out the
+ * character itself as printf(3) also does.
+ */
+ default:
+ break;
+ }
+ }
+ if (pt == ptlim)
+ break;
+ *pt++ = *format;
+ }
+ return (pt);
+}
+
+static char *
+_conv(const int n, const char * const format, char * const pt,
+ const char * const ptlim, locale_t loc)
+{
+ char buf[INT_STRLEN_MAXIMUM(int) + 1];
+
+ (void) sprintf_l(buf, loc, format, n);
+ return _add(buf, pt, ptlim);
+}
+
+static char *
+_add(const char *str, char *pt, const char * const ptlim)
+{
+ while (pt < ptlim && (*pt = *str++) != '\0')
+ ++pt;
+ return (pt);
+}
+
+/*
+ * POSIX and the C Standard are unclear or inconsistent about
+ * what %C and %y do if the year is negative or exceeds 9999.
+ * Use the convention that %C concatenated with %y yields the
+ * same output as %Y, and that %Y contains at least 4 bytes,
+ * with more only if necessary.
+ */
+
+static char *
+_yconv(const int a, const int b, const int convert_top, const int convert_yy,
+ char *pt, const char * const ptlim, locale_t loc)
+{
+ register int lead;
+ register int trail;
+
+#define DIVISOR 100
+ trail = a % DIVISOR + b % DIVISOR;
+ lead = a / DIVISOR + b / DIVISOR + trail / DIVISOR;
+ trail %= DIVISOR;
+ if (trail < 0 && lead > 0) {
+ trail += DIVISOR;
+ --lead;
+ } else if (lead < 0 && trail > 0) {
+ trail -= DIVISOR;
+ ++lead;
+ }
+ if (convert_top) {
+ if (lead == 0 && trail < 0)
+ pt = _add("-0", pt, ptlim);
+ else pt = _conv(lead, "%02d", pt, ptlim, loc);
+ }
+ if (convert_yy)
+ pt = _conv(((trail < 0) ? -trail : trail), "%02d", pt,
+ ptlim, loc);
+ return (pt);
+}
diff --git a/lib/libc/stdtime/strptime.3 b/lib/libc/stdtime/strptime.3
new file mode 100644
index 000000000000..2b50f0efd109
--- /dev/null
+++ b/lib/libc/stdtime/strptime.3
@@ -0,0 +1,182 @@
+.\"
+.\" Copyright (c) 1997 Joerg Wunsch
+.\"
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\" "
+.Dd October 2, 2014
+.Dt STRPTIME 3
+.Os
+.Sh NAME
+.Nm strptime
+.Nd parse date and time string
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In time.h
+.Ft char *
+.Fo strptime
+.Fa "const char * restrict buf"
+.Fa "const char * restrict format"
+.Fa "struct tm * restrict timeptr"
+.Fc
+.In time.h
+.In xlocale.h
+.Ft char *
+.Fn strptime_l "const char * restrict buf" "const char * restrict format" "struct tm * restrict timeptr" "locale_t loc"
+.Sh DESCRIPTION
+The
+.Fn strptime
+function parses the string in the buffer
+.Fa buf
+according to the string pointed to by
+.Fa format ,
+and fills in the elements of the structure pointed to by
+.Fa timeptr .
+The resulting values will be relative to the local time zone.
+Thus, it can be considered the reverse operation of
+.Xr strftime 3 .
+The
+.Fn strptime_l
+function does the same as
+.Fn strptime ,
+but takes an explicit locale rather than using the current locale.
+.Pp
+The
+.Fa format
+string consists of zero or more conversion specifications and
+ordinary characters.
+All ordinary characters are matched exactly with the buffer, where
+white space in the format string will match any amount of white space
+in the buffer.
+All conversion specifications are identical to those described in
+.Xr strftime 3 .
+.Pp
+Two-digit year values, including formats
+.Fa %y
+and
+.Fa \&%D ,
+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
+string does not contain enough conversion specifications to completely
+specify the resulting
+.Vt struct tm ,
+the unspecified members of
+.Va timeptr
+are left untouched.
+For example, if
+.Fa format
+is
+.Dq Li "%H:%M:%S" ,
+only
+.Va tm_hour ,
+.Va tm_sec
+and
+.Va tm_min
+will be modified.
+If time relative to today is desired, initialize the
+.Fa timeptr
+structure with today's date before passing it to
+.Fn strptime .
+.Sh RETURN VALUES
+Upon successful completion,
+.Fn strptime
+returns the pointer to the first character in
+.Fa buf
+that has not been required to satisfy the specified conversions in
+.Fa format .
+It returns
+.Dv NULL
+if one of the conversions failed.
+.Fn strptime_l
+returns the same values as
+.Fn strptime .
+.Sh SEE ALSO
+.Xr date 1 ,
+.Xr scanf 3 ,
+.Xr strftime 3
+.Sh HISTORY
+The
+.Fn strptime
+function appeared in
+.Fx 3.0 .
+.Sh AUTHORS
+The
+.Fn strptime
+function has been contributed by Powerdog Industries.
+.Pp
+This man page was written by
+.An J\(:org Wunsch .
+.Sh BUGS
+Both the
+.Fa %e
+and
+.Fa %l
+format specifiers may incorrectly scan one too many digits
+if the intended values comprise only a single digit
+and that digit is followed immediately by another digit.
+Both specifiers accept zero-padded values,
+even though they are both defined as taking unpadded values.
+.Pp
+The
+.Fa %p
+format specifier has no effect unless it is parsed
+.Em after
+hour-related specifiers.
+Specifying
+.Fa %l
+without
+.Fa %p
+will produce undefined results.
+Note that 12AM
+(ante meridiem)
+is taken as midnight
+and 12PM
+(post meridiem)
+is taken as noon.
+.Pp
+The
+.Fa %Z
+format specifier only accepts time zone abbreviations of the local time zone,
+or the value "GMT".
+This limitation is because of ambiguity due to of the over loading of time
+zone abbreviations.
+One such example is
+.Fa EST
+which is both Eastern Standard Time and Eastern Australia Summer Time.
+.Pp
+The
+.Fn strptime
+function does not correctly handle multibyte characters in the
+.Fa format
+argument.
diff --git a/lib/libc/stdtime/strptime.c b/lib/libc/stdtime/strptime.c
new file mode 100644
index 000000000000..89703ec8be3c
--- /dev/null
+++ b/lib/libc/stdtime/strptime.c
@@ -0,0 +1,707 @@
+/*-
+ * Copyright (c) 2014 Gary Mills
+ * Copyright 2011, Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 1994 Powerdog Industries. All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY POWERDOG INDUSTRIES ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE POWERDOG INDUSTRIES BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * official policies, either expressed or implied, of Powerdog Industries.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#ifndef NOID
+static char copyright[] __unused =
+"@(#) Copyright (c) 1994 Powerdog Industries. All rights reserved.";
+static char sccsid[] __unused = "@(#)strptime.c 0.1 (Powerdog) 94/03/27";
+#endif /* !defined NOID */
+#endif /* not lint */
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <time.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#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 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,
+ locale_t locale)
+{
+ char c;
+ const char *ptr;
+ int day_offset = -1, wday_offset;
+ int week_offset;
+ int i, len;
+ int flags;
+ int Ealternative, Oalternative;
+ 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) {
+ c = *ptr++;
+
+ if (c != '%') {
+ if (isspace_l((unsigned char)c, locale))
+ while (*buf != 0 &&
+ isspace_l((unsigned char)*buf, locale))
+ buf++;
+ else if (c != *buf++)
+ return (NULL);
+ continue;
+ }
+
+ Ealternative = 0;
+ Oalternative = 0;
+label:
+ c = *ptr++;
+ switch (c) {
+ case '%':
+ if (*buf++ != '%')
+ return (NULL);
+ break;
+
+ case '+':
+ 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':
+ if (!isdigit_l((unsigned char)*buf, locale))
+ return (NULL);
+
+ /* XXX This will break for 3-digit centuries. */
+ len = 2;
+ for (i = 0; len && *buf != 0 &&
+ isdigit_l((unsigned char)*buf, locale); buf++) {
+ i *= 10;
+ i += *buf - '0';
+ len--;
+ }
+ if (i < 19)
+ return (NULL);
+
+ 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':
+ if (Ealternative || Oalternative)
+ break;
+ Ealternative++;
+ goto label;
+
+ case 'O':
+ if (Ealternative || Oalternative)
+ break;
+ Oalternative++;
+ goto label;
+
+ case 'F':
+ buf = _strptime(buf, "%Y-%m-%d", tm, GMTp, locale);
+ if (buf == NULL)
+ return (NULL);
+ flags |= FLAG_MONTH | FLAG_MDAY | FLAG_YEAR;
+ break;
+
+ case 'R':
+ buf = _strptime(buf, "%H:%M", tm, GMTp, locale);
+ if (buf == NULL)
+ return (NULL);
+ break;
+
+ case 'r':
+ buf = _strptime(buf, tptr->ampm_fmt, tm, GMTp, locale);
+ if (buf == NULL)
+ return (NULL);
+ break;
+
+ case 'T':
+ buf = _strptime(buf, "%H:%M:%S", tm, GMTp, locale);
+ if (buf == NULL)
+ return (NULL);
+ break;
+
+ case 'X':
+ buf = _strptime(buf, tptr->X_fmt, tm, GMTp, locale);
+ if (buf == NULL)
+ return (NULL);
+ break;
+
+ case 'x':
+ buf = _strptime(buf, tptr->x_fmt, tm, GMTp, locale);
+ if (buf == NULL)
+ return (NULL);
+ flags |= FLAG_MONTH | FLAG_MDAY | FLAG_YEAR;
+ break;
+
+ case 'j':
+ if (!isdigit_l((unsigned char)*buf, locale))
+ return (NULL);
+
+ len = 3;
+ for (i = 0; len && *buf != 0 &&
+ isdigit_l((unsigned char)*buf, locale); buf++){
+ i *= 10;
+ i += *buf - '0';
+ len--;
+ }
+ if (i < 1 || i > 366)
+ return (NULL);
+
+ tm->tm_yday = i - 1;
+ flags |= FLAG_YDAY;
+
+ break;
+
+ case 'M':
+ case 'S':
+ if (*buf == 0 ||
+ isspace_l((unsigned char)*buf, locale))
+ break;
+
+ if (!isdigit_l((unsigned char)*buf, locale))
+ return (NULL);
+
+ len = 2;
+ for (i = 0; len && *buf != 0 &&
+ isdigit_l((unsigned char)*buf, locale); buf++){
+ i *= 10;
+ i += *buf - '0';
+ len--;
+ }
+
+ if (c == 'M') {
+ if (i > 59)
+ return (NULL);
+ tm->tm_min = i;
+ } else {
+ if (i > 60)
+ return (NULL);
+ tm->tm_sec = i;
+ }
+
+ break;
+
+ case 'H':
+ case 'I':
+ case 'k':
+ case 'l':
+ /*
+ * Of these, %l is the only specifier explicitly
+ * documented as not being zero-padded. However,
+ * there is no harm in allowing zero-padding.
+ *
+ * XXX The %l specifier may gobble one too many
+ * digits if used incorrectly.
+ */
+ if (!isdigit_l((unsigned char)*buf, locale))
+ return (NULL);
+
+ len = 2;
+ for (i = 0; len && *buf != 0 &&
+ isdigit_l((unsigned char)*buf, locale); buf++) {
+ i *= 10;
+ i += *buf - '0';
+ len--;
+ }
+ if (c == 'H' || c == 'k') {
+ if (i > 23)
+ return (NULL);
+ } else if (i > 12)
+ return (NULL);
+
+ tm->tm_hour = i;
+
+ break;
+
+ case 'p':
+ /*
+ * XXX This is bogus if parsed before hour-related
+ * specifiers.
+ */
+ if (tm->tm_hour > 12)
+ return (NULL);
+
+ len = strlen(tptr->am);
+ if (strncasecmp_l(buf, tptr->am, len, locale) == 0) {
+ if (tm->tm_hour == 12)
+ tm->tm_hour = 0;
+ buf += len;
+ break;
+ }
+
+ len = strlen(tptr->pm);
+ if (strncasecmp_l(buf, tptr->pm, len, locale) == 0) {
+ if (tm->tm_hour != 12)
+ tm->tm_hour += 12;
+ buf += len;
+ break;
+ }
+
+ return (NULL);
+
+ case 'A':
+ case 'a':
+ for (i = 0; i < asizeof(tptr->weekday); i++) {
+ len = strlen(tptr->weekday[i]);
+ if (strncasecmp_l(buf, tptr->weekday[i],
+ len, locale) == 0)
+ break;
+ len = strlen(tptr->wday[i]);
+ if (strncasecmp_l(buf, tptr->wday[i],
+ len, locale) == 0)
+ break;
+ }
+ if (i == asizeof(tptr->weekday))
+ return (NULL);
+
+ buf += len;
+ tm->tm_wday = i;
+ flags |= FLAG_WDAY;
+ break;
+
+ case 'U':
+ case 'W':
+ /*
+ * XXX This is bogus, as we can not assume any valid
+ * information present in the tm structure at this
+ * point to calculate a real value, so just check the
+ * range for now.
+ */
+ if (!isdigit_l((unsigned char)*buf, locale))
+ return (NULL);
+
+ len = 2;
+ for (i = 0; len && *buf != 0 &&
+ isdigit_l((unsigned char)*buf, locale); buf++) {
+ i *= 10;
+ i += *buf - '0';
+ len--;
+ }
+ if (i > 53)
+ return (NULL);
+
+ if (c == 'U')
+ day_offset = TM_SUNDAY;
+ else
+ day_offset = TM_MONDAY;
+
+
+ week_offset = i;
+
+ break;
+
+ case 'u':
+ case 'w':
+ if (!isdigit_l((unsigned char)*buf, locale))
+ return (NULL);
+
+ i = *buf++ - '0';
+ if (i < 0 || i > 7 || (c == 'u' && i < 1) ||
+ (c == 'w' && i > 6))
+ return (NULL);
+
+ tm->tm_wday = i % 7;
+ flags |= FLAG_WDAY;
+
+ break;
+
+ case 'e':
+ /*
+ * With %e format, our strftime(3) adds a blank space
+ * before single digits.
+ */
+ if (*buf != 0 &&
+ isspace_l((unsigned char)*buf, locale))
+ buf++;
+ /* FALLTHROUGH */
+ case 'd':
+ /*
+ * The %e specifier was once explicitly documented as
+ * not being zero-padded but was later changed to
+ * equivalent to %d. There is no harm in allowing
+ * such padding.
+ *
+ * XXX The %e specifier may gobble one too many
+ * digits if used incorrectly.
+ */
+ if (!isdigit_l((unsigned char)*buf, locale))
+ return (NULL);
+
+ len = 2;
+ for (i = 0; len && *buf != 0 &&
+ isdigit_l((unsigned char)*buf, locale); buf++) {
+ i *= 10;
+ i += *buf - '0';
+ len--;
+ }
+ if (i > 31)
+ return (NULL);
+
+ tm->tm_mday = i;
+ flags |= FLAG_MDAY;
+
+ break;
+
+ case 'B':
+ case 'b':
+ case 'h':
+ for (i = 0; i < asizeof(tptr->month); i++) {
+ if (Oalternative) {
+ if (c == 'B') {
+ len = strlen(tptr->alt_month[i]);
+ if (strncasecmp_l(buf,
+ tptr->alt_month[i],
+ len, locale) == 0)
+ break;
+ }
+ } else {
+ len = strlen(tptr->month[i]);
+ if (strncasecmp_l(buf, tptr->month[i],
+ len, locale) == 0)
+ break;
+ }
+ }
+ /*
+ * Try the abbreviated month name if the full name
+ * wasn't found and Oalternative was not requested.
+ */
+ if (i == asizeof(tptr->month) && !Oalternative) {
+ for (i = 0; i < asizeof(tptr->month); i++) {
+ len = strlen(tptr->mon[i]);
+ if (strncasecmp_l(buf, tptr->mon[i],
+ len, locale) == 0)
+ break;
+ }
+ }
+ if (i == asizeof(tptr->month))
+ return (NULL);
+
+ tm->tm_mon = i;
+ buf += len;
+ flags |= FLAG_MONTH;
+
+ break;
+
+ case 'm':
+ if (!isdigit_l((unsigned char)*buf, locale))
+ return (NULL);
+
+ len = 2;
+ for (i = 0; len && *buf != 0 &&
+ isdigit_l((unsigned char)*buf, locale); buf++) {
+ i *= 10;
+ i += *buf - '0';
+ len--;
+ }
+ if (i < 1 || i > 12)
+ return (NULL);
+
+ tm->tm_mon = i - 1;
+ flags |= FLAG_MONTH;
+
+ break;
+
+ case 's':
+ {
+ char *cp;
+ int sverrno;
+ long n;
+ time_t t;
+
+ sverrno = errno;
+ errno = 0;
+ n = strtol_l(buf, &cp, 10, locale);
+ if (errno == ERANGE || (long)(t = n) != n) {
+ errno = sverrno;
+ return (NULL);
+ }
+ errno = sverrno;
+ buf = cp;
+ if (gmtime_r(&t, tm) == NULL)
+ return (NULL);
+ *GMTp = 1;
+ flags |= FLAG_YDAY | FLAG_WDAY | FLAG_MONTH |
+ FLAG_MDAY | FLAG_YEAR;
+ }
+ break;
+
+ case 'Y':
+ case 'y':
+ if (*buf == 0 ||
+ isspace_l((unsigned char)*buf, locale))
+ break;
+
+ if (!isdigit_l((unsigned char)*buf, locale))
+ return (NULL);
+
+ len = (c == 'Y') ? 4 : 2;
+ for (i = 0; len && *buf != 0 &&
+ isdigit_l((unsigned char)*buf, locale); buf++) {
+ i *= 10;
+ i += *buf - '0';
+ len--;
+ }
+ if (c == 'Y')
+ i -= TM_YEAR_BASE;
+ if (c == 'y' && i < 69)
+ i += 100;
+ if (i < 0)
+ return (NULL);
+
+ tm->tm_year = i;
+ flags |= FLAG_YEAR;
+
+ break;
+
+ case 'Z':
+ {
+ const char *cp;
+ char *zonestr;
+
+ for (cp = buf; *cp &&
+ isupper_l((unsigned char)*cp, locale); ++cp) {
+ /*empty*/}
+ if (cp - buf) {
+ zonestr = alloca(cp - buf + 1);
+ strncpy(zonestr, buf, cp - buf);
+ zonestr[cp - buf] = '\0';
+ tzset();
+ if (0 == strcmp(zonestr, "GMT") ||
+ 0 == strcmp(zonestr, "UTC")) {
+ *GMTp = 1;
+ } else if (0 == strcmp(zonestr, tzname[0])) {
+ tm->tm_isdst = 0;
+ } else if (0 == strcmp(zonestr, tzname[1])) {
+ tm->tm_isdst = 1;
+ } else {
+ return (NULL);
+ }
+ buf += cp - buf;
+ }
+ }
+ break;
+
+ case 'z':
+ {
+ int sign = 1;
+
+ if (*buf != '+') {
+ if (*buf == '-')
+ sign = -1;
+ else
+ return (NULL);
+ }
+
+ buf++;
+ i = 0;
+ for (len = 4; len > 0; len--) {
+ if (isdigit_l((unsigned char)*buf, locale)) {
+ i *= 10;
+ i += *buf - '0';
+ buf++;
+ } else if (len == 2) {
+ i *= 100;
+ break;
+ } else
+ return (NULL);
+ }
+
+ if (i > 1400 || (sign == -1 && i > 1200) ||
+ (i % 100) >= 60)
+ return (NULL);
+ tm->tm_hour -= sign * (i / 100);
+ tm->tm_min -= sign * (i % 100);
+ *GMTp = 1;
+ }
+ break;
+
+ case 'n':
+ case 't':
+ 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) {
+ int tmpwday, tmpyday, fwo;
+
+ fwo = first_wday_of(tm->tm_year + TM_YEAR_BASE);
+ /* No incomplete week (week 0). */
+ if (week_offset == 0 && fwo == day_offset)
+ return (NULL);
+
+ /* Set the date to the first Sunday (or Monday)
+ * of the specified week of the year.
+ */
+ tmpwday = (flags & FLAG_WDAY) ? tm->tm_wday :
+ day_offset;
+ tmpyday = (7 - fwo + day_offset) % 7 +
+ (week_offset - 1) * 7 +
+ (tmpwday - day_offset + 7) % 7;
+ /* Impossible yday for incomplete week (week 0). */
+ if (tmpyday < 0) {
+ if (flags & FLAG_WDAY)
+ return (NULL);
+ tmpyday = 0;
+ }
+ tm->tm_yday = tmpyday;
+ 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)
+{
+ char *ret;
+ int gmt;
+ FIX_LOCALE(loc);
+
+ gmt = 0;
+ 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)
+{
+ return strptime_l(buf, fmt, tm, __get_locale());
+}
diff --git a/lib/libc/stdtime/time32.c b/lib/libc/stdtime/time32.c
new file mode 100644
index 000000000000..e852a4f279e4
--- /dev/null
+++ b/lib/libc/stdtime/time32.c
@@ -0,0 +1,100 @@
+/*-
+ * Copyright (c) 2001 FreeBSD Inc.
+ * All rights reserved.
+ *
+ * These routines are for converting time_t to fixed-bit representations
+ * for use in protocols or storage. When converting time to a larger
+ * representation of time_t these routines are expected to assume temporal
+ * locality and use the 50-year rule to properly set the msb bits. XXX
+ *
+ * Redistribution and use under the terms of the COPYRIGHT file at the
+ * base of the source tree.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <timeconv.h>
+
+/*
+ * Convert a 32 bit representation of time_t into time_t. XXX needs to
+ * implement the 50-year rule to handle post-2038 conversions.
+ */
+time_t
+_time32_to_time(__int32_t t32)
+{
+ return((time_t)t32);
+}
+
+/*
+ * Convert time_t to a 32 bit representation. If time_t is 64 bits we can
+ * simply chop it down. The resulting 32 bit representation can be
+ * converted back to a temporally local 64 bit time_t using time32_to_time.
+ */
+__int32_t
+_time_to_time32(time_t t)
+{
+ return((__int32_t)t);
+}
+
+/*
+ * Convert a 64 bit representation of time_t into time_t. If time_t is
+ * represented as 32 bits we can simply chop it and not support times
+ * past 2038.
+ */
+time_t
+_time64_to_time(__int64_t t64)
+{
+ return((time_t)t64);
+}
+
+/*
+ * Convert time_t to a 64 bit representation. If time_t is represented
+ * as 32 bits we simply sign-extend and do not support times past 2038.
+ */
+__int64_t
+_time_to_time64(time_t t)
+{
+ return((__int64_t)t);
+}
+
+/*
+ * Convert to/from 'long'. Depending on the sizeof(long) this may or
+ * may not require using the 50-year rule.
+ */
+long
+_time_to_long(time_t t)
+{
+ if (sizeof(long) == sizeof(__int64_t))
+ return(_time_to_time64(t));
+ return((long)t);
+}
+
+time_t
+_long_to_time(long tlong)
+{
+ if (sizeof(long) == sizeof(__int32_t))
+ return(_time32_to_time(tlong));
+ return((time_t)tlong);
+}
+
+/*
+ * Convert to/from 'int'. Depending on the sizeof(int) this may or
+ * may not require using the 50-year rule.
+ */
+int
+_time_to_int(time_t t)
+{
+ if (sizeof(int) == sizeof(__int64_t))
+ return(_time_to_time64(t));
+ return((int)t);
+}
+
+time_t
+_int_to_time(int tint)
+{
+ if (sizeof(int) == sizeof(__int32_t))
+ return(_time32_to_time(tint));
+ return((time_t)tint);
+}
diff --git a/lib/libc/stdtime/timelocal.c b/lib/libc/stdtime/timelocal.c
new file mode 100644
index 000000000000..362cec3958ce
--- /dev/null
+++ b/lib/libc/stdtime/timelocal.c
@@ -0,0 +1,154 @@
+/*-
+ * Copyright (c) 2001 Alexey Zelkin <phantom@FreeBSD.org>
+ * Copyright (c) 1997 FreeBSD Inc.
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 <stddef.h>
+
+#include "ldpart.h"
+#include "timelocal.h"
+
+struct xlocale_time {
+ struct xlocale_component header;
+ char *buffer;
+ struct lc_time_T locale;
+};
+
+struct xlocale_time __xlocale_global_time;
+
+#define LCTIME_SIZE (sizeof(struct lc_time_T) / sizeof(char *))
+
+static const struct lc_time_T _C_time_locale = {
+ {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+ }, {
+ "January", "February", "March", "April", "May", "June",
+ "July", "August", "September", "October", "November", "December"
+ }, {
+ "Sun", "Mon", "Tue", "Wed",
+ "Thu", "Fri", "Sat"
+ }, {
+ "Sunday", "Monday", "Tuesday", "Wednesday",
+ "Thursday", "Friday", "Saturday"
+ },
+
+ /* X_fmt */
+ "%H:%M:%S",
+
+ /*
+ * x_fmt
+ * Since the C language standard calls for
+ * "date, using locale's date format," anything goes.
+ * Using just numbers (as here) makes Quakers happier;
+ * it's also compatible with SVR4.
+ */
+ "%m/%d/%y",
+
+ /*
+ * c_fmt
+ */
+ "%a %b %e %H:%M:%S %Y",
+
+ /* am */
+ "AM",
+
+ /* pm */
+ "PM",
+
+ /* date_fmt */
+ "%a %b %e %H:%M:%S %Z %Y",
+
+ /* alt_month
+ * Standalone months forms for %OB
+ */
+ {
+ "January", "February", "March", "April", "May", "June",
+ "July", "August", "September", "October", "November", "December"
+ },
+
+ /* md_order
+ * Month / day order in dates
+ */
+ "md",
+
+ /* ampm_fmt
+ * To determine 12-hour clock format time (empty, if N/A)
+ */
+ "%I:%M:%S %p"
+};
+
+static void destruct_time(void *v)
+{
+ struct xlocale_time *l = v;
+ if (l->buffer)
+ free(l->buffer);
+ free(l);
+}
+
+#include <stdio.h>
+struct lc_time_T *
+__get_current_time_locale(locale_t loc)
+{
+ return (loc->using_time_locale
+ ? &((struct xlocale_time *)loc->components[XLC_TIME])->locale
+ : (struct lc_time_T *)&_C_time_locale);
+}
+
+static int
+time_load_locale(struct xlocale_time *l, int *using_locale, const char *name)
+{
+ struct lc_time_T *time_locale = &l->locale;
+ return (__part_load_locale(name, using_locale,
+ &l->buffer, "LC_TIME",
+ LCTIME_SIZE, LCTIME_SIZE,
+ (const char **)time_locale));
+}
+int
+__time_load_locale(const char *name)
+{
+ return time_load_locale(&__xlocale_global_time,
+ &__xlocale_global_locale.using_time_locale, name);
+}
+void* __time_load(const char* name, locale_t loc)
+{
+ struct xlocale_time *new = calloc(sizeof(struct xlocale_time), 1);
+ new->header.header.destructor = destruct_time;
+ if (time_load_locale(new, &loc->using_time_locale, name) == _LDP_ERROR)
+ {
+ xlocale_release(new);
+ return NULL;
+ }
+ return new;
+}
+
diff --git a/lib/libc/stdtime/timelocal.h b/lib/libc/stdtime/timelocal.h
new file mode 100644
index 000000000000..2e44415b9940
--- /dev/null
+++ b/lib/libc/stdtime/timelocal.h
@@ -0,0 +1,61 @@
+/*-
+ * Copyright (c) 1997-2002 FreeBSD Project.
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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 _TIMELOCAL_H_
+#define _TIMELOCAL_H_
+#include "xlocale_private.h"
+
+/*
+ * Private header file for the strftime and strptime localization
+ * stuff.
+ */
+struct lc_time_T {
+ const char *mon[12];
+ const char *month[12];
+ const char *wday[7];
+ const char *weekday[7];
+ const char *X_fmt;
+ const char *x_fmt;
+ const char *c_fmt;
+ const char *am;
+ const char *pm;
+ const char *date_fmt;
+ const char *alt_month[12];
+ const char *md_order;
+ const char *ampm_fmt;
+};
+
+struct lc_time_T *__get_current_time_locale(locale_t);
+int __time_load_locale(const char *);
+
+#endif /* !_TIMELOCAL_H_ */
diff --git a/lib/libc/string/Makefile.inc b/lib/libc/string/Makefile.inc
new file mode 100644
index 000000000000..d8ade45e491a
--- /dev/null
+++ b/lib/libc/string/Makefile.inc
@@ -0,0 +1,102 @@
+# @(#)Makefile.inc 8.1 (Berkeley) 6/4/93
+# $FreeBSD$
+
+.PATH: ${LIBC_SRCTOP}/${LIBC_ARCH}/string ${LIBC_SRCTOP}/string
+.PATH: ${SRCTOP}/sys/libkern
+
+CFLAGS+= -I${LIBC_SRCTOP}/locale
+
+# machine-independent string sources
+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 \
+ strcat.c strcasestr.c strchr.c strchrnul.c strcmp.c strcoll.c strcpy.c\
+ strcspn.c strdup.c strerror.c strlcat.c strlcpy.c strlen.c strmode.c \
+ strncat.c strncmp.c strncpy.c strndup.c strnlen.c strnstr.c \
+ strpbrk.c strrchr.c strsep.c strsignal.c strspn.c strstr.c strtok.c \
+ strxfrm.c swab.c \
+ timingsafe_bcmp.c \
+ timingsafe_memcmp.c \
+ wcpcpy.c wcpncpy.c wcscasecmp.c wcscat.c \
+ wcschr.c wcscmp.c wcscoll.c wcscpy.c wcscspn.c wcsdup.c \
+ wcslcat.c wcslcpy.c wcslen.c wcsncasecmp.c wcsncat.c wcsncmp.c \
+ wcsncpy.c wcsnlen.c wcspbrk.c \
+ wcsrchr.c wcsspn.c wcsstr.c wcstok.c wcswidth.c wcsxfrm.c wmemchr.c \
+ wmemcmp.c \
+ wmemcpy.c wmemmove.c wmemset.c
+
+SYM_MAPS+= ${LIBC_SRCTOP}/string/Symbol.map
+
+
+# machine-dependent string sources
+.sinclude "${LIBC_SRCTOP}/${LIBC_ARCH}/string/Makefile.inc"
+
+MAN+= bcmp.3 bcopy.3 bstring.3 bzero.3 ffs.3 index.3 memccpy.3 memchr.3 \
+ memcmp.3 memcpy.3 memmem.3 memmove.3 memset.3 strcasecmp.3 strcat.3 \
+ strchr.3 strcmp.3 strcoll.3 strcpy.3 strdup.3 strerror.3 \
+ string.3 strlcpy.3 strlen.3 strmode.3 strpbrk.3 strsep.3 \
+ strspn.3 strstr.3 strtok.3 strxfrm.3 swab.3 \
+ timingsafe_bcmp.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 \
+ ffs.3 flsl.3 \
+ ffs.3 flsll.3
+MLINKS+=index.3 rindex.3
+MLINKS+=memchr.3 memrchr.3
+MLINKS+=strcasecmp.3 strncasecmp.3 \
+ strcasecmp.3 strcasecmp_l.3 \
+ strcasecmp.3 strncasecmp_l.3
+MLINKS+=strcat.3 strncat.3
+MLINKS+=strchr.3 strrchr.3 \
+ strchr.3 strchrnul.3
+MLINKS+=strcmp.3 strncmp.3
+MLINKS+=strcoll.3 strcoll_l.3
+MLINKS+=strcpy.3 stpcpy.3 \
+ strcpy.3 stpncpy.3 \
+ strcpy.3 strncpy.3
+MLINKS+=strdup.3 strndup.3
+MLINKS+=strerror.3 perror.3 \
+ strerror.3 strerror_r.3 \
+ strerror.3 sys_errlist.3 \
+ strerror.3 sys_nerr.3
+MLINKS+=strlcpy.3 strlcat.3
+MLINKS+=strlen.3 strnlen.3
+MLINKS+=strspn.3 strcspn.3
+MLINKS+=strstr.3 strcasestr.3 \
+ strstr.3 strnstr.3 \
+ strstr.3 strcasestr_l.3
+MLINKS+=strtok.3 strtok_r.3
+MLINKS+=strxfrm.3 strxfrm_l.3
+MLINKS+=timingsafe_bcmp.3 timingsafe_memcmp.3
+MLINKS+=wmemchr.3 wcpcpy.3 \
+ wmemchr.3 wcpncpy.3 \
+ wmemchr.3 wcscasecmp.3 \
+ wmemchr.3 wcscat.3 \
+ wmemchr.3 wcschr.3 \
+ wmemchr.3 wcscmp.3 \
+ wmemchr.3 wcscpy.3 \
+ wmemchr.3 wcscspn.3 \
+ wmemchr.3 wcsdup.3 \
+ wmemchr.3 wcslcat.3 \
+ wmemchr.3 wcslcpy.3 \
+ wmemchr.3 wcslen.3 \
+ wmemchr.3 wcsncasecmp.3 \
+ wmemchr.3 wcsncat.3 \
+ wmemchr.3 wcsncmp.3 \
+ wmemchr.3 wcsncpy.3 \
+ wmemchr.3 wcsnlen.3 \
+ wmemchr.3 wcspbrk.3 \
+ wmemchr.3 wcsrchr.3 \
+ wmemchr.3 wcsspn.3 \
+ wmemchr.3 wcsstr.3 \
+ wmemchr.3 wmemcmp.3 \
+ wmemchr.3 wmemcpy.3 \
+ wmemchr.3 wmemmove.3 \
+ wmemchr.3 wmemset.3
diff --git a/lib/libc/string/Symbol.map b/lib/libc/string/Symbol.map
new file mode 100644
index 000000000000..cbf80cf9751c
--- /dev/null
+++ b/lib/libc/string/Symbol.map
@@ -0,0 +1,114 @@
+/*
+ * $FreeBSD$
+ */
+
+FBSD_1.0 {
+ bcmp;
+ bcopy;
+ memcpy;
+ memmove;
+ ffs;
+ ffsl;
+ fls;
+ flsl;
+ index;
+ strchr;
+ memccpy;
+ memchr;
+ memcmp;
+ memmem;
+ bzero;
+ memset;
+ strrchr;
+ rindex;
+ stpcpy;
+ strcasecmp;
+ strncasecmp;
+ strcasestr;
+ strcat;
+ strcmp;
+ strcoll;
+ strcpy;
+ strcspn;
+ strdup;
+ strerror_r;
+ strerror;
+ strlcat;
+ strlcpy;
+ strlen;
+ strmode;
+ strncat;
+ strncmp;
+ strncpy;
+ strnstr;
+ strpbrk;
+ strsep;
+ strsignal;
+ strspn;
+ strstr;
+ strtok_r;
+ strtok;
+ strxfrm;
+ swab;
+ wcscat;
+ wcschr;
+ wcscmp;
+ wcscoll;
+ wcscpy;
+ wcscspn;
+ wcsdup;
+ wcslcat;
+ wcslcpy;
+ wcslen;
+ wcsncat;
+ wcsncmp;
+ wcsncpy;
+ wcspbrk;
+ wcsrchr;
+ wcsspn;
+ wcsstr;
+ wcstok;
+ wcswidth;
+ wcsxfrm;
+ wmemchr;
+ wmemcmp;
+ wmemcpy;
+ wmemmove;
+ wmemset;
+};
+
+FBSD_1.1 {
+ ffsll;
+ flsll;
+ memrchr;
+ stpncpy;
+ strndup;
+ strnlen;
+ wcpcpy;
+ wcpncpy;
+ wcscasecmp;
+ wcsncasecmp;
+ wcsnlen;
+};
+
+FBSD_1.3 {
+ strcasecmp_l;
+ strcasestr_l;
+ strchrnul;
+ strncasecmp_l;
+ wcswidth_l;
+ wcwidth_l;
+};
+
+FBSD_1.4 {
+ explicit_bzero;
+};
+
+FBSD_1.5 {
+ timingsafe_bcmp;
+ timingsafe_memcmp;
+};
+
+FBSDprivate_1.0 {
+ __strtok_r;
+};
diff --git a/lib/libc/string/bcmp.3 b/lib/libc/string/bcmp.3
new file mode 100644
index 000000000000..e2d4063a1654
--- /dev/null
+++ b/lib/libc/string/bcmp.3
@@ -0,0 +1,78 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek.
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)bcmp.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd August 15, 2016
+.Dt BCMP 3
+.Os
+.Sh NAME
+.Nm bcmp
+.Nd compare byte string
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In strings.h
+.Ft int
+.Fn bcmp "const void *b1" "const void *b2" "size_t len"
+.Sh DESCRIPTION
+The
+.Fn bcmp
+function
+compares byte string
+.Fa b1
+against byte string
+.Fa b2 ,
+returning zero if they are identical, non-zero otherwise.
+Both strings are assumed to be
+.Fa len
+bytes long.
+Zero-length strings are always identical.
+.Pp
+The strings may overlap.
+.Sh SEE ALSO
+.Xr memcmp 3 ,
+.Xr strcasecmp 3 ,
+.Xr strcmp 3 ,
+.Xr strcoll 3 ,
+.Xr strxfrm 3 ,
+.Xr timingsafe_bcmp 3
+.Sh HISTORY
+A
+.Fn bcmp
+function first appeared in
+.Bx 4.2 .
+Its prototype existed previously in
+.In string.h
+before it was moved to
+.In strings.h
+for
+.St -p1003.1-2001
+compliance.
diff --git a/lib/libc/string/bcmp.c b/lib/libc/string/bcmp.c
new file mode 100644
index 000000000000..f1178a660b2b
--- /dev/null
+++ b/lib/libc/string/bcmp.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 1987, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)bcmp.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <strings.h>
+
+/*
+ * bcmp -- vax cmpc3 instruction
+ */
+int
+bcmp(const void *b1, const void *b2, size_t length)
+{
+ char *p1, *p2;
+
+ if (length == 0)
+ return (0);
+ p1 = (char *)b1;
+ p2 = (char *)b2;
+ do
+ if (*p1++ != *p2++)
+ break;
+ while (--length);
+ return (length);
+}
diff --git a/lib/libc/string/bcopy.3 b/lib/libc/string/bcopy.3
new file mode 100644
index 000000000000..ac480f8ca966
--- /dev/null
+++ b/lib/libc/string/bcopy.3
@@ -0,0 +1,98 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)bcopy.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd August 24, 2015
+.Dt BCOPY 3
+.Os
+.Sh NAME
+.Nm bcopy
+.Nd copy byte string
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In strings.h
+.Ft void
+.Fn bcopy "const void *src" "void *dst" "size_t len"
+.Sh DESCRIPTION
+The
+.Fn bcopy
+function
+copies
+.Fa len
+bytes from string
+.Fa src
+to string
+.Fa dst .
+The two strings may overlap.
+If
+.Fa len
+is zero, no bytes are copied.
+.Sh SEE ALSO
+.Xr memccpy 3 ,
+.Xr memcpy 3 ,
+.Xr memmove 3 ,
+.Xr strcpy 3 ,
+.Xr strncpy 3
+.Sh HISTORY
+A
+.Fn bcopy
+function appeared in
+.Bx 4.2 .
+Its prototype existed previously in
+.In string.h
+before it was moved to
+.In strings.h
+for
+.St -p1003.1-2001
+compliance.
+.Pp
+.St -p1003.1-2008
+removes the specification of
+.Fn bcopy
+and it is marked as LEGACY in
+.St -p1003.1-2004 .
+New programs should use
+.Xr memmove 3 .
+If the input and output buffer do not overlap, then
+.Xr memcpy 3
+is more efficient.
+Note that
+.Fn bcopy
+takes
+.Ar src
+and
+.Ar dst
+in the opposite order from
+.Fn memmove
+and
+.Fn memcpy .
diff --git a/lib/libc/string/bcopy.c b/lib/libc/string/bcopy.c
new file mode 100644
index 000000000000..c424de560f6c
--- /dev/null
+++ b/lib/libc/string/bcopy.c
@@ -0,0 +1,137 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)bcopy.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+/*
+ * sizeof(word) MUST BE A POWER OF TWO
+ * SO THAT wmask BELOW IS ALL ONES
+ */
+typedef int word; /* "word" used for optimal copy speed */
+
+#define wsize sizeof(word)
+#define wmask (wsize - 1)
+
+/*
+ * Copy a block of memory, handling overlap.
+ * This is the routine that actually implements
+ * (the portable versions of) bcopy, memcpy, and memmove.
+ */
+#if defined(MEMCOPY) || defined(MEMMOVE)
+#include <string.h>
+
+void *
+#ifdef MEMCOPY
+memcpy
+#else
+memmove
+#endif
+(void *dst0, const void *src0, size_t length)
+#else
+#include <strings.h>
+
+void
+bcopy(const void *src0, void *dst0, size_t length)
+#endif
+{
+ char *dst = dst0;
+ const char *src = src0;
+ size_t t;
+
+ if (length == 0 || dst == src) /* nothing to do */
+ goto done;
+
+ /*
+ * Macros: loop-t-times; and loop-t-times, t>0
+ */
+#define TLOOP(s) if (t) TLOOP1(s)
+#define TLOOP1(s) do { s; } while (--t)
+
+ if ((unsigned long)dst < (unsigned long)src) {
+ /*
+ * Copy forward.
+ */
+ t = (uintptr_t)src; /* only need low bits */
+ if ((t | (uintptr_t)dst) & wmask) {
+ /*
+ * Try to align operands. This cannot be done
+ * unless the low bits match.
+ */
+ if ((t ^ (uintptr_t)dst) & wmask || length < wsize)
+ t = length;
+ else
+ t = wsize - (t & wmask);
+ length -= t;
+ TLOOP1(*dst++ = *src++);
+ }
+ /*
+ * Copy whole words, then mop up any trailing bytes.
+ */
+ t = length / wsize;
+ TLOOP(*(word *)dst = *(word *)src; src += wsize; dst += wsize);
+ t = length & wmask;
+ TLOOP(*dst++ = *src++);
+ } else {
+ /*
+ * Copy backwards. Otherwise essentially the same.
+ * Alignment works as before, except that it takes
+ * (t&wmask) bytes to align, not wsize-(t&wmask).
+ */
+ src += length;
+ dst += length;
+ t = (uintptr_t)src;
+ if ((t | (uintptr_t)dst) & wmask) {
+ if ((t ^ (uintptr_t)dst) & wmask || length <= wsize)
+ t = length;
+ else
+ t &= wmask;
+ length -= t;
+ TLOOP1(*--dst = *--src);
+ }
+ t = length / wsize;
+ TLOOP(src -= wsize; dst -= wsize; *(word *)dst = *(word *)src);
+ t = length & wmask;
+ TLOOP(*--dst = *--src);
+ }
+done:
+#if defined(MEMCOPY) || defined(MEMMOVE)
+ return (dst0);
+#else
+ return;
+#endif
+}
diff --git a/lib/libc/string/bstring.3 b/lib/libc/string/bstring.3
new file mode 100644
index 000000000000..b8ed0908c88a
--- /dev/null
+++ b/lib/libc/string/bstring.3
@@ -0,0 +1,108 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek.
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)bstring.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt BSTRING 3
+.Os
+.Sh NAME
+.Nm bcmp ,
+.Nm bcopy ,
+.Nm bzero ,
+.Nm memccpy ,
+.Nm memchr ,
+.Nm memcmp ,
+.Nm memcpy ,
+.Nm memmove ,
+.Nm memset
+.Nd byte string operations
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In string.h
+.Ft int
+.Fn bcmp "const void *b1" "const void *b2" "size_t len"
+.Ft void
+.Fn bcopy "const void *src" "void *dst" "size_t len"
+.Ft void
+.Fn bzero "void *b" "size_t len"
+.Ft void *
+.Fn memchr "const void *b" "int c" "size_t len"
+.Ft int
+.Fn memcmp "const void *b1" "const void *b2" "size_t len"
+.Ft void *
+.Fn memccpy "void *dst" "const void *src" "int c" "size_t len"
+.Ft void *
+.Fn memcpy "void *dst" "const void *src" "size_t len"
+.Ft void *
+.Fn memmove "void *dst" "const void *src" "size_t len"
+.Ft void *
+.Fn memset "void *b" "int c" "size_t len"
+.Sh DESCRIPTION
+These functions operate on variable length strings of bytes.
+They do not check for terminating null bytes as the routines
+listed in
+.Xr string 3
+do.
+.Pp
+See the specific manual pages for more information.
+.Sh SEE ALSO
+.Xr bcmp 3 ,
+.Xr bcopy 3 ,
+.Xr bzero 3 ,
+.Xr memccpy 3 ,
+.Xr memchr 3 ,
+.Xr memcmp 3 ,
+.Xr memcpy 3 ,
+.Xr memmove 3 ,
+.Xr memset 3
+.Sh STANDARDS
+The functions
+.Fn memchr ,
+.Fn memcmp ,
+.Fn memcpy ,
+.Fn memmove ,
+and
+.Fn memset
+conform to
+.St -isoC .
+.Sh HISTORY
+The functions
+.Fn bzero
+and
+.Fn memccpy
+appeared in
+.Bx 4.3 ;
+the functions
+.Fn bcmp ,
+.Fn bcopy ,
+appeared in
+.Bx 4.2 .
diff --git a/lib/libc/string/bzero.3 b/lib/libc/string/bzero.3
new file mode 100644
index 000000000000..130a652fe849
--- /dev/null
+++ b/lib/libc/string/bzero.3
@@ -0,0 +1,98 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)bzero.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd August 24, 2015
+.Dt BZERO 3
+.Os
+.Sh NAME
+.Nm bzero ,
+.Nm explicit_bzero
+.Nd write zeroes to a byte string
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.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
+function
+writes
+.Fa len
+zero bytes to the string
+.Fa b .
+If
+.Fa len
+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
+.Sh HISTORY
+A
+.Fn bzero
+function
+appeared in
+.Bx 4.3 .
+Its prototype existed previously in
+.In string.h
+before it was moved to
+.In strings.h
+for
+.St -p1003.1-2001
+compliance.
+.Pp
+The
+.Fn explicit_bzero
+function first appeared in
+.Ox 5.5
+and
+.Fx 11.0 .
+.Pp
+.St -p1003.1-2008
+removes the specification of
+.Fn bzero
+and it is marked as LEGACY in
+.St -p1003.1-2004 .
+For portability with other systems new programs should use
+.Xr memset 3 .
diff --git a/lib/libc/string/bzero.c b/lib/libc/string/bzero.c
new file mode 100644
index 000000000000..201bd64f808d
--- /dev/null
+++ b/lib/libc/string/bzero.c
@@ -0,0 +1,5 @@
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#define BZERO
+#include "memset.c"
diff --git a/lib/libc/string/ffs.3 b/lib/libc/string/ffs.3
new file mode 100644
index 000000000000..8d2601d6efc7
--- /dev/null
+++ b/lib/libc/string/ffs.3
@@ -0,0 +1,111 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek.
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)ffs.3 8.2 (Berkeley) 4/19/94
+.\" $FreeBSD$
+.\"
+.Dd October 17, 2015
+.Dt FFS 3
+.Os
+.Sh NAME
+.Nm ffs ,
+.Nm ffsl ,
+.Nm ffsll ,
+.Nm fls ,
+.Nm flsl ,
+.Nm flsll
+.Nd find first or last bit set in a bit string
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In strings.h
+.Ft int
+.Fn ffs "int value"
+.Ft int
+.Fn ffsl "long value"
+.Ft int
+.Fn ffsll "long long value"
+.Ft int
+.Fn fls "int value"
+.Ft int
+.Fn flsl "long value"
+.Ft int
+.Fn flsll "long long value"
+.Sh DESCRIPTION
+The
+.Fn ffs ,
+.Fn ffsl
+and
+.Fn ffsll
+functions find the first (least significant) bit set
+in
+.Fa value
+and return the index of that bit.
+.Pp
+The
+.Fn fls ,
+.Fn flsl
+and
+.Fn flsll
+functions find the last (most significant) bit set in
+.Fa value
+and return the index of that bit.
+.Pp
+Bits are numbered starting at 1, the least significant bit.
+A return value of zero from any of these functions means that the
+argument was zero.
+.Sh SEE ALSO
+.Xr bitstring 3 ,
+.Xr bitset 9
+.Sh HISTORY
+The
+.Fn ffs
+function appeared in
+.Bx 4.3 .
+Its prototype existed previously in
+.In string.h
+before it was moved to
+.In strings.h
+for
+.St -p1003.1-2001
+compliance.
+.Pp
+The
+.Fn ffsl ,
+.Fn fls
+and
+.Fn flsl
+functions appeared in
+.Fx 5.3 .
+The
+.Fn ffsll
+and
+.Fn flsll
+functions appeared in
+.Fx 7.1 .
diff --git a/lib/libc/string/ffs.c b/lib/libc/string/ffs.c
new file mode 100644
index 000000000000..42a94ef7383d
--- /dev/null
+++ b/lib/libc/string/ffs.c
@@ -0,0 +1,51 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)ffs.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <strings.h>
+
+/*
+ * Find First Set bit
+ */
+int
+ffs(int mask)
+{
+ int bit;
+
+ if (mask == 0)
+ return(0);
+ for (bit = 1; !(mask & 1); bit++)
+ mask = (unsigned int)mask >> 1;
+ return (bit);
+}
diff --git a/lib/libc/string/ffsl.c b/lib/libc/string/ffsl.c
new file mode 100644
index 000000000000..3fd94521d623
--- /dev/null
+++ b/lib/libc/string/ffsl.c
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <strings.h>
+
+/*
+ * Find First Set bit
+ */
+int
+ffsl(long mask)
+{
+ int bit;
+
+ if (mask == 0)
+ return (0);
+ for (bit = 1; !(mask & 1); bit++)
+ mask = (unsigned long)mask >> 1;
+ return (bit);
+}
diff --git a/lib/libc/string/ffsll.c b/lib/libc/string/ffsll.c
new file mode 100644
index 000000000000..e19df91d1f03
--- /dev/null
+++ b/lib/libc/string/ffsll.c
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <strings.h>
+
+/*
+ * Find First Set bit
+ */
+int
+ffsll(long long mask)
+{
+ int bit;
+
+ if (mask == 0)
+ return (0);
+ for (bit = 1; !(mask & 1); bit++)
+ mask = (unsigned long long)mask >> 1;
+ return (bit);
+}
diff --git a/lib/libc/string/fls.c b/lib/libc/string/fls.c
new file mode 100644
index 000000000000..7145b909f026
--- /dev/null
+++ b/lib/libc/string/fls.c
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <strings.h>
+
+/*
+ * Find Last Set bit
+ */
+int
+fls(int mask)
+{
+ int bit;
+
+ if (mask == 0)
+ return (0);
+ for (bit = 1; mask != 1; bit++)
+ mask = (unsigned int)mask >> 1;
+ return (bit);
+}
diff --git a/lib/libc/string/flsl.c b/lib/libc/string/flsl.c
new file mode 100644
index 000000000000..19485b2f787e
--- /dev/null
+++ b/lib/libc/string/flsl.c
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <strings.h>
+
+/*
+ * Find Last Set bit
+ */
+int
+flsl(long mask)
+{
+ int bit;
+
+ if (mask == 0)
+ return (0);
+ for (bit = 1; mask != 1; bit++)
+ mask = (unsigned long)mask >> 1;
+ return (bit);
+}
diff --git a/lib/libc/string/flsll.c b/lib/libc/string/flsll.c
new file mode 100644
index 000000000000..b12f12f2d0d7
--- /dev/null
+++ b/lib/libc/string/flsll.c
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <strings.h>
+
+/*
+ * Find Last Set bit
+ */
+int
+flsll(long long mask)
+{
+ int bit;
+
+ if (mask == 0)
+ return (0);
+ for (bit = 1; mask != 1; bit++)
+ mask = (unsigned long long)mask >> 1;
+ return (bit);
+}
diff --git a/lib/libc/string/index.3 b/lib/libc/string/index.3
new file mode 100644
index 000000000000..dcce40031983
--- /dev/null
+++ b/lib/libc/string/index.3
@@ -0,0 +1,115 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek.
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)index.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd March 20, 2011
+.Dt INDEX 3
+.Os
+.Sh NAME
+.Nm index , rindex
+.Nd locate character in string
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In strings.h
+.Ft "char *"
+.Fn index "const char *s" "int c"
+.Ft "char *"
+.Fn rindex "const char *s" "int c"
+.Sh DESCRIPTION
+.Bf -symbolic
+The
+.Fn index
+and
+.Fn rindex
+functions have been deprecated in favor of
+.Xr strchr 3
+and
+.Xr strrchr 3 .
+.Ef
+.Pp
+The
+.Fn index
+function
+locates the first occurrence of
+.Fa c
+(converted to a
+.Vt char )
+in the string pointed to by
+.Fa s .
+The terminating null character is considered part of the string;
+therefore if
+.Fa c
+is
+.Ql \e0 ,
+the functions locate the terminating
+.Ql \e0 .
+.Pp
+The
+.Fn rindex
+function is identical to
+.Fn index ,
+except it locates the last occurrence of
+.Fa c .
+.Sh RETURN VALUES
+The functions
+.Fn index
+and
+.Fn rindex
+return a pointer to the located character, or
+.Dv NULL
+if the character does not appear in the string.
+.Sh SEE ALSO
+.Xr memchr 3 ,
+.Xr strchr 3 ,
+.Xr strcspn 3 ,
+.Xr strpbrk 3 ,
+.Xr strrchr 3 ,
+.Xr strsep 3 ,
+.Xr strspn 3 ,
+.Xr strstr 3 ,
+.Xr strtok 3
+.Sh HISTORY
+The
+.Fn index
+and
+.Fn rindex
+functions appeared in
+.At v6 .
+Their prototypes existed previously in
+.In string.h
+before they were moved to
+.In strings.h
+for
+.St -p1003.1-2001
+compliance.
+The functions are not specified by
+.St -p1003.1-2008 .
diff --git a/lib/libc/string/memccpy.3 b/lib/libc/string/memccpy.3
new file mode 100644
index 000000000000..5bf323115746
--- /dev/null
+++ b/lib/libc/string/memccpy.3
@@ -0,0 +1,74 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)memccpy.3 8.1 (Berkeley) 6/9/93
+.\" $FreeBSD$
+.\"
+.Dd June 9, 1993
+.Dt MEMCCPY 3
+.Os
+.Sh NAME
+.Nm memccpy
+.Nd copy string until character found
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In string.h
+.Ft void *
+.Fn memccpy "void *dst" "const void *src" "int c" "size_t len"
+.Sh DESCRIPTION
+The
+.Fn memccpy
+function
+copies bytes from string
+.Fa src
+to string
+.Fa dst .
+If the character
+.Fa c
+(as converted to an
+.Vt "unsigned char" )
+occurs in the string
+.Fa src ,
+the copy stops and a pointer to the byte after the copy of
+.Fa c
+in the string
+.Fa dst
+is returned.
+Otherwise,
+.Fa len
+bytes are copied, and a NULL pointer is returned.
+.Sh SEE ALSO
+.Xr bcopy 3 ,
+.Xr memcpy 3 ,
+.Xr memmove 3 ,
+.Xr strcpy 3
+.Sh HISTORY
+The
+.Fn memccpy
+function first appeared in
+.Bx 4.4 .
diff --git a/lib/libc/string/memccpy.c b/lib/libc/string/memccpy.c
new file mode 100644
index 000000000000..6102a5bdedaf
--- /dev/null
+++ b/lib/libc/string/memccpy.c
@@ -0,0 +1,52 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)memccpy.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <string.h>
+
+void *
+memccpy(void *t, const void *f, int c, size_t n)
+{
+
+ if (n) {
+ unsigned char *tp = t;
+ const unsigned char *fp = f;
+ unsigned char uc = c;
+ do {
+ if ((*tp++ = *fp++) == uc)
+ return (tp);
+ } while (--n != 0);
+ }
+ return (0);
+}
diff --git a/lib/libc/string/memchr.3 b/lib/libc/string/memchr.3
new file mode 100644
index 000000000000..de571ca66e96
--- /dev/null
+++ b/lib/libc/string/memchr.3
@@ -0,0 +1,106 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek and the American National Standards Committee X3,
+.\" on Information Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)memchr.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd April 9, 2008
+.Dt MEMCHR 3
+.Os
+.Sh NAME
+.Nm memchr
+.Nd locate byte in byte string
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In string.h
+.Ft void *
+.Fn memchr "const void *b" "int c" "size_t len"
+.Ft void *
+.Fn memrchr "const void *b" "int c" "size_t len"
+.Sh DESCRIPTION
+The
+.Fn memchr
+function
+locates the first occurrence of
+.Fa c
+(converted to an
+.Vt "unsigned char" )
+in string
+.Fa b .
+.Pp
+The
+.Fn memrchr
+function behaves like
+.Fn memchr ,
+except that it locates the last occurrence of
+.Fa c
+in string
+.Fa b .
+.Sh RETURN VALUES
+The
+.Fn memchr
+and
+.Fn memrchr
+functions
+return a pointer to the byte located,
+or NULL if no such byte exists within
+.Fa len
+bytes.
+.Sh SEE ALSO
+.Xr memmem 3 ,
+.Xr strchr 3 ,
+.Xr strcspn 3 ,
+.Xr strpbrk 3 ,
+.Xr strrchr 3 ,
+.Xr strsep 3 ,
+.Xr strspn 3 ,
+.Xr strstr 3 ,
+.Xr strtok 3 ,
+.Xr wmemchr 3
+.Sh STANDARDS
+The
+.Fn memchr
+function
+conforms to
+.St -isoC .
+.Pp
+The
+.Fn memrchr
+function is a GNU extension and conforms to no standard.
+.Sh HISTORY
+The
+.Fn memrchr
+function first appeared in GNU libc 2.1.91, this implementation
+first appeared in
+.Fx 6.4 ,
+coming from
+.Ox 4.3 .
diff --git a/lib/libc/string/memchr.c b/lib/libc/string/memchr.c
new file mode 100644
index 000000000000..8020333dec3b
--- /dev/null
+++ b/lib/libc/string/memchr.c
@@ -0,0 +1,53 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)memchr.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <string.h>
+
+void *
+memchr(const void *s, int c, size_t n)
+{
+ if (n != 0) {
+ const unsigned char *p = s;
+
+ do {
+ if (*p++ == (unsigned char)c)
+ return ((void *)(p - 1));
+ } while (--n != 0);
+ }
+ return (NULL);
+}
diff --git a/lib/libc/string/memcmp.3 b/lib/libc/string/memcmp.3
new file mode 100644
index 000000000000..245e2abe1d71
--- /dev/null
+++ b/lib/libc/string/memcmp.3
@@ -0,0 +1,85 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek and the American National Standards Committee X3,
+.\" on Information Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)memcmp.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd August 15, 2016
+.Dt MEMCMP 3
+.Os
+.Sh NAME
+.Nm memcmp
+.Nd compare byte string
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In string.h
+.Ft int
+.Fn memcmp "const void *b1" "const void *b2" "size_t len"
+.Sh DESCRIPTION
+The
+.Fn memcmp
+function
+compares byte string
+.Fa b1
+against byte string
+.Fa b2 .
+Both strings are assumed to be
+.Fa len
+bytes long.
+.Sh RETURN VALUES
+The
+.Fn memcmp
+function
+returns zero if the two strings are identical,
+otherwise returns the difference between the first two differing bytes
+(treated as
+.Vt "unsigned char"
+values, so that
+.Sq Li \e200
+is greater than
+.Sq Li \&\e0 ,
+for example).
+Zero-length strings are always identical.
+.Sh SEE ALSO
+.Xr bcmp 3 ,
+.Xr strcasecmp 3 ,
+.Xr strcmp 3 ,
+.Xr strcoll 3 ,
+.Xr strxfrm 3 ,
+.Xr timingsafe_memcmp 3 ,
+.Xr wmemcmp 3
+.Sh STANDARDS
+The
+.Fn memcmp
+function
+conforms to
+.St -isoC .
diff --git a/lib/libc/string/memcmp.c b/lib/libc/string/memcmp.c
new file mode 100644
index 000000000000..d2d0f27d35ef
--- /dev/null
+++ b/lib/libc/string/memcmp.c
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)memcmp.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <string.h>
+
+/*
+ * Compare memory regions.
+ */
+int
+memcmp(const void *s1, const void *s2, size_t n)
+{
+ if (n != 0) {
+ const unsigned char *p1 = s1, *p2 = s2;
+
+ do {
+ if (*p1++ != *p2++)
+ return (*--p1 - *--p2);
+ } while (--n != 0);
+ }
+ return (0);
+}
diff --git a/lib/libc/string/memcpy.3 b/lib/libc/string/memcpy.3
new file mode 100644
index 000000000000..25a6c359f1da
--- /dev/null
+++ b/lib/libc/string/memcpy.3
@@ -0,0 +1,88 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek and the American National Standards Committee X3,
+.\" on Information Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)memcpy.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt MEMCPY 3
+.Os
+.Sh NAME
+.Nm memcpy
+.Nd copy byte string
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In string.h
+.Ft void *
+.Fn memcpy "void *dst" "const void *src" "size_t len"
+.Sh DESCRIPTION
+The
+.Fn memcpy
+function
+copies
+.Fa len
+bytes from string
+.Fa src
+to string
+.Fa dst .
+.Sh RETURN VALUES
+The
+.Fn memcpy
+function
+returns the original value of
+.Fa dst .
+.Sh SEE ALSO
+.Xr bcopy 3 ,
+.Xr memccpy 3 ,
+.Xr memmove 3 ,
+.Xr strcpy 3 ,
+.Xr wmemcpy 3
+.Sh STANDARDS
+The
+.Fn memcpy
+function
+conforms to
+.St -isoC .
+.Sh BUGS
+In this implementation
+.Fn memcpy
+is implemented using
+.Xr bcopy 3 ,
+and therefore the strings may overlap.
+On other systems, copying overlapping strings may produce surprises.
+Programs intended to be portable should use
+.Xr memmove 3
+when
+.Fa src
+and
+.Fa dst
+may overlap.
diff --git a/lib/libc/string/memcpy.c b/lib/libc/string/memcpy.c
new file mode 100644
index 000000000000..ed03856e54b4
--- /dev/null
+++ b/lib/libc/string/memcpy.c
@@ -0,0 +1,5 @@
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#define MEMCOPY
+#include "bcopy.c"
diff --git a/lib/libc/string/memmem.3 b/lib/libc/string/memmem.3
new file mode 100644
index 000000000000..a0db94fa408e
--- /dev/null
+++ b/lib/libc/string/memmem.3
@@ -0,0 +1,92 @@
+.\" Copyright (c) 2005 Pascal Gloor <pascal.gloor@spale.com>
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. The name of the author may not be used to endorse or promote
+.\" products derived from this software without specific prior written
+.\" permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 May 26, 2015
+.Dt MEMMEM 3
+.Os
+.Sh NAME
+.Nm memmem
+.Nd "locate a byte substring in a byte string"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In string.h
+.Ft "void *"
+.Fo memmem
+.Fa "const void *big" "size_t big_len"
+.Fa "const void *little" "size_t little_len"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn memmem
+function
+locates the first occurrence of the byte string
+.Fa little
+in the byte string
+.Fa big .
+.Sh RETURN VALUES
+If
+.Fa little_len
+is zero
+.Fa big
+is returned (that is, an empty little is deemed to match at the beginning of
+big);
+if
+.Fa little
+occurs nowhere in
+.Fa big ,
+.Dv NULL
+is returned;
+otherwise a pointer to the first character of the first occurrence of
+.Fa little
+is returned.
+.Sh SEE ALSO
+.Xr memchr 3 ,
+.Xr strchr 3 ,
+.Xr strstr 3
+.Sh CONFORMING TO
+.Fn memmem
+is a GNU extension.
+.Sh HISTORY
+The
+.Fn memmem
+function first appeared in
+.Fx 6.0 .
+.Sh AUTHORS
+.An Pascal Gloor Aq Mt pascal.gloor@spale.com
+.Sh BUGS
+This function was broken in Linux libc up to and including version 5.0.9
+and in GNU libc prior to version 2.1.
+Prior to
+.Fx 11.0
+.Nm
+returned
+.Dv NULL
+when
+.Fa little_len
+equals 0.
diff --git a/lib/libc/string/memmem.c b/lib/libc/string/memmem.c
new file mode 100644
index 000000000000..3fd05dfdbbc9
--- /dev/null
+++ b/lib/libc/string/memmem.c
@@ -0,0 +1,65 @@
+/*-
+ * Copyright (c) 2005 Pascal Gloor <pascal.gloor@spale.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 <string.h>
+
+/*
+ * Find the first occurrence of the byte string s in byte string l.
+ */
+
+void *
+memmem(const void *l, size_t l_len, const void *s, size_t s_len)
+{
+ register char *cur, *last;
+ const char *cl = (const char *)l;
+ const char *cs = (const char *)s;
+
+ /* empty "s" matches the beginning of "l" */
+ if (s_len == 0)
+ return (void *)cl;
+
+ /* "s" must be smaller or equal to "l" */
+ if (l_len < s_len)
+ return NULL;
+
+ /* special case where s_len == 1 */
+ if (s_len == 1)
+ return memchr(l, (int)*cs, l_len);
+
+ /* the last position where its possible to find "s" in "l" */
+ last = (char *)cl + l_len - s_len;
+
+ for (cur = (char *)cl; cur <= last; cur++)
+ if (cur[0] == cs[0] && memcmp(cur, cs, s_len) == 0)
+ return cur;
+
+ return NULL;
+}
diff --git a/lib/libc/string/memmove.3 b/lib/libc/string/memmove.3
new file mode 100644
index 000000000000..8d1c33cd9d4e
--- /dev/null
+++ b/lib/libc/string/memmove.3
@@ -0,0 +1,75 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek and the American National Standards Committee X3,
+.\" on Information Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)memmove.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt MEMMOVE 3
+.Os
+.Sh NAME
+.Nm memmove
+.Nd copy byte string
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In string.h
+.Ft void *
+.Fn memmove "void *dst" "const void *src" "size_t len"
+.Sh DESCRIPTION
+The
+.Fn memmove
+function
+copies
+.Fa len
+bytes from string
+.Fa src
+to string
+.Fa dst .
+The two strings may overlap;
+the copy is always done in a non-destructive manner.
+.Sh RETURN VALUES
+The
+.Fn memmove
+function returns the original value of
+.Fa dst .
+.Sh SEE ALSO
+.Xr bcopy 3 ,
+.Xr memccpy 3 ,
+.Xr memcpy 3 ,
+.Xr strcpy 3 ,
+.Xr wmemmove 3
+.Sh STANDARDS
+The
+.Fn memmove
+function
+conforms to
+.St -isoC .
diff --git a/lib/libc/string/memmove.c b/lib/libc/string/memmove.c
new file mode 100644
index 000000000000..05cf75a2ce6a
--- /dev/null
+++ b/lib/libc/string/memmove.c
@@ -0,0 +1,5 @@
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#define MEMMOVE
+#include "bcopy.c"
diff --git a/lib/libc/string/memrchr.c b/lib/libc/string/memrchr.c
new file mode 100644
index 000000000000..f477bc356491
--- /dev/null
+++ b/lib/libc/string/memrchr.c
@@ -0,0 +1,40 @@
+/* $OpenBSD: memrchr.c,v 1.2 2007/11/27 16:22:12 martynas Exp $ */
+
+/*
+ * Copyright (c) 2007 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $FreeBSD$
+ */
+
+#include <string.h>
+
+/*
+ * Reverse memchr()
+ * Find the last occurrence of 'c' in the buffer 's' of size 'n'.
+ */
+void *
+memrchr(const void *s, int c, size_t n)
+{
+ const unsigned char *cp;
+
+ if (n != 0) {
+ cp = (unsigned char *)s + n;
+ do {
+ if (*(--cp) == (unsigned char)c)
+ return((void *)cp);
+ } while (--n != 0);
+ }
+ return(NULL);
+}
diff --git a/lib/libc/string/memset.3 b/lib/libc/string/memset.3
new file mode 100644
index 000000000000..28d1919f706b
--- /dev/null
+++ b/lib/libc/string/memset.3
@@ -0,0 +1,72 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek and the American National Standards Committee X3,
+.\" on Information Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)memset.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt MEMSET 3
+.Os
+.Sh NAME
+.Nm memset
+.Nd write a byte to byte string
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In string.h
+.Ft void *
+.Fn memset "void *b" "int c" "size_t len"
+.Sh DESCRIPTION
+The
+.Fn memset
+function
+writes
+.Fa len
+bytes of value
+.Fa c
+(converted to an
+.Vt "unsigned char" )
+to the string
+.Fa b .
+.Sh RETURN VALUES
+The
+.Fn memset
+function returns its first argument.
+.Sh SEE ALSO
+.Xr bzero 3 ,
+.Xr swab 3 ,
+.Xr wmemset 3
+.Sh STANDARDS
+The
+.Fn memset
+function
+conforms to
+.St -isoC .
diff --git a/lib/libc/string/memset.c b/lib/libc/string/memset.c
new file mode 100644
index 000000000000..ad0d513933fe
--- /dev/null
+++ b/lib/libc/string/memset.c
@@ -0,0 +1,128 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Mike Hibler and Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)memset.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+#include <limits.h>
+
+#define wsize sizeof(u_int)
+#define wmask (wsize - 1)
+
+#ifdef BZERO
+#include <strings.h>
+
+#define RETURN return
+#define VAL 0
+#define WIDEVAL 0
+
+void
+bzero(void *dst0, size_t length)
+#else
+#include <string.h>
+
+#define RETURN return (dst0)
+#define VAL c0
+#define WIDEVAL c
+
+void *
+memset(void *dst0, int c0, size_t length)
+#endif
+{
+ size_t t;
+#ifndef BZERO
+ u_int c;
+#endif
+ u_char *dst;
+
+ dst = dst0;
+ /*
+ * If not enough words, just fill bytes. A length >= 2 words
+ * guarantees that at least one of them is `complete' after
+ * any necessary alignment. For instance:
+ *
+ * |-----------|-----------|-----------|
+ * |00|01|02|03|04|05|06|07|08|09|0A|00|
+ * ^---------------------^
+ * dst dst+length-1
+ *
+ * but we use a minimum of 3 here since the overhead of the code
+ * to do word writes is substantial.
+ */
+ if (length < 3 * wsize) {
+ while (length != 0) {
+ *dst++ = VAL;
+ --length;
+ }
+ RETURN;
+ }
+
+#ifndef BZERO
+ if ((c = (u_char)c0) != 0) { /* Fill the word. */
+ c = (c << 8) | c; /* u_int is 16 bits. */
+#if UINT_MAX > 0xffff
+ c = (c << 16) | c; /* u_int is 32 bits. */
+#endif
+#if UINT_MAX > 0xffffffff
+ c = (c << 32) | c; /* u_int is 64 bits. */
+#endif
+ }
+#endif
+ /* Align destination by filling in bytes. */
+ if ((t = (long)dst & wmask) != 0) {
+ t = wsize - t;
+ length -= t;
+ do {
+ *dst++ = VAL;
+ } while (--t != 0);
+ }
+
+ /* Fill words. Length was >= 2*words so we know t >= 1 here. */
+ t = length / wsize;
+ do {
+ *(u_int *)dst = WIDEVAL;
+ dst += wsize;
+ } while (--t != 0);
+
+ /* Mop up trailing bytes, if any. */
+ t = length & wmask;
+ if (t != 0)
+ do {
+ *dst++ = VAL;
+ } while (--t != 0);
+ RETURN;
+}
diff --git a/lib/libc/string/stpcpy.c b/lib/libc/string/stpcpy.c
new file mode 100644
index 000000000000..beb115948d8a
--- /dev/null
+++ b/lib/libc/string/stpcpy.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 1999
+ * David E. O'Brien
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strcpy.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <string.h>
+
+char *
+stpcpy(char * __restrict to, const char * __restrict from)
+{
+
+ for (; (*to = *from); ++from, ++to);
+ return(to);
+}
diff --git a/lib/libc/string/stpncpy.c b/lib/libc/string/stpncpy.c
new file mode 100644
index 000000000000..df70dc608cce
--- /dev/null
+++ b/lib/libc/string/stpncpy.c
@@ -0,0 +1,45 @@
+/*-
+ * Copyright (c) 2009 David Schultz <das@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <string.h>
+
+char *
+stpncpy(char * __restrict dst, const char * __restrict src, size_t n)
+{
+
+ for (; n--; dst++, src++) {
+ if (!(*dst = *src)) {
+ char *ret = dst;
+ while (n--)
+ *++dst = '\0';
+ return (ret);
+ }
+ }
+ return (dst);
+}
diff --git a/lib/libc/string/strcasecmp.3 b/lib/libc/string/strcasecmp.3
new file mode 100644
index 000000000000..4a13cc41d934
--- /dev/null
+++ b/lib/libc/string/strcasecmp.3
@@ -0,0 +1,118 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek.
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)strcasecmp.3 8.1 (Berkeley) 6/9/93
+.\" $FreeBSD$
+.\"
+.Dd May 29, 2014
+.Dt STRCASECMP 3
+.Os
+.Sh NAME
+.Nm strcasecmp ,
+.Nm strncasecmp
+.Nd compare strings, ignoring case
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In strings.h
+.Ft int
+.Fn strcasecmp "const char *s1" "const char *s2"
+.Ft int
+.Fn strncasecmp "const char *s1" "const char *s2" "size_t len"
+.In strings.h
+.In xlocale.h
+.Ft int
+.Fn strcasecmp_l "const char *s1" "const char *s2" "locale_t loc"
+.Ft int
+.Fn strncasecmp_l "const char *s1" "const char *s2" "size_t len" "locale_t loc"
+.Sh DESCRIPTION
+The
+.Fn strcasecmp
+and
+.Fn strncasecmp
+functions
+compare the null-terminated strings
+.Fa s1
+and
+.Fa s2 .
+.Pp
+The
+.Fn strncasecmp
+function compares at most
+.Fa len
+characters.
+The
+.Fn strcasecmp_l
+and
+.Fn strncasecmp_l
+functions do the same as their non-locale versions above, but take an
+explicit locale rather than using the current locale.
+.Sh RETURN VALUES
+The functions
+.Fn strcasecmp
+and
+.Fn strncasecmp
+return an integer greater than, equal to, or less than 0,
+depending on whether
+.Fa s1
+is lexicographically greater than, equal to, or less than
+.Fa s2
+after translation of each corresponding character to lower-case.
+The strings themselves are not modified.
+The comparison is done using unsigned characters, so that
+.Sq Li \e200
+is greater than
+.Ql \e0 .
+The functions
+.Fn strcasecmp_l
+and
+.Fn strncasecmp_l
+do the same but take explicit locales.
+.Sh SEE ALSO
+.Xr bcmp 3 ,
+.Xr memcmp 3 ,
+.Xr strcmp 3 ,
+.Xr strcoll 3 ,
+.Xr strxfrm 3 ,
+.Xr tolower 3 ,
+.Xr wcscasecmp 3
+.Sh HISTORY
+The
+.Fn strcasecmp
+and
+.Fn strncasecmp
+functions first appeared in
+.Bx 4.4 .
+Their prototypes existed previously in
+.In string.h
+before they were moved to
+.In strings.h
+for
+.St -p1003.1-2001
+compliance.
diff --git a/lib/libc/string/strcasecmp.c b/lib/libc/string/strcasecmp.c
new file mode 100644
index 000000000000..c72a660508c4
--- /dev/null
+++ b/lib/libc/string/strcasecmp.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 1987, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strcasecmp.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <strings.h>
+#include <ctype.h>
+#include "xlocale_private.h"
+
+int
+strcasecmp_l(const char *s1, const char *s2, locale_t locale)
+{
+ const u_char
+ *us1 = (const u_char *)s1,
+ *us2 = (const u_char *)s2;
+ FIX_LOCALE(locale);
+
+ while (tolower_l(*us1, locale) == tolower_l(*us2++, locale))
+ if (*us1++ == '\0')
+ return (0);
+ return (tolower_l(*us1, locale) - tolower_l(*--us2, locale));
+}
+int
+strcasecmp(const char *s1, const char *s2)
+{
+ return strcasecmp_l(s1, s2, __get_locale());
+}
+
+int
+strncasecmp_l(const char *s1, const char *s2, size_t n, locale_t locale)
+{
+ FIX_LOCALE(locale);
+ if (n != 0) {
+ const u_char
+ *us1 = (const u_char *)s1,
+ *us2 = (const u_char *)s2;
+
+ do {
+ if (tolower_l(*us1, locale) != tolower_l(*us2++, locale))
+ return (tolower_l(*us1, locale) - tolower_l(*--us2, locale));
+ if (*us1++ == '\0')
+ break;
+ } while (--n != 0);
+ }
+ return (0);
+}
+
+int
+strncasecmp(const char *s1, const char *s2, size_t n)
+{
+ return strncasecmp_l(s1, s2, n, __get_locale());
+}
diff --git a/lib/libc/string/strcasestr.c b/lib/libc/string/strcasestr.c
new file mode 100644
index 000000000000..cca16dc7bb63
--- /dev/null
+++ b/lib/libc/string/strcasestr.c
@@ -0,0 +1,72 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <ctype.h>
+#include <string.h>
+#include "xlocale_private.h"
+
+/*
+ * Find the first occurrence of find in s, ignore case.
+ */
+char *
+strcasestr_l(const char *s, const char *find, locale_t locale)
+{
+ char c, sc;
+ size_t len;
+ FIX_LOCALE(locale);
+
+ if ((c = *find++) != 0) {
+ c = tolower_l((unsigned char)c, locale);
+ len = strlen(find);
+ do {
+ do {
+ if ((sc = *s++) == 0)
+ return (NULL);
+ } while ((char)tolower_l((unsigned char)sc, locale) != c);
+ } while (strncasecmp_l(s, find, len, locale) != 0);
+ s--;
+ }
+ return ((char *)s);
+}
+char *
+strcasestr(const char *s, const char *find)
+{
+ return strcasestr_l(s, find, __get_locale());
+}
diff --git a/lib/libc/string/strcat.3 b/lib/libc/string/strcat.3
new file mode 100644
index 000000000000..802226980d27
--- /dev/null
+++ b/lib/libc/string/strcat.3
@@ -0,0 +1,155 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek and the American National Standards Committee X3,
+.\" on Information Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)strcat.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd December 1, 2009
+.Dt STRCAT 3
+.Os
+.Sh NAME
+.Nm strcat ,
+.Nm strncat
+.Nd concatenate strings
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In string.h
+.Ft char *
+.Fn strcat "char * restrict s" "const char * restrict append"
+.Ft char *
+.Fn strncat "char * restrict s" "const char * restrict append" "size_t count"
+.Sh DESCRIPTION
+The
+.Fn strcat
+and
+.Fn strncat
+functions
+append a copy of the null-terminated string
+.Fa append
+to the end of the null-terminated string
+.Fa s ,
+then add a terminating
+.Ql \e0 .
+The string
+.Fa s
+must have sufficient space to hold the result.
+.Pp
+The
+.Fn strncat
+function
+appends not more than
+.Fa count
+characters from
+.Fa append ,
+and then adds a terminating
+.Ql \e0 .
+.Sh RETURN VALUES
+The
+.Fn strcat
+and
+.Fn strncat
+functions
+return the pointer
+.Fa s .
+.Sh SEE ALSO
+.Xr bcopy 3 ,
+.Xr memccpy 3 ,
+.Xr memcpy 3 ,
+.Xr memmove 3 ,
+.Xr strcpy 3 ,
+.Xr strlcat 3 ,
+.Xr strlcpy 3 ,
+.Xr wcscat 3
+.Sh STANDARDS
+The
+.Fn strcat
+and
+.Fn strncat
+functions
+conform to
+.St -isoC .
+.Sh SECURITY CONSIDERATIONS
+The
+.Fn strcat
+function is easily misused in a manner
+which enables malicious users to arbitrarily change
+a running program's functionality through a buffer overflow attack.
+.Pp
+Avoid using
+.Fn strcat .
+Instead, use
+.Fn strncat
+or
+.Fn strlcat
+and ensure that no more characters are copied to the destination buffer
+than it can hold.
+.Pp
+Note that
+.Fn strncat
+can also be problematic.
+It may be a security concern for a string to be truncated at all.
+Since the truncated string will not be as long as the original,
+it may refer to a completely different resource
+and usage of the truncated resource
+could result in very incorrect behavior.
+Example:
+.Bd -literal
+void
+foo(const char *arbitrary_string)
+{
+ char onstack[8];
+
+#if defined(BAD)
+ /*
+ * This first strcat is bad behavior. Do not use strcat!
+ */
+ (void)strcat(onstack, arbitrary_string); /* BAD! */
+#elif defined(BETTER)
+ /*
+ * The following two lines demonstrate better use of
+ * strncat().
+ */
+ (void)strncat(onstack, arbitrary_string,
+ sizeof(onstack) - strlen(onstack) - 1);
+#elif defined(BEST)
+ /*
+ * These lines are even more robust due to testing for
+ * truncation.
+ */
+ if (strlen(arbitrary_string) + 1 >
+ sizeof(onstack) - strlen(onstack))
+ err(1, "onstack would be truncated");
+ (void)strncat(onstack, arbitrary_string,
+ sizeof(onstack) - strlen(onstack) - 1);
+#endif
+}
+.Ed
diff --git a/lib/libc/string/strcat.c b/lib/libc/string/strcat.c
new file mode 100644
index 000000000000..07a3c08c1a2f
--- /dev/null
+++ b/lib/libc/string/strcat.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strcat.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <string.h>
+
+char *
+strcat(char * __restrict s, const char * __restrict append)
+{
+ char *save = s;
+
+ for (; *s; ++s);
+ while ((*s++ = *append++));
+ return(save);
+}
diff --git a/lib/libc/string/strchr.3 b/lib/libc/string/strchr.3
new file mode 100644
index 000000000000..a39ea3e79d71
--- /dev/null
+++ b/lib/libc/string/strchr.3
@@ -0,0 +1,125 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek and the American National Standards Committee X3,
+.\" on Information Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)strchr.3 8.2 (Berkeley) 4/19/94
+.\" $FreeBSD$
+.\"
+.Dd February 13, 2013
+.Dt STRCHR 3
+.Os
+.Sh NAME
+.Nm strchr , strrchr , strchrnul
+.Nd locate character in string
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In string.h
+.Ft "char *"
+.Fn strchr "const char *s" "int c"
+.Ft "char *"
+.Fn strrchr "const char *s" "int c"
+.Ft "char *"
+.Fn strchrnul "const char *s" "int c"
+.Sh DESCRIPTION
+The
+.Fn strchr
+function locates the first occurrence of
+.Fa c
+(converted to a
+.Vt char )
+in the string pointed to by
+.Fa s .
+The terminating null character is considered part of the string;
+therefore if
+.Fa c
+is
+.Ql \e0 ,
+the functions locate the terminating
+.Ql \e0 .
+.Pp
+The
+.Fn strrchr
+function is identical to
+.Fn strchr
+except it locates the last occurrence of
+.Fa c .
+.Pp
+The
+.Fn strchrnul
+function is identical to
+.Fn strchr
+except that if
+.Fa c
+is not found in
+.Fa s
+a pointer to the terminating
+.Ql \e0
+is returned.
+.Sh RETURN VALUES
+The functions
+.Fn strchr
+and
+.Fn strrchr
+return a pointer to the located character, or
+.Dv NULL
+if the character does not appear in the string.
+.Pp
+.Fn strchrnul
+returns a pointer to the terminating
+.Ql \e0
+if the character does not appear in the string.
+.Sh SEE ALSO
+.Xr memchr 3 ,
+.Xr memmem 3 ,
+.Xr strcspn 3 ,
+.Xr strpbrk 3 ,
+.Xr strsep 3 ,
+.Xr strspn 3 ,
+.Xr strstr 3 ,
+.Xr strtok 3 ,
+.Xr wcschr 3
+.Sh STANDARDS
+The functions
+.Fn strchr
+and
+.Fn strrchr
+conform to
+.St -isoC .
+The function
+.Fn strchrnul
+is a
+.Tn GNU
+extension.
+.Sh HISTORY
+The
+.Fn strchrnul
+function first appeared in glibc 2.1.1 and was added in
+.Fx 10.0 .
diff --git a/lib/libc/string/strchr.c b/lib/libc/string/strchr.c
new file mode 100644
index 000000000000..ab83b3995a44
--- /dev/null
+++ b/lib/libc/string/strchr.c
@@ -0,0 +1,54 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)index.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stddef.h>
+#include <string.h>
+
+char *
+strchr(const char *p, int ch)
+{
+ char c;
+
+ c = ch;
+ for (;; ++p) {
+ if (*p == c)
+ return ((char *)p);
+ if (*p == '\0')
+ return (NULL);
+ }
+ /* NOTREACHED */
+}
+
+__weak_reference(strchr, index);
diff --git a/lib/libc/string/strchrnul.c b/lib/libc/string/strchrnul.c
new file mode 100644
index 000000000000..893468cbdcbc
--- /dev/null
+++ b/lib/libc/string/strchrnul.c
@@ -0,0 +1,50 @@
+/*-
+ * Copyright (c) 2013 Niclas Zeising
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 <stddef.h>
+#include <string.h>
+
+__weak_reference(__strchrnul, strchrnul);
+
+char *__strchrnul(const char *, int);
+
+char *
+__strchrnul(const char *p, int ch)
+{
+ char c;
+
+ c = ch;
+ for (;; ++p) {
+ if (*p == c || *p == '\0')
+ return ((char *)p);
+ }
+ /* NOTREACHED */
+}
+
diff --git a/lib/libc/string/strcmp.3 b/lib/libc/string/strcmp.3
new file mode 100644
index 000000000000..a79852d2a240
--- /dev/null
+++ b/lib/libc/string/strcmp.3
@@ -0,0 +1,101 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek and the American National Standards Committee X3,
+.\" on Information Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)strcmp.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd October 11, 2001
+.Dt STRCMP 3
+.Os
+.Sh NAME
+.Nm strcmp ,
+.Nm strncmp
+.Nd compare strings
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In string.h
+.Ft int
+.Fn strcmp "const char *s1" "const char *s2"
+.Ft int
+.Fn strncmp "const char *s1" "const char *s2" "size_t len"
+.Sh DESCRIPTION
+The
+.Fn strcmp
+and
+.Fn strncmp
+functions
+lexicographically compare the null-terminated strings
+.Fa s1
+and
+.Fa s2 .
+.Pp
+The
+.Fn strncmp
+function
+compares not more than
+.Fa len
+characters.
+Because
+.Fn strncmp
+is designed for comparing strings rather than binary data,
+characters that appear after a
+.Ql \e0
+character are not compared.
+.Sh RETURN VALUES
+The
+.Fn strcmp
+and
+.Fn strncmp
+functions return an integer greater than, equal to, or less than 0, according
+as the string
+.Fa s1
+is greater than, equal to, or less than the string
+.Fa s2 .
+The comparison is done using unsigned characters, so that
+.Ql \e200
+is greater than
+.Ql \e0 .
+.Sh SEE ALSO
+.Xr bcmp 3 ,
+.Xr memcmp 3 ,
+.Xr strcasecmp 3 ,
+.Xr strcoll 3 ,
+.Xr strxfrm 3 ,
+.Xr wcscmp 3
+.Sh STANDARDS
+The
+.Fn strcmp
+and
+.Fn strncmp
+functions
+conform to
+.St -isoC .
diff --git a/lib/libc/string/strcmp.c b/lib/libc/string/strcmp.c
new file mode 100644
index 000000000000..9daf624acce0
--- /dev/null
+++ b/lib/libc/string/strcmp.c
@@ -0,0 +1,51 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strcmp.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <string.h>
+
+/*
+ * Compare strings.
+ */
+int
+strcmp(const char *s1, const char *s2)
+{
+ while (*s1 == *s2++)
+ if (*s1++ == '\0')
+ return (0);
+ return (*(const unsigned char *)s1 - *(const unsigned char *)(s2 - 1));
+}
diff --git a/lib/libc/string/strcoll.3 b/lib/libc/string/strcoll.3
new file mode 100644
index 000000000000..d53a23d11b2f
--- /dev/null
+++ b/lib/libc/string/strcoll.3
@@ -0,0 +1,83 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek and the American National Standards Committee X3,
+.\" on Information Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)strcoll.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt STRCOLL 3
+.Os
+.Sh NAME
+.Nm strcoll
+.Nd compare strings according to current collation
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In string.h
+.Ft int
+.Fn strcoll "const char *s1" "const char *s2"
+.Ft int
+.Fn strcoll_l "const char *s1" "const char *s2" "locale_t loc"
+.Sh DESCRIPTION
+The
+.Fn strcoll
+function
+lexicographically compares the null-terminated strings
+.Fa s1
+and
+.Fa s2
+according to the current locale collation
+and returns an integer greater than, equal to, or less than 0,
+depending on whether
+.Fa s1
+is greater than, equal to, or less than
+.Fa s2 .
+If information about the current locale collation is not available,
+the value of
+.Fn strcmp s1 s2
+is returned.
+The
+.Fn strcoll_l
+function uses an explicit locale argument rather than the system locale.
+.Sh SEE ALSO
+.Xr setlocale 3 ,
+.Xr strcmp 3 ,
+.Xr strxfrm 3 ,
+.Xr wcscoll 3
+.Sh STANDARDS
+The
+.Fn strcoll
+function conforms to
+.St -isoC .
+The
+.Fn strcoll_l
+function conforms to
+.St -p1003.1-2008 .
diff --git a/lib/libc/string/strcoll.c b/lib/libc/string/strcoll.c
new file mode 100644
index 000000000000..7675e0a3ddf5
--- /dev/null
+++ b/lib/libc/string/strcoll.c
@@ -0,0 +1,118 @@
+/*-
+ * Copyright 2010 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 1995 Alex Tatmanjants <alex@elvisti.kiev.ua>
+ * at Electronni Visti IA, Kiev, Ukraine.
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 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 <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <wchar.h>
+#include "collate.h"
+
+
+/*
+ * In order to properly handle multibyte locales, its easiest to just
+ * convert to wide characters and then use wcscoll. However if an
+ * error occurs, we gracefully fall back to simple strcmp. Caller
+ * should check errno.
+ */
+int
+strcoll_l(const char *s, const char *s2, locale_t locale)
+{
+ int ret;
+ wchar_t *t1 = NULL, *t2 = NULL;
+ wchar_t *w1 = NULL, *w2 = NULL;
+ const char *cs1, *cs2;
+ mbstate_t mbs1;
+ mbstate_t mbs2;
+ size_t sz1, sz2;
+
+ memset(&mbs1, 0, sizeof (mbstate_t));
+ memset(&mbs2, 0, sizeof (mbstate_t));
+
+ /*
+ * The mbsrtowcs_l function can set the src pointer to null upon
+ * failure, so it should act on a copy to avoid:
+ * - sending null pointer to strcmp
+ * - having strcoll/strcoll_l change *s or *s2 to null
+ */
+ cs1 = s;
+ cs2 = s2;
+
+ FIX_LOCALE(locale);
+ struct xlocale_collate *table =
+ (struct xlocale_collate*)locale->components[XLC_COLLATE];
+
+ if (table->__collate_load_error)
+ goto error;
+
+ sz1 = strlen(s) + 1;
+ sz2 = strlen(s2) + 1;
+
+ /*
+ * Simple assumption: conversion to wide format is strictly
+ * reducing, i.e. a single byte (or multibyte character)
+ * cannot result in multiple wide characters.
+ */
+ if ((t1 = malloc(sz1 * sizeof (wchar_t))) == NULL)
+ goto error;
+ w1 = t1;
+ if ((t2 = malloc(sz2 * sizeof (wchar_t))) == NULL)
+ goto error;
+ w2 = t2;
+
+ if ((mbsrtowcs_l(w1, &cs1, sz1, &mbs1, locale)) == (size_t)-1)
+ goto error;
+
+ if ((mbsrtowcs_l(w2, &cs2, sz2, &mbs2, locale)) == (size_t)-1)
+ goto error;
+
+ ret = wcscoll_l(w1, w2, locale);
+ free(t1);
+ free(t2);
+
+ return (ret);
+
+error:
+ free(t1);
+ free(t2);
+ return (strcmp(s, s2));
+}
+
+int
+strcoll(const char *s, const char *s2)
+{
+ return strcoll_l(s, s2, __get_locale());
+}
+
diff --git a/lib/libc/string/strcpy.3 b/lib/libc/string/strcpy.3
new file mode 100644
index 000000000000..4d4a1ee7b3ce
--- /dev/null
+++ b/lib/libc/string/strcpy.3
@@ -0,0 +1,212 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek and the American National Standards Committee X3,
+.\" on Information Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)strcpy.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd February 28, 2009
+.Dt STRCPY 3
+.Os
+.Sh NAME
+.Nm stpcpy, stpncpy, strcpy , strncpy
+.Nd copy strings
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In string.h
+.Ft char *
+.Fn stpcpy "char * restrict dst" "const char * restrict src"
+.Ft char *
+.Fn stpncpy "char * restrict dst" "const char * restrict src" "size_t len"
+.Ft char *
+.Fn strcpy "char * restrict dst" "const char * restrict src"
+.Ft char *
+.Fn strncpy "char * restrict dst" "const char * restrict src" "size_t len"
+.Sh DESCRIPTION
+The
+.Fn stpcpy
+and
+.Fn strcpy
+functions
+copy the string
+.Fa src
+to
+.Fa dst
+(including the terminating
+.Ql \e0
+character.)
+.Pp
+The
+.Fn stpncpy
+and
+.Fn strncpy
+functions copy at most
+.Fa len
+characters from
+.Fa src
+into
+.Fa dst .
+If
+.Fa src
+is less than
+.Fa len
+characters long,
+the remainder of
+.Fa dst
+is filled with
+.Ql \e0
+characters.
+Otherwise,
+.Fa dst
+is
+.Em not
+terminated.
+.Sh RETURN VALUES
+The
+.Fn strcpy
+and
+.Fn strncpy
+functions
+return
+.Fa dst .
+The
+.Fn stpcpy
+and
+.Fn stpncpy
+functions return a pointer to the terminating
+.Ql \e0
+character of
+.Fa dst .
+If
+.Fn stpncpy
+does not terminate
+.Fa dst
+with a
+.Dv NUL
+character, it instead returns a pointer to
+.Li dst[n]
+(which does not necessarily refer to a valid memory location.)
+.Sh EXAMPLES
+The following sets
+.Va chararray
+to
+.Dq Li abc\e0\e0\e0 :
+.Bd -literal -offset indent
+char chararray[6];
+
+(void)strncpy(chararray, "abc", sizeof(chararray));
+.Ed
+.Pp
+The following sets
+.Va chararray
+to
+.Dq Li abcdef :
+.Bd -literal -offset indent
+char chararray[6];
+
+(void)strncpy(chararray, "abcdefgh", sizeof(chararray));
+.Ed
+.Pp
+Note that it does
+.Em not
+.Tn NUL
+terminate
+.Va chararray
+because the length of the source string is greater than or equal
+to the length argument.
+.Pp
+The following copies as many characters from
+.Va input
+to
+.Va buf
+as will fit and
+.Tn NUL
+terminates the result.
+Because
+.Fn strncpy
+does
+.Em not
+guarantee to
+.Tn NUL
+terminate the string itself, this must be done explicitly.
+.Bd -literal -offset indent
+char buf[1024];
+
+(void)strncpy(buf, input, sizeof(buf) - 1);
+buf[sizeof(buf) - 1] = '\e0';
+.Ed
+.Pp
+This could be better achieved using
+.Xr strlcpy 3 ,
+as shown in the following example:
+.Pp
+.Dl "(void)strlcpy(buf, input, sizeof(buf));"
+.Pp
+Note that because
+.Xr strlcpy 3
+is not defined in any standards, it should
+only be used when portability is not a concern.
+.Sh SEE ALSO
+.Xr bcopy 3 ,
+.Xr memccpy 3 ,
+.Xr memcpy 3 ,
+.Xr memmove 3 ,
+.Xr strlcpy 3 ,
+.Xr wcscpy 3
+.Sh STANDARDS
+The
+.Fn strcpy
+and
+.Fn strncpy
+functions
+conform to
+.St -isoC .
+The
+.Fn stpcpy
+and
+.Fn stpncpy
+functions conform to
+.St -p1003.1-2008 .
+.Sh HISTORY
+The
+.Fn stpcpy
+function first appeared in
+.Fx 4.4 ,
+and
+.Fn stpncpy
+was added in
+.Fx 8.0 .
+.Sh SECURITY CONSIDERATIONS
+The
+.Fn strcpy
+function is easily misused in a manner which enables malicious users
+to arbitrarily change a running program's functionality through a
+buffer overflow attack.
diff --git a/lib/libc/string/strcpy.c b/lib/libc/string/strcpy.c
new file mode 100644
index 000000000000..8a48d0d0d732
--- /dev/null
+++ b/lib/libc/string/strcpy.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strcpy.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <string.h>
+
+char *
+strcpy(char * __restrict to, const char * __restrict from)
+{
+ char *save = to;
+
+ for (; (*to = *from); ++from, ++to);
+ return(save);
+}
diff --git a/lib/libc/string/strcspn.c b/lib/libc/string/strcspn.c
new file mode 100644
index 000000000000..3879a3b085c7
--- /dev/null
+++ b/lib/libc/string/strcspn.c
@@ -0,0 +1,72 @@
+/*-
+ * Copyright (c) 2005 David Schultz <das@FreeBSD.ORG>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <limits.h>
+#include <string.h>
+
+#define IDX(c) ((u_char)(c) / LONG_BIT)
+#define BIT(c) ((u_long)1 << ((u_char)(c) % LONG_BIT))
+
+size_t
+strcspn(const char *s, const char *charset)
+{
+ /*
+ * NB: idx and bit are temporaries whose use causes gcc 3.4.2 to
+ * generate better code. Without them, gcc gets a little confused.
+ */
+ const char *s1;
+ u_long bit;
+ u_long tbl[(UCHAR_MAX + 1) / LONG_BIT];
+ int idx;
+
+ if(*s == '\0')
+ return (0);
+
+#if LONG_BIT == 64 /* always better to unroll on 64-bit architectures */
+ tbl[0] = 1;
+ tbl[3] = tbl[2] = tbl[1] = 0;
+#else
+ for (tbl[0] = idx = 1; idx < sizeof(tbl) / sizeof(tbl[0]); idx++)
+ tbl[idx] = 0;
+#endif
+ for (; *charset != '\0'; charset++) {
+ idx = IDX(*charset);
+ bit = BIT(*charset);
+ tbl[idx] |= bit;
+ }
+
+ for(s1 = s; ; s1++) {
+ idx = IDX(*s1);
+ bit = BIT(*s1);
+ if ((tbl[idx] & bit) != 0)
+ break;
+ }
+ return (s1 - s);
+}
diff --git a/lib/libc/string/strdup.3 b/lib/libc/string/strdup.3
new file mode 100644
index 000000000000..f9ed5c208362
--- /dev/null
+++ b/lib/libc/string/strdup.3
@@ -0,0 +1,84 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)strdup.3 8.1 (Berkeley) 6/9/93
+.\" $FreeBSD$
+.\"
+.Dd December 5, 2008
+.Dt STRDUP 3
+.Os
+.Sh NAME
+.Nm strdup ,
+.Nm strndup
+.Nd save a copy of a string
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In string.h
+.Ft char *
+.Fn strdup "const char *str"
+.Ft char *
+.Fn strndup "const char *str" "size_t len"
+.Sh DESCRIPTION
+The
+.Fn strdup
+function
+allocates sufficient memory for a copy
+of the string
+.Fa str ,
+does the copy, and returns a pointer to it.
+The pointer may subsequently be used as an
+argument to the function
+.Xr free 3 .
+.Pp
+If insufficient memory is available, NULL is returned and
+.Va errno
+is set to
+.Er ENOMEM .
+.Pp
+The
+.Fn strndup
+function copies at most
+.Fa len
+characters from the string
+.Fa str
+always
+.Dv NUL
+terminating the copied string.
+.Sh SEE ALSO
+.Xr free 3 ,
+.Xr malloc 3 ,
+.Xr wcsdup 3
+.Sh HISTORY
+The
+.Fn strdup
+function first appeared in
+.Bx 4.4 .
+The
+.Fn strndup
+function was added in
+.Fx 7.2 .
diff --git a/lib/libc/string/strdup.c b/lib/libc/string/strdup.c
new file mode 100644
index 000000000000..8e90aa05fcb9
--- /dev/null
+++ b/lib/libc/string/strdup.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strdup.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+char *
+strdup(const char *str)
+{
+ size_t len;
+ char *copy;
+
+ len = strlen(str) + 1;
+ if ((copy = malloc(len)) == NULL)
+ return (NULL);
+ memcpy(copy, str, len);
+ return (copy);
+}
diff --git a/lib/libc/string/strerror.3 b/lib/libc/string/strerror.3
new file mode 100644
index 000000000000..a47494fd0784
--- /dev/null
+++ b/lib/libc/string/strerror.3
@@ -0,0 +1,190 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)strerror.3 8.1 (Berkeley) 6/9/93
+.\" $FreeBSD$
+.\"
+.Dd April 5, 2011
+.Dt STRERROR 3
+.Os
+.Sh NAME
+.Nm perror ,
+.Nm strerror ,
+.Nm strerror_r ,
+.Nm sys_errlist ,
+.Nm sys_nerr
+.Nd system error messages
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdio.h
+.Ft void
+.Fn perror "const char *string"
+.Vt extern const char * const sys_errlist[] ;
+.Vt extern const int sys_nerr ;
+.In string.h
+.Ft "char *"
+.Fn strerror "int errnum"
+.Ft int
+.Fn strerror_r "int errnum" "char *strerrbuf" "size_t buflen"
+.Sh DESCRIPTION
+The
+.Fn strerror ,
+.Fn strerror_r
+and
+.Fn perror
+functions look up the error message string corresponding to an
+error number.
+.Pp
+The
+.Fn strerror
+function accepts an error number argument
+.Fa errnum
+and returns a pointer to the corresponding
+message string.
+.Pp
+The
+.Fn strerror_r
+function renders the same result into
+.Fa strerrbuf
+for a maximum of
+.Fa buflen
+characters and returns 0 upon success.
+.Pp
+The
+.Fn perror
+function finds the error message corresponding to the current
+value of the global variable
+.Va errno
+.Pq Xr intro 2
+and writes it, followed by a newline, to the
+standard error file descriptor.
+If the argument
+.Fa string
+is
+.Pf non- Dv NULL
+and does not point to the null character,
+this string is prepended to the message
+string and separated from it by
+a colon and space
+.Pq Dq Li ":\ " ;
+otherwise, only the error message string is printed.
+.Pp
+If the error number is not recognized, these functions return an error message
+string containing
+.Dq Li "Unknown error:\ "
+followed by the error number in decimal.
+The
+.Fn strerror
+and
+.Fn strerror_r
+functions return
+.Er EINVAL
+as a warning.
+Error numbers recognized by this implementation fall in
+the range 0 <
+.Fa errnum
+<
+.Fa sys_nerr .
+The number 0 is also recognized, although applications that take advantage of
+this are likely to use unspecified values of
+.Va errno .
+.Pp
+If insufficient storage is provided in
+.Fa strerrbuf
+(as specified in
+.Fa buflen )
+to contain the error string,
+.Fn strerror_r
+returns
+.Er ERANGE
+and
+.Fa strerrbuf
+will contain an error message that has been truncated and
+.Dv NUL
+terminated to fit the length specified by
+.Fa buflen .
+.Pp
+The message strings can be accessed directly using the external
+array
+.Va sys_errlist .
+The external value
+.Va sys_nerr
+contains a count of the messages in
+.Va sys_errlist .
+The use of these variables is deprecated;
+.Fn strerror
+or
+.Fn strerror_r
+should be used instead.
+.Sh SEE ALSO
+.Xr intro 2 ,
+.Xr err 3 ,
+.Xr psignal 3
+.Sh STANDARDS
+The
+.Fn perror
+and
+.Fn strerror
+functions conform to
+.St -isoC-99 .
+The
+.Fn strerror_r
+function conforms to
+.St -p1003.1-2001 .
+.Sh HISTORY
+The
+.Fn strerror
+and
+.Fn perror
+functions first appeared in
+.Bx 4.4 .
+The
+.Fn strerror_r
+function was implemented in
+.Fx 4.4
+by
+.An Wes Peters Aq Mt wes@FreeBSD.org .
+.Sh BUGS
+The
+.Fn strerror
+function returns its result in a static buffer which
+will be overwritten by subsequent calls.
+.Pp
+The return type for
+.Fn strerror
+is missing a type-qualifier; it should actually be
+.Vt const char * .
+.Pp
+Programs that use the deprecated
+.Va sys_errlist
+variable often fail to compile because they declare it
+inconsistently.
diff --git a/lib/libc/string/strerror.c b/lib/libc/string/strerror.c
new file mode 100644
index 000000000000..1d7a385bd9ea
--- /dev/null
+++ b/lib/libc/string/strerror.c
@@ -0,0 +1,128 @@
+/*-
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strerror.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#if defined(NLS)
+#include <nl_types.h>
+#endif
+
+#include <limits.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "errlst.h"
+
+#define UPREFIX "Unknown error"
+
+/*
+ * Define a buffer size big enough to describe a 64-bit signed integer
+ * converted to ASCII decimal (19 bytes), with an optional leading sign
+ * (1 byte); finally, we get the prefix, delimiter (": ") and a trailing
+ * NUL from UPREFIX.
+ */
+#define EBUFSIZE (20 + 2 + sizeof(UPREFIX))
+
+/*
+ * Doing this by hand instead of linking with stdio(3) avoids bloat for
+ * statically linked binaries.
+ */
+static void
+errstr(int num, char *uprefix, char *buf, size_t len)
+{
+ char *t;
+ unsigned int uerr;
+ char tmp[EBUFSIZE];
+
+ t = tmp + sizeof(tmp);
+ *--t = '\0';
+ uerr = (num >= 0) ? num : -num;
+ do {
+ *--t = "0123456789"[uerr % 10];
+ } while (uerr /= 10);
+ if (num < 0)
+ *--t = '-';
+ *--t = ' ';
+ *--t = ':';
+ strlcpy(buf, uprefix, len);
+ strlcat(buf, t, len);
+}
+
+int
+strerror_r(int errnum, char *strerrbuf, size_t buflen)
+{
+ int retval = 0;
+#if defined(NLS)
+ int saved_errno = errno;
+ nl_catd catd;
+ catd = catopen("libc", NL_CAT_LOCALE);
+#endif
+
+ if (errnum < 0 || errnum >= __hidden_sys_nerr) {
+ errstr(errnum,
+#if defined(NLS)
+ catgets(catd, 1, 0xffff, UPREFIX),
+#else
+ UPREFIX,
+#endif
+ strerrbuf, buflen);
+ retval = EINVAL;
+ } else {
+ if (strlcpy(strerrbuf,
+#if defined(NLS)
+ catgets(catd, 1, errnum, __hidden_sys_errlist[errnum]),
+#else
+ __hidden_sys_errlist[errnum],
+#endif
+ buflen) >= buflen)
+ retval = ERANGE;
+ }
+
+#if defined(NLS)
+ catclose(catd);
+ errno = saved_errno;
+#endif
+
+ return (retval);
+}
+
+char *
+strerror(int num)
+{
+ static char ebuf[NL_TEXTMAX];
+
+ if (strerror_r(num, ebuf, sizeof(ebuf)) != 0)
+ errno = EINVAL;
+ return (ebuf);
+}
diff --git a/lib/libc/string/string.3 b/lib/libc/string/string.3
new file mode 100644
index 000000000000..e9ef152bb8ee
--- /dev/null
+++ b/lib/libc/string/string.3
@@ -0,0 +1,157 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek.
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)string.3 8.2 (Berkeley) 12/11/93
+.\" $FreeBSD$
+.\"
+.Dd December 11, 1993
+.Dt STRING 3
+.Os
+.Sh NAME
+.Nm stpcpy ,
+.Nm strcat ,
+.Nm strncat ,
+.Nm strchr ,
+.Nm strrchr ,
+.Nm strcmp ,
+.Nm strncmp ,
+.Nm strcasecmp ,
+.Nm strncasecmp ,
+.Nm strcpy ,
+.Nm strncpy ,
+.Nm strerror ,
+.Nm strlen ,
+.Nm strpbrk ,
+.Nm strsep ,
+.Nm strspn ,
+.Nm strcspn ,
+.Nm strstr ,
+.Nm strtok ,
+.Nm index ,
+.Nm rindex
+.Nd string specific functions
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In string.h
+.Ft char *
+.Fn stpcpy "char *dst" "const char *src"
+.Ft char *
+.Fn strcat "char *s" "const char * append"
+.Ft char *
+.Fn strncat "char *s" "const char *append" "size_t count"
+.Ft char *
+.Fn strchr "const char *s" "int c"
+.Ft char *
+.Fn strrchr "const char *s" "int c"
+.Ft int
+.Fn strcmp "const char *s1" "const char *s2"
+.Ft int
+.Fn strncmp "const char *s1" "const char *s2" "size_t count"
+.Ft int
+.Fn strcasecmp "const char *s1" "const char *s2"
+.Ft int
+.Fn strncasecmp "const char *s1" "const char *s2" "size_t count"
+.Ft char *
+.Fn strcpy "char *dst" "const char *src"
+.Ft char *
+.Fn strncpy "char *dst" "const char *src" "size_t count"
+.Ft char *
+.Fn strerror "int errno"
+.Ft size_t
+.Fn strlen "const char *s"
+.Ft char *
+.Fn strpbrk "const char *s" "const char *charset"
+.Ft char *
+.Fn strsep "char **stringp" "const char *delim"
+.Ft size_t
+.Fn strspn "const char *s" "const char *charset"
+.Ft size_t
+.Fn strcspn "const char *s" "const char *charset"
+.Ft char *
+.Fn strstr "const char *big" "const char *little"
+.Ft char *
+.Fn strtok "char *s" "const char *delim"
+.Ft char *
+.Fn index "const char *s" "int c"
+.Ft char *
+.Fn rindex "const char *s" "int c"
+.Sh DESCRIPTION
+The string
+functions manipulate strings terminated by a
+null byte.
+.Pp
+See the specific manual pages for more information.
+For manipulating variable length generic objects as byte
+strings (without the null byte check), see
+.Xr bstring 3 .
+.Pp
+Except as noted in their specific manual pages,
+the string functions do not test the destination
+for size limitations.
+.Sh SEE ALSO
+.Xr bstring 3 ,
+.Xr index 3 ,
+.Xr rindex 3 ,
+.Xr stpcpy 3 ,
+.Xr strcasecmp 3 ,
+.Xr strcat 3 ,
+.Xr strchr 3 ,
+.Xr strcmp 3 ,
+.Xr strcpy 3 ,
+.Xr strcspn 3 ,
+.Xr strerror 3 ,
+.Xr strlen 3 ,
+.Xr strpbrk 3 ,
+.Xr strrchr 3 ,
+.Xr strsep 3 ,
+.Xr strspn 3 ,
+.Xr strstr 3 ,
+.Xr strtok 3
+.Sh STANDARDS
+The
+.Fn strcat ,
+.Fn strncat ,
+.Fn strchr ,
+.Fn strrchr ,
+.Fn strcmp ,
+.Fn strncmp ,
+.Fn strcpy ,
+.Fn strncpy ,
+.Fn strerror ,
+.Fn strlen ,
+.Fn strpbrk ,
+.Fn strspn ,
+.Fn strcspn ,
+.Fn strstr ,
+and
+.Fn strtok
+functions
+conform to
+.St -isoC .
diff --git a/lib/libc/string/strlcat.c b/lib/libc/string/strlcat.c
new file mode 100644
index 000000000000..f5ed6c6cf70c
--- /dev/null
+++ b/lib/libc/string/strlcat.c
@@ -0,0 +1,58 @@
+/* $OpenBSD: strlcat.c,v 1.15 2015/03/02 21:41:08 millert Exp $ */
+
+/*
+ * Copyright (c) 1998, 2015 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <string.h>
+
+/*
+ * Appends src to string dst of size dsize (unlike strncat, dsize is the
+ * full size of dst, not space left). At most dsize-1 characters
+ * will be copied. Always NUL terminates (unless dsize <= strlen(dst)).
+ * Returns strlen(src) + MIN(dsize, strlen(initial dst)).
+ * If retval >= dsize, truncation occurred.
+ */
+size_t
+strlcat(char * __restrict dst, const char * __restrict src, size_t dsize)
+{
+ const char *odst = dst;
+ const char *osrc = src;
+ size_t n = dsize;
+ size_t dlen;
+
+ /* Find the end of dst and adjust bytes left but don't go past end. */
+ while (n-- != 0 && *dst != '\0')
+ dst++;
+ dlen = dst - odst;
+ n = dsize - dlen;
+
+ if (n-- == 0)
+ return(dlen + strlen(src));
+ while (*src != '\0') {
+ if (n != 0) {
+ *dst++ = *src;
+ n--;
+ }
+ src++;
+ }
+ *dst = '\0';
+
+ return(dlen + (src - osrc)); /* count does not include NUL */
+}
diff --git a/lib/libc/string/strlcpy.3 b/lib/libc/string/strlcpy.3
new file mode 100644
index 000000000000..30a758840ce7
--- /dev/null
+++ b/lib/libc/string/strlcpy.3
@@ -0,0 +1,200 @@
+.\" $OpenBSD: strlcpy.3,v 1.26 2013/09/30 12:02:35 millert Exp $
+.\"
+.\" Copyright (c) 1998, 2000 Todd C. Miller <Todd.Miller@courtesan.com>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+.\" AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+.\" THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+.\" EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+.\" PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+.\" OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+.\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd February 26, 2016
+.Dt STRLCPY 3
+.Os
+.Sh NAME
+.Nm strlcpy ,
+.Nm strlcat
+.Nd size-bounded string copying and concatenation
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In string.h
+.Ft size_t
+.Fn strlcpy "char * restrict dst" "const char * restrict src" "size_t dstsize"
+.Ft size_t
+.Fn strlcat "char * restrict dst" "const char * restrict src" "size_t dstsize"
+.Sh DESCRIPTION
+The
+.Fn strlcpy
+and
+.Fn strlcat
+functions copy and concatenate strings with the
+same input parameters and output result as
+.Xr snprintf 3 .
+They are designed to be safer, more consistent, and less error
+prone replacements for the easily misused functions
+.Xr strncpy 3
+and
+.Xr strncat 3 .
+.Pp
+.Fn strlcpy
+and
+.Fn strlcat
+take the full size of the destination buffer and guarantee
+NUL-termination if there is room.
+Note that room for the NUL should be included in
+.Fa dstsize .
+.Pp
+.Fn strlcpy
+copies up to
+.Fa dstsize
+\- 1 characters from the string
+.Fa src
+to
+.Fa dst ,
+NUL-terminating the result if
+.Fa dstsize
+is not 0.
+.Pp
+.Fn strlcat
+appends string
+.Fa src
+to the end of
+.Fa dst .
+It will append at most
+.Fa dstsize
+\- strlen(dst) \- 1 characters.
+It will then NUL-terminate, unless
+.Fa dstsize
+is 0 or the original
+.Fa dst
+string was longer than
+.Fa dstsize
+(in practice this should not happen
+as it means that either
+.Fa dstsize
+is incorrect or that
+.Fa dst
+is not a proper string).
+.Pp
+If the
+.Fa src
+and
+.Fa dst
+strings overlap, the behavior is undefined.
+.Sh RETURN VALUES
+Besides quibbles over the return type
+.Pf ( Va size_t
+versus
+.Va int )
+and signal handler safety
+.Pf ( Xr snprintf 3
+is not entirely safe on some systems), the
+following two are equivalent:
+.Bd -literal -offset indent
+n = strlcpy(dst, src, len);
+n = snprintf(dst, len, "%s", src);
+.Ed
+.Pp
+Like
+.Xr snprintf 3 ,
+the
+.Fn strlcpy
+and
+.Fn strlcat
+functions return the total length of the string they tried to create.
+For
+.Fn strlcpy
+that means the length of
+.Fa src .
+For
+.Fn strlcat
+that means the initial length of
+.Fa dst
+plus
+the length of
+.Fa src .
+.Pp
+If the return value is
+.Cm >=
+.Va dstsize ,
+the output string has been truncated.
+It is the caller's responsibility to handle this.
+.Sh EXAMPLES
+The following code fragment illustrates the simple case:
+.Bd -literal -offset indent
+char *s, *p, buf[BUFSIZ];
+
+\&...
+
+(void)strlcpy(buf, s, sizeof(buf));
+(void)strlcat(buf, p, sizeof(buf));
+.Ed
+.Pp
+To detect truncation, perhaps while building a pathname, something
+like the following might be used:
+.Bd -literal -offset indent
+char *dir, *file, pname[MAXPATHLEN];
+
+\&...
+
+if (strlcpy(pname, dir, sizeof(pname)) >= sizeof(pname))
+ goto toolong;
+if (strlcat(pname, file, sizeof(pname)) >= sizeof(pname))
+ goto toolong;
+.Ed
+.Pp
+Since it is known how many characters were copied the first time, things
+can be sped up a bit by using a copy instead of an append:
+.Bd -literal -offset indent
+char *dir, *file, pname[MAXPATHLEN];
+size_t n;
+
+\&...
+
+n = strlcpy(pname, dir, sizeof(pname));
+if (n >= sizeof(pname))
+ goto toolong;
+if (strlcpy(pname + n, file, sizeof(pname) - n) >= sizeof(pname) - n)
+ goto toolong;
+.Ed
+.Pp
+However, one may question the validity of such optimizations, as they
+defeat the whole purpose of
+.Fn strlcpy
+and
+.Fn strlcat .
+As a matter of fact, the first version of this manual page got it wrong.
+.Sh SEE ALSO
+.Xr snprintf 3 ,
+.Xr strncat 3 ,
+.Xr strncpy 3 ,
+.Xr wcslcpy 3
+.Sh HISTORY
+The
+.Fn strlcpy
+and
+.Fn strlcat
+functions first appeared in
+.Ox 2.4 ,
+and
+.Fx 3.3 .
diff --git a/lib/libc/string/strlcpy.c b/lib/libc/string/strlcpy.c
new file mode 100644
index 000000000000..019d2316a046
--- /dev/null
+++ b/lib/libc/string/strlcpy.c
@@ -0,0 +1,53 @@
+/* $OpenBSD: strlcpy.c,v 1.12 2015/01/15 03:54:12 millert Exp $ */
+
+/*
+ * Copyright (c) 1998, 2015 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <string.h>
+
+/*
+ * Copy string src to buffer dst of size dsize. At most dsize-1
+ * chars will be copied. Always NUL terminates (unless dsize == 0).
+ * Returns strlen(src); if retval >= dsize, truncation occurred.
+ */
+size_t
+strlcpy(char * __restrict dst, const char * __restrict src, size_t dsize)
+{
+ const char *osrc = src;
+ size_t nleft = dsize;
+
+ /* Copy as many bytes as will fit. */
+ if (nleft != 0) {
+ while (--nleft != 0) {
+ if ((*dst++ = *src++) == '\0')
+ break;
+ }
+ }
+
+ /* Not enough room in dst, add NUL and traverse rest of src. */
+ if (nleft == 0) {
+ if (dsize != 0)
+ *dst = '\0'; /* NUL-terminate dst */
+ while (*src++)
+ ;
+ }
+
+ return(src - osrc - 1); /* count does not include NUL */
+}
diff --git a/lib/libc/string/strlen.3 b/lib/libc/string/strlen.3
new file mode 100644
index 000000000000..fb2fa3cd2acb
--- /dev/null
+++ b/lib/libc/string/strlen.3
@@ -0,0 +1,92 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek and the American National Standards Committee X3,
+.\" on Information Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)strlen.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd February 28, 2009
+.Dt STRLEN 3
+.Os
+.Sh NAME
+.Nm strlen, strnlen
+.Nd find length of string
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In string.h
+.Ft size_t
+.Fn strlen "const char *s"
+.Ft size_t
+.Fn strnlen "const char *s" "size_t maxlen"
+.Sh DESCRIPTION
+The
+.Fn strlen
+function
+computes the length of the string
+.Fa s .
+The
+.Fn strnlen
+function attempts to compute the length of
+.Fa s ,
+but never scans beyond the first
+.Fa maxlen
+bytes of
+.Fa s .
+.Sh RETURN VALUES
+The
+.Fn strlen
+function
+returns
+the number of characters that precede the
+terminating
+.Dv NUL
+character.
+The
+.Fn strnlen
+function returns either the same result as
+.Fn strlen
+or
+.Fa maxlen ,
+whichever is smaller.
+.Sh SEE ALSO
+.Xr string 3 ,
+.Xr wcslen 3 ,
+.Xr wcswidth 3
+.Sh STANDARDS
+The
+.Fn strlen
+function
+conforms to
+.St -isoC .
+The
+.Fn strnlen
+function conforms to
+.St -p1003.1-2008 .
diff --git a/lib/libc/string/strlen.c b/lib/libc/string/strlen.c
new file mode 100644
index 000000000000..2bc1f2b1febb
--- /dev/null
+++ b/lib/libc/string/strlen.c
@@ -0,0 +1,130 @@
+/*-
+ * Copyright (c) 2009, 2010 Xin LI <delphij@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/limits.h>
+#include <sys/types.h>
+#include <string.h>
+
+/*
+ * Portable strlen() for 32-bit and 64-bit systems.
+ *
+ * Rationale: it is generally much more efficient to do word length
+ * operations and avoid branches on modern computer systems, as
+ * compared to byte-length operations with a lot of branches.
+ *
+ * The expression:
+ *
+ * ((x - 0x01....01) & ~x & 0x80....80)
+ *
+ * would evaluate to a non-zero value iff any of the bytes in the
+ * original word is zero.
+ *
+ * On multi-issue processors, we can divide the above expression into:
+ * a) (x - 0x01....01)
+ * b) (~x & 0x80....80)
+ * c) a & b
+ *
+ * Where, a) and b) can be partially computed in parallel.
+ *
+ * The algorithm above is found on "Hacker's Delight" by
+ * Henry S. Warren, Jr.
+ */
+
+/* Magic numbers for the algorithm */
+#if LONG_BIT == 32
+static const unsigned long mask01 = 0x01010101;
+static const unsigned long mask80 = 0x80808080;
+#elif LONG_BIT == 64
+static const unsigned long mask01 = 0x0101010101010101;
+static const unsigned long mask80 = 0x8080808080808080;
+#else
+#error Unsupported word size
+#endif
+
+#define LONGPTR_MASK (sizeof(long) - 1)
+
+/*
+ * Helper macro to return string length if we caught the zero
+ * byte.
+ */
+#define testbyte(x) \
+ do { \
+ if (p[x] == '\0') \
+ return (p - str + x); \
+ } while (0)
+
+size_t
+strlen(const char *str)
+{
+ const char *p;
+ const unsigned long *lp;
+ long va, vb;
+
+ /*
+ * Before trying the hard (unaligned byte-by-byte access) way
+ * to figure out whether there is a nul character, try to see
+ * if there is a nul character is within this accessible word
+ * first.
+ *
+ * p and (p & ~LONGPTR_MASK) must be equally accessible since
+ * they always fall in the same memory page, as long as page
+ * boundaries is integral multiple of word size.
+ */
+ lp = (const unsigned long *)((uintptr_t)str & ~LONGPTR_MASK);
+ va = (*lp - mask01);
+ vb = ((~*lp) & mask80);
+ lp++;
+ if (va & vb)
+ /* Check if we have \0 in the first part */
+ for (p = str; p < (const char *)lp; p++)
+ if (*p == '\0')
+ return (p - str);
+
+ /* Scan the rest of the string using word sized operation */
+ for (; ; lp++) {
+ va = (*lp - mask01);
+ vb = ((~*lp) & mask80);
+ if (va & vb) {
+ p = (const char *)(lp);
+ testbyte(0);
+ testbyte(1);
+ testbyte(2);
+ testbyte(3);
+#if (LONG_BIT >= 64)
+ testbyte(4);
+ testbyte(5);
+ testbyte(6);
+ testbyte(7);
+#endif
+ }
+ }
+
+ /* NOTREACHED */
+ return (0);
+}
diff --git a/lib/libc/string/strmode.3 b/lib/libc/string/strmode.3
new file mode 100644
index 000000000000..e963d28b9cde
--- /dev/null
+++ b/lib/libc/string/strmode.3
@@ -0,0 +1,142 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)strmode.3 8.3 (Berkeley) 7/28/94
+.\" $FreeBSD$
+.\"
+.Dd July 28, 1994
+.Dt STRMODE 3
+.Os
+.Sh NAME
+.Nm strmode
+.Nd convert inode status information into a symbolic string
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In string.h
+.Ft void
+.Fn strmode "mode_t mode" "char *bp"
+.Sh DESCRIPTION
+The
+.Fn strmode
+function
+converts a file
+.Fa mode
+(the type and permission information associated with an inode, see
+.Xr stat 2 )
+into a symbolic string which is stored in the location referenced by
+.Fa bp .
+This stored string is eleven characters in length plus a trailing
+.Dv NUL .
+.Pp
+The first character is the inode type, and will be one of the following:
+.Pp
+.Bl -tag -width flag -offset indent -compact
+.It \-
+regular file
+.It b
+block special
+.It c
+character special
+.It d
+directory
+.It l
+symbolic link
+.It p
+fifo
+.It s
+socket
+.It w
+whiteout
+.It ?
+unknown inode type
+.El
+.Pp
+The next nine characters encode three sets of permissions, in three
+characters each.
+The first three characters are the permissions for the owner of the
+file, the second three for the group the file belongs to, and the
+third for the ``other'', or default, set of users.
+.Pp
+Permission checking is done as specifically as possible.
+If read permission is denied to the owner of a file in the first set
+of permissions, the owner of the file will not be able to read the file.
+This is true even if the owner is in the file's group and the group
+permissions allow reading or the ``other'' permissions allow reading.
+.Pp
+If the first character of the three character set is an ``r'', the file is
+readable for that set of users; if a dash ``\-'', it is not readable.
+.Pp
+If the second character of the three character set is a ``w'', the file is
+writable for that set of users; if a dash ``\-'', it is not writable.
+.Pp
+The third character is the first of the following characters that apply:
+.Bl -tag -width xxxx
+.It S
+If the character is part of the owner permissions and the file is not
+executable or the directory is not searchable by the owner, and the
+set-user-id bit is set.
+.It S
+If the character is part of the group permissions and the file is not
+executable or the directory is not searchable by the group, and the
+set-group-id bit is set.
+.It T
+If the character is part of the other permissions and the file is not
+executable or the directory is not searchable by others, and the ``sticky''
+.Pq Dv S_ISVTX
+bit is set.
+.It s
+If the character is part of the owner permissions and the file is
+executable or the directory searchable by the owner, and the set-user-id
+bit is set.
+.It s
+If the character is part of the group permissions and the file is
+executable or the directory searchable by the group, and the set-group-id
+bit is set.
+.It t
+If the character is part of the other permissions and the file is
+executable or the directory searchable by others, and the ``sticky''
+.Pq Dv S_ISVTX
+bit is set.
+.It x
+The file is executable or the directory is searchable.
+.It \-
+None of the above apply.
+.El
+.Pp
+The last character will always be a space.
+.Sh SEE ALSO
+.Xr chmod 1 ,
+.Xr find 1 ,
+.Xr stat 2 ,
+.Xr getmode 3 ,
+.Xr setmode 3
+.Sh HISTORY
+The
+.Fn strmode
+function first appeared in
+.Bx 4.4 .
diff --git a/lib/libc/string/strmode.c b/lib/libc/string/strmode.c
new file mode 100644
index 000000000000..a73dd0ede401
--- /dev/null
+++ b/lib/libc/string/strmode.c
@@ -0,0 +1,148 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strmode.c 8.3 (Berkeley) 8/15/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+
+void
+strmode(/* mode_t */ int mode, char *p)
+{
+ /* print type */
+ switch (mode & S_IFMT) {
+ case S_IFDIR: /* directory */
+ *p++ = 'd';
+ break;
+ case S_IFCHR: /* character special */
+ *p++ = 'c';
+ break;
+ case S_IFBLK: /* block special */
+ *p++ = 'b';
+ break;
+ case S_IFREG: /* regular */
+ *p++ = '-';
+ break;
+ case S_IFLNK: /* symbolic link */
+ *p++ = 'l';
+ break;
+ case S_IFSOCK: /* socket */
+ *p++ = 's';
+ break;
+#ifdef S_IFIFO
+ case S_IFIFO: /* fifo */
+ *p++ = 'p';
+ break;
+#endif
+#ifdef S_IFWHT
+ case S_IFWHT: /* whiteout */
+ *p++ = 'w';
+ break;
+#endif
+ default: /* unknown */
+ *p++ = '?';
+ break;
+ }
+ /* usr */
+ if (mode & S_IRUSR)
+ *p++ = 'r';
+ else
+ *p++ = '-';
+ if (mode & S_IWUSR)
+ *p++ = 'w';
+ else
+ *p++ = '-';
+ switch (mode & (S_IXUSR | S_ISUID)) {
+ case 0:
+ *p++ = '-';
+ break;
+ case S_IXUSR:
+ *p++ = 'x';
+ break;
+ case S_ISUID:
+ *p++ = 'S';
+ break;
+ case S_IXUSR | S_ISUID:
+ *p++ = 's';
+ break;
+ }
+ /* group */
+ if (mode & S_IRGRP)
+ *p++ = 'r';
+ else
+ *p++ = '-';
+ if (mode & S_IWGRP)
+ *p++ = 'w';
+ else
+ *p++ = '-';
+ switch (mode & (S_IXGRP | S_ISGID)) {
+ case 0:
+ *p++ = '-';
+ break;
+ case S_IXGRP:
+ *p++ = 'x';
+ break;
+ case S_ISGID:
+ *p++ = 'S';
+ break;
+ case S_IXGRP | S_ISGID:
+ *p++ = 's';
+ break;
+ }
+ /* other */
+ if (mode & S_IROTH)
+ *p++ = 'r';
+ else
+ *p++ = '-';
+ if (mode & S_IWOTH)
+ *p++ = 'w';
+ else
+ *p++ = '-';
+ switch (mode & (S_IXOTH | S_ISVTX)) {
+ case 0:
+ *p++ = '-';
+ break;
+ case S_IXOTH:
+ *p++ = 'x';
+ break;
+ case S_ISVTX:
+ *p++ = 'T';
+ break;
+ case S_IXOTH | S_ISVTX:
+ *p++ = 't';
+ break;
+ }
+ *p++ = ' ';
+ *p = '\0';
+}
diff --git a/lib/libc/string/strncat.c b/lib/libc/string/strncat.c
new file mode 100644
index 000000000000..6a0e553daa3f
--- /dev/null
+++ b/lib/libc/string/strncat.c
@@ -0,0 +1,62 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strncat.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <string.h>
+
+/*
+ * Concatenate src on the end of dst. At most strlen(dst)+n+1 bytes
+ * are written at dst (at most n+1 bytes being appended). Return dst.
+ */
+char *
+strncat(char * __restrict dst, const char * __restrict src, size_t n)
+{
+ if (n != 0) {
+ char *d = dst;
+ const char *s = src;
+
+ while (*d != 0)
+ d++;
+ do {
+ if ((*d = *s++) == 0)
+ break;
+ d++;
+ } while (--n != 0);
+ *d = 0;
+ }
+ return (dst);
+}
diff --git a/lib/libc/string/strncmp.c b/lib/libc/string/strncmp.c
new file mode 100644
index 000000000000..4967a9483e64
--- /dev/null
+++ b/lib/libc/string/strncmp.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strncmp.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <string.h>
+
+int
+strncmp(const char *s1, const char *s2, size_t n)
+{
+
+ if (n == 0)
+ return (0);
+ do {
+ if (*s1 != *s2++)
+ return (*(const unsigned char *)s1 -
+ *(const unsigned char *)(s2 - 1));
+ if (*s1++ == '\0')
+ break;
+ } while (--n != 0);
+ return (0);
+}
diff --git a/lib/libc/string/strncpy.c b/lib/libc/string/strncpy.c
new file mode 100644
index 000000000000..39074035084c
--- /dev/null
+++ b/lib/libc/string/strncpy.c
@@ -0,0 +1,62 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strncpy.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <string.h>
+
+/*
+ * Copy src to dst, truncating or null-padding to always copy n bytes.
+ * Return dst.
+ */
+char *
+strncpy(char * __restrict dst, const char * __restrict src, size_t n)
+{
+ if (n != 0) {
+ char *d = dst;
+ const char *s = src;
+
+ do {
+ if ((*d++ = *s++) == '\0') {
+ /* NUL pad the remaining n-1 bytes */
+ while (--n != 0)
+ *d++ = '\0';
+ break;
+ }
+ } while (--n != 0);
+ }
+ return (dst);
+}
diff --git a/lib/libc/string/strndup.c b/lib/libc/string/strndup.c
new file mode 100644
index 000000000000..bee944db167a
--- /dev/null
+++ b/lib/libc/string/strndup.c
@@ -0,0 +1,40 @@
+/* $OpenBSD: strndup.c,v 1.1 2010/05/18 22:24:55 tedu Exp $ */
+
+/*
+ * Copyright (c) 2010 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+char *
+strndup(const char *str, size_t maxlen)
+{
+ char *copy;
+ size_t len;
+
+ len = strnlen(str, maxlen);
+ copy = malloc(len + 1);
+ if (copy != NULL) {
+ (void)memcpy(copy, str, len);
+ copy[len] = '\0';
+ }
+
+ return copy;
+}
diff --git a/lib/libc/string/strnlen.c b/lib/libc/string/strnlen.c
new file mode 100644
index 000000000000..f44151f730dc
--- /dev/null
+++ b/lib/libc/string/strnlen.c
@@ -0,0 +1,42 @@
+/*-
+ * Copyright (c) 2009 David Schultz <das@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <string.h>
+
+size_t
+strnlen(const char *s, size_t maxlen)
+{
+ size_t len;
+
+ for (len = 0; len < maxlen; len++, s++) {
+ if (!*s)
+ break;
+ }
+ return (len);
+}
diff --git a/lib/libc/string/strnstr.c b/lib/libc/string/strnstr.c
new file mode 100644
index 000000000000..4de757d5996f
--- /dev/null
+++ b/lib/libc/string/strnstr.c
@@ -0,0 +1,65 @@
+/*-
+ * Copyright (c) 2001 Mike Barcroft <mike@FreeBSD.org>
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strstr.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <string.h>
+
+/*
+ * Find the first occurrence of find in s, where the search is limited to the
+ * first slen characters of s.
+ */
+char *
+strnstr(const char *s, const char *find, size_t slen)
+{
+ char c, sc;
+ size_t len;
+
+ if ((c = *find++) != '\0') {
+ len = strlen(find);
+ do {
+ do {
+ if (slen-- < 1 || (sc = *s++) == '\0')
+ return (NULL);
+ } while (sc != c);
+ if (len > slen)
+ return (NULL);
+ } while (strncmp(s, find, len) != 0);
+ s--;
+ }
+ return ((char *)s);
+}
diff --git a/lib/libc/string/strpbrk.3 b/lib/libc/string/strpbrk.3
new file mode 100644
index 000000000000..bfa50990a71d
--- /dev/null
+++ b/lib/libc/string/strpbrk.3
@@ -0,0 +1,77 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek and the American National Standards Committee X3,
+.\" on Information Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)strpbrk.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt STRPBRK 3
+.Os
+.Sh NAME
+.Nm strpbrk
+.Nd locate multiple characters in string
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In string.h
+.Ft char *
+.Fn strpbrk "const char *s" "const char *charset"
+.Sh DESCRIPTION
+The
+.Fn strpbrk
+function
+locates in the null-terminated string
+.Fa s
+the first occurrence of any character in the string
+.Fa charset
+and returns a pointer to this character.
+If no characters from
+.Fa charset
+occur anywhere in
+.Fa s
+.Fn strpbrk
+returns NULL.
+.Sh SEE ALSO
+.Xr memchr 3 ,
+.Xr strchr 3 ,
+.Xr strcspn 3 ,
+.Xr strrchr 3 ,
+.Xr strsep 3 ,
+.Xr strspn 3 ,
+.Xr strstr 3 ,
+.Xr strtok 3 ,
+.Xr wcspbrk 3
+.Sh STANDARDS
+The
+.Fn strpbrk
+function
+conforms to
+.St -isoC .
diff --git a/lib/libc/string/strpbrk.c b/lib/libc/string/strpbrk.c
new file mode 100644
index 000000000000..565ef82f11d3
--- /dev/null
+++ b/lib/libc/string/strpbrk.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 1985, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strpbrk.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <string.h>
+
+/*
+ * Find the first occurrence in s1 of a character in s2 (excluding NUL).
+ */
+char *
+strpbrk(const char *s1, const char *s2)
+{
+ const char *scanp;
+ int c, sc;
+
+ while ((c = *s1++) != 0) {
+ for (scanp = s2; (sc = *scanp++) != '\0';)
+ if (sc == c)
+ return ((char *)(s1 - 1));
+ }
+ return (NULL);
+}
diff --git a/lib/libc/string/strrchr.c b/lib/libc/string/strrchr.c
new file mode 100644
index 000000000000..f84ffb78c438
--- /dev/null
+++ b/lib/libc/string/strrchr.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)rindex.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stddef.h>
+#include <string.h>
+
+char *
+strrchr(const char *p, int ch)
+{
+ char *save;
+ char c;
+
+ c = ch;
+ for (save = NULL;; ++p) {
+ if (*p == c)
+ save = (char *)p;
+ if (*p == '\0')
+ return (save);
+ }
+ /* NOTREACHED */
+}
+
+__weak_reference(strrchr, rindex);
diff --git a/lib/libc/string/strsep.3 b/lib/libc/string/strsep.3
new file mode 100644
index 000000000000..4e9dad9db5ae
--- /dev/null
+++ b/lib/libc/string/strsep.3
@@ -0,0 +1,135 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)strsep.3 8.1 (Berkeley) 6/9/93
+.\" $FreeBSD$
+.\"
+.Dd December 5, 2008
+.Dt STRSEP 3
+.Os
+.Sh NAME
+.Nm strsep
+.Nd separate strings
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In string.h
+.Ft char *
+.Fn strsep "char **stringp" "const char *delim"
+.Sh DESCRIPTION
+The
+.Fn strsep
+function locates, in the string referenced by
+.Fa *stringp ,
+the first occurrence of any character in the string
+.Fa delim
+(or the terminating
+.Ql \e0
+character) and replaces it with a
+.Ql \e0 .
+The location of the next character after the delimiter character
+(or NULL, if the end of the string was reached) is stored in
+.Fa *stringp .
+The original value of
+.Fa *stringp
+is returned.
+.Pp
+An
+.Dq empty
+field (i.e., a character in the string
+.Fa delim
+occurs as the first character of
+.Fa *stringp )
+can be detected by comparing the location referenced by the returned pointer
+to
+.Ql \e0 .
+.Pp
+If
+.Fa *stringp
+is initially
+.Dv NULL ,
+.Fn strsep
+returns
+.Dv NULL .
+.Sh EXAMPLES
+The following uses
+.Fn strsep
+to parse a string, and prints each token in separate line:
+.Bd -literal -offset indent
+char *token, *string, *tofree;
+
+tofree = string = strdup("abc,def,ghi");
+assert(string != NULL);
+
+while ((token = strsep(&string, ",")) != NULL)
+ printf("%s\en", token);
+
+free(tofree);
+.Ed
+.Pp
+The following uses
+.Fn strsep
+to parse a string, containing tokens delimited by white space, into an
+argument vector:
+.Bd -literal -offset indent
+char **ap, *argv[10], *inputstring;
+
+for (ap = argv; (*ap = strsep(&inputstring, " \et")) != NULL;)
+ if (**ap != '\e0')
+ if (++ap >= &argv[10])
+ break;
+.Ed
+.Sh SEE ALSO
+.Xr memchr 3 ,
+.Xr strchr 3 ,
+.Xr strcspn 3 ,
+.Xr strpbrk 3 ,
+.Xr strrchr 3 ,
+.Xr strspn 3 ,
+.Xr strstr 3 ,
+.Xr strtok 3
+.Sh HISTORY
+The
+.Fn strsep
+function
+is intended as a replacement for the
+.Fn strtok
+function.
+While the
+.Fn strtok
+function should be preferred for portability reasons (it conforms to
+.St -isoC )
+it is unable to handle empty fields, i.e., detect fields delimited by
+two adjacent delimiter characters, or to be used for more than a single
+string at a time.
+The
+.Fn strsep
+function first appeared in
+.Bx 4.4 .
diff --git a/lib/libc/string/strsep.c b/lib/libc/string/strsep.c
new file mode 100644
index 000000000000..73c61af8115f
--- /dev/null
+++ b/lib/libc/string/strsep.c
@@ -0,0 +1,75 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strsep.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <string.h>
+#include <stdio.h>
+
+/*
+ * Get next token from string *stringp, where tokens are possibly-empty
+ * strings separated by characters from delim.
+ *
+ * Writes NULs into the string at *stringp to end tokens.
+ * delim need not remain constant from call to call.
+ * On return, *stringp points past the last NUL written (if there might
+ * be further tokens), or is NULL (if there are definitely no more tokens).
+ *
+ * If *stringp is NULL, strsep returns NULL.
+ */
+char *
+strsep(char **stringp, const char *delim)
+{
+ char *s;
+ const char *spanp;
+ int c, sc;
+ char *tok;
+
+ if ((s = *stringp) == NULL)
+ return (NULL);
+ for (tok = s;;) {
+ c = *s++;
+ spanp = delim;
+ do {
+ if ((sc = *spanp++) == c) {
+ if (c == 0)
+ s = NULL;
+ else
+ s[-1] = 0;
+ *stringp = s;
+ return (tok);
+ }
+ } while (sc != 0);
+ }
+ /* NOTREACHED */
+}
diff --git a/lib/libc/string/strsignal.c b/lib/libc/string/strsignal.c
new file mode 100644
index 000000000000..7c461a3dbb80
--- /dev/null
+++ b/lib/libc/string/strsignal.c
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strerror.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#if defined(NLS)
+#include <nl_types.h>
+#endif
+#include <limits.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include "reentrant.h"
+#include "un-namespace.h"
+
+#define UPREFIX "Unknown signal"
+
+static char sig_ebuf[NL_TEXTMAX];
+static char sig_ebuf_err[NL_TEXTMAX];
+static once_t sig_init_once = ONCE_INITIALIZER;
+static thread_key_t sig_key;
+static int sig_keycreated = 0;
+
+static void
+sig_keycreate(void)
+{
+ sig_keycreated = (thr_keycreate(&sig_key, free) == 0);
+}
+
+static char *
+sig_tlsalloc(void)
+{
+ char *ebuf = NULL;
+
+ if (thr_main() != 0)
+ ebuf = sig_ebuf;
+ else {
+ if (thr_once(&sig_init_once, sig_keycreate) != 0 ||
+ !sig_keycreated)
+ goto thr_err;
+ if ((ebuf = thr_getspecific(sig_key)) == NULL) {
+ if ((ebuf = malloc(sizeof(sig_ebuf))) == NULL)
+ goto thr_err;
+ if (thr_setspecific(sig_key, ebuf) != 0) {
+ free(ebuf);
+ ebuf = NULL;
+ goto thr_err;
+ }
+ }
+ }
+thr_err:
+ if (ebuf == NULL)
+ ebuf = sig_ebuf_err;
+ return (ebuf);
+}
+
+/* XXX: negative 'num' ? (REGR) */
+char *
+strsignal(int num)
+{
+ char *ebuf;
+ char tmp[20];
+ size_t n;
+ int signum;
+ char *t, *p;
+
+#if defined(NLS)
+ int saved_errno = errno;
+ nl_catd catd;
+ catd = catopen("libc", NL_CAT_LOCALE);
+#endif
+
+ ebuf = sig_tlsalloc();
+
+ if (num > 0 && num < sys_nsig) {
+ n = strlcpy(ebuf,
+#if defined(NLS)
+ catgets(catd, 2, num, sys_siglist[num]),
+#else
+ sys_siglist[num],
+#endif
+ sizeof(sig_ebuf));
+ } else {
+ n = strlcpy(ebuf,
+#if defined(NLS)
+ catgets(catd, 2, 0xffff, UPREFIX),
+#else
+ UPREFIX,
+#endif
+ sizeof(sig_ebuf));
+
+ signum = num;
+ if (num < 0)
+ signum = -signum;
+
+ t = tmp;
+ do {
+ *t++ = "0123456789"[signum % 10];
+ } while (signum /= 10);
+ if (num < 0)
+ *t++ = '-';
+
+ p = (ebuf + n);
+ *p++ = ':';
+ *p++ = ' ';
+
+ for (;;) {
+ *p++ = *--t;
+ if (t <= tmp)
+ break;
+ }
+ *p = '\0';
+ }
+
+#if defined(NLS)
+ catclose(catd);
+ errno = saved_errno;
+#endif
+ return (ebuf);
+}
diff --git a/lib/libc/string/strspn.3 b/lib/libc/string/strspn.3
new file mode 100644
index 000000000000..4a8e3f40ce59
--- /dev/null
+++ b/lib/libc/string/strspn.3
@@ -0,0 +1,111 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek and the American National Standards Committee X3,
+.\" on Information Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)strspn.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd May 24, 2014
+.Dt STRSPN 3
+.Os
+.Sh NAME
+.Nm strspn ,
+.Nm strcspn
+.Nd span a string
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In string.h
+.Ft size_t
+.Fn strspn "const char *s" "const char *charset"
+.Ft size_t
+.Fn strcspn "const char *s" "const char *charset"
+.Sh DESCRIPTION
+The
+.Fn strspn
+function
+spans the initial part of the null-terminated string
+.Fa s
+as long as the characters from
+.Fa s
+occur in the null-terminated string
+.Fa charset .
+In other words, it computes the string array index
+of the first character of
+.Fa s
+which is not in
+.Fa charset ,
+else the index of the first null character.
+.Pp
+The
+.Fn strcspn
+function
+spans the initial part of the null-terminated string
+.Fa s
+as long as the characters from
+.Fa s
+.Sy do not
+occur in the null-terminated string
+.Fa charset
+.Po it spans the
+.Sy complement
+of
+.Fa charset
+.Pc .
+In other words, it computes the string array index
+of the first character of
+.Fa s
+which is also in
+.Fa charset ,
+else the index of the first null character.
+.Sh RETURN VALUES
+The
+.Fn strspn
+and
+.Fn strcspn
+functions
+return the number of characters spanned.
+.Sh SEE ALSO
+.Xr memchr 3 ,
+.Xr strchr 3 ,
+.Xr strpbrk 3 ,
+.Xr strrchr 3 ,
+.Xr strsep 3 ,
+.Xr strstr 3 ,
+.Xr strtok 3 ,
+.Xr wcsspn 3
+.Sh STANDARDS
+The
+.Fn strspn
+and
+.Fn strcspn
+functions
+conform to
+.St -isoC .
diff --git a/lib/libc/string/strspn.c b/lib/libc/string/strspn.c
new file mode 100644
index 000000000000..5dbac0a67857
--- /dev/null
+++ b/lib/libc/string/strspn.c
@@ -0,0 +1,71 @@
+/*-
+ * Copyright (c) 2005 David Schultz <das@FreeBSD.ORG>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <limits.h>
+#include <string.h>
+
+#define IDX(c) ((u_char)(c) / LONG_BIT)
+#define BIT(c) ((u_long)1 << ((u_char)(c) % LONG_BIT))
+
+size_t
+strspn(const char *s, const char *charset)
+{
+ /*
+ * NB: idx and bit are temporaries whose use causes gcc 3.4.2 to
+ * generate better code. Without them, gcc gets a little confused.
+ */
+ const char *s1;
+ u_long bit;
+ u_long tbl[(UCHAR_MAX + 1) / LONG_BIT];
+ int idx;
+
+ if(*s == '\0')
+ return (0);
+
+#if LONG_BIT == 64 /* always better to unroll on 64-bit architectures */
+ tbl[3] = tbl[2] = tbl[1] = tbl[0] = 0;
+#else
+ for (idx = 0; idx < sizeof(tbl) / sizeof(tbl[0]); idx++)
+ tbl[idx] = 0;
+#endif
+ for (; *charset != '\0'; charset++) {
+ idx = IDX(*charset);
+ bit = BIT(*charset);
+ tbl[idx] |= bit;
+ }
+
+ for(s1 = s; ; s1++) {
+ idx = IDX(*s1);
+ bit = BIT(*s1);
+ if ((tbl[idx] & bit) == 0)
+ break;
+ }
+ return (s1 - s);
+}
diff --git a/lib/libc/string/strstr.3 b/lib/libc/string/strstr.3
new file mode 100644
index 000000000000..b1106b3c5759
--- /dev/null
+++ b/lib/libc/string/strstr.3
@@ -0,0 +1,155 @@
+.\" Copyright (c) 2001 Mike Barcroft <mike@FreeBSD.org>
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek and the American National Standards Committee X3,
+.\" on Information Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)strstr.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd October 11, 2001
+.Dt STRSTR 3
+.Os
+.Sh NAME
+.Nm strstr , strcasestr , strnstr
+.Nd locate a substring in a string
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In string.h
+.Ft char *
+.Fn strstr "const char *big" "const char *little"
+.Ft char *
+.Fn strcasestr "const char *big" "const char *little"
+.Ft char *
+.Fn strnstr "const char *big" "const char *little" "size_t len"
+.In string.h
+.In xlocale.h
+.Ft char *
+.Fn strcasestr_l "const char *big" "const char *little" "locale_t loc"
+.Sh DESCRIPTION
+The
+.Fn strstr
+function
+locates the first occurrence of the null-terminated string
+.Fa little
+in the null-terminated string
+.Fa big .
+.Pp
+The
+.Fn strcasestr
+function is similar to
+.Fn strstr ,
+but ignores the case of both strings.
+.Pp
+The
+.Fn strcasestr_l
+function does the same as
+.Fn strcasestr
+but takes an explicit locale rather than using the current locale.
+.Pp
+The
+.Fn strnstr
+function
+locates the first occurrence of the null-terminated string
+.Fa little
+in the string
+.Fa big ,
+where not more than
+.Fa len
+characters are searched.
+Characters that appear after a
+.Ql \e0
+character are not searched.
+Since the
+.Fn strnstr
+function is a
+.Fx
+specific API, it should only be used when portability is not a concern.
+.Sh RETURN VALUES
+If
+.Fa little
+is an empty string,
+.Fa big
+is returned;
+if
+.Fa little
+occurs nowhere in
+.Fa big ,
+.Dv NULL
+is returned;
+otherwise a pointer to the first character of the first occurrence of
+.Fa little
+is returned.
+.Sh EXAMPLES
+The following sets the pointer
+.Va ptr
+to the
+.Qq Li Bar Baz
+portion of
+.Va largestring :
+.Bd -literal -offset indent
+const char *largestring = "Foo Bar Baz";
+const char *smallstring = "Bar";
+char *ptr;
+
+ptr = strstr(largestring, smallstring);
+.Ed
+.Pp
+The following sets the pointer
+.Va ptr
+to
+.Dv NULL ,
+because only the first 4 characters of
+.Va largestring
+are searched:
+.Bd -literal -offset indent
+const char *largestring = "Foo Bar Baz";
+const char *smallstring = "Bar";
+char *ptr;
+
+ptr = strnstr(largestring, smallstring, 4);
+.Ed
+.Sh SEE ALSO
+.Xr memchr 3 ,
+.Xr memmem 3 ,
+.Xr strchr 3 ,
+.Xr strcspn 3 ,
+.Xr strpbrk 3 ,
+.Xr strrchr 3 ,
+.Xr strsep 3 ,
+.Xr strspn 3 ,
+.Xr strtok 3 ,
+.Xr wcsstr 3
+.Sh STANDARDS
+The
+.Fn strstr
+function
+conforms to
+.St -isoC .
diff --git a/lib/libc/string/strstr.c b/lib/libc/string/strstr.c
new file mode 100644
index 000000000000..18e60d579881
--- /dev/null
+++ b/lib/libc/string/strstr.c
@@ -0,0 +1,61 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strstr.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <string.h>
+
+/*
+ * Find the first occurrence of find in s.
+ */
+char *
+strstr(const char *s, const char *find)
+{
+ char c, sc;
+ size_t len;
+
+ if ((c = *find++) != '\0') {
+ len = strlen(find);
+ do {
+ do {
+ if ((sc = *s++) == '\0')
+ return (NULL);
+ } while (sc != c);
+ } while (strncmp(s, find, len) != 0);
+ s--;
+ }
+ return ((char *)s);
+}
diff --git a/lib/libc/string/strtok.3 b/lib/libc/string/strtok.3
new file mode 100644
index 000000000000..837064ba2c60
--- /dev/null
+++ b/lib/libc/string/strtok.3
@@ -0,0 +1,176 @@
+.\" Copyright (c) 1998 Softweyr LLC. All rights reserved.
+.\"
+.\" strtok_r, from Berkeley strtok
+.\" Oct 13, 1998 by Wes Peters <wes@softweyr.com>
+.\"
+.\" Copyright (c) 1988, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notices, this list of conditions and the following disclaimer.
+.\"
+.\" 2. Redistributions in binary form must reproduce the above
+.\" copyright notices, this list of conditions and the following
+.\" disclaimer in the documentation and/or other materials provided
+.\" with the distribution.
+.\"
+.\" 3. Neither the name of Softweyr LLC, the University nor the names
+.\" of its contributors may be used to endorse or promote products
+.\" derived from this software without specific prior written
+.\" permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY SOFTWEYR LLC, THE REGENTS AND
+.\" CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+.\" DISCLAIMED. IN NO EVENT SHALL SOFTWEYR LLC, THE REGENTS, OR
+.\" CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+.\" USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+.\" ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+.\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+.\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)strtok.3 8.2 (Berkeley) 2/3/94
+.\" $FreeBSD$
+.\"
+.Dd January 22, 2016
+.Dt STRTOK 3
+.Os
+.Sh NAME
+.Nm strtok , strtok_r
+.Nd string tokens
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In string.h
+.Ft char *
+.Fn strtok "char *str" "const char *sep"
+.Ft char *
+.Fn strtok_r "char *str" "const char *sep" "char **last"
+.Sh DESCRIPTION
+.Bf -symbolic
+This interface is obsoleted by
+.Xr strsep 3 .
+.Ef
+.Pp
+The
+.Fn strtok
+function
+is used to isolate sequential tokens in a null-terminated string,
+.Fa str .
+These tokens are separated in the string by at least one of the
+characters in
+.Fa sep .
+The first time that
+.Fn strtok
+is called,
+.Fa str
+should be specified; subsequent calls, wishing to obtain further tokens
+from the same string, should pass a null pointer instead.
+The separator string,
+.Fa sep ,
+must be supplied each time, and may change between calls.
+.Pp
+The implementation will behave as if no library function calls
+.Fn strtok .
+.Pp
+The
+.Fn strtok_r
+function is a reentrant version of
+.Fn strtok .
+The context pointer
+.Fa last
+must be provided on each call.
+The
+.Fn strtok_r
+function
+may also be used to nest two parsing loops within one another, as
+long as separate context pointers are used.
+.Pp
+The
+.Fn strtok
+and
+.Fn strtok_r
+functions
+return a pointer to the beginning of each subsequent token in the string,
+after replacing the token itself with a
+.Dv NUL
+character.
+When no more tokens remain, a null pointer is returned.
+.Sh EXAMPLES
+The following uses
+.Fn strtok_r
+to parse two strings using separate contexts:
+.Bd -literal
+char test[80], blah[80];
+char *sep = "\e\e/:;=-";
+char *word, *phrase, *brkt, *brkb;
+
+strcpy(test, "This;is.a:test:of=the/string\e\etokenizer-function.");
+
+for (word = strtok_r(test, sep, &brkt);
+ word;
+ word = strtok_r(NULL, sep, &brkt))
+{
+ strcpy(blah, "blah:blat:blab:blag");
+
+ for (phrase = strtok_r(blah, sep, &brkb);
+ phrase;
+ phrase = strtok_r(NULL, sep, &brkb))
+ {
+ printf("So far we're at %s:%s\en", word, phrase);
+ }
+}
+.Ed
+.Sh SEE ALSO
+.Xr memchr 3 ,
+.Xr strchr 3 ,
+.Xr strcspn 3 ,
+.Xr strpbrk 3 ,
+.Xr strrchr 3 ,
+.Xr strsep 3 ,
+.Xr strspn 3 ,
+.Xr strstr 3 ,
+.Xr wcstok 3
+.Sh STANDARDS
+The
+.Fn strtok
+function
+conforms to
+.St -isoC .
+The
+.Fn strtok_r
+function
+conforms to
+.St -p1003.1-2001 .
+.Sh AUTHORS
+.An Wes Peters Aq Mt wes@softweyr.com ,
+Softweyr LLC
+.Pp
+Based on the
+.Fx 3.0
+implementation.
+.Sh BUGS
+The System V
+.Fn strtok ,
+if handed a string containing only delimiter characters,
+will not alter the next starting point, so that a call to
+.Fn strtok
+with a different (or empty) delimiter string
+may return a
+.Pf non- Dv NULL
+value.
+Since this implementation always alters the next starting point,
+such a sequence of calls would always return
+.Dv NULL .
diff --git a/lib/libc/string/strtok.c b/lib/libc/string/strtok.c
new file mode 100644
index 000000000000..063a554339a6
--- /dev/null
+++ b/lib/libc/string/strtok.c
@@ -0,0 +1,136 @@
+/*-
+ * Copyright (c) 1998 Softweyr LLC. All rights reserved.
+ *
+ * strtok_r, from Berkeley strtok
+ * Oct 13, 1998 by Wes Peters <wes@softweyr.com>
+ *
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notices, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notices, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY SOFTWEYR LLC, THE REGENTS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SOFTWEYR LLC, THE
+ * REGENTS, OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strtok.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stddef.h>
+#ifdef DEBUG_STRTOK
+#include <stdio.h>
+#endif
+#include <string.h>
+
+char *__strtok_r(char *, const char *, char **);
+
+__weak_reference(__strtok_r, strtok_r);
+
+char *
+__strtok_r(char *s, const char *delim, char **last)
+{
+ char *spanp, *tok;
+ int c, sc;
+
+ if (s == NULL && (s = *last) == NULL)
+ return (NULL);
+
+ /*
+ * Skip (span) leading delimiters (s += strspn(s, delim), sort of).
+ */
+cont:
+ c = *s++;
+ for (spanp = (char *)delim; (sc = *spanp++) != 0;) {
+ if (c == sc)
+ goto cont;
+ }
+
+ if (c == 0) { /* no non-delimiter characters */
+ *last = NULL;
+ return (NULL);
+ }
+ tok = s - 1;
+
+ /*
+ * Scan token (scan for delimiters: s += strcspn(s, delim), sort of).
+ * Note that delim must have one NUL; we stop if we see that, too.
+ */
+ for (;;) {
+ c = *s++;
+ spanp = (char *)delim;
+ do {
+ if ((sc = *spanp++) == c) {
+ if (c == 0)
+ s = NULL;
+ else
+ s[-1] = '\0';
+ *last = s;
+ return (tok);
+ }
+ } while (sc != 0);
+ }
+ /* NOTREACHED */
+}
+
+char *
+strtok(char *s, const char *delim)
+{
+ static char *last;
+
+ return (__strtok_r(s, delim, &last));
+}
+
+#ifdef DEBUG_STRTOK
+/*
+ * Test the tokenizer.
+ */
+int
+main(void)
+{
+ char blah[80], test[80];
+ char *brkb, *brkt, *phrase, *sep, *word;
+
+ sep = "\\/:;=-";
+ phrase = "foo";
+
+ printf("String tokenizer test:\n");
+ strcpy(test, "This;is.a:test:of=the/string\\tokenizer-function.");
+ for (word = strtok(test, sep); word; word = strtok(NULL, sep))
+ printf("Next word is \"%s\".\n", word);
+ strcpy(test, "This;is.a:test:of=the/string\\tokenizer-function.");
+
+ for (word = strtok_r(test, sep, &brkt); word;
+ word = strtok_r(NULL, sep, &brkt)) {
+ strcpy(blah, "blah:blat:blab:blag");
+
+ for (phrase = strtok_r(blah, sep, &brkb); phrase;
+ phrase = strtok_r(NULL, sep, &brkb))
+ printf("So far we're at %s:%s\n", word, phrase);
+ }
+
+ return (0);
+}
+
+#endif /* DEBUG_STRTOK */
diff --git a/lib/libc/string/strxfrm.3 b/lib/libc/string/strxfrm.3
new file mode 100644
index 000000000000..f2750f4a385a
--- /dev/null
+++ b/lib/libc/string/strxfrm.3
@@ -0,0 +1,108 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek and the American National Standards Committee X3,
+.\" on Information Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)strxfrm.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt STRXFRM 3
+.Os
+.Sh NAME
+.Nm strxfrm
+.Nd transform a string under locale
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In string.h
+.Ft size_t
+.Fn strxfrm "char * restrict dst" "const char * restrict src" "size_t n"
+.Ft size_t
+.Fn strxfrm_l "char * restrict dst" "const char *restrict src" "size_t n" "locale_t loc"
+.Sh DESCRIPTION
+The
+.Fn strxfrm
+function transforms a null-terminated string pointed to by
+.Fa src
+according to the current locale collation if any,
+then copies the transformed string
+into
+.Fa dst .
+Not more than
+.Fa n
+characters are copied into
+.Fa dst ,
+including the terminating null character added.
+If
+.Fa n
+is set to 0
+(it helps to determine an actual size needed
+for transformation),
+.Fa dst
+is permitted to be a NULL pointer.
+.Pp
+Comparing two strings using
+.Fn strcmp
+after
+.Fn strxfrm
+is equal to comparing
+two original strings with
+.Fn strcoll .
+.Pp
+.Fn strxfrm_l
+does the same, however takes an explicit locale rather than the global
+locale.
+.Sh RETURN VALUES
+Upon successful completion,
+.Fn strxfrm
+and
+.Fn strxfrm_l
+return the length of the transformed string not including
+the terminating null character.
+If this value is
+.Fa n
+or more, the contents of
+.Fa dst
+are indeterminate.
+.Sh SEE ALSO
+.Xr setlocale 3 ,
+.Xr strcmp 3 ,
+.Xr strcoll 3 ,
+.Xr wcsxfrm 3
+.Sh STANDARDS
+The
+.Fn strxfrm
+function
+conforms to
+.St -isoC .
+The
+.Fn strxfrm_l
+function conforms to
+.St -p1003.1-2008 .
diff --git a/lib/libc/string/strxfrm.c b/lib/libc/string/strxfrm.c
new file mode 100644
index 000000000000..06ae6393069d
--- /dev/null
+++ b/lib/libc/string/strxfrm.c
@@ -0,0 +1,103 @@
+/*-
+ * Copyright 2010 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 1995 Alex Tatmanjants <alex@elvisti.kiev.ua>
+ * at Electronni Visti IA, Kiev, Ukraine.
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 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 <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <wchar.h>
+#include "collate.h"
+
+size_t
+strxfrm_l(char * __restrict dest, const char * __restrict src, size_t len, locale_t loc);
+size_t
+strxfrm(char * __restrict dest, const char * __restrict src, size_t len)
+{
+ return strxfrm_l(dest, src, len, __get_locale());
+}
+
+size_t
+strxfrm_l(char * __restrict dest, const char * __restrict src, size_t len, locale_t locale)
+{
+ size_t slen;
+ size_t xlen;
+ wchar_t *wcs = NULL;
+
+ FIX_LOCALE(locale);
+ struct xlocale_collate *table =
+ (struct xlocale_collate*)locale->components[XLC_COLLATE];
+
+ if (!*src) {
+ if (len > 0)
+ *dest = '\0';
+ return (0);
+ }
+
+ /*
+ * The conversion from multibyte to wide character strings is
+ * strictly reducing (one byte of an mbs cannot expand to more
+ * than one wide character.)
+ */
+ slen = strlen(src);
+
+ if (table->__collate_load_error)
+ goto error;
+
+ if ((wcs = malloc((slen + 1) * sizeof (wchar_t))) == NULL)
+ goto error;
+
+ if (mbstowcs_l(wcs, src, slen + 1, locale) == (size_t)-1)
+ goto error;
+
+ if ((xlen = _collate_sxfrm(table, wcs, dest, len)) == (size_t)-1)
+ goto error;
+
+ free(wcs);
+
+ if (len > xlen) {
+ dest[xlen] = 0;
+ } else if (len) {
+ dest[len-1] = 0;
+ }
+
+ return (xlen);
+
+error:
+ /* errno should be set to ENOMEM if malloc failed */
+ free(wcs);
+ strlcpy(dest, src, len);
+
+ return (slen);
+}
diff --git a/lib/libc/string/swab.3 b/lib/libc/string/swab.3
new file mode 100644
index 000000000000..204b976ab1f4
--- /dev/null
+++ b/lib/libc/string/swab.3
@@ -0,0 +1,67 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)swab.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd March 4, 2012
+.Dt SWAB 3
+.Os
+.Sh NAME
+.Nm swab
+.Nd swap adjacent bytes
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft void
+.Fn swab "const void * restrict src" "void * restrict dst" "ssize_t len"
+.Sh DESCRIPTION
+The function
+.Fn swab
+copies
+.Fa len
+bytes from the location referenced by
+.Fa src
+to the location referenced by
+.Fa dst ,
+swapping adjacent bytes.
+.Pp
+The argument
+.Fa len
+must be an even number.
+If
+.Fa len
+is less than zero, nothing will be done.
+.Sh SEE ALSO
+.Xr bzero 3 ,
+.Xr memset 3
+.Sh HISTORY
+A
+.Fn swab
+function appeared in
+.At v7 .
diff --git a/lib/libc/string/swab.c b/lib/libc/string/swab.c
new file mode 100644
index 000000000000..84633094be3b
--- /dev/null
+++ b/lib/libc/string/swab.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jeffrey Mogul.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)swab.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <unistd.h>
+
+void
+swab(const void * __restrict from, void * __restrict to, ssize_t len)
+{
+ unsigned long temp;
+ int n;
+ char *fp, *tp;
+
+ if (len <= 0)
+ return;
+ n = len >> 1;
+ fp = (char *)from;
+ tp = (char *)to;
+#define STEP temp = *fp++,*tp++ = *fp++,*tp++ = temp
+ /* round to multiple of 8 */
+ for (; n & 0x7; --n)
+ STEP;
+ for (n >>= 3; n > 0; --n) {
+ STEP; STEP; STEP; STEP;
+ STEP; STEP; STEP; STEP;
+ }
+}
diff --git a/lib/libc/string/timingsafe_bcmp.3 b/lib/libc/string/timingsafe_bcmp.3
new file mode 100644
index 000000000000..502e57176806
--- /dev/null
+++ b/lib/libc/string/timingsafe_bcmp.3
@@ -0,0 +1,92 @@
+.\" $OpenBSD: timingsafe_bcmp.3,v 1.2 2014/06/21 20:22:15 tedu Exp $
+.\"
+.\" Copyright (c) 2014 Google Inc.
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.\" $FreeBSD$
+.Dd August 15, 2016
+.Dt TIMINGSAFE_BCMP 3
+.Os
+.Sh NAME
+.Nm timingsafe_bcmp ,
+.Nm timingsafe_memcmp
+.Nd timing-safe byte sequence comparisons
+.Sh SYNOPSIS
+.In string.h
+.Ft int
+.Fn timingsafe_bcmp "const void *b1" "const void *b2" "size_t len"
+.Ft int
+.Fn timingsafe_memcmp "const void *b1" "const void *b2" "size_t len"
+.Sh DESCRIPTION
+The
+.Fn timingsafe_bcmp
+and
+.Fn timingsafe_memcmp
+functions lexicographically compare the first
+.Fa len
+bytes (each interpreted as an
+.Vt unsigned char )
+pointed to by
+.Fa b1
+and
+.Fa b2 .
+.Pp
+Additionally, their running times are independent of the byte sequences compared,
+making them safe to use for comparing secret values such as cryptographic MACs.
+In contrast,
+.Xr bcmp 3
+and
+.Xr memcmp 3
+may short-circuit after finding the first differing byte.
+.Sh RETURN VALUES
+The
+.Fn timingsafe_bcmp
+function returns 0 or not zero if the byte sequence pointed to by
+.Fa b1
+compares equal to or not equal to (respectively)
+the byte sequence pointed to by
+.Fa b2 .
+.Pp
+The
+.Fn timingsafe_memcmp
+function returns a negative value, 0, or positive value if the byte sequence
+pointed to by
+.Fa b1
+compares less than, equal to, or greater than (respectively)
+the byte sequence pointed to by
+.Fa b2 .
+.Sh SEE ALSO
+.Xr bcmp 3 ,
+.Xr memcmp 3
+.Sh STANDARDS
+The
+.Fn timingsafe_bcmp
+and
+.Fn timingsafe_memcmp
+functions are
+.Fx
+extensions.
+.Sh HISTORY
+The
+.Fn timingsafe_bcmp
+function first appeared in
+.Ox 4.9 .
+.Pp
+The
+.Fn timingsafe_memcmp
+function first appeared in
+.Ox 5.6 .
+.Pp
+Both functions first appeared in
+.Fx 12.0 .
diff --git a/lib/libc/string/timingsafe_bcmp.c b/lib/libc/string/timingsafe_bcmp.c
new file mode 100644
index 000000000000..d098158059f3
--- /dev/null
+++ b/lib/libc/string/timingsafe_bcmp.c
@@ -0,0 +1,36 @@
+/* $OpenBSD: timingsafe_bcmp.c,v 1.3 2015/08/31 02:53:57 guenther Exp $ */
+/*
+ * Copyright (c) 2010 Damien Miller. All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <string.h>
+
+int __timingsafe_bcmp(const void *, const void *, size_t);
+
+int
+__timingsafe_bcmp(const void *b1, const void *b2, size_t n)
+{
+ const unsigned char *p1 = b1, *p2 = b2;
+ int ret = 0;
+
+ for (; n > 0; n--)
+ ret |= *p1++ ^ *p2++;
+ return (ret != 0);
+}
+
+__weak_reference(__timingsafe_bcmp, timingsafe_bcmp);
diff --git a/lib/libc/string/timingsafe_memcmp.c b/lib/libc/string/timingsafe_memcmp.c
new file mode 100644
index 000000000000..7abfb48045f8
--- /dev/null
+++ b/lib/libc/string/timingsafe_memcmp.c
@@ -0,0 +1,53 @@
+/* $OpenBSD: timingsafe_memcmp.c,v 1.2 2015/08/31 02:53:57 guenther Exp $ */
+/*
+ * Copyright (c) 2014 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <limits.h>
+#include <string.h>
+
+int __timingsafe_memcmp(const void *, const void *, size_t);
+
+int
+__timingsafe_memcmp(const void *b1, const void *b2, size_t len)
+{
+ const unsigned char *p1 = b1, *p2 = b2;
+ size_t i;
+ int res = 0, done = 0;
+
+ for (i = 0; i < len; i++) {
+ /* lt is -1 if p1[i] < p2[i]; else 0. */
+ int lt = (p1[i] - p2[i]) >> CHAR_BIT;
+
+ /* gt is -1 if p1[i] > p2[i]; else 0. */
+ int gt = (p2[i] - p1[i]) >> CHAR_BIT;
+
+ /* cmp is 1 if p1[i] > p2[i]; -1 if p1[i] < p2[i]; else 0. */
+ int cmp = lt - gt;
+
+ /* set res = cmp if !done. */
+ res |= cmp & ~done;
+
+ /* set done if p1[i] != p2[i]. */
+ done |= lt | gt;
+ }
+
+ return (res);
+}
+
+__weak_reference(__timingsafe_memcmp, timingsafe_memcmp);
diff --git a/lib/libc/string/wcpcpy.c b/lib/libc/string/wcpcpy.c
new file mode 100644
index 000000000000..df63d72a0463
--- /dev/null
+++ b/lib/libc/string/wcpcpy.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 1999
+ * David E. O'Brien
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strcpy.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <wchar.h>
+
+wchar_t *
+wcpcpy(wchar_t * __restrict to, const wchar_t * __restrict from)
+{
+
+ for (; (*to = *from); ++from, ++to);
+ return(to);
+}
diff --git a/lib/libc/string/wcpncpy.c b/lib/libc/string/wcpncpy.c
new file mode 100644
index 000000000000..87b361c9737d
--- /dev/null
+++ b/lib/libc/string/wcpncpy.c
@@ -0,0 +1,45 @@
+/*-
+ * Copyright (c) 2009 David Schultz <das@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <wchar.h>
+
+wchar_t *
+wcpncpy(wchar_t * __restrict dst, const wchar_t * __restrict src, size_t n)
+{
+
+ for (; n--; dst++, src++) {
+ if (!(*dst = *src)) {
+ wchar_t *ret = dst;
+ while (n--)
+ *++dst = L'\0';
+ return (ret);
+ }
+ }
+ return (dst);
+}
diff --git a/lib/libc/string/wcscasecmp.c b/lib/libc/string/wcscasecmp.c
new file mode 100644
index 000000000000..01435432722c
--- /dev/null
+++ b/lib/libc/string/wcscasecmp.c
@@ -0,0 +1,45 @@
+/*-
+ * Copyright (c) 2009 David Schultz <das@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <wchar.h>
+#include <wctype.h>
+
+int
+wcscasecmp(const wchar_t *s1, const wchar_t *s2)
+{
+ wchar_t c1, c2;
+
+ for (; *s1; s1++, s2++) {
+ c1 = towlower(*s1);
+ c2 = towlower(*s2);
+ if (c1 != c2)
+ return ((int)c1 - c2);
+ }
+ return (-*s2);
+}
diff --git a/lib/libc/string/wcscat.c b/lib/libc/string/wcscat.c
new file mode 100644
index 000000000000..7ae4e801157a
--- /dev/null
+++ b/lib/libc/string/wcscat.c
@@ -0,0 +1,51 @@
+/*-
+ * Copyright (c)1999 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * citrus Id: wcscat.c,v 1.1 1999/12/29 21:47:45 tshiozak Exp
+ */
+
+#include <sys/cdefs.h>
+#if 0
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: wcscat.c,v 1.1 2000/12/23 23:14:36 itojun Exp $");
+#endif /* LIBC_SCCS and not lint */
+#endif
+__FBSDID("$FreeBSD$");
+
+#include <wchar.h>
+
+wchar_t *
+wcscat(wchar_t * __restrict s1, const wchar_t * __restrict s2)
+{
+ wchar_t *cp;
+
+ cp = s1;
+ while (*cp != L'\0')
+ cp++;
+ while ((*cp++ = *s2++) != L'\0')
+ ;
+
+ return (s1);
+}
diff --git a/lib/libc/string/wcschr.c b/lib/libc/string/wcschr.c
new file mode 100644
index 000000000000..1df1fe6cd520
--- /dev/null
+++ b/lib/libc/string/wcschr.c
@@ -0,0 +1,41 @@
+/*-
+ * Copyright (c) 2002 Tim J. Robbins
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <wchar.h>
+
+wchar_t *
+wcschr(const wchar_t *s, wchar_t c)
+{
+
+ while (*s != c && *s != L'\0')
+ s++;
+ if (*s == c)
+ return ((wchar_t *)s);
+ return (NULL);
+}
diff --git a/lib/libc/string/wcscmp.c b/lib/libc/string/wcscmp.c
new file mode 100644
index 000000000000..c2abe4c797f7
--- /dev/null
+++ b/lib/libc/string/wcscmp.c
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strcmp.c 8.1 (Berkeley) 6/4/93";
+#if 0
+__RCSID("$NetBSD: wcscmp.c,v 1.3 2001/01/05 12:13:12 itojun Exp $");
+#endif
+#endif /* LIBC_SCCS and not lint */
+__FBSDID("$FreeBSD$");
+
+#include <wchar.h>
+
+/*
+ * Compare strings.
+ */
+int
+wcscmp(const wchar_t *s1, const wchar_t *s2)
+{
+
+ while (*s1 == *s2++)
+ if (*s1++ == '\0')
+ return (0);
+ /* XXX assumes wchar_t = int */
+ return (*(const unsigned int *)s1 - *(const unsigned int *)--s2);
+}
diff --git a/lib/libc/string/wcscoll.3 b/lib/libc/string/wcscoll.3
new file mode 100644
index 000000000000..ba89fb3c268e
--- /dev/null
+++ b/lib/libc/string/wcscoll.3
@@ -0,0 +1,108 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek and the American National Standards Committee X3,
+.\" on Information Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)strcoll.3 8.1 (Berkeley) 6/4/93
+.\" FreeBSD: src/lib/libc/string/strcoll.3,v 1.11 2001/10/01 16:09:00 ru Exp
+.\" $FreeBSD$
+.\"
+.Dd October 4, 2002
+.Dt WCSCOLL 3
+.Os
+.Sh NAME
+.Nm wcscoll
+.Nd compare wide strings according to current collation
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In wchar.h
+.Ft int
+.Fn wcscoll "const wchar_t *s1" "const wchar_t *s2"
+.Sh DESCRIPTION
+The
+.Fn wcscoll
+function compares the null-terminated strings
+.Fa s1
+and
+.Fa s2
+according to the current locale collation order.
+In the
+.Dq Li C
+locale,
+.Fn wcscoll
+is equivalent to
+.Fn wcscmp .
+.Sh RETURN VALUES
+The
+.Fn wcscoll
+function
+returns an integer greater than, equal to, or less than 0,
+if
+.Fa s1
+is greater than, equal to, or less than
+.Fa s2 .
+.Pp
+No return value is reserved to indicate errors;
+callers should set
+.Va errno
+to 0 before calling
+.Fn wcscoll .
+If it is non-zero upon return from
+.Fn wcscoll ,
+an error has occurred.
+.Sh ERRORS
+The
+.Fn wcscoll
+function will fail if:
+.Bl -tag -width Er
+.It Bq Er EILSEQ
+An invalid wide character code was specified.
+.It Bq Er ENOMEM
+Cannot allocate enough memory for temporary buffers.
+.El
+.Sh SEE ALSO
+.Xr setlocale 3 ,
+.Xr strcoll 3 ,
+.Xr wcscmp 3 ,
+.Xr wcsxfrm 3
+.Sh STANDARDS
+The
+.Fn wcscoll
+function
+conforms to
+.St -isoC-99 .
+.Sh BUGS
+The current implementation of
+.Fn wcscoll
+only works in single-byte
+.Dv LC_CTYPE
+locales, and falls back to using
+.Fn wcscmp
+in locales with extended character sets.
diff --git a/lib/libc/string/wcscoll.c b/lib/libc/string/wcscoll.c
new file mode 100644
index 000000000000..a3e959d10c94
--- /dev/null
+++ b/lib/libc/string/wcscoll.c
@@ -0,0 +1,223 @@
+/*-
+ * Copyright 2010 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2002 Tim J. Robbins
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include "collate.h"
+
+int
+wcscoll_l(const wchar_t *ws1, const wchar_t *ws2, locale_t locale)
+{
+ int len1, len2, pri1, pri2, ret;
+ wchar_t *tr1 = NULL, *tr2 = NULL;
+ int direc, pass;
+
+ FIX_LOCALE(locale);
+ struct xlocale_collate *table =
+ (struct xlocale_collate*)locale->components[XLC_COLLATE];
+
+ if (table->__collate_load_error)
+ /*
+ * Locale has no special collating order or could not be
+ * loaded, do a fast binary comparison.
+ */
+ return (wcscmp(ws1, ws2));
+
+ ret = 0;
+
+ /*
+ * Once upon a time we had code to try to optimize this, but
+ * it turns out that you really can't make many assumptions
+ * safely. You absolutely have to run this pass by pass,
+ * because some passes will be ignored for a given character,
+ * while others will not. Simpler locales will benefit from
+ * having fewer passes, and most comparisons should resolve
+ * during the primary pass anyway.
+ *
+ * Note that we do one final extra pass at the end to pick
+ * up UNDEFINED elements. There is special handling for them.
+ */
+ for (pass = 0; pass <= table->info->directive_count; pass++) {
+
+ const int32_t *st1 = NULL;
+ const int32_t *st2 = NULL;
+ const wchar_t *w1 = ws1;
+ const wchar_t *w2 = ws2;
+ int check1, check2;
+
+ /* special pass for UNDEFINED */
+ if (pass == table->info->directive_count) {
+ direc = DIRECTIVE_FORWARD | DIRECTIVE_UNDEFINED;
+ } else {
+ direc = table->info->directive[pass];
+ }
+
+ if (direc & DIRECTIVE_BACKWARD) {
+ wchar_t *bp, *fp, c;
+ if ((tr1 = wcsdup(w1)) == NULL)
+ goto fail;
+ bp = tr1;
+ fp = tr1 + wcslen(tr1) - 1;
+ while (bp < fp) {
+ c = *bp;
+ *bp++ = *fp;
+ *fp-- = c;
+ }
+ if ((tr2 = wcsdup(w2)) == NULL)
+ goto fail;
+ bp = tr2;
+ fp = tr2 + wcslen(tr2) - 1;
+ while (bp < fp) {
+ c = *bp;
+ *bp++ = *fp;
+ *fp-- = c;
+ }
+ w1 = tr1;
+ w2 = tr2;
+ }
+
+ if (direc & DIRECTIVE_POSITION) {
+ while (*w1 && *w2) {
+ pri1 = pri2 = 0;
+ check1 = check2 = 1;
+ while ((pri1 == pri2) && (check1 || check2)) {
+ if (check1) {
+ _collate_lookup(table, w1, &len1,
+ &pri1, pass, &st1);
+ if (pri1 < 0) {
+ errno = EINVAL;
+ goto fail;
+ }
+ if (!pri1) {
+ pri1 = COLLATE_MAX_PRIORITY;
+ st1 = NULL;
+ }
+ check1 = (st1 != NULL);
+ }
+ if (check2) {
+ _collate_lookup(table, w2, &len2,
+ &pri2, pass, &st2);
+ if (pri2 < 0) {
+ errno = EINVAL;
+ goto fail;
+ }
+ if (!pri2) {
+ pri2 = COLLATE_MAX_PRIORITY;
+ st2 = NULL;
+ }
+ check2 = (st2 != NULL);
+ }
+ }
+ if (pri1 != pri2) {
+ ret = pri1 - pri2;
+ goto end;
+ }
+ w1 += len1;
+ w2 += len2;
+ }
+ } else {
+ while (*w1 && *w2) {
+ pri1 = pri2 = 0;
+ check1 = check2 = 1;
+ while ((pri1 == pri2) && (check1 || check2)) {
+ while (check1 && *w1) {
+ _collate_lookup(table, w1,
+ &len1, &pri1, pass, &st1);
+ if (pri1 > 0)
+ break;
+ if (pri1 < 0) {
+ errno = EINVAL;
+ goto fail;
+ }
+ st1 = NULL;
+ w1 += 1;
+ }
+ check1 = (st1 != NULL);
+ while (check2 && *w2) {
+ _collate_lookup(table, w2,
+ &len2, &pri2, pass, &st2);
+ if (pri2 > 0)
+ break;
+ if (pri2 < 0) {
+ errno = EINVAL;
+ goto fail;
+ }
+ st2 = NULL;
+ w2 += 1;
+ }
+ check2 = (st2 != NULL);
+ if (!pri1 || !pri2)
+ break;
+ }
+ if (!pri1 || !pri2)
+ break;
+ if (pri1 != pri2) {
+ ret = pri1 - pri2;
+ goto end;
+ }
+ w1 += len1;
+ w2 += len2;
+ }
+ }
+ if (!*w1) {
+ if (*w2) {
+ ret = -(int)*w2;
+ goto end;
+ }
+ } else {
+ ret = *w1;
+ goto end;
+ }
+ }
+ ret = 0;
+
+end:
+ free(tr1);
+ free(tr2);
+
+ return (ret);
+
+fail:
+ ret = wcscmp(ws1, ws2);
+ goto end;
+}
+
+int
+wcscoll(const wchar_t *ws1, const wchar_t *ws2)
+{
+ return wcscoll_l(ws1, ws2, __get_locale());
+}
diff --git a/lib/libc/string/wcscpy.c b/lib/libc/string/wcscpy.c
new file mode 100644
index 000000000000..0c6e1f28f711
--- /dev/null
+++ b/lib/libc/string/wcscpy.c
@@ -0,0 +1,49 @@
+/*-
+ * Copyright (c)1999 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * citrus Id: wcscpy.c,v 1.2 2000/12/21 04:51:09 itojun Exp
+ */
+
+#include <sys/cdefs.h>
+#if 0
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: wcscpy.c,v 1.1 2000/12/23 23:14:36 itojun Exp $");
+#endif /* LIBC_SCCS and not lint */
+#endif
+__FBSDID("$FreeBSD$");
+
+#include <wchar.h>
+
+wchar_t *
+wcscpy(wchar_t * __restrict s1, const wchar_t * __restrict s2)
+{
+ wchar_t *cp;
+
+ cp = s1;
+ while ((*cp++ = *s2++) != L'\0')
+ ;
+
+ return (s1);
+}
diff --git a/lib/libc/string/wcscspn.c b/lib/libc/string/wcscspn.c
new file mode 100644
index 000000000000..7729dc8ab381
--- /dev/null
+++ b/lib/libc/string/wcscspn.c
@@ -0,0 +1,58 @@
+/*-
+ * Copyright (c)1999 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * citrus Id: wcscspn.c,v 1.1 1999/12/29 21:47:45 tshiozak Exp
+ */
+
+#include <sys/cdefs.h>
+#if 0
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: wcscspn.c,v 1.1 2000/12/23 23:14:36 itojun Exp $");
+#endif /* LIBC_SCCS and not lint */
+#endif
+__FBSDID("$FreeBSD$");
+
+#include <wchar.h>
+
+size_t
+wcscspn(const wchar_t *s, const wchar_t *set)
+{
+ const wchar_t *p;
+ const wchar_t *q;
+
+ p = s;
+ while (*p) {
+ q = set;
+ while (*q) {
+ if (*p == *q)
+ goto done;
+ q++;
+ }
+ p++;
+ }
+
+done:
+ return (p - s);
+}
diff --git a/lib/libc/string/wcsdup.c b/lib/libc/string/wcsdup.c
new file mode 100644
index 000000000000..1e5db9258a05
--- /dev/null
+++ b/lib/libc/string/wcsdup.c
@@ -0,0 +1,43 @@
+/*-
+ * Copyright (c) 2005 Tim J. Robbins.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdlib.h>
+#include <wchar.h>
+
+wchar_t *
+wcsdup(const wchar_t *s)
+{
+ wchar_t *copy;
+ size_t len;
+
+ len = wcslen(s) + 1;
+ if ((copy = malloc(len * sizeof(wchar_t))) == NULL)
+ return (NULL);
+ return (wmemcpy(copy, s, len));
+}
diff --git a/lib/libc/string/wcslcat.c b/lib/libc/string/wcslcat.c
new file mode 100644
index 000000000000..2df94777d51f
--- /dev/null
+++ b/lib/libc/string/wcslcat.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * from OpenBSD: strlcat.c,v 1.3 2000/11/24 11:10:02 itojun Exp
+ */
+
+#include <sys/cdefs.h>
+#if 0
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: wcslcat.c,v 1.1 2000/12/23 23:14:36 itojun Exp $");
+#endif /* LIBC_SCCS and not lint */
+#endif
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <wchar.h>
+
+/*
+ * Appends src to string dst of size siz (unlike wcsncat, siz is the
+ * full size of dst, not space left). At most siz-1 characters
+ * will be copied. Always NUL terminates (unless siz == 0).
+ * Returns wcslen(initial dst) + wcslen(src); if retval >= siz,
+ * truncation occurred.
+ */
+size_t
+wcslcat(wchar_t *dst, const wchar_t *src, size_t siz)
+{
+ wchar_t *d = dst;
+ const wchar_t *s = src;
+ size_t n = siz;
+ size_t dlen;
+
+ /* Find the end of dst and adjust bytes left but don't go past end */
+ while (n-- != 0 && *d != '\0')
+ d++;
+ dlen = d - dst;
+ n = siz - dlen;
+
+ if (n == 0)
+ return(dlen + wcslen(s));
+ while (*s != '\0') {
+ if (n != 1) {
+ *d++ = *s;
+ n--;
+ }
+ s++;
+ }
+ *d = '\0';
+
+ return(dlen + (s - src)); /* count does not include NUL */
+}
diff --git a/lib/libc/string/wcslcpy.c b/lib/libc/string/wcslcpy.c
new file mode 100644
index 000000000000..b104a0622a6e
--- /dev/null
+++ b/lib/libc/string/wcslcpy.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * from OpenBSD: strlcpy.c,v 1.4 1999/05/01 18:56:41 millert Exp
+ */
+
+#include <sys/cdefs.h>
+#if 0
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: wcslcpy.c,v 1.1 2000/12/23 23:14:36 itojun Exp $");
+#endif /* LIBC_SCCS and not lint */
+#endif
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <wchar.h>
+
+/*
+ * Copy src to string dst of size siz. At most siz-1 characters
+ * will be copied. Always NUL terminates (unless siz == 0).
+ * Returns wcslen(src); if retval >= siz, truncation occurred.
+ */
+size_t
+wcslcpy(wchar_t *dst, const wchar_t *src, size_t siz)
+{
+ wchar_t *d = dst;
+ const wchar_t *s = src;
+ size_t n = siz;
+
+ /* Copy as many bytes as will fit */
+ if (n != 0 && --n != 0) {
+ do {
+ if ((*d++ = *s++) == 0)
+ break;
+ } while (--n != 0);
+ }
+
+ /* Not enough room in dst, add NUL and traverse rest of src */
+ if (n == 0) {
+ if (siz != 0)
+ *d = '\0'; /* NUL-terminate dst */
+ while (*s++)
+ ;
+ }
+
+ return(s - src - 1); /* count does not include NUL */
+}
diff --git a/lib/libc/string/wcslen.c b/lib/libc/string/wcslen.c
new file mode 100644
index 000000000000..ca3004e03cb9
--- /dev/null
+++ b/lib/libc/string/wcslen.c
@@ -0,0 +1,49 @@
+/*-
+ * Copyright (c)1999 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * citrus Id: wcslen.c,v 1.1 1999/12/29 21:47:45 tshiozak Exp
+ */
+
+#include <sys/cdefs.h>
+#if 0
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: wcslen.c,v 1.1 2000/12/23 23:14:36 itojun Exp $");
+#endif /* LIBC_SCCS and not lint */
+#endif
+__FBSDID("$FreeBSD$");
+
+#include <wchar.h>
+
+size_t
+wcslen(const wchar_t *s)
+{
+ const wchar_t *p;
+
+ p = s;
+ while (*p)
+ p++;
+
+ return p - s;
+}
diff --git a/lib/libc/string/wcsncasecmp.c b/lib/libc/string/wcsncasecmp.c
new file mode 100644
index 000000000000..a42d98c92c9c
--- /dev/null
+++ b/lib/libc/string/wcsncasecmp.c
@@ -0,0 +1,49 @@
+/*-
+ * Copyright (c) 2009 David Schultz <das@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <wchar.h>
+#include <wctype.h>
+
+int
+wcsncasecmp(const wchar_t *s1, const wchar_t *s2, size_t n)
+{
+ wchar_t c1, c2;
+
+ if (n == 0)
+ return (0);
+ for (; *s1; s1++, s2++) {
+ c1 = towlower(*s1);
+ c2 = towlower(*s2);
+ if (c1 != c2)
+ return ((int)c1 - c2);
+ if (--n == 0)
+ return (0);
+ }
+ return (-*s2);
+}
diff --git a/lib/libc/string/wcsncat.c b/lib/libc/string/wcsncat.c
new file mode 100644
index 000000000000..5a243477db5b
--- /dev/null
+++ b/lib/libc/string/wcsncat.c
@@ -0,0 +1,57 @@
+/*-
+ * Copyright (c)1999 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * citrus Id: wcsncat.c,v 1.1 1999/12/29 21:47:45 tshiozak Exp
+ */
+
+#include <sys/cdefs.h>
+#if 0
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: wcsncat.c,v 1.1 2000/12/23 23:14:36 itojun Exp $");
+#endif /* LIBC_SCCS and not lint */
+#endif
+__FBSDID("$FreeBSD$");
+
+#include <wchar.h>
+
+wchar_t *
+wcsncat(wchar_t * __restrict s1, const wchar_t * __restrict s2, size_t n)
+{
+ wchar_t *p;
+ wchar_t *q;
+ const wchar_t *r;
+
+ p = s1;
+ while (*p)
+ p++;
+ q = p;
+ r = s2;
+ while (n && *r) {
+ *q++ = *r++;
+ n--;
+ }
+ *q = '\0';
+ return s1;
+}
diff --git a/lib/libc/string/wcsncmp.c b/lib/libc/string/wcsncmp.c
new file mode 100644
index 000000000000..8236d969feef
--- /dev/null
+++ b/lib/libc/string/wcsncmp.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#if 0
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strncmp.c 8.1 (Berkeley) 6/4/93";
+__RCSID("$NetBSD: wcsncmp.c,v 1.3 2001/01/05 12:13:13 itojun Exp $");
+#endif /* LIBC_SCCS and not lint */
+#endif
+__FBSDID("$FreeBSD$");
+
+#include <wchar.h>
+
+int
+wcsncmp(const wchar_t *s1, const wchar_t *s2, size_t n)
+{
+
+ if (n == 0)
+ return (0);
+ do {
+ if (*s1 != *s2++) {
+ /* XXX assumes wchar_t = int */
+ return (*(const unsigned int *)s1 -
+ *(const unsigned int *)--s2);
+ }
+ if (*s1++ == 0)
+ break;
+ } while (--n != 0);
+ return (0);
+}
diff --git a/lib/libc/string/wcsncpy.c b/lib/libc/string/wcsncpy.c
new file mode 100644
index 000000000000..215e9a115156
--- /dev/null
+++ b/lib/libc/string/wcsncpy.c
@@ -0,0 +1,64 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strncpy.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <wchar.h>
+
+/*
+ * Copy src to dst, truncating or null-padding to always copy n bytes.
+ * Return dst.
+ */
+wchar_t *
+wcsncpy(wchar_t * __restrict dst, const wchar_t * __restrict src, size_t n)
+{
+ if (n != 0) {
+ wchar_t *d = dst;
+ const wchar_t *s = src;
+
+ do {
+ if ((*d++ = *s++) == L'\0') {
+ /* NUL pad the remaining n-1 bytes */
+ while (--n != 0)
+ *d++ = L'\0';
+ break;
+ }
+ } while (--n != 0);
+ }
+ return (dst);
+}
diff --git a/lib/libc/string/wcsnlen.c b/lib/libc/string/wcsnlen.c
new file mode 100644
index 000000000000..f03cf76c05ae
--- /dev/null
+++ b/lib/libc/string/wcsnlen.c
@@ -0,0 +1,42 @@
+/*-
+ * Copyright (c) 2009 David Schultz <das@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <wchar.h>
+
+size_t
+wcsnlen(const wchar_t *s, size_t maxlen)
+{
+ size_t len;
+
+ for (len = 0; len < maxlen; len++, s++) {
+ if (!*s)
+ break;
+ }
+ return (len);
+}
diff --git a/lib/libc/string/wcspbrk.c b/lib/libc/string/wcspbrk.c
new file mode 100644
index 000000000000..2ff71ba92f61
--- /dev/null
+++ b/lib/libc/string/wcspbrk.c
@@ -0,0 +1,58 @@
+/*-
+ * Copyright (c)1999 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * citrus Id: wcspbrk.c,v 1.2 2000/12/21 05:07:25 itojun Exp
+ */
+
+#include <sys/cdefs.h>
+#if 0
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: wcspbrk.c,v 1.1 2000/12/23 23:14:37 itojun Exp $");
+#endif /* LIBC_SCCS and not lint */
+#endif
+__FBSDID("$FreeBSD$");
+
+#include <wchar.h>
+
+wchar_t *
+wcspbrk(const wchar_t *s, const wchar_t *set)
+{
+ const wchar_t *p;
+ const wchar_t *q;
+
+ p = s;
+ while (*p) {
+ q = set;
+ while (*q) {
+ if (*p == *q) {
+ /* LINTED interface specification */
+ return (wchar_t *)p;
+ }
+ q++;
+ }
+ p++;
+ }
+ return NULL;
+}
diff --git a/lib/libc/string/wcsrchr.c b/lib/libc/string/wcsrchr.c
new file mode 100644
index 000000000000..37c81ec8cdb7
--- /dev/null
+++ b/lib/libc/string/wcsrchr.c
@@ -0,0 +1,47 @@
+/*-
+ * Copyright (c) 2002 Tim J. Robbins
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <wchar.h>
+
+wchar_t *
+wcsrchr(const wchar_t *s, wchar_t c)
+{
+ const wchar_t *last;
+
+ last = NULL;
+ for (;;) {
+ if (*s == c)
+ last = s;
+ if (*s == L'\0')
+ break;
+ s++;
+ }
+
+ return ((wchar_t *)last);
+}
diff --git a/lib/libc/string/wcsspn.c b/lib/libc/string/wcsspn.c
new file mode 100644
index 000000000000..6569206208b0
--- /dev/null
+++ b/lib/libc/string/wcsspn.c
@@ -0,0 +1,60 @@
+/*-
+ * Copyright (c)1999 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * citrus Id: wcsspn.c,v 1.1 1999/12/29 21:47:45 tshiozak Exp
+ */
+
+#include <sys/cdefs.h>
+#if 0
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: wcsspn.c,v 1.1 2000/12/23 23:14:37 itojun Exp $");
+#endif /* LIBC_SCCS and not lint */
+#endif
+__FBSDID("$FreeBSD$");
+
+#include <wchar.h>
+
+size_t
+wcsspn(const wchar_t *s, const wchar_t *set)
+{
+ const wchar_t *p;
+ const wchar_t *q;
+
+ p = s;
+ while (*p) {
+ q = set;
+ while (*q) {
+ if (*p == *q)
+ break;
+ q++;
+ }
+ if (!*q)
+ goto done;
+ p++;
+ }
+
+done:
+ return (p - s);
+}
diff --git a/lib/libc/string/wcsstr.c b/lib/libc/string/wcsstr.c
new file mode 100644
index 000000000000..ce598a698969
--- /dev/null
+++ b/lib/libc/string/wcsstr.c
@@ -0,0 +1,63 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strstr.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <wchar.h>
+
+/*
+ * Find the first occurrence of find in s.
+ */
+wchar_t *
+wcsstr(const wchar_t * __restrict s, const wchar_t * __restrict find)
+{
+ wchar_t c, sc;
+ size_t len;
+
+ if ((c = *find++) != L'\0') {
+ len = wcslen(find);
+ do {
+ do {
+ if ((sc = *s++) == L'\0')
+ return (NULL);
+ } while (sc != c);
+ } while (wcsncmp(s, find, len) != 0);
+ s--;
+ }
+ return ((wchar_t *)s);
+}
diff --git a/lib/libc/string/wcstok.3 b/lib/libc/string/wcstok.3
new file mode 100644
index 000000000000..0de24d8366c8
--- /dev/null
+++ b/lib/libc/string/wcstok.3
@@ -0,0 +1,133 @@
+.\" Copyright (c) 1998 Softweyr LLC. All rights reserved.
+.\"
+.\" strtok_r, from Berkeley strtok
+.\" Oct 13, 1998 by Wes Peters <wes@softweyr.com>
+.\"
+.\" Copyright (c) 1988, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notices, this list of conditions and the following disclaimer.
+.\"
+.\" 2. Redistributions in binary form must reproduce the above
+.\" copyright notices, this list of conditions and the following
+.\" disclaimer in the documentation and/or other materials provided
+.\" with the distribution.
+.\"
+.\" 3. All advertising materials mentioning features or use of this
+.\" software must display the following acknowledgement:
+.\"
+.\" This product includes software developed by Softweyr LLC, the
+.\" University of California, Berkeley, and its contributors.
+.\"
+.\" 4. Neither the name of Softweyr LLC, the University nor the names
+.\" of its contributors may be used to endorse or promote products
+.\" derived from this software without specific prior written
+.\" permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY SOFTWEYR LLC, THE REGENTS AND
+.\" CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+.\" DISCLAIMED. IN NO EVENT SHALL SOFTWEYR LLC, THE REGENTS, OR
+.\" CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+.\" USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+.\" ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+.\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+.\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd October 3, 2002
+.Dt WCSTOK 3
+.Os
+.Sh NAME
+.Nm wcstok
+.Nd split wide-character string into tokens
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In wchar.h
+.Ft wchar_t *
+.Fn wcstok "wchar_t * restrict str" "const wchar_t * restrict sep" "wchar_t ** restrict last"
+.Sh DESCRIPTION
+The
+.Fn wcstok
+function
+is used to isolate sequential tokens in a null-terminated wide character
+string,
+.Fa str .
+These tokens are separated in the string by at least one of the
+characters in
+.Fa sep .
+The first time that
+.Fn wcstok
+is called,
+.Fa str
+should be specified; subsequent calls, wishing to obtain further tokens
+from the same string, should pass a null pointer instead.
+The separator string,
+.Fa sep ,
+must be supplied each time, and may change between calls.
+The context pointer
+.Fa last
+must be provided on each call.
+.Pp
+The
+.Fn wcstok
+function is the wide character counterpart of the
+.Fn strtok_r
+function.
+.Sh RETURN VALUES
+The
+.Fn wcstok
+function
+returns a pointer to the beginning of each subsequent token in the string,
+after replacing the token itself with a null wide character (L'\e0').
+When no more tokens remain, a null pointer is returned.
+.Sh EXAMPLES
+The following code fragment splits a wide character string on
+.Tn ASCII
+space, tab and newline characters and writes the tokens to
+standard output:
+.Bd -literal -offset indent
+const wchar_t *seps = L" \et\en";
+wchar_t *last, *tok, text[] = L" \enone\ettwo\et\etthree \en";
+
+for (tok = wcstok(text, seps, &last); tok != NULL;
+ tok = wcstok(NULL, seps, &last))
+ wprintf(L"%ls\en", tok);
+.Ed
+.Sh COMPATIBILITY
+Some early implementations of
+.Fn wcstok
+omit the
+context pointer argument,
+.Fa last ,
+and maintain state across calls in a static variable like
+.Fn strtok
+does.
+.Sh SEE ALSO
+.Xr strtok 3 ,
+.Xr wcschr 3 ,
+.Xr wcscspn 3 ,
+.Xr wcspbrk 3 ,
+.Xr wcsrchr 3 ,
+.Xr wcsspn 3
+.Sh STANDARDS
+The
+.Fn wcstok
+function
+conforms to
+.St -isoC-99 .
diff --git a/lib/libc/string/wcstok.c b/lib/libc/string/wcstok.c
new file mode 100644
index 000000000000..441fbd444854
--- /dev/null
+++ b/lib/libc/string/wcstok.c
@@ -0,0 +1,86 @@
+/*-
+ * Copyright (c) 1998 Softweyr LLC. All rights reserved.
+ *
+ * strtok_r, from Berkeley strtok
+ * Oct 13, 1998 by Wes Peters <wes@softweyr.com>
+ *
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notices, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notices, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY SOFTWEYR LLC, THE REGENTS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SOFTWEYR LLC, THE
+ * REGENTS, OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <wchar.h>
+
+wchar_t *
+wcstok(wchar_t * __restrict s, const wchar_t * __restrict delim,
+ wchar_t ** __restrict last)
+{
+ const wchar_t *spanp;
+ wchar_t *tok;
+ wchar_t c, sc;
+
+ if (s == NULL && (s = *last) == NULL)
+ return (NULL);
+
+ /*
+ * Skip (span) leading delimiters (s += wcsspn(s, delim), sort of).
+ */
+cont:
+ c = *s++;
+ for (spanp = delim; (sc = *spanp++) != L'\0';) {
+ if (c == sc)
+ goto cont;
+ }
+
+ if (c == L'\0') { /* no non-delimiter characters */
+ *last = NULL;
+ return (NULL);
+ }
+ tok = s - 1;
+
+ /*
+ * Scan token (scan for delimiters: s += wcscspn(s, delim), sort of).
+ * Note that delim must have one NUL; we stop if we see that, too.
+ */
+ for (;;) {
+ c = *s++;
+ spanp = delim;
+ do {
+ if ((sc = *spanp++) == c) {
+ if (c == L'\0')
+ s = NULL;
+ else
+ s[-1] = L'\0';
+ *last = s;
+ return (tok);
+ }
+ } while (sc != L'\0');
+ }
+ /* NOTREACHED */
+}
diff --git a/lib/libc/string/wcswidth.3 b/lib/libc/string/wcswidth.3
new file mode 100644
index 000000000000..76d32ad8e4b9
--- /dev/null
+++ b/lib/libc/string/wcswidth.3
@@ -0,0 +1,62 @@
+.\" Copyright (c) 2002 Tim J. Robbins
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd August 20, 2002
+.Dt WCSWIDTH 3
+.Os
+.Sh NAME
+.Nm wcswidth
+.Nd "number of column positions in wide-character string"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In wchar.h
+.Ft int
+.Fn wcswidth "const wchar_t *pwcs" "size_t n"
+.Sh DESCRIPTION
+The
+.Fn wcswidth
+function determines the number of column positions required for the first
+.Fa n
+characters of
+.Fa pwcs ,
+or until a null wide character (L'\e0') is encountered.
+.Sh RETURN VALUES
+The
+.Fn wcswidth
+function returns 0 if
+.Fa pwcs
+is an empty string (L""),
+\-1 if a non-printing wide character is encountered,
+otherwise it returns the number of column positions occupied.
+.Sh SEE ALSO
+.Xr iswprint 3 ,
+.Xr wcwidth 3
+.Sh STANDARDS
+The
+.Fn wcswidth
+function conforms to
+.St -p1003.1-2001 .
diff --git a/lib/libc/string/wcswidth.c b/lib/libc/string/wcswidth.c
new file mode 100644
index 000000000000..bac979b5b9f0
--- /dev/null
+++ b/lib/libc/string/wcswidth.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Borman at Krystal Technologies.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <wchar.h>
+#include "xlocale_private.h"
+
+int
+wcswidth_l(const wchar_t *pwcs, size_t n, locale_t locale)
+{
+ wchar_t wc;
+ int len, l;
+ FIX_LOCALE(locale);
+
+ len = 0;
+ while (n-- > 0 && (wc = *pwcs++) != L'\0') {
+ if ((l = wcwidth_l(wc, locale)) < 0)
+ return (-1);
+ len += l;
+ }
+ return (len);
+}
+
+int
+wcswidth(const wchar_t *pwcs, size_t n)
+{
+ return wcswidth_l(pwcs, n, __get_locale());
+}
diff --git a/lib/libc/string/wcsxfrm.3 b/lib/libc/string/wcsxfrm.3
new file mode 100644
index 000000000000..ac30d38e1131
--- /dev/null
+++ b/lib/libc/string/wcsxfrm.3
@@ -0,0 +1,122 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek and the American National Standards Committee X3,
+.\" on Information Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)strxfrm.3 8.1 (Berkeley) 6/4/93
+.\" FreeBSD: src/lib/libc/string/strxfrm.3,v 1.16 2002/09/06 11:24:06 tjr Exp
+.\" $FreeBSD$
+.\"
+.Dd October 4, 2002
+.Dt WCSXFRM 3
+.Os
+.Sh NAME
+.Nm wcsxfrm
+.Nd transform a wide string under locale
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In wchar.h
+.Ft size_t
+.Fn wcsxfrm "wchar_t * restrict dst" "const wchar_t * restrict src" "size_t n"
+.Sh DESCRIPTION
+The
+.Fn wcsxfrm
+function transforms a null-terminated wide character string pointed to by
+.Fa src
+according to the current locale collation order
+then copies the transformed string
+into
+.Fa dst .
+No more than
+.Fa n
+wide characters are copied into
+.Fa dst ,
+including the terminating null character added.
+If
+.Fa n
+is set to 0
+(it helps to determine an actual size needed
+for transformation),
+.Fa dst
+is permitted to be a
+.Dv NULL
+pointer.
+.Pp
+Comparing two strings using
+.Fn wcscmp
+after
+.Fn wcsxfrm
+is equivalent to comparing
+two original strings with
+.Fn wcscoll .
+.Sh RETURN VALUES
+Upon successful completion,
+.Fn wcsxfrm
+returns the length of the transformed string not including
+the terminating null character.
+If this value is
+.Fa n
+or more, the contents of
+.Fa dst
+are indeterminate.
+.Sh SEE ALSO
+.Xr setlocale 3 ,
+.Xr strxfrm 3 ,
+.Xr wcscmp 3 ,
+.Xr wcscoll 3
+.Sh STANDARDS
+The
+.Fn wcsxfrm
+function
+conforms to
+.St -isoC-99 .
+.Sh BUGS
+The current implementation of
+.Fn wcsxfrm
+only works in single-byte
+.Dv LC_CTYPE
+locales, and falls back to using
+.Fn wcsncpy
+in locales with extended character sets.
+.Pp
+Comparing two strings using
+.Fn wcscmp
+after
+.Fn wcsxfrm
+is
+.Em not
+always equivalent to comparison with
+.Fn wcscoll ;
+.Fn wcsxfrm
+only stores information about primary collation weights into
+.Fa dst ,
+whereas
+.Fn wcscoll
+compares characters using both primary and secondary weights.
diff --git a/lib/libc/string/wcsxfrm.c b/lib/libc/string/wcsxfrm.c
new file mode 100644
index 000000000000..3d6c9601db01
--- /dev/null
+++ b/lib/libc/string/wcsxfrm.c
@@ -0,0 +1,85 @@
+/*-
+ * Copyright 2010 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 1995 Alex Tatmanjants <alex@elvisti.kiev.ua>
+ * at Electronni Visti IA, Kiev, Ukraine.
+ * All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 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 <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include "collate.h"
+
+size_t
+wcsxfrm_l(wchar_t * __restrict dest, const wchar_t * __restrict src, size_t len, locale_t locale)
+{
+ size_t slen;
+ FIX_LOCALE(locale);
+ struct xlocale_collate *table =
+ (struct xlocale_collate*)locale->components[XLC_COLLATE];
+
+ if (*src == L'\0') {
+ if (len != 0)
+ *dest = L'\0';
+ return (0);
+ }
+
+ if ((table->__collate_load_error) ||
+ ((slen = _collate_wxfrm(table, src, dest, len)) == (size_t)-1)) {
+ goto error;
+ }
+
+ /* Add null termination at the correct location. */
+ if (len > slen) {
+ dest[slen] = 0;
+ } else if (len) {
+ dest[len-1] = 0;
+ }
+
+ return (slen);
+
+error:
+ slen = wcslen(src);
+ if (slen < len)
+ (void) wcscpy(dest, src);
+ else {
+ (void) wcsncpy(dest, src, len - 1);
+ dest[len - 1] = L'\0';
+ }
+ return (slen);
+}
+
+size_t
+wcsxfrm(wchar_t * __restrict dest, const wchar_t * __restrict src, size_t len)
+{
+ return wcsxfrm_l(dest, src, len, __get_locale());
+}
diff --git a/lib/libc/string/wmemchr.3 b/lib/libc/string/wmemchr.3
new file mode 100644
index 000000000000..37ba05031ca9
--- /dev/null
+++ b/lib/libc/string/wmemchr.3
@@ -0,0 +1,174 @@
+.\" $NetBSD: wmemchr.3,v 1.4 2001/01/02 11:26:23 itojun Exp $
+.\"
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek and the American National Standards Committee X3,
+.\" on Information Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" from: @(#)strcpy.3 8.1 (Berkeley) 6/4/93
+.\"
+.\" $FreeBSD$
+.\"
+.Dd March 4, 2009
+.Dt WMEMCHR 3
+.Os
+.Sh NAME
+.Nm wmemchr ,
+.Nm wmemcmp ,
+.Nm wmemcpy ,
+.Nm wmemmove ,
+.Nm wmemset ,
+.Nm wcpcpy ,
+.Nm wcpncpy ,
+.Nm wcscasecmp ,
+.Nm wcscat ,
+.Nm wcschr ,
+.Nm wcscmp ,
+.Nm wcscpy ,
+.Nm wcscspn ,
+.Nm wcsdup ,
+.Nm wcslcat ,
+.Nm wcslcpy ,
+.Nm wcslen ,
+.Nm wcsncasecmp ,
+.Nm wcsncat ,
+.Nm wcsncmp ,
+.Nm wcsncpy ,
+.Nm wcsnlen ,
+.Nm wcspbrk ,
+.Nm wcsrchr ,
+.Nm wcsspn ,
+.Nm wcsstr
+.Nd wide character string manipulation operations
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In wchar.h
+.Ft wchar_t *
+.Fn wmemchr "const wchar_t *s" "wchar_t c" "size_t n"
+.Ft int
+.Fn wmemcmp "const wchar_t *s1" "const wchar_t *s2" "size_t n"
+.Ft wchar_t *
+.Fn wmemcpy "wchar_t * restrict s1" "const wchar_t * restrict s2" "size_t n"
+.Ft wchar_t *
+.Fn wmemmove "wchar_t *s1" "const wchar_t *s2" "size_t n"
+.Ft wchar_t *
+.Fn wmemset "wchar_t *s" "wchar_t c" "size_t n"
+.Ft wchar_t *
+.Fn wcpcpy "wchar_t *s1" "wchar_t *s2"
+.Ft wchar_t *
+.Fn wcpncpy "wchar_t *s1" "wchar_t *s2" "size_t n"
+.Ft int
+.Fn wcscasecmp "const wchar_t *s1" "const wchar_t *s2"
+.Ft wchar_t *
+.Fn wcscat "wchar_t * restrict s1" "const wchar_t * restrict s2"
+.Ft wchar_t *
+.Fn wcschr "const wchar_t *s" "wchar_t c"
+.Ft int
+.Fn wcscmp "const wchar_t *s1" "const wchar_t *s2"
+.Ft wchar_t *
+.Fn wcscpy "wchar_t * restrict s1" "const wchar_t * restrict s2"
+.Ft size_t
+.Fn wcscspn "const wchar_t *s1" "const wchar_t *s2"
+.Ft wchar_t *
+.Fn wcsdup "const wchar_t *s"
+.Ft size_t
+.Fn wcslcat "wchar_t *s1" "const wchar_t *s2" "size_t n"
+.Ft size_t
+.Fn wcslcpy "wchar_t *s1" "const wchar_t *s2" "size_t n"
+.Ft size_t
+.Fn wcslen "const wchar_t *s"
+.Ft int
+.Fn wcsncasecmp "const wchar_t *s1" "const wchar_t *s2" "size_t n"
+.Ft wchar_t *
+.Fn wcsncat "wchar_t * restrict s1" "const wchar_t * restrict s2" "size_t n"
+.Ft int
+.Fn wcsncmp "const wchar_t *s1" "const wchar_t * s2" "size_t n"
+.Ft wchar_t *
+.Fn wcsncpy "wchar_t * restrict s1" "const wchar_t * restrict s2" "size_t n"
+.Ft size_t
+.Fn wcsnlen "const wchar_t *s" "size_t maxlen"
+.Ft wchar_t *
+.Fn wcspbrk "const wchar_t *s1" "const wchar_t *s2"
+.Ft wchar_t *
+.Fn wcsrchr "const wchar_t *s" "wchar_t c"
+.Ft size_t
+.Fn wcsspn "const wchar_t *s1" "const wchar_t *s2"
+.Ft wchar_t *
+.Fn wcsstr "const wchar_t * restrict s1" "const wchar_t * restrict s2"
+.Sh DESCRIPTION
+The functions implement string manipulation operations over wide character
+strings.
+For a detailed description, refer to documents for the respective single-byte
+counterpart, such as
+.Xr memchr 3 .
+.Sh SEE ALSO
+.Xr memchr 3 ,
+.Xr memcmp 3 ,
+.Xr memcpy 3 ,
+.Xr memmove 3 ,
+.Xr memset 3 ,
+.Xr stpcpy 3 ,
+.Xr stpncpy 3 ,
+.Xr strcasecmp 3 ,
+.Xr strcat 3 ,
+.Xr strchr 3 ,
+.Xr strcmp 3 ,
+.Xr strcpy 3 ,
+.Xr strcspn 3 ,
+.Xr strdup 3 ,
+.Xr strlcat 3 ,
+.Xr strlcpy 3 ,
+.Xr strlen 3 ,
+.Xr strncat 3 ,
+.Xr strncmp 3 ,
+.Xr strncpy 3 ,
+.Xr strnlen 3 ,
+.Xr strpbrk 3 ,
+.Xr strrchr 3 ,
+.Xr strspn 3 ,
+.Xr strstr 3
+.Sh STANDARDS
+These functions conform to
+.St -isoC-99 ,
+with the exception of
+.Fn wcpcpy ,
+.Fn wcpncpy ,
+.Fn wcscasecmp ,
+.Fn wcsdup ,
+.Fn wcsncasecmp ,
+and
+.Fn wcsnlen ,
+which conform to
+.St -p1003.1-2008 ;
+and
+.Fn wcslcat
+and
+.Fn wcslcpy ,
+which are extensions.
diff --git a/lib/libc/string/wmemchr.c b/lib/libc/string/wmemchr.c
new file mode 100644
index 000000000000..cab89c9ade4f
--- /dev/null
+++ b/lib/libc/string/wmemchr.c
@@ -0,0 +1,52 @@
+/*-
+ * Copyright (c)1999 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * citrus Id: wmemchr.c,v 1.2 2000/12/20 14:08:31 itojun Exp
+ */
+
+#include <sys/cdefs.h>
+#if 0
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: wmemchr.c,v 1.1 2000/12/23 23:14:37 itojun Exp $");
+#endif /* LIBC_SCCS and not lint */
+#endif
+__FBSDID("$FreeBSD$");
+
+#include <wchar.h>
+
+wchar_t *
+wmemchr(const wchar_t *s, wchar_t c, size_t n)
+{
+ size_t i;
+
+ for (i = 0; i < n; i++) {
+ if (*s == c) {
+ /* LINTED const castaway */
+ return (wchar_t *)s;
+ }
+ s++;
+ }
+ return NULL;
+}
diff --git a/lib/libc/string/wmemcmp.c b/lib/libc/string/wmemcmp.c
new file mode 100644
index 000000000000..fdb1f986f3a4
--- /dev/null
+++ b/lib/libc/string/wmemcmp.c
@@ -0,0 +1,53 @@
+/*-
+ * Copyright (c)1999 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * citrus Id: wmemcmp.c,v 1.2 2000/12/20 14:08:31 itojun Exp
+ */
+
+#include <sys/cdefs.h>
+#if 0
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: wmemcmp.c,v 1.1 2000/12/23 23:14:37 itojun Exp $");
+#endif /* LIBC_SCCS and not lint */
+#endif
+__FBSDID("$FreeBSD$");
+
+#include <wchar.h>
+
+int
+wmemcmp(const wchar_t *s1, const wchar_t *s2, size_t n)
+{
+ size_t i;
+
+ for (i = 0; i < n; i++) {
+ if (*s1 != *s2) {
+ /* wchar might be unsigned */
+ return *s1 > *s2 ? 1 : -1;
+ }
+ s1++;
+ s2++;
+ }
+ return 0;
+}
diff --git a/lib/libc/string/wmemcpy.c b/lib/libc/string/wmemcpy.c
new file mode 100644
index 000000000000..c10770ce4ec5
--- /dev/null
+++ b/lib/libc/string/wmemcpy.c
@@ -0,0 +1,44 @@
+/*-
+ * Copyright (c)1999 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * citrus Id: wmemcpy.c,v 1.2 2000/12/20 14:08:31 itojun Exp
+ */
+
+#include <sys/cdefs.h>
+#if 0
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: wmemcpy.c,v 1.1 2000/12/23 23:14:37 itojun Exp $");
+#endif /* LIBC_SCCS and not lint */
+#endif
+__FBSDID("$FreeBSD$");
+
+#include <string.h>
+#include <wchar.h>
+
+wchar_t *
+wmemcpy(wchar_t * __restrict d, const wchar_t * __restrict s, size_t n)
+{
+ return (wchar_t *)memcpy(d, s, n * sizeof(wchar_t));
+}
diff --git a/lib/libc/string/wmemmove.c b/lib/libc/string/wmemmove.c
new file mode 100644
index 000000000000..05cfd1082afe
--- /dev/null
+++ b/lib/libc/string/wmemmove.c
@@ -0,0 +1,44 @@
+/*-
+ * Copyright (c)1999 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * citrus Id: wmemmove.c,v 1.2 2000/12/20 14:08:31 itojun Exp
+ */
+
+#include <sys/cdefs.h>
+#if 0
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: wmemmove.c,v 1.1 2000/12/23 23:14:37 itojun Exp $");
+#endif /* LIBC_SCCS and not lint */
+#endif
+__FBSDID("$FreeBSD$");
+
+#include <string.h>
+#include <wchar.h>
+
+wchar_t *
+wmemmove(wchar_t *d, const wchar_t *s, size_t n)
+{
+ return (wchar_t *)memmove(d, s, n * sizeof(wchar_t));
+}
diff --git a/lib/libc/string/wmemset.c b/lib/libc/string/wmemset.c
new file mode 100644
index 000000000000..0e96356ec007
--- /dev/null
+++ b/lib/libc/string/wmemset.c
@@ -0,0 +1,51 @@
+/*-
+ * Copyright (c)1999 Citrus Project,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * citrus Id: wmemset.c,v 1.2 2000/12/20 14:08:31 itojun Exp
+ */
+
+#include <sys/cdefs.h>
+#if 0
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: wmemset.c,v 1.1 2000/12/23 23:14:37 itojun Exp $");
+#endif /* LIBC_SCCS and not lint */
+#endif
+__FBSDID("$FreeBSD$");
+
+#include <wchar.h>
+
+wchar_t *
+wmemset(wchar_t *s, wchar_t c, size_t n)
+{
+ size_t i;
+ wchar_t *p;
+
+ p = (wchar_t *)s;
+ for (i = 0; i < n; i++) {
+ *p = c;
+ p++;
+ }
+ return s;
+}
diff --git a/lib/libc/sys/Makefile.inc b/lib/libc/sys/Makefile.inc
new file mode 100644
index 000000000000..03c326c93711
--- /dev/null
+++ b/lib/libc/sys/Makefile.inc
@@ -0,0 +1,486 @@
+# @(#)Makefile.inc 8.3 (Berkeley) 10/24/94
+# $FreeBSD$
+
+# sys sources
+.PATH: ${LIBC_SRCTOP}/${LIBC_ARCH}/sys ${LIBC_SRCTOP}/sys
+
+# Include the generated makefile containing the *complete* list
+# of syscall names in MIASM.
+.include "${SRCTOP}/sys/sys/syscall.mk"
+
+# Include machine dependent definitions.
+#
+# MDASM names override the default syscall names in MIASM.
+# NOASM will prevent the default syscall code from being generated.
+# PSEUDO generates _<sys>() and __sys_<sys>() symbols, but not <sys>().
+#
+# While historically machine dependent, all architectures have the following
+# declarations in common:
+#
+NOASM= break.o \
+ exit.o \
+ getlogin.o \
+ sstk.o \
+ yield.o
+PSEUDO= _exit.o \
+ _getlogin.o
+.sinclude "${LIBC_SRCTOP}/${LIBC_ARCH}/sys/Makefile.inc"
+
+SRCS+= clock_gettime.c gettimeofday.c __vdso_gettimeofday.c
+NOASM+= clock_gettime.o gettimeofday.o
+PSEUDO+= _clock_gettime.o _gettimeofday.o
+
+# Sources common to both syscall interfaces:
+SRCS+= \
+ __error.c \
+ interposing_table.c
+
+SRCS+= futimens.c utimensat.c
+NOASM+= futimens.o utimensat.o
+PSEUDO+= _futimens.o _utimensat.o
+
+SRCS+= pipe.c
+
+INTERPOSED = \
+ accept \
+ accept4 \
+ aio_suspend \
+ close \
+ connect \
+ fcntl \
+ fdatasync \
+ fsync \
+ fork \
+ kevent \
+ msync \
+ nanosleep \
+ open \
+ openat \
+ poll \
+ ppoll \
+ pselect \
+ ptrace \
+ read \
+ readv \
+ recvfrom \
+ recvmsg \
+ select \
+ sendmsg \
+ sendto \
+ setcontext \
+ sigprocmask \
+ sigsuspend \
+ sigtimedwait \
+ sigwait \
+ sigwaitinfo \
+ swapcontext \
+ wait4 \
+ wait6 \
+ write \
+ writev
+
+.if ${MACHINE_CPUARCH} == "sparc64"
+SRCS+= sigaction.c
+NOASM+= sigaction.o
+.else
+INTERPOSED+= sigaction
+.endif
+
+SRCS+= ${INTERPOSED:S/$/.c/}
+NOASM+= ${INTERPOSED:S/$/.o/}
+PSEUDO+= ${INTERPOSED:C/^.*$/_&.o/}
+
+# Add machine dependent asm sources:
+SRCS+=${MDASM}
+
+# Look though the complete list of syscalls (MIASM) for names that are
+# not defined with machine dependent implementations (MDASM) and are
+# not declared for no generation of default code (NOASM). Add each
+# syscall that satisfies these conditions to the ASM list.
+.for _asm in ${MIASM}
+.if (${MDASM:R:M${_asm:R}} == "")
+.if (${NOASM:R:M${_asm:R}} == "")
+ASM+=$(_asm)
+.endif
+.endif
+.endfor
+
+SASM= ${ASM:S/.o/.S/}
+
+SPSEUDO= ${PSEUDO:S/.o/.S/}
+
+SRCS+= ${SASM} ${SPSEUDO}
+
+SYM_MAPS+= ${LIBC_SRCTOP}/sys/Symbol.map
+
+# Generated files
+CLEANFILES+= ${SASM} ${SPSEUDO}
+
+.if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_CPUARCH} == "i386" || \
+ ${MACHINE_CPUARCH} == "powerpc" || ${MACHINE_ARCH:Marmv6*}
+NOTE_GNU_STACK='\t.section .note.GNU-stack,"",%%progbits\n'
+.else
+NOTE_GNU_STACK=''
+.endif
+
+${SASM}:
+ printf '#include "compat.h"\n' > ${.TARGET}
+ printf '#include "SYS.h"\nRSYSCALL(${.PREFIX})\n' >> ${.TARGET}
+ printf ${NOTE_GNU_STACK} >>${.TARGET}
+
+${SPSEUDO}:
+ printf '#include "compat.h"\n' > ${.TARGET}
+ printf '#include "SYS.h"\nPSEUDO(${.PREFIX:S/_//})\n' \
+ >> ${.TARGET}
+ printf ${NOTE_GNU_STACK} >>${.TARGET}
+
+MAN+= abort2.2 \
+ accept.2 \
+ access.2 \
+ acct.2 \
+ adjtime.2 \
+ aio_cancel.2 \
+ aio_error.2 \
+ aio_fsync.2 \
+ aio_mlock.2 \
+ aio_read.2 \
+ aio_return.2 \
+ aio_suspend.2 \
+ aio_waitcomplete.2 \
+ aio_write.2 \
+ bind.2 \
+ bindat.2 \
+ brk.2 \
+ cap_enter.2 \
+ cap_fcntls_limit.2 \
+ cap_ioctls_limit.2 \
+ cap_rights_limit.2 \
+ chdir.2 \
+ chflags.2 \
+ chmod.2 \
+ chown.2 \
+ chroot.2 \
+ clock_gettime.2 \
+ close.2 \
+ closefrom.2 \
+ connect.2 \
+ connectat.2 \
+ cpuset.2 \
+ cpuset_getaffinity.2 \
+ dup.2 \
+ execve.2 \
+ _exit.2 \
+ extattr_get_file.2 \
+ fcntl.2 \
+ ffclock.2 \
+ fhopen.2 \
+ flock.2 \
+ fork.2 \
+ fsync.2 \
+ getdirentries.2 \
+ getdtablesize.2 \
+ getfh.2 \
+ getfsstat.2 \
+ getgid.2 \
+ getgroups.2 \
+ getitimer.2 \
+ getlogin.2 \
+ getloginclass.2 \
+ getpeername.2 \
+ getpgrp.2 \
+ getpid.2 \
+ getpriority.2 \
+ getrlimit.2 \
+ getrusage.2 \
+ getsid.2 \
+ getsockname.2 \
+ getsockopt.2 \
+ gettimeofday.2 \
+ getuid.2 \
+ intro.2 \
+ ioctl.2 \
+ issetugid.2 \
+ jail.2 \
+ kenv.2 \
+ kill.2 \
+ kldfind.2 \
+ kldfirstmod.2 \
+ kldload.2 \
+ kldnext.2 \
+ kldstat.2 \
+ kldsym.2 \
+ kldunload.2 \
+ kqueue.2 \
+ ktrace.2 \
+ link.2 \
+ lio_listio.2 \
+ listen.2 \
+ lseek.2 \
+ madvise.2 \
+ mincore.2 \
+ minherit.2 \
+ mkdir.2 \
+ mkfifo.2 \
+ mknod.2 \
+ mlock.2 \
+ mlockall.2 \
+ mmap.2 \
+ modfind.2 \
+ modnext.2 \
+ modstat.2 \
+ mount.2 \
+ mprotect.2 \
+ mq_close.2 \
+ mq_getattr.2 \
+ mq_notify.2 \
+ mq_open.2 \
+ mq_receive.2 \
+ mq_send.2 \
+ mq_setattr.2 \
+ msgctl.2 \
+ msgget.2 \
+ msgrcv.2 \
+ msgsnd.2 \
+ msync.2 \
+ munmap.2 \
+ nanosleep.2 \
+ nfssvc.2 \
+ ntp_adjtime.2 \
+ numa_getaffinity.2 \
+ open.2 \
+ pathconf.2 \
+ pdfork.2 \
+ pipe.2 \
+ poll.2 \
+ posix_fadvise.2 \
+ posix_fallocate.2 \
+ posix_openpt.2 \
+ procctl.2 \
+ profil.2 \
+ pselect.2 \
+ ptrace.2 \
+ quotactl.2 \
+ rctl_add_rule.2 \
+ read.2 \
+ readlink.2 \
+ reboot.2 \
+ recv.2 \
+ rename.2 \
+ revoke.2 \
+ rfork.2 \
+ rmdir.2 \
+ rtprio.2
+.if !defined(NO_P1003_1B)
+MAN+= sched_get_priority_max.2 \
+ sched_setparam.2 \
+ sched_setscheduler.2 \
+ sched_yield.2
+.endif
+MAN+= sctp_generic_recvmsg.2 \
+ sctp_generic_sendmsg.2 \
+ sctp_peeloff.2 \
+ select.2 \
+ semctl.2 \
+ semget.2 \
+ semop.2 \
+ send.2 \
+ setfib.2 \
+ sendfile.2 \
+ setgroups.2 \
+ setpgid.2 \
+ setregid.2 \
+ setresuid.2 \
+ setreuid.2 \
+ setsid.2 \
+ setuid.2 \
+ shmat.2 \
+ shmctl.2 \
+ shmget.2 \
+ shm_open.2 \
+ shutdown.2 \
+ sigaction.2 \
+ sigaltstack.2 \
+ sigpending.2 \
+ sigprocmask.2 \
+ sigqueue.2 \
+ sigreturn.2 \
+ sigstack.2 \
+ sigsuspend.2 \
+ sigwait.2 \
+ sigwaitinfo.2 \
+ socket.2 \
+ socketpair.2 \
+ stat.2 \
+ statfs.2 \
+ swapon.2 \
+ symlink.2 \
+ sync.2 \
+ sysarch.2 \
+ syscall.2 \
+ thr_exit.2 \
+ thr_kill.2 \
+ thr_new.2 \
+ thr_self.2 \
+ thr_set_name.2 \
+ thr_suspend.2 \
+ thr_wake.2 \
+ timer_create.2 \
+ timer_delete.2 \
+ timer_settime.2 \
+ truncate.2 \
+ umask.2 \
+ undelete.2 \
+ unlink.2 \
+ utimensat.2 \
+ utimes.2 \
+ utrace.2 \
+ uuidgen.2 \
+ vfork.2 \
+ wait.2 \
+ write.2 \
+ _umtx_op.2
+
+MLINKS+=accept.2 accept4.2
+MLINKS+=access.2 eaccess.2 \
+ access.2 faccessat.2
+MLINKS+=brk.2 sbrk.2
+MLINKS+=cap_enter.2 cap_getmode.2
+MLINKS+=cap_fcntls_limit.2 cap_fcntls_get.2
+MLINKS+=cap_ioctls_limit.2 cap_ioctls_get.2
+MLINKS+=cap_rights_limit.2 cap_rights_get.2
+MLINKS+=chdir.2 fchdir.2
+MLINKS+=chflags.2 chflagsat.2 \
+ chflags.2 fchflags.2 \
+ chflags.2 lchflags.2
+MLINKS+=chmod.2 fchmod.2 \
+ chmod.2 fchmodat.2 \
+ chmod.2 lchmod.2
+MLINKS+=chown.2 fchown.2 \
+ chown.2 fchownat.2 \
+ chown.2 lchown.2
+MLINKS+=clock_gettime.2 clock_getres.2 \
+ clock_gettime.2 clock_settime.2
+MLINKS+=cpuset.2 cpuset_getid.2 \
+ cpuset.2 cpuset_setid.2
+MLINKS+=cpuset_getaffinity.2 cpuset_setaffinity.2
+MLINKS+=dup.2 dup2.2
+MLINKS+=execve.2 fexecve.2
+MLINKS+=extattr_get_file.2 extattr.2 \
+ extattr_get_file.2 extattr_delete_fd.2 \
+ extattr_get_file.2 extattr_delete_file.2 \
+ extattr_get_file.2 extattr_delete_link.2 \
+ extattr_get_file.2 extattr_get_fd.2 \
+ extattr_get_file.2 extattr_get_link.2 \
+ extattr_get_file.2 extattr_list_fd.2 \
+ extattr_get_file.2 extattr_list_file.2 \
+ extattr_get_file.2 extattr_list_link.2 \
+ extattr_get_file.2 extattr_set_fd.2 \
+ extattr_get_file.2 extattr_set_file.2 \
+ extattr_get_file.2 extattr_set_link.2
+MLINKS+=ffclock.2 ffclock_getcounter.2 \
+ ffclock.2 ffclock_getestimate.2 \
+ ffclock.2 ffclock_setestimate.2
+MLINKS+=fhopen.2 fhstat.2 fhopen.2 fhstatfs.2
+MLINKS+=fsync.2 fdatasync.2
+MLINKS+=getdirentries.2 getdents.2
+MLINKS+=getfh.2 lgetfh.2
+MLINKS+=getgid.2 getegid.2
+MLINKS+=getitimer.2 setitimer.2
+MLINKS+=getlogin.2 getlogin_r.3
+MLINKS+=getlogin.2 setlogin.2
+MLINKS+=getloginclass.2 setloginclass.2
+MLINKS+=getpgrp.2 getpgid.2
+MLINKS+=getpid.2 getppid.2
+MLINKS+=getpriority.2 setpriority.2
+MLINKS+=getrlimit.2 setrlimit.2
+MLINKS+=getsockopt.2 setsockopt.2
+MLINKS+=gettimeofday.2 settimeofday.2
+MLINKS+=getuid.2 geteuid.2
+MLINKS+=intro.2 errno.2
+MLINKS+=jail.2 jail_attach.2 \
+ jail.2 jail_get.2 \
+ jail.2 jail_remove.2 \
+ jail.2 jail_set.2
+MLINKS+=kldunload.2 kldunloadf.2
+MLINKS+=kqueue.2 kevent.2 \
+ kqueue.2 EV_SET.3
+MLINKS+=link.2 linkat.2
+MLINKS+=madvise.2 posix_madvise.2
+MLINKS+=mkdir.2 mkdirat.2
+MLINKS+=mkfifo.2 mkfifoat.2
+MLINKS+=mknod.2 mknodat.2
+MLINKS+=mlock.2 munlock.2
+MLINKS+=mlockall.2 munlockall.2
+MLINKS+=modnext.2 modfnext.2
+MLINKS+=mount.2 nmount.2 \
+ mount.2 unmount.2
+MLINKS+=mq_receive.2 mq_timedreceive.2
+MLINKS+=mq_send.2 mq_timedsend.2
+MLINKS+=ntp_adjtime.2 ntp_gettime.2
+MLINKS+=numa_getaffinity.2 numa_setaffinity.2
+MLINKS+=open.2 openat.2
+MLINKS+=pathconf.2 fpathconf.2
+MLINKS+=pathconf.2 lpathconf.2
+MLINKS+=pdfork.2 pdgetpid.2\
+ pdfork.2 pdkill.2 \
+ pdfork.2 pdwait4.2
+MLINKS+=pipe.2 pipe2.2
+MLINKS+=poll.2 ppoll.2
+MLINKS+=rctl_add_rule.2 rctl_get_limits.2 \
+ rctl_add_rule.2 rctl_get_racct.2 \
+ rctl_add_rule.2 rctl_get_rules.2 \
+ rctl_add_rule.2 rctl_remove_rule.2
+MLINKS+=read.2 pread.2 \
+ read.2 preadv.2 \
+ read.2 readv.2
+MLINKS+=readlink.2 readlinkat.2
+MLINKS+=recv.2 recvfrom.2 \
+ recv.2 recvmsg.2
+MLINKS+=rename.2 renameat.2
+MLINKS+=rtprio.2 rtprio_thread.2
+.if !defined(NO_P1003_1B)
+MLINKS+=sched_get_priority_max.2 sched_get_priority_min.2 \
+ sched_get_priority_max.2 sched_rr_get_interval.2
+MLINKS+=sched_setparam.2 sched_getparam.2
+MLINKS+=sched_setscheduler.2 sched_getscheduler.2
+.endif
+MLINKS+=select.2 FD_CLR.3 \
+ select.2 FD_ISSET.3 \
+ select.2 FD_SET.3 \
+ select.2 FD_ZERO.3
+MLINKS+=send.2 sendmsg.2 \
+ send.2 sendto.2
+MLINKS+=setpgid.2 setpgrp.2
+MLINKS+=setresuid.2 getresgid.2 \
+ setresuid.2 getresuid.2 \
+ setresuid.2 setresgid.2
+MLINKS+=setuid.2 setegid.2 \
+ setuid.2 seteuid.2 \
+ setuid.2 setgid.2
+MLINKS+=shmat.2 shmdt.2
+MLINKS+=shm_open.2 shm_unlink.2
+MLINKS+=sigwaitinfo.2 sigtimedwait.2
+MLINKS+=stat.2 fstat.2 \
+ stat.2 fstatat.2 \
+ stat.2 lstat.2
+MLINKS+=statfs.2 fstatfs.2
+MLINKS+=swapon.2 swapoff.2
+MLINKS+=symlink.2 symlinkat.2
+MLINKS+=syscall.2 __syscall.2
+MLINKS+=timer_settime.2 timer_getoverrun.2 \
+ timer_settime.2 timer_gettime.2
+MLINKS+=thr_kill.2 thr_kill2.2
+MLINKS+=truncate.2 ftruncate.2
+MLINKS+=unlink.2 unlinkat.2
+MLINKS+=utimensat.2 futimens.2
+MLINKS+=utimes.2 futimes.2 \
+ utimes.2 futimesat.2 \
+ utimes.2 lutimes.2
+MLINKS+=wait.2 wait3.2 \
+ wait.2 wait4.2 \
+ wait.2 waitpid.2 \
+ wait.2 waitid.2 \
+ wait.2 wait6.2
+MLINKS+=write.2 pwrite.2 \
+ write.2 pwritev.2 \
+ write.2 writev.2
diff --git a/lib/libc/sys/Symbol.map b/lib/libc/sys/Symbol.map
new file mode 100644
index 000000000000..489635ec0fa4
--- /dev/null
+++ b/lib/libc/sys/Symbol.map
@@ -0,0 +1,1047 @@
+/*
+ * $FreeBSD$
+ */
+
+/*
+ * It'd be nice to automatically generate the syscall symbols, but we
+ * don't know to what version they will eventually belong to, so for now
+ * it has to be manual.
+ */
+FBSD_1.0 {
+ __acl_aclcheck_fd;
+ __acl_aclcheck_file;
+ __acl_aclcheck_link;
+ __acl_delete_fd;
+ __acl_delete_file;
+ __acl_delete_link;
+ __acl_get_fd;
+ __acl_get_file;
+ __acl_get_link;
+ __acl_set_fd;
+ __acl_set_file;
+ __acl_set_link;
+ __getcwd;
+ __mac_execve;
+ __mac_get_fd;
+ __mac_get_file;
+ __mac_get_link;
+ __mac_get_pid;
+ __mac_get_proc;
+ __mac_set_fd;
+ __mac_set_file;
+ __mac_set_link;
+ __mac_set_proc;
+ __setugid;
+ __syscall;
+ __sysctl;
+ _umtx_op;
+ abort2;
+ accept;
+ access;
+ acct;
+ adjtime;
+ aio_cancel;
+ aio_error;
+ aio_fsync;
+ aio_read;
+ aio_return;
+ aio_suspend;
+ aio_waitcomplete;
+ aio_write;
+ audit;
+ auditctl;
+ auditon;
+ bind;
+ chdir;
+ chflags;
+ chmod;
+ chown;
+ chroot;
+ clock_getres;
+ clock_gettime;
+ clock_settime;
+ close;
+ connect;
+ dup;
+ dup2;
+ eaccess;
+ execve;
+ extattr_delete_fd;
+ extattr_delete_file;
+ extattr_delete_link;
+ extattr_get_fd;
+ extattr_get_file;
+ extattr_get_link;
+ extattr_list_fd;
+ extattr_list_file;
+ extattr_list_link;
+ extattr_set_fd;
+ extattr_set_file;
+ extattr_set_link;
+ extattrctl;
+ fchdir;
+ fchflags;
+ fchmod;
+ fchown;
+ fcntl;
+ fhopen;
+ fhstat;
+ fhstatfs;
+ flock;
+ fork;
+ fpathconf;
+ fstat;
+ fstatfs;
+ fsync;
+ futimes;
+ getaudit;
+ getaudit_addr;
+ getauid;
+ getcontext;
+ getdents;
+ getdirentries;
+ getdtablesize;
+ getegid;
+ geteuid;
+ getfh;
+ getfsstat;
+ getgid;
+ getgroups;
+ getitimer;
+ getpeername;
+ getpgid;
+ getpgrp;
+ getpid;
+ getppid;
+ getpriority;
+ getresgid;
+ getresuid;
+ getrlimit;
+ getrusage;
+ getsid;
+ getsockname;
+ getsockopt;
+ gettimeofday;
+ getuid;
+ ioctl;
+ issetugid;
+ jail;
+ jail_attach;
+ kenv;
+ kevent;
+ kill;
+ kldfind;
+ kldfirstmod;
+ kldload;
+ kldnext;
+ kldstat;
+ kldsym;
+ kldunload;
+ kldunloadf;
+ kqueue;
+ kmq_notify; /* Do we want these to be public interfaces? */
+ kmq_open; /* librt uses them to provide mq_xxx. */
+ kmq_setattr;
+ kmq_timedreceive;
+ kmq_timedsend;
+ kmq_unlink;
+ ksem_close;
+ ksem_destroy;
+ ksem_getvalue;
+ ksem_init;
+ ksem_open;
+ ksem_post;
+ ksem_timedwait;
+ ksem_trywait;
+ ksem_unlink;
+ ksem_wait;
+ ktrace;
+ lchflags;
+ lchmod;
+ lchown;
+ lgetfh;
+ link;
+ lio_listio;
+ listen;
+ lstat;
+ lutimes;
+ mac_syscall;
+ madvise;
+ mincore;
+ minherit;
+ mkdir;
+ mkfifo;
+ mknod;
+ mlock;
+ mlockall;
+ modfind;
+ modfnext;
+ modnext;
+ modstat;
+ mount;
+ mprotect;
+ msgget;
+ msgrcv;
+ msgsnd;
+ msgsys;
+ msync;
+ munlock;
+ munlockall;
+ munmap;
+ nanosleep;
+ netbsd_lchown;
+ netbsd_msync;
+ nfssvc;
+ nfstat;
+ nlstat;
+ nmount;
+ nstat;
+ ntp_adjtime;
+ ntp_gettime;
+ open;
+ pathconf;
+ pipe;
+ poll;
+ posix_openpt;
+ preadv;
+ profil;
+ pselect;
+ ptrace;
+ pwritev;
+ quotactl;
+ read;
+ readlink;
+ readv;
+ reboot;
+ recvfrom;
+ recvmsg;
+ rename;
+ revoke;
+ rfork;
+ rmdir;
+ rtprio;
+ rtprio_thread;
+ sched_get_priority_max;
+ sched_get_priority_min;
+ sched_getparam;
+ sched_getscheduler;
+ sched_rr_get_interval;
+ sched_setparam;
+ sched_setscheduler;
+ sched_yield;
+ select;
+ semget;
+ semop;
+ semsys;
+ sendfile;
+ sendmsg;
+ sendto;
+ setaudit;
+ setaudit_addr;
+ setauid;
+ setegid;
+ seteuid;
+ setgid;
+ setgroups;
+ setitimer;
+ setlogin;
+ setpgid;
+ setpriority;
+ setregid;
+ setresgid;
+ setresuid;
+ setreuid;
+ setrlimit;
+ setsid;
+ setsockopt;
+ settimeofday;
+ setuid;
+ shm_open;
+ shm_unlink;
+ shmat;
+ shmdt;
+ shmget;
+ shmsys;
+ shutdown;
+ sigaction;
+ sigaltstack;
+ sigpending;
+ sigprocmask;
+ sigqueue;
+ sigreturn;
+ sigsuspend;
+ sigtimedwait;
+ sigwait;
+ sigwaitinfo;
+ socket;
+ socketpair;
+ stat;
+ statfs;
+ swapoff;
+ swapon;
+ symlink;
+ sync;
+ sysarch;
+ syscall;
+ thr_create;
+ thr_exit;
+ thr_kill;
+ thr_kill2;
+ thr_new;
+ thr_self;
+ thr_set_name;
+ thr_suspend;
+ thr_wake;
+ ktimer_create; /* Do we want these to be public interfaces? */
+ ktimer_delete; /* librt uses them to provide timer_xxx. */
+ ktimer_getoverrun;
+ ktimer_gettime;
+ ktimer_settime;
+ umask;
+ undelete;
+ unlink;
+ unmount;
+ utimes;
+ utrace;
+ uuidgen;
+ vadvise;
+ wait4;
+ write;
+ writev;
+
+ __error;
+ ftruncate;
+ lseek;
+ mmap;
+ pread;
+ pwrite;
+ truncate;
+};
+
+FBSD_1.1 {
+ __semctl;
+ closefrom;
+ cpuset;
+ cpuset_getid;
+ cpuset_setid;
+ cpuset_getaffinity;
+ cpuset_setaffinity;
+ faccessat;
+ fchmodat;
+ fchownat;
+ fexecve;
+ fstatat;
+ futimesat;
+ jail_get;
+ jail_set;
+ jail_remove;
+ linkat;
+ lpathconf;
+ mkdirat;
+ mkfifoat;
+ mknodat;
+ msgctl;
+ readlinkat;
+ renameat;
+ setfib;
+ shmctl;
+ symlinkat;
+ unlinkat;
+};
+
+FBSD_1.2 {
+ cap_enter;
+ cap_getmode;
+ getloginclass;
+ pdfork;
+ pdgetpid;
+ pdkill;
+ posix_fallocate;
+ rctl_get_racct;
+ rctl_get_rules;
+ rctl_get_limits;
+ rctl_add_rule;
+ rctl_remove_rule;
+ setloginclass;
+};
+
+FBSD_1.3 {
+ accept4;
+ aio_mlock;
+ bindat;
+ cap_fcntls_get;
+ cap_fcntls_limit;
+ cap_ioctls_get;
+ cap_ioctls_limit;
+ __cap_rights_get;
+ cap_rights_limit;
+ cap_sandboxed;
+ chflagsat;
+ clock_getcpuclockid2;
+ connectat;
+ ffclock_getcounter;
+ ffclock_getestimate;
+ ffclock_setestimate;
+ pipe2;
+ posix_fadvise;
+ procctl;
+ wait6;
+};
+
+FBSD_1.4 {
+ futimens;
+ ppoll;
+ utimensat;
+ numa_setaffinity;
+ numa_getaffinity;
+ sendmmsg;
+ recvmmsg;
+};
+
+FBSD_1.5 {
+ fdatasync;
+};
+
+FBSDprivate_1.0 {
+ ___acl_aclcheck_fd;
+ __sys___acl_aclcheck_fd;
+ ___acl_aclcheck_file;
+ __sys___acl_aclcheck_file;
+ ___acl_aclcheck_link;
+ __sys___acl_aclcheck_link;
+ ___acl_delete_fd;
+ __sys___acl_delete_fd;
+ ___acl_delete_file;
+ __sys___acl_delete_file;
+ ___acl_delete_link;
+ __sys___acl_delete_link;
+ ___acl_get_fd;
+ __sys___acl_get_fd;
+ ___acl_get_file;
+ __sys___acl_get_file;
+ ___acl_get_link;
+ __sys___acl_get_link;
+ ___acl_set_fd;
+ __sys___acl_set_fd;
+ ___acl_set_file;
+ __sys___acl_set_file;
+ ___acl_set_link;
+ __sys___acl_set_link;
+ ___getcwd;
+ __sys___getcwd;
+ ___mac_execve;
+ __sys___mac_execve;
+ ___mac_get_fd;
+ __sys___mac_get_fd;
+ ___mac_get_file;
+ __sys___mac_get_file;
+ ___mac_get_link;
+ __sys___mac_get_link;
+ ___mac_get_pid;
+ __sys___mac_get_pid;
+ ___mac_get_proc;
+ __sys___mac_get_proc;
+ ___mac_set_fd;
+ __sys___mac_set_fd;
+ ___mac_set_file;
+ __sys___mac_set_file;
+ ___mac_set_link;
+ __sys___mac_set_link;
+ ___mac_set_proc;
+ __sys___mac_set_proc;
+ ___semctl;
+ __sys___semctl;
+ ___setugid;
+ __sys___setugid;
+ ___syscall;
+ __sys___syscall;
+ ___sysctl;
+ __sys___sysctl;
+ __umtx_op;
+ __sys__umtx_op;
+ _abort2;
+ __sys_abort2;
+ _accept;
+ __sys_accept;
+ _accept4;
+ __sys_accept4;
+ _access;
+ __sys_access;
+ _acct;
+ __sys_acct;
+ _adjtime;
+ __sys_adjtime;
+ _aio_cancel;
+ __sys_aio_cancel;
+ _aio_error;
+ __sys_aio_error;
+ _aio_fsync;
+ __sys_aio_fsync;
+ _aio_read;
+ __sys_aio_read;
+ _aio_return;
+ __sys_aio_return;
+ _aio_suspend;
+ __sys_aio_suspend;
+ _aio_waitcomplete;
+ __sys_aio_waitcomplete;
+ _aio_write;
+ __sys_aio_write;
+ _audit;
+ __sys_audit;
+ _auditctl;
+ __sys_auditctl;
+ _auditon;
+ __sys_auditon;
+ _bind;
+ __sys_bind;
+ _chdir;
+ __sys_chdir;
+ _chflags;
+ __sys_chflags;
+ _chmod;
+ __sys_chmod;
+ _chown;
+ __sys_chown;
+ _chroot;
+ __sys_chroot;
+ _clock_getcpuclockid2;
+ __sys_clock_getcpuclockid2;
+ _clock_getres;
+ __sys_clock_getres;
+ _clock_gettime;
+ __sys_clock_gettime;
+ _clock_settime;
+ __sys_clock_settime;
+ _close;
+ __sys_close;
+ _closefrom;
+ __sys_closefrom;
+ _connect;
+ __sys_connect;
+ _cpuset;
+ __sys_cpuset;
+ _cpuset_getid;
+ __sys_cpuset_getid;
+ _cpuset_setid;
+ __sys_cpuset_setid;
+ _cpuset_getaffinity;
+ __sys_cpuset_getaffinity;
+ _cpuset_setaffinity;
+ __sys_cpuset_setaffinity;
+ _dup;
+ __sys_dup;
+ _dup2;
+ __sys_dup2;
+ _eaccess;
+ __sys_eaccess;
+ _execve;
+ __sys_execve;
+ _extattr_delete_fd;
+ __sys_extattr_delete_fd;
+ _extattr_delete_file;
+ __sys_extattr_delete_file;
+ _extattr_delete_link;
+ __sys_extattr_delete_link;
+ _extattr_get_fd;
+ __sys_extattr_get_fd;
+ _extattr_get_file;
+ __sys_extattr_get_file;
+ _extattr_get_link;
+ __sys_extattr_get_link;
+ _extattr_list_fd;
+ __sys_extattr_list_fd;
+ _extattr_list_file;
+ __sys_extattr_list_file;
+ _extattr_list_link;
+ __sys_extattr_list_link;
+ _extattr_set_fd;
+ __sys_extattr_set_fd;
+ _extattr_set_file;
+ __sys_extattr_set_file;
+ _extattr_set_link;
+ __sys_extattr_set_link;
+ _extattrctl;
+ __sys_extattrctl;
+ _fchdir;
+ __sys_fchdir;
+ _fchflags;
+ __sys_fchflags;
+ _fchmod;
+ __sys_fchmod;
+ _fchown;
+ __sys_fchown;
+ _fcntl;
+ __sys_fcntl;
+ __fcntl_compat;
+ _fhopen;
+ __sys_fhopen;
+ _fhstat;
+ __sys_fhstat;
+ _fhstatfs;
+ __sys_fhstatfs;
+ _flock;
+ __sys_flock;
+ _fork;
+ __sys_fork;
+ _fpathconf;
+ __sys_fpathconf;
+ _fstat;
+ __sys_fstat;
+ _fstatfs;
+ __sys_fstatfs;
+ _fsync;
+ __sys_fsync;
+ _fdatasync;
+ __sys_fdatasync;
+ _futimes;
+ __sys_futimes;
+ _getaudit;
+ __sys_getaudit;
+ _getaudit_addr;
+ __sys_getaudit_addr;
+ _getauid;
+ __sys_getauid;
+ _getcontext;
+ __sys_getcontext;
+ _getdents;
+ __sys_getdents;
+ _getdirentries;
+ __sys_getdirentries;
+ _getdtablesize;
+ __sys_getdtablesize;
+ _getegid;
+ __sys_getegid;
+ _geteuid;
+ __sys_geteuid;
+ _getfh;
+ __sys_getfh;
+ _getfsstat;
+ __sys_getfsstat;
+ _getgid;
+ __sys_getgid;
+ _getgroups;
+ __sys_getgroups;
+ _getitimer;
+ __sys_getitimer;
+ _getpeername;
+ __sys_getpeername;
+ _getpgid;
+ __sys_getpgid;
+ _getpgrp;
+ __sys_getpgrp;
+ _getpid;
+ __sys_getpid;
+ _getppid;
+ __sys_getppid;
+ _getpriority;
+ __sys_getpriority;
+ _getresgid;
+ __sys_getresgid;
+ _getresuid;
+ __sys_getresuid;
+ _getrlimit;
+ __sys_getrlimit;
+ _getrusage;
+ __sys_getrusage;
+ _getsid;
+ __sys_getsid;
+ _getsockname;
+ __sys_getsockname;
+ _getsockopt;
+ __sys_getsockopt;
+ _gettimeofday;
+ __sys_gettimeofday;
+ _getuid;
+ __sys_getuid;
+ _ioctl;
+ __sys_ioctl;
+ _issetugid;
+ __sys_issetugid;
+ _jail;
+ __sys_jail;
+ _jail_attach;
+ __sys_jail_attach;
+ _kenv;
+ __sys_kenv;
+ _kevent;
+ __sys_kevent;
+ _kill;
+ __sys_kill;
+ _kldfind;
+ __sys_kldfind;
+ _kldfirstmod;
+ __sys_kldfirstmod;
+ _kldload;
+ __sys_kldload;
+ _kldnext;
+ __sys_kldnext;
+ _kldstat;
+ __sys_kldstat;
+ _kldsym;
+ __sys_kldsym;
+ _kldunload;
+ __sys_kldunload;
+ _kldunloadf;
+ __sys_kldunloadf;
+ _kmq_notify;
+ __sys_kmq_notify;
+ _kmq_open;
+ __sys_kmq_open;
+ _kmq_setattr;
+ __sys_kmq_setattr;
+ _kmq_timedreceive;
+ __sys_kmq_timedreceive;
+ _kmq_timedsend;
+ __sys_kmq_timedsend;
+ _kmq_unlink;
+ __sys_kmq_unlink;
+ _kqueue;
+ __sys_kqueue;
+ _ksem_close;
+ __sys_ksem_close;
+ _ksem_destroy;
+ __sys_ksem_destroy;
+ _ksem_getvalue;
+ __sys_ksem_getvalue;
+ _ksem_init;
+ __sys_ksem_init;
+ _ksem_open;
+ __sys_ksem_open;
+ _ksem_post;
+ __sys_ksem_post;
+ _ksem_timedwait;
+ __sys_ksem_timedwait;
+ _ksem_trywait;
+ __sys_ksem_trywait;
+ _ksem_unlink;
+ __sys_ksem_unlink;
+ _ksem_wait;
+ __sys_ksem_wait;
+ _ktrace;
+ __sys_ktrace;
+ _lchflags;
+ __sys_lchflags;
+ _lchmod;
+ __sys_lchmod;
+ _lchown;
+ __sys_lchown;
+ _lgetfh;
+ __sys_lgetfh;
+ _link;
+ __sys_link;
+ _lio_listio;
+ __sys_lio_listio;
+ _listen;
+ __sys_listen;
+ _lstat;
+ __sys_lstat;
+ _lutimes;
+ __sys_lutimes;
+ _mac_syscall;
+ __sys_mac_syscall;
+ _madvise;
+ __sys_madvise;
+ _mincore;
+ __sys_mincore;
+ _minherit;
+ __sys_minherit;
+ _mkdir;
+ __sys_mkdir;
+ _mkfifo;
+ __sys_mkfifo;
+ _mknod;
+ __sys_mknod;
+ _mlock;
+ __sys_mlock;
+ _mlockall;
+ __sys_mlockall;
+ _modfind;
+ __sys_modfind;
+ _modfnext;
+ __sys_modfnext;
+ _modnext;
+ __sys_modnext;
+ _modstat;
+ __sys_modstat;
+ _mount;
+ __sys_mount;
+ _mprotect;
+ __sys_mprotect;
+ _msgctl;
+ __sys_msgctl;
+ _msgget;
+ __sys_msgget;
+ _msgrcv;
+ __sys_msgrcv;
+ _msgsnd;
+ __sys_msgsnd;
+ _msgsys;
+ __sys_msgsys;
+ _msync;
+ __sys_msync;
+ _munlock;
+ __sys_munlock;
+ _munlockall;
+ __sys_munlockall;
+ _munmap;
+ __sys_munmap;
+ _nanosleep;
+ __sys_nanosleep;
+ _netbsd_lchown;
+ __sys_netbsd_lchown;
+ _netbsd_msync;
+ __sys_netbsd_msync;
+ _nfssvc;
+ __sys_nfssvc;
+ _nfstat;
+ __sys_nfstat;
+ _nlstat;
+ __sys_nlstat;
+ _nmount;
+ __sys_nmount;
+ _nstat;
+ __sys_nstat;
+ _ntp_adjtime;
+ __sys_ntp_adjtime;
+ _ntp_gettime;
+ __sys_ntp_gettime;
+ _open;
+ __sys_open;
+ _openat;
+ __sys_openat;
+ _pathconf;
+ __sys_pathconf;
+ _pipe;
+ __sys_pipe;
+ _poll;
+ __sys_poll;
+ _ppoll;
+ __sys_ppoll;
+ _preadv;
+ __sys_preadv;
+ _procctl;
+ __sys_procctl;
+ _profil;
+ __sys_profil;
+ _pselect;
+ __sys_pselect;
+ _ptrace;
+ __sys_ptrace;
+ _pwritev;
+ __sys_pwritev;
+ _quotactl;
+ __sys_quotactl;
+ _read;
+ __sys_read;
+ _readlink;
+ __sys_readlink;
+ _readv;
+ __sys_readv;
+ _reboot;
+ __sys_reboot;
+ _recvfrom;
+ __sys_recvfrom;
+ _recvmsg;
+ __sys_recvmsg;
+ _rename;
+ __sys_rename;
+ _revoke;
+ __sys_revoke;
+ _rfork;
+ __sys_rfork;
+ _rmdir;
+ __sys_rmdir;
+ _rtprio;
+ __sys_rtprio;
+ _rtprio_thread;
+ __sys_rtprio_thread;
+ _sched_get_priority_max;
+ __sys_sched_get_priority_max;
+ _sched_get_priority_min;
+ __sys_sched_get_priority_min;
+ _sched_getparam;
+ __sys_sched_getparam;
+ _sched_getscheduler;
+ __sys_sched_getscheduler;
+ _sched_rr_get_interval;
+ __sys_sched_rr_get_interval;
+ _sched_setparam;
+ __sys_sched_setparam;
+ _sched_setscheduler;
+ __sys_sched_setscheduler;
+ _sched_yield;
+ __sys_sched_yield;
+ _select;
+ __sys_select;
+ _semget;
+ __sys_semget;
+ _semop;
+ __sys_semop;
+ _semsys;
+ __sys_semsys;
+ _sendfile;
+ __sys_sendfile;
+ _sendmsg;
+ __sys_sendmsg;
+ _sendto;
+ __sys_sendto;
+ _setaudit;
+ __sys_setaudit;
+ _setaudit_addr;
+ __sys_setaudit_addr;
+ _setauid;
+ __sys_setauid;
+ _setcontext;
+ __sys_setcontext;
+ _setegid;
+ __sys_setegid;
+ _seteuid;
+ __sys_seteuid;
+ _setgid;
+ __sys_setgid;
+ _setgroups;
+ __sys_setgroups;
+ _setitimer;
+ __sys_setitimer;
+ _setlogin;
+ __sys_setlogin;
+ _setpgid;
+ __sys_setpgid;
+ _setpriority;
+ __sys_setpriority;
+ _setregid;
+ __sys_setregid;
+ _setresgid;
+ __sys_setresgid;
+ _setresuid;
+ __sys_setresuid;
+ _setreuid;
+ __sys_setreuid;
+ _setrlimit;
+ __sys_setrlimit;
+ _setsid;
+ __sys_setsid;
+ _setsockopt;
+ __sys_setsockopt;
+ _settimeofday;
+ __sys_settimeofday;
+ _setuid;
+ __sys_setuid;
+ _shm_open;
+ __sys_shm_open;
+ _shm_unlink;
+ __sys_shm_unlink;
+ _shmat;
+ __sys_shmat;
+ _shmctl;
+ __sys_shmctl;
+ _shmdt;
+ __sys_shmdt;
+ _shmget;
+ __sys_shmget;
+ _shmsys;
+ __sys_shmsys;
+ _shutdown;
+ __sys_shutdown;
+ _sigaction;
+ __sys_sigaction;
+ _sigaltstack;
+ __sys_sigaltstack;
+ _sigpending;
+ __sys_sigpending;
+ _sigprocmask;
+ __sys_sigprocmask;
+ _sigqueue;
+ __sys_sigqueue;
+ _sigreturn;
+ __sys_sigreturn;
+ _sigsuspend;
+ __sys_sigsuspend;
+ _sigtimedwait;
+ __sys_sigtimedwait;
+ _sigwait;
+ __sigwait;
+ __sys_sigwait;
+ _sigwaitinfo;
+ __sys_sigwaitinfo;
+ _socket;
+ __sys_socket;
+ _socketpair;
+ __sys_socketpair;
+ _stat;
+ __sys_stat;
+ _statfs;
+ __sys_statfs;
+ _swapcontext;
+ __sys_swapcontext;
+ _swapoff;
+ __sys_swapoff;
+ _swapon;
+ __sys_swapon;
+ _symlink;
+ __sys_symlink;
+ _sync;
+ __sys_sync;
+ _sysarch;
+ __sys_sysarch;
+ _syscall;
+ __sys_syscall;
+ _thr_create;
+ __sys_thr_create;
+ _thr_exit;
+ __sys_thr_exit;
+ _thr_kill;
+ __sys_thr_kill;
+ _thr_kill2;
+ __sys_thr_kill2;
+ _thr_new;
+ __sys_thr_new;
+ _thr_self;
+ __sys_thr_self;
+ _thr_set_name;
+ __sys_thr_set_name;
+ _thr_suspend;
+ __sys_thr_suspend;
+ _thr_wake;
+ __sys_thr_wake;
+ _ktimer_create;
+ __sys_ktimer_create;
+ _ktimer_delete;
+ __sys_ktimer_delete;
+ _ktimer_getoverrun;
+ __sys_ktimer_getoverrun;
+ _ktimer_gettime;
+ __sys_ktimer_gettime;
+ _ktimer_settime;
+ __sys_ktimer_settime;
+ _umask;
+ __sys_umask;
+ _undelete;
+ __sys_undelete;
+ _unlink;
+ __sys_unlink;
+ _unmount;
+ __sys_unmount;
+ _utimes;
+ __sys_utimes;
+ _utrace;
+ __sys_utrace;
+ _uuidgen;
+ __sys_uuidgen;
+ _vadvise;
+ __sys_vadvise;
+ _wait4;
+ __sys_wait4;
+ _wait6;
+ __sys_wait6;
+ _write;
+ __sys_write;
+ _writev;
+ __sys_writev;
+ __set_error_selector;
+ nlm_syscall;
+ gssd_syscall;
+ __libc_interposing_slot;
+ __libc_sigwait;
+};
diff --git a/lib/libc/sys/__error.c b/lib/libc/sys/__error.c
new file mode 100644
index 000000000000..8a065bf72002
--- /dev/null
+++ b/lib/libc/sys/__error.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 1997 John Birrell <jb@cimlogic.com.au>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "libc_private.h"
+
+extern int errno;
+
+static int *
+__error_unthreaded(void)
+{
+
+ return (&errno);
+}
+
+static int *(*__error_selector)(void) = __error_unthreaded;
+
+void
+__set_error_selector(int *(*arg)(void))
+{
+
+ __error_selector = arg;
+}
+
+int *
+__error(void)
+{
+
+ return (__error_selector());
+}
diff --git a/lib/libc/sys/__vdso_gettimeofday.c b/lib/libc/sys/__vdso_gettimeofday.c
new file mode 100644
index 000000000000..0368b9787efc
--- /dev/null
+++ b/lib/libc/sys/__vdso_gettimeofday.c
@@ -0,0 +1,156 @@
+/*-
+ * Copyright (c) 2012 Konstantin Belousov <kib@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/elf.h>
+#include <sys/time.h>
+#include <sys/vdso.h>
+#include <errno.h>
+#include <time.h>
+#include <machine/atomic.h>
+#include "libc_private.h"
+
+static int
+tc_delta(const struct vdso_timehands *th, u_int *delta)
+{
+ int error;
+ u_int tc;
+
+ error = __vdso_gettc(th, &tc);
+ if (error == 0)
+ *delta = (tc - th->th_offset_count) & th->th_counter_mask;
+ return (error);
+}
+
+/*
+ * Calculate the absolute or boot-relative time from the
+ * machine-specific fast timecounter and the published timehands
+ * structure read from the shared page.
+ *
+ * The lockless reading scheme is similar to the one used to read the
+ * in-kernel timehands, see sys/kern/kern_tc.c:binuptime(). This code
+ * is based on the kernel implementation.
+ */
+static int
+binuptime(struct bintime *bt, struct vdso_timekeep *tk, int abs)
+{
+ struct vdso_timehands *th;
+ uint32_t curr, gen;
+ u_int delta;
+ int error;
+
+ do {
+ if (!tk->tk_enabled)
+ return (ENOSYS);
+
+ curr = atomic_load_acq_32(&tk->tk_current);
+ th = &tk->tk_th[curr];
+ gen = atomic_load_acq_32(&th->th_gen);
+ *bt = th->th_offset;
+ error = tc_delta(th, &delta);
+ if (error == EAGAIN)
+ continue;
+ if (error != 0)
+ return (error);
+ bintime_addx(bt, th->th_scale * delta);
+ if (abs)
+ bintime_add(bt, &th->th_boottime);
+
+ /*
+ * Ensure that the load of th_offset is completed
+ * before the load of th_gen.
+ */
+ atomic_thread_fence_acq();
+ } while (curr != tk->tk_current || gen == 0 || gen != th->th_gen);
+ return (0);
+}
+
+static struct vdso_timekeep *tk;
+
+#pragma weak __vdso_gettimeofday
+int
+__vdso_gettimeofday(struct timeval *tv, struct timezone *tz)
+{
+ struct bintime bt;
+ int error;
+
+ if (tz != NULL)
+ return (ENOSYS);
+ if (tk == NULL) {
+ error = __vdso_gettimekeep(&tk);
+ if (error != 0 || tk == NULL)
+ return (ENOSYS);
+ }
+ if (tk->tk_ver != VDSO_TK_VER_CURR)
+ return (ENOSYS);
+ error = binuptime(&bt, tk, 1);
+ if (error != 0)
+ return (error);
+ bintime2timeval(&bt, tv);
+ return (0);
+}
+
+#pragma weak __vdso_clock_gettime
+int
+__vdso_clock_gettime(clockid_t clock_id, struct timespec *ts)
+{
+ struct bintime bt;
+ int abs, error;
+
+ if (tk == NULL) {
+ error = _elf_aux_info(AT_TIMEKEEP, &tk, sizeof(tk));
+ if (error != 0 || tk == NULL)
+ return (ENOSYS);
+ }
+ if (tk->tk_ver != VDSO_TK_VER_CURR)
+ return (ENOSYS);
+ switch (clock_id) {
+ case CLOCK_REALTIME:
+ case CLOCK_REALTIME_PRECISE:
+ case CLOCK_REALTIME_FAST:
+ case CLOCK_SECOND:
+ abs = 1;
+ break;
+ case CLOCK_MONOTONIC:
+ case CLOCK_MONOTONIC_PRECISE:
+ case CLOCK_MONOTONIC_FAST:
+ case CLOCK_UPTIME:
+ case CLOCK_UPTIME_PRECISE:
+ case CLOCK_UPTIME_FAST:
+ abs = 0;
+ break;
+ default:
+ return (ENOSYS);
+ }
+ error = binuptime(&bt, tk, abs);
+ if (error != 0)
+ return (error);
+ bintime2timespec(&bt, ts);
+ if (clock_id == CLOCK_SECOND)
+ ts->tv_nsec = 0;
+ return (0);
+}
diff --git a/lib/libc/sys/_exit.2 b/lib/libc/sys/_exit.2
new file mode 100644
index 000000000000..120ef1c9e4ef
--- /dev/null
+++ b/lib/libc/sys/_exit.2
@@ -0,0 +1,125 @@
+.\" Copyright (c) 1980, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)_exit.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd September 8, 2016
+.Dt EXIT 2
+.Os
+.Sh NAME
+.Nm _exit
+.Nd terminate the calling process
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft void
+.Fn _exit "int status"
+.Sh DESCRIPTION
+The
+.Fn _exit
+system call
+terminates a process with the following consequences:
+.Bl -bullet
+.It
+All of the descriptors open in the calling process are closed.
+This may entail delays, for example, waiting for output to drain;
+a process in this state may not be killed, as it is already dying.
+.It
+If the parent process of the calling process has an outstanding
+.Xr wait 2
+call
+or catches the
+.Dv SIGCHLD
+signal,
+it is notified of the calling process's termination and
+the
+.Fa status
+is set as defined by
+.Xr wait 2 .
+.It
+The parent process-ID of all of the calling process's existing child
+processes are set to the process-ID of the calling process's reaper;
+the reaper (normally the initialization process)
+inherits each of these processes
+(see
+.Xr procctl 2 ,
+.Xr init 8
+and the
+.Sx DEFINITIONS
+section of
+.Xr intro 2 ) .
+.It
+If the termination of the process causes any process group
+to become orphaned (usually because the parents of all members
+of the group have now exited; see
+.Dq orphaned process group
+in
+.Xr intro 2 ) ,
+and if any member of the orphaned group is stopped,
+the
+.Dv SIGHUP
+signal and the
+.Dv SIGCONT
+signal are sent to all members of the newly-orphaned process group.
+.It
+If the process is a controlling process (see
+.Xr intro 2 ) ,
+the
+.Dv SIGHUP
+signal is sent to the foreground process group of the controlling terminal,
+and all current access to the controlling terminal is revoked.
+.El
+.Pp
+Most C programs call the library routine
+.Xr exit 3 ,
+which flushes buffers, closes streams, unlinks temporary files, etc.,
+before
+calling
+.Fn _exit .
+.Sh RETURN VALUES
+The
+.Fn _exit
+system call
+can never return.
+.Sh SEE ALSO
+.Xr fork 2 ,
+.Xr sigaction 2 ,
+.Xr wait 2 ,
+.Xr exit 3 ,
+.Xr init 8
+.Sh STANDARDS
+The
+.Fn _exit
+system call is expected to conform to
+.St -p1003.1-90 .
+.Sh HISTORY
+The
+.Fn _exit
+function appeared in
+.At v7 .
diff --git a/lib/libc/sys/_umtx_op.2 b/lib/libc/sys/_umtx_op.2
new file mode 100644
index 000000000000..63509991ad24
--- /dev/null
+++ b/lib/libc/sys/_umtx_op.2
@@ -0,0 +1,1427 @@
+.\" Copyright (c) 2016 The FreeBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" 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:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd May 29, 2016
+.Dt _UMTX_OP 2
+.Os
+.Sh NAME
+.Nm _umtx_op
+.Nd interface for implementation of userspace threading synchronization primitives
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/umtx.h
+.Ft int
+.Fn _umtx_op "void *obj" "int op" "u_long val" "void *uaddr" "void *uaddr2"
+.Sh DESCRIPTION
+The
+.Fn _umtx_op
+system call provides kernel support for userspace implementation of
+the threading synchronization primitives.
+The
+.Lb libthr
+uses the syscall to implement
+.St -p1003.1-2001
+pthread locks, like mutexes, condition variables and so on.
+.Ss STRUCTURES
+The operations, performed by the
+.Fn _umtx_op
+syscall, operate on userspace objects which are described
+by the following structures.
+Reserved fields and paddings are omitted.
+All objects require ABI-mandated alignment, but this is not currently
+enforced consistently on all architectures.
+.Pp
+The following flags are defined for flag fields of all structures:
+.Bl -tag -width "Dv USYNC_PROCESS_SHARED"
+.It Dv USYNC_PROCESS_SHARED
+Allow selection of the process-shared sleep queue for the thread sleep
+container, when the lock ownership cannot be granted immediately,
+and the operation must sleep.
+The process-shared or process-private sleep queue is selected based on
+the attributes of the memory mapping which contains the first byte of
+the structure, see
+.Xr mmap 2 .
+Otherwise, if the flag is not specified, the process-private sleep queue
+is selected regardless of the memory mapping attributes, as an optimization.
+.Pp
+See the
+.Sx SLEEP QUEUES
+subsection below for more details on sleep queues.
+.El
+.Pp
+.Bl -hang -offset indent
+.It Sy Mutex
+.Bd -literal
+struct umutex {
+ volatile lwpid_t m_owner;
+ uint32_t m_flags;
+ uint32_t m_ceilings[2];
+ uintptr_t m_rb_lnk;
+};
+.Ed
+.Pp
+The
+.Dv m_owner
+field is the actual lock.
+It contains either the thread identifier of the lock owner in the
+locked state, or zero when the lock is unowned.
+The highest bit set indicates that there is contention on the lock.
+The constants are defined for special values:
+.Bl -tag -width "Dv UMUTEX_RB_OWNERDEAD"
+.It Dv UMUTEX_UNOWNED
+Zero, the value stored in the unowned lock.
+.It Dv UMUTEX_CONTESTED
+The contenion indicator.
+.It Dv UMUTEX_RB_OWNERDEAD
+A thread owning the robust mutex terminated.
+The mutex is in unlocked state.
+.It Dv UMUTEX_RB_NOTRECOV
+The robust mutex is in a non-recoverable state.
+It cannot be locked until reinitialized.
+.El
+.Pp
+The
+.Dv m_flags
+field may contain the following umutex-specific flags, in addition to
+the common flags:
+.Bl -tag -width "Dv UMUTEX_NONCONSISTENT"
+.It Dv UMUTEX_PRIO_INHERIT
+Mutex implements
+.Em Priority Inheritance
+protocol.
+.It Dv UMUTEX_PRIO_PROTECT
+Mutex implements
+.Em Priority Protection
+protocol.
+.It Dv UMUTEX_ROBUST
+Mutex is robust, as described in the
+.Sx ROBUST UMUTEXES
+section below.
+.It Dv UMUTEX_NONCONSISTENT
+Robust mutex is in a transient non-consistent state.
+Not used by kernel.
+.El
+.Pp
+In the manual page, mutexes not having
+.Dv UMUTEX_PRIO_INHERIT
+and
+.Dv UMUTEX_PRIO_PROTECT
+flags set, are called normal mutexes.
+Each type of mutex, i.e. normal mutexes, priority-inherited mutexes,
+and priority-protected mutexes, have a separate sleep queue associated
+with the given key.
+.Pp
+For priority protected mutexes, the
+.Dv m_ceilings
+array contains priority ceiling values.
+The
+.Dv m_ceilings[0]
+is the ceiling value for the mutex, as specified by
+.St -p1003.1-2008
+for the
+.Em Priority Protected
+mutex protocol.
+The
+.Dv m_ceilings[1]
+is used only for the unlock of a priority protected mutex, when
+unlock is done in an order other than the reversed lock order.
+In this case,
+.Dv m_ceilings[1]
+must contain the ceiling value for the last locked priority protected
+mutex, for proper priority reassignment.
+If, instead, the unlocking mutex was the last priority propagated
+mutex locked by the thread,
+.Dv m_ceilings[1]
+should contain \-1.
+This is required because kernel does not maintain the ordered lock list.
+.It Sy Condition variable
+.Bd -literal
+struct ucond {
+ volatile uint32_t c_has_waiters;
+ uint32_t c_flags;
+ uint32_t c_clockid;
+};
+.Ed
+.Pp
+A non-zero
+.Dv c_has_waiters
+value indicates that there are in-kernel waiters for the condition,
+executing the
+.Dv UMTX_OP_CV_WAIT
+request.
+.Pp
+The
+.Dv c_flags
+field contains flags.
+Only the common flags, i.e.
+.Dv USYNC_PROCESS_SHARED ,
+are defined for ucond.
+.Pp
+The
+.Dv c_clockid
+member provides the clock identifier to use for timeout, when the
+.Dv UMTX_OP_CV_WAIT
+request has both the
+.Dv CVWAIT_CLOCKID
+flag and the timeout specified.
+Valid clock identifiers are subset of the valid clock ids for the
+.Xr clock_gettime 2
+syscall, namely,
+.Dv CLOCK_REALTIME ,
+.Dv CLOCK_VIRTUAL ,
+.Dv CLOCK_PROF ,
+.Dv CLOCK_MONOTONIC ,
+.Dv CLOCK_UPTIME ,
+.Dv CLOCK_UPTIME_PRECISE ,
+.Dv CLOCK_UPTIME_FAST ,
+.Dv CLOCK_REALTIME_PRECISE ,
+.Dv CLOCK_REALTIME_FAST ,
+.Dv CLOCK_MONOTONIC_PRECISE ,
+.Dv CLOCK_MONOTONIC_FAST ,
+and
+.Dv CLOCK_SECOND
+are allowed.
+.It Sy Reader/writer lock
+.Bd -literal
+struct urwlock {
+ volatile int32_t rw_state;
+ uint32_t rw_flags;
+ uint32_t rw_blocked_readers;
+ uint32_t rw_blocked_writers;
+};
+.Ed
+.Pp
+The
+.Dv rw_state
+field is the actual lock.
+It contains both the flags and counter of the read locks which were
+granted.
+Names of the
+.Dv rw_state
+bits are following:
+.Bl -tag -width "Dv URWLOCK_WRITE_WAITERS"
+.It Dv URWLOCK_WRITE_OWNER
+Write lock was granted.
+.It Dv URWLOCK_WRITE_WAITERS
+There are write lock waiters.
+.It Dv URWLOCK_READ_WAITERS
+There are read lock waiters.
+.It Dv URWLOCK_READER_COUNT(c)
+Returns the count of currently granted read locks.
+.El
+.Pp
+At any given time there may be only one thread to which the writer lock
+is granted on the
+.Vt struct rwlock ,
+and no threads are granted read lock.
+Or, at the given time, up to
+.Dv URWLOCK_MAX_READERS
+threads may be granted the read lock simultaneously, but write lock is
+not granted to any thread.
+.Pp
+The following flags for the
+.Dv rw_flags
+member of
+.Vt struct urwlock
+are defined, in addition to the common flags:
+.Bl -tag -width "Dv URWLOCK_PREFER_READER"
+.It Dv URWLOCK_PREFER_READER
+If specified, immediately grant read lock requests when
+.Dv urwlock
+is already read-locked, even in presence of unsatisfied write
+lock requests.
+By default, if there is a write lock waiter, further read requests are
+not granted, to prevent unfair write lock waiter starvation.
+.El
+.Pp
+The
+.Dv rw_blocked_readers
+and
+.Dv rw_blocked_writers
+members contain the count of threads which are sleeping in kernel,
+waiting for the associated request type to be granted.
+The fields are used by kernel to update the
+.Dv URWLOCK_READ_WAITERS
+and
+.Dv URWLOCK_WRITE_WAITERS
+flags of the
+.Dv rw_state
+lock after requesting thread was woken up.
+.It Sy Semaphore
+.Bd -literal
+struct _usem2 {
+ volatile uint32_t _count;
+ uint32_t _flags;
+};
+.Ed
+.Pp
+The
+.Dv _count
+word represents a counting semaphore.
+A non-zero value indicates an unlocked (posted) semaphore, while zero
+represents the locked state.
+The maximal supported semaphore count is
+.Dv USEM_MAX_COUNT .
+.Pp
+The
+.Dv _count
+word, besides the counter of posts (unlocks), also contains the
+.Dv USEM_HAS_WAITERS
+bit, which indicates that locked semaphore has waiting threads.
+.Pp
+The
+.Dv USEM_COUNT()
+macro, applied to the
+.Dv _count
+word, returns the current semaphore counter, i.e. the number of posts
+issued on the semaphore.
+.Pp
+The following bits for the
+.Dv _flags
+member of
+.Vt struct _usem2
+are defined, in addition to the common flags:
+.Bl -tag -width "Dv USEM_NAMED"
+.It Dv USEM_NAMED
+Flag is ignored by kernel.
+.El
+.It Sy Timeout parameter
+.Bd -literal
+struct _umtx_time {
+ struct timespec _timeout;
+ uint32_t _flags;
+ uint32_t _clockid;
+};
+.Ed
+.Pp
+Several
+.Fn _umtx_op
+operations allow the blocking time to be limited, failing the request
+if it cannot be satisfied in the specified time period.
+The timeout is specified by passing either the address of
+.Vt struct timespec ,
+or its extended variant,
+.Vt struct _umtx_time ,
+as the
+.Fa uaddr2
+argument of
+.Fn _umtx_op .
+They are distinguished by the
+.Fa uaddr
+value, which must be equal to the size of the structure pointed to by
+.Fa uaddr2 ,
+casted to
+.Vt uintptr_t .
+.Pp
+The
+.Dv _timeout
+member specifies the time when the timeout should occur.
+Legal values for clock identifier
+.Dv _clockid
+are shared with the
+.Fa clock_id
+argument to the
+.Xr clock_gettime 2
+function,
+and use the same underlying clocks.
+The specified clock is used to obtain the current time value.
+Interval counting is always performed by the monotonic wall clock.
+.Pp
+The
+.Dv _flags
+argument allows the following flags to further define the timeout behaviour:
+.Bl -tag -width "It Dv UMTX_ABSTIME"
+.It Dv UMTX_ABSTIME
+The
+.Dv _timeout
+value is the absolute time.
+The thread will be unblocked and the request failed when specified
+clock value is equal or exceeds the
+.Dv _timeout.
+.Pp
+If the flag is absent, the timeout value is relative, that is the amount
+of time, measured by the monotonic wall clock from the moment of the request
+start.
+.El
+.El
+.Ss SLEEP QUEUES
+.Pp
+When a locking request cannot be immediately satisfied, the thread is
+typically put to
+.Em sleep ,
+which is a non-runnable state terminated by the
+.Em wake
+operation.
+Lock operations include a
+.Em try
+variant which returns an error rather than sleeping if the lock cannot
+be obtained.
+Also,
+.Fn _umtx_op
+provides requests which explicitly put the thread to sleep.
+.Pp
+Wakes need to know which threads to make runnable, so sleeping threads
+are grouped into containers called
+.Em sleep queues .
+A sleep queue is identified by a key, which for
+.Fn _umtx_op
+is defined as the physical address of some variable.
+Note that the
+.Em physical
+address is used, which means that same variable mapped multiple
+times will give one key value.
+This mechanism enables the construction of
+.Em process-shared
+locks.
+.Pp
+A related attribute of the key is shareability.
+Some requests always interpret keys as private for the current process,
+creating sleep queues with the scope of the current process even if
+the memory is shared.
+Others either select the shareability automatically from the
+mapping attributes, or take additional input as the
+.Dv USYNC_PROCESS_SHARED
+common flag.
+This is done as optimization, allowing the lock scope to be limited
+regardless of the kind of backing memory.
+.Pp
+Only the address of the start byte of the variable specified as key is
+important for determining corresponding sleep queue.
+The size of the variable does not matter, so e.g. sleep on the same
+address interpeted as
+.Vt uint32_t
+and
+.Vt long
+on a little-endian 64-bit platform would collide.
+.Pp
+The last attribute of the key is the object type.
+The sleep queue to which a sleeping thread is assigned is an individual
+one for simple wait requests, mutexes, rwlocks, condvars and other
+primitives, even when the physical address of the key is same.
+.Pp
+When waking up a limited number of threads from a given sleep queue,
+the highest priority threads that have been blocked for the longest on
+the queue are selected.
+.Ss ROBUST UMUTEXES
+The
+.Em robust umutexes
+are provided as a substrate for a userspace library to implement
+.Tn POSIX
+robust mutexes.
+A robust umutex must have the
+.Dv UMUTEX_ROBUST
+flag set.
+.Pp
+On thread termination, the kernel walks two lists of mutexes.
+The two lists head addresses must be provided by a prior call to
+.Dv UMTX_OP_ROBUST_LISTS
+request.
+The lists are singly-linked.
+The link to next element is provided by the
+.Dv m_rb_lnk
+member of the
+.Vt struct umutex .
+.Pp
+Robust list processing is aborted if the kernel finds a mutex
+with any of the following conditions:
+.Bl -dash -offset indent -compact
+.It
+the
+.Dv UMUTEX_ROBUST
+flag is not set
+.It
+not owned by the current thread, except when the mutex is pointed to
+by the
+.Dv robust_inactive
+member of the
+.Vt struct umtx_robust_lists_params ,
+registered for the current thread
+.It
+the combination of mutex flags is invalid
+.It
+read of the umutex memory faults
+.It
+the list length limit described in
+.Xr libthr 3
+is reached.
+.El
+.Pp
+Every mutex in both lists is unlocked as if the
+.Dv UMTX_OP_MUTEX_UNLOCK
+request is performed on it, but instead of the
+.Dv UMUTEX_UNOWNED
+value, the
+.Dv m_owner
+field is written with the
+.Dv UMUTEX_RB_OWNERDEAD
+value.
+When a mutex in the
+.Dv UMUTEX_RB_OWNERDEAD
+state is locked by kernel due to the
+.Dv UMTX_OP_MUTEX_TRYLOCK
+and
+.Dv UMTX_OP_MUTEX_LOCK
+requests, the lock is granted and
+.Er EOWNERDEAD
+error is returned.
+.Pp
+Also, the kernel handles the
+.Dv UMUTEX_RB_NOTRECOV
+value of
+.Dv the m_owner
+field specially, always returning the
+.Er ENOTRECOVERABLE
+error for lock attempts, without granting the lock.
+.Ss OPERATIONS
+The following operations, requested by the
+.Fa op
+argument to the function, are implemented:
+.Bl -tag -width "It Dv UMTX_OP_WAIT_UINT_PRIVATE"
+.It Dv UMTX_OP_WAIT
+Wait.
+The arguments for the request are:
+.Bl -tag -width "It Fa obj"
+.It Fa obj
+Pointer to a variable of type
+.Vt long .
+.It Fa val
+Current value of the
+.Dv *obj .
+.El
+.Pp
+The current value of the variable pointed to by the
+.Fa obj
+argument is compared with the
+.Fa val .
+If they are equal, the requesting thread is put to interruptible sleep
+until woken up or the optionally specified timeout expires.
+.Pp
+The comparison and sleep are atomic.
+In other words, if another thread writes a new value to
+.Dv *obj
+and then issues
+.Dv UMTX_OP_WAKE ,
+the request is guaranteed to not miss the wakeup,
+which might otherwise happen between comparison and blocking.
+.Pp
+The physical address of memory where the
+.Fa *obj
+variable is located, is used as a key to index sleeping threads.
+.Pp
+The read of the current value of the
+.Dv *obj
+variable is not guarded by barriers.
+In particular, it is the user's duty to ensure the lock acquire
+and release memory semantics, if the
+.Dv UMTX_OP_WAIT
+and
+.Dv UMTX_OP_WAKE
+requests are used as a substrate for implementing a simple lock.
+.Pp
+The request is not restartable.
+An unblocked signal delivered during the wait always results in sleep
+interruption and
+.Er EINTR
+error.
+.Pp
+Optionally, a timeout for the request may be specified.
+.It Dv UMTX_OP_WAKE
+Wake the threads possibly sleeping due to
+.Dv UMTX_OP_WAIT .
+The arguments for the request are:
+.Bl -tag -width "It Fa obj"
+.It Fa obj
+Pointer to a variable, used as a key to find sleeping threads.
+.It Fa val
+Up to
+.Fa val
+threads are woken up by this request.
+Specify
+.Dv INT_MAX
+to wake up all waiters.
+.El
+.It Dv UMTX_OP_MUTEX_TRYLOCK
+Try to lock umutex.
+The arguments to the request are:
+.Bl -tag -width "It Fa obj"
+.It Fa obj
+Pointer to the umutex.
+.El
+.Pp
+Operates same as the
+.Dv UMTX_OP_MUTEX_LOCK
+request, but returns
+.Er EBUSY
+instead of sleeping if the lock cannot be obtained immediately.
+.It Dv UMTX_OP_MUTEX_LOCK
+Lock umutex.
+The arguments to the request are:
+.Bl -tag -width "It Fa obj"
+.It Fa obj
+Pointer to the umutex.
+.El
+.Pp
+Locking is performed by writing the current thread id into the
+.Dv m_owner
+word of the
+.Vt struct umutex .
+The write is atomic, preserves the
+.Dv UMUTEX_CONTESTED
+contention indicator, and provides the acquire barrier for
+lock entrance semantic.
+.Pp
+If the lock cannot be obtained immediately because another thread owns
+the lock, the current thread is put to sleep, with
+.Dv UMUTEX_CONTESTED
+bit set before.
+Upon wake up, the lock conditions are re-tested.
+.Pp
+The request adheres to the priority protection or inheritance protocol
+of the mutex, specified by the
+.Dv UMUTEX_PRIO_PROTECT
+or
+.Dv UMUTEX_PRIO_INHERIT
+flag, respectively.
+.Pp
+Optionally, a timeout for the request may be specified.
+.Pp
+A request with a timeout specified is not restartable.
+An unblocked signal delivered during the wait always results in sleep
+interruption and
+.Er EINTR
+error.
+A request without timeout specified is always restarted after return
+from a signal handler.
+.It Dv UMTX_OP_MUTEX_UNLOCK
+Unlock umutex.
+The arguments to the request are:
+.Bl -tag -width "It Fa obj"
+.It Fa obj
+Pointer to the umutex.
+.El
+.Pp
+Unlocks the mutex, by writing
+.Dv UMUTEX_UNOWNED
+(zero) value into
+.Dv m_owner
+word of the
+.Vt struct umutex .
+The write is done with a release barrier, to provide lock leave semantic.
+.Pp
+If there are threads sleeping in the sleep queue associated with the
+umutex, one thread is woken up.
+If more than one thread sleeps in the sleep queue, the
+.Dv UMUTEX_CONTESTED
+bit is set together with the write of the
+.Dv UMUTEX_UNOWNED
+value into
+.Dv m_owner .
+.Pp
+The request adheres to the priority protection or inheritance protocol
+of the mutex, specified by the
+.Dv UMUTEX_PRIO_PROTECT
+or
+.Dv UMUTEX_PRIO_INHERIT
+flag, respectively.
+See description of the
+.Dv m_ceilings
+member of the
+.Vt struct umutex
+structure for additional details of the request operation on the
+priority protected protocol mutex.
+.It Dv UMTX_OP_SET_CEILING
+Set ceiling for the priority protected umutex.
+The arguments to the request are:
+.Bl -tag -width "It Fa obj"
+.It Fa obj
+Pointer to the umutex.
+.It Fa val
+New ceiling value.
+.It Fa uaddr
+Address of a variable of type
+.Vt uint32_t .
+If not
+.Dv NULL
+and the update was successful, the previous ceiling value is
+written to the location pointed to by
+.Fa uaddr .
+.El
+.Pp
+The request locks the umutex pointed to by the
+.Fa obj
+parameter, waiting for the lock if not immediately available.
+After the lock is obtained, the new ceiling value
+.Fa val
+is written to the
+.Dv m_ceilings[0]
+member of the
+.Vt struct umutex,
+after which the umutex is unlocked.
+.Pp
+The locking does not adhere to the priority protect protocol,
+to conform to the
+.Tn POSIX
+requirements for the
+.Xr pthread_mutex_setprioceiling 3
+interface.
+.It Dv UMTX_OP_CV_WAIT
+Wait for a condition.
+The arguments to the request are:
+.Bl -tag -width "It Fa uaddr2"
+.It Fa obj
+Pointer to the
+.Vt struct ucond .
+.It Fa val
+Request flags, see below.
+.It Fa uaddr
+Pointer to the umutex.
+.It Fa uaddr2
+Optional pointer to a
+.Vt struct timespec
+for timeout specification.
+.El
+.Pp
+The request must be issued by the thread owning the mutex pointed to
+by the
+.Fa uaddr
+argument.
+The
+.Dv c_hash_waiters
+member of the
+.Vt struct ucond ,
+pointed to by the
+.Fa obj
+argument, is set to an arbitrary non-zero value, after which the
+.Fa uaddr
+mutex is unlocked (following the appropriate protocol), and
+the current thread is put to sleep on the sleep queue keyed by
+the
+.Fa obj
+argument.
+The operations are performed atomically.
+It is guaranteed to not miss a wakeup from
+.Dv UMTX_OP_CV_SIGNAL
+or
+.Dv UMTX_OP_CV_BROADCAST
+sent between mutex unlock and putting the current thread on the sleep queue.
+.Pp
+Upon wakeup, if the timeout expired and no other threads are sleeping in
+the same sleep queue, the
+.Dv c_hash_waiters
+member is cleared.
+After wakeup, the
+.Fa uaddr
+umutex is not relocked.
+.Pp
+The following flags are defined:
+.Bl -tag -width "Dv CVWAIT_CLOCKID"
+.It Dv CVWAIT_ABSTIME
+Timeout is absolute.
+.It Dv CVWAIT_CLOCKID
+Clockid is provided.
+.El
+.Pp
+Optionally, a timeout for the request may be specified.
+Unlike other requests, the timeout value is specified directly by a
+.Vt struct timespec ,
+pointed to by the
+.Fa uaddr2
+argument.
+If the
+.Dv CVWAIT_CLOCKID
+flag is provided, the timeout uses the clock from the
+.Dv c_clockid
+member of the
+.Vt struct ucond ,
+pointed to by
+.Fa obj
+argument.
+Otherwise,
+.Dv CLOCK_REALTIME
+is used, regardless of the clock identifier possibly specified in the
+.Vt struct _umtx_time .
+If the
+.Dv CVWAIT_ABSTIME
+flag is supplied, the timeout specifies absolute time value, otherwise
+it denotes a relative time interval.
+.Pp
+The request is not restartable.
+An unblocked signal delivered during
+the wait always results in sleep interruption and
+.Er EINTR
+error.
+.It Dv UMTX_OP_CV_SIGNAL
+Wake up one condition waiter.
+The arguments to the request are:
+.Bl -tag -width "It Fa obj"
+.It Fa obj
+Pointer to
+.Vt struct ucond .
+.El
+.Pp
+The request wakes up at most one thread sleeping on the sleep queue keyed
+by the
+.Fa obj
+argument.
+If the woken up thread was the last on the sleep queue, the
+.Dv c_has_waiters
+member of the
+.Vt struct ucond
+is cleared.
+.It Dv UMTX_OP_CV_BROADCAST
+Wake up all condition waiters.
+The arguments to the request are:
+.Bl -tag -width "It Fa obj"
+.It Fa obj
+Pointer to
+.Vt struct ucond .
+.El
+.Pp
+The request wakes up all threads sleeping on the sleep queue keyed by the
+.Fa obj
+argument.
+The
+.Dv c_has_waiters
+member of the
+.Vt struct ucond
+is cleared.
+.It Dv UMTX_OP_WAIT_UINT
+Same as
+.Dv UMTX_OP_WAIT ,
+but the type of the variable pointed to by
+.Fa obj
+is
+.Vt u_int ,
+i.e. 32-bit integer.
+.It Dv UMTX_OP_RW_RDLOCK
+Read-lock a
+.Vt struct rwlock
+lock.
+The arguments to the request are:
+.Bl -tag -width "It Fa obj"
+.It Fa obj
+Pointer to the lock (of type
+.Vt struct rwlock )
+to be read-locked.
+.It Fa val
+Additional flags to augment locking behaviour.
+The valid flags in the
+.Fa val
+argument are:
+.Bl -tag -width "It Dv URWLOCK_PREFER_READER"
+.It Dv URWLOCK_PREFER_READER
+.El
+.El
+.Pp
+The request obtains the read lock on the specified
+.Vt struct rwlock
+by incrementing the count of readers in the
+.Dv rw_state
+word of the structure.
+If the
+.Dv URWLOCK_WRITE_OWNER
+bit is set in the word
+.Dv rw_state ,
+the lock was granted to a writer which has not yet relinquished
+its ownership.
+In this case the current thread is put to sleep until it makes sense to
+retry.
+.Pp
+If the
+.Dv URWLOCK_PREFER_READER
+flag is set either in the
+.Dv rw_flags
+word of the structure, or in the
+.Fa val
+argument of the request, the presence of the threads trying to obtain
+the write lock on the same structure does not prevent the current thread
+from trying to obtain the read lock.
+Otherwise, if the flag is not set, and the
+.Dv URWLOCK_WRITE_WAITERS
+flag is set in
+.Dv rw_state ,
+the current thread does not attempt to obtain read-lock.
+Instead it sets the
+.Dv URWLOCK_READ_WAITERS
+in the
+.Dv rw_state
+word and puts itself to sleep on corresponding sleep queue.
+Upon wakeup, the locking conditions are re-evaluated.
+.Pp
+Optionally, a timeout for the request may be specified.
+.Pp
+The request is not restartable.
+An unblocked signal delivered during the wait always results in sleep
+interruption and
+.Er EINTR
+error.
+.It Dv UMTX_OP_RW_WRLOCK
+Write-lock a
+.Vt struct rwlock
+lock.
+The arguments to the request are:
+.Bl -tag -width "It Fa obj"
+.It Fa obj
+Pointer to the lock (of type
+.Vt struct rwlock )
+to be write-locked.
+.El
+.Pp
+The request obtains a write lock on the specified
+.Vt struct rwlock ,
+by setting the
+.Dv URWLOCK_WRITE_OWNER
+bit in the
+.Dv rw_state
+word of the structure.
+If there is already a write lock owner, as indicated by the
+.Dv URWLOCK_WRITE_OWNER
+bit being set, or there are read lock owners, as indicated
+by the read-lock counter, the current thread does not attempt to
+obtain the write-lock.
+Instead it sets the
+.Dv URWLOCK_WRITE_WAITERS
+in the
+.Dv rw_state
+word and puts itself to sleep on corresponding sleep queue.
+Upon wakeup, the locking conditions are re-evaluated.
+.Pp
+Optionally, a timeout for the request may be specified.
+.Pp
+The request is not restartable.
+An unblocked signal delivered during the wait always results in sleep
+interruption and
+.Er EINTR
+error.
+.It Dv UMTX_OP_RW_UNLOCK
+Unlock rwlock.
+The arguments to the request are:
+.Bl -tag -width "It Fa obj"
+.It Fa obj
+Pointer to the lock (of type
+.Vt struct rwlock )
+to be unlocked.
+.El
+.Pp
+The unlock type (read or write) is determined by the
+current lock state.
+Note that the
+.Vt struct rwlock
+does not save information about the identity of the thread which
+acquired the lock.
+.Pp
+If there are pending writers after the unlock, and the
+.Dv URWLOCK_PREFER_READER
+flag is not set in the
+.Dv rw_flags
+member of the
+.Fa *obj
+structure, one writer is woken up, selected as described in the
+.Sx SLEEP QUEUES
+subsection.
+If the
+.Dv URWLOCK_PREFER_READER
+flag is set, a pending writer is woken up only if there is
+no pending readers.
+.Pp
+If there are no pending writers, or, in the case that the
+.Dv URWLOCK_PREFER_READER
+flag is set, then all pending readers are woken up by unlock.
+.It Dv UMTX_OP_WAIT_UINT_PRIVATE
+Same as
+.Dv UMTX_OP_WAIT_UINT ,
+but unconditionally select the process-private sleep queue.
+.It Dv UMTX_OP_WAKE_PRIVATE
+Same as
+.Dv UMTX_OP_WAKE ,
+but unconditionally select the process-private sleep queue.
+.It Dv UMTX_OP_MUTEX_WAIT
+Wait for mutex availability.
+The arguments to the request are:
+.Bl -tag -width "It Fa obj"
+.It Fa obj
+Address of the mutex.
+.El
+.Pp
+Similarly to the
+.Dv UMTX_OP_MUTEX_LOCK ,
+put the requesting thread to sleep if the mutex lock cannot be obtained
+immediately.
+The
+.Dv UMUTEX_CONTESTED
+bit is set in the
+.Dv m_owner
+word of the mutex to indicate that there is a waiter, before the thread
+is added to the sleep queue.
+Unlike the
+.Dv UMTX_OP_MUTEX_LOCK
+request, the lock is not obtained.
+.Pp
+The operation is not implemented for priority protected and
+priority inherited protocol mutexes.
+.Pp
+Optionally, a timeout for the request may be specified.
+.Pp
+.Pp
+A request with a timeout specified is not restartable.
+An unblocked signal delivered during the wait always results in sleep
+interruption and
+.Er EINTR
+error.
+A request without a timeout automatically restarts if the signal disposition
+requested restart via the
+.Dv SA_RESTART
+flag in
+.Vt struct sigaction
+member
+.Dv sa_flags .
+.It Dv UMTX_OP_NWAKE_PRIVATE
+Wake up a batch of sleeping threads.
+The arguments to the request are:
+.Bl -tag -width "It Fa obj"
+.It Fa obj
+Pointer to the array of pointers.
+.It Fa val
+Number of elements in the array pointed to by
+.Fa obj .
+.El
+.Pp
+For each element in the array pointed to by
+.Fa obj ,
+wakes up all threads waiting on the
+.Em private
+sleep queue with the key
+being the byte addressed by the array element.
+.It Dv UMTX_OP_MUTEX_WAKE
+Check if a normal umutex is unlocked and wake up a waiter.
+The arguments for the request are:
+.Bl -tag -width "It Fa obj"
+.It Fa obj
+Pointer to the umutex.
+.El
+.Pp
+If the
+.Dv m_owner
+word of the mutex pointed to by the
+.Fa obj
+argument indicates unowned mutex, which has its contention indicator bit
+.Dv UMUTEX_CONTESTED
+set, clear the bit and wake up one waiter in the sleep queue associated
+with the byte addressed by the
+.Fa obj ,
+if any.
+Only normal mutexes are supported by the request.
+The sleep queue is always one for a normal mutex type.
+.Pp
+This request is deprecated in favor of
+.Dv UMTX_OP_MUTEX_WAKE2
+since mutexes using it cannot synchronize their own destruction.
+That is, the
+.Dv m_owner
+word has already been set to
+.Dv UMUTEX_UNOWNED
+when this request is made,
+so that another thread can lock, unlock and destroy the mutex
+(if no other thread uses the mutex afterwards).
+Clearing the
+.Dv UMUTEX_CONTESTED
+bit may then modify freed memory.
+.It Dv UMTX_OP_MUTEX_WAKE2
+Check if a umutex is unlocked and wake up a waiter.
+The arguments for the request are:
+.Bl -tag -width "It Fa obj"
+.It Fa obj
+Pointer to the umutex.
+.It Fa val
+The umutex flags.
+.El
+.Pp
+The request does not read the
+.Dv m_flags
+member of the
+.Vt struct umutex ;
+instead, the
+.Fa val
+argument supplies flag information, in particular, to determine the
+sleep queue where the waiters are found for wake up.
+.Pp
+If the mutex is unowned, one waiter is woken up.
+.Pp
+If the mutex memory cannot be accessed, all waiters are woken up.
+.Pp
+If there is more than one waiter on the sleep queue, or there is only
+one waiter but the mutex is owned by a thread, the
+.Dv UMUTEX_CONTESTED
+bit is set in the
+.Dv m_owner
+word of the
+.Vt struct umutex .
+.It Dv UMTX_OP_SEM2_WAIT
+Wait until semaphore is available.
+The arguments to the request are:
+.Bl -tag -width "It Fa obj"
+.It Fa obj
+Pointer to the semaphore (of type
+.Vt struct _usem2 ) .
+.El
+Put the requesting thread onto a sleep queue if the semaphore counter
+is zero.
+If the thread is put to sleep, the
+.Dv USEM_HAS_WAITERS
+bit is set in the
+.Dv _count
+word to indicate waiters.
+The function returns either due to
+.Dv _count
+indicating the semaphore is available (non-zero count due to post),
+or due to a wakeup.
+The return does not guarantee that the semaphore is available,
+nor does it consume the semaphore lock on successful return.
+.Pp
+Optionally, a timeout for the request may be specified.
+.Pp
+A request with non-absolute timeout value is not restartable.
+An unblocked signal delivered during such wait results in sleep
+interruption and
+.Er EINTR
+error.
+.It Dv UMTX_OP_SEM2_WAKE
+Wake up waiters on semaphore lock.
+The arguments to the request are:
+.Bl -tag -width "It Fa obj"
+.It Fa obj
+Pointer to the semaphore (of type
+.Vt struct _usem2 ) .
+.El
+.Pp
+The request wakes up one waiter for the semaphore lock.
+The function does not increment the semaphore lock count.
+If the
+.Dv USEM_HAS_WAITERS
+bit was set in the
+.Dv _count
+word, and the last sleeping thread was woken up, the bit is cleared.
+.It Dv UMTX_OP_SHM
+Manage anonymous
+.Tn POSIX
+shared memory objects (see
+.Xr shm_open 2 ) ,
+which can be attached to a byte of physical memory, mapped into the
+process address space.
+The objects are used to implement process-shared locks in
+.Dv libthr .
+.Pp
+The
+.Fa val
+argument specifies the sub-request of the
+.Dv UMTX_OP_SHM
+request:
+.Bl -tag -width "Dv UMTX_SHM_DESTROY"
+.It Dv UMTX_SHM_CREAT
+Creates the anonymous shared memory object, which can be looked up
+with the specified key
+.Fa uaddr.
+If the object associated with the
+.Fa uaddr
+key already exists, it is returned instead of creating a new object.
+The object's size is one page.
+On success, the file descriptor referencing the object is returned.
+The descriptor can be used for mapping the object using
+.Xr mmap 2 ,
+or for other shared memory operations.
+.It Dv UMTX_SHM_LOOKUP
+Same as
+.Dv UMTX_SHM_CREATE
+request, but if there is no shared memory object associated with
+the specified key
+.Fa uaddr ,
+an error is returned, and no new object is created.
+.It Dv UMTX_SHM_DESTROY
+De-associate the shared object with the specified key
+.Fa uaddr.
+The object is destroyed after the last open file descriptor is closed
+and the last mapping for it is destroyed.
+.It Dv UMTX_SHM_ALIVE
+Checks whether there is a live shared object associated with the
+supplied key
+.Fa uaddr .
+Returns zero if there is, and an error otherwise.
+This request is an optimization of the
+.Dv UMTX_SHM_LOOKUP
+request.
+It is cheaper when only the liveness of the associated object is asked
+for, since no file descriptor is installed in the process fd table
+on success.
+.El
+.Pp
+The
+.Fa uaddr
+argument specifies the virtual address, which backing physical memory
+byte identity is used as a key for the anonymous shared object
+creation or lookup.
+.It Dv UMTX_OP_ROBUST_LISTS
+Register the list heads for the current thread's robust mutex lists.
+The arguments to the request are:
+.Bl -tag -width "It Fa obj"
+.It Fa val
+Size of the structure passed in the
+.Fa uaddr
+argument.
+.It Fa uaddr
+Pointer to the structure of type
+.Vt struct umtx_robust_lists_params .
+.El
+.Pp
+The structure is defined as
+.Bd -literal
+struct umtx_robust_lists_params {
+ uintptr_t robust_list_offset;
+ uintptr_t robust_priv_list_offset;
+ uintptr_t robust_inact_offset;
+};
+.Ed
+.Pp
+The
+.Dv robust_list_offset
+member contains address of the first element in the list of locked
+robust shared mutexes.
+The
+.Dv robust_priv_list_offset
+member contains address of the first element in the list of locked
+robust private mutexes.
+The private and shared robust locked lists are split to allow fast
+termination of the shared list on fork, in the child.
+.Pp
+The
+.Dv robust_inact_offset
+contains a pointer to the mutex which might be locked in nearby future,
+or might have been just unlocked.
+It is typically set by the lock or unlock mutex implementation code
+around the whole operation, since lists can be only changed race-free
+when the thread owns the mutex.
+The kernel inspects the
+.Dv robust_inact_offset
+in addition to walking the shared and private lists.
+Also, the mutex pointed to by
+.Dv robust_inact_offset
+is handled more loosely at the thread termination time,
+than other mutexes on the list.
+That mutex is allowed to be not owned by the current thread,
+in which case list processing is continued.
+See
+.Sx ROBUST UMUTEXES
+subsection for details.
+.El
+.Sh RETURN VALUES
+If successful,
+all requests, except
+.Dv UMTX_SHM_CREAT
+and
+.Dv UMTX_SHM_LOOKUP
+sub-requests of the
+.Dv UMTX_OP_SHM
+request, will return zero.
+The
+.Dv UMTX_SHM_CREAT
+and
+.Dv UMTX_SHM_LOOKUP
+return a shared memory file descriptor on success.
+On error \-1 is returned, and the
+.Va errno
+variable is set to indicate the error.
+.Sh ERRORS
+The
+.Fn _umtx_op
+operations will return the following errors:
+.Bl -tag -width "Bq Er ENOTRECOVERABLE"
+.It Bq Er EFAULT
+One of the arguments point to invalid memory.
+.It Bq Er EINVAL
+The clock identifier, specified for the
+.Vt struct _umtx_time
+timeout parameter, or in the
+.Dv c_clockid
+member of
+.Vt struct ucond,
+is invalid.
+.It Bq Er EINVAL
+The type of the mutex, encoded by the
+.Dv m_flags
+member of
+.Vt struct umutex ,
+is invalid.
+.It Bq Er EINVAL
+The
+.Dv m_owner
+member of the
+.Vt struct umutex
+has changed the lock owner thread identifier during unlock.
+.It Bq Er EINVAL
+The
+.Dv timeout.tv_sec
+or
+.Dv timeout.tv_nsec
+member of
+.Vt struct _umtx_time
+is less than zero, or
+.Dv timeout.tv_nsec
+is greater than 1000000000.
+.It Bq Er EINVAL
+The
+.Fa op
+argument specifies invalid operation.
+.It Bq Er EINVAL
+The
+.Fa uaddr
+argument for the
+.Dv UMTX_OP_SHM
+request specifies invalid operation.
+.It Bq Er EINVAL
+The
+.Dv UMTX_OP_SET_CEILING
+request specifies non priority protected mutex.
+.It Bq Er EINVAL
+The new ceiling value for the
+.Dv UMTX_OP_SET_CEILING
+request, or one or more of the values read from the
+.Dv m_ceilings
+array during lock or unlock operations, is greater than
+.Dv RTP_PRIO_MAX .
+.It Bq Er EPERM
+Unlock attempted on an object not owned by the current thread.
+.It Bq Er EOWNERDEAD
+The lock was requested on an umutex where the
+.Dv m_owner
+field was set to the
+.Dv UMUTEX_RB_OWNERDEAD
+value, indicating terminated robust mutex.
+The lock was granted to the caller, so this error in fact
+indicates success with additional conditions.
+.It Bq Er ENOTRECOVERABLE
+The lock was requested on an umutex which
+.Dv m_owner
+field is equal to the
+.Dv UMUTEX_RB_NOTRECOV
+value, indicating abandoned robust mutex after termination.
+The lock was not granted to the caller.
+.It Bq Er ENOTTY
+The shared memory object, associated with the address passed to the
+.Dv UMTX_SHM_ALIVE
+sub-request of
+.Dv UMTX_OP_SHM
+request, was destroyed.
+.It Bq Er ESRCH
+For the
+.Dv UMTX_SHM_LOOKUP ,
+.Dv UMTX_SHM_DESTROY ,
+and
+.Dv UMTX_SHM_ALIVE
+sub-requests of the
+.Dv UMTX_OP_SHM
+request, there is no shared memory object associated with the provided key.
+.It Bq Er ENOMEM
+The
+.Dv UMTX_SHM_CREAT
+sub-request of the
+.Dv UMTX_OP_SHM
+request cannot be satisfied, because allocation of the shared memory object
+would exceed the
+.Dv RLIMIT_UMTXP
+resource limit, see
+.Xr setrlimit 2 .
+.It Bq Er EAGAIN
+The maximum number of readers
+.Dv ( URWLOCK_MAX_READERS )
+were already granted ownership of the given
+.Vt struct rwlock
+for read.
+.It Bq Er EBUSY
+A try mutex lock operation was not able to obtain the lock.
+.It Bq Er ETIMEDOUT
+The request specified a timeout in the
+.Fa uaddr
+and
+.Fa uaddr2
+arguments, and timed out before obtaining the lock or being woken up.
+.It Bq Er EINTR
+A signal was delivered during wait, for a non-restartable operation.
+Operations with timeouts are typically non-restartable, but timeouts
+specified in absolute time may be restartable.
+.It Bq Er ERESTART
+A signal was delivered during wait, for a restartable operation.
+Mutex lock requests without timeout specified are restartable.
+The error is not returned to userspace code since restart
+is handled by usual adjustment of the instruction counter.
+.El
+.Sh BUGS
+A window between a unlocking robust mutex and resetting the pointer in the
+.Dv robust_inact_offset
+member of the registered
+.Vt struct umtx_robust_lists_params
+allows another thread to destroy the mutex, thus making the kernel inspect
+freed or reused memory.
+The
+.Li libthr
+implementation is only vulnerable to this race when operating on
+a shared mutex.
+A possible fix for the current implementation is to strengthen the checks
+for shared mutexes before terminating them, in particular, verifying
+that the mutex memory is mapped from a shared memory object allocated
+by the
+.Dv UMTX_OP_SHM
+request.
+This is not done because it is believed that the race is adequately
+covered by other consistency checks, while adding the check would
+prevent alternative implementations of
+.Li libpthread .
+.Sh SEE ALSO
+.Xr clock_gettime 2 ,
+.Xr mmap 2 ,
+.Xr shm_open 2 ,
+.Xr setrlimit 2 ,
+.Xr sigaction 2 ,
+.Xr thr_exit 2 ,
+.Xr thr_kill 2 ,
+.Xr thr_kill2 2 ,
+.Xr thr_new 2 ,
+.Xr thr_self 2 ,
+.Xr thr_set_name 2 ,
+.Xr signal 3
+.Sh STANDARDS
+The
+.Fn _umtx_op
+system call is non-standard and is used by the
+.Lb libthr
+to implement
+.St -p1003.1-2001
+.Xr pthread 3
+functionality.
diff --git a/lib/libc/sys/abort2.2 b/lib/libc/sys/abort2.2
new file mode 100644
index 000000000000..ca31d74267f3
--- /dev/null
+++ b/lib/libc/sys/abort2.2
@@ -0,0 +1,113 @@
+.\" Copyright (c) 2005 Wojciech A. Koszek <dunstan@FreeBSD.czest.pl>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 September 30, 2006
+.Dt ABORT2 2
+.Os
+.Sh NAME
+.Nm abort2
+.Nd "abort process with diagnostics"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft void
+.Fn abort2 "const char *why" "int nargs" "void **args"
+.Sh DESCRIPTION
+The
+.Fn abort2
+system call causes the process to be killed and the specified diagnostic
+message (with arguments) to be delivered by the kernel to the
+.Xr syslogd 8
+daemon.
+.Pp
+The
+.Fa why
+argument points to a
+.Dv NUL- Ns
+terminated string specifying a reason of the program's termination
+(maximum 128 characters long).
+The
+.Fa args
+array contains pointers which will be logged numerically
+(with the kernel's
+.Ql %p
+.Xr printf 9
+format).
+The
+.Fa nargs
+argument specifies the number of pointers in
+.Fa args
+(maximum 16).
+.Pp
+The
+.Fn abort2
+system call
+is intended for use in situations where continuation of a process
+is impossible or for other definitive reasons is unwanted, and normal
+diagnostic channels cannot be trusted to deliver the message.
+.Sh RETURN VALUES
+The
+.Fn abort2
+function
+never returns.
+.Pp
+The process is killed with
+.Dv SIGABRT
+unless the arguments to
+.Fn abort2
+are invalid, in which case
+.Dv SIGKILL
+is used.
+.Sh EXAMPLES
+.Bd -literal -compact
+#include <stdlib.h>
+
+if (weight_kg > max_load) {
+ void *ptrs[3];
+
+ ptrs[0] = (void *)(intptr_t)weight_kg;
+ ptrs[1] = (void *)(intptr_t)max_load;
+ ptrs[2] = haystack;
+ abort2("Camel overloaded", 3, ptrs);
+}
+.Ed
+.Sh SEE ALSO
+.Xr abort 3 ,
+.Xr exit 3
+.Sh HISTORY
+The
+.Fn abort2
+system call first appeared in
+.Fx 7.0 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Fn abort2
+system call was designed by
+.An Poul-Henning Kamp Aq Mt phk@FreeBSD.org .
+It was implemented by
+.An Wojciech A. Koszek Aq Mt dunstan@freebsd.czest.pl .
diff --git a/lib/libc/sys/accept.2 b/lib/libc/sys/accept.2
new file mode 100644
index 000000000000..7e60ccc4ccc5
--- /dev/null
+++ b/lib/libc/sys/accept.2
@@ -0,0 +1,239 @@
+.\" Copyright (c) 1983, 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)accept.2 8.2 (Berkeley) 12/11/93
+.\" $FreeBSD$
+.\"
+.Dd October 9, 2014
+.Dt ACCEPT 2
+.Os
+.Sh NAME
+.Nm accept ,
+.Nm accept4
+.Nd accept a connection on a socket
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/socket.h
+.Ft int
+.Fn accept "int s" "struct sockaddr * restrict addr" "socklen_t * restrict addrlen"
+.Ft int
+.Fn accept4 "int s" "struct sockaddr * restrict addr" "socklen_t * restrict addrlen" "int flags"
+.Sh DESCRIPTION
+The argument
+.Fa s
+is a socket that has been created with
+.Xr socket 2 ,
+bound to an address with
+.Xr bind 2 ,
+and is listening for connections after a
+.Xr listen 2 .
+The
+.Fn accept
+system call extracts the first connection request on the
+queue of pending connections, creates a new socket,
+and allocates a new file descriptor for the socket which
+inherits the state of the
+.Dv O_NONBLOCK
+and
+.Dv O_ASYNC
+properties and the destination of
+.Dv SIGIO
+and
+.Dv SIGURG
+signals from the original socket
+.Fa s .
+.Pp
+The
+.Fn accept4
+system call is similar,
+but the
+.Dv O_NONBLOCK
+property of the new socket is instead determined by the
+.Dv SOCK_NONBLOCK
+flag in the
+.Fa flags
+argument,
+the
+.Dv O_ASYNC
+property is cleared,
+the signal destination is cleared
+and the close-on-exec flag on the new file descriptor can be set via the
+.Dv SOCK_CLOEXEC
+flag in the
+.Fa flags
+argument.
+.Pp
+If no pending connections are
+present on the queue, and the original socket
+is not marked as non-blocking,
+.Fn accept
+blocks the caller until a connection is present.
+If the original socket
+is marked non-blocking and no pending
+connections are present on the queue,
+.Fn accept
+returns an error as described below.
+The accepted socket
+may not be used
+to accept more connections.
+The original socket
+.Fa s
+remains open.
+.Pp
+The argument
+.Fa addr
+is a result argument that is filled-in with
+the address of the connecting entity,
+as known to the communications layer.
+The exact format of the
+.Fa addr
+argument is determined by the domain in which the communication
+is occurring.
+A null pointer may be specified for
+.Fa addr
+if the address information is not desired;
+in this case,
+.Fa addrlen
+is not used and should also be null.
+Otherwise, the
+.Fa addrlen
+argument
+is a value-result argument; it should initially contain the
+amount of space pointed to by
+.Fa addr ;
+on return it will contain the actual length (in bytes) of the
+address returned.
+This call
+is used with connection-based socket types, currently with
+.Dv SOCK_STREAM .
+.Pp
+It is possible to
+.Xr select 2
+a socket for the purposes of doing an
+.Fn accept
+by selecting it for read.
+.Pp
+For certain protocols which require an explicit confirmation,
+such as
+.Tn ISO
+or
+.Tn DATAKIT ,
+.Fn accept
+can be thought of
+as merely dequeueing the next connection
+request and not implying confirmation.
+Confirmation can be implied by a normal read or write on the new
+file descriptor, and rejection can be implied by closing the
+new socket.
+.Pp
+For some applications, performance may be enhanced by using an
+.Xr accept_filter 9
+to pre-process incoming connections.
+.Pp
+When using
+.Fn accept ,
+portable programs should not rely on the
+.Dv O_NONBLOCK
+and
+.Dv O_ASYNC
+properties and the signal destination being inherited,
+but should set them explicitly using
+.Xr fcntl 2 ;
+.Fn accept4
+sets these properties consistently,
+but may not be fully portable across
+.Ux
+platforms.
+.Sh RETURN VALUES
+These calls return \-1 on error.
+If they succeed, they return a non-negative
+integer that is a descriptor for the accepted socket.
+.Sh ERRORS
+The
+.Fn accept
+and
+.Fn accept4
+system calls will fail if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The descriptor is invalid.
+.It Bq Er EINTR
+The
+.Fn accept
+operation was interrupted.
+.It Bq Er EMFILE
+The per-process descriptor table is full.
+.It Bq Er ENFILE
+The system file table is full.
+.It Bq Er ENOTSOCK
+The descriptor references a file, not a socket.
+.It Bq Er EINVAL
+.Xr listen 2
+has not been called on the socket descriptor.
+.It Bq Er EFAULT
+The
+.Fa addr
+argument is not in a writable part of the
+user address space.
+.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
+A connection arrived, but it was closed while waiting
+on the listen queue.
+.El
+.Pp
+The
+.Fn accept4
+system call will also fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa flags
+argument is invalid.
+.El
+.Sh SEE ALSO
+.Xr bind 2 ,
+.Xr connect 2 ,
+.Xr getpeername 2 ,
+.Xr getsockname 2 ,
+.Xr listen 2 ,
+.Xr select 2 ,
+.Xr socket 2 ,
+.Xr accept_filter 9
+.Sh HISTORY
+The
+.Fn accept
+system call appeared in
+.Bx 4.2 .
+.Pp
+The
+.Fn accept4
+system call appeared in
+.Fx 10.0 .
diff --git a/lib/libc/sys/accept.c b/lib/libc/sys/accept.c
new file mode 100644
index 000000000000..38e32f2c836d
--- /dev/null
+++ b/lib/libc/sys/accept.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2014 The FreeBSD Foundation.
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Konstantin Belousov
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice(s), this list of conditions and the following disclaimer as
+ * the first lines of this file unmodified other than the possible
+ * addition of one or more copyright notices.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice(s), this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/syscall.h>
+#include <sys/socket.h>
+#include "libc_private.h"
+
+__weak_reference(__sys_accept, __accept);
+
+#pragma weak accept
+int
+accept(int s, struct sockaddr *addr, socklen_t *addrlen)
+{
+
+ return (((int (*)(int, struct sockaddr *, socklen_t *))
+ __libc_interposing[INTERPOS_accept])(s, addr, addrlen));
+}
diff --git a/lib/libc/sys/accept4.c b/lib/libc/sys/accept4.c
new file mode 100644
index 000000000000..2907b047efdc
--- /dev/null
+++ b/lib/libc/sys/accept4.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2014 The FreeBSD Foundation.
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Konstantin Belousov
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice(s), this list of conditions and the following disclaimer as
+ * the first lines of this file unmodified other than the possible
+ * addition of one or more copyright notices.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice(s), this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/syscall.h>
+#include <sys/socket.h>
+#include "libc_private.h"
+
+__weak_reference(__sys_accept4, __accept4);
+
+#pragma weak accept4
+int
+accept4(int s, struct sockaddr *addr, socklen_t *addrlen, int flags)
+{
+
+ return (((int (*)(int, struct sockaddr *, socklen_t *, int))
+ __libc_interposing[INTERPOS_accept4])(s, addr, addrlen, flags));
+}
diff --git a/lib/libc/sys/access.2 b/lib/libc/sys/access.2
new file mode 100644
index 000000000000..c70e7a2d5313
--- /dev/null
+++ b/lib/libc/sys/access.2
@@ -0,0 +1,243 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)access.2 8.2 (Berkeley) 4/1/94
+.\" $FreeBSD$
+.\"
+.Dd September 15, 2014
+.Dt ACCESS 2
+.Os
+.Sh NAME
+.Nm access ,
+.Nm eaccess ,
+.Nm faccessat
+.Nd check accessibility of a file
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft int
+.Fn access "const char *path" "int mode"
+.Ft int
+.Fn eaccess "const char *path" "int mode"
+.Ft int
+.Fn faccessat "int fd" "const char *path" "int mode" "int flag"
+.Sh DESCRIPTION
+The
+.Fn access
+and
+.Fn eaccess
+system calls check the accessibility of the
+file named by
+the
+.Fa path
+argument
+for the access permissions indicated by
+the
+.Fa mode
+argument.
+The value of
+.Fa mode
+is either the bitwise-inclusive OR of the access permissions to be
+checked
+.Dv ( R_OK
+for read permission,
+.Dv W_OK
+for write permission, and
+.Dv X_OK
+for execute/search permission),
+or the existence test
+.Pq Dv F_OK .
+.Pp
+For additional information, see the
+.Sx "File Access Permission"
+section of
+.Xr intro 2 .
+.Pp
+The
+.Fn eaccess
+system call uses
+the effective user ID and the group access list
+to authorize the request;
+the
+.Fn access
+system call uses
+the real user ID in place of the effective user ID,
+the real group ID in place of the effective group ID,
+and the rest of the group access list.
+.Pp
+The
+.Fn faccessat
+system call is equivalent to
+.Fn access
+except in the case where
+.Fa path
+specifies a relative path.
+In this case the file whose accessibility is to be determined is
+located relative to the directory associated with the file descriptor
+.Fa fd
+instead of the current working directory.
+If
+.Fn faccessat
+is passed the special value
+.Dv AT_FDCWD
+in the
+.Fa fd
+parameter, the current working directory is used and the behavior is
+identical to a call to
+.Fn access .
+Values for
+.Fa flag
+are constructed by a bitwise-inclusive OR of flags from the following
+list, defined in
+.In fcntl.h :
+.Bl -tag -width indent
+.It Dv AT_EACCESS
+The checks for accessibility are performed using the effective user and group
+IDs instead of the real user and group ID as required in a call to
+.Fn access .
+.El
+.Pp
+Even if a process's real or effective user has appropriate privileges
+and indicates success for
+.Dv X_OK ,
+the file may not actually have execute permission bits set.
+Likewise for
+.Dv R_OK
+and
+.Dv W_OK .
+.Sh RETURN VALUES
+.Rv -std
+.Sh ERRORS
+.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
+A component of a pathname exceeded 255 characters,
+or an entire path name exceeded 1023 characters.
+.It Bq Er ENOENT
+The named file does not exist.
+.It Bq Er ELOOP
+Too many symbolic links were encountered in translating the pathname.
+.It Bq Er EROFS
+Write access is requested for a file on a read-only file system.
+.It Bq Er ETXTBSY
+Write access is requested for a pure procedure (shared text)
+file presently being executed.
+.It Bq Er EACCES
+Permission bits of the file mode do not permit the requested
+access, or search permission is denied on a component of the
+path prefix.
+.It Bq Er EFAULT
+The
+.Fa path
+argument
+points outside the process's allocated address space.
+.It Bq Er EIO
+An I/O error occurred while reading from or writing to the file system.
+.El
+.Pp
+Also, the
+.Fn faccessat
+system call may fail if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa path
+argument does not specify an absolute path and the
+.Fa fd
+argument is
+neither
+.Dv AT_FDCWD
+nor a valid file descriptor.
+.It Bq Er EINVAL
+The value of the
+.Fa flag
+argument is not valid.
+.It Bq Er ENOTDIR
+The
+.Fa path
+argument is not an absolute path and
+.Fa fd
+is neither
+.Dv AT_FDCWD
+nor a file descriptor associated with a directory.
+.El
+.Sh SEE ALSO
+.Xr chmod 2 ,
+.Xr intro 2 ,
+.Xr stat 2
+.Sh STANDARDS
+The
+.Fn access
+system call is expected to conform to
+.St -p1003.1-90 .
+The
+.Fn faccessat
+system call follows The Open Group Extended API Set 2 specification.
+.Sh HISTORY
+The
+.Fn access
+function appeared in
+.At v7 .
+The
+.Fn faccessat
+system call appeared in
+.Fx 8.0 .
+.Sh SECURITY CONSIDERATIONS
+The
+.Fn access
+system call
+is a potential security hole due to race conditions and
+should never be used.
+Set-user-ID and set-group-ID applications should restore the
+effective user or group ID,
+and perform actions directly rather than use
+.Fn access
+to simulate access checks for the real user or group ID.
+The
+.Fn eaccess
+system call
+likewise may be subject to races if used inappropriately.
+.Pp
+.Fn access
+remains useful for providing clues to users as to whether operations
+make sense for particular filesystem objects (e.g. 'delete' menu
+item only highlighted in a writable folder ... avoiding interpretation
+of the st_mode bits that the application might not understand --
+e.g. in the case of AFS).
+It also allows a cheaper file existence test than
+.Xr stat 2 .
diff --git a/lib/libc/sys/acct.2 b/lib/libc/sys/acct.2
new file mode 100644
index 000000000000..caf1aeab3b46
--- /dev/null
+++ b/lib/libc/sys/acct.2
@@ -0,0 +1,131 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)acct.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd April 17, 2004
+.Dt ACCT 2
+.Os
+.Sh NAME
+.Nm acct
+.Nd enable or disable process accounting
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft int
+.Fn acct "const char *file"
+.Sh DESCRIPTION
+The
+.Fn acct
+system call enables or disables the collection of system accounting
+records.
+If the argument
+.Fa file
+is a null pointer, accounting is disabled.
+If
+.Fa file
+is an
+.Em existing
+pathname (null-terminated), record collection is enabled and for
+every process initiated which terminates under normal
+conditions an accounting record is appended to
+.Fa file .
+Abnormal conditions of termination are reboots
+or other fatal system problems.
+Records for processes which never terminate cannot be
+produced by
+.Fn acct .
+.Pp
+For more information on the record structure used by
+.Fn acct ,
+see
+.In sys/acct.h
+and
+.Xr acct 5 .
+.Pp
+This call is permitted only to the super-user.
+.Sh NOTES
+Accounting is automatically disabled when the file system the
+accounting file resides on runs out of space; it is enabled when
+space once again becomes available.
+The values controlling this behaviour can be modified using the following
+.Xr sysctl 8
+variables:
+.Bl -tag -width ".Va kern.acct_chkfreq"
+.It Va kern.acct_chkfreq
+Specifies the frequency (in seconds) with which free disk
+space should be checked.
+.It Va kern.acct_resume
+The percentage of free disk space above which process
+accounting will resume.
+.It Va kern.acct_suspend
+The percentage of free disk space below which process
+accounting will suspend.
+.El
+.Sh RETURN VALUES
+On error -1 is returned.
+The file must exist and the call may be exercised only by the super-user.
+.Sh ERRORS
+The
+.Fn acct
+system call will fail if one of the following is true:
+.Bl -tag -width Er
+.It Bq Er EPERM
+The caller is not the super-user.
+.It Bq Er ENOTDIR
+A component of the path prefix is not a directory.
+.It Bq Er ENAMETOOLONG
+A component of a pathname exceeded 255 characters,
+or an entire path name exceeded 1023 characters.
+.It Bq Er ENOENT
+The named file does not exist.
+.It Bq Er EACCES
+Search permission is denied for a component of the path prefix,
+or the path name is not a regular file.
+.It Bq Er ELOOP
+Too many symbolic links were encountered in translating the pathname.
+.It Bq Er EROFS
+The named file resides on a read-only file system.
+.It Bq Er EFAULT
+The
+.Fa file
+argument
+points outside the process's allocated address space.
+.It Bq Er EIO
+An I/O error occurred while reading from or writing to the file system.
+.El
+.Sh SEE ALSO
+.Xr acct 5 ,
+.Xr accton 8 ,
+.Xr sa 8
+.Sh HISTORY
+The
+.Fn acct
+function appeared in
+.At v7 .
diff --git a/lib/libc/sys/adjtime.2 b/lib/libc/sys/adjtime.2
new file mode 100644
index 000000000000..95cfca0a464a
--- /dev/null
+++ b/lib/libc/sys/adjtime.2
@@ -0,0 +1,111 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)adjtime.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt ADJTIME 2
+.Os
+.Sh NAME
+.Nm adjtime
+.Nd "correct the time to allow synchronization of the system clock"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/time.h
+.Ft int
+.Fn adjtime "const struct timeval *delta" "struct timeval *olddelta"
+.Sh DESCRIPTION
+The
+.Fn adjtime
+system call
+makes small adjustments to the system time, as returned by
+.Xr gettimeofday 2 ,
+advancing or retarding it
+by the time specified by the timeval
+.Fa delta .
+If
+.Fa delta
+is negative, the clock is
+slowed down by incrementing it more slowly than normal until
+the correction is complete.
+If
+.Fa delta
+is positive, a larger increment than normal
+is used.
+The skew used to perform the correction is generally a fraction of one percent.
+Thus, the time is always
+a monotonically increasing function.
+A time correction from an earlier call to
+.Fn adjtime
+may not be finished when
+.Fn adjtime
+is called again.
+If
+.Fa olddelta
+is not a null pointer,
+the structure pointed to will contain, upon return, the
+number of microseconds still to be corrected
+from the earlier call.
+.Pp
+This call may be used by time servers that synchronize the clocks
+of computers in a local area network.
+Such time servers would slow down the clocks of some machines
+and speed up the clocks of others to bring them to the average network time.
+.Pp
+The
+.Fn adjtime
+system call
+is restricted to the super-user.
+.Sh RETURN VALUES
+.Rv -std adjtime
+.Sh ERRORS
+The
+.Fn adjtime
+system call will fail if:
+.Bl -tag -width Er
+.It Bq Er EFAULT
+An argument points outside the process's allocated address space.
+.It Bq Er EPERM
+The process's effective user ID is not that of the super-user.
+.El
+.Sh SEE ALSO
+.Xr date 1 ,
+.Xr gettimeofday 2 ,
+.Xr timed 8 ,
+.Xr timedc 8
+.Rs
+.%T "TSP: The Time Synchronization Protocol for UNIX 4.3BSD"
+.%A R. Gusella
+.%A S. Zatti
+.Re
+.Sh HISTORY
+The
+.Fn adjtime
+system call appeared in
+.Bx 4.3 .
diff --git a/lib/libc/sys/aio_cancel.2 b/lib/libc/sys/aio_cancel.2
new file mode 100644
index 000000000000..3d9cbaf2ff4f
--- /dev/null
+++ b/lib/libc/sys/aio_cancel.2
@@ -0,0 +1,117 @@
+.\" Copyright (c) 1999 Softweyr LLC.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY Softweyr LLC AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL Softweyr LLC OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 January 19, 2000
+.Dt AIO_CANCEL 2
+.Os
+.Sh NAME
+.Nm aio_cancel
+.Nd cancel an outstanding asynchronous I/O operation (REALTIME)
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In aio.h
+.Ft int
+.Fn aio_cancel "int fildes" "struct aiocb *iocb"
+.Sh DESCRIPTION
+The
+.Fn aio_cancel
+system call cancels the outstanding asynchronous
+I/O request for the file descriptor specified in
+.Fa fildes .
+If
+.Fa iocb
+is specified, only that specific asynchronous I/O request is cancelled.
+.Pp
+Normal asynchronous notification occurs for cancelled requests.
+Requests complete with an error result of
+.Er ECANCELED .
+.Sh RESTRICTIONS
+The
+.Fn aio_cancel
+system call does not cancel asynchronous I/O requests for raw disk devices.
+The
+.Fn aio_cancel
+system call will always return
+.Dv AIO_NOTCANCELED
+for file descriptors associated with raw disk devices.
+.Sh RETURN VALUES
+The
+.Fn aio_cancel
+system call returns -1 to indicate an error, or one of the following:
+.Bl -tag -width Dv
+.It Bq Dv AIO_CANCELED
+All outstanding requests meeting the criteria specified were cancelled.
+.It Bq Dv AIO_NOTCANCELED
+Some requests were not cancelled, status for the requests should be
+checked with
+.Xr aio_error 2 .
+.It Bq Dv AIO_ALLDONE
+All of the requests meeting the criteria have finished.
+.El
+.Sh ERRORS
+An error return from
+.Fn aio_cancel
+indicates:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa fildes
+argument
+is an invalid file descriptor.
+.El
+.Sh SEE ALSO
+.Xr aio_error 2 ,
+.Xr aio_read 2 ,
+.Xr aio_return 2 ,
+.Xr aio_suspend 2 ,
+.Xr aio_write 2 ,
+.Xr aio 4
+.Sh STANDARDS
+The
+.Fn aio_cancel
+system call is expected to conform to the
+.St -p1003.1
+standard.
+.Sh HISTORY
+The
+.Fn aio_cancel
+system call first appeared in
+.Fx 3.0 .
+The first functional implementation of
+.Fn aio_cancel
+appeared in
+.Fx 4.0 .
+.Sh AUTHORS
+.An -nosplit
+This
+manual page was originally written by
+.An Wes Peters Aq Mt wes@softweyr.com .
+.An Christopher M Sedore Aq Mt cmsedore@maxwell.syr.edu
+updated it when
+.Fn aio_cancel
+was implemented for
+.Fx 4.0 .
diff --git a/lib/libc/sys/aio_error.2 b/lib/libc/sys/aio_error.2
new file mode 100644
index 000000000000..030914616121
--- /dev/null
+++ b/lib/libc/sys/aio_error.2
@@ -0,0 +1,101 @@
+.\" Copyright (c) 1999 Softweyr LLC.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY Softweyr LLC AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL Softweyr LLC OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd June 2, 1999
+.Dt AIO_ERROR 2
+.Os
+.Sh NAME
+.Nm aio_error
+.Nd retrieve error status of asynchronous I/O operation (REALTIME)
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In aio.h
+.Ft int
+.Fn aio_error "const struct aiocb *iocb"
+.Sh DESCRIPTION
+The
+.Fn aio_error
+system call returns the error status of the asynchronous I/O request
+associated with the structure pointed to by
+.Fa iocb .
+.Sh RETURN VALUES
+If the asynchronous I/O request has completed successfully,
+.Fn aio_error
+returns 0.
+If the request has not yet completed,
+.Er EINPROGRESS
+is returned.
+If the request has completed unsuccessfully the error
+status is returned as described in
+.Xr read 2 ,
+.Xr write 2 ,
+or
+.Xr fsync 2 .
+On failure,
+.Fn aio_error
+returns
+.Dv -1
+and sets
+.Dv errno
+to indicate the error condition.
+.Sh ERRORS
+The
+.Fn aio_error
+system call will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa iocb
+argument
+does not reference an outstanding asynchronous I/O request.
+.El
+.Sh SEE ALSO
+.Xr aio_cancel 2 ,
+.Xr aio_read 2 ,
+.Xr aio_return 2 ,
+.Xr aio_suspend 2 ,
+.Xr aio_write 2 ,
+.Xr fsync 2 ,
+.Xr read 2 ,
+.Xr write 2 ,
+.Xr aio 4
+.Sh STANDARDS
+The
+.Fn aio_error
+system call
+is expected to conform to the
+.St -p1003.1
+standard.
+.Sh HISTORY
+The
+.Fn aio_error
+system call first appeared in
+.Fx 3.0 .
+.Sh AUTHORS
+This
+manual page was written by
+.An Wes Peters Aq Mt wes@softweyr.com .
diff --git a/lib/libc/sys/aio_fsync.2 b/lib/libc/sys/aio_fsync.2
new file mode 100644
index 000000000000..9d5d143416b3
--- /dev/null
+++ b/lib/libc/sys/aio_fsync.2
@@ -0,0 +1,178 @@
+.\" Copyright (c) 2013 Sergey Kandaurov
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 August 19, 2016
+.Dt AIO_FSYNC 2
+.Os
+.Sh NAME
+.Nm aio_fsync
+.Nd asynchronous file synchronization (REALTIME)
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In aio.h
+.Ft int
+.Fn aio_fsync "int op" "struct aiocb *iocb"
+.Sh DESCRIPTION
+The
+.Fn aio_fsync
+system call allows the calling process to move all modified data
+associated with the descriptor
+.Fa iocb->aio_fildes
+to a permanent storage device.
+The call returns immediately after the synchronization request has been
+enqueued to the descriptor; the synchronization may or may not have
+completed at the time the call returns.
+.Pp
+The
+.Fa op
+argument can only be set to
+.Dv O_SYNC
+to cause all currently queued I/O operations to be completed
+as if by a call to
+.Xr fsync 2 .
+.Pp
+If _POSIX_PRIORITIZED_IO is defined, and the descriptor supports it,
+then the enqueued operation is submitted at a priority equal to that
+of the calling process minus
+.Fa iocb->aio_reqprio .
+.Pp
+The
+.Fa iocb
+pointer may be subsequently used as an argument to
+.Fn aio_return
+and
+.Fn aio_error
+in order to determine return or error status for the enqueued operation
+while it is in progress.
+.Pp
+If the request could not be enqueued (generally due to invalid arguments),
+the call returns without having enqueued the request.
+.Pp
+The
+.Fa iocb->aio_sigevent
+structure can be used to request notification of the operation's
+completion as described in
+.Xr aio 4 .
+.Sh RESTRICTIONS
+The Asynchronous I/O Control Block structure pointed to by
+.Fa iocb
+must remain valid until the
+operation has completed.
+.Pp
+The asynchronous I/O control buffer
+.Fa iocb
+should be zeroed before the
+.Fn aio_fsync
+call to avoid passing bogus context information to the kernel.
+.Pp
+Modification of the Asynchronous I/O Control Block structure is not allowed
+while the request is queued.
+.Sh RETURN VALUES
+.Rv -std aio_fsync
+.Sh ERRORS
+The
+.Fn aio_fsync
+system call will fail if:
+.Bl -tag -width Er
+.It Bq Er EAGAIN
+The request was not queued because of system resource limitations.
+.It Bq Er EINVAL
+The asynchronous notification method in
+.Fa iocb->aio_sigevent.sigev_notify
+is invalid or not supported.
+.It Bq Er EOPNOTSUPP
+Asynchronous file synchronization operations on the file descriptor
+.Fa iocb->aio_fildes
+are unsafe and unsafe asynchronous I/O operations are disabled.
+.It Bq Er EINVAL
+A value of the
+.Fa op
+argument is not set to
+.Dv O_SYNC .
+.El
+.Pp
+The following conditions may be synchronously detected when the
+.Fn aio_fsync
+system call is made, or asynchronously, at any time thereafter.
+If they are detected at call time,
+.Fn aio_fsync
+returns -1 and sets
+.Va errno
+appropriately; otherwise the
+.Fn aio_return
+system call must be called, and will return -1, and
+.Fn aio_error
+must be called to determine the actual value that would have been
+returned in
+.Va errno .
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa iocb->aio_fildes
+argument
+is not a valid descriptor.
+.It Bq Er EINVAL
+This implementation does not support synchronized I/O for this file.
+.El
+.Pp
+If the request is successfully enqueued, but subsequently cancelled
+or an error occurs, the value returned by the
+.Fn aio_return
+system call is per the
+.Xr read 2
+and
+.Xr write 2
+system calls, and the value returned by the
+.Fn aio_error
+system call is one of the error returns from the
+.Xr read 2
+or
+.Xr write 2
+system calls.
+.Sh SEE ALSO
+.Xr aio_cancel 2 ,
+.Xr aio_error 2 ,
+.Xr aio_read 2 ,
+.Xr aio_return 2 ,
+.Xr aio_suspend 2 ,
+.Xr aio_waitcomplete 2 ,
+.Xr aio_write 2 ,
+.Xr fsync 2 ,
+.Xr sigevent 3 ,
+.Xr siginfo 3 ,
+.Xr aio 4
+.Sh STANDARDS
+The
+.Fn aio_fsync
+system call is expected to conform to the
+.St -p1003.1
+standard.
+.Sh HISTORY
+The
+.Fn aio_fsync
+system call first appeared in
+.Fx 7.0 .
diff --git a/lib/libc/sys/aio_mlock.2 b/lib/libc/sys/aio_mlock.2
new file mode 100644
index 000000000000..f7f4a2781a91
--- /dev/null
+++ b/lib/libc/sys/aio_mlock.2
@@ -0,0 +1,138 @@
+.\" Copyright (c) 2013 Gleb Smirnoff <glebius@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 August 19, 2016
+.Dt AIO_MLOCK 2
+.Os
+.Sh NAME
+.Nm aio_mlock
+.Nd asynchronous
+.Xr mlock 2
+operation
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In aio.h
+.Ft int
+.Fn aio_mlock "struct aiocb *iocb"
+.Sh DESCRIPTION
+The
+.Fn aio_mlock
+system call allows the calling process to lock into memory the
+physical pages associated with the virtual address range starting at
+.Fa iocb->aio_buf
+for
+.Fa iocb->aio_nbytes
+bytes.
+The call returns immediately after the locking request has
+been enqueued; the operation may or may not have completed at the time
+the call returns.
+.Pp
+The
+.Fa iocb
+pointer may be subsequently used as an argument to
+.Fn aio_return
+and
+.Fn aio_error
+in order to determine return or error status for the enqueued operation
+while it is in progress.
+.Pp
+If the request could not be enqueued (generally due to
+.Xr aio 4
+limits),
+then the call returns without having enqueued the request.
+.Pp
+The
+.Fa iocb->aio_sigevent
+structure can be used to request notification of the operation's
+completion as described in
+.Xr aio 4 .
+.Sh RESTRICTIONS
+The Asynchronous I/O Control Block structure pointed to by
+.Fa iocb
+and the buffer that the
+.Fa iocb->aio_buf
+member of that structure references must remain valid until the
+operation has completed.
+.Pp
+The asynchronous I/O control buffer
+.Fa iocb
+should be zeroed before the
+.Fn aio_mlock
+call to avoid passing bogus context information to the kernel.
+.Pp
+Modifications of the Asynchronous I/O Control Block structure or the
+memory mapping described by the virtual address range are not allowed
+while the request is queued.
+.Sh RETURN VALUES
+.Rv -std aio_mlock
+.Sh ERRORS
+The
+.Fn aio_mlock
+system call will fail if:
+.Bl -tag -width Er
+.It Bq Er EAGAIN
+The request was not queued because of system resource limitations.
+.It Bq Er EINVAL
+The asynchronous notification method in
+.Fa iocb->aio_sigevent.sigev_notify
+is invalid or not supported.
+.El
+.Pp
+If the request is successfully enqueued, but subsequently cancelled
+or an error occurs, the value returned by the
+.Fn aio_return
+system call is per the
+.Xr mlock 2
+system call, and the value returned by the
+.Fn aio_error
+system call is one of the error returns from the
+.Xr mlock 2
+system call, or
+.Er ECANCELED
+if the request was explicitly cancelled via a call to
+.Fn aio_cancel .
+.Sh SEE ALSO
+.Xr aio_cancel 2 ,
+.Xr aio_error 2 ,
+.Xr aio_return 2 ,
+.Xr mlock 2 ,
+.Xr sigevent 3 ,
+.Xr aio 4
+.Sh PORTABILITY
+The
+.Fn aio_mlock
+system call is a
+.Fx
+extension, and should not be used in portable code.
+.Sh HISTORY
+The
+.Fn aio_mlock
+system call first appeared in
+.Fx 10.0 .
+.Sh AUTHORS
+The system call was introduced by
+.An Gleb Smirnoff Aq Mt glebius@FreeBSD.org .
diff --git a/lib/libc/sys/aio_read.2 b/lib/libc/sys/aio_read.2
new file mode 100644
index 000000000000..bbf96cc89890
--- /dev/null
+++ b/lib/libc/sys/aio_read.2
@@ -0,0 +1,222 @@
+.\" Copyright (c) 1998 Terry Lambert
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 August 19, 2016
+.Dt AIO_READ 2
+.Os
+.Sh NAME
+.Nm aio_read
+.Nd asynchronous read from a file (REALTIME)
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In aio.h
+.Ft int
+.Fn aio_read "struct aiocb *iocb"
+.Sh DESCRIPTION
+The
+.Fn aio_read
+system call allows the calling process to read
+.Fa iocb->aio_nbytes
+from the descriptor
+.Fa iocb->aio_fildes
+beginning at the offset
+.Fa iocb->aio_offset
+into the buffer pointed to by
+.Fa iocb->aio_buf .
+The call returns immediately after the read request has
+been enqueued to the descriptor; the read may or may not have
+completed at the time the call returns.
+.Pp
+If _POSIX_PRIORITIZED_IO is defined, and the descriptor supports it,
+then the enqueued operation is submitted at a priority equal to that
+of the calling process minus
+.Fa iocb->aio_reqprio .
+.Pp
+The
+.Fa iocb->aio_lio_opcode
+argument
+is ignored by the
+.Fn aio_read
+system call.
+.Pp
+The
+.Fa iocb
+pointer may be subsequently used as an argument to
+.Fn aio_return
+and
+.Fn aio_error
+in order to determine return or error status for the enqueued operation
+while it is in progress.
+.Pp
+If the request could not be enqueued (generally due to invalid arguments),
+then the call returns without having enqueued the request.
+.Pp
+If the request is successfully enqueued, the value of
+.Fa iocb->aio_offset
+can be modified during the request as context, so this value must
+not be referenced after the request is enqueued.
+.Pp
+The
+.Fa iocb->aio_sigevent
+structure can be used to request notification of the operation's
+completion as described in
+.Xr aio 4 .
+.Sh RESTRICTIONS
+The Asynchronous I/O Control Block structure pointed to by
+.Fa iocb
+and the buffer that the
+.Fa iocb->aio_buf
+member of that structure references must remain valid until the
+operation has completed.
+.Pp
+The asynchronous I/O control buffer
+.Fa iocb
+should be zeroed before the
+.Fn aio_read
+call to avoid passing bogus context information to the kernel.
+.Pp
+Modifications of the Asynchronous I/O Control Block structure or the
+buffer contents are not allowed while the request is queued.
+.Pp
+If the file offset in
+.Fa iocb->aio_offset
+is past the offset maximum for
+.Fa iocb->aio_fildes ,
+no I/O will occur.
+.Sh RETURN VALUES
+.Rv -std aio_read
+.Sh DIAGNOSTICS
+None.
+.Sh ERRORS
+The
+.Fn aio_read
+system call will fail if:
+.Bl -tag -width Er
+.It Bq Er EAGAIN
+The request was not queued because of system resource limitations.
+.It Bq Er EINVAL
+The asynchronous notification method in
+.Fa iocb->aio_sigevent.sigev_notify
+is invalid or not supported.
+.It Bq Er EOPNOTSUPP
+Asynchronous read operations on the file descriptor
+.Fa iocb->aio_fildes
+are unsafe and unsafe asynchronous I/O operations are disabled.
+.El
+.Pp
+The following conditions may be synchronously detected when the
+.Fn aio_read
+system call is made, or asynchronously, at any time thereafter.
+If they
+are detected at call time,
+.Fn aio_read
+returns -1 and sets
+.Va errno
+appropriately; otherwise the
+.Fn aio_return
+system call must be called, and will return -1, and
+.Fn aio_error
+must be called to determine the actual value that would have been
+returned in
+.Va errno .
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa iocb->aio_fildes
+argument
+is invalid.
+.It Bq Er EINVAL
+The offset
+.Fa iocb->aio_offset
+is not valid, the priority specified by
+.Fa iocb->aio_reqprio
+is not a valid priority, or the number of bytes specified by
+.Fa iocb->aio_nbytes
+is not valid.
+.It Bq Er EOVERFLOW
+The file is a regular file,
+.Fa iocb->aio_nbytes
+is greater than zero, the starting offset in
+.Fa iocb->aio_offset
+is before the end of the file, but is at or beyond the
+.Fa iocb->aio_fildes
+offset maximum.
+.El
+.Pp
+If the request is successfully enqueued, but subsequently cancelled
+or an error occurs, the value returned by the
+.Fn aio_return
+system call is per the
+.Xr read 2
+system call, and the value returned by the
+.Fn aio_error
+system call is either one of the error returns from the
+.Xr read 2
+system call, or one of:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa iocb->aio_fildes
+argument
+is invalid for reading.
+.It Bq Er ECANCELED
+The request was explicitly cancelled via a call to
+.Fn aio_cancel .
+.It Bq Er EINVAL
+The offset
+.Fa iocb->aio_offset
+would be invalid.
+.El
+.Sh SEE ALSO
+.Xr aio_cancel 2 ,
+.Xr aio_error 2 ,
+.Xr aio_return 2 ,
+.Xr aio_suspend 2 ,
+.Xr aio_waitcomplete 2 ,
+.Xr aio_write 2 ,
+.Xr sigevent 3 ,
+.Xr siginfo 3 ,
+.Xr aio 4
+.Sh STANDARDS
+The
+.Fn aio_read
+system call is expected to conform to the
+.St -p1003.1
+standard.
+.Sh HISTORY
+The
+.Fn aio_read
+system call first appeared in
+.Fx 3.0 .
+.Sh AUTHORS
+This
+manual page was written by
+.An Terry Lambert Aq Mt terry@whistle.com .
+.Sh BUGS
+Invalid information in
+.Fa iocb->_aiocb_private
+may confuse the kernel.
diff --git a/lib/libc/sys/aio_return.2 b/lib/libc/sys/aio_return.2
new file mode 100644
index 000000000000..df558734ed41
--- /dev/null
+++ b/lib/libc/sys/aio_return.2
@@ -0,0 +1,102 @@
+.\" Copyright (c) 1999 Softweyr LLC.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY Softweyr LLC AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL Softweyr LLC OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 March 21, 2016
+.Dt AIO_RETURN 2
+.Os
+.Sh NAME
+.Nm aio_return
+.Nd retrieve return status of asynchronous I/O operation (REALTIME)
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In aio.h
+.Ft ssize_t
+.Fn aio_return "struct aiocb *iocb"
+.Sh DESCRIPTION
+The
+.Fn aio_return
+system call returns the final status of the asynchronous I/O request
+associated with the structure pointed to by
+.Fa iocb .
+.Pp
+The
+.Fn aio_return
+system call
+should only be called once, to obtain the final status of an asynchronous
+I/O operation once it has completed
+.Xr ( aio_error 2
+returns something other than
+.Er EINPROGRESS ) .
+.Sh RETURN VALUES
+If the asynchronous I/O request has completed, the status is returned
+as described in
+.Xr read 2 ,
+.Xr write 2 ,
+or
+.Xr fsync 2 .
+Otherwise,
+.Fn aio_return
+returns \-1 and sets
+.Va errno
+to indicate the error condition.
+.Sh ERRORS
+The
+.Fn aio_return
+system call will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa iocb
+argument
+does not reference a completed asynchronous I/O request.
+.El
+.Sh SEE ALSO
+.Xr aio_cancel 2 ,
+.Xr aio_error 2 ,
+.Xr aio_suspend 2 ,
+.Xr aio_waitcomplete 2 ,
+.Xr aio_write 2 ,
+.Xr fsync 2 ,
+.Xr read 2 ,
+.Xr write 2 ,
+.Xr aio 4
+.Sh STANDARDS
+The
+.Fn aio_return
+system call
+is expected to conform to the
+.St -p1003.1
+standard.
+.Sh HISTORY
+The
+.Fn aio_return
+system call first appeared in
+.Fx 3.0 .
+.Sh AUTHORS
+This
+manual page was written by
+.An Wes Peters Aq Mt wes@softweyr.com .
diff --git a/lib/libc/sys/aio_suspend.2 b/lib/libc/sys/aio_suspend.2
new file mode 100644
index 000000000000..0ff25f51c5ab
--- /dev/null
+++ b/lib/libc/sys/aio_suspend.2
@@ -0,0 +1,117 @@
+.\" Copyright (c) 1999 Softweyr LLC.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY Softweyr LLC AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL Softweyr LLC OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd June 2, 1999
+.Dt AIO_SUSPEND 2
+.Os
+.Sh NAME
+.Nm aio_suspend
+.Nd suspend until asynchronous I/O operations or timeout complete (REALTIME)
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In aio.h
+.Ft int
+.Fn aio_suspend "const struct aiocb *const iocbs[]" "int niocb" "const struct timespec *timeout"
+.Sh DESCRIPTION
+The
+.Fn aio_suspend
+system call suspends the calling process until at least one of the
+specified asynchronous I/O requests have completed, a signal is
+delivered, or the
+.Fa timeout
+has passed.
+.Pp
+The
+.Fa iocbs
+argument
+is an array of
+.Fa niocb
+pointers to asynchronous I/O requests.
+Array members containing
+null pointers will be silently ignored.
+.Pp
+If
+.Fa timeout
+is not a null pointer, it specifies a maximum interval to suspend.
+If
+.Fa timeout
+is a null pointer, the suspend blocks indefinitely.
+To effect a
+poll, the
+.Fa timeout
+should point to a zero-value timespec structure.
+.Sh RETURN VALUES
+If one or more of the specified asynchronous I/O requests have
+completed,
+.Fn aio_suspend
+returns 0.
+Otherwise it returns -1 and sets
+.Va errno
+to indicate the error, as enumerated below.
+.Sh ERRORS
+The
+.Fn aio_suspend
+system call will fail if:
+.Bl -tag -width Er
+.It Bq Er EAGAIN
+the
+.Fa timeout
+expired before any I/O requests completed.
+.It Bq Er EINVAL
+The
+.Fa iocbs
+argument
+contains more than
+.Dv AIO_LISTIO_MAX
+asynchronous I/O requests, or at least one of the requests is not
+valid.
+.It Bq Er EINTR
+the suspend was interrupted by a signal.
+.El
+.Sh SEE ALSO
+.Xr aio_cancel 2 ,
+.Xr aio_error 2 ,
+.Xr aio_return 2 ,
+.Xr aio_waitcomplete 2 ,
+.Xr aio_write 2 ,
+.Xr aio 4
+.Sh STANDARDS
+The
+.Fn aio_suspend
+system call
+is expected to conform to the
+.St -p1003.1
+standard.
+.Sh HISTORY
+The
+.Fn aio_suspend
+system call first appeared in
+.Fx 3.0 .
+.Sh AUTHORS
+This
+manual page was written by
+.An Wes Peters Aq Mt wes@softweyr.com .
diff --git a/lib/libc/sys/aio_suspend.c b/lib/libc/sys/aio_suspend.c
new file mode 100644
index 000000000000..020edf8a74fa
--- /dev/null
+++ b/lib/libc/sys/aio_suspend.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2014 The FreeBSD Foundation.
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Konstantin Belousov
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice(s), this list of conditions and the following disclaimer as
+ * the first lines of this file unmodified other than the possible
+ * addition of one or more copyright notices.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice(s), this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/aio.h>
+#include "libc_private.h"
+
+__weak_reference(__sys_aio_suspend, __aio_suspend);
+
+#pragma weak aio_suspend
+int
+aio_suspend(const struct aiocb * const iocbs[], int niocb,
+ const struct timespec *timeout)
+{
+
+ return (((int (*)(const struct aiocb * const[], int,
+ const struct timespec *))
+ __libc_interposing[INTERPOS_aio_suspend])(iocbs, niocb, timeout));
+}
diff --git a/lib/libc/sys/aio_waitcomplete.2 b/lib/libc/sys/aio_waitcomplete.2
new file mode 100644
index 000000000000..66e7208d7b48
--- /dev/null
+++ b/lib/libc/sys/aio_waitcomplete.2
@@ -0,0 +1,137 @@
+.\" Copyright (c) 1999 Christopher M Sedore.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 March 21, 2016
+.Dt AIO_WAITCOMPLETE 2
+.Os
+.Sh NAME
+.Nm aio_waitcomplete
+.Nd wait for the next completion of an aio request
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In aio.h
+.Ft ssize_t
+.Fn aio_waitcomplete "struct aiocb **iocbp" "struct timespec *timeout"
+.Sh DESCRIPTION
+The
+.Fn aio_waitcomplete
+system call waits for completion of an asynchronous I/O request.
+Upon completion,
+.Fn aio_waitcomplete
+returns the result of the function and sets
+.Fa iocbp
+to point to the structure associated with the original request.
+If an asynchronous I/O request is completed before
+.Fn aio_waitcomplete
+is called, it returns immediately with the completed request.
+.Pp
+If
+.Fa timeout
+is a non-NULL pointer, it specifies a maximum interval to wait for a
+asynchronous I/O request to complete.
+If
+.Fa timeout
+is a NULL pointer,
+.Fn aio_waitcomplete
+waits indefinitely.
+To effect a poll, the
+.Fa timeout
+argument should be non-NULL, pointing to a zero-valued timeval structure.
+.Pp
+The
+.Fn aio_waitcomplete
+system call also serves the function of
+.Fn aio_return ,
+thus
+.Fn aio_return
+should not be called for the control block returned in
+.Fa iocbp .
+.Sh RETURN VALUES
+If an asynchronous I/O request has completed,
+.Fa iocbp
+is set to point to the control block passed with the original request,
+and the status is returned as described in
+.Xr read 2 ,
+.Xr write 2 ,
+or
+.Xr fsync 2 .
+On failure,
+.Fn aio_waitcomplete
+returns
+.Dv -1 ,
+sets iocbp to
+.Dv NULL
+and sets
+.Va errno
+to indicate the error condition.
+.Sh ERRORS
+The
+.Fn aio_waitcomplete
+system call fails if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The specified time limit is invalid.
+.It Bq Er EAGAIN
+The process has not yet called
+.Fn aio_read
+or
+.Fn aio_write .
+.It Bq Er EINTR
+A signal was delivered before the timeout expired and before any
+asynchronous I/O requests completed.
+.It Bq Er EWOULDBLOCK
+.It Bq Er EINPROGRESS
+The specified time limit expired before any asynchronous I/O requests
+completed.
+.El
+.Sh SEE ALSO
+.Xr aio_cancel 2 ,
+.Xr aio_error 2 ,
+.Xr aio_read 2 ,
+.Xr aio_return 2 ,
+.Xr aio_suspend 2 ,
+.Xr aio_write 2 ,
+.Xr fsync 2 ,
+.Xr read 2 ,
+.Xr write 2 ,
+.Xr aio 4
+.Sh STANDARDS
+The
+.Fn aio_waitcomplete
+system call is a
+.Fx Ns -specific
+extension.
+.Sh HISTORY
+The
+.Fn aio_waitcomplete
+system call first appeared in
+.Fx 4.0 .
+.Sh AUTHORS
+The
+.Fn aio_waitcomplete
+system call and this manual page were written by
+.An Christopher M Sedore Aq Mt cmsedore@maxwell.syr.edu .
diff --git a/lib/libc/sys/aio_write.2 b/lib/libc/sys/aio_write.2
new file mode 100644
index 000000000000..a3268e50ea90
--- /dev/null
+++ b/lib/libc/sys/aio_write.2
@@ -0,0 +1,217 @@
+.\" Copyright (c) 1999 Softweyr LLC.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY Softweyr LLC AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL Softweyr LLC OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 August 19, 2016
+.Dt AIO_WRITE 2
+.Os
+.Sh NAME
+.Nm aio_write
+.Nd asynchronous write to a file (REALTIME)
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In aio.h
+.Ft int
+.Fn aio_write "struct aiocb *iocb"
+.Sh DESCRIPTION
+The
+.Fn aio_write
+system call allows the calling process to write
+.Fa iocb->aio_nbytes
+from the buffer pointed to by
+.Fa iocb->aio_buf
+to the descriptor
+.Fa iocb->aio_fildes .
+The call returns immediately after the write request has been enqueued
+to the descriptor; the write may or may not have completed at the time
+the call returns.
+If the request could not be enqueued, generally due
+to invalid arguments, the call returns without having enqueued the
+request.
+.Pp
+If
+.Dv O_APPEND
+is set for
+.Fa iocb->aio_fildes ,
+.Fn aio_write
+operations append to the file in the same order as the calls were
+made.
+If
+.Dv O_APPEND
+is not set for the file descriptor, the write operation will occur at
+the absolute position from the beginning of the file plus
+.Fa iocb->aio_offset .
+.Pp
+If
+.Dv _POSIX_PRIORITIZED_IO
+is defined, and the descriptor supports it, then the enqueued
+operation is submitted at a priority equal to that of the calling
+process minus
+.Fa iocb->aio_reqprio .
+.Pp
+The
+.Fa iocb
+pointer may be subsequently used as an argument to
+.Fn aio_return
+and
+.Fn aio_error
+in order to determine return or error status for the enqueued operation
+while it is in progress.
+.Pp
+If the request is successfully enqueued, the value of
+.Fa iocb->aio_offset
+can be modified during the request as context, so this value must not
+be referenced after the request is enqueued.
+.Pp
+The
+.Fa iocb->aio_sigevent
+structure can be used to request notification of the operation's
+completion as described in
+.Xr aio 4 .
+.Sh RESTRICTIONS
+The Asynchronous I/O Control Block structure pointed to by
+.Fa iocb
+and the buffer that the
+.Fa iocb->aio_buf
+member of that structure references must remain valid until the
+operation has completed.
+.Pp
+The asynchronous I/O control buffer
+.Fa iocb
+should be zeroed before the
+.Fn aio_write
+system call to avoid passing bogus context information to the kernel.
+.Pp
+Modifications of the Asynchronous I/O Control Block structure or the
+buffer contents are not allowed while the request is queued.
+.Pp
+If the file offset in
+.Fa iocb->aio_offset
+is past the offset maximum for
+.Fa iocb->aio_fildes ,
+no I/O will occur.
+.Sh RETURN VALUES
+.Rv -std aio_write
+.Sh ERRORS
+The
+.Fn aio_write
+system call will fail if:
+.Bl -tag -width Er
+.It Bq Er EAGAIN
+The request was not queued because of system resource limitations.
+.It Bq Er EINVAL
+The asynchronous notification method in
+.Fa iocb->aio_sigevent.sigev_notify
+is invalid or not supported.
+.It Bq Er EOPNOTSUPP
+Asynchronous write operations on the file descriptor
+.Fa iocb->aio_fildes
+are unsafe and unsafe asynchronous I/O operations are disabled.
+.El
+.Pp
+The following conditions may be synchronously detected when the
+.Fn aio_write
+system call is made, or asynchronously, at any time thereafter.
+If they
+are detected at call time,
+.Fn aio_write
+returns -1 and sets
+.Va errno
+appropriately; otherwise the
+.Fn aio_return
+system call must be called, and will return -1, and
+.Fn aio_error
+must be called to determine the actual value that would have been
+returned in
+.Va errno .
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa iocb->aio_fildes
+argument
+is invalid, or is not opened for writing.
+.It Bq Er EINVAL
+The offset
+.Fa iocb->aio_offset
+is not valid, the priority specified by
+.Fa iocb->aio_reqprio
+is not a valid priority, or the number of bytes specified by
+.Fa iocb->aio_nbytes
+is not valid.
+.El
+.Pp
+If the request is successfully enqueued, but subsequently canceled
+or an error occurs, the value returned by the
+.Fn aio_return
+system call is per the
+.Xr write 2
+system call, and the value returned by the
+.Fn aio_error
+system call is either one of the error returns from the
+.Xr write 2
+system call, or one of:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa iocb->aio_fildes
+argument
+is invalid for writing.
+.It Bq Er ECANCELED
+The request was explicitly canceled via a call to
+.Fn aio_cancel .
+.It Bq Er EINVAL
+The offset
+.Fa iocb->aio_offset
+would be invalid.
+.El
+.Sh SEE ALSO
+.Xr aio_cancel 2 ,
+.Xr aio_error 2 ,
+.Xr aio_return 2 ,
+.Xr aio_suspend 2 ,
+.Xr aio_waitcomplete 2 ,
+.Xr sigevent 3 ,
+.Xr siginfo 3 ,
+.Xr aio 4
+.Sh STANDARDS
+The
+.Fn aio_write
+system call
+is expected to conform to the
+.St -p1003.1
+standard.
+.Sh HISTORY
+The
+.Fn aio_write
+system call first appeared in
+.Fx 3.0 .
+.Sh AUTHORS
+This manual page was written by
+.An Wes Peters Aq Mt wes@softweyr.com .
+.Sh BUGS
+Invalid information in
+.Fa iocb->_aiocb_private
+may confuse the kernel.
diff --git a/lib/libc/sys/bind.2 b/lib/libc/sys/bind.2
new file mode 100644
index 000000000000..065a38165e9b
--- /dev/null
+++ b/lib/libc/sys/bind.2
@@ -0,0 +1,139 @@
+.\" Copyright (c) 1983, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)bind.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd August 18, 2016
+.Dt BIND 2
+.Os
+.Sh NAME
+.Nm bind
+.Nd assign a local protocol address to a socket
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/socket.h
+.Ft int
+.Fn bind "int s" "const struct sockaddr *addr" "socklen_t addrlen"
+.Sh DESCRIPTION
+The
+.Fn bind
+system call
+assigns the local protocol address to a socket.
+When a socket is created
+with
+.Xr socket 2
+it exists in an address family space but has no protocol address assigned.
+The
+.Fn bind
+system call requests that
+.Fa addr
+be assigned to the socket.
+.Sh NOTES
+Binding an address in the UNIX domain creates a socket in the file
+system that must be deleted by the caller when it is no longer
+needed (using
+.Xr unlink 2 ) .
+.Pp
+The rules used in address binding vary between communication domains.
+Consult the manual entries in section 4 for detailed information.
+.Pp
+For maximum portability, you should always zero the socket address structure
+before populating it and passing it to
+.Fn bind .
+.Sh RETURN VALUES
+.Rv -std bind
+.Sh ERRORS
+The
+.Fn bind
+system call will fail if:
+.Bl -tag -width Er
+.It Bq Er EAGAIN
+Kernel resources to complete the request are
+temporarily unavailable.
+.It Bq Er EBADF
+The
+.Fa s
+argument
+is not a valid descriptor.
+.It Bq Er EINVAL
+The socket is already bound to an address, and the protocol does not support
+binding to a new address; or the socket has been shut down.
+.It Bq Er EINVAL
+The
+.Fa addrlen
+argument is not a valid length for the address family.
+.It Bq Er ENOTSOCK
+The
+.Fa s
+argument
+is not a socket.
+.It Bq Er EADDRNOTAVAIL
+The specified address is not available from the local machine.
+.It Bq Er EADDRINUSE
+The specified address is already in use.
+.It Bq Er EAFNOSUPPORT
+Addresses in the specified address family cannot be used with this socket.
+.It Bq Er EACCES
+The requested address is protected, and the current user
+has inadequate permission to access it.
+.It Bq Er EFAULT
+The
+.Fa addr
+argument is not in a valid part of the user
+address space.
+.El
+.Pp
+The following errors are specific to binding addresses in the UNIX domain.
+.Bl -tag -width EADDRNOTAVA
+.It Bq Er ENOTDIR
+A component of the path prefix is not a directory.
+.It Bq Er ENAMETOOLONG
+A component of a pathname exceeded 255 characters,
+or an entire path name exceeded 1023 characters.
+.It Bq Er ENOENT
+A prefix component of the path name does not exist.
+.It Bq Er ELOOP
+Too many symbolic links were encountered in translating the pathname.
+.It Bq Er EIO
+An I/O error occurred while making the directory entry or allocating the inode.
+.It Bq Er EROFS
+The name would reside on a read-only file system.
+.It Bq Er EISDIR
+An empty pathname was specified.
+.El
+.Sh SEE ALSO
+.Xr connect 2 ,
+.Xr getsockname 2 ,
+.Xr listen 2 ,
+.Xr socket 2
+.Sh HISTORY
+The
+.Fn bind
+system call appeared in
+.Bx 4.2 .
diff --git a/lib/libc/sys/bindat.2 b/lib/libc/sys/bindat.2
new file mode 100644
index 000000000000..692099092d6c
--- /dev/null
+++ b/lib/libc/sys/bindat.2
@@ -0,0 +1,109 @@
+.\" Copyright (c) 2013 The FreeBSD Foundation
+.\" All rights reserved.
+.\"
+.\" This documentation was written 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$
+.\"
+.Dd February 13, 2013
+.Dt BINDAT 2
+.Os
+.Sh NAME
+.Nm bindat
+.Nd assign a local protocol address to a socket
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/socket.h
+.Pp
+.In fcntl.h
+.Ft int
+.Fn bindat "int fd" "int s" "const struct sockaddr *addr" "socklen_t addrlen"
+.Sh DESCRIPTION
+The
+.Fn bindat
+system call assigns the local protocol address to a socket.
+It works just like the
+.Xr bind 2
+system call with two exceptions:
+.Pp
+.Bl -enum -offset indent -compact
+.It
+It is limited to sockets in the PF_LOCAL domain.
+.Pp
+.It
+If the file path stored in the
+.Fa sun_path
+field of the sockaddr_un structure is a relative path, it is located relative
+to the directory associated with the file descriptor
+.Fa fd .
+If
+.Fn bindat
+is passed the special value
+.Dv AT_FDCWD
+in the
+.Fa fd
+parameter, the current working directory is used and the behavior is identical
+to a call to
+.Xr bind 2 .
+.El
+.Sh RETURN VALUES
+.Rv -std bindat
+.Sh ERRORS
+The
+.Fn bindat
+system call may fail with the same errors as the
+.Xr bind 2
+system call for a UNIX domain socket or with the following errors:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa sun_path
+field does not specify an absolute path and the
+.Fa fd
+argument is neither
+.Dv AT_FDCWD
+nor a valid file descriptor.
+.It Bq Er ENOTDIR
+The
+.Fa sun_path
+field is not an absolute path and
+.Fa fd
+is neither
+.Dv AT_FDCWD
+nor a file descriptor associated with a directory.
+.El
+.Sh SEE ALSO
+.Xr bind 2 ,
+.Xr connectat 2 ,
+.Xr socket 2 ,
+.Xr unix 4
+.Sh AUTHORS
+The
+.Nm
+was developed by
+.An Pawel Jakub Dawidek Aq Mt pawel@dawidek.net
+under sponsorship from the FreeBSD Foundation.
diff --git a/lib/libc/sys/brk.2 b/lib/libc/sys/brk.2
new file mode 100644
index 000000000000..0a529ee3a99a
--- /dev/null
+++ b/lib/libc/sys/brk.2
@@ -0,0 +1,170 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)brk.2 8.4 (Berkeley) 5/1/95
+.\" $FreeBSD$
+.\"
+.Dd December 15, 2015
+.Dt BRK 2
+.Os
+.Sh NAME
+.Nm brk ,
+.Nm sbrk
+.Nd change data segment size
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft int
+.Fn brk "const void *addr"
+.Ft void *
+.Fn sbrk "intptr_t incr"
+.Sh DESCRIPTION
+.Bf -symbolic
+The
+.Fn brk
+and
+.Fn sbrk
+functions are legacy interfaces from before the
+advent of modern virtual memory management.
+.Ef
+.Pp
+The
+.Fn brk
+and
+.Fn sbrk
+functions are used to change the amount of memory allocated in a
+process's data segment.
+They do this by moving the location of the
+.Dq break .
+The break is the first address after the end of the process's
+uninitialized data segment (also known as the
+.Dq BSS ) .
+.Pp
+The
+.Fn brk
+function
+sets the break to
+.Fa addr .
+.Pp
+The
+.Fn sbrk
+function raises the break by
+.Fa incr
+bytes, thus allocating at least
+.Fa incr
+bytes of new memory in the data segment.
+If
+.Fa incr
+is negative,
+the break is lowered by
+.Fa incr
+bytes.
+.Sh NOTES
+While the actual process data segment size maintained by the kernel will only
+grow or shrink in page sizes, these functions allow setting the break
+to unaligned values (i.e., it may point to any address inside the last
+page of the data segment).
+.Pp
+The current value of the program break may be determined by calling
+.Fn sbrk 0 .
+See also
+.Xr end 3 .
+.Pp
+The
+.Xr getrlimit 2
+system call may be used to determine
+the maximum permissible size of the
+data segment.
+It will not be possible to set the break
+beyond
+.Dq Va etext No + Va rlim.rlim_max
+where the
+.Va rlim.rlim_max
+value is returned from a call to
+.Fn getrlimit RLIMIT_DATA &rlim .
+(See
+.Xr end 3
+for the definition of
+.Va etext ) .
+.Sh RETURN VALUES
+.Rv -std brk
+.Pp
+The
+.Fn sbrk
+function returns the prior break value if successful;
+otherwise the value
+.Po Vt "void *" Pc Ns \-1
+is returned and the global variable
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+The
+.Fn brk
+and
+.Fn sbrk
+functions
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The requested break value was beyond the beginning of the data segment.
+.It Bq Er ENOMEM
+The data segment size limit, as set by
+.Xr setrlimit 2 ,
+was exceeded.
+.It Bq Er ENOMEM
+Insufficient space existed in the swap area
+to support the expansion of the data segment.
+.El
+.Sh SEE ALSO
+.Xr execve 2 ,
+.Xr getrlimit 2 ,
+.Xr mmap 2 ,
+.Xr end 3 ,
+.Xr free 3 ,
+.Xr malloc 3
+.Sh HISTORY
+The
+.Fn brk
+function appeared in
+.At v7 .
+.Sh BUGS
+Mixing
+.Fn brk
+or
+.Fn sbrk
+with
+.Xr malloc 3 ,
+.Xr free 3 ,
+or similar functions will result in non-portable program behavior.
+.Pp
+Setting the break may fail due to a temporary lack of
+swap space.
+It is not possible to distinguish this
+from a failure caused by exceeding the maximum size of
+the data segment without consulting
+.Xr getrlimit 2 .
diff --git a/lib/libc/sys/cap_enter.2 b/lib/libc/sys/cap_enter.2
new file mode 100644
index 000000000000..c1d1e20a751a
--- /dev/null
+++ b/lib/libc/sys/cap_enter.2
@@ -0,0 +1,160 @@
+.\"
+.\" Copyright (c) 2008-2009 Robert N. M. Watson
+.\" All rights reserved.
+.\"
+.\" This software was developed at the University of Cambridge Computer
+.\" Laboratory with support from a grant from Google, Inc.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 September 27, 2016
+.Dt CAP_ENTER 2
+.Os
+.Sh NAME
+.Nm cap_enter ,
+.Nm cap_getmode
+.Nd Capability mode system calls
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/capsicum.h
+.Ft int
+.Fn cap_enter "void"
+.Ft int
+.Fn cap_getmode "u_int *modep"
+.Sh DESCRIPTION
+.Fn cap_enter
+places the current process into capability mode, a mode of execution in which
+processes may only issue system calls operating on file descriptors or
+reading limited global system state.
+Access to global name spaces, such as file system or IPC name spaces, is
+prevented.
+If the process is already in a capability mode sandbox, the system call is a
+no-op.
+Future process descendants created with
+.Xr fork 2
+or
+.Xr pdfork 2
+will be placed in capability mode from inception.
+.Pp
+When combined with
+.Xr cap_rights_limit 2 ,
+.Xr cap_ioctls_limit 2 ,
+.Xr cap_fcntls_limit 2 ,
+.Fn cap_enter
+may be used to create kernel-enforced sandboxes in which
+appropriately-crafted applications or application components may be run.
+.Pp
+.Fn cap_getmode
+returns a flag indicating whether or not the process is in a capability mode
+sandbox.
+.Sh RUN-TIME SETTINGS
+If the
+.Dv kern.trap_enocap
+sysctl MIB is set to a non-zero value, then for any process executing in a
+capability mode sandbox, any syscall which results in either an
+.Er ENOTCAPABLE
+or
+.Er ECAPMODE
+error also generates the synchronous
+.Dv SIGTRAP
+signal to the thread on the syscall return.
+On signal delivery, the
+.Va si_errno
+member of the
+.Fa siginfo
+signal handler parameter is set to the syscall error value,
+and the
+.Va si_code
+member is set to
+.Dv TRAP_CAP .
+.Pp
+See also the
+.Dv PROC_TRAPCAP_CTL
+and
+.Dv PROC_TRAPCAP_STATUS
+operations of the
+.Xr procctl 2
+function for similar per-process functionality.
+.Sh CAVEAT
+Creating effective process sandboxes is a tricky process that involves
+identifying the least possible rights required by the process and then
+passing those rights into the process in a safe manner.
+Consumers of
+.Fn cap_enter
+should also be aware of other inherited rights, such as access to VM
+resources, memory contents, and other process properties that should be
+considered.
+It is advisable to use
+.Xr fexecve 2
+to create a runtime environment inside the sandbox that has as few implicitly
+acquired rights as possible.
+.Sh RETURN VALUES
+.Rv -std cap_enter cap_getmode
+.Pp
+When the process is in capability mode,
+.Fn cap_getmode
+sets the flag to a non-zero value.
+A zero value means the process is not in capability mode.
+.Sh ERRORS
+The
+.Fn cap_enter
+and
+.Fn cap_getmode
+system calls
+will fail if:
+.Bl -tag -width Er
+.It Bq Er ENOSYS
+The kernel is compiled without:
+.Pp
+.Cd "options CAPABILITY_MODE"
+.El
+.Pp
+The
+.Fn cap_getmode
+system call may also return the following error:
+.Bl -tag -width Er
+.It Bq Er EFAULT
+Pointer
+.Fa modep
+points outside the process's allocated address space.
+.El
+.Sh SEE ALSO
+.Xr cap_fcntls_limit 2 ,
+.Xr cap_ioctls_limit 2 ,
+.Xr cap_rights_limit 2 ,
+.Xr procctl 2 ,
+.Xr sysctl 2 ,
+.Xr fexecve 2 ,
+.Xr cap_sandboxed 3 ,
+.Xr capsicum 4
+.Sh HISTORY
+Support for capabilities and capabilities mode was developed as part of the
+.Tn TrustedBSD
+Project.
+.Sh AUTHORS
+These functions and the capability facility were created by
+.An "Robert N. M. Watson"
+at the University of Cambridge Computer Laboratory with support from a grant
+from Google, Inc.
diff --git a/lib/libc/sys/cap_fcntls_limit.2 b/lib/libc/sys/cap_fcntls_limit.2
new file mode 100644
index 000000000000..193d97da37eb
--- /dev/null
+++ b/lib/libc/sys/cap_fcntls_limit.2
@@ -0,0 +1,126 @@
+.\"
+.\" Copyright (c) 2012 The FreeBSD Foundation
+.\" All rights reserved.
+.\"
+.\" This documentation was written by Pawel Jakub Dawidek under sponsorship
+.\" 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd March 27, 2014
+.Dt CAP_FCNTLS_LIMIT 2
+.Os
+.Sh NAME
+.Nm cap_fcntls_limit ,
+.Nm cap_fcntls_get
+.Nd manage allowed fcntl commands
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/capsicum.h
+.Ft int
+.Fn cap_fcntls_limit "int fd" "uint32_t fcntlrights"
+.Ft int
+.Fn cap_fcntls_get "int fd" "uint32_t *fcntlrightsp"
+.Sh DESCRIPTION
+If a file descriptor is granted the
+.Dv CAP_FCNTL
+capability right, the list of allowed
+.Xr fcntl 2
+commands can be selectively reduced (but never expanded) with the
+.Fn cap_fcntls_limit
+system call.
+.Pp
+A bitmask of allowed fcntls commands for a given file descriptor can be obtained
+with the
+.Fn cap_fcntls_get
+system call.
+.Sh FLAGS
+The following flags may be specified in the
+.Fa fcntlrights
+argument or returned in the
+.Fa fcntlrightsp
+argument:
+.Bl -tag -width CAP_FCNTL_GETOWN
+.It Dv CAP_FCNTL_GETFL
+Permit
+.Dv F_GETFL
+command.
+.It Dv CAP_FCNTL_SETFL
+Permit
+.Dv F_SETFL
+command.
+.It Dv CAP_FCNTL_GETOWN
+Permit
+.Dv F_GETOWN
+command.
+.It Dv CAP_FCNTL_SETOWN
+Permit
+.Dv F_SETOWN
+command.
+.El
+.Sh RETURN VALUES
+.Rv -std
+.Sh ERRORS
+.Fn cap_fcntls_limit
+succeeds unless:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa fd
+argument is not a valid descriptor.
+.It Bq Er EINVAL
+An invalid flag has been passed in
+.Fa fcntlrights .
+.It Bq Er ENOTCAPABLE
+.Fa fcntlrights
+would expand the list of allowed
+.Xr fcntl 2
+commands.
+.El
+.Pp
+.Fn cap_fcntls_get
+succeeds unless:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa fd
+argument is not a valid descriptor.
+.It Bq Er EFAULT
+The
+.Fa fcntlrightsp
+argument points at an invalid address.
+.El
+.Sh SEE ALSO
+.Xr cap_ioctls_limit 2 ,
+.Xr cap_rights_limit 2 ,
+.Xr fcntl 2
+.Sh HISTORY
+Support for capabilities and capabilities mode was developed as part of the
+.Tn TrustedBSD
+Project.
+.Sh AUTHORS
+This function was created by
+.An Pawel Jakub Dawidek Aq Mt pawel@dawidek.net
+under sponsorship of the FreeBSD Foundation.
diff --git a/lib/libc/sys/cap_ioctls_limit.2 b/lib/libc/sys/cap_ioctls_limit.2
new file mode 100644
index 000000000000..39f117f03087
--- /dev/null
+++ b/lib/libc/sys/cap_ioctls_limit.2
@@ -0,0 +1,159 @@
+.\"
+.\" Copyright (c) 2012 The FreeBSD Foundation
+.\" All rights reserved.
+.\"
+.\" This documentation was written by Pawel Jakub Dawidek under sponsorship
+.\" 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd March 6, 2015
+.Dt CAP_IOCTLS_LIMIT 2
+.Os
+.Sh NAME
+.Nm cap_ioctls_limit ,
+.Nm cap_ioctls_get
+.Nd manage allowed ioctl commands
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/capsicum.h
+.Ft int
+.Fn cap_ioctls_limit "int fd" "const unsigned long *cmds" "size_t ncmds"
+.Ft ssize_t
+.Fn cap_ioctls_get "int fd" "unsigned long *cmds" "size_t maxcmds"
+.Sh DESCRIPTION
+If a file descriptor is granted the
+.Dv CAP_IOCTL
+capability right, the list of allowed
+.Xr ioctl 2
+commands can be selectively reduced (but never expanded) with the
+.Fn cap_ioctls_limit
+system call.
+The
+.Fa cmds
+argument is an array of
+.Xr ioctl 2
+commands and the
+.Fa ncmds
+argument specifies the number of elements in the array.
+There can be up to
+.Va 256
+elements in the array.
+Including an element that has been previously revoked will generate an error.
+After a successful call only those listed in the array may be used.
+.Pp
+The list of allowed ioctl commands for a given file descriptor can be obtained
+with the
+.Fn cap_ioctls_get
+system call.
+The
+.Fa cmds
+argument points at memory that can hold up to
+.Fa maxcmds
+values.
+The function populates the provided buffer with up to
+.Fa maxcmds
+elements, but always returns the total number of ioctl commands allowed for the
+given file descriptor.
+The total number of ioctls commands for the given file descriptor can be
+obtained by passing
+.Dv NULL as the
+.Fa cmds
+argument and
+.Va 0
+as the
+.Fa maxcmds
+argument.
+If all ioctl commands are allowed
+.Dv ( CAP_IOCTL
+capability right is assigned to the file descriptor and the
+.Fn cap_ioctls_limit
+system call was never called for this file descriptor), the
+.Fn cap_ioctls_get
+system call will return
+.Dv CAP_IOCTLS_ALL
+and will not modify the buffer pointed to by the
+.Fa cmds
+argument.
+.Sh RETURN VALUES
+.Rv -std cap_ioctls_limit
+.Pp
+The
+.Fn cap_ioctls_get
+function, if successful, returns the total number of allowed ioctl commands or
+the value
+.Dv CAP_IOCTLS_ALL
+if all ioctls commands are allowed.
+On failure the value
+.Va -1
+is returned and the global variable errno is set to indicate the error.
+.Sh ERRORS
+.Fn cap_ioctls_limit
+succeeds unless:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa fd
+argument is not a valid descriptor.
+.It Bq Er EFAULT
+The
+.Fa cmds
+argument points at an invalid address.
+.It Bq Er EINVAL
+The
+.Fa ncmds
+argument is greater than
+.Va 256 .
+.It Bq Er ENOTCAPABLE
+.Fa cmds
+would expand the list of allowed
+.Xr ioctl 2
+commands.
+.El
+.Pp
+.Fn cap_ioctls_get
+succeeds unless:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa fd
+argument is not a valid descriptor.
+.It Bq Er EFAULT
+The
+.Fa cmds
+argument points at invalid address.
+.El
+.Sh SEE ALSO
+.Xr cap_fcntls_limit 2 ,
+.Xr cap_rights_limit 2 ,
+.Xr ioctl 2
+.Sh HISTORY
+Support for capabilities and capabilities mode was developed as part of the
+.Tn TrustedBSD
+Project.
+.Sh AUTHORS
+This function was created by
+.An Pawel Jakub Dawidek Aq Mt pawel@dawidek.net
+under sponsorship of the FreeBSD Foundation.
diff --git a/lib/libc/sys/cap_rights_limit.2 b/lib/libc/sys/cap_rights_limit.2
new file mode 100644
index 000000000000..4663951e5029
--- /dev/null
+++ b/lib/libc/sys/cap_rights_limit.2
@@ -0,0 +1,157 @@
+.\"
+.\" Copyright (c) 2008-2010 Robert N. M. Watson
+.\" Copyright (c) 2012-2013 The FreeBSD Foundation
+.\" All rights reserved.
+.\"
+.\" This software was developed at the University of Cambridge Computer
+.\" Laboratory with support from a grant from Google, Inc.
+.\"
+.\" Portions of this documentation were written 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 March 27, 2014
+.Dt CAP_RIGHTS_LIMIT 2
+.Os
+.Sh NAME
+.Nm cap_rights_limit
+.Nd limit capability rights
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/capsicum.h
+.Ft int
+.Fn cap_rights_limit "int fd" "const cap_rights_t *rights"
+.Sh DESCRIPTION
+When a file descriptor is created by a function such as
+.Xr accept 2 ,
+.Xr accept4 2 ,
+.Xr fhopen 2 ,
+.Xr kqueue 2 ,
+.Xr mq_open 2 ,
+.Xr open 2 ,
+.Xr openat 2 ,
+.Xr pdfork 2 ,
+.Xr pipe 2 ,
+.Xr shm_open 2 ,
+.Xr socket 2
+or
+.Xr socketpair 2 ,
+it is assigned all capability rights.
+Those rights can be reduced (but never expanded) by using the
+.Fn cap_rights_limit
+system call.
+Once capability rights are reduced, operations on the file descriptor will be
+limited to those permitted by
+.Fa rights .
+.Pp
+The
+.Fa rights
+argument should be prepared using
+.Xr cap_rights_init 3
+family of functions.
+.Pp
+Capability rights assigned to a file descriptor can be obtained with the
+.Xr cap_rights_get 3
+function.
+.Pp
+The complete list of the capability rights can be found in the
+.Xr rights 4
+manual page.
+.Sh RETURN VALUES
+.Rv -std
+.Sh EXAMPLES
+The following example demonstrates how to limit file descriptor capability
+rights to allow reading only.
+.Bd -literal
+cap_rights_t setrights;
+char buf[1];
+int fd;
+
+fd = open("/tmp/foo", O_RDWR);
+if (fd < 0)
+ err(1, "open() failed");
+
+if (cap_enter() < 0)
+ err(1, "cap_enter() failed");
+
+cap_rights_init(&setrights, CAP_READ);
+if (cap_rights_limit(fd, &setrights) < 0)
+ err(1, "cap_rights_limit() failed");
+
+buf[0] = 'X';
+
+if (write(fd, buf, sizeof(buf)) > 0)
+ errx(1, "write() succeeded!");
+
+if (read(fd, buf, sizeof(buf)) < 0)
+ err(1, "read() failed");
+.Ed
+.Sh ERRORS
+.Fn cap_rights_limit
+succeeds unless:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa fd
+argument is not a valid active descriptor.
+.It Bq Er EINVAL
+An invalid right has been requested in
+.Fa rights .
+.It Bq Er ENOTCAPABLE
+The
+.Fa rights
+argument contains capability rights not present for the given file descriptor.
+Capability rights list can only be reduced, never expanded.
+.El
+.Sh SEE ALSO
+.Xr accept 2 ,
+.Xr accept4 2 ,
+.Xr cap_enter 2 ,
+.Xr fhopen 2 ,
+.Xr kqueue 2 ,
+.Xr mq_open 2 ,
+.Xr open 2 ,
+.Xr openat 2 ,
+.Xr pdfork 2 ,
+.Xr pipe 2 ,
+.Xr read 2 ,
+.Xr shm_open 2 ,
+.Xr socket 2 ,
+.Xr socketpair 2 ,
+.Xr write 2 ,
+.Xr cap_rights_get 3 ,
+.Xr cap_rights_init 3 ,
+.Xr err 3 ,
+.Xr capsicum 4 ,
+.Xr rights 4
+.Sh HISTORY
+Support for capabilities and capabilities mode was developed as part of the
+.Tn TrustedBSD
+Project.
+.Sh AUTHORS
+This function was created by
+.An Pawel Jakub Dawidek Aq Mt pawel@dawidek.net
+under sponsorship of the FreeBSD Foundation.
diff --git a/lib/libc/sys/chdir.2 b/lib/libc/sys/chdir.2
new file mode 100644
index 000000000000..33940c39c51d
--- /dev/null
+++ b/lib/libc/sys/chdir.2
@@ -0,0 +1,132 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)chdir.2 8.2 (Berkeley) 12/11/93
+.\" $FreeBSD$
+.\"
+.Dd December 11, 1993
+.Dt CHDIR 2
+.Os
+.Sh NAME
+.Nm chdir ,
+.Nm fchdir
+.Nd change current working directory
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft int
+.Fn chdir "const char *path"
+.Ft int
+.Fn fchdir "int fd"
+.Sh DESCRIPTION
+The
+.Fa path
+argument points to the pathname of a directory.
+The
+.Fn chdir
+system call
+causes the named directory
+to become the current working directory, that is,
+the starting point for path searches of pathnames not beginning with
+a slash,
+.Ql / .
+.Pp
+The
+.Fn fchdir
+system call
+causes the directory referenced by
+.Fa fd
+to become the current working directory,
+the starting point for path searches of pathnames not beginning with
+a slash,
+.Ql / .
+.Pp
+In order for a directory to become the current directory,
+a process must have execute (search) access to the directory.
+.Sh RETURN VALUES
+.Rv -std
+.Sh ERRORS
+The
+.Fn chdir
+system call
+will fail and the current working directory will be unchanged if
+one or more of the following are true:
+.Bl -tag -width Er
+.It Bq Er ENOTDIR
+A component of the path prefix is not a directory.
+.It Bq Er ENAMETOOLONG
+A component of a pathname exceeded 255 characters,
+or an entire path name exceeded 1023 characters.
+.It Bq Er ENOENT
+The named directory does not exist.
+.It Bq Er ELOOP
+Too many symbolic links were encountered in translating the pathname.
+.It Bq Er EACCES
+Search permission is denied for any component of
+the path name.
+.It Bq Er EFAULT
+The
+.Fa path
+argument
+points outside the process's allocated address space.
+.It Bq Er EIO
+An I/O error occurred while reading from or writing to the file system.
+.El
+.Pp
+The
+.Fn fchdir
+system call
+will fail and the current working directory will be unchanged if
+one or more of the following are true:
+.Bl -tag -width Er
+.It Bq Er EACCES
+Search permission is denied for the directory referenced by the
+file descriptor.
+.It Bq Er ENOTDIR
+The file descriptor does not reference a directory.
+.It Bq Er EBADF
+The argument
+.Fa fd
+is not a valid file descriptor.
+.El
+.Sh SEE ALSO
+.Xr chroot 2
+.Sh STANDARDS
+The
+.Fn chdir
+system call is expected to conform to
+.St -p1003.1-90 .
+.Sh HISTORY
+The
+.Fn chdir
+system call appeared in
+.At v7 .
+The
+.Fn fchdir
+system call appeared in
+.Bx 4.2 .
diff --git a/lib/libc/sys/chflags.2 b/lib/libc/sys/chflags.2
new file mode 100644
index 000000000000..8dc14bd8965e
--- /dev/null
+++ b/lib/libc/sys/chflags.2
@@ -0,0 +1,326 @@
+.\" Copyright (c) 1989, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)chflags.2 8.3 (Berkeley) 5/2/95
+.\" $FreeBSD$
+.\"
+.Dd March 22, 2013
+.Dt CHFLAGS 2
+.Os
+.Sh NAME
+.Nm chflags ,
+.Nm lchflags ,
+.Nm fchflags ,
+.Nm chflagsat
+.Nd set file flags
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/stat.h
+.In unistd.h
+.Ft int
+.Fn chflags "const char *path" "unsigned long flags"
+.Ft int
+.Fn lchflags "const char *path" "unsigned long flags"
+.Ft int
+.Fn fchflags "int fd" "unsigned long flags"
+.Ft int
+.Fn chflagsat "int fd" "const char *path" "unsigned long flags" "int atflag"
+.Sh DESCRIPTION
+The file whose name
+is given by
+.Fa path
+or referenced by the descriptor
+.Fa fd
+has its flags changed to
+.Fa flags .
+.Pp
+The
+.Fn lchflags
+system call is like
+.Fn chflags
+except in the case where the named file is a symbolic link,
+in which case
+.Fn lchflags
+will change the flags of the link itself,
+rather than the file it points to.
+.Pp
+The
+.Fn chflagsat
+is equivalent to either
+.Fn chflags
+or
+.Fn lchflags
+depending on the
+.Fa atflag
+except in the case where
+.Fa path
+specifies a relative path.
+In this case the file to be changed is determined relative to the directory
+associated with the file descriptor
+.Fa fd
+instead of the current working directory.
+The values for the
+.Fa atflag
+are constructed by a bitwise-inclusive OR of flags from the following list,
+defined in
+.In fcntl.h :
+.Bl -tag -width indent
+.It Dv AT_SYMLINK_NOFOLLOW
+If
+.Fa path
+names a symbolic link, then the flags of the symbolic link are changed.
+.El
+.Pp
+If
+.Fn chflagsat
+is passed the special value
+.Dv AT_FDCWD
+in the
+.Fa fd
+parameter, the current working directory is used.
+If also
+.Fa atflag
+is zero, the behavior is identical to a call to
+.Fn chflags .
+.Pp
+The flags specified are formed by
+.Em or Ns 'ing
+the following values
+.Pp
+.Bl -tag -width ".Dv SF_IMMUTABLE" -compact -offset indent
+.It Dv SF_APPEND
+The file may only be appended to.
+.It Dv SF_ARCHIVED
+The file has been archived.
+This flag means the opposite of the DOS, Windows and CIFS
+FILE_ATTRIBUTE_ARCHIVE attribute.
+This flag has been deprecated, and may be removed in a future release.
+.It Dv SF_IMMUTABLE
+The file may not be changed.
+.It Dv SF_NOUNLINK
+The file may not be renamed or deleted.
+.It Dv SF_SNAPSHOT
+The file is a snapshot file.
+.It Dv UF_APPEND
+The file may only be appended to.
+.It Dv UF_ARCHIVE
+The file needs to be archived.
+This flag has the same meaning as the DOS, Windows and CIFS
+FILE_ATTRIBUTE_ARCHIVE attribute.
+Filesystems in FreeBSD may or may not have special handling for this flag.
+For instance, ZFS tracks changes to files and will set this bit when a
+file is updated.
+UFS only stores the flag, and relies on the application to change it when
+needed.
+.It Dv UF_HIDDEN
+The file may be hidden from directory listings at the application's
+discretion.
+The file has the DOS, Windows and CIFS FILE_ATTRIBUTE_HIDDEN attribute.
+.It Dv UF_IMMUTABLE
+The file may not be changed.
+.It Dv UF_NODUMP
+Do not dump the file.
+.It Dv UF_NOUNLINK
+The file may not be renamed or deleted.
+.It Dv UF_OFFLINE
+The file is offline, or has the Windows and CIFS FILE_ATTRIBUTE_OFFLINE
+attribute.
+Filesystems in FreeBSD store and display this flag, but do not provide any
+special handling when it is set.
+.It Dv UF_OPAQUE
+The directory is opaque when viewed through a union stack.
+.It Dv UF_READONLY
+The file is read only, and may not be written or appended.
+Filesystems may use this flag to maintain compatibility with the DOS, Windows
+and CIFS FILE_ATTRIBUTE_READONLY attribute.
+.It Dv UF_REPARSE
+The file contains a Windows reparse point and has the Windows and CIFS
+FILE_ATTRIBUTE_REPARSE_POINT attribute.
+.It Dv UF_SPARSE
+The file has the Windows FILE_ATTRIBUTE_SPARSE_FILE attribute.
+This may also be used by a filesystem to indicate a sparse file.
+.It Dv UF_SYSTEM
+The file has the DOS, Windows and CIFS FILE_ATTRIBUTE_SYSTEM attribute.
+Filesystems in FreeBSD may store and display this flag, but do not provide
+any special handling when it is set.
+.El
+.Pp
+If one of
+.Dv SF_IMMUTABLE , SF_APPEND ,
+or
+.Dv SF_NOUNLINK
+is set a non-super-user cannot change any flags and even the super-user
+can change flags only if securelevel is 0.
+(See
+.Xr init 8
+for details.)
+.Pp
+The
+.Dv UF_IMMUTABLE , UF_APPEND , UF_NOUNLINK , UF_NODUMP ,
+and
+.Dv UF_OPAQUE
+flags may be set or unset by either the owner of a file or the super-user.
+.Pp
+The
+.Dv SF_IMMUTABLE , SF_APPEND , SF_NOUNLINK ,
+and
+.Dv SF_ARCHIVED
+flags may only be set or unset by the super-user.
+Attempts to toggle these flags by non-super-users are rejected.
+These flags may be set at any time, but normally may only be unset when
+the system is in single-user mode.
+(See
+.Xr init 8
+for details.)
+.Pp
+The implementation of all flags is filesystem-dependent.
+See the description of the
+.Dv UF_ARCHIVE
+flag above for one example of the differences in behavior.
+Care should be exercised when writing applications to account for
+support or lack of support of these flags in various filesystems.
+.Pp
+The
+.Dv SF_SNAPSHOT
+flag is maintained by the system and cannot be toggled.
+.Sh RETURN VALUES
+.Rv -std
+.Sh ERRORS
+The
+.Fn chflags
+system call will fail if:
+.Bl -tag -width Er
+.It Bq Er ENOTDIR
+A component of the path prefix is not a directory.
+.It Bq Er ENAMETOOLONG
+A component of a pathname exceeded 255 characters,
+or an entire path name exceeded 1023 characters.
+.It Bq Er ENOENT
+The named file does not exist.
+.It Bq Er EACCES
+Search permission is denied for a component of the path prefix.
+.It Bq Er ELOOP
+Too many symbolic links were encountered in translating the pathname.
+.It Bq Er EPERM
+The effective user ID does not match the owner of the file and
+the effective user ID is not the super-user.
+.It Bq Er EPERM
+One of
+.Dv SF_IMMUTABLE , SF_APPEND ,
+or
+.Dv SF_NOUNLINK
+is set and the user is either not the super-user or
+securelevel is greater than 0.
+.It Bq Er EPERM
+A non-super-user attempted to toggle one of
+.Dv SF_ARCHIVED , SF_IMMUTABLE , SF_APPEND ,
+or
+.Dv SF_NOUNLINK .
+.It Bq Er EPERM
+An attempt was made to toggle the
+.Dv SF_SNAPSHOT
+flag.
+.It Bq Er EROFS
+The named file resides on a read-only file system.
+.It Bq Er EFAULT
+The
+.Fa path
+argument
+points outside the process's allocated address space.
+.It Bq Er EIO
+An
+.Tn I/O
+error occurred while reading from or writing to the file system.
+.It Bq Er EOPNOTSUPP
+The underlying file system does not support file flags, or
+does not support all of the flags set in
+.Fa flags .
+.El
+.Pp
+The
+.Fn fchflags
+system call will fail if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The descriptor is not valid.
+.It Bq Er EINVAL
+The
+.Fa fd
+argument
+refers to a socket, not to a file.
+.It Bq Er EPERM
+The effective user ID does not match the owner of the file and
+the effective user ID is not the super-user.
+.It Bq Er EPERM
+One of
+.Dv SF_IMMUTABLE , SF_APPEND ,
+or
+.Dv SF_NOUNLINK
+is set and the user is either not the super-user or
+securelevel is greater than 0.
+.It Bq Er EPERM
+A non-super-user attempted to toggle one of
+.Dv SF_ARCHIVED , SF_IMMUTABLE , SF_APPEND ,
+or
+.Dv SF_NOUNLINK .
+.It Bq Er EPERM
+An attempt was made to toggle the
+.Dv SF_SNAPSHOT
+flag.
+.It Bq Er EROFS
+The file resides on a read-only file system.
+.It Bq Er EIO
+An
+.Tn I/O
+error occurred while reading from or writing to the file system.
+.It Bq Er EOPNOTSUPP
+The underlying file system does not support file flags, or
+does not support all of the flags set in
+.Fa flags .
+.El
+.Sh SEE ALSO
+.Xr chflags 1 ,
+.Xr fflagstostr 3 ,
+.Xr strtofflags 3 ,
+.Xr init 8 ,
+.Xr mount_unionfs 8
+.Sh HISTORY
+The
+.Fn chflags
+and
+.Fn fchflags
+system calls first appeared in
+.Bx 4.4 .
+The
+.Fn lchflags
+system call first appeared in
+.Fx 5.0 .
+The
+.Fn chflagsat
+system call first appeared in
+.Fx 10.0 .
diff --git a/lib/libc/sys/chmod.2 b/lib/libc/sys/chmod.2
new file mode 100644
index 000000000000..332cf3a132fa
--- /dev/null
+++ b/lib/libc/sys/chmod.2
@@ -0,0 +1,327 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)chmod.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd December 1, 2013
+.Dt CHMOD 2
+.Os
+.Sh NAME
+.Nm chmod ,
+.Nm fchmod ,
+.Nm lchmod ,
+.Nm fchmodat
+.Nd change mode of file
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/stat.h
+.Ft int
+.Fn chmod "const char *path" "mode_t mode"
+.Ft int
+.Fn fchmod "int fd" "mode_t mode"
+.Ft int
+.Fn lchmod "const char *path" "mode_t mode"
+.Ft int
+.Fn fchmodat "int fd" "const char *path" "mode_t mode" "int flag"
+.Sh DESCRIPTION
+The file permission bits of the file named specified by
+.Fa path
+or referenced by the file descriptor
+.Fa fd
+are changed to
+.Fa mode .
+The
+.Fn chmod
+system call verifies that the process owner (user) either owns
+the file specified by
+.Fa path
+(or
+.Fa fd ) ,
+or
+is the super-user.
+The
+.Fn chmod
+system call follows symbolic links to operate on the target of the link
+rather than the link itself.
+.Pp
+The
+.Fn lchmod
+system call is similar to
+.Fn chmod
+but does not follow symbolic links.
+.Pp
+The
+.Fn fchmodat
+is equivalent to either
+.Fn chmod
+or
+.Fn lchmod
+depending on the
+.Fa flag
+except in the case where
+.Fa path
+specifies a relative path.
+In this case the file to be changed is determined relative to the directory
+associated with the file descriptor
+.Fa fd
+instead of the current working directory.
+The values for the
+.Fa flag
+are constructed by a bitwise-inclusive OR of flags from the following list, defined
+in
+.In fcntl.h :
+.Bl -tag -width indent
+.It Dv AT_SYMLINK_NOFOLLOW
+If
+.Fa path
+names a symbolic link, then the mode of the symbolic link is changed.
+.El
+.Pp
+If
+.Fn fchmodat
+is passed the special value
+.Dv AT_FDCWD
+in the
+.Fa fd
+parameter, the current working directory is used.
+If also
+.Fa flag
+is zero, the behavior is identical to a call to
+.Fn chmod .
+.Pp
+A mode is created from
+.Em or'd
+permission bit masks
+defined in
+.In sys/stat.h :
+.Pp
+.Bd -literal -offset indent -compact
+#define S_IRWXU 0000700 /* RWX mask for owner */
+#define S_IRUSR 0000400 /* R for owner */
+#define S_IWUSR 0000200 /* W for owner */
+#define S_IXUSR 0000100 /* X for owner */
+
+#define S_IRWXG 0000070 /* RWX mask for group */
+#define S_IRGRP 0000040 /* R for group */
+#define S_IWGRP 0000020 /* W for group */
+#define S_IXGRP 0000010 /* X for group */
+
+#define S_IRWXO 0000007 /* RWX mask for other */
+#define S_IROTH 0000004 /* R for other */
+#define S_IWOTH 0000002 /* W for other */
+#define S_IXOTH 0000001 /* X for other */
+
+#define S_ISUID 0004000 /* set user id on execution */
+#define S_ISGID 0002000 /* set group id on execution */
+#define S_ISVTX 0001000 /* sticky bit */
+.Ed
+.Pp
+The non-standard
+.Dv S_ISTXT
+is a synonym for
+.Dv S_ISVTX .
+.Pp
+The
+.Fx
+VM system totally ignores the sticky bit
+.Pq Dv S_ISVTX
+for executables.
+On UFS-based file systems (FFS, LFS) the sticky
+bit may only be set upon directories.
+.Pp
+If mode
+.Dv S_ISVTX
+(the `sticky bit') is set on a directory,
+an unprivileged user may not delete or rename
+files of other users in that directory.
+The sticky bit may be
+set by any user on a directory which the user owns or has appropriate
+permissions.
+For more details of the properties of the sticky bit, see
+.Xr sticky 7 .
+.Pp
+If mode ISUID (set UID) is set on a directory,
+and the MNT_SUIDDIR option was used in the mount of the file system,
+then the owner of any new files and sub-directories
+created within this directory are set
+to be the same as the owner of that directory.
+If this function is enabled, new directories will inherit
+the bit from their parents.
+Execute bits are removed from
+the file, and it will not be given to root.
+This behavior does not change the
+requirements for the user to be allowed to write the file, but only the eventual
+owner after it has been created.
+Group inheritance is not affected.
+.Pp
+This feature is designed for use on fileservers serving PC users via
+ftp, SAMBA, or netatalk.
+It provides security holes for shell users and as
+such should not be used on shell machines, especially on home directories.
+This option requires the SUIDDIR
+option in the kernel to work.
+Only UFS file systems support this option.
+For more details of the suiddir mount option, see
+.Xr mount 8 .
+.Pp
+Writing or changing the owner of a file
+turns off the set-user-id and set-group-id bits
+unless the user is the super-user.
+This makes the system somewhat more secure
+by protecting set-user-id (set-group-id) files
+from remaining set-user-id (set-group-id) if they are modified,
+at the expense of a degree of compatibility.
+.Sh RETURN VALUES
+.Rv -std
+.Sh ERRORS
+The
+.Fn chmod
+system call
+will fail and the file mode will be unchanged if:
+.Bl -tag -width Er
+.It Bq Er ENOTDIR
+A component of the path prefix is not a directory.
+.It Bq Er ENAMETOOLONG
+A component of a pathname exceeded 255 characters,
+or an entire path name exceeded 1023 characters.
+.It Bq Er ENOENT
+The named file does not exist.
+.It Bq Er EACCES
+Search permission is denied for a component of the path prefix.
+.It Bq Er ELOOP
+Too many symbolic links were encountered in translating the pathname.
+.It Bq Er EPERM
+The effective user ID does not match the owner of the file and
+the effective user ID is not the super-user.
+.It Bq Er EPERM
+The effective user ID is not the super-user, the effective user ID do match the
+owner of the file, but the group ID of the file does not match the effective
+group ID nor one of the supplementary group IDs.
+.It Bq Er EPERM
+The named file has its immutable or append-only flag set, see the
+.Xr chflags 2
+manual page for more information.
+.It Bq Er EROFS
+The named file resides on a read-only file system.
+.It Bq Er EFAULT
+The
+.Fa path
+argument
+points outside the process's allocated address space.
+.It Bq Er EIO
+An I/O error occurred while reading from or writing to the file system.
+.It Bq Er EFTYPE
+The effective user ID is not the super-user, the mode includes the sticky bit
+.Dv ( S_ISVTX ) ,
+and path does not refer to a directory.
+.El
+.Pp
+The
+.Fn fchmod
+system call will fail if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The descriptor is not valid.
+.It Bq Er EINVAL
+The
+.Fa fd
+argument
+refers to a socket, not to a file.
+.It Bq Er EROFS
+The file resides on a read-only file system.
+.It Bq Er EIO
+An I/O error occurred while reading from or writing to the file system.
+.El
+.Pp
+In addition to the
+.Fn chmod
+errors,
+.Fn fchmodat
+fails if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa path
+argument does not specify an absolute path and the
+.Fa fd
+argument is neither
+.Fa AT_FDCWD
+nor a valid file descriptor open for searching.
+.It Bq Er EINVAL
+The value of the
+.Fa flag
+argument is not valid.
+.It Bq Er ENOTDIR
+The
+.Fa path
+argument is not an absolute path and
+.Fa fd
+is neither
+.Dv AT_FDCWD
+nor a file descriptor associated with a directory.
+.El
+.Sh SEE ALSO
+.Xr chmod 1 ,
+.Xr chflags 2 ,
+.Xr chown 2 ,
+.Xr open 2 ,
+.Xr stat 2 ,
+.Xr sticky 7
+.Sh STANDARDS
+The
+.Fn chmod
+system call is expected to conform to
+.St -p1003.1-90 ,
+except for the return of
+.Er EFTYPE .
+The
+.Dv S_ISVTX
+bit on directories is expected to conform to
+.St -susv3 .
+The
+.Fn fchmodat
+system call is expected to conform to
+.St -p1003.1-2008 .
+.Sh HISTORY
+The
+.Fn chmod
+function appeared in
+.At v7 .
+The
+.Fn fchmod
+system call appeared in
+.Bx 4.2 .
+The
+.Fn lchmod
+system call appeared in
+.Fx 3.0 .
+The
+.Fn fchmodat
+system call appeared in
+.Fx 8.0 .
diff --git a/lib/libc/sys/chown.2 b/lib/libc/sys/chown.2
new file mode 100644
index 000000000000..32c29ff72ab5
--- /dev/null
+++ b/lib/libc/sys/chown.2
@@ -0,0 +1,268 @@
+.\" Copyright (c) 1980, 1991, 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)chown.2 8.4 (Berkeley) 4/19/94
+.\" $FreeBSD$
+.\"
+.Dd April 10, 2008
+.Dt CHOWN 2
+.Os
+.Sh NAME
+.Nm chown ,
+.Nm fchown ,
+.Nm lchown ,
+.Nm fchownat
+.Nd change owner and group of a file
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft int
+.Fn chown "const char *path" "uid_t owner" "gid_t group"
+.Ft int
+.Fn fchown "int fd" "uid_t owner" "gid_t group"
+.Ft int
+.Fn lchown "const char *path" "uid_t owner" "gid_t group"
+.Ft int
+.Fn fchownat "int fd" "const char *path" "uid_t owner" "gid_t group" "int flag"
+.Sh DESCRIPTION
+The owner ID and group ID of the file
+named by
+.Fa path
+or referenced by
+.Fa fd
+is changed as specified by the arguments
+.Fa owner
+and
+.Fa group .
+The owner of a file may change the
+.Fa group
+to a group of which
+he or she is a member,
+but the change
+.Fa owner
+capability is restricted to the super-user.
+.Pp
+The
+.Fn chown
+system call
+clears the set-user-id and set-group-id bits
+on the file
+to prevent accidental or mischievous creation of
+set-user-id and set-group-id programs if not executed
+by the super-user.
+The
+.Fn chown
+system call
+follows symbolic links to operate on the target of the link
+rather than the link itself.
+.Pp
+The
+.Fn fchown
+system call
+is particularly useful when used in conjunction
+with the file locking primitives (see
+.Xr flock 2 ) .
+.Pp
+The
+.Fn lchown
+system call is similar to
+.Fn chown
+but does not follow symbolic links.
+.Pp
+The
+.Fn fchownat
+system call is equivalent to the
+.Fn chown
+and
+.Fn lchown
+except in the case where
+.Fa path
+specifies a relative path.
+In this case the file to be changed is determined relative to the directory
+associated with the file descriptor
+.Fa fd
+instead of the current working directory.
+.Pp
+Values for
+.Fa flag
+are constructed by a bitwise-inclusive OR of flags from the following
+list, defined in
+.In fcntl.h :
+.Bl -tag -width indent
+.It Dv AT_SYMLINK_NOFOLLOW
+If
+.Fa path
+names a symbolic link, ownership of the symbolic link is changed.
+.El
+.Pp
+If
+.Fn fchownat
+is passed the special value
+.Dv AT_FDCWD
+in the
+.Fa fd
+parameter, the current working directory is used and the behavior is identical
+to a call to
+.Fn chown
+or
+.Fn lchown
+respectively, depending on whether or not the
+.Dv AT_SYMLINK_NOFOLLOW
+bit is set in the
+.Fa flag
+argument.
+.Pp
+One of the owner or group id's
+may be left unchanged by specifying it as -1.
+.Sh RETURN VALUES
+.Rv -std
+.Sh ERRORS
+The
+.Fn chown
+and
+.Fn lchown
+will fail and the file will be unchanged if:
+.Bl -tag -width Er
+.It Bq Er ENOTDIR
+A component of the path prefix is not a directory.
+.It Bq Er ENAMETOOLONG
+A component of a pathname exceeded 255 characters,
+or an entire path name exceeded 1023 characters.
+.It Bq Er ENOENT
+The named file does not exist.
+.It Bq Er EACCES
+Search permission is denied for a component of the path prefix.
+.It Bq Er ELOOP
+Too many symbolic links were encountered in translating the pathname.
+.It Bq Er EPERM
+The operation would change the ownership, but the effective user ID is not the
+super-user.
+.It Bq Er EPERM
+The named file has its immutable or append-only flag set, see the
+.Xr chflags 2
+manual page for more information.
+.It Bq Er EROFS
+The named file resides on a read-only file system.
+.It Bq Er EFAULT
+The
+.Fa path
+argument
+points outside the process's allocated address space.
+.It Bq Er EIO
+An I/O error occurred while reading from or writing to the file system.
+.El
+.Pp
+The
+.Fn fchown
+system call will fail if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa fd
+argument
+does not refer to a valid descriptor.
+.It Bq Er EINVAL
+The
+.Fa fd
+argument
+refers to a socket, not a file.
+.It Bq Er EPERM
+The effective user ID is not the super-user.
+.It Bq Er EROFS
+The named file resides on a read-only file system.
+.It Bq Er EIO
+An I/O error occurred while reading from or writing to the file system.
+.El
+.Pp
+In addition to the errors specified for
+.Fn chown
+and
+.Fn lchown ,
+the
+.Fn fchownat
+system call may fail if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa path
+argument does not specify an absolute path and the
+.Fa fd
+argument is neither
+.Dv AT_FDCWD
+nor a valid file descriptor open for searching.
+.It Bq Er EINVAL
+The value of the
+.Fa flag
+argument is not valid.
+.It Bq Er ENOTDIR
+The
+.Fa path
+argument is not an absolute path and
+.Fa fd
+is neither
+.Dv AT_FDCWD
+nor a file descriptor associated with a directory.
+.El
+.Sh SEE ALSO
+.Xr chgrp 1 ,
+.Xr chflags 2 ,
+.Xr chmod 2 ,
+.Xr flock 2 ,
+.Xr chown 8
+.Sh STANDARDS
+The
+.Fn chown
+system call is expected to conform to
+.St -p1003.1-90 .
+The
+.Fn fchownat
+system call follows The Open Group Extended API Set 2 specification.
+.Sh HISTORY
+The
+.Fn chown
+function appeared in
+.At v7 .
+The
+.Fn fchown
+system call appeared in
+.Bx 4.2 .
+.Pp
+The
+.Fn chown
+system call was changed to follow symbolic links in
+.Bx 4.4 .
+The
+.Fn lchown
+system call was added in
+.Fx 3.0
+to compensate for the loss of functionality.
+.Pp
+The
+.Fn fchownat
+system call appeared in
+.Fx 8.0 .
diff --git a/lib/libc/sys/chroot.2 b/lib/libc/sys/chroot.2
new file mode 100644
index 000000000000..36d0364bd7f4
--- /dev/null
+++ b/lib/libc/sys/chroot.2
@@ -0,0 +1,156 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)chroot.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd January 3, 2012
+.Dt CHROOT 2
+.Os
+.Sh NAME
+.Nm chroot
+.Nd change root directory
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft int
+.Fn chroot "const char *dirname"
+.Sh DESCRIPTION
+The
+.Fa dirname
+argument
+is the address of the pathname of a directory, terminated by an ASCII NUL.
+The
+.Fn chroot
+system call causes
+.Fa dirname
+to become the root directory,
+that is, the starting point for path searches of pathnames
+beginning with
+.Ql / .
+.Pp
+In order for a directory to become the root directory
+a process must have execute (search) access for that directory.
+.Pp
+It should be noted that
+.Fn chroot
+has no effect on the process's current directory.
+.Pp
+This call is restricted to the super-user.
+.Pp
+Depending on the setting of the
+.Ql kern.chroot_allow_open_directories
+sysctl variable, open filedescriptors which reference directories
+will make the
+.Fn chroot
+fail as follows:
+.Pp
+If
+.Ql kern.chroot_allow_open_directories
+is set to zero,
+.Fn chroot
+will always fail with
+.Er EPERM
+if there are any directories open.
+.Pp
+If
+.Ql kern.chroot_allow_open_directories
+is set to one (the default),
+.Fn chroot
+will fail with
+.Er EPERM
+if there are any directories open and the
+process is already subject to the
+.Fn chroot
+system call.
+.Pp
+Any other value for
+.Ql kern.chroot_allow_open_directories
+will bypass the check for open directories
+.Sh RETURN VALUES
+.Rv -std
+.Sh ERRORS
+The
+.Fn chroot
+system call
+will fail and the root directory will be unchanged if:
+.Bl -tag -width Er
+.It Bq Er ENOTDIR
+A component of the path name is not a directory.
+.It Bq Er EPERM
+The effective user ID is not the super-user, or one or more
+filedescriptors are open directories.
+.It Bq Er ENAMETOOLONG
+A component of a pathname exceeded 255 characters,
+or an entire path name exceeded 1023 characters.
+.It Bq Er ENOENT
+The named directory does not exist.
+.It Bq Er EACCES
+Search permission is denied for any component of the path name.
+.It Bq Er ELOOP
+Too many symbolic links were encountered in translating the pathname.
+.It Bq Er EFAULT
+The
+.Fa dirname
+argument
+points outside the process's allocated address space.
+.It Bq Er EIO
+An I/O error occurred while reading from or writing to the file system.
+.El
+.Sh SEE ALSO
+.Xr chdir 2 ,
+.Xr jail 2
+.Sh HISTORY
+The
+.Fn chroot
+system call appeared in
+.Bx 4.2 .
+It was marked as
+.Dq legacy
+in
+.St -susv2 ,
+and was removed in subsequent standards.
+.Sh BUGS
+If the process is able to change its working directory to the target
+directory, but another access control check fails (such as a check for
+open directories, or a MAC check), it is possible that this system
+call may return an error, with the working directory of the process
+left changed.
+.Sh SECURITY CONSIDERATIONS
+The system have many hardcoded paths to files where it may load after
+the process starts.
+It is generally recommended to drop privileges immediately after a
+successful
+.Nm
+call,
+and restrict write access to a limited subtree of the
+.Nm
+root,
+for instance,
+setup the sandbox so that the sandboxed user will have no write
+access to any well-known system directories.
diff --git a/lib/libc/sys/clock_gettime.2 b/lib/libc/sys/clock_gettime.2
new file mode 100644
index 000000000000..e77b1e81dc33
--- /dev/null
+++ b/lib/libc/sys/clock_gettime.2
@@ -0,0 +1,166 @@
+.\" $OpenBSD: clock_gettime.2,v 1.4 1997/05/08 20:21:16 kstailey Exp $
+.\"
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd December 27, 2015
+.Dt CLOCK_GETTIME 2
+.Os
+.Sh NAME
+.Nm clock_gettime ,
+.Nm clock_settime ,
+.Nm clock_getres
+.Nd get/set/calibrate date and time
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In time.h
+.Ft int
+.Fn clock_gettime "clockid_t clock_id" "struct timespec *tp"
+.Ft int
+.Fn clock_settime "clockid_t clock_id" "const struct timespec *tp"
+.Ft int
+.Fn clock_getres "clockid_t clock_id" "struct timespec *tp"
+.Sh DESCRIPTION
+The
+.Fn clock_gettime
+and
+.Fn clock_settime
+system calls allow the calling process to retrieve or set the value
+used by a clock which is specified by
+.Fa clock_id .
+.Pp
+The
+.Fa clock_id
+argument
+can be one of the following values:
+.Dv CLOCK_REALTIME ,
+.Dv CLOCK_REALTIME_PRECISE ,
+.Dv CLOCK_REALTIME_FAST
+for time that increments as
+a wall clock should;
+.Dv CLOCK_MONOTONIC ,
+.Dv CLOCK_MONOTONIC_PRECISE ,
+.Dv CLOCK_MONOTONIC_FAST
+which increments in SI seconds;
+.Dv CLOCK_UPTIME ,
+.Dv CLOCK_UPTIME_PRECISE ,
+.Dv CLOCK_UPTIME_FAST
+which starts at zero when the kernel boots and increments
+monotonically in SI seconds while the machine is running;
+.Dv CLOCK_VIRTUAL
+for time that increments only when
+the CPU is running in user mode on behalf of the calling process;
+.Dv CLOCK_PROF
+for time that increments when the CPU is running in user or
+kernel mode; or
+.Dv CLOCK_SECOND
+which returns the current second without performing a full time counter
+query, using in-kernel cached value of current second.
+.Pp
+The clock IDs
+.Fa CLOCK_REALTIME_FAST ,
+.Fa CLOCK_MONOTONIC_FAST ,
+.Fa CLOCK_UPTIME_FAST
+are analogs of corresponding IDs without _FAST suffix but do not perform
+a full time counter query, so their accuracy is one timer tick.
+Similarly,
+.Fa CLOCK_REALTIME_PRECISE ,
+.Fa CLOCK_MONOTONIC_PRECISE ,
+.Fa CLOCK_UPTIME_PRECISE
+are used to get the most exact value as possible, at the expense of
+execution time.
+.Pp
+The structure pointed to by
+.Fa tp
+is defined in
+.In sys/timespec.h
+as:
+.Bd -literal
+struct timespec {
+ time_t tv_sec; /* seconds */
+ long tv_nsec; /* and nanoseconds */
+};
+.Ed
+.Pp
+Only the super-user may set the time of day, using only
+.Fa CLOCK_REALTIME .
+If the system securelevel is greater than 1 (see
+.Xr init 8 ) ,
+the time may only be advanced.
+This limitation is imposed to prevent a malicious super-user
+from setting arbitrary time stamps on files.
+The system time can still be adjusted backwards using the
+.Xr adjtime 2
+system call even when the system is secure.
+.Pp
+The resolution (granularity) of a clock is returned by the
+.Fn clock_getres
+system call.
+This value is placed in a (non-NULL)
+.Fa *tp .
+.Sh RETURN VALUES
+.Rv -std
+.Sh ERRORS
+The following error codes may be set in
+.Va errno :
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa clock_id
+or
+.Fa timespec
+argument
+was not a valid value.
+.It Bq Er EPERM
+A user other than the super-user attempted to set the time.
+.El
+.Sh SEE ALSO
+.Xr date 1 ,
+.Xr adjtime 2 ,
+.Xr ctime 3 ,
+.Xr timed 8
+.Sh STANDARDS
+The
+.Fn clock_gettime ,
+.Fn clock_settime ,
+and
+.Fn clock_getres
+system calls conform to
+.St -p1003.1b-93 .
+The clock IDs
+.Fa CLOCK_REALTIME_FAST ,
+.Fa CLOCK_REALTIME_PRECISE ,
+.Fa CLOCK_MONOTONIC_FAST ,
+.Fa CLOCK_MONOTONIC_PRECISE ,
+.Fa CLOCK_UPTIME ,
+.Fa CLOCK_UPTIME_FAST ,
+.Fa CLOCK_UPTIME_PRECISE ,
+.Fa CLOCK_SECOND
+are FreeBSD extensions to the POSIX interface.
diff --git a/lib/libc/sys/clock_gettime.c b/lib/libc/sys/clock_gettime.c
new file mode 100644
index 000000000000..e7e701b2e509
--- /dev/null
+++ b/lib/libc/sys/clock_gettime.c
@@ -0,0 +1,52 @@
+/*-
+ * Copyright (c) 2012 Konstantin Belousov <kib@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/vdso.h>
+#include <errno.h>
+#include <time.h>
+#include "libc_private.h"
+
+int __clock_gettime(clockid_t, struct timespec *ts);
+
+__weak_reference(__clock_gettime, clock_gettime);
+
+int
+__clock_gettime(clockid_t clock_id, struct timespec *ts)
+{
+ int error;
+
+ if (__vdso_clock_gettime != NULL && __vdso_gettc != NULL)
+ error = __vdso_clock_gettime(clock_id, ts);
+ else
+ error = ENOSYS;
+ if (error == ENOSYS)
+ error = __sys_clock_gettime(clock_id, ts);
+ return (error);
+}
diff --git a/lib/libc/sys/close.2 b/lib/libc/sys/close.2
new file mode 100644
index 000000000000..6df4500643be
--- /dev/null
+++ b/lib/libc/sys/close.2
@@ -0,0 +1,144 @@
+.\" Copyright (c) 1980, 1991, 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)close.2 8.2 (Berkeley) 4/19/94
+.\" $FreeBSD$
+.\"
+.Dd September 11, 2013
+.Dt CLOSE 2
+.Os
+.Sh NAME
+.Nm close
+.Nd delete a descriptor
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft int
+.Fn close "int fd"
+.Sh DESCRIPTION
+The
+.Fn close
+system call deletes a descriptor from the per-process object
+reference table.
+If this is the last reference to the underlying object, the
+object will be deactivated.
+For example, on the last close of a file
+the current
+.Em seek
+pointer associated with the file is lost;
+on the last close of a
+.Xr socket 2
+associated naming information and queued data are discarded;
+on the last close of a file holding an advisory lock
+the lock is released (see further
+.Xr flock 2 ) .
+However, the semantics of System V and
+.St -p1003.1-88
+dictate that all
+.Xr fcntl 2
+advisory record locks associated with a file for a given process
+are removed when
+.Em any
+file descriptor for that file is closed by that process.
+.Pp
+When a process exits,
+all associated file descriptors are freed, but since there is
+a limit on active descriptors per processes, the
+.Fn close
+system call
+is useful when a large quantity of file descriptors are being handled.
+.Pp
+When a process forks (see
+.Xr fork 2 ) ,
+all descriptors for the new child process reference the same
+objects as they did in the parent before the fork.
+If a new process is then to be run using
+.Xr execve 2 ,
+the process would normally inherit these descriptors.
+Most
+of the descriptors can be rearranged with
+.Xr dup2 2
+or deleted with
+.Fn close
+before the
+.Xr execve 2
+is attempted, but if some of these descriptors will still
+be needed if the execve fails, it is necessary to arrange for them
+to be closed if the execve succeeds.
+For this reason, the call
+.Dq Li fcntl(d, F_SETFD, FD_CLOEXEC)
+is provided,
+which arranges that a descriptor will be closed after a successful
+execve; the call
+.Dq Li fcntl(d, F_SETFD, 0)
+restores the default,
+which is to not close the descriptor.
+.Sh RETURN VALUES
+.Rv -std close
+.Sh ERRORS
+The
+.Fn close
+system call will fail if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa fd
+argument
+is not an active descriptor.
+.It Bq Er EINTR
+An interrupt was received.
+.It Bq Er ENOSPC
+The underlying object did not fit, cached data was lost.
+.It Bq Er ECONNRESET
+The underlying object was a stream socket that was shut down by the peer
+before all pending data was delivered.
+.El
+.Pp
+In case of any error except
+.Er EBADF ,
+the supplied file descriptor is deallocated and therefore is no longer valid.
+.Sh SEE ALSO
+.Xr accept 2 ,
+.Xr closefrom 2 ,
+.Xr execve 2 ,
+.Xr fcntl 2 ,
+.Xr flock 2 ,
+.Xr open 2 ,
+.Xr pipe 2 ,
+.Xr socket 2 ,
+.Xr socketpair 2
+.Sh STANDARDS
+The
+.Fn close
+system call is expected to conform to
+.St -p1003.1-90 .
+.Sh HISTORY
+The
+.Fn close
+function appeared in
+.At v7 .
diff --git a/lib/libc/sys/close.c b/lib/libc/sys/close.c
new file mode 100644
index 000000000000..f7b36f85ddd5
--- /dev/null
+++ b/lib/libc/sys/close.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2014 The FreeBSD Foundation.
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Konstantin Belousov
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice(s), this list of conditions and the following disclaimer as
+ * the first lines of this file unmodified other than the possible
+ * addition of one or more copyright notices.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice(s), this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/fcntl.h>
+#include <unistd.h>
+#include "libc_private.h"
+
+__weak_reference(__sys_close, __close);
+
+#pragma weak close
+int
+close(int fd)
+{
+
+ return (((int (*)(int))__libc_interposing[INTERPOS_close])(fd));
+}
diff --git a/lib/libc/sys/closefrom.2 b/lib/libc/sys/closefrom.2
new file mode 100644
index 000000000000..a0b5fc218666
--- /dev/null
+++ b/lib/libc/sys/closefrom.2
@@ -0,0 +1,53 @@
+.\" Copyright (c) 2009 Hudson River Trading LLC
+.\" Written by: John H. Baldwin <jhb@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd June 12, 2009
+.Dt CLOSEFROM 2
+.Os
+.Sh NAME
+.Nm closefrom
+.Nd delete open file descriptors
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft void
+.Fn closefrom "int lowfd"
+.Sh DESCRIPTION
+The
+.Fn closefrom
+system call deletes all open file descriptors greater than or equal to
+.Fa lowfd
+from the per-process object reference table.
+Any errors encountered while closing file descriptors are ignored.
+.Sh SEE ALSO
+.Xr close 2
+.Sh HISTORY
+The
+.Fn closefrom
+function first appeared in
+.Fx 8.0 .
diff --git a/lib/libc/sys/connect.2 b/lib/libc/sys/connect.2
new file mode 100644
index 000000000000..dceec0d40209
--- /dev/null
+++ b/lib/libc/sys/connect.2
@@ -0,0 +1,185 @@
+.\" Copyright (c) 1983, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)connect.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd August 18, 2016
+.Dt CONNECT 2
+.Os
+.Sh NAME
+.Nm connect
+.Nd initiate a connection on a socket
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/socket.h
+.Ft int
+.Fn connect "int s" "const struct sockaddr *name" "socklen_t namelen"
+.Sh DESCRIPTION
+The
+.Fa s
+argument
+is a socket.
+If it is of type
+.Dv SOCK_DGRAM ,
+this call specifies the peer with which the socket is to be associated;
+this address is that to which datagrams are to be sent,
+and the only address from which datagrams are to be received.
+If the socket is of type
+.Dv SOCK_STREAM ,
+this call attempts to make a connection to
+another socket.
+The other socket is specified by
+.Fa name ,
+which is an address in the communications space of the socket.
+.Fa namelen
+indicates the amount of space pointed to by
+.Fa name ,
+in bytes; the
+.Fa sa_len
+member of
+.Fa name
+is ignored.
+Each communications space interprets the
+.Fa name
+argument in its own way.
+Generally, stream sockets may successfully
+.Fn connect
+only once; datagram sockets may use
+.Fn connect
+multiple times to change their association.
+Datagram sockets may dissolve the association
+by connecting to an invalid address, such as a null address.
+.Sh RETURN VALUES
+.Rv -std connect
+.Sh ERRORS
+The
+.Fn connect
+system call fails if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa s
+argument
+is not a valid descriptor.
+.It Bq Er EINVAL
+The
+.Fa namelen
+argument is not a valid length for the address family.
+.It Bq Er ENOTSOCK
+The
+.Fa s
+argument
+is a descriptor for a file, not a socket.
+.It Bq Er EADDRNOTAVAIL
+The specified address is not available on this machine.
+.It Bq Er EAFNOSUPPORT
+Addresses in the specified address family cannot be used with this socket.
+.It Bq Er EISCONN
+The socket is already connected.
+.It Bq Er ETIMEDOUT
+Connection establishment timed out without establishing a connection.
+.It Bq Er ECONNREFUSED
+The attempt to connect was forcefully rejected.
+.It Bq Er ECONNRESET
+The connection was reset by the remote host.
+.It Bq Er ENETUNREACH
+The network is not reachable from this host.
+.It Bq Er EHOSTUNREACH
+The remote host is not reachable from this host.
+.It Bq Er EADDRINUSE
+The address is already in use.
+.It Bq Er EFAULT
+The
+.Fa name
+argument specifies an area outside
+the process address space.
+.It Bq Er EINPROGRESS
+The socket is non-blocking
+and the connection cannot
+be completed immediately.
+It is possible to
+.Xr select 2
+for completion by selecting the socket for writing.
+.It Bq Er EINTR
+The connection attempt was interrupted by the delivery of a signal.
+The connection will be established in the background,
+as in the case of
+.Er EINPROGRESS .
+.It Bq Er EALREADY
+A previous connection attempt has not yet been completed.
+.It Bq Er EACCES
+An attempt is made to connect to a broadcast address (obtained through the
+.Dv INADDR_BROADCAST
+constant or the
+.Dv INADDR_NONE
+return value) through a socket that does not provide broadcast functionality.
+.It Bq Er EAGAIN
+An auto-assigned port number was requested but no auto-assigned ports
+are available.
+Increasing the port range specified by
+.Xr sysctl 3
+MIB variables
+.Va net.inet.ip.portrange.first
+and
+.Va net.inet.ip.portrange.last
+may alleviate the problem.
+.El
+.Pp
+The following errors are specific to connecting names in the UNIX domain.
+These errors may not apply in future versions of the UNIX IPC domain.
+.Bl -tag -width Er
+.It Bq Er ENOTDIR
+A component of the path prefix is not a directory.
+.It Bq Er ENAMETOOLONG
+A component of a pathname exceeded 255 characters,
+or an entire path name exceeded 1023 characters.
+.It Bq Er ENOENT
+The named socket does not exist.
+.It Bq Er EACCES
+Search permission is denied for a component of the path prefix.
+.It Bq Er EACCES
+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 ,
+.Xr getpeername 2 ,
+.Xr getsockname 2 ,
+.Xr select 2 ,
+.Xr socket 2 ,
+.Xr sysctl 3 ,
+.Xr sysctl 8
+.Sh HISTORY
+The
+.Fn connect
+system call appeared in
+.Bx 4.2 .
diff --git a/lib/libc/sys/connect.c b/lib/libc/sys/connect.c
new file mode 100644
index 000000000000..7969142ad072
--- /dev/null
+++ b/lib/libc/sys/connect.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2014 The FreeBSD Foundation.
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Konstantin Belousov
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice(s), this list of conditions and the following disclaimer as
+ * the first lines of this file unmodified other than the possible
+ * addition of one or more copyright notices.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice(s), this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/syscall.h>
+#include <sys/socket.h>
+#include "libc_private.h"
+
+__weak_reference(__sys_connect, __connect);
+
+#pragma weak connect
+int
+connect(int s, const struct sockaddr *addr, socklen_t addrlen)
+{
+
+ return (((int (*)(int, const struct sockaddr *, socklen_t))
+ __libc_interposing[INTERPOS_connect])(s, addr, addrlen));
+}
diff --git a/lib/libc/sys/connectat.2 b/lib/libc/sys/connectat.2
new file mode 100644
index 000000000000..759b7eac8e2e
--- /dev/null
+++ b/lib/libc/sys/connectat.2
@@ -0,0 +1,109 @@
+.\" Copyright (c) 2013 The FreeBSD Foundation
+.\" All rights reserved.
+.\"
+.\" This documentation was written 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$
+.\"
+.Dd February 13, 2013
+.Dt CONNECTAT 2
+.Os
+.Sh NAME
+.Nm connectat
+.Nd initiate a connection on a socket
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/socket.h
+.Pp
+.In fcntl.h
+.Ft int
+.Fn connectat "int fd" "int s" "const struct sockaddr *name" "socklen_t namelen"
+.Sh DESCRIPTION
+The
+.Fn connectat
+system call initiates a connection on a socket.
+It works just like the
+.Xr connect 2
+system call with two exceptions:
+.Pp
+.Bl -enum -offset indent -compact
+.It
+It is limited to sockets in the PF_LOCAL domain.
+.Pp
+.It
+If the file path stored in the
+.Fa sun_path
+field of the sockaddr_un structure is a relative path, it is located relative
+to the directory associated with the file descriptor
+.Fa fd .
+If
+.Fn connectat
+is passed the special value
+.Dv AT_FDCWD
+in the
+.Fa fd
+parameter, the current working directory is used and the behavior is identical
+to a call to
+.Xr connect 2 .
+.El
+.Sh RETURN VALUES
+.Rv -std connectat
+.Sh ERRORS
+The
+.Fn connectat
+system call may fail with the same errors as the
+.Xr connect 2
+system call for a UNIX domain socket or with the following errors:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa sun_path
+field does not specify an absolute path and the
+.Fa fd
+argument is neither
+.Dv AT_FDCWD
+nor a valid file descriptor.
+.It Bq Er ENOTDIR
+The
+.Fa sun_path
+field is not an absolute path and
+.Fa fd
+is neither
+.Dv AT_FDCWD
+nor a file descriptor associated with a directory.
+.El
+.Sh SEE ALSO
+.Xr bindat 2 ,
+.Xr connect 2 ,
+.Xr socket 2 ,
+.Xr unix 4
+.Sh AUTHORS
+The
+.Nm
+was developed by
+.An Pawel Jakub Dawidek Aq Mt pawel@dawidek.net
+under sponsorship from the FreeBSD Foundation.
diff --git a/lib/libc/sys/cpuset.2 b/lib/libc/sys/cpuset.2
new file mode 100644
index 000000000000..d16b3ff37511
--- /dev/null
+++ b/lib/libc/sys/cpuset.2
@@ -0,0 +1,230 @@
+.\" Copyright (c) 2008 Christian Brueffer
+.\" Copyright (c) 2008 Jeffrey Roberson
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd October 20, 2015
+.Dt CPUSET 2
+.Os
+.Sh NAME
+.Nm cpuset ,
+.Nm cpuset_getid ,
+.Nm cpuset_setid
+.Nd manage CPU affinity sets
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/param.h
+.In sys/cpuset.h
+.Ft int
+.Fn cpuset "cpusetid_t *setid"
+.Ft int
+.Fn cpuset_setid "cpuwhich_t which" "id_t id" "cpusetid_t setid"
+.Ft int
+.Fn cpuset_getid "cpulevel_t level" "cpuwhich_t which" "id_t id" "cpusetid_t *setid"
+.Sh DESCRIPTION
+The
+.Nm
+family of system calls allow applications to control sets of processors and
+assign processes and threads to these sets.
+Processor sets contain lists of CPUs that members may run on and exist only
+as long as some process is a member of the set.
+All processes in the system have an assigned set.
+The default set for all processes in the system is the set numbered 1.
+Threads belong to the same set as the process which contains them,
+however, they may further restrict their set with the anonymous
+per-thread mask.
+.Pp
+Sets are referenced by a number of type
+.Ft cpuset_id_t .
+Each thread has a root set, an assigned set, and an anonymous mask.
+Only the root and assigned sets are numbered.
+The root set is the set of all CPUs available in the system or in the
+system partition the thread is running in.
+The assigned set is a subset of the root set and is administratively
+assignable on a per-process basis.
+Many processes and threads may be members of a numbered set.
+.Pp
+The anonymous set is a further thread-specific refinement on the assigned
+set.
+It is intended that administrators will manipulate numbered sets using
+.Xr cpuset 1
+while application developers will manipulate anonymous sets using
+.Xr cpuset_setaffinity 2 .
+.Pp
+To select the correct set a value of type
+.Ft cpulevel_t
+is used.
+The following values for
+.Fa level
+are supported:
+.Bl -column CPU_LEVEL_CPUSET -offset indent
+.It Dv CPU_LEVEL_ROOT Ta "Root set"
+.It Dv CPU_LEVEL_CPUSET Ta "Assigned set"
+.It Dv CPU_LEVEL_WHICH Ta "Set specified by which argument"
+.El
+.Pp
+The
+.Fa which
+argument determines how the value of
+.Fa id
+is interpreted and is of type
+.Ft cpuwhich_t .
+The
+.Fa which
+argument may have the following values:
+.Bl -column CPU_WHICH_CPUSET -offset indent
+.It Dv CPU_WHICH_TID Ta "id is lwpid_t (thread id)"
+.It Dv CPU_WHICH_PID Ta "id is pid_t (process id)"
+.It Dv CPU_WHICH_JAIL Ta "id is jid (jail id)"
+.It Dv CPU_WHICH_CPUSET Ta "id is a cpusetid_t (cpuset id)"
+.It Dv CPU_WHICH_IRQ Ta "id is an irq number"
+.It Dv CPU_WHICH_DOMAIN Ta "id is a NUMA domain"
+.El
+.Pp
+An
+.Fa id
+of '-1' may be used with a
+.Fa which
+of
+.Dv CPU_WHICH_TID ,
+.Dv CPU_WHICH_PID ,
+or
+.Dv CPU_WHICH_CPUSET
+to mean the current thread, process, or current thread's
+cpuset.
+All cpuset syscalls allow this usage.
+.Pp
+A
+.Fa level
+argument of
+.Dv CPU_LEVEL_WHICH
+combined with a
+.Fa which
+argument other than
+.Dv CPU_WHICH_CPUSET
+refers to the anonymous mask of the object.
+This mask does not have an id and may only be manipulated with
+.Xr cpuset_setaffinity 2 .
+.Pp
+.Fn cpuset
+creates a new set containing the same CPUs as the root set of the current
+process and stores its id in the space provided by
+.Fa setid .
+On successful completion the calling process joins the set and is the
+only member.
+Children inherit this set after a call to
+.Xr fork 2 .
+.Pp
+.Fn cpuset_setid
+attempts to set the id of the object specified by the
+.Fa which
+argument.
+Currently
+.Dv CPU_WHICH_PID
+is the only acceptable value for which as
+threads do not have an id distinct from their process and the API does
+not permit changing the id of an existing set.
+Upon successful completion all of the threads in the target process will
+be running on CPUs permitted by the set.
+.Pp
+.Fn cpuset_getid
+retrieves a set id from the object indicated by
+.Fa which
+and stores it in the space pointed to by
+.Fa setid .
+The retrieved id may be that of either the root or assigned set
+depending on the value of
+.Fa level .
+.Fa level
+should be
+.Dv CPU_LEVEL_CPUSET
+or
+.Dv CPU_LEVEL_ROOT
+to get the set id from
+the process or thread specified by the
+.Fa id
+argument.
+Specifying
+.Dv CPU_LEVEL_WHICH
+with a process or thread is unsupported since
+this references the unnumbered anonymous mask.
+.Pp
+The actual contents of the sets may be retrieved or manipulated using
+.Xr cpuset_getaffinity 2
+and
+.Xr cpuset_setaffinity 2 .
+See those manual pages for more detail.
+.Sh RETURN VALUES
+.Rv -std
+.Sh ERRORS
+The following error codes may be set in
+.Va errno :
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa which
+or
+.Fa level
+argument was not a valid value.
+.It Bq Er EDEADLK
+The
+.Fn cpuset_setid
+call would leave a thread without a valid CPU to run on because the set
+does not overlap with the thread's anonymous mask.
+.It Bq Er EFAULT
+The setid pointer passed to
+.Fn cpuset_getid
+or
+.Fn cpuset
+was invalid.
+.It Bq Er ESRCH
+The object specified by the
+.Fa id
+and
+.Fa which
+arguments could not be found.
+.It Bq Er EPERM
+The calling process did not have the credentials required to complete the
+operation.
+.It Bq Er ENFILE
+There was no free
+.Ft cpusetid_t
+for allocation.
+.El
+.Sh SEE ALSO
+.Xr cpuset 1 ,
+.Xr cpuset_getaffinity 2 ,
+.Xr cpuset_setaffinity 2 ,
+.Xr pthread_affinity_np 3 ,
+.Xr pthread_attr_affinity_np 3 ,
+.Xr cpuset 9
+.Sh HISTORY
+The
+.Nm
+family of system calls first appeared in
+.Fx 7.1 .
+.Sh AUTHORS
+.An Jeffrey Roberson Aq Mt jeff@FreeBSD.org
diff --git a/lib/libc/sys/cpuset_getaffinity.2 b/lib/libc/sys/cpuset_getaffinity.2
new file mode 100644
index 000000000000..c379518214b8
--- /dev/null
+++ b/lib/libc/sys/cpuset_getaffinity.2
@@ -0,0 +1,166 @@
+.\" Copyright (c) 2008 Christian Brueffer
+.\" Copyright (c) 2008 Jeffrey Roberson
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd June 2, 2016
+.Dt CPUSET_GETAFFINITY 2
+.Os
+.Sh NAME
+.Nm cpuset_getaffinity ,
+.Nm cpuset_setaffinity
+.Nd manage CPU affinity
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/param.h
+.In sys/cpuset.h
+.Ft int
+.Fn cpuset_getaffinity "cpulevel_t level" "cpuwhich_t which" "id_t id" "size_t setsize" "cpuset_t *mask"
+.Ft int
+.Fn cpuset_setaffinity "cpulevel_t level" "cpuwhich_t which" "id_t id" "size_t setsize" "const cpuset_t *mask"
+.Sh DESCRIPTION
+.Fn cpuset_getaffinity
+and
+.Fn cpuset_setaffinity
+allow the manipulation of sets of CPUs available to processes, threads,
+interrupts, jails and other resources.
+These functions may manipulate sets of CPUs that contain many processes
+or per-object anonymous masks that effect only a single object.
+.Pp
+The valid values for the
+.Fa level
+and
+.Fa which
+arguments are documented in
+.Xr cpuset 2 .
+These arguments specify which object and which set of the object we are
+referring to.
+Not all possible combinations are valid.
+For example, only processes may belong to a numbered set accessed by a
+.Fa level
+argument of
+.Dv CPU_LEVEL_CPUSET .
+All resources, however, have a mask which may be manipulated with
+.Dv CPU_LEVEL_WHICH .
+.Pp
+Masks of type
+.Ft cpuset_t
+are composed using the
+.Dv CPU_SET
+macros.
+The kernel tolerates large sets as long as all CPUs specified
+in the set exist.
+Sets smaller than the kernel uses generate an error on calls to
+.Fn cpuset_getaffinity
+even if the result set would fit within the user supplied set.
+Calls to
+.Fn cpuset_setaffinity
+tolerate small sets with no restrictions.
+.Pp
+The supplied mask should have a size of
+.Fa setsize
+bytes.
+This size is usually provided by calling
+.Li sizeof(mask)
+which is ultimately determined by the value of
+.Dv CPU_SETSIZE
+as defined in
+.In sys/cpuset.h .
+.Pp
+.Fn cpuset_getaffinity
+retrieves the
+mask from the object specified by
+.Fa level ,
+.Fa which
+and
+.Fa id
+and stores it in the space provided by
+.Fa mask .
+.Pp
+.Fn cpuset_setaffinity
+attempts to set the mask for the object specified by
+.Fa level ,
+.Fa which
+and
+.Fa id
+to the value in
+.Fa mask .
+.Sh RETURN VALUES
+.Rv -std
+.Sh ERRORS
+The following error codes may be set in
+.Va errno :
+.Bl -tag -width Er
+.\" When changing this list, consider updating share/man/man3/pthread_create.3,
+.\" since that function can return any of these errors.
+.It Bq Er EINVAL
+The
+.Fa level
+or
+.Fa which
+argument was not a valid value.
+.It Bq Er EINVAL
+The
+.Fa mask
+argument specified when calling
+.Fn cpuset_setaffinity
+was not a valid value.
+.It Bq Er EDEADLK
+The
+.Fn cpuset_setaffinity
+call would leave a thread without a valid CPU to run on because the set
+does not overlap with the thread's anonymous mask.
+.It Bq Er EFAULT
+The mask pointer passed was invalid.
+.It Bq Er ESRCH
+The object specified by the
+.Fa id
+and
+.Fa which
+arguments could not be found.
+.It Bq Er ERANGE
+The
+.Fa cpusetsize
+was either preposterously large or smaller than the kernel set size.
+.It Bq Er EPERM
+The calling process did not have the credentials required to complete the
+operation.
+.El
+.Sh SEE ALSO
+.Xr cpuset 1 ,
+.Xr cpuset 2 ,
+.Xr cpuset_getid 2 ,
+.Xr cpuset_setid 2 ,
+.Xr pthread_affinity_np 3 ,
+.Xr pthread_attr_affinity_np 3 ,
+.Xr cpuset 9
+.Sh HISTORY
+The
+.Nm
+family of system calls first appeared in
+.Fx 7.1 .
+.Sh AUTHORS
+.An Jeffrey Roberson Aq Mt jeff@FreeBSD.org
diff --git a/lib/libc/sys/dup.2 b/lib/libc/sys/dup.2
new file mode 100644
index 000000000000..f21c93b5868b
--- /dev/null
+++ b/lib/libc/sys/dup.2
@@ -0,0 +1,169 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)dup.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 1, 2013
+.Dt DUP 2
+.Os
+.Sh NAME
+.Nm dup ,
+.Nm dup2
+.Nd duplicate an existing file descriptor
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft int
+.Fn dup "int oldd"
+.Ft int
+.Fn dup2 "int oldd" "int newd"
+.Sh DESCRIPTION
+The
+.Fn dup
+system call
+duplicates an existing object descriptor and returns its value to
+the calling process
+.Fa ( newd
+=
+.Fn dup oldd ) .
+The argument
+.Fa oldd
+is a small non-negative integer index in
+the per-process descriptor table.
+The new descriptor returned by the call
+is the lowest numbered descriptor
+currently not in use by the process.
+.Pp
+The object referenced by the descriptor does not distinguish
+between
+.Fa oldd
+and
+.Fa newd
+in any way.
+Thus if
+.Fa newd
+and
+.Fa oldd
+are duplicate references to an open
+file,
+.Xr read 2 ,
+.Xr write 2
+and
+.Xr lseek 2
+calls all move a single pointer into the file,
+and append mode, non-blocking I/O and asynchronous I/O options
+are shared between the references.
+If a separate pointer into the file is desired, a different
+object reference to the file must be obtained by issuing an
+additional
+.Xr open 2
+system call.
+The close-on-exec flag on the new file descriptor is unset.
+.Pp
+In
+.Fn dup2 ,
+the value of the new descriptor
+.Fa newd
+is specified.
+If this descriptor is already in use and
+.Fa oldd
+\*(Ne
+.Fa newd ,
+the descriptor is first deallocated as if the
+.Xr close 2
+system call had been used.
+If
+.Fa oldd
+is not a valid descriptor, then
+.Fa newd
+is not closed.
+If
+.Fa oldd
+==
+.Fa newd
+and
+.Fa oldd
+is a valid descriptor, then
+.Fn dup2
+is successful, and does nothing.
+.Sh RETURN VALUES
+These calls return the new file descriptor if successful;
+otherwise the value -1 is returned and
+the external variable
+.Va errno
+is set to indicate the cause of the error.
+.Sh ERRORS
+The
+.Fn dup
+system call fails if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa oldd
+argument
+is not a valid active descriptor
+.It Bq Er EMFILE
+Too many descriptors are active.
+.El
+.Pp
+The
+.Fn dup2
+system call fails if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa oldd
+argument is not a valid active descriptor or the
+.Fa newd
+argument is negative or exceeds the maximum allowable descriptor number
+.El
+.Sh SEE ALSO
+.Xr accept 2 ,
+.Xr close 2 ,
+.Xr fcntl 2 ,
+.Xr getdtablesize 2 ,
+.Xr open 2 ,
+.Xr pipe 2 ,
+.Xr socket 2 ,
+.Xr socketpair 2 ,
+.Xr dup3 3
+.Sh STANDARDS
+The
+.Fn dup
+and
+.Fn dup2
+system calls are expected to conform to
+.St -p1003.1-90 .
+.Sh HISTORY
+The
+.Fn dup
+and
+.Fn dup2
+functions appeared in
+.At v7 .
diff --git a/lib/libc/sys/execve.2 b/lib/libc/sys/execve.2
new file mode 100644
index 000000000000..991495c3c9d8
--- /dev/null
+++ b/lib/libc/sys/execve.2
@@ -0,0 +1,377 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)execve.2 8.5 (Berkeley) 6/1/94
+.\" $FreeBSD$
+.\"
+.Dd September 21, 2010
+.Dt EXECVE 2
+.Os
+.Sh NAME
+.Nm execve ,
+.Nm fexecve
+.Nd execute a file
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft int
+.Fn execve "const char *path" "char *const argv[]" "char *const envp[]"
+.Ft int
+.Fn fexecve "int fd" "char *const argv[]" "char *const envp[]"
+.Sh DESCRIPTION
+The
+.Fn execve
+system call
+transforms the calling process into a new process.
+The new process is constructed from an ordinary file,
+whose name is pointed to by
+.Fa path ,
+called the
+.Em new process file .
+The
+.Fn fexecve
+system call is equivalent to
+.Fn execve
+except that the file to be executed is determined by the file
+descriptor
+.Fa fd
+instead of a
+.Fa path .
+This file is either an executable object file,
+or a file of data for an interpreter.
+An executable object file consists of an identifying header,
+followed by pages of data representing the initial program (text)
+and initialized data pages.
+Additional pages may be specified
+by the header to be initialized with zero data; see
+.Xr elf 5
+and
+.Xr a.out 5 .
+.Pp
+An interpreter file begins with a line of the form:
+.Pp
+.Bd -ragged -offset indent -compact
+.Sy \&#!
+.Em interpreter
+.Bq Em arg
+.Ed
+.Pp
+When an interpreter file is
+.Sy execve Ap d ,
+the system actually
+.Sy execve Ap s
+the specified
+.Em interpreter .
+If the optional
+.Em arg
+is specified, it becomes the first argument to the
+.Em interpreter ,
+and the name of the originally
+.Sy execve Ap d
+file becomes the second argument;
+otherwise, the name of the originally
+.Sy execve Ap d
+file becomes the first argument.
+The original arguments are shifted over to
+become the subsequent arguments.
+The zeroth argument is set to the specified
+.Em interpreter .
+.Pp
+The argument
+.Fa argv
+is a pointer to a null-terminated array of
+character pointers to null-terminated character strings.
+These strings construct the argument list to be made available to the new
+process.
+At least one argument must be present in
+the array; by custom, the first element should be
+the name of the executed program (for example, the last component of
+.Fa path ) .
+.Pp
+The argument
+.Fa envp
+is also a pointer to a null-terminated array of
+character pointers to null-terminated strings.
+A pointer to this array is normally stored in the global variable
+.Va environ .
+These strings pass information to the
+new process that is not directly an argument to the command (see
+.Xr environ 7 ) .
+.Pp
+File descriptors open in the calling process image remain open in
+the new process image, except for those for which the close-on-exec
+flag is set (see
+.Xr close 2
+and
+.Xr fcntl 2 ) .
+Descriptors that remain open are unaffected by
+.Fn execve .
+If any of the standard descriptors (0, 1, and/or 2) are closed at the
+time
+.Fn execve
+is called, and the process will gain privilege as a result of set-id
+semantics, those descriptors will be re-opened automatically.
+No programs, whether privileged or not, should assume that these descriptors
+will remain closed across a call to
+.Fn execve .
+.Pp
+Signals set to be ignored in the calling process are set to be ignored in
+the
+new process.
+Signals which are set to be caught in the calling process image
+are set to default action in the new process image.
+Blocked signals remain blocked regardless of changes to the signal action.
+The signal stack is reset to be undefined (see
+.Xr sigaction 2
+for more information).
+.Pp
+If the set-user-ID mode bit of the new process image file is set
+(see
+.Xr chmod 2 ) ,
+the effective user ID of the new process image is set to the owner ID
+of the new process image file.
+If the set-group-ID mode bit of the new process image file is set,
+the effective group ID of the new process image is set to the group ID
+of the new process image file.
+(The effective group ID is the first element of the group list.)
+The real user ID, real group ID and
+other group IDs of the new process image remain the same as the calling
+process image.
+After any set-user-ID and set-group-ID processing,
+the effective user ID is recorded as the saved set-user-ID,
+and the effective group ID is recorded as the saved set-group-ID.
+These values may be used in changing the effective IDs later (see
+.Xr setuid 2 ) .
+.Pp
+The set-ID bits are not honored if the respective file system has the
+.Cm nosuid
+option enabled or if the new process file is an interpreter file.
+Syscall
+tracing is disabled if effective IDs are changed.
+.Pp
+The new process also inherits the following attributes from
+the calling process:
+.Pp
+.Bl -column parent_process_ID -offset indent -compact
+.It process ID Ta see Xr getpid 2
+.It parent process ID Ta see Xr getppid 2
+.It process group ID Ta see Xr getpgrp 2
+.It access groups Ta see Xr getgroups 2
+.It working directory Ta see Xr chdir 2
+.It root directory Ta see Xr chroot 2
+.It control terminal Ta see Xr termios 4
+.It resource usages Ta see Xr getrusage 2
+.It interval timers Ta see Xr getitimer 2
+.It resource limits Ta see Xr getrlimit 2
+.It file mode mask Ta see Xr umask 2
+.It signal mask Ta see Xr sigaction 2 ,
+.Xr sigprocmask 2
+.El
+.Pp
+When a program is executed as a result of an
+.Fn execve
+system call, it is entered as follows:
+.Bd -literal -offset indent
+main(argc, argv, envp)
+int argc;
+char **argv, **envp;
+.Ed
+.Pp
+where
+.Fa argc
+is the number of elements in
+.Fa argv
+(the ``arg count'')
+and
+.Fa argv
+points to the array of character pointers
+to the arguments themselves.
+.Pp
+The
+.Fn fexecve
+ignores the file offset of
+.Fa fd .
+Since execute permission is checked by
+.Fn fexecve ,
+the file descriptor
+.Fa fd
+need not have been opened with the
+.Dv O_EXEC
+flag.
+However, if the file to be executed denies read permission for the process
+preparing to do the exec, the only way to provide the
+.Fa fd
+to
+.Fn fexecve
+is to use the
+.Dv O_EXEC
+flag when opening
+.Fa fd .
+Note that the file to be executed can not be open for writing.
+.Sh RETURN VALUES
+As the
+.Fn execve
+system call overlays the current process image
+with a new process image the successful call
+has no process to return to.
+If
+.Fn execve
+does return to the calling process an error has occurred; the
+return value will be -1 and the global variable
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+The
+.Fn execve
+system call
+will fail and return to the calling process if:
+.Bl -tag -width Er
+.It Bq Er ENOTDIR
+A component of the path prefix is not a directory.
+.It Bq Er ENAMETOOLONG
+A component of a pathname exceeded 255 characters,
+or an entire path name exceeded 1023 characters.
+.It Bq Er ENOEXEC
+When invoking an interpreted script, the length of the first line,
+inclusive of the
+.Sy \&#!
+prefix and terminating newline, exceeds
+.Dv MAXSHELLCMDLEN
+characters.
+.It Bq Er ENOENT
+The new process file does not exist.
+.It Bq Er ELOOP
+Too many symbolic links were encountered in translating the pathname.
+.It Bq Er EACCES
+Search permission is denied for a component of the path prefix.
+.It Bq Er EACCES
+The new process file is not an ordinary file.
+.It Bq Er EACCES
+The new process file mode denies execute permission.
+.It Bq Er ENOEXEC
+The new process file has the appropriate access
+permission, but has an invalid magic number in its header.
+.It Bq Er ETXTBSY
+The new process file is a pure procedure (shared text)
+file that is currently open for writing by some process.
+.It Bq Er ENOMEM
+The new process requires more virtual memory than
+is allowed by the imposed maximum
+.Pq Xr getrlimit 2 .
+.It Bq Er E2BIG
+The number of bytes in the new process' argument list
+is larger than the system-imposed limit.
+This limit is specified by the
+.Xr sysctl 3
+MIB variable
+.Dv KERN_ARGMAX .
+.It Bq Er EFAULT
+The new process file is not as long as indicated by
+the size values in its header.
+.It Bq Er EFAULT
+The
+.Fa path ,
+.Fa argv ,
+or
+.Fa envp
+arguments
+point
+to an illegal address.
+.It Bq Er EIO
+An I/O error occurred while reading from the file system.
+.El
+.Pp
+In addition, the
+.Fn fexecve
+will fail and return to the calling process if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa fd
+argument is not a valid file descriptor open for executing.
+.El
+.Sh SEE ALSO
+.Xr ktrace 1 ,
+.Xr _exit 2 ,
+.Xr fork 2 ,
+.Xr open 2 ,
+.Xr execl 3 ,
+.Xr exit 3 ,
+.Xr sysctl 3 ,
+.Xr a.out 5 ,
+.Xr elf 5 ,
+.Xr fdescfs 5 ,
+.Xr environ 7 ,
+.Xr mount 8
+.Sh STANDARDS
+The
+.Fn execve
+system call conforms to
+.St -p1003.1-2001 ,
+with the exception of reopening descriptors 0, 1, and/or 2 in certain
+circumstances.
+A future update of the Standard is expected to require this behavior,
+and it may become the default for non-privileged processes as well.
+.\" NB: update this caveat when TC1 is blessed.
+The support for executing interpreted programs is an extension.
+The
+.Fn fexecve
+system call conforms to The Open Group Extended API Set 2 specification.
+.Sh HISTORY
+The
+.Fn execve
+system call appeared in
+.Bx 4.2 .
+The
+.Fn fexecve
+system call appeared in
+.Fx 8.0 .
+.Sh CAVEATS
+If a program is
+.Em setuid
+to a non-super-user, but is executed when
+the real
+.Em uid
+is ``root'', then the program has some of the powers
+of a super-user as well.
+.Pp
+When executing an interpreted program through
+.Fn fexecve ,
+kernel supplies
+.Pa /dev/fd/n
+as a second argument to the interpreter,
+where
+.Ar n
+is the file descriptor passed in the
+.Fa fd
+argument to
+.Fn fexecve .
+For this construction to work correctly, the
+.Xr fdescfs 5
+filesystem shall be mounted on
+.Pa /dev/fd .
diff --git a/lib/libc/sys/extattr_get_file.2 b/lib/libc/sys/extattr_get_file.2
new file mode 100644
index 000000000000..db4ea92fd59f
--- /dev/null
+++ b/lib/libc/sys/extattr_get_file.2
@@ -0,0 +1,276 @@
+.\"
+.\" Copyright (c) 2001 Dima Dorfman <dima@unixfreak.org>
+.\" Copyright (c) 2003 Robert Watson <rwatson@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 January 29, 2008
+.Dt EXTATTR 2
+.Os
+.Sh NAME
+.Nm extattr_get_fd ,
+.Nm extattr_set_fd ,
+.Nm extattr_delete_fd ,
+.Nm extattr_list_fd ,
+.Nm extattr_get_file ,
+.Nm extattr_set_file ,
+.Nm extattr_delete_file ,
+.Nm extattr_list_file ,
+.Nm extattr_get_link ,
+.Nm extattr_set_link ,
+.Nm extattr_delete_link ,
+.Nm extattr_list_link
+.Nd system calls to manipulate VFS extended attributes
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/extattr.h
+.Ft ssize_t
+.Fn extattr_get_fd "int fd" "int attrnamespace" "const char *attrname" "void *data" "size_t nbytes"
+.Ft ssize_t
+.Fn extattr_set_fd "int fd" "int attrnamespace" "const char *attrname" "const void *data" "size_t nbytes"
+.Ft int
+.Fn extattr_delete_fd "int fd" "int attrnamespace" "const char *attrname"
+.Ft ssize_t
+.Fn extattr_list_fd "int fd" "int attrnamespace" "void *data" "size_t nbytes"
+.Ft ssize_t
+.Fn extattr_get_file "const char *path" "int attrnamespace" "const char *attrname" "void *data" "size_t nbytes"
+.Ft ssize_t
+.Fn extattr_set_file "const char *path" "int attrnamespace" "const char *attrname" "const void *data" "size_t nbytes"
+.Ft int
+.Fn extattr_delete_file "const char *path" "int attrnamespace" "const char *attrname"
+.Ft ssize_t
+.Fn extattr_list_file "const char *path" "int attrnamespace" "void *data" "size_t nbytes"
+.Ft ssize_t
+.Fn extattr_get_link "const char *path" "int attrnamespace" "const char *attrname" "void *data" "size_t nbytes"
+.Ft ssize_t
+.Fn extattr_set_link "const char *path" "int attrnamespace" "const char *attrname" "const void *data" "size_t nbytes"
+.Ft int
+.Fn extattr_delete_link "const char *path" "int attrnamespace" "const char *attrname"
+.Ft ssize_t
+.Fn extattr_list_link "const char *path" "int attrnamespace" "void *data" "size_t nbytes"
+.Sh DESCRIPTION
+Named extended attributes are meta-data associated with vnodes
+representing files and directories.
+They exist as
+.Qq Li name=value
+pairs within a set of namespaces.
+.Pp
+The
+.Fn extattr_get_file
+system call retrieves the value of the specified extended attribute into
+a buffer pointed to by
+.Fa data
+of size
+.Fa nbytes .
+The
+.Fn extattr_set_file
+system call sets the value of the specified extended attribute to the data
+described by
+.Fa data .
+The
+.Fn extattr_delete_file
+system call deletes the extended attribute specified.
+The
+.Fn extattr_list_file
+returns a list of attributes present in the requested namespace.
+Each list entry consists of a single byte containing the length
+of the attribute name, followed by the attribute name.
+The attribute name is not terminated by ASCII 0 (nul).
+The
+.Fn extattr_get_file ,
+and
+.Fn extattr_list_file
+calls consume the
+.Fa data
+and
+.Fa nbytes
+arguments in the style of
+.Xr read 2 ;
+.Fn extattr_set_file
+consumes these arguments in the style of
+.Xr write 2 .
+.Pp
+If
+.Fa data
+is
+.Dv NULL
+in a call to
+.Fn extattr_get_file
+and
+.Fn extattr_list_file
+then the size of defined extended attribute data will be returned, rather
+than the quantity read, permitting applications to test the size of the
+data without performing a read.
+The
+.Fn extattr_delete_link ,
+.Fn extattr_get_link ,
+and
+.Fn extattr_set_link
+system calls behave in the same way as their _file counterparts, except that
+they do not follow symlinks.
+.Pp
+The
+.Fn extattr_get_fd ,
+.Fn extattr_set_fd ,
+.Fn extattr_delete_fd ,
+and
+.Fn extattr_list_fd ,
+calls are identical to their
+.Qq Li _file
+counterparts except for the first argument.
+The
+.Qq Li _fd
+functions take a file descriptor, while the
+.Qq Li _file
+functions take a path.
+Both arguments describe a file associated with the extended attribute
+that should be manipulated.
+.Pp
+The following arguments are common to all the system calls described here:
+.Bl -tag -width attrnamespace
+.It Fa attrnamespace
+the namespace in which the extended attribute resides; see
+.Xr extattr 9
+.It Fa attrname
+the name of the extended attribute
+.El
+.Pp
+Named extended attribute semantics vary by file system implementing the call.
+Not all operations may be supported for a particular attribute.
+Additionally, the format of the data in
+.Fa data
+is attribute-specific.
+.Pp
+For more information on named extended attributes, please see
+.Xr extattr 9 .
+.Sh CAVEAT
+This interface is under active development, and as such is subject to
+change as applications are adapted to use it.
+Developers are discouraged from relying on its stability.
+.Sh RETURN VALUES
+If successful, the
+.Fn extattr_get_file ,
+.Fn extattr_set_file ,
+and
+.Fn extattr_list_file
+calls return the number of bytes
+that were read or written from the
+.Fa data ,
+respectively, or if
+.Fa data
+was
+.Dv NULL ,
+then
+.Fn extattr_get_file
+and
+.Fn extattr_list_file
+return the number of bytes available to read.
+If any of the calls are unsuccessful, the value \-1 is returned
+and the global variable
+.Va errno
+is set to indicate the error.
+.Pp
+.Rv -std extattr_delete_file
+.Sh ERRORS
+The following errors may be returned by the system calls themselves.
+Additionally, the file system implementing the call may return any
+other errors it desires.
+.Bl -tag -width Er
+.It Bq Er EFAULT
+The
+.Fa attrnamespace
+and
+.Fa attrname
+arguments,
+or the memory range defined by
+.Fa data
+and
+.Fa nbytes
+point outside the process's allocated address space.
+.It Bq Er ENAMETOOLONG
+The attribute name was longer than
+.Dv EXTATTR_MAXNAMELEN .
+.El
+.Pp
+The
+.Fn extattr_get_fd ,
+.Fn extattr_set_fd ,
+.Fn extattr_delete_fd ,
+and
+.Fn extattr_list_fd
+system calls may also fail if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The file descriptor referenced by
+.Fa fd
+was invalid.
+.El
+.Pp
+Additionally, the
+.Fn extattr_get_file ,
+.Fn extattr_set_file ,
+and
+.Fn extattr_delete_file
+calls may also fail due to the following errors:
+.Bl -tag -width Er
+.It Bq Er ENOATTR
+The requested attribute was not defined for this file.
+.It Bq Er ENOTDIR
+A component of the path prefix is not a directory.
+.It Bq Er ENAMETOOLONG
+A component of a pathname exceeded 255 characters,
+or an entire path name exceeded 1023 characters.
+.It Bq Er ENOENT
+A component of the path name that must exist does not exist.
+.It Bq Er EACCES
+Search permission is denied for a component of the path prefix.
+.\" XXX are any missing?
+.El
+.Sh SEE ALSO
+.Xr extattr 3 ,
+.Xr getextattr 8 ,
+.Xr setextattr 8 ,
+.Xr extattr 9 ,
+.Xr VOP_GETEXTATTR 9 ,
+.Xr VOP_SETEXTATTR 9
+.Sh HISTORY
+Extended attribute support was developed as part of the
+.Tn TrustedBSD
+Project, and introduced in
+.Fx 5.0 .
+It was developed to support security extensions requiring additional labels
+to be associated with each file or directory.
+.Sh BUGS
+In earlier versions of this API, passing an empty string for the
+attribute name to
+.Fn extattr_get_fd ,
+.Fn extattr_get_file ,
+or
+.Fn extattr_get_link
+would return the list of attributes defined for the target object.
+This interface has been deprecated in preference to using the explicit
+list API, and should not be used.
diff --git a/lib/libc/sys/fcntl.2 b/lib/libc/sys/fcntl.2
new file mode 100644
index 000000000000..cb91fbad079c
--- /dev/null
+++ b/lib/libc/sys/fcntl.2
@@ -0,0 +1,679 @@
+.\" Copyright (c) 1983, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)fcntl.2 8.2 (Berkeley) 1/12/94
+.\" $FreeBSD$
+.\"
+.Dd July 7, 2016
+.Dt FCNTL 2
+.Os
+.Sh NAME
+.Nm fcntl
+.Nd file control
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In fcntl.h
+.Ft int
+.Fn fcntl "int fd" "int cmd" "..."
+.Sh DESCRIPTION
+The
+.Fn fcntl
+system call provides for control over descriptors.
+The argument
+.Fa fd
+is a descriptor to be operated on by
+.Fa cmd
+as described below.
+Depending on the value of
+.Fa cmd ,
+.Fn fcntl
+can take an additional third argument
+.Fa "int arg" .
+.Bl -tag -width F_DUP2FD_CLOEXEC
+.It Dv F_DUPFD
+Return a new descriptor as follows:
+.Pp
+.Bl -bullet -compact -offset 4n
+.It
+Lowest numbered available descriptor greater than or equal to
+.Fa arg .
+.It
+Same object references as the original descriptor.
+.It
+New descriptor shares the same file offset if the object
+was a file.
+.It
+Same access mode (read, write or read/write).
+.It
+Same file status flags (i.e., both file descriptors
+share the same file status flags).
+.It
+The close-on-exec flag
+.Dv FD_CLOEXEC
+associated with the new file descriptor is cleared, so the file descriptor is
+to remain open across
+.Xr execve 2
+system calls.
+.El
+.It Dv F_DUPFD_CLOEXEC
+Like
+.Dv F_DUPFD ,
+but the
+.Dv FD_CLOEXEC
+flag associated with the new file descriptor is set, so the file descriptor
+is closed when
+.Xr execve 2
+system call executes.
+.It Dv F_DUP2FD
+It is functionally equivalent to
+.Bd -literal -offset indent
+dup2(fd, arg)
+.Ed
+.It Dv F_DUP2FD_CLOEXEC
+Like
+.Dv F_DUP2FD ,
+but the
+.Dv FD_CLOEXEC
+flag associated with the new file descriptor is set.
+.Pp
+The
+.Dv F_DUP2FD
+and
+.Dv F_DUP2FD_CLOEXEC
+constants are not portable, so they should not be used if
+portability is needed.
+Use
+.Fn dup2
+instead of
+.Dv F_DUP2FD .
+.It Dv F_GETFD
+Get the close-on-exec flag associated with the file descriptor
+.Fa fd
+as
+.Dv FD_CLOEXEC .
+If the returned value ANDed with
+.Dv FD_CLOEXEC
+is 0,
+the file will remain open across
+.Fn exec ,
+otherwise the file will be closed upon execution of
+.Fn exec
+.Fa ( arg
+is ignored).
+.It Dv F_SETFD
+Set the close-on-exec flag associated with
+.Fa fd
+to
+.Fa arg ,
+where
+.Fa arg
+is either 0 or
+.Dv FD_CLOEXEC ,
+as described above.
+.It Dv F_GETFL
+Get descriptor status flags, as described below
+.Fa ( arg
+is ignored).
+.It Dv F_SETFL
+Set descriptor status flags to
+.Fa arg .
+.It Dv F_GETOWN
+Get the process ID or process group
+currently receiving
+.Dv SIGIO
+and
+.Dv SIGURG
+signals; process groups are returned
+as negative values
+.Fa ( arg
+is ignored).
+.It Dv F_SETOWN
+Set the process or process group
+to receive
+.Dv SIGIO
+and
+.Dv SIGURG
+signals;
+process groups are specified by supplying
+.Fa arg
+as negative, otherwise
+.Fa arg
+is interpreted as a process ID.
+.It Dv F_READAHEAD
+Set or clear the read ahead amount for sequential access to the third
+argument,
+.Fa arg ,
+which is rounded up to the nearest block size.
+A zero value in
+.Fa arg
+turns off read ahead, a negative value restores the system default.
+.It Dv F_RDAHEAD
+Equivalent to Darwin counterpart which sets read ahead amount of 128KB
+when the third argument,
+.Fa arg
+is non-zero.
+A zero value in
+.Fa arg
+turns off read ahead.
+.El
+.Pp
+The flags for the
+.Dv F_GETFL
+and
+.Dv F_SETFL
+flags are as follows:
+.Bl -tag -width O_NONBLOCKX
+.It Dv O_NONBLOCK
+Non-blocking I/O; if no data is available to a
+.Xr read 2
+system call, or if a
+.Xr write 2
+operation would block,
+the read or write call returns -1 with the error
+.Er EAGAIN .
+.It Dv O_APPEND
+Force each write to append at the end of file;
+corresponds to the
+.Dv O_APPEND
+flag of
+.Xr open 2 .
+.It Dv O_DIRECT
+Minimize or eliminate the cache effects of reading and writing.
+The system
+will attempt to avoid caching the data you read or write.
+If it cannot
+avoid caching the data, it will minimize the impact the data has on the cache.
+Use of this flag can drastically reduce performance if not used with care.
+.It Dv O_ASYNC
+Enable the
+.Dv SIGIO
+signal to be sent to the process group
+when I/O is possible, e.g.,
+upon availability of data to be read.
+.El
+.Pp
+Several commands are available for doing advisory file locking;
+they all operate on the following structure:
+.Bd -literal
+struct flock {
+ off_t l_start; /* starting offset */
+ off_t l_len; /* len = 0 means until end of file */
+ pid_t l_pid; /* lock owner */
+ short l_type; /* lock type: read/write, etc. */
+ short l_whence; /* type of l_start */
+ int l_sysid; /* remote system id or zero for local */
+};
+.Ed
+The commands available for advisory record locking are as follows:
+.Bl -tag -width F_SETLKWX
+.It Dv F_GETLK
+Get the first lock that blocks the lock description pointed to by the
+third argument,
+.Fa arg ,
+taken as a pointer to a
+.Fa "struct flock"
+(see above).
+The information retrieved overwrites the information passed to
+.Fn fcntl
+in the
+.Fa flock
+structure.
+If no lock is found that would prevent this lock from being created,
+the structure is left unchanged by this system call except for the
+lock type which is set to
+.Dv F_UNLCK .
+.It Dv F_SETLK
+Set or clear a file segment lock according to the lock description
+pointed to by the third argument,
+.Fa arg ,
+taken as a pointer to a
+.Fa "struct flock"
+(see above).
+.Dv F_SETLK
+is used to establish shared (or read) locks
+.Pq Dv F_RDLCK
+or exclusive (or write) locks,
+.Pq Dv F_WRLCK ,
+as well as remove either type of lock
+.Pq Dv F_UNLCK .
+If a shared or exclusive lock cannot be set,
+.Fn fcntl
+returns immediately with
+.Er EAGAIN .
+.It Dv F_SETLKW
+This command is the same as
+.Dv F_SETLK
+except that if a shared or exclusive lock is blocked by other locks,
+the process waits until the request can be satisfied.
+If a signal that is to be caught is received while
+.Fn fcntl
+is waiting for a region, the
+.Fn fcntl
+will be interrupted if the signal handler has not specified the
+.Dv SA_RESTART
+(see
+.Xr sigaction 2 ) .
+.El
+.Pp
+When a shared lock has been set on a segment of a file,
+other processes can set shared locks on that segment
+or a portion of it.
+A shared lock prevents any other process from setting an exclusive
+lock on any portion of the protected area.
+A request for a shared lock fails if the file descriptor was not
+opened with read access.
+.Pp
+An exclusive lock prevents any other process from setting a shared lock or
+an exclusive lock on any portion of the protected area.
+A request for an exclusive lock fails if the file was not
+opened with write access.
+.Pp
+The value of
+.Fa l_whence
+is
+.Dv SEEK_SET ,
+.Dv SEEK_CUR ,
+or
+.Dv SEEK_END
+to indicate that the relative offset,
+.Fa l_start
+bytes, will be measured from the start of the file,
+current position, or end of the file, respectively.
+The value of
+.Fa l_len
+is the number of consecutive bytes to be locked.
+If
+.Fa l_len
+is negative,
+.Fa l_start
+means end edge of the region.
+The
+.Fa l_pid
+and
+.Fa l_sysid
+fields are only used with
+.Dv F_GETLK
+to return the process ID of the process holding a blocking lock and
+the system ID of the system that owns that process.
+Locks created by the local system will have a system ID of zero.
+After a successful
+.Dv F_GETLK
+request, the value of
+.Fa l_whence
+is
+.Dv SEEK_SET .
+.Pp
+Locks may start and extend beyond the current end of a file,
+but may not start or extend before the beginning of the file.
+A lock is set to extend to the largest possible value of the
+file offset for that file if
+.Fa l_len
+is set to zero.
+If
+.Fa l_whence
+and
+.Fa l_start
+point to the beginning of the file, and
+.Fa l_len
+is zero, the entire file is locked.
+If an application wishes only to do entire file locking, the
+.Xr flock 2
+system call is much more efficient.
+.Pp
+There is at most one type of lock set for each byte in the file.
+Before a successful return from an
+.Dv F_SETLK
+or an
+.Dv F_SETLKW
+request when the calling process has previously existing locks
+on bytes in the region specified by the request,
+the previous lock type for each byte in the specified
+region is replaced by the new lock type.
+As specified above under the descriptions
+of shared locks and exclusive locks, an
+.Dv F_SETLK
+or an
+.Dv F_SETLKW
+request fails or blocks respectively when another process has existing
+locks on bytes in the specified region and the type of any of those
+locks conflicts with the type specified in the request.
+.Pp
+The queuing for
+.Dv F_SETLKW
+requests on local files is fair;
+that is, while the thread is blocked,
+subsequent requests conflicting with its requests will not be granted,
+even if these requests do not conflict with existing locks.
+.Pp
+This interface follows the completely stupid semantics of System V and
+.St -p1003.1-88
+that require that all locks associated with a file for a given process are
+removed when
+.Em any
+file descriptor for that file is closed by that process.
+This semantic means that applications must be aware of any files that
+a subroutine library may access.
+For example if an application for updating the password file locks the
+password file database while making the update, and then calls
+.Xr getpwnam 3
+to retrieve a record,
+the lock will be lost because
+.Xr getpwnam 3
+opens, reads, and closes the password database.
+The database close will release all locks that the process has
+associated with the database, even if the library routine never
+requested a lock on the database.
+Another minor semantic problem with this interface is that
+locks are not inherited by a child process created using the
+.Xr fork 2
+system call.
+The
+.Xr flock 2
+interface has much more rational last close semantics and
+allows locks to be inherited by child processes.
+The
+.Xr flock 2
+system call is recommended for applications that want to ensure the integrity
+of their locks when using library routines or wish to pass locks
+to their children.
+.Pp
+The
+.Fn fcntl ,
+.Xr flock 2 ,
+and
+.Xr lockf 3
+locks are compatible.
+Processes using different locking interfaces can cooperate
+over the same file safely.
+However, only one of such interfaces should be used within
+the same process.
+If a file is locked by a process through
+.Xr flock 2 ,
+any record within the file will be seen as locked
+from the viewpoint of another process using
+.Fn fcntl
+or
+.Xr lockf 3 ,
+and vice versa.
+Note that
+.Fn fcntl F_GETLK
+returns \-1 in
+.Fa l_pid
+if the process holding a blocking lock previously locked the
+file descriptor by
+.Xr flock 2 .
+.Pp
+All locks associated with a file for a given process are
+removed when the process terminates.
+.Pp
+All locks obtained before a call to
+.Xr execve 2
+remain in effect until the new program releases them.
+If the new program does not know about the locks, they will not be
+released until the program exits.
+.Pp
+A potential for deadlock occurs if a process controlling a locked region
+is put to sleep by attempting to lock the locked region of another process.
+This implementation detects that sleeping until a locked region is unlocked
+would cause a deadlock and fails with an
+.Er EDEADLK
+error.
+.Sh RETURN VALUES
+Upon successful completion, the value returned depends on
+.Fa cmd
+as follows:
+.Bl -tag -width F_GETOWNX -offset indent
+.It Dv F_DUPFD
+A new file descriptor.
+.It Dv F_DUP2FD
+A file descriptor equal to
+.Fa arg .
+.It Dv F_GETFD
+Value of flag (only the low-order bit is defined).
+.It Dv F_GETFL
+Value of flags.
+.It Dv F_GETOWN
+Value of file descriptor owner.
+.It other
+Value other than -1.
+.El
+.Pp
+Otherwise, a value of -1 is returned and
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+The
+.Fn fcntl
+system call will fail if:
+.Bl -tag -width Er
+.It Bq Er EAGAIN
+The argument
+.Fa cmd
+is
+.Dv F_SETLK ,
+the type of lock
+.Pq Fa l_type
+is a shared lock
+.Pq Dv F_RDLCK
+or exclusive lock
+.Pq Dv F_WRLCK ,
+and the segment of a file to be locked is already
+exclusive-locked by another process;
+or the type is an exclusive lock and some portion of the
+segment of a file to be locked is already shared-locked or
+exclusive-locked by another process.
+.It Bq Er EBADF
+The
+.Fa fd
+argument
+is not a valid open file descriptor.
+.Pp
+The argument
+.Fa cmd
+is
+.Dv F_DUP2FD ,
+and
+.Fa arg
+is not a valid file descriptor.
+.Pp
+The argument
+.Fa cmd
+is
+.Dv F_SETLK
+or
+.Dv F_SETLKW ,
+the type of lock
+.Pq Fa l_type
+is a shared lock
+.Pq Dv F_RDLCK ,
+and
+.Fa fd
+is not a valid file descriptor open for reading.
+.Pp
+The argument
+.Fa cmd
+is
+.Dv F_SETLK
+or
+.Dv F_SETLKW ,
+the type of lock
+.Pq Fa l_type
+is an exclusive lock
+.Pq Dv F_WRLCK ,
+and
+.Fa fd
+is not a valid file descriptor open for writing.
+.It Bq Er EDEADLK
+The argument
+.Fa cmd
+is
+.Dv F_SETLKW ,
+and a deadlock condition was detected.
+.It Bq Er EINTR
+The argument
+.Fa cmd
+is
+.Dv F_SETLKW ,
+and the system call was interrupted by a signal.
+.It Bq Er EINVAL
+The
+.Fa cmd
+argument
+is
+.Dv F_DUPFD
+and
+.Fa arg
+is negative or greater than the maximum allowable number
+(see
+.Xr getdtablesize 2 ) .
+.Pp
+The argument
+.Fa cmd
+is
+.Dv F_GETLK ,
+.Dv F_SETLK
+or
+.Dv F_SETLKW
+and the data to which
+.Fa arg
+points is not valid.
+.It Bq Er EMFILE
+The argument
+.Fa cmd
+is
+.Dv F_DUPFD
+and the maximum number of file descriptors permitted for the
+process are already in use,
+or no file descriptors greater than or equal to
+.Fa arg
+are available.
+.It Bq Er ENOLCK
+The argument
+.Fa cmd
+is
+.Dv F_SETLK
+or
+.Dv F_SETLKW ,
+and satisfying the lock or unlock request would result in the
+number of locked regions in the system exceeding a system-imposed limit.
+.It Bq Er EOPNOTSUPP
+The argument
+.Fa cmd
+is
+.Dv F_GETLK ,
+.Dv F_SETLK
+or
+.Dv F_SETLKW
+and
+.Fa fd
+refers to a file for which locking is not supported.
+.It Bq Er EOVERFLOW
+The argument
+.Fa cmd
+is
+.Dv F_GETLK ,
+.Dv F_SETLK
+or
+.Dv F_SETLKW
+and an
+.Fa off_t
+calculation overflowed.
+.It Bq Er EPERM
+The
+.Fa cmd
+argument
+is
+.Dv F_SETOWN
+and
+the process ID or process group given as an argument is in a
+different session than the caller.
+.It Bq Er ESRCH
+The
+.Fa cmd
+argument
+is
+.Dv F_SETOWN
+and
+the process ID given as argument is not in use.
+.El
+.Pp
+In addition, if
+.Fa fd
+refers to a descriptor open on a terminal device (as opposed to a
+descriptor open on a socket), a
+.Fa cmd
+of
+.Dv F_SETOWN
+can fail for the same reasons as in
+.Xr tcsetpgrp 3 ,
+and a
+.Fa cmd
+of
+.Dv F_GETOWN
+for the reasons as stated in
+.Xr tcgetpgrp 3 .
+.Sh SEE ALSO
+.Xr close 2 ,
+.Xr dup2 2 ,
+.Xr execve 2 ,
+.Xr flock 2 ,
+.Xr getdtablesize 2 ,
+.Xr open 2 ,
+.Xr sigaction 2 ,
+.Xr lockf 3 ,
+.Xr tcgetpgrp 3 ,
+.Xr tcsetpgrp 3
+.Sh STANDARDS
+The
+.Dv F_DUP2FD
+constant is non portable.
+It is provided for compatibility with AIX and Solaris.
+.Pp
+Per
+.St -susv4 ,
+a call with
+.Dv F_SETLKW
+should fail with
+.Bq Er EINTR
+after any caught signal
+and should continue waiting during thread suspension such as a stop signal.
+However, in this implementation a call with
+.Dv F_SETLKW
+is restarted after catching a signal with a
+.Dv SA_RESTART
+handler or a thread suspension such as a stop signal.
+.Sh HISTORY
+The
+.Fn fcntl
+system call appeared in
+.Bx 4.2 .
+.Pp
+The
+.Dv F_DUP2FD
+constant first appeared in
+.Fx 7.1 .
diff --git a/lib/libc/sys/fcntl.c b/lib/libc/sys/fcntl.c
new file mode 100644
index 000000000000..e85574a6e0e3
--- /dev/null
+++ b/lib/libc/sys/fcntl.c
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 2008 Isilon Inc http://www.isilon.com/
+ * Authors: Doug Rabson <dfr@rabson.org>
+ * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org>
+ *
+ * Copyright (c) 2014-2015 The FreeBSD Foundation.
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Konstantin Belousov
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <fcntl.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/syscall.h>
+#include "libc_private.h"
+
+#pragma weak fcntl
+int
+fcntl(int fd, int cmd, ...)
+{
+ va_list args;
+ long arg;
+
+ va_start(args, cmd);
+ arg = va_arg(args, long);
+ va_end(args);
+
+ return (((int (*)(int, int, ...))
+ __libc_interposing[INTERPOS_fcntl])(fd, cmd, arg));
+}
diff --git a/lib/libc/sys/fdatasync.c b/lib/libc/sys/fdatasync.c
new file mode 100644
index 000000000000..fed97913d31e
--- /dev/null
+++ b/lib/libc/sys/fdatasync.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2016 The FreeBSD Foundation.
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Konstantin Belousov
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice(s), this list of conditions and the following disclaimer as
+ * the first lines of this file unmodified other than the possible
+ * addition of one or more copyright notices.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice(s), this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/fcntl.h>
+#include <unistd.h>
+#include "libc_private.h"
+
+int
+fdatasync(int fd)
+{
+
+ return (((int (*)(int))__libc_interposing[INTERPOS_fdatasync])(fd));
+}
diff --git a/lib/libc/sys/ffclock.2 b/lib/libc/sys/ffclock.2
new file mode 100644
index 000000000000..78fed527b148
--- /dev/null
+++ b/lib/libc/sys/ffclock.2
@@ -0,0 +1,177 @@
+.\" Copyright (c) 2011 The University of Melbourne
+.\" All rights reserved.
+.\"
+.\" This documentation was written by Julien Ridoux at the University of
+.\" Melbourne 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd November 21, 2011
+.Dt FFCLOCK 2
+.Os
+.Sh NAME
+.Nm ffclock_getcounter ,
+.Nm ffclock_getestimate ,
+.Nm ffclock_setestimate
+.Nd Retrieve feed-forward counter, get and set feed-forward clock estimates
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/timeffc.h
+.Ft int
+.Fn ffclock_getcounter "ffcounter *ffcount"
+.Ft int
+.Fn ffclock_getestimate "struct ffclock_estimate *cest"
+.Ft int
+.Fn ffclock_setestimate "struct ffclock_estimate *cest"
+.Sh DESCRIPTION
+The ffclock is an alternative method to synchronise the system clock.
+The ffclock implements a feed-forward paradigm and decouples the timestamping
+and timekeeping kernel functions.
+This ensures that past clock errors do not affect current timekeeping, an
+approach radically different from the feedback alternative implemented by the
+ntpd daemon when adjusting the system clock.
+The feed-forward approach has demonstrated better performance and higher
+robustness than a feedback approach when synchronising over the network.
+.Pp
+In the feed-forward context, a
+.Em timestamp
+is a cumulative value of the ticks of the timecounter, which can be converted
+into seconds by using the feed-forward
+.Em clock estimates .
+.Pp
+The
+.Fn ffclock_getcounter
+system call allows the calling process to retrieve the current value of the
+feed-forward counter maintained by the kernel.
+.Pp
+The
+.Fn ffclock_getestimate
+and
+.Fn ffclock_setestimate
+system calls allow the caller to get and set the kernel's feed-forward clock
+parameter estimates respectively.
+The
+.Fn ffclock_setestimate
+system call should be invoked by a single instance of a feed-forward
+synchronisation daemon.
+The
+.Fn ffclock_getestimate
+system call can be called by any process to retrieve the feed-forward clock
+estimates.
+.Pp
+The feed-forward approach does not require that the clock estimates be retrieved
+every time a timestamp is to be converted into seconds.
+The number of system calls can therefore be greatly reduced if the calling
+process retrieves the clock estimates from the clock synchronisation daemon
+instead.
+The
+.Fn ffclock_getestimate
+must be used when the feed-forward synchronisation daemon is not running
+.Po see
+.Sx USAGE
+below
+.Pc .
+.Pp
+The clock parameter estimates structure pointed to by
+.Fa cest
+is defined in
+.In sys/timeffc.h
+as:
+.Bd -literal
+struct ffclock_estimate {
+ struct bintime update_time; /* Time of last estimates update. */
+ ffcounter update_ffcount; /* Counter value at last update. */
+ ffcounter leapsec_next; /* Counter value of next leap second. */
+ uint64_t period; /* Estimate of counter period. */
+ uint32_t errb_abs; /* Bound on absolute clock error [ns]. */
+ uint32_t errb_rate; /* Bound on counter rate error [ps/s]. */
+ uint32_t status; /* Clock status. */
+ int16_t leapsec_total; /* All leap seconds seen so far. */
+ int8_t leapsec; /* Next leap second (in {-1,0,1}). */
+};
+.Ed
+.Pp
+Only the super-user may set the feed-forward clock estimates.
+.Sh RETURN VALUES
+.Rv -std
+.Sh ERRORS
+The following error codes may be set in
+.Va errno :
+.Bl -tag -width Er
+.It Bq Er EFAULT
+The
+.Fa ffcount
+or
+.Fa cest
+pointer referenced invalid memory.
+.It Bq Er EPERM
+A user other than the super-user attempted to set the feed-forward clock
+parameter estimates.
+.El
+.Sh USAGE
+The feed-forward paradigm enables the definition of specialised clock functions.
+.Pp
+In its simplest form,
+.Fn ffclock_getcounter
+can be used to establish strict order between events or to measure small time
+intervals very accurately with a minimum performance cost.
+.Pp
+Different methods exist to access absolute time
+.Po or
+.Qq wall-clock time
+.Pc tracked by the ffclock.
+The simplest method uses the ffclock sysctl interface
+.Va kern.ffclock
+to make the system clock return the ffclock time.
+The
+.Xr clock_gettime 2
+system call can then be used to retrieve the current time seen by the
+feed-forward clock.
+Note that this setting affects the entire system and that a feed-forward
+synchronisation daemon should be running.
+.Pp
+A less automated method consists of retrieving the feed-forward counter
+timestamp from the kernel and using the feed-forward clock parameter estimates
+to convert the timestamp into seconds.
+The feed-forward clock parameter estimates can be retrieved from the kernel or
+from the synchronisation daemon directly (preferred).
+This method allows converting timestamps using different clock models as needed
+by the application, while collecting meaningful upper bounds on current clock
+error.
+.Sh SEE ALSO
+.Xr date 1 ,
+.Xr adjtime 2 ,
+.Xr clock_gettime 2 ,
+.Xr ctime 3
+.Sh HISTORY
+Feed-forward clock support first appeared in
+.Fx 10.0 .
+.Sh AUTHORS
+.An -nosplit
+The feed-forward clock support was written by
+.An Julien Ridoux Aq Mt jridoux@unimelb.edu.au
+in collaboration with
+.An Darryl Veitch Aq Mt dveitch@unimelb.edu.au
+at the University of Melbourne under sponsorship from the FreeBSD Foundation.
diff --git a/lib/libc/sys/fhopen.2 b/lib/libc/sys/fhopen.2
new file mode 100644
index 000000000000..2a609c1c2cd2
--- /dev/null
+++ b/lib/libc/sys/fhopen.2
@@ -0,0 +1,147 @@
+.\" $NetBSD: fhopen.2,v 1.1 1999/06/30 01:32:15 wrstuden Exp $
+.\"
+.\" Copyright (c) 1999 National Aeronautics & Space Administration
+.\" All rights reserved.
+.\"
+.\" This software was written by William Studenmund of the
+.\" Numerical Aerospace Simulation Facility, NASA Ames Research Center.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the National Aeronautics & Space Administration
+.\" nor the names of its contributors may be used to endorse or promote
+.\" products derived from this software without specific prior written
+.\" permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NATIONAL AERONAUTICS & SPACE ADMINISTRATION
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ADMINISTRATION OR CONTRIB-
+.\" UTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+.\" OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd June 29, 1999
+.Dt FHOPEN 2
+.Os
+.Sh NAME
+.Nm fhopen ,
+.Nm fhstat ,
+.Nm fhstatfs
+.Nd access file via file handle
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/param.h
+.In sys/mount.h
+.In sys/stat.h
+.Ft int
+.Fn fhopen "const fhandle_t *fhp" "int flags"
+.Ft int
+.Fn fhstat "const fhandle_t *fhp" "struct stat *sb"
+.Ft int
+.Fn fhstatfs "const fhandle_t *fhp" "struct statfs *buf"
+.Sh DESCRIPTION
+These system calls provide a means to access a file given the file handle
+.Fa fhp .
+As this method bypasses directory access restrictions, these calls are
+restricted to the superuser.
+.Pp
+The
+.Fn fhopen
+system call
+opens the file referenced by
+.Fa fhp
+for reading and/or writing as specified by the argument
+.Fa flags
+and returns the file descriptor to the calling process.
+The
+.Fa flags
+argument
+is specified by
+.Em or Ns 'ing
+together the flags used for the
+.Xr open 2
+system call.
+All said flags are valid except for
+.Dv O_CREAT .
+.Pp
+The
+.Fn fhstat
+and
+.Fn fhstatfs
+system calls
+provide the functionality of the
+.Xr fstat 2
+and
+.Xr fstatfs 2
+calls except that they return information for the file referred to by
+.Fa fhp
+rather than an open file.
+.Sh RETURN VALUES
+Upon successful completion,
+.Fn fhopen
+returns the file descriptor for the opened file;
+otherwise the value \-1 is returned and the global variable
+.Va errno
+is set to indicate the error.
+.Pp
+.Rv -std fhstat fhstatfs
+.Sh ERRORS
+In addition to the errors returned by
+.Xr open 2 ,
+.Xr fstat 2 ,
+and
+.Xr fstatfs 2
+respectively,
+.Fn fhopen ,
+.Fn fhstat ,
+and
+.Fn fhstatfs
+will return
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Calling
+.Fn fhopen
+with
+.Dv O_CREAT
+set.
+.It Bq Er ESTALE
+The file handle
+.Fa fhp
+is no longer valid.
+.El
+.Sh SEE ALSO
+.Xr fstat 2 ,
+.Xr fstatfs 2 ,
+.Xr getfh 2 ,
+.Xr open 2
+.Sh HISTORY
+The
+.Fn fhopen ,
+.Fn fhstat ,
+and
+.Fn fhstatfs
+system calls first appeared in
+.Nx 1.5
+and were adapted to
+.Fx 4.0
+by
+.An Alfred Perlstein .
+.Sh AUTHORS
+This manual page was written by
+.An William Studenmund
+for
+.Nx .
diff --git a/lib/libc/sys/flock.2 b/lib/libc/sys/flock.2
new file mode 100644
index 000000000000..6106bf4f5100
--- /dev/null
+++ b/lib/libc/sys/flock.2
@@ -0,0 +1,173 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)flock.2 8.2 (Berkeley) 12/11/93
+.\" $FreeBSD$
+.\"
+.Dd November 9, 2011
+.Dt FLOCK 2
+.Os
+.Sh NAME
+.Nm flock
+.Nd "apply or remove an advisory lock on an open file"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/file.h
+.Fd "#define LOCK_SH 0x01 /* shared file lock */"
+.Fd "#define LOCK_EX 0x02 /* exclusive file lock */"
+.Fd "#define LOCK_NB 0x04 /* do not block when locking */"
+.Fd "#define LOCK_UN 0x08 /* unlock file */"
+.Ft int
+.Fn flock "int fd" "int operation"
+.Sh DESCRIPTION
+The
+.Fn flock
+system call applies or removes an
+.Em advisory
+lock on the file associated with the file descriptor
+.Fa fd .
+A lock is applied by specifying an
+.Fa operation
+argument that is one of
+.Dv LOCK_SH
+or
+.Dv LOCK_EX
+with the optional addition of
+.Dv LOCK_NB .
+To unlock
+an existing lock
+.Dv operation
+should be
+.Dv LOCK_UN .
+.Pp
+Advisory locks allow cooperating processes to perform
+consistent operations on files, but do not guarantee
+consistency (i.e., processes may still access files
+without using advisory locks possibly resulting in
+inconsistencies).
+.Pp
+The locking mechanism allows two types of locks:
+.Em shared
+locks and
+.Em exclusive
+locks.
+At any time multiple shared locks may be applied to a file,
+but at no time are multiple exclusive, or both shared and exclusive,
+locks allowed simultaneously on a file.
+.Pp
+A shared lock may be
+.Em upgraded
+to an exclusive lock, and vice versa, simply by specifying
+the appropriate lock type; this results in the previous
+lock being released and the new lock applied (possibly
+after other processes have gained and released the lock).
+.Pp
+Requesting a lock on an object that is already locked
+normally causes the caller to be blocked until the lock may be
+acquired.
+If
+.Dv LOCK_NB
+is included in
+.Fa operation ,
+then this will not happen; instead the call will fail and
+the error
+.Er EWOULDBLOCK
+will be returned.
+.Sh NOTES
+Locks are on files, not file descriptors.
+That is, file descriptors
+duplicated through
+.Xr dup 2
+or
+.Xr fork 2
+do not result in multiple instances of a lock, but rather multiple
+references to a single lock.
+If a process holding a lock on a file
+forks and the child explicitly unlocks the file, the parent will
+lose its lock.
+.Pp
+The
+.Fn flock ,
+.Xr fcntl 2 ,
+and
+.Xr lockf 3
+locks are compatible.
+Processes using different locking interfaces can cooperate
+over the same file safely.
+However, only one of such interfaces should be used within
+the same process.
+If a file is locked by a process through
+.Fn flock ,
+any record within the file will be seen as locked
+from the viewpoint of another process using
+.Xr fcntl 2
+or
+.Xr lockf 3 ,
+and vice versa.
+.Pp
+Processes blocked awaiting a lock may be awakened by signals.
+.Sh RETURN VALUES
+.Rv -std flock
+.Sh ERRORS
+The
+.Fn flock
+system call fails if:
+.Bl -tag -width Er
+.It Bq Er EWOULDBLOCK
+The file is locked and the
+.Dv LOCK_NB
+option was specified.
+.It Bq Er EBADF
+The argument
+.Fa fd
+is an invalid descriptor.
+.It Bq Er EINVAL
+The argument
+.Fa fd
+refers to an object other than a file.
+.It Bq Er EOPNOTSUPP
+The argument
+.Fa fd
+refers to an object that does not support file locking.
+.It Bq Er ENOLCK
+A lock was requested, but no locks are available.
+.El
+.Sh SEE ALSO
+.Xr close 2 ,
+.Xr dup 2 ,
+.Xr execve 2 ,
+.Xr fcntl 2 ,
+.Xr fork 2 ,
+.Xr open 2 ,
+.Xr flopen 3 ,
+.Xr lockf 3
+.Sh HISTORY
+The
+.Fn flock
+system call appeared in
+.Bx 4.2 .
diff --git a/lib/libc/sys/fork.2 b/lib/libc/sys/fork.2
new file mode 100644
index 000000000000..4fda74d605e7
--- /dev/null
+++ b/lib/libc/sys/fork.2
@@ -0,0 +1,148 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)fork.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd May 1, 2015
+.Dt FORK 2
+.Os
+.Sh NAME
+.Nm fork
+.Nd create a new process
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft pid_t
+.Fn fork void
+.Sh DESCRIPTION
+The
+.Fn fork
+system call causes creation of a new process.
+The new process (child process) is an exact copy of the
+calling process (parent process) except for the following:
+.Bl -bullet -offset indent
+.It
+The child process has a unique process ID.
+.It
+The child process has a different parent
+process ID (i.e., the process ID of the parent process).
+.It
+The child process has its own copy of the parent's descriptors,
+except for descriptors returned by
+.Xr kqueue 2 ,
+which are not inherited from the parent process.
+These descriptors reference the same underlying objects, so that,
+for instance, file pointers in file objects are shared between
+the child and the parent, so that an
+.Xr lseek 2
+on a descriptor in the child process can affect a subsequent
+.Xr read 2
+or
+.Xr write 2
+by the parent.
+This descriptor copying is also used by the shell to
+establish standard input and output for newly created processes
+as well as to set up pipes.
+.It
+The child process' resource utilizations
+are set to 0; see
+.Xr setrlimit 2 .
+.It
+All interval timers are cleared; see
+.Xr setitimer 2 .
+.It
+The child process has only one thread,
+corresponding to the calling thread in the parent process.
+If the process has more than one thread,
+locks and other resources held by the other threads are not released
+and therefore only async-signal-safe functions
+(see
+.Xr sigaction 2 )
+are guaranteed to work in the child process until a call to
+.Xr execve 2
+or a similar function.
+.El
+.Sh RETURN VALUES
+Upon successful completion,
+.Fn fork
+returns a value
+of 0 to the child process and returns the process ID of the child
+process to the parent process.
+Otherwise, a value of -1 is returned
+to the parent process, no child process is created, and the global
+variable
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+The
+.Fn fork
+system call will fail and no child process will be created if:
+.Bl -tag -width Er
+.It Bq Er EAGAIN
+The system-imposed limit on the total
+number of processes under execution would be exceeded.
+The limit is given by the
+.Xr sysctl 3
+MIB variable
+.Dv KERN_MAXPROC .
+(The limit is actually ten less than this
+except for the super user).
+.It Bq Er EAGAIN
+The user is not the super user, and
+the system-imposed limit
+on the total number of
+processes under execution by a single user would be exceeded.
+The limit is given by the
+.Xr sysctl 3
+MIB variable
+.Dv KERN_MAXPROCPERUID .
+.It Bq Er EAGAIN
+The user is not the super user, and
+the soft resource limit corresponding to the
+.Fa resource
+argument
+.Dv RLIMIT_NPROC
+would be exceeded (see
+.Xr getrlimit 2 ) .
+.It Bq Er ENOMEM
+There is insufficient swap space for the new process.
+.El
+.Sh SEE ALSO
+.Xr execve 2 ,
+.Xr rfork 2 ,
+.Xr setitimer 2 ,
+.Xr setrlimit 2 ,
+.Xr sigaction 2 ,
+.Xr vfork 2 ,
+.Xr wait 2
+.Sh HISTORY
+The
+.Fn fork
+function appeared in
+.At v6 .
diff --git a/lib/libc/sys/fork.c b/lib/libc/sys/fork.c
new file mode 100644
index 000000000000..695540a7264f
--- /dev/null
+++ b/lib/libc/sys/fork.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2014 The FreeBSD Foundation.
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Konstantin Belousov
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice(s), this list of conditions and the following disclaimer as
+ * the first lines of this file unmodified other than the possible
+ * addition of one or more copyright notices.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice(s), this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <unistd.h>
+#include "libc_private.h"
+
+__weak_reference(__sys_fork, __fork);
+
+#pragma weak fork
+pid_t
+fork(void)
+{
+
+ return (((pid_t (*)(void))__libc_interposing[INTERPOS_fork])());
+}
diff --git a/lib/libc/sys/fsync.2 b/lib/libc/sys/fsync.2
new file mode 100644
index 000000000000..3f83291a0dbb
--- /dev/null
+++ b/lib/libc/sys/fsync.2
@@ -0,0 +1,130 @@
+.\" Copyright (c) 1983, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\" Copyright (c) 2016 The FreeBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" Parts of this documentation were 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:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)fsync.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd August 17, 2016
+.Dt FSYNC 2
+.Os
+.Sh NAME
+.Nm fdatasync, fsync
+.Nd "synchronise changes to a file"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft int
+.Fn fdatasync "int fd"
+.Ft int
+.Fn fsync "int fd"
+.Sh DESCRIPTION
+The
+.Fn fsync
+system call
+causes all modified data and attributes of the file referenced by
+the file descriptor
+.Fa fd
+to be moved to a permanent storage device.
+This normally results in all in-core modified copies
+of buffers for the associated file to be written to a disk.
+.Pp
+The
+.Fn fdatasync
+system call causes all modified data of
+.Fa fd
+to be moved to a permanent storage device.
+Unlike
+.Fn fsync ,
+the system call does not guarantee that file attributes or
+metadata necessary to access the file are committed to the permanent storage.
+.Pp
+The
+.Fn fsync
+system call
+should be used by programs that require a file to be
+in a known state, for example, in building a simple transaction
+facility.
+If the file metadata has already been committed, using
+.Fn fdatasync
+can be more efficient than
+.Fn fsync .
+.Pp
+Both
+.Fn fdatasync
+and
+.Fn fsync
+calls are cancellation points.
+.Sh RETURN VALUES
+.Rv -std fsync
+.Sh ERRORS
+The
+.Fn fsync
+and
+.Fn fdatasync
+calls fail if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa fd
+argument
+is not a valid descriptor.
+.It Bq Er EINVAL
+The
+.Fa fd
+argument
+refers to a socket, not to a file.
+.It Bq Er EIO
+An I/O error occurred while reading from or writing to the file system.
+.El
+.Sh SEE ALSO
+.Xr sync 2 ,
+.Xr syncer 4 ,
+.Xr sync 8
+.Sh HISTORY
+The
+.Fn fsync
+system call appeared in
+.Bx 4.2 .
+The
+.Fn fdatasync
+system call appeared in
+.Fx 12.0
+.Sh BUGS
+The
+.Fn fdatasync
+system call currently does not guarantee that enqueued
+.Xr aio 4
+requests for the file referenced by
+.Fa fd
+are completed before the syscall returns.
diff --git a/lib/libc/sys/fsync.c b/lib/libc/sys/fsync.c
new file mode 100644
index 000000000000..5f1512932baa
--- /dev/null
+++ b/lib/libc/sys/fsync.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2014 The FreeBSD Foundation.
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Konstantin Belousov
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice(s), this list of conditions and the following disclaimer as
+ * the first lines of this file unmodified other than the possible
+ * addition of one or more copyright notices.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice(s), this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/fcntl.h>
+#include <unistd.h>
+#include "libc_private.h"
+
+__weak_reference(__sys_fsync, __fsync);
+
+int
+fsync(int fd)
+{
+
+ return (((int (*)(int))__libc_interposing[INTERPOS_fsync])(fd));
+}
diff --git a/lib/libc/sys/futimens.c b/lib/libc/sys/futimens.c
new file mode 100644
index 000000000000..59fb37f5249a
--- /dev/null
+++ b/lib/libc/sys/futimens.c
@@ -0,0 +1,100 @@
+/*-
+ * Copyright (c) 2015 Jilles Tjoelker
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <time.h>
+#include "un-namespace.h"
+
+#include "libc_private.h"
+
+int
+futimens(int fd, const struct timespec times[2])
+{
+ struct timeval now, tv[2], *tvp;
+ struct stat sb;
+ int osreldate;
+
+ osreldate = __getosreldate();
+ if (osreldate >= 1100056 ||
+ (osreldate >= 1002506 && osreldate < 1100000))
+ return (__sys_futimens(fd, times));
+
+ if (times == NULL || (times[0].tv_nsec == UTIME_NOW &&
+ times[1].tv_nsec == UTIME_NOW))
+ tvp = NULL;
+ else if (times[0].tv_nsec == UTIME_OMIT &&
+ times[1].tv_nsec == UTIME_OMIT)
+ return (0);
+ else {
+ if ((times[0].tv_nsec < 0 || times[0].tv_nsec > 999999999) &&
+ times[0].tv_nsec != UTIME_NOW &&
+ times[0].tv_nsec != UTIME_OMIT) {
+ errno = EINVAL;
+ return (-1);
+ }
+ if ((times[1].tv_nsec < 0 || times[1].tv_nsec > 999999999) &&
+ times[1].tv_nsec != UTIME_NOW &&
+ times[1].tv_nsec != UTIME_OMIT) {
+ errno = EINVAL;
+ return (-1);
+ }
+ tv[0].tv_sec = times[0].tv_sec;
+ tv[0].tv_usec = times[0].tv_nsec / 1000;
+ tv[1].tv_sec = times[1].tv_sec;
+ tv[1].tv_usec = times[1].tv_nsec / 1000;
+ tvp = tv;
+ if (times[0].tv_nsec == UTIME_OMIT ||
+ times[1].tv_nsec == UTIME_OMIT) {
+ if (_fstat(fd, &sb) == -1)
+ return (-1);
+ if (times[0].tv_nsec == UTIME_OMIT) {
+ tv[0].tv_sec = sb.st_atim.tv_sec;
+ tv[0].tv_usec = sb.st_atim.tv_nsec / 1000;
+ }
+ if (times[1].tv_nsec == UTIME_OMIT) {
+ tv[1].tv_sec = sb.st_mtim.tv_sec;
+ tv[1].tv_usec = sb.st_mtim.tv_nsec / 1000;
+ }
+ }
+ if (times[0].tv_nsec == UTIME_NOW ||
+ times[1].tv_nsec == UTIME_NOW) {
+ if (gettimeofday(&now, NULL) == -1)
+ return (-1);
+ if (times[0].tv_nsec == UTIME_NOW)
+ tv[0] = now;
+ if (times[1].tv_nsec == UTIME_NOW)
+ tv[1] = now;
+ }
+ }
+ return (futimes(fd, tvp));
+}
diff --git a/lib/libc/sys/getdirentries.2 b/lib/libc/sys/getdirentries.2
new file mode 100644
index 000000000000..e4f61dbe82da
--- /dev/null
+++ b/lib/libc/sys/getdirentries.2
@@ -0,0 +1,186 @@
+.\" Copyright (c) 1989, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)getdirentries.2 8.2 (Berkeley) 5/3/95
+.\" $FreeBSD$
+.\"
+.Dd May 3, 1995
+.Dt GETDIRENTRIES 2
+.Os
+.Sh NAME
+.Nm getdirentries ,
+.Nm getdents
+.Nd "get directory entries in a file system independent format"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In dirent.h
+.Ft int
+.Fn getdirentries "int fd" "char *buf" "int nbytes" "long *basep"
+.Ft int
+.Fn getdents "int fd" "char *buf" "int nbytes"
+.Sh DESCRIPTION
+The
+.Fn getdirentries
+and
+.Fn getdents
+system calls read directory entries from the directory
+referenced by the file descriptor
+.Fa fd
+into the buffer pointed to by
+.Fa buf ,
+in a file system independent format.
+Up to
+.Fa nbytes
+of data will be transferred.
+The
+.Fa nbytes
+argument must be greater than or equal to the
+block size associated with the file,
+see
+.Xr stat 2 .
+Some file systems may not support these system calls
+with buffers smaller than this size.
+.Pp
+The data in the buffer is a series of
+.Vt dirent
+structures each containing the following entries:
+.Bd -literal -offset indent
+uint32_t d_fileno;
+uint16_t d_reclen;
+uint8_t d_type;
+uint8_t d_namlen;
+char d_name[MAXNAMLEN + 1]; /* see below */
+.Ed
+.Pp
+The
+.Fa d_fileno
+entry is a number which is unique for each
+distinct file in the file system.
+Files that are linked by hard links (see
+.Xr link 2 )
+have the same
+.Fa d_fileno .
+The
+.Fa d_reclen
+entry is the length, in bytes, of the directory record.
+The
+.Fa d_type
+entry is the type of the file pointed to by the directory record.
+The file type values are defined in
+.Fa <sys/dirent.h> .
+The
+.Fa d_name
+entry contains a null terminated file name.
+The
+.Fa d_namlen
+entry specifies the length of the file name excluding the null byte.
+Thus the actual size of
+.Fa d_name
+may vary from 1 to
+.Dv MAXNAMLEN
+\&+ 1.
+.Pp
+Entries may be separated by extra space.
+The
+.Fa d_reclen
+entry may be used as an offset from the start of a
+.Fa dirent
+structure to the next structure, if any.
+.Pp
+The actual number of bytes transferred is returned.
+The current position pointer associated with
+.Fa fd
+is set to point to the next block of entries.
+The pointer may not advance by the number of bytes returned by
+.Fn getdirentries
+or
+.Fn getdents .
+A value of zero is returned when
+the end of the directory has been reached.
+.Pp
+The
+.Fn getdirentries
+system call writes the position of the block read into the location pointed to by
+.Fa basep .
+Alternatively, the current position pointer may be set and retrieved by
+.Xr lseek 2 .
+The current position pointer should only be set to a value returned by
+.Xr lseek 2 ,
+a value returned in the location pointed to by
+.Fa basep
+.Po Fn getdirentries
+only
+.Pc
+or zero.
+.Sh RETURN VALUES
+If successful, the number of bytes actually transferred is returned.
+Otherwise, -1 is returned and the global variable
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+The
+.Fn getdirentries
+system call
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa fd
+argument
+is not a valid file descriptor open for reading.
+.It Bq Er EFAULT
+Either
+.Fa buf
+or
+.Fa basep
+point outside the allocated address space.
+.It Bq Er EINVAL
+The file referenced by
+.Fa fd
+is not a directory, or
+.Fa nbytes
+is too small for returning a directory entry or block of entries,
+or the current position pointer is invalid.
+.It Bq Er EIO
+An
+.Tn I/O
+error occurred while reading from or writing to the file system.
+.El
+.Sh SEE ALSO
+.Xr lseek 2 ,
+.Xr open 2
+.Sh HISTORY
+The
+.Fn getdirentries
+system call first appeared in
+.Bx 4.4 .
+The
+.Fn getdents
+system call first appeared in
+.Fx 3.0 .
diff --git a/lib/libc/sys/getdtablesize.2 b/lib/libc/sys/getdtablesize.2
new file mode 100644
index 000000000000..c47189123bd8
--- /dev/null
+++ b/lib/libc/sys/getdtablesize.2
@@ -0,0 +1,62 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)getdtablesize.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd April 24, 2013
+.Dt GETDTABLESIZE 2
+.Os
+.Sh NAME
+.Nm getdtablesize
+.Nd get file descriptor limit
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft int
+.Fn getdtablesize void
+.Sh DESCRIPTION
+The
+.Fn getdtablesize
+system call returns the maximum number of file descriptors
+that the current process may open.
+The maximum file descriptor number that the system may assign
+is the return value minus one.
+Existing file descriptor numbers may be higher
+if the limit was lowered after they were opened.
+.Sh SEE ALSO
+.Xr close 2 ,
+.Xr closefrom 2 ,
+.Xr dup 2 ,
+.Xr getrlimit 2 ,
+.Xr sysconf 3
+.Sh HISTORY
+The
+.Fn getdtablesize
+system call appeared in
+.Bx 4.2 .
diff --git a/lib/libc/sys/getfh.2 b/lib/libc/sys/getfh.2
new file mode 100644
index 000000000000..b44d4af001f0
--- /dev/null
+++ b/lib/libc/sys/getfh.2
@@ -0,0 +1,115 @@
+.\" Copyright (c) 1989, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)getfh.2 8.1 (Berkeley) 6/9/93
+.\" $FreeBSD$
+.\"
+.Dd April 14, 2011
+.Dt GETFH 2
+.Os
+.Sh NAME
+.Nm getfh ,
+.Nm lgetfh
+.Nd get file handle
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/param.h
+.In sys/mount.h
+.Ft int
+.Fn getfh "const char *path" "fhandle_t *fhp"
+.Ft int
+.Fn lgetfh "const char *path" "fhandle_t *fhp"
+.Sh DESCRIPTION
+The
+.Fn getfh
+system call
+returns a file handle for the specified file or directory
+in the file handle pointed to by
+.Fa fhp .
+The
+.Fn lgetfh
+system call is like
+.Fn getfh
+except in the case where the named file is a symbolic link,
+in which case
+.Fn lgetfh
+returns information about the link,
+while
+.Fn getfh
+returns information about the file the link references.
+These system calls are restricted to the superuser.
+.Sh RETURN VALUES
+.Rv -std
+.Sh ERRORS
+The
+.Fn getfh
+and
+.Fn lgetfh
+system calls
+fail if one or more of the following are true:
+.Bl -tag -width Er
+.It Bq Er ENOTDIR
+A component of the path prefix of
+.Fa path
+is not a directory.
+.It Bq Er ENAMETOOLONG
+The length of a component of
+.Fa path
+exceeds 255 characters,
+or the length of
+.Fa path
+exceeds 1023 characters.
+.It Bq Er ENOENT
+The file referred to by
+.Fa path
+does not exist.
+.It Bq Er EACCES
+Search permission is denied for a component of the path prefix of
+.Fa path .
+.It Bq Er ELOOP
+Too many symbolic links were encountered in translating
+.Fa path .
+.It Bq Er EFAULT
+The
+.Fa fhp
+argument
+points to an invalid address.
+.It Bq Er EIO
+An
+.Tn I/O
+error occurred while reading from or writing to the file system.
+.El
+.Sh SEE ALSO
+.Xr fhopen 2 ,
+.Xr open 2 ,
+.Xr stat 2
+.Sh HISTORY
+The
+.Fn getfh
+system call first appeared in
+.Bx 4.4 .
diff --git a/lib/libc/sys/getfsstat.2 b/lib/libc/sys/getfsstat.2
new file mode 100644
index 000000000000..08cdf49d6e39
--- /dev/null
+++ b/lib/libc/sys/getfsstat.2
@@ -0,0 +1,130 @@
+.\" Copyright (c) 1989, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)getfsstat.2 8.3 (Berkeley) 5/25/95
+.\" $FreeBSD$
+.\"
+.Dd December 27, 2016
+.Dt GETFSSTAT 2
+.Os
+.Sh NAME
+.Nm getfsstat
+.Nd get list of all mounted file systems
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/param.h
+.In sys/ucred.h
+.In sys/mount.h
+.Ft int
+.Fn getfsstat "struct statfs *buf" "long bufsize" "int mode"
+.Sh DESCRIPTION
+The
+.Fn getfsstat
+system call
+returns information about all mounted file systems.
+The
+.Fa buf
+argument
+is a pointer to
+.Vt statfs
+structures, as described in
+.Xr statfs 2 .
+.Pp
+Fields that are undefined for a particular file system are set to -1.
+The buffer is filled with an array of
+.Fa statfs
+structures, one for each mounted file system
+up to the byte count specified by
+.Fa bufsize .
+Note, the
+.Fa bufsize
+argument is the number of bytes that
+.Fa buf
+can hold, not the count of statfs structures it will hold.
+.Pp
+If
+.Fa buf
+is given as NULL,
+.Fn getfsstat
+returns just the number of mounted file systems.
+.Pp
+Normally
+.Fa mode
+should be specified as
+.Dv MNT_WAIT .
+If
+.Fa mode
+is set to
+.Dv MNT_NOWAIT ,
+.Fn getfsstat
+will return the information it has available without requesting
+an update from each file system.
+Thus, some of the information will be out of date, but
+.Fn getfsstat
+will not block waiting for information from a file system that is
+unable to respond.
+It will also skip any file system that is in the process of being
+unmounted, even if the unmount would eventually fail.
+.Sh RETURN VALUES
+Upon successful completion, the number of
+.Fa statfs
+structures is returned.
+Otherwise, -1 is returned and the global variable
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+The
+.Fn getfsstat
+system call
+fails if one or more of the following are true:
+.Bl -tag -width Er
+.It Bq Er EFAULT
+The
+.Fa buf
+argument
+points to an invalid address.
+.It Bq Er EINVAL
+.Fa mode
+is set to a value other than
+.Dv MNT_WAIT
+or
+.Dv MNT_NOWAIT .
+.It Bq Er EIO
+An
+.Tn I/O
+error occurred while reading from or writing to the file system.
+.El
+.Sh SEE ALSO
+.Xr statfs 2 ,
+.Xr fstab 5 ,
+.Xr mount 8
+.Sh HISTORY
+The
+.Fn getfsstat
+system call first appeared in
+.Bx 4.4 .
diff --git a/lib/libc/sys/getgid.2 b/lib/libc/sys/getgid.2
new file mode 100644
index 000000000000..5bd2a94b9dc1
--- /dev/null
+++ b/lib/libc/sys/getgid.2
@@ -0,0 +1,80 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)getgid.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd December 15, 2015
+.Dt GETGID 2
+.Os
+.Sh NAME
+.Nm getgid ,
+.Nm getegid
+.Nd get group process identification
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft gid_t
+.Fn getgid void
+.Ft gid_t
+.Fn getegid void
+.Sh DESCRIPTION
+The
+.Fn getgid
+system call returns the real group ID of the calling process,
+.Fn getegid
+returns the effective group ID of the calling process.
+.Pp
+The real group ID is specified at login time.
+.Pp
+The real group ID is the group of the user who invoked the program.
+As the effective group ID gives the process additional permissions
+during the execution of
+.Dq Em set-group-ID
+mode processes,
+.Fn getgid
+is used to determine the real-user-id of the calling process.
+.Sh ERRORS
+The
+.Fn getgid
+and
+.Fn getegid
+system calls are always successful, and no return value is reserved to
+indicate an error.
+.Sh SEE ALSO
+.Xr getuid 2 ,
+.Xr issetugid 2 ,
+.Xr setgid 2 ,
+.Xr setregid 2
+.Sh STANDARDS
+The
+.Fn getgid
+and
+.Fn getegid
+system calls are expected to conform to
+.St -p1003.1-90 .
diff --git a/lib/libc/sys/getgroups.2 b/lib/libc/sys/getgroups.2
new file mode 100644
index 000000000000..66238a15ce90
--- /dev/null
+++ b/lib/libc/sys/getgroups.2
@@ -0,0 +1,107 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)getgroups.2 8.2 (Berkeley) 4/16/94
+.\" $FreeBSD$
+.\"
+.Dd January 21, 2011
+.Dt GETGROUPS 2
+.Os
+.Sh NAME
+.Nm getgroups
+.Nd get group access list
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft int
+.Fn getgroups "int gidsetlen" "gid_t *gidset"
+.Sh DESCRIPTION
+The
+.Fn getgroups
+system call
+gets the current group access list of the user process
+and stores it in the array
+.Fa gidset .
+The
+.Fa gidsetlen
+argument
+indicates the number of entries that may be placed in
+.Fa gidset .
+The
+.Fn getgroups
+system call
+returns the actual number of groups returned in
+.Fa gidset .
+At least one and as many as {NGROUPS_MAX}+1 values may be returned.
+If
+.Fa gidsetlen
+is zero,
+.Fn getgroups
+returns the number of supplementary group IDs associated with
+the calling process without modifying the array pointed to by
+.Fa gidset .
+.Pp
+The value of
+.Dv {NGROUPS_MAX}
+should be obtained using
+.Xr sysconf 3
+to avoid hard-coding it into the executable.
+.Sh RETURN VALUES
+A successful call returns the number of groups in the group set.
+A value of -1 indicates that an error occurred, and the error
+code is stored in the global variable
+.Va errno .
+.Sh ERRORS
+The possible errors for
+.Fn getgroups
+are:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The argument
+.Fa gidsetlen
+is smaller than the number of groups in the group set.
+.It Bq Er EFAULT
+The argument
+.Fa gidset
+specifies
+an invalid address.
+.El
+.Sh SEE ALSO
+.Xr setgroups 2 ,
+.Xr initgroups 3 ,
+.Xr sysconf 3
+.Sh STANDARDS
+The
+.Fn getgroups
+system call conforms to
+.St -p1003.1-2008 .
+.Sh HISTORY
+The
+.Fn getgroups
+system call appeared in
+.Bx 4.2 .
diff --git a/lib/libc/sys/getitimer.2 b/lib/libc/sys/getitimer.2
new file mode 100644
index 000000000000..539dea61bec1
--- /dev/null
+++ b/lib/libc/sys/getitimer.2
@@ -0,0 +1,180 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)getitimer.2 8.3 (Berkeley) 5/16/95
+.\" $FreeBSD$
+.\"
+.Dd May 16, 1995
+.Dt GETITIMER 2
+.Os
+.Sh NAME
+.Nm getitimer ,
+.Nm setitimer
+.Nd get/set value of interval timer
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/time.h
+.Fd "#define ITIMER_REAL 0"
+.Fd "#define ITIMER_VIRTUAL 1"
+.Fd "#define ITIMER_PROF 2"
+.Ft int
+.Fn getitimer "int which" "struct itimerval *value"
+.Ft int
+.Fn setitimer "int which" "const struct itimerval *value" "struct itimerval *ovalue"
+.Sh DESCRIPTION
+The system provides each process with three interval timers,
+defined in
+.In sys/time.h .
+The
+.Fn getitimer
+system call returns the current value for the timer specified in
+.Fa which
+in the structure at
+.Fa value .
+The
+.Fn setitimer
+system call sets a timer to the specified
+.Fa value
+(returning the previous value of the timer if
+.Fa ovalue
+is not a null pointer).
+.Pp
+A timer value is defined by the
+.Fa itimerval
+structure:
+.Bd -literal -offset indent
+struct itimerval {
+ struct timeval it_interval; /* timer interval */
+ struct timeval it_value; /* current value */
+};
+.Ed
+.Pp
+If
+.Fa it_value
+is non-zero, it indicates the time to the next timer expiration.
+If
+.Fa it_interval
+is non-zero, it specifies a value to be used in reloading
+.Fa it_value
+when the timer expires.
+Setting
+.Fa it_value
+to 0 disables a timer, regardless of the value of
+.Fa it_interval .
+Setting
+.Fa it_interval
+to 0 causes a timer to be disabled after its next expiration (assuming
+.Fa it_value
+is non-zero).
+.Pp
+Time values smaller than the resolution of the
+system clock are rounded up to this resolution
+(typically 10 milliseconds).
+.Pp
+The
+.Dv ITIMER_REAL
+timer decrements in real time.
+A
+.Dv SIGALRM
+signal is
+delivered when this timer expires.
+.Pp
+The
+.Dv ITIMER_VIRTUAL
+timer decrements in process virtual time.
+It runs only when the process is executing.
+A
+.Dv SIGVTALRM
+signal
+is delivered when it expires.
+.Pp
+The
+.Dv ITIMER_PROF
+timer decrements both in process virtual time and
+when the system is running on behalf of the process.
+It is designed
+to be used by interpreters in statistically profiling the execution
+of interpreted programs.
+Each time the
+.Dv ITIMER_PROF
+timer expires, the
+.Dv SIGPROF
+signal is
+delivered.
+Because this signal may interrupt in-progress
+system calls, programs using this timer must be prepared to
+restart interrupted system calls.
+.Pp
+The maximum number of seconds allowed for
+.Fa it_interval
+and
+.Fa it_value
+in
+.Fn setitimer
+is 100000000.
+.Sh NOTES
+Three macros for manipulating time values are defined in
+.In sys/time.h .
+The
+.Fn timerclear
+macro
+sets a time value to zero,
+.Fn timerisset
+tests if a time value is non-zero, and
+.Fn timercmp
+compares two time values.
+.Sh RETURN VALUES
+.Rv -std
+.Sh ERRORS
+The
+.Fn getitimer
+and
+.Fn setitimer
+system calls
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EFAULT
+The
+.Fa value
+argument specified a bad address.
+.It Bq Er EINVAL
+The
+.Fa value
+argument specified a time that was too large
+to be handled.
+.El
+.Sh SEE ALSO
+.Xr gettimeofday 2 ,
+.Xr select 2 ,
+.Xr sigaction 2 ,
+.Xr clocks 7
+.Sh HISTORY
+The
+.Fn getitimer
+system call appeared in
+.Bx 4.2 .
diff --git a/lib/libc/sys/getlogin.2 b/lib/libc/sys/getlogin.2
new file mode 100644
index 000000000000..b7c27df3329a
--- /dev/null
+++ b/lib/libc/sys/getlogin.2
@@ -0,0 +1,204 @@
+.\" Copyright (c) 1989, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)getlogin.2 8.1 (Berkeley) 6/9/93
+.\" $FreeBSD$
+.\"
+.Dd June 9, 1993
+.Dt GETLOGIN 2
+.Os
+.Sh NAME
+.Nm getlogin ,
+.Nm getlogin_r ,
+.Nm setlogin
+.Nd get/set login name
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft char *
+.Fn getlogin void
+.In sys/param.h
+.Ft int
+.Fn getlogin_r "char *name" "int len"
+.Ft int
+.Fn setlogin "const char *name"
+.Sh DESCRIPTION
+The
+.Fn getlogin
+routine
+returns the login name of the user associated with the current session,
+as previously set by
+.Fn setlogin .
+The name is normally associated with a login shell
+at the time a session is created,
+and is inherited by all processes descended from the login shell.
+(This is true even if some of those processes assume another user ID,
+for example when
+.Xr su 1
+is used).
+.Pp
+The
+.Fn getlogin_r
+function
+provides the same service as
+.Fn getlogin
+except the caller must provide the buffer
+.Fa name
+with length
+.Fa len
+bytes
+to hold the result.
+The buffer should be at least
+.Dv MAXLOGNAME
+bytes in length.
+.Pp
+The
+.Fn setlogin
+system call
+sets the login name of the user associated with the current session to
+.Fa name .
+This system call is restricted to the super-user, and
+is normally used only when a new session is being created on behalf
+of the named user
+(for example, at login time, or when a remote shell is invoked).
+.Pp
+.Em NOTE :
+There is only one login name per session.
+.Pp
+It is
+.Em CRITICALLY
+important to ensure that
+.Fn setlogin
+is only ever called after the process has taken adequate steps to ensure
+that it is detached from its parent's session.
+Making a
+.Fn setsid
+system call is the
+.Em ONLY
+way to do this.
+The
+.Xr daemon 3
+function calls
+.Fn setsid
+which is an ideal way of detaching from a controlling terminal and
+forking into the background.
+.Pp
+In particular, doing a
+.Fn ioctl ttyfd TIOCNOTTY ...\&
+or
+.Fn setpgrp ...\&
+is
+.Em NOT
+sufficient.
+.Pp
+Once a parent process does a
+.Fn setsid
+system call, it is acceptable for some child of that process to then do a
+.Fn setlogin
+even though it is not the session leader, but beware that ALL processes
+in the session will change their login name at the same time, even the
+parent.
+.Pp
+This is not the same as the traditional UNIX behavior of inheriting privilege.
+.Pp
+Since the
+.Fn setlogin
+system call is restricted to the super-user, it is assumed that (like
+all other privileged programs) the programmer has taken adequate
+precautions to prevent security violations.
+.Sh RETURN VALUES
+If a call to
+.Fn getlogin
+succeeds, it returns a pointer to a null-terminated string in a static buffer,
+or
+.Dv NULL
+if the name has not been set.
+The
+.Fn getlogin_r
+function
+returns zero if successful, or the error number upon failure.
+.Pp
+.Rv -std setlogin
+.Sh ERRORS
+The following errors may be returned by these calls:
+.Bl -tag -width Er
+.It Bq Er EFAULT
+The
+.Fa name
+argument gave an
+invalid address.
+.It Bq Er EINVAL
+The
+.Fa name
+argument
+pointed to a string that was too long.
+Login names are limited to
+.Dv MAXLOGNAME
+(from
+.In sys/param.h )
+characters, currently 17 including null.
+.It Bq Er EPERM
+The caller tried to set the login name and was not the super-user.
+.It Bq Er ERANGE
+The size of the buffer is smaller than the result to be returned.
+.El
+.Sh SEE ALSO
+.Xr setsid 2 ,
+.Xr daemon 3
+.Sh STANDARDS
+The
+.Fn getlogin
+system call
+and
+the
+.Fn getlogin_r
+function
+conform to
+.St -p1003.1-96 .
+.Sh HISTORY
+The
+.Fn getlogin
+system call first appeared in
+.Bx 4.4 .
+The return value of
+.Fn getlogin_r
+was changed from earlier versions of
+.Fx
+to be conformant with
+.St -p1003.1-96 .
+.Sh BUGS
+In earlier versions of the system,
+.Fn getlogin
+failed unless the process was associated with a login terminal.
+The current implementation (using
+.Fn setlogin )
+allows getlogin to succeed even when the process has no controlling terminal.
+In earlier versions of the system, the value returned by
+.Fn getlogin
+could not be trusted without checking the user ID.
+Portable programs should probably still make this check.
diff --git a/lib/libc/sys/getloginclass.2 b/lib/libc/sys/getloginclass.2
new file mode 100644
index 000000000000..6249d830c82e
--- /dev/null
+++ b/lib/libc/sys/getloginclass.2
@@ -0,0 +1,100 @@
+.\"-
+.\" Copyright (c) 2011 Edward Tomasz Napierala
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 July 12, 2016
+.Dt GETLOGINCLASS 2
+.Os
+.Sh NAME
+.Nm getloginclass ,
+.Nm setloginclass
+.Nd get/set login class
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft int
+.Fn getloginclass "char *name" "size_t len"
+.Ft int
+.Fn setloginclass "const char *name"
+.Sh DESCRIPTION
+The
+.Fn getloginclass
+routine returns the login class name associated with the calling process,
+as previously set by
+.Fn setloginclass .
+The caller must provide the buffer
+.Fa name
+with length
+.Fa len
+bytes to hold the result.
+The buffer should be at least
+.Dv MAXLOGNAME
+bytes in length.
+.Pp
+The
+.Fn setloginclass
+system call sets the login class of the calling process to
+.Fa name .
+This system call is restricted to the super-user, and is normally used
+only when a new session is being created on behalf of the named user
+(for example, at login time, or when a remote shell is invoked).
+Processes inherit login class from their parents.
+.Sh RETURN VALUES
+.Rv -std
+.Sh ERRORS
+The following errors may be returned by these calls:
+.Bl -tag -width Er
+.It Bq Er EFAULT
+The
+.Fa name
+argument gave an invalid address.
+.It Bq Er EINVAL
+The
+.Fa name
+argument pointed to a string that was too long.
+Login class names are limited to
+.Dv MAXLOGNAME
+(from
+.In sys/param.h )
+characters, currently 17 including null.
+.It Bq Er EPERM
+The caller tried to set the login class and was not the super-user.
+.It Bq Er ENAMETOOLONG
+The size of the buffer is smaller than the result to be returned.
+.El
+.Sh SEE ALSO
+.Xr ps 1 ,
+.Xr setusercontext 3 ,
+.Xr login.conf 5 ,
+.Xr rctl 8
+.Sh HISTORY
+The
+.Fn getloginclass
+and
+.Fn setloginclass
+system calls first appeared in
+.Fx 9.0 .
diff --git a/lib/libc/sys/getpeername.2 b/lib/libc/sys/getpeername.2
new file mode 100644
index 000000000000..255c7a01bb88
--- /dev/null
+++ b/lib/libc/sys/getpeername.2
@@ -0,0 +1,98 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)getpeername.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt GETPEERNAME 2
+.Os
+.Sh NAME
+.Nm getpeername
+.Nd get name of connected peer
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/socket.h
+.Ft int
+.Fn getpeername "int s" "struct sockaddr * restrict name" "socklen_t * restrict namelen"
+.Sh DESCRIPTION
+The
+.Fn getpeername
+system call
+returns the name of the peer connected to
+socket
+.Fa s .
+The
+.Fa namelen
+argument should be initialized to indicate
+the amount of space pointed to by
+.Fa name .
+On return it contains the actual size of the name
+returned (in bytes).
+The name is truncated if the buffer provided is too small.
+.Sh RETURN VALUES
+.Rv -std getpeername
+.Sh ERRORS
+The call succeeds unless:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The argument
+.Fa s
+is not a valid descriptor.
+.It Bq Er ECONNRESET
+The connection has been reset by the peer.
+.It Bq Er EINVAL
+The value of the
+.Fa namelen
+argument is not valid.
+.It Bq Er ENOTSOCK
+The argument
+.Fa s
+is a file, not a socket.
+.It Bq Er ENOTCONN
+The socket is not connected.
+.It Bq Er ENOBUFS
+Insufficient resources were available in the system
+to perform the operation.
+.It Bq Er EFAULT
+The
+.Fa name
+argument points to memory not in a valid part of the
+process address space.
+.El
+.Sh SEE ALSO
+.Xr accept 2 ,
+.Xr bind 2 ,
+.Xr getsockname 2 ,
+.Xr socket 2
+.Sh HISTORY
+The
+.Fn getpeername
+system call appeared in
+.Bx 4.2 .
diff --git a/lib/libc/sys/getpgrp.2 b/lib/libc/sys/getpgrp.2
new file mode 100644
index 000000000000..f5e81a8a81e5
--- /dev/null
+++ b/lib/libc/sys/getpgrp.2
@@ -0,0 +1,142 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)getpgrp.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt GETPGRP 2
+.Os
+.Sh NAME
+.Nm getpgrp
+.Nd get process group
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft pid_t
+.Fn getpgrp void
+.Ft pid_t
+.Fn getpgid "pid_t pid"
+.Sh DESCRIPTION
+The process group of the current process is returned by
+.Fn getpgrp .
+The process group of the process identified by
+.Fa pid
+is returned by
+.Fn getpgid .
+If
+.Fa pid
+is zero,
+.Fn getpgid
+returns the process group of the current process.
+.Pp
+Process groups are used for distribution of signals, and
+by terminals to arbitrate requests for their input: processes
+that have the same process group as the terminal are foreground
+and may read, while others will block with a signal if they attempt
+to read.
+.Pp
+This system call is thus used by programs such as
+.Xr csh 1
+to create
+process groups
+in implementing job control.
+The
+.Fn tcgetpgrp
+and
+.Fn tcsetpgrp
+calls
+are used to get/set the process group of the control terminal.
+.Sh RETURN VALUES
+The
+.Fn getpgrp
+system call always succeeds.
+Upon successful completion, the
+.Fn getpgid
+system call returns the process group of the specified process;
+otherwise, it returns a value of \-1 and sets
+.Va errno
+to indicate the error.
+.Sh COMPATIBILITY
+This version of
+.Fn getpgrp
+differs from past Berkeley versions by not taking a
+.Fa "pid_t pid"
+argument.
+This incompatibility is required by
+.St -p1003.1-90 .
+.Pp
+From the
+.St -p1003.1-90
+Rationale:
+.Pp
+.Bx 4.3
+provides a
+.Fn getpgrp
+system call that returns the process group ID for a specified process.
+Although this function is used to support job control, all known
+job-control shells always specify the calling process with this
+function.
+Thus, the simpler
+.At V
+.Fn getpgrp
+suffices, and the added complexity of the
+.Bx 4.3
+.Fn getpgrp
+has been omitted from POSIX.1.
+The old functionality is available from the
+.Fn getpgid
+system call.
+.Sh ERRORS
+The
+.Fn getpgid
+system call
+will succeed unless:
+.Bl -tag -width Er
+.It Bq Er ESRCH
+there is no process whose process ID equals
+.Fa pid
+.El
+.Sh SEE ALSO
+.Xr getsid 2 ,
+.Xr setpgid 2 ,
+.Xr termios 4
+.Sh STANDARDS
+The
+.Fn getpgrp
+system call is expected to conform to
+.St -p1003.1-90 .
+.Sh HISTORY
+The
+.Fn getpgrp
+system call appeared in
+.Bx 4.0 .
+The
+.Fn getpgid
+system call is derived from its usage in
+.At V.4 .
diff --git a/lib/libc/sys/getpid.2 b/lib/libc/sys/getpid.2
new file mode 100644
index 000000000000..ab69f7117aeb
--- /dev/null
+++ b/lib/libc/sys/getpid.2
@@ -0,0 +1,90 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)getpid.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd December 15, 2015
+.Dt GETPID 2
+.Os
+.Sh NAME
+.Nm getpid ,
+.Nm getppid
+.Nd get parent or calling process identification
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft pid_t
+.Fn getpid void
+.Ft pid_t
+.Fn getppid void
+.Sh DESCRIPTION
+The
+.Fn getpid
+system call
+returns
+the process ID of
+the calling process.
+Though the ID is guaranteed to be unique, it should
+.Em NOT
+be used for constructing temporary file names, for
+security reasons; see
+.Xr mkstemp 3
+instead.
+.Pp
+The
+.Fn getppid
+system call
+returns the process ID of the parent
+of the calling process.
+.Sh ERRORS
+The
+.Fn getpid
+and
+.Fn getppid
+system calls are always successful, and no return value is reserved to
+indicate an error.
+.Sh SEE ALSO
+.Xr fork 2 ,
+.Xr getpgrp 2 ,
+.Xr kill 2 ,
+.Xr setpgid 2 ,
+.Xr setsid 2 ,
+.Xr exec 3
+.Sh STANDARDS
+The
+.Fn getpid
+and
+.Fn getppid
+system calls are expected to conform to
+.St -p1003.1-90 .
+.Sh HISTORY
+The
+.Fn getpid
+function appeared in
+.At v7 .
diff --git a/lib/libc/sys/getpriority.2 b/lib/libc/sys/getpriority.2
new file mode 100644
index 000000000000..ae70f5f441d5
--- /dev/null
+++ b/lib/libc/sys/getpriority.2
@@ -0,0 +1,150 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)getpriority.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt GETPRIORITY 2
+.Os
+.Sh NAME
+.Nm getpriority ,
+.Nm setpriority
+.Nd get/set program scheduling priority
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/time.h
+.In sys/resource.h
+.Ft int
+.Fn getpriority "int which" "int who"
+.Ft int
+.Fn setpriority "int which" "int who" "int prio"
+.Sh DESCRIPTION
+The scheduling
+priority of the process, process group, or user, as indicated by
+.Fa which
+and
+.Fa who
+is obtained with the
+.Fn getpriority
+system call and set with the
+.Fn setpriority
+system call.
+The
+.Fa which
+argument
+is one of
+.Dv PRIO_PROCESS ,
+.Dv PRIO_PGRP ,
+or
+.Dv PRIO_USER ,
+and
+.Fa who
+is interpreted relative to
+.Fa which
+(a process identifier for
+.Dv PRIO_PROCESS ,
+process group
+identifier for
+.Dv PRIO_PGRP ,
+and a user ID for
+.Dv PRIO_USER ) .
+A zero value of
+.Fa who
+denotes the current process, process group, or user.
+The
+.Fa prio
+argument
+is a value in the range -20 to 20.
+The default priority is 0;
+lower priorities cause more favorable scheduling.
+.Pp
+The
+.Fn getpriority
+system call returns the highest priority (lowest numerical value)
+enjoyed by any of the specified processes.
+The
+.Fn setpriority
+system call sets the priorities of all of the specified processes
+to the specified value.
+Only the super-user may lower priorities.
+.Sh RETURN VALUES
+Since
+.Fn getpriority
+can legitimately return the value -1, it is necessary
+to clear the external variable
+.Va errno
+prior to the
+call, then check it afterward to determine
+if a -1 is an error or a legitimate value.
+.Pp
+.Rv -std setpriority
+.Sh ERRORS
+The
+.Fn getpriority
+and
+.Fn setpriority
+system calls
+will fail if:
+.Bl -tag -width Er
+.It Bq Er ESRCH
+No process was located using the
+.Fa which
+and
+.Fa who
+values specified.
+.It Bq Er EINVAL
+The
+.Fa which
+argument
+was not one of
+.Dv PRIO_PROCESS ,
+.Dv PRIO_PGRP ,
+or
+.Dv PRIO_USER .
+.El
+.Pp
+In addition to the errors indicated above,
+.Fn setpriority
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EPERM
+A process was located, but neither its effective nor real user
+ID matched the effective user ID of the caller.
+.It Bq Er EACCES
+A non super-user attempted to lower a process priority.
+.El
+.Sh SEE ALSO
+.Xr nice 1 ,
+.Xr fork 2 ,
+.Xr renice 8
+.Sh HISTORY
+The
+.Fn getpriority
+system call appeared in
+.Bx 4.2 .
diff --git a/lib/libc/sys/getrlimit.2 b/lib/libc/sys/getrlimit.2
new file mode 100644
index 000000000000..1ac01d396ee9
--- /dev/null
+++ b/lib/libc/sys/getrlimit.2
@@ -0,0 +1,238 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)getrlimit.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd September 30, 2016
+.Dt GETRLIMIT 2
+.Os
+.Sh NAME
+.Nm getrlimit ,
+.Nm setrlimit
+.Nd control maximum system resource consumption
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/time.h
+.In sys/resource.h
+.Ft int
+.Fn getrlimit "int resource" "struct rlimit *rlp"
+.Ft int
+.Fn setrlimit "int resource" "const struct rlimit *rlp"
+.Sh DESCRIPTION
+Limits on the consumption of system resources by the current process
+and each process it creates may be obtained with the
+.Fn getrlimit
+system call, and set with the
+.Fn setrlimit
+system call.
+.Pp
+The
+.Fa resource
+argument is one of the following:
+.Bl -tag -width RLIMIT_FSIZEAA
+.It Dv RLIMIT_AS
+The maximum amount (in bytes) of virtual memory the process is
+allowed to map.
+.It Dv RLIMIT_CORE
+The largest size (in bytes)
+.Xr core 5
+file that may be created.
+.It Dv RLIMIT_CPU
+The maximum amount of cpu time (in seconds) to be used by
+each process.
+.It Dv RLIMIT_DATA
+The maximum size (in bytes) of the data segment for a process;
+this defines how far a program may extend its break with the
+.Xr sbrk 2
+function.
+.It Dv RLIMIT_FSIZE
+The largest size (in bytes) file that may be created.
+.It Dv RLIMIT_KQUEUES
+The maximum number of kqueues this user id is allowed to create.
+.It Dv RLIMIT_MEMLOCK
+The maximum size (in bytes) which a process may lock into memory
+using the
+.Xr mlock 2
+system call.
+.It Dv RLIMIT_NOFILE
+The maximum number of open files for this process.
+.It Dv RLIMIT_NPROC
+The maximum number of simultaneous processes for this user id.
+.It Dv RLIMIT_NPTS
+The maximum number of pseudo-terminals this user id is allowed to create.
+.It Dv RLIMIT_RSS
+When there is memory pressure and swap is available, prioritize eviction of
+a process' resident pages beyond this amount (in bytes).
+When memory is not under pressure, this rlimit is effectively ignored.
+Even when there is memory pressure, the amount of available swap space and some
+sysctl settings like
+.Xr vm.swap_enabled
+and
+.Xr vm.swap_idle_enabled
+can affect what happens to processes that have exceeded this size.
+.Pp
+Processes that exceed their set
+.Dv RLIMIT_RSS
+are not signalled or halted.
+The limit is merely a hint to the VM daemon to prefer to deactivate pages from
+processes that have exceeded their set
+.Dv RLIMIT_RSS .
+.It Dv RLIMIT_SBSIZE
+The maximum size (in bytes) of socket buffer usage for this user.
+This limits the amount of network memory, and hence the amount of
+mbufs, that this user may hold at any time.
+.It Dv RLIMIT_STACK
+The maximum size (in bytes) of the stack segment for a process;
+this defines how far a program's stack segment may be extended.
+Stack extension is performed automatically by the system.
+.It Dv RLIMIT_SWAP
+The maximum size (in bytes) of the swap space that may be reserved or
+used by all of this user id's processes.
+This limit is enforced only if bit 1 of the
+.Va vm.overcommit
+sysctl is set.
+Please see
+.Xr tuning 7
+for a complete description of this sysctl.
+.It Dv RLIMIT_VMEM
+An alias for
+.Dv RLIMIT_AS .
+.El
+.Pp
+A resource limit is specified as a soft limit and a hard limit.
+When a soft limit is exceeded, a process might or might not receive a signal.
+For example, signals are generated when the cpu time or file size is exceeded,
+but not if the address space or RSS limit is exceeded.
+A program that exceeds the soft limit is allowed to continue execution until it
+reaches the hard limit, or modifies its own resource limit.
+Even reaching the hard limit does not necessarily halt a process.
+For example, if the RSS hard limit is exceeded, nothing happens.
+.Pp
+The
+.Vt rlimit
+structure is used to specify the hard and soft limits on a resource.
+.Bd -literal -offset indent
+struct rlimit {
+ rlim_t rlim_cur; /* current (soft) limit */
+ rlim_t rlim_max; /* maximum value for rlim_cur */
+};
+.Ed
+.Pp
+Only the super-user may raise the maximum limits.
+Other users
+may only alter
+.Fa rlim_cur
+within the range from 0 to
+.Fa rlim_max
+or (irreversibly) lower
+.Fa rlim_max .
+.Pp
+An
+.Dq infinite
+value for a limit is defined as
+.Dv RLIM_INFINITY .
+.Pp
+Because this information is stored in the per-process information,
+this system call must be executed directly by the shell if it
+is to affect all future processes created by the shell;
+.Ic limit
+is thus a built-in command to
+.Xr csh 1 .
+.Pp
+The system refuses to extend the data or stack space when the limits
+would be exceeded in the normal way: a
+.Xr brk 2
+function fails if the data space limit is reached.
+When the stack limit is reached, the process receives
+a segmentation fault
+.Pq Dv SIGSEGV ;
+if this signal is not
+caught by a handler using the signal stack, this signal
+will kill the process.
+.Pp
+A file I/O operation that would create a file larger that the process'
+soft limit will cause the write to fail and a signal
+.Dv SIGXFSZ
+to be
+generated; this normally terminates the process, but may be caught.
+When
+the soft cpu time limit is exceeded, a
+.Dv SIGXCPU
+signal is sent to the
+offending process.
+.Pp
+When most operations would allocate more virtual memory than allowed by the
+soft limit of
+.Dv RLIMIT_AS ,
+the operation fails with
+.Dv ENOMEM
+and no signal is raised.
+A notable exception is stack extension, described above.
+If stack extension would allocate more virtual memory than allowed by the soft
+limit of
+.Dv RLIMIT_AS ,
+a
+.Dv SIGSEGV
+signal will be delivered.
+The caller is free to raise the soft address space limit up to the hard limit
+and retry the allocation.
+.Sh RETURN VALUES
+.Rv -std
+.Sh ERRORS
+The
+.Fn getrlimit
+and
+.Fn setrlimit
+system calls
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EFAULT
+The address specified for
+.Fa rlp
+is invalid.
+.It Bq Er EPERM
+The limit specified to
+.Fn setrlimit
+would have
+raised the maximum limit value, and the caller is not the super-user.
+.El
+.Sh SEE ALSO
+.Xr csh 1 ,
+.Xr quota 1 ,
+.Xr quotactl 2 ,
+.Xr sigaction 2 ,
+.Xr sigaltstack 2 ,
+.Xr sysctl 3 ,
+.Xr ulimit 3
+.Sh HISTORY
+The
+.Fn getrlimit
+system call appeared in
+.Bx 4.2 .
diff --git a/lib/libc/sys/getrusage.2 b/lib/libc/sys/getrusage.2
new file mode 100644
index 000000000000..45ded184932a
--- /dev/null
+++ b/lib/libc/sys/getrusage.2
@@ -0,0 +1,186 @@
+.\" Copyright (c) 1985, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)getrusage.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd May 1, 2010
+.Dt GETRUSAGE 2
+.Os
+.Sh NAME
+.Nm getrusage
+.Nd get information about resource utilization
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/time.h
+.In sys/resource.h
+.Fd "#define RUSAGE_SELF 0"
+.Fd "#define RUSAGE_CHILDREN -1"
+.Fd "#define RUSAGE_THREAD 1"
+.Ft int
+.Fn getrusage "int who" "struct rusage *rusage"
+.Sh DESCRIPTION
+The
+.Fn getrusage
+system call
+returns information describing the resources utilized by the current
+thread, the current process, or all its terminated child processes.
+The
+.Fa who
+argument is either
+.Dv RUSAGE_THREAD ,
+.Dv RUSAGE_SELF ,
+or
+.Dv RUSAGE_CHILDREN .
+The buffer to which
+.Fa rusage
+points will be filled in with
+the following structure:
+.Bd -literal
+struct rusage {
+ struct timeval ru_utime; /* user time used */
+ struct timeval ru_stime; /* system time used */
+ long ru_maxrss; /* max resident set size */
+ long ru_ixrss; /* integral shared text memory size */
+ long ru_idrss; /* integral unshared data size */
+ long ru_isrss; /* integral unshared stack size */
+ long ru_minflt; /* page reclaims */
+ long ru_majflt; /* page faults */
+ long ru_nswap; /* swaps */
+ long ru_inblock; /* block input operations */
+ long ru_oublock; /* block output operations */
+ long ru_msgsnd; /* messages sent */
+ long ru_msgrcv; /* messages received */
+ long ru_nsignals; /* signals received */
+ long ru_nvcsw; /* voluntary context switches */
+ long ru_nivcsw; /* involuntary context switches */
+};
+.Ed
+.Pp
+The fields are interpreted as follows:
+.Bl -tag -width ru_minfltaa
+.It Fa ru_utime
+the total amount of time spent executing in user mode.
+.It Fa ru_stime
+the total amount of time spent in the system executing on behalf
+of the process(es).
+.It Fa ru_maxrss
+the maximum resident set size utilized (in kilobytes).
+.It Fa ru_ixrss
+an
+.Dq integral
+value indicating the amount of memory used
+by the text segment
+that was also shared among other processes.
+This value is expressed
+in units of kilobytes * ticks-of-execution.
+Ticks are statistics clock ticks.
+The statistics clock has a frequency of
+.Fn sysconf _SC_CLK_TCK
+ticks per second.
+.It Fa ru_idrss
+an integral value of the amount of unshared memory residing in the
+data segment of a process (expressed in units of
+kilobytes * ticks-of-execution).
+.It Fa ru_isrss
+an integral value of the amount of unshared memory residing in the
+stack segment of a process (expressed in units of
+kilobytes * ticks-of-execution).
+.It Fa ru_minflt
+the number of page faults serviced without any I/O activity; here
+I/O activity is avoided by
+.Dq reclaiming
+a page frame from
+the list of pages awaiting reallocation.
+.It Fa ru_majflt
+the number of page faults serviced that required I/O activity.
+.It Fa ru_nswap
+the number of times a process was
+.Dq swapped
+out of main
+memory.
+.It Fa ru_inblock
+the number of times the file system had to perform input.
+.It Fa ru_oublock
+the number of times the file system had to perform output.
+.It Fa ru_msgsnd
+the number of IPC messages sent.
+.It Fa ru_msgrcv
+the number of IPC messages received.
+.It Fa ru_nsignals
+the number of signals delivered.
+.It Fa ru_nvcsw
+the number of times a context switch resulted due to a process
+voluntarily giving up the processor before its time slice was
+completed (usually to await availability of a resource).
+.It Fa ru_nivcsw
+the number of times a context switch resulted due to a higher
+priority process becoming runnable or because the current process
+exceeded its time slice.
+.El
+.Sh NOTES
+The numbers
+.Fa ru_inblock
+and
+.Fa ru_oublock
+account only for real
+I/O; data supplied by the caching mechanism is charged only
+to the first process to read or write the data.
+.Sh RETURN VALUES
+.Rv -std getrusage
+.Sh ERRORS
+The
+.Fn getrusage
+system call will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa who
+argument is not a valid value.
+.It Bq Er EFAULT
+The address specified by the
+.Fa rusage
+argument is not in a valid part of the process address space.
+.El
+.Sh SEE ALSO
+.Xr gettimeofday 2 ,
+.Xr wait 2 ,
+.Xr clocks 7
+.Sh HISTORY
+The
+.Fn getrusage
+system call appeared in
+.Bx 4.2 .
+The
+.Dv RUSAGE_THREAD
+facility first appeared in
+.Fx 8.1 .
+.Sh BUGS
+There is no way to obtain information about a child process
+that has not yet terminated.
diff --git a/lib/libc/sys/getsid.2 b/lib/libc/sys/getsid.2
new file mode 100644
index 000000000000..8d3107439601
--- /dev/null
+++ b/lib/libc/sys/getsid.2
@@ -0,0 +1,82 @@
+.\" Copyright (c) 1997 Peter Wemm <peter@FreeBSD.org>
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd August 19, 1997
+.Dt GETSID 2
+.Os
+.Sh NAME
+.Nm getsid
+.Nd get process session
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft pid_t
+.Fn getsid "pid_t pid"
+.Sh DESCRIPTION
+The session ID of the process identified by
+.Fa pid
+is returned by
+.Fn getsid .
+If
+.Fa pid
+is zero,
+.Fn getsid
+returns the session ID of the current process.
+.Sh RETURN VALUES
+Upon successful completion, the
+.Fn getsid
+system call
+returns the session ID of
+the specified process; otherwise, it returns a value of -1 and
+sets errno to indicate an error.
+.Sh ERRORS
+The
+.Fn getsid
+system call
+will succeed unless:
+.Bl -tag -width Er
+.It Bq Er ESRCH
+if there is no process with a process ID equal to
+.Fa pid .
+.El
+.Pp
+Note that an implementation may restrict this system call to
+processes within the same session ID as the calling process.
+.Sh SEE ALSO
+.Xr getpgid 2 ,
+.Xr getpgrp 2 ,
+.Xr setpgid 2 ,
+.Xr setsid 2 ,
+.Xr termios 4
+.Sh HISTORY
+The
+.Fn getsid
+system call appeared in
+.Fx 3.0 .
+The
+.Fn getsid
+system call is derived from its usage in
+.At V .
diff --git a/lib/libc/sys/getsockname.2 b/lib/libc/sys/getsockname.2
new file mode 100644
index 000000000000..1de025768358
--- /dev/null
+++ b/lib/libc/sys/getsockname.2
@@ -0,0 +1,98 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)getsockname.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt GETSOCKNAME 2
+.Os
+.Sh NAME
+.Nm getsockname
+.Nd get socket name
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/socket.h
+.Ft int
+.Fn getsockname "int s" "struct sockaddr * restrict name" "socklen_t * restrict namelen"
+.Sh DESCRIPTION
+The
+.Fn getsockname
+system call
+returns the current
+.Fa name
+for the specified socket.
+The
+.Fa namelen
+argument should be initialized to indicate
+the amount of space pointed to by
+.Fa name .
+On return it contains the actual size of the name
+returned (in bytes).
+.Sh RETURN VALUES
+.Rv -std getsockname
+.Sh ERRORS
+The call succeeds unless:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The argument
+.Fa s
+is not a valid descriptor.
+.It Bq Er ECONNRESET
+The connection has been reset by the peer.
+.It Bq Er EINVAL
+The value of the
+.Fa namelen
+argument is not valid.
+.It Bq Er ENOTSOCK
+The argument
+.Fa s
+is a file, not a socket.
+.It Bq Er ENOBUFS
+Insufficient resources were available in the system
+to perform the operation.
+.It Bq Er EFAULT
+The
+.Fa name
+argument points to memory not in a valid part of the
+process address space.
+.El
+.Sh SEE ALSO
+.Xr bind 2 ,
+.Xr getpeername 2 ,
+.Xr socket 2
+.Sh HISTORY
+The
+.Fn getsockname
+system call appeared in
+.Bx 4.2 .
+.Sh BUGS
+Names bound to sockets in the UNIX domain are inaccessible;
+.Fn getsockname
+returns a zero length name.
diff --git a/lib/libc/sys/getsockopt.2 b/lib/libc/sys/getsockopt.2
new file mode 100644
index 000000000000..1f742ee7c334
--- /dev/null
+++ b/lib/libc/sys/getsockopt.2
@@ -0,0 +1,576 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)getsockopt.2 8.4 (Berkeley) 5/2/95
+.\" $FreeBSD$
+.\"
+.Dd January 18, 2017
+.Dt GETSOCKOPT 2
+.Os
+.Sh NAME
+.Nm getsockopt ,
+.Nm setsockopt
+.Nd get and set options on sockets
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/socket.h
+.Ft int
+.Fn getsockopt "int s" "int level" "int optname" "void * restrict optval" "socklen_t * restrict optlen"
+.Ft int
+.Fn setsockopt "int s" "int level" "int optname" "const void *optval" "socklen_t optlen"
+.Sh DESCRIPTION
+The
+.Fn getsockopt
+and
+.Fn setsockopt
+system calls
+manipulate the
+.Em options
+associated with a socket.
+Options may exist at multiple
+protocol levels; they are always present at the uppermost
+.Dq socket
+level.
+.Pp
+When manipulating socket options the level at which the
+option resides and the name of the option must be specified.
+To manipulate options at the socket level,
+.Fa level
+is specified as
+.Dv SOL_SOCKET .
+To manipulate options at any
+other level the protocol number of the appropriate protocol
+controlling the option is supplied.
+For example,
+to indicate that an option is to be interpreted by the
+.Tn TCP
+protocol,
+.Fa level
+should be set to the protocol number of
+.Tn TCP ;
+see
+.Xr getprotoent 3 .
+.Pp
+The
+.Fa optval
+and
+.Fa optlen
+arguments
+are used to access option values for
+.Fn setsockopt .
+For
+.Fn getsockopt
+they identify a buffer in which the value for the
+requested option(s) are to be returned.
+For
+.Fn getsockopt ,
+.Fa optlen
+is a value-result argument, initially containing the
+size of the buffer pointed to by
+.Fa optval ,
+and modified on return to indicate the actual size of
+the value returned.
+If no option value is
+to be supplied or returned,
+.Fa optval
+may be NULL.
+.Pp
+The
+.Fa optname
+argument
+and any specified options are passed uninterpreted to the appropriate
+protocol module for interpretation.
+The include file
+.In sys/socket.h
+contains definitions for
+socket level options, described below.
+Options at other protocol levels vary in format and
+name; consult the appropriate entries in
+section
+4 of the manual.
+.Pp
+Most socket-level options utilize an
+.Vt int
+argument for
+.Fa optval .
+For
+.Fn setsockopt ,
+the argument should be non-zero to enable a boolean option,
+or zero if the option is to be disabled.
+.Dv SO_LINGER
+uses a
+.Vt "struct linger"
+argument, defined in
+.In sys/socket.h ,
+which specifies the desired state of the option and the
+linger interval (see below).
+.Dv SO_SNDTIMEO
+and
+.Dv SO_RCVTIMEO
+use a
+.Vt "struct timeval"
+argument, defined in
+.In sys/time.h .
+.Pp
+The following options are recognized at the socket level.
+For protocol-specific options, see protocol manual pages,
+e.g.
+.Xr ip 4
+or
+.Xr tcp 4 .
+Except as noted, each may be examined with
+.Fn getsockopt
+and set with
+.Fn setsockopt .
+.Bl -column SO_ACCEPTFILTER -offset indent
+.It Dv SO_DEBUG Ta "enables recording of debugging information"
+.It Dv SO_REUSEADDR Ta "enables local address reuse"
+.It Dv SO_REUSEPORT Ta "enables duplicate address and port bindings"
+.It Dv SO_KEEPALIVE Ta "enables keep connections alive"
+.It Dv SO_DONTROUTE Ta "enables routing bypass for outgoing messages"
+.It Dv SO_LINGER Ta "linger on close if data present"
+.It Dv SO_BROADCAST Ta "enables permission to transmit broadcast messages"
+.It Dv SO_OOBINLINE Ta "enables reception of out-of-band data in band"
+.It Dv SO_SNDBUF Ta "set buffer size for output"
+.It Dv SO_RCVBUF Ta "set buffer size for input"
+.It Dv SO_SNDLOWAT Ta "set minimum count for output"
+.It Dv SO_RCVLOWAT Ta "set minimum count for input"
+.It Dv SO_SNDTIMEO Ta "set timeout value for output"
+.It Dv SO_RCVTIMEO Ta "set timeout value for input"
+.It Dv SO_ACCEPTFILTER Ta "set accept filter on listening socket"
+.It Dv SO_NOSIGPIPE Ta
+controls generation of
+.Dv SIGPIPE
+for the socket
+.It Dv SO_TIMESTAMP Ta "enables reception of a timestamp with datagrams"
+.It Dv SO_BINTIME Ta "enables reception of a timestamp with datagrams"
+.It Dv SO_ACCEPTCONN Ta "get listening status of the socket (get only)"
+.It Dv SO_TYPE Ta "get the type of the socket (get only)"
+.It Dv SO_PROTOCOL Ta "get the protocol number for the socket (get only)"
+.It Dv SO_PROTOTYPE Ta "SunOS alias for the Linux SO_PROTOCOL (get only)"
+.It Dv SO_ERROR Ta "get and clear error on the socket (get only)"
+.It Dv SO_SETFIB Ta "set the associated FIB (routing table) for the socket (set only)"
+.El
+.Pp
+The following options are recognized in
+.Fx :
+.Bl -column SO_LISTENINCQLEN -offset indent
+.It Dv SO_LABEL Ta "get MAC label of the socket (get only)"
+.It Dv SO_PEERLABEL Ta "get socket's peer's MAC label (get only)"
+.It Dv SO_LISTENQLIMIT Ta "get backlog limit of the socket (get only)"
+.It Dv SO_LISTENQLEN Ta "get complete queue length of the socket (get only)"
+.It Dv SO_LISTENINCQLEN Ta "get incomplete queue length of the socket (get only)"
+.It Dv SO_USER_COOKIE Ta "set the 'so_user_cookie' value for the socket (uint32_t, set only)"
+.It Dv SO_TS_CLOCK Ta "set specific format of timestamp returned by SO_TIMESTAMP"
+.It Dv SO_MAX_PACING_RATE "set the maximum transmit rate in bytes per second for the socket"
+.El
+.Pp
+.Dv SO_DEBUG
+enables debugging in the underlying protocol modules.
+.Pp
+.Dv SO_REUSEADDR
+indicates that the rules used in validating addresses supplied
+in a
+.Xr bind 2
+system call should allow reuse of local addresses.
+.Pp
+.Dv SO_REUSEPORT
+allows completely duplicate bindings by multiple processes
+if they all set
+.Dv SO_REUSEPORT
+before binding the port.
+This option permits multiple instances of a program to each
+receive UDP/IP multicast or broadcast datagrams destined for the bound port.
+.Pp
+.Dv SO_KEEPALIVE
+enables the
+periodic transmission of messages on a connected socket.
+Should the
+connected party fail to respond to these messages, the connection is
+considered broken and processes using the socket are notified via a
+.Dv SIGPIPE
+signal when attempting to send data.
+.Pp
+.Dv SO_DONTROUTE
+indicates that outgoing messages should
+bypass the standard routing facilities.
+Instead, messages are directed
+to the appropriate network interface according to the network portion
+of the destination address.
+.Pp
+.Dv SO_LINGER
+controls the action taken when unsent messages
+are queued on socket and a
+.Xr close 2
+is performed.
+If the socket promises reliable delivery of data and
+.Dv SO_LINGER
+is set,
+the system will block the process on the
+.Xr close 2
+attempt until it is able to transmit the data or until it decides it
+is unable to deliver the information (a timeout period, termed the
+linger interval, is specified in seconds in the
+.Fn setsockopt
+system call when
+.Dv SO_LINGER
+is requested).
+If
+.Dv SO_LINGER
+is disabled and a
+.Xr close 2
+is issued, the system will process the close in a manner that allows
+the process to continue as quickly as possible.
+.Pp
+The option
+.Dv SO_BROADCAST
+requests permission to send broadcast datagrams
+on the socket.
+Broadcast was a privileged operation in earlier versions of the system.
+.Pp
+With protocols that support out-of-band data, the
+.Dv SO_OOBINLINE
+option
+requests that out-of-band data be placed in the normal data input queue
+as received; it will then be accessible with
+.Xr recv 2
+or
+.Xr read 2
+calls without the
+.Dv MSG_OOB
+flag.
+Some protocols always behave as if this option is set.
+.Pp
+.Dv SO_SNDBUF
+and
+.Dv SO_RCVBUF
+are options to adjust the normal
+buffer sizes allocated for output and input buffers, respectively.
+The buffer size may be increased for high-volume connections,
+or may be decreased to limit the possible backlog of incoming data.
+The system places an absolute maximum on these values, which is accessible
+through the
+.Xr sysctl 3
+MIB variable
+.Dq Li kern.ipc.maxsockbuf .
+.Pp
+.Dv SO_SNDLOWAT
+is an option to set the minimum count for output operations.
+Most output operations process all of the data supplied
+by the call, delivering data to the protocol for transmission
+and blocking as necessary for flow control.
+Nonblocking output operations will process as much data as permitted
+subject to flow control without blocking, but will process no data
+if flow control does not allow the smaller of the low water mark value
+or the entire request to be processed.
+A
+.Xr select 2
+operation testing the ability to write to a socket will return true
+only if the low water mark amount could be processed.
+The default value for
+.Dv SO_SNDLOWAT
+is set to a convenient size for network efficiency, often 1024.
+.Pp
+.Dv SO_RCVLOWAT
+is an option to set the minimum count for input operations.
+In general, receive calls will block until any (non-zero) amount of data
+is received, then return with the smaller of the amount available or the amount
+requested.
+The default value for
+.Dv SO_RCVLOWAT
+is 1.
+If
+.Dv SO_RCVLOWAT
+is set to a larger value, blocking receive calls normally
+wait until they have received the smaller of the low water mark value
+or the requested amount.
+Receive calls may still return less than the low water mark if an error
+occurs, a signal is caught, or the type of data next in the receive queue
+is different from that which was returned.
+.Pp
+.Dv SO_SNDTIMEO
+is an option to set a timeout value for output operations.
+It accepts a
+.Vt "struct timeval"
+argument with the number of seconds and microseconds
+used to limit waits for output operations to complete.
+If a send operation has blocked for this much time,
+it returns with a partial count
+or with the error
+.Er EWOULDBLOCK
+if no data were sent.
+In the current implementation, this timer is restarted each time additional
+data are delivered to the protocol,
+implying that the limit applies to output portions ranging in size
+from the low water mark to the high water mark for output.
+.Pp
+.Dv SO_RCVTIMEO
+is an option to set a timeout value for input operations.
+It accepts a
+.Vt "struct timeval"
+argument with the number of seconds and microseconds
+used to limit waits for input operations to complete.
+In the current implementation, this timer is restarted each time additional
+data are received by the protocol,
+and thus the limit is in effect an inactivity timer.
+If a receive operation has been blocked for this much time without
+receiving additional data, it returns with a short count
+or with the error
+.Er EWOULDBLOCK
+if no data were received.
+.Pp
+.Dv SO_SETFIB
+can be used to over-ride the default FIB (routing table) for the given socket.
+The value must be from 0 to one less than the number returned from
+the sysctl
+.Em net.fibs .
+.Pp
+.Dv SO_USER_COOKIE
+can be used to set the uint32_t so_user_cookie field in the socket.
+The value is an uint32_t, and can be used in the kernel code that
+manipulates traffic related to the socket.
+The default value for the field is 0.
+As an example, the value can be used as the skipto target or
+pipe number in
+.Nm ipfw/dummynet .
+.Pp
+.Dv SO_ACCEPTFILTER
+places an
+.Xr accept_filter 9
+on the socket,
+which will filter incoming connections
+on a listening stream socket before being presented for
+.Xr accept 2 .
+Once more,
+.Xr listen 2
+must be called on the socket before
+trying to install the filter on it,
+or else the
+.Fn setsockopt
+system call will fail.
+.Bd -literal
+struct accept_filter_arg {
+ char af_name[16];
+ char af_arg[256-16];
+};
+.Ed
+.Pp
+The
+.Fa optval
+argument
+should point to a
+.Fa struct accept_filter_arg
+that will select and configure the
+.Xr accept_filter 9 .
+The
+.Fa af_name
+argument
+should be filled with the name of the accept filter
+that the application wishes to place on the listening socket.
+The optional argument
+.Fa af_arg
+can be passed to the accept
+filter specified by
+.Fa af_name
+to provide additional configuration options at attach time.
+Passing in an
+.Fa optval
+of NULL will remove the filter.
+.Pp
+The
+.Dv SO_NOSIGPIPE
+option controls generation of the
+.Dv SIGPIPE
+signal normally sent
+when writing to a connected socket where the other end has been
+closed returns with the error
+.Er EPIPE .
+.Pp
+If the
+.Dv SO_TIMESTAMP
+or
+.Dv SO_BINTIME
+option is enabled on a
+.Dv SOCK_DGRAM
+socket, the
+.Xr recvmsg 2
+call will return a timestamp corresponding to when the datagram was received.
+The
+.Va msg_control
+field in the
+.Vt msghdr
+structure points to a buffer that contains a
+.Vt cmsghdr
+structure followed by a
+.Vt "struct timeval"
+for
+.Dv SO_TIMESTAMP
+and
+.Vt "struct bintime"
+for
+.Dv SO_BINTIME .
+The
+.Vt cmsghdr
+fields have the following values for TIMESTAMP by default:
+.Bd -literal
+ cmsg_len = CMSG_LEN(sizeof(struct timeval));
+ cmsg_level = SOL_SOCKET;
+ cmsg_type = SCM_TIMESTAMP;
+.Ed
+.Pp
+and for
+.Dv SO_BINTIME :
+.Bd -literal
+ cmsg_len = CMSG_LEN(sizeof(struct bintime));
+ cmsg_level = SOL_SOCKET;
+ cmsg_type = SCM_BINTIME;
+.Ed
+.Pp
+Additional timestamp types are available by following
+.Dv SO_TIMESTAMP
+with
+.Dv SO_TS_CLOCK ,
+which requests a specific timestamp format to be returned instead of
+.Dv SCM_TIMESTAMP when
+.Dv SO_TIMESTAMP is enabled.
+These
+.Dv SO_TS_CLOCK
+values are recognized in
+.Fx :
+.Bl -column SO_TS_CLOCK -offset indent
+.It Dv SO_TS_REALTIME_MICRO Ta "realtime (SCM_TIMESTAMP, struct timeval), default"
+.It Dv SO_TS_BINTIME Ta "realtime (SCM_BINTIME, struct bintime)"
+.It Dv SO_TS_REALTIME Ta "realtime (SCM_REALTIME, struct timespec)"
+.It Dv SO_TS_MONOTONIC Ta "monotonic time (SCM_MONOTONIC, struct timespec)"
+.El
+.Pp
+.Dv SO_ACCEPTCONN ,
+.Dv SO_TYPE ,
+.Dv SO_PROTOCOL
+(and its alias
+.Dv SO_PROTOTYPE )
+and
+.Dv SO_ERROR
+are options used only with
+.Fn getsockopt .
+.Dv SO_ACCEPTCONN
+returns whether the socket is currently accepting connections,
+that is, whether or not the
+.Xr listen 2
+system call was invoked on the socket.
+.Dv SO_TYPE
+returns the type of the socket, such as
+.Dv SOCK_STREAM ;
+it is useful for servers that inherit sockets on startup.
+.Dv SO_PROTOCOL
+returns the protocol number for the socket, for
+.Dv AF_INET
+and
+.Dv AF_INET6
+address families.
+.Dv SO_ERROR
+returns any pending error on the socket and clears
+the error status.
+It may be used to check for asynchronous errors on connected
+datagram sockets or for other asynchronous errors.
+.Pp
+Finally,
+.Dv SO_LABEL
+returns the MAC label of the socket.
+.Dv SO_PEERLABEL
+returns the MAC label of the socket's peer.
+Note that your kernel must be compiled with MAC support.
+See
+.Xr mac 3
+for more information.
+.Dv SO_LISTENQLIMIT
+returns the maximal number of queued connections, as set by
+.Xr listen 2 .
+.Dv SO_LISTENQLEN
+returns the number of unaccepted complete connections.
+.Dv SO_LISTENINCQLEN
+returns the number of unaccepted incomplete connections.
+.Pp
+.Dv SO_MAX_PACING_RATE
+instruct the socket and underlying network adapter layers to limit the
+transfer rate to the given unsigned 32-bit value in bytes per second.
+.Sh RETURN VALUES
+.Rv -std
+.Sh ERRORS
+The call succeeds unless:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The argument
+.Fa s
+is not a valid descriptor.
+.It Bq Er ENOTSOCK
+The argument
+.Fa s
+is a file, not a socket.
+.It Bq Er ENOPROTOOPT
+The option is unknown at the level indicated.
+.It Bq Er EFAULT
+The address pointed to by
+.Fa optval
+is not in a valid part of the process address space.
+For
+.Fn getsockopt ,
+this error may also be returned if
+.Fa optlen
+is not in a valid part of the process address space.
+.It Bq Er EINVAL
+Installing an
+.Xr accept_filter 9
+on a non-listening socket was attempted.
+.El
+.Sh SEE ALSO
+.Xr ioctl 2 ,
+.Xr listen 2 ,
+.Xr recvmsg 2 ,
+.Xr socket 2 ,
+.Xr getprotoent 3 ,
+.Xr mac 3 ,
+.Xr sysctl 3 ,
+.Xr ip 4 ,
+.Xr ip6 4 ,
+.Xr sctp 4 ,
+.Xr tcp 4 ,
+.Xr protocols 5 ,
+.Xr sysctl 8 ,
+.Xr accept_filter 9 ,
+.Xr bintime 9
+.Sh HISTORY
+The
+.Fn getsockopt
+and
+.Fn setsockopt
+system calls appeared in
+.Bx 4.2 .
+.Sh BUGS
+Several of the socket options should be handled at lower levels of the system.
diff --git a/lib/libc/sys/gettimeofday.2 b/lib/libc/sys/gettimeofday.2
new file mode 100644
index 000000000000..86b6b1aa1937
--- /dev/null
+++ b/lib/libc/sys/gettimeofday.2
@@ -0,0 +1,132 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)gettimeofday.2 8.2 (Berkeley) 5/26/95
+.\" $FreeBSD$
+.\"
+.Dd December 27, 2015
+.Dt GETTIMEOFDAY 2
+.Os
+.Sh NAME
+.Nm gettimeofday ,
+.Nm settimeofday
+.Nd get/set date and time
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/time.h
+.Ft int
+.Fn gettimeofday "struct timeval *tp" "struct timezone *tzp"
+.Ft int
+.Fn settimeofday "const struct timeval *tp" "const struct timezone *tzp"
+.Sh DESCRIPTION
+.Bf -symbolic
+Note: timezone is no longer used; this information is kept outside
+the kernel.
+.Ef
+.Pp
+The system's notion of the current Greenwich time and the current time
+zone is obtained with the
+.Fn gettimeofday
+system call, and set with the
+.Fn settimeofday
+system call.
+The time is expressed in seconds and microseconds
+since midnight (0 hour), January 1, 1970.
+The resolution of the system
+clock is hardware dependent, and the time may be updated continuously or
+in
+.Dq ticks .
+If
+.Fa tp
+or
+.Fa tzp
+is NULL, the associated time
+information will not be returned or set.
+.Pp
+The structures pointed to by
+.Fa tp
+and
+.Fa tzp
+are defined in
+.In sys/time.h
+as:
+.Bd -literal
+struct timeval {
+ time_t tv_sec; /* seconds */
+ suseconds_t tv_usec; /* and microseconds */
+};
+
+struct timezone {
+ int tz_minuteswest; /* minutes west of Greenwich */
+ int tz_dsttime; /* type of dst correction */
+};
+.Ed
+.Pp
+The
+.Vt timezone
+structure indicates the local time zone
+(measured in minutes of time westward from Greenwich),
+and a flag that, if nonzero, indicates that
+Daylight Saving time applies locally during
+the appropriate part of the year.
+.Pp
+Only the super-user may set the time of day or time zone.
+If the system is running at securelevel >= 2 (see
+.Xr init 8 ) ,
+the time may only be advanced or retarded by a maximum of one second.
+This limitation is imposed to prevent a malicious super-user
+from setting arbitrary time stamps on files.
+The system time can be adjusted backwards without restriction using the
+.Xr adjtime 2
+system call even when the system is secure.
+.Sh RETURN VALUES
+.Rv -std
+.Sh ERRORS
+The following error codes may be set in
+.Va errno :
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The supplied
+.Fa timeval
+value is invalid.
+.It Bq Er EPERM
+A user other than the super-user attempted to set the time.
+.El
+.Sh SEE ALSO
+.Xr date 1 ,
+.Xr adjtime 2 ,
+.Xr clock_gettime 2 ,
+.Xr ctime 3 ,
+.Xr timeradd 3 ,
+.Xr clocks 7 ,
+.Xr timed 8
+.Sh HISTORY
+The
+.Fn gettimeofday
+system call appeared in
+.Bx 4.2 .
diff --git a/lib/libc/sys/gettimeofday.c b/lib/libc/sys/gettimeofday.c
new file mode 100644
index 000000000000..5b1252314c39
--- /dev/null
+++ b/lib/libc/sys/gettimeofday.c
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 2012 Konstantin Belousov <kib@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/vdso.h>
+#include <errno.h>
+#include "libc_private.h"
+
+int __gettimeofday(struct timeval *tv, struct timezone *tz);
+
+__weak_reference(__gettimeofday, gettimeofday);
+
+int
+__gettimeofday(struct timeval *tv, struct timezone *tz)
+{
+ int error;
+
+ error = __vdso_gettimeofday(tv, tz);
+ if (error == ENOSYS)
+ error = __sys_gettimeofday(tv, tz);
+ return (error);
+}
diff --git a/lib/libc/sys/getuid.2 b/lib/libc/sys/getuid.2
new file mode 100644
index 000000000000..414535698f89
--- /dev/null
+++ b/lib/libc/sys/getuid.2
@@ -0,0 +1,89 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)getuid.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd December 15, 2015
+.Dt GETUID 2
+.Os
+.Sh NAME
+.Nm getuid ,
+.Nm geteuid
+.Nd get user identification
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft uid_t
+.Fn getuid void
+.Ft uid_t
+.Fn geteuid void
+.Sh DESCRIPTION
+The
+.Fn getuid
+system call returns the real user ID of the calling process.
+The
+.Fn geteuid
+system call
+returns the effective user ID of the calling process.
+.Pp
+The real user ID is that of the user who has invoked the program.
+As the effective user ID
+gives the process additional permissions during
+execution of
+.Dq Em set-user-ID
+mode processes,
+.Fn getuid
+is used to determine the real-user-id of the calling process.
+.Sh ERRORS
+The
+.Fn getuid
+and
+.Fn geteuid
+system calls are always successful, and no return value is reserved to
+indicate an error.
+.Sh SEE ALSO
+.Xr getgid 2 ,
+.Xr issetugid 2 ,
+.Xr setgid 2 ,
+.Xr setreuid 2 ,
+.Xr setuid 2
+.Sh STANDARDS
+The
+.Fn geteuid
+and
+.Fn getuid
+system calls are expected to conform to
+.St -p1003.1-90 .
+.Sh HISTORY
+The
+.Fn getuid
+and
+.Fn geteuid
+functions appeared in
+.At v7 .
diff --git a/lib/libc/sys/interposing_table.c b/lib/libc/sys/interposing_table.c
new file mode 100644
index 000000000000..1447e42ef238
--- /dev/null
+++ b/lib/libc/sys/interposing_table.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2014 The FreeBSD Foundation.
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Konstantin Belousov
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice(s), this list of conditions and the following disclaimer as
+ * the first lines of this file unmodified other than the possible
+ * addition of one or more copyright notices.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice(s), this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include "libc_private.h"
+
+#define SLOT(a, b) \
+ [INTERPOS_##a] = (interpos_func_t)b
+interpos_func_t __libc_interposing[INTERPOS_MAX] = {
+ SLOT(accept, __sys_accept),
+ SLOT(accept4, __sys_accept4),
+ SLOT(aio_suspend, __sys_aio_suspend),
+ SLOT(close, __sys_close),
+ SLOT(connect, __sys_connect),
+ SLOT(fcntl, __sys_fcntl),
+ SLOT(fsync, __sys_fsync),
+ SLOT(fork, __sys_fork),
+ SLOT(msync, __sys_msync),
+ SLOT(nanosleep, __sys_nanosleep),
+ SLOT(openat, __sys_openat),
+ SLOT(poll, __sys_poll),
+ SLOT(pselect, __sys_pselect),
+ SLOT(read, __sys_read),
+ SLOT(readv, __sys_readv),
+ SLOT(recvfrom, __sys_recvfrom),
+ SLOT(recvmsg, __sys_recvmsg),
+ SLOT(select, __sys_select),
+ SLOT(sendmsg, __sys_sendmsg),
+ SLOT(sendto, __sys_sendto),
+ SLOT(setcontext, __sys_setcontext),
+ SLOT(sigaction, __sys_sigaction),
+ SLOT(sigprocmask, __sys_sigprocmask),
+ SLOT(sigsuspend, __sys_sigsuspend),
+ SLOT(sigwait, __libc_sigwait),
+ SLOT(sigtimedwait, __sys_sigtimedwait),
+ SLOT(sigwaitinfo, __sys_sigwaitinfo),
+ SLOT(swapcontext, __sys_swapcontext),
+ SLOT(system, __libc_system),
+ SLOT(tcdrain, __libc_tcdrain),
+ SLOT(wait4, __sys_wait4),
+ SLOT(write, __sys_write),
+ SLOT(writev, __sys_writev),
+ SLOT(_pthread_mutex_init_calloc_cb, _pthread_mutex_init_calloc_cb_stub),
+ SLOT(spinlock, __libc_spinlock_stub),
+ SLOT(spinunlock, __libc_spinunlock_stub),
+ SLOT(kevent, __sys_kevent),
+ SLOT(wait6, __sys_wait6),
+ SLOT(ppoll, __sys_ppoll),
+ SLOT(map_stacks_exec, __libc_map_stacks_exec),
+ SLOT(fdatasync, __sys_fdatasync),
+};
+#undef SLOT
+
+interpos_func_t *
+__libc_interposing_slot(int interposno)
+{
+
+ return (&__libc_interposing[interposno]);
+}
diff --git a/lib/libc/sys/intro.2 b/lib/libc/sys/intro.2
new file mode 100644
index 000000000000..5a3e17e901f9
--- /dev/null
+++ b/lib/libc/sys/intro.2
@@ -0,0 +1,754 @@
+.\" Copyright (c) 1980, 1983, 1986, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)intro.2 8.5 (Berkeley) 2/27/95
+.\" $FreeBSD$
+.\"
+.Dd September 8, 2016
+.Dt INTRO 2
+.Os
+.Sh NAME
+.Nm intro
+.Nd introduction to system calls and error numbers
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In errno.h
+.Sh DESCRIPTION
+This section provides an overview of the system calls,
+their error returns, and other common definitions and concepts.
+.\".Pp
+.\".Sy System call restart
+.\".Pp
+.\"(more later...)
+.Sh RETURN VALUES
+Nearly all of the system calls provide an error number referenced via
+the external identifier errno.
+This identifier is defined in
+.In sys/errno.h
+as
+.Pp
+.Dl extern int * __error();
+.Dl #define errno (* __error())
+.Pp
+The
+.Va __error()
+function returns a pointer to a field in the thread specific structure for
+threads other than the initial thread.
+For the initial thread and
+non-threaded processes,
+.Va __error()
+returns a pointer to a global
+.Va errno
+variable that is compatible with the previous definition.
+.Pp
+When a system call detects an error,
+it returns an integer value
+indicating failure (usually -1)
+and sets the variable
+.Va errno
+accordingly.
+(This allows interpretation of the failure on receiving
+a -1 and to take action accordingly.)
+Successful calls never set
+.Va errno ;
+once set, it remains until another error occurs.
+It should only be examined after an error.
+Note that a number of system calls overload the meanings of these
+error numbers, and that the meanings must be interpreted according
+to the type and circumstances of the call.
+.Pp
+The following is a complete list of the errors and their
+names as given in
+.In sys/errno.h .
+.Bl -hang -width Ds
+.It Er 0 Em "Undefined error: 0" .
+Not used.
+.It Er 1 EPERM Em "Operation not permitted" .
+An attempt was made to perform an operation limited to processes
+with appropriate privileges or to the owner of a file or other
+resources.
+.It Er 2 ENOENT Em "No such file or directory" .
+A component of a specified pathname did not exist, or the
+pathname was an empty string.
+.It Er 3 ESRCH Em "No such process" .
+No process could be found corresponding to that specified by the given
+process ID.
+.It Er 4 EINTR Em "Interrupted system call" .
+An asynchronous signal (such as
+.Dv SIGINT
+or
+.Dv SIGQUIT )
+was caught by the process during the execution of an interruptible
+function.
+If the signal handler performs a normal return, the
+interrupted system call will seem to have returned the error condition.
+.It Er 5 EIO Em "Input/output error" .
+Some physical input or output error occurred.
+This error will not be reported until a subsequent operation on the same file
+descriptor and may be lost (over written) by any subsequent errors.
+.It Er 6 ENXIO Em "Device not configured" .
+Input or output on a special file referred to a device that did not
+exist, or
+made a request beyond the limits of the device.
+This error may also occur when, for example,
+a tape drive is not online or no disk pack is
+loaded on a drive.
+.It Er 7 E2BIG Em "Argument list too long" .
+The number of bytes used for the argument and environment
+list of the new process exceeded the current limit
+.Dv ( NCARGS
+in
+.In sys/param.h ) .
+.It Er 8 ENOEXEC Em "Exec format error" .
+A request was made to execute a file
+that, although it has the appropriate permissions,
+was not in the format required for an
+executable file.
+.It Er 9 EBADF Em "Bad file descriptor" .
+A file descriptor argument was out of range, referred to no open file,
+or a read (write) request was made to a file that was only open for
+writing (reading).
+.It Er 10 ECHILD Em "\&No child processes" .
+A
+.Xr wait 2
+or
+.Xr waitpid 2
+function was executed by a process that had no existing or unwaited-for
+child processes.
+.It Er 11 EDEADLK Em "Resource deadlock avoided" .
+An attempt was made to lock a system resource that
+would have resulted in a deadlock situation.
+.It Er 12 ENOMEM Em "Cannot allocate memory" .
+The new process image required more memory than was allowed by the hardware
+or by system-imposed memory management constraints.
+A lack of swap space is normally temporary; however,
+a lack of core is not.
+Soft limits may be increased to their corresponding hard limits.
+.It Er 13 EACCES Em "Permission denied" .
+An attempt was made to access a file in a way forbidden
+by its file access permissions.
+.It Er 14 EFAULT Em "Bad address" .
+The system detected an invalid address in attempting to
+use an argument of a call.
+.It Er 15 ENOTBLK Em "Block device required" .
+A block device operation was attempted on a non-block device or file.
+.It Er 16 EBUSY Em "Device busy" .
+An attempt to use a system resource which was in use at the time
+in a manner which would have conflicted with the request.
+.It Er 17 EEXIST Em "File exists" .
+An existing file was mentioned in an inappropriate context,
+for instance, as the new link name in a
+.Xr link 2
+system call.
+.It Er 18 EXDEV Em "Cross-device link" .
+A hard link to a file on another file system
+was attempted.
+.It Er 19 ENODEV Em "Operation not supported by device" .
+An attempt was made to apply an inappropriate
+function to a device,
+for example,
+trying to read a write-only device such as a printer.
+.It Er 20 ENOTDIR Em "Not a directory" .
+A component of the specified pathname existed, but it was
+not a directory, when a directory was expected.
+.It Er 21 EISDIR Em "Is a directory" .
+An attempt was made to open a directory with write mode specified.
+.It Er 22 EINVAL Em "Invalid argument" .
+Some invalid argument was supplied.
+(For example,
+specifying an undefined signal to a
+.Xr signal 3
+function
+or a
+.Xr kill 2
+system call).
+.It Er 23 ENFILE Em "Too many open files in system" .
+Maximum number of open files allowable on the system
+has been reached and requests for an open cannot be satisfied
+until at least one has been closed.
+.It Er 24 EMFILE Em "Too many open files" .
+Maximum number of file descriptors allowable in the process
+has been reached and requests for an open cannot be satisfied
+until at least one has been closed.
+The
+.Xr getdtablesize 2
+system call will obtain the current limit.
+.It Er 25 ENOTTY Em "Inappropriate ioctl for device" .
+A control function (see
+.Xr ioctl 2 )
+was attempted for a file or
+special device for which the operation was inappropriate.
+.It Er 26 ETXTBSY Em "Text file busy" .
+The new process was a pure procedure (shared text) file
+which was open for writing by another process, or
+while the pure procedure file was being executed an
+.Xr open 2
+call requested write access.
+.It Er 27 EFBIG Em "File too large" .
+The size of a file exceeded the maximum.
+.It Er 28 ENOSPC Em "No space left on device" .
+A
+.Xr write 2
+to an ordinary file, the creation of a
+directory or symbolic link, or the creation of a directory
+entry failed because no more disk blocks were available
+on the file system, or the allocation of an inode for a newly
+created file failed because no more inodes were available
+on the file system.
+.It Er 29 ESPIPE Em "Illegal seek" .
+An
+.Xr lseek 2
+system call was issued on a socket, pipe or
+.Tn FIFO .
+.It Er 30 EROFS Em "Read-only file system" .
+An attempt was made to modify a file or directory
+on a file system that was read-only at the time.
+.It Er 31 EMLINK Em "Too many links" .
+Maximum allowable hard links to a single file has been exceeded (limit
+of 32767 hard links per file).
+.It Er 32 EPIPE Em "Broken pipe" .
+A write on a pipe, socket or
+.Tn FIFO
+for which there is no process
+to read the data.
+.It Er 33 EDOM Em "Numerical argument out of domain" .
+A numerical input argument was outside the defined domain of the mathematical
+function.
+.It Er 34 ERANGE Em "Result too large" .
+A numerical result of the function was too large to fit in the
+available space (perhaps exceeded precision).
+.It Er 35 EAGAIN Em "Resource temporarily unavailable" .
+This is a temporary condition and later calls to the
+same routine may complete normally.
+.It Er 36 EINPROGRESS Em "Operation now in progress" .
+An operation that takes a long time to complete (such as
+a
+.Xr connect 2 )
+was attempted on a non-blocking object (see
+.Xr fcntl 2 ) .
+.It Er 37 EALREADY Em "Operation already in progress" .
+An operation was attempted on a non-blocking object that already
+had an operation in progress.
+.It Er 38 ENOTSOCK Em "Socket operation on non-socket" .
+Self-explanatory.
+.It Er 39 EDESTADDRREQ Em "Destination address required" .
+A required address was omitted from an operation on a socket.
+.It Er 40 EMSGSIZE Em "Message too long" .
+A message sent on a socket was larger than the internal message buffer
+or some other network limit.
+.It Er 41 EPROTOTYPE Em "Protocol wrong type for socket" .
+A protocol was specified that does not support the semantics of the
+socket type requested.
+For example, you cannot use the
+.Tn ARPA
+Internet
+.Tn UDP
+protocol with type
+.Dv SOCK_STREAM .
+.It Er 42 ENOPROTOOPT Em "Protocol not available" .
+A bad option or level was specified in a
+.Xr getsockopt 2
+or
+.Xr setsockopt 2
+call.
+.It Er 43 EPROTONOSUPPORT Em "Protocol not supported" .
+The protocol has not been configured into the
+system or no implementation for it exists.
+.It Er 44 ESOCKTNOSUPPORT Em "Socket type not supported" .
+The support for the socket type has not been configured into the
+system or no implementation for it exists.
+.It Er 45 EOPNOTSUPP Em "Operation not supported" .
+The attempted operation is not supported for the type of object referenced.
+Usually this occurs when a file descriptor refers to a file or socket
+that cannot support this operation,
+for example, trying to
+.Em accept
+a connection on a datagram socket.
+.It Er 46 EPFNOSUPPORT Em "Protocol family not supported" .
+The protocol family has not been configured into the
+system or no implementation for it exists.
+.It Er 47 EAFNOSUPPORT Em "Address family not supported by protocol family" .
+An address incompatible with the requested protocol was used.
+For example, you should not necessarily expect to be able to use
+.Tn NS
+addresses with
+.Tn ARPA
+Internet protocols.
+.It Er 48 EADDRINUSE Em "Address already in use" .
+Only one usage of each address is normally permitted.
+.It Er 49 EADDRNOTAVAIL Em "Can't assign requested address" .
+Normally results from an attempt to create a socket with an
+address not on this machine.
+.It Er 50 ENETDOWN Em "Network is down" .
+A socket operation encountered a dead network.
+.It Er 51 ENETUNREACH Em "Network is unreachable" .
+A socket operation was attempted to an unreachable network.
+.It Er 52 ENETRESET Em "Network dropped connection on reset" .
+The host you were connected to crashed and rebooted.
+.It Er 53 ECONNABORTED Em "Software caused connection abort" .
+A connection abort was caused internal to your host machine.
+.It Er 54 ECONNRESET Em "Connection reset by peer" .
+A connection was forcibly closed by a peer.
+This normally
+results from a loss of the connection on the remote socket
+due to a timeout or a reboot.
+.It Er 55 ENOBUFS Em "\&No buffer space available" .
+An operation on a socket or pipe was not performed because
+the system lacked sufficient buffer space or because a queue was full.
+.It Er 56 EISCONN Em "Socket is already connected" .
+A
+.Xr connect 2
+request was made on an already connected socket; or,
+a
+.Xr sendto 2
+or
+.Xr sendmsg 2
+request on a connected socket specified a destination
+when already connected.
+.It Er 57 ENOTCONN Em "Socket is not connected" .
+An request to send or receive data was disallowed because
+the socket was not connected and (when sending on a datagram socket)
+no address was supplied.
+.It Er 58 ESHUTDOWN Em "Can't send after socket shutdown" .
+A request to send data was disallowed because the socket
+had already been shut down with a previous
+.Xr shutdown 2
+call.
+.It Er 60 ETIMEDOUT Em "Operation timed out" .
+A
+.Xr connect 2
+or
+.Xr send 2
+request failed because the connected party did not
+properly respond after a period of time.
+(The timeout
+period is dependent on the communication protocol.)
+.It Er 61 ECONNREFUSED Em "Connection refused" .
+No connection could be made because the target machine actively
+refused it.
+This usually results from trying to connect
+to a service that is inactive on the foreign host.
+.It Er 62 ELOOP Em "Too many levels of symbolic links" .
+A path name lookup involved more than 32
+.Pq Dv MAXSYMLINKS
+symbolic links.
+.It Er 63 ENAMETOOLONG Em "File name too long" .
+A component of a path name exceeded
+.Brq Dv NAME_MAX
+characters, or an entire
+path name exceeded
+.Brq Dv PATH_MAX
+characters.
+(See also the description of
+.Dv _PC_NO_TRUNC
+in
+.Xr pathconf 2 . )
+.It Er 64 EHOSTDOWN Em "Host is down" .
+A socket operation failed because the destination host was down.
+.It Er 65 EHOSTUNREACH Em "No route to host" .
+A socket operation was attempted to an unreachable host.
+.It Er 66 ENOTEMPTY Em "Directory not empty" .
+A directory with entries other than
+.Ql .\&
+and
+.Ql ..\&
+was supplied to a remove directory or rename call.
+.It Er 67 EPROCLIM Em "Too many processes" .
+.It Er 68 EUSERS Em "Too many users" .
+The quota system ran out of table entries.
+.It Er 69 EDQUOT Em "Disc quota exceeded" .
+A
+.Xr write 2
+to an ordinary file, the creation of a
+directory or symbolic link, or the creation of a directory
+entry failed because the user's quota of disk blocks was
+exhausted, or the allocation of an inode for a newly
+created file failed because the user's quota of inodes
+was exhausted.
+.It Er 70 ESTALE Em "Stale NFS file handle" .
+An attempt was made to access an open file (on an
+.Tn NFS
+file system)
+which is now unavailable as referenced by the file descriptor.
+This may indicate the file was deleted on the
+.Tn NFS
+server or some
+other catastrophic event occurred.
+.It Er 72 EBADRPC Em "RPC struct is bad" .
+Exchange of
+.Tn RPC
+information was unsuccessful.
+.It Er 73 ERPCMISMATCH Em "RPC version wrong" .
+The version of
+.Tn RPC
+on the remote peer is not compatible with
+the local version.
+.It Er 74 EPROGUNAVAIL Em "RPC prog. not avail" .
+The requested program is not registered on the remote host.
+.It Er 75 EPROGMISMATCH Em "Program version wrong" .
+The requested version of the program is not available
+on the remote host
+.Pq Tn RPC .
+.It Er 76 EPROCUNAVAIL Em "Bad procedure for program" .
+An
+.Tn RPC
+call was attempted for a procedure which does not exist
+in the remote program.
+.It Er 77 ENOLCK Em "No locks available" .
+A system-imposed limit on the number of simultaneous file
+locks was reached.
+.It Er 78 ENOSYS Em "Function not implemented" .
+Attempted a system call that is not available on this
+system.
+.It Er 79 EFTYPE Em "Inappropriate file type or format" .
+The file was the wrong type for the operation, or a data file had
+the wrong format.
+.It Er 80 EAUTH Em "Authentication error" .
+Attempted to use an invalid authentication ticket to mount a
+.Tn NFS
+file system.
+.It Er 81 ENEEDAUTH Em "Need authenticator" .
+An authentication ticket must be obtained before the given
+.Tn NFS
+file system may be mounted.
+.It Er 82 EIDRM Em "Identifier removed" .
+An IPC identifier was removed while the current process was waiting on it.
+.It Er 83 ENOMSG Em "No message of desired type" .
+An IPC message queue does not contain a message of the desired type, or a
+message catalog does not contain the requested message.
+.It Er 84 EOVERFLOW Em "Value too large to be stored in data type" .
+A numerical result of the function was too large to be stored in the caller
+provided space.
+.It Er 85 ECANCELED Em "Operation canceled" .
+The scheduled operation was canceled.
+.It Er 86 EILSEQ Em "Illegal byte sequence" .
+While decoding a multibyte character the function came along an
+invalid or an incomplete sequence of bytes or the given wide
+character is invalid.
+.It Er 87 ENOATTR Em "Attribute not found" .
+The specified extended attribute does not exist.
+.It Er 88 EDOOFUS Em "Programming error" .
+A function or API is being abused in a way which could only be detected
+at run-time.
+.It Er 89 EBADMSG Em "Bad message" .
+A corrupted message was detected.
+.It Er 90 EMULTIHOP Em "Multihop attempted" .
+This error code is unused, but present for compatibility with other systems.
+.It Er 91 ENOLINK Em "Link has been severed" .
+This error code is unused, but present for compatibility with other systems.
+.It Er 92 EPROTO Em "Protocol error" .
+A device or socket encountered an unrecoverable protocol error.
+.It Er 93 ENOTCAPABLE Em "Capabilities insufficient" .
+An operation on a capability file descriptor requires greater privilege than
+the capability allows.
+.It Er 94 ECAPMODE Em "Not permitted in capability mode" .
+The system call or operation is not permitted for capability mode processes.
+.It Er 95 ENOTRECOVERABLE Em "State not recoverable" .
+The state protected by a robust mutex is not recoverable.
+.It Er 96 EOWNERDEAD Em "Previous owner died" .
+The owner of a robust mutex terminated while holding the mutex lock.
+.El
+.Sh DEFINITIONS
+.Bl -tag -width Ds
+.It Process ID .
+Each active process in the system is uniquely identified by a non-negative
+integer called a process ID.
+The range of this ID is from 0 to 99999.
+.It Parent process ID
+A new process is created by a currently active process (see
+.Xr fork 2 ) .
+The parent process ID of a process is initially the process ID of its creator.
+If the creating process exits,
+the parent process ID of each child is set to the ID of the calling process's
+reaper (see
+.Xr procctl 2 ) ,
+normally
+.Xr init 8 .
+.It Process Group
+Each active process is a member of a process group that is identified by
+a non-negative integer called the process group ID.
+This is the process
+ID of the group leader.
+This grouping permits the signaling of related
+processes (see
+.Xr termios 4 )
+and the job control mechanisms of
+.Xr csh 1 .
+.It Session
+A session is a set of one or more process groups.
+A session is created by a successful call to
+.Xr setsid 2 ,
+which causes the caller to become the only member of the only process
+group in the new session.
+.It Session leader
+A process that has created a new session by a successful call to
+.Xr setsid 2 ,
+is known as a session leader.
+Only a session leader may acquire a terminal as its controlling terminal (see
+.Xr termios 4 ) .
+.It Controlling process
+A session leader with a controlling terminal is a controlling process.
+.It Controlling terminal
+A terminal that is associated with a session is known as the controlling
+terminal for that session and its members.
+.It "Terminal Process Group ID"
+A terminal may be acquired by a session leader as its controlling terminal.
+Once a terminal is associated with a session, any of the process groups
+within the session may be placed into the foreground by setting
+the terminal process group ID to the ID of the process group.
+This facility is used
+to arbitrate between multiple jobs contending for the same terminal;
+(see
+.Xr csh 1
+and
+.Xr tty 4 ) .
+.It "Orphaned Process Group"
+A process group is considered to be
+.Em orphaned
+if it is not under the control of a job control shell.
+More precisely, a process group is orphaned
+when none of its members has a parent process that is in the same session
+as the group,
+but is in a different process group.
+Note that when a process exits, the parent process for its children
+is normally changed to be
+.Xr init 8 ,
+which is in a separate session.
+Not all members of an orphaned process group are necessarily orphaned
+processes (those whose creating process has exited).
+The process group of a session leader is orphaned by definition.
+.It "Real User ID and Real Group ID"
+Each user on the system is identified by a positive integer
+termed the real user ID.
+.Pp
+Each user is also a member of one or more groups.
+One of these groups is distinguished from others and
+used in implementing accounting facilities.
+The positive
+integer corresponding to this distinguished group is termed
+the real group ID.
+.Pp
+All processes have a real user ID and real group ID.
+These are initialized from the equivalent attributes
+of the process that created it.
+.It "Effective User Id, Effective Group Id, and Group Access List"
+Access to system resources is governed by two values:
+the effective user ID, and the group access list.
+The first member of the group access list is also known as the
+effective group ID.
+(In POSIX.1, the group access list is known as the set of supplementary
+group IDs, and it is unspecified whether the effective group ID is
+a member of the list.)
+.Pp
+The effective user ID and effective group ID are initially the
+process's real user ID and real group ID respectively.
+Either
+may be modified through execution of a set-user-ID or set-group-ID
+file (possibly by one its ancestors) (see
+.Xr execve 2 ) .
+By convention, the effective group ID (the first member of the group access
+list) is duplicated, so that the execution of a set-group-ID program
+does not result in the loss of the original (real) group ID.
+.Pp
+The group access list is a set of group IDs
+used only in determining resource accessibility.
+Access checks
+are performed as described below in ``File Access Permissions''.
+.It "Saved Set User ID and Saved Set Group ID"
+When a process executes a new file, the effective user ID is set
+to the owner of the file if the file is set-user-ID, and the effective
+group ID (first element of the group access list) is set to the group
+of the file if the file is set-group-ID.
+The effective user ID of the process is then recorded as the saved set-user-ID,
+and the effective group ID of the process is recorded as the saved set-group-ID.
+These values may be used to regain those values as the effective user
+or group ID after reverting to the real ID (see
+.Xr setuid 2 ) .
+(In POSIX.1, the saved set-user-ID and saved set-group-ID are optional,
+and are used in setuid and setgid, but this does not work as desired
+for the super-user.)
+.It Super-user
+A process is recognized as a
+.Em super-user
+process and is granted special privileges if its effective user ID is 0.
+.It Descriptor
+An integer assigned by the system when a file is referenced
+by
+.Xr open 2
+or
+.Xr dup 2 ,
+or when a socket is created by
+.Xr pipe 2 ,
+.Xr socket 2
+or
+.Xr socketpair 2 ,
+which uniquely identifies an access path to that file or socket from
+a given process or any of its children.
+.It File Name
+Names consisting of up to
+.Brq Dv NAME_MAX
+characters may be used to name
+an ordinary file, special file, or directory.
+.Pp
+These characters may be arbitrary eight-bit values,
+excluding
+.Dv NUL
+.Tn ( ASCII
+0) and the
+.Ql \&/
+character (slash,
+.Tn ASCII
+47).
+.Pp
+Note that it is generally unwise to use
+.Ql \&* ,
+.Ql \&? ,
+.Ql \&[
+or
+.Ql \&]
+as part of
+file names because of the special meaning attached to these characters
+by the shell.
+.It Path Name
+A path name is a
+.Dv NUL Ns -terminated
+character string starting with an
+optional slash
+.Ql \&/ ,
+followed by zero or more directory names separated
+by slashes, optionally followed by a file name.
+The total length of a path name must be less than
+.Brq Dv PATH_MAX
+characters.
+(On some systems, this limit may be infinite.)
+.Pp
+If a path name begins with a slash, the path search begins at the
+.Em root
+directory.
+Otherwise, the search begins from the current working directory.
+A slash by itself names the root directory.
+An empty
+pathname refers to the current directory.
+.It Directory
+A directory is a special type of file that contains entries
+that are references to other files.
+Directory entries are called links.
+By convention, a directory
+contains at least two links,
+.Ql .\&
+and
+.Ql \&.. ,
+referred to as
+.Em dot
+and
+.Em dot-dot
+respectively.
+Dot refers to the directory itself and
+dot-dot refers to its parent directory.
+.It "Root Directory and Current Working Directory"
+Each process has associated with it a concept of a root directory
+and a current working directory for the purpose of resolving path
+name searches.
+A process's root directory need not be the root
+directory of the root file system.
+.It File Access Permissions
+Every file in the file system has a set of access permissions.
+These permissions are used in determining whether a process
+may perform a requested operation on the file (such as opening
+a file for writing).
+Access permissions are established at the
+time a file is created.
+They may be changed at some later time
+through the
+.Xr chmod 2
+call.
+.Pp
+File access is broken down according to whether a file may be: read,
+written, or executed.
+Directory files use the execute
+permission to control if the directory may be searched.
+.Pp
+File access permissions are interpreted by the system as
+they apply to three different classes of users: the owner
+of the file, those users in the file's group, anyone else.
+Every file has an independent set of access permissions for
+each of these classes.
+When an access check is made, the system
+decides if permission should be granted by checking the access
+information applicable to the caller.
+.Pp
+Read, write, and execute/search permissions on
+a file are granted to a process if:
+.Pp
+The process's effective user ID is that of the super-user.
+(Note:
+even the super-user cannot execute a non-executable file.)
+.Pp
+The process's effective user ID matches the user ID of the owner
+of the file and the owner permissions allow the access.
+.Pp
+The process's effective user ID does not match the user ID of the
+owner of the file, and either the process's effective
+group ID matches the group ID
+of the file, or the group ID of the file is in
+the process's group access list,
+and the group permissions allow the access.
+.Pp
+Neither the effective user ID nor effective group ID
+and group access list of the process
+match the corresponding user ID and group ID of the file,
+but the permissions for ``other users'' allow access.
+.Pp
+Otherwise, permission is denied.
+.It Sockets and Address Families
+A socket is an endpoint for communication between processes.
+Each socket has queues for sending and receiving data.
+.Pp
+Sockets are typed according to their communications properties.
+These properties include whether messages sent and received
+at a socket require the name of the partner, whether communication
+is reliable, the format used in naming message recipients, etc.
+.Pp
+Each instance of the system supports some
+collection of socket types; consult
+.Xr socket 2
+for more information about the types available and
+their properties.
+.Pp
+Each instance of the system supports some number of sets of
+communications protocols.
+Each protocol set supports addresses
+of a certain format.
+An Address Family is the set of addresses
+for a specific group of protocols.
+Each socket has an address
+chosen from the address family in which the socket was created.
+.El
+.Sh SEE ALSO
+.Xr intro 3 ,
+.Xr perror 3
diff --git a/lib/libc/sys/ioctl.2 b/lib/libc/sys/ioctl.2
new file mode 100644
index 000000000000..81500a938ac9
--- /dev/null
+++ b/lib/libc/sys/ioctl.2
@@ -0,0 +1,155 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)ioctl.2 8.2 (Berkeley) 12/11/93
+.\"
+.\" $FreeBSD$
+.\"
+.Dd September 11, 2013
+.Dt IOCTL 2
+.Os
+.Sh NAME
+.Nm ioctl
+.Nd control device
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/ioctl.h
+.Ft int
+.Fn ioctl "int fd" "unsigned long request" ...
+.Sh DESCRIPTION
+The
+.Fn ioctl
+system call manipulates the underlying device parameters of special files.
+In particular, many operating
+characteristics of character special files (e.g.\& terminals)
+may be controlled with
+.Fn ioctl
+requests.
+The argument
+.Fa fd
+must be an open file descriptor.
+.Pp
+The third argument to
+.Fn ioctl
+is traditionally named
+.Va "char *argp" .
+Most uses of
+.Fn ioctl ,
+however, require the third argument to be a
+.Vt caddr_t
+or an
+.Vt int .
+.Pp
+An
+.Fn ioctl
+.Fa request
+has encoded in it whether the argument is an
+.Dq in
+argument
+or
+.Dq out
+argument, and the size of the argument
+.Fa argp
+in bytes.
+Macros and defines used in specifying an ioctl
+.Fa request
+are located in the file
+.In sys/ioctl.h .
+.Sh GENERIC IOCTLS
+Some generic ioctls are not implemented for all types of file
+descriptors.
+These include:
+.Bl -tag -width "xxxxxx"
+.It Dv FIONREAD int
+Get the number of bytes that are immediately available for reading.
+.It Dv FIONWRITE int
+Get the number of bytes in the descriptor's send queue.
+These bytes are data which has been written to the descriptor but
+which are being held by the kernel for further processing.
+The nature of the required processing depends on the underlying device.
+For TCP sockets, these bytes have not yet been acknowledged by the
+other side of the connection.
+.It Dv FIONSPACE int
+Get the free space in the descriptor's send queue.
+This value is the size of the send queue minus the number of bytes
+being held in the queue.
+Note: while this value represents the number of bytes that may be
+added to the queue, other resource limitations may cause a write
+not larger than the send queue's space to be blocked.
+One such limitation would be a lack of network buffers for a write
+to a network connection.
+.El
+.Sh RETURN VALUES
+If an error has occurred, a value of -1 is returned and
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+The
+.Fn ioctl
+system call
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa fd
+argument
+is not a valid descriptor.
+.It Bq Er ENOTTY
+The
+.Fa fd
+argument
+is not associated with a character
+special device.
+.It Bq Er ENOTTY
+The specified request does not apply to the kind
+of object that the descriptor
+.Fa fd
+references.
+.It Bq Er EINVAL
+The
+.Fa request
+or
+.Fa argp
+argument
+is not valid.
+.It Bq Er EFAULT
+The
+.Fa argp
+argument
+points outside the process's allocated address space.
+.El
+.Sh SEE ALSO
+.Xr execve 2 ,
+.Xr fcntl 2 ,
+.Xr intro 4 ,
+.Xr tty 4
+.Sh HISTORY
+The
+.Fn ioctl
+function appeared in
+.At v7 .
diff --git a/lib/libc/sys/issetugid.2 b/lib/libc/sys/issetugid.2
new file mode 100644
index 000000000000..aed5062a10ad
--- /dev/null
+++ b/lib/libc/sys/issetugid.2
@@ -0,0 +1,98 @@
+.\" $OpenBSD: issetugid.2,v 1.7 1997/02/18 00:16:09 deraadt Exp $
+.\"
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd August 25, 1996
+.Dt ISSETUGID 2
+.Os
+.Sh NAME
+.Nm issetugid
+.Nd is current process tainted by uid or gid changes
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft int
+.Fn issetugid void
+.Sh DESCRIPTION
+The
+.Fn issetugid
+system call returns 1 if the process environment or memory address space
+is considered
+.Dq tainted ,
+and returns 0 otherwise.
+.Pp
+A process is tainted if it was created as a result of an
+.Xr execve 2
+system call which had either of the setuid or setgid bits set (and extra
+privileges were given as a result) or if it has changed any of its real,
+effective or saved user or group ID's since it began execution.
+.Pp
+This system call exists so that library routines (eg: libc, libtermcap)
+can reliably determine if it is safe to use information
+that was obtained from the user, in particular the results from
+.Xr getenv 3
+should be viewed with suspicion if it is used to control operation.
+.Pp
+A
+.Dq tainted
+status is inherited by child processes as a result of the
+.Xr fork 2
+system call (or other library code that calls fork, such as
+.Xr popen 3 ) .
+.Pp
+It is assumed that a program that clears all privileges as it prepares
+to execute another will also reset the environment, hence the
+.Dq tainted
+status will not be passed on.
+This is important for programs such as
+.Xr su 1
+which begin setuid but need to be able to create an untainted process.
+.Sh ERRORS
+The
+.Fn issetugid
+system call is always successful, and no return value is reserved to
+indicate an error.
+.Sh SEE ALSO
+.Xr execve 2 ,
+.Xr fork 2 ,
+.Xr setegid 2 ,
+.Xr seteuid 2 ,
+.Xr setgid 2 ,
+.Xr setregid 2 ,
+.Xr setreuid 2 ,
+.Xr setuid 2
+.Sh HISTORY
+The
+.Fn issetugid
+system call first appeared in
+.Ox 2.0
+and was also implemented in
+.Fx 3.0 .
diff --git a/lib/libc/sys/jail.2 b/lib/libc/sys/jail.2
new file mode 100644
index 000000000000..2e13a6c3a381
--- /dev/null
+++ b/lib/libc/sys/jail.2
@@ -0,0 +1,411 @@
+.\" Copyright (c) 1999 Poul-Henning Kamp.
+.\" Copyright (c) 2009 James Gritton.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 February 8, 2012
+.Dt JAIL 2
+.Os
+.Sh NAME
+.Nm jail ,
+.Nm jail_get ,
+.Nm jail_set ,
+.Nm jail_remove ,
+.Nm jail_attach
+.Nd create and manage system jails
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/param.h
+.In sys/jail.h
+.Ft int
+.Fn jail "struct jail *jail"
+.Ft int
+.Fn jail_attach "int jid"
+.Ft int
+.Fn jail_remove "int jid"
+.In sys/uio.h
+.Ft int
+.Fn jail_get "struct iovec *iov" "u_int niov" "int flags"
+.Ft int
+.Fn jail_set "struct iovec *iov" "u_int niov" "int flags"
+.Sh DESCRIPTION
+The
+.Fn jail
+system call sets up a jail and locks the current process in it.
+.Pp
+The argument is a pointer to a structure describing the prison:
+.Bd -literal -offset indent
+struct jail {
+ uint32_t version;
+ char *path;
+ char *hostname;
+ char *jailname;
+ unsigned int ip4s;
+ unsigned int ip6s;
+ struct in_addr *ip4;
+ struct in6_addr *ip6;
+};
+.Ed
+.Pp
+.Dq Li version
+defines the version of the API in use.
+.Dv JAIL_API_VERSION
+is defined for the current version.
+.Pp
+The
+.Dq Li path
+pointer should be set to the directory which is to be the root of the
+prison.
+.Pp
+The
+.Dq Li hostname
+pointer can be set to the hostname of the prison.
+This can be changed
+from the inside of the prison.
+.Pp
+The
+.Dq Li jailname
+pointer is an optional name that can be assigned to the jail
+for example for management purposes.
+.Pp
+The
+.Dq Li ip4s
+and
+.Dq Li ip6s
+give the numbers of IPv4 and IPv6 addresses that will be passed
+via their respective pointers.
+.Pp
+The
+.Dq Li ip4
+and
+.Dq Li ip6
+pointers can be set to an arrays of IPv4 and IPv6 addresses to be assigned to
+the prison, or NULL if none.
+IPv4 addresses must be in network byte order.
+.Pp
+This is equivalent to, and deprecated in favor of, the
+.Fn jail_set
+system call (see below), with the parameters
+.Va path ,
+.Va host.hostname ,
+.Va name ,
+.Va ip4.addr ,
+and
+.Va ip6.addr ,
+and with the
+.Dv JAIL_ATTACH
+flag.
+.Pp
+The
+.Fn jail_set
+system call creates a new jail, or modifies an existing one, and optionally
+locks the current process in it.
+Jail parameters are passed as an array of name-value pairs in the array
+.Fa iov ,
+containing
+.Fa niov
+elements.
+Parameter names are a null-terminated string, and values may be strings,
+integers, or other arbitrary data.
+Some parameters are boolean, and do not have a value (their length is zero)
+but are set by the name alone with or without a
+.Dq no
+prefix, e.g.
+.Va persist
+or
+.Va nopersist .
+Any parameters not set will be given default values, generally based on
+the current environment.
+.Pp
+Jails have a set of core parameters, and modules can add their own jail
+parameters.
+The current set of available parameters, and their formats, can be
+retrieved via the
+.Va security.jail.param
+sysctl MIB entry.
+Notable parameters include those mentioned in the
+.Fn jail
+description above, as well as
+.Va jid
+and
+.Va name ,
+which identify the jail being created or modified.
+See
+.Xr jail 8
+for more information on the core jail parameters.
+.Pp
+The
+.Fa flags
+arguments consists of one or more of the following flags:
+.Bl -tag -width indent
+.It Dv JAIL_CREATE
+Create a new jail.
+If a
+.Va jid
+or
+.Va name
+parameters exists, they must not refer to an existing jail.
+.It Dv JAIL_UPDATE
+Modify an existing jail.
+One of the
+.Va jid
+or
+.Va name
+parameters must exist, and must refer to an existing jail.
+If both
+.Dv JAIL_CREATE
+and
+.Dv JAIL_UPDATE
+are set, a jail will be created if it does not yet exist, and modified if it
+does exist.
+.It Dv JAIL_ATTACH
+In addition to creating or modifying the jail, attach the current process to
+it, as with the
+.Fn jail_attach
+system call.
+.It Dv JAIL_DYING
+Allow setting a jail that is in the process of being removed.
+.El
+.Pp
+The
+.Fn jail_get
+system call retrieves jail parameters, using the same name-value list as
+.Fn jail_set
+in the
+.Fa iov
+and
+.Fa niov
+arguments.
+The jail to read can be specified by either
+.Va jid
+or
+.Va name
+by including those parameters in the list.
+If they are included but are not intended to be the search key, they
+should be cleared (zero and the empty string respectively).
+.Pp
+The special parameter
+.Va lastjid
+can be used to retrieve a list of all jails.
+It will fetch the jail with the jid above and closest to the passed value.
+The first jail (usually but not always jid 1) can be found by passing a
+.Va lastjid
+of zero.
+.Pp
+The
+.Fa flags
+arguments consists of one or more following flags:
+.Bl -tag -width indent
+.It Dv JAIL_DYING
+Allow getting a jail that is in the process of being removed.
+.El
+.Pp
+The
+.Fn jail_attach
+system call attaches the current process to an existing jail,
+identified by
+.Fa jid .
+.Pp
+The
+.Fn jail_remove
+system call removes the jail identified by
+.Fa jid .
+It will kill all processes belonging to the jail, and remove any children
+of that jail.
+.Sh RETURN VALUES
+If successful,
+.Fn jail ,
+.Fn jail_set ,
+and
+.Fn jail_get
+return a non-negative integer, termed the jail identifier (JID).
+They return \-1 on failure, and set
+.Va errno
+to indicate the error.
+.Pp
+.Rv -std jail_attach jail_remove
+.Sh ERRORS
+The
+.Fn jail
+system call
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EPERM
+This process is not allowed to create a jail, either because it is not
+the super-user, or because it would exceed the jail's
+.Va children.max
+limit.
+.It Bq Er EFAULT
+.Fa jail
+points to an address outside the allocated address space of the process.
+.It Bq Er EINVAL
+The version number of the argument is not correct.
+.It Bq Er EAGAIN
+No free JID could be found.
+.El
+.Pp
+The
+.Fn jail_set
+system call
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EPERM
+This process is not allowed to create a jail, either because it is not
+the super-user, or because it would exceed the jail's
+.Va children.max
+limit.
+.It Bq Er EPERM
+A jail parameter was set to a less restrictive value then the current
+environment.
+.It Bq Er EFAULT
+.Fa Iov ,
+or one of the addresses contained within it,
+points to an address outside the allocated address space of the process.
+.It Bq Er ENOENT
+The jail referred to by a
+.Va jid
+or
+.Va name
+parameter does not exist, and the
+.Dv JAIL_CREATE
+flag is not set.
+.It Bq Er ENOENT
+The jail referred to by a
+.Va jid
+is not accessible by the process, because the process is in a different
+jail.
+.It Bq Er EEXIST
+The jail referred to by a
+.Va jid
+or
+.Va name
+parameter exists, and the
+.Dv JAIL_UPDATE
+flag is not set.
+.It Bq Er EINVAL
+A supplied parameter is the wrong size.
+.It Bq Er EINVAL
+A supplied parameter is out of range.
+.It Bq Er EINVAL
+A supplied string parameter is not null-terminated.
+.It Bq Er EINVAL
+A supplied parameter name does not match any known parameters.
+.It Bq Er EINVAL
+One of the
+.Dv JAIL_CREATE
+or
+.Dv JAIL_UPDATE
+flags is not set.
+.It Bq Er ENAMETOOLONG
+A supplied string parameter is longer than allowed.
+.It Bq Er EAGAIN
+There are no jail IDs left.
+.El
+.Pp
+The
+.Fn jail_get
+system call
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EFAULT
+.Fa Iov ,
+or one of the addresses contained within it,
+points to an address outside the allocated address space of the process.
+.It Bq Er ENOENT
+The jail referred to by a
+.Va jid
+or
+.Va name
+parameter does not exist.
+.It Bq Er ENOENT
+The jail referred to by a
+.Va jid
+is not accessible by the process, because the process is in a different
+jail.
+.It Bq Er ENOENT
+The
+.Va lastjid
+parameter is greater than the highest current jail ID.
+.It Bq Er EINVAL
+A supplied parameter is the wrong size.
+.It Bq Er EINVAL
+A supplied parameter name does not match any known parameters.
+.El
+.Pp
+The
+.Fn jail_attach
+and
+.Fn jail_remove
+system calls
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EPERM
+A user other than the super-user attempted to attach to or remove a jail.
+.It Bq Er EINVAL
+The jail specified by
+.Fa jid
+does not exist.
+.El
+.Pp
+Further
+.Fn jail ,
+.Fn jail_set ,
+and
+.Fn jail_attach
+call
+.Xr chroot 2
+internally, so they can fail for all the same reasons.
+Please consult the
+.Xr chroot 2
+manual page for details.
+.Sh SEE ALSO
+.Xr chdir 2 ,
+.Xr chroot 2 ,
+.Xr jail 8
+.Sh HISTORY
+The
+.Fn jail
+system call appeared in
+.Fx 4.0 .
+The
+.Fn jail_attach
+system call appeared in
+.Fx 5.1 .
+The
+.Fn jail_set ,
+.Fn jail_get ,
+and
+.Fn jail_remove
+system calls appeared in
+.Fx 8.0 .
+.Sh AUTHORS
+The jail feature was written by
+.An Poul-Henning Kamp
+for R&D Associates
+who contributed it to
+.Fx .
+.An James Gritton
+added the extensible jail parameters and hierarchical jails.
diff --git a/lib/libc/sys/kenv.2 b/lib/libc/sys/kenv.2
new file mode 100644
index 000000000000..dc17388f08ba
--- /dev/null
+++ b/lib/libc/sys/kenv.2
@@ -0,0 +1,179 @@
+.\"
+.\" Copyright (C) 2002 Chad David <davidc@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(s), this list of conditions and the following disclaimer as
+.\" the first lines of this file unmodified other than the possible
+.\" addition of one or more copyright notices.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice(s), this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+.\" EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+.\" DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
+.\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+.\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+.\" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+.\" CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+.\" DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd April 17, 2002
+.Dt KENV 2
+.Os
+.Sh NAME
+.Nm kenv
+.Nd kernel environment
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In kenv.h
+.Ft int
+.Fn kenv "int action" "const char *name" "char *value" "int len"
+.Sh DESCRIPTION
+The
+.Fn kenv
+system call manipulates kernel environment variables.
+It supports the well known userland actions of getting, setting and unsetting
+environment variables, as well as the ability to dump all of the entries in
+the kernel environment.
+.Pp
+The
+.Fa action
+argument can be one of the following:
+.Bl -tag -width ".Dv KENV_UNSET"
+.It Dv KENV_GET
+Returns the value associated with the named kernel environment variable.
+If the variable is not found, \-1 is returned and
+the global variable
+.Va errno
+is set to
+.Er ENOENT .
+Only the number of bytes available in
+.Fa value
+are copied out.
+.It Dv KENV_SET
+Sets or adds a new kernel environment variable.
+This option is only available to the superuser.
+.It Dv KENV_UNSET
+Unsets the kernel environment variable
+.Fa name .
+If the variable does not exist, \-1 is returned and
+the global variable
+.Va errno
+is set to
+.Er EINVAL .
+This option is only available to the superuser.
+.It Dv KENV_DUMP
+Dumps as much of the kernel environment as will fit in
+.Fa value .
+If
+.Fa value
+is
+.Dv NULL ,
+.Fn kenv
+will return the number of bytes required to copy out the entire environment.
+.El
+.Pp
+The
+.Fa name
+argument is the name of the environment variable to be affected.
+In the case of
+.Dv KENV_DUMP
+it is ignored.
+.Pp
+The
+.Fa value
+argument contains either the value to set the environment variable
+.Fa name
+to in the case of
+.Dv KENV_SET ,
+or it points to the location where
+.Fn kenv
+should copy return data to in the case of
+.Dv KENV_DUMP
+and
+.Dv KENV_GET .
+If
+.Fa value
+is
+.Dv NULL
+in the case of
+.Dv KENV_DUMP ,
+.Fn kenv
+will return the number of bytes required to copy out the entire environment.
+.Pp
+The
+.Fa len
+argument indicates how many bytes of storage
+.Fa value
+points to.
+.Sh RETURN VALUES
+The
+.Fn kenv
+system call returns 0 if successful in the case of
+.Dv KENV_SET
+and
+.Dv KENV_UNSET ,
+and the number of bytes copied into
+.Fa value
+in the case of
+.Dv KENV_DUMP
+and
+.Dv KENV_GET .
+If an error occurs, a value of \-1 is returned and
+the global variable
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+The
+.Fn kenv
+system call
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa action
+argument
+is not a valid option, or the length of the
+.Fa value
+is less than 1 for a
+.Dv KENV_SET .
+.It Bq Er ENOENT
+no value could be found for
+.Fa name
+for a
+.Dv KENV_SET
+or
+.Dv KENV_UNSET .
+.It Bq Er EPERM
+a user other than the superuser attempted to set or unset a kernel
+environment variable.
+.It Bq Er EFAULT
+bad address was encountered while attempting to copy in user arguments,
+or copy out value(s).
+.It Bq Er ENAMETOOLONG
+the name of a variable supplied by the user is longer than
+.Dv KENV_MNAMELEN
+or the value of a variable is longer than
+.Dv KENV_MVALLEN .
+.El
+.Sh SEE ALSO
+.Xr kenv 1
+.Sh AUTHORS
+.An -nosplit
+This manual page was written by
+.An Chad David Aq Mt davidc@FreeBSD.org .
+.Pp
+The
+.Fn kenv
+system call was written by
+.An Maxime Henrion Aq Mt mux@FreeBSD.org .
diff --git a/lib/libc/sys/kevent.c b/lib/libc/sys/kevent.c
new file mode 100644
index 000000000000..5f84ef8b10a6
--- /dev/null
+++ b/lib/libc/sys/kevent.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2015 The FreeBSD Foundation.
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Konstantin Belousov
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice(s), this list of conditions and the following disclaimer as
+ * the first lines of this file unmodified other than the possible
+ * addition of one or more copyright notices.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice(s), this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/event.h>
+#include <sys/time.h>
+#include "libc_private.h"
+
+__weak_reference(__sys_kevent, __kevent);
+
+#pragma weak kevent
+int
+kevent(int kq, const struct kevent *changelist, int nchanges,
+ struct kevent *eventlist, int nevents, const struct timespec *timeout)
+{
+
+ return (((int (*)(int, const struct kevent *, int,
+ struct kevent *, int, const struct timespec *))
+ __libc_interposing[INTERPOS_kevent])(kq, changelist, nchanges,
+ eventlist, nevents, timeout));
+}
diff --git a/lib/libc/sys/kill.2 b/lib/libc/sys/kill.2
new file mode 100644
index 000000000000..98c305086404
--- /dev/null
+++ b/lib/libc/sys/kill.2
@@ -0,0 +1,156 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)kill.2 8.3 (Berkeley) 4/19/94
+.\" $FreeBSD$
+.\"
+.Dd March 15, 2012
+.Dt KILL 2
+.Os
+.Sh NAME
+.Nm kill
+.Nd send signal to a process
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In signal.h
+.Ft int
+.Fn kill "pid_t pid" "int sig"
+.Sh DESCRIPTION
+The
+.Fn kill
+system call sends the signal given by
+.Fa sig
+to
+.Fa pid ,
+a
+process or a group of processes.
+The
+.Fa sig
+argument
+may be one of the signals specified in
+.Xr sigaction 2
+or it may be 0, in which case
+error checking is performed but no
+signal is actually sent.
+This can be used to check the validity of
+.Fa pid .
+.Pp
+For a process to have permission to send a signal to a process designated
+by
+.Fa pid ,
+the user must be the super-user, or
+the real or saved user ID of the receiving process must match
+the real or effective user ID of the sending process.
+A single exception is the signal SIGCONT, which may always be sent
+to any process with the same session ID as the sender.
+In addition, if the
+.Va security.bsd.conservative_signals
+.Xr sysctl
+is set to 1, the user is not a super-user, and
+the receiver is set-uid, then
+only job control and terminal control signals may
+be sent (in particular, only SIGKILL, SIGINT, SIGTERM, SIGALRM,
+SIGSTOP, SIGTTIN, SIGTTOU, SIGTSTP, SIGHUP, SIGUSR1, SIGUSR2).
+.Bl -tag -width Ds
+.It \&If Fa pid No \&is greater than zero :
+The
+.Fa sig
+signal
+is sent to the process whose ID is equal to
+.Fa pid .
+.It \&If Fa pid No \&is zero :
+The
+.Fa sig
+signal
+is sent to all processes whose group ID is equal
+to the process group ID of the sender, and for which the
+process has permission;
+this is a variant of
+.Xr killpg 2 .
+.It \&If Fa pid No \&is -1 :
+If the user has super-user privileges,
+the signal is sent to all processes excluding
+system processes
+(with
+.Dv P_SYSTEM
+flag set),
+process with ID 1
+(usually
+.Xr init 8 ) ,
+and the process sending the signal.
+If the user is not the super user, the signal is sent to all processes
+with the same uid as the user excluding the process sending the signal.
+No error is returned if any process could be signaled.
+.El
+.Pp
+For compatibility with System V,
+if the process number is negative but not -1,
+the signal is sent to all processes whose process group ID
+is equal to the absolute value of the process number.
+This is a variant of
+.Xr killpg 2 .
+.Sh RETURN VALUES
+.Rv -std kill
+.Sh ERRORS
+The
+.Fn kill
+system call
+will fail and no signal will be sent if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa sig
+argument
+is not a valid signal number.
+.It Bq Er ESRCH
+No process or process group can be found corresponding to that specified by
+.Fa pid .
+.It Bq Er EPERM
+The sending process does not have permission to send
+.Va sig
+to the receiving process.
+.El
+.Sh SEE ALSO
+.Xr getpgrp 2 ,
+.Xr getpid 2 ,
+.Xr killpg 2 ,
+.Xr sigaction 2 ,
+.Xr sigqueue 2 ,
+.Xr raise 3 ,
+.Xr init 8
+.Sh STANDARDS
+The
+.Fn kill
+system call is expected to conform to
+.St -p1003.1-90 .
+.Sh HISTORY
+The
+.Fn kill
+function appeared in
+.At v7 .
diff --git a/lib/libc/sys/kldfind.2 b/lib/libc/sys/kldfind.2
new file mode 100644
index 000000000000..a8892ed00650
--- /dev/null
+++ b/lib/libc/sys/kldfind.2
@@ -0,0 +1,86 @@
+.\"
+.\" Copyright (c) 1999 Chris Costello
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 March 3, 1999
+.Dt KLDFIND 2
+.Os
+.Sh NAME
+.Nm kldfind
+.Nd returns the fileid of a kld file
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/param.h
+.In sys/linker.h
+.Ft int
+.Fn kldfind "const char *file"
+.Sh DESCRIPTION
+The
+.Fn kldfind
+system call
+returns the fileid of the kld file referenced by
+.Fa file .
+.Sh RETURN VALUES
+The
+.Fn kldfind
+system call
+returns the fileid of the kld file referenced by
+.Fa file .
+Upon error,
+.Fn kldfind
+returns -1 and sets
+.Va errno
+to indicate the error.
+.Sh ERRORS
+.Va errno
+is set to the following if
+.Fn kldfind
+fails:
+.Bl -tag -width Er
+.It Bq Er EFAULT
+The data required for this operation could not be read from the kernel space.
+.It Bq Er ENOENT
+The file specified is not loaded in the kernel.
+.El
+.Sh SEE ALSO
+.Xr kldfirstmod 2 ,
+.Xr kldload 2 ,
+.Xr kldnext 2 ,
+.Xr kldstat 2 ,
+.Xr kldsym 2 ,
+.Xr kldunload 2 ,
+.Xr modfind 2 ,
+.Xr modfnext 2 ,
+.Xr modnext 2 ,
+.Xr modstat 2 ,
+.Xr kld 4 ,
+.Xr kldstat 8
+.Sh HISTORY
+The
+.Nm kld
+interface first appeared in
+.Fx 3.0 .
diff --git a/lib/libc/sys/kldfirstmod.2 b/lib/libc/sys/kldfirstmod.2
new file mode 100644
index 000000000000..d9967ccd779c
--- /dev/null
+++ b/lib/libc/sys/kldfirstmod.2
@@ -0,0 +1,76 @@
+.\"
+.\" Copyright (c) 1999 Chris Costello
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 March 3, 1999
+.Dt KLDFIRSTMOD 2
+.Os
+.Sh NAME
+.Nm kldfirstmod
+.Nd "return first module id from the kld file specified"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/param.h
+.In sys/linker.h
+.Ft int
+.Fn kldfirstmod "int fileid"
+.Sh DESCRIPTION
+The
+.Fn kldfirstmod
+system call returns the module id pertaining to the first module referenced by
+.Fa fileid .
+.Sh RETURN VALUES
+The
+.Fn kldfirstmod
+will return the id of the first module referenced by
+.Fa fileid
+or 0 if there are no references.
+.Sh ERRORS
+.Bl -tag -width Er
+.It Bq Er ENOENT
+The kld file referenced by
+.Fa fileid
+was not found.
+.El
+.Sh SEE ALSO
+.Xr kldfind 2 ,
+.Xr kldload 2 ,
+.Xr kldnext 2 ,
+.Xr kldstat 2 ,
+.Xr kldsym 2 ,
+.Xr kldunload 2 ,
+.Xr modfind 2 ,
+.Xr modfnext 2 ,
+.Xr modnext 2 ,
+.Xr modstat 2 ,
+.Xr kld 4 ,
+.Xr kldstat 8
+.Sh HISTORY
+The
+.Nm kld
+interface first appeared in
+.Fx 3.0 .
diff --git a/lib/libc/sys/kldload.2 b/lib/libc/sys/kldload.2
new file mode 100644
index 000000000000..d31cc086e2f9
--- /dev/null
+++ b/lib/libc/sys/kldload.2
@@ -0,0 +1,96 @@
+.\"
+.\" Copyright (c) 1999 Chris Costello
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 March 3, 1999
+.Dt KLDLOAD 2
+.Os
+.Sh NAME
+.Nm kldload
+.Nd load KLD files into the kernel
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/param.h
+.In sys/linker.h
+.Ft int
+.Fn kldload "const char *file"
+.Sh DESCRIPTION
+The
+.Fn kldload
+system call
+loads a kld file into the kernel using the kernel linker.
+.Sh RETURN VALUES
+The
+.Fn kldload
+system call
+returns the fileid of the kld file which was loaded into the kernel.
+If an error occurs,
+.Fn kldload
+will return -1 and set
+.Va errno
+to indicate the error.
+.Sh ERRORS
+The named file is loaded unless:
+.Bl -tag -width Er
+.It Bq Er EPERM
+You do not have access to read the file or link it with the kernel.
+You should be the root user to be able to use the
+.Nm kld
+system calls.
+.It Bq Er EFAULT
+Bad address encountered when adding kld info into the kernel space.
+.It Bq Er ENOMEM
+There is no memory to load the file into the kernel.
+.It Bq Er ENOENT
+The file was not found.
+.It Bq Er ENOEXEC
+The file format of
+.Fa file
+was unrecognized.
+.It Bq Er EEXIST
+The supplied
+.Fa file
+has already been loaded.
+.El
+.Sh SEE ALSO
+.Xr kldfind 2 ,
+.Xr kldfirstmod 2 ,
+.Xr kldnext 2 ,
+.Xr kldstat 2 ,
+.Xr kldsym 2 ,
+.Xr kldunload 2 ,
+.Xr modfind 2 ,
+.Xr modfnext 2 ,
+.Xr modnext 2 ,
+.Xr modstat 2 ,
+.Xr kld 4 ,
+.Xr kldload 8
+.Sh HISTORY
+The
+.Nm kld
+interface first appeared in
+.Fx 3.0 .
diff --git a/lib/libc/sys/kldnext.2 b/lib/libc/sys/kldnext.2
new file mode 100644
index 000000000000..c856a2e671f8
--- /dev/null
+++ b/lib/libc/sys/kldnext.2
@@ -0,0 +1,89 @@
+.\"
+.\" Copyright (c) 1999 Chris Costello
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 February 22, 2006
+.Dt KLDNEXT 2
+.Os
+.Sh NAME
+.Nm kldnext
+.Nd return the fileid of the next kld file
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/param.h
+.In sys/linker.h
+.Ft int
+.Fn kldnext "int fileid"
+.Sh DESCRIPTION
+The
+.Fn kldnext
+system call
+returns the fileid of the next kld file (that is, the one after
+.Fa fileid )
+or 0 if
+.Fa fileid
+is the last file loaded.
+To get the fileid of the first kld file, pass
+.Fa fileid
+of 0 to
+.Fn kldnext .
+.Sh RETURN VALUES
+The
+.Fn kldnext
+system call
+returns the fileid of the next kld file or 0 if successful.
+Otherwise
+.Fn kldnext
+returns the value \-1 and sets the global variable
+.Va errno
+to indicate the error.
+.Sh ERRORS
+The only error set by
+.Fn kldnext
+is
+.Er ENOENT ,
+which is set when
+.Fa fileid
+refers to a kld file that does not exist (is not loaded).
+.Sh SEE ALSO
+.Xr kldfind 2 ,
+.Xr kldfirstmod 2 ,
+.Xr kldload 2 ,
+.Xr kldstat 2 ,
+.Xr kldsym 2 ,
+.Xr kldunload 2 ,
+.Xr modfind 2 ,
+.Xr modfnext 2 ,
+.Xr modnext 2 ,
+.Xr modstat 2 ,
+.Xr kld 4 ,
+.Xr kldstat 8
+.Sh HISTORY
+The
+.Nm kld
+interface first appeared in
+.Fx 3.0 .
diff --git a/lib/libc/sys/kldstat.2 b/lib/libc/sys/kldstat.2
new file mode 100644
index 000000000000..8b4e5320dd75
--- /dev/null
+++ b/lib/libc/sys/kldstat.2
@@ -0,0 +1,133 @@
+.\"
+.\" Copyright (c) 1999 Chris Costello
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 March 28, 2012
+.Dt KLDSTAT 2
+.Os
+.Sh NAME
+.Nm kldstat
+.Nd get status of kld file
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/param.h
+.In sys/linker.h
+.Ft int
+.Fn kldstat "int fileid" "struct kld_file_stat *stat"
+.Sh DESCRIPTION
+The
+.Fn kldstat
+system call writes the info for the file referred to by
+.Fa fileid
+into
+.Fa stat .
+.Bd -literal
+struct kld_file_stat {
+ int version; /* set to sizeof(struct kld_file_stat) */
+ char name[MAXPATHLEN];
+ int refs;
+ int id;
+ caddr_t address;
+ size_t size;
+ char pathname[MAXPATHLEN];
+};
+.Ed
+.Bl -tag -width XXXaddress
+.It version
+This field is set to the size of the structure mentioned above by the code
+calling
+.Fn kldstat ,
+and not
+.Fn kldstat
+itself.
+.It name
+The name of the file referred to by
+.Fa fileid .
+.It refs
+The number of modules referenced by
+.Fa fileid .
+.It id
+The id of the file specified in
+.Fa fileid .
+.It address
+The load address of the kld file.
+.It size
+The amount of memory in bytes allocated by the file.
+.It pathname
+The full name of the file referred to by
+.Fa fileid ,
+including the path.
+.El
+.Sh RETURN VALUES
+.Rv -std kldstat
+.Sh ERRORS
+The information for the file referred to by
+.Fa fileid
+is filled into the structure pointed to by
+.Fa stat
+unless:
+.Bl -tag -width Er
+.It Bq Er ENOENT
+The file was not found (probably not loaded).
+.It Bq Er EINVAL
+The version specified in the
+.Fa version
+field of stat is not the proper version.
+You would need to rebuild world, the
+kernel, or your application, if this error occurs, given that you did properly
+fill in the
+.Fa version
+field.
+.It Bq Er EFAULT
+There was a problem copying one, some, or all of the fields into
+.Fa stat
+in the
+.Xr copyout 9
+function.
+.El
+.Sh SEE ALSO
+.Xr kldfind 2 ,
+.Xr kldfirstmod 2 ,
+.Xr kldload 2 ,
+.Xr kldnext 2 ,
+.Xr kldsym 2 ,
+.Xr kldunload 2 ,
+.Xr modfind 2 ,
+.Xr modfnext 2 ,
+.Xr modnext 2 ,
+.Xr modstat 2 ,
+.Xr kld 4 ,
+.Xr kldstat 8
+.Sh HISTORY
+The
+.Nm kld
+interface first appeared in
+.Fx 3.0 .
+.Sh BUGS
+The pathname may not be accurate if the file system mounts have
+changed since the module was loaded, or if this function is called
+within a chrooted environment.
diff --git a/lib/libc/sys/kldsym.2 b/lib/libc/sys/kldsym.2
new file mode 100644
index 000000000000..422feaa268fd
--- /dev/null
+++ b/lib/libc/sys/kldsym.2
@@ -0,0 +1,121 @@
+.\" Copyright (c) 2001 Chris Costello <chris@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 October 17, 2016
+.Dt KLDSYM 2
+.Os
+.Sh NAME
+.Nm kldsym
+.Nd look up address by symbol name in a KLD
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/param.h
+.In sys/linker.h
+.Ft int
+.Fn kldsym "int fileid" "int cmd" "void *data"
+.Sh DESCRIPTION
+The
+.Fn kldsym
+system call returns the address of the symbol specified in
+.Fa data
+in the module specified by
+.Fa fileid .
+If
+.Fa fileid
+is 0, all loaded modules are searched.
+Currently, the only
+.Fa cmd
+implemented is
+.Dv KLDSYM_LOOKUP .
+.Pp
+The
+.Fa data
+argument is of the following structure:
+.Bd -literal -offset indent
+struct kld_sym_lookup {
+ int version; /* sizeof(struct kld_sym_lookup) */
+ char *symname; /* Symbol name we are looking up */
+ u_long symvalue;
+ size_t symsize;
+};
+.Ed
+.Pp
+The
+.Va version
+member is to be set
+by the code calling
+.Fn kldsym
+to
+.Fn sizeof "struct kld_sym_lookup" .
+The next two members,
+.Va version
+and
+.Va symname ,
+are specified by the user.
+The last two,
+.Va symvalue
+and
+.Va symsize ,
+are filled in by
+.Fn kldsym
+and contain the address associated with
+.Va symname
+and the size of the data it points to, respectively.
+.Sh RETURN VALUES
+.Rv -std kldsym
+.Sh ERRORS
+The
+.Fn kldsym
+system call will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Invalid value in
+.Fa data->version
+or
+.Fa cmd .
+.It Bq Er ENOENT
+The
+.Fa fileid
+argument
+is invalid,
+or the specified symbol could not be found.
+.El
+.Sh SEE ALSO
+.Xr kldfind 2 ,
+.Xr kldfirstmod 2 ,
+.Xr kldload 2 ,
+.Xr kldnext 2 ,
+.Xr kldunload 2 ,
+.Xr modfind 2 ,
+.Xr modnext 2 ,
+.Xr modstat 2 ,
+.Xr kld 4
+.Sh HISTORY
+The
+.Fn kldsym
+system call first appeared in
+.Fx 3.0 .
diff --git a/lib/libc/sys/kldunload.2 b/lib/libc/sys/kldunload.2
new file mode 100644
index 000000000000..d1c259b51461
--- /dev/null
+++ b/lib/libc/sys/kldunload.2
@@ -0,0 +1,94 @@
+.\"
+.\" Copyright (c) 1999 Chris Costello
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd December 25, 2008
+.Dt KLDUNLOAD 2
+.Os
+.Sh NAME
+.Nm kldunload , kldunloadf
+.Nd unload kld files
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/param.h
+.In sys/linker.h
+.Ft int
+.Fn kldunload "int fileid"
+.Ft int
+.Fn kldunloadf "int fileid" "int flags"
+.Sh DESCRIPTION
+The
+.Fn kldunload
+system call
+unloads a kld file from the kernel that was previously linked via
+.Xr kldload 2 .
+.Pp
+The
+.Fn kldunloadf
+system call accepts an additional flags argument, which may be one of
+.Dv LINKER_UNLOAD_NORMAL ,
+giving the same behavior as
+.Fn kldunload ,
+or
+.Dv LINKER_UNLOAD_FORCE ,
+which causes the unload to ignore a failure to quiesce the module.
+.Sh RETURN VALUES
+.Rv -std
+.Sh ERRORS
+The file referred to by
+.Fa fileid
+is unloaded unless:
+.Bl -tag -width Er
+.It Bq Er EPERM
+You do not have access to unlink the file from the kernel.
+.It Bq Er ENOENT
+The file was not found.
+.It Bq Er EBUSY
+You attempted to unload a file linked by the kernel.
+.It Bq Er EINVAL
+The
+.Fn kldunloadf
+system call was passed invalid flags.
+.El
+.Sh SEE ALSO
+.Xr kldfind 2 ,
+.Xr kldfirstmod 2 ,
+.Xr kldload 2 ,
+.Xr kldnext 2 ,
+.Xr kldstat 2 ,
+.Xr kldsym 2 ,
+.Xr modfind 2 ,
+.Xr modfnext 2 ,
+.Xr modnext 2 ,
+.Xr modstat 2 ,
+.Xr kld 4 ,
+.Xr kldunload 8
+.Sh HISTORY
+The
+.Nm kld
+interface first appeared in
+.Fx 3.0 .
diff --git a/lib/libc/sys/kqueue.2 b/lib/libc/sys/kqueue.2
new file mode 100644
index 000000000000..adaee1ec37e6
--- /dev/null
+++ b/lib/libc/sys/kqueue.2
@@ -0,0 +1,771 @@
+.\" Copyright (c) 2000 Jonathan Lemon
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 May 3, 2016
+.Dt KQUEUE 2
+.Os
+.Sh NAME
+.Nm kqueue ,
+.Nm kevent
+.Nd kernel event notification mechanism
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/event.h
+.In sys/time.h
+.Ft int
+.Fn kqueue "void"
+.Ft int
+.Fn kevent "int kq" "const struct kevent *changelist" "int nchanges" "struct kevent *eventlist" "int nevents" "const struct timespec *timeout"
+.Fn EV_SET "kev" ident filter flags fflags data udata
+.Sh DESCRIPTION
+The
+.Fn kqueue
+system call
+provides a generic method of notifying the user when an event
+happens or a condition holds, based on the results of small
+pieces of kernel code termed filters.
+A kevent is identified by the (ident, filter) pair; there may only
+be one unique kevent per kqueue.
+.Pp
+The filter is executed upon the initial registration of a kevent
+in order to detect whether a preexisting condition is present, and is also
+executed whenever an event is passed to the filter for evaluation.
+If the filter determines that the condition should be reported,
+then the kevent is placed on the kqueue for the user to retrieve.
+.Pp
+The filter is also run when the user attempts to retrieve the kevent
+from the kqueue.
+If the filter indicates that the condition that triggered
+the event no longer holds, the kevent is removed from the kqueue and
+is not returned.
+.Pp
+Multiple events which trigger the filter do not result in multiple
+kevents being placed on the kqueue; instead, the filter will aggregate
+the events into a single struct kevent.
+Calling
+.Fn close
+on a file descriptor will remove any kevents that reference the descriptor.
+.Pp
+The
+.Fn kqueue
+system call
+creates a new kernel event queue and returns a descriptor.
+The queue is not inherited by a child created with
+.Xr fork 2 .
+However, if
+.Xr rfork 2
+is called without the
+.Dv RFFDG
+flag, then the descriptor table is shared,
+which will allow sharing of the kqueue between two processes.
+.Pp
+The
+.Fn kevent
+system call
+is used to register events with the queue, and return any pending
+events to the user.
+The
+.Fa changelist
+argument
+is a pointer to an array of
+.Va kevent
+structures, as defined in
+.In sys/event.h .
+All changes contained in the
+.Fa changelist
+are applied before any pending events are read from the queue.
+The
+.Fa nchanges
+argument
+gives the size of
+.Fa changelist .
+The
+.Fa eventlist
+argument
+is a pointer to an array of kevent structures.
+The
+.Fa nevents
+argument
+determines the size of
+.Fa eventlist .
+When
+.Fa nevents
+is zero,
+.Fn kevent
+will return immediately even if there is a
+.Fa timeout
+specified unlike
+.Xr select 2 .
+If
+.Fa timeout
+is a non-NULL pointer, it specifies a maximum interval to wait
+for an event, which will be interpreted as a struct timespec.
+If
+.Fa timeout
+is a NULL pointer,
+.Fn kevent
+waits indefinitely.
+To effect a poll, the
+.Fa timeout
+argument should be non-NULL, pointing to a zero-valued
+.Va timespec
+structure.
+The same array may be used for the
+.Fa changelist
+and
+.Fa eventlist .
+.Pp
+The
+.Fn EV_SET
+macro is provided for ease of initializing a
+kevent structure.
+.Pp
+The
+.Va kevent
+structure is defined as:
+.Bd -literal
+struct kevent {
+ uintptr_t ident; /* identifier for this event */
+ short filter; /* filter for event */
+ u_short flags; /* action flags for kqueue */
+ u_int fflags; /* filter flag value */
+ intptr_t data; /* filter data value */
+ void *udata; /* opaque user data identifier */
+};
+.Ed
+.Pp
+The fields of
+.Fa struct kevent
+are:
+.Bl -tag -width "Fa filter"
+.It Fa ident
+Value used to identify this event.
+The exact interpretation is determined by the attached filter,
+but often is a file descriptor.
+.It Fa filter
+Identifies the kernel filter used to process this event.
+The pre-defined
+system filters are described below.
+.It Fa flags
+Actions to perform on the event.
+.It Fa fflags
+Filter-specific flags.
+.It Fa data
+Filter-specific data value.
+.It Fa udata
+Opaque user-defined value passed through the kernel unchanged.
+.El
+.Pp
+The
+.Va flags
+field can contain the following values:
+.Bl -tag -width EV_DISPATCH
+.It Dv EV_ADD
+Adds the event to the kqueue.
+Re-adding an existing event
+will modify the parameters of the original event, and not result
+in a duplicate entry.
+Adding an event automatically enables it,
+unless overridden by the EV_DISABLE flag.
+.It Dv EV_ENABLE
+Permit
+.Fn kevent
+to return the event if it is triggered.
+.It Dv EV_DISABLE
+Disable the event so
+.Fn kevent
+will not return it.
+The filter itself is not disabled.
+.It Dv EV_DISPATCH
+Disable the event source immediately after delivery of an event.
+See
+.Dv EV_DISABLE
+above.
+.It Dv EV_DELETE
+Removes the event from the kqueue.
+Events which are attached to
+file descriptors are automatically deleted on the last close of
+the descriptor.
+.It Dv EV_RECEIPT
+This flag is useful for making bulk changes to a kqueue without draining
+any pending events.
+When passed as input, it forces
+.Dv EV_ERROR
+to always be returned.
+When a filter is successfully added the
+.Va data
+field will be zero.
+.It Dv EV_ONESHOT
+Causes the event to return only the first occurrence of the filter
+being triggered.
+After the user retrieves the event from the kqueue,
+it is deleted.
+.It Dv EV_CLEAR
+After the event is retrieved by the user, its state is reset.
+This is useful for filters which report state transitions
+instead of the current state.
+Note that some filters may automatically
+set this flag internally.
+.It Dv EV_EOF
+Filters may set this flag to indicate filter-specific EOF condition.
+.It Dv EV_ERROR
+See
+.Sx RETURN VALUES
+below.
+.El
+.Pp
+The predefined system filters are listed below.
+Arguments may be passed to and from the filter via the
+.Va fflags
+and
+.Va data
+fields in the kevent structure.
+.Bl -tag -width "Dv EVFILT_PROCDESC"
+.It Dv EVFILT_READ
+Takes a descriptor as the identifier, and returns whenever
+there is data available to read.
+The behavior of the filter is slightly different depending
+on the descriptor type.
+.Bl -tag -width 2n
+.It Sockets
+Sockets which have previously been passed to
+.Fn listen
+return when there is an incoming connection pending.
+.Va data
+contains the size of the listen backlog.
+.Pp
+Other socket descriptors return when there is data to be read,
+subject to the
+.Dv SO_RCVLOWAT
+value of the socket buffer.
+This may be overridden with a per-filter low water mark at the
+time the filter is added by setting the
+.Dv NOTE_LOWAT
+flag in
+.Va fflags ,
+and specifying the new low water mark in
+.Va data .
+On return,
+.Va data
+contains the number of bytes of protocol data available to read.
+.Pp
+If the read direction of the socket has shutdown, then the filter
+also sets
+.Dv EV_EOF
+in
+.Va flags ,
+and returns the socket error (if any) in
+.Va fflags .
+It is possible for EOF to be returned (indicating the connection is gone)
+while there is still data pending in the socket buffer.
+.It Vnodes
+Returns when the file pointer is not at the end of file.
+.Va data
+contains the offset from current position to end of file,
+and may be negative.
+.Pp
+This behavior is different from
+.Xr poll 2 ,
+where read events are triggered for regular files unconditionally.
+This event can be triggered unconditionally by setting the
+.Dv NOTE_FILE_POLL
+flag in
+.Va fflags .
+.It "Fifos, Pipes"
+Returns when the there is data to read;
+.Va data
+contains the number of bytes available.
+.Pp
+When the last writer disconnects, the filter will set
+.Dv EV_EOF
+in
+.Va flags .
+This may be cleared by passing in
+.Dv EV_CLEAR ,
+at which point the
+filter will resume waiting for data to become available before
+returning.
+.It "BPF devices"
+Returns when the BPF buffer is full, the BPF timeout has expired, or
+when the BPF has
+.Dq immediate mode
+enabled and there is any data to read;
+.Va data
+contains the number of bytes available.
+.El
+.It Dv EVFILT_WRITE
+Takes a descriptor as the identifier, and returns whenever
+it is possible to write to the descriptor.
+For sockets, pipes
+and fifos,
+.Va data
+will contain the amount of space remaining in the write buffer.
+The filter will set EV_EOF when the reader disconnects, and for
+the fifo case, this may be cleared by use of
+.Dv EV_CLEAR .
+Note that this filter is not supported for vnodes or BPF devices.
+.Pp
+For sockets, the low water mark and socket error handling is
+identical to the
+.Dv EVFILT_READ
+case.
+.It Dv EVFILT_AIO
+The sigevent portion of the AIO request is filled in, with
+.Va sigev_notify_kqueue
+containing the descriptor of the kqueue that the event should
+be attached to,
+.Va sigev_notify_kevent_flags
+containing the kevent flags which should be
+.Dv EV_ONESHOT ,
+.Dv EV_CLEAR
+or
+.Dv EV_DISPATCH ,
+.Va sigev_value
+containing the udata value, and
+.Va sigev_notify
+set to
+.Dv SIGEV_KEVENT .
+When the
+.Fn aio_*
+system call is made, the event will be registered
+with the specified kqueue, and the
+.Va ident
+argument set to the
+.Fa struct aiocb
+returned by the
+.Fn aio_*
+system call.
+The filter returns under the same conditions as
+.Fn aio_error .
+.It Dv EVFILT_VNODE
+Takes a file descriptor as the identifier and the events to watch for in
+.Va fflags ,
+and returns when one or more of the requested events occurs on the descriptor.
+The events to monitor are:
+.Bl -tag -width "Dv NOTE_CLOSE_WRITE"
+.It Dv NOTE_ATTRIB
+The file referenced by the descriptor had its attributes changed.
+.It Dv NOTE_CLOSE
+A file descriptor referencing the monitored file, was closed.
+The closed file descriptor did not have write access.
+.It Dv NOTE_CLOSE_WRITE
+A file descriptor referencing the monitored file, was closed.
+The closed file descriptor had write access.
+.Pp
+This note, as well as
+.Dv NOTE_CLOSE ,
+are not activated when files are closed forcibly by
+.Xr unmount 2 or
+.Xr revoke 2 .
+Instead,
+.Dv NOTE_REVOKE
+is sent for such events.
+.It Dv NOTE_DELETE
+The
+.Fn unlink
+system call was called on the file referenced by the descriptor.
+.It Dv NOTE_EXTEND
+For regular file, the file referenced by the descriptor was extended.
+.Pp
+For directory, reports that a directory entry was added or removed,
+as the result of rename operation.
+The
+.Dv NOTE_EXTEND
+event is not reported when a name is changed inside the directory.
+.It Dv NOTE_LINK
+The link count on the file changed.
+In particular, the
+.Dv NOTE_LINK
+event is reported if a subdirectory was created or deleted inside
+the directory referenced by the descriptor.
+.It Dv NOTE_OPEN
+The file referenced by the descriptor was opened.
+.It Dv NOTE_READ
+A read occurred on the file referenced by the descriptor.
+.It Dv NOTE_RENAME
+The file referenced by the descriptor was renamed.
+.It Dv NOTE_REVOKE
+Access to the file was revoked via
+.Xr revoke 2
+or the underlying file system was unmounted.
+.It Dv NOTE_WRITE
+A write occurred on the file referenced by the descriptor.
+.El
+.Pp
+On return,
+.Va fflags
+contains the events which triggered the filter.
+.It Dv EVFILT_PROC
+Takes the process ID to monitor as the identifier and the events to watch for
+in
+.Va fflags ,
+and returns when the process performs one or more of the requested events.
+If a process can normally see another process, it can attach an event to it.
+The events to monitor are:
+.Bl -tag -width "Dv NOTE_TRACKERR"
+.It Dv NOTE_EXIT
+The process has exited.
+The exit status will be stored in
+.Va data .
+.It Dv NOTE_FORK
+The process has called
+.Fn fork .
+.It Dv NOTE_EXEC
+The process has executed a new process via
+.Xr execve 2
+or a similar call.
+.It Dv NOTE_TRACK
+Follow a process across
+.Fn fork
+calls.
+The parent process registers a new kevent to monitor the child process
+using the same
+.Va fflags
+as the original event.
+The child process will signal an event with
+.Dv NOTE_CHILD
+set in
+.Va fflags
+and the parent PID in
+.Va data .
+.Pp
+If the parent process fails to register a new kevent
+.Pq usually due to resource limitations ,
+it will signal an event with
+.Dv NOTE_TRACKERR
+set in
+.Va fflags ,
+and the child process will not signal a
+.Dv NOTE_CHILD
+event.
+.El
+.Pp
+On return,
+.Va fflags
+contains the events which triggered the filter.
+.It Dv EVFILT_PROCDESC
+Takes the process descriptor created by
+.Xr pdfork 2
+to monitor as the identifier and the events to watch for in
+.Va fflags ,
+and returns when the associated process performs one or more of the
+requested events.
+The events to monitor are:
+.Bl -tag -width "Dv NOTE_EXIT"
+.It Dv NOTE_EXIT
+The process has exited.
+The exit status will be stored in
+.Va data .
+.El
+.Pp
+On return,
+.Va fflags
+contains the events which triggered the filter.
+.It Dv EVFILT_SIGNAL
+Takes the signal number to monitor as the identifier and returns
+when the given signal is delivered to the process.
+This coexists with the
+.Fn signal
+and
+.Fn sigaction
+facilities, and has a lower precedence.
+The filter will record
+all attempts to deliver a signal to a process, even if the signal has
+been marked as
+.Dv SIG_IGN ,
+except for the
+.Dv SIGCHLD
+signal, which, if ignored, won't be recorded by the filter.
+Event notification happens after normal
+signal delivery processing.
+.Va data
+returns the number of times the signal has occurred since the last call to
+.Fn kevent .
+This filter automatically sets the
+.Dv EV_CLEAR
+flag internally.
+.It Dv EVFILT_TIMER
+Establishes an arbitrary timer identified by
+.Va ident .
+When adding a timer,
+.Va data
+specifies the timeout period.
+The timer will be periodic unless
+.Dv EV_ONESHOT
+is specified.
+On return,
+.Va data
+contains the number of times the timeout has expired since the last call to
+.Fn kevent .
+This filter automatically sets the EV_CLEAR flag internally.
+There is a system wide limit on the number of timers
+which is controlled by the
+.Va kern.kq_calloutmax
+sysctl.
+.Bl -tag -width "Dv NOTE_USECONDS"
+.It Dv NOTE_SECONDS
+.Va data
+is in seconds.
+.It Dv NOTE_MSECONDS
+.Va data
+is in milliseconds.
+.It Dv NOTE_USECONDS
+.Va data
+is in microseconds.
+.It Dv NOTE_NSECONDS
+.Va data
+is in nanoseconds.
+.El
+.Pp
+If
+.Va fflags
+is not set, the default is milliseconds. On return,
+.Va fflags
+contains the events which triggered the filter.
+.It Dv EVFILT_USER
+Establishes a user event identified by
+.Va ident
+which is not associated with any kernel mechanism but is triggered by
+user level code.
+The lower 24 bits of the
+.Va fflags
+may be used for user defined flags and manipulated using the following:
+.Bl -tag -width "Dv NOTE_FFLAGSMASK"
+.It Dv NOTE_FFNOP
+Ignore the input
+.Va fflags .
+.It Dv NOTE_FFAND
+Bitwise AND
+.Va fflags .
+.It Dv NOTE_FFOR
+Bitwise OR
+.Va fflags .
+.It Dv NOTE_FFCOPY
+Copy
+.Va fflags .
+.It Dv NOTE_FFCTRLMASK
+Control mask for
+.Va fflags .
+.It Dv NOTE_FFLAGSMASK
+User defined flag mask for
+.Va fflags .
+.El
+.Pp
+A user event is triggered for output with the following:
+.Bl -tag -width "Dv NOTE_FFLAGSMASK"
+.It Dv NOTE_TRIGGER
+Cause the event to be triggered.
+.El
+.Pp
+On return,
+.Va fflags
+contains the users defined flags in the lower 24 bits.
+.El
+.Sh CANCELLATION BEHAVIOUR
+If
+.Fa nevents
+is non-zero, i.e. the function is potentially blocking, the call
+is a cancellation point.
+Otherwise, i.e. if
+.Fa nevents
+is zero, the call is not cancellable.
+Cancellation can only occur before any changes are made to the kqueue,
+or when the call was blocked and no changes to the queue were requested.
+.Sh RETURN VALUES
+The
+.Fn kqueue
+system call
+creates a new kernel event queue and returns a file descriptor.
+If there was an error creating the kernel event queue, a value of -1 is
+returned and errno set.
+.Pp
+The
+.Fn kevent
+system call
+returns the number of events placed in the
+.Fa eventlist ,
+up to the value given by
+.Fa nevents .
+If an error occurs while processing an element of the
+.Fa changelist
+and there is enough room in the
+.Fa eventlist ,
+then the event will be placed in the
+.Fa eventlist
+with
+.Dv EV_ERROR
+set in
+.Va flags
+and the system error in
+.Va data .
+Otherwise,
+.Dv -1
+will be returned, and
+.Dv errno
+will be set to indicate the error condition.
+If the time limit expires, then
+.Fn kevent
+returns 0.
+.Sh EXAMPLES
+.Bd -literal -compact
+#include <sys/types.h>
+#include <sys/event.h>
+#include <sys/time.h>
+#include <err.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+int
+main(int argc, char **argv)
+{
+ struct kevent event; /* Event we want to monitor */
+ struct kevent tevent; /* Event triggered */
+ int kq, fd, ret;
+
+ if (argc != 2)
+ err(EXIT_FAILURE, "Usage: %s path\en", argv[0]);
+ fd = open(argv[1], O_RDONLY);
+ if (fd == -1)
+ err(EXIT_FAILURE, "Failed to open '%s'", argv[1]);
+
+ /* Create kqueue. */
+ kq = kqueue();
+ if (kq == -1)
+ err(EXIT_FAILURE, "kqueue() failed");
+
+ /* Initialize kevent structure. */
+ EV_SET(&event, fd, EVFILT_VNODE, EV_ADD | EV_CLEAR, NOTE_WRITE,
+ 0, NULL);
+ /* Attach event to the kqueue. */
+ ret = kevent(kq, &event, 1, NULL, 0, NULL);
+ if (ret == -1)
+ err(EXIT_FAILURE, "kevent register");
+ if (event.flags & EV_ERROR)
+ errx(EXIT_FAILURE, "Event error: %s", strerror(event.data));
+
+ for (;;) {
+ /* Sleep until something happens. */
+ ret = kevent(kq, NULL, 0, &tevent, 1, NULL);
+ if (ret == -1) {
+ err(EXIT_FAILURE, "kevent wait");
+ } else if (ret > 0) {
+ printf("Something was written in '%s'\en", argv[1]);
+ }
+ }
+}
+.Ed
+.Sh ERRORS
+The
+.Fn kqueue
+system call fails if:
+.Bl -tag -width Er
+.It Bq Er ENOMEM
+The kernel failed to allocate enough memory for the kernel queue.
+.It Bq Er ENOMEM
+The
+.Dv RLIMIT_KQUEUES
+rlimit
+(see
+.Xr getrlimit 2 )
+for the current user would be exceeded.
+.It Bq Er EMFILE
+The per-process descriptor table is full.
+.It Bq Er ENFILE
+The system file table is full.
+.El
+.Pp
+The
+.Fn kevent
+system call fails if:
+.Bl -tag -width Er
+.It Bq Er EACCES
+The process does not have permission to register a filter.
+.It Bq Er EFAULT
+There was an error reading or writing the
+.Va kevent
+structure.
+.It Bq Er EBADF
+The specified descriptor is invalid.
+.It Bq Er EINTR
+A signal was delivered before the timeout expired and before any
+events were placed on the kqueue for return.
+.It Bq Er EINTR
+A cancellation request was delivered to the thread, but not yet handled.
+.It Bq Er EINVAL
+The specified time limit or filter is invalid.
+.It Bq Er ENOENT
+The event could not be found to be modified or deleted.
+.It Bq Er ENOMEM
+No memory was available to register the event
+or, in the special case of a timer, the maximum number of
+timers has been exceeded.
+This maximum is configurable via the
+.Va kern.kq_calloutmax
+sysctl.
+.It Bq Er ESRCH
+The specified process to attach to does not exist.
+.El
+.Pp
+When
+.Fn kevent
+call fails with
+.Er EINTR
+error, all changes in the
+.Fa changelist
+have been applied.
+.Sh SEE ALSO
+.Xr aio_error 2 ,
+.Xr aio_read 2 ,
+.Xr aio_return 2 ,
+.Xr poll 2 ,
+.Xr read 2 ,
+.Xr select 2 ,
+.Xr sigaction 2 ,
+.Xr write 2 ,
+.Xr pthread_setcancelstate 3 ,
+.Xr signal 3
+.Sh HISTORY
+The
+.Fn kqueue
+and
+.Fn kevent
+system calls first appeared in
+.Fx 4.1 .
+.Sh AUTHORS
+The
+.Fn kqueue
+system and this manual page were written by
+.An Jonathan Lemon Aq Mt jlemon@FreeBSD.org .
+.Sh BUGS
+The
+.Fa timeout
+value is limited to 24 hours; longer timeouts will be silently
+reinterpreted as 24 hours.
diff --git a/lib/libc/sys/ktrace.2 b/lib/libc/sys/ktrace.2
new file mode 100644
index 000000000000..b02a6724bc3a
--- /dev/null
+++ b/lib/libc/sys/ktrace.2
@@ -0,0 +1,204 @@
+.\" Copyright (c) 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)ktrace.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd March 31, 2016
+.Dt KTRACE 2
+.Os
+.Sh NAME
+.Nm ktrace
+.Nd process tracing
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/param.h
+.In sys/time.h
+.In sys/uio.h
+.In sys/ktrace.h
+.Ft int
+.Fn ktrace "const char *tracefile" "int ops" "int trpoints" "int pid"
+.Sh DESCRIPTION
+The
+.Fn ktrace
+system call enables or disables tracing of one or more processes.
+Users may only trace their own processes.
+Only the super-user can trace setuid or setgid programs.
+.Pp
+The
+.Fa tracefile
+argument
+gives the pathname of the file to be used for tracing.
+The file must exist and be a regular file writable by the calling process.
+All trace records are always appended to the file,
+so the file must be truncated to zero length to discard
+previous trace data.
+If tracing points are being disabled (see KTROP_CLEAR below),
+.Fa tracefile
+may be NULL.
+.Pp
+The
+.Fa ops
+argument specifies the requested ktrace operation.
+The defined operations are:
+.Bl -column KTRFLAG_DESCENDXXX -offset indent
+.It KTROP_SET Ta "Enable trace points specified in"
+.Fa trpoints .
+.It KTROP_CLEAR Ta "Disable trace points specified in"
+.Fa trpoints .
+.It KTROP_CLEARFILE Ta "Stop all tracing."
+.It KTRFLAG_DESCEND Ta "The tracing change should apply to the"
+specified process and all its current children.
+.El
+.Pp
+The
+.Fa trpoints
+argument specifies the trace points of interest.
+The defined trace points are:
+.Bl -column KTRFAC_PROCCTORXXX -offset indent
+.It KTRFAC_SYSCALL Ta "Trace system calls."
+.It KTRFAC_SYSRET Ta "Trace return values from system calls."
+.It KTRFAC_NAMEI Ta "Trace name lookup operations."
+.It KTRFAC_GENIO Ta "Trace all I/O (note that this option can"
+generate much output).
+.It KTRFAC_PSIG Ta "Trace posted signals."
+.It KTRFAC_CSW Ta "Trace context switch points."
+.It KTRFAC_USER Ta "Trace application-specific events."
+.It KTRFAC_STRUCT Ta "Trace certain data structures."
+.It KTRFAC_SYSCTL Ta "Trace sysctls."
+.It KTRFAC_PROCCTOR Ta "Trace process construction."
+.It KTRFAC_PROCDTOR Ta "Trace process destruction."
+.It KTRFAC_CAPFAIL Ta "Trace capability failures."
+.It KTRFAC_FAULT Ta "Trace page faults."
+.It KTRFAC_FAULTEND Ta "Trace the end of page faults."
+.It KTRFAC_INHERIT Ta "Inherit tracing to future children."
+.El
+.Pp
+Each tracing event outputs a record composed of a generic header
+followed by a trace point specific structure.
+The generic header is:
+.Bd -literal
+struct ktr_header {
+ int ktr_len; /* length of buf */
+ short ktr_type; /* trace record type */
+ pid_t ktr_pid; /* process id */
+ char ktr_comm[MAXCOMLEN+1]; /* command name */
+ struct timeval ktr_time; /* timestamp */
+ intptr_t ktr_tid; /* was ktr_buffer */
+};
+.Ed
+.Pp
+The
+.Va ktr_len
+field specifies the length of the
+.Va ktr_type
+data that follows this header.
+The
+.Va ktr_pid
+and
+.Va ktr_comm
+fields specify the process and command generating the record.
+The
+.Va ktr_time
+field gives the time (with microsecond resolution)
+that the record was generated.
+The
+.Va ktr_tid
+field holds a thread id.
+.Pp
+The generic header is followed by
+.Va ktr_len
+bytes of a
+.Va ktr_type
+record.
+The type specific records are defined in the
+.In sys/ktrace.h
+include file.
+.Sh SYSCTL TUNABLES
+The following
+.Xr sysctl 8
+tunables influence the behaviour of
+.Fn ktrace :
+.Bl -tag -width indent
+.It Va kern.ktrace.geniosize
+bounds the amount of data a traced I/O request will log
+to the trace file.
+.It Va kern.ktrace.request_pool
+bounds the number of trace events being logged at a time.
+.El
+.Pp
+Sysctl tunables that control process debuggability (as determined by
+.Xr p_candebug 9 )
+also affect the operation of
+.Fn ktrace .
+.Sh RETURN VALUES
+.Rv -std ktrace
+.Sh ERRORS
+The
+.Fn ktrace
+system call
+will fail if:
+.Bl -tag -width Er
+.It Bq Er ENOTDIR
+A component of the path prefix is not a directory.
+.It Bq Er ENAMETOOLONG
+A component of a pathname exceeded 255 characters,
+or an entire path name exceeded 1023 characters.
+.It Bq Er ENOENT
+The named tracefile does not exist.
+.It Bq Er EACCES
+Search permission is denied for a component of the path prefix.
+.It Bq Er ELOOP
+Too many symbolic links were encountered in translating the pathname.
+.It Bq Er EIO
+An I/O error occurred while reading from or writing to the file system.
+.It Bq Er ENOSYS
+The kernel was not compiled with
+.Nm
+support.
+.El
+.Pp
+A thread may be unable to log one or more tracing events due to a
+temporary shortage of resources.
+This condition is remembered by the kernel, and the next tracing request
+that succeeds will have the flag
+.Li KTR_DROP
+set in its
+.Va ktr_type
+field.
+.Sh SEE ALSO
+.Xr kdump 1 ,
+.Xr ktrace 1 ,
+.Xr utrace 2 ,
+.Xr sysctl 8 ,
+.Xr p_candebug 9
+.Sh HISTORY
+The
+.Fn ktrace
+system call first appeared in
+.Bx 4.4 .
diff --git a/lib/libc/sys/link.2 b/lib/libc/sys/link.2
new file mode 100644
index 000000000000..e1fc3178fb59
--- /dev/null
+++ b/lib/libc/sys/link.2
@@ -0,0 +1,288 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)link.2 8.3 (Berkeley) 1/12/94
+.\" $FreeBSD$
+.\"
+.Dd April 10, 2008
+.Dt LINK 2
+.Os
+.Sh NAME
+.Nm link ,
+.Nm linkat
+.Nd make a hard file link
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft int
+.Fn link "const char *name1" "const char *name2"
+.Ft int
+.Fo linkat
+.Fa "int fd1" "const char *name1" "int fd2" "const char *name2" "int flag"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn link
+system call
+atomically creates the specified directory entry (hard link)
+.Fa name2
+with the attributes of the underlying object pointed at by
+.Fa name1 .
+If the link is successful: the link count of the underlying object
+is incremented;
+.Fa name1
+and
+.Fa name2
+share equal access and rights
+to the
+underlying object.
+.Pp
+If
+.Fa name1
+is removed, the file
+.Fa name2
+is not deleted and the link count of the
+underlying object is
+decremented.
+.Pp
+The object pointed at by the
+.Fa name1
+argument
+must exist for the hard link to
+succeed and
+both
+.Fa name1
+and
+.Fa name2
+must be in the same file system.
+The
+.Fa name1
+argument
+may not be a directory.
+.Pp
+The
+.Fn linkat
+system call is equivalent to
+.Fa link
+except in the case where either
+.Fa name1
+or
+.Fa name2
+or both are relative paths.
+In this case a relative path
+.Fa name1
+is interpreted relative to
+the directory associated with the file descriptor
+.Fa fd1
+instead of the current working directory and similarly for
+.Fa name2
+and the file descriptor
+.Fa fd2 .
+.Pp
+Values for
+.Fa flag
+are constructed by a bitwise-inclusive OR of flags from the following
+list, defined in
+.In fcntl.h :
+.Bl -tag -width indent
+.It Dv AT_SYMLINK_FOLLOW
+If
+.Fa name1
+names a symbolic link, a new link for the target of the symbolic link is
+created.
+.El
+.Pp
+If
+.Fn linkat
+is passed the special value
+.Dv AT_FDCWD
+in the
+.Fa fd1
+or
+.Fa fd2
+parameter, the current working directory is used for the respective
+.Fa name
+argument.
+If both
+.Fa fd1
+and
+.Fa fd2
+have value
+.Dv AT_FDCWD ,
+the behavior is identical to a call to
+.Fn link .
+Unless
+.Fa flag
+contains the
+.Dv AT_SYMLINK_FOLLOW
+flag, if
+.Fa name1
+names a symbolic link, a new link is created for the symbolic link
+.Fa name1
+and not its target.
+.Sh RETURN VALUES
+.Rv -std link
+.Sh ERRORS
+The
+.Fn link
+system call
+will fail and no link will be created if:
+.Bl -tag -width Er
+.It Bq Er ENOTDIR
+A component of either path prefix is not a directory.
+.It Bq Er ENAMETOOLONG
+A component of either pathname exceeded 255 characters,
+or entire length of either path name exceeded 1023 characters.
+.It Bq Er ENOENT
+A component of either path prefix does not exist.
+.It Bq Er EOPNOTSUPP
+The file system containing the file named by
+.Fa name1
+does not support links.
+.It Bq Er EMLINK
+The link count of the file named by
+.Fa name1
+would exceed 32767.
+.It Bq Er EACCES
+A component of either path prefix denies search permission.
+.It Bq Er EACCES
+The requested link requires writing in a directory with a mode
+that denies write permission.
+.It Bq Er ELOOP
+Too many symbolic links were encountered in translating one of the pathnames.
+.It Bq Er ENOENT
+The file named by
+.Fa name1
+does not exist.
+.It Bq Er EEXIST
+The link named by
+.Fa name2
+does exist.
+.It Bq Er EPERM
+The file named by
+.Fa name1
+is a directory.
+.It Bq Er EPERM
+The file named by
+.Fa name1
+has its immutable or append-only flag set, see the
+.Xr chflags 2
+manual page for more information.
+.It Bq Er EPERM
+The parent directory of the file named by
+.Fa name2
+has its immutable flag set.
+.It Bq Er EXDEV
+The link named by
+.Fa name2
+and the file named by
+.Fa name1
+are on different file systems.
+.It Bq Er ENOSPC
+The directory in which the entry for the new link is being placed
+cannot be extended because there is no space left on the file
+system containing the directory.
+.It Bq Er EDQUOT
+The directory in which the entry for the new link
+is being placed cannot be extended because the
+user's quota of disk blocks on the file system
+containing the directory has been exhausted.
+.It Bq Er EIO
+An I/O error occurred while reading from or writing to
+the file system to make the directory entry.
+.It Bq Er EROFS
+The requested link requires writing in a directory on a read-only file
+system.
+.It Bq Er EFAULT
+One of the pathnames specified
+is outside the process's allocated address space.
+.El
+.Pp
+In addition to the errors returned by the
+.Fn link ,
+the
+.Fn linkat
+system call may fail if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa name1
+or
+.Fa name2
+argument does not specify an absolute path and the
+.Fa fd1
+or
+.Fa fd2
+argument, respectively, is neither
+.Dv AT_FDCWD
+nor a valid file descriptor open for searching.
+.It Bq Er EINVAL
+The value of the
+.Fa flag
+argument is not valid.
+.It Bq Er ENOTDIR
+The
+.Fa name1
+or
+.Fa name2
+argument is not an absolute path and
+.Fa fd1
+or
+.Fa fd2 ,
+respectively, is neither
+.Dv AT_FDCWD
+nor a file descriptor associated with a directory.
+.El
+.Sh SEE ALSO
+.Xr chflags 2 ,
+.Xr readlink 2 ,
+.Xr symlink 2 ,
+.Xr unlink 2
+.Sh STANDARDS
+The
+.Fn link
+system call is expected to conform to
+.St -p1003.1-90 .
+The
+.Fn linkat
+system call follows The Open Group Extended API Set 2 specification.
+.Sh HISTORY
+The
+.Fn link
+function appeared in
+.At v7 .
+The
+.Fn linkat
+system call appeared in
+.Fx 8.0 .
+.Pp
+The
+.Fn link
+system call traditionally allows the super-user to link directories which
+corrupts the file system coherency.
+This implementation no longer permits it.
diff --git a/lib/libc/sys/lio_listio.2 b/lib/libc/sys/lio_listio.2
new file mode 100644
index 000000000000..ae228f7e2d8f
--- /dev/null
+++ b/lib/libc/sys/lio_listio.2
@@ -0,0 +1,218 @@
+.\" Copyright (c) 2003 Tim J. Robbins
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd July 15, 2016
+.Dt LIO_LISTIO 2
+.Os
+.Sh NAME
+.Nm lio_listio
+.Nd "list directed I/O (REALTIME)"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In aio.h
+.Ft int
+.Fo lio_listio
+.Fa "int mode"
+.Fa "struct aiocb * const list[]"
+.Fa "int nent"
+.Fa "struct sigevent *sig"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn lio_listio
+function initiates a list of I/O requests with a single function call.
+The
+.Fa list
+argument is an array of pointers to
+.Vt aiocb
+structures describing each operation to perform,
+with
+.Fa nent
+elements.
+.Dv NULL
+elements are ignored.
+.Pp
+The
+.Va aio_lio_opcode
+field of each
+.Vt aiocb
+specifies the operation to be performed.
+The following operations are supported:
+.Bl -tag -width ".Dv LIO_WRITE"
+.It Dv LIO_READ
+Read data as if by a call to
+.Xr aio_read 2 .
+.It Dv LIO_NOP
+No operation.
+.It Dv LIO_WRITE
+Write data as if by a call to
+.Xr aio_write 2 .
+.El
+.Pp
+If the
+.Fa mode
+argument is
+.Dv LIO_WAIT ,
+.Fn lio_listio
+does not return until all the requested operations have been completed.
+If
+.Fa mode
+is
+.Dv LIO_NOWAIT ,
+.Fa sig
+can be used to request asynchronous notification when all operations have
+completed.
+If
+.Fa sig
+is
+.Dv NULL ,
+no notification is sent.
+.Pp
+For
+.Dv SIGEV_KEVENT
+notifications,
+the posted kevent will contain:
+.Bl -column ".Va filter"
+.It Sy Member Ta Sy Value
+.It Va ident Ta Fa list
+.It Va filter Ta Dv EVFILT_LIO
+.It Va udata Ta
+value stored in
+.Fa sig->sigev_value
+.El
+.Pp
+For
+.Dv SIGEV_SIGNO
+and
+.Dv SIGEV_THREAD_ID
+notifications,
+the information for the queued signal will include
+.Dv SI_ASYNCIO
+in the
+.Va si_code
+field and the value stored in
+.Fa sig->sigev_value
+in the
+.Va si_value
+field.
+.Pp
+For
+.Dv SIGEV_THREAD
+notifications,
+the value stored in
+.Fa sig->sigev_value
+is passed to the
+.Fa sig->sigev_notify_function
+as described in
+.Xr sigevent 3 .
+.Pp
+The order in which the requests are carried out is not specified;
+in particular, there is no guarantee that they will be executed in
+the order 0, 1, ...,
+.Fa nent Ns \-1 .
+.Sh RETURN VALUES
+If
+.Fa mode
+is
+.Dv LIO_WAIT ,
+the
+.Fn lio_listio
+function returns 0 if the operations completed successfully,
+otherwise \-1.
+.Pp
+If
+.Fa mode
+is
+.Dv LIO_NOWAIT ,
+the
+.Fn lio_listio
+function returns 0 if the operations are successfully queued,
+otherwise \-1.
+.Sh ERRORS
+The
+.Fn lio_listio
+function will fail if:
+.Bl -tag -width Er
+.It Bq Er EAGAIN
+There are not enough resources to enqueue the requests.
+.It Bq Er EAGAIN
+The request would cause the system-wide limit
+.Dv AIO_MAX
+to be exceeded.
+.It Bq Er EINVAL
+The
+.Fa mode
+argument is neither
+.Dv LIO_WAIT
+nor
+.Dv LIO_NOWAIT ,
+or
+.Fa nent
+is greater than
+.Dv AIO_LISTIO_MAX .
+.It Bq Er EINVAL
+The asynchronous notification method in
+.Fa sig->sigev_notify
+is invalid or not supported.
+.It Bq Er EINTR
+A signal interrupted the system call before it could be completed.
+.It Bq Er EIO
+One or more requests failed.
+.El
+.Pp
+In addition, the
+.Fn lio_listio
+function may fail for any of the reasons listed for
+.Xr aio_read 2
+and
+.Xr aio_write 2 .
+.Pp
+If
+.Fn lio_listio
+succeeds, or fails with an error code of
+.Er EAGAIN , EINTR ,
+or
+.Er EIO ,
+some of the requests may have been initiated.
+The caller should check the error status of each
+.Vt aiocb
+structure individually by calling
+.Xr aio_error 2 .
+.Sh SEE ALSO
+.Xr aio_error 2 ,
+.Xr aio_read 2 ,
+.Xr aio_write 2 ,
+.Xr read 2 ,
+.Xr write 2 ,
+.Xr sigevent 3 ,
+.Xr siginfo 3 ,
+.Xr aio 4
+.Sh STANDARDS
+The
+.Fn lio_listio
+function is expected to conform to
+.St -p1003.1-2001 .
diff --git a/lib/libc/sys/listen.2 b/lib/libc/sys/listen.2
new file mode 100644
index 000000000000..2bf5a3dd6a49
--- /dev/null
+++ b/lib/libc/sys/listen.2
@@ -0,0 +1,186 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" From: @(#)listen.2 8.2 (Berkeley) 12/11/93
+.\" $FreeBSD$
+.\"
+.Dd August 18, 2016
+.Dt LISTEN 2
+.Os
+.Sh NAME
+.Nm listen
+.Nd listen for connections on a socket
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/socket.h
+.Ft int
+.Fn listen "int s" "int backlog"
+.Sh DESCRIPTION
+To accept connections, a socket
+is first created with
+.Xr socket 2 ,
+a willingness to accept incoming connections and
+a queue limit for incoming connections are specified with
+.Fn listen ,
+and then the connections are
+accepted with
+.Xr accept 2 .
+The
+.Fn listen
+system call applies only to sockets of type
+.Dv SOCK_STREAM
+or
+.Dv SOCK_SEQPACKET .
+.Pp
+The
+.Fa backlog
+argument defines the maximum length the queue of
+pending connections may grow to.
+The real maximum queue length will be 1.5 times more than the value
+specified in the
+.Fa backlog
+argument.
+A subsequent
+.Fn listen
+system call on the listening socket allows the caller to change the maximum
+queue length using a new
+.Fa backlog
+argument.
+If a connection
+request arrives with the queue full the client may
+receive an error with an indication of
+.Er ECONNREFUSED ,
+or, in the case of TCP, the connection will be
+silently dropped.
+.Pp
+Current queue lengths of listening sockets can be queried using
+.Xr netstat 1
+command.
+.Pp
+Note that before
+.Fx 4.5
+and the introduction of the syncache,
+the
+.Fa backlog
+argument also determined the length of the incomplete
+connection queue, which held TCP sockets in the process
+of completing TCP's 3-way handshake.
+These incomplete connections
+are now held entirely in the syncache, which is unaffected by
+queue lengths.
+Inflated
+.Fa backlog
+values to help handle denial
+of service attacks are no longer necessary.
+.Pp
+The
+.Xr sysctl 3
+MIB variable
+.Va kern.ipc.soacceptqueue
+specifies a hard limit on
+.Fa backlog ;
+if a value greater than
+.Va kern.ipc.soacceptqueue
+or less than zero is specified,
+.Fa backlog
+is silently forced to
+.Va kern.ipc.soacceptqueue .
+.Sh INTERACTION WITH ACCEPT FILTERS
+When accept filtering is used on a socket, a second queue will
+be used to hold sockets that have connected, but have not yet
+met their accept filtering criteria.
+Once the criteria has been
+met, these sockets will be moved over into the completed connection
+queue to be
+.Xr accept 2 Ns ed .
+If this secondary queue is full and a
+new connection comes in, the oldest socket which has not yet met
+its accept filter criteria will be terminated.
+.Pp
+This secondary queue, like the primary listen queue, is sized
+according to the
+.Fa backlog
+argument.
+.Sh RETURN VALUES
+.Rv -std listen
+.Sh ERRORS
+The
+.Fn listen
+system call
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The argument
+.Fa s
+is not a valid descriptor.
+.It Bq Er EDESTADDRREQ
+The socket is not bound to a local address, and the protocol does not
+support listening on an unbound socket.
+.It Bq Er EINVAL
+The socket is already connected, or in the process of being connected.
+.It Bq Er ENOTSOCK
+The argument
+.Fa s
+is not a socket.
+.It Bq Er EOPNOTSUPP
+The socket is not of a type that supports the operation
+.Fn listen .
+.El
+.Sh SEE ALSO
+.Xr netstat 1 ,
+.Xr accept 2 ,
+.Xr connect 2 ,
+.Xr socket 2 ,
+.Xr sysctl 3 ,
+.Xr sysctl 8 ,
+.Xr accept_filter 9
+.Sh HISTORY
+The
+.Fn listen
+system call appeared in
+.Bx 4.2 .
+The ability to configure the maximum
+.Fa backlog
+at run-time, and to use a negative
+.Fa backlog
+to request the maximum allowable value, was introduced in
+.Fx 2.2 .
+The
+.Va kern.ipc.somaxconn
+.Xr sysctl 3
+has been replaced with
+.Va kern.ipc.soacceptqueue
+in
+.Fx 10.0
+to prevent confusion about its actual functionality.
+The original
+.Xr sysctl 3
+.Va kern.ipc.somaxconn
+is still available but hidden from a
+.Xr sysctl 3
+-a output so that existing applications and scripts continue to work.
diff --git a/lib/libc/sys/lseek.2 b/lib/libc/sys/lseek.2
new file mode 100644
index 000000000000..017dc54227eb
--- /dev/null
+++ b/lib/libc/sys/lseek.2
@@ -0,0 +1,217 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)lseek.2 8.3 (Berkeley) 4/19/94
+.\" $FreeBSD$
+.\"
+.Dd February 18, 2016
+.Dt LSEEK 2
+.Os
+.Sh NAME
+.Nm lseek
+.Nd reposition read/write file offset
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft off_t
+.Fn lseek "int fildes" "off_t offset" "int whence"
+.Sh DESCRIPTION
+The
+.Fn lseek
+system call repositions the offset of the file descriptor
+.Fa fildes
+to the
+argument
+.Fa offset
+according to the directive
+.Fa whence .
+The argument
+.Fa fildes
+must be an open
+file descriptor.
+The
+.Fn lseek
+system call
+repositions the file position pointer associated with the file
+descriptor
+.Fa fildes
+as follows:
+.Bl -item -offset indent
+.It
+If
+.Fa whence
+is
+.Dv SEEK_SET ,
+the offset is set to
+.Fa offset
+bytes.
+.It
+If
+.Fa whence
+is
+.Dv SEEK_CUR ,
+the offset is set to its current location plus
+.Fa offset
+bytes.
+.It
+If
+.Fa whence
+is
+.Dv SEEK_END ,
+the offset is set to the size of the
+file plus
+.Fa offset
+bytes.
+.It
+If
+.Fa whence
+is
+.Dv SEEK_HOLE ,
+the offset is set to the start of the next hole greater than or equal
+to the supplied
+.Fa offset .
+The definition of a hole is provided below.
+.It
+If
+.Fa whence
+is
+.Dv SEEK_DATA ,
+the offset is set to the start of the next non-hole file region greater
+than or equal to the supplied
+.Fa offset .
+.El
+.Pp
+The
+.Fn lseek
+system call allows the file offset to be set beyond the end
+of the existing end-of-file of the file.
+If data is later written
+at this point, subsequent reads of the data in the gap return
+bytes of zeros (until data is actually written into the gap).
+.Pp
+Some devices are incapable of seeking.
+The value of the pointer
+associated with such a device is undefined.
+.Pp
+A
+.Qq hole
+is defined as a contiguous range of bytes in a file, all having the value of
+zero, but not all zeros in a file are guaranteed to be represented as holes
+returned with
+.Dv SEEK_HOLE .
+File systems are allowed to expose ranges of zeros with
+.Dv SEEK_HOLE ,
+but not required to.
+Applications can use
+.Dv SEEK_HOLE
+to optimise their behavior for ranges of zeros, but must not depend on it to
+find all such ranges in a file.
+Each file is presented as having a zero-size virtual hole at the very
+end of the file.
+The existence of a hole at the end of every data region allows for easy
+programming and also provides compatibility to the original implementation
+in Solaris.
+It also causes the current file size (i.e., end-of-file offset) to be returned
+to indicate that there are no more holes past the supplied
+.Fa offset .
+Applications should use
+.Fn fpathconf _PC_MIN_HOLE_SIZE
+or
+.Fn pathconf _PC_MIN_HOLE_SIZE
+to determine if a file system supports
+.Dv SEEK_HOLE .
+See
+.Xr pathconf 2 .
+.Pp
+For file systems that do not supply information about holes, the file will be
+represented as one entire data region.
+.Sh RETURN VALUES
+Upon successful completion,
+.Fn lseek
+returns the resulting offset location as measured in bytes from the
+beginning of the file.
+Otherwise,
+a value of -1 is returned and
+.Va errno
+is set to indicate
+the error.
+.Sh ERRORS
+The
+.Fn lseek
+system call
+will fail and the file position pointer will remain unchanged if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa fildes
+argument
+is not an open file descriptor.
+.It Bq Er EINVAL
+The
+.Fa whence
+argument
+is not a proper value
+or the resulting file offset would
+be negative for a non-character special file.
+.It Bq Er ENXIO
+For
+.Dv SEEK_DATA ,
+there are no more data regions past the supplied offset.
+Due to existence of the hole at the end of the file, for
+.Dv SEEK_HOLE
+this error is only returned when the
+.Fa offset
+already points to the end-of-file position.
+.It Bq Er EOVERFLOW
+The resulting file offset would be a value which cannot be represented
+correctly in an object of type
+.Fa off_t .
+.It Bq Er ESPIPE
+The
+.Fa fildes
+argument
+is associated with a pipe, socket, or FIFO.
+.El
+.Sh SEE ALSO
+.Xr dup 2 ,
+.Xr open 2 ,
+.Xr pathconf 2
+.Sh STANDARDS
+The
+.Fn lseek
+system call is expected to conform to
+.St -p1003.1-90 .
+.Sh HISTORY
+The
+.Fn lseek
+function appeared in
+.At v7 .
+.Sh BUGS
+This document's use of
+.Fa whence
+is incorrect English, but is maintained for historical reasons.
diff --git a/lib/libc/sys/madvise.2 b/lib/libc/sys/madvise.2
new file mode 100644
index 000000000000..499bf67b8a91
--- /dev/null
+++ b/lib/libc/sys/madvise.2
@@ -0,0 +1,186 @@
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)madvise.2 8.1 (Berkeley) 6/9/93
+.\" $FreeBSD$
+.\"
+.Dd July 12, 2015
+.Dt MADVISE 2
+.Os
+.Sh NAME
+.Nm madvise , posix_madvise
+.Nd give advice about use of memory
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/mman.h
+.Ft int
+.Fn madvise "void *addr" "size_t len" "int behav"
+.Ft int
+.Fn posix_madvise "void *addr" "size_t len" "int behav"
+.Sh DESCRIPTION
+The
+.Fn madvise
+system call
+allows a process that has knowledge of its memory behavior
+to describe it to the system.
+The
+.Fn posix_madvise
+interface is identical, except it returns an error number on error and does
+not modify
+.Va errno ,
+and is provided for standards conformance.
+.Pp
+The known behaviors are:
+.Bl -tag -width MADV_SEQUENTIAL
+.It Dv MADV_NORMAL
+Tells the system to revert to the default paging
+behavior.
+.It Dv MADV_RANDOM
+Is a hint that pages will be accessed randomly, and prefetching
+is likely not advantageous.
+.It Dv MADV_SEQUENTIAL
+Causes the VM system to depress the priority of
+pages immediately preceding a given page when it is faulted in.
+.It Dv MADV_WILLNEED
+Causes pages that are in a given virtual address range
+to temporarily have higher priority, and if they are in
+memory, decrease the likelihood of them being freed.
+Additionally,
+the pages that are already in memory will be immediately mapped into
+the process, thereby eliminating unnecessary overhead of going through
+the entire process of faulting the pages in.
+This WILL NOT fault
+pages in from backing store, but quickly map the pages already in memory
+into the calling process.
+.It Dv MADV_DONTNEED
+Allows the VM system to decrease the in-memory priority
+of pages in the specified address range.
+Consequently, future references to this address range are more likely
+to incur a page fault.
+.It Dv MADV_FREE
+Gives the VM system the freedom to free pages,
+and tells the system that information in the specified page range
+is no longer important.
+This is an efficient way of allowing
+.Xr malloc 3
+to free pages anywhere in the address space, while keeping the address space
+valid.
+The next time that the page is referenced, the page might be demand
+zeroed, or might contain the data that was there before the
+.Dv MADV_FREE
+call.
+References made to that address space range will not make the VM system
+page the information back in from backing store until the page is
+modified again.
+.It Dv MADV_NOSYNC
+Request that the system not flush the data associated with this map to
+physical backing store unless it needs to.
+Typically this prevents the
+file system update daemon from gratuitously writing pages dirtied
+by the VM system to physical disk.
+Note that VM/file system coherency is
+always maintained, this feature simply ensures that the mapped data is
+only flush when it needs to be, usually by the system pager.
+.Pp
+This feature is typically used when you want to use a file-backed shared
+memory area to communicate between processes (IPC) and do not particularly
+need the data being stored in that area to be physically written to disk.
+With this feature you get the equivalent performance with mmap that you
+would expect to get with SysV shared memory calls, but in a more controllable
+and less restrictive manner.
+However, note that this feature is not portable
+across UNIX platforms (though some may do the right thing by default).
+For more information see the MAP_NOSYNC section of
+.Xr mmap 2
+.It Dv MADV_AUTOSYNC
+Undoes the effects of MADV_NOSYNC for any future pages dirtied within the
+address range.
+The effect on pages already dirtied is indeterminate - they
+may or may not be reverted.
+You can guarantee reversion by using the
+.Xr msync 2
+or
+.Xr fsync 2
+system calls.
+.It Dv MADV_NOCORE
+Region is not included in a core file.
+.It Dv MADV_CORE
+Include region in a core file.
+.It Dv MADV_PROTECT
+Informs the VM system this process should not be killed when the
+swap space is exhausted.
+The process must have superuser privileges.
+This should be used judiciously in processes that must remain running
+for the system to properly function.
+.El
+.Pp
+Portable programs that call the
+.Fn posix_madvise
+interface should use the aliases
+.Dv POSIX_MADV_NORMAL , POSIX_MADV_SEQUENTIAL ,
+.Dv POSIX_MADV_RANDOM , POSIX_MADV_WILLNEED ,
+and
+.Dv POSIX_MADV_DONTNEED
+rather than the flags described above.
+.Sh RETURN VALUES
+.Rv -std madvise
+.Sh ERRORS
+The
+.Fn madvise
+system call will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa behav
+argument is not valid.
+.It Bq Er ENOMEM
+The virtual address range specified by the
+.Fa addr
+and
+.Fa len
+arguments is not valid.
+.It Bq Er EPERM
+.Dv MADV_PROTECT
+was specified and the process does not have superuser privileges.
+.El
+.Sh SEE ALSO
+.Xr mincore 2 ,
+.Xr mprotect 2 ,
+.Xr msync 2 ,
+.Xr munmap 2 ,
+.Xr posix_fadvise 2
+.Sh STANDARDS
+The
+.Fn posix_madvise
+interface conforms to
+.St -p1003.1-2001 .
+.Sh HISTORY
+The
+.Fn madvise
+system call first appeared in
+.Bx 4.4 .
diff --git a/lib/libc/sys/mincore.2 b/lib/libc/sys/mincore.2
new file mode 100644
index 000000000000..6c0fc670ef24
--- /dev/null
+++ b/lib/libc/sys/mincore.2
@@ -0,0 +1,115 @@
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)mincore.2 8.1 (Berkeley) 6/9/93
+.\" $FreeBSD$
+.\"
+.Dd January 17, 2003
+.Dt MINCORE 2
+.Os
+.Sh NAME
+.Nm mincore
+.Nd determine residency of memory pages
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/mman.h
+.Ft int
+.Fn mincore "const void *addr" "size_t len" "char *vec"
+.Sh DESCRIPTION
+The
+.Fn mincore
+system call determines whether each of the pages in the region beginning at
+.Fa addr
+and continuing for
+.Fa len
+bytes is resident.
+.\"The beginning address,
+.\".Fa addr ,
+.\"is first rounded down to a multiple of the page size (see
+.\".Xr getpagesize 3 ) .
+.\"The end address,
+.\".Fa addr No + Fa len ,
+.\"is rounded up to a multiple of the page size.
+The status is returned in the
+.Fa vec
+array, one character per page.
+Each character is either 0 if the page is not resident, or a combination of
+the following flags (defined in
+.In sys/mman.h ) :
+.Bl -tag -width ".Dv MINCORE_REFERENCED_OTHER"
+.It Dv MINCORE_INCORE
+Page is in core (resident).
+.It Dv MINCORE_REFERENCED
+Page has been referenced by us.
+.It Dv MINCORE_MODIFIED
+Page has been modified by us.
+.It Dv MINCORE_REFERENCED_OTHER
+Page has been referenced.
+.It Dv MINCORE_MODIFIED_OTHER
+Page has been modified.
+.It Dv MINCORE_SUPER
+Page is part of a "super" page. (only i386 & amd64)
+.El
+.Pp
+The information returned by
+.Fn mincore
+may be out of date by the time the system call returns.
+The only way to ensure that a page is resident is to lock it into memory
+with the
+.Xr mlock 2
+system call.
+.Sh RETURN VALUES
+.Rv -std mincore
+.Sh ERRORS
+The
+.Fn mincore
+system call will fail if:
+.Bl -tag -width Er
+.It Bq Er ENOMEM
+The virtual address range specified by the
+.Fa addr
+and
+.Fa len
+arguments is not fully mapped.
+.It Bq Er EFAULT
+The
+.Fa vec
+argument points to an illegal address.
+.El
+.Sh SEE ALSO
+.Xr madvise 2 ,
+.Xr mlock 2 ,
+.Xr mprotect 2 ,
+.Xr msync 2 ,
+.Xr munmap 2 ,
+.Xr getpagesize 3
+.Sh HISTORY
+The
+.Fn mincore
+system call first appeared in
+.Bx 4.4 .
diff --git a/lib/libc/sys/minherit.2 b/lib/libc/sys/minherit.2
new file mode 100644
index 000000000000..dc85d09fd28e
--- /dev/null
+++ b/lib/libc/sys/minherit.2
@@ -0,0 +1,139 @@
+.\" $FreeBSD$
+.\"
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)minherit.2 8.1 (Berkeley) 6/9/93
+.\"
+.Dd October 30, 2007
+.Dt MINHERIT 2
+.Os
+.Sh NAME
+.Nm minherit
+.Nd control the inheritance of pages
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/mman.h
+.Ft int
+.Fn minherit "void *addr" "size_t len" "int inherit"
+.Sh DESCRIPTION
+The
+.Fn minherit
+system call
+changes the specified pages to have the inheritance characteristic
+.Fa inherit .
+Not all implementations will guarantee that the inheritance characteristic
+can be set on a page basis;
+the granularity of changes may be as large as an entire region.
+.Fx
+is capable of adjusting inheritance characteristics on a page basis.
+Inheritance only effects children created by
+.Fn fork .
+It has no effect on
+.Fn exec .
+exec'd processes replace their address space entirely.
+This system call also
+has no effect on the parent's address space (other than to potentially
+share the address space with its children).
+.Pp
+Inheritance is a rather esoteric feature largely superseded by the
+.Dv MAP_SHARED
+feature of
+.Fn mmap .
+However, it is possible to use
+.Fn minherit
+to share a block of memory between parent and child that has been mapped
+.Dv MAP_PRIVATE .
+That is, modifications made by parent or child are shared but
+the original underlying file is left untouched.
+.Bl -tag -width ".Dv INHERIT_SHARE"
+.It Dv INHERIT_SHARE
+This option causes the address space in question to be shared between
+parent and child.
+It has no effect on how the original underlying backing
+store was mapped.
+.It Dv INHERIT_NONE
+This option prevents the address space in question from being inherited
+at all.
+The address space will be unmapped in the child.
+.It Dv INHERIT_COPY
+This option causes the child to inherit the address space as copy-on-write.
+This option also has an unfortunate side effect of causing the parent
+address space to become copy-on-write when the parent forks.
+If the original mapping was
+.Dv MAP_SHARED ,
+it will no longer be shared in the parent
+after the parent forks and there is no way to get the previous
+shared-backing-store mapping without unmapping and remapping the address
+space in the parent.
+.El
+.Sh RETURN VALUES
+.Rv -std minherit
+.Sh ERRORS
+The
+.Fn minherit
+system call will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The virtual address range specified by the
+.Fa addr
+and
+.Fa len
+arguments is not valid.
+.It Bq Er EACCES
+The flags specified by the
+.Fa inherit
+argument were not valid for the pages specified
+by the
+.Fa addr
+and
+.Fa len
+arguments.
+.El
+.Sh SEE ALSO
+.Xr fork 2 ,
+.Xr madvise 2 ,
+.Xr mincore 2 ,
+.Xr mprotect 2 ,
+.Xr msync 2 ,
+.Xr munmap 2 ,
+.Xr rfork 2
+.Sh HISTORY
+The
+.Fn minherit
+system call first appeared in
+.Ox
+and then in
+.Fx 2.2 .
+.Sh BUGS
+Once you set inheritance to
+.Dv MAP_PRIVATE
+or
+.Dv MAP_SHARED ,
+there is no way to recover the original copy-on-write semantics
+short of unmapping and remapping the area.
diff --git a/lib/libc/sys/mkdir.2 b/lib/libc/sys/mkdir.2
new file mode 100644
index 000000000000..1edb408f85c9
--- /dev/null
+++ b/lib/libc/sys/mkdir.2
@@ -0,0 +1,176 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)mkdir.2 8.2 (Berkeley) 12/11/93
+.\" $FreeBSD$
+.\"
+.Dd June 26, 2008
+.Dt MKDIR 2
+.Os
+.Sh NAME
+.Nm mkdir ,
+.Nm mkdirat
+.Nd make a directory file
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/stat.h
+.Ft int
+.Fn mkdir "const char *path" "mode_t mode"
+.Ft int
+.Fn mkdirat "int fd" "const char *path" "mode_t mode"
+.Sh DESCRIPTION
+The directory
+.Fa path
+is created with the access permissions specified by
+.Fa mode
+and restricted by the
+.Xr umask 2
+of the calling process.
+.Pp
+The directory's owner ID is set to the process's effective user ID.
+The directory's group ID is set to that of the parent directory in
+which it is created.
+.Pp
+The
+.Fn mkdirat
+system call is equivalent to
+.Fn mkdir
+except in the case where
+.Fa path
+specifies a relative path.
+In this case the newly created directory is created relative to the
+directory associated with the file descriptor
+.Fa fd
+instead of the current working directory.
+If
+.Fn mkdirat
+is passed the special value
+.Dv AT_FDCWD
+in the
+.Fa fd
+parameter, the current working directory is used and the behavior is
+identical to a call to
+.Fn mkdir .
+.Sh RETURN VALUES
+.Rv -std mkdir
+.Sh ERRORS
+The
+.Fn mkdir
+system call
+will fail and no directory will be created if:
+.Bl -tag -width Er
+.It Bq Er ENOTDIR
+A component of the path prefix is not a directory.
+.It Bq Er ENAMETOOLONG
+A component of a pathname exceeded 255 characters,
+or an entire path name exceeded 1023 characters.
+.It Bq Er ENOENT
+A component of the path prefix does not exist.
+.It Bq Er EACCES
+Search permission is denied for a component of the path prefix,
+or write permission is denied
+on the parent directory of the directory to be created.
+.It Bq Er ELOOP
+Too many symbolic links were encountered in translating the pathname.
+.It Bq Er EPERM
+The parent directory of the directory to be created has its immutable flag set,
+see the
+.Xr chflags 2
+manual page for more information.
+.It Bq Er EROFS
+The named directory would reside on a read-only file system.
+.It Bq Er EMLINK
+The new directory cannot be created because the parent directory contains
+too many subdirectories.
+.It Bq Er EEXIST
+The named file exists.
+.It Bq Er ENOSPC
+The new directory cannot be created because there is no space left
+on the file system that will contain the directory.
+.It Bq Er ENOSPC
+There are no free inodes on the file system on which the
+directory is being created.
+.It Bq Er EDQUOT
+The new directory cannot be created because the user's
+quota of disk blocks on the file system that will
+contain the directory has been exhausted.
+.It Bq Er EDQUOT
+The user's quota of inodes on the file system on
+which the directory is being created has been exhausted.
+.It Bq Er EIO
+An I/O error occurred while making the directory entry or allocating the inode.
+.It Bq Er EIO
+An I/O error occurred while reading from or writing to the file system.
+.It Bq Er EFAULT
+The
+.Fa path
+argument
+points outside the process's allocated address space.
+.El
+.Pp
+In addition to the errors returned by the
+.Fn mkdir ,
+the
+.Fn mkdirat
+may fail if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa path
+argument does not specify an absolute path and the
+.Fa fd
+argument is neither
+.Dv AT_FDCWD
+nor a valid file descriptor open for searching.
+.It Bq Er ENOTDIR
+The
+.Fa path
+argument is not an absolute path and
+.Fa fd
+is neither
+.Dv AT_FDCWD
+nor a file descriptor associated with a directory.
+.El
+.Sh SEE ALSO
+.Xr chflags 2 ,
+.Xr chmod 2 ,
+.Xr stat 2 ,
+.Xr umask 2
+.Sh STANDARDS
+The
+.Fn mkdir
+system call is expected to conform to
+.St -p1003.1-90 .
+The
+.Fn mkdirat
+system call follows The Open Group Extended API Set 2 specification.
+.Sh HISTORY
+The
+.Fn mkdirat
+system call appeared in
+.Fx 8.0 .
diff --git a/lib/libc/sys/mkfifo.2 b/lib/libc/sys/mkfifo.2
new file mode 100644
index 000000000000..9b4ac5d29fd9
--- /dev/null
+++ b/lib/libc/sys/mkfifo.2
@@ -0,0 +1,185 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)mkfifo.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd April 10, 2008
+.Dt MKFIFO 2
+.Os
+.Sh NAME
+.Nm mkfifo ,
+.Nm mkfifoat
+.Nd make a fifo file
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/stat.h
+.Ft int
+.Fn mkfifo "const char *path" "mode_t mode"
+.Ft int
+.Fn mkfifoat "int fd" "const char *path" "mode_t mode"
+.Sh DESCRIPTION
+The
+.Fn mkfifo
+system call
+creates a new fifo file with name
+.Fa path .
+The access permissions are
+specified by
+.Fa mode
+and restricted by the
+.Xr umask 2
+of the calling process.
+.Pp
+The fifo's owner ID is set to the process's effective user ID.
+The fifo's group ID is set to that of the parent directory in
+which it is created.
+.Pp
+The
+.Fn mkfifoat
+system call is equivalent to
+.Fn mkfifo
+except in the case where
+.Fa path
+specifies a relative path.
+In this case the newly created FIFO is created relative to the
+directory associated with the file descriptor
+.Fa fd
+instead of the current working directory.
+If
+.Fn mkfifoat
+is passed the special value
+.Dv AT_FDCWD
+in the
+.Fa fd
+parameter, the current working directory is used and the behavior is
+identical to a call to
+.Fn mkfifo .
+.Sh RETURN VALUES
+.Rv -std mkfifo
+.Sh ERRORS
+The
+.Fn mkfifo
+system call
+will fail and no fifo will be created if:
+.Bl -tag -width Er
+.It Bq Er ENOTSUP
+The kernel has not been configured to support fifo's.
+.It Bq Er ENOTDIR
+A component of the path prefix is not a directory.
+.It Bq Er ENAMETOOLONG
+A component of a pathname exceeded 255 characters,
+or an entire path name exceeded 1023 characters.
+.It Bq Er ENOENT
+A component of the path prefix does not exist.
+.It Bq Er EACCES
+A component of the path prefix denies search permission, or write permission
+is denied on the parent directory of the fifo to be created.
+.It Bq Er ELOOP
+Too many symbolic links were encountered in translating the pathname.
+.It Bq Er EROFS
+The named file would reside on a read-only file system.
+.It Bq Er EEXIST
+The named file exists.
+.It Bq Er EPERM
+The parent directory of the named file has its immutable flag set, see the
+.Xr chflags 2
+manual page for more information.
+.It Bq Er ENOSPC
+The directory in which the entry for the new fifo is being placed
+cannot be extended because there is no space left on the file
+system containing the directory.
+.It Bq Er ENOSPC
+There are no free inodes on the file system on which the
+fifo is being created.
+.It Bq Er EDQUOT
+The directory in which the entry for the new fifo
+is being placed cannot be extended because the
+user's quota of disk blocks on the file system
+containing the directory has been exhausted.
+.It Bq Er EDQUOT
+The user's quota of inodes on the file system on
+which the fifo is being created has been exhausted.
+.It Bq Er EIO
+An
+.Tn I/O
+error occurred while making the directory entry or allocating the inode.
+.It Bq Er EIO
+An
+.Tn I/O
+error occurred while reading from or writing to the file system.
+.It Bq Er EFAULT
+The
+.Fa path
+argument
+points outside the process's allocated address space.
+.El
+.Pp
+In addition to the errors returned by the
+.Fn mkfifo ,
+the
+.Fn mkfifoat
+may fail if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa path
+argument does not specify an absolute path and the
+.Fa fd
+argument is neither
+.Dv AT_FDCWD
+nor a valid file descriptor open for searching.
+.It Bq Er ENOTDIR
+The
+.Fa path
+argument is not an absolute path and
+.Fa fd
+is neither
+.Dv AT_FDCWD
+nor a file descriptor associated with a directory.
+.El
+.Sh SEE ALSO
+.Xr chflags 2 ,
+.Xr chmod 2 ,
+.Xr mknod 2 ,
+.Xr stat 2 ,
+.Xr umask 2
+.Sh STANDARDS
+The
+.Fn mkfifo
+system call is expected to conform to
+.St -p1003.1-90 .
+The
+.Fn mkfifoat
+system call follows The Open Group Extended API Set 2 specification.
+.Sh HISTORY
+The
+.Fn mkfifoat
+system call appeared in
+.Fx 8.0 .
diff --git a/lib/libc/sys/mknod.2 b/lib/libc/sys/mknod.2
new file mode 100644
index 000000000000..a40606806a55
--- /dev/null
+++ b/lib/libc/sys/mknod.2
@@ -0,0 +1,182 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)mknod.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd January 16, 2011
+.Dt MKNOD 2
+.Os
+.Sh NAME
+.Nm mknod ,
+.Nm mknodat
+.Nd make a special file node
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/stat.h
+.Ft int
+.Fn mknod "const char *path" "mode_t mode" "dev_t dev"
+.Ft int
+.Fn mknodat "int fd" "const char *path" "mode_t mode" "dev_t dev"
+.Sh DESCRIPTION
+The file system node
+.Fa path
+is created with the file type and access permissions specified in
+.Fa mode .
+The access permissions are modified by the process's umask value.
+.Pp
+If
+.Fa mode
+indicates a block or character special file,
+.Fa dev
+is a configuration dependent specification denoting a particular device
+on the system.
+Otherwise,
+.Fa dev
+is ignored.
+.Pp
+The
+.Fn mknod
+system call
+requires super-user privileges.
+.Pp
+The
+.Fn mknodat
+system call is equivalent to
+.Fn mknod
+except in the case where
+.Fa path
+specifies a relative path.
+In this case the newly created device node is created relative to the
+directory associated with the file descriptor
+.Fa fd
+instead of the current working directory.
+If
+.Fn mknodat
+is passed the special value
+.Dv AT_FDCWD
+in the
+.Fa fd
+parameter, the current working directory is used and the behavior is
+identical to a call to
+.Fn mknod .
+.Sh RETURN VALUES
+.Rv -std mknod
+.Sh ERRORS
+The
+.Fn mknod
+system call
+will fail and the file will be not created if:
+.Bl -tag -width Er
+.It Bq Er ENOTDIR
+A component of the path prefix is not a directory.
+.It Bq Er ENAMETOOLONG
+A component of a pathname exceeded 255 characters,
+or an entire path name exceeded 1023 characters.
+.It Bq Er ENOENT
+A component of the path prefix does not exist.
+.It Bq Er EACCES
+Search permission is denied for a component of the path prefix.
+.It Bq Er ELOOP
+Too many symbolic links were encountered in translating the pathname.
+.It Bq Er EPERM
+The process's effective user ID is not super-user.
+.It Bq Er EIO
+An I/O error occurred while making the directory entry or allocating the inode.
+.It Bq Er ENOSPC
+The directory in which the entry for the new node is being placed
+cannot be extended because there is no space left on the file
+system containing the directory.
+.It Bq Er ENOSPC
+There are no free inodes on the file system on which the
+node is being created.
+.It Bq Er EDQUOT
+The directory in which the entry for the new node
+is being placed cannot be extended because the
+user's quota of disk blocks on the file system
+containing the directory has been exhausted.
+.It Bq Er EDQUOT
+The user's quota of inodes on the file system on
+which the node is being created has been exhausted.
+.It Bq Er EROFS
+The named file resides on a read-only file system.
+.It Bq Er EEXIST
+The named file exists.
+.It Bq Er EFAULT
+The
+.Fa path
+argument
+points outside the process's allocated address space.
+.It Bq Er EINVAL
+Creating anything else than a block or character special
+file (or a
+.Em whiteout )
+is not supported.
+.El
+.Pp
+In addition to the errors returned by the
+.Fn mknod ,
+the
+.Fn mknodat
+may fail if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa path
+argument does not specify an absolute path and the
+.Fa fd
+argument is neither
+.Dv AT_FDCWD
+nor a valid file descriptor open for searching.
+.It Bq Er ENOTDIR
+The
+.Fa path
+argument is not an absolute path and
+.Fa fd
+is neither
+.Dv AT_FDCWD
+nor a file descriptor associated with a directory.
+.El
+.Sh SEE ALSO
+.Xr chmod 2 ,
+.Xr mkfifo 2 ,
+.Xr stat 2 ,
+.Xr umask 2
+.Sh STANDARDS
+The
+.Fn mknodat
+system call follows The Open Group Extended API Set 2 specification.
+.Sh HISTORY
+The
+.Fn mknod
+function appeared in
+.At v6 .
+The
+.Fn mknodat
+system call appeared in
+.Fx 8.0 .
diff --git a/lib/libc/sys/mlock.2 b/lib/libc/sys/mlock.2
new file mode 100644
index 000000000000..4f264206fd26
--- /dev/null
+++ b/lib/libc/sys/mlock.2
@@ -0,0 +1,183 @@
+.\" Copyright (c) 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)mlock.2 8.2 (Berkeley) 12/11/93
+.\" $FreeBSD$
+.\"
+.Dd May 17, 2014
+.Dt MLOCK 2
+.Os
+.Sh NAME
+.Nm mlock ,
+.Nm munlock
+.Nd lock (unlock) physical pages in memory
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/mman.h
+.Ft int
+.Fn mlock "const void *addr" "size_t len"
+.Ft int
+.Fn munlock "const void *addr" "size_t len"
+.Sh DESCRIPTION
+The
+.Fn mlock
+system call
+locks into memory the physical pages associated with the virtual address
+range starting at
+.Fa addr
+for
+.Fa len
+bytes.
+The
+.Fn munlock
+system call unlocks pages previously locked by one or more
+.Fn mlock
+calls.
+For both, the
+.Fa addr
+argument should be aligned to a multiple of the page size.
+If the
+.Fa len
+argument is not a multiple of the page size, it will be rounded up
+to be so.
+The entire range must be allocated.
+.Pp
+After an
+.Fn mlock
+system call, the indicated pages will cause neither a non-resident page
+nor address-translation fault until they are unlocked.
+They may still cause protection-violation faults or TLB-miss faults on
+architectures with software-managed TLBs.
+The physical pages remain in memory until all locked mappings for the pages
+are removed.
+Multiple processes may have the same physical pages locked via their own
+virtual address mappings.
+A single process may likewise have pages multiply-locked via different virtual
+mappings of the same pages or via nested
+.Fn mlock
+calls on the same address range.
+Unlocking is performed explicitly by
+.Fn munlock
+or implicitly by a call to
+.Fn munmap
+which deallocates the unmapped address range.
+Locked mappings are not inherited by the child process after a
+.Xr fork 2 .
+.Pp
+Since physical memory is a potentially scarce resource, processes are
+limited in how much they can lock down.
+The amount of memory that a single process can
+.Fn mlock
+is limited by both the per-process
+.Dv RLIMIT_MEMLOCK
+resource limit and the
+system-wide
+.Dq wired pages
+limit
+.Va vm.max_wired .
+.Va vm.max_wired
+applies to the system as a whole, so the amount available to a single
+process at any given time is the difference between
+.Va vm.max_wired
+and
+.Va vm.stats.vm.v_wire_count .
+.Pp
+If
+.Va security.bsd.unprivileged_mlock
+is set to 0 these calls are only available to the super-user.
+.Sh RETURN VALUES
+.Rv -std
+.Pp
+If the call succeeds, all pages in the range become locked (unlocked);
+otherwise the locked status of all pages in the range remains unchanged.
+.Sh ERRORS
+The
+.Fn mlock
+system call
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EPERM
+.Va security.bsd.unprivileged_mlock
+is set to 0 and the caller is not the super-user.
+.It Bq Er EINVAL
+The address given is not page aligned or the length is negative.
+.It Bq Er EAGAIN
+Locking the indicated range would exceed the system limit for locked memory.
+.It Bq Er ENOMEM
+Some portion of the indicated address range is not allocated.
+There was an error faulting/mapping a page.
+Locking the indicated range would exceed the per-process limit for locked
+memory.
+.El
+The
+.Fn munlock
+system call
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EPERM
+.Va security.bsd.unprivileged_mlock
+is set to 0 and the caller is not the super-user.
+.It Bq Er EINVAL
+The address given is not page aligned or the length is negative.
+.It Bq Er ENOMEM
+Some or all of the address range specified by the addr and len
+arguments does not correspond to valid mapped pages in the address space
+of the process.
+.It Bq Er ENOMEM
+Locking the pages mapped by the specified range would exceed a limit on
+the amount of memory that the process may lock.
+.El
+.Sh "SEE ALSO"
+.Xr fork 2 ,
+.Xr mincore 2 ,
+.Xr minherit 2 ,
+.Xr mlockall 2 ,
+.Xr mmap 2 ,
+.Xr munlockall 2 ,
+.Xr munmap 2 ,
+.Xr setrlimit 2 ,
+.Xr getpagesize 3
+.Sh HISTORY
+The
+.Fn mlock
+and
+.Fn munlock
+system calls first appeared in
+.Bx 4.4 .
+.Sh BUGS
+Allocating too much wired memory can lead to a memory-allocation deadlock
+which requires a reboot to recover from.
+.Pp
+The per-process resource limit is a limit on the amount of virtual
+memory locked, while the system-wide limit is for the number of locked
+physical pages.
+Hence a process with two distinct locked mappings of the same physical page
+counts as 2 pages against the per-process limit and as only a single page
+in the system limit.
+.Pp
+The per-process resource limit is not currently supported.
diff --git a/lib/libc/sys/mlockall.2 b/lib/libc/sys/mlockall.2
new file mode 100644
index 000000000000..23c644a8493f
--- /dev/null
+++ b/lib/libc/sys/mlockall.2
@@ -0,0 +1,146 @@
+.\" $NetBSD: mlockall.2,v 1.11 2003/04/16 13:34:54 wiz Exp $
+.\"
+.\" Copyright (c) 1999 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+.\" NASA Ames Research Center.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd December 25, 2012
+.Dt MLOCKALL 2
+.Os
+.Sh NAME
+.Nm mlockall ,
+.Nm munlockall
+.Nd lock (unlock) the address space of a process
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/mman.h
+.Ft int
+.Fn mlockall "int flags"
+.Ft int
+.Fn munlockall "void"
+.Sh DESCRIPTION
+The
+.Fn mlockall
+system call locks into memory the physical pages associated with the
+address space of a process until the address space is unlocked, the
+process exits, or execs another program image.
+.Pp
+The following flags affect the behavior of
+.Fn mlockall :
+.Bl -tag -width ".Dv MCL_CURRENT"
+.It Dv MCL_CURRENT
+Lock all pages currently mapped into the process's address space.
+.It Dv MCL_FUTURE
+Lock all pages mapped into the process's address space in the future,
+at the time the mapping is established.
+Note that this may cause future mappings to fail if those mappings
+cause resource limits to be exceeded.
+.El
+.Pp
+Since physical memory is a potentially scarce resource, processes are
+limited in how much they can lock down.
+A single process can lock the minimum of a system-wide
+.Dq wired pages
+limit
+.Va vm.max_wired
+and the per-process
+.Dv RLIMIT_MEMLOCK
+resource limit.
+.Pp
+If
+.Va security.bsd.unprivileged_mlock
+is set to 0 these calls are only available to the super-user.
+If
+.Va vm.old_mlock
+is set to 1 the per-process
+.Dv RLIMIT_MEMLOCK
+resource limit will not be applied for
+.Fn mlockall
+calls.
+.Pp
+The
+.Fn munlockall
+call unlocks any locked memory regions in the process address space.
+Any regions mapped after an
+.Fn munlockall
+call will not be locked.
+.Sh RETURN VALUES
+A return value of 0 indicates that the call
+succeeded and all pages in the range have either been locked or unlocked.
+A return value of \-1 indicates an error occurred and the locked
+status of all pages in the range remains unchanged.
+In this case, the global location
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+.Fn mlockall
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa flags
+argument is zero, or includes unimplemented flags.
+.It Bq Er ENOMEM
+Locking the indicated range would exceed either the system or per-process
+limit for locked memory.
+.It Bq Er EAGAIN
+Some or all of the memory mapped into the process's address space
+could not be locked when the call was made.
+.It Bq Er EPERM
+The calling process does not have the appropriate privilege to perform
+the requested operation.
+.El
+.Sh SEE ALSO
+.Xr mincore 2 ,
+.Xr mlock 2 ,
+.Xr mmap 2 ,
+.Xr munmap 2 ,
+.Xr setrlimit 2
+.Sh STANDARDS
+The
+.Fn mlockall
+and
+.Fn munlockall
+functions are believed to conform to
+.St -p1003.1-2001 .
+.Sh HISTORY
+The
+.Fn mlockall
+and
+.Fn munlockall
+functions first appeared in
+.Fx 5.1 .
+.Sh BUGS
+The per-process resource limit is a limit on the amount of virtual
+memory locked, while the system-wide limit is for the number of locked
+physical pages.
+Hence a process with two distinct locked mappings of the same physical page
+counts as 2 pages against the per-process limit and as only a single page
+in the system limit.
diff --git a/lib/libc/sys/mmap.2 b/lib/libc/sys/mmap.2
new file mode 100644
index 000000000000..82418bdbaeda
--- /dev/null
+++ b/lib/libc/sys/mmap.2
@@ -0,0 +1,452 @@
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)mmap.2 8.4 (Berkeley) 5/11/95
+.\" $FreeBSD$
+.\"
+.Dd November 25, 2016
+.Dt MMAP 2
+.Os
+.Sh NAME
+.Nm mmap
+.Nd allocate memory, or map files or devices into memory
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/mman.h
+.Ft void *
+.Fn mmap "void *addr" "size_t len" "int prot" "int flags" "int fd" "off_t offset"
+.Sh DESCRIPTION
+The
+.Fn mmap
+system call causes the pages starting at
+.Fa addr
+and continuing for at most
+.Fa len
+bytes to be mapped from the object described by
+.Fa fd ,
+starting at byte offset
+.Fa offset .
+If
+.Fa len
+is not a multiple of the pagesize, the mapped region may extend past the
+specified range.
+Any such extension beyond the end of the mapped object will be zero-filled.
+.Pp
+If
+.Fa addr
+is non-zero, it is used as a hint to the system.
+(As a convenience to the system, the actual address of the region may differ
+from the address supplied.)
+If
+.Fa addr
+is zero, an address will be selected by the system.
+The actual starting address of the region is returned.
+A successful
+.Fa mmap
+deletes any previous mapping in the allocated address range.
+.Pp
+The protections (region accessibility) are specified in the
+.Fa prot
+argument by
+.Em or Ns 'ing
+the following values:
+.Pp
+.Bl -tag -width PROT_WRITE -compact
+.It Dv PROT_NONE
+Pages may not be accessed.
+.It Dv PROT_READ
+Pages may be read.
+.It Dv PROT_WRITE
+Pages may be written.
+.It Dv PROT_EXEC
+Pages may be executed.
+.El
+.Pp
+The
+.Fa flags
+argument specifies the type of the mapped object, mapping options and
+whether modifications made to the mapped copy of the page are private
+to the process or are to be shared with other references.
+Sharing, mapping type and options are specified in the
+.Fa flags
+argument by
+.Em or Ns 'ing
+the following values:
+.Bl -tag -width MAP_PREFAULT_READ
+.It Dv MAP_32BIT
+Request a region in the first 2GB of the current process's address space.
+If a suitable region cannot be found,
+.Fn mmap
+will fail.
+This flag is only available on 64-bit platforms.
+.It Dv MAP_ALIGNED Ns Pq Fa n
+Align the region on a requested boundary.
+If a suitable region cannot be found,
+.Fn mmap
+will fail.
+The
+.Fa n
+argument specifies the binary logarithm of the desired alignment.
+.It Dv MAP_ALIGNED_SUPER
+Align the region to maximize the potential use of large
+.Pq Dq super
+pages.
+If a suitable region cannot be found,
+.Fn mmap
+will fail.
+The system will choose a suitable page size based on the size of
+mapping.
+The page size used as well as the alignment of the region may both be
+affected by properties of the file being mapped.
+In particular,
+the physical address of existing pages of a file may require a specific
+alignment.
+The region is not guaranteed to be aligned on any specific boundary.
+.It Dv MAP_ANON
+Map anonymous memory not associated with any specific file.
+The file descriptor used for creating
+.Dv MAP_ANON
+must be \-1.
+The
+.Fa offset
+argument must be 0.
+.\".It Dv MAP_FILE
+.\"Mapped from a regular file or character-special device memory.
+.It Dv MAP_ANONYMOUS
+This flag is identical to
+.Dv MAP_ANON
+and is provided for compatibility.
+.It Dv MAP_EXCL
+This flag can only be used in combination with
+.Dv MAP_FIXED .
+Please see the definition of
+.Dv MAP_FIXED
+for the description of its effect.
+.It Dv MAP_FIXED
+Do not permit the system to select a different address than the one
+specified.
+If the specified address cannot be used,
+.Fn mmap
+will fail.
+If
+.Dv MAP_FIXED
+is specified,
+.Fa addr
+must be a multiple of the pagesize.
+If
+.Dv MAP_EXCL
+is not specified, a successful
+.Dv MAP_FIXED
+request replaces any previous mappings for the process'
+pages in the range from
+.Fa addr
+to
+.Fa addr
++
+.Fa len .
+In contrast, if
+.Dv MAP_EXCL
+is specified, the request will fail if a mapping
+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_NOCORE
+Region is not included in a core file.
+.It Dv MAP_NOSYNC
+Causes data dirtied via this VM map to be flushed to physical media
+only when necessary (usually by the pager) rather than gratuitously.
+Typically this prevents the update daemons from flushing pages dirtied
+through such maps and thus allows efficient sharing of memory across
+unassociated processes using a file-backed shared memory map.
+Without
+this option any VM pages you dirty may be flushed to disk every so often
+(every 30-60 seconds usually) which can create performance problems if you
+do not need that to occur (such as when you are using shared file-backed
+mmap regions for IPC purposes).
+Dirty data will be flushed automatically when all mappings of an object are
+removed and all descriptors referencing the object are closed.
+Note that VM/file system coherency is
+maintained whether you use
+.Dv MAP_NOSYNC
+or not.
+This option is not portable
+across
+.Ux
+platforms (yet), though some may implement the same behavior
+by default.
+.Pp
+.Em WARNING !
+Extending a file with
+.Xr ftruncate 2 ,
+thus creating a big hole, and then filling the hole by modifying a shared
+.Fn mmap
+can lead to severe file fragmentation.
+In order to avoid such fragmentation you should always pre-allocate the
+file's backing store by
+.Fn write Ns ing
+zero's into the newly extended area prior to modifying the area via your
+.Fn mmap .
+The fragmentation problem is especially sensitive to
+.Dv MAP_NOSYNC
+pages, because pages may be flushed to disk in a totally random order.
+.Pp
+The same applies when using
+.Dv MAP_NOSYNC
+to implement a file-based shared memory store.
+It is recommended that you create the backing store by
+.Fn write Ns ing
+zero's to the backing file rather than
+.Fn ftruncate Ns ing
+it.
+You can test file fragmentation by observing the KB/t (kilobytes per
+transfer) results from an
+.Dq Li iostat 1
+while reading a large file sequentially, e.g.,\& using
+.Dq Li dd if=filename of=/dev/null bs=32k .
+.Pp
+The
+.Xr fsync 2
+system call will flush all dirty data and metadata associated with a file,
+including dirty NOSYNC VM data, to physical media.
+The
+.Xr sync 8
+command and
+.Xr sync 2
+system call generally do not flush dirty NOSYNC VM data.
+The
+.Xr msync 2
+system call is usually not needed since
+.Bx
+implements a coherent file system buffer cache.
+However, it may be
+used to associate dirty VM pages with file system buffers and thus cause
+them to be flushed to physical media sooner rather than later.
+.It Dv MAP_PREFAULT_READ
+Immediately update the calling process's lowest-level virtual address
+translation structures, such as its page table, so that every memory
+resident page within the region is mapped for read access.
+Ordinarily these structures are updated lazily.
+The effect of this option is to eliminate any soft faults that would
+otherwise occur on the initial read accesses to the region.
+Although this option does not preclude
+.Fa prot
+from including
+.Dv PROT_WRITE ,
+it does not eliminate soft faults on the initial write accesses to the
+region.
+.It Dv MAP_PRIVATE
+Modifications are private.
+.It Dv MAP_SHARED
+Modifications are shared.
+.It Dv MAP_STACK
+.Dv MAP_STACK
+implies
+.Dv MAP_ANON ,
+and
+.Fa offset
+of 0.
+The
+.Fa fd
+argument
+must be -1 and
+.Fa prot
+must include at least
+.Dv PROT_READ
+and
+.Dv PROT_WRITE .
+This option creates
+a memory region that grows to at most
+.Fa len
+bytes in size, starting from the stack top and growing down.
+The
+stack top is the starting address returned by the call, plus
+.Fa len
+bytes.
+The bottom of the stack at maximum growth is the starting
+address returned by the call.
+.El
+.Pp
+The
+.Xr close 2
+system call does not unmap pages, see
+.Xr munmap 2
+for further information.
+.Sh NOTES
+Although this implementation does not impose any alignment restrictions on
+the
+.Fa offset
+argument, a portable program must only use page-aligned values.
+.Pp
+Large page mappings require that the pages backing an object be
+aligned in matching blocks in both the virtual address space and RAM.
+The system will automatically attempt to use large page mappings when
+mapping an object that is already backed by large pages in RAM by
+aligning the mapping request in the virtual address space to match the
+alignment of the large physical pages.
+The system may also use large page mappings when mapping portions of an
+object that are not yet backed by pages in RAM.
+The
+.Dv MAP_ALIGNED_SUPER
+flag is an optimization that will align the mapping request to the
+size of a large page similar to
+.Dv MAP_ALIGNED ,
+except that the system will override this alignment if an object already
+uses large pages so that the mapping will be consistent with the existing
+large pages.
+This flag is mostly useful for maximizing the use of large pages on the
+first mapping of objects that do not yet have pages present in RAM.
+.Sh RETURN VALUES
+Upon successful completion,
+.Fn mmap
+returns a pointer to the mapped region.
+Otherwise, a value of
+.Dv MAP_FAILED
+is returned and
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+The
+.Fn mmap
+system call
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EACCES
+The flag
+.Dv PROT_READ
+was specified as part of the
+.Fa prot
+argument and
+.Fa fd
+was not open for reading.
+The flags
+.Dv MAP_SHARED
+and
+.Dv PROT_WRITE
+were specified as part of the
+.Fa flags
+and
+.Fa prot
+argument and
+.Fa fd
+was not open for writing.
+.It Bq Er EBADF
+The
+.Fa fd
+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
+argument was not page aligned, or part of the desired address space
+resides out of the valid address space for a user process.
+.It Bq Er EINVAL
+Both
+.Dv MAP_FIXED
+and
+.Dv MAP_32BIT
+were specified and part of the desired address space resides outside
+of the first 2GB of user address space.
+.It Bq Er EINVAL
+The
+.Fa len
+argument
+was equal to zero.
+.It Bq Er EINVAL
+.Dv MAP_ALIGNED
+was specified and the desired alignment was either larger than the
+virtual address size of the machine or smaller than a page.
+.It Bq Er EINVAL
+.Dv MAP_ANON
+was specified and the
+.Fa fd
+argument was not -1.
+.It Bq Er EINVAL
+.Dv MAP_ANON
+was specified and the
+.Fa offset
+argument was not 0.
+.It Bq Er EINVAL
+Both
+.Dv MAP_FIXED
+and
+.Dv MAP_EXCL
+were specified, but the requested region is already used by a mapping.
+.It Bq Er EINVAL
+.Dv MAP_EXCL
+was specified, but
+.Dv MAP_FIXED
+was not.
+.It Bq Er ENODEV
+.Dv MAP_ANON
+has not been specified and
+.Fa fd
+did not reference a regular or character special file.
+.It Bq Er ENOMEM
+.Dv MAP_FIXED
+was specified and the
+.Fa addr
+argument was not available.
+.Dv MAP_ANON
+was specified and insufficient memory was available.
+.El
+.Sh SEE ALSO
+.Xr madvise 2 ,
+.Xr mincore 2 ,
+.Xr minherit 2 ,
+.Xr mlock 2 ,
+.Xr mprotect 2 ,
+.Xr msync 2 ,
+.Xr munlock 2 ,
+.Xr munmap 2 ,
+.Xr getpagesize 3 ,
+.Xr getpagesizes 3
diff --git a/lib/libc/sys/modfind.2 b/lib/libc/sys/modfind.2
new file mode 100644
index 000000000000..38d09c4ee9f3
--- /dev/null
+++ b/lib/libc/sys/modfind.2
@@ -0,0 +1,86 @@
+.\"
+.\" Copyright (c) 1999 Chris Costello
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 September 28, 2000
+.Dt MODFIND 2
+.Os
+.Sh NAME
+.Nm modfind
+.Nd returns the modid of a kernel module
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/param.h
+.In sys/module.h
+.Ft int
+.Fn modfind "const char *modname"
+.Sh DESCRIPTION
+The
+.Fn modfind
+system call
+returns the modid of the kernel module referenced by
+.Fa modname .
+.Sh RETURN VALUES
+The
+.Fn modfind
+system call
+returns the modid of the kernel module referenced by
+.Fa modname .
+Upon error,
+.Fn modfind
+returns -1 and sets
+.Va errno
+to indicate the error.
+.Sh ERRORS
+.Va errno
+is set to the following if
+.Fn modfind
+fails:
+.Bl -tag -width Er
+.It Bq Er EFAULT
+The data required for this operation could not be read from the kernel space.
+.It Bq Er ENOENT
+The file specified is not loaded in the kernel.
+.El
+.Sh SEE ALSO
+.Xr kldfind 2 ,
+.Xr kldfirstmod 2 ,
+.Xr kldload 2 ,
+.Xr kldnext 2 ,
+.Xr kldstat 2 ,
+.Xr kldsym 2 ,
+.Xr kldunload 2 ,
+.Xr modfnext 2 ,
+.Xr modnext 2 ,
+.Xr modstat 2 ,
+.Xr kld 4 ,
+.Xr kldstat 8
+.Sh HISTORY
+The
+.Nm kld
+interface first appeared in
+.Fx 3.0 .
diff --git a/lib/libc/sys/modnext.2 b/lib/libc/sys/modnext.2
new file mode 100644
index 000000000000..c0c0a0d3a223
--- /dev/null
+++ b/lib/libc/sys/modnext.2
@@ -0,0 +1,97 @@
+.\"
+.\" Copyright (c) 1999 Chris Costello
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 September 28, 2000
+.Dt MODNEXT 2
+.Os
+.Sh NAME
+.Nm modnext
+.Nd return the modid of the next kernel module
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/param.h
+.In sys/module.h
+.Ft int
+.Fn modnext "int modid"
+.Ft int
+.Fn modfnext "int modid"
+.Sh DESCRIPTION
+The
+.Fn modnext
+system call
+returns the modid of the next kernel module (that is, the one after
+.Va modid )
+or 0 if
+.Va modid
+is the last module in the list.
+.Pp
+If the
+.Va modid
+value is 0, then
+.Fn modnext
+will return the modid of the first module.
+The
+.Fn modfnext
+system call
+must always be given a valid modid.
+.Sh RETURN VALUES
+The
+.Fn modnext
+system call
+returns the modid of the next module (see
+.Sx DESCRIPTION )
+or 0.
+If an error
+occurs,
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+The only error set by
+.Fn modnext
+is
+.Er ENOENT ,
+which is set when
+.Va modid
+refers to a kernel module that does not exist (is not loaded).
+.Sh SEE ALSO
+.Xr kldfind 2 ,
+.Xr kldfirstmod 2 ,
+.Xr kldload 2 ,
+.Xr kldnext 2 ,
+.Xr kldstat 2 ,
+.Xr kldsym 2 ,
+.Xr kldunload 2 ,
+.Xr modfind 2 ,
+.Xr modstat 2 ,
+.Xr kld 4 ,
+.Xr kldstat 8
+.Sh HISTORY
+The
+.Nm kld
+interface first appeared in
+.Fx 3.0 .
diff --git a/lib/libc/sys/modstat.2 b/lib/libc/sys/modstat.2
new file mode 100644
index 000000000000..5f106b4b1af3
--- /dev/null
+++ b/lib/libc/sys/modstat.2
@@ -0,0 +1,127 @@
+.\"
+.\" Copyright (c) 1999 Chris Costello
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 July 15, 2008
+.Dt MODSTAT 2
+.Os
+.Sh NAME
+.Nm modstat
+.Nd get status of kernel module
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/param.h
+.In sys/module.h
+.Ft int
+.Fn modstat "int modid" "struct module_stat *stat"
+.Sh DESCRIPTION
+The
+.Fn modstat
+system call writes the info for the kernel module referred to by
+.Fa modid
+into
+.Fa stat .
+.Bd -literal
+struct module_stat {
+ int version; /* set to sizeof(module_stat) */
+ char name[MAXMODNAME];
+ int refs;
+ int id;
+ modspecific_t data;
+};
+typedef union modspecific {
+ int intval;
+ u_int uintval;
+ long longval;
+ u_long ulongval;
+} modspecific_t;
+.Ed
+.Bl -tag -width XXXaddress
+.It version
+This field is set to the size of the structure mentioned above by the code
+calling
+.Fn modstat ,
+and not
+.Fn modstat
+itself.
+.It name
+The name of the module referred to by
+.Fa modid .
+.It refs
+The number of modules referenced by
+.Fa modid .
+.It id
+The id of the module specified in
+.Fa modid .
+.It data
+Module specific data.
+.El
+.Sh RETURN VALUES
+.Rv -std modstat
+.Sh ERRORS
+The information for the module referred to by
+.Fa modid
+is filled into the structure pointed to by
+.Fa stat
+unless:
+.Bl -tag -width Er
+.It Bq Er ENOENT
+The module was not found (probably not loaded).
+.It Bq Er EINVAL
+The version specified in the
+.Fa version
+field of stat is not the proper version.
+You would need to rebuild world, the
+kernel, or your application, if this error occurs, given that you did properly
+fill in the
+.Fa version
+field.
+.It Bq Er EFAULT
+There was a problem copying one, some, or all of the fields into
+.Fa stat
+in the
+.Xr copyout 9
+function.
+.El
+.Sh SEE ALSO
+.Xr kldfind 2 ,
+.Xr kldfirstmod 2 ,
+.Xr kldload 2 ,
+.Xr kldnext 2 ,
+.Xr kldstat 2 ,
+.Xr kldsym 2 ,
+.Xr kldunload 2 ,
+.Xr modfind 2 ,
+.Xr modfnext 2 ,
+.Xr modnext 2 ,
+.Xr kld 4 ,
+.Xr kldstat 8
+.Sh HISTORY
+The
+.Nm kld
+interface first appeared in
+.Fx 3.0 .
diff --git a/lib/libc/sys/mount.2 b/lib/libc/sys/mount.2
new file mode 100644
index 000000000000..881d830967aa
--- /dev/null
+++ b/lib/libc/sys/mount.2
@@ -0,0 +1,378 @@
+.\" Copyright (c) 1980, 1989, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)mount.2 8.3 (Berkeley) 5/24/95
+.\" $FreeBSD$
+.\"
+.Dd April 13, 2015
+.Dt MOUNT 2
+.Os
+.Sh NAME
+.Nm mount ,
+.Nm nmount ,
+.Nm unmount
+.Nd mount or dismount a file system
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/param.h
+.In sys/mount.h
+.Ft int
+.Fn mount "const char *type" "const char *dir" "int flags" "void *data"
+.Ft int
+.Fn unmount "const char *dir" "int flags"
+.In sys/uio.h
+.Ft int
+.Fn nmount "struct iovec *iov" "u_int niov" "int flags"
+.Sh DESCRIPTION
+The
+.Fn mount
+system call grafts
+a file system object onto the system file tree
+at the point
+.Fa dir .
+The argument
+.Fa data
+describes the file system object to be mounted.
+The argument
+.Fa type
+tells the kernel how to interpret
+.Fa data
+(See
+.Fa type
+below).
+The contents of the file system
+become available through the new mount point
+.Fa dir .
+Any files in
+.Fa dir
+at the time
+of a successful mount are swept under the carpet so to speak, and
+are unavailable until the file system is unmounted.
+.Pp
+The
+.Fn nmount
+system call behaves similarly to
+.Fn mount ,
+except that the mount options (file system type name, device to mount,
+mount-point name, etc.) are passed as an array of name-value pairs
+in the array
+.Fa iov ,
+containing
+.Fa niov
+elements.
+The following options are required by all file systems:
+.Bl -column fstype -offset indent
+.It
+.Li fstype Ta file system type name (e.g., Dq Li procfs )
+.It
+.Li fspath Ta mount point pathname (e.g., Dq Li /proc )
+.El
+.Pp
+Depending on the file system type, other options may be
+recognized or required;
+for example, most disk-based file systems require a
+.Dq Li from
+option containing the pathname of a special device
+in addition to the options listed above.
+.Pp
+By default only the super-user may call the
+.Fn mount
+system call.
+This restriction can be removed by setting the
+.Va vfs.usermount
+.Xr sysctl 8
+variable
+to a non-zero value; see the BUGS section for more information.
+.Pp
+The following
+.Fa flags
+may be specified to
+suppress default semantics which affect file system access.
+.Bl -tag -width MNT_SYNCHRONOUS
+.It Dv MNT_RDONLY
+The file system should be treated as read-only;
+even the super-user may not write on it.
+Specifying MNT_UPDATE without this option will upgrade
+a read-only file system to read/write.
+.It Dv MNT_NOEXEC
+Do not allow files to be executed from the file system.
+.It Dv MNT_NOSUID
+Do not honor setuid or setgid bits on files when executing them.
+This flag is set automatically when the caller is not the super-user.
+.It Dv MNT_NOATIME
+Disable update of file access times.
+.It Dv MNT_SNAPSHOT
+Create a snapshot of the file system.
+This is currently only supported on UFS2 file systems, see
+.Xr mksnap_ffs 8
+for more information.
+.It Dv MNT_SUIDDIR
+Directories with the SUID bit set chown new files to their own owner.
+This flag requires the SUIDDIR option to have been compiled into the kernel
+to have any effect.
+See the
+.Xr mount 8
+and
+.Xr chmod 2
+pages for more information.
+.It Dv MNT_SYNCHRONOUS
+All I/O to the file system should be done synchronously.
+.It Dv MNT_ASYNC
+All I/O to the file system should be done asynchronously.
+.It Dv MNT_FORCE
+Force a read-write mount even if the file system appears to be unclean.
+Dangerous.
+Together with
+.Dv MNT_UPDATE
+and
+.Dv MNT_RDONLY ,
+specify that the file system is to be forcibly downgraded to a read-only
+mount even if some files are open for writing.
+.It Dv MNT_NOCLUSTERR
+Disable read clustering.
+.It Dv MNT_NOCLUSTERW
+Disable write clustering.
+.El
+.Pp
+The flag
+.Dv MNT_UPDATE
+indicates that the mount command is being applied
+to an already mounted file system.
+This allows the mount flags to be changed without requiring
+that the file system be unmounted and remounted.
+Some file systems may not allow all flags to be changed.
+For example,
+many file systems will not allow a change from read-write to read-only.
+.Pp
+The flag
+.Dv MNT_RELOAD
+causes the vfs subsystem to update its data structures pertaining to
+the specified already mounted file system.
+.Pp
+The
+.Fa type
+argument names the file system.
+The types of file systems known to the system can be obtained with
+.Xr lsvfs 1 .
+.Pp
+The
+.Fa data
+argument
+is a pointer to a structure that contains the type
+specific arguments to mount.
+The format for these argument structures is described in the
+manual page for each file system.
+By convention file system manual pages are named
+by prefixing ``mount_'' to the name of the file system as returned by
+.Xr lsvfs 1 .
+Thus the
+.Tn NFS
+file system is described by the
+.Xr mount_nfs 8
+manual page.
+It should be noted that a manual page for default
+file systems, known as UFS and UFS2, does not exist.
+.Pp
+The
+.Fn unmount
+system call disassociates the file system from the specified
+mount point
+.Fa dir .
+.Pp
+The
+.Fa flags
+argument may include
+.Dv MNT_FORCE
+to specify that the file system should be forcibly unmounted
+even if files are still active.
+Active special devices continue to work,
+but any further accesses to any other active files result in errors
+even if the file system is later remounted.
+.Pp
+If the
+.Dv MNT_BYFSID
+flag is specified,
+.Fa dir
+should instead be a file system ID encoded as
+.Dq Li FSID : Ns Ar val0 : Ns Ar val1 ,
+where
+.Ar val0
+and
+.Ar val1
+are the contents of the
+.Vt fsid_t
+.Va val[]
+array in decimal.
+The file system that has the specified file system ID will be unmounted.
+.Sh RETURN VALUES
+.Rv -std
+.Sh ERRORS
+The
+.Fn mount
+and
+.Fn nmount
+system calls will fail when one of the following occurs:
+.Bl -tag -width Er
+.It Bq Er EPERM
+The caller is neither the super-user nor the owner of
+.Fa dir .
+.It Bq Er ENAMETOOLONG
+A component of a pathname exceeded 255 characters,
+or the entire length of a path name exceeded 1023 characters.
+.It Bq Er ELOOP
+Too many symbolic links were encountered in translating a pathname.
+.It Bq Er ENOENT
+A component of
+.Fa dir
+does not exist.
+.It Bq Er ENOTDIR
+A component of
+.Fa name
+is not a directory,
+or a path prefix of
+.Fa special
+is not a directory.
+.It Bq Er EBUSY
+Another process currently holds a reference to
+.Fa dir .
+.It Bq Er EFAULT
+The
+.Fa dir
+argument
+points outside the process's allocated address space.
+.El
+.Pp
+The following errors can occur for a
+.Em ufs
+file system mount:
+.Bl -tag -width Er
+.It Bq Er ENODEV
+A component of ufs_args
+.Fa fspec
+does not exist.
+.It Bq Er ENOTBLK
+The
+.Fa fspec
+argument
+is not a block device.
+.It Bq Er ENXIO
+The major device number of
+.Fa fspec
+is out of range (this indicates no device driver exists
+for the associated hardware).
+.It Bq Er EBUSY
+.Fa fspec
+is already mounted.
+.It Bq Er EMFILE
+No space remains in the mount table.
+.It Bq Er EINVAL
+The super block for the file system had a bad magic
+number or an out of range block size.
+.It Bq Er ENOMEM
+Not enough memory was available to read the cylinder
+group information for the file system.
+.It Bq Er EIO
+An I/O error occurred while reading the super block or
+cylinder group information.
+.It Bq Er EFAULT
+The
+.Fa fspec
+argument
+points outside the process's allocated address space.
+.El
+.Pp
+The following errors can occur for a
+.Em nfs
+file system mount:
+.Bl -tag -width Er
+.It Bq Er ETIMEDOUT
+.Em Nfs
+timed out trying to contact the server.
+.It Bq Er EFAULT
+Some part of the information described by nfs_args
+points outside the process's allocated address space.
+.El
+.Pp
+The
+.Fn unmount
+system call may fail with one of the following errors:
+.Bl -tag -width Er
+.It Bq Er EPERM
+The caller is neither the super-user nor the user who issued the corresponding
+.Fn mount
+call.
+.It Bq Er ENAMETOOLONG
+The length of the path name exceeded 1023 characters.
+.It Bq Er EINVAL
+The requested directory is not in the mount table.
+.It Bq Er ENOENT
+The file system ID specified using
+.Dv MNT_BYFSID
+was not found in the mount table.
+.It Bq Er EINVAL
+The file system ID specified using
+.Dv MNT_BYFSID
+could not be decoded.
+.It Bq Er EINVAL
+The specified file system is the root file system.
+.It Bq Er EBUSY
+A process is holding a reference to a file located
+on the file system.
+.It Bq Er EIO
+An I/O error occurred while writing cached file system information.
+.It Bq Er EFAULT
+The
+.Fa dir
+argument
+points outside the process's allocated address space.
+.El
+.Sh SEE ALSO
+.Xr lsvfs 1 ,
+.Xr mksnap_ffs 8 ,
+.Xr mount 8 ,
+.Xr umount 8
+.Sh HISTORY
+The
+.Fn mount
+and
+.Fn unmount
+functions appeared in
+.At v6 .
+The
+.Fn nmount
+system call first appeared in
+.Fx 5.0 .
+.Sh BUGS
+Some of the error codes need translation to more obvious messages.
+.Pp
+Allowing untrusted users to mount arbitrary media, e.g. by enabling
+.Va vfs.usermount ,
+should not be considered safe.
+Most file systems in
+.Fx
+were not built to safeguard against malicious devices.
diff --git a/lib/libc/sys/mprotect.2 b/lib/libc/sys/mprotect.2
new file mode 100644
index 000000000000..9e12af82a55e
--- /dev/null
+++ b/lib/libc/sys/mprotect.2
@@ -0,0 +1,97 @@
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)mprotect.2 8.1 (Berkeley) 6/9/93
+.\" $FreeBSD$
+.\"
+.Dd August 3, 2016
+.Dt MPROTECT 2
+.Os
+.Sh NAME
+.Nm mprotect
+.Nd control the protection of pages
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/mman.h
+.Ft int
+.Fn mprotect "void *addr" "size_t len" "int prot"
+.Sh DESCRIPTION
+The
+.Fn mprotect
+system call
+changes the specified pages to have protection
+.Fa prot .
+Not all implementations will guarantee protection on a page basis;
+the granularity of protection changes may be as large as an entire region.
+A region is the virtual address space defined by the start
+and end addresses of a
+.Vt "struct vm_map_entry" .
+.Pp
+Currently these protection bits are known,
+which can be combined, OR'd together:
+.Pp
+.Bl -tag -width ".Dv PROT_WRITE" -compact
+.It Dv PROT_NONE
+No permissions at all.
+.It Dv PROT_READ
+The pages can be read.
+.It Dv PROT_WRITE
+The pages can be written.
+.It Dv PROT_EXEC
+The pages can be executed.
+.El
+.Sh RETURN VALUES
+.Rv -std mprotect
+.Sh ERRORS
+The
+.Fn mprotect
+system call will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The virtual address range specified by the
+.Fa addr
+and
+.Fa len
+arguments is not valid.
+.It Bq Er EACCES
+The calling process was not allowed to change
+the protection to the value specified by
+the
+.Fa prot
+argument.
+.El
+.Sh SEE ALSO
+.Xr madvise 2 ,
+.Xr mincore 2 ,
+.Xr msync 2 ,
+.Xr munmap 2
+.Sh HISTORY
+The
+.Fn mprotect
+system call first appeared in
+.Bx 4.4 .
diff --git a/lib/libc/sys/mq_close.2 b/lib/libc/sys/mq_close.2
new file mode 100644
index 000000000000..f9ec06239c48
--- /dev/null
+++ b/lib/libc/sys/mq_close.2
@@ -0,0 +1,105 @@
+.\" Copyright (c) 2005 David Xu <davidxu@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice(s), this list of conditions and the following disclaimer as
+.\" the first lines of this file unmodified other than the possible
+.\" addition of one or more copyright notices.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice(s), this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+.\" EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+.\" OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+.\" EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" Portions of this text are reprinted and reproduced in electronic form
+.\" from IEEE Std 1003.1, 2004 Edition, Standard for Information Technology --
+.\" Portable Operating System Interface (POSIX), The Open Group Base
+.\" Specifications Issue 6, Copyright (C) 2001-2004 by the Institute of
+.\" Electrical and Electronics Engineers, Inc and The Open Group. In the
+.\" event of any discrepancy between this version and the original IEEE and
+.\" The Open Group Standard, the original IEEE and The Open Group Standard is
+.\" the referee document. The original Standard can be obtained online at
+.\" http://www.opengroup.org/unix/online.html.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd November 29, 2005
+.Dt MQ_CLOSE 2
+.Os
+.Sh NAME
+.Nm mq_close
+.Nd "close a message queue (REALTIME)"
+.Sh LIBRARY
+.Lb librt
+.Sh SYNOPSIS
+.In mqueue.h
+.Ft int
+.Fn mq_close "mqd_t mqdes"
+.Sh DESCRIPTION
+The
+.Fn mq_close
+system call removes the association between the message queue descriptor,
+.Fa mqdes ,
+and its message queue.
+The results of using this message queue descriptor
+after successful return from this
+.Fn mq_close ,
+and until the return of this message queue descriptor from a subsequent
+.Fn mq_open ,
+are undefined.
+.Pp
+If the process has successfully attached a notification request to the
+message queue via this
+.Fa mqdes ,
+this attachment will be removed, and the message queue is available for
+another process to attach for notification.
+.Sh RETURN VALUES
+.Rv -std
+.Sh ERRORS
+The
+.Fn mq_close
+system call
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa mqdes
+argument is not a valid message queue descriptor.
+.El
+.Sh SEE ALSO
+.Xr mq_open 2 ,
+.Xr mq_unlink 2
+.Sh STANDARDS
+The
+.Fn mq_close
+system call conforms to
+.St -p1003.1-2004 .
+.Sh HISTORY
+Support for
+.Tn POSIX
+message queues first appeared in
+.Fx 7.0 .
+.Sh COPYRIGHT
+Portions of this text are reprinted and reproduced in electronic form
+from IEEE Std 1003.1, 2004 Edition, Standard for Information Technology --
+Portable Operating System Interface (POSIX), The Open Group Base
+Specifications Issue 6, Copyright (C) 2001-2004 by the Institute of
+Electrical and Electronics Engineers, Inc and The Open Group. In the
+event of any discrepancy between this version and the original IEEE and
+The Open Group Standard, the original IEEE and The Open Group Standard is
+the referee document. The original Standard can be obtained online at
+http://www.opengroup.org/unix/online.html.
diff --git a/lib/libc/sys/mq_getattr.2 b/lib/libc/sys/mq_getattr.2
new file mode 100644
index 000000000000..fc42d5914d04
--- /dev/null
+++ b/lib/libc/sys/mq_getattr.2
@@ -0,0 +1,127 @@
+.\" Copyright (c) 2005 David Xu <davidxu@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice(s), this list of conditions and the following disclaimer as
+.\" the first lines of this file unmodified other than the possible
+.\" addition of one or more copyright notices.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice(s), this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+.\" EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+.\" OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+.\" EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" Portions of this text are reprinted and reproduced in electronic form
+.\" from IEEE Std 1003.1, 2004 Edition, Standard for Information Technology --
+.\" Portable Operating System Interface (POSIX), The Open Group Base
+.\" Specifications Issue 6, Copyright (C) 2001-2004 by the Institute of
+.\" Electrical and Electronics Engineers, Inc and The Open Group. In the
+.\" event of any discrepancy between this version and the original IEEE and
+.\" The Open Group Standard, the original IEEE and The Open Group Standard is
+.\" the referee document. The original Standard can be obtained online at
+.\" http://www.opengroup.org/unix/online.html.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd February 21, 2014
+.Dt MQ_GETATTR 2
+.Os
+.Sh NAME
+.Nm mq_getattr
+.Nd "get message queue attributes (REALTIME)"
+.Sh LIBRARY
+.Lb librt
+.Sh SYNOPSIS
+.In mqueue.h
+.Ft int
+.Fn mq_getattr "mqd_t mqdes" "struct mq_attr *mqstat"
+.Sh DESCRIPTION
+The
+.Fn mq_getattr
+system call obtains status information and attributes of the message queue and
+the open message queue description associated with the message queue
+descriptor.
+.Pp
+The
+.Fa mqdes
+argument specifies a message queue descriptor.
+.Pp
+The results are returned in the
+.Vt mq_attr
+structure referenced by the
+.Fa mqstat
+argument.
+.Pp
+Upon return, the following members will have the values associated with the
+open message queue description as set when the message queue was opened and
+as modified by subsequent
+.Fn mq_setattr
+calls:
+.Va mq_flags .
+.Pp
+The following attributes of the message queue will be returned as set at
+message queue creation:
+.Va mq_maxmsg , mq_msgsize .
+.Pp
+Upon return, the following members within the
+.Vt mq_attr
+structure referenced by the
+.Fa mqstat
+argument will be set to the current state
+of the message queue:
+.Bl -tag -width ".Va mq_curmsgs"
+.It Va mq_curmsgs
+The number of messages currently on the queue.
+.El
+.Sh RETURN VALUES
+.Rv -std
+.Sh ERRORS
+The
+.Fn mq_getattr
+system call
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa mqdes
+argument is not a valid message queue descriptor.
+.El
+.Sh SEE ALSO
+.Xr mq_open 2 ,
+.Xr mq_send 2 ,
+.Xr mq_setattr 2 ,
+.Xr mq_timedsend 2
+.Sh STANDARDS
+The
+.Fn mq_getattr
+system call conforms to
+.St -p1003.1-2004 .
+.Sh HISTORY
+Support for
+.Tn POSIX
+message queues first appeared in
+.Fx 7.0 .
+.Sh COPYRIGHT
+Portions of this text are reprinted and reproduced in electronic form
+from IEEE Std 1003.1, 2004 Edition, Standard for Information Technology --
+Portable Operating System Interface (POSIX), The Open Group Base
+Specifications Issue 6, Copyright (C) 2001-2004 by the Institute of
+Electrical and Electronics Engineers, Inc and The Open Group. In the
+event of any discrepancy between this version and the original IEEE and
+The Open Group Standard, the original IEEE and The Open Group Standard is
+the referee document. The original Standard can be obtained online at
+http://www.opengroup.org/unix/online.html.
diff --git a/lib/libc/sys/mq_notify.2 b/lib/libc/sys/mq_notify.2
new file mode 100644
index 000000000000..4418c60449d9
--- /dev/null
+++ b/lib/libc/sys/mq_notify.2
@@ -0,0 +1,165 @@
+.\" Copyright (c) 2005 David Xu <davidxu@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice(s), this list of conditions and the following disclaimer as
+.\" the first lines of this file unmodified other than the possible
+.\" addition of one or more copyright notices.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice(s), this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+.\" EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+.\" OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+.\" EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" Portions of this text are reprinted and reproduced in electronic form
+.\" from IEEE Std 1003.1, 2004 Edition, Standard for Information Technology --
+.\" Portable Operating System Interface (POSIX), The Open Group Base
+.\" Specifications Issue 6, Copyright (C) 2001-2004 by the Institute of
+.\" Electrical and Electronics Engineers, Inc and The Open Group. In the
+.\" event of any discrepancy between this version and the original IEEE and
+.\" The Open Group Standard, the original IEEE and The Open Group Standard is
+.\" the referee document. The original Standard can be obtained online at
+.\" http://www.opengroup.org/unix/online.html.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd July 15, 2016
+.Dt MQ_NOTIFY 2
+.Os
+.Sh NAME
+.Nm mq_notify
+.Nd "notify process that a message is available (REALTIME)"
+.Sh LIBRARY
+.Lb librt
+.Sh SYNOPSIS
+.In mqueue.h
+.Ft int
+.Fn mq_notify "mqd_t mqdes" "const struct sigevent *notification"
+.Sh DESCRIPTION
+If the argument notification is not
+.Dv NULL ,
+this system call will register the calling process to be notified of message
+arrival at an empty message queue associated with the specified message
+queue descriptor,
+.Fa mqdes .
+The notification specified by the
+.Fa notification
+argument will be sent to
+the process when the message queue transitions from empty to non-empty.
+At any time, only one process may be registered for notification by a
+message queue.
+If the calling process or any other process has already
+registered for notification of message arrival at the specified message
+queue, subsequent attempts to register for that message queue will fail.
+.Pp
+The
+.Fa notification
+argument points to a
+.Vt sigevent
+structure that defines how the calling process will be notified.
+If
+.Fa notification->sigev_notify
+is
+.Dv SIGEV_NONE ,
+then no signal will be posted, but the error status and the return status
+for the operation will be set appropriately.
+For
+.Dv SIGEV_SIGNO
+and
+.Dv SIGEV_THREAD_ID
+notifications,
+the signal specified in
+.Fa notification->sigev_signo
+will be sent to the calling process
+.Pq Dv SIGEV_SIGNO
+or to the thread whose LWP ID is
+.Fa notification->sigev_notify_thread_id
+.Pq Dv SIGEV_THREAD_ID .
+The information for the queued signal will include:
+.Bl -column ".Va si_value"
+.It Sy Member Ta Sy Value
+.It Va si_code Ta Dv SI_MESGQ
+.It Va si_value Ta
+the value stored in
+.Fa notification->sigev_value
+.It Va si_mqd Ta Fa mqdes
+.El
+.Pp
+If
+.Fa notification
+is
+.Dv NULL
+and the process is currently registered for notification by the specified
+message queue, the existing registration will be removed.
+.Pp
+When the notification is sent to the registered process, its registration
+is removed.
+The message queue then is available for registration.
+.Pp
+If a process has registered for notification of message arrival at a
+message queue and some thread is blocked in
+.Fn mq_receive
+waiting to receive a message when a message arrives at the queue, the
+arriving message will satisfy the appropriate
+.Fn mq_receive .
+The resulting behavior is as if the message queue remains empty, and no
+notification will be sent.
+.Sh RETURN VALUES
+.Rv -std
+.Sh ERRORS
+The
+.Fn mq_notify
+system call
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa mqdes
+argument is not a valid message queue descriptor.
+.It Bq Er EBUSY
+Process is already registered for notification by the message queue.
+.It Bq Er EINVAL
+The asynchronous notification method in
+.Fa notification->sigev_notify
+is invalid or not supported.
+.El
+.Sh SEE ALSO
+.Xr mq_open 2 ,
+.Xr mq_send 2 ,
+.Xr mq_timedsend 2 ,
+.Xr sigevent 3 ,
+.Xr siginfo 3
+.Sh STANDARDS
+The
+.Fn mq_notify
+system call conforms to
+.St -p1003.1-2004 .
+.Sh HISTORY
+Support for
+.Tn POSIX
+message queues first appeared in
+.Fx 7.0 .
+.Sh COPYRIGHT
+Portions of this text are reprinted and reproduced in electronic form
+from IEEE Std 1003.1, 2004 Edition, Standard for Information Technology --
+Portable Operating System Interface (POSIX), The Open Group Base
+Specifications Issue 6, Copyright (C) 2001-2004 by the Institute of
+Electrical and Electronics Engineers, Inc and The Open Group. In the
+event of any discrepancy between this version and the original IEEE and
+The Open Group Standard, the original IEEE and The Open Group Standard is
+the referee document. The original Standard can be obtained online at
+http://www.opengroup.org/unix/online.html.
diff --git a/lib/libc/sys/mq_open.2 b/lib/libc/sys/mq_open.2
new file mode 100644
index 000000000000..ef6154b7ff5a
--- /dev/null
+++ b/lib/libc/sys/mq_open.2
@@ -0,0 +1,329 @@
+.\" Copyright (c) 2005 David Xu <davidxu@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice(s), this list of conditions and the following disclaimer as
+.\" the first lines of this file unmodified other than the possible
+.\" addition of one or more copyright notices.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice(s), this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+.\" EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+.\" OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+.\" EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" Portions of this text are reprinted and reproduced in electronic form
+.\" from IEEE Std 1003.1, 2004 Edition, Standard for Information Technology --
+.\" Portable Operating System Interface (POSIX), The Open Group Base
+.\" Specifications Issue 6, Copyright (C) 2001-2004 by the Institute of
+.\" Electrical and Electronics Engineers, Inc and The Open Group. In the
+.\" event of any discrepancy between this version and the original IEEE and
+.\" The Open Group Standard, the original IEEE and The Open Group Standard is
+.\" the referee document. The original Standard can be obtained online at
+.\" http://www.opengroup.org/unix/online.html.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd September 15, 2014
+.Dt MQ_OPEN 2
+.Os
+.Sh NAME
+.Nm mq_open
+.Nd "open a message queue (REALTIME)"
+.Sh LIBRARY
+.Lb librt
+.Sh SYNOPSIS
+.In mqueue.h
+.Ft mqd_t
+.Fn mq_open "const char *name" "int oflag" "..."
+.Sh DESCRIPTION
+The
+.Fn mq_open
+system call establishes the connection between a process and a message queue
+with a message queue descriptor.
+It creates an open message queue
+description that refers to the message queue, and a message queue descriptor
+that refers to that open message queue description.
+The message queue
+descriptor is used by other functions to refer to that message queue.
+The
+.Fa name
+argument points to a string naming a message queue.
+The
+.Fa name
+argument should conform to the construction rules for a pathname.
+The
+.Fa name
+should begin with a slash character.
+Processes calling
+.Fn mq_open
+with the same value of
+.Fa name
+refers to the same message queue object, as long as that name has not been
+removed.
+If the
+.Fa name
+argument is not the name of an existing message queue and creation is not
+requested,
+.Fn mq_open
+will fail and return an error.
+.Pp
+The
+.Fa oflag
+argument requests the desired receive and/or send access to the message
+queue.
+The requested access permission to receive messages or send messages
+would be granted if the calling process would be granted read or write access,
+respectively, to an equivalently protected file.
+.Pp
+The value of
+.Fa oflag
+is the bitwise-inclusive OR of values from the following list.
+Applications should specify exactly one of the first three values (access
+modes) below in the value of
+.Fa oflag :
+.Bl -tag -width ".Dv O_NONBLOCK"
+.It Dv O_RDONLY
+Open the message queue for receiving messages.
+The process can use the
+returned message queue descriptor with
+.Fn mq_receive ,
+but not
+.Fn mq_send .
+A message queue may be open multiple times in the same or different processes
+for receiving messages.
+.It Dv O_WRONLY
+Open the queue for sending messages.
+The process can use the returned
+message queue descriptor with
+.Fn mq_send
+but not
+.Fn mq_receive .
+A message queue may be open multiple times in the same or different processes
+for sending messages.
+.It Dv O_RDWR
+Open the queue for both receiving and sending messages.
+The process can use
+any of the functions allowed for
+.Dv O_RDONLY
+and
+.Dv O_WRONLY .
+A message queue may be open multiple times in the same or different processes
+for sending messages.
+.El
+.Pp
+Any combination of the remaining flags may be specified in the value of
+.Fa oflag :
+.Bl -tag -width ".Dv O_NONBLOCK"
+.It Dv O_CREAT
+Create a message queue.
+It requires two additional arguments:
+.Fa mode ,
+which is of type
+.Vt mode_t ,
+and
+.Fa attr ,
+which is a pointer to an
+.Vt mq_attr
+structure.
+If the pathname
+.Fa name
+has already been used to create a message queue that still exists, then
+this flag has no effect, except as noted under
+.Dv O_EXCL .
+Otherwise, a message queue will be created without any messages
+in it.
+The user ID of the message queue will be set to the effective user ID
+of the process, and the group ID of the message queue will be set to the
+effective group ID of the process.
+The permission bits of the message queue
+will be set to the value of the
+.Fa mode
+argument, except those set in the file mode creation mask of the process.
+When bits in
+.Fa mode
+other than the file permission bits are specified, the effect is
+unspecified.
+If
+.Fa attr
+is
+.Dv NULL ,
+the message queue is created with implementation-defined default message
+queue attributes.
+If attr is
+.Pf non- Dv NULL
+and the calling process has the
+appropriate privilege on name, the message queue
+.Va mq_maxmsg
+and
+.Va mq_msgsize
+attributes will be set to the values of the corresponding members in the
+.Vt mq_attr
+structure referred to by
+.Fa attr .
+If
+.Fa attr
+is
+.Pf non- Dv NULL ,
+but the calling process does not have the appropriate privilege
+on name, the
+.Fn mq_open
+function will fail and return an error without creating the message queue.
+.It Dv O_EXCL
+If
+.Dv O_EXCL
+and
+.Dv O_CREAT
+are set,
+.Fn mq_open
+will fail if the message queue name exists.
+.It Dv O_NONBLOCK
+Determines whether an
+.Fn mq_send
+or
+.Fn mq_receive
+waits for resources or messages that are not currently available, or fails
+with
+.Va errno
+set to
+.Er EAGAIN ;
+see
+.Xr mq_send 2
+and
+.Xr mq_receive 2
+for details.
+.El
+.Pp
+The
+.Fn mq_open
+system call does not add or remove messages from the queue.
+.Sh NOTES
+.Fx
+implements message queue based on file descriptor.
+The descriptor
+is inherited by child after
+.Xr fork 2 .
+The descriptor is closed in a new image after
+.Xr exec 3 .
+The
+.Xr select 2
+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
+.Po Vt mqd_t Pc Ns \-1
+and sets the global variable
+.Va errno
+to indicate the error.
+.Sh ERRORS
+The
+.Fn mq_open
+system call
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EACCES
+The message queue exists and the permissions specified by
+.Fa oflag
+are denied, or the message queue does not exist and permission to create the
+message queue is denied.
+.It Bq Er EEXIST
+.Dv O_CREAT
+and
+.Dv O_EXCL
+are set and the named message queue already exists.
+.It Bq Er EINTR
+The
+.Fn mq_open
+function was interrupted by a signal.
+.It Bq Er EINVAL
+The
+.Fn mq_open
+function is not supported for the given name.
+.It Bq Er EINVAL
+.Dv O_CREAT
+was specified in
+.Fa oflag ,
+the value of
+.Fa attr
+is not
+.Dv NULL ,
+and either
+.Va mq_maxmsg
+or
+.Va mq_msgsize
+was less than or equal to zero.
+.It Bq Er EMFILE
+Too many message queue descriptors or file descriptors are currently in use
+by this process.
+.It Bq Er ENAMETOOLONG
+The length of the
+.Fa name
+argument exceeds
+.Brq Dv PATH_MAX
+or a pathname component
+is longer than
+.Brq Dv NAME_MAX .
+.It Bq Er ENFILE
+Too many message queues are currently open in the system.
+.It Bq Er ENOENT
+.Dv O_CREAT
+is not set and the named message queue does not exist.
+.It Bq Er ENOSPC
+There is insufficient space for the creation of the new message queue.
+.El
+.Sh SEE ALSO
+.Xr mq_close 2 ,
+.Xr mq_getattr 2 ,
+.Xr mq_receive 2 ,
+.Xr mq_send 2 ,
+.Xr mq_setattr 2 ,
+.Xr mq_timedreceive 3 ,
+.Xr mq_timedsend 3 ,
+.Xr mq_unlink 3 ,
+.Xr mqueuefs 5
+.Sh STANDARDS
+The
+.Fn mq_open
+system call conforms to
+.St -p1003.1-2004 .
+.Sh HISTORY
+Support for
+.Tn POSIX
+message queues first appeared in
+.Fx 7.0 .
+.Sh BUGS
+This implementation places strict requirements on the value of
+.Fa name :
+it must begin with a slash
+.Pq Ql /
+and contain no other slash characters.
+.Sh COPYRIGHT
+Portions of this text are reprinted and reproduced in electronic form
+from IEEE Std 1003.1, 2004 Edition, Standard for Information Technology --
+Portable Operating System Interface (POSIX), The Open Group Base
+Specifications Issue 6, Copyright (C) 2001-2004 by the Institute of
+Electrical and Electronics Engineers, Inc and The Open Group. In the
+event of any discrepancy between this version and the original IEEE and
+The Open Group Standard, the original IEEE and The Open Group Standard is
+the referee document. The original Standard can be obtained online at
+http://www.opengroup.org/unix/online.html.
diff --git a/lib/libc/sys/mq_receive.2 b/lib/libc/sys/mq_receive.2
new file mode 100644
index 000000000000..730636bf31ee
--- /dev/null
+++ b/lib/libc/sys/mq_receive.2
@@ -0,0 +1,217 @@
+.\" Copyright (c) 2005 David Xu <davidxu@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice(s), this list of conditions and the following disclaimer as
+.\" the first lines of this file unmodified other than the possible
+.\" addition of one or more copyright notices.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice(s), this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+.\" EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+.\" OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+.\" EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" Portions of this text are reprinted and reproduced in electronic form
+.\" from IEEE Std 1003.1, 2004 Edition, Standard for Information Technology --
+.\" Portable Operating System Interface (POSIX), The Open Group Base
+.\" Specifications Issue 6, Copyright (C) 2001-2004 by the Institute of
+.\" Electrical and Electronics Engineers, Inc and The Open Group. In the
+.\" event of any discrepancy between this version and the original IEEE and
+.\" The Open Group Standard, the original IEEE and The Open Group Standard is
+.\" the referee document. The original Standard can be obtained online at
+.\" http://www.opengroup.org/unix/online.html.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd November 29, 2005
+.Dt MQ_RECEIVE 2
+.Os
+.Sh NAME
+.Nm mq_receive , mq_timedreceive
+.Nd "receive a message from message queue (REALTIME)"
+.Sh LIBRARY
+.Lb librt
+.Sh SYNOPSIS
+.In mqueue.h
+.Ft ssize_t
+.Fo mq_receive
+.Fa "mqd_t mqdes"
+.Fa "char *msg_ptr"
+.Fa "size_t msg_len"
+.Fa "unsigned *msg_prio"
+.Fc
+.Ft ssize_t
+.Fo mq_timedreceive
+.Fa "mqd_t mqdes"
+.Fa "char *msg_ptr"
+.Fa "size_t msg_len"
+.Fa "unsigned *msg_prio"
+.Fa "const struct timespec *abs_timeout"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn mq_receive
+system call receives oldest of the highest priority message(s) from the
+message queue specified by
+.Fa mqdes .
+If the size of the buffer in bytes, specified by the
+.Fa msg_len
+argument, is less than the
+.Va mq_msgsize
+attribute of the message queue, the system call will fail and return an
+error.
+Otherwise, the selected message will be removed from the queue
+and copied to the buffer pointed to by the
+.Fa msg_ptr
+argument.
+.Pp
+If the argument
+.Fa msg_prio
+is not
+.Dv NULL ,
+the priority of the selected message will be stored in the
+location referenced by
+.Fa msg_prio .
+If the specified message queue is empty and
+.Dv O_NONBLOCK
+is not set in the message queue description associated with
+.Fa mqdes ,
+.Fn mq_receive
+will block until a message is enqueued on the message queue or until
+.Fn mq_receive
+is interrupted by a signal.
+If more than one thread is waiting to receive
+a message when a message arrives at an empty queue and the Priority
+Scheduling option is supported, then the thread of highest priority that
+has been waiting the longest will be selected to receive the message.
+Otherwise, it is unspecified which waiting thread receives the message.
+If the specified message queue is empty and
+.Dv O_NONBLOCK
+is set in the message queue description associated with
+.Fa mqdes ,
+no message
+will be removed from the queue, and
+.Fn mq_receive
+will return an error.
+.Pp
+The
+.Fn mq_timedreceive
+system call will receive the oldest of the highest priority messages from the
+message queue specified by
+.Fa mqdes
+as described for the
+.Fn mq_receive
+system call.
+However, if
+.Dv O_NONBLOCK
+was not specified when the message queue was opened via the
+.Fn mq_open
+system call, and no message exists on the queue to satisfy the receive, the wait
+for such a message will be terminated when the specified timeout expires.
+If
+.Dv O_NONBLOCK
+is set, this system call is equivalent to
+.Fn mq_receive .
+.Pp
+The timeout expires when the absolute time specified by
+.Fa abs_timeout
+passes, as measured by the clock on which timeouts are based (that is, when
+the value of that clock equals or exceeds
+.Fa abs_timeout ) ,
+or if the absolute time specified by
+.Fa abs_timeout
+has already been passed at the time of the call.
+.Pp
+The timeout is based on the
+.Dv CLOCK_REALTIME
+clock.
+.Sh RETURN VALUES
+Upon successful completion, the
+.Fn mq_receive
+and
+.Fn mq_timedreceive
+system calls return the length of the selected message in bytes and the
+message is removed from the queue.
+Otherwise, no message is removed
+from the queue, the system call returns a value of \-1,
+and the global variable
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+The
+.Fn mq_receive
+and
+.Fn mq_timedreceive
+system calls
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EAGAIN
+.Dv O_NONBLOCK
+flag is set in the message queue description associated with
+.Fa mqdes ,
+and the specified message queue is empty.
+.It Bq Er EBADF
+The
+.Fa mqdes
+argument is not a valid message queue descriptor open for reading.
+.It Bq Er EMSGSIZE
+The specified message buffer size,
+.Fa msg_len ,
+is less than the message size attribute of the message queue.
+.It Bq Er EINTR
+The
+.Fn mq_receive
+or
+.Fn mq_timedreceive
+operation was interrupted by a signal.
+.It Bq Er EINVAL
+The process or thread would have blocked, and the
+.Fa abs_timeout
+parameter specified a nanoseconds field value less than zero or greater
+than or equal to 1000 million.
+.It Bq Er ETIMEDOUT
+The
+.Dv O_NONBLOCK
+flag was not set when the message queue was opened, but no message arrived
+on the queue before the specified timeout expired.
+.El
+.Sh SEE ALSO
+.Xr mq_open 2 ,
+.Xr mq_send 2 ,
+.Xr mq_timedsend 2
+.Sh STANDARDS
+The
+.Fn mq_receive
+and
+.Fn mq_timedreceive
+system calls conform to
+.St -p1003.1-2004 .
+.Sh HISTORY
+Support for
+.Tn POSIX
+message queues first appeared in
+.Fx 7.0 .
+.Sh COPYRIGHT
+Portions of this text are reprinted and reproduced in electronic form
+from IEEE Std 1003.1, 2004 Edition, Standard for Information Technology --
+Portable Operating System Interface (POSIX), The Open Group Base
+Specifications Issue 6, Copyright (C) 2001-2004 by the Institute of
+Electrical and Electronics Engineers, Inc and The Open Group. In the
+event of any discrepancy between this version and the original IEEE and
+The Open Group Standard, the original IEEE and The Open Group Standard is
+the referee document. The original Standard can be obtained online at
+http://www.opengroup.org/unix/online.html.
diff --git a/lib/libc/sys/mq_send.2 b/lib/libc/sys/mq_send.2
new file mode 100644
index 000000000000..6f18b90c14bc
--- /dev/null
+++ b/lib/libc/sys/mq_send.2
@@ -0,0 +1,236 @@
+.\" Copyright (c) 2005 David Xu <davidxu@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice(s), this list of conditions and the following disclaimer as
+.\" the first lines of this file unmodified other than the possible
+.\" addition of one or more copyright notices.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice(s), this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+.\" EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+.\" OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+.\" EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" Portions of this text are reprinted and reproduced in electronic form
+.\" from IEEE Std 1003.1, 2004 Edition, Standard for Information Technology --
+.\" Portable Operating System Interface (POSIX), The Open Group Base
+.\" Specifications Issue 6, Copyright (C) 2001-2004 by the Institute of
+.\" Electrical and Electronics Engineers, Inc and The Open Group. In the
+.\" event of any discrepancy between this version and the original IEEE and
+.\" The Open Group Standard, the original IEEE and The Open Group Standard is
+.\" the referee document. The original Standard can be obtained online at
+.\" http://www.opengroup.org/unix/online.html.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd November 29, 2005
+.Dt MQ_SEND 2
+.Os
+.Sh NAME
+.Nm mq_send , mq_timedsend
+.Nd "send a message to message queue (REALTIME)"
+.Sh LIBRARY
+.Lb librt
+.Sh SYNOPSIS
+.In mqueue.h
+.Ft int
+.Fo mq_send
+.Fa "mqd_t mqdes"
+.Fa "const char *msg_ptr"
+.Fa "size_t msg_len"
+.Fa "unsigned msg_prio"
+.Fc
+.Ft int
+.Fo mq_timedsend
+.Fa "mqd_t mqdes"
+.Fa "const char *msg_ptr"
+.Fa "size_t msg_len"
+.Fa "unsigned msg_prio"
+.Fa "const struct timespec *abs_timeout"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn mq_send
+system call adds the message pointed to by the argument
+.Fa msg_ptr
+to the message queue specified by
+.Fa mqdes .
+The
+.Fa msg_len
+argument specifies the length of the message, in bytes, pointed to by
+.Fa msg_ptr .
+The value of
+.Fa msg_len
+should be less than or equal to the
+.Va mq_msgsize
+attribute of the message queue, or
+.Fn mq_send
+will fail.
+.Pp
+If the specified message queue is not full,
+.Fn mq_send
+will behave as if the message is inserted into the message queue at
+the position indicated by the
+.Fa msg_prio
+argument.
+A message with a larger numeric value of
+.Fa msg_prio
+will be inserted before messages with lower values of
+.Fa msg_prio .
+A message will be inserted after other messages in the queue, if any,
+with equal
+.Fa msg_prio .
+The value of
+.Fa msg_prio
+should be less than
+.Brq Dv MQ_PRIO_MAX .
+.Pp
+If the specified message queue is full and
+.Dv O_NONBLOCK
+is not set in the message queue description associated with
+.Fa mqdes ,
+.Fn mq_send
+will block until space becomes available to enqueue the
+message, or until
+.Fn mq_send
+is interrupted by a signal.
+If more than one thread is
+waiting to send when space becomes available in the message queue and
+the Priority Scheduling option is supported, then the thread of the
+highest priority that has been waiting the longest will be unblocked
+to send its message.
+Otherwise, it is unspecified which waiting thread
+is unblocked.
+If the specified message queue is full and
+.Dv O_NONBLOCK
+is set in the message queue description associated with
+.Fa mqdes ,
+the message will not be queued and
+.Fn mq_send
+will return an error.
+.Pp
+The
+.Fn mq_timedsend
+system call will add a message to the message queue specified by
+.Fa mqdes
+in the manner defined for the
+.Fn mq_send
+system call.
+However, if the specified message queue is full and
+.Dv O_NONBLOCK
+is not set in the message queue description associated with
+.Fa mqdes ,
+the wait for sufficient room in the queue will be terminated when
+the specified timeout expires.
+If
+.Dv O_NONBLOCK
+is set in the message queue description, this system call is
+equivalent to
+.Fn mq_send .
+.Pp
+The timeout will expire when the absolute time specified by
+.Fa abs_timeout
+passes, as measured by the clock on which timeouts are based (that is,
+when the value of that clock equals or exceeds
+.Fa abs_timeout ) ,
+or if the absolute time specified by
+.Fa abs_timeout
+has already been passed at the time of the call.
+.Pp
+The timeout is based on the
+.Dv CLOCK_REALTIME
+clock.
+.Sh RETURN VALUES
+Upon successful completion, the
+.Fn mq_send
+and
+.Fn mq_timedsend
+system calls return a value of zero.
+Otherwise, no message will be
+enqueued, the system calls return \-1, and
+the global variable
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+The
+.Fn mq_send
+and
+.Fn mq_timedsend
+system calls
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EAGAIN
+The
+.Dv O_NONBLOCK
+flag is set in the message queue description associated with
+.Fa mqdes ,
+and the specified message queue is full.
+.It Bq Er EBADF
+The
+.Fa mqdes
+argument is not a valid message queue descriptor open for writing.
+.It Bq Er EINTR
+A signal interrupted the call to
+.Fn mq_send
+or
+.Fn mq_timedsend .
+.It Bq Er EINVAL
+The value of
+.Fa msg_prio
+was outside the valid range.
+.It Bq Er EINVAL
+The process or thread would have blocked, and the
+.Fa abs_timeout
+parameter specified a nanoseconds field value less than zero or greater
+than or equal to 1000 million.
+.It Bq Er EMSGSIZE
+The specified message length,
+.Fa msg_len ,
+exceeds the message size attribute of the message queue.
+.It Bq Er ETIMEDOUT
+The
+.Dv O_NONBLOCK
+flag was not set when the message queue was opened, but the timeout
+expired before the message could be added to the queue.
+.El
+.Sh SEE ALSO
+.Xr mq_open 2 ,
+.Xr mq_receive 2 ,
+.Xr mq_setattr 2 ,
+.Xr mq_timedreceive 2
+.Sh STANDARDS
+The
+.Fn mq_send
+and
+.Fn mq_timedsend
+system calls conform to
+.St -p1003.1-2004 .
+.Sh HISTORY
+Support for
+.Tn POSIX
+message queues first appeared in
+.Fx 7.0 .
+.Sh COPYRIGHT
+Portions of this text are reprinted and reproduced in electronic form
+from IEEE Std 1003.1, 2004 Edition, Standard for Information Technology --
+Portable Operating System Interface (POSIX), The Open Group Base
+Specifications Issue 6, Copyright (C) 2001-2004 by the Institute of
+Electrical and Electronics Engineers, Inc and The Open Group. In the
+event of any discrepancy between this version and the original IEEE and
+The Open Group Standard, the original IEEE and The Open Group Standard is
+the referee document. The original Standard can be obtained online at
+http://www.opengroup.org/unix/online.html.
diff --git a/lib/libc/sys/mq_setattr.2 b/lib/libc/sys/mq_setattr.2
new file mode 100644
index 000000000000..79e523d6dd75
--- /dev/null
+++ b/lib/libc/sys/mq_setattr.2
@@ -0,0 +1,123 @@
+.\" Copyright (c) 2005 David Xu <davidxu@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice(s), this list of conditions and the following disclaimer as
+.\" the first lines of this file unmodified other than the possible
+.\" addition of one or more copyright notices.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice(s), this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+.\" EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+.\" OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+.\" EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" Portions of this text are reprinted and reproduced in electronic form
+.\" from IEEE Std 1003.1, 2004 Edition, Standard for Information Technology --
+.\" Portable Operating System Interface (POSIX), The Open Group Base
+.\" Specifications Issue 6, Copyright (C) 2001-2004 by the Institute of
+.\" Electrical and Electronics Engineers, Inc and The Open Group. In the
+.\" event of any discrepancy between this version and the original IEEE and
+.\" The Open Group Standard, the original IEEE and The Open Group Standard is
+.\" the referee document. The original Standard can be obtained online at
+.\" http://www.opengroup.org/unix/online.html.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd May 17, 2011
+.Dt MQ_SETATTR 2
+.Os
+.Sh NAME
+.Nm mq_setattr
+.Nd "set message queue attributes (REALTIME)"
+.Sh LIBRARY
+.Lb librt
+.Sh SYNOPSIS
+.In mqueue.h
+.Ft int
+.Fo mq_setattr
+.Fa "mqd_t mqdes"
+.Fa "const struct mq_attr *restrict mqstat"
+.Fa "struct mq_attr *restrict omqstat"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn mq_setattr
+system call sets attributes associated with the open message queue description
+referenced by the message queue descriptor specified by
+.Fa mqdes .
+The message queue attributes corresponding to the following members defined
+in the
+.Vt mq_attr
+structure will be set to the specified values upon successful completion of
+.Fn mq_setattr :
+.Bl -tag -width ".Va mq_flags"
+.It Va mq_flags
+The value of this member is zero or
+.Dv O_NONBLOCK .
+.El
+.Pp
+The values of the
+.Va mq_maxmsg , mq_msgsize ,
+and
+.Va mq_curmsgs
+members of the
+.Vt mq_attr
+structure are ignored by
+.Fn mq_setattr .
+.Sh RETURN VALUES
+Upon successful completion, the function returns a value of zero and the
+attributes of the message queue will have been changed as specified.
+.Pp
+Otherwise, the message queue attributes are unchanged, and the function
+returns a value of \-1 and sets the global variable
+.Va errno
+to indicate the error.
+.Sh ERRORS
+The
+.Fn mq_setattr
+system call
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa mqdes
+argument is not a valid message queue descriptor.
+.El
+.Sh SEE ALSO
+.Xr mq_open 2 ,
+.Xr mq_send 2 ,
+.Xr mq_timedsend 2
+.Sh STANDARDS
+The
+.Fn mq_setattr
+system call conforms to
+.St -p1003.1-2004 .
+.Sh HISTORY
+Support for
+.Tn POSIX
+message queues first appeared in
+.Fx 7.0 .
+.Sh COPYRIGHT
+Portions of this text are reprinted and reproduced in electronic form
+from IEEE Std 1003.1, 2004 Edition, Standard for Information Technology --
+Portable Operating System Interface (POSIX), The Open Group Base
+Specifications Issue 6, Copyright (C) 2001-2004 by the Institute of
+Electrical and Electronics Engineers, Inc and The Open Group. In the
+event of any discrepancy between this version and the original IEEE and
+The Open Group Standard, the original IEEE and The Open Group Standard is
+the referee document. The original Standard can be obtained online at
+http://www.opengroup.org/unix/online.html.
diff --git a/lib/libc/sys/msgctl.2 b/lib/libc/sys/msgctl.2
new file mode 100644
index 000000000000..34c52633d8c8
--- /dev/null
+++ b/lib/libc/sys/msgctl.2
@@ -0,0 +1,210 @@
+.\" $NetBSD: msgctl.2,v 1.1 1995/10/16 23:49:15 jtc Exp $
+.\"
+.\" Copyright (c) 1995 Frank van der Linden
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed for the NetBSD Project
+.\" by Frank van der Linden
+.\" 4. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"/
+.Dd July 9, 2009
+.Dt MSGCTL 2
+.Os
+.Sh NAME
+.Nm msgctl
+.Nd message control operations
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/ipc.h
+.In sys/msg.h
+.Ft int
+.Fn msgctl "int msqid" "int cmd" "struct msqid_ds *buf"
+.Sh DESCRIPTION
+The
+.Fn msgctl
+system call performs some control operations on the message queue specified
+by
+.Fa msqid .
+.Pp
+Each message queue has a data structure associated with it, parts of which
+may be altered by
+.Fn msgctl
+and parts of which determine the actions of
+.Fn msgctl .
+The data structure is defined in
+.In sys/msg.h
+and contains (amongst others) the following members:
+.Bd -literal
+struct msqid_ds {
+ struct ipc_perm msg_perm; /* msg queue permission bits */
+ struct msg *msg_first; /* first message in the queue */
+ struct msg *msg_last; /* last message in the queue */
+ msglen_t msg_cbytes; /* number of bytes in use on the queue */
+ msgqnum_t msg_qnum; /* number of msgs in the queue */
+ msglen_t msg_qbytes; /* max # of bytes on the queue */
+ pid_t msg_lspid; /* pid of last msgsnd() */
+ pid_t msg_lrpid; /* pid of last msgrcv() */
+ time_t msg_stime; /* time of last msgsnd() */
+ time_t msg_rtime; /* time of last msgrcv() */
+ time_t msg_ctime; /* time of last msgctl() */
+};
+.Ed
+.Pp
+The
+.Vt ipc_perm
+structure used inside the
+.Vt msqid_ds
+structure is defined in
+.In sys/ipc.h
+and looks like this:
+.Bd -literal
+struct ipc_perm {
+ uid_t cuid; /* creator user id */
+ gid_t cgid; /* creator group id */
+ uid_t uid; /* user id */
+ gid_t gid; /* group id */
+ mode_t mode; /* r/w permission */
+ unsigned short seq; /* sequence # (to generate unique ipcid) */
+ key_t key; /* user specified msg/sem/shm key */
+};
+.Ed
+.Pp
+The operation to be performed by
+.Fn msgctl
+is specified in
+.Fa cmd
+and is one of:
+.Bl -tag -width IPC_RMIDX
+.It Dv IPC_STAT
+Gather information about the message queue and place it in the
+structure pointed to by
+.Fa buf .
+.It Dv IPC_SET
+Set the value of the
+.Va msg_perm.uid ,
+.Va msg_perm.gid ,
+.Va msg_perm.mode
+and
+.Va msg_qbytes
+fields in the structure associated with
+.Fa msqid .
+The values are taken from the corresponding fields in the structure
+pointed to by
+.Fa buf .
+This operation can only be executed by the super-user, or a process that
+has an effective user id equal to either
+.Va msg_perm.cuid
+or
+.Va msg_perm.uid
+in the data structure associated with the message queue.
+The value of
+.Va msg_qbytes
+can only be increased by the super-user.
+Values for
+.Va msg_qbytes
+that exceed the system limit (MSGMNB from
+.In sys/msg.h )
+are silently truncated to that limit.
+.It Dv IPC_RMID
+Remove the message queue specified by
+.Fa msqid
+and destroy the data associated with it.
+Only the super-user or a process
+with an effective uid equal to the
+.Va msg_perm.cuid
+or
+.Va msg_perm.uid
+values in the data structure associated with the queue can do this.
+.El
+.Pp
+The permission to read from or write to a message queue (see
+.Xr msgsnd 2
+and
+.Xr msgrcv 2 )
+is determined by the
+.Va msg_perm.mode
+field in the same way as is
+done with files (see
+.Xr chmod 2 ) ,
+but the effective uid can match either the
+.Va msg_perm.cuid
+field or the
+.Va msg_perm.uid
+field, and the
+effective gid can match either
+.Va msg_perm.cgid
+or
+.Va msg_perm.gid .
+.Sh RETURN VALUES
+.Rv -std msgctl
+.Sh ERRORS
+The
+.Fn msgctl
+function
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EPERM
+The
+.Fa cmd
+argument
+is equal to IPC_SET or IPC_RMID and the caller is not the super-user, nor does
+the effective uid match either the
+.Va msg_perm.uid
+or
+.Va msg_perm.cuid
+fields of the data structure associated with the message queue.
+.Pp
+An attempt is made to increase the value of
+.Va msg_qbytes
+through IPC_SET
+but the caller is not the super-user.
+.It Bq Er EACCES
+The command is IPC_STAT
+and the caller has no read permission for this message queue.
+.It Bq Er EINVAL
+The
+.Fa msqid
+argument
+is not a valid message queue identifier.
+.Pp
+.Va cmd
+is not a valid command.
+.It Bq Er EFAULT
+The
+.Fa buf
+argument
+specifies an invalid address.
+.El
+.Sh SEE ALSO
+.Xr msgget 2 ,
+.Xr msgrcv 2 ,
+.Xr msgsnd 2
+.Sh HISTORY
+Message queues appeared in the first release of
+.At V .
diff --git a/lib/libc/sys/msgget.2 b/lib/libc/sys/msgget.2
new file mode 100644
index 000000000000..27e1766350ca
--- /dev/null
+++ b/lib/libc/sys/msgget.2
@@ -0,0 +1,141 @@
+.\" $NetBSD: msgget.2,v 1.1 1995/10/16 23:49:19 jtc Exp $
+.\"
+.\" Copyright (c) 1995 Frank van der Linden
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed for the NetBSD Project
+.\" by Frank van der Linden
+.\" 4. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\" $FreeBSD$
+.\"
+.\"/
+.Dd July 9, 2009
+.Dt MSGGET 2
+.Os
+.Sh NAME
+.Nm msgget
+.Nd get message queue
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/ipc.h
+.In sys/msg.h
+.Ft int
+.Fn msgget "key_t key" "int msgflg"
+.Sh DESCRIPTION
+The
+.Fn msgget
+function
+returns the message queue identifier associated with
+.Fa key .
+A message queue identifier is a unique integer greater than zero.
+.Pp
+A message queue is created if either
+.Fa key
+is equal to
+.Dv IPC_PRIVATE ,
+or
+.Fa key
+does not have a message queue identifier associated with it, and the
+.Dv IPC_CREAT
+bit is set in
+.Fa msgflg .
+.Pp
+If a new message queue is created, the data structure associated with it (the
+.Va msqid_ds
+structure, see
+.Xr msgctl 2 )
+is initialized as follows:
+.Bl -bullet
+.It
+.Va msg_perm.cuid
+and
+.Va msg_perm.uid
+are set to the effective uid of the calling process.
+.It
+.Va msg_perm.gid
+and
+.Va msg_perm.cgid
+are set to the effective gid of the calling process.
+.It
+.Va msg_perm.mode
+is set to the lower 9 bits of
+.Fa msgflg .
+.It
+.Va msg_cbytes ,
+.Va msg_qnum ,
+.Va msg_lspid ,
+.Va msg_lrpid ,
+.Va msg_rtime ,
+and
+.Va msg_stime
+are set to 0.
+.It
+.Va msg_qbytes
+is set to the system wide maximum value for the number of bytes in a queue
+.Pf ( Dv MSGMNB ) .
+.It
+.Va msg_ctime
+is set to the current time.
+.El
+.Sh RETURN VALUES
+Upon successful completion a positive message queue identifier is returned.
+Otherwise, -1 is returned and the global variable
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+.Bl -tag -width Er
+.It Bq Er EACCES
+A message queue is already associated with
+.Fa key
+and the caller has no permission to access it.
+.It Bq Er EEXIST
+Both
+.Dv IPC_CREAT
+and
+.Dv IPC_EXCL
+are set in
+.Fa msgflg ,
+and a message queue is already associated with
+.Fa key .
+.It Bq Er ENOSPC
+A new message queue could not be created because the system limit for
+the number of message queues has been reached.
+.It Bq Er ENOENT
+.Dv IPC_CREAT
+was not set in
+.Fa msgflg
+and no message queue associated with
+.Fa key
+was found.
+.El
+.Sh SEE ALSO
+.Xr msgctl 2 ,
+.Xr msgrcv 2 ,
+.Xr msgsnd 2
+.Sh HISTORY
+Message queues appeared in the first release of
+.At V .
diff --git a/lib/libc/sys/msgrcv.2 b/lib/libc/sys/msgrcv.2
new file mode 100644
index 000000000000..59eeec42f2d5
--- /dev/null
+++ b/lib/libc/sys/msgrcv.2
@@ -0,0 +1,222 @@
+.\" $NetBSD: msgrcv.2,v 1.1 1995/10/16 23:49:20 jtc Exp $
+.\"
+.\" Copyright (c) 1995 Frank van der Linden
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed for the NetBSD Project
+.\" by Frank van der Linden
+.\" 4. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\" $FreeBSD$
+.\"
+.\"/
+.Dd July 28, 2016
+.Dt MSGRCV 2
+.Os
+.Sh NAME
+.Nm msgrcv
+.Nd receive a message from a message queue
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/ipc.h
+.In sys/msg.h
+.Ft ssize_t
+.Fn msgrcv "int msqid" "void *msgp" "size_t msgsz" "long msgtyp" "int msgflg"
+.Sh DESCRIPTION
+The
+.Fn msgrcv
+function receives a message from the message queue specified in
+.Fa msqid ,
+and places it into the structure pointed to by
+.Fa msgp .
+This structure should consist of the following members:
+.Bd -literal
+ long mtype; /* message type */
+ char mtext[1]; /* body of message */
+.Ed
+.Pp
+.Va mtype
+is an integer greater than 0 that can be used for selecting messages,
+.Va mtext
+is an array of bytes, with a size up to that of the system limit
+.Pf ( Dv MSGMAX ) .
+.Pp
+The value of
+.Fa msgtyp
+has one of the following meanings:
+.Bl -bullet
+.It
+The
+.Fa msgtyp
+argument
+is greater than 0.
+The first message of type
+.Fa msgtyp
+will be received.
+.It
+The
+.Fa msgtyp
+argument
+is equal to 0.
+The first message on the queue will be received.
+.It
+The
+.Fa msgtyp
+argument
+is less than 0.
+The first message of the lowest message type that is
+less than or equal to the absolute value of
+.Fa msgtyp
+will be received.
+.El
+.Pp
+The
+.Fa msgsz
+argument
+specifies the maximum length of the requested message.
+If the received
+message has a length greater than
+.Fa msgsz
+it will be silently truncated if the
+.Dv MSG_NOERROR
+flag is set in
+.Fa msgflg ,
+otherwise an error will be returned.
+.Pp
+If no matching message is present on the message queue specified by
+.Fa msqid ,
+the behavior of
+.Fn msgrcv
+depends on whether the
+.Dv IPC_NOWAIT
+flag is set in
+.Fa msgflg
+or not.
+If
+.Dv IPC_NOWAIT
+is set,
+.Fn msgrcv
+will immediately return a value of -1, and set
+.Va errno
+to
+.Er ENOMSG .
+If
+.Dv IPC_NOWAIT
+is not set, the calling process will be blocked
+until:
+.Bl -bullet
+.It
+A message of the requested type becomes available on the message queue.
+.It
+The message queue is removed, in which case -1 will be returned, and
+.Va errno
+set to
+.Er EINVAL .
+.It
+A signal is received and caught.
+-1 is returned, and
+.Va errno
+set to
+.Er EINTR .
+.El
+.Pp
+If a message is successfully received, the data structure associated with
+.Fa msqid
+is updated as follows:
+.Bl -bullet
+.It
+.Va msg_cbytes
+is decremented by the size of the message.
+.It
+.Va msg_lrpid
+is set to the pid of the caller.
+.It
+.Va msg_lrtime
+is set to the current time.
+.It
+.Va msg_qnum
+is decremented by 1.
+.El
+.Sh RETURN VALUES
+Upon successful completion,
+.Fn msgrcv
+returns the number of bytes received into the
+.Va mtext
+field of the structure pointed to by
+.Fa msgp .
+Otherwise, -1 is returned, and
+.Va errno
+set to indicate the error.
+.Sh ERRORS
+The
+.Fn msgrcv
+function
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa msqid
+argument
+is not a valid message queue identifier.
+.Pp
+The message queue was removed while
+.Fn msgrcv
+was waiting for a message of the requested type to become available on it.
+.Pp
+The
+.Fa msgsz
+argument
+is less than 0.
+.It Bq Er E2BIG
+A matching message was received, but its size was greater than
+.Fa msgsz
+and the
+.Dv MSG_NOERROR
+flag was not set in
+.Fa msgflg .
+.It Bq Er EACCES
+The calling process does not have read access to the message queue.
+.It Bq Er EFAULT
+The
+.Fa msgp
+argument
+points to an invalid address.
+.It Bq Er EINTR
+The system call was interrupted by the delivery of a signal.
+.It Bq Er ENOMSG
+There is no message of the requested type available on the message queue,
+and
+.Dv IPC_NOWAIT
+is set in
+.Fa msgflg .
+.El
+.Sh SEE ALSO
+.Xr msgctl 2 ,
+.Xr msgget 2 ,
+.Xr msgsnd 2
+.Sh HISTORY
+Message queues appeared in the first release of
+.At V .
diff --git a/lib/libc/sys/msgsnd.2 b/lib/libc/sys/msgsnd.2
new file mode 100644
index 000000000000..051c9922e58c
--- /dev/null
+++ b/lib/libc/sys/msgsnd.2
@@ -0,0 +1,184 @@
+.\" $NetBSD: msgsnd.2,v 1.1 1995/10/16 23:49:24 jtc Exp $
+.\"
+.\" Copyright (c) 1995 Frank van der Linden
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed for the NetBSD Project
+.\" by Frank van der Linden
+.\" 4. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd July 9, 2009
+.Dt MSGSND 2
+.Os
+.Sh NAME
+.Nm msgsnd
+.Nd send a message to a message queue
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/ipc.h
+.In sys/msg.h
+.Ft int
+.Fn msgsnd "int msqid" "const void *msgp" "size_t msgsz" "int msgflg"
+.Sh DESCRIPTION
+The
+.Fn msgsnd
+function sends a message to the message queue specified in
+.Fa msqid .
+The
+.Fa msgp
+argument
+points to a structure containing the message.
+This structure should
+consist of the following members:
+.Bd -literal
+ long mtype; /* message type */
+ char mtext[1]; /* body of message */
+.Ed
+.Pp
+.Va mtype
+is an integer greater than 0 that can be used for selecting messages (see
+.Xr msgrcv 2 ) ,
+.Va mtext
+is an array of
+.Fa msgsz
+bytes.
+The argument
+.Fa msgsz
+can range from 0 to a system-imposed maximum,
+.Dv MSGMAX .
+.Pp
+If the number of bytes already on the message queue plus
+.Fa msgsz
+is bigger than the maximum number of bytes on the message queue
+.Pf ( Va msg_qbytes ,
+see
+.Xr msgctl 2 ) ,
+or the number of messages on all queues system-wide is already equal to
+the system limit,
+.Fa msgflg
+determines the action of
+.Fn msgsnd .
+If
+.Fa msgflg
+has
+.Dv IPC_NOWAIT
+mask set in it, the call will return immediately.
+If
+.Fa msgflg
+does not have
+.Dv IPC_NOWAIT
+set in it, the call will block until:
+.Bl -bullet
+.It
+The condition which caused the call to block does no longer exist.
+The message will be sent.
+.It
+The message queue is removed, in which case -1 will be returned, and
+.Va errno
+is set to
+.Er EINVAL .
+.It
+The caller catches a signal.
+The call returns with
+.Va errno
+set to
+.Er EINTR .
+.El
+.Pp
+After a successful call, the data structure associated with the message
+queue is updated in the following way:
+.Bl -bullet
+.It
+.Va msg_cbytes
+is incremented by the size of the message.
+.It
+.Va msg_qnum
+is incremented by 1.
+.It
+.Va msg_lspid
+is set to the pid of the calling process.
+.It
+.Va msg_stime
+is set to the current time.
+.El
+.Sh RETURN VALUES
+.Rv -std msgsnd
+.Sh ERRORS
+The
+.Fn msgsnd
+function
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa msqid
+argument
+is not a valid message queue identifier.
+.Pp
+The message queue was removed while
+.Fn msgsnd
+was waiting for a resource to become available in order to deliver the
+message.
+.Pp
+The
+.Fa msgsz
+argument
+is greater than
+.Va msg_qbytes .
+.Pp
+The
+.Fa mtype
+argument
+is not greater than 0.
+.It Bq Er EACCES
+The calling process does not have write access to the message queue.
+.It Bq Er EAGAIN
+There was no space for this message either on the queue, or in the whole
+system, and
+.Dv IPC_NOWAIT
+was set in
+.Fa msgflg .
+.It Bq Er EFAULT
+The
+.Fa msgp
+argument
+points to an invalid address.
+.It Bq Er EINTR
+The system call was interrupted by the delivery of a signal.
+.El
+.Sh HISTORY
+Message queues appeared in the first release of AT&T Unix System V.
+.Sh BUGS
+.Nx
+and
+.Fx
+do not define the
+.Er EIDRM
+error value, which should be used
+in the case of a removed message queue.
diff --git a/lib/libc/sys/msync.2 b/lib/libc/sys/msync.2
new file mode 100644
index 000000000000..a91faf2a66e0
--- /dev/null
+++ b/lib/libc/sys/msync.2
@@ -0,0 +1,126 @@
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)msync.2 8.2 (Berkeley) 6/21/94
+.\" $FreeBSD$
+.\"
+.Dd March 18, 2012
+.Dt MSYNC 2
+.Os
+.Sh NAME
+.Nm msync
+.Nd synchronize a mapped region
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/mman.h
+.Ft int
+.Fn msync "void *addr" "size_t len" "int flags"
+.Sh DESCRIPTION
+The
+.Fn msync
+system call
+writes any modified pages back to the file system and updates
+the file modification time.
+If
+.Fa len
+is 0, all modified pages within the region containing
+.Fa addr
+will be flushed;
+if
+.Fa len
+is non-zero, only those pages containing
+.Fa addr
+and
+.Fa len-1
+succeeding locations will be examined.
+The
+.Fa flags
+argument may be specified as follows:
+.Pp
+.Bl -tag -width ".Dv MS_INVALIDATE" -compact
+.It Dv MS_ASYNC
+Return immediately
+.It Dv MS_SYNC
+Perform synchronous writes
+.It Dv MS_INVALIDATE
+Invalidate all cached data
+.El
+.Sh RETURN VALUES
+.Rv -std msync
+.Sh ERRORS
+The
+.Fn msync
+system call
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EBUSY
+Some or all of the pages in the specified region are locked and
+.Dv MS_INVALIDATE
+is specified.
+.It Bq Er EINVAL
+The
+.Fa addr
+argument
+is not a multiple of the hardware page size.
+.It Bq Er ENOMEM
+The addresses in the range starting at
+.Fa addr
+and continuing for
+.Fa len
+bytes are outside the range allowed for the address space of a
+process or specify one or more pages that are not mapped.
+.It Bq Er EINVAL
+The
+.Fa flags
+argument
+was both MS_ASYNC and MS_INVALIDATE.
+Only one of these flags is allowed.
+.It Bq Er EIO
+An error occurred while writing at least one of the pages in
+the specified region.
+.El
+.Sh SEE ALSO
+.Xr madvise 2 ,
+.Xr mincore 2 ,
+.Xr mlock 2 ,
+.Xr mprotect 2 ,
+.Xr munmap 2
+.Sh HISTORY
+The
+.Fn msync
+system call first appeared in
+.Bx 4.4 .
+.Sh BUGS
+The
+.Fn msync
+system call is usually not needed since
+.Bx
+implements a coherent file system buffer cache.
+However, it may be used to associate dirty VM pages with file system
+buffers and thus cause them to be flushed to physical media sooner
+rather than later.
diff --git a/lib/libc/sys/msync.c b/lib/libc/sys/msync.c
new file mode 100644
index 000000000000..d86cc0462dd8
--- /dev/null
+++ b/lib/libc/sys/msync.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2014 The FreeBSD Foundation.
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Konstantin Belousov
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice(s), this list of conditions and the following disclaimer as
+ * the first lines of this file unmodified other than the possible
+ * addition of one or more copyright notices.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice(s), this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/fcntl.h>
+#include <sys/mman.h>
+#include "libc_private.h"
+
+__weak_reference(__sys_msync, __msync);
+
+#pragma weak msync
+int
+msync(void *addr, size_t len, int flags)
+{
+
+ return (((int (*)(void *, size_t, int))
+ __libc_interposing[INTERPOS_msync])(addr, len, flags));
+}
diff --git a/lib/libc/sys/munmap.2 b/lib/libc/sys/munmap.2
new file mode 100644
index 000000000000..643107286203
--- /dev/null
+++ b/lib/libc/sys/munmap.2
@@ -0,0 +1,78 @@
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)munmap.2 8.3 (Berkeley) 5/27/94
+.\" $FreeBSD$
+.\"
+.Dd May 27, 1994
+.Dt MUNMAP 2
+.Os
+.Sh NAME
+.Nm munmap
+.Nd remove a mapping
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/mman.h
+.Ft int
+.Fn munmap "void *addr" "size_t len"
+.Sh DESCRIPTION
+The
+.Fn munmap
+system call
+deletes the mappings for the specified address range,
+and causes further references to addresses within the range
+to generate invalid memory references.
+.Sh RETURN VALUES
+.Rv -std munmap
+.Sh ERRORS
+The
+.Fn munmap
+system call
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa addr
+argument was not page aligned, the
+.Fa len
+argument was zero or negative, or
+some part of the region being unmapped is outside the
+valid address range for a process.
+.El
+.Sh "SEE ALSO"
+.Xr madvise 2 ,
+.Xr mincore 2 ,
+.Xr mmap 2 ,
+.Xr mprotect 2 ,
+.Xr msync 2 ,
+.Xr getpagesize 3
+.Sh HISTORY
+The
+.Fn munmap
+system call first appeared in
+.Bx 4.4 .
diff --git a/lib/libc/sys/nanosleep.2 b/lib/libc/sys/nanosleep.2
new file mode 100644
index 000000000000..f50544b83d69
--- /dev/null
+++ b/lib/libc/sys/nanosleep.2
@@ -0,0 +1,111 @@
+.\" $OpenBSD: nanosleep.2,v 1.1 1997/04/20 20:56:20 tholo Exp $
+.\" $NetBSD: nanosleep.2,v 1.1 1997/04/17 18:12:02 jtc Exp $
+.\"
+.\" Copyright (c) 1986, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)sleep.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd April 17, 1997
+.Dt NANOSLEEP 2
+.Os
+.Sh NAME
+.Nm nanosleep
+.Nd suspend process execution for an interval measured in nanoseconds
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In time.h
+.Ft int
+.Fn nanosleep "const struct timespec *rqtp" "struct timespec *rmtp"
+.Sh DESCRIPTION
+The
+.Fn nanosleep
+system call
+causes the calling thread to sleep until the time interval specified by
+.Fa rqtp
+has elapsed.
+An unmasked signal will
+cause it to terminate the sleep early, regardless of the
+.Dv SA_RESTART
+value on the interrupting signal.
+.Sh RETURN VALUES
+If the
+.Fn nanosleep
+system call returns because the requested time has elapsed, the value
+returned will be zero.
+.Pp
+If the
+.Fn nanosleep
+system call returns due to the delivery of a signal, the value returned
+will be -1, and the global variable
+.Va errno
+will be set to indicate the interruption.
+If
+.Fa rmtp
+is
+.No non- Ns Dv NULL ,
+the timespec structure it references is updated to contain the
+unslept amount (the request time minus the time actually slept).
+.Sh ERRORS
+The
+.Fn nanosleep
+system call fails if:
+.Bl -tag -width Er
+.It Bq Er EFAULT
+Either
+.Fa rqtp
+or
+.Fa rmtp
+points to memory that is not a valid part of the process
+address space.
+.It Bq Er EINTR
+The
+.Fn nanosleep
+system call
+was interrupted by the delivery of a signal.
+.It Bq Er EINVAL
+The
+.Fa rqtp
+argument
+specified a nanosecond value less than zero
+or greater than or equal to 1000 million.
+.It Bq Er ENOSYS
+The
+.Fn nanosleep
+system call
+is not supported by this implementation.
+.El
+.Sh SEE ALSO
+.Xr sigsuspend 2 ,
+.Xr sleep 3
+.Sh STANDARDS
+The
+.Fn nanosleep
+system call conforms to
+.St -p1003.1b-93 .
diff --git a/lib/libc/sys/nanosleep.c b/lib/libc/sys/nanosleep.c
new file mode 100644
index 000000000000..412b05e778b0
--- /dev/null
+++ b/lib/libc/sys/nanosleep.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2014 The FreeBSD Foundation.
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Konstantin Belousov
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice(s), this list of conditions and the following disclaimer as
+ * the first lines of this file unmodified other than the possible
+ * addition of one or more copyright notices.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice(s), this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <time.h>
+#include "libc_private.h"
+
+__weak_reference(__sys_nanosleep, __nanosleep);
+
+#pragma weak nanosleep
+int
+nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
+{
+
+ return (((int (*)(const struct timespec *, struct timespec *))
+ __libc_interposing[INTERPOS_nanosleep])(rqtp, rmtp));
+}
diff --git a/lib/libc/sys/nfssvc.2 b/lib/libc/sys/nfssvc.2
new file mode 100644
index 000000000000..f816231ef0a1
--- /dev/null
+++ b/lib/libc/sys/nfssvc.2
@@ -0,0 +1,258 @@
+.\" Copyright (c) 1989, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)nfssvc.2 8.1 (Berkeley) 6/9/93
+.\" $FreeBSD$
+.\"
+.Dd June 9, 1993
+.Dt NFSSVC 2
+.Os
+.Sh NAME
+.Nm nfssvc
+.Nd NFS services
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/param.h
+.In sys/mount.h
+.In sys/time.h
+.In nfs/rpcv2.h
+.In nfsserver/nfs.h
+.In unistd.h
+.Ft int
+.Fn nfssvc "int flags" "void *argstructp"
+.Sh DESCRIPTION
+The
+.Fn nfssvc
+system call is used by the NFS daemons to pass information into and out
+of the kernel and also to enter the kernel as a server daemon.
+The
+.Fa flags
+argument consists of several bits that show what action is to be taken
+once in the kernel and the
+.Fa argstructp
+points to one of three structures depending on which bits are set in
+flags.
+.Pp
+On the client side,
+.Xr nfsiod 8
+calls
+.Fn nfssvc
+with the
+.Fa flags
+argument set to
+.Dv NFSSVC_BIOD
+and
+.Fa argstructp
+set to
+.Dv NULL
+to enter the kernel as a block I/O server daemon.
+For
+.Tn NQNFS ,
+.Xr mount_nfs 8
+calls
+.Fn nfssvc
+with the
+.Dv NFSSVC_MNTD
+flag, optionally or'd with the flags
+.Dv NFSSVC_GOTAUTH
+and
+.Dv NFSSVC_AUTHINFAIL
+along with a pointer to a
+.Bd -literal
+struct nfsd_cargs {
+ char *ncd_dirp; /* Mount dir path */
+ uid_t ncd_authuid; /* Effective uid */
+ int ncd_authtype; /* Type of authenticator */
+ int ncd_authlen; /* Length of authenticator string */
+ u_char *ncd_authstr; /* Authenticator string */
+ int ncd_verflen; /* and the verifier */
+ u_char *ncd_verfstr;
+ NFSKERBKEY_T ncd_key; /* Session key */
+};
+.Ed
+.Pp
+structure.
+The initial call has only the
+.Dv NFSSVC_MNTD
+flag set to specify service for the mount point.
+If the mount point is using Kerberos, then the
+.Xr mount_nfs 8
+utility will return from
+.Fn nfssvc
+with
+.Va errno
+==
+.Er ENEEDAUTH
+whenever the client side requires an ``rcmd''
+authentication ticket for the user.
+The
+.Xr mount_nfs 8
+utility will attempt to get the Kerberos ticket, and if successful will call
+.Fn nfssvc
+with the flags
+.Dv NFSSVC_MNTD
+and
+.Dv NFSSVC_GOTAUTH
+after filling the ticket into the
+ncd_authstr field
+and
+setting the ncd_authlen and ncd_authtype
+fields of the nfsd_cargs structure.
+If
+.Xr mount_nfs 8
+failed to get the ticket,
+.Fn nfssvc
+will be called with the flags
+.Dv NFSSVC_MNTD ,
+.Dv NFSSVC_GOTAUTH
+and
+.Dv NFSSVC_AUTHINFAIL
+to denote a failed authentication attempt.
+.Pp
+On the server side,
+.Fn nfssvc
+is called with the flag
+.Dv NFSSVC_NFSD
+and a pointer to a
+.Bd -literal
+struct nfsd_srvargs {
+ struct nfsd *nsd_nfsd; /* Pointer to in kernel nfsd struct */
+ uid_t nsd_uid; /* Effective uid mapped to cred */
+ uint32_t nsd_haddr; /* Ip address of client */
+ struct ucred nsd_cr; /* Cred. uid maps to */
+ int nsd_authlen; /* Length of auth string (ret) */
+ u_char *nsd_authstr; /* Auth string (ret) */
+ int nsd_verflen; /* and the verifier */
+ u_char *nsd_verfstr;
+ struct timeval nsd_timestamp; /* timestamp from verifier */
+ uint32_t nsd_ttl; /* credential ttl (sec) */
+ NFSKERBKEY_T nsd_key; /* Session key */
+};
+.Ed
+.Pp
+to enter the kernel as an
+.Xr nfsd 8
+daemon.
+Whenever an
+.Xr nfsd 8
+daemon receives a Kerberos authentication ticket, it will return from
+.Fn nfssvc
+with
+.Va errno
+==
+.Er ENEEDAUTH .
+The
+.Xr nfsd 8
+utility will attempt to authenticate the ticket and generate a set of credentials
+on the server for the ``user id'' specified in the field nsd_uid.
+This is done by first authenticating the Kerberos ticket and then mapping
+the Kerberos principal to a local name and getting a set of credentials for
+that user via
+.Xr getpwnam 3
+and
+.Xr getgrouplist 3 .
+If successful, the
+.Xr nfsd 8
+utility will call
+.Fn nfssvc
+with the
+.Dv NFSSVC_NFSD
+and
+.Dv NFSSVC_AUTHIN
+flags set to pass the credential mapping in nsd_cr into the
+kernel to be cached on the server socket for that client.
+If the authentication failed,
+.Xr nfsd 8
+calls
+.Fn nfssvc
+with the flags
+.Dv NFSSVC_NFSD
+and
+.Dv NFSSVC_AUTHINFAIL
+to denote an authentication failure.
+.Pp
+The master
+.Xr nfsd 8
+server daemon calls
+.Fn nfssvc
+with the flag
+.Dv NFSSVC_ADDSOCK
+and a pointer to a
+.Bd -literal
+struct nfsd_args {
+ int sock; /* Socket to serve */
+ caddr_t name; /* Client address for connection based sockets */
+ int namelen;/* Length of name */
+};
+.Ed
+.Pp
+to pass a server side
+.Tn NFS
+socket into the kernel for servicing by the
+.Xr nfsd 8
+daemons.
+.Sh RETURN VALUES
+Normally
+.Fn nfssvc
+does not return unless the server
+is terminated by a signal when a value of 0 is returned.
+Otherwise, -1 is returned and the global variable
+.Va errno
+is set to specify the error.
+.Sh ERRORS
+.Bl -tag -width Er
+.It Bq Er ENEEDAUTH
+This special error value
+is really used for authentication support, particularly Kerberos,
+as explained above.
+.It Bq Er EPERM
+The caller is not the super-user.
+.El
+.Sh SEE ALSO
+.Xr mount_nfs 8 ,
+.Xr nfsd 8 ,
+.Xr nfsiod 8
+.Sh HISTORY
+The
+.Fn nfssvc
+system call first appeared in
+.Bx 4.4 .
+.Sh BUGS
+The
+.Fn nfssvc
+system call is designed specifically for the
+.Tn NFS
+support daemons and as such is specific to their requirements.
+It should really return values to indicate the need for authentication
+support, since
+.Er ENEEDAUTH
+is not really an error.
+Several fields of the argument structures are assumed to be valid and
+sometimes to be unchanged from a previous call, such that
+.Fn nfssvc
+must be used with extreme care.
diff --git a/lib/libc/sys/ntp_adjtime.2 b/lib/libc/sys/ntp_adjtime.2
new file mode 100644
index 000000000000..8ce78e7fb86e
--- /dev/null
+++ b/lib/libc/sys/ntp_adjtime.2
@@ -0,0 +1,315 @@
+.\" $NetBSD: ntp_adjtime.2,v 1.6 2003/04/16 13:34:55 wiz Exp $
+.\"
+.\" Copyright (c) 2001 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Thomas Klausner.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 July 13, 2005
+.Dt NTP_ADJTIME 2
+.Os
+.Sh NAME
+.Nm ntp_adjtime ,
+.Nm ntp_gettime
+.Nd Network Time Protocol (NTP) daemon interface system calls
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/timex.h
+.Ft int
+.Fn ntp_adjtime "struct timex *"
+.Ft int
+.Fn ntp_gettime "struct ntptimeval *"
+.Sh DESCRIPTION
+The two system calls
+.Fn ntp_adjtime
+and
+.Fn ntp_gettime
+are the kernel interface to the Network Time Protocol (NTP) daemon
+.Xr ntpd 8 .
+.Pp
+The
+.Fn ntp_adjtime
+function is used by the NTP daemon to adjust the system clock to an
+externally derived time.
+The time offset and related variables which are set by
+.Fn ntp_adjtime
+are used by
+.Fn hardclock
+to adjust the phase and frequency of the phase- or frequency-lock loop
+(PLL resp. FLL) which controls the system clock.
+.Pp
+The
+.Fn ntp_gettime
+function provides the time, maximum error (sync distance) and
+estimated error (dispersion) to client user application programs.
+.Pp
+In the following, all variables that refer PPS are only relevant if
+the
+.Em PPS_SYNC
+option is enabled in the kernel.
+.Pp
+.Fn ntp_adjtime
+has as argument a
+.Va struct timex *
+of the following form:
+.Bd -literal
+struct timex {
+ unsigned int modes; /* clock mode bits (wo) */
+ long offset; /* time offset (us) (rw) */
+ long freq; /* frequency offset (scaled ppm) (rw) */
+ long maxerror; /* maximum error (us) (rw) */
+ long esterror; /* estimated error (us) (rw) */
+ int status; /* clock status bits (rw) */
+ long constant; /* pll time constant (rw) */
+ long precision; /* clock precision (us) (ro) */
+ long tolerance; /* clock frequency tolerance (scaled
+ * ppm) (ro) */
+ /*
+ * The following read-only structure members are implemented
+ * only if the PPS signal discipline is configured in the
+ * kernel.
+ */
+ long ppsfreq; /* pps frequency (scaled ppm) (ro) */
+ long jitter; /* pps jitter (us) (ro) */
+ int shift; /* interval duration (s) (shift) (ro) */
+ long stabil; /* pps stability (scaled ppm) (ro) */
+ long jitcnt; /* jitter limit exceeded (ro) */
+ long calcnt; /* calibration intervals (ro) */
+ long errcnt; /* calibration errors (ro) */
+ long stbcnt; /* stability limit exceeded (ro) */
+};
+.Ed
+.Pp
+The members of this struct have the following meanings when used as
+argument for
+.Fn ntp_adjtime :
+.Bl -tag -width tolerance -compact
+.It Fa modes
+Defines what settings should be changed with the current
+.Fn ntp_adjtime
+call (write-only).
+Bitwise OR of the following:
+.Bl -tag -width MOD_TIMECONST -compact -offset indent
+.It MOD_OFFSET
+set time offset
+.It MOD_FREQUENCY
+set frequency offset
+.It MOD_MAXERROR
+set maximum time error
+.It MOD_ESTERROR
+set estimated time error
+.It MOD_STATUS
+set clock status bits
+.It MOD_TIMECONST
+set PLL time constant
+.It MOD_CLKA
+set clock A
+.It MOD_CLKB
+set clock B
+.El
+.It Fa offset
+Time offset (in microseconds), used by the PLL/FLL to adjust the
+system time in small increments (read-write).
+.It Fa freq
+Frequency offset (scaled ppm) (read-write).
+.It Fa maxerror
+Maximum error (in microseconds).
+Initialized by an
+.Fn ntp_adjtime
+call, and increased by the kernel once each second to reflect the maximum
+error bound growth (read-write).
+.It Fa esterror
+Estimated error (in microseconds).
+Set and read by
+.Fn ntp_adjtime ,
+but unused by the kernel (read-write).
+.It Fa status
+System clock status bits (read-write).
+Bitwise OR of the following:
+.Bl -tag -width STA_PPSJITTER -compact -offset indent
+.It STA_PLL
+Enable PLL updates (read-write).
+.It STA_PPSFREQ
+Enable PPS freq discipline (read-write).
+.It STA_PPSTIME
+Enable PPS time discipline (read-write).
+.It STA_FLL
+Select frequency-lock mode (read-write).
+.It STA_INS
+Insert leap (read-write).
+.It STA_DEL
+Delete leap (read-write).
+.It STA_UNSYNC
+Clock unsynchronized (read-write).
+.It STA_FREQHOLD
+Hold frequency (read-write).
+.It STA_PPSSIGNAL
+PPS signal present (read-only).
+.It STA_PPSJITTER
+PPS signal jitter exceeded (read-only).
+.It STA_PPSWANDER
+PPS signal wander exceeded (read-only).
+.It STA_PPSERROR
+PPS signal calibration error (read-only).
+.It STA_CLOCKERR
+Clock hardware fault (read-only).
+.El
+.It Fa constant
+PLL time constant, determines the bandwidth, or
+.Dq stiffness ,
+of the PLL (read-write).
+.It Fa precision
+Clock precision (in microseconds).
+In most cases the same as the kernel tick variable (see
+.Xr hz 9 ) .
+If a precision clock counter or external time-keeping signal is available,
+it could be much lower (and depend on the state of the signal)
+(read-only).
+.It Fa tolerance
+Maximum frequency error, or tolerance of the CPU clock oscillator (scaled
+ppm).
+Ordinarily a property of the architecture, but could change under
+the influence of external time-keeping signals (read-only).
+.It Fa ppsfreq
+PPS frequency offset produced by the frequency median filter (scaled
+ppm) (read-only).
+.It Fa jitter
+PPS jitter measured by the time median filter in microseconds
+(read-only).
+.It Fa shift
+Logarithm to base 2 of the interval duration in seconds (PPS,
+read-only).
+.It Fa stabil
+PPS stability (scaled ppm); dispersion (wander) measured by the
+frequency median filter (read-only).
+.It Fa jitcnt
+Number of seconds that have been discarded because the jitter measured
+by the time median filter exceeded the limit
+.Em MAXTIME
+(PPS, read-only).
+.It Fa calcnt
+Count of calibration intervals (PPS, read-only).
+.It Fa errcnt
+Number of calibration intervals that have been discarded because the
+wander exceeded the limit
+.Em MAXFREQ
+or where the calibration interval jitter exceeded two ticks (PPS,
+read-only).
+.It Fa stbcnt
+Number of calibration intervals that have been discarded because the
+frequency wander exceeded the limit
+.Em MAXFREQ Ns /4
+(PPS, read-only).
+.El
+After the
+.Fn ntp_adjtime
+call, the
+.Va struct timex *
+structure contains the current values of the corresponding variables.
+.Pp
+.Fn ntp_gettime
+has as argument a
+.Va struct ntptimeval *
+with the following members:
+.Bd -literal
+struct ntptimeval {
+ struct timeval time; /* current time (ro) */
+ long maxerror; /* maximum error (us) (ro) */
+ long esterror; /* estimated error (us) (ro) */
+};
+.Ed
+.Pp
+These have the following meaning:
+.Bl -tag -width tolerance -compact
+.It Fa time
+Current time (read-only).
+.It Fa maxerror
+Maximum error in microseconds (read-only).
+.It Fa esterror
+Estimated error in microseconds (read-only).
+.El
+.Sh RETURN VALUES
+.Fn ntp_adjtime
+and
+.Fn ntp_gettime
+return the current state of the clock on success, or any of the errors
+of
+.Xr copyin 9
+and
+.Xr copyout 9 .
+.Fn ntp_adjtime
+may additionally return
+.Er EPERM
+if the user calling
+.Fn ntp_adjtime
+does not have sufficient permissions.
+.Pp
+Possible states of the clock are:
+.Bl -tag -width TIME_ERROR -compact -offset indent
+.It TIME_OK
+Everything okay, no leap second warning.
+.It TIME_INS
+.Dq insert leap second
+warning.
+At the end of the day, a leap second will be inserted after 23:59:59.
+.It TIME_DEL
+.Dq delete leap second
+warning.
+At the end of the day, second 23:59:59 will be skipped.
+.It TIME_OOP
+Leap second in progress.
+.It TIME_WAIT
+Leap second has occurred within the last few seconds.
+.It TIME_ERROR
+Clock not synchronized.
+.El
+.Sh ERRORS
+The
+.Fn ntp_adjtime
+system call may return
+.Er EPERM
+if the caller
+does not have sufficient permissions.
+.Sh SEE ALSO
+.Xr options 4 ,
+.Xr ntpd 8 ,
+.Xr hardclock 9 ,
+.Xr hz 9
+.Bl -tag -width indent
+.It Pa http://www.bipm.fr/enus/5_Scientific/c_time/time_1.html
+.It Pa http://www.boulder.nist.gov/timefreq/general/faq.htm
+.It Pa ftp://time.nist.gov/pub/leap-seconds.list
+.El
+.Sh BUGS
+Take note that this
+.Tn API
+is extremely complex and stateful.
+Users should not attempt modification without first
+reviewing the
+.Xr ntpd 8
+sources in depth.
diff --git a/lib/libc/sys/numa_getaffinity.2 b/lib/libc/sys/numa_getaffinity.2
new file mode 100644
index 000000000000..efb78e988210
--- /dev/null
+++ b/lib/libc/sys/numa_getaffinity.2
@@ -0,0 +1,197 @@
+.\" Copyright (c) 2008 Christian Brueffer
+.\" Copyright (c) 2008 Jeffrey Roberson
+.\" Copyright (c) 2015 Adrian Chadd
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 May 7, 2015
+.Dt NUMA_GETAFFINITY 2
+.Os
+.Sh NAME
+.Nm numa_getaffinity ,
+.Nm numa_setaffinity
+.Nd manage NUMA affinity
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/param.h
+.In sys/numa.h
+.Ft int
+.Fn numa_getaffinity "cpuwhich_t which" "id_t id" "struct vm_domain_policy_entry *policy"
+.Ft int
+.Fn numa_setaffinity "cpuwhich_t which" "id_t id" "const struct vm_domain_policy_entry *policy"
+.Sh DESCRIPTION
+.Fn numa_getaffinity
+and
+.Fn numa_setaffinity
+allow the manipulation of NUMA policies available to processes and threads.
+These functions may manipulate NUMA policies that contain many processes
+or affect only a single object.
+.Pp
+Valid values for the
+.Fa which
+argument are documented in
+.Xr cpuset 2 .
+These arguments specify which object set are used.
+Only
+.Dv CPU_WHICH_TID
+and
+.Dv CPU_WHICH_PID
+can be manipulated.
+.Pp
+The
+.Fa policy
+entry contains a vm_domain_policy_entry with the following fields:
+.Bd -literal
+struct vm_domain_policy_entry {
+ vm_domain_policy_type_t policy; /* VM policy */
+ int domain; /* VM domain, if applicable */
+}
+.Ed
+.Fa vm_domain_policy_type_t policy
+is one these:
+.Bl -tag -width VM_POLICY_NONE
+.It Dv VM_POLICY_NONE
+Reset the domain back to none.
+Any parent object NUMA domain policy will apply.
+The only valid value for
+.Dv domain
+is -1.
+.It Dv VM_POLICY_ROUND_ROBIN
+Select round-robin policy.
+Pages will be allocated round-robin from each VM domain in order.
+The only valid value for
+.Dv domain
+is -1.
+.It Dv VM_POLICY_FIXED_DOMAIN
+Select fixed-domain only policy.
+Pages will be allocated from the given
+.Dv domain
+which must be set to a valid VM domain.
+Pages will not be allocated from another domain if
+.Dv domain
+is out of free pages.
+.It Dv VM_POLICY_FIXED_DOMAIN_ROUND_ROBIN
+Select fixed-domain only policy.
+Pages will be allocated from
+.Dv domain
+which must be set to a valid VM domain.
+If page allocation fails, pages will be round-robin
+allocated from another domain if
+.Dv domain
+is out of free pages.
+.It Dv VM_POLICY_FIRST_TOUCH
+Select first-touch policy.
+Pages will be allocated from the NUMA domain which the thread
+is currently scheduled upon.
+Pages will not be allocated from another domain if the current domain
+is out of free pages.
+The only valid value for
+.Dv domain
+is -1.
+.It Dv VM_POLICY_FIRST_TOUCH_ROUND_ROBIN
+Select first-touch policy.
+Pages will be allocated from the NUMA domain which the thread
+is currently scheduled upon.
+Pages will be allocated round-robin from another domain if the
+current domain is out of free pages.
+The only valid value for
+.Dv domain
+is -1.
+.El
+.Pp
+Note that the VM might assign some pages from other domains.
+For example, if an existing page allocation is covered by a superpage
+allocation.
+.Pp
+.Fn numa_getaffinity
+retrieves the
+NUMA policy from the object specified by
+.Fa which
+and
+.Fa id
+and stores it in the space provided by
+.Fa policy .
+.Pp
+.Fn numa_setaffinity
+attempts to set the NUMA policy for the object specified by
+.Fa which
+and
+.Fa id
+to the policy in
+.Fa policy .
+.Sh RETURN VALUES
+.Rv -std
+.Sh ERRORS
+.Va errno
+can contain these error codes:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa level
+or
+.Fa which
+argument was not a valid value.
+.It Bq Er EINVAL
+The
+.Fa policy
+argument specified when calling
+.Fn numa_setaffinity
+did not contain a valid policy.
+.It Bq Er EFAULT
+The policy pointer passed was invalid.
+.It Bq Er ESRCH
+The object specified by the
+.Fa id
+and
+.Fa which
+arguments could not be found.
+.It Bq Er ERANGE
+The
+.Fa domain
+in the given policy
+was out of the range of possible VM domains available.
+.It Bq Er EPERM
+The calling process did not have the credentials required to complete the
+operation.
+.El
+.Sh SEE ALSO
+.Xr cpuset 1 ,
+.Xr numactl 1 ,
+.Xr cpuset 2 ,
+.Xr cpuset_getaffinity 2 ,
+.Xr cpuset_getid 2 ,
+.Xr cpuset_setaffinity 2 ,
+.Xr cpuset_setid 2 ,
+.Xr pthread_affinity_np 3 ,
+.Xr pthread_attr_affinity_np 3 ,
+.Xr numa 4
+.Sh HISTORY
+The
+.Nm
+family of system calls first appeared in
+.Fx 11.0 .
+.Sh AUTHORS
+.An Adrian Chadd Aq Mt adrian@FreeBSD.org
diff --git a/lib/libc/sys/open.2 b/lib/libc/sys/open.2
new file mode 100644
index 000000000000..c1701188b49a
--- /dev/null
+++ b/lib/libc/sys/open.2
@@ -0,0 +1,532 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)open.2 8.2 (Berkeley) 11/16/93
+.\" $FreeBSD$
+.\"
+.Dd November 22, 2016
+.Dt OPEN 2
+.Os
+.Sh NAME
+.Nm open , openat
+.Nd open or create a file for reading, writing or executing
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In fcntl.h
+.Ft int
+.Fn open "const char *path" "int flags" "..."
+.Ft int
+.Fn openat "int fd" "const char *path" "int flags" "..."
+.Sh DESCRIPTION
+The file name specified by
+.Fa path
+is opened
+for either execution or reading and/or writing as specified by the
+argument
+.Fa flags
+and the file descriptor returned to the calling process.
+The
+.Fa flags
+argument may indicate the file is to be
+created if it does not exist (by specifying the
+.Dv O_CREAT
+flag).
+In this case
+.Fn open
+and
+.Fn openat
+require an additional argument
+.Fa "mode_t mode" ,
+and the file is created with mode
+.Fa mode
+as described in
+.Xr chmod 2
+and modified by the process' umask value (see
+.Xr umask 2 ) .
+.Pp
+The
+.Fn openat
+function is equivalent to the
+.Fn open
+function except in the case where the
+.Fa path
+specifies a relative path.
+In this case the file to be opened is determined relative to the directory
+associated with the file descriptor
+.Fa fd
+instead of the current working directory.
+The
+.Fa flag
+parameter and the optional fourth parameter correspond exactly to
+the parameters of
+.Fn open .
+If
+.Fn openat
+is passed the special value
+.Dv AT_FDCWD
+in the
+.Fa fd
+parameter, the current working directory is used
+and the behavior is identical to a call to
+.Fn open .
+.Pp
+In
+.Xr capsicum 4
+capability mode,
+.Fn open
+is not permitted.
+The
+.Fa path
+argument to
+.Fn openat
+must be strictly relative to a file descriptor
+.Fa fd ,
+as defined in
+.Pa sys/kern/vfs_lookup.c .
+.Fa path
+must not be an absolute path and must not contain ".." components.
+Additionally, no symbolic link in
+.Fa path
+may contain ".." components either.
+.Fa fd
+must not be
+.Dv AT_FDCWD .
+.Pp
+The flags specified are formed by
+.Em or Ns 'ing
+the following values
+.Pp
+.Bd -literal -offset indent -compact
+O_RDONLY open for reading only
+O_WRONLY open for writing only
+O_RDWR open for reading and writing
+O_EXEC open for execute only
+O_NONBLOCK do not block on open
+O_APPEND append on each write
+O_CREAT create file if it does not exist
+O_TRUNC truncate size to 0
+O_EXCL error if create and file exists
+O_SHLOCK atomically obtain a shared lock
+O_EXLOCK atomically obtain an exclusive lock
+O_DIRECT eliminate or reduce cache effects
+O_FSYNC synchronous writes
+O_SYNC synchronous writes
+O_NOFOLLOW do not follow symlinks
+O_NOCTTY ignored
+O_TTY_INIT ignored
+O_DIRECTORY error if file is not a directory
+O_CLOEXEC set FD_CLOEXEC upon open
+.Ed
+.Pp
+Opening a file with
+.Dv O_APPEND
+set causes each write on the file
+to be appended to the end.
+If
+.Dv O_TRUNC
+is specified and the
+file exists, the file is truncated to zero length.
+If
+.Dv O_EXCL
+is set with
+.Dv O_CREAT
+and the file already
+exists,
+.Fn open
+returns an error.
+This may be used to
+implement a simple exclusive access locking mechanism.
+If
+.Dv O_EXCL
+is set and the last component of the pathname is
+a symbolic link,
+.Fn open
+will fail even if the symbolic
+link points to a non-existent name.
+If the
+.Dv O_NONBLOCK
+flag is specified and the
+.Fn open
+system call would result
+in the process being blocked for some reason (e.g., waiting for
+carrier on a dialup line),
+.Fn open
+returns immediately.
+The descriptor remains in non-blocking mode for subsequent operations.
+.Pp
+If
+.Dv O_FSYNC
+is used in the mask, all writes will
+immediately be written to disk,
+the kernel will not cache written data
+and all writes on the descriptor will not return until
+the data to be written completes.
+.Pp
+.Dv O_SYNC
+is a synonym for
+.Dv O_FSYNC
+required by
+.Tn POSIX .
+.Pp
+If
+.Dv O_NOFOLLOW
+is used in the mask and the target file passed to
+.Fn open
+is a symbolic link then the
+.Fn open
+will fail.
+.Pp
+When opening a file, a lock with
+.Xr flock 2
+semantics can be obtained by setting
+.Dv O_SHLOCK
+for a shared lock, or
+.Dv O_EXLOCK
+for an exclusive lock.
+If creating a file with
+.Dv O_CREAT ,
+the request for the lock will never fail
+(provided that the underlying file system supports locking).
+.Pp
+.Dv O_DIRECT
+may be used to minimize or eliminate the cache effects of reading and writing.
+The system will attempt to avoid caching the data you read or write.
+If it cannot avoid caching the data,
+it will minimize the impact the data has on the cache.
+Use of this flag can drastically reduce performance if not used with care.
+.Pp
+.Dv O_NOCTTY
+may be used to ensure the OS does not assign this file as the
+controlling terminal when it opens a tty device.
+This is the default on
+.Fx ,
+but is present for
+.Tn POSIX
+compatibility.
+The
+.Fn open
+system call will not assign controlling terminals on
+.Fx .
+.Pp
+.Dv O_TTY_INIT
+may be used to ensure the OS restores the terminal attributes when
+initially opening a TTY.
+This is the default on
+.Fx ,
+but is present for
+.Tn POSIX
+compatibility.
+The initial call to
+.Fn open
+on a TTY will always restore default terminal attributes on
+.Fx .
+.Pp
+.Dv O_DIRECTORY
+may be used to ensure the resulting file descriptor refers to a
+directory.
+This flag can be used to prevent applications with elevated privileges
+from opening files which are even unsafe to open with
+.Dv O_RDONLY ,
+such as device nodes.
+.Pp
+.Dv O_CLOEXEC
+may be used to set
+.Dv FD_CLOEXEC
+flag for the newly returned file descriptor.
+.Pp
+If successful,
+.Fn open
+returns a non-negative integer, termed a file descriptor.
+It returns \-1 on failure.
+The file pointer used to mark the current position within the
+file is set to the beginning of the file.
+.Pp
+If a sleeping open of a device node from
+.Xr devfs 5
+is interrupted by a signal, the call always fails with
+.Er EINTR ,
+even if the
+.Dv SA_RESTART
+flag is set for the signal.
+A sleeping open of a fifo (see
+.Xr mkfifo 2 )
+is restarted as normal.
+.Pp
+When a new file is created it is given the group of the directory
+which contains it.
+.Pp
+Unless
+.Dv O_CLOEXEC
+flag was specified,
+the new descriptor is set to remain open across
+.Xr execve 2
+system calls; see
+.Xr close 2 ,
+.Xr fcntl 2
+and
+.Dv O_CLOEXEC
+description.
+.Pp
+The system imposes a limit on the number of file descriptors
+open simultaneously by one process.
+The
+.Xr getdtablesize 2
+system call returns the current system limit.
+.Sh RETURN VALUES
+If successful,
+.Fn open
+and
+.Fn openat
+return a non-negative integer, termed a file descriptor.
+They return \-1 on failure, and set
+.Va errno
+to indicate the error.
+.Sh ERRORS
+The named file is opened unless:
+.Bl -tag -width Er
+.It Bq Er ENOTDIR
+A component of the path prefix is not a directory.
+.It Bq Er ENAMETOOLONG
+A component of a pathname exceeded 255 characters,
+or an entire path name exceeded 1023 characters.
+.It Bq Er ENOENT
+.Dv O_CREAT
+is not set and the named file does not exist.
+.It Bq Er ENOENT
+A component of the path name that must exist does not exist.
+.It Bq Er EACCES
+Search permission is denied for a component of the path prefix.
+.It Bq Er EACCES
+The required permissions (for reading and/or writing)
+are denied for the given flags.
+.It Bq Er EACCES
+.Dv O_TRUNC
+is specified and write permission is denied.
+.It Bq Er EACCES
+.Dv O_CREAT
+is specified,
+the file does not exist,
+and the directory in which it is to be created
+does not permit writing.
+.It Bq Er EPERM
+.Dv O_CREAT
+is specified, the file does not exist, and the directory in which it is to be
+created has its immutable flag set, see the
+.Xr chflags 2
+manual page for more information.
+.It Bq Er EPERM
+The named file has its immutable flag set and the file is to be modified.
+.It Bq Er EPERM
+The named file has its append-only flag set, the file is to be modified, and
+.Dv O_TRUNC
+is specified or
+.Dv O_APPEND
+is not specified.
+.It Bq Er ELOOP
+Too many symbolic links were encountered in translating the pathname.
+.It Bq Er EISDIR
+The named file is a directory, and the arguments specify
+it is to be modified.
+.It Bq Er EROFS
+The named file resides on a read-only file system,
+and the file is to be modified.
+.It Bq Er EROFS
+.Dv O_CREAT
+is specified and the named file would reside on a read-only file system.
+.It Bq Er EMFILE
+The process has already reached its limit for open file descriptors.
+.It Bq Er ENFILE
+The system file table is full.
+.It Bq Er EMLINK
+.Dv O_NOFOLLOW
+was specified and the target is a symbolic link.
+.It Bq Er ENXIO
+The named file is a character special or block
+special file, and the device associated with this special file
+does not exist.
+.It Bq Er ENXIO
+.Dv O_NONBLOCK
+is set, the named file is a fifo,
+.Dv O_WRONLY
+is set, and no process has the file open for reading.
+.It Bq Er EINTR
+The
+.Fn open
+operation was interrupted by a signal.
+.It Bq Er EOPNOTSUPP
+.Dv O_SHLOCK
+or
+.Dv O_EXLOCK
+is specified but the underlying file system does not support locking.
+.It Bq Er EOPNOTSUPP
+The named file is a special file mounted through a file system that
+does not support access to it (e.g.\& NFS).
+.It Bq Er EWOULDBLOCK
+.Dv O_NONBLOCK
+and one of
+.Dv O_SHLOCK
+or
+.Dv O_EXLOCK
+is specified and the file is locked.
+.It Bq Er ENOSPC
+.Dv O_CREAT
+is specified,
+the file does not exist,
+and the directory in which the entry for the new file is being placed
+cannot be extended because there is no space left on the file
+system containing the directory.
+.It Bq Er ENOSPC
+.Dv O_CREAT
+is specified,
+the file does not exist,
+and there are no free inodes on the file system on which the
+file is being created.
+.It Bq Er EDQUOT
+.Dv O_CREAT
+is specified,
+the file does not exist,
+and the directory in which the entry for the new file
+is being placed cannot be extended because the
+user's quota of disk blocks on the file system
+containing the directory has been exhausted.
+.It Bq Er EDQUOT
+.Dv O_CREAT
+is specified,
+the file does not exist,
+and the user's quota of inodes on the file system on
+which the file is being created has been exhausted.
+.It Bq Er EIO
+An I/O error occurred while making the directory entry or
+allocating the inode for
+.Dv O_CREAT .
+.It Bq Er ETXTBSY
+The file is a pure procedure (shared text) file that is being
+executed and the
+.Fn open
+system call requests write access.
+.It Bq Er EFAULT
+The
+.Fa path
+argument
+points outside the process's allocated address space.
+.It Bq Er EEXIST
+.Dv O_CREAT
+and
+.Dv O_EXCL
+were specified and the file exists.
+.It Bq Er EOPNOTSUPP
+An attempt was made to open a socket (not currently implemented).
+.It Bq Er EINVAL
+An attempt was made to open a descriptor with an illegal combination
+of
+.Dv O_RDONLY ,
+.Dv O_WRONLY ,
+.Dv O_RDWR
+and
+.Dv O_EXEC .
+.It Bq Er EBADF
+The
+.Fa path
+argument does not specify an absolute path and the
+.Fa fd
+argument is
+neither
+.Dv AT_FDCWD
+nor a valid file descriptor open for searching.
+.It Bq Er ENOTDIR
+The
+.Fa path
+argument is not an absolute path and
+.Fa fd
+is neither
+.Dv AT_FDCWD
+nor a file descriptor associated with a directory.
+.It Bq Er ENOTDIR
+.Dv O_DIRECTORY
+is specified and the file is not a directory.
+.It Bq Er ECAPMODE
+.Dv AT_FDCWD
+is specified and the process is in capability mode.
+.It Bq Er ECAPMODE
+.Fn open
+was called and the process is in capability mode.
+.It Bq Er ENOTCAPABLE
+.Fa path
+is an absolute path or contained "..".
+.El
+.Sh SEE ALSO
+.Xr capsicum 4 ,
+.Xr chmod 2 ,
+.Xr close 2 ,
+.Xr dup 2 ,
+.Xr fexecve 2 ,
+.Xr fhopen 2 ,
+.Xr getdtablesize 2 ,
+.Xr getfh 2 ,
+.Xr lgetfh 2 ,
+.Xr lseek 2 ,
+.Xr read 2 ,
+.Xr umask 2 ,
+.Xr write 2 ,
+.Xr fopen 3
+.Sh HISTORY
+The
+.Fn open
+function appeared in
+.At v6 .
+The
+.Fn openat
+function was introduced in
+.Fx 8.0 .
+.Sh STANDARDS
+These functions are specified by
+.St -p1003.1-2008 .
+.Fx
+sets
+.Va errno
+to
+.Er EMLINK instead of
+.Er ELOOP
+as specified by
+.Tn POSIX
+when
+.Dv O_NOFOLLOW
+is set in flags and the final component of pathname is a symbolic link
+to distinguish it from the case of too many symbolic link traversals
+in one of its non-final components.
+.Sh BUGS
+The Open Group Extended API Set 2 specification requires that the test
+for whether
+.Fa fd
+is searchable is based on whether
+.Fa fd
+is open for searching, not whether the underlying directory currently
+permits searches.
+The present implementation of the
+.Fa openat
+checks the current permissions of directory instead.
diff --git a/lib/libc/sys/open.c b/lib/libc/sys/open.c
new file mode 100644
index 000000000000..e0273c68a34c
--- /dev/null
+++ b/lib/libc/sys/open.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2014 The FreeBSD Foundation.
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Konstantin Belousov
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice(s), this list of conditions and the following disclaimer as
+ * the first lines of this file unmodified other than the possible
+ * addition of one or more copyright notices.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice(s), this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/fcntl.h>
+#include <stdarg.h>
+#include "libc_private.h"
+
+__weak_reference(__sys_open, __open);
+
+#pragma weak open
+int
+open(const char *path, int flags, ...)
+{
+ va_list ap;
+ int mode;
+
+ if ((flags & O_CREAT) != 0) {
+ va_start(ap, flags);
+ mode = va_arg(ap, int);
+ va_end(ap);
+ } else {
+ mode = 0;
+ }
+ return (((int (*)(int, const char *, int, ...))
+ __libc_interposing[INTERPOS_openat])(AT_FDCWD, path, flags, mode));
+}
diff --git a/lib/libc/sys/openat.c b/lib/libc/sys/openat.c
new file mode 100644
index 000000000000..1bd12ea2a8d8
--- /dev/null
+++ b/lib/libc/sys/openat.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2014 The FreeBSD Foundation.
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Konstantin Belousov
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice(s), this list of conditions and the following disclaimer as
+ * the first lines of this file unmodified other than the possible
+ * addition of one or more copyright notices.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice(s), this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/fcntl.h>
+#include <stdarg.h>
+#include "libc_private.h"
+
+__weak_reference(__sys_openat, __openat);
+__sym_compat(openat, __impl_openat, FBSD_1.1);
+__weak_reference(openat, __impl_openat);
+__sym_default(openat, openat, FBSD_1.2);
+
+#pragma weak openat
+int
+openat(int fd, const char *path, int flags, ...)
+{
+ va_list ap;
+ int mode;
+
+ if ((flags & O_CREAT) != 0) {
+ va_start(ap, flags);
+ mode = va_arg(ap, int);
+ va_end(ap);
+ } else {
+ mode = 0;
+ }
+ return (((int (*)(int, const char *, int, ...))
+ __libc_interposing[INTERPOS_openat])(fd, path, flags, mode));
+}
diff --git a/lib/libc/sys/pathconf.2 b/lib/libc/sys/pathconf.2
new file mode 100644
index 000000000000..efa13387d651
--- /dev/null
+++ b/lib/libc/sys/pathconf.2
@@ -0,0 +1,261 @@
+.\" Copyright (c) 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)pathconf.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd July 7, 2009
+.Dt PATHCONF 2
+.Os
+.Sh NAME
+.Nm pathconf ,
+.Nm lpathconf ,
+.Nm fpathconf
+.Nd get configurable pathname variables
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft long
+.Fn pathconf "const char *path" "int name"
+.Ft long
+.Fn lpathconf "const char *path" "int name"
+.Ft long
+.Fn fpathconf "int fd" "int name"
+.Sh DESCRIPTION
+The
+.Fn pathconf ,
+.Fn lpathconf
+and
+.Fn fpathconf
+system calls provide a method for applications to determine the current
+value of a configurable system limit or option variable associated
+with a pathname or file descriptor.
+.Pp
+For
+.Fn pathconf
+and
+.Fn lpathconf ,
+the
+.Fa path
+argument is the name of a file or directory.
+For
+.Fn fpathconf ,
+the
+.Fa fd
+argument is an open file descriptor.
+The
+.Fa name
+argument specifies the system variable to be queried.
+Symbolic constants for each name value are found in the include file
+.Li <unistd.h> .
+.Pp
+The
+.Fn lpathconf
+system call is like
+.Fn pathconf
+except in the case where the named file is a symbolic link,
+in which case
+.Fn lpathconf
+returns information about the link,
+while
+.Fn pathconf
+returns information about the file the link references.
+.Pp
+The available values are as follows:
+.Bl -tag -width 6n
+.It Li _PC_LINK_MAX
+The maximum file link count.
+.It Li _PC_MAX_CANON
+The maximum number of bytes in terminal canonical input line.
+.It Li _PC_MAX_INPUT
+The minimum maximum number of bytes for which space is available in
+a terminal input queue.
+.It Li _PC_NAME_MAX
+The maximum number of bytes in a file name.
+.It Li _PC_PATH_MAX
+The maximum number of bytes in a pathname.
+.It Li _PC_PIPE_BUF
+The maximum number of bytes which will be written atomically to a pipe.
+.It Li _PC_CHOWN_RESTRICTED
+Return 1 if appropriate privilege is required for the
+.Xr chown 2
+system call, otherwise 0.
+.St -p1003.1-2001
+requires appropriate privilege in all cases, but this behavior was optional
+in prior editions of the standard.
+.It Li _PC_NO_TRUNC
+Return greater than zero if attempts to use pathname components longer than
+.Brq Dv NAME_MAX
+will result in an
+.Bq Er ENAMETOOLONG
+error; otherwise, such components will be truncated to
+.Brq Dv NAME_MAX .
+.St -p1003.1-2001
+requires the error in all cases, but this behavior was optional in prior
+editions of the standard, and some
+.No non- Ns Tn POSIX Ns -compliant
+file systems do not support this behavior.
+.It Li _PC_VDISABLE
+Returns the terminal character disabling value.
+.It Li _PC_ASYNC_IO
+Return 1 if asynchronous I/O is supported, otherwise 0.
+.It Li _PC_PRIO_IO
+Returns 1 if prioritised I/O is supported for this file,
+otherwise 0.
+.It Li _PC_SYNC_IO
+Returns 1 if synchronised I/O is supported for this file, otherwise 0.
+.It Li _PC_ALLOC_SIZE_MIN
+Minimum number of bytes of storage allocated for any portion of a file.
+.It Li _PC_FILESIZEBITS
+Number of bits needed to represent the maximum file size.
+.It Li _PC_REC_INCR_XFER_SIZE
+Recommended increment for file transfer sizes between
+.Dv _PC_REC_MIN_XFER_SIZE
+and
+.Dv _PC_REC_MAX_XFER_SIZE .
+.It Li _PC_REC_MAX_XFER_SIZE
+Maximum recommended file transfer size.
+.It Li _PC_REC_MIN_XFER_SIZE
+Minimum recommended file transfer size.
+.It Li _PC_REC_XFER_ALIGN
+Recommended file transfer buffer alignment.
+.It Li _PC_SYMLINK_MAX
+Maximum number of bytes in a symbolic link.
+.It Li _PC_ACL_EXTENDED
+Returns 1 if an Access Control List (ACL) can be set on the specified
+file, otherwise 0.
+.It Li _PC_ACL_NFS4
+Returns 1 if an NFSv4 ACLs can be set on the specified
+file, otherwise 0.
+.It Li _PC_ACL_PATH_MAX
+Maximum number of ACL entries per file.
+.It Li _PC_CAP_PRESENT
+Returns 1 if a capability state can be set on the specified file,
+otherwise 0.
+.It Li _PC_INF_PRESENT
+Returns 1 if an information label can be set on the specified file,
+otherwise 0.
+.It Li _PC_MAC_PRESENT
+Returns 1 if a Mandatory Access Control (MAC) label can be set on the
+specified file, otherwise 0.
+.It Li _PC_MIN_HOLE_SIZE
+If a file system supports the reporting of holes (see
+.Xr lseek 2 ) ,
+.Fn pathconf
+and
+.Fn fpathconf
+return a positive number that represents the minimum hole size returned in
+bytes.
+The offsets of holes returned will be aligned to this same value.
+A special value of 1 is returned if the file system does not specify the minimum
+hole size but still reports holes.
+.El
+.Sh RETURN VALUES
+If the call to
+.Fn pathconf
+or
+.Fn fpathconf
+is not successful, \-1 is returned and
+.Va errno
+is set appropriately.
+Otherwise, if the variable is associated with functionality that does
+not have a limit in the system, \-1 is returned and
+.Va errno
+is not modified.
+Otherwise, the current variable value is returned.
+.Sh ERRORS
+If any of the following conditions occur, the
+.Fn pathconf
+and
+.Fn fpathconf
+system calls shall return -1 and set
+.Va errno
+to the corresponding value.
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The value of the
+.Fa name
+argument is invalid.
+.It Bq Er EINVAL
+The implementation does not support an association of the variable
+name with the associated file.
+.El
+.Pp
+The
+.Fn pathconf
+system call
+will fail if:
+.Bl -tag -width Er
+.It Bq Er ENOTDIR
+A component of the path prefix is not a directory.
+.It Bq Er ENAMETOOLONG
+A component of a pathname exceeded
+.Brq Dv NAME_MAX
+characters (but see
+.Dv _PC_NO_TRUNC
+above),
+or an entire path name exceeded
+.Brq Dv PATH_MAX
+characters.
+.It Bq Er ENOENT
+The named file does not exist.
+.It Bq Er EACCES
+Search permission is denied for a component of the path prefix.
+.It Bq Er ELOOP
+Too many symbolic links were encountered in translating the pathname.
+.It Bq Er EIO
+An I/O error occurred while reading from or writing to the file system.
+.El
+.Pp
+The
+.Fn fpathconf
+system call
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa fd
+argument
+is not a valid open file descriptor.
+.It Bq Er EIO
+An I/O error occurred while reading from or writing to the file system.
+.El
+.Sh SEE ALSO
+.Xr lseek 2 ,
+.Xr sysctl 3
+.Sh HISTORY
+The
+.Fn pathconf
+and
+.Fn fpathconf
+system calls first appeared in
+.Bx 4.4 .
+The
+.Fn lpathconf
+system call first appeared in
+.Fx 8.0 .
diff --git a/lib/libc/sys/pdfork.2 b/lib/libc/sys/pdfork.2
new file mode 100644
index 000000000000..5f1a86e3b961
--- /dev/null
+++ b/lib/libc/sys/pdfork.2
@@ -0,0 +1,202 @@
+.\"
+.\" Copyright (c) 2009-2010, 2012-2013 Robert N. M. Watson
+.\" All rights reserved.
+.\"
+.\" This software was developed at the University of Cambridge Computer
+.\" Laboratory with support from a grant from Google, Inc.
+.\"
+.\" This software was developed by SRI International and the University of
+.\" Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
+.\" ("CTSRD"), as part of the DARPA CRASH research programme.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd June 8, 2016
+.Dt PDFORK 2
+.Os
+.Sh NAME
+.Nm pdfork ,
+.Nm pdgetpid ,
+.Nm pdkill ,
+.Nm pdwait4
+.Nd System calls to manage process descriptors
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/procdesc.h
+.Ft pid_t
+.Fn pdfork "int *fdp" "int flags"
+.Ft int
+.Fn pdgetpid "int fd" "pid_t *pidp"
+.Ft int
+.Fn pdkill "int fd" "int signum"
+.Ft int
+.Fn pdwait4 "int fd" "int *status" "int options" "struct rusage *rusage"
+.Sh DESCRIPTION
+Process descriptors are special file descriptors that represent processes,
+and are created using
+.Fn pdfork ,
+a variant of
+.Xr fork 2 ,
+which, if successful, returns a process descriptor in the integer pointed to
+by
+.Fa fdp .
+Processes created via
+.Fn pdfork
+will not cause
+.Dv SIGCHLD
+on termination.
+.Fn pdfork
+can accept the flags:
+.Bl -tag -width ".Dv PD_DAEMON"
+.It Dv PD_DAEMON
+Instead of the default terminate-on-close behaviour, allow the process to
+live until it is explicitly killed with
+.Xr kill 2 .
+.Pp
+This option is not permitted in
+.Xr capsicum 4
+capability mode (see
+.Xr cap_enter 2 ) .
+.El
+.Bl -tag -width ".Dv PD_DAEMON"
+.It Dv PD_CLOEXEC
+Set close-on-exec on process descriptor.
+.El
+.Pp
+.Fn pdgetpid
+queries the process ID (PID) in the process descriptor
+.Fa fd .
+.Pp
+.Fn pdkill
+is functionally identical to
+.Xr kill 2 ,
+except that it accepts a process descriptor,
+.Fa fd ,
+rather than a PID.
+.Pp
+.Fn pdwait4
+behaves identically to
+.Xr wait4 2 ,
+but operates with respect to a process descriptor argument rather than a PID.
+.Pp
+The following system calls also have effects specific to process descriptors:
+.Pp
+.Xr fstat 2
+queries status of a process descriptor; currently only the
+.Fa st_mode ,
+.Fa st_birthtime ,
+.Fa st_atime ,
+.Fa st_ctime
+and
+.Fa st_mtime
+fields are defined.
+If the owner read, write, and execute bits are set then the
+process represented by the process descriptor is still alive.
+.Pp
+.Xr poll 2
+and
+.Xr select 2
+allow waiting for process state transitions; currently only
+.Dv POLLHUP
+is defined, and will be raised when the process dies.
+Process state transitions can also be monitored using
+.Xr kqueue 2
+filter
+.Dv EVFILT_PROCDESC ;
+currently only
+.Dv NOTE_EXIT
+is implemented.
+.Pp
+.Xr close 2
+will close the process descriptor unless
+.Dv PD_DAEMON
+is set; if the process is still alive and this is
+the last reference to the process descriptor, the process will be terminated
+with the signal
+.Dv SIGKILL .
+.Sh RETURN VALUES
+.Fn pdfork
+returns a PID, 0 or -1, as
+.Xr fork 2
+does.
+.Pp
+.Fn pdgetpid
+and
+.Fn pdkill
+return 0 on success and -1 on failure.
+.Pp
+.Fn pdwait4
+returns a PID on success and -1 on failure.
+.Sh ERRORS
+These functions may return the same error numbers as their PID-based equivalents
+(e.g.
+.Fn pdfork
+may return the same error numbers as
+.Xr fork 2 ) ,
+with the following additions:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The signal number given to
+.Fn pdkill
+is invalid.
+.It Bq Er ENOTCAPABLE
+The process descriptor being operated on has insufficient rights (e.g.
+.Dv CAP_PDKILL
+for
+.Fn pdkill ) .
+.El
+.Sh SEE ALSO
+.Xr close 2 ,
+.Xr fork 2 ,
+.Xr fstat 2 ,
+.Xr kill 2 ,
+.Xr poll 2 ,
+.Xr wait4 2 ,
+.Xr capsicum 4 ,
+.Xr procdesc 4
+.Sh HISTORY
+The
+.Fn pdfork ,
+.Fn pdgetpid ,
+.Fn pdkill
+and
+.Fn pdwait4
+system calls first appeared in
+.Fx 9.0 .
+.Pp
+Support for process descriptors mode was developed as part of the
+.Tn TrustedBSD
+Project.
+.Sh AUTHORS
+.An -nosplit
+These functions and the capability facility were created by
+.An Robert N. M. Watson Aq Mt rwatson@FreeBSD.org
+and
+.An Jonathan Anderson Aq Mt jonathan@FreeBSD.org
+at the University of Cambridge Computer Laboratory with support from a grant
+from Google, Inc.
+.Sh BUGS
+.Fn pdwait4
+has not yet been implemented.
diff --git a/lib/libc/sys/pipe.2 b/lib/libc/sys/pipe.2
new file mode 100644
index 000000000000..63e013a014b0
--- /dev/null
+++ b/lib/libc/sys/pipe.2
@@ -0,0 +1,178 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)pipe.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd July 20, 2016
+.Dt PIPE 2
+.Os
+.Sh NAME
+.Nm pipe ,
+.Nm pipe2
+.Nd create descriptor pair for interprocess communication
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft int
+.Fn pipe "int fildes[2]"
+.Ft int
+.Fn pipe2 "int fildes[2]" "int flags"
+.Sh DESCRIPTION
+The
+.Fn pipe
+function
+creates a
+.Em pipe ,
+which is an object allowing
+bidirectional data flow,
+and allocates a pair of file descriptors.
+.Pp
+The
+.Fn pipe2
+system call allows control over the attributes of the file descriptors
+via the
+.Fa flags
+argument.
+Values for
+.Fa flags
+are constructed by a bitwise-inclusive OR of flags from the following
+list, defined in
+.In fcntl.h :
+.Bl -tag -width ".Dv O_NONBLOCK"
+.It Dv O_CLOEXEC
+Set the close-on-exec flag for the new file descriptors.
+.It Dv O_NONBLOCK
+Set the non-blocking flag for the ends of the pipe.
+.El
+.Pp
+If the
+.Fa flags
+argument is 0, the behavior is identical to a call to
+.Fn pipe .
+.Pp
+By convention, the first descriptor is normally used as the
+.Em read end
+of the pipe,
+and the second is normally the
+.Em write end ,
+so that data written to
+.Fa fildes[1]
+appears on (i.e., can be read from)
+.Fa fildes[0] .
+This allows the output of one program to be
+sent
+to another program:
+the source's standard output is set up to be
+the write end of the pipe,
+and the sink's standard input is set up to be
+the read end of the pipe.
+The pipe itself persists until all its associated descriptors are
+closed.
+.Pp
+A pipe that has had an end closed is considered
+.Em widowed .
+Writing on such a pipe causes the writing process to receive
+a
+.Dv SIGPIPE
+signal.
+Widowing a pipe is the only way to deliver end-of-file to a reader:
+after the reader consumes any buffered data, reading a widowed pipe
+returns a zero count.
+.Pp
+The bidirectional nature of this implementation of pipes is not
+portable to older systems, so it is recommended to use the convention
+for using the endpoints in the traditional manner when using a
+pipe in one direction.
+.Sh IMPLEMENTATION NOTES
+The
+.Fn pipe
+function calls the
+.Fn pipe2
+system call.
+As a result, system call traces such as those captured by
+.Xr dtrace 1
+or
+.Xr ktrace 1
+will show calls to
+.Fn pipe2 .
+.Sh RETURN VALUES
+.Rv -std pipe
+.Sh ERRORS
+The
+.Fn pipe
+and
+.Fn pipe2
+system calls will fail if:
+.Bl -tag -width Er
+.It Bq Er EFAULT
+.Ar fildes
+argument points to an invalid memory location.
+.It Bq Er EMFILE
+Too many descriptors are active.
+.It Bq Er ENFILE
+The system file table is full.
+.It Bq Er ENOMEM
+Not enough kernel memory to establish a pipe.
+.El
+.Pp
+The
+.Fn pipe2
+system call will also fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa flags
+argument is invalid.
+.El
+.Sh SEE ALSO
+.Xr sh 1 ,
+.Xr fork 2 ,
+.Xr read 2 ,
+.Xr socketpair 2 ,
+.Xr write 2
+.Sh HISTORY
+The
+.Fn pipe
+function appeared in
+.At v3 .
+.Pp
+Bidirectional pipes were first used on
+.At V.4 .
+.Pp
+The
+.Fn pipe2
+function appeared in
+.Fx 10.0 .
+.Pp
+The
+.Fn pipe
+function became a wrapper around
+.Fn pipe2
+in
+.Fx 11.0 .
diff --git a/lib/libc/sys/pipe.c b/lib/libc/sys/pipe.c
new file mode 100644
index 000000000000..f5ade0eb914b
--- /dev/null
+++ b/lib/libc/sys/pipe.c
@@ -0,0 +1,47 @@
+/*-
+ * Copyright (c) 2016 SRI International
+ * All rights reserved.
+ *
+ * This software was developed by SRI International and the University of
+ * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237
+ * ("CTSRD"), as part of the DARPA CRASH research programme.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/cdefs.h>
+
+#include <unistd.h>
+
+__weak_reference(__sys_pipe, pipe);
+__weak_reference(__sys_pipe, _pipe);
+
+extern int __sys_pipe2(int fildes[2], int flags);
+
+int
+__sys_pipe(int fildes[2])
+{
+
+ return (__sys_pipe2(fildes, 0));
+}
diff --git a/lib/libc/sys/poll.2 b/lib/libc/sys/poll.2
new file mode 100644
index 000000000000..dbd641f50bf7
--- /dev/null
+++ b/lib/libc/sys/poll.2
@@ -0,0 +1,273 @@
+.\" $NetBSD: poll.2,v 1.3 1996/09/07 21:53:08 mycroft Exp $
+.\" $FreeBSD$
+.\"
+.\" Copyright (c) 1996 Charles M. Hannum. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by Charles M. Hannum.
+.\" 4. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd November 13, 2014
+.Dt POLL 2
+.Os
+.Sh NAME
+.Nm poll
+.Nd synchronous I/O multiplexing
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.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
+system call
+examines a set of file descriptors to see if some of them are ready for
+I/O.
+The
+.Fa fds
+argument is a pointer to an array of pollfd structures as defined in
+.In poll.h
+(shown below).
+The
+.Fa nfds
+argument determines the size of the
+.Fa fds
+array.
+.Bd -literal
+struct pollfd {
+ int fd; /* file descriptor */
+ short events; /* events to look for */
+ short revents; /* events returned */
+};
+.Ed
+.Pp
+The fields of
+.Fa struct pollfd
+are as follows:
+.Bl -tag -width XXXrevents
+.It fd
+File descriptor to poll.
+If fd is equal to -1 then
+.Fa revents
+is cleared (set to zero), and that pollfd is not checked.
+.It events
+Events to poll for.
+(See below.)
+.It revents
+Events which may occur.
+(See below.)
+.El
+.Pp
+The event bitmasks in
+.Fa events
+and
+.Fa revents
+have the following bits:
+.Bl -tag -width XXXPOLLWRNORM
+.It POLLIN
+Data other than high priority data may be read without blocking.
+.It POLLRDNORM
+Normal data may be read without blocking.
+.It POLLRDBAND
+Data with a non-zero priority may be read without blocking.
+.It POLLPRI
+High priority data may be read without blocking.
+.It POLLOUT
+.It POLLWRNORM
+Normal data may be written without blocking.
+.It POLLWRBAND
+Data with a non-zero priority may be written without blocking.
+.It POLLERR
+An exceptional condition has occurred on the device or socket.
+This
+flag is always checked, even if not present in the
+.Fa events
+bitmask.
+.It POLLHUP
+The device or socket has been disconnected.
+This flag is always
+checked, even if not present in the
+.Fa events
+bitmask.
+Note that
+POLLHUP
+and
+POLLOUT
+should never be present in the
+.Fa revents
+bitmask at the same time.
+.It POLLNVAL
+The file descriptor is not open.
+This flag is always checked, even
+if not present in the
+.Fa events
+bitmask.
+.El
+.Pp
+If
+.Fa timeout
+is neither zero nor INFTIM (-1), it specifies a maximum interval to
+wait for any file descriptor to become ready, in milliseconds.
+If
+.Fa timeout
+is INFTIM (-1), the poll blocks indefinitely.
+If
+.Fa timeout
+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.
+.Bd -literal
+struct timespec {
+ time_t tv_sec; /* seconds */
+ long tv_nsec; /* and nanoseconds */
+};
+.Ed
+.Sh RETURN VALUES
+The
+.Fn poll
+system call
+returns the number of descriptors that are ready for I/O, or -1 if an
+error occurred.
+If the time limit expires,
+.Fn poll
+returns 0.
+If
+.Fn poll
+returns with an error,
+including one due to an interrupted system call,
+the
+.Fa fds
+array will be unmodified.
+.Sh COMPATIBILITY
+This implementation differs from the historical one in that a given
+file descriptor may not cause
+.Fn poll
+to return with an error.
+In cases where this would have happened in
+the historical implementation (e.g.\& trying to poll a
+.Xr revoke 2 Ns ed
+descriptor), this implementation instead copies the
+.Fa events
+bitmask to the
+.Fa revents
+bitmask.
+Attempting to perform I/O on this descriptor will then
+return an error.
+This behaviour is believed to be more useful.
+.Sh ERRORS
+An error return from
+.Fn poll
+indicates:
+.Bl -tag -width Er
+.It Bq Er EFAULT
+The
+.Fa fds
+argument
+points outside the process's allocated address space.
+.It Bq Er EINTR
+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 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
+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
+and
+.Fa revents
+bitmasks is really not useful without STREAMS.
+The fields are
+defined for compatibility with existing software.
diff --git a/lib/libc/sys/poll.c b/lib/libc/sys/poll.c
new file mode 100644
index 000000000000..43c17d2f65ce
--- /dev/null
+++ b/lib/libc/sys/poll.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2014 The FreeBSD Foundation.
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Konstantin Belousov
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice(s), this list of conditions and the following disclaimer as
+ * the first lines of this file unmodified other than the possible
+ * addition of one or more copyright notices.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice(s), this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/poll.h>
+#include "libc_private.h"
+
+__weak_reference(__sys_poll, __poll);
+
+#pragma weak poll
+int
+poll(struct pollfd pfd[], nfds_t nfds, int timeout)
+{
+
+ return (((int (*)(struct pollfd *, nfds_t, int))
+ __libc_interposing[INTERPOS_poll])(pfd, nfds, timeout));
+}
diff --git a/lib/libc/sys/posix_fadvise.2 b/lib/libc/sys/posix_fadvise.2
new file mode 100644
index 000000000000..641bc9bff5ef
--- /dev/null
+++ b/lib/libc/sys/posix_fadvise.2
@@ -0,0 +1,139 @@
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)madvise.2 8.1 (Berkeley) 6/9/93
+.\" $FreeBSD$
+.\"
+.Dd October 3, 2015
+.Dt POSIX_FADVISE 2
+.Os
+.Sh NAME
+.Nm posix_fadvise
+.Nd give advice about use of file data
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In fcntl.h
+.Ft int
+.Fn posix_fadvise "int fd" "off_t offset" "off_t len" "int advice"
+.Sh DESCRIPTION
+The
+.Fn posix_fadvise
+system call
+allows a process to describe to the system its data access behavior for an
+open file descriptor
+.Fa fd .
+The advice covers the data starting at offset
+.Fa offset
+and continuing for
+.Fa len
+bytes.
+If
+.Fa len
+is zero,
+all data from
+.Fa offset
+to the end of the file is covered.
+.Pp
+The behavior is specified by the
+.Fa advice
+parameter and may be one of:
+.Bl -tag -width POSIX_FADV_SEQUENTIAL
+.It Dv POSIX_FADV_NORMAL
+Tells the system to revert to the default data access behavior.
+.It Dv POSIX_FADV_RANDOM
+Is a hint that file data will be accessed randomly,
+and prefetching is likely not advantageous.
+.It Dv POSIX_FADV_SEQUENTIAL
+Tells the system that file data will be accessed sequentially.
+This currently does nothing as the default behavior uses heuristics to
+detect sequential behavior.
+.It Dv POSIX_FADV_WILLNEED
+Tells the system that the specified data will be accessed in the near future.
+The system may initiate an asynchronous read of the data if it is not already
+present in memory.
+.It Dv POSIX_FADV_DONTNEED
+Tells the system that the specified data will not be accessed in the near
+future.
+The system may decrease the in-memory priority of clean data within the
+specified range and future access to this data may require a read operation.
+.It Dv POSIX_FADV_NOREUSE
+Tells the system that the specified data will only be accessed once and
+then not reused.
+The system may decrease the in-memory priority of data once it has been
+read or written.
+Future access to this data may require a read operation.
+.El
+.Sh RETURN VALUES
+If successful,
+.Fn posix_fadvise
+returns zero.
+It returns an error on failure, without setting
+.Va errno .
+.Sh ERRORS
+Possible failure conditions:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa fd
+argument is not a valid file descriptor.
+.It Bq Er EINVAL
+The
+.Fa advice
+argument is not valid.
+.It Bq Er EINVAL
+The
+.Fa offset
+or
+.Fa len
+arguments are negative,
+or
+.Fa offset
++
+.Fa len
+is greater than the maximum file size.
+.It Bq Er ENODEV
+The
+.Fa fd
+argument does not refer to a regular file.
+.It Bq Er ESPIPE
+The
+.Fa fd
+argument is associated with a pipe or FIFO.
+.El
+.Sh SEE ALSO
+.Xr madvise 2
+.Sh STANDARDS
+The
+.Fn posix_fadvise
+interface conforms to
+.St -p1003.1-2001 .
+.Sh HISTORY
+The
+.Fn posix_fadvise
+system call first appeared in
+.Fx 9.1 .
diff --git a/lib/libc/sys/posix_fallocate.2 b/lib/libc/sys/posix_fallocate.2
new file mode 100644
index 000000000000..4c92d9b9c2be
--- /dev/null
+++ b/lib/libc/sys/posix_fallocate.2
@@ -0,0 +1,144 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)open.2 8.2 (Berkeley) 11/16/93
+.\" $FreeBSD$
+.\"
+.Dd January 23, 2014
+.Dt POSIX_FALLOCATE 2
+.Os
+.Sh NAME
+.Nm posix_fallocate
+.Nd pre-allocate storage for a range in a file
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In fcntl.h
+.Ft int
+.Fn posix_fallocate "int fd" "off_t offset" "off_t len"
+.Sh DESCRIPTION
+Required storage for the range
+.Fa offset
+to
+.Fa offset +
+.Fa len
+in the file referenced by
+.Fa fd
+is guaranteed to be allocated upon successful return.
+That is, if
+.Fn posix_fallocate
+returns successfully, subsequent writes to the specified file data
+will not fail due to lack of free space on the file system storage
+media.
+Any existing file data in the specified range is unmodified.
+If
+.Fa offset +
+.Fa len
+is beyond the current file size, then
+.Fn posix_fallocate
+will adjust the file size to
+.Fa offset +
+.Fa len .
+Otherwise, the file size will not be changed.
+.Pp
+Space allocated by
+.Fn posix_fallocate
+will be freed by a successful call to
+.Xr creat 2
+or
+.Xr open 2
+that truncates the size of the file.
+Space allocated via
+.Fn posix_fallocate
+may be freed by a successful call to
+.Xr ftruncate 2
+that reduces the file size to a size smaller than
+.Fa offset +
+.Fa len .
+.Sh RETURN VALUES
+If successful,
+.Fn posix_fallocate
+returns zero.
+It returns an error on failure, without setting
+.Va errno .
+.Sh ERRORS
+Possible failure conditions:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa fd
+argument is not a valid file descriptor.
+.It Bq Er EBADF
+The
+.Fa fd
+argument references a file that was opened without write permission.
+.It Bq Er EFBIG
+The value of
+.Fa offset +
+.Fa len
+is greater than the maximum file size.
+.It Bq Er EINTR
+A signal was caught during execution.
+.It Bq Er EINVAL
+The
+.Fa len
+argument was less than or equal to zero or the
+.Fa offset
+argument was less than zero.
+.It Bq Er EIO
+An I/O error occurred while reading from or writing to a file system.
+.It Bq Er ENODEV
+The
+.Fa fd
+argument does not refer to a regular file.
+.It Bq Er ENOSPC
+There is insufficient free space remaining on the file system storage
+media.
+.It Bq Er ESPIPE
+The
+.Fa fd
+argument is associated with a pipe or FIFO.
+.El
+.Sh SEE ALSO
+.Xr creat 2 ,
+.Xr ftruncate 2 ,
+.Xr open 2 ,
+.Xr unlink 2
+.Sh STANDARDS
+The
+.Fn posix_fallocate
+system call conforms to
+.St -p1003.1-2004 .
+.Sh HISTORY
+The
+.Fn posix_fallocate
+function appeared in
+.Fx 9.0 .
+.Sh AUTHORS
+.Fn posix_fallocate
+and this manual page were initially written by
+.An Matthew Fleming Aq Mt mdf@FreeBSD.org .
diff --git a/lib/libc/sys/posix_openpt.2 b/lib/libc/sys/posix_openpt.2
new file mode 100644
index 000000000000..01a372931af8
--- /dev/null
+++ b/lib/libc/sys/posix_openpt.2
@@ -0,0 +1,140 @@
+.\" Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Portions of this software were developed under sponsorship from Snow
+.\" B.V., the Netherlands.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" Portions of this text are reprinted and reproduced in electronic form
+.\" from IEEE Std 1003.1, 2004 Edition, Standard for Information Technology --
+.\" Portable Operating System Interface (POSIX), The Open Group Base
+.\" Specifications Issue 6, Copyright (C) 2001-2004 by the Institute of
+.\" Electrical and Electronics Engineers, Inc and The Open Group. In the
+.\" event of any discrepancy between this version and the original IEEE and
+.\" The Open Group Standard, the original IEEE and The Open Group Standard is
+.\" the referee document. The original Standard can be obtained online at
+.\" http://www.opengroup.org/unix/online.html.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd September 21, 2016
+.Dt POSIX_OPENPT 2
+.Os
+.Sh NAME
+.Nm posix_openpt
+.Nd "open a pseudo-terminal device"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In fcntl.h
+.In stdlib.h
+.Ft int
+.Fn posix_openpt "int oflag"
+.Sh DESCRIPTION
+The
+.Fn posix_openpt
+function allocates a new pseudo-terminal and establishes a connection
+with its master device.
+A slave device shall be created in
+.Pa /dev/pts .
+After the pseudo-terminal has been allocated, the slave device should
+have the proper permissions before it can be used (see
+.Xr grantpt 3 ) .
+The name of the slave device can be determined by calling
+.Xr ptsname 3 .
+.Pp
+The file status flags and file access modes of the open file description
+shall be set according to the value of
+.Fa oflag .
+Values for
+.Fa oflag
+are constructed by a bitwise-inclusive OR of flags from the following
+list, defined in
+.In fcntl.h :
+.Bl -tag -width ".Dv O_CLOEXEC"
+.It Dv O_RDWR
+Open for reading and writing.
+.It Dv O_NOCTTY
+If set
+.Fn posix_openpt
+shall not cause the terminal device to become the controlling terminal
+for the process.
+.It Dv O_CLOEXEC
+Set the close-on-exec flag for the new file descriptor.
+.El
+.Pp
+The
+.Fn posix_openpt
+function shall fail when
+.Fa oflag
+contains other values.
+.Sh RETURN VALUES
+Upon successful completion, the
+.Fn posix_openpt
+function shall allocate a new pseudo-terminal device and return a
+non-negative integer representing a file descriptor, which is connected
+to its master device.
+Otherwise, -1 shall be returned and errno set to indicate the error.
+.Sh ERRORS
+The
+.Fn posix_openpt
+function shall fail if:
+.Bl -tag -width Er
+.It Bq Er ENFILE
+The system file table is full.
+.It Bq Er EINVAL
+The value of
+.Fa oflag
+is not valid.
+.It Bq Er EAGAIN
+Out of pseudo-terminal resources.
+.El
+.Sh SEE ALSO
+.Xr ptsname 3 ,
+.Xr pts 4 ,
+.Xr tty 4
+.Sh STANDARDS
+The
+.Fn posix_openpt
+function conforms to
+.St -p1003.1-2001 .
+The ability to use
+.Dv O_CLOEXEC
+is an extension to the standard.
+.Sh HISTORY
+The
+.Fn posix_openpt
+function appeared in
+.Fx 5.0 .
+In
+.Fx 8.0 ,
+this function was changed to a system call.
+.Sh NOTES
+The flag
+.Dv O_NOCTTY
+is included for compatibility; in
+.Fx ,
+opening a terminal does not cause it to become a process's controlling
+terminal.
+.Sh AUTHORS
+.An \&Ed Schouten Aq Mt ed@FreeBSD.org
diff --git a/lib/libc/sys/ppoll.c b/lib/libc/sys/ppoll.c
new file mode 100644
index 000000000000..f62fd19cafe1
--- /dev/null
+++ b/lib/libc/sys/ppoll.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2015 The FreeBSD Foundation.
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Konstantin Belousov
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice(s), this list of conditions and the following disclaimer as
+ * the first lines of this file unmodified other than the possible
+ * addition of one or more copyright notices.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice(s), this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/poll.h>
+#include "libc_private.h"
+
+__weak_reference(__sys_ppoll, __ppoll);
+
+#pragma weak ppoll
+int
+ppoll(struct pollfd pfd[], nfds_t nfds, const struct timespec *__restrict
+ timeout, const sigset_t *__restrict newsigmask)
+{
+
+ return (((int (*)(struct pollfd *, nfds_t, const struct timespec *,
+ const sigset_t *)) __libc_interposing[INTERPOS_ppoll])(pfd, nfds,
+ timeout, newsigmask));
+}
diff --git a/lib/libc/sys/procctl.2 b/lib/libc/sys/procctl.2
new file mode 100644
index 000000000000..da73fb04f93d
--- /dev/null
+++ b/lib/libc/sys/procctl.2
@@ -0,0 +1,505 @@
+.\" Copyright (c) 2013 Hudson River Trading LLC
+.\" Written by: John H. Baldwin <jhb@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Copyright (c) 2014 The FreeBSD Foundation
+.\" Portions of this documentation were written by Konstantin Belousov
+.\" under sponsorship from the FreeBSD Foundation.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd September 27, 2016
+.Dt PROCCTL 2
+.Os
+.Sh NAME
+.Nm procctl
+.Nd control processes
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/procctl.h
+.Ft int
+.Fn procctl "idtype_t idtype" "id_t id" "int cmd" "void *arg"
+.Sh DESCRIPTION
+The
+.Fn procctl
+system call provides for control over processes.
+The
+.Fa idtype
+and
+.Fa id
+arguments specify the set of processes to control.
+If multiple processes match the identifier,
+.Nm
+will make a
+.Dq best effort
+to control as many of the selected processes as possible.
+An error is only returned if no selected processes successfully complete
+the request.
+The following identifier types are supported:
+.Bl -tag -width "Dv P_PGID"
+.It Dv P_PID
+Control the process with the process ID
+.Fa id .
+.It Dv P_PGID
+Control processes belonging to the process group with the ID
+.Fa id .
+.El
+.Pp
+The control request to perform is specified by the
+.Fa cmd
+argument.
+The following commands are supported:
+.Bl -tag -width "Dv PROC_TRAPCAP_STATUS"
+.It Dv PROC_SPROTECT
+Set process protection state.
+This is used to mark a process as protected from being killed if the system
+exhausts the available memory and swap.
+The
+.Fa arg
+parameter must point to an integer containing an operation and zero or more
+optional flags.
+The following operations are supported:
+.Bl -tag -width "Dv PPROT_CLEAR"
+.It Dv PPROT_SET
+Mark the selected processes as protected.
+.It Dv PPROT_CLEAR
+Clear the protected state of selected processes.
+.El
+.Pp
+The following optional flags are supported:
+.Bl -tag -width "Dv PPROT_DESCEND"
+.It Dv PPROT_DESCEND
+Apply the requested operation to all child processes of each selected process
+in addition to each selected process.
+.It Dv PPROT_INHERIT
+When used with
+.Dv PPROT_SET ,
+mark all future child processes of each selected process as protected.
+Future child processes will also mark all of their future child processes.
+.El
+.It Dv PROC_REAP_ACQUIRE
+Acquires the reaper status for the current process.
+Reaper status means that children orphaned by the reaper's descendants
+that were forked after the acquisition of reaper status are reparented to the
+reaper process.
+After system initialization,
+.Xr init 8
+is the default reaper.
+.It Dv PROC_REAP_RELEASE
+Release the reaper state for the current process.
+The reaper of the current process becomes the new reaper of the
+current process's descendants.
+.It Dv PROC_REAP_STATUS
+Provides information about the reaper of the specified process,
+or the process itself when it is a reaper.
+The
+.Fa data
+argument must point to a
+.Vt procctl_reaper_status
+structure which is filled in by the syscall on successful return.
+.Bd -literal
+struct procctl_reaper_status {
+ u_int rs_flags;
+ u_int rs_children;
+ u_int rs_descendants;
+ pid_t rs_reaper;
+ pid_t rs_pid;
+};
+.Ed
+The
+.Fa rs_flags
+may have the following flags returned:
+.Bl -tag -width "Dv REAPER_STATUS_REALINIT"
+.It Dv REAPER_STATUS_OWNED
+The specified process has acquired reaper status and has not
+released it.
+When the flag is returned, the specified process
+.Fa id ,
+pid, identifies the reaper, otherwise the
+.Fa rs_reaper
+field of the structure is set to the pid of the reaper
+for the specified process id.
+.It Dv REAPER_STATUS_REALINIT
+The specified process is the root of the reaper tree, i.e.,
+.Xr init 8 .
+.El
+.Pp
+The
+.Fa rs_children
+field returns the number of children of the reaper among the descendants.
+It is possible to have a child whose reaper is not the specified process,
+since the reaper for any existing children is not reset on the
+.Dv PROC_REAP_ACQUIRE
+operation.
+The
+.Fa rs_descendants
+field returns the total number of descendants of the reaper(s),
+not counting descendants of the reaper in the subtree.
+The
+.Fa rs_reaper
+field returns the reaper pid.
+The
+.Fa rs_pid
+returns the pid of one reaper child if there are any descendants.
+.It Dv PROC_REAP_GETPIDS
+Queries the list of descendants of the reaper of the specified process.
+The request takes a pointer to a
+.Vt procctl_reaper_pids
+structure in the
+.Fa data
+parameter.
+.Bd -literal
+struct procctl_reaper_pids {
+ u_int rp_count;
+ struct procctl_reaper_pidinfo *rp_pids;
+};
+.Ed
+When called, the
+.Fa rp_pids
+field must point to an array of
+.Vt procctl_reaper_pidinfo
+structures, to be filled in on return,
+and the
+.Fa rp_count
+field must specify the size of the array,
+into which no more than
+.Fa rp_count
+elements will be filled in by the kernel.
+.Pp
+The
+.Vt "struct procctl_reaper_pidinfo"
+structure provides some information about one of the reaper's descendants.
+Note that for a descendant that is not a child, it may be incorrectly
+identified because of a race in which the original child process exited
+and the exited process's pid was reused for an unrelated process.
+.Bd -literal
+struct procctl_reaper_pidinfo {
+ pid_t pi_pid;
+ pid_t pi_subtree;
+ u_int pi_flags;
+};
+.Ed
+The
+.Fa pi_pid
+field is the process id of the descendant.
+The
+.Fa pi_subtree
+field provides the pid of the child of the reaper, which is the (grand-)parent
+of the process.
+The
+.Fa pi_flags
+field returns the following flags, further describing the descendant:
+.Bl -tag -width "Dv REAPER_PIDINFO_VALID"
+.It Dv REAPER_PIDINFO_VALID
+Set to indicate that the
+.Vt procctl_reaper_pidinfo
+structure was filled in by the kernel.
+Zero-filling the
+.Fa rp_pids
+array and testing the
+.Dv REAPER_PIDINFO_VALID
+flag allows the caller to detect the end
+of the returned array.
+.It Dv REAPER_PIDINFO_CHILD
+The
+.Fa pi_pid
+field identifies the direct child of the reaper.
+.El
+.It Dv PROC_REAP_KILL
+Request to deliver a signal to some subset of the descendants of the reaper.
+The
+.Fa data
+parameter must point to a
+.Vt procctl_reaper_kill
+structure, which is used both for parameters and status return.
+.Bd -literal
+struct procctl_reaper_kill {
+ int rk_sig;
+ u_int rk_flags;
+ pid_t rk_subtree;
+ u_int rk_killed;
+ pid_t rk_fpid;
+};
+.Ed
+The
+.Fa rk_sig
+field specifies the signal to be delivered.
+Zero is not a valid signal number, unlike for
+.Xr kill 2 .
+The
+.Fa rk_flags
+field further directs the operation.
+It is or-ed from the following flags:
+.Bl -tag -width "Dv REAPER_KILL_CHILDREN"
+.It Dv REAPER_KILL_CHILDREN
+Deliver the specified signal only to direct children of the reaper.
+.It Dv REAPER_KILL_SUBTREE
+Deliver the specified signal only to descendants that were forked by
+the direct child with pid specified in the
+.Fa rk_subtree
+field.
+.El
+If neither the
+.Dv REAPER_KILL_CHILDREN
+nor the
+.Dv REAPER_KILL_SUBTREE
+flags are specified, all current descendants of the reaper are signalled.
+.Pp
+If a signal was delivered to any process, the return value from the request
+is zero.
+In this case, the
+.Fa rk_killed
+field identifies the number of processes signalled.
+The
+.Fa rk_fpid
+field is set to the pid of the first process for which signal
+delivery failed, e.g., due to permission problems.
+If no such process exists, the
+.Fa rk_fpid
+field is set to -1.
+.It Dv PROC_TRACE_CTL
+Enable or disable tracing of the specified process(es), according to the
+value of the integer argument.
+Tracing includes attachment to the process using the
+.Xr ptrace 2
+and
+.Xr ktrace 2 ,
+debugging sysctls,
+.Xr hwpmc 4 ,
+.Xr dtrace 1 ,
+and core dumping.
+Possible values for the
+.Fa data
+argument are:
+.Bl -tag -width "Dv PROC_TRACE_CTL_DISABLE_EXEC"
+.It Dv PROC_TRACE_CTL_ENABLE
+Enable tracing, after it was disabled by
+.Dv PROC_TRACE_CTL_DISABLE .
+Only allowed for self.
+.It Dv PROC_TRACE_CTL_DISABLE
+Disable tracing for the specified process.
+Tracing is re-enabled when the process changes the executing
+program with the
+.Xr execve 2
+syscall.
+A child inherits the trace settings from the parent on
+.Xr fork 2 .
+.It Dv PROC_TRACE_CTL_DISABLE_EXEC
+Same as
+.Dv PROC_TRACE_CTL_DISABLE ,
+but the setting persists for the process even after
+.Xr execve 2 .
+.El
+.It Dv PROC_TRACE_STATUS
+Returns the current tracing status for the specified process in
+the integer variable pointed to by
+.Fa data .
+If tracing is disabled,
+.Fa data
+is set to -1.
+If tracing is enabled, but no debugger is attached by the
+.Xr ptrace 2
+syscall,
+.Fa data
+is set to 0.
+If a debugger is attached,
+.Fa data
+is set to the pid of the debugger process.
+.It Dv PROC_TRAPCAP_CTL
+Controls the capability mode sandbox actions for the specified
+sandboxed processes,
+on a return from any syscall which gives either a
+.Er ENOTCAPABLE
+or
+.Er ECAPMODE
+error.
+If the control is enabled, such errors from the syscalls cause
+delivery of the synchronous
+.Dv SIGTRAP
+signal to the thread immediately before returning from the syscalls.
+.Pp
+Possible values for the
+.Fa data
+argument are:
+.Bl -tag -width "Dv PROC_TRAPCAP_CTL_DISABLE"
+.It Dv PROC_TRAPCAP_CTL_ENABLE
+Enable the
+.Dv SIGTRAP
+signal delivery on capability mode access violations.
+The enabled mode is inherited by the children of the process,
+and is kept after
+.Xr fexecve 2
+calls.
+.It Dv PROC_TRAPCAP_CTL_DISABLE
+Disable the signal delivery on capability mode access violations.
+Note that the global sysctl
+.Dv kern.trap_enocap
+might still cause the signal to be delivered.
+See
+.Xr capsicum 4 .
+.El
+.Pp
+On signal delivery, the
+.Va si_errno
+member of the
+.Fa siginfo
+signal handler parameter is set to the syscall error value,
+and the
+.Va si_code
+member is set to
+.Dv TRAP_CAP .
+.Pp
+See
+.Xr capsicum 4
+for more information about the capability mode.
+.It Dv PROC_TRAPCAP_STATUS
+Return the current status of signalling capability mode access
+violations for the specified process.
+The integer value pointed to by the
+.Fa data
+argument is set to the
+.Dv PROC_TRAPCAP_CTL_ENABLE
+value if the process control enables signal delivery, and to
+.Dv PROC_TRAPCAP_CTL_DISABLE
+otherwise.
+.Pp
+See the note about sysctl
+.Dv kern.trap_enocap
+above, which gives independent global control of signal delivery.
+.El
+.Sh NOTES
+Disabling tracing on a process should not be considered a security
+feature, as it is bypassable both by the kernel and privileged processes,
+and via other system mechanisms.
+As such, it should not be utilized to reliably protect cryptographic
+keying material or other confidential data.
+.Sh RETURN VALUES
+If an error occurs, a value of -1 is returned and
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+The
+.Fn procctl
+system call
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EFAULT
+The
+.Fa arg
+parameter points outside the process's allocated address space.
+.It Bq Er EINVAL
+The
+.Fa cmd
+argument specifies an unsupported command.
+.Pp
+The
+.Fa idtype
+argument specifies an unsupported identifier type.
+.It Bq Er EPERM
+The calling process does not have permission to perform the requested
+operation on any of the selected processes.
+.It Bq Er ESRCH
+No processes matched the requested
+.Fa idtype
+and
+.Fa id .
+.It Bq Er EINVAL
+An invalid operation or flag was passed in
+.Fa arg
+for a
+.Dv PROC_SPROTECT
+command.
+.It Bq Er EPERM
+The
+.Fa idtype
+argument is not equal to
+.Dv P_PID ,
+or
+.Fa id
+is not equal to the pid of the calling process, for
+.Dv PROC_REAP_ACQUIRE
+or
+.Dv PROC_REAP_RELEASE
+requests.
+.It Bq Er EINVAL
+Invalid or undefined flags were passed to a
+.Dv PROC_REAP_KILL
+request.
+.It Bq Er EINVAL
+An invalid or zero signal number was requested for a
+.Dv PROC_REAP_KILL
+request.
+.It Bq Er EINVAL
+The
+.Dv PROC_REAP_RELEASE
+request was issued by the
+.Xr init 8
+process.
+.It Bq Er EBUSY
+The
+.Dv PROC_REAP_ACQUIRE
+request was issued by a process that had already acquired reaper status
+and has not yet released it.
+.It Bq Er EBUSY
+The
+.Dv PROC_TRACE_CTL
+request was issued for a process already being traced.
+.It Bq Er EPERM
+The
+.Dv PROC_TRACE_CTL
+request to re-enable tracing of the process
+.Po Dv PROC_TRACE_CTL_ENABLE Pc ,
+or to disable persistence of
+.Dv PROC_TRACE_CTL_DISABLE
+on
+.Xr execve 2
+was issued for a non-current process.
+.It Bq Er EINVAL
+The value of the integer
+.Fa data
+parameter for the
+.Dv PROC_TRACE_CTL
+or
+.Dv PROC_TRAPCAP_CTL
+request is invalid.
+.El
+.Sh SEE ALSO
+.Xr dtrace 1 ,
+.Xr cap_enter 2,
+.Xr kill 2 ,
+.Xr ktrace 2 ,
+.Xr ptrace 2 ,
+.Xr wait 2 ,
+.Xr capsicum 4 ,
+.Xr hwpmc 4 ,
+.Xr init 8
+.Sh HISTORY
+The
+.Fn procctl
+function appeared in
+.Fx 10.0 .
+The reaper facility is based on a similar feature of Linux and
+DragonflyBSD, and first appeared in
+.Fx 10.2 .
diff --git a/lib/libc/sys/profil.2 b/lib/libc/sys/profil.2
new file mode 100644
index 000000000000..444d3c3373c3
--- /dev/null
+++ b/lib/libc/sys/profil.2
@@ -0,0 +1,122 @@
+.\" Copyright (c) 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Donn Seeley of BSDI.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)profil.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt PROFIL 2
+.Os
+.Sh NAME
+.Nm profil
+.Nd control process profiling
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft int
+.Fn profil "char *samples" "size_t size" "vm_offset_t offset" "int scale"
+.Sh DESCRIPTION
+The
+.Fn profil
+system call enables or disables
+program counter profiling of the current process.
+If profiling is enabled,
+then at every profiling clock tick,
+the kernel updates an appropriate count in the
+.Fa samples
+buffer.
+The frequency of the profiling clock is recorded
+in the header in the profiling output file.
+.Pp
+The buffer
+.Fa samples
+contains
+.Fa size
+bytes and is divided into
+a series of 16-bit bins.
+Each bin counts the number of times the program counter
+was in a particular address range in the process
+when a profiling clock tick occurred while profiling was enabled.
+For a given program counter address,
+the number of the corresponding bin is given
+by the relation:
+.Bd -literal -offset indent
+[(pc - offset) / 2] * scale / 65536
+.Ed
+.Pp
+The
+.Fa offset
+argument is the lowest address at which
+the kernel takes program counter samples.
+The
+.Fa scale
+argument ranges from 1 to 65536 and
+can be used to change the span of the bins.
+A scale of 65536 maps each bin to 2 bytes of address range;
+a scale of 32768 gives 4 bytes, 16384 gives 8 bytes and so on.
+Intermediate values provide approximate intermediate ranges.
+A
+.Fa scale
+value of 0 disables profiling.
+.Sh RETURN VALUES
+.Rv -std profil
+.Sh FILES
+.Bl -tag -width /usr/lib/gcrt0.o -compact
+.It Pa /usr/lib/gcrt0.o
+profiling C run-time startup file
+.It Pa gmon.out
+conventional name for profiling output file
+.El
+.Sh ERRORS
+The following error may be reported:
+.Bl -tag -width Er
+.It Bq Er EFAULT
+The buffer
+.Fa samples
+contains an invalid address.
+.El
+.Sh SEE ALSO
+.Xr gprof 1
+.Sh HISTORY
+The
+.Fn profil
+function appeared in
+.At v7 .
+.Sh BUGS
+This routine should be named
+.Fn profile .
+.Pp
+The
+.Fa samples
+argument should really be a vector of type
+.Fa "unsigned short" .
+.Pp
+The format of the gmon.out file is undocumented.
diff --git a/lib/libc/sys/pselect.2 b/lib/libc/sys/pselect.2
new file mode 100644
index 000000000000..6221c473e7d7
--- /dev/null
+++ b/lib/libc/sys/pselect.2
@@ -0,0 +1,123 @@
+.\"
+.\" Copyright 2002 Massachusetts Institute of Technology
+.\"
+.\" Permission to use, copy, modify, and distribute this software and
+.\" its documentation for any purpose and without fee is hereby
+.\" granted, provided that both the above copyright notice and this
+.\" permission notice appear in all copies, that both the above
+.\" copyright notice and this permission notice appear in all
+.\" supporting documentation, and that the name of M.I.T. not be used
+.\" in advertising or publicity pertaining to distribution of the
+.\" software without specific, written prior permission. M.I.T. makes
+.\" no representations about the suitability of this software for any
+.\" purpose. It is provided "as is" without express or implied
+.\" warranty.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
+.\" ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
+.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
+.\" SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+.\" USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+.\" ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+.\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+.\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd August 16, 2013
+.Dt PSELECT 2
+.Os
+.Sh NAME
+.Nm pselect
+.Nd synchronous I/O multiplexing a la POSIX.1g
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/select.h
+.Ft int
+.Fo pselect
+.Fa "int nfds"
+.Fa "fd_set * restrict readfds"
+.Fa "fd_set * restrict writefds"
+.Fa "fd_set * restrict exceptfds"
+.Fa "const struct timespec * restrict timeout"
+.Fa "const sigset_t * restrict newsigmask"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn pselect
+function was introduced by
+.St -p1003.1g-2000
+as a slightly stronger version of
+.Xr select 2 .
+The
+.Fa nfds , readfds , writefds ,
+and
+.Fa exceptfds
+arguments are all identical to the analogous arguments of
+.Fn select .
+The
+.Fa timeout
+argument in
+.Fn pselect
+points to a
+.Vt "const struct timespec"
+rather than the (modifiable)
+.Vt "struct timeval"
+used by
+.Fn select ;
+as in
+.Fn select ,
+a null pointer may be passed to indicate that
+.Fn pselect
+should wait indefinitely.
+Finally,
+.Fa newsigmask
+specifies a signal mask which is set while waiting for input.
+When
+.Fn pselect
+returns, the original signal mask is restored.
+.Pp
+See
+.Xr select 2
+for a more detailed discussion of the semantics of this interface, and
+for macros used to manipulate the
+.Vt "fd_set"
+data type.
+.Sh RETURN VALUES
+The
+.Fn pselect
+function returns the same values and under the same conditions as
+.Fn select .
+.Sh ERRORS
+The
+.Fn pselect
+function may fail for any of the reasons documented for
+.Xr select 2
+and (if a signal mask is provided)
+.Xr sigprocmask 2 .
+.Sh SEE ALSO
+.Xr kqueue 2 ,
+.Xr poll 2 ,
+.Xr select 2 ,
+.Xr sigprocmask 2 ,
+.Xr sigsuspend 2
+.Sh STANDARDS
+The
+.Fn pselect
+function conforms to
+.St -p1003.1-2001 .
+.Sh HISTORY
+The
+.Fn pselect
+function first appeared in
+.Fx 5.0 .
+.Sh AUTHORS
+The first implementation of
+.Fn pselect
+function and this manual page were written by
+.An Garrett Wollman Aq Mt wollman@FreeBSD.org .
diff --git a/lib/libc/sys/pselect.c b/lib/libc/sys/pselect.c
new file mode 100644
index 000000000000..a623a7d5cc74
--- /dev/null
+++ b/lib/libc/sys/pselect.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2014 The FreeBSD Foundation.
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Konstantin Belousov
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice(s), this list of conditions and the following disclaimer as
+ * the first lines of this file unmodified other than the possible
+ * addition of one or more copyright notices.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice(s), this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/select.h>
+#include "libc_private.h"
+
+__weak_reference(__sys_pselect, __pselect);
+
+#pragma weak pselect
+int
+pselect(int n, fd_set *rs, fd_set *ws, fd_set *es, const struct timespec *t,
+ const sigset_t *s)
+{
+
+ return (((int (*)(int, fd_set *, fd_set *, fd_set *,
+ const struct timespec *, const sigset_t *))
+ __libc_interposing[INTERPOS_pselect])(n, rs, ws, es, t, s));
+}
diff --git a/lib/libc/sys/ptrace.2 b/lib/libc/sys/ptrace.2
new file mode 100644
index 000000000000..2cd26ee3465a
--- /dev/null
+++ b/lib/libc/sys/ptrace.2
@@ -0,0 +1,1066 @@
+.\" $FreeBSD$
+.\" $NetBSD: ptrace.2,v 1.2 1995/02/27 12:35:37 cgd Exp $
+.\"
+.\" This file is in the public domain.
+.Dd August 29, 2016
+.Dt PTRACE 2
+.Os
+.Sh NAME
+.Nm ptrace
+.Nd process tracing and debugging
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/ptrace.h
+.Ft int
+.Fn ptrace "int request" "pid_t pid" "caddr_t addr" "int data"
+.Sh DESCRIPTION
+The
+.Fn ptrace
+system call
+provides tracing and debugging facilities.
+It allows one process
+(the
+.Em tracing
+process)
+to control another
+(the
+.Em traced
+process).
+The tracing process must first attach to the traced process, and then
+issue a series of
+.Fn ptrace
+system calls to control the execution of the process, as well as access
+process memory and register state.
+For the duration of the tracing session, the traced process will be
+.Dq re-parented ,
+with its parent process ID (and resulting behavior)
+changed to the tracing process.
+It is permissible for a tracing process to attach to more than one
+other process at a time.
+When the tracing process has completed its work, it must detach the
+traced process; if a tracing process exits without first detaching all
+processes it has attached, those processes will be killed.
+.Pp
+Most of the time, the traced process runs normally, but when it
+receives a signal
+(see
+.Xr sigaction 2 ) ,
+it stops.
+The tracing process is expected to notice this via
+.Xr wait 2
+or the delivery of a
+.Dv SIGCHLD
+signal, examine the state of the stopped process, and cause it to
+terminate or continue as appropriate.
+The signal may be a normal process signal, generated as a result of
+traced process behavior, or use of the
+.Xr kill 2
+system call; alternatively, it may be generated by the tracing facility
+as a result of attaching, stepping by the tracing
+process,
+or an event in the traced process.
+The tracing process may choose to intercept the signal, using it to
+observe process behavior (such as
+.Dv SIGTRAP ) ,
+or forward the signal to the process if appropriate.
+The
+.Fn ptrace
+system call
+is the mechanism by which all this happens.
+.Pp
+A traced process may report additional signal stops corresponding to
+events in the traced process.
+These additional signal stops are reported as
+.Dv SIGTRAP
+or
+.Dv SIGSTOP
+signals.
+The tracing process can use the
+.Dv PT_LWPINFO
+request to determine which events are associated with a
+.Dv SIGTRAP
+or
+.Dv SIGSTOP
+signal.
+Note that multiple events may be associated with a single signal.
+For example, events indicated by the
+.Dv PL_FLAG_BORN ,
+.Dv PL_FLAG_FORKED ,
+and
+.Dv PL_FLAG_EXEC
+flags are also reported as a system call exit event
+.Pq Dv PL_FLAG_SCX .
+The signal stop for a new child process enabled via
+.Dv PTRACE_FORK
+will report a
+.Dv SIGSTOP
+signal.
+All other additional signal stops use
+.Dv SIGTRAP .
+.Pp
+Each traced process has a tracing event mask.
+An event in the traced process only reports a
+signal stop if the corresponding flag is set in the tracing event mask.
+The current set of tracing event flags include:
+.Bl -tag -width "Dv PTRACE_SYSCALL"
+.It Dv PTRACE_EXEC
+Report a stop for a successful invocation of
+.Xr execve 2 .
+This event is indicated by the
+.Dv PL_FLAG_EXEC
+flag in the
+.Va pl_flags
+member of
+.Vt "struct ptrace_lwpinfo" .
+.It Dv PTRACE_SCE
+Report a stop on each system call entry.
+This event is indicated by the
+.Dv PL_FLAG_SCE
+flag in the
+.Va pl_flags
+member of
+.Vt "struct ptrace_lwpinfo" .
+.It Dv PTRACE_SCX
+Report a stop on each system call exit.
+This event is indicated by the
+.Dv PL_FLAG_SCX
+flag in the
+.Va pl_flags
+member of
+.Vt "struct ptrace_lwpinfo" .
+.It Dv PTRACE_SYSCALL
+Report stops for both system call entry and exit.
+.It Dv PTRACE_FORK
+This event flag controls tracing for new child processes of a traced process.
+.Pp
+When this event flag is enabled,
+new child processes will enable tracing and stop before executing their
+first instruction.
+The new child process will include the
+.Dv PL_FLAG_CHILD
+flag in the
+.Va pl_flags
+member of
+.Vt "struct ptrace_lwpinfo" .
+The traced process will report a stop that includes the
+.Dv PL_FLAG_FORKED
+flag.
+The process ID of the new child process will also be present in the
+.Va pl_child_pid
+member of
+.Vt "struct ptrace_lwpinfo" .
+If the new child process was created via
+.Xr vfork 2 ,
+the traced process's stop will also include the
+.Dv PL_FLAG_VFORKED
+flag.
+Note that new child processes will be attached with the default
+tracing event mask;
+they do not inherit the event mask of the traced process.
+.Pp
+When this event flag is not enabled,
+new child processes will execute without tracing enabled.
+.It Dv PTRACE_LWP
+This event flag controls tracing of LWP
+.Pq kernel thread
+creation and destruction.
+When this event is enabled,
+new LWPs will stop and report an event with
+.Dv PL_FLAG_BORN
+set before executing their first instruction,
+and exiting LWPs will stop and report an event with
+.Dv PL_FLAG_EXITED
+set before completing their termination.
+.Pp
+Note that new processes do not report an event for the creation of their
+initial thread,
+and exiting processes do not report an event for the termination of the
+last thread.
+.It Dv PTRACE_VFORK
+Report a stop event when a parent process resumes after a
+.Xr vfork 2 .
+.Pp
+When a thread in the traced process creates a new child process via
+.Xr vfork 2 ,
+the stop that reports
+.Dv PL_FLAG_FORKED
+and
+.Dv PL_FLAG_SCX
+occurs just after the child process is created,
+but before the thread waits for the child process to stop sharing process
+memory.
+If a debugger is not tracing the new child process,
+it must ensure that no breakpoints are enabled in the shared process
+memory before detaching from the new child process.
+This means that no breakpoints are enabled in the parent process either.
+.Pp
+The
+.Dv PTRACE_VFORK
+flag enables a new stop that indicates when the new child process stops
+sharing the process memory of the parent process.
+A debugger can reinsert breakpoints in the parent process and resume it
+in response to this event.
+This event is indicated by setting the
+.Dv PL_FLAG_VFORK_DONE
+flag.
+.El
+.Pp
+The default tracing event mask when attaching to a process via
+.Dv PT_ATTACH ,
+.Dv PT_TRACE_ME ,
+or
+.Dv PTRACE_FORK
+includes only
+.Dv PTRACE_EXEC
+events.
+All other event flags are disabled.
+.Pp
+The
+.Fa request
+argument specifies what operation is being performed; the meaning of
+the rest of the arguments depends on the operation, but except for one
+special case noted below, all
+.Fn ptrace
+calls are made by the tracing process, and the
+.Fa pid
+argument specifies the process ID of the traced process
+or a corresponding thread ID.
+The
+.Fa request
+argument
+can be:
+.Bl -tag -width "Dv PT_GET_EVENT_MASK"
+.It Dv PT_TRACE_ME
+This request is the only one used by the traced process; it declares
+that the process expects to be traced by its parent.
+All the other arguments are ignored.
+(If the parent process does not expect to trace the child, it will
+probably be rather confused by the results; once the traced process
+stops, it cannot be made to continue except via
+.Fn ptrace . )
+When a process has used this request and calls
+.Xr execve 2
+or any of the routines built on it
+(such as
+.Xr execv 3 ) ,
+it will stop before executing the first instruction of the new image.
+Also, any setuid or setgid bits on the executable being executed will
+be ignored.
+If the child was created by
+.Xr vfork 2
+system call or
+.Xr rfork 2
+call with the
+.Dv RFMEM
+flag specified, the debugging events are reported to the parent
+only after the
+.Xr execve 2
+is executed.
+.It Dv PT_READ_I , Dv PT_READ_D
+These requests read a single
+.Vt int
+of data from the traced process's address space.
+Traditionally,
+.Fn ptrace
+has allowed for machines with distinct address spaces for instruction
+and data, which is why there are two requests: conceptually,
+.Dv PT_READ_I
+reads from the instruction space and
+.Dv PT_READ_D
+reads from the data space.
+In the current
+.Fx
+implementation, these two requests are completely identical.
+The
+.Fa addr
+argument specifies the address
+(in the traced process's virtual address space)
+at which the read is to be done.
+This address does not have to meet any alignment constraints.
+The value read is returned as the return value from
+.Fn ptrace .
+.It Dv PT_WRITE_I , Dv PT_WRITE_D
+These requests parallel
+.Dv PT_READ_I
+and
+.Dv PT_READ_D ,
+except that they write rather than read.
+The
+.Fa data
+argument supplies the value to be written.
+.It Dv PT_IO
+This request allows reading and writing arbitrary amounts of data in
+the traced process's address space.
+The
+.Fa addr
+argument specifies a pointer to a
+.Vt "struct ptrace_io_desc" ,
+which is defined as follows:
+.Bd -literal
+struct ptrace_io_desc {
+ int piod_op; /* I/O operation */
+ void *piod_offs; /* child offset */
+ void *piod_addr; /* parent offset */
+ size_t piod_len; /* request length */
+};
+
+/*
+ * Operations in piod_op.
+ */
+#define PIOD_READ_D 1 /* Read from D space */
+#define PIOD_WRITE_D 2 /* Write to D space */
+#define PIOD_READ_I 3 /* Read from I space */
+#define PIOD_WRITE_I 4 /* Write to I space */
+.Ed
+.Pp
+The
+.Fa data
+argument is ignored.
+The actual number of bytes read or written is stored in
+.Va piod_len
+upon return.
+.It Dv PT_CONTINUE
+The traced process continues execution.
+The
+.Fa addr
+argument
+is an address specifying the place where execution is to be resumed
+(a new value for the program counter),
+or
+.Po Vt caddr_t Pc Ns 1
+to indicate that execution is to pick up where it left off.
+The
+.Fa data
+argument
+provides a signal number to be delivered to the traced process as it
+resumes execution, or 0 if no signal is to be sent.
+.It Dv PT_STEP
+The traced process is single stepped one instruction.
+The
+.Fa addr
+argument
+should be passed
+.Po Vt caddr_t Pc Ns 1 .
+The
+.Fa data
+argument
+provides a signal number to be delivered to the traced process as it
+resumes execution, or 0 if no signal is to be sent.
+.It Dv PT_KILL
+The traced process terminates, as if
+.Dv PT_CONTINUE
+had been used with
+.Dv SIGKILL
+given as the signal to be delivered.
+.It Dv PT_ATTACH
+This request allows a process to gain control of an otherwise
+unrelated process and begin tracing it.
+It does not need any cooperation from the to-be-traced process.
+In
+this case,
+.Fa pid
+specifies the process ID of the to-be-traced process, and the other
+two arguments are ignored.
+This request requires that the target process must have the same real
+UID as the tracing process, and that it must not be executing a setuid
+or setgid executable.
+(If the tracing process is running as root, these restrictions do not
+apply.)
+The tracing process will see the newly-traced process stop and may
+then control it as if it had been traced all along.
+.It Dv PT_DETACH
+This request is like PT_CONTINUE, except that it does not allow
+specifying an alternate place to continue execution, and after it
+succeeds, the traced process is no longer traced and continues
+execution normally.
+.It Dv PT_GETREGS
+This request reads the traced process's machine registers into the
+.Do
+.Vt "struct reg"
+.Dc
+(defined in
+.In machine/reg.h )
+pointed to by
+.Fa addr .
+.It Dv PT_SETREGS
+This request is the converse of
+.Dv PT_GETREGS ;
+it loads the traced process's machine registers from the
+.Do
+.Vt "struct reg"
+.Dc
+(defined in
+.In machine/reg.h )
+pointed to by
+.Fa addr .
+.It Dv PT_GETFPREGS
+This request reads the traced process's floating-point registers into
+the
+.Do
+.Vt "struct fpreg"
+.Dc
+(defined in
+.In machine/reg.h )
+pointed to by
+.Fa addr .
+.It Dv PT_SETFPREGS
+This request is the converse of
+.Dv PT_GETFPREGS ;
+it loads the traced process's floating-point registers from the
+.Do
+.Vt "struct fpreg"
+.Dc
+(defined in
+.In machine/reg.h )
+pointed to by
+.Fa addr .
+.It Dv PT_GETDBREGS
+This request reads the traced process's debug registers into
+the
+.Do
+.Vt "struct dbreg"
+.Dc
+(defined in
+.In machine/reg.h )
+pointed to by
+.Fa addr .
+.It Dv PT_SETDBREGS
+This request is the converse of
+.Dv PT_GETDBREGS ;
+it loads the traced process's debug registers from the
+.Do
+.Vt "struct dbreg"
+.Dc
+(defined in
+.In machine/reg.h )
+pointed to by
+.Fa addr .
+.It Dv PT_LWPINFO
+This request can be used to obtain information about the kernel thread,
+also known as light-weight process, that caused the traced process to stop.
+The
+.Fa addr
+argument specifies a pointer to a
+.Vt "struct ptrace_lwpinfo" ,
+which is defined as follows:
+.Bd -literal
+struct ptrace_lwpinfo {
+ lwpid_t pl_lwpid;
+ int pl_event;
+ int pl_flags;
+ sigset_t pl_sigmask;
+ sigset_t pl_siglist;
+ siginfo_t pl_siginfo;
+ char pl_tdname[MAXCOMLEN + 1];
+ pid_t pl_child_pid;
+ u_int pl_syscall_code;
+ u_int pl_syscall_narg;
+};
+.Ed
+.Pp
+The
+.Fa data
+argument is to be set to the size of the structure known to the caller.
+This allows the structure to grow without affecting older programs.
+.Pp
+The fields in the
+.Vt "struct ptrace_lwpinfo"
+have the following meaning:
+.Bl -tag -width indent -compact
+.It Va pl_lwpid
+LWP id of the thread
+.It Va pl_event
+Event that caused the stop.
+Currently defined events are:
+.Bl -tag -width "Dv PL_EVENT_SIGNAL" -compact
+.It Dv PL_EVENT_NONE
+No reason given
+.It Dv PL_EVENT_SIGNAL
+Thread stopped due to the pending signal
+.El
+.It Va pl_flags
+Flags that specify additional details about observed stop.
+Currently defined flags are:
+.Bl -tag -width indent -compact
+.It Dv PL_FLAG_SCE
+The thread stopped due to system call entry, right after the kernel is entered.
+The debugger may examine syscall arguments that are stored in memory and
+registers according to the ABI of the current process, and modify them,
+if needed.
+.It Dv PL_FLAG_SCX
+The thread is stopped immediately before syscall is returning to the usermode.
+The debugger may examine system call return values in the ABI-defined registers
+and/or memory.
+.It Dv PL_FLAG_EXEC
+When
+.Dv PL_FLAG_SCX
+is set, this flag may be additionally specified to inform that the
+program being executed by debuggee process has been changed by successful
+execution of a system call from the
+.Fn execve 2
+family.
+.It Dv PL_FLAG_SI
+Indicates that
+.Va pl_siginfo
+member of
+.Vt "struct ptrace_lwpinfo"
+contains valid information.
+.It Dv PL_FLAG_FORKED
+Indicates that the process is returning from a call to
+.Fn fork 2
+that created a new child process.
+The process identifier of the new process is available in the
+.Va pl_child_pid
+member of
+.Vt "struct ptrace_lwpinfo" .
+.It Dv PL_FLAG_CHILD
+The flag is set for first event reported from a new child which is
+automatically attached when
+.Dv PTRACE_FORK
+is enabled.
+.It Dv PL_FLAG_BORN
+This flag is set for the first event reported from a new LWP when
+.Dv PTRACE_LWP
+is enabled.
+It is reported along with
+.Dv PL_FLAG_SCX .
+.It Dv PL_FLAG_EXITED
+This flag is set for the last event reported by an exiting LWP when
+.Dv PTRACE_LWP
+is enabled.
+Note that this event is not reported when the last LWP in a process exits.
+The termination of the last thread is reported via a normal process exit
+event.
+.It Dv PL_FLAG_VFORKED
+Indicates that the thread is returning from a call to
+.Xr vfork 2
+that created a new child process.
+This flag is set in addition to
+.Dv PL_FLAG_FORKED .
+.It Dv PL_FLAG_VFORK_DONE
+Indicates that the thread has resumed after a child process created via
+.Xr vfork 2
+has stopped sharing its address space with the traced process.
+.El
+.It Va pl_sigmask
+The current signal mask of the LWP
+.It Va pl_siglist
+The current pending set of signals for the LWP.
+Note that signals that are delivered to the process would not appear
+on an LWP siglist until the thread is selected for delivery.
+.It Va pl_siginfo
+The siginfo that accompanies the signal pending.
+Only valid for
+.Dv PL_EVENT_SIGNAL
+stop when
+.Dv PL_FLAG_SI
+is set in
+.Va pl_flags .
+.It Va pl_tdname
+The name of the thread.
+.It Va pl_child_pid
+The process identifier of the new child process.
+Only valid for a
+.Dv PL_EVENT_SIGNAL
+stop when
+.Dv PL_FLAG_FORKED
+is set in
+.Va pl_flags .
+.It Va pl_syscall_code
+The ABI-specific identifier of the current system call.
+Note that for indirect system calls this field reports the indirected
+system call.
+Only valid when
+.Dv PL_FLAG_SCE
+or
+.Dv PL_FLAG_SCX
+is set in
+.Va pl_flags.
+.It Va pl_syscall_narg
+The number of arguments passed to the current system call not counting
+the system call identifier.
+Note that for indirect system calls this field reports the arguments
+passed to the indirected system call.
+Only valid when
+.Dv PL_FLAG_SCE
+or
+.Dv PL_FLAG_SCX
+is set in
+.Va pl_flags.
+.El
+.It Dv PT_GETNUMLWPS
+This request returns the number of kernel threads associated with the
+traced process.
+.It Dv PT_GETLWPLIST
+This request can be used to get the current thread list.
+A pointer to an array of type
+.Vt lwpid_t
+should be passed in
+.Fa addr ,
+with the array size specified by
+.Fa data .
+The return value from
+.Fn ptrace
+is the count of array entries filled in.
+.It Dv PT_SETSTEP
+This request will turn on single stepping of the specified process.
+.It Dv PT_CLEARSTEP
+This request will turn off single stepping of the specified process.
+.It Dv PT_SUSPEND
+This request will suspend the specified thread.
+.It Dv PT_RESUME
+This request will resume the specified thread.
+.It Dv PT_TO_SCE
+This request will set the
+.Dv PTRACE_SCE
+event flag to trace all future system call entries and continue the process.
+The
+.Fa addr
+and
+.Fa data
+arguments are used the same as for
+.Dv PT_CONTINUE.
+.It Dv PT_TO_SCX
+This request will set the
+.Dv PTRACE_SCX
+event flag to trace all future system call exits and continue the process.
+The
+.Fa addr
+and
+.Fa data
+arguments are used the same as for
+.Dv PT_CONTINUE.
+.It Dv PT_SYSCALL
+This request will set the
+.Dv PTRACE_SYSCALL
+event flag to trace all future system call entries and exits and continue
+the process.
+The
+.Fa addr
+and
+.Fa data
+arguments are used the same as for
+.Dv PT_CONTINUE.
+.It Dv PT_FOLLOW_FORK
+This request controls tracing for new child processes of a traced process.
+If
+.Fa data
+is non-zero,
+.Dv PTRACE_FORK
+is set in the traced process's event tracing mask.
+If
+.Fa data
+is zero,
+.Dv PTRACE_FORK
+is cleared from the traced process's event tracing mask.
+.It Dv PT_LWP_EVENTS
+This request controls tracing of LWP creation and destruction.
+If
+.Fa data
+is non-zero,
+.Dv PTRACE_LWP
+is set in the traced process's event tracing mask.
+If
+.Fa data
+is zero,
+.Dv PTRACE_LWP
+is cleared from the traced process's event tracing mask.
+.It Dv PT_GET_EVENT_MASK
+This request reads the traced process's event tracing mask into the
+integer pointed to by
+.Fa addr .
+The size of the integer must be passed in
+.Fa data .
+.It Dv PT_SET_EVENT_MASK
+This request sets the traced process's event tracing mask from the
+integer pointed to by
+.Fa addr .
+The size of the integer must be passed in
+.Fa data .
+.It Dv PT_VM_TIMESTAMP
+This request returns the generation number or timestamp of the memory map of
+the traced process as the return value from
+.Fn ptrace .
+This provides a low-cost way for the tracing process to determine if the
+VM map changed since the last time this request was made.
+.It Dv PT_VM_ENTRY
+This request is used to iterate over the entries of the VM map of the traced
+process.
+The
+.Fa addr
+argument specifies a pointer to a
+.Vt "struct ptrace_vm_entry" ,
+which is defined as follows:
+.Bd -literal
+struct ptrace_vm_entry {
+ int pve_entry;
+ int pve_timestamp;
+ u_long pve_start;
+ u_long pve_end;
+ u_long pve_offset;
+ u_int pve_prot;
+ u_int pve_pathlen;
+ long pve_fileid;
+ uint32_t pve_fsid;
+ char *pve_path;
+};
+.Ed
+.Pp
+The first entry is returned by setting
+.Va pve_entry
+to zero.
+Subsequent entries are returned by leaving
+.Va pve_entry
+unmodified from the value returned by previous requests.
+The
+.Va pve_timestamp
+field can be used to detect changes to the VM map while iterating over the
+entries.
+The tracing process can then take appropriate action, such as restarting.
+By setting
+.Va pve_pathlen
+to a non-zero value on entry, the pathname of the backing object is returned
+in the buffer pointed to by
+.Va pve_path ,
+provided the entry is backed by a vnode.
+The
+.Va pve_pathlen
+field is updated with the actual length of the pathname (including the
+terminating null character).
+The
+.Va pve_offset
+field is the offset within the backing object at which the range starts.
+The range is located in the VM space at
+.Va pve_start
+and extends up to
+.Va pve_end
+(inclusive).
+.Pp
+The
+.Fa data
+argument is ignored.
+.El
+.Sh x86 MACHINE-SPECIFIC REQUESTS
+.Bl -tag -width "Dv PT_GETXSTATE_INFO"
+.It Dv PT_GETXMMREGS
+Copy the XMM FPU state into the buffer pointed to by the
+argument
+.Fa addr .
+The buffer has the same layout as the 32-bit save buffer for the
+machine instruction
+.Dv FXSAVE .
+.Pp
+This request is only valid for i386 programs, both on native 32-bit
+systems and on amd64 kernels.
+For 64-bit amd64 programs, the XMM state is reported as part of
+the FPU state returned by the
+.Dv PT_GETFPREGS
+request.
+.Pp
+The
+.Fa data
+argument is ignored.
+.It Dv PT_SETXMMREGS
+Load the XMM FPU state for the thread from the buffer pointed to
+by the argument
+.Fa addr .
+The buffer has the same layout as the 32-bit load buffer for the
+machine instruction
+.Dv FXRSTOR .
+.Pp
+As with
+.Dv PT_GETXMMREGS,
+this request is only valid for i386 programs.
+.Pp
+The
+.Fa data
+argument is ignored.
+.It Dv PT_GETXSTATE_INFO
+Report which XSAVE FPU extensions are supported by the CPU
+and allowed in userspace programs.
+The
+.Fa addr
+argument must point to a variable of type
+.Vt struct ptrace_xstate_info ,
+which contains the information on the request return.
+.Vt struct ptrace_xstate_info
+is defined as follows:
+.Bd -literal
+struct ptrace_xstate_info {
+ uint64_t xsave_mask;
+ uint32_t xsave_len;
+};
+.Ed
+The
+.Dv xsave_mask
+field is a bitmask of the currently enabled extensions.
+The meaning of the bits is defined in the Intel and AMD
+processor documentation.
+The
+.Dv xsave_len
+field reports the length of the XSAVE area for storing the hardware
+state for currently enabled extensions in the format defined by the x86
+.Dv XSAVE
+machine instruction.
+.Pp
+The
+.Fa data
+argument value must be equal to the size of the
+.Vt struct ptrace_xstate_info .
+.It Dv PT_GETXSTATE
+Return the content of the XSAVE area for the thread.
+The
+.Fa addr
+argument points to the buffer where the content is copied, and the
+.Fa data
+argument specifies the size of the buffer.
+The kernel copies out as much content as allowed by the buffer size.
+The buffer layout is specified by the layout of the save area for the
+.Dv XSAVE
+machine instruction.
+.It Dv PT_SETXSTATE
+Load the XSAVE state for the thread from the buffer specified by the
+.Fa addr
+pointer.
+The buffer size is passed in the
+.Fa data
+argument.
+The buffer must be at least as large as the
+.Vt struct savefpu
+(defined in
+.Pa x86/fpu.h )
+to allow the complete x87 FPU and XMM state load.
+It must not be larger than the XSAVE state length, as reported by the
+.Dv xsave_len
+field from the
+.Vt struct ptrace_xstate_info
+of the
+.Dv PT_GETXSTATE_INFO
+request.
+Layout of the buffer is identical to the layout of the load area for the
+.Dv XRSTOR
+machine instruction.
+.It Dv PT_GETFSBASE
+Return the value of the base used when doing segmented
+memory addressing using the %fs segment register.
+The
+.Fa addr
+argument points to an
+.Vt unsigned long
+variable where the base value is stored.
+.Pp
+The
+.Fa data
+argument is ignored.
+.It Dv PT_GETGSBASE
+Like the
+.Dv PT_GETFSBASE
+request, but returns the base for the %gs segment register.
+.It Dv PT_SETFSBASE
+Set the base for the %fs segment register to the value pointed to
+by the
+.Fa addr
+argument.
+.Fa addr
+must point to the
+.Vt unsigned long
+variable containing the new base.
+.Pp
+The
+.Fa data
+argument is ignored.
+.It Dv PT_SETGSBASE
+Like the
+.Dv PT_SETFSBASE
+request, but sets the base for the %gs segment register.
+.El
+.Sh PowerPC MACHINE-SPECIFIC REQUESTS
+.Bl -tag -width "Dv PT_SETVRREGS"
+.It Dv PT_GETVRREGS
+Return the thread's
+.Dv ALTIVEC
+machine state in the buffer pointed to by
+.Fa addr .
+.Pp
+The
+.Fa data
+argument is ignored.
+.It Dv PT_SETVRREGS
+Set the thread's
+.Dv ALTIVEC
+machine state from the buffer pointed to by
+.Fa addr .
+.Pp
+The
+.Fa data
+argument is ignored.
+.El
+.Pp
+Additionally, other machine-specific requests can exist.
+.Sh RETURN VALUES
+Most requests return 0 on success and \-1 on error.
+Some requests can cause
+.Fn ptrace
+to return
+\-1
+as a non-error value, among them are
+.Dv PT_READ_I
+and
+.Dv PT_READ_D ,
+which return the value read from the process memory on success.
+To disambiguate,
+.Va errno
+can be set to 0 before the call and checked afterwards.
+.Pp
+The current
+.Fn ptrace
+implementation always sets
+.Va errno
+to 0 before calling into the kernel, both for historic reasons and for
+consistency with other operating systems.
+It is recommended to assign zero to
+.Va errno
+explicitly for forward compatibility.
+.Sh ERRORS
+The
+.Fn ptrace
+system call may fail if:
+.Bl -tag -width Er
+.It Bq Er ESRCH
+.Bl -bullet -compact
+.It
+No process having the specified process ID exists.
+.El
+.It Bq Er EINVAL
+.Bl -bullet -compact
+.It
+A process attempted to use
+.Dv PT_ATTACH
+on itself.
+.It
+The
+.Fa request
+argument
+was not one of the legal requests.
+.It
+The signal number
+(in
+.Fa data )
+to
+.Dv PT_CONTINUE
+was neither 0 nor a legal signal number.
+.It
+.Dv PT_GETREGS ,
+.Dv PT_SETREGS ,
+.Dv PT_GETFPREGS ,
+.Dv PT_SETFPREGS ,
+.Dv PT_GETDBREGS ,
+or
+.Dv PT_SETDBREGS
+was attempted on a process with no valid register set.
+(This is normally true only of system processes.)
+.It
+.Dv PT_VM_ENTRY
+was given an invalid value for
+.Fa pve_entry .
+This can also be caused by changes to the VM map of the process.
+.It
+The size (in
+.Fa data )
+provided to
+.Dv PT_LWPINFO
+was less than or equal to zero, or larger than the
+.Vt ptrace_lwpinfo
+structure known to the kernel.
+.It
+The size (in
+.Fa data )
+provided to the x86-specific
+.Dv PT_GETXSTATE_INFO
+request was not equal to the size of the
+.Vt struct ptrace_xstate_info .
+.It
+The size (in
+.Fa data )
+provided to the x86-specific
+.Dv PT_SETXSTATE
+request was less than the size of the x87 plus the XMM save area.
+.It
+The size (in
+.Fa data )
+provided to the x86-specific
+.Dv PT_SETXSTATE
+request was larger than returned in the
+.Dv xsave_len
+member of the
+.Vt struct ptrace_xstate_info
+from the
+.Dv PT_GETXSTATE_INFO
+request.
+.It
+The base value, provided to the amd64-specific requests
+.Dv PT_SETFSBASE
+or
+.Dv PT_SETGSBASE ,
+pointed outside of the valid user address space.
+This error will not occur in 32-bit programs.
+.El
+.It Bq Er EBUSY
+.Bl -bullet -compact
+.It
+.Dv PT_ATTACH
+was attempted on a process that was already being traced.
+.It
+A request attempted to manipulate a process that was being traced by
+some process other than the one making the request.
+.It
+A request
+(other than
+.Dv PT_ATTACH )
+specified a process that was not stopped.
+.El
+.It Bq Er EPERM
+.Bl -bullet -compact
+.It
+A request
+(other than
+.Dv PT_ATTACH )
+attempted to manipulate a process that was not being traced at all.
+.It
+An attempt was made to use
+.Dv PT_ATTACH
+on a process in violation of the requirements listed under
+.Dv PT_ATTACH
+above.
+.El
+.It Bq Er ENOENT
+.Bl -bullet -compact
+.It
+.Dv PT_VM_ENTRY
+previously returned the last entry of the memory map.
+No more entries exist.
+.El
+.It Bq Er ENAMETOOLONG
+.Bl -bullet -compact
+.It
+.Dv PT_VM_ENTRY
+cannot return the pathname of the backing object because the buffer is not big
+enough.
+.Fa pve_pathlen
+holds the minimum buffer size required on return.
+.El
+.El
+.Sh SEE ALSO
+.Xr execve 2 ,
+.Xr sigaction 2 ,
+.Xr wait 2 ,
+.Xr execv 3 ,
+.Xr i386_clr_watch 3 ,
+.Xr i386_set_watch 3
+.Sh HISTORY
+The
+.Fn ptrace
+function appeared in
+.At v7 .
diff --git a/lib/libc/sys/ptrace.c b/lib/libc/sys/ptrace.c
new file mode 100644
index 000000000000..2bb615fe563e
--- /dev/null
+++ b/lib/libc/sys/ptrace.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2016 The FreeBSD Foundation.
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Konstantin Belousov
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice(s), this list of conditions and the following disclaimer as
+ * the first lines of this file unmodified other than the possible
+ * addition of one or more copyright notices.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice(s), this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <errno.h>
+#include "libc_private.h"
+
+__weak_reference(_ptrace, ptrace);
+
+int
+_ptrace(int request, pid_t pid, caddr_t addr, int data)
+{
+
+ errno = 0;
+ return (__sys_ptrace(request, pid, addr, data));
+}
diff --git a/lib/libc/sys/quotactl.2 b/lib/libc/sys/quotactl.2
new file mode 100644
index 000000000000..6dabff0ec30c
--- /dev/null
+++ b/lib/libc/sys/quotactl.2
@@ -0,0 +1,261 @@
+.\" Copyright (c) 1983, 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Robert Elz at The University of Melbourne.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)quotactl.2 8.2 (Berkeley) 3/10/95
+.\" $FreeBSD$
+.\"
+.Dd March 5, 1999
+.Dt QUOTACTL 2
+.Os
+.Sh NAME
+.Nm quotactl
+.Nd manipulate file system quotas
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In ufs/ufs/quota.h
+.Ft int
+.Fn quotactl "const char *path" "int cmd" "int id" "void *addr"
+.Sh DESCRIPTION
+The
+.Fn quotactl
+system call enables, disables and
+manipulates file system quotas.
+A quota control command
+given by
+.Fa cmd
+operates on the given filename
+.Fa path
+for the given user or group
+.Fa id .
+(NOTE: One should use the QCMD macro defined in
+.In ufs/ufs/quota.h
+to formulate the value for
+.Fa cmd . )
+The address of an optional command specific data structure,
+.Fa addr ,
+may be given; its interpretation
+is discussed below with each command.
+.Pp
+For commands that use the
+.Fa id
+identifier, it must be either -1 or any positive value.
+The value of -1 indicates that the current UID or GID should be used.
+Any other negative value will return an error.
+.Pp
+Currently quotas are supported only for the
+.Dq ufs
+file system.
+For
+.Dq ufs ,
+a command is composed of a primary command (see below)
+and a command type used to interpret the
+.Fa id .
+Types are supported for interpretation of user identifiers (USRQUOTA)
+and group identifiers (GRPQUOTA).
+The
+.Dq ufs
+specific commands are:
+.Bl -tag -width Q_GETQUOTASIZEx
+.It Dv Q_QUOTAON
+Enable disk quotas for the file system specified by
+.Fa path .
+The command type specifies the type of the quotas being enabled.
+The
+.Fa addr
+argument specifies a file from which to take the quotas.
+The quota file must exist;
+it is normally created with the
+.Xr quotacheck 8
+program.
+The
+.Fa id
+argument is unused.
+Only the super-user may turn quotas on.
+.It Dv Q_QUOTAOFF
+Disable disk quotas for the file system specified by
+.Fa path .
+The command type specifies the type of the quotas being disabled.
+The
+.Fa addr
+and
+.Fa id
+arguments are unused.
+Only the super-user may turn quotas off.
+.It Dv Q_GETQUOTASIZE
+Get the wordsize used to represent the quotas for the user or group
+(as determined by the command type).
+Possible values are 32 for the old-style quota file
+and 64 for the new-style quota file.
+The
+.Fa addr
+argument is a pointer to an integer into which the size is stored.
+The identifier
+.Fa id
+is not used.
+.It Dv Q_GETQUOTA
+Get disk quota limits and current usage for the user or group
+(as determined by the command type) with identifier
+.Fa id .
+The
+.Fa addr
+argument
+is a pointer to a
+.Fa struct dqblk
+structure (defined in
+.In ufs/ufs/quota.h ) .
+.It Dv Q_SETQUOTA
+Set disk quota limits for the user or group
+(as determined by the command type) with identifier
+.Fa id .
+The
+.Fa addr
+argument
+is a pointer to a
+.Fa struct dqblk
+structure (defined in
+.In ufs/ufs/quota.h ) .
+The usage fields of the
+.Fa dqblk
+structure are ignored.
+This system call is restricted to the super-user.
+.It Dv Q_SETUSE
+Set disk usage limits for the user or group
+(as determined by the command type) with identifier
+.Fa id .
+The
+.Fa addr
+argument
+is a pointer to a
+.Fa struct dqblk
+structure (defined in
+.In ufs/ufs/quota.h ) .
+Only the usage fields are used.
+This system call is restricted to the super-user.
+.It Dv Q_SYNC
+Update the on-disk copy of quota usages.
+The command type specifies which type of quotas are to be updated.
+The
+.Fa id
+and
+.Fa addr
+arguments are ignored.
+.El
+.Sh RETURN VALUES
+.Rv -std quotactl
+.Sh ERRORS
+The
+.Fn quotactl
+system call will fail if:
+.Bl -tag -width Er
+.It Bq Er EOPNOTSUPP
+The kernel has not been compiled with the
+.Dv QUOTA
+option.
+.It Bq Er EUSERS
+The quota table cannot be expanded.
+.It Bq Er EINVAL
+The
+.Fa cmd
+argument
+or the command type is invalid.
+In
+.Dv Q_GETQUOTASIZE ,
+.Dv Q_GETQUOTA ,
+.Dv Q_SETQUOTA ,
+and
+.Dv Q_SETUSE ,
+quotas are not currently enabled for this file system.
+.Pp
+The
+.Fa id
+argument to
+.Dv Q_GETQUOTA ,
+.Dv Q_SETQUOTA
+or
+.Dv Q_SETUSE
+is a negative value.
+.It Bq Er EACCES
+In
+.Dv Q_QUOTAON ,
+the quota file is not a plain file.
+.It Bq Er EACCES
+Search permission is denied for a component of a path prefix.
+.It Bq Er ENOTDIR
+A component of a path prefix was not a directory.
+.It Bq Er ENAMETOOLONG
+A component of either pathname exceeded 255 characters,
+or the entire length of either path name exceeded 1023 characters.
+.It Bq Er ENOENT
+A filename does not exist.
+.It Bq Er ELOOP
+Too many symbolic links were encountered in translating a pathname.
+.It Bq Er EROFS
+In
+.Dv Q_QUOTAON ,
+either the file system on which quotas are to be enabled is mounted read-only
+or the quota file resides on a read-only file system.
+.It Bq Er EIO
+An
+.Tn I/O
+error occurred while reading from or writing
+to a file containing quotas.
+.It Bq Er EFAULT
+An invalid
+.Fa addr
+was supplied; the associated structure could not be copied in or out
+of the kernel.
+.It Bq Er EFAULT
+The
+.Fa path
+argument
+points outside the process's allocated address space.
+.It Bq Er EPERM
+The call was privileged and the caller was not the super-user.
+.El
+.Sh SEE ALSO
+.Xr quota 1 ,
+.Xr fstab 5 ,
+.Xr edquota 8 ,
+.Xr quotacheck 8 ,
+.Xr quotaon 8 ,
+.Xr repquota 8
+.Sh HISTORY
+The
+.Fn quotactl
+system call appeared in
+.Bx 4.3 Reno .
+.Sh BUGS
+There should be some way to integrate this call with the resource
+limit interface provided by
+.Xr setrlimit 2
+and
+.Xr getrlimit 2 .
diff --git a/lib/libc/sys/rctl_add_rule.2 b/lib/libc/sys/rctl_add_rule.2
new file mode 100644
index 000000000000..667a0059470d
--- /dev/null
+++ b/lib/libc/sys/rctl_add_rule.2
@@ -0,0 +1,220 @@
+.\" Copyright (c) 2016 Eric Badger
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 September 14, 2016
+.Dt RCTL_ADD_RULE 2
+.Os
+.Sh NAME
+.Nm rctl_add_rule,
+.Nm rctl_get_limits
+.Nm rctl_get_racct,
+.Nm rctl_get_rules,
+.Nm rctl_remove_rule
+.Nd manipulate and query the resource limits database
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/rctl.h
+.Ft int
+.Fo rctl_add_rule
+.Fa "const char *inbufp" "size_t inbuflen" "char *outbufp" "size_t outbuflen"
+.Fc
+.Ft int
+.Fo rctl_get_limits
+.Fa "const char *inbufp" "size_t inbuflen" "char *outbufp" "size_t outbuflen"
+.Fc
+.Ft int
+.Fo rctl_get_racct
+.Fa "const char *inbufp" "size_t inbuflen" "char *outbufp" "size_t outbuflen"
+.Fc
+.Ft int
+.Fo rctl_get_rules
+.Fa "const char *inbufp" "size_t inbuflen" "char *outbufp" "size_t outbuflen"
+.Fc
+.Ft int
+.Fo rctl_remove_rule
+.Fa "const char *inbufp" "size_t inbuflen" "char *outbufp" "size_t outbuflen"
+.Fc
+.Sh DESCRIPTION
+These system calls are used to manipulate and query the resource limits
+database.
+For all functions,
+.Fa inbuflen
+refers to the length of the buffer pointed to by
+.Fa inbufp
+and
+.Fa outbuflen
+refers to the length of the buffer pointed to by
+.Fa outbufp .
+.Pp
+The
+.Fn rctl_add_rule
+function adds the rule pointed to by
+.Fa inbufp
+to the resource limits database.
+The
+.Fa outbufp
+and
+.Fa outbuflen
+arguments are unused.
+Rule format is as described in
+.Xr rctl 8 ,
+with exceptions noted in the
+.Sx RULES AND FILTERS
+section.
+.Pp
+The
+.Fn rctl_get_limits
+function returns in
+.Fa outbufp
+a comma-separated list of rules that apply to the process that
+matches the filter specified in
+.Fa inbufp .
+This includes rules with a subject of the process itself as well as rules
+with a different subject (such as user or loginclass) that apply to the
+process.
+.Pp
+The
+.Fn rctl_get_racct
+function returns resource usage information for a given subject.
+The subject is specified by passing a filter in
+.Fa inbufp .
+Filter syntax is as described in
+.Xr rctl 8 ,
+with exceptions noted in the
+.Sx RULES AND FILTERS
+section.
+A comma-separated list of resources and the amount used of each by the
+specified subject is returned in
+.Fa outbufp .
+The resource and amount is formatted as
+.Qq resource=amount .
+.Pp
+The
+.Fn rctl_get_rules
+function returns in
+.Fa outbufp
+a comma-separated list of rules from the resource limits database that
+match the filter passed in
+.Fa inbufp .
+Filter syntax is as described in
+.Xr rctl 8 ,
+with exceptions noted in the
+.Sx RULES AND FILTERS
+section.
+A filter of
+.Va ::
+may be passed to return all rules.
+.Pp
+The
+.Fn rctl_remove_rule
+function removes all rules matching the filter passed in
+.Fa inbufp
+from the resource limits database.
+Filter syntax is as described in
+.Xr rctl 8 ,
+with exceptions noted in the
+.Sx RULES AND FILTERS
+section.
+.Fa outbufp
+and
+.Fa outbuflen
+are unused.
+.Sh RULES AND FILTERS
+This section explains how the rule and filter format described in
+.Xr rctl 8
+differs from the format passed to the system calls themselves.
+The rctl tool provides several conveniences that the system calls do not.
+When using the system call:
+.Bl -dash -offset indent
+.It
+The subject must be fully specified.
+For example, abbreviating
+.Ql user
+to
+.Ql u
+is not acceptable.
+.It
+User and group IDs must be numeric.
+For example,
+.Ql root
+must be expressed as
+.Ql 0 .
+.It
+Units are not permitted on resource amounts.
+For example, a quantity of 1024 bytes must be expressed as
+.Ql 1024
+and not
+.Ql 1k .
+.El
+.Sh RETURN VALUES
+.Rv -std
+.Sh ERRORS
+The rctl system calls may fail if:
+.Bl -tag -width Er
+.It Bq Er ENOSYS
+RACCT/RCTL support is not present in the kernel or the
+.Va kern.racct.enable
+sysctl is 0.
+.It Bq Er EINVAL
+The rule or filter passed in
+.Fa inbufp
+is invalid.
+.It Bq Er EPERM
+User has insufficient privileges to carry out the requested operation.
+.It Bq Er E2BIG
+.Fa inbufp
+or
+.Fa outbufp
+are too large.
+.It Bq Er ESRCH
+No process matched the provided rule or filter.
+.It Bq Er ENAMETOOLONG
+The loginclass or jail name specified is too long.
+.It Bq Er ERANGE
+The rule amount is outside of the allowable range or
+.Fa outbufp
+is too small.
+.It Bq Er EOPNOTSUPP
+The requested operation is not supported for the given rule or filter.
+.It Bq Er EFAULT
+.Fa inbufp
+or
+.Fa outbufp
+refer to invalid addresses.
+.El
+.Sh SEE ALSO
+.Xr rctl 8
+.Sh HISTORY
+The rctl family of system calls appeared in
+.Fx 9.0 .
+.Sh AUTHORS
+.An -nosplit
+The rctl system calls were developed by
+.An Edward Tomasz Napierala Aq Mt trasz@FreeBSD.org
+under sponsorship from the FreeBSD Foundation.
+This manual page was written by
+.An Eric Badger Aq Mt badger@FreeBSD.org .
diff --git a/lib/libc/sys/read.2 b/lib/libc/sys/read.2
new file mode 100644
index 000000000000..a0a7be838c0b
--- /dev/null
+++ b/lib/libc/sys/read.2
@@ -0,0 +1,284 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)read.2 8.4 (Berkeley) 2/26/94
+.\" $FreeBSD$
+.\"
+.Dd December 15, 2015
+.Dt READ 2
+.Os
+.Sh NAME
+.Nm read ,
+.Nm readv ,
+.Nm pread ,
+.Nm preadv
+.Nd read input
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft ssize_t
+.Fn read "int fd" "void *buf" "size_t nbytes"
+.Ft ssize_t
+.Fn pread "int fd" "void *buf" "size_t nbytes" "off_t offset"
+.In sys/uio.h
+.Ft ssize_t
+.Fn readv "int fd" "const struct iovec *iov" "int iovcnt"
+.Ft ssize_t
+.Fn preadv "int fd" "const struct iovec *iov" "int iovcnt" "off_t offset"
+.Sh DESCRIPTION
+The
+.Fn read
+system call
+attempts to read
+.Fa nbytes
+of data from the object referenced by the descriptor
+.Fa fd
+into the buffer pointed to by
+.Fa buf .
+The
+.Fn readv
+system call
+performs the same action, but scatters the input data
+into the
+.Fa iovcnt
+buffers specified by the members of the
+.Fa iov
+array: iov[0], iov[1], ..., iov[iovcnt\|\-\|1].
+The
+.Fn pread
+and
+.Fn preadv
+system calls
+perform the same functions, but read from the specified position in
+the file without modifying the file pointer.
+.Pp
+For
+.Fn readv
+and
+.Fn preadv ,
+the
+.Fa iovec
+structure is defined as:
+.Pp
+.Bd -literal -offset indent -compact
+struct iovec {
+ void *iov_base; /* Base address. */
+ size_t iov_len; /* Length. */
+};
+.Ed
+.Pp
+Each
+.Fa iovec
+entry specifies the base address and length of an area
+in memory where data should be placed.
+The
+.Fn readv
+system call
+will always fill an area completely before proceeding
+to the next.
+.Pp
+On objects capable of seeking, the
+.Fn read
+starts at a position
+given by the pointer associated with
+.Fa fd
+(see
+.Xr lseek 2 ) .
+Upon return from
+.Fn read ,
+the pointer is incremented by the number of bytes actually read.
+.Pp
+Objects that are not capable of seeking always read from the current
+position.
+The value of the pointer associated with such an
+object is undefined.
+.Pp
+Upon successful completion,
+.Fn read ,
+.Fn readv ,
+.Fn pread
+and
+.Fn preadv
+return the number of bytes actually read and placed in the buffer.
+The system guarantees to read the number of bytes requested if
+the descriptor references a normal file that has that many bytes left
+before the end-of-file, but in no other case.
+.Sh RETURN VALUES
+If successful, the
+number of bytes actually read is returned.
+Upon reading end-of-file,
+zero is returned.
+Otherwise, a -1 is returned and the global variable
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+The
+.Fn read ,
+.Fn readv ,
+.Fn pread
+and
+.Fn preadv
+system calls
+will succeed unless:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa fd
+argument
+is not a valid file or socket descriptor open for reading.
+.It Bq Er ECONNRESET
+The
+.Fa fd
+argument refers to a socket, and the remote socket end is
+forcibly closed.
+.It Bq Er EFAULT
+The
+.Fa buf
+argument
+points outside the allocated address space.
+.It Bq Er EIO
+An I/O error occurred while reading from the file system.
+.It Bq Er EBUSY
+Failed to read from a file, e.g. /proc/<pid>/regs while <pid> is not stopped
+.It Bq Er EINTR
+A read from a slow device
+(i.e.\& one that might block for an arbitrary amount of time)
+was interrupted by the delivery of a signal
+before any data arrived.
+.It Bq Er EINVAL
+The pointer associated with
+.Fa fd
+was negative.
+.It Bq Er EAGAIN
+The file was marked for non-blocking I/O,
+and no data were ready to be read.
+.It Bq Er EISDIR
+The file descriptor is associated with a directory residing
+on a file system that does not allow regular read operations on
+directories (e.g.\& NFS).
+.It Bq Er EOPNOTSUPP
+The file descriptor is associated with a file system and file type that
+do not allow regular read operations on it.
+.It Bq Er EOVERFLOW
+The file descriptor is associated with a regular file,
+.Fa nbytes
+is greater than 0,
+.Fa offset
+is before the end-of-file, and
+.Fa offset
+is greater than or equal to the offset maximum established
+for this file system.
+.It Bq Er EINVAL
+The value
+.Fa nbytes
+is greater than
+.Dv INT_MAX .
+.El
+.Pp
+In addition,
+.Fn readv
+and
+.Fn preadv
+may return one of the following errors:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa iovcnt
+argument
+was less than or equal to 0, or greater than
+.Dv IOV_MAX .
+.It Bq Er EINVAL
+One of the
+.Fa iov_len
+values in the
+.Fa iov
+array was negative.
+.It Bq Er EINVAL
+The sum of the
+.Fa iov_len
+values in the
+.Fa iov
+array overflowed a 32-bit integer.
+.It Bq Er EFAULT
+Part of the
+.Fa iov
+array points outside the process's allocated address space.
+.El
+.Pp
+The
+.Fn pread
+and
+.Fn preadv
+system calls may also return the following errors:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa offset
+value was negative.
+.It Bq Er ESPIPE
+The file descriptor is associated with a pipe, socket, or FIFO.
+.El
+.Sh SEE ALSO
+.Xr dup 2 ,
+.Xr fcntl 2 ,
+.Xr getdirentries 2 ,
+.Xr open 2 ,
+.Xr pipe 2 ,
+.Xr select 2 ,
+.Xr socket 2 ,
+.Xr socketpair 2 ,
+.Xr fread 3 ,
+.Xr readdir 3
+.Sh STANDARDS
+The
+.Fn read
+system call is expected to conform to
+.St -p1003.1-90 .
+The
+.Fn readv
+and
+.Fn pread
+system calls are expected to conform to
+.St -xpg4.2 .
+.Sh HISTORY
+The
+.Fn preadv
+system call appeared in
+.Fx 6.0 .
+The
+.Fn pread
+function appeared in
+.At V.4 .
+The
+.Fn readv
+system call appeared in
+.Bx 4.2 .
+The
+.Fn read
+function appeared in
+.At v6 .
diff --git a/lib/libc/sys/read.c b/lib/libc/sys/read.c
new file mode 100644
index 000000000000..ab30189026e3
--- /dev/null
+++ b/lib/libc/sys/read.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2014 The FreeBSD Foundation.
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Konstantin Belousov
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice(s), this list of conditions and the following disclaimer as
+ * the first lines of this file unmodified other than the possible
+ * addition of one or more copyright notices.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice(s), this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+#include "libc_private.h"
+
+__weak_reference(__sys_read, __read);
+
+#pragma weak read
+ssize_t
+read(int fd, void *buf, size_t nbytes)
+{
+
+ return (((ssize_t (*)(int, void *, size_t))
+ __libc_interposing[INTERPOS_read])(fd, buf, nbytes));
+}
diff --git a/lib/libc/sys/readlink.2 b/lib/libc/sys/readlink.2
new file mode 100644
index 000000000000..4b2405254538
--- /dev/null
+++ b/lib/libc/sys/readlink.2
@@ -0,0 +1,158 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)readlink.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd April 10, 2008
+.Dt READLINK 2
+.Os
+.Sh NAME
+.Nm readlink ,
+.Nm readlinkat
+.Nd read value of a symbolic link
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft ssize_t
+.Fn readlink "const char *restrict path" "char *restrict buf" "size_t bufsiz"
+.Ft ssize_t
+.Fo readlinkat
+.Fa "int fd" "const char *restrict path" "char *restrict buf" "size_t bufsize"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn readlink
+system call
+places the contents of the symbolic link
+.Fa path
+in the buffer
+.Fa buf ,
+which has size
+.Fa bufsiz .
+The
+.Fn readlink
+system call does not append a
+.Dv NUL
+character to
+.Fa buf .
+.Pp
+The
+.Fn readlinkat
+system call is equivalent to
+.Fn readlink
+except in the case where
+.Fa path
+specifies a relative path.
+In this case the symbolic link whose content is read relative to the
+directory associated with the file descriptor
+.Fa fd
+instead of the current working directory.
+If
+.Fn readlinkat
+is passed the special value
+.Dv AT_FDCWD
+in the
+.Fa fd
+parameter, the current working directory is used and the behavior is
+identical to a call to
+.Fn readlink .
+.Sh RETURN VALUES
+The call returns the count of characters placed in the buffer
+if it succeeds, or a \-1 if an error occurs, placing the error
+code in the global variable
+.Va errno .
+.Sh ERRORS
+The
+.Fn readlink
+system call
+will fail if:
+.Bl -tag -width Er
+.It Bq Er ENOTDIR
+A component of the path prefix is not a directory.
+.It Bq Er ENAMETOOLONG
+A component of a pathname exceeded 255 characters,
+or an entire path name exceeded 1023 characters.
+.It Bq Er ENOENT
+The named file does not exist.
+.It Bq Er EACCES
+Search permission is denied for a component of the path prefix.
+.It Bq Er ELOOP
+Too many symbolic links were encountered in translating the pathname.
+.It Bq Er EINVAL
+The named file is not a symbolic link.
+.It Bq Er EIO
+An I/O error occurred while reading from the file system.
+.It Bq Er EFAULT
+The
+.Fa buf
+argument
+extends outside the process's allocated address space.
+.El
+.Pp
+In addition to the errors returned by the
+.Fn readlink ,
+the
+.Fn readlinkat
+may fail if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa path
+argument does not specify an absolute path and the
+.Fa fd
+argument is neither
+.Dv AT_FDCWD
+nor a valid file descriptor open for searching.
+.It Bq Er ENOTDIR
+The
+.Fa path
+argument is not an absolute path and
+.Fa fd
+is neither
+.Dv AT_FDCWD
+nor a file descriptor associated with a directory.
+.El
+.Sh SEE ALSO
+.Xr lstat 2 ,
+.Xr stat 2 ,
+.Xr symlink 2 ,
+.Xr symlink 7
+.Sh STANDARDS
+The
+.Fn readlinkat
+system call follows The Open Group Extended API Set 2 specification.
+.Sh HISTORY
+The
+.Fn readlink
+system call appeared in
+.Bx 4.2 .
+The
+.Fn readlinkat
+system call appeared in
+.Fx 8.0 .
diff --git a/lib/libc/sys/readv.c b/lib/libc/sys/readv.c
new file mode 100644
index 000000000000..567292750da0
--- /dev/null
+++ b/lib/libc/sys/readv.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2014 The FreeBSD Foundation.
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Konstantin Belousov
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice(s), this list of conditions and the following disclaimer as
+ * the first lines of this file unmodified other than the possible
+ * addition of one or more copyright notices.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice(s), this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/syscall.h>
+#include <sys/uio.h>
+#include <unistd.h>
+#include "libc_private.h"
+
+__weak_reference(__sys_readv, __readv);
+
+#pragma weak readv
+ssize_t
+readv(int fd, const struct iovec *iov, int iovcnt)
+{
+
+ return (((ssize_t (*)(int, const struct iovec *, int))
+ __libc_interposing[INTERPOS_readv])(fd, iov, iovcnt));
+}
diff --git a/lib/libc/sys/reboot.2 b/lib/libc/sys/reboot.2
new file mode 100644
index 000000000000..ce8cc713d931
--- /dev/null
+++ b/lib/libc/sys/reboot.2
@@ -0,0 +1,168 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)reboot.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd September 18, 2015
+.Dt REBOOT 2
+.Os
+.Sh NAME
+.Nm reboot
+.Nd reboot system or halt processor
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.In sys/reboot.h
+.Ft int
+.Fn reboot "int howto"
+.Sh DESCRIPTION
+The
+.Fn reboot
+system call
+reboots the system.
+Only the super-user may reboot a machine on demand.
+However, a reboot is invoked
+automatically in the event of unrecoverable system failures.
+.Pp
+The
+.Fa howto
+argument
+is a mask of options; the system call interface allows the following
+options, defined in the include file
+.In sys/reboot.h ,
+to be passed
+to the new kernel or the new bootstrap and init programs.
+.Bl -tag -width RB_INITNAMEA
+.It Dv RB_AUTOBOOT
+The default, causing the system to reboot in its usual fashion.
+.It Dv RB_ASKNAME
+Interpreted by the bootstrap program itself, causing it to
+prompt on the console as to what file should be booted.
+Normally, the system is booted from the file
+.Dq Ar xx Ns No (0,0)kernel ,
+where
+.Ar xx
+is the default disk name,
+without prompting for the file name.
+.It Dv RB_DFLTROOT
+Use the compiled in root device.
+Normally, the system uses the device from which it was booted
+as the root device if possible.
+(The default behavior is dependent on the ability of the bootstrap program
+to determine the drive from which it was loaded, which is not possible
+on all systems.)
+.It Dv RB_DUMP
+Dump kernel memory before rebooting; see
+.Xr savecore 8
+for more information.
+.It Dv RB_HALT
+The processor is simply halted; no reboot takes place.
+This option should be used with caution.
+.It Dv RB_POWEROFF
+After halting, the shutdown code will do what it can to turn
+off the power.
+This requires hardware support.
+.It Dv RB_INITNAME
+An option allowing the specification of an init program (see
+.Xr init 8 )
+other than
+.Pa /sbin/init
+to be run when the system reboots.
+This switch is not currently available.
+.It Dv RB_KDB
+Load the symbol table and enable a built-in debugger in the system.
+This option will have no useful function if the kernel is not configured
+for debugging.
+Several other options have different meaning if combined
+with this option, although their use may not be possible
+via the
+.Fn reboot
+system call.
+See
+.Xr ddb 4
+for more information.
+.It Dv RB_NOSYNC
+Normally, the disks are sync'd (see
+.Xr sync 8 )
+before the processor is halted or rebooted.
+This option may be useful if file system changes have been made manually
+or if the processor is on fire.
+.It Dv RB_REROOT
+Instead of rebooting, unmount all filesystems except the one containing
+currently-running executable, and mount root filesystem using the same
+mechanism which is used during normal boot, based on
+vfs.root.mountfrom
+.Xr kenv 1
+variable.
+.It Dv RB_RDONLY
+Initially mount the root file system read-only.
+This is currently the default, and this option has been deprecated.
+.It Dv RB_SINGLE
+Normally, the reboot procedure involves an automatic disk consistency
+check and then multi-user operations.
+.Dv RB_SINGLE
+prevents this, booting the system with a single-user shell
+on the console.
+.Dv RB_SINGLE
+is actually interpreted by the
+.Xr init 8
+program in the newly booted system.
+.El
+.Pp
+When no options are given (i.e.,
+.Dv RB_AUTOBOOT
+is used), the system is
+rebooted from file
+.Dq kernel
+in the root file system of unit 0
+of a disk chosen in a processor specific way.
+An automatic consistency check of the disks is normally performed
+(see
+.Xr fsck 8 ) .
+.Sh RETURN VALUES
+If successful, this call never returns.
+Otherwise, a -1 is returned and an error is returned in the global
+variable
+.Va errno .
+.Sh ERRORS
+.Bl -tag -width Er
+.It Bq Er EPERM
+The caller is not the super-user.
+.El
+.Sh SEE ALSO
+.Xr crash 8 ,
+.Xr halt 8 ,
+.Xr init 8 ,
+.Xr reboot 8 ,
+.Xr savecore 8
+.Sh HISTORY
+The
+.Fn reboot
+system call appeared in
+.Bx 4.0 .
diff --git a/lib/libc/sys/recv.2 b/lib/libc/sys/recv.2
new file mode 100644
index 000000000000..b0b008fec514
--- /dev/null
+++ b/lib/libc/sys/recv.2
@@ -0,0 +1,423 @@
+.\" Copyright (c) 1983, 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)recv.2 8.3 (Berkeley) 2/21/94
+.\" $FreeBSD$
+.\"
+.Dd August 18, 2016
+.Dt RECV 2
+.Os
+.Sh NAME
+.Nm recv ,
+.Nm recvfrom ,
+.Nm recvmsg ,
+.Nm recvmmsg
+.Nd receive message(s) from a socket
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/socket.h
+.Ft ssize_t
+.Fn recv "int s" "void *buf" "size_t len" "int flags"
+.Ft ssize_t
+.Fn recvfrom "int s" "void *buf" "size_t len" "int flags" "struct sockaddr * restrict from" "socklen_t * restrict fromlen"
+.Ft ssize_t
+.Fn recvmsg "int s" "struct msghdr *msg" "int flags"
+.Ft ssize_t
+.Fn recvmmsg "int s" "struct mmsghdr * restrict msgvec" "size_t vlen" "int flags" "const struct timespec * restrict timeout"
+.Sh DESCRIPTION
+The
+.Fn recvfrom ,
+.Fn recvmsg ,
+and
+.Fn recvmmsg
+system calls
+are used to receive messages from a socket,
+and may be used to receive data on a socket whether or not
+it is connection-oriented.
+.Pp
+If
+.Fa from
+is not a null pointer
+and the socket is not connection-oriented,
+the source address of the message is filled in.
+The
+.Fa fromlen
+argument
+is a value-result argument, initialized to the size of
+the buffer associated with
+.Fa from ,
+and modified on return to indicate the actual size of the
+address stored there.
+.Pp
+The
+.Fn recv
+function is normally used only on a
+.Em connected
+socket (see
+.Xr connect 2 )
+and is identical to
+.Fn recvfrom
+with a
+null pointer passed as its
+.Fa from
+argument.
+.Pp
+The
+.Fn recvmmsg
+function is used to receive multiple
+messages at a call.
+Their number is supplied by
+.Fa vlen .
+The messages are placed in the buffers described by
+.Fa msgvec
+vector, after reception.
+The size of each received message is placed in the
+.Fa msg_len
+field of each element of the vector.
+If
+.Fa timeout
+is NULL the call blocks until the data is available for each
+supplied message buffer.
+Otherwise it waits for data for the specified amount of time.
+If the timeout expired and there is no data received,
+a value 0 is returned.
+The
+.Xr ppoll 2
+system call is used to implement the timeout mechanism,
+before first receive is performed.
+.Pp
+The
+.Fn recv ,
+.Fn recvfrom
+and
+.Fn recvmsg
+return the length of the message on successful
+completion, whereas
+.Fn recvmmsg
+returns the number of received messages.
+If a message is too long to fit in the supplied buffer,
+excess bytes may be discarded depending on the type of socket
+the message is received from (see
+.Xr socket 2 ) .
+.Pp
+If no messages are available at the socket, the
+receive call waits for a message to arrive, unless
+the socket is non-blocking (see
+.Xr fcntl 2 )
+in which case the value
+\-1 is returned and the global variable
+.Va errno
+is set to
+.Er EAGAIN .
+The receive calls except
+.Fn recvmmsg
+normally return any data available,
+up to the requested amount,
+rather than waiting for receipt of the full amount requested;
+this behavior is affected by the socket-level options
+.Dv SO_RCVLOWAT
+and
+.Dv SO_RCVTIMEO
+described in
+.Xr getsockopt 2 .
+The
+.Fn recvmmsg
+function implements this behaviour for each message in the vector.
+.Pp
+The
+.Xr select 2
+system call may be used to determine when more data arrives.
+.Pp
+The
+.Fa flags
+argument to a
+.Fn recv
+function is formed by
+.Em or Ap ing
+one or more of the values:
+.Bl -column ".Dv MSG_CMSG_CLOEXEC" -offset indent
+.It Dv MSG_OOB Ta process out-of-band data
+.It Dv MSG_PEEK Ta peek at incoming message
+.It Dv MSG_WAITALL Ta wait for full request or error
+.It Dv MSG_DONTWAIT Ta do not block
+.It Dv MSG_CMSG_CLOEXEC Ta set received fds close-on-exec
+.It Dv MSG_WAITFORONE Ta do not block after receiving the first message
+(only for
+.Fn recvmmsg
+)
+.El
+.Pp
+The
+.Dv MSG_OOB
+flag requests receipt of out-of-band data
+that would not be received in the normal data stream.
+Some protocols place expedited data at the head of the normal
+data queue, and thus this flag cannot be used with such protocols.
+The
+.Dv MSG_PEEK
+flag causes the receive operation to return data
+from the beginning of the receive queue without removing that
+data from the queue.
+Thus, a subsequent receive call will return the same data.
+The
+.Dv MSG_WAITALL
+flag requests that the operation block until
+the full request is satisfied.
+However, the call may still return less data than requested
+if a signal is caught, an error or disconnect occurs,
+or the next data to be received is of a different type than that returned.
+The
+.Dv MSG_DONTWAIT
+flag requests the call to return when it would block otherwise.
+If no data is available,
+.Va errno
+is set to
+.Er EAGAIN .
+This flag is not available in strict
+.Tn ANSI
+or C99 compilation mode.
+The
+.Dv MSG_WAITFORONE
+flag sets MSG_DONTWAIT after the first message has been received.
+This flag is only relevant for
+.Fn recvmmsg .
+.Pp
+The
+.Fn recvmsg
+system call uses a
+.Fa msghdr
+structure to minimize the number of directly supplied arguments.
+This structure has the following form, as defined in
+.In sys/socket.h :
+.Bd -literal
+struct msghdr {
+ void *msg_name; /* optional address */
+ socklen_t msg_namelen; /* size of address */
+ struct iovec *msg_iov; /* scatter/gather array */
+ int msg_iovlen; /* # elements in msg_iov */
+ void *msg_control; /* ancillary data, see below */
+ socklen_t msg_controllen;/* ancillary data buffer len */
+ int msg_flags; /* flags on received message */
+};
+.Ed
+.Pp
+Here
+.Fa msg_name
+and
+.Fa msg_namelen
+specify the destination address if the socket is unconnected;
+.Fa msg_name
+may be given as a null pointer if no names are desired or required.
+The
+.Fa msg_iov
+and
+.Fa msg_iovlen
+arguments
+describe scatter gather locations, as discussed in
+.Xr read 2 .
+The
+.Fa msg_control
+argument,
+which has length
+.Fa msg_controllen ,
+points to a buffer for other protocol control related messages
+or other miscellaneous ancillary data.
+The messages are of the form:
+.Bd -literal
+struct cmsghdr {
+ socklen_t cmsg_len; /* data byte count, including hdr */
+ int cmsg_level; /* originating protocol */
+ int cmsg_type; /* protocol-specific type */
+/* followed by
+ u_char cmsg_data[]; */
+};
+.Ed
+.Pp
+As an example, one could use this to learn of changes in the data-stream
+in XNS/SPP, or in ISO, to obtain user-connection-request data by requesting
+a
+.Fn recvmsg
+with no data buffer provided immediately after an
+.Fn accept
+system call.
+.Pp
+Open file descriptors are now passed as ancillary data for
+.Dv AF_UNIX
+domain sockets, with
+.Fa cmsg_level
+set to
+.Dv SOL_SOCKET
+and
+.Fa cmsg_type
+set to
+.Dv SCM_RIGHTS .
+The close-on-exec flag on received descriptors is set according to the
+.Dv MSG_CMSG_CLOEXEC
+flag passed to
+.Fn recvmsg .
+.Pp
+Process credentials can also be passed as ancillary data for
+.Dv AF_UNIX
+domain sockets using a
+.Fa cmsg_type
+of
+.Dv SCM_CREDS .
+In this case,
+.Fa cmsg_data
+should be a structure of type
+.Fa cmsgcred ,
+which is defined in
+.In sys/socket.h
+as follows:
+.Bd -literal
+struct cmsgcred {
+ pid_t cmcred_pid; /* PID of sending process */
+ uid_t cmcred_uid; /* real UID of sending process */
+ uid_t cmcred_euid; /* effective UID of sending process */
+ gid_t cmcred_gid; /* real GID of sending process */
+ short cmcred_ngroups; /* number or groups */
+ gid_t cmcred_groups[CMGROUP_MAX]; /* groups */
+};
+.Ed
+.Pp
+If a sender supplies ancillary data with enough space for the above struct
+tagged as
+.Dv SCM_CREDS
+control message type to the
+.Fn sendmsg
+system call, then kernel will fill in the credential information of the
+sending process and deliver it to the receiver.
+Since receiver usually has no control over a sender, this method of retrieving
+credential information isn't reliable.
+For reliable retrieval of remote side credentials it is advised to use the
+.Dv LOCAL_CREDS
+socket option on the receiving socket.
+See
+.Xr unix 4
+for details.
+.Pp
+The
+.Fa msg_flags
+field is set on return according to the message received.
+.Dv MSG_EOR
+indicates end-of-record;
+the data returned completed a record (generally used with sockets of type
+.Dv SOCK_SEQPACKET ) .
+.Dv MSG_TRUNC
+indicates that
+the trailing portion of a datagram was discarded because the datagram
+was larger than the buffer supplied.
+.Dv MSG_CTRUNC
+indicates that some
+control data were discarded due to lack of space in the buffer
+for ancillary data.
+.Dv MSG_OOB
+is returned to indicate that expedited or out-of-band data were received.
+.Pp
+The
+.Fn recvmmsg
+system call uses the
+.Fa mmsghdr
+structure, defined as follows in the
+.In sys/socket.h
+header :
+.Bd -literal
+struct mmsghdr {
+ struct msghdr msg_hdr; /* message header */
+ ssize_t msg_len; /* message length */
+};
+.Ed
+.Pp
+On data reception the
+.Fa msg_len
+field is updated to the length of the received message.
+.Sh RETURN VALUES
+These calls except
+.Fn recvmmsg
+return the number of bytes received.
+.Fn recvmmsg
+returns the number of messages received.
+A value of -1 is returned if an error occurred.
+.Sh ERRORS
+The calls fail if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The argument
+.Fa s
+is an invalid descriptor.
+.It Bq Er ECONNRESET
+The remote socket end is forcibly closed.
+.It Bq Er ENOTCONN
+The socket is associated with a connection-oriented protocol
+and has not been connected (see
+.Xr connect 2
+and
+.Xr accept 2 ) .
+.It Bq Er ENOTSOCK
+The argument
+.Fa s
+does not refer to a socket.
+.It Bq Er EMSGSIZE
+The
+.Fn recvmsg
+system call
+was used to receive rights (file descriptors) that were in flight on the
+connection.
+However, the receiving program did not have enough free file
+descriptor slots to accept them.
+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
+would block, or
+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
+any data were available.
+.It Bq Er EFAULT
+The receive buffer pointer(s) point outside the process's
+address space.
+.El
+.Sh SEE ALSO
+.Xr fcntl 2 ,
+.Xr getsockopt 2 ,
+.Xr read 2 ,
+.Xr select 2 ,
+.Xr socket 2 ,
+.Xr unix 4
+.Sh HISTORY
+The
+.Fn recv
+function appeared in
+.Bx 4.2 .
+The
+.Fn recvmmsg
+function appeared in
+.Fx 11.0 .
diff --git a/lib/libc/sys/recvfrom.c b/lib/libc/sys/recvfrom.c
new file mode 100644
index 000000000000..aa6ef3fb7be2
--- /dev/null
+++ b/lib/libc/sys/recvfrom.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2014 The FreeBSD Foundation.
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Konstantin Belousov
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice(s), this list of conditions and the following disclaimer as
+ * the first lines of this file unmodified other than the possible
+ * addition of one or more copyright notices.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice(s), this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/syscall.h>
+#include <sys/socket.h>
+#include "libc_private.h"
+
+__weak_reference(__sys_recvfrom, __recvfrom);
+
+#pragma weak recvfrom
+ssize_t
+recvfrom(int s, void *buf, size_t len, int flags,
+ struct sockaddr * __restrict from, socklen_t * __restrict fromlen)
+{
+
+ return (((ssize_t (*)(int, void *, size_t, int,
+ struct sockaddr *, socklen_t *))
+ __libc_interposing[INTERPOS_recvfrom])(s, buf, len, flags,
+ from, fromlen));
+}
diff --git a/lib/libc/sys/recvmsg.c b/lib/libc/sys/recvmsg.c
new file mode 100644
index 000000000000..282ede9995ff
--- /dev/null
+++ b/lib/libc/sys/recvmsg.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2014 The FreeBSD Foundation.
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Konstantin Belousov
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice(s), this list of conditions and the following disclaimer as
+ * the first lines of this file unmodified other than the possible
+ * addition of one or more copyright notices.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice(s), this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/syscall.h>
+#include <sys/socket.h>
+#include "libc_private.h"
+
+__weak_reference(__sys_recvmsg, __recvmsg);
+
+#pragma weak recvmsg
+ssize_t
+recvmsg(int s, struct msghdr *msg, int flags)
+{
+
+ return (((int (*)(int, struct msghdr *, int))
+ __libc_interposing[INTERPOS_recvmsg])(s, msg, flags));
+}
diff --git a/lib/libc/sys/rename.2 b/lib/libc/sys/rename.2
new file mode 100644
index 000000000000..b98edd5e23cb
--- /dev/null
+++ b/lib/libc/sys/rename.2
@@ -0,0 +1,308 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)rename.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd April 10, 2008
+.Dt RENAME 2
+.Os
+.Sh NAME
+.Nm rename
+.Nd change the name of a file
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdio.h
+.Ft int
+.Fn rename "const char *from" "const char *to"
+.Ft int
+.Fn renameat "int fromfd" "const char *from" "int tofd" "const char *to"
+.Sh DESCRIPTION
+The
+.Fn rename
+system call
+causes the link named
+.Fa from
+to be renamed as
+.Fa to .
+If
+.Fa to
+exists, it is first removed.
+Both
+.Fa from
+and
+.Fa to
+must be of the same type (that is, both directories or both
+non-directories), and must reside on the same file system.
+.Pp
+The
+.Fn rename
+system call
+guarantees that if
+.Fa to
+already exists, an instance of
+.Fa to
+will always exist, even if the system should crash in
+the middle of the operation.
+.Pp
+If the final component of
+.Fa from
+is a symbolic link,
+the symbolic link is renamed,
+not the file or directory to which it points.
+.Pp
+The
+.Fn renameat
+system call is equivalent to
+.Fn rename
+except in the case where either
+.Fa from
+or
+.Fa to
+specifies a relative path.
+If
+.Fa from
+is a relative path, the file to be renamed is located
+relative to the directory associated with the file descriptor
+.Fa fromfd
+instead of the current working directory.
+If the
+.Fa to
+is a relative path, the same happens only relative to the directory associated
+with
+.Fa tofd .
+If the
+.Fn renameat
+is passed the special value
+.Dv AT_FDCWD
+in the
+.Fa fromfd
+or
+.Fa tofd
+parameter, the current working directory is used in the determination
+of the file for the respective path parameter.
+.\".Sh CAVEAT
+.\"The system can deadlock if a loop in the file system graph is present.
+.\"This loop takes the form of an entry in directory
+.\".Pa a ,
+.\"say
+.\".Pa a/foo ,
+.\"being a hard link to directory
+.\".Pa b ,
+.\"and an entry in
+.\"directory
+.\".Pa b ,
+.\"say
+.\".Pa b/bar ,
+.\"being a hard link
+.\"to directory
+.\".Pa a .
+.\"When such a loop exists and two separate processes attempt to
+.\"perform
+.\".Ql rename a/foo b/bar
+.\"and
+.\".Ql rename b/bar a/foo ,
+.\"respectively,
+.\"the system may deadlock attempting to lock
+.\"both directories for modification.
+.\"Hard links to directories should be
+.\"replaced by symbolic links by the system administrator.
+.Sh RETURN VALUES
+.Rv -std rename
+.Sh ERRORS
+The
+.Fn rename
+system call
+will fail and neither of the argument files will be
+affected if:
+.Bl -tag -width Er
+.It Bq Er ENAMETOOLONG
+A component of either pathname exceeded 255 characters,
+or the entire length of either path name exceeded 1023 characters.
+.It Bq Er ENOENT
+A component of the
+.Fa from
+path does not exist,
+or a path prefix of
+.Fa to
+does not exist.
+.It Bq Er EACCES
+A component of either path prefix denies search permission.
+.It Bq Er EACCES
+The requested link requires writing in a directory with a mode
+that denies write permission.
+.It Bq Er EACCES
+The directory pointed at by the
+.Fa from
+argument denies write permission, and the operation would move
+it to another parent directory.
+.It Bq Er EPERM
+The file pointed at by the
+.Fa from
+argument has its immutable, undeletable or append-only flag set, see the
+.Xr chflags 2
+manual page for more information.
+.It Bq Er EPERM
+The parent directory of the file pointed at by the
+.Fa from
+argument has its immutable or append-only flag set.
+.It Bq Er EPERM
+The parent directory of the file pointed at by the
+.Fa to
+argument has its immutable flag set.
+.It Bq Er EPERM
+The directory containing
+.Fa from
+is marked sticky,
+and neither the containing directory nor
+.Fa from
+are owned by the effective user ID.
+.It Bq Er EPERM
+The file pointed at by the
+.Fa to
+argument
+exists,
+the directory containing
+.Fa to
+is marked sticky,
+and neither the containing directory nor
+.Fa to
+are owned by the effective user ID.
+.It Bq Er ELOOP
+Too many symbolic links were encountered in translating either pathname.
+.It Bq Er ENOTDIR
+A component of either path prefix is not a directory.
+.It Bq Er ENOTDIR
+The
+.Fa from
+argument
+is a directory, but
+.Fa to
+is not a directory.
+.It Bq Er EISDIR
+The
+.Fa to
+argument
+is a directory, but
+.Fa from
+is not a directory.
+.It Bq Er EXDEV
+The link named by
+.Fa to
+and the file named by
+.Fa from
+are on different logical devices (file systems).
+Note that this error
+code will not be returned if the implementation permits cross-device
+links.
+.It Bq Er ENOSPC
+The directory in which the entry for the new name is being placed
+cannot be extended because there is no space left on the file
+system containing the directory.
+.It Bq Er EDQUOT
+The directory in which the entry for the new name
+is being placed cannot be extended because the
+user's quota of disk blocks on the file system
+containing the directory has been exhausted.
+.It Bq Er EIO
+An I/O error occurred while making or updating a directory entry.
+.It Bq Er EROFS
+The requested link requires writing in a directory on a read-only file
+system.
+.It Bq Er EFAULT
+Path
+points outside the process's allocated address space.
+.It Bq Er EINVAL
+The
+.Fa from
+argument
+is a parent directory of
+.Fa to ,
+or an attempt is made to rename
+.Ql .\&
+or
+.Ql \&.. .
+.It Bq Er ENOTEMPTY
+The
+.Fa to
+argument
+is a directory and is not empty.
+.El
+.Pp
+In addition to the errors returned by the
+.Fn rename ,
+the
+.Fn renameat
+may fail if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa from
+argument does not specify an absolute path and the
+.Fa fromfd
+argument is neither
+.Dv AT_FDCWD
+nor a valid file descriptor open for searching, or the
+.Fa to
+argument does not specify an absolute path and the
+.Fa tofd
+argument is neither
+.Dv AT_FDCWD
+nor a valid file descriptor open for searching.
+.It Bq Er ENOTDIR
+The
+.Fa from
+argument is not an absolute path and
+.Fa fromfd
+is neither
+.Dv AT_FDCWD
+nor a file descriptor associated with a directory, or the
+.Fa to
+argument is not an absolute path and
+.Fa tofd
+is neither
+.Dv AT_FDCWD
+nor a file descriptor associated with a directory.
+.El
+.Sh SEE ALSO
+.Xr chflags 2 ,
+.Xr open 2 ,
+.Xr symlink 7
+.Sh STANDARDS
+The
+.Fn rename
+system call is expected to conform to
+.St -p1003.1-96 .
+The
+.Fn renameat
+system call follows The Open Group Extended API Set 2 specification.
+.Sh HISTORY
+The
+.Fn renameat
+system call appeared in
+.Fx 8.0 .
diff --git a/lib/libc/sys/revoke.2 b/lib/libc/sys/revoke.2
new file mode 100644
index 000000000000..3d7ad00bfe34
--- /dev/null
+++ b/lib/libc/sys/revoke.2
@@ -0,0 +1,110 @@
+.\" Copyright (c) 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Berkeley Software Design, Inc.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)revoke.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd Jan 25, 2016
+.Dt REVOKE 2
+.Os
+.Sh NAME
+.Nm revoke
+.Nd revoke file access
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft int
+.Fn revoke "const char *path"
+.Sh DESCRIPTION
+The
+.Fn revoke
+system call invalidates all current open file descriptors in the system
+for the file named by
+.Fa path .
+Subsequent operations on any such descriptors
+fail, with the exceptions that a
+.Fn read
+from a character device file which has been revoked
+returns a count of zero (end of file),
+and a
+.Fn close
+system call will succeed.
+If the file is a special file for a device which is open,
+the device close function
+is called as if all open references to the file had been closed
+using a special close method which does not block.
+.Pp
+Access to a file may be revoked only by its owner or the super user.
+The
+.Fn revoke
+system call is currently supported only for block and character special
+device files.
+It is normally used to prepare a terminal device for a new login session,
+preventing any access by a previous user of the terminal.
+.Sh RETURN VALUES
+.Rv -std revoke
+.Sh ERRORS
+Access to the named file is revoked unless one of the following:
+.Bl -tag -width Er
+.It Bq Er ENOTDIR
+A component of the path prefix is not a directory.
+.It Bq Er ENAMETOOLONG
+A component of a pathname exceeded 255 characters,
+or an entire path name exceeded 1024 characters.
+.It Bq Er ENOENT
+The named file or a component of the path name does not exist.
+.It Bq Er EACCES
+Search permission is denied for a component of the path prefix.
+.It Bq Er ELOOP
+Too many symbolic links were encountered in translating the pathname.
+.It Bq Er EFAULT
+The
+.Fa path
+argument
+points outside the process's allocated address space.
+.It Bq Er EINVAL
+The implementation does not support the
+.Fn revoke
+operation on the named file.
+.It Bq Er EPERM
+The caller is neither the owner of the file nor the super user.
+.El
+.Sh SEE ALSO
+.Xr revoke 1 ,
+.Xr close 2
+.Sh HISTORY
+The
+.Fn revoke
+system call first appeared in
+.Bx 4.3 Reno .
+.Sh BUGS
+The non-blocking close method is only correctly implemented for
+terminal devices.
diff --git a/lib/libc/sys/rfork.2 b/lib/libc/sys/rfork.2
new file mode 100644
index 000000000000..222bac425496
--- /dev/null
+++ b/lib/libc/sys/rfork.2
@@ -0,0 +1,192 @@
+.\"
+.\" This manual page is taken directly from Plan9, and modified to
+.\" describe the actual BSD implementation. Permission for
+.\" use of this page comes from Rob Pike <rob@plan9.att.com>.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd July 12, 2011
+.Dt RFORK 2
+.Os
+.Sh NAME
+.Nm rfork
+.Nd manipulate process resources
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft pid_t
+.Fn rfork "int flags"
+.Sh DESCRIPTION
+Forking, vforking or rforking are the only ways new processes are created.
+The
+.Fa flags
+argument to
+.Fn rfork
+selects which resources of the
+invoking process (parent) are shared
+by the new process (child) or initialized to
+their default values.
+The resources include
+the open file descriptor table (which, when shared, permits processes
+to open and close files for other processes),
+and open files.
+The
+.Fa flags
+argument
+is the logical OR of some subset of:
+.Bl -tag -width ".Dv RFLINUXTHPN"
+.It Dv RFPROC
+If set a new process is created; otherwise changes affect the
+current process.
+.It Dv RFNOWAIT
+If set, the child process will be dissociated from the parent.
+Upon
+exit the child will not leave a status for the parent to collect.
+See
+.Xr wait 2 .
+.It Dv RFFDG
+If set, the invoker's file descriptor table (see
+.Xr intro 2 )
+is copied; otherwise the two processes share a
+single table.
+.It Dv RFCFDG
+If set, the new process starts with a clean file descriptor table.
+Is mutually exclusive with
+.Dv RFFDG .
+.It Dv RFTHREAD
+If set, the new process shares file descriptor to process leaders table
+with its parent.
+Only applies when neither
+.Dv RFFDG
+nor
+.Dv RFCFDG
+are set.
+.It Dv RFMEM
+If set, the kernel will force sharing of the entire address space,
+typically by sharing the hardware page table directly.
+The child
+will thus inherit and share all the segments the parent process owns,
+whether they are normally shareable or not.
+The stack segment is
+not split (both the parent and child return on the same stack) and thus
+.Fn rfork
+with the RFMEM flag may not generally be called directly from high level
+languages including C.
+May be set only with
+.Dv RFPROC .
+A helper function is provided to assist with this problem and will cause
+the new process to run on the provided stack.
+See
+.Xr rfork_thread 3
+for information.
+Note that a lot of code will not run correctly in such an environment.
+.It Dv RFSIGSHARE
+If set, the kernel will force sharing the sigacts structure between the
+child and the parent.
+.It Dv RFTSIGZMB
+If set, the kernel will deliver a specified signal to the parent
+upon the child exit, instead of default SIGCHLD.
+The signal number
+.Dv signum
+is specified by oring the
+.Dv RFTSIGFLAGS(signum)
+expression into
+.Fa flags .
+Specifying signal number 0 disables signal delivery upon the child exit.
+.It Dv RFLINUXTHPN
+If set, the kernel will deliver SIGUSR1 instead of SIGCHLD upon thread
+exit for the child.
+This is intended to mimic certain Linux clone behaviour.
+.El
+.Pp
+File descriptors in a shared file descriptor table are kept
+open until either they are explicitly closed
+or all processes sharing the table exit.
+.Pp
+If
+.Dv RFPROC
+is set, the
+value returned in the parent process
+is the process id
+of the child process; the value returned in the child is zero.
+Without
+.Dv RFPROC ,
+the return value is zero.
+Process id's range from 1 to the maximum integer
+.Ft ( int )
+value.
+The
+.Fn rfork
+system call
+will sleep, if necessary, until required process resources are available.
+.Pp
+The
+.Fn fork
+system call
+can be implemented as a call to
+.Fn rfork "RFFDG | RFPROC"
+but is not for backwards compatibility.
+.Sh RETURN VALUES
+Upon successful completion,
+.Fn rfork
+returns a value
+of 0 to the child process and returns the process ID of the child
+process to the parent process.
+Otherwise, a value of -1 is returned
+to the parent process, no child process is created, and the global
+variable
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+The
+.Fn rfork
+system call
+will fail and no child process will be created if:
+.Bl -tag -width Er
+.It Bq Er EAGAIN
+The system-imposed limit on the total
+number of processes under execution would be exceeded.
+The limit is given by the
+.Xr sysctl 3
+MIB variable
+.Dv KERN_MAXPROC .
+(The limit is actually ten less than this
+except for the super user).
+.It Bq Er EAGAIN
+The user is not the super user, and
+the system-imposed limit
+on the total number of
+processes under execution by a single user would be exceeded.
+The limit is given by the
+.Xr sysctl 3
+MIB variable
+.Dv KERN_MAXPROCPERUID .
+.It Bq Er EAGAIN
+The user is not the super user, and
+the soft resource limit corresponding to the
+.Fa resource
+argument
+.Dv RLIMIT_NOFILE
+would be exceeded (see
+.Xr getrlimit 2 ) .
+.It Bq Er EINVAL
+Both the RFFDG and the RFCFDG flags were specified.
+.It Bq Er EINVAL
+Any flags not listed above were specified.
+.It Bq Er EINVAL
+An invalid signal number was specified.
+.It Bq Er ENOMEM
+There is insufficient swap space for the new process.
+.El
+.Sh SEE ALSO
+.Xr fork 2 ,
+.Xr intro 2 ,
+.Xr minherit 2 ,
+.Xr vfork 2 ,
+.Xr pthread_create 3 ,
+.Xr rfork_thread 3
+.Sh HISTORY
+The
+.Fn rfork
+function first appeared in Plan9.
diff --git a/lib/libc/sys/rmdir.2 b/lib/libc/sys/rmdir.2
new file mode 100644
index 000000000000..597c94647fae
--- /dev/null
+++ b/lib/libc/sys/rmdir.2
@@ -0,0 +1,118 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)rmdir.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd December 9, 2006
+.Dt RMDIR 2
+.Os
+.Sh NAME
+.Nm rmdir
+.Nd remove a directory file
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft int
+.Fn rmdir "const char *path"
+.Sh DESCRIPTION
+The
+.Fn rmdir
+system call
+removes a directory file
+whose name is given by
+.Fa path .
+The directory must not have any entries other
+than
+.Ql .\&
+and
+.Ql \&.. .
+.Sh RETURN VALUES
+.Rv -std rmdir
+.Sh ERRORS
+The named file is removed unless:
+.Bl -tag -width Er
+.It Bq Er ENOTDIR
+A component of the path is not a directory.
+.It Bq Er ENAMETOOLONG
+A component of a pathname exceeded 255 characters,
+or an entire path name exceeded 1023 characters.
+.It Bq Er ENOENT
+The named directory does not exist.
+.It Bq Er ELOOP
+Too many symbolic links were encountered in translating the pathname.
+.It Bq Er ENOTEMPTY
+The named directory contains files other than
+.Ql .\&
+and
+.Ql ..\&
+in it.
+.It Bq Er EACCES
+Search permission is denied for a component of the path prefix.
+.It Bq Er EACCES
+Write permission is denied on the directory containing the link
+to be removed.
+.It Bq Er EPERM
+The directory to be removed has its immutable, undeletable or append-only flag
+set, see the
+.Xr chflags 2
+manual page for more information.
+.It Bq Er EPERM
+The parent directory of the directory to be removed has its immutable or
+append-only flag set.
+.It Bq Er EPERM
+The directory containing the directory to be removed is marked sticky,
+and neither the containing directory nor the directory to be removed
+are owned by the effective user ID.
+.It Bq Er EINVAL
+The last component of the path is
+.Ql .\&
+or
+.Ql .. .
+.It Bq Er EBUSY
+The directory to be removed is the mount point
+for a mounted file system.
+.It Bq Er EIO
+An I/O error occurred while deleting the directory entry
+or deallocating the inode.
+.It Bq Er EROFS
+The directory entry to be removed resides on a read-only file system.
+.It Bq Er EFAULT
+The
+.Fa path
+argument
+points outside the process's allocated address space.
+.El
+.Sh SEE ALSO
+.Xr mkdir 2 ,
+.Xr unlink 2
+.Sh HISTORY
+The
+.Fn rmdir
+system call appeared in
+.Bx 4.2 .
diff --git a/lib/libc/sys/rtprio.2 b/lib/libc/sys/rtprio.2
new file mode 100644
index 000000000000..23088a705967
--- /dev/null
+++ b/lib/libc/sys/rtprio.2
@@ -0,0 +1,199 @@
+.\"-
+.\" Copyright (c) 1994, Henrik Vestergaard Draboel
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by Henrik Vestergaard Draboel.
+.\" 4. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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) 2011 Xin LI <delphij@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 December 27, 2011
+.Dt RTPRIO 2
+.Os
+.Sh NAME
+.Nm rtprio ,
+.Nm rtprio_thread
+.Nd examine or modify realtime or idle priority
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/rtprio.h
+.Ft int
+.Fn rtprio "int function" "pid_t pid" "struct rtprio *rtp"
+.Ft int
+.Fn rtprio_thread "int function" "lwpid_t lwpid" "struct rtprio *rtp"
+.Sh DESCRIPTION
+The
+.Fn rtprio
+system call
+is used to lookup or change the realtime or idle priority of a process,
+or the calling thread.
+The
+.Fn rtprio_thread
+system call
+is used to lookup or change the realtime or idle priority of a thread.
+.Pp
+The
+.Fa function
+argument
+specifies the operation to be performed.
+RTP_LOOKUP to lookup the current priority,
+and RTP_SET to set the priority.
+.Pp
+For the
+.Fn rtprio
+system call,
+the
+.Fa pid
+argument
+specifies the process to operate on,
+0 for the calling thread.
+When
+.Fa pid
+is non-zero,
+the system call reports the highest priority in the process,
+or sets all threads' priority in the process,
+depending on value of the
+.Fa function
+argument.
+.Pp
+For the
+.Fn rtprio_thread
+system call,
+the
+.Fa lwpid
+specifies the thread to operate on,
+0 for the calling thread.
+.Pp
+The
+.Fa *rtp
+argument
+is a pointer to a struct rtprio which is used to specify the priority and priority type.
+This structure has the following form:
+.Bd -literal
+struct rtprio {
+ u_short type;
+ u_short prio;
+};
+.Ed
+.Pp
+The value of the
+.Va type
+field may be RTP_PRIO_REALTIME for realtime priorities,
+RTP_PRIO_NORMAL for normal priorities, and RTP_PRIO_IDLE for idle priorities.
+The priority specified by the
+.Va prio
+field ranges between 0 and
+.Dv RTP_PRIO_MAX
+.Pq usually 31 .
+0 is the highest possible priority.
+.Pp
+Realtime and idle priority is inherited through fork() and exec().
+.Pp
+A realtime thread can only be preempted by a thread of equal or
+higher priority, or by an interrupt; idle priority threads will run only
+when no other real/normal priority thread is runnable.
+Higher real/idle priority threads
+preempt lower real/idle priority threads.
+Threads of equal real/idle priority are run round-robin.
+.Sh RETURN VALUES
+.Rv -std rtprio rtprio_thread
+.Sh ERRORS
+The
+.Fn rtprio
+and
+.Fn rtprio_thread
+system calls
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EFAULT
+The rtp pointer passed to
+.Fn rtprio
+or
+.Fn rtprio_thread
+was invalid.
+.It Bq Er EINVAL
+The specified
+.Fa prio
+was out of range.
+.It Bq Er EPERM
+The calling thread is not allowed to set the realtime priority.
+Only
+root is allowed to change the realtime priority of any thread, and non-root
+may only change the idle priority of threads the user owns,
+when the
+.Xr sysctl 8
+variable
+.Va security.bsd.unprivileged_idprio
+is set to non-zero.
+.It Bq Er ESRCH
+The specified process or thread was not found or visible.
+.El
+.Sh SEE ALSO
+.Xr nice 1 ,
+.Xr ps 1 ,
+.Xr rtprio 1 ,
+.Xr setpriority 2 ,
+.Xr nice 3 ,
+.Xr renice 8 ,
+.Xr p_cansee 9
+.Sh AUTHORS
+.An -nosplit
+The original author was
+.An Henrik Vestergaard Draboel Aq Mt hvd@terry.ping.dk .
+This implementation in
+.Fx
+was substantially rewritten by
+.An David Greenman .
+The
+.Fn rtprio_thread
+system call was implemented by
+.An David Xu .
diff --git a/lib/libc/sys/sched_get_priority_max.2 b/lib/libc/sys/sched_get_priority_max.2
new file mode 100644
index 000000000000..88d1d6d1460d
--- /dev/null
+++ b/lib/libc/sys/sched_get_priority_max.2
@@ -0,0 +1,123 @@
+.\" Copyright (c) 1998 HD Associates, 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd March 12, 1998
+.Dt SCHED_GET_PRIORITY_MAX 2
+.Os
+.Sh NAME
+.Nm sched_get_priority_max ,
+.Nm sched_get_priority_min ,
+.Nm sched_rr_get_interval
+.Nd get scheduling parameter limits
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sched.h
+.Ft int
+.Fn sched_get_priority_max "int policy"
+.Ft int
+.Fn sched_get_priority_min "int policy"
+.Ft int
+.Fn sched_rr_get_interval "pid_t pid" "struct timespec *interval"
+.Sh DESCRIPTION
+The
+.Fn sched_get_priority_max
+and
+.Fn sched_get_priority_min
+system calls return the appropriate maximum or minimum, respectively,
+for the scheduling policy specified by
+.Fa policy .
+The
+.Fn sched_rr_get_interval
+system call updates the
+.Fa timespec
+structure referenced by the
+.Fa interval
+argument to contain the current execution time limit (i.e., time
+quantum) for the process specified by
+.Fa pid .
+If
+.Fa pid
+is zero, the current execution time limit for the calling process is
+returned.
+.Pp
+The value of
+.Fa policy
+should be one of the scheduling policy values defined in
+.Fa <sched.h> :
+.Bl -tag -width [SCHED_OTHER]
+.It Bq Er SCHED_FIFO
+First-in-first-out fixed priority scheduling with no round robin scheduling;
+.It Bq Er SCHED_OTHER
+The standard time sharing scheduler;
+.It Bq Er SCHED_RR
+Round-robin scheduling across same priority processes.
+.El
+.Sh RETURN VALUES
+If successful, the
+.Fn sched_get_priority_max
+and
+.Fn sched_get_priority_min
+system calls shall return the appropriate maximum or minimum values,
+respectively.
+If unsuccessful, they shall return a value of -1 and set
+.Fa errno
+to indicate the error.
+.Pp
+.Rv -std sched_rr_get_interval
+.Sh ERRORS
+On failure
+.Va errno
+will be set to the corresponding value:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The value of the
+.Fa policy
+argument does not represent a defined scheduling policy.
+.It Bq Er ENOSYS
+The
+.Fn sched_get_priority_max ,
+.Fn sched_get_priority_min ,
+and
+.Fn sched_rr_get_interval
+system calls are not supported by the implementation.
+.It Bq Er ESRCH
+No process can be found corresponding to that specified by
+.Fa pid .
+.El
+.Sh SEE ALSO
+.Xr sched_getparam 2 ,
+.Xr sched_getscheduler 2 ,
+.Xr sched_setparam 2 ,
+.Xr sched_setscheduler 2
+.Sh STANDARDS
+The
+.Fn sched_get_priority_max ,
+.Fn sched_get_priority_min ,
+and
+.Fn sched_rr_get_interval
+system calls conform to
+.St -p1003.1b-93 .
diff --git a/lib/libc/sys/sched_setparam.2 b/lib/libc/sys/sched_setparam.2
new file mode 100644
index 000000000000..315fd826cc7d
--- /dev/null
+++ b/lib/libc/sys/sched_setparam.2
@@ -0,0 +1,174 @@
+.\" $FreeBSD$
+.\" Copyright (c) 1998 HD Associates, 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.
+.\"
+.Dd March 12, 1998
+.Dt SCHED_SETPARAM 2
+.Os
+.Sh NAME
+.Nm sched_setparam ,
+.Nm sched_getparam
+.Nd set/get scheduling parameters
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sched.h
+.Ft int
+.Fn sched_setparam "pid_t pid" "const struct sched_param *param"
+.Ft int
+.Fn sched_getparam "pid_t pid" "struct sched_param *param"
+.Sh DESCRIPTION
+The
+.Fn sched_setparam
+system call sets the scheduling parameters of the process specified by
+.Fa pid
+to the values specified by the
+.Fa sched_param
+structure pointed to by
+.Fa param .
+The value of the
+.Fa sched_priority
+member in the
+.Fa param
+structure must be any integer within the inclusive priority range for
+the current scheduling policy of the process specified by
+.Fa pid .
+Higher numerical values for the priority represent higher priorities.
+.Pp
+In this implementation, if the value of
+.Fa pid
+is negative the system call will fail.
+.Pp
+If a process specified by
+.Fa pid
+exists and if the calling process has permission, the scheduling
+parameters are set for the process whose process ID is equal to
+.Fa pid .
+.Pp
+If
+.Fa pid
+is zero, the scheduling parameters are set for the calling process.
+.Pp
+In this implementation, the policy of when a process can affect
+the scheduling parameters of another process is specified in
+.St -p1003.1b-93
+as a write-style operation.
+.Pp
+The target process, whether it is running or not running, will resume
+execution after all other runnable processes of equal or greater
+priority have been scheduled to run.
+.Pp
+If the priority of the process specified by the
+.Fa pid
+argument is set higher than that of the lowest priority running process
+and if the specified process is ready to run, the process specified by
+the
+.Fa pid
+argument will preempt a lowest priority running process.
+Similarly, if
+the process calling
+.Fn sched_setparam
+sets its own priority lower than that of one or more other nonempty
+process lists, then the process that is the head of the highest priority
+list will also preempt the calling process.
+Thus, in either case, the
+originating process might not receive notification of the completion of
+the requested priority change until the higher priority process has
+executed.
+.Pp
+In this implementation, when the current scheduling policy for the
+process specified by
+.Fa pid
+is normal timesharing (SCHED_OTHER, aka SCHED_NORMAL when not POSIX-source)
+or the idle policy (SCHED_IDLE when not POSIX-source) then the behavior
+is as if the process had been running under SCHED_RR with a priority
+lower than any actual realtime priority.
+.Pp
+The
+.Fn sched_getparam
+system call will return the scheduling parameters of a process specified
+by
+.Fa pid
+in the
+.Fa sched_param
+structure pointed to by
+.Fa param .
+.Pp
+If a process specified by
+.Fa pid
+exists and if the calling process has permission,
+the scheduling parameters for the process whose process ID is equal to
+.Fa pid
+are returned.
+.Pp
+In this implementation, the policy of when a process can obtain the
+scheduling parameters of another process are detailed in
+.St -p1003.1b-93
+as a read-style operation.
+.Pp
+If
+.Fa pid
+is zero, the scheduling parameters for the calling process will be
+returned.
+In this implementation, the
+.Fa sched_getparam
+system call will fail if
+.Fa pid
+is negative.
+.Sh RETURN VALUES
+.Rv -std
+.Sh ERRORS
+On failure
+.Va errno
+will be set to the corresponding value:
+.Bl -tag -width Er
+.It Bq Er ENOSYS
+The system is not configured to support this functionality.
+.It Bq Er EPERM
+The requesting process doesn not have permission as detailed in
+.St -p1003.1b-93 .
+.It Bq Er ESRCH
+No process can be found corresponding to that specified by
+.Fa pid .
+.It Bq Er EINVAL
+For
+.Fn sched_setparam :
+one or more of the requested scheduling parameters
+is outside the range defined for the scheduling policy of the specified
+.Fa pid .
+.El
+.Sh SEE ALSO
+.Xr sched_get_priority_max 2 ,
+.Xr sched_get_priority_min 2 ,
+.Xr sched_getscheduler 2 ,
+.Xr sched_rr_get_interval 2 ,
+.Xr sched_setscheduler 2 ,
+.Xr sched_yield 2
+.Sh STANDARDS
+The
+.Fn sched_setparam
+and
+.Fn sched_getparam
+system calls conform to
+.St -p1003.1b-93 .
diff --git a/lib/libc/sys/sched_setscheduler.2 b/lib/libc/sys/sched_setscheduler.2
new file mode 100644
index 000000000000..b84c1a1c9e35
--- /dev/null
+++ b/lib/libc/sys/sched_setscheduler.2
@@ -0,0 +1,166 @@
+.\" $FreeBSD$
+.\" Copyright (c) 1998 HD Associates, 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.
+.\"
+.Dd March 12, 1998
+.Dt SCHED_SETSCHEDULER 2
+.Os
+.Sh NAME
+.Nm sched_setscheduler ,
+.Nm sched_getscheduler
+.Nd set/get scheduling policy and scheduler parameters
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sched.h
+.Ft int
+.Fn sched_setscheduler "pid_t pid" "int policy" "const struct sched_param *param"
+.Ft int
+.Fn sched_getscheduler "pid_t pid"
+.Sh DESCRIPTION
+The
+.Fn sched_setscheduler
+system call sets the scheduling policy and scheduling parameters
+of the process specified by
+.Fa pid
+to
+.Fa policy
+and the parameters specified in the
+.Vt sched_param
+structure pointed to by
+.Fa param ,
+respectively.
+The value of the
+.Fa sched_priority
+member in the
+.Fa param
+structure must be any integer within the inclusive priority range for
+the scheduling policy specified by
+.Fa policy .
+.Pp
+In this implementation, if the value of
+.Fa pid
+is negative the system call will fail.
+.Pp
+If a process specified by
+.Fa pid
+exists and if the calling process has permission, the scheduling
+policy and scheduling parameters will be set for the process
+whose process ID is equal to
+.Fa pid .
+.Pp
+If
+.Fa pid
+is zero, the scheduling policy and scheduling
+parameters are set for the calling process.
+.Pp
+In this implementation, the policy of when a process can affect
+the scheduling parameters of another process is specified in
+.St -p1003.1b-93
+as a write-style operation.
+.Pp
+The scheduling policies are in
+.Fa <sched.h> :
+.Bl -tag -width [SCHED_OTHER]
+.It Bq Er SCHED_FIFO
+First-in-first-out fixed priority scheduling with no round robin scheduling;
+.It Bq Er SCHED_OTHER
+The standard time sharing scheduler;
+.It Bq Er SCHED_RR
+Round-robin scheduling across same priority processes.
+.El
+.Pp
+The
+.Vt sched_param
+structure is defined in
+.Fa <sched.h> :
+.Bd -literal -offset indent
+struct sched_param {
+ int sched_priority; /* scheduling priority */
+};
+.Ed
+.Pp
+The
+.Fn sched_getscheduler
+system call returns the scheduling policy of the process specified
+by
+.Fa pid .
+.Pp
+If a process specified by
+.Fa pid
+exists and if the calling process has permission,
+the scheduling parameters for the process whose process ID is equal to
+.Fa pid
+are returned.
+.Pp
+In this implementation, the policy of when a process can obtain the
+scheduling parameters of another process are detailed in
+.St -p1003.1b-93
+as a read-style operation.
+.Pp
+If
+.Fa pid
+is zero, the scheduling parameters for the calling process will be
+returned.
+In this implementation, the
+.Fa sched_getscheduler
+system call will fail if
+.Fa pid
+is negative.
+.Sh RETURN VALUES
+.Rv -std
+.Sh ERRORS
+On failure
+.Va errno
+will be set to the corresponding value:
+.Bl -tag -width Er
+.It Bq Er ENOSYS
+The system is not configured to support this functionality.
+.It Bq Er EPERM
+The requesting process doesn not have permission as detailed in
+.St -p1003.1b-93 .
+.It Bq Er ESRCH
+No process can be found corresponding to that specified by
+.Fa pid .
+.It Bq Er EINVAL
+The value of the
+.Fa policy
+argument is invalid, or one or more of the parameters contained in
+.Fa param
+is outside the valid range for the specified scheduling policy.
+.El
+.Sh SEE ALSO
+.Xr sched_get_priority_max 2 ,
+.Xr sched_get_priority_min 2 ,
+.Xr sched_getparam 2 ,
+.Xr sched_rr_get_interval 2 ,
+.Xr sched_setparam 2 ,
+.Xr sched_yield 2
+.Sh STANDARDS
+The
+.Fn sched_setscheduler
+and
+.Fn sched_getscheduler
+system calls conform to
+.St -p1003.1b-93 .
diff --git a/lib/libc/sys/sched_yield.2 b/lib/libc/sys/sched_yield.2
new file mode 100644
index 000000000000..9db8942249e2
--- /dev/null
+++ b/lib/libc/sys/sched_yield.2
@@ -0,0 +1,58 @@
+.\" $FreeBSD$
+.\" Copyright (c) 1998 HD Associates, 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.
+.\"
+.Dd March 12, 1998
+.Dt SCHED_YIELD 2
+.Os
+.Sh NAME
+.Nm sched_yield
+.Nd yield processor
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sched.h
+.Ft int
+.Fn sched_yield void
+.Sh DESCRIPTION
+The
+.Fn sched_yield
+system call forces the running process to relinquish the processor until it
+again becomes the head of its process list.
+It takes no arguments.
+.Sh RETURN VALUES
+.Rv -std sched_yield
+.Sh ERRORS
+On failure
+.Va errno
+will be set to the corresponding value:
+.Bl -tag -width Er
+.It Bq Er ENOSYS
+The system is not configured to support this functionality.
+.El
+.Sh STANDARDS
+The
+.Fn sched_yield
+system call conforms to
+.St -p1003.1b-93 .
diff --git a/lib/libc/sys/sctp_generic_recvmsg.2 b/lib/libc/sys/sctp_generic_recvmsg.2
new file mode 100644
index 000000000000..8ee3d36f90e9
--- /dev/null
+++ b/lib/libc/sys/sctp_generic_recvmsg.2
@@ -0,0 +1,74 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd October 30, 2007
+.Dt SCTP_GENERIC_RECVMSG 2
+.Os
+.Sh NAME
+.Nm sctp_generic_recvmsg
+.Nd receive data from a peer
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/socket.h
+.In netinet/sctp.h
+.Ft int
+.Fn sctp_generic_recvmsg "int s" "struct iovec *iov" "int iovlen" "struct sockaddr *from" "socklen_t *fromlen" "struct sctp_sndrcvinfo *sinfo" "int *msgflags"
+.Sh DESCRIPTION
+.Fn sctp_generic_recvmsg
+is the true system call used by the
+.Xr sctp_recvmsg 3
+function call.
+This call is more efficient since it is a
+true system call but it is specific to
+.Fx
+and can be expected
+.Em not
+to be present on any other operating
+system.
+For detailed usage please see the
+.Xr sctp_recvmsg 3
+function call.
+.Sh RETURN VALUES
+The call returns the number of bytes read on success and -1 upon failure.
+.Sh ERRORS
+.Bl -tag -width Er
+.It Bq Er EBADF
+The argument
+.Fa s
+is not a valid descriptor.
+.It Bq Er ENOTSOCK
+The argument
+.Fa s
+is not a socket.
+.El
+.Sh SEE ALSO
+.Xr sctp_recvmsg 3 ,
+.Xr sctp 4
diff --git a/lib/libc/sys/sctp_generic_sendmsg.2 b/lib/libc/sys/sctp_generic_sendmsg.2
new file mode 100644
index 000000000000..bf54e95473d5
--- /dev/null
+++ b/lib/libc/sys/sctp_generic_sendmsg.2
@@ -0,0 +1,86 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd October 30, 2007
+.Dt SCTP_GENERIC_SENDMSG 2
+.Os
+.Sh NAME
+.Nm sctp_generic_sendmsg
+.Nm sctp_generic_sendmsg_iov
+.Nd send data to a peer
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/socket.h
+.In netinet/sctp.h
+.Ft int
+.Fn sctp_generic_sendmsg "int s" "void *msg" "int msglen" "struct sockaddr *to" "socklen_t len" "struct sctp_sndrcvinfo *sinfo" "int flags"
+.Ft int
+.Fn sctp_generic_sendmsg_iov "int s" "struct iovec *iov" "int iovlen" "struct sockaddr *to" "struct sctp_sndrcvinfo *sinfo" "int flags"
+.Sh DESCRIPTION
+.Fn sctp_generic_sendmsg
+and
+.Fn sctp_generic_sendmsg_iov
+are the true system calls used by the
+.Xr sctp_sendmsg 3
+and
+.Xr sctp_send 3
+function calls.
+These are more efficient since they are
+true system calls but they are specific to
+.Fx
+and can be expected
+.Em not
+to be present on any other operating
+system.
+For detailed usage please see either the
+.Xr sctp_send 3
+or
+.Xr sctp_sendmsg 3
+function calls.
+.Sh RETURN VALUES
+The call returns the number of bytes written on success and -1 upon failure.
+.Sh ERRORS
+.Bl -tag -width Er
+.It Bq Er EBADF
+The argument
+.Fa s
+is not a valid descriptor.
+.It Bq Er ENOTSOCK
+The argument
+.Fa s
+is not a socket.
+.El
+.Sh SEE ALSO
+.Xr sctp_send 3 ,
+.Xr sctp_sendmsg 3 ,
+.Xr sctp_sendmsgx 3 ,
+.Xr sctp_sendx 3 ,
+.Xr sctp 4
diff --git a/lib/libc/sys/sctp_peeloff.2 b/lib/libc/sys/sctp_peeloff.2
new file mode 100644
index 000000000000..9964586c9e9e
--- /dev/null
+++ b/lib/libc/sys/sctp_peeloff.2
@@ -0,0 +1,76 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd October 30, 2007
+.Dt SCTP_PEELOFF 2
+.Os
+.Sh NAME
+.Nm sctp_peeloff
+.Nd detach an association from a one-to-many socket to its own fd
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/socket.h
+.In netinet/sctp.h
+.Ft int
+.Fn sctp_peeloff "int s" "sctp_assoc_t id"
+.Sh DESCRIPTION
+The
+.Fn sctp_peeloff
+system call attempts detach the association specified by
+.Fa id
+into its own separate socket.
+.Sh RETURN VALUES
+The call returns -1 on failure and the new socket descriptor
+upon success.
+.Sh ERRORS
+The
+.Fn sctp_peeloff
+system call can return the following errors:
+.Bl -tag -width Er
+.It Bq Er ENOTCONN
+The
+.Fa id
+given to the call does not map to a valid
+association.
+.It Bq Er E2BIG
+The size of the address list exceeds the amount of
+data provided.
+.It Bq Er EBADF
+The argument
+.Fa s
+is not a valid descriptor.
+.It Bq Er ENOTSOCK
+The argument
+.Fa s
+is not a socket.
+.El
+.Sh SEE ALSO
+.Xr sctp 4
diff --git a/lib/libc/sys/select.2 b/lib/libc/sys/select.2
new file mode 100644
index 000000000000..59a79984f546
--- /dev/null
+++ b/lib/libc/sys/select.2
@@ -0,0 +1,227 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)select.2 8.2 (Berkeley) 3/25/94
+.\" $FreeBSD$
+.\"
+.Dd November 17, 2002
+.Dt SELECT 2
+.Os
+.Sh NAME
+.Nm select
+.Nd synchronous I/O multiplexing
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/select.h
+.Ft int
+.Fn select "int nfds" "fd_set *readfds" "fd_set *writefds" "fd_set *exceptfds" "struct timeval *timeout"
+.Fn FD_SET fd &fdset
+.Fn FD_CLR fd &fdset
+.Fn FD_ISSET fd &fdset
+.Fn FD_ZERO &fdset
+.Sh DESCRIPTION
+The
+.Fn select
+system call
+examines the I/O descriptor sets whose addresses are passed in
+.Fa readfds ,
+.Fa writefds ,
+and
+.Fa exceptfds
+to see if some of their descriptors
+are ready for reading, are ready for writing, or have an exceptional
+condition pending, respectively.
+The only exceptional condition detectable is out-of-band
+data received on a socket.
+The first
+.Fa nfds
+descriptors are checked in each set;
+i.e., the descriptors from 0 through
+.Fa nfds Ns No -1
+in the descriptor sets are examined.
+On return,
+.Fn select
+replaces the given descriptor sets
+with subsets consisting of those descriptors that are ready
+for the requested operation.
+The
+.Fn select
+system call
+returns the total number of ready descriptors in all the sets.
+.Pp
+The descriptor sets are stored as bit fields in arrays of integers.
+The following macros are provided for manipulating such descriptor sets:
+.Fn FD_ZERO &fdset
+initializes a descriptor set
+.Fa fdset
+to the null set.
+.Fn FD_SET fd &fdset
+includes a particular descriptor
+.Fa fd
+in
+.Fa fdset .
+.Fn FD_CLR fd &fdset
+removes
+.Fa fd
+from
+.Fa fdset .
+.Fn FD_ISSET fd &fdset
+is non-zero if
+.Fa fd
+is a member of
+.Fa fdset ,
+zero otherwise.
+The behavior of these macros is undefined if
+a descriptor value is less than zero or greater than or equal to
+.Dv FD_SETSIZE ,
+which is normally at least equal
+to the maximum number of descriptors supported by the system.
+.Pp
+If
+.Fa timeout
+is not a null pointer, it specifies the maximum interval to wait for the
+selection to complete.
+System activity can lengthen the interval by
+an indeterminate amount.
+.Pp
+If
+.Fa timeout
+is a null pointer, the select blocks indefinitely.
+.Pp
+To effect a poll, the
+.Fa timeout
+argument should not be a null pointer,
+but it should point to a zero-valued timeval structure.
+.Pp
+Any of
+.Fa readfds ,
+.Fa writefds ,
+and
+.Fa exceptfds
+may be given as null pointers if no descriptors are of interest.
+.Sh RETURN VALUES
+The
+.Fn select
+system call
+returns the number of ready descriptors that are contained in
+the descriptor sets,
+or -1 if an error occurred.
+If the time limit expires,
+.Fn select
+returns 0.
+If
+.Fn select
+returns with an error,
+including one due to an interrupted system call,
+the descriptor sets will be unmodified.
+.Sh ERRORS
+An error return from
+.Fn select
+indicates:
+.Bl -tag -width Er
+.It Bq Er EBADF
+One of the descriptor sets specified an invalid descriptor.
+.It Bq Er EFAULT
+One of the arguments
+.Fa readfds , writefds , exceptfds ,
+or
+.Fa timeout
+points to an invalid address.
+.It Bq Er EINTR
+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 invalid.
+One of its components is
+negative or too large.
+.It Bq Er EINVAL
+The
+.Fa nfds
+argument
+was invalid.
+.El
+.Sh SEE ALSO
+.Xr accept 2 ,
+.Xr connect 2 ,
+.Xr getdtablesize 2 ,
+.Xr gettimeofday 2 ,
+.Xr kqueue 2 ,
+.Xr poll 2 ,
+.Xr read 2 ,
+.Xr recv 2 ,
+.Xr send 2 ,
+.Xr write 2 ,
+.Xr clocks 7
+.Sh NOTES
+The default size of
+.Dv FD_SETSIZE
+is currently 1024.
+In order to accommodate programs which might potentially
+use a larger number of open files with
+.Fn select ,
+it is possible
+to increase this size by having the program define
+.Dv FD_SETSIZE
+before the inclusion of any header which includes
+.In sys/types.h .
+.Pp
+If
+.Fa nfds
+is greater than the number of open files,
+.Fn select
+is not guaranteed to examine the unused file descriptors.
+For historical
+reasons,
+.Fn select
+will always examine the first 256 descriptors.
+.Sh STANDARDS
+The
+.Fn select
+system call and
+.Fn FD_CLR ,
+.Fn FD_ISSET ,
+.Fn FD_SET ,
+and
+.Fn FD_ZERO
+macros conform with
+.St -p1003.1-2001 .
+.Sh HISTORY
+The
+.Fn select
+system call appeared in
+.Bx 4.2 .
+.Sh BUGS
+.St -susv2
+allows systems to modify the original timeout in place.
+Thus, it is unwise to assume that the timeout value will be unmodified
+by the
+.Fn select
+system call.
+.Fx
+does not modify the return value, which can cause problems for applications
+ported from other systems.
diff --git a/lib/libc/sys/select.c b/lib/libc/sys/select.c
new file mode 100644
index 000000000000..3990496ec412
--- /dev/null
+++ b/lib/libc/sys/select.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2014 The FreeBSD Foundation.
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Konstantin Belousov
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice(s), this list of conditions and the following disclaimer as
+ * the first lines of this file unmodified other than the possible
+ * addition of one or more copyright notices.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice(s), this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/select.h>
+#include "libc_private.h"
+
+__weak_reference(__sys_select, __select);
+
+#pragma weak select
+int
+select(int n, fd_set *rs, fd_set *ws, fd_set *es, struct timeval *t)
+{
+
+ return (((int (*)(int, fd_set *, fd_set *, fd_set *, struct timeval *))
+ __libc_interposing[INTERPOS_select])(n, rs, ws, es, t));
+}
diff --git a/lib/libc/sys/semctl.2 b/lib/libc/sys/semctl.2
new file mode 100644
index 000000000000..adfb9ef52d79
--- /dev/null
+++ b/lib/libc/sys/semctl.2
@@ -0,0 +1,200 @@
+.\"
+.\" Copyright (c) 1995 David Hovemeyer <daveho@infocom.com>
+.\"
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (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 September 12, 1995
+.Dt SEMCTL 2
+.Os
+.Sh NAME
+.Nm semctl
+.Nd control operations on a semaphore set
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/ipc.h
+.In sys/sem.h
+.Ft int
+.Fn semctl "int semid" "int semnum" "int cmd" ...
+.Sh DESCRIPTION
+The
+.Fn semctl
+system call
+performs the operation indicated by
+.Fa cmd
+on the semaphore set indicated by
+.Fa semid .
+A fourth argument, a
+.Fa "union semun arg" ,
+is required for certain values of
+.Fa cmd .
+For the commands that use the
+.Fa arg
+argument,
+.Fa "union semun"
+is defined as follows:
+.\"
+.\" From <sys/sem.h>:
+.\"
+.Bd -literal
+union semun {
+ int val; /* value for SETVAL */
+ struct semid_ds *buf; /* buffer for IPC_STAT & IPC_SET */
+ u_short *array; /* array for GETALL & SETALL */
+};
+.Ed
+.Pp
+Commands are performed as follows:
+.\"
+.\" This section based on Stevens, _Advanced Programming in the UNIX
+.\" Environment_.
+.\"
+.Bl -tag -width IPC_RMIDXXX
+.It Dv IPC_STAT
+Fetch the semaphore set's
+.Fa "struct semid_ds" ,
+storing it in the memory pointed to by
+.Fa arg.buf .
+.It Dv IPC_SET
+Changes the
+.Fa sem_perm.uid ,
+.Fa sem_perm.gid ,
+and
+.Fa sem_perm.mode
+members of the semaphore set's
+.Fa "struct semid_ds"
+to match those of the struct pointed to by
+.Fa arg.buf .
+The calling process's effective uid must
+match either
+.Fa sem_perm.uid
+or
+.Fa sem_perm.cuid ,
+or it must have superuser privileges.
+.It IPC_RMID
+Immediately removes the semaphore set from the system.
+The calling
+process's effective uid must equal the semaphore set's
+.Fa sem_perm.uid
+or
+.Fa sem_perm.cuid ,
+or the process must have superuser privileges.
+.It Dv GETVAL
+Return the value of semaphore number
+.Fa semnum .
+.It Dv SETVAL
+Set the value of semaphore number
+.Fa semnum
+to
+.Fa arg.val .
+Outstanding adjust on exit values for this semaphore in any process
+are cleared.
+.It Dv GETPID
+Return the pid of the last process to perform an operation on
+semaphore number
+.Fa semnum .
+.It Dv GETNCNT
+Return the number of processes waiting for semaphore number
+.Fa semnum Ns 's
+value to become greater than its current value.
+.It Dv GETZCNT
+Return the number of processes waiting for semaphore number
+.Fa semnum Ns 's
+value to become 0.
+.It Dv GETALL
+Fetch the value of all of the semaphores in the set into the
+array pointed to by
+.Fa arg.array .
+.It Dv SETALL
+Set the values of all of the semaphores in the set to the values
+in the array pointed to by
+.Fa arg.array .
+Outstanding adjust on exit values for all semaphores in this set,
+in any process are cleared.
+.El
+.Pp
+The
+.Vt "struct semid_ds"
+is defined as follows:
+.\"
+.\" Taken straight from <sys/sem.h>.
+.\"
+.Bd -literal
+struct semid_ds {
+ struct ipc_perm sem_perm; /* operation permission struct */
+ struct sem *sem_base; /* pointer to first semaphore in set */
+ u_short sem_nsems; /* number of sems in set */
+ time_t sem_otime; /* last operation time */
+ time_t sem_ctime; /* last change time */
+ /* Times measured in secs since */
+ /* 00:00:00 GMT, Jan. 1, 1970 */
+};
+.Ed
+.Sh RETURN VALUES
+On success, when
+.Fa cmd
+is one of
+.Dv GETVAL , GETPID , GETNCNT
+or
+.Dv GETZCNT ,
+.Fn semctl
+returns the corresponding value; otherwise, 0 is returned.
+On failure, -1 is returned, and
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+The
+.Fn semctl
+system call
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+No semaphore set corresponds to
+.Fa semid .
+.It Bq Er EINVAL
+The
+.Fa semnum
+argument
+is not in the range of valid semaphores for given semaphore set.
+.It Bq Er EPERM
+The calling process's effective uid does not match the uid of
+the semaphore set's owner or creator.
+.It Bq Er EACCES
+Permission denied due to mismatch between operation and mode of
+semaphore set.
+.It Bq Er ERANGE
+.Dv SETVAL
+or
+.Dv SETALL
+attempted to set a semaphore outside the allowable range
+.Bq 0 .. Dv SEMVMX .
+.El
+.Sh SEE ALSO
+.Xr semget 2 ,
+.Xr semop 2
+.Sh BUGS
+.Dv SETALL
+may update some semaphore elements before returning an error.
diff --git a/lib/libc/sys/semget.2 b/lib/libc/sys/semget.2
new file mode 100644
index 000000000000..debcf11224ae
--- /dev/null
+++ b/lib/libc/sys/semget.2
@@ -0,0 +1,159 @@
+.\"
+.\" Copyright (c) 1995 David Hovemeyer <daveho@infocom.com>
+.\"
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (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 February 7, 2016
+.Dt SEMGET 2
+.Os
+.Sh NAME
+.Nm semget
+.Nd obtain a semaphore id
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/ipc.h
+.In sys/sem.h
+.Ft int
+.Fn semget "key_t key" "int nsems" "int flag"
+.Sh DESCRIPTION
+Based on the values of
+.Fa key
+and
+.Fa flag ,
+.Fn semget
+returns the identifier of a newly created or previously existing
+set of semaphores.
+.\"
+.\" This is copied verbatim from the shmget manpage. Perhaps
+.\" it should go in a common manpage, such as .Xr ipc 2
+.\"
+The key
+is analogous to a filename: it provides a handle that names an
+IPC object.
+There are three ways to specify a key:
+.Bl -bullet
+.It
+IPC_PRIVATE may be specified, in which case a new IPC object
+will be created.
+.It
+An integer constant may be specified.
+If no IPC object corresponding
+to
+.Fa key
+is specified and the IPC_CREAT bit is set in
+.Fa flag ,
+a new one will be created.
+.It
+The
+.Xr ftok 3
+function
+may be used to generate a key from a pathname.
+.El
+.\"
+.\" Likewise for this section, except SHM_* becomes SEM_*.
+.\"
+.Pp
+The mode of a newly created IPC object is determined by
+.Em OR Ns 'ing
+the following constants into the
+.Fa flag
+argument:
+.Bl -tag -width XSEM_WXX6XXX
+.It Dv SEM_R
+Read access for user.
+.It Dv SEM_A
+Alter access for user.
+.It Dv ( SEM_R>>3 )
+Read access for group.
+.It Dv ( SEM_A>>3 )
+Alter access for group.
+.It Dv ( SEM_R>>6 )
+Read access for other.
+.It Dv ( SEM_A>>6 )
+Alter access for other.
+.El
+.Pp
+If a new set of semaphores is being created,
+.Fa nsems
+is used to indicate the number of semaphores the set should contain.
+Otherwise,
+.Fa nsems
+may be specified as 0.
+.Sh RETURN VALUES
+The
+.Fn semget
+system call
+returns the id of a semaphore set if successful; otherwise, -1
+is returned and
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+The
+.Fn semget
+system call
+will fail if:
+.Bl -tag -width Er
+.\" ipcperm could fail (we are opening to read and write, as it were)
+.It Bq Er EACCES
+Access permission failure.
+.\"
+.\" sysv_sem.c is quite explicit about these, so I'm pretty sure
+.\" this is accurate
+.\"
+.It Bq Er EEXIST
+IPC_CREAT and IPC_EXCL were specified, and a semaphore set
+corresponding to
+.Fa key
+already exists.
+.It Bq Er EINVAL
+The number of semaphores requested exceeds the system imposed maximum
+per set.
+.It Bq Er EINVAL
+A semaphore set corresponding to
+.Fa key
+already exists and contains fewer semaphores than
+.Fa nsems .
+.It Bq Er EINVAL
+A semaphore set corresponding to
+.Fa key
+does not exist and
+.Fa nsems
+is 0 or negative.
+.It Bq Er ENOSPC
+Insufficiently many semaphores are available.
+.It Bq Er ENOSPC
+The kernel could not allocate a
+.Fa "struct semid_ds" .
+.It Bq Er ENOENT
+No semaphore set was found corresponding to
+.Fa key ,
+and IPC_CREAT was not specified.
+.El
+.Sh SEE ALSO
+.Xr semctl 2 ,
+.Xr semop 2 ,
+.Xr ftok 3
diff --git a/lib/libc/sys/semop.2 b/lib/libc/sys/semop.2
new file mode 100644
index 000000000000..a08f65e8e8bd
--- /dev/null
+++ b/lib/libc/sys/semop.2
@@ -0,0 +1,289 @@
+.\"
+.\" Copyright (c) 1995 David Hovemeyer <daveho@infocom.com>
+.\"
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (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 September 22, 1995
+.Dt SEMOP 2
+.Os
+.Sh NAME
+.Nm semop
+.Nd atomic array of operations on a semaphore set
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/ipc.h
+.In sys/sem.h
+.Ft int
+.Fn semop "int semid" "struct sembuf *array" "size_t nops"
+.Sh DESCRIPTION
+The
+.Fn semop
+system call
+atomically performs the array of operations indicated by
+.Fa array
+on the semaphore set indicated by
+.Fa semid .
+The length of
+.Fa array
+is indicated by
+.Fa nops .
+Each operation is encoded in a
+.Vt "struct sembuf" ,
+which is defined as follows:
+.\"
+.\" From <sys/sem.h>
+.\"
+.Bd -literal
+struct sembuf {
+ u_short sem_num; /* semaphore # */
+ short sem_op; /* semaphore operation */
+ short sem_flg; /* operation flags */
+};
+.Ed
+.Pp
+For each element in
+.Fa array ,
+.Va sem_op
+and
+.Va sem_flg
+determine an operation to be performed on semaphore number
+.Va sem_num
+in the set.
+The values
+.Dv SEM_UNDO
+and
+.Dv IPC_NOWAIT
+may be
+.Em OR Ns 'ed
+into the
+.Va sem_flg
+member in order to modify the behavior of the given operation.
+.Pp
+The operation performed depends as follows on the value of
+.Va sem_op :
+.\"
+.\" This section is based on the description of semop() in
+.\" Stevens, _Advanced Programming in the UNIX Environment_,
+.\" and the semop(2) description in The Open Group Unix2 specification.
+.\"
+.Bl -bullet
+.It
+When
+.Va sem_op
+is positive and the process has alter permission,
+the semaphore's value is incremented by
+.Va sem_op Ns 's
+value.
+If
+.Dv SEM_UNDO
+is specified, the semaphore's adjust on exit value is decremented by
+.Va sem_op Ns 's
+value.
+A positive value for
+.Va sem_op
+generally corresponds to a process releasing a resource
+associated with the semaphore.
+.It
+The behavior when
+.Va sem_op
+is negative and the process has alter permission,
+depends on the current value of the semaphore:
+.Bl -bullet
+.It
+If the current value of the semaphore is greater than or equal to
+the absolute value of
+.Va sem_op ,
+then the value is decremented by the absolute value of
+.Va sem_op .
+If
+.Dv SEM_UNDO
+is specified, the semaphore's adjust on exit
+value is incremented by the absolute value of
+.Va sem_op .
+.It
+If the current value of the semaphore is less than the absolute value of
+.Va sem_op ,
+one of the following happens:
+.\" XXX a *second* sublist?
+.Bl -bullet
+.It
+If
+.Dv IPC_NOWAIT
+was specified, then
+.Fn semop
+returns immediately with a return value of
+.Er EAGAIN .
+.It
+Otherwise, the calling process is put to sleep until one of the following
+conditions is satisfied:
+.\" XXX We already have two sublists, why not a third?
+.Bl -bullet
+.It
+Some other process removes the semaphore with the
+.Dv IPC_RMID
+option of
+.Xr semctl 2 .
+In this case,
+.Fn semop
+returns immediately with a return value of
+.Er EIDRM .
+.It
+The process receives a signal that is to be caught.
+In this case, the process will resume execution as defined by
+.Xr sigaction 2 .
+.It
+The semaphore's
+value is greater than or equal to the absolute value of
+.Va sem_op .
+When this condition becomes true, the semaphore's value is decremented
+by the absolute value of
+.Va sem_op ,
+the semaphore's adjust on exit value is incremented by the
+absolute value of
+.Va sem_op .
+.El
+.El
+.El
+.Pp
+A negative value for
+.Va sem_op
+generally means that a process is waiting for a resource to become
+available.
+.It
+When
+.Va sem_op
+is zero and the process has read permission,
+one of the following will occur:
+.Bl -bullet
+.It
+If the current value of the semaphore is equal to zero
+then
+.Fn semop
+can return immediately.
+.It
+If
+.Dv IPC_NOWAIT
+was specified, then
+.Fn semop
+returns immediately with a return value of
+.Er EAGAIN .
+.It
+Otherwise, the calling process is put to sleep until one of the following
+conditions is satisfied:
+.\" XXX Another nested sublists
+.Bl -bullet
+.It
+Some other process removes the semaphore with the
+.Dv IPC_RMID
+option of
+.Xr semctl 2 .
+In this case,
+.Fn semop
+returns immediately with a return value of
+.Er EIDRM .
+.It
+The process receives a signal that is to be caught.
+In this case, the process will resume execution as defined by
+.Xr sigaction 2 .
+.It
+The semaphore's value becomes zero.
+.El
+.El
+.El
+.Pp
+For each semaphore a process has in use, the kernel maintains an
+.Dq "adjust on exit"
+value, as alluded to earlier.
+When a process
+exits, either voluntarily or involuntarily, the adjust on exit value
+for each semaphore is added to the semaphore's value.
+This can
+be used to ensure that a resource is released if a process terminates
+unexpectedly.
+.Sh RETURN VALUES
+.Rv -std semop
+.Sh ERRORS
+The
+.Fn semop
+system call will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+No semaphore set corresponds to
+.Fa semid ,
+or the process would exceed the system-defined limit for the number of
+per-process
+.Dv SEM_UNDO
+structures.
+.It Bq Er EACCES
+Permission denied due to mismatch between operation and mode of
+semaphore set.
+.It Bq Er EAGAIN
+The semaphore's value would have resulted in the process being put to sleep
+and
+.Dv IPC_NOWAIT
+was specified.
+.It Bq Er E2BIG
+Too many operations were specified.
+.Bq Dv SEMOPM
+.It Bq Er EFBIG
+.\"
+.\" I'd have thought this would be EINVAL, but the source says
+.\" EFBIG.
+.\"
+.Va sem_num
+was not in the range of valid semaphores for the set.
+.It Bq Er EIDRM
+The semaphore set was removed from the system.
+.It Bq Er EINTR
+The
+.Fn semop
+system call was interrupted by a signal.
+.It Bq Er ENOSPC
+The system
+.Dv SEM_UNDO
+pool
+.Bq Dv SEMMNU
+is full.
+.It Bq Er ERANGE
+The requested operation would cause either
+the semaphore's current value
+.Bq Dv SEMVMX
+or its adjust on exit value
+.Bq Dv SEMAEM
+to exceed the system-imposed limits.
+.El
+.Sh SEE ALSO
+.Xr semctl 2 ,
+.Xr semget 2 ,
+.Xr sigaction 2
+.Sh BUGS
+The
+.Fn semop
+system call
+may block waiting for memory even if
+.Dv IPC_NOWAIT
+was specified.
diff --git a/lib/libc/sys/send.2 b/lib/libc/sys/send.2
new file mode 100644
index 000000000000..160bda1a0e62
--- /dev/null
+++ b/lib/libc/sys/send.2
@@ -0,0 +1,269 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" From: @(#)send.2 8.2 (Berkeley) 2/21/94
+.\" $FreeBSD$
+.\"
+.Dd August 18, 2016
+.Dt SEND 2
+.Os
+.Sh NAME
+.Nm send ,
+.Nm sendto ,
+.Nm sendmsg ,
+.Nm sendmmsg
+.Nd send message(s) from a socket
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/socket.h
+.Ft ssize_t
+.Fn send "int s" "const void *msg" "size_t len" "int flags"
+.Ft ssize_t
+.Fn sendto "int s" "const void *msg" "size_t len" "int flags" "const struct sockaddr *to" "socklen_t tolen"
+.Ft ssize_t
+.Fn sendmsg "int s" "const struct msghdr *msg" "int flags"
+.Ft ssize_t
+.Fn sendmmsg "int s" "struct mmsghdr * restrict msgvec" "size_t vlen" "int flags"
+.Sh DESCRIPTION
+The
+.Fn send
+and
+.Fn sendmmsg
+functions,
+and
+.Fn sendto
+and
+.Fn sendmsg
+system calls
+are used to transmit one or more messages (with the
+.Fn sendmmsg
+call) to
+another socket.
+The
+.Fn send
+function
+may be used only when the socket is in a
+.Em connected
+state, while
+.Fn sendto ,
+.Fn sendmsg
+and
+.Fn sendmmsg
+may be used at any time.
+.Pp
+The address of the target is given by
+.Fa to
+with
+.Fa tolen
+specifying its size.
+The length of the message is given by
+.Fa len .
+If the message is too long to pass atomically through the
+underlying protocol, the error
+.Er EMSGSIZE
+is returned, and
+the message is not transmitted.
+.Pp
+The
+.Fn sendmmsg
+function sends multiple messages at a call.
+They are given by the
+.Fa msgvec
+vector along with
+.Fa vlen
+specifying the vector size.
+The number of octets sent per each message is placed in the
+.Fa msg_len
+field of each processed element of the vector after transmission.
+.Pp
+No indication of failure to deliver is implicit in a
+.Fn send .
+Locally detected errors are indicated by a return value of -1.
+.Pp
+If no messages space is available at the socket to hold
+the message to be transmitted, then
+.Fn send
+normally blocks, unless the socket has been placed in
+non-blocking I/O mode.
+The
+.Xr select 2
+system call may be used to determine when it is possible to
+send more data.
+.Pp
+The
+.Fa flags
+argument may include one or more of the following:
+.Bd -literal
+#define MSG_OOB 0x00001 /* process out-of-band data */
+#define MSG_DONTROUTE 0x00004 /* bypass routing, use direct interface */
+#define MSG_EOR 0x00008 /* data completes record */
+#define MSG_EOF 0x00100 /* data completes transaction */
+#define MSG_NOSIGNAL 0x20000 /* do not generate SIGPIPE on EOF */
+.Ed
+.Pp
+The flag
+.Dv MSG_OOB
+is used to send
+.Dq out-of-band
+data on sockets that support this notion (e.g.\&
+.Dv SOCK_STREAM ) ;
+the underlying protocol must also support
+.Dq out-of-band
+data.
+.Dv MSG_EOR
+is used to indicate a record mark for protocols which support the
+concept.
+.Dv MSG_EOF
+requests that the sender side of a socket be shut down, and that an
+appropriate indication be sent at the end of the specified data;
+this flag is only implemented for
+.Dv SOCK_STREAM
+sockets in the
+.Dv PF_INET
+protocol family.
+.Dv MSG_DONTROUTE
+is usually used only by diagnostic or routing programs.
+.Dv MSG_NOSIGNAL
+is used to prevent
+.Dv SIGPIPE
+generation when writing a socket that
+may be closed.
+.Pp
+See
+.Xr recv 2
+for a description of the
+.Fa msghdr
+structure and the
+.Fa mmsghdr
+structure.
+.Sh RETURN VALUES
+The
+.Fn send ,
+.Fn sendto
+and
+.Fn sendmsg
+calls
+return the number of octets sent.
+The
+.Fn sendmmsg
+call returns the number of messages sent.
+If an error occurred a value of -1 is returned.
+.Sh ERRORS
+The
+.Fn send
+and
+.Fn sendmmsg
+functions and
+.Fn sendto
+and
+.Fn sendmsg
+system calls
+fail if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+An invalid descriptor was specified.
+.It Bq Er EACCES
+The destination address is a broadcast address, and
+.Dv SO_BROADCAST
+has not been set on the socket.
+.It Bq Er ENOTSOCK
+The argument
+.Fa s
+is not a socket.
+.It Bq Er EFAULT
+An invalid user space address was specified for an argument.
+.It Bq Er EMSGSIZE
+The socket requires that message be sent atomically,
+and the size of the message to be sent made this impossible.
+.It Bq Er EAGAIN
+The socket is marked non-blocking and the requested operation
+would block.
+.It Bq Er ENOBUFS
+The system was unable to allocate an internal buffer.
+The operation may succeed when buffers become available.
+.It Bq Er ENOBUFS
+The output queue for a network interface was full.
+This generally indicates that the interface has stopped sending,
+but may be caused by transient congestion.
+.It Bq Er EHOSTUNREACH
+The remote host was unreachable.
+.It Bq Er EISCONN
+A destination address was specified and the socket is already connected.
+.It Bq Er ECONNREFUSED
+The socket received an ICMP destination unreachable message
+from the last message sent.
+This typically means that the
+receiver is not listening on the remote port.
+.It Bq Er EHOSTDOWN
+The remote host was down.
+.It Bq Er ENETDOWN
+The remote network was down.
+.It Bq Er EADDRNOTAVAIL
+The process using a
+.Dv SOCK_RAW
+socket was jailed and the source
+address specified in the IP header did not match the IP
+address bound to the prison.
+.It Bq Er EPIPE
+The socket is unable to send anymore data
+.Dv ( SBS_CANTSENDMORE
+has been set on the socket).
+This typically means that the socket
+is not connected.
+.El
+.Sh SEE ALSO
+.Xr fcntl 2 ,
+.Xr getsockopt 2 ,
+.Xr recv 2 ,
+.Xr select 2 ,
+.Xr socket 2 ,
+.Xr write 2
+.Sh HISTORY
+The
+.Fn send
+function appeared in
+.Bx 4.2 .
+The
+.Fn sendmmsg
+function appeared in
+.Fx 11.0 .
+.Sh BUGS
+Because
+.Fn sendmsg
+does not necessarily block until the data has been transferred, it
+is possible to transfer an open file descriptor across an
+.Dv AF_UNIX
+domain socket
+(see
+.Xr recv 2 ) ,
+then
+.Fn close
+it before it has actually been sent, the result being that the receiver
+gets a closed file descriptor.
+It is left to the application to
+implement an acknowledgment mechanism to prevent this from happening.
diff --git a/lib/libc/sys/sendfile.2 b/lib/libc/sys/sendfile.2
new file mode 100644
index 000000000000..313c349ee9ff
--- /dev/null
+++ b/lib/libc/sys/sendfile.2
@@ -0,0 +1,399 @@
+.\" Copyright (c) 2003, David G. Lawrence
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice unmodified, this list of conditions, and the following
+.\" disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 November 17, 2016
+.Dt SENDFILE 2
+.Os
+.Sh NAME
+.Nm sendfile
+.Nd send a file to a socket
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/socket.h
+.In sys/uio.h
+.Ft int
+.Fo sendfile
+.Fa "int fd" "int s" "off_t offset" "size_t nbytes"
+.Fa "struct sf_hdtr *hdtr" "off_t *sbytes" "int flags"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn sendfile
+system call
+sends a regular file or shared memory object specified by descriptor
+.Fa fd
+out a stream socket specified by descriptor
+.Fa s .
+.Pp
+The
+.Fa offset
+argument specifies where to begin in the file.
+Should
+.Fa offset
+fall beyond the end of file, the system will return
+success and report 0 bytes sent as described below.
+The
+.Fa nbytes
+argument specifies how many bytes of the file should be sent, with 0 having the special
+meaning of send until the end of file has been reached.
+.Pp
+An optional header and/or trailer can be sent before and after the file data by specifying
+a pointer to a
+.Vt "struct sf_hdtr" ,
+which has the following structure:
+.Pp
+.Bd -literal -offset indent -compact
+struct sf_hdtr {
+ struct iovec *headers; /* pointer to header iovecs */
+ int hdr_cnt; /* number of header iovecs */
+ struct iovec *trailers; /* pointer to trailer iovecs */
+ int trl_cnt; /* number of trailer iovecs */
+};
+.Ed
+.Pp
+The
+.Fa headers
+and
+.Fa trailers
+pointers, if
+.Pf non- Dv NULL ,
+point to arrays of
+.Vt "struct iovec"
+structures.
+See the
+.Fn writev
+system call for information on the iovec structure.
+The number of iovecs in these
+arrays is specified by
+.Fa hdr_cnt
+and
+.Fa trl_cnt .
+.Pp
+If
+.Pf non- Dv NULL ,
+the system will write the total number of bytes sent on the socket to the
+variable pointed to by
+.Fa sbytes .
+.Pp
+The least significant 16 bits of
+.Fa flags
+argument is a bitmap of these values:
+.Bl -tag -offset indent
+.It Dv SF_NODISKIO
+This flag causes
+.Nm
+to return
+.Er EBUSY
+instead of blocking when a busy page is encountered.
+This rare situation can happen if some other process is now working
+with the same region of the file.
+It is advised to retry the operation after a short period.
+.Pp
+Note that in older
+.Fx
+versions the
+.Dv SF_NODISKIO
+had slightly different notion.
+The flag prevented
+.Nm
+to run I/O operations in case if an invalid (not cached) page is encountered,
+thus avoiding blocking on I/O.
+Starting with
+.Fx 11
+.Nm
+sending files off the
+.Xr ffs 7
+filesystem doesn't block on I/O
+(see
+.Sx IMPLEMENTATION NOTES
+), so the condition no longer applies.
+However, it is safe if an application utilizes
+.Dv SF_NODISKIO
+and on
+.Er EBUSY
+performs the same action as it did in
+older
+.Fx
+versions, e.g.
+.Xr aio_read 2,
+.Xr read 2
+or
+.Nm
+in a different context.
+.It Dv SF_NOCACHE
+The data sent to socket will not be cached by the virtual memory system,
+and will be freed directly to the pool of free pages.
+.It Dv SF_SYNC
+.Nm
+sleeps until the network stack no longer references the VM pages
+of the file, making subsequent modifications to it safe.
+Please note that this is not a guarantee that the data has actually
+been sent.
+.It Dv SF_USER_READAHEAD
+.Nm
+has some internal heuristics to do readahead when sending data.
+This flag forces
+.Nm
+to override any heuristically calculated readahead and use exactly the
+application specified readahead.
+See
+.Sx SETTING READAHEAD
+for more details on readahead.
+.El
+.Pp
+When using a socket marked for non-blocking I/O,
+.Fn sendfile
+may send fewer bytes than requested.
+In this case, the number of bytes successfully
+written is returned in
+.Fa *sbytes
+(if specified),
+and the error
+.Er EAGAIN
+is returned.
+.Sh SETTING READAHEAD
+.Nm
+uses internal heuristics based on request size and file system layout
+to do readahead.
+Additionally application may request extra readahead.
+The most significant 16 bits of
+.Fa flags
+specify amount of pages that
+.Nm
+may read ahead when reading the file.
+A macro
+.Fn SF_FLAGS
+is provided to combine readahead amount and flags.
+Example shows specifing readahead of 16 pages and
+.Dv SF_NOCACHE
+flag:
+.Pp
+.Bd -literal -offset indent -compact
+ SF_FLAGS(16, SF_NOCACHE)
+.Ed
+.Pp
+.Nm
+will use either application specified readahead or internally calculated,
+whichever is bigger.
+Setting flag
+.Dv SF_USER_READAHEAD
+would turn off any heuristics and set maximum possible readahead length to
+the number of pages specified via flags.
+.Sh IMPLEMENTATION NOTES
+The
+.Fx
+implementation of
+.Fn sendfile
+doesn't block on disk I/O when it sends a file off the
+.Xr ffs 7
+filesystem.
+The syscall returns success before the actual I/O completes, and data
+is put into the socket later unattended.
+However, the order of data in the socket is preserved, so it is safe
+to do further writes to the socket.
+.Pp
+The
+.Fx
+implementation of
+.Fn sendfile
+is "zero-copy", meaning that it has been optimized so that copying of the file data is avoided.
+.Sh TUNING
+On some architectures, this system call internally uses a special
+.Fn sendfile
+buffer
+.Pq Vt "struct sf_buf"
+to handle sending file data to the client.
+If the sending socket is
+blocking, and there are not enough
+.Fn sendfile
+buffers available,
+.Fn sendfile
+will block and report a state of
+.Dq Li sfbufa .
+If the sending socket is non-blocking and there are not enough
+.Fn sendfile
+buffers available, the call will block and wait for the
+necessary buffers to become available before finishing the call.
+.Pp
+The number of
+.Vt sf_buf Ns 's
+allocated should be proportional to the number of nmbclusters used to
+send data to a client via
+.Fn sendfile .
+Tune accordingly to avoid blocking!
+Busy installations that make extensive use of
+.Fn sendfile
+may want to increase these values to be inline with their
+.Va kern.ipc.nmbclusters
+(see
+.Xr tuning 7
+for details).
+.Pp
+The number of
+.Fn sendfile
+buffers available is determined at boot time by either the
+.Va kern.ipc.nsfbufs
+.Xr loader.conf 5
+variable or the
+.Dv NSFBUFS
+kernel configuration tunable.
+The number of
+.Fn sendfile
+buffers scales with
+.Va kern.maxusers .
+The
+.Va kern.ipc.nsfbufsused
+and
+.Va kern.ipc.nsfbufspeak
+read-only
+.Xr sysctl 8
+variables show current and peak
+.Fn sendfile
+buffers usage respectively.
+These values may also be viewed through
+.Nm netstat Fl m .
+.Pp
+If a value of zero is reported for
+.Va kern.ipc.nsfbufs ,
+your architecture does not need to use
+.Fn sendfile
+buffers because their task can be efficiently performed
+by the generic virtual memory structures.
+.Sh RETURN VALUES
+.Rv -std sendfile
+.Sh ERRORS
+.Bl -tag -width Er
+.It Bq Er EAGAIN
+The socket is marked for non-blocking I/O and not all data was sent due to
+the socket buffer being filled.
+If specified, the number of bytes successfully sent will be returned in
+.Fa *sbytes .
+.It Bq Er EBADF
+The
+.Fa fd
+argument
+is not a valid file descriptor.
+.It Bq Er EBADF
+The
+.Fa s
+argument
+is not a valid socket descriptor.
+.It Bq Er EBUSY
+A busy page was encountered and
+.Dv SF_NODISKIO
+had been specified.
+Partial data may have been sent.
+.It Bq Er EFAULT
+An invalid address was specified for an argument.
+.It Bq Er EINTR
+A signal interrupted
+.Fn sendfile
+before it could be completed.
+If specified, the number
+of bytes successfully sent will be returned in
+.Fa *sbytes .
+.It Bq Er EINVAL
+The
+.Fa fd
+argument
+is not a regular file.
+.It Bq Er EINVAL
+The
+.Fa s
+argument
+is not a SOCK_STREAM type socket.
+.It Bq Er EINVAL
+The
+.Fa offset
+argument
+is negative.
+.It Bq Er EIO
+An error occurred while reading from
+.Fa fd .
+.It Bq Er ENOBUFS
+The system was unable to allocate an internal buffer.
+.It Bq Er ENOTCONN
+The
+.Fa s
+argument
+points to an unconnected socket.
+.It Bq Er ENOTSOCK
+The
+.Fa s
+argument
+is not a socket.
+.It Bq Er EOPNOTSUPP
+The file system for descriptor
+.Fa fd
+does not support
+.Fn sendfile .
+.It Bq Er EPIPE
+The socket peer has closed the connection.
+.El
+.Sh SEE ALSO
+.Xr netstat 1 ,
+.Xr open 2 ,
+.Xr send 2 ,
+.Xr socket 2 ,
+.Xr writev 2 ,
+.Xr tuning 7
+.Rs
+.%A K. Elmeleegy
+.%A A. Chanda
+.%A A. L. Cox
+.%A W. Zwaenepoel
+.%T A Portable Kernel Abstraction for Low-Overhead Ephemeral Mapping Management
+.%J The Proceedings of the 2005 USENIX Annual Technical Conference
+.%P pp 223-236
+.%D 2005
+.Re
+.Sh HISTORY
+The
+.Fn sendfile
+system call
+first appeared in
+.Fx 3.0 .
+This manual page first appeared in
+.Fx 3.1 .
+In
+.Fx 10
+support for sending shared memory descriptors had been introduced.
+In
+.Fx 11
+a non-blocking implementation had been introduced.
+.Sh AUTHORS
+The initial implementation of
+.Fn sendfile
+system call
+and this manual page were written by
+.An David G. Lawrence Aq Mt dg@dglawrence.com .
+The
+.Fx 11
+implementation was written by
+.An Gleb Smirnoff Aq Mt glebius@FreeBSD.org .
diff --git a/lib/libc/sys/sendmsg.c b/lib/libc/sys/sendmsg.c
new file mode 100644
index 000000000000..794464339043
--- /dev/null
+++ b/lib/libc/sys/sendmsg.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2014 The FreeBSD Foundation.
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Konstantin Belousov
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice(s), this list of conditions and the following disclaimer as
+ * the first lines of this file unmodified other than the possible
+ * addition of one or more copyright notices.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice(s), this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/syscall.h>
+#include <sys/socket.h>
+#include "libc_private.h"
+
+__weak_reference(__sys_sendmsg, __sendmsg);
+
+#pragma weak sendmsg
+ssize_t
+sendmsg(int s, const struct msghdr *msg, int flags)
+{
+
+ return (((int (*)(int, const struct msghdr *, int))
+ __libc_interposing[INTERPOS_sendmsg])(s, msg, flags));
+}
diff --git a/lib/libc/sys/sendto.c b/lib/libc/sys/sendto.c
new file mode 100644
index 000000000000..ecf98ee05b19
--- /dev/null
+++ b/lib/libc/sys/sendto.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2014 The FreeBSD Foundation.
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Konstantin Belousov
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice(s), this list of conditions and the following disclaimer as
+ * the first lines of this file unmodified other than the possible
+ * addition of one or more copyright notices.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice(s), this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/syscall.h>
+#include <sys/socket.h>
+#include "libc_private.h"
+
+__weak_reference(__sys_sendto, __sendto);
+
+#pragma weak sendto
+ssize_t
+sendto(int s, const void *msg, size_t len, int flags,
+ const struct sockaddr *to, socklen_t tolen)
+{
+
+ return (((ssize_t (*)(int, const void *, size_t, int,
+ const struct sockaddr *, socklen_t))
+ __libc_interposing[INTERPOS_sendto])(s, msg, len, flags,
+ to, tolen));
+}
diff --git a/lib/libc/sys/setcontext.c b/lib/libc/sys/setcontext.c
new file mode 100644
index 000000000000..31b888f2bcff
--- /dev/null
+++ b/lib/libc/sys/setcontext.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2014 The FreeBSD Foundation.
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Konstantin Belousov
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice(s), this list of conditions and the following disclaimer as
+ * the first lines of this file unmodified other than the possible
+ * addition of one or more copyright notices.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice(s), this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <ucontext.h>
+#include "libc_private.h"
+
+__weak_reference(__sys_setcontext, __setcontext);
+__sym_compat(setcontext, __impl_setcontext, FBSD_1.0);
+__weak_reference(setcontext, __impl_setcontext);
+__sym_default(setcontext, setcontext, FBSD_1.2);
+
+#pragma weak setcontext
+int
+setcontext(const ucontext_t *uc)
+{
+
+ return (((int (*)(const ucontext_t *))
+ __libc_interposing[INTERPOS_setcontext])(uc));
+}
diff --git a/lib/libc/sys/setfib.2 b/lib/libc/sys/setfib.2
new file mode 100644
index 000000000000..d759109fa39e
--- /dev/null
+++ b/lib/libc/sys/setfib.2
@@ -0,0 +1,107 @@
+.\" Copyright (c) 2008 Cisco Systems. All rights reserved.
+.\" Author: Julian Elischer
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Neither the name of the Cisco Systems nor the names of its employees
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd March 19, 2012
+.Dt SETFIB 2
+.Os
+.Sh NAME
+.Nm setfib
+.Nd set the default FIB (routing table) for the calling process.
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/socket.h
+.Ft int
+.Fn setfib "int fib"
+.Sh DESCRIPTION
+The
+.Fn setfib
+system call sets the associated fib for all sockets opened
+subsequent to the call, to be that of the argument
+.Fa fib .
+The
+.Fa fib
+argument
+must be greater than or equal to 0
+and less than the current system maximum which
+may be retrieved by the
+.Va net.fibs
+sysctl.
+The system maximum is set in the kernel configuration file with
+.Bd -ragged -offset indent
+.Cd "options ROUTETABLES=" Ns Em N
+.Ed
+.Pp
+or in
+.Pa /boot/loader.conf
+with
+.Pp
+.Dl net.fibs= Ns Qq Em N
+.Pp
+where
+.Em N
+is an integer.
+This maximum is capped at 65536 due to the implementation storing
+the fib number in a 16-bit field in the
+.Xr mbuf 9
+packet header, however it is not suggested that one use such a large number
+as memory is allocated for every FIB regardless of whether it is used, and
+there are places where all FIBs are iterated over.
+.Pp
+The default fib of the process will be applied to all protocol families
+that support multiple fibs, and ignored by those that do not.
+The default fib for a process may be overridden for a socket with the use
+of the
+.Dv SO_SETFIB
+socket option.
+.Sh RETURN VALUES
+.Rv -std setfib
+.Sh ERRORS
+The
+.Fn setfib
+system call
+will fail and no action will be taken and return
+.Er EINVAL
+if the
+.Fa fib
+argument is greater than the current system maximum.
+.Sh SEE ALSO
+.Xr setfib 1 ,
+.Xr setsockopt 2
+.Sh STANDARDS
+The
+.Fn setfib
+system call is a
+.Fx
+extension however similar extensions
+have been added to many other
+.Ux
+style kernels.
+.Sh HISTORY
+The
+.Fn setfib
+function appeared in
+.Fx 7.1 .
diff --git a/lib/libc/sys/setgroups.2 b/lib/libc/sys/setgroups.2
new file mode 100644
index 000000000000..ef4c34c266e1
--- /dev/null
+++ b/lib/libc/sys/setgroups.2
@@ -0,0 +1,87 @@
+.\" Copyright (c) 1983, 1991, 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)setgroups.2 8.2 (Berkeley) 4/16/94
+.\" $FreeBSD$
+.\"
+.Dd April 16, 1994
+.Dt SETGROUPS 2
+.Os
+.Sh NAME
+.Nm setgroups
+.Nd set group access list
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/param.h
+.In unistd.h
+.Ft int
+.Fn setgroups "int ngroups" "const gid_t *gidset"
+.Sh DESCRIPTION
+The
+.Fn setgroups
+system call
+sets the group access list of the current user process
+according to the array
+.Fa gidset .
+The
+.Fa ngroups
+argument
+indicates the number of entries in the array and must be no
+more than
+.Dv {NGROUPS_MAX}+1 .
+.Pp
+Only the super-user may set a new group list.
+.Sh RETURN VALUES
+.Rv -std setgroups
+.Sh ERRORS
+The
+.Fn setgroups
+system call will fail if:
+.Bl -tag -width Er
+.It Bq Er EPERM
+The caller is not the super-user.
+.It Bq Er EINVAL
+The number specified in the
+.Fa ngroups
+argument is larger than the
+.Dv {NGROUPS_MAX}+1
+limit.
+.It Bq Er EFAULT
+The address specified for
+.Fa gidset
+is outside the process
+address space.
+.El
+.Sh SEE ALSO
+.Xr getgroups 2 ,
+.Xr initgroups 3
+.Sh HISTORY
+The
+.Fn setgroups
+system call appeared in
+.Bx 4.2 .
diff --git a/lib/libc/sys/setpgid.2 b/lib/libc/sys/setpgid.2
new file mode 100644
index 000000000000..4ad89de3263f
--- /dev/null
+++ b/lib/libc/sys/setpgid.2
@@ -0,0 +1,110 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)setpgid.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd February 8, 2004
+.Dt SETPGID 2
+.Os
+.Sh NAME
+.Nm setpgid ,
+.Nm setpgrp
+.Nd set process group
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft int
+.Fn setpgid "pid_t pid" "pid_t pgrp"
+.Ft int
+.Fn setpgrp "pid_t pid" "pid_t pgrp"
+.Sh DESCRIPTION
+The
+.Fn setpgid
+system call
+sets the process group of the specified process
+.Fa pid
+to the specified
+.Fa pgrp .
+If
+.Fa pid
+is zero, then the call applies to the current process.
+If
+.Fa pgrp
+is zero, then the process id of the process specified by
+.Fa pid
+is used instead.
+.Pp
+If the affected process is not the invoking process, then it must be a
+child of the invoking process, it must not have performed an
+.Xr exec 3
+operation, and both processes must be in the same session.
+The requested process group ID must already exist in the session of
+the caller, or it must be equal to the target process ID.
+.Sh RETURN VALUES
+.Rv -std setpgid
+.Sh COMPATIBILITY
+The
+.Fn setpgrp
+system call
+is identical to
+.Fn setpgid ,
+and is retained for calling convention compatibility with historical
+versions of
+.Bx .
+.Sh ERRORS
+The
+.Fn setpgid
+system call
+will fail and the process group will not be altered if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The requested process group ID is not legal.
+.It Bq Er ESRCH
+The requested process does not exist.
+.It Bq Er ESRCH
+The target process is not the calling process or
+a child of the calling process.
+.It Bq Er EACCES
+The requested process is a child of the calling process,
+but it has performed an
+.Xr exec 3
+operation.
+.It Bq Er EPERM
+The target process is a session leader.
+.It Bq Er EPERM
+The requested process group ID is not in the session of the caller,
+and it is not equal to the process ID of the target process.
+.El
+.Sh SEE ALSO
+.Xr getpgrp 2
+.Sh STANDARDS
+The
+.Fn setpgid
+system call is expected to conform to
+.St -p1003.1-90 .
diff --git a/lib/libc/sys/setregid.2 b/lib/libc/sys/setregid.2
new file mode 100644
index 000000000000..2eedae2ceda1
--- /dev/null
+++ b/lib/libc/sys/setregid.2
@@ -0,0 +1,90 @@
+.\" Copyright (c) 1980, 1991, 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)setregid.2 8.2 (Berkeley) 4/16/94
+.\" $FreeBSD$
+.\"
+.Dd April 16, 1994
+.Dt SETREGID 2
+.Os
+.Sh NAME
+.Nm setregid
+.Nd set real and effective group ID
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft int
+.Fn setregid "gid_t rgid" "gid_t egid"
+.Sh DESCRIPTION
+The real and effective group ID's of the current process
+are set to the arguments.
+If the real group ID is changed, the saved group ID is changed to the
+new value of the effective group ID.
+.Pp
+Unprivileged users may change the real group
+ID to the effective group ID and vice-versa; only the super-user may
+make other changes.
+.Pp
+Supplying a value of -1 for either the real or effective
+group ID forces the system to substitute the current
+ID in place of the -1 argument.
+.Pp
+The
+.Fn setregid
+system call was intended to allow swapping
+the real and effective group IDs
+in set-group-ID programs to temporarily relinquish the set-group-ID value.
+This system call did not work correctly,
+and its purpose is now better served by the use of the
+.Xr setegid 2
+system call.
+.Pp
+When setting the real and effective group IDs to the same value,
+the standard
+.Fn setgid
+system call is preferred.
+.Sh RETURN VALUES
+.Rv -std setregid
+.Sh ERRORS
+.Bl -tag -width Er
+.It Bq Er EPERM
+The current process is not the super-user and a change
+other than changing the effective group-id to the real group-id
+was specified.
+.El
+.Sh SEE ALSO
+.Xr getgid 2 ,
+.Xr issetugid 2 ,
+.Xr setegid 2 ,
+.Xr setgid 2 ,
+.Xr setuid 2
+.Sh HISTORY
+The
+.Fn setregid
+system call appeared in
+.Bx 4.2 .
diff --git a/lib/libc/sys/setresuid.2 b/lib/libc/sys/setresuid.2
new file mode 100644
index 000000000000..602166f80c38
--- /dev/null
+++ b/lib/libc/sys/setresuid.2
@@ -0,0 +1,94 @@
+.\" Copyright (c) 2000
+.\" Sheldon Hearn. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES
+.\"
+.\" $FreeBSD$
+.\"
+.Dd February 7, 2015
+.Dt SETRESUID 2
+.Os
+.Sh NAME
+.Nm getresgid ,
+.Nm getresuid ,
+.Nm setresgid ,
+.Nm setresuid
+.Nd "get or set real, effective and saved user or group ID"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In unistd.h
+.Ft int
+.Fn getresgid "gid_t *rgid" "gid_t *egid" "gid_t *sgid"
+.Ft int
+.Fn getresuid "uid_t *ruid" "uid_t *euid" "uid_t *suid"
+.Ft int
+.Fn setresgid "gid_t rgid" "gid_t egid" "gid_t sgid"
+.Ft int
+.Fn setresuid "uid_t ruid" "uid_t euid" "uid_t suid"
+.Sh DESCRIPTION
+The
+.Fn setresuid
+system call sets the real,
+effective and saved user IDs of the current process.
+The analogous
+.Fn setresgid
+sets the real, effective and saved group IDs.
+.Pp
+Privileged processes may set these IDs
+to arbitrary values.
+Unprivileged processes are restricted
+in that each of the new IDs must match one of the current IDs.
+.Pp
+Passing -1 as an argument causes the corresponding value
+to remain unchanged.
+.Pp
+The
+.Fn getresgid
+and
+.Fn getresuid
+calls retrieve the real, effective, and saved group and user IDs of
+the current process, respectively.
+.Sh RETURN VALUES
+.Rv -std
+.Sh ERRORS
+.Bl -tag -width Er
+.It Bq Er EPERM
+The calling process was not privileged
+and tried to change one or more IDs to a value
+which was not the current real ID, the current effective ID
+nor the current saved ID.
+.It Bq Er EFAULT
+An address passed to
+.Fn getresgid
+or
+.Fn getresuid
+was invalid.
+.El
+.Sh SEE ALSO
+.Xr getegid 2 ,
+.Xr geteuid 2 ,
+.Xr getgid 2 ,
+.Xr getuid 2 ,
+.Xr issetugid 2 ,
+.Xr setgid 2 ,
+.Xr setregid 2 ,
+.Xr setreuid 2 ,
+.Xr setuid 2
+.Sh HISTORY
+These functions first appeared in HP-UX.
diff --git a/lib/libc/sys/setreuid.2 b/lib/libc/sys/setreuid.2
new file mode 100644
index 000000000000..2983820334c9
--- /dev/null
+++ b/lib/libc/sys/setreuid.2
@@ -0,0 +1,90 @@
+.\" Copyright (c) 1980, 1991, 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)setreuid.2 8.2 (Berkeley) 4/16/94
+.\" $FreeBSD$
+.\"
+.Dd February 8, 2001
+.Dt SETREUID 2
+.Os
+.Sh NAME
+.Nm setreuid
+.Nd set real and effective user ID's
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft int
+.Fn setreuid "uid_t ruid" "uid_t euid"
+.Sh DESCRIPTION
+The real and effective user IDs of the
+current process are set according to the arguments.
+If
+.Fa ruid
+or
+.Fa euid
+is -1, the current uid is filled in by the system.
+Unprivileged users may change the real user
+ID to the effective user ID and vice-versa; only the super-user may
+make other changes.
+.Pp
+If the real user ID is changed (i.e.\&
+.Fa ruid
+is not -1) or the effective user ID is changed to something other than
+the real user ID, then the saved user ID will be set to the effective user ID.
+.Pp
+The
+.Fn setreuid
+system call has been used to swap the real and effective user IDs
+in set-user-ID programs to temporarily relinquish the set-user-ID value.
+This purpose is now better served by the use of the
+.Xr seteuid 2
+system call.
+.Pp
+When setting the real and effective user IDs to the same value,
+the standard
+.Fn setuid
+system call is preferred.
+.Sh RETURN VALUES
+.Rv -std setreuid
+.Sh ERRORS
+.Bl -tag -width Er
+.It Bq Er EPERM
+The current process is not the super-user and a change
+other than changing the effective user-id to the real user-id
+was specified.
+.El
+.Sh SEE ALSO
+.Xr getuid 2 ,
+.Xr issetugid 2 ,
+.Xr seteuid 2 ,
+.Xr setuid 2
+.Sh HISTORY
+The
+.Fn setreuid
+system call appeared in
+.Bx 4.2 .
diff --git a/lib/libc/sys/setsid.2 b/lib/libc/sys/setsid.2
new file mode 100644
index 000000000000..a09a31ae715a
--- /dev/null
+++ b/lib/libc/sys/setsid.2
@@ -0,0 +1,81 @@
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)setsid.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt SETSID 2
+.Os
+.Sh NAME
+.Nm setsid
+.Nd create session and set process group ID
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft pid_t
+.Fn setsid void
+.Sh DESCRIPTION
+The
+.Fn setsid
+system call creates a new session.
+The calling process is the session leader of the new session, is the
+process group leader of a new process group and has no controlling
+terminal.
+The calling process is the only process in either the session or the
+process group.
+.Sh RETURN VALUES
+Upon successful completion, the
+.Fn setsid
+system call returns the value of the process group ID of the new process
+group, which is the same as the process ID of the calling process.
+If an error occurs,
+.Fn setsid
+returns -1 and the global variable
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+The
+.Fn setsid
+system call will fail if:
+.Bl -tag -width Er
+.It Bq Er EPERM
+The calling process is already a process group leader, or the process
+group ID of a process other than the calling process matches the process
+ID of the calling process.
+.El
+.Sh SEE ALSO
+.Xr setpgid 2 ,
+.Xr tcgetpgrp 3 ,
+.Xr tcsetpgrp 3
+.Sh STANDARDS
+The
+.Fn setsid
+system call is expected to be compliant with the
+.St -p1003.1-90
+specification.
diff --git a/lib/libc/sys/setuid.2 b/lib/libc/sys/setuid.2
new file mode 100644
index 000000000000..949d93633c03
--- /dev/null
+++ b/lib/libc/sys/setuid.2
@@ -0,0 +1,187 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)setuid.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd December 15, 2015
+.Dt SETUID 2
+.Os
+.Sh NAME
+.Nm setuid ,
+.Nm seteuid ,
+.Nm setgid ,
+.Nm setegid
+.Nd set user and group ID
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft int
+.Fn setuid "uid_t uid"
+.Ft int
+.Fn seteuid "uid_t euid"
+.Ft int
+.Fn setgid "gid_t gid"
+.Ft int
+.Fn setegid "gid_t egid"
+.Sh DESCRIPTION
+The
+.Fn setuid
+system call
+sets the real and effective
+user IDs and the saved set-user-ID of the current process
+to the specified value.
+.\" Comment out next block for !_POSIX_SAVED_IDS
+.\" The real user ID and the saved set-user-ID are changed only if the
+.\" effective user ID is that of the super user.
+.\" I.e.
+.\" .Fn setuid
+.\" system call is equal to
+.\" .Fn seteuid
+.\" system call if the effective user ID is not that of the super user.
+.\" End of block
+The
+.Fn setuid
+system call is permitted if the specified ID is equal to the real user ID
+.\" Comment out next line for !_POSIX_SAVED_IDS
+.\" or the saved set-user-ID
+.\" Next line is for Appendix B.4.2.2 case.
+or the effective user ID
+of the process, or if the effective user ID is that of the super user.
+.Pp
+The
+.Fn setgid
+system call
+sets the real and effective
+group IDs and the saved set-group-ID of the current process
+to the specified value.
+.\" Comment out next block for !_POSIX_SAVED_IDS
+.\" The real group ID and the saved set-group-ID are changed only if the
+.\" effective user ID is that of the super user.
+.\" I.e.
+.\" .Fn setgid
+.\" system call is equal to
+.\" .Fn setegid
+.\" system call if the effective user ID is not that of the super user.
+.\" End of block
+The
+.Fn setgid
+system call is permitted if the specified ID is equal to the real group ID
+.\" Comment out next line for !_POSIX_SAVED_IDS
+.\" or the saved set-group-ID
+.\" Next line is for Appendix B.4.2.2 case.
+or the effective group ID
+of the process, or if the effective user ID is that of the super user.
+.Pp
+The
+.Fn seteuid
+system call
+.Pq Fn setegid
+sets the effective user ID (group ID) of the
+current process.
+The effective user ID may be set to the value
+of the real user ID or the saved set-user-ID (see
+.Xr intro 2
+and
+.Xr execve 2 ) ;
+in this way, the effective user ID of a set-user-ID executable
+may be toggled by switching to the real user ID, then re-enabled
+by reverting to the set-user-ID value.
+Similarly, the effective group ID may be set to the value
+of the real group ID or the saved set-group-ID.
+.Sh RETURN VALUES
+.Rv -std
+.Sh ERRORS
+The system calls will fail if:
+.Bl -tag -width Er
+.It Bq Er EPERM
+The user is not the super user and the ID
+specified is not the real, effective ID, or saved ID.
+.El
+.Sh SEE ALSO
+.Xr getgid 2 ,
+.Xr getuid 2 ,
+.Xr issetugid 2 ,
+.Xr setregid 2 ,
+.Xr setreuid 2
+.Sh STANDARDS
+The
+.Fn setuid
+and
+.Fn setgid
+system calls are compliant with the
+.St -p1003.1-90
+specification with
+.Li _POSIX_SAVED_IDS
+.\" Uncomment next line for !_POSIX_SAVED_IDS
+not
+defined with the permitted extensions from Appendix B.4.2.2.
+The
+.Fn seteuid
+and
+.Fn setegid
+system calls are extensions based on the
+.Tn POSIX
+concept of
+.Li _POSIX_SAVED_IDS ,
+and have been proposed for a future revision of the standard.
+.Sh HISTORY
+The
+.Fn setuid
+and
+.Fn setgid
+functions appeared in
+.At v7 .
+.Sh SECURITY CONSIDERATIONS
+Read and write permissions to files are determined upon a call to
+.Xr open 2 .
+Once a file descriptor is open, dropping privilege does not affect
+the process's read/write permissions, even if the user ID specified
+has no read or write permissions to the file.
+These files normally remain open in any new process executed,
+resulting in a user being able to read or modify
+potentially sensitive data.
+.Pp
+To prevent these files from remaining open after an
+.Xr exec 3
+call, be sure to set the close-on-exec flag:
+.Bd -literal
+void
+pseudocode(void)
+{
+ int fd;
+ /* ... */
+
+ fd = open("/path/to/sensitive/data", O_RDWR | O_CLOEXEC);
+ if (fd == -1)
+ err(1, "open");
+
+ /* ... */
+ execve(path, argv, environ);
+}
+.Ed
diff --git a/lib/libc/sys/shm_open.2 b/lib/libc/sys/shm_open.2
new file mode 100644
index 000000000000..0855c076faf5
--- /dev/null
+++ b/lib/libc/sys/shm_open.2
@@ -0,0 +1,313 @@
+.\"
+.\" Copyright 2000 Massachusetts Institute of Technology
+.\"
+.\" Permission to use, copy, modify, and distribute this software and
+.\" its documentation for any purpose and without fee is hereby
+.\" granted, provided that both the above copyright notice and this
+.\" permission notice appear in all copies, that both the above
+.\" copyright notice and this permission notice appear in all
+.\" supporting documentation, and that the name of M.I.T. not be used
+.\" in advertising or publicity pertaining to distribution of the
+.\" software without specific, written prior permission. M.I.T. makes
+.\" no representations about the suitability of this software for any
+.\" purpose. It is provided "as is" without express or implied
+.\" warranty.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
+.\" ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
+.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
+.\" SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+.\" USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+.\" ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+.\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+.\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd January 20, 2017
+.Dt SHM_OPEN 2
+.Os
+.Sh NAME
+.Nm shm_open , shm_unlink
+.Nd "shared memory object operations"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/mman.h
+.In fcntl.h
+.Ft int
+.Fn shm_open "const char *path" "int flags" "mode_t mode"
+.Ft int
+.Fn shm_unlink "const char *path"
+.Sh DESCRIPTION
+The
+.Fn shm_open
+system call opens (or optionally creates) a
+.Tn POSIX
+shared memory object named
+.Fa path .
+The
+.Fa flags
+argument contains a subset of the flags used by
+.Xr open 2 .
+An access mode of either
+.Dv O_RDONLY
+or
+.Dv O_RDWR
+must be included in
+.Fa flags .
+The optional flags
+.Dv O_CREAT ,
+.Dv O_EXCL ,
+and
+.Dv O_TRUNC
+may also be specified.
+.Pp
+If
+.Dv O_CREAT
+is specified,
+then a new shared memory object named
+.Fa path
+will be created if it does not exist.
+In this case,
+the shared memory object is created with mode
+.Fa mode
+subject to the process' umask value.
+If both the
+.Dv O_CREAT
+and
+.Dv O_EXCL
+flags are specified and a shared memory object named
+.Fa path
+already exists,
+then
+.Fn shm_open
+will fail with
+.Er EEXIST .
+.Pp
+Newly created objects start off with a size of zero.
+If an existing shared memory object is opened with
+.Dv O_RDWR
+and the
+.Dv O_TRUNC
+flag is specified,
+then the shared memory object will be truncated to a size of zero.
+The size of the object can be adjusted via
+.Xr ftruncate 2
+and queried via
+.Xr fstat 2 .
+.Pp
+The new descriptor is set to close during
+.Xr execve 2
+system calls;
+see
+.Xr close 2
+and
+.Xr fcntl 2 .
+.Pp
+As a FreeBSD extension,
+the constant
+.Dv SHM_ANON
+may be used for the
+.Fa path
+argument to
+.Fn shm_open .
+In this case, an anonymous, unnamed shared memory object is created.
+Since the object has no name,
+it cannot be removed via a subsequent call to
+.Fn shm_unlink .
+Instead,
+the shared memory object will be garbage collected when the last reference to
+the shared memory object is removed.
+The shared memory object may be shared with other processes by sharing the
+file descriptor via
+.Xr fork 2
+or
+.Xr sendmsg 2 .
+Attempting to open an anonymous shared memory object with
+.Dv O_RDONLY
+will fail with
+.Er EINVAL .
+All other flags are ignored.
+.Pp
+The
+.Fn shm_unlink
+system call removes a shared memory object named
+.Fa path .
+.Sh RETURN VALUES
+If successful,
+.Fn shm_open
+returns a non-negative integer,
+and
+.Fn shm_unlink
+returns zero.
+Both functions return -1 on failure, and set
+.Va errno
+to indicate the error.
+.Sh COMPATIBILITY
+The
+.Fa path
+argument does not necessarily represent a pathname (although it does in
+most other implementations).
+Two processes opening the same
+.Fa path
+are guaranteed to access the same shared memory object if and only if
+.Fa path
+begins with a slash
+.Pq Ql \&/
+character.
+.Pp
+Only the
+.Dv O_RDONLY ,
+.Dv O_RDWR ,
+.Dv O_CREAT ,
+.Dv O_EXCL ,
+and
+.Dv O_TRUNC
+flags may be used in portable programs.
+.Pp
+.Tn POSIX
+specifications state that the result of using
+.Xr open 2 ,
+.Xr read 2 ,
+or
+.Xr write 2
+on a shared memory object, or on the descriptor returned by
+.Fn shm_open ,
+is undefined.
+However, the
+.Fx
+kernel implementation explicitly includes support for
+.Xr read 2
+and
+.Xr write 2 .
+.Pp
+.Fx
+also supports zero-copy transmission of data from shared memory
+objects with
+.Xr sendfile 2 .
+.Pp
+Neither shared memory objects nor their contents persist across reboots.
+.Pp
+Writes do not extend shared memory objects, so
+.Xr ftruncate 2
+must be called before any data can be written.
+See
+.Sx EXAMPLES .
+.Sh EXAMPLES
+This example fails without the call to
+.Xr ftruncate 2 :
+.Bd -literal -compact
+
+ uint8_t buffer[getpagesize()];
+ ssize_t len;
+ int fd;
+
+ fd = shm_open(SHM_ANON, O_RDWR | O_CREAT, 0600);
+ if (fd < 0)
+ err(EX_OSERR, "%s: shm_open", __func__);
+ if (ftruncate(fd, getpagesize()) < 0)
+ err(EX_IOERR, "%s: ftruncate", __func__);
+ len = pwrite(fd, buffer, getpagesize(), 0);
+ if (len < 0)
+ err(EX_IOERR, "%s: pwrite", __func__);
+ if (len != getpagesize())
+ errx(EX_IOERR, "%s: pwrite length mismatch", __func__);
+.Ed
+.Sh ERRORS
+.Fn shm_open
+fails with these error codes for these conditions:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+A flag other than
+.Dv O_RDONLY ,
+.Dv O_RDWR ,
+.Dv O_CREAT ,
+.Dv O_EXCL ,
+or
+.Dv O_TRUNC
+was included in
+.Fa flags .
+.It Bq Er EMFILE
+The process has already reached its limit for open file descriptors.
+.It Bq Er ENFILE
+The system file table is full.
+.It Bq Er EINVAL
+.Dv O_RDONLY
+was specified while creating an anonymous shared memory object via
+.Dv SHM_ANON .
+.It Bq Er EFAULT
+The
+.Fa path
+argument points outside the process' allocated address space.
+.It Bq Er ENAMETOOLONG
+The entire pathname exceeded 1023 characters.
+.It Bq Er EINVAL
+The
+.Fa path
+does not begin with a slash
+.Pq Ql \&/
+character.
+.It Bq Er ENOENT
+.Dv O_CREAT
+is specified and the named shared memory object does not exist.
+.It Bq Er EEXIST
+.Dv O_CREAT
+and
+.Dv O_EXCL
+are specified and the named shared memory object does exist.
+.It Bq Er EACCES
+The required permissions (for reading or reading and writing) are denied.
+.El
+.Pp
+.Fn shm_unlink
+fails with these error codes for these conditions:
+.Bl -tag -width Er
+.It Bq Er EFAULT
+The
+.Fa path
+argument points outside the process' allocated address space.
+.It Bq Er ENAMETOOLONG
+The entire pathname exceeded 1023 characters.
+.It Bq Er ENOENT
+The named shared memory object does not exist.
+.It Bq Er EACCES
+The required permissions are denied.
+.Fn shm_unlink
+requires write permission to the shared memory object.
+.El
+.Sh SEE ALSO
+.Xr close 2 ,
+.Xr fstat 2 ,
+.Xr ftruncate 2 ,
+.Xr mmap 2 ,
+.Xr munmap 2 ,
+.Xr sendfile 2
+.Sh STANDARDS
+The
+.Fn shm_open
+and
+.Fn shm_unlink
+functions are believed to conform to
+.St -p1003.1b-93 .
+.Sh HISTORY
+The
+.Fn shm_open
+and
+.Fn shm_unlink
+functions first appeared in
+.Fx 4.3 .
+The functions were reimplemented as system calls using shared memory objects
+directly rather than files in
+.Fx 8.0 .
+.Sh AUTHORS
+.An Garrett A. Wollman Aq Mt wollman@FreeBSD.org
+(C library support and this manual page)
+.Pp
+.An Matthew Dillon Aq Mt dillon@FreeBSD.org
+.Pq Dv MAP_NOSYNC
diff --git a/lib/libc/sys/shmat.2 b/lib/libc/sys/shmat.2
new file mode 100644
index 000000000000..fd1db932ce85
--- /dev/null
+++ b/lib/libc/sys/shmat.2
@@ -0,0 +1,122 @@
+.\"
+.\" Copyright (c) 1995 David Hovemeyer <daveho@infocom.com>
+.\"
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (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 August 2, 1995
+.Dt SHMAT 2
+.Os
+.Sh NAME
+.Nm shmat ,
+.Nm shmdt
+.Nd attach or detach shared memory
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/ipc.h
+.In sys/shm.h
+.Ft void *
+.Fn shmat "int shmid" "const void *addr" "int flag"
+.Ft int
+.Fn shmdt "const void *addr"
+.Sh DESCRIPTION
+The
+.Fn shmat
+system call
+attaches the shared memory segment identified by
+.Fa shmid
+to the calling process's address space.
+The address where the segment
+is attached is determined as follows:
+.\"
+.\" These are cribbed almost exactly from Stevens, _Advanced Programming in
+.\" the UNIX Environment_.
+.\"
+.Bl -bullet
+.It
+If
+.Fa addr
+is 0, the segment is attached at an address selected by the
+kernel.
+.It
+If
+.Fa addr
+is nonzero and SHM_RND is not specified in
+.Fa flag ,
+the segment is attached the specified address.
+.It
+If
+.Fa addr
+is specified and SHM_RND is specified,
+.Fa addr
+is rounded down to the nearest multiple of SHMLBA.
+.El
+.Pp
+The
+.Fn shmdt
+system call
+detaches the shared memory segment at the address specified by
+.Fa addr
+from the calling process's address space.
+.Sh RETURN VALUES
+Upon success,
+.Fn shmat
+returns the address where the segment is attached; otherwise, -1
+is returned and
+.Va errno
+is set to indicate the error.
+.Pp
+.Rv -std shmdt
+.Sh ERRORS
+The
+.Fn shmat
+system call
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+No shared memory segment was found corresponding to
+.Fa shmid .
+.It Bq Er EINVAL
+The
+.Fa addr
+argument
+was not an acceptable address.
+.El
+.Pp
+The
+.Fn shmdt
+system call
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa addr
+argument
+does not point to a shared memory segment.
+.El
+.Sh "SEE ALSO"
+.Xr shmctl 2 ,
+.Xr shmget 2
diff --git a/lib/libc/sys/shmctl.2 b/lib/libc/sys/shmctl.2
new file mode 100644
index 000000000000..788e79f1900d
--- /dev/null
+++ b/lib/libc/sys/shmctl.2
@@ -0,0 +1,141 @@
+.\"
+.\" Copyright (c) 1995 David Hovemeyer <daveho@infocom.com>
+.\"
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd October 10, 2015
+.Dt SHMCTL 2
+.Os
+.Sh NAME
+.Nm shmctl
+.Nd shared memory control
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/ipc.h
+.In sys/shm.h
+.Ft int
+.Fn shmctl "int shmid" "int cmd" "struct shmid_ds *buf"
+.Sh DESCRIPTION
+Performs the action specified by
+.Fa cmd
+on the shared memory segment identified by
+.Fa shmid :
+.Bl -tag -width SHM_UNLOCKX
+.It Dv IPC_STAT
+Fetch the segment's
+.Fa "struct shmid_ds" ,
+storing it in the memory pointed to by
+.Fa buf .
+.\"
+.\" XXX need to make sure that this is correct for FreeBSD
+.\"
+.It Dv IPC_SET
+Changes the
+.Fa shm_perm.uid ,
+.Fa shm_perm.gid ,
+and
+.Fa shm_perm.mode
+members of the segment's
+.Fa "struct shmid_ds"
+to match those of the struct pointed to by
+.Fa buf .
+The calling process's effective uid must
+match either
+.Fa shm_perm.uid
+or
+.Fa shm_perm.cuid ,
+or it must have superuser privileges.
+.It Dv IPC_RMID
+Removes the segment from the system.
+The removal will not take
+effect until all processes having attached the segment have exited.
+For the operation
+to succeed, the calling process's effective uid must match
+.Fa shm_perm.uid
+or
+.Fa shm_perm.cuid ,
+or the process must have superuser privileges.
+If the
+.Va kern.ipc.shm_allow_removed
+.Xr sysctl 3
+variable is set to 0, once the IPC_RMID operation has taken place,
+no further processes will be allowed to attach the segment.
+.\" .It Dv SHM_LOCK
+.\" Locks the segment in memory. The calling process must have
+.\" superuser privileges. Not implemented in FreeBSD.
+.\" .It Dv SHM_UNLOCK
+.\" Unlocks the segment from memory. The calling process must
+.\" have superuser privileges. Not implemented in FreeBSD.
+.El
+.Pp
+The
+.Vt shmid_ds
+structure is defined as follows:
+.\"
+.\" I fiddled with the spaces a bit to make it fit well when viewed
+.\" with nroff, but otherwise it is straight from sys/shm.h
+.\"
+.Bd -literal
+struct shmid_ds {
+ struct ipc_perm shm_perm; /* operation permission structure */
+ size_t shm_segsz; /* size of segment in bytes */
+ pid_t shm_lpid; /* process ID of last shared memory op */
+ pid_t shm_cpid; /* process ID of creator */
+ int shm_nattch; /* number of current attaches */
+ time_t shm_atime; /* time of last shmat() */
+ time_t shm_dtime; /* time of last shmdt() */
+ time_t shm_ctime; /* time of last change by shmctl() */
+};
+.Ed
+.Sh RETURN VALUES
+.Rv -std shmctl
+.Sh ERRORS
+The
+.Fn shmctl
+system call
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Invalid operation, or
+no shared memory segment was found corresponding to
+.Fa shmid .
+.\"
+.\" XXX I think the following is right: ipcperm() only returns EPERM
+.\" when an attempt is made to modify (IPC_M) by a non-creator
+.\" non-owner
+.It Bq Er EPERM
+The calling process's effective uid does not match the uid of
+the shared memory segment's owner or creator.
+.It Bq Er EACCES
+Permission denied due to mismatch between operation and mode of
+shared memory segment.
+.El
+.Sh "SEE ALSO"
+.Xr shmat 2 ,
+.Xr shmdt 2 ,
+.Xr shmget 2 ,
+.Xr ftok 3
diff --git a/lib/libc/sys/shmget.2 b/lib/libc/sys/shmget.2
new file mode 100644
index 000000000000..309434553162
--- /dev/null
+++ b/lib/libc/sys/shmget.2
@@ -0,0 +1,146 @@
+.\"
+.\" Copyright (c) 1995 David Hovemeyer <daveho@infocom.com>
+.\"
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd December 17, 2010
+.Dt SHMGET 2
+.Os
+.Sh NAME
+.Nm shmget
+.Nd obtain a shared memory identifier
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/ipc.h
+.In sys/shm.h
+.Ft int
+.Fn shmget "key_t key" "size_t size" "int flag"
+.Sh DESCRIPTION
+Based on the values of
+.Fa key
+and
+.Fa flag ,
+.Fn shmget
+returns the identifier of a newly created or previously existing shared
+memory segment.
+.\"
+.\" The following bit about keys and modes also applies to semaphores
+.\" and message queues.
+.\"
+The key
+is analogous to a filename: it provides a handle that names an
+IPC object.
+There are three ways to specify a key:
+.Bl -bullet
+.It
+IPC_PRIVATE may be specified, in which case a new IPC object
+will be created.
+.It
+An integer constant may be specified.
+If no IPC object corresponding
+to
+.Fa key
+is specified and the IPC_CREAT bit is set in
+.Fa flag ,
+a new one will be created.
+.It
+The
+.Xr ftok 3
+may be used to generate a key from a pathname.
+.El
+.Pp
+The mode of a newly created IPC object is determined by
+.Em OR Ns 'ing
+the following constants into the
+.Fa flag
+argument:
+.Bl -tag -width XSHM_WXX6XXX
+.It Dv S_IRUSR
+Read access for owner.
+.It Dv S_IWUSR
+Write access for owner.
+.It Dv S_IRGRP
+Read access for group.
+.It Dv S_IWGRP
+Write access for group.
+.It Dv S_IROTH
+Read access for other.
+.It Dv S_IWOTH
+Write access for other.
+.El
+.\"
+.\" XXX - we should also mention how uid, euid, and gid affect ownership
+.\" and use
+.\"
+.\" end section about keys and modes
+.\"
+.Pp
+When creating a new shared memory segment,
+.Fa size
+indicates the desired size of the new segment in bytes.
+The size
+of the segment may be rounded up to a multiple convenient to the
+kernel (i.e., the page size).
+.Sh RETURN VALUES
+Upon successful completion,
+.Fn shmget
+returns the positive integer identifier of a shared memory segment.
+Otherwise, -1 is returned and
+.Va errno
+set to indicate the error.
+.Sh ERRORS
+The
+.Fn shmget
+system call
+will fail if:
+.Bl -tag -width Er
+.\"
+.\" XXX What about ipcperm failing?
+.\"
+.It Bq Er EINVAL
+Size specified is greater than the size of the previously existing segment.
+Size specified is less than the system imposed minimum, or greater than
+the system imposed maximum.
+.It Bq Er ENOENT
+No shared memory segment was found matching
+.Fa key ,
+and IPC_CREAT was not specified.
+.It Bq Er ENOSPC
+The kernel was unable to allocate enough memory to
+satisfy the request.
+.It Bq Er EEXIST
+IPC_CREAT and IPC_EXCL were specified, and a shared memory segment
+corresponding to
+.Fa key
+already exists.
+.El
+.Sh "SEE ALSO"
+.Xr shmat 2 ,
+.Xr shmctl 2 ,
+.Xr shmdt 2 ,
+.Xr stat 2 ,
+.Xr ftok 3
diff --git a/lib/libc/sys/shutdown.2 b/lib/libc/sys/shutdown.2
new file mode 100644
index 000000000000..35c464e9fe2e
--- /dev/null
+++ b/lib/libc/sys/shutdown.2
@@ -0,0 +1,171 @@
+.\" Copyright (c) 2007 Bruce M. Simpson.
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)shutdown.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd July 27, 2015
+.Dt SHUTDOWN 2
+.Os
+.Sh NAME
+.Nm shutdown
+.Nd disable sends and/or receives on a socket
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/socket.h
+.Ft int
+.Fn shutdown "int s" "int how"
+.Sh DESCRIPTION
+The
+.Fn shutdown
+system call disables sends or receives on a socket.
+The
+.Fa how
+argument specifies the type of shutdown.
+Possible values are:
+.Bl -tag -width ".Dv SHUT_RDWR"
+.It Dv SHUT_RD
+Further receives will be disallowed.
+.It Dv SHUT_WR
+Further sends will be disallowed.
+This may cause actions specific to the protocol family of the socket
+.Fa s
+to happen; see
+.Sx IMPLEMENTATION NOTES .
+.It Dv SHUT_RDWR
+Further sends and receives will be disallowed.
+Implies
+.Dv SHUT_WR .
+.El
+.Pp
+If the file descriptor
+.Fa s
+is associated with a
+.Dv SOCK_STREAM
+socket, all or part of the full-duplex connection will be shut down.
+.\"
+.Sh IMPLEMENTATION NOTES
+The following protocol specific actions apply to the use of
+.Dv SHUT_WR
+(and potentially also
+.Dv SHUT_RDWR ) ,
+based on the properties of the socket associated with the file descriptor
+.Fa s .
+.Bl -column ".Dv PF_INET6" ".Dv SOCK_STREAM" ".Dv IPPROTO_SCTP"
+.It Sy Domain Ta Sy Type Ta Sy Protocol Ta Sy Action
+.It Dv PF_INET Ta Dv SOCK_DGRAM Ta Dv IPPROTO_SCTP Ta
+Failure,
+as socket is not connected.
+.It Dv PF_INET Ta Dv SOCK_DGRAM Ta Dv IPPROTO_UDP Ta
+Failure,
+as socket is not connected.
+.It Dv PF_INET Ta Dv SOCK_STREAM Ta Dv IPPROTO_SCTP Ta
+Send queued data and tear down association.
+.It Dv PF_INET Ta Dv SOCK_STREAM Ta Dv IPPROTO_TCP Ta
+Send queued data, wait for ACK, then send FIN.
+.It Dv PF_INET6 Ta Dv SOCK_DGRAM Ta Dv IPPROTO_SCTP Ta
+Failure,
+as socket is not connected.
+.It Dv PF_INET6 Ta Dv SOCK_DGRAM Ta Dv IPPROTO_UDP Ta
+Failure,
+as socket is not connected.
+.It Dv PF_INET6 Ta Dv SOCK_STREAM Ta Dv IPPROTO_SCTP Ta
+Send queued data and tear down association.
+.It Dv PF_INET6 Ta Dv SOCK_STREAM Ta Dv IPPROTO_TCP Ta
+Send queued data, wait for ACK, then send FIN.
+.El
+.\"
+.Sh RETURN VALUES
+.Rv -std shutdown
+.Sh ERRORS
+The
+.Fn shutdown
+system call fails if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa s
+argument is not a valid file descriptor.
+.It Bq Er EINVAL
+The
+.Fa how
+argument is invalid.
+.It Bq Er ENOTCONN
+The
+.Fa s
+argument specifies a socket which is not connected.
+.It Bq Er ENOTSOCK
+The
+.Fa s
+argument does not refer to a socket.
+.El
+.Sh SEE ALSO
+.Xr connect 2 ,
+.Xr socket 2 ,
+.Xr inet 4 ,
+.Xr inet6 4
+.Sh STANDARDS
+The
+.Fn shutdown
+system call is expected to comply with
+.St -p1003.1g-2000 ,
+when finalized.
+.Sh HISTORY
+The
+.Fn shutdown
+system call appeared in
+.Bx 4.2 .
+The
+.Dv SHUT_RD , SHUT_WR ,
+and
+.Dv SHUT_RDWR
+constants appeared in
+.St -p1003.1g-2000 .
+.Sh AUTHORS
+.An -nosplit
+This manual page was updated by
+.An Bruce M. Simpson Aq Mt bms@FreeBSD.org
+to reflect how
+.Fn shutdown
+behaves with
+.Dv PF_INET
+and
+.Dv PF_INET6
+sockets.
+.Sh BUGS
+The ICMP
+.Dq Li "port unreachable"
+message should be generated in response to
+datagrams received on a local port to which
+.Fa s
+is bound
+after
+.Fn shutdown
+is called.
diff --git a/lib/libc/sys/sigaction.2 b/lib/libc/sys/sigaction.2
new file mode 100644
index 000000000000..00d8215d7b1d
--- /dev/null
+++ b/lib/libc/sys/sigaction.2
@@ -0,0 +1,791 @@
+.\" Copyright (c) 1980, 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.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" From: @(#)sigaction.2 8.2 (Berkeley) 4/3/94
+.\" $FreeBSD$
+.\"
+.Dd September 30, 2016
+.Dt SIGACTION 2
+.Os
+.Sh NAME
+.Nm sigaction
+.Nd software signal facilities
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In signal.h
+.Bd -literal
+struct sigaction {
+ void (*sa_handler)(int);
+ void (*sa_sigaction)(int, siginfo_t *, void *);
+ int sa_flags; /* see signal options below */
+ sigset_t sa_mask; /* signal mask to apply */
+};
+.Ed
+.Ft int
+.Fo sigaction
+.Fa "int sig"
+.Fa "const struct sigaction * restrict act"
+.Fa "struct sigaction * restrict oact"
+.Fc
+.Sh DESCRIPTION
+The system defines a set of signals that may be delivered to a process.
+Signal delivery resembles the occurrence of a hardware interrupt:
+the signal is normally blocked from further occurrence, the current thread
+context is saved, and a new one is built.
+A process may specify a
+.Em handler
+to which a signal is delivered, or specify that a signal is to be
+.Em ignored .
+A process may also specify that a default action is to be taken
+by the system when a signal occurs.
+A signal may also be
+.Em blocked
+for a thread,
+in which case it will not be delivered to that thread until it is
+.Em unblocked .
+The action to be taken on delivery is determined at the time
+of delivery.
+Normally, signal handlers execute on the current stack
+of the thread.
+This may be changed, on a per-handler basis,
+so that signals are taken on a special
+.Em "signal stack" .
+.Pp
+Signal routines normally execute with the signal that caused their
+invocation
+.Em blocked ,
+but other signals may yet occur.
+A global
+.Em "signal mask"
+defines the set of signals currently blocked from delivery
+to a thread.
+The signal mask for a thread is initialized
+from that of its parent (normally empty).
+It may be changed with a
+.Xr sigprocmask 2
+or
+.Xr pthread_sigmask 3
+call, or when a signal is delivered to the thread.
+.Pp
+When a signal
+condition arises for a process or thread, the signal is added to a set of
+signals pending for the process or thread.
+Whether the signal is directed at the process in general or at a specific
+thread depends on how it is generated.
+For signals directed at a specific thread,
+if the signal is not currently
+.Em blocked
+by the thread then it is delivered to the thread.
+For signals directed at the process,
+if the signal is not currently
+.Em blocked
+by all threads then it is delivered to one thread that does not have it blocked
+(the selection of which is unspecified).
+Signals may be delivered any time a thread enters the operating system
+(e.g., during a system call, page fault or trap, or clock interrupt).
+If multiple signals are ready to be delivered at the same time,
+any signals that could be caused by traps are delivered first.
+Additional signals may be processed at the same time, with each
+appearing to interrupt the handlers for the previous signals
+before their first instructions.
+The set of pending signals is returned by the
+.Xr sigpending 2
+system call.
+When a caught signal
+is delivered, the current state of the thread is saved,
+a new signal mask is calculated (as described below),
+and the signal handler is invoked.
+The call to the handler
+is arranged so that if the signal handling routine returns
+normally the thread will resume execution in the context
+from before the signal's delivery.
+If the thread wishes to resume in a different context, then it
+must arrange to restore the previous context itself.
+.Pp
+When a signal is delivered to a thread a new signal mask is
+installed for the duration of the process' signal handler
+(or until a
+.Xr sigprocmask 2
+system call is made).
+This mask is formed by taking the union of the current signal mask set,
+the signal to be delivered, and
+the signal mask associated with the handler to be invoked.
+.Pp
+The
+.Fn sigaction
+system call
+assigns an action for a signal specified by
+.Fa sig .
+If
+.Fa act
+is non-zero, it
+specifies an action
+.Dv ( SIG_DFL ,
+.Dv SIG_IGN ,
+or a handler routine) and mask
+to be used when delivering the specified signal.
+If
+.Fa oact
+is non-zero, the previous handling information for the signal
+is returned to the user.
+.Pp
+The above declaration of
+.Vt "struct sigaction"
+is not literal.
+It is provided only to list the accessible members.
+See
+.In sys/signal.h
+for the actual definition.
+In particular, the storage occupied by sa_handler and sa_sigaction overlaps,
+and an application can not use both simultaneously.
+.Pp
+Once a signal handler is installed, it normally remains installed
+until another
+.Fn sigaction
+system call is made, or an
+.Xr execve 2
+is performed.
+A signal-specific default action may be reset by
+setting
+.Va sa_handler
+to
+.Dv SIG_DFL .
+The defaults are process termination, possibly with core dump;
+no action; stopping the process; or continuing the process.
+See the signal list below for each signal's default action.
+If
+.Va sa_handler
+is
+.Dv SIG_DFL ,
+the default action for the signal is to discard the signal,
+and if a signal is pending,
+the pending signal is discarded even if the signal is masked.
+If
+.Va sa_handler
+is set to
+.Dv SIG_IGN
+current and pending instances
+of the signal are ignored and discarded.
+.Pp
+Options may be specified by setting
+.Va sa_flags .
+The meaning of the various bits is as follows:
+.Bl -tag -offset indent -width SA_RESETHANDXX
+.It Dv SA_NOCLDSTOP
+If this bit is set when installing a catching function
+for the
+.Dv SIGCHLD
+signal,
+the
+.Dv SIGCHLD
+signal will be generated only when a child process exits,
+not when a child process stops.
+.It Dv SA_NOCLDWAIT
+If this bit is set when calling
+.Fn sigaction
+for the
+.Dv SIGCHLD
+signal, the system will not create zombie processes when children of
+the calling process exit.
+If the calling process subsequently issues a
+.Xr wait 2
+(or equivalent), it blocks until all of the calling process's child
+processes terminate, and then returns a value of \-1 with
+.Va errno
+set to
+.Er ECHILD .
+The same effect of avoiding zombie creation can also be achieved by setting
+.Va sa_handler
+for
+.Dv SIGCHLD
+to
+.Dv SIG_IGN .
+.It Dv SA_ONSTACK
+If this bit is set, the system will deliver the signal to the process
+on a
+.Em "signal stack" ,
+specified by each thread with
+.Xr sigaltstack 2 .
+.It Dv SA_NODEFER
+If this bit is set, further occurrences of the delivered signal are
+not masked during the execution of the handler.
+.It Dv SA_RESETHAND
+If this bit is set, the handler is reset back to
+.Dv SIG_DFL
+at the moment the signal is delivered.
+.It Dv SA_RESTART
+See paragraph below.
+.It Dv SA_SIGINFO
+If this bit is set, the handler function is assumed to be pointed to by the
+.Va sa_sigaction
+member of
+.Vt "struct sigaction"
+and should match the prototype shown above or as below in
+.Sx EXAMPLES .
+This bit should not be set when assigning
+.Dv SIG_DFL
+or
+.Dv SIG_IGN .
+.El
+.Pp
+If a signal is caught during the system calls listed below,
+the call may be forced to terminate
+with the error
+.Er EINTR ,
+the call may return with a data transfer shorter than requested,
+or the call may be restarted.
+Restart of pending calls is requested
+by setting the
+.Dv SA_RESTART
+bit in
+.Va sa_flags .
+The affected system calls include
+.Xr open 2 ,
+.Xr read 2 ,
+.Xr write 2 ,
+.Xr sendto 2 ,
+.Xr recvfrom 2 ,
+.Xr sendmsg 2
+and
+.Xr recvmsg 2
+on a communications channel or a slow device (such as a terminal,
+but not a regular file)
+and during a
+.Xr wait 2
+or
+.Xr ioctl 2 .
+However, calls that have already committed are not restarted,
+but instead return a partial success (for example, a short read count).
+.Pp
+After a
+.Xr pthread_create 3
+the signal mask is inherited by the new thread and
+the set of pending signals and the signal stack for the new thread are empty.
+.Pp
+After a
+.Xr fork 2
+or
+.Xr vfork 2
+all signals, the signal mask, the signal stack,
+and the restart/interrupt flags are inherited by the child.
+.Pp
+The
+.Xr execve 2
+system call reinstates the default
+action for all signals which were caught and
+resets all signals to be caught on the user stack.
+Ignored signals remain ignored;
+the signal mask remains the same;
+signals that restart pending system calls continue to do so.
+.Pp
+The following is a list of all signals
+with names as in the include file
+.In signal.h :
+.Bl -column SIGVTALARMXX "create core imagexxx"
+.It Sy NAME Ta Sy Default Action Ta Sy Description
+.It Dv SIGHUP Ta terminate process Ta terminal line hangup
+.It Dv SIGINT Ta terminate process Ta interrupt program
+.It Dv SIGQUIT Ta create core image Ta quit program
+.It Dv SIGILL Ta create core image Ta illegal instruction
+.It Dv SIGTRAP Ta create core image Ta trace trap
+.It Dv SIGABRT Ta create core image Ta Xr abort 3 call (formerly Dv SIGIOT )
+.It Dv SIGEMT Ta create core image Ta emulate instruction executed
+.It Dv SIGFPE Ta create core image Ta floating-point exception
+.It Dv SIGKILL Ta terminate process Ta kill program
+.It Dv SIGBUS Ta create core image Ta bus error
+.It Dv SIGSEGV Ta create core image Ta segmentation violation
+.It Dv SIGSYS Ta create core image Ta non-existent system call invoked
+.It Dv SIGPIPE Ta terminate process Ta write on a pipe with no reader
+.It Dv SIGALRM Ta terminate process Ta real-time timer expired
+.It Dv SIGTERM Ta terminate process Ta software termination signal
+.It Dv SIGURG Ta discard signal Ta urgent condition present on socket
+.It Dv SIGSTOP Ta stop process Ta stop (cannot be caught or ignored)
+.It Dv SIGTSTP Ta stop process Ta stop signal generated from keyboard
+.It Dv SIGCONT Ta discard signal Ta continue after stop
+.It Dv SIGCHLD Ta discard signal Ta child status has changed
+.It Dv SIGTTIN Ta stop process Ta background read attempted from control terminal
+.It Dv SIGTTOU Ta stop process Ta background write attempted to control terminal
+.It Dv SIGIO Ta discard signal Ta I/O is possible on a descriptor (see Xr fcntl 2 )
+.It Dv SIGXCPU Ta terminate process Ta cpu time limit exceeded (see Xr setrlimit 2 )
+.It Dv SIGXFSZ Ta terminate process Ta file size limit exceeded (see Xr setrlimit 2 )
+.It Dv SIGVTALRM Ta terminate process Ta virtual time alarm (see Xr setitimer 2 )
+.It Dv SIGPROF Ta terminate process Ta profiling timer alarm (see Xr setitimer 2 )
+.It Dv SIGWINCH Ta discard signal Ta window size change
+.It Dv SIGINFO Ta discard signal Ta status request from keyboard
+.It Dv SIGUSR1 Ta terminate process Ta user defined signal 1
+.It Dv SIGUSR2 Ta terminate process Ta user defined signal 2
+.El
+.Sh NOTE
+The
+.Va sa_mask
+field specified in
+.Fa act
+is not allowed to block
+.Dv SIGKILL
+or
+.Dv SIGSTOP .
+Any attempt to do so will be silently ignored.
+.Pp
+The following functions are either reentrant or not interruptible
+by signals and are async-signal safe.
+Therefore applications may
+invoke them, without restriction, from signal-catching functions
+or from a child process after calling
+.Xr fork 2
+in a multi-threaded process:
+.Pp
+Base Interfaces:
+.Pp
+.Fn _Exit ,
+.Fn _exit ,
+.Fn accept ,
+.Fn access ,
+.Fn alarm ,
+.Fn bind ,
+.Fn cfgetispeed ,
+.Fn cfgetospeed ,
+.Fn cfsetispeed ,
+.Fn cfsetospeed ,
+.Fn chdir ,
+.Fn chmod ,
+.Fn chown ,
+.Fn close ,
+.Fn connect ,
+.Fn creat ,
+.Fn dup ,
+.Fn dup2 ,
+.Fn execl ,
+.Fn execle ,
+.Fn execv ,
+.Fn execve ,
+.Fn faccessat ,
+.Fn fchdir ,
+.Fn fchmod ,
+.Fn fchmodat ,
+.Fn fchown ,
+.Fn fchownat ,
+.Fn fcntl ,
+.Fn fork ,
+.Fn fstat ,
+.Fn fstatat ,
+.Fn fsync ,
+.Fn ftruncate ,
+.Fn getegid ,
+.Fn geteuid ,
+.Fn getgid ,
+.Fn getgroups ,
+.Fn getpeername ,
+.Fn getpgrp ,
+.Fn getpid ,
+.Fn getppid ,
+.Fn getsockname ,
+.Fn getsockopt ,
+.Fn getuid ,
+.Fn kill ,
+.Fn link ,
+.Fn linkat ,
+.Fn listen ,
+.Fn lseek ,
+.Fn lstat ,
+.Fn mkdir ,
+.Fn mkdirat ,
+.Fn mkfifo ,
+.Fn mkfifoat ,
+.Fn mknod ,
+.Fn mknodat ,
+.Fn open ,
+.Fn openat ,
+.Fn pause ,
+.Fn pipe ,
+.Fn poll ,
+.Fn pselect ,
+.Fn pthread_sigmask ,
+.Fn raise ,
+.Fn read ,
+.Fn readlink ,
+.Fn readlinkat ,
+.Fn recv ,
+.Fn recvfrom ,
+.Fn recvmsg ,
+.Fn rename ,
+.Fn renameat ,
+.Fn rmdir ,
+.Fn select ,
+.Fn send ,
+.Fn sendmsg ,
+.Fn sendto ,
+.Fn setgid ,
+.Fn setpgid ,
+.Fn setsid ,
+.Fn setsockopt ,
+.Fn setuid ,
+.Fn shutdown ,
+.Fn sigaction ,
+.Fn sigaddset ,
+.Fn sigdelset ,
+.Fn sigemptyset ,
+.Fn sigfillset ,
+.Fn sigismember ,
+.Fn signal ,
+.Fn sigpending ,
+.Fn sigprocmask ,
+.Fn sigsuspend ,
+.Fn sleep ,
+.Fn sockatmark ,
+.Fn socket ,
+.Fn socketpair ,
+.Fn stat ,
+.Fn symlink ,
+.Fn symlinkat ,
+.Fn tcdrain ,
+.Fn tcflow ,
+.Fn tcflush ,
+.Fn tcgetattr ,
+.Fn tcgetpgrp ,
+.Fn tcsendbreak ,
+.Fn tcsetattr ,
+.Fn tcsetpgrp ,
+.Fn time ,
+.Fn times ,
+.Fn umask ,
+.Fn uname ,
+.Fn unlink ,
+.Fn unlinkat ,
+.Fn utime ,
+.Fn wait ,
+.Fn waitpid ,
+.Fn write .
+.Pp
+X/Open Systems Interfaces:
+.Pp
+.Fn sigpause ,
+.Fn sigset ,
+.Fn utimes .
+.Pp
+Realtime Interfaces:
+.Pp
+.Fn aio_error ,
+.Fn clock_gettime ,
+.Fn timer_getoverrun ,
+.Fn aio_return ,
+.Fn fdatasync ,
+.Fn sigqueue ,
+.Fn timer_gettime ,
+.Fn aio_suspend ,
+.Fn sem_post ,
+.Fn timer_settime .
+.Pp
+Base Interfaces not specified as async-signal safe by
+.Tn POSIX :
+.Pp
+.Fn fpathconf ,
+.Fn pathconf ,
+.Fn sysconf .
+.Pp
+Base Interfaces not specified as async-signal safe by
+.Tn POSIX ,
+but planned to be:
+.Pp
+.Fn ffs ,
+.Fn htonl ,
+.Fn htons ,
+.Fn memccpy ,
+.Fn memchr ,
+.Fn memcmp ,
+.Fn memcpy ,
+.Fn memmove ,
+.Fn memset ,
+.Fn ntohl ,
+.Fn ntohs ,
+.Fn stpcpy ,
+.Fn stpncpy ,
+.Fn strcat ,
+.Fn strchr ,
+.Fn strcmp ,
+.Fn strcpy ,
+.Fn strcspn ,
+.Fn strlen ,
+.Fn strncat ,
+.Fn strncmp ,
+.Fn strncpy ,
+.Fn strnlen ,
+.Fn strpbrk ,
+.Fn strrchr ,
+.Fn strspn ,
+.Fn strstr ,
+.Fn strtok_r ,
+.Fn wcpcpy ,
+.Fn wcpncpy ,
+.Fn wcscat ,
+.Fn wcschr ,
+.Fn wcscmp ,
+.Fn wcscpy ,
+.Fn wcscspn ,
+.Fn wcslen ,
+.Fn wcsncat ,
+.Fn wcsncmp ,
+.Fn wcsncpy ,
+.Fn wcsnlen ,
+.Fn wcspbrk ,
+.Fn wcsrchr ,
+.Fn wcsspn ,
+.Fn wcsstr ,
+.Fn wcstok ,
+.Fn wmemchr ,
+.Fn wmemcmp ,
+.Fn wmemcpy ,
+.Fn wmemmove ,
+.Fn wmemset .
+.Pp
+Extension Interfaces:
+.Pp
+.Fn accept4 ,
+.Fn bindat ,
+.Fn closefrom ,
+.Fn connectat ,
+.Fn eaccess ,
+.Fn ffsl ,
+.Fn ffsll ,
+.Fn flock ,
+.Fn fls ,
+.Fn flsl ,
+.Fn flsll ,
+.Fn futimesat ,
+.Fn pipe2 ,
+.Fn strlcat .
+.Fn strlcpy ,
+.Fn strsep .
+.Pp
+In addition, reading or writing
+.Va errno
+is async-signal safe.
+.Pp
+All functions not in the above lists are considered to be unsafe
+with respect to signals.
+That is to say, the behaviour of such
+functions is undefined when they are called from a signal handler
+that interrupted an unsafe function.
+In general though, signal handlers should do little more than set a
+flag; most other actions are not safe.
+.Pp
+Also, it is good practice to make a copy of the global variable
+.Va errno
+and restore it before returning from the signal handler.
+This protects against the side effect of
+.Va errno
+being set by functions called from inside the signal handler.
+.Sh RETURN VALUES
+.Rv -std sigaction
+.Sh EXAMPLES
+There are three possible prototypes the handler may match:
+.Bl -tag -offset indent -width short
+.It Tn ANSI C :
+.Ft void
+.Fn handler int ;
+.It Traditional BSD style:
+.Ft void
+.Fn handler int "int code" "struct sigcontext *scp" ;
+.It Tn POSIX Dv SA_SIGINFO :
+.Ft void
+.Fn handler int "siginfo_t *info" "ucontext_t *uap" ;
+.El
+.Pp
+The handler function should match the
+.Dv SA_SIGINFO
+prototype if the
+.Dv SA_SIGINFO
+bit is set in
+.Va sa_flags .
+It then should be pointed to by the
+.Va sa_sigaction
+member of
+.Vt "struct sigaction" .
+Note that you should not assign
+.Dv SIG_DFL
+or
+.Dv SIG_IGN
+this way.
+.Pp
+If the
+.Dv SA_SIGINFO
+flag is not set, the handler function should match
+either the
+.Tn ANSI C
+or traditional
+.Bx
+prototype and be pointed to by
+the
+.Va sa_handler
+member of
+.Vt "struct sigaction" .
+In practice,
+.Fx
+always sends the three arguments of the latter and since the
+.Tn ANSI C
+prototype is a subset, both will work.
+The
+.Va sa_handler
+member declaration in
+.Fx
+include files is that of
+.Tn ANSI C
+(as required by
+.Tn POSIX ) ,
+so a function pointer of a
+.Bx Ns -style
+function needs to be casted to
+compile without warning.
+The traditional
+.Bx
+style is not portable and since its capabilities
+are a full subset of a
+.Dv SA_SIGINFO
+handler,
+its use is deprecated.
+.Pp
+The
+.Fa sig
+argument is the signal number, one of the
+.Dv SIG...
+values from
+.In signal.h .
+.Pp
+The
+.Fa code
+argument of the
+.Bx Ns -style
+handler and the
+.Va si_code
+member of the
+.Fa info
+argument to a
+.Dv SA_SIGINFO
+handler contain a numeric code explaining the
+cause of the signal, usually one of the
+.Dv SI_...
+values from
+.In sys/signal.h
+or codes specific to a signal, i.e., one of the
+.Dv FPE_...
+values for
+.Dv SIGFPE .
+.Pp
+The
+.Fa scp
+argument to a
+.Bx Ns -style
+handler points to an instance of
+.Vt "struct sigcontext" .
+.Pp
+The
+.Fa uap
+argument to a
+.Tn POSIX
+.Dv SA_SIGINFO
+handler points to an instance of
+ucontext_t.
+.Sh ERRORS
+The
+.Fn sigaction
+system call
+will fail and no new signal handler will be installed if one
+of the following occurs:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa sig
+argument
+is not a valid signal number.
+.It Bq Er EINVAL
+An attempt is made to ignore or supply a handler for
+.Dv SIGKILL
+or
+.Dv SIGSTOP .
+.El
+.Sh SEE ALSO
+.Xr kill 1 ,
+.Xr kill 2 ,
+.Xr ptrace 2 ,
+.Xr setitimer 2 ,
+.Xr setrlimit 2 ,
+.Xr sigaltstack 2 ,
+.Xr sigpending 2 ,
+.Xr sigprocmask 2 ,
+.Xr sigsuspend 2 ,
+.Xr wait 2 ,
+.Xr fpsetmask 3 ,
+.Xr setjmp 3 ,
+.Xr siginfo 3 ,
+.Xr siginterrupt 3 ,
+.Xr sigsetops 3 ,
+.Xr ucontext 3 ,
+.Xr tty 4
+.Sh STANDARDS
+The
+.Fn sigaction
+system call is expected to conform to
+.St -p1003.1-90 .
+The
+.Dv SA_ONSTACK
+and
+.Dv SA_RESTART
+flags are Berkeley extensions,
+as are the signals,
+.Dv SIGTRAP ,
+.Dv SIGEMT ,
+.Dv SIGBUS ,
+.Dv SIGSYS ,
+.Dv SIGURG ,
+.Dv SIGIO ,
+.Dv SIGXCPU ,
+.Dv SIGXFSZ ,
+.Dv SIGVTALRM ,
+.Dv SIGPROF ,
+.Dv SIGWINCH ,
+and
+.Dv SIGINFO .
+Those signals are available on most
+.Bx Ns \-derived
+systems.
+The
+.Dv SA_NODEFER
+and
+.Dv SA_RESETHAND
+flags are intended for backwards compatibility with other operating
+systems.
+The
+.Dv SA_NOCLDSTOP ,
+and
+.Dv SA_NOCLDWAIT
+.\" and
+.\" SA_SIGINFO
+flags are featuring options commonly found in other operating systems.
+The flags are approved by
+.St -susv2 ,
+along with the option to avoid zombie creation by ignoring
+.Dv SIGCHLD .
diff --git a/lib/libc/sys/sigaction.c b/lib/libc/sys/sigaction.c
new file mode 100644
index 000000000000..b4d65639b816
--- /dev/null
+++ b/lib/libc/sys/sigaction.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2014 The FreeBSD Foundation.
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Konstantin Belousov
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice(s), this list of conditions and the following disclaimer as
+ * the first lines of this file unmodified other than the possible
+ * addition of one or more copyright notices.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice(s), this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <signal.h>
+#include "libc_private.h"
+
+__weak_reference(__sys_sigaction, __sigaction);
+__weak_reference(sigaction, __libc_sigaction);
+
+#pragma weak sigaction
+int
+sigaction(int sig, const struct sigaction *act, struct sigaction *oact)
+{
+
+ return (((int (*)(int, const struct sigaction *, struct sigaction *))
+ __libc_interposing[INTERPOS_sigaction])(sig, act, oact));
+}
diff --git a/lib/libc/sys/sigaltstack.2 b/lib/libc/sys/sigaltstack.2
new file mode 100644
index 000000000000..d9cb27362592
--- /dev/null
+++ b/lib/libc/sys/sigaltstack.2
@@ -0,0 +1,162 @@
+.\" Copyright (c) 1983, 1991, 1992, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)sigaltstack.2 8.2 (Berkeley) 5/1/95
+.\" $FreeBSD$
+.\"
+.Dd May 6, 2010
+.Dt SIGALTSTACK 2
+.Os
+.Sh NAME
+.Nm sigaltstack
+.Nd set and/or get signal stack context
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In signal.h
+.Bd -literal
+typedef struct {
+ char *ss_sp;
+ size_t ss_size;
+ int ss_flags;
+} stack_t;
+.Ed
+.Ft int
+.Fn sigaltstack "const stack_t * restrict ss" "stack_t * restrict oss"
+.Sh DESCRIPTION
+The
+.Fn sigaltstack
+system call
+allows defining an alternate stack on which signals
+are to be processed for the current thread.
+If
+.Fa ss
+is non-zero,
+it specifies a pointer to and the size of a
+.Em "signal stack"
+on which to deliver signals.
+When a signal's action indicates its handler
+should execute on the signal stack (specified with a
+.Xr sigaction 2
+system call), the system checks to see
+if the thread is currently executing on that stack.
+If the thread is not currently executing on the signal stack,
+the system arranges a switch to the signal stack for the
+duration of the signal handler's execution.
+.Pp
+An active stack cannot be modified.
+.Pp
+If
+.Dv SS_DISABLE
+is set in
+.Fa ss_flags ,
+.Fa ss_sp
+and
+.Fa ss_size
+are ignored and the signal stack will be disabled.
+A disabled stack will cause all signals to be
+taken on the regular user stack.
+If the stack is later re-enabled then all signals that were specified
+to be processed on an alternate stack will resume doing so.
+.Pp
+If
+.Fa oss
+is non-zero, the current signal stack state is returned.
+The
+.Fa ss_flags
+field will contain the value
+.Dv SS_ONSTACK
+if the thread is currently on a signal stack and
+.Dv SS_DISABLE
+if the signal stack is currently disabled.
+.Sh NOTES
+The value
+.Dv SIGSTKSZ
+is defined to be the number of bytes/chars that would be used to cover
+the usual case when allocating an alternate stack area.
+The following code fragment is typically used to allocate an alternate stack.
+.Bd -literal -offset indent
+if ((sigstk.ss_sp = malloc(SIGSTKSZ)) == NULL)
+ /* error return */
+sigstk.ss_size = SIGSTKSZ;
+sigstk.ss_flags = 0;
+if (sigaltstack(&sigstk, NULL) < 0)
+ perror("sigaltstack");
+.Ed
+An alternative approach is provided for programs with signal handlers
+that require a specific amount of stack space other than the default size.
+The value
+.Dv MINSIGSTKSZ
+is defined to be the number of bytes/chars that is required by
+the operating system to implement the alternate stack feature.
+In computing an alternate stack size,
+programs should add
+.Dv MINSIGSTKSZ
+to their stack requirements to allow for the operating system overhead.
+.Pp
+Signal stacks are automatically adjusted for the direction of stack
+growth and alignment requirements.
+Signal stacks may or may not be protected by the hardware and
+are not ``grown'' automatically as is done for the normal stack.
+If the stack overflows and this space is not protected
+unpredictable results may occur.
+.Sh RETURN VALUES
+.Rv -std sigaltstack
+.Sh ERRORS
+The
+.Fn sigaltstack
+system call
+will fail and the signal stack context will remain unchanged
+if one of the following occurs.
+.Bl -tag -width Er
+.It Bq Er EFAULT
+Either
+.Fa ss
+or
+.Fa oss
+points to memory that is not a valid part of the process
+address space.
+.It Bq Er EPERM
+An attempt was made to modify an active stack.
+.It Bq Er EINVAL
+The
+.Fa ss_flags
+field was invalid.
+.It Bq Er ENOMEM
+Size of alternate stack area is less than or equal to
+.Dv MINSIGSTKSZ .
+.El
+.Sh SEE ALSO
+.Xr sigaction 2 ,
+.Xr setjmp 3
+.Sh HISTORY
+The predecessor to
+.Fn sigaltstack ,
+the
+.Fn sigstack
+system call, appeared in
+.Bx 4.2 .
diff --git a/lib/libc/sys/sigpending.2 b/lib/libc/sys/sigpending.2
new file mode 100644
index 000000000000..06ecc004501d
--- /dev/null
+++ b/lib/libc/sys/sigpending.2
@@ -0,0 +1,77 @@
+.\" Copyright (c) 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Berkeley Software Design, Inc.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)sigpending.2 8.3 (Berkeley) 1/12/94
+.\" $FreeBSD$
+.\"
+.Dd September 6, 2013
+.Dt SIGPENDING 2
+.Os
+.Sh NAME
+.Nm sigpending
+.Nd get pending signals
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In signal.h
+.Ft int
+.Fn sigpending "sigset_t *set"
+.Sh DESCRIPTION
+The
+.Fn sigpending
+system call returns a mask of the signals pending for delivery
+to the calling thread or the calling process in the location indicated by
+.Fa set .
+Signals may be pending because they are currently masked,
+or transiently before delivery (although the latter case is not
+normally detectable).
+.Sh RETURN VALUES
+.Rv -std sigpending
+.Sh ERRORS
+The
+.Fn sigpending
+system call
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EFAULT
+The
+.Fa set
+argument specified an invalid address.
+.El
+.Sh SEE ALSO
+.Xr sigaction 2 ,
+.Xr sigprocmask 2 ,
+.Xr sigsuspend 2 ,
+.Xr sigsetops 3
+.Sh STANDARDS
+The
+.Fn sigpending
+system call is expected to conform to
+.St -p1003.1-90 .
diff --git a/lib/libc/sys/sigprocmask.2 b/lib/libc/sys/sigprocmask.2
new file mode 100644
index 000000000000..f7c833535882
--- /dev/null
+++ b/lib/libc/sys/sigprocmask.2
@@ -0,0 +1,131 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)sigprocmask.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd May 7, 2010
+.Dt SIGPROCMASK 2
+.Os
+.Sh NAME
+.Nm sigprocmask
+.Nd manipulate current signal mask
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In signal.h
+.Ft int
+.Fo sigprocmask
+.Fa "int how"
+.Fa "const sigset_t * restrict set"
+.Fa "sigset_t * restrict oset"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn sigprocmask
+system call examines and/or changes the current signal mask (those signals
+that are blocked from delivery).
+Signals are blocked if they are members of the current signal mask set.
+.Pp
+If
+.Fa set
+is not null, the action of
+.Fn sigprocmask
+depends on the value of the
+.Fa how
+argument.
+The signal mask is changed as a function of the specified
+.Fa set
+and the current mask.
+The function is specified by
+.Fa how
+using one of the following values from
+.In signal.h :
+.Bl -tag -width SIG_UNBLOCK
+.It Dv SIG_BLOCK
+The new mask is the union of the current mask and the specified
+.Fa set .
+.It Dv SIG_UNBLOCK
+The new mask is the intersection of the current mask
+and the complement of the specified
+.Fa set .
+.It Dv SIG_SETMASK
+The current mask is replaced by the specified
+.Fa set .
+.El
+.Pp
+If
+.Fa oset
+is not null, it is set to
+the previous value of the signal mask.
+When
+.Fa set
+is null,
+the value of
+.Fa how
+is insignificant and the mask remains unset
+providing a way to examine the signal mask without modification.
+.Pp
+The system
+quietly disallows
+.Dv SIGKILL
+or
+.Dv SIGSTOP
+to be blocked.
+.Pp
+In threaded applications,
+.Xr pthread_sigmask 3
+must be used instead of
+.Fn sigprocmask .
+.Sh RETURN VALUES
+.Rv -std sigprocmask
+.Sh ERRORS
+The
+.Fn sigprocmask
+system call will fail and the signal mask will be unchanged if one
+of the following occurs:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa how
+argument
+has a value other than those listed here.
+.El
+.Sh SEE ALSO
+.Xr kill 2 ,
+.Xr sigaction 2 ,
+.Xr sigpending 2 ,
+.Xr sigsuspend 2 ,
+.Xr fpsetmask 3 ,
+.Xr pthread_sigmask 3 ,
+.Xr sigsetops 3
+.Sh STANDARDS
+The
+.Fn sigprocmask
+system call is expected to
+conform to
+.St -p1003.1-90 .
diff --git a/lib/libc/sys/sigprocmask.c b/lib/libc/sys/sigprocmask.c
new file mode 100644
index 000000000000..d24bb89c1f79
--- /dev/null
+++ b/lib/libc/sys/sigprocmask.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2014 The FreeBSD Foundation.
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Konstantin Belousov
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice(s), this list of conditions and the following disclaimer as
+ * the first lines of this file unmodified other than the possible
+ * addition of one or more copyright notices.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice(s), this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <signal.h>
+#include "libc_private.h"
+
+__weak_reference(__sys_sigprocmask, __sigprocmask);
+__weak_reference(sigprocmask, __libc_sigprocmask);
+
+#pragma weak sigprocmask
+int
+sigprocmask(int how, const sigset_t *set, sigset_t *oset)
+{
+
+ return (((int (*)(int, const sigset_t *, sigset_t *))
+ __libc_interposing[INTERPOS_sigprocmask])(how, set, oset));
+}
diff --git a/lib/libc/sys/sigqueue.2 b/lib/libc/sys/sigqueue.2
new file mode 100644
index 000000000000..04e101bc3443
--- /dev/null
+++ b/lib/libc/sys/sigqueue.2
@@ -0,0 +1,149 @@
+.\" Copyright (c) 2005 David Xu <davidxu@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice(s), this list of conditions and the following disclaimer as
+.\" the first lines of this file unmodified other than the possible
+.\" addition of one or more copyright notices.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice(s), this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+.\" EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+.\" OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+.\" EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd March 10, 2012
+.Dt SIGQUEUE 2
+.Os
+.Sh NAME
+.Nm sigqueue
+.Nd "queue a signal to a process (REALTIME)"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In signal.h
+.Ft int
+.Fn sigqueue "pid_t pid" "int signo" "const union sigval value"
+.Sh DESCRIPTION
+The
+.Fn sigqueue
+system call causes the signal specified by
+.Fa signo
+to be sent with the value specified by
+.Fa value
+to the process specified by
+.Fa pid .
+If
+.Fa signo
+is zero (the null signal), error checking is performed but
+no signal is actually sent.
+The null signal can be used to check the
+validity of PID.
+.Pp
+The conditions required for a process to have permission to queue a
+signal to another process are the same as for the
+.Xr kill 2
+system call.
+The
+.Fn sigqueue
+system call queues a signal to a single process specified by the
+.Fa pid
+argument.
+.Pp
+The
+.Fn sigqueue
+system call returns immediately.
+If the resources were
+available to queue the signal, the signal will be queued and sent to
+the receiving process.
+.Pp
+If the value of
+.Fa pid
+causes
+.Fa signo
+to be generated for the sending process, and if
+.Fa signo
+is not blocked for the calling thread and if no other thread has
+.Fa signo
+unblocked or is waiting in a
+.Fn sigwait
+system call for
+.Fa signo ,
+either
+.Fa signo
+or at least the pending, unblocked signal will be delivered to the
+calling thread before
+.Fn sigqueue
+returns.
+Should any multiple pending signals in the range
+.Dv SIGRTMIN
+to
+.Dv SIGRTMAX
+be selected for delivery, it is the lowest numbered
+one.
+The selection order between realtime and non-realtime signals, or
+between multiple pending non-realtime signals, is unspecified.
+.Sh RETURN VALUES
+.Rv -std
+.Sh ERRORS
+The
+.Fn sigqueue
+system call
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EAGAIN
+No resources are available to queue the signal.
+The process has already
+queued
+.Brq Dv SIGQUEUE_MAX
+signals that are still pending at the receiver(s),
+or a system-wide resource limit has been exceeded.
+.It Bq Er EINVAL
+The value of the
+.Fa signo
+argument is an invalid or unsupported signal number.
+.It Bq Er EPERM
+The process does not have the appropriate privilege to send the signal
+to the receiving process.
+.It Bq Er ESRCH
+The process
+.Fa pid
+does not exist.
+.El
+.Sh SEE ALSO
+.Xr kill 2 ,
+.Xr sigaction 2 ,
+.Xr sigpending 2 ,
+.Xr sigqueue 2 ,
+.Xr sigsuspend 2 ,
+.Xr sigtimedwait 2 ,
+.Xr sigwait 2 ,
+.Xr sigwaitinfo 2 ,
+.Xr pause 3 ,
+.Xr pthread_sigmask 3 ,
+.Xr siginfo 3
+.Sh STANDARDS
+The
+.Fn sigqueue
+system call conforms to
+.St -p1003.1-2004 .
+.Sh HISTORY
+Support for
+.Tn POSIX
+realtime signal queue first appeared in
+.Fx 7.0 .
diff --git a/lib/libc/sys/sigreturn.2 b/lib/libc/sys/sigreturn.2
new file mode 100644
index 000000000000..1b76468a84ec
--- /dev/null
+++ b/lib/libc/sys/sigreturn.2
@@ -0,0 +1,89 @@
+.\" Copyright (c) 1985, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)sigreturn.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd September 6, 2013
+.Dt SIGRETURN 2
+.Os
+.Sh NAME
+.Nm sigreturn
+.Nd return from signal
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In signal.h
+.Ft int
+.Fn sigreturn "const ucontext_t *scp"
+.Sh DESCRIPTION
+The
+.Fn sigreturn
+system call
+allows users to atomically unmask, switch stacks,
+and return from a signal context.
+The thread's signal mask and stack status are
+restored from the context structure pointed to by
+.Fa scp .
+The system call does not return;
+the users stack pointer, frame pointer, argument pointer,
+and processor status longword are restored from the context.
+Execution resumes at the specified pc.
+This system call is used by the trampoline code and
+.Xr longjmp 3
+when returning from a signal to the previously executing program.
+.Sh RETURN VALUES
+If successful, the system call does not return.
+Otherwise, a value of -1 is returned and
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+The
+.Fn sigreturn
+system call
+will fail and the thread context will remain unchanged
+if one of the following occurs.
+.Bl -tag -width Er
+.It Bq Er EFAULT
+The
+.Fa scp
+argument
+points to memory that is not a valid part of the process
+address space.
+.It Bq Er EINVAL
+The process status longword is invalid or would improperly
+raise the privilege level of the process.
+.El
+.Sh SEE ALSO
+.Xr sigaction 2 ,
+.Xr setjmp 3 ,
+.Xr ucontext 3
+.Sh HISTORY
+The
+.Fn sigreturn
+system call appeared in
+.Bx 4.3 .
diff --git a/lib/libc/sys/sigstack.2 b/lib/libc/sys/sigstack.2
new file mode 100644
index 000000000000..efd7ed76e673
--- /dev/null
+++ b/lib/libc/sys/sigstack.2
@@ -0,0 +1,50 @@
+.\" Copyright (c) 1983, 1992, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)sigstack.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt SIGSTACK 2
+.Os
+.Sh NAME
+.Nm sigstack
+.Nd set and/or get signal stack context
+.Sh LIBRARY
+.Lb libc
+.Sh DESCRIPTION
+The
+.Fn sigstack
+function has been deprecated in favor of the interface described in
+.Xr sigaltstack 2 .
+.Sh SEE ALSO
+.Xr sigaltstack 2
+.Sh HISTORY
+The
+.Fn sigstack
+system call appeared in
+.Bx 4.2 .
diff --git a/lib/libc/sys/sigsuspend.2 b/lib/libc/sys/sigsuspend.2
new file mode 100644
index 000000000000..0ffc11dc4f3e
--- /dev/null
+++ b/lib/libc/sys/sigsuspend.2
@@ -0,0 +1,85 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)sigsuspend.2 8.2 (Berkeley) 5/16/95
+.\" $FreeBSD$
+.\"
+.Dd August 16, 2013
+.Dt SIGSUSPEND 2
+.Os
+.Sh NAME
+.Nm sigsuspend
+.Nd atomically release blocked signals and wait for interrupt
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In signal.h
+.Ft int
+.Fn sigsuspend "const sigset_t *sigmask"
+.Sh DESCRIPTION
+The
+.Fn sigsuspend
+system call
+temporarily changes the blocked signal mask to the set to which
+.Fa sigmask
+points,
+and then waits for a signal to arrive;
+on return the previous set of masked signals is restored.
+The signal mask set
+is usually empty to indicate that all
+signals are to be unblocked for the duration of the call.
+.Pp
+In normal usage, a signal is blocked using
+.Xr sigprocmask 2
+to begin a critical section, variables modified on the occurrence
+of the signal are examined to determine that there is no work
+to be done, and the process pauses awaiting work by using
+.Fn sigsuspend
+with the previous mask returned by
+.Xr sigprocmask 2 .
+.Sh RETURN VALUES
+The
+.Fn sigsuspend
+system call
+always terminates by being interrupted, returning -1 with
+.Va errno
+set to
+.Er EINTR .
+.Sh SEE ALSO
+.Xr pselect 2 ,
+.Xr sigaction 2 ,
+.Xr sigpending 2 ,
+.Xr sigprocmask 2 ,
+.Xr sigtimedwait 2 ,
+.Xr sigwait 2 ,
+.Xr sigwaitinfo 2 ,
+.Xr sigsetops 3
+.Sh STANDARDS
+The
+.Fn sigsuspend
+system call is expected to conform to
+.St -p1003.1-90 .
diff --git a/lib/libc/sys/sigsuspend.c b/lib/libc/sys/sigsuspend.c
new file mode 100644
index 000000000000..1f980a117a1b
--- /dev/null
+++ b/lib/libc/sys/sigsuspend.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2014 The FreeBSD Foundation.
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Konstantin Belousov
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice(s), this list of conditions and the following disclaimer as
+ * the first lines of this file unmodified other than the possible
+ * addition of one or more copyright notices.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice(s), this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <signal.h>
+#include "libc_private.h"
+
+__weak_reference(__sys_sigsuspend, __sigsuspend);
+__weak_reference(sigsuspend, __libc_sigsuspend);
+
+#pragma weak sigsuspend
+int
+sigsuspend(const sigset_t *set)
+{
+
+ return (((int (*)(const sigset_t *))
+ __libc_interposing[INTERPOS_sigsuspend])(set));
+}
diff --git a/lib/libc/sys/sigtimedwait.c b/lib/libc/sys/sigtimedwait.c
new file mode 100644
index 000000000000..4e067192ca4b
--- /dev/null
+++ b/lib/libc/sys/sigtimedwait.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2014 The FreeBSD Foundation.
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Konstantin Belousov
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice(s), this list of conditions and the following disclaimer as
+ * the first lines of this file unmodified other than the possible
+ * addition of one or more copyright notices.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice(s), this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <signal.h>
+#include "libc_private.h"
+
+__weak_reference(__sys_sigtimedwait, __sigtimedwait);
+
+#pragma weak sigtimedwait
+int
+sigtimedwait(const sigset_t * __restrict set, siginfo_t * __restrict info,
+ const struct timespec * __restrict t)
+{
+
+ return (((int (*)(const sigset_t *, siginfo_t *,
+ const struct timespec *))
+ __libc_interposing[INTERPOS_sigtimedwait])(set, info, t));
+}
diff --git a/lib/libc/sys/sigwait.2 b/lib/libc/sys/sigwait.2
new file mode 100644
index 000000000000..4da64a99dddd
--- /dev/null
+++ b/lib/libc/sys/sigwait.2
@@ -0,0 +1,124 @@
+.\" Copyright (C) 2000 Jason Evans <jasone@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(s), this list of conditions and the following disclaimer as
+.\" the first lines of this file unmodified other than the possible
+.\" addition of one or more copyright notices.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice(s), this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+.\" EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+.\" OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+.\" EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd September 6, 2013
+.Dt SIGWAIT 2
+.Os
+.Sh NAME
+.Nm sigwait
+.Nd select a set of signals
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In signal.h
+.Ft int
+.Fn sigwait "const sigset_t * restrict set" "int * restrict sig"
+.Sh DESCRIPTION
+The
+.Fn sigwait
+system call selects a set of signals, specified by
+.Fa set .
+If none of the selected signals are pending,
+.Fn sigwait
+waits until one or more of the selected signals has been generated.
+Then
+.Fn sigwait
+atomically clears one of the selected signals from the set of pending signals
+(for the process or for the current thread) and sets the location pointed to by
+.Fa sig
+to the signal number that was cleared.
+.Pp
+The signals specified by
+.Fa set
+should be blocked at the time of the call to
+.Fn sigwait .
+.Pp
+If more than one thread is using
+.Fn sigwait
+to wait for the same signal, no more than one of these threads will return from
+.Fn sigwait
+with the signal number.
+If more than a single thread is blocked in
+.Fn sigwait
+for a signal when that signal is generated for the process, it is unspecified
+which of the waiting threads returns from
+.Fn sigwait .
+If the signal is generated for a specific thread, as by
+.Fn pthread_kill ,
+only that thread will return.
+.Pp
+Should any of the multiple pending signals in the range
+.Dv SIGRTMIN
+to
+.Dv SIGRTMAX
+be
+selected, it will be the lowest numbered one.
+The selection order between realtime
+and non-realtime signals, or between multiple pending non-realtime signals,
+is unspecified.
+.Sh IMPLEMENTATION NOTES
+The
+.Fn sigwait
+function is implemented as a wrapper around the
+.Fn __sys_sigwait
+system call, which retries the call on
+.Er EINTR
+error.
+.Sh RETURN VALUES
+If successful,
+.Fn sigwait
+returns 0 and sets the location pointed to by
+.Fa sig
+to the cleared signal number.
+Otherwise, an error number is returned.
+.Sh ERRORS
+The
+.Fn sigwait
+system call will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa set
+argument
+specifies one or more invalid signal numbers.
+.El
+.Sh SEE ALSO
+.Xr sigaction 2 ,
+.Xr sigpending 2 ,
+.Xr sigqueue 2 ,
+.Xr sigsuspend 2 ,
+.Xr sigtimedwait 2 ,
+.Xr sigwaitinfo 2 ,
+.Xr pause 3 ,
+.Xr pthread_sigmask 3
+.Sh STANDARDS
+The
+.Fn sigwait
+function conforms to
+.St -p1003.1-96 .
diff --git a/lib/libc/sys/sigwait.c b/lib/libc/sys/sigwait.c
new file mode 100644
index 000000000000..b21cabdeac55
--- /dev/null
+++ b/lib/libc/sys/sigwait.c
@@ -0,0 +1,54 @@
+/*-
+ * Copyright (c) 2010 davidxu@freebsd.org
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <signal.h>
+#include "libc_private.h"
+
+__weak_reference(__libc_sigwait, __sigwait);
+
+#pragma weak sigwait
+int
+sigwait(const sigset_t *set, int *sig)
+{
+
+ return (((int (*)(const sigset_t *, int *))
+ __libc_interposing[INTERPOS_sigwait])(set, sig));
+}
+
+int
+__libc_sigwait(const sigset_t *set, int *sig)
+{
+ int ret;
+
+ /* POSIX does not allow EINTR to be returned */
+ do {
+ ret = __sys_sigwait(set, sig);
+ } while (ret == EINTR);
+ return (ret);
+}
diff --git a/lib/libc/sys/sigwaitinfo.2 b/lib/libc/sys/sigwaitinfo.2
new file mode 100644
index 000000000000..b497592ed1f3
--- /dev/null
+++ b/lib/libc/sys/sigwaitinfo.2
@@ -0,0 +1,206 @@
+.\" Copyright (c) 2005 David Xu <davidxu@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice(s), this list of conditions and the following disclaimer as
+.\" the first lines of this file unmodified other than the possible
+.\" addition of one or more copyright notices.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice(s), this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+.\" EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+.\" OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+.\" EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd September 27, 2012
+.Dt SIGTIMEDWAIT 2
+.Os
+.Sh NAME
+.Nm sigtimedwait , sigwaitinfo
+.Nd "wait for queued signals (REALTIME)"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In signal.h
+.Ft int
+.Fo sigtimedwait
+.Fa "const sigset_t *restrict set" "siginfo_t *restrict info"
+.Fa "const struct timespec *restrict timeout"
+.Fc
+.Ft int
+.Fn sigwaitinfo "const sigset_t * restrict set" "siginfo_t * restrict info"
+.Sh DESCRIPTION
+The
+.Fn sigtimedwait
+system call is equivalent to
+.Fn sigwaitinfo
+except that if none of the signals specified by
+.Fa set
+are pending,
+.Fn sigtimedwait
+waits for the time interval specified in the
+.Vt timespec
+structure referenced by
+.Fa timeout .
+If the
+.Vt timespec
+structure pointed to by
+.Fa timeout
+is zero-valued and if none of the signals specified by
+.Fa set
+are pending, then
+.Fn sigtimedwait
+returns immediately with an error.
+If
+.Fa timeout
+is the
+.Dv NULL
+pointer, the behavior is unspecified.
+.Dv CLOCK_MONOTONIC
+clock is used to measure the time interval specified by the
+.Fa timeout
+argument.
+.Pp
+The
+.Fn sigwaitinfo
+system call selects the pending signal from the set specified by
+.Fa set .
+Should any of multiple pending signals in the range
+.Dv SIGRTMIN
+to
+.Dv SIGRTMAX
+be selected, it shall be the lowest numbered one.
+The
+selection order between realtime and non-realtime signals, or
+between multiple pending non-realtime signals, is unspecified.
+If no signal in
+.Fa set
+is pending at the time of the call, the calling thread
+is suspended until one or more signals in
+.Fa set
+become pending or until it is interrupted by an unblocked, caught signal.
+.Pp
+The
+.Fn sigwaitinfo
+system call is equivalent to the
+.Fn sigwait
+system call if the
+.Fa info
+argument is
+.Dv NULL .
+If the
+.Fa info
+argument is
+.Pf non- Dv NULL ,
+the
+.Fn sigwaitinfo
+function is equivalent to
+.Fn sigwait ,
+except that the selected signal number shall be stored in the
+.Va si_signo
+member, and the cause of the signal shall be stored in the
+.Va si_code
+member.
+Besides this, the
+.Fn sigwaitinfo
+and
+.Fn sigtimedwait
+system calls may return
+.Er EINTR
+if interrupted by signal, which is not allowed for the
+.Fn sigwait
+function.
+.Pp
+If any value is queued to the selected signal, the first such queued
+value is dequeued and, if the info argument is
+.Pf non- Dv NULL ,
+the value is stored in the
+.Va si_value
+member of
+.Fa info .
+The system resource used to queue the signal
+is released and returned to the system for other use.
+If no value is queued,
+the content of the
+.Va si_value
+member is zero-valued.
+If no further signals are
+queued for the selected signal, the pending indication for that signal
+is reset.
+.Sh RETURN VALUES
+Upon successful completion (that is, one of the signals specified by
+.Fa set
+is pending or is generated)
+.Fn sigwaitinfo
+and
+.Fn sigtimedwait
+return the selected signal number.
+Otherwise, the functions return a value of \-1
+and set the global variable
+.Va errno
+to indicate the error.
+.Sh ERRORS
+The
+.Fn sigtimedwait
+system call
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EAGAIN
+No signal specified by set was generated within the specified timeout period.
+.El
+.Pp
+The
+.Fn sigtimedwait
+and
+.Fn sigwaitinfo
+system calls fail if:
+.Bl -tag -width Er
+.It Bq Er EINTR
+The wait was interrupted by an unblocked, caught signal.
+.El
+.Pp
+The
+.Fn sigtimedwait
+system call may also fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa timeout
+argument specified a
+.Va tv_nsec
+value less than zero or greater than or equal
+to 1000 million.
+Kernel only checks for this error if no signal is pending in set and it
+is necessary to wait.
+.El
+.Sh SEE ALSO
+.Xr sigaction 2 ,
+.Xr sigpending 2 ,
+.Xr sigqueue 2 ,
+.Xr sigsuspend 2 ,
+.Xr sigwait 2 ,
+.Xr pause 3 ,
+.Xr pthread_sigmask 3 ,
+.Xr siginfo 3
+.Sh STANDARDS
+The
+.Fn sigtimedwait
+and
+.Fn sigwaitinfo
+system calls conform to
+.St -p1003.1-96 .
diff --git a/lib/libc/sys/sigwaitinfo.c b/lib/libc/sys/sigwaitinfo.c
new file mode 100644
index 000000000000..b9cdc79bc224
--- /dev/null
+++ b/lib/libc/sys/sigwaitinfo.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2014 The FreeBSD Foundation.
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Konstantin Belousov
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice(s), this list of conditions and the following disclaimer as
+ * the first lines of this file unmodified other than the possible
+ * addition of one or more copyright notices.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice(s), this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <signal.h>
+#include "libc_private.h"
+
+__weak_reference(__sys_sigwaitinfo, __sigwaitinfo);
+
+#pragma weak sigwaitinfo
+int
+sigwaitinfo(const sigset_t * __restrict set, siginfo_t * __restrict info)
+{
+
+ return (((int (*)(const sigset_t *, siginfo_t *))
+ __libc_interposing[INTERPOS_sigwaitinfo])(set, info));
+}
diff --git a/lib/libc/sys/socket.2 b/lib/libc/sys/socket.2
new file mode 100644
index 000000000000..3e7e9d92d151
--- /dev/null
+++ b/lib/libc/sys/socket.2
@@ -0,0 +1,350 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" From: @(#)socket.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd August 18, 2016
+.Dt SOCKET 2
+.Os
+.Sh NAME
+.Nm socket
+.Nd create an endpoint for communication
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/socket.h
+.Ft int
+.Fn socket "int domain" "int type" "int protocol"
+.Sh DESCRIPTION
+The
+.Fn socket
+system call
+creates an endpoint for communication and returns a descriptor.
+.Pp
+The
+.Fa domain
+argument specifies a communications domain within which
+communication will take place; this selects the protocol family
+which should be used.
+These families are defined in the include file
+.In sys/socket.h .
+The currently understood formats are:
+.Pp
+.Bd -literal -offset indent -compact
+PF_LOCAL Host-internal protocols (alias for PF_UNIX),
+PF_UNIX Host-internal protocols,
+PF_INET Internet version 4 protocols,
+PF_INET6 Internet version 6 protocols,
+PF_ROUTE Internal routing protocol,
+PF_LINK Link layer interface,
+PF_KEY Internal key-management function,
+PF_NATM Asynchronous transfer mode protocols,
+PF_NETGRAPH Netgraph sockets,
+PF_IEEE80211 IEEE 802.11 wireless link-layer protocols (WiFi),
+PF_BLUETOOTH Bluetooth protocols,
+PF_INET_SDP OFED socket direct protocol (IPv4),
+PF_INET6_SDP OFED socket direct protocol (IPv6)
+.Ed
+.Pp
+Each protocol family is connected to an address family, which has the
+same name except that the prefix is
+.Dq Dv AF_
+in place of
+.Dq Dv PF_ .
+Other protocol families may be also defined, beginning with
+.Dq Dv PF_ ,
+with corresponding address families.
+.Pp
+The socket has the indicated
+.Fa type ,
+which specifies the semantics of communication.
+Currently
+defined types are:
+.Pp
+.Bd -literal -offset indent -compact
+SOCK_STREAM Stream socket,
+SOCK_DGRAM Datagram socket,
+SOCK_RAW Raw-protocol interface,
+SOCK_RDM Reliably-delivered packet,
+SOCK_SEQPACKET Sequenced packet stream
+.Ed
+.Pp
+A
+.Dv SOCK_STREAM
+type provides sequenced, reliable,
+two-way connection based byte streams.
+An out-of-band data transmission mechanism may be supported.
+A
+.Dv SOCK_DGRAM
+socket supports
+datagrams (connectionless, unreliable messages of
+a fixed (typically small) maximum length).
+A
+.Dv SOCK_SEQPACKET
+socket may provide a sequenced, reliable,
+two-way connection-based data transmission path for datagrams
+of fixed maximum length; a consumer may be required to read
+an entire packet with each read system call.
+This facility is protocol specific, and presently unimplemented.
+.Dv SOCK_RAW
+sockets provide access to internal network protocols and interfaces.
+The types
+.Dv SOCK_RAW ,
+which is available only to the super-user, and
+.Dv SOCK_RDM ,
+which is planned,
+but not yet implemented, are not described here.
+.Pp
+Additionally, the following flags are allowed in the
+.Fa type
+argument:
+.Pp
+.Bd -literal -offset indent -compact
+SOCK_CLOEXEC Set close-on-exec on the new descriptor,
+SOCK_NONBLOCK Set non-blocking mode on the new socket
+.Ed
+.Pp
+The
+.Fa protocol
+argument
+specifies a particular protocol to be used with the socket.
+Normally only a single protocol exists to support a particular
+socket type within a given protocol family.
+However, it is possible
+that many protocols may exist, in which case a particular protocol
+must be specified in this manner.
+The protocol number to use is
+particular to the
+.Dq "communication domain"
+in which communication
+is to take place; see
+.Xr protocols 5 .
+.Pp
+The
+.Fa protocol
+argument may be set to zero (0) to request the default
+implementation of a socket type for the protocol, if any.
+.Pp
+Sockets of type
+.Dv SOCK_STREAM
+are full-duplex byte streams, similar
+to pipes.
+A stream socket must be in a
+.Em connected
+state before any data may be sent or received
+on it.
+A connection to another socket is created with a
+.Xr connect 2
+system call.
+Once connected, data may be transferred using
+.Xr read 2
+and
+.Xr write 2
+calls or some variant of the
+.Xr send 2
+and
+.Xr recv 2
+functions.
+(Some protocol families, such as the Internet family,
+support the notion of an
+.Dq implied connect ,
+which permits data to be sent piggybacked onto a connect operation by
+using the
+.Xr sendto 2
+system call.)
+When a session has been completed a
+.Xr close 2
+may be performed.
+Out-of-band data may also be transmitted as described in
+.Xr send 2
+and received as described in
+.Xr recv 2 .
+.Pp
+The communications protocols used to implement a
+.Dv SOCK_STREAM
+ensure that data
+is not lost or duplicated.
+If a piece of data for which the
+peer protocol has buffer space cannot be successfully transmitted
+within a reasonable length of time, then
+the connection is considered broken and calls
+will indicate an error with
+-1 returns and with
+.Er ETIMEDOUT
+as the specific code
+in the global variable
+.Va errno .
+The protocols optionally keep sockets
+.Dq warm
+by forcing transmissions
+roughly every minute in the absence of other activity.
+An error is then indicated if no response can be
+elicited on an otherwise
+idle connection for an extended period (e.g.\& 5 minutes).
+By default, a
+.Dv SIGPIPE
+signal is raised if a process sends
+on a broken stream, but this behavior may be inhibited via
+.Xr setsockopt 2 .
+.Pp
+.Dv SOCK_SEQPACKET
+sockets employ the same system calls
+as
+.Dv SOCK_STREAM
+sockets.
+The only difference
+is that
+.Xr read 2
+calls will return only the amount of data requested,
+and any remaining in the arriving packet will be discarded.
+.Pp
+.Dv SOCK_DGRAM
+and
+.Dv SOCK_RAW
+sockets allow sending of datagrams to correspondents
+named in
+.Xr send 2
+calls.
+Datagrams are generally received with
+.Xr recvfrom 2 ,
+which returns the next datagram with its return address.
+.Pp
+An
+.Xr fcntl 2
+system call can be used to specify a process group to receive
+a
+.Dv SIGURG
+signal when the out-of-band data arrives.
+It may also enable non-blocking I/O
+and asynchronous notification of I/O events
+via
+.Dv SIGIO .
+.Pp
+The operation of sockets is controlled by socket level
+.Em options .
+These options are defined in the file
+.In sys/socket.h .
+The
+.Xr setsockopt 2
+and
+.Xr getsockopt 2
+system calls are used to set and get options, respectively.
+.Sh RETURN VALUES
+A -1 is returned if an error occurs, otherwise the return
+value is a descriptor referencing the socket.
+.Sh ERRORS
+The
+.Fn socket
+system call fails if:
+.Bl -tag -width Er
+.It Bq Er EACCES
+Permission to create a socket of the specified type and/or protocol
+is denied.
+.It Bq Er EAFNOSUPPORT
+The address family (domain) is not supported or the
+specified domain is not supported by this protocol family.
+.It Bq Er EMFILE
+The per-process descriptor table is full.
+.It Bq Er ENFILE
+The system file table is full.
+.It Bq Er ENOBUFS
+Insufficient buffer space is available.
+The socket cannot be created until sufficient resources are freed.
+.It Bq Er EPERM
+User has insufficient privileges to carry out the requested operation.
+.It Bq Er EPROTONOSUPPORT
+The protocol type or the specified protocol is not supported
+within this domain.
+.It Bq Er EPROTOTYPE
+The socket type is not supported by the protocol.
+.El
+.Sh SEE ALSO
+.Xr accept 2 ,
+.Xr bind 2 ,
+.Xr connect 2 ,
+.Xr getpeername 2 ,
+.Xr getsockname 2 ,
+.Xr getsockopt 2 ,
+.Xr ioctl 2 ,
+.Xr listen 2 ,
+.Xr read 2 ,
+.Xr recv 2 ,
+.Xr select 2 ,
+.Xr send 2 ,
+.Xr shutdown 2 ,
+.Xr socketpair 2 ,
+.Xr write 2 ,
+.Xr getprotoent 3 ,
+.Xr netgraph 4 ,
+.Xr protocols 5
+.Rs
+.%T "An Introductory 4.3 BSD Interprocess Communication Tutorial"
+.%B PS1
+.%N 7
+.Re
+.Rs
+.%T "BSD Interprocess Communication Tutorial"
+.%B PS1
+.%N 8
+.Re
+.Sh STANDARDS
+The
+.Fn socket
+function conforms to
+.St -p1003.1-2008 .
+The
+.Tn POSIX
+standard specifies only the
+.Dv AF_INET ,
+.Dv AF_INET6 ,
+and
+.Dv AF_UNIX
+constants for address families, and requires the use of
+.Dv AF_*
+constants for the
+.Fa domain
+argument of
+.Fn socket .
+The
+.Dv SOCK_CLOEXEC
+flag is expected to conform to the next revision of the
+.Tn POSIX
+standard.
+The
+.Dv SOCK_RDM
+.Fa type ,
+the
+.Dv PF_*
+constants, and other address families are
+.Fx
+extensions.
+.Sh HISTORY
+The
+.Fn socket
+system call appeared in
+.Bx 4.2 .
diff --git a/lib/libc/sys/socketpair.2 b/lib/libc/sys/socketpair.2
new file mode 100644
index 000000000000..b15553afc583
--- /dev/null
+++ b/lib/libc/sys/socketpair.2
@@ -0,0 +1,100 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)socketpair.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd May 4, 2015
+.Dt SOCKETPAIR 2
+.Os
+.Sh NAME
+.Nm socketpair
+.Nd create a pair of connected sockets
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/socket.h
+.Ft int
+.Fn socketpair "int domain" "int type" "int protocol" "int *sv"
+.Sh DESCRIPTION
+The
+.Fn socketpair
+system call creates an unnamed pair of connected sockets in
+the specified communications
+.Fa domain ,
+of the specified
+.Fa type ,
+and using the optionally specified
+.Fa protocol .
+The descriptors used in referencing the new sockets
+are returned in
+.Fa sv Ns [0]
+and
+.Fa sv Ns [1] .
+The two sockets are indistinguishable.
+.Pp
+The
+.Dv SOCK_CLOEXEC
+and
+.Dv SOCK_NONBLOCK
+flags in the
+.Fa type
+argument apply to both descriptors.
+.Sh RETURN VALUES
+.Rv -std socketpair
+.Sh ERRORS
+The call succeeds unless:
+.Bl -tag -width Er
+.It Bq Er EMFILE
+Too many descriptors are in use by this process.
+.It Bq Er EAFNOSUPPORT
+The specified address family is not supported on this machine.
+.It Bq Er EPROTONOSUPPORT
+The specified protocol is not supported on this machine.
+.It Bq Er EOPNOTSUPP
+The specified protocol does not support creation of socket pairs.
+.It Bq Er EFAULT
+The address
+.Fa sv
+does not specify a valid part of the
+process address space.
+.El
+.Sh SEE ALSO
+.Xr pipe 2 ,
+.Xr read 2 ,
+.Xr socket 2 ,
+.Xr write 2
+.Sh HISTORY
+The
+.Fn socketpair
+system call appeared in
+.Bx 4.2 .
+.Sh BUGS
+This call is currently implemented only for the
+.Ux
+domain.
diff --git a/lib/libc/sys/stat.2 b/lib/libc/sys/stat.2
new file mode 100644
index 000000000000..3405d6e3511c
--- /dev/null
+++ b/lib/libc/sys/stat.2
@@ -0,0 +1,436 @@
+.\" Copyright (c) 1980, 1991, 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)stat.2 8.4 (Berkeley) 5/1/95
+.\" $FreeBSD$
+.\"
+.Dd January 14, 2016
+.Dt STAT 2
+.Os
+.Sh NAME
+.Nm stat ,
+.Nm lstat ,
+.Nm fstat ,
+.Nm fstatat
+.Nd get file status
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/stat.h
+.Ft int
+.Fn stat "const char * restrict path" "struct stat * restrict sb"
+.Ft int
+.Fn lstat "const char * restrict path" "struct stat * restrict sb"
+.Ft int
+.Fn fstat "int fd" "struct stat *sb"
+.Ft int
+.Fn fstatat "int fd" "const char *path" "struct stat *buf" "int flag"
+.Sh DESCRIPTION
+The
+.Fn stat
+system call obtains information about the file pointed to by
+.Fa path .
+Read, write or execute
+permission of the named file is not required, but all directories
+listed in the path name leading to the file must be searchable.
+.Pp
+The
+.Fn lstat
+system call is like
+.Fn stat
+except in the case where the named file is a symbolic link,
+in which case
+.Fn lstat
+returns information about the link,
+while
+.Fn stat
+returns information about the file the link references.
+.Pp
+The
+.Fn fstat
+system call obtains the same information about an open file
+known by the file descriptor
+.Fa fd .
+.Pp
+The
+.Fn fstatat
+system call is equivalent to
+.Fn stat
+and
+.Fn lstat
+except in the case where the
+.Fa path
+specifies a relative path.
+In this case the status is retrieved from a file relative to
+the directory associated with the file descriptor
+.Fa fd
+instead of the current working directory.
+.Pp
+The values for the
+.Fa flag
+are constructed by a bitwise-inclusive OR of flags from the following list,
+defined in
+.In fcntl.h :
+.Bl -tag -width indent
+.It Dv AT_SYMLINK_NOFOLLOW
+If
+.Fa path
+names a symbolic link, the status of the symbolic link is returned.
+.El
+.Pp
+If
+.Fn fstatat
+is passed the special value
+.Dv AT_FDCWD
+in the
+.Fa fd
+parameter, the current working directory is used and the behavior is
+identical to a call to
+.Fn stat
+or
+.Fn lstat
+respectively, depending on whether or not the
+.Dv AT_SYMLINK_NOFOLLOW
+bit is set in
+.Fa flag .
+.Pp
+The
+.Fa sb
+argument is a pointer to a
+.Vt stat
+structure
+as defined by
+.In sys/stat.h
+and into which information is placed concerning the file.
+.Pp
+The fields of
+.Vt "struct stat"
+related to the file system are as follows:
+.Bl -tag -width ".Va st_nlink"
+.It Va st_dev
+The numeric ID of the device containing the file.
+.It Va st_ino
+The file's inode number.
+.It Va st_nlink
+The number of hard links to the file.
+.El
+.Pp
+The
+.Va st_dev
+and
+.Va st_ino
+fields together identify the file uniquely within the system.
+.Pp
+The time-related fields of
+.Vt "struct stat"
+are as follows:
+.Bl -tag -width ".Va st_birthtim"
+.It Va st_atim
+Time when file data last accessed.
+Changed by the
+.Xr mknod 2 ,
+.Xr utimes 2 ,
+.Xr read 2
+and
+.Xr readv 2
+system calls.
+.It Va st_mtim
+Time when file data last modified.
+Changed by the
+.Xr mkdir 2 ,
+.Xr mkfifo 2 ,
+.Xr mknod 2 ,
+.Xr utimes 2 ,
+.Xr write 2
+and
+.Xr writev 2
+system calls.
+.It Va st_ctim
+Time when file status was last changed (inode data modification).
+Changed by the
+.Xr chflags 2 ,
+.Xr chmod 2 ,
+.Xr chown 2 ,
+.Xr creat 2 ,
+.Xr link 2 ,
+.Xr mkdir 2 ,
+.Xr mkfifo 2 ,
+.Xr mknod 2 ,
+.Xr rename 2 ,
+.Xr rmdir 2 ,
+.Xr symlink 2 ,
+.Xr truncate 2 ,
+.Xr unlink 2 ,
+.Xr utimes 2 ,
+.Xr write 2
+and
+.Xr writev 2
+system calls.
+.It Va st_birthtim
+Time when the inode was created.
+.El
+.Pp
+The following time-related macros are defined for compatibility:
+.Bd -literal
+#define st_atime st_atim.tv_sec
+#define st_mtime st_mtim.tv_sec
+#define st_ctime st_ctim.tv_sec
+#ifndef _POSIX_SOURCE
+#define st_birthtime st_birthtim.tv_sec
+#endif
+
+#ifndef _POSIX_SOURCE
+#define st_atimespec st_atim
+#define st_mtimespec st_mtim
+#define st_ctimespec st_ctim
+#define st_birthtimespec st_birthtim
+#endif
+.Ed
+.Pp
+The size-related fields of the
+.Vt "struct stat"
+are as follows:
+.Bl -tag -width ".Va st_blksize"
+.It Va st_size
+The file size in bytes.
+.It Va st_blksize
+The optimal I/O block size for the file.
+.It Va st_blocks
+The actual number of blocks allocated for the file in 512-byte units.
+As short symbolic links are stored in the inode, this number may
+be zero.
+.El
+.Pp
+The access-related fields of
+.Vt "struct stat"
+are as follows:
+.Bl -tag -width ".Va st_mode"
+.It Va st_uid
+The user ID of the file's owner.
+.It Va st_gid
+The group ID of the file.
+.It Va st_mode
+Status of the file (see below).
+.El
+.Pp
+The status information word
+.Fa st_mode
+has the following bits:
+.Bd -literal
+#define S_IFMT 0170000 /* type of file mask */
+#define S_IFIFO 0010000 /* named pipe (fifo) */
+#define S_IFCHR 0020000 /* character special */
+#define S_IFDIR 0040000 /* directory */
+#define S_IFBLK 0060000 /* block special */
+#define S_IFREG 0100000 /* regular */
+#define S_IFLNK 0120000 /* symbolic link */
+#define S_IFSOCK 0140000 /* socket */
+#define S_IFWHT 0160000 /* whiteout */
+#define S_ISUID 0004000 /* set user id on execution */
+#define S_ISGID 0002000 /* set group id on execution */
+#define S_ISVTX 0001000 /* save swapped text even after use */
+#define S_IRWXU 0000700 /* RWX mask for owner */
+#define S_IRUSR 0000400 /* read permission, owner */
+#define S_IWUSR 0000200 /* write permission, owner */
+#define S_IXUSR 0000100 /* execute/search permission, owner */
+#define S_IRWXG 0000070 /* RWX mask for group */
+#define S_IRGRP 0000040 /* read permission, group */
+#define S_IWGRP 0000020 /* write permission, group */
+#define S_IXGRP 0000010 /* execute/search permission, group */
+#define S_IRWXO 0000007 /* RWX mask for other */
+#define S_IROTH 0000004 /* read permission, other */
+#define S_IWOTH 0000002 /* write permission, other */
+#define S_IXOTH 0000001 /* execute/search permission, other */
+.Ed
+.Pp
+For a list of access modes, see
+.In sys/stat.h ,
+.Xr access 2
+and
+.Xr chmod 2 .
+The following macros are available to test whether a
+.Va st_mode
+value passed in the
+.Fa m
+argument corresponds to a file of the specified type:
+.Bl -tag -width ".Fn S_ISFIFO m"
+.It Fn S_ISBLK m
+Test for a block special file.
+.It Fn S_ISCHR m
+Test for a character special file.
+.It Fn S_ISDIR m
+Test for a directory.
+.It Fn S_ISFIFO m
+Test for a pipe or FIFO special file.
+.It Fn S_ISLNK m
+Test for a symbolic link.
+.It Fn S_ISREG m
+Test for a regular file.
+.It Fn S_ISSOCK m
+Test for a socket.
+.It Fn S_ISWHT m
+Test for a whiteout.
+.El
+.Pp
+The macros evaluate to a non-zero value if the test is true
+or to the value 0 if the test is false.
+.Sh RETURN VALUES
+.Rv -std
+.Sh COMPATIBILITY
+Previous versions of the system used different types for the
+.Va st_dev ,
+.Va st_uid ,
+.Va st_gid ,
+.Va st_rdev ,
+.Va st_size ,
+.Va st_blksize
+and
+.Va st_blocks
+fields.
+.Sh ERRORS
+The
+.Fn stat
+and
+.Fn lstat
+system calls will fail if:
+.Bl -tag -width Er
+.It Bq Er EACCES
+Search permission is denied for a component of the path prefix.
+.It Bq Er EFAULT
+The
+.Fa sb
+or
+.Fa path
+argument
+points to an invalid address.
+.It Bq Er EIO
+An I/O error occurred while reading from or writing to the file system.
+.It Bq Er ELOOP
+Too many symbolic links were encountered in translating the pathname.
+.It Bq Er ENAMETOOLONG
+A component of a pathname exceeded 255 characters,
+or an entire path name exceeded 1023 characters.
+.It Bq Er ENOENT
+The named file does not exist.
+.It Bq Er ENOTDIR
+A component of the path prefix is not a directory.
+.It Bq Er EOVERFLOW
+The file size in bytes cannot be
+represented correctly in the structure pointed to by
+.Fa sb .
+.El
+.Pp
+The
+.Fn fstat
+system call will fail if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa fd
+argument
+is not a valid open file descriptor.
+.It Bq Er EFAULT
+The
+.Fa sb
+argument
+points to an invalid address.
+.It Bq Er EIO
+An I/O error occurred while reading from or writing to the file system.
+.It Bq Er EOVERFLOW
+The file size in bytes cannot be
+represented correctly in the structure pointed to by
+.Fa sb .
+.El
+.Pp
+In addition to the errors returned by the
+.Fn lstat ,
+the
+.Fn fstatat
+may fail if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa path
+argument does not specify an absolute path and the
+.Fa fd
+argument is neither
+.Dv AT_FDCWD
+nor a valid file descriptor open for searching.
+.It Bq Er EINVAL
+The value of the
+.Fa flag
+argument is not valid.
+.It Bq Er ENOTDIR
+The
+.Fa path
+argument is not an absolute path and
+.Fa fd
+is neither
+.Dv AT_FDCWD
+nor a file descriptor associated with a directory.
+.El
+.Sh SEE ALSO
+.Xr access 2 ,
+.Xr chmod 2 ,
+.Xr chown 2 ,
+.Xr fhstat 2 ,
+.Xr statfs 2 ,
+.Xr utimes 2 ,
+.Xr sticky 7 ,
+.Xr symlink 7
+.Sh STANDARDS
+The
+.Fn stat
+and
+.Fn fstat
+system calls are expected to conform to
+.St -p1003.1-90 .
+The
+.Fn fstatat
+system call follows The Open Group Extended API Set 2 specification.
+.Sh HISTORY
+The
+.Fn stat
+and
+.Fn fstat
+system calls appeared in
+.At v7 .
+The
+.Fn lstat
+system call appeared in
+.Bx 4.2 .
+The
+.Fn fstatat
+system call appeared in
+.Fx 8.0 .
+.Sh BUGS
+Applying
+.Fn fstat
+to a socket
+returns a zeroed buffer,
+except for the blocksize field,
+and a unique device and inode number.
diff --git a/lib/libc/sys/statfs.2 b/lib/libc/sys/statfs.2
new file mode 100644
index 000000000000..888f97641434
--- /dev/null
+++ b/lib/libc/sys/statfs.2
@@ -0,0 +1,235 @@
+.\" Copyright (c) 1989, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)statfs.2 8.5 (Berkeley) 5/24/95
+.\" $FreeBSD$
+.\"
+.Dd November 1, 2006
+.Dt STATFS 2
+.Os
+.Sh NAME
+.Nm statfs
+.Nd get file system statistics
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/param.h
+.In sys/mount.h
+.Ft int
+.Fn statfs "const char *path" "struct statfs *buf"
+.Ft int
+.Fn fstatfs "int fd" "struct statfs *buf"
+.Sh DESCRIPTION
+The
+.Fn statfs
+system call
+returns information about a mounted file system.
+The
+.Fa path
+argument
+is the path name of any file within the mounted file system.
+The
+.Fa buf
+argument
+is a pointer to a
+.Vt statfs
+structure defined as follows:
+.Bd -literal
+typedef struct fsid { int32_t val[2]; } fsid_t; /* file system id type */
+
+/*
+ * filesystem statistics
+ */
+
+#define MFSNAMELEN 16 /* length of type name including null */
+#define MNAMELEN 88 /* size of on/from name bufs */
+#define STATFS_VERSION 0x20030518 /* current version number */
+
+struct statfs {
+uint32_t f_version; /* structure version number */
+uint32_t f_type; /* type of filesystem */
+uint64_t f_flags; /* copy of mount exported flags */
+uint64_t f_bsize; /* filesystem fragment size */
+uint64_t f_iosize; /* optimal transfer block size */
+uint64_t f_blocks; /* total data blocks in filesystem */
+uint64_t f_bfree; /* free blocks in filesystem */
+int64_t f_bavail; /* free blocks avail to non-superuser */
+uint64_t f_files; /* total file nodes in filesystem */
+int64_t f_ffree; /* free nodes avail to non-superuser */
+uint64_t f_syncwrites; /* count of sync writes since mount */
+uint64_t f_asyncwrites; /* count of async writes since mount */
+uint64_t f_syncreads; /* count of sync reads since mount */
+uint64_t f_asyncreads; /* count of async reads since mount */
+uint64_t f_spare[10]; /* unused spare */
+uint32_t f_namemax; /* maximum filename length */
+uid_t f_owner; /* user that mounted the filesystem */
+fsid_t f_fsid; /* filesystem id */
+char f_charspare[80]; /* spare string space */
+char f_fstypename[MFSNAMELEN]; /* filesystem type name */
+char f_mntfromname[MNAMELEN]; /* mounted filesystem */
+char f_mntonname[MNAMELEN]; /* directory on which mounted */
+};
+.Ed
+.Pp
+The flags that may be returned include:
+.Bl -tag -width MNT_SYNCHRONOUS
+.It Dv MNT_RDONLY
+The file system is mounted read-only;
+Even the super-user may not write on it.
+.It Dv MNT_NOEXEC
+Files may not be executed from the file system.
+.It Dv MNT_NOSUID
+Setuid and setgid bits on files are not honored when they are executed.
+.It Dv MNT_SYNCHRONOUS
+All I/O to the file system is done synchronously.
+.It Dv MNT_ASYNC
+No file system I/O is done synchronously.
+.It Dv MNT_SOFTDEP
+Soft updates being done (see
+.Xr ffs 7 ) .
+.It Dv MNT_GJOURNAL
+Journaling with gjournal is enabled (see
+.Xr gjournal 8 ) .
+.It Dv MNT_SUIDDIR
+Special handling of SUID bit on directories.
+.It Dv MNT_UNION
+Union with underlying file system.
+.It Dv MNT_NOSYMFOLLOW
+Symbolic links are not followed.
+.It Dv MNT_NOCLUSTERR
+Read clustering is disabled.
+.It Dv MNT_NOCLUSTERW
+Write clustering is disabled.
+.\".It Dv MNT_JAILDEVFS
+.\"XXX
+.It Dv MNT_MULTILABEL
+Mandatory Access Control (MAC) support for individual objects
+(see
+.Xr mac 4 ) .
+.It Dv MNT_ACLS
+Access Control List (ACL) support enabled.
+.It Dv MNT_LOCAL
+The file system resides locally.
+.It Dv MNT_QUOTA
+The file system has quotas enabled on it.
+.It Dv MNT_ROOTFS
+Identifies the root file system.
+.It Dv MNT_EXRDONLY
+The file system is exported read-only.
+.It Dv MNT_NOATIME
+Updating of file access times is disabled.
+.It Dv MNT_USER
+The file system has been mounted by a user.
+.\".It Dv MNT_IGNORE
+.\"XXX
+.It Dv MNT_EXPORTED
+The file system is exported for both reading and writing.
+.It Dv MNT_DEFEXPORTED
+The file system is exported for both reading and writing to any Internet host.
+.It Dv MNT_EXPORTANON
+The file system maps all remote accesses to the anonymous user.
+.It Dv MNT_EXKERB
+The file system is exported with Kerberos uid mapping.
+.It Dv MNT_EXPUBLIC
+The file system is exported publicly (WebNFS).
+.El
+.Pp
+Fields that are undefined for a particular file system are set to -1.
+The
+.Fn fstatfs
+system call
+returns the same information about an open file referenced by descriptor
+.Fa fd .
+.Sh RETURN VALUES
+.Rv -std
+.Sh ERRORS
+The
+.Fn statfs
+system call
+fails if one or more of the following are true:
+.Bl -tag -width Er
+.It Bq Er ENOTDIR
+A component of the path prefix of
+.Fa path
+is not a directory.
+.It Bq Er ENAMETOOLONG
+The length of a component of
+.Fa path
+exceeds 255 characters,
+or the length of
+.Fa path
+exceeds 1023 characters.
+.It Bq Er ENOENT
+The file referred to by
+.Fa path
+does not exist.
+.It Bq Er EACCES
+Search permission is denied for a component of the path prefix of
+.Fa path .
+.It Bq Er ELOOP
+Too many symbolic links were encountered in translating
+.Fa path .
+.It Bq Er EFAULT
+The
+.Fa buf
+or
+.Fa path
+argument
+points to an invalid address.
+.It Bq Er EIO
+An
+.Tn I/O
+error occurred while reading from or writing to the file system.
+.El
+.Pp
+The
+.Fn fstatfs
+system call
+fails if one or more of the following are true:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa fd
+argument
+is not a valid open file descriptor.
+.It Bq Er EFAULT
+The
+.Fa buf
+argument
+points to an invalid address.
+.It Bq Er EIO
+An
+.Tn I/O
+error occurred while reading from or writing to the file system.
+.El
+.Sh SEE ALSO
+.Xr fhstatfs 2
+.Sh HISTORY
+The
+.Fn statfs
+system call first appeared in
+.Bx 4.4 .
diff --git a/lib/libc/sys/swapcontext.c b/lib/libc/sys/swapcontext.c
new file mode 100644
index 000000000000..0a8125eeabb5
--- /dev/null
+++ b/lib/libc/sys/swapcontext.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2001 Daniel M. Eischen <deischen@freebsd.org>
+ * Copyright (c) 2014 The FreeBSD Foundation.
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Konstantin Belousov
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Neither the name of the author nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/signal.h>
+#include <sys/ucontext.h>
+#include <errno.h>
+#include <stddef.h>
+#include "libc_private.h"
+
+__weak_reference(__sys_swapcontext, __swapcontext);
+__sym_compat(swapcontext, __impl_swapcontext, FBSD_1.0);
+__weak_reference(swapcontext, __impl_swapcontext);
+__sym_default(swapcontext, swapcontext, FBSD_1.2);
+
+#pragma weak swapcontext
+int
+swapcontext(ucontext_t *oucp, const ucontext_t *ucp)
+{
+
+ return (((int (*)(ucontext_t *, const ucontext_t *))
+ __libc_interposing[INTERPOS_swapcontext])(oucp, ucp));
+}
diff --git a/lib/libc/sys/swapon.2 b/lib/libc/sys/swapon.2
new file mode 100644
index 000000000000..6879513ce300
--- /dev/null
+++ b/lib/libc/sys/swapon.2
@@ -0,0 +1,143 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)swapon.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd October 4, 2013
+.Dt SWAPON 2
+.Os
+.Sh NAME
+.Nm swapon , swapoff
+.Nd control devices for interleaved paging/swapping
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft int
+.Fn swapon "const char *special"
+.Ft int
+.Fn swapoff "const char *special"
+.Sh DESCRIPTION
+The
+.Fn swapon
+system call
+makes the block device
+.Fa special
+available to the system for
+allocation for paging and swapping.
+The names of potentially
+available devices are known to the system and defined at system
+configuration time.
+The size of the swap area on
+.Fa special
+is calculated at the time the device is first made available
+for swapping.
+.Pp
+The
+.Fn swapoff
+system call disables paging and swapping on the given device.
+All associated swap metadata are deallocated, and the device
+is made available for other purposes.
+.Sh RETURN VALUES
+If an error has occurred, a value of -1 is returned and
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+Both
+.Fn swapon
+and
+.Fn swapoff
+can fail if:
+.Bl -tag -width Er
+.It Bq Er ENOTDIR
+A component of the path prefix is not a directory.
+.It Bq Er ENAMETOOLONG
+A component of a pathname exceeded 255 characters,
+or an entire path name exceeded 1023 characters.
+.It Bq Er ENOENT
+The named device does not exist.
+.It Bq Er EACCES
+Search permission is denied for a component of the path prefix.
+.It Bq Er ELOOP
+Too many symbolic links were encountered in translating the pathname.
+.It Bq Er EPERM
+The caller is not the super-user.
+.It Bq Er EFAULT
+The
+.Fa special
+argument
+points outside the process's allocated address space.
+.El
+.Pp
+Additionally,
+.Fn swapon
+can fail for the following reasons:
+.Bl -tag -width Er
+.It Bq Er ENOTBLK
+The
+.Fa special
+argument
+is not a block device.
+.It Bq Er EBUSY
+The device specified by
+.Fa special
+has already
+been made available for swapping
+.It Bq Er ENXIO
+The major device number of
+.Fa special
+is out of range (this indicates no device driver exists
+for the associated hardware).
+.It Bq Er EIO
+An I/O error occurred while opening the swap device.
+.El
+.Pp
+Lastly,
+.Fn swapoff
+can fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The system is not currently swapping to
+.Fa special .
+.It Bq Er ENOMEM
+Not enough virtual memory is available to safely disable
+paging and swapping to the given device.
+.El
+.Sh SEE ALSO
+.Xr config 8 ,
+.Xr swapon 8 ,
+.Xr sysctl 8
+.Sh HISTORY
+The
+.Fn swapon
+system call appeared in
+.Bx 4.0 .
+The
+.Fn swapoff
+system call appeared in
+.Fx 5.0 .
diff --git a/lib/libc/sys/symlink.2 b/lib/libc/sys/symlink.2
new file mode 100644
index 000000000000..bfe2ede25f8a
--- /dev/null
+++ b/lib/libc/sys/symlink.2
@@ -0,0 +1,206 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)symlink.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd April 10, 2008
+.Dt SYMLINK 2
+.Os
+.Sh NAME
+.Nm symlink ,
+.Nm symlinkat
+.Nd make symbolic link to a file
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft int
+.Fn symlink "const char *name1" "const char *name2"
+.Ft int
+.Fn symlinkat "const char *name1" "int fd" "const char *name2"
+.Sh DESCRIPTION
+A symbolic link
+.Fa name2
+is created to
+.Fa name1
+.Fa ( name2
+is the name of the
+file created,
+.Fa name1
+is the string
+used in creating the symbolic link).
+Either name may be an arbitrary path name; the files need not
+be on the same file system.
+.Pp
+The
+.Fn symlinkat
+system call is equivalent to
+.Fn symlink
+except in the case where
+.Fa name2
+specifies a relative path.
+In this case the symbolic link is created relative to the directory
+associated with the file descriptor
+.Fa fd
+instead of the current working directory.
+If
+.Fn symlinkat
+is passed the special value
+.Dv AT_FDCWD
+in the
+.Fa fd
+parameter, the current working directory is used and the behavior is
+identical to a call to
+.Fn symlink .
+.Sh RETURN VALUES
+.Rv -std symlink
+.Sh ERRORS
+The symbolic link succeeds unless:
+.Bl -tag -width Er
+.It Bq Er ENOTDIR
+A component of the
+.Fa name2
+path prefix is not a directory.
+.It Bq Er ENAMETOOLONG
+A component of the
+.Fa name2
+pathname exceeded 255 characters,
+or the entire length of either path name exceeded 1023 characters.
+.It Bq Er ENOENT
+A component of the
+.Fa name2
+path prefix does not exist.
+.It Bq Er EACCES
+A component of the
+.Fa name2
+path prefix denies search permission, or write permission is denied on the
+parent directory of the file to be created.
+.It Bq Er ELOOP
+Too many symbolic links were encountered in translating the
+.Fa name2
+path name.
+.It Bq Er EEXIST
+The path name pointed at by the
+.Fa name2
+argument
+already exists.
+.It Bq Er EPERM
+The parent directory of the file named by
+.Fa name2
+has its immutable flag set, see the
+.Xr chflags 2
+manual page for more information.
+.It Bq Er EIO
+An I/O error occurred while making the directory entry for
+.Fa name2 ,
+or allocating the inode for
+.Fa name2 ,
+or writing out the link contents of
+.Fa name2 .
+.It Bq Er EROFS
+The file
+.Fa name2
+would reside on a read-only file system.
+.It Bq Er ENOSPC
+The directory in which the entry for the new symbolic link is being placed
+cannot be extended because there is no space left on the file
+system containing the directory.
+.It Bq Er ENOSPC
+The new symbolic link cannot be created because
+there is no space left on the file
+system that will contain the symbolic link.
+.It Bq Er ENOSPC
+There are no free inodes on the file system on which the
+symbolic link is being created.
+.It Bq Er EDQUOT
+The directory in which the entry for the new symbolic link
+is being placed cannot be extended because the
+user's quota of disk blocks on the file system
+containing the directory has been exhausted.
+.It Bq Er EDQUOT
+The new symbolic link cannot be created because the user's
+quota of disk blocks on the file system that will
+contain the symbolic link has been exhausted.
+.It Bq Er EDQUOT
+The user's quota of inodes on the file system on
+which the symbolic link is being created has been exhausted.
+.It Bq Er EIO
+An I/O error occurred while making the directory entry or allocating the inode.
+.It Bq Er EFAULT
+The
+.Fa name1
+or
+.Fa name2
+argument
+points outside the process's allocated address space.
+.El
+.Pp
+In addition to the errors returned by the
+.Fn symlink ,
+the
+.Fn symlinkat
+may fail if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa name2
+argument does not specify an absolute path and the
+.Fa fd
+argument is neither
+.Dv AT_FDCWD
+nor a valid file descriptor open for searching.
+.It Bq Er ENOTDIR
+The
+.Fa name2
+argument is not an absolute path and
+.Fa fd
+is neither
+.Dv AT_FDCWD
+nor a file descriptor associated with a directory.
+.El
+.Sh SEE ALSO
+.Xr ln 1 ,
+.Xr chflags 2 ,
+.Xr link 2 ,
+.Xr lstat 2 ,
+.Xr readlink 2 ,
+.Xr unlink 2 ,
+.Xr symlink 7
+.Sh STANDARDS
+The
+.Fn symlinkat
+system call follows The Open Group Extended API Set 2 specification.
+.Sh HISTORY
+The
+.Fn symlink
+system call appeared in
+.Bx 4.2 .
+The
+.Fn symlinkat
+system call appeared in
+.Fx 8.0 .
diff --git a/lib/libc/sys/sync.2 b/lib/libc/sys/sync.2
new file mode 100644
index 000000000000..06d5e935c6b2
--- /dev/null
+++ b/lib/libc/sys/sync.2
@@ -0,0 +1,77 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)sync.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt SYNC 2
+.Os
+.Sh NAME
+.Nm sync
+.Nd "schedule file system updates"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft void
+.Fn sync void
+.Sh DESCRIPTION
+The
+.Fn sync
+system call forces a write of dirty (modified) buffers
+in the block buffer cache out
+to disk.
+The kernel keeps this information in core to reduce
+the number of disk I/O transfers required by the system.
+As information in the cache is lost after a system crash, a
+.Fn sync
+system call is issued
+frequently
+by the kernel process
+.Xr syncer 4
+(about every 30 seconds).
+.Pp
+The
+.Xr fsync 2
+system call
+may be used to synchronize individual file descriptor
+attributes.
+.Sh SEE ALSO
+.Xr fsync 2 ,
+.Xr syncer 4 ,
+.Xr sync 8
+.Sh HISTORY
+The
+.Fn sync
+function appeared in
+.At v6 .
+.Sh BUGS
+The
+.Fn sync
+system call
+may return before the buffers are completely flushed.
diff --git a/lib/libc/sys/sysarch.2 b/lib/libc/sys/sysarch.2
new file mode 100644
index 000000000000..bd060d17790c
--- /dev/null
+++ b/lib/libc/sys/sysarch.2
@@ -0,0 +1,81 @@
+.\" $NetBSD: sysarch.2,v 1.6 1998/02/25 21:24:57 perry Exp $
+.\" $FreeBSD$
+.\"
+.\" Copyright (c) 1980, 1991 Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" from: @(#)syscall.2 6.3 (Berkeley) 3/10/91
+.\"
+.Dd October 11, 1993
+.Dt SYSARCH 2
+.Os
+.Sh NAME
+.Nm sysarch
+.Nd architecture-dependent system call
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In machine/sysarch.h
+.Ft int
+.Fn sysarch "int number" "void *args"
+.Sh DESCRIPTION
+The
+.Fn sysarch
+system call
+performs the architecture-dependent function
+specified by
+.Fa number
+with the arguments specified by the
+.Fa args
+pointer.
+The
+.Fa args
+argument
+is a pointer to a structure defining the actual
+arguments of the function.
+Symbolic constants and argument structures
+for the architecture-dependent
+functions can be found in the header file
+.In machine/sysarch.h .
+.Pp
+The
+.Fn sysarch
+system call should never be called directly by
+user programs.
+Instead, they should access
+its functions using the architecture-dependent
+library.
+.Sh RETURN VALUES
+See the manual pages for specific architecture-dependent system calls
+for information about their return values.
+.Sh SEE ALSO
+.Xr i386_get_ioperm 2 ,
+.Xr i386_get_ldt 2 ,
+.Xr i386_vm86 2
+.Sh HISTORY
+This manual page was taken from
+.Nx .
diff --git a/lib/libc/sys/syscall.2 b/lib/libc/sys/syscall.2
new file mode 100644
index 000000000000..a9402d62bcf7
--- /dev/null
+++ b/lib/libc/sys/syscall.2
@@ -0,0 +1,77 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)syscall.2 8.1 (Berkeley) 6/16/93
+.\" $FreeBSD$
+.\"
+.Dd June 16, 1993
+.Dt SYSCALL 2
+.Os
+.Sh NAME
+.Nm syscall ,
+.Nm __syscall
+.Nd indirect system call
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/syscall.h
+.In unistd.h
+.Ft int
+.Fn syscall "int number" ...
+.Ft off_t
+.Fn __syscall "quad_t number" ...
+.Sh DESCRIPTION
+The
+.Fn syscall
+function
+performs the system call whose assembly language
+interface has the specified
+.Fa number
+with the specified arguments.
+Symbolic constants for system calls can be found in the header file
+.In sys/syscall.h .
+The
+.Fn __syscall
+form should be used when one or more of the arguments is a
+64-bit argument to ensure that argument alignment is correct.
+This system call is useful for testing new system calls that
+do not have entries in the C library.
+.Sh RETURN VALUES
+The return values are defined by the system call being invoked.
+In general, a 0 return value indicates success.
+A -1 return value indicates an error,
+and an error code is stored in
+.Va errno .
+.Sh HISTORY
+The
+.Fn syscall
+function appeared in
+.Bx 4.0 .
+.Sh BUGS
+There is no way to simulate system calls that have multiple return values
+such as
+.Xr pipe 2 .
diff --git a/lib/libc/sys/thr_exit.2 b/lib/libc/sys/thr_exit.2
new file mode 100644
index 000000000000..781b07fde7e8
--- /dev/null
+++ b/lib/libc/sys/thr_exit.2
@@ -0,0 +1,90 @@
+.\" Copyright (c) 2016 The FreeBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" 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:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd June 1, 2016
+.Dt THR_EXIT 2
+.Os
+.Sh NAME
+.Nm thr_exit
+.Nd terminate current thread
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/thr.h
+.Ft void
+.Fn thr_exit "long *state"
+.Sh DESCRIPTION
+.Bf -symbolic
+This function is intended for implementing threading.
+Normal applications should call
+.Xr pthread_exit 3
+instead.
+.Ef
+.Pp
+The
+.Fn thr_exit
+system call terminates the current kernel-scheduled thread.
+.Pp
+If the
+.Fa state
+argument is not
+.Dv NULL ,
+the location pointed to by the argument is
+updated with an arbitrary non-zero value, and an
+.Xr _umtx_op 2
+.Dv UMTX_OP_WAKE
+operation is consequently performed on the location.
+.Pp
+Attempts to terminate the last thread in the process are silently ignored.
+Use
+.Xr _exit 2
+syscall to terminate the process.
+.Sh RETURN VALUES
+The function does not return a value.
+A return from the function indicates that the calling thread was the
+last one in the process.
+.Sh SEE ALSO
+.Xr _exit 2 ,
+.Xr thr_kill 2 ,
+.Xr thr_kill2 2 ,
+.Xr thr_new 2 ,
+.Xr thr_self 2 ,
+.Xr thr_set_name 2 ,
+.Xr _umtx_op 2 ,
+.Xr pthread_exit 3
+.Sh STANDARDS
+The
+.Fn thr_exit
+system call is non-standard and is used by
+.Lb libthr
+to implement
+.St -p1003.1-2001
+.Xr pthread 3
+functionality.
diff --git a/lib/libc/sys/thr_kill.2 b/lib/libc/sys/thr_kill.2
new file mode 100644
index 000000000000..04293aa59ee7
--- /dev/null
+++ b/lib/libc/sys/thr_kill.2
@@ -0,0 +1,133 @@
+.\" Copyright (c) 2016 The FreeBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" 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:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd June 1, 2016
+.Dt THR_kill 2
+.Os
+.Sh NAME
+.Nm thr_kill
+.Nd send signal to thread
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/thr.h
+.Ft int
+.Fn thr_kill "long id" "int sig"
+.Ft int
+.Fn thr_kill2 "pid_t pid" "long id" "int sig"
+.Sh DESCRIPTION
+The
+.Fn thr_kill
+and
+.Fn thr_kill2
+system calls allow sending a signal, specified by the
+.Fa sig
+argument, to some threads in a process.
+For the
+.Fn thr_kill
+function, signalled threads are always limited to the current process.
+For the
+.Fn thr_kill2
+function, the
+.Fa pid
+argument specifies the process with threads to be signalled.
+.Pp
+The
+.Fa id
+argument specifies which threads get the signal.
+If
+.Fa id
+is equal to \-1, all threads in the specified process are signalled.
+Otherwise, only the thread with the thread identifier equal to the
+argument is signalled.
+.Pp
+The
+.Fa sig
+argument defines the delivered signal.
+It must be a valid signal number or zero.
+In the latter case no signal is actually sent, and the call is used to
+verify the liveness of the thread.
+.Pp
+The signal is delivered with
+.Dv siginfo
+.Dv si_code
+set to
+.Dv SI_LWP .
+.Sh RETURN VALUES
+If successful,
+.Fn thr_kill
+and
+.Fn thr_kill2
+will return zero, otherwise \-1 is returned, and
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+The
+.Fn thr_kill
+and
+.Fn thr_kill2
+operations return the following errors:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa sig
+argument is not zero and does not specify valid signal.
+.It Bq Er ESRCH
+The specified process or thread was not found.
+.El
+.Pp
+Additionally, the
+.Fn thr_kill2
+may return the following errors:
+.Bl -tag -width Er
+.It Bq Er EPERM
+The current process does not have sufficient privilege to check existence or
+send a signal to the specified process.
+.El
+.Sh SEE ALSO
+.Xr kill 2 ,
+.Xr thr_exit 2 ,
+.Xr thr_new 2 ,
+.Xr thr_self 2 ,
+.Xr thr_set_name 2 ,
+.Xr _umtx_op 2 ,
+.Xr pthread_kill 3 ,
+.Xr signal 3
+.Sh STANDARDS
+The
+.Fn thr_kill
+and
+.Fn thr_kill2
+system calls are non-standard and are used by the
+.Lb libthr
+to implement
+.St -p1003.1-2001
+.Xr pthread 3
+functionality.
diff --git a/lib/libc/sys/thr_new.2 b/lib/libc/sys/thr_new.2
new file mode 100644
index 000000000000..27f4191ae8b5
--- /dev/null
+++ b/lib/libc/sys/thr_new.2
@@ -0,0 +1,245 @@
+.\" Copyright (c) 2016 The FreeBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" 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:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd June 2, 2016
+.Dt THR_NEW 2
+.Os
+.Sh NAME
+.Nm thr_new
+.Nd create new thread of execution
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/thr.h
+.Ft int
+.Fn thr_new "struct thr_param *param" "int param_size"
+.Sh DESCRIPTION
+.Bf -symbolic
+This function is intended for implementing threading.
+Normal applications should call
+.Xr pthread_create 3
+instead.
+.Ef
+.Pp
+The
+.Fn thr_new
+system call creates a new kernel-scheduled thread of execution in the context
+of the current process.
+The newly created thread shares all attributes of the process with the
+existing kernel-scheduled threads in the process, but has private processor
+execution state.
+The machine context for the new thread is copied from the creating thread's
+context, including coprocessor state.
+FPU state and specific machine registers are excluded from the copy.
+These are set according to ABI requirements and syscall parameters.
+The FPU state for the new thread is reinitialized to clean.
+.Pp
+The
+.Fa param
+structure supplies parameters affecting the thread creation.
+The structure is defined in the
+.In sys/thr.h
+header as follows
+.Bd -literal
+struct thr_param {
+ void (*start_func)(void *);
+ void *arg;
+ char *stack_base;
+ size_t stack_size;
+ char *tls_base;
+ size_t tls_size;
+ long *child_tid;
+ long *parent_tid;
+ int flags;
+ struct rtprio *rtp;
+};
+.Ed
+and contains the following fields:
+.Bl -tag -width ".Va parent_tid"
+.It Va start_func
+Pointer to the thread entry function.
+The kernel arranges for the new thread to start executing the function
+upon the first return to userspace.
+.It Va arg
+Opaque argument supplied to the entry function.
+.It Va stack_base
+Stack base address.
+The stack must be allocated by the caller.
+On some architectures, the ABI might require that the system put information
+on the stack to ensure the execution environment for
+.Va start_func .
+.It Va stack_size
+Stack size.
+.It Va tls_base
+TLS base address.
+The value of TLS base is loaded into the ABI-defined machine register
+in the new thread context.
+.It Va tls_size
+TLS size.
+.It Va child_tid
+Address to store the new thread identifier, for the child's use.
+.It Va parent_tid
+Address to store the new thread identifier, for the parent's use.
+.Pp
+Both
+.Va child_tid
+and
+.Va parent_tid
+are provided, with the intent that
+.Va child_tid
+is used by the new thread to get its thread identifier without
+issuing the
+.Xr thr_self 2
+syscall, while
+.Va parent_tid
+is used by the thread creator.
+The latter is separate from
+.Va child_tid
+because the new thread might exit and free its thread data before the parent
+has a chance to execute far enough to access it.
+.It Va flags
+Thread creation flags.
+The
+.Va flags
+member may specify the following flags:
+.Bl -tag -width ".Dv THR_SYSTEM_SCOPE"
+.It Dv THR_SUSPENDED
+Create the new thread in the suspended state.
+The flag is not currently implemented.
+.It Dv THR_SYSTEM_SCOPE
+Create the system scope thread.
+The flag is not currently implemented.
+.El
+.It Va rtp
+Real-time scheduling priority for the new thread.
+May be
+.Dv NULL
+to inherit the priority from the
+creating thread.
+.El
+.Pp
+The
+.Fa param_size
+argument should be set to the size of the
+.Fa param
+structure.
+.Pp
+After the first successful creation of an additional thread,
+the process is marked by the kernel as multi-threaded.
+In particular, the
+.Dv P_HADTHREADS
+flag is set in the process'
+.Dv p_flag
+(visible in the
+.Xr ps 1
+output), and several operations are executed in multi-threaded mode.
+For instance, the
+.Xr execve 2
+system call terminates all threads but the calling one on successful
+execution.
+.Sh RETURN VALUES
+If successful,
+.Fn thr_new
+will return zero, otherwise \-1 is returned, and
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+The
+.Fn thr_new
+operation returns the following errors:
+.Bl -tag -width Er
+.\" When changing this list, consider updating share/man/man3/pthread_create.3,
+.\" since that function can return any of these errors.
+.It Bq Er EFAULT
+The memory pointed to by the
+.Fa param
+argument is not valid.
+.It Bq Er EFAULT
+The memory pointed to by the
+.Fa param
+structure
+.Fa child_tid , parent_tid
+or
+.Fa rtp
+arguments is not valid.
+.It Bq Er EFAULT
+The specified stack base is invalid, or the kernel was unable to put required
+initial data on the stack.
+.It Bq Er EINVAL
+The
+.Fa param_size
+argument specifies a negative value, or the value is greater than the
+largest
+.Fa struct param
+size the kernel can interpret.
+.It Bq Er EINVAL
+The
+.Fa rtp
+member is not
+.Dv NULL
+and specifies invalid scheduling parameters.
+.It Bq Er EINVAL
+The specified TLS base is invalid.
+.It Bq Er EPERM
+The caller does not have permission to set the scheduling parameters or
+scheduling policy.
+.It Bq Er EPROCLIM
+Creation of the new thread would exceed the
+.Dv RACCT_NTHR
+limit, see
+.Xr racct 2 .
+.It Bq Er EPROCLIM
+Creation of the new thread would exceed the
+.Dv kern.threads.max_threads_per_proc
+.Xr sysctl 2
+limit.
+.It Bq Er ENOMEM
+There was not enough kernel memory to allocate the new thread structures.
+.El
+.Sh SEE ALSO
+.Xr ps 1 ,
+.Xr execve 2 ,
+.Xr racct 2 ,
+.Xr thr_exit 2 ,
+.Xr thr_kill 2 ,
+.Xr thr_kill2 2 ,
+.Xr thr_self 2 ,
+.Xr thr_set_name 2 ,
+.Xr _umtx_op 2 ,
+.Xr pthread_create 3
+.Sh STANDARDS
+The
+.Fn thr_new
+system call is non-standard and is used by the
+.Lb libthr
+to implement
+.St -p1003.1-2001
+.Xr pthread 3
+functionality.
diff --git a/lib/libc/sys/thr_self.2 b/lib/libc/sys/thr_self.2
new file mode 100644
index 000000000000..949b600a17f7
--- /dev/null
+++ b/lib/libc/sys/thr_self.2
@@ -0,0 +1,90 @@
+.\" Copyright (c) 2016 The FreeBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" 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:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd June 1, 2016
+.Dt THR_SELF 2
+.Os
+.Sh NAME
+.Nm thr_self
+.Nd return thread identifier for the calling thread
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/thr.h
+.Ft int
+.Fn thr_self "long *id"
+.Sh DESCRIPTION
+The
+.Fn thr_self
+system call stores the system-wide thread identifier for the current
+kernel-scheduled thread in the variable pointed by the argument
+.Va id .
+.Pp
+The thread identifier is an integer in the range from
+.Dv PID_MAX + 2
+(10002) to
+.Dv INT_MAX .
+The thread identifier is guaranteed to be unique at any given time,
+for each running thread in the system.
+After the thread exits, the identifier may be reused.
+.Sh RETURN VALUES
+If successful,
+.Fn thr_self
+will return zero, otherwise \-1 is returned, and
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+The
+.Fn thr_self
+operation may return the following errors:
+.Bl -tag -width Er
+.It Bq Er EFAULT
+The memory pointed to by the
+.Fa id
+argument is not valid.
+.El
+.Sh SEE ALSO
+.Xr thr_exit 2 ,
+.Xr thr_kill 2 ,
+.Xr thr_kill2 2 ,
+.Xr thr_new 2 ,
+.Xr thr_set_name 2 ,
+.Xr _umtx_op 2 ,
+.Xr pthread_getthreadid_np 3 ,
+.Xr pthread_self 3
+.Sh STANDARDS
+The
+.Fn thr_self
+system call is non-standard and is used by
+.Lb libthr
+to implement
+.St -p1003.1-2001
+.Xr pthread 3
+functionality.
diff --git a/lib/libc/sys/thr_set_name.2 b/lib/libc/sys/thr_set_name.2
new file mode 100644
index 000000000000..a83e53109491
--- /dev/null
+++ b/lib/libc/sys/thr_set_name.2
@@ -0,0 +1,94 @@
+.\" Copyright (c) 2016 The FreeBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" 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:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd December 2, 2016
+.Dt THR_SET_NAME 2
+.Os
+.Sh NAME
+.Nm thr_set_name
+.Nd set user-visible thread name
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/thr.h
+.Ft int
+.Fn thr_set_name "long id" "const char *name"
+.Sh DESCRIPTION
+The
+.Fn thr_set_name
+system call sets the user-visible name for the thread with the identifier
+.Va id
+in the current process to the NUL-terminated string
+.Va name .
+The name will be silently truncated to fit into a buffer of
+.Dv MAXCOMLEN + 1
+bytes.
+The thread name can be seen in the output of the
+.Xr ps 1
+and
+.Xr top 1
+commands, in the kernel debuggers and kernel tracing facility outputs,
+and in userland debuggers and program core files, as notes.
+.Sh RETURN VALUES
+If successful,
+.Fn thr_set_name
+returns zero; otherwise, \-1 is returned, and
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+The
+.Fn thr_set_name
+system call may return the following errors:
+.Bl -tag -width Er
+.It Bq Er EFAULT
+The memory pointed to by the
+.Fa name
+argument is not valid.
+.It Bq Er ESRCH
+The thread with the identifier
+.Fa id
+does not exist in the current process.
+.El
+.Sh SEE ALSO
+.Xr ps 1 ,
+.Xr thr_exit 2 ,
+.Xr thr_kill 2 ,
+.Xr thr_kill2 2 ,
+.Xr thr_new 2 ,
+.Xr thr_self 2 ,
+.Xr _umtx_op 2 ,
+.Xr pthread_set_name_np 3 ,
+.Xr ddb 4 ,
+.Xr ktr 9
+.Sh STANDARDS
+The
+.Fn thr_set_name
+system call is non-standard and is used by the
+.Lb libthr .
diff --git a/lib/libc/sys/thr_suspend.2 b/lib/libc/sys/thr_suspend.2
new file mode 100644
index 000000000000..b470d189e45b
--- /dev/null
+++ b/lib/libc/sys/thr_suspend.2
@@ -0,0 +1,130 @@
+.\" Copyright (c) 2016 The FreeBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" 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:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd September 23, 2016
+.Dt THR_SUSPEND 2
+.Os
+.Sh NAME
+.Nm thr_suspend
+.Nd suspend the calling thread
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/thr.h
+.Ft int
+.Fn thr_suspend "struct timespec *timeout"
+.Sh DESCRIPTION
+.Bf -symbolic
+This function is intended for implementing threading.
+Normal applications should use
+.Xr pthread_cond_timedwait 3
+together with
+.Xr pthread_cond_broadcast 3
+for typical safe suspension with cooperation of the thread
+being suspended, or
+.Xr pthread_suspend_np 3
+and
+.Xr pthread_resume_np 3
+in some specific situations, instead.
+.Ef
+.Pp
+The
+.Fn thr_suspend
+system call puts the calling thread in a suspended state, where it is
+not eligible for CPU time.
+This state is exited by another thread calling
+.Xr thr_wake 2 ,
+when the time interval specified by
+.Fa timeout
+has elapsed,
+or by the delivery of a signal to the suspended thread.
+.Pp
+If the
+.Fa timeout
+argument is
+.Dv NULL ,
+the suspended state can be only terminated by explicit
+.Fn thr_wake
+or signal.
+.Pp
+If a wake from
+.Xr thr_wake 2
+was delivered before the
+.Nm
+call, the thread is not put into a suspended state.
+Instead, the call
+returns immediately without an error.
+.Pp
+If a thread previously called
+.Xr thr_wake 2
+with its own thread identifier, which resulted in setting the internal kernel
+flag to immediately abort interruptible sleeps with an
+.Er EINTR
+error
+.Po
+see
+.Xr thr_wake 2
+.Pc ,
+the flag is cleared.
+As with
+.Xr thr_wake 2
+called from another thread, the next
+.Nm
+call does not result in suspension.
+.Pp
+.Sh RETURN VALUES
+.Rv -std thr_suspend
+.Sh ERRORS
+The
+.Fn thr_suspend
+operation returns the following errors:
+.Bl -tag -width Er
+.It Bq Er EFAULT
+The memory pointed to by the
+.Fa timeout
+argument is not valid.
+.It Bq Er ETIMEDOUT
+The specified timeout expired.
+.It Bq Er ETIMEDOUT
+The
+.Fa timeout
+argument specified a zero time interval.
+.It Bq Er EINTR
+The sleep was interrupted by a signal.
+.El
+.Sh SEE ALSO
+.Xr ps 1 ,
+.Xr thr_wake 2 ,
+.Xr pthread_resume_np 3 ,
+.Xr pthread_suspend_np 3
+.Sh STANDARDS
+The
+.Fn thr_suspend
+system call is non-standard.
diff --git a/lib/libc/sys/thr_wake.2 b/lib/libc/sys/thr_wake.2
new file mode 100644
index 000000000000..59df7d2c903a
--- /dev/null
+++ b/lib/libc/sys/thr_wake.2
@@ -0,0 +1,112 @@
+.\" Copyright (c) 2016 The FreeBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" 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:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd September 23, 2016
+.Dt THR_WAKE 2
+.Os
+.Sh NAME
+.Nm thr_wake
+.Nd wake up the suspended thread
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/thr.h
+.Ft int
+.Fn thr_wake "long id"
+.Sh DESCRIPTION
+.Bf -symbolic
+This function is intended for implementing threading.
+Normal applications should use
+.Xr pthread_cond_timedwait 3
+together with
+.Xr pthread_cond_broadcast 3
+for typical safe suspension with cooperation of the thread
+being suspended, or
+.Xr pthread_suspend_np 3
+and
+.Xr pthread_resume_np 3
+in some specific situations, instead.
+.Ef
+.Pp
+Passing the thread identifier of the calling thread
+.Po
+see
+.Xr thr_self 2
+.Pc
+to
+.Fn thr_wake
+sets a thread's flag to cause the next signal-interruptible sleep
+of that thread in the kernel to fail immediately with the
+.Er EINTR
+error.
+The flag is cleared by an interruptible sleep attempt or by a call to
+.Xr thr_suspend 2.
+This is used by the system threading library to implement cancellation.
+.Pp
+If
+.Fa id
+is not equal to the current thread identifier, the specified thread is
+woken up if suspended by the
+.Xr thr_suspend
+system call.
+If the thread is not suspended at the time of the
+.Nm
+call, the wake is remembered and the next attempt of the thread to
+suspend itself with the
+.Xr thr_suspend 2
+results in immediate return with success.
+Only one wake is remembered.
+.Sh RETURN VALUES
+.Rv -std thr_wake
+.Sh ERRORS
+The
+.Fn thr_wake
+operation returns these errors:
+.Bl -tag -width Er
+.It Bq Er ESRCH
+The specified thread was not found or does not belong to the process
+of the calling thread.
+.El
+.Sh SEE ALSO
+.Xr ps 1 ,
+.Xr thr_self 2
+.Xr thr_suspend 2 ,
+.Xr pthread_cancel 3 ,
+.Xr pthread_resume_np 3 ,
+.Xr pthread_suspend_np 3
+.Sh STANDARDS
+The
+.Fn thr_suspend
+system call is non-standard and is used by
+.Lb libthr
+to implement
+.St -p1003.1-2001
+.Xr pthread 3
+functionality.
diff --git a/lib/libc/sys/timer_create.2 b/lib/libc/sys/timer_create.2
new file mode 100644
index 000000000000..1dd0cd5d1fac
--- /dev/null
+++ b/lib/libc/sys/timer_create.2
@@ -0,0 +1,200 @@
+.\" Copyright (c) 2005 David Xu <davidxu@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice(s), this list of conditions and the following disclaimer as
+.\" the first lines of this file unmodified other than the possible
+.\" addition of one or more copyright notices.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice(s), this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+.\" EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+.\" OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+.\" EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd July 15, 2016
+.Dt TIMER_CREATE 2
+.Os
+.Sh NAME
+.Nm timer_create
+.Nd "create a per-process timer (REALTIME)"
+.Sh LIBRARY
+.Lb librt
+.Sh SYNOPSIS
+.In time.h
+.In signal.h
+.Ft int
+.Fo timer_create
+.Fa "clockid_t clockid" "struct sigevent *restrict evp"
+.Fa "timer_t *restrict timerid"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn timer_create
+system call creates a per-process timer using the specified clock,
+.Fa clock_id ,
+as the timing base.
+The
+.Fn timer_create
+system call returns, in the location referenced by
+.Fa timerid ,
+a timer ID of type
+.Vt timer_t
+used to identify the timer in timer requests.
+This timer ID is unique within the calling process until the timer is deleted.
+The particular clock,
+.Fa clock_id ,
+is defined in
+.In time.h .
+The timer whose ID is returned is in a disarmed state upon return from
+.Fn timer_create .
+.Pp
+The
+.Fa evp
+argument, if
+.Pf non- Dv NULL ,
+points to a
+.Vt sigevent
+structure.
+This structure,
+allocated by the application, defines the asynchronous notification to occur
+when the timer expires.
+.Pp
+If
+.Fa evp->sigev_notify
+is
+.Dv SIGEV_SIGNO
+or
+.Dv SIGEV_THREAD_ID ,
+the signal specified in
+.Fa evp->sigev_signo
+will be sent to the calling process
+.Pq Dv SIGEV_SIGNO
+or to the thread whose LWP ID is
+.Fa evp->sigev_notify_thread_id
+.Pq Dv SIGEV_THREAD_ID .
+The information for the queued signal will include:
+.Bl -column ".Va si_value"
+.It Sy Member Ta Sy Value
+.It Va si_code Ta Dv SI_TIMER
+.It Va si_value Ta
+the value stored in
+.Fa evp->sigev_value
+.It Va si_timerid Ta timer ID
+.It Va si_overrun Ta timer overrun count
+.It Va si_errno Ta
+If timer overrun is
+.Brq Dv DELAYTIMER_MAX ,
+an error code defined in
+.In errno.h
+.El
+.Pp
+If the
+.Fa evp
+argument is
+.Dv NULL ,
+the effect is as if the
+.Fa evp
+argument pointed to a
+.Vt sigevent
+structure with the
+.Va sigev_notify
+member having the value
+.Dv SIGEV_SIGNAL ,
+the
+.Va sigev_signo
+having a default signal number
+.Pq Dv SIGALRM ,
+and the
+.Va sigev_value
+member having
+the value of the timer ID.
+.Pp
+This implementation supports a
+.Fa clock_id
+of
+.Dv CLOCK_REALTIME
+or
+.Dv CLOCK_MONOTONIC .
+.Pp
+If
+.Fa evp->sigev_notify
+is
+.Dv SIGEV_THREAD
+and
+.Fa sev->sigev_notify_attributes
+is not
+.Dv NULL ,
+if the attribute pointed to by
+.Fa sev->sigev_notify_attributes
+has
+a thread stack address specified by a call to
+.Fn pthread_attr_setstack
+or
+.Fn pthread_attr_setstackaddr ,
+the results are unspecified if the signal is generated more than once.
+.Sh RETURN VALUES
+If the call succeeds,
+.Fn timer_create
+returns zero and updates the location referenced by
+.Fa timerid
+to a
+.Vt timer_t ,
+which can be passed to the per-process timer calls.
+If an error
+occurs, the system call returns a value of \-1
+and the global variable
+.Va errno
+is set to indicate the
+error.
+The value of
+.Fa timerid
+is undefined if an error occurs.
+.Sh ERRORS
+The
+.Fn timer_create
+system call
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EAGAIN
+The calling process has already created all of the timers it is allowed by
+this implementation.
+.It Bq Er EINVAL
+The specified clock ID is not supported.
+.It Bq Er EINVAL
+The specified asynchronous notification method is not supported.
+.It Bq Er EFAULT
+Any arguments point outside the allocated address space or there is a
+memory protection fault.
+.El
+.Sh SEE ALSO
+.Xr clock_getres 2 ,
+.Xr timer_delete 2 ,
+.Xr timer_getoverrun 2 ,
+.Xr sigevent 3 ,
+.Xr siginfo 3
+.Sh STANDARDS
+The
+.Fn timer_create
+system call conforms to
+.St -p1003.1-2004 .
+.Sh HISTORY
+Support for
+.Tn POSIX
+per-process timer first appeared in
+.Fx 7.0 .
diff --git a/lib/libc/sys/timer_delete.2 b/lib/libc/sys/timer_delete.2
new file mode 100644
index 000000000000..a7f5ada0eb51
--- /dev/null
+++ b/lib/libc/sys/timer_delete.2
@@ -0,0 +1,80 @@
+.\" Copyright (c) 2005 David Xu <davidxu@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice(s), this list of conditions and the following disclaimer as
+.\" the first lines of this file unmodified other than the possible
+.\" addition of one or more copyright notices.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice(s), this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+.\" EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+.\" OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+.\" EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd September 11, 2000
+.Dt TIMER_DELETE 2
+.Os
+.Sh NAME
+.Nm timer_delete
+.Nd "delete a per-process timer (REALTIME)"
+.Sh LIBRARY
+.Lb librt
+.Sh SYNOPSIS
+.In time.h
+.Ft int
+.Fn timer_delete "timer_t timerid"
+.Sh DESCRIPTION
+The
+.Fn timer_delete
+system call
+deletes the specified timer,
+.Fa timerid ,
+previously created by the
+.Xr timer_create 2
+system call.
+If the timer is armed when
+.Fn timer_delete
+is called, the behavior is as if the timer is automatically disarmed before
+removal.
+Pending signals for the deleted timer are cleared.
+.Sh RETURN VALUES
+.Rv -std
+.Sh ERRORS
+The
+.Fn timer_delete
+system call
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The timer ID specified by
+.Fa timerid
+is not a valid timer ID.
+.El
+.Sh SEE ALSO
+.Xr timer_create 2
+.Sh STANDARDS
+The
+.Fn timer_delete
+system call conforms to
+.St -p1003.1-2004 .
+.Sh HISTORY
+Support for
+.Tn POSIX
+per-process timer first appeared in
+.Fx 7.0 .
diff --git a/lib/libc/sys/timer_settime.2 b/lib/libc/sys/timer_settime.2
new file mode 100644
index 000000000000..3f7be18c217d
--- /dev/null
+++ b/lib/libc/sys/timer_settime.2
@@ -0,0 +1,265 @@
+.\" Copyright (c) 2005 David Xu <davidxu@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice(s), this list of conditions and the following disclaimer as
+.\" the first lines of this file unmodified other than the possible
+.\" addition of one or more copyright notices.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice(s), this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+.\" EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+.\" OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+.\" EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd September 11, 2000
+.Dt TIMER_SETTIME 2
+.Os
+.Sh NAME
+.Nm timer_getoverrun ,
+.Nm timer_gettime ,
+.Nm timer_settime
+.Nd "per-process timers (REALTIME)"
+.Sh LIBRARY
+.Lb librt
+.Sh SYNOPSIS
+.In time.h
+.Ft int
+.Fn timer_getoverrun "timer_t timerid"
+.Ft int
+.Fn timer_gettime "timer_t timerid" "struct itimerspec *value"
+.Ft int
+.Fo timer_settime
+.Fa "timer_t timerid" "int flags" "const struct itimerspec *restrict value"
+.Fa "struct itimerspec *restrict ovalue"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn timer_gettime
+system call stores the amount of time until the specified timer,
+.Fa timerid ,
+expires and the reload value of the timer into the space pointed to by the
+.Fa value
+argument.
+The
+.Va it_value
+member of this structure contains the amount of time
+before the timer expires, or zero if the timer is disarmed.
+This value is
+returned as the interval until timer expiration, even if the timer was armed
+with absolute time.
+The
+.Va it_interval
+member of
+.Fa value
+contains the reload
+value last set by
+.Fn timer_settime .
+.Pp
+The
+.Fn timer_settime
+system call sets the time until the next expiration of the timer specified
+by
+.Fa timerid
+from the
+.Va it_value
+member of the
+.Fa value
+argument and arms the timer if the
+.Va it_value
+member of
+.Fa value
+is non-zero.
+If the specified timer was already
+armed when
+.Fn timer_settime
+is called, this call resets the time until next expiration to the value
+specified.
+If the
+.Va it_value
+member of
+.Fa value
+is zero, the timer is disarmed.
+If the timer is disarmed, then pending signal is removed.
+.Pp
+If the flag
+.Dv TIMER_ABSTIME
+is not set in the argument
+.Fa flags ,
+.Fn timer_settime
+behaves as if the time until next expiration is set to
+be equal to the interval specified by the
+.Va it_value
+member of
+.Fa value .
+That is,
+the timer expires in
+.Va it_value
+nanoseconds from when the call is made.
+If the flag
+.Dv TIMER_ABSTIME
+is set in the argument
+.Fa flags ,
+.Fn timer_settime
+behaves as if the time until next expiration is set to be equal to the
+difference between the absolute time specified by the it_value member of
+value and the current value of the clock associated with
+.Fa timerid .
+That is, the timer expires when the clock reaches the value specified by the
+.Va it_value
+member of
+.Fa value .
+If the specified time has already passed, the
+system call succeeds and the expiration notification is made.
+.Pp
+The reload value of the timer is set to the value specified by the
+.Va it_interval
+member of
+.Fa value .
+When a timer is armed with a non-zero
+.Va it_interval ,
+a periodic
+(or repetitive) timer is specified.
+.Pp
+Time values that are between two consecutive non-negative integer multiples of
+the resolution of the specified timer are rounded up to the larger multiple of
+the resolution.
+Quantization error will not cause the timer to expire earlier
+than the rounded time value.
+.Pp
+If the argument
+.Fa ovalue
+is not
+.Dv NULL ,
+the
+.Fn timer_settime
+system call stores, in the location referenced by
+.Fa ovalue ,
+a value representing
+the previous amount of time before the timer would have expired, or zero if the
+timer was disarmed, together with the previous timer reload value.
+Timers do not
+expire before their scheduled time.
+.Pp
+Only a single signal is queued to the process for a given timer at any point in
+time.
+When a timer for which a signal is still pending expires, no signal is
+queued, and a timer overrun will occur.
+When a timer expiration signal is
+accepted by a process, the
+.Fn timer_getoverrun
+system call returns the timer expiration overrun count for the specified timer.
+The overrun count returned contains the number of extra timer expirations that
+occurred between the time the signal was generated (queued) and when it was
+accepted, up to but not including an maximum of
+.Brq Dv DELAYTIMER_MAX .
+If the number of
+such extra expirations is greater than or equal to
+.Brq Dv DELAYTIMER_MAX ,
+then the overrun count is set to
+.Brq Dv DELAYTIMER_MAX .
+The value returned by
+.Fn timer_getoverrun
+applies to the most recent expiration signal acceptance for the timer.
+If no
+expiration signal has been delivered for the timer, the return value of
+.Fn timer_getoverrun
+is unspecified.
+.Sh RETURN VALUES
+If the
+.Fn timer_getoverrun
+system call succeeds, it returns the timer expiration overrun count as explained
+above.
+Otherwise the value \-1 is returned, and the global variable
+.Va errno
+is set to indicate the error.
+.Pp
+.Rv -std timer_gettime timer_settime
+.Sh ERRORS
+The
+.Fn timer_settime
+system call
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+A
+.Fa value
+structure specified a nanosecond value less than zero or greater than
+or equal to 1000 million, and the
+.Va it_value
+member of that structure did not
+specify zero seconds and nanoseconds.
+.El
+.Pp
+These system calls may fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa timerid
+argument does not correspond to an ID returned by
+.Fn timer_create
+but not yet deleted by
+.Fn timer_delete .
+.El
+.Pp
+The
+.Fn timer_settime
+system call may fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Va it_interval
+member of
+.Fa value
+is not zero and the timer was created with
+notification by creation of a new thread
+.Va ( sigev_sigev_notify
+was
+.Dv SIGEV_THREAD )
+and a fixed stack address has been set in the thread attribute pointed to by
+.Va sigev_notify_attributes .
+.El
+.Pp
+The
+.Fn timer_gettime
+and
+.Fn timer_settime
+system calls
+may fail if:
+.Bl -tag -width Er
+.It Bq Er EFAULT
+Any arguments point outside the allocated address space or there is a
+memory protection fault.
+.El
+.Sh SEE ALSO
+.Xr clock_getres 2 ,
+.Xr timer_create 2 ,
+.Xr siginfo 3
+.Sh STANDARDS
+The
+.Fn timer_getoverrun ,
+.Fn timer_gettime ,
+and
+.Fn timer_settime
+system calls conform to
+.St -p1003.1-2004 .
+.Sh HISTORY
+Support for
+.Tn POSIX
+per-process timer first appeared in
+.Fx 7.0 .
diff --git a/lib/libc/sys/trivial-vdso_tc.c b/lib/libc/sys/trivial-vdso_tc.c
new file mode 100644
index 000000000000..ce0c1444f318
--- /dev/null
+++ b/lib/libc/sys/trivial-vdso_tc.c
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 2013 Konstantin Belousov <kib@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/vdso.h>
+#include <errno.h>
+
+#pragma weak __vdso_gettc
+int
+__vdso_gettc(const struct vdso_timehands *th, u_int *tc)
+{
+
+ return (ENOSYS);
+}
+
+#pragma weak __vdso_gettimekeep
+int
+__vdso_gettimekeep(struct vdso_timekeep **tk)
+{
+
+ return (ENOSYS);
+}
diff --git a/lib/libc/sys/truncate.2 b/lib/libc/sys/truncate.2
new file mode 100644
index 000000000000..0734464c868c
--- /dev/null
+++ b/lib/libc/sys/truncate.2
@@ -0,0 +1,165 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)truncate.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd May 4, 2015
+.Dt TRUNCATE 2
+.Os
+.Sh NAME
+.Nm truncate ,
+.Nm ftruncate
+.Nd truncate or extend a file to a specified length
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft int
+.Fn truncate "const char *path" "off_t length"
+.Ft int
+.Fn ftruncate "int fd" "off_t length"
+.Sh DESCRIPTION
+The
+.Fn truncate
+system call
+causes the file named by
+.Fa path
+or referenced by
+.Fa fd
+to be truncated or extended to
+.Fa length
+bytes in size.
+If the file
+was larger than this size, the extra data
+is lost.
+If the file was smaller than this size,
+it will be extended as if by writing bytes
+with the value zero.
+.Pp
+The
+.Fn ftruncate
+system call causes the file or shared memory object backing the file descriptor
+.Fa fd
+to be truncated or extended to
+.Fa length
+bytes in size.
+The file descriptor must be a valid file descriptor open for writing.
+The file position pointer associated with the file descriptor
+.Fa fd
+will not be modified.
+.Sh RETURN VALUES
+.Rv -std
+If the file to be modified is not a directory or
+a regular file, the
+.Fn truncate
+call has no effect and returns the value 0.
+.Sh ERRORS
+The
+.Fn truncate
+system call
+succeeds unless:
+.Bl -tag -width Er
+.It Bq Er ENOTDIR
+A component of the path prefix is not a directory.
+.It Bq Er ENAMETOOLONG
+A component of a pathname exceeded 255 characters,
+or an entire path name exceeded 1023 characters.
+.It Bq Er ENOENT
+The named file does not exist.
+.It Bq Er EACCES
+Search permission is denied for a component of the path prefix.
+.It Bq Er EACCES
+The named file is not writable by the user.
+.It Bq Er ELOOP
+Too many symbolic links were encountered in translating the pathname.
+.It Bq Er EPERM
+The named file has its immutable or append-only flag set, see the
+.Xr chflags 2
+manual page for more information.
+.It Bq Er EISDIR
+The named file is a directory.
+.It Bq Er EROFS
+The named file resides on a read-only file system.
+.It Bq Er ETXTBSY
+The file is a pure procedure (shared text) file that is being executed.
+.It Bq Er EFBIG
+The
+.Fa length
+argument was greater than the maximum file size.
+.It Bq Er EINVAL
+The
+.Fa length
+argument was less than 0.
+.It Bq Er EIO
+An I/O error occurred updating the inode.
+.It Bq Er EFAULT
+The
+.Fa path
+argument
+points outside the process's allocated address space.
+.El
+.Pp
+The
+.Fn ftruncate
+system call
+succeeds unless:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa fd
+argument
+is not a valid descriptor.
+.It Bq Er EINVAL
+The
+.Fa fd
+argument
+references a file descriptor that is not a regular file or shared memory object.
+.It Bq Er EINVAL
+The
+.Fa fd
+descriptor
+is not open for writing.
+.El
+.Sh SEE ALSO
+.Xr chflags 2 ,
+.Xr open 2 ,
+.Xr shm_open 2
+.Sh HISTORY
+The
+.Fn truncate
+and
+.Fn ftruncate
+system calls appeared in
+.Bx 4.2 .
+.Sh BUGS
+These calls should be generalized to allow ranges
+of bytes in a file to be discarded.
+.Pp
+Use of
+.Fn truncate
+to extend a file is not portable.
diff --git a/lib/libc/sys/umask.2 b/lib/libc/sys/umask.2
new file mode 100644
index 000000000000..025a72640e14
--- /dev/null
+++ b/lib/libc/sys/umask.2
@@ -0,0 +1,88 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)umask.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt UMASK 2
+.Os
+.Sh NAME
+.Nm umask
+.Nd set file creation mode mask
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/stat.h
+.Ft mode_t
+.Fn umask "mode_t numask"
+.Sh DESCRIPTION
+The
+.Fn umask
+routine sets the process's file mode creation mask to
+.Fa numask
+and returns the previous value of the mask.
+The 9 low-order
+access permission
+bits of
+.Fa numask
+are used by system calls, including
+.Xr open 2 ,
+.Xr mkdir 2 ,
+and
+.Xr mkfifo 2 ,
+to turn off corresponding bits
+requested in file mode.
+(See
+.Xr chmod 2 ) .
+This clearing allows each user to restrict the default access
+to his files.
+.Pp
+The default mask value is S_IWGRP|S_IWOTH (022, write access for the
+owner only).
+Child processes inherit the mask of the calling process.
+.Sh RETURN VALUES
+The previous value of the file mode mask is returned by the call.
+.Sh ERRORS
+The
+.Fn umask
+system call is always successful.
+.Sh SEE ALSO
+.Xr chmod 2 ,
+.Xr mkfifo 2 ,
+.Xr mknod 2 ,
+.Xr open 2
+.Sh STANDARDS
+The
+.Fn umask
+system call is expected to conform to
+.St -p1003.1-90 .
+.Sh HISTORY
+The
+.Fn umask
+function appeared in
+.At v7 .
diff --git a/lib/libc/sys/undelete.2 b/lib/libc/sys/undelete.2
new file mode 100644
index 000000000000..f686f5ec1e11
--- /dev/null
+++ b/lib/libc/sys/undelete.2
@@ -0,0 +1,105 @@
+.\" Copyright (c) 1994
+.\" Jan-Simon Pendry
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)undelete.2 8.4 (Berkeley) 10/18/94
+.\" $FreeBSD$
+.\"
+.Dd January 22, 2006
+.Dt UNDELETE 2
+.Os
+.Sh NAME
+.Nm undelete
+.Nd attempt to recover a deleted file
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft int
+.Fn undelete "const char *path"
+.Sh DESCRIPTION
+The
+.Fn undelete
+system call attempts to recover the deleted file named by
+.Fa path .
+Currently, this works only when the named object
+is a whiteout in a union file system.
+The system call removes the whiteout causing
+any objects in a lower layer of the
+union stack to become visible once more.
+.Pp
+Eventually, the
+.Fn undelete
+functionality may be expanded to other file systems able to recover
+deleted files such as the log-structured file system.
+.Sh RETURN VALUES
+.Rv -std undelete
+.Sh ERRORS
+The
+.Fn undelete
+succeeds unless:
+.Bl -tag -width Er
+.It Bq Er ENOTDIR
+A component of the path prefix is not a directory.
+.It Bq Er ENAMETOOLONG
+A component of a pathname exceeded 255 characters,
+or an entire path name exceeded 1023 characters.
+.It Bq Er EEXIST
+The path does not reference a whiteout.
+.It Bq Er ENOENT
+The named whiteout does not exist.
+.It Bq Er EACCES
+Search permission is denied for a component of the path prefix.
+.It Bq Er EACCES
+Write permission is denied on the directory containing the name
+to be undeleted.
+.It Bq Er ELOOP
+Too many symbolic links were encountered in translating the pathname.
+.It Bq Er EPERM
+The directory containing the name is marked sticky,
+and the containing directory is not owned by the effective user ID.
+.It Bq Er EINVAL
+The last component of the path is
+.Ql .. .
+.It Bq Er EIO
+An I/O error occurred while updating the directory entry.
+.It Bq Er EROFS
+The name resides on a read-only file system.
+.It Bq Er EFAULT
+The
+.Fa path
+argument
+points outside the process's allocated address space.
+.El
+.Sh SEE ALSO
+.Xr unlink 2 ,
+.Xr mount_unionfs 8
+.Sh HISTORY
+The
+.Fn undelete
+system call first appeared in
+.Bx 4.4 Lite .
diff --git a/lib/libc/sys/unlink.2 b/lib/libc/sys/unlink.2
new file mode 100644
index 000000000000..e59ecf8b2a93
--- /dev/null
+++ b/lib/libc/sys/unlink.2
@@ -0,0 +1,228 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)unlink.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd July 28, 2015
+.Dt UNLINK 2
+.Os
+.Sh NAME
+.Nm unlink ,
+.Nm unlinkat
+.Nd remove directory entry
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft int
+.Fn unlink "const char *path"
+.Ft int
+.Fn unlinkat "int fd" "const char *path" "int flag"
+.Sh DESCRIPTION
+The
+.Fn unlink
+system call
+removes the link named by
+.Fa path
+from its directory and decrements the link count of the
+file which was referenced by the link.
+If that decrement reduces the link count of the file
+to zero,
+and no process has the file open, then
+all resources associated with the file are reclaimed.
+If one or more process have the file open when the last link is removed,
+the link is removed, but the removal of the file is delayed until
+all references to it have been closed.
+The
+.Fa path
+argument
+may not be a directory.
+.Pp
+The
+.Fn unlinkat
+system call is equivalent to
+.Fn unlink
+or
+.Fn rmdir
+except in the case where
+.Fa path
+specifies a relative path.
+In this case the directory entry to be removed is determined
+relative to the directory associated with the file descriptor
+.Fa fd
+instead of the current working directory.
+.Pp
+The values for
+.Fa flag
+are constructed by a bitwise-inclusive OR of flags from the following list,
+defined in
+.In fcntl.h :
+.Bl -tag -width indent
+.It Dv AT_REMOVEDIR
+Remove the directory entry specified by
+.Fa fd
+and
+.Fa path
+as a directory, not a normal file.
+.El
+.Pp
+If
+.Fn unlinkat
+is passed the special value
+.Dv AT_FDCWD
+in the
+.Fa fd
+parameter, the current working directory is used and the behavior is
+identical to a call to
+.Fa unlink
+or
+.Fa rmdir
+respectively, depending on whether or not the
+.Dv AT_REMOVEDIR
+bit is set in flag.
+.Sh RETURN VALUES
+.Rv -std unlink
+.Sh ERRORS
+The
+.Fn unlink
+succeeds unless:
+.Bl -tag -width Er
+.It Bq Er ENOTDIR
+A component of the path prefix is not a directory.
+.It Bq Er EISDIR
+The named file is a directory.
+.It Bq Er ENAMETOOLONG
+A component of a pathname exceeded 255 characters,
+or an entire path name exceeded 1023 characters.
+.It Bq Er ENOENT
+The named file does not exist.
+.It Bq Er EACCES
+Search permission is denied for a component of the path prefix.
+.It Bq Er EACCES
+Write permission is denied on the directory containing the link
+to be removed.
+.It Bq Er ELOOP
+Too many symbolic links were encountered in translating the pathname.
+.It Bq Er EPERM
+The named file is a directory.
+.It Bq Er EPERM
+The named file has its immutable, undeletable or append-only flag set, see the
+.Xr chflags 2
+manual page for more information.
+.It Bq Er EPERM
+The parent directory of the named file has its immutable or append-only flag
+set.
+.It Bq Er EPERM
+The directory containing the file is marked sticky,
+and neither the containing directory nor the file to be removed
+are owned by the effective user ID.
+.It Bq Er EIO
+An I/O error occurred while deleting the directory entry
+or deallocating the inode.
+.It Bq Er EROFS
+The named file resides on a read-only file system.
+.It Bq Er EFAULT
+The
+.Fa path
+argument
+points outside the process's allocated address space.
+.It Bq Er ENOSPC
+On file systems supporting copy-on-write or snapshots, there was not enough
+free space to record metadata for the delete operation of the file.
+.El
+.Pp
+In addition to the errors returned by the
+.Fn unlink ,
+the
+.Fn unlinkat
+may fail if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa path
+argument does not specify an absolute path and the
+.Fa fd
+argument is neither
+.Dv AT_FDCWD
+nor a valid file descriptor open for searching.
+.It Bq Er ENOTEMPTY
+The
+.Fa flag
+parameter has the
+.Dv AT_REMOVEDIR
+bit set and the
+.Fa path
+argument names a directory that is not an empty directory,
+or there are hard links to the directory other than dot or
+a single entry in dot-dot.
+.It Bq Er ENOTDIR
+The
+.Fa flag
+parameter has the
+.Dv AT_REMOVEDIR
+bit set and
+.Fa path
+does not name a directory.
+.It Bq Er EINVAL
+The value of the
+.Fa flag
+argument is not valid.
+.It Bq Er ENOTDIR
+The
+.Fa path
+argument is not an absolute path and
+.Fa fd
+is neither
+.Dv AT_FDCWD
+nor a file descriptor associated with a directory.
+.El
+.Sh SEE ALSO
+.Xr chflags 2 ,
+.Xr close 2 ,
+.Xr link 2 ,
+.Xr rmdir 2 ,
+.Xr symlink 7
+.Sh STANDARDS
+The
+.Fn unlinkat
+system call follows The Open Group Extended API Set 2 specification.
+.Sh HISTORY
+The
+.Fn unlink
+function appeared in
+.At v6 .
+The
+.Fn unlinkat
+system call appeared in
+.Fx 8.0 .
+.Pp
+The
+.Fn unlink
+system call traditionally allows the super-user to unlink directories which
+can damage the file system integrity.
+This implementation no longer permits it.
diff --git a/lib/libc/sys/utimensat.2 b/lib/libc/sys/utimensat.2
new file mode 100644
index 000000000000..a714b344888b
--- /dev/null
+++ b/lib/libc/sys/utimensat.2
@@ -0,0 +1,295 @@
+.\" $NetBSD: utimes.2,v 1.13 1999/03/22 19:45:11 garbled Exp $
+.\"
+.\" Copyright (c) 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\" Copyright (c) 2012, Jilles Tjoelker
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)utimes.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd January 17, 2016
+.Dt UTIMENSAT 2
+.Os
+.Sh NAME
+.Nm futimens ,
+.Nm utimensat
+.Nd set file access and modification times
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/stat.h
+.Ft int
+.Fn futimens "int fd" "const struct timespec times[2]"
+.Ft int
+.Fo utimensat
+.Fa "int fd"
+.Fa "const char *path"
+.Fa "const struct timespec times[2]"
+.Fa "int flag"
+.Fc
+.Sh DESCRIPTION
+The access and modification times of the file named by
+.Fa path
+or referenced by
+.Fa fd
+are changed as specified by the argument
+.Fa times .
+The inode-change-time of the file is set to the current time.
+.Pp
+If
+.Fa path
+specifies a relative path,
+it is relative to the current working directory if
+.Fa fd
+is
+.Dv AT_FDCWD
+and otherwise relative to the directory associated with the file descriptor
+.Fa fd .
+.Pp
+The
+.Va tv_nsec
+field of a
+.Vt timespec
+structure
+can be set to the special value
+.Dv UTIME_NOW
+to set the current time, or to
+.Dv UTIME_OMIT
+to leave the time unchanged.
+In either case, the
+.Va tv_sec
+field is ignored.
+.Pp
+If
+.Fa times
+is
+.No non- Ns Dv NULL ,
+it is assumed to point to an array of two timespec structures.
+The access time is set to the value of the first element, and the
+modification time is set to the value of the second element.
+For file systems that support file birth (creation) times (such as
+.Dv UFS2 ) ,
+the birth time will be set to the value of the second element
+if the second element is older than the currently set birth time.
+To set both a birth time and a modification time,
+two calls are required; the first to set the birth time
+and the second to set the (presumably newer) modification time.
+Ideally a new system call will be added that allows the setting
+of all three times at once.
+If
+.Fa times
+is
+.Dv NULL ,
+this is equivalent to passing
+a pointer to an array of two timespec structures
+with both
+.Va tv_nsec
+fields set to
+.Dv UTIME_NOW .
+.Pp
+If both
+.Va tv_nsec
+fields are
+.Dv UTIME_OMIT ,
+the timestamps remain unchanged and
+no permissions are needed for the file itself,
+although search permissions may be required for the path prefix.
+The call may or may not succeed if the named file does not exist.
+.Pp
+If both
+.Va tv_nsec
+fields are
+.Dv UTIME_NOW ,
+the caller must be the owner of the file, have permission to
+write the file, or be the super-user.
+.Pp
+For all other values of the timestamps,
+the caller must be the owner of the file or be the super-user.
+.Pp
+The values for the
+.Fa flag
+argument of the
+.Fn utimensat
+system call
+are constructed by a bitwise-inclusive OR of flags from the following list,
+defined in
+.In fcntl.h :
+.Bl -tag -width indent
+.It Dv AT_SYMLINK_NOFOLLOW
+If
+.Fa path
+names a symbolic link, the symbolic link's times are changed.
+By default,
+.Fn utimensat
+changes the times of the file referenced by the symbolic link.
+.El
+.Sh RETURN VALUES
+.Rv -std
+.Sh COMPATIBILITY
+If the running kernel does not support this system call,
+a wrapper emulates it using
+.Xr fstatat 2 ,
+.Xr futimesat 2
+and
+.Xr lutimes 2 .
+As a result, timestamps will be rounded down to the nearest microsecond,
+.Dv UTIME_OMIT
+is not atomic and
+.Dv AT_SYMLINK_NOFOLLOW
+is not available with a path relative to a file descriptor.
+.Sh ERRORS
+These system calls will fail if:
+.Bl -tag -width Er
+.It Bq Er EACCES
+The
+.Fa times
+argument is
+.Dv NULL ,
+or both
+.Va tv_nsec
+values are
+.Dv UTIME_NOW ,
+and the effective user ID of the process does not
+match the owner of the file, and is not the super-user, and write
+access is denied.
+.It Bq Er EFAULT
+The
+.Fa times
+argument
+points outside the process's allocated address space.
+.It Bq Er EINVAL
+The
+.Va tv_nsec
+component of at least one of the values specified by the
+.Fa times
+argument has a value less than 0 or greater than 999999999 and is not equal to
+.Dv UTIME_NOW
+or
+.Dv UTIME_OMIT .
+.It Bq Er EIO
+An I/O error occurred while reading or writing the affected inode.
+.It Bq Er EPERM
+The
+.Fa times
+argument is not
+.Dv NULL
+nor are both
+.Va tv_nsec
+values
+.Dv UTIME_NOW ,
+nor are both
+.Va tv_nsec
+values
+.Dv UTIME_OMIT
+and the calling process's effective user ID
+does not match the owner of the file and is not the super-user.
+.It Bq Er EPERM
+The named file has its immutable or append-only flag set, see the
+.Xr chflags 2
+manual page for more information.
+.It Bq Er EROFS
+The file system containing the file is mounted read-only.
+.El
+.Pp
+The
+.Fn futimens
+system call
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa fd
+argument
+does not refer to a valid descriptor.
+.El
+.Pp
+The
+.Fn utimensat
+system call
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EACCES
+Search permission is denied for a component of the path prefix.
+.It Bq Er EBADF
+The
+.Fa path
+argument does not specify an absolute path and the
+.Fa fd
+argument is neither
+.Dv AT_FDCWD
+nor a valid file descriptor.
+.It Bq Er EFAULT
+The
+.Fa path
+argument
+points outside the process's allocated address space.
+.It Bq Er ELOOP
+Too many symbolic links were encountered in translating the pathname.
+.It Bq Er ENAMETOOLONG
+A component of a pathname exceeded
+.Dv NAME_MAX
+characters, or an entire path name exceeded
+.Dv PATH_MAX
+characters.
+.It Bq Er ENOENT
+The named file does not exist.
+.It Bq Er ENOTDIR
+A component of the path prefix is not a directory.
+.It Bq Er ENOTDIR
+The
+.Fa path
+argument is not an absolute path and
+.Fa fd
+is neither
+.Dv AT_FDCWD
+nor a file descriptor associated with a directory.
+.It Bq Er ENOTSUP
+The running kernel does not support this system call and
+.Dv AT_SYMLINK_NOFOLLOW
+is used with a path relative to a file descriptor.
+.El
+.Sh SEE ALSO
+.Xr chflags 2 ,
+.Xr stat 2 ,
+.Xr symlink 2 ,
+.Xr utimes 2 ,
+.Xr utime 3 ,
+.Xr symlink 7
+.Sh STANDARDS
+The
+.Fn futimens
+and
+.Fn utimensat
+system calls are expected to conform to
+.St -p1003.1-2008 .
+.Sh HISTORY
+The
+.Fn futimens
+and
+.Fn utimensat
+system calls appeared in
+.Fx 10.3 .
diff --git a/lib/libc/sys/utimensat.c b/lib/libc/sys/utimensat.c
new file mode 100644
index 000000000000..a1c3c211fe95
--- /dev/null
+++ b/lib/libc/sys/utimensat.c
@@ -0,0 +1,112 @@
+/*-
+ * Copyright (c) 2015 Jilles Tjoelker
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <time.h>
+#include "un-namespace.h"
+
+#include "libc_private.h"
+
+int
+utimensat(int fd, const char *path, const struct timespec times[2], int flag)
+{
+ struct timeval now, tv[2], *tvp;
+ struct stat sb;
+ int osreldate;
+
+ osreldate = __getosreldate();
+ if (osreldate >= 1100056 ||
+ (osreldate >= 1002506 && osreldate < 1100000))
+ return (__sys_utimensat(fd, path, times, flag));
+
+ if ((flag & ~AT_SYMLINK_NOFOLLOW) != 0) {
+ errno = EINVAL;
+ return (-1);
+ }
+ if (times == NULL || (times[0].tv_nsec == UTIME_NOW &&
+ times[1].tv_nsec == UTIME_NOW))
+ tvp = NULL;
+ else if (times[0].tv_nsec == UTIME_OMIT &&
+ times[1].tv_nsec == UTIME_OMIT)
+ return (0);
+ else {
+ if ((times[0].tv_nsec < 0 || times[0].tv_nsec > 999999999) &&
+ times[0].tv_nsec != UTIME_NOW &&
+ times[0].tv_nsec != UTIME_OMIT) {
+ errno = EINVAL;
+ return (-1);
+ }
+ if ((times[1].tv_nsec < 0 || times[1].tv_nsec > 999999999) &&
+ times[1].tv_nsec != UTIME_NOW &&
+ times[1].tv_nsec != UTIME_OMIT) {
+ errno = EINVAL;
+ return (-1);
+ }
+ tv[0].tv_sec = times[0].tv_sec;
+ tv[0].tv_usec = times[0].tv_nsec / 1000;
+ tv[1].tv_sec = times[1].tv_sec;
+ tv[1].tv_usec = times[1].tv_nsec / 1000;
+ tvp = tv;
+ if (times[0].tv_nsec == UTIME_OMIT ||
+ times[1].tv_nsec == UTIME_OMIT) {
+ if (fstatat(fd, path, &sb, flag) == -1)
+ return (-1);
+ if (times[0].tv_nsec == UTIME_OMIT) {
+ tv[0].tv_sec = sb.st_atim.tv_sec;
+ tv[0].tv_usec = sb.st_atim.tv_nsec / 1000;
+ }
+ if (times[1].tv_nsec == UTIME_OMIT) {
+ tv[1].tv_sec = sb.st_mtim.tv_sec;
+ tv[1].tv_usec = sb.st_mtim.tv_nsec / 1000;
+ }
+ }
+ if (times[0].tv_nsec == UTIME_NOW ||
+ times[1].tv_nsec == UTIME_NOW) {
+ if (gettimeofday(&now, NULL) == -1)
+ return (-1);
+ if (times[0].tv_nsec == UTIME_NOW)
+ tv[0] = now;
+ if (times[1].tv_nsec == UTIME_NOW)
+ tv[1] = now;
+ }
+ }
+ if ((flag & AT_SYMLINK_NOFOLLOW) == 0)
+ return (futimesat(fd, path, tvp));
+ else if ((flag & AT_SYMLINK_NOFOLLOW) != 0 &&
+ (fd == AT_FDCWD || path[0] == '/'))
+ return (lutimes(path, tvp));
+ else {
+ errno = ENOTSUP;
+ return (-1);
+ }
+}
diff --git a/lib/libc/sys/utimes.2 b/lib/libc/sys/utimes.2
new file mode 100644
index 000000000000..30d31d27536a
--- /dev/null
+++ b/lib/libc/sys/utimes.2
@@ -0,0 +1,262 @@
+.\" $NetBSD: utimes.2,v 1.13 1999/03/22 19:45:11 garbled Exp $
+.\"
+.\" Copyright (c) 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)utimes.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 9, 2016
+.Dt UTIMES 2
+.Os
+.Sh NAME
+.Nm utimes ,
+.Nm lutimes ,
+.Nm futimes ,
+.Nm futimesat
+.Nd set file access and modification times
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/time.h
+.Ft int
+.Fn utimes "const char *path" "const struct timeval *times"
+.Ft int
+.Fn lutimes "const char *path" "const struct timeval *times"
+.Ft int
+.Fn futimes "int fd" "const struct timeval *times"
+.Ft int
+.Fn futimesat "int fd" "const char *path" "const struct timeval times[2]"
+.Sh DESCRIPTION
+.Bf -symbolic
+These interfaces are obsoleted by
+.Xr futimens 2
+and
+.Xr utimensat 2
+because they are not accurate to nanoseconds.
+.Ef
+.Pp
+The access and modification times of the file named by
+.Fa path
+or referenced by
+.Fa fd
+are changed as specified by the argument
+.Fa times .
+.Pp
+If
+.Fa times
+is
+.Dv NULL ,
+the access and modification times are set to the current time.
+The caller must be the owner of the file, have permission to
+write the file, or be the super-user.
+.Pp
+If
+.Fa times
+is
+.No non- Ns Dv NULL ,
+it is assumed to point to an array of two timeval structures.
+The access time is set to the value of the first element, and the
+modification time is set to the value of the second element.
+For file systems that support file birth (creation) times (such as
+.Dv UFS2 ) ,
+the birth time will be set to the value of the second element
+if the second element is older than the currently set birth time.
+To set both a birth time and a modification time,
+two calls are required; the first to set the birth time
+and the second to set the (presumably newer) modification time.
+Ideally a new system call will be added that allows the setting
+of all three times at once.
+The caller must be the owner of the file or be the super-user.
+.Pp
+In either case, the inode-change-time of the file is set to the current
+time.
+.Pp
+The
+.Fn lutimes
+system call
+is like
+.Fn utimes
+except in the case where the named file is a symbolic link,
+in which case
+.Fn lutimes
+changes the access and modification times of the link,
+while
+.Fn utimes
+changes the times of the file the link references.
+.Pp
+The
+.Fn futimesat
+system call is equivalent to
+.Fn utimes
+except in the case where
+.Fa path
+specifies a relative path.
+In this case the access and modification time
+is set to that of a file relative to the directory associated with the file
+descriptor
+.Fa fd
+instead of the current working directory.
+If
+.Fn futimesat
+is passed the special value
+.Dv AT_FDCWD
+in the
+.Fa fd
+parameter, the current working directory is used and the behavior
+is identical to a call to
+.Fn utimes .
+.Sh RETURN VALUES
+.Rv -std
+.Sh ERRORS
+All of the system call will fail if:
+.Bl -tag -width Er
+.It Bq Er EACCES
+Search permission is denied for a component of the path prefix.
+.It Bq Er EACCES
+The
+.Fa times
+argument is
+.Dv NULL
+and the effective user ID of the process does not
+match the owner of the file, and is not the super-user, and write
+access is denied.
+.It Bq Er EFAULT
+The
+.Fa path
+or
+.Fa times
+argument
+points outside the process's allocated address space.
+.It Bq Er EFAULT
+The
+.Fa times
+argument
+points outside the process's allocated address space.
+.It Bq Er EINVAL
+The
+.Va tv_usec
+component of at least one of the values specified by the
+.Fa times
+argument has a value less than 0 or greater than 999999.
+.It Bq Er EIO
+An I/O error occurred while reading or writing the affected inode.
+.It Bq Er ELOOP
+Too many symbolic links were encountered in translating the pathname.
+.It Bq Er ENAMETOOLONG
+A component of a pathname exceeded
+.Dv NAME_MAX
+characters, or an entire path name exceeded
+.Dv PATH_MAX
+characters.
+.It Bq Er ENOENT
+The named file does not exist.
+.It Bq Er ENOTDIR
+A component of the path prefix is not a directory.
+.It Bq Er EPERM
+The
+.Fa times
+argument is not
+.Dv NULL
+and the calling process's effective user ID
+does not match the owner of the file and is not the super-user.
+.It Bq Er EPERM
+The named file has its immutable or append-only flags set.
+See the
+.Xr chflags 2
+manual page for more information.
+.It Bq Er EROFS
+The file system containing the file is mounted read-only.
+.El
+.Pp
+The
+.Fn futimes
+system call
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa fd
+argument
+does not refer to a valid descriptor.
+.El
+.Pp
+In addition to the errors returned by the
+.Fn utimes ,
+the
+.Fn futimesat
+may fail if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa path
+argument does not specify an absolute path and the
+.Fa fd
+argument is neither
+.Dv AT_FDCWD
+nor a valid file descriptor open for searching.
+.It Bq Er ENOTDIR
+The
+.Fa path
+argument is not an absolute path and
+.Fa fd
+is neither
+.Dv AT_FDCWD
+nor a file descriptor associated with a directory.
+.El
+.Sh SEE ALSO
+.Xr chflags 2 ,
+.Xr stat 2 ,
+.Xr utimensat 2 ,
+.Xr utime 3
+.Sh STANDARDS
+The
+.Fn utimes
+function is expected to conform to
+.St -xpg4.2 .
+The
+.Fn futimesat
+system call follows The Open Group Extended API Set 2 specification
+but was replaced by
+.Fn utimensat
+in
+.St -p1003.1-2008 .
+.Sh HISTORY
+The
+.Fn utimes
+system call appeared in
+.Bx 4.2 .
+The
+.Fn futimes
+and
+.Fn lutimes
+system calls first appeared in
+.Fx 3.0 .
+The
+.Fn futimesat
+system call appeared in
+.Fx 8.0 .
diff --git a/lib/libc/sys/utrace.2 b/lib/libc/sys/utrace.2
new file mode 100644
index 000000000000..814091aeb30d
--- /dev/null
+++ b/lib/libc/sys/utrace.2
@@ -0,0 +1,80 @@
+.\" $NetBSD: utrace.2,v 1.11 2003/04/24 12:17:49 wiz Exp $
+.\"
+.\" Copyright (c) 2000 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Gregory McGarry <g.mcgarry@ieee.org>.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd December 11, 2015
+.Dt UTRACE 2
+.Os
+.Sh NAME
+.Nm utrace
+.Nd insert user record in ktrace log
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/param.h
+.In sys/time.h
+.In sys/uio.h
+.In sys/ktrace.h
+.Ft int
+.Fn utrace "const void *addr" "size_t len"
+.Sh DESCRIPTION
+Adds a record to the process trace with information supplied by user.
+The record contains
+.Fa len
+bytes from memory pointed to by
+.Fa addr .
+This call only has an effect if the calling process is being traced.
+.Sh RETURN VALUES
+.Rv -std
+.Sh ERRORS
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Specified data length
+.Fa len
+was bigger than
+.Dv KTR_USER_MAXLEN .
+.It Bq Er ENOMEM
+Insufficient memory to honor the request.
+.It Bq Er ENOSYS
+Currently running kernel was compiled without
+.Xr ktrace 2
+support
+.Pq Cd "options KTRACE" .
+.El
+.Sh SEE ALSO
+.Xr kdump 1 ,
+.Xr ktrace 1 ,
+.Xr truss 1 ,
+.Xr ktrace 2 ,
+.Xr sysdecode_utrace 3
+.Sh HISTORY
+The
+.Fn utrace
+system call first appeared in
+.Fx 2.2 .
diff --git a/lib/libc/sys/uuidgen.2 b/lib/libc/sys/uuidgen.2
new file mode 100644
index 000000000000..9c90102b3e2f
--- /dev/null
+++ b/lib/libc/sys/uuidgen.2
@@ -0,0 +1,142 @@
+.\" Copyright (c) 2002 Marcel Moolenaar
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd May 26, 2002
+.Dt UUIDGEN 2
+.Os
+.Sh NAME
+.Nm uuidgen
+.Nd generate universally unique identifiers
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/uuid.h
+.Ft int
+.Fn uuidgen "struct uuid *store" "int count"
+.Sh DESCRIPTION
+The
+.Fn uuidgen
+system call generates
+.Fa count
+universally unique identifiers (UUIDs) and writes them to the buffer
+pointed to by
+.Fa store .
+The identifiers are generated according to the syntax and semantics of the
+DCE version 1 variant of universally unique identifiers.
+See below for a more in-depth description of the identifiers.
+When no IEEE 802
+address is available for the node field, a random multicast address is
+generated for each invocation of the system call.
+According to the algorithm of generating time-based UUIDs, this will also
+force a new random clock sequence, thereby increasing the likelihood for
+the identifier to be unique.
+.Pp
+When multiple identifiers are to be generated, the
+.Fn uuidgen
+system call will generate a set of identifiers that is dense in such a way
+that there is no identifier that is larger than the smallest identifier in the
+set and smaller than the largest identifier in the set and that is not already
+in the set.
+.Pp
+Universally unique identifiers, also known as globally unique identifiers
+(GUIDs), have a binary representation of 128-bits.
+The grouping and meaning of these bits is described by the following
+structure and its description of the fields that follow it:
+.Bd -literal
+struct uuid {
+ uint32_t time_low;
+ uint16_t time_mid;
+ uint16_t time_hi_and_version;
+ uint8_t clock_seq_hi_and_reserved;
+ uint8_t clock_seq_low;
+ uint8_t node[_UUID_NODE_LEN];
+};
+.Ed
+.Bl -tag -width ".Va clock_seq_hi_and_reserved"
+.It Va time_low
+The least significant 32 bits of a 60-bit timestamp.
+This field is stored in the native byte-order.
+.It Va time_mid
+The least significant 16 bits of the most significant 28 bits of the 60-bit
+timestamp.
+This field is stored in the native byte-order.
+.It Va time_hi_and_version
+The most significant 12 bits of the 60-bit timestamp multiplexed with a 4-bit
+version number.
+The version number is stored in the most significant 4 bits of the 16-bit
+field.
+This field is stored in the native byte-order.
+.It Va clock_seq_hi_and_reserved
+The most significant 6 bits of a 14-bit sequence number multiplexed with a
+2-bit variant value.
+Note that the width of the variant value is determined by the variant itself.
+Identifiers generated by the
+.Fn uuidgen
+system call have variant value 10b.
+the variant value is stored in the most significant bits of the field.
+.It Va clock_seq_low
+The least significant 8 bits of a 14-bit sequence number.
+.It Va node
+The 6-byte IEEE 802 (MAC) address of one of the interfaces of the node.
+If no such interface exists, a random multi-cast address is used instead.
+.El
+.Pp
+The binary representation is sensitive to byte ordering.
+Any multi-byte field is to be stored in the local or native byte-order and
+identifiers must be converted when transmitted to hosts that do not agree
+on the byte-order.
+The specification does not however document what this means in concrete
+terms and is otherwise beyond the scope of this system call.
+.Sh RETURN VALUES
+.Rv -std
+.Sh ERRORS
+The
+.Fn uuidgen
+system call can fail with:
+.Bl -tag -width Er
+.It Bq Er EFAULT
+The buffer pointed to by
+.Fa store
+could not be written to for any or all identifiers.
+.It Bq Er EINVAL
+The
+.Fa count
+argument is less than 1 or larger than the hard upper limit of 2048.
+.El
+.Sh SEE ALSO
+.Xr uuidgen 1 ,
+.Xr uuid 3
+.Sh STANDARDS
+The identifiers are represented and generated in conformance with the DCE 1.1
+RPC specification.
+The
+.Fn uuidgen
+system call is itself not part of the specification.
+.Sh HISTORY
+The
+.Fn uuidgen
+system call first appeared in
+.Fx 5.0 .
diff --git a/lib/libc/sys/vfork.2 b/lib/libc/sys/vfork.2
new file mode 100644
index 000000000000..07405c5f805a
--- /dev/null
+++ b/lib/libc/sys/vfork.2
@@ -0,0 +1,145 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)vfork.2 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd May 22, 2016
+.Dt VFORK 2
+.Os
+.Sh NAME
+.Nm vfork
+.Nd create a new process without copying the address space
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft pid_t
+.Fn vfork void
+.Sh DESCRIPTION
+.Bf -symbolic
+Since this function is hard to use correctly from application software,
+it is recommended to use
+.Xr posix_spawn 3
+or
+.Xr fork 2
+instead.
+.Ef
+.Pp
+The
+.Fn vfork
+system call
+can be used to create new processes without fully copying the address
+space of the old process, which is inefficient in a paged
+environment.
+It is useful when the purpose of
+.Xr fork 2
+would have been to create a new system context for an
+.Xr execve 2 .
+The
+.Fn vfork
+system call
+differs from
+.Xr fork 2
+in that the child borrows the parent process's address space and the
+calling thread's stack
+until a call to
+.Xr execve 2
+or an exit (either by a call to
+.Xr _exit 2
+or abnormally).
+The calling thread is suspended while the child is using its resources.
+Other threads continue to run.
+.Pp
+The
+.Fn vfork
+system call
+returns 0 in the child's context and (later) the pid of the child in
+the parent's context.
+.Pp
+Many problems can occur when replacing
+.Xr fork 2
+with
+.Fn vfork .
+For example, it does not work to return while running in the child's context
+from the procedure that called
+.Fn vfork
+since the eventual return from
+.Fn vfork
+would then return to a no longer existent stack frame.
+Also, changing process state which is partially implemented in user space
+such as signal handlers with
+.Xr libthr 3
+will corrupt the parent's state.
+.Pp
+Be careful, also, to call
+.Xr _exit 2
+rather than
+.Xr exit 3
+if you cannot
+.Xr execve 2 ,
+since
+.Xr exit 3
+will flush and close standard I/O channels, and thereby mess up the
+parent processes standard I/O data structures.
+(Even with
+.Xr fork 2
+it is wrong to call
+.Xr exit 3
+since buffered data would then be flushed twice.)
+.Sh RETURN VALUES
+Same as for
+.Xr fork 2 .
+.Sh SEE ALSO
+.Xr _exit 2 ,
+.Xr execve 2 ,
+.Xr fork 2 ,
+.Xr rfork 2 ,
+.Xr sigaction 2 ,
+.Xr wait 2 ,
+.Xr exit 3 ,
+.Xr posix_spawn 3
+.Sh HISTORY
+The
+.Fn vfork
+system call appeared in
+.Bx 3 .
+.Sh BUGS
+To avoid a possible deadlock situation,
+processes that are children in the middle
+of a
+.Fn vfork
+are never sent
+.Dv SIGTTOU
+or
+.Dv SIGTTIN
+signals; rather,
+output or
+.Xr ioctl 2
+calls
+are allowed
+and input attempts result in an end-of-file indication.
diff --git a/lib/libc/sys/wait.2 b/lib/libc/sys/wait.2
new file mode 100644
index 000000000000..38b7bb7e6b33
--- /dev/null
+++ b/lib/libc/sys/wait.2
@@ -0,0 +1,680 @@
+.\" Copyright (c) 1980, 1991, 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)wait.2 8.2 (Berkeley) 4/19/94
+.\" $FreeBSD$
+.\"
+.Dd June 1, 2016
+.Dt WAIT 2
+.Os
+.Sh NAME
+.Nm wait ,
+.Nm waitid ,
+.Nm waitpid ,
+.Nm wait3 ,
+.Nm wait4 ,
+.Nm wait6
+.Nd wait for processes to change status
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/wait.h
+.Ft pid_t
+.Fn wait "int *status"
+.Ft pid_t
+.Fn waitpid "pid_t wpid" "int *status" "int options"
+.In signal.h
+.Ft int
+.Fn waitid "idtype_t idtype" "id_t id" "siginfo_t *info" "int options"
+.In sys/time.h
+.In sys/resource.h
+.Ft pid_t
+.Fn wait3 "int *status" "int options" "struct rusage *rusage"
+.Ft pid_t
+.Fn wait4 "pid_t wpid" "int *status" "int options" "struct rusage *rusage"
+.Ft pid_t
+.Fn wait6 "idtype_t idtype" "id_t id" "int *status" "int options" "struct __wrusage *wrusage" "siginfo_t *infop"
+.Sh DESCRIPTION
+The
+.Fn wait
+function suspends execution of its calling thread until
+.Fa status
+information is available for a child process
+or a signal is received.
+On return from a successful
+.Fn wait
+call,
+the
+.Fa status
+area contains information about the process that reported a status change
+as defined below.
+.Pp
+The
+.Fn wait4
+and
+.Fn wait6
+system calls provide a more general interface for programs
+that need to wait for specific child processes,
+that need resource utilization statistics accumulated by child processes,
+or that require options.
+The other wait functions are implemented using either
+.Fn wait4
+or
+.Fn wait6 .
+.Pp
+The
+.Fn wait6
+function is the most general function in this family and its distinct
+features are:
+.Pp
+All of the desired process statuses to be waited on must be explicitly
+specified in
+.Fa options .
+The
+.Fn wait ,
+.Fn waitpid ,
+.Fn wait3 ,
+and
+.Fn wait4
+functions all implicitly wait for exited and trapped processes,
+but the
+.Fn waitid
+and
+.Fn wait6
+functions require the corresponding
+.Dv WEXITED
+and
+.Dv WTRAPPED
+flags to be explicitly specified.
+This allows waiting for processes which have experienced other
+status changes without having to also handle the exit status from
+terminated processes.
+.Pp
+The
+.Fn wait6
+function accepts a
+.Fa wrusage
+argument which points to a structure defined as:
+.Bd -literal
+struct __wrusage {
+ struct rusage wru_self;
+ struct rusage wru_children;
+};
+.Ed
+.Pp
+This allows the calling process to collect resource usage statistics
+from both its own child process as well as from its grand children.
+When no resource usage statistics are needed this pointer can be
+.Dv NULL .
+.Pp
+The last argument
+.Fa infop
+must be either
+.Dv NULL
+or a pointer to a
+.Fa siginfo_t
+structure.
+If
+.Pf non- Dv NULL ,
+the structure is filled with the same data as for a
+.Dv SIGCHLD
+signal delivered when the process changed state.
+.Pp
+The set of child processes to be queried is specified by the arguments
+.Fa idtype
+and
+.Fa id .
+The separate
+.Fa idtype
+and
+.Fa id
+arguments support many other types of
+identifiers in addition to process IDs and process group IDs.
+.Bl -bullet -offset indent
+.It
+If
+.Fa idtype
+is
+.Dv P_PID ,
+.Fn waitid
+and
+.Fn wait6
+wait for the child process with a process ID equal to
+.Dv (pid_t)id .
+.It
+If
+.Fa idtype
+is
+.Dv P_PGID ,
+.Fn waitid
+and
+.Fn wait6
+wait for the child process with a process group ID equal to
+.Dv (pid_t)id .
+.It
+If
+.Fa idtype
+is
+.Dv P_ALL ,
+.Fn waitid
+and
+.Fn wait6
+wait for any child process and the
+.Dv id
+is ignored.
+.It
+If
+.Fa idtype
+is
+.Dv P_PID
+or
+.Dv P_PGID
+and the
+.Dv id
+is zero,
+.Fn waitid
+and
+.Fn wait6
+wait for any child process in the same process group as the caller.
+.El
+.Pp
+Non-standard identifier types supported by this
+implementation of
+.Fn waitid
+and
+.Fn wait6
+are:
+.Bl -tag -width P_JAILID
+.It Dv P_UID
+Wait for processes whose effective user ID is equal to
+.Dv (uid_t) Fa id .
+.It Dv P_GID
+Wait for processes whose effective group ID is equal to
+.Dv (gid_t) Fa id .
+.It Dv P_SID
+Wait for processes whose session ID is equal to
+.Fa id .
+.\" This is just how sessions work, not sure this needs to be documented here
+If the child process started its own session,
+its session ID will be the same as its process ID.
+Otherwise the session ID of a child process will match the caller's session ID.
+.It Dv P_JAILID
+Waits for processes within a jail whose jail identifier is equal to
+.Fa id .
+.El
+.Pp
+For the
+.Fn waitpid
+and
+.Fn wait4
+functions, the single
+.Fa wpid
+argument specifies the set of child processes for which to wait.
+.Bl -bullet -offset indent
+.It
+If
+.Fa wpid
+is -1, the call waits for any child process.
+.It
+If
+.Fa wpid
+is 0,
+the call waits for any child process in the process group of the caller.
+.It
+If
+.Fa wpid
+is greater than zero, the call waits for the process with process ID
+.Fa wpid .
+.It
+If
+.Fa wpid
+is less than -1, the call waits for any process whose process group ID
+equals the absolute value of
+.Fa wpid .
+.El
+.Pp
+The
+.Fa status
+argument is defined below.
+.Pp
+The
+.Fa options
+argument contains the bitwise OR of any of the following options.
+.Bl -tag -width WCONTINUED
+.It Dv WCONTINUED
+Report the status of selected processes that
+have continued from a job control stop by receiving a
+.Dv SIGCONT
+signal.
+.It Dv WNOHANG
+Do not block when
+there are no processes wishing to report status.
+.It Dv WUNTRACED
+Report the status of selected processes which are stopped due to a
+.Dv SIGTTIN , SIGTTOU , SIGTSTP ,
+or
+.Dv SIGSTOP
+signal.
+.It Dv WSTOPPED
+An alias for
+.Dv WUNTRACED .
+.It Dv WTRAPPED
+Report the status of selected processes which are being traced via
+.Xr ptrace 2
+and have trapped or reached a breakpoint.
+This flag is implicitly set for the functions
+.Fn wait ,
+.Fn waitpid ,
+.Fn wait3 ,
+and
+.Fn wait4 .
+.br
+For the
+.Fn waitid
+and
+.Fn wait6
+functions, the flag has to be explicitly included in
+.Fa options
+if status reports from trapped processes are expected.
+.It Dv WEXITED
+Report the status of selected processes which have terminated.
+This flag is implicitly set for the functions
+.Fn wait ,
+.Fn waitpid ,
+.Fn wait3 ,
+and
+.Fn wait4 .
+.br
+For the
+.Fn waitid
+and
+.Fn wait6
+functions, the flag has to be explicitly included in
+.Fa options
+if status reports from terminated processes are expected.
+.It Dv WNOWAIT
+Keep the process whose status is returned in a waitable state.
+The process may be waited for again after this call completes.
+.El
+.sp
+For the
+.Fn waitid
+and
+.Fn wait6
+functions, at least one of the options
+.Dv WEXITED ,
+.Dv WUNTRACED ,
+.Dv WSTOPPED ,
+.Dv WTRAPPED ,
+or
+.Dv WCONTINUED
+must be specified.
+Otherwise there will be no events for the call to report.
+To avoid hanging indefinitely in such a case these functions
+return -1 with
+.Dv errno
+set to
+.Dv EINVAL .
+.Pp
+If
+.Fa rusage
+is non-NULL, a summary of the resources used by the terminated
+process and all its children is returned.
+.Pp
+If
+.Fa wrusage
+is non-NULL, separate summaries are returned for the resources used
+by the terminated process and the resources used by all its children.
+.Pp
+If
+.Fa infop
+is non-NULL, a
+.Dv siginfo_t
+structure is returned with the
+.Fa si_signo
+field set to
+.Dv SIGCHLD
+and the
+.Fa si_pid
+field set to the process ID of the process reporting status.
+For the exited process, the
+.Fa si_status
+field of the
+.Dv siginfo_t
+structure contains the full 32 bit exit status passed to
+.Xr _exit 2 ;
+the
+.Fa status
+argument of other calls only returns 8 lowest bits of the exit status.
+.Pp
+When the
+.Dv WNOHANG
+option is specified and no processes
+wish to report status,
+.Fn waitid
+sets the
+.Fa si_signo
+and
+.Fa si_pid
+fields in
+.Fa infop
+to zero.
+Checking these fields is the only way to know if a status change was reported.
+.Pp
+When the
+.Dv WNOHANG
+option is specified and no processes
+wish to report status,
+.Fn wait4
+and
+.Fn wait6
+return a
+process id
+of 0.
+.Pp
+The
+.Fn wait
+call is the same as
+.Fn wait4
+with a
+.Fa wpid
+value of -1,
+with an
+.Fa options
+value of zero,
+and a
+.Fa rusage
+value of
+.Dv NULL .
+The
+.Fn waitpid
+function is identical to
+.Fn wait4
+with an
+.Fa rusage
+value of
+.Dv NULL .
+The older
+.Fn wait3
+call is the same as
+.Fn wait4
+with a
+.Fa wpid
+value of -1.
+The
+.Fn wait4
+function is identical to
+.Fn wait6
+with the flags
+.Dv WEXITED
+and
+.Dv WTRAPPED
+set in
+.Fa options
+and
+.Fa infop
+set to
+.Dv NULL .
+.Pp
+The following macros may be used to test the current status of the process.
+Exactly one of the following four macros will evaluate to a non-zero
+.Pq true
+value:
+.Bl -tag -width Ds
+.It Fn WIFCONTINUED status
+True if the process has not terminated, and
+has continued after a job control stop.
+This macro can be true only if the wait call specified the
+.Dv WCONTINUED
+option.
+.It Fn WIFEXITED status
+True if the process terminated normally by a call to
+.Xr _exit 2
+or
+.Xr exit 3 .
+.It Fn WIFSIGNALED status
+True if the process terminated due to receipt of a signal.
+.It Fn WIFSTOPPED status
+True if the process has not terminated, but has stopped and can be restarted.
+This macro can be true only if the wait call specified the
+.Dv WUNTRACED
+option
+or if the child process is being traced (see
+.Xr ptrace 2 ) .
+.El
+.Pp
+Depending on the values of those macros, the following macros
+produce the remaining status information about the child process:
+.Bl -tag -width Ds
+.It Fn WEXITSTATUS status
+If
+.Fn WIFEXITED status
+is true, evaluates to the low-order 8 bits
+of the argument passed to
+.Xr _exit 2
+or
+.Xr exit 3
+by the child.
+.It Fn WTERMSIG status
+If
+.Fn WIFSIGNALED status
+is true, evaluates to the number of the signal
+that caused the termination of the process.
+.It Fn WCOREDUMP status
+If
+.Fn WIFSIGNALED status
+is true, evaluates as true if the termination
+of the process was accompanied by the creation of a core file
+containing an image of the process when the signal was received.
+.It Fn WSTOPSIG status
+If
+.Fn WIFSTOPPED status
+is true, evaluates to the number of the signal
+that caused the process to stop.
+.El
+.Sh NOTES
+See
+.Xr sigaction 2
+for a list of termination signals.
+A status of 0 indicates normal termination.
+.Pp
+If a parent process terminates without
+waiting for all of its child processes to terminate,
+the remaining child processes are assigned the parent
+process 1 ID (the init process ID).
+.Pp
+If a signal is caught while any of the
+.Fn wait
+calls are pending,
+the call may be interrupted or restarted when the signal-catching routine
+returns,
+depending on the options in effect for the signal;
+see discussion of
+.Dv SA_RESTART
+in
+.Xr sigaction 2 .
+.Pp
+The implementation queues one
+.Dv SIGCHLD
+signal for each child process whose
+status has changed; if
+.Fn wait
+returns because the status of a child process is available, the pending
+SIGCHLD signal associated with the process ID of the child process will
+be discarded.
+Any other pending
+.Dv SIGCHLD
+signals remain pending.
+.Pp
+If
+.Dv SIGCHLD
+is blocked and
+.Fn wait
+returns because the status of a child process is available, the pending
+.Dv SIGCHLD
+signal will be cleared unless another status of the child process
+is available.
+.Sh RETURN VALUES
+If
+.Fn wait
+returns due to a stopped, continued,
+or terminated child process, the process ID of the child
+is returned to the calling process.
+Otherwise, a value of \-1
+is returned and
+.Va errno
+is set to indicate the error.
+.Pp
+If
+.Fn wait6 ,
+.Fn wait4 ,
+.Fn wait3 ,
+or
+.Fn waitpid
+returns due to a stopped, continued,
+or terminated child process, the process ID of the child
+is returned to the calling process.
+If there are no children not previously awaited,
+-1 is returned with
+.Va errno
+set to
+.Er ECHILD .
+Otherwise, if
+.Dv WNOHANG
+is specified and there are
+no stopped, continued or exited children,
+0 is returned.
+If an error is detected or a caught signal aborts the call,
+a value of -1
+is returned and
+.Va errno
+is set to indicate the error.
+.Pp
+If
+.Fn waitid
+returns because one or more processes have a state change to report,
+0 is returned.
+If an error is detected,
+a value of -1
+is returned and
+.Va errno
+is set to indicate the error.
+If
+.Dv WNOHANG
+is specified and there are
+no stopped, continued or exited children,
+0 is returned.
+The
+.Fa si_signo
+and
+.Fa si_pid
+fields of
+.Fa infop
+must be checked against zero to determine if a process reported status.
+.Pp
+.Fn wait
+called with -1 to wait for any child process will ignore a child that is
+referenced by a process descriptor (see
+.Xr pdfork 2 ) .
+Specific processes can still be waited on by specifying the process ID
+or descriptor (see
+.Xr pdwait 4 ) .
+.Sh ERRORS
+The
+.Fn wait
+function
+will fail and return immediately if:
+.Bl -tag -width Er
+.It Bq Er ECHILD
+The calling process has no existing unwaited-for
+child processes.
+.It Bq Er ECHILD
+No status from the terminated child process is available
+because the calling process has asked the system to discard
+such status by ignoring the signal
+.Dv SIGCHLD
+or setting the flag
+.Dv SA_NOCLDWAIT
+for that signal.
+.It Bq Er EFAULT
+The
+.Fa status
+or
+.Fa rusage
+argument points to an illegal address.
+(May not be detected before exit of a child process.)
+.It Bq Er EINTR
+The call was interrupted by a caught signal,
+or the signal did not have the
+.Dv SA_RESTART
+flag set.
+.It Bq Er EINVAL
+An invalid value was specified for
+.Fa options ,
+or
+.Fa idtype
+and
+.Fa id
+do not specify a valid set of processes.
+.El
+.Sh SEE ALSO
+.Xr _exit 2 ,
+.Xr ptrace 2 ,
+.Xr sigaction 2 ,
+.Xr exit 3 ,
+.Xr siginfo 3
+.Sh STANDARDS
+The
+.Fn wait ,
+.Fn waitpid ,
+and
+.Fn waitid
+functions are defined by POSIX;
+.Fn wait6 ,
+.Fn wait4 ,
+and
+.Fn wait3
+are not specified by POSIX.
+The
+.Fn WCOREDUMP
+macro
+is an extension to the POSIX interface.
+.Pp
+The ability to use the
+.Dv WNOWAIT
+flag with
+.Fn waitpid
+is an extension;
+.Tn POSIX
+only permits this flag with
+.Fn waitid .
+.Sh HISTORY
+The
+.Fn wait
+function appeared in
+.At v6 .
diff --git a/lib/libc/sys/wait4.c b/lib/libc/sys/wait4.c
new file mode 100644
index 000000000000..a5dbd0fcb1aa
--- /dev/null
+++ b/lib/libc/sys/wait4.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2014 The FreeBSD Foundation.
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Konstantin Belousov
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice(s), this list of conditions and the following disclaimer as
+ * the first lines of this file unmodified other than the possible
+ * addition of one or more copyright notices.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice(s), this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include "libc_private.h"
+
+__weak_reference(__sys_wait4, __wait4);
+
+#pragma weak wait4
+pid_t
+wait4(pid_t pid, int *status, int options, struct rusage *ru)
+{
+
+ return (((pid_t (*)(pid_t, int *, int, struct rusage *))
+ __libc_interposing[INTERPOS_wait4])(pid, status, options, ru));
+}
diff --git a/lib/libc/sys/wait6.c b/lib/libc/sys/wait6.c
new file mode 100644
index 000000000000..d280a7698747
--- /dev/null
+++ b/lib/libc/sys/wait6.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2015 The FreeBSD Foundation.
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Konstantin Belousov
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice(s), this list of conditions and the following disclaimer as
+ * the first lines of this file unmodified other than the possible
+ * addition of one or more copyright notices.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice(s), this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include "libc_private.h"
+
+__weak_reference(__sys_wait6, __wait6);
+
+#pragma weak wait6
+pid_t
+wait6(idtype_t idtype, id_t id, int *status, int options, struct __wrusage *ru,
+ siginfo_t *infop)
+{
+
+ return (((pid_t (*)(idtype_t, id_t, int *, int, struct __wrusage *,
+ siginfo_t *))__libc_interposing[INTERPOS_wait6])(idtype, id,
+ status, options, ru, infop));
+}
diff --git a/lib/libc/sys/write.2 b/lib/libc/sys/write.2
new file mode 100644
index 000000000000..0bfe56530f7c
--- /dev/null
+++ b/lib/libc/sys/write.2
@@ -0,0 +1,285 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)write.2 8.5 (Berkeley) 4/2/94
+.\" $FreeBSD$
+.\"
+.Dd December 15, 2015
+.Dt WRITE 2
+.Os
+.Sh NAME
+.Nm write ,
+.Nm writev ,
+.Nm pwrite ,
+.Nm pwritev
+.Nd write output
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Ft ssize_t
+.Fn write "int fd" "const void *buf" "size_t nbytes"
+.Ft ssize_t
+.Fn pwrite "int fd" "const void *buf" "size_t nbytes" "off_t offset"
+.In sys/uio.h
+.Ft ssize_t
+.Fn writev "int fd" "const struct iovec *iov" "int iovcnt"
+.Ft ssize_t
+.Fn pwritev "int fd" "const struct iovec *iov" "int iovcnt" "off_t offset"
+.Sh DESCRIPTION
+The
+.Fn write
+system call
+attempts to write
+.Fa nbytes
+of data to the object referenced by the descriptor
+.Fa fd
+from the buffer pointed to by
+.Fa buf .
+The
+.Fn writev
+system call
+performs the same action, but gathers the output data
+from the
+.Fa iovcnt
+buffers specified by the members of the
+.Fa iov
+array: iov[0], iov[1], ..., iov[iovcnt\|-\|1].
+The
+.Fn pwrite
+and
+.Fn pwritev
+system calls
+perform the same functions, but write to the specified position in
+the file without modifying the file pointer.
+.Pp
+For
+.Fn writev
+and
+.Fn pwritev ,
+the
+.Fa iovec
+structure is defined as:
+.Pp
+.Bd -literal -offset indent -compact
+struct iovec {
+ void *iov_base; /* Base address. */
+ size_t iov_len; /* Length. */
+};
+.Ed
+.Pp
+Each
+.Fa iovec
+entry specifies the base address and length of an area
+in memory from which data should be written.
+The
+.Fn writev
+system call
+will always write a complete area before proceeding
+to the next.
+.Pp
+On objects capable of seeking, the
+.Fn write
+starts at a position
+given by the pointer associated with
+.Fa fd ,
+see
+.Xr lseek 2 .
+Upon return from
+.Fn write ,
+the pointer is incremented by the number of bytes which were written.
+.Pp
+Objects that are not capable of seeking always write from the current
+position.
+The value of the pointer associated with such an object
+is undefined.
+.Pp
+If the real user is not the super-user, then
+.Fn write
+clears the set-user-id bit on a file.
+This prevents penetration of system security
+by a user who
+.Dq captures
+a writable set-user-id file
+owned by the super-user.
+.Pp
+When using non-blocking I/O on objects such as sockets that are subject
+to flow control,
+.Fn write
+and
+.Fn writev
+may write fewer bytes than requested;
+the return value must be noted,
+and the remainder of the operation should be retried when possible.
+.Sh RETURN VALUES
+Upon successful completion the number of bytes which were written
+is returned.
+Otherwise a -1 is returned and the global variable
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+The
+.Fn write ,
+.Fn writev ,
+.Fn pwrite
+and
+.Fn pwritev
+system calls
+will fail and the file pointer will remain unchanged if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa fd
+argument
+is not a valid descriptor open for writing.
+.It Bq Er EPIPE
+An attempt is made to write to a pipe that is not open
+for reading by any process.
+.It Bq Er EPIPE
+An attempt is made to write to a socket of type
+.Dv SOCK_STREAM
+that is not connected to a peer socket.
+.It Bq Er EFBIG
+An attempt was made to write a file that exceeds the process's
+file size limit or the maximum file size.
+.It Bq Er EFAULT
+Part of
+.Fa iov
+or data to be written to the file
+points outside the process's allocated address space.
+.It Bq Er EINVAL
+The pointer associated with
+.Fa fd
+was negative.
+.It Bq Er ENOSPC
+There is no free space remaining on the file system
+containing the file.
+.It Bq Er EDQUOT
+The user's quota of disk blocks on the file system
+containing the file has been exhausted.
+.It Bq Er EIO
+An I/O error occurred while reading from or writing to the file system.
+.It Bq Er EINTR
+A signal interrupted the write before it could be completed.
+.It Bq Er EAGAIN
+The file was marked for non-blocking I/O,
+and no data could be written immediately.
+.It Bq Er EROFS
+An attempt was made to write over a disk label area at the beginning
+of a slice.
+Use
+.Xr disklabel 8
+.Fl W
+to enable writing on the disk label area.
+.It Bq Er EINVAL
+The value
+.Fa nbytes
+is greater than
+.Dv INT_MAX .
+.El
+.Pp
+In addition,
+.Fn writev
+and
+.Fn pwritev
+may return one of the following errors:
+.Bl -tag -width Er
+.It Bq Er EDESTADDRREQ
+The destination is no longer available when writing to a
+.Ux
+domain datagram socket on which
+.Xr connect 2
+had been used to set a destination address.
+.It Bq Er EINVAL
+The
+.Fa iovcnt
+argument
+was less than or equal to 0, or greater than
+.Dv IOV_MAX .
+.It Bq Er EINVAL
+One of the
+.Fa iov_len
+values in the
+.Fa iov
+array was negative.
+.It Bq Er EINVAL
+The sum of the
+.Fa iov_len
+values in the
+.Fa iov
+array overflowed a 32-bit integer.
+.It Bq Er ENOBUFS
+The mbuf pool has been completely exhausted when writing to a socket.
+.El
+.Pp
+The
+.Fn pwrite
+and
+.Fn pwritev
+system calls may also return the following errors:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa offset
+value was negative.
+.It Bq Er ESPIPE
+The file descriptor is associated with a pipe, socket, or FIFO.
+.El
+.Sh SEE ALSO
+.Xr fcntl 2 ,
+.Xr lseek 2 ,
+.Xr open 2 ,
+.Xr pipe 2 ,
+.Xr select 2
+.Sh STANDARDS
+The
+.Fn write
+system call is expected to conform to
+.St -p1003.1-90 .
+The
+.Fn writev
+and
+.Fn pwrite
+system calls are expected to conform to
+.St -xpg4.2 .
+.Sh HISTORY
+The
+.Fn pwritev
+system call appeared in
+.Fx 6.0 .
+The
+.Fn pwrite
+function appeared in
+.At V.4 .
+The
+.Fn writev
+system call appeared in
+.Bx 4.2 .
+The
+.Fn write
+function appeared in
+.At v6 .
diff --git a/lib/libc/sys/write.c b/lib/libc/sys/write.c
new file mode 100644
index 000000000000..ffb1aa5ffba7
--- /dev/null
+++ b/lib/libc/sys/write.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2014 The FreeBSD Foundation.
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Konstantin Belousov
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice(s), this list of conditions and the following disclaimer as
+ * the first lines of this file unmodified other than the possible
+ * addition of one or more copyright notices.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice(s), this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+#include "libc_private.h"
+
+__weak_reference(__sys_write, __write);
+
+#pragma weak write
+ssize_t
+write(int fd, const void *buf, size_t nbytes)
+{
+
+ return (((ssize_t (*)(int, const void *, size_t))
+ __libc_interposing[INTERPOS_write])(fd, buf, nbytes));
+}
diff --git a/lib/libc/sys/writev.c b/lib/libc/sys/writev.c
new file mode 100644
index 000000000000..20b10053dc59
--- /dev/null
+++ b/lib/libc/sys/writev.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2014 The FreeBSD Foundation.
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Konstantin Belousov
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice(s), this list of conditions and the following disclaimer as
+ * the first lines of this file unmodified other than the possible
+ * addition of one or more copyright notices.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice(s), this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/syscall.h>
+#include <sys/uio.h>
+#include <unistd.h>
+#include "libc_private.h"
+
+__weak_reference(__sys_writev, __writev);
+
+#pragma weak writev
+ssize_t
+writev(int fd, const struct iovec *iov, int iovcnt)
+{
+
+ return (((ssize_t (*)(int, const struct iovec *, int))
+ __libc_interposing[INTERPOS_writev])(fd, iov, iovcnt));
+}
diff --git a/lib/libc/tests/Makefile b/lib/libc/tests/Makefile
new file mode 100644
index 000000000000..3e71350d82a9
--- /dev/null
+++ b/lib/libc/tests/Makefile
@@ -0,0 +1,40 @@
+# $FreeBSD$
+
+.include <src.opts.mk>
+
+SUBDIR= tls_dso
+
+TESTS_SUBDIRS= c063
+TESTS_SUBDIRS+= db
+TESTS_SUBDIRS+= gen
+TESTS_SUBDIRS+= hash
+TESTS_SUBDIRS+= inet
+TESTS_SUBDIRS+= net
+TESTS_SUBDIRS+= nss
+TESTS_SUBDIRS+= regex
+TESTS_SUBDIRS+= resolv
+TESTS_SUBDIRS+= rpc
+TESTS_SUBDIRS+= setjmp
+TESTS_SUBDIRS+= stdio
+TESTS_SUBDIRS+= stdlib
+TESTS_SUBDIRS+= string
+TESTS_SUBDIRS+= sys
+TESTS_SUBDIRS+= termios
+TESTS_SUBDIRS+= tls
+TESTS_SUBDIRS+= ttyio
+
+SUBDIR_DEPEND_tls= tls_dso
+
+.if ${MK_ICONV} != "no"
+TESTS_SUBDIRS+= iconv
+.endif
+
+.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.depend b/lib/libc/tests/Makefile.depend
new file mode 100644
index 000000000000..f80275d86ab1
--- /dev/null
+++ b/lib/libc/tests/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/lib/libc/tests/Makefile.netbsd-tests b/lib/libc/tests/Makefile.netbsd-tests
new file mode 100644
index 000000000000..18b0276b7296
--- /dev/null
+++ b/lib/libc/tests/Makefile.netbsd-tests
@@ -0,0 +1,9 @@
+# $FreeBSD$
+
+TESTSRC:= ${SRCTOP}/contrib/netbsd-tests/${RELDIR:C/libc\/tests/libc/}
+
+TESTSDIR:= ${TESTSBASE}/${RELDIR:C/libc\/tests/libc/}
+
+WARNS?= 2
+
+.include <netbsd-tests.test.mk>
diff --git a/lib/libc/tests/c063/Makefile b/lib/libc/tests/c063/Makefile
new file mode 100644
index 000000000000..05da6ea212a9
--- /dev/null
+++ b/lib/libc/tests/c063/Makefile
@@ -0,0 +1,25 @@
+# $FreeBSD$
+
+#TODO: t_o_search
+
+NETBSD_ATF_TESTS_C= faccessat_test
+NETBSD_ATF_TESTS_C+= fchmodat_test
+NETBSD_ATF_TESTS_C+= fchownat_test
+NETBSD_ATF_TESTS_C+= fexecve_test
+NETBSD_ATF_TESTS_C+= fstatat_test
+NETBSD_ATF_TESTS_C+= linkat_test
+NETBSD_ATF_TESTS_C+= mkdirat_test
+NETBSD_ATF_TESTS_C+= mkfifoat_test
+NETBSD_ATF_TESTS_C+= mknodat_test
+NETBSD_ATF_TESTS_C+= openat_test
+NETBSD_ATF_TESTS_C+= readlinkat_test
+NETBSD_ATF_TESTS_C+= renameat_test
+NETBSD_ATF_TESTS_C+= symlinkat_test
+NETBSD_ATF_TESTS_C+= unlinkat_test
+NETBSD_ATF_TESTS_C+= utimensat_test
+
+CFLAGS+= -D_INCOMPLETE_XOPEN_C063
+
+.include "../Makefile.netbsd-tests"
+
+.include <bsd.test.mk>
diff --git a/lib/libc/tests/c063/Makefile.depend b/lib/libc/tests/c063/Makefile.depend
new file mode 100644
index 000000000000..e8ee295f115a
--- /dev/null
+++ b/lib/libc/tests/c063/Makefile.depend
@@ -0,0 +1,20 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ gnu/lib/csu \
+ gnu/lib/libgcc \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/atf/libatf-c \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libnetbsd \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/lib/libc/tests/db/Makefile b/lib/libc/tests/db/Makefile
new file mode 100644
index 000000000000..132cfb321a22
--- /dev/null
+++ b/lib/libc/tests/db/Makefile
@@ -0,0 +1,20 @@
+# $FreeBSD$
+
+PACKAGE= tests
+
+BINDIR= ${TESTSDIR}
+
+PROGS= h_db
+PROGS+= h_lfsr
+
+${PACKAGE}FILES+= README
+
+NETBSD_ATF_TESTS_C+= db_hash_seq_test
+NETBSD_ATF_TESTS_SH+= db_test
+ATF_TESTS_SH_SED_db_test= -e 's,/bin/csh,/bin/cat,g'
+
+CFLAGS+= -I${SRCTOP}/lib/libc/db/btree
+
+.include "../Makefile.netbsd-tests"
+
+.include <bsd.test.mk>
diff --git a/lib/libc/tests/db/Makefile.depend b/lib/libc/tests/db/Makefile.depend
new file mode 100644
index 000000000000..3646e2e2b1af
--- /dev/null
+++ b/lib/libc/tests/db/Makefile.depend
@@ -0,0 +1,18 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ gnu/lib/csu \
+ gnu/lib/libgcc \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/lib/libc/tests/gen/Makefile b/lib/libc/tests/gen/Makefile
new file mode 100644
index 000000000000..2ec336ee5b28
--- /dev/null
+++ b/lib/libc/tests/gen/Makefile
@@ -0,0 +1,89 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+ATF_TESTS_C+= arc4random_test
+ATF_TESTS_C+= fmtcheck2_test
+ATF_TESTS_C+= fmtmsg_test
+ATF_TESTS_C+= fnmatch2_test
+ATF_TESTS_C+= fpclassify2_test
+ATF_TESTS_C+= ftw_test
+ATF_TESTS_C+= popen_test
+ATF_TESTS_C+= posix_spawn_test
+ATF_TESTS_C+= wordexp_test
+ATF_TESTS_C+= dlopen_empty_test
+
+# TODO: t_closefrom, t_cpuset, t_fmtcheck, t_randomid,
+# TODO: t_siginfo (fixes require further inspection)
+# TODO: t_sethostname_test (consistently screws up the hostname)
+
+CFLAGS+= -DTEST_LONG_DOUBLE
+
+# Not sure why this isn't defined for all architectures, since most
+# have long double.
+.if ${MACHINE_CPUARCH} == "aarch64" || \
+ ${MACHINE_CPUARCH} == "amd64" || \
+ ${MACHINE_CPUARCH} == "i386"
+CFLAGS+= -D__HAVE_LONG_DOUBLE
+.endif
+
+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"
+
+LIBADD.humanize_number_test+= util
+
+LIBADD.fpclassify_test+=m
+LIBADD.fpsetround_test+=m
+LIBADD.siginfo_test+= m
+
+LIBADD.nice_test+= pthread
+LIBADD.syslog_test+= pthread
+
+CFLAGS+= -I${.CURDIR}
+
+SRCS.fmtcheck2_test= fmtcheck_test.c
+SRCS.fnmatch2_test= fnmatch_test.c
+
+TESTS_SUBDIRS= execve
+TESTS_SUBDIRS+= posix_spawn
+
+# The old testcase name
+TEST_FNMATCH= test-fnmatch
+CLEANFILES+= ${GEN_SH_CASE_TESTCASES}
+sh-tests: .PHONY
+.for target in clean obj depend all
+ @cd ${.CURDIR} && ${MAKE} PROG=${TEST_FNMATCH} \
+ -DNO_SUBDIR ${target}
+.endfor
+ @cd ${.OBJDIR} && ./${TEST_FNMATCH} -s 1 > \
+ ${SRCTOP}/bin/sh/tests/builtins/case2.0
+ @cd ${.OBJDIR} && ./${TEST_FNMATCH} -s 2 > \
+ ${SRCTOP}/bin/sh/tests/builtins/case3.0
+
+.include <bsd.test.mk>
diff --git a/lib/libc/tests/gen/Makefile.depend b/lib/libc/tests/gen/Makefile.depend
new file mode 100644
index 000000000000..7826828c8155
--- /dev/null
+++ b/lib/libc/tests/gen/Makefile.depend
@@ -0,0 +1,23 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ gnu/lib/csu \
+ gnu/lib/libgcc \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/atf/libatf-c \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libnetbsd \
+ lib/libthr \
+ lib/libutil \
+ lib/msun \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/lib/libc/tests/gen/arc4random_test.c b/lib/libc/tests/gen/arc4random_test.c
new file mode 100644
index 000000000000..a28db303e88c
--- /dev/null
+++ b/lib/libc/tests/gen/arc4random_test.c
@@ -0,0 +1,89 @@
+/*-
+ * 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 <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <atf-c.h>
+
+/*
+ * BUFSIZE is the number of bytes of rc4 output to compare. The probability
+ * that this test fails spuriously is 2**(-BUFSIZE * 8).
+ */
+#define BUFSIZE 8
+
+/*
+ * Test whether arc4random_buf() returns the same sequence of bytes in both
+ * parent and child processes. (Hint: It shouldn't.)
+ */
+ATF_TC_WITHOUT_HEAD(test_arc4random);
+ATF_TC_BODY(test_arc4random, tc)
+{
+ struct shared_page {
+ char parentbuf[BUFSIZE];
+ char childbuf[BUFSIZE];
+ } *page;
+ pid_t pid;
+ char c;
+
+ page = mmap(NULL, sizeof(struct shared_page), PROT_READ | PROT_WRITE,
+ MAP_ANON | MAP_SHARED, -1, 0);
+ ATF_REQUIRE_MSG(page != MAP_FAILED, "mmap failed; errno=%d", errno);
+
+ arc4random_buf(&c, 1);
+
+ pid = fork();
+ ATF_REQUIRE(0 <= pid);
+ if (pid == 0) {
+ /* child */
+ arc4random_buf(page->childbuf, BUFSIZE);
+ exit(0);
+ } else {
+ /* parent */
+ int status;
+ arc4random_buf(page->parentbuf, BUFSIZE);
+ wait(&status);
+ }
+ ATF_CHECK_MSG(memcmp(page->parentbuf, page->childbuf, BUFSIZE) != 0,
+ "sequences are the same");
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, test_arc4random);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/gen/dlopen_empty_test.c b/lib/libc/tests/gen/dlopen_empty_test.c
new file mode 100644
index 000000000000..42f9269a10b2
--- /dev/null
+++ b/lib/libc/tests/gen/dlopen_empty_test.c
@@ -0,0 +1,97 @@
+/*-
+ * Copyright (c) 2016 Maksym Sobolyev
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/stat.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <atf-c.h>
+
+static const char *funname;
+static char *soname;
+
+static void
+sigsegv_handler(int sig __unused)
+{
+ unlink(soname);
+ free(soname);
+ atf_tc_fail("got SIGSEGV in the %s(3)", funname);
+}
+
+ATF_TC(dlopen_empty_test);
+ATF_TC_HEAD(dlopen_empty_test, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Tests the dlopen() of an empty file "
+ "returns an error");
+}
+ATF_TC_BODY(dlopen_empty_test, tc)
+{
+ char tempname[] = "/tmp/temp.XXXXXX";
+ char *fname;
+ int fd;
+ void *dlh;
+ struct sigaction act, oact;
+
+ fname = mktemp(tempname);
+ ATF_REQUIRE_MSG(fname != NULL, "mktemp failed; errno=%d", errno);
+ asprintf(&soname, "%s.so", fname);
+ ATF_REQUIRE_MSG(soname != NULL, "asprintf failed; errno=%d", ENOMEM);
+ fd = open(soname, O_WRONLY | O_CREAT | O_TRUNC, DEFFILEMODE);
+ ATF_REQUIRE_MSG(fd != -1, "open(\"%s\") failed; errno=%d", soname, errno);
+ close(fd);
+
+ act.sa_handler = sigsegv_handler;
+ act.sa_flags = 0;
+ sigemptyset(&act.sa_mask);
+ ATF_CHECK_MSG(sigaction(SIGSEGV, &act, &oact) != -1,
+ "sigaction() failed");
+
+ funname = "dlopen";
+ dlh = dlopen(soname, RTLD_LAZY);
+ if (dlh != NULL) {
+ funname = "dlclose";
+ dlclose(dlh);
+ }
+ ATF_REQUIRE_MSG(dlh == NULL, "dlopen(\"%s\") did not fail", soname);
+ unlink(soname);
+ free(soname);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, dlopen_empty_test);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/gen/execve/Makefile b/lib/libc/tests/gen/execve/Makefile
new file mode 100644
index 000000000000..5e8bc6fb7640
--- /dev/null
+++ b/lib/libc/tests/gen/execve/Makefile
@@ -0,0 +1,9 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+NETBSD_ATF_TESTS_C= execve_test
+
+.include "../../Makefile.netbsd-tests"
+
+.include <bsd.test.mk>
diff --git a/lib/libc/tests/gen/execve/Makefile.depend b/lib/libc/tests/gen/execve/Makefile.depend
new file mode 100644
index 000000000000..e8ee295f115a
--- /dev/null
+++ b/lib/libc/tests/gen/execve/Makefile.depend
@@ -0,0 +1,20 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ gnu/lib/csu \
+ gnu/lib/libgcc \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/atf/libatf-c \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libnetbsd \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/lib/libc/tests/gen/fmtcheck_test.c b/lib/libc/tests/gen/fmtcheck_test.c
new file mode 100644
index 000000000000..3e180c9ca2e6
--- /dev/null
+++ b/lib/libc/tests/gen/fmtcheck_test.c
@@ -0,0 +1,105 @@
+/* $NetBSD: tfmtcheck.c,v 1.3 2008/04/28 20:23:04 martin Exp $ */
+
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code was contributed to The NetBSD Foundation by Allen Briggs.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <atf-c.h>
+
+struct test_fmt {
+ char *fmt1;
+ char *fmt2;
+ int correct;
+} test_fmts[] = {
+ { "%d", "%d", 1 },
+ { "%2d", "%2.2d", 1 },
+ { "%x", "%d", 1 },
+ { "%u", "%d", 1 },
+ { "%03d", "%d", 1 },
+ { "%-2d", "%d", 1 },
+ { "%d", "%-12.1d", 1 },
+ { "%d", "%-01.3d", 1 },
+ { "%X", "%-01.3d", 1 },
+ { "%D", "%ld", 1 },
+ { "%s", "%s", 1 },
+ { "%s", "This is a %s test", 1 },
+ { "Hi, there. This is a %s test", "%s", 1 },
+ { "%d", "%s", 2 },
+ { "%e", "%s", 2 },
+ { "%r", "%d", 2 },
+ { "%*.2d", "%*d", 1 },
+ { "%2.*d", "%*d", 2 },
+ { "%*d", "%*d", 1 },
+ { "%-3", "%d", 2 },
+ { "%d %s", "%d", 2 },
+ { "%*.*.*d", "%*.*.*d", 2 },
+ { "%d", "%d %s", 1 },
+ { "%40s", "%20s", 1 },
+ { "%x %x %x", "%o %u %d", 1 },
+ { "%o %u %d", "%x %x %X", 1 },
+ { "%#o %u %#-d", "%x %#x %X", 1 },
+ { "%qd", "%llx", 1 },
+ { "%%", "%llx", 1 },
+ { "%p %30s %#llx %-10.*e", "This number %lu%% and string %s has %qd numbers and %.*g floats", 1 },
+};
+
+ATF_TC_WITHOUT_HEAD(fmtcheck_test);
+ATF_TC_BODY(fmtcheck_test, tc)
+{
+ int i;
+ const char *f, *cf, *f1, *f2;
+
+ for (i = 0; i < nitems(test_fmts); i++) {
+ f1 = test_fmts[i].fmt1;
+ f2 = test_fmts[i].fmt2;
+ f = fmtcheck(f1, f2);
+ if (test_fmts[i].correct == 1)
+ cf = f1;
+ else
+ cf = f2;
+ ATF_CHECK_MSG(f == cf,
+ "Test %d: (%s) vs. (%s) failed "
+ "(should have returned %s)", i + 1, f1, f2,
+ (test_fmts[i].correct == 1) ? "1st" : "2nd");
+ }
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, fmtcheck_test);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/gen/fmtmsg_test.c b/lib/libc/tests/gen/fmtmsg_test.c
new file mode 100644
index 000000000000..aa3ca19425fe
--- /dev/null
+++ b/lib/libc/tests/gen/fmtmsg_test.c
@@ -0,0 +1,252 @@
+/*-
+ * Copyright (c) 2012 Jilles Tjoelker
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/wait.h>
+#include <err.h>
+#include <errno.h>
+#include <fmtmsg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <atf-c.h>
+
+static char *run_test(long classification, const char *label, int severity,
+ const char *text, const char *action, const char *tag);
+
+struct testcase {
+ long classification;
+ const char *label;
+ int severity;
+ const char *text;
+ const char *action;
+ const char *tag;
+ const char *msgverb;
+ const char *result;
+} testcases[] = {
+ {
+ MM_UTIL | MM_PRINT, "BSD:ls", MM_ERROR,
+ "illegal option -- z", "refer to manual", "BSD:ls:001",
+ NULL,
+ "BSD:ls: ERROR: illegal option -- z\n"
+ "TO FIX: refer to manual BSD:ls:001\n"
+ },
+ {
+ MM_UTIL | MM_PRINT, "BSD:ls", MM_ERROR,
+ "illegal option -- z", "refer to manual", "BSD:ls:001",
+ "text:severity:action:tag",
+ "illegal option -- z: ERROR\n"
+ "TO FIX: refer to manual BSD:ls:001\n"
+ },
+ {
+ MM_UTIL | MM_PRINT, "BSD:ls", MM_ERROR,
+ "illegal option -- z", "refer to manual", "BSD:ls:001",
+ "text",
+ "illegal option -- z\n"
+ },
+ {
+ MM_UTIL | MM_PRINT, "BSD:ls", MM_ERROR,
+ "illegal option -- z", "refer to manual", "BSD:ls:001",
+ "severity:text",
+ "ERROR: illegal option -- z\n"
+ },
+ {
+ MM_UTIL | MM_PRINT, "BSD:ls", MM_ERROR,
+ "illegal option -- z", "refer to manual", "BSD:ls:001",
+ "ignore me",
+ "BSD:ls: ERROR: illegal option -- z\n"
+ "TO FIX: refer to manual BSD:ls:001\n"
+ },
+ {
+ MM_UTIL | MM_PRINT, "BSD:ls", MM_ERROR,
+ "illegal option -- z", "refer to manual", "BSD:ls:001",
+ "tag:severity:text:nothing:action",
+ "BSD:ls: ERROR: illegal option -- z\n"
+ "TO FIX: refer to manual BSD:ls:001\n"
+ },
+ {
+ MM_UTIL | MM_PRINT, "BSD:ls", MM_ERROR,
+ "illegal option -- z", "refer to manual", "BSD:ls:001",
+ "",
+ "BSD:ls: ERROR: illegal option -- z\n"
+ "TO FIX: refer to manual BSD:ls:001\n"
+ },
+ {
+ MM_UTIL | MM_PRINT, MM_NULLLBL, MM_ERROR,
+ "illegal option -- z", "refer to manual", "BSD:ls:001",
+ NULL,
+ "ERROR: illegal option -- z\n"
+ "TO FIX: refer to manual BSD:ls:001\n"
+ },
+ {
+ MM_UTIL | MM_PRINT, "BSD:ls", MM_ERROR,
+ "illegal option -- z", MM_NULLACT, MM_NULLTAG,
+ NULL,
+ "BSD:ls: ERROR: illegal option -- z\n"
+ },
+ {
+ MM_UTIL | MM_NULLMC, "BSD:ls", MM_ERROR,
+ "illegal option -- z", "refer to manual", "BSD:ls:001",
+ NULL,
+ ""
+ },
+ {
+ MM_APPL | MM_PRINT, "ABCDEFGHIJ:abcdefghijklmn", MM_INFO,
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
+ "refer to manual", "ABCDEFGHIJ:abcdefghijklmn:001",
+ NULL,
+ "ABCDEFGHIJ:abcdefghijklmn: INFO: "
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n"
+ "TO FIX: refer to manual ABCDEFGHIJ:abcdefghijklmn:001\n"
+ },
+ {
+ MM_OPSYS | MM_PRINT, "TEST:test", MM_HALT,
+ "failed", "nothing can help me", "NOTHING",
+ NULL,
+ "TEST:test: HALT: failed\n"
+ "TO FIX: nothing can help me NOTHING\n"
+ },
+ {
+ MM_OPSYS | MM_PRINT, "TEST:test", MM_WARNING,
+ "failed", "nothing can help me", "NOTHING",
+ NULL,
+ "TEST:test: WARNING: failed\n"
+ "TO FIX: nothing can help me NOTHING\n"
+ },
+ {
+ MM_OPSYS | MM_PRINT, "TEST:test", MM_NOSEV,
+ "failed", "nothing can help me", "NOTHING",
+ NULL,
+ "TEST:test: failed\n"
+ "TO FIX: nothing can help me NOTHING\n"
+ }
+};
+
+static char *
+run_test(long classification, const char *label, int severity,
+ const char *text, const char *action, const char *tag)
+{
+ int pip[2];
+ pid_t pid, wpid;
+ char *result, *p;
+ size_t resultsize;
+ ssize_t n;
+ int status;
+
+ if (pipe(pip) == -1)
+ err(2, "pipe");
+ pid = fork();
+ if (pid == -1)
+ err(2, "fork");
+ if (pid == 0) {
+ close(pip[0]);
+ if (pip[1] != STDERR_FILENO &&
+ dup2(pip[1], STDERR_FILENO) == -1)
+ _exit(2);
+ if (fmtmsg(classification, label, severity, text, action, tag)
+ != MM_OK)
+ _exit(1);
+ else
+ _exit(0);
+ }
+ close(pip[1]);
+ resultsize = 1024;
+ result = malloc(resultsize);
+ p = result;
+ while ((n = read(pip[0], p, result + resultsize - p - 1)) != 0) {
+ if (n == -1) {
+ if (errno == EINTR)
+ continue;
+ else
+ err(2, "read");
+ }
+ p += n;
+ if (result + resultsize == p - 1) {
+ resultsize *= 2;
+ result = realloc(result, resultsize);
+ if (result == NULL)
+ err(2, "realloc");
+ }
+ }
+ if (memchr(result, '\0', p - result) != NULL) {
+ free(result);
+ return (NULL);
+ }
+ *p = '\0';
+ close(pip[0]);
+ while ((wpid = waitpid(pid, &status, 0)) == -1 && errno == EINTR)
+ ;
+ if (wpid == -1)
+ err(2, "waitpid");
+ if (status != 0) {
+ free(result);
+ return (NULL);
+ }
+ return (result);
+}
+
+ATF_TC_WITHOUT_HEAD(fmtmsg_test);
+ATF_TC_BODY(fmtmsg_test, tc)
+{
+ char *result;
+ struct testcase *t;
+ int i;
+
+ for (i = 0; i < nitems(testcases); i++) {
+ t = &testcases[i];
+ if (t->msgverb != NULL)
+ setenv("MSGVERB", t->msgverb, 1);
+ else
+ unsetenv("MSGVERB");
+ result = run_test(t->classification, t->label, t->severity,
+ t->text, t->action, t->tag);
+ ATF_CHECK_MSG(result != NULL, "testcase %d failed", i + 1);
+ if (result != NULL)
+ ATF_CHECK_MSG(strcmp(result, t->result) == 0,
+ "results for testcase %d didn't match; "
+ "`%s` != `%s`", i + 1, result, t->result);
+ free(result);
+ }
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, fmtmsg_test);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/gen/fnmatch_test.c b/lib/libc/tests/gen/fnmatch_test.c
new file mode 100644
index 000000000000..8d9ead2eff91
--- /dev/null
+++ b/lib/libc/tests/gen/fnmatch_test.c
@@ -0,0 +1,188 @@
+/*-
+ * Copyright (c) 2010 Jilles Tjoelker
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <atf-c.h>
+
+#include "fnmatch_testcases.h"
+
+static const char *
+flags_to_string(int flags)
+{
+ static const int flagvalues[] = { FNM_NOESCAPE, FNM_PATHNAME,
+ FNM_PERIOD, FNM_LEADING_DIR, FNM_CASEFOLD, 0 };
+ static const char flagnames[] = "FNM_NOESCAPE\0FNM_PATHNAME\0FNM_PERIOD\0FNM_LEADING_DIR\0FNM_CASEFOLD\0";
+ static char result[sizeof(flagnames) + 3 * sizeof(int) + 2];
+ char *p;
+ size_t i, len;
+ const char *fp;
+
+ p = result;
+ fp = flagnames;
+ for (i = 0; flagvalues[i] != 0; i++) {
+ len = strlen(fp);
+ if (flags & flagvalues[i]) {
+ if (p != result)
+ *p++ = '|';
+ memcpy(p, fp, len);
+ p += len;
+ flags &= ~flagvalues[i];
+ }
+ fp += len + 1;
+ }
+ if (p == result)
+ memcpy(p, "0", 2);
+ else if (flags != 0)
+ sprintf(p, "%d", flags);
+ else
+ *p = '\0';
+ return result;
+}
+
+ATF_TC_WITHOUT_HEAD(fnmatch_test);
+ATF_TC_BODY(fnmatch_test, tc)
+{
+ size_t i;
+ int flags, result;
+ struct testcase *t;
+
+ for (i = 0; i < nitems(testcases); i++) {
+ t = &testcases[i];
+ flags = t->flags;
+ do {
+ result = fnmatch(t->pattern, t->string, flags);
+ if (result != t->result)
+ break;
+ if (strchr(t->pattern, '\\') == NULL &&
+ !(flags & FNM_NOESCAPE)) {
+ flags |= FNM_NOESCAPE;
+ result = fnmatch(t->pattern, t->string, flags);
+ if (result != t->result)
+ break;
+ flags = t->flags;
+ }
+ if (strchr(t->pattern, '\\') != NULL &&
+ strchr(t->string, '\\') == NULL &&
+ t->result == FNM_NOMATCH &&
+ !(flags & (FNM_NOESCAPE | FNM_LEADING_DIR))) {
+ flags |= FNM_NOESCAPE;
+ result = fnmatch(t->pattern, t->string, flags);
+ if (result != t->result)
+ break;
+ flags = t->flags;
+ }
+ if ((t->string[0] != '.' || t->pattern[0] == '.' ||
+ t->result == FNM_NOMATCH) &&
+ !(flags & (FNM_PATHNAME | FNM_PERIOD))) {
+ flags |= FNM_PERIOD;
+ result = fnmatch(t->pattern, t->string, flags);
+ if (result != t->result)
+ break;
+ flags = t->flags;
+ }
+ if ((strchr(t->string, '/') == NULL ||
+ t->result == FNM_NOMATCH) &&
+ !(flags & FNM_PATHNAME)) {
+ flags |= FNM_PATHNAME;
+ result = fnmatch(t->pattern, t->string, flags);
+ if (result != t->result)
+ break;
+ flags = t->flags;
+ }
+ if ((((t->string[0] != '.' || t->pattern[0] == '.') &&
+ strstr(t->string, "/.") == NULL) ||
+ t->result == FNM_NOMATCH) &&
+ flags & FNM_PATHNAME && !(flags & FNM_PERIOD)) {
+ flags |= FNM_PERIOD;
+ result = fnmatch(t->pattern, t->string, flags);
+ if (result != t->result)
+ break;
+ flags = t->flags;
+ }
+ if ((((t->string[0] != '.' || t->pattern[0] == '.') &&
+ strchr(t->string, '/') == NULL) ||
+ t->result == FNM_NOMATCH) &&
+ !(flags & (FNM_PATHNAME | FNM_PERIOD))) {
+ flags |= FNM_PATHNAME | FNM_PERIOD;
+ result = fnmatch(t->pattern, t->string, flags);
+ if (result != t->result)
+ break;
+ flags = t->flags;
+ }
+ if ((strchr(t->string, '/') == NULL || t->result == 0)
+ && !(flags & FNM_LEADING_DIR)) {
+ flags |= FNM_LEADING_DIR;
+ result = fnmatch(t->pattern, t->string, flags);
+ if (result != t->result)
+ break;
+ flags = t->flags;
+ }
+ if (t->result == 0 && !(flags & FNM_CASEFOLD)) {
+ flags |= FNM_CASEFOLD;
+ result = fnmatch(t->pattern, t->string, flags);
+ if (result != t->result)
+ break;
+ flags = t->flags;
+ }
+ if (strchr(t->pattern, '\\') == NULL &&
+ t->result == 0 &&
+ !(flags & (FNM_NOESCAPE | FNM_CASEFOLD))) {
+ flags |= FNM_NOESCAPE | FNM_CASEFOLD;
+ result = fnmatch(t->pattern, t->string, flags);
+ if (result != t->result)
+ break;
+ flags = t->flags;
+ }
+ } while (0);
+
+ ATF_CHECK(result == t->result);
+ if (result == t->result)
+ printf("fnmatch(\"%s\", \"%s\", %s) == %d\n",
+ t->pattern, t->string, flags_to_string(flags), result);
+ else
+ printf("fnmatch(\"%s\", \"%s\", %s) != %d (was %d)\n",
+ t->pattern, t->string, flags_to_string(flags),
+ t->result, result);
+ }
+
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, fnmatch_test);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/gen/fnmatch_testcases.h b/lib/libc/tests/gen/fnmatch_testcases.h
new file mode 100644
index 000000000000..537011fc34a7
--- /dev/null
+++ b/lib/libc/tests/gen/fnmatch_testcases.h
@@ -0,0 +1,176 @@
+/*-
+ * Copyright (c) 2010 Jilles Tjoelker
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <fnmatch.h>
+
+struct testcase {
+ const char *pattern;
+ const char *string;
+ int flags;
+ int result;
+} testcases[] = {
+ { "", "", 0, 0 },
+ { "a", "a", 0, 0 },
+ { "a", "b", 0, FNM_NOMATCH },
+ { "a", "A", 0, FNM_NOMATCH },
+ { "*", "a", 0, 0 },
+ { "*", "aa", 0, 0 },
+ { "*a", "a", 0, 0 },
+ { "*a", "b", 0, FNM_NOMATCH },
+ { "*a*", "b", 0, FNM_NOMATCH },
+ { "*a*b*", "ab", 0, 0 },
+ { "*a*b*", "qaqbq", 0, 0 },
+ { "*a*bb*", "qaqbqbbq", 0, 0 },
+ { "*a*bc*", "qaqbqbcq", 0, 0 },
+ { "*a*bb*", "qaqbqbb", 0, 0 },
+ { "*a*bc*", "qaqbqbc", 0, 0 },
+ { "*a*bb", "qaqbqbb", 0, 0 },
+ { "*a*bc", "qaqbqbc", 0, 0 },
+ { "*a*bb", "qaqbqbbq", 0, FNM_NOMATCH },
+ { "*a*bc", "qaqbqbcq", 0, FNM_NOMATCH },
+ { "*a*a*a*a*a*a*a*a*a*a*", "aaaaaaaaa", 0, FNM_NOMATCH },
+ { "*a*a*a*a*a*a*a*a*a*a*", "aaaaaaaaaa", 0, 0 },
+ { "*a*a*a*a*a*a*a*a*a*a*", "aaaaaaaaaaa", 0, 0 },
+ { ".*.*.*.*.*.*.*.*.*.*", ".........", 0, FNM_NOMATCH },
+ { ".*.*.*.*.*.*.*.*.*.*", "..........", 0, 0 },
+ { ".*.*.*.*.*.*.*.*.*.*", "...........", 0, 0 },
+ { "*?*?*?*?*?*?*?*?*?*?*", "123456789", 0, FNM_NOMATCH },
+ { "??????????*", "123456789", 0, FNM_NOMATCH },
+ { "*??????????", "123456789", 0, FNM_NOMATCH },
+ { "*?*?*?*?*?*?*?*?*?*?*", "1234567890", 0, 0 },
+ { "??????????*", "1234567890", 0, 0 },
+ { "*??????????", "1234567890", 0, 0 },
+ { "*?*?*?*?*?*?*?*?*?*?*", "12345678901", 0, 0 },
+ { "??????????*", "12345678901", 0, 0 },
+ { "*??????????", "12345678901", 0, 0 },
+ { "[x]", "x", 0, 0 },
+ { "[*]", "*", 0, 0 },
+ { "[?]", "?", 0, 0 },
+ { "[", "[", 0, 0 },
+ { "[[]", "[", 0, 0 },
+ { "[[]", "x", 0, FNM_NOMATCH },
+ { "[*]", "", 0, FNM_NOMATCH },
+ { "[*]", "x", 0, FNM_NOMATCH },
+ { "[?]", "x", 0, FNM_NOMATCH },
+ { "*[*]*", "foo*foo", 0, 0 },
+ { "*[*]*", "foo", 0, FNM_NOMATCH },
+ { "[0-9]", "0", 0, 0 },
+ { "[0-9]", "5", 0, 0 },
+ { "[0-9]", "9", 0, 0 },
+ { "[0-9]", "/", 0, FNM_NOMATCH },
+ { "[0-9]", ":", 0, FNM_NOMATCH },
+ { "[0-9]", "*", 0, FNM_NOMATCH },
+ { "[!0-9]", "0", 0, FNM_NOMATCH },
+ { "[!0-9]", "5", 0, FNM_NOMATCH },
+ { "[!0-9]", "9", 0, FNM_NOMATCH },
+ { "[!0-9]", "/", 0, 0 },
+ { "[!0-9]", ":", 0, 0 },
+ { "[!0-9]", "*", 0, 0 },
+ { "*[0-9]", "a0", 0, 0 },
+ { "*[0-9]", "a5", 0, 0 },
+ { "*[0-9]", "a9", 0, 0 },
+ { "*[0-9]", "a/", 0, FNM_NOMATCH },
+ { "*[0-9]", "a:", 0, FNM_NOMATCH },
+ { "*[0-9]", "a*", 0, FNM_NOMATCH },
+ { "*[!0-9]", "a0", 0, FNM_NOMATCH },
+ { "*[!0-9]", "a5", 0, FNM_NOMATCH },
+ { "*[!0-9]", "a9", 0, FNM_NOMATCH },
+ { "*[!0-9]", "a/", 0, 0 },
+ { "*[!0-9]", "a:", 0, 0 },
+ { "*[!0-9]", "a*", 0, 0 },
+ { "*[0-9]", "a00", 0, 0 },
+ { "*[0-9]", "a55", 0, 0 },
+ { "*[0-9]", "a99", 0, 0 },
+ { "*[0-9]", "a0a0", 0, 0 },
+ { "*[0-9]", "a5a5", 0, 0 },
+ { "*[0-9]", "a9a9", 0, 0 },
+ { "\\*", "*", 0, 0 },
+ { "\\?", "?", 0, 0 },
+ { "\\[x]", "[x]", 0, 0 },
+ { "\\[", "[", 0, 0 },
+ { "\\\\", "\\", 0, 0 },
+ { "*\\**", "foo*foo", 0, 0 },
+ { "*\\**", "foo", 0, FNM_NOMATCH },
+ { "*\\\\*", "foo\\foo", 0, 0 },
+ { "*\\\\*", "foo", 0, FNM_NOMATCH },
+ { "\\(", "(", 0, 0 },
+ { "\\a", "a", 0, 0 },
+ { "\\*", "a", 0, FNM_NOMATCH },
+ { "\\?", "a", 0, FNM_NOMATCH },
+ { "\\*", "\\*", 0, FNM_NOMATCH },
+ { "\\?", "\\?", 0, FNM_NOMATCH },
+ { "\\[x]", "\\[x]", 0, FNM_NOMATCH },
+ { "\\[x]", "\\x", 0, FNM_NOMATCH },
+ { "\\[", "\\[", 0, FNM_NOMATCH },
+ { "\\(", "\\(", 0, FNM_NOMATCH },
+ { "\\a", "\\a", 0, FNM_NOMATCH },
+ { "\\", "\\", 0, FNM_NOMATCH },
+ { "\\", "", 0, 0 },
+ { "\\*", "\\*", FNM_NOESCAPE, 0 },
+ { "\\?", "\\?", FNM_NOESCAPE, 0 },
+ { "\\", "\\", FNM_NOESCAPE, 0 },
+ { "\\\\", "\\", FNM_NOESCAPE, FNM_NOMATCH },
+ { "\\\\", "\\\\", FNM_NOESCAPE, 0 },
+ { "*\\*", "foo\\foo", FNM_NOESCAPE, 0 },
+ { "*\\*", "foo", FNM_NOESCAPE, FNM_NOMATCH },
+ { "*", ".", FNM_PERIOD, FNM_NOMATCH },
+ { "?", ".", FNM_PERIOD, FNM_NOMATCH },
+ { ".*", ".", 0, 0 },
+ { ".*", "..", 0, 0 },
+ { ".*", ".a", 0, 0 },
+ { "[0-9]", ".", FNM_PERIOD, FNM_NOMATCH },
+ { "a*", "a.", 0, 0 },
+ { "a/a", "a/a", FNM_PATHNAME, 0 },
+ { "a/*", "a/a", FNM_PATHNAME, 0 },
+ { "*/a", "a/a", FNM_PATHNAME, 0 },
+ { "*/*", "a/a", FNM_PATHNAME, 0 },
+ { "a*b/*", "abbb/x", FNM_PATHNAME, 0 },
+ { "a*b/*", "abbb/.x", FNM_PATHNAME, 0 },
+ { "*", "a/a", FNM_PATHNAME, FNM_NOMATCH },
+ { "*/*", "a/a/a", FNM_PATHNAME, FNM_NOMATCH },
+ { "b/*", "b/.x", FNM_PATHNAME | FNM_PERIOD, FNM_NOMATCH },
+ { "b*/*", "a/.x", FNM_PATHNAME | FNM_PERIOD, FNM_NOMATCH },
+ { "b/.*", "b/.x", FNM_PATHNAME | FNM_PERIOD, 0 },
+ { "b*/.*", "b/.x", FNM_PATHNAME | FNM_PERIOD, 0 },
+ { "a", "A", FNM_CASEFOLD, 0 },
+ { "A", "a", FNM_CASEFOLD, 0 },
+ { "[a]", "A", FNM_CASEFOLD, 0 },
+ { "[A]", "a", FNM_CASEFOLD, 0 },
+ { "a", "b", FNM_CASEFOLD, FNM_NOMATCH },
+ { "a", "a/b", FNM_PATHNAME, FNM_NOMATCH },
+ { "*", "a/b", FNM_PATHNAME, FNM_NOMATCH },
+ { "*b", "a/b", FNM_PATHNAME, FNM_NOMATCH },
+ { "a", "a/b", FNM_PATHNAME | FNM_LEADING_DIR, 0 },
+ { "*", "a/b", FNM_PATHNAME | FNM_LEADING_DIR, 0 },
+ { "*", ".a/b", FNM_PATHNAME | FNM_LEADING_DIR, 0 },
+ { "*a", ".a/b", FNM_PATHNAME | FNM_LEADING_DIR, 0 },
+ { "*", ".a/b", FNM_PATHNAME | FNM_PERIOD | FNM_LEADING_DIR, FNM_NOMATCH },
+ { "*a", ".a/b", FNM_PATHNAME | FNM_PERIOD | FNM_LEADING_DIR, FNM_NOMATCH },
+ { "a*b/*", "abbb/.x", FNM_PATHNAME | FNM_PERIOD, FNM_NOMATCH },
+};
diff --git a/lib/libc/tests/gen/fpclassify2_test.c b/lib/libc/tests/gen/fpclassify2_test.c
new file mode 100644
index 000000000000..a6bb1df3c9f2
--- /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/ftw_test.c b/lib/libc/tests/gen/ftw_test.c
new file mode 100644
index 000000000000..b120f01ff4f1
--- /dev/null
+++ b/lib/libc/tests/gen/ftw_test.c
@@ -0,0 +1,127 @@
+/*-
+ * Copyright (c) 2012 Jilles Tjoelker
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Limited test program for nftw() as specified by IEEE Std. 1003.1-2008.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/wait.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <ftw.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <spawn.h>
+#include <unistd.h>
+
+#include <atf-c.h>
+
+extern char **environ;
+
+static char template[] = "testftw.XXXXXXXXXX";
+static char dir[PATH_MAX];
+static int ftwflags;
+
+static int
+cb(const char *path, const struct stat *st, int type, struct FTW *f)
+{
+
+ switch (type) {
+ case FTW_D:
+ if ((ftwflags & FTW_DEPTH) == 0)
+ return (0);
+ break;
+ case FTW_DP:
+ if ((ftwflags & FTW_DEPTH) != 0)
+ return (0);
+ break;
+ case FTW_SL:
+ if ((ftwflags & FTW_PHYS) != 0)
+ return (0);
+ break;
+ }
+ ATF_CHECK_MSG(false,
+ "unexpected path=%s type=%d f.level=%d\n",
+ path, type, f->level);
+ return (0);
+}
+
+ATF_TC_WITHOUT_HEAD(ftw_test);
+ATF_TC_BODY(ftw_test, tc)
+{
+ int fd;
+
+ ATF_REQUIRE_MSG(mkdtemp(template) != NULL, "mkdtemp failed");
+
+ /* XXX: the path needs to be absolute for the 0/FTW_DEPTH testcases */
+ ATF_REQUIRE_MSG(realpath(template, dir) != NULL,
+ "realpath failed; errno=%d", errno);
+
+ fd = open(dir, O_DIRECTORY|O_RDONLY);
+ ATF_REQUIRE_MSG(fd != -1, "open failed; errno=%d", errno);
+
+ ATF_REQUIRE_MSG(mkdirat(fd, "d1", 0777) == 0,
+ "mkdirat failed; errno=%d", errno);
+
+ ATF_REQUIRE_MSG(symlinkat(dir, fd, "d1/looper") == 0,
+ "symlinkat failed; errno=%d", errno);
+
+ printf("ftwflags=FTW_PHYS\n");
+ ftwflags = FTW_PHYS;
+ ATF_REQUIRE_MSG(nftw(dir, cb, 10, ftwflags) != -1,
+ "nftw FTW_PHYS failed; errno=%d", errno);
+
+ printf("ftwflags=FTW_PHYS|FTW_DEPTH\n");
+ ftwflags = FTW_PHYS|FTW_DEPTH;
+ ATF_REQUIRE_MSG(nftw(dir, cb, 10, ftwflags) != -1,
+ "nftw FTW_PHYS|FTW_DEPTH failed; errno=%d", errno);
+
+ printf("ftwflags=0\n");
+ ftwflags = 0;
+ ATF_REQUIRE_MSG(nftw(dir, cb, 10, ftwflags) != -1,
+ "nftw 0 failed; errno=%d", errno);
+
+ printf("ftwflags=FTW_DEPTH\n");
+ ftwflags = FTW_DEPTH;
+ ATF_REQUIRE_MSG(nftw(dir, cb, 10, ftwflags) != -1,
+ "nftw FTW_DEPTH failed; errno=%d", errno);
+
+ close(fd);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, ftw_test);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/gen/popen_test.c b/lib/libc/tests/gen/popen_test.c
new file mode 100644
index 000000000000..5c615b7146e9
--- /dev/null
+++ b/lib/libc/tests/gen/popen_test.c
@@ -0,0 +1,251 @@
+/*-
+ * Copyright (c) 2013 Jilles Tjoelker
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Limited test program for popen() as specified by IEEE Std. 1003.1-2008,
+ * with BSD extensions.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <atf-c.h>
+
+static volatile sig_atomic_t got_sigpipe;
+
+static void
+sigpipe_handler(int sig __unused)
+{
+ got_sigpipe = 1;
+}
+
+static void
+check_cloexec(FILE *fp, const char *mode)
+{
+ int exp_flags, flags;
+
+ flags = fcntl(fileno(fp), F_GETFD);
+ ATF_CHECK_MSG(flags != -1, "fcntl(F_GETFD) failed; errno=%d", errno);
+ if (flags == -1)
+ return;
+ if (strchr(mode, 'e') != NULL)
+ exp_flags = FD_CLOEXEC;
+ else
+ exp_flags = 0;
+ ATF_CHECK_MSG((flags & FD_CLOEXEC) == exp_flags,
+ "bad cloexec flag; %d != %d", flags, exp_flags);
+}
+
+ATF_TC_WITHOUT_HEAD(popen_all_modes_test);
+ATF_TC_BODY(popen_all_modes_test, tc)
+{
+ FILE *fp;
+ int i, status;
+ const char *mode;
+ const char *allmodes[] = { "r", "w", "r+", "re", "we", "r+e", "re+" };
+
+ for (i = 0; i < nitems(allmodes); i++) {
+ mode = allmodes[i];
+ fp = popen("exit 7", mode);
+ ATF_CHECK_MSG(fp != NULL, "popen(, \"%s\") failed", mode);
+ if (fp == NULL)
+ continue;
+ check_cloexec(fp, mode);
+ status = pclose(fp);
+ ATF_CHECK_MSG(WIFEXITED(status) && WEXITSTATUS(status) == 7,
+ "bad exit status (no I/O)");
+ }
+}
+
+ATF_TC_WITHOUT_HEAD(popen_rmodes_test);
+ATF_TC_BODY(popen_rmodes_test, tc)
+{
+ FILE *fp;
+ const char *rmodes[] = { "r", "r+", "re", "r+e", "re+" };
+ const char *mode;
+ char buf[80];
+ int i, status;
+
+ for (i = 0; i < nitems(rmodes); i++) {
+ mode = rmodes[i];
+ fp = popen("exit 9", mode);
+ ATF_CHECK_MSG(fp != NULL, "popen(, \"%s\") failed", mode);
+ if (fp == NULL)
+ continue;
+ check_cloexec(fp, mode);
+ bool input_error_1 = !(fgetc(fp) != EOF || !feof(fp) || !ferror(fp));
+ ATF_CHECK_MSG(!input_error_1, "input error 1");
+ if (input_error_1)
+ continue;
+ status = pclose(fp);
+ ATF_CHECK_MSG(WIFEXITED(status) && WEXITSTATUS(status) == 9,
+ "bad exit status (input)");
+ }
+
+ for (i = 0; i < nitems(rmodes); i++) {
+ char *sres;
+ mode = rmodes[i];
+ fp = popen("echo hi there", mode);
+ ATF_CHECK_MSG(fp != NULL, "popen(, \"%s\") failed", mode);
+ if (fp == NULL)
+ continue;
+ check_cloexec(fp, mode);
+ ATF_CHECK_MSG((sres = fgets(buf, sizeof(buf), fp)) != NULL,
+ "Input error 2");
+ if (sres != NULL)
+ ATF_CHECK_MSG(strcmp(buf, "hi there\n") == 0,
+ "Bad input 1");
+ status = pclose(fp);
+ ATF_CHECK_MSG(WIFEXITED(status) && WEXITSTATUS(status) == 0,
+ "Bad exit status (input)");
+ }
+}
+
+ATF_TC_WITHOUT_HEAD(popen_wmodes_test);
+ATF_TC_BODY(popen_wmodes_test, tc)
+{
+ FILE *fp, *fp2;
+ const char *wmodes[] = { "w", "r+", "we", "r+e", "re+" };
+ const char *mode;
+ struct sigaction act, oact;
+ int i, j, status;
+
+ for (i = 0; i < nitems(wmodes); i++) {
+ mode = wmodes[i];
+ fp = popen("read x && [ \"$x\" = abcd ]", mode);
+ ATF_CHECK_MSG(fp != NULL, "popen(, \"%s\") failed", mode);
+ if (fp == NULL)
+ continue;
+ check_cloexec(fp, mode);
+ ATF_CHECK_MSG(fputs("abcd\n", fp) != EOF,
+ "Output error 1");
+ status = pclose(fp);
+ ATF_CHECK_MSG(WIFEXITED(status) && WEXITSTATUS(status) == 0,
+ "Bad exit status (output)");
+ }
+
+ act.sa_handler = sigpipe_handler;
+ act.sa_flags = SA_RESTART;
+ sigemptyset(&act.sa_mask);
+ ATF_CHECK_MSG(sigaction(SIGPIPE, &act, &oact) != -1,
+ "sigaction() failed");
+ for (i = 0; i < nitems(wmodes); i++) {
+ mode = wmodes[i];
+ fp = popen("exit 88", mode);
+ ATF_CHECK_MSG(fp != NULL, "popen(, \"%s\") failed", mode);
+ if (fp == NULL)
+ continue;
+ check_cloexec(fp, mode);
+ got_sigpipe = 0;
+ while (fputs("abcd\n", fp) != EOF)
+ ;
+ ATF_CHECK_MSG(ferror(fp) && errno == EPIPE, "Expected EPIPE");
+ ATF_CHECK_MSG(got_sigpipe, "Expected SIGPIPE");
+ status = pclose(fp);
+ ATF_CHECK_MSG(WIFEXITED(status) && WEXITSTATUS(status) == 88,
+ "Bad exit status (EPIPE)");
+ }
+ ATF_CHECK_MSG(sigaction(SIGPIPE, &oact, NULL) != -1,
+ "sigaction() failed");
+
+ for (i = 0; i < nitems(wmodes); i++) {
+ for (j = 0; j < nitems(wmodes); j++) {
+ mode = wmodes[i];
+ fp = popen("read x", mode);
+ ATF_CHECK_MSG(fp != NULL,
+ "popen(, \"%s\") failed", mode);
+ if (fp == NULL)
+ continue;
+ mode = wmodes[j];
+ fp2 = popen("read x", mode);
+ ATF_CHECK_MSG(fp2 != NULL,
+ "popen(, \"%s\") failed", mode);
+ if (fp2 == NULL) {
+ pclose(fp);
+ continue;
+ }
+ /* If fp2 inherits fp's pipe, we will deadlock here. */
+ status = pclose(fp);
+ ATF_CHECK_MSG(WIFEXITED(status) && WEXITSTATUS(status) == 1,
+ "bad exit status (2 pipes)");
+ status = pclose(fp2);
+ ATF_CHECK_MSG(WIFEXITED(status) && WEXITSTATUS(status) == 1,
+ "bad exit status (2 pipes)");
+ }
+ }
+}
+
+ATF_TC_WITHOUT_HEAD(popen_rwmodes_test);
+ATF_TC_BODY(popen_rwmodes_test, tc)
+{
+ const char *rwmodes[] = { "r+", "r+e", "re+" };
+ FILE *fp;
+ const char *mode;
+ char *sres;
+ char buf[80];
+ int i, ires, status;
+
+ for (i = 0; i < nitems(rwmodes); i++) {
+ mode = rwmodes[i];
+ fp = popen("read x && printf '%s\\n' \"Q${x#a}\"", mode);
+ ATF_CHECK_MSG(fp != NULL, "popen(, \"%s\") failed", mode);
+ if (fp == NULL)
+ continue;
+ check_cloexec(fp, mode);
+ ATF_CHECK_MSG((ires = fputs("abcd\n", fp)) != EOF,
+ "Output error 2");
+ if (ires != EOF) {
+ sres = fgets(buf, sizeof(buf), fp);
+ ATF_CHECK_MSG(sres != NULL, "Input error 3");
+ if (sres != NULL)
+ ATF_CHECK_MSG(strcmp(buf, "Qbcd\n") == 0,
+ "Bad input 2");
+ }
+ status = pclose(fp);
+ ATF_CHECK_MSG(WIFEXITED(status) && WEXITSTATUS(status) == 0,
+ "bad exit status (I/O)");
+ }
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, popen_all_modes_test);
+ ATF_TP_ADD_TC(tp, popen_rmodes_test);
+ ATF_TP_ADD_TC(tp, popen_wmodes_test);
+ ATF_TP_ADD_TC(tp, popen_rwmodes_test);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/gen/posix_spawn/Makefile b/lib/libc/tests/gen/posix_spawn/Makefile
new file mode 100644
index 000000000000..9b687c6d5fed
--- /dev/null
+++ b/lib/libc/tests/gen/posix_spawn/Makefile
@@ -0,0 +1,30 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+BINDIR= ${TESTSDIR}
+
+NETBSD_ATF_TESTS_C= fileactions_test
+NETBSD_ATF_TESTS_C+= spawn_test
+NETBSD_ATF_TESTS_C+= spawnattr_test
+
+PROGS= h_fileactions
+PROGS+= h_spawn
+PROGS+= h_spawnattr
+
+SCRIPTS= h_nonexec
+SCRIPTS+= h_zero
+
+CLEANFILES+= h_nonexec
+
+.include "../../Makefile.netbsd-tests"
+
+h_zero:
+ dd if=/dev/zero of=h_zero bs=1k count=2 status=none
+ chmod a+x h_zero
+
+CLEANFILES+= h_zero
+
+WARNS?=3
+
+.include <bsd.test.mk>
diff --git a/lib/libc/tests/gen/posix_spawn/Makefile.depend b/lib/libc/tests/gen/posix_spawn/Makefile.depend
new file mode 100644
index 000000000000..e8ee295f115a
--- /dev/null
+++ b/lib/libc/tests/gen/posix_spawn/Makefile.depend
@@ -0,0 +1,20 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ gnu/lib/csu \
+ gnu/lib/libgcc \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/atf/libatf-c \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libnetbsd \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/lib/libc/tests/gen/posix_spawn_test.c b/lib/libc/tests/gen/posix_spawn_test.c
new file mode 100644
index 000000000000..e04d103e1a30
--- /dev/null
+++ b/lib/libc/tests/gen/posix_spawn_test.c
@@ -0,0 +1,103 @@
+/*-
+ * Copyright (c) 2011 Jilles Tjoelker
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Test program for posix_spawn() and posix_spawnp() as specified by
+ * IEEE Std. 1003.1-2008.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/wait.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <spawn.h>
+
+#include <atf-c.h>
+
+char *myenv[2] = { "answer=42", NULL };
+
+ATF_TC_WITHOUT_HEAD(posix_spawn_simple_test);
+ATF_TC_BODY(posix_spawn_simple_test, tc)
+{
+ char *myargs[4];
+ int error, status;
+ pid_t pid, waitres;
+
+ /* Make sure we have no child processes. */
+ while (waitpid(-1, NULL, 0) != -1)
+ ;
+ ATF_REQUIRE_MSG(errno == ECHILD, "errno was not ECHILD: %d", errno);
+
+ /* Simple test. */
+ myargs[0] = "sh";
+ myargs[1] = "-c";
+ myargs[2] = "exit $answer";
+ myargs[3] = NULL;
+ error = posix_spawnp(&pid, myargs[0], NULL, NULL, myargs, myenv);
+ ATF_REQUIRE(error == 0);
+ waitres = waitpid(pid, &status, 0);
+ ATF_REQUIRE(waitres == pid);
+ ATF_REQUIRE(WIFEXITED(status) && WEXITSTATUS(status) == 42);
+}
+
+ATF_TC_WITHOUT_HEAD(posix_spawn_no_such_command_negative_test);
+ATF_TC_BODY(posix_spawn_no_such_command_negative_test, tc)
+{
+ char *myargs[4];
+ int error, status;
+ pid_t pid, waitres;
+
+ /*
+ * If the executable does not exist, the function shall either fail
+ * and not create a child process or succeed and create a child
+ * process that exits with status 127.
+ */
+ myargs[0] = "/var/empty/nonexistent";
+ myargs[1] = NULL;
+ error = posix_spawn(&pid, myargs[0], NULL, NULL, myargs, myenv);
+ if (error == 0) {
+ waitres = waitpid(pid, &status, 0);
+ ATF_REQUIRE(waitres == pid);
+ ATF_REQUIRE(WIFEXITED(status) && WEXITSTATUS(status) == 127);
+ } else {
+ ATF_REQUIRE(error == ENOENT);
+ waitres = waitpid(-1, NULL, 0);
+ ATF_REQUIRE(waitres == -1 && errno == ECHILD);
+ }
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, posix_spawn_simple_test);
+ ATF_TP_ADD_TC(tp, posix_spawn_no_such_command_negative_test);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/gen/test-fnmatch.c b/lib/libc/tests/gen/test-fnmatch.c
new file mode 100644
index 000000000000..7771ab37f0a0
--- /dev/null
+++ b/lib/libc/tests/gen/test-fnmatch.c
@@ -0,0 +1,102 @@
+/*-
+ * Copyright (c) 2010 Jilles Tjoelker
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "fnmatch_testcases.h"
+
+static int
+write_sh_tests(const char *progname, int num)
+{
+ size_t i;
+ struct testcase *t;
+
+ printf("# Generated by %s -s %d, do not edit.\n", progname, num);
+ printf("# $" "FreeBSD$\n");
+ printf("failures=\n");
+ printf("failed() { printf '%%s\\n' \"Failed: $1 '$2' '$3'\"; failures=x$failures; }\n");
+ if (num == 1) {
+ printf("testmatch() { eval \"case \\$2 in ''$1) ;; *) failed testmatch \\\"\\$@\\\";; esac\"; }\n");
+ printf("testnomatch() { eval \"case \\$2 in ''$1) failed testnomatch \\\"\\$@\\\";; esac\"; }\n");
+ } else if (num == 2) {
+ printf("# We do not treat a backslash specially in this case,\n");
+ printf("# but this is not the case in all shells.\n");
+ printf("netestmatch() { case $2 in $1) ;; *) failed netestmatch \"$@\";; esac; }\n");
+ printf("netestnomatch() { case $2 in $1) failed netestnomatch \"$@\";; esac; }\n");
+ }
+
+ for (i = 0; i < nitems(testcases); i++) {
+ t = &testcases[i];
+ if (strchr(t->pattern, '\'') != NULL ||
+ strchr(t->string, '\'') != NULL)
+ continue;
+ if (t->flags == 0 && strcmp(t->pattern, "\\") == 0)
+ continue;
+ if (num == 1 && t->flags == 0)
+ printf("test%smatch '%s' '%s'\n",
+ t->result == FNM_NOMATCH ? "no" : "",
+ t->pattern, t->string);
+ if (num == 2 && (t->flags == FNM_NOESCAPE ||
+ (t->flags == 0 && strchr(t->pattern, '\\') == NULL)))
+ printf("netest%smatch '%s' '%s'\n",
+ t->result == FNM_NOMATCH ? "no" : "",
+ t->pattern, t->string);
+ }
+ printf("[ -z \"$failures\" ]\n");
+ return 0;
+}
+
+static void
+usage(char *progname)
+{
+ fprintf(stderr, "usage: %s [-s num]\n", progname);
+ fprintf(stderr, "-s option writes tests for sh(1), num is 1 or 2\n");
+}
+
+int
+main(int argc, char *argv[])
+{
+ int opt;
+
+ while ((opt = getopt(argc, argv, "s:")) != -1) {
+ switch (opt) {
+ case 's':
+ return (write_sh_tests(argv[0], atoi(optarg)));
+ default:
+ usage(argv[0]);
+ exit(1);
+ }
+ }
+ usage(argv[0]);
+ exit(1);
+}
diff --git a/lib/libc/tests/gen/wordexp_test.c b/lib/libc/tests/gen/wordexp_test.c
new file mode 100644
index 000000000000..3ccc67774c7f
--- /dev/null
+++ b/lib/libc/tests/gen/wordexp_test.c
@@ -0,0 +1,360 @@
+/*-
+ * Copyright (c) 2003 Tim J. Robbins
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Test program for wordexp() and wordfree() as specified by
+ * IEEE Std. 1003.1-2001.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/wait.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wordexp.h>
+
+#include <atf-c.h>
+
+static void
+chld_handler(int x)
+{
+ int status, serrno;
+
+ (void)x;
+ serrno = errno;
+ while (waitpid(-1, &status, WNOHANG) > 0)
+ ;
+ errno = serrno;
+}
+
+ATF_TC_WITHOUT_HEAD(simple_test);
+ATF_TC_BODY(simple_test, tc)
+{
+ wordexp_t we;
+ int r;
+
+ /* Test that the macros are there. */
+ (void)(WRDE_APPEND + WRDE_DOOFFS + WRDE_NOCMD + WRDE_REUSE +
+ WRDE_SHOWERR + WRDE_UNDEF);
+ (void)(WRDE_BADCHAR + WRDE_BADVAL + WRDE_CMDSUB + WRDE_NOSPACE +
+ WRDE_SYNTAX);
+
+ /* Simple test. */
+ r = wordexp("hello world", &we, 0);
+ ATF_REQUIRE(r == 0);
+ ATF_REQUIRE(we.we_wordc == 2);
+ ATF_REQUIRE(strcmp(we.we_wordv[0], "hello") == 0);
+ ATF_REQUIRE(strcmp(we.we_wordv[1], "world") == 0);
+ ATF_REQUIRE(we.we_wordv[2] == NULL);
+ wordfree(&we);
+}
+
+ATF_TC_WITHOUT_HEAD(long_output_test);
+ATF_TC_BODY(long_output_test, tc)
+{
+ char longdata[6 * 10000 + 1];
+ wordexp_t we;
+ int i, r;
+
+ /* Long output. */
+ for (i = 0; i < 10000; i++)
+ snprintf(longdata + 6 * i, 7, "%05d ", i);
+ r = wordexp(longdata, &we, 0);
+ ATF_REQUIRE(r == 0);
+ ATF_REQUIRE(we.we_wordc == 10000);
+ ATF_REQUIRE(we.we_wordv[10000] == NULL);
+ wordfree(&we);
+}
+
+ATF_TC_WITHOUT_HEAD(WRDE_DOOFFS_test);
+ATF_TC_BODY(WRDE_DOOFFS_test, tc)
+{
+ wordexp_t we;
+ int r;
+
+ we.we_offs = 3;
+ r = wordexp("hello world", &we, WRDE_DOOFFS);
+ ATF_REQUIRE(r == 0);
+ ATF_REQUIRE(we.we_wordc == 2);
+ ATF_REQUIRE(we.we_wordv[0] == NULL);
+ ATF_REQUIRE(we.we_wordv[1] == NULL);
+ ATF_REQUIRE(we.we_wordv[2] == NULL);
+ ATF_REQUIRE(strcmp(we.we_wordv[3], "hello") == 0);
+ ATF_REQUIRE(strcmp(we.we_wordv[4], "world") == 0);
+ ATF_REQUIRE(we.we_wordv[5] == NULL);
+ wordfree(&we);
+}
+
+ATF_TC_WITHOUT_HEAD(WRDE_REUSE_test);
+ATF_TC_BODY(WRDE_REUSE_test, tc)
+{
+ wordexp_t we;
+ int r;
+
+ r = wordexp("hello world", &we, 0);
+ r = wordexp("hello world", &we, WRDE_REUSE);
+ ATF_REQUIRE(r == 0);
+ ATF_REQUIRE(we.we_wordc == 2);
+ ATF_REQUIRE(strcmp(we.we_wordv[0], "hello") == 0);
+ ATF_REQUIRE(strcmp(we.we_wordv[1], "world") == 0);
+ ATF_REQUIRE(we.we_wordv[2] == NULL);
+ wordfree(&we);
+}
+
+ATF_TC_WITHOUT_HEAD(WRDE_APPEND_test);
+ATF_TC_BODY(WRDE_APPEND_test, tc)
+{
+ wordexp_t we;
+ int r;
+
+ r = wordexp("this is", &we, 0);
+ ATF_REQUIRE(r == 0);
+ r = wordexp("a test", &we, WRDE_APPEND);
+ ATF_REQUIRE(r == 0);
+ ATF_REQUIRE(we.we_wordc == 4);
+ ATF_REQUIRE(strcmp(we.we_wordv[0], "this") == 0);
+ ATF_REQUIRE(strcmp(we.we_wordv[1], "is") == 0);
+ ATF_REQUIRE(strcmp(we.we_wordv[2], "a") == 0);
+ ATF_REQUIRE(strcmp(we.we_wordv[3], "test") == 0);
+ ATF_REQUIRE(we.we_wordv[4] == NULL);
+ wordfree(&we);
+}
+
+ATF_TC_WITHOUT_HEAD(WRDE_DOOFFS__WRDE_APPEND_test);
+ATF_TC_BODY(WRDE_DOOFFS__WRDE_APPEND_test, tc)
+{
+ wordexp_t we;
+ int r;
+
+ we.we_offs = 2;
+ r = wordexp("this is", &we, WRDE_DOOFFS);
+ ATF_REQUIRE(r == 0);
+ r = wordexp("a test", &we, WRDE_APPEND|WRDE_DOOFFS);
+ ATF_REQUIRE(r == 0);
+ r = wordexp("of wordexp", &we, WRDE_APPEND|WRDE_DOOFFS);
+ ATF_REQUIRE(r == 0);
+ ATF_REQUIRE(we.we_wordc == 6);
+ ATF_REQUIRE(we.we_wordv[0] == NULL);
+ ATF_REQUIRE(we.we_wordv[1] == NULL);
+ ATF_REQUIRE(strcmp(we.we_wordv[2], "this") == 0);
+ ATF_REQUIRE(strcmp(we.we_wordv[3], "is") == 0);
+ ATF_REQUIRE(strcmp(we.we_wordv[4], "a") == 0);
+ ATF_REQUIRE(strcmp(we.we_wordv[5], "test") == 0);
+ ATF_REQUIRE(strcmp(we.we_wordv[6], "of") == 0);
+ ATF_REQUIRE(strcmp(we.we_wordv[7], "wordexp") == 0);
+ ATF_REQUIRE(we.we_wordv[8] == NULL);
+ wordfree(&we);
+}
+
+ATF_TC_WITHOUT_HEAD(WRDE_UNDEF_test);
+ATF_TC_BODY(WRDE_UNDEF_test, tc)
+{
+ wordexp_t we;
+ int r;
+
+ r = wordexp("${dont_set_me}", &we, WRDE_UNDEF);
+ ATF_REQUIRE(r == WRDE_BADVAL);
+}
+
+ATF_TC_WITHOUT_HEAD(WRDE_NOCMD_test);
+ATF_TC_BODY(WRDE_NOCMD_test, tc)
+{
+ wordexp_t we;
+ int r;
+
+ r = wordexp("`date`", &we, WRDE_NOCMD);
+ ATF_REQUIRE(r == WRDE_CMDSUB);
+ r = wordexp("\"`date`\"", &we, WRDE_NOCMD);
+ ATF_REQUIRE(r == WRDE_CMDSUB);
+ r = wordexp("$(date)", &we, WRDE_NOCMD);
+ ATF_REQUIRE(r == WRDE_CMDSUB);
+ r = wordexp("\"$(date)\"", &we, WRDE_NOCMD);
+ ATF_REQUIRE(r == WRDE_CMDSUB);
+ r = wordexp("$((3+5))", &we, WRDE_NOCMD);
+ ATF_REQUIRE(r == 0);
+ r = wordexp("\\$\\(date\\)", &we, WRDE_NOCMD|WRDE_REUSE);
+ ATF_REQUIRE(r == 0);
+ r = wordexp("'`date`'", &we, WRDE_NOCMD|WRDE_REUSE);
+ ATF_REQUIRE(r == 0);
+ r = wordexp("'$(date)'", &we, WRDE_NOCMD|WRDE_REUSE);
+ ATF_REQUIRE(r == 0);
+ wordfree(&we);
+}
+
+ATF_TC_WITHOUT_HEAD(WRDE_BADCHAR_test);
+ATF_TC_BODY(WRDE_BADCHAR_test, tc)
+{
+ wordexp_t we;
+ int r;
+
+ r = wordexp("'\n|&;<>(){}'", &we, 0);
+ ATF_REQUIRE(r == 0);
+ r = wordexp("\"\n|&;<>(){}\"", &we, WRDE_REUSE);
+ ATF_REQUIRE(r == 0);
+ r = wordexp("\\\n\\|\\&\\;\\<\\>\\(\\)\\{\\}", &we, WRDE_REUSE);
+ ATF_REQUIRE(r == 0);
+ wordfree(&we);
+ r = wordexp("test \n test", &we, 0);
+ ATF_REQUIRE(r == WRDE_BADCHAR);
+ r = wordexp("test | test", &we, 0);
+ ATF_REQUIRE(r == WRDE_BADCHAR);
+ r = wordexp("test & test", &we, 0);
+ ATF_REQUIRE(r == WRDE_BADCHAR);
+ r = wordexp("test ; test", &we, 0);
+ ATF_REQUIRE(r == WRDE_BADCHAR);
+ r = wordexp("test > test", &we, 0);
+ ATF_REQUIRE(r == WRDE_BADCHAR);
+ r = wordexp("test < test", &we, 0);
+ ATF_REQUIRE(r == WRDE_BADCHAR);
+ r = wordexp("test ( test", &we, 0);
+ ATF_REQUIRE(r == WRDE_BADCHAR);
+ r = wordexp("test ) test", &we, 0);
+ ATF_REQUIRE(r == WRDE_BADCHAR);
+ r = wordexp("test { test", &we, 0);
+ ATF_REQUIRE(r == WRDE_BADCHAR);
+ r = wordexp("test } test", &we, 0);
+ ATF_REQUIRE(r == WRDE_BADCHAR);
+}
+
+ATF_TC_WITHOUT_HEAD(WRDE_SYNTAX_test);
+ATF_TC_BODY(WRDE_SYNTAX_test, tc)
+{
+ wordexp_t we;
+ int r;
+
+ r = wordexp("'", &we, 0);
+ ATF_REQUIRE(r == WRDE_SYNTAX);
+ r = wordexp("'", &we, WRDE_UNDEF);
+ ATF_REQUIRE(r == WRDE_SYNTAX);
+ r = wordexp("'\\'", &we, 0);
+ ATF_REQUIRE(r == 0);
+ ATF_REQUIRE(we.we_wordc == 1);
+ ATF_REQUIRE(strcmp(we.we_wordv[0], "\\") == 0);
+ ATF_REQUIRE(we.we_wordv[1] == NULL);
+ wordfree(&we);
+ /* Two syntax errors that are not detected by the current we_check(). */
+ r = wordexp("${IFS:+'}", &we, 0);
+ ATF_REQUIRE(r == WRDE_SYNTAX);
+ r = wordexp("${IFS:+'}", &we, WRDE_UNDEF);
+ ATF_REQUIRE(r == WRDE_SYNTAX);
+ r = wordexp("$(case)", &we, 0);
+ ATF_REQUIRE(r == WRDE_SYNTAX);
+ r = wordexp("$(case)", &we, WRDE_UNDEF);
+ ATF_REQUIRE(r == WRDE_SYNTAX);
+}
+
+ATF_TC_WITHOUT_HEAD(with_SIGCHILD_handler_test);
+ATF_TC_BODY(with_SIGCHILD_handler_test, tc)
+{
+ struct sigaction sa;
+ wordexp_t we;
+ int r;
+
+ /* With a SIGCHLD handler that reaps all zombies. */
+ sa.sa_flags = 0;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_handler = chld_handler;
+ r = sigaction(SIGCHLD, &sa, NULL);
+ ATF_REQUIRE(r == 0);
+ r = wordexp("hello world", &we, 0);
+ ATF_REQUIRE(r == 0);
+ ATF_REQUIRE(we.we_wordc == 2);
+ ATF_REQUIRE(strcmp(we.we_wordv[0], "hello") == 0);
+ ATF_REQUIRE(strcmp(we.we_wordv[1], "world") == 0);
+ ATF_REQUIRE(we.we_wordv[2] == NULL);
+ wordfree(&we);
+ sa.sa_handler = SIG_DFL;
+ r = sigaction(SIGCHLD, &sa, NULL);
+ ATF_REQUIRE(r == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(with_unused_non_default_IFS_test);
+ATF_TC_BODY(with_unused_non_default_IFS_test, tc)
+{
+ wordexp_t we;
+ int r;
+
+ /*
+ * With IFS set to a non-default value (without depending on whether
+ * IFS is inherited or not).
+ */
+ r = setenv("IFS", ":", 1);
+ ATF_REQUIRE(r == 0);
+ r = wordexp("hello world", &we, 0);
+ ATF_REQUIRE(r == 0);
+ ATF_REQUIRE(we.we_wordc == 2);
+ ATF_REQUIRE(strcmp(we.we_wordv[0], "hello") == 0);
+ ATF_REQUIRE(strcmp(we.we_wordv[1], "world") == 0);
+ ATF_REQUIRE(we.we_wordv[2] == NULL);
+ wordfree(&we);
+ r = unsetenv("IFS");
+ ATF_REQUIRE(r == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(with_used_non_default_IFS_test);
+ATF_TC_BODY(with_used_non_default_IFS_test, tc)
+{
+ wordexp_t we;
+ int r;
+
+ /*
+ * With IFS set to a non-default value, and using it.
+ */
+ r = setenv("IFS", ":", 1);
+ ATF_REQUIRE(r == 0);
+ r = wordexp("${IFS+hello:world}", &we, 0);
+ ATF_REQUIRE(r == 0);
+ ATF_REQUIRE(we.we_wordc == 2);
+ ATF_REQUIRE(strcmp(we.we_wordv[0], "hello") == 0);
+ ATF_REQUIRE(strcmp(we.we_wordv[1], "world") == 0);
+ ATF_REQUIRE(we.we_wordv[2] == NULL);
+ wordfree(&we);
+ r = unsetenv("IFS");
+ ATF_REQUIRE(r == 0);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+ ATF_TP_ADD_TC(tp, simple_test);
+ ATF_TP_ADD_TC(tp, long_output_test);
+ ATF_TP_ADD_TC(tp, WRDE_DOOFFS_test);
+ ATF_TP_ADD_TC(tp, WRDE_REUSE_test);
+ ATF_TP_ADD_TC(tp, WRDE_APPEND_test);
+ ATF_TP_ADD_TC(tp, WRDE_DOOFFS__WRDE_APPEND_test);
+ ATF_TP_ADD_TC(tp, WRDE_UNDEF_test);
+ ATF_TP_ADD_TC(tp, WRDE_NOCMD_test);
+ ATF_TP_ADD_TC(tp, WRDE_BADCHAR_test);
+ ATF_TP_ADD_TC(tp, WRDE_SYNTAX_test);
+ ATF_TP_ADD_TC(tp, with_SIGCHILD_handler_test);
+ ATF_TP_ADD_TC(tp, with_unused_non_default_IFS_test);
+ ATF_TP_ADD_TC(tp, with_used_non_default_IFS_test);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/hash/Makefile b/lib/libc/tests/hash/Makefile
new file mode 100644
index 000000000000..1e2cd29dbddf
--- /dev/null
+++ b/lib/libc/tests/hash/Makefile
@@ -0,0 +1,40 @@
+# $FreeBSD$
+
+PACKAGE= tests
+
+.include <src.opts.mk>
+
+NETBSD_ATF_TESTS_C=
+
+.if ${MK_OPENSSL} != "no"
+# XXX: doesn't compile
+#NETBSD_ATF_TESTS_C+= hmac_test
+NETBSD_ATF_TESTS_C+= sha2_test
+.endif
+
+NETBSD_ATF_TESTS_SH= hash_test
+
+BINDIR= ${TESTSDIR}
+
+PROGS+= h_hash
+
+FILESGROUPS+= ${PACKAGE}DATA_FILES
+${PACKAGE}DATA_FILESPACKAGE= tests
+
+${PACKAGE}DATA_FILESDIR= ${TESTSDIR}/data
+
+${PACKAGE}DATA_FILES+= data/md5test-in
+${PACKAGE}DATA_FILES+= data/md5test-out
+${PACKAGE}DATA_FILES+= data/sha1test-in
+${PACKAGE}DATA_FILES+= data/sha1test-out
+${PACKAGE}DATA_FILES+= data/sha1test2-out
+
+LIBADD+= md
+LIBADD.sha2_test+= crypto
+
+CFLAGS.sha2_test+= -I${SRCTOP}/crypto/openssh/openbsd-compat
+CFLAGS.sha2_test+= -I${SRCTOP}/crypto/openssh
+
+.include "../Makefile.netbsd-tests"
+
+.include <bsd.test.mk>
diff --git a/lib/libc/tests/hash/Makefile.depend b/lib/libc/tests/hash/Makefile.depend
new file mode 100644
index 000000000000..b1a491e414cc
--- /dev/null
+++ b/lib/libc/tests/hash/Makefile.depend
@@ -0,0 +1,22 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ gnu/lib/csu \
+ gnu/lib/libgcc \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/atf/libatf-c \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libmd \
+ lib/libnetbsd \
+ secure/lib/libcrypto \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/lib/libc/tests/iconv/Makefile b/lib/libc/tests/iconv/Makefile
new file mode 100644
index 000000000000..635c26c7cfb7
--- /dev/null
+++ b/lib/libc/tests/iconv/Makefile
@@ -0,0 +1,7 @@
+# $FreeBSD$
+
+TESTSDIR= ${TESTSBASE}/lib/libc/iconv
+
+ATF_TESTS_C+= iconvctl_test
+
+.include <bsd.test.mk>
diff --git a/lib/libc/tests/iconv/iconvctl_test.c b/lib/libc/tests/iconv/iconvctl_test.c
new file mode 100644
index 000000000000..04bf24b8481d
--- /dev/null
+++ b/lib/libc/tests/iconv/iconvctl_test.c
@@ -0,0 +1,69 @@
+/*-
+ * Copyright (c) 2016 Eric van Gyzen
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 <iconv.h>
+
+#include <atf-c.h>
+
+void
+test_trivialp(const char *src, const char *dst, int expected)
+{
+ iconv_t ic;
+ int actual, status;
+
+ ic = iconv_open(dst, src);
+ ATF_REQUIRE(ic != (iconv_t)-1);
+
+ status = iconvctl(ic, ICONV_TRIVIALP, &actual);
+ ATF_REQUIRE(status == 0);
+
+ ATF_REQUIRE(actual == expected);
+
+ status = iconv_close(ic);
+ ATF_REQUIRE(status == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(iconvctl_trivialp_test);
+ATF_TC_BODY(iconvctl_trivialp_test, tc)
+{
+
+ test_trivialp("ISO-8859-1", "ISO-8859-1", 1);
+ test_trivialp("ISO-8859-1", "ISO-8859-15", 0);
+ test_trivialp("ISO-8859-15", "ISO-8859-1", 0);
+ test_trivialp("ISO-8859-15", "UTF-8", 0);
+ test_trivialp("UTF-8", "ASCII", 0);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, iconvctl_trivialp_test);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/inet/Makefile b/lib/libc/tests/inet/Makefile
new file mode 100644
index 000000000000..fa4499c9d11b
--- /dev/null
+++ b/lib/libc/tests/inet/Makefile
@@ -0,0 +1,10 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+NETBSD_ATF_TESTS_C+= inet_addr_test
+NETBSD_ATF_TESTS_C+= inet_network_test
+
+.include "../Makefile.netbsd-tests"
+
+.include <bsd.test.mk>
diff --git a/lib/libc/tests/inet/Makefile.depend b/lib/libc/tests/inet/Makefile.depend
new file mode 100644
index 000000000000..08e76dc00e2a
--- /dev/null
+++ b/lib/libc/tests/inet/Makefile.depend
@@ -0,0 +1,21 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ gnu/lib/csu \
+ gnu/lib/libgcc \
+ include \
+ include/arpa \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/atf/libatf-c \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libnetbsd \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/lib/libc/tests/locale/Makefile b/lib/libc/tests/locale/Makefile
new file mode 100644
index 000000000000..e05cbae3ac9f
--- /dev/null
+++ b/lib/libc/tests/locale/Makefile
@@ -0,0 +1,44 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+ATF_TESTS_C+= btowc_test
+ATF_TESTS_C+= c16rtomb_test
+ATF_TESTS_C+= iswctype_test
+ATF_TESTS_C+= mblen_test
+ATF_TESTS_C+= mbrlen_test
+ATF_TESTS_C+= mbrtoc16_test
+ATF_TESTS_C+= mbrtowc_2_test
+ATF_TESTS_C+= mbsnrtowcs_2_test
+ATF_TESTS_C+= mbsrtowcs_test
+ATF_TESTS_C+= mbstowcs_2_test
+ATF_TESTS_C+= mbtowc_2_test
+ATF_TESTS_C+= towctrans_test
+ATF_TESTS_C+= wcrtomb_test
+ATF_TESTS_C+= wcsnrtombs_test
+ATF_TESTS_C+= wcsrtombs_test
+ATF_TESTS_C+= wcstombs_test
+ATF_TESTS_C+= wctomb_2_test
+
+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
+
+SRCS.mbrtowc_2_test= mbrtowc_test.c
+SRCS.mbsnrtowcs_2_test= mbsnrtowcs_test.c
+SRCS.mbstowcs_2_test= mbstowcs_test.c
+SRCS.mbtowc_2_test= mbtowc_test.c
+SRCS.wctomb_2_test= wctomb_test.c
+
+CFLAGS.t_wctomb.c+= -Wno-stack-protector
+
+.include "../Makefile.netbsd-tests"
+
+.include <bsd.test.mk>
diff --git a/lib/libc/tests/locale/Makefile.depend b/lib/libc/tests/locale/Makefile.depend
new file mode 100644
index 000000000000..68a9dd09c55e
--- /dev/null
+++ b/lib/libc/tests/locale/Makefile.depend
@@ -0,0 +1,21 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ gnu/lib/csu \
+ gnu/lib/libgcc \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/atf/libatf-c \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libnetbsd \
+ lib/msun \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/lib/libc/tests/locale/btowc_test.c b/lib/libc/tests/locale/btowc_test.c
new file mode 100644
index 000000000000..01a1133e89d5
--- /dev/null
+++ b/lib/libc/tests/locale/btowc_test.c
@@ -0,0 +1,71 @@
+/*-
+ * Copyright (c) 2002 Tim J. Robbins
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Test program for btowc() and wctob() as specified by IEEE Std. 1003.1-2001
+ * and ISO/IEC 9899:1999.
+ *
+ * The function is tested in the "C" and "ja_JP.eucJP" locales.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <limits.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+
+#include <atf-c.h>
+
+ATF_TC_WITHOUT_HEAD(btowc_test);
+ATF_TC_BODY(btowc_test, tc)
+{
+ int i;
+
+ /* C/POSIX locale. */
+ ATF_REQUIRE(btowc(EOF) == WEOF);
+ ATF_REQUIRE(wctob(WEOF) == EOF);
+ for (i = 0; i < UCHAR_MAX; i++)
+ ATF_REQUIRE(btowc(i) == (wchar_t)i && i == (int)wctob(i));
+
+ /* Japanese (EUC) locale. */
+ ATF_REQUIRE(strcmp(setlocale(LC_CTYPE, "ja_JP.eucJP"), "ja_JP.eucJP") == 0);
+ ATF_REQUIRE(MB_CUR_MAX > 1);
+ ATF_REQUIRE(btowc('A') == L'A' && wctob(L'A') == 'A');
+ ATF_REQUIRE(btowc(0xa3) == WEOF && wctob(0xa3c1) == EOF);
+
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, btowc_test);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/locale/c16rtomb_test.c b/lib/libc/tests/locale/c16rtomb_test.c
new file mode 100644
index 000000000000..ea1f64f7d308
--- /dev/null
+++ b/lib/libc/tests/locale/c16rtomb_test.c
@@ -0,0 +1,166 @@
+/*-
+ * Copyright (c) 2002 Tim J. Robbins
+ * All rights reserved.
+ *
+ * Copyright (c) 2013 Ed Schouten <ed@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * Test program for c16rtomb() as specified by ISO/IEC 9899:2011.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <limits.h>
+#include <locale.h>
+#include <stdio.h>
+#include <string.h>
+#include <uchar.h>
+
+#include <atf-c.h>
+
+static void
+require_lc_ctype(const char *locale_name)
+{
+ char *lc_ctype_set;
+
+ lc_ctype_set = setlocale(LC_CTYPE, locale_name);
+ if (lc_ctype_set == NULL)
+ atf_tc_fail("setlocale(LC_CTYPE, \"%s\") failed; errno=%d",
+ locale_name, errno);
+
+ ATF_REQUIRE(strcmp(lc_ctype_set, locale_name) == 0);
+}
+
+static mbstate_t s;
+static char buf[MB_LEN_MAX + 1];
+
+ATF_TC_WITHOUT_HEAD(c16rtomb_c_locale_test);
+ATF_TC_BODY(c16rtomb_c_locale_test, tc)
+{
+
+ require_lc_ctype("C");
+
+ /*
+ * If the buffer argument is NULL, c16 is implicitly 0,
+ * c16rtomb() resets its internal state.
+ */
+ ATF_REQUIRE(c16rtomb(NULL, L'\0', NULL) == 1);
+ ATF_REQUIRE(c16rtomb(NULL, 0xdc00, NULL) == 1);
+
+ /* Null wide character. */
+ memset(&s, 0, sizeof(s));
+ memset(buf, 0xcc, sizeof(buf));
+ ATF_REQUIRE(c16rtomb(buf, 0, &s) == 1);
+ ATF_REQUIRE((unsigned char)buf[0] == 0 && (unsigned char)buf[1] == 0xcc);
+
+ /* Latin letter A, internal state. */
+ ATF_REQUIRE(c16rtomb(NULL, L'\0', NULL) == 1);
+ ATF_REQUIRE(c16rtomb(NULL, L'A', NULL) == 1);
+
+ /* Latin letter A. */
+ memset(&s, 0, sizeof(s));
+ memset(buf, 0xcc, sizeof(buf));
+ ATF_REQUIRE(c16rtomb(buf, L'A', &s) == 1);
+ ATF_REQUIRE((unsigned char)buf[0] == 'A' && (unsigned char)buf[1] == 0xcc);
+
+ /* Unicode character 'Pile of poo'. */
+ memset(&s, 0, sizeof(s));
+ memset(buf, 0xcc, sizeof(buf));
+ ATF_REQUIRE(c16rtomb(buf, 0xd83d, &s) == 0);
+ ATF_REQUIRE(c16rtomb(buf, 0xdca9, &s) == (size_t)-1);
+ ATF_REQUIRE(errno == EILSEQ);
+ ATF_REQUIRE((unsigned char)buf[0] == 0xcc);
+}
+
+ATF_TC_WITHOUT_HEAD(c16rtomb_iso_8859_1_test);
+ATF_TC_BODY(c16rtomb_iso_8859_1_test, tc)
+{
+
+ require_lc_ctype("en_US.ISO8859-1");
+
+ /* Unicode character 'Euro sign'. */
+ memset(&s, 0, sizeof(s));
+ memset(buf, 0xcc, sizeof(buf));
+ ATF_REQUIRE(c16rtomb(buf, 0x20ac, &s) == (size_t)-1);
+ ATF_REQUIRE(errno == EILSEQ);
+ ATF_REQUIRE((unsigned char)buf[0] == 0xcc);
+}
+
+ATF_TC_WITHOUT_HEAD(c16rtomb_iso_8859_15_test);
+ATF_TC_BODY(c16rtomb_iso_8859_15_test, tc)
+{
+
+ require_lc_ctype("en_US.ISO8859-15");
+
+ /* Unicode character 'Euro sign'. */
+ memset(&s, 0, sizeof(s));
+ memset(buf, 0xcc, sizeof(buf));
+ ATF_REQUIRE(c16rtomb(buf, 0x20ac, &s) == 1);
+ ATF_REQUIRE((unsigned char)buf[0] == 0xa4 && (unsigned char)buf[1] == 0xcc);
+}
+
+ATF_TC_WITHOUT_HEAD(c16rtomb_utf_8_test);
+ATF_TC_BODY(c16rtomb_utf_8_test, tc)
+{
+
+ require_lc_ctype("en_US.UTF-8");
+
+ /* Unicode character 'Pile of poo'. */
+ memset(&s, 0, sizeof(s));
+ memset(buf, 0xcc, sizeof(buf));
+ ATF_REQUIRE(c16rtomb(buf, 0xd83d, &s) == 0);
+ ATF_REQUIRE(c16rtomb(buf, 0xdca9, &s) == 4);
+ ATF_REQUIRE((unsigned char)buf[0] == 0xf0 && (unsigned char)buf[1] == 0x9f &&
+ (unsigned char)buf[2] == 0x92 && (unsigned char)buf[3] == 0xa9 &&
+ (unsigned char)buf[4] == 0xcc);
+
+ /* Invalid code; 'Pile of poo' without the trail surrogate. */
+ memset(&s, 0, sizeof(s));
+ memset(buf, 0xcc, sizeof(buf));
+ ATF_REQUIRE(c16rtomb(buf, 0xd83d, &s) == 0);
+ ATF_REQUIRE(c16rtomb(buf, L'A', &s) == (size_t)-1);
+ ATF_REQUIRE(errno == EILSEQ);
+ ATF_REQUIRE((unsigned char)buf[0] == 0xcc);
+
+ /* Invalid code; 'Pile of poo' without the lead surrogate. */
+ memset(&s, 0, sizeof(s));
+ memset(buf, 0xcc, sizeof(buf));
+ ATF_REQUIRE(c16rtomb(buf, 0xdca9, &s) == (size_t)-1);
+ ATF_REQUIRE(errno == EILSEQ);
+ ATF_REQUIRE((unsigned char)buf[0] == 0xcc);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, c16rtomb_c_locale_test);
+ ATF_TP_ADD_TC(tp, c16rtomb_iso_8859_1_test);
+ ATF_TP_ADD_TC(tp, c16rtomb_iso_8859_15_test);
+ ATF_TP_ADD_TC(tp, c16rtomb_utf_8_test);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/locale/iswctype_test.c b/lib/libc/tests/locale/iswctype_test.c
new file mode 100644
index 000000000000..14e57b4e29a3
--- /dev/null
+++ b/lib/libc/tests/locale/iswctype_test.c
@@ -0,0 +1,122 @@
+/*-
+ * Copyright (c) 2003 Tim J. Robbins
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Test program for wctype() and iswctype() as specified by
+ * IEEE Std. 1003.1-2001 and ISO/IEC 9899:1999.
+ *
+ * The functions are tested in the "C" and "ja_JP.eucJP" locales.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <errno.h>
+#include <locale.h>
+#include <stdio.h>
+#include <string.h>
+#include <wchar.h>
+#include <wctype.h>
+
+#include <atf-c.h>
+
+static void
+require_lc_ctype(const char *locale_name)
+{
+ char *lc_ctype_set;
+
+ lc_ctype_set = setlocale(LC_CTYPE, locale_name);
+ if (lc_ctype_set == NULL)
+ atf_tc_fail("setlocale(LC_CTYPE, \"%s\") failed; errno=%d",
+ locale_name, errno);
+
+ ATF_REQUIRE(strcmp(lc_ctype_set, locale_name) == 0);
+}
+
+static wctype_t t;
+static int i, j;
+static struct {
+ const char *name;
+ int (*func)(wint_t);
+} cls[] = {
+ { "alnum", iswalnum },
+ { "alpha", iswalpha },
+ { "blank", iswblank },
+ { "cntrl", iswcntrl },
+ { "digit", iswdigit },
+ { "graph", iswgraph },
+ { "lower", iswlower },
+ { "print", iswprint },
+ { "punct", iswpunct },
+ { "space", iswspace },
+ { "upper", iswupper },
+ { "xdigit", iswxdigit }
+};
+
+ATF_TC_WITHOUT_HEAD(iswctype_c_locale_test);
+ATF_TC_BODY(iswctype_c_locale_test, tc)
+{
+
+ require_lc_ctype("C");
+ for (i = 0; i < nitems(cls); i++) {
+ t = wctype(cls[i].name);
+ ATF_REQUIRE(t != 0);
+ for (j = 0; j < 256; j++)
+ ATF_REQUIRE(cls[i].func(j) == iswctype(j, t));
+ }
+ t = wctype("elephant");
+ ATF_REQUIRE(t == 0);
+ for (i = 0; i < 256; i++)
+ ATF_REQUIRE(iswctype(i, t) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(iswctype_euc_jp_test);
+ATF_TC_BODY(iswctype_euc_jp_test, tc)
+{
+
+ require_lc_ctype("ja_JP.eucJP");
+
+ for (i = 0; i < nitems(cls); i++) {
+ t = wctype(cls[i].name);
+ ATF_REQUIRE(t != 0);
+ for (j = 0; j < 65536; j++)
+ ATF_REQUIRE(cls[i].func(j) == iswctype(j, t));
+ }
+ t = wctype("elephant");
+ ATF_REQUIRE(t == 0);
+ for (i = 0; i < 65536; i++)
+ ATF_REQUIRE(iswctype(i, t) == 0);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, iswctype_c_locale_test);
+ ATF_TP_ADD_TC(tp, iswctype_euc_jp_test);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/locale/mblen_test.c b/lib/libc/tests/locale/mblen_test.c
new file mode 100644
index 000000000000..fbb938d3e5a6
--- /dev/null
+++ b/lib/libc/tests/locale/mblen_test.c
@@ -0,0 +1,116 @@
+/*-
+ * Copyright (c) 2002-2004 Tim J. Robbins
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Test program for mblen(), as specified by IEEE Std. 1003.1-2001 and
+ * ISO/IEC 9899:1990.
+ *
+ * The function is tested with both the "C" ("POSIX") LC_CTYPE setting and
+ * "ja_JP.eucJP". Other encodings are not tested.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <limits.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <atf-c.h>
+
+ATF_TC_WITHOUT_HEAD(mblen_test);
+ATF_TC_BODY(mblen_test, tc)
+{
+ char buf[MB_LEN_MAX + 1];
+
+ /*
+ * C/POSIX locale.
+ */
+
+ ATF_REQUIRE(MB_CUR_MAX == 1);
+
+ /* No shift states in C locale. */
+ ATF_REQUIRE(mblen(NULL, 0) == 0);
+
+ /* Null wide character. */
+ memset(buf, 0xcc, sizeof(buf));
+ buf[0] = '\0';
+ ATF_REQUIRE(mblen(buf, 1) == 0);
+
+ /* Latin letter A. */
+ buf[0] = 'A';
+ ATF_REQUIRE(mblen(buf, 1) == 1);
+
+ /* Incomplete character sequence. */
+ buf[0] = '\0';
+ ATF_REQUIRE(mblen(buf, 0) == -1);
+ ATF_REQUIRE(mblen(NULL, 0) == 0);
+
+ /*
+ * Japanese (EUC) locale.
+ */
+
+ ATF_REQUIRE(strcmp(setlocale(LC_CTYPE, "ja_JP.eucJP"), "ja_JP.eucJP") == 0);
+ ATF_REQUIRE(MB_CUR_MAX > 1);
+
+ /* No shift states in EUC. */
+ ATF_REQUIRE(mblen(NULL, 0) == 0);
+
+ /* Null wide character. */
+ memset(buf, 0xcc, sizeof(buf));
+ buf[0] = '\0';
+ ATF_REQUIRE(mblen(buf, 1) == 0);
+
+ /* Latin letter A. */
+ buf[0] = 'A';
+ ATF_REQUIRE(mblen(buf, 1) == 1);
+
+ /* Incomplete character sequence. */
+ buf[0] = '\0';
+ ATF_REQUIRE(mblen(buf, 0) == -1);
+ ATF_REQUIRE(mblen(NULL, 0) == 0);
+
+ /* Incomplete character sequence (truncated double-byte). */
+ memset(buf, 0xcc, sizeof(buf));
+ buf[0] = 0xa3;
+ buf[1] = 0x00;
+ ATF_REQUIRE(mblen(buf, 1) == -1);
+ ATF_REQUIRE(mblen(NULL, 0) == 0);
+
+ /* Same as above, but complete. */
+ buf[1] = 0xc1;
+ ATF_REQUIRE(mblen(buf, 2) == 2);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, mblen_test);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/locale/mbrlen_test.c b/lib/libc/tests/locale/mbrlen_test.c
new file mode 100644
index 000000000000..c2bc54832156
--- /dev/null
+++ b/lib/libc/tests/locale/mbrlen_test.c
@@ -0,0 +1,126 @@
+/*-
+ * Copyright (c) 2002 Tim J. Robbins
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Test program for mbrlen(), as specified by IEEE Std. 1003.1-2001 and
+ * ISO/IEC 9899:1999.
+ *
+ * The function is tested with both the "C" ("POSIX") LC_CTYPE setting and
+ * "ja_JP.eucJP". Other encodings are not tested.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <limits.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+
+#include <atf-c.h>
+
+ATF_TC_WITHOUT_HEAD(mbrlen_test);
+ATF_TC_BODY(mbrlen_test, tc)
+{
+ mbstate_t s;
+ char buf[MB_LEN_MAX + 1];
+
+ /* C/POSIX locale. */
+ ATF_REQUIRE(MB_CUR_MAX == 1);
+
+ /* Null wide character, internal state. */
+ memset(buf, 0xcc, sizeof(buf));
+ buf[0] = 0;
+ ATF_REQUIRE(mbrlen(buf, 1, NULL) == 0);
+
+ /* Null wide character. */
+ memset(&s, 0, sizeof(s));
+ ATF_REQUIRE(mbrlen(buf, 1, &s) == 0);
+
+ /* Latin letter A, internal state. */
+ ATF_REQUIRE(mbrlen(NULL, 0, NULL) == 0);
+ buf[0] = 'A';
+ ATF_REQUIRE(mbrlen(buf, 1, NULL) == 1);
+
+ /* Latin letter A. */
+ memset(&s, 0, sizeof(s));
+ ATF_REQUIRE(mbrlen(buf, 1, &s) == 1);
+
+ /* Incomplete character sequence. */
+ memset(&s, 0, sizeof(s));
+ ATF_REQUIRE(mbrlen(buf, 0, &s) == (size_t)-2);
+
+ /* Japanese (EUC) locale. */
+
+ ATF_REQUIRE(strcmp(setlocale(LC_CTYPE, "ja_JP.eucJP"), "ja_JP.eucJP") == 0);
+ ATF_REQUIRE(MB_CUR_MAX > 1);
+
+ /* Null wide character, internal state. */
+ ATF_REQUIRE(mbrlen(NULL, 0, NULL) == 0);
+ memset(buf, 0xcc, sizeof(buf));
+ buf[0] = 0;
+ ATF_REQUIRE(mbrlen(buf, 1, NULL) == 0);
+
+ /* Null wide character. */
+ memset(&s, 0, sizeof(s));
+ ATF_REQUIRE(mbrlen(buf, 1, &s) == 0);
+
+ /* Latin letter A, internal state. */
+ ATF_REQUIRE(mbrlen(NULL, 0, NULL) == 0);
+ buf[0] = 'A';
+ ATF_REQUIRE(mbrlen(buf, 1, NULL) == 1);
+
+ /* Latin letter A. */
+ memset(&s, 0, sizeof(s));
+ ATF_REQUIRE(mbrlen(buf, 1, &s) == 1);
+
+ /* Incomplete character sequence (zero length). */
+ memset(&s, 0, sizeof(s));
+ ATF_REQUIRE(mbrlen(buf, 0, &s) == (size_t)-2);
+
+ /* Incomplete character sequence (truncated double-byte). */
+ memset(buf, 0xcc, sizeof(buf));
+ buf[0] = 0xa3;
+ buf[1] = 0x00;
+ memset(&s, 0, sizeof(s));
+ ATF_REQUIRE(mbrlen(buf, 1, &s) == (size_t)-2);
+
+ /* Same as above, but complete. */
+ buf[1] = 0xc1;
+ memset(&s, 0, sizeof(s));
+ ATF_REQUIRE(mbrlen(buf, 2, &s) == 2);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, mbrlen_test);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/locale/mbrtoc16_test.c b/lib/libc/tests/locale/mbrtoc16_test.c
new file mode 100644
index 000000000000..a6289e1004ca
--- /dev/null
+++ b/lib/libc/tests/locale/mbrtoc16_test.c
@@ -0,0 +1,214 @@
+/*-
+ * Copyright (c) 2002 Tim J. Robbins
+ * All rights reserved.
+ *
+ * Copyright (c) 2013 Ed Schouten <ed@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * Test program for mbrtoc16() as specified by ISO/IEC 9899:2011.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <limits.h>
+#include <locale.h>
+#include <stdio.h>
+#include <string.h>
+#include <uchar.h>
+
+#include <atf-c.h>
+
+static void
+require_lc_ctype(const char *locale_name)
+{
+ char *lc_ctype_set;
+
+ lc_ctype_set = setlocale(LC_CTYPE, locale_name);
+ if (lc_ctype_set == NULL)
+ atf_tc_fail("setlocale(LC_CTYPE, \"%s\") failed; errno=%d",
+ locale_name, errno);
+
+ ATF_REQUIRE(strcmp(lc_ctype_set, locale_name) == 0);
+}
+
+static mbstate_t s;
+static char16_t c16;
+
+ATF_TC_WITHOUT_HEAD(mbrtoc16_c_locale_test);
+ATF_TC_BODY(mbrtoc16_c_locale_test, tc)
+{
+
+ require_lc_ctype("C");
+
+ /* Null wide character, internal state. */
+ ATF_REQUIRE(mbrtoc16(&c16, "", 1, NULL) == 0);
+ ATF_REQUIRE(c16 == 0);
+
+ /* Null wide character. */
+ memset(&s, 0, sizeof(s));
+ ATF_REQUIRE(mbrtoc16(&c16, "", 1, &s) == 0);
+ ATF_REQUIRE(c16 == 0);
+
+ /* Latin letter A, internal state. */
+ ATF_REQUIRE(mbrtoc16(NULL, 0, 0, NULL) == 0);
+ ATF_REQUIRE(mbrtoc16(&c16, "A", 1, NULL) == 1);
+ ATF_REQUIRE(c16 == L'A');
+
+ /* Latin letter A. */
+ memset(&s, 0, sizeof(s));
+ ATF_REQUIRE(mbrtoc16(&c16, "A", 1, &s) == 1);
+ ATF_REQUIRE(c16 == L'A');
+
+ /* Incomplete character sequence. */
+ c16 = L'z';
+ memset(&s, 0, sizeof(s));
+ ATF_REQUIRE(mbrtoc16(&c16, "", 0, &s) == (size_t)-2);
+ ATF_REQUIRE(c16 == L'z');
+
+ /* Check that mbrtoc16() doesn't access the buffer when n == 0. */
+ c16 = L'z';
+ memset(&s, 0, sizeof(s));
+ ATF_REQUIRE(mbrtoc16(&c16, "", 0, &s) == (size_t)-2);
+ ATF_REQUIRE(c16 == L'z');
+
+ /* Check that mbrtoc16() doesn't read ahead too aggressively. */
+ memset(&s, 0, sizeof(s));
+ ATF_REQUIRE(mbrtoc16(&c16, "AB", 2, &s) == 1);
+ ATF_REQUIRE(c16 == L'A');
+ ATF_REQUIRE(mbrtoc16(&c16, "C", 1, &s) == 1);
+ ATF_REQUIRE(c16 == L'C');
+
+}
+
+ATF_TC_WITHOUT_HEAD(mbrtoc16_iso_8859_1_test);
+ATF_TC_BODY(mbrtoc16_iso_8859_1_test, tc)
+{
+
+ require_lc_ctype("en_US.ISO8859-1");
+
+ /* Currency sign. */
+ memset(&s, 0, sizeof(s));
+ ATF_REQUIRE(mbrtoc16(&c16, "\xa4", 1, &s) == 1);
+ ATF_REQUIRE(c16 == 0xa4);
+}
+
+ATF_TC_WITHOUT_HEAD(mbrtoc16_iso_8859_15_test);
+ATF_TC_BODY(mbrtoc16_iso_8859_15_test, tc)
+{
+
+ require_lc_ctype("en_US.ISO8859-15");
+
+ /* Euro sign. */
+ memset(&s, 0, sizeof(s));
+ ATF_REQUIRE(mbrtoc16(&c16, "\xa4", 1, &s) == 1);
+ ATF_REQUIRE(c16 == 0x20ac);
+}
+
+ATF_TC_WITHOUT_HEAD(mbrtoc16_utf_8_test);
+ATF_TC_BODY(mbrtoc16_utf_8_test, tc)
+{
+
+ require_lc_ctype("en_US.UTF-8");
+
+ /* Null wide character, internal state. */
+ ATF_REQUIRE(mbrtoc16(NULL, 0, 0, NULL) == 0);
+ ATF_REQUIRE(mbrtoc16(&c16, "", 1, NULL) == 0);
+ ATF_REQUIRE(c16 == 0);
+
+ /* Null wide character. */
+ memset(&s, 0, sizeof(s));
+ ATF_REQUIRE(mbrtoc16(&c16, "", 1, &s) == 0);
+ ATF_REQUIRE(c16 == 0);
+
+ /* Latin letter A, internal state. */
+ ATF_REQUIRE(mbrtoc16(NULL, 0, 0, NULL) == 0);
+ ATF_REQUIRE(mbrtoc16(&c16, "A", 1, NULL) == 1);
+ ATF_REQUIRE(c16 == L'A');
+
+ /* Latin letter A. */
+ memset(&s, 0, sizeof(s));
+ ATF_REQUIRE(mbrtoc16(&c16, "A", 1, &s) == 1);
+ ATF_REQUIRE(c16 == L'A');
+
+ /* Incomplete character sequence (zero length). */
+ c16 = L'z';
+ memset(&s, 0, sizeof(s));
+ ATF_REQUIRE(mbrtoc16(&c16, "", 0, &s) == (size_t)-2);
+ ATF_REQUIRE(c16 == L'z');
+
+ /* Incomplete character sequence (truncated double-byte). */
+ memset(&s, 0, sizeof(s));
+ c16 = 0;
+ ATF_REQUIRE(mbrtoc16(&c16, "\xc3", 1, &s) == (size_t)-2);
+
+ /* Same as above, but complete. */
+ memset(&s, 0, sizeof(s));
+ c16 = 0;
+ ATF_REQUIRE(mbrtoc16(&c16, "\xc3\x84", 2, &s) == 2);
+ ATF_REQUIRE(c16 == 0xc4);
+
+ /* Test restarting behaviour. */
+ memset(&s, 0, sizeof(s));
+ c16 = 0;
+ ATF_REQUIRE(mbrtoc16(&c16, "\xc3", 1, &s) == (size_t)-2);
+ ATF_REQUIRE(c16 == 0);
+ ATF_REQUIRE(mbrtoc16(&c16, "\xb7", 1, &s) == 1);
+ ATF_REQUIRE(c16 == 0xf7);
+
+ /* Surrogate pair. */
+ memset(&s, 0, sizeof(s));
+ c16 = 0;
+ ATF_REQUIRE(mbrtoc16(&c16, "\xf0\x9f\x92\xa9", 4, &s) == 4);
+ ATF_REQUIRE(c16 == 0xd83d);
+ ATF_REQUIRE(mbrtoc16(&c16, "", 0, &s) == (size_t)-3);
+ ATF_REQUIRE(c16 == 0xdca9);
+
+ /* Letter e with acute, precomposed. */
+ memset(&s, 0, sizeof(s));
+ c16 = 0;
+ ATF_REQUIRE(mbrtoc16(&c16, "\xc3\xa9", 2, &s) == 2);
+ ATF_REQUIRE(c16 == 0xe9);
+
+ /* Letter e with acute, combined. */
+ memset(&s, 0, sizeof(s));
+ c16 = 0;
+ ATF_REQUIRE(mbrtoc16(&c16, "\x65\xcc\x81", 3, &s) == 1);
+ ATF_REQUIRE(c16 == 0x65);
+ ATF_REQUIRE(mbrtoc16(&c16, "\xcc\x81", 2, &s) == 2);
+ ATF_REQUIRE(c16 == 0x301);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, mbrtoc16_c_locale_test);
+ ATF_TP_ADD_TC(tp, mbrtoc16_iso_8859_1_test);
+ ATF_TP_ADD_TC(tp, mbrtoc16_iso_8859_15_test);
+ ATF_TP_ADD_TC(tp, mbrtoc16_utf_8_test);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/locale/mbrtowc_test.c b/lib/libc/tests/locale/mbrtowc_test.c
new file mode 100644
index 000000000000..37e0bfd6fbaa
--- /dev/null
+++ b/lib/libc/tests/locale/mbrtowc_test.c
@@ -0,0 +1,165 @@
+/*-
+ * Copyright (c) 2002 Tim J. Robbins
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Test program for mbrtowc(), as specified by IEEE Std. 1003.1-2001 and
+ * ISO/IEC 9899:1999.
+ *
+ * The function is tested with both the "C" ("POSIX") LC_CTYPE setting and
+ * "ja_JP.eucJP". Other encodings are not tested.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <limits.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+
+#include <atf-c.h>
+
+ATF_TC_WITHOUT_HEAD(mbrtowc_test);
+ATF_TC_BODY(mbrtowc_test, tc)
+{
+ mbstate_t s;
+ wchar_t wc;
+ char buf[MB_LEN_MAX + 1];
+
+ /*
+ * C/POSIX locale.
+ */
+
+ ATF_REQUIRE(MB_CUR_MAX == 1);
+
+ /* Null wide character, internal state. */
+ memset(buf, 0xcc, sizeof(buf));
+ buf[0] = 0;
+ ATF_REQUIRE(mbrtowc(&wc, buf, 1, NULL) == 0);
+ ATF_REQUIRE(wc == 0);
+
+ /* Null wide character. */
+ memset(&s, 0, sizeof(s));
+ ATF_REQUIRE(mbrtowc(&wc, buf, 1, &s) == 0);
+ ATF_REQUIRE(wc == 0);
+
+ /* Latin letter A, internal state. */
+ ATF_REQUIRE(mbrtowc(NULL, 0, 0, NULL) == 0);
+ buf[0] = 'A';
+ ATF_REQUIRE(mbrtowc(&wc, buf, 1, NULL) == 1);
+ ATF_REQUIRE(wc == L'A');
+
+ /* Latin letter A. */
+ memset(&s, 0, sizeof(s));
+ ATF_REQUIRE(mbrtowc(&wc, buf, 1, &s) == 1);
+ ATF_REQUIRE(wc == L'A');
+
+ /* Incomplete character sequence. */
+ wc = L'z';
+ memset(&s, 0, sizeof(s));
+ ATF_REQUIRE(mbrtowc(&wc, buf, 0, &s) == (size_t)-2);
+ ATF_REQUIRE(wc == L'z');
+
+ /* Check that mbrtowc() doesn't access the buffer when n == 0. */
+ wc = L'z';
+ memset(&s, 0, sizeof(s));
+ buf[0] = '\0';
+ ATF_REQUIRE(mbrtowc(&wc, buf, 0, &s) == (size_t)-2);
+ ATF_REQUIRE(wc == L'z');
+
+ /*
+ * Japanese (EUC) locale.
+ */
+
+ ATF_REQUIRE(strcmp(setlocale(LC_CTYPE, "ja_JP.eucJP"), "ja_JP.eucJP") == 0);
+ ATF_REQUIRE(MB_CUR_MAX > 1);
+
+ /* Null wide character, internal state. */
+ ATF_REQUIRE(mbrtowc(NULL, 0, 0, NULL) == 0);
+ memset(buf, 0xcc, sizeof(buf));
+ buf[0] = 0;
+ ATF_REQUIRE(mbrtowc(&wc, buf, 1, NULL) == 0);
+ ATF_REQUIRE(wc == 0);
+
+ /* Null wide character. */
+ memset(&s, 0, sizeof(s));
+ ATF_REQUIRE(mbrtowc(&wc, buf, 1, &s) == 0);
+ ATF_REQUIRE(wc == 0);
+
+ /* Latin letter A, internal state. */
+ ATF_REQUIRE(mbrtowc(NULL, 0, 0, NULL) == 0);
+ buf[0] = 'A';
+ ATF_REQUIRE(mbrtowc(&wc, buf, 1, NULL) == 1);
+ ATF_REQUIRE(wc == L'A');
+
+ /* Latin letter A. */
+ memset(&s, 0, sizeof(s));
+ ATF_REQUIRE(mbrtowc(&wc, buf, 1, &s) == 1);
+ ATF_REQUIRE(wc == L'A');
+
+ /* Incomplete character sequence (zero length). */
+ wc = L'z';
+ memset(&s, 0, sizeof(s));
+ ATF_REQUIRE(mbrtowc(&wc, buf, 0, &s) == (size_t)-2);
+ ATF_REQUIRE(wc == L'z');
+
+ /* Incomplete character sequence (truncated double-byte). */
+ memset(buf, 0xcc, sizeof(buf));
+ buf[0] = 0xa3;
+ buf[1] = 0x00;
+ memset(&s, 0, sizeof(s));
+ wc = 0;
+ ATF_REQUIRE(mbrtowc(&wc, buf, 1, &s) == (size_t)-2);
+
+ /* Same as above, but complete. */
+ buf[1] = 0xc1;
+ memset(&s, 0, sizeof(s));
+ wc = 0;
+ ATF_REQUIRE(mbrtowc(&wc, buf, 2, &s) == 2);
+ ATF_REQUIRE(wc == 0xa3c1);
+
+ /* Test restarting behaviour. */
+ memset(buf, 0xcc, sizeof(buf));
+ buf[0] = 0xa3;
+ memset(&s, 0, sizeof(s));
+ wc = 0;
+ ATF_REQUIRE(mbrtowc(&wc, buf, 1, &s) == (size_t)-2);
+ ATF_REQUIRE(wc == 0);
+ buf[0] = 0xc1;
+ ATF_REQUIRE(mbrtowc(&wc, buf, 1, &s) == 1);
+ ATF_REQUIRE(wc == 0xa3c1);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, mbrtowc_test);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/locale/mbsnrtowcs_test.c b/lib/libc/tests/locale/mbsnrtowcs_test.c
new file mode 100644
index 000000000000..4012b7e99720
--- /dev/null
+++ b/lib/libc/tests/locale/mbsnrtowcs_test.c
@@ -0,0 +1,195 @@
+/*-
+ * Copyright (c) 2002-2004 Tim J. Robbins
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Test program for mbsnrtowcs().
+ *
+ * The function is tested with both the "C" ("POSIX") LC_CTYPE setting and
+ * "ja_JP.eucJP". Other encodings are not tested.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <limits.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+
+#include <atf-c.h>
+
+ATF_TC_WITHOUT_HEAD(mbsnrtowcs_test);
+ATF_TC_BODY(mbsnrtowcs_test, tc)
+{
+ char srcbuf[128];
+ wchar_t dstbuf[128];
+ char *src;
+ mbstate_t s;
+
+ /* C/POSIX locale. */
+
+ /* Simple null terminated string. */
+ memset(srcbuf, 0xcc, sizeof(srcbuf));
+ strcpy(srcbuf, "hello");
+ wmemset(dstbuf, 0xcccc, sizeof(dstbuf) / sizeof(*dstbuf));
+ src = srcbuf;
+ memset(&s, 0, sizeof(s));
+ ATF_REQUIRE(mbsnrtowcs(dstbuf, (const char **)&src, 6, sizeof(dstbuf) /
+ sizeof(*dstbuf), &s) == 5);
+ ATF_REQUIRE(wcscmp(dstbuf, L"hello") == 0);
+ ATF_REQUIRE(dstbuf[6] == 0xcccc);
+ ATF_REQUIRE(src == NULL);
+
+ /* Simple null terminated string, stopping early. */
+ memset(srcbuf, 0xcc, sizeof(srcbuf));
+ strcpy(srcbuf, "hello");
+ wmemset(dstbuf, 0xcccc, sizeof(dstbuf) / sizeof(*dstbuf));
+ src = srcbuf;
+ memset(&s, 0, sizeof(s));
+ ATF_REQUIRE(mbsnrtowcs(dstbuf, (const char **)&src, 4, sizeof(dstbuf) /
+ sizeof(*dstbuf), &s) == 4);
+ ATF_REQUIRE(wmemcmp(dstbuf, L"hell", 4) == 0);
+ ATF_REQUIRE(dstbuf[5] == 0xcccc);
+ ATF_REQUIRE(src == srcbuf + 4);
+
+ /* Not enough space in destination buffer. */
+ memset(srcbuf, 0xcc, sizeof(srcbuf));
+ strcpy(srcbuf, "hello");
+ wmemset(dstbuf, 0xcccc, sizeof(dstbuf) / sizeof(*dstbuf));
+ src = srcbuf;
+ memset(&s, 0, sizeof(s));
+ ATF_REQUIRE(mbsnrtowcs(dstbuf, (const char **)&src, 6, 4, &s) == 4);
+ ATF_REQUIRE(wmemcmp(dstbuf, L"hell", 4) == 0);
+ ATF_REQUIRE(dstbuf[5] == 0xcccc);
+ ATF_REQUIRE(src == srcbuf + 4);
+
+ /* Null terminated string, internal dest. buffer */
+ memset(srcbuf, 0xcc, sizeof(srcbuf));
+ strcpy(srcbuf, "hello");
+ src = srcbuf;
+ memset(&s, 0, sizeof(s));
+ ATF_REQUIRE(mbsnrtowcs(NULL, (const char **)&src, 6, 0, &s) == 5);
+
+ /* Null terminated string, internal dest. buffer, stopping early */
+ memset(srcbuf, 0xcc, sizeof(srcbuf));
+ strcpy(srcbuf, "hello");
+ src = srcbuf;
+ memset(&s, 0, sizeof(s));
+ ATF_REQUIRE(mbsnrtowcs(NULL, (const char **)&src, 4, 0, &s) == 4);
+
+ /* Null terminated string, internal state. */
+ memset(srcbuf, 0xcc, sizeof(srcbuf));
+ strcpy(srcbuf, "hello");
+ wmemset(dstbuf, 0xcccc, sizeof(dstbuf) / sizeof(*dstbuf));
+ src = srcbuf;
+ ATF_REQUIRE(mbsnrtowcs(dstbuf, (const char **)&src, 6, sizeof(dstbuf) /
+ sizeof(*dstbuf), NULL) == 5);
+ ATF_REQUIRE(wcscmp(dstbuf, L"hello") == 0);
+ ATF_REQUIRE(dstbuf[6] == 0xcccc);
+ ATF_REQUIRE(src == NULL);
+
+ /* Null terminated string, internal state, internal dest. buffer. */
+ memset(srcbuf, 0xcc, sizeof(srcbuf));
+ strcpy(srcbuf, "hello");
+ src = srcbuf;
+ ATF_REQUIRE(mbsnrtowcs(NULL, (const char **)&src, 6, 0, NULL) == 5);
+
+ /* Empty source buffer. */
+ memset(srcbuf, 0xcc, sizeof(srcbuf));
+ srcbuf[0] = '\0';
+ src = srcbuf;
+ memset(&s, 0, sizeof(s));
+ wmemset(dstbuf, 0xcccc, sizeof(dstbuf) / sizeof(*dstbuf));
+ ATF_REQUIRE(mbsnrtowcs(dstbuf, (const char **)&src, 1, 1, &s) == 0);
+ ATF_REQUIRE(dstbuf[0] == 0);
+ ATF_REQUIRE(dstbuf[1] == 0xcccc);
+ ATF_REQUIRE(src == NULL);
+
+ /* Zero length destination buffer. */
+ memset(srcbuf, 0xcc, sizeof(srcbuf));
+ strcpy(srcbuf, "hello");
+ src = srcbuf;
+ memset(&s, 0, sizeof(s));
+ wmemset(dstbuf, 0xcccc, sizeof(dstbuf) / sizeof(*dstbuf));
+ ATF_REQUIRE(mbsnrtowcs(dstbuf, (const char **)&src, 1, 0, &s) == 0);
+ ATF_REQUIRE(dstbuf[0] == 0xcccc);
+ ATF_REQUIRE(src == srcbuf);
+
+ /* Zero length source buffer. */
+ memset(srcbuf, 0xcc, sizeof(srcbuf));
+ src = srcbuf;
+ memset(&s, 0, sizeof(s));
+ wmemset(dstbuf, 0xcccc, sizeof(dstbuf) / sizeof(*dstbuf));
+ ATF_REQUIRE(mbsnrtowcs(dstbuf, (const char **)&src, 0, 1, &s) == 0);
+ ATF_REQUIRE(dstbuf[0] == 0xcccc);
+ ATF_REQUIRE(src == srcbuf);
+
+ /*
+ * Japanese (EUC) locale.
+ */
+
+ ATF_REQUIRE(strcmp(setlocale(LC_CTYPE, "ja_JP.eucJP"), "ja_JP.eucJP") == 0);
+ ATF_REQUIRE(MB_CUR_MAX > 1);
+
+ memset(srcbuf, 0xcc, sizeof(srcbuf));
+ strcpy(srcbuf, "\xA3\xC1 B \xA3\xC3");
+ src = srcbuf;
+ memset(&s, 0, sizeof(s));
+ wmemset(dstbuf, 0xcccc, sizeof(dstbuf) / sizeof(*dstbuf));
+ ATF_REQUIRE(mbsnrtowcs(dstbuf, (const char **)&src, 8, sizeof(dstbuf) /
+ sizeof(*dstbuf), &s) == 5);
+ ATF_REQUIRE(dstbuf[0] == 0xA3C1 && dstbuf[1] == 0x20 && dstbuf[2] == 0x42 &&
+ dstbuf[3] == 0x20 && dstbuf[4] == 0xA3C3 && dstbuf[5] == 0);
+ ATF_REQUIRE(src == NULL);
+
+ /* Partial character. */
+ memset(srcbuf, 0xcc, sizeof(srcbuf));
+ strcpy(srcbuf, "\xA3\xC1 B \xA3\xC3");
+ src = srcbuf;
+ memset(&s, 0, sizeof(s));
+ wmemset(dstbuf, 0xcccc, sizeof(dstbuf) / sizeof(*dstbuf));
+ ATF_REQUIRE(mbsnrtowcs(dstbuf, (const char **)&src, 6, sizeof(dstbuf) /
+ sizeof(*dstbuf), &s) == 4);
+ ATF_REQUIRE(src == srcbuf + 6);
+ ATF_REQUIRE(!mbsinit(&s));
+ ATF_REQUIRE(mbsnrtowcs(dstbuf, (const char **)&src, 1, sizeof(dstbuf) /
+ sizeof(*dstbuf), &s) == 1);
+ ATF_REQUIRE(src == srcbuf + 7);
+ ATF_REQUIRE(mbsnrtowcs(dstbuf, (const char **)&src, 1, sizeof(dstbuf) /
+ sizeof(*dstbuf), &s) == 0);
+ ATF_REQUIRE(src == NULL);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, mbsnrtowcs_test);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/locale/mbsrtowcs_test.c b/lib/libc/tests/locale/mbsrtowcs_test.c
new file mode 100644
index 000000000000..1b9d5c933af1
--- /dev/null
+++ b/lib/libc/tests/locale/mbsrtowcs_test.c
@@ -0,0 +1,153 @@
+/*-
+ * Copyright (c) 2002 Tim J. Robbins
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Test program for mbsrtowcs(), as specified by IEEE Std. 1003.1-2001 and
+ * ISO/IEC 9899:1999.
+ *
+ * The function is tested with both the "C" ("POSIX") LC_CTYPE setting and
+ * "ja_JP.eucJP". Other encodings are not tested.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <limits.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+
+#include <atf-c.h>
+
+ATF_TC_WITHOUT_HEAD(mbsrtowcs_test);
+ATF_TC_BODY(mbsrtowcs_test, tc)
+{
+ char srcbuf[128];
+ wchar_t dstbuf[128];
+ char *src;
+ mbstate_t s;
+
+ /*
+ * C/POSIX locale.
+ */
+
+ /* Simple null terminated string. */
+ memset(srcbuf, 0xcc, sizeof(srcbuf));
+ strcpy(srcbuf, "hello");
+ wmemset(dstbuf, 0xcccc, sizeof(dstbuf) / sizeof(*dstbuf));
+ src = srcbuf;
+ memset(&s, 0, sizeof(s));
+ ATF_REQUIRE(mbsrtowcs(dstbuf, (const char **)&src, sizeof(dstbuf) /
+ sizeof(*dstbuf), &s) == 5);
+ ATF_REQUIRE(wcscmp(dstbuf, L"hello") == 0);
+ ATF_REQUIRE(dstbuf[6] == 0xcccc);
+ ATF_REQUIRE(src == NULL);
+
+ /* Not enough space in destination buffer. */
+ memset(srcbuf, 0xcc, sizeof(srcbuf));
+ strcpy(srcbuf, "hello");
+ wmemset(dstbuf, 0xcccc, sizeof(dstbuf) / sizeof(*dstbuf));
+ src = srcbuf;
+ memset(&s, 0, sizeof(s));
+ ATF_REQUIRE(mbsrtowcs(dstbuf, (const char **)&src, 4, &s) == 4);
+ ATF_REQUIRE(wmemcmp(dstbuf, L"hell", 4) == 0);
+ ATF_REQUIRE(dstbuf[5] == 0xcccc);
+ ATF_REQUIRE(src == srcbuf + 4);
+
+ /* Null terminated string, internal dest. buffer */
+ memset(srcbuf, 0xcc, sizeof(srcbuf));
+ strcpy(srcbuf, "hello");
+ src = srcbuf;
+ memset(&s, 0, sizeof(s));
+ ATF_REQUIRE(mbsrtowcs(NULL, (const char **)&src, 0, &s) == 5);
+
+ /* Null terminated string, internal state. */
+ memset(srcbuf, 0xcc, sizeof(srcbuf));
+ strcpy(srcbuf, "hello");
+ wmemset(dstbuf, 0xcccc, sizeof(dstbuf) / sizeof(*dstbuf));
+ src = srcbuf;
+ ATF_REQUIRE(mbsrtowcs(dstbuf, (const char **)&src, sizeof(dstbuf) /
+ sizeof(*dstbuf), NULL) == 5);
+ ATF_REQUIRE(wcscmp(dstbuf, L"hello") == 0);
+ ATF_REQUIRE(dstbuf[6] == 0xcccc);
+ ATF_REQUIRE(src == NULL);
+
+ /* Null terminated string, internal state, internal dest. buffer. */
+ memset(srcbuf, 0xcc, sizeof(srcbuf));
+ strcpy(srcbuf, "hello");
+ src = srcbuf;
+ ATF_REQUIRE(mbsrtowcs(NULL, (const char **)&src, 0, NULL) == 5);
+
+ /* Empty source buffer. */
+ memset(srcbuf, 0xcc, sizeof(srcbuf));
+ srcbuf[0] = '\0';
+ src = srcbuf;
+ memset(&s, 0, sizeof(s));
+ wmemset(dstbuf, 0xcccc, sizeof(dstbuf) / sizeof(*dstbuf));
+ ATF_REQUIRE(mbsrtowcs(dstbuf, (const char **)&src, 1, &s) == 0);
+ ATF_REQUIRE(dstbuf[0] == 0);
+ ATF_REQUIRE(dstbuf[1] == 0xcccc);
+ ATF_REQUIRE(src == NULL);
+
+ /* Zero length destination buffer. */
+ memset(srcbuf, 0xcc, sizeof(srcbuf));
+ strcpy(srcbuf, "hello");
+ src = srcbuf;
+ memset(&s, 0, sizeof(s));
+ wmemset(dstbuf, 0xcccc, sizeof(dstbuf) / sizeof(*dstbuf));
+ ATF_REQUIRE(mbsrtowcs(dstbuf, (const char **)&src, 0, &s) == 0);
+ ATF_REQUIRE(dstbuf[0] == 0xcccc);
+ ATF_REQUIRE(src == srcbuf);
+
+ /*
+ * Japanese (EUC) locale.
+ */
+
+ ATF_REQUIRE(strcmp(setlocale(LC_CTYPE, "ja_JP.eucJP"), "ja_JP.eucJP") == 0);
+ ATF_REQUIRE(MB_CUR_MAX > 1);
+
+ memset(srcbuf, 0xcc, sizeof(srcbuf));
+ strcpy(srcbuf, "\xA3\xC1 B \xA3\xC3");
+ src = srcbuf;
+ memset(&s, 0, sizeof(s));
+ wmemset(dstbuf, 0xcccc, sizeof(dstbuf) / sizeof(*dstbuf));
+ ATF_REQUIRE(mbsrtowcs(dstbuf, (const char **)&src, sizeof(dstbuf) /
+ sizeof(*dstbuf), &s) == 5);
+ ATF_REQUIRE(dstbuf[0] == 0xA3C1 && dstbuf[1] == 0x20 && dstbuf[2] == 0x42 &&
+ dstbuf[3] == 0x20 && dstbuf[4] == 0xA3C3 && dstbuf[5] == 0);
+ ATF_REQUIRE(src == NULL);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, mbsrtowcs_test);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/locale/mbstowcs_test.c b/lib/libc/tests/locale/mbstowcs_test.c
new file mode 100644
index 000000000000..77b0e9e52f35
--- /dev/null
+++ b/lib/libc/tests/locale/mbstowcs_test.c
@@ -0,0 +1,111 @@
+/*-
+ * Copyright (c) 2002 Tim J. Robbins
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Test program for mbstowcs(), as specified by IEEE Std. 1003.1-2001 and
+ * ISO/IEC 9899:1999.
+ *
+ * The function is tested with both the "C" ("POSIX") LC_CTYPE setting and
+ * "ja_JP.eucJP". Other encodings are not tested.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <limits.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+
+#include <atf-c.h>
+
+ATF_TC_WITHOUT_HEAD(mbstowcs_test);
+ATF_TC_BODY(mbstowcs_test, tc)
+{
+ char srcbuf[128];
+ wchar_t dstbuf[128];
+
+ /* C/POSIX locale. */
+
+ /* Simple null terminated string. */
+ memset(srcbuf, 0xcc, sizeof(srcbuf));
+ strcpy(srcbuf, "hello");
+ wmemset(dstbuf, 0xcccc, sizeof(dstbuf) / sizeof(*dstbuf));
+ ATF_REQUIRE(mbstowcs(dstbuf, srcbuf, sizeof(dstbuf) / sizeof(*dstbuf)) == 5);
+ ATF_REQUIRE(wcscmp(dstbuf, L"hello") == 0);
+ ATF_REQUIRE(dstbuf[6] == 0xcccc);
+
+ /* Not enough space in destination buffer. */
+ memset(srcbuf, 0xcc, sizeof(srcbuf));
+ strcpy(srcbuf, "hello");
+ wmemset(dstbuf, 0xcccc, sizeof(dstbuf) / sizeof(*dstbuf));
+ ATF_REQUIRE(mbstowcs(dstbuf, srcbuf, 4) == 4);
+ ATF_REQUIRE(wmemcmp(dstbuf, L"hell", 4) == 0);
+ ATF_REQUIRE(dstbuf[5] == 0xcccc);
+
+ /* Null terminated string, internal dest. buffer (XSI extension) */
+ memset(srcbuf, 0xcc, sizeof(srcbuf));
+ strcpy(srcbuf, "hello");
+ ATF_REQUIRE(mbstowcs(NULL, srcbuf, 0) == 5);
+
+ /* Empty source buffer. */
+ memset(srcbuf, 0xcc, sizeof(srcbuf));
+ srcbuf[0] = '\0';
+ wmemset(dstbuf, 0xcccc, sizeof(dstbuf) / sizeof(*dstbuf));
+ ATF_REQUIRE(mbstowcs(dstbuf, srcbuf, 1) == 0);
+ ATF_REQUIRE(dstbuf[0] == 0);
+ ATF_REQUIRE(dstbuf[1] == 0xcccc);
+
+ /* Zero length destination buffer. */
+ memset(srcbuf, 0xcc, sizeof(srcbuf));
+ strcpy(srcbuf, "hello");
+ wmemset(dstbuf, 0xcccc, sizeof(dstbuf) / sizeof(*dstbuf));
+ ATF_REQUIRE(mbstowcs(dstbuf, srcbuf, 0) == 0);
+ ATF_REQUIRE(dstbuf[0] == 0xcccc);
+
+ /* Japanese (EUC) locale. */
+
+ ATF_REQUIRE(strcmp(setlocale(LC_CTYPE, "ja_JP.eucJP"), "ja_JP.eucJP") == 0);
+ ATF_REQUIRE(MB_CUR_MAX > 1);
+
+ memset(srcbuf, 0xcc, sizeof(srcbuf));
+ strcpy(srcbuf, "\xA3\xC1 B \xA3\xC3");
+ wmemset(dstbuf, 0xcccc, sizeof(dstbuf) / sizeof(*dstbuf));
+ ATF_REQUIRE(mbstowcs(dstbuf, srcbuf, sizeof(dstbuf) / sizeof(*dstbuf)) == 5);
+ ATF_REQUIRE(dstbuf[0] == 0xA3C1 && dstbuf[1] == 0x20 && dstbuf[2] == 0x42 &&
+ dstbuf[3] == 0x20 && dstbuf[4] == 0xA3C3 && dstbuf[5] == 0);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, mbstowcs_test);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/locale/mbtowc_test.c b/lib/libc/tests/locale/mbtowc_test.c
new file mode 100644
index 000000000000..7c7f80eb5cc4
--- /dev/null
+++ b/lib/libc/tests/locale/mbtowc_test.c
@@ -0,0 +1,122 @@
+/*-
+ * Copyright (c) 2002-2004 Tim J. Robbins
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Test program for mbtowc(), as specified by IEEE Std. 1003.1-2001 and
+ * ISO/IEC 9899:1990.
+ *
+ * The function is tested with both the "C" ("POSIX") LC_CTYPE setting and
+ * "ja_JP.eucJP". Other encodings are not tested.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <limits.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <atf-c.h>
+
+ATF_TC_WITHOUT_HEAD(mbtowc_test);
+ATF_TC_BODY(mbtowc_test, tc)
+{
+ char buf[MB_LEN_MAX + 1];
+ wchar_t wc;
+
+ /* C/POSIX locale. */
+
+ ATF_REQUIRE(MB_CUR_MAX == 1);
+
+ /* No shift states in C locale. */
+ ATF_REQUIRE(mbtowc(NULL, NULL, 0) == 0);
+
+ /* Null wide character. */
+ wc = 0xcccc;
+ memset(buf, 0, sizeof(buf));
+ ATF_REQUIRE(mbtowc(&wc, buf, 1) == 0);
+ ATF_REQUIRE(wc == 0);
+
+ /* Latin letter A. */
+ buf[0] = 'A';
+ ATF_REQUIRE(mbtowc(&wc, buf, 1) == 1);
+ ATF_REQUIRE(wc == L'A');
+
+ /* Incomplete character sequence. */
+ wc = L'z';
+ buf[0] = '\0';
+ ATF_REQUIRE(mbtowc(&wc, buf, 0) == -1);
+ ATF_REQUIRE(wc == L'z');
+ ATF_REQUIRE(mbtowc(NULL, NULL, 0) == 0);
+
+ /* Japanese (EUC) locale. */
+
+ ATF_REQUIRE(strcmp(setlocale(LC_CTYPE, "ja_JP.eucJP"), "ja_JP.eucJP") == 0);
+ ATF_REQUIRE(MB_CUR_MAX > 1);
+
+ /* Null wide character */
+ memset(buf, 0xcc, sizeof(buf));
+ buf[0] = 0;
+ wc = 0xcccc;
+ ATF_REQUIRE(mbtowc(&wc, buf, 1) == 0);
+ ATF_REQUIRE(wc == 0);
+
+ /* Latin letter A. */
+ buf[0] = 'A';
+ ATF_REQUIRE(mbtowc(&wc, buf, 1) == 1);
+ ATF_REQUIRE(wc == L'A');
+
+ /* Incomplete character sequence (zero length). */
+ wc = L'z';
+ buf[0] = '\0';
+ ATF_REQUIRE(mbtowc(&wc, buf, 0) == -1);
+ ATF_REQUIRE(wc == L'z');
+ ATF_REQUIRE(mbtowc(NULL, NULL, 0) == 0);
+
+ /* Incomplete character sequence (truncated double-byte). */
+ memset(buf, 0xcc, sizeof(buf));
+ buf[0] = 0xa3;
+ buf[1] = 0x00;
+ wc = L'z';
+ ATF_REQUIRE(mbtowc(&wc, buf, 1) == -1);
+ ATF_REQUIRE(wc == L'z');
+ ATF_REQUIRE(mbtowc(NULL, NULL, 0) == 0);
+
+ /* Same as above, but complete. */
+ buf[1] = 0xc1;
+ ATF_REQUIRE(mbtowc(&wc, buf, 2) == 2);
+ ATF_REQUIRE(wc == 0xa3c1);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, mbtowc_test);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/locale/towctrans_test.c b/lib/libc/tests/locale/towctrans_test.c
new file mode 100644
index 000000000000..bb9d97ca2e54
--- /dev/null
+++ b/lib/libc/tests/locale/towctrans_test.c
@@ -0,0 +1,90 @@
+/*-
+ * Copyright (c) 2003 Tim J. Robbins
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Test program for wctrans() and towctrans() as specified by
+ * IEEE Std. 1003.1-2001 and ISO/IEC 9899:1999.
+ *
+ * The functions are tested in the "C" and "ja_JP.eucJP" locales.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <locale.h>
+#include <stdio.h>
+#include <string.h>
+#include <wchar.h>
+#include <wctype.h>
+
+#include <atf-c.h>
+
+ATF_TC_WITHOUT_HEAD(towctrans_test);
+ATF_TC_BODY(towctrans_test, tc)
+{
+ wctype_t t;
+ int i, j;
+ struct {
+ const char *name;
+ wint_t (*func)(wint_t);
+ } tran[] = {
+ { "tolower", towlower },
+ { "toupper", towupper },
+ };
+
+ /* C/POSIX locale. */
+ for (i = 0; i < sizeof(tran) / sizeof(*tran); i++) {
+ t = wctrans(tran[i].name);
+ ATF_REQUIRE(t != 0);
+ for (j = 0; j < 256; j++)
+ ATF_REQUIRE(tran[i].func(j) == towctrans(j, t));
+ }
+ t = wctrans("elephant");
+ ATF_REQUIRE(t == 0);
+ for (i = 0; i < 256; i++)
+ ATF_REQUIRE(towctrans(i, t) == i);
+
+ /* Japanese (EUC) locale. */
+ ATF_REQUIRE(strcmp(setlocale(LC_CTYPE, "ja_JP.eucJP"), "ja_JP.eucJP") == 0);
+ for (i = 0; i < sizeof(tran) / sizeof(*tran); i++) {
+ t = wctrans(tran[i].name);
+ ATF_REQUIRE(t != 0);
+ for (j = 0; j < 65536; j++)
+ ATF_REQUIRE(tran[i].func(j) == towctrans(j, t));
+ }
+ t = wctrans("elephant");
+ ATF_REQUIRE(t == 0);
+ for (i = 0; i < 65536; i++)
+ ATF_REQUIRE(towctrans(i, t) == i);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, towctrans_test);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/locale/wcrtomb_test.c b/lib/libc/tests/locale/wcrtomb_test.c
new file mode 100644
index 000000000000..09199ba97c99
--- /dev/null
+++ b/lib/libc/tests/locale/wcrtomb_test.c
@@ -0,0 +1,135 @@
+/*-
+ * Copyright (c) 2002 Tim J. Robbins
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Test program for wcrtomb(), as specified by IEEE Std. 1003.1-2001 and
+ * ISO/IEC 9899:1999.
+ *
+ * The function is tested with both the "C" ("POSIX") LC_CTYPE setting and
+ * "ja_JP.eucJP". Other encodings are not tested.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <limits.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+
+#include <atf-c.h>
+
+ATF_TC_WITHOUT_HEAD(wcrtomb_test);
+ATF_TC_BODY(wcrtomb_test, tc)
+{
+ mbstate_t s;
+ size_t len;
+ char buf[MB_LEN_MAX + 1];
+
+ /* C/POSIX locale. */
+
+ ATF_REQUIRE(MB_CUR_MAX == 1);
+
+ /*
+ * If the buffer argument is NULL, wc is implicitly L'\0',
+ * wcrtomb() resets its internal state.
+ */
+ ATF_REQUIRE(wcrtomb(NULL, L'\0', NULL) == 1);
+ ATF_REQUIRE(wcrtomb(NULL, UCHAR_MAX + 1, NULL) == 1);
+
+ /* Null wide character. */
+ memset(&s, 0, sizeof(s));
+ memset(buf, 0xcc, sizeof(buf));
+ len = wcrtomb(buf, L'\0', &s);
+ ATF_REQUIRE(len == 1);
+ ATF_REQUIRE((unsigned char)buf[0] == 0 && (unsigned char)buf[1] == 0xcc);
+
+ /* Latin letter A, internal state. */
+ ATF_REQUIRE(wcrtomb(NULL, L'\0', NULL) == 1);
+ ATF_REQUIRE(wcrtomb(NULL, L'A', NULL) == 1);
+
+ /* Latin letter A. */
+ memset(&s, 0, sizeof(s));
+ memset(buf, 0xcc, sizeof(buf));
+ len = wcrtomb(buf, L'A', &s);
+ ATF_REQUIRE(len == 1);
+ ATF_REQUIRE((unsigned char)buf[0] == 'A' && (unsigned char)buf[1] == 0xcc);
+
+ /* Invalid code. */
+ ATF_REQUIRE(wcrtomb(buf, UCHAR_MAX + 1, NULL) == (size_t)-1);
+ ATF_REQUIRE(errno == EILSEQ);
+
+ /*
+ * Japanese (EUC) locale.
+ */
+
+ ATF_REQUIRE(strcmp(setlocale(LC_CTYPE, "ja_JP.eucJP"), "ja_JP.eucJP") == 0);
+ ATF_REQUIRE(MB_CUR_MAX == 3);
+
+ /*
+ * If the buffer argument is NULL, wc is implicitly L'\0',
+ * wcrtomb() resets its internal state.
+ */
+ ATF_REQUIRE(wcrtomb(NULL, L'\0', NULL) == 1);
+
+ /* Null wide character. */
+ memset(&s, 0, sizeof(s));
+ memset(buf, 0xcc, sizeof(buf));
+ len = wcrtomb(buf, L'\0', &s);
+ ATF_REQUIRE(len == 1);
+ ATF_REQUIRE((unsigned char)buf[0] == 0 && (unsigned char)buf[1] == 0xcc);
+
+ /* Latin letter A, internal state. */
+ ATF_REQUIRE(wcrtomb(NULL, L'\0', NULL) == 1);
+ ATF_REQUIRE(wcrtomb(NULL, L'A', NULL) == 1);
+
+ /* Latin letter A. */
+ memset(&s, 0, sizeof(s));
+ memset(buf, 0xcc, sizeof(buf));
+ len = wcrtomb(buf, L'A', &s);
+ ATF_REQUIRE(len == 1);
+ ATF_REQUIRE((unsigned char)buf[0] == 'A' && (unsigned char)buf[1] == 0xcc);
+
+ /* Full width letter A. */
+ memset(&s, 0, sizeof(s));
+ memset(buf, 0xcc, sizeof(buf));
+ len = wcrtomb(buf, 0xa3c1, &s);
+ ATF_REQUIRE(len == 2);
+ ATF_REQUIRE((unsigned char)buf[0] == 0xa3 &&
+ (unsigned char)buf[1] == 0xc1 &&
+ (unsigned char)buf[2] == 0xcc);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, wcrtomb_test);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/locale/wcsnrtombs_test.c b/lib/libc/tests/locale/wcsnrtombs_test.c
new file mode 100644
index 000000000000..2e330a10ad83
--- /dev/null
+++ b/lib/libc/tests/locale/wcsnrtombs_test.c
@@ -0,0 +1,195 @@
+/*-
+ * Copyright (c) 2002-2004 Tim J. Robbins
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Test program for wcsnrtombs().
+ *
+ * The function is tested with both the "C" ("POSIX") LC_CTYPE setting and
+ * "ja_JP.eucJP". Other encodings are not tested.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <limits.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+
+#include <atf-c.h>
+
+ATF_TC_WITHOUT_HEAD(wcsnrtombs_test);
+ATF_TC_BODY(wcsnrtombs_test, tc)
+{
+ wchar_t srcbuf[128];
+ char dstbuf[128];
+ wchar_t *src;
+ mbstate_t s;
+
+ /* C/POSIX locale. */
+
+ /* Simple null terminated string. */
+ wmemset(srcbuf, 0xcc, sizeof(srcbuf) / sizeof(*srcbuf));
+ wcscpy(srcbuf, L"hello");
+ memset(dstbuf, 0xcc, sizeof(dstbuf));
+ src = srcbuf;
+ memset(&s, 0, sizeof(s));
+ ATF_REQUIRE(wcsnrtombs(dstbuf, (const wchar_t **)&src, 6, sizeof(dstbuf),
+ &s) == 5);
+ ATF_REQUIRE(strcmp(dstbuf, "hello") == 0);
+ ATF_REQUIRE((unsigned char)dstbuf[6] == 0xcc);
+ ATF_REQUIRE(src == NULL);
+
+ /* Simple null terminated string, stopping early. */
+ wmemset(srcbuf, 0xcc, sizeof(srcbuf) / sizeof(*srcbuf));
+ wcscpy(srcbuf, L"hello");
+ memset(dstbuf, 0xcc, sizeof(dstbuf));
+ src = srcbuf;
+ memset(&s, 0, sizeof(s));
+ ATF_REQUIRE(wcsnrtombs(dstbuf, (const wchar_t **)&src, 4, sizeof(dstbuf),
+ &s) == 4);
+ ATF_REQUIRE(memcmp(dstbuf, "hell", 4) == 0);
+ ATF_REQUIRE((unsigned char)dstbuf[5] == 0xcc);
+ ATF_REQUIRE(src == srcbuf + 4);
+
+ /* Not enough space in destination buffer. */
+ wmemset(srcbuf, 0xcc, sizeof(srcbuf) / sizeof(*srcbuf));
+ wcscpy(srcbuf, L"hello");
+ memset(dstbuf, 0xcc, sizeof(dstbuf));
+ src = srcbuf;
+ memset(&s, 0, sizeof(s));
+ ATF_REQUIRE(wcsnrtombs(dstbuf, (const wchar_t **)&src, 6, 4,
+ &s) == 4);
+ ATF_REQUIRE(memcmp(dstbuf, "hell", 4) == 0);
+ ATF_REQUIRE((unsigned char)dstbuf[5] == 0xcc);
+ ATF_REQUIRE(src == srcbuf + 4);
+
+ /* Null terminated string, internal dest. buffer */
+ wmemset(srcbuf, 0xcc, sizeof(srcbuf) / sizeof(*srcbuf));
+ wcscpy(srcbuf, L"hello");
+ src = srcbuf;
+ memset(&s, 0, sizeof(s));
+ ATF_REQUIRE(wcsnrtombs(NULL, (const wchar_t **)&src, 6, sizeof(dstbuf),
+ &s) == 5);
+
+ /* Null terminated string, internal dest. buffer, stopping early. */
+ wmemset(srcbuf, 0xcc, sizeof(srcbuf) / sizeof(*srcbuf));
+ wcscpy(srcbuf, L"hello");
+ src = srcbuf;
+ memset(&s, 0, sizeof(s));
+ ATF_REQUIRE(wcsnrtombs(NULL, (const wchar_t **)&src, 4, sizeof(dstbuf),
+ &s) == 4);
+
+ /* Null terminated string, internal state. */
+ wmemset(srcbuf, 0xcc, sizeof(srcbuf) / sizeof(*srcbuf));
+ wcscpy(srcbuf, L"hello");
+ memset(dstbuf, 0xcc, sizeof(dstbuf));
+ src = srcbuf;
+ ATF_REQUIRE(wcsnrtombs(dstbuf, (const wchar_t **)&src, 6, sizeof(dstbuf),
+ NULL) == 5);
+ ATF_REQUIRE(strcmp(dstbuf, "hello") == 0);
+ ATF_REQUIRE((unsigned char)dstbuf[6] == 0xcc);
+ ATF_REQUIRE(src == NULL);
+
+ /* Null terminated string, internal state, internal dest. buffer. */
+ wmemset(srcbuf, 0xcc, sizeof(srcbuf) / sizeof(*srcbuf));
+ wcscpy(srcbuf, L"hello");
+ src = srcbuf;
+ ATF_REQUIRE(wcsnrtombs(NULL, (const wchar_t **)&src, 6, 0, NULL) == 5);
+
+ /* Empty source buffer. */
+ wmemset(srcbuf, 0xcc, sizeof(srcbuf) / sizeof(*srcbuf));
+ srcbuf[0] = L'\0';
+ memset(dstbuf, 0xcc, sizeof(dstbuf));
+ src = srcbuf;
+ memset(&s, 0, sizeof(s));
+ ATF_REQUIRE(wcsnrtombs(dstbuf, (const wchar_t **)&src, 1, sizeof(dstbuf),
+ &s) == 0);
+ ATF_REQUIRE(dstbuf[0] == L'\0');
+
+ /* Zero length destination buffer. */
+ wmemset(srcbuf, 0xcc, sizeof(srcbuf) / sizeof(*srcbuf));
+ wcscpy(srcbuf, L"hello");
+ memset(dstbuf, 0xcc, sizeof(dstbuf));
+ src = srcbuf;
+ memset(&s, 0, sizeof(s));
+ ATF_REQUIRE(wcsnrtombs(dstbuf, (const wchar_t **)&src, 6, 0, &s) == 0);
+ ATF_REQUIRE((unsigned char)dstbuf[0] == 0xcc);
+
+ /* Zero length source buffer. */
+ wmemset(srcbuf, 0xcc, sizeof(srcbuf) / sizeof(*srcbuf));
+ memset(dstbuf, 0xcc, sizeof(dstbuf));
+ src = srcbuf;
+ memset(&s, 0, sizeof(s));
+ ATF_REQUIRE(wcsnrtombs(dstbuf, (const wchar_t **)&src, 0, sizeof(dstbuf),
+ &s) == 0);
+ ATF_REQUIRE((unsigned char)dstbuf[0] == 0xcc);
+ ATF_REQUIRE(src == srcbuf);
+
+ /*
+ * Japanese (EUC) locale.
+ */
+
+ ATF_REQUIRE(strcmp(setlocale(LC_CTYPE, "ja_JP.eucJP"), "ja_JP.eucJP") == 0);
+ ATF_REQUIRE(MB_CUR_MAX > 1);
+
+ wmemset(srcbuf, 0xcc, sizeof(srcbuf) / sizeof(*srcbuf));
+ srcbuf[0] = 0xA3C1;
+ srcbuf[1] = 0x0020;
+ srcbuf[2] = 0x0042;
+ srcbuf[3] = 0x0020;
+ srcbuf[4] = 0xA3C3;
+ srcbuf[5] = 0x0000;
+ memset(dstbuf, 0xcc, sizeof(dstbuf));
+ src = srcbuf;
+ memset(&s, 0, sizeof(s));
+ ATF_REQUIRE(wcsnrtombs(dstbuf, (const wchar_t **)&src, 6, sizeof(dstbuf),
+ &s) == 7);
+ ATF_REQUIRE(strcmp(dstbuf, "\xA3\xC1 B \xA3\xC3") == 0);
+ ATF_REQUIRE((unsigned char)dstbuf[8] == 0xcc);
+ ATF_REQUIRE(src == NULL);
+
+ /* Stopping early. */
+ memset(dstbuf, 0xcc, sizeof(dstbuf));
+ src = srcbuf;
+ memset(&s, 0, sizeof(s));
+ ATF_REQUIRE(wcsnrtombs(dstbuf, (const wchar_t **)&src, 6, 6,
+ &s) == 5);
+ ATF_REQUIRE(memcmp(dstbuf, "\xA3\xC1 B ", 5) == 0);
+ ATF_REQUIRE((unsigned char)dstbuf[5] == 0xcc);
+ ATF_REQUIRE(src == srcbuf + 4);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, wcsnrtombs_test);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/locale/wcsrtombs_test.c b/lib/libc/tests/locale/wcsrtombs_test.c
new file mode 100644
index 000000000000..4c3455a87769
--- /dev/null
+++ b/lib/libc/tests/locale/wcsrtombs_test.c
@@ -0,0 +1,156 @@
+/*-
+ * Copyright (c) 2002 Tim J. Robbins
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Test program for wcsrtombs(), as specified by IEEE Std. 1003.1-2001 and
+ * ISO/IEC 9899:1999.
+ *
+ * The function is tested with both the "C" ("POSIX") LC_CTYPE setting and
+ * "ja_JP.eucJP". Other encodings are not tested.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <limits.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+
+#include <atf-c.h>
+
+ATF_TC_WITHOUT_HEAD(wcsrtombs_test);
+ATF_TC_BODY(wcsrtombs_test, tc)
+{
+ wchar_t srcbuf[128];
+ char dstbuf[128];
+ wchar_t *src;
+ mbstate_t s;
+
+ /* C/POSIX locale. */
+
+ /* Simple null terminated string. */
+ wmemset(srcbuf, 0xcc, sizeof(srcbuf) / sizeof(*srcbuf));
+ wcscpy(srcbuf, L"hello");
+ memset(dstbuf, 0xcc, sizeof(dstbuf));
+ src = srcbuf;
+ memset(&s, 0, sizeof(s));
+ ATF_REQUIRE(wcsrtombs(dstbuf, (const wchar_t **)&src, sizeof(dstbuf),
+ &s) == 5);
+ ATF_REQUIRE(strcmp(dstbuf, "hello") == 0);
+ ATF_REQUIRE((unsigned char)dstbuf[6] == 0xcc);
+ ATF_REQUIRE(src == NULL);
+
+ /* Not enough space in destination buffer. */
+ wmemset(srcbuf, 0xcc, sizeof(srcbuf) / sizeof(*srcbuf));
+ wcscpy(srcbuf, L"hello");
+ memset(dstbuf, 0xcc, sizeof(dstbuf));
+ src = srcbuf;
+ memset(&s, 0, sizeof(s));
+ ATF_REQUIRE(wcsrtombs(dstbuf, (const wchar_t **)&src, 4,
+ &s) == 4);
+ ATF_REQUIRE(memcmp(dstbuf, "hell", 4) == 0);
+ ATF_REQUIRE((unsigned char)dstbuf[5] == 0xcc);
+ ATF_REQUIRE(src == srcbuf + 4);
+
+ /* Null terminated string, internal dest. buffer */
+ wmemset(srcbuf, 0xcc, sizeof(srcbuf) / sizeof(*srcbuf));
+ wcscpy(srcbuf, L"hello");
+ src = srcbuf;
+ memset(&s, 0, sizeof(s));
+ ATF_REQUIRE(wcsrtombs(NULL, (const wchar_t **)&src, sizeof(dstbuf),
+ &s) == 5);
+
+ /* Null terminated string, internal state. */
+ wmemset(srcbuf, 0xcc, sizeof(srcbuf) / sizeof(*srcbuf));
+ wcscpy(srcbuf, L"hello");
+ memset(dstbuf, 0xcc, sizeof(dstbuf));
+ src = srcbuf;
+ ATF_REQUIRE(wcsrtombs(dstbuf, (const wchar_t **)&src, sizeof(dstbuf),
+ NULL) == 5);
+ ATF_REQUIRE(strcmp(dstbuf, "hello") == 0);
+ ATF_REQUIRE((unsigned char)dstbuf[6] == 0xcc);
+ ATF_REQUIRE(src == NULL);
+
+ /* Null terminated string, internal state, internal dest. buffer. */
+ wmemset(srcbuf, 0xcc, sizeof(srcbuf) / sizeof(*srcbuf));
+ wcscpy(srcbuf, L"hello");
+ src = srcbuf;
+ ATF_REQUIRE(wcsrtombs(NULL, (const wchar_t **)&src, 0, NULL) == 5);
+
+ /* Empty source buffer. */
+ wmemset(srcbuf, 0xcc, sizeof(srcbuf) / sizeof(*srcbuf));
+ srcbuf[0] = L'\0';
+ memset(dstbuf, 0xcc, sizeof(dstbuf));
+ src = srcbuf;
+ memset(&s, 0, sizeof(s));
+ ATF_REQUIRE(wcsrtombs(dstbuf, (const wchar_t **)&src, sizeof(dstbuf),
+ &s) == 0);
+ ATF_REQUIRE(dstbuf[0] == L'\0');
+
+ /* Zero length destination buffer. */
+ wmemset(srcbuf, 0xcc, sizeof(srcbuf) / sizeof(*srcbuf));
+ wcscpy(srcbuf, L"hello");
+ memset(dstbuf, 0xcc, sizeof(dstbuf));
+ src = srcbuf;
+ memset(&s, 0, sizeof(s));
+ ATF_REQUIRE(wcsrtombs(dstbuf, (const wchar_t **)&src, 0, &s) == 0);
+ ATF_REQUIRE((unsigned char)dstbuf[0] == 0xcc);
+
+ /*
+ * Japanese (EUC) locale.
+ */
+
+ ATF_REQUIRE(strcmp(setlocale(LC_CTYPE, "ja_JP.eucJP"), "ja_JP.eucJP") == 0);
+ ATF_REQUIRE(MB_CUR_MAX > 1);
+
+ wmemset(srcbuf, 0xcc, sizeof(srcbuf) / sizeof(*srcbuf));
+ srcbuf[0] = 0xA3C1;
+ srcbuf[1] = 0x0020;
+ srcbuf[2] = 0x0042;
+ srcbuf[3] = 0x0020;
+ srcbuf[4] = 0xA3C3;
+ srcbuf[5] = 0x0000;
+ memset(dstbuf, 0xcc, sizeof(dstbuf));
+ src = srcbuf;
+ memset(&s, 0, sizeof(s));
+ ATF_REQUIRE(wcsrtombs(dstbuf, (const wchar_t **)&src, sizeof(dstbuf),
+ &s) == 7);
+ ATF_REQUIRE(strcmp(dstbuf, "\xA3\xC1 B \xA3\xC3") == 0);
+ ATF_REQUIRE((unsigned char)dstbuf[8] == 0xcc);
+ ATF_REQUIRE(src == NULL);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, wcsrtombs_test);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/locale/wcstombs_test.c b/lib/libc/tests/locale/wcstombs_test.c
new file mode 100644
index 000000000000..f3fcd81001f1
--- /dev/null
+++ b/lib/libc/tests/locale/wcstombs_test.c
@@ -0,0 +1,130 @@
+/*-
+ * Copyright (c) 2002 Tim J. Robbins
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Test program for wcstombs(), as specified by IEEE Std. 1003.1-2001 and
+ * ISO/IEC 9899:1999.
+ *
+ * The function is tested with both the "C" ("POSIX") LC_CTYPE setting and
+ * "ja_JP.eucJP". Other encodings are not tested.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <limits.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+
+#include <atf-c.h>
+
+ATF_TC_WITHOUT_HEAD(wcstombs_test);
+ATF_TC_BODY(wcstombs_test, tc)
+{
+ wchar_t srcbuf[128];
+ char dstbuf[128];
+
+ /* C/POSIX locale. */
+
+ /* Simple null terminated string. */
+ wmemset(srcbuf, 0xcc, sizeof(srcbuf) / sizeof(*srcbuf));
+ wcscpy(srcbuf, L"hello");
+ memset(dstbuf, 0xcc, sizeof(dstbuf));
+ ATF_REQUIRE(wcstombs(dstbuf, srcbuf, sizeof(dstbuf)) == 5);
+ ATF_REQUIRE(strcmp(dstbuf, "hello") == 0);
+ ATF_REQUIRE((unsigned char)dstbuf[6] == 0xcc);
+
+ /* Not enough space in destination buffer. */
+ wmemset(srcbuf, 0xcc, sizeof(srcbuf) / sizeof(*srcbuf));
+ wcscpy(srcbuf, L"hello");
+ memset(dstbuf, 0xcc, sizeof(dstbuf));
+ ATF_REQUIRE(wcstombs(dstbuf, srcbuf, 4) == 4);
+ ATF_REQUIRE(memcmp(dstbuf, "hell", 4) == 0);
+ ATF_REQUIRE((unsigned char)dstbuf[5] == 0xcc);
+
+ /* Null terminated string, internal dest. buffer */
+ wmemset(srcbuf, 0xcc, sizeof(srcbuf) / sizeof(*srcbuf));
+ wcscpy(srcbuf, L"hello");
+ ATF_REQUIRE(wcstombs(NULL, srcbuf, sizeof(dstbuf)) == 5);
+
+ /* Null terminated string, internal state. */
+ wmemset(srcbuf, 0xcc, sizeof(srcbuf) / sizeof(*srcbuf));
+ wcscpy(srcbuf, L"hello");
+ memset(dstbuf, 0xcc, sizeof(dstbuf));
+ ATF_REQUIRE(wcstombs(dstbuf, srcbuf, sizeof(dstbuf)) == 5);
+ ATF_REQUIRE(strcmp(dstbuf, "hello") == 0);
+ ATF_REQUIRE((unsigned char)dstbuf[6] == 0xcc);
+
+ /* Null terminated string, internal state, internal dest. buffer. */
+ wmemset(srcbuf, 0xcc, sizeof(srcbuf) / sizeof(*srcbuf));
+ wcscpy(srcbuf, L"hello");
+ ATF_REQUIRE(wcstombs(NULL, srcbuf, 0) == 5);
+
+ /* Empty source buffer. */
+ wmemset(srcbuf, 0xcc, sizeof(srcbuf) / sizeof(*srcbuf));
+ srcbuf[0] = L'\0';
+ memset(dstbuf, 0xcc, sizeof(dstbuf));
+ ATF_REQUIRE(wcstombs(dstbuf, srcbuf, sizeof(dstbuf)) == 0);
+ ATF_REQUIRE(dstbuf[0] == L'\0');
+
+ /* Zero length destination buffer. */
+ wmemset(srcbuf, 0xcc, sizeof(srcbuf) / sizeof(*srcbuf));
+ wcscpy(srcbuf, L"hello");
+ memset(dstbuf, 0xcc, sizeof(dstbuf));
+ ATF_REQUIRE(wcstombs(dstbuf, srcbuf, 0) == 0);
+ ATF_REQUIRE((unsigned char)dstbuf[0] == 0xcc);
+
+ /*
+ * Japanese (EUC) locale.
+ */
+
+ ATF_REQUIRE(strcmp(setlocale(LC_CTYPE, "ja_JP.eucJP"), "ja_JP.eucJP") == 0);
+ ATF_REQUIRE(MB_CUR_MAX > 1);
+
+ wmemset(srcbuf, 0xcc, sizeof(srcbuf) / sizeof(*srcbuf));
+ srcbuf[0] = 0xA3C1;
+ srcbuf[1] = 0x0020;
+ srcbuf[2] = 0x0042;
+ srcbuf[3] = 0x0020;
+ srcbuf[4] = 0xA3C3;
+ srcbuf[5] = 0x0000;
+ memset(dstbuf, 0xcc, sizeof(dstbuf));
+ ATF_REQUIRE(wcstombs(dstbuf, srcbuf, sizeof(dstbuf)) == 7);
+ ATF_REQUIRE(strcmp(dstbuf, "\xA3\xC1 B \xA3\xC3") == 0);
+ ATF_REQUIRE((unsigned char)dstbuf[8] == 0xcc);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, wcstombs_test);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/locale/wctomb_test.c b/lib/libc/tests/locale/wctomb_test.c
new file mode 100644
index 000000000000..255cda432d7d
--- /dev/null
+++ b/lib/libc/tests/locale/wctomb_test.c
@@ -0,0 +1,113 @@
+/*-
+ * Copyright (c) 2002-2004 Tim J. Robbins
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Test program for wctomb(), as specified by IEEE Std. 1003.1-2001 and
+ * ISO/IEC 9899:1999.
+ *
+ * The function is tested with both the "C" ("POSIX") LC_CTYPE setting and
+ * "ja_JP.eucJP". Other encodings are not tested.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <limits.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <atf-c.h>
+
+ATF_TC_WITHOUT_HEAD(wctomb_test);
+ATF_TC_BODY(wctomb_test, tc)
+{
+ size_t len;
+ char buf[MB_LEN_MAX + 1];
+
+ /* C/POSIX locale. */
+
+ ATF_REQUIRE(MB_CUR_MAX == 1);
+
+ /* No shift states in C locale. */
+ ATF_REQUIRE(wctomb(NULL, L'\0') == 0);
+
+ /* Null wide character. */
+ memset(buf, 0xcc, sizeof(buf));
+ len = wctomb(buf, L'\0');
+ ATF_REQUIRE(len == 1);
+ ATF_REQUIRE((unsigned char)buf[0] == 0 && (unsigned char)buf[1] == 0xcc);
+
+ /* Latin letter A. */
+ memset(buf, 0xcc, sizeof(buf));
+ len = wctomb(buf, L'A');
+ ATF_REQUIRE(len == 1);
+ ATF_REQUIRE((unsigned char)buf[0] == 'A' && (unsigned char)buf[1] == 0xcc);
+
+ /* Invalid code. */
+ ATF_REQUIRE(wctomb(buf, UCHAR_MAX + 1) == -1);
+ ATF_REQUIRE(wctomb(NULL, 0) == 0);
+
+ /*
+ * Japanese (EUC) locale.
+ */
+
+ ATF_REQUIRE(strcmp(setlocale(LC_CTYPE, "ja_JP.eucJP"), "ja_JP.eucJP") == 0);
+ ATF_REQUIRE(MB_CUR_MAX == 3);
+
+ /* No shift states in EUC encoding. */
+ ATF_REQUIRE(wctomb(NULL, L'\0') == 0);
+
+ /* Null wide character. */
+ memset(buf, 0xcc, sizeof(buf));
+ len = wctomb(buf, L'\0');
+ ATF_REQUIRE(len == 1);
+ ATF_REQUIRE((unsigned char)buf[0] == 0 && (unsigned char)buf[1] == 0xcc);
+
+ /* Latin letter A. */
+ memset(buf, 0xcc, sizeof(buf));
+ len = wctomb(buf, L'A');
+ ATF_REQUIRE(len == 1);
+ ATF_REQUIRE((unsigned char)buf[0] == 'A' && (unsigned char)buf[1] == 0xcc);
+
+ /* Full width letter A. */
+ memset(buf, 0xcc, sizeof(buf));
+ len = wctomb(buf, 0xa3c1);
+ ATF_REQUIRE(len == 2);
+ ATF_REQUIRE((unsigned char)buf[0] == 0xa3 &&
+ (unsigned char)buf[1] == 0xc1 &&
+ (unsigned char)buf[2] == 0xcc);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, wctomb_test);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/net/Makefile b/lib/libc/tests/net/Makefile
new file mode 100644
index 000000000000..23def7e20c68
--- /dev/null
+++ b/lib/libc/tests/net/Makefile
@@ -0,0 +1,41 @@
+# $FreeBSD$
+
+PACKAGE= tests
+
+ATF_TESTS_C+= ether_test
+ATF_TESTS_C+= eui64_aton_test
+ATF_TESTS_C+= eui64_ntoa_test
+
+CFLAGS+= -I${.CURDIR}
+
+NETBSD_ATF_TESTS_C+= getprotoent_test
+NETBSD_ATF_TESTS_C+= ether_aton_test
+
+SRCS.ether_aton_test= aton_ether_subr.c t_ether_aton.c
+
+# TODO: hostent_test
+NETBSD_ATF_TESTS_SH= nsdispatch_test
+NETBSD_ATF_TESTS_SH+= protoent_test
+NETBSD_ATF_TESTS_SH+= servent_test
+
+BINDIR= ${TESTSDIR}
+
+PROGS= h_nsd_recurse
+PROGS+= h_protoent
+PROGS+= h_servent
+PROGS+= h_dns_server
+
+LIBADD.h_nsd_recurse+= pthread
+
+CLEANFILES+= aton_ether_subr.c
+aton_ether_subr.c: gen_ether_subr ${SRCTOP}/sys/net/if_ethersubr.c
+ ${__MAKE_SHELL} ${.ALLSRC} ${.TARGET}
+
+.include "../Makefile.netbsd-tests"
+
+# TODO: the testcases needs to be ported to FreeBSD
+#TESTS_SUBDIRS= getaddrinfo
+${PACKAGE}FILES+= hosts
+${PACKAGE}FILES+= resolv.conf
+
+.include <bsd.test.mk>
diff --git a/lib/libc/tests/net/Makefile.depend b/lib/libc/tests/net/Makefile.depend
new file mode 100644
index 000000000000..949a9f66ea92
--- /dev/null
+++ b/lib/libc/tests/net/Makefile.depend
@@ -0,0 +1,21 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ gnu/lib/csu \
+ gnu/lib/libgcc \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/atf/libatf-c \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libnetbsd \
+ lib/libthr \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/lib/libc/tests/net/ether_test.c b/lib/libc/tests/net/ether_test.c
new file mode 100644
index 000000000000..5b596f01a439
--- /dev/null
+++ b/lib/libc/tests/net/ether_test.c
@@ -0,0 +1,192 @@
+/*-
+ * Copyright (c) 2007 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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 <net/ethernet.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <atf-c.h>
+
+static const char *ether_line_string = "01:23:45:67:89:ab ether_line_hostname";
+static const char *ether_line_hostname = "ether_line_hostname";
+static const struct ether_addr ether_line_addr = {
+ { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }
+};
+
+ATF_TC_WITHOUT_HEAD(ether_line);
+ATF_TC_BODY(ether_line, tc)
+{
+ struct ether_addr e;
+ char hostname[256];
+
+ ATF_REQUIRE_MSG(ether_line(ether_line_string, &e, hostname) == 0,
+ "ether_line failed; errno=%d", errno);
+ ATF_REQUIRE_MSG(bcmp(&e, &ether_line_addr, ETHER_ADDR_LEN) == 0,
+ "bad address");
+ ATF_REQUIRE_MSG(strcmp(hostname, ether_line_hostname) == 0,
+ "bad hostname");
+}
+
+static const char *ether_line_bad_1_string = "x";
+
+ATF_TC_WITHOUT_HEAD(ether_line_bad_1);
+ATF_TC_BODY(ether_line_bad_1, tc)
+{
+ struct ether_addr e;
+ char hostname[256];
+
+ ATF_REQUIRE_MSG(ether_line(ether_line_bad_1_string, &e, hostname) != 0,
+ "ether_line succeeded unexpectedly");
+}
+
+static const char *ether_line_bad_2_string = "x x";
+
+ATF_TC_WITHOUT_HEAD(ether_line_bad_2);
+ATF_TC_BODY(ether_line_bad_2, tc)
+{
+ struct ether_addr e;
+ char hostname[256];
+
+ ATF_REQUIRE_MSG(ether_line(ether_line_bad_2_string, &e, hostname) != 0,
+ "ether_line succeeded unexpectedly");
+}
+
+static const char *ether_aton_string = "01:23:45:67:89:ab";
+static const struct ether_addr ether_aton_addr = {
+ { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }
+};
+
+ATF_TC_WITHOUT_HEAD(ether_aton_r);
+ATF_TC_BODY(ether_aton_r, tc)
+{
+ struct ether_addr e, *ep;
+
+ ep = ether_aton_r(ether_aton_string, &e);
+
+ ATF_REQUIRE_MSG(ep != NULL, "ether_aton_r failed; errno=%d", errno);
+ ATF_REQUIRE_MSG(ep == &e,
+ "ether_aton_r returned different pointers; %p != %p", ep, &e);
+}
+
+static const char *ether_aton_bad_string = "x";
+
+ATF_TC_WITHOUT_HEAD(ether_aton_r_bad);
+ATF_TC_BODY(ether_aton_r_bad, tc)
+{
+ struct ether_addr e, *ep;
+
+ ep = ether_aton_r(ether_aton_bad_string, &e);
+ ATF_REQUIRE_MSG(ep == NULL, "ether_aton_r succeeded unexpectedly");
+}
+
+ATF_TC_WITHOUT_HEAD(ether_aton);
+ATF_TC_BODY(ether_aton, tc)
+{
+ struct ether_addr *ep;
+
+ ep = ether_aton(ether_aton_string);
+ ATF_REQUIRE_MSG(ep != NULL, "ether_aton failed");
+ ATF_REQUIRE_MSG(bcmp(ep, &ether_aton_addr, ETHER_ADDR_LEN) == 0,
+ "bad address");
+}
+
+ATF_TC_WITHOUT_HEAD(ether_aton_bad);
+ATF_TC_BODY(ether_aton_bad, tc)
+{
+ struct ether_addr *ep;
+
+ ep = ether_aton(ether_aton_bad_string);
+ ATF_REQUIRE_MSG(ep == NULL, "ether_aton succeeded unexpectedly");
+}
+
+static const char *ether_ntoa_string = "01:23:45:67:89:ab";
+static const struct ether_addr ether_ntoa_addr = {
+ { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }
+};
+
+ATF_TC_WITHOUT_HEAD(ether_ntoa_r);
+ATF_TC_BODY(ether_ntoa_r, tc)
+{
+ char buf[256], *cp;
+
+ cp = ether_ntoa_r(&ether_ntoa_addr, buf);
+ ATF_REQUIRE_MSG(cp != NULL, "ether_ntoa_r failed");
+ ATF_REQUIRE_MSG(cp == buf,
+ "ether_ntoa_r returned a different pointer; %p != %p", cp, buf);
+ ATF_REQUIRE_MSG(strcmp(cp, ether_ntoa_string) == 0,
+ "strings did not match (`%s` != `%s`)", cp, ether_ntoa_string);
+}
+
+ATF_TC_WITHOUT_HEAD(ether_ntoa);
+ATF_TC_BODY(ether_ntoa, tc)
+{
+ char *cp;
+
+ cp = ether_ntoa(&ether_ntoa_addr);
+ ATF_REQUIRE_MSG(cp != NULL, "ether_ntoa failed");
+ ATF_REQUIRE_MSG(strcmp(cp, ether_ntoa_string) == 0,
+ "strings did not match (`%s` != `%s`)", cp, ether_ntoa_string);
+}
+
+#if 0
+ATF_TC_WITHOUT_HEAD(ether_ntohost);
+ATF_TC_BODY(ether_ntohost, tc)
+{
+
+}
+
+ATF_TC_WITHOUT_HEAD(ether_hostton);
+ATF_TC_BODY(ether_hostton, tc)
+{
+
+}
+#endif
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, ether_line);
+ ATF_TP_ADD_TC(tp, ether_line_bad_1);
+ ATF_TP_ADD_TC(tp, ether_line_bad_2);
+ ATF_TP_ADD_TC(tp, ether_aton_r);
+ ATF_TP_ADD_TC(tp, ether_aton_r_bad);
+ ATF_TP_ADD_TC(tp, ether_aton);
+ ATF_TP_ADD_TC(tp, ether_aton_bad);
+ ATF_TP_ADD_TC(tp, ether_ntoa_r);
+ ATF_TP_ADD_TC(tp, ether_ntoa);
+#if 0
+ ATF_TP_ADD_TC(tp, ether_ntohost);
+ ATF_TP_ADD_TC(tp, ether_hostton);
+#endif
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/net/eui64_aton_test.c b/lib/libc/tests/net/eui64_aton_test.c
new file mode 100644
index 000000000000..7b97d7fb0521
--- /dev/null
+++ b/lib/libc/tests/net/eui64_aton_test.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2004 The Aerospace Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions, and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of The Aerospace Corporation may not be used to endorse or
+ * promote products derived from this software.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AEROSPACE CORPORATION "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AEROSPACE CORPORATION BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/eui64.h>
+#include <locale.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <atf-c.h>
+
+#include "test-eui64.h"
+
+static void
+test_str(const char *str, const struct eui64 *eui)
+{
+ struct eui64 e;
+ char buf[EUI64_SIZ];
+ int rc;
+
+ ATF_REQUIRE_MSG(eui64_aton(str, &e) == 0, "eui64_aton failed");
+ rc = memcmp(&e, eui, sizeof(e));
+ if (rc != 0) {
+ eui64_ntoa(&e, buf, sizeof(buf));
+ atf_tc_fail(
+ "eui64_aton(\"%s\", ..) failed; memcmp returned %d. "
+ "String obtained form eui64_ntoa was: `%s`",
+ str, rc, buf);
+ }
+}
+
+ATF_TC_WITHOUT_HEAD(id_ascii);
+ATF_TC_BODY(id_ascii, tc)
+{
+
+ test_str(test_eui64_id_ascii, &test_eui64_id);
+}
+
+ATF_TC_WITHOUT_HEAD(id_colon_ascii);
+ATF_TC_BODY(id_colon_ascii, tc)
+{
+
+ test_str(test_eui64_id_colon_ascii, &test_eui64_id);
+}
+
+ATF_TC_WITHOUT_HEAD(mac_ascii);
+ATF_TC_BODY(mac_ascii, tc)
+{
+
+ test_str(test_eui64_mac_ascii, &test_eui64_eui48);
+}
+
+ATF_TC_WITHOUT_HEAD(mac_colon_ascii);
+ATF_TC_BODY(mac_colon_ascii, tc)
+{
+
+ test_str(test_eui64_mac_colon_ascii, &test_eui64_eui48);
+}
+
+ATF_TC_WITHOUT_HEAD(hex_ascii);
+ATF_TC_BODY(hex_ascii, tc)
+{
+
+ test_str(test_eui64_hex_ascii, &test_eui64_id);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, id_ascii);
+ ATF_TP_ADD_TC(tp, id_colon_ascii);
+ ATF_TP_ADD_TC(tp, mac_ascii);
+ ATF_TP_ADD_TC(tp, mac_colon_ascii);
+ ATF_TP_ADD_TC(tp, hex_ascii);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/net/eui64_ntoa_test.c b/lib/libc/tests/net/eui64_ntoa_test.c
new file mode 100644
index 000000000000..4158e7a42cce
--- /dev/null
+++ b/lib/libc/tests/net/eui64_ntoa_test.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2004 The Aerospace Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions, and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of The Aerospace Corporation may not be used to endorse or
+ * promote products derived from this software.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AEROSPACE CORPORATION "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AEROSPACE CORPORATION BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/eui64.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <atf-c.h>
+
+#include "test-eui64.h"
+
+static void
+test_str(const char *str, const struct eui64 *eui)
+{
+ char a[EUI64_SIZ];
+
+ ATF_REQUIRE_MSG(eui64_ntoa(&test_eui64_id, a, sizeof(a)) == 0,
+ "eui64_ntoa failed");
+ ATF_REQUIRE_MSG(strcmp(a, test_eui64_id_ascii) == 0,
+ "the strings mismatched: `%s` != `%s`", a, test_eui64_id_ascii);
+}
+
+ATF_TC_WITHOUT_HEAD(id_ascii);
+ATF_TC_BODY(id_ascii, tc)
+{
+
+ test_str(test_eui64_id_ascii, &test_eui64_id);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, id_ascii);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/net/getaddrinfo/Makefile b/lib/libc/tests/net/getaddrinfo/Makefile
new file mode 100644
index 000000000000..96b60d2a9792
--- /dev/null
+++ b/lib/libc/tests/net/getaddrinfo/Makefile
@@ -0,0 +1,32 @@
+# $FreeBSD$
+
+PACKAGE= tests
+
+TESTSRC= ${SRCTOP}/contrib/netbsd-tests/lib/libc/net/${.CURDIR:T}
+
+.include <bsd.own.mk>
+
+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
+
+FILESGROUPS+= ${PACKAGE}DATA_FILES
+${PACKAGE}DATA_FILESPACKAGE= tests
+
+${PACKAGE}DATA_FILESDIR= ${TESTSDIR}/data
+
+${PACKAGE}DATA_FILES+= basics_v4.exp basics_v4v6.exp
+${PACKAGE}DATA_FILES+= no_host_v4.exp no_host_v4v6.exp
+${PACKAGE}DATA_FILES+= no_serv_v4.exp no_serv_v4v6.exp
+${PACKAGE}DATA_FILES+= sock_raw_v4.exp sock_raw_v4v6.exp
+${PACKAGE}DATA_FILES+= spec_fam_v4.exp spec_fam_v4v6.exp
+${PACKAGE}DATA_FILES+= scoped.exp
+${PACKAGE}DATA_FILES+= unsup_fam.exp
+
+.include "../../Makefile.netbsd-tests"
+
+.include <bsd.test.mk>
diff --git a/lib/libc/tests/net/test-eui64.h b/lib/libc/tests/net/test-eui64.h
new file mode 100644
index 000000000000..ea82a10c1487
--- /dev/null
+++ b/lib/libc/tests/net/test-eui64.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2004 The Aerospace Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions, and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of The Aerospace Corporation may not be used to endorse or
+ * promote products derived from this software.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AEROSPACE CORPORATION "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AEROSPACE CORPORATION BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _TEST_EUI64_H
+#define _TEST_EUI64_H
+
+struct eui64 test_eui64_id = {{0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77}};
+struct eui64 test_eui64_eui48 = {{0x00,0x11,0x22,0xFF,0xFE,0x33,0x44,0x55}};
+struct eui64 test_eui64_mac48 = {{0x00,0x11,0x22,0xFF,0xFF,0x33,0x44,0x55}};
+
+#define test_eui64_id_ascii "00-11-22-33-44-55-66-77"
+#define test_eui64_id_colon_ascii "00:11:22:33:44:55:66:77"
+#define test_eui64_hex_ascii "0x0011223344556677"
+#define test_eui64_eui48_ascii "00-11-22-ff-fe-33-44-55"
+#define test_eui64_mac48_ascii "00-11-22-ff-fe-33-44-55"
+#define test_eui64_mac_ascii "00-11-22-33-44-55"
+#define test_eui64_mac_colon_ascii "00:11:22:33:44:55"
+#define test_eui64_id_host "id"
+#define test_eui64_eui48_host "eui-48"
+#define test_eui64_mac48_host "mac-48"
+
+#define test_eui64_line_id "00-11-22-33-44-55-66-77 id"
+#define test_eui64_line_id_colon "00:11:22:33:44:55:66:77 id"
+#define test_eui64_line_eui48 "00-11-22-FF-fe-33-44-55 eui-48"
+#define test_eui64_line_mac48 "00-11-22-FF-ff-33-44-55 mac-48"
+#define test_eui64_line_eui48_6byte "00-11-22-33-44-55 eui-48"
+#define test_eui64_line_eui48_6byte_c "00:11:22:33:44:55 eui-48"
+
+#endif /* !_TEST_EUI64_H */
diff --git a/lib/libc/tests/nss/Makefile b/lib/libc/tests/nss/Makefile
new file mode 100644
index 000000000000..79f13c5fae87
--- /dev/null
+++ b/lib/libc/tests/nss/Makefile
@@ -0,0 +1,25 @@
+# $FreeBSD$
+
+PACKAGE= tests
+
+TESTSDIR= ${TESTSBASE}/lib/libc/nss
+
+BINDIR= ${TESTSDIR}
+
+.PATH: ${.CURDIR:H}/resolv
+
+${PACKAGE}FILES+= mach
+
+CFLAGS+= -I${SRCTOP}/tests
+
+ATF_TESTS_C+= getaddrinfo_test
+ATF_TESTS_C+= getgr_test
+ATF_TESTS_C+= gethostby_test
+TEST_METADATA.gethostby_test= timeout="1200"
+ATF_TESTS_C+= getpw_test
+ATF_TESTS_C+= getproto_test
+ATF_TESTS_C+= getrpc_test
+ATF_TESTS_C+= getserv_test
+ATF_TESTS_C+= getusershell_test
+
+.include <bsd.test.mk>
diff --git a/lib/libc/tests/nss/Makefile.depend b/lib/libc/tests/nss/Makefile.depend
new file mode 100644
index 000000000000..4d038059d9d9
--- /dev/null
+++ b/lib/libc/tests/nss/Makefile.depend
@@ -0,0 +1,21 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ gnu/lib/csu \
+ gnu/lib/libgcc \
+ include \
+ include/arpa \
+ include/rpc \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/atf/libatf-c \
+ lib/libc \
+ lib/libcompiler_rt \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/lib/libc/tests/nss/getaddrinfo_test.c b/lib/libc/tests/nss/getaddrinfo_test.c
new file mode 100644
index 000000000000..0c9704fe366d
--- /dev/null
+++ b/lib/libc/tests/nss/getaddrinfo_test.c
@@ -0,0 +1,556 @@
+/*-
+ * Copyright (c) 2006 Michael Bushkov <bushman@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stringlist.h>
+#include <unistd.h>
+
+#include <atf-c.h>
+
+#include "freebsd_test_suite/macros.h"
+#include "testutil.h"
+
+enum test_methods {
+ TEST_GETADDRINFO,
+ TEST_BUILD_SNAPSHOT
+};
+
+static struct addrinfo hints;
+static enum test_methods method = TEST_GETADDRINFO;
+
+DECLARE_TEST_DATA(addrinfo)
+DECLARE_TEST_FILE_SNAPSHOT(addrinfo)
+DECLARE_2PASS_TEST(addrinfo)
+
+static void clone_addrinfo(struct addrinfo *, struct addrinfo const *);
+static int compare_addrinfo(struct addrinfo *, struct addrinfo *, void *);
+static void dump_addrinfo(struct addrinfo *);
+
+static void sdump_addrinfo(struct addrinfo *, char *, size_t);
+
+IMPLEMENT_TEST_DATA(addrinfo)
+IMPLEMENT_TEST_FILE_SNAPSHOT(addrinfo)
+IMPLEMENT_2PASS_TEST(addrinfo)
+
+static void
+clone_addrinfo(struct addrinfo *dest, struct addrinfo const *src)
+{
+
+ ATF_REQUIRE(dest != NULL);
+ ATF_REQUIRE(src != NULL);
+
+ memcpy(dest, src, sizeof(struct addrinfo));
+ if (src->ai_canonname != NULL)
+ dest->ai_canonname = strdup(src->ai_canonname);
+
+ if (src->ai_addr != NULL) {
+ dest->ai_addr = malloc(src->ai_addrlen);
+ ATF_REQUIRE(dest->ai_addr != NULL);
+ memcpy(dest->ai_addr, src->ai_addr, src->ai_addrlen);
+ }
+
+ if (src->ai_next != NULL) {
+ dest->ai_next = malloc(sizeof(struct addrinfo));
+ ATF_REQUIRE(dest->ai_next != NULL);
+ clone_addrinfo(dest->ai_next, src->ai_next);
+ }
+}
+
+static int
+compare_addrinfo_(struct addrinfo *ai1, struct addrinfo *ai2)
+{
+
+ if ((ai1 == NULL) || (ai2 == NULL))
+ return (-1);
+
+ if (ai1->ai_flags != ai2->ai_flags ||
+ ai1->ai_family != ai2->ai_family ||
+ ai1->ai_socktype != ai2->ai_socktype ||
+ ai1->ai_protocol != ai2->ai_protocol ||
+ ai1->ai_addrlen != ai2->ai_addrlen ||
+ ((ai1->ai_addr == NULL || ai2->ai_addr == NULL) &&
+ ai1->ai_addr != ai2->ai_addr) ||
+ ((ai1->ai_canonname == NULL || ai2->ai_canonname == NULL) &&
+ ai1->ai_canonname != ai2->ai_canonname))
+ return (-1);
+
+ if (ai1->ai_canonname != NULL &&
+ strcmp(ai1->ai_canonname, ai2->ai_canonname) != 0)
+ return (-1);
+
+ if (ai1->ai_addr != NULL &&
+ memcmp(ai1->ai_addr, ai2->ai_addr, ai1->ai_addrlen) != 0)
+ return (-1);
+
+ if (ai1->ai_next == NULL && ai2->ai_next == NULL)
+ return (0);
+ else
+ return (compare_addrinfo_(ai1->ai_next, ai2->ai_next));
+}
+
+static int
+compare_addrinfo(struct addrinfo *ai1, struct addrinfo *ai2, void *mdata)
+{
+ int rv;
+
+ printf("testing equality of 2 addrinfo structures\n");
+
+ rv = compare_addrinfo_(ai1, ai2);
+
+ if (rv == 0)
+ printf("equal\n");
+ else {
+ dump_addrinfo(ai1);
+ dump_addrinfo(ai2);
+ printf("not equal\n");
+ }
+
+ return (rv);
+}
+
+void
+free_addrinfo(struct addrinfo *ai)
+{
+ if (ai == NULL)
+ return;
+
+ free(ai->ai_addr);
+ free(ai->ai_canonname);
+ free_addrinfo(ai->ai_next);
+}
+
+void
+sdump_addrinfo(struct addrinfo *ai, char *buffer, size_t buflen)
+{
+ int written, i;
+
+ written = snprintf(buffer, buflen, "%d %d %d %d %d ",
+ ai->ai_flags, ai->ai_family, ai->ai_socktype, ai->ai_protocol,
+ ai->ai_addrlen);
+ buffer += written;
+ if (written > buflen)
+ return;
+ buflen -= written;
+
+ written = snprintf(buffer, buflen, "%s ",
+ ai->ai_canonname == NULL ? "(null)" : ai->ai_canonname);
+ buffer += written;
+ if (written > buflen)
+ return;
+ buflen -= written;
+
+ if (ai->ai_addr == NULL) {
+ written = snprintf(buffer, buflen, "(null)");
+ buffer += written;
+ if (written > buflen)
+ return;
+ buflen -= written;
+ } else {
+ for (i = 0; i < ai->ai_addrlen; i++) {
+ written = snprintf(buffer, buflen,
+ i + 1 != ai->ai_addrlen ? "%d." : "%d",
+ ((unsigned char *)ai->ai_addr)[i]);
+ buffer += written;
+ if (written > buflen)
+ return;
+ buflen -= written;
+
+ if (buflen == 0)
+ return;
+ }
+ }
+
+ if (ai->ai_next != NULL) {
+ written = snprintf(buffer, buflen, ":");
+ buffer += written;
+ if (written > buflen)
+ return;
+ buflen -= written;
+
+ sdump_addrinfo(ai->ai_next, buffer, buflen);
+ }
+}
+
+void
+dump_addrinfo(struct addrinfo *result)
+{
+ if (result != NULL) {
+ char buffer[2048];
+ sdump_addrinfo(result, buffer, sizeof(buffer));
+ printf("%s\n", buffer);
+ } else
+ printf("(null)\n");
+}
+
+static int
+addrinfo_read_snapshot_addr(char *addr, unsigned char *result, size_t len)
+{
+ char *s, *ps, *ts;
+
+ ps = addr;
+ while ((s = strsep(&ps, ".")) != NULL) {
+ if (len == 0)
+ return (-1);
+
+ *result = (unsigned char)strtol(s, &ts, 10);
+ ++result;
+ if (*ts != '\0')
+ return (-1);
+
+ --len;
+ }
+ if (len != 0)
+ return (-1);
+ else
+ return (0);
+}
+
+static int
+addrinfo_read_snapshot_ai(struct addrinfo *ai, char *line)
+{
+ char *s, *ps, *ts;
+ int i, rv, *pi;
+
+ rv = 0;
+ i = 0;
+ ps = line;
+ memset(ai, 0, sizeof(struct addrinfo));
+ while ((s = strsep(&ps, " ")) != NULL) {
+ switch (i) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ pi = &ai->ai_flags + i;
+ *pi = (int)strtol(s, &ts, 10);
+ if (*ts != '\0')
+ goto fin;
+ break;
+ case 4:
+ ai->ai_addrlen = (socklen_t)strtol(s, &ts, 10);
+ if (*ts != '\0')
+ goto fin;
+ break;
+ case 5:
+ if (strcmp(s, "(null)") != 0) {
+ ai->ai_canonname = strdup(s);
+ ATF_REQUIRE(ai->ai_canonname != NULL);
+ }
+ break;
+ case 6:
+ if (strcmp(s, "(null)") != 0) {
+ ai->ai_addr = calloc(1, ai->ai_addrlen);
+ ATF_REQUIRE(ai->ai_addr != NULL);
+ rv = addrinfo_read_snapshot_addr(s,
+ (unsigned char *)ai->ai_addr,
+ ai->ai_addrlen);
+
+ if (rv != 0)
+ goto fin;
+ }
+ break;
+ default:
+ /* NOTE: should not be reachable */
+ rv = -1;
+ goto fin;
+ }
+
+ ++i;
+ }
+
+fin:
+ if (i != 7 || rv != 0) {
+ free_addrinfo(ai);
+ ai = NULL;
+ return (-1);
+ }
+
+ return (0);
+}
+
+static int
+addrinfo_read_snapshot_func(struct addrinfo *ai, char *line)
+{
+ struct addrinfo *ai2;
+ char *s, *ps;
+ int i, rv;
+
+ printf("1 line read from snapshot:\n%s\n", line);
+
+ rv = 0;
+ i = 0;
+ ps = line;
+
+ s = strsep(&ps, ":");
+ if (s == NULL)
+ return (-1);
+
+ rv = addrinfo_read_snapshot_ai(ai, s);
+ if (rv != 0)
+ return (-1);
+
+ ai2 = ai;
+ while ((s = strsep(&ps, ":")) != NULL) {
+ ai2->ai_next = calloc(1, sizeof(struct addrinfo));
+ ATF_REQUIRE(ai2->ai_next != NULL);
+
+ rv = addrinfo_read_snapshot_ai(ai2->ai_next, s);
+ if (rv != 0) {
+ free_addrinfo(ai);
+ ai = NULL;
+ return (-1);
+ }
+
+ ai2 = ai2->ai_next;
+ }
+
+ return (0);
+}
+
+static int
+addrinfo_test_correctness(struct addrinfo *ai, void *mdata)
+{
+
+ printf("testing correctness with the following data:\n");
+ dump_addrinfo(ai);
+
+ if (ai == NULL)
+ goto errfin;
+
+ if (!(ai->ai_family >= 0 && ai->ai_family < AF_MAX))
+ goto errfin;
+
+ if (ai->ai_socktype != 0 && ai->ai_socktype != SOCK_STREAM &&
+ ai->ai_socktype != SOCK_DGRAM && ai->ai_socktype != SOCK_RAW)
+ goto errfin;
+
+ if (ai->ai_protocol != 0 && ai->ai_protocol != IPPROTO_UDP &&
+ ai->ai_protocol != IPPROTO_TCP)
+ goto errfin;
+
+ if ((ai->ai_flags & ~(AI_CANONNAME | AI_NUMERICHOST | AI_PASSIVE)) != 0)
+ goto errfin;
+
+ if (ai->ai_addrlen != ai->ai_addr->sa_len ||
+ ai->ai_family != ai->ai_addr->sa_family)
+ goto errfin;
+
+ printf("correct\n");
+
+ return (0);
+errfin:
+ printf("incorrect\n");
+
+ return (-1);
+}
+
+static int
+addrinfo_read_hostlist_func(struct addrinfo *ai, char *line)
+{
+ struct addrinfo *result;
+ int rv;
+
+ printf("resolving %s: ", line);
+ rv = getaddrinfo(line, NULL, &hints, &result);
+ if (rv == 0) {
+ printf("found\n");
+
+ rv = addrinfo_test_correctness(result, NULL);
+ if (rv != 0) {
+ freeaddrinfo(result);
+ result = NULL;
+ return (rv);
+ }
+
+ clone_addrinfo(ai, result);
+ freeaddrinfo(result);
+ result = NULL;
+ } else {
+ printf("not found\n");
+
+ memset(ai, 0, sizeof(struct addrinfo));
+ }
+ return (0);
+}
+
+void
+run_tests(char *hostlist_file, char *snapshot_file, int ai_family)
+{
+ struct addrinfo_test_data td, td_snap;
+ int rv;
+
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = ai_family;
+ hints.ai_flags = AI_CANONNAME;
+
+ if (snapshot_file != NULL)
+ method = TEST_BUILD_SNAPSHOT;
+
+ TEST_DATA_INIT(addrinfo, &td, clone_addrinfo, free_addrinfo);
+ TEST_DATA_INIT(addrinfo, &td_snap, clone_addrinfo, free_addrinfo);
+
+ ATF_REQUIRE_MSG(access(hostlist_file, R_OK) == 0,
+ "can't access the hostlist file %s\n", hostlist_file);
+
+ printf("building host lists from %s\n", hostlist_file);
+
+ rv = TEST_SNAPSHOT_FILE_READ(addrinfo, hostlist_file, &td,
+ addrinfo_read_hostlist_func);
+ if (rv != 0)
+ goto fin;
+
+ if (snapshot_file != NULL) {
+ if (access(snapshot_file, W_OK | R_OK) != 0) {
+ if (errno == ENOENT)
+ method = TEST_BUILD_SNAPSHOT;
+ else {
+ printf("can't access the snapshot "
+ "file %s\n", snapshot_file);
+
+ rv = -1;
+ goto fin;
+ }
+ } else {
+ rv = TEST_SNAPSHOT_FILE_READ(addrinfo, snapshot_file,
+ &td_snap, addrinfo_read_snapshot_func);
+ if (rv != 0) {
+ printf("error reading snapshot file: %s\n",
+ strerror(errno));
+ goto fin;
+ }
+ }
+ }
+
+ switch (method) {
+ case TEST_GETADDRINFO:
+ if (snapshot_file != NULL)
+ ATF_CHECK(DO_2PASS_TEST(addrinfo, &td, &td_snap,
+ compare_addrinfo, NULL) == 0);
+ break;
+ case TEST_BUILD_SNAPSHOT:
+ if (snapshot_file != NULL) {
+ ATF_CHECK(TEST_SNAPSHOT_FILE_WRITE(addrinfo,
+ snapshot_file, &td, sdump_addrinfo) == 0);
+ }
+ break;
+ default:
+ break;
+ }
+
+fin:
+ TEST_DATA_DESTROY(addrinfo, &td_snap);
+ TEST_DATA_DESTROY(addrinfo, &td);
+
+ free(hostlist_file);
+ free(snapshot_file);
+}
+
+#define HOSTLIST_FILE "mach"
+#define RUN_TESTS(tc, snapshot_file, ai_family) do { \
+ char *_hostlist_file; \
+ char *_snapshot_file; \
+ ATF_REQUIRE(0 < asprintf(&_hostlist_file, "%s/%s", \
+ atf_tc_get_config_var(tc, "srcdir"), HOSTLIST_FILE)); \
+ if (snapshot_file == NULL) \
+ _snapshot_file = NULL; \
+ else { \
+ _snapshot_file = strdup(snapshot_file); \
+ ATF_REQUIRE(_snapshot_file != NULL); \
+ } \
+ run_tests(_hostlist_file, _snapshot_file, ai_family); \
+} while(0)
+
+ATF_TC_WITHOUT_HEAD(pf_unspec);
+ATF_TC_BODY(pf_unspec, tc)
+{
+
+ RUN_TESTS(tc, NULL, AF_UNSPEC);
+}
+
+ATF_TC_WITHOUT_HEAD(pf_unspec_with_snapshot);
+ATF_TC_BODY(pf_unspec_with_snapshot, tc)
+{
+
+ RUN_TESTS(tc, "snapshot_ai", AF_UNSPEC);
+}
+
+ATF_TC_WITHOUT_HEAD(pf_inet);
+ATF_TC_BODY(pf_inet, tc)
+{
+
+ ATF_REQUIRE_FEATURE("inet");
+ RUN_TESTS(tc, NULL, AF_INET);
+}
+
+ATF_TC_WITHOUT_HEAD(pf_inet_with_snapshot);
+ATF_TC_BODY(pf_inet_with_snapshot, tc)
+{
+
+ ATF_REQUIRE_FEATURE("inet");
+ RUN_TESTS(tc, "snapshot_ai4", AF_INET);
+}
+
+ATF_TC_WITHOUT_HEAD(pf_inet6);
+ATF_TC_BODY(pf_inet6, tc)
+{
+
+ ATF_REQUIRE_FEATURE("inet6");
+ RUN_TESTS(tc, NULL, AF_INET6);
+}
+
+ATF_TC_WITHOUT_HEAD(pf_inet6_with_snapshot);
+ATF_TC_BODY(pf_inet6_with_snapshot, tc)
+{
+
+ ATF_REQUIRE_FEATURE("inet6");
+ RUN_TESTS(tc, "snapshot_ai6", AF_INET6);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, pf_unspec);
+ ATF_TP_ADD_TC(tp, pf_unspec_with_snapshot);
+ ATF_TP_ADD_TC(tp, pf_inet);
+ ATF_TP_ADD_TC(tp, pf_inet_with_snapshot);
+ ATF_TP_ADD_TC(tp, pf_inet6);
+ ATF_TP_ADD_TC(tp, pf_inet6_with_snapshot);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/nss/getgr_test.c b/lib/libc/tests/nss/getgr_test.c
new file mode 100644
index 000000000000..81c1cd074264
--- /dev/null
+++ b/lib/libc/tests/nss/getgr_test.c
@@ -0,0 +1,546 @@
+/*-
+ * Copyright (c) 2006 Michael Bushkov <bushman@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <grp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stringlist.h>
+#include <unistd.h>
+
+#include <atf-c.h>
+
+#include "testutil.h"
+
+enum test_methods {
+ TEST_GETGRENT = 1,
+ TEST_GETGRNAM = 2,
+ TEST_GETGRGID = 4,
+ TEST_GETGRENT_2PASS = 8,
+ TEST_BUILD_SNAPSHOT = 16,
+};
+
+static enum test_methods method = TEST_BUILD_SNAPSHOT;
+
+DECLARE_TEST_DATA(group)
+DECLARE_TEST_FILE_SNAPSHOT(group)
+DECLARE_1PASS_TEST(group)
+DECLARE_2PASS_TEST(group)
+
+static void clone_group(struct group *, struct group const *);
+static int compare_group(struct group *, struct group *, void *);
+static void dump_group(struct group *);
+static void free_group(struct group *);
+
+static void sdump_group(struct group *, char *, size_t);
+static int group_read_snapshot_func(struct group *, char *);
+
+static int group_check_ambiguity(struct group_test_data *,
+ struct group *);
+static int group_fill_test_data(struct group_test_data *);
+static int group_test_correctness(struct group *, void *);
+static int group_test_getgrnam(struct group *, void *);
+static int group_test_getgrgid(struct group *, void *);
+static int group_test_getgrent(struct group *, void *);
+
+IMPLEMENT_TEST_DATA(group)
+IMPLEMENT_TEST_FILE_SNAPSHOT(group)
+IMPLEMENT_1PASS_TEST(group)
+IMPLEMENT_2PASS_TEST(group)
+
+static void
+clone_group(struct group *dest, struct group const *src)
+{
+ ATF_REQUIRE(dest != NULL);
+ ATF_REQUIRE(src != NULL);
+
+ char **cp;
+ int members_num;
+
+ memset(dest, 0, sizeof(struct group));
+
+ if (src->gr_name != NULL) {
+ dest->gr_name = strdup(src->gr_name);
+ ATF_REQUIRE(dest->gr_name != NULL);
+ }
+
+ if (src->gr_passwd != NULL) {
+ dest->gr_passwd = strdup(src->gr_passwd);
+ ATF_REQUIRE(dest->gr_passwd != NULL);
+ }
+ dest->gr_gid = src->gr_gid;
+
+ if (src->gr_mem != NULL) {
+ members_num = 0;
+ for (cp = src->gr_mem; *cp; ++cp)
+ ++members_num;
+
+ dest->gr_mem = calloc(1, (members_num + 1) * sizeof(char *));
+ ATF_REQUIRE(dest->gr_mem != NULL);
+
+ for (cp = src->gr_mem; *cp; ++cp) {
+ dest->gr_mem[cp - src->gr_mem] = strdup(*cp);
+ ATF_REQUIRE(dest->gr_mem[cp - src->gr_mem] != NULL);
+ }
+ }
+}
+
+static void
+free_group(struct group *grp)
+{
+ char **cp;
+
+ ATF_REQUIRE(grp != NULL);
+
+ free(grp->gr_name);
+ free(grp->gr_passwd);
+
+ for (cp = grp->gr_mem; *cp; ++cp)
+ free(*cp);
+ free(grp->gr_mem);
+}
+
+static int
+compare_group(struct group *grp1, struct group *grp2, void *mdata)
+{
+ char **c1, **c2;
+
+ if (grp1 == grp2)
+ return (0);
+
+ if (grp1 == NULL || grp2 == NULL)
+ goto errfin;
+
+ if (strcmp(grp1->gr_name, grp2->gr_name) != 0 ||
+ strcmp(grp1->gr_passwd, grp2->gr_passwd) != 0 ||
+ grp1->gr_gid != grp2->gr_gid)
+ goto errfin;
+
+ c1 = grp1->gr_mem;
+ c2 = grp2->gr_mem;
+
+ if (grp1->gr_mem == NULL || grp2->gr_mem == NULL)
+ goto errfin;
+
+ for (; *c1 && *c2; ++c1, ++c2)
+ if (strcmp(*c1, *c2) != 0)
+ goto errfin;
+
+ if (*c1 != '\0' || *c2 != '\0')
+ goto errfin;
+
+ return 0;
+
+errfin:
+ if (mdata == NULL) {
+ printf("following structures are not equal:\n");
+ dump_group(grp1);
+ dump_group(grp2);
+ }
+
+ return (-1);
+}
+
+static void
+sdump_group(struct group *grp, char *buffer, size_t buflen)
+{
+ char **cp;
+ int written;
+
+ written = snprintf(buffer, buflen, "%s:%s:%d:",
+ grp->gr_name, grp->gr_passwd, grp->gr_gid);
+ buffer += written;
+ if (written > buflen)
+ return;
+ buflen -= written;
+
+ if (grp->gr_mem != NULL) {
+ if (*(grp->gr_mem) != '\0') {
+ for (cp = grp->gr_mem; *cp; ++cp) {
+ written = snprintf(buffer, buflen, "%s%s",
+ cp == grp->gr_mem ? "" : ",", *cp);
+ buffer += written;
+ if (written > buflen)
+ return;
+ buflen -= written;
+
+ if (buflen == 0)
+ return;
+ }
+ } else
+ snprintf(buffer, buflen, "nomem");
+ } else
+ snprintf(buffer, buflen, "(null)");
+}
+
+static int
+group_read_snapshot_func(struct group *grp, char *line)
+{
+ StringList *sl;
+ char *s, *ps, *ts;
+ const char *sep;
+ int i;
+
+ printf("1 line read from snapshot:\n%s\n", line);
+
+ i = 0;
+ sl = NULL;
+ ps = line;
+ sep = ":";
+ memset(grp, 0, sizeof(struct group));
+ while ((s = strsep(&ps, sep)) != NULL) {
+ switch (i) {
+ case 0:
+ grp->gr_name = strdup(s);
+ ATF_REQUIRE(grp->gr_name != NULL);
+ break;
+
+ case 1:
+ grp->gr_passwd = strdup(s);
+ ATF_REQUIRE(grp->gr_passwd != NULL);
+ break;
+
+ case 2:
+ grp->gr_gid = (gid_t)strtol(s, &ts, 10);
+ if (*ts != '\0') {
+ free(grp->gr_name);
+ free(grp->gr_passwd);
+ grp->gr_name = NULL;
+ grp->gr_passwd = NULL;
+ return (-1);
+ }
+ /* Change to parsing groups. */
+ sep = ",";
+ break;
+
+ default:
+ if (sl == NULL) {
+ if (strcmp(s, "(null)") == 0)
+ return (0);
+
+ sl = sl_init();
+ ATF_REQUIRE(sl != NULL);
+
+ if (strcmp(s, "nomem") != 0) {
+ ts = strdup(s);
+ ATF_REQUIRE(ts != NULL);
+ sl_add(sl, ts);
+ }
+ } else {
+ ts = strdup(s);
+ ATF_REQUIRE(ts != NULL);
+ sl_add(sl, ts);
+ }
+ break;
+ }
+ ++i;
+ }
+
+ if (i < 3) {
+ free(grp->gr_name);
+ free(grp->gr_passwd);
+ memset(grp, 0, sizeof(struct group));
+ return (-1);
+ }
+
+ sl_add(sl, NULL);
+ grp->gr_mem = sl->sl_str;
+
+ /* NOTE: is it a dirty hack or not? */
+ free(sl);
+ return (0);
+}
+
+static void
+dump_group(struct group *result)
+{
+ if (result != NULL) {
+ char buffer[1024];
+ sdump_group(result, buffer, sizeof(buffer));
+ printf("%s\n", buffer);
+ } else
+ printf("(null)\n");
+}
+
+static int
+group_fill_test_data(struct group_test_data *td)
+{
+ struct group *grp;
+
+ setgroupent(1);
+ while ((grp = getgrent()) != NULL) {
+ if (group_test_correctness(grp, NULL) == 0)
+ TEST_DATA_APPEND(group, td, grp);
+ else
+ return (-1);
+ }
+ endgrent();
+
+ return (0);
+}
+
+static int
+group_test_correctness(struct group *grp, void *mdata)
+{
+ printf("testing correctness with the following data:\n");
+ dump_group(grp);
+
+ if (grp == NULL)
+ goto errfin;
+
+ if (grp->gr_name == NULL)
+ goto errfin;
+
+ if (grp->gr_passwd == NULL)
+ goto errfin;
+
+ if (grp->gr_mem == NULL)
+ goto errfin;
+
+ printf("correct\n");
+
+ return (0);
+errfin:
+ printf("incorrect\n");
+
+ return (-1);
+}
+
+/* group_check_ambiguity() is needed here because when doing the getgrent()
+ * calls sequence, records from different nsswitch sources can be different,
+ * though having the same pw_name/pw_uid */
+static int
+group_check_ambiguity(struct group_test_data *td, struct group *pwd)
+{
+
+ return (TEST_DATA_FIND(group, td, pwd, compare_group,
+ NULL) != NULL ? 0 : -1);
+}
+
+static int
+group_test_getgrnam(struct group *grp_model, void *mdata)
+{
+ struct group *grp;
+
+ printf("testing getgrnam() with the following data:\n");
+ dump_group(grp_model);
+
+ grp = getgrnam(grp_model->gr_name);
+ if (group_test_correctness(grp, NULL) != 0)
+ goto errfin;
+
+ if (compare_group(grp, grp_model, NULL) != 0 &&
+ group_check_ambiguity((struct group_test_data *)mdata, grp) != 0)
+ goto errfin;
+
+ return (0);
+
+errfin:
+ return (-1);
+}
+
+static int
+group_test_getgrgid(struct group *grp_model, void *mdata)
+{
+ struct group *grp;
+
+ printf("testing getgrgid() with the following data...\n");
+ dump_group(grp_model);
+
+ grp = getgrgid(grp_model->gr_gid);
+ if (group_test_correctness(grp, NULL) != 0 ||
+ (compare_group(grp, grp_model, NULL) != 0 &&
+ group_check_ambiguity((struct group_test_data *)mdata, grp) != 0)) {
+ return (-1);
+ } else {
+ return (0);
+ }
+}
+
+static int
+group_test_getgrent(struct group *grp, void *mdata)
+{
+ /* Only correctness can be checked when doing 1-pass test for
+ * getgrent(). */
+ return (group_test_correctness(grp, NULL));
+}
+
+static int
+run_tests(const char *snapshot_file, enum test_methods method)
+{
+ struct group_test_data td, td_snap, td_2pass;
+ int rv;
+
+ TEST_DATA_INIT(group, &td, clone_group, free_group);
+ TEST_DATA_INIT(group, &td_snap, clone_group, free_group);
+ if (snapshot_file != NULL) {
+ if (access(snapshot_file, W_OK | R_OK) != 0) {
+ if (errno == ENOENT)
+ method = TEST_BUILD_SNAPSHOT;
+ else {
+ printf("can't access the file %s\n",
+ snapshot_file);
+
+ rv = -1;
+ goto fin;
+ }
+ } else {
+ if (method == TEST_BUILD_SNAPSHOT) {
+ rv = 0;
+ goto fin;
+ }
+
+ TEST_SNAPSHOT_FILE_READ(group, snapshot_file,
+ &td_snap, group_read_snapshot_func);
+ }
+ }
+
+ rv = group_fill_test_data(&td);
+ if (rv == -1)
+ return (-1);
+ switch (method) {
+ case TEST_GETGRNAM:
+ if (snapshot_file == NULL)
+ rv = DO_1PASS_TEST(group, &td,
+ group_test_getgrnam, (void *)&td);
+ else
+ rv = DO_1PASS_TEST(group, &td_snap,
+ group_test_getgrnam, (void *)&td_snap);
+ break;
+ case TEST_GETGRGID:
+ if (snapshot_file == NULL)
+ rv = DO_1PASS_TEST(group, &td,
+ group_test_getgrgid, (void *)&td);
+ else
+ rv = DO_1PASS_TEST(group, &td_snap,
+ group_test_getgrgid, (void *)&td_snap);
+ break;
+ case TEST_GETGRENT:
+ if (snapshot_file == NULL)
+ rv = DO_1PASS_TEST(group, &td, group_test_getgrent,
+ (void *)&td);
+ else
+ rv = DO_2PASS_TEST(group, &td, &td_snap,
+ compare_group, NULL);
+ break;
+ case TEST_GETGRENT_2PASS:
+ TEST_DATA_INIT(group, &td_2pass, clone_group, free_group);
+ rv = group_fill_test_data(&td_2pass);
+ if (rv != -1)
+ rv = DO_2PASS_TEST(group, &td, &td_2pass,
+ compare_group, NULL);
+ TEST_DATA_DESTROY(group, &td_2pass);
+ break;
+ case TEST_BUILD_SNAPSHOT:
+ if (snapshot_file != NULL)
+ rv = TEST_SNAPSHOT_FILE_WRITE(group, snapshot_file, &td,
+ sdump_group);
+ break;
+ default:
+ rv = 0;
+ break;
+ }
+
+fin:
+ TEST_DATA_DESTROY(group, &td_snap);
+ TEST_DATA_DESTROY(group, &td);
+
+ return (rv);
+}
+
+#define SNAPSHOT_FILE "snapshot_grp"
+
+ATF_TC_BODY(getgrent, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETGRENT) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getgrent_with_snapshot);
+ATF_TC_BODY(getgrent_with_snapshot, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETGRENT) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getgrent_with_two_pass);
+ATF_TC_BODY(getgrent_with_two_pass, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETGRENT_2PASS) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getgrgid);
+ATF_TC_BODY(getgrgid, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETGRGID) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getgrgid_with_snapshot);
+ATF_TC_BODY(getgrgid_with_snapshot, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETGRGID) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getgrnam);
+ATF_TC_BODY(getgrnam, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETGRNAM) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getgrnam_with_snapshot);
+ATF_TC_BODY(getgrnam_with_snapshot, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETGRNAM) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getgrent);
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, getgrent);
+ ATF_TP_ADD_TC(tp, getgrent_with_snapshot);
+ ATF_TP_ADD_TC(tp, getgrent_with_two_pass);
+ ATF_TP_ADD_TC(tp, getgrgid);
+ ATF_TP_ADD_TC(tp, getgrgid_with_snapshot);
+ ATF_TP_ADD_TC(tp, getgrnam);
+ ATF_TP_ADD_TC(tp, getgrnam_with_snapshot);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/nss/gethostby_test.c b/lib/libc/tests/nss/gethostby_test.c
new file mode 100644
index 000000000000..618f7470920b
--- /dev/null
+++ b/lib/libc/tests/nss/gethostby_test.c
@@ -0,0 +1,1506 @@
+/*-
+ * Copyright (c) 2006 Michael Bushkov <bushman@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stringlist.h>
+#include <unistd.h>
+
+#include <atf-c.h>
+
+#include "freebsd_test_suite/macros.h"
+#include "testutil.h"
+
+enum test_methods {
+ TEST_GETHOSTBYNAME2,
+ TEST_GETHOSTBYADDR,
+ TEST_GETHOSTBYNAME2_GETADDRINFO,
+ TEST_GETHOSTBYADDR_GETNAMEINFO,
+ TEST_BUILD_SNAPSHOT,
+ TEST_BUILD_ADDR_SNAPSHOT
+};
+
+static int ipnode_flags = 0;
+static int af_type = AF_INET;
+static bool use_ipnode_functions;
+
+DECLARE_TEST_DATA(hostent)
+DECLARE_TEST_FILE_SNAPSHOT(hostent)
+DECLARE_1PASS_TEST(hostent)
+DECLARE_2PASS_TEST(hostent)
+
+/* These stubs will use gethostby***() or getipnodeby***() functions,
+ * depending on the use_ipnode_functions global variable value */
+static struct hostent *__gethostbyname2(const char *, int);
+static struct hostent *__gethostbyaddr(const void *, socklen_t, int);
+static void __freehostent(struct hostent *);
+
+static void clone_hostent(struct hostent *, struct hostent const *);
+static int compare_hostent(struct hostent *, struct hostent *, void *);
+static void dump_hostent(struct hostent *);
+static void free_hostent(struct hostent *);
+
+static int is_hostent_equal(struct hostent *, struct addrinfo *);
+
+static void sdump_hostent(struct hostent *, char *, size_t);
+static int hostent_read_hostlist_func(struct hostent *, char *);
+static int hostent_read_snapshot_addr(char *, unsigned char *, size_t);
+static int hostent_read_snapshot_func(struct hostent *, char *);
+
+static int hostent_test_correctness(struct hostent *, void *);
+static int hostent_test_gethostbyaddr(struct hostent *, void *);
+static int hostent_test_getaddrinfo_eq(struct hostent *, void *);
+static int hostent_test_getnameinfo_eq(struct hostent *, void *);
+
+static void usage(void) __attribute__((__noreturn__));
+
+IMPLEMENT_TEST_DATA(hostent)
+IMPLEMENT_TEST_FILE_SNAPSHOT(hostent)
+IMPLEMENT_1PASS_TEST(hostent)
+IMPLEMENT_2PASS_TEST(hostent)
+
+static struct hostent *
+__gethostbyname2(const char *name, int af)
+{
+ struct hostent *he;
+ int error;
+
+ if (use_ipnode_functions) {
+ error = 0;
+ he = getipnodebyname(name, af, ipnode_flags, &error);
+ if (he == NULL)
+ errno = error;
+ } else
+ he = gethostbyname2(name, af);
+
+ return (he);
+}
+
+static struct hostent *
+__gethostbyaddr(const void *addr, socklen_t len, int af)
+{
+ struct hostent *he;
+ int error;
+
+ if (use_ipnode_functions) {
+ error = 0;
+ he = getipnodebyaddr(addr, len, af, &error);
+ if (he == NULL)
+ errno = error;
+ } else
+ he = gethostbyaddr(addr, len, af);
+
+ return (he);
+}
+
+static void
+__freehostent(struct hostent *he)
+{
+
+ /* NOTE: checking for he != NULL - just in case */
+ if (use_ipnode_functions && he != NULL)
+ freehostent(he);
+}
+
+static void
+clone_hostent(struct hostent *dest, struct hostent const *src)
+{
+ ATF_REQUIRE(dest != NULL);
+ ATF_REQUIRE(src != NULL);
+
+ char **cp;
+ int aliases_num;
+ int addrs_num;
+ size_t offset;
+
+ memset(dest, 0, sizeof(struct hostent));
+
+ if (src->h_name != NULL) {
+ dest->h_name = strdup(src->h_name);
+ ATF_REQUIRE(dest->h_name != NULL);
+ }
+
+ dest->h_addrtype = src->h_addrtype;
+ dest->h_length = src->h_length;
+
+ if (src->h_aliases != NULL) {
+ aliases_num = 0;
+ for (cp = src->h_aliases; *cp; ++cp)
+ ++aliases_num;
+
+ dest->h_aliases = calloc(1, (aliases_num + 1) *
+ sizeof(char *));
+ ATF_REQUIRE(dest->h_aliases != NULL);
+
+ for (cp = src->h_aliases; *cp; ++cp) {
+ dest->h_aliases[cp - src->h_aliases] = strdup(*cp);
+ ATF_REQUIRE(dest->h_aliases[cp - src->h_aliases] != NULL);
+ }
+ }
+
+ if (src->h_addr_list != NULL) {
+ addrs_num = 0;
+ for (cp = src->h_addr_list; *cp; ++cp)
+ ++addrs_num;
+
+ dest->h_addr_list = calloc(1, (addrs_num + 1) * sizeof(char *));
+ ATF_REQUIRE(dest->h_addr_list != NULL);
+
+ for (cp = src->h_addr_list; *cp; ++cp) {
+ offset = cp - src->h_addr_list;
+ dest->h_addr_list[offset] = malloc(src->h_length);
+ ATF_REQUIRE(dest->h_addr_list[offset] != NULL);
+ memcpy(dest->h_addr_list[offset],
+ src->h_addr_list[offset], src->h_length);
+ }
+ }
+}
+
+static void
+free_hostent(struct hostent *ht)
+{
+ char **cp;
+
+ ATF_REQUIRE(ht != NULL);
+
+ free(ht->h_name);
+
+ if (ht->h_aliases != NULL) {
+ for (cp = ht->h_aliases; *cp; ++cp)
+ free(*cp);
+ free(ht->h_aliases);
+ }
+
+ if (ht->h_addr_list != NULL) {
+ for (cp = ht->h_addr_list; *cp; ++cp)
+ free(*cp);
+ free(ht->h_addr_list);
+ }
+}
+
+static int
+compare_hostent(struct hostent *ht1, struct hostent *ht2, void *mdata)
+{
+ char **c1, **c2, **ct, **cb;
+ int b;
+
+ if (ht1 == ht2)
+ return 0;
+
+ if (ht1 == NULL || ht2 == NULL)
+ goto errfin;
+
+ if (ht1->h_name == NULL || ht2->h_name == NULL)
+ goto errfin;
+
+ if (ht1->h_addrtype != ht2->h_addrtype ||
+ ht1->h_length != ht2->h_length ||
+ strcmp(ht1->h_name, ht2->h_name) != 0)
+ goto errfin;
+
+ c1 = ht1->h_aliases;
+ c2 = ht2->h_aliases;
+
+ if ((ht1->h_aliases == NULL || ht2->h_aliases == NULL) &&
+ ht1->h_aliases != ht2->h_aliases)
+ goto errfin;
+
+ if (c1 != NULL && c2 != NULL) {
+ cb = c1;
+ for (;*c1; ++c1) {
+ b = 0;
+ for (ct = c2; *ct; ++ct) {
+ if (strcmp(*c1, *ct) == 0) {
+ b = 1;
+ break;
+ }
+ }
+ if (b == 0) {
+ printf("h1 aliases item can't be found in h2 "
+ "aliases\n");
+ goto errfin;
+ }
+ }
+
+ c1 = cb;
+ for (;*c2; ++c2) {
+ b = 0;
+ for (ct = c1; *ct; ++ct) {
+ if (strcmp(*c2, *ct) == 0) {
+ b = 1;
+ break;
+ }
+ }
+ if (b == 0) {
+ printf("h2 aliases item can't be found in h1 "
+ "aliases\n");
+ goto errfin;
+ }
+ }
+ }
+
+ c1 = ht1->h_addr_list;
+ c2 = ht2->h_addr_list;
+
+ if ((ht1->h_addr_list == NULL || ht2->h_addr_list== NULL) &&
+ ht1->h_addr_list != ht2->h_addr_list)
+ goto errfin;
+
+ if (c1 != NULL && c2 != NULL) {
+ cb = c1;
+ for (; *c1; ++c1) {
+ b = 0;
+ for (ct = c2; *ct; ++ct) {
+ if (memcmp(*c1, *ct, ht1->h_length) == 0) {
+ b = 1;
+ break;
+ }
+ }
+ if (b == 0) {
+ printf("h1 addresses item can't be found in "
+ "h2 addresses\n");
+ goto errfin;
+ }
+ }
+
+ c1 = cb;
+ for (; *c2; ++c2) {
+ b = 0;
+ for (ct = c1; *ct; ++ct) {
+ if (memcmp(*c2, *ct, ht1->h_length) == 0) {
+ b = 1;
+ break;
+ }
+ }
+ if (b == 0) {
+ printf("h2 addresses item can't be found in "
+ "h1 addresses\n");
+ goto errfin;
+ }
+ }
+ }
+
+ return 0;
+
+errfin:
+ if (mdata == NULL) {
+ printf("following structures are not equal:\n");
+ dump_hostent(ht1);
+ dump_hostent(ht2);
+ }
+
+ return (-1);
+}
+
+static int
+check_addrinfo_for_name(struct addrinfo *ai, char const *name)
+{
+ struct addrinfo *ai2;
+
+ for (ai2 = ai; ai2 != NULL; ai2 = ai2->ai_next) {
+ if (strcmp(ai2->ai_canonname, name) == 0)
+ return (0);
+ }
+
+ return (-1);
+}
+
+static int
+check_addrinfo_for_addr(struct addrinfo *ai, char const *addr,
+ socklen_t addrlen, int af)
+{
+ struct addrinfo *ai2;
+
+ for (ai2 = ai; ai2 != NULL; ai2 = ai2->ai_next) {
+ if (af != ai2->ai_family)
+ continue;
+
+ switch (af) {
+ case AF_INET:
+ if (memcmp(addr,
+ (void *)&((struct sockaddr_in *)ai2->ai_addr)->sin_addr,
+ MIN(addrlen, ai2->ai_addrlen)) == 0)
+ return (0);
+ break;
+ case AF_INET6:
+ if (memcmp(addr,
+ (void *)&((struct sockaddr_in6 *)ai2->ai_addr)->sin6_addr,
+ MIN(addrlen, ai2->ai_addrlen)) == 0)
+ return (0);
+ break;
+ default:
+ break;
+ }
+ }
+
+ return (-1);
+}
+
+static int
+is_hostent_equal(struct hostent *he, struct addrinfo *ai)
+{
+ char **cp;
+ int rv;
+
+#ifdef DEBUG
+ printf("checking equality of he and ai\n");
+#endif
+
+ rv = check_addrinfo_for_name(ai, he->h_name);
+ if (rv != 0) {
+ printf("not equal - he->h_name couldn't be found\n");
+ return (rv);
+ }
+
+ for (cp = he->h_addr_list; *cp; ++cp) {
+ rv = check_addrinfo_for_addr(ai, *cp, he->h_length,
+ he->h_addrtype);
+ if (rv != 0) {
+ printf("not equal - one of he->h_addr_list couldn't be found\n");
+ return (rv);
+ }
+ }
+
+#ifdef DEBUG
+ printf("equal\n");
+#endif
+
+ return (0);
+}
+
+static void
+sdump_hostent(struct hostent *ht, char *buffer, size_t buflen)
+{
+ char **cp;
+ size_t i;
+ int written;
+
+ written = snprintf(buffer, buflen, "%s %d %d",
+ ht->h_name, ht->h_addrtype, ht->h_length);
+ buffer += written;
+ if (written > buflen)
+ return;
+ buflen -= written;
+
+ if (ht->h_aliases != NULL) {
+ if (*(ht->h_aliases) != NULL) {
+ for (cp = ht->h_aliases; *cp; ++cp) {
+ written = snprintf(buffer, buflen, " %s",*cp);
+ buffer += written;
+ if (written > buflen)
+ return;
+ buflen -= written;
+
+ if (buflen == 0)
+ return;
+ }
+ } else {
+ written = snprintf(buffer, buflen, " noaliases");
+ buffer += written;
+ if (written > buflen)
+ return;
+ buflen -= written;
+ }
+ } else {
+ written = snprintf(buffer, buflen, " (null)");
+ buffer += written;
+ if (written > buflen)
+ return;
+ buflen -= written;
+ }
+
+ written = snprintf(buffer, buflen, " : ");
+ buffer += written;
+ if (written > buflen)
+ return;
+ buflen -= written;
+
+ if (ht->h_addr_list != NULL) {
+ if (*(ht->h_addr_list) != NULL) {
+ for (cp = ht->h_addr_list; *cp; ++cp) {
+ for (i = 0; i < ht->h_length; ++i ) {
+ written = snprintf(buffer, buflen,
+ i + 1 != ht->h_length ? "%d." : "%d",
+ (unsigned char)(*cp)[i]);
+ buffer += written;
+ if (written > buflen)
+ return;
+ buflen -= written;
+
+ if (buflen == 0)
+ return;
+ }
+
+ if (*(cp + 1) ) {
+ written = snprintf(buffer, buflen, " ");
+ buffer += written;
+ if (written > buflen)
+ return;
+ buflen -= written;
+ }
+ }
+ } else {
+ written = snprintf(buffer, buflen, " noaddrs");
+ buffer += written;
+ if (written > buflen)
+ return;
+ buflen -= written;
+ }
+ } else {
+ written = snprintf(buffer, buflen, " (null)");
+ buffer += written;
+ if (written > buflen)
+ return;
+ buflen -= written;
+ }
+}
+
+static int
+hostent_read_hostlist_func(struct hostent *he, char *line)
+{
+ struct hostent *result;
+ int rv;
+
+#ifdef DEBUG
+ printf("resolving %s: ", line);
+#endif
+ result = __gethostbyname2(line, af_type);
+ if (result != NULL) {
+#ifdef DEBUG
+ printf("found\n");
+#endif
+
+ rv = hostent_test_correctness(result, NULL);
+ if (rv != 0) {
+ __freehostent(result);
+ return (rv);
+ }
+
+ clone_hostent(he, result);
+ __freehostent(result);
+ } else {
+#ifdef DEBUG
+ printf("not found\n");
+#endif
+ memset(he, 0, sizeof(struct hostent));
+ he->h_name = strdup(line);
+ ATF_REQUIRE(he->h_name != NULL);
+ }
+ return (0);
+}
+
+static int
+hostent_read_snapshot_addr(char *addr, unsigned char *result, size_t len)
+{
+ char *s, *ps, *ts;
+
+ ps = addr;
+ while ( (s = strsep(&ps, ".")) != NULL) {
+ if (len == 0)
+ return (-1);
+
+ *result = (unsigned char)strtol(s, &ts, 10);
+ ++result;
+ if (*ts != '\0')
+ return (-1);
+
+ --len;
+ }
+ if (len != 0)
+ return (-1);
+ else
+ return (0);
+}
+
+static int
+hostent_read_snapshot_func(struct hostent *ht, char *line)
+{
+ StringList *sl1, *sl2;
+ char *s, *ps, *ts;
+ int i, rv;
+
+#ifdef DEBUG
+ printf("1 line read from snapshot:\n%s\n", line);
+#endif
+
+ rv = 0;
+ i = 0;
+ sl1 = sl2 = NULL;
+ ps = line;
+ memset(ht, 0, sizeof(struct hostent));
+ while ((s = strsep(&ps, " ")) != NULL) {
+ switch (i) {
+ case 0:
+ ht->h_name = strdup(s);
+ ATF_REQUIRE(ht->h_name != NULL);
+ break;
+
+ case 1:
+ ht->h_addrtype = (int)strtol(s, &ts, 10);
+ if (*ts != '\0')
+ goto fin;
+ break;
+
+ case 2:
+ ht->h_length = (int)strtol(s, &ts, 10);
+ if (*ts != '\0')
+ goto fin;
+ break;
+
+ case 3:
+ if (sl1 == NULL) {
+ if (strcmp(s, "(null)") == 0)
+ return (0);
+
+ sl1 = sl_init();
+ ATF_REQUIRE(sl1 != NULL);
+
+ if (strcmp(s, "noaliases") != 0) {
+ ts = strdup(s);
+ ATF_REQUIRE(ts != NULL);
+ sl_add(sl1, ts);
+ }
+ } else {
+ if (strcmp(s, ":") == 0)
+ ++i;
+ else {
+ ts = strdup(s);
+ ATF_REQUIRE(ts != NULL);
+ sl_add(sl1, ts);
+ }
+ }
+ break;
+
+ case 4:
+ if (sl2 == NULL) {
+ if (strcmp(s, "(null)") == 0)
+ return (0);
+
+ sl2 = sl_init();
+ ATF_REQUIRE(sl2 != NULL);
+
+ if (strcmp(s, "noaddrs") != 0) {
+ ts = calloc(1, ht->h_length);
+ ATF_REQUIRE(ts != NULL);
+ rv = hostent_read_snapshot_addr(s,
+ (unsigned char *)ts,
+ ht->h_length);
+ sl_add(sl2, ts);
+ if (rv != 0)
+ goto fin;
+ }
+ } else {
+ ts = calloc(1, ht->h_length);
+ ATF_REQUIRE(ts != NULL);
+ rv = hostent_read_snapshot_addr(s,
+ (unsigned char *)ts, ht->h_length);
+ sl_add(sl2, ts);
+ if (rv != 0)
+ goto fin;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (i != 3 && i != 4)
+ ++i;
+ }
+
+fin:
+ if (sl1 != NULL) {
+ sl_add(sl1, NULL);
+ ht->h_aliases = sl1->sl_str;
+ }
+ if (sl2 != NULL) {
+ sl_add(sl2, NULL);
+ ht->h_addr_list = sl2->sl_str;
+ }
+
+ if ((i != 4) || (rv != 0)) {
+ free_hostent(ht);
+ memset(ht, 0, sizeof(struct hostent));
+ return (-1);
+ }
+
+ /* NOTE: is it a dirty hack or not? */
+ free(sl1);
+ free(sl2);
+ return (0);
+}
+
+static void
+dump_hostent(struct hostent *result)
+{
+ if (result != NULL) {
+ char buffer[1024];
+ sdump_hostent(result, buffer, sizeof(buffer));
+ printf("%s\n", buffer);
+ } else
+ printf("(null)\n");
+}
+
+static int
+hostent_test_correctness(struct hostent *ht, void *mdata)
+{
+
+#ifdef DEBUG
+ printf("testing correctness with the following data:\n");
+ dump_hostent(ht);
+#endif
+
+ if (ht == NULL)
+ goto errfin;
+
+ if (ht->h_name == NULL)
+ goto errfin;
+
+ if (!((ht->h_addrtype >= 0) && (ht->h_addrtype < AF_MAX)))
+ goto errfin;
+
+ if ((ht->h_length != sizeof(struct in_addr)) &&
+ (ht->h_length != sizeof(struct in6_addr)))
+ goto errfin;
+
+ if (ht->h_aliases == NULL)
+ goto errfin;
+
+ if (ht->h_addr_list == NULL)
+ goto errfin;
+
+#ifdef DEBUG
+ printf("correct\n");
+#endif
+
+ return (0);
+errfin:
+ printf("incorrect\n");
+
+ return (-1);
+}
+
+static int
+hostent_test_gethostbyaddr(struct hostent *he, void *mdata)
+{
+ struct hostent *result;
+ struct hostent_test_data *addr_test_data;
+ int rv;
+
+ addr_test_data = (struct hostent_test_data *)mdata;
+
+ /* We should omit unresolved hostents */
+ if (he->h_addr_list != NULL) {
+ char **cp;
+ for (cp = he->h_addr_list; *cp; ++cp) {
+#ifdef DEBUG
+ printf("doing reverse lookup for %s\n", he->h_name);
+#endif
+
+ result = __gethostbyaddr(*cp, he->h_length,
+ he->h_addrtype);
+ if (result == NULL) {
+#ifdef DEBUG
+ printf("%s: warning: reverse lookup failed "
+ "for %s: %s\n", __func__, he->h_name,
+ strerror(errno));
+#endif
+ continue;
+ }
+ rv = hostent_test_correctness(result, NULL);
+ if (rv != 0) {
+ __freehostent(result);
+ return (rv);
+ }
+
+ if (addr_test_data != NULL)
+ TEST_DATA_APPEND(hostent, addr_test_data,
+ result);
+
+ __freehostent(result);
+ }
+ }
+
+ return (0);
+}
+
+static int
+hostent_test_getaddrinfo_eq(struct hostent *he, void *mdata)
+{
+ struct addrinfo *ai, hints;
+ int rv;
+
+ ai = NULL;
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = af_type;
+ hints.ai_flags = AI_CANONNAME;
+
+ printf("using getaddrinfo() to resolve %s\n", he->h_name);
+
+ /* struct hostent *he was not resolved */
+ if (he->h_addr_list == NULL) {
+ /* We can be sure that he->h_name is not NULL */
+ rv = getaddrinfo(he->h_name, NULL, &hints, &ai);
+ if (rv == 0) {
+ printf("not ok - shouldn't have been resolved\n");
+ return (-1);
+ }
+ } else {
+ rv = getaddrinfo(he->h_name, NULL, &hints, &ai);
+ if (rv != 0) {
+ printf("not ok - should have been resolved\n");
+ return (-1);
+ }
+
+ rv = is_hostent_equal(he, ai);
+ if (rv != 0) {
+ printf("not ok - addrinfo and hostent are not equal\n");
+ return (-1);
+ }
+
+ }
+
+ return (0);
+}
+
+static int
+hostent_test_getnameinfo_eq(struct hostent *he, void *mdata)
+{
+ char **cp;
+ char buffer[NI_MAXHOST];
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
+ struct sockaddr *saddr;
+ struct hostent *result;
+ int i, rv;
+
+ if (he->h_addr_list == NULL)
+ return (0);
+
+ for (cp = he->h_addr_list; *cp; ++cp) {
+#ifdef DEBUG
+ printf("doing reverse lookup for %s\n", he->h_name);
+#endif
+ result = __gethostbyaddr(*cp, he->h_length,
+ he->h_addrtype);
+ if (result != NULL) {
+ rv = hostent_test_correctness(result, NULL);
+ if (rv != 0) {
+ __freehostent(result);
+ return (rv);
+ }
+ } else
+ printf("%s: warning: reverse lookup failed "
+ "for %s: %s\n", __func__, he->h_name,
+ strerror(errno));
+
+ switch (he->h_addrtype) {
+ case AF_INET:
+ memset(&sin, 0, sizeof(struct sockaddr_in));
+ sin.sin_len = sizeof(struct sockaddr_in);
+ sin.sin_family = AF_INET;
+ memcpy(&sin.sin_addr, *cp, he->h_length);
+
+ saddr = (struct sockaddr *)&sin;
+ break;
+ case AF_INET6:
+ memset(&sin6, 0, sizeof(struct sockaddr_in6));
+ sin6.sin6_len = sizeof(struct sockaddr_in6);
+ sin6.sin6_family = AF_INET6;
+ memcpy(&sin6.sin6_addr, *cp, he->h_length);
+
+ saddr = (struct sockaddr *)&sin6;
+ break;
+ default:
+ printf("warning: %d family is unsupported\n",
+ he->h_addrtype);
+ continue;
+ }
+
+ ATF_REQUIRE(saddr != NULL);
+ rv = getnameinfo(saddr, saddr->sa_len, buffer,
+ sizeof(buffer), NULL, 0, NI_NAMEREQD);
+
+ if (rv != 0 && result != NULL) {
+ printf("getnameinfo() didn't make the reverse "
+ "lookup, when it should have (%s)\n",
+ gai_strerror(rv));
+ return (rv);
+ }
+
+ if (rv == 0 && result == NULL) {
+ printf("getnameinfo() made the "
+ "reverse lookup, when it shouldn't have\n");
+ return (rv);
+ }
+
+ if (rv != 0 && result == NULL) {
+#ifdef DEBUG
+ printf("both getnameinfo() and ***byaddr() failed as "
+ "expected\n");
+#endif
+ continue;
+ }
+
+#ifdef DEBUG
+ printf("comparing %s with %s\n", result->h_name,
+ buffer);
+#endif
+
+ /*
+ * An address might reverse resolve to hostname alias or the
+ * official hostname, e.g. moon.vub.ac.be.
+ */
+ bool found_a_match;
+
+ if (strcmp(result->h_name, buffer) == 0) {
+ found_a_match = true;
+#ifdef DEBUG
+ printf("matched official hostname\n");
+#endif
+ } else {
+ for (i = 0; result->h_aliases[i] != NULL; i++) {
+ printf("[%d] resolved: %s\n", i,
+ result->h_aliases[i]);
+ if (strcmp(result->h_aliases[i],
+ buffer) == 0) {
+ printf("matched hostname alias\n");
+ found_a_match = true;
+ break;
+ }
+ }
+ }
+ __freehostent(result);
+
+ if (found_a_match) {
+#ifdef DEBUG
+ printf("getnameinfo() and ***byaddr() results are "
+ "equal\n");
+#endif
+ } else {
+ printf("getnameinfo() and ***byaddr() results are not "
+ "equal for %s\n", he->h_name);
+ return (-1);
+ }
+ }
+
+ return (0);
+}
+
+int
+run_tests(const char *hostlist_file, const char *snapshot_file, int af_type,
+ enum test_methods method, bool use_ipv6_mapping)
+{
+ struct hostent_test_data td, td_addr, td_snap;
+ res_state statp;
+ int rv = -2;
+
+ switch (af_type) {
+ case AF_INET:
+ ATF_REQUIRE_FEATURE("inet");
+ ATF_REQUIRE(!use_ipv6_mapping);
+ break;
+ case AF_INET6:
+ ATF_REQUIRE_FEATURE("inet6");
+ break;
+ default:
+ atf_tc_fail("unhandled address family: %d", af_type);
+ break;
+ }
+
+ if (!use_ipnode_functions) {
+ statp = __res_state();
+ if (statp == NULL || ((statp->options & RES_INIT) == 0 &&
+ res_ninit(statp) == -1)) {
+ printf("error: can't init res_state\n");
+
+ return (-1);
+ }
+
+ if (use_ipv6_mapping)
+ statp->options |= RES_USE_INET6;
+ else
+ statp->options &= ~RES_USE_INET6;
+ }
+
+ TEST_DATA_INIT(hostent, &td, clone_hostent, free_hostent);
+ TEST_DATA_INIT(hostent, &td_addr, clone_hostent, free_hostent);
+ TEST_DATA_INIT(hostent, &td_snap, clone_hostent, free_hostent);
+
+ if (access(hostlist_file, R_OK) != 0) {
+ printf("can't access the hostlist file %s\n", hostlist_file);
+ rv = -1;
+ goto fin;
+ }
+
+#ifdef DEBUG
+ printf("building host lists from %s\n", hostlist_file);
+#endif
+
+ rv = TEST_SNAPSHOT_FILE_READ(hostent, hostlist_file, &td,
+ hostent_read_hostlist_func);
+ if (rv != 0) {
+ printf("failed to read the host list file: %s\n",
+ hostlist_file);
+ goto fin;
+ }
+
+ if (snapshot_file != NULL) {
+ if (access(snapshot_file, W_OK | R_OK) != 0) {
+ if (errno == ENOENT) {
+ if (method != TEST_GETHOSTBYADDR)
+ method = TEST_BUILD_SNAPSHOT;
+ else
+ method = TEST_BUILD_ADDR_SNAPSHOT;
+ } else {
+ printf("can't access the snapshot file %s\n",
+ snapshot_file);
+ rv = -1;
+ goto fin;
+ }
+ } else {
+ rv = TEST_SNAPSHOT_FILE_READ(hostent, snapshot_file,
+ &td_snap, hostent_read_snapshot_func);
+ if (rv != 0) {
+ printf("error reading snapshot file\n");
+ goto fin;
+ }
+ }
+ }
+
+ switch (method) {
+ case TEST_GETHOSTBYNAME2:
+ if (snapshot_file != NULL)
+ rv = DO_2PASS_TEST(hostent, &td, &td_snap,
+ compare_hostent, NULL);
+ break;
+ case TEST_GETHOSTBYADDR:
+ rv = DO_1PASS_TEST(hostent, &td,
+ hostent_test_gethostbyaddr, (void *)&td_addr);
+ if (rv != 0)
+ goto fin;
+
+ if (snapshot_file != NULL)
+ rv = DO_2PASS_TEST(hostent, &td_addr, &td_snap,
+ compare_hostent, NULL);
+ break;
+ case TEST_GETHOSTBYNAME2_GETADDRINFO:
+ rv = DO_1PASS_TEST(hostent, &td,
+ hostent_test_getaddrinfo_eq, NULL);
+ break;
+ case TEST_GETHOSTBYADDR_GETNAMEINFO:
+ rv = DO_1PASS_TEST(hostent, &td,
+ hostent_test_getnameinfo_eq, NULL);
+ break;
+ case TEST_BUILD_SNAPSHOT:
+ if (snapshot_file != NULL) {
+ rv = TEST_SNAPSHOT_FILE_WRITE(hostent, snapshot_file,
+ &td, sdump_hostent);
+ }
+ break;
+ case TEST_BUILD_ADDR_SNAPSHOT:
+ if (snapshot_file != NULL) {
+ rv = DO_1PASS_TEST(hostent, &td,
+ hostent_test_gethostbyaddr, (void *)&td_addr);
+ if (rv != 0)
+ goto fin;
+ rv = TEST_SNAPSHOT_FILE_WRITE(hostent, snapshot_file,
+ &td_addr, sdump_hostent);
+ }
+ break;
+ default:
+ rv = 0;
+ break;
+ }
+
+fin:
+ TEST_DATA_DESTROY(hostent, &td_snap);
+ TEST_DATA_DESTROY(hostent, &td_addr);
+ TEST_DATA_DESTROY(hostent, &td);
+
+ return (rv);
+}
+
+#define HOSTLIST_FILE "mach"
+
+#define _RUN_TESTS(tc, snapshot_file, af_type, method, use_ipv6_mapping) \
+do { \
+ char *_hostlist_file; \
+ char *_snapshot_file; \
+ ATF_REQUIRE(0 < asprintf(&_hostlist_file, "%s/%s", \
+ atf_tc_get_config_var(tc, "srcdir"), HOSTLIST_FILE)); \
+ if (snapshot_file == NULL) \
+ _snapshot_file = NULL; \
+ else { \
+ _snapshot_file = strdup(snapshot_file); \
+ ATF_REQUIRE(_snapshot_file != NULL); \
+ } \
+ ATF_REQUIRE(run_tests(_hostlist_file, _snapshot_file, af_type, \
+ method, use_ipv6_mapping) == 0); \
+} while(0)
+
+#define RUN_HOST_TESTS(tc, snapshot_file, af_type, method, use_ipv6_mapping) \
+do { \
+ use_ipnode_functions = false; \
+ _RUN_TESTS(tc, snapshot_file, af_type, method, use_ipv6_mapping); \
+} while(0)
+
+#define RUN_IPNODE_TESTS(tc, snapshot_file, af_type, method, use_ipv6_mapping) \
+do { \
+ use_ipnode_functions = true; \
+ _RUN_TESTS(tc, snapshot_file, af_type, method, use_ipv6_mapping); \
+} while(0)
+
+ATF_TC_WITHOUT_HEAD(gethostbyaddr_ipv4);
+ATF_TC_BODY(gethostbyaddr_ipv4, tc)
+{
+
+ RUN_HOST_TESTS(tc, NULL, AF_INET, TEST_GETHOSTBYADDR, false);
+}
+
+ATF_TC_WITHOUT_HEAD(gethostbyaddr_ipv4_with_snapshot);
+ATF_TC_BODY(gethostbyaddr_ipv4_with_snapshot, tc)
+{
+
+ RUN_HOST_TESTS(tc, "snapshot_htaddr4", AF_INET, TEST_GETHOSTBYADDR, false);
+}
+
+ATF_TC_WITHOUT_HEAD(gethostbyaddr_ipv6);
+ATF_TC_BODY(gethostbyaddr_ipv6, tc)
+{
+
+ RUN_HOST_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYADDR, false);
+}
+
+ATF_TC_WITHOUT_HEAD(gethostbyaddr_ipv6_AI_V4MAPPED);
+ATF_TC_BODY(gethostbyaddr_ipv6_AI_V4MAPPED, tc)
+{
+
+ ipnode_flags = AI_V4MAPPED;
+ RUN_HOST_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYADDR, true);
+}
+
+ATF_TC_WITHOUT_HEAD(gethostbyaddr_ipv6_with_snapshot);
+ATF_TC_BODY(gethostbyaddr_ipv6_with_snapshot, tc)
+{
+
+ RUN_HOST_TESTS(tc, "snapshot_htaddr6", AF_INET6, TEST_GETHOSTBYADDR, false);
+}
+
+ATF_TC_WITHOUT_HEAD(gethostbyaddr_ipv6_with_snapshot_AI_V4MAPPED);
+ATF_TC_BODY(gethostbyaddr_ipv6_with_snapshot_AI_V4MAPPED, tc)
+{
+
+ ipnode_flags = AI_V4MAPPED;
+ RUN_HOST_TESTS(tc, "snapshot_htaddr6map", AF_INET6, TEST_GETHOSTBYADDR, true);
+}
+
+ATF_TC_WITHOUT_HEAD(gethostbyname2_getaddrinfo_ipv4);
+ATF_TC_BODY(gethostbyname2_getaddrinfo_ipv4, tc)
+{
+
+ RUN_HOST_TESTS(tc, NULL, AF_INET, TEST_GETHOSTBYNAME2_GETADDRINFO, false);
+}
+
+ATF_TC_WITHOUT_HEAD(gethostbyname2_getaddrinfo_ipv6);
+ATF_TC_BODY(gethostbyname2_getaddrinfo_ipv6, tc)
+{
+
+ RUN_HOST_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYNAME2_GETADDRINFO, false);
+}
+
+ATF_TC_WITHOUT_HEAD(gethostbyaddr_getnameinfo_ipv4);
+ATF_TC_BODY(gethostbyaddr_getnameinfo_ipv4, tc)
+{
+
+ RUN_HOST_TESTS(tc, NULL, AF_INET, TEST_GETHOSTBYADDR_GETNAMEINFO, false);
+}
+
+ATF_TC_WITHOUT_HEAD(gethostbyaddr_getnameinfo_ipv6);
+ATF_TC_BODY(gethostbyaddr_getnameinfo_ipv6, tc)
+{
+
+ RUN_HOST_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYADDR_GETNAMEINFO, false);
+}
+
+ATF_TC_WITHOUT_HEAD(gethostbyname2_ipv4);
+ATF_TC_BODY(gethostbyname2_ipv4, tc)
+{
+
+ RUN_HOST_TESTS(tc, NULL, AF_INET, TEST_GETHOSTBYNAME2, false);
+}
+
+ATF_TC_WITHOUT_HEAD(gethostbyname2_ipv4_with_snapshot);
+ATF_TC_BODY(gethostbyname2_ipv4_with_snapshot, tc)
+{
+
+ RUN_HOST_TESTS(tc, "snapshot_htname4", AF_INET, TEST_GETHOSTBYNAME2, false);
+}
+
+ATF_TC_WITHOUT_HEAD(gethostbyname2_ipv6);
+ATF_TC_BODY(gethostbyname2_ipv6, tc)
+{
+
+ RUN_HOST_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYNAME2, false);
+}
+
+ATF_TC_WITHOUT_HEAD(gethostbyname2_ipv6_AI_V4MAPPED);
+ATF_TC_BODY(gethostbyname2_ipv6_AI_V4MAPPED, tc)
+{
+
+ ipnode_flags = AI_V4MAPPED;
+ RUN_HOST_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYNAME2, true);
+}
+
+ATF_TC_WITHOUT_HEAD(gethostbyname2_ipv6_with_snapshot);
+ATF_TC_BODY(gethostbyname2_ipv6_with_snapshot, tc)
+{
+
+ RUN_HOST_TESTS(tc, "snapshot_htname6", AF_INET6, TEST_GETHOSTBYNAME2, false);
+}
+
+ATF_TC_WITHOUT_HEAD(gethostbyname2_ipv6_with_snapshot_AI_V4MAPPED);
+ATF_TC_BODY(gethostbyname2_ipv6_with_snapshot_AI_V4MAPPED, tc)
+{
+
+ ipnode_flags = AI_V4MAPPED;
+ RUN_HOST_TESTS(tc, "snapshot_htname6map", AF_INET6, TEST_GETHOSTBYNAME2, true);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyaddr_ipv4);
+ATF_TC_BODY(getipnodebyaddr_ipv4, tc)
+{
+
+ RUN_IPNODE_TESTS(tc, NULL, AF_INET, TEST_GETHOSTBYADDR, false);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyaddr_ipv4_with_snapshot);
+ATF_TC_BODY(getipnodebyaddr_ipv4_with_snapshot, tc)
+{
+
+ RUN_IPNODE_TESTS(tc, "snapshot_ipnodeaddr4", AF_INET, TEST_GETHOSTBYADDR, false);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyaddr_getnameinfo_ipv4);
+ATF_TC_BODY(getipnodebyaddr_getnameinfo_ipv4, tc)
+{
+
+ RUN_IPNODE_TESTS(tc, NULL, AF_INET, TEST_GETHOSTBYADDR_GETNAMEINFO, false);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyaddr_ipv6);
+ATF_TC_BODY(getipnodebyaddr_ipv6, tc)
+{
+
+ RUN_IPNODE_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYADDR, false);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyaddr_ipv6_AI_V4MAPPED);
+ATF_TC_BODY(getipnodebyaddr_ipv6_AI_V4MAPPED, tc)
+{
+
+ ipnode_flags = AI_V4MAPPED;
+ RUN_IPNODE_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYADDR, true);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyaddr_ipv6_AI_V4MAPPED_CFG);
+ATF_TC_BODY(getipnodebyaddr_ipv6_AI_V4MAPPED_CFG, tc)
+{
+
+ ipnode_flags = AI_V4MAPPED_CFG;
+ RUN_IPNODE_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYADDR, true);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyaddr_ipv6_AI_V4MAPPED_CFG_AI_ALL);
+ATF_TC_BODY(getipnodebyaddr_ipv6_AI_V4MAPPED_CFG_AI_ALL, tc)
+{
+
+ ipnode_flags = AI_V4MAPPED_CFG | AI_ALL;
+ RUN_IPNODE_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYADDR, true);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyaddr_ipv6_with_snapshot);
+ATF_TC_BODY(getipnodebyaddr_ipv6_with_snapshot, tc)
+{
+
+ RUN_IPNODE_TESTS(tc, "snapshot_ipnodeaddr6", AF_INET6, TEST_GETHOSTBYADDR, false);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyaddr_ipv6_with_snapshot_AI_V4MAPPED);
+ATF_TC_BODY(getipnodebyaddr_ipv6_with_snapshot_AI_V4MAPPED, tc)
+{
+
+ ipnode_flags = AI_V4MAPPED;
+ RUN_IPNODE_TESTS(tc,
+ "snapshot_ipnodeaddr6_AI_V4MAPPED", AF_INET6,
+ TEST_GETHOSTBYADDR, true);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyaddr_ipv6_with_snapshot_AI_V4MAPPED_CFG);
+ATF_TC_BODY(getipnodebyaddr_ipv6_with_snapshot_AI_V4MAPPED_CFG, tc)
+{
+
+ ipnode_flags = AI_V4MAPPED_CFG;
+ RUN_IPNODE_TESTS(tc,
+ "snapshot_ipnodeaddr6_AI_V4MAPPED_CFG", AF_INET6,
+ TEST_GETHOSTBYADDR, true);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyaddr_ipv6_with_snapshot_AI_V4MAPPED_CFG_AI_ALL);
+ATF_TC_BODY(getipnodebyaddr_ipv6_with_snapshot_AI_V4MAPPED_CFG_AI_ALL, tc)
+{
+
+ ipnode_flags = AI_V4MAPPED_CFG | AI_ALL;
+ RUN_IPNODE_TESTS(tc,
+ "snapshot_ipnodeaddr6_AI_V4MAPPED_CFG_AI_ALL", AF_INET6,
+ TEST_GETHOSTBYADDR, true);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyaddr_getnameinfo_ipv6);
+ATF_TC_BODY(getipnodebyaddr_getnameinfo_ipv6, tc)
+{
+
+ RUN_IPNODE_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYADDR_GETNAMEINFO, false);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv4);
+ATF_TC_BODY(getipnodebyname_ipv4, tc)
+{
+
+ RUN_IPNODE_TESTS(tc, NULL, AF_INET, TEST_GETHOSTBYNAME2, false);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv4_with_snapshot);
+ATF_TC_BODY(getipnodebyname_ipv4_with_snapshot, tc)
+{
+
+ RUN_IPNODE_TESTS(tc, "snapshot_ipnodename4", AF_INET, TEST_GETHOSTBYNAME2, false);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv4_AI_ADDRCONFIG);
+ATF_TC_BODY(getipnodebyname_ipv4_AI_ADDRCONFIG, tc)
+{
+
+ ipnode_flags = AI_ADDRCONFIG;
+ RUN_IPNODE_TESTS(tc, NULL, AF_INET, TEST_GETHOSTBYNAME2, false);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv4_with_snapshot_AI_ADDRCONFIG);
+ATF_TC_BODY(getipnodebyname_ipv4_with_snapshot_AI_ADDRCONFIG, tc)
+{
+
+ ipnode_flags = AI_ADDRCONFIG;
+ RUN_IPNODE_TESTS(tc, "snapshot_ipnodename4_AI_ADDRCONFIG", AF_INET,
+ TEST_GETHOSTBYNAME2, false);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyname_getaddrinfo_ipv4);
+ATF_TC_BODY(getipnodebyname_getaddrinfo_ipv4, tc)
+{
+
+ RUN_IPNODE_TESTS(tc, NULL, AF_INET, TEST_GETHOSTBYNAME2_GETADDRINFO, false);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv6);
+ATF_TC_BODY(getipnodebyname_ipv6, tc)
+{
+
+ RUN_IPNODE_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYNAME2, false);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv6_with_snapshot);
+ATF_TC_BODY(getipnodebyname_ipv6_with_snapshot, tc)
+{
+
+ RUN_IPNODE_TESTS(tc, "snapshot_ipnodename6", AF_INET6, TEST_GETHOSTBYNAME2, false);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv6_AI_ADDRCONFIG);
+ATF_TC_BODY(getipnodebyname_ipv6_AI_ADDRCONFIG, tc)
+{
+
+ ipnode_flags = AI_ADDRCONFIG;
+ RUN_IPNODE_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYNAME2, false);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv6_AI_V4MAPPED);
+ATF_TC_BODY(getipnodebyname_ipv6_AI_V4MAPPED, tc)
+{
+
+ ipnode_flags = AI_V4MAPPED;
+ RUN_IPNODE_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYNAME2, true);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv6_AI_V4MAPPED_CFG);
+ATF_TC_BODY(getipnodebyname_ipv6_AI_V4MAPPED_CFG, tc)
+{
+
+ ipnode_flags = AI_V4MAPPED_CFG;
+ RUN_IPNODE_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYNAME2, true);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv6_AI_V4MAPPED_CFG_AI_ADDRCONFIG);
+ATF_TC_BODY(getipnodebyname_ipv6_AI_V4MAPPED_CFG_AI_ADDRCONFIG, tc)
+{
+
+ ipnode_flags = AI_V4MAPPED_CFG | AI_ADDRCONFIG;
+ RUN_IPNODE_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYNAME2, false);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv6_AI_V4MAPPED_CFG_AI_ALL);
+ATF_TC_BODY(getipnodebyname_ipv6_AI_V4MAPPED_CFG_AI_ALL, tc)
+{
+
+ ipnode_flags = AI_V4MAPPED_CFG | AI_ALL;
+ RUN_IPNODE_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYNAME2, true);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv6_with_snapshot_AI_V4MAPPED);
+ATF_TC_BODY(getipnodebyname_ipv6_with_snapshot_AI_V4MAPPED, tc)
+{
+
+ ipnode_flags = AI_V4MAPPED;
+ RUN_IPNODE_TESTS(tc,
+ "snapshot_ipnodename6_AI_V4MAPPED", AF_INET6,
+ TEST_GETHOSTBYNAME2, true);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv6_with_snapshot_AI_V4MAPPED_CFG);
+ATF_TC_BODY(getipnodebyname_ipv6_with_snapshot_AI_V4MAPPED_CFG, tc)
+{
+
+ ipnode_flags = AI_V4MAPPED_CFG;
+ RUN_IPNODE_TESTS(tc,
+ "snapshot_ipnodename6_AI_V4MAPPED_CFG", AF_INET6,
+ TEST_GETHOSTBYNAME2, true);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv6_with_snapshot_AI_V4MAPPED_CFG_AI_ADDRCONFIG);
+ATF_TC_BODY(getipnodebyname_ipv6_with_snapshot_AI_V4MAPPED_CFG_AI_ADDRCONFIG, tc)
+{
+
+ ipnode_flags = AI_V4MAPPED_CFG | AI_ADDRCONFIG;
+ RUN_IPNODE_TESTS(tc,
+ "snapshot_ipnodename6_AI_V4MAPPED_CFG_AI_ADDRCONFIG", AF_INET6,
+ TEST_GETHOSTBYNAME2, false);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv6_with_snapshot_AI_V4MAPPED_CFG_AI_ALL);
+ATF_TC_BODY(getipnodebyname_ipv6_with_snapshot_AI_V4MAPPED_CFG_AI_ALL, tc)
+{
+
+ ipnode_flags = AI_V4MAPPED_CFG | AI_ALL;
+ RUN_IPNODE_TESTS(tc,
+ "snapshot_ipnodename6_AI_V4MAPPED_CFG_AI_ALL", AF_INET6,
+ TEST_GETHOSTBYNAME2, true);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv6_with_snapshot_AI_ADDRCONFIG);
+ATF_TC_BODY(getipnodebyname_ipv6_with_snapshot_AI_ADDRCONFIG, tc)
+{
+
+ ipnode_flags = AI_ADDRCONFIG;
+ RUN_IPNODE_TESTS(tc, "snapshot_ipnodename6_AI_ADDRCONFIG", AF_INET6,
+ TEST_GETHOSTBYNAME2, false);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyname_getaddrinfo_ipv6);
+ATF_TC_BODY(getipnodebyname_getaddrinfo_ipv6, tc)
+{
+
+ RUN_IPNODE_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYNAME2_GETADDRINFO, false);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ /* gethostbyaddr */
+ ATF_TP_ADD_TC(tp, gethostbyaddr_ipv4);
+ ATF_TP_ADD_TC(tp, gethostbyaddr_ipv4_with_snapshot);
+ ATF_TP_ADD_TC(tp, gethostbyaddr_ipv6);
+ ATF_TP_ADD_TC(tp, gethostbyaddr_ipv6_AI_V4MAPPED); /* XXX */
+ ATF_TP_ADD_TC(tp, gethostbyaddr_ipv6_with_snapshot);
+ ATF_TP_ADD_TC(tp, gethostbyaddr_ipv6_with_snapshot_AI_V4MAPPED);
+ ATF_TP_ADD_TC(tp, gethostbyaddr_getnameinfo_ipv4);
+ ATF_TP_ADD_TC(tp, gethostbyaddr_getnameinfo_ipv6);
+
+ /* gethostbyname2 */
+ ATF_TP_ADD_TC(tp, gethostbyname2_getaddrinfo_ipv4);
+ ATF_TP_ADD_TC(tp, gethostbyname2_getaddrinfo_ipv6);
+ ATF_TP_ADD_TC(tp, gethostbyname2_ipv4);
+ ATF_TP_ADD_TC(tp, gethostbyname2_ipv4_with_snapshot);
+ ATF_TP_ADD_TC(tp, gethostbyname2_ipv6);
+ ATF_TP_ADD_TC(tp, gethostbyname2_ipv6_AI_V4MAPPED);
+ ATF_TP_ADD_TC(tp, gethostbyname2_ipv6_with_snapshot);
+ ATF_TP_ADD_TC(tp, gethostbyname2_ipv6_with_snapshot_AI_V4MAPPED);
+
+ /* getipnodebyaddr */
+ ATF_TP_ADD_TC(tp, getipnodebyaddr_ipv4);
+ ATF_TP_ADD_TC(tp, getipnodebyaddr_ipv4_with_snapshot);
+ ATF_TP_ADD_TC(tp, getipnodebyaddr_getnameinfo_ipv4);
+ ATF_TP_ADD_TC(tp, getipnodebyaddr_ipv6);
+ ATF_TP_ADD_TC(tp, getipnodebyaddr_ipv6_AI_V4MAPPED);
+ ATF_TP_ADD_TC(tp, getipnodebyaddr_ipv6_AI_V4MAPPED_CFG);
+ ATF_TP_ADD_TC(tp, getipnodebyaddr_ipv6_AI_V4MAPPED_CFG_AI_ALL);
+ ATF_TP_ADD_TC(tp, getipnodebyaddr_ipv6_with_snapshot);
+ ATF_TP_ADD_TC(tp, getipnodebyaddr_ipv6_with_snapshot_AI_V4MAPPED);
+ ATF_TP_ADD_TC(tp, getipnodebyaddr_ipv6_with_snapshot_AI_V4MAPPED_CFG);
+ ATF_TP_ADD_TC(tp, getipnodebyaddr_ipv6_with_snapshot_AI_V4MAPPED_CFG_AI_ALL);
+ ATF_TP_ADD_TC(tp, getipnodebyaddr_getnameinfo_ipv6);
+
+ /* getipnodebyname */
+ ATF_TP_ADD_TC(tp, getipnodebyname_ipv4);
+ ATF_TP_ADD_TC(tp, getipnodebyname_ipv4_with_snapshot);
+ ATF_TP_ADD_TC(tp, getipnodebyname_ipv4_AI_ADDRCONFIG);
+ ATF_TP_ADD_TC(tp, getipnodebyname_ipv4_with_snapshot_AI_ADDRCONFIG);
+ ATF_TP_ADD_TC(tp, getipnodebyname_getaddrinfo_ipv4);
+ ATF_TP_ADD_TC(tp, getipnodebyname_ipv6);
+ ATF_TP_ADD_TC(tp, getipnodebyname_ipv6_with_snapshot);
+ ATF_TP_ADD_TC(tp, getipnodebyname_ipv6_AI_ADDRCONFIG);
+ ATF_TP_ADD_TC(tp, getipnodebyname_ipv6_AI_V4MAPPED);
+ ATF_TP_ADD_TC(tp, getipnodebyname_ipv6_AI_V4MAPPED_CFG);
+ ATF_TP_ADD_TC(tp, getipnodebyname_ipv6_AI_V4MAPPED_CFG_AI_ADDRCONFIG);
+ ATF_TP_ADD_TC(tp, getipnodebyname_ipv6_AI_V4MAPPED_CFG_AI_ALL);
+ ATF_TP_ADD_TC(tp, getipnodebyname_ipv6_with_snapshot_AI_V4MAPPED);
+ ATF_TP_ADD_TC(tp, getipnodebyname_ipv6_with_snapshot_AI_V4MAPPED_CFG);
+ ATF_TP_ADD_TC(tp, getipnodebyname_ipv6_with_snapshot_AI_V4MAPPED_CFG_AI_ADDRCONFIG);
+ ATF_TP_ADD_TC(tp, getipnodebyname_ipv6_with_snapshot_AI_V4MAPPED_CFG_AI_ALL);
+ ATF_TP_ADD_TC(tp, getipnodebyname_ipv6_with_snapshot_AI_ADDRCONFIG);
+ ATF_TP_ADD_TC(tp, getipnodebyname_getaddrinfo_ipv6);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/nss/getproto_test.c b/lib/libc/tests/nss/getproto_test.c
new file mode 100644
index 000000000000..5ae855542f9e
--- /dev/null
+++ b/lib/libc/tests/nss/getproto_test.c
@@ -0,0 +1,556 @@
+/*-
+ * Copyright (c) 2006 Michael Bushkov <bushman@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <arpa/inet.h>
+#include <assert.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stringlist.h>
+#include <unistd.h>
+
+#include <atf-c.h>
+
+#include "testutil.h"
+
+enum test_methods {
+ TEST_GETPROTOENT,
+ TEST_GETPROTOBYNAME,
+ TEST_GETPROTOBYNUMBER,
+ TEST_GETPROTOENT_2PASS,
+ TEST_BUILD_SNAPSHOT
+};
+
+DECLARE_TEST_DATA(protoent)
+DECLARE_TEST_FILE_SNAPSHOT(protoent)
+DECLARE_1PASS_TEST(protoent)
+DECLARE_2PASS_TEST(protoent)
+
+static void clone_protoent(struct protoent *, struct protoent const *);
+static int compare_protoent(struct protoent *, struct protoent *, void *);
+static void dump_protoent(struct protoent *);
+static void free_protoent(struct protoent *);
+
+static void sdump_protoent(struct protoent *, char *, size_t);
+static int protoent_read_snapshot_func(struct protoent *, char *);
+
+static int protoent_check_ambiguity(struct protoent_test_data *,
+ struct protoent *);
+static int protoent_fill_test_data(struct protoent_test_data *);
+static int protoent_test_correctness(struct protoent *, void *);
+static int protoent_test_getprotobyname(struct protoent *, void *);
+static int protoent_test_getprotobynumber(struct protoent *, void *);
+static int protoent_test_getprotoent(struct protoent *, void *);
+
+IMPLEMENT_TEST_DATA(protoent)
+IMPLEMENT_TEST_FILE_SNAPSHOT(protoent)
+IMPLEMENT_1PASS_TEST(protoent)
+IMPLEMENT_2PASS_TEST(protoent)
+
+static void
+clone_protoent(struct protoent *dest, struct protoent const *src)
+{
+ assert(dest != NULL);
+ assert(src != NULL);
+
+ char **cp;
+ int aliases_num;
+
+ memset(dest, 0, sizeof(struct protoent));
+
+ if (src->p_name != NULL) {
+ dest->p_name = strdup(src->p_name);
+ assert(dest->p_name != NULL);
+ }
+
+ dest->p_proto = src->p_proto;
+
+ if (src->p_aliases != NULL) {
+ aliases_num = 0;
+ for (cp = src->p_aliases; *cp; ++cp)
+ ++aliases_num;
+
+ dest->p_aliases = calloc(1, (aliases_num+1) * sizeof(char *));
+ assert(dest->p_aliases != NULL);
+
+ for (cp = src->p_aliases; *cp; ++cp) {
+ dest->p_aliases[cp - src->p_aliases] = strdup(*cp);
+ assert(dest->p_aliases[cp - src->p_aliases] != NULL);
+ }
+ }
+}
+
+static void
+free_protoent(struct protoent *pe)
+{
+ char **cp;
+
+ assert(pe != NULL);
+
+ free(pe->p_name);
+
+ for (cp = pe->p_aliases; *cp; ++cp)
+ free(*cp);
+ free(pe->p_aliases);
+}
+
+static int
+compare_protoent(struct protoent *pe1, struct protoent *pe2, void *mdata)
+{
+ char **c1, **c2;
+
+ if (pe1 == pe2)
+ return 0;
+
+ if ((pe1 == NULL) || (pe2 == NULL))
+ goto errfin;
+
+ if ((strcmp(pe1->p_name, pe2->p_name) != 0) ||
+ (pe1->p_proto != pe2->p_proto))
+ goto errfin;
+
+ c1 = pe1->p_aliases;
+ c2 = pe2->p_aliases;
+
+ if ((pe1->p_aliases == NULL) || (pe2->p_aliases == NULL))
+ goto errfin;
+
+ for (;*c1 && *c2; ++c1, ++c2)
+ if (strcmp(*c1, *c2) != 0)
+ goto errfin;
+
+ if ((*c1 != '\0') || (*c2 != '\0'))
+ goto errfin;
+
+ return 0;
+
+errfin:
+ if (mdata == NULL) {
+ printf("following structures are not equal:\n");
+ dump_protoent(pe1);
+ dump_protoent(pe2);
+ }
+
+ return (-1);
+}
+
+static void
+sdump_protoent(struct protoent *pe, char *buffer, size_t buflen)
+{
+ char **cp;
+ int written;
+
+ written = snprintf(buffer, buflen, "%s %d",
+ pe->p_name, pe->p_proto);
+ buffer += written;
+ if (written > buflen)
+ return;
+ buflen -= written;
+
+ if (pe->p_aliases != NULL) {
+ if (*(pe->p_aliases) != '\0') {
+ for (cp = pe->p_aliases; *cp; ++cp) {
+ written = snprintf(buffer, buflen, " %s",*cp);
+ buffer += written;
+ if (written > buflen)
+ return;
+ buflen -= written;
+
+ if (buflen == 0)
+ return;
+ }
+ } else
+ snprintf(buffer, buflen, " noaliases");
+ } else
+ snprintf(buffer, buflen, " (null)");
+}
+
+static int
+protoent_read_snapshot_func(struct protoent *pe, char *line)
+{
+ StringList *sl;
+ char *s, *ps, *ts;
+ int i;
+
+ printf("1 line read from snapshot:\n%s\n", line);
+
+ i = 0;
+ sl = NULL;
+ ps = line;
+ memset(pe, 0, sizeof(struct protoent));
+ while ( (s = strsep(&ps, " ")) != NULL) {
+ switch (i) {
+ case 0:
+ pe->p_name = strdup(s);
+ assert(pe->p_name != NULL);
+ break;
+
+ case 1:
+ pe->p_proto = (int)strtol(s, &ts, 10);
+ if (*ts != '\0') {
+ free(pe->p_name);
+ return (-1);
+ }
+ break;
+
+ default:
+ if (sl == NULL) {
+ if (strcmp(s, "(null)") == 0)
+ return (0);
+
+ sl = sl_init();
+ assert(sl != NULL);
+
+ if (strcmp(s, "noaliases") != 0) {
+ ts = strdup(s);
+ assert(ts != NULL);
+ sl_add(sl, ts);
+ }
+ } else {
+ ts = strdup(s);
+ assert(ts != NULL);
+ sl_add(sl, ts);
+ }
+ break;
+ }
+ ++i;
+ }
+
+ if (i < 3) {
+ free(pe->p_name);
+ memset(pe, 0, sizeof(struct protoent));
+ return (-1);
+ }
+
+ sl_add(sl, NULL);
+ pe->p_aliases = sl->sl_str;
+
+ /* NOTE: is it a dirty hack or not? */
+ free(sl);
+ return (0);
+}
+
+static void
+dump_protoent(struct protoent *result)
+{
+ if (result != NULL) {
+ char buffer[1024];
+ sdump_protoent(result, buffer, sizeof(buffer));
+ printf("%s\n", buffer);
+ } else
+ printf("(null)\n");
+}
+
+static int
+protoent_fill_test_data(struct protoent_test_data *td)
+{
+ struct protoent *pe;
+
+ setprotoent(1);
+ while ((pe = getprotoent()) != NULL) {
+ if (protoent_test_correctness(pe, NULL) == 0)
+ TEST_DATA_APPEND(protoent, td, pe);
+ else
+ return (-1);
+ }
+ endprotoent();
+
+ return (0);
+}
+
+static int
+protoent_test_correctness(struct protoent *pe, void *mdata)
+{
+ printf("testing correctness with the following data:\n");
+ dump_protoent(pe);
+
+ if (pe == NULL)
+ goto errfin;
+
+ if (pe->p_name == NULL)
+ goto errfin;
+
+ if (pe->p_proto < 0)
+ goto errfin;
+
+ if (pe->p_aliases == NULL)
+ goto errfin;
+
+ printf("correct\n");
+
+ return (0);
+errfin:
+ printf("incorrect\n");
+
+ return (-1);
+}
+
+/* protoent_check_ambiguity() is needed when one port+proto is associated with
+ * more than one piece (these cases are usually marked as PROBLEM in
+ * /etc/peices. This functions is needed also when one piece+proto is
+ * associated with several ports. We have to check all the protoent structures
+ * to make sure that pe really exists and correct */
+static int
+protoent_check_ambiguity(struct protoent_test_data *td, struct protoent *pe)
+{
+
+ return (TEST_DATA_FIND(protoent, td, pe, compare_protoent,
+ NULL) != NULL ? 0 : -1);
+}
+
+static int
+protoent_test_getprotobyname(struct protoent *pe_model, void *mdata)
+{
+ char **alias;
+ struct protoent *pe;
+
+ printf("testing getprotobyname() with the following data:\n");
+ dump_protoent(pe_model);
+
+ pe = getprotobyname(pe_model->p_name);
+ if (protoent_test_correctness(pe, NULL) != 0)
+ goto errfin;
+
+ if ((compare_protoent(pe, pe_model, NULL) != 0) &&
+ (protoent_check_ambiguity((struct protoent_test_data *)mdata, pe)
+ !=0))
+ goto errfin;
+
+ for (alias = pe_model->p_aliases; *alias; ++alias) {
+ pe = getprotobyname(*alias);
+
+ if (protoent_test_correctness(pe, NULL) != 0)
+ goto errfin;
+
+ if ((compare_protoent(pe, pe_model, NULL) != 0) &&
+ (protoent_check_ambiguity(
+ (struct protoent_test_data *)mdata, pe) != 0))
+ goto errfin;
+ }
+
+ printf("ok\n");
+ return (0);
+
+errfin:
+ printf("not ok\n");
+
+ return (-1);
+}
+
+static int
+protoent_test_getprotobynumber(struct protoent *pe_model, void *mdata)
+{
+ struct protoent *pe;
+
+ printf("testing getprotobyport() with the following data...\n");
+ dump_protoent(pe_model);
+
+ pe = getprotobynumber(pe_model->p_proto);
+ if ((protoent_test_correctness(pe, NULL) != 0) ||
+ ((compare_protoent(pe, pe_model, NULL) != 0) &&
+ (protoent_check_ambiguity((struct protoent_test_data *)mdata, pe)
+ != 0))) {
+ printf("not ok\n");
+ return (-1);
+ } else {
+ printf("ok\n");
+ return (0);
+ }
+}
+
+static int
+protoent_test_getprotoent(struct protoent *pe, void *mdata)
+{
+ /* Only correctness can be checked when doing 1-pass test for
+ * getprotoent(). */
+ return (protoent_test_correctness(pe, NULL));
+}
+
+int
+run_tests(const char *snapshot_file, enum test_methods method)
+{
+ struct protoent_test_data td, td_snap, td_2pass;
+ int rv;
+
+ TEST_DATA_INIT(protoent, &td, clone_protoent, free_protoent);
+ TEST_DATA_INIT(protoent, &td_snap, clone_protoent, free_protoent);
+ if (snapshot_file != NULL) {
+ if (access(snapshot_file, W_OK | R_OK) != 0) {
+ if (errno == ENOENT)
+ method = TEST_BUILD_SNAPSHOT;
+ else {
+ printf("can't access the file %s\n",
+ snapshot_file);
+
+ rv = -1;
+ goto fin;
+ }
+ } else {
+ if (method == TEST_BUILD_SNAPSHOT) {
+ rv = 0;
+ goto fin;
+ }
+
+ TEST_SNAPSHOT_FILE_READ(protoent, snapshot_file,
+ &td_snap, protoent_read_snapshot_func);
+ }
+ }
+
+ rv = protoent_fill_test_data(&td);
+ if (rv == -1)
+ return (-1);
+ switch (method) {
+ case TEST_GETPROTOBYNAME:
+ if (snapshot_file == NULL)
+ rv = DO_1PASS_TEST(protoent, &td,
+ protoent_test_getprotobyname, (void *)&td);
+ else
+ rv = DO_1PASS_TEST(protoent, &td_snap,
+ protoent_test_getprotobyname, (void *)&td_snap);
+ break;
+ case TEST_GETPROTOBYNUMBER:
+ if (snapshot_file == NULL)
+ rv = DO_1PASS_TEST(protoent, &td,
+ protoent_test_getprotobynumber, (void *)&td);
+ else
+ rv = DO_1PASS_TEST(protoent, &td_snap,
+ protoent_test_getprotobynumber, (void *)&td_snap);
+ break;
+ case TEST_GETPROTOENT:
+ if (snapshot_file == NULL)
+ rv = DO_1PASS_TEST(protoent, &td,
+ protoent_test_getprotoent, (void *)&td);
+ else
+ rv = DO_2PASS_TEST(protoent, &td, &td_snap,
+ compare_protoent, NULL);
+ break;
+ case TEST_GETPROTOENT_2PASS:
+ TEST_DATA_INIT(protoent, &td_2pass, clone_protoent,
+ free_protoent);
+ rv = protoent_fill_test_data(&td_2pass);
+ if (rv != -1)
+ rv = DO_2PASS_TEST(protoent, &td, &td_2pass,
+ compare_protoent, NULL);
+ TEST_DATA_DESTROY(protoent, &td_2pass);
+ break;
+ case TEST_BUILD_SNAPSHOT:
+ if (snapshot_file != NULL)
+ rv = TEST_SNAPSHOT_FILE_WRITE(protoent, snapshot_file,
+ &td, sdump_protoent);
+ break;
+ default:
+ rv = 0;
+ break;
+ }
+
+fin:
+ TEST_DATA_DESTROY(protoent, &td_snap);
+ TEST_DATA_DESTROY(protoent, &td);
+
+ return (rv);
+}
+
+#define SNAPSHOT_FILE "snapshot_proto"
+
+ATF_TC_WITHOUT_HEAD(build_snapshot);
+ATF_TC_BODY(build_snapshot, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getprotoent);
+ATF_TC_BODY(getprotoent, tc)
+{
+
+ ATF_REQUIRE(run_tests(NULL, TEST_GETPROTOENT) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getprotoent_with_snapshot);
+ATF_TC_BODY(getprotoent_with_snapshot, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETPROTOENT) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getprotoent_with_two_pass);
+ATF_TC_BODY(getprotoent_with_two_pass, tc)
+{
+
+ ATF_REQUIRE(run_tests(NULL, TEST_GETPROTOENT_2PASS) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getprotobyname);
+ATF_TC_BODY(getprotobyname, tc)
+{
+
+ ATF_REQUIRE(run_tests(NULL, TEST_GETPROTOBYNAME) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getprotobyname_with_snapshot);
+ATF_TC_BODY(getprotobyname_with_snapshot, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETPROTOBYNAME) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getprotobynumber);
+ATF_TC_BODY(getprotobynumber, tc)
+{
+
+ ATF_REQUIRE(run_tests(NULL, TEST_GETPROTOBYNUMBER) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getprotobynumber_with_snapshot);
+ATF_TC_BODY(getprotobynumber_with_snapshot, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETPROTOBYNUMBER) == 0);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, build_snapshot);
+ ATF_TP_ADD_TC(tp, getprotoent);
+ ATF_TP_ADD_TC(tp, getprotoent_with_snapshot);
+ ATF_TP_ADD_TC(tp, getprotoent_with_two_pass);
+ ATF_TP_ADD_TC(tp, getprotobyname);
+ ATF_TP_ADD_TC(tp, getprotobyname_with_snapshot);
+ ATF_TP_ADD_TC(tp, getprotobynumber);
+ ATF_TP_ADD_TC(tp, getprotobynumber_with_snapshot);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/nss/getpw_test.c b/lib/libc/tests/nss/getpw_test.c
new file mode 100644
index 000000000000..98f890ff7313
--- /dev/null
+++ b/lib/libc/tests/nss/getpw_test.c
@@ -0,0 +1,530 @@
+/*-
+ * Copyright (c) 2006 Michael Bushkov <bushman@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <atf-c.h>
+
+#include "testutil.h"
+
+enum test_methods {
+ TEST_GETPWENT,
+ TEST_GETPWNAM,
+ TEST_GETPWUID,
+ TEST_GETPWENT_2PASS,
+ TEST_BUILD_SNAPSHOT
+};
+
+static enum test_methods method = TEST_BUILD_SNAPSHOT;
+
+DECLARE_TEST_DATA(passwd)
+DECLARE_TEST_FILE_SNAPSHOT(passwd)
+DECLARE_1PASS_TEST(passwd)
+DECLARE_2PASS_TEST(passwd)
+
+static void clone_passwd(struct passwd *, struct passwd const *);
+static int compare_passwd(struct passwd *, struct passwd *, void *);
+static void free_passwd(struct passwd *);
+
+static void sdump_passwd(struct passwd *, char *, size_t);
+static void dump_passwd(struct passwd *);
+
+static int passwd_read_snapshot_func(struct passwd *, char *);
+
+static int passwd_check_ambiguity(struct passwd_test_data *, struct passwd *);
+static int passwd_fill_test_data(struct passwd_test_data *);
+static int passwd_test_correctness(struct passwd *, void *);
+static int passwd_test_getpwnam(struct passwd *, void *);
+static int passwd_test_getpwuid(struct passwd *, void *);
+static int passwd_test_getpwent(struct passwd *, void *);
+
+IMPLEMENT_TEST_DATA(passwd)
+IMPLEMENT_TEST_FILE_SNAPSHOT(passwd)
+IMPLEMENT_1PASS_TEST(passwd)
+IMPLEMENT_2PASS_TEST(passwd)
+
+static void
+clone_passwd(struct passwd *dest, struct passwd const *src)
+{
+ ATF_REQUIRE(dest != NULL);
+ ATF_REQUIRE(src != NULL);
+
+ memcpy(dest, src, sizeof(struct passwd));
+ if (src->pw_name != NULL)
+ dest->pw_name = strdup(src->pw_name);
+ if (src->pw_passwd != NULL)
+ dest->pw_passwd = strdup(src->pw_passwd);
+ if (src->pw_class != NULL)
+ dest->pw_class = strdup(src->pw_class);
+ if (src->pw_gecos != NULL)
+ dest->pw_gecos = strdup(src->pw_gecos);
+ if (src->pw_dir != NULL)
+ dest->pw_dir = strdup(src->pw_dir);
+ if (src->pw_shell != NULL)
+ dest->pw_shell = strdup(dest->pw_shell);
+}
+
+static int
+compare_passwd(struct passwd *pwd1, struct passwd *pwd2, void *mdata)
+{
+ ATF_REQUIRE(pwd1 != NULL);
+ ATF_REQUIRE(pwd2 != NULL);
+
+ if (pwd1 == pwd2)
+ return (0);
+
+ if (pwd1->pw_uid != pwd2->pw_uid ||
+ pwd1->pw_gid != pwd2->pw_gid ||
+ pwd1->pw_change != pwd2->pw_change ||
+ pwd1->pw_expire != pwd2->pw_expire ||
+ pwd1->pw_fields != pwd2->pw_fields ||
+ strcmp(pwd1->pw_name, pwd2->pw_name) != 0 ||
+ strcmp(pwd1->pw_passwd, pwd2->pw_passwd) != 0 ||
+ strcmp(pwd1->pw_class, pwd2->pw_class) != 0 ||
+ strcmp(pwd1->pw_gecos, pwd2->pw_gecos) != 0 ||
+ strcmp(pwd1->pw_dir, pwd2->pw_dir) != 0 ||
+ strcmp(pwd1->pw_shell, pwd2->pw_shell) != 0)
+ return (-1);
+ else
+ return (0);
+}
+
+static void
+free_passwd(struct passwd *pwd)
+{
+ free(pwd->pw_name);
+ free(pwd->pw_passwd);
+ free(pwd->pw_class);
+ free(pwd->pw_gecos);
+ free(pwd->pw_dir);
+ free(pwd->pw_shell);
+}
+
+static void
+sdump_passwd(struct passwd *pwd, char *buffer, size_t buflen)
+{
+ snprintf(buffer, buflen, "%s:%s:%d:%d:%jd:%s:%s:%s:%s:%jd:%d",
+ pwd->pw_name, pwd->pw_passwd, pwd->pw_uid, pwd->pw_gid,
+ (uintmax_t)pwd->pw_change, pwd->pw_class, pwd->pw_gecos,
+ pwd->pw_dir, pwd->pw_shell, (uintmax_t)pwd->pw_expire,
+ pwd->pw_fields);
+}
+
+static void
+dump_passwd(struct passwd *pwd)
+{
+ if (pwd != NULL) {
+ char buffer[2048];
+ sdump_passwd(pwd, buffer, sizeof(buffer));
+ printf("%s\n", buffer);
+ } else
+ printf("(null)\n");
+}
+
+static int
+passwd_read_snapshot_func(struct passwd *pwd, char *line)
+{
+ char *s, *ps, *ts;
+ int i;
+
+#ifdef DEBUG
+ printf("1 line read from snapshot:\n%s\n", line);
+#endif
+
+ i = 0;
+ ps = line;
+ memset(pwd, 0, sizeof(struct passwd));
+ while ((s = strsep(&ps, ":")) != NULL) {
+ switch (i) {
+ case 0:
+ pwd->pw_name = strdup(s);
+ ATF_REQUIRE(pwd->pw_name != NULL);
+ break;
+ case 1:
+ pwd->pw_passwd = strdup(s);
+ ATF_REQUIRE(pwd->pw_passwd != NULL);
+ break;
+ case 2:
+ pwd->pw_uid = (uid_t)strtol(s, &ts, 10);
+ if (*ts != '\0')
+ goto fin;
+ break;
+ case 3:
+ pwd->pw_gid = (gid_t)strtol(s, &ts, 10);
+ if (*ts != '\0')
+ goto fin;
+ break;
+ case 4:
+ pwd->pw_change = (time_t)strtol(s, &ts, 10);
+ if (*ts != '\0')
+ goto fin;
+ break;
+ case 5:
+ pwd->pw_class = strdup(s);
+ ATF_REQUIRE(pwd->pw_class != NULL);
+ break;
+ case 6:
+ pwd->pw_gecos = strdup(s);
+ ATF_REQUIRE(pwd->pw_gecos != NULL);
+ break;
+ case 7:
+ pwd->pw_dir = strdup(s);
+ ATF_REQUIRE(pwd->pw_dir != NULL);
+ break;
+ case 8:
+ pwd->pw_shell = strdup(s);
+ ATF_REQUIRE(pwd->pw_shell != NULL);
+ break;
+ case 9:
+ pwd->pw_expire = (time_t)strtol(s, &ts, 10);
+ if (*ts != '\0')
+ goto fin;
+ break;
+ case 10:
+ pwd->pw_fields = (int)strtol(s, &ts, 10);
+ if (*ts != '\0')
+ goto fin;
+ break;
+ default:
+ break;
+ }
+ ++i;
+ }
+
+fin:
+ if (i != 11) {
+ free_passwd(pwd);
+ memset(pwd, 0, sizeof(struct passwd));
+ return (-1);
+ }
+
+ return (0);
+}
+
+static int
+passwd_fill_test_data(struct passwd_test_data *td)
+{
+ struct passwd *pwd;
+
+ setpassent(1);
+ while ((pwd = getpwent()) != NULL) {
+ if (passwd_test_correctness(pwd, NULL) == 0)
+ TEST_DATA_APPEND(passwd, td, pwd);
+ else
+ return (-1);
+ }
+ endpwent();
+
+ return (0);
+}
+
+static int
+passwd_test_correctness(struct passwd *pwd, void *mdata)
+{
+
+#ifdef DEBUG
+ printf("testing correctness with the following data:\n");
+ dump_passwd(pwd);
+#endif
+
+ if (pwd == NULL)
+ return (-1);
+
+ if (pwd->pw_name == NULL)
+ goto errfin;
+
+ if (pwd->pw_passwd == NULL)
+ goto errfin;
+
+ if (pwd->pw_class == NULL)
+ goto errfin;
+
+ if (pwd->pw_gecos == NULL)
+ goto errfin;
+
+ if (pwd->pw_dir == NULL)
+ goto errfin;
+
+ if (pwd->pw_shell == NULL)
+ goto errfin;
+
+#ifdef DEBUG
+ printf("correct\n");
+#endif
+
+ return (0);
+errfin:
+#ifdef DEBUG
+ printf("incorrect\n");
+#endif
+
+ return (-1);
+}
+
+/* passwd_check_ambiguity() is needed here because when doing the getpwent()
+ * calls sequence, records from different nsswitch sources can be different,
+ * though having the same pw_name/pw_uid */
+static int
+passwd_check_ambiguity(struct passwd_test_data *td, struct passwd *pwd)
+{
+
+ return (TEST_DATA_FIND(passwd, td, pwd, compare_passwd,
+ NULL) != NULL ? 0 : -1);
+}
+
+static int
+passwd_test_getpwnam(struct passwd *pwd_model, void *mdata)
+{
+ struct passwd *pwd;
+
+#ifdef DEBUG
+ printf("testing getpwnam() with the following data:\n");
+ dump_passwd(pwd_model);
+#endif
+
+ pwd = getpwnam(pwd_model->pw_name);
+ if (passwd_test_correctness(pwd, NULL) != 0)
+ goto errfin;
+
+ if ((compare_passwd(pwd, pwd_model, NULL) != 0) &&
+ (passwd_check_ambiguity((struct passwd_test_data *)mdata, pwd)
+ !=0))
+ goto errfin;
+
+#ifdef DEBUG
+ printf("ok\n");
+#endif
+ return (0);
+
+errfin:
+#ifdef DEBUG
+ printf("not ok\n");
+#endif
+ return (-1);
+}
+
+static int
+passwd_test_getpwuid(struct passwd *pwd_model, void *mdata)
+{
+ struct passwd *pwd;
+
+#ifdef DEBUG
+ printf("testing getpwuid() with the following data...\n");
+ dump_passwd(pwd_model);
+#endif
+
+ pwd = getpwuid(pwd_model->pw_uid);
+ if ((passwd_test_correctness(pwd, NULL) != 0) ||
+ ((compare_passwd(pwd, pwd_model, NULL) != 0) &&
+ (passwd_check_ambiguity((struct passwd_test_data *)mdata, pwd)
+ != 0))) {
+#ifdef DEBUG
+ printf("not ok\n");
+#endif
+ return (-1);
+ } else {
+#ifdef DEBUG
+ printf("ok\n");
+#endif
+ return (0);
+ }
+}
+
+static int
+passwd_test_getpwent(struct passwd *pwd, void *mdata)
+{
+ /* Only correctness can be checked when doing 1-pass test for
+ * getpwent(). */
+ return (passwd_test_correctness(pwd, NULL));
+}
+
+static int
+run_tests(const char *snapshot_file, enum test_methods method)
+{
+ struct passwd_test_data td, td_snap, td_2pass;
+ int rv;
+
+ TEST_DATA_INIT(passwd, &td, clone_passwd, free_passwd);
+ TEST_DATA_INIT(passwd, &td_snap, clone_passwd, free_passwd);
+ if (snapshot_file != NULL) {
+ if (access(snapshot_file, W_OK | R_OK) != 0) {
+ if (errno == ENOENT)
+ method = TEST_BUILD_SNAPSHOT;
+ else {
+ printf("can't access the file %s\n",
+ snapshot_file);
+ rv = -1;
+ goto fin;
+ }
+ } else {
+ if (method == TEST_BUILD_SNAPSHOT) {
+ rv = 0;
+ goto fin;
+ }
+
+ TEST_SNAPSHOT_FILE_READ(passwd, snapshot_file,
+ &td_snap, passwd_read_snapshot_func);
+ }
+ }
+
+ rv = passwd_fill_test_data(&td);
+ if (rv == -1)
+ return (-1);
+
+ switch (method) {
+ case TEST_GETPWNAM:
+ if (snapshot_file == NULL)
+ rv = DO_1PASS_TEST(passwd, &td,
+ passwd_test_getpwnam, (void *)&td);
+ else
+ rv = DO_1PASS_TEST(passwd, &td_snap,
+ passwd_test_getpwnam, (void *)&td_snap);
+ break;
+ case TEST_GETPWUID:
+ if (snapshot_file == NULL)
+ rv = DO_1PASS_TEST(passwd, &td,
+ passwd_test_getpwuid, (void *)&td);
+ else
+ rv = DO_1PASS_TEST(passwd, &td_snap,
+ passwd_test_getpwuid, (void *)&td_snap);
+ break;
+ case TEST_GETPWENT:
+ if (snapshot_file == NULL)
+ rv = DO_1PASS_TEST(passwd, &td, passwd_test_getpwent,
+ (void *)&td);
+ else
+ rv = DO_2PASS_TEST(passwd, &td, &td_snap,
+ compare_passwd, NULL);
+ break;
+ case TEST_GETPWENT_2PASS:
+ TEST_DATA_INIT(passwd, &td_2pass, clone_passwd, free_passwd);
+ rv = passwd_fill_test_data(&td_2pass);
+ if (rv != -1)
+ rv = DO_2PASS_TEST(passwd, &td, &td_2pass,
+ compare_passwd, NULL);
+ TEST_DATA_DESTROY(passwd, &td_2pass);
+ break;
+ case TEST_BUILD_SNAPSHOT:
+ if (snapshot_file != NULL)
+ rv = TEST_SNAPSHOT_FILE_WRITE(passwd, snapshot_file,
+ &td, sdump_passwd);
+ break;
+ default:
+ rv = 0;
+ break;
+ }
+
+fin:
+ TEST_DATA_DESTROY(passwd, &td_snap);
+ TEST_DATA_DESTROY(passwd, &td);
+
+ return (rv);
+}
+
+#define SNAPSHOT_FILE "snapshot_pwd"
+
+ATF_TC_WITHOUT_HEAD(build_snapshot);
+ATF_TC_BODY(build_snapshot, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getpwent);
+ATF_TC_BODY(getpwent, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETPWENT) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getpwent_with_snapshot);
+ATF_TC_BODY(getpwent_with_snapshot, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETPWENT) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getpwent_with_two_pass);
+ATF_TC_BODY(getpwent_with_two_pass, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETPWENT_2PASS) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getpwnam);
+ATF_TC_BODY(getpwnam, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETPWNAM) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getpwnam_with_snapshot);
+ATF_TC_BODY(getpwnam_with_snapshot, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETPWNAM) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getpwuid);
+ATF_TC_BODY(getpwuid, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETPWUID) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getpwuid_with_snapshot);
+ATF_TC_BODY(getpwuid_with_snapshot, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETPWUID) == 0);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, build_snapshot);
+ ATF_TP_ADD_TC(tp, getpwent);
+ ATF_TP_ADD_TC(tp, getpwent_with_snapshot);
+ ATF_TP_ADD_TC(tp, getpwent_with_two_pass);
+ ATF_TP_ADD_TC(tp, getpwnam);
+ ATF_TP_ADD_TC(tp, getpwnam_with_snapshot);
+ ATF_TP_ADD_TC(tp, getpwuid);
+ ATF_TP_ADD_TC(tp, getpwuid_with_snapshot);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/nss/getrpc_test.c b/lib/libc/tests/nss/getrpc_test.c
new file mode 100644
index 000000000000..54e04b269542
--- /dev/null
+++ b/lib/libc/tests/nss/getrpc_test.c
@@ -0,0 +1,560 @@
+/*-
+ * Copyright (c) 2006 Michael Bushkov <bushman@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <arpa/inet.h>
+#include <rpc/rpc.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stringlist.h>
+#include <unistd.h>
+
+#include <atf-c.h>
+
+#include "testutil.h"
+
+enum test_methods {
+ TEST_GETRPCENT,
+ TEST_GETRPCBYNAME,
+ TEST_GETRPCBYNUMBER,
+ TEST_GETRPCENT_2PASS,
+ TEST_BUILD_SNAPSHOT
+};
+
+DECLARE_TEST_DATA(rpcent)
+DECLARE_TEST_FILE_SNAPSHOT(rpcent)
+DECLARE_1PASS_TEST(rpcent)
+DECLARE_2PASS_TEST(rpcent)
+
+static void clone_rpcent(struct rpcent *, struct rpcent const *);
+static int compare_rpcent(struct rpcent *, struct rpcent *, void *);
+static void dump_rpcent(struct rpcent *);
+static void free_rpcent(struct rpcent *);
+
+static void sdump_rpcent(struct rpcent *, char *, size_t);
+static int rpcent_read_snapshot_func(struct rpcent *, char *);
+
+static int rpcent_check_ambiguity(struct rpcent_test_data *,
+ struct rpcent *);
+static int rpcent_fill_test_data(struct rpcent_test_data *);
+static int rpcent_test_correctness(struct rpcent *, void *);
+static int rpcent_test_getrpcbyname(struct rpcent *, void *);
+static int rpcent_test_getrpcbynumber(struct rpcent *, void *);
+static int rpcent_test_getrpcent(struct rpcent *, void *);
+
+static void usage(void) __attribute__((__noreturn__));
+
+IMPLEMENT_TEST_DATA(rpcent)
+IMPLEMENT_TEST_FILE_SNAPSHOT(rpcent)
+IMPLEMENT_1PASS_TEST(rpcent)
+IMPLEMENT_2PASS_TEST(rpcent)
+
+static void
+clone_rpcent(struct rpcent *dest, struct rpcent const *src)
+{
+ ATF_REQUIRE(dest != NULL);
+ ATF_REQUIRE(src != NULL);
+
+ char **cp;
+ int aliases_num;
+
+ memset(dest, 0, sizeof(struct rpcent));
+
+ if (src->r_name != NULL) {
+ dest->r_name = strdup(src->r_name);
+ ATF_REQUIRE(dest->r_name != NULL);
+ }
+
+ dest->r_number = src->r_number;
+
+ if (src->r_aliases != NULL) {
+ aliases_num = 0;
+ for (cp = src->r_aliases; *cp; ++cp)
+ ++aliases_num;
+
+ dest->r_aliases = calloc(1, (aliases_num + 1) * sizeof(char *));
+ ATF_REQUIRE(dest->r_aliases != NULL);
+
+ for (cp = src->r_aliases; *cp; ++cp) {
+ dest->r_aliases[cp - src->r_aliases] = strdup(*cp);
+ ATF_REQUIRE(dest->r_aliases[cp - src->r_aliases] != NULL);
+ }
+ }
+}
+
+static void
+free_rpcent(struct rpcent *rpc)
+{
+ char **cp;
+
+ ATF_REQUIRE(rpc != NULL);
+
+ free(rpc->r_name);
+
+ for (cp = rpc->r_aliases; *cp; ++cp)
+ free(*cp);
+ free(rpc->r_aliases);
+}
+
+static int
+compare_rpcent(struct rpcent *rpc1, struct rpcent *rpc2, void *mdata)
+{
+ char **c1, **c2;
+
+ if (rpc1 == rpc2)
+ return 0;
+
+ if ((rpc1 == NULL) || (rpc2 == NULL))
+ goto errfin;
+
+ if ((strcmp(rpc1->r_name, rpc2->r_name) != 0) ||
+ (rpc1->r_number != rpc2->r_number))
+ goto errfin;
+
+ c1 = rpc1->r_aliases;
+ c2 = rpc2->r_aliases;
+
+ if ((rpc1->r_aliases == NULL) || (rpc2->r_aliases == NULL))
+ goto errfin;
+
+ for (;*c1 && *c2; ++c1, ++c2)
+ if (strcmp(*c1, *c2) != 0)
+ goto errfin;
+
+ if ((*c1 != '\0') || (*c2 != '\0'))
+ goto errfin;
+
+ return 0;
+
+errfin:
+ if (mdata == NULL) {
+ printf("following structures are not equal:\n");
+ dump_rpcent(rpc1);
+ dump_rpcent(rpc2);
+ }
+
+ return (-1);
+}
+
+static void
+sdump_rpcent(struct rpcent *rpc, char *buffer, size_t buflen)
+{
+ char **cp;
+ int written;
+
+ written = snprintf(buffer, buflen, "%s %d",
+ rpc->r_name, rpc->r_number);
+ buffer += written;
+ if (written > buflen)
+ return;
+ buflen -= written;
+
+ if (rpc->r_aliases != NULL) {
+ if (*(rpc->r_aliases) != '\0') {
+ for (cp = rpc->r_aliases; *cp; ++cp) {
+ written = snprintf(buffer, buflen, " %s",*cp);
+ buffer += written;
+ if (written > buflen)
+ return;
+ buflen -= written;
+
+ if (buflen == 0)
+ return;
+ }
+ } else
+ snprintf(buffer, buflen, " noaliases");
+ } else
+ snprintf(buffer, buflen, " (null)");
+}
+
+static int
+rpcent_read_snapshot_func(struct rpcent *rpc, char *line)
+{
+ StringList *sl;
+ char *s, *ps, *ts;
+ int i;
+
+ printf("1 line read from snapshot:\n%s\n", line);
+
+ i = 0;
+ sl = NULL;
+ ps = line;
+ memset(rpc, 0, sizeof(struct rpcent));
+ while ((s = strsep(&ps, " ")) != NULL) {
+ switch (i) {
+ case 0:
+ rpc->r_name = strdup(s);
+ ATF_REQUIRE(rpc->r_name != NULL);
+ break;
+
+ case 1:
+ rpc->r_number = (int)strtol(s, &ts, 10);
+ if (*ts != '\0') {
+ free(rpc->r_name);
+ return (-1);
+ }
+ break;
+
+ default:
+ if (sl == NULL) {
+ if (strcmp(s, "(null)") == 0)
+ return (0);
+
+ sl = sl_init();
+ ATF_REQUIRE(sl != NULL);
+
+ if (strcmp(s, "noaliases") != 0) {
+ ts = strdup(s);
+ ATF_REQUIRE(ts != NULL);
+ sl_add(sl, ts);
+ }
+ } else {
+ ts = strdup(s);
+ ATF_REQUIRE(ts != NULL);
+ sl_add(sl, ts);
+ }
+ break;
+ }
+ i++;
+ }
+
+ if (i < 3) {
+ free(rpc->r_name);
+ memset(rpc, 0, sizeof(struct rpcent));
+ return (-1);
+ }
+
+ sl_add(sl, NULL);
+ rpc->r_aliases = sl->sl_str;
+
+ /* NOTE: is it a dirty hack or not? */
+ free(sl);
+ return (0);
+}
+
+static void
+dump_rpcent(struct rpcent *result)
+{
+ if (result != NULL) {
+ char buffer[1024];
+ sdump_rpcent(result, buffer, sizeof(buffer));
+ printf("%s\n", buffer);
+ } else
+ printf("(null)\n");
+}
+
+static int
+rpcent_fill_test_data(struct rpcent_test_data *td)
+{
+ struct rpcent *rpc;
+
+ setrpcent(1);
+ while ((rpc = getrpcent()) != NULL) {
+ if (rpcent_test_correctness(rpc, NULL) == 0)
+ TEST_DATA_APPEND(rpcent, td, rpc);
+ else
+ return (-1);
+ }
+ endrpcent();
+
+ return (0);
+}
+
+static int
+rpcent_test_correctness(struct rpcent *rpc, void *mdata)
+{
+
+ printf("testing correctness with the following data:\n");
+ dump_rpcent(rpc);
+
+ if (rpc == NULL)
+ goto errfin;
+
+ if (rpc->r_name == NULL)
+ goto errfin;
+
+ if (rpc->r_number < 0)
+ goto errfin;
+
+ if (rpc->r_aliases == NULL)
+ goto errfin;
+
+ printf("correct\n");
+
+ return (0);
+errfin:
+ printf("incorrect\n");
+
+ return (-1);
+}
+
+/* rpcent_check_ambiguity() is needed when one port+rpc is associated with
+ * more than one piece (these cases are usually marked as PROBLEM in
+ * /etc/peices. This functions is needed also when one piece+rpc is
+ * associated with several ports. We have to check all the rpcent structures
+ * to make sure that rpc really exists and correct */
+static int
+rpcent_check_ambiguity(struct rpcent_test_data *td, struct rpcent *rpc)
+{
+
+ return (TEST_DATA_FIND(rpcent, td, rpc, compare_rpcent,
+ NULL) != NULL ? 0 : -1);
+}
+
+static int
+rpcent_test_getrpcbyname(struct rpcent *rpc_model, void *mdata)
+{
+ char **alias;
+ struct rpcent *rpc;
+
+ printf("testing getrpcbyname() with the following data:\n");
+ dump_rpcent(rpc_model);
+
+ rpc = getrpcbyname(rpc_model->r_name);
+ if (rpcent_test_correctness(rpc, NULL) != 0)
+ goto errfin;
+
+ if ((compare_rpcent(rpc, rpc_model, NULL) != 0) &&
+ (rpcent_check_ambiguity((struct rpcent_test_data *)mdata, rpc)
+ !=0))
+ goto errfin;
+
+ for (alias = rpc_model->r_aliases; *alias; ++alias) {
+ rpc = getrpcbyname(*alias);
+
+ if (rpcent_test_correctness(rpc, NULL) != 0)
+ goto errfin;
+
+ if ((compare_rpcent(rpc, rpc_model, NULL) != 0) &&
+ (rpcent_check_ambiguity(
+ (struct rpcent_test_data *)mdata, rpc) != 0))
+ goto errfin;
+ }
+
+ printf("ok\n");
+ return (0);
+
+errfin:
+ printf("not ok\n");
+
+ return (-1);
+}
+
+static int
+rpcent_test_getrpcbynumber(struct rpcent *rpc_model, void *mdata)
+{
+ struct rpcent *rpc;
+
+ printf("testing getrpcbyport() with the following data...\n");
+ dump_rpcent(rpc_model);
+
+ rpc = getrpcbynumber(rpc_model->r_number);
+ if (rpcent_test_correctness(rpc, NULL) != 0 ||
+ (compare_rpcent(rpc, rpc_model, NULL) != 0 &&
+ rpcent_check_ambiguity((struct rpcent_test_data *)mdata, rpc)
+ != 0)) {
+ printf("not ok\n");
+ return (-1);
+ } else {
+ printf("ok\n");
+ return (0);
+ }
+}
+
+static int
+rpcent_test_getrpcent(struct rpcent *rpc, void *mdata)
+{
+
+ /*
+ * Only correctness can be checked when doing 1-pass test for
+ * getrpcent().
+ */
+ return (rpcent_test_correctness(rpc, NULL));
+}
+
+int
+run_tests(const char *snapshot_file, enum test_methods method)
+{
+ struct rpcent_test_data td, td_snap, td_2pass;
+ int rv;
+
+ TEST_DATA_INIT(rpcent, &td, clone_rpcent, free_rpcent);
+ TEST_DATA_INIT(rpcent, &td_snap, clone_rpcent, free_rpcent);
+ if (snapshot_file != NULL) {
+ if (access(snapshot_file, W_OK | R_OK) != 0) {
+ if (errno == ENOENT)
+ method = TEST_BUILD_SNAPSHOT;
+ else {
+ printf("can't access the file %s\n",
+ snapshot_file);
+
+ rv = -1;
+ goto fin;
+ }
+ } else {
+ if (method == TEST_BUILD_SNAPSHOT) {
+ rv = 0;
+ goto fin;
+ }
+
+ TEST_SNAPSHOT_FILE_READ(rpcent, snapshot_file,
+ &td_snap, rpcent_read_snapshot_func);
+ }
+ }
+
+ rv = rpcent_fill_test_data(&td);
+ if (rv == -1)
+ return (-1);
+ switch (method) {
+ case TEST_GETRPCBYNAME:
+ if (snapshot_file == NULL)
+ rv = DO_1PASS_TEST(rpcent, &td,
+ rpcent_test_getrpcbyname, (void *)&td);
+ else
+ rv = DO_1PASS_TEST(rpcent, &td_snap,
+ rpcent_test_getrpcbyname, (void *)&td_snap);
+ break;
+ case TEST_GETRPCBYNUMBER:
+ if (snapshot_file == NULL)
+ rv = DO_1PASS_TEST(rpcent, &td,
+ rpcent_test_getrpcbynumber, (void *)&td);
+ else
+ rv = DO_1PASS_TEST(rpcent, &td_snap,
+ rpcent_test_getrpcbynumber, (void *)&td_snap);
+ break;
+ case TEST_GETRPCENT:
+ if (snapshot_file == NULL)
+ rv = DO_1PASS_TEST(rpcent, &td, rpcent_test_getrpcent,
+ (void *)&td);
+ else
+ rv = DO_2PASS_TEST(rpcent, &td, &td_snap,
+ compare_rpcent, NULL);
+ break;
+ case TEST_GETRPCENT_2PASS:
+ TEST_DATA_INIT(rpcent, &td_2pass, clone_rpcent, free_rpcent);
+ rv = rpcent_fill_test_data(&td_2pass);
+ if (rv != -1)
+ rv = DO_2PASS_TEST(rpcent, &td, &td_2pass,
+ compare_rpcent, NULL);
+ TEST_DATA_DESTROY(rpcent, &td_2pass);
+ break;
+ case TEST_BUILD_SNAPSHOT:
+ if (snapshot_file != NULL)
+ rv = TEST_SNAPSHOT_FILE_WRITE(rpcent, snapshot_file, &td,
+ sdump_rpcent);
+ break;
+ default:
+ rv = 0;
+ break;
+ }
+
+fin:
+ TEST_DATA_DESTROY(rpcent, &td_snap);
+ TEST_DATA_DESTROY(rpcent, &td);
+
+ return (rv);
+}
+
+#define SNAPSHOT_FILE "snapshot_rpc"
+
+ATF_TC_WITHOUT_HEAD(build_snapshot);
+ATF_TC_BODY(build_snapshot, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getrpcbyname);
+ATF_TC_BODY(getrpcbyname, tc)
+{
+
+ ATF_REQUIRE(run_tests(NULL, TEST_GETRPCBYNAME) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getrpcbyname_with_snapshot);
+ATF_TC_BODY(getrpcbyname_with_snapshot, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETRPCBYNAME) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getrpcbynumber);
+ATF_TC_BODY(getrpcbynumber, tc)
+{
+
+ ATF_REQUIRE(run_tests(NULL, TEST_GETRPCBYNUMBER) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getrpcbynumber_with_snapshot);
+ATF_TC_BODY(getrpcbynumber_with_snapshot, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETRPCBYNUMBER) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getrpcbyent);
+ATF_TC_BODY(getrpcbyent, tc)
+{
+
+ ATF_REQUIRE(run_tests(NULL, TEST_GETRPCENT) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getrpcbyent_with_snapshot);
+ATF_TC_BODY(getrpcbyent_with_snapshot, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETRPCENT) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getrpcbyent_with_two_pass);
+ATF_TC_BODY(getrpcbyent_with_two_pass, tc)
+{
+
+ ATF_REQUIRE(run_tests(NULL, TEST_GETRPCENT_2PASS) == 0);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, build_snapshot);
+ ATF_TP_ADD_TC(tp, getrpcbyname);
+ ATF_TP_ADD_TC(tp, getrpcbyname_with_snapshot);
+ ATF_TP_ADD_TC(tp, getrpcbynumber);
+ ATF_TP_ADD_TC(tp, getrpcbynumber_with_snapshot);
+ ATF_TP_ADD_TC(tp, getrpcbyent);
+ ATF_TP_ADD_TC(tp, getrpcbyent_with_snapshot);
+ ATF_TP_ADD_TC(tp, getrpcbyent_with_two_pass);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/nss/getserv_test.c b/lib/libc/tests/nss/getserv_test.c
new file mode 100644
index 000000000000..29c1dfaf2ddd
--- /dev/null
+++ b/lib/libc/tests/nss/getserv_test.c
@@ -0,0 +1,570 @@
+/*-
+ * Copyright (c) 2006 Michael Bushkov <bushman@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stringlist.h>
+#include <unistd.h>
+
+#include <atf-c.h>
+
+#include "testutil.h"
+
+enum test_methods {
+ TEST_GETSERVENT,
+ TEST_GETSERVBYNAME,
+ TEST_GETSERVBYPORT,
+ TEST_GETSERVENT_2PASS,
+ TEST_BUILD_SNAPSHOT
+};
+
+DECLARE_TEST_DATA(servent)
+DECLARE_TEST_FILE_SNAPSHOT(servent)
+DECLARE_1PASS_TEST(servent)
+DECLARE_2PASS_TEST(servent)
+
+static void clone_servent(struct servent *, struct servent const *);
+static int compare_servent(struct servent *, struct servent *, void *);
+static void dump_servent(struct servent *);
+static void free_servent(struct servent *);
+
+static void sdump_servent(struct servent *, char *, size_t);
+static int servent_read_snapshot_func(struct servent *, char *);
+
+static int servent_check_ambiguity(struct servent_test_data *,
+ struct servent *);
+static int servent_fill_test_data(struct servent_test_data *);
+static int servent_test_correctness(struct servent *, void *);
+static int servent_test_getservbyname(struct servent *, void *);
+static int servent_test_getservbyport(struct servent *, void *);
+static int servent_test_getservent(struct servent *, void *);
+
+IMPLEMENT_TEST_DATA(servent)
+IMPLEMENT_TEST_FILE_SNAPSHOT(servent)
+IMPLEMENT_1PASS_TEST(servent)
+IMPLEMENT_2PASS_TEST(servent)
+
+static void
+clone_servent(struct servent *dest, struct servent const *src)
+{
+ ATF_REQUIRE(dest != NULL);
+ ATF_REQUIRE(src != NULL);
+
+ char **cp;
+ int aliases_num;
+
+ memset(dest, 0, sizeof(struct servent));
+
+ if (src->s_name != NULL) {
+ dest->s_name = strdup(src->s_name);
+ ATF_REQUIRE(dest->s_name != NULL);
+ }
+
+ if (src->s_proto != NULL) {
+ dest->s_proto = strdup(src->s_proto);
+ ATF_REQUIRE(dest->s_proto != NULL);
+ }
+ dest->s_port = src->s_port;
+
+ if (src->s_aliases != NULL) {
+ aliases_num = 0;
+ for (cp = src->s_aliases; *cp; ++cp)
+ ++aliases_num;
+
+ dest->s_aliases = calloc(1, (aliases_num + 1) * sizeof(char *));
+ ATF_REQUIRE(dest->s_aliases != NULL);
+
+ for (cp = src->s_aliases; *cp; ++cp) {
+ dest->s_aliases[cp - src->s_aliases] = strdup(*cp);
+ ATF_REQUIRE(dest->s_aliases[cp - src->s_aliases] != NULL);
+ }
+ }
+}
+
+static void
+free_servent(struct servent *serv)
+{
+ char **cp;
+
+ ATF_REQUIRE(serv != NULL);
+
+ free(serv->s_name);
+ free(serv->s_proto);
+
+ for (cp = serv->s_aliases; *cp; ++cp)
+ free(*cp);
+ free(serv->s_aliases);
+}
+
+static int
+compare_servent(struct servent *serv1, struct servent *serv2, void *mdata)
+{
+ char **c1, **c2;
+
+ if (serv1 == serv2)
+ return 0;
+
+ if ((serv1 == NULL) || (serv2 == NULL))
+ goto errfin;
+
+ if ((strcmp(serv1->s_name, serv2->s_name) != 0) ||
+ (strcmp(serv1->s_proto, serv2->s_proto) != 0) ||
+ (serv1->s_port != serv2->s_port))
+ goto errfin;
+
+ c1 = serv1->s_aliases;
+ c2 = serv2->s_aliases;
+
+ if ((serv1->s_aliases == NULL) || (serv2->s_aliases == NULL))
+ goto errfin;
+
+ for (;*c1 && *c2; ++c1, ++c2)
+ if (strcmp(*c1, *c2) != 0)
+ goto errfin;
+
+ if ((*c1 != '\0') || (*c2 != '\0'))
+ goto errfin;
+
+ return 0;
+
+errfin:
+ if (mdata == NULL) {
+ printf("following structures are not equal:\n");
+ dump_servent(serv1);
+ dump_servent(serv2);
+ }
+
+ return (-1);
+}
+
+static void
+sdump_servent(struct servent *serv, char *buffer, size_t buflen)
+{
+ char **cp;
+ int written;
+
+ written = snprintf(buffer, buflen, "%s %d %s",
+ serv->s_name, ntohs(serv->s_port), serv->s_proto);
+ buffer += written;
+ if (written > buflen)
+ return;
+ buflen -= written;
+
+ if (serv->s_aliases != NULL) {
+ if (*(serv->s_aliases) != '\0') {
+ for (cp = serv->s_aliases; *cp; ++cp) {
+ written = snprintf(buffer, buflen, " %s",*cp);
+ buffer += written;
+ if (written > buflen)
+ return;
+ buflen -= written;
+
+ if (buflen == 0)
+ return;
+ }
+ } else
+ snprintf(buffer, buflen, " noaliases");
+ } else
+ snprintf(buffer, buflen, " (null)");
+}
+
+static int
+servent_read_snapshot_func(struct servent *serv, char *line)
+{
+ StringList *sl;
+ char *s, *ps, *ts;
+ int i;
+
+ printf("1 line read from snapshot:\n%s\n", line);
+
+ i = 0;
+ sl = NULL;
+ ps = line;
+ memset(serv, 0, sizeof(struct servent));
+ while ( (s = strsep(&ps, " ")) != NULL) {
+ switch (i) {
+ case 0:
+ serv->s_name = strdup(s);
+ ATF_REQUIRE(serv->s_name != NULL);
+ break;
+
+ case 1:
+ serv->s_port = htons(
+ (int)strtol(s, &ts, 10));
+ if (*ts != '\0') {
+ free(serv->s_name);
+ return (-1);
+ }
+ break;
+
+ case 2:
+ serv->s_proto = strdup(s);
+ ATF_REQUIRE(serv->s_proto != NULL);
+ break;
+
+ default:
+ if (sl == NULL) {
+ if (strcmp(s, "(null)") == 0)
+ return (0);
+
+ sl = sl_init();
+ ATF_REQUIRE(sl != NULL);
+
+ if (strcmp(s, "noaliases") != 0) {
+ ts = strdup(s);
+ ATF_REQUIRE(ts != NULL);
+ sl_add(sl, ts);
+ }
+ } else {
+ ts = strdup(s);
+ ATF_REQUIRE(ts != NULL);
+ sl_add(sl, ts);
+ }
+ break;
+ }
+ ++i;
+ }
+
+ if (i < 3) {
+ free(serv->s_name);
+ free(serv->s_proto);
+ memset(serv, 0, sizeof(struct servent));
+ return (-1);
+ }
+
+ sl_add(sl, NULL);
+ serv->s_aliases = sl->sl_str;
+
+ /* NOTE: is it a dirty hack or not? */
+ free(sl);
+ return (0);
+}
+
+static void
+dump_servent(struct servent *result)
+{
+ if (result != NULL) {
+ char buffer[1024];
+ sdump_servent(result, buffer, sizeof(buffer));
+ printf("%s\n", buffer);
+ } else
+ printf("(null)\n");
+}
+
+static int
+servent_fill_test_data(struct servent_test_data *td)
+{
+ struct servent *serv;
+
+ setservent(1);
+ while ((serv = getservent()) != NULL) {
+ if (servent_test_correctness(serv, NULL) == 0)
+ TEST_DATA_APPEND(servent, td, serv);
+ else
+ return (-1);
+ }
+ endservent();
+
+ return (0);
+}
+
+static int
+servent_test_correctness(struct servent *serv, void *mdata)
+{
+ printf("testing correctness with the following data:\n");
+ dump_servent(serv);
+
+ if (serv == NULL)
+ goto errfin;
+
+ if (serv->s_name == NULL)
+ goto errfin;
+
+ if (serv->s_proto == NULL)
+ goto errfin;
+
+ if (ntohs(serv->s_port < 0))
+ goto errfin;
+
+ if (serv->s_aliases == NULL)
+ goto errfin;
+
+ printf("correct\n");
+
+ return (0);
+errfin:
+ printf("incorrect\n");
+
+ return (-1);
+}
+
+/* servent_check_ambiguity() is needed when one port+proto is associated with
+ * more than one service (these cases are usually marked as PROBLEM in
+ * /etc/services. This functions is needed also when one service+proto is
+ * associated with several ports. We have to check all the servent structures
+ * to make sure that serv really exists and correct */
+static int
+servent_check_ambiguity(struct servent_test_data *td, struct servent *serv)
+{
+
+ return (TEST_DATA_FIND(servent, td, serv, compare_servent,
+ NULL) != NULL ? 0 : -1);
+}
+
+static int
+servent_test_getservbyname(struct servent *serv_model, void *mdata)
+{
+ char **alias;
+ struct servent *serv;
+
+ printf("testing getservbyname() with the following data:\n");
+ dump_servent(serv_model);
+
+ serv = getservbyname(serv_model->s_name, serv_model->s_proto);
+ if (servent_test_correctness(serv, NULL) != 0)
+ goto errfin;
+
+ if ((compare_servent(serv, serv_model, NULL) != 0) &&
+ (servent_check_ambiguity((struct servent_test_data *)mdata, serv)
+ !=0))
+ goto errfin;
+
+ for (alias = serv_model->s_aliases; *alias; ++alias) {
+ serv = getservbyname(*alias, serv_model->s_proto);
+
+ if (servent_test_correctness(serv, NULL) != 0)
+ goto errfin;
+
+ if ((compare_servent(serv, serv_model, NULL) != 0) &&
+ (servent_check_ambiguity(
+ (struct servent_test_data *)mdata, serv) != 0))
+ goto errfin;
+ }
+
+ printf("ok\n");
+ return (0);
+
+errfin:
+ printf("not ok\n");
+
+ return (-1);
+}
+
+static int
+servent_test_getservbyport(struct servent *serv_model, void *mdata)
+{
+ struct servent *serv;
+
+ printf("testing getservbyport() with the following data...\n");
+ dump_servent(serv_model);
+
+ serv = getservbyport(serv_model->s_port, serv_model->s_proto);
+ if ((servent_test_correctness(serv, NULL) != 0) ||
+ ((compare_servent(serv, serv_model, NULL) != 0) &&
+ (servent_check_ambiguity((struct servent_test_data *)mdata, serv)
+ != 0))) {
+ printf("not ok\n");
+ return (-1);
+ } else {
+ printf("ok\n");
+ return (0);
+ }
+}
+
+static int
+servent_test_getservent(struct servent *serv, void *mdata)
+{
+ /* Only correctness can be checked when doing 1-pass test for
+ * getservent(). */
+ return (servent_test_correctness(serv, NULL));
+}
+
+int
+run_tests(const char *snapshot_file, enum test_methods method)
+{
+ struct servent_test_data td, td_snap, td_2pass;
+ int rv;
+
+ TEST_DATA_INIT(servent, &td, clone_servent, free_servent);
+ TEST_DATA_INIT(servent, &td_snap, clone_servent, free_servent);
+ if (snapshot_file != NULL) {
+ if (access(snapshot_file, W_OK | R_OK) != 0) {
+ if (errno == ENOENT)
+ method = TEST_BUILD_SNAPSHOT;
+ else {
+ printf("can't access the file %s\n",
+ snapshot_file);
+
+ rv = -1;
+ goto fin;
+ }
+ } else {
+ if (method == TEST_BUILD_SNAPSHOT) {
+ rv = 0;
+ goto fin;
+ }
+
+ TEST_SNAPSHOT_FILE_READ(servent, snapshot_file,
+ &td_snap, servent_read_snapshot_func);
+ }
+ }
+
+ rv = servent_fill_test_data(&td);
+ if (rv == -1)
+ return (-1);
+ switch (method) {
+ case TEST_GETSERVBYNAME:
+ if (snapshot_file == NULL)
+ rv = DO_1PASS_TEST(servent, &td,
+ servent_test_getservbyname, (void *)&td);
+ else
+ rv = DO_1PASS_TEST(servent, &td_snap,
+ servent_test_getservbyname, (void *)&td_snap);
+ break;
+ case TEST_GETSERVBYPORT:
+ if (snapshot_file == NULL)
+ rv = DO_1PASS_TEST(servent, &td,
+ servent_test_getservbyport, (void *)&td);
+ else
+ rv = DO_1PASS_TEST(servent, &td_snap,
+ servent_test_getservbyport, (void *)&td_snap);
+ break;
+ case TEST_GETSERVENT:
+ if (snapshot_file == NULL)
+ rv = DO_1PASS_TEST(servent, &td, servent_test_getservent,
+ (void *)&td);
+ else
+ rv = DO_2PASS_TEST(servent, &td, &td_snap,
+ compare_servent, NULL);
+ break;
+ case TEST_GETSERVENT_2PASS:
+ TEST_DATA_INIT(servent, &td_2pass, clone_servent, free_servent);
+ rv = servent_fill_test_data(&td_2pass);
+ if (rv != -1)
+ rv = DO_2PASS_TEST(servent, &td, &td_2pass,
+ compare_servent, NULL);
+ TEST_DATA_DESTROY(servent, &td_2pass);
+ break;
+ case TEST_BUILD_SNAPSHOT:
+ if (snapshot_file != NULL)
+ rv = TEST_SNAPSHOT_FILE_WRITE(servent, snapshot_file, &td,
+ sdump_servent);
+ break;
+ default:
+ rv = 0;
+ break;
+ }
+
+fin:
+ TEST_DATA_DESTROY(servent, &td_snap);
+ TEST_DATA_DESTROY(servent, &td);
+
+ return (rv);
+}
+
+#define SNAPSHOT_FILE "snapshot_serv"
+
+ATF_TC_WITHOUT_HEAD(build_snapshot);
+ATF_TC_BODY(build_snapshot, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getservbyname);
+ATF_TC_BODY(getservbyname, tc)
+{
+
+ ATF_REQUIRE(run_tests(NULL, TEST_GETSERVBYNAME) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getservbyname_with_snapshot);
+ATF_TC_BODY(getservbyname_with_snapshot, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETSERVBYNAME) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getservbyport);
+ATF_TC_BODY(getservbyport, tc)
+{
+
+ ATF_REQUIRE(run_tests(NULL, TEST_GETSERVBYPORT) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getservbyport_with_snapshot);
+ATF_TC_BODY(getservbyport_with_snapshot, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETSERVBYPORT) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getservbyent);
+ATF_TC_BODY(getservbyent, tc)
+{
+
+ ATF_REQUIRE(run_tests(NULL, TEST_GETSERVENT) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getservbyent_with_snapshot);
+ATF_TC_BODY(getservbyent_with_snapshot, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETSERVENT) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getservbyent_with_two_pass);
+ATF_TC_BODY(getservbyent_with_two_pass, tc)
+{
+
+ ATF_REQUIRE(run_tests(NULL, TEST_GETSERVENT_2PASS) == 0);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, build_snapshot);
+ ATF_TP_ADD_TC(tp, getservbyent);
+ ATF_TP_ADD_TC(tp, getservbyent_with_snapshot);
+ ATF_TP_ADD_TC(tp, getservbyent_with_two_pass);
+ ATF_TP_ADD_TC(tp, getservbyname);
+ ATF_TP_ADD_TC(tp, getservbyname_with_snapshot);
+ ATF_TP_ADD_TC(tp, getservbyport);
+ ATF_TP_ADD_TC(tp, getservbyport_with_snapshot);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/nss/getusershell_test.c b/lib/libc/tests/nss/getusershell_test.c
new file mode 100644
index 000000000000..ccd8cf96a6ed
--- /dev/null
+++ b/lib/libc/tests/nss/getusershell_test.c
@@ -0,0 +1,225 @@
+/*-
+ * Copyright (c) 2006 Michael Bushkov <bushman@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <atf-c.h>
+
+#include "testutil.h"
+
+enum test_methods {
+ TEST_GETUSERSHELL,
+ TEST_BUILD_SNAPSHOT
+};
+
+struct usershell {
+ char *path;
+};
+
+static enum test_methods method = TEST_GETUSERSHELL;
+
+DECLARE_TEST_DATA(usershell)
+DECLARE_TEST_FILE_SNAPSHOT(usershell)
+DECLARE_2PASS_TEST(usershell)
+
+static void clone_usershell(struct usershell *, struct usershell const *);
+static int compare_usershell(struct usershell *, struct usershell *, void *);
+static void free_usershell(struct usershell *);
+
+static void sdump_usershell(struct usershell *, char *, size_t);
+static void dump_usershell(struct usershell *);
+
+IMPLEMENT_TEST_DATA(usershell)
+IMPLEMENT_TEST_FILE_SNAPSHOT(usershell)
+IMPLEMENT_2PASS_TEST(usershell)
+
+static void
+clone_usershell(struct usershell *dest, struct usershell const *src)
+{
+ assert(dest != NULL);
+ assert(src != NULL);
+
+ if (src->path != NULL) {
+ dest->path = strdup(src->path);
+ assert(dest->path != NULL);
+ }
+}
+
+static int
+compare_usershell(struct usershell *us1, struct usershell *us2, void *mdata)
+{
+ int rv;
+
+ assert(us1 != NULL);
+ assert(us2 != NULL);
+
+ dump_usershell(us1);
+ dump_usershell(us2);
+
+ if (us1 == us2)
+ return (0);
+
+ rv = strcmp(us1->path, us2->path);
+ if (rv != 0) {
+ printf("following structures are not equal:\n");
+ dump_usershell(us1);
+ dump_usershell(us2);
+ }
+
+ return (rv);
+}
+
+static void
+free_usershell(struct usershell *us)
+{
+ free(us->path);
+}
+
+static void
+sdump_usershell(struct usershell *us, char *buffer, size_t buflen)
+{
+ snprintf(buffer, buflen, "%s", us->path);
+}
+
+static void
+dump_usershell(struct usershell *us)
+{
+ if (us != NULL) {
+ char buffer[2048];
+ sdump_usershell(us, buffer, sizeof(buffer));
+ printf("%s\n", buffer);
+ } else
+ printf("(null)\n");
+}
+
+static int
+usershell_read_snapshot_func(struct usershell *us, char *line)
+{
+
+ us->path = strdup(line);
+ ATF_REQUIRE(us->path != NULL);
+
+ return (0);
+}
+
+int
+run_tests(const char *snapshot_file, enum test_methods method)
+{
+ struct usershell_test_data td, td_snap;
+ struct usershell ushell;
+ int rv;
+
+ rv = 0;
+
+ TEST_DATA_INIT(usershell, &td, clone_usershell, free_usershell);
+ TEST_DATA_INIT(usershell, &td_snap, clone_usershell, free_usershell);
+
+ setusershell();
+ while ((ushell.path = getusershell()) != NULL) {
+ printf("usershell found:\n");
+ dump_usershell(&ushell);
+ TEST_DATA_APPEND(usershell, &td, &ushell);
+ }
+ endusershell();
+
+ if (snapshot_file != NULL) {
+ if (access(snapshot_file, W_OK | R_OK) != 0) {
+ if (errno == ENOENT)
+ method = TEST_BUILD_SNAPSHOT;
+ else {
+ printf("can't access the snapshot file %s\n",
+ snapshot_file);
+
+ rv = -1;
+ goto fin;
+ }
+ } else {
+ rv = TEST_SNAPSHOT_FILE_READ(usershell, snapshot_file,
+ &td_snap, usershell_read_snapshot_func);
+ if (rv != 0) {
+ printf("error reading snapshot file\n");
+ goto fin;
+ }
+ }
+ }
+
+ switch (method) {
+ case TEST_GETUSERSHELL:
+ rv = DO_2PASS_TEST(usershell, &td, &td_snap,
+ compare_usershell, NULL);
+ break;
+ case TEST_BUILD_SNAPSHOT:
+ if (snapshot_file != NULL) {
+ rv = TEST_SNAPSHOT_FILE_WRITE(usershell, snapshot_file,
+ &td, sdump_usershell);
+ }
+ break;
+ default:
+ rv = 0;
+ break;
+ }
+
+fin:
+ TEST_DATA_DESTROY(usershell, &td_snap);
+ TEST_DATA_DESTROY(usershell, &td);
+
+ return (rv);
+}
+
+#define SNAPSHOT_FILE "snapshot_usershell"
+
+ATF_TC_WITHOUT_HEAD(getusershell_with_snapshot);
+ATF_TC_BODY(getusershell_with_snapshot, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getusershell_with_two_pass);
+ATF_TC_BODY(getusershell_with_two_pass, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETUSERSHELL) == 0);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, getusershell_with_snapshot);
+ ATF_TP_ADD_TC(tp, getusershell_with_two_pass);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/nss/testutil.h b/lib/libc/tests/nss/testutil.h
new file mode 100644
index 000000000000..ff9e8f0a9304
--- /dev/null
+++ b/lib/libc/tests/nss/testutil.h
@@ -0,0 +1,330 @@
+/*-
+ * Copyright (c) 2006 Michael Bushkov <bushman@freebsd.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/queue.h>
+
+#define DECLARE_TEST_DATA(ent) \
+struct ent##_entry { \
+ struct ent data; \
+ STAILQ_ENTRY(ent##_entry) entries; \
+}; \
+ \
+struct ent##_test_data { \
+ void (*clone_func)(struct ent *, struct ent const *); \
+ void (*free_func)(struct ent *); \
+ \
+ STAILQ_HEAD(ent_head, ent##_entry) snapshot_data; \
+}; \
+ \
+void __##ent##_test_data_init(struct ent##_test_data *, \
+ void (*)(struct ent *, struct ent const *), \
+ void (*freef)(struct ent *)); \
+void __##ent##_test_data_destroy(struct ent##_test_data *); \
+ \
+void __##ent##_test_data_append(struct ent##_test_data *, struct ent *data);\
+int __##ent##_test_data_foreach(struct ent##_test_data *, \
+ int (*)(struct ent *, void *), void *); \
+int __##ent##_test_data_compare(struct ent##_test_data *, \
+ struct ent##_test_data *, int (*)(struct ent *, struct ent *, \
+ void *), void *); \
+struct ent *__##ent##_test_data_find(struct ent##_test_data *, struct ent *,\
+ int (*)(struct ent *, struct ent *, void *), void *); \
+void __##ent##_test_data_clear(struct ent##_test_data *);
+
+#define TEST_DATA_INIT(ent, td, clonef, freef)\
+ __##ent##_test_data_init(td, clonef, freef)
+#define TEST_DATA_DESTROY(ent, td) __##ent##_test_data_destroy(td)
+#define TEST_DATA_APPEND(ent, td, d) __##ent##_test_data_append(td, d)
+#define TEST_DATA_FOREACH(ent, td, f, mdata)\
+ __##ent##_test_data_foreach(td, f, mdata)
+#define TEST_DATA_COMPARE(ent, td1, td2, fcmp, mdata)\
+ __##ent##_test_data_compare(td1, td2, fcmp, mdata);
+#define TEST_DATA_FIND(ent, td, d, fcmp, mdata)\
+ __##ent##_test_data_find(td, d, fcmp, mdata)
+#define TEST_DATA_CLEAR(ent, td) __##ent##_test_data_clear(td)
+
+#define IMPLEMENT_TEST_DATA(ent) \
+void \
+__##ent##_test_data_init(struct ent##_test_data *td, \
+ void (*clonef)(struct ent *, struct ent const *), \
+ void (*freef)(struct ent *)) \
+{ \
+ ATF_REQUIRE(td != NULL); \
+ ATF_REQUIRE(clonef != NULL); \
+ ATF_REQUIRE(freef != NULL); \
+ \
+ memset(td, 0, sizeof(*td)); \
+ td->clone_func = clonef; \
+ td->free_func = freef; \
+ STAILQ_INIT(&td->snapshot_data); \
+} \
+ \
+void \
+__##ent##_test_data_destroy(struct ent##_test_data *td) \
+{ \
+ __##ent##_test_data_clear(td); \
+} \
+ \
+void \
+__##ent##_test_data_append(struct ent##_test_data *td, struct ent *app_data)\
+{ \
+ struct ent##_entry *e; \
+ \
+ ATF_REQUIRE(td != NULL); \
+ ATF_REQUIRE(app_data != NULL); \
+ \
+ e = (struct ent##_entry *)malloc(sizeof(struct ent##_entry)); \
+ ATF_REQUIRE(e != NULL); \
+ memset(e, 0, sizeof(struct ent##_entry)); \
+ \
+ td->clone_func(&e->data, app_data); \
+ STAILQ_INSERT_TAIL(&td->snapshot_data, e, entries); \
+} \
+ \
+int \
+__##ent##_test_data_foreach(struct ent##_test_data *td, \
+ int (*forf)(struct ent *, void *), void *mdata) \
+{ \
+ struct ent##_entry *e; \
+ int rv; \
+ \
+ ATF_REQUIRE(td != NULL); \
+ ATF_REQUIRE(forf != NULL); \
+ \
+ rv = 0; \
+ STAILQ_FOREACH(e, &td->snapshot_data, entries) { \
+ rv = forf(&e->data, mdata); \
+ if (rv != 0) \
+ break; \
+ } \
+ \
+ return (rv); \
+} \
+ \
+int \
+__##ent##_test_data_compare(struct ent##_test_data *td1, struct ent##_test_data *td2,\
+ int (*cmp_func)(struct ent *, struct ent *, void *), void *mdata)\
+{ \
+ struct ent##_entry *e1, *e2; \
+ int rv; \
+ \
+ ATF_REQUIRE(td1 != NULL); \
+ ATF_REQUIRE(td2 != NULL); \
+ ATF_REQUIRE(cmp_func != NULL); \
+ \
+ e1 = STAILQ_FIRST(&td1->snapshot_data); \
+ e2 = STAILQ_FIRST(&td2->snapshot_data); \
+ \
+ rv = 0; \
+ do { \
+ if ((e1 == NULL) || (e2 == NULL)) { \
+ if (e1 == e2) \
+ return (0); \
+ else \
+ return (-1); \
+ } \
+ \
+ rv = cmp_func(&e1->data, &e2->data, mdata); \
+ e1 = STAILQ_NEXT(e1, entries); \
+ e2 = STAILQ_NEXT(e2, entries); \
+ } while (rv == 0); \
+ \
+ return (rv); \
+} \
+ \
+struct ent * \
+__##ent##_test_data_find(struct ent##_test_data *td, struct ent *data, \
+ int (*cmp)(struct ent *, struct ent *, void *), void *mdata) \
+{ \
+ struct ent##_entry *e; \
+ struct ent *result; \
+ \
+ ATF_REQUIRE(td != NULL); \
+ ATF_REQUIRE(cmp != NULL); \
+ \
+ result = NULL; \
+ STAILQ_FOREACH(e, &td->snapshot_data, entries) { \
+ if (cmp(&e->data, data, mdata) == 0) { \
+ result = &e->data; \
+ break; \
+ } \
+ } \
+ \
+ return (result); \
+} \
+ \
+ \
+void \
+__##ent##_test_data_clear(struct ent##_test_data *td) \
+{ \
+ struct ent##_entry *e; \
+ ATF_REQUIRE(td != NULL); \
+ \
+ while (!STAILQ_EMPTY(&td->snapshot_data)) { \
+ e = STAILQ_FIRST(&td->snapshot_data); \
+ STAILQ_REMOVE_HEAD(&td->snapshot_data, entries); \
+ \
+ td->free_func(&e->data); \
+ free(e); \
+ e = NULL; \
+ } \
+}
+
+#define DECLARE_TEST_FILE_SNAPSHOT(ent) \
+struct ent##_snp_param { \
+ FILE *fp; \
+ void (*sdump_func)(struct ent *, char *, size_t); \
+}; \
+ \
+int __##ent##_snapshot_write_func(struct ent *, void *); \
+int __##ent##_snapshot_write(char const *, struct ent##_test_data *, \
+ void (*)(struct ent *, char *, size_t)); \
+int __##ent##_snapshot_read(char const *, struct ent##_test_data *, \
+ int (*)(struct ent *, char *));
+
+#define TEST_SNAPSHOT_FILE_WRITE(ent, fname, td, f) \
+ __##ent##_snapshot_write(fname, td, f)
+#define TEST_SNAPSHOT_FILE_READ(ent, fname, td, f) \
+ __##ent##_snapshot_read(fname, td, f)
+
+#define IMPLEMENT_TEST_FILE_SNAPSHOT(ent) \
+int \
+__##ent##_snapshot_write_func(struct ent *data, void *mdata) \
+{ \
+ char buffer[1024]; \
+ struct ent##_snp_param *param; \
+ \
+ ATF_REQUIRE(data != NULL); \
+ \
+ param = (struct ent##_snp_param *)mdata; \
+ param->sdump_func(data, buffer, sizeof(buffer)); \
+ fputs(buffer, param->fp); \
+ fputc('\n', param->fp); \
+ \
+ return (0); \
+} \
+ \
+int \
+__##ent##_snapshot_write(char const *fname, struct ent##_test_data *td, \
+ void (*sdump_func)(struct ent *, char *, size_t)) \
+{ \
+ struct ent##_snp_param param; \
+ \
+ ATF_REQUIRE(fname != NULL); \
+ ATF_REQUIRE(td != NULL); \
+ \
+ param.fp = fopen(fname, "w"); \
+ if (param.fp == NULL) \
+ return (-1); \
+ \
+ param.sdump_func = sdump_func; \
+ __##ent##_test_data_foreach(td, __##ent##_snapshot_write_func, &param);\
+ fclose(param.fp); \
+ \
+ return (0); \
+} \
+ \
+int \
+__##ent##_snapshot_read(char const *fname, struct ent##_test_data *td, \
+ int (*read_func)(struct ent *, char *)) \
+{ \
+ struct ent data; \
+ FILE *fi; \
+ size_t len; \
+ int rv; \
+ \
+ ATF_REQUIRE(fname != NULL); \
+ ATF_REQUIRE(td != NULL); \
+ \
+ fi = fopen(fname, "r"); \
+ if (fi == NULL) \
+ return (-1); \
+ \
+ rv = 0; \
+ while (!feof(fi)) { \
+ char *buf = fgetln(fi, &len); \
+ if (buf == NULL || len <= 1) \
+ continue; \
+ if (buf[len - 1] == '\n') \
+ buf[len - 1] = '\0'; \
+ else \
+ buf[len] = '\0'; \
+ if (buf[0] == '#') \
+ continue; \
+ rv = read_func(&data, buf); \
+ if (rv == 0) { \
+ __##ent##_test_data_append(td, &data); \
+ td->free_func(&data); \
+ } else \
+ goto fin; \
+ } \
+ \
+fin: \
+ fclose(fi); \
+ return (rv); \
+}
+
+#define DECLARE_1PASS_TEST(ent) \
+int __##ent##_1pass_test(struct ent##_test_data *, \
+ int (*)(struct ent *, void *), \
+ void *);
+
+#define DO_1PASS_TEST(ent, td, f, mdata) \
+ __##ent##_1pass_test(td, f, mdata)
+
+#define IMPLEMENT_1PASS_TEST(ent) \
+int \
+__##ent##_1pass_test(struct ent##_test_data *td, \
+ int (*tf)(struct ent *, void *), \
+ void *mdata) \
+{ \
+ int rv; \
+ rv = __##ent##_test_data_foreach(td, tf, mdata); \
+ \
+ return (rv); \
+}
+
+#define DECLARE_2PASS_TEST(ent) \
+int __##ent##_2pass_test(struct ent##_test_data *, \
+ struct ent##_test_data *, \
+ int (*)(struct ent *, struct ent *, void *), void *);
+
+#define DO_2PASS_TEST(ent, td1, td2, f, mdata) \
+ __##ent##_2pass_test(td1, td2, f, mdata)
+
+#define IMPLEMENT_2PASS_TEST(ent) \
+int \
+__##ent##_2pass_test(struct ent##_test_data *td1, \
+ struct ent##_test_data *td2, \
+ int (*cmp_func)(struct ent *, struct ent *, void *), \
+ void *cmp_mdata) \
+{ \
+ int rv; \
+ \
+ rv = __##ent##_test_data_compare(td1, td2, cmp_func, cmp_mdata); \
+ return (rv); \
+}
diff --git a/lib/libc/tests/regex/Makefile b/lib/libc/tests/regex/Makefile
new file mode 100644
index 000000000000..c4f43512623d
--- /dev/null
+++ b/lib/libc/tests/regex/Makefile
@@ -0,0 +1,62 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+PACKAGE= tests
+
+BINDIR= ${TESTSDIR}
+
+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
+
+${PACKAGE}FILES+= README
+
+FILESGROUPS+= ${PACKAGE}DATA_FILES
+${PACKAGE}DATA_FILESPACKAGE=${PACKAGE}
+
+${PACKAGE}DATA_FILESDIR= ${TESTSDIR}/data
+${PACKAGE}DATA_FILES+= data/anchor.in
+${PACKAGE}DATA_FILES+= data/backref.in
+${PACKAGE}DATA_FILES+= data/basic.in
+${PACKAGE}DATA_FILES+= data/bracket.in
+${PACKAGE}DATA_FILES+= data/c_comments.in
+${PACKAGE}DATA_FILES+= data/complex.in
+${PACKAGE}DATA_FILES+= data/error.in
+${PACKAGE}DATA_FILES+= data/meta.in
+${PACKAGE}DATA_FILES+= data/nospec.in
+${PACKAGE}DATA_FILES+= data/paren.in
+${PACKAGE}DATA_FILES+= data/regress.in
+${PACKAGE}DATA_FILES+= data/repet_bounded.in
+${PACKAGE}DATA_FILES+= data/repet_multi.in
+${PACKAGE}DATA_FILES+= data/repet_ordinary.in
+${PACKAGE}DATA_FILES+= data/startend.in
+${PACKAGE}DATA_FILES+= data/subexp.in
+${PACKAGE}DATA_FILES+= data/subtle.in
+${PACKAGE}DATA_FILES+= data/word_bound.in
+${PACKAGE}DATA_FILES+= data/zero.in
+#${PACKAGE}DATA_FILES+= data/att/README
+${PACKAGE}DATA_FILES+= data/att/basic.dat
+${PACKAGE}DATA_FILES+= data/att/categorization.dat
+${PACKAGE}DATA_FILES+= data/att/forcedassoc.dat
+${PACKAGE}DATA_FILES+= data/att/leftassoc.dat
+${PACKAGE}DATA_FILES+= data/att/nullsubexpr.dat
+${PACKAGE}DATA_FILES+= data/att/repetition.dat
+${PACKAGE}DATA_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"
+
+LIBADD.regex_att_test+= util
+
+.include <bsd.test.mk>
diff --git a/lib/libc/tests/regex/Makefile.depend b/lib/libc/tests/regex/Makefile.depend
new file mode 100644
index 000000000000..5212dd0e39f5
--- /dev/null
+++ b/lib/libc/tests/regex/Makefile.depend
@@ -0,0 +1,21 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ gnu/lib/csu \
+ gnu/lib/libgcc \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/atf/libatf-c \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libnetbsd \
+ lib/libutil \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/lib/libc/tests/resolv/Makefile b/lib/libc/tests/resolv/Makefile
new file mode 100644
index 000000000000..cb82da67c4f7
--- /dev/null
+++ b/lib/libc/tests/resolv/Makefile
@@ -0,0 +1,15 @@
+# $FreeBSD$
+
+PACKAGE= tests
+
+TESTSDIR= ${TESTSBASE}/lib/libc/resolv
+
+${PACKAGE}FILES+= mach
+
+ATF_TESTS_C+= resolv_test
+
+# Note: this test relies on being dynamically linked. You will get a
+# spurious PASS for a statically linked test.
+LIBADD.resolv_test+= pthread
+
+.include <bsd.test.mk>
diff --git a/lib/libc/tests/resolv/Makefile.depend b/lib/libc/tests/resolv/Makefile.depend
new file mode 100644
index 000000000000..505fe5ac3403
--- /dev/null
+++ b/lib/libc/tests/resolv/Makefile.depend
@@ -0,0 +1,20 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ gnu/lib/csu \
+ gnu/lib/libgcc \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/atf/libatf-c \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libthr \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/lib/libc/tests/resolv/mach b/lib/libc/tests/resolv/mach
new file mode 100644
index 000000000000..4b47ebb73448
--- /dev/null
+++ b/lib/libc/tests/resolv/mach
@@ -0,0 +1,46 @@
+# $FreeBSD$
+localhost
+anoncvs.cirr.com
+anoncvs.netbsd.se
+antioche.antioche.eu.org
+centaurus.4web.cz
+chur.math.ntnu.no
+console.netbsd.org
+cvs.netbsd.org
+cvsup.netbsd.se
+ftp.chg.ru
+ftp.estpak.ee
+ftp.fsn.hu
+ftp.funet.fi
+ftp.netbsd.org
+ftp.nluug.nl
+ftp.plig.org
+ftp.uni-erlangen.de
+ftp.xgate.co.kr
+gd.tuwien.ac.at
+gort.ludd.luth.se
+irc.warped.net
+knug.youn.co.kr
+mail.jp.netbsd.org
+mail.netbsd.org
+melanoma.cs.rmit.edu.au
+mirror.aarnet.edu.au
+moon.vub.ac.be
+net.bsd.cz
+netbsd.3miasto.net
+netbsd.4ka.mipt.ru
+netbsd.csie.nctu.edu.tw
+netbsd.enderunix.org
+netbsd.ftp.fu-berlin.de
+netbsd.pair.com
+netbsdiso.interoute.net.uk
+netbsdwww.cs.rmit.edu.au
+netbsdwww.interoute.net.uk
+ns.netbsd.org
+skeleton.phys.spbu.ru
+www.en.netbsd.de
+www.netbsd.cl
+www.netbsd.nl
+www.netbsd.org
+www.netbsd.ro
+zeppo.rediris.es
diff --git a/lib/libc/tests/resolv/resolv_test.c b/lib/libc/tests/resolv/resolv_test.c
new file mode 100644
index 000000000000..1da42e3bcd18
--- /dev/null
+++ b/lib/libc/tests/resolv/resolv_test.c
@@ -0,0 +1,331 @@
+/* $NetBSD: resolv.c,v 1.6 2004/05/23 16:59:11 christos Exp $ */
+
+/*-
+ * Copyright (c) 2004 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/* $FreeBSD$ */
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: resolv.c,v 1.6 2004/05/23 16:59:11 christos Exp $");
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stringlist.h>
+
+#include <atf-c.h>
+
+#define NTHREADS 10
+#define NHOSTS 100
+#define WS " \t\n\r"
+
+enum method {
+ METHOD_GETADDRINFO,
+ METHOD_GETHOSTBY,
+ METHOD_GETIPNODEBY
+};
+
+static StringList *hosts = NULL;
+static enum method method = METHOD_GETADDRINFO;
+static int *ask = NULL;
+static int *got = NULL;
+
+static void load(const char *);
+static void resolvone(int);
+static void *resolvloop(void *);
+static void run(int *);
+
+static pthread_mutex_t stats = PTHREAD_MUTEX_INITIALIZER;
+
+static void
+load(const char *fname)
+{
+ FILE *fp;
+ size_t len;
+ char *line;
+
+ if ((fp = fopen(fname, "r")) == NULL)
+ ATF_REQUIRE(fp != NULL);
+ while ((line = fgetln(fp, &len)) != NULL) {
+ char c = line[len];
+ char *ptr;
+ line[len] = '\0';
+ for (ptr = strtok(line, WS); ptr; ptr = strtok(NULL, WS)) {
+ if (ptr == '\0' || ptr[0] == '#')
+ continue;
+ sl_add(hosts, strdup(ptr));
+ }
+ line[len] = c;
+ }
+
+ (void)fclose(fp);
+}
+
+static int
+resolv_getaddrinfo(pthread_t self, char *host, int port)
+{
+ char portstr[6], buf[1024], hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
+ struct addrinfo hints, *res;
+ int error, len;
+
+ snprintf(portstr, sizeof(portstr), "%d", port);
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_socktype = SOCK_STREAM;
+ error = getaddrinfo(host, portstr, &hints, &res);
+ len = snprintf(buf, sizeof(buf), "%p: host %s %s\n",
+ self, host, error ? "not found" : "ok");
+ (void)write(STDOUT_FILENO, buf, len);
+ if (error == 0) {
+ memset(hbuf, 0, sizeof(hbuf));
+ memset(pbuf, 0, sizeof(pbuf));
+ getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, sizeof(hbuf),
+ pbuf, sizeof(pbuf), 0);
+ len = snprintf(buf, sizeof(buf),
+ "%p: reverse %s %s\n", self, hbuf, pbuf);
+ (void)write(STDOUT_FILENO, buf, len);
+ }
+ if (error == 0)
+ freeaddrinfo(res);
+ return error;
+}
+
+static int
+resolv_gethostby(pthread_t self, char *host)
+{
+ char buf[1024];
+ struct hostent *hp, *hp2;
+ int len;
+
+ hp = gethostbyname(host);
+ len = snprintf(buf, sizeof(buf), "%p: host %s %s\n",
+ self, host, (hp == NULL) ? "not found" : "ok");
+ (void)write(STDOUT_FILENO, buf, len);
+ if (hp) {
+ memcpy(buf, hp->h_addr, hp->h_length);
+ hp2 = gethostbyaddr(buf, hp->h_length, hp->h_addrtype);
+ if (hp2) {
+ len = snprintf(buf, sizeof(buf),
+ "%p: reverse %s\n", self, hp2->h_name);
+ (void)write(STDOUT_FILENO, buf, len);
+ }
+ }
+ return hp ? 0 : -1;
+}
+
+static int
+resolv_getipnodeby(pthread_t self, char *host)
+{
+ char buf[1024];
+ struct hostent *hp, *hp2;
+ int len, h_error;
+
+ hp = getipnodebyname(host, AF_INET, 0, &h_error);
+ len = snprintf(buf, sizeof(buf), "%p: host %s %s\n",
+ self, host, (hp == NULL) ? "not found" : "ok");
+ (void)write(STDOUT_FILENO, buf, len);
+ if (hp) {
+ memcpy(buf, hp->h_addr, hp->h_length);
+ hp2 = getipnodebyaddr(buf, hp->h_length, hp->h_addrtype,
+ &h_error);
+ if (hp2) {
+ len = snprintf(buf, sizeof(buf),
+ "%p: reverse %s\n", self, hp2->h_name);
+ (void)write(STDOUT_FILENO, buf, len);
+ }
+ if (hp2)
+ freehostent(hp2);
+ }
+ if (hp)
+ freehostent(hp);
+ return hp ? 0 : -1;
+}
+
+static void
+resolvone(int n)
+{
+ char buf[1024];
+ pthread_t self = pthread_self();
+ size_t i = (random() & 0x0fffffff) % hosts->sl_cur;
+ char *host = hosts->sl_str[i];
+ struct addrinfo hints, *res;
+ int error, len;
+
+ len = snprintf(buf, sizeof(buf), "%p: %d resolving %s %d\n",
+ self, n, host, (int)i);
+ (void)write(STDOUT_FILENO, buf, len);
+ switch (method) {
+ case METHOD_GETADDRINFO:
+ error = resolv_getaddrinfo(self, host, i);
+ break;
+ case METHOD_GETHOSTBY:
+ error = resolv_gethostby(self, host);
+ break;
+ case METHOD_GETIPNODEBY:
+ error = resolv_getipnodeby(self, host);
+ break;
+ default:
+ break;
+ }
+ pthread_mutex_lock(&stats);
+ ask[i]++;
+ got[i] += error == 0;
+ pthread_mutex_unlock(&stats);
+}
+
+static void *
+resolvloop(void *p)
+{
+ int *nhosts = (int *)p;
+ if (*nhosts == 0)
+ return NULL;
+ do
+ resolvone(*nhosts);
+ while (--(*nhosts));
+ return NULL;
+}
+
+static void
+run(int *nhosts)
+{
+ pthread_t self;
+ int rc;
+
+ self = pthread_self();
+ rc = pthread_create(&self, NULL, resolvloop, nhosts);
+ ATF_REQUIRE_MSG(rc == 0, "pthread_create failed: %s", strerror(rc));
+}
+
+static int
+run_tests(const char *hostlist_file, enum method method)
+{
+ int nthreads = NTHREADS;
+ int nhosts = NHOSTS;
+ int i, c, done, *nleft;
+ hosts = sl_init();
+
+ srandom(1234);
+
+ load(hostlist_file);
+
+ ATF_REQUIRE_MSG(0 < hosts->sl_cur, "0 hosts in %s", hostlist_file);
+
+ nleft = malloc(nthreads * sizeof(int));
+ ATF_REQUIRE(nleft != NULL);
+
+ ask = calloc(hosts->sl_cur, sizeof(int));
+ ATF_REQUIRE(ask != NULL);
+
+ got = calloc(hosts->sl_cur, sizeof(int));
+ ATF_REQUIRE(got != NULL);
+
+ for (i = 0; i < nthreads; i++) {
+ nleft[i] = nhosts;
+ run(&nleft[i]);
+ }
+
+ for (done = 0; !done;) {
+ done = 1;
+ for (i = 0; i < nthreads; i++) {
+ if (nleft[i] != 0) {
+ done = 0;
+ break;
+ }
+ }
+ sleep(1);
+ }
+ c = 0;
+ for (i = 0; i < hosts->sl_cur; i++) {
+ if (ask[i] != got[i] && got[i] != 0) {
+ printf("Error: host %s ask %d got %d\n",
+ hosts->sl_str[i], ask[i], got[i]);
+ c++;
+ }
+ }
+ free(nleft);
+ free(ask);
+ free(got);
+ sl_free(hosts, 1);
+ return c;
+}
+
+#define HOSTLIST_FILE "mach"
+
+#define RUN_TESTS(tc, method) \
+do { \
+ char *_hostlist_file; \
+ ATF_REQUIRE(0 < asprintf(&_hostlist_file, "%s/%s", \
+ atf_tc_get_config_var(tc, "srcdir"), HOSTLIST_FILE)); \
+ ATF_REQUIRE(run_tests(_hostlist_file, method) == 0); \
+} while(0)
+
+ATF_TC(getaddrinfo_test);
+ATF_TC_HEAD(getaddrinfo_test, tc) {
+ atf_tc_set_md_var(tc, "timeout", "1200");
+}
+ATF_TC_BODY(getaddrinfo_test, tc)
+{
+
+ RUN_TESTS(tc, METHOD_GETADDRINFO);
+}
+
+ATF_TC(gethostby_test);
+ATF_TC_HEAD(gethostby_test, tc) {
+ atf_tc_set_md_var(tc, "timeout", "1200");
+}
+ATF_TC_BODY(gethostby_test, tc)
+{
+
+ RUN_TESTS(tc, METHOD_GETHOSTBY);
+}
+
+ATF_TC(getipnodeby_test);
+ATF_TC_HEAD(getipnodeby_test, tc) {
+
+ atf_tc_set_md_var(tc, "timeout", "1200");
+}
+ATF_TC_BODY(getipnodeby_test, tc)
+{
+
+ RUN_TESTS(tc, METHOD_GETIPNODEBY);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, getaddrinfo_test);
+ ATF_TP_ADD_TC(tp, gethostby_test);
+ ATF_TP_ADD_TC(tp, getipnodeby_test);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/rpc/Makefile b/lib/libc/tests/rpc/Makefile
new file mode 100644
index 000000000000..d7780ef4b86c
--- /dev/null
+++ b/lib/libc/tests/rpc/Makefile
@@ -0,0 +1,25 @@
+# $FreeBSD$
+
+SRCS.xdr_test= ${RPCSRC:.x=_xdr.c} t_xdr.c ${RPCSRC:.x=.h} \
+ h_testbits.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}
+
+LIBADD+= rpcsvc util
+
+.include "../Makefile.netbsd-tests"
+
+.include <bsd.test.mk>
diff --git a/lib/libc/tests/rpc/Makefile.depend b/lib/libc/tests/rpc/Makefile.depend
new file mode 100644
index 000000000000..7cd75155dd46
--- /dev/null
+++ b/lib/libc/tests/rpc/Makefile.depend
@@ -0,0 +1,23 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ gnu/lib/csu \
+ gnu/lib/libgcc \
+ include \
+ include/rpc \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/atf/libatf-c \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libnetbsd \
+ lib/librpcsvc \
+ lib/libutil \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/lib/libc/tests/setjmp/Makefile b/lib/libc/tests/setjmp/Makefile
new file mode 100644
index 000000000000..39b0a96295f4
--- /dev/null
+++ b/lib/libc/tests/setjmp/Makefile
@@ -0,0 +1,12 @@
+# $FreeBSD$
+
+NETBSD_ATF_TESTS_C= setjmp_test
+NETBSD_ATF_TESTS_C+= threadjmp_test
+
+LIBADD.t_threadjmp+= pthread
+
+WARNS?= 4
+
+.include "../Makefile.netbsd-tests"
+
+.include <bsd.test.mk>
diff --git a/lib/libc/tests/setjmp/Makefile.depend b/lib/libc/tests/setjmp/Makefile.depend
new file mode 100644
index 000000000000..e8ee295f115a
--- /dev/null
+++ b/lib/libc/tests/setjmp/Makefile.depend
@@ -0,0 +1,20 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ gnu/lib/csu \
+ gnu/lib/libgcc \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/atf/libatf-c \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libnetbsd \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/lib/libc/tests/ssp/Makefile b/lib/libc/tests/ssp/Makefile
new file mode 100644
index 000000000000..5e0cca1fadf5
--- /dev/null
+++ b/lib/libc/tests/ssp/Makefile
@@ -0,0 +1,70 @@
+# $FreeBSD$
+
+# XXX This is a workaround to allow i386 to cross-compile on an amd64 host.
+.include <host-target.mk>
+# XXX ---
+
+.include <bsd.own.mk>
+
+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
+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
+# This testcase doesn't run properly when not compiled with -fsantize=bounds
+# with clang, which is currently contingent on a compiler_rt update
+#
+# XXX: the h_raw/h_read testcases don't cause a SIGABRT with in-tree gcc right
+# now on amd64 when it trips the stack bounds specified in t_ssp.sh . This
+# probably needs to be fixed as it's currently hardcoded.
+#
+# sanitizer is not tested or supported for ARM right now. sbruno
+.if ${MACHINE_CPUARCH} == "i386" || ${MACHINE_CPUARCH} == "amd64"
+.if ${COMPILER_TYPE} == "clang" && ${MK_TOOLCHAIN} == "yes"
+.if ${COMPILER_VERSION} < 30500 || 30700 <= ${COMPILER_VERSION}
+
+# XXX This is a workaround to allow i386 to cross-compile on an amd64 host.
+.if ${MACHINE_CPUARCH} == ${_HOST_ARCH}
+# XXX ---
+
+PROGS+= h_raw
+
+# XXX This is a workaround to allow i386 to cross-compile on an amd64 host.
+.endif
+# XXX ---
+
+.endif
+.endif
+.endif
+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/ssp/Makefile.depend b/lib/libc/tests/ssp/Makefile.depend
new file mode 100644
index 000000000000..bb203f1bf8c2
--- /dev/null
+++ b/lib/libc/tests/ssp/Makefile.depend
@@ -0,0 +1,21 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ gnu/lib/csu \
+ gnu/lib/libgcc \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/librt \
+ lib/libthr \
+ lib/msun \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/lib/libc/tests/stdio/Makefile b/lib/libc/tests/stdio/Makefile
new file mode 100644
index 000000000000..7ebe3ffe052f
--- /dev/null
+++ b/lib/libc/tests/stdio/Makefile
@@ -0,0 +1,43 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+ATF_TESTS_C+= fdopen_test
+ATF_TESTS_C+= fmemopen2_test
+ATF_TESTS_C+= fopen2_test
+ATF_TESTS_C+= freopen_test
+ATF_TESTS_C+= getdelim_test
+ATF_TESTS_C+= mkostemp_test
+ATF_TESTS_C+= open_memstream2_test
+ATF_TESTS_C+= open_wmemstream_test
+ATF_TESTS_C+= perror_test
+ATF_TESTS_C+= print_positional_test
+ATF_TESTS_C+= printbasic_test
+ATF_TESTS_C+= printfloat_test
+ATF_TESTS_C+= scanfloat_test
+
+SRCS.fopen2_test= fopen_test.c
+
+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+= open_memstream_test
+NETBSD_ATF_TESTS_C+= popen_test
+NETBSD_ATF_TESTS_C+= printf_test
+NETBSD_ATF_TESTS_C+= scanf_test
+
+LIBADD.printfloat_test+= m
+LIBADD.scanfloat_test+= m
+
+.if ${COMPILER_TYPE} == "gcc"
+# 90: use of assignment suppression and length modifier together in scanf format
+PROG_OVERRIDE_VARS+= NO_WFORMAT
+NO_WFORMAT.scanfloat_test=
+.endif
+
+.include "../Makefile.netbsd-tests"
+
+.include <bsd.test.mk>
diff --git a/lib/libc/tests/stdio/Makefile.depend b/lib/libc/tests/stdio/Makefile.depend
new file mode 100644
index 000000000000..68a9dd09c55e
--- /dev/null
+++ b/lib/libc/tests/stdio/Makefile.depend
@@ -0,0 +1,21 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ gnu/lib/csu \
+ gnu/lib/libgcc \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/atf/libatf-c \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libnetbsd \
+ lib/msun \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/lib/libc/tests/stdio/fdopen_test.c b/lib/libc/tests/stdio/fdopen_test.c
new file mode 100644
index 000000000000..060635af498b
--- /dev/null
+++ b/lib/libc/tests/stdio/fdopen_test.c
@@ -0,0 +1,225 @@
+/*-
+ * Copyright (c) 2014 Jilles Tjoelker
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <atf-c.h>
+
+static void
+runtest(const char *fname, int intmode, const char *strmode, bool success)
+{
+ FILE *fp;
+ int fd;
+
+ fd = open(fname, intmode);
+ ATF_REQUIRE_MSG(fd != -1,
+ "open(\"%s\", %#x) failed; errno=%d", fname, intmode, errno);
+
+ fp = fdopen(fd, strmode);
+ if (fp == NULL) {
+ close(fd);
+ ATF_REQUIRE_MSG(success == false,
+ "fdopen(open(\"%s\", %#x), \"%s\") succeeded unexpectedly",
+ fname, intmode, strmode);
+ return;
+ }
+ ATF_REQUIRE_MSG(success == true,
+ "fdopen(open(\"%s\", %#x), \"%s\") failed; errno=%d",
+ fname, intmode, strmode, errno);
+ fclose(fp);
+}
+
+ATF_TC_WITHOUT_HEAD(null__O_RDONLY__r_test);
+ATF_TC_BODY(null__O_RDONLY__r_test, tc)
+{
+
+ runtest(_PATH_DEVNULL, O_RDONLY, "r", true);
+}
+
+ATF_TC_WITHOUT_HEAD(null__O_WRONLY__r_test);
+ATF_TC_BODY(null__O_WRONLY__r_test, tc)
+{
+
+ runtest(_PATH_DEVNULL, O_WRONLY, "r", false);
+}
+
+ATF_TC_WITHOUT_HEAD(null__O_RDWR__r_test);
+ATF_TC_BODY(null__O_RDWR__r_test, tc)
+{
+
+ runtest(_PATH_DEVNULL, O_RDWR, "r", true);
+}
+
+ATF_TC_WITHOUT_HEAD(null__O_RDONLY__w_test);
+ATF_TC_BODY(null__O_RDONLY__w_test, tc)
+{
+
+ runtest(_PATH_DEVNULL, O_RDONLY, "w", false);
+}
+
+ATF_TC_WITHOUT_HEAD(null__O_WRONLY__w_test);
+ATF_TC_BODY(null__O_WRONLY__w_test, tc)
+{
+
+ runtest(_PATH_DEVNULL, O_WRONLY, "w", true);
+}
+
+ATF_TC_WITHOUT_HEAD(null__O_RDWR__w_test);
+ATF_TC_BODY(null__O_RDWR__w_test, tc)
+{
+
+ runtest(_PATH_DEVNULL, O_RDWR, "w", true);
+}
+
+ATF_TC_WITHOUT_HEAD(null__O_RDONLY__a_test);
+ATF_TC_BODY(null__O_RDONLY__a_test, tc)
+{
+
+ runtest(_PATH_DEVNULL, O_RDONLY, "a", false);
+}
+
+ATF_TC_WITHOUT_HEAD(null__O_WRONLY__a_test);
+ATF_TC_BODY(null__O_WRONLY__a_test, tc)
+{
+
+ runtest(_PATH_DEVNULL, O_WRONLY, "a", true);
+}
+
+ATF_TC_WITHOUT_HEAD(null__O_RDWR__test);
+ATF_TC_BODY(null__O_RDWR__test, tc)
+{
+
+ runtest(_PATH_DEVNULL, O_RDWR, "a", true);
+}
+
+ATF_TC_WITHOUT_HEAD(null__O_RDONLY__r_append);
+ATF_TC_BODY(null__O_RDONLY__r_append, tc)
+{
+
+ runtest(_PATH_DEVNULL, O_RDONLY, "r+", false);
+}
+
+ATF_TC_WITHOUT_HEAD(null__O_WRONLY__r_append);
+ATF_TC_BODY(null__O_WRONLY__r_append, tc)
+{
+
+ runtest(_PATH_DEVNULL, O_WRONLY, "r+", false);
+}
+
+ATF_TC_WITHOUT_HEAD(null__O_RDWR__r_append);
+ATF_TC_BODY(null__O_RDWR__r_append, tc)
+{
+
+ runtest(_PATH_DEVNULL, O_RDWR, "r+", true);
+}
+
+ATF_TC_WITHOUT_HEAD(null__O_RDONLY__w_append);
+ATF_TC_BODY(null__O_RDONLY__w_append, tc)
+{
+
+ runtest(_PATH_DEVNULL, O_RDONLY, "w+", false);
+}
+
+ATF_TC_WITHOUT_HEAD(null__O_WRONLY__w_append);
+ATF_TC_BODY(null__O_WRONLY__w_append, tc)
+{
+
+ runtest(_PATH_DEVNULL, O_WRONLY, "w+", false);
+}
+
+ATF_TC_WITHOUT_HEAD(null__O_RDWR__w_append);
+ATF_TC_BODY(null__O_RDWR__w_append, tc)
+{
+
+ runtest(_PATH_DEVNULL, O_RDWR, "w+", true);
+}
+
+ATF_TC_WITHOUT_HEAD(sh__O_EXEC__r);
+ATF_TC_BODY(sh__O_EXEC__r, tc)
+{
+
+ runtest("/bin/sh", O_EXEC, "r", false);
+}
+
+ATF_TC_WITHOUT_HEAD(sh__O_EXEC__w);
+ATF_TC_BODY(sh__O_EXEC__w, tc)
+{
+
+ runtest("/bin/sh", O_EXEC, "w", false);
+}
+
+ATF_TC_WITHOUT_HEAD(sh__O_EXEC__r_append);
+ATF_TC_BODY(sh__O_EXEC__r_append, tc)
+{
+
+ runtest("/bin/sh", O_EXEC, "r+", false);
+}
+
+ATF_TC_WITHOUT_HEAD(sh__O_EXEC__w_append);
+ATF_TC_BODY(sh__O_EXEC__w_append, tc)
+{
+
+ runtest("/bin/sh", O_EXEC, "w+", false);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, null__O_RDONLY__r_test);
+ ATF_TP_ADD_TC(tp, null__O_WRONLY__r_test);
+ ATF_TP_ADD_TC(tp, null__O_RDWR__r_test);
+ ATF_TP_ADD_TC(tp, null__O_RDONLY__w_test);
+ ATF_TP_ADD_TC(tp, null__O_WRONLY__w_test);
+ ATF_TP_ADD_TC(tp, null__O_RDWR__w_test);
+ ATF_TP_ADD_TC(tp, null__O_RDONLY__a_test);
+ ATF_TP_ADD_TC(tp, null__O_WRONLY__a_test);
+ ATF_TP_ADD_TC(tp, null__O_RDWR__test);
+ ATF_TP_ADD_TC(tp, null__O_RDONLY__r_append);
+ ATF_TP_ADD_TC(tp, null__O_WRONLY__r_append);
+ ATF_TP_ADD_TC(tp, null__O_RDWR__r_append);
+ ATF_TP_ADD_TC(tp, null__O_RDONLY__w_append);
+ ATF_TP_ADD_TC(tp, null__O_WRONLY__w_append);
+ ATF_TP_ADD_TC(tp, null__O_RDWR__w_append);
+ ATF_TP_ADD_TC(tp, sh__O_EXEC__r);
+ ATF_TP_ADD_TC(tp, sh__O_EXEC__w);
+ ATF_TP_ADD_TC(tp, sh__O_EXEC__r_append);
+ ATF_TP_ADD_TC(tp, sh__O_EXEC__w_append);
+
+ return (atf_no_error());
+}
+
+/*
+ vim:ts=8:cin:sw=8
+ */
diff --git a/lib/libc/tests/stdio/fmemopen2_test.c b/lib/libc/tests/stdio/fmemopen2_test.c
new file mode 100644
index 000000000000..a2ca3257fe4e
--- /dev/null
+++ b/lib/libc/tests/stdio/fmemopen2_test.c
@@ -0,0 +1,288 @@
+/*-
+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);
+ ATF_REQUIRE(rc == 0);
+
+ /* Check that the string was not modified after the first 4 bytes. */
+ ATF_REQUIRE(strcmp(str, str3) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(test_autoalloc);
+ATF_TC_BODY(test_autoalloc, tc)
+{
+ /* Let fmemopen allocate the buffer. */
+ FILE *fp;
+ long pos;
+ size_t nofw, i;
+ int rc;
+
+ /* Open a FILE * using fmemopen. */
+ fp = fmemopen(NULL, 512, "w+");
+ ATF_REQUIRE(fp != NULL);
+
+ /* fill the buffer */
+ for (i = 0; i < 512; i++) {
+ nofw = fwrite("a", 1, 1, fp);
+ ATF_REQUIRE(nofw == 1);
+ }
+
+ /* Get the current position into the stream. */
+ pos = ftell(fp);
+ ATF_REQUIRE(pos == 512);
+
+ /* Try to write past the end, we should get a short object count (0) */
+ nofw = fwrite("a", 1, 1, fp);
+ ATF_REQUIRE(nofw == 0);
+
+ /* Close the FILE *. */
+ rc = fclose(fp);
+ ATF_REQUIRE(rc == 0);
+
+ /* Open a FILE * using a wrong mode */
+ fp = fmemopen(NULL, 512, "r");
+ ATF_REQUIRE(fp == NULL);
+
+ fp = fmemopen(NULL, 512, "w");
+ ATF_REQUIRE(fp == NULL);
+}
+
+ATF_TC_WITHOUT_HEAD(test_data_length);
+ATF_TC_BODY(test_data_length, tc)
+{
+ /*
+ * Here we test that a read operation doesn't go past the end of the
+ * data actually written, and that a SEEK_END seeks from the end of the
+ * data, not of the whole buffer.
+ */
+ FILE *fp;
+ char buf[512] = {'\0'};
+ char str[] = "Test data length. ";
+ char str2[] = "Do we have two sentences?";
+ char str3[sizeof(str) + sizeof(str2) -1];
+ long pos;
+ size_t nofw, nofr;
+ int rc;
+
+ /* Open a FILE * for updating our buffer. */
+ fp = fmemopen(buf, sizeof(buf), "w+");
+ ATF_REQUIRE(fp != NULL);
+
+ /* Write our string into the buffer. */
+ nofw = fwrite(str, 1, sizeof(str), fp);
+ ATF_REQUIRE(nofw == sizeof(str));
+
+ /* Now seek to the end and check that ftell gives us sizeof(str). */
+ rc = fseek(fp, 0, SEEK_END);
+ ATF_REQUIRE(rc == 0);
+ pos = ftell(fp);
+ ATF_REQUIRE(pos == sizeof(str));
+
+ /* Close the FILE *. */
+ rc = fclose(fp);
+ ATF_REQUIRE(rc == 0);
+
+ /* Reopen the buffer for appending. */
+ fp = fmemopen(buf, sizeof(buf), "a+");
+ ATF_REQUIRE(fp != NULL);
+
+ /* We should now be writing after the first string. */
+ nofw = fwrite(str2, 1, sizeof(str2), fp);
+ ATF_REQUIRE(nofw == sizeof(str2));
+
+ /* Rewind the FILE *. */
+ rc = fseek(fp, 0, SEEK_SET);
+ ATF_REQUIRE(rc == 0);
+
+ /* Make sure we're at the beginning. */
+ pos = ftell(fp);
+ ATF_REQUIRE(pos == 0);
+
+ /* Read the whole buffer. */
+ nofr = fread(str3, 1, sizeof(buf), fp);
+ ATF_REQUIRE(nofr == sizeof(str3));
+
+ /* Make sure the two strings are there. */
+ ATF_REQUIRE(strncmp(str3, str, sizeof(str) - 1) == 0);
+ ATF_REQUIRE(strncmp(str3 + sizeof(str) - 1, str2, sizeof(str2)) == 0);
+
+ /* Close the FILE *. */
+ rc = fclose(fp);
+ ATF_REQUIRE(rc == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(test_binary);
+ATF_TC_BODY(test_binary, tc)
+{
+ /*
+ * Make sure that NULL bytes are never appended when opening a buffer
+ * in binary mode.
+ */
+
+ FILE *fp;
+ char buf[20];
+ char str[] = "Test";
+ size_t nofw;
+ int rc, i;
+
+ /* Pre-fill the buffer. */
+ memset(buf, 'A', sizeof(buf));
+
+ /* Open a FILE * in binary mode. */
+ fp = fmemopen(buf, sizeof(buf), "w+b");
+ ATF_REQUIRE(fp != NULL);
+
+ /* Write some data into it. */
+ nofw = fwrite(str, 1, strlen(str), fp);
+ ATF_REQUIRE(nofw == strlen(str));
+
+ /* Make sure that the buffer doesn't contain any NULL bytes. */
+ for (i = 0; i < sizeof(buf); i++)
+ ATF_REQUIRE(buf[i] != '\0');
+
+ /* Close the FILE *. */
+ rc = fclose(fp);
+ ATF_REQUIRE(rc == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(test_append_binary_pos);
+ATF_TC_BODY(test_append_binary_pos, tc)
+{
+ /*
+ * For compatibility with other implementations (glibc), we set the
+ * position to 0 when opening an automatically allocated binary stream
+ * for appending.
+ */
+
+ FILE *fp;
+
+ fp = fmemopen(NULL, 16, "ab+");
+ ATF_REQUIRE(fp != NULL);
+ ATF_REQUIRE(ftell(fp) == 0L);
+ fclose(fp);
+
+ /* Make sure that a pre-allocated buffer behaves correctly. */
+ char buf[] = "Hello";
+ fp = fmemopen(buf, sizeof(buf), "ab+");
+ ATF_REQUIRE(fp != NULL);
+ ATF_REQUIRE(ftell(fp) == strlen(buf));
+ fclose(fp);
+}
+
+ATF_TC_WITHOUT_HEAD(test_size_0);
+ATF_TC_BODY(test_size_0, tc)
+{
+ /* POSIX mandates that we return EINVAL if size is 0. */
+
+ FILE *fp;
+
+ fp = fmemopen(NULL, 0, "r+");
+ ATF_REQUIRE(fp == NULL);
+ ATF_REQUIRE(errno == EINVAL);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, test_autoalloc);
+ ATF_TP_ADD_TC(tp, test_preexisting);
+ ATF_TP_ADD_TC(tp, test_data_length);
+ ATF_TP_ADD_TC(tp, test_binary);
+ ATF_TP_ADD_TC(tp, test_append_binary_pos);
+ ATF_TP_ADD_TC(tp, test_size_0);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/stdio/fopen_test.c b/lib/libc/tests/stdio/fopen_test.c
new file mode 100644
index 000000000000..962e7fdb1a34
--- /dev/null
+++ b/lib/libc/tests/stdio/fopen_test.c
@@ -0,0 +1,205 @@
+/*-
+ * Copyright (c) 2013 Jilles Tjoelker
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <fcntl.h>
+#include <paths.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <atf-c.h>
+
+/*
+ * O_ACCMODE is currently defined incorrectly. This is what it should be.
+ * Various code depends on the incorrect value.
+ */
+#define CORRECT_O_ACCMODE (O_ACCMODE | O_EXEC)
+
+static void
+runtest(const char *fname, const char *mode)
+{
+ FILE *fp;
+ int exp_fget_ret, fget_ret, fd, flags, wantedflags;
+
+ fp = fopen(fname, mode);
+ ATF_REQUIRE_MSG(fp != NULL,
+ "fopen(\"%s\", \"%s\") failed", fname, mode);
+ fd = fileno(fp);
+ ATF_REQUIRE_MSG(fd >= 0, "fileno() failed for fopen");
+ exp_fget_ret = strchr(mode, 'e') != NULL ? FD_CLOEXEC : 0;
+ ATF_REQUIRE_MSG((fget_ret = fcntl(fd, F_GETFD)) == exp_fget_ret,
+ "fcntl(.., F_GETFD) didn't FD_CLOEXEC as expected %d != %d",
+ exp_fget_ret, fget_ret);
+ flags = fcntl(fd, F_GETFL);
+ if (strchr(mode, '+'))
+ wantedflags = O_RDWR | (*mode == 'a' ? O_APPEND : 0);
+ else if (*mode == 'r')
+ wantedflags = O_RDONLY;
+ else if (*mode == 'w')
+ wantedflags = O_WRONLY;
+ else if (*mode == 'a')
+ wantedflags = O_WRONLY | O_APPEND;
+ else
+ wantedflags = -1;
+ fclose(fp);
+ if (wantedflags == -1)
+ atf_tc_fail("unrecognized mode: %s", mode);
+ else if ((flags & (CORRECT_O_ACCMODE | O_APPEND)) != wantedflags)
+ atf_tc_fail("incorrect access mode: %s", mode);
+}
+
+ATF_TC_WITHOUT_HEAD(fopen_r_test);
+ATF_TC_BODY(fopen_r_test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "r");
+}
+
+ATF_TC_WITHOUT_HEAD(fopen_r_append_test);
+ATF_TC_BODY(fopen_r_append_test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "r+");
+}
+
+ATF_TC_WITHOUT_HEAD(fopen_w_test);
+ATF_TC_BODY(fopen_w_test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "w");
+}
+
+ATF_TC_WITHOUT_HEAD(fopen_w_append_test);
+ATF_TC_BODY(fopen_w_append_test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "w+");
+}
+
+ATF_TC_WITHOUT_HEAD(fopen_a_test);
+ATF_TC_BODY(fopen_a_test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "a");
+}
+
+ATF_TC_WITHOUT_HEAD(fopen_a_append_test);
+ATF_TC_BODY(fopen_a_append_test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "a+");
+}
+
+ATF_TC_WITHOUT_HEAD(fopen_re_test);
+ATF_TC_BODY(fopen_re_test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "re");
+}
+
+ATF_TC_WITHOUT_HEAD(fopen_r_append_e_test);
+ATF_TC_BODY(fopen_r_append_e_test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "r+e");
+}
+
+ATF_TC_WITHOUT_HEAD(fopen_we_test);
+ATF_TC_BODY(fopen_we_test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "we");
+}
+
+ATF_TC_WITHOUT_HEAD(fopen_w_append_e_test);
+ATF_TC_BODY(fopen_w_append_e_test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "w+e");
+}
+
+ATF_TC_WITHOUT_HEAD(fopen_ae_test);
+ATF_TC_BODY(fopen_ae_test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "ae");
+}
+
+ATF_TC_WITHOUT_HEAD(fopen_a_append_e_test);
+ATF_TC_BODY(fopen_a_append_e_test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "a+e");
+}
+
+ATF_TC_WITHOUT_HEAD(fopen_re_append_test);
+ATF_TC_BODY(fopen_re_append_test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "re+");
+}
+
+ATF_TC_WITHOUT_HEAD(fopen_we_append_test);
+ATF_TC_BODY(fopen_we_append_test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "we+");
+}
+
+ATF_TC_WITHOUT_HEAD(fopen_ae_append_test);
+ATF_TC_BODY(fopen_ae_append_test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "ae+");
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, fopen_r_test);
+ ATF_TP_ADD_TC(tp, fopen_r_append_test);
+ ATF_TP_ADD_TC(tp, fopen_w_test);
+ ATF_TP_ADD_TC(tp, fopen_w_append_test);
+ ATF_TP_ADD_TC(tp, fopen_a_test);
+ ATF_TP_ADD_TC(tp, fopen_a_append_test);
+ ATF_TP_ADD_TC(tp, fopen_re_test);
+ ATF_TP_ADD_TC(tp, fopen_r_append_e_test);
+ ATF_TP_ADD_TC(tp, fopen_we_test);
+ ATF_TP_ADD_TC(tp, fopen_w_append_e_test);
+ ATF_TP_ADD_TC(tp, fopen_ae_test);
+ ATF_TP_ADD_TC(tp, fopen_a_append_e_test);
+ ATF_TP_ADD_TC(tp, fopen_re_append_test);
+ ATF_TP_ADD_TC(tp, fopen_we_append_test);
+ ATF_TP_ADD_TC(tp, fopen_ae_append_test);
+
+ return (atf_no_error());
+}
+
+/*
+ vim:ts=8:cin:sw=8
+ */
diff --git a/lib/libc/tests/stdio/freopen_test.c b/lib/libc/tests/stdio/freopen_test.c
new file mode 100644
index 000000000000..8ca4719e8603
--- /dev/null
+++ b/lib/libc/tests/stdio/freopen_test.c
@@ -0,0 +1,223 @@
+/*-
+ * Copyright (c) 2014 Jilles Tjoelker
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <paths.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <atf-c.h>
+
+static void
+runtest(const char *fname1, const char *mode1, const char *fname2,
+ const char *mode2, bool success)
+{
+ FILE *fp1, *fp2;
+ const char *fname2_print;
+
+ fname2_print = fname2 != NULL ? fname2 : "<NULL>";
+ fp1 = fopen(fname1, mode1);
+ ATF_REQUIRE_MSG(fp1 != NULL,
+ "fopen(\"%s\", \"%s\") failed; errno=%d", fname1, mode1, errno);
+ fp2 = freopen(fname2, mode2, fp1);
+ if (fp2 == NULL) {
+ ATF_REQUIRE_MSG(success == false,
+ "freopen(\"%s\", \"%s\", fopen(\"%s\", \"%s\")) succeeded "
+ "unexpectedly", fname2_print, mode2, fname1, mode1);
+ return;
+ }
+ ATF_REQUIRE_MSG(success == true,
+ "freopen(\"%s\", \"%s\", fopen(\"%s\", \"%s\")) failed: %d",
+ fname2_print, mode2, fname1, mode1, errno);
+ fclose(fp2);
+}
+
+ATF_TC_WITHOUT_HEAD(null__r__r__test);
+ATF_TC_BODY(null__r__r__test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "r", NULL, "r", true);
+}
+
+ATF_TC_WITHOUT_HEAD(null__w__r__test);
+ATF_TC_BODY(null__w__r__test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "w", NULL, "r", false);
+}
+
+ATF_TC_WITHOUT_HEAD(null__r_append__r__test);
+ATF_TC_BODY(null__r_append__r__test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "r+", NULL, "r", true);
+}
+
+ATF_TC_WITHOUT_HEAD(null__r__w__test);
+ATF_TC_BODY(null__r__w__test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "r", NULL, "w", false);
+}
+
+ATF_TC_WITHOUT_HEAD(null__w__w__test);
+ATF_TC_BODY(null__w__w__test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "w", NULL, "w", true);
+}
+
+ATF_TC_WITHOUT_HEAD(null__r_append__w__test);
+ATF_TC_BODY(null__r_append__w__test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "r+", NULL, "w", true);
+}
+
+ATF_TC_WITHOUT_HEAD(null__r__a__test);
+ATF_TC_BODY(null__r__a__test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "r", NULL, "a", false);
+}
+
+ATF_TC_WITHOUT_HEAD(null__w__a__test);
+ATF_TC_BODY(null__w__a__test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "w", NULL, "a", true);
+}
+
+ATF_TC_WITHOUT_HEAD(null__r_append__a__test);
+ATF_TC_BODY(null__r_append__a__test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "r+", NULL, "a", true);
+}
+
+ATF_TC_WITHOUT_HEAD(null__r__r_append__test);
+ATF_TC_BODY(null__r__r_append__test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "r", NULL, "r+", false);
+}
+
+ATF_TC_WITHOUT_HEAD(null__w__r_append__test);
+ATF_TC_BODY(null__w__r_append__test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "w", NULL, "r+", false);
+}
+
+ATF_TC_WITHOUT_HEAD(null__r_append__r_append__test);
+ATF_TC_BODY(null__r_append__r_append__test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "r+", NULL, "r+", true);
+}
+
+ATF_TC_WITHOUT_HEAD(null__r__w_append__test);
+ATF_TC_BODY(null__r__w_append__test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "r", NULL, "w+", false);
+}
+
+ATF_TC_WITHOUT_HEAD(null__w__w_append__test);
+ATF_TC_BODY(null__w__w_append__test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "w", NULL, "w+", false);
+}
+
+ATF_TC_WITHOUT_HEAD(null__r_append__w_append__test);
+ATF_TC_BODY(null__r_append__w_append__test, tc)
+{
+
+ runtest(_PATH_DEVNULL, "r+", NULL, "w+", true);
+}
+
+ATF_TC_WITHOUT_HEAD(sh__r__r__test);
+ATF_TC_BODY(sh__r__r__test, tc)
+{
+
+ runtest("/bin/sh", "r", NULL, "r", true);
+}
+
+ATF_TC_WITHOUT_HEAD(sh__sh__r__r__test);
+ATF_TC_BODY(sh__sh__r__r__test, tc)
+{
+
+ runtest("/bin/sh", "r", "/bin/sh", "r", true);
+}
+
+ATF_TC_WITHOUT_HEAD(sh__null__r__r__test);
+ATF_TC_BODY(sh__null__r__r__test, tc)
+{
+
+ runtest("/bin/sh", "r", _PATH_DEVNULL, "r", true);
+}
+
+ATF_TC_WITHOUT_HEAD(sh__null__r__w__test);
+ATF_TC_BODY(sh__null__r__w__test, tc)
+{
+
+ runtest("/bin/sh", "r", _PATH_DEVNULL, "w", true);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, null__r__r__test);
+ ATF_TP_ADD_TC(tp, null__w__r__test);
+ ATF_TP_ADD_TC(tp, null__r_append__r__test);
+ ATF_TP_ADD_TC(tp, null__r__w__test);
+ ATF_TP_ADD_TC(tp, null__w__w__test);
+ ATF_TP_ADD_TC(tp, null__r_append__w__test);
+ ATF_TP_ADD_TC(tp, null__r__a__test);
+ ATF_TP_ADD_TC(tp, null__w__a__test);
+ ATF_TP_ADD_TC(tp, null__r_append__a__test);
+ ATF_TP_ADD_TC(tp, null__r__r_append__test);
+ ATF_TP_ADD_TC(tp, null__w__r_append__test);
+ ATF_TP_ADD_TC(tp, null__r_append__r_append__test);
+ ATF_TP_ADD_TC(tp, null__r__w_append__test);
+ ATF_TP_ADD_TC(tp, null__w__w_append__test);
+ ATF_TP_ADD_TC(tp, null__r_append__w_append__test);
+ ATF_TP_ADD_TC(tp, sh__r__r__test);
+ ATF_TP_ADD_TC(tp, sh__sh__r__r__test);
+ ATF_TP_ADD_TC(tp, sh__null__r__r__test);
+ ATF_TP_ADD_TC(tp, sh__null__r__w__test);
+
+ return (atf_no_error());
+}
+
+/*
+ vim:ts=8:cin:sw=8
+ */
diff --git a/lib/libc/tests/stdio/getdelim_test.c b/lib/libc/tests/stdio/getdelim_test.c
new file mode 100644
index 000000000000..8dc662fcab8f
--- /dev/null
+++ b/lib/libc/tests/stdio/getdelim_test.c
@@ -0,0 +1,235 @@
+/*-
+ * Copyright (c) 2009 David Schultz <das@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <atf-c.h>
+
+#define CHUNK_MAX 10
+
+/* The assertions depend on this string. */
+char apothegm[] = "All work and no play\0 makes Jack a dull boy.\n";
+
+/*
+ * This is a neurotic reader function designed to give getdelim() a
+ * hard time. It reads through the string `apothegm' and returns a
+ * random number of bytes up to the requested length.
+ */
+static int
+_reader(void *cookie, char *buf, int len)
+{
+ size_t *offp = cookie;
+ size_t r;
+
+ r = random() % CHUNK_MAX + 1;
+ if (len > r)
+ len = r;
+ if (len > sizeof(apothegm) - *offp)
+ len = sizeof(apothegm) - *offp;
+ memcpy(buf, apothegm + *offp, len);
+ *offp += len;
+ return (len);
+}
+
+static FILE *
+mkfilebuf(void)
+{
+ size_t *offp;
+
+ offp = malloc(sizeof(*offp)); /* XXX leak */
+ *offp = 0;
+ return (fropen(offp, _reader));
+}
+
+ATF_TC_WITHOUT_HEAD(getline_basic);
+ATF_TC_BODY(getline_basic, tc)
+{
+ FILE *fp;
+ char *line;
+ size_t linecap;
+ int i;
+
+ srandom(0);
+
+ /*
+ * Test multiple times with different buffer sizes
+ * and different _reader() return values.
+ */
+ errno = 0;
+ for (i = 0; i < 8; i++) {
+ fp = mkfilebuf();
+ linecap = i;
+ line = malloc(i);
+ /* First line: the full apothegm */
+ ATF_REQUIRE(getline(&line, &linecap, fp) == sizeof(apothegm) - 1);
+ ATF_REQUIRE(memcmp(line, apothegm, sizeof(apothegm)) == 0);
+ ATF_REQUIRE(linecap >= sizeof(apothegm));
+ /* Second line: the NUL terminator following the newline */
+ ATF_REQUIRE(getline(&line, &linecap, fp) == 1);
+ ATF_REQUIRE(line[0] == '\0' && line[1] == '\0');
+ /* Third line: EOF */
+ line[0] = 'X';
+ ATF_REQUIRE(getline(&line, &linecap, fp) == -1);
+ ATF_REQUIRE(line[0] == '\0');
+ free(line);
+ line = NULL;
+ ATF_REQUIRE(feof(fp));
+ ATF_REQUIRE(!ferror(fp));
+ fclose(fp);
+ }
+ ATF_REQUIRE(errno == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(stream_error);
+ATF_TC_BODY(stream_error, tc)
+{
+ char *line;
+ size_t linecap;
+
+ /* Make sure read errors are handled properly. */
+ line = NULL;
+ linecap = 0;
+ errno = 0;
+ ATF_REQUIRE(getline(&line, &linecap, stdout) == -1);
+ ATF_REQUIRE(errno == EBADF);
+ errno = 0;
+ ATF_REQUIRE(getdelim(&line, &linecap, 'X', stdout) == -1);
+ ATF_REQUIRE(errno == EBADF);
+ ATF_REQUIRE(ferror(stdout));
+}
+
+ATF_TC_WITHOUT_HEAD(invalid_params);
+ATF_TC_BODY(invalid_params, tc)
+{
+ FILE *fp;
+ char *line;
+ size_t linecap;
+
+ /* Make sure NULL linep or linecapp pointers are handled. */
+ fp = mkfilebuf();
+ ATF_REQUIRE(getline(NULL, &linecap, fp) == -1);
+ ATF_REQUIRE(errno == EINVAL);
+ ATF_REQUIRE(getline(&line, NULL, fp) == -1);
+ ATF_REQUIRE(errno == EINVAL);
+ ATF_REQUIRE(ferror(fp));
+ fclose(fp);
+}
+
+ATF_TC_WITHOUT_HEAD(eof);
+ATF_TC_BODY(eof, tc)
+{
+ FILE *fp;
+ char *line;
+ size_t linecap;
+
+ /* Make sure getline() allocates memory as needed if fp is at EOF. */
+ errno = 0;
+ fp = mkfilebuf();
+ while (!feof(fp)) /* advance to EOF; can't fseek this stream */
+ getc(fp);
+ line = NULL;
+ linecap = 0;
+ printf("getline\n");
+ ATF_REQUIRE(getline(&line, &linecap, fp) == -1);
+ ATF_REQUIRE(line[0] == '\0');
+ ATF_REQUIRE(linecap > 0);
+ ATF_REQUIRE(errno == 0);
+ printf("feof\n");
+ ATF_REQUIRE(feof(fp));
+ ATF_REQUIRE(!ferror(fp));
+ fclose(fp);
+}
+
+ATF_TC_WITHOUT_HEAD(nul);
+ATF_TC_BODY(nul, tc)
+{
+ FILE *fp;
+ char *line;
+ size_t linecap, n;
+
+ errno = 0;
+ line = NULL;
+ linecap = 0;
+ /* Make sure a NUL delimiter works. */
+ fp = mkfilebuf();
+ n = strlen(apothegm);
+ printf("getdelim\n");
+ ATF_REQUIRE(getdelim(&line, &linecap, '\0', fp) == n + 1);
+ ATF_REQUIRE(strcmp(line, apothegm) == 0);
+ ATF_REQUIRE(line[n + 1] == '\0');
+ ATF_REQUIRE(linecap > n + 1);
+ n = strlen(apothegm + n + 1);
+ printf("getdelim 2\n");
+ ATF_REQUIRE(getdelim(&line, &linecap, '\0', fp) == n + 1);
+ ATF_REQUIRE(line[n + 1] == '\0');
+ ATF_REQUIRE(linecap > n + 1);
+ ATF_REQUIRE(errno == 0);
+ ATF_REQUIRE(!ferror(fp));
+ fclose(fp);
+}
+
+ATF_TC_WITHOUT_HEAD(empty_NULL_buffer);
+ATF_TC_BODY(empty_NULL_buffer, tc)
+{
+ FILE *fp;
+ char *line;
+ size_t linecap;
+
+ /* Make sure NULL *linep and zero *linecapp are handled. */
+ fp = mkfilebuf();
+ line = NULL;
+ linecap = 42;
+ ATF_REQUIRE(getline(&line, &linecap, fp) == sizeof(apothegm) - 1);
+ ATF_REQUIRE(memcmp(line, apothegm, sizeof(apothegm)) == 0);
+ fp = mkfilebuf();
+ free(line);
+ line = malloc(100);
+ linecap = 0;
+ ATF_REQUIRE(getline(&line, &linecap, fp) == sizeof(apothegm) - 1);
+ ATF_REQUIRE(memcmp(line, apothegm, sizeof(apothegm)) == 0);
+ free(line);
+ ATF_REQUIRE(!ferror(fp));
+ fclose(fp);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, getline_basic);
+ ATF_TP_ADD_TC(tp, stream_error);
+ ATF_TP_ADD_TC(tp, eof);
+ ATF_TP_ADD_TC(tp, invalid_params);
+ ATF_TP_ADD_TC(tp, nul);
+ ATF_TP_ADD_TC(tp, empty_NULL_buffer);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/stdio/mkostemp_test.c b/lib/libc/tests/stdio/mkostemp_test.c
new file mode 100644
index 000000000000..0dd475b4ec61
--- /dev/null
+++ b/lib/libc/tests/stdio/mkostemp_test.c
@@ -0,0 +1,185 @@
+/*-
+ * Copyright (c) 2013 Jilles Tjoelker
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Test program for mkostemp().
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <atf-c.h>
+
+static const char template[] = "mkostemp.XXXXXXXX";
+static int testnum;
+
+#define MISCFLAGS (O_APPEND | O_DIRECT | O_SHLOCK | O_EXLOCK | O_SYNC)
+
+static void
+test_one(int oflags)
+{
+ char tmpf[sizeof(template)];
+ struct stat st1, st2;
+ int fd;
+
+ memcpy(tmpf, template, sizeof(tmpf));
+ fd = mkostemp(tmpf, oflags);
+ if (fd < 0) {
+ printf("not ok %d - oflags=%#x "
+ "mkostemp() reported failure: %s\n",
+ testnum++, oflags, strerror(errno));
+ return;
+ }
+ if (memcmp(tmpf, template, sizeof(tmpf) - 8 - 1) != 0) {
+ printf("not ok %d - oflags=%#x "
+ "returned pathname does not match template: %s\n",
+ testnum++, oflags, tmpf);
+ return;
+ }
+ do {
+ if (fcntl(fd, F_GETFD) !=
+ (oflags & O_CLOEXEC ? FD_CLOEXEC : 0)) {
+ printf("not ok %d - oflags=%#x "
+ "close-on-exec flag incorrect\n",
+ testnum++, oflags);
+ break;
+ }
+ if ((fcntl(fd, F_GETFL) & MISCFLAGS) != (oflags & MISCFLAGS)) {
+ printf("not ok %d - oflags=%#x "
+ "open flags incorrect\n",
+ testnum++, oflags);
+ break;
+ }
+ if (stat(tmpf, &st1) == -1) {
+ printf("not ok %d - oflags=%#x "
+ "cannot stat returned pathname %s: %s\n",
+ testnum++, oflags, tmpf, strerror(errno));
+ break;
+ }
+ if (fstat(fd, &st2) == -1) {
+ printf("not ok %d - oflags=%#x "
+ "cannot fstat returned fd %d: %s\n",
+ testnum++, oflags, fd, strerror(errno));
+ break;
+ }
+ if (!S_ISREG(st1.st_mode) || (st1.st_mode & 0777) != 0600 ||
+ st1.st_nlink != 1 || st1.st_size != 0) {
+ printf("not ok %d - oflags=%#x "
+ "named file attributes incorrect\n",
+ testnum++, oflags);
+ break;
+ }
+ if (!S_ISREG(st2.st_mode) || (st2.st_mode & 0777) != 0600 ||
+ st2.st_nlink != 1 || st2.st_size != 0) {
+ printf("not ok %d - oflags=%#x "
+ "opened file attributes incorrect\n",
+ testnum++, oflags);
+ break;
+ }
+ if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino) {
+ printf("not ok %d - oflags=%#x "
+ "named and opened file do not match\n",
+ testnum++, oflags);
+ break;
+ }
+ (void)unlink(tmpf);
+ if (fstat(fd, &st2) == -1)
+ printf("not ok %d - oflags=%#x "
+ "cannot fstat returned fd %d again: %s\n",
+ testnum++, oflags, fd, strerror(errno));
+ else if (st2.st_nlink != 0)
+ printf("not ok %d - oflags=%#x "
+ "st_nlink is not 0 after unlink\n",
+ testnum++, oflags);
+ else
+ printf("ok %d - oflags=%#x\n", testnum++, oflags);
+ (void)close(fd);
+ return;
+ } while (0);
+ (void)close(fd);
+ (void)unlink(tmpf);
+}
+
+ATF_TC_WITHOUT_HEAD(zero);
+ATF_TC_BODY(zero, tc)
+{
+
+ test_one(0);
+}
+
+ATF_TC_WITHOUT_HEAD(O_CLOEXEC);
+ATF_TC_BODY(O_CLOEXEC, tc)
+{
+
+ test_one(O_CLOEXEC);
+}
+
+ATF_TC_WITHOUT_HEAD(O_APPEND);
+ATF_TC_BODY(O_APPEND, tc)
+{
+
+ test_one(O_APPEND);
+}
+
+ATF_TC_WITHOUT_HEAD(O_APPEND__O_CLOEXEC);
+ATF_TC_BODY(O_APPEND__O_CLOEXEC, tc)
+{
+
+ test_one(O_APPEND|O_CLOEXEC);
+}
+
+ATF_TC_WITHOUT_HEAD(bad_flags);
+ATF_TC_BODY(bad_flags, tc)
+{
+
+ char tmpf[sizeof(template)];
+
+ memcpy(tmpf, template, sizeof(tmpf));
+ ATF_REQUIRE_MSG(mkostemp(tmpf, O_CREAT) == -1,
+ "mkostemp(O_CREAT) succeeded unexpectedly");
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, zero);
+ ATF_TP_ADD_TC(tp, O_CLOEXEC);
+ ATF_TP_ADD_TC(tp, O_APPEND);
+ ATF_TP_ADD_TC(tp, O_APPEND__O_CLOEXEC);
+ ATF_TP_ADD_TC(tp, bad_flags);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/stdio/open_memstream2_test.c b/lib/libc/tests/stdio/open_memstream2_test.c
new file mode 100644
index 000000000000..21ea64c7c669
--- /dev/null
+++ b/lib/libc/tests/stdio/open_memstream2_test.c
@@ -0,0 +1,201 @@
+/*-
+ * Copyright (c) 2013 Hudson River Trading LLC
+ * Written by: John H. Baldwin <jhb@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+
+#include <atf-c.h>
+
+static char *buf;
+static size_t len;
+
+static void
+assert_stream(const char *contents)
+{
+ if (strlen(contents) != len)
+ printf("bad length %zd for \"%s\"\n", len, contents);
+ else if (strncmp(buf, contents, strlen(contents)) != 0)
+ printf("bad buffer \"%s\" for \"%s\"\n", buf, contents);
+}
+
+ATF_TC_WITHOUT_HEAD(open_group_test);
+ATF_TC_BODY(open_group_test, tc)
+{
+ FILE *fp;
+ off_t eob;
+
+ fp = open_memstream(&buf, &len);
+ ATF_REQUIRE_MSG(fp != NULL, "open_memstream failed");
+
+ fprintf(fp, "hello my world");
+ fflush(fp);
+ assert_stream("hello my world");
+ eob = ftello(fp);
+ rewind(fp);
+ fprintf(fp, "good-bye");
+ fseeko(fp, eob, SEEK_SET);
+ fclose(fp);
+ assert_stream("good-bye world");
+ free(buf);
+}
+
+ATF_TC_WITHOUT_HEAD(simple_tests);
+ATF_TC_BODY(simple_tests, tc)
+{
+ static const char zerobuf[] =
+ { 'f', 'o', 'o', 0, 0, 0, 0, 'b', 'a', 'r', 0 };
+ char c;
+ FILE *fp;
+
+ fp = open_memstream(&buf, NULL);
+ ATF_REQUIRE_MSG(fp == NULL, "open_memstream did not fail");
+ ATF_REQUIRE_MSG(errno == EINVAL,
+ "open_memstream didn't fail with EINVAL");
+ fp = open_memstream(NULL, &len);
+ ATF_REQUIRE_MSG(fp == NULL, "open_memstream did not fail");
+ ATF_REQUIRE_MSG(errno == EINVAL,
+ "open_memstream didn't fail with EINVAL");
+ fp = open_memstream(&buf, &len);
+ ATF_REQUIRE_MSG(fp != NULL, "open_memstream failed; errno=%d", errno);
+ fflush(fp);
+ assert_stream("");
+ if (fwide(fp, 0) >= 0)
+ printf("stream is not byte-oriented\n");
+
+ fprintf(fp, "fo");
+ fflush(fp);
+ assert_stream("fo");
+ fputc('o', fp);
+ fflush(fp);
+ assert_stream("foo");
+ rewind(fp);
+ fflush(fp);
+ assert_stream("");
+ fseek(fp, 0, SEEK_END);
+ fflush(fp);
+ assert_stream("foo");
+
+ /*
+ * Test seeking out past the current end. Should zero-fill the
+ * intermediate area.
+ */
+ fseek(fp, 4, SEEK_END);
+ fprintf(fp, "bar");
+ fflush(fp);
+
+ /*
+ * Can't use assert_stream() here since this should contain
+ * embedded null characters.
+ */
+ if (len != 10)
+ printf("bad length %zd for zero-fill test\n", len);
+ else if (memcmp(buf, zerobuf, sizeof(zerobuf)) != 0)
+ printf("bad buffer for zero-fill test\n");
+
+ fseek(fp, 3, SEEK_SET);
+ fprintf(fp, " in ");
+ fflush(fp);
+ assert_stream("foo in ");
+ fseek(fp, 0, SEEK_END);
+ fflush(fp);
+ assert_stream("foo in bar");
+
+ rewind(fp);
+ if (fread(&c, sizeof(c), 1, fp) != 0)
+ printf("fread did not fail\n");
+ else if (!ferror(fp))
+ printf("error indicator not set after fread\n");
+ else
+ clearerr(fp);
+
+ fseek(fp, 4, SEEK_SET);
+ fprintf(fp, "bar baz");
+ fclose(fp);
+ assert_stream("foo bar baz");
+ free(buf);
+}
+
+ATF_TC_WITHOUT_HEAD(seek_tests);
+ATF_TC_BODY(seek_tests, tc)
+{
+ FILE *fp;
+
+ fp = open_memstream(&buf, &len);
+ ATF_REQUIRE_MSG(fp != NULL, "open_memstream failed: %d", errno);
+
+#define SEEK_FAIL(offset, whence, error) do { \
+ errno = 0; \
+ ATF_REQUIRE_MSG(fseeko(fp, (offset), (whence)) != 0, \
+ "fseeko(%s, %s) did not fail, set pos to %jd", \
+ __STRING(offset), __STRING(whence), \
+ (intmax_t)ftello(fp)); \
+ ATF_REQUIRE_MSG(errno == (error), \
+ "fseeko(%s, %s) failed with %d rather than %s", \
+ __STRING(offset), __STRING(whence), errno, \
+ __STRING(error)); \
+} while (0)
+
+#define SEEK_OK(offset, whence, result) do { \
+ ATF_REQUIRE_MSG(fseeko(fp, (offset), (whence)) == 0, \
+ "fseeko(%s, %s) failed: %s", \
+ __STRING(offset), __STRING(whence), strerror(errno)); \
+ ATF_REQUIRE_MSG(ftello(fp) == (result), \
+ "fseeko(%s, %s) seeked to %jd rather than %s", \
+ __STRING(offset), __STRING(whence), \
+ (intmax_t)ftello(fp), __STRING(result)); \
+} while (0)
+
+ SEEK_FAIL(-1, SEEK_SET, EINVAL);
+ SEEK_FAIL(-1, SEEK_CUR, EINVAL);
+ SEEK_FAIL(-1, SEEK_END, EINVAL);
+ fprintf(fp, "foo");
+ SEEK_OK(-1, SEEK_CUR, 2);
+ SEEK_OK(0, SEEK_SET, 0);
+ SEEK_OK(-1, SEEK_END, 2);
+ SEEK_OK(OFF_MAX - 1, SEEK_SET, OFF_MAX - 1);
+ SEEK_FAIL(2, SEEK_CUR, EOVERFLOW);
+ fclose(fp);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, open_group_test);
+ ATF_TP_ADD_TC(tp, simple_tests);
+ ATF_TP_ADD_TC(tp, seek_tests);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/stdio/open_wmemstream_test.c b/lib/libc/tests/stdio/open_wmemstream_test.c
new file mode 100644
index 000000000000..324bcf3d3482
--- /dev/null
+++ b/lib/libc/tests/stdio/open_wmemstream_test.c
@@ -0,0 +1,201 @@
+/*-
+ * Copyright (c) 2013 Hudson River Trading LLC
+ * Written by: John H. Baldwin <jhb@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+
+#include <atf-c.h>
+
+static wchar_t *buf;
+static size_t len;
+
+static void
+assert_stream(const wchar_t *contents)
+{
+ if (wcslen(contents) != len)
+ printf("bad length %zd for \"%ls\"\n", len, contents);
+ else if (wcsncmp(buf, contents, wcslen(contents)) != 0)
+ printf("bad buffer \"%ls\" for \"%ls\"\n", buf, contents);
+}
+
+ATF_TC_WITHOUT_HEAD(open_group_test);
+ATF_TC_BODY(open_group_test, tc)
+{
+ FILE *fp;
+ off_t eob;
+
+ fp = open_wmemstream(&buf, &len);
+ ATF_REQUIRE_MSG(fp != NULL, "open_wmemstream failed");
+
+ fwprintf(fp, L"hello my world");
+ fflush(fp);
+ assert_stream(L"hello my world");
+ eob = ftello(fp);
+ rewind(fp);
+ fwprintf(fp, L"good-bye");
+ fseeko(fp, eob, SEEK_SET);
+ fclose(fp);
+ assert_stream(L"good-bye world");
+ free(buf);
+}
+
+ATF_TC_WITHOUT_HEAD(simple_tests);
+ATF_TC_BODY(simple_tests, tc)
+{
+ static const wchar_t zerobuf[] =
+ { L'f', L'o', L'o', 0, 0, 0, 0, L'b', L'a', L'r', 0 };
+ wchar_t c;
+ FILE *fp;
+
+ fp = open_wmemstream(&buf, NULL);
+ ATF_REQUIRE_MSG(fp == NULL, "open_wmemstream did not fail");
+ ATF_REQUIRE_MSG(errno == EINVAL,
+ "open_wmemstream didn't fail with EINVAL");
+ fp = open_wmemstream(NULL, &len);
+ ATF_REQUIRE_MSG(fp == NULL, "open_wmemstream did not fail");
+ ATF_REQUIRE_MSG(errno == EINVAL,
+ "open_wmemstream didn't fail with EINVAL");
+ fp = open_wmemstream(&buf, &len);
+ ATF_REQUIRE_MSG(fp != NULL, "open_memstream failed; errno=%d", errno);
+ fflush(fp);
+ assert_stream(L"");
+ if (fwide(fp, 0) <= 0)
+ printf("stream is not wide-oriented\n");
+
+ fwprintf(fp, L"fo");
+ fflush(fp);
+ assert_stream(L"fo");
+ fputwc(L'o', fp);
+ fflush(fp);
+ assert_stream(L"foo");
+ rewind(fp);
+ fflush(fp);
+ assert_stream(L"");
+ fseek(fp, 0, SEEK_END);
+ fflush(fp);
+ assert_stream(L"foo");
+
+ /*
+ * Test seeking out past the current end. Should zero-fill the
+ * intermediate area.
+ */
+ fseek(fp, 4, SEEK_END);
+ fwprintf(fp, L"bar");
+ fflush(fp);
+
+ /*
+ * Can't use assert_stream() here since this should contain
+ * embedded null characters.
+ */
+ if (len != 10)
+ printf("bad length %zd for zero-fill test\n", len);
+ else if (memcmp(buf, zerobuf, sizeof(zerobuf)) != 0)
+ printf("bad buffer for zero-fill test\n");
+
+ fseek(fp, 3, SEEK_SET);
+ fwprintf(fp, L" in ");
+ fflush(fp);
+ assert_stream(L"foo in ");
+ fseek(fp, 0, SEEK_END);
+ fflush(fp);
+ assert_stream(L"foo in bar");
+
+ rewind(fp);
+ if (fread(&c, sizeof(c), 1, fp) != 0)
+ printf("fread did not fail\n");
+ else if (!ferror(fp))
+ printf("error indicator not set after fread\n");
+ else
+ clearerr(fp);
+
+ fseek(fp, 4, SEEK_SET);
+ fwprintf(fp, L"bar baz");
+ fclose(fp);
+ assert_stream(L"foo bar baz");
+ free(buf);
+}
+
+ATF_TC_WITHOUT_HEAD(seek_tests);
+ATF_TC_BODY(seek_tests, tc)
+{
+ FILE *fp;
+
+ fp = open_wmemstream(&buf, &len);
+ ATF_REQUIRE_MSG(fp != NULL, "open_wmemstream failed; errno=%d", errno);
+
+#define SEEK_FAIL(offset, whence, error) do { \
+ errno = 0; \
+ ATF_REQUIRE_MSG(fseeko(fp, (offset), (whence)) != 0, \
+ "fseeko(%s, %s) did not fail, set pos to %jd", \
+ __STRING(offset), __STRING(whence), \
+ (intmax_t)ftello(fp)); \
+ ATF_REQUIRE_MSG(errno == (error), \
+ "fseeko(%s, %s) failed with %d rather than %s", \
+ __STRING(offset), __STRING(whence), errno, \
+ __STRING(error)); \
+} while (0)
+
+#define SEEK_OK(offset, whence, result) do { \
+ ATF_REQUIRE_MSG(fseeko(fp, (offset), (whence)) == 0, \
+ "fseeko(%s, %s) failed: %s", \
+ __STRING(offset), __STRING(whence), strerror(errno)); \
+ ATF_REQUIRE_MSG(ftello(fp) == (result), \
+ "fseeko(%s, %s) seeked to %jd rather than %s", \
+ __STRING(offset), __STRING(whence), \
+ (intmax_t)ftello(fp), __STRING(result)); \
+} while (0)
+
+ SEEK_FAIL(-1, SEEK_SET, EINVAL);
+ SEEK_FAIL(-1, SEEK_CUR, EINVAL);
+ SEEK_FAIL(-1, SEEK_END, EINVAL);
+ fwprintf(fp, L"foo");
+ SEEK_OK(-1, SEEK_CUR, 2);
+ SEEK_OK(0, SEEK_SET, 0);
+ SEEK_OK(-1, SEEK_END, 2);
+ SEEK_OK(OFF_MAX - 1, SEEK_SET, OFF_MAX - 1);
+ SEEK_FAIL(2, SEEK_CUR, EOVERFLOW);
+ fclose(fp);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, open_group_test);
+ ATF_TP_ADD_TC(tp, simple_tests);
+ ATF_TP_ADD_TC(tp, seek_tests);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/stdio/perror_test.c b/lib/libc/tests/stdio/perror_test.c
new file mode 100644
index 000000000000..989f1ff6ea59
--- /dev/null
+++ b/lib/libc/tests/stdio/perror_test.c
@@ -0,0 +1,107 @@
+/*-
+ * Copyright (c) 2002 Tim J. Robbins
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Test program for perror() as specified by IEEE Std. 1003.1-2001 and
+ * ISO/IEC 9899:1999.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <atf-c.h>
+
+static char tmpfil[PATH_MAX];
+
+ATF_TC_WITHOUT_HEAD(perror_test);
+ATF_TC_BODY(perror_test, tc)
+{
+ char lbuf[512];
+ int i;
+ char *s;
+
+ strcpy(tmpfil, "perror.XXXXXXXX");
+ ATF_REQUIRE(mkstemp(tmpfil) >= 0);
+ /* Reopen stderr on a file descriptor other than 2. */
+ fclose(stderr);
+ for (i = 0; i < 3; i++)
+ dup(0);
+ ATF_REQUIRE(freopen(tmpfil, "r+", stderr) != NULL);
+
+ /*
+ * Test that perror() doesn't call strerror() (4.4BSD bug),
+ * the two ways of omitting a program name, and the formatting when
+ * a program name is specified.
+ */
+ s = strerror(ENOENT);
+ ATF_REQUIRE_MSG(strcmp(s, "No such file or directory") == 0,
+ "message obtained was: %s", s);
+ errno = EPERM;
+ perror(NULL);
+ perror("");
+ perror("perror_test");
+ ATF_REQUIRE_MSG(strcmp(s, "No such file or directory") == 0,
+ "message obtained was: %s", s);
+
+ /*
+ * Read it back to check...
+ */
+ rewind(stderr);
+ s = fgets(lbuf, sizeof(lbuf), stderr);
+ ATF_REQUIRE(s != NULL);
+ ATF_REQUIRE_MSG(strcmp(s, "Operation not permitted\n") == 0,
+ "message obtained was: %s", s);
+ s = fgets(lbuf, sizeof(lbuf), stderr);
+ ATF_REQUIRE(s != NULL);
+ ATF_REQUIRE_MSG(strcmp(s, "Operation not permitted\n") == 0,
+ "message obtained was: %s", s);
+ s = fgets(lbuf, sizeof(lbuf), stderr);
+ ATF_REQUIRE(s != NULL);
+ ATF_REQUIRE_MSG(
+ strcmp(s, "perror_test: Operation not permitted\n") == 0,
+ "message obtained was: %s", s);
+ s = fgets(lbuf, sizeof(lbuf), stderr);
+ ATF_REQUIRE(s == NULL);
+ fclose(stderr);
+
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, perror_test);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/stdio/print_positional_test.c b/lib/libc/tests/stdio/print_positional_test.c
new file mode 100644
index 000000000000..9c9ec314d62d
--- /dev/null
+++ b/lib/libc/tests/stdio/print_positional_test.c
@@ -0,0 +1,157 @@
+/* $OpenBSD: sprintf_test.c,v 1.3 2004/09/16 20:22:26 otto Exp $ */
+
+/*
+ * Copyright (c) 2003 Theo de Raadt
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+
+#include <atf-c.h>
+
+const char correct[] =
+ "|xx 01 02 03 04\n"
+ "|xx 05 06 07 08\n"
+ "|xx 09 10 11 12\n"
+ "|xx 13 14 15 16\n"
+ "|xx 17 18 19 20\n"
+ "|xx 21 22 23 24\n"
+ "|xx 25 26 27 28\n"
+ "|xx 29 30 31 32\n"
+ "|xx 33 34 35 36\n"
+ "|xx 37 38 39 40\n"
+ "|xx 41 42 43 44\n"
+ "|xx 45 -1 1 -1 1\n";
+
+const char correct2[] =
+ "b bs BSD";
+static char buf[1024];
+static wchar_t wbuf1[1024], wbuf2[1024];
+static const char *temp;
+
+ATF_TC_WITHOUT_HEAD(positional_normal);
+ATF_TC_BODY(positional_normal, tc)
+{
+
+ /* Test positional arguments */
+ snprintf(buf, sizeof buf,
+ "|xx %1$s %2$s %3$s %4$s\n"
+ "|xx %5$s %6$s %7$s %8$s\n"
+ "|xx %9$s %10$s %11$s %12$s\n"
+ "|xx %13$s %14$s %15$s %16$s\n"
+ "|xx %17$s %18$s %19$s %20$s\n"
+ "|xx %21$s %22$s %23$s %24$s\n"
+ "|xx %25$s %26$s %27$s %28$s\n"
+ "|xx %29$s %30$s %31$s %32$s\n"
+ "|xx %33$s %34$s %35$s %36$s\n"
+ "|xx %37$s %38$s %39$s %40$s\n"
+ "|xx %41$s %42$s %43$s %44$s\n"
+ "|xx %45$d %46$ld %47$lld %48$d %49$lld\n",
+ "01", "02", "03", "04", "05", "06",
+ "07", "08", "09", "10", "11", "12",
+ "13", "14", "15", "16", "17", "18",
+ "19", "20", "21", "22", "23", "24",
+ "25", "26", "27", "28", "29", "30",
+ "31", "32", "33", "34", "35", "36",
+ "37", "38", "39", "40", "41", "42",
+ "43", "44", 45, -1L, 1LL, -1, 1LL
+ );
+ ATF_REQUIRE_MSG(wcscmp(wbuf1, wbuf2) == 0,
+ "buffers didn't match");
+}
+
+ATF_TC_WITHOUT_HEAD(positional_wide);
+ATF_TC_BODY(positional_wide, tc)
+{
+
+ swprintf(wbuf1, nitems(wbuf1),
+ L"|xx %1$s %2$s %3$s %4$s\n"
+ "|xx %5$s %6$s %7$s %8$s\n"
+ "|xx %9$s %10$s %11$s %12$s\n"
+ "|xx %13$s %14$s %15$s %16$s\n"
+ "|xx %17$s %18$s %19$s %20$s\n"
+ "|xx %21$s %22$s %23$s %24$s\n"
+ "|xx %25$s %26$s %27$s %28$s\n"
+ "|xx %29$s %30$s %31$s %32$s\n"
+ "|xx %33$s %34$s %35$s %36$s\n"
+ "|xx %37$s %38$s %39$s %40$s\n"
+ "|xx %41$s %42$s %43$s %44$s\n"
+ "|xx %45$d %46$ld %47$lld %48$d %49$lld\n",
+ "01", "02", "03", "04", "05", "06",
+ "07", "08", "09", "10", "11", "12",
+ "13", "14", "15", "16", "17", "18",
+ "19", "20", "21", "22", "23", "24",
+ "25", "26", "27", "28", "29", "30",
+ "31", "32", "33", "34", "35", "36",
+ "37", "38", "39", "40", "41", "42",
+ "43", "44", 45, -1L, 1LL, -1, 1LL
+ );
+ temp = correct;
+ mbsrtowcs(wbuf2, &temp, nitems(wbuf2), NULL);
+ ATF_REQUIRE_MSG(wcscmp(wbuf1, wbuf2) == 0,
+ "buffers didn't match");
+}
+
+ATF_TC_WITHOUT_HEAD(positional_precision);
+ATF_TC_BODY(positional_precision, tc)
+{
+
+ snprintf(buf, sizeof buf, "%2$.*4$s %2$.*3$s %1$s",
+ "BSD", "bsd", 2, 1);
+ ATF_REQUIRE_MSG(strcmp(buf, correct2) == 0,
+ "buffers didn't match");
+}
+
+ATF_TC_WITHOUT_HEAD(positional_precision_wide);
+ATF_TC_BODY(positional_precision_wide, tc)
+{
+
+ swprintf(wbuf1, sizeof buf, L"%2$.*4$s %2$.*3$s %1$s",
+ "BSD", "bsd", 2, 1);
+ temp = correct2;
+ mbsrtowcs(wbuf2, &temp, nitems(wbuf2), NULL);
+ ATF_REQUIRE_MSG(wcscmp(wbuf1, wbuf2) == 0,
+ "buffers didn't match");
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, positional_normal);
+ ATF_TP_ADD_TC(tp, positional_wide);
+ ATF_TP_ADD_TC(tp, positional_precision);
+ ATF_TP_ADD_TC(tp, positional_precision_wide);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/stdio/printbasic_test.c b/lib/libc/tests/stdio/printbasic_test.c
new file mode 100644
index 000000000000..7f7c6cbbd65c
--- /dev/null
+++ b/lib/libc/tests/stdio/printbasic_test.c
@@ -0,0 +1,160 @@
+/*-
+ * Copyright (c) 2009 David Schultz <das@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Tests for basic and miscellaneous printf() formats.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <err.h>
+#include <limits.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+
+#include <atf-c.h>
+
+#define S_UINT64MAX "18446744073709551615"
+#define S_UINT32MAX "4294967295"
+#define S_INT64MIN "-9223372036854775808"
+#define S_INT32MIN "-2147483648"
+
+#define S_SIZEMAX (SIZE_MAX == UINT64_MAX ? S_UINT64MAX : S_UINT32MAX)
+#define S_ULONGMAX (ULONG_MAX == UINT64_MAX ? S_UINT64MAX : S_UINT32MAX)
+#define S_ULLONGMAX (ULLONG_MAX == UINT64_MAX ? S_UINT64MAX : S_UINT32MAX)
+
+static void
+smash_stack(void)
+{
+ static uint32_t junk = 0xdeadbeef;
+ uint32_t buf[512];
+ int i;
+
+ for (i = 0; i < sizeof(buf) / sizeof(buf[0]); i++)
+ buf[i] = junk;
+}
+
+#define testfmt(result, fmt, ...) \
+ _testfmt((result), #__VA_ARGS__, fmt, __VA_ARGS__)
+static void
+_testfmt(const char *result, const char *argstr, const char *fmt,...)
+{
+#define BUF 100
+ wchar_t ws[BUF], wfmt[BUF], wresult[BUF];
+ char s[BUF];
+ va_list ap, ap2;
+
+ va_start(ap, fmt);
+ va_copy(ap2, ap);
+ smash_stack();
+ vsnprintf(s, sizeof(s), fmt, ap);
+ if (strcmp(result, s) != 0) {
+ atf_tc_fail(
+ "printf(\"%s\", %s) ==> [%s], expected [%s]",
+ fmt, argstr, s, result);
+ }
+
+ smash_stack();
+ mbstowcs(ws, s, BUF - 1);
+ mbstowcs(wfmt, fmt, BUF - 1);
+ mbstowcs(wresult, result, BUF - 1);
+ vswprintf(ws, sizeof(ws) / sizeof(ws[0]), wfmt, ap2);
+ if (wcscmp(wresult, ws) != 0) {
+ atf_tc_fail(
+ "wprintf(\"%ls\", %s) ==> [%ls], expected [%ls]",
+ wfmt, argstr, ws, wresult);
+ }
+ va_end(ap);
+ va_end(ap2);
+}
+
+ATF_TC_WITHOUT_HEAD(int_within_limits);
+ATF_TC_BODY(int_within_limits, tc)
+{
+
+ ATF_REQUIRE(setlocale(LC_NUMERIC, "C"));
+
+ /* The test requires these to be true. */
+ ATF_REQUIRE(UINTMAX_MAX == UINT64_MAX);
+ ATF_REQUIRE(UINT_MAX == UINT32_MAX);
+ ATF_REQUIRE(USHRT_MAX == 0xffff);
+ ATF_REQUIRE(UCHAR_MAX == 0xff);
+
+ /* Make sure we handle signed vs. unsigned args correctly. */
+ testfmt("-1", "%jd", (intmax_t)-1);
+ testfmt(S_UINT64MAX, "%ju", UINT64_MAX);
+
+ testfmt("-1", "%td", (ptrdiff_t)-1);
+ testfmt(S_SIZEMAX, "%tu", (size_t)-1);
+
+ testfmt("-1", "%zd", (ssize_t)-1);
+ testfmt(S_SIZEMAX, "%zu", (ssize_t)-1);
+
+ testfmt("-1", "%ld", (long)-1);
+ testfmt(S_ULONGMAX, "%lu", ULONG_MAX);
+
+ testfmt("-1", "%lld", (long long)-1);
+ testfmt(S_ULLONGMAX, "%llu", ULLONG_MAX);
+
+ testfmt("-1", "%d", -1);
+ testfmt(S_UINT32MAX, "%u", UINT32_MAX);
+
+ testfmt("-1", "%hd", -1);
+ testfmt("65535", "%hu", USHRT_MAX);
+
+ testfmt("-1", "%hhd", -1);
+ testfmt("255", "%hhu", UCHAR_MAX);
+}
+
+ATF_TC_WITHOUT_HEAD(int_limits);
+ATF_TC_BODY(int_limits, tc)
+{
+
+ ATF_REQUIRE(setlocale(LC_NUMERIC, "C"));
+
+ /*
+ * Check that printing the largest negative number does not cause
+ * overflow when it is negated.
+ */
+ testfmt(S_INT32MIN, "%d", INT_MIN);
+ testfmt(S_INT64MIN, "%jd", INTMAX_MIN);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, int_within_limits);
+ ATF_TP_ADD_TC(tp, int_limits);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/stdio/printfloat_test.c b/lib/libc/tests/stdio/printfloat_test.c
new file mode 100644
index 000000000000..974374fae5ca
--- /dev/null
+++ b/lib/libc/tests/stdio/printfloat_test.c
@@ -0,0 +1,392 @@
+/*-
+ * Copyright (c) 2002-2009 David Schultz <das@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Test for printf() floating point formats.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <err.h>
+#include <fenv.h>
+#include <float.h>
+#include <locale.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+
+#include <atf-c.h>
+
+static void
+smash_stack(void)
+{
+ static uint32_t junk = 0xdeadbeef;
+ uint32_t buf[512];
+ int i;
+
+ for (i = 0; i < sizeof(buf) / sizeof(buf[0]); i++)
+ buf[i] = junk;
+}
+
+#define testfmt(result, fmt, ...) \
+ _testfmt((result), #__VA_ARGS__, fmt, __VA_ARGS__)
+static void
+_testfmt(const char *result, const char *argstr, const char *fmt,...)
+{
+#define BUF 100
+ wchar_t ws[BUF], wfmt[BUF], wresult[BUF];
+ char s[BUF];
+ va_list ap, ap2;
+
+ va_start(ap, fmt);
+ va_copy(ap2, ap);
+ smash_stack();
+ vsnprintf(s, sizeof(s), fmt, ap);
+ if (strcmp(result, s) != 0) {
+ atf_tc_fail(
+ "printf(\"%s\", %s) ==> [%s], expected [%s]",
+ fmt, argstr, s, result);
+ }
+
+ smash_stack();
+ mbstowcs(ws, s, BUF - 1);
+ mbstowcs(wfmt, fmt, BUF - 1);
+ mbstowcs(wresult, result, BUF - 1);
+ vswprintf(ws, sizeof(ws) / sizeof(ws[0]), wfmt, ap2);
+ if (wcscmp(wresult, ws) != 0) {
+ atf_tc_fail(
+ "wprintf(\"%ls\", %s) ==> [%ls], expected [%ls]",
+ wfmt, argstr, ws, wresult);
+ }
+ va_end(ap);
+ va_end(ap2);
+}
+
+ATF_TC_WITHOUT_HEAD(float_within_limits);
+ATF_TC_BODY(float_within_limits, tc)
+{
+
+ ATF_REQUIRE(setlocale(LC_NUMERIC, "C"));
+
+ /* Basic tests of decimal output functionality. */
+ testfmt(" 1.000000E+00", "%13E", 1.0);
+ testfmt(" 1.000000", "%13f", 1.0);
+ testfmt(" 1", "%13G", 1.0);
+ testfmt(" 1.000000E+00", "%13LE", 1.0L);
+ testfmt(" 1.000000", "%13Lf", 1.0L);
+ testfmt(" 1", "%13LG", 1.0L);
+
+ testfmt("2.718282", "%.*f", -2, 2.7182818);
+
+ testfmt("1.234568e+06", "%e", 1234567.8);
+ testfmt("1234567.800000", "%f", 1234567.8);
+ testfmt("1.23457E+06", "%G", 1234567.8);
+ testfmt("1.234568e+06", "%Le", 1234567.8L);
+ testfmt("1234567.800000", "%Lf", 1234567.8L);
+ testfmt("1.23457E+06", "%LG", 1234567.8L);
+
+#if (LDBL_MANT_DIG > DBL_MANT_DIG) && !defined(__i386__)
+ testfmt("123456789.864210", "%Lf", 123456789.8642097531L);
+ testfmt("-1.23457E+08", "%LG", -123456789.8642097531L);
+ testfmt("123456789.8642097531", "%.10Lf", 123456789.8642097531L);
+ testfmt(" 3.141592653589793238e-4000", "%L27.18Le",
+ 3.14159265358979323846e-4000L);
+#endif
+}
+
+ATF_TC_WITHOUT_HEAD(infinities_and_nans);
+ATF_TC_BODY(infinities_and_nans, tc)
+{
+
+ ATF_REQUIRE(setlocale(LC_NUMERIC, "C"));
+
+ testfmt("nan", "%e", NAN);
+ testfmt("NAN", "%F", NAN);
+ testfmt("nan", "%g", NAN);
+ testfmt("NAN", "%LE", (long double)NAN);
+ testfmt(" nan", "%05e", NAN);
+
+ testfmt("INF", "%E", HUGE_VAL);
+ testfmt("-inf", "%f", -HUGE_VAL);
+ testfmt("+inf", "%+g", HUGE_VAL);
+ testfmt(" inf", "%4.2Le", HUGE_VALL);
+ testfmt("-inf", "%Lf", -HUGE_VALL);
+ testfmt(" inf", "%05e", HUGE_VAL);
+ testfmt(" -inf", "%05e", -HUGE_VAL);
+}
+
+ATF_TC_WITHOUT_HEAD(padding);
+ATF_TC_BODY(padding, tc)
+{
+
+ ATF_REQUIRE(setlocale(LC_NUMERIC, "C"));
+
+ testfmt("0.000000e+00", "%e", 0.0);
+ testfmt("0.000000", "%F", (double)0.0);
+ testfmt("0", "%G", 0.0);
+ testfmt(" 0", "%3.0Lg", 0.0L);
+ testfmt(" 0", "%5.0f", 0.001);
+}
+
+ATF_TC_WITHOUT_HEAD(precision_specifiers);
+ATF_TC_BODY(precision_specifiers, tc)
+{
+
+ ATF_REQUIRE(setlocale(LC_NUMERIC, "C"));
+
+ testfmt("1.0123e+00", "%.4e", 1.0123456789);
+ testfmt("1.0123", "%.4f", 1.0123456789);
+ testfmt("1.012", "%.4g", 1.0123456789);
+ testfmt("1.2346e-02", "%.4e", 0.0123456789);
+ testfmt("0.0123", "%.4f", 0.0123456789);
+ testfmt("0.01235", "%.4g", 0.0123456789);
+}
+
+ATF_TC_WITHOUT_HEAD(thousands_separator_and_other_locale_tests);
+ATF_TC_BODY(thousands_separator_and_other_locale_tests, tc)
+{
+
+ ATF_REQUIRE(setlocale(LC_NUMERIC, "C"));
+
+ testfmt("12345678.0625", "%'.04f", 12345678.0625);
+ testfmt("0012345678.0625", "%'015.4F", 12345678.0625);
+
+ ATF_REQUIRE(setlocale(LC_NUMERIC, "hi_IN.ISCII-DEV")); /* grouping == 2;3 */
+ testfmt("1,23,45,678.0625", "%'.4f", 12345678.0625);
+ testfmt("01,23,45,678.0625", "%'017.4F", 12345678.0625);
+ testfmt(" 9,000", "%'6.0f", 9000.0);
+ testfmt("9,000.0", "%'.1f", 9000.0);
+
+ ATF_REQUIRE(setlocale(LC_NUMERIC, "ru_RU.ISO8859-5")); /* decimalpoint==, */
+ testfmt("3,1415", "%g", 3.1415);
+
+ /* thousands=. decimalpoint=, grouping=3;3 */
+ ATF_REQUIRE(setlocale(LC_NUMERIC, "el_GR.ISO8859-7")); /* decimalpoint==, */
+ testfmt("1.234,00", "%'.2f", 1234.00);
+ testfmt("123.456,789", "%'.3f", 123456.789);
+
+ ATF_REQUIRE(setlocale(LC_NUMERIC, "C"));
+ testfmt("12345678.062500", "%'f", 12345678.0625);
+ testfmt("9000.000000", "%'f", 9000.0);
+}
+
+ATF_TC_WITHOUT_HEAD(signed_conversions);
+ATF_TC_BODY(signed_conversions, tc)
+{
+
+ ATF_REQUIRE(setlocale(LC_NUMERIC, "C"));
+
+ testfmt("+2.500000e-01", "%+e", 0.25);
+ testfmt("+0.000000", "%+F", 0.0);
+ testfmt("-1", "%+g", -1.0);
+
+ testfmt("-1.000000e+00", "% e", -1.0);
+ testfmt("+1.000000", "% +f", 1.0);
+ testfmt(" 1", "% g", 1.0);
+ testfmt(" 0", "% g", 0.0);
+}
+
+ATF_TC_WITHOUT_HEAD(alternate_form);
+ATF_TC_BODY(alternate_form, tc)
+{
+
+ ATF_REQUIRE(setlocale(LC_NUMERIC, "C"));
+
+ testfmt("1.250e+00", "%#.3e", 1.25);
+ testfmt("123.000000", "%#f", 123.0);
+ testfmt(" 12345.", "%#7.5g", 12345.0);
+ testfmt(" 1.00000", "%#8g", 1.0);
+ testfmt("0.0", "%#.2g", 0.0);
+}
+
+ATF_TC_WITHOUT_HEAD(padding_and_decimal_point_placement);
+ATF_TC_BODY(padding_and_decimal_point_placement, tc)
+{
+
+ ATF_REQUIRE(setlocale(LC_NUMERIC, "C"));
+
+ testfmt("03.2E+00", "%08.1E", 3.25);
+ testfmt("003.25", "%06.2F", 3.25);
+ testfmt("0003.25", "%07.4G", 3.25);
+
+ testfmt("3.14159e-05", "%g", 3.14159e-5);
+ testfmt("0.000314159", "%g", 3.14159e-4);
+ testfmt("3.14159e+06", "%g", 3.14159e6);
+ testfmt("314159", "%g", 3.14159e5);
+ testfmt("314159.", "%#g", 3.14159e5);
+
+ testfmt(" 9.000000e+03", "%13e", 9000.0);
+ testfmt(" 9000.000000", "%12f", 9000.0);
+ testfmt(" 9000", "%5g", 9000.0);
+ testfmt(" 900000.", "%#8g", 900000.0);
+ testfmt(" 9e+06", "%6g", 9000000.0);
+ testfmt(" 9.000000e-04", "%13e", 0.0009);
+ testfmt(" 0.000900", "%9f", 0.0009);
+ testfmt(" 0.0009", "%7g", 0.0009);
+ testfmt(" 9e-05", "%6g", 0.00009);
+ testfmt(" 9.00000e-05", "%#12g", 0.00009);
+ testfmt(" 9.e-05", "%#7.1g", 0.00009);
+
+ testfmt(" 0.0", "%4.1f", 0.0);
+ testfmt("90.0", "%4.1f", 90.0);
+ testfmt(" 100", "%4.0f", 100.0);
+ testfmt("9.0e+01", "%4.1e", 90.0);
+ testfmt("1e+02", "%4.0e", 100.0);
+}
+
+ATF_TC_WITHOUT_HEAD(decimal_rounding);
+ATF_TC_BODY(decimal_rounding, tc)
+{
+
+ ATF_REQUIRE(setlocale(LC_NUMERIC, "C"));
+
+ fesetround(FE_DOWNWARD);
+ testfmt("4.437", "%.3f", 4.4375);
+ testfmt("-4.438", "%.3f", -4.4375);
+ testfmt("4.437", "%.3Lf", 4.4375L);
+ testfmt("-4.438", "%.3Lf", -4.4375L);
+
+ fesetround(FE_UPWARD);
+ testfmt("4.438", "%.3f", 4.4375);
+ testfmt("-4.437", "%.3f", -4.4375);
+ testfmt("4.438", "%.3Lf", 4.4375L);
+ testfmt("-4.437", "%.3Lf", -4.4375L);
+
+ fesetround(FE_TOWARDZERO);
+ testfmt("4.437", "%.3f", 4.4375);
+ testfmt("-4.437", "%.3f", -4.4375);
+ testfmt("4.437", "%.3Lf", 4.4375L);
+ testfmt("-4.437", "%.3Lf", -4.4375L);
+
+ fesetround(FE_TONEAREST);
+ testfmt("4.438", "%.3f", 4.4375);
+ testfmt("-4.438", "%.3f", -4.4375);
+ testfmt("4.438", "%.3Lf", 4.4375L);
+ testfmt("-4.438", "%.3Lf", -4.4375L);
+}
+
+ATF_TC_WITHOUT_HEAD(hexadecimal_floating_point);
+ATF_TC_BODY(hexadecimal_floating_point, tc)
+{
+
+ ATF_REQUIRE(setlocale(LC_NUMERIC, "C"));
+
+ /*
+ * Hexadecimal floating point (%a, %A) tests. Some of these
+ * are only valid if the implementation converts to hex digits
+ * on nibble boundaries.
+ */
+ testfmt("0x0p+0", "%a", 0x0.0p0);
+ testfmt("0X0.P+0", "%#LA", 0x0.0p0L);
+ testfmt("inf", "%La", (long double)INFINITY);
+ testfmt("+INF", "%+A", INFINITY);
+ testfmt("nan", "%La", (long double)NAN);
+ testfmt("NAN", "%A", NAN);
+
+ testfmt(" 0x1.23p+0", "%10a", 0x1.23p0);
+ testfmt(" 0x1.23p-500", "%12a", 0x1.23p-500);
+ testfmt(" 0x1.2p+40", "%10.1a", 0x1.23p40);
+ testfmt(" 0X1.230000000000000000000000P-4", "%32.24A", 0x1.23p-4);
+ testfmt("0x1p-1074", "%a", 0x1p-1074);
+ testfmt("0x1.2345p-1024", "%a", 0x1.2345p-1024);
+
+#if (LDBL_MANT_DIG == 64) && !defined(__i386__)
+ testfmt("0x1.921fb54442d18468p+1", "%La", 0x3.243f6a8885a308dp0L);
+ testfmt("0x1p-16445", "%La", 0x1p-16445L);
+ testfmt("0x1.30ecap-16381", "%La", 0x9.8765p-16384L);
+#elif (LDBL_MANT_DIG == 113)
+ testfmt("0x1.921fb54442d18469898cc51701b8p+1", "%La",
+ 0x3.243f6a8885a308d313198a2e037p0L);
+ testfmt("0x1p-16494", "%La", 0x1p-16494L);
+ testfmt("0x1.2345p-16384", "%La", 0x1.2345p-16384L);
+#else
+ testfmt("0x1.921fb54442d18p+1", "%La", 0x3.243f6a8885a31p0L);
+ testfmt("0x1p-1074", "%La", 0x1p-1074L);
+ testfmt("0x1.30ecap-1021", "%La", 0x9.8765p-1024L);
+#endif
+}
+
+ATF_TC_WITHOUT_HEAD(hexadecimal_rounding);
+ATF_TC_BODY(hexadecimal_rounding, tc)
+{
+
+ ATF_REQUIRE(setlocale(LC_NUMERIC, "C"));
+
+ fesetround(FE_TOWARDZERO);
+ testfmt("0X1.23456789ABCP+0", "%.11A", 0x1.23456789abcdep0);
+ testfmt("-0x1.23456p+0", "%.5a", -0x1.23456789abcdep0);
+ testfmt("0x1.23456p+0", "%.5a", 0x1.23456789abcdep0);
+ testfmt("0x1.234567p+0", "%.6a", 0x1.23456789abcdep0);
+ testfmt("-0x1.234566p+0", "%.6a", -0x1.23456689abcdep0);
+
+ fesetround(FE_DOWNWARD);
+ testfmt("0X1.23456789ABCP+0", "%.11A", 0x1.23456789abcdep0);
+ testfmt("-0x1.23457p+0", "%.5a", -0x1.23456789abcdep0);
+ testfmt("0x1.23456p+0", "%.5a", 0x1.23456789abcdep0);
+ testfmt("0x1.234567p+0", "%.6a", 0x1.23456789abcdep0);
+ testfmt("-0x1.234567p+0", "%.6a", -0x1.23456689abcdep0);
+
+ fesetround(FE_UPWARD);
+ testfmt("0X1.23456789ABDP+0", "%.11A", 0x1.23456789abcdep0);
+ testfmt("-0x1.23456p+0", "%.5a", -0x1.23456789abcdep0);
+ testfmt("0x1.23457p+0", "%.5a", 0x1.23456789abcdep0);
+ testfmt("0x1.234568p+0", "%.6a", 0x1.23456789abcdep0);
+ testfmt("-0x1.234566p+0", "%.6a", -0x1.23456689abcdep0);
+
+ fesetround(FE_TONEAREST);
+ testfmt("0x1.23456789abcdep+4", "%a", 0x1.23456789abcdep4);
+ testfmt("0X1.23456789ABDP+0", "%.11A", 0x1.23456789abcdep0);
+ testfmt("-0x1.23456p+0", "%.5a", -0x1.23456789abcdep0);
+ testfmt("0x1.23456p+0", "%.5a", 0x1.23456789abcdep0);
+ testfmt("0x1.234568p+0", "%.6a", 0x1.23456789abcdep0);
+ testfmt("-0x1.234567p+0", "%.6a", -0x1.23456689abcdep0);
+ testfmt("0x1.00p-1029", "%.2a", 0x1.fffp-1030);
+ testfmt("0x1.00p-1026", "%.2a", 0xf.fffp-1030);
+ testfmt("0x1.83p+0", "%.2a", 1.51);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, float_within_limits);
+ ATF_TP_ADD_TC(tp, infinities_and_nans);
+ ATF_TP_ADD_TC(tp, padding);
+ ATF_TP_ADD_TC(tp, precision_specifiers);
+ ATF_TP_ADD_TC(tp, thousands_separator_and_other_locale_tests);
+ ATF_TP_ADD_TC(tp, signed_conversions);
+ ATF_TP_ADD_TC(tp, alternate_form);
+ ATF_TP_ADD_TC(tp, padding_and_decimal_point_placement);
+ ATF_TP_ADD_TC(tp, decimal_rounding);
+ ATF_TP_ADD_TC(tp, hexadecimal_floating_point);
+ ATF_TP_ADD_TC(tp, hexadecimal_rounding);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/stdio/scanfloat_test.c b/lib/libc/tests/stdio/scanfloat_test.c
new file mode 100644
index 000000000000..7e27e69542e7
--- /dev/null
+++ b/lib/libc/tests/stdio/scanfloat_test.c
@@ -0,0 +1,316 @@
+/*-
+ * Copyright (C) 2003, 2005 David Schultz <das@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Test for scanf() floating point formats.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <fenv.h>
+#include <float.h>
+#include <locale.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <atf-c.h>
+
+#define eq(type, a, b) _eq(type##_EPSILON, (a), (b))
+static int
+_eq(long double epsilon, long double a, long double b)
+{
+ long double delta;
+
+ delta = fabsl(a - b);
+ return (delta <= epsilon);
+}
+
+ATF_TC_WITHOUT_HEAD(normalized_numbers);
+ATF_TC_BODY(normalized_numbers, tc)
+{
+ char buf[128];
+ long double ld = 0.0;
+ double d = 0.0;
+ float f = 0.0;
+
+ buf[0] = '\0';
+ ATF_REQUIRE(setlocale(LC_NUMERIC, ""));
+
+ sscanf("3.141592", "%e", &f);
+ ATF_REQUIRE(eq(FLT, f, 3.141592));
+
+ sscanf("3.141592653589793", "%lf", &d);
+ ATF_REQUIRE(eq(DBL, d, 3.141592653589793));
+
+ sscanf("1.234568e+06", "%E", &f);
+ ATF_REQUIRE(eq(FLT, f, 1.234568e+06));
+
+ sscanf("-1.234568e6", "%lF", &d);
+ ATF_REQUIRE(eq(DBL, d, -1.234568e6));
+
+ sscanf("+1.234568e-52", "%LG", &ld);
+ ATF_REQUIRE(eq(LDBL, ld, 1.234568e-52L));
+
+ sscanf("0.1", "%la", &d);
+ ATF_REQUIRE(eq(DBL, d, 0.1));
+
+ sscanf("00.2", "%lA", &d);
+ ATF_REQUIRE(eq(DBL, d, 0.2));
+
+ sscanf("123456", "%5le%s", &d, buf);
+ ATF_REQUIRE(eq(DBL, d, 12345.));
+ ATF_REQUIRE(strcmp(buf, "6") == 0);
+
+ sscanf("1.0Q", "%*5le%s", buf);
+ ATF_REQUIRE(strcmp(buf, "Q") == 0);
+
+ sscanf("-1.23e", "%e%s", &f, buf);
+ ATF_REQUIRE(eq(FLT, f, -1.23));
+ ATF_REQUIRE(strcmp(buf, "e") == 0);
+
+ sscanf("1.25e+", "%le%s", &d, buf);
+ ATF_REQUIRE(eq(DBL, d, 1.25));
+ ATF_REQUIRE(strcmp(buf, "e+") == 0);
+
+ sscanf("1.23E4E5", "%le%s", &d, buf);
+ ATF_REQUIRE(eq(DBL, d, 1.23e4));
+ ATF_REQUIRE(strcmp(buf, "E5") == 0);
+
+ sscanf("12e6", "%le", &d);
+ ATF_REQUIRE(eq(DBL, d, 12e6));
+
+ sscanf("1.a", "%le%s", &d, buf);
+ ATF_REQUIRE(eq(DBL, d, 1.0));
+ ATF_REQUIRE(strcmp(buf, "a") == 0);
+
+ sscanf(".0p4", "%le%s", &d, buf);
+ ATF_REQUIRE(eq(DBL, d, 0.0));
+ ATF_REQUIRE(strcmp(buf, "p4") == 0);
+
+ d = 0.25;
+ ATF_REQUIRE(sscanf(".", "%le", &d) == 0);
+ ATF_REQUIRE(d == 0.25);
+
+ sscanf("0x08", "%le", &d);
+ ATF_REQUIRE(d == 0x8p0);
+
+ sscanf("0x90a.bcdefP+09a", "%le%s", &d, buf);
+ ATF_REQUIRE(d == 0x90a.bcdefp+09);
+ ATF_REQUIRE(strcmp(buf, "a") == 0);
+
+#if (LDBL_MANT_DIG > DBL_MANT_DIG) && !defined(__i386__)
+ sscanf("3.14159265358979323846", "%Lg", &ld);
+ ATF_REQUIRE(eq(LDBL, ld, 3.14159265358979323846L));
+
+ sscanf(" 0X.0123456789abcdefffp-3g", "%Le%s", &ld, buf);
+ ATF_REQUIRE(ld == 0x0.0123456789abcdefffp-3L);
+ ATF_REQUIRE(strcmp(buf, "g") == 0);
+#endif
+
+ sscanf("0xg", "%le%s", &d, buf);
+ ATF_REQUIRE(d == 0.0);
+ ATF_REQUIRE(strcmp(buf, "xg") == 0);
+
+ ATF_REQUIRE(setlocale(LC_NUMERIC, "ru_RU.ISO8859-5")); /* decimalpoint==, */
+
+ sscanf("1.23", "%le%s", &d, buf);
+ ATF_REQUIRE(d == 1.0);
+ ATF_REQUIRE(strcmp(buf, ".23") == 0);
+
+ sscanf("1,23", "%le", &d);
+ ATF_REQUIRE(d == 1.23);
+
+ ATF_REQUIRE(setlocale(LC_NUMERIC, ""));
+}
+
+ATF_TC_WITHOUT_HEAD(infinities_and_nans);
+ATF_TC_BODY(infinities_and_nans, tc)
+{
+ char buf[128];
+ long double ld = 0.0;
+ double d = 0.0;
+ float f = 0.0;
+
+ ATF_REQUIRE(setlocale(LC_NUMERIC, "C"));
+
+ sscanf("-Inf", "%le", &d);
+ ATF_REQUIRE(d < 0.0 && isinf(d));
+
+ sscanf("iNfInItY and beyond", "%le%s", &d, buf);
+ ATF_REQUIRE(d > 0.0 && isinf(d));
+ ATF_REQUIRE(strcmp(buf, " and beyond"));
+
+ sscanf("NaN", "%le", &d);
+ ATF_REQUIRE(isnan(d));
+
+ sscanf("NAN(123Y", "%le%s", &d, buf);
+ ATF_REQUIRE(isnan(d));
+ ATF_REQUIRE(strcmp(buf, "(123Y") == 0);
+
+ sscanf("nan(f00f)plugh", "%le%s", &d, buf);
+ ATF_REQUIRE(isnan(d));
+ ATF_REQUIRE(strcmp(buf, "plugh") == 0);
+
+ sscanf("-nan", "%le", &d);
+ ATF_REQUIRE(isnan(d));
+
+ /* Only quiet NaNs should be returned. */
+ sscanf("NaN", "%e", &f);
+ sscanf("nan", "%le", &d);
+ sscanf("nan", "%Le", &ld);
+ feclearexcept(FE_ALL_EXCEPT);
+ ATF_REQUIRE(f != f);
+ ATF_REQUIRE(d != d);
+ ATF_REQUIRE(ld != ld);
+ ATF_REQUIRE(fetestexcept(FE_INVALID) == 0);
+ sscanf("nan(1234)", "%e", &f);
+ sscanf("nan(1234)", "%le", &d);
+ sscanf("nan(1234)", "%Le", &ld);
+ feclearexcept(FE_ALL_EXCEPT);
+ ATF_REQUIRE(f != f);
+ ATF_REQUIRE(d != d);
+ ATF_REQUIRE(ld != ld);
+ /* POSIX says we should only generate quiet NaNs. */
+ ATF_REQUIRE(fetestexcept(FE_INVALID) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(rounding_tests);
+ATF_TC_BODY(rounding_tests, tc)
+{
+ long double ld = 0.0;
+ double d = 0.0;
+
+ ATF_REQUIRE(setlocale(LC_NUMERIC, "C"));
+
+ fesetround(FE_DOWNWARD);
+
+ sscanf("1.999999999999999999999999999999999", "%le", &d);
+ ATF_REQUIRE(d < 2.0);
+ sscanf("0x1.ffffffffffffffp0", "%le", &d);
+ ATF_REQUIRE(d < 2.0);
+ sscanf("1.999999999999999999999999999999999", "%Le", &ld);
+ ATF_REQUIRE(ld < 2.0);
+
+ sscanf("1.0571892669084007", "%le", &d);
+ ATF_REQUIRE(d == 0x1.0ea3f4af0dc59p0);
+ sscanf("-1.0571892669084007", "%le", &d);
+ ATF_REQUIRE(d == -0x1.0ea3f4af0dc5ap0);
+ sscanf("1.0571892669084010", "%le", &d);
+ ATF_REQUIRE(d == 0x1.0ea3f4af0dc5ap0);
+
+ sscanf("0x1.23p-5000", "%le", &d);
+ ATF_REQUIRE(d == 0.0);
+
+ sscanf("0x1.2345678p-1050", "%le", &d);
+ ATF_REQUIRE(d == 0x1.234567p-1050);
+
+ fesetround(FE_UPWARD);
+
+ sscanf("1.0571892669084007", "%le", &d);
+ ATF_REQUIRE(d == 0x1.0ea3f4af0dc5ap0);
+ sscanf("-1.0571892669084007", "%le", &d);
+ ATF_REQUIRE(d == -0x1.0ea3f4af0dc59p0);
+ sscanf("1.0571892669084010", "%le", &d);
+ ATF_REQUIRE(d == 0x1.0ea3f4af0dc5bp0);
+
+ sscanf("0x1.23p-5000", "%le", &d);
+ ATF_REQUIRE(d == 0x1p-1074);
+
+ sscanf("0x1.2345678p-1050", "%le", &d);
+ ATF_REQUIRE(d == 0x1.234568p-1050);
+
+ fesetround(FE_TOWARDZERO);
+
+ sscanf("1.0571892669084007", "%le", &d);
+ ATF_REQUIRE(d == 0x1.0ea3f4af0dc59p0);
+ sscanf("-1.0571892669084007", "%le", &d);
+ ATF_REQUIRE(d == -0x1.0ea3f4af0dc59p0);
+ sscanf("1.0571892669084010", "%le", &d);
+ ATF_REQUIRE(d == 0x1.0ea3f4af0dc5ap0);
+
+ sscanf("0x1.23p-5000", "%le", &d);
+ ATF_REQUIRE(d == 0.0);
+
+ sscanf("0x1.2345678p-1050", "%le", &d);
+ ATF_REQUIRE(d == 0x1.234567p-1050);
+
+ fesetround(FE_TONEAREST);
+
+ /* 1.0571892669084007 is slightly closer to 0x1.0ea3f4af0dc59p0 */
+ sscanf("1.0571892669084007", "%le", &d);
+ ATF_REQUIRE(d == 0x1.0ea3f4af0dc59p0);
+ sscanf("-1.0571892669084007", "%le", &d);
+ ATF_REQUIRE(d == -0x1.0ea3f4af0dc59p0);
+ sscanf("1.0571892669084010", "%le", &d);
+ ATF_REQUIRE(d == 0x1.0ea3f4af0dc5bp0);
+
+ /* strtod() should round small numbers to 0. */
+ sscanf("0x1.23p-5000", "%le", &d);
+ ATF_REQUIRE(d == 0.0);
+
+ /* Extra digits in a denormal shouldn't break anything. */
+ sscanf("0x1.2345678p-1050", "%le", &d);
+ ATF_REQUIRE(d == 0x1.234568p-1050);
+}
+
+ATF_TC_WITHOUT_HEAD(strtod);
+ATF_TC_BODY(strtod, tc)
+{
+ char *endp;
+
+ ATF_REQUIRE(setlocale(LC_NUMERIC, "C"));
+
+ ATF_REQUIRE(strtod("0xy", &endp) == 0);
+ ATF_REQUIRE(strcmp("xy", endp) == 0);
+
+ /* This used to cause an infinite loop and round the wrong way. */
+ fesetround(FE_DOWNWARD);
+ ATF_REQUIRE(strtof("3.5e38", &endp) == FLT_MAX);
+ ATF_REQUIRE(strtod("2e308", &endp) == DBL_MAX);
+ fesetround(FE_UPWARD);
+ ATF_REQUIRE(strtof("3.5e38", &endp) == INFINITY);
+ ATF_REQUIRE(strtod("2e308", &endp) == INFINITY);
+ fesetround(FE_TOWARDZERO);
+ ATF_REQUIRE(strtof("3.5e38", &endp) == FLT_MAX);
+ ATF_REQUIRE(strtod("2e308", &endp) == DBL_MAX);
+ fesetround(FE_TONEAREST);
+ ATF_REQUIRE(strtof("3.5e38", &endp) == INFINITY);
+ ATF_REQUIRE(strtod("2e308", &endp) == INFINITY);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, normalized_numbers);
+ ATF_TP_ADD_TC(tp, infinities_and_nans);
+ ATF_TP_ADD_TC(tp, rounding_tests);
+ ATF_TP_ADD_TC(tp, strtod);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/stdlib/Makefile b/lib/libc/tests/stdlib/Makefile
new file mode 100644
index 000000000000..c681cb604383
--- /dev/null
+++ b/lib/libc/tests/stdlib/Makefile
@@ -0,0 +1,63 @@
+# $FreeBSD$
+
+.include <src.opts.mk>
+
+ATF_TESTS_C+= heapsort_test
+ATF_TESTS_C+= mergesort_test
+ATF_TESTS_C+= qsort_test
+ATF_TESTS_C+= tsearch_test
+.if ${COMPILER_FEATURES:Mc++11}
+ATF_TESTS_CXX+= cxa_thread_atexit_test
+ATF_TESTS_CXX+= cxa_thread_atexit_nothr_test
+.endif
+
+# Not sure why this isn't defined for all architectures, since most
+# have long double.
+.if ${MACHINE_CPUARCH} == "aarch64" || \
+ ${MACHINE_CPUARCH} == "amd64" || \
+ ${MACHINE_CPUARCH} == "i386"
+CFLAGS+= -D__HAVE_LONG_DOUBLE
+.endif
+
+# TODO: t_getenv_thread, t_mi_vector_hash, t_strtoi
+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
+
+CFLAGS+= -I${.CURDIR}
+
+CXXFLAGS.cxa_thread_atexit_test+= -std=c++11
+CXXFLAGS.cxa_thread_atexit_nothr_test+= -std=c++11
+LIBADD.cxa_thread_atexit_test+= pthread
+
+.for t in h_getopt h_getopt_long
+CFLAGS.$t+= -I${LIBNETBSD_SRCDIR} -I${SRCTOP}/contrib/netbsd-tests
+LDFLAGS.$t+= -L${LIBNETBSD_OBJDIR}
+
+LIBADD.${t}+= netbsd util
+.endfor
+
+LIBADD.strtod_test+= m
+
+.include <bsd.test.mk>
diff --git a/lib/libc/tests/stdlib/Makefile.depend b/lib/libc/tests/stdlib/Makefile.depend
new file mode 100644
index 000000000000..1ace922e7b2a
--- /dev/null
+++ b/lib/libc/tests/stdlib/Makefile.depend
@@ -0,0 +1,26 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ gnu/lib/csu \
+ gnu/lib/libgcc \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/atf/libatf-c \
+ lib/atf/libatf-c++ \
+ lib/libc \
+ lib/libc++ \
+ lib/libcompiler_rt \
+ lib/libcxxrt \
+ lib/libnetbsd \
+ lib/libthr \
+ lib/libutil \
+ lib/msun \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/lib/libc/tests/stdlib/cxa_thread_atexit_nothr_test.cc b/lib/libc/tests/stdlib/cxa_thread_atexit_nothr_test.cc
new file mode 100644
index 000000000000..3ac360279e8a
--- /dev/null
+++ b/lib/libc/tests/stdlib/cxa_thread_atexit_nothr_test.cc
@@ -0,0 +1,102 @@
+/*-
+ * Copyright (c) 2016 Mahdi Mokhtari <mokhi64@gmail.com>
+ * Copyright (c) 2016 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <dlfcn.h>
+#include <atf-c++.hpp>
+#include <cstdio>
+#include <cstdlib>
+
+static FILE *output = NULL;
+
+struct Foo {
+ Foo() { ATF_REQUIRE(fprintf(output, "Created\n") > 0); }
+ ~Foo() { ATF_REQUIRE(fprintf(output, "Destroyed\n") > 0); }
+ void use() { ATF_REQUIRE(fprintf(output, "Used\n") > 0); }
+};
+
+static thread_local Foo f;
+
+/*
+ * This test must not be linked to libpthread.
+ */
+ATF_TEST_CASE_WITHOUT_HEAD(cxx__nothr);
+ATF_TEST_CASE_BODY(cxx__nothr)
+{
+ void *libthr_handle;
+
+ /* Avoid coredump during f construction. */
+ output = stderr;
+
+ libthr_handle = dlopen("libthr.so.3", RTLD_LAZY | RTLD_GLOBAL |
+ RTLD_NOLOAD);
+ ATF_REQUIRE(libthr_handle == NULL);
+}
+
+static void
+check_local_main(void)
+{
+ static const char out_log[] = "Created\nUsed\nDestroyed\n";
+
+ fflush(output);
+ ATF_REQUIRE(atf::utils::compare_file("test_main.txt", out_log));
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(cxx__thread_local_main);
+ATF_TEST_CASE_BODY(cxx__thread_local_main)
+{
+
+ ATF_REQUIRE((output = fopen("test_main.txt", "w")) != NULL);
+ f.use();
+ atexit(check_local_main);
+}
+
+extern "C" int __cxa_thread_atexit(void (*)(void *), void *, void *);
+
+static void
+again(void *arg)
+{
+
+ __cxa_thread_atexit(again, arg, &output);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(cxx__thread_inf_dtors);
+ATF_TEST_CASE_BODY(cxx__thread_inf_dtors)
+{
+
+ again(NULL);
+}
+
+ATF_INIT_TEST_CASES(tcs)
+{
+
+ ATF_ADD_TEST_CASE(tcs, cxx__nothr);
+ ATF_ADD_TEST_CASE(tcs, cxx__thread_local_main);
+ ATF_ADD_TEST_CASE(tcs, cxx__thread_inf_dtors);
+}
diff --git a/lib/libc/tests/stdlib/cxa_thread_atexit_test.cc b/lib/libc/tests/stdlib/cxa_thread_atexit_test.cc
new file mode 100644
index 000000000000..ded91c943c8a
--- /dev/null
+++ b/lib/libc/tests/stdlib/cxa_thread_atexit_test.cc
@@ -0,0 +1,180 @@
+/*-
+ * Copyright (c) 2016 Mahdi Mokhtari <mokhi64@gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <dlfcn.h>
+#include <atf-c++.hpp>
+#include <cstdio>
+#include <cstdlib>
+#include <thread>
+
+static FILE *output = NULL;
+
+struct Foo {
+ Foo() { ATF_REQUIRE(fprintf(output, "Created\n") > 0); }
+ ~Foo() { ATF_REQUIRE(fprintf(output, "Destroyed\n") > 0); }
+ void use() { ATF_REQUIRE(fprintf(output, "Used\n") > 0); }
+};
+
+struct Bar {
+ Bar() {}
+ ~Bar() {
+ thread_local static Foo foo;
+ ATF_REQUIRE(fprintf(output, "DIED\n") > 0);
+ }
+ void use() {}
+};
+
+extern "C" int __cxa_thread_atexit(void (*)(void *), void *, void *);
+
+static void
+again(void *arg)
+{
+
+ __cxa_thread_atexit(again, arg, &output);
+}
+
+struct Baz {
+ Baz() {}
+ ~Baz() {
+ again(NULL);
+ }
+ void use() {}
+};
+
+static thread_local Foo f;
+static thread_local Foo g;
+static thread_local Bar h;
+static thread_local Baz e;
+
+/*
+ * This test must be linked to libpthread.
+ */
+ATF_TEST_CASE_WITHOUT_HEAD(cxx__thr);
+ATF_TEST_CASE_BODY(cxx__thr)
+{
+ void *libthr_handle;
+
+ /* Avoid coredump during f construction. */
+ output = stderr;
+
+ libthr_handle = dlopen("libthr.so.3", RTLD_LAZY | RTLD_GLOBAL |
+ RTLD_NOLOAD);
+ ATF_REQUIRE(libthr_handle != NULL);
+ dlclose(libthr_handle);
+}
+
+/*
+ * In this test f.use() will test cxa_thread_atexit() in non-threaded mode.
+ * After f.use() main will be threaded and we'll have one additional thread
+ * with its own TLS data.
+ */
+ATF_TEST_CASE_WITHOUT_HEAD(cxx__thread_local_before);
+ATF_TEST_CASE_BODY(cxx__thread_local_before)
+{
+ static const char out_log[] = "Created\nCreated\nUsed\nCreated\n"
+ "Created\nUsed\nCreated\nDIED\nDestroyed\nDestroyed\nDestroyed\n";
+
+ ATF_REQUIRE((output = fopen("test_before.txt", "w")) != NULL);
+
+ f.use();
+ std::thread t([]() { f.use(); });
+ t.join();
+
+ fflush(output);
+
+ ATF_REQUIRE(atf::utils::compare_file("test_before.txt", out_log));
+}
+
+/*
+ * In this test, f.use() will test __cxa_thread_atexit()
+ * in threaded mode (but still in main-threaed).
+ */
+ATF_TEST_CASE_WITHOUT_HEAD(cxx__thread_local_after);
+ATF_TEST_CASE_BODY(cxx__thread_local_after)
+{
+ static const char out_log[] = "Created\nCreated\nUsed\nCreated\n"
+ "DIED\nDestroyed\nDestroyed\nDestroyed\nCreated\nCreated\nUsed\n";
+
+ ATF_REQUIRE((output = fopen("test_after.txt", "w")) != NULL);
+
+ std::thread t([]() { g.use(); });
+ t.join();
+ sleep(1);
+ g.use();
+
+ fflush(output);
+
+ ATF_REQUIRE(atf::utils::compare_file("test_after.txt", out_log));
+}
+
+/*
+ * In this test, we register a new dtor while dtors are being run
+ * in __cxa_thread_atexit().
+ */
+ATF_TEST_CASE_WITHOUT_HEAD(cxx__thread_local_add_while_calling_dtors);
+ATF_TEST_CASE_BODY(cxx__thread_local_add_while_calling_dtors)
+{
+ static const char out_log[] = "Created\nCreated\nCreated\nDIED\n"
+ "Destroyed\nDestroyed\nDestroyed\n";
+
+ ATF_REQUIRE((output = fopen("test_add_meanwhile.txt", "w")) != NULL);
+
+ std::thread t([]() { h.use(); });
+ t.join();
+ sleep(1);
+
+ fflush(output);
+
+ ATF_REQUIRE(atf::utils::compare_file("test_add_meanwhile.txt", out_log));
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(cxx__thread_inf_dtors);
+ATF_TEST_CASE_BODY(cxx__thread_inf_dtors)
+{
+
+ /*
+ * Only added to make isolated run of this test not
+ * coredumping. Construction of Foo objects require filled
+ * output.
+ */
+ output = stderr;
+
+ std::thread t([]() { e.use(); });
+ t.join();
+}
+
+ATF_INIT_TEST_CASES(tcs)
+{
+
+ ATF_ADD_TEST_CASE(tcs, cxx__thr);
+ ATF_ADD_TEST_CASE(tcs, cxx__thread_local_before);
+ ATF_ADD_TEST_CASE(tcs, cxx__thread_local_after);
+ ATF_ADD_TEST_CASE(tcs, cxx__thread_local_add_while_calling_dtors);
+ ATF_ADD_TEST_CASE(tcs, cxx__thread_inf_dtors);
+}
diff --git a/lib/libc/tests/stdlib/heapsort_test.c b/lib/libc/tests/stdlib/heapsort_test.c
new file mode 100644
index 000000000000..a83786d1cc5f
--- /dev/null
+++ b/lib/libc/tests/stdlib/heapsort_test.c
@@ -0,0 +1,71 @@
+/*-
+ * Copyright (C) 2004 Maxim Sobolev <sobomax@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Test for heapsort() routine.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "test-sort.h"
+
+ATF_TC_WITHOUT_HEAD(heapsort_test);
+ATF_TC_BODY(heapsort_test, tc)
+{
+ int sresvector[IVEC_LEN];
+ int testvector[IVEC_LEN];
+ int i, j;
+
+ for (j = 2; j < IVEC_LEN; j++) {
+ /* Populate test vectors */
+ for (i = 0; i < j; i++)
+ testvector[i] = sresvector[i] = initvector[i];
+
+ /* Sort using heapsort(3) */
+ heapsort(testvector, j, sizeof(testvector[0]), sorthelp);
+ /* Sort using reference slow sorting routine */
+ ssort(sresvector, j);
+
+ /* Compare results */
+ for (i = 0; i < j; i++)
+ ATF_CHECK_MSG(testvector[i] == sresvector[i],
+ "item at index %d didn't match: %d != %d",
+ i, testvector[i], sresvector[i]);
+ }
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, heapsort_test);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/stdlib/mergesort_test.c b/lib/libc/tests/stdlib/mergesort_test.c
new file mode 100644
index 000000000000..4334b924f6bb
--- /dev/null
+++ b/lib/libc/tests/stdlib/mergesort_test.c
@@ -0,0 +1,71 @@
+/*-
+ * Copyright (C) 2004 Maxim Sobolev <sobomax@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Test for mergesort() routine.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "test-sort.h"
+
+ATF_TC_WITHOUT_HEAD(mergesort_test);
+ATF_TC_BODY(mergesort_test, tc)
+{
+ int sresvector[IVEC_LEN];
+ int testvector[IVEC_LEN];
+ int i, j;
+
+ for (j = 2; j < IVEC_LEN; j++) {
+ /* Populate test vectors */
+ for (i = 0; i < j; i++)
+ testvector[i] = sresvector[i] = initvector[i];
+
+ /* Sort using mergesort(3) */
+ mergesort(testvector, j, sizeof(testvector[0]), sorthelp);
+ /* Sort using reference slow sorting routine */
+ ssort(sresvector, j);
+
+ /* Compare results */
+ for (i = 0; i < j; i++)
+ ATF_CHECK_MSG(testvector[i] == sresvector[i],
+ "item at index %d didn't match: %d != %d",
+ i, testvector[i], sresvector[i]);
+ }
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, mergesort_test);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/stdlib/qsort_test.c b/lib/libc/tests/stdlib/qsort_test.c
new file mode 100644
index 000000000000..14e02925dfa5
--- /dev/null
+++ b/lib/libc/tests/stdlib/qsort_test.c
@@ -0,0 +1,71 @@
+/*-
+ * Copyright (C) 2004 Maxim Sobolev <sobomax@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Test for qsort() routine.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "test-sort.h"
+
+ATF_TC_WITHOUT_HEAD(qsort_test);
+ATF_TC_BODY(qsort_test, tc)
+{
+ int testvector[IVEC_LEN];
+ int sresvector[IVEC_LEN];
+ int i, j;
+
+ for (j = 2; j < IVEC_LEN; j++) {
+ /* Populate test vectors */
+ for (i = 0; i < j; i++)
+ testvector[i] = sresvector[i] = initvector[i];
+
+ /* Sort using qsort(3) */
+ qsort(testvector, j, sizeof(testvector[0]), sorthelp);
+ /* Sort using reference slow sorting routine */
+ ssort(sresvector, j);
+
+ /* Compare results */
+ for (i = 0; i < j; i++)
+ ATF_CHECK_MSG(testvector[i] == sresvector[i],
+ "item at index %d didn't match: %d != %d",
+ i, testvector[i], sresvector[i]);
+ }
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, qsort_test);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/stdlib/test-sort.h b/lib/libc/tests/stdlib/test-sort.h
new file mode 100644
index 000000000000..f038acdb42cc
--- /dev/null
+++ b/lib/libc/tests/stdlib/test-sort.h
@@ -0,0 +1,273 @@
+/*-
+ * Copyright (C) 2004 Maxim Sobolev <sobomax@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _TEST_SORT_H
+#define _TEST_SORT_H
+
+#include <sys/param.h>
+
+#include <atf-c.h>
+
+static int
+sorthelp(const void *a, const void *b)
+{
+ const int *oa, *ob;
+
+ oa = a;
+ ob = b;
+ /* Don't use "return *oa - *ob" since it's easy to cause overflow! */
+ if (*oa > *ob)
+ return (1);
+ if (*oa < *ob)
+ return (-1);
+ return (0);
+}
+
+/* Reference sorting routine (slooow!) */
+static void
+ssort(int v[], int nmemb)
+{
+ int i, j, k;
+
+ for (i = 0; i < nmemb; i++) {
+ for (j = i + 1; j < nmemb; j++) {
+ if (v[j] < v[i]) {
+ k = v[i];
+ v[i] = v[j];
+ v[j] = k;
+ }
+ }
+ }
+}
+
+/* Some random data */
+static int initvector[1024] = {
+ 599853225, 371951333, -428880425, 1450668530, 85530178, -460170550,
+ -270680269, 717137591, 106244401, -1138072905, -113532586,
+ 599690958, 464993720, 107690177, 24249019, -1151018550, 794225588,
+ 1494905642, -62951716, -734531757, 1197251494, 1020063925,
+ -634536734, -216634704, 617366508, -18840190, 481010395,
+ -1555785724, 128221950, -1747743676, 1119012320, -252160437,
+ 617137855, 1159833073, -106647920, -1570719046, -769400990,
+ -130308848, 1186546396, 215253591, 445832488, 160263176, 777264170,
+ -274636650, -696134447, 1057957088, -626175254, 188632134,
+ -98941793, -1602334908, -373717125, 885013862, 571258221,
+ -399572192, 407761463, -733249776, 12094800, -367046815, 178974501,
+ -452638559, -516580143, -94282073, 1411115180, -1151792797,
+ 1442815268, 1106583674, 515269284, -74019972, 598818901, 696848474,
+ -657910766, -287309335, 1538095746, 143543003, 851444033,
+ -947573348, 296222973, 1339592140, -947505360, 872027891,
+ -418844714, -583075597, -324758197, -964531573, 1016795914,
+ -866842580, -304084402, -286930819, 338975583, 803597943,
+ -452483372, 1525283506, -1185830826, -596405894, 905191340,
+ -1638026278, 106749913, 582771197, -730713796, 56052422,
+ 1498040174, 644967266, 182541575, 280483468, -1932835017,
+ -435546874, 940106007, 1753388509, -340355019, -231577358,
+ -714879035, 1051182949, 204261785, 1321346243, -895289878,
+ -240369893, 566608506, -350777580, -1384849829, -876816409,
+ 1013787299, -1408035937, -222626650, 1708168486, -645148461,
+ 1854654, -393012507, 179327030, -1607975548, -715202732, 730588290,
+ 246968517, -550975254, -101136772, -174103176, 1188941016,
+ 2004650834, -1501389866, -2021225998, 1219042515, -464113898,
+ 268565342, 126451123, -1045877126, -198918003, 310177444,
+ 1578314812, 1828867082, 453336898, -908485523, 749777130,
+ -1028565802, 61360571, 241484853, -175693399, 1816211059,
+ 533940889, -1496933703, 385185125, -821132413, -8923391,
+ -1429546239, 46190992, 449247332, -20432494, 778761611, -178782699,
+ -811194695, -632276211, 70196094, 890817525, -1447776908,
+ -323783741, -62333222, 954929503, 247668507, -1394420605,
+ 367913886, 1364926759, 1298781924, 357923028, -73644747,
+ -319744305, 61718202, -1454549286, 387493522, 2018321449,
+ 861026653, 289973298, 1755939093, -84772204, 43425266, -1325753781,
+ -679938775, 1228500370, -763816405, 548903035, 1765563727,
+ 425183052, 1424621863, -188287424, 554385654, 751831998,
+ 1377088085, 66622090, 139224450, -1305816167, 650140724, 593988868,
+ -444913321, 589045097, 1261428989, 101292769, -780376786,
+ 559307348, 1644593236, -1838606833, 53570301, -680576100,
+ -44969538, 268718267, -632104125, 276904628, 626299449, -11761453,
+ 545899086, -1027343598, -432251872, 539353494, -399575006,
+ -568383580, -677802882, 1296513472, 801202048, 806425805, 1983363,
+ 850487421, 38046173, 1535399484, 1998285544, -1301751898,
+ -46561973, 56545408, -1107662676, 456041145, -452923904,
+ -262219453, -371849200, 392524281, 1650231392, 1185585356,
+ 126610511, -1125389657, 1015981177, -1318481342, -213835789,
+ 1263484054, -654361441, 1408272041, -231555284, -1121778152,
+ -395512897, 332277674, -349703586, 1809474399, -223731607,
+ -1342224737, 736165236, 67535587, 89879082, 471445838, 423788300,
+ -384354470, 907475706, 154886390, -1406736539, -8558766,
+ -203405718, -422127884, 1048520863, 747418501, 87438975, 727668160,
+ -914936981, 428266976, -455742009, -949014605, 487159058,
+ -262526850, -309451504, -76928461, 1072951428, -1370953830,
+ 238231681, -1831047244, -405735199, -35941848, 469048670,
+ 505307987, -660553590, 876537439, -314195871, 999234339,
+ -1405846240, -579885695, 629067031, 863481510, -742301385,
+ -1723403128, -153070386, 782682839, -343111818, -877101810,
+ 1438467302, -319951459, -1585702508, -338381888, 484108815,
+ -1726935191, -749923706, 1657932127, -816151395, -566321865,
+ -133542331, 84961164, 598275578, 1302065347, -533098653,
+ -1766383037, 53169714, -464201288, 617735133, 862536123,
+ -141730724, -1967377125, -1023736305, -1012511106, 64484992,
+ -1250856831, 426409332, -355670055, -298251663, -867634978,
+ -776124819, 74018333, -425385214, -108004251, -1192766130,
+ 1294193867, -109867195, -78667637, 1164855393, -826007552,
+ -522528066, 1160283046, -1095276403, -1218917472, -396475366,
+ -77394733, -425603169, 251928357, -393559355, 1488845184,
+ 898455978, -773338691, -37627855, -345014717, 204298578, 209084274,
+ 1047080643, -414348222, 26496664, 705759824, 575149152, 604904761,
+ 624988690, 1446041250, 1000757225, -1354896151, 1422958189,
+ -1607165311, -832757521, 365074225, 1171764999, 1200795217,
+ -203957828, 23166236, -846818698, -547439867, -790192498,
+ -122123561, 914298013, 66225525, -36163174, -480698856,
+ -1269421818, 624641703, 254923102, 1564329013, -583609221,
+ -649433551, -743396069, 1182455435, 102658744, 285599336,
+ 692480463, -852737563, -660090184, 1374350065, 72300985, 690541659,
+ -1194212957, -1151816525, 157415641, 487398246, 1030153072,
+ 933723020, 1359181027, -1303457764, -1543773272, 774306017,
+ -854382652, 755485667, -864943584, -63242545, -1271480354,
+ 157720215, -205001173, 889984130, -581583822, -473779111,
+ -932136577, 735326252, 428638717, 1888884222, 561493709,
+ -1966427364, -1710208603, 340121869, 918894036, 927172509,
+ 904178436, 1476687667, 90796414, 651591731, -550913123, -42218158,
+ 637756529, 1091478400, 124976584, -48739309, -798898083, 393581349,
+ -1078624722, -789291577, 1010582542, -512317005, 1222773656,
+ 466454593, 1183558811, 822782663, -851624703, -850404012,
+ 1473672600, 852527073, 1073953362, 137635828, 936104739, -86567759,
+ -882563252, 1845232980, -737978404, -104703380, 149802989,
+ -349118325, 1479797538, 1966007488, 1254228842, 414304661,
+ -790805785, 31583329, -76864151, 558202855, -1447047313, 716720607,
+ -404224238, -54107627, 1747385914, -657407390, 202940208,
+ 1083067056, -532861378, 163426933, -130289277, 1301785258,
+ -302920320, -637947485, -644895903, -1668027530, 391890467,
+ -126586485, -536836984, -1154536413, -339505118, -1187229462,
+ -670985870, -601310813, -1350055158, -482479784, 139847714,
+ -253955849, 5190414, -542857077, 1175835684, -584165057,
+ 1132775766, -592091269, -891445655, -340995936, 736395810,
+ 779967964, 515095845, -1138437307, -259226729, -167820100,
+ -801611617, -282451622, -1313679283, -1436126694, 1258773990,
+ -717601098, -583559645, -1307478759, 1238647247, 1589011223,
+ -1029216445, -107030650, 400152690, -1349079913, 1428582247,
+ 21546946, 208807686, -169450574, -1086213374, -1242715198,
+ 669098277, 416626722, -1122525014, -1389466669, -391843085,
+ -56318357, 421040094, 212303518, 738666684, -1185364904,
+ -506192760, 646735912, -1424722633, 745226976, 1019191717,
+ -190891744, -310320868, -373655022, -665117060, 830760000,
+ 583906512, -330536027, 611092636, -321344259, -1255008904,
+ -777959046, -523043472, 88896910, 346062204, -163734816, 336635665,
+ 906060268, -128891583, 740952564, 916767203, 296514859, 198670559,
+ 358136672, -152253676, 12038867, -1469916749, -1020980597,
+ -897143313, 354240970, -97959800, 814172811, 1983363241, 264990663,
+ 105154676, 1060463014, 430172143, 375111946, -824526943,
+ -708877751, -1377442616, -236559551, 684724584, 1602131358,
+ -42140186, -763499840, -605167, 98575879, -376577598, 1689746083,
+ -777973879, -1396984691, -187780326, 281040966, 1858859521,
+ 158395760, 1022807978, -218458812, 811779708, 1495113833,
+ 1192561226, 629539535, -1365196683, -1120253162, 1091681956,
+ 134286445, 1172218369, -34093658, -137087343, -27869226,
+ -180889478, 55705436, 52362743, -1745516232, -926564477,
+ -513701675, -1666272054, 1457952810, 843953275, -478275722,
+ -1240291080, 101859661, -1606687523, 916365333, 314713310,
+ -22002688, 1019022641, -1171741314, -129050627, -211955813,
+ -1020176299, 1357865293, -609819628, 724533854, -1141449545,
+ 22285231, -97731145, -302329687, 191910894, -1300709885,
+ -644951895, 640448036, -1289009824, 1445456129, 846416471,
+ 1821291740, -1639640821, -712724532, -447475807, 132156847,
+ 258067455, 324301319, 278586969, -1544082357, 636007277, 977122066,
+ 127462480, 365126129, 1086276825, -432124148, 896598926,
+ -388550179, 273357331, -845018695, -1089465389, 384439820,
+ -558419772, 1476422025, 730712769, 190665059, -764968927,
+ -789708218, 637873581, 348429858, 1386000168, -638123594,
+ -842010345, -607926448, 19535163, -742771490, -18323344, 246155488,
+ 350409468, 1290907730, -492566468, 300358636, 501876267, 252441807,
+ 1233551975, -1431067042, 517177374, -1540299707, -948380761,
+ 1253997663, 693795998, 148707823, 152894502, 98729538, -30042824,
+ -563057441, 723726409, 367338961, 1395435261, 217868876,
+ 1220652431, 953572083, -1134905155, -734486813, -587470130,
+ -864647866, 1030737023, 781798521, -321076732, -460548153,
+ 122681678, -873728847, -1286304399, -75472885, 113390881,
+ -1556849198, -1070802176, 924389470, 957478910, 5974049, 709413506,
+ 476334647, 572869787, 776298405, -8822420, -99326499, -707855342,
+ -1187216303, 668038414, 262454769, -1120293198, -32011040,
+ 249812104, -101835410, 1082281087, -570183855, -954535179,
+ 1384361473, -983199686, 2017611313, 328926483, -878162849,
+ -1202254181, -225604951, 966898955, 247213529, -1257544612,
+ -197005970, -1039902730, -1947925142, 1752780907, -313410699,
+ -464474556, 416580338, -1063356643, -292212702, 57509168,
+ 1034124629, 1059212593, 468522867, 845369497, 1872717306,
+ -1216544764, -1419907623, 1376869956, -66585488, -1590974467,
+ -367070705, -1456529060, 791844031, 336217635, -1106832215,
+ 1476739427, -751018210, -1411671555, -1880387375, -1714242595,
+ 1169006474, -479442380, -892267555, -1471250266, -267888858,
+ 808634418, 1324777189, -585449929, 1127186951, 468768901,
+ -2002989138, -52352849, 186493053, 1258464606, 117157186,
+ 445919258, 908401949, -1112221136, 863904453, -942718649,
+ 796754809, -38943966, -781978872, -56814078, 1273857459,
+ -1781920832, 209979504, 811828269, -1150814437, 850061883,
+ -532968763, 252506408, -885025629, 391567580, -1295702482,
+ 574894420, 1462248349, 1622584325, -88443443, -1122006092,
+ -169758578, 456282338, -443233309, 436693483, -956563815,
+ -480221349, 435252860, -1114099391, 1060053979, -470893945,
+ -1273682879, -734596176, 639950927, -1278648701, 306274747,
+ -410562146, 1137869228, -1970746553, 1313830798, 1248071822,
+ -247297704, 1015218053, -1607348116, -261817613, -821413148,
+ -782942639, -628711083, 240953091, -629550668, -1584736319,
+ 856616893, -186759752, 197905373, 541638393, 603407919, -278480495,
+ 410077039, 544065371, -1509627427, 402918436, -450463799,
+ -131169308, 249920630, 1079548609, -927911828, 1444577689,
+ -353002528, -224292462, 1247795279, -790844631, -40427503,
+ 59829765, -332587567, 1319862109, -1261340753, 121711726,
+ 1342756342, -643495787, 100326201, -934436714, -69134888,
+ -898880561, -379524737, -577234570, -805827092, -1575493557,
+ -289920678, -476605057, 1235714994, -317239591, 418553949,
+ 410053338, -204985448, 1206503615, 202610372, -932244873,
+ 782207875, -288661931, -806814809, 1270953679, 2060991595,
+ -311412846, 327279979, 1148562672, 55239149, -610114433,
+ -1511688434, 87619740, -433503545, 326150519, -581293393,
+ -97417688, -289736140, -1543886029, -1251976119, 1585774446,
+ 1570011421, 432602745, 486343696, -834680922, 265004849,
+ -1132107706, 502627197, -815873818, 249635389, 1985714127,
+ -1095817653, -130743522, -645266828, -334621094, 199921747,
+ 1059256177, 378031303, 1519740920, 925540689, 1405957844,
+ 1387748290, -56138046, -770637828, -187984510, -1361735163,
+ 1294823206, -608941238, 451860688, -510549867, 1143516283,
+ -779090703, 1459305047, -600335915, -1684168049, 1516622316,
+ -631733335, -4360068, 499778796, 587600402, -1296000335, -37959743,
+ -1084203927, 1162902556, 246374600, -515103645, 341724568,
+ -702303954, 452229900, 485108287, 1170048553, -1510148355,
+ 611133912, 1997927484, -142022671, -724776653, -336090522,
+ 708283514, -1409637378, -2052637687, 376055110, 226628105,
+ -1714452033, -1776158002, 369167930, 1800807012, 710680889,
+ -69951947, -1223849766, -1862239787, 218536127, -656411794,
+ -1202269188, 609634805, -224425858, 519797951, 284223080,
+ 869408930, 270750206, -544967439, 2097168510, 31650971, -600985417,
+ -165303097, -257809088, -1043223971, 1827891621, -156827355,
+ 499719603
+};
+
+#define IVEC_LEN (nitems(initvector))
+
+#endif
diff --git a/lib/libc/tests/stdlib/tsearch_test.c b/lib/libc/tests/stdlib/tsearch_test.c
new file mode 100644
index 000000000000..88c62f580336
--- /dev/null
+++ b/lib/libc/tests/stdlib/tsearch_test.c
@@ -0,0 +1,131 @@
+/*-
+ * Copyright (c) 2015 Nuxi, https://nuxi.nl/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <atf-c.h>
+#define _SEARCH_PRIVATE
+#include <search.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+/* Validates the integrity of an AVL tree. */
+static inline unsigned int
+tnode_assert(const posix_tnode *n)
+{
+ unsigned int height_left, height_right;
+ int balance;
+
+ if (n == NULL)
+ return 0;
+ height_left = tnode_assert(n->llink);
+ height_right = tnode_assert(n->rlink);
+ balance = (int)height_left - (int)height_right;
+ ATF_CHECK(balance >= -1);
+ ATF_CHECK(balance <= 1);
+ ATF_CHECK_EQ(balance, n->balance);
+ return (height_left > height_right ? height_left : height_right) + 1;
+}
+
+static int
+compar(const void *a, const void *b)
+{
+
+ return *(int *)a - *(int *)b;
+}
+
+ATF_TC_WITHOUT_HEAD(tsearch_test);
+ATF_TC_BODY(tsearch_test, tc)
+{
+ /*
+ * Run the test below in a deterministic fashion to prevent this
+ * test from potentially flapping. We assume that this provides
+ * enough coverage.
+ */
+#if 0
+ unsigned short random_state[3];
+ arc4random_buf(random_state, sizeof(random_state));
+#else
+ unsigned short random_state[3] = { 26554, 13330, 3246 };
+#endif
+
+#define NKEYS 1000
+ /* Create 1000 possible keys. */
+ int keys[NKEYS];
+ for (int i = 0; i < NKEYS; ++i)
+ keys[i] = i;
+
+ /* Apply random operations on a binary tree and check the results. */
+ posix_tnode *root = NULL;
+ bool present[NKEYS] = {};
+ for (int i = 0; i < NKEYS * 10; ++i) {
+ int key = nrand48(random_state) % NKEYS;
+ switch (nrand48(random_state) % 3) {
+ case 0: /* tdelete(). */
+ if (present[key]) {
+ ATF_CHECK(tdelete(&key, &root, compar) != NULL);
+ present[key] = false;
+ } else {
+ ATF_CHECK_EQ(NULL,
+ tdelete(&key, &root, compar));
+ }
+ break;
+ case 1: /* tfind(). */
+ if (present[key]) {
+ ATF_CHECK_EQ(&keys[key],
+ *(int **)tfind(&key, &root, compar));
+ } else {
+ ATF_CHECK_EQ(NULL, tfind(&key, &root, compar));
+ }
+ break;
+ case 2: /* tsearch(). */
+ if (present[key]) {
+ ATF_CHECK_EQ(&keys[key],
+ *(int **)tsearch(&key, &root, compar));
+ } else {
+ ATF_CHECK_EQ(&keys[key], *(int **)tsearch(
+ &keys[key], &root, compar));
+ present[key] = true;
+ }
+ break;
+ }
+ tnode_assert(root);
+ }
+
+ /* Remove all entries from the tree. */
+ for (int key = 0; key < NKEYS; ++key)
+ if (present[key])
+ ATF_CHECK(tdelete(&key, &root, compar) != NULL);
+ ATF_CHECK_EQ(NULL, root);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, tsearch_test);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/string/Makefile b/lib/libc/tests/string/Makefile
new file mode 100644
index 000000000000..4867040e652f
--- /dev/null
+++ b/lib/libc/tests/string/Makefile
@@ -0,0 +1,36 @@
+# $FreeBSD$
+
+ATF_TESTS_C+= memcmp_test
+ATF_TESTS_C+= stpncpy_test
+ATF_TESTS_C+= strerror2_test
+ATF_TESTS_C+= wcscasecmp_test
+ATF_TESTS_C+= wcsnlen_test
+ATF_TESTS_C+= strxfrm_test
+ATF_TESTS_C+= wcscoll_test
+
+# TODO: popcount, stresep
+
+NETBSD_ATF_TESTS_C+= memchr_test
+NETBSD_ATF_TESTS_C+= memcpy_test
+NETBSD_ATF_TESTS_C+= memmem_test
+NETBSD_ATF_TESTS_C+= memset_test
+NETBSD_ATF_TESTS_C+= strcat_test
+NETBSD_ATF_TESTS_C+= strchr_test
+NETBSD_ATF_TESTS_C+= strcmp_test
+NETBSD_ATF_TESTS_C+= strcpy_test
+NETBSD_ATF_TESTS_C+= strcspn_test
+NETBSD_ATF_TESTS_C+= strerror_test
+NETBSD_ATF_TESTS_C+= strlen_test
+NETBSD_ATF_TESTS_C+= strpbrk_test
+NETBSD_ATF_TESTS_C+= strrchr_test
+NETBSD_ATF_TESTS_C+= strspn_test
+NETBSD_ATF_TESTS_C+= swab_test
+
+SRCS.strerror2_test= strerror_test.c
+
+.include "../Makefile.netbsd-tests"
+
+LIBADD.memchr_test+= md
+LIBADD.memcpy_test+= md
+
+.include <bsd.test.mk>
diff --git a/lib/libc/tests/string/Makefile.depend b/lib/libc/tests/string/Makefile.depend
new file mode 100644
index 000000000000..fbc70c89a626
--- /dev/null
+++ b/lib/libc/tests/string/Makefile.depend
@@ -0,0 +1,21 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ gnu/lib/csu \
+ gnu/lib/libgcc \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/atf/libatf-c \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libmd \
+ lib/libnetbsd \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/lib/libc/tests/string/memcmp_test.c b/lib/libc/tests/string/memcmp_test.c
new file mode 100644
index 000000000000..d7fbd8c342bd
--- /dev/null
+++ b/lib/libc/tests/string/memcmp_test.c
@@ -0,0 +1,124 @@
+/*-
+ * Copyright (c) 2016 Jilles Tjoelker <jilles@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 <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <atf-c.h>
+
+ATF_TC_WITHOUT_HEAD(zero);
+ATF_TC_BODY(zero, tc)
+{
+
+ assert(memcmp("a", "b", 0) == 0);
+ assert(memcmp("", "", 0) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(eq);
+ATF_TC_BODY(eq, tc)
+{
+ unsigned char data1[256], data2[256];
+ int i;
+
+ for (i = 0; i < 256; i++)
+ data1[i] = data2[i] = i ^ 0x55;
+ for (i = 1; i < 256; i++)
+ assert(memcmp(data1, data2, i) == 0);
+ for (i = 1; i < 256; i++)
+ assert(memcmp(data1 + i, data2 + i, 256 - i) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(neq);
+ATF_TC_BODY(neq, tc)
+{
+ unsigned char data1[256], data2[256];
+ int i;
+
+ for (i = 0; i < 256; i++) {
+ data1[i] = i;
+ data2[i] = i ^ 0x55;
+ }
+ for (i = 1; i < 256; i++)
+ assert(memcmp(data1, data2, i) != 0);
+ for (i = 1; i < 256; i++)
+ assert(memcmp(data1 + i, data2 + i, 256 - i) != 0);
+}
+
+ATF_TC_WITHOUT_HEAD(diff);
+ATF_TC_BODY(diff, tc)
+{
+ unsigned char data1[256], data2[256];
+ int i;
+
+ memset(data1, 'a', sizeof(data1));
+ memset(data2, 'a', sizeof(data2));
+ data1[128] = 255;
+ data2[128] = 0;
+ for (i = 1; i < 66; i++) {
+ assert(memcmp(data1 + 128, data2 + 128, i) == 255);
+ assert(memcmp(data2 + 128, data1 + 128, i) == -255);
+ assert(memcmp(data1 + 129 - i, data2 + 129 - i, i) == 255);
+ assert(memcmp(data2 + 129 - i, data1 + 129 - i, i) == -255);
+ assert(memcmp(data1 + 129 - i, data2 + 129 - i, i * 2) == 255);
+ assert(memcmp(data2 + 129 - i, data1 + 129 - i, i * 2) == -255);
+ }
+ data1[128] = 'c';
+ data2[128] = 'e';
+ for (i = 1; i < 66; i++) {
+ assert(memcmp(data1 + 128, data2 + 128, i) == -2);
+ assert(memcmp(data2 + 128, data1 + 128, i) == 2);
+ assert(memcmp(data1 + 129 - i, data2 + 129 - i, i) == -2);
+ assert(memcmp(data2 + 129 - i, data1 + 129 - i, i) == 2);
+ assert(memcmp(data1 + 129 - i, data2 + 129 - i, i * 2) == -2);
+ assert(memcmp(data2 + 129 - i, data1 + 129 - i, i * 2) == 2);
+ }
+ memset(data1 + 129, 'A', sizeof(data1) - 129);
+ memset(data2 + 129, 'Z', sizeof(data2) - 129);
+ for (i = 1; i < 66; i++) {
+ assert(memcmp(data1 + 128, data2 + 128, i) == -2);
+ assert(memcmp(data2 + 128, data1 + 128, i) == 2);
+ assert(memcmp(data1 + 129 - i, data2 + 129 - i, i) == -2);
+ assert(memcmp(data2 + 129 - i, data1 + 129 - i, i) == 2);
+ assert(memcmp(data1 + 129 - i, data2 + 129 - i, i * 2) == -2);
+ assert(memcmp(data2 + 129 - i, data1 + 129 - i, i * 2) == 2);
+ }
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, zero);
+ ATF_TP_ADD_TC(tp, eq);
+ ATF_TP_ADD_TC(tp, neq);
+ ATF_TP_ADD_TC(tp, diff);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/string/stpncpy_test.c b/lib/libc/tests/string/stpncpy_test.c
new file mode 100644
index 000000000000..0a7b1d28e9c1
--- /dev/null
+++ b/lib/libc/tests/string/stpncpy_test.c
@@ -0,0 +1,110 @@
+/*-
+ * Copyright (c) 2009 David Schultz <das@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/mman.h>
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <atf-c.h>
+
+static char *
+makebuf(size_t len, int guard_at_end)
+{
+ char *buf;
+ size_t alloc_size = roundup2(len, PAGE_SIZE) + PAGE_SIZE;
+
+ buf = mmap(NULL, alloc_size, PROT_READ | PROT_WRITE, MAP_ANON, -1, 0);
+ assert(buf);
+ if (guard_at_end) {
+ assert(munmap(buf + alloc_size - PAGE_SIZE, PAGE_SIZE) == 0);
+ return (buf + alloc_size - PAGE_SIZE - len);
+ } else {
+ assert(munmap(buf, PAGE_SIZE) == 0);
+ return (buf + PAGE_SIZE);
+ }
+}
+
+static void
+test_stpncpy(const char *s)
+{
+ char *src, *dst;
+ size_t size, len, bufsize, x;
+ int i, j;
+
+ size = strlen(s) + 1;
+ for (i = 0; i <= 1; i++) {
+ for (j = 0; j <= 1; j++) {
+ for (bufsize = 0; bufsize <= size + 10; bufsize++) {
+ src = makebuf(size, i);
+ memcpy(src, s, size);
+ dst = makebuf(bufsize, j);
+ memset(dst, 'X', bufsize);
+ len = (bufsize < size) ? bufsize : size - 1;
+ assert(stpncpy(dst, src, bufsize) == dst+len);
+ assert(memcmp(src, dst, len) == 0);
+ for (x = len; x < bufsize; x++)
+ assert(dst[x] == '\0');
+ }
+ }
+ }
+}
+
+ATF_TC_WITHOUT_HEAD(nul);
+ATF_TC_BODY(nul, tc)
+{
+
+ test_stpncpy("");
+}
+
+ATF_TC_WITHOUT_HEAD(foo);
+ATF_TC_BODY(foo, tc)
+{
+
+ test_stpncpy("foo");
+}
+
+ATF_TC_WITHOUT_HEAD(glorp);
+ATF_TC_BODY(glorp, tc)
+{
+
+ test_stpncpy("glorp");
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, nul);
+ ATF_TP_ADD_TC(tp, foo);
+ ATF_TP_ADD_TC(tp, glorp);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/string/strerror_test.c b/lib/libc/tests/string/strerror_test.c
new file mode 100644
index 000000000000..51bbf1765804
--- /dev/null
+++ b/lib/libc/tests/string/strerror_test.c
@@ -0,0 +1,206 @@
+/*-
+ * Copyright (c) 2001 Wes Peters <wes@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 <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <atf-c.h>
+
+static char buf[64];
+static char *sret;
+static int iret;
+
+ATF_TC_WITHOUT_HEAD(strerror_unknown_error);
+ATF_TC_BODY(strerror_unknown_error, tc)
+{
+
+ errno = 0;
+ sret = strerror(INT_MAX);
+ snprintf(buf, sizeof(buf), "Unknown error: %d", INT_MAX);
+ ATF_CHECK(strcmp(sret, buf) == 0);
+ ATF_CHECK(errno == EINVAL);
+}
+
+ATF_TC_WITHOUT_HEAD(strerror_no_error);
+ATF_TC_BODY(strerror_no_error, tc)
+{
+
+ errno = 0;
+ sret = strerror(0);
+ ATF_CHECK(strcmp(sret, "No error: 0") == 0);
+ ATF_CHECK(errno == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(strerror_EPERM_test);
+ATF_TC_BODY(strerror_EPERM_test, tc)
+{
+
+ errno = 0;
+ sret = strerror(EPERM);
+ ATF_CHECK(strcmp(sret, "Operation not permitted") == 0);
+ ATF_CHECK(errno == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(strerror_EPFNOSUPPORT_test);
+ATF_TC_BODY(strerror_EPFNOSUPPORT_test, tc)
+{
+
+ errno = 0;
+ sret = strerror(EPFNOSUPPORT);
+ ATF_CHECK(strcmp(sret, "Protocol family not supported") == 0);
+ ATF_CHECK(errno == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(strerror_ELAST_test);
+ATF_TC_BODY(strerror_ELAST_test, tc)
+{
+
+ errno = 0;
+ sret = strerror(ELAST);
+ ATF_CHECK(errno == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(strerror_r__unknown_error);
+ATF_TC_BODY(strerror_r__unknown_error, tc)
+{
+
+ memset(buf, '*', sizeof(buf));
+ iret = strerror_r(-1, buf, sizeof(buf));
+ ATF_CHECK(strcmp(buf, "Unknown error: -1") == 0);
+ ATF_CHECK(iret == EINVAL);
+}
+
+ATF_TC_WITHOUT_HEAD(strerror_r__EPERM_one_byte_short);
+ATF_TC_BODY(strerror_r__EPERM_one_byte_short, tc)
+{
+
+ memset(buf, '*', sizeof(buf));
+ /* One byte too short. */
+ iret = strerror_r(EPERM, buf, strlen("Operation not permitted"));
+ ATF_CHECK(strcmp(buf, "Operation not permitte") == 0);
+ ATF_CHECK(iret == ERANGE);
+}
+
+ATF_TC_WITHOUT_HEAD(strerror_r__EPERM_unknown_error_one_byte_short);
+ATF_TC_BODY(strerror_r__EPERM_unknown_error_one_byte_short, tc)
+{
+
+ memset(buf, '*', sizeof(buf));
+ /* One byte too short. */
+ iret = strerror_r(-1, buf, strlen("Unknown error: -1"));
+ ATF_CHECK(strcmp(buf, "Unknown error: -") == 0);
+ ATF_CHECK(iret == EINVAL);
+}
+
+ATF_TC_WITHOUT_HEAD(strerror_r__EPERM_unknown_error_two_bytes_short);
+ATF_TC_BODY(strerror_r__EPERM_unknown_error_two_bytes_short, tc)
+{
+
+ memset(buf, '*', sizeof(buf));
+ /* Two bytes too short. */
+ iret = strerror_r(-2, buf, strlen("Unknown error: -2") - 1);
+ ATF_CHECK(strcmp(buf, "Unknown error: ") == 0);
+ ATF_CHECK(iret == EINVAL);
+}
+
+ATF_TC_WITHOUT_HEAD(strerror_r__EPERM_unknown_error_three_bytes_short);
+ATF_TC_BODY(strerror_r__EPERM_unknown_error_three_bytes_short, tc)
+{
+
+ memset(buf, '*', sizeof(buf));
+ /* Three bytes too short. */
+ iret = strerror_r(-2, buf, strlen("Unknown error: -2") - 2);
+ ATF_CHECK(strcmp(buf, "Unknown error:") == 0);
+ ATF_CHECK(iret == EINVAL);
+}
+
+ATF_TC_WITHOUT_HEAD(strerror_r__EPERM_unknown_error_12345_one_byte_short);
+ATF_TC_BODY(strerror_r__EPERM_unknown_error_12345_one_byte_short, tc)
+{
+
+ memset(buf, '*', sizeof(buf));
+ /* One byte too short. */
+ iret = strerror_r(12345, buf, strlen("Unknown error: 12345"));
+ ATF_CHECK(strcmp(buf, "Unknown error: 1234") == 0);
+ ATF_CHECK(iret == EINVAL);
+}
+
+ATF_TC_WITHOUT_HEAD(strerror_r__no_error);
+ATF_TC_BODY(strerror_r__no_error, tc)
+{
+
+ memset(buf, '*', sizeof(buf));
+ iret = strerror_r(0, buf, sizeof(buf));
+ ATF_CHECK(strcmp(buf, "No error: 0") == 0);
+ ATF_CHECK(iret == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(strerror_r__EDEADLK);
+ATF_TC_BODY(strerror_r__EDEADLK, tc)
+{
+
+ memset(buf, '*', sizeof(buf));
+ iret = strerror_r(EDEADLK, buf, sizeof(buf));
+ ATF_CHECK(strcmp(buf, "Resource deadlock avoided") == 0);
+ ATF_CHECK(iret == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(strerror_r__EPROCLIM);
+ATF_TC_BODY(strerror_r__EPROCLIM, tc)
+{
+
+ memset(buf, '*', sizeof(buf));
+ iret = strerror_r(EPROCLIM, buf, sizeof(buf));
+ ATF_CHECK(strcmp(buf, "Too many processes") == 0);
+ ATF_CHECK(iret == 0);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, strerror_unknown_error);
+ ATF_TP_ADD_TC(tp, strerror_no_error);
+ ATF_TP_ADD_TC(tp, strerror_EPERM_test);
+ ATF_TP_ADD_TC(tp, strerror_EPFNOSUPPORT_test);
+ ATF_TP_ADD_TC(tp, strerror_ELAST_test);
+ ATF_TP_ADD_TC(tp, strerror_r__unknown_error);
+ ATF_TP_ADD_TC(tp, strerror_r__EPERM_one_byte_short);
+ ATF_TP_ADD_TC(tp, strerror_r__EPERM_unknown_error_one_byte_short);
+ ATF_TP_ADD_TC(tp, strerror_r__EPERM_unknown_error_two_bytes_short);
+ ATF_TP_ADD_TC(tp, strerror_r__EPERM_unknown_error_three_bytes_short);
+ ATF_TP_ADD_TC(tp, strerror_r__EPERM_unknown_error_12345_one_byte_short);
+ ATF_TP_ADD_TC(tp, strerror_r__no_error);
+ ATF_TP_ADD_TC(tp, strerror_r__EDEADLK);
+ ATF_TP_ADD_TC(tp, strerror_r__EPROCLIM);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/string/strxfrm_test.c b/lib/libc/tests/string/strxfrm_test.c
new file mode 100644
index 000000000000..98f3b3bddee7
--- /dev/null
+++ b/lib/libc/tests/string/strxfrm_test.c
@@ -0,0 +1,51 @@
+/*-
+ * Copyright (c) 2016 Baptiste Daroussin <bapt@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <string.h>
+#include <locale.h>
+#include <stdio.h>
+
+#include <atf-c.h>
+
+ATF_TC_WITHOUT_HEAD(iso_8859_5);
+ATF_TC_BODY(iso_8859_5, tc)
+{
+ char s1[8];
+ const char s2[] = { 0xa1, 0 };
+
+ setlocale(LC_ALL, "ru_RU.ISO8859-5");
+ strxfrm(s1, s2, 0x8);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+ ATF_TP_ADD_TC(tp, iso_8859_5);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/string/wcscasecmp_test.c b/lib/libc/tests/string/wcscasecmp_test.c
new file mode 100644
index 000000000000..4385f3a8f0d2
--- /dev/null
+++ b/lib/libc/tests/string/wcscasecmp_test.c
@@ -0,0 +1,128 @@
+/*-
+ * Copyright (c) 2009 David Schultz <das@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <assert.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include <wctype.h>
+
+#include <atf-c.h>
+
+ATF_TC_WITHOUT_HEAD(nul);
+ATF_TC_BODY(nul, tc)
+{
+
+ ATF_REQUIRE(setlocale(LC_CTYPE, "C") != NULL);
+
+ ATF_CHECK(wcscasecmp(L"", L"") == 0);
+ ATF_CHECK(wcsncasecmp(L"", L"", 50) == 0);
+ ATF_CHECK(wcsncasecmp(L"", L"", 0) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(wcscasecmp_equal);
+ATF_TC_BODY(wcscasecmp_equal, tc)
+{
+
+ ATF_REQUIRE(setlocale(LC_CTYPE, "C") != NULL);
+
+ ATF_CHECK(wcscasecmp(L"abc", L"abc") == 0);
+ ATF_CHECK(wcscasecmp(L"ABC", L"ABC") == 0);
+ ATF_CHECK(wcscasecmp(L"abc", L"ABC") == 0);
+ ATF_CHECK(wcscasecmp(L"ABC", L"abc") == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(wcscasecmp_same_len_buffers);
+ATF_TC_BODY(wcscasecmp_same_len_buffers, tc)
+{
+
+ ATF_REQUIRE(setlocale(LC_CTYPE, "C") != NULL);
+
+ ATF_CHECK(wcscasecmp(L"abc", L"xyz") < 0);
+ ATF_CHECK(wcscasecmp(L"ABC", L"xyz") < 0);
+ ATF_CHECK(wcscasecmp(L"abc", L"XYZ") < 0);
+ ATF_CHECK(wcscasecmp(L"ABC", L"XYZ") < 0);
+ ATF_CHECK(wcscasecmp(L"xyz", L"abc") > 0);
+ ATF_CHECK(wcscasecmp(L"XYZ", L"abc") > 0);
+ ATF_CHECK(wcscasecmp(L"xyz", L"ABC") > 0);
+ ATF_CHECK(wcscasecmp(L"XYZ", L"ABC") > 0);
+}
+
+ATF_TC_WITHOUT_HEAD(wcscasecmp_mismatched_len_buffers);
+ATF_TC_BODY(wcscasecmp_mismatched_len_buffers, tc)
+{
+
+ ATF_REQUIRE(setlocale(LC_CTYPE, "C") != NULL);
+
+ ATF_CHECK(wcscasecmp(L"abc", L"ABCD") < 0);
+ ATF_CHECK(wcscasecmp(L"ABC", L"abcd") < 0);
+ ATF_CHECK(wcscasecmp(L"abcd", L"ABC") > 0);
+ ATF_CHECK(wcscasecmp(L"ABCD", L"abc") > 0);
+}
+
+ATF_TC_WITHOUT_HEAD(wcsncasecmp);
+ATF_TC_BODY(wcsncasecmp, tc)
+{
+
+ ATF_REQUIRE(setlocale(LC_CTYPE, "C") != NULL);
+
+ ATF_CHECK(wcsncasecmp(L"abc", L"ABCD", 4) < 0);
+ ATF_CHECK(wcsncasecmp(L"ABC", L"abcd", 4) < 0);
+ ATF_CHECK(wcsncasecmp(L"abcd", L"ABC", 4) > 0);
+ ATF_CHECK(wcsncasecmp(L"ABCD", L"abc", 4) > 0);
+ ATF_CHECK(wcsncasecmp(L"abc", L"ABCD", 3) == 0);
+ ATF_CHECK(wcsncasecmp(L"ABC", L"abcd", 3) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(wcscasecmp_greek);
+ATF_TC_BODY(wcscasecmp_greek, tc)
+{
+
+ ATF_REQUIRE(setlocale(LC_CTYPE, "C") != NULL);
+
+ ATF_CHECK(wcscasecmp(L"λ", L"Λ") != 0);
+ ATF_REQUIRE(setlocale(LC_CTYPE, "el_GR.UTF-8") != NULL);
+ ATF_CHECK(wcscasecmp(L"λ", L"Λ") == 0);
+ ATF_CHECK(wcscasecmp(L"λ", L"Ω") < 0);
+ ATF_CHECK(wcscasecmp(L"Ω", L"λ") > 0);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, nul);
+ ATF_TP_ADD_TC(tp, wcscasecmp_equal);
+ ATF_TP_ADD_TC(tp, wcscasecmp_same_len_buffers);
+ ATF_TP_ADD_TC(tp, wcscasecmp_mismatched_len_buffers);
+ ATF_TP_ADD_TC(tp, wcsncasecmp);
+ ATF_TP_ADD_TC(tp, wcscasecmp_greek);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/string/wcscoll_test.c b/lib/libc/tests/string/wcscoll_test.c
new file mode 100644
index 000000000000..2f2472b5249d
--- /dev/null
+++ b/lib/libc/tests/string/wcscoll_test.c
@@ -0,0 +1,63 @@
+/*-
+ * Copyright (c) 2016 Baptiste Daroussin <bapt@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <wchar.h>
+#include <locale.h>
+#include <stdlib.h>
+
+#include <atf-c.h>
+
+static int
+cmp(const void *a, const void *b)
+{
+ const wchar_t wa[2] = { *(const wchar_t *)a, 0 };
+ const wchar_t wb[2] = { *(const wchar_t *)b, 0 };
+
+ return (wcscoll(wa, wb));
+}
+
+ATF_TC_WITHOUT_HEAD(russian_collation);
+ATF_TC_BODY(russian_collation, tc)
+{
+ wchar_t c[] = L"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzÐÐБВГДЕЖЗИЙКЛМÐОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрÑтуфхцчшщъыьÑÑŽÑÑ‘";
+ wchar_t res[] = L"aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZаÐбБвВгГдДеЕёÐжЖзЗиИйЙкКлЛмМнÐоОпПрРÑСтТуУфФхХцЦчЧшШщЩъЪыЫьЬÑЭюЮÑЯ";
+
+ ATF_CHECK_MSG(setlocale(LC_ALL, "ru_RU.UTF-8") != NULL,
+ "Fail to set locale to \"ru_RU.UTF-8\"");
+ qsort(c, wcslen(c), sizeof(wchar_t), cmp);
+ ATF_CHECK_MSG(wcscmp(c, res) == 0,
+ "Bad collation, expected: '%ls' got '%ls'", res, c);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+ ATF_TP_ADD_TC(tp, russian_collation);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/string/wcsnlen_test.c b/lib/libc/tests/string/wcsnlen_test.c
new file mode 100644
index 000000000000..ec11938b19a9
--- /dev/null
+++ b/lib/libc/tests/string/wcsnlen_test.c
@@ -0,0 +1,104 @@
+/*-
+ * Copyright (c) 2009 David Schultz <das@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/mman.h>
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+
+#include <atf-c.h>
+
+static void *
+makebuf(size_t len, int guard_at_end)
+{
+ char *buf;
+ size_t alloc_size = roundup2(len, PAGE_SIZE) + PAGE_SIZE;
+
+ buf = mmap(NULL, alloc_size, PROT_READ | PROT_WRITE, MAP_ANON, -1, 0);
+ ATF_CHECK(buf);
+ if (guard_at_end) {
+ ATF_CHECK(munmap(buf + alloc_size - PAGE_SIZE, PAGE_SIZE) == 0);
+ return (buf + alloc_size - PAGE_SIZE - len);
+ } else {
+ ATF_CHECK(munmap(buf, PAGE_SIZE) == 0);
+ return (buf + PAGE_SIZE);
+ }
+}
+
+static void
+test_wcsnlen(const wchar_t *s)
+{
+ wchar_t *s1;
+ size_t size, len, bufsize;
+ int i;
+
+ size = wcslen(s) + 1;
+ for (i = 0; i <= 1; i++) {
+ for (bufsize = 0; bufsize <= size + 10; bufsize++) {
+ s1 = makebuf(bufsize * sizeof(wchar_t), i);
+ wmemcpy(s1, s, bufsize);
+ len = (size > bufsize) ? bufsize : size - 1;
+ ATF_CHECK(wcsnlen(s1, bufsize) == len);
+ }
+ }
+}
+
+ATF_TC_WITHOUT_HEAD(nul);
+ATF_TC_BODY(nul, tc)
+{
+
+ test_wcsnlen(L"");
+}
+
+ATF_TC_WITHOUT_HEAD(foo);
+ATF_TC_BODY(foo, tc)
+{
+
+ test_wcsnlen(L"foo");
+}
+
+ATF_TC_WITHOUT_HEAD(glorp);
+ATF_TC_BODY(glorp, tc)
+{
+
+ test_wcsnlen(L"glorp");
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, nul);
+ ATF_TP_ADD_TC(tp, foo);
+ ATF_TP_ADD_TC(tp, glorp);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/sys/Makefile b/lib/libc/tests/sys/Makefile
new file mode 100644
index 000000000000..794e1f2cce1a
--- /dev/null
+++ b/lib/libc/tests/sys/Makefile
@@ -0,0 +1,97 @@
+# $FreeBSD$
+
+PACKAGE= tests
+
+.include <bsd.own.mk>
+
+ATF_TESTS_C+= queue_test
+
+# TODO: clone, lwp_create, lwp_ctl, posix_fadvise, recvmmsg,
+# swapcontext
+NETBSD_ATF_TESTS_C+= access_test
+NETBSD_ATF_TESTS_C+= bind_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+= getsockname_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+= posix_fallocate_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+= wait_test
+NETBSD_ATF_TESTS_C+= wait_noproc_test
+NETBSD_ATF_TESTS_C+= wait_noproc_wnohang_test
+NETBSD_ATF_TESTS_C+= write_test
+
+CSTD?= c99
+
+LIBADD.getpid_test+= pthread
+LIBADD.timer_create_test+= rt
+
+.include "../Makefile.netbsd-tests"
+
+SRCS.mlock_test+= mlock_helper.c
+SRCS.setrlimit_test+= mlock_helper.c
+
+.if ${COMPILER_TYPE} == "gcc"
+WARNS?= 3
+.else
+WARNS?= 4
+.endif
+
+FILESGROUPS+= 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
+truncate_test_FILESPACKAGE= ${PACKAGE}
+
+CLEANFILES= truncate_test.root_owned
+truncate_test.root_owned:
+ dd if=/dev/null bs=1 count=1 of=${.TARGET} status=none
+
+.include <bsd.test.mk>
diff --git a/lib/libc/tests/sys/Makefile.depend b/lib/libc/tests/sys/Makefile.depend
new file mode 100644
index 000000000000..ae11679ef381
--- /dev/null
+++ b/lib/libc/tests/sys/Makefile.depend
@@ -0,0 +1,24 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ gnu/lib/csu \
+ gnu/lib/libgcc \
+ include \
+ include/arpa \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/atf/libatf-c \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libkvm \
+ lib/libnetbsd \
+ lib/librt \
+ lib/libthr \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/lib/libc/tests/sys/mlock_helper.c b/lib/libc/tests/sys/mlock_helper.c
new file mode 100644
index 000000000000..7fa40d11861d
--- /dev/null
+++ b/lib/libc/tests/sys/mlock_helper.c
@@ -0,0 +1,114 @@
+/*-
+ * Copyright (C) 2016 Bryan Drewery <bdrewery@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Helper for mlock(3) to avoid EAGAIN errors
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/sysctl.h>
+
+#include <atf-c.h>
+#include <errno.h>
+#include <stdio.h>
+#include <limits.h>
+
+#define VM_MAX_WIRED "vm.max_wired"
+
+static void
+vm_max_wired_sysctl(int *old_value, int *new_value)
+{
+ size_t old_len;
+ size_t new_len = (new_value == NULL ? 0 : sizeof(int));
+
+ if (old_value == NULL)
+ printf("Setting the new value to %d\n", *new_value);
+ else {
+ ATF_REQUIRE_MSG(sysctlbyname(VM_MAX_WIRED, NULL, &old_len,
+ new_value, new_len) == 0,
+ "sysctlbyname(%s) failed: %s", VM_MAX_WIRED, strerror(errno));
+ }
+
+ ATF_REQUIRE_MSG(sysctlbyname(VM_MAX_WIRED, old_value, &old_len,
+ new_value, new_len) == 0,
+ "sysctlbyname(%s) failed: %s", VM_MAX_WIRED, strerror(errno));
+
+ if (old_value != NULL)
+ printf("Saved the old value (%d)\n", *old_value);
+}
+
+void
+set_vm_max_wired(int new_value)
+{
+ FILE *fp;
+ int old_value;
+
+ fp = fopen(VM_MAX_WIRED, "w");
+ if (fp == NULL) {
+ atf_tc_skip("could not open %s for writing: %s",
+ VM_MAX_WIRED, strerror(errno));
+ return;
+ }
+
+ vm_max_wired_sysctl(&old_value, NULL);
+
+ ATF_REQUIRE_MSG(fprintf(fp, "%d", old_value) > 0,
+ "saving %s failed", VM_MAX_WIRED);
+
+ fclose(fp);
+
+ vm_max_wired_sysctl(NULL, &new_value);
+}
+
+void
+restore_vm_max_wired(void)
+{
+ FILE *fp;
+ int saved_max_wired;
+
+ fp = fopen(VM_MAX_WIRED, "r");
+ if (fp == NULL) {
+ perror("fopen failed\n");
+ return;
+ }
+
+ if (fscanf(fp, "%d", &saved_max_wired) != 1) {
+ perror("fscanf failed\n");
+ fclose(fp);
+ return;
+ }
+
+ fclose(fp);
+ printf("old value in %s: %d\n", VM_MAX_WIRED, saved_max_wired);
+
+ if (saved_max_wired == 0) /* This will cripple the test host */
+ return;
+
+ vm_max_wired_sysctl(NULL, &saved_max_wired);
+}
diff --git a/lib/libc/tests/sys/queue_test.c b/lib/libc/tests/sys/queue_test.c
new file mode 100644
index 000000000000..2405e3a69f5c
--- /dev/null
+++ b/lib/libc/tests/sys/queue_test.c
@@ -0,0 +1,237 @@
+/*-
+ * Copyright (c) 2015 EMC Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/queue.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <atf-c.h>
+
+ATF_TC(slist_test);
+ATF_TC_HEAD(slist_test, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "SLIST macro feature tests");
+}
+
+ATF_TC_BODY(slist_test, tc)
+{
+ SLIST_HEAD(stailhead, entry) head = SLIST_HEAD_INITIALIZER(head);
+ struct entry {
+ SLIST_ENTRY(entry) entries;
+ int i;
+ } *n1, *n2, *n3, *np;
+ int i, j, length;
+
+ SLIST_INIT(&head);
+
+ printf("Ensuring SLIST_EMPTY works\n");
+
+ ATF_REQUIRE(SLIST_EMPTY(&head));
+
+ i = length = 0;
+
+ SLIST_FOREACH(np, &head, entries) {
+ length++;
+ }
+ ATF_REQUIRE_EQ(length, 0);
+
+ printf("Ensuring SLIST_INSERT_HEAD works\n");
+
+ n1 = malloc(sizeof(struct entry));
+ ATF_REQUIRE(n1 != NULL);
+ n1->i = i++;
+
+ SLIST_INSERT_HEAD(&head, n1, entries);
+
+ printf("Ensuring SLIST_FIRST returns element 1\n");
+ ATF_REQUIRE_EQ(SLIST_FIRST(&head), n1);
+
+ j = length = 0;
+ SLIST_FOREACH(np, &head, entries) {
+ ATF_REQUIRE_EQ_MSG(np->i, j,
+ "%d (entry counter) != %d (counter)", np->i, j);
+ j++;
+ length++;
+ }
+ ATF_REQUIRE_EQ(length, 1);
+
+ printf("Ensuring SLIST_INSERT_AFTER works\n");
+
+ n2 = malloc(sizeof(struct entry));
+ ATF_REQUIRE(n2 != NULL);
+ n2->i = i++;
+
+ SLIST_INSERT_AFTER(n1, n2, entries);
+
+ n3 = malloc(sizeof(struct entry));
+ ATF_REQUIRE(n3 != NULL);
+ n3->i = i++;
+
+ SLIST_INSERT_AFTER(n2, n3, entries);
+
+ j = length = 0;
+ SLIST_FOREACH(np, &head, entries) {
+ ATF_REQUIRE_EQ_MSG(np->i, j,
+ "%d (entry counter) != %d (counter)", np->i, j);
+ j++;
+ length++;
+ }
+ ATF_REQUIRE_EQ(length, 3);
+
+ printf("Ensuring SLIST_REMOVE_HEAD works\n");
+
+ printf("Ensuring SLIST_FIRST returns element 1\n");
+ ATF_REQUIRE_EQ(SLIST_FIRST(&head), n1);
+
+ SLIST_REMOVE_HEAD(&head, entries);
+
+ printf("Ensuring SLIST_FIRST now returns element 2\n");
+ ATF_REQUIRE_EQ(SLIST_FIRST(&head), n2);
+
+ j = 1; /* Starting point's 1 this time */
+ length = 0;
+ SLIST_FOREACH(np, &head, entries) {
+ ATF_REQUIRE_EQ_MSG(np->i, j,
+ "%d (entry counter) != %d (counter)", np->i, j);
+ j++;
+ length++;
+ }
+ ATF_REQUIRE_EQ(length, 2);
+
+ printf("Ensuring SLIST_REMOVE_AFTER works by removing the tail\n");
+
+ SLIST_REMOVE_AFTER(n2, entries);
+
+ j = 1; /* Starting point's 1 this time */
+ length = 0;
+ SLIST_FOREACH(np, &head, entries) {
+ ATF_REQUIRE_EQ_MSG(np->i, j,
+ "%d (entry counter) != %d (counter)", np->i, j);
+ j++;
+ length++;
+ }
+ ATF_REQUIRE_EQ(length, 1);
+
+ printf("Ensuring SLIST_FIRST returns element 2\n");
+ ATF_REQUIRE_EQ(SLIST_FIRST(&head), n2);
+
+}
+
+ATF_TC(stailq_test);
+ATF_TC_HEAD(stailq_test, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "STAILQ macro feature tests");
+}
+
+ATF_TC_BODY(stailq_test, tc)
+{
+ STAILQ_HEAD(stailhead, entry) head = STAILQ_HEAD_INITIALIZER(head);
+ struct entry {
+ STAILQ_ENTRY(entry) entries;
+ int i;
+ } *n1, *n2, *n3, *np;
+ int i, j, length;
+
+ printf("Ensuring empty STAILQs are treated properly\n");
+ STAILQ_INIT(&head);
+ ATF_REQUIRE(STAILQ_EMPTY(&head));
+
+ i = length = 0;
+
+ STAILQ_FOREACH(np, &head, entries) {
+ length++;
+ }
+ ATF_REQUIRE_EQ(length, 0);
+
+ printf("Ensuring STAILQ_INSERT_HEAD works\n");
+
+ n1 = malloc(sizeof(struct entry));
+ ATF_REQUIRE(n1 != NULL);
+ n1->i = i++;
+
+ STAILQ_INSERT_HEAD(&head, n1, entries);
+
+ j = length = 0;
+ STAILQ_FOREACH(np, &head, entries) {
+ ATF_REQUIRE_EQ_MSG(np->i, j,
+ "%d (entry counter) != %d (counter)", np->i, j);
+ j++;
+ length++;
+ }
+ ATF_REQUIRE_EQ(length, 1);
+
+ printf("Ensuring STAILQ_INSERT_TAIL works\n");
+
+ n2 = malloc(sizeof(struct entry));
+ ATF_REQUIRE(n2 != NULL);
+ n2->i = i++;
+
+ STAILQ_INSERT_TAIL(&head, n2, entries);
+
+ n3 = malloc(sizeof(struct entry));
+ ATF_REQUIRE(n3 != NULL);
+ n3->i = i++;
+
+ STAILQ_INSERT_TAIL(&head, n3, entries);
+
+ j = length = 0;
+ STAILQ_FOREACH(np, &head, entries) {
+ ATF_REQUIRE_EQ_MSG(np->i, j,
+ "%d (entry counter) != %d (counter)", np->i, j);
+ j++;
+ length++;
+ }
+ ATF_REQUIRE_EQ(length, 3);
+
+ printf("Ensuring STAILQ_REMOVE_HEAD works\n");
+
+ STAILQ_REMOVE_HEAD(&head, entries);
+
+ j = 1; /* Starting point's 1 this time */
+ length = 0;
+ STAILQ_FOREACH(np, &head, entries) {
+ ATF_REQUIRE_EQ_MSG(np->i, j,
+ "%d (entry counter) != %d (counter)", np->i, j);
+ j++;
+ length++;
+ }
+ ATF_REQUIRE_EQ(length, 2);
+
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, slist_test);
+ ATF_TP_ADD_TC(tp, stailq_test);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/termios/Makefile b/lib/libc/tests/termios/Makefile
new file mode 100644
index 000000000000..0495d684b505
--- /dev/null
+++ b/lib/libc/tests/termios/Makefile
@@ -0,0 +1,9 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+NETBSD_ATF_TESTS_C= tcsetpgrp_test
+
+.include "../Makefile.netbsd-tests"
+
+.include <bsd.test.mk>
diff --git a/lib/libc/tests/termios/Makefile.depend b/lib/libc/tests/termios/Makefile.depend
new file mode 100644
index 000000000000..e8ee295f115a
--- /dev/null
+++ b/lib/libc/tests/termios/Makefile.depend
@@ -0,0 +1,20 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ gnu/lib/csu \
+ gnu/lib/libgcc \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/atf/libatf-c \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libnetbsd \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/lib/libc/tests/time/Makefile b/lib/libc/tests/time/Makefile
new file mode 100644
index 000000000000..feb543dad243
--- /dev/null
+++ b/lib/libc/tests/time/Makefile
@@ -0,0 +1,10 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+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/time/Makefile.depend b/lib/libc/tests/time/Makefile.depend
new file mode 100644
index 000000000000..e8ee295f115a
--- /dev/null
+++ b/lib/libc/tests/time/Makefile.depend
@@ -0,0 +1,20 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ gnu/lib/csu \
+ gnu/lib/libgcc \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/atf/libatf-c \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libnetbsd \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/lib/libc/tests/tls/Makefile b/lib/libc/tests/tls/Makefile
new file mode 100644
index 000000000000..cbf441d6e1b1
--- /dev/null
+++ b/lib/libc/tests/tls/Makefile
@@ -0,0 +1,33 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+.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
+
+LIBADD.tls_static_test+= pthread
+LDFLAGS.tls_static_test+= -static
+SRCS.tls_static_test= t_tls_static.c t_tls_static_helper.c
+
+DPADD.tls_dynamic_test+= ${DSODIR}/libh_tls_dynamic.so
+LDADD.tls_dynamic_test+= -lh_tls_dynamic
+LDFLAGS.tls_dynamic_test+= -Wl,-rpath,${TESTSDIR} -L${DSODIR}
+LIBADD.tls_dynamic_test+= pthread
+
+LIBADD.tls_dlopen_test+= pthread
+LDFLAGS.tls_dlopen_test+= -Wl,-rpath,${TESTSDIR} -Wl,-export-dynamic
+
+.include <bsd.test.mk>
diff --git a/lib/libc/tests/tls/Makefile.depend b/lib/libc/tests/tls/Makefile.depend
new file mode 100644
index 000000000000..933417c3fdd8
--- /dev/null
+++ b/lib/libc/tests/tls/Makefile.depend
@@ -0,0 +1,22 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ gnu/lib/csu \
+ gnu/lib/libgcc \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/atf/libatf-c \
+ lib/libc \
+ lib/libc/tests/tls_dso \
+ lib/libcompiler_rt \
+ lib/libnetbsd \
+ lib/libthr \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/lib/libc/tests/tls/dso/Makefile b/lib/libc/tests/tls/dso/Makefile
new file mode 100644
index 000000000000..84225f4a1d0e
--- /dev/null
+++ b/lib/libc/tests/tls/dso/Makefile
@@ -0,0 +1,16 @@
+# $FreeBSD$
+
+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 000000000000..5449799de96c
--- /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/tls_dso/Makefile.depend b/lib/libc/tests/tls_dso/Makefile.depend
new file mode 100644
index 000000000000..9cb890b58360
--- /dev/null
+++ b/lib/libc/tests/tls_dso/Makefile.depend
@@ -0,0 +1,17 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ gnu/lib/csu \
+ gnu/lib/libgcc \
+ include \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/lib/libc/tests/ttyio/Makefile b/lib/libc/tests/ttyio/Makefile
new file mode 100644
index 000000000000..d5b8f0168558
--- /dev/null
+++ b/lib/libc/tests/ttyio/Makefile
@@ -0,0 +1,12 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+# TODO: ptm_test
+NETBSD_ATF_TESTS_C= ttyio_test
+
+LIBADD.ttyio_test+= util
+
+.include "../Makefile.netbsd-tests"
+
+.include <bsd.test.mk>
diff --git a/lib/libc/tests/ttyio/Makefile.depend b/lib/libc/tests/ttyio/Makefile.depend
new file mode 100644
index 000000000000..5212dd0e39f5
--- /dev/null
+++ b/lib/libc/tests/ttyio/Makefile.depend
@@ -0,0 +1,21 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ gnu/lib/csu \
+ gnu/lib/libgcc \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/atf/libatf-c \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libnetbsd \
+ lib/libutil \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/lib/libc/uuid/Makefile.inc b/lib/libc/uuid/Makefile.inc
new file mode 100644
index 000000000000..05c1322b53a5
--- /dev/null
+++ b/lib/libc/uuid/Makefile.inc
@@ -0,0 +1,24 @@
+# $FreeBSD$
+
+# DCE 1.1 UUID implementation sources
+
+.PATH: ${LIBC_SRCTOP}/uuid
+
+SRCS+= uuid_compare.c uuid_create.c uuid_create_nil.c uuid_equal.c \
+ uuid_from_string.c uuid_hash.c uuid_is_nil.c uuid_stream.c \
+ uuid_to_string.c
+SYM_MAPS+= ${LIBC_SRCTOP}/uuid/Symbol.map
+
+MAN+= uuid.3
+MLINKS+=uuid.3 uuid_compare.3
+MLINKS+=uuid.3 uuid_create.3
+MLINKS+=uuid.3 uuid_create_nil.3
+MLINKS+=uuid.3 uuid_equal.3
+MLINKS+=uuid.3 uuid_from_string.3
+MLINKS+=uuid.3 uuid_hash.3
+MLINKS+=uuid.3 uuid_is_nil.3
+MLINKS+=uuid.3 uuid_enc_le.3
+MLINKS+=uuid.3 uuid_dec_le.3
+MLINKS+=uuid.3 uuid_enc_be.3
+MLINKS+=uuid.3 uuid_dec_be.3
+MLINKS+=uuid.3 uuid_to_string.3
diff --git a/lib/libc/uuid/Symbol.map b/lib/libc/uuid/Symbol.map
new file mode 100644
index 000000000000..10acc781225f
--- /dev/null
+++ b/lib/libc/uuid/Symbol.map
@@ -0,0 +1,21 @@
+/*
+ * $FreeBSD$
+ */
+
+FBSD_1.0 {
+ uuid_to_string;
+ uuid_is_nil;
+ uuid_hash;
+ uuid_from_string;
+ uuid_equal;
+ uuid_create_nil;
+ uuid_create;
+ uuid_compare;
+};
+
+FBSD_1.1 {
+ uuid_enc_le;
+ uuid_dec_le;
+ uuid_enc_be;
+ uuid_dec_be;
+};
diff --git a/lib/libc/uuid/uuid.3 b/lib/libc/uuid/uuid.3
new file mode 100644
index 000000000000..4fa41dec98bd
--- /dev/null
+++ b/lib/libc/uuid/uuid.3
@@ -0,0 +1,136 @@
+.\" Copyright (c) 2002 Marcel Moolenaar
+.\" Copyright (c) 2002 Hiten Mahesh Pandya
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd March 1, 2012
+.Dt UUID 3
+.Os
+.Sh NAME
+.Nm uuid_compare , uuid_create , uuid_create_nil , uuid_equal ,
+.Nm uuid_from_string , uuid_hash , uuid_is_nil , uuid_to_string
+.Nd DCE 1.1 compliant UUID functions
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In uuid.h
+.Ft int32_t
+.Fn uuid_compare "const uuid_t *uuid1" "const uuid_t *uuid2" "uint32_t *status"
+.Ft void
+.Fn uuid_create "uuid_t *uuid" "uint32_t *status"
+.Ft void
+.Fn uuid_create_nil "uuid_t *uuid" "uint32_t *status"
+.Ft int32_t
+.Fn uuid_equal "const uuid_t *uuid1" "const uuid_t *uuid2" "uint32_t *status"
+.Ft void
+.Fn uuid_from_string "const char *str" "uuid_t *uuid" "uint32_t *status"
+.Ft uint16_t
+.Fn uuid_hash "const uuid_t *uuid" "uint32_t *status"
+.Ft int32_t
+.Fn uuid_is_nil "const uuid_t *uuid" "uint32_t *status"
+.Ft void
+.Fn uuid_to_string "const uuid_t *uuid" "char **str" "uint32_t *status"
+.Ft void
+.Fn uuid_enc_le "void *buf" "const uuid_t *uuid"
+.Ft void
+.Fn uuid_dec_le "const void *buf" "uuid_t *"
+.Ft void
+.Fn uuid_enc_be "void *buf" "const uuid_t *uuid"
+.Ft void
+.Fn uuid_dec_be "const void *buf" "uuid_t *"
+.Sh DESCRIPTION
+The family of DCE 1.1 compliant UUID functions allow applications to operate
+on universally unique identifiers, or UUIDs.
+The
+.Fn uuid_create
+and
+.Fn uuid_create_nil
+functions create UUIDs.
+The
+.Fn uuid_compare ,
+.Fn uuid_equal
+and
+.Fn uuid_is_nil
+functions can be used to test UUIDs.
+To convert from the binary representation to the string representation or
+vice versa, use
+.Fn uuid_to_string
+or
+.Fn uuid_from_string
+respectively.
+A 16-bit hash value can be obtained by calling
+.Fn uuid_hash .
+.Pp
+The
+.Fn uuid_to_string
+function set
+.Fa *str
+to be a pointer to a buffer sufficiently large to hold the string.
+This pointer should be passed to
+.Xr free 3
+to release the allocated storage when it is no longer needed.
+.Pp
+The
+.Fn uuid_enc_le
+and
+.Fn uuid_enc_be
+functions encode a binary representation of a UUID into an octet stream
+in little-endian and big-endian byte-order, respectively.
+The destination buffer must be pre-allocated by the caller, and must be
+large enough to hold the 16-octet binary UUID.
+These routines are not part of the DCE RPC API.
+They are provided for convenience.
+.Pp
+The
+.Fn uuid_dec_le
+and
+.Fn uuid_dec_be
+functions decode a UUID from an octet stream in little-endian and
+big-endian byte-order, respectively.
+These routines are not part of the DCE RPC API.
+They are provided for convenience.
+.Sh RETURN VALUES
+The successful or unsuccessful completion of the function is returned in
+the
+.Fa status
+argument.
+Possible values are:
+.Bl -tag -width ".Dv uuid_s_invalid_string_uuid"
+.It Dv uuid_s_ok
+The function completed successfully.
+.It Dv uuid_s_bad_version
+The UUID does not have a known version.
+.It Dv uuid_s_invalid_string_uuid
+The string representation of an UUID is not valid.
+.It Dv uuid_s_no_memory
+The function can not allocate memory to store an UUID representation.
+.El
+.Sh SEE ALSO
+.Xr uuidgen 1 ,
+.Xr uuidgen 2
+.Sh STANDARDS
+The UUID functions conform to the DCE 1.1 RPC specification.
+.Sh BUGS
+This manpage can be improved.
diff --git a/lib/libc/uuid/uuid_compare.c b/lib/libc/uuid/uuid_compare.c
new file mode 100644
index 000000000000..13d7c2743bf5
--- /dev/null
+++ b/lib/libc/uuid/uuid_compare.c
@@ -0,0 +1,76 @@
+/*-
+ * Copyright (c) 2002,2005 Marcel Moolenaar
+ * Copyright (c) 2002 Hiten Mahesh Pandya
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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 <string.h>
+#include <uuid.h>
+
+/* A macro used to improve the readability of uuid_compare(). */
+#define DIFF_RETURN(a, b, field) do { \
+ if ((a)->field != (b)->field) \
+ return (((a)->field < (b)->field) ? -1 : 1); \
+} while (0)
+
+/*
+ * uuid_compare() - compare two UUIDs.
+ * See also:
+ * http://www.opengroup.org/onlinepubs/009629399/uuid_compare.htm
+ *
+ * NOTE: Either UUID can be NULL, meaning a nil UUID. nil UUIDs are smaller
+ * than any non-nil UUID.
+ */
+int32_t
+uuid_compare(const uuid_t *a, const uuid_t *b, uint32_t *status)
+{
+ int res;
+
+ if (status != NULL)
+ *status = uuid_s_ok;
+
+ /* Deal with NULL or equal pointers. */
+ if (a == b)
+ return (0);
+ if (a == NULL)
+ return ((uuid_is_nil(b, NULL)) ? 0 : -1);
+ if (b == NULL)
+ return ((uuid_is_nil(a, NULL)) ? 0 : 1);
+
+ /* We have to compare the hard way. */
+ DIFF_RETURN(a, b, time_low);
+ DIFF_RETURN(a, b, time_mid);
+ DIFF_RETURN(a, b, time_hi_and_version);
+ DIFF_RETURN(a, b, clock_seq_hi_and_reserved);
+ DIFF_RETURN(a, b, clock_seq_low);
+
+ res = memcmp(a->node, b->node, sizeof(a->node));
+ if (res)
+ return ((res < 0) ? -1 : 1);
+ return (0);
+}
+
+#undef DIFF_RETURN
diff --git a/lib/libc/uuid/uuid_create.c b/lib/libc/uuid/uuid_create.c
new file mode 100644
index 000000000000..da3f1d39f78d
--- /dev/null
+++ b/lib/libc/uuid/uuid_create.c
@@ -0,0 +1,45 @@
+/*-
+ * Copyright (c) 2002 Marcel Moolenaar
+ * Copyright (c) 2002 Hiten Mahesh Pandya
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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 <uuid.h>
+
+/*
+ * uuid_create() - create an UUID.
+ * See also:
+ * http://www.opengroup.org/onlinepubs/009629399/uuid_create.htm
+ */
+void
+uuid_create(uuid_t *u, uint32_t *status)
+{
+
+ if (status)
+ *status = uuid_s_ok;
+
+ uuidgen(u, 1);
+}
diff --git a/lib/libc/uuid/uuid_create_nil.c b/lib/libc/uuid/uuid_create_nil.c
new file mode 100644
index 000000000000..6e85ae7fb768
--- /dev/null
+++ b/lib/libc/uuid/uuid_create_nil.c
@@ -0,0 +1,46 @@
+/*-
+ * Copyright (c) 2002 Marcel Moolenaar
+ * Copyright (c) 2002 Hiten Mahesh Pandya
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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 <strings.h>
+#include <uuid.h>
+
+/*
+ * uuid_create_nil() - create a nil UUID.
+ * See also:
+ * http://www.opengroup.org/onlinepubs/009629399/uuid_create_nil.htm
+ */
+void
+uuid_create_nil(uuid_t *u, uint32_t *status)
+{
+
+ if (status)
+ *status = uuid_s_ok;
+
+ bzero(u, sizeof(*u));
+}
diff --git a/lib/libc/uuid/uuid_equal.c b/lib/libc/uuid/uuid_equal.c
new file mode 100644
index 000000000000..e4c48e5253a1
--- /dev/null
+++ b/lib/libc/uuid/uuid_equal.c
@@ -0,0 +1,55 @@
+/*-
+ * Copyright (c) 2002,2005 Marcel Moolenaar
+ * Copyright (c) 2002 Hiten Mahesh Pandya
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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 <string.h>
+#include <uuid.h>
+
+/*
+ * uuid_equal() - compare for equality.
+ * See also:
+ * http://www.opengroup.org/onlinepubs/009629399/uuid_equal.htm
+ */
+int32_t
+uuid_equal(const uuid_t *a, const uuid_t *b, uint32_t *status)
+{
+
+ if (status != NULL)
+ *status = uuid_s_ok;
+
+ /* Deal with equal or NULL pointers. */
+ if (a == b)
+ return (1);
+ if (a == NULL)
+ return (uuid_is_nil(b, NULL));
+ if (b == NULL)
+ return (uuid_is_nil(a, NULL));
+
+ /* Do a byte for byte comparison. */
+ return ((memcmp(a, b, sizeof(uuid_t))) ? 0 : 1);
+}
diff --git a/lib/libc/uuid/uuid_from_string.c b/lib/libc/uuid/uuid_from_string.c
new file mode 100644
index 000000000000..b09a04df875d
--- /dev/null
+++ b/lib/libc/uuid/uuid_from_string.c
@@ -0,0 +1,92 @@
+/*-
+ * Copyright (c) 2002 Marcel Moolenaar
+ * Copyright (c) 2002 Hiten Mahesh Pandya
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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 <string.h>
+#include <uuid.h>
+
+/*
+ * uuid_from_string() - convert a string representation of an UUID into
+ * a binary representation.
+ * See also:
+ * http://www.opengroup.org/onlinepubs/009629399/uuid_from_string.htm
+ *
+ * NOTE: The sequence field is in big-endian, while the time fields are in
+ * native byte order.
+ */
+void
+uuid_from_string(const char *s, uuid_t *u, uint32_t *status)
+{
+ int n;
+
+ /* Short-circuit 2 special cases: NULL pointer and empty string. */
+ if (s == NULL || *s == '\0') {
+ uuid_create_nil(u, status);
+ return;
+ }
+
+ /* Assume the worst. */
+ if (status != NULL)
+ *status = uuid_s_invalid_string_uuid;
+
+ /* The UUID string representation has a fixed length. */
+ if (strlen(s) != 36)
+ return;
+
+ /*
+ * We only work with "new" UUIDs. New UUIDs have the form:
+ * 01234567-89ab-cdef-0123-456789abcdef
+ * The so called "old" UUIDs, which we don't support, have the form:
+ * 0123456789ab.cd.ef.01.23.45.67.89.ab
+ */
+ if (s[8] != '-')
+ return;
+
+ n = sscanf(s,
+ "%8x-%4hx-%4hx-%2hhx%2hhx-%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx",
+ &u->time_low, &u->time_mid, &u->time_hi_and_version,
+ &u->clock_seq_hi_and_reserved, &u->clock_seq_low, &u->node[0],
+ &u->node[1], &u->node[2], &u->node[3], &u->node[4], &u->node[5]);
+
+ /* Make sure we have all conversions. */
+ if (n != 11)
+ return;
+
+ /* We have a successful scan. Check semantics... */
+ n = u->clock_seq_hi_and_reserved;
+ if ((n & 0x80) != 0x00 && /* variant 0? */
+ (n & 0xc0) != 0x80 && /* variant 1? */
+ (n & 0xe0) != 0xc0) { /* variant 2? */
+ if (status != NULL)
+ *status = uuid_s_bad_version;
+ } else {
+ if (status != NULL)
+ *status = uuid_s_ok;
+ }
+}
diff --git a/lib/libc/uuid/uuid_hash.c b/lib/libc/uuid/uuid_hash.c
new file mode 100644
index 000000000000..e5695ee4f60e
--- /dev/null
+++ b/lib/libc/uuid/uuid_hash.c
@@ -0,0 +1,49 @@
+/*-
+ * Copyright (c) 2002,2005 Marcel Moolenaar
+ * Copyright (c) 2002 Hiten Mahesh Pandya
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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 <uuid.h>
+
+/*
+ * uuid_hash() - generate a hash value.
+ * See also:
+ * http://www.opengroup.org/onlinepubs/009629399/uuid_hash.htm
+ */
+uint16_t
+uuid_hash(const uuid_t *u, uint32_t *status)
+{
+
+ if (status)
+ *status = uuid_s_ok;
+
+ /*
+ * Use the most frequently changing bits in the UUID as the hash
+ * value. This should yield a good enough distribution...
+ */
+ return ((u) ? u->time_low & 0xffff : 0);
+}
diff --git a/lib/libc/uuid/uuid_is_nil.c b/lib/libc/uuid/uuid_is_nil.c
new file mode 100644
index 000000000000..ee1865349dee
--- /dev/null
+++ b/lib/libc/uuid/uuid_is_nil.c
@@ -0,0 +1,54 @@
+/*-
+ * Copyright (c) 2002,2005 Marcel Moolenaar
+ * Copyright (c) 2002 Hiten Mahesh Pandya
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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 <uuid.h>
+
+/*
+ * uuid_is_nil() - return whether the UUID is a nil UUID.
+ * See also:
+ * http://www.opengroup.org/onlinepubs/009629399/uuid_is_nil.htm
+ */
+int32_t
+uuid_is_nil(const uuid_t *u, uint32_t *status)
+{
+ const uint32_t *p;
+
+ if (status)
+ *status = uuid_s_ok;
+
+ if (!u)
+ return (1);
+
+ /*
+ * Pick the largest type that has equivalent alignment constraints
+ * as an UUID and use it to test if the UUID consists of all zeroes.
+ */
+ p = (const uint32_t*)u;
+ return ((p[0] == 0 && p[1] == 0 && p[2] == 0 && p[3] == 0) ? 1 : 0);
+}
diff --git a/lib/libc/uuid/uuid_stream.c b/lib/libc/uuid/uuid_stream.c
new file mode 100644
index 000000000000..a7cfd7d17393
--- /dev/null
+++ b/lib/libc/uuid/uuid_stream.c
@@ -0,0 +1,113 @@
+/* $NetBSD: uuid_stream.c,v 1.3 2008/04/19 18:21:38 plunky Exp $ */
+
+/*-
+ * Copyright (c) 2002 Marcel Moolenaar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/endian.h>
+#include <uuid.h>
+
+/*
+ * Encode/Decode UUID into octet-stream.
+ * http://www.opengroup.org/dce/info/draft-leach-uuids-guids-01.txt
+ *
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | time_low |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | time_mid | time_hi_and_version |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |clk_seq_hi_res | clk_seq_low | node (0-1) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | node (2-5) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * NOTE: These routines are not part of the DCE RPC API. They are
+ * provided for convenience.
+ */
+
+void
+uuid_enc_le(void *buf, const uuid_t *uuid)
+{
+ uint8_t *p = buf;
+ int i;
+
+ le32enc(p, uuid->time_low);
+ le16enc(p + 4, uuid->time_mid);
+ le16enc(p + 6, uuid->time_hi_and_version);
+ p[8] = uuid->clock_seq_hi_and_reserved;
+ p[9] = uuid->clock_seq_low;
+ for (i = 0; i < _UUID_NODE_LEN; i++)
+ p[10 + i] = uuid->node[i];
+}
+
+void
+uuid_dec_le(const void *buf, uuid_t *uuid)
+{
+ const uint8_t *p = buf;
+ int i;
+
+ uuid->time_low = le32dec(p);
+ uuid->time_mid = le16dec(p + 4);
+ uuid->time_hi_and_version = le16dec(p + 6);
+ uuid->clock_seq_hi_and_reserved = p[8];
+ uuid->clock_seq_low = p[9];
+ for (i = 0; i < _UUID_NODE_LEN; i++)
+ uuid->node[i] = p[10 + i];
+}
+
+void
+uuid_enc_be(void *buf, const uuid_t *uuid)
+{
+ uint8_t *p = buf;
+ int i;
+
+ be32enc(p, uuid->time_low);
+ be16enc(p + 4, uuid->time_mid);
+ be16enc(p + 6, uuid->time_hi_and_version);
+ p[8] = uuid->clock_seq_hi_and_reserved;
+ p[9] = uuid->clock_seq_low;
+ for (i = 0; i < _UUID_NODE_LEN; i++)
+ p[10 + i] = uuid->node[i];
+}
+
+void
+uuid_dec_be(const void *buf, uuid_t *uuid)
+{
+ const uint8_t *p = buf;
+ int i;
+
+ uuid->time_low = be32dec(p);
+ uuid->time_mid = be16dec(p + 4);
+ uuid->time_hi_and_version = be16dec(p + 6);
+ uuid->clock_seq_hi_and_reserved = p[8];
+ uuid->clock_seq_low = p[9];
+ for (i = 0; i < _UUID_NODE_LEN; i++)
+ uuid->node[i] = p[10 + i];
+}
diff --git a/lib/libc/uuid/uuid_to_string.c b/lib/libc/uuid/uuid_to_string.c
new file mode 100644
index 000000000000..35f8581bfe00
--- /dev/null
+++ b/lib/libc/uuid/uuid_to_string.c
@@ -0,0 +1,67 @@
+/*-
+ * Copyright (c) 2002,2005 Marcel Moolenaar
+ * Copyright (c) 2002 Hiten Mahesh Pandya
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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 <string.h>
+#include <uuid.h>
+
+/*
+ * uuid_to_string() - Convert a binary UUID into a string representation.
+ * See also:
+ * http://www.opengroup.org/onlinepubs/009629399/uuid_to_string.htm
+ *
+ * NOTE: The references given above do not have a status code for when
+ * the string could not be allocated. The status code has been
+ * taken from the Hewlett-Packard implementation.
+ */
+void
+uuid_to_string(const uuid_t *u, char **s, uint32_t *status)
+{
+ uuid_t nil;
+
+ if (status != NULL)
+ *status = uuid_s_ok;
+
+ /* Why allow a NULL-pointer here? */
+ if (s == NULL)
+ return;
+
+ if (u == NULL) {
+ u = &nil;
+ uuid_create_nil(&nil, NULL);
+ }
+
+ asprintf(s, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ u->time_low, u->time_mid, u->time_hi_and_version,
+ u->clock_seq_hi_and_reserved, u->clock_seq_low, u->node[0],
+ u->node[1], u->node[2], u->node[3], u->node[4], u->node[5]);
+
+ if (*s == NULL && status != NULL)
+ *status = uuid_s_no_memory;
+}
diff --git a/lib/libc/x86/sys/Makefile.inc b/lib/libc/x86/sys/Makefile.inc
new file mode 100644
index 000000000000..0e8026ae47c2
--- /dev/null
+++ b/lib/libc/x86/sys/Makefile.inc
@@ -0,0 +1,10 @@
+# $FreeBSD$
+
+.PATH: ${LIBC_SRCTOP}/x86/sys
+
+SRCS+= \
+ __vdso_gettc.c
+
+.if ${MACHINE_CPUARCH} == "amd64" && ${MK_HYPERV} != "no"
+CFLAGS+= -DWANT_HYPERV
+.endif
diff --git a/lib/libc/x86/sys/__vdso_gettc.c b/lib/libc/x86/sys/__vdso_gettc.c
new file mode 100644
index 000000000000..bf46a10e48b7
--- /dev/null
+++ b/lib/libc/x86/sys/__vdso_gettc.c
@@ -0,0 +1,268 @@
+/*-
+ * Copyright (c) 2012 Konstantin Belousov <kib@FreeBSD.org>
+ * Copyright (c) 2016, 2017 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Konstantin Belousov
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include "namespace.h"
+#include <sys/elf.h>
+#include <sys/fcntl.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+#include <sys/vdso.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include "un-namespace.h"
+#include <machine/atomic.h>
+#include <machine/cpufunc.h>
+#include <machine/specialreg.h>
+#include <dev/acpica/acpi_hpet.h>
+#ifdef WANT_HYPERV
+#include <dev/hyperv/hyperv.h>
+#endif
+#include "libc_private.h"
+
+static void
+lfence_mb(void)
+{
+#if defined(__i386__)
+ static int lfence_works = -1;
+ u_int cpuid_supported, p[4];
+
+ if (lfence_works == -1) {
+ __asm __volatile(
+ " pushfl\n"
+ " popl %%eax\n"
+ " movl %%eax,%%ecx\n"
+ " xorl $0x200000,%%eax\n"
+ " pushl %%eax\n"
+ " popfl\n"
+ " pushfl\n"
+ " popl %%eax\n"
+ " xorl %%eax,%%ecx\n"
+ " je 1f\n"
+ " movl $1,%0\n"
+ " jmp 2f\n"
+ "1: movl $0,%0\n"
+ "2:\n"
+ : "=r" (cpuid_supported) : : "eax", "ecx", "cc");
+ if (cpuid_supported) {
+ __asm __volatile(
+ " pushl %%ebx\n"
+ " cpuid\n"
+ " movl %%ebx,%1\n"
+ " popl %%ebx\n"
+ : "=a" (p[0]), "=r" (p[1]), "=c" (p[2]), "=d" (p[3])
+ : "0" (0x1));
+ lfence_works = (p[3] & CPUID_SSE2) != 0;
+ } else
+ lfence_works = 0;
+ }
+ if (lfence_works == 1)
+ lfence();
+#elif defined(__amd64__)
+ lfence();
+#else
+#error "arch"
+#endif
+}
+
+static u_int
+__vdso_gettc_rdtsc_low(const struct vdso_timehands *th)
+{
+ u_int rv;
+
+ lfence_mb();
+ __asm __volatile("rdtsc; shrd %%cl, %%edx, %0"
+ : "=a" (rv) : "c" (th->th_x86_shift) : "edx");
+ return (rv);
+}
+
+static u_int
+__vdso_rdtsc32(void)
+{
+
+ lfence_mb();
+ return (rdtsc32());
+}
+
+#define HPET_DEV_MAP_MAX 10
+static volatile char *hpet_dev_map[HPET_DEV_MAP_MAX];
+
+static void
+__vdso_init_hpet(uint32_t u)
+{
+ static const char devprefix[] = "/dev/hpet";
+ char devname[64], *c, *c1, t;
+ volatile char *new_map, *old_map;
+ uint32_t u1;
+ int fd;
+
+ c1 = c = stpcpy(devname, devprefix);
+ u1 = u;
+ do {
+ *c++ = u1 % 10 + '0';
+ u1 /= 10;
+ } while (u1 != 0);
+ *c = '\0';
+ for (c--; c1 != c; c1++, c--) {
+ t = *c1;
+ *c1 = *c;
+ *c = t;
+ }
+
+ old_map = hpet_dev_map[u];
+ if (old_map != NULL)
+ return;
+
+ fd = _open(devname, O_RDONLY);
+ if (fd == -1) {
+ atomic_cmpset_rel_ptr((volatile uintptr_t *)&hpet_dev_map[u],
+ (uintptr_t)old_map, (uintptr_t)MAP_FAILED);
+ return;
+ }
+ new_map = mmap(NULL, PAGE_SIZE, PROT_READ, MAP_SHARED, fd, 0);
+ _close(fd);
+ if (atomic_cmpset_rel_ptr((volatile uintptr_t *)&hpet_dev_map[u],
+ (uintptr_t)old_map, (uintptr_t)new_map) == 0 &&
+ new_map != MAP_FAILED)
+ munmap((void *)new_map, PAGE_SIZE);
+}
+
+#ifdef WANT_HYPERV
+
+#define HYPERV_REFTSC_DEVPATH "/dev/" HYPERV_REFTSC_DEVNAME
+
+/*
+ * NOTE:
+ * We use 'NULL' for this variable to indicate that initialization
+ * is required. And if this variable is 'MAP_FAILED', then Hyper-V
+ * reference TSC can not be used, e.g. in misconfigured jail.
+ */
+static struct hyperv_reftsc *hyperv_ref_tsc;
+
+static void
+__vdso_init_hyperv_tsc(void)
+{
+ int fd;
+
+ fd = _open(HYPERV_REFTSC_DEVPATH, O_RDONLY);
+ if (fd < 0) {
+ /* Prevent the caller from re-entering. */
+ hyperv_ref_tsc = MAP_FAILED;
+ return;
+ }
+ hyperv_ref_tsc = mmap(NULL, sizeof(*hyperv_ref_tsc), PROT_READ,
+ MAP_SHARED, fd, 0);
+ _close(fd);
+}
+
+static int
+__vdso_hyperv_tsc(struct hyperv_reftsc *tsc_ref, u_int *tc)
+{
+ uint64_t disc, ret, tsc, scale;
+ uint32_t seq;
+ int64_t ofs;
+
+ while ((seq = atomic_load_acq_int(&tsc_ref->tsc_seq)) != 0) {
+ scale = tsc_ref->tsc_scale;
+ ofs = tsc_ref->tsc_ofs;
+
+ lfence_mb();
+ tsc = rdtsc();
+
+ /* ret = ((tsc * scale) >> 64) + ofs */
+ __asm__ __volatile__ ("mulq %3" :
+ "=d" (ret), "=a" (disc) :
+ "a" (tsc), "r" (scale));
+ ret += ofs;
+
+ atomic_thread_fence_acq();
+ if (tsc_ref->tsc_seq == seq) {
+ *tc = ret;
+ return (0);
+ }
+
+ /* Sequence changed; re-sync. */
+ }
+ return (ENOSYS);
+}
+
+#endif /* WANT_HYPERV */
+
+#pragma weak __vdso_gettc
+int
+__vdso_gettc(const struct vdso_timehands *th, u_int *tc)
+{
+ volatile char *map;
+ uint32_t idx;
+
+ switch (th->th_algo) {
+ case VDSO_TH_ALGO_X86_TSC:
+ *tc = th->th_x86_shift > 0 ? __vdso_gettc_rdtsc_low(th) :
+ __vdso_rdtsc32();
+ return (0);
+ case VDSO_TH_ALGO_X86_HPET:
+ idx = th->th_x86_hpet_idx;
+ if (idx >= HPET_DEV_MAP_MAX)
+ return (ENOSYS);
+ map = (volatile char *)atomic_load_acq_ptr(
+ (volatile uintptr_t *)&hpet_dev_map[idx]);
+ if (map == NULL) {
+ __vdso_init_hpet(idx);
+ map = (volatile char *)atomic_load_acq_ptr(
+ (volatile uintptr_t *)&hpet_dev_map[idx]);
+ }
+ if (map == MAP_FAILED)
+ return (ENOSYS);
+ *tc = *(volatile uint32_t *)(map + HPET_MAIN_COUNTER);
+ return (0);
+#ifdef WANT_HYPERV
+ case VDSO_TH_ALGO_X86_HVTSC:
+ if (hyperv_ref_tsc == NULL)
+ __vdso_init_hyperv_tsc();
+ if (hyperv_ref_tsc == MAP_FAILED)
+ return (ENOSYS);
+ return (__vdso_hyperv_tsc(hyperv_ref_tsc, tc));
+#endif
+ default:
+ return (ENOSYS);
+ }
+}
+
+#pragma weak __vdso_gettimekeep
+int
+__vdso_gettimekeep(struct vdso_timekeep **tk)
+{
+
+ return (_elf_aux_info(AT_TIMEKEEP, tk, sizeof(*tk)));
+}
diff --git a/lib/libc/xdr/Makefile.inc b/lib/libc/xdr/Makefile.inc
new file mode 100644
index 000000000000..ff2c47305a9e
--- /dev/null
+++ b/lib/libc/xdr/Makefile.inc
@@ -0,0 +1,52 @@
+# @(#)Makefile 5.11 (Berkeley) 9/6/90
+# $FreeBSD$
+
+.PATH: ${LIBC_SRCTOP}/xdr ${LIBC_SRCTOP}/.
+SRCS+= xdr.c xdr_array.c xdr_float.c xdr_mem.c \
+ xdr_rec.c xdr_reference.c xdr_sizeof.c \
+ xdr_stdio.c
+
+SYM_MAPS+= ${LIBC_SRCTOP}/xdr/Symbol.map
+
+MAN+= xdr.3
+
+MLINKS+= rpc_xdr.3 xdr_accepted_reply.3 \
+ rpc_xdr.3 xdr_authsys_parms.3 \
+ rpc_xdr.3 xdr_callhdr.3 \
+ rpc_xdr.3 xdr_callmsg.3 \
+ rpc_xdr.3 xdr_opaque_auth.3 \
+ rpc_xdr.3 xdr_rejected_reply.3 \
+ rpc_xdr.3 xdr_replymsg.3 \
+ xdr.3 xdr_array.3 \
+ xdr.3 xdr_bool.3 \
+ xdr.3 xdr_bytes.3 \
+ xdr.3 xdr_char.3 \
+ xdr.3 xdr_destroy.3 \
+ xdr.3 xdr_double.3 \
+ xdr.3 xdr_enum.3 \
+ xdr.3 xdr_float.3 \
+ xdr.3 xdr_free.3 \
+ xdr.3 xdr_getpos.3 \
+ xdr.3 xdr_inline.3 \
+ xdr.3 xdr_int.3 \
+ xdr.3 xdr_long.3 \
+ xdr.3 xdrmem_create.3 \
+ xdr.3 xdr_opaque.3 \
+ xdr.3 xdr_pointer.3 \
+ xdr.3 xdrrec_create.3 \
+ xdr.3 xdrrec_endofrecord.3 \
+ xdr.3 xdrrec_eof.3 \
+ xdr.3 xdrrec_skiprecord.3 \
+ xdr.3 xdr_reference.3 \
+ xdr.3 xdr_setpos.3 \
+ xdr.3 xdr_short.3 \
+ xdr.3 xdr_sizeof.3 \
+ xdr.3 xdrstdio_create.3 \
+ xdr.3 xdr_string.3 \
+ xdr.3 xdr_u_char.3 \
+ xdr.3 xdr_u_long.3 \
+ xdr.3 xdr_u_short.3 \
+ xdr.3 xdr_union.3 \
+ xdr.3 xdr_vector.3 \
+ xdr.3 xdr_void.3 \
+ xdr.3 xdr_wrapstring.3
diff --git a/lib/libc/xdr/Symbol.map b/lib/libc/xdr/Symbol.map
new file mode 100644
index 000000000000..a8eb3a101ec4
--- /dev/null
+++ b/lib/libc/xdr/Symbol.map
@@ -0,0 +1,56 @@
+/*
+ * $FreeBSD$
+ */
+
+FBSD_1.0 {
+ xdr_free;
+ xdr_void;
+ xdr_int;
+ xdr_u_int;
+ xdr_long;
+ xdr_u_long;
+ xdr_int32_t;
+ xdr_u_int32_t;
+ xdr_short;
+ xdr_u_short;
+ xdr_int16_t;
+ xdr_u_int16_t;
+ xdr_char;
+ xdr_u_char;
+ xdr_bool;
+ xdr_enum;
+ xdr_opaque;
+ xdr_bytes;
+ xdr_netobj;
+ xdr_union;
+ xdr_string;
+ xdr_wrapstring;
+ xdr_int64_t;
+ xdr_u_int64_t;
+ xdr_hyper;
+ xdr_u_hyper;
+ xdr_longlong_t;
+ xdr_u_longlong_t;
+ xdr_array;
+ xdr_vector;
+ xdr_float;
+ xdr_double;
+ xdrmem_create;
+ xdrrec_create;
+ xdrrec_skiprecord;
+ xdrrec_eof;
+ xdrrec_endofrecord;
+ xdr_reference;
+ xdr_pointer;
+ xdrstdio_create;
+};
+
+FBSD_1.1 {
+ xdr_uint16_t;
+ xdr_uint32_t;
+ xdr_uint64_t;
+};
+
+FBSD_1.2 {
+ xdr_sizeof;
+};
diff --git a/lib/libc/xdr/xdr.3 b/lib/libc/xdr/xdr.3
new file mode 100644
index 000000000000..69f25449be67
--- /dev/null
+++ b/lib/libc/xdr/xdr.3
@@ -0,0 +1,847 @@
+.\" @(#)xdr.3n 2.2 88/08/03 4.0 RPCSRC; from 1.16 88/03/14 SMI
+.\" $FreeBSD$
+.\"
+.Dd February 16, 1988
+.Dt XDR 3
+.Os
+.Sh NAME
+.Nm xdr ,
+.Nm xdr_array ,
+.Nm xdr_bool ,
+.Nm xdr_bytes ,
+.Nm xdr_char ,
+.Nm xdr_destroy ,
+.Nm xdr_double ,
+.Nm xdr_enum ,
+.Nm xdr_float ,
+.Nm xdr_free ,
+.Nm xdr_getpos ,
+.Nm xdr_hyper ,
+.Nm xdr_inline ,
+.Nm xdr_int ,
+.Nm xdr_long ,
+.Nm xdr_longlong_t ,
+.Nm xdrmem_create ,
+.Nm xdr_opaque ,
+.Nm xdr_pointer ,
+.Nm xdrrec_create ,
+.Nm xdrrec_endofrecord ,
+.Nm xdrrec_eof ,
+.Nm xdrrec_skiprecord ,
+.Nm xdr_reference ,
+.Nm xdr_setpos ,
+.Nm xdr_short ,
+.Nm xdr_sizeof,
+.Nm xdrstdio_create ,
+.Nm xdr_string ,
+.Nm xdr_u_char ,
+.Nm xdr_u_hyper ,
+.Nm xdr_u_int ,
+.Nm xdr_u_long ,
+.Nm xdr_u_longlong_t ,
+.Nm xdr_u_short ,
+.Nm xdr_union ,
+.Nm xdr_vector ,
+.Nm xdr_void ,
+.Nm xdr_wrapstring
+.Nd "library routines for external data representation"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In rpc/types.h
+.In rpc/xdr.h
+.Pp
+See
+.Sx DESCRIPTION
+for function declarations.
+.Sh DESCRIPTION
+These routines allow C programmers to describe
+arbitrary data structures in a machine-independent fashion.
+Data for remote procedure calls are transmitted using these
+routines.
+.Pp
+.Bl -tag -width indent -compact
+.It Xo
+.Ft int
+.Xc
+.It Xo
+.Fo xdr_array
+.Fa "XDR *xdrs"
+.Fa "char **arrp"
+.Fa "u_int *sizep"
+.Fa "u_int maxsize"
+.Fa "u_int elsize"
+.Fa "xdrproc_t elproc"
+.Fc
+.Xc
+.Pp
+A filter primitive that translates between variable-length
+arrays
+and their corresponding external representations.
+The
+.Fa arrp
+argument
+is the address of the pointer to the array, while
+.Fa sizep
+is the address of the element count of the array;
+this element count cannot exceed
+.Fa maxsize .
+The
+.Fa elsize
+argument
+is the
+.Ic sizeof
+each of the array's elements, and
+.Fa elproc
+is an
+.Tn XDR
+filter that translates between
+the array elements' C form, and their external
+representation.
+This routine returns one if it succeeds, zero otherwise.
+.Pp
+.It Xo
+.Ft int
+.Xc
+.It Xo
+.Fn xdr_bool "XDR *xdrs" "bool_t *bp"
+.Xc
+.Pp
+A filter primitive that translates between booleans (C
+integers)
+and their external representations.
+When encoding data, this
+filter produces values of either one or zero.
+This routine returns one if it succeeds, zero otherwise.
+.Pp
+.It Xo
+.Ft int
+.Xc
+.It Xo
+.Fn xdr_bytes "XDR *xdrs" "char **sp" "u_int *sizep" "u_int maxsize"
+.Xc
+.Pp
+A filter primitive that translates between counted byte
+strings and their external representations.
+The
+.Fa sp
+argument
+is the address of the string pointer.
+The length of the
+string is located at address
+.Fa sizep ;
+strings cannot be longer than
+.Fa maxsize .
+This routine returns one if it succeeds, zero otherwise.
+.Pp
+.It Xo
+.Ft int
+.Xc
+.It Xo
+.Fn xdr_char "XDR *xdrs" "char *cp"
+.Xc
+.Pp
+A filter primitive that translates between C characters
+and their external representations.
+This routine returns one if it succeeds, zero otherwise.
+Note: encoded characters are not packed, and occupy 4 bytes
+each.
+For arrays of characters, it is worthwhile to
+consider
+.Fn xdr_bytes ,
+.Fn xdr_opaque
+or
+.Fn xdr_string .
+.Pp
+.It Xo
+.Ft void
+.Xc
+.It Xo
+.Fn xdr_destroy "XDR *xdrs"
+.Xc
+.Pp
+A macro that invokes the destroy routine associated with the
+.Tn XDR
+stream,
+.Fa xdrs .
+Destruction usually involves freeing private data structures
+associated with the stream.
+Using
+.Fa xdrs
+after invoking
+.Fn xdr_destroy
+is undefined.
+.Pp
+.It Xo
+.Ft int
+.Xc
+.It Xo
+.Fn xdr_double "XDR *xdrs" "double *dp"
+.Xc
+.Pp
+A filter primitive that translates between C
+.Vt double
+precision numbers and their external representations.
+This routine returns one if it succeeds, zero otherwise.
+.Pp
+.It Xo
+.Ft int
+.Xc
+.It Xo
+.Fn xdr_enum "XDR *xdrs" "enum_t *ep"
+.Xc
+.Pp
+A filter primitive that translates between C
+.Vt enum Ns s
+(actually integers) and their external representations.
+This routine returns one if it succeeds, zero otherwise.
+.Pp
+.It Xo
+.Ft int
+.Xc
+.It Xo
+.Fn xdr_float "XDR *xdrs" "float *fp"
+.Xc
+.Pp
+A filter primitive that translates between C
+.Vt float Ns s
+and their external representations.
+This routine returns one if it succeeds, zero otherwise.
+.Pp
+.It Xo
+.Ft void
+.Xc
+.It Xo
+.Fn xdr_free "xdrproc_t proc" "void *objp"
+.Xc
+.Pp
+Generic freeing routine.
+The first argument is the
+.Tn XDR
+routine for the object being freed.
+The second argument
+is a pointer to the object itself.
+Note: the pointer passed
+to this routine is
+.Em not
+freed, but what it points to
+.Em is
+freed (recursively).
+.Pp
+.It Xo
+.Ft u_int
+.Xc
+.It Xo
+.Fn xdr_getpos "XDR *xdrs"
+.Xc
+.Pp
+A macro that invokes the get\-position routine
+associated with the
+.Tn XDR
+stream,
+.Fa xdrs .
+The routine returns an unsigned integer,
+which indicates the position of the
+.Tn XDR
+byte stream.
+A desirable feature of
+.Tn XDR
+streams is that simple arithmetic works with this number,
+although the
+.Tn XDR
+stream instances need not guarantee this.
+.Pp
+.It Xo
+.Ft int
+.Xc
+.It Xo
+.Fn xdr_hyper "XDR *xdrs" "quad_t *llp"
+.Xc
+A filter primitive that translates between ANSI C
+.Vt "long long"
+integers and their external representations.
+This routine returns one if it succeeds, zero otherwise.
+.Pp
+.It Xo
+.Ft "long *"
+.Xc
+.It Xo
+.Fn xdr_inline "XDR *xdrs" "int len"
+.Xc
+.Pp
+A macro that invokes the in-line routine associated with the
+.Tn XDR
+stream,
+.Fa xdrs .
+The routine returns a pointer
+to a contiguous piece of the stream's buffer;
+.Fa len
+is the byte length of the desired buffer.
+Note: pointer is cast to
+.Vt "long *" .
+.Pp
+Warning:
+.Fn xdr_inline
+may return
+.Dv NULL
+(0)
+if it cannot allocate a contiguous piece of a buffer.
+Therefore the behavior may vary among stream instances;
+it exists for the sake of efficiency.
+.Pp
+.It Xo
+.Ft int
+.Xc
+.It Xo
+.Fn xdr_int "XDR *xdrs" "int *ip"
+.Xc
+.Pp
+A filter primitive that translates between C integers
+and their external representations.
+This routine returns one if it succeeds, zero otherwise.
+.Pp
+.It Xo
+.Ft int
+.Xc
+.It Xo
+.Fn xdr_long "XDR *xdrs" "long *lp"
+.Xc
+.Pp
+A filter primitive that translates between C
+.Vt long
+integers and their external representations.
+This routine returns one if it succeeds, zero otherwise.
+.Pp
+.It Xo
+.Ft int
+.Xc
+.It Xo
+.Fn xdr_longlong_t "XDR *xdrs" "quad_t *llp"
+.Xc
+A filter primitive that translates between ANSI C
+.Vt "long long"
+integers and their external representations.
+This routine returns one if it succeeds, zero otherwise.
+.Pp
+.It Xo
+.Ft void
+.Xc
+.It Xo
+.Fn xdrmem_create "XDR *xdrs" "char *addr" "u_int size" "enum xdr_op op"
+.Xc
+.Pp
+This routine initializes the
+.Tn XDR
+stream object pointed to by
+.Fa xdrs .
+The stream's data is written to, or read from,
+a chunk of memory at location
+.Fa addr
+whose length is no more than
+.Fa size
+bytes long.
+The
+.Fa op
+argument
+determines the direction of the
+.Tn XDR
+stream
+(either
+.Dv XDR_ENCODE ,
+.Dv XDR_DECODE ,
+or
+.Dv XDR_FREE ) .
+.Pp
+.It Xo
+.Ft int
+.Xc
+.It Xo
+.Fn xdr_opaque "XDR *xdrs" "char *cp" "u_int cnt"
+.Xc
+.Pp
+A filter primitive that translates between fixed size opaque
+data
+and its external representation.
+The
+.Fa cp
+argument
+is the address of the opaque object, and
+.Fa cnt
+is its size in bytes.
+This routine returns one if it succeeds, zero otherwise.
+.Pp
+.It Xo
+.Ft int
+.Xc
+.It Xo
+.Fn xdr_pointer "XDR *xdrs" "char **objpp" "u_int objsize" "xdrproc_t xdrobj"
+.Xc
+.Pp
+Like
+.Fn xdr_reference
+except that it serializes
+.Dv NULL
+pointers, whereas
+.Fn xdr_reference
+does not.
+Thus,
+.Fn xdr_pointer
+can represent
+recursive data structures, such as binary trees or
+linked lists.
+.Pp
+.It Xo
+.Ft void
+.Xc
+.It Xo
+.Fo xdrrec_create
+.Fa "XDR *xdrs"
+.Fa "u_int sendsize"
+.Fa "u_int recvsize"
+.Fa "void *handle"
+.Fa "int \*(lp*readit\*(rp\*(lp\*(rp"
+.Fa "int \*(lp*writeit\*(rp\*(lp\*(rp"
+.Fc
+.Xc
+.Pp
+This routine initializes the
+.Tn XDR
+stream object pointed to by
+.Fa xdrs .
+The stream's data is written to a buffer of size
+.Fa sendsize ;
+a value of zero indicates the system should use a suitable
+default.
+The stream's data is read from a buffer of size
+.Fa recvsize ;
+it too can be set to a suitable default by passing a zero
+value.
+When a stream's output buffer is full,
+.Fn writeit
+is called.
+Similarly, when a stream's input buffer is empty,
+.Fn readit
+is called.
+The behavior of these two routines is similar to
+the
+system calls
+.Xr read 2
+and
+.Xr write 2 ,
+except that
+.Fa handle
+is passed to the former routines as the first argument.
+Note: the
+.Tn XDR
+stream's
+.Fa op
+field must be set by the caller.
+.Pp
+Warning: this
+.Tn XDR
+stream implements an intermediate record stream.
+Therefore there are additional bytes in the stream
+to provide record boundary information.
+.Pp
+.It Xo
+.Ft int
+.Xc
+.It Xo
+.Fn xdrrec_endofrecord "XDR *xdrs" "int sendnow"
+.Xc
+.Pp
+This routine can be invoked only on
+streams created by
+.Fn xdrrec_create .
+The data in the output buffer is marked as a completed
+record,
+and the output buffer is optionally written out if
+.Fa sendnow
+is non-zero.
+This routine returns one if it succeeds, zero
+otherwise.
+.Pp
+.It Xo
+.Ft int
+.Xc
+.It Xo
+.Fn xdrrec_eof "XDR *xdrs"
+.Xc
+.Pp
+This routine can be invoked only on
+streams created by
+.Fn xdrrec_create .
+After consuming the rest of the current record in the stream,
+this routine returns one if the stream has no more input,
+zero otherwise.
+.Pp
+.It Xo
+.Ft int
+.Xc
+.It Xo
+.Fn xdrrec_skiprecord "XDR *xdrs"
+.Xc
+.Pp
+This routine can be invoked only on
+streams created by
+.Fn xdrrec_create .
+It tells the
+.Tn XDR
+implementation that the rest of the current record
+in the stream's input buffer should be discarded.
+This routine returns one if it succeeds, zero otherwise.
+.Pp
+.It Xo
+.Ft int
+.Xc
+.It Xo
+.Fn xdr_reference "XDR *xdrs" "char **pp" "u_int size" "xdrproc_t proc"
+.Xc
+.Pp
+A primitive that provides pointer chasing within structures.
+The
+.Fa pp
+argument
+is the address of the pointer;
+.Fa size
+is the
+.Ic sizeof
+the structure that
+.Fa *pp
+points to; and
+.Fa proc
+is an
+.Tn XDR
+procedure that filters the structure
+between its C form and its external representation.
+This routine returns one if it succeeds, zero otherwise.
+.Pp
+Warning: this routine does not understand
+.Dv NULL
+pointers.
+Use
+.Fn xdr_pointer
+instead.
+.Pp
+.It Xo
+.Ft int
+.Xc
+.It Xo
+.Fn xdr_setpos "XDR *xdrs" "u_int pos"
+.Xc
+.Pp
+A macro that invokes the set position routine associated with
+the
+.Tn XDR
+stream
+.Fa xdrs .
+The
+.Fa pos
+argument
+is a position value obtained from
+.Fn xdr_getpos .
+This routine returns one if the
+.Tn XDR
+stream could be repositioned,
+and zero otherwise.
+.Pp
+Warning: it is difficult to reposition some types of
+.Tn XDR
+streams, so this routine may fail with one
+type of stream and succeed with another.
+.Pp
+.It Xo
+.Ft int
+.Xc
+.It Xo
+.Fn xdr_short "XDR *xdrs" "short *sp"
+.Xc
+.Pp
+A filter primitive that translates between C
+.Vt short
+integers and their external representations.
+This routine returns one if it succeeds, zero otherwise.
+.Pp
+.It Xo
+.Ft unsigned long
+.Xc
+.It Xo
+.Fn xdr_sizeof "xdrproc_t func" "void *data"
+.Xc
+.Pp
+This routine returns the amount of memory required to encode
+.Fa data
+using filter
+.Fa func .
+.Pp
+.It Li "#ifdef _STDIO_H_"
+.It Li "/* XDR using stdio library */"
+.It Xo
+.Ft void
+.Xc
+.It Xo
+.Fn xdrstdio_create "XDR *xdrs" "FILE *file" "enum xdr_op op"
+.Xc
+.It Li "#endif"
+.Pp
+This routine initializes the
+.Tn XDR
+stream object pointed to by
+.Fa xdrs .
+The
+.Tn XDR
+stream data is written to, or read from, the Standard
+.Tn I/O
+stream
+.Fa file .
+The
+.Fa op
+argument
+determines the direction of the
+.Tn XDR
+stream (either
+.Dv XDR_ENCODE ,
+.Dv XDR_DECODE ,
+or
+.Dv XDR_FREE ) .
+.Pp
+Warning: the destroy routine associated with such
+.Tn XDR
+streams calls
+.Xr fflush 3
+on the
+.Fa file
+stream, but never
+.Xr fclose 3 .
+.Pp
+.It Xo
+.Ft int
+.Xc
+.It Xo
+.Fn xdr_string "XDR *xdrs" "char **sp" "u_int maxsize"
+.Xc
+.Pp
+A filter primitive that translates between C strings and
+their
+corresponding external representations.
+Strings cannot be longer than
+.Fa maxsize .
+Note:
+.Fa sp
+is the address of the string's pointer.
+This routine returns one if it succeeds, zero otherwise.
+.Pp
+.It Xo
+.Ft int
+.Xc
+.It Xo
+.Fn xdr_u_char "XDR *xdrs" "unsigned char *ucp"
+.Xc
+.Pp
+A filter primitive that translates between
+.Vt unsigned
+C characters and their external representations.
+This routine returns one if it succeeds, zero otherwise.
+.Pp
+.It Xo
+.Ft int
+.Xc
+.It Xo
+.Fn xdr_u_hyper "XDR *xdrs" "u_quad_t *ullp"
+.Xc
+A filter primitive that translates between
+.Vt unsigned
+ANSI C
+.Vt long long
+integers and their external representations.
+This routine returns one if it succeeds, zero otherwise.
+.Pp
+.It Xo
+.Ft int
+.Xc
+.It Xo
+.Fn xdr_u_int "XDR *xdrs" "unsigned *up"
+.Xc
+.Pp
+A filter primitive that translates between C
+.Vt unsigned
+integers and their external representations.
+This routine returns one if it succeeds, zero otherwise.
+.Pp
+.It Xo
+.Ft int
+.Xc
+.It Xo
+.Fn xdr_u_long "XDR *xdrs" "unsigned long *ulp"
+.Xc
+.Pp
+A filter primitive that translates between C
+.Vt "unsigned long"
+integers and their external representations.
+This routine returns one if it succeeds, zero otherwise.
+.Pp
+.It Xo
+.Ft int
+.Xc
+.It Xo
+.Fn xdr_u_longlong_t "XDR *xdrs" "u_quad_t *ullp"
+.Xc
+A filter primitive that translates between
+.Vt unsigned
+ANSI C
+.Vt "long long"
+integers and their external representations.
+This routine returns one if it succeeds, zero otherwise.
+.Pp
+.It Xo
+.Ft int
+.Xc
+.It Xo
+.Fn xdr_u_short "XDR *xdrs" "unsigned short *usp"
+.Xc
+.Pp
+A filter primitive that translates between C
+.Vt "unsigned short"
+integers and their external representations.
+This routine returns one if it succeeds, zero otherwise.
+.Pp
+.It Xo
+.Ft int
+.Xc
+.It Xo
+.Fo xdr_union
+.Fa "XDR *xdrs"
+.Fa "enum_t *dscmp"
+.Fa "char *unp"
+.Fa "const struct xdr_discrim *choices"
+.Fa "xdrproc_t defaultarm"
+.Fc
+.Xc
+.Pp
+A filter primitive that translates between a discriminated C
+.Vt union
+and its corresponding external representation.
+It first
+translates the discriminant of the union located at
+.Fa dscmp .
+This discriminant is always an
+.Vt enum_t .
+Next the union located at
+.Fa unp
+is translated.
+The
+.Fa choices
+argument
+is a pointer to an array of
+.Vt xdr_discrim
+structures.
+Each structure contains an ordered pair of
+.Bq Va value , proc .
+If the union's discriminant is equal to the associated
+.Va value ,
+then the
+.Fn proc
+is called to translate the union.
+The end of the
+.Vt xdr_discrim
+structure array is denoted by a routine of value
+.Dv NULL .
+If the discriminant is not found in the
+.Fa choices
+array, then the
+.Fn defaultarm
+procedure is called (if it is not
+.Dv NULL ) .
+Returns one if it succeeds, zero otherwise.
+.Pp
+.It Xo
+.Ft int
+.Xc
+.It Xo
+.Fo xdr_vector
+.Fa "XDR *xdrs"
+.Fa "char *arrp"
+.Fa "u_int size"
+.Fa "u_int elsize"
+.Fa "xdrproc_t elproc"
+.Fc
+.Xc
+.Pp
+A filter primitive that translates between fixed-length
+arrays
+and their corresponding external representations.
+The
+.Fa arrp
+argument
+is the address of the pointer to the array, while
+.Fa size
+is the element count of the array.
+The
+.Fa elsize
+argument
+is the
+.Ic sizeof
+each of the array's elements, and
+.Fa elproc
+is an
+.Tn XDR
+filter that translates between
+the array elements' C form, and their external
+representation.
+This routine returns one if it succeeds, zero otherwise.
+.Pp
+.It Xo
+.Ft int
+.Xc
+.It Xo
+.Fn xdr_void void
+.Xc
+.Pp
+This routine always returns one.
+It may be passed to
+.Tn RPC
+routines that require a function argument,
+where nothing is to be done.
+.Pp
+.It Xo
+.Ft int
+.Xc
+.It Xo
+.Fn xdr_wrapstring "XDR *xdrs" "char **sp"
+.Xc
+.Pp
+A primitive that calls
+.Fn xdr_string xdrs sp MAXUN.UNSIGNED ;
+where
+.Dv MAXUN.UNSIGNED
+is the maximum value of an unsigned integer.
+The
+.Fn xdr_wrapstring
+function
+is handy because the
+.Tn RPC
+package passes a maximum of two
+.Tn XDR
+routines as arguments, and
+.Fn xdr_string ,
+one of the most frequently used primitives, requires three.
+Returns one if it succeeds, zero otherwise.
+.El
+.Sh SEE ALSO
+.Xr rpc 3
+.Rs
+.%T "eXternal Data Representation Standard: Protocol Specification"
+.Re
+.Rs
+.%T "eXternal Data Representation: Sun Technical Notes"
+.Re
+.Rs
+.%T "XDR: External Data Representation Standard"
+.%O RFC1014
+.%Q "Sun Microsystems, Inc., USC\-ISI"
+.Re
+.Sh HISTORY
+The
+.Nm xdr_sizeof
+function first appeared in
+.Fx 9.0 .
diff --git a/lib/libc/xdr/xdr.c b/lib/libc/xdr/xdr.c
new file mode 100644
index 000000000000..4138171e5023
--- /dev/null
+++ b/lib/libc/xdr/xdr.c
@@ -0,0 +1,907 @@
+/* $NetBSD: xdr.c,v 1.22 2000/07/06 03:10:35 christos Exp $ */
+
+/*-
+ * Copyright (c) 2010, Oracle America, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ * * Neither the name of the "Oracle America, Inc." nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *sccsid2 = "@(#)xdr.c 1.35 87/08/12";
+static char *sccsid = "@(#)xdr.c 2.1 88/07/29 4.0 RPCSRC";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * xdr.c, Generic XDR routines implementation.
+ *
+ * These are the "generic" xdr routines used to serialize and de-serialize
+ * most common data items. See xdr.h for more info on the interface to
+ * xdr.
+ */
+
+#include "namespace.h"
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#include "un-namespace.h"
+
+typedef quad_t longlong_t; /* ANSI long long type */
+typedef u_quad_t u_longlong_t; /* ANSI unsigned long long type */
+
+/*
+ * constants specific to the xdr "protocol"
+ */
+#define XDR_FALSE ((long) 0)
+#define XDR_TRUE ((long) 1)
+#define LASTUNSIGNED ((u_int) 0-1)
+
+/*
+ * for unit alignment
+ */
+static const char xdr_zero[BYTES_PER_XDR_UNIT] = { 0, 0, 0, 0 };
+
+/*
+ * Free a data structure using XDR
+ * Not a filter, but a convenient utility nonetheless
+ */
+void
+xdr_free(xdrproc_t proc, void *objp)
+{
+ XDR x;
+
+ x.x_op = XDR_FREE;
+ (*proc)(&x, objp);
+}
+
+/*
+ * XDR nothing
+ */
+bool_t
+xdr_void(void)
+{
+
+ return (TRUE);
+}
+
+
+/*
+ * XDR integers
+ */
+bool_t
+xdr_int(XDR *xdrs, int *ip)
+{
+ long l;
+
+ switch (xdrs->x_op) {
+
+ case XDR_ENCODE:
+ l = (long) *ip;
+ return (XDR_PUTLONG(xdrs, &l));
+
+ case XDR_DECODE:
+ if (!XDR_GETLONG(xdrs, &l)) {
+ return (FALSE);
+ }
+ *ip = (int) l;
+ return (TRUE);
+
+ case XDR_FREE:
+ return (TRUE);
+ }
+ /* NOTREACHED */
+ return (FALSE);
+}
+
+/*
+ * XDR unsigned integers
+ */
+bool_t
+xdr_u_int(XDR *xdrs, u_int *up)
+{
+ u_long l;
+
+ switch (xdrs->x_op) {
+
+ case XDR_ENCODE:
+ l = (u_long) *up;
+ return (XDR_PUTLONG(xdrs, (long *)&l));
+
+ case XDR_DECODE:
+ if (!XDR_GETLONG(xdrs, (long *)&l)) {
+ return (FALSE);
+ }
+ *up = (u_int) l;
+ return (TRUE);
+
+ case XDR_FREE:
+ return (TRUE);
+ }
+ /* NOTREACHED */
+ return (FALSE);
+}
+
+
+/*
+ * XDR long integers
+ * same as xdr_u_long - open coded to save a proc call!
+ */
+bool_t
+xdr_long(XDR *xdrs, long *lp)
+{
+ switch (xdrs->x_op) {
+ case XDR_ENCODE:
+ return (XDR_PUTLONG(xdrs, lp));
+ case XDR_DECODE:
+ return (XDR_GETLONG(xdrs, lp));
+ case XDR_FREE:
+ return (TRUE);
+ }
+ /* NOTREACHED */
+ return (FALSE);
+}
+
+/*
+ * XDR unsigned long integers
+ * same as xdr_long - open coded to save a proc call!
+ */
+bool_t
+xdr_u_long(XDR *xdrs, u_long *ulp)
+{
+ switch (xdrs->x_op) {
+ case XDR_ENCODE:
+ return (XDR_PUTLONG(xdrs, (long *)ulp));
+ case XDR_DECODE:
+ return (XDR_GETLONG(xdrs, (long *)ulp));
+ case XDR_FREE:
+ return (TRUE);
+ }
+ /* NOTREACHED */
+ return (FALSE);
+}
+
+
+/*
+ * XDR 32-bit integers
+ * same as xdr_u_int32_t - open coded to save a proc call!
+ */
+bool_t
+xdr_int32_t(XDR *xdrs, int32_t *int32_p)
+{
+ long l;
+
+ switch (xdrs->x_op) {
+
+ case XDR_ENCODE:
+ l = (long) *int32_p;
+ return (XDR_PUTLONG(xdrs, &l));
+
+ case XDR_DECODE:
+ if (!XDR_GETLONG(xdrs, &l)) {
+ return (FALSE);
+ }
+ *int32_p = (int32_t) l;
+ return (TRUE);
+
+ case XDR_FREE:
+ return (TRUE);
+ }
+ /* NOTREACHED */
+ return (FALSE);
+}
+
+/*
+ * XDR unsigned 32-bit integers
+ * same as xdr_int32_t - open coded to save a proc call!
+ */
+bool_t
+xdr_u_int32_t(XDR *xdrs, u_int32_t *u_int32_p)
+{
+ u_long l;
+
+ switch (xdrs->x_op) {
+
+ case XDR_ENCODE:
+ l = (u_long) *u_int32_p;
+ return (XDR_PUTLONG(xdrs, (long *)&l));
+
+ case XDR_DECODE:
+ if (!XDR_GETLONG(xdrs, (long *)&l)) {
+ return (FALSE);
+ }
+ *u_int32_p = (u_int32_t) l;
+ return (TRUE);
+
+ case XDR_FREE:
+ return (TRUE);
+ }
+ /* NOTREACHED */
+ return (FALSE);
+}
+
+/*
+ * XDR unsigned 32-bit integers
+ * same as xdr_int32_t - open coded to save a proc call!
+ */
+bool_t
+xdr_uint32_t(XDR *xdrs, uint32_t *u_int32_p)
+{
+ u_long l;
+
+ switch (xdrs->x_op) {
+
+ case XDR_ENCODE:
+ l = (u_long) *u_int32_p;
+ return (XDR_PUTLONG(xdrs, (long *)&l));
+
+ case XDR_DECODE:
+ if (!XDR_GETLONG(xdrs, (long *)&l)) {
+ return (FALSE);
+ }
+ *u_int32_p = (u_int32_t) l;
+ return (TRUE);
+
+ case XDR_FREE:
+ return (TRUE);
+ }
+ /* NOTREACHED */
+ return (FALSE);
+}
+
+/*
+ * XDR short integers
+ */
+bool_t
+xdr_short(XDR *xdrs, short *sp)
+{
+ long l;
+
+ switch (xdrs->x_op) {
+
+ case XDR_ENCODE:
+ l = (long) *sp;
+ return (XDR_PUTLONG(xdrs, &l));
+
+ case XDR_DECODE:
+ if (!XDR_GETLONG(xdrs, &l)) {
+ return (FALSE);
+ }
+ *sp = (short) l;
+ return (TRUE);
+
+ case XDR_FREE:
+ return (TRUE);
+ }
+ /* NOTREACHED */
+ return (FALSE);
+}
+
+/*
+ * XDR unsigned short integers
+ */
+bool_t
+xdr_u_short(XDR *xdrs, u_short *usp)
+{
+ u_long l;
+
+ switch (xdrs->x_op) {
+
+ case XDR_ENCODE:
+ l = (u_long) *usp;
+ return (XDR_PUTLONG(xdrs, (long *)&l));
+
+ case XDR_DECODE:
+ if (!XDR_GETLONG(xdrs, (long *)&l)) {
+ return (FALSE);
+ }
+ *usp = (u_short) l;
+ return (TRUE);
+
+ case XDR_FREE:
+ return (TRUE);
+ }
+ /* NOTREACHED */
+ return (FALSE);
+}
+
+
+/*
+ * XDR 16-bit integers
+ */
+bool_t
+xdr_int16_t(XDR *xdrs, int16_t *int16_p)
+{
+ long l;
+
+ switch (xdrs->x_op) {
+
+ case XDR_ENCODE:
+ l = (long) *int16_p;
+ return (XDR_PUTLONG(xdrs, &l));
+
+ case XDR_DECODE:
+ if (!XDR_GETLONG(xdrs, &l)) {
+ return (FALSE);
+ }
+ *int16_p = (int16_t) l;
+ return (TRUE);
+
+ case XDR_FREE:
+ return (TRUE);
+ }
+ /* NOTREACHED */
+ return (FALSE);
+}
+
+/*
+ * XDR unsigned 16-bit integers
+ */
+bool_t
+xdr_u_int16_t(XDR *xdrs, u_int16_t *u_int16_p)
+{
+ u_long l;
+
+ switch (xdrs->x_op) {
+
+ case XDR_ENCODE:
+ l = (u_long) *u_int16_p;
+ return (XDR_PUTLONG(xdrs, (long *)&l));
+
+ case XDR_DECODE:
+ if (!XDR_GETLONG(xdrs, (long *)&l)) {
+ return (FALSE);
+ }
+ *u_int16_p = (u_int16_t) l;
+ return (TRUE);
+
+ case XDR_FREE:
+ return (TRUE);
+ }
+ /* NOTREACHED */
+ return (FALSE);
+}
+
+/*
+ * XDR unsigned 16-bit integers
+ */
+bool_t
+xdr_uint16_t(XDR *xdrs, uint16_t *u_int16_p)
+{
+ u_long l;
+
+ switch (xdrs->x_op) {
+
+ case XDR_ENCODE:
+ l = (u_long) *u_int16_p;
+ return (XDR_PUTLONG(xdrs, (long *)&l));
+
+ case XDR_DECODE:
+ if (!XDR_GETLONG(xdrs, (long *)&l)) {
+ return (FALSE);
+ }
+ *u_int16_p = (u_int16_t) l;
+ return (TRUE);
+
+ case XDR_FREE:
+ return (TRUE);
+ }
+ /* NOTREACHED */
+ return (FALSE);
+}
+
+
+/*
+ * XDR a char
+ */
+bool_t
+xdr_char(XDR *xdrs, char *cp)
+{
+ int i;
+
+ i = (*cp);
+ if (!xdr_int(xdrs, &i)) {
+ return (FALSE);
+ }
+ *cp = i;
+ return (TRUE);
+}
+
+/*
+ * XDR an unsigned char
+ */
+bool_t
+xdr_u_char(XDR *xdrs, u_char *cp)
+{
+ u_int u;
+
+ u = (*cp);
+ if (!xdr_u_int(xdrs, &u)) {
+ return (FALSE);
+ }
+ *cp = u;
+ return (TRUE);
+}
+
+/*
+ * XDR booleans
+ */
+bool_t
+xdr_bool(XDR *xdrs, bool_t *bp)
+{
+ long lb;
+
+ switch (xdrs->x_op) {
+
+ case XDR_ENCODE:
+ lb = *bp ? XDR_TRUE : XDR_FALSE;
+ return (XDR_PUTLONG(xdrs, &lb));
+
+ case XDR_DECODE:
+ if (!XDR_GETLONG(xdrs, &lb)) {
+ return (FALSE);
+ }
+ *bp = (lb == XDR_FALSE) ? FALSE : TRUE;
+ return (TRUE);
+
+ case XDR_FREE:
+ return (TRUE);
+ }
+ /* NOTREACHED */
+ return (FALSE);
+}
+
+/*
+ * XDR enumerations
+ */
+bool_t
+xdr_enum(XDR *xdrs, enum_t *ep)
+{
+ enum sizecheck { SIZEVAL }; /* used to find the size of an enum */
+
+ /*
+ * enums are treated as ints
+ */
+ /* LINTED */ if (sizeof (enum sizecheck) == sizeof (long)) {
+ return (xdr_long(xdrs, (long *)(void *)ep));
+ } else /* LINTED */ if (sizeof (enum sizecheck) == sizeof (int)) {
+ return (xdr_int(xdrs, (int *)(void *)ep));
+ } else /* LINTED */ if (sizeof (enum sizecheck) == sizeof (short)) {
+ return (xdr_short(xdrs, (short *)(void *)ep));
+ } else {
+ return (FALSE);
+ }
+}
+
+/*
+ * XDR opaque data
+ * Allows the specification of a fixed size sequence of opaque bytes.
+ * cp points to the opaque object and cnt gives the byte length.
+ */
+bool_t
+xdr_opaque(XDR *xdrs, caddr_t cp, u_int cnt)
+{
+ u_int rndup;
+ static int crud[BYTES_PER_XDR_UNIT];
+
+ /*
+ * if no data we are done
+ */
+ if (cnt == 0)
+ return (TRUE);
+
+ /*
+ * round byte count to full xdr units
+ */
+ rndup = cnt % BYTES_PER_XDR_UNIT;
+ if (rndup > 0)
+ rndup = BYTES_PER_XDR_UNIT - rndup;
+
+ if (xdrs->x_op == XDR_DECODE) {
+ if (!XDR_GETBYTES(xdrs, cp, cnt)) {
+ return (FALSE);
+ }
+ if (rndup == 0)
+ return (TRUE);
+ return (XDR_GETBYTES(xdrs, (caddr_t)(void *)crud, rndup));
+ }
+
+ if (xdrs->x_op == XDR_ENCODE) {
+ if (!XDR_PUTBYTES(xdrs, cp, cnt)) {
+ return (FALSE);
+ }
+ if (rndup == 0)
+ return (TRUE);
+ return (XDR_PUTBYTES(xdrs, xdr_zero, rndup));
+ }
+
+ if (xdrs->x_op == XDR_FREE) {
+ return (TRUE);
+ }
+
+ return (FALSE);
+}
+
+/*
+ * XDR counted bytes
+ * *cpp is a pointer to the bytes, *sizep is the count.
+ * If *cpp is NULL maxsize bytes are allocated
+ */
+bool_t
+xdr_bytes(XDR *xdrs, char **cpp, u_int *sizep, u_int maxsize)
+{
+ char *sp = *cpp; /* sp is the actual string pointer */
+ u_int nodesize;
+
+ /*
+ * first deal with the length since xdr bytes are counted
+ */
+ if (! xdr_u_int(xdrs, sizep)) {
+ return (FALSE);
+ }
+ nodesize = *sizep;
+ if ((nodesize > maxsize) && (xdrs->x_op != XDR_FREE)) {
+ return (FALSE);
+ }
+
+ /*
+ * now deal with the actual bytes
+ */
+ switch (xdrs->x_op) {
+
+ case XDR_DECODE:
+ if (nodesize == 0) {
+ return (TRUE);
+ }
+ if (sp == NULL) {
+ *cpp = sp = mem_alloc(nodesize);
+ }
+ if (sp == NULL) {
+ warnx("xdr_bytes: out of memory");
+ return (FALSE);
+ }
+ /* FALLTHROUGH */
+
+ case XDR_ENCODE:
+ return (xdr_opaque(xdrs, sp, nodesize));
+
+ case XDR_FREE:
+ if (sp != NULL) {
+ mem_free(sp, nodesize);
+ *cpp = NULL;
+ }
+ return (TRUE);
+ }
+ /* NOTREACHED */
+ return (FALSE);
+}
+
+/*
+ * Implemented here due to commonality of the object.
+ */
+bool_t
+xdr_netobj(XDR *xdrs, struct netobj *np)
+{
+
+ return (xdr_bytes(xdrs, &np->n_bytes, &np->n_len, MAX_NETOBJ_SZ));
+}
+
+/*
+ * XDR a descriminated union
+ * Support routine for discriminated unions.
+ * You create an array of xdrdiscrim structures, terminated with
+ * an entry with a null procedure pointer. The routine gets
+ * the discriminant value and then searches the array of xdrdiscrims
+ * looking for that value. It calls the procedure given in the xdrdiscrim
+ * to handle the discriminant. If there is no specific routine a default
+ * routine may be called.
+ * If there is no specific or default routine an error is returned.
+ */
+bool_t
+xdr_union(XDR *xdrs, enum_t *dscmp, char *unp, const struct xdr_discrim *choices, xdrproc_t dfault)
+/*
+ * XDR *xdrs;
+ * enum_t *dscmp; // enum to decide which arm to work on
+ * char *unp; // the union itself
+ * const struct xdr_discrim *choices; // [value, xdr proc] for each arm
+ * xdrproc_t dfault; // default xdr routine
+ */
+{
+ enum_t dscm;
+
+ /*
+ * we deal with the discriminator; it's an enum
+ */
+ if (! xdr_enum(xdrs, dscmp)) {
+ return (FALSE);
+ }
+ dscm = *dscmp;
+
+ /*
+ * search choices for a value that matches the discriminator.
+ * if we find one, execute the xdr routine for that value.
+ */
+ for (; choices->proc != NULL_xdrproc_t; choices++) {
+ if (choices->value == dscm)
+ return ((*(choices->proc))(xdrs, unp));
+ }
+
+ /*
+ * no match - execute the default xdr routine if there is one
+ */
+ return ((dfault == NULL_xdrproc_t) ? FALSE :
+ (*dfault)(xdrs, unp));
+}
+
+
+/*
+ * Non-portable xdr primitives.
+ * Care should be taken when moving these routines to new architectures.
+ */
+
+
+/*
+ * XDR null terminated ASCII strings
+ * xdr_string deals with "C strings" - arrays of bytes that are
+ * terminated by a NULL character. The parameter cpp references a
+ * pointer to storage; If the pointer is null, then the necessary
+ * storage is allocated. The last parameter is the max allowed length
+ * of the string as specified by a protocol.
+ */
+bool_t
+xdr_string(XDR *xdrs, char **cpp, u_int maxsize)
+{
+ char *sp = *cpp; /* sp is the actual string pointer */
+ u_int size;
+ u_int nodesize;
+
+ /*
+ * first deal with the length since xdr strings are counted-strings
+ */
+ switch (xdrs->x_op) {
+ case XDR_FREE:
+ if (sp == NULL) {
+ return(TRUE); /* already free */
+ }
+ /* FALLTHROUGH */
+ case XDR_ENCODE:
+ size = strlen(sp);
+ break;
+ case XDR_DECODE:
+ break;
+ }
+ if (! xdr_u_int(xdrs, &size)) {
+ return (FALSE);
+ }
+ if (size > maxsize) {
+ return (FALSE);
+ }
+ nodesize = size + 1;
+
+ /*
+ * now deal with the actual bytes
+ */
+ switch (xdrs->x_op) {
+
+ case XDR_DECODE:
+ if (nodesize == 0) {
+ return (TRUE);
+ }
+ if (sp == NULL)
+ *cpp = sp = mem_alloc(nodesize);
+ if (sp == NULL) {
+ warnx("xdr_string: out of memory");
+ return (FALSE);
+ }
+ sp[size] = 0;
+ /* FALLTHROUGH */
+
+ case XDR_ENCODE:
+ return (xdr_opaque(xdrs, sp, size));
+
+ case XDR_FREE:
+ mem_free(sp, nodesize);
+ *cpp = NULL;
+ return (TRUE);
+ }
+ /* NOTREACHED */
+ return (FALSE);
+}
+
+/*
+ * Wrapper for xdr_string that can be called directly from
+ * routines like clnt_call
+ */
+bool_t
+xdr_wrapstring(XDR *xdrs, char **cpp)
+{
+ return xdr_string(xdrs, cpp, LASTUNSIGNED);
+}
+
+/*
+ * NOTE: xdr_hyper(), xdr_u_hyper(), xdr_longlong_t(), and xdr_u_longlong_t()
+ * are in the "non-portable" section because they require that a `long long'
+ * be a 64-bit type.
+ *
+ * --thorpej@netbsd.org, November 30, 1999
+ */
+
+/*
+ * XDR 64-bit integers
+ */
+bool_t
+xdr_int64_t(XDR *xdrs, int64_t *llp)
+{
+ u_long ul[2];
+
+ switch (xdrs->x_op) {
+ case XDR_ENCODE:
+ ul[0] = (u_long)((u_int64_t)*llp >> 32) & 0xffffffff;
+ ul[1] = (u_long)((u_int64_t)*llp) & 0xffffffff;
+ if (XDR_PUTLONG(xdrs, (long *)&ul[0]) == FALSE)
+ return (FALSE);
+ return (XDR_PUTLONG(xdrs, (long *)&ul[1]));
+ case XDR_DECODE:
+ if (XDR_GETLONG(xdrs, (long *)&ul[0]) == FALSE)
+ return (FALSE);
+ if (XDR_GETLONG(xdrs, (long *)&ul[1]) == FALSE)
+ return (FALSE);
+ *llp = (int64_t)
+ (((u_int64_t)ul[0] << 32) | ((u_int64_t)ul[1]));
+ return (TRUE);
+ case XDR_FREE:
+ return (TRUE);
+ }
+ /* NOTREACHED */
+ return (FALSE);
+}
+
+
+/*
+ * XDR unsigned 64-bit integers
+ */
+bool_t
+xdr_u_int64_t(XDR *xdrs, u_int64_t *ullp)
+{
+ u_long ul[2];
+
+ switch (xdrs->x_op) {
+ case XDR_ENCODE:
+ ul[0] = (u_long)(*ullp >> 32) & 0xffffffff;
+ ul[1] = (u_long)(*ullp) & 0xffffffff;
+ if (XDR_PUTLONG(xdrs, (long *)&ul[0]) == FALSE)
+ return (FALSE);
+ return (XDR_PUTLONG(xdrs, (long *)&ul[1]));
+ case XDR_DECODE:
+ if (XDR_GETLONG(xdrs, (long *)&ul[0]) == FALSE)
+ return (FALSE);
+ if (XDR_GETLONG(xdrs, (long *)&ul[1]) == FALSE)
+ return (FALSE);
+ *ullp = (u_int64_t)
+ (((u_int64_t)ul[0] << 32) | ((u_int64_t)ul[1]));
+ return (TRUE);
+ case XDR_FREE:
+ return (TRUE);
+ }
+ /* NOTREACHED */
+ return (FALSE);
+}
+
+/*
+ * XDR unsigned 64-bit integers
+ */
+bool_t
+xdr_uint64_t(XDR *xdrs, uint64_t *ullp)
+{
+ u_long ul[2];
+
+ switch (xdrs->x_op) {
+ case XDR_ENCODE:
+ ul[0] = (u_long)(*ullp >> 32) & 0xffffffff;
+ ul[1] = (u_long)(*ullp) & 0xffffffff;
+ if (XDR_PUTLONG(xdrs, (long *)&ul[0]) == FALSE)
+ return (FALSE);
+ return (XDR_PUTLONG(xdrs, (long *)&ul[1]));
+ case XDR_DECODE:
+ if (XDR_GETLONG(xdrs, (long *)&ul[0]) == FALSE)
+ return (FALSE);
+ if (XDR_GETLONG(xdrs, (long *)&ul[1]) == FALSE)
+ return (FALSE);
+ *ullp = (u_int64_t)
+ (((u_int64_t)ul[0] << 32) | ((u_int64_t)ul[1]));
+ return (TRUE);
+ case XDR_FREE:
+ return (TRUE);
+ }
+ /* NOTREACHED */
+ return (FALSE);
+}
+
+
+/*
+ * XDR hypers
+ */
+bool_t
+xdr_hyper(XDR *xdrs, longlong_t *llp)
+{
+
+ /*
+ * Don't bother open-coding this; it's a fair amount of code. Just
+ * call xdr_int64_t().
+ */
+ return (xdr_int64_t(xdrs, (int64_t *)llp));
+}
+
+
+/*
+ * XDR unsigned hypers
+ */
+bool_t
+xdr_u_hyper(XDR *xdrs, u_longlong_t *ullp)
+{
+
+ /*
+ * Don't bother open-coding this; it's a fair amount of code. Just
+ * call xdr_u_int64_t().
+ */
+ return (xdr_u_int64_t(xdrs, (u_int64_t *)ullp));
+}
+
+
+/*
+ * XDR longlong_t's
+ */
+bool_t
+xdr_longlong_t(XDR *xdrs, longlong_t *llp)
+{
+
+ /*
+ * Don't bother open-coding this; it's a fair amount of code. Just
+ * call xdr_int64_t().
+ */
+ return (xdr_int64_t(xdrs, (int64_t *)llp));
+}
+
+
+/*
+ * XDR u_longlong_t's
+ */
+bool_t
+xdr_u_longlong_t(XDR *xdrs, u_longlong_t *ullp)
+{
+
+ /*
+ * Don't bother open-coding this; it's a fair amount of code. Just
+ * call xdr_u_int64_t().
+ */
+ return (xdr_u_int64_t(xdrs, (u_int64_t *)ullp));
+}
diff --git a/lib/libc/xdr/xdr_array.c b/lib/libc/xdr/xdr_array.c
new file mode 100644
index 000000000000..a11c7a11545c
--- /dev/null
+++ b/lib/libc/xdr/xdr_array.c
@@ -0,0 +1,160 @@
+/* $NetBSD: xdr_array.c,v 1.12 2000/01/22 22:19:18 mycroft Exp $ */
+
+/*-
+ * Copyright (c) 2010, Oracle America, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ * * Neither the name of the "Oracle America, Inc." nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *sccsid2 = "@(#)xdr_array.c 1.10 87/08/11 Copyr 1984 Sun Micro";
+static char *sccsid = "@(#)xdr_array.c 2.1 88/07/29 4.0 RPCSRC";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * xdr_array.c, Generic XDR routines impelmentation.
+ *
+ * These are the "non-trivial" xdr primitives used to serialize and de-serialize
+ * arrays. See xdr.h for more info on the interface to xdr.
+ */
+
+#include "namespace.h"
+#include <err.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#include "un-namespace.h"
+
+/*
+ * XDR an array of arbitrary elements
+ * *addrp is a pointer to the array, *sizep is the number of elements.
+ * If addrp is NULL (*sizep * elsize) bytes are allocated.
+ * elsize is the size (in bytes) of each element, and elproc is the
+ * xdr procedure to call to handle each element of the array.
+ */
+bool_t
+xdr_array(XDR *xdrs, caddr_t *addrp, u_int *sizep, u_int maxsize, u_int elsize, xdrproc_t elproc)
+/*
+ * XDR *xdrs;
+ * caddr_t *addrp; // array pointer
+ * u_int *sizep; // number of elements
+ * u_int maxsize; // max numberof elements
+ * u_int elsize; // size in bytes of each element
+ * xdrproc_t elproc; // xdr routine to handle each element
+ */
+{
+ u_int i;
+ caddr_t target = *addrp;
+ u_int c; /* the actual element count */
+ bool_t stat = TRUE;
+ u_int nodesize;
+
+ /* like strings, arrays are really counted arrays */
+ if (!xdr_u_int(xdrs, sizep)) {
+ return (FALSE);
+ }
+ c = *sizep;
+ if ((c > maxsize || UINT_MAX/elsize < c) &&
+ (xdrs->x_op != XDR_FREE)) {
+ return (FALSE);
+ }
+ nodesize = c * elsize;
+
+ /*
+ * if we are deserializing, we may need to allocate an array.
+ * We also save time by checking for a null array if we are freeing.
+ */
+ if (target == NULL)
+ switch (xdrs->x_op) {
+ case XDR_DECODE:
+ if (c == 0)
+ return (TRUE);
+ *addrp = target = mem_alloc(nodesize);
+ if (target == NULL) {
+ warnx("xdr_array: out of memory");
+ return (FALSE);
+ }
+ memset(target, 0, nodesize);
+ break;
+
+ case XDR_FREE:
+ return (TRUE);
+
+ case XDR_ENCODE:
+ break;
+ }
+
+ /*
+ * now we xdr each element of array
+ */
+ for (i = 0; (i < c) && stat; i++) {
+ stat = (*elproc)(xdrs, target);
+ target += elsize;
+ }
+
+ /*
+ * the array may need freeing
+ */
+ if (xdrs->x_op == XDR_FREE) {
+ mem_free(*addrp, nodesize);
+ *addrp = NULL;
+ }
+ return (stat);
+}
+
+/*
+ * xdr_vector():
+ *
+ * XDR a fixed length array. Unlike variable-length arrays,
+ * the storage of fixed length arrays is static and unfreeable.
+ * > basep: base of the array
+ * > size: size of the array
+ * > elemsize: size of each element
+ * > xdr_elem: routine to XDR each element
+ */
+bool_t
+xdr_vector(XDR *xdrs, char *basep, u_int nelem, u_int elemsize, xdrproc_t xdr_elem)
+{
+ u_int i;
+ char *elptr;
+
+ elptr = basep;
+ for (i = 0; i < nelem; i++) {
+ if (!(*xdr_elem)(xdrs, elptr)) {
+ return(FALSE);
+ }
+ elptr += elemsize;
+ }
+ return(TRUE);
+}
diff --git a/lib/libc/xdr/xdr_float.c b/lib/libc/xdr/xdr_float.c
new file mode 100644
index 000000000000..1f16a4e44da7
--- /dev/null
+++ b/lib/libc/xdr/xdr_float.c
@@ -0,0 +1,295 @@
+/* $NetBSD: xdr_float.c,v 1.23 2000/07/17 04:59:51 matt Exp $ */
+
+/*-
+ * Copyright (c) 2010, Oracle America, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ * * Neither the name of the "Oracle America, Inc." nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *sccsid2 = "@(#)xdr_float.c 1.12 87/08/11 Copyr 1984 Sun Micro";
+static char *sccsid = "@(#)xdr_float.c 2.1 88/07/29 4.0 RPCSRC";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * xdr_float.c, Generic XDR routines implementation.
+ *
+ * These are the "floating point" xdr routines used to (de)serialize
+ * most common data items. See xdr.h for more info on the interface to
+ * xdr.
+ */
+
+#include "namespace.h"
+#include <sys/param.h>
+
+#include <stdio.h>
+
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#include "un-namespace.h"
+
+/*
+ * NB: Not portable.
+ * This routine works on machines with IEEE754 FP and Vaxen.
+ */
+
+#include <machine/endian.h>
+#define IEEEFP
+
+#if defined(__vax__)
+
+/* What IEEE single precision floating point looks like on a Vax */
+struct ieee_single {
+ unsigned int mantissa: 23;
+ unsigned int exp : 8;
+ unsigned int sign : 1;
+};
+
+/* Vax single precision floating point */
+struct vax_single {
+ unsigned int mantissa1 : 7;
+ unsigned int exp : 8;
+ unsigned int sign : 1;
+ unsigned int mantissa2 : 16;
+};
+
+#define VAX_SNG_BIAS 0x81
+#define IEEE_SNG_BIAS 0x7f
+
+static struct sgl_limits {
+ struct vax_single s;
+ struct ieee_single ieee;
+} sgl_limits[2] = {
+ {{ 0x7f, 0xff, 0x0, 0xffff }, /* Max Vax */
+ { 0x0, 0xff, 0x0 }}, /* Max IEEE */
+ {{ 0x0, 0x0, 0x0, 0x0 }, /* Min Vax */
+ { 0x0, 0x0, 0x0 }} /* Min IEEE */
+};
+#endif /* vax */
+
+bool_t
+xdr_float(XDR *xdrs, float *fp)
+{
+#ifndef IEEEFP
+ struct ieee_single is;
+ struct vax_single vs, *vsp;
+ struct sgl_limits *lim;
+ u_int i;
+#endif
+ switch (xdrs->x_op) {
+
+ case XDR_ENCODE:
+#ifdef IEEEFP
+ return (XDR_PUTINT32(xdrs, (int32_t *)fp));
+#else
+ vs = *((struct vax_single *)fp);
+ for (i = 0, lim = sgl_limits; i < nitems(sgl_limits);
+ i++, lim++) {
+ if ((vs.mantissa2 == lim->s.mantissa2) &&
+ (vs.exp == lim->s.exp) &&
+ (vs.mantissa1 == lim->s.mantissa1)) {
+ is = lim->ieee;
+ goto shipit;
+ }
+ }
+ is.exp = vs.exp - VAX_SNG_BIAS + IEEE_SNG_BIAS;
+ is.mantissa = (vs.mantissa1 << 16) | vs.mantissa2;
+ shipit:
+ is.sign = vs.sign;
+ return (XDR_PUTINT32(xdrs, (int32_t *)&is));
+#endif
+
+ case XDR_DECODE:
+#ifdef IEEEFP
+ return (XDR_GETINT32(xdrs, (int32_t *)fp));
+#else
+ vsp = (struct vax_single *)fp;
+ if (!XDR_GETINT32(xdrs, (int32_t *)&is))
+ return (FALSE);
+ for (i = 0, lim = sgl_limits; i < nitems(sgl_limits);
+ i++, lim++) {
+ if ((is.exp == lim->ieee.exp) &&
+ (is.mantissa == lim->ieee.mantissa)) {
+ *vsp = lim->s;
+ goto doneit;
+ }
+ }
+ vsp->exp = is.exp - IEEE_SNG_BIAS + VAX_SNG_BIAS;
+ vsp->mantissa2 = is.mantissa;
+ vsp->mantissa1 = (is.mantissa >> 16);
+ doneit:
+ vsp->sign = is.sign;
+ return (TRUE);
+#endif
+
+ case XDR_FREE:
+ return (TRUE);
+ }
+ /* NOTREACHED */
+ return (FALSE);
+}
+
+#if defined(__vax__)
+/* What IEEE double precision floating point looks like on a Vax */
+struct ieee_double {
+ unsigned int mantissa1 : 20;
+ unsigned int exp : 11;
+ unsigned int sign : 1;
+ unsigned int mantissa2 : 32;
+};
+
+/* Vax double precision floating point */
+struct vax_double {
+ unsigned int mantissa1 : 7;
+ unsigned int exp : 8;
+ unsigned int sign : 1;
+ unsigned int mantissa2 : 16;
+ unsigned int mantissa3 : 16;
+ unsigned int mantissa4 : 16;
+};
+
+#define VAX_DBL_BIAS 0x81
+#define IEEE_DBL_BIAS 0x3ff
+#define MASK(nbits) ((1 << nbits) - 1)
+
+static struct dbl_limits {
+ struct vax_double d;
+ struct ieee_double ieee;
+} dbl_limits[2] = {
+ {{ 0x7f, 0xff, 0x0, 0xffff, 0xffff, 0xffff }, /* Max Vax */
+ { 0x0, 0x7ff, 0x0, 0x0 }}, /* Max IEEE */
+ {{ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, /* Min Vax */
+ { 0x0, 0x0, 0x0, 0x0 }} /* Min IEEE */
+};
+
+#endif /* vax */
+
+
+bool_t
+xdr_double(XDR *xdrs, double *dp)
+{
+#ifdef IEEEFP
+ int32_t *i32p;
+ bool_t rv;
+#else
+ int32_t *lp;
+ struct ieee_double id;
+ struct vax_double vd;
+ struct dbl_limits *lim;
+ u_int i;
+#endif
+
+ switch (xdrs->x_op) {
+
+ case XDR_ENCODE:
+#ifdef IEEEFP
+ i32p = (int32_t *)(void *)dp;
+#if BYTE_ORDER == BIG_ENDIAN
+ rv = XDR_PUTINT32(xdrs, i32p);
+ if (!rv)
+ return (rv);
+ rv = XDR_PUTINT32(xdrs, i32p+1);
+#else
+ rv = XDR_PUTINT32(xdrs, i32p+1);
+ if (!rv)
+ return (rv);
+ rv = XDR_PUTINT32(xdrs, i32p);
+#endif
+ return (rv);
+#else
+ vd = *((struct vax_double *)dp);
+ for (i = 0, lim = dbl_limits; i < nitems(dbl_limits);
+ i++, lim++) {
+ if ((vd.mantissa4 == lim->d.mantissa4) &&
+ (vd.mantissa3 == lim->d.mantissa3) &&
+ (vd.mantissa2 == lim->d.mantissa2) &&
+ (vd.mantissa1 == lim->d.mantissa1) &&
+ (vd.exp == lim->d.exp)) {
+ id = lim->ieee;
+ goto shipit;
+ }
+ }
+ id.exp = vd.exp - VAX_DBL_BIAS + IEEE_DBL_BIAS;
+ id.mantissa1 = (vd.mantissa1 << 13) | (vd.mantissa2 >> 3);
+ id.mantissa2 = ((vd.mantissa2 & MASK(3)) << 29) |
+ (vd.mantissa3 << 13) |
+ ((vd.mantissa4 >> 3) & MASK(13));
+ shipit:
+ id.sign = vd.sign;
+ lp = (int32_t *)&id;
+ return (XDR_PUTINT32(xdrs, lp++) && XDR_PUTINT32(xdrs, lp));
+#endif
+
+ case XDR_DECODE:
+#ifdef IEEEFP
+ i32p = (int32_t *)(void *)dp;
+#if BYTE_ORDER == BIG_ENDIAN
+ rv = XDR_GETINT32(xdrs, i32p);
+ if (!rv)
+ return (rv);
+ rv = XDR_GETINT32(xdrs, i32p+1);
+#else
+ rv = XDR_GETINT32(xdrs, i32p+1);
+ if (!rv)
+ return (rv);
+ rv = XDR_GETINT32(xdrs, i32p);
+#endif
+ return (rv);
+#else
+ lp = (int32_t *)&id;
+ if (!XDR_GETINT32(xdrs, lp++) || !XDR_GETINT32(xdrs, lp))
+ return (FALSE);
+ for (i = 0, lim = dbl_limits; i < nitems(dbl_limits);
+ i++, lim++) {
+ if ((id.mantissa2 == lim->ieee.mantissa2) &&
+ (id.mantissa1 == lim->ieee.mantissa1) &&
+ (id.exp == lim->ieee.exp)) {
+ vd = lim->d;
+ goto doneit;
+ }
+ }
+ vd.exp = id.exp - IEEE_DBL_BIAS + VAX_DBL_BIAS;
+ vd.mantissa1 = (id.mantissa1 >> 13);
+ vd.mantissa2 = ((id.mantissa1 & MASK(13)) << 3) |
+ (id.mantissa2 >> 29);
+ vd.mantissa3 = (id.mantissa2 >> 13);
+ vd.mantissa4 = (id.mantissa2 << 3);
+ doneit:
+ vd.sign = id.sign;
+ *dp = *((double *)&vd);
+ return (TRUE);
+#endif
+
+ case XDR_FREE:
+ return (TRUE);
+ }
+ /* NOTREACHED */
+ return (FALSE);
+}
diff --git a/lib/libc/xdr/xdr_mem.c b/lib/libc/xdr/xdr_mem.c
new file mode 100644
index 000000000000..ecefb2ec38db
--- /dev/null
+++ b/lib/libc/xdr/xdr_mem.c
@@ -0,0 +1,234 @@
+/* $NetBSD: xdr_mem.c,v 1.15 2000/01/22 22:19:18 mycroft Exp $ */
+
+/*-
+ * Copyright (c) 2010, Oracle America, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ * * Neither the name of the "Oracle America, Inc." nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *sccsid2 = "@(#)xdr_mem.c 1.19 87/08/11 Copyr 1984 Sun Micro";
+static char *sccsid = "@(#)xdr_mem.c 2.1 88/07/29 4.0 RPCSRC";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * xdr_mem.h, XDR implementation using memory buffers.
+ *
+ * If you have some data to be interpreted as external data representation
+ * or to be converted to external data representation in a memory buffer,
+ * then this is the package for you.
+ *
+ */
+
+#include "namespace.h"
+#include <sys/types.h>
+
+#include <netinet/in.h>
+
+#include <string.h>
+
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#include "un-namespace.h"
+
+static void xdrmem_destroy(XDR *);
+static bool_t xdrmem_getlong_aligned(XDR *, long *);
+static bool_t xdrmem_putlong_aligned(XDR *, const long *);
+static bool_t xdrmem_getlong_unaligned(XDR *, long *);
+static bool_t xdrmem_putlong_unaligned(XDR *, const long *);
+static bool_t xdrmem_getbytes(XDR *, char *, u_int);
+static bool_t xdrmem_putbytes(XDR *, const char *, u_int);
+/* XXX: w/64-bit pointers, u_int not enough! */
+static u_int xdrmem_getpos(XDR *);
+static bool_t xdrmem_setpos(XDR *, u_int);
+static int32_t *xdrmem_inline_aligned(XDR *, u_int);
+static int32_t *xdrmem_inline_unaligned(XDR *, u_int);
+
+static const struct xdr_ops xdrmem_ops_aligned = {
+ xdrmem_getlong_aligned,
+ xdrmem_putlong_aligned,
+ xdrmem_getbytes,
+ xdrmem_putbytes,
+ xdrmem_getpos,
+ xdrmem_setpos,
+ xdrmem_inline_aligned,
+ xdrmem_destroy
+};
+
+static const struct xdr_ops xdrmem_ops_unaligned = {
+ xdrmem_getlong_unaligned,
+ xdrmem_putlong_unaligned,
+ xdrmem_getbytes,
+ xdrmem_putbytes,
+ xdrmem_getpos,
+ xdrmem_setpos,
+ xdrmem_inline_unaligned,
+ xdrmem_destroy
+};
+
+/*
+ * The procedure xdrmem_create initializes a stream descriptor for a
+ * memory buffer.
+ */
+void
+xdrmem_create(XDR *xdrs, char *addr, u_int size, enum xdr_op op)
+{
+
+ xdrs->x_op = op;
+ xdrs->x_ops = ((unsigned long)addr & (sizeof(int32_t) - 1))
+ ? &xdrmem_ops_unaligned : &xdrmem_ops_aligned;
+ xdrs->x_private = xdrs->x_base = addr;
+ xdrs->x_handy = size;
+}
+
+/*ARGSUSED*/
+static void
+xdrmem_destroy(XDR *xdrs)
+{
+
+}
+
+static bool_t
+xdrmem_getlong_aligned(XDR *xdrs, long *lp)
+{
+
+ if (xdrs->x_handy < sizeof(int32_t))
+ return (FALSE);
+ xdrs->x_handy -= sizeof(int32_t);
+ *lp = ntohl(*(u_int32_t *)xdrs->x_private);
+ xdrs->x_private = (char *)xdrs->x_private + sizeof(int32_t);
+ return (TRUE);
+}
+
+static bool_t
+xdrmem_putlong_aligned(XDR *xdrs, const long *lp)
+{
+
+ if (xdrs->x_handy < sizeof(int32_t))
+ return (FALSE);
+ xdrs->x_handy -= sizeof(int32_t);
+ *(u_int32_t *)xdrs->x_private = htonl((u_int32_t)*lp);
+ xdrs->x_private = (char *)xdrs->x_private + sizeof(int32_t);
+ return (TRUE);
+}
+
+static bool_t
+xdrmem_getlong_unaligned(XDR *xdrs, long *lp)
+{
+ u_int32_t l;
+
+ if (xdrs->x_handy < sizeof(int32_t))
+ return (FALSE);
+ xdrs->x_handy -= sizeof(int32_t);
+ memmove(&l, xdrs->x_private, sizeof(int32_t));
+ *lp = ntohl(l);
+ xdrs->x_private = (char *)xdrs->x_private + sizeof(int32_t);
+ return (TRUE);
+}
+
+static bool_t
+xdrmem_putlong_unaligned(XDR *xdrs, const long *lp)
+{
+ u_int32_t l;
+
+ if (xdrs->x_handy < sizeof(int32_t))
+ return (FALSE);
+ xdrs->x_handy -= sizeof(int32_t);
+ l = htonl((u_int32_t)*lp);
+ memmove(xdrs->x_private, &l, sizeof(int32_t));
+ xdrs->x_private = (char *)xdrs->x_private + sizeof(int32_t);
+ return (TRUE);
+}
+
+static bool_t
+xdrmem_getbytes(XDR *xdrs, char *addr, u_int len)
+{
+
+ if (xdrs->x_handy < len)
+ return (FALSE);
+ xdrs->x_handy -= len;
+ memmove(addr, xdrs->x_private, len);
+ xdrs->x_private = (char *)xdrs->x_private + len;
+ return (TRUE);
+}
+
+static bool_t
+xdrmem_putbytes(XDR *xdrs, const char *addr, u_int len)
+{
+
+ if (xdrs->x_handy < len)
+ return (FALSE);
+ xdrs->x_handy -= len;
+ memmove(xdrs->x_private, addr, len);
+ xdrs->x_private = (char *)xdrs->x_private + len;
+ return (TRUE);
+}
+
+static u_int
+xdrmem_getpos(XDR *xdrs)
+{
+
+ /* XXX w/64-bit pointers, u_int not enough! */
+ return (u_int)((u_long)xdrs->x_private - (u_long)xdrs->x_base);
+}
+
+static bool_t
+xdrmem_setpos(XDR *xdrs, u_int pos)
+{
+ char *newaddr = xdrs->x_base + pos;
+ char *lastaddr = (char *)xdrs->x_private + xdrs->x_handy;
+
+ if (newaddr > lastaddr)
+ return (FALSE);
+ xdrs->x_private = newaddr;
+ xdrs->x_handy = (u_int)(lastaddr - newaddr); /* XXX sizeof(u_int) <? sizeof(ptrdiff_t) */
+ return (TRUE);
+}
+
+static int32_t *
+xdrmem_inline_aligned(XDR *xdrs, u_int len)
+{
+ int32_t *buf = NULL;
+
+ if (xdrs->x_handy >= len) {
+ xdrs->x_handy -= len;
+ buf = (int32_t *)xdrs->x_private;
+ xdrs->x_private = (char *)xdrs->x_private + len;
+ }
+ return (buf);
+}
+
+/* ARGSUSED */
+static int32_t *
+xdrmem_inline_unaligned(XDR *xdrs, u_int len)
+{
+
+ return (0);
+}
diff --git a/lib/libc/xdr/xdr_rec.c b/lib/libc/xdr/xdr_rec.c
new file mode 100644
index 000000000000..f818ed94b122
--- /dev/null
+++ b/lib/libc/xdr/xdr_rec.c
@@ -0,0 +1,761 @@
+/* $NetBSD: xdr_rec.c,v 1.18 2000/07/06 03:10:35 christos Exp $ */
+
+/*-
+ * Copyright (c) 2010, Oracle America, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ * * Neither the name of the "Oracle America, Inc." nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *sccsid2 = "@(#)xdr_rec.c 1.21 87/08/11 Copyr 1984 Sun Micro";
+static char *sccsid = "@(#)xdr_rec.c 2.2 88/08/01 4.0 RPCSRC";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * xdr_rec.c, Implements TCP/IP based XDR streams with a "record marking"
+ * layer above tcp (for rpc's use).
+ *
+ * These routines interface XDRSTREAMS to a tcp/ip connection.
+ * There is a record marking layer between the xdr stream
+ * and the tcp transport level. A record is composed on one or more
+ * record fragments. A record fragment is a thirty-two bit header followed
+ * by n bytes of data, where n is contained in the header. The header
+ * is represented as a htonl(u_long). Thegh order bit encodes
+ * whether or not the fragment is the last fragment of the record
+ * (1 => fragment is last, 0 => more fragments to follow.
+ * The other 31 bits encode the byte length of the fragment.
+ */
+
+#include "namespace.h"
+#include <sys/types.h>
+
+#include <netinet/in.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#include <rpc/auth.h>
+#include <rpc/svc.h>
+#include <rpc/clnt.h>
+#include <sys/stddef.h>
+#include "un-namespace.h"
+#include "rpc_com.h"
+
+static bool_t xdrrec_getlong(XDR *, long *);
+static bool_t xdrrec_putlong(XDR *, const long *);
+static bool_t xdrrec_getbytes(XDR *, char *, u_int);
+
+static bool_t xdrrec_putbytes(XDR *, const char *, u_int);
+static u_int xdrrec_getpos(XDR *);
+static bool_t xdrrec_setpos(XDR *, u_int);
+static int32_t *xdrrec_inline(XDR *, u_int);
+static void xdrrec_destroy(XDR *);
+
+static const struct xdr_ops xdrrec_ops = {
+ xdrrec_getlong,
+ xdrrec_putlong,
+ xdrrec_getbytes,
+ xdrrec_putbytes,
+ xdrrec_getpos,
+ xdrrec_setpos,
+ xdrrec_inline,
+ xdrrec_destroy
+};
+
+/*
+ * A record is composed of one or more record fragments.
+ * A record fragment is a four-byte header followed by zero to
+ * 2**32-1 bytes. The header is treated as a long unsigned and is
+ * encode/decoded to the network via htonl/ntohl. The low order 31 bits
+ * are a byte count of the fragment. The highest order bit is a boolean:
+ * 1 => this fragment is the last fragment of the record,
+ * 0 => this fragment is followed by more fragment(s).
+ *
+ * The fragment/record machinery is not general; it is constructed to
+ * meet the needs of xdr and rpc based on tcp.
+ */
+
+#define LAST_FRAG ((u_int32_t)(1U << 31))
+
+typedef struct rec_strm {
+ char *tcp_handle;
+ /*
+ * out-goung bits
+ */
+ int (*writeit)(void *, void *, int);
+ char *out_base; /* output buffer (points to frag header) */
+ char *out_finger; /* next output position */
+ char *out_boundry; /* data cannot up to this address */
+ u_int32_t *frag_header; /* beginning of curren fragment */
+ bool_t frag_sent; /* true if buffer sent in middle of record */
+ /*
+ * in-coming bits
+ */
+ int (*readit)(void *, void *, int);
+ u_long in_size; /* fixed size of the input buffer */
+ char *in_base;
+ char *in_finger; /* location of next byte to be had */
+ char *in_boundry; /* can read up to this location */
+ long fbtbc; /* fragment bytes to be consumed */
+ bool_t last_frag;
+ u_int sendsize;
+ u_int recvsize;
+
+ bool_t nonblock;
+ bool_t in_haveheader;
+ u_int32_t in_header;
+ char *in_hdrp;
+ int in_hdrlen;
+ int in_reclen;
+ int in_received;
+ int in_maxrec;
+} RECSTREAM;
+
+static u_int fix_buf_size(u_int);
+static bool_t flush_out(RECSTREAM *, bool_t);
+static bool_t fill_input_buf(RECSTREAM *);
+static bool_t get_input_bytes(RECSTREAM *, char *, int);
+static bool_t set_input_fragment(RECSTREAM *);
+static bool_t skip_input_bytes(RECSTREAM *, long);
+static bool_t realloc_stream(RECSTREAM *, int);
+
+
+/*
+ * Create an xdr handle for xdrrec
+ * xdrrec_create fills in xdrs. Sendsize and recvsize are
+ * send and recv buffer sizes (0 => use default).
+ * tcp_handle is an opaque handle that is passed as the first parameter to
+ * the procedures readit and writeit. Readit and writeit are read and
+ * write respectively. They are like the system
+ * calls expect that they take an opaque handle rather than an fd.
+ */
+void
+xdrrec_create(XDR *xdrs, u_int sendsize, u_int recvsize, void *tcp_handle,
+ int (*readit)(void *, void *, int), int (*writeit)(void *, void *, int))
+/*
+ * XDR *xdrs;
+ * u_int sendsize;
+ * u_int recvsize;
+ * void *tcp_handle;
+ * // like read, but pass it a tcp_handle, not sock
+ * int (*readit)(void *, void *, int);
+ * // like write, but pass it a tcp_handle, not sock
+ * int (*writeit)(void *, void *, int);
+ */
+{
+ RECSTREAM *rstrm = mem_alloc(sizeof(RECSTREAM));
+
+ if (rstrm == NULL) {
+ warnx("xdrrec_create: out of memory");
+ /*
+ * This is bad. Should rework xdrrec_create to
+ * return a handle, and in this case return NULL
+ */
+ return;
+ }
+ rstrm->sendsize = sendsize = fix_buf_size(sendsize);
+ rstrm->out_base = mem_alloc(rstrm->sendsize);
+ if (rstrm->out_base == NULL) {
+ warnx("xdrrec_create: out of memory");
+ mem_free(rstrm, sizeof(RECSTREAM));
+ return;
+ }
+ rstrm->recvsize = recvsize = fix_buf_size(recvsize);
+ rstrm->in_base = mem_alloc(recvsize);
+ if (rstrm->in_base == NULL) {
+ warnx("xdrrec_create: out of memory");
+ mem_free(rstrm->out_base, sendsize);
+ mem_free(rstrm, sizeof(RECSTREAM));
+ return;
+ }
+ /*
+ * now the rest ...
+ */
+ xdrs->x_ops = &xdrrec_ops;
+ xdrs->x_private = rstrm;
+ rstrm->tcp_handle = tcp_handle;
+ rstrm->readit = readit;
+ rstrm->writeit = writeit;
+ rstrm->out_finger = rstrm->out_boundry = rstrm->out_base;
+ rstrm->frag_header = (u_int32_t *)(void *)rstrm->out_base;
+ rstrm->out_finger += sizeof(u_int32_t);
+ rstrm->out_boundry += sendsize;
+ rstrm->frag_sent = FALSE;
+ rstrm->in_size = recvsize;
+ rstrm->in_boundry = rstrm->in_base;
+ rstrm->in_finger = (rstrm->in_boundry += recvsize);
+ rstrm->fbtbc = 0;
+ rstrm->last_frag = TRUE;
+ rstrm->in_haveheader = FALSE;
+ rstrm->in_hdrlen = 0;
+ rstrm->in_hdrp = (char *)(void *)&rstrm->in_header;
+ rstrm->nonblock = FALSE;
+ rstrm->in_reclen = 0;
+ rstrm->in_received = 0;
+}
+
+
+/*
+ * The reoutines defined below are the xdr ops which will go into the
+ * xdr handle filled in by xdrrec_create.
+ */
+
+static bool_t
+xdrrec_getlong(XDR *xdrs, long *lp)
+{
+ RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
+ int32_t *buflp = (int32_t *)(void *)(rstrm->in_finger);
+ int32_t mylong;
+
+ /* first try the inline, fast case */
+ if ((rstrm->fbtbc >= sizeof(int32_t)) &&
+ (((long)rstrm->in_boundry - (long)buflp) >= sizeof(int32_t))) {
+ *lp = (long)ntohl((u_int32_t)(*buflp));
+ rstrm->fbtbc -= sizeof(int32_t);
+ rstrm->in_finger += sizeof(int32_t);
+ } else {
+ if (! xdrrec_getbytes(xdrs, (char *)(void *)&mylong,
+ sizeof(int32_t)))
+ return (FALSE);
+ *lp = (long)ntohl((u_int32_t)mylong);
+ }
+ return (TRUE);
+}
+
+static bool_t
+xdrrec_putlong(XDR *xdrs, const long *lp)
+{
+ RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
+ int32_t *dest_lp = ((int32_t *)(void *)(rstrm->out_finger));
+
+ if ((rstrm->out_finger += sizeof(int32_t)) > rstrm->out_boundry) {
+ /*
+ * this case should almost never happen so the code is
+ * inefficient
+ */
+ rstrm->out_finger -= sizeof(int32_t);
+ rstrm->frag_sent = TRUE;
+ if (! flush_out(rstrm, FALSE))
+ return (FALSE);
+ dest_lp = ((int32_t *)(void *)(rstrm->out_finger));
+ rstrm->out_finger += sizeof(int32_t);
+ }
+ *dest_lp = (int32_t)htonl((u_int32_t)(*lp));
+ return (TRUE);
+}
+
+static bool_t /* must manage buffers, fragments, and records */
+xdrrec_getbytes(XDR *xdrs, char *addr, u_int len)
+{
+ RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
+ int current;
+
+ while (len > 0) {
+ current = (int)rstrm->fbtbc;
+ if (current == 0) {
+ if (rstrm->last_frag)
+ return (FALSE);
+ if (! set_input_fragment(rstrm))
+ return (FALSE);
+ continue;
+ }
+ current = (len < current) ? len : current;
+ if (! get_input_bytes(rstrm, addr, current))
+ return (FALSE);
+ addr += current;
+ rstrm->fbtbc -= current;
+ len -= current;
+ }
+ return (TRUE);
+}
+
+static bool_t
+xdrrec_putbytes(XDR *xdrs, const char *addr, u_int len)
+{
+ RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
+ size_t current;
+
+ while (len > 0) {
+ current = (size_t)((u_long)rstrm->out_boundry -
+ (u_long)rstrm->out_finger);
+ current = (len < current) ? len : current;
+ memmove(rstrm->out_finger, addr, current);
+ rstrm->out_finger += current;
+ addr += current;
+ len -= current;
+ if (rstrm->out_finger == rstrm->out_boundry) {
+ rstrm->frag_sent = TRUE;
+ if (! flush_out(rstrm, FALSE))
+ return (FALSE);
+ }
+ }
+ return (TRUE);
+}
+
+static u_int
+xdrrec_getpos(XDR *xdrs)
+{
+ RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private;
+ off_t pos;
+
+ pos = lseek((int)(u_long)rstrm->tcp_handle, (off_t)0, 1);
+ if (pos == -1)
+ pos = 0;
+ switch (xdrs->x_op) {
+
+ case XDR_ENCODE:
+ pos += rstrm->out_finger - rstrm->out_base;
+ break;
+
+ case XDR_DECODE:
+ pos -= rstrm->in_boundry - rstrm->in_finger;
+ break;
+
+ default:
+ pos = (off_t) -1;
+ break;
+ }
+ return ((u_int) pos);
+}
+
+static bool_t
+xdrrec_setpos(XDR *xdrs, u_int pos)
+{
+ RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private;
+ u_int currpos = xdrrec_getpos(xdrs);
+ int delta = currpos - pos;
+ char *newpos;
+
+ if ((int)currpos != -1)
+ switch (xdrs->x_op) {
+
+ case XDR_ENCODE:
+ newpos = rstrm->out_finger - delta;
+ if ((newpos > (char *)(void *)(rstrm->frag_header)) &&
+ (newpos < rstrm->out_boundry)) {
+ rstrm->out_finger = newpos;
+ return (TRUE);
+ }
+ break;
+
+ case XDR_DECODE:
+ newpos = rstrm->in_finger - delta;
+ if ((delta < (int)(rstrm->fbtbc)) &&
+ (newpos <= rstrm->in_boundry) &&
+ (newpos >= rstrm->in_base)) {
+ rstrm->in_finger = newpos;
+ rstrm->fbtbc -= delta;
+ return (TRUE);
+ }
+ break;
+
+ case XDR_FREE:
+ break;
+ }
+ return (FALSE);
+}
+
+static int32_t *
+xdrrec_inline(XDR *xdrs, u_int len)
+{
+ RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private;
+ int32_t *buf = NULL;
+
+ switch (xdrs->x_op) {
+
+ case XDR_ENCODE:
+ if ((rstrm->out_finger + len) <= rstrm->out_boundry) {
+ buf = (int32_t *)(void *)rstrm->out_finger;
+ rstrm->out_finger += len;
+ }
+ break;
+
+ case XDR_DECODE:
+ if ((len <= rstrm->fbtbc) &&
+ ((rstrm->in_finger + len) <= rstrm->in_boundry)) {
+ buf = (int32_t *)(void *)rstrm->in_finger;
+ rstrm->fbtbc -= len;
+ rstrm->in_finger += len;
+ }
+ break;
+
+ case XDR_FREE:
+ break;
+ }
+ return (buf);
+}
+
+static void
+xdrrec_destroy(XDR *xdrs)
+{
+ RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private;
+
+ mem_free(rstrm->out_base, rstrm->sendsize);
+ mem_free(rstrm->in_base, rstrm->recvsize);
+ mem_free(rstrm, sizeof(RECSTREAM));
+}
+
+
+/*
+ * Exported routines to manage xdr records
+ */
+
+/*
+ * Before reading (deserializing from the stream, one should always call
+ * this procedure to guarantee proper record alignment.
+ */
+bool_t
+xdrrec_skiprecord(XDR *xdrs)
+{
+ RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
+ enum xprt_stat xstat;
+
+ if (rstrm->nonblock) {
+ if (__xdrrec_getrec(xdrs, &xstat, FALSE)) {
+ rstrm->fbtbc = 0;
+ return TRUE;
+ }
+ if (rstrm->in_finger == rstrm->in_boundry &&
+ xstat == XPRT_MOREREQS) {
+ rstrm->fbtbc = 0;
+ return TRUE;
+ }
+ return FALSE;
+ }
+
+ while (rstrm->fbtbc > 0 || (! rstrm->last_frag)) {
+ if (! skip_input_bytes(rstrm, rstrm->fbtbc))
+ return (FALSE);
+ rstrm->fbtbc = 0;
+ if ((! rstrm->last_frag) && (! set_input_fragment(rstrm)))
+ return (FALSE);
+ }
+ rstrm->last_frag = FALSE;
+ return (TRUE);
+}
+
+/*
+ * Look ahead function.
+ * Returns TRUE iff there is no more input in the buffer
+ * after consuming the rest of the current record.
+ */
+bool_t
+xdrrec_eof(XDR *xdrs)
+{
+ RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
+
+ while (rstrm->fbtbc > 0 || (! rstrm->last_frag)) {
+ if (! skip_input_bytes(rstrm, rstrm->fbtbc))
+ return (TRUE);
+ rstrm->fbtbc = 0;
+ if ((! rstrm->last_frag) && (! set_input_fragment(rstrm)))
+ return (TRUE);
+ }
+ if (rstrm->in_finger == rstrm->in_boundry)
+ return (TRUE);
+ return (FALSE);
+}
+
+/*
+ * The client must tell the package when an end-of-record has occurred.
+ * The second paraemters tells whether the record should be flushed to the
+ * (output) tcp stream. (This let's the package support batched or
+ * pipelined procedure calls.) TRUE => immmediate flush to tcp connection.
+ */
+bool_t
+xdrrec_endofrecord(XDR *xdrs, bool_t sendnow)
+{
+ RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
+ u_long len; /* fragment length */
+
+ if (sendnow || rstrm->frag_sent ||
+ ((u_long)rstrm->out_finger + sizeof(u_int32_t) >=
+ (u_long)rstrm->out_boundry)) {
+ rstrm->frag_sent = FALSE;
+ return (flush_out(rstrm, TRUE));
+ }
+ len = (u_long)(rstrm->out_finger) - (u_long)(rstrm->frag_header) -
+ sizeof(u_int32_t);
+ *(rstrm->frag_header) = htonl((u_int32_t)len | LAST_FRAG);
+ rstrm->frag_header = (u_int32_t *)(void *)rstrm->out_finger;
+ rstrm->out_finger += sizeof(u_int32_t);
+ return (TRUE);
+}
+
+/*
+ * Fill the stream buffer with a record for a non-blocking connection.
+ * Return true if a record is available in the buffer, false if not.
+ */
+bool_t
+__xdrrec_getrec(XDR *xdrs, enum xprt_stat *statp, bool_t expectdata)
+{
+ RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
+ ssize_t n;
+ int fraglen;
+
+ if (!rstrm->in_haveheader) {
+ n = rstrm->readit(rstrm->tcp_handle, rstrm->in_hdrp,
+ (int)sizeof (rstrm->in_header) - rstrm->in_hdrlen);
+ if (n == 0) {
+ *statp = expectdata ? XPRT_DIED : XPRT_IDLE;
+ return FALSE;
+ }
+ if (n < 0) {
+ *statp = XPRT_DIED;
+ return FALSE;
+ }
+ rstrm->in_hdrp += n;
+ rstrm->in_hdrlen += n;
+ if (rstrm->in_hdrlen < sizeof (rstrm->in_header)) {
+ *statp = XPRT_MOREREQS;
+ return FALSE;
+ }
+ rstrm->in_header = ntohl(rstrm->in_header);
+ fraglen = (int)(rstrm->in_header & ~LAST_FRAG);
+ if (fraglen == 0 || fraglen > rstrm->in_maxrec ||
+ (rstrm->in_reclen + fraglen) > rstrm->in_maxrec) {
+ *statp = XPRT_DIED;
+ return FALSE;
+ }
+ rstrm->in_reclen += fraglen;
+ if (rstrm->in_reclen > rstrm->recvsize)
+ realloc_stream(rstrm, rstrm->in_reclen);
+ if (rstrm->in_header & LAST_FRAG) {
+ rstrm->in_header &= ~LAST_FRAG;
+ rstrm->last_frag = TRUE;
+ }
+ /*
+ * We can only reasonably expect to read once from a
+ * non-blocking stream. Reading the fragment header
+ * may have drained the stream.
+ */
+ expectdata = FALSE;
+ }
+
+ n = rstrm->readit(rstrm->tcp_handle,
+ rstrm->in_base + rstrm->in_received,
+ (rstrm->in_reclen - rstrm->in_received));
+
+ if (n < 0) {
+ *statp = XPRT_DIED;
+ return FALSE;
+ }
+
+ if (n == 0) {
+ *statp = expectdata ? XPRT_DIED : XPRT_IDLE;
+ return FALSE;
+ }
+
+ rstrm->in_received += n;
+
+ if (rstrm->in_received == rstrm->in_reclen) {
+ rstrm->in_haveheader = FALSE;
+ rstrm->in_hdrp = (char *)(void *)&rstrm->in_header;
+ rstrm->in_hdrlen = 0;
+ if (rstrm->last_frag) {
+ rstrm->fbtbc = rstrm->in_reclen;
+ rstrm->in_boundry = rstrm->in_base + rstrm->in_reclen;
+ rstrm->in_finger = rstrm->in_base;
+ rstrm->in_reclen = rstrm->in_received = 0;
+ *statp = XPRT_MOREREQS;
+ return TRUE;
+ }
+ }
+
+ *statp = XPRT_MOREREQS;
+ return FALSE;
+}
+
+bool_t
+__xdrrec_setnonblock(XDR *xdrs, int maxrec)
+{
+ RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
+
+ rstrm->nonblock = TRUE;
+ if (maxrec == 0)
+ maxrec = rstrm->recvsize;
+ rstrm->in_maxrec = maxrec;
+ return TRUE;
+}
+
+/*
+ * Internal useful routines
+ */
+static bool_t
+flush_out(RECSTREAM *rstrm, bool_t eor)
+{
+ u_int32_t eormask = (eor == TRUE) ? LAST_FRAG : 0;
+ u_int32_t len = (u_int32_t)((u_long)(rstrm->out_finger) -
+ (u_long)(rstrm->frag_header) - sizeof(u_int32_t));
+
+ *(rstrm->frag_header) = htonl(len | eormask);
+ len = (u_int32_t)((u_long)(rstrm->out_finger) -
+ (u_long)(rstrm->out_base));
+ if ((*(rstrm->writeit))(rstrm->tcp_handle, rstrm->out_base, (int)len)
+ != (int)len)
+ return (FALSE);
+ rstrm->frag_header = (u_int32_t *)(void *)rstrm->out_base;
+ rstrm->out_finger = (char *)rstrm->out_base + sizeof(u_int32_t);
+ return (TRUE);
+}
+
+static bool_t /* knows nothing about records! Only about input buffers */
+fill_input_buf(RECSTREAM *rstrm)
+{
+ char *where;
+ u_int32_t i;
+ int len;
+
+ if (rstrm->nonblock)
+ return FALSE;
+
+ where = rstrm->in_base;
+ i = (u_int32_t)((u_long)rstrm->in_boundry % BYTES_PER_XDR_UNIT);
+ where += i;
+ len = (u_int32_t)(rstrm->in_size - i);
+ if ((len = (*(rstrm->readit))(rstrm->tcp_handle, where, len)) == -1)
+ return (FALSE);
+ rstrm->in_finger = where;
+ where += len;
+ rstrm->in_boundry = where;
+ return (TRUE);
+}
+
+static bool_t /* knows nothing about records! Only about input buffers */
+get_input_bytes(RECSTREAM *rstrm, char *addr, int len)
+{
+ size_t current;
+
+ if (rstrm->nonblock) {
+ if (len > (int)(rstrm->in_boundry - rstrm->in_finger))
+ return FALSE;
+ memcpy(addr, rstrm->in_finger, (size_t)len);
+ rstrm->in_finger += len;
+ return TRUE;
+ }
+
+ while (len > 0) {
+ current = (size_t)((long)rstrm->in_boundry -
+ (long)rstrm->in_finger);
+ if (current == 0) {
+ if (! fill_input_buf(rstrm))
+ return (FALSE);
+ continue;
+ }
+ current = (len < current) ? len : current;
+ memmove(addr, rstrm->in_finger, current);
+ rstrm->in_finger += current;
+ addr += current;
+ len -= current;
+ }
+ return (TRUE);
+}
+
+static bool_t /* next two bytes of the input stream are treated as a header */
+set_input_fragment(RECSTREAM *rstrm)
+{
+ u_int32_t header;
+
+ if (rstrm->nonblock)
+ return FALSE;
+ if (! get_input_bytes(rstrm, (char *)(void *)&header, sizeof(header)))
+ return (FALSE);
+ header = ntohl(header);
+ rstrm->last_frag = ((header & LAST_FRAG) == 0) ? FALSE : TRUE;
+ /*
+ * Sanity check. Try not to accept wildly incorrect
+ * record sizes. Unfortunately, the only record size
+ * we can positively identify as being 'wildly incorrect'
+ * is zero. Ridiculously large record sizes may look wrong,
+ * but we don't have any way to be certain that they aren't
+ * what the client actually intended to send us.
+ */
+ if (header == 0)
+ return(FALSE);
+ rstrm->fbtbc = header & (~LAST_FRAG);
+ return (TRUE);
+}
+
+static bool_t /* consumes input bytes; knows nothing about records! */
+skip_input_bytes(RECSTREAM *rstrm, long cnt)
+{
+ u_int32_t current;
+
+ while (cnt > 0) {
+ current = (size_t)((long)rstrm->in_boundry -
+ (long)rstrm->in_finger);
+ if (current == 0) {
+ if (! fill_input_buf(rstrm))
+ return (FALSE);
+ continue;
+ }
+ current = (u_int32_t)((cnt < current) ? cnt : current);
+ rstrm->in_finger += current;
+ cnt -= current;
+ }
+ return (TRUE);
+}
+
+static u_int
+fix_buf_size(u_int s)
+{
+
+ if (s < 100)
+ s = 4000;
+ return (RNDUP(s));
+}
+
+/*
+ * Reallocate the input buffer for a non-block stream.
+ */
+static bool_t
+realloc_stream(RECSTREAM *rstrm, int size)
+{
+ ptrdiff_t diff;
+ char *buf;
+
+ if (size > rstrm->recvsize) {
+ buf = realloc(rstrm->in_base, (size_t)size);
+ if (buf == NULL)
+ return FALSE;
+ diff = buf - rstrm->in_base;
+ rstrm->in_finger += diff;
+ rstrm->in_base = buf;
+ rstrm->in_boundry = buf + size;
+ rstrm->recvsize = size;
+ rstrm->in_size = size;
+ }
+
+ return TRUE;
+}
diff --git a/lib/libc/xdr/xdr_reference.c b/lib/libc/xdr/xdr_reference.c
new file mode 100644
index 000000000000..9acdd9640063
--- /dev/null
+++ b/lib/libc/xdr/xdr_reference.c
@@ -0,0 +1,141 @@
+/* $NetBSD: xdr_reference.c,v 1.13 2000/01/22 22:19:18 mycroft Exp $ */
+
+/*-
+ * Copyright (c) 2010, Oracle America, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ * * Neither the name of the "Oracle America, Inc." nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *sccsid2 = "@(#)xdr_reference.c 1.11 87/08/11 SMI";
+static char *sccsid = "@(#)xdr_reference.c 2.1 88/07/29 4.0 RPCSRC";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * xdr_reference.c, Generic XDR routines impelmentation.
+ *
+ * These are the "non-trivial" xdr primitives used to serialize and de-serialize
+ * "pointers". See xdr.h for more info on the interface to xdr.
+ */
+
+#include "namespace.h"
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#include "libc_private.h"
+
+/*
+ * XDR an indirect pointer
+ * xdr_reference is for recursively translating a structure that is
+ * referenced by a pointer inside the structure that is currently being
+ * translated. pp references a pointer to storage. If *pp is null
+ * the necessary storage is allocated.
+ * size is the sizeof the referneced structure.
+ * proc is the routine to handle the referenced structure.
+ */
+bool_t
+xdr_reference(XDR *xdrs, caddr_t *pp, u_int size, xdrproc_t proc)
+/*
+ * XDR *xdrs;
+ * caddr_t *pp; // the pointer to work on
+ * u_int size; // size of the object pointed to
+ * xdrproc_t proc; // xdr routine to handle the object
+ */
+{
+ caddr_t loc = *pp;
+ bool_t stat;
+
+ if (loc == NULL)
+ switch (xdrs->x_op) {
+ case XDR_FREE:
+ return (TRUE);
+
+ case XDR_DECODE:
+ *pp = loc = (caddr_t) mem_alloc(size);
+ if (loc == NULL) {
+ warnx("xdr_reference: out of memory");
+ return (FALSE);
+ }
+ memset(loc, 0, size);
+ break;
+
+ case XDR_ENCODE:
+ break;
+ }
+
+ stat = (*proc)(xdrs, loc);
+
+ if (xdrs->x_op == XDR_FREE) {
+ mem_free(loc, size);
+ *pp = NULL;
+ }
+ return (stat);
+}
+
+
+/*
+ * xdr_pointer():
+ *
+ * XDR a pointer to a possibly recursive data structure. This
+ * differs with xdr_reference in that it can serialize/deserialiaze
+ * trees correctly.
+ *
+ * What's sent is actually a union:
+ *
+ * union object_pointer switch (boolean b) {
+ * case TRUE: object_data data;
+ * case FALSE: void nothing;
+ * }
+ *
+ * > objpp: Pointer to the pointer to the object.
+ * > obj_size: size of the object.
+ * > xdr_obj: routine to XDR an object.
+ *
+ */
+bool_t
+xdr_pointer(XDR *xdrs, char **objpp, u_int obj_size, xdrproc_t xdr_obj)
+{
+
+ bool_t more_data;
+
+ more_data = (*objpp != NULL);
+ if (! xdr_bool(xdrs,&more_data)) {
+ return (FALSE);
+ }
+ if (! more_data) {
+ *objpp = NULL;
+ return (TRUE);
+ }
+ return (xdr_reference(xdrs,objpp,obj_size,xdr_obj));
+}
diff --git a/lib/libc/xdr/xdr_sizeof.c b/lib/libc/xdr/xdr_sizeof.c
new file mode 100644
index 000000000000..f4b287449e9f
--- /dev/null
+++ b/lib/libc/xdr/xdr_sizeof.c
@@ -0,0 +1,155 @@
+/*-
+ * Copyright (c) 2010, Oracle America, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ * * Neither the name of the "Oracle America, Inc." nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * xdr_sizeof.c
+ *
+ * General purpose routine to see how much space something will use
+ * when serialized using XDR.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include "un-namespace.h"
+
+/* ARGSUSED */
+static bool_t
+x_putlong(XDR *xdrs, const long *longp)
+{
+ xdrs->x_handy += BYTES_PER_XDR_UNIT;
+ return (TRUE);
+}
+
+/* ARGSUSED */
+static bool_t
+x_putbytes(XDR *xdrs, const char *bp, u_int len)
+{
+ xdrs->x_handy += len;
+ return (TRUE);
+}
+
+static u_int
+x_getpostn(XDR *xdrs)
+{
+ return (xdrs->x_handy);
+}
+
+/* ARGSUSED */
+static bool_t
+x_setpostn(XDR *xdrs, u_int pos)
+{
+ /* This is not allowed */
+ return (FALSE);
+}
+
+static int32_t *
+x_inline(XDR *xdrs, u_int len)
+{
+ if (len == 0) {
+ return (NULL);
+ }
+ if (xdrs->x_op != XDR_ENCODE) {
+ return (NULL);
+ }
+ if (len < (u_int)(uintptr_t)xdrs->x_base) {
+ /* x_private was already allocated */
+ xdrs->x_handy += len;
+ return ((int32_t *) xdrs->x_private);
+ } else {
+ /* Free the earlier space and allocate new area */
+ if (xdrs->x_private)
+ free(xdrs->x_private);
+ if ((xdrs->x_private = (caddr_t) malloc(len)) == NULL) {
+ xdrs->x_base = 0;
+ return (NULL);
+ }
+ xdrs->x_base = (caddr_t)(uintptr_t)len;
+ xdrs->x_handy += len;
+ return ((int32_t *) xdrs->x_private);
+ }
+}
+
+static int
+harmless(void)
+{
+ /* Always return FALSE/NULL, as the case may be */
+ return (0);
+}
+
+static void
+x_destroy(XDR *xdrs)
+{
+ xdrs->x_handy = 0;
+ xdrs->x_base = 0;
+ if (xdrs->x_private) {
+ free(xdrs->x_private);
+ xdrs->x_private = NULL;
+ }
+ return;
+}
+
+unsigned long
+xdr_sizeof(xdrproc_t func, void *data)
+{
+ XDR x;
+ struct xdr_ops ops;
+ bool_t stat;
+ /* to stop ANSI-C compiler from complaining */
+ typedef bool_t (* dummyfunc1)(XDR *, long *);
+ typedef bool_t (* dummyfunc2)(XDR *, caddr_t, u_int);
+
+ ops.x_putlong = x_putlong;
+ ops.x_putbytes = x_putbytes;
+ ops.x_inline = x_inline;
+ ops.x_getpostn = x_getpostn;
+ ops.x_setpostn = x_setpostn;
+ ops.x_destroy = x_destroy;
+
+ /* the other harmless ones */
+ ops.x_getlong = (dummyfunc1) harmless;
+ ops.x_getbytes = (dummyfunc2) harmless;
+
+ x.x_op = XDR_ENCODE;
+ x.x_ops = &ops;
+ x.x_handy = 0;
+ x.x_private = (caddr_t) NULL;
+ x.x_base = (caddr_t) 0;
+
+ stat = func(&x, data);
+ if (x.x_private)
+ free(x.x_private);
+ return (stat == TRUE ? (unsigned) x.x_handy: 0);
+}
diff --git a/lib/libc/xdr/xdr_stdio.c b/lib/libc/xdr/xdr_stdio.c
new file mode 100644
index 000000000000..0065154a0cd7
--- /dev/null
+++ b/lib/libc/xdr/xdr_stdio.c
@@ -0,0 +1,177 @@
+/* $NetBSD: xdr_stdio.c,v 1.14 2000/01/22 22:19:19 mycroft Exp $ */
+
+/*-
+ * Copyright (c) 2010, Oracle America, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ * * Neither the name of the "Oracle America, Inc." nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *sccsid2 = "@(#)xdr_stdio.c 1.16 87/08/11 Copyr 1984 Sun Micro";
+static char *sccsid = "@(#)xdr_stdio.c 2.1 88/07/29 4.0 RPCSRC";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * xdr_stdio.c, XDR implementation on standard i/o file.
+ *
+ * This set of routines implements a XDR on a stdio stream.
+ * XDR_ENCODE serializes onto the stream, XDR_DECODE de-serializes
+ * from the stream.
+ */
+
+#include "namespace.h"
+#include <stdio.h>
+
+#include <arpa/inet.h>
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#include "un-namespace.h"
+
+static void xdrstdio_destroy(XDR *);
+static bool_t xdrstdio_getlong(XDR *, long *);
+static bool_t xdrstdio_putlong(XDR *, const long *);
+static bool_t xdrstdio_getbytes(XDR *, char *, u_int);
+static bool_t xdrstdio_putbytes(XDR *, const char *, u_int);
+static u_int xdrstdio_getpos(XDR *);
+static bool_t xdrstdio_setpos(XDR *, u_int);
+static int32_t *xdrstdio_inline(XDR *, u_int);
+
+/*
+ * Ops vector for stdio type XDR
+ */
+static const struct xdr_ops xdrstdio_ops = {
+ xdrstdio_getlong, /* deseraialize a long int */
+ xdrstdio_putlong, /* seraialize a long int */
+ xdrstdio_getbytes, /* deserialize counted bytes */
+ xdrstdio_putbytes, /* serialize counted bytes */
+ xdrstdio_getpos, /* get offset in the stream */
+ xdrstdio_setpos, /* set offset in the stream */
+ xdrstdio_inline, /* prime stream for inline macros */
+ xdrstdio_destroy /* destroy stream */
+};
+
+/*
+ * Initialize a stdio xdr stream.
+ * Sets the xdr stream handle xdrs for use on the stream file.
+ * Operation flag is set to op.
+ */
+void
+xdrstdio_create(XDR *xdrs, FILE *file, enum xdr_op op)
+{
+
+ xdrs->x_op = op;
+ xdrs->x_ops = &xdrstdio_ops;
+ xdrs->x_private = file;
+ xdrs->x_handy = 0;
+ xdrs->x_base = 0;
+}
+
+/*
+ * Destroy a stdio xdr stream.
+ * Cleans up the xdr stream handle xdrs previously set up by xdrstdio_create.
+ */
+static void
+xdrstdio_destroy(XDR *xdrs)
+{
+ (void)fflush((FILE *)xdrs->x_private);
+ /* XXX: should we close the file ?? */
+}
+
+static bool_t
+xdrstdio_getlong(XDR *xdrs, long *lp)
+{
+ u_int32_t temp;
+
+ if (fread(&temp, sizeof(int32_t), 1, (FILE *)xdrs->x_private) != 1)
+ return (FALSE);
+ *lp = (long)ntohl(temp);
+ return (TRUE);
+}
+
+static bool_t
+xdrstdio_putlong(XDR *xdrs, const long *lp)
+{
+ int32_t mycopy = htonl((u_int32_t)*lp);
+
+ if (fwrite(&mycopy, sizeof(int32_t), 1, (FILE *)xdrs->x_private) != 1)
+ return (FALSE);
+ return (TRUE);
+}
+
+static bool_t
+xdrstdio_getbytes(XDR *xdrs, char *addr, u_int len)
+{
+
+ if ((len != 0) && (fread(addr, (size_t)len, 1, (FILE *)xdrs->x_private) != 1))
+ return (FALSE);
+ return (TRUE);
+}
+
+static bool_t
+xdrstdio_putbytes(XDR *xdrs, const char *addr, u_int len)
+{
+
+ if ((len != 0) && (fwrite(addr, (size_t)len, 1,
+ (FILE *)xdrs->x_private) != 1))
+ return (FALSE);
+ return (TRUE);
+}
+
+static u_int
+xdrstdio_getpos(XDR *xdrs)
+{
+
+ return ((u_int) ftell((FILE *)xdrs->x_private));
+}
+
+static bool_t
+xdrstdio_setpos(XDR *xdrs, u_int pos)
+{
+
+ return ((fseek((FILE *)xdrs->x_private, (long)pos, 0) < 0) ?
+ FALSE : TRUE);
+}
+
+/* ARGSUSED */
+static int32_t *
+xdrstdio_inline(XDR *xdrs, u_int len)
+{
+
+ /*
+ * Must do some work to implement this: must insure
+ * enough data in the underlying stdio buffer,
+ * that the buffer is aligned so that we can indirect through a
+ * long *, and stuff this pointer in xdrs->x_buf. Doing
+ * a fread or fwrite to a scratch buffer would defeat
+ * most of the gains to be had here and require storage
+ * management on this buffer, so we don't do this.
+ */
+ return (NULL);
+}
diff --git a/lib/libc/yp/Makefile.inc b/lib/libc/yp/Makefile.inc
new file mode 100644
index 000000000000..166c9d79caa7
--- /dev/null
+++ b/lib/libc/yp/Makefile.inc
@@ -0,0 +1,19 @@
+# from: @(#)Makefile.inc 5.3 (Berkeley) 2/20/91
+# $FreeBSD$
+
+# yp sources
+.PATH: ${LIBC_SRCTOP}/yp
+
+SRCS+= xdryp.c yp.h yp_xdr.c yplib.c
+CLEANFILES+= yp.h yp_xdr.c
+
+SYM_MAPS+= ${LIBC_SRCTOP}/yp/Symbol.map
+
+RPCSRC= ${SRCTOP}/include/rpcsvc/yp.x
+RPCGEN= RPCGEN_CPP=${CPP:Q} rpcgen -C
+
+yp_xdr.c: ${RPCSRC}
+ ${RPCGEN} -c -o ${.TARGET} ${RPCSRC}
+
+yp.h: ${RPCSRC}
+ ${RPCGEN} -h -o ${.TARGET} ${RPCSRC}
diff --git a/lib/libc/yp/Symbol.map b/lib/libc/yp/Symbol.map
new file mode 100644
index 000000000000..cf2470a2dcb9
--- /dev/null
+++ b/lib/libc/yp/Symbol.map
@@ -0,0 +1,25 @@
+/*
+ * $FreeBSD$
+ */
+
+FBSD_1.0 {
+ xdr_datum;
+ xdr_ypresp_all_seq;
+ ypresp_data;
+ ypresp_allfn;
+ ypbinderr_string;
+ _yp_dobind;
+ yp_bind;
+ yp_unbind;
+ yp_match;
+ yp_get_default_domain;
+ yp_first;
+ yp_next;
+ yp_all;
+ yp_order;
+ yp_master;
+ yp_maplist;
+ yperr_string;
+ ypprot_err;
+ _yp_check;
+};
diff --git a/lib/libc/yp/xdryp.c b/lib/libc/yp/xdryp.c
new file mode 100644
index 000000000000..bb9096bb289f
--- /dev/null
+++ b/lib/libc/yp/xdryp.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 1992/3 Theo de Raadt <deraadt@fsa.ca>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rpc/rpc.h>
+#include <rpcsvc/yp.h>
+#include <stdlib.h>
+#include <string.h>
+
+extern int (*ypresp_allfn)();
+extern void *ypresp_data;
+
+/*
+ * I'm leaving the xdr_datum() function in purely for backwards
+ * compatibility. yplib.c doesn't actually use it, but it's listed
+ * in yp_prot.h as being available, so it's probably a good idea to
+ * leave it in case somebody goes looking for it.
+ */
+typedef struct {
+ char *dptr;
+ int dsize;
+} datum;
+
+bool_t
+xdr_datum(XDR *xdrs, datum *objp)
+{
+ if (!xdr_bytes(xdrs, (char **)&objp->dptr, (u_int *)&objp->dsize, YPMAXRECORD)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_ypresp_all_seq(XDR *xdrs, u_long *objp)
+{
+ struct ypresp_all out;
+ u_long status;
+ char *key, *val;
+ int r;
+
+ bzero(&out, sizeof out);
+ while (1) {
+ if (!xdr_ypresp_all(xdrs, &out)) {
+ xdr_free((xdrproc_t)xdr_ypresp_all, &out);
+ *objp = YP_YPERR;
+ return (FALSE);
+ }
+ if (out.more == 0) {
+ xdr_free((xdrproc_t)xdr_ypresp_all, &out);
+ *objp = YP_NOMORE;
+ return (TRUE);
+ }
+ status = out.ypresp_all_u.val.stat;
+ switch (status) {
+ case YP_TRUE:
+ key = (char *)malloc(out.ypresp_all_u.val.key.keydat_len + 1);
+ if (key == NULL) {
+ xdr_free((xdrproc_t)xdr_ypresp_all, &out);
+ *objp = YP_YPERR;
+ return (FALSE);
+ }
+ bcopy(out.ypresp_all_u.val.key.keydat_val, key,
+ out.ypresp_all_u.val.key.keydat_len);
+ key[out.ypresp_all_u.val.key.keydat_len] = '\0';
+ val = (char *)malloc(out.ypresp_all_u.val.val.valdat_len + 1);
+ if (val == NULL) {
+ free(key);
+ xdr_free((xdrproc_t)xdr_ypresp_all, &out);
+ *objp = YP_YPERR;
+ return (FALSE);
+ }
+ bcopy(out.ypresp_all_u.val.val.valdat_val, val,
+ out.ypresp_all_u.val.val.valdat_len);
+ val[out.ypresp_all_u.val.val.valdat_len] = '\0';
+ xdr_free((xdrproc_t)xdr_ypresp_all, &out);
+
+ r = (*ypresp_allfn)(status,
+ key, out.ypresp_all_u.val.key.keydat_len,
+ val, out.ypresp_all_u.val.val.valdat_len,
+ ypresp_data);
+ *objp = status;
+ free(key);
+ free(val);
+ if (r)
+ return (TRUE);
+ break;
+ case YP_NOMORE:
+ xdr_free((xdrproc_t)xdr_ypresp_all, &out);
+ *objp = YP_NOMORE;
+ return (TRUE);
+ default:
+ xdr_free((xdrproc_t)xdr_ypresp_all, &out);
+ *objp = status;
+ return (TRUE);
+ }
+ }
+}
diff --git a/lib/libc/yp/yplib.c b/lib/libc/yp/yplib.c
new file mode 100644
index 000000000000..b04966f5c67c
--- /dev/null
+++ b/lib/libc/yp/yplib.c
@@ -0,0 +1,1242 @@
+/*
+ * Copyright (c) 1992/3 Theo de Raadt <deraadt@fsa.ca>
+ * Copyright (c) 1998 Bill Paul <wpaul@ctr.columbia.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include "reentrant.h"
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <sys/uio.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <rpc/rpc.h>
+#include <rpc/xdr.h>
+#include <rpcsvc/yp.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+
+/*
+ * We have to define these here due to clashes between yp_prot.h and
+ * yp.h.
+ */
+
+#define YPMATCHCACHE
+
+#ifdef YPMATCHCACHE
+struct ypmatch_ent {
+ char *ypc_map;
+ keydat ypc_key;
+ valdat ypc_val;
+ time_t ypc_expire_t;
+ struct ypmatch_ent *ypc_next;
+};
+#define YPLIB_MAXCACHE 5 /* At most 5 entries */
+#define YPLIB_EXPIRE 5 /* Expire after 5 seconds */
+#endif
+
+struct dom_binding {
+ struct dom_binding *dom_pnext;
+ char dom_domain[YPMAXDOMAIN + 1];
+ struct sockaddr_in dom_server_addr;
+ u_short dom_server_port;
+ int dom_socket;
+ CLIENT *dom_client;
+ u_short dom_local_port; /* now I finally know what this is for. */
+ long dom_vers;
+#ifdef YPMATCHCACHE
+ struct ypmatch_ent *cache;
+ int ypmatch_cachecnt;
+#endif
+};
+
+#include <rpcsvc/ypclnt.h>
+
+#ifndef BINDINGDIR
+#define BINDINGDIR "/var/yp/binding"
+#endif
+#define MAX_RETRIES 20
+
+extern bool_t xdr_domainname(), xdr_ypbind_resp();
+extern bool_t xdr_ypreq_key(), xdr_ypresp_val();
+extern bool_t xdr_ypreq_nokey(), xdr_ypresp_key_val();
+extern bool_t xdr_ypresp_all(), xdr_ypresp_all_seq();
+extern bool_t xdr_ypresp_master();
+
+int (*ypresp_allfn)();
+void *ypresp_data;
+
+static void _yp_unbind(struct dom_binding *);
+struct dom_binding *_ypbindlist;
+static char _yp_domain[MAXHOSTNAMELEN];
+int _yplib_timeout = 20;
+
+static mutex_t _ypmutex = MUTEX_INITIALIZER;
+#define YPLOCK() mutex_lock(&_ypmutex);
+#define YPUNLOCK() mutex_unlock(&_ypmutex);
+
+#ifdef YPMATCHCACHE
+static void
+ypmatch_cache_delete(struct dom_binding *ypdb, struct ypmatch_ent *prev,
+ struct ypmatch_ent *cur)
+{
+ if (prev == NULL)
+ ypdb->cache = cur->ypc_next;
+ else
+ prev->ypc_next = cur->ypc_next;
+
+ free(cur->ypc_map);
+ free(cur->ypc_key.keydat_val);
+ free(cur->ypc_val.valdat_val);
+ free(cur);
+
+ ypdb->ypmatch_cachecnt--;
+
+ return;
+}
+
+static void
+ypmatch_cache_flush(struct dom_binding *ypdb)
+{
+ struct ypmatch_ent *n, *c = ypdb->cache;
+
+ while (c != NULL) {
+ n = c->ypc_next;
+ ypmatch_cache_delete(ypdb, NULL, c);
+ c = n;
+ }
+
+ return;
+}
+
+static void
+ypmatch_cache_expire(struct dom_binding *ypdb)
+{
+ struct ypmatch_ent *c = ypdb->cache;
+ struct ypmatch_ent *n, *p = NULL;
+ time_t t;
+
+ time(&t);
+
+ while (c != NULL) {
+ if (t >= c->ypc_expire_t) {
+ n = c->ypc_next;
+ ypmatch_cache_delete(ypdb, p, c);
+ c = n;
+ } else {
+ p = c;
+ c = c->ypc_next;
+ }
+ }
+
+ return;
+}
+
+static void
+ypmatch_cache_insert(struct dom_binding *ypdb, char *map, keydat *key,
+ valdat *val)
+{
+ struct ypmatch_ent *new;
+
+ /* Do an expire run to maybe open up a slot. */
+ if (ypdb->ypmatch_cachecnt)
+ ypmatch_cache_expire(ypdb);
+
+ /*
+ * If there are no slots free, then force an expire of
+ * the least recently used entry.
+ */
+ if (ypdb->ypmatch_cachecnt >= YPLIB_MAXCACHE) {
+ struct ypmatch_ent *o = NULL, *c = ypdb->cache;
+ time_t oldest = 0;
+
+ oldest = ~oldest;
+
+ while (c != NULL) {
+ if (c->ypc_expire_t < oldest) {
+ oldest = c->ypc_expire_t;
+ o = c;
+ }
+ c = c->ypc_next;
+ }
+
+ if (o == NULL)
+ return;
+ o->ypc_expire_t = 0;
+ ypmatch_cache_expire(ypdb);
+ }
+
+ new = malloc(sizeof(struct ypmatch_ent));
+ if (new == NULL)
+ return;
+
+ new->ypc_map = strdup(map);
+ if (new->ypc_map == NULL) {
+ free(new);
+ return;
+ }
+ new->ypc_key.keydat_val = malloc(key->keydat_len);
+ if (new->ypc_key.keydat_val == NULL) {
+ free(new->ypc_map);
+ free(new);
+ return;
+ }
+ new->ypc_val.valdat_val = malloc(val->valdat_len);
+ if (new->ypc_val.valdat_val == NULL) {
+ free(new->ypc_val.valdat_val);
+ free(new->ypc_map);
+ free(new);
+ return;
+ }
+
+ new->ypc_expire_t = time(NULL) + YPLIB_EXPIRE;
+ new->ypc_key.keydat_len = key->keydat_len;
+ new->ypc_val.valdat_len = val->valdat_len;
+ bcopy(key->keydat_val, new->ypc_key.keydat_val, key->keydat_len);
+ bcopy(val->valdat_val, new->ypc_val.valdat_val, val->valdat_len);
+
+ new->ypc_next = ypdb->cache;
+ ypdb->cache = new;
+
+ ypdb->ypmatch_cachecnt++;
+
+ return;
+}
+
+static bool_t
+ypmatch_cache_lookup(struct dom_binding *ypdb, char *map, keydat *key,
+ valdat *val)
+{
+ struct ypmatch_ent *c;
+
+ ypmatch_cache_expire(ypdb);
+
+ for (c = ypdb->cache; c != NULL; c = c->ypc_next) {
+ if (strcmp(map, c->ypc_map))
+ continue;
+ if (key->keydat_len != c->ypc_key.keydat_len)
+ continue;
+ if (bcmp(key->keydat_val, c->ypc_key.keydat_val,
+ key->keydat_len))
+ continue;
+ }
+
+ if (c == NULL)
+ return(FALSE);
+
+ val->valdat_len = c->ypc_val.valdat_len;
+ val->valdat_val = c->ypc_val.valdat_val;
+
+ return(TRUE);
+}
+#endif
+
+const char *
+ypbinderr_string(int incode)
+{
+ static char err[80];
+ switch (incode) {
+ case 0:
+ return ("Success");
+ case YPBIND_ERR_ERR:
+ return ("Internal ypbind error");
+ case YPBIND_ERR_NOSERV:
+ return ("Domain not bound");
+ case YPBIND_ERR_RESC:
+ return ("System resource allocation failure");
+ }
+ sprintf(err, "Unknown ypbind error: #%d\n", incode);
+ return (err);
+}
+
+int
+_yp_dobind(char *dom, struct dom_binding **ypdb)
+{
+ static pid_t pid = -1;
+ char path[MAXPATHLEN];
+ struct dom_binding *ysd, *ysd2;
+ struct ypbind_resp ypbr;
+ struct timeval tv;
+ struct sockaddr_in clnt_sin;
+ int clnt_sock, fd;
+ pid_t gpid;
+ CLIENT *client;
+ int new = 0, r;
+ int retries = 0;
+ struct sockaddr_in check;
+ socklen_t checklen = sizeof(struct sockaddr_in);
+
+ /* Not allowed; bad doggie. Bad. */
+ if (strchr(dom, '/') != NULL)
+ return(YPERR_BADARGS);
+
+ gpid = getpid();
+ if (!(pid == -1 || pid == gpid)) {
+ ysd = _ypbindlist;
+ while (ysd) {
+ if (ysd->dom_client != NULL)
+ _yp_unbind(ysd);
+ ysd2 = ysd->dom_pnext;
+ free(ysd);
+ ysd = ysd2;
+ }
+ _ypbindlist = NULL;
+ }
+ pid = gpid;
+
+ if (ypdb != NULL)
+ *ypdb = NULL;
+
+ if (dom == NULL || strlen(dom) == 0)
+ return (YPERR_BADARGS);
+
+ for (ysd = _ypbindlist; ysd; ysd = ysd->dom_pnext)
+ if (strcmp(dom, ysd->dom_domain) == 0)
+ break;
+
+
+ if (ysd == NULL) {
+ ysd = (struct dom_binding *)malloc(sizeof *ysd);
+ if (ysd == NULL)
+ return (YPERR_RESRC);
+ bzero((char *)ysd, sizeof *ysd);
+ ysd->dom_socket = -1;
+ ysd->dom_vers = 0;
+ new = 1;
+ } else {
+ /* Check the socket -- may have been hosed by the caller. */
+ if (_getsockname(ysd->dom_socket, (struct sockaddr *)&check,
+ &checklen) == -1 || check.sin_family != AF_INET ||
+ check.sin_port != ysd->dom_local_port) {
+ /* Socket became bogus somehow... need to rebind. */
+ int save, sock;
+
+ sock = ysd->dom_socket;
+ save = _dup(ysd->dom_socket);
+ if (ysd->dom_client != NULL)
+ clnt_destroy(ysd->dom_client);
+ ysd->dom_vers = 0;
+ ysd->dom_client = NULL;
+ sock = _dup2(save, sock);
+ _close(save);
+ }
+ }
+
+again:
+ retries++;
+ if (retries > MAX_RETRIES) {
+ if (new)
+ free(ysd);
+ return(YPERR_YPBIND);
+ }
+#ifdef BINDINGDIR
+ if (ysd->dom_vers == 0) {
+ /*
+ * We're trying to make a new binding: zorch the
+ * existing handle now (if any).
+ */
+ if (ysd->dom_client != NULL) {
+ clnt_destroy(ysd->dom_client);
+ ysd->dom_client = NULL;
+ ysd->dom_socket = -1;
+ }
+ snprintf(path, sizeof(path), "%s/%s.%d", BINDINGDIR, dom, 2);
+ if ((fd = _open(path, O_RDONLY | O_CLOEXEC)) == -1) {
+ /* no binding file, YP is dead. */
+ /* Try to bring it back to life. */
+ _close(fd);
+ goto skipit;
+ }
+ if (_flock(fd, LOCK_EX|LOCK_NB) == -1 && errno == EWOULDBLOCK) {
+ struct iovec iov[2];
+ struct ypbind_resp ybr;
+ u_short ypb_port;
+
+ iov[0].iov_base = (caddr_t)&ypb_port;
+ iov[0].iov_len = sizeof ypb_port;
+ iov[1].iov_base = (caddr_t)&ybr;
+ iov[1].iov_len = sizeof ybr;
+
+ r = _readv(fd, iov, 2);
+ if (r != iov[0].iov_len + iov[1].iov_len) {
+ _close(fd);
+ ysd->dom_vers = -1;
+ goto again;
+ }
+
+ bzero(&ysd->dom_server_addr, sizeof ysd->dom_server_addr);
+ ysd->dom_server_addr.sin_family = AF_INET;
+ ysd->dom_server_addr.sin_len = sizeof(struct sockaddr_in);
+ bcopy(&ybr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr,
+ &ysd->dom_server_addr.sin_addr.s_addr,
+ sizeof(ysd->dom_server_addr.sin_addr.s_addr));
+ bcopy(&ybr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port,
+ &ysd->dom_server_addr.sin_port,
+ sizeof(ysd->dom_server_addr.sin_port));
+
+ ysd->dom_server_port = ysd->dom_server_addr.sin_port;
+ _close(fd);
+ goto gotit;
+ } else {
+ /* no lock on binding file, YP is dead. */
+ /* Try to bring it back to life. */
+ _close(fd);
+ goto skipit;
+ }
+ }
+skipit:
+#endif
+ if (ysd->dom_vers == -1 || ysd->dom_vers == 0) {
+ /*
+ * We're trying to make a new binding: zorch the
+ * existing handle now (if any).
+ */
+ if (ysd->dom_client != NULL) {
+ clnt_destroy(ysd->dom_client);
+ ysd->dom_client = NULL;
+ ysd->dom_socket = -1;
+ }
+ bzero((char *)&clnt_sin, sizeof clnt_sin);
+ clnt_sin.sin_family = AF_INET;
+ clnt_sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+ clnt_sock = RPC_ANYSOCK;
+ client = clnttcp_create(&clnt_sin, YPBINDPROG, YPBINDVERS, &clnt_sock,
+ 0, 0);
+ if (client == NULL) {
+ /*
+ * These conditions indicate ypbind just isn't
+ * alive -- we probably don't want to shoot our
+ * mouth off in this case; instead generate error
+ * messages only for really exotic problems.
+ */
+ if (rpc_createerr.cf_stat != RPC_PROGNOTREGISTERED &&
+ (rpc_createerr.cf_stat != RPC_SYSTEMERROR &&
+ rpc_createerr.cf_error.re_errno == ECONNREFUSED))
+ clnt_pcreateerror("clnttcp_create");
+ if (new)
+ free(ysd);
+ return (YPERR_YPBIND);
+ }
+
+ /*
+ * Check the port number -- should be < IPPORT_RESERVED.
+ * If not, it's possible someone has registered a bogus
+ * ypbind with the portmapper and is trying to trick us.
+ */
+ if (ntohs(clnt_sin.sin_port) >= IPPORT_RESERVED) {
+ if (client != NULL)
+ clnt_destroy(client);
+ if (new)
+ free(ysd);
+ return(YPERR_YPBIND);
+ }
+ tv.tv_sec = _yplib_timeout/2;
+ tv.tv_usec = 0;
+ r = clnt_call(client, YPBINDPROC_DOMAIN,
+ (xdrproc_t)xdr_domainname, &dom,
+ (xdrproc_t)xdr_ypbind_resp, &ypbr, tv);
+ if (r != RPC_SUCCESS) {
+ clnt_destroy(client);
+ ysd->dom_vers = -1;
+ if (r == RPC_PROGUNAVAIL || r == RPC_PROCUNAVAIL) {
+ if (new)
+ free(ysd);
+ return(YPERR_YPBIND);
+ }
+ fprintf(stderr,
+ "YP: server for domain %s not responding, retrying\n", dom);
+ goto again;
+ } else {
+ if (ypbr.ypbind_status != YPBIND_SUCC_VAL) {
+ struct timespec time_to_sleep, time_remaining;
+
+ clnt_destroy(client);
+ ysd->dom_vers = -1;
+
+ time_to_sleep.tv_sec = _yplib_timeout/2;
+ time_to_sleep.tv_nsec = 0;
+ _nanosleep(&time_to_sleep,
+ &time_remaining);
+ goto again;
+ }
+ }
+ clnt_destroy(client);
+
+ bzero((char *)&ysd->dom_server_addr, sizeof ysd->dom_server_addr);
+ ysd->dom_server_addr.sin_family = AF_INET;
+ bcopy(&ypbr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port,
+ &ysd->dom_server_addr.sin_port,
+ sizeof(ysd->dom_server_addr.sin_port));
+ bcopy(&ypbr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr,
+ &ysd->dom_server_addr.sin_addr.s_addr,
+ sizeof(ysd->dom_server_addr.sin_addr.s_addr));
+
+ /*
+ * We could do a reserved port check here too, but this
+ * could pose compatibility problems. The local ypbind is
+ * supposed to decide whether or not to trust yp servers
+ * on insecure ports. For now, we trust its judgement.
+ */
+ ysd->dom_server_port =
+ *(u_short *)&ypbr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port;
+gotit:
+ ysd->dom_vers = YPVERS;
+ strlcpy(ysd->dom_domain, dom, sizeof(ysd->dom_domain));
+ }
+
+ /* Don't rebuild the connection to the server unless we have to. */
+ if (ysd->dom_client == NULL) {
+ tv.tv_sec = _yplib_timeout/2;
+ tv.tv_usec = 0;
+ ysd->dom_socket = RPC_ANYSOCK;
+ ysd->dom_client = clntudp_bufcreate(&ysd->dom_server_addr,
+ YPPROG, YPVERS, tv, &ysd->dom_socket, 1280, 2304);
+ if (ysd->dom_client == NULL) {
+ clnt_pcreateerror("clntudp_create");
+ ysd->dom_vers = -1;
+ goto again;
+ }
+ if (_fcntl(ysd->dom_socket, F_SETFD, 1) == -1)
+ perror("fcntl: F_SETFD");
+ /*
+ * We want a port number associated with this socket
+ * so that we can check its authenticity later.
+ */
+ checklen = sizeof(struct sockaddr_in);
+ bzero((char *)&check, checklen);
+ _bind(ysd->dom_socket, (struct sockaddr *)&check, checklen);
+ check.sin_family = AF_INET;
+ if (!_getsockname(ysd->dom_socket,
+ (struct sockaddr *)&check, &checklen)) {
+ ysd->dom_local_port = check.sin_port;
+ } else {
+ clnt_destroy(ysd->dom_client);
+ if (new)
+ free(ysd);
+ return(YPERR_YPBIND);
+ }
+ }
+
+ if (new) {
+ ysd->dom_pnext = _ypbindlist;
+ _ypbindlist = ysd;
+ }
+
+ /*
+ * Set low retry timeout to realistically handle UDP packet
+ * loss for YP packet bursts.
+ */
+ tv.tv_sec = 1;
+ tv.tv_usec = 0;
+ clnt_control(ysd->dom_client, CLSET_RETRY_TIMEOUT, (char*)&tv);
+
+ if (ypdb != NULL)
+ *ypdb = ysd;
+ return (0);
+}
+
+static void
+_yp_unbind(struct dom_binding *ypb)
+{
+ struct sockaddr_in check;
+ socklen_t checklen = sizeof(struct sockaddr_in);
+
+ if (ypb->dom_client != NULL) {
+ /* Check the socket -- may have been hosed by the caller. */
+ if (_getsockname(ypb->dom_socket, (struct sockaddr *)&check,
+ &checklen) == -1 || check.sin_family != AF_INET ||
+ check.sin_port != ypb->dom_local_port) {
+ int save, sock;
+
+ sock = ypb->dom_socket;
+ save = _dup(ypb->dom_socket);
+ clnt_destroy(ypb->dom_client);
+ sock = _dup2(save, sock);
+ _close(save);
+ } else
+ clnt_destroy(ypb->dom_client);
+ }
+
+ ypb->dom_client = NULL;
+ ypb->dom_socket = -1;
+ ypb->dom_vers = -1;
+#ifdef YPMATCHCACHE
+ ypmatch_cache_flush(ypb);
+#endif
+}
+
+static int
+yp_bind_locked(char *dom)
+{
+ return (_yp_dobind(dom, NULL));
+}
+
+int
+yp_bind(char *dom)
+{
+ int r;
+
+ YPLOCK();
+ r = yp_bind_locked(dom);
+ YPUNLOCK();
+ return (r);
+}
+
+static void
+yp_unbind_locked(char *dom)
+{
+ struct dom_binding *ypb, *ypbp;
+
+ ypbp = NULL;
+ for (ypb = _ypbindlist; ypb; ypb = ypb->dom_pnext) {
+ if (strcmp(dom, ypb->dom_domain) == 0) {
+ _yp_unbind(ypb);
+ if (ypbp)
+ ypbp->dom_pnext = ypb->dom_pnext;
+ else
+ _ypbindlist = ypb->dom_pnext;
+ free(ypb);
+ return;
+ }
+ ypbp = ypb;
+ }
+ return;
+}
+
+void
+yp_unbind(char *dom)
+{
+ YPLOCK();
+ yp_unbind_locked(dom);
+ YPUNLOCK();
+}
+
+int
+yp_match(char *indomain, char *inmap, const char *inkey, int inkeylen,
+ char **outval, int *outvallen)
+{
+ struct dom_binding *ysd;
+ struct ypresp_val yprv;
+ struct timeval tv;
+ struct ypreq_key yprk;
+ int r;
+ int retries = 0;
+ *outval = NULL;
+ *outvallen = 0;
+
+ /* Sanity check */
+
+ if (inkey == NULL || !strlen(inkey) || inkeylen <= 0 ||
+ inmap == NULL || !strlen(inmap) ||
+ indomain == NULL || !strlen(indomain))
+ return (YPERR_BADARGS);
+
+ YPLOCK();
+ if (_yp_dobind(indomain, &ysd) != 0) {
+ YPUNLOCK();
+ return(YPERR_DOMAIN);
+ }
+
+ yprk.domain = indomain;
+ yprk.map = inmap;
+ yprk.key.keydat_val = (char *)inkey;
+ yprk.key.keydat_len = inkeylen;
+
+#ifdef YPMATCHCACHE
+ if (ypmatch_cache_lookup(ysd, yprk.map, &yprk.key, &yprv.val) == TRUE) {
+/*
+ if (!strcmp(_yp_domain, indomain) && ypmatch_find(inmap, inkey,
+ inkeylen, &yprv.val.valdat_val, &yprv.val.valdat_len)) {
+*/
+ *outvallen = yprv.val.valdat_len;
+ *outval = (char *)malloc(*outvallen+1);
+ if (*outval == NULL) {
+ _yp_unbind(ysd);
+ *outvallen = 0;
+ YPUNLOCK();
+ return (YPERR_RESRC);
+ }
+ bcopy(yprv.val.valdat_val, *outval, *outvallen);
+ (*outval)[*outvallen] = '\0';
+ YPUNLOCK();
+ return (0);
+ }
+ _yp_unbind(ysd);
+#endif
+
+again:
+ if (retries > MAX_RETRIES) {
+ YPUNLOCK();
+ return (YPERR_RPC);
+ }
+
+ if (_yp_dobind(indomain, &ysd) != 0) {
+ YPUNLOCK();
+ return (YPERR_DOMAIN);
+ }
+
+ tv.tv_sec = _yplib_timeout;
+ tv.tv_usec = 0;
+
+ bzero((char *)&yprv, sizeof yprv);
+
+ r = clnt_call(ysd->dom_client, YPPROC_MATCH,
+ (xdrproc_t)xdr_ypreq_key, &yprk,
+ (xdrproc_t)xdr_ypresp_val, &yprv, tv);
+ if (r != RPC_SUCCESS) {
+ clnt_perror(ysd->dom_client, "yp_match: clnt_call");
+ _yp_unbind(ysd);
+ retries++;
+ goto again;
+ }
+
+ if (!(r = ypprot_err(yprv.stat))) {
+ *outvallen = yprv.val.valdat_len;
+ *outval = (char *)malloc(*outvallen+1);
+ if (*outval == NULL) {
+ _yp_unbind(ysd);
+ *outvallen = 0;
+ xdr_free((xdrproc_t)xdr_ypresp_val, &yprv);
+ YPUNLOCK();
+ return (YPERR_RESRC);
+ }
+ bcopy(yprv.val.valdat_val, *outval, *outvallen);
+ (*outval)[*outvallen] = '\0';
+#ifdef YPMATCHCACHE
+ ypmatch_cache_insert(ysd, yprk.map, &yprk.key, &yprv.val);
+#endif
+ }
+
+ xdr_free((xdrproc_t)xdr_ypresp_val, &yprv);
+ YPUNLOCK();
+ return (r);
+}
+
+static int
+yp_get_default_domain_locked(char **domp)
+{
+ *domp = NULL;
+ if (_yp_domain[0] == '\0')
+ if (getdomainname(_yp_domain, sizeof _yp_domain))
+ return (YPERR_NODOM);
+ *domp = _yp_domain;
+ return (0);
+}
+
+int
+yp_get_default_domain(char **domp)
+{
+ int r;
+
+ YPLOCK();
+ r = yp_get_default_domain_locked(domp);
+ YPUNLOCK();
+ return (r);
+}
+
+int
+yp_first(char *indomain, char *inmap, char **outkey, int *outkeylen,
+ char **outval, int *outvallen)
+{
+ struct ypresp_key_val yprkv;
+ struct ypreq_nokey yprnk;
+ struct dom_binding *ysd;
+ struct timeval tv;
+ int r;
+ int retries = 0;
+ /* Sanity check */
+
+ if (indomain == NULL || !strlen(indomain) ||
+ inmap == NULL || !strlen(inmap))
+ return (YPERR_BADARGS);
+
+ *outkey = *outval = NULL;
+ *outkeylen = *outvallen = 0;
+
+ YPLOCK();
+again:
+ if (retries > MAX_RETRIES) {
+ YPUNLOCK();
+ return (YPERR_RPC);
+ }
+
+ if (_yp_dobind(indomain, &ysd) != 0) {
+ YPUNLOCK();
+ return (YPERR_DOMAIN);
+ }
+
+ tv.tv_sec = _yplib_timeout;
+ tv.tv_usec = 0;
+
+ yprnk.domain = indomain;
+ yprnk.map = inmap;
+ bzero((char *)&yprkv, sizeof yprkv);
+
+ r = clnt_call(ysd->dom_client, YPPROC_FIRST,
+ (xdrproc_t)xdr_ypreq_nokey, &yprnk,
+ (xdrproc_t)xdr_ypresp_key_val, &yprkv, tv);
+ if (r != RPC_SUCCESS) {
+ clnt_perror(ysd->dom_client, "yp_first: clnt_call");
+ _yp_unbind(ysd);
+ retries++;
+ goto again;
+ }
+ if (!(r = ypprot_err(yprkv.stat))) {
+ *outkeylen = yprkv.key.keydat_len;
+ *outkey = (char *)malloc(*outkeylen+1);
+ if (*outkey == NULL) {
+ _yp_unbind(ysd);
+ *outkeylen = 0;
+ xdr_free((xdrproc_t)xdr_ypresp_key_val, &yprkv);
+ YPUNLOCK();
+ return (YPERR_RESRC);
+ }
+ bcopy(yprkv.key.keydat_val, *outkey, *outkeylen);
+ (*outkey)[*outkeylen] = '\0';
+ *outvallen = yprkv.val.valdat_len;
+ *outval = (char *)malloc(*outvallen+1);
+ if (*outval == NULL) {
+ free(*outkey);
+ _yp_unbind(ysd);
+ *outkeylen = *outvallen = 0;
+ xdr_free((xdrproc_t)xdr_ypresp_key_val, &yprkv);
+ YPUNLOCK();
+ return (YPERR_RESRC);
+ }
+ bcopy(yprkv.val.valdat_val, *outval, *outvallen);
+ (*outval)[*outvallen] = '\0';
+ }
+
+ xdr_free((xdrproc_t)xdr_ypresp_key_val, &yprkv);
+ YPUNLOCK();
+ return (r);
+}
+
+int
+yp_next(char *indomain, char *inmap, char *inkey, int inkeylen,
+ char **outkey, int *outkeylen, char **outval, int *outvallen)
+{
+ struct ypresp_key_val yprkv;
+ struct ypreq_key yprk;
+ struct dom_binding *ysd;
+ struct timeval tv;
+ int r;
+ int retries = 0;
+ /* Sanity check */
+
+ if (inkey == NULL || !strlen(inkey) || inkeylen <= 0 ||
+ inmap == NULL || !strlen(inmap) ||
+ indomain == NULL || !strlen(indomain))
+ return (YPERR_BADARGS);
+
+ *outkey = *outval = NULL;
+ *outkeylen = *outvallen = 0;
+
+ YPLOCK();
+again:
+ if (retries > MAX_RETRIES) {
+ YPUNLOCK();
+ return (YPERR_RPC);
+ }
+
+ if (_yp_dobind(indomain, &ysd) != 0) {
+ YPUNLOCK();
+ return (YPERR_DOMAIN);
+ }
+
+ tv.tv_sec = _yplib_timeout;
+ tv.tv_usec = 0;
+
+ yprk.domain = indomain;
+ yprk.map = inmap;
+ yprk.key.keydat_val = inkey;
+ yprk.key.keydat_len = inkeylen;
+ bzero((char *)&yprkv, sizeof yprkv);
+
+ r = clnt_call(ysd->dom_client, YPPROC_NEXT,
+ (xdrproc_t)xdr_ypreq_key, &yprk,
+ (xdrproc_t)xdr_ypresp_key_val, &yprkv, tv);
+ if (r != RPC_SUCCESS) {
+ clnt_perror(ysd->dom_client, "yp_next: clnt_call");
+ _yp_unbind(ysd);
+ retries++;
+ goto again;
+ }
+ if (!(r = ypprot_err(yprkv.stat))) {
+ *outkeylen = yprkv.key.keydat_len;
+ *outkey = (char *)malloc(*outkeylen+1);
+ if (*outkey == NULL) {
+ _yp_unbind(ysd);
+ *outkeylen = 0;
+ xdr_free((xdrproc_t)xdr_ypresp_key_val, &yprkv);
+ YPUNLOCK();
+ return (YPERR_RESRC);
+ }
+ bcopy(yprkv.key.keydat_val, *outkey, *outkeylen);
+ (*outkey)[*outkeylen] = '\0';
+ *outvallen = yprkv.val.valdat_len;
+ *outval = (char *)malloc(*outvallen+1);
+ if (*outval == NULL) {
+ free(*outkey);
+ _yp_unbind(ysd);
+ *outkeylen = *outvallen = 0;
+ xdr_free((xdrproc_t)xdr_ypresp_key_val, &yprkv);
+ YPUNLOCK();
+ return (YPERR_RESRC);
+ }
+ bcopy(yprkv.val.valdat_val, *outval, *outvallen);
+ (*outval)[*outvallen] = '\0';
+ }
+
+ xdr_free((xdrproc_t)xdr_ypresp_key_val, &yprkv);
+ YPUNLOCK();
+ return (r);
+}
+
+int
+yp_all(char *indomain, char *inmap, struct ypall_callback *incallback)
+{
+ struct ypreq_nokey yprnk;
+ struct dom_binding *ysd;
+ struct timeval tv;
+ struct sockaddr_in clnt_sin;
+ CLIENT *clnt;
+ u_long status, savstat;
+ int clnt_sock;
+ int retries = 0;
+ /* Sanity check */
+
+ if (indomain == NULL || !strlen(indomain) ||
+ inmap == NULL || !strlen(inmap))
+ return (YPERR_BADARGS);
+
+ YPLOCK();
+again:
+ if (retries > MAX_RETRIES) {
+ YPUNLOCK();
+ return (YPERR_RPC);
+ }
+
+ if (_yp_dobind(indomain, &ysd) != 0) {
+ YPUNLOCK();
+ return (YPERR_DOMAIN);
+ }
+
+ tv.tv_sec = _yplib_timeout;
+ tv.tv_usec = 0;
+
+ /* YPPROC_ALL manufactures its own channel to ypserv using TCP */
+
+ clnt_sock = RPC_ANYSOCK;
+ clnt_sin = ysd->dom_server_addr;
+ clnt_sin.sin_port = 0;
+ clnt = clnttcp_create(&clnt_sin, YPPROG, YPVERS, &clnt_sock, 0, 0);
+ if (clnt == NULL) {
+ YPUNLOCK();
+ printf("clnttcp_create failed\n");
+ return (YPERR_PMAP);
+ }
+
+ yprnk.domain = indomain;
+ yprnk.map = inmap;
+ ypresp_allfn = incallback->foreach;
+ ypresp_data = (void *)incallback->data;
+
+ if (clnt_call(clnt, YPPROC_ALL,
+ (xdrproc_t)xdr_ypreq_nokey, &yprnk,
+ (xdrproc_t)xdr_ypresp_all_seq, &status, tv) != RPC_SUCCESS) {
+ clnt_perror(clnt, "yp_all: clnt_call");
+ clnt_destroy(clnt);
+ _yp_unbind(ysd);
+ retries++;
+ goto again;
+ }
+
+ clnt_destroy(clnt);
+ savstat = status;
+ xdr_free((xdrproc_t)xdr_ypresp_all_seq, &status); /* not really needed... */
+ YPUNLOCK();
+ if (savstat != YP_NOMORE)
+ return (ypprot_err(savstat));
+ return (0);
+}
+
+int
+yp_order(char *indomain, char *inmap, int *outorder)
+{
+ struct dom_binding *ysd;
+ struct ypresp_order ypro;
+ struct ypreq_nokey yprnk;
+ struct timeval tv;
+ int r;
+
+ /* Sanity check */
+
+ if (indomain == NULL || !strlen(indomain) ||
+ inmap == NULL || !strlen(inmap))
+ return (YPERR_BADARGS);
+
+ YPLOCK();
+again:
+ if (_yp_dobind(indomain, &ysd) != 0) {
+ YPUNLOCK();
+ return (YPERR_DOMAIN);
+ }
+
+ tv.tv_sec = _yplib_timeout;
+ tv.tv_usec = 0;
+
+ yprnk.domain = indomain;
+ yprnk.map = inmap;
+
+ bzero((char *)(char *)&ypro, sizeof ypro);
+
+ r = clnt_call(ysd->dom_client, YPPROC_ORDER,
+ (xdrproc_t)xdr_ypreq_nokey, &yprnk,
+ (xdrproc_t)xdr_ypresp_order, &ypro, tv);
+
+ /*
+ * NIS+ in YP compat mode doesn't support the YPPROC_ORDER
+ * procedure.
+ */
+ if (r == RPC_PROCUNAVAIL) {
+ YPUNLOCK();
+ return(YPERR_YPERR);
+ }
+
+ if (r != RPC_SUCCESS) {
+ clnt_perror(ysd->dom_client, "yp_order: clnt_call");
+ _yp_unbind(ysd);
+ goto again;
+ }
+
+ if (!(r = ypprot_err(ypro.stat))) {
+ *outorder = ypro.ordernum;
+ }
+
+ xdr_free((xdrproc_t)xdr_ypresp_order, &ypro);
+ YPUNLOCK();
+ return (r);
+}
+
+int
+yp_master(char *indomain, char *inmap, char **outname)
+{
+ struct dom_binding *ysd;
+ struct ypresp_master yprm;
+ struct ypreq_nokey yprnk;
+ struct timeval tv;
+ int r;
+
+ /* Sanity check */
+
+ if (indomain == NULL || !strlen(indomain) ||
+ inmap == NULL || !strlen(inmap))
+ return (YPERR_BADARGS);
+ YPLOCK();
+again:
+ if (_yp_dobind(indomain, &ysd) != 0) {
+ YPUNLOCK();
+ return (YPERR_DOMAIN);
+ }
+
+ tv.tv_sec = _yplib_timeout;
+ tv.tv_usec = 0;
+
+ yprnk.domain = indomain;
+ yprnk.map = inmap;
+
+ bzero((char *)&yprm, sizeof yprm);
+
+ r = clnt_call(ysd->dom_client, YPPROC_MASTER,
+ (xdrproc_t)xdr_ypreq_nokey, &yprnk,
+ (xdrproc_t)xdr_ypresp_master, &yprm, tv);
+ if (r != RPC_SUCCESS) {
+ clnt_perror(ysd->dom_client, "yp_master: clnt_call");
+ _yp_unbind(ysd);
+ goto again;
+ }
+
+ if (!(r = ypprot_err(yprm.stat))) {
+ *outname = (char *)strdup(yprm.peer);
+ }
+
+ xdr_free((xdrproc_t)xdr_ypresp_master, &yprm);
+ YPUNLOCK();
+ return (r);
+}
+
+int
+yp_maplist(char *indomain, struct ypmaplist **outmaplist)
+{
+ struct dom_binding *ysd;
+ struct ypresp_maplist ypml;
+ struct timeval tv;
+ int r;
+
+ /* Sanity check */
+
+ if (indomain == NULL || !strlen(indomain))
+ return (YPERR_BADARGS);
+
+ YPLOCK();
+again:
+ if (_yp_dobind(indomain, &ysd) != 0) {
+ YPUNLOCK();
+ return (YPERR_DOMAIN);
+ }
+
+ tv.tv_sec = _yplib_timeout;
+ tv.tv_usec = 0;
+
+ bzero((char *)&ypml, sizeof ypml);
+
+ r = clnt_call(ysd->dom_client, YPPROC_MAPLIST,
+ (xdrproc_t)xdr_domainname, &indomain,
+ (xdrproc_t)xdr_ypresp_maplist, &ypml,tv);
+ if (r != RPC_SUCCESS) {
+ clnt_perror(ysd->dom_client, "yp_maplist: clnt_call");
+ _yp_unbind(ysd);
+ goto again;
+ }
+ if (!(r = ypprot_err(ypml.stat))) {
+ *outmaplist = ypml.maps;
+ }
+
+ /* NO: xdr_free((xdrproc_t)xdr_ypresp_maplist, &ypml);*/
+ YPUNLOCK();
+ return (r);
+}
+
+const char *
+yperr_string(int incode)
+{
+ static char err[80];
+
+ switch (incode) {
+ case 0:
+ return ("Success");
+ case YPERR_BADARGS:
+ return ("Request arguments bad");
+ case YPERR_RPC:
+ return ("RPC failure");
+ case YPERR_DOMAIN:
+ return ("Can't bind to server which serves this domain");
+ case YPERR_MAP:
+ return ("No such map in server's domain");
+ case YPERR_KEY:
+ return ("No such key in map");
+ case YPERR_YPERR:
+ return ("YP server error");
+ case YPERR_RESRC:
+ return ("Local resource allocation failure");
+ case YPERR_NOMORE:
+ return ("No more records in map database");
+ case YPERR_PMAP:
+ return ("Can't communicate with portmapper");
+ case YPERR_YPBIND:
+ return ("Can't communicate with ypbind");
+ case YPERR_YPSERV:
+ return ("Can't communicate with ypserv");
+ case YPERR_NODOM:
+ return ("Local domain name not set");
+ case YPERR_BADDB:
+ return ("Server data base is bad");
+ case YPERR_VERS:
+ return ("YP server version mismatch - server can't supply service.");
+ case YPERR_ACCESS:
+ return ("Access violation");
+ case YPERR_BUSY:
+ return ("Database is busy");
+ }
+ sprintf(err, "YP unknown error %d\n", incode);
+ return (err);
+}
+
+int
+ypprot_err(unsigned int incode)
+{
+ switch (incode) {
+ case YP_TRUE:
+ return (0);
+ case YP_FALSE:
+ return (YPERR_YPBIND);
+ case YP_NOMORE:
+ return (YPERR_NOMORE);
+ case YP_NOMAP:
+ return (YPERR_MAP);
+ case YP_NODOM:
+ return (YPERR_DOMAIN);
+ case YP_NOKEY:
+ return (YPERR_KEY);
+ case YP_BADOP:
+ return (YPERR_YPERR);
+ case YP_BADDB:
+ return (YPERR_BADDB);
+ case YP_YPERR:
+ return (YPERR_YPERR);
+ case YP_BADARGS:
+ return (YPERR_BADARGS);
+ case YP_VERS:
+ return (YPERR_VERS);
+ }
+ return (YPERR_YPERR);
+}
+
+int
+_yp_check(char **dom)
+{
+ char *unused;
+
+ YPLOCK();
+ if (_yp_domain[0]=='\0')
+ if (yp_get_default_domain_locked(&unused)) {
+ YPUNLOCK();
+ return (0);
+ }
+
+ if (dom)
+ *dom = _yp_domain;
+
+ if (yp_bind_locked(_yp_domain) == 0) {
+ yp_unbind_locked(_yp_domain);
+ YPUNLOCK();
+ return (1);
+ }
+ YPUNLOCK();
+ return (0);
+}